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
diff --git a/src/auth.c b/src/auth.c
index 03e4cf9..a708d0c 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -78,7 +78,7 @@
   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 6b761da..af899d2 100644
--- a/src/build.c
+++ b/src/build.c
@@ -3468,7 +3468,7 @@
       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 9c10cab..07f6688 100644
--- a/src/main.c
+++ b/src/main.c
@@ -849,7 +849,7 @@
             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 @@
   sqlite3EndBenignMalloc();
 
   if( schemaChange ){
-    sqlite3ExpirePreparedStatements(db);
+    sqlite3ExpirePreparedStatements(db, 0);
     sqlite3ResetAllSchemasOfConnection(db);
   }
   sqlite3BtreeLeaveAll(db);
@@ -1747,7 +1747,7 @@
       assert( !db->mallocFailed );
       return SQLITE_BUSY;
     }else{
-      sqlite3ExpirePreparedStatements(db);
+      sqlite3ExpirePreparedStatements(db, 0);
     }
   }
 
@@ -2522,7 +2522,7 @@
         "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 f84cd78..2c52dfe 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -4223,7 +4223,7 @@
 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 f9c7eba..39b3079 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -3102,7 +3102,7 @@
           }
         }
         if( isSchemaChange ){
-          sqlite3ExpirePreparedStatements(db);
+          sqlite3ExpirePreparedStatements(db, 0);
           sqlite3ResetAllSchemasOfConnection(db);
           db->mDbFlags |= DBFLAG_SchemaChange;
         }
@@ -3391,7 +3391,7 @@
   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 @@
   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 @@
 }
 #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 @@
 ** 
 ** 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 d6c5660..e291825 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -390,9 +390,9 @@
   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 d6efead..4550c7c 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -4659,11 +4659,19 @@
 ** 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 7894bbc..c9ce838 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -262,7 +262,7 @@
   assert( sqlite3_mutex_held(db->mutex) );
 
   if( p ){
-    sqlite3ExpirePreparedStatements(db);
+    sqlite3ExpirePreparedStatements(db, 0);
     do {
       VTable *pNext = p->pNext;
       sqlite3VtabUnlock(p);