Index: third_party/sqlite/src/src/vdbeaux.c |
diff --git a/third_party/sqlite/src/src/vdbeaux.c b/third_party/sqlite/src/src/vdbeaux.c |
index dbbb2a6ccb1c0e75f0f2b9f3b1298fb1e78b6971..68f6a5acc84196d391e7c6ac0e75200c542d995d 100644 |
--- a/third_party/sqlite/src/src/vdbeaux.c |
+++ b/third_party/sqlite/src/src/vdbeaux.c |
@@ -21,8 +21,9 @@ |
Vdbe *sqlite3VdbeCreate(Parse *pParse){ |
sqlite3 *db = pParse->db; |
Vdbe *p; |
- p = sqlite3DbMallocZero(db, sizeof(Vdbe) ); |
+ p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) ); |
if( p==0 ) return 0; |
+ memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp)); |
p->db = db; |
if( db->pVdbe ){ |
db->pVdbe->pPrev = p; |
@@ -65,19 +66,12 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ |
} |
/* |
-** Return the SQL associated with a prepared statement |
-*/ |
-const char *sqlite3_sql(sqlite3_stmt *pStmt){ |
- Vdbe *p = (Vdbe *)pStmt; |
- return p ? p->zSql : 0; |
-} |
- |
-/* |
** Swap all content between two VDBE structures. |
*/ |
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ |
Vdbe tmp, *pTmp; |
char *zTmp; |
+ assert( pA->db==pB->db ); |
tmp = *pA; |
*pA = *pB; |
*pB = tmp; |
@@ -129,7 +123,7 @@ static int growOpArray(Vdbe *v, int nOp){ |
p->nOpAlloc = p->szOpAlloc/sizeof(Op); |
v->aOp = pNew; |
} |
- return (pNew ? SQLITE_OK : SQLITE_NOMEM); |
+ return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT); |
} |
#ifdef SQLITE_DEBUG |
@@ -171,7 +165,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ |
i = p->nOp; |
assert( p->magic==VDBE_MAGIC_INIT ); |
- assert( op>0 && op<0xff ); |
+ assert( op>=0 && op<0xff ); |
if( p->pParse->nOpAlloc<=i ){ |
return growOp3(p, op, p1, p2, p3); |
} |
@@ -191,9 +185,8 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ |
if( p->db->flags & SQLITE_VdbeAddopTrace ){ |
int jj, kk; |
Parse *pParse = p->pParse; |
- for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){ |
+ for(jj=kk=0; jj<pParse->nColCache; jj++){ |
struct yColCache *x = pParse->aColCache + jj; |
- if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue; |
printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn); |
kk++; |
} |
@@ -250,8 +243,7 @@ void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){ |
for(i=0; (c = zTypes[i])!=0; i++){ |
if( c=='s' ){ |
const char *z = va_arg(ap, const char*); |
- int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++); |
- if( z ) sqlite3VdbeChangeP4(p, addr, z, 0); |
+ sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0); |
}else{ |
assert( c=='i' ); |
sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++); |
@@ -290,7 +282,7 @@ int sqlite3VdbeAddOp4Dup8( |
const u8 *zP4, /* The P4 operand */ |
int p4type /* P4 operand type */ |
){ |
- char *p4copy = sqlite3DbMallocRaw(sqlite3VdbeDb(p), 8); |
+ char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8); |
if( p4copy ) memcpy(p4copy, zP4, 8); |
return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); |
} |
@@ -305,8 +297,7 @@ int sqlite3VdbeAddOp4Dup8( |
*/ |
void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){ |
int j; |
- int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0); |
- sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC); |
+ sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); |
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j); |
} |
@@ -322,10 +313,29 @@ int sqlite3VdbeAddOp4Int( |
int p4 /* The P4 operand as an integer */ |
){ |
int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); |
- sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32); |
+ if( p->db->mallocFailed==0 ){ |
+ VdbeOp *pOp = &p->aOp[addr]; |
+ pOp->p4type = P4_INT32; |
+ pOp->p4.i = p4; |
+ } |
return addr; |
} |
+/* Insert the end of a co-routine |
+*/ |
+void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){ |
+ sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); |
+ |
+ /* Clear the temporary register cache, thereby ensuring that each |
+ ** co-routine has its own independent set of registers, because co-routines |
+ ** might expect their registers to be preserved across an OP_Yield, and |
+ ** that could cause problems if two or more co-routines are using the same |
+ ** temporary register. |
+ */ |
+ v->pParse->nTempReg = 0; |
+ v->pParse->nRangeReg = 0; |
+} |
+ |
/* |
** Create a new symbolic label for an instruction that has yet to be |
** coded. The symbolic label is really just a negative number. The |
@@ -368,7 +378,6 @@ void sqlite3VdbeResolveLabel(Vdbe *v, int x){ |
if( p->aLabel ){ |
p->aLabel[j] = v->nOp; |
} |
- p->iFixedOp = v->nOp - 1; |
} |
/* |
@@ -378,6 +387,13 @@ void sqlite3VdbeRunOnlyOnce(Vdbe *p){ |
p->runOnlyOnce = 1; |
} |
+/* |
+** Mark the VDBE as one that can only be run multiple times. |
+*/ |
+void sqlite3VdbeReusable(Vdbe *p){ |
+ p->runOnlyOnce = 0; |
+} |
+ |
#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */ |
/* |
@@ -524,73 +540,84 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ |
** (4) Initialize the p4.xAdvance pointer on opcodes that use it. |
** |
** (5) Reclaim the memory allocated for storing labels. |
+** |
+** This routine will only function correctly if the mkopcodeh.tcl generator |
+** script numbers the opcodes correctly. Changes to this routine must be |
+** coordinated with changes to mkopcodeh.tcl. |
*/ |
static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ |
- int i; |
int nMaxArgs = *pMaxFuncArgs; |
Op *pOp; |
Parse *pParse = p->pParse; |
int *aLabel = pParse->aLabel; |
p->readOnly = 1; |
p->bIsReader = 0; |
- for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ |
- u8 opcode = pOp->opcode; |
- |
- /* NOTE: Be sure to update mkopcodeh.awk when adding or removing |
- ** cases from this switch! */ |
- switch( opcode ){ |
- case OP_Transaction: { |
- if( pOp->p2!=0 ) p->readOnly = 0; |
- /* fall thru */ |
- } |
- case OP_AutoCommit: |
- case OP_Savepoint: { |
- p->bIsReader = 1; |
- break; |
- } |
+ pOp = &p->aOp[p->nOp-1]; |
+ while(1){ |
+ |
+ /* Only JUMP opcodes and the short list of special opcodes in the switch |
+ ** below need to be considered. The mkopcodeh.tcl generator script groups |
+ ** all these opcodes together near the front of the opcode list. Skip |
+ ** any opcode that does not need processing by virtual of the fact that |
+ ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization. |
+ */ |
+ if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){ |
+ /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing |
+ ** cases from this switch! */ |
+ switch( pOp->opcode ){ |
+ case OP_Transaction: { |
+ if( pOp->p2!=0 ) p->readOnly = 0; |
+ /* fall thru */ |
+ } |
+ case OP_AutoCommit: |
+ case OP_Savepoint: { |
+ p->bIsReader = 1; |
+ break; |
+ } |
#ifndef SQLITE_OMIT_WAL |
- case OP_Checkpoint: |
+ case OP_Checkpoint: |
#endif |
- case OP_Vacuum: |
- case OP_JournalMode: { |
- p->readOnly = 0; |
- p->bIsReader = 1; |
- break; |
- } |
+ case OP_Vacuum: |
+ case OP_JournalMode: { |
+ p->readOnly = 0; |
+ p->bIsReader = 1; |
+ break; |
+ } |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
- case OP_VUpdate: { |
- if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; |
- break; |
- } |
- case OP_VFilter: { |
- int n; |
- assert( p->nOp - i >= 3 ); |
- assert( pOp[-1].opcode==OP_Integer ); |
- n = pOp[-1].p1; |
- if( n>nMaxArgs ) nMaxArgs = n; |
- break; |
- } |
+ case OP_VUpdate: { |
+ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; |
+ break; |
+ } |
+ case OP_VFilter: { |
+ int n; |
+ assert( (pOp - p->aOp) >= 3 ); |
+ assert( pOp[-1].opcode==OP_Integer ); |
+ n = pOp[-1].p1; |
+ if( n>nMaxArgs ) nMaxArgs = n; |
+ break; |
+ } |
#endif |
- case OP_Next: |
- case OP_NextIfOpen: |
- case OP_SorterNext: { |
- pOp->p4.xAdvance = sqlite3BtreeNext; |
- pOp->p4type = P4_ADVANCE; |
- break; |
+ case OP_Next: |
+ case OP_NextIfOpen: |
+ case OP_SorterNext: { |
+ pOp->p4.xAdvance = sqlite3BtreeNext; |
+ pOp->p4type = P4_ADVANCE; |
+ break; |
+ } |
+ case OP_Prev: |
+ case OP_PrevIfOpen: { |
+ pOp->p4.xAdvance = sqlite3BtreePrevious; |
+ pOp->p4type = P4_ADVANCE; |
+ break; |
+ } |
} |
- case OP_Prev: |
- case OP_PrevIfOpen: { |
- pOp->p4.xAdvance = sqlite3BtreePrevious; |
- pOp->p4type = P4_ADVANCE; |
- break; |
+ if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){ |
+ assert( ADDR(pOp->p2)<pParse->nLabel ); |
+ pOp->p2 = aLabel[ADDR(pOp->p2)]; |
} |
} |
- |
- pOp->opflags = sqlite3OpcodeProperty[opcode]; |
- if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ |
- assert( ADDR(pOp->p2)<pParse->nLabel ); |
- pOp->p2 = aLabel[ADDR(pOp->p2)]; |
- } |
+ if( pOp==p->aOp ) break; |
+ pOp--; |
} |
sqlite3DbFree(p->db, pParse->aLabel); |
pParse->aLabel = 0; |
@@ -608,6 +635,36 @@ int sqlite3VdbeCurrentAddr(Vdbe *p){ |
} |
/* |
+** Verify that at least N opcode slots are available in p without |
+** having to malloc for more space (except when compiled using |
+** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing |
+** to verify that certain calls to sqlite3VdbeAddOpList() can never |
+** fail due to a OOM fault and hence that the return value from |
+** sqlite3VdbeAddOpList() will always be non-NULL. |
+*/ |
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) |
+void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){ |
+ assert( p->nOp + N <= p->pParse->nOpAlloc ); |
+} |
+#endif |
+ |
+/* |
+** Verify that the VM passed as the only argument does not contain |
+** an OP_ResultRow opcode. Fail an assert() if it does. This is used |
+** by code in pragma.c to ensure that the implementation of certain |
+** pragmas comports with the flags specified in the mkpragmatab.tcl |
+** script. |
+*/ |
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) |
+void sqlite3VdbeVerifyNoResultRow(Vdbe *p){ |
+ int i; |
+ for(i=0; i<p->nOp; i++){ |
+ assert( p->aOp[i].opcode!=OP_ResultRow ); |
+ } |
+} |
+#endif |
+ |
+/* |
** This function returns a pointer to the array of opcodes associated with |
** the Vdbe passed as the first argument. It is the callers responsibility |
** to arrange for the returned array to be eventually freed using the |
@@ -632,24 +689,34 @@ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){ |
} |
/* |
-** Add a whole list of operations to the operation stack. Return the |
-** address of the first operation added. |
+** Add a whole list of operations to the operation stack. Return a |
+** pointer to the first operation inserted. |
+** |
+** Non-zero P2 arguments to jump instructions are automatically adjusted |
+** so that the jump target is relative to the first operation inserted. |
*/ |
-int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ |
- int addr, i; |
- VdbeOp *pOut; |
+VdbeOp *sqlite3VdbeAddOpList( |
+ Vdbe *p, /* Add opcodes to the prepared statement */ |
+ int nOp, /* Number of opcodes to add */ |
+ VdbeOpList const *aOp, /* The opcodes to be added */ |
+ int iLineno /* Source-file line number of first opcode */ |
+){ |
+ int i; |
+ VdbeOp *pOut, *pFirst; |
assert( nOp>0 ); |
assert( p->magic==VDBE_MAGIC_INIT ); |
if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){ |
return 0; |
} |
- addr = p->nOp; |
- pOut = &p->aOp[addr]; |
+ pFirst = pOut = &p->aOp[p->nOp]; |
for(i=0; i<nOp; i++, aOp++, pOut++){ |
pOut->opcode = aOp->opcode; |
pOut->p1 = aOp->p1; |
pOut->p2 = aOp->p2; |
assert( aOp->p2>=0 ); |
+ if( (sqlite3OpcodeProperty[aOp->opcode] & OPFLG_JUMP)!=0 && aOp->p2>0 ){ |
+ pOut->p2 += p->nOp; |
+ } |
pOut->p3 = aOp->p3; |
pOut->p4type = P4_NOTUSED; |
pOut->p4.p = 0; |
@@ -664,12 +731,12 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ |
#endif |
#ifdef SQLITE_DEBUG |
if( p->db->flags & SQLITE_VdbeAddopTrace ){ |
- sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); |
+ sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]); |
} |
#endif |
} |
p->nOp += nOp; |
- return addr; |
+ return pFirst; |
} |
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) |
@@ -716,8 +783,9 @@ void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){ |
void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){ |
sqlite3VdbeGetOp(p,addr)->p3 = val; |
} |
-void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){ |
- sqlite3VdbeGetOp(p,-1)->p5 = p5; |
+void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ |
+ assert( p->nOp>0 || p->db->mallocFailed ); |
+ if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5; |
} |
/* |
@@ -725,7 +793,6 @@ void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){ |
** the address of the next instruction to be coded. |
*/ |
void sqlite3VdbeJumpHere(Vdbe *p, int addr){ |
- p->pParse->iFixedOp = p->nOp - 1; |
sqlite3VdbeChangeP2(p, addr, p->nOp); |
} |
@@ -735,7 +802,7 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){ |
** the FuncDef is not ephermal, then do nothing. |
*/ |
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ |
- if( ALWAYS(pDef) && (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ |
+ if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ |
sqlite3DbFree(db, pDef); |
} |
} |
@@ -745,53 +812,53 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int); |
/* |
** Delete a P4 value if necessary. |
*/ |
+static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ |
+ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); |
+ sqlite3DbFree(db, p); |
+} |
+static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ |
+ freeEphemeralFunction(db, p->pFunc); |
+ sqlite3DbFree(db, p); |
+} |
static void freeP4(sqlite3 *db, int p4type, void *p4){ |
- if( p4 ){ |
- assert( db ); |
- switch( p4type ){ |
- case P4_FUNCCTX: { |
- freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc); |
- /* Fall through into the next case */ |
- } |
- case P4_REAL: |
- case P4_INT64: |
- case P4_DYNAMIC: |
- case P4_INTARRAY: { |
- sqlite3DbFree(db, p4); |
- break; |
- } |
- case P4_KEYINFO: { |
- if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); |
- break; |
- } |
+ assert( db ); |
+ switch( p4type ){ |
+ case P4_FUNCCTX: { |
+ freeP4FuncCtx(db, (sqlite3_context*)p4); |
+ break; |
+ } |
+ case P4_REAL: |
+ case P4_INT64: |
+ case P4_DYNAMIC: |
+ case P4_INTARRAY: { |
+ sqlite3DbFree(db, p4); |
+ break; |
+ } |
+ case P4_KEYINFO: { |
+ if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); |
+ break; |
+ } |
#ifdef SQLITE_ENABLE_CURSOR_HINTS |
- case P4_EXPR: { |
- sqlite3ExprDelete(db, (Expr*)p4); |
- break; |
- } |
+ case P4_EXPR: { |
+ sqlite3ExprDelete(db, (Expr*)p4); |
+ break; |
+ } |
#endif |
- case P4_MPRINTF: { |
- if( db->pnBytesFreed==0 ) sqlite3_free(p4); |
- break; |
- } |
- case P4_FUNCDEF: { |
- freeEphemeralFunction(db, (FuncDef*)p4); |
- break; |
- } |
- case P4_MEM: { |
- if( db->pnBytesFreed==0 ){ |
- sqlite3ValueFree((sqlite3_value*)p4); |
- }else{ |
- Mem *p = (Mem*)p4; |
- if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); |
- sqlite3DbFree(db, p); |
- } |
- break; |
- } |
- case P4_VTAB : { |
- if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); |
- break; |
+ case P4_FUNCDEF: { |
+ freeEphemeralFunction(db, (FuncDef*)p4); |
+ break; |
+ } |
+ case P4_MEM: { |
+ if( db->pnBytesFreed==0 ){ |
+ sqlite3ValueFree((sqlite3_value*)p4); |
+ }else{ |
+ freeP4Mem(db, (Mem*)p4); |
} |
+ break; |
+ } |
+ case P4_VTAB : { |
+ if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); |
+ break; |
} |
} |
} |
@@ -805,7 +872,7 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ |
if( aOp ){ |
Op *pOp; |
for(pOp=aOp; pOp<&aOp[nOp]; pOp++){ |
- freeP4(db, pOp->p4type, pOp->p4.p); |
+ if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p); |
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS |
sqlite3DbFree(db, pOp->zComment); |
#endif |
@@ -827,14 +894,16 @@ void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ |
/* |
** Change the opcode at addr into OP_Noop |
*/ |
-void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ |
- if( addr<p->nOp ){ |
- VdbeOp *pOp = &p->aOp[addr]; |
- sqlite3 *db = p->db; |
- freeP4(db, pOp->p4type, pOp->p4.p); |
- memset(pOp, 0, sizeof(pOp[0])); |
- pOp->opcode = OP_Noop; |
- } |
+int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ |
+ VdbeOp *pOp; |
+ if( p->db->mallocFailed ) return 0; |
+ assert( addr>=0 && addr<p->nOp ); |
+ pOp = &p->aOp[addr]; |
+ freeP4(p->db, pOp->p4type, pOp->p4.p); |
+ pOp->p4type = P4_NOTUSED; |
+ pOp->p4.z = 0; |
+ pOp->opcode = OP_Noop; |
+ return 1; |
} |
/* |
@@ -842,9 +911,8 @@ void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ |
** then remove it. Return true if and only if an opcode was removed. |
*/ |
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; |
+ if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){ |
+ return sqlite3VdbeChangeToNoop(p, p->nOp-1); |
}else{ |
return 0; |
} |
@@ -867,16 +935,34 @@ int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ |
** |
** If addr<0 then change P4 on the most recently inserted instruction. |
*/ |
+static void SQLITE_NOINLINE vdbeChangeP4Full( |
+ Vdbe *p, |
+ Op *pOp, |
+ const char *zP4, |
+ int n |
+){ |
+ if( pOp->p4type ){ |
+ freeP4(p->db, pOp->p4type, pOp->p4.p); |
+ pOp->p4type = 0; |
+ pOp->p4.p = 0; |
+ } |
+ if( n<0 ){ |
+ sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n); |
+ }else{ |
+ if( n==0 ) n = sqlite3Strlen30(zP4); |
+ pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); |
+ pOp->p4type = P4_DYNAMIC; |
+ } |
+} |
void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ |
Op *pOp; |
sqlite3 *db; |
assert( p!=0 ); |
db = p->db; |
assert( p->magic==VDBE_MAGIC_INIT ); |
- if( p->aOp==0 || db->mallocFailed ){ |
- if( n!=P4_VTAB ){ |
- freeP4(db, n, (void*)*(char**)&zP4); |
- } |
+ assert( p->aOp!=0 || db->mallocFailed ); |
+ if( db->mallocFailed ){ |
+ if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4); |
return; |
} |
assert( p->nOp>0 ); |
@@ -885,43 +971,45 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ |
addr = p->nOp - 1; |
} |
pOp = &p->aOp[addr]; |
- assert( pOp->p4type==P4_NOTUSED |
- || pOp->p4type==P4_INT32 |
- || pOp->p4type==P4_KEYINFO ); |
- freeP4(db, pOp->p4type, pOp->p4.p); |
- pOp->p4.p = 0; |
+ if( n>=0 || pOp->p4type ){ |
+ vdbeChangeP4Full(p, pOp, zP4, n); |
+ return; |
+ } |
if( n==P4_INT32 ){ |
/* Note: this cast is safe, because the origin data point was an int |
** that was cast to a (const char *). */ |
pOp->p4.i = SQLITE_PTR_TO_INT(zP4); |
pOp->p4type = P4_INT32; |
- }else if( zP4==0 ){ |
- pOp->p4.p = 0; |
- pOp->p4type = P4_NOTUSED; |
- }else if( n==P4_KEYINFO ){ |
- pOp->p4.p = (void*)zP4; |
- pOp->p4type = P4_KEYINFO; |
-#ifdef SQLITE_ENABLE_CURSOR_HINTS |
- }else if( n==P4_EXPR ){ |
- /* Responsibility for deleting the Expr tree is handed over to the |
- ** VDBE by this operation. The caller should have already invoked |
- ** sqlite3ExprDup() or whatever other routine is needed to make a |
- ** private copy of the tree. */ |
- pOp->p4.pExpr = (Expr*)zP4; |
- pOp->p4type = P4_EXPR; |
-#endif |
- }else if( n==P4_VTAB ){ |
- pOp->p4.p = (void*)zP4; |
- pOp->p4type = P4_VTAB; |
- sqlite3VtabLock((VTable *)zP4); |
- assert( ((VTable *)zP4)->db==p->db ); |
- }else if( n<0 ){ |
+ }else if( zP4!=0 ){ |
+ assert( n<0 ); |
pOp->p4.p = (void*)zP4; |
pOp->p4type = (signed char)n; |
+ if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4); |
+ } |
+} |
+ |
+/* |
+** Change the P4 operand of the most recently coded instruction |
+** to the value defined by the arguments. This is a high-speed |
+** version of sqlite3VdbeChangeP4(). |
+** |
+** The P4 operand must not have been previously defined. And the new |
+** P4 must not be P4_INT32. Use sqlite3VdbeChangeP4() in either of |
+** those cases. |
+*/ |
+void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){ |
+ VdbeOp *pOp; |
+ assert( n!=P4_INT32 && n!=P4_VTAB ); |
+ assert( n<=0 ); |
+ if( p->db->mallocFailed ){ |
+ freeP4(p->db, n, pP4); |
}else{ |
- if( n==0 ) n = sqlite3Strlen30(zP4); |
- pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); |
- pOp->p4type = P4_DYNAMIC; |
+ assert( pP4!=0 ); |
+ assert( p->nOp>0 ); |
+ pOp = &p->aOp[p->nOp-1]; |
+ assert( pOp->p4type==P4_NOTUSED ); |
+ pOp->p4type = n; |
+ pOp->p4.p = pP4; |
} |
} |
@@ -931,10 +1019,11 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ |
*/ |
void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){ |
Vdbe *v = pParse->pVdbe; |
+ KeyInfo *pKeyInfo; |
assert( v!=0 ); |
assert( pIdx!=0 ); |
- sqlite3VdbeChangeP4(v, -1, (char*)sqlite3KeyInfoOfIndex(pParse, pIdx), |
- P4_KEYINFO); |
+ pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pIdx); |
+ if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); |
} |
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS |
@@ -1046,12 +1135,21 @@ static int displayComment( |
const char *zSynopsis; |
int nOpName; |
int ii, jj; |
+ char zAlt[50]; |
zOpName = sqlite3OpcodeName(pOp->opcode); |
nOpName = sqlite3Strlen30(zOpName); |
if( zOpName[nOpName+1] ){ |
int seenCom = 0; |
char c; |
zSynopsis = zOpName += nOpName + 1; |
+ if( strncmp(zSynopsis,"IF ",3)==0 ){ |
+ if( pOp->p5 & SQLITE_STOREP2 ){ |
+ sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3); |
+ }else{ |
+ sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); |
+ } |
+ zSynopsis = zAlt; |
+ } |
for(ii=jj=0; jj<nTemp-1 && (c = zSynopsis[ii])!=0; ii++){ |
if( c=='P' ){ |
c = zSynopsis[++ii]; |
@@ -1105,28 +1203,27 @@ static int displayComment( |
** Translate the P4.pExpr value for an OP_CursorHint opcode into text |
** that can be displayed in the P4 column of EXPLAIN output. |
*/ |
-static int displayP4Expr(int nTemp, char *zTemp, Expr *pExpr){ |
+static void displayP4Expr(StrAccum *p, Expr *pExpr){ |
const char *zOp = 0; |
- int n; |
switch( pExpr->op ){ |
case TK_STRING: |
- sqlite3_snprintf(nTemp, zTemp, "%Q", pExpr->u.zToken); |
+ sqlite3XPrintf(p, "%Q", pExpr->u.zToken); |
break; |
case TK_INTEGER: |
- sqlite3_snprintf(nTemp, zTemp, "%d", pExpr->u.iValue); |
+ sqlite3XPrintf(p, "%d", pExpr->u.iValue); |
break; |
case TK_NULL: |
- sqlite3_snprintf(nTemp, zTemp, "NULL"); |
+ sqlite3XPrintf(p, "NULL"); |
break; |
case TK_REGISTER: { |
- sqlite3_snprintf(nTemp, zTemp, "r[%d]", pExpr->iTable); |
+ sqlite3XPrintf(p, "r[%d]", pExpr->iTable); |
break; |
} |
case TK_COLUMN: { |
if( pExpr->iColumn<0 ){ |
- sqlite3_snprintf(nTemp, zTemp, "rowid"); |
+ sqlite3XPrintf(p, "rowid"); |
}else{ |
- sqlite3_snprintf(nTemp, zTemp, "c%d", (int)pExpr->iColumn); |
+ sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn); |
} |
break; |
} |
@@ -1158,21 +1255,19 @@ static int displayP4Expr(int nTemp, char *zTemp, Expr *pExpr){ |
case TK_NOTNULL: zOp = "NOTNULL"; break; |
default: |
- sqlite3_snprintf(nTemp, zTemp, "%s", "expr"); |
+ sqlite3XPrintf(p, "%s", "expr"); |
break; |
} |
if( zOp ){ |
- sqlite3_snprintf(nTemp, zTemp, "%s(", zOp); |
- n = sqlite3Strlen30(zTemp); |
- n += displayP4Expr(nTemp-n, zTemp+n, pExpr->pLeft); |
- if( n<nTemp-1 && pExpr->pRight ){ |
- zTemp[n++] = ','; |
- n += displayP4Expr(nTemp-n, zTemp+n, pExpr->pRight); |
- } |
- sqlite3_snprintf(nTemp-n, zTemp+n, ")"); |
+ sqlite3XPrintf(p, "%s(", zOp); |
+ displayP4Expr(p, pExpr->pLeft); |
+ if( pExpr->pRight ){ |
+ sqlite3StrAccumAppend(p, ",", 1); |
+ displayP4Expr(p, pExpr->pRight); |
+ } |
+ sqlite3StrAccumAppend(p, ")", 1); |
} |
- return sqlite3Strlen30(zTemp); |
} |
#endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */ |
@@ -1184,72 +1279,57 @@ static int displayP4Expr(int nTemp, char *zTemp, Expr *pExpr){ |
*/ |
static char *displayP4(Op *pOp, char *zTemp, int nTemp){ |
char *zP4 = zTemp; |
+ StrAccum x; |
assert( nTemp>=20 ); |
+ sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0); |
switch( pOp->p4type ){ |
case P4_KEYINFO: { |
- int i, j; |
+ int j; |
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; |
assert( pKeyInfo->aSortOrder!=0 ); |
- sqlite3_snprintf(nTemp, zTemp, "k(%d", pKeyInfo->nField); |
- i = sqlite3Strlen30(zTemp); |
+ sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField); |
for(j=0; j<pKeyInfo->nField; j++){ |
CollSeq *pColl = pKeyInfo->aColl[j]; |
- const char *zColl = pColl ? pColl->zName : "nil"; |
- int n = sqlite3Strlen30(zColl); |
- if( n==6 && memcmp(zColl,"BINARY",6)==0 ){ |
- zColl = "B"; |
- n = 1; |
- } |
- if( i+n>nTemp-7 ){ |
- memcpy(&zTemp[i],",...",4); |
- i += 4; |
- break; |
- } |
- zTemp[i++] = ','; |
- if( pKeyInfo->aSortOrder[j] ){ |
- zTemp[i++] = '-'; |
- } |
- memcpy(&zTemp[i], zColl, n+1); |
- i += n; |
+ const char *zColl = pColl ? pColl->zName : ""; |
+ if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; |
+ sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl); |
} |
- zTemp[i++] = ')'; |
- zTemp[i] = 0; |
- assert( i<nTemp ); |
+ sqlite3StrAccumAppend(&x, ")", 1); |
break; |
} |
#ifdef SQLITE_ENABLE_CURSOR_HINTS |
case P4_EXPR: { |
- displayP4Expr(nTemp, zTemp, pOp->p4.pExpr); |
+ displayP4Expr(&x, pOp->p4.pExpr); |
break; |
} |
#endif |
case P4_COLLSEQ: { |
CollSeq *pColl = pOp->p4.pColl; |
- sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName); |
+ sqlite3XPrintf(&x, "(%.20s)", pColl->zName); |
break; |
} |
case P4_FUNCDEF: { |
FuncDef *pDef = pOp->p4.pFunc; |
- sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg); |
+ sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); |
break; |
} |
-#ifdef SQLITE_DEBUG |
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) |
case P4_FUNCCTX: { |
FuncDef *pDef = pOp->p4.pCtx->pFunc; |
- sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg); |
+ sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); |
break; |
} |
#endif |
case P4_INT64: { |
- sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64); |
+ sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64); |
break; |
} |
case P4_INT32: { |
- sqlite3_snprintf(nTemp, zTemp, "%d", pOp->p4.i); |
+ sqlite3XPrintf(&x, "%d", pOp->p4.i); |
break; |
} |
case P4_REAL: { |
- sqlite3_snprintf(nTemp, zTemp, "%.16g", *pOp->p4.pReal); |
+ sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal); |
break; |
} |
case P4_MEM: { |
@@ -1257,11 +1337,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ |
if( pMem->flags & MEM_Str ){ |
zP4 = pMem->z; |
}else if( pMem->flags & MEM_Int ){ |
- sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i); |
+ sqlite3XPrintf(&x, "%lld", pMem->u.i); |
}else if( pMem->flags & MEM_Real ){ |
- sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r); |
+ sqlite3XPrintf(&x, "%.16g", pMem->u.r); |
}else if( pMem->flags & MEM_Null ){ |
- sqlite3_snprintf(nTemp, zTemp, "NULL"); |
+ zP4 = "NULL"; |
}else{ |
assert( pMem->flags & MEM_Blob ); |
zP4 = "(blob)"; |
@@ -1271,22 +1351,34 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
case P4_VTAB: { |
sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; |
- sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab); |
+ sqlite3XPrintf(&x, "vtab:%p", pVtab); |
break; |
} |
#endif |
case P4_INTARRAY: { |
- sqlite3_snprintf(nTemp, zTemp, "intarray"); |
+ int i; |
+ int *ai = pOp->p4.ai; |
+ int n = ai[0]; /* The first element of an INTARRAY is always the |
+ ** count of the number of elements to follow */ |
+ for(i=1; i<n; i++){ |
+ sqlite3XPrintf(&x, ",%d", ai[i]); |
+ } |
+ zTemp[0] = '['; |
+ sqlite3StrAccumAppend(&x, "]", 1); |
break; |
} |
case P4_SUBPROGRAM: { |
- sqlite3_snprintf(nTemp, zTemp, "program"); |
+ sqlite3XPrintf(&x, "program"); |
break; |
} |
case P4_ADVANCE: { |
zTemp[0] = 0; |
break; |
} |
+ case P4_TABLE: { |
+ sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName); |
+ break; |
+ } |
default: { |
zP4 = pOp->p4.z; |
if( zP4==0 ){ |
@@ -1295,6 +1387,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ |
} |
} |
} |
+ sqlite3StrAccumFinish(&x); |
assert( zP4!=0 ); |
return zP4; |
} |
@@ -1317,7 +1410,7 @@ void sqlite3VdbeUsesBtree(Vdbe *p, int i){ |
} |
} |
-#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 |
+#if !defined(SQLITE_OMIT_SHARED_CACHE) |
/* |
** If SQLite is compiled to support shared-cache mode and to be threadsafe, |
** this routine obtains the mutex associated with each BtShared structure |
@@ -1408,13 +1501,27 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ |
#endif |
/* |
+** Initialize an array of N Mem element. |
+*/ |
+static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ |
+ while( (N--)>0 ){ |
+ p->db = db; |
+ p->flags = flags; |
+ p->szMalloc = 0; |
+#ifdef SQLITE_DEBUG |
+ p->pScopyFrom = 0; |
+#endif |
+ p++; |
+ } |
+} |
+ |
+/* |
** Release an array of N Mem elements |
*/ |
static void releaseMemArray(Mem *p, int N){ |
if( p && N ){ |
Mem *pEnd = &p[N]; |
sqlite3 *db = p->db; |
- u8 malloc_failed = db->mallocFailed; |
if( db->pnBytesFreed ){ |
do{ |
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); |
@@ -1450,7 +1557,6 @@ static void releaseMemArray(Mem *p, int N){ |
p->flags = MEM_Undefined; |
}while( (++p)<pEnd ); |
- db->mallocFailed = malloc_failed; |
} |
} |
@@ -1466,6 +1572,7 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){ |
sqlite3VdbeFreeCursor(p->v, apCsr[i]); |
} |
releaseMemArray(aMem, p->nChildMem); |
+ sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0); |
sqlite3DbFree(p->v->db, p); |
} |
@@ -1508,10 +1615,10 @@ int sqlite3VdbeList( |
releaseMemArray(pMem, 8); |
p->pResultSet = 0; |
- if( p->rc==SQLITE_NOMEM ){ |
+ if( p->rc==SQLITE_NOMEM_BKPT ){ |
/* This happens if a malloc() inside a call to sqlite3_column_text() or |
** sqlite3_column_text16() failed. */ |
- db->mallocFailed = 1; |
+ sqlite3OomFault(db); |
return SQLITE_ERROR; |
} |
@@ -1619,6 +1726,7 @@ int sqlite3VdbeList( |
pMem->flags = MEM_Str|MEM_Term; |
zP4 = displayP4(pOp, pMem->z, pMem->szMalloc); |
if( zP4!=pMem->z ){ |
+ pMem->n = 0; |
sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0); |
}else{ |
assert( pMem->z!=0 ); |
@@ -1709,41 +1817,43 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){ |
} |
#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */ |
-/* |
-** Allocate space from a fixed size buffer and return a pointer to |
-** that space. If insufficient space is available, return NULL. |
-** |
-** The pBuf parameter is the initial value of a pointer which will |
-** receive the new memory. pBuf is normally NULL. If pBuf is not |
-** NULL, it means that memory space has already been allocated and that |
-** this routine should not allocate any new memory. When pBuf is not |
-** NULL simply return pBuf. Only allocate new memory space when pBuf |
-** is NULL. |
-** |
-** nByte is the number of bytes of space needed. |
+/* An instance of this object describes bulk memory available for use |
+** by subcomponents of a prepared statement. Space is allocated out |
+** of a ReusableSpace object by the allocSpace() routine below. |
+*/ |
+struct ReusableSpace { |
+ u8 *pSpace; /* Available memory */ |
+ int nFree; /* Bytes of available memory */ |
+ int nNeeded; /* Total bytes that could not be allocated */ |
+}; |
+ |
+/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf |
+** from the ReusableSpace object. Return a pointer to the allocated |
+** memory on success. If insufficient memory is available in the |
+** ReusableSpace object, increase the ReusableSpace.nNeeded |
+** value by the amount needed and return NULL. |
** |
-** pFrom points to *pnFrom bytes of available space. New space is allocated |
-** from the end of the pFrom buffer and *pnFrom is decremented. |
+** If pBuf is not initially NULL, that means that the memory has already |
+** been allocated by a prior call to this routine, so just return a copy |
+** of pBuf and leave ReusableSpace unchanged. |
** |
-** *pnNeeded is a counter of the number of bytes of space that have failed |
-** to allocate. If there is insufficient space in pFrom to satisfy the |
-** request, then increment *pnNeeded by the amount of the request. |
+** This allocator is employed to repurpose unused slots at the end of the |
+** opcode array of prepared state for other memory needs of the prepared |
+** statement. |
*/ |
static void *allocSpace( |
- void *pBuf, /* Where return pointer will be stored */ |
- int nByte, /* Number of bytes to allocate */ |
- u8 *pFrom, /* Memory available for allocation */ |
- int *pnFrom, /* IN/OUT: Space available at pFrom */ |
- int *pnNeeded /* If allocation cannot be made, increment *pnByte */ |
+ struct ReusableSpace *p, /* Bulk memory available for allocation */ |
+ void *pBuf, /* Pointer to a prior allocation */ |
+ int nByte /* Bytes of memory needed */ |
){ |
- assert( EIGHT_BYTE_ALIGNMENT(pFrom) ); |
+ assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); |
if( pBuf==0 ){ |
nByte = ROUND8(nByte); |
- if( nByte <= *pnFrom ){ |
- *pnFrom -= nByte; |
- pBuf = &pFrom[*pnFrom]; |
+ if( nByte <= p->nFree ){ |
+ p->nFree -= nByte; |
+ pBuf = &p->pSpace[p->nFree]; |
}else{ |
- *pnNeeded += nByte; |
+ p->nNeeded += nByte; |
} |
} |
assert( EIGHT_BYTE_ALIGNMENT(pBuf) ); |
@@ -1759,7 +1869,7 @@ void sqlite3VdbeRewind(Vdbe *p){ |
int i; |
#endif |
assert( p!=0 ); |
- assert( p->magic==VDBE_MAGIC_INIT ); |
+ assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET ); |
/* There should be at least one opcode. |
*/ |
@@ -1769,14 +1879,13 @@ void sqlite3VdbeRewind(Vdbe *p){ |
p->magic = VDBE_MAGIC_RUN; |
#ifdef SQLITE_DEBUG |
- for(i=1; i<p->nMem; i++){ |
+ for(i=0; i<p->nMem; i++){ |
assert( p->aMem[i].db==p->db ); |
} |
#endif |
p->pc = -1; |
p->rc = SQLITE_OK; |
p->errorAction = OE_Abort; |
- p->magic = VDBE_MAGIC_RUN; |
p->nChange = 0; |
p->cacheCtr = 1; |
p->minWriteFileFormat = 255; |
@@ -1817,11 +1926,8 @@ void sqlite3VdbeMakeReady( |
int nMem; /* Number of VM memory registers */ |
int nCursor; /* Number of cursors required */ |
int nArg; /* Number of arguments in subprograms */ |
- int nOnce; /* Number of OP_Once instructions */ |
int n; /* Loop counter */ |
- int nFree; /* Available free space */ |
- u8 *zCsr; /* Memory available for allocation */ |
- int nByte; /* How much extra memory is needed */ |
+ struct ReusableSpace x; /* Reusable bulk memory */ |
assert( p!=0 ); |
assert( p->nOp>0 ); |
@@ -1834,35 +1940,25 @@ void sqlite3VdbeMakeReady( |
nMem = pParse->nMem; |
nCursor = pParse->nTab; |
nArg = pParse->nMaxArg; |
- nOnce = pParse->nOnce; |
- if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */ |
- /* For each cursor required, also allocate a memory cell. Memory |
- ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by |
- ** the vdbe program. Instead they are used to allocate space for |
- ** VdbeCursor/BtCursor structures. The blob of memory associated with |
- ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1) |
- ** stores the blob of memory associated with cursor 1, etc. |
- ** |
+ /* Each cursor uses a memory cell. The first cursor (cursor 0) can |
+ ** use aMem[0] which is not otherwise used by the VDBE program. Allocate |
+ ** space at the end of aMem[] for cursors 1 and greater. |
** See also: allocateCursor(). |
*/ |
nMem += nCursor; |
+ if( nCursor==0 && nMem>0 ) nMem++; /* Space for aMem[0] even if not used */ |
- /* zCsr will initially point to nFree bytes of unused space at the |
- ** end of the opcode array, p->aOp. The computation of nFree is |
- ** conservative - it might be smaller than the true number of free |
- ** bytes, but never larger. nFree must be a multiple of 8 - it is |
- ** rounded down if is not. |
+ /* Figure out how much reusable memory is available at the end of the |
+ ** opcode array. This extra memory will be reallocated for other elements |
+ ** of the prepared statement. |
*/ |
- n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode space used */ |
- zCsr = &((u8*)p->aOp)[n]; /* Unused opcode space */ |
- assert( EIGHT_BYTE_ALIGNMENT(zCsr) ); |
- nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused space */ |
- assert( nFree>=0 ); |
- if( nFree>0 ){ |
- memset(zCsr, 0, nFree); |
- assert( EIGHT_BYTE_ALIGNMENT(&zCsr[nFree]) ); |
- } |
+ n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */ |
+ x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */ |
+ assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) ); |
+ x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */ |
+ assert( x.nFree>=0 ); |
+ assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) ); |
resolveP2Values(p, &nArg); |
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); |
@@ -1871,58 +1967,48 @@ void sqlite3VdbeMakeReady( |
} |
p->expired = 0; |
- /* Memory for registers, parameters, cursor, etc, is allocated in two |
- ** passes. On the first pass, we try to reuse unused space at the |
+ /* Memory for registers, parameters, cursor, etc, is allocated in one or two |
+ ** passes. On the first pass, we try to reuse unused memory at the |
** end of the opcode array. If we are unable to satisfy all memory |
** requirements by reusing the opcode array tail, then the second |
- ** pass will fill in the rest using a fresh allocation. |
+ ** pass will fill in the remainder using a fresh memory allocation. |
** |
** This two-pass approach that reuses as much memory as possible from |
- ** the leftover space at the end of the opcode array can significantly |
+ ** the leftover memory at the end of the opcode array. This can significantly |
** reduce the amount of memory held by a prepared statement. |
*/ |
do { |
- nByte = 0; |
- p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte); |
- p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte); |
- p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte); |
- p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), zCsr, &nFree, &nByte); |
- p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*), |
- zCsr, &nFree, &nByte); |
- p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte); |
+ x.nNeeded = 0; |
+ p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem)); |
+ p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem)); |
+ p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*)); |
+ p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); |
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS |
- p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte); |
+ p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64)); |
#endif |
- if( nByte ){ |
- p->pFree = sqlite3DbMallocZero(db, nByte); |
- } |
- zCsr = p->pFree; |
- nFree = nByte; |
- }while( nByte && !db->mallocFailed ); |
+ if( x.nNeeded==0 ) break; |
+ x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded); |
+ x.nFree = x.nNeeded; |
+ }while( !db->mallocFailed ); |
- p->nCursor = nCursor; |
- p->nOnceFlag = nOnce; |
- if( p->aVar ){ |
+ p->pVList = pParse->pVList; |
+ pParse->pVList = 0; |
+ p->explain = pParse->explain; |
+ if( db->mallocFailed ){ |
+ p->nVar = 0; |
+ p->nCursor = 0; |
+ p->nMem = 0; |
+ }else{ |
+ p->nCursor = nCursor; |
p->nVar = (ynVar)nVar; |
- for(n=0; n<nVar; n++){ |
- p->aVar[n].flags = MEM_Null; |
- p->aVar[n].db = db; |
- } |
- } |
- if( p->azVar && pParse->nzVar>0 ){ |
- p->nzVar = pParse->nzVar; |
- memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0])); |
- memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0])); |
- } |
- if( p->aMem ){ |
- p->aMem--; /* aMem[] goes from 1..nMem */ |
- p->nMem = nMem; /* not from 0..nMem-1 */ |
- for(n=1; n<=nMem; n++){ |
- p->aMem[n].flags = MEM_Undefined; |
- p->aMem[n].db = db; |
- } |
+ initMemArray(p->aVar, nVar, db, MEM_Null); |
+ p->nMem = nMem; |
+ initMemArray(p->aMem, nMem, db, MEM_Undefined); |
+ memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*)); |
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS |
+ memset(p->anExec, 0, p->nOp*sizeof(i64)); |
+#endif |
} |
- p->explain = pParse->explain; |
sqlite3VdbeRewind(p); |
} |
@@ -1934,15 +2020,15 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ |
if( pCx==0 ){ |
return; |
} |
- assert( pCx->pBt==0 || pCx->eCurType==CURTYPE_BTREE ); |
+ assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE ); |
switch( pCx->eCurType ){ |
case CURTYPE_SORTER: { |
sqlite3VdbeSorterClose(p->db, pCx); |
break; |
} |
case CURTYPE_BTREE: { |
- if( pCx->pBt ){ |
- sqlite3BtreeClose(pCx->pBt); |
+ if( pCx->pBtx ){ |
+ sqlite3BtreeClose(pCx->pBtx); |
/* The pCx->pCursor will be close automatically, if it exists, by |
** the call above. */ |
}else{ |
@@ -1991,8 +2077,6 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ |
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS |
v->anExec = pFrame->anExec; |
#endif |
- v->aOnceFlag = pFrame->aOnceFlag; |
- v->nOnceFlag = pFrame->nOnceFlag; |
v->aOp = pFrame->aOp; |
v->nOp = pFrame->nOp; |
v->aMem = pFrame->aMem; |
@@ -2002,6 +2086,9 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ |
v->db->lastRowid = pFrame->lastRowid; |
v->nChange = pFrame->nChange; |
v->db->nChange = pFrame->nDbChange; |
+ sqlite3VdbeDeleteAuxData(v->db, &v->pAuxData, -1, 0); |
+ v->pAuxData = pFrame->pAuxData; |
+ pFrame->pAuxData = 0; |
return pFrame->pc; |
} |
@@ -2024,7 +2111,7 @@ static void closeAllCursors(Vdbe *p){ |
assert( p->nFrame==0 ); |
closeCursorsInFrame(p); |
if( p->aMem ){ |
- releaseMemArray(&p->aMem[1], p->nMem); |
+ releaseMemArray(p->aMem, p->nMem); |
} |
while( p->pDelFrame ){ |
VdbeFrame *pDel = p->pDelFrame; |
@@ -2033,7 +2120,7 @@ static void closeAllCursors(Vdbe *p){ |
} |
/* Delete any auxdata allocations made by the VM */ |
- if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0); |
+ if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p->db, &p->pAuxData, -1, 0); |
assert( p->pAuxData==0 ); |
} |
@@ -2049,7 +2136,7 @@ static void Cleanup(Vdbe *p){ |
int i; |
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 ); |
if( p->aMem ){ |
- for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); |
+ for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); |
} |
#endif |
@@ -2073,13 +2160,9 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ |
sqlite3DbFree(db, p->aColName); |
n = nResColumn*COLNAME_N; |
p->nResColumn = (u16)nResColumn; |
- p->aColName = pColName = (Mem*)sqlite3DbMallocZero(db, sizeof(Mem)*n ); |
+ p->aColName = pColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); |
if( p->aColName==0 ) return; |
- while( n-- > 0 ){ |
- pColName->flags = MEM_Null; |
- pColName->db = p->db; |
- pColName++; |
- } |
+ initMemArray(p->aColName, n, p->db, MEM_Null); |
} |
/* |
@@ -2105,7 +2188,7 @@ int sqlite3VdbeSetColName( |
assert( var<COLNAME_N ); |
if( p->db->mallocFailed ){ |
assert( !zName || xDel!=SQLITE_DYNAMIC ); |
- return SQLITE_NOMEM; |
+ return SQLITE_NOMEM_BKPT; |
} |
assert( p->aColName!=0 ); |
pColName = &(p->aColName[idx+var*p->nResColumn]); |
@@ -2122,7 +2205,9 @@ int sqlite3VdbeSetColName( |
*/ |
static int vdbeCommit(sqlite3 *db, Vdbe *p){ |
int i; |
- int nTrans = 0; /* Number of databases with an active write-transaction */ |
+ int nTrans = 0; /* Number of databases with an active write-transaction |
+ ** that are candidates for a two-phase commit using a |
+ ** master-journal */ |
int rc = SQLITE_OK; |
int needXcommit = 0; |
@@ -2150,10 +2235,28 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ |
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ |
Btree *pBt = db->aDb[i].pBt; |
if( sqlite3BtreeIsInTrans(pBt) ){ |
+ /* Whether or not a database might need a master journal depends upon |
+ ** its journal mode (among other things). This matrix determines which |
+ ** journal modes use a master journal and which do not */ |
+ static const u8 aMJNeeded[] = { |
+ /* DELETE */ 1, |
+ /* PERSIST */ 1, |
+ /* OFF */ 0, |
+ /* TRUNCATE */ 1, |
+ /* MEMORY */ 0, |
+ /* WAL */ 0 |
+ }; |
+ Pager *pPager; /* Pager associated with pBt */ |
needXcommit = 1; |
- if( i!=1 ) nTrans++; |
sqlite3BtreeEnter(pBt); |
- rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt)); |
+ pPager = sqlite3BtreePager(pBt); |
+ if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF |
+ && aMJNeeded[sqlite3PagerGetJournalMode(pPager)] |
+ ){ |
+ assert( i!=1 ); |
+ nTrans++; |
+ } |
+ rc = sqlite3PagerExclusiveLock(pPager); |
sqlite3BtreeLeave(pBt); |
} |
} |
@@ -2211,7 +2314,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ |
#ifndef SQLITE_OMIT_DISKIO |
else{ |
sqlite3_vfs *pVfs = db->pVfs; |
- int needSync = 0; |
char *zMaster = 0; /* File-name for the master journal */ |
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); |
sqlite3_file *pMaster = 0; |
@@ -2223,7 +2325,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ |
/* Select a master journal file name */ |
nMainFile = sqlite3Strlen30(zMainFile); |
zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile); |
- if( zMaster==0 ) return SQLITE_NOMEM; |
+ if( zMaster==0 ) return SQLITE_NOMEM_BKPT; |
do { |
u32 iRandom; |
if( retryCount ){ |
@@ -2271,9 +2373,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ |
continue; /* Ignore TEMP and :memory: databases */ |
} |
assert( zFile[0]!=0 ); |
- if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){ |
- needSync = 1; |
- } |
rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset); |
offset += sqlite3Strlen30(zFile)+1; |
if( rc!=SQLITE_OK ){ |
@@ -2288,8 +2387,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ |
/* Sync the master journal file. If the IOCAP_SEQUENTIAL device |
** flag is set this is not required. |
*/ |
- if( needSync |
- && 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL) |
+ if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL) |
&& SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL)) |
){ |
sqlite3OsCloseFree(pMaster); |
@@ -2325,7 +2423,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ |
** doing this the directory is synced again before any individual |
** transaction files are deleted. |
*/ |
- rc = sqlite3OsDelete(pVfs, zMaster, needSync); |
+ rc = sqlite3OsDelete(pVfs, zMaster, 1); |
sqlite3DbFree(db, zMaster); |
zMaster = 0; |
if( rc ){ |
@@ -2399,60 +2497,59 @@ static void checkActiveVdbeCnt(sqlite3 *db){ |
** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. |
** Otherwise SQLITE_OK. |
*/ |
-int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ |
+static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){ |
sqlite3 *const db = p->db; |
int rc = SQLITE_OK; |
+ int i; |
+ const int iSavepoint = p->iStatement-1; |
- /* If p->iStatement is greater than zero, then this Vdbe opened a |
- ** statement transaction that should be closed here. The only exception |
- ** is that an IO error may have occurred, causing an emergency rollback. |
- ** In this case (db->nStatement==0), and there is nothing to do. |
- */ |
- if( db->nStatement && p->iStatement ){ |
- int i; |
- const int iSavepoint = p->iStatement-1; |
- |
- assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE); |
- assert( db->nStatement>0 ); |
- assert( p->iStatement==(db->nStatement+db->nSavepoint) ); |
- |
- for(i=0; i<db->nDb; i++){ |
- int rc2 = SQLITE_OK; |
- Btree *pBt = db->aDb[i].pBt; |
- if( pBt ){ |
- if( eOp==SAVEPOINT_ROLLBACK ){ |
- rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint); |
- } |
- if( rc2==SQLITE_OK ){ |
- rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint); |
- } |
- if( rc==SQLITE_OK ){ |
- rc = rc2; |
- } |
- } |
- } |
- db->nStatement--; |
- p->iStatement = 0; |
+ assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE); |
+ assert( db->nStatement>0 ); |
+ assert( p->iStatement==(db->nStatement+db->nSavepoint) ); |
- if( rc==SQLITE_OK ){ |
+ for(i=0; i<db->nDb; i++){ |
+ int rc2 = SQLITE_OK; |
+ Btree *pBt = db->aDb[i].pBt; |
+ if( pBt ){ |
if( eOp==SAVEPOINT_ROLLBACK ){ |
- rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); |
+ rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint); |
+ } |
+ if( rc2==SQLITE_OK ){ |
+ rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint); |
} |
if( rc==SQLITE_OK ){ |
- rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); |
+ rc = rc2; |
} |
} |
+ } |
+ db->nStatement--; |
+ p->iStatement = 0; |
- /* If the statement transaction is being rolled back, also restore the |
- ** database handles deferred constraint counter to the value it had when |
- ** the statement transaction was opened. */ |
+ if( rc==SQLITE_OK ){ |
if( eOp==SAVEPOINT_ROLLBACK ){ |
- db->nDeferredCons = p->nStmtDefCons; |
- db->nDeferredImmCons = p->nStmtDefImmCons; |
+ rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); |
} |
+ if( rc==SQLITE_OK ){ |
+ rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); |
+ } |
+ } |
+ |
+ /* If the statement transaction is being rolled back, also restore the |
+ ** database handles deferred constraint counter to the value it had when |
+ ** the statement transaction was opened. */ |
+ if( eOp==SAVEPOINT_ROLLBACK ){ |
+ db->nDeferredCons = p->nStmtDefCons; |
+ db->nDeferredImmCons = p->nStmtDefImmCons; |
} |
return rc; |
} |
+int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ |
+ if( p->db->nStatement && p->iStatement ){ |
+ return vdbeCloseStatement(p, eOp); |
+ } |
+ return SQLITE_OK; |
+} |
+ |
/* |
** This function is called when a transaction opened by the database |
@@ -2512,10 +2609,9 @@ int sqlite3VdbeHalt(Vdbe *p){ |
** one, or the complete transaction if there is no statement transaction. |
*/ |
- if( p->db->mallocFailed ){ |
- p->rc = SQLITE_NOMEM; |
+ if( db->mallocFailed ){ |
+ p->rc = SQLITE_NOMEM_BKPT; |
} |
- if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag); |
closeAllCursors(p); |
if( p->magic!=VDBE_MAGIC_RUN ){ |
return SQLITE_OK; |
@@ -2673,8 +2769,8 @@ int sqlite3VdbeHalt(Vdbe *p){ |
} |
p->magic = VDBE_MAGIC_HALT; |
checkActiveVdbeCnt(db); |
- if( p->db->mallocFailed ){ |
- p->rc = SQLITE_NOMEM; |
+ if( db->mallocFailed ){ |
+ p->rc = SQLITE_NOMEM_BKPT; |
} |
/* If the auto-commit flag is set to true, then any locks that were held |
@@ -2710,12 +2806,12 @@ int sqlite3VdbeTransferError(Vdbe *p){ |
sqlite3 *db = p->db; |
int rc = p->rc; |
if( p->zErrMsg ){ |
- u8 mallocFailed = db->mallocFailed; |
+ db->bBenignMalloc++; |
sqlite3BeginBenignMalloc(); |
if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db); |
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); |
sqlite3EndBenignMalloc(); |
- db->mallocFailed = mallocFailed; |
+ db->bBenignMalloc--; |
db->errCode = rc; |
}else{ |
sqlite3Error(db, rc); |
@@ -2827,7 +2923,7 @@ int sqlite3VdbeReset(Vdbe *p){ |
} |
#endif |
p->iCurrentTime = 0; |
- p->magic = VDBE_MAGIC_INIT; |
+ p->magic = VDBE_MAGIC_RESET; |
return p->rc & db->errMask; |
} |
@@ -2861,8 +2957,7 @@ int sqlite3VdbeFinalize(Vdbe *p){ |
** * the corresponding bit in argument mask is clear (where the first |
** function parameter corresponds to bit 0 etc.). |
*/ |
-void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ |
- AuxData **pp = &pVdbe->pAuxData; |
+void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){ |
while( *pp ){ |
AuxData *pAux = *pp; |
if( (iOp<0) |
@@ -2873,7 +2968,7 @@ void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ |
pAux->xDelete(pAux->pAux); |
} |
*pp = pAux->pNext; |
- sqlite3DbFree(pVdbe->db, pAux); |
+ sqlite3DbFree(db, pAux); |
}else{ |
pp= &pAux->pNext; |
} |
@@ -2890,25 +2985,29 @@ void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ |
*/ |
void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ |
SubProgram *pSub, *pNext; |
- int i; |
assert( p->db==0 || p->db==db ); |
- releaseMemArray(p->aVar, p->nVar); |
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); |
for(pSub=p->pProgram; pSub; pSub=pNext){ |
pNext = pSub->pNext; |
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); |
sqlite3DbFree(db, pSub); |
} |
- for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); |
+ if( p->magic!=VDBE_MAGIC_INIT ){ |
+ releaseMemArray(p->aVar, p->nVar); |
+ sqlite3DbFree(db, p->pVList); |
+ sqlite3DbFree(db, p->pFree); |
+ } |
vdbeFreeOpArray(db, p->aOp, p->nOp); |
sqlite3DbFree(db, p->aColName); |
sqlite3DbFree(db, p->zSql); |
- sqlite3DbFree(db, p->pFree); |
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS |
- for(i=0; i<p->nScan; i++){ |
- sqlite3DbFree(db, p->aScan[i].zName); |
+ { |
+ int i; |
+ for(i=0; i<p->nScan; i++){ |
+ sqlite3DbFree(db, p->aScan[i].zName); |
+ } |
+ sqlite3DbFree(db, p->aScan); |
} |
- sqlite3DbFree(db, p->aScan); |
#endif |
} |
@@ -3003,9 +3102,16 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){ |
** If the cursor is already pointing to the correct row and that row has |
** not been deleted out from under the cursor, then this routine is a no-op. |
*/ |
-int sqlite3VdbeCursorMoveto(VdbeCursor *p){ |
+int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ |
+ VdbeCursor *p = *pp; |
if( p->eCurType==CURTYPE_BTREE ){ |
if( p->deferredMoveto ){ |
+ int iMap; |
+ if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){ |
+ *pp = p->pAltCursor; |
+ *piCol = iMap - 1; |
+ return SQLITE_OK; |
+ } |
return handleDeferredMoveto(p); |
} |
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ |
@@ -3402,30 +3508,13 @@ u32 sqlite3VdbeSerialGet( |
** If an OOM error occurs, NULL is returned. |
*/ |
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( |
- KeyInfo *pKeyInfo, /* Description of the record */ |
- char *pSpace, /* Unaligned space available */ |
- int szSpace, /* Size of pSpace[] in bytes */ |
- char **ppFree /* OUT: Caller should free this pointer */ |
+ KeyInfo *pKeyInfo /* Description of the record */ |
){ |
UnpackedRecord *p; /* Unpacked record to return */ |
- int nOff; /* Increment pSpace by nOff to align it */ |
int nByte; /* Number of bytes required for *p */ |
- |
- /* We want to shift the pointer pSpace up such that it is 8-byte aligned. |
- ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift |
- ** it by. If pSpace is already 8-byte aligned, nOff should be zero. |
- */ |
- nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7; |
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1); |
- if( nByte>szSpace+nOff ){ |
- p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); |
- *ppFree = (char *)p; |
- if( !p ) return 0; |
- }else{ |
- p = (UnpackedRecord*)&pSpace[nOff]; |
- *ppFree = 0; |
- } |
- |
+ p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); |
+ if( !p ) return 0; |
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; |
assert( pKeyInfo->aSortOrder!=0 ); |
p->pKeyInfo = pKeyInfo; |
@@ -3464,6 +3553,7 @@ void sqlite3VdbeRecordUnpack( |
pMem->db = pKeyInfo->db; |
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */ |
pMem->szMalloc = 0; |
+ pMem->z = 0; |
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); |
pMem++; |
if( (++u)>=p->nField ) break; |
@@ -3644,22 +3734,56 @@ static int vdbeCompareMemString( |
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); |
n2 = v2==0 ? 0 : c2.n; |
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); |
+ if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT; |
sqlite3VdbeMemRelease(&c1); |
sqlite3VdbeMemRelease(&c2); |
- if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM; |
return rc; |
} |
} |
/* |
+** The input pBlob is guaranteed to be a Blob that is not marked |
+** with MEM_Zero. Return true if it could be a zero-blob. |
+*/ |
+static int isAllZero(const char *z, int n){ |
+ int i; |
+ for(i=0; i<n; i++){ |
+ if( z[i] ) return 0; |
+ } |
+ return 1; |
+} |
+ |
+/* |
** Compare two blobs. Return negative, zero, or positive if the first |
** is less than, equal to, or greater than the second, respectively. |
** If one blob is a prefix of the other, then the shorter is the lessor. |
*/ |
static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ |
- int c = memcmp(pB1->z, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n); |
+ int c; |
+ int n1 = pB1->n; |
+ int n2 = pB2->n; |
+ |
+ /* It is possible to have a Blob value that has some non-zero content |
+ ** followed by zero content. But that only comes up for Blobs formed |
+ ** by the OP_MakeRecord opcode, and such Blobs never get passed into |
+ ** sqlite3MemCompare(). */ |
+ assert( (pB1->flags & MEM_Zero)==0 || n1==0 ); |
+ assert( (pB2->flags & MEM_Zero)==0 || n2==0 ); |
+ |
+ if( (pB1->flags|pB2->flags) & MEM_Zero ){ |
+ if( pB1->flags & pB2->flags & MEM_Zero ){ |
+ return pB1->u.nZero - pB2->u.nZero; |
+ }else if( pB1->flags & MEM_Zero ){ |
+ if( !isAllZero(pB2->z, pB2->n) ) return -1; |
+ return pB1->u.nZero - n2; |
+ }else{ |
+ if( !isAllZero(pB1->z, pB1->n) ) return +1; |
+ return n1 - pB2->u.nZero; |
+ } |
+ } |
+ c = memcmp(pB1->z, pB2->z, n1>n2 ? n2 : n1); |
if( c ) return c; |
- return pB1->n - pB2->n; |
+ return n1 - n2; |
} |
/* |
@@ -3965,6 +4089,7 @@ int sqlite3VdbeRecordCompareWithSkip( |
/* RHS is a blob */ |
else if( pRhs->flags & MEM_Blob ){ |
+ assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 ); |
getVarint32(&aKey1[idx1], serial_type); |
testcase( serial_type==12 ); |
if( serial_type<12 || (serial_type & 0x01) ){ |
@@ -3976,6 +4101,12 @@ int sqlite3VdbeRecordCompareWithSkip( |
if( (d1+nStr) > (unsigned)nKey1 ){ |
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; |
return 0; /* Corruption */ |
+ }else if( pRhs->flags & MEM_Zero ){ |
+ if( !isAllZero((const char*)&aKey1[d1],nStr) ){ |
+ rc = 1; |
+ }else{ |
+ rc = nStr - pRhs->u.nZero; |
+ } |
}else{ |
int nCmp = MIN(nStr, pRhs->n); |
rc = memcmp(&aKey1[d1], pRhs->z, nCmp); |
@@ -4046,7 +4177,7 @@ static int vdbeRecordCompareInt( |
int res; |
u32 y; |
u64 x; |
- i64 v = pPKey2->aMem[0].u.i; |
+ i64 v; |
i64 lhs; |
vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); |
@@ -4105,6 +4236,7 @@ static int vdbeRecordCompareInt( |
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); |
} |
+ v = pPKey2->aMem[0].u.i; |
if( v>lhs ){ |
res = pPKey2->r1; |
}else if( v<lhs ){ |
@@ -4251,13 +4383,12 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ |
** this code can safely assume that nCellKey is 32-bits |
*/ |
assert( sqlite3BtreeCursorIsValid(pCur) ); |
- VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); |
- assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ |
+ nCellKey = sqlite3BtreePayloadSize(pCur); |
assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); |
/* Read in the complete content of the index entry */ |
sqlite3VdbeMemInit(&m, db, 0); |
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); |
+ rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); |
if( rc ){ |
return rc; |
} |
@@ -4329,8 +4460,7 @@ int sqlite3VdbeIdxKeyCompare( |
assert( pC->eCurType==CURTYPE_BTREE ); |
pCur = pC->uc.pCursor; |
assert( sqlite3BtreeCursorIsValid(pCur) ); |
- VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); |
- assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ |
+ nCellKey = sqlite3BtreePayloadSize(pCur); |
/* nCellKey will always be between 0 and 0xffffffff because of the way |
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ |
if( nCellKey<=0 || nCellKey>0x7fffffff ){ |
@@ -4338,7 +4468,7 @@ int sqlite3VdbeIdxKeyCompare( |
return SQLITE_CORRUPT_BKPT; |
} |
sqlite3VdbeMemInit(&m, db, 0); |
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); |
+ rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); |
if( rc ){ |
return rc; |
} |
@@ -4434,10 +4564,101 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ |
** in memory obtained from sqlite3DbMalloc). |
*/ |
void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){ |
- sqlite3 *db = p->db; |
- sqlite3DbFree(db, p->zErrMsg); |
- p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); |
- sqlite3_free(pVtab->zErrMsg); |
- pVtab->zErrMsg = 0; |
+ if( pVtab->zErrMsg ){ |
+ sqlite3 *db = p->db; |
+ sqlite3DbFree(db, p->zErrMsg); |
+ p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); |
+ sqlite3_free(pVtab->zErrMsg); |
+ pVtab->zErrMsg = 0; |
+ } |
} |
#endif /* SQLITE_OMIT_VIRTUALTABLE */ |
+ |
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK |
+ |
+/* |
+** If the second argument is not NULL, release any allocations associated |
+** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord |
+** structure itself, using sqlite3DbFree(). |
+** |
+** This function is used to free UnpackedRecord structures allocated by |
+** the vdbeUnpackRecord() function found in vdbeapi.c. |
+*/ |
+static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){ |
+ if( p ){ |
+ int i; |
+ for(i=0; i<nField; i++){ |
+ Mem *pMem = &p->aMem[i]; |
+ if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem); |
+ } |
+ sqlite3DbFree(db, p); |
+ } |
+} |
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ |
+ |
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK |
+/* |
+** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call, |
+** then cursor passed as the second argument should point to the row about |
+** to be update or deleted. If the application calls sqlite3_preupdate_old(), |
+** the required value will be read from the row the cursor points to. |
+*/ |
+void sqlite3VdbePreUpdateHook( |
+ Vdbe *v, /* Vdbe pre-update hook is invoked by */ |
+ VdbeCursor *pCsr, /* Cursor to grab old.* values from */ |
+ int op, /* SQLITE_INSERT, UPDATE or DELETE */ |
+ const char *zDb, /* Database name */ |
+ Table *pTab, /* Modified table */ |
+ i64 iKey1, /* Initial key value */ |
+ int iReg /* Register for new.* record */ |
+){ |
+ sqlite3 *db = v->db; |
+ i64 iKey2; |
+ PreUpdate preupdate; |
+ const char *zTbl = pTab->zName; |
+ static const u8 fakeSortOrder = 0; |
+ |
+ assert( db->pPreUpdate==0 ); |
+ memset(&preupdate, 0, sizeof(PreUpdate)); |
+ if( HasRowid(pTab)==0 ){ |
+ iKey1 = iKey2 = 0; |
+ preupdate.pPk = sqlite3PrimaryKeyIndex(pTab); |
+ }else{ |
+ if( op==SQLITE_UPDATE ){ |
+ iKey2 = v->aMem[iReg].u.i; |
+ }else{ |
+ iKey2 = iKey1; |
+ } |
+ } |
+ |
+ assert( pCsr->nField==pTab->nCol |
+ || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) |
+ ); |
+ |
+ preupdate.v = v; |
+ preupdate.pCsr = pCsr; |
+ preupdate.op = op; |
+ preupdate.iNewReg = iReg; |
+ preupdate.keyinfo.db = db; |
+ preupdate.keyinfo.enc = ENC(db); |
+ preupdate.keyinfo.nField = pTab->nCol; |
+ preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder; |
+ preupdate.iKey1 = iKey1; |
+ preupdate.iKey2 = iKey2; |
+ preupdate.pTab = pTab; |
+ |
+ db->pPreUpdate = &preupdate; |
+ db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); |
+ db->pPreUpdate = 0; |
+ sqlite3DbFree(db, preupdate.aRecord); |
+ vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pUnpacked); |
+ vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pNewUnpacked); |
+ if( preupdate.aNew ){ |
+ int i; |
+ for(i=0; i<pCsr->nField; i++){ |
+ sqlite3VdbeMemRelease(&preupdate.aNew[i]); |
+ } |
+ sqlite3DbFree(db, preupdate.aNew); |
+ } |
+} |
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ |