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: |
f256bc0796ca8bd4569dd6de37621c96 |
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
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 | *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 */ | > > > > > > > > > > < < | < | 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 | pParse->rc = SQLITE_TOOBIG; break; } switch( tokenType ){ case TK_SPACE: { if( db->u1.isInterrupted ){ sqlite3ErrorMsg(pParse, "interrupt"); | | | 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 | ** ** 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 */ | < | 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 | */ case OP_Prev: /* jump */ case OP_Next: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; int res; | < | 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 | ** 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 ); | < | 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 | goto vdbe_error_halt; /* Jump to here if the sqlite3_interrupt() API sets the interrupt ** flag. */ abort_due_to_interrupt: assert( db->u1.isInterrupted ); | | | 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 | 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 ){ | | | 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 | } # 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. # | | | | 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 |