SQLite

Changes On Branch nonblocking-rollback
Login

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

Changes In Branch nonblocking-rollback Excluding Merge-Ins

This is equivalent to a diff from 76bb649e to 549f4fd0

2012-02-13
21:24
Merge the non-blocking ROLLBACK changes into trunk. (check-in: 9c572d42 user: drh tags: trunk)
20:16
On unix, ignore the umask when creating journal files. That way, journal files will have exactly the same permissions as the original database and any process that has permission to write to the database can also recover hot journals. (check-in: 84b32460 user: drh tags: trunk)
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)
13:44
Generalize the interrupt mechanism so that individual statements can be interrupted and so that codes other than just SQLITE_INTERRUPT can be returned as a consequence of an interrupt. (Closed-Leaf check-in: 922bcbb4 user: drh tags: generalize-interrupt)
10:00
Changes to various test scripts so that veryquick.test runs with OMIT_COMPOUND_SELECT defined. (check-in: 76bb649e user: dan tags: trunk)
08:50
Fix a typo in the type of the fchown() function in os_unix.c. (check-in: bfbfe05b user: dan tags: trunk)

Changes to src/backup.c.

564
565
566
567
568
569
570
571

572
573
574
575
576
577
578
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);
  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
2037
2038
2039
2040
2041
2042
2043

2044
2045
2046
2047
2048
2049
2050
2051







-
+







    }
  }

  /* Rollback any active transaction and free the handle structure.
  ** The call to sqlite3BtreeRollback() drops any table-locks held by
  ** this handle.
  */
  sqlite3BtreeRollback(p);
  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 );
3275
3276
3277
3278
3279
3280
3281

3282
3283
3284
3285
3286
3287
3288
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289







+







** 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++){
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
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







-
+





+
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
+

-







** 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 sqlite3BtreeRollback(Btree *p, int tripCode){
  int rc;
  BtShared *pBt = p->pBt;
  MemPage *pPage1;

  sqlite3BtreeEnter(p);
  if( tripCode==SQLITE_OK ){
  rc = saveAllCursors(pBt, 0, 0);
#ifndef SQLITE_OMIT_SHARED_CACHE
  if( rc!=SQLITE_OK ){
    rc = tripCode = saveAllCursors(pBt, 0, 0);
  }else{
    rc = SQLITE_OK;
  }
  if( tripCode ){
    /* 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);
    sqlite3BtreeTripAllCursors(p, tripCode);
  }
#endif
  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
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 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
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.
** 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){
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++){
    if( db->aDb[i].pBt ){
      if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
    Btree *p = db->aDb[i].pBt;
    if( p ){
      if( sqlite3BtreeIsInTrans(p) ){
        inTrans = 1;
      }
      sqlite3BtreeRollback(db->aDb[i].pBt);
      sqlite3BtreeRollback(p, tripCode);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3VtabRollback(db);
  sqlite3EndBenignMalloc();

  if( db->flags&SQLITE_InternChanges ){
912
913
914
915
916
917
918







919
920
921
922





923
924



925
926
927
928
929
930
931
916
917
918
919
920
921
922
923
924
925
926
927
928
929




930
931
932
933
934


935
936
937
938
939
940
941
942
943
944







+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
-
+
+
+







    /* SQLITE_MISUSE      */ "library routine called out of sequence",
    /* SQLITE_NOLFS       */ "large file support is disabled",
    /* SQLITE_AUTH        */ "authorization denied",
    /* SQLITE_FORMAT      */ "auxiliary database format error",
    /* SQLITE_RANGE       */ "bind or column index out of range",
    /* SQLITE_NOTADB      */ "file is encrypted or is not a database",
  };
  const char *zErr = "unknown error";
  switch( rc ){
    case SQLITE_ABORT_ROLLBACK: {
      zErr = "abort due to ROLLBACK";
      break;
    }
    default: {
  rc &= 0xff;
  if( ALWAYS(rc>=0) && rc<(int)(sizeof(aMsg)/sizeof(aMsg[0])) && aMsg[rc]!=0 ){
    return aMsg[rc];
  }else{
      rc &= 0xff;
      if( ALWAYS(rc>=0) && rc<ArraySize(aMsg) && aMsg[rc]!=0 ){
        zErr = aMsg[rc];
      }
      break;
    return "unknown error";
  }
    }
  }
  return zErr;
}

/*
** This routine implements a busy callback that sleeps and tries
** again until a timeout value is reached.  The timeout value is
** an integer number of milliseconds passed in as the first
** argument.

Changes to src/sqlite.h.in.

452
453
454
455
456
457
458

459
460
461
462
463
464
465
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466







+







#define SQLITE_IOERR_SEEK              (SQLITE_IOERR | (22<<8))
#define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
#define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
#define SQLITE_ABORT_ROLLBACK          (SQLITE_ABORT | (2<<8))

/*
** CAPI3REF: Flags For File Open Operations
**
** These bit values are intended for use in the
** 3rd parameter to the [sqlite3_open_v2()] interface and
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.

Changes to src/sqliteInt.h.

2796
2797
2798
2799
2800
2801
2802
2803

2804
2805
2806
2807
2808
2809
2810
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 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
2680
2681
2682
2683
2684
2685
2686

2687


2688

2689

2690
2691

2692

2693
2694
2695
2696
2697
2698
2699







-
+
-
-

-
+
-


-
+
-







      pSavepoint = pSavepoint->pNext
    ){
      iSavepoint++;
    }
    if( !pSavepoint ){
      sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", zName);
      rc = SQLITE_ERROR;
    }else if( 
    }else if( db->writeVdbeCnt>0 && p1==SAVEPOINT_RELEASE ){
        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
      ** active write statements.
      ** if there are any active statements at all.
      */
      sqlite3SetString(&p->zErrMsg, db, 
        "cannot %s savepoint - SQL statements in progress",
        "cannot release 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. 
2714
2715
2716
2717
2718
2719
2720



2721
2722
2723
2724
2725
2726
2727
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726







+
+
+







          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 ){
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
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







+








+
+
-
+









-
+







  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
  }else if( turnOnAC && !iRollback && db->writeVdbeCnt>0 ){
  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);
      sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
      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
1998
1999
2000
2001
2002
2003
2004


























2005
2006
2007
2008
2009
2010
2011







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







  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.
**
2188
2189
2190
2191
2192
2193
2194
2195
2196

2197
2198
2199
2200
2201
2202
2203
2162
2163
2164
2165
2166
2167
2168


2169
2170
2171
2172
2173
2174
2175
2176







-
-
+







      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);
          sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
          sqlite3CloseSavepoints(db);
          db->autoCommit = 1;
        }
      }
    }

    /* Check for immediate foreign key violations. */
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
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275

