Verify that the rollback-hook is invoked correctly when a malloc() failure occurs. (CVS 2824)
FossilOrigin-Name: 83c8ae5bee3b6bdb556d2e85fa260ba855742601
This commit is contained in:
+1
-13
@@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.274 2005/12/16 06:54:02 danielk1977 Exp $
|
||||
** $Id: btree.c,v 1.275 2005/12/16 15:24:29 danielk1977 Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@@ -5818,15 +5818,3 @@ int sqlite3BtreeSync(Btree *pBt, const char *zMaster){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||
/*
|
||||
** Reset the btree and underlying pager after a malloc() failure. Any
|
||||
** transaction that was active when malloc() failed is rolled back.
|
||||
*/
|
||||
int sqlite3BtreeReset(Btree *pBt){
|
||||
if( pBt->pCursor ) return SQLITE_BUSY;
|
||||
pBt->inTrans = TRANS_NONE;
|
||||
unlockBtreeIfUnused(pBt);
|
||||
return sqlite3pager_reset(pBt->pPager);
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-2
@@ -13,7 +13,7 @@
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.64 2005/08/27 16:36:49 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.65 2005/12/16 15:24:29 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@@ -74,7 +74,6 @@ int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
||||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
int sqlite3BtreeIsInStmt(Btree*);
|
||||
int sqlite3BtreeSync(Btree*, const char *zMaster);
|
||||
int sqlite3BtreeReset(Btree *);
|
||||
|
||||
const char *sqlite3BtreeGetFilename(Btree *);
|
||||
const char *sqlite3BtreeGetDirname(Btree *);
|
||||
|
||||
+6
-2
@@ -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.311 2005/12/16 06:54:02 danielk1977 Exp $
|
||||
** $Id: main.c,v 1.312 2005/12/16 15:24:29 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@@ -204,8 +204,12 @@ int sqlite3_close(sqlite3 *db){
|
||||
*/
|
||||
void sqlite3RollbackAll(sqlite3 *db){
|
||||
int i;
|
||||
int inTrans = 0;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt ){
|
||||
if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
|
||||
inTrans = 1;
|
||||
}
|
||||
sqlite3BtreeRollback(db->aDb[i].pBt);
|
||||
db->aDb[i].inTrans = 0;
|
||||
}
|
||||
@@ -215,7 +219,7 @@ void sqlite3RollbackAll(sqlite3 *db){
|
||||
}
|
||||
|
||||
/* If one has been configured, invoke the rollback-hook callback */
|
||||
if( db->xRollbackCallback ){
|
||||
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
|
||||
db->xRollbackCallback(db->pRollbackArg);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -12,7 +12,7 @@
|
||||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.147 2005/12/16 06:54:02 danielk1977 Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.148 2005/12/16 15:24:29 danielk1977 Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
@@ -1319,6 +1319,21 @@ void *sqlite3_update_hook(
|
||||
void*
|
||||
);
|
||||
|
||||
/*
|
||||
** Register a callback to be invoked whenever a transaction is rolled
|
||||
** back.
|
||||
**
|
||||
** The new callback function overrides any existing rollback-hook
|
||||
** callback. If there was an existing callback, then it's pArg value
|
||||
** (the third argument to sqlite3_rollback_hook() when it was registered)
|
||||
** is returned. Otherwise, NULL is returned.
|
||||
**
|
||||
** For the purposes of this API, a transaction is said to have been
|
||||
** rolled back if an explicit "ROLLBACK" statement is executed, or
|
||||
** an error or constraint causes an implicit rollback to occur. The
|
||||
** callback is not invoked if a transaction is automatically rolled
|
||||
** back because the database connection is closed.
|
||||
*/
|
||||
void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
||||
|
||||
/*
|
||||
|
||||
+11
-8
@@ -43,7 +43,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.505 2005/12/15 15:22:10 danielk1977 Exp $
|
||||
** $Id: vdbe.c,v 1.506 2005/12/16 15:24:29 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@@ -2299,16 +2299,19 @@ case OP_AutoCommit: { /* no-push */
|
||||
" transaction - SQL statements in progress", 0);
|
||||
rc = SQLITE_ERROR;
|
||||
}else if( i!=db->autoCommit ){
|
||||
db->autoCommit = i;
|
||||
if( pOp->p2 ){
|
||||
assert( i==1 );
|
||||
sqlite3RollbackAll(db);
|
||||
}else if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
|
||||
p->pTos = pTos;
|
||||
p->pc = pc;
|
||||
db->autoCommit = 1-i;
|
||||
p->rc = SQLITE_BUSY;
|
||||
return SQLITE_BUSY;
|
||||
db->autoCommit = 1;
|
||||
}else{
|
||||
db->autoCommit = i;
|
||||
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
|
||||
p->pTos = pTos;
|
||||
p->pc = pc;
|
||||
db->autoCommit = 1-i;
|
||||
p->rc = SQLITE_BUSY;
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
}
|
||||
return SQLITE_DONE;
|
||||
}else{
|
||||
|
||||
+12
-20
@@ -1177,12 +1177,12 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
return SQLITE_BUSY;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
p->rc = rc;
|
||||
xFunc = sqlite3BtreeRollback;
|
||||
sqlite3RollbackAll(db);
|
||||
}else{
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
}else{
|
||||
xFunc = sqlite3BtreeRollback;
|
||||
sqlite3RollbackAll(db);
|
||||
}
|
||||
}else{
|
||||
|
||||
@@ -1227,9 +1227,9 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
}else if( p->errorAction==OE_Abort ){
|
||||
xFunc = sqlite3BtreeRollbackStmt;
|
||||
}else{
|
||||
xFunc = sqlite3BtreeRollback;
|
||||
db->autoCommit = 1;
|
||||
abortOtherActiveVdbes(p);
|
||||
sqlite3RollbackAll(db);
|
||||
db->autoCommit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1240,20 +1240,14 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
*/
|
||||
assert(!xFunc ||
|
||||
xFunc==sqlite3BtreeCommitStmt ||
|
||||
xFunc==sqlite3BtreeRollbackStmt ||
|
||||
xFunc==sqlite3BtreeRollback
|
||||
xFunc==sqlite3BtreeRollbackStmt
|
||||
);
|
||||
if( xFunc==sqlite3BtreeRollback ){
|
||||
assert( p->rc!=SQLITE_OK );
|
||||
sqlite3RollbackAll(db);
|
||||
}else{
|
||||
for(i=0; xFunc && i<db->nDb; i++){
|
||||
int rc;
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
rc = xFunc(pBt);
|
||||
if( p->rc==SQLITE_OK ) p->rc = rc;
|
||||
}
|
||||
for(i=0; xFunc && i<db->nDb; i++){
|
||||
int rc;
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
rc = xFunc(pBt);
|
||||
if( p->rc==SQLITE_OK ) p->rc = rc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1270,9 +1264,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
/* Rollback or commit any schema changes that occurred. */
|
||||
if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
if( xFunc!=sqlite3BtreeRollback ){
|
||||
db->flags = (db->flags | SQLITE_InternChanges);
|
||||
}
|
||||
db->flags = (db->flags | SQLITE_InternChanges);
|
||||
}
|
||||
|
||||
/* We have successfully halted and closed the VM. Record this fact. */
|
||||
|
||||
Reference in New Issue
Block a user