diff options
author | dan <dan@noemail.net> | 2018-06-04 08:28:18 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2018-06-04 08:28:18 +0000 |
commit | 2b1287cf4443e040662a16667bb024f948e51c17 (patch) | |
tree | 10151f634a4b704038fdabb24a6b813990d61cb8 /src | |
parent | f1abe3680e04cc0f5c9eed7a9e6b47093a490beb (diff) | |
parent | eb7df46e3203bb1fe1cfbd1c42c3af1a26a6ce6d (diff) | |
download | sqlite-2b1287cf4443e040662a16667bb024f948e51c17.tar.gz sqlite-2b1287cf4443e040662a16667bb024f948e51c17.zip |
Merge latest trunk changes into this branch.
FossilOrigin-Name: 83d6416a868fac81a78c9507185a48d00920e4322276245e285946f760915f4a
Diffstat (limited to 'src')
-rw-r--r-- | src/auth.c | 2 | ||||
-rw-r--r-- | src/btree.c | 6 | ||||
-rw-r--r-- | src/build.c | 6 | ||||
-rw-r--r-- | src/callback.c | 2 | ||||
-rw-r--r-- | src/expr.c | 2 | ||||
-rw-r--r-- | src/fkey.c | 7 | ||||
-rw-r--r-- | src/insert.c | 8 | ||||
-rw-r--r-- | src/main.c | 43 | ||||
-rw-r--r-- | src/os_unix.c | 2 | ||||
-rw-r--r-- | src/parse.y | 2 | ||||
-rw-r--r-- | src/printf.c | 2 | ||||
-rw-r--r-- | src/resolve.c | 47 | ||||
-rw-r--r-- | src/select.c | 2 | ||||
-rw-r--r-- | src/shell.c.in | 2 | ||||
-rw-r--r-- | src/sqlite.h.in | 6 | ||||
-rw-r--r-- | src/sqliteInt.h | 2 | ||||
-rw-r--r-- | src/upsert.c | 1 | ||||
-rw-r--r-- | src/vdbe.c | 45 | ||||
-rw-r--r-- | src/vdbe.h | 5 | ||||
-rw-r--r-- | src/vdbeInt.h | 9 | ||||
-rw-r--r-- | src/vdbeapi.c | 22 | ||||
-rw-r--r-- | src/vdbeaux.c | 40 | ||||
-rw-r--r-- | src/vdbemem.c | 2 | ||||
-rw-r--r-- | src/vtab.c | 23 |
24 files changed, 208 insertions, 80 deletions
diff --git a/src/auth.c b/src/auth.c index 7d6f851d8..03e4cf9f5 100644 --- a/src/auth.c +++ b/src/auth.c @@ -150,6 +150,7 @@ void sqlite3AuthRead( int iDb; /* The index of the database the expression refers to */ int iCol; /* Index of column in table */ + assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); if( db->xAuth==0 ) return; iDb = sqlite3SchemaToIndex(pParse->db, pSchema); if( iDb<0 ){ @@ -158,7 +159,6 @@ void sqlite3AuthRead( return; } - assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); if( pExpr->op==TK_TRIGGER ){ pTab = pParse->pTriggerTab; }else{ diff --git a/src/btree.c b/src/btree.c index 316fa701d..0971575dc 100644 --- a/src/btree.c +++ b/src/btree.c @@ -864,7 +864,11 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ ** back to where it ought to be if this routine returns true. */ int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ - return pCur->eState!=CURSOR_VALID; + assert( EIGHT_BYTE_ALIGNMENT(pCur) + || pCur==sqlite3BtreeFakeValidCursor() ); + assert( offsetof(BtCursor, eState)==0 ); + assert( sizeof(pCur->eState)==1 ); + return CURSOR_VALID != *(u8*)pCur; } /* diff --git a/src/build.c b/src/build.c index d0cb0062e..3d982f72e 100644 --- a/src/build.c +++ b/src/build.c @@ -2843,6 +2843,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v); regRecord = sqlite3GetTempReg(pParse); + sqlite3MultiWrite(pParse); sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); @@ -2856,12 +2857,13 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); if( IsUniqueIndex(pIndex) ){ - int j2 = sqlite3VdbeCurrentAddr(v) + 3; - sqlite3VdbeGoto(v, j2); + int j2 = sqlite3VdbeGoto(v, 1); addr2 = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); + sqlite3VdbeJumpHere(v, j2); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } diff --git a/src/callback.c b/src/callback.c index 0396df7a0..a629b6825 100644 --- a/src/callback.c +++ b/src/callback.c @@ -406,10 +406,12 @@ FuncDef *sqlite3FindFunction( if( createFlag && bestScore<FUNC_PERFECT_MATCH && (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){ FuncDef *pOther; + u8 *z; pBest->zName = (const char*)&pBest[1]; pBest->nArg = (u16)nArg; pBest->funcFlags = enc; memcpy((char*)&pBest[1], zName, nName+1); + for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z]; pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest); if( pOther==pBest ){ sqlite3DbFree(db, pBest); diff --git a/src/expr.c b/src/expr.c index 81aa66f69..54e9ced00 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4026,7 +4026,7 @@ expr_code_doover: case TK_COLLATE: case TK_UPLUS: { pExpr = pExpr->pLeft; - goto expr_code_doover; + goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. OSSFuzz. */ } case TK_TRIGGER: { diff --git a/src/fkey.c b/src/fkey.c index c366c1b3a..256b19db8 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -331,6 +331,12 @@ static void fkLookupParent( int iCur = pParse->nTab - 1; /* Cursor number to use */ int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */ + sqlite3VdbeVerifyAbortable(v, + (!pFKey->isDeferred + && !(pParse->db->flags & SQLITE_DeferFKs) + && !pParse->pToplevel + && !pParse->isMultiWrite) ? OE_Abort : OE_Ignore); + /* If nIncr is less than zero, then check at runtime if there are any ** outstanding constraints to resolve. If there are not, there is no need ** to check if deleting this row resolves any outstanding violations. @@ -738,6 +744,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ ** constraints are violated. */ if( (db->flags & SQLITE_DeferFKs)==0 ){ + sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, diff --git a/src/insert.c b/src/insert.c index 76293c601..3d5164283 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1420,6 +1420,7 @@ void sqlite3GenerateConstraintChecks( Expr *pExpr = pCheck->a[i].pExpr; if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue; allOk = sqlite3VdbeMakeLabel(v); + sqlite3VdbeVerifyAbortable(v, onError); sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL); if( onError==OE_Ignore ){ sqlite3VdbeGoto(v, ignoreDest); @@ -1529,6 +1530,7 @@ void sqlite3GenerateConstraintChecks( /* Check to see if the new rowid already exists in the table. Skip ** the following conflict logic if it does not. */ VdbeNoopComment((v, "uniqueness check for ROWID")); + sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); @@ -1741,6 +1743,7 @@ void sqlite3GenerateConstraintChecks( /* Check to see if the new index entry will be unique */ sqlite3ExprCachePush(pParse); + sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, regIdx, pIdx->nKeyCol); VdbeCoverage(v); @@ -1827,10 +1830,12 @@ void sqlite3GenerateConstraintChecks( default: { Trigger *pTrigger = 0; assert( onError==OE_Replace ); - sqlite3MultiWrite(pParse); if( db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); } + if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ + sqlite3MultiWrite(pParse); + } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); @@ -2350,6 +2355,7 @@ static int xferOptimization( emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); + sqlite3VdbeVerifyAbortable(v, onError); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); VdbeCoverage(v); sqlite3RowidConstraint(pParse, onError, pDest); diff --git a/src/main.c b/src/main.c index d23f9afcf..8e89cc553 100644 --- a/src/main.c +++ b/src/main.c @@ -1808,11 +1808,13 @@ int sqlite3_create_function_v2( #endif sqlite3_mutex_enter(db->mutex); if( xDestroy ){ - pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor)); + pArg = (FuncDestructor *)sqlite3Malloc(sizeof(FuncDestructor)); if( !pArg ){ + sqlite3OomFault(db); xDestroy(p); goto out; } + pArg->nRef = 0; pArg->xDestroy = xDestroy; pArg->pUserData = p; } @@ -1820,7 +1822,7 @@ int sqlite3_create_function_v2( if( pArg && pArg->nRef==0 ){ assert( rc!=SQLITE_OK ); xDestroy(p); - sqlite3DbFree(db, pArg); + sqlite3_free(pArg); } out: @@ -1859,6 +1861,28 @@ int sqlite3_create_function16( /* +** The following is the implementation of an SQL function that always +** fails with an error message stating that the function is used in the +** wrong context. The sqlite3_overload_function() API might construct +** SQL function that use this routine so that the functions will exist +** for name resolution but are actually overloaded by the xFindFunction +** method of virtual tables. +*/ +static void sqlite3InvalidFunction( + sqlite3_context *context, /* The function calling context */ + int NotUsed, /* Number of arguments to the function */ + sqlite3_value **NotUsed2 /* Value of each argument */ +){ + const char *zName = (const char*)sqlite3_user_data(context); + char *zErr; + UNUSED_PARAMETER2(NotUsed, NotUsed2); + zErr = sqlite3_mprintf( + "unable to use function %s in the requested context", zName); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); +} + +/* ** Declare that a function has been overloaded by a virtual table. ** ** If the function already exists as a regular global function, then @@ -1875,7 +1899,8 @@ int sqlite3_overload_function( const char *zName, int nArg ){ - int rc = SQLITE_OK; + int rc; + char *zCopy; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){ @@ -1883,13 +1908,13 @@ int sqlite3_overload_function( } #endif sqlite3_mutex_enter(db->mutex); - if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){ - rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, - 0, sqlite3InvalidFunction, 0, 0, 0); - } - rc = sqlite3ApiExit(db, rc); + rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0; sqlite3_mutex_leave(db->mutex); - return rc; + if( rc ) return SQLITE_OK; + zCopy = sqlite3_mprintf(zName); + if( zCopy==0 ) return SQLITE_NOMEM; + return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8, + zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free); } #ifndef SQLITE_OMIT_TRACE diff --git a/src/os_unix.c b/src/os_unix.c index 2b9c117e3..0dd461da0 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3779,7 +3779,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ do{ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); }while( err==EINTR ); - if( err ) return SQLITE_IOERR_WRITE; + if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; #else /* If the OS does not have posix_fallocate(), fake it. Write a ** single byte to the last byte in each block that falls entirely diff --git a/src/parse.y b/src/parse.y index a997ea401..e52991d67 100644 --- a/src/parse.y +++ b/src/parse.y @@ -469,6 +469,7 @@ cmd ::= select(X). { } } +%ifndef SQLITE_OMIT_CTE select(A) ::= WITH wqlist(W) selectnowith(X). { Select *p = X; if( p ){ @@ -489,6 +490,7 @@ select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X). { } A = p; } +%endif /* SQLITE_OMIT_CTE */ select(A) ::= selectnowith(X). { Select *p = X; if( p ){ diff --git a/src/printf.c b/src/printf.c index d412e5ee2..71296ac90 100644 --- a/src/printf.c +++ b/src/printf.c @@ -974,7 +974,7 @@ char *sqlite3StrAccumFinish(StrAccum *p){ ** an SQLITE_NOMEM error. */ static sqlite3_str sqlite3OomStr = { - 0, 0, 0, 0, 0, SQLITE_NOMEM + 0, 0, 0, 0, 0, SQLITE_NOMEM, 0 }; /* Finalize a string created using sqlite3_str_new(). diff --git a/src/resolve.c b/src/resolve.c index 84baf01ab..47f22a971 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -75,29 +75,31 @@ static void resolveAlias( assert( pOrig!=0 ); db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); - if( pDup==0 ) return; - if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery); - if( pExpr->op==TK_COLLATE ){ - pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); - } - ExprSetProperty(pDup, EP_Alias); - - /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This - ** prevents ExprDelete() from deleting the Expr structure itself, - ** allowing it to be repopulated by the memcpy() on the following line. - ** The pExpr->u.zToken might point into memory that will be freed by the - ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to - ** make a copy of the token before doing the sqlite3DbFree(). - */ - ExprSetProperty(pExpr, EP_Static); - sqlite3ExprDelete(db, pExpr); - memcpy(pExpr, pDup, sizeof(*pExpr)); - if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ - assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); - pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); - pExpr->flags |= EP_MemToken; + if( pDup!=0 ){ + if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery); + if( pExpr->op==TK_COLLATE ){ + pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); + } + ExprSetProperty(pDup, EP_Alias); + + /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This + ** prevents ExprDelete() from deleting the Expr structure itself, + ** allowing it to be repopulated by the memcpy() on the following line. + ** The pExpr->u.zToken might point into memory that will be freed by the + ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to + ** make a copy of the token before doing the sqlite3DbFree(). + */ + ExprSetProperty(pExpr, EP_Static); + sqlite3ExprDelete(db, pExpr); + memcpy(pExpr, pDup, sizeof(*pExpr)); + if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ + assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); + pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); + pExpr->flags |= EP_MemToken; + } + sqlite3DbFree(db, pDup); } - sqlite3DbFree(db, pDup); + ExprSetProperty(pExpr, EP_Alias); } @@ -349,6 +351,7 @@ static int lookupName( testcase( iCol==(-1) ); pExpr->iTable = pNC->uNC.pUpsert->regData + iCol; eNewExprOp = TK_REGISTER; + ExprSetProperty(pExpr, EP_Alias); }else #endif /* SQLITE_OMIT_UPSERT */ { diff --git a/src/select.c b/src/select.c index d255aaa7a..cf1034bb6 100644 --- a/src/select.c +++ b/src/select.c @@ -810,7 +810,7 @@ static void selectExprDefer( if( pItem->u.x.iOrderByCol==0 ){ Expr *pExpr = pItem->pExpr; Table *pTab = pExpr->pTab; - if( pExpr->op==TK_COLUMN && pTab && !IsVirtual(pTab) + if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab) && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF) ){ int j; diff --git a/src/shell.c.in b/src/shell.c.in index e7cc36f47..b9d7cecbc 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -8243,7 +8243,7 @@ static void usage(int showDetail){ */ static void verify_uninitialized(void){ if( sqlite3_config(-1)==SQLITE_MISUSE ){ - utf8_printf(stdout, "WARNING: attempt to configuration SQLite after" + utf8_printf(stdout, "WARNING: attempt to configure SQLite after" " initialization.\n"); } } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index db2619ef5..3d2effa5b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6294,6 +6294,10 @@ struct sqlite3_index_info { /* ** CAPI3REF: Virtual Table Scan Flags +** +** Virtual table implementations are allowed to set the +** [sqlite3_index_info].idxFlags field to some combination of +** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ @@ -9034,7 +9038,7 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same ** values of D and S. ** The size of the database is written into *P even if the -** SQLITE_SERIALIZE_NOCOPY bit is set but no contigious copy +** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5826342de..e3c3c17ca 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4225,6 +4225,7 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*), FuncDestructor *pDestructor ); +void sqlite3NoopDestructor(void*); void sqlite3OomFault(sqlite3*); void sqlite3OomClear(sqlite3*); int sqlite3ApiExit(sqlite3 *db, int); @@ -4327,7 +4328,6 @@ int sqlite3VtabCallConnect(Parse*, Table*); int sqlite3VtabCallDestroy(sqlite3*, int, const char *); int sqlite3VtabBegin(sqlite3 *, VTable *); FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); -void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); diff --git a/src/upsert.c b/src/upsert.c index 764957ebb..31a905dd6 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -229,6 +229,7 @@ void sqlite3UpsertDoUpdate( VdbeComment((v, "%s.%s", pIdx->zName, pTab->aCol[pPk->aiColumn[i]].zName)); } + sqlite3VdbeVerifyAbortable(v, OE_Abort); i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0, diff --git a/src/vdbe.c b/src/vdbe.c index c2111b46f..ef5c0a163 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -915,6 +915,9 @@ case OP_Yield: { /* in1, jump */ */ case OP_HaltIfNull: { /* in3 */ pIn3 = &aMem[pOp->p3]; +#ifdef SQLITE_DEBUG + if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } +#endif if( (pIn3->flags & MEM_Null)==0 ) break; /* Fall through into OP_Halt */ } @@ -954,6 +957,9 @@ case OP_Halt: { int pcx; pcx = (int)(pOp - aOp); +#ifdef SQLITE_DEBUG + if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } +#endif if( pOp->p1==SQLITE_OK && p->pFrame ){ /* Halt the sub-program. Return control to the parent frame. */ pFrame = p->pFrame; @@ -3324,6 +3330,8 @@ case OP_ReadCookie: { /* out2 */ */ case OP_SetCookie: { Db *pDb; + + sqlite3VdbeIncrWriteCounter(p, 0); assert( pOp->p2<SQLITE_N_BTREE_META ); assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); @@ -4457,6 +4465,7 @@ case OP_InsertInt: { assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable ); assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC ); REGISTER_TRACE(pOp->p2, pData); + sqlite3VdbeIncrWriteCounter(p, pC); if( pOp->opcode==OP_Insert ){ pKey = &aMem[pOp->p3]; @@ -4571,6 +4580,7 @@ case OP_Delete: { assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->deferredMoveto==0 ); + sqlite3VdbeIncrWriteCounter(p, pC); #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ @@ -4739,10 +4749,10 @@ case OP_SorterData: { ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. ** -** If P3!=0 then this opcode is allowed to make an ephermeral pointer +** If P3!=0 then this opcode is allowed to make an ephemeral pointer ** into the database page. That means that the content of the output ** register will be invalidated as soon as the cursor moves - including -** moves caused by other cursors that "save" the the current cursors +** moves caused by other cursors that "save" the current cursors ** position in order that they can write to the same table. If P3==0 ** then a copy of the data is made into memory. P3!=0 is faster, but ** P3==0 is safer. @@ -5190,6 +5200,7 @@ case OP_IdxInsert: { /* in2 */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; + sqlite3VdbeIncrWriteCounter(p, pC); assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) ); pIn2 = &aMem[pOp->p2]; @@ -5236,6 +5247,7 @@ case OP_IdxDelete: { pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); + sqlite3VdbeIncrWriteCounter(p, pC); pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); assert( pOp->p5==0 ); @@ -5458,6 +5470,7 @@ case OP_Destroy: { /* out2 */ int iMoved; int iDb; + sqlite3VdbeIncrWriteCounter(p, 0); assert( p->readOnly==0 ); assert( pOp->p1>1 ); pOut = out2Prerelease(p, pOp); @@ -5507,6 +5520,7 @@ case OP_Destroy: { /* out2 */ case OP_Clear: { int nChange; + sqlite3VdbeIncrWriteCounter(p, 0); nChange = 0; assert( p->readOnly==0 ); assert( DbMaskTest(p->btreeMask, pOp->p2) ); @@ -5556,13 +5570,14 @@ case OP_ResetSorter: { ** Allocate a new b-tree in the main database file if P1==0 or in the ** TEMP database file if P1==1 or in an attached database if ** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table -** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table. +** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table. ** The root page number of the new b-tree is stored in register P2. */ case OP_CreateBtree: { /* out2 */ int pgno; Db *pDb; + sqlite3VdbeIncrWriteCounter(p, 0); pOut = out2Prerelease(p, pOp); pgno = 0; assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY ); @@ -5582,6 +5597,7 @@ case OP_CreateBtree: { /* out2 */ ** Run the SQL statement or statements specified in the P4 string. */ case OP_SqlExec: { + sqlite3VdbeIncrWriteCounter(p, 0); db->nSqlExec++; rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0); db->nSqlExec--; @@ -5671,6 +5687,7 @@ case OP_LoadAnalysis: { ** schema consistent with what is on disk. */ case OP_DropTable: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z); break; } @@ -5684,6 +5701,7 @@ case OP_DropTable: { ** schema consistent with what is on disk. */ case OP_DropIndex: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z); break; } @@ -5697,6 +5715,7 @@ case OP_DropIndex: { ** schema consistent with what is on disk. */ case OP_DropTrigger: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z); break; } @@ -6911,6 +6930,7 @@ case OP_VUpdate: { || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace ); assert( p->readOnly==0 ); + sqlite3VdbeIncrWriteCounter(p, 0); pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; @@ -7228,6 +7248,22 @@ case OP_CursorHint: { } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ +#ifdef SQLITE_DEBUG +/* Opcode: Abortable * * * * * +** +** Verify that an Abort can happen. Assert if an Abort at this point +** might cause database corruption. This opcode only appears in debugging +** builds. +** +** An Abort is safe if either there have been no writes, or if there is +** an active statement journal. +*/ +case OP_Abortable: { + sqlite3VdbeAssertAbortable(p); + break; +} +#endif + /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump @@ -7239,8 +7275,9 @@ case OP_CursorHint: { ** This opcode records information from the optimizer. It is the ** the same as a no-op. This opcodesnever appears in a real VM program. */ -default: { /* This is really OP_Noop and OP_Explain */ +default: { /* This is really OP_Noop, OP_Explain */ assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain ); + break; } diff --git a/src/vdbe.h b/src/vdbe.h index 3177570a0..51bbdf96c 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -197,6 +197,11 @@ void sqlite3VdbeEndCoroutine(Vdbe*,int); # define sqlite3VdbeVerifyNoMallocRequired(A,B) # define sqlite3VdbeVerifyNoResultRow(A) #endif +#if defined(SQLITE_DEBUG) + void sqlite3VdbeVerifyAbortable(Vdbe *p, int); +#else +# define sqlite3VdbeVerifyAbortable(A,B) +#endif VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); #ifndef SQLITE_OMIT_EXPLAIN void sqlite3VdbeExplain(Parse*,u8,const char*,...); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 24d6bf91d..aaa935682 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -379,6 +379,7 @@ struct Vdbe { int nOp; /* Number of instructions in the program */ #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ + u32 nWrite; /* Number of write operations that have occurred */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ @@ -515,6 +516,14 @@ int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); +#ifdef SQLITE_DEBUG + void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*); + void sqlite3VdbeAssertAbortable(Vdbe*); +#else +# define sqlite3VdbeIncrWriteCounter(V,C) +# define sqlite3VdbeAssertAbortable(V) +#endif + #if !defined(SQLITE_OMIT_SHARED_CACHE) void sqlite3VdbeEnter(Vdbe*); #else diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 2a6e1f8f0..ced3e9014 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -788,28 +788,6 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ } /* -** The following is the implementation of an SQL function that always -** fails with an error message stating that the function is used in the -** wrong context. The sqlite3_overload_function() API might construct -** SQL function that use this routine so that the functions will exist -** for name resolution but are actually overloaded by the xFindFunction -** method of virtual tables. -*/ -void sqlite3InvalidFunction( - sqlite3_context *context, /* The function calling context */ - int NotUsed, /* Number of arguments to the function */ - sqlite3_value **NotUsed2 /* Value of each argument */ -){ - const char *zName = context->pFunc->zName; - char *zErr; - UNUSED_PARAMETER2(NotUsed, NotUsed2); - zErr = sqlite3_mprintf( - "unable to use function %s in the requested context", zName); - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); -} - -/* ** Create a new aggregate context for p and return a pointer to ** its pMem->z element. */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 4b0764751..38ef85f0e 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -603,6 +603,32 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ +#ifdef SQLITE_DEBUG +/* +** Increment the nWrite counter in the VDBE if the cursor is not an +** ephemeral cursor, or if the cursor argument is NULL. +*/ +void sqlite3VdbeIncrWriteCounter(Vdbe *p, VdbeCursor *pC){ + if( pC==0 + || (pC->eCurType!=CURTYPE_SORTER + && pC->eCurType!=CURTYPE_PSEUDO + && !pC->isEphemeral) + ){ + p->nWrite++; + } +} +#endif + +#ifdef SQLITE_DEBUG +/* +** Assert if an Abort at this point in time might result in a corrupt +** database. +*/ +void sqlite3VdbeAssertAbortable(Vdbe *p){ + assert( p->nWrite==0 || p->usesStmtJournal ); +} +#endif + /* ** This routine is called after all opcodes have been inserted. It loops ** through all the opcodes and fixes up some details. @@ -763,6 +789,17 @@ void sqlite3VdbeVerifyNoResultRow(Vdbe *p){ #endif /* +** Generate code (a single OP_Abortable opcode) that will +** verify that the VDBE program can safely call Abort in the current +** context. +*/ +#if defined(SQLITE_DEBUG) +void sqlite3VdbeVerifyAbortable(Vdbe *p, int onError){ + if( onError==OE_Abort ) sqlite3VdbeAddOp0(p, OP_Abortable); +} +#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 @@ -2995,6 +3032,9 @@ int sqlite3VdbeReset(Vdbe *p){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; p->pResultSet = 0; +#ifdef SQLITE_DEBUG + p->nWrite = 0; +#endif /* Save profiling information from this VDBE run. */ diff --git a/src/vdbemem.c b/src/vdbemem.c index a64ed0963..c3e376d79 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -817,7 +817,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ } /* A no-op destructor */ -static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } +void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } /* ** Set the value stored in *pMem should already be a NULL. diff --git a/src/vtab.c b/src/vtab.c index bc1fa3e8c..7894bbc8b 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -1049,9 +1049,6 @@ FuncDef *sqlite3VtabOverloadFunction( void *pArg = 0; FuncDef *pNew; int rc = 0; - char *zLowerName; - unsigned char *z; - /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; @@ -1066,16 +1063,22 @@ FuncDef *sqlite3VtabOverloadFunction( if( pMod->xFindFunction==0 ) return pDef; /* Call the xFindFunction method on the virtual table implementation - ** to see if the implementation wants to overload this function + ** to see if the implementation wants to overload this function. + ** + ** Though undocumented, we have historically always invoked xFindFunction + ** with an all lower-case function name. Continue in this tradition to + ** avoid any chance of an incompatibility. */ - zLowerName = sqlite3DbStrDup(db, pDef->zName); - if( zLowerName ){ - for(z=(unsigned char*)zLowerName; *z; z++){ - *z = sqlite3UpperToLower[*z]; +#ifdef SQLITE_DEBUG + { + int i; + for(i=0; pDef->zName[i]; i++){ + unsigned char x = (unsigned char)pDef->zName[i]; + assert( x==sqlite3UpperToLower[x] ); } - rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg); - sqlite3DbFree(db, zLowerName); } +#endif + rc = pMod->xFindFunction(pVtab, nArg, pDef->zName, &xSFunc, &pArg); if( rc==0 ){ return pDef; } |