1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Prevent regular DELETE and UPDATE statements from running against contentless_unindexed=1 tables that are not also contentless_delete=1.

FossilOrigin-Name: 21539e9d0d57fdc762affbce9220d1bb1ca009d9dc751b4ccfe63eecbbe2f575
This commit is contained in:
dan
2024-09-25 12:03:08 +00:00
parent 0218424e5a
commit 777c35dbe8
4 changed files with 81 additions and 21 deletions

View File

@ -332,10 +332,16 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
#endif
/*
** Return true if pTab is a contentless table.
** Return true if pTab is a contentless table. If parameter bIncludeUnindexed
** is true, this includes contentless tables that store UNINDEXED columns
** only.
*/
static int fts5IsContentless(Fts5FullTable *pTab){
return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
static int fts5IsContentless(Fts5FullTable *pTab, int bIncludeUnindexed){
int eContent = pTab->p.pConfig->eContent;
return (
eContent==FTS5_CONTENT_NONE
|| (bIncludeUnindexed && eContent==FTS5_CONTENT_UNINDEXED)
);
}
/*
@ -1726,9 +1732,7 @@ static int fts5SpecialInsert(
}
bLoadConfig = 1;
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NONE
|| pConfig->eContent==FTS5_CONTENT_UNINDEXED
){
if( fts5IsContentless(pTab, 1) ){
fts5SetVtabError(pTab,
"'rebuild' may not be used with a contentless fts5 table"
);
@ -1895,7 +1899,7 @@ static int fts5UpdateMethod(
** This is not suported. Except - they are both supported if the CREATE
** VIRTUAL TABLE statement contained "contentless_delete=1". */
if( eType0==SQLITE_INTEGER
&& pConfig->eContent==FTS5_CONTENT_NONE
&& fts5IsContentless(pTab, 1)
&& pConfig->bContentlessDelete==0
){
pTab->p.base.zErrMsg = sqlite3_mprintf(
@ -2172,7 +2176,7 @@ static int fts5ApiColumnText(
assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
if( iCol<0 || iCol>=pTab->pConfig->nCol ){
rc = SQLITE_RANGE;
}else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) ){
}else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab), 0) ){
*pz = 0;
*pn = 0;
}else{
@ -2205,7 +2209,7 @@ static int fts5CsrPoslist(
if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
rc = SQLITE_RANGE;
}else if( pConfig->eDetail!=FTS5_DETAIL_FULL
&& pConfig->eContent==FTS5_CONTENT_NONE
&& fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
){
*pa = 0;
*pn = 0;
@ -2689,7 +2693,7 @@ static int fts5ApiColumnLocale(
rc = SQLITE_RANGE;
}else if(
pConfig->abUnindexed[iCol]==0
&& pConfig->eContent!=FTS5_CONTENT_NONE
&& 0==fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
&& pConfig->bLocale
){
rc = fts5SeekCursor(pCsr, 0);
@ -2967,13 +2971,15 @@ static int fts5ColumnMethod(
/* A column created by the user containing values. */
int bNochange = sqlite3_vtab_nochange(pCtx);
if( fts5IsContentless(pTab) ){
if( bNochange && pConfig->bContentlessDelete ){
if( bNochange ){
if( pConfig->bContentlessDelete
&& (pConfig->eContent==FTS5_CONTENT_NONE || !pConfig->abUnindexed[iCol])
){
fts5ResultError(pCtx, "cannot UPDATE a subset of "
"columns on fts5 contentless-delete table: %s", pConfig->zName
);
}
}else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){
}else if( pConfig->eContent!=FTS5_CONTENT_NONE ){
pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
rc = fts5SeekCursor(pCsr, 1);
if( rc==SQLITE_OK ){

View File

@ -201,5 +201,59 @@ do_catchsql_test 4.2 {
);
} {1 {contentless_unindexed=1 requires a contentless table}}
do_catchsql_test 4.3 {
DELETE FROM ft WHERE rowid=1
} {1 {cannot DELETE from contentless fts5 table: ft}}
#-------------------------------------------------------------------------
# Check that the usual restrictions on contentless tables apply to
# contentless_unindexed=1 tables.
#
reset_db
do_execsql_test 5.0 {
CREATE VIRTUAL TABLE ft USING fts5(
a, b UNINDEXED, c, content='', contentless_unindexed=1
);
INSERT INTO ft VALUES('one', 'two', 'three');
INSERT INTO ft VALUES('four', 'five', 'six');
INSERT INTO ft VALUES('seven', 'eight', 'nine');
SELECT rowid, * FROM ft;
} {
1 {} two {}
2 {} five {}
3 {} eight {}
}
do_execsql_test 5.1 {
PRAGMA integrity_check
} {ok}
do_catchsql_test 5.2 {
DELETE FROM ft WHERE rowid=2
} {1 {cannot DELETE from contentless fts5 table: ft}}
do_execsql_test 5.3 {
SELECT rowid, * FROM ft('six')
} {
2 {} five {}
}
do_catchsql_test 5.4 {
UPDATE ft SET a='x', b='y', c='z' WHERE rowid=3
} {1 {cannot UPDATE contentless fts5 table: ft}}
fts5_aux_test_functions db
do_execsql_test 5.5 {
SELECT fts5_test_columntext(ft) FROM ft WHERE rowid=3
} {
{{} eight {}}
}
do_execsql_test 5.6 {
SELECT fts5_test_columntext(ft) FROM ft('three');
} {
{{} two {}}
}
finish_test