/ Check-in [9b66c79e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Change the ROLLBACK command so that pending statements to not block it. The pending statements instead return SQLITE_ABORT upon next access. Note: This causes separate shared-cache connections in read_uncommitted mode to abort as well.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | nonblocking-rollback
Files: files | file ages | folders
SHA1: 9b66c79e054c8a109d1ee8d35fed1c42814c330d
User & Date: drh 2012-02-13 16:43:16
Context
2012-02-13
17:01
Add the new SQLITE_ABORT_ROLLBACK extended error code to be returned for statements that are cancelled due to a rollback. Closed-Leaf check-in: 549f4fd0 user: drh tags: nonblocking-rollback
16:43
Change the ROLLBACK command so that pending statements to not block it. The pending statements instead return SQLITE_ABORT upon next access. Note: This causes separate shared-cache connections in read_uncommitted mode to abort as well. check-in: 9b66c79e user: drh tags: nonblocking-rollback
10:00
Changes to various test scripts so that veryquick.test runs with OMIT_COMPOUND_SELECT defined. check-in: 76bb649e user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/backup.c.

564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
    while( *pp!=p ){
      pp = &(*pp)->pNext;
    }
    *pp = p->pNext;
  }

  /* If a transaction is still open on the Btree, roll it back. */
  sqlite3BtreeRollback(p->pDest);

  /* Set the error code of the destination database handle. */
  rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
  sqlite3Error(p->pDestDb, rc, 0);

  /* Exit the mutexes and free the backup context structure. */
  if( p->pDestDb ){







|







564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
    while( *pp!=p ){
      pp = &(*pp)->pNext;
    }
    *pp = p->pNext;
  }

  /* If a transaction is still open on the Btree, roll it back. */
  sqlite3BtreeRollback(p->pDest, SQLITE_OK);

  /* Set the error code of the destination database handle. */
  rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
  sqlite3Error(p->pDestDb, rc, 0);

  /* Exit the mutexes and free the backup context structure. */
  if( p->pDestDb ){

Changes to src/btree.c.

2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
....
3275
3276
3277
3278
3279
3280
3281

3282
3283
3284
3285
3286
3287
3288
....
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310

3311
3312

3313
3314
3315

3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
    }
  }

  /* Rollback any active transaction and free the handle structure.
  ** The call to sqlite3BtreeRollback() drops any table-locks held by
  ** this handle.
  */
  sqlite3BtreeRollback(p);
  sqlite3BtreeLeave(p);

  /* If there are still other outstanding references to the shared-btree
  ** structure, return now. The remainder of this procedure cleans 
  ** up the shared-btree.
  */
  assert( p->wantToLock==0 && p->locked==0 );
