zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
if( !zSql ) return SQLITE_NOMEM;
p->bLock++;
- rc = sqlite3_prepare_v3(
- p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
- );
+ rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt);
p->bLock--;
sqlite3_free(zSql);
}
}
if( zSql ){
p->bLock++;
- rc = sqlite3_prepare_v3(
- p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
- );
+ rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt);
p->bLock--;
sqlite3_free(zSql);
}else{
UNUSED_PARAMETER(isQuick);
rc = sqlite3Fts3IntegrityCheck(p, &bOk);
+ assert( pVtab->zErrMsg==0 || rc!=SQLITE_OK );
assert( rc!=SQLITE_CORRUPT_VTAB );
if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){
*pzErr = sqlite3_mprintf("unable to validate the inverted index for"
(*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \
)
+int sqlite3Fts3PrepareStmt(
+ Fts3Table *p, /* Prepare for this connection */
+ const char *zSql, /* SQL to prepare */
+ int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */
+ int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */
+ sqlite3_stmt **pp /* OUT: Prepared statement */
+);
+
+
/* fts3.c */
void sqlite3Fts3ErrMsg(char**,const char*,...);
int sqlite3Fts3PutVarint(char *, sqlite3_int64);
#define SQL_UPDATE_LEVEL_IDX 38
#define SQL_UPDATE_LEVEL 39
+/*
+** Wrapper around sqlite3_prepare_v3() to ensure that SQLITE_PREPARE_FROM_DDL
+** is always set.
+*/
+int sqlite3Fts3PrepareStmt(
+ Fts3Table *p, /* Prepare for this connection */
+ const char *zSql, /* SQL to prepare */
+ int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */
+ int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */
+ sqlite3_stmt **pp /* OUT: Prepared statement */
+){
+ int f = SQLITE_PREPARE_FROM_DDL
+ |((bAllowVtab==0) ? SQLITE_PREPARE_NO_VTAB : 0)
+ |(bPersist ? SQLITE_PREPARE_PERSISTENT : 0);
+
+ return sqlite3_prepare_v3(p->db, zSql, -1, f, pp, NULL);
+}
+
/*
** This function is used to obtain an SQLite prepared statement handle
** for the statement identified by the second argument. If successful,
pStmt = p->aStmt[eStmt];
if( !pStmt ){
- int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
+ int bAllowVtab = 0;
char *zSql;
if( eStmt==SQL_CONTENT_INSERT ){
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
}else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
- f &= ~SQLITE_PREPARE_NO_VTAB;
+ bAllowVtab = 1;
zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
}else{
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
if( !zSql ){
rc = SQLITE_NOMEM;
}else{
- rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL);
+ rc = sqlite3Fts3PrepareStmt(p, zSql, 1, bAllowVtab, &pStmt);
sqlite3_free(zSql);
assert( rc==SQLITE_OK || pStmt==0 );
p->aStmt[eStmt] = pStmt;
if( !zSql ){
rc = SQLITE_NOMEM;
}else{
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt);
sqlite3_free(zSql);
}
if( !zSql ){
rc = SQLITE_NOMEM;
}else{
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt);
sqlite3_free(zSql);
}
-C Fix\sspurious\serror\slog\sreports\scaused\sby\s[d25c8a6222d4e3f2].\s\sSee\n[forum:/forumpost/d2326687662430c1|forum\spost\sd2326687662].
-D 2025-12-22T12:33:27.145
+C Add\sthe\sSQLITE_PREPARE_FROM_DDL\sflag\sto\ssqlite3_prepare_v3().\sUse\sthis\sto\sprevent\sfts3/4\stables\sin\snon-trusted\sschemas\sfrom\scalling\sunsafe\sSQL\sfunctions.
+D 2025-12-22T15:22:02.051
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/fts3/README.syntax b72477722e9b4fe43f8403227d790a1c94221bfad15c27863a4b36d1052e892b
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c 4f02858ab845a97bedf06e6cc1fba49a81fe5e00a26df68d0ad0f00a5814fa70
+F ext/fts3/fts3.c 6cc7bbc307f27e7b6ee2e1d5ff63ffff4df3b42529dfe00eb34ddded417961b3
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h ed9b8bc5ed5be402069651e49d4855cb849af706cf3fe68548f58a2c21eefc7f
+F ext/fts3/fts3Int.h fd6051f7aa4db93e05fdc703ef35faf79f78170419e809139109d7aef28f4170
F ext/fts3/fts3_aux.c 7eab82a9cf0830f6551ba3abfdbe73ed39e322a4d3940ee82fbf723674ecd9f3
F ext/fts3/fts3_expr.c 5c13796638d8192c388777166075cdc8bc4b6712024cd5b72c31acdbefce5984
F ext/fts3/fts3_hash.c d9dba473741445789330c7513d4f65737c92df23c3212784312931641814672a
F ext/fts3/fts3_tokenizer1.c c1de4ae28356ad98ccb8b2e3388a7fdcce7607b5523738c9afb6275dab765154
F ext/fts3/fts3_unicode.c de426ff05c1c2e7bce161cf6b706638419c3a1d9c2667de9cb9dc0458c18e226
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
-F ext/fts3/fts3_write.c 3a412c62e39c72283e34a51ec60c59eee6d684882fea7156b09a9733bd1f10e8
+F ext/fts3/fts3_write.c d218b687fb55bce8c9340c6dbb368a10d94647cbe39801d85492d576a4e7da75
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
F ext/fts3/tool/fts3view.c 413c346399159df81f86c4928b7c4a455caab73bfbc8cd68f950f632e5751674
F src/date.c e19e0cfff9a41bfdd884c655755f6f00bca4c1a22272b56e0dd6667b7ea893a2
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
-F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
-F src/expr.c b4530f3e23d8ea38c7de4c7b55af52d43156c79128c042a580e670776f59a9bc
+F src/delete.c e020dde34838369e2f0eff75f25c44a4e56a41262593f7c48d1223689d674e4d
+F src/expr.c 252e62742f5bb01517377c93057b6040ab954034ec3dde4d6fc583565d859a9c
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c c065da737307a29e4d240ac727758dbf4102cb3218a1f651eb689b6a6fa12531
F src/func.c 0b802107498048d3dcac0b757720bcb8506507ce02159e213ab8161458eb293b
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
-F src/select.c 9d55dc7bfea75b7aec14e819b9f65ca97472cea301ac5115d45ad435a63f7350
+F src/select.c 85852256d860f3ba5be4a9edc1238e68dbea082a0167f31b7345c821ae45775d
F src/shell.c.in c4b775c664c339ac0351549a998b5f8816bf2496af5385e3937050c1fb5688fe
-F src/sqlite.h.in b7d0e99d1384e73882f3157d86e0cd886d0c510d8db2b288b1d17631d6f26089
+F src/sqlite.h.in ecdd8ee84fe9e30d51433a4cc7951bb0423f588943f5d6f32c6c6ea779662f90
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
F src/sqliteInt.h af67bc95fa6b66cd3c7f3d18d2d040ad386e4cbb02965ee318cc721ee9d5fa45
F src/util.c 36fb1150062957280777655976f3f9a75db236cb8207a0770ceae8d5ec17fcd3
F src/vacuum.c 1bacdd0a81d2b5dc1c508fbf0d938c89fa78dd8d5b46ec92686d44030d4f4789
F src/vdbe.c b44c366e83412d3b8c190feb1f029b7d02e1bd69252a57b32f195107f0d03964
-F src/vdbe.h be33bd7b17f2ec92939642416030491508c51071f6c14e27cd195983fec56b63
+F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9
F src/vdbeInt.h 2aaeb6df2938b181b4700a9328688a3986f2bba71e8b96f6a80671316618fa49
F src/vdbeapi.c 6a2181cfd27c86b4cc1d8abb27ae11f3b3f0357567814fa276ec37b043542938
F src/vdbeaux.c 908d8a191aed444b2e4c920159249127f3ff67b94c56a16fad1dfdf9c7488f20
F test/fts3aux2.test 2459e7fa3e22734aed237d1e2ae192f5541c4d8b218956ad2d90754977bf907f
F test/fts3b.test c15c4a9d04e210d0be67e54ce6a87b927168fbf9c1e3faec8c1a732c366fd491
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
-F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
+F test/fts3comp1.test f1b05ece56481f3973ece6a968cbabeeb0866c43f5375318313c003518ac53fb
F test/fts3conf.test c9cd45433b6787d48a43e84949aa2eb8b3b3d242bac7276731c1476290d31f29
F test/fts3corrupt.test 6732477c5ace050c5758a40a8b5706c8c0cccd416b9c558e0e15224805a40e57
F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0
F test/fts3varint.test 0b84a3fd4eba8a39f3687523804d18f3b322e6d4539a55bf342079c3614f2ada
F test/fts4aa.test 0e6bfd6a81695a39b23e448dda25d864e63dda75bde6949c45ddc95426c6c3f5
F test/fts4check.test f0ea5e5581951d8ef7a341eea14486daf6c5f516a2f3273b0d5e8cb8a6cd3bd2
-F test/fts4content.test 73bbb123420d2c46ef2fb3b24761e9acdb78b0877179d3a5d7d57aada08066f6
+F test/fts4content.test 7f441866207f5b1e76e0f18bde5d9925d1ee8f60388054613dd14a29a79f0bc4
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
F test/fts4growth.test 289833c34ad45a5e6e6133b53b6a71647231fb89d36ddcb8d9c87211b6721d7f
F test/fts4growth2.test 13ad4e76451af6e6906c95cdc725d01b00044269
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P f43d3339c1f06aabcb8e678ed4b91a490cfd0bc880c642ce9c1138c7e08cb360
-R 368416e9322dccc113e01f13b887d649
-U drh
-Z 991a818d717546a1f42472b805bde58a
+P 403dafc7790a2e8d1772537800760addc47d3e3555bda343c3991d56c1b36e70
+R 7581ed8e32b81aa2384ce190ebdf96b2
+U dan
+Z 1915d46eae49cba5052e06a07b4e8b93
# Remove this line to create a well-formed Fossil manifest.
-403dafc7790a2e8d1772537800760addc47d3e3555bda343c3991d56c1b36e70
+26f39ac806a5582fab1497e38a4ce68dad2b79df8c8aade43c4e21eed7576931
** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS
** virtual tables if PRAGMA trusted_schema=ON.
*/
- if( pParse->pToplevel!=0
+ if( (pParse->pToplevel!=0 || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL))
&& pTab->u.vtab.p->eVtabRisk >
((pParse->db->flags & SQLITE_TrustedSchema)!=0)
){
){
assert( !IN_RENAME_OBJECT );
assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 );
- if( ExprHasProperty(pExpr, EP_FromDDL) ){
+ if( ExprHasProperty(pExpr, EP_FromDDL)
+ || pParse->prepFlags & SQLITE_PREPARE_FROM_DDL
+ ){
if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
|| (pParse->db->flags & SQLITE_TrustedSchema)==0
){
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( ALWAYS(IsVirtual(pTab))
- && pFrom->fg.fromDDL
+ && (pFrom->fg.fromDDL || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL))
&& ALWAYS(pTab->u.vtab.p!=0)
&& pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
){
** fails, the sqlite3_prepare_v3() call returns the same error indications
** with or without this flag; it just omits the call to [sqlite3_log()] that
** logs the error.
+**
+** [[SQLITE_PREPARE_FROM_DDL]] <dt>SQLITE_PREPARE_FROM_DDL</dt>
+** <dd>The SQLITE_PREPARE_FROM_DDL causes the SQL compiler to behave as if
+** the SQL statement was part of a database schema. This only makes a
+** difference if the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is set to off.
+** This flag may be used by virtual table implementations that do not
+** completely control the SQL commands that they evaluate.
** </dl>
*/
#define SQLITE_PREPARE_PERSISTENT 0x01
#define SQLITE_PREPARE_NORMALIZE 0x02
#define SQLITE_PREPARE_NO_VTAB 0x04
#define SQLITE_PREPARE_DONT_LOG 0x10
+#define SQLITE_PREPARE_FROM_DDL 0x20
/*
** CAPI3REF: Compiling An SQL Statement
** Additional non-public SQLITE_PREPARE_* flags
*/
#define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */
-#define SQLITE_PREPARE_MASK 0x1f /* Mask of public flags */
+#define SQLITE_PREPARE_MASK 0x3f /* Mask of public flags */
/*
** Prototypes for the VDBE interface. See comments on the implementation
CREATE VIRTUAL TABLE t2 USING fts4(x, uncompress=unzip)
} {1 {missing compress parameter in fts4 constructor}}
+#--------------------------------------------------------------------------
+reset_db
+do_execsql_test 3.0 {
+ PRAGMA trusted_schema = OFF;
+}
+
+set ::myfunc_invoked 0
+proc myfunc {data} {
+ incr ::myfunc_invoked
+ return $data
+}
+db func myfunc myfunc
+
+do_execsql_test 3.1 {
+ CREATE VIEW v1 AS SELECT myfunc('xyz');
+}
+
+do_catchsql_test 3.2 {
+ SELECT * FROM v1
+} {1 {unsafe use of myfunc()}}
+
+do_execsql_test 3.3 {
+ CREATE VIRTUAL TABLE f1 USING fts4(x, compress=myfunc, uncompress=myfunc);
+}
+
+do_catchsql_test 3.4 {
+ INSERT INTO f1(rowid, x) VALUES(123, 'one two three');
+} {1 {SQL logic error}}
+
+do_test 3.5 {
+ set ::myfunc_invoked
+} {0}
+
+do_execsql_test 3.6.1 {
+ CREATE TABLE t1(x);
+ CREATE TABLE t2(y);
+
+ CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
+ INSERT INTO t2 VALUES( myfunc(new.x) );
+ END;
+}
+
+do_catchsql_test 3.6.2 {
+ INSERT INTO t1 VALUES('hello world');
+} {1 {unsafe use of myfunc()}}
+
+
finish_test
# Check that an fts4 table cannot be its own content table.
#
reset_db
-breakpoint
do_execsql_test 12.1.1 {
CREATE VIRTUAL TABLE t1 USING fts4(a, content=t1 );
INSERT INTO t1(rowid, a) VALUES(1, 'abc');
SELECT count(*) FROM t1;
} {1 {SQL logic error}}
+#---------------------------------------------------------------------------
+# Check that an fts4 table cannot read from an unsafe vtab in a non-trusted
+# schema.
+reset_db
+do_execsql_test 13.0 {
+ PRAGMA trusted_schema = off;
+ CREATE VIRTUAL TABLE t1 USING fts4(data, content=sqlite_dbpage);
+}
+
+do_catchsql_test 13.1 {
+ INSERT INTO t1(t1) VALUES('rebuild');
+} {1 {SQL logic error}}
+
+proc vtab_command {method args} {
+ switch -- $method {
+ xConnect {
+ return "CREATE TABLE t1(a)"
+ }
+
+ xBestIndex {
+ return ""
+ }
+
+ xFilter {
+ return [list sql {SELECT 1, 123}]
+ }
+
+ xUpdate {
+ return 123
+ }
+ }
+
+ return {}
+}
+
+register_tcl_module db xyz
+
+do_execsql_test 13.2.0 {
+ CREATE VIRTUAL TABLE aa USING tcl(vtab_command);
+}
+
+do_execsql_test 13.2.1 {
+ INSERT INTO aa VALUES('one two three');
+}
+
+do_test 13.2.2 {
+ set ::stmt [sqlite3_prepare_v3 db \
+ "INSERT INTO aa VALUES('one two three');" -1 0x00
+ ]
+ sqlite3_finalize $::stmt
+} {SQLITE_OK}
+do_test 13.2.2 {
+ list [catch {
+ set ::stmt [sqlite3_prepare_v3 db \
+ "INSERT INTO aa VALUES('one two three');" -1 0x20
+ ]
+ } msg] $msg
+} {1 {(1) unsafe use of virtual table "aa"}}
finish_test