From 617dc8602d049822bf3d488dc2f09cb762fa029b Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 16 May 2013 11:57:28 +0000 Subject: [PATCH] In sqlite3_close_v2(), do not attempt to roll back a transaction if there exist active statement objects. Any open transaction will be rolled back when the last of these statement objects is finalized. FossilOrigin-Name: d11e76072a17fe833b87595d9d79f2c4b0b09cb3 --- manifest | 17 ++++++----- manifest.uuid | 2 +- src/main.c | 20 +++++++++---- src/test1.c | 25 ++++++++++++++++ test/close.test | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 test/close.test diff --git a/manifest b/manifest index ec49a5a18d..f3e24afc9e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Treat\sidentifiers\sin\sthe\sHAVING\sclause\sthe\ssame\sas\sin\sthe\sWHERE\sclause.\nOnly\sconsider\sAS\snames\sfrom\sthe\sresult\sset\sto\smatch\sif\sthere\sare\sno\sother\nmatches.\s\sContinuation\sof\sthe\sfix\sfor\s[2500cdb9be05].\s\sThis\scheck-in\nfixes\sa\sbug\sfound\sby\s[http://www.sqlite.org/sqllogictest/\s|\sSqlLogicTest]\nduring\srelease\stesting\sfor\sversion\s3.7.17. -D 2013-05-16T01:02:45.632 +C In\ssqlite3_close_v2(),\sdo\snot\sattempt\sto\sroll\sback\sa\stransaction\sif\sthere\sexist\sactive\sstatement\sobjects.\sAny\sopen\stransaction\swill\sbe\srolled\sback\swhen\sthe\slast\sof\sthese\sstatement\sobjects\sis\sfinalized. +D 2013-05-16T11:57:28.062 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 101fc5d712bfa348313987e5728ead013dc82fba F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -160,7 +160,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2 -F src/main.c ccbac976228cd21209ede2bdc82bbf22b0ddf197 +F src/main.c c6419ef57392b1aa0cf6ed9c80dfc06b153fe299 F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa @@ -201,7 +201,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c 2ecec9937e69bc17560ad886da35195daa7261b8 -F src/test1.c ab9dd4fc486a2542f57a2ca17d74fc7f28dfd05a +F src/test1.c 045d45a4f7eeb5d963f8fc150339f1bad279011a F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -338,6 +338,7 @@ F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1 F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287 +F test/close.test e37610d60e9c9b9979a981f3f50071d7dff28616 F test/closure01.test dbb28f1ea9eeaf0a53ec5bc0fed352e479def8c7 F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91 F test/collate1.test fd02c4d8afc71879c4bb952586389961a21fb0ce @@ -1064,7 +1065,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7e76889d675e4c646158f7f9188d25f155c18876 -R 734d69ab143a2741580e8434cd6321b1 -U drh -Z 6441f17ff50e2e08c247bf534d4dc934 +P 9ffff3d05226bbd01a0745dd0a511776358253c0 +R 1a17d95315a3a4d605dc90092cbaec4e +U dan +Z 6e4c531756ef5b922f59a9b9e491858b diff --git a/manifest.uuid b/manifest.uuid index b0132386fc..99b6ba1500 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9ffff3d05226bbd01a0745dd0a511776358253c0 \ No newline at end of file +d11e76072a17fe833b87595d9d79f2c4b0b09cb3 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 763adbfe8e..39f60421e6 100644 --- a/src/main.c +++ b/src/main.c @@ -848,12 +848,6 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ return SQLITE_BUSY; } - /* If a transaction is open, roll it back. This also ensures that if - ** any database schemas have been modified by the current transaction - ** they are reset. And that the required b-tree mutex is held to make - ** the the pager rollback and schema reset an atomic operation. */ - sqlite3RollbackAll(db, SQLITE_OK); - #ifdef SQLITE_ENABLE_SQLLOG if( sqlite3GlobalConfig.xSqllog ){ /* Closing the handle. Fourth parameter is passed the value 2. */ @@ -908,6 +902,12 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ ** go ahead and free all resources. */ + /* If a transaction is open, roll it back. This also ensures that if + ** any database schemas have been modified by an uncommitted transaction + ** they are reset. And that the required b-tree mutex is held to make + ** the pager rollback and schema reset an atomic operation. */ + sqlite3RollbackAll(db, SQLITE_OK); + /* Free any outstanding Savepoint structures. */ sqlite3CloseSavepoints(db); @@ -1008,7 +1008,15 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ int inTrans = 0; assert( sqlite3_mutex_held(db->mutex) ); sqlite3BeginBenignMalloc(); + + /* Obtain all b-tree mutexes before making any calls to BtreeRollback(). + ** This is important in case the transaction being rolled back has + ** modified the database schema. If the b-tree mutexes are not taken + ** here, then another shared-cache connection might sneak in between + ** the database rollback and schema reset, which can cause false + ** corruption reports in some cases. */ sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ diff --git a/src/test1.c b/src/test1.c index 59de1db8e5..a638e480ad 100644 --- a/src/test1.c +++ b/src/test1.c @@ -681,6 +681,30 @@ static int sqlite_test_close( return TCL_OK; } +/* +** Usage: sqlite3_close_v2 DB +** +** Closes the database opened by sqlite3_open. +*/ +static int sqlite_test_close_v2( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + sqlite3 *db; + int rc; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " FILENAME\"", 0); + return TCL_ERROR; + } + if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; + rc = sqlite3_close_v2(db); + Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); + return TCL_OK; +} + /* ** Implementation of the x_coalesce() function. ** Return the first argument non-NULL argument. @@ -6077,6 +6101,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, #endif { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, + { "sqlite3_close_v2", (Tcl_CmdProc*)sqlite_test_close_v2 }, { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, diff --git a/test/close.test b/test/close.test new file mode 100644 index 0000000000..355a8865b5 --- /dev/null +++ b/test/close.test @@ -0,0 +1,79 @@ +# 2013 May 14 +# +# 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. +# +#*********************************************************************** +# +# Test some specific circumstances to do with shared cache mode. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix close + +do_execsql_test 1.0 { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('one'); + INSERT INTO t1 VALUES('two'); + INSERT INTO t1 VALUES('three'); +} +db close + +do_test 1.1 { + set DB [sqlite3_open test.db] + sqlite3_close_v2 $DB +} {SQLITE_OK} + +do_test 1.2.1 { + set DB [sqlite3_open test.db] + set STMT [sqlite3_prepare $DB "SELECT * FROM t1" -1 dummy] + sqlite3_close_v2 $DB +} {SQLITE_OK} +do_test 1.2.2 { + sqlite3_finalize $STMT +} {SQLITE_OK} + +do_test 1.3.1 { + set DB [sqlite3_open test.db] + set STMT [sqlite3_prepare $DB "SELECT * FROM t1" -1 dummy] + sqlite3_step $STMT + sqlite3_close_v2 $DB +} {SQLITE_OK} + +do_test 1.3.2 { + sqlite3_column_text $STMT 0 +} {one} + +do_test 1.3.3 { + sqlite3_finalize $STMT +} {SQLITE_OK} + +do_test 1.4.1 { + set DB [sqlite3_open test.db] + set STMT [sqlite3_prepare $DB "SELECT * FROM t1" -1 dummy] + sqlite3_step $STMT + sqlite3_close_v2 $DB +} {SQLITE_OK} + +do_test 1.4.2 { + list [sqlite3_step $STMT] [sqlite3_column_text $STMT 0] +} {SQLITE_ROW two} + +do_test 1.4.3 { + list [catch { + sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 dummy + } msg] $msg +} {1 {(21) library routine called out of sequence}} + +do_test 1.4.4 { + sqlite3_finalize $STMT +} {SQLITE_OK} + +finish_test + -- 2.47.2