................................................................................
** the rollback.  The rollback may have deleted tables
** or moved root pages, so it is not sufficient to
** save the state of the cursor.  The cursor must be
** invalidated.
*/
void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
  BtCursor *p;

  sqlite3BtreeEnter(pBtree);
  for(p=pBtree->pBt->pCursor; p; p=p->pNext){
    int i;
    sqlite3BtreeClearCursor(p);
    p->eState = CURSOR_FAULT;
    p->skipNext = errCode;
    for(i=0; i<=p->iPage; i++){
................................................................................
** invalided by this operation.  Any attempt to use a cursor
** that was open at the beginning of this operation will result
** in an error.
**
** This will release the write lock on the database file.  If there
** are no active cursors, it also releases the read lock.
*/
int sqlite3BtreeRollback(Btree *p){
  int rc;
  BtShared *pBt = p->pBt;
  MemPage *pPage1;

  sqlite3BtreeEnter(p);

  rc = saveAllCursors(pBt, 0, 0);
#ifndef SQLITE_OMIT_SHARED_CACHE

  if( rc!=SQLITE_OK ){
    /* This is a horrible situation. An IO or malloc() error occurred 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.
    */
    sqlite3BtreeTripAllCursors(p, rc);
  }
#endif
  btreeIntegrity(p);

  if( p->inTrans==TRANS_WRITE ){
    int rc2;

    assert( TRANS_WRITE==pBt->inTransaction );
    rc2 = sqlite3PagerRollback(pBt->pPager);







|







 







>







 







|





>
|
<
>
|
<
<
>
|
<
<
<
<
|

<







2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
....
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
....
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313

3314
3315


3316
3317




3318
3319

3320
3321
3322
3323
3324
3325
3326
    }
  }

  /* Rollback any active transaction and free the handle structure.
  ** The call to sqlite3BtreeRollback() drops any table-locks held by
  ** this handle.
  */
  sqlite3BtreeRollback(p, SQLITE_OK);
  sqlite3BtreeLeave(p);

  /* If there are still other outstanding references to the shared-btree
  ** structure, return now. The remainder of this procedure cleans 
  ** up the shared-btree.
  */
  assert( p->wantToLock==0 && p->locked==0 );
................................................................................
** the rollback.  The rollback may have deleted tables
** or moved root pages, so it is not sufficient to
** save the state of the cursor.  The cursor must be
** invalidated.
*/
void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
  BtCursor *p;
  if( pBtree==0 ) return;
  sqlite3BtreeEnter(pBtree);
  for(p=pBtree->pBt->pCursor; p; p=p->pNext){
    int i;
    sqlite3BtreeClearCursor(p);
    p->eState = CURSOR_FAULT;
    p->skipNext = errCode;
    for(i=0; i<=p->iPage; i++){
................................................................................
** invalided by this operation.  Any attempt to use a cursor
** that was open at the beginning of this operation will result
** in an error.
**
** This will release the write lock on the database file.  If there
** are no active cursors, it also releases the read lock.
*/
int sqlite3BtreeRollback(Btree *p, int tripCode){
  int rc;
  BtShared *pBt = p->pBt;
  MemPage *pPage1;

  sqlite3BtreeEnter(p);
  if( tripCode==SQLITE_OK ){
    rc = tripCode = saveAllCursors(pBt, 0, 0);

  }else{
    rc = SQLITE_OK;


  }
  if( tripCode ){




    sqlite3BtreeTripAllCursors(p, tripCode);
  }

  btreeIntegrity(p);

  if( p->inTrans==TRANS_WRITE ){
    int rc2;

    assert( TRANS_WRITE==pBt->inTransaction );
    rc2 = sqlite3PagerRollback(pBt->pPager);

Changes to src/btree.h.

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
int sqlite3BtreeGetReserve(Btree*);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int);
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*,int);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeIsInBackup(Btree*);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *pBtree);







|







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
int sqlite3BtreeGetReserve(Btree*);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int);
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*,int);
int sqlite3BtreeBeginStmt(Btree*,int);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeIsInBackup(Btree*);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *pBtree);

Changes to src/main.c.

845
846
847
848
849
850
851
852



853
854
855
856
857
858
859
860

861
862
863
864
865
866
867
868
869
870
871
    sqlite3_free(db->lookaside.pStart);
  }
  sqlite3_free(db);
  return SQLITE_OK;
}

/*
** Rollback all database files.



*/
void sqlite3RollbackAll(sqlite3 *db){
  int i;
  int inTrans = 0;
  assert( sqlite3_mutex_held(db->mutex) );
  sqlite3BeginBenignMalloc();
  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;
    }
  }
  sqlite3VtabRollback(db);
  sqlite3EndBenignMalloc();

  if( db->flags&SQLITE_InternChanges ){







|
>
>
>

|





|
>
|


|







845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
    sqlite3_free(db->lookaside.pStart);
  }
  sqlite3_free(db);
  return SQLITE_OK;
}