2276
2277
2278
2279
2280
2281
2282
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
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245


2246
2247
2248
2249
2250
2251
2252
2253







-
+





-
+








-
-
+



















-
-
+







          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);
          sqlite3RollbackAll(db, SQLITE_OK);
        }else{
          db->nDeferredCons = 0;
          sqlite3CommitInternalChanges(db);
        }
      }else{
        sqlite3RollbackAll(db);
        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{
        invalidateCursorsOnModifiedBtrees(db);
        sqlite3RollbackAll(db);
        sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
        sqlite3CloseSavepoints(db);
        db->autoCommit = 1;
      }
    }
  
    /* If eStatementOp is non-zero, then a statement transaction needs to
    ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
    ** do so. If this operation returns an error, and the current statement
    ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
    ** current statement error code.
    */
    if( eStatementOp ){
      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);
        sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
        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
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;
  }
} {1 {cannot rollback transaction - SQL statements in progress}}
} {0 {}}
do_test capi3-11.9.3 {
  sqlite3_get_autocommit $DB
} 0
} 1
do_test capi3-11.10 {
  sqlite3_step $STMT
} {SQLITE_ROW}
} {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 3}
} {1 2}
do_test capi3-11.14.1 {
  sqlite3_get_autocommit $DB
} 0
} 1
do_test capi3-11.15 {
  catchsql {
    ROLLBACK;
  }
} {0 {}}
} {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
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;
  }
} {1 {cannot rollback transaction - SQL statements in progress}}
} {0 {}}
do_test capi3c-11.9.3 {
  sqlite3_get_autocommit $DB
} 0
} 1
do_test capi3c-11.10 {
  sqlite3_step $STMT
} {SQLITE_ROW}
} {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 3}
} {1 2}
do_test capi3c-11.14.1 {
  sqlite3_get_autocommit $DB
} 0
} 1
do_test capi3c-11.15 {
  catchsql {
    ROLLBACK;
  }
} {0 {}}
} {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
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 rollback should be illegal (because 
  # there is an open blob channel).  But commit is also illegal because
  # At this point commit should be illegal (because 
  # there is an open blob channel).
  # 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 {

Changes to test/savepoint.test.

299
300
301
302
303
304
305
306

307
308




309

310




311
312
313
314
315
316
317
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 {
  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 {}}
  } {1 {cannot rollback savepoint - SQL statements in progress}}
  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
75
76
77
78
79
80
81










































82
83
84
85
86
87
88







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







        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}

Changes to test/tkt-f777251dc7a.test.

38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52







-
+







db function force_rollback force_rollback

do_test tkt-f7772-1.2 {
  catchsql {
    BEGIN IMMEDIATE;
    SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2;
  }
} {1 {callback requested query abort}}
} {1 {abort due to ROLLBACK}}
do_test tkt-f7772-1.3 {
  sqlite3_get_autocommit db
} {1}

do_test tkt-f7772-2.1 {
  execsql {
     DROP TABLE IF EXISTS t1;

Changes to test/trans3.test.

60
61
62
63
64
65
66
67

68
69
70

71
72
73
74

75
76
77
60
61
62
63
64
65
66

67
68
69

70
71

72

73
74
75
76







-
+


-
+

-

-
+



        if {[catch {db eval ROLLBACK} errmsg]} {
           set ::ecode [sqlite3_extended_errcode db]
           error $errmsg
        }
     }
  } errmsg]
  lappend x $errmsg
} {1 {cannot rollback transaction - SQL statements in progress}}
} {1 {abort due to ROLLBACK}}
do_test trans3-1.6 {
  set ::ecode
} {SQLITE_BUSY}
} {}
do_test trans3-1.7 {
  db eval COMMIT
  db eval {SELECT * FROM t1}
} {1 2 3 4 5}
} {1 2 3 4}
unset -nocomplain ecode

finish_test