diff options
author | danielk1977 <danielk1977@noemail.net> | 2007-08-29 12:31:25 +0000 |
---|---|---|
committer | danielk1977 <danielk1977@noemail.net> | 2007-08-29 12:31:25 +0000 |
commit | a1644fd86384de5f37fc42a7fb871a8c9a12dab5 (patch) | |
tree | ccd22487d7d42e8de86c109311e9d8aef043154a /src | |
parent | 1fee73e74acab48412a3c596d4cd68deecadeef6 (diff) | |
download | sqlite-a1644fd86384de5f37fc42a7fb871a8c9a12dab5.tar.gz sqlite-a1644fd86384de5f37fc42a7fb871a8c9a12dab5.zip |
Modifications to the malloc failure tests to test transient and persistent failures. (CVS 4321)
FossilOrigin-Name: e38ef81b85feb5bff2ad8448f3438ff0ab36571e
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 13 | ||||
-rw-r--r-- | src/build.c | 14 | ||||
-rw-r--r-- | src/callback.c | 10 | ||||
-rw-r--r-- | src/expr.c | 30 | ||||
-rw-r--r-- | src/func.c | 76 | ||||
-rw-r--r-- | src/hash.c | 10 | ||||
-rw-r--r-- | src/legacy.c | 5 | ||||
-rw-r--r-- | src/malloc.c | 36 | ||||
-rw-r--r-- | src/mem2.c | 24 | ||||
-rw-r--r-- | src/pager.c | 43 | ||||
-rw-r--r-- | src/pager.h | 4 | ||||
-rw-r--r-- | src/prepare.c | 17 | ||||
-rw-r--r-- | src/printf.c | 4 | ||||
-rw-r--r-- | src/select.c | 10 | ||||
-rw-r--r-- | src/sqlite.h.in | 3 | ||||
-rw-r--r-- | src/sqliteInt.h | 7 | ||||
-rw-r--r-- | src/test2.c | 6 | ||||
-rw-r--r-- | src/test3.c | 9 | ||||
-rw-r--r-- | src/test8.c | 121 | ||||
-rw-r--r-- | src/test_malloc.c | 60 | ||||
-rw-r--r-- | src/vacuum.c | 5 | ||||
-rw-r--r-- | src/vdbe.c | 5 | ||||
-rw-r--r-- | src/vdbeapi.c | 7 | ||||
-rw-r--r-- | src/vdbeaux.c | 4 | ||||
-rw-r--r-- | src/vdbemem.c | 4 | ||||
-rw-r--r-- | src/vtab.c | 3 | ||||
-rw-r--r-- | src/where.c | 8 |
27 files changed, 363 insertions, 175 deletions
diff --git a/src/btree.c b/src/btree.c index a955b384c..46553e524 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.416 2007/08/29 04:00:58 drh Exp $ +** $Id: btree.c,v 1.417 2007/08/29 12:31:26 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -1212,7 +1212,8 @@ int sqlite3BtreeOpen( pBt->pageSize = get2byte(&zDbHeader[16]); if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ - pBt->pageSize = sqlite3PagerSetPagesize(pBt->pPager, 0); + pBt->pageSize = 0; + sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); pBt->maxEmbedFrac = 64; /* 25% */ pBt->minEmbedFrac = 32; /* 12.5% */ pBt->minLeafFrac = 32; /* 12.5% */ @@ -1242,7 +1243,7 @@ int sqlite3BtreeOpen( } pBt->usableSize = pBt->pageSize - nReserve; assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ - sqlite3PagerSetPagesize(pBt->pPager, pBt->pageSize); + sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. @@ -1488,6 +1489,7 @@ int sqlite3BtreeSyncDisabled(Btree *p){ ** bytes per page is left unchanged. */ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){ + int rc = SQLITE_OK; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); if( pBt->pageSizeFixed ){ @@ -1501,11 +1503,12 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){ ((pageSize-1)&pageSize)==0 ){ assert( (pageSize & 7)==0 ); assert( !pBt->pPage1 && !pBt->pCursor ); - pBt->pageSize = sqlite3PagerSetPagesize(pBt->pPager, pageSize); + pBt->pageSize = pageSize; + rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize); } pBt->usableSize = pBt->pageSize - nReserve; sqlite3BtreeLeave(p); - return SQLITE_OK; + return rc; } /* diff --git a/src/build.c b/src/build.c index 8369df50b..047576134 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.440 2007/08/28 22:24:35 drh Exp $ +** $Id: build.c,v 1.441 2007/08/29 12:31:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -241,6 +241,7 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ zSql = sqlite3VMPrintf(pParse->db, zFormat, ap); va_end(ap); if( zSql==0 ){ + pParse->db->mallocFailed = 1; return; /* A malloc must have failed */ } pParse->nested++; @@ -1562,9 +1563,13 @@ void sqlite3EndTable( } #ifndef SQLITE_OMIT_FOREIGN_KEY for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + void *data; int nTo = strlen(pFKey->zTo) + 1; pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo); - sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey); + data = sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey); + if( data==(void *)pFKey ){ + db->mallocFailed = 1; + } } #endif pParse->pNewTable = 0; @@ -2383,7 +2388,10 @@ void sqlite3CreateIndex( sqlite3_snprintf(sizeof(zBuf),zBuf,"_%d",n); zName = 0; sqlite3SetString(&zName, "sqlite_autoindex_", pTab->zName, zBuf, (char*)0); - if( zName==0 ) goto exit_create_index; + if( zName==0 ){ + db->mallocFailed = 1; + goto exit_create_index; + } } /* Check for authorization to create an index. diff --git a/src/callback.c b/src/callback.c index 181f26f1b..009cfd740 100644 --- a/src/callback.c +++ b/src/callback.c @@ -13,7 +13,7 @@ ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. ** -** $Id: callback.c,v 1.22 2007/08/22 20:18:22 drh Exp $ +** $Id: callback.c,v 1.23 2007/08/29 12:31:26 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -361,11 +361,13 @@ void sqlite3SchemaFree(void *p){ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ Schema * p; if( pBt ){ - p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree); + p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaFree); }else{ - p = (Schema *)sqlite3DbMallocZero(db,sizeof(Schema)); + p = (Schema *)sqlite3MallocZero(sizeof(Schema)); } - if( p && 0==p->file_format ){ + if( !p ){ + db->mallocFailed = 1; + }else if ( 0==p->file_format ){ sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0); diff --git a/src/expr.c b/src/expr.c index 1d1fb0e18..778c65f3b 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.308 2007/08/22 20:18:22 drh Exp $ +** $Id: expr.c,v 1.309 2007/08/29 12:31:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -221,13 +221,14 @@ static int codeCompare( ** is responsible for making sure the node eventually gets freed. */ Expr *sqlite3Expr( + sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */ int op, /* Expression opcode */ Expr *pLeft, /* Left operand */ Expr *pRight, /* Right operand */ const Token *pToken /* Argument token */ ){ Expr *pNew; - pNew = sqlite3MallocZero( sizeof(Expr) ); + pNew = sqlite3DbMallocZero(db, sizeof(Expr)); if( pNew==0 ){ /* When malloc fails, delete pLeft and pRight. Expressions passed to ** this function must always be allocated with sqlite3Expr() for this @@ -273,11 +274,7 @@ Expr *sqlite3PExpr( Expr *pRight, /* Right operand */ const Token *pToken /* Argument token */ ){ - Expr *pNew = sqlite3Expr(op, pLeft, pRight, pToken); - if( pNew==0 ){ - pParse->db->mallocFailed = 1; - } - return pNew; + return sqlite3Expr(pParse->db, op, pLeft, pRight, pToken); } /* @@ -297,12 +294,11 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){ int depth; if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken); - return sqlite3Expr(TK_NULL, 0, 0, 0); + return sqlite3PExpr(pParse, TK_NULL, 0, 0, 0); } if( v==0 ) return 0; - p = sqlite3Expr(TK_REGISTER, 0, 0, pToken); + p = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, pToken); if( p==0 ){ - pParse->db->mallocFailed = 1; return 0; /* Malloc failed */ } depth = atoi((char*)&pToken->z[1]); @@ -322,7 +318,7 @@ Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ }else if( pRight==0 ){ return pLeft; }else{ - Expr *p = sqlite3Expr(TK_AND, pLeft, pRight, 0); + Expr *p = sqlite3Expr(db, TK_AND, pLeft, pRight, 0); if( p==0 ){ db->mallocFailed = 1; } @@ -1234,9 +1230,13 @@ static int lookupName( }else{ z = sqlite3StrDup(zCol); } - sqlite3ErrorMsg(pParse, zErr, z); - sqlite3_free(z); - pTopNC->nErr++; + if( z ){ + sqlite3ErrorMsg(pParse, zErr, z); + sqlite3_free(z); + pTopNC->nErr++; + }else{ + db->mallocFailed = 1; + } } /* If a column from a table in pSrcList is referenced, then record @@ -1668,7 +1668,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ VdbeComment((v, "# Init EXISTS result")); } sqlite3ExprDelete(pSel->pLimit); - pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one); + pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one); if( sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0) ){ return; } diff --git a/src/func.c b/src/func.c index 7b981df30..989e29527 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.169 2007/08/23 02:47:53 drh Exp $ +** $Id: func.c,v 1.170 2007/08/29 12:31:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -234,6 +234,14 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_result_double(context, r); } +static void *contextMalloc(sqlite3_context *context, int nByte){ + char *z = sqlite3_malloc(nByte); + if( !z && nByte>0 ){ + sqlite3_result_error_nomem(context); + } + return z; +} + /* ** Implementation of the upper() and lower() SQL functions. */ @@ -247,7 +255,7 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ /* Verify that the call to _bytes() does not invalidate the _text() pointer */ assert( z2==(char*)sqlite3_value_text(argv[0]) ); if( z2 ){ - z1 = sqlite3_malloc(n+1); + z1 = contextMalloc(context, n+1); if( z1 ){ memcpy(z1, z2, n+1); for(i=0; z1[i]; i++){ @@ -267,7 +275,7 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ /* Verify that the call to _bytes() does not invalidate the _text() pointer */ assert( z2==(char*)sqlite3_value_text(argv[0]) ); if( z2 ){ - z1 = sqlite3_malloc(n+1); + z1 = contextMalloc(context, n+1); if( z1 ){ memcpy(z1, z2, n+1); for(i=0; z1[i]; i++){ @@ -332,7 +340,7 @@ static void randomBlob( sqlite3_result_error_toobig(context); return; } - p = sqlite3_malloc(n); + p = contextMalloc(context, n); if( p ){ sqlite3Randomness(n, p); sqlite3_result_blob(context, (char*)p, n, sqlite3_free); @@ -665,10 +673,8 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_result_error_toobig(context); return; } - zText = (char *)sqlite3_malloc((2*nBlob)+4); - if( !zText ){ - sqlite3_result_error(context, "out of memory", -1); - }else{ + zText = (char *)contextMalloc(context, (2*nBlob)+4); + if( zText ){ int i; for(i=0; i<nBlob; i++){ zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F]; @@ -695,19 +701,19 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_result_error_toobig(context); return; } - z = sqlite3_malloc( i+n+3 ); - if( z==0 ) return; - z[0] = '\''; - for(i=0, j=1; zArg[i]; i++){ - z[j++] = zArg[i]; - if( zArg[i]=='\'' ){ - z[j++] = '\''; + z = contextMalloc(context, i+n+3); + if( z ){ + z[0] = '\''; + for(i=0, j=1; zArg[i]; i++){ + z[j++] = zArg[i]; + if( zArg[i]=='\'' ){ + z[j++] = '\''; + } } + z[j++] = '\''; + z[j] = 0; + sqlite3_result_text(context, z, j, sqlite3_free); } - z[j++] = '\''; - z[j] = 0; - sqlite3_result_text(context, z, j, SQLITE_TRANSIENT); - sqlite3_free(z); } } } @@ -732,15 +738,16 @@ static void hexFunc( return; } assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ - z = zHex = sqlite3_malloc(n*2 + 1); - if( zHex==0 ) return; - for(i=0; i<n; i++, pBlob++){ - unsigned char c = *pBlob; - *(z++) = hexdigits[(c>>4)&0xf]; - *(z++) = hexdigits[c&0xf]; + z = zHex = contextMalloc(context, n*2 + 1); + if( zHex ){ + for(i=0; i<n; i++, pBlob++){ + unsigned char c = *pBlob; + *(z++) = hexdigits[(c>>4)&0xf]; + *(z++) = hexdigits[c&0xf]; + } + *z = 0; + sqlite3_result_text(context, zHex, n*2, sqlite3_free); } - *z = 0; - sqlite3_result_text(context, zHex, n*2, sqlite3_free); } /* @@ -798,7 +805,7 @@ static void replaceFunc( assert( zRep==sqlite3_value_text(argv[2]) ); nOut = nStr + 1; assert( nOut<SQLITE_MAX_LENGTH ); - zOut = sqlite3_malloc((int)nOut); + zOut = contextMalloc(context, (int)nOut); if( zOut==0 ){ return; } @@ -817,6 +824,7 @@ static void replaceFunc( zOld = zOut; zOut = sqlite3_realloc(zOut, (int)nOut); if( zOut==0 ){ + sqlite3_result_error_nomem(context); sqlite3_free(zOld); return; } @@ -873,7 +881,7 @@ static void trimFunc( SQLITE_SKIP_UTF8(z); } if( nChar>0 ){ - azChar = sqlite3_malloc( nChar*(sizeof(char*)+1) ); + azChar = contextMalloc(context, nChar*(sizeof(char*)+1)); if( azChar==0 ){ return; } @@ -1110,8 +1118,9 @@ static void test_auxdata( sqlite3_value **argv ){ int i; - char *zRet = sqlite3MallocZero(nArg*2); + char *zRet = contextMalloc(pCtx, nArg*2); if( !zRet ) return; + memset(zRet, 0, nArg*2); for(i=0; i<nArg; i++){ char const *z = (char*)sqlite3_value_text(argv[i]); if( z ){ @@ -1125,8 +1134,11 @@ static void test_auxdata( } }else{ zRet[i*2] = '0'; - zAux = sqlite3StrDup(z); - sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata); + zAux = contextMalloc(pCtx, strlen(z)+1); + if( zAux ){ + strcpy(zAux, z); + sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata); + } } zRet[i*2+1] = ' '; } diff --git a/src/hash.c b/src/hash.c index fd1ceba98..e917197d6 100644 --- a/src/hash.c +++ b/src/hash.c @@ -12,7 +12,7 @@ ** This is the implementation of generic hash-tables ** used in SQLite. ** -** $Id: hash.c,v 1.21 2007/08/16 10:09:03 danielk1977 Exp $ +** $Id: hash.c,v 1.22 2007/08/29 12:31:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include <assert.h> @@ -222,6 +222,14 @@ static void rehash(Hash *pH, int new_size){ int (*xHash)(const void*,int); /* The hash function */ assert( (new_size & (new_size-1))==0 ); + + /* There is a call to sqlite3_malloc() inside rehash(). If there is + ** already an allocation at pH->ht, then if this malloc() fails it + ** is benign (since failing to resize a hash table is a performance + ** hit only, not a fatal error). + */ + sqlite3MallocBenignFailure(pH->htsize>0); + new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) ); if( new_ht==0 ) return; if( pH->ht ) sqlite3_free(pH->ht); diff --git a/src/legacy.c b/src/legacy.c index 72637b268..c004b89e1 100644 --- a/src/legacy.c +++ b/src/legacy.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: legacy.c,v 1.21 2007/08/22 20:18:22 drh Exp $ +** $Id: legacy.c,v 1.22 2007/08/29 12:31:26 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -46,6 +46,8 @@ int sqlite3_exec( int nCallback; if( zSql==0 ) return SQLITE_OK; + + sqlite3_mutex_enter(db->mutex); while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){ int nCol; char **azVals = 0; @@ -127,5 +129,6 @@ exec_out: } assert( (rc&db->errMask)==rc ); + sqlite3_mutex_leave(db->mutex); return rc; } diff --git a/src/malloc.c b/src/malloc.c index bd86636e9..5db775d8e 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -12,7 +12,7 @@ ** Memory allocation functions used throughout sqlite. ** ** -** $Id: malloc.c,v 1.11 2007/08/24 03:51:34 drh Exp $ +** $Id: malloc.c,v 1.12 2007/08/29 12:31:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include <stdarg.h> @@ -82,11 +82,9 @@ void *sqlite3MallocZero(unsigned n){ ** the mallocFailed flag in the connection pointer. */ void *sqlite3DbMallocZero(sqlite3 *db, unsigned n){ - void *p = sqlite3_malloc(n); + void *p = sqlite3DbMallocRaw(db, n); if( p ){ memset(p, 0, n); - }else if( db ){ - db->mallocFailed = 1; } return p; } @@ -96,28 +94,40 @@ void *sqlite3DbMallocZero(sqlite3 *db, unsigned n){ ** the mallocFailed flag in the connection pointer. */ void *sqlite3DbMallocRaw(sqlite3 *db, unsigned n){ - void *p = sqlite3_malloc(n); - if( !p && db ){ - db->mallocFailed = 1; + void *p = 0; + if( !db || db->mallocFailed==0 ){ + p = sqlite3_malloc(n); + if( !p && db ){ + db->mallocFailed = 1; + } } return p; } +void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ + void *pNew = 0; + if( db->mallocFailed==0 ){ + pNew = sqlite3_realloc(p, n); + if( !pNew ){ + db->mallocFailed = 1; + } + } + return pNew; +} + /* ** Attempt to reallocate p. If the reallocation fails, then free p ** and set the mallocFailed flag in the database connection. */ void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){ void *pNew; - pNew = sqlite3_realloc(p, n); + pNew = sqlite3DbRealloc(db, p, n); if( !pNew ){ sqlite3_free(p); - db->mallocFailed = 1; } return pNew; } - /* ** Make a copy of a string in memory obtained from sqliteMalloc(). These ** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This @@ -211,6 +221,11 @@ void sqlite3SetString(char **pz, ...){ ** is set to SQLITE_NOMEM. */ int sqlite3ApiExit(sqlite3* db, int rc){ + /* If the db handle is not NULL, then we must hold the connection handle + ** mutex here. Otherwise the read (and possible write) of db->mallocFailed + ** is unsafe, as is the call to sqlite3Error(). + */ + assert( !db || sqlite3_mutex_held(db->mutex) ); if( db && db->mallocFailed ){ sqlite3Error(db, SQLITE_NOMEM, 0); db->mallocFailed = 0; @@ -218,3 +233,4 @@ int sqlite3ApiExit(sqlite3* db, int rc){ } return rc & (db ? db->errMask : 0xff); } + diff --git a/src/mem2.c b/src/mem2.c index 03f2c2039..d3cc9354a 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -12,7 +12,7 @@ ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem2.c,v 1.10 2007/08/24 04:15:00 drh Exp $ +** $Id: mem2.c,v 1.11 2007/08/29 12:31:26 danielk1977 Exp $ */ /* @@ -138,7 +138,9 @@ static struct { */ int iFail; /* Decrement and fail malloc when this is 1 */ int iReset; /* When malloc fails set iiFail to this value */ - int iFailCnt; /* Number of failures */ + int iFailCnt; /* Number of failures */ + int iBenignFailCnt; /* Number of benign failures */ + int iNextIsBenign; /* True if the next call to malloc may fail benignly */ /* ** sqlite3MallocDisallow() increments the following counter. @@ -247,6 +249,7 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ */ static void sqlite3MemsysFailed(void){ mem.iFailCnt = 0; + mem.iBenignFailCnt = 0; } /* @@ -261,6 +264,7 @@ void *sqlite3_malloc(int nByte){ int totalSize; if( nByte<=0 ){ + mem.iNextIsBenign = 0; return 0; } if( mem.mutex==0 ){ @@ -282,6 +286,9 @@ void *sqlite3_malloc(int nByte){ sqlite3MemsysFailed(); /* A place to set a breakpoint */ } mem.iFailCnt++; + if( mem.iNextIsBenign ){ + mem.iBenignFailCnt++; + } }else{ p = malloc(totalSize); mem.iFail--; @@ -329,6 +336,7 @@ void *sqlite3_malloc(int nByte){ p = (void*)pInt; } sqlite3_mutex_leave(mem.mutex); + mem.iNextIsBenign = 0; return p; } @@ -475,16 +483,26 @@ void sqlite3_memdebug_dump(const char *zFilename){ ** This routine returns the number of simulated failures that have ** occurred since the previous call. */ -int sqlite3_memdebug_fail(int iFail, int iRepeat){ +int sqlite3_memdebug_fail(int iFail, int iRepeat, int *piBenign){ int n = mem.iFailCnt; + if( piBenign ){ + *piBenign = mem.iBenignFailCnt; + } mem.iFail = iFail+1; if( iRepeat>=0 ){ mem.iReset = iRepeat; } mem.iFailCnt = 0; + mem.iBenignFailCnt = 0; return n; } +void sqlite3MallocBenignFailure(int isBenign){ + if( isBenign ){ + mem.iNextIsBenign = 1; + } +} + /* ** The following two routines are used to assert that no memory ** allocations occur between one call and the next. The use of diff --git a/src/pager.c b/src/pager.c index 9bbb640ea..5901ca1ee 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.379 2007/08/28 22:24:35 drh Exp $ +** @(#) $Id: pager.c,v 1.380 2007/08/29 12:31:27 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -699,6 +699,7 @@ static void pager_resize_hash_table(Pager *pPager, int N){ PgHdr **aHash, *pPg; assert( N>0 && (N&(N-1))==0 ); pagerLeave(pPager); + sqlite3MallocBenignFailure((int)pPager->aHash); aHash = sqlite3MallocZero( sizeof(aHash[0])*N ); pagerEnter(pPager); if( aHash==0 ){ @@ -2266,22 +2267,32 @@ void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*,int)){ } /* -** Set the page size. Return the new size. If the suggest new page -** size is inappropriate, then an alternative page size is selected -** and returned. +** Set the page size to *pPageSize. If the suggest new page size is +** inappropriate, then an alternative page size is set to that +** value before returning. */ -int sqlite3PagerSetPagesize(Pager *pPager, int pageSize){ +int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize){ + int rc = SQLITE_OK; + u16 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); - if( pageSize && !pPager->memDb && pPager->nRef==0 ){ - pagerEnter(pPager); - pager_reset(pPager); - pPager->pageSize = pageSize; - setSectorSize(pPager); - pagerLeave(pPager); - sqlite3_free(pPager->pTmpSpace); - pPager->pTmpSpace = sqlite3_malloc(pageSize); + if( pageSize && pageSize!=pPager->pageSize + && !pPager->memDb && pPager->nRef==0 + ){ + char *pNew = (char *)sqlite3_malloc(pageSize); + if( !pNew ){ + rc = SQLITE_NOMEM; + }else{ + pagerEnter(pPager); + pager_reset(pPager); + pPager->pageSize = pageSize; + setSectorSize(pPager); + sqlite3_free(pPager->pTmpSpace); + pPager->pTmpSpace = pNew; + pagerLeave(pPager); + } } - return pPager->pageSize; + *pPageSize = pPager->pageSize; + return rc; } /* @@ -3267,7 +3278,7 @@ static int pagerSharedLock(Pager *pPager){ int fout = 0; int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL; assert( !pPager->tempFile ); - rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags,&fout); + rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, &fout); assert( rc!=SQLITE_OK || pPager->jfd->pMethods ); if( fout&SQLITE_OPEN_READONLY ){ rc = SQLITE_BUSY; @@ -3276,7 +3287,7 @@ static int pagerSharedLock(Pager *pPager){ } if( rc!=SQLITE_OK ){ pager_unlock(pPager); - return SQLITE_BUSY; + return (rc==SQLITE_NOMEM?rc:SQLITE_BUSY); } pPager->journalOpen = 1; pPager->journalStarted = 0; diff --git a/src/pager.h b/src/pager.h index 41d7f66c8..7402dd74e 100644 --- a/src/pager.h +++ b/src/pager.h @@ -13,7 +13,7 @@ ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** -** @(#) $Id: pager.h,v 1.63 2007/08/28 22:24:35 drh Exp $ +** @(#) $Id: pager.h,v 1.64 2007/08/29 12:31:27 danielk1977 Exp $ */ #ifndef _PAGER_H_ @@ -58,7 +58,7 @@ int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char *, int, int); void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler); void sqlite3PagerSetDestructor(Pager*, void(*)(DbPage*,int)); void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int)); -int sqlite3PagerSetPagesize(Pager*, int); +int sqlite3PagerSetPagesize(Pager*, u16*); int sqlite3PagerMaxPageCount(Pager*, int); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); void sqlite3PagerSetCachesize(Pager*, int); diff --git a/src/prepare.c b/src/prepare.c index cf6be6a3a..c7f2462f8 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -13,7 +13,7 @@ ** interface, and routines that contribute to loading the database schema ** from disk. ** -** $Id: prepare.c,v 1.59 2007/08/29 00:33:07 drh Exp $ +** $Id: prepare.c,v 1.60 2007/08/29 12:31:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -182,7 +182,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0); if( rc ){ sqlite3SafetyOn(db); - return initData.rc; + rc = initData.rc; + goto error_out; } pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); if( pTab ){ @@ -204,7 +205,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); sqlite3BtreeLeave(pDb->pBt); - return rc; + goto error_out; } /* Get the database meta information. @@ -233,7 +234,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); sqlite3BtreeCloseCursor(curMain); sqlite3BtreeLeave(pDb->pBt); - return rc; + goto error_out; } }else{ memset(meta, 0, sizeof(meta)); @@ -329,6 +330,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ rc = SQLITE_OK; } sqlite3BtreeLeave(pDb->pBt); + +error_out: + if( rc==SQLITE_NOMEM ){ + db->mallocFailed = 1; + } return rc; } @@ -422,6 +428,9 @@ static int schemaIsValid(sqlite3 *db){ } sqlite3BtreeCloseCursor(curTemp); } + if( rc==SQLITE_NOMEM ){ + db->mallocFailed = 1; + } } return allOk; } diff --git a/src/printf.c b/src/printf.c index 37390a5f0..d59c8fd7f 100644 --- a/src/printf.c +++ b/src/printf.c @@ -789,7 +789,9 @@ static char *base_vprintf( memcpy(sM.zText, sM.zBase, sM.nChar+1); } }else if( sM.nAlloc>sM.nChar+10 ){ - char *zNew = xRealloc(sM.zText, sM.nChar+1); + char *zNew; + sqlite3MallocBenignFailure(1); + zNew = xRealloc(sM.zText, sM.nChar+1); if( zNew ){ sM.zText = zNew; } diff --git a/src/select.c b/src/select.c index 7cf96bb1c..8383e2be3 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.356 2007/08/16 10:09:03 danielk1977 Exp $ +** $Id: select.c,v 1.357 2007/08/29 12:31:27 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -60,7 +60,7 @@ Select *sqlite3SelectNew( memset(pNew, 0, sizeof(*pNew)); } if( pEList==0 ){ - pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(TK_ALL,0,0,0), 0); + pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0,0,0), 0); } pNew->pEList = pEList; pNew->pSrc = pSrc; @@ -1364,12 +1364,12 @@ static int prepSelectStmt(Parse *pParse, Select *p){ continue; } } - pRight = sqlite3Expr(TK_ID, 0, 0, 0); + pRight = sqlite3PExpr(pParse, TK_ID, 0, 0, 0); if( pRight==0 ) break; setQuotedToken(pParse, &pRight->token, zName); if( zTabName && (longNames || pTabList->nSrc>1) ){ - Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, 0); - pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0); + Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, 0); + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); if( pExpr==0 ) break; setQuotedToken(pParse, &pLeft->token, zTabName); setToken(&pExpr->span, diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 0bfdb7897..46d5d6048 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.246 2007/08/28 15:47:45 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.247 2007/08/29 12:31:28 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -2414,6 +2414,7 @@ void sqlite3_result_double(sqlite3_context*, double); void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int); void sqlite3_result_error_toobig(sqlite3_context*); +void sqlite3_result_error_nomem(sqlite3_context*); void sqlite3_result_int(sqlite3_context*, int); void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); void sqlite3_result_null(sqlite3_context*); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index ef69cb639..29cf1022a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.604 2007/08/28 16:34:43 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.605 2007/08/29 12:31:28 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1542,6 +1542,7 @@ char *sqlite3StrNDup(const char*, int); char *sqlite3DbStrDup(sqlite3*,const char*); char *sqlite3DbStrNDup(sqlite3*,const char*, int); void *sqlite3DbReallocOrFree(sqlite3 *, void *, int); +void *sqlite3DbRealloc(sqlite3 *, void *, int); char *sqlite3MPrintf(sqlite3*,const char*, ...); char *sqlite3VMPrintf(sqlite3*,const char*, va_list); @@ -1557,7 +1558,7 @@ void sqlite3DequoteExpr(sqlite3*, Expr*); int sqlite3KeywordCode(const unsigned char*, int); int sqlite3RunParser(Parse*, const char*, char **); void sqlite3FinishCoding(Parse*); -Expr *sqlite3Expr(int, Expr*, Expr*, const Token*); +Expr *sqlite3Expr(sqlite3*, int, Expr*, Expr*, const Token*); Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*); Expr *sqlite3RegisterExpr(Parse*,Token*); Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); @@ -1832,9 +1833,11 @@ void sqlite3Parser(void*, int, Token, Parse*); #ifdef SQLITE_MEMDEBUG void sqlite3MallocDisallow(void); void sqlite3MallocAllow(void); + void sqlite3MallocBenignFailure(int); #else # define sqlite3MallocDisallow() # define sqlite3MallocAllow() +# define sqlite3MallocBenignFailure(x) #endif diff --git a/src/test2.c b/src/test2.c index 9480f8f7f..ded9547ce 100644 --- a/src/test2.c +++ b/src/test2.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test2.c,v 1.50 2007/08/21 10:44:16 drh Exp $ +** $Id: test2.c,v 1.51 2007/08/29 12:31:28 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -66,6 +66,7 @@ static int pager_open( int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ + u16 pageSize; Pager *pPager; int nPage; int rc; @@ -82,7 +83,8 @@ static int pager_open( return TCL_ERROR; } sqlite3PagerSetCachesize(pPager, nPage); - sqlite3PagerSetPagesize(pPager, test_pagesize); + pageSize = test_pagesize; + sqlite3PagerSetPagesize(pPager, &pageSize); sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; diff --git a/src/test3.c b/src/test3.c index fcfa37caf..d35efaab4 100644 --- a/src/test3.c +++ b/src/test3.c @@ -13,9 +13,10 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test3.c,v 1.82 2007/08/24 16:08:29 drh Exp $ +** $Id: test3.c,v 1.83 2007/08/29 12:31:28 danielk1977 Exp $ */ #include "sqliteInt.h" +#include "btreeInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> @@ -530,6 +531,7 @@ static int btree_pager_stats( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3_mutex_enter(pBt->pSqlite->mutex); sqlite3BtreeEnter(pBt); a = sqlite3PagerStats(sqlite3BtreePager(pBt)); for(i=0; i<11; i++){ @@ -543,6 +545,7 @@ static int btree_pager_stats( Tcl_AppendElement(interp, zBuf); } sqlite3BtreeLeave(pBt); + sqlite3_mutex_leave(pBt->pSqlite->mutex); return TCL_OK; } @@ -1493,7 +1496,11 @@ static int btree_set_cache_size( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; + + sqlite3_mutex_enter(pBt->pSqlite->mutex); sqlite3BtreeSetCacheSize(pBt, nCache); + sqlite3_mutex_leave(pBt->pSqlite->mutex); + return TCL_OK; } diff --git a/src/test8.c b/src/test8.c index b27bd31c4..1b7c6957f 100644 --- a/src/test8.c +++ b/src/test8.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test8.c,v 1.54 2007/08/25 13:37:49 danielk1977 Exp $ +** $Id: test8.c,v 1.55 2007/08/29 12:31:28 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -361,6 +361,7 @@ static int echoConstructor( sqlite3_vtab **ppVtab, char **pzErr ){ + int rc; int i; echo_vtab *pVtab; @@ -404,9 +405,10 @@ static int echoConstructor( ** structure. If an error occurs, delete the sqlite3_vtab structure and ** return an error code. */ - if( echoDeclareVtab(pVtab, db) ){ + rc = echoDeclareVtab(pVtab, db); + if( rc!=SQLITE_OK ){ echoDestructor((sqlite3_vtab *)pVtab); - return SQLITE_ERROR; + return rc; } /* Success. Set *ppVtab and return */ @@ -646,14 +648,25 @@ static int echoFilter( ** If the third argument, doFree, is true, then sqlite3_free() is ** also called to free the buffer pointed to by zAppend. */ -static void string_concat(char **pzStr, char *zAppend, int doFree){ +static void string_concat(char **pzStr, char *zAppend, int doFree, int *pRc){ char *zIn = *pzStr; - if( zIn ){ - char *zTemp = zIn; - zIn = sqlite3_mprintf("%s%s", zIn, zAppend); - sqlite3_free(zTemp); + if( !zAppend && doFree && *pRc==SQLITE_OK ){ + *pRc = SQLITE_NOMEM; + } + if( *pRc!=SQLITE_OK ){ + sqlite3_free(zIn); + zIn = 0; }else{ - zIn = sqlite3_mprintf("%s", zAppend); + if( zIn ){ + char *zTemp = zIn; + zIn = sqlite3_mprintf("%s%s", zIn, zAppend); + sqlite3_free(zTemp); + }else{ + zIn = sqlite3_mprintf("%s", zAppend); + } + if( !zIn ){ + *pRc = SQLITE_NOMEM; + } } *pzStr = zIn; if( doFree ){ @@ -709,6 +722,9 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ useCost = 1; } else { zQuery = sqlite3_mprintf("SELECT count(*) FROM %Q", pVtab->zTableName); + if( !zQuery ){ + return SQLITE_NOMEM; + } rc = sqlite3_prepare(pVtab->db, zQuery, -1, &pStmt, 0); sqlite3_free(zQuery); if( rc!=SQLITE_OK ){ @@ -723,6 +739,9 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ } zQuery = sqlite3_mprintf("SELECT rowid, * FROM %Q", pVtab->zTableName); + if( !zQuery ){ + return SQLITE_NOMEM; + } for(ii=0; ii<pIdxInfo->nConstraint; ii++){ const struct sqlite3_index_constraint *pConstraint; struct sqlite3_index_constraint_usage *pUsage; @@ -759,7 +778,7 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ } else { zNew = sqlite3_mprintf(" %s %s %s ?", zSep, zCol, zOp); } - string_concat(&zQuery, zNew, 1); + string_concat(&zQuery, zNew, 1, &rc); zSep = "AND"; pUsage->argvIndex = ++nArg; @@ -779,7 +798,7 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ zCol = "rowid"; } zNew = sqlite3_mprintf(" ORDER BY %s %s", zCol, zDir); - string_concat(&zQuery, zNew, 1); + string_concat(&zQuery, zNew, 1, &rc); pIdxInfo->orderByConsumed = 1; } @@ -787,7 +806,7 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ appendToEchoModule(pVtab->interp, zQuery); if( !zQuery ){ - return SQLITE_NOMEM; + return rc; } pIdxInfo->idxNum = hashString(zQuery); pIdxInfo->idxStr = zQuery; @@ -843,26 +862,32 @@ int echoUpdate( if( nData>1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){ char *zSep = " SET"; z = sqlite3_mprintf("UPDATE %Q", pVtab->zTableName); + if( !z ){ + rc = SQLITE_NOMEM; + } bindArgOne = (apData[1] && sqlite3_value_type(apData[1])==SQLITE_INTEGER); bindArgZero = 1; if( bindArgOne ){ - string_concat(&z, " SET rowid=?1 ", 0); + string_concat(&z, " SET rowid=?1 ", 0, &rc); zSep = ","; } for(i=2; i<nData; i++){ if( apData[i]==0 ) continue; string_concat(&z, sqlite3_mprintf( - "%s %Q=?%d", zSep, pVtab->aCol[i-2], i), 1); + "%s %Q=?%d", zSep, pVtab->aCol[i-2], i), 1, &rc); zSep = ","; } - string_concat(&z, sqlite3_mprintf(" WHERE rowid=?%d", nData), 1); + string_concat(&z, sqlite3_mprintf(" WHERE rowid=?%d", nData), 1, &rc); } /* If apData[0] is an integer and nData==1 then do a DELETE */ else if( nData==1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){ z = sqlite3_mprintf("DELETE FROM %Q WHERE rowid = ?1", pVtab->zTableName); + if( !z ){ + rc = SQLITE_NOMEM; + } bindArgZero = 1; } @@ -873,24 +898,27 @@ int echoUpdate( char *zValues = 0; zInsert = sqlite3_mprintf("INSERT INTO %Q (", pVtab->zTableName); + if( !zInsert ){ + rc = SQLITE_NOMEM; + } if( sqlite3_value_type(apData[1])==SQLITE_INTEGER ){ bindArgOne = 1; zValues = sqlite3_mprintf("?"); - string_concat(&zInsert, "rowid", 0); + string_concat(&zInsert, "rowid", 0, &rc); } assert((pVtab->nCol+2)==nData); for(ii=2; ii<nData; ii++){ string_concat(&zInsert, - sqlite3_mprintf("%s%Q", zValues?", ":"", pVtab->aCol[ii-2]), 1); + sqlite3_mprintf("%s%Q", zValues?", ":"", pVtab->aCol[ii-2]), 1, &rc); string_concat(&zValues, - sqlite3_mprintf("%s?%d", zValues?", ":"", ii), 1); + sqlite3_mprintf("%s?%d", zValues?", ":"", ii), 1, &rc); } - string_concat(&z, zInsert, 1); - string_concat(&z, ") VALUES(", 0); - string_concat(&z, zValues, 1); - string_concat(&z, ")", 0); + string_concat(&z, zInsert, 1, &rc); + string_concat(&z, ") VALUES(", 0, &rc); + string_concat(&z, zValues, 1, &rc); + string_concat(&z, ")", 0, &rc); } /* Anything else is an error */ @@ -899,7 +927,9 @@ int echoUpdate( return SQLITE_ERROR; } - rc = sqlite3_prepare(db, z, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare(db, z, -1, &pStmt, 0); + } assert( rc!=SQLITE_OK || pStmt ); sqlite3_free(z); if( rc==SQLITE_OK ) { @@ -935,43 +965,50 @@ static int echoTransactionCall(sqlite3_vtab *tab, const char *zCall){ appendToEchoModule(pVtab->interp, zCall); appendToEchoModule(pVtab->interp, z); sqlite3_free(z); - return SQLITE_OK; + return (z?SQLITE_OK:SQLITE_NOMEM); } static int echoBegin(sqlite3_vtab *tab){ + int rc; echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; - echoTransactionCall(tab, "xBegin"); + rc = echoTransactionCall(tab, "xBegin"); - /* Check if the $::echo_module_begin_fail variable is defined. If it is, - ** and it is set to the name of the real table underlying this virtual - ** echo module table, then cause this xSync operation to fail. - */ - zVal = Tcl_GetVar(interp, "echo_module_begin_fail", TCL_GLOBAL_ONLY); - if( zVal && 0==strcmp(zVal, pVtab->zTableName) ){ - return SQLITE_ERROR; + if( rc==SQLITE_OK ){ + /* Check if the $::echo_module_begin_fail variable is defined. If it is, + ** and it is set to the name of the real table underlying this virtual + ** echo module table, then cause this xSync operation to fail. + */ + zVal = Tcl_GetVar(interp, "echo_module_begin_fail", TCL_GLOBAL_ONLY); + if( zVal && 0==strcmp(zVal, pVtab->zTableName) ){ + rc = SQLITE_ERROR; + } } - return SQLITE_OK; + return rc; } static int echoSync(sqlite3_vtab *tab){ + int rc; echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; - echoTransactionCall(tab, "xSync"); + rc = echoTransactionCall(tab, "xSync"); - /* Check if the $::echo_module_sync_fail variable is defined. If it is, - ** and it is set to the name of the real table underlying this virtual - ** echo module table, then cause this xSync operation to fail. - */ - zVal = Tcl_GetVar(interp, "echo_module_sync_fail", TCL_GLOBAL_ONLY); - if( zVal && 0==strcmp(zVal, pVtab->zTableName) ){ - return -1; + if( rc==SQLITE_OK ){ + /* Check if the $::echo_module_sync_fail variable is defined. If it is, + ** and it is set to the name of the real table underlying this virtual + ** echo module table, then cause this xSync operation to fail. + */ + zVal = Tcl_GetVar(interp, "echo_module_sync_fail", TCL_GLOBAL_ONLY); + if( zVal && 0==strcmp(zVal, pVtab->zTableName) ){ + rc = -1; + } } - return SQLITE_OK; + return rc; } static int echoCommit(sqlite3_vtab *tab){ + sqlite3MallocBenignFailure(1); return echoTransactionCall(tab, "xCommit"); } static int echoRollback(sqlite3_vtab *tab){ diff --git a/src/test_malloc.c b/src/test_malloc.c index d09f3e899..a0b03c370 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.5 2007/08/24 03:51:34 drh Exp $ +** $Id: test_malloc.c,v 1.6 2007/08/29 12:31:28 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -245,7 +245,12 @@ static int test_memdebug_dump( /* -** Usage: sqlite3_memdebug_fail COUNTER ?REPEAT? +** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? +** +** where options are: +** +** -repeat <boolean> +** -benigncnt <varname> ** ** Arrange for a simulated malloc() failure after COUNTER successes. ** If REPEAT is 1 then all subsequent malloc()s fail. If REPEAT is @@ -263,23 +268,56 @@ static int test_memdebug_fail( int objc, Tcl_Obj *CONST objv[] ){ + int ii; int iFail; - int iRepeat; + int iRepeat = -1; + int iBenignCnt; + Tcl_Obj *pBenignCnt = 0; + int nFail = 0; - if( objc!=3 && objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?REPEAT?"); + + if( objc<2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; - if( objc==3 ){ - if( Tcl_GetIntFromObj(interp, objv[2], &iRepeat) ) return TCL_ERROR; - }else{ - iRepeat = -1; + + for(ii=2; ii<objc; ii+=2){ + int nOption; + char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption); + char *zErr = 0; + + if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){ + if( ii==(objc-1) ){ + zErr = "option requires an argument: "; + }else{ + if( Tcl_GetIntFromObj(interp, objv[ii+1], &iRepeat) ){ + return TCL_ERROR; + } + } + }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){ + if( ii==(objc-1) ){ + zErr = "option requires an argument: "; + }else{ + pBenignCnt = objv[ii+1]; + } + }else{ + zErr = "unknown option: "; + } + + if( zErr ){ + Tcl_AppendResult(interp, zErr, zOption, 0); + return TCL_ERROR; + } } + #ifdef SQLITE_MEMDEBUG { - extern int sqlite3_memdebug_fail(int,int); - nFail = sqlite3_memdebug_fail(iFail, iRepeat); + extern int sqlite3_memdebug_fail(int,int,int*); + nFail = sqlite3_memdebug_fail(iFail, iRepeat, &iBenignCnt); + if( pBenignCnt ){ + Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(iBenignCnt), 0); + } } #endif Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); diff --git a/src/vacuum.c b/src/vacuum.c index ec396c236..73cccba26 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -14,7 +14,7 @@ ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** -** $Id: vacuum.c,v 1.72 2007/08/24 11:43:37 drh Exp $ +** $Id: vacuum.c,v 1.73 2007/08/29 12:31:28 danielk1977 Exp $ */ #include "sqliteInt.h" #include "vdbeInt.h" @@ -25,6 +25,9 @@ */ static int execSql(sqlite3 *db, const char *zSql){ sqlite3_stmt *pStmt; + if( !zSql ){ + return SQLITE_NOMEM; + } if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){ return sqlite3_errcode(db); } diff --git a/src/vdbe.c b/src/vdbe.c index 9f9e24044..d0baf886b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.646 2007/08/28 23:28:08 drh Exp $ +** $Id: vdbe.c,v 1.647 2007/08/29 12:31:28 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -2637,7 +2637,8 @@ case OP_VerifyCookie: { /* no-push */ iMeta = 0; } if( rc==SQLITE_OK && iMeta!=pOp->p2 ){ - sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0); + sqlite3_free(p->zErrMsg); + p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); /* If the schema-cookie from the database file matches the cookie ** stored with the in-memory representation of the schema, do ** not reload the schema from the database file. diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 1ad103e82..6716256c0 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -234,6 +234,13 @@ void sqlite3_result_error_toobig(sqlite3_context *pCtx){ sqlite3VdbeMemSetZeroBlob(&pCtx->s, SQLITE_MAX_LENGTH+1); } +/* An SQLITE_NOMEM error. */ +void sqlite3_result_error_nomem(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); + sqlite3VdbeMemSetNull(&pCtx->s); + pCtx->isError = 1; + pCtx->s.db->mallocFailed = 1; +} /* ** Execute the statement pStmt, either until a row of data is ready, the diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 5b58588a6..55cb88ab3 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -115,15 +115,13 @@ static void resizeOpArray(Vdbe *p, int N){ VdbeOp *pNew; int nNew = N + 100*(!runMode); int oldSize = p->nOpAlloc; - pNew = sqlite3_realloc(p->aOp, nNew*sizeof(Op)); + pNew = sqlite3DbRealloc(p->db, p->aOp, nNew*sizeof(Op)); if( pNew ){ p->nOpAlloc = nNew; p->aOp = pNew; if( nNew>oldSize ){ memset(&p->aOp[oldSize], 0, (nNew-oldSize)*sizeof(Op)); } - }else{ - p->db->mallocFailed = 1; } } } diff --git a/src/vdbemem.c b/src/vdbemem.c index 3e3c89005..ef96b2fa2 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -260,9 +260,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ if( pMem->flags & MEM_Short ){ pMem->z = pMem->zShort; } - if( ctx.isError ){ - rc = SQLITE_ERROR; - } + rc = (ctx.isError?SQLITE_ERROR:SQLITE_OK); } return rc; } diff --git a/src/vtab.c b/src/vtab.c index 70d7efc17..7559bdefa 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to help implement virtual tables. ** -** $Id: vtab.c,v 1.54 2007/08/24 03:51:34 drh Exp $ +** $Id: vtab.c,v 1.55 2007/08/29 12:31:29 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" @@ -296,6 +296,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ int nName = strlen(zName) + 1; pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); if( pOld ){ + db->mallocFailed = 1; assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } diff --git a/src/where.c b/src/where.c index 65c7dbfe2..6f93f67ed 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.257 2007/08/16 11:36:15 danielk1977 Exp $ +** $Id: where.c,v 1.258 2007/08/29 12:31:29 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -791,7 +791,7 @@ static void exprAnalyze( for(i=0; i<2; i++){ Expr *pNewExpr; int idxNew; - pNewExpr = sqlite3Expr(ops[i], sqlite3ExprDup(db, pExpr->pLeft), + pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft), sqlite3ExprDup(db, pList->a[i].pExpr), 0); idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); exprAnalyze(pSrc, pWC, idxNew); @@ -858,7 +858,7 @@ static void exprAnalyze( } assert( pLeft!=0 ); pDup = sqlite3ExprDup(db, pLeft); - pNew = sqlite3Expr(TK_IN, pDup, 0, 0); + pNew = sqlite3Expr(db, TK_IN, pDup, 0, 0); if( pNew ){ int idxNew; transferJoinMarkings(pNew, pExpr); @@ -934,7 +934,7 @@ or_not_possible: prereqColumn = exprTableUsage(pMaskSet, pLeft); if( (prereqExpr & prereqColumn)==0 ){ Expr *pNewExpr; - pNewExpr = sqlite3Expr(TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0); + pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0); idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = prereqExpr; |