Handle errors in saving cursor positions during a rollback by aborting all active statements. (CVS 3027)
FossilOrigin-Name: 5df9f022bfb22976f22b996bda169635354b825c
This commit is contained in:
parent
2b8c13e7a7
commit
8d34dfd656
20
manifest
20
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
32d45bcf746e7e926b8cc8bd038d66e7c2ec6562
|
||||
5df9f022bfb22976f22b996bda169635354b825c
|
37
src/btree.c
37
src/btree.c
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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}
|
||||
do_test shared_malloc-4.$::n.cleanup.2 {
|
||||
sqlite3_column_text $::STMT 0
|
||||
} {2222222222}
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user