Handle errors in saving cursor positions during a rollback by aborting all active statements. (CVS 3027)

FossilOrigin-Name: 5df9f022bfb22976f22b996bda169635354b825c
This commit is contained in:
danielk1977 2006-01-24 16:37:57 +00:00
parent 2b8c13e7a7
commit 8d34dfd656
7 changed files with 111 additions and 37 deletions

View File

@ -1,5 +1,5 @@
C Save\sthe\sposition\sof\sany\sopen\scursors\sbefore\sa\srollback.\s(CVS\s3026)
D 2006-01-24T14:21:24
C Handle\serrors\sin\ssaving\scursor\spositions\sduring\sa\srollback\sby\saborting\sall\sactive\sstatements.\s(CVS\s3027)
D 2006-01-24T16:37:58
F Makefile.in 53841eb72e9eeb6030a8ce28c2595a92f440fd10
F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -34,7 +34,7 @@ F src/alter.c 90b779cf00489535cab6490df6dc050f40e4e874
F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a
F src/attach.c d73a3505de3fb9e373d0a158978116c4212031d0
F src/auth.c 9ae84d2d94eb96195e04515715e08e85963e96c2
F src/btree.c 5b71740985d4845f3a6ac7e0bb809e41d25830d4
F src/btree.c f45f57e6cbd3b3db947cdd699db64e5215d20b2a
F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184
F src/build.c feaa61e769d7887ffeaa060d746638c7b3e994ef
F src/callback.c 1bf497306c32229114f826707054df7ebe10abf2
@ -48,7 +48,7 @@ F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
F src/insert.c 7e931b7f06afbcefcbbaab175c02eff8268db33f
F src/legacy.c 86b669707b3cefd570e34154e2f6457547d1df4f
F src/main.c dc3fc9b02b1a022574d6e12d25abe58b93b85b1f
F src/main.c 2693776249865dc69b97904205638e84a34a059c
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
F src/os.c 59f05de8c5777c34876607114a2fbe55ae578235
F src/os.h 93035a0e3b9dd05cdd0aaef32ea28ca28e02fe78
@ -70,7 +70,7 @@ F src/select.c daee9b20702ba51cf3807fc1b130edd8846e3e48
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da
F src/sqlite.h.in 492580f7e3ff71eb43193eb7bb98e2d549889ce3
F src/sqliteInt.h 35a3c3556abfca796cf44fea83c9f04385efcfb6
F src/sqliteInt.h 0121298397ac14eb468ab1ba9d488ac7ed7d88a1
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
F src/tclsqlite.c 7764ab34df617b3d3cfd5f0fdf3444ed219c11d6
F src/test1.c ce715e15c8045c598fe83a17f862ddeedf60c057
@ -91,7 +91,7 @@ F src/vdbe.c 799e6280aef25bae55d2da21b5a6dbdda5e76e36
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
F src/vdbeInt.h eb3f86ab08ef11635bc78eb88c3ff13f923c233b
F src/vdbeapi.c dcb2636f49b4807e34960d52a2fc257b3a751140
F src/vdbeaux.c 0c27d3b3bd8dda7ed73eb8fcfa74350ca6633895
F src/vdbeaux.c bc90137791c9442ddd9e81453f10a23688d19dbf
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
F src/vdbemem.c 2034e93b32c14bda6e306bb54e3a8e930b963027
F src/where.c 8409e00fa2cb5fce873b4c911165cfed097e9c49
@ -228,7 +228,7 @@ F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6
F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5
F test/shared.test 0ed247941236788c255b3b29b5a82d5ca71b6432
F test/shared2.test 3466dc54ca69a3c50ac259e106fb5cd067b8cd53
F test/shared_err.test 162ad76d510370e4d3878cb6c376e1292db06005
F test/shared_err.test 299a9180a6376b2089e8e0d469f383fe91bfa4ff
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/subquery.test ae324ee928c5fb463a3ce08a8860d6e7f1ca5797
F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
@ -344,7 +344,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P c30705a00d7d9d61fb9cb47a1019b1a186d690a7
R 6675c7ec185eda4043b15c5e61211396
P 32d45bcf746e7e926b8cc8bd038d66e7c2ec6562
R bfc84cb6ae1c5988a33aa090aaeb35d5
U danielk1977
Z 32002e918852056122387d8fed3cdfe2
Z b319ec5ca674b878a1973ce33be953dd

