Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -1048,11 +1048,12 @@ /* ** Cause any pending operation to stop at its earliest opportunity. */ void sqlite3_interrupt(sqlite3 *db){ - db->u1.isInterrupted = 1; + db->errcodeInterrupt = SQLITE_INTERRUPT; + db->nInterrupt++; } /* ** This function is exactly the same as sqlite3_create_function(), except Index: src/prepare.c ================================================================== --- src/prepare.c +++ src/prepare.c @@ -541,10 +541,11 @@ if( pParse==0 ){ rc = SQLITE_NOMEM; goto end_prepare; } pParse->pReprepare = pReprepare; + pParse->nInterrupt = db->nInterrupt; assert( ppStmt && *ppStmt==0 ); assert( !db->mallocFailed ); assert( sqlite3_mutex_held(db->mutex) ); /* Check to verify that it is possible to get a read lock on all Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -852,14 +852,12 @@ void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); void *pCollNeededArg; sqlite3_value *pErr; /* Most recent error message */ char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ - union { - volatile int isInterrupted; /* True if sqlite3_interrupt has been called */ - double notUsed1; /* Spacer */ - } u1; + u32 nInterrupt; /* Increment on each sqlite3_interrupt() */ + int errcodeInterrupt; /* Reason for the most recent interrupt */ Lookaside lookaside; /* Lookaside malloc configuration */ #ifndef SQLITE_OMIT_AUTHORIZATION int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); /* Access authorization function */ void *pAuthArg; /* 1st argument to the access auth function */ @@ -2171,10 +2169,11 @@ struct Parse { sqlite3 *db; /* The main database structure */ char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ + u32 nInterrupt; /* Interrupts seen prior to this parse */ u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 nTempInUse; /* Number of aTempReg[] currently checked out */ Index: src/tokenize.c ================================================================== --- src/tokenize.c +++ src/tokenize.c @@ -394,13 +394,10 @@ 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); @@ -424,11 +421,11 @@ pParse->rc = SQLITE_TOOBIG; break; } switch( tokenType ){ case TK_SPACE: { - if( db->u1.isInterrupted ){ + if( db->nInterrupt!=pParse->nInterrupt ){ sqlite3ErrorMsg(pParse, "interrupt"); pParse->rc = SQLITE_INTERRUPT; goto abort_parse; } break; Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -474,11 +474,11 @@ ** implement a loop. This test used to be on every single instruction, ** but that meant we more testing than we needed. By only testing the ** flag on jump instructions, we get a (small) speed improvement. */ #define CHECK_FOR_INTERRUPT \ - if( db->u1.isInterrupted ) goto abort_due_to_interrupt; + if( db->nInterrupt!=p->nInterrupt ) goto abort_due_to_interrupt; #ifndef NDEBUG /* ** This function is only called from within an assert() expression. It @@ -6175,11 +6175,11 @@ /* Jump to here if the sqlite3_interrupt() API sets the interrupt ** flag. */ abort_due_to_interrupt: - assert( db->u1.isInterrupted ); - rc = SQLITE_INTERRUPT; + assert( db->nInterrupt!=p->nInterrupt ); + rc = db->errcodeInterrupt; p->rc = rc; sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(rc)); goto vdbe_error_halt; } Index: src/vdbeInt.h ================================================================== --- src/vdbeInt.h +++ src/vdbeInt.h @@ -311,10 +311,11 @@ ynVar nVar; /* Number of entries in aVar[] */ ynVar nzVar; /* Number of entries in azVar[] */ u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ + u32 nInterrupt; /* Interrupts prior to start of this statement */ u8 errorAction; /* Recovery action to do in case of an error */ u8 explain; /* True if EXPLAIN present on SQL command */ u8 changeCntOn; /* True to update the change-counter */ u8 expired; /* True if the VM needs to be recompiled */ u8 runOnlyOnce; /* Automatically expire on reset */ Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -382,18 +382,10 @@ p->rc = SQLITE_SCHEMA; rc = SQLITE_ERROR; goto end_of_step; } if( p->pc<0 ){ - /* If there are no other statements currently running, then - ** reset the interrupt flag. This prevents a call to sqlite3_interrupt - ** from interrupting a statement that has not yet started. - */ - if( db->activeVdbeCnt==0 ){ - db->u1.isInterrupted = 0; - } - assert( db->writeVdbeCnt>0 || db->autoCommit==0 || db->nDeferredCons==0 ); #ifndef SQLITE_OMIT_TRACE if( db->xProfile && !db->init.busy ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); @@ -401,10 +393,11 @@ #endif db->activeVdbeCnt++; if( p->readOnly==0 ) db->writeVdbeCnt++; p->pc = 0; + p->nInterrupt = db->nInterrupt; } #ifndef SQLITE_OMIT_EXPLAIN if( p->explain ){ rc = sqlite3VdbeList(p); }else Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -1191,12 +1191,12 @@ i = p->pc++; }while( iexplain==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; + }else if( db->nInterrupt!=p->nInterrupt ){ + p->rc = db->errcodeInterrupt; rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(p->rc)); }else{ char *z; Op *pOp;