aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordanielk1977 <danielk1977@noemail.net>2007-08-29 12:31:25 +0000
committerdanielk1977 <danielk1977@noemail.net>2007-08-29 12:31:25 +0000
commita1644fd86384de5f37fc42a7fb871a8c9a12dab5 (patch)
treeccd22487d7d42e8de86c109311e9d8aef043154a /src
parent1fee73e74acab48412a3c596d4cd68deecadeef6 (diff)
downloadsqlite-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.c13
-rw-r--r--src/build.c14
-rw-r--r--src/callback.c10
-rw-r--r--src/expr.c30
-rw-r--r--src/func.c76
-rw-r--r--src/hash.c10
-rw-r--r--src/legacy.c5
-rw-r--r--src/malloc.c36
-rw-r--r--src/mem2.c24
-rw-r--r--src/pager.c43
-rw-r--r--src/pager.h4
-rw-r--r--src/prepare.c17
-rw-r--r--src/printf.c4
-rw-r--r--src/select.c10
-rw-r--r--src/sqlite.h.in3
-rw-r--r--src/sqliteInt.h7
-rw-r--r--src/test2.c6
-rw-r--r--src/test3.c9
-rw-r--r--src/test8.c121
-rw-r--r--src/test_malloc.c60
-rw-r--r--src/vacuum.c5
-rw-r--r--src/vdbe.c5
-rw-r--r--src/vdbeapi.c7
-rw-r--r--src/vdbeaux.c4
-rw-r--r--src/vdbemem.c4
-rw-r--r--src/vtab.c3
-rw-r--r--src/where.c8
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;