| 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 c169b3727261eed76267837fa533e748f82df178..4d4bb224f93d8ce16b7b653344164df9a026f624 100644
|
| --- a/third_party/sqlite/src/src/vdbeaux.c
|
| +++ b/third_party/sqlite/src/src/vdbeaux.c
|
| @@ -13,8 +13,6 @@
|
| ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior
|
| ** to version 2.8.7, all this code was combined into the vdbe.c source file.
|
| ** But that file was getting too big so this subroutines were split out.
|
| -**
|
| -** $Id: vdbeaux.c,v 1.480 2009/08/08 18:01:08 drh Exp $
|
| */
|
| #include "sqliteInt.h"
|
| #include "vdbeInt.h"
|
| @@ -53,13 +51,14 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
|
| ** Remember the SQL string for a prepared statement.
|
| */
|
| void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
| + assert( isPrepareV2==1 || isPrepareV2==0 );
|
| if( p==0 ) return;
|
| #ifdef SQLITE_OMIT_TRACE
|
| if( !isPrepareV2 ) return;
|
| #endif
|
| assert( p->zSql==0 );
|
| p->zSql = sqlite3DbStrNDup(p->db, z, n);
|
| - p->isPrepareV2 = isPrepareV2 ? 1 : 0;
|
| + p->isPrepareV2 = (u8)isPrepareV2;
|
| }
|
|
|
| /*
|
| @@ -67,7 +66,7 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
| */
|
| const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
| Vdbe *p = (Vdbe *)pStmt;
|
| - return (p->isPrepareV2 ? p->zSql : 0);
|
| + return (p && p->isPrepareV2) ? p->zSql : 0;
|
| }
|
|
|
| /*
|
| @@ -158,6 +157,12 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
| pOp->p4.p = 0;
|
| pOp->p4type = P4_NOTUSED;
|
| p->expired = 0;
|
| + if( op==OP_ParseSchema ){
|
| + /* Any program that uses the OP_ParseSchema opcode needs to lock
|
| + ** all btrees. */
|
| + int j;
|
| + for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
|
| + }
|
| #ifdef SQLITE_DEBUG
|
| pOp->zComment = 0;
|
| if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
|
| @@ -197,6 +202,22 @@ int sqlite3VdbeAddOp4(
|
| }
|
|
|
| /*
|
| +** Add an opcode that includes the p4 value as an integer.
|
| +*/
|
| +int sqlite3VdbeAddOp4Int(
|
| + Vdbe *p, /* Add the opcode to this VM */
|
| + int op, /* The new opcode */
|
| + int p1, /* The P1 operand */
|
| + int p2, /* The P2 operand */
|
| + int p3, /* The P3 operand */
|
| + 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);
|
| + return addr;
|
| +}
|
| +
|
| +/*
|
| ** Create a new symbolic label for an instruction that has yet to be
|
| ** coded. The symbolic label is really just a negative number. The
|
| ** label can be used as the P2 value of an operation. Later, when
|
| @@ -240,7 +261,14 @@ void sqlite3VdbeResolveLabel(Vdbe *p, int x){
|
| }
|
| }
|
|
|
| -#ifdef SQLITE_DEBUG
|
| +/*
|
| +** Mark the VDBE as one that can only be run one time.
|
| +*/
|
| +void sqlite3VdbeRunOnlyOnce(Vdbe *p){
|
| + p->runOnlyOnce = 1;
|
| +}
|
| +
|
| +#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
|
|
|
| /*
|
| ** The following type and function are used to iterate through all opcodes
|
| @@ -312,7 +340,7 @@ static Op *opIterNext(VdbeOpIter *p){
|
|
|
| /*
|
| ** Check if the program stored in the VM associated with pParse may
|
| -** throw an ABORT exception (causing the statement, but not transaction
|
| +** throw an ABORT exception (causing the statement, but not entire transaction
|
| ** to be rolled back). This condition is true if the main program or any
|
| ** sub-programs contains any of the following:
|
| **
|
| @@ -321,6 +349,7 @@ static Op *opIterNext(VdbeOpIter *p){
|
| ** * OP_Destroy
|
| ** * OP_VUpdate
|
| ** * OP_VRename
|
| +** * OP_FkCounter with P2==0 (immediate foreign key constraint)
|
| **
|
| ** Then check that the value of Parse.mayAbort is true if an
|
| ** ABORT may be thrown, or false otherwise. Return true if it does
|
| @@ -339,6 +368,9 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
| while( (pOp = opIterNext(&sIter))!=0 ){
|
| int opcode = pOp->opcode;
|
| if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| + || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
|
| +#endif
|
| || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
|
| && (pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
|
| ){
|
| @@ -355,7 +387,7 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
| ** from failing. */
|
| return ( v->db->mallocFailed || hasAbort==mayAbort );
|
| }
|
| -#endif
|
| +#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
|
|
|
| /*
|
| ** Loop through the program looking for P2 values that are negative
|
| @@ -367,6 +399,8 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
| ** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
|
| ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by
|
| ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
|
| +**
|
| +** The Op.opflags field is set on all opcodes.
|
| */
|
| static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
| int i;
|
| @@ -377,15 +411,14 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
| for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
|
| u8 opcode = pOp->opcode;
|
|
|
| + pOp->opflags = sqlite3OpcodeProperty[opcode];
|
| if( opcode==OP_Function || opcode==OP_AggStep ){
|
| if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
|
| + }else if( (opcode==OP_Transaction && pOp->p2!=0) || opcode==OP_Vacuum ){
|
| + p->readOnly = 0;
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| }else if( opcode==OP_VUpdate ){
|
| if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
|
| -#endif
|
| - }else if( opcode==OP_Transaction && pOp->p2!=0 ){
|
| - p->readOnly = 0;
|
| -#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| }else if( opcode==OP_VFilter ){
|
| int n;
|
| assert( p->nOp - i >= 3 );
|
| @@ -395,7 +428,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
| #endif
|
| }
|
|
|
| - if( sqlite3VdbeOpcodeHasProperty(opcode, OPFLG_JUMP) && pOp->p2<0 ){
|
| + if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
|
| assert( -1-pOp->p2<p->nLabel );
|
| pOp->p2 = aLabel[-1-pOp->p2];
|
| }
|
| @@ -430,7 +463,7 @@ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
|
| assert( aOp && !p->db->mallocFailed );
|
|
|
| /* Check that sqlite3VdbeUsesBtree() was not called on this VM */
|
| - assert( p->aMutex.nMutex==0 );
|
| + assert( p->btreeMask==0 );
|
|
|
| resolveP2Values(p, pnMaxArg);
|
| *pnOp = p->nOp;
|
| @@ -457,7 +490,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
| VdbeOp *pOut = &p->aOp[i+addr];
|
| pOut->opcode = pIn->opcode;
|
| pOut->p1 = pIn->p1;
|
| - if( p2<0 && sqlite3VdbeOpcodeHasProperty(pOut->opcode, OPFLG_JUMP) ){
|
| + if( p2<0 && (sqlite3OpcodeProperty[pOut->opcode] & OPFLG_JUMP)!=0 ){
|
| pOut->p2 = addr + ADDR(p2);
|
| }else{
|
| pOut->p2 = p2;
|
| @@ -532,6 +565,7 @@ void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
|
| ** the address of the next instruction to be coded.
|
| */
|
| void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
| + assert( addr>=0 );
|
| sqlite3VdbeChangeP2(p, addr, p->nOp);
|
| }
|
|
|
| @@ -546,15 +580,17 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
|
| }
|
| }
|
|
|
| +static void vdbeFreeOpArray(sqlite3 *, Op *, int);
|
| +
|
| /*
|
| ** Delete a P4 value if necessary.
|
| */
|
| static void freeP4(sqlite3 *db, int p4type, void *p4){
|
| if( p4 ){
|
| + assert( db );
|
| switch( p4type ){
|
| case P4_REAL:
|
| case P4_INT64:
|
| - case P4_MPRINTF:
|
| case P4_DYNAMIC:
|
| case P4_KEYINFO:
|
| case P4_INTARRAY:
|
| @@ -562,10 +598,14 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
| sqlite3DbFree(db, p4);
|
| break;
|
| }
|
| + case P4_MPRINTF: {
|
| + if( db->pnBytesFreed==0 ) sqlite3_free(p4);
|
| + break;
|
| + }
|
| case P4_VDBEFUNC: {
|
| VdbeFunc *pVdbeFunc = (VdbeFunc *)p4;
|
| freeEphemeralFunction(db, pVdbeFunc->pFunc);
|
| - sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
| + if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
| sqlite3DbFree(db, pVdbeFunc);
|
| break;
|
| }
|
| @@ -574,15 +614,17 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
| break;
|
| }
|
| case P4_MEM: {
|
| - sqlite3ValueFree((sqlite3_value*)p4);
|
| + if( db->pnBytesFreed==0 ){
|
| + sqlite3ValueFree((sqlite3_value*)p4);
|
| + }else{
|
| + Mem *p = (Mem*)p4;
|
| + sqlite3DbFree(db, p->zMalloc);
|
| + sqlite3DbFree(db, p);
|
| + }
|
| break;
|
| }
|
| case P4_VTAB : {
|
| - sqlite3VtabUnlock((VTable *)p4);
|
| - break;
|
| - }
|
| - case P4_SUBPROGRAM : {
|
| - sqlite3VdbeProgramDelete(db, (SubProgram *)p4, 1);
|
| + if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
|
| break;
|
| }
|
| }
|
| @@ -608,35 +650,15 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
|
| }
|
|
|
| /*
|
| -** Decrement the ref-count on the SubProgram structure passed as the
|
| -** second argument. If the ref-count reaches zero, free the structure.
|
| -**
|
| -** The array of VDBE opcodes stored as SubProgram.aOp is freed if
|
| -** either the ref-count reaches zero or parameter freeop is non-zero.
|
| -**
|
| -** Since the array of opcodes pointed to by SubProgram.aOp may directly
|
| -** or indirectly contain a reference to the SubProgram structure itself.
|
| -** By passing a non-zero freeop parameter, the caller may ensure that all
|
| -** SubProgram structures and their aOp arrays are freed, even when there
|
| -** are such circular references.
|
| +** Link the SubProgram object passed as the second argument into the linked
|
| +** list at Vdbe.pSubProgram. This list is used to delete all sub-program
|
| +** objects when the VM is no longer required.
|
| */
|
| -void sqlite3VdbeProgramDelete(sqlite3 *db, SubProgram *p, int freeop){
|
| - if( p ){
|
| - assert( p->nRef>0 );
|
| - if( freeop || p->nRef==1 ){
|
| - Op *aOp = p->aOp;
|
| - p->aOp = 0;
|
| - vdbeFreeOpArray(db, aOp, p->nOp);
|
| - p->nOp = 0;
|
| - }
|
| - p->nRef--;
|
| - if( p->nRef==0 ){
|
| - sqlite3DbFree(db, p);
|
| - }
|
| - }
|
| +void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
|
| + p->pNext = pVdbe->pProgram;
|
| + pVdbe->pProgram = p;
|
| }
|
|
|
| -
|
| /*
|
| ** Change N opcodes starting at addr to No-ops.
|
| */
|
| @@ -712,11 +734,11 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
|
|
| nField = ((KeyInfo*)zP4)->nField;
|
| nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
|
| - pKeyInfo = sqlite3Malloc( nByte );
|
| + pKeyInfo = sqlite3DbMallocRaw(0, nByte);
|
| pOp->p4.pKeyInfo = pKeyInfo;
|
| if( pKeyInfo ){
|
| u8 *aSortOrder;
|
| - memcpy(pKeyInfo, zP4, nByte);
|
| + memcpy((char*)pKeyInfo, zP4, nByte - nField);
|
| aSortOrder = pKeyInfo->aSortOrder;
|
| if( aSortOrder ){
|
| pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
|
| @@ -787,9 +809,12 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
| **
|
| ** If a memory allocation error has occurred prior to the calling of this
|
| ** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
|
| -** is readable and writable, but it has no effect. The return of a dummy
|
| -** opcode allows the call to continue functioning after a OOM fault without
|
| -** having to check to see if the return from this routine is a valid pointer.
|
| +** is readable but not writable, though it is cast to a writable value.
|
| +** The return of a dummy opcode allows the call to continue functioning
|
| +** after a OOM fault without having to check to see if the return from
|
| +** this routine is a valid pointer. But because the dummy.opcode is 0,
|
| +** dummy will never be written to. This is verified by code inspection and
|
| +** by running with Valgrind.
|
| **
|
| ** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called
|
| ** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE,
|
| @@ -800,17 +825,19 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
| ** check the value of p->nOp-1 before continuing.
|
| */
|
| VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
| - static VdbeOp dummy;
|
| + /* C89 specifies that the constant "dummy" will be initialized to all
|
| + ** zeros, which is correct. MSVC generates a warning, nevertheless. */
|
| + static const VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
|
| assert( p->magic==VDBE_MAGIC_INIT );
|
| if( addr<0 ){
|
| #ifdef SQLITE_OMIT_TRACE
|
| - if( p->nOp==0 ) return &dummy;
|
| + if( p->nOp==0 ) return (VdbeOp*)&dummy;
|
| #endif
|
| addr = p->nOp - 1;
|
| }
|
| assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
|
| if( p->db->mallocFailed ){
|
| - return &dummy;
|
| + return (VdbeOp*)&dummy;
|
| }else{
|
| return &p->aOp[addr];
|
| }
|
| @@ -923,18 +950,81 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
|
|
| /*
|
| ** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
|
| +**
|
| +** The prepared statements need to know in advance the complete set of
|
| +** attached databases that they will be using. A mask of these databases
|
| +** is maintained in p->btreeMask and is used for locking and other purposes.
|
| */
|
| void sqlite3VdbeUsesBtree(Vdbe *p, int i){
|
| - int mask;
|
| - assert( i>=0 && i<p->db->nDb && i<sizeof(u32)*8 );
|
| + assert( i>=0 && i<p->db->nDb && i<(int)sizeof(yDbMask)*8 );
|
| assert( i<(int)sizeof(p->btreeMask)*8 );
|
| - mask = ((u32)1)<<i;
|
| - if( (p->btreeMask & mask)==0 ){
|
| - p->btreeMask |= mask;
|
| - sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
|
| + p->btreeMask |= ((yDbMask)1)<<i;
|
| + if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
|
| + p->lockMask |= ((yDbMask)1)<<i;
|
| }
|
| }
|
|
|
| +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
|
| +/*
|
| +** If SQLite is compiled to support shared-cache mode and to be threadsafe,
|
| +** this routine obtains the mutex associated with each BtShared structure
|
| +** that may be accessed by the VM passed as an argument. In doing so it also
|
| +** sets the BtShared.db member of each of the BtShared structures, ensuring
|
| +** that the correct busy-handler callback is invoked if required.
|
| +**
|
| +** If SQLite is not threadsafe but does support shared-cache mode, then
|
| +** sqlite3BtreeEnter() is invoked to set the BtShared.db variables
|
| +** of all of BtShared structures accessible via the database handle
|
| +** associated with the VM.
|
| +**
|
| +** If SQLite is not threadsafe and does not support shared-cache mode, this
|
| +** function is a no-op.
|
| +**
|
| +** The p->btreeMask field is a bitmask of all btrees that the prepared
|
| +** statement p will ever use. Let N be the number of bits in p->btreeMask
|
| +** corresponding to btrees that use shared cache. Then the runtime of
|
| +** this routine is N*N. But as N is rarely more than 1, this should not
|
| +** be a problem.
|
| +*/
|
| +void sqlite3VdbeEnter(Vdbe *p){
|
| + int i;
|
| + yDbMask mask;
|
| + sqlite3 *db;
|
| + Db *aDb;
|
| + int nDb;
|
| + if( p->lockMask==0 ) return; /* The common case */
|
| + db = p->db;
|
| + aDb = db->aDb;
|
| + nDb = db->nDb;
|
| + for(i=0, mask=1; i<nDb; i++, mask += mask){
|
| + if( i!=1 && (mask & p->lockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
|
| + sqlite3BtreeEnter(aDb[i].pBt);
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
|
| +/*
|
| +** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
|
| +*/
|
| +void sqlite3VdbeLeave(Vdbe *p){
|
| + int i;
|
| + yDbMask mask;
|
| + sqlite3 *db;
|
| + Db *aDb;
|
| + int nDb;
|
| + if( p->lockMask==0 ) return; /* The common case */
|
| + db = p->db;
|
| + aDb = db->aDb;
|
| + nDb = db->nDb;
|
| + for(i=0, mask=1; i<nDb; i++, mask += mask){
|
| + if( i!=1 && (mask & p->lockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
|
| + sqlite3BtreeLeave(aDb[i].pBt);
|
| + }
|
| + }
|
| +}
|
| +#endif
|
|
|
| #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
| /*
|
| @@ -966,6 +1056,12 @@ static void releaseMemArray(Mem *p, int N){
|
| Mem *pEnd;
|
| sqlite3 *db = p->db;
|
| u8 malloc_failed = db->mallocFailed;
|
| + if( db->pnBytesFreed ){
|
| + for(pEnd=&p[N]; p<pEnd; p++){
|
| + sqlite3DbFree(db, p->zMalloc);
|
| + }
|
| + return;
|
| + }
|
| for(pEnd=&p[N]; p<pEnd; p++){
|
| assert( (&p[1])==pEnd || p[0].db==p[1].db );
|
|
|
| @@ -1009,27 +1105,6 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){
|
| sqlite3DbFree(p->v->db, p);
|
| }
|
|
|
| -
|
| -#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
| -int sqlite3VdbeReleaseBuffers(Vdbe *p){
|
| - int ii;
|
| - int nFree = 0;
|
| - assert( sqlite3_mutex_held(p->db->mutex) );
|
| - for(ii=1; ii<=p->nMem; ii++){
|
| - Mem *pMem = &p->aMem[ii];
|
| - if( pMem->flags & MEM_RowSet ){
|
| - sqlite3RowSetClear(pMem->u.pRowSet);
|
| - }
|
| - if( pMem->z && pMem->flags&MEM_Dyn ){
|
| - assert( !pMem->xDel );
|
| - nFree += sqlite3DbMallocSize(pMem->db, pMem->z);
|
| - sqlite3VdbeMemRelease(pMem);
|
| - }
|
| - }
|
| - return nFree;
|
| -}
|
| -#endif
|
| -
|
| #ifndef SQLITE_OMIT_EXPLAIN
|
| /*
|
| ** Give a listing of the program in the virtual machine.
|
| @@ -1042,22 +1117,24 @@ int sqlite3VdbeReleaseBuffers(Vdbe *p){
|
| ** p->explain==2, only OP_Explain instructions are listed and these
|
| ** are shown in a different format. p->explain==2 is used to implement
|
| ** EXPLAIN QUERY PLAN.
|
| +**
|
| +** When p->explain==1, first the main program is listed, then each of
|
| +** the trigger subprograms are listed one by one.
|
| */
|
| int sqlite3VdbeList(
|
| Vdbe *p /* The VDBE */
|
| ){
|
| - int nRow; /* Total number of rows to return */
|
| + int nRow; /* Stop when row count reaches this */
|
| int nSub = 0; /* Number of sub-vdbes seen so far */
|
| SubProgram **apSub = 0; /* Array of sub-vdbes */
|
| - Mem *pSub = 0;
|
| - sqlite3 *db = p->db;
|
| - int i;
|
| - int rc = SQLITE_OK;
|
| - Mem *pMem = p->pResultSet = &p->aMem[1];
|
| + Mem *pSub = 0; /* Memory cell hold array of subprogs */
|
| + sqlite3 *db = p->db; /* The database connection */
|
| + int i; /* Loop counter */
|
| + int rc = SQLITE_OK; /* Return code */
|
| + Mem *pMem = p->pResultSet = &p->aMem[1]; /* First Mem of result set */
|
|
|
| assert( p->explain );
|
| assert( p->magic==VDBE_MAGIC_RUN );
|
| - assert( db->magic==SQLITE_MAGIC_BUSY );
|
| assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM );
|
|
|
| /* Even though this opcode does not use dynamic strings for
|
| @@ -1073,12 +1150,24 @@ int sqlite3VdbeList(
|
| return SQLITE_ERROR;
|
| }
|
|
|
| - /* Figure out total number of rows that will be returned by this
|
| - ** EXPLAIN program. */
|
| + /* When the number of output rows reaches nRow, that means the
|
| + ** listing has finished and sqlite3_step() should return SQLITE_DONE.
|
| + ** nRow is the sum of the number of rows in the main program, plus
|
| + ** the sum of the number of rows in all trigger subprograms encountered
|
| + ** so far. The nRow value will increase as new trigger subprograms are
|
| + ** encountered, but p->pc will eventually catch up to nRow.
|
| + */
|
| nRow = p->nOp;
|
| if( p->explain==1 ){
|
| + /* The first 8 memory cells are used for the result set. So we will
|
| + ** commandeer the 9th cell to use as storage for an array of pointers
|
| + ** to trigger subprograms. The VDBE is guaranteed to have at least 9
|
| + ** cells. */
|
| + assert( p->nMem>9 );
|
| pSub = &p->aMem[9];
|
| if( pSub->flags&MEM_Blob ){
|
| + /* On the first call to sqlite3_step(), pSub will hold a NULL. It is
|
| + ** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */
|
| nSub = pSub->n/sizeof(Vdbe*);
|
| apSub = (SubProgram **)pSub->z;
|
| }
|
| @@ -1101,8 +1190,12 @@ int sqlite3VdbeList(
|
| char *z;
|
| Op *pOp;
|
| if( i<p->nOp ){
|
| + /* The output line number is small enough that we are still in the
|
| + ** main program. */
|
| pOp = &p->aOp[i];
|
| }else{
|
| + /* We are currently listing subprograms. Figure out which one and
|
| + ** pick up the appropriate opcode. */
|
| int j;
|
| i -= p->nOp;
|
| for(j=0; i>=apSub[j]->nOp; j++){
|
| @@ -1124,6 +1217,11 @@ int sqlite3VdbeList(
|
| pMem->enc = SQLITE_UTF8;
|
| pMem++;
|
|
|
| + /* When an OP_Program opcode is encounter (the only opcode that has
|
| + ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
|
| + ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
|
| + ** has not already been seen.
|
| + */
|
| if( pOp->p4type==P4_SUBPROGRAM ){
|
| int nByte = (nSub+1)*sizeof(SubProgram*);
|
| int j;
|
| @@ -1149,12 +1247,10 @@ int sqlite3VdbeList(
|
| pMem->type = SQLITE_INTEGER;
|
| pMem++;
|
|
|
| - if( p->explain==1 ){
|
| - pMem->flags = MEM_Int;
|
| - pMem->u.i = pOp->p3; /* P3 */
|
| - pMem->type = SQLITE_INTEGER;
|
| - pMem++;
|
| - }
|
| + pMem->flags = MEM_Int;
|
| + pMem->u.i = pOp->p3; /* P3 */
|
| + pMem->type = SQLITE_INTEGER;
|
| + pMem++;
|
|
|
| if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
|
| assert( p->db->mallocFailed );
|
| @@ -1199,7 +1295,7 @@ int sqlite3VdbeList(
|
| }
|
| }
|
|
|
| - p->nResColumn = 8 - 5*(p->explain-1);
|
| + p->nResColumn = 8 - 4*(p->explain-1);
|
| p->rc = SQLITE_OK;
|
| rc = SQLITE_ROW;
|
| }
|
| @@ -1255,38 +1351,43 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
|
| #endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
|
|
|
| /*
|
| -** Allocate space from a fixed size buffer. Make *pp point to the
|
| -** allocated space. (Note: pp is a char* rather than a void** to
|
| -** work around the pointer aliasing rules of C.) *pp should initially
|
| -** be zero. If *pp is not zero, that means that the space has already
|
| -** been allocated and this routine is a noop.
|
| +** 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.
|
| **
|
| -** *ppFrom point to available space and pEnd points to the end of the
|
| -** available space.
|
| +** *ppFrom points to available space and pEnd points to the end of the
|
| +** available space. When space is allocated, *ppFrom is advanced past
|
| +** the end of the allocated space.
|
| **
|
| ** *pnByte is a counter of the number of bytes of space that have failed
|
| ** to allocate. If there is insufficient space in *ppFrom to satisfy the
|
| ** request, then increment *pnByte by the amount of the request.
|
| */
|
| -static void allocSpace(
|
| - char *pp, /* IN/OUT: Set *pp to point to allocated buffer */
|
| +static void *allocSpace(
|
| + void *pBuf, /* Where return pointer will be stored */
|
| int nByte, /* Number of bytes to allocate */
|
| u8 **ppFrom, /* IN/OUT: Allocate from *ppFrom */
|
| u8 *pEnd, /* Pointer to 1 byte past the end of *ppFrom buffer */
|
| int *pnByte /* If allocation cannot be made, increment *pnByte */
|
| ){
|
| assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) );
|
| - if( (*(void**)pp)==0 ){
|
| - nByte = ROUND8(nByte);
|
| - if( &(*ppFrom)[nByte] <= pEnd ){
|
| - *(void**)pp = (void *)*ppFrom;
|
| - *ppFrom += nByte;
|
| - }else{
|
| - *pnByte += nByte;
|
| - }
|
| + if( pBuf ) return pBuf;
|
| + nByte = ROUND8(nByte);
|
| + if( &(*ppFrom)[nByte] <= pEnd ){
|
| + pBuf = (void*)*ppFrom;
|
| + *ppFrom += nByte;
|
| + }else{
|
| + *pnByte += nByte;
|
| }
|
| + return pBuf;
|
| }
|
|
|
| /*
|
| @@ -1345,9 +1446,10 @@ void sqlite3VdbeMakeReady(
|
| ** being called from sqlite3_reset() to reset the virtual machine.
|
| */
|
| if( nVar>=0 && ALWAYS(db->mallocFailed==0) ){
|
| - u8 *zCsr = (u8 *)&p->aOp[p->nOp];
|
| - u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc];
|
| - int nByte;
|
| + u8 *zCsr = (u8 *)&p->aOp[p->nOp]; /* Memory avaliable for alloation */
|
| + u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc]; /* First byte past available mem */
|
| + int nByte; /* How much extra memory needed */
|
| +
|
| resolveP2Values(p, &nArg);
|
| p->usesStmtJournal = (u8)usesStmtJournal;
|
| if( isExplain && nMem<10 ){
|
| @@ -1357,15 +1459,24 @@ void sqlite3VdbeMakeReady(
|
| zCsr += (zCsr - (u8*)0)&7;
|
| assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
|
|
|
| + /* Memory for registers, parameters, cursor, etc, is allocated in two
|
| + ** passes. On the first pass, we try to reuse unused space 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.
|
| + **
|
| + ** This two-pass approach that reuses as much memory as possible from
|
| + ** the leftover space at the end of the opcode array can significantly
|
| + ** reduce the amount of memory held by a prepared statement.
|
| + */
|
| do {
|
| nByte = 0;
|
| - allocSpace((char*)&p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
|
| - allocSpace((char*)&p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
|
| - allocSpace((char*)&p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
|
| - allocSpace((char*)&p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
| - allocSpace((char*)&p->apCsr,
|
| - nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte
|
| - );
|
| + p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
|
| + p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
|
| + p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
|
| + p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
| + p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
|
| + &zCsr, zEnd, &nByte);
|
| if( nByte ){
|
| p->pFree = sqlite3DbMallocZero(db, nByte);
|
| }
|
| @@ -1375,7 +1486,7 @@ void sqlite3VdbeMakeReady(
|
|
|
| p->nCursor = (u16)nCursor;
|
| if( p->aVar ){
|
| - p->nVar = (u16)nVar;
|
| + p->nVar = (ynVar)nVar;
|
| for(n=0; n<nVar; n++){
|
| p->aVar[n].flags = MEM_Null;
|
| p->aVar[n].db = db;
|
| @@ -1405,6 +1516,7 @@ void sqlite3VdbeMakeReady(
|
| p->cacheCtr = 1;
|
| p->minWriteFileFormat = 255;
|
| p->iStatement = 0;
|
| + p->nFkConstraint = 0;
|
| #ifdef VDBE_PROFILE
|
| {
|
| int i;
|
| @@ -1436,9 +1548,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
| sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
|
| const sqlite3_module *pModule = pCx->pModule;
|
| p->inVtabMethod = 1;
|
| - (void)sqlite3SafetyOff(p->db);
|
| pModule->xClose(pVtabCursor);
|
| - (void)sqlite3SafetyOn(p->db);
|
| p->inVtabMethod = 0;
|
| }
|
| #endif
|
| @@ -1472,7 +1582,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
| */
|
| static void closeAllCursors(Vdbe *p){
|
| if( p->pFrame ){
|
| - VdbeFrame *pFrame = p->pFrame;
|
| + VdbeFrame *pFrame;
|
| for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
|
| sqlite3VdbeFrameRestore(pFrame);
|
| }
|
| @@ -1492,6 +1602,11 @@ static void closeAllCursors(Vdbe *p){
|
| if( p->aMem ){
|
| releaseMemArray(&p->aMem[1], p->nMem);
|
| }
|
| + while( p->pDelFrame ){
|
| + VdbeFrame *pDel = p->pDelFrame;
|
| + p->pDelFrame = pDel->pParent;
|
| + sqlite3VdbeFrameDelete(pDel);
|
| + }
|
| }
|
|
|
| /*
|
| @@ -1599,9 +1714,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
| ** to the transaction.
|
| */
|
| rc = sqlite3VtabSync(db, &p->zErrMsg);
|
| - if( rc!=SQLITE_OK ){
|
| - return rc;
|
| - }
|
|
|
| /* This loop determines (a) if the commit hook should be invoked and
|
| ** (b) how many database files have open write transactions, not
|
| @@ -1609,19 +1721,21 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
| ** one database file has an open write transaction, a master journal
|
| ** file is required for an atomic commit.
|
| */
|
| - for(i=0; i<db->nDb; i++){
|
| + for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
| Btree *pBt = db->aDb[i].pBt;
|
| if( sqlite3BtreeIsInTrans(pBt) ){
|
| needXcommit = 1;
|
| if( i!=1 ) nTrans++;
|
| + rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
|
| }
|
| }
|
| + if( rc!=SQLITE_OK ){
|
| + return rc;
|
| + }
|
|
|
| /* If there are any write-transactions at all, invoke the commit hook */
|
| if( needXcommit && db->xCommitCallback ){
|
| - (void)sqlite3SafetyOff(db);
|
| rc = db->xCommitCallback(db->pCommitArg);
|
| - (void)sqlite3SafetyOn(db);
|
| if( rc ){
|
| return SQLITE_CONSTRAINT;
|
| }
|
| @@ -1654,7 +1768,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
| for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
| Btree *pBt = db->aDb[i].pBt;
|
| if( pBt ){
|
| - rc = sqlite3BtreeCommitPhaseTwo(pBt);
|
| + rc = sqlite3BtreeCommitPhaseTwo(pBt, 0);
|
| }
|
| }
|
| if( rc==SQLITE_OK ){
|
| @@ -1707,10 +1821,12 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
| */
|
| for(i=0; i<db->nDb; i++){
|
| Btree *pBt = db->aDb[i].pBt;
|
| - if( i==1 ) continue; /* Ignore the TEMP database */
|
| if( sqlite3BtreeIsInTrans(pBt) ){
|
| char const *zFile = sqlite3BtreeGetJournalname(pBt);
|
| - if( zFile[0]==0 ) continue; /* Ignore :memory: databases */
|
| + if( zFile==0 ){
|
| + continue; /* Ignore TEMP and :memory: databases */
|
| + }
|
| + assert( zFile[0]!=0 );
|
| if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
|
| needSync = 1;
|
| }
|
| @@ -1755,6 +1871,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
| }
|
| }
|
| sqlite3OsCloseFree(pMaster);
|
| + assert( rc!=SQLITE_BUSY );
|
| if( rc!=SQLITE_OK ){
|
| sqlite3DbFree(db, zMaster);
|
| return rc;
|
| @@ -1783,7 +1900,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
| for(i=0; i<db->nDb; i++){
|
| Btree *pBt = db->aDb[i].pBt;
|
| if( pBt ){
|
| - sqlite3BtreeCommitPhaseTwo(pBt);
|
| + sqlite3BtreeCommitPhaseTwo(pBt, 1);
|
| }
|
| }
|
| sqlite3EndBenignMalloc();
|
| @@ -1895,34 +2012,37 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
|
| }
|
| 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( eOp==SAVEPOINT_ROLLBACK ){
|
| + db->nDeferredCons = p->nStmtDefCons;
|
| + }
|
| }
|
| return rc;
|
| }
|
|
|
| /*
|
| -** If SQLite is compiled to support shared-cache mode and to be threadsafe,
|
| -** this routine obtains the mutex associated with each BtShared structure
|
| -** that may be accessed by the VM passed as an argument. In doing so it
|
| -** sets the BtShared.db member of each of the BtShared structures, ensuring
|
| -** that the correct busy-handler callback is invoked if required.
|
| -**
|
| -** If SQLite is not threadsafe but does support shared-cache mode, then
|
| -** sqlite3BtreeEnterAll() is invoked to set the BtShared.db variables
|
| -** of all of BtShared structures accessible via the database handle
|
| -** associated with the VM. Of course only a subset of these structures
|
| -** will be accessed by the VM, and we could use Vdbe.btreeMask to figure
|
| -** that subset out, but there is no advantage to doing so.
|
| +** This function is called when a transaction opened by the database
|
| +** handle associated with the VM passed as an argument is about to be
|
| +** committed. If there are outstanding deferred foreign key constraint
|
| +** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
|
| **
|
| -** If SQLite is not threadsafe and does not support shared-cache mode, this
|
| -** function is a no-op.
|
| +** If there are outstanding FK violations and this function returns
|
| +** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT and write
|
| +** an error message to it. Then return SQLITE_ERROR.
|
| */
|
| -#ifndef SQLITE_OMIT_SHARED_CACHE
|
| -void sqlite3VdbeMutexArrayEnter(Vdbe *p){
|
| -#if SQLITE_THREADSAFE
|
| - sqlite3BtreeMutexArrayEnter(&p->aMutex);
|
| -#else
|
| - sqlite3BtreeEnterAll(p->db);
|
| -#endif
|
| +#ifndef SQLITE_OMIT_FOREIGN_KEY
|
| +int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
|
| + sqlite3 *db = p->db;
|
| + if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){
|
| + p->rc = SQLITE_CONSTRAINT;
|
| + p->errorAction = OE_Abort;
|
| + sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
|
| + return SQLITE_ERROR;
|
| + }
|
| + return SQLITE_OK;
|
| }
|
| #endif
|
|
|
| @@ -1975,7 +2095,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| int isSpecialError; /* Set to true if a 'special' error */
|
|
|
| /* Lock all btrees used by the statement */
|
| - sqlite3VdbeMutexArrayEnter(p);
|
| + sqlite3VdbeEnter(p);
|
|
|
| /* Check for one of the special errors */
|
| mrc = p->rc & 0xff;
|
| @@ -1983,8 +2103,17 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|
| || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
|
| if( isSpecialError ){
|
| - /* If the query was read-only, we need do no rollback at all. Otherwise,
|
| - ** proceed with the special handling.
|
| + /* If the query was read-only and the error code is SQLITE_INTERRUPT,
|
| + ** no rollback is necessary. Otherwise, at least a savepoint
|
| + ** transaction must be rolled back to restore the database to a
|
| + ** consistent state.
|
| + **
|
| + ** Even if the statement is read-only, it is important to perform
|
| + ** a statement or transaction rollback operation. If the error
|
| + ** occured while writing to the journal, sub-journal or database
|
| + ** file as part of an effort to free up cache space (see function
|
| + ** pagerStress() in pager.c), the rollback is required to restore
|
| + ** the pager to a consistent state.
|
| */
|
| if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
|
| if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){
|
| @@ -2000,6 +2129,11 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| }
|
| }
|
| }
|
| +
|
| + /* Check for immediate foreign key violations. */
|
| + if( p->rc==SQLITE_OK ){
|
| + sqlite3VdbeCheckFk(p, 0);
|
| + }
|
|
|
| /* If the auto-commit flag is set and this is the only active writer
|
| ** VM, then we do either a commit or rollback of the current transaction.
|
| @@ -2012,18 +2146,28 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| && db->writeVdbeCnt==(p->readOnly==0)
|
| ){
|
| if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
|
| - /* The auto-commit flag is true, and the vdbe program was
|
| - ** successful or hit an 'OR FAIL' constraint. This means a commit
|
| - ** is required.
|
| - */
|
| - rc = vdbeCommit(db, p);
|
| - if( rc==SQLITE_BUSY ){
|
| - sqlite3BtreeMutexArrayLeave(&p->aMutex);
|
| + rc = sqlite3VdbeCheckFk(p, 1);
|
| + if( rc!=SQLITE_OK ){
|
| + if( NEVER(p->readOnly) ){
|
| + sqlite3VdbeLeave(p);
|
| + return SQLITE_ERROR;
|
| + }
|
| + rc = SQLITE_CONSTRAINT;
|
| + }else{
|
| + /* The auto-commit flag is true, the vdbe program was successful
|
| + ** or hit an 'OR FAIL' constraint and there are no deferred foreign
|
| + ** key constraints to hold up the transaction. This means a commit
|
| + ** is required. */
|
| + rc = vdbeCommit(db, p);
|
| + }
|
| + if( rc==SQLITE_BUSY && p->readOnly ){
|
| + sqlite3VdbeLeave(p);
|
| return SQLITE_BUSY;
|
| }else if( rc!=SQLITE_OK ){
|
| p->rc = rc;
|
| sqlite3RollbackAll(db);
|
| }else{
|
| + db->nDeferredCons = 0;
|
| sqlite3CommitInternalChanges(db);
|
| }
|
| }else{
|
| @@ -2046,15 +2190,27 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| /* If eStatementOp is non-zero, then a statement transaction needs to
|
| ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
|
| ** do so. If this operation returns an error, and the current statement
|
| - ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then set the error
|
| - ** code to the new value.
|
| + ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
|
| + ** current statement error code.
|
| + **
|
| + ** Note that sqlite3VdbeCloseStatement() can only fail if eStatementOp
|
| + ** is SAVEPOINT_ROLLBACK. But if p->rc==SQLITE_OK then eStatementOp
|
| + ** must be SAVEPOINT_RELEASE. Hence the NEVER(p->rc==SQLITE_OK) in
|
| + ** the following code.
|
| */
|
| if( eStatementOp ){
|
| rc = sqlite3VdbeCloseStatement(p, eStatementOp);
|
| - if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
|
| - p->rc = rc;
|
| - sqlite3DbFree(db, p->zErrMsg);
|
| - p->zErrMsg = 0;
|
| + if( rc ){
|
| + assert( eStatementOp==SAVEPOINT_ROLLBACK );
|
| + if( NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT ){
|
| + p->rc = rc;
|
| + sqlite3DbFree(db, p->zErrMsg);
|
| + p->zErrMsg = 0;
|
| + }
|
| + invalidateCursorsOnModifiedBtrees(db);
|
| + sqlite3RollbackAll(db);
|
| + sqlite3CloseSavepoints(db);
|
| + db->autoCommit = 1;
|
| }
|
| }
|
|
|
| @@ -2072,12 +2228,12 @@ int sqlite3VdbeHalt(Vdbe *p){
|
|
|
| /* Rollback or commit any schema changes that occurred. */
|
| if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
|
| - sqlite3ResetInternalSchema(db, 0);
|
| + sqlite3ResetInternalSchema(db, -1);
|
| db->flags = (db->flags | SQLITE_InternChanges);
|
| }
|
|
|
| /* Release the locks */
|
| - sqlite3BtreeMutexArrayLeave(&p->aMutex);
|
| + sqlite3VdbeLeave(p);
|
| }
|
|
|
| /* We have successfully halted and closed the VM. Record this fact. */
|
| @@ -2103,7 +2259,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
| }
|
|
|
| assert( db->activeVdbeCnt>0 || db->autoCommit==0 || db->nStatement==0 );
|
| - return SQLITE_OK;
|
| + return (p->rc==SQLITE_BUSY ? SQLITE_BUSY : SQLITE_OK);
|
| }
|
|
|
|
|
| @@ -2134,9 +2290,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
| ** error, then it might not have been halted properly. So halt
|
| ** it now.
|
| */
|
| - (void)sqlite3SafetyOn(db);
|
| sqlite3VdbeHalt(p);
|
| - (void)sqlite3SafetyOff(db);
|
|
|
| /* If the VDBE has be run even partially, then transfer the error code
|
| ** and error message from the VDBE into the main database structure. But
|
| @@ -2156,6 +2310,7 @@ int sqlite3VdbeReset(Vdbe *p){
|
| }else{
|
| sqlite3Error(db, SQLITE_OK, 0);
|
| }
|
| + if( p->runOnlyOnce ) p->expired = 1;
|
| }else if( p->rc && p->expired ){
|
| /* The expired flag was set on the VDBE before the first call
|
| ** to sqlite3_step(). For consistency (since sqlite3_step() was
|
| @@ -2233,6 +2388,30 @@ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
|
| }
|
|
|
| /*
|
| +** Free all memory associated with the Vdbe passed as the second argument.
|
| +** The difference between this function and sqlite3VdbeDelete() is that
|
| +** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
|
| +** the database connection.
|
| +*/
|
| +void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
|
| + SubProgram *pSub, *pNext;
|
| + 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);
|
| + }
|
| + vdbeFreeOpArray(db, p->aOp, p->nOp);
|
| + sqlite3DbFree(db, p->aLabel);
|
| + sqlite3DbFree(db, p->aColName);
|
| + sqlite3DbFree(db, p->zSql);
|
| + sqlite3DbFree(db, p->pFree);
|
| + sqlite3DbFree(db, p);
|
| +}
|
| +
|
| +/*
|
| ** Delete an entire VDBE.
|
| */
|
| void sqlite3VdbeDelete(Vdbe *p){
|
| @@ -2249,15 +2428,9 @@ void sqlite3VdbeDelete(Vdbe *p){
|
| if( p->pNext ){
|
| p->pNext->pPrev = p->pPrev;
|
| }
|
| - releaseMemArray(p->aVar, p->nVar);
|
| - releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
| - vdbeFreeOpArray(db, p->aOp, p->nOp);
|
| - sqlite3DbFree(db, p->aLabel);
|
| - sqlite3DbFree(db, p->aColName);
|
| - sqlite3DbFree(db, p->zSql);
|
| p->magic = VDBE_MAGIC_DEAD;
|
| - sqlite3DbFree(db, p->pFree);
|
| - sqlite3DbFree(db, p);
|
| + p->db = 0;
|
| + sqlite3VdbeDeleteObject(db, p);
|
| }
|
|
|
| /*
|
| @@ -2283,11 +2456,8 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
| rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
|
| if( rc ) return rc;
|
| p->lastRowid = p->movetoTarget;
|
| - p->rowidIsValid = ALWAYS(res==0) ?1:0;
|
| - if( NEVER(res<0) ){
|
| - rc = sqlite3BtreeNext(p->pCursor, &res);
|
| - if( rc ) return rc;
|
| - }
|
| + if( res!=0 ) return SQLITE_CORRUPT_BKPT;
|
| + p->rowidIsValid = 1;
|
| #ifdef SQLITE_TEST
|
| sqlite3_search_count++;
|
| #endif
|
| @@ -2365,7 +2535,13 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
| if( file_format>=4 && (i&1)==i ){
|
| return 8+(u32)i;
|
| }
|
| - u = i<0 ? -i : i;
|
| + if( i<0 ){
|
| + if( i<(-MAX_6BYTE) ) return 6;
|
| + /* Previous test prevents: u = -(-9223372036854775808) */
|
| + u = -i;
|
| + }else{
|
| + u = i;
|
| + }
|
| if( u<=127 ) return 1;
|
| if( u<=32767 ) return 2;
|
| if( u<=8388607 ) return 3;
|
| @@ -2748,9 +2924,17 @@ int sqlite3VdbeRecordCompare(
|
| pKeyInfo = pPKey2->pKeyInfo;
|
| mem1.enc = pKeyInfo->enc;
|
| mem1.db = pKeyInfo->db;
|
| - mem1.flags = 0;
|
| - mem1.u.i = 0; /* not needed, here to silence compiler warning */
|
| - mem1.zMalloc = 0;
|
| + /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */
|
| + VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */
|
| +
|
| + /* Compilers may complain that mem1.u.i is potentially uninitialized.
|
| + ** We could initialize it, as shown here, to silence those complaints.
|
| + ** But in fact, mem1.u.i will never actually be used initialized, and doing
|
| + ** the unnecessary initialization has a measurable negative performance
|
| + ** impact, since this routine is a very high runner. And so, we choose
|
| + ** to ignore the compiler warnings and leave this variable uninitialized.
|
| + */
|
| + /* mem1.u.i = 0; // not needed, here to silence compiler warning */
|
|
|
| idx1 = getVarint32(aKey1, szHdr1);
|
| d1 = szHdr1;
|
| @@ -2774,47 +2958,52 @@ int sqlite3VdbeRecordCompare(
|
| rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i],
|
| i<nField ? pKeyInfo->aColl[i] : 0);
|
| if( rc!=0 ){
|
| - break;
|
| + assert( mem1.zMalloc==0 ); /* See comment below */
|
| +
|
| + /* Invert the result if we are using DESC sort order. */
|
| + if( pKeyInfo->aSortOrder && i<nField && pKeyInfo->aSortOrder[i] ){
|
| + rc = -rc;
|
| + }
|
| +
|
| + /* If the PREFIX_SEARCH flag is set and all fields except the final
|
| + ** rowid field were equal, then clear the PREFIX_SEARCH flag and set
|
| + ** pPKey2->rowid to the value of the rowid field in (pKey1, nKey1).
|
| + ** This is used by the OP_IsUnique opcode.
|
| + */
|
| + if( (pPKey2->flags & UNPACKED_PREFIX_SEARCH) && i==(pPKey2->nField-1) ){
|
| + assert( idx1==szHdr1 && rc );
|
| + assert( mem1.flags & MEM_Int );
|
| + pPKey2->flags &= ~UNPACKED_PREFIX_SEARCH;
|
| + pPKey2->rowid = mem1.u.i;
|
| + }
|
| +
|
| + return rc;
|
| }
|
| i++;
|
| }
|
|
|
| - /* No memory allocation is ever used on mem1. */
|
| - if( NEVER(mem1.zMalloc) ) sqlite3VdbeMemRelease(&mem1);
|
| -
|
| - /* If the PREFIX_SEARCH flag is set and all fields except the final
|
| - ** rowid field were equal, then clear the PREFIX_SEARCH flag and set
|
| - ** pPKey2->rowid to the value of the rowid field in (pKey1, nKey1).
|
| - ** This is used by the OP_IsUnique opcode.
|
| + /* No memory allocation is ever used on mem1. Prove this using
|
| + ** the following assert(). If the assert() fails, it indicates a
|
| + ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1).
|
| */
|
| - if( (pPKey2->flags & UNPACKED_PREFIX_SEARCH) && i==(pPKey2->nField-1) ){
|
| - assert( idx1==szHdr1 && rc );
|
| - assert( mem1.flags & MEM_Int );
|
| - pPKey2->flags &= ~UNPACKED_PREFIX_SEARCH;
|
| - pPKey2->rowid = mem1.u.i;
|
| - }
|
| -
|
| - if( rc==0 ){
|
| - /* rc==0 here means that one of the keys ran out of fields and
|
| - ** all the fields up to that point were equal. If the UNPACKED_INCRKEY
|
| - ** flag is set, then break the tie by treating key2 as larger.
|
| - ** If the UPACKED_PREFIX_MATCH flag is set, then keys with common prefixes
|
| - ** are considered to be equal. Otherwise, the longer key is the
|
| - ** larger. As it happens, the pPKey2 will always be the longer
|
| - ** if there is a difference.
|
| - */
|
| - if( pPKey2->flags & UNPACKED_INCRKEY ){
|
| - rc = -1;
|
| - }else if( pPKey2->flags & UNPACKED_PREFIX_MATCH ){
|
| - /* Leave rc==0 */
|
| - }else if( idx1<szHdr1 ){
|
| - rc = 1;
|
| - }
|
| - }else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
|
| - && pKeyInfo->aSortOrder[i] ){
|
| - rc = -rc;
|
| + assert( mem1.zMalloc==0 );
|
| +
|
| + /* rc==0 here means that one of the keys ran out of fields and
|
| + ** all the fields up to that point were equal. If the UNPACKED_INCRKEY
|
| + ** flag is set, then break the tie by treating key2 as larger.
|
| + ** If the UPACKED_PREFIX_MATCH flag is set, then keys with common prefixes
|
| + ** are considered to be equal. Otherwise, the longer key is the
|
| + ** larger. As it happens, the pPKey2 will always be the longer
|
| + ** if there is a difference.
|
| + */
|
| + assert( rc==0 );
|
| + if( pPKey2->flags & UNPACKED_INCRKEY ){
|
| + rc = -1;
|
| + }else if( pPKey2->flags & UNPACKED_PREFIX_MATCH ){
|
| + /* Leave rc==0 */
|
| + }else if( idx1<szHdr1 ){
|
| + rc = 1;
|
| }
|
| -
|
| return rc;
|
| }
|
|
|
| @@ -2924,7 +3113,7 @@ int sqlite3VdbeIdxKeyCompare(
|
| ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
|
| if( nCellKey<=0 || nCellKey>0x7fffffff ){
|
| *res = 0;
|
| - return SQLITE_CORRUPT;
|
| + return SQLITE_CORRUPT_BKPT;
|
| }
|
| memset(&m, 0, sizeof(m));
|
| rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (int)nCellKey, 1, &m);
|
| @@ -2978,3 +3167,42 @@ void sqlite3ExpirePreparedStatements(sqlite3 *db){
|
| sqlite3 *sqlite3VdbeDb(Vdbe *v){
|
| return v->db;
|
| }
|
| +
|
| +/*
|
| +** Return a pointer to an sqlite3_value structure containing the value bound
|
| +** parameter iVar of VM v. Except, if the value is an SQL NULL, return
|
| +** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_*
|
| +** constants) to the value before returning it.
|
| +**
|
| +** The returned value must be freed by the caller using sqlite3ValueFree().
|
| +*/
|
| +sqlite3_value *sqlite3VdbeGetValue(Vdbe *v, int iVar, u8 aff){
|
| + assert( iVar>0 );
|
| + if( v ){
|
| + Mem *pMem = &v->aVar[iVar-1];
|
| + if( 0==(pMem->flags & MEM_Null) ){
|
| + sqlite3_value *pRet = sqlite3ValueNew(v->db);
|
| + if( pRet ){
|
| + sqlite3VdbeMemCopy((Mem *)pRet, pMem);
|
| + sqlite3ValueApplyAffinity(pRet, aff, SQLITE_UTF8);
|
| + sqlite3VdbeMemStoreType((Mem *)pRet);
|
| + }
|
| + return pRet;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/*
|
| +** Configure SQL variable iVar so that binding a new value to it signals
|
| +** to sqlite3_reoptimize() that re-preparing the statement may result
|
| +** in a better query plan.
|
| +*/
|
| +void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
| + assert( iVar>0 );
|
| + if( iVar>32 ){
|
| + v->expmask = 0xffffffff;
|
| + }else{
|
| + v->expmask |= ((u32)1 << (iVar-1));
|
| + }
|
| +}
|
|
|