aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2018-07-24 22:02:12 +0000
committerdrh <drh@noemail.net>2018-07-24 22:02:12 +0000
commitba968dbfe7f1e7cc227c4b5952c9868f7f036bad (patch)
tree71f1f5ba3f1ace7f8fe86edce1c62c4a86d46c9e /src
parent5a193dd8e609c2cd6827fbb3d9cc4ff7c66e0c25 (diff)
downloadsqlite-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.c2
-rw-r--r--src/build.c2
-rw-r--r--src/main.c8
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/vdbe.c19
-rw-r--r--src/vdbeInt.h4
-rw-r--r--src/vdbeaux.c12
-rw-r--r--src/vtab.c2
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);