diff options
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/vdbeaux.c')
-rw-r--r-- | ext/pdo_sqlite/sqlite/src/vdbeaux.c | 569 |
1 files changed, 399 insertions, 170 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeaux.c b/ext/pdo_sqlite/sqlite/src/vdbeaux.c index cba9c096d..c71c8f4ea 100644 --- a/ext/pdo_sqlite/sqlite/src/vdbeaux.c +++ b/ext/pdo_sqlite/sqlite/src/vdbeaux.c @@ -58,8 +58,14 @@ void sqlite3VdbeTrace(Vdbe *p, FILE *trace){ /* ** Resize the Vdbe.aOp array so that it contains at least N ** elements. If the Vdbe is in VDBE_MAGIC_RUN state, then -** the Vdbe.aOp array will be sized to contain exactly N -** elements. +** the Vdbe.aOp array will be sized to contain exactly N +** elements. Vdbe.nOpAlloc is set to reflect the new size of +** the array. +** +** If an out-of-memory error occurs while resizing the array, +** Vdbe.aOp and Vdbe.nOpAlloc remain unchanged (this is so that +** any opcodes already allocated can be correctly deallocated +** along with the rest of the Vdbe). */ static void resizeOpArray(Vdbe *p, int N){ int runMode = p->magic==VDBE_MAGIC_RUN; @@ -101,9 +107,11 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ i = p->nOp; p->nOp++; assert( p->magic==VDBE_MAGIC_INIT ); - resizeOpArray(p, i+1); - if( sqlite3_malloc_failed ){ - return 0; + if( p->nOpAlloc<=i ){ + resizeOpArray(p, i+1); + if( sqlite3MallocFailed() ){ + return 0; + } } pOp = &p->aOp[i]; pOp->opcode = op; @@ -147,7 +155,7 @@ int sqlite3VdbeMakeLabel(Vdbe *p){ assert( p->magic==VDBE_MAGIC_INIT ); if( i>=p->nLabelAlloc ){ p->nLabelAlloc = p->nLabelAlloc*2 + 10; - sqlite3ReallocOrFree((void**)&p->aLabel, + sqliteReallocOrFree((void**)&p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); } if( p->aLabel ){ @@ -196,12 +204,13 @@ static int opcodeNoPush(u8 op){ ** IEEE floats. */ static const u32 masks[5] = { - NOPUSH_MASK_0 + (NOPUSH_MASK_1<<16), - NOPUSH_MASK_2 + (NOPUSH_MASK_3<<16), - NOPUSH_MASK_4 + (NOPUSH_MASK_5<<16), - NOPUSH_MASK_6 + (NOPUSH_MASK_7<<16), - NOPUSH_MASK_8 + (NOPUSH_MASK_9<<16) + NOPUSH_MASK_0 + (((unsigned)NOPUSH_MASK_1)<<16), + NOPUSH_MASK_2 + (((unsigned)NOPUSH_MASK_3)<<16), + NOPUSH_MASK_4 + (((unsigned)NOPUSH_MASK_5)<<16), + NOPUSH_MASK_6 + (((unsigned)NOPUSH_MASK_7)<<16), + NOPUSH_MASK_8 + (((unsigned)NOPUSH_MASK_9)<<16) }; + assert( op<32*5 ); return (masks[op>>5] & (1<<(op&0x1F))); } @@ -219,7 +228,7 @@ int sqlite3VdbeOpcodeNoPush(u8 op){ ** This routine is called once after all opcodes have been inserted. ** ** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument -** to an OP_Function or OP_AggStep opcode. This is used by +** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. ** ** The integer *pMaxStack is set to the maximum number of vdbe stack @@ -242,20 +251,25 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){ for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ u8 opcode = pOp->opcode; - if( opcode==OP_Function || opcode==OP_AggStep ){ + if( opcode==OP_Function || opcode==OP_AggStep +#ifndef SQLITE_OMIT_VIRTUALTABLE + || opcode==OP_VUpdate +#endif + ){ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; }else if( opcode==OP_Halt ){ if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ doesStatementRollback = 1; } - }else if( opcode==OP_IdxInsert ){ - if( pOp->p2 ){ - doesStatementRollback = 1; - } }else if( opcode==OP_Statement ){ hasStatementBegin = 1; + }else if( opcode==OP_VFilter ){ + int n; + assert( p->nOp - i >= 3 ); + assert( pOp[-2].opcode==OP_Integer ); + n = pOp[-2].p1; + if( n>nMaxArgs ) nMaxArgs = n; } - if( opcodeNoPush(opcode) ){ nMaxStack--; } @@ -300,7 +314,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ int addr; assert( p->magic==VDBE_MAGIC_INIT ); resizeOpArray(p, p->nOp + nOp); - if( sqlite3_malloc_failed ){ + if( sqlite3MallocFailed() ){ return 0; } addr = p->nOp; @@ -333,7 +347,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ ** few minor changes to the program. */ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ - assert( p->magic==VDBE_MAGIC_INIT ); + assert( p==0 || p->magic==VDBE_MAGIC_INIT ); if( p && addr>=0 && p->nOp>addr && p->aOp ){ p->aOp[addr].p1 = val; } @@ -345,20 +359,31 @@ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ */ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ assert( val>=0 ); - assert( p->magic==VDBE_MAGIC_INIT ); + assert( p==0 || p->magic==VDBE_MAGIC_INIT ); if( p && addr>=0 && p->nOp>addr && p->aOp ){ p->aOp[addr].p2 = val; } } /* -** Change teh P2 operand of instruction addr so that it points to +** Change the P2 operand of instruction addr so that it points to ** the address of the next instruction to be coded. */ void sqlite3VdbeJumpHere(Vdbe *p, int addr){ sqlite3VdbeChangeP2(p, addr, p->nOp); } + +/* +** If the input FuncDef structure is ephemeral, then free it. If +** the FuncDef is not ephermal, then do nothing. +*/ +static void freeEphemeralFunction(FuncDef *pDef){ + if( pDef && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){ + sqliteFree(pDef); + } +} + /* ** Delete a P3 value if necessary. */ @@ -371,12 +396,21 @@ static void freeP3(int p3type, void *p3){ sqliteFree(p3); break; } + case P3_MPRINTF: { + sqlite3_free(p3); + break; + } case P3_VDBEFUNC: { VdbeFunc *pVdbeFunc = (VdbeFunc *)p3; + freeEphemeralFunction(pVdbeFunc->pFunc); sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); sqliteFree(pVdbeFunc); break; } + case P3_FUNCDEF: { + freeEphemeralFunction((FuncDef*)p3); + break; + } case P3_MEM: { sqlite3ValueFree((sqlite3_value*)p3); break; @@ -387,6 +421,19 @@ static void freeP3(int p3type, void *p3){ /* +** Change N opcodes starting at addr to No-ops. +*/ +void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){ + VdbeOp *pOp = &p->aOp[addr]; + while( N-- ){ + freeP3(pOp->p3type, pOp->p3); + memset(pOp, 0, sizeof(pOp[0])); + pOp->opcode = OP_Noop; + pOp++; + } +} + +/* ** Change the value of the P3 operand for a specific instruction. ** This routine is useful when a large program is loaded from a ** static array using sqlite3VdbeAddOpList but we want to make a @@ -413,9 +460,11 @@ static void freeP3(int p3type, void *p3){ */ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ Op *pOp; - assert( p->magic==VDBE_MAGIC_INIT ); - if( p==0 || p->aOp==0 ){ - freeP3(n, (void*)*(char**)&zP3); + assert( p==0 || p->magic==VDBE_MAGIC_INIT ); + if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){ + if (n != P3_KEYINFO) { + freeP3(n, (void*)*(char**)&zP3); + } return; } if( addr<0 || addr>=p->nOp ){ @@ -432,16 +481,18 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ KeyInfo *pKeyInfo; int nField, nByte; - /* KeyInfo structures that include an KeyInfo.aSortOrder are always - ** sent in using P3_KEYINFO_HANDOFF. The KeyInfo.aSortOrder array - ** is not duplicated when P3_KEYINFO is used. */ - /* assert( pKeyInfo->aSortOrder==0 ); */ nField = ((KeyInfo*)zP3)->nField; - nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]); + nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField; pKeyInfo = sqliteMallocRaw( nByte ); pOp->p3 = (char*)pKeyInfo; if( pKeyInfo ){ + unsigned char *aSortOrder; memcpy(pKeyInfo, zP3, nByte); + aSortOrder = pKeyInfo->aSortOrder; + if( aSortOrder ){ + pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField]; + memcpy(pKeyInfo->aSortOrder, aSortOrder, nField); + } pOp->p3type = P3_KEYINFO; }else{ pOp->p3type = P3_NOTUSED; @@ -467,7 +518,8 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_list ap; assert( p->nOp>0 ); - assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 ); + assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 + || sqlite3MallocFailed() ); va_start(ap, zFormat); sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC); va_end(ap); @@ -531,15 +583,18 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){ } case P3_FUNCDEF: { FuncDef *pDef = (FuncDef*)pOp->p3; - char zNum[30]; - sprintf(zTemp, "%.*s", nTemp, pDef->zName); - sprintf(zNum,"(%d)", pDef->nArg); - if( strlen(zTemp)+strlen(zNum)+1<=nTemp ){ - strcat(zTemp, zNum); - } + sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg); + zP3 = zTemp; + break; + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + case P3_VTAB: { + sqlite3_vtab *pVtab = (sqlite3_vtab*)pOp->p3; + sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule); zP3 = zTemp; break; } +#endif default: { zP3 = pOp->p3; if( zP3==0 || pOp->opcode==OP_Noop ){ @@ -547,6 +602,7 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){ } } } + assert( zP3!=0 ); return zP3; } #endif @@ -614,8 +670,7 @@ int sqlite3VdbeList( if( i>=p->nOp ){ p->rc = SQLITE_OK; rc = SQLITE_DONE; - }else if( db->flags & SQLITE_Interrupt ){ - db->flags &= ~SQLITE_Interrupt; + }else if( db->u1.isInterrupted ){ p->rc = SQLITE_INTERRUPT; rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0); @@ -629,6 +684,7 @@ int sqlite3VdbeList( pMem->flags = MEM_Static|MEM_Str|MEM_Term; pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */ + assert( pMem->z!=0 ); pMem->n = strlen(pMem->z); pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; @@ -644,8 +700,10 @@ int sqlite3VdbeList( pMem->type = SQLITE_INTEGER; pMem++; - pMem->flags = MEM_Short|MEM_Str|MEM_Term; /* P3 */ + pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P3 */ pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort)); + assert( pMem->z!=0 ); + pMem->n = strlen(pMem->z); pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; @@ -724,7 +782,9 @@ void sqlite3VdbeMakeReady( resizeOpArray(p, p->nOp); assert( nVar>=0 ); assert( nStack<p->nOp ); - nStack = isExplain ? 10 : nStack; + if( isExplain ){ + nStack = 10; + } p->aStack = sqliteMalloc( nStack*sizeof(p->aStack[0]) /* aStack */ + nArg*sizeof(Mem*) /* apArg */ @@ -733,7 +793,7 @@ void sqlite3VdbeMakeReady( + nMem*sizeof(Mem) /* aMem */ + nCursor*sizeof(Cursor*) /* apCsr */ ); - if( !sqlite3_malloc_failed ){ + if( !sqlite3MallocFailed() ){ p->aMem = &p->aStack[nStack]; p->nMem = nMem; p->aVar = &p->aMem[nMem]; @@ -777,6 +837,8 @@ void sqlite3VdbeMakeReady( p->explain |= isExplain; p->magic = VDBE_MAGIC_RUN; p->nChange = 0; + p->cacheCtr = 1; + p->minWriteFileFormat = 255; #ifdef VDBE_PROFILE { int i; @@ -792,7 +854,7 @@ void sqlite3VdbeMakeReady( ** Close a cursor and release all the resources that cursor happens ** to hold. */ -void sqlite3VdbeFreeCursor(Cursor *pCx){ +void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){ if( pCx==0 ){ return; } @@ -802,6 +864,17 @@ void sqlite3VdbeFreeCursor(Cursor *pCx){ if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); } +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( pCx->pVtabCursor ){ + sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor; + const sqlite3_module *pModule = pCx->pModule; + p->inVtabMethod = 1; + sqlite3SafetyOff(p->db); + pModule->xClose(pVtabCursor); + sqlite3SafetyOn(p->db); + p->inVtabMethod = 0; + } +#endif sqliteFree(pCx->pData); sqliteFree(pCx->aType); sqliteFree(pCx); @@ -814,8 +887,10 @@ static void closeAllCursors(Vdbe *p){ int i; if( p->apCsr==0 ) return; for(i=0; i<p->nCursor; i++){ - sqlite3VdbeFreeCursor(p->apCsr[i]); - p->apCsr[i] = 0; + if( !p->inVtabMethod || (p->apCsr[i] && !p->apCsr[i]->pVtabCursor) ){ + sqlite3VdbeFreeCursor(p, p->apCsr[i]); + p->apCsr[i] = 0; + } } } @@ -857,9 +932,10 @@ static void Cleanup(Vdbe *p){ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ Mem *pColName; int n; - assert( 0==p->nResColumn ); + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); + sqliteFree(p->aColName); + n = nResColumn*COLNAME_N; p->nResColumn = nResColumn; - n = nResColumn*2; p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n ); if( p->aColName==0 ) return; while( n-- > 0 ){ @@ -878,13 +954,14 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ ** the string is freed using sqliteFree() when the vdbe is finished with ** it. Otherwise, N bytes of zName are copied. */ -int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){ +int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){ int rc; Mem *pColName; - assert( idx<(2*p->nResColumn) ); - if( sqlite3_malloc_failed ) return SQLITE_NOMEM; + assert( idx<p->nResColumn ); + assert( var<COLNAME_N ); + if( sqlite3MallocFailed() ) return SQLITE_NOMEM; assert( p->aColName!=0 ); - pColName = &(p->aColName[idx]); + pColName = &(p->aColName[idx+var*p->nResColumn]); if( N==P3_DYNAMIC || N==P3_STATIC ){ rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC); }else{ @@ -909,6 +986,23 @@ static int vdbeCommit(sqlite3 *db){ int rc = SQLITE_OK; int needXcommit = 0; + /* Before doing anything else, call the xSync() callback for any + ** virtual module tables written in this transaction. This has to + ** be done before determining whether a master journal file is + ** required, as an xSync() callback may add an attached database + ** to the transaction. + */ + rc = sqlite3VtabSync(db, rc); + 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 + ** including the temp database. (b) is important because if more than + ** 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++){ Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeIsInTrans(pBt) ){ @@ -919,7 +1013,6 @@ static int vdbeCommit(sqlite3 *db){ /* If there are any write-transactions at all, invoke the commit hook */ if( needXcommit && db->xCommitCallback ){ - int rc; sqlite3SafetyOff(db); rc = db->xCommitCallback(db->pCommitArg); sqlite3SafetyOn(db); @@ -953,6 +1046,7 @@ static int vdbeCommit(sqlite3 *db){ sqlite3BtreeCommit(pBt); } } + sqlite3VtabCommit(db); } } @@ -965,7 +1059,7 @@ static int vdbeCommit(sqlite3 *db){ int needSync = 0; char *zMaster = 0; /* File-name for the master journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); - OsFile master; + OsFile *master = 0; /* Select a master journal file name */ do { @@ -979,7 +1073,6 @@ static int vdbeCommit(sqlite3 *db){ }while( sqlite3OsFileExists(zMaster) ); /* Open the master journal. */ - memset(&master, 0, sizeof(master)); rc = sqlite3OsOpenExclusive(zMaster, &master, 0); if( rc!=SQLITE_OK ){ sqliteFree(zMaster); @@ -1001,7 +1094,7 @@ static int vdbeCommit(sqlite3 *db){ if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){ needSync = 1; } - rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1); + rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1); if( rc!=SQLITE_OK ){ sqlite3OsClose(&master); sqlite3OsDelete(zMaster); @@ -1016,9 +1109,9 @@ static int vdbeCommit(sqlite3 *db){ ** the master journal file is store in so that it gets synced too. */ zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt); - rc = sqlite3OsOpenDirectory(zMainFile, &master); + rc = sqlite3OsOpenDirectory(master, zMainFile); if( rc!=SQLITE_OK || - (needSync && (rc=sqlite3OsSync(&master,0))!=SQLITE_OK) ){ + (needSync && (rc=sqlite3OsSync(master,0))!=SQLITE_OK) ){ sqlite3OsClose(&master); sqlite3OsDelete(zMaster); sqliteFree(zMaster); @@ -1035,18 +1128,17 @@ static int vdbeCommit(sqlite3 *db){ ** file name was written into the journal file before the failure ** occured. */ - for(i=0; i<db->nDb; i++){ + for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeIsInTrans(pBt) ){ rc = sqlite3BtreeSync(pBt, zMaster); - if( rc!=SQLITE_OK ){ - sqlite3OsClose(&master); - sqliteFree(zMaster); - return rc; - } } } sqlite3OsClose(&master); + if( rc!=SQLITE_OK ){ + sqliteFree(zMaster); + return rc; + } /* Delete the master journal file. This commits the transaction. After ** doing this the directory is synced again before any individual @@ -1081,29 +1173,13 @@ static int vdbeCommit(sqlite3 *db){ sqlite3BtreeCommit(pBt); } } + sqlite3VtabCommit(db); } #endif return rc; } -/* -** Find every active VM other than pVdbe and change its status to -** aborted. This happens when one VM causes a rollback due to an -** ON CONFLICT ROLLBACK clause (for example). The other VMs must be -** aborted so that they do not have data rolled out from underneath -** them leading to a segfault. -*/ -static void abortOtherActiveVdbes(Vdbe *pVdbe){ - Vdbe *pOther; - for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){ - if( pOther==pVdbe ) continue; - if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue; - closeAllCursors(pOther); - pOther->aborted = 1; - } -} - /* ** This routine checks that the sqlite3.activeVdbeCnt count variable ** matches the number of vdbe's in the list sqlite3.pVdbe that are @@ -1131,6 +1207,25 @@ static void checkActiveVdbeCnt(sqlite3 *db){ #endif /* +** Find every active VM other than pVdbe and change its status to +** aborted. This happens when one VM causes a rollback due to an +** ON CONFLICT ROLLBACK clause (for example). The other VMs must be +** aborted so that they do not have data rolled out from underneath +** them leading to a segfault. +*/ +void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){ + Vdbe *pOther; + for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){ + if( pOther==pExcept ) continue; + if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue; + checkActiveVdbeCnt(db); + closeAllCursors(pOther); + checkActiveVdbeCnt(db); + pOther->aborted = 1; + } +} + +/* ** This routine is called the when a VDBE tries to halt. If the VDBE ** has made changes and is in autocommit mode, then commit those ** changes. If a rollback is needed, then do the rollback. @@ -1146,73 +1241,174 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3 *db = p->db; int i; int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */ + int isSpecialError; /* Set to true if SQLITE_NOMEM or IOERR */ + + /* This function contains the logic that determines if a statement or + ** transaction will be committed or rolled back as a result of the + ** execution of this virtual machine. + ** + ** Special errors: + ** + ** If an SQLITE_NOMEM error has occured in a statement that writes to + ** the database, then either a statement or transaction must be rolled + ** back to ensure the tree-structures are in a consistent state. A + ** statement transaction is rolled back if one is open, otherwise the + ** entire transaction must be rolled back. + ** + ** If an SQLITE_IOERR error has occured in a statement that writes to + ** the database, then the entire transaction must be rolled back. The + ** I/O error may have caused garbage to be written to the journal + ** file. Were the transaction to continue and eventually be rolled + ** back that garbage might end up in the database file. + ** + ** In both of the above cases, the Vdbe.errorAction variable is + ** ignored. If the sqlite3.autoCommit flag is false and a transaction + ** is rolled back, it will be set to true. + ** + ** Other errors: + ** + ** No error: + ** + */ + if( sqlite3MallocFailed() ){ + p->rc = SQLITE_NOMEM; + } if( p->magic!=VDBE_MAGIC_RUN ){ /* Already halted. Nothing to do. */ assert( p->magic==VDBE_MAGIC_HALT ); +#ifndef SQLITE_OMIT_VIRTUALTABLE + closeAllCursors(p); +#endif return SQLITE_OK; } closeAllCursors(p); checkActiveVdbeCnt(db); - if( p->pc<0 ){ - /* No commit or rollback needed if the program never started */ - }else if( db->autoCommit && db->activeVdbeCnt==1 ){ - if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ - /* The auto-commit flag is true, there are no other active queries - ** using this handle and the vdbe program was successful or hit an - ** 'OR FAIL' constraint. This means a commit is required. + + /* No commit or rollback needed if the program never started */ + if( p->pc>=0 ){ + + /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */ + isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0); + if( isSpecialError ){ + /* This loop does static analysis of the query to see which of the + ** following three categories it falls into: + ** + ** Read-only + ** Query with statement journal + ** Query without statement journal + ** + ** We could do something more elegant than this static analysis (i.e. + ** store the type of query as part of the compliation phase), but + ** handling malloc() or IO failure is a fairly obscure edge case so + ** this is probably easier. Todo: Might be an opportunity to reduce + ** code size a very small amount though... */ - int rc = vdbeCommit(db); - if( rc==SQLITE_BUSY ){ - return SQLITE_BUSY; - }else if( rc!=SQLITE_OK ){ - p->rc = rc; - xFunc = sqlite3BtreeRollback; + int isReadOnly = 1; + int isStatement = 0; + assert(p->aOp || p->nOp==0); + for(i=0; i<p->nOp; i++){ + switch( p->aOp[i].opcode ){ + case OP_Transaction: + isReadOnly = 0; + break; + case OP_Statement: + isStatement = 1; + break; + } + } + + /* If the query was read-only, we need do no rollback at all. Otherwise, + ** proceed with the special handling. + */ + if( !isReadOnly ){ + if( p->rc==SQLITE_NOMEM && isStatement ){ + xFunc = sqlite3BtreeRollbackStmt; + }else{ + /* We are forced to roll back the active transaction. Before doing + ** so, abort any other statements this handle currently has active. + */ + sqlite3AbortOtherActiveVdbes(db, p); + sqlite3RollbackAll(db); + db->autoCommit = 1; + } } - }else{ - xFunc = sqlite3BtreeRollback; } - }else{ - if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ - xFunc = sqlite3BtreeCommitStmt; - }else if( p->errorAction==OE_Abort ){ - xFunc = sqlite3BtreeRollbackStmt; - }else{ - xFunc = sqlite3BtreeRollback; - db->autoCommit = 1; - abortOtherActiveVdbes(p); + + /* If the auto-commit flag is set and this is the only active vdbe, then + ** we do either a commit or rollback of the current transaction. + ** + ** Note: This block also runs if one of the special errors handled + ** above has occured. + */ + if( db->autoCommit && db->activeVdbeCnt==1 ){ + 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. + */ + int rc = vdbeCommit(db); + if( rc==SQLITE_BUSY ){ + return SQLITE_BUSY; + }else if( rc!=SQLITE_OK ){ + p->rc = rc; + sqlite3RollbackAll(db); + }else{ + sqlite3CommitInternalChanges(db); + } + }else{ + sqlite3RollbackAll(db); + } + }else if( !xFunc ){ + if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ + xFunc = sqlite3BtreeCommitStmt; + }else if( p->errorAction==OE_Abort ){ + xFunc = sqlite3BtreeRollbackStmt; + }else{ + sqlite3AbortOtherActiveVdbes(db, p); + sqlite3RollbackAll(db); + db->autoCommit = 1; + } } - } - - /* If xFunc is not NULL, then it is one of sqlite3BtreeRollback, - ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on - ** each backend. If an error occurs and the return code is still - ** SQLITE_OK, set the return code to the new error value. - */ - for(i=0; xFunc && i<db->nDb; i++){ - int rc; - Btree *pBt = db->aDb[i].pBt; - if( pBt ){ - rc = xFunc(pBt); - if( p->rc==SQLITE_OK ) p->rc = rc; + + /* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or + ** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs + ** and the return code is still SQLITE_OK, set the return code to the new + ** error value. + */ + assert(!xFunc || + xFunc==sqlite3BtreeCommitStmt || + xFunc==sqlite3BtreeRollbackStmt + ); + for(i=0; xFunc && i<db->nDb; i++){ + int rc; + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + rc = xFunc(pBt); + if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){ + p->rc = rc; + sqlite3SetString(&p->zErrMsg, 0); + } + } } - } - - /* If this was an INSERT, UPDATE or DELETE, set the change counter. */ - if( p->changeCntOn && p->pc>=0 ){ - if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){ - sqlite3VdbeSetChanges(db, p->nChange); - }else{ - sqlite3VdbeSetChanges(db, 0); + + /* If this was an INSERT, UPDATE or DELETE and the statement was committed, + ** set the change counter. + */ + if( p->changeCntOn && p->pc>=0 ){ + if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){ + sqlite3VdbeSetChanges(db, p->nChange); + }else{ + sqlite3VdbeSetChanges(db, 0); + } + p->nChange = 0; + } + + /* Rollback or commit any schema changes that occurred. */ + if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){ + sqlite3ResetInternalSchema(db, 0); + db->flags = (db->flags | SQLITE_InternChanges); } - p->nChange = 0; - } - - /* Rollback or commit any schema changes that occurred. */ - if( p->rc!=SQLITE_OK ){ - sqlite3RollbackInternalChanges(db); - }else if( db->flags & SQLITE_InternChanges ){ - sqlite3CommitInternalChanges(db); } /* We have successfully halted and closed the VM. Record this fact. */ @@ -1246,7 +1442,9 @@ int sqlite3VdbeReset(Vdbe *p){ ** error, then it might not have been halted properly. So halt ** it now. */ + sqlite3SafetyOn(p->db); sqlite3VdbeHalt(p); + sqlite3SafetyOff(p->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 @@ -1255,8 +1453,9 @@ int sqlite3VdbeReset(Vdbe *p){ */ if( p->pc>=0 ){ if( p->zErrMsg ){ - sqlite3Error(p->db, p->rc, "%s", p->zErrMsg); - sqliteFree(p->zErrMsg); + sqlite3* db = p->db; + sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX); + db->errCode = p->rc; p->zErrMsg = 0; }else if( p->rc ){ sqlite3Error(p->db, p->rc, 0); @@ -1277,7 +1476,7 @@ int sqlite3VdbeReset(Vdbe *p){ /* Save profiling information from this VDBE run. */ - assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 ); + assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || !p->aStack ); #ifdef VDBE_PROFILE { FILE *out = fopen("vdbe_profile.out", "a"); @@ -1314,7 +1513,6 @@ int sqlite3VdbeReset(Vdbe *p){ */ int sqlite3VdbeFinalize(Vdbe *p){ int rc = SQLITE_OK; - if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){ rc = sqlite3VdbeReset(p); }else if( p->magic!=VDBE_MAGIC_INIT ){ @@ -1369,7 +1567,7 @@ void sqlite3VdbeDelete(Vdbe *p){ releaseMemArray(p->aVar, p->nVar); sqliteFree(p->aLabel); sqliteFree(p->aStack); - releaseMemArray(p->aColName, p->nResColumn*2); + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); sqliteFree(p->aColName); p->magic = VDBE_MAGIC_DEAD; sqliteFree(p); @@ -1383,7 +1581,9 @@ void sqlite3VdbeDelete(Vdbe *p){ int sqlite3VdbeCursorMoveto(Cursor *p){ if( p->deferredMoveto ){ int res, rc; +#ifdef SQLITE_TEST extern int sqlite3_search_count; +#endif assert( p->isTable ); if( p->isTable ){ rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res); @@ -1399,9 +1599,11 @@ int sqlite3VdbeCursorMoveto(Cursor *p){ rc = sqlite3BtreeNext(p->pCursor, &res); if( rc ) return rc; } +#ifdef SQLITE_TEST sqlite3_search_count++; +#endif p->deferredMoveto = 0; - p->cacheValid = 0; + p->cacheStatus = CACHE_STALE; } return SQLITE_OK; } @@ -1438,16 +1640,20 @@ int sqlite3VdbeCursorMoveto(Cursor *p){ ** 5 6 signed integer ** 6 8 signed integer ** 7 8 IEEE float -** 8-11 reserved for expansion +** 8 0 Integer constant 0 +** 9 0 Integer constant 1 +** 10,11 reserved for expansion ** N>=12 and even (N-12)/2 BLOB ** N>=13 and odd (N-13)/2 text ** +** The 8 and 9 types were added in 3.3.0, file format 4. Prior versions +** of SQLite will not understand those serial types. */ /* ** Return the serial-type for the value stored in pMem. */ -u32 sqlite3VdbeSerialType(Mem *pMem){ +u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ int flags = pMem->flags; if( flags&MEM_Null ){ @@ -1457,7 +1663,11 @@ u32 sqlite3VdbeSerialType(Mem *pMem){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ # define MAX_6BYTE ((((i64)0x00001000)<<32)-1) i64 i = pMem->i; - u64 u = i<0 ? -i : i; + u64 u; + if( file_format>=4 && (i&1)==i ){ + return 8+i; + } + u = i<0 ? -i : i; if( u<=127 ) return 1; if( u<=32767 ) return 2; if( u<=8388607 ) return 3; @@ -1496,17 +1706,12 @@ int sqlite3VdbeSerialTypeLen(u32 serial_type){ ** buf. It is assumed that the caller has allocated sufficient space. ** Return the number of bytes written. */ -int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem){ - u32 serial_type = sqlite3VdbeSerialType(pMem); +int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){ + u32 serial_type = sqlite3VdbeSerialType(pMem, file_format); int len; - /* NULL */ - if( serial_type==0 ){ - return 0; - } - /* Integer and Real */ - if( serial_type<=7 ){ + if( serial_type<=7 && serial_type>0 ){ u64 v; int i; if( serial_type==7 ){ @@ -1521,12 +1726,16 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem){ } return len; } - + /* String or blob */ - assert( serial_type>=12 ); - len = sqlite3VdbeSerialTypeLen(serial_type); - memcpy(buf, pMem->z, len); - return len; + if( serial_type>=12 ){ + len = sqlite3VdbeSerialTypeLen(serial_type); + memcpy(buf, pMem->z, len); + return len; + } + + /* NULL or constants 0 or 1 */ + return 0; } /* @@ -1539,8 +1748,6 @@ int sqlite3VdbeSerialGet( Mem *pMem /* Memory cell to write value into */ ){ switch( serial_type ){ - case 8: /* Reserved for future use */ - case 9: /* Reserved for future use */ case 10: /* Reserved for future use */ case 11: /* Reserved for future use */ case 0: { /* NULL */ @@ -1579,7 +1786,7 @@ int sqlite3VdbeSerialGet( case 7: { /* IEEE floating point */ u64 x; u32 y; -#ifndef NDEBUG +#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) /* Verify that integers and floating point values use the same ** byte order. The byte order differs on some (broken) architectures. */ @@ -1599,6 +1806,12 @@ int sqlite3VdbeSerialGet( } return 8; } + case 8: /* Integer 0 */ + case 9: { /* Integer 1 */ + pMem->i = serial_type-8; + pMem->flags = MEM_Int; + return 0; + } default: { int len = (serial_type-12)/2; pMem->z = (char *)buf; @@ -1616,6 +1829,23 @@ int sqlite3VdbeSerialGet( } /* +** The header of a record consists of a sequence variable-length integers. +** These integers are almost always small and are encoded as a single byte. +** The following macro takes advantage this fact to provide a fast decode +** of the integers in a record header. It is faster for the common case +** where the integer is a single byte. It is a little slower when the +** integer is two or more bytes. But overall it is faster. +** +** The following expressions are equivalent: +** +** x = sqlite3GetVarint32( A, &B ); +** +** x = GetVarint( A, B ); +** +*/ +#define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B)) + +/* ** This function compares the two table rows or index records specified by ** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero ** or positive integer if {nKey1, pKey1} is less than, equal to or @@ -1642,9 +1872,9 @@ int sqlite3VdbeRecordCompare( mem1.enc = pKeyInfo->enc; mem2.enc = pKeyInfo->enc; - idx1 = sqlite3GetVarint32(pKey1, &szHdr1); + idx1 = GetVarint(aKey1, szHdr1); d1 = szHdr1; - idx2 = sqlite3GetVarint32(pKey2, &szHdr2); + idx2 = GetVarint(aKey2, szHdr2); d2 = szHdr2; nField = pKeyInfo->nField; while( idx1<szHdr1 && idx2<szHdr2 ){ @@ -1652,9 +1882,9 @@ int sqlite3VdbeRecordCompare( u32 serial_type2; /* Read the serial types for the next element in each key. */ - idx1 += sqlite3GetVarint32(&aKey1[idx1], &serial_type1); + idx1 += GetVarint( aKey1+idx1, serial_type1 ); if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break; - idx2 += sqlite3GetVarint32(&aKey2[idx2], &serial_type2); + idx2 += GetVarint( aKey2+idx2, serial_type2 ); if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break; /* Assert that there is enough space left in each key for the blob of @@ -1686,9 +1916,8 @@ int sqlite3VdbeRecordCompare( }else if( d2<nKey2 ){ rc = -1; } - } - - if( pKeyInfo->aSortOrder && i<pKeyInfo->nField && pKeyInfo->aSortOrder[i] ){ + }else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField + && pKeyInfo->aSortOrder[i] ){ rc = -rc; } @@ -1701,7 +1930,7 @@ int sqlite3VdbeRecordCompare( ** an integer rowid). This routine returns the number of bytes in ** that integer. */ -int sqlite3VdbeIdxRowidLen(int nKey, const u8 *aKey){ +int sqlite3VdbeIdxRowidLen(const u8 *aKey){ u32 szHdr; /* Size of the header */ u32 typeRowid; /* Serial type of the rowid */ @@ -1732,10 +1961,10 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ if( rc ){ return rc; } - sqlite3GetVarint32(m.z, &szHdr); - sqlite3GetVarint32(&m.z[szHdr-1], &typeRowid); + sqlite3GetVarint32((u8*)m.z, &szHdr); + sqlite3GetVarint32((u8*)&m.z[szHdr-1], &typeRowid); lenRowid = sqlite3VdbeSerialTypeLen(typeRowid); - sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v); + sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v); *rowid = v.i; sqlite3VdbeMemRelease(&m); return SQLITE_OK; @@ -1771,7 +2000,7 @@ int sqlite3VdbeIdxKeyCompare( if( rc ){ return rc; } - lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z); + lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z); *res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey); sqlite3VdbeMemRelease(&m); return SQLITE_OK; |