/*
** Rollback all database files.  If tripCode is not SQLITE_OK, then
** any open cursors are invalidated ("tripped" - as in "tripping a circuit
** breaker") and made to return tripCode if there are any further
** attempts to use that cursor.
*/
void sqlite3RollbackAll(sqlite3 *db, int tripCode){
  int i;
  int inTrans = 0;
  assert( sqlite3_mutex_held(db->mutex) );
  sqlite3BeginBenignMalloc();
  for(i=0; i<db->nDb; i++){
    Btree *p = db->aDb[i].pBt;
    if( p ){
      if( sqlite3BtreeIsInTrans(p) ){
        inTrans = 1;
      }
      sqlite3BtreeRollback(p, tripCode);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3VtabRollback(db);
  sqlite3EndBenignMalloc();

  if( db->flags&SQLITE_InternChanges ){

Changes to src/sqliteInt.h.

2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
int sqlite3ExprListCompare(ExprList*, ExprList*);
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*);
void sqlite3PrngSaveState(void);
void sqlite3PrngRestoreState(void);
void sqlite3PrngResetState(void);
void sqlite3RollbackAll(sqlite3*);
void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
void sqlite3Savepoint(Parse*, int, Token*);
void sqlite3CloseSavepoints(sqlite3 *);







|







2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
int sqlite3ExprListCompare(ExprList*, ExprList*);
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*);
void sqlite3PrngSaveState(void);
void sqlite3PrngRestoreState(void);
void sqlite3PrngResetState(void);
void sqlite3RollbackAll(sqlite3*,int);
void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
void sqlite3Savepoint(Parse*, int, Token*);
void sqlite3CloseSavepoints(sqlite3 *);

Changes to src/vdbe.c.

2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
....
2714
2715
2716
2717
2718
2719
2720



2721
2722
2723
2724
2725
2726
2727
....
2782
2783
2784
2785
2786
2787
2788

2789
2790
2791
2792
2793
2794
2795
2796


2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
      pSavepoint = pSavepoint->pNext
    ){
      iSavepoint++;
    }
    if( !pSavepoint ){
      sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", zName);
      rc = SQLITE_ERROR;
    }else if( 
        db->writeVdbeCnt>0 || (p1==SAVEPOINT_ROLLBACK && db->activeVdbeCnt>1) 
    ){
      /* It is not possible to release (commit) a savepoint if there are 
      ** active write statements. It is not possible to rollback a savepoint
      ** if there are any active statements at all.
      */
      sqlite3SetString(&p->zErrMsg, db, 
        "cannot %s savepoint - SQL statements in progress",
        (p1==SAVEPOINT_ROLLBACK ? "rollback": "release")
      );
      rc = SQLITE_BUSY;
    }else{

      /* Determine whether or not this is a transaction savepoint. If so,
      ** and this is a RELEASE command, then the current transaction 
      ** is committed. 
................................................................................
          p->rc = rc = SQLITE_BUSY;
          goto vdbe_return;
        }
        db->isTransactionSavepoint = 0;
        rc = p->rc;
      }else{
        iSavepoint = db->nSavepoint - iSavepoint - 1;



        for(ii=0; ii<db->nDb; ii++){
          rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
          if( rc!=SQLITE_OK ){
            goto abort_due_to_error;
          }
        }
        if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
................................................................................
  desiredAutoCommit = pOp->p1;
  iRollback = pOp->p2;
  turnOnAC = desiredAutoCommit && !db->autoCommit;
  assert( desiredAutoCommit==1 || desiredAutoCommit==0 );
  assert( desiredAutoCommit==1 || iRollback==0 );
  assert( db->activeVdbeCnt>0 );  /* At least this one VM is active */


  if( turnOnAC && iRollback && db->activeVdbeCnt>1 ){
    /* If this instruction implements a ROLLBACK and other VMs are
    ** still running, and a transaction is active, return an error indicating
    ** that the other VMs must complete first. 
    */
    sqlite3SetString(&p->zErrMsg, db, "cannot rollback transaction - "
        "SQL statements in progress");
    rc = SQLITE_BUSY;


  }else if( turnOnAC && !iRollback && db->writeVdbeCnt>0 ){
    /* If this instruction implements a COMMIT and other VMs are writing
    ** return an error indicating that the other VMs must complete first. 
    */
    sqlite3SetString(&p->zErrMsg, db, "cannot commit transaction - "
        "SQL statements in progress");
    rc = SQLITE_BUSY;
  }else if( desiredAutoCommit!=db->autoCommit ){
    if( iRollback ){
      assert( desiredAutoCommit==1 );
      sqlite3RollbackAll(db);
      db->autoCommit = 1;
    }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
      goto vdbe_return;
    }else{
      db->autoCommit = (u8)desiredAutoCommit;
      if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
        p->pc = pc;







|
<
<

|
<


|
<







 







>
>
>







 







>








>
>
|









|







2680
2681
2682
2683
2684
2685
2686
2687


2688
2689

2690
2691
2692

2693
2694
2695
2696
2697
2698
2699
....
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
....
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
      pSavepoint = pSavepoint->pNext
    ){
      iSavepoint++;
    }
    if( !pSavepoint ){
      sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", zName);
      rc = SQLITE_ERROR;
    }else if( db->writeVdbeCnt>0 && p1==SAVEPOINT_RELEASE ){


      /* It is not possible to release (commit) a savepoint if there are 
      ** active write statements.

      */
      sqlite3SetString(&p->zErrMsg, db, 
        "cannot release savepoint - SQL statements in progress"

      );
      rc = SQLITE_BUSY;
    }else{

      /* Determine whether or not this is a transaction savepoint. If so,
      ** and this is a RELEASE command, then the current transaction 
      ** is committed. 
................................................................................
          p->rc = rc = SQLITE_BUSY;
          goto vdbe_return;
        }
        db->isTransactionSavepoint = 0;
        rc = p->rc;
      }else{
        iSavepoint = db->nSavepoint - iSavepoint - 1;
        for(ii=0; ii<db->nDb; ii++){
          sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT);
        }
        for(ii=0; ii<db->nDb; ii++){
          rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
          if( rc!=SQLITE_OK ){
            goto abort_due_to_error;
          }
        }
        if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
................................................................................
  desiredAutoCommit = pOp->p1;
  iRollback = pOp->p2;
  turnOnAC = desiredAutoCommit && !db->autoCommit;
  assert( desiredAutoCommit==1 || desiredAutoCommit==0 );
  assert( desiredAutoCommit==1 || iRollback==0 );
  assert( db->activeVdbeCnt>0 );  /* At least this one VM is active */

#if 0
  if( turnOnAC && iRollback && db->activeVdbeCnt>1 ){
    /* If this instruction implements a ROLLBACK and other VMs are
    ** still running, and a transaction is active, return an error indicating
    ** that the other VMs must complete first. 
    */
    sqlite3SetString(&p->zErrMsg, db, "cannot rollback transaction - "
        "SQL statements in progress");
    rc = SQLITE_BUSY;
  }else
#endif
  if( turnOnAC && !iRollback && db->writeVdbeCnt>0 ){
    /* If this instruction implements a COMMIT and other VMs are writing
    ** return an error indicating that the other VMs must complete first. 
    */
    sqlite3SetString(&p->zErrMsg, db, "cannot commit transaction - "
        "SQL statements in progress");
    rc = SQLITE_BUSY;
  }else if( desiredAutoCommit!=db->autoCommit ){
    if( iRollback ){
      assert( desiredAutoCommit==1 );
      sqlite3RollbackAll(db, SQLITE_ABORT);
      db->autoCommit = 1;
    }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
      goto vdbe_return;
    }else{
      db->autoCommit = (u8)desiredAutoCommit;
      if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
        p->pc = pc;

Changes to src/vdbeaux.c.

1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
....
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
....
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
....
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
  assert( cnt==db->activeVdbeCnt );
  assert( nWrite==db->writeVdbeCnt );
}
#else
#define checkActiveVdbeCnt(x)
#endif

/*
** For every Btree that in database connection db which 
** has been modified, "trip" or invalidate each cursor in
** that Btree might have been modified so that the cursor
** can never be used again.  This happens when a rollback
*** occurs.  We have to trip all the other cursors, even
** cursor from other VMs in different database connections,
** so that none of them try to use the data at which they
** were pointing and which now may have been changed due
** to the rollback.
**
** Remember that a rollback can delete tables complete and
** reorder rootpages.  So it is not sufficient just to save
** the state of the cursor.  We have to invalidate the cursor
** so that it is never used again.
*/
static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
  int i;
  for(i=0; i<db->nDb; i++){
    Btree *p = db->aDb[i].pBt;
    if( p && sqlite3BtreeIsInTrans(p) ){
      sqlite3BtreeTripAllCursors(p, SQLITE_ABORT);
    }
  }
}

/*
** If the Vdbe passed as the first argument opened a statement-transaction,
** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or
** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement
** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the 
** statement transaction is commtted.
**
................................................................................
      if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
        if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){
          eStatementOp = SAVEPOINT_ROLLBACK;
        }else{
          /* We are forced to roll back the active transaction. Before doing
          ** so, abort any other statements this handle currently has active.
          */
          invalidateCursorsOnModifiedBtrees(db);
          sqlite3RollbackAll(db);
          sqlite3CloseSavepoints(db);
          db->autoCommit = 1;
        }
      }
    }

    /* Check for immediate foreign key violations. */
