diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/sqlite.h.in | 3 | ||||
-rw-r--r-- | src/sqliteInt.h | 26 | ||||
-rw-r--r-- | src/status.c | 7 | ||||
-rw-r--r-- | src/test_malloc.c | 3 | ||||
-rw-r--r-- | src/util.c | 16 | ||||
-rw-r--r-- | src/where.c | 19 |
7 files changed, 62 insertions, 17 deletions
diff --git a/src/main.c b/src/main.c index 2f31aa535..c3a89488c 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.472 2008/07/08 19:34:07 drh Exp $ +** $Id: main.c,v 1.473 2008/07/09 13:28:54 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -579,7 +579,8 @@ static int sqliteDefaultBusyCallback( */ int sqlite3InvokeBusyHandler(BusyHandler *p){ int rc; - if( p==0 || p->xFunc==0 || p->nBusy<0 ) return 0; + failsafe( p==0, 0x912aaf8d, {return 0;}) + if( p->xFunc==0 || p->nBusy<0 ) return 0; rc = p->xFunc(p->pArg, p->nBusy); if( rc==0 ){ p->nBusy = -1; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 916e84dcd..bb4ba97ad 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -30,7 +30,7 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** -** @(#) $Id: sqlite.h.in,v 1.364 2008/07/07 19:52:10 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.365 2008/07/09 13:28:54 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -6120,6 +6120,7 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); #define SQLITE_STATUS_SCRATCH_USED 3 #define SQLITE_STATUS_SCRATCH_OVERFLOW 4 #define SQLITE_STATUS_MALLOC_SIZE 5 +#define SQLITE_STATUS_FAILSAFE 6 /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3b22e94ca..9f9985f4b 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.738 2008/07/08 23:40:20 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.739 2008/07/09 13:28:54 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -62,6 +62,26 @@ # define testcase(X) #endif +/* +** The failsafe() macro is used to test for error conditions that +** should never occur. This is similar to assert() except that with +** failsafe() the application attempts to recover gracefully rather +** than abort. If a error condition is detected, a global flag is +** set to the "Id" prior to recovery in order to alert the application +** to the error condition. +** +** The Id should be a random integer. The idea behind the Id is that +** failsafe() faults in the field can be mapped back to specific failsafe() +** macros, even if line numbers and filenames have changed. +** +** The test condition is argument Cond. The recovery action is +** argument Action. +*/ +#ifdef SQLITE_COVERAGE_TEST +# define failsafe(Cond,Id,Action) +#else +# define failsafe(Cond,Id,Action) if( Cond ){ sqlite3Failsafe(Id); Action; } +#endif /* ** The macro unlikely() is a hint that surrounds a boolean @@ -1756,6 +1776,7 @@ struct Sqlite3Config { int bCoreMutex; /* True to enable core mutexing */ int bFullMutex; /* True to enable full mutexing */ int mxStrlen; /* Maximum string length */ + int iFailsafe; /* Id of failed failsafe() */ sqlite3_mem_methods m; /* Low-level memory allocation interface */ sqlite3_mutex_methods mutex; /* Low-level mutex interface */ void *pHeap; /* Heap storage space */ @@ -1791,10 +1812,8 @@ struct Sqlite3Config { #ifdef SQLITE_DEBUG int sqlite3Corrupt(void); # define SQLITE_CORRUPT_BKPT sqlite3Corrupt() -# define DEBUGONLY(X) X #else # define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT -# define DEBUGONLY(X) #endif /* @@ -2001,6 +2020,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite3*); #endif int sqlite3SafetyCheckOk(sqlite3*); int sqlite3SafetyCheckSickOrOk(sqlite3*); +void sqlite3Failsafe(int); void sqlite3ChangeCookie(Parse*, int); void sqlite3MaterializeView(Parse*, Select*, Expr*, int); diff --git a/src/status.c b/src/status.c index f4afa18be..e5d54f06a 100644 --- a/src/status.c +++ b/src/status.c @@ -13,7 +13,7 @@ ** This module implements the sqlite3_status() interface and related ** functionality. ** -** $Id: status.c,v 1.1 2008/06/19 13:20:02 drh Exp $ +** $Id: status.c,v 1.2 2008/07/09 13:28:54 drh Exp $ */ #include "sqliteInt.h" @@ -73,6 +73,11 @@ void sqlite3StatusSet(int op, int X){ ** then this routine is not threadsafe. */ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ + if( op==SQLITE_STATUS_FAILSAFE ){ + *pCurrent = *pHighwater = sqlite3Config.iFailsafe; + if( resetFlag ) sqlite3Config.iFailsafe = 0; + return SQLITE_OK; + } if( op<0 || op>=ArraySize(sqlite3Stat.nowValue) ){ return SQLITE_MISUSE; } diff --git a/src/test_malloc.c b/src/test_malloc.c index 906ee26a7..a35562a5f 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -13,7 +13,7 @@ ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. ** -** $Id: test_malloc.c,v 1.33 2008/06/27 14:05:25 danielk1977 Exp $ +** $Id: test_malloc.c,v 1.34 2008/07/09 13:28:54 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -1043,6 +1043,7 @@ static int test_status( { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED }, { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW }, { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE }, + { "SQLITE_STATUS_FAILSAFE", SQLITE_STATUS_FAILSAFE }, }; Tcl_Obj *pResult; if( objc!=3 ){ diff --git a/src/util.c b/src/util.c index bcf55e0a0..419cf03a9 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.234 2008/07/08 14:52:10 drh Exp $ +** $Id: util.c,v 1.235 2008/07/09 13:28:54 drh Exp $ */ #include "sqliteInt.h" #include <stdarg.h> @@ -936,3 +936,17 @@ int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ magic!=SQLITE_MAGIC_BUSY ) return 0; return 1; } + +/* +** Report a failsafe() macro failure +*/ +void sqlite3Failsafe(int iCode){ + sqlite3Config.iFailsafe = iCode; + + /* The following assert is always false. When assert() is enabled, + ** the following causes a failsafe() failure to work like an assert() + ** failure. Normal operating mode for SQLite is for assert() to be + ** disabled, however, so the following is normally a no-op. + */ + assert( iCode==0 ); /* Always fails if assert() is enabled */ +} diff --git a/src/where.c b/src/where.c index b59450a0c..0f5ba2a5e 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.314 2008/07/08 22:28:49 shane Exp $ +** $Id: where.c,v 1.315 2008/07/09 13:28:54 drh Exp $ */ #include "sqliteInt.h" @@ -450,13 +450,14 @@ static WhereTerm *findTerm( ){ WhereTerm *pTerm; int k; + assert( iCur>=0 ); for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ if( pTerm->leftCursor==iCur && (pTerm->prereqRight & notReady)==0 && pTerm->leftColumn==iColumn && (pTerm->eOperator & op)!=0 ){ - if( iCur>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){ + if( pIdx && pTerm->eOperator!=WO_ISNULL ){ Expr *pX = pTerm->pExpr; CollSeq *pColl; char idxaff; @@ -476,8 +477,9 @@ static WhereTerm *findTerm( pColl = pParse->db->pDfltColl; } - for(j=0; j<pIdx->nColumn && pIdx->aiColumn[j]!=iColumn; j++){} - assert( j<pIdx->nColumn ); + for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ + failsafe( j>=pIdx->nColumn, 0x0128fc98, {return 0;}); + } if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue; } return pTerm; @@ -866,7 +868,7 @@ static void exprAnalyze( ExprList *pList = 0; Expr *pNew, *pDup; Expr *pLeft = 0; - for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){ + for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0; i--, pOrTerm++){ if( (pOrTerm->flags & TERM_OR_OK)==0 ) continue; pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight); pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0); @@ -1606,7 +1608,8 @@ static double bestIndex( flags |= WHERE_COLUMN_IN; if( pExpr->pSelect!=0 ){ inMultiplier *= 25; - }else if( pExpr->pList!=0 ){ + }else{ + failsafe( pExpr->pList==0, 0x16b91d0f, continue); inMultiplier *= pExpr->pList->nExpr + 1; } } @@ -1722,9 +1725,9 @@ static double bestIndex( */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ if( pTerm - && (pTerm->flags & TERM_CODED)==0 && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) ){ + failsafe( (pTerm->flags & TERM_CODED)!=0, 0x641154a4, /* no-op */ ); pTerm->flags |= TERM_CODED; if( pTerm->iParent>=0 ){ WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent]; @@ -1870,7 +1873,7 @@ static int codeAllEqualityTerms( int r1; int k = pIdx->aiColumn[j]; pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx); - if( pTerm==0 ) break; + failsafe( pTerm==0, 0x7592494c, break ); assert( (pTerm->flags & TERM_CODED)==0 ); r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j); if( r1!=regBase+j ){ |