aboutsummaryrefslogtreecommitdiff
path: root/src/vdbeaux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vdbeaux.c')
-rw-r--r--src/vdbeaux.c111
1 files changed, 76 insertions, 35 deletions
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 55ced4b21..60e785361 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -659,12 +659,11 @@ void sqlite3VdbeMakeReady(
}
#endif
p->pTos = &p->aStack[-1];
- p->pc = 0;
+ p->pc = -1;
p->rc = SQLITE_OK;
p->uniqueCnt = 0;
p->returnDepth = 0;
p->errorAction = OE_Abort;
- p->undoTransOnError = 0;
p->popStack = 0;
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
@@ -896,6 +895,32 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
return rc;
}
+/*
+** This routine checks that the sqlite3.activeVdbeCnt count variable
+** matches the number of vdbe's in the list sqlite3.pVdbe that are
+** currently active. An assertion fails if the two counts do not match.
+**
+** This is a no-op if NDEBUG is defined.
+*/
+#ifndef NDEBUG
+static void checkActiveVdbeCnt(sqlite *db){
+ Vdbe *p;
+ int cnt = 0;
+
+ p = db->pVdbe;
+ while( p ){
+ if( (p->magic==VDBE_MAGIC_RUN && p->pc>=0) || p->magic==VDBE_MAGIC_HALT ){
+ cnt++;
+ }
+ p = p->pNext;
+ }
+
+ assert( cnt==db->activeVdbeCnt );
+}
+#else
+#define checkActiveVdbeCnt(x)
+#endif
+
/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg. Return the result code.
@@ -906,10 +931,13 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){
sqlite *db = p->db;
int i;
+ int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
+ int needXcommit = 0;
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
sqlite3SetString(pzErrMsg, sqlite3_error_string(SQLITE_MISUSE), (char*)0);
- sqlite3Error(p->db, SQLITE_MISUSE, sqlite3_error_string(SQLITE_MISUSE),0);
+ sqlite3Error(p->db, SQLITE_MISUSE, 0 ,0);
+ db->activeVdbeCnt--;
return SQLITE_MISUSE;
}
if( p->zErrMsg ){
@@ -922,48 +950,61 @@ int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){
p->zErrMsg = 0;
}else if( p->rc ){
sqlite3SetString(pzErrMsg, sqlite3_error_string(p->rc), (char*)0);
- sqlite3Error(p->db, p->rc, "%s", sqlite3_error_string(p->rc) , 0);
+ sqlite3Error(p->db, p->rc, 0);
}else{
sqlite3Error(p->db, SQLITE_OK, 0);
}
Cleanup(p);
- if( p->rc!=SQLITE_OK ){
- switch( p->errorAction ){
- case OE_Abort: {
- if( !p->undoTransOnError ){
- for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt ){
- sqlite3BtreeRollbackStmt(db->aDb[i].pBt);
- }
- }
- break;
- }
- /* Fall through to ROLLBACK */
- }
- case OE_Rollback: {
- sqlite3RollbackAll(db);
- db->flags &= ~SQLITE_InTrans;
- db->onError = OE_Default;
- break;
- }
- default: {
- if( p->undoTransOnError ){
- sqlite3RollbackAll(db);
- db->flags &= ~SQLITE_InTrans;
- db->onError = OE_Default;
+
+ /* Figure out which function to call on the btree backends that
+ ** have active transactions.
+ */
+ checkActiveVdbeCnt(db);
+ if( db->autoCommit && db->activeVdbeCnt==1 ){
+ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
+ xFunc = sqlite3BtreeCommit;
+ needXcommit = 1;
+ }else{
+ xFunc = sqlite3BtreeRollback;
+ }
+ }else{
+ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
+ xFunc = sqlite3BtreeCommitStmt;
+ }else if( p->errorAction==OE_Abort ){
+ xFunc = sqlite3BtreeRollbackStmt;
+ }else{
+ xFunc = sqlite3BtreeRollback;
+ db->autoCommit = 1;
+ }
+ }
+
+ for(i=0; xFunc && i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( sqlite3BtreeIsInTrans(pBt) ){
+ int rc;
+ if( db->xCommitCallback && needXcommit ){
+ if( db->xCommitCallback(db->pCommitArg)!=0 ){
+ p->rc = SQLITE_CONSTRAINT;
+ sqlite3Error(db, SQLITE_CONSTRAINT, 0);
+ xFunc = sqlite3BtreeRollback;
}
- break;
+ needXcommit = 0;
}
+ rc = xFunc(pBt);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
}
+ }
+
+
+ if( p->rc!=SQLITE_OK ){
sqlite3RollbackInternalChanges(db);
}
- for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt && db->aDb[i].inTrans==2 ){
- sqlite3BtreeCommitStmt(db->aDb[i].pBt);
- db->aDb[i].inTrans = 1;
- }
+
+ if( (p->magic==VDBE_MAGIC_RUN && p->pc>=0) || p->magic==VDBE_MAGIC_HALT ){
+ db->activeVdbeCnt--;
}
- assert( p->pTos<&p->aStack[p->pc] || sqlite3_malloc_failed==1 );
+
+ assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );
#ifdef VDBE_PROFILE
{
FILE *out = fopen("vdbe_profile.out", "a");