................................................................................
          rc = vdbeCommit(db, p);
        }
        if( rc==SQLITE_BUSY && p->readOnly ){
          sqlite3VdbeLeave(p);
          return SQLITE_BUSY;
        }else if( rc!=SQLITE_OK ){
          p->rc = rc;
          sqlite3RollbackAll(db);
        }else{
          db->nDeferredCons = 0;
          sqlite3CommitInternalChanges(db);
        }
      }else{
        sqlite3RollbackAll(db);
      }
      db->nStatement = 0;
    }else if( eStatementOp==0 ){
      if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
        eStatementOp = SAVEPOINT_RELEASE;
      }else if( p->errorAction==OE_Abort ){
        eStatementOp = SAVEPOINT_ROLLBACK;
      }else{
        invalidateCursorsOnModifiedBtrees(db);
        sqlite3RollbackAll(db);
        sqlite3CloseSavepoints(db);
        db->autoCommit = 1;
      }
    }
  
    /* If eStatementOp is non-zero, then a statement transaction needs to
    ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
................................................................................
      rc = sqlite3VdbeCloseStatement(p, eStatementOp);
      if( rc ){
        if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
          p->rc = rc;
          sqlite3DbFree(db, p->zErrMsg);
          p->zErrMsg = 0;
        }
        invalidateCursorsOnModifiedBtrees(db);
        sqlite3RollbackAll(db);
        sqlite3CloseSavepoints(db);
        db->autoCommit = 1;
      }
    }
  
    /* If this was an INSERT, UPDATE or DELETE and no statement transaction
    ** has been rolled back, update the database connection change-counter. 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
|







 







|





|








<
|







 







<
|







1998
1999
2000
2001
2002
2003
2004


























2005
2006
2007
2008
2009
2010
2011
....
2162
2163
2164
2165
2166
2167
2168

2169
2170
2171
2172
2173
2174
2175
2176
....
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225

2226
2227
2228
2229
2230
2231
2232
2233
....
2239
2240
2241
2242
2243
2244
2245

2246
2247
2248
2249
2250
2251
2252
2253
  assert( cnt==db->activeVdbeCnt );
  assert( nWrite==db->writeVdbeCnt );
}
#else
#define checkActiveVdbeCnt(x)
#endif



























/*
** If the Vdbe passed as the first argument opened a statement-transaction,
** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or
** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement
** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the 
** statement transaction is commtted.
**
................................................................................
      if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
        if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){
          eStatementOp = SAVEPOINT_ROLLBACK;
        }else{
          /* We are forced to roll back the active transaction. Before doing
          ** so, abort any other statements this handle currently has active.
          */

          sqlite3RollbackAll(db, SQLITE_ABORT);
          sqlite3CloseSavepoints(db);
          db->autoCommit = 1;
        }
      }
    }

    /* Check for immediate foreign key violations. */
