aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2016-02-05 01:55:27 +0000
committerdrh <drh@noemail.net>2016-02-05 01:55:27 +0000
commit4a642b60607e55a2c25f663b472af3609c76b214 (patch)
treed4af5d6c69d8cde0c32bfcc7a427eb34c2815080 /src
parente514f651d0fb5364e6495b9d6c4dd80ca51a227f (diff)
downloadsqlite-4a642b60607e55a2c25f663b472af3609c76b214.tar.gz
sqlite-4a642b60607e55a2c25f663b472af3609c76b214.zip
Improvements to the way that OOM errors are processed.
FossilOrigin-Name: c3ef03478a5788c855b3aef385d43ae7f494f440
Diffstat (limited to 'src')
-rw-r--r--src/alter.c2
-rw-r--r--src/analyze.c13
-rw-r--r--src/attach.c4
-rw-r--r--src/build.c21
-rw-r--r--src/callback.c4
-rw-r--r--src/expr.c5
-rw-r--r--src/fkey.c6
-rw-r--r--src/func.c2
-rw-r--r--src/insert.c4
-rw-r--r--src/legacy.c2
-rw-r--r--src/main.c8
-rw-r--r--src/malloc.c51
-rw-r--r--src/parse.y13
-rw-r--r--src/pragma.c2
-rw-r--r--src/prepare.c18
-rw-r--r--src/printf.c2
-rw-r--r--src/select.c9
-rw-r--r--src/sqliteInt.h6
-rw-r--r--src/tokenize.c7
-rw-r--r--src/trigger.c2
-rw-r--r--src/vdbe.c7
-rw-r--r--src/vdbeapi.c4
-rw-r--r--src/vdbeaux.c8
-rw-r--r--src/vdbemem.c2
-rw-r--r--src/vtab.c8
-rw-r--r--src/where.c2
-rw-r--r--src/whereexpr.c1
27 files changed, 126 insertions, 87 deletions
diff --git a/src/alter.c b/src/alter.c
index 16b7a9e19..3419059fa 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -695,7 +695,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
if( rc!=SQLITE_OK ){
- db->mallocFailed = 1;
+ assert( db->mallocFailed = 1 );
return;
}
if( !pVal ){
diff --git a/src/analyze.c b/src/analyze.c
index 4d777fa9f..7a7d68f59 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -1523,7 +1523,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
** the old data with the new instead of allocating a new array. */
if( pIndex->aiRowEst==0 ){
pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol);
- if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1;
+ if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db);
}
aiRowEst = pIndex->aiRowEst;
#endif
@@ -1670,7 +1670,7 @@ static int loadStatTbl(
Index *pPrevIdx = 0; /* Previous index in the loop */
IndexSample *pSample; /* A slot in pIdx->aSample[] */
- assert( db->lookaside.bEnabled==0 );
+ assert( db->lookaside.bDisable );
zSql = sqlite3MPrintf(db, zSql1, zDb);
if( !zSql ){
return SQLITE_NOMEM;
@@ -1784,7 +1784,7 @@ static int loadStatTbl(
static int loadStat4(sqlite3 *db, const char *zDb){
int rc = SQLITE_OK; /* Result codes from subroutines */
- assert( db->lookaside.bEnabled==0 );
+ assert( db->lookaside.bDisable );
if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
rc = loadStatTbl(db, 0,
"SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
@@ -1866,10 +1866,9 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
- int lookasideEnabled = db->lookaside.bEnabled;
- db->lookaside.bEnabled = 0;
+ db->lookaside.bDisable++;
rc = loadStat4(db, sInfo.zDatabase);
- db->lookaside.bEnabled = lookasideEnabled;
+ db->lookaside.bDisable--;
}
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
@@ -1879,7 +1878,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
#endif
if( rc==SQLITE_NOMEM ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
return rc;
}
diff --git a/src/attach.c b/src/attach.c
index 12d3ac3ff..e167951f6 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -127,7 +127,7 @@ static void attachFunc(
flags = db->openFlags;
rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
+ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
return;
@@ -230,7 +230,7 @@ static void attachFunc(
sqlite3ResetAllSchemasOfConnection(db);
db->nDb = iDb;
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
sqlite3DbFree(db, zErrDyn);
zErrDyn = sqlite3MPrintf(db, "out of memory");
}else if( zErrDyn==0 ){
diff --git a/src/build.c b/src/build.c
index cea05d51c..097149fd4 100644
--- a/src/build.c
+++ b/src/build.c
@@ -78,7 +78,7 @@ void sqlite3TableLock(
p->zName = zName;
}else{
pToplevel->nTableLock = 0;
- pToplevel->db->mallocFailed = 1;
+ sqlite3OomFault(pToplevel->db);
}
}
@@ -1555,7 +1555,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
n += 35 + 6*p->nCol;
zStmt = sqlite3DbMallocRaw(0, n);
if( zStmt==0 ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
return 0;
}
sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
@@ -2038,7 +2038,7 @@ void sqlite3EndTable(
pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
return;
}
pParse->pNewTable = 0;
@@ -2142,7 +2142,6 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
sqlite3_xauth xAuth; /* Saved xAuth pointer */
- u8 bEnabledLA; /* Saved db->lookaside.bEnabled state */
assert( pTable );
@@ -2188,18 +2187,18 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** statement that defines the view.
*/
assert( pTable->pSelect );
- bEnabledLA = db->lookaside.bEnabled;
if( pTable->pCheck ){
- db->lookaside.bEnabled = 0;
+ db->lookaside.bDisable++;
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
&pTable->nCol, &pTable->aCol);
+ db->lookaside.bDisable--;
}else{
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
- db->lookaside.bEnabled = 0;
+ db->lookaside.bDisable++;
#ifndef SQLITE_OMIT_AUTHORIZATION
xAuth = db->xAuth;
db->xAuth = 0;
@@ -2208,6 +2207,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#else
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
#endif
+ db->lookaside.bDisable--;
pParse->nTab = n;
if( pSelTab ){
assert( pTable->aCol==0 );
@@ -2226,7 +2226,6 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
nErr++;
}
}
- db->lookaside.bEnabled = bEnabledLA;
pTable->pSchema->schemaFlags |= DB_UnresetViews;
#endif /* SQLITE_OMIT_VIEW */
return nErr;
@@ -2692,7 +2691,7 @@ void sqlite3CreateForeignKey(
pFKey->zTo, (void *)pFKey
);
if( pNextTo==pFKey ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
goto fk_end;
}
if( pNextTo ){
@@ -3274,7 +3273,7 @@ Index *sqlite3CreateIndex(
pIndex->zName, pIndex);
if( p ){
assert( p==pIndex ); /* Malloc must have failed */
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
goto exit_create_index;
}
db->flags |= SQLITE_InternChanges;
@@ -3992,7 +3991,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
db->aDb[1].pBt = pBt;
assert( db->aDb[1].pSchema );
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
return 1;
}
}
diff --git a/src/callback.c b/src/callback.c
index 2a9f5b802..2b955fdcd 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -177,7 +177,7 @@ static CollSeq *findCollSeqEntry(
*/
assert( pDel==0 || pDel==pColl );
if( pDel!=0 ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
sqlite3DbFree(db, pDel);
pColl = 0;
}
@@ -465,7 +465,7 @@ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
}
if( !p ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}else if ( 0==p->file_format ){
sqlite3HashInit(&p->tblHash);
sqlite3HashInit(&p->idxHash);
diff --git a/src/expr.c b/src/expr.c
index c91db2834..5b134d666 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -699,7 +699,10 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
if( x>pParse->nzVar ){
char **a;
a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
- if( a==0 ) return; /* Error reported through db->mallocFailed */
+ if( a==0 ){
+ assert( db->mallocFailed ); /* Error reported through mallocFailed */
+ return;
+ }
pParse->azVar = a;
memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
pParse->nzVar = x;
diff --git a/src/fkey.c b/src/fkey.c
index 7eb188924..fae25c482 100644
--- a/src/fkey.c
+++ b/src/fkey.c
@@ -1165,7 +1165,6 @@ static Trigger *fkActionTrigger(
pTrigger = pFKey->apTrigger[iAction];
if( action!=OE_None && !pTrigger ){
- u8 enableLookaside; /* Copy of db->lookaside.bEnabled */
char const *zFrom; /* Name of child table */
int nFrom; /* Length in bytes of zFrom */
Index *pIdx = 0; /* Parent key index for this FK */
@@ -1274,8 +1273,7 @@ static Trigger *fkActionTrigger(
}
/* Disable lookaside memory allocation */
- enableLookaside = db->lookaside.bEnabled;
- db->lookaside.bEnabled = 0;
+ db->lookaside.bDisable++;
pTrigger = (Trigger *)sqlite3DbMallocZero(db,
sizeof(Trigger) + /* struct Trigger */
@@ -1297,7 +1295,7 @@ static Trigger *fkActionTrigger(
}
/* Re-enable the lookaside buffer, if it was disabled earlier. */
- db->lookaside.bEnabled = enableLookaside;
+ db->lookaside.bDisable--;
sqlite3ExprDelete(db, pWhere);
sqlite3ExprDelete(db, pWhen);
diff --git a/src/func.c b/src/func.c
index 982a8c2ca..d615cf90b 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1615,7 +1615,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
int rc = sqlite3_overload_function(db, "MATCH", 2);
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
}
diff --git a/src/insert.c b/src/insert.c
index 5f36c089f..a8cde7295 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -83,7 +83,7 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
Table *pTab = pIdx->pTable;
pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
if( !pIdx->zColAff ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
return 0;
}
for(n=0; n<pIdx->nColumn; n++){
@@ -134,7 +134,7 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
sqlite3 *db = sqlite3VdbeDb(v);
zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
if( !zColAff ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
return;
}
diff --git a/src/legacy.c b/src/legacy.c
index a10006e55..1b5e518d4 100644
--- a/src/legacy.c
+++ b/src/legacy.c
@@ -90,7 +90,7 @@ int sqlite3_exec(
for(i=0; i<nCol; i++){
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
goto exec_out;
}
}
diff --git a/src/main.c b/src/main.c
index 63a105c3f..588461b48 100644
--- a/src/main.c
+++ b/src/main.c
@@ -698,12 +698,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
p = (LookasideSlot*)&((u8*)p)[sz];
}
db->lookaside.pEnd = p;
- db->lookaside.bEnabled = 1;
+ db->lookaside.bDisable = 0;
db->lookaside.bMalloced = pBuf==0 ?1:0;
}else{
db->lookaside.pStart = db;
db->lookaside.pEnd = db;
- db->lookaside.bEnabled = 0;
+ db->lookaside.bDisable = 1;
db->lookaside.bMalloced = 0;
}
#endif /* SQLITE_OMIT_LOOKASIDE */
@@ -2208,7 +2208,7 @@ const void *sqlite3_errmsg16(sqlite3 *db){
** be cleared before returning. Do this directly, instead of via
** sqlite3ApiExit(), to avoid setting the database handle error message.
*/
- db->mallocFailed = 0;
+ sqlite3OomClear(db);
}
sqlite3_mutex_leave(db->mutex);
return z;
@@ -2846,7 +2846,7 @@ static int openDatabase(
db->openFlags = flags;
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
+ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
sqlite3_free(zErrMsg);
goto opendb_out;
diff --git a/src/malloc.c b/src/malloc.c
index c8a04128c..057d36a4b 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -608,10 +608,8 @@ void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
#ifndef SQLITE_OMIT_LOOKASIDE
if( db ){
LookasideSlot *pBuf;
- if( db->mallocFailed ){
- return 0;
- }
- if( db->lookaside.bEnabled ){
+ if( db->lookaside.bDisable==0 ){
+ assert( db->mallocFailed==0 );
if( n>db->lookaside.sz ){
db->lookaside.anStat[1]++;
}else if( (pBuf = db->lookaside.pFree)==0 ){
@@ -625,7 +623,10 @@ void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
}
return (void*)pBuf;
}
+ }else if( db->mallocFailed ){
+ return 0;
}
+
}
#else
if( db && db->mallocFailed ){
@@ -637,10 +638,10 @@ void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
void *p = sqlite3Malloc(n);
if( !p && db ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
sqlite3MemdebugSetType(p,
- (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
+ (db && db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
return p;
}
@@ -671,10 +672,10 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
pNew = sqlite3_realloc64(p, n);
if( !pNew ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
sqlite3MemdebugSetType(pNew,
- (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
+ (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
}
}
return pNew;
@@ -737,10 +738,42 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
}
/*
+** Call this routine to record the fact that an OOM (out-of-memory) error
+** has happened. This routine will set db->mallocFailed, and also
+** temporarily disable the lookaside memory allocator and interrupt
+** any running VDBEs.
+*/
+void sqlite3OomFault(sqlite3 *db){
+ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
+ db->mallocFailed = 1;
+ if( db->nVdbeExec>0 ){
+ db->u1.isInterrupted = 1;
+ }
+ db->lookaside.bDisable++;
+ }
+}
+
+/*
+** This routine reactivates the memory allocator and clears the
+** db->mallocFailed flag as necessary.
+**
+** The memory allocator is not restarted if there are running
+** VDBEs.
+*/
+void sqlite3OomClear(sqlite3 *db){
+ if( db->mallocFailed && db->nVdbeExec==0 ){
+ db->mallocFailed = 0;
+ db->u1.isInterrupted = 0;
+ assert( db->lookaside.bDisable>0 );
+ db->lookaside.bDisable--;
+ }
+}
+
+/*
** Take actions at the end of an API call to indicate an OOM error
*/
static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
- db->mallocFailed = 0;
+ sqlite3OomClear(db);
sqlite3Error(db, SQLITE_NOMEM);
return SQLITE_NOMEM;
}
diff --git a/src/parse.y b/src/parse.y
index 846c2504b..0bfe4e473 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -106,6 +106,15 @@ struct TrigEvent { int a; IdList * b; };
*/
struct AttachKey { int type; Token key; };
+/*
+** Disable lookaside memory allocation for objects that might be
+** shared across database connections.
+*/
+static void disableLookaside(Parse *pParse){
+ pParse->disableLookaside++;
+ pParse->db->lookaside.bDisable++;
+}
+
} // end %include
// Input is a single SQL command
@@ -156,7 +165,7 @@ create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
}
createkw(A) ::= CREATE(X). {
- pParse->db->lookaside.bEnabled = 0;
+ disableLookaside(pParse);
A = X;
}
%type ifnotexists {int}
@@ -1507,7 +1516,7 @@ cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column(Y). {
sqlite3AlterFinishAddColumn(pParse, &Y);
}
add_column_fullname ::= fullname(X). {
- pParse->db->lookaside.bEnabled = 0;
+ disableLookaside(pParse);
sqlite3AlterBeginAddColumn(pParse, X);
}
kwcolumn_opt ::= .
diff --git a/src/pragma.c b/src/pragma.c
index bde17d1e8..c34d5421c 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -478,7 +478,7 @@ void sqlite3Pragma(
*/
db->nextPagesize = sqlite3Atoi(zRight);
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
}
break;
diff --git a/src/prepare.c b/src/prepare.c
index f8ad54665..3fb71a770 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -32,7 +32,7 @@ static void corruptSchema(
if( z && zExtra ) z = sqlite3_mprintf("%z - %s", z, zExtra);
sqlite3DbFree(db, *pData->pzErrMsg);
*pData->pzErrMsg = z;
- if( z==0 ) db->mallocFailed = 1;
+ if( z==0 ) sqlite3OomFault(db);
}
pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT;
}
@@ -91,7 +91,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
}else{
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
corruptSchema(pData, argv[0], sqlite3_errmsg(db));
}
@@ -336,7 +336,7 @@ initone_error_out:
error_out:
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
return rc;
}
@@ -434,7 +434,7 @@ static void schemaIsValid(Parse *pParse){
if( !sqlite3BtreeIsInReadTrans(pBt) ){
rc = sqlite3BtreeBeginTrans(pBt, 0);
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
if( rc!=SQLITE_OK ) return;
openedTransaction = 1;
@@ -497,6 +497,11 @@ void sqlite3ParserReset(Parse *pParse){
sqlite3 *db = pParse->db;
sqlite3DbFree(db, pParse->aLabel);
sqlite3ExprListDelete(db, pParse->pConstExpr);
+ if( db ){
+ assert( db->lookaside.bDisable >= pParse->disableLookaside );
+ db->lookaside.bDisable -= pParse->disableLookaside;
+ }
+ pParse->disableLookaside = 0;
}
}
@@ -592,9 +597,6 @@ static int sqlite3Prepare(
}
assert( 0==pParse->nQueryLoop );
- if( db->mallocFailed ){
- pParse->rc = SQLITE_NOMEM;
- }
if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
if( pParse->checkSchema ){
schemaIsValid(pParse);
@@ -716,7 +718,7 @@ int sqlite3Reprepare(Vdbe *p){
rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0);
if( rc ){
if( rc==SQLITE_NOMEM ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
assert( pNew==0 );
return rc;
diff --git a/src/printf.c b/src/printf.c
index 946161f64..238997f37 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -929,7 +929,7 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
sqlite3VXPrintf(&acc, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
if( acc.accError==STRACCUM_NOMEM ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
return z;
}
diff --git a/src/select.c b/src/select.c
index 891b12354..84d5423de 100644
--- a/src/select.c
+++ b/src/select.c
@@ -1016,7 +1016,7 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
p->nRef = 1;
memset(&p[1], 0, nExtra);
}else{
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
return p;
}
@@ -1677,7 +1677,7 @@ int sqlite3ColumnsFromExprList(
pCol->zName = zName;
sqlite3ColumnPropertiesFromName(0, pCol);
if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}
}
sqlite3HashClear(&ht);
@@ -1764,7 +1764,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
}
/* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
** is disabled */
- assert( db->lookaside.bEnabled==0 );
+ assert( db->lookaside.bDisable );
pTab->nRef = 1;
pTab->zName = 0;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
@@ -5562,7 +5562,8 @@ int sqlite3Select(
if( flag ){
pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
pDel = pMinMax;
- if( pMinMax && !db->mallocFailed ){
+ assert( db->mallocFailed || pMinMax!=0 );
+ if( !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
pMinMax->a[0].pExpr->op = TK_COLUMN;
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 16d3ea992..70f210c0a 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1094,8 +1094,8 @@ struct Schema {
** lookaside allocations are not used to construct the schema objects.
*/
struct Lookaside {
+ u32 bDisable; /* Only operate the lookaside when zero */
u16 sz; /* Size of each buffer in bytes */
- u8 bEnabled; /* False to disable new lookaside allocations */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
int nOut; /* Number of buffers currently checked out */
int mxOut; /* Highwater mark for nOut */
@@ -1178,6 +1178,7 @@ struct sqlite3 {
u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */
u8 mallocFailed; /* True if we have seen a malloc failure */
+ u8 bBenignMalloc; /* Do not require OOMs if true */
u8 dfltLockMode; /* Default locking-mode for attached dbs */
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
u8 suppressErr; /* Do not issue error messages if true */
@@ -2733,6 +2734,7 @@ struct Parse {
u8 mayAbort; /* True if statement may throw an ABORT exception */
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
u8 okConstFactor; /* OK to factor out constants */
+ u8 disableLookaside; /* Number of times lookaside has been disabled */
int aTempReg[8]; /* Holding area for temporary registers */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
@@ -3777,6 +3779,8 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
FuncDestructor *pDestructor
);
+void sqlite3OomFault(sqlite3*);
+void sqlite3OomClear(sqlite3*);
int sqlite3ApiExit(sqlite3 *db, int);
int sqlite3OpenTempDatabase(Parse *);
diff --git a/src/tokenize.c b/src/tokenize.c
index b85e35dc1..5bee3d5a8 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -390,7 +390,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
void *pEngine; /* The LEMON-generated LALR(1) parser */
int tokenType; /* type of the next token */
int lastTokenParsed = -1; /* type of the previous token */
- u8 enableLookaside; /* Saved value of db->lookaside.bEnabled */
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
@@ -406,7 +405,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
/* sqlite3ParserTrace(stdout, "parser: "); */
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
if( pEngine==0 ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
return SQLITE_NOMEM;
}
assert( pParse->pNewTable==0 );
@@ -414,8 +413,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->nVar==0 );
assert( pParse->nzVar==0 );
assert( pParse->azVar==0 );
- enableLookaside = db->lookaside.bEnabled;
- if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
while( zSql[i]!=0 ){
assert( i>=0 );
pParse->sLastToken.z = &zSql[i];
@@ -428,7 +425,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
if( tokenType>=TK_SPACE ){
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
if( db->u1.isInterrupted ){
- sqlite3ErrorMsg(pParse, "interrupt");
pParse->rc = SQLITE_INTERRUPT;
break;
}
@@ -463,7 +459,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
sqlite3_mutex_leave(sqlite3MallocMutex());
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
- db->lookaside.bEnabled = enableLookaside;
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
}
diff --git a/src/trigger.c b/src/trigger.c
index 4bfb55af6..72c31eb2a 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -323,7 +323,7 @@ void sqlite3FinishTrigger(
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pTrig = sqlite3HashInsert(pHash, zName, pTrig);
if( pTrig ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
}else if( pLink->pSchema==pLink->pTabSchema ){
Table *pTab;
pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table);
diff --git a/src/vdbe.c b/src/vdbe.c
index 62ad86d4f..c0eff6a09 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -629,7 +629,6 @@ int sqlite3VdbeExec(
#endif
for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
- if( db->mallocFailed ) goto no_mem;
#ifdef VDBE_PROFILE
start = sqlite3Hwtime();
#endif
@@ -6785,7 +6784,7 @@ vdbe_error_halt:
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
(int)(pOp - aOp), p->zSql, p->zErrMsg);
sqlite3VdbeHalt(p);
- if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
+ if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
rc = SQLITE_ERROR;
if( resetSchemaOnFault>0 ){
sqlite3ResetOneSchema(db, resetSchemaOnFault-1);
@@ -6815,7 +6814,7 @@ too_big:
/* Jump to here if a malloc() fails.
*/
no_mem:
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
sqlite3VdbeError(p, "out of memory");
rc = SQLITE_NOMEM;
goto vdbe_error_halt;
@@ -6836,7 +6835,7 @@ abort_due_to_error:
*/
abort_due_to_interrupt:
assert( db->u1.isInterrupted );
- rc = SQLITE_INTERRUPT;
+ rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_INTERRUPT;
p->rc = rc;
sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
goto vdbe_error_halt;
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 0a15633dd..fce43630e 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -473,7 +473,7 @@ void sqlite3_result_error_nomem(sqlite3_context *pCtx){
sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM;
pCtx->fErrorOrAux = 1;
- pCtx->pOut->db->mallocFailed = 1;
+ sqlite3OomFault(pCtx->pOut->db);
}
/*
@@ -1101,7 +1101,7 @@ static const void *columnName(
** is the case, clear the mallocFailed flag and return NULL.
*/
if( db->mallocFailed ){
- db->mallocFailed = 0;
+ sqlite3OomClear(db);
ret = 0;
}
sqlite3_mutex_leave(db->mutex);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 632c1231a..7d3a8c429 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1423,7 +1423,6 @@ static void releaseMemArray(Mem *p, int N){
if( p && N ){
Mem *pEnd = &p[N];
sqlite3 *db = p->db;
- u8 malloc_failed = db->mallocFailed;
if( db->pnBytesFreed ){
do{
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
@@ -1459,7 +1458,6 @@ static void releaseMemArray(Mem *p, int N){
p->flags = MEM_Undefined;
}while( (++p)<pEnd );
- db->mallocFailed = malloc_failed;
}
}
@@ -1520,7 +1518,7 @@ int sqlite3VdbeList(
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
return SQLITE_ERROR;
}
@@ -2711,12 +2709,12 @@ int sqlite3VdbeTransferError(Vdbe *p){
sqlite3 *db = p->db;
int rc = p->rc;
if( p->zErrMsg ){
- u8 mallocFailed = db->mallocFailed;
+ db->bBenignMalloc++;
sqlite3BeginBenignMalloc();
if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db);
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
sqlite3EndBenignMalloc();
- db->mallocFailed = mallocFailed;
+ db->bBenignMalloc--;
db->errCode = rc;
}else{
sqlite3Error(db, rc);
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 0eeb59ef8..974b99074 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -1381,7 +1381,7 @@ static int valueFromExpr(
return rc;
no_mem:
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
sqlite3DbFree(db, zVal);
assert( *ppVal==0 );
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
diff --git a/src/vtab.c b/src/vtab.c
index ea79cd8ce..ca444944f 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -62,7 +62,7 @@ static int createModule(
pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
assert( pDel==0 || pDel==pMod );
if( pDel ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
sqlite3DbFree(db, pDel);
}
}
@@ -439,7 +439,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab);
if( pOld ){
- db->mallocFailed = 1;
+ sqlite3OomFault(db);
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
return;
}
@@ -530,7 +530,7 @@ static int vtabCallConstructor(
db->pVtabCtx = &sCtx;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
db->pVtabCtx = sCtx.pPrior;
- if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
+ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
assert( sCtx.pTab==pTab );
if( SQLITE_OK!=rc ){
@@ -1088,7 +1088,7 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
pToplevel->apVtabLock = apVtabLock;
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
}else{
- pToplevel->db->mallocFailed = 1;
+ sqlite3OomFault(pToplevel->db);
}
}
diff --git a/src/where.c b/src/where.c
index 8c8dfbb7b..d3a4ab87e 100644
--- a/src/where.c
+++ b/src/where.c
@@ -943,7 +943,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ){
- pParse->db->mallocFailed = 1;
+ sqlite3OomFault(pParse->db);
}else if( !pVtab->zErrMsg ){
sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
}else{
diff --git a/src/whereexpr.c b/src/whereexpr.c
index e0b8bac1b..ec244bcb4 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -563,7 +563,6 @@ static void exprAnalyzeOrTerm(
sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND);
sqlite3WhereExprAnalyze(pSrc, pAndWC);
pAndWC->pOuter = pWC;
- testcase( db->mallocFailed );
if( !db->mallocFailed ){
for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
assert( pAndTerm->pExpr );