-C Fix\sa\sbuffer\soverread\sin\sfts5\sthat\smight\soccur\swhile\sprocessing\sa\scorrupt\sdb.
-D 2025-11-28T12:36:04.399
+C A\sbetter\sfix\sfor\sthe\sissue\swith\sRETURNING\striggers\son\seponymous\nvirtual\stables\sand\sSQLITE_SCHEMA\serrors.
+D 2025-11-28T13:04:31.843
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
F src/build.c 611e07299d72ff04bbcb9e7109183467e30925d203c3e121ef9bb3cf6876289b
-F src/callback.c afa59adfaa483f668260ce69f740c8273dee3e6fee9106846e0499ebdd1ac076
+F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
F src/carray.c ff6081a31878fc34df8fa1052a9cbf17ddc22652544dcb3e2326886ed1053b55
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/date.c e19e0cfff9a41bfdd884c655755f6f00bca4c1a22272b56e0dd6667b7ea893a2
F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
F src/func.c 0b802107498048d3dcac0b757720bcb8506507ce02159e213ab8161458eb293b
F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b
-F src/hash.c dff10fa89d4a8280b764df9599b29342ea98cba2b868dccb5dfb3c419841a3f0
-F src/hash.h c5f4a02aaf1dca835a68b51c8b906af265c6ca3d8d53d255e0453f0abce561be
+F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca
+F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
F src/test9.c df9ddc7db6ef1b8cf745866ee229090779728bcbe660c7f297d3127ab21d92af
F src/test_autoext.c 14d4bbd3d0bd1eec0f6d16b29e28cf1e2d0b020d454835f0721a5f68121ac10f
F src/test_backup.c a2bfd90d2ff2511b8635507bdb30fa9b605ade19c16b533066cae3077f5bdb72
-F src/test_bestindex.c 3401bee51665cbf7f9ed2552b5795452a8b86365e4c9ece745b54155a55670c6
+F src/test_bestindex.c a9428931bec06de830b2630f57a7b1f2711761269f04df62b7aa1affcbce15bb
F src/test_blob.c 77b994e17f2c87055f44fd96c9a206c5a7155bae2cda2769af60c2f3582f962c
F src/test_btree.c 28283787d32b8fa953eb77412ad0de2c9895260e4e5bd5a94b3c7411664f90d5
F src/test_config.c 18aa596d37de1d5968c439fd58ebf38bc4d9c9d1db63621504e241fde375cecd
F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41
F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
-F src/vtab.c 828221bdbeaaa6d62126ee6d07fd4ec0d09dcaea846f87ad01944d8b7e548859
+F src/vtab.c 5437ce986db2f70e639ce8a3fe68dcdfe64b0f1abb14eaebecdabd5e0766cc68
F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab
F src/wal.c 505a98fbc599a971d92cb90371cf54546c404cd61e04fd093e7b0c8ff978f9b6
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F test/bestindexB.test 328b97b69cd1a20928d5997f9ecb04d2e00f1d18e19ab27f9e9adb44d7bc51ce
F test/bestindexC.test 95b4a527b1a5d07951d731604a6d4cf7e5a806b39cea0e7819d4c9667e11c3fc
F test/bestindexD.test 6a8f6f84990bcf17dfa59652a1f935beddb7afd96f8302830fbc86b0a13df3c3
-F test/bestindexE.test f0c7105d1e7facaa8f5e6c498849cc6dcadd533b35ea9e5e1176e54a9a2d70f1
+F test/bestindexE.test 297f3ea8500a8f3c17d6f78e55bdfee089064c6144ee84a110bd005a03338f49
F test/between.test e7587149796101cbe8d5f8abae8d2a7b87f04d8226610aa1091615005dcf4d54
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
F test/resetdb.test 54c06f18bc832ac6d6319e5ab23d5c8dd49fdbeec7c696d791682a8006bd5fc3
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/returning1.test cd32517148948859db214dd814354597dd40e7489259590fac1a4f7bf44deb97
-F test/returningfault.test ae4c4b5e8745813287a359d9ccdb9d5c883c2e68afb18fb0767937d5de5692a4
+F test/returningfault.test 5f9649d05680357ab077fa6bad574a3eb3f6e4858a6880b25171be516a4efcda
F test/rollback.test 952c4d805bca96adc2be76f621ea22115fe40b330015af36fcc8028c8547fcee
F test/rollback2.test 3f3a4e20401825017df7e7671e9f31b6de5fae5620c2b9b49917f52f8c160a8f
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 0c836387518dee719eaac8992c63da955630ac073a5e4ba4d887160dff42b898
-Q +8b0cbc18be3c6f2501b102757af6be98c48044a296104cca7bce822ac2304515
-R 1c559fa01e2045a73634bbe221e92967
+P 712e31c59254f82e62a19e41d3b6ac15391dd6e9df966cacadfa9ae79415b243
+Q +6a9fdde109865b23888f099d066721404e8b853f3dacd55ce08c8bbda2491ec3
+Q +bf399992cb98e5d5f002a90b521328d5c2f113ebab8601653452d78222077bde
+Q +dc569288dd63754269e14be7a9937c882531685a3e9caec25f86ec8c01eb9583
+R e6faec25512909b375a6de433bcc999d
U drh
-Z a5ce86195e7ae4027ea13f269316d3e3
+Z 6bdf6810679e96e0bba6c4bccb37d033
# Remove this line to create a well-formed Fossil manifest.
-712e31c59254f82e62a19e41d3b6ac15391dd6e9df966cacadfa9ae79415b243
+40ddaca3fb752425c26570365a9f31820786d21d043c1c0a4b49746ff9bc0782
temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash);
sqlite3HashClear(&pSchema->idxHash);
- for(pElem=sqliteHashFirst(&temp2); pElem; ){
- HashElem *pNext = sqliteHashNext(pElem);
- Trigger *pTrig = (Trigger*)sqliteHashData(pElem);
- if( pTrig->bReturning ){
- /* Do not remove RETURNING triggers from the temp-triggers hash */
- sqlite3HashTransfer(&pSchema->trigHash, &temp2, pElem);
- }else{
- sqlite3DeleteTrigger(&xdb, pTrig);
- }
- pElem = pNext;
+ for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
+ sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
}
+
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
return 0;
}
-/*
-** Parameter pElem is currently part of hash table pFrom. Add it to hash
-** table pTo.
-**
-** This procedure corrupts hash table pFrom. Specifically, it removes element
-** pElem from the list of all elements in the hash table, but may leave
-** a pointer to it in one of the hash buckets of pFrom. This is not a problem
-** because this function is only called if hash table pFrom will be cleared
-** before any further lookups or inserts are attempted.
-*/
-void sqlite3HashTransfer(Hash *pTo, Hash *pFrom, HashElem *pElem){
- if( pElem->prev ){
- pElem->prev->next = pElem->next;
- }else{
- assert( pFrom->first==pElem );
- pFrom->first = pElem->next;
- }
- pTo->count++;
- insertElement(pTo, pTo->ht ? &pTo->ht[pElem->h % pTo->htsize] : 0, pElem);
-}
-
-
void *sqlite3HashInsert(Hash*, const char *pKey, void *pData);
void *sqlite3HashFind(const Hash*, const char *pKey);
void sqlite3HashClear(Hash*);
-void sqlite3HashTransfer(Hash*, Hash*, HashElem *pElem);
/*
** Macros for looping over all elements of a hash table. The idiom is
typedef struct tcl_vtab tcl_vtab;
typedef struct tcl_cursor tcl_cursor;
typedef struct TestFindFunction TestFindFunction;
+typedef struct TestVtabContext TestVtabContext;
/*
** A fs virtual-table object
TestFindFunction *pNext;
};
+struct TestVtabContext {
+ Tcl_Interp *interp;
+ Tcl_Obj *pDefault;
+};
/*
** Dequote string z in place.
sqlite3_vtab **ppVtab,
char **pzErr
){
- Tcl_Interp *interp = (Tcl_Interp*)pAux;
+ TestVtabContext *pCtx = (TestVtabContext*)pAux;
+ Tcl_Interp *interp = pCtx->interp;
tcl_vtab *pTab = 0;
char *zCmd = 0;
Tcl_Obj *pScript = 0;
int rc = SQLITE_OK;
- if( argc!=4 ){
+ if( argc!=4 && (argc!=3 || pCtx->pDefault==0) ){
*pzErr = sqlite3_mprintf("wrong number of arguments");
return SQLITE_ERROR;
}
- zCmd = sqlite3_malloc64(strlen(argv[3])+1);
+ if( argc==4 ){
+ zCmd = sqlite3_malloc64(strlen(argv[3])+1);
+ }
pTab = (tcl_vtab*)sqlite3_malloc64(sizeof(tcl_vtab));
- if( zCmd && pTab ){
- memcpy(zCmd, argv[3], strlen(argv[3])+1);
- tclDequote(zCmd);
+ if( (zCmd || argc==3) && pTab ){
memset(pTab, 0, sizeof(tcl_vtab));
- pTab->pCmd = Tcl_NewStringObj(zCmd, -1);
+ if( zCmd ){
+ memcpy(zCmd, argv[3], strlen(argv[3])+1);
+ tclDequote(zCmd);
+ pTab->pCmd = Tcl_NewStringObj(zCmd, -1);
+ }else{
+ pTab->pCmd = Tcl_DuplicateObj(pCtx->pDefault);
+ }
+
pTab->interp = interp;
pTab->db = db;
Tcl_IncrRefCount(pTab->pCmd);
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ){
*pzErr = sqlite3_mprintf("%s", Tcl_GetStringResult(interp));
- rc = SQLITE_ERROR;
+ if( sqlite3_stricmp(*pzErr, "database schema has changed")==0 ){
+ rc = SQLITE_SCHEMA;
+ }else{
+ rc = SQLITE_ERROR;
+ }
}else{
rc = sqlite3_declare_vtab(db, Tcl_GetStringResult(interp));
if( rc!=SQLITE_OK ){
return iRet;
}
+static int tclUpdate(
+ sqlite3_vtab *tab,
+ int nArg,
+ sqlite3_value **apVal,
+ sqlite3_int64 *piRowid
+){
+ tcl_vtab *pTab = (tcl_vtab*)tab;
+ Tcl_Interp *interp = pTab->interp;
+ Tcl_Obj *pEval = Tcl_DuplicateObj(pTab->pCmd);
+ Tcl_Obj *pRes = 0;
+ int rc = TCL_OK;
+
+ Tcl_IncrRefCount(pEval);
+ Tcl_ListObjAppendElement(interp, pEval, Tcl_NewStringObj("xUpdate",-1));
+
+ rc = Tcl_EvalObjEx(interp, pEval, TCL_EVAL_GLOBAL);
+ Tcl_DecrRefCount(pEval);
+
+ if( rc==TCL_OK ){
+ Tcl_Obj *pRes = Tcl_GetObjResult(interp);
+ Tcl_WideInt v;
+ rc = Tcl_GetWideIntFromObj(interp, pRes, &v);
+ *piRowid = (sqlite3_int64)v;
+ }
+
+ if( rc!=TCL_OK ){
+ tab->zErrMsg = sqlite3_mprintf("%s", Tcl_GetStringResult(pTab->interp));
+ return rc;
+ }
+
+ return SQLITE_OK;
+}
+
/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
0, /* xShadowName */
0 /* xIntegrity */
};
+static sqlite3_module tclModuleUpdate = {
+ 0, /* iVersion */
+ tclConnect,
+ tclConnect,
+ tclBestIndex,
+ tclDisconnect,
+ tclDisconnect,
+ tclOpen, /* xOpen - open a cursor */
+ tclClose, /* xClose - close a cursor */
+ tclFilter, /* xFilter - configure scan constraints */
+ tclNext, /* xNext - advance a cursor */
+ tclEof, /* xEof - check for end of scan */
+ tclColumn, /* xColumn - read data */
+ tclRowid, /* xRowid - read data */
+ tclUpdate, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ tclFindFunction, /* xFindFunction */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
+};
/*
** Decode a pointer to an sqlite3 object.
*/
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
+static void delTestVtabCtx(void *p){
+ TestVtabContext *pCtx = (TestVtabContext*)p;
+ if( pCtx->pDefault ){
+ Tcl_DecrRefCount(pCtx->pDefault);
+ }
+ ckfree(pCtx);
+}
+
/*
** Register the echo virtual table module.
*/
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3 *db;
- if( objc!=2 ){
- Tcl_WrongNumArgs(interp, 1, objv, "DB");
+ if( objc!=2 && objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB ?DEFAULT-CMD?");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
#ifndef SQLITE_OMIT_VIRTUALTABLE
- sqlite3_create_module(db, "tcl", &tclModule, (void *)interp);
+ {
+ sqlite3_module *pMod = &tclModule;
+ TestVtabContext *pCtx = (TestVtabContext*)ckalloc(sizeof(TestVtabContext));
+ pCtx->interp = interp;
+ pCtx->pDefault = 0;
+ if( objc==3 ){
+ pCtx->pDefault = objv[2];
+ Tcl_IncrRefCount(pCtx->pDefault);
+ }
+
+ if( objc==3 ){ pMod = &tclModuleUpdate; }
+ sqlite3_create_module_v2(db, "tcl", pMod, (void*)pCtx, delTestVtabCtx);
+ }
#endif
return TCL_OK;
}
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
addModuleArgument(pParse, pTab, 0);
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
+ db->nSchemaLock++;
rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr);
+ db->nSchemaLock--;
if( rc ){
sqlite3ErrorMsg(pParse, "%s", zErr);
+ pParse->rc = rc;
sqlite3DbFree(db, zErr);
sqlite3VtabEponymousTableClear(db, pMod);
}
set testdir [file dirname $argv0]
source $testdir/tester.tcl
-set testprefix bestindex1
+set testprefix bestindexE
ifcapable !vtab {
finish_test
{Customer: oid=?}
}
+#--------------------------------------------------------------------------
+reset_db
+register_tcl_module db eponymous_cmd
+proc eponymous_cmd {method args} {
+ switch -- $method {
+ xConnect {
+ db eval { SELECT * FROM sqlite_schema }
+ return "CREATE TABLE t1 (a, b)"
+ }
+ xBestIndex {
+ return "idxnum 555"
+ }
+
+ xFilter {
+ return [list sql {SELECT 123, 'A', 'B'}]
+ }
+
+ xUpdate {
+ return 123
+ }
+
+ }
+
+ return {}
+}
+
+do_execsql_test 3.1.0 {
+ PRAGMA table_info = tcl
+} {
+ 0 a {} 0 {} 0 1 b {} 0 {} 0
+}
+do_execsql_test 3.1.1 {
+ SELECT rowid, * FROM tcl
+} {123 A B}
+do_execsql_test 3.1.2 {
+ INSERT INTO tcl VALUES('i', 'ii') RETURNING *;
+} {i ii}
+do_test 3.1.3 {
+ db last_insert_rowid
+} {123}
+
+do_execsql_test 3.1.4 {
+ CREATE TABLE x1(x);
+}
+
+db close
+sqlite3 db test.db
+register_tcl_module db eponymous_cmd
+sqlite3 db2 test.db
+
+# Load the schema into connection [db]
+do_execsql_test 3.2.1 { SELECT * FROM x1 }
+
+# Modify the schema on disk
+do_execsql_test -db db2 3.2.2 { CREATE TABLE x2(x) }
+
+# Insert with RETURNING trigger on eponymous table.
+do_execsql_test 3.2.3 {
+ INSERT INTO tcl VALUES('i', 'ii') RETURNING *;
+} {i ii}
finish_test
+
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
+set ::testprefix returningfault
+
do_execsql_test 1.0 {
CREATE TABLE t1 (b);
} {}
faultsim_save_and_close
-do_faultsim_test pagerfault-1 -faults oom-t* -prep {
+do_faultsim_test 1 -faults oom-t* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
faultsim_test_result {1 {sub-select returns 5 columns - expected 1}}
}
+ifcapable vtab {
+ reset_db
+ do_execsql_test 2.0 {
+ CREATE TABLE t1(x);
+ }
+
+ proc eponymous_cmd {method args} {
+ switch -- $method {
+ xConnect {
+ db eval { SELECT * FROM sqlite_schema }
+ return "CREATE TABLE t1 (a, b)"
+ }
+
+ xBestIndex {
+ return "idxnum 555"
+ }
+
+ xFilter {
+ return [list sql {SELECT 123, 'A', 'B'}]
+ }
+
+ xUpdate {
+ return 123
+ }
+
+ }
+
+ return {}
+ }
+
+ faultsim_save_and_close
+
+ do_faultsim_test 2 -faults oom* -prep {
+ faultsim_restore_and_reopen
+ register_tcl_module db eponymous_cmd
+ db eval { SELECT * FROM t1 }
+ sqlite3 db2 test.db
+ db2 eval { CREATE TABLE t2(y) }
+ db2 close
+ } -body {
+ db eval {
+ INSERT INTO tcl VALUES('hello', 'world') RETURNING *
+ }
+ } -test {
+ faultsim_test_result {0 {hello world}} {1 {vtable constructor failed: tcl}}
+ }
+}
finish_test