................................................................................
          rc = vdbeCommit(db, p);
        }
        if( rc==SQLITE_BUSY && p->readOnly ){
          sqlite3VdbeLeave(p);
          return SQLITE_BUSY;
        }else if( rc!=SQLITE_OK ){
          p->rc = rc;
          sqlite3RollbackAll(db, SQLITE_OK);
        }else{
          db->nDeferredCons = 0;
          sqlite3CommitInternalChanges(db);
        }
      }else{
        sqlite3RollbackAll(db, SQLITE_OK);
      }
      db->nStatement = 0;
    }else if( eStatementOp==0 ){
      if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
        eStatementOp = SAVEPOINT_RELEASE;
      }else if( p->errorAction==OE_Abort ){
        eStatementOp = SAVEPOINT_ROLLBACK;
      }else{

        sqlite3RollbackAll(db, SQLITE_ABORT);
        sqlite3CloseSavepoints(db);
        db->autoCommit = 1;
      }
    }
  
    /* If eStatementOp is non-zero, then a statement transaction needs to
    ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
................................................................................
      rc = sqlite3VdbeCloseStatement(p, eStatementOp);
      if( rc ){
        if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
          p->rc = rc;
          sqlite3DbFree(db, p->zErrMsg);
          p->zErrMsg = 0;
        }

        sqlite3RollbackAll(db, SQLITE_ABORT);
        sqlite3CloseSavepoints(db);
        db->autoCommit = 1;
      }
    }
  
    /* If this was an INSERT, UPDATE or DELETE and no statement transaction
    ** has been rolled back, update the database connection change-counter. 

Changes to test/capi3.test.

890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907

908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
do_test capi3-11.9.1 {
  sqlite3_get_autocommit $DB
} 0
do_test capi3-11.9.2 {
  catchsql {
    ROLLBACK;
  }
} {1 {cannot rollback transaction - SQL statements in progress}}
do_test capi3-11.9.3 {
  sqlite3_get_autocommit $DB
} 0
do_test capi3-11.10 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-11.11 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-11.12 {

  sqlite3_step $STMT
} {SQLITE_DONE}
do_test capi3-11.13 {
  sqlite3_finalize $STMT
} {SQLITE_OK}
do_test capi3-11.14 {
  execsql {
    SELECT a FROM t2;
  }
} {1 2 3}
do_test capi3-11.14.1 {
  sqlite3_get_autocommit $DB
} 0
do_test capi3-11.15 {
  catchsql {
    ROLLBACK;
  }
} {0 {}}
do_test capi3-11.15.1 {
  sqlite3_get_autocommit $DB
} 1
do_test capi3-11.16 {
  execsql {
    SELECT a FROM t2;
  }







|


|


|




>









|


|




|







890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
do_test capi3-11.9.1 {
  sqlite3_get_autocommit $DB
} 0
do_test capi3-11.9.2 {
  catchsql {
    ROLLBACK;
  }
} {0 {}}
do_test capi3-11.9.3 {
  sqlite3_get_autocommit $DB
} 1
do_test capi3-11.10 {
  sqlite3_step $STMT
} {SQLITE_ERROR}
do_test capi3-11.11 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-11.12 {
  sqlite3_step $STMT
  sqlite3_step $STMT
} {SQLITE_DONE}
do_test capi3-11.13 {
  sqlite3_finalize $STMT
} {SQLITE_OK}
do_test capi3-11.14 {
  execsql {
    SELECT a FROM t2;
  }
} {1 2}
do_test capi3-11.14.1 {
  sqlite3_get_autocommit $DB
} 1
do_test capi3-11.15 {
  catchsql {
    ROLLBACK;
  }
} {1 {cannot rollback - no transaction is active}}
do_test capi3-11.15.1 {
  sqlite3_get_autocommit $DB
} 1
do_test capi3-11.16 {
  execsql {
    SELECT a FROM t2;
  }

Changes to test/capi3c.test.

845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862

863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
do_test capi3c-11.9.1 {
  sqlite3_get_autocommit $DB
} 0
do_test capi3c-11.9.2 {
  catchsql {
    ROLLBACK;
  }
} {1 {cannot rollback transaction - SQL statements in progress}}
do_test capi3c-11.9.3 {
  sqlite3_get_autocommit $DB
} 0
do_test capi3c-11.10 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3c-11.11 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3c-11.12 {

  sqlite3_step $STMT
} {SQLITE_DONE}
do_test capi3c-11.13 {
  sqlite3_finalize $STMT
} {SQLITE_OK}
do_test capi3c-11.14 {
  execsql {
    SELECT a FROM t2;
  }
} {1 2 3}
do_test capi3c-11.14.1 {
  sqlite3_get_autocommit $DB
} 0
do_test capi3c-11.15 {
  catchsql {
    ROLLBACK;
  }
} {0 {}}
do_test capi3c-11.15.1 {
  sqlite3_get_autocommit $DB
} 1
do_test capi3c-11.16 {
  execsql {
    SELECT a FROM t2;
  }







|


|


|




>









|


|




|







845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
do_test capi3c-11.9.1 {
  sqlite3_get_autocommit $DB
} 0
do_test capi3c-11.9.2 {
  catchsql {
    ROLLBACK;
  }
} {0 {}}
do_test capi3c-11.9.3 {
  sqlite3_get_autocommit $DB
} 1
do_test capi3c-11.10 {
  sqlite3_step $STMT
} {SQLITE_ABORT}
do_test capi3c-11.11 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3c-11.12 {
  sqlite3_step $STMT
  sqlite3_step $STMT
} {SQLITE_DONE}
do_test capi3c-11.13 {
  sqlite3_finalize $STMT
} {SQLITE_OK}
do_test capi3c-11.14 {
  execsql {
    SELECT a FROM t2;
  }
} {1 2}
do_test capi3c-11.14.1 {
  sqlite3_get_autocommit $DB
} 1
do_test capi3c-11.15 {
  catchsql {
    ROLLBACK;
  }
} {1 {cannot rollback - no transaction is active}}
do_test capi3c-11.15.1 {
  sqlite3_get_autocommit $DB
} 1
do_test capi3c-11.16 {
  execsql {
    SELECT a FROM t2;
  }

Changes to test/incrblob.test.

469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  } {10}
  do_test incrblob-6.9 {
    seek $::blob 0
    puts -nonewline $::blob "invocation"
    flush $::blob
  } {}
  
  # At this point rollback should be illegal (because 
  # there is an open blob channel).  But commit is also illegal because
  # the open blob is read-write.
  #
  do_test incrblob-6.10 {
    catchsql {
      ROLLBACK;
    } db2
  } {1 {cannot rollback transaction - SQL statements in progress}}
  do_test incrblob-6.11 {
    catchsql {
      COMMIT;
    } db2
  } {1 {cannot commit transaction - SQL statements in progress}}
  
  do_test incrblob-6.12 {







|
|
<

<
<
<
<
<







469
470
471
472
473
474
475
476
477

478





479
480
481
482
483
484
485
  } {10}
  do_test incrblob-6.9 {
    seek $::blob 0
    puts -nonewline $::blob "invocation"
    flush $::blob
  } {}
  
  # At this point commit should be illegal (because 
  # there is an open blob channel).

  #





  do_test incrblob-6.11 {
    catchsql {
      COMMIT;
    } db2
  } {1 {cannot commit transaction - SQL statements in progress}}
  
  do_test incrblob-6.12 {

Changes to test/savepoint.test.

299
300
301
302
303
304
305
306
307
308




309
310





311
312
313
314
315
316
317
    catchsql {RELEASE abc}
  } {1 {no such savepoint: abc}}
  
  do_test savepoint-5.3.1 {
    execsql  {SAVEPOINT abc}
    catchsql {ROLLBACK TO def}
  } {1 {no such savepoint: def}}
  do_test savepoint-5.3.2 {
    execsql  {SAVEPOINT def}
    set fd [db incrblob -readonly blobs x 1]




    catchsql {ROLLBACK TO def}
  } {1 {cannot rollback savepoint - SQL statements in progress}}





  do_test savepoint-5.3.3 {
    catchsql  {RELEASE def}
  } {0 {}}
  do_test savepoint-5.3.4 {
    close $fd
    execsql  {savepoint def}
    set fd [db incrblob blobs x 1]







|


>
>
>
>

<
>
>
>
>
>







299
300
301
302
303
304
305
306
307
308
309
310
311
312
313

314
315
316
317
318
319
320
321
322
323
324
325
    catchsql {RELEASE abc}
  } {1 {no such savepoint: abc}}
  
  do_test savepoint-5.3.1 {
    execsql  {SAVEPOINT abc}
    catchsql {ROLLBACK TO def}
  } {1 {no such savepoint: def}}
  do_test savepoint-5.3.2.1 {
    execsql  {SAVEPOINT def}
    set fd [db incrblob -readonly blobs x 1]
    set rc [catch {seek $fd 0;read $fd} res]
    lappend rc $res
  } {0 {hellontyeight character blob}}
  do_test savepoint-5.3.2.2 {
    catchsql {ROLLBACK TO def}

  } {0 {}}
  do_test savepoint-5.3.2.3 {
    set rc [catch {seek $fd 0; read $fd} res]
    set rc
  } {1}
  do_test savepoint-5.3.3 {
    catchsql  {RELEASE def}
  } {0 {}}
  do_test savepoint-5.3.4 {
    close $fd
    execsql  {savepoint def}
    set fd [db incrblob blobs x 1]

Changes to test/shared2.test.

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
        DELETE FROM numbers;
      } db1
    }
  }
  list $a $count
} {32 64}

#---------------------------------------------------------------------------
# These tests, shared2.2.*, test the outcome when data is added to or 
# removed from a table due to a rollback while a read-uncommitted 
# cursor is scanning it.
#
do_test shared2-2.1 {
  execsql {
    INSERT INTO numbers VALUES(1, 'Medium length text field');
    INSERT INTO numbers VALUES(2, 'Medium length text field');
    INSERT INTO numbers VALUES(3, 'Medium length text field');
    INSERT INTO numbers VALUES(4, 'Medium length text field');
    BEGIN;
    DELETE FROM numbers WHERE (a%2)=0;
  } db1
  set res [list]
  db2 eval {
    SELECT a FROM numbers ORDER BY a;
  } {
    lappend res $a
    if {$a==3} {
      execsql {ROLLBACK} db1
    }
  }
  set res
} {1 3 4}
do_test shared2-2.2 {
  execsql {
    BEGIN;
    INSERT INTO numbers VALUES(5, 'Medium length text field');
    INSERT INTO numbers VALUES(6, 'Medium length text field');
  } db1
  set res [list]
  db2 eval {
    SELECT a FROM numbers ORDER BY a;
  } {
    lappend res $a
    if {$a==5} {
      execsql {ROLLBACK} db1
    }
  }
  set res
} {1 2 3 4 5}

db1 close
db2 close

do_test shared2-3.2 {
  sqlite3_enable_shared_cache 1
} {1}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







75
76
77
78
79
80
81










































82
83
84
85
86
87
88
        DELETE FROM numbers;
      } db1
    }
  }
  list $a $count
} {32 64}












































db1 close
db2 close

do_test shared2-3.2 {
  sqlite3_enable_shared_cache 1
} {1}