Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -138,10 +138,11 @@ */ v = sqlite3GetVdbe(pParse); assert( !pParse->isMultiWrite || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ + while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){} sqlite3VdbeAddOp0(v, OP_Halt); /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a Index: src/delete.c ================================================================== --- src/delete.c +++ src/delete.c @@ -788,13 +788,11 @@ ** might be stored in the table as an integer (using a compact ** representation) then converted to REAL by an OP_RealAffinity opcode. ** But we are getting ready to store this value back into an index, where ** it should be converted by to INTEGER again. So omit the OP_RealAffinity ** opcode if it is present */ - if( sqlite3VdbeGetOp(v, -1)->opcode==OP_RealAffinity ){ - sqlite3VdbeDeleteLastOpcode(v); - } + sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); } if( regOut ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); } sqlite3ReleaseTempRange(pParse, regBase, nCol); Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -2291,10 +2291,11 @@ int nSet; /* Number of sets used so far */ int nOnce; /* Number of OP_Once instructions so far */ int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int nLabel; /* Number of labels used */ int *aLabel; /* Space to hold the labels */ + int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */ int ckBase; /* Base register of data during check constraints */ int iPartIdxTab; /* Table corresponding to a partial index */ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */ struct yColCache { Index: src/vdbe.h ================================================================== --- src/vdbe.h +++ src/vdbe.h @@ -173,11 +173,11 @@ void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u8 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); void sqlite3VdbeChangeToNoop(Vdbe*, int addr); -void sqlite3VdbeDeleteLastOpcode(Vdbe*); +int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Vdbe*); Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -274,10 +274,11 @@ assert( v->magic==VDBE_MAGIC_INIT ); assert( jnLabel ); if( j>=0 && p->aLabel ){ p->aLabel[j] = v->nOp; } + p->iFixedOp = v->nOp - 1; } /* ** Mark the VDBE as one that can only be run one time. */ @@ -622,11 +623,12 @@ /* ** Change the P2 operand of instruction addr so that it points to ** the address of the next instruction to be coded. */ void sqlite3VdbeJumpHere(Vdbe *p, int addr){ - if( ALWAYS(addr>=0) ) sqlite3VdbeChangeP2(p, addr, p->nOp); + sqlite3VdbeChangeP2(p, addr, p->nOp); + p->pParse->iFixedOp = p->nOp - 1; } /* ** If the input FuncDef structure is ephemeral, then free it. If @@ -727,12 +729,17 @@ } /* ** Remove the last opcode inserted */ -void sqlite3VdbeDeleteLastOpcode(Vdbe *p){ - p->nOp--; +int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ + if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){ + sqlite3VdbeChangeToNoop(p, p->nOp-1); + return 1; + }else{ + return 0; + } } /* ** Change the value of the P4 operand for a specific instruction. ** This routine is useful when a large program is loaded from a