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:
@ -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 ){
|
||||
|
@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user