aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c5
-rw-r--r--src/sqlite.h.in3
-rw-r--r--src/sqliteInt.h26
-rw-r--r--src/status.c7
-rw-r--r--src/test_malloc.c3
-rw-r--r--src/util.c16
-rw-r--r--src/where.c19
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 ){