diff options
author | drh <drh@noemail.net> | 2018-07-24 22:02:12 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2018-07-24 22:02:12 +0000 |
commit | ba968dbfe7f1e7cc227c4b5952c9868f7f036bad (patch) | |
tree | 71f1f5ba3f1ace7f8fe86edce1c62c4a86d46c9e /src | |
parent | 5a193dd8e609c2cd6827fbb3d9cc4ff7c66e0c25 (diff) | |
download | sqlite-ba968dbfe7f1e7cc227c4b5952c9868f7f036bad.tar.gz sqlite-ba968dbfe7f1e7cc227c4b5952c9868f7f036bad.zip |
Do not abort running queries due to a CREATE INDEX statement. Allow them
to run to completion before being reprepared. Fix for ticket
[c694113e50321afdf9].
FossilOrigin-Name: 2bd593332da0aade467e7a4ee89e966aa6302f37540a2c5e23671f98a6cb599c
Diffstat (limited to 'src')
-rw-r--r-- | src/auth.c | 2 | ||||
-rw-r--r-- | src/build.c | 2 | ||||
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | src/sqliteInt.h | 2 | ||||
-rw-r--r-- | src/vdbe.c | 19 | ||||
-rw-r--r-- | src/vdbeInt.h | 4 | ||||
-rw-r--r-- | src/vdbeaux.c | 12 | ||||
-rw-r--r-- | src/vtab.c | 2 |
8 files changed, 33 insertions, 18 deletions
diff --git a/src/auth.c b/src/auth.c index 03e4cf9f5..a708d0c24 100644 --- a/src/auth.c +++ b/src/auth.c @@ -78,7 +78,7 @@ int sqlite3_set_authorizer( sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } diff --git a/src/build.c b/src/build.c index 6b761da02..af899d278 100644 --- a/src/build.c +++ b/src/build.c @@ -3468,7 +3468,7 @@ void sqlite3CreateIndex( sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); - sqlite3VdbeAddOp0(v, OP_Expire); + sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); } sqlite3VdbeJumpHere(v, pIndex->tnum); diff --git a/src/main.c b/src/main.c index 9c10cab6a..07f668881 100644 --- a/src/main.c +++ b/src/main.c @@ -849,7 +849,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){ db->flags &= ~aFlagOp[i].mask; } if( oldFlags!=db->flags ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); } if( pRes ){ *pRes = (db->flags & aFlagOp[i].mask)!=0; @@ -1292,7 +1292,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ sqlite3EndBenignMalloc(); if( schemaChange ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); } sqlite3BtreeLeaveAll(db); @@ -1747,7 +1747,7 @@ int sqlite3CreateFunc( assert( !db->mallocFailed ); return SQLITE_BUSY; }else{ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); } } @@ -2522,7 +2522,7 @@ static int createCollation( "unable to delete/modify collation sequence due to active statements"); return SQLITE_BUSY; } - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); /* If collation sequence pColl was created directly by a call to ** sqlite3_create_collation, and not generated by synthCollSeq(), diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f84cd780f..2c52dfec5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4223,7 +4223,7 @@ void sqlite3AlterFunctions(void); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); -void sqlite3ExpirePreparedStatements(sqlite3*); +void sqlite3ExpirePreparedStatements(sqlite3*, int); int sqlite3CodeSubselect(Parse*, Expr *, int, int); void sqlite3SelectPrep(Parse*, Select*, NameContext*); void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); diff --git a/src/vdbe.c b/src/vdbe.c index f9c7eba91..39b307980 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3102,7 +3102,7 @@ case OP_Savepoint: { } } if( isSchemaChange ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); db->mDbFlags |= DBFLAG_SchemaChange; } @@ -3391,7 +3391,7 @@ case OP_SetCookie: { if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); p->expired = 0; } if( rc ) goto abort_due_to_error; @@ -3509,7 +3509,7 @@ case OP_OpenWrite: assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); - if( p->expired ){ + if( p->expired==1 ){ rc = SQLITE_ABORT_ROLLBACK; goto abort_due_to_error; } @@ -6690,7 +6690,7 @@ case OP_IncrVacuum: { /* jump */ } #endif -/* Opcode: Expire P1 * * * * +/* Opcode: Expire P1 P2 * * * ** ** Cause precompiled statements to expire. When an expired statement ** is executed using sqlite3_step() it will either automatically @@ -6699,12 +6699,19 @@ case OP_IncrVacuum: { /* jump */ ** ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, ** then only the currently executing statement is expired. +** +** If P2 is 0, then SQL statements are expired immediately. If P2 is 1, +** then running SQL statements are allowed to continue to run to completion. +** The P2==1 case occurs when a CREATE INDEX or similar schema change happens +** that might help the statement run faster but which does not affect the +** correctness of operation. */ case OP_Expire: { + assert( pOp->p2==0 || pOp->p2==1 ); if( !pOp->p1 ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, pOp->p2); }else{ - p->expired = 1; + p->expired = pOp->p2+1; } break; } diff --git a/src/vdbeInt.h b/src/vdbeInt.h index d6c566027..e291825e3 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -390,9 +390,9 @@ struct Vdbe { u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ - bft expired:1; /* True if the VM needs to be recompiled */ - bft doingRerun:1; /* True if rerunning after an auto-reprepare */ + bft expired:2; /* 1: recompile VM immediately 2: when convenient */ bft explain:2; /* True if EXPLAIN present on SQL command */ + bft doingRerun:1; /* True if rerunning after an auto-reprepare */ bft changeCntOn:1; /* True to update the change-counter */ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index d6efead32..4550c7cf7 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -4659,11 +4659,19 @@ void sqlite3VdbeCountChanges(Vdbe *v){ ** programs obsolete. Removing user-defined functions or collating ** sequences, or changing an authorization function are the types of ** things that make prepared statements obsolete. +** +** If iCode is 1, then expiration is advisory. The statement should +** be reprepared before being restarted, but if it is already running +** it is allowed to run to completion. +** +** Internally, this function just sets the Vdbe.expired flag on all +** prepared statements. The flag is set to 1 for an immediate expiration +** and set to 2 for an advisory expiration. */ -void sqlite3ExpirePreparedStatements(sqlite3 *db){ +void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){ Vdbe *p; for(p = db->pVdbe; p; p=p->pNext){ - p->expired = 1; + p->expired = iCode+1; } } diff --git a/src/vtab.c b/src/vtab.c index 7894bbc8b..c9ce83890 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -262,7 +262,7 @@ void sqlite3VtabUnlockList(sqlite3 *db){ assert( sqlite3_mutex_held(db->mutex) ); if( p ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); |