SQLite

Check-in [f256bc0796]
Login

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

Overview
Comment:When a forced rollback occurs, cause all active statements on the same database connection to halt immediately with an SQLITE_ABORT error code. This is a partial fix to ticket [f777251dc7].
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | trunk | experimental
Files: files | file ages | folders
SHA1: f256bc0796ca8bd4569dd6de37621c961efaecd1
User & Date: drh 2009-10-15 23:03:11.000
Original Comment: When a forced rollback occurs, cause all active statements on the same database connection to halt immediately with an SQLITE_ABORT error code. This is a partial fix to ticket [f777251dc7].
Context
2009-10-15
23:03
When a forced rollback occurs, cause all active statements on the same database connection to halt immediately with an SQLITE_ABORT error code. This is a partial fix to ticket [f777251dc7]. (Closed-Leaf check-in: f256bc0796 user: drh tags: trunk, experimental)
2009-10-14
11:33
Version 3.6.19 (check-in: c1d499afc5 user: drh tags: trunk, release)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/main.c.
721
722
723
724
725
726
727




728
729
730
731
732
733
734
      }
      sqlite3BtreeRollback(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3VtabRollback(db);
  sqlite3EndBenignMalloc();





  if( db->flags&SQLITE_InternChanges ){
    sqlite3ExpirePreparedStatements(db);
    sqlite3ResetInternalSchema(db, 0);
  }

  /* Any deferred constraint violations have now been resolved. */







>
>
>
>







721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
      }
      sqlite3BtreeRollback(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3VtabRollback(db);
  sqlite3EndBenignMalloc();
  if( inTrans ){
    sqlite3_interrupt(db);
    db->interruptErrorCode = SQLITE_ABORT;
  }

  if( db->flags&SQLITE_InternChanges ){
    sqlite3ExpirePreparedStatements(db);
    sqlite3ResetInternalSchema(db, 0);
  }

  /* Any deferred constraint violations have now been resolved. */
Changes to src/sqliteInt.h.
789
790
791
792
793
794
795

796
797
798
799
800
801
802
  int errCode;                  /* Most recent error code (SQLITE_*) */
  int errMask;                  /* & result codes with this before returning */
  u8 autoCommit;                /* The auto-commit flag. */
  u8 temp_store;                /* 1: file 2: memory 0: default */
  u8 mallocFailed;              /* True if we have seen a malloc failure */
  u8 dfltLockMode;              /* Default locking-mode for attached dbs */
  u8 dfltJournalMode;           /* Default journal mode for attached dbs */

  signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
  int nextPagesize;             /* Pagesize after VACUUM if >0 */
  int nTable;                   /* Number of tables in the database */
  CollSeq *pDfltColl;           /* The default collating sequence (BINARY) */
  i64 lastRowid;                /* ROWID of most recent insert (see above) */
  u32 magic;                    /* Magic number for detect library misuse */
  int nChange;                  /* Value returned by sqlite3_changes() */







>







789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  int errCode;                  /* Most recent error code (SQLITE_*) */
  int errMask;                  /* & result codes with this before returning */
  u8 autoCommit;                /* The auto-commit flag. */
  u8 temp_store;                /* 1: file 2: memory 0: default */
  u8 mallocFailed;              /* True if we have seen a malloc failure */
  u8 dfltLockMode;              /* Default locking-mode for attached dbs */
  u8 dfltJournalMode;           /* Default journal mode for attached dbs */
  u8 interruptErrorCode;        /* Error code returned after isInterrupted */
  signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
  int nextPagesize;             /* Pagesize after VACUUM if >0 */
  int nTable;                   /* Number of tables in the database */
  CollSeq *pDfltColl;           /* The default collating sequence (BINARY) */
  i64 lastRowid;                /* ROWID of most recent insert (see above) */
  u32 magic;                    /* Magic number for detect library misuse */
  int nChange;                  /* Value returned by sqlite3_changes() */
2508
2509
2510
2511
2512
2513
2514

2515
2516
2517
2518
2519
2520
2521
  void *sqlite3TestTextToPtr(const char*);
#endif
void sqlite3SetString(char **, sqlite3*, const char*, ...);
void sqlite3ErrorMsg(Parse*, const char*, ...);
void sqlite3ErrorClear(Parse*);
int sqlite3Dequote(char*);
int sqlite3KeywordCode(const unsigned char*, int);

int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
int sqlite3GetTempReg(Parse*);
void sqlite3ReleaseTempReg(Parse*,int);
int sqlite3GetTempRange(Parse*,int);
void sqlite3ReleaseTempRange(Parse*,int,int);
Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);







