Avoid resetting the shared-cache schema when on of the connections using
the shared cache closes. Delay resetting the schema until the last connection closes. FossilOrigin-Name: 635e3a762ddeb1f952f66a08c1d4d53e3f42c9eb
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
C Add\ssqlite3_quota_ferror()\sand\ssqlite3_quota_file_available()\sinterfaces\sto\ntest_quota.c.\s\sChange\ssqlite3_quota_fwrite()\sto\suse\sa\sconst\sinput\sbuffer.
|
||||
D 2012-06-05T13:56:15.352
|
||||
C Avoid\sresetting\sthe\sshared-cache\sschema\swhen\son\sof\sthe\sconnections\susing\nthe\sshared\scache\scloses.\s\sDelay\sresetting\sthe\sschema\suntil\sthe\slast\sconnection\ncloses.
|
||||
D 2012-06-06T19:01:13.928
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 4f37eb61be9d38643cdd839a74b8e3bad724cfcf
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -118,15 +118,15 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c 149cc80d9257971b0bff34e58fb2263e01998289
|
||||
F src/analyze.c 70c46504c0d2543ea5cdca01140b2cd3e1d886e7
|
||||
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
|
||||
F src/attach.c 577bf5675b0c50495fc28549f2fcbdb1bac71143
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 6be23a344d3301ae38e92fddb3a33b91c309fce4
|
||||
F src/backup.c d7fb4c6d2ad3fe51a4ce1a897fde7b00f4de5fef
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c f0b71054103cb77eb5e782088c16998ec4f06624
|
||||
F src/btree.h 48a013f8964f12d944d90e4700df47b72dd6d923
|
||||
F src/btreeInt.h 38a639c0542c29fe8331a221c4aed0cb8686249e
|
||||
F src/build.c 2bb2163bb1e69f59e9f36a9413079ead42fa1d2c
|
||||
F src/build.c 47c4506afe4bcb4ed1f4b5357582d1cb3402f8ad
|
||||
F src/callback.c 0cb4228cdcd827dcc5def98fb099edcc9142dbcd
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
|
||||
@@ -145,7 +145,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
|
||||
F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d
|
||||
F src/main.c fdd95737fe28db3ad2b740c8a134b40592c6b20a
|
||||
F src/main.c 41bfe7e14319b44f6322332bce2b48599e524f75
|
||||
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c b3677415e69603d6a0e7c5410a1b3731d55beda1
|
||||
@@ -172,8 +172,8 @@ F src/parse.y f29df90bd3adc64b33114ab1de9fb7768fcf2099
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c
|
||||
F src/pcache1.c b30b1c35908346ecc43d8d9d17f2ddf6817f8f60
|
||||
F src/pragma.c e708b3bb5704605816f617e0b1d63a5488060715
|
||||
F src/prepare.c 9a00a9612ebf80203fbb41f8a29ab8cb27a05f40
|
||||
F src/pragma.c 28d7955a9e9a27d41cb462690228d39e3cec231c
|
||||
F src/prepare.c 33291b83cca285718048d219c67b8298501fa3a5
|
||||
F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c b3c70ab28cac60de33684c9aa9e5138dcf71d6dd
|
||||
@@ -182,7 +182,7 @@ F src/select.c f6c4833c4d8e94714761d99013d74f381e084f1d
|
||||
F src/shell.c c16f72e34f611f060546709564c121a67cb2b31b
|
||||
F src/sqlite.h.in 922d2907cc2b0177b2c4a3b462f04937750d6edd
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h 64cffc7ff43725ade0cdfdbab0ef6a56ef3b682f
|
||||
F src/sqliteInt.h 29b5348f0056d9b46d0bb94d4853db21568afde9
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@@ -194,7 +194,7 @@ F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
|
||||
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
|
||||
F src/test6.c 417e1e214734393c24a8ee80b41485a9c4169123
|
||||
F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843
|
||||
F src/test8.c 5ecbffe6712da81d5d10454e9d77d6c5bac95fe8
|
||||
F src/test8.c 235f1d19716fa768c46fc461ccbf529b2c9e4399
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
||||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
@@ -238,8 +238,8 @@ F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684
|
||||
F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
|
||||
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
|
||||
F src/util.c 4f6cfad661b2e3454b0cdd5b1b9d39a54942d0e3
|
||||
F src/vacuum.c bfd53f9bd20a8fdb70b0fa8e77182b866875c0d8
|
||||
F src/vdbe.c b6cb2ac43263843a5612892c0ad2309609b32c26
|
||||
F src/vacuum.c 587a52bb8833d7ac15af8916f25437e2575028bd
|
||||
F src/vdbe.c 76ae5ef2a0227681c3808ce20fe2d8b194bac634
|
||||
F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
|
||||
F src/vdbeInt.h 6ff4180a05683566a8835d12f7ec504b22932c82
|
||||
F src/vdbeapi.c 3662b6a468a2a4605a15dfab313baa6dff81ad91
|
||||
@@ -248,7 +248,7 @@ F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
|
||||
F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74
|
||||
F src/vdbesort.c b25814d385895544ebc8118245c8311ded7f81c9
|
||||
F src/vdbetrace.c 79059ebd17b3c8545fab2a24253713e77e4ab392
|
||||
F src/vtab.c ae657b1c22cff43863458e768a44f915c07bc0e4
|
||||
F src/vtab.c bb8ea3a26608bb1357538a5d2fc72beba6638998
|
||||
F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146
|
||||
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
@@ -314,7 +314,7 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test f64136b0893c293d0b910ed057b3b711249099a7
|
||||
F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360
|
||||
F test/capi3.test 8dedb0050610e9ff95cd9d487beb0ce5f33a31ee
|
||||
F test/capi3.test 8a33b82c4a2469977aed91b6eb99ae3ca1546444
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test 01f197d73f4d4d66316483662f475cab7ab5bd60
|
||||
F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
|
||||
@@ -695,6 +695,7 @@ F test/shared3.test ebf77f023f4bdaa8f74f65822b559e86ce5c6257
|
||||
F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d
|
||||
F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9
|
||||
F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e
|
||||
F test/shared8.test b27befbefbe7f4517f1d6b7ff8f64a41ec74165d
|
||||
F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de
|
||||
F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf
|
||||
F test/shell1.test 6e3013bc50e2b73f00d17e491f776decc82a71c8
|
||||
@@ -906,7 +907,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b
|
||||
F test/view.test b182a67ec43f490b156b5a710827a341be83dd17
|
||||
F test/vtab1.test e429a6835faa3870016c55d1178dcfead85f936a
|
||||
F test/vtab1.test 331ca61ba0b5df4d2f2e55ee2b9596fde4228dbe
|
||||
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
|
||||
F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
|
||||
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
|
||||
@@ -1004,7 +1005,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
P 70c419a434be77b042a23174483d6a411899eb5d
|
||||
R 6f34bdd03e1922ea3b6cb56fd9309a2c
|
||||
P 61669c95859e187618fb2fb4249306a947ae8d26 c469850b2eb61a63150cc5fc7d2fe98f0b5abffb
|
||||
R 4e8ba0ec11cbdf49789a46888b404344
|
||||
U drh
|
||||
Z 1b017ff1370375c5086bff54a1d45078
|
||||
Z 7052addf7652de59fa1313dd54313af2
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
61669c95859e187618fb2fb4249306a947ae8d26
|
||||
635e3a762ddeb1f952f66a08c1d4d53e3f42c9eb
|
||||
+2
-2
@@ -216,7 +216,7 @@ static void attachFunc(
|
||||
db->aDb[iDb].pBt = 0;
|
||||
db->aDb[iDb].pSchema = 0;
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
db->nDb = iDb;
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
@@ -288,7 +288,7 @@ static void detachFunc(
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
return;
|
||||
|
||||
detach_error:
|
||||
|
||||
+1
-1
@@ -414,7 +414,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( p->pDestDb ){
|
||||
sqlite3ResetInternalSchema(p->pDestDb, -1);
|
||||
sqlite3ResetAllSchemasOfConnection(p->pDestDb);
|
||||
}
|
||||
if( destMode==PAGER_JOURNALMODE_WAL ){
|
||||
rc = sqlite3BtreeSetVersion(p->pDest, 2);
|
||||
|
||||
+52
-50
@@ -394,58 +394,15 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
||||
}
|
||||
|
||||
/*
|
||||
** Erase all schema information from the in-memory hash tables of
|
||||
** a single database. This routine is called to reclaim memory
|
||||
** before the database closes. It is also called during a rollback
|
||||
** if there were schema changes during the transaction or if a
|
||||
** schema-cookie mismatch occurs.
|
||||
** Look through the list of open database files in db->aDb[] and if
|
||||
** any have been closed, remove them from the list. Reallocate the
|
||||
** db->aDb[] structure to a smaller size, if possible.
|
||||
**
|
||||
** If iDb<0 then reset the internal schema tables for all database
|
||||
** files. If iDb>=0 then reset the internal schema for only the
|
||||
** single file indicated.
|
||||
** Entry 0 (the "main" database) and entry 1 (the "temp" database)
|
||||
** are never candidates for being collapsed.
|
||||
*/
|
||||
void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
|
||||
void sqlite3CollapseDatabaseArray(sqlite3 *db){
|
||||
int i, j;
|
||||
assert( iDb<db->nDb );
|
||||
|
||||
if( iDb>=0 ){
|
||||
/* Case 1: Reset the single schema identified by iDb */
|
||||
Db *pDb = &db->aDb[iDb];
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
assert( pDb->pSchema!=0 );
|
||||
sqlite3SchemaClear(pDb->pSchema);
|
||||
|
||||
/* If any database other than TEMP is reset, then also reset TEMP
|
||||
** since TEMP might be holding triggers that reference tables in the
|
||||
** other database.
|
||||
*/
|
||||
if( iDb!=1 ){
|
||||
pDb = &db->aDb[1];
|
||||
assert( pDb->pSchema!=0 );
|
||||
sqlite3SchemaClear(pDb->pSchema);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* Case 2 (from here to the end): Reset all schemas for all attached
|
||||
** databases. */
|
||||
assert( iDb<0 );
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Db *pDb = &db->aDb[i];
|
||||
if( pDb->pSchema ){
|
||||
sqlite3SchemaClear(pDb->pSchema);
|
||||
}
|
||||
}
|
||||
db->flags &= ~SQLITE_InternChanges;
|
||||
sqlite3VtabUnlockList(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
|
||||
/* If one or more of the auxiliary database files has been closed,
|
||||
** then remove them from the auxiliary database list. We take the
|
||||
** opportunity to do this here since we have just deleted all of the
|
||||
** schema hash tables and therefore do not have to make any changes
|
||||
** to any of those tables.
|
||||
*/
|
||||
for(i=j=2; i<db->nDb; i++){
|
||||
struct Db *pDb = &db->aDb[i];
|
||||
if( pDb->pBt==0 ){
|
||||
@@ -467,6 +424,51 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset the schema for the database at index iDb. Also reset the
|
||||
** TEMP schema.
|
||||
*/
|
||||
void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
|
||||
Db *pDb;
|
||||
assert( iDb<db->nDb );
|
||||
|
||||
/* Case 1: Reset the single schema identified by iDb */
|
||||
pDb = &db->aDb[iDb];
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
assert( pDb->pSchema!=0 );
|
||||
sqlite3SchemaClear(pDb->pSchema);
|
||||
|
||||
/* If any database other than TEMP is reset, then also reset TEMP
|
||||
** since TEMP might be holding triggers that reference tables in the
|
||||
** other database.
|
||||
*/
|
||||
if( iDb!=1 ){
|
||||
pDb = &db->aDb[1];
|
||||
assert( pDb->pSchema!=0 );
|
||||
sqlite3SchemaClear(pDb->pSchema);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Erase all schema information from all attached databases (including
|
||||
** "main" and "temp") for a single database connection.
|
||||
*/
|
||||
void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
|
||||
int i;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Db *pDb = &db->aDb[i];
|
||||
if( pDb->pSchema ){
|
||||
sqlite3SchemaClear(pDb->pSchema);
|
||||
}
|
||||
}
|
||||
db->flags &= ~SQLITE_InternChanges;
|
||||
sqlite3VtabUnlockList(db);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
sqlite3CollapseDatabaseArray(db);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called when a commit occurs.
|
||||
*/
|
||||
@@ -2763,7 +2765,7 @@ Index *sqlite3CreateIndex(
|
||||
}else{
|
||||
zColl = pTab->aCol[j].zColl;
|
||||
if( !zColl ){
|
||||
zColl = db->pDfltColl->zName;
|
||||
zColl = "BINARY";
|
||||
}
|
||||
}
|
||||
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
|
||||
|
||||
+39
-7
@@ -720,6 +720,30 @@ static void functionDestroy(sqlite3 *db, FuncDef *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Disconnect all sqlite3_vtab objects that belong to database connection
|
||||
** db. This is called when db is being closed.
|
||||
*/
|
||||
static void disconnectAllVtab(sqlite3 *db){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
int i;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Schema *pSchema = db->aDb[i].pSchema;
|
||||
if( db->aDb[i].pSchema ){
|
||||
HashElem *p;
|
||||
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
|
||||
Table *pTab = (Table *)sqliteHashData(p);
|
||||
if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an existing SQLite database
|
||||
*/
|
||||
@@ -735,10 +759,10 @@ int sqlite3_close(sqlite3 *db){
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
/* Force xDestroy calls on all virtual tables */
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
/* Force xDisconnect calls on all virtual tables */
|
||||
disconnectAllVtab(db);
|
||||
|
||||
/* If a transaction is open, the ResetInternalSchema() call above
|
||||
/* If a transaction is open, the disconnectAllVtab() call above
|
||||
** will not have called the xDisconnect() method on any virtual
|
||||
** tables in the db->aVTrans[] array. The following sqlite3VtabRollback()
|
||||
** call will do so. We need to do this before the check for active
|
||||
@@ -769,6 +793,7 @@ int sqlite3_close(sqlite3 *db){
|
||||
/* Free any outstanding Savepoint structures. */
|
||||
sqlite3CloseSavepoints(db);
|
||||
|
||||
/* Close all database connections */
|
||||
for(j=0; j<db->nDb; j++){
|
||||
struct Db *pDb = &db->aDb[j];
|
||||
if( pDb->pBt ){
|
||||
@@ -779,15 +804,22 @@ int sqlite3_close(sqlite3 *db){
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
/* Clear the TEMP schema separately and last */
|
||||
if( db->aDb[1].pSchema ){
|
||||
sqlite3SchemaClear(db->aDb[1].pSchema);
|
||||
}
|
||||
sqlite3VtabUnlockList(db);
|
||||
|
||||
/* Free up the array of auxiliary databases */
|
||||
sqlite3CollapseDatabaseArray(db);
|
||||
assert( db->nDb<=2 );
|
||||
assert( db->aDb==db->aDbStatic );
|
||||
|
||||
/* Tell the code in notify.c that the connection no longer holds any
|
||||
** locks and does not require any further unlock-notify callbacks.
|
||||
*/
|
||||
sqlite3ConnectionClosed(db);
|
||||
|
||||
assert( db->nDb<=2 );
|
||||
assert( db->aDb==db->aDbStatic );
|
||||
for(j=0; j<ArraySize(db->aFunc.a); j++){
|
||||
FuncDef *pNext, *pHash, *p;
|
||||
for(p=db->aFunc.a[j]; p; p=pHash){
|
||||
@@ -874,7 +906,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
|
||||
if( db->flags&SQLITE_InternChanges ){
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
}
|
||||
|
||||
/* Any deferred constraint violations have now been resolved. */
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ static int invalidateTempStorage(Parse *pParse){
|
||||
}
|
||||
sqlite3BtreeClose(db->aDb[1].pBt);
|
||||
db->aDb[1].pBt = 0;
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+4
-5
@@ -262,7 +262,6 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
|
||||
if( encoding==0 ) encoding = SQLITE_UTF8;
|
||||
ENC(db) = encoding;
|
||||
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
|
||||
}else{
|
||||
/* If opening an attached database, the encoding much match ENC(db) */
|
||||
if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
|
||||
@@ -342,7 +341,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
}
|
||||
if( db->mallocFailed ){
|
||||
rc = SQLITE_NOMEM;
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
}
|
||||
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
|
||||
/* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
|
||||
@@ -395,7 +394,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
|
||||
rc = sqlite3InitOne(db, i, pzErrMsg);
|
||||
if( rc ){
|
||||
sqlite3ResetInternalSchema(db, i);
|
||||
sqlite3ResetOneSchema(db, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,7 +407,7 @@ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
||||
&& !DbHasProperty(db, 1, DB_SchemaLoaded) ){
|
||||
rc = sqlite3InitOne(db, 1, pzErrMsg);
|
||||
if( rc ){
|
||||
sqlite3ResetInternalSchema(db, 1);
|
||||
sqlite3ResetOneSchema(db, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -476,7 +475,7 @@ static void schemaIsValid(Parse *pParse){
|
||||
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
||||
sqlite3ResetInternalSchema(db, iDb);
|
||||
sqlite3ResetOneSchema(db, iDb);
|
||||
pParse->rc = SQLITE_SCHEMA;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -2709,7 +2709,9 @@ void sqlite3ExprListDelete(sqlite3*, ExprList*);
|
||||
int sqlite3Init(sqlite3*, char**);
|
||||
int sqlite3InitCallback(void*, int, char**, char**);
|
||||
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
|
||||
void sqlite3ResetInternalSchema(sqlite3*, int);
|
||||
void sqlite3ResetAllSchemasOfConnection(sqlite3*);
|
||||
void sqlite3ResetOneSchema(sqlite3*,int);
|
||||
void sqlite3CollapseDatabaseArray(sqlite3*);
|
||||
void sqlite3BeginParse(Parse*,int);
|
||||
void sqlite3CommitInternalChanges(sqlite3*);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,Select*);
|
||||
@@ -3114,6 +3116,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
# define sqlite3GetVTable(X,Y) ((VTable*)0)
|
||||
#else
|
||||
void sqlite3VtabClear(sqlite3 *db, Table*);
|
||||
void sqlite3VtabDisconnect(sqlite3 *db, Table *p);
|
||||
int sqlite3VtabSync(sqlite3 *db, char **);
|
||||
int sqlite3VtabRollback(sqlite3 *db);
|
||||
int sqlite3VtabCommit(sqlite3 *db);
|
||||
|
||||
+14
-6
@@ -1300,6 +1300,7 @@ static sqlite3_module echoModuleV2 = {
|
||||
** Decode a pointer to an sqlite3 object.
|
||||
*/
|
||||
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
extern const char *sqlite3TestErrorName(int rc);
|
||||
|
||||
static void moduleDestroy(void *p){
|
||||
sqlite3_free(p);
|
||||
@@ -1314,6 +1315,7 @@ static int register_echo_module(
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
int rc;
|
||||
sqlite3 *db;
|
||||
EchoModule *pMod;
|
||||
if( objc!=2 ){
|
||||
@@ -1325,14 +1327,20 @@ static int register_echo_module(
|
||||
/* Virtual table module "echo" */
|
||||
pMod = sqlite3_malloc(sizeof(EchoModule));
|
||||
pMod->interp = interp;
|
||||
sqlite3_create_module_v2(db, "echo", &echoModule, (void*)pMod, moduleDestroy);
|
||||
rc = sqlite3_create_module_v2(
|
||||
db, "echo", &echoModule, (void*)pMod, moduleDestroy
|
||||
);
|
||||
|
||||
/* Virtual table module "echo_v2" */
|
||||
pMod = sqlite3_malloc(sizeof(EchoModule));
|
||||
pMod->interp = interp;
|
||||
sqlite3_create_module_v2(db, "echo_v2",
|
||||
&echoModuleV2, (void*)pMod, moduleDestroy
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
pMod = sqlite3_malloc(sizeof(EchoModule));
|
||||
pMod->interp = interp;
|
||||
rc = sqlite3_create_module_v2(db, "echo_v2",
|
||||
&echoModuleV2, (void*)pMod, moduleDestroy
|
||||
);
|
||||
}
|
||||
|
||||
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -339,7 +339,7 @@ end_of_vacuum:
|
||||
|
||||
/* This both clears the schemas and reduces the size of the db->aDb[]
|
||||
** array. */
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
+4
-4
@@ -2747,7 +2747,7 @@ case OP_Savepoint: {
|
||||
}
|
||||
if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
db->flags = (db->flags | SQLITE_InternChanges);
|
||||
}
|
||||
}
|
||||
@@ -3051,7 +3051,7 @@ case OP_VerifyCookie: {
|
||||
** a v-table method.
|
||||
*/
|
||||
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
|
||||
sqlite3ResetInternalSchema(db, pOp->p1);
|
||||
sqlite3ResetOneSchema(db, pOp->p1);
|
||||
}
|
||||
|
||||
p->expired = 1;
|
||||
@@ -4864,7 +4864,7 @@ case OP_ParseSchema: {
|
||||
db->init.busy = 0;
|
||||
}
|
||||
}
|
||||
if( rc ) sqlite3ResetInternalSchema(db, -1);
|
||||
if( rc ) sqlite3ResetAllSchemasOfConnection(db);
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
goto no_mem;
|
||||
}
|
||||
@@ -6159,7 +6159,7 @@ vdbe_error_halt:
|
||||
if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
|
||||
rc = SQLITE_ERROR;
|
||||
if( resetSchemaOnFault>0 ){
|
||||
sqlite3ResetInternalSchema(db, resetSchemaOnFault-1);
|
||||
sqlite3ResetOneSchema(db, resetSchemaOnFault-1);
|
||||
}
|
||||
|
||||
/* This is the only way out of this procedure. We have to
|
||||
|
||||
+51
-24
@@ -22,8 +22,8 @@
|
||||
** are invoked only from within xCreate and xConnect methods.
|
||||
*/
|
||||
struct VtabCtx {
|
||||
Table *pTab;
|
||||
VTable *pVTable;
|
||||
VTable *pVTable; /* The virtual table being constructed */
|
||||
Table *pTab; /* The Table object to which the virtual table belongs */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -38,33 +38,35 @@ static int createModule(
|
||||
void *pAux, /* Context pointer for xCreate/xConnect */
|
||||
void (*xDestroy)(void *) /* Module destructor function */
|
||||
){
|
||||
int rc, nName;
|
||||
Module *pMod;
|
||||
int rc = SQLITE_OK;
|
||||
int nName;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
nName = sqlite3Strlen30(zName);
|
||||
pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1);
|
||||
if( pMod ){
|
||||
Module *pDel;
|
||||
char *zCopy = (char *)(&pMod[1]);
|
||||
memcpy(zCopy, zName, nName+1);
|
||||
pMod->zName = zCopy;
|
||||
pMod->pModule = pModule;
|
||||
pMod->pAux = pAux;
|
||||
pMod->xDestroy = xDestroy;
|
||||
pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod);
|
||||
if( pDel && pDel->xDestroy ){
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
pDel->xDestroy(pDel->pAux);
|
||||
if( sqlite3HashFind(&db->aModule, zName, nName) ){
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
}else{
|
||||
Module *pMod;
|
||||
pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1);
|
||||
if( pMod ){
|
||||
Module *pDel;
|
||||
char *zCopy = (char *)(&pMod[1]);
|
||||
memcpy(zCopy, zName, nName+1);
|
||||
pMod->zName = zCopy;
|
||||
pMod->pModule = pModule;
|
||||
pMod->pAux = pAux;
|
||||
pMod->xDestroy = xDestroy;
|
||||
pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,nName,(void*)pMod);
|
||||
assert( pDel==0 || pDel==pMod );
|
||||
if( pDel ){
|
||||
db->mallocFailed = 1;
|
||||
sqlite3DbFree(db, pDel);
|
||||
}
|
||||
}
|
||||
sqlite3DbFree(db, pDel);
|
||||
if( pDel==pMod ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
}else if( xDestroy ){
|
||||
xDestroy(pAux);
|
||||
}
|
||||
rc = sqlite3ApiExit(db, SQLITE_OK);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux);
|
||||
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
@@ -180,6 +182,31 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Table *p is a virtual table. This function removes the VTable object
|
||||
** for table *p associated with database connection db from the linked
|
||||
** list in p->pVTab. It also decrements the VTable ref count. This is
|
||||
** used when closing database connection db to free all of its VTable
|
||||
** objects without disturbing the rest of the Schema object (which may
|
||||
** be being used by other shared-cache connections).
|
||||
*/
|
||||
void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
|
||||
VTable **ppVTab;
|
||||
|
||||
assert( IsVirtual(p) );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
|
||||
for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){
|
||||
if( (*ppVTab)->db==db ){
|
||||
VTable *pVTab = *ppVTab;
|
||||
*ppVTab = pVTab->pNext;
|
||||
sqlite3VtabUnlock(pVTab);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Disconnect all the virtual table objects in the sqlite3.pDisconnect list.
|
||||
|
||||
+7
-2
@@ -649,13 +649,18 @@ do_test capi3-6.1 {
|
||||
db cache flush
|
||||
sqlite3_close $DB
|
||||
} {SQLITE_BUSY}
|
||||
|
||||
# 6.2 and 6.3 used to return SQLITE_ERROR and SQLITE_SCHEMA, respectively.
|
||||
# But since attempting to close a connection no longer resets the internal
|
||||
# schema and expires all statements, this is no longer the case.
|
||||
do_test capi3-6.2 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ERROR}
|
||||
} {SQLITE_ROW}
|
||||
#check_data $STMT capi3-6.3 {INTEGER} {1} {1.0} {1}
|
||||
do_test capi3-6.3 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_SCHEMA}
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test capi3-6.4-misuse {
|
||||
db cache flush
|
||||
sqlite3_close $DB
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# 2012 May 15
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The tests in this file are intended to show that closing one database
|
||||
# connection to a shared-cache while there exist other connections (a)
|
||||
# does not cause the schema to be reloaded and (b) does not cause any
|
||||
# other problems.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !shared_cache { finish_test ; return }
|
||||
set testprefix shared8
|
||||
|
||||
db close
|
||||
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
do_test 0.0 { sqlite3_enable_shared_cache } {1}
|
||||
|
||||
proc roman {n} {
|
||||
array set R {1 i 2 ii 3 iii 4 iv 5 v 6 vi 7 vii 8 viii 9 ix 10 x}
|
||||
set R($n)
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests work as follows:
|
||||
#
|
||||
# 1.0: Open connection [db1] and populate the database.
|
||||
#
|
||||
# 1.1: Using "PRAGMA writable_schema", destroy the database schema on
|
||||
# disk. The schema is still in memory, so it is possible to keep
|
||||
# using it, but any attempt to reload it from disk will fail.
|
||||
#
|
||||
# 1.3-4: Open connection db2. Check that it can see the db schema. Then
|
||||
# close db1 and check that db2 still works. This shows that closing
|
||||
# db1 did not reset the in-memory schema.
|
||||
#
|
||||
# 1.5-7: Similar to 1.3-4.
|
||||
#
|
||||
# 1.8: Close all database connections (deleting the in-memory schema).
|
||||
# Then open a new connection and check that it cannot read the db.
|
||||
#
|
||||
do_test 1.0 {
|
||||
sqlite3 db1 test.db
|
||||
db1 func roman roman
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3);
|
||||
INSERT INTO t1 VALUES(4, 4);
|
||||
CREATE VIEW v1 AS SELECT a, roman(b) FROM t1;
|
||||
SELECT * FROM v1;
|
||||
} db1
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.1 {
|
||||
execsql {
|
||||
PRAGMA writable_schema = 1;
|
||||
DELETE FROM sqlite_master WHERE 1;
|
||||
PRAGMA writable_schema = 0;
|
||||
SELECT * FROM sqlite_master;
|
||||
} db1
|
||||
} {}
|
||||
|
||||
do_test 1.2 {
|
||||
execsql { SELECT * FROM v1 } db1
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.3 {
|
||||
sqlite3 db2 test.db
|
||||
db2 func roman roman
|
||||
execsql { SELECT * FROM v1 } db2
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.4 {
|
||||
db1 close
|
||||
execsql { SELECT * FROM v1 } db2
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.5 {
|
||||
sqlite3 db3 test.db
|
||||
db3 func roman roman
|
||||
execsql { SELECT * FROM v1 } db3
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.6 {
|
||||
execsql { SELECT * FROM v1 } db2
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.7 {
|
||||
db2 close
|
||||
execsql { SELECT * FROM v1 } db3
|
||||
} {1 i 2 ii 3 iii 4 iv}
|
||||
|
||||
do_test 1.8 {
|
||||
db3 close
|
||||
sqlite3 db4 test.db
|
||||
catchsql { SELECT * FROM v1 } db4
|
||||
} {1 {no such table: v1}}
|
||||
|
||||
|
||||
foreach db {db1 db2 db3 db4} { catch { $db close } }
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
finish_test
|
||||
|
||||
@@ -1275,4 +1275,18 @@ foreach {tn sql res filter} {
|
||||
}
|
||||
do_execsql_test 18.2.x { PRAGMA case_sensitive_like = OFF }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that an existing module may not be overridden.
|
||||
#
|
||||
do_test 19.1 {
|
||||
sqlite3 db2 test.db
|
||||
register_echo_module [sqlite3_connection_pointer db2]
|
||||
} SQLITE_OK
|
||||
do_test 19.2 {
|
||||
register_echo_module [sqlite3_connection_pointer db2]
|
||||
} SQLITE_MISUSE
|
||||
do_test 19.3 {
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user