View File

@ -1 +1 @@
32d45bcf746e7e926b8cc8bd038d66e7c2ec6562
5df9f022bfb22976f22b996bda169635354b825c

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.310 2006/01/24 14:21:24 danielk1977 Exp $
** $Id: btree.c,v 1.311 2006/01/24 16:37:58 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@ -1693,9 +1693,6 @@ int sqlite3BtreeClose(Btree *p){
ThreadData *pTsd;
#endif
/* Drop any table-locks */
unlockAllTables(p);
/* Close all cursors opened via this handle. */
pCur = pBt->pCursor;
while( pCur ){
@ -1706,7 +1703,10 @@ int sqlite3BtreeClose(Btree *p){
}
}
/* Rollback any active transaction and free the handle structure */
/* Rollback any active transaction and free the handle structure.
** The call to sqlite3BtreeRollback() drops any table-locks held by
** this handle.
*/
sqlite3BtreeRollback(p);
sqliteFree(p);
@ -2538,21 +2538,40 @@ void sqlite3BtreeCursorList(Btree *p){
** are no active cursors, it also releases the read lock.
*/
int sqlite3BtreeRollback(Btree *p){
int rc = SQLITE_OK;
int rc;
BtShared *pBt = p->pBt;
MemPage *pPage1;
rc = saveAllCursors(pBt, 0, 0);
#ifndef SQLITE_OMIT_SHARED_CACHE
if( rc!=SQLITE_OK ){
return rc;
/* This is a horrible situation. An IO or malloc() error occured whilst
** trying to save cursor positions. If this is an automatic rollback (as
** the result of a constraint, malloc() failure or IO error) then
** the cache may be internally inconsistent (not contain valid trees) so
** we cannot simply return the error to the caller. Instead, abort
** all queries that may be using any of the cursors that failed to save.
*/
while( pBt->pCursor ){
sqlite3 *db = pBt->pCursor->pBtree->pSqlite;
if( db ){
sqlite3AbortOtherActiveVdbes(db, 0);
}
}
}
#endif
btreeIntegrity(p);
unlockAllTables(p);
if( p->inTrans==TRANS_WRITE ){
assert( TRANS_WRITE==pBt->inTransaction );
int rc2;
assert( TRANS_WRITE==pBt->inTransaction );
rc2 = sqlite3pager_rollback(pBt->pPager);
if( rc2!=SQLITE_OK ){
rc = rc2;
}
rc = sqlite3pager_rollback(pBt->pPager);
/* The rollback may have destroyed the pPage1->aData value. So
** call getPage() on page 1 again to make sure pPage1->aData is
** set correctly. */

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.330 2006/01/24 13:09:33 danielk1977 Exp $
** $Id: main.c,v 1.331 2006/01/24 16:37:58 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -131,9 +131,6 @@ int sqlite3_close(sqlite3 *db){
return SQLITE_ERROR;
}
/* sqlite3_close() may not invoke sqliteMalloc(). */
sqlite3MallocDisallow();
for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j];
if( pDb->pBt ){
@ -177,7 +174,6 @@ int sqlite3_close(sqlite3 *db){
*/
sqliteFree(db->aDb[1].pSchema);
sqliteFree(db);
sqlite3MallocAllow();
sqlite3ReleaseThreadData();
return SQLITE_OK;
}

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.478 2006/01/23 13:28:54 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.479 2006/01/24 16:37:58 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -1747,6 +1747,7 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
int sqlite3ApiExit(sqlite3 *db, int);
int sqlite3MallocFailed(void);
void sqlite3FailedMalloc(void);
void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *);
#ifndef SQLITE_OMIT_SHARED_CACHE
void sqlite3TableLock(Parse *, int, int, u8, const char *);

View File

@ -1101,10 +1101,10 @@ static int vdbeCommit(sqlite3 *db){
** aborted so that they do not have data rolled out from underneath
** them leading to a segfault.
*/
static void abortOtherActiveVdbes(Vdbe *pVdbe){
void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
Vdbe *pOther;
for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){
if( pOther==pVdbe ) continue;
for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
if( pOther==pExcept ) continue;
if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
closeAllCursors(pOther);
pOther->aborted = 1;
@ -1237,7 +1237,7 @@ int sqlite3VdbeHalt(Vdbe *p){
/* We are forced to roll back the active transaction. Before doing
** so, abort any other statements this handle currently has active.
*/
abortOtherActiveVdbes(p);
sqlite3AbortOtherActiveVdbes(db, p);
sqlite3RollbackAll(db);
db->autoCommit = 1;
}
@ -1274,7 +1274,7 @@ int sqlite3VdbeHalt(Vdbe *p){
}else if( p->errorAction==OE_Abort ){
xFunc = sqlite3BtreeRollbackStmt;
}else{
abortOtherActiveVdbes(p);
sqlite3AbortOtherActiveVdbes(db, p);
sqlite3RollbackAll(db);
db->autoCommit = 1;
}

View File

@ -13,7 +13,7 @@
# cache context. What happens to connection B if one connection A encounters
# an IO-error whilst reading or writing the file-system?
#
# $Id: shared_err.test,v 1.8 2006/01/24 11:30:27 danielk1977 Exp $
# $Id: shared_err.test,v 1.9 2006/01/24 16:37:59 danielk1977 Exp $
proc skip {args} {}
@ -311,11 +311,14 @@ do_malloc_test 4 -tclprep {
}
} -cleanup {
do_test shared_malloc-4.$::n.cleanup.1 {
sqlite3_step $::STMT
} {SQLITE_ROW}
set ::rc [sqlite3_step $::STMT]
expr {$::rc=="SQLITE_ROW" || $::rc=="SQLITE_ABORT"}
} {1}
if {$::rc=="SQLITE_ROW"} {
do_test shared_malloc-4.$::n.cleanup.2 {
sqlite3_column_text $::STMT 0
} {2222222222}
}
do_test shared_malloc-4.$::n.cleanup.3 {
sqlite3_finalize $::STMT
} {SQLITE_OK}
@ -349,6 +352,61 @@ do_test shared_misuse-7.1 {
set msg
} {library routine called out of sequence}
# Again provoke a malloc() failure when a cursor position is being saved,
# this time during a ROLLBACK operation by some other handle.
#
# The library should return an SQLITE_NOMEM to the caller. The query that
# owns the cursor (the one for which the position is not saved) should
# be aborted.
#
set ::aborted 0
do_malloc_test 8 -tclprep {
sqlite3 db2 test.db
execsql {
PRAGMA read_uncommitted = 1;
BEGIN;
CREATE TABLE t1(a, b, UNIQUE(a, b));
} db2
for {set i 0} {$i < 2} {incr i} {
set a [string repeat $i 10]
set b [string repeat $i 2000]
execsql {INSERT INTO t1 VALUES($a, $b)} db2
}
execsql {COMMIT} db2
set ::DB2 [sqlite3_connection_pointer db2]
set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
sqlite3_step $::STMT ;# Cursor points at 0000000000
sqlite3_step $::STMT ;# Cursor points at 1111111111
} -tclbody {
execsql {
BEGIN;
INSERT INTO t1 VALUES(6, NULL);
ROLLBACK;
}
} -cleanup {
do_test shared_malloc-8.$::n.cleanup.1 {
lrange [execsql {
SELECT a FROM t1;
} db2] 0 1
} {0000000000 1111111111}
do_test shared_malloc-8.$::n.cleanup.2 {
set rc1 [sqlite3_step $::STMT]
set rc2 [sqlite3_finalize $::STMT]
if {$rc1=="SQLITE_ABORT"} {
incr ::aborted
}
expr {
($rc1=="SQLITE_DONE" && $rc2=="SQLITE_OK") ||
($rc1=="SQLITE_ABORT" && $rc2=="SQLITE_OK")
}
} {1}
db2 close
}
do_test shared_malloc-8.X {
# Test that one or more queries were aborted due to the malloc() failure.
expr $::aborted>=1
} {1}
catch {db close}
sqlite3_enable_shared_cache $::enable_shared_cache
finish_test