>







2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
  void *sqlite3TestTextToPtr(const char*);
#endif
void sqlite3SetString(char **, sqlite3*, const char*, ...);
void sqlite3ErrorMsg(Parse*, const char*, ...);
void sqlite3ErrorClear(Parse*);
int sqlite3Dequote(char*);
int sqlite3KeywordCode(const unsigned char*, int);
void sqlite3ResetInterrupt(sqlite3*);
int sqlite3RunParser(Parse*, const char*, char **);
void sqlite3FinishCoding(Parse*);
int sqlite3GetTempReg(Parse*);
void sqlite3ReleaseTempReg(Parse*,int);
int sqlite3GetTempRange(Parse*,int);
void sqlite3ReleaseTempRange(Parse*,int,int);
Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
Changes to src/tokenize.c.
382
383
384
385
386
387
388










389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
      *tokenType = keywordCode((char*)z, i);
      return i;
    }
  }
  *tokenType = TK_ILLEGAL;
  return 1;
}











/*
** Run the parser on the given SQL string.  The parser structure is
** passed in.  An SQLITE_ status code is returned.  If an error occurs
** then an and attempt is made to write an error message into 
** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that
** error message.
*/
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
  int nErr = 0;                   /* Number of errors encountered */
  int i;                          /* Loop counter */
  void *pEngine;                  /* The LEMON-generated LALR(1) parser */
  int tokenType;                  /* type of the next token */
  int lastTokenParsed = -1;       /* type of the previous token */
  u8 enableLookaside;             /* Saved value of db->lookaside.bEnabled */
  sqlite3 *db = pParse->db;       /* The database connection */
  int mxSqlLen;                   /* Max length of an SQL string */


  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
  if( db->activeVdbeCnt==0 ){
    db->u1.isInterrupted = 0;
  }
  pParse->rc = SQLITE_OK;
  pParse->zTail = zSql;
  i = 0;
  assert( pzErrMsg!=0 );
  pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc);
  if( pEngine==0 ){
    db->mallocFailed = 1;







>
>
>
>
>
>
>
>
>
>


















<

<
|
<







382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416

417

418

419
420
421
422
423
424
425
      *tokenType = keywordCode((char*)z, i);
      return i;
    }
  }
  *tokenType = TK_ILLEGAL;
  return 1;
}

/*
** If there are no active VDBEs, then reset the interrupt flag.
*/
void sqlite3ResetInterrupt(sqlite3 *db){
  if( db->activeVdbeCnt==0 ){
    db->u1.isInterrupted = 0;
    db->interruptErrorCode = SQLITE_INTERRUPT;
  }
}

/*
** Run the parser on the given SQL string.  The parser structure is
** passed in.  An SQLITE_ status code is returned.  If an error occurs
** then an and attempt is made to write an error message into 
** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that
** error message.
*/
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
  int nErr = 0;                   /* Number of errors encountered */
  int i;                          /* Loop counter */
  void *pEngine;                  /* The LEMON-generated LALR(1) parser */
  int tokenType;                  /* type of the next token */
  int lastTokenParsed = -1;       /* type of the previous token */
  u8 enableLookaside;             /* Saved value of db->lookaside.bEnabled */
  sqlite3 *db = pParse->db;       /* The database connection */
  int mxSqlLen;                   /* Max length of an SQL string */


  mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];

  sqlite3ResetInterrupt(db);

  pParse->rc = SQLITE_OK;
  pParse->zTail = zSql;
  i = 0;
  assert( pzErrMsg!=0 );
  pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc);
  if( pEngine==0 ){
    db->mallocFailed = 1;
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
      pParse->rc = SQLITE_TOOBIG;
      break;
    }
    switch( tokenType ){
      case TK_SPACE: {
        if( db->u1.isInterrupted ){
          sqlite3ErrorMsg(pParse, "interrupt");
          pParse->rc = SQLITE_INTERRUPT;
          goto abort_parse;
        }
        break;
      }
      case TK_ILLEGAL: {
        sqlite3DbFree(db, *pzErrMsg);
        *pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",







|







442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
      pParse->rc = SQLITE_TOOBIG;
      break;
    }
    switch( tokenType ){
      case TK_SPACE: {
        if( db->u1.isInterrupted ){
          sqlite3ErrorMsg(pParse, "interrupt");
          pParse->rc = db->interruptErrorCode;
          goto abort_parse;
        }
        break;
      }
      case TK_ILLEGAL: {
        sqlite3DbFree(db, *pzErrMsg);
        *pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
Changes to src/vdbe.c.
731
732
733
734
735
736
737

738
739
740
741
742
743
744
    }else if( (opProperty & OPFLG_IN3)!=0 ){
      assert( pOp->p3>0 );
      assert( pOp->p3<=p->nMem );
      pIn3 = &p->aMem[pOp->p3];
      REGISTER_TRACE(pOp->p3, pIn3);
    }


    switch( pOp->opcode ){

/*****************************************************************************
** What follows is a massive switch statement where each case implements a
** separate instruction in the virtual machine.  If we follow the usual
** indentation conventions, each case should be indented by 6 spaces.  But
** that is a lot of wasted space on the left margin.  So the code within







>







731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
    }else if( (opProperty & OPFLG_IN3)!=0 ){
      assert( pOp->p3>0 );
      assert( pOp->p3<=p->nMem );
      pIn3 = &p->aMem[pOp->p3];
      REGISTER_TRACE(pOp->p3, pIn3);
    }

    CHECK_FOR_INTERRUPT;
    switch( pOp->opcode ){

/*****************************************************************************
** What follows is a massive switch statement where each case implements a
** separate instruction in the virtual machine.  If we follow the usual
** indentation conventions, each case should be indented by 6 spaces.  But
** that is a lot of wasted space on the left margin.  So the code within
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
**
** An unconditional jump to address P2.
** The next instruction executed will be 
** the one at index P2 from the beginning of
** the program.
*/
case OP_Goto: {             /* jump */
  CHECK_FOR_INTERRUPT;
  pc = pOp->p2 - 1;
  break;
}

/* Opcode:  Gosub P1 P2 * * *
**
** Write the current address onto register P1







<







777
778
779
780
781
782
783

784
785
786
787
788
789
790
**
** An unconditional jump to address P2.
** The next instruction executed will be 
** the one at index P2 from the beginning of
** the program.
*/
case OP_Goto: {             /* jump */

  pc = pOp->p2 - 1;
  break;
}

/* Opcode:  Gosub P1 P2 * * *
**
** Write the current address onto register P1
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
*/
case OP_Prev:          /* jump */
case OP_Next: {        /* jump */
  VdbeCursor *pC;
  BtCursor *pCrsr;
  int res;

  CHECK_FOR_INTERRUPT;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  if( pC==0 ){
    break;  /* See ticket #2273 */
  }
  pCrsr = pC->pCursor;
  if( pCrsr==0 ){







<







4150
4151
4152
4153
4154
4155
4156

4157
4158
4159
4160
4161
4162
4163
*/
case OP_Prev:          /* jump */
case OP_Next: {        /* jump */
  VdbeCursor *pC;
  BtCursor *pCrsr;
  int res;


  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  if( pC==0 ){
    break;  /* See ticket #2273 */
  }
  pCrsr = pC->pCursor;
  if( pCrsr==0 ){
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
** register P3.  Or, if boolean index P1 is initially empty, leave P3
** unchanged and jump to instruction P2.
*/
case OP_RowSetRead: {       /* jump, out3 */
  Mem *pIdx;
  i64 val;
  assert( pOp->p1>0 && pOp->p1<=p->nMem );
  CHECK_FOR_INTERRUPT;
  pIdx = &p->aMem[pOp->p1];
  pOut = &p->aMem[pOp->p3];
  if( (pIdx->flags & MEM_RowSet)==0 
   || sqlite3RowSetNext(pIdx->u.pRowSet, &val)==0
  ){
    /* The boolean index is empty */
    sqlite3VdbeMemSetNull(pIdx);







<







4698
4699
4700
4701
4702
4703
4704

4705
4706
4707
4708
4709
4710
4711
** register P3.  Or, if boolean index P1 is initially empty, leave P3
** unchanged and jump to instruction P2.
*/
case OP_RowSetRead: {       /* jump, out3 */
  Mem *pIdx;
  i64 val;
  assert( pOp->p1>0 && pOp->p1<=p->nMem );

  pIdx = &p->aMem[pOp->p1];
  pOut = &p->aMem[pOp->p3];
  if( (pIdx->flags & MEM_RowSet)==0 
   || sqlite3RowSetNext(pIdx->u.pRowSet, &val)==0
  ){
    /* The boolean index is empty */
    sqlite3VdbeMemSetNull(pIdx);
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
  goto vdbe_error_halt;

  /* Jump to here if the sqlite3_interrupt() API sets the interrupt
  ** flag.
  */
abort_due_to_interrupt:
  assert( db->u1.isInterrupted );
  rc = SQLITE_INTERRUPT;
  p->rc = rc;
  sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(rc));
  goto vdbe_error_halt;
}







|




5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
  goto vdbe_error_halt;

  /* Jump to here if the sqlite3_interrupt() API sets the interrupt
  ** flag.
  */
abort_due_to_interrupt:
  assert( db->u1.isInterrupted );
  rc = db->interruptErrorCode;
  p->rc = rc;
  sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(rc));
  goto vdbe_error_halt;
}
Changes to src/vdbeaux.c.
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  do{
    i = p->pc++;
  }while( i<nRow && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
  if( i>=nRow ){
    p->rc = SQLITE_OK;
    rc = SQLITE_DONE;
  }else if( db->u1.isInterrupted ){
    p->rc = SQLITE_INTERRUPT;
    rc = SQLITE_ERROR;
    sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(p->rc));
  }else{
    char *z;
    Op *pOp;
    if( i<p->nOp ){
      pOp = &p->aOp[i];







|







1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  do{
    i = p->pc++;
  }while( i<nRow && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
  if( i>=nRow ){
    p->rc = SQLITE_OK;
    rc = SQLITE_DONE;
  }else if( db->u1.isInterrupted ){
    p->rc = db->interruptErrorCode;
    rc = SQLITE_ERROR;
    sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(p->rc));
  }else{
    char *z;
    Op *pOp;
    if( i<p->nOp ){
      pOp = &p->aOp[i];
2127
2128
2129
2130
2131
2132
2133

2134
2135
2136
2137
2138
2139
2140
  /* We have successfully halted and closed the VM.  Record this fact. */
  if( p->pc>=0 ){
    db->activeVdbeCnt--;
    if( !p->readOnly ){
      db->writeVdbeCnt--;
    }
    assert( db->activeVdbeCnt>=db->writeVdbeCnt );

  }
  p->magic = VDBE_MAGIC_HALT;
  checkActiveVdbeCnt(db);
  if( p->db->mallocFailed ){
    p->rc = SQLITE_NOMEM;
  }








>







2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
  /* We have successfully halted and closed the VM.  Record this fact. */
  if( p->pc>=0 ){
    db->activeVdbeCnt--;
    if( !p->readOnly ){
      db->writeVdbeCnt--;
    }
    assert( db->activeVdbeCnt>=db->writeVdbeCnt );
    sqlite3ResetInterrupt(db);
  }
  p->magic = VDBE_MAGIC_HALT;
  checkActiveVdbeCnt(db);
  if( p->db->mallocFailed ){
    p->rc = SQLITE_NOMEM;
  }

Changes to test/tkt2820.test.
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  }

  # The INSERT statement within the loop should fail on a
  # constraint violation on the second inserted row.  This
  # should cause the entire INSERT to rollback using a statement
  # journal.
  #
  db eval {SELECT name FROM sqlite_master} {
    catch {db eval {
      INSERT INTO t1 SELECT a+1 FROM t1 ORDER BY a DESC
    }}
  }
  db eval {SELECT a FROM t1 ORDER BY a}
} {1 2}

finish_test







|



|




79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  }

  # The INSERT statement within the loop should fail on a
  # constraint violation on the second inserted row.  This
  # should cause the entire INSERT to rollback using a statement
  # journal.
  #
  catch {db eval {SELECT name FROM sqlite_master} {
    catch {db eval {
      INSERT INTO t1 SELECT a+1 FROM t1 ORDER BY a DESC
    }}
  }}
  db eval {SELECT a FROM t1 ORDER BY a}
} {1 2}

finish_test