}
}
+/*
+** Run a single SQL statement in zSql. If zSql contains two or more
+** SQL statements separated by ';', only the first is run.
+**
+** Return the sqlite3_finalizer() or sqlite3_prepare() result code
+** from running the zSql statement.
+*/
+static int recoverOneStmt(sqlite3 *db, const char *zSql){
+ sqlite3_stmt *pStmt = 0;
+ int rc;
+ if( zSql==0 ) return SQLITE_OK;
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ if( rc ){
+ sqlite3_finalize(pStmt);
+ return rc;
+ }
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){}
+ return sqlite3_finalize(pStmt);
+}
+
/*
** This function is a no-op if recover handle p already contains an error
** (if p->errCode!=SQLITE_OK). A copy of p->errCode is returned in this
** case.
**
-** Otherwise, execute SQL script zSql. If successful, return SQLITE_OK.
-** Or, if an error occurs, leave an error code and message in the recover
-** handle and return a copy of the error code.
+** Otherwise, execute a single SQL statment in zSql. Even if zSql contains
+** two or more SQL statements separated by ';', only execute the first one.
+** If successful, return SQLITE_OK. Or, if an error occurs, leave an error
+** code and message in the recover handle and return a copy of the error code.
*/
static int recoverExec(sqlite3_recover *p, sqlite3 *db, const char *zSql){
if( p->errCode==SQLITE_OK ){
- int rc = sqlite3_exec(db, zSql, 0, 0, 0);
+ int rc = recoverOneStmt(db, zSql);
if( rc ){
recoverDbError(p, db);
}
}
recoverFinalize(p, p1);
}
- recoverExec(p, db2, "CREATE TABLE t1(a); DROP TABLE t1;");
+ recoverExec(p, db2, "CREATE TABLE t1(a)");
+ recoverExec(p, db2, "DROP TABLE t1");
if( p->errCode==SQLITE_OK ){
sqlite3 *db = p->dbOut;
static void recoverOpenRecovery(sqlite3_recover *p){
char *zSql = recoverMPrintf(p, "ATTACH %Q AS recovery;", p->zStateDb);
recoverExec(p, p->dbOut, zSql);
- recoverExec(p, p->dbOut,
- "PRAGMA writable_schema = 1;"
- "CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT);"
- "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);"
- );
sqlite3_free(zSql);
+ recoverExec(p, p->dbOut, "PRAGMA writable_schema = 1");
+ recoverExec(p, p->dbOut,
+ "CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT)");
+ recoverExec(p, p->dbOut,
+ "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql)");
}
")"
"SELECT rootpage, tbl, isVirtual, name, sql"
" FROM dbschema "
- " WHERE tbl OR isIndex"
+ " WHERE (tbl OR isIndex) AND sql GLOB 'CREATE *'"
" ORDER BY tbl DESC, name=='sqlite_sequence' DESC"
);
zName, zName, zSql
));
}
- rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0);
+ rc = recoverOneStmt(p->dbOut, zSql);
if( rc==SQLITE_OK ){
recoverSqlCallback(p, zSql);
if( bTable && !bVirtual ){
p->bSlowIndexes ?
"SELECT rootpage, sql FROM recovery.schema "
" WHERE type!='table' AND type!='index'"
+ " AND sql GLOB 'CREATE *'"
:
"SELECT rootpage, sql FROM recovery.schema "
" WHERE type!='table' AND (type!='index' OR sql NOT LIKE '%unique%')"
+ " AND sql GLOB 'CREATE *'"
);
if( pSelect ){
while( sqlite3_step(pSelect)==SQLITE_ROW ){
const char *zSql = (const char*)sqlite3_column_text(pSelect, 1);
- int rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0);
+ int rc = recoverOneStmt(p->dbOut, zSql);
if( rc==SQLITE_OK ){
recoverSqlCallback(p, zSql);
}else if( rc!=SQLITE_ERROR ){
if( bUseWrapper ) recoverUninstallWrapper(p);
}while( p->errCode==SQLITE_NOTADB
&& (bUseWrapper--)
- && SQLITE_OK==sqlite3_exec(p->dbIn, "ROLLBACK", 0, 0, 0)
+ && SQLITE_OK==recoverOneStmt(p->dbIn, "ROLLBACK")
);
}
** database. Regardless of whether or not an error has occurred, make
** an attempt to end the read transaction on the input database. */
recoverExec(p, p->dbOut, "COMMIT");
- rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0);
+ rc = recoverOneStmt(p->dbIn, "END");
if( p->errCode==SQLITE_OK ) p->errCode = rc;
recoverSqlCallback(p, "PRAGMA writable_schema = off");
}else{
recoverFinalCleanup(p);
if( p->bCloseTransaction && sqlite3_get_autocommit(p->dbIn)==0 ){
- rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0);
+ rc = recoverOneStmt(p->dbIn, "END");
if( p->errCode==SQLITE_OK ) p->errCode = rc;
}
rc = p->errCode;
-C Check-in\s[1786fcd5b4ee6cd9]\sworks\sgreat\sand\sgenerates\scorrect\scode,\sbut\sit\nupset\sUBSAN.\s\sThis\scheck-in\sfixes\sthe\sUBSAN\scomplaint.
-D 2026-05-01T16:03:51.242
+C Harden\sthe\srecovery\sextension\sagainst\sSQL\sinjections\scoming\sfrom\sthe\nsqlite_schema\stable\sof\sthe\sdatabase\sbeing\srecovered.
+D 2026-05-01T16:06:21.671
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/recover/recoverrowid.test f948bf4024a5f41b0e21b8af80c60564c5b5d78c05a8d64fc00787715ff9f45f
F ext/recover/recoverslowidx.test c90d59c46bb8924a973ac6fbc38f3163cee38cc240256addcab1cf1a322c37dc
F ext/recover/recoversql.test e66d01f95302a223bcd3fd42b5ee58dc2b53d70afa90b0d00e41e4b8eab20486
-F ext/recover/sqlite3recover.c 56c216332ea91233d6d820d429f3384adbec9ecedda67aa98186b691d427cc57
+F ext/recover/sqlite3recover.c dfbfca5a8e4909333e5aa3749bcffb5dd7e396de9541c338f8cc843b2e20217e
F ext/recover/sqlite3recover.h 011c799f02deb70ab685916f6f538e6bb32c4e0025e79bfd0e24ff9c74820959
F ext/recover/test_recover.c 3d0fb1df7823f5bc22a0b93955034d16a2dfa2eb1e443e9a0123a77f120599a3
F ext/rtree/README 734aa36238bcd2dee91db5dba107d5fcbdb02396612811377a8ad50f1272b1c1
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 4aac1057eeaf6c29a4893e9c080497c780b0963e810c501532d79eba1b457f27
-R 74200f0a0383f282cba5b1796713142c
+P 7cd76847e8c9b683e39c1063a343288f11b4aa5e9302394fe0c4244d361ee4f1
+Q +555401fe048a51ecaed3ef672723b6ef8e1340c7028c11a17731abbc399bc078
+R 449a0525f9cddd36be0bcbca19693106
U drh
-Z 73b4b7a2467bd85e602423bc2cc89be8
+Z 24c5c67d5a2b3769f39c9c1e890467e4
# Remove this line to create a well-formed Fossil manifest.