diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backup.c | 7 | ||||
-rw-r--r-- | src/main.c | 51 | ||||
-rw-r--r-- | src/sqlite.h.in | 13 | ||||
-rw-r--r-- | src/sqliteInt.h | 2 | ||||
-rw-r--r-- | src/vdbeapi.c | 11 | ||||
-rw-r--r-- | src/vdbeaux.c | 1 |
6 files changed, 54 insertions, 31 deletions
diff --git a/src/backup.c b/src/backup.c index 7a4047f34..6655ee391 100644 --- a/src/backup.c +++ b/src/backup.c @@ -543,14 +543,13 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ */ int sqlite3_backup_finish(sqlite3_backup *p){ sqlite3_backup **pp; /* Ptr to head of pagers backup list */ - MUTEX_LOGIC( sqlite3_mutex *mutex; ) /* Mutex to protect source database */ + sqlite3 *pSrcDb = p->pSrcDb; /* Source database connection */ int rc; /* Value to return */ /* Enter the mutexes */ if( p==0 ) return SQLITE_OK; sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); - MUTEX_LOGIC( mutex = p->pSrcDb->mutex; ) if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } @@ -576,7 +575,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){ /* Exit the mutexes and free the backup context structure. */ if( p->pDestDb ){ - sqlite3_mutex_leave(p->pDestDb->mutex); + sqlite3LeaveMutexAndCloseZombie(p->pDestDb); } sqlite3BtreeLeave(p->pSrc); if( p->pDestDb ){ @@ -585,7 +584,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){ ** sqlite3_backup_finish(). */ sqlite3_free(p); } - sqlite3_mutex_leave(mutex); + sqlite3LeaveMutexAndCloseZombie(pSrcDb); return rc; } diff --git a/src/main.c b/src/main.c index 4e9a605f4..d0aebd5ee 100644 --- a/src/main.c +++ b/src/main.c @@ -703,6 +703,7 @@ void sqlite3CloseSavepoints(sqlite3 *db){ db->isTransactionSavepoint = 0; } + /* ** 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 @@ -724,9 +725,6 @@ static void functionDestroy(sqlite3 *db, FuncDef *p){ ** Close an existing SQLite database */ int sqlite3_close(sqlite3 *db){ - HashElem *i; /* Hash table iterator */ - int j; - if( !db ){ return SQLITE_OK; } @@ -747,25 +745,51 @@ 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"); + /* + ** Mark this database connection as a zombie. Then try to close it. + */ + db->magic = SQLITE_MAGIC_ZOMBIE; + sqlite3LeaveMutexAndCloseZombie(db); + return SQLITE_OK; +} + + +/* +** 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)) 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; + + assert( sqlite3_mutex_held(db->mutex) ); + + /* If there are outstanding sqlite3_stmt or sqlite3_backup objects + ** or if the connection has not yet been closed by sqlite3_close, then + ** just leave the mutex and return. + */ + if( db->pVdbe || db->magic!=SQLITE_MAGIC_ZOMBIE ){ sqlite3_mutex_leave(db->mutex); - return SQLITE_BUSY; + return; } - 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; + 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); @@ -845,7 +869,6 @@ int sqlite3_close(sqlite3 *db){ sqlite3_free(db->lookaside.pStart); } sqlite3_free(db); - return SQLITE_OK; } /* diff --git a/src/sqlite.h.in b/src/sqlite.h.in index e96c19680..ce07c386f 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -265,12 +265,15 @@ typedef sqlite_uint64 sqlite3_uint64; ** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is ** successfully destroyed and all associated resources are deallocated. ** -** Applications must [sqlite3_finalize | finalize] all [prepared statements] -** and [sqlite3_blob_close | close] all [BLOB handles] associated with -** the [sqlite3] object prior to attempting to close the object. ^If +** Applications should [sqlite3_finalize | finalize] all [prepared statements], +** [sqlite3_blob_close | close] all [BLOB handles], and +** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated +** with the [sqlite3] object prior to attempting to close the object. ^If ** sqlite3_close() is called on a [database connection] that still has -** outstanding [prepared statements] or [BLOB handles], then it returns -** SQLITE_BUSY. +** outstanding [prepared statements], [BLOB handles], and/or +** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation +** of resources is deferred until all [prepared statements], [BLOB handles], +** and [sqlite3_backup] objects are also destroyed. ** ** ^If [sqlite3_close()] is invoked while a transaction is open, ** the transaction is automatically rolled back. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 85dabb0b3..9732c8f22 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -974,6 +974,7 @@ struct sqlite3 { #define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */ #define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ #define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ +#define SQLITE_MAGIC_ZOMBIE 0x64cffc7f /* Close with last statement close */ /* ** Each SQL function is defined by an instance of the following @@ -2833,6 +2834,7 @@ void sqlite3CommitTransaction(Parse*); void sqlite3RollbackTransaction(Parse*); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); +void sqlite3LeaveMutexAndCloseZombie(sqlite3*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 94db205e1..e25acd944 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -71,17 +71,12 @@ int sqlite3_finalize(sqlite3_stmt *pStmt){ }else{ Vdbe *v = (Vdbe*)pStmt; sqlite3 *db = v->db; -#if SQLITE_THREADSAFE - sqlite3_mutex *mutex; -#endif if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT; -#if SQLITE_THREADSAFE - mutex = v->db->mutex; -#endif - sqlite3_mutex_enter(mutex); + sqlite3_mutex_enter(db->mutex); rc = sqlite3VdbeFinalize(v); + if( (rc&0xff)==SQLITE_MISUSE ) rc = SQLITE_OK; rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(mutex); + sqlite3LeaveMutexAndCloseZombie(db); } return rc; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index caa2bf670..3ccf71161 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2469,6 +2469,7 @@ void sqlite3VdbeDelete(Vdbe *p){ if( NEVER(p==0) ) return; db = p->db; + assert( sqlite3_mutex_held(db->mutex) ); if( p->pPrev ){ p->pPrev->pNext = p->pNext; }else{ |