1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-18 10:21:03 +03:00

Revert sqlite3_close() to legacy behavior. Create a new sqlite3_close_v2()

interface that exhibits the deferred-close behavior.  This minimizes the
chance of breakage in legacy apps.

FossilOrigin-Name: c4b8621125ce77308b06692d92f70586b10055a9
This commit is contained in:
drh
2012-06-02 17:09:46 +00:00
parent 4245c405ea
commit 167cd6ab78
8 changed files with 110 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
C The\ssqlite3_close()\sinterface\sreturns\sSQLITE_OK\seven\sif\sthere\sare\soutstanding\nsqlite3_stmt\sand\ssqlite3_backup\sobjects.\s\sThe\sconnection\sbecomes\sa\szombie.\nResource\sdeallocation\sis\sdeferred\suntil\sthe\slast\ssqlite3_stmt\sor\s\nsqlite3_backup\sobject\scloses.\s\sThis\sis\sintended\sto\shelp\sSQLite\splay\snicer\nwith\sgarbage\scollectors. C Revert\ssqlite3_close()\sto\slegacy\sbehavior.\s\sCreate\sa\snew\ssqlite3_close_v2()\ninterface\sthat\sexhibits\sthe\sdeferred-close\sbehavior.\s\sThis\sminimizes\sthe\nchance\sof\sbreakage\sin\slegacy\sapps.
D 2012-06-02T14:32:21.619 D 2012-06-02T17:09:46.071
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 4f37eb61be9d38643cdd839a74b8e3bad724cfcf F Makefile.in 4f37eb61be9d38643cdd839a74b8e3bad724cfcf
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -145,7 +145,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416 F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d
F src/main.c 7ccc7d2dbd06b8eb9226e3f4f46150299dc69da3 F src/main.c 4f47dad00c32092a28cac06d2e7cdcde024af432
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c b3677415e69603d6a0e7c5410a1b3731d55beda1 F src/mem1.c b3677415e69603d6a0e7c5410a1b3731d55beda1
@@ -180,7 +180,7 @@ F src/resolve.c b3c70ab28cac60de33684c9aa9e5138dcf71d6dd
F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1 F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1
F src/select.c f6c4833c4d8e94714761d99013d74f381e084f1d F src/select.c f6c4833c4d8e94714761d99013d74f381e084f1d
F src/shell.c c16f72e34f611f060546709564c121a67cb2b31b F src/shell.c c16f72e34f611f060546709564c121a67cb2b31b
F src/sqlite.h.in f8f4b07ecf9516403ecb0b88c2c4e6fe939bd495 F src/sqlite.h.in 238059420ea5e60deb6dacc3c46a44f47739060d
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
F src/sqliteInt.h d3b7409a510f7aeb0f9e6a2c74a18db3c659435c F src/sqliteInt.h d3b7409a510f7aeb0f9e6a2c74a18db3c659435c
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
@@ -288,7 +288,7 @@ F test/autovacuum.test fcaf4616ae5bb18098db1cb36262565e5c841c3c
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
F test/backcompat.test bccbc64769d9c755ad65ee7c2f7336b86e3cc0c8 F test/backcompat.test bccbc64769d9c755ad65ee7c2f7336b86e3cc0c8
F test/backup.test d7c3e3d522631c3e44fddeac1e5f2f8cb5498a2c F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62
F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf
F test/backup_ioerr.test 40d208bc9224b666ee3ed423f49bc9062a36a9d0 F test/backup_ioerr.test 40d208bc9224b666ee3ed423f49bc9062a36a9d0
F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
@@ -314,9 +314,9 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0 F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
F test/cache.test f64136b0893c293d0b910ed057b3b711249099a7 F test/cache.test f64136b0893c293d0b910ed057b3b711249099a7
F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360 F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360
F test/capi3.test d527782c154b1dc8a96d16c140226dcf3cff0834 F test/capi3.test 8dedb0050610e9ff95cd9d487beb0ce5f33a31ee
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
F test/capi3c.test 51b51d053549c9a022cf3c04f334e697f44fbd45 F test/capi3c.test 01f197d73f4d4d66316483662f475cab7ab5bd60
F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1 F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
@@ -618,7 +618,7 @@ F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5 F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test 4337d84e441f36cee62656f9f7ba8bc22a7ca721 F test/misc7.test 4337d84e441f36cee62656f9f7ba8bc22a7ca721
F test/misuse.test 1564457e771fa0d1066b9a29b1c3149837f8c561 F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054
F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
@@ -1004,10 +1004,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
P 70c419a434be77b042a23174483d6a411899eb5d P e276a02b7f54e804caa553dca99023416a415e1c
R 117d6304ef757a98fccc6a61da6ef5e1 R 8a810a07bd449d4ae1bace844f29b96d
T *branch * deferred-close
T *sym-deferred-close *
T -sym-trunk *
U drh U drh
Z e1d9ca4a10dedd659e87ebf966dd6be6 Z 06fa4191b1c8c7f470cba6494d9b6a75

View File

@@ -1 +1 @@
e276a02b7f54e804caa553dca99023416a415e1c c4b8621125ce77308b06692d92f70586b10055a9

View File

@@ -703,7 +703,6 @@ void sqlite3CloseSavepoints(sqlite3 *db){
db->isTransactionSavepoint = 0; db->isTransactionSavepoint = 0;
} }
/* /*
** Invoke the destructor function associated with FuncDef p, if any. Except, ** Invoke the destructor function associated with FuncDef p, if any. Except,
** if this is not the last copy of the function, do not invoke it. Multiple ** if this is not the last copy of the function, do not invoke it. Multiple
@@ -721,10 +720,25 @@ static void functionDestroy(sqlite3 *db, FuncDef *p){
} }
} }
/*
** Return TRUE if database connection db has unfinalized prepared
** statements or unfinished sqlite3_backup objects.
*/
static int connectionIsBusy(sqlite3 *db){
int j;
assert( sqlite3_mutex_held(db->mutex) );
if( db->pVdbe ) return 1;
for(j=0; j<db->nDb; j++){
Btree *pBt = db->aDb[j].pBt;
if( pBt && sqlite3BtreeIsInBackup(pBt) ) return 1;
}
return 0;
}
/* /*
** Close an existing SQLite database ** Close an existing SQLite database
*/ */
int sqlite3_close(sqlite3 *db){ static int sqlite3Close(sqlite3 *db, int forceZombie){
if( !db ){ if( !db ){
return SQLITE_OK; return SQLITE_OK;
} }
@@ -745,44 +759,56 @@ int sqlite3_close(sqlite3 *db){
*/ */
sqlite3VtabRollback(db); sqlite3VtabRollback(db);
/* /* Legacy behavior (sqlite3_close() behavior) is to return
** Mark this database connection as a zombie. Then try to close it. ** SQLITE_BUSY if the connection can not be closed immediately.
*/
if( !forceZombie && connectionIsBusy(db) ){
sqlite3Error(db, SQLITE_BUSY, "unable to close due to unfinalized "
"statements or unfinished backups");
sqlite3_mutex_leave(db->mutex);
return SQLITE_BUSY;
}
/* Convert the connection into a zombie and then close it.
*/ */
db->magic = SQLITE_MAGIC_ZOMBIE; db->magic = SQLITE_MAGIC_ZOMBIE;
sqlite3LeaveMutexAndCloseZombie(db); sqlite3LeaveMutexAndCloseZombie(db);
return SQLITE_OK; return SQLITE_OK;
} }
/*
** Two variations on the public interface for closing a database
** connection. The sqlite3_close() version returns SQLITE_BUSY and
** leaves the connection option if there are unfinalized prepared
** statements or unfinished sqlite3_backups. The sqlite3_close_v2()
** version forces the connection to become a zombie if there are
** unclosed resources, and arranges for deallocation when the last
** prepare statement or sqlite3_backup closes.
*/
int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
/* /*
** Close the mutex on database connection db. ** Close the mutex on database connection db.
** **
** Furthermore, if database connection db is a zombie (meaning that there ** Furthermore, if database connection db is a zombie (meaning that there
** has been a prior call to sqlite3_close(db)) and every sqlite3_stmt ** has been a prior call to sqlite3_close(db) or sqlite3_close_v2(db)) and
** has now been finalized and every sqlite3_backup has finished, then ** every sqlite3_stmt has now been finalized and every sqlite3_backup has
** free all resources. ** finished, then free all resources.
*/ */
void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
HashElem *i; /* Hash table iterator */ HashElem *i; /* Hash table iterator */
int j; int j;
assert( sqlite3_mutex_held(db->mutex) );
/* If there are outstanding sqlite3_stmt or sqlite3_backup objects /* If there are outstanding sqlite3_stmt or sqlite3_backup objects
** or if the connection has not yet been closed by sqlite3_close, then ** or if the connection has not yet been closed by sqlite3_close_v2(),
** just leave the mutex and return. ** then just leave the mutex and return.
*/ */
if( db->pVdbe || db->magic!=SQLITE_MAGIC_ZOMBIE ){ if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){
sqlite3_mutex_leave(db->mutex); sqlite3_mutex_leave(db->mutex);
return; return;
} }
for(j=0; j<db->nDb; j++){
Btree *pBt = db->aDb[j].pBt;
if( pBt && sqlite3BtreeIsInBackup(pBt) ){
sqlite3_mutex_leave(db->mutex);
return;
}
}
/* If we reach this point, it means that the database connection has /* If we reach this point, it means that the database connection has
** closed all sqlite3_stmt and sqlite3_backup objects and has been ** closed all sqlite3_stmt and sqlite3_backup objects and has been
@@ -869,6 +895,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3_free(db->lookaside.pStart); sqlite3_free(db->lookaside.pStart);
} }
sqlite3_free(db); sqlite3_free(db);
return SQLITE_OK;
} }
/* /*

View File

@@ -214,7 +214,8 @@ int sqlite3_threadsafe(void);
** the opaque structure named "sqlite3". It is useful to think of an sqlite3 ** the opaque structure named "sqlite3". It is useful to think of an sqlite3
** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and ** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and
** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()] ** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()]
** is its destructor. There are many other interfaces (such as ** and [sqlite3_close_v2()] are its destructors. There are many other
** interfaces (such as
** [sqlite3_prepare_v2()], [sqlite3_create_function()], and ** [sqlite3_prepare_v2()], [sqlite3_create_function()], and
** [sqlite3_busy_timeout()] to name but three) that are methods on an ** [sqlite3_busy_timeout()] to name but three) that are methods on an
** sqlite3 object. ** sqlite3 object.
@@ -261,9 +262,22 @@ typedef sqlite_uint64 sqlite3_uint64;
/* /*
** CAPI3REF: Closing A Database Connection ** CAPI3REF: Closing A Database Connection
** **
** ^The sqlite3_close() routine is the destructor for the [sqlite3] object. ** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is ** for the [sqlite3] object.
** successfully destroyed and all associated resources are deallocated. ** ^Calls to sqlite3_close() and sqlite3_close_v2() return SQLITE_OK if
** the [sqlite3] object is successfully destroyed and all associated
** resources are deallocated.
**
** ^If the database connection is associated with unfinalized prepared
** statements or unfinished sqlite3_backup objects then sqlite3_close()
** will leave the database connection open and return [SQLITE_BUSY].
** ^If sqlite3_close_v2() is called with unfinalized prepared statements
** and unfinished sqlite3_backups, then the database connection becomes
** an unusable "zombie" which will automatically be deallocated when the
** last prepared statement is finalized or the last sqlite3_backup is
** finished. The sqlite3_close_v2() interface is intended for use with
** host languages that are garbage collected, and where the order in which
** destructors are called is arbitrary.
** **
** Applications should [sqlite3_finalize | finalize] all [prepared statements], ** Applications should [sqlite3_finalize | finalize] all [prepared statements],
** [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_blob_close | close] all [BLOB handles], and
@@ -275,17 +289,19 @@ typedef sqlite_uint64 sqlite3_uint64;
** of resources is deferred until all [prepared statements], [BLOB handles], ** of resources is deferred until all [prepared statements], [BLOB handles],
** and [sqlite3_backup] objects are also destroyed. ** and [sqlite3_backup] objects are also destroyed.
** **
** ^If [sqlite3_close()] is invoked while a transaction is open, ** ^If an [sqlite3] object is destroyed while a transaction is open,
** the transaction is automatically rolled back. ** the transaction is automatically rolled back.
** **
** The C parameter to [sqlite3_close(C)] must be either a NULL ** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)]
** must be either a NULL
** pointer or an [sqlite3] object pointer obtained ** pointer or an [sqlite3] object pointer obtained
** from [sqlite3_open()], [sqlite3_open16()], or ** from [sqlite3_open()], [sqlite3_open16()], or
** [sqlite3_open_v2()], and not previously closed. ** [sqlite3_open_v2()], and not previously closed.
** ^Calling sqlite3_close() with a NULL pointer argument is a ** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
** harmless no-op. ** argument is a harmless no-op.
*/ */
int sqlite3_close(sqlite3 *); int sqlite3_close(sqlite3*);
int sqlite3_close_v2(sqlite3*);
/* /*
** The type for a callback function. ** The type for a callback function.

View File

@@ -419,8 +419,11 @@ do_test backup-4.3.1 {
} {B} } {B}
do_test backup-4.3.2 { do_test backup-4.3.2 {
db2 cache flush db2 cache flush
db2 close ;# close will be deferred until the backup finishes sqlite3_close db2
} {} } {SQLITE_BUSY}
do_test backup-4.3.3 {
sqlite3_errmsg db2
} {unable to close due to unfinalized statements or unfinished backups}
do_test backup-4.3.4 { do_test backup-4.3.4 {
B step 50 B step 50
} {SQLITE_DONE} } {SQLITE_DONE}
@@ -433,7 +436,7 @@ do_test backup-4.4.1 {
list $rc [sqlite3_errcode db] [sqlite3_errmsg db] list $rc [sqlite3_errcode db] [sqlite3_errmsg db]
} {1 SQLITE_ERROR {source and destination must be distinct}} } {1 SQLITE_ERROR {source and destination must be distinct}}
db close db close
db2 close
do_test backup-4.5.1 { do_test backup-4.5.1 {
catch { forcedelete test.db } catch { forcedelete test.db }

View File

@@ -647,14 +647,20 @@ do_test capi3-6.0 {
} {0} } {0}
do_test capi3-6.1 { do_test capi3-6.1 {
db cache flush db cache flush
db close sqlite3_close $DB
} {} } {SQLITE_BUSY}
do_test capi3-6.2 { do_test capi3-6.2 {
sqlite3_step $STMT sqlite3_step $STMT
} {SQLITE_ERROR} } {SQLITE_ERROR}
#check_data $STMT capi3-6.3 {INTEGER} {1} {1.0} {1}
do_test capi3-6.3 { do_test capi3-6.3 {
sqlite3_finalize $STMT sqlite3_finalize $STMT
} {SQLITE_SCHEMA} } {SQLITE_SCHEMA}
do_test capi3-6.4-misuse {
db cache flush
sqlite3_close $DB
} {SQLITE_OK}
db close
# This procedure sets the value of the file-format in file 'test.db' # This procedure sets the value of the file-format in file 'test.db'
# to $newval. Also, the schema cookie is incremented. # to $newval. Also, the schema cookie is incremented.

View File

@@ -618,14 +618,22 @@ do_test capi3c-6.0 {
} {0} } {0}
do_test capi3c-6.1 { do_test capi3c-6.1 {
db cache flush db cache flush
db close; # close deferred sqlite3_close $DB
} {} } {SQLITE_BUSY}
do_test capi3c-6.2-misuse { do_test capi3c-6.2 {
sqlite3_step $STMT sqlite3_step $STMT
} {SQLITE_MISUSE} } {SQLITE_ROW}
check_data $STMT capi3c-6.3 {INTEGER} {1} {1.0} {1}
do_test capi3c-6.3 { do_test capi3c-6.3 {
sqlite3_finalize $STMT sqlite3_finalize $STMT
} {SQLITE_OK} } {SQLITE_OK}
do_test capi3c-6.4 {
db cache flush
sqlite3_close $DB
} {SQLITE_OK}
do_test capi3c-6.99-misuse {
db close
} {}
# This procedure sets the value of the file-format in file 'test.db' # This procedure sets the value of the file-format in file 'test.db'
# to $newval. Also, the schema cookie is incremented. # to $newval. Also, the schema cookie is incremented.

View File

@@ -170,7 +170,7 @@ do_test misuse-4.3 {
} }
} msg] } msg]
lappend v $msg $r lappend v $msg $r
} {0 {} SQLITE_OK} } {0 {} SQLITE_BUSY}
do_test misuse-4.4 { do_test misuse-4.4 {
# Flush the TCL statement cache here, otherwise the sqlite3_close() will # Flush the TCL statement cache here, otherwise the sqlite3_close() will
# fail because there are still un-finalized() VDBEs. # fail because there are still un-finalized() VDBEs.