aboutsummaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2012-08-15 16:21:55 +0000
committerdrh <drh@noemail.net>2012-08-15 16:21:55 +0000
commit16de7f4d3297a8a197d1e588b64e3bdde9593a2a (patch)
tree7a38b09267984dec9cee3a2c29a8277ab2c5e3f0 /src/main.c
parent618fea4830063e6a24fb4c71d7cd5c680ef7d0ab (diff)
parente74f4651da9d37fef98d83b293ed220d2ca6a7e4 (diff)
downloadsqlite-16de7f4d3297a8a197d1e588b64e3bdde9593a2a.tar.gz
sqlite-16de7f4d3297a8a197d1e588b64e3bdde9593a2a.zip
Merge all the latest trunk changes into the sessions branch.
FossilOrigin-Name: fc07a4795e027108674d1d41eb4350df629ddc8b
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c83
1 files changed, 66 insertions, 17 deletions
diff --git a/src/main.c b/src/main.c
index c7e3420a9..34109c40f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -766,12 +766,24 @@ static void disconnectAllVtab(sqlite3 *db){
}
/*
-** Close an existing SQLite database
+** Return TRUE if database connection db has unfinalized prepared
+** statements or unfinished sqlite3_backup objects.
*/
-int sqlite3_close(sqlite3 *db){
- HashElem *i; /* Hash table iterator */
+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
+*/
+static int sqlite3Close(sqlite3 *db, int forceZombie){
if( !db ){
return SQLITE_OK;
}
@@ -792,25 +804,63 @@ int sqlite3_close(sqlite3 *db){
*/
sqlite3VtabRollback(db);
- /* If there are any outstanding VMs, return SQLITE_BUSY. */
- if( db->pVdbe ){
- sqlite3Error(db, SQLITE_BUSY,
- "unable to close due to unfinalised statements");
+ /* Legacy behavior (sqlite3_close() behavior) is to return
+ ** 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;
}
- assert( sqlite3SafetyCheckSickOrOk(db) );
- for(j=0; j<db->nDb; j++){
- Btree *pBt = db->aDb[j].pBt;
- if( pBt && sqlite3BtreeIsInBackup(pBt) ){
- sqlite3Error(db, SQLITE_BUSY,
- "unable to close due to unfinished backup operation");
- sqlite3_mutex_leave(db->mutex);
- return SQLITE_BUSY;
- }
+ /* Convert the connection into a zombie and then close it.
+ */
+ db->magic = SQLITE_MAGIC_ZOMBIE;
+ sqlite3LeaveMutexAndCloseZombie(db);
+ 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.
+**
+** Furthermore, if database connection db is a zombie (meaning that there
+** has been a prior call to sqlite3_close(db) or sqlite3_close_v2(db)) and
+** every sqlite3_stmt has now been finalized and every sqlite3_backup has
+** finished, then free all resources.
+*/
+void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
+ HashElem *i; /* Hash table iterator */
+ int j;
+
+ /* If there are outstanding sqlite3_stmt or sqlite3_backup objects
+ ** or if the connection has not yet been closed by sqlite3_close_v2(),
+ ** then just leave the mutex and return.
+ */
+ if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){
+ sqlite3_mutex_leave(db->mutex);
+ return;
}
+ /* If we reach this point, it means that the database connection has
+ ** closed all sqlite3_stmt and sqlite3_backup objects and has been
+ ** pased to sqlite3_close (meaning that it is a zombie). Therefore,
+ ** go ahead and free all resources.
+ */
+
/* Free any outstanding Savepoint structures. */
sqlite3CloseSavepoints(db);
@@ -898,7 +948,6 @@ int sqlite3_close(sqlite3 *db){
sqlite3_free(db->lookaside.pStart);
}
sqlite3_free(db);
- return SQLITE_OK;
}
/*