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:
drh
2012-06-06 19:01:13 +00:00
16 changed files with 327 additions and 123 deletions
+19 -18
View File
@@ -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
View File
@@ -1 +1 @@
61669c95859e187618fb2fb4249306a947ae8d26
635e3a762ddeb1f952f66a08c1d4d53e3f42c9eb
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+113
View File
@@ -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
+14
View File
@@ -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