]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
better handling of out-of-memory errors (CVS 207)
authordrh <drh@noemail.net>
Wed, 11 Apr 2001 14:28:42 +0000 (14:28 +0000)
committerdrh <drh@noemail.net>
Wed, 11 Apr 2001 14:28:42 +0000 (14:28 +0000)
FossilOrigin-Name: 86b30cd0975dfea9424b9f9f0d4194aa71ce508b

27 files changed:
manifest
manifest.uuid
src/build.c
src/dbbe.c
src/dbbegdbm.c
src/dbbemem.c
src/delete.c
src/expr.c
src/insert.c
src/main.c
src/parse.y
src/printf.c
src/select.c
src/shell.c
src/sqliteInt.h
src/table.c
src/test1.c
src/tokenize.c
src/update.c
src/util.c
src/vdbe.c
src/where.c
test/all.test
test/printf.test
test/tableapi.test
test/tester.tcl
www/changes.tcl

index ca68d1c0ebe6c338e6ddc16444efe02d636fe814..f7b6fd060c2ec9478985bb5eae0d9d2a74102c07 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Added\snew\stests\s(CVS\s206)
-D 2001-04-07T15:24:33
+C better\shandling\sof\sout-of-memory\serrors\s(CVS\s207)
+D 2001-04-11T14:28:42
 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
 F Makefile.in 4775f7fd1ed543606bb24fa3fada1bc90a23a6b9
 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@@ -9,12 +9,12 @@ F configure.in 6940e3f88bf3d28a10c73b06ab99fd3a7e039a61
 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
 F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e
 F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
-F src/build.c 4c5eede16695d5e74bb3004e51923492b66eae62
-F src/dbbe.c dd318ba657bfc8c2fec00c8cf51ea29dbfd284bf
+F src/build.c 6afbb6106c1e8c771ffcb81107b755e200310574
+F src/dbbe.c ec82c602c598748204a61a35ab0c31e34ca58223
 F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8
-F src/dbbegdbm.c d044b9e3a463608ac4f35283c78ac372d5da64c6
-F src/dbbemem.c fa84058f79dd5e6af1ccbb0d41c85e05a6bc19ac
-F src/delete.c 7aa9dcb86d5e98c3eb9dee00a459e0ef9b73fbe3
+F src/dbbegdbm.c 9d3a3c18b27f9f2533a3aaa3741e8668bdda7e98
+F src/dbbemem.c b62821ba8cec4b1d7392157e94f72baf1ff015f2
+F src/delete.c 40ddb169ee98013d976b2dadd140d98f7876f54f
 F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a
 F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7
 F src/ex/db.h 3f2933ee20c147fe494835786e4c6f3a562def4e
@@ -23,28 +23,28 @@ F src/ex/dbbemird.c b00aef85656fa0a101dac2c32e12922ad106715a
 F src/ex/pg.c 2bbf6a94f37226d06337868b6bf4d7affc60197f
 F src/ex/pg.h 23a4ac807b0546ec2bb6239ec8bd3e06926572cd
 F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
-F src/expr.c 745383609b65d504a2cc04ac4d9389e9c8e2bc80
-F src/insert.c 4bc1cab84f7805d560a1417734a532843e30b762
-F src/main.c fe5c26620c46770539056525d8a79e3afb6e75e8
+F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16
+F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
+F src/main.c 92ce30a89f622ba36cc8b7d912829e14a480722c
 F src/pager.h 889c5cf517ad30704e295540793c893ac843fd5f
-F src/parse.y 1ba81d3b75f37ca868aa0ab990bb977fd41519eb
-F src/printf.c af0dc65c293427272e1949c7807b1d88f10004fd
+F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
+F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
 F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a
-F src/select.c a6bfdaa92d4614e79bf18129283c5163faa291fc
-F src/shell.c c1785b4af18192056adbe894f8626a7e7bdf47aa
+F src/select.c 52bb7d081ac00dfad3687d52c917d2d90165331d
+F src/shell.c d9c64418765d90909e9e200b207ff9e355afb5c4
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 3e5906f72608f0fd4394dfbb1d7e8d35b8353677
-F src/sqliteInt.h 054c00c2b3deaedf4034b85d69287abeb4c15c96
-F src/table.c 5be76051a8ed6f6bfa641f4adc52529efa34fbf9
+F src/sqliteInt.h fc1000f023b41882bbdb8db4f80172f77b44307b
+F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6
 F src/tclsqlite.c 83dcbf015ea0319c2a97514b8b812a12d621e40a
-F src/test1.c 7d88c76725ce5b881cff2a283662fe068d792002
-F src/tokenize.c 8fc3936eefad84f1fff19e0892ed0542eb9ac7b3
-F src/update.c 8365b3922ea098330d1e20862d6e64911e4e03d0
-F src/util.c aec315b834bad444c9e0e90efd9d2eaeeb37c90c
-F src/vdbe.c 5f5be704686ed328275c35815e39d041a0c6cbb6
+F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4
+F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf
+F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6
+F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc
+F src/vdbe.c ee5a6ab95c8c84497f6685ebde153da6fb06e825
 F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437
-F src/where.c 459bf37ac7849599da400420984b3306484b4cbb
-F test/all.test 15cac2f6b2d4c55bf896212aff3cc9d6597b0490
+F src/where.c 0c542fc44bd85152dfb8507862cfe2e60c629e9f
+F test/all.test 4ba0807feec7f29bf90c4f0ffd10b3801634461d
 F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
 F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c
 F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf
@@ -56,7 +56,7 @@ F test/insert.test dbd3bd189edb61fddbe66c236694ef23352429f1
 F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6
 F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a
 F test/main.test da635f9e078cd21ddf074e727381a715064489ff
-F test/printf.test 18e44e4e154e13cba74d67b85202172d37ddb5ed
+F test/printf.test 4c71871e1a75a2dacb673945fc13ddb30168798f
 F test/rowid.test 128453599def7435e988216f7fe89c7450b8a9a3
 F test/select1.test 824d9d5007dffd6a45edde79e89c0a04c36e3ebe
 F test/select2.test 04ac3bd69298f58c7d0883159bab42ab9ad6021c
@@ -66,9 +66,9 @@ F test/select5.test e2b9d51d88cbd6c307c2c05b0ef55fe7ba811ac2
 F test/sort.test 838cd862642ed9a2c47e1a17b5c33da452b4552e
 F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5
 F test/table.test c1704fead1af27d67850a934d531848ce5bee4a7
-F test/tableapi.test 9ecb98590d1b6ebcb4b791697bd5275e73bba530
+F test/tableapi.test 4778414470ba150983d03b9858334effe720c2e0
 F test/tclsqlite.test d2aa55926874783b2401f0146e839f773c6796e1
-F test/tester.tcl dba25c97cc89f109a9350f12792f17b24202d65f
+F test/tester.tcl 39a707dac2b6048d9c9e07a98d3256d50069fe47
 F test/trans.test 82556605d48f56ad4679e95478d70546a763f26a
 F test/update.test 72c0c93310483b86dc904a992220c5b84c7ce100
 F test/vacuum.test b95d8119a0a83dc6c4ac63888f8872f06199e065
@@ -86,7 +86,7 @@ F www/arch.fig 4f246003b7da23bd63b8b0af0618afb4ee3055c8
 F www/arch.png 8dae0766d42ed3de9ed013c1341a5792bcf633e6
 F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be
 F www/c_interface.tcl ddca19005c47dd5a15882addc02fff5de83d8ed9
-F www/changes.tcl 64e5779a681bda4b34d0403c33aaf8902d8cf056
+F www/changes.tcl cad714ae8d6e5c19e8d14282dbfbe7c61c5cc4ee
 F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
 F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
@@ -97,7 +97,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
 F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
 F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
-P 8f0d98193e4ba913fa31d5f8d5adc46ad9d346a1
-R b4947cdaa9daf5e442bdf2c2d5dbb11c
+P 2507ec40610d8034ccf9dcb58a16934065e6f120
+R 0329ee9c40e806471f7c325d51a23bb6
 U drh
-Z 46e79499f1b58c1b58c6255886d7f82a
+Z 598daf9af8c7873df8fb5f69d495d703
index 153fed2cfea0560a10f304908580b2cd522dc20c..67d0873d5dc0b522fcd7401af233bb9a2efbb900 100644 (file)
@@ -1 +1 @@
-2507ec40610d8034ccf9dcb58a16934065e6f120
\ No newline at end of file
+86b30cd0975dfea9424b9f9f0d4194aa71ce508b
\ No newline at end of file
index 9c71383bd4616e15bccc904b2173c91866361dd2..df2526960b793a81407e8fbab26c9e444ff319d1 100644 (file)
@@ -33,7 +33,7 @@
 **     COPY
 **     VACUUM
 **
-** $Id: build.c,v 1.26 2001/04/04 11:48:57 drh Exp $
+** $Id: build.c,v 1.27 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -49,6 +49,7 @@
 */
 void sqliteExec(Parse *pParse){
   int rc = SQLITE_OK;
+  if( sqlite_malloc_failed ) return;
   if( pParse->pVdbe ){
     if( pParse->explain ){
       rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
@@ -96,8 +97,10 @@ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
 ** text between the two given tokens.
 */
 void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
-  pExpr->span.z = pLeft->z;
-  pExpr->span.n = pRight->n + (int)pRight->z - (int)pLeft->z;
+  if( pExpr ){
+    pExpr->span.z = pLeft->z;
+    pExpr->span.n = pRight->n + (int)pRight->z - (int)pLeft->z;
+  }
 }
 
 /*
@@ -167,13 +170,13 @@ Index *sqliteFindIndex(sqlite *db, char *zName){
 ** Remove the given index from the index hash table, and free
 ** its memory structures.
 **
-** The index is removed from the database hash table, but it is
-** not unlinked from the Table that is being indexed.  Unlinking
-** from the Table must be done by the calling function.
+** The index is removed from the database hash table if db!=NULL.
+** But it is not unlinked from the Table that is being indexed.  
+** Unlinking from the Table must be done by the calling function.
 */
 static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
   int h;
-  if( pIndex->zName ){
+  if( pIndex->zName && db ){
     h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH;
     if( db->apIdxHash[h]==pIndex ){
       db->apIdxHash[h] = pIndex->pHash;
@@ -195,6 +198,11 @@ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
 ** This routine just deletes the data structure.  It does not unlink
 ** the table data structure from the hash table.  But does it destroy
 ** memory structures of the indices associated with the table.
+**
+** Indices associated with the table are unlinked from the "db"
+** data structure if db!=NULL.  If db==NULL, indices attached to
+** the table are deleted, but it is assumed they have already been
+** unlinked.
 */
 void sqliteDeleteTable(sqlite *db, Table *pTable){
   int i;
@@ -236,6 +244,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
 
   pParse->sFirstToken = *pStart;
   zName = sqliteTableNameFromToken(pName);
+  if( zName==0 ) return;
   pTable = sqliteFindTable(pParse->db, zName);
   if( pTable!=0 ){
     sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
@@ -252,11 +261,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
     return;
   }
   pTable = sqliteMalloc( sizeof(Table) );
-  if( pTable==0 ){
-    sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
-    pParse->nErr++;
-    return;
-  }
+  if( pTable==0 ) return;
   pTable->zName = zName;
   pTable->pHash = 0;
   pTable->nCol = 0;
@@ -275,10 +280,10 @@ void sqliteAddColumn(Parse *pParse, Token *pName){
   if( (p = pParse->pNewTable)==0 ) return;
   if( (p->nCol & 0x7)==0 ){
     p->aCol = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0]));
-  }
-  if( p->aCol==0 ){
-    p->nCol = 0;
-    return;
+    if( p->aCol==0 ){
+      p->nCol = 0;
+      return;
+    }
   }
   memset(&p->aCol[p->nCol], 0, sizeof(p->aCol[0]));
   pz = &p->aCol[p->nCol++].zName;
@@ -323,13 +328,14 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
   int h;
   int addMeta;       /* True to insert a meta records into the file */
 
-  if( pParse->nErr ) return;
+  if( pEnd==0 || pParse->nErr || sqlite_malloc_failed ) return;
   p = pParse->pNewTable;
-  addMeta =  p!=0 && pParse->db->nTable==1;
+  if( p==0 ) return;
+  addMeta =  pParse->db->nTable==1;
 
   /* Add the table to the in-memory representation of the database
   */
-  if( p!=0 && pParse->explain==0 ){
+  if( pParse->explain==0 ){
     h = sqliteHashNoCase(p->zName, 0) % N_HASH;
     p->pHash = pParse->db->apTblHash[h];
     pParse->db->apTblHash[h] = p;
@@ -381,8 +387,11 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
 ** an error for the parser to find and return NULL.
 */
 Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
-  char *zName = sqliteTableNameFromToken(pTok);
-  Table *pTab = sqliteFindTable(pParse->db, zName);
+  char *zName;
+  Table *pTab;
+  zName = sqliteTableNameFromToken(pTok);
+  if( zName==0 ) return 0;
+  pTab = sqliteFindTable(pParse->db, zName);
   sqliteFree(zName);
   if( pTab==0 ){
     sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, 
@@ -401,6 +410,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
   Vdbe *v;
   int base;
 
+  if( pParse->nErr || sqlite_malloc_failed ) return;
   pTable = sqliteTableFromToken(pParse, pName);
   if( pTable==0 ) return;
   if( pTable->readOnly ){
@@ -486,6 +496,8 @@ void sqliteCreateIndex(
   int i, j, h;
   Token nullId;    /* Fake token for an empty ID list */
 
+  if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
+
   /*
   ** Find the table that is to be indexed.  Return early if not found.
   */
@@ -512,6 +524,7 @@ void sqliteCreateIndex(
     zName = 0;
     sqliteSetString(&zName, pTab->zName, "__primary_key", 0);
   }
+  if( zName==0 ) goto exit_create_index;
   if( sqliteFindIndex(pParse->db, zName) ){
     sqliteSetString(&pParse->zErrMsg, "index ", zName, 
        " already exists", 0);
@@ -541,11 +554,7 @@ void sqliteCreateIndex(
   */
   pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
                         sizeof(int)*pList->nId );
-  if( pIndex==0 ){
-    sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
-    pParse->nErr++;
-    goto exit_create_index;
-  }
+  if( pIndex==0 ) goto exit_create_index;
   pIndex->aiColumn = (int*)&pIndex[1];
   pIndex->zName = (char*)&pIndex->aiColumn[pList->nId];
   strcpy(pIndex->zName, zName);
@@ -656,7 +665,9 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
   char *zName;
   Vdbe *v;
 
+  if( pParse->nErr || sqlite_malloc_failed ) return;
   zName = sqliteTableNameFromToken(pName);
+  if( zName==0 ) return;
   pIndex = sqliteFindIndex(pParse->db, zName);
   sqliteFree(zName);
   if( pIndex==0 ){
@@ -714,8 +725,8 @@ ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
   int i;
   if( pList==0 ){
     pList = sqliteMalloc( sizeof(ExprList) );
+    if( pList==0 ) return 0;
   }
-  if( pList==0 ) return 0;
   if( (pList->nExpr & 7)==0 ){
     int n = pList->nExpr + 8;
     pList->a = sqliteRealloc(pList->a, n*sizeof(pList->a[0]));
@@ -751,6 +762,8 @@ void sqliteExprListDelete(ExprList *pList){
 /*
 ** Append a new element to the given IdList.  Create a new IdList if
 ** need be.
+**
+** A new IdList is returned, or NULL if malloc() fails.
 */
 IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
   if( pList==0 ){
@@ -761,13 +774,20 @@ IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
     pList->a = sqliteRealloc(pList->a, (pList->nId+8)*sizeof(pList->a[0]) );
     if( pList->a==0 ){
       pList->nId = 0;
-      return pList;
+      sqliteIdListDelete(pList);
+      return 0;
     }
   }
   memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
   if( pToken ){
-    sqliteSetNString(&pList->a[pList->nId].zName, pToken->z, pToken->n, 0);
-    sqliteDequote(pList->a[pList->nId].zName);
+    char **pz = &pList->a[pList->nId].zName;
+    sqliteSetNString(pz, pToken->z, pToken->n, 0);
+    if( *pz==0 ){
+      sqliteIdListDelete(pList);
+      return 0;
+    }else{
+      sqliteDequote(*pz);
+    }
   }
   pList->nId++;
   return pList;
@@ -793,6 +813,11 @@ void sqliteIdListDelete(IdList *pList){
   for(i=0; i<pList->nId; i++){
     sqliteFree(pList->a[i].zName);
     sqliteFree(pList->a[i].zAlias);
+    if( pList->a[i].pSelect ){
+      sqliteFree(pList->a[i].zName);
+      sqliteSelectDelete(pList->a[i].pSelect);
+      sqliteDeleteTable(0, pList->a[i].pTab);
+    }
   }
   sqliteFree(pList->a);
   sqliteFree(pList);
@@ -824,6 +849,7 @@ void sqliteCopy(
   Index *pIdx;
 
   zTab = sqliteTableNameFromToken(pTableName);
+  if( sqlite_malloc_failed || zTab==0 ) goto copy_cleanup;
   pTab = sqliteFindTable(pParse->db, zTab);
   sqliteFree(zTab);
   if( pTab==0 ){
@@ -891,6 +917,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
   char *zName;
   Vdbe *v;
 
+  if( pParse->nErr || sqlite_malloc_failed ) return;
   if( pTableName ){
     zName = sqliteTableNameFromToken(pTableName);
   }else{
@@ -933,6 +960,7 @@ void sqliteBeginTransaction(Parse *pParse){
   DbbeMethods *pM;
   sqlite *db;
   if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
+  if( pParse->nErr || sqlite_malloc_failed ) return;
   if( db->flags & SQLITE_InTrans ) return;
   pM = pParse->db->pBe->x;
   if( pM && pM->BeginTransaction ){
@@ -953,6 +981,7 @@ void sqliteCommitTransaction(Parse *pParse){
   DbbeMethods *pM;
   sqlite *db;
   if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
+  if( pParse->nErr || sqlite_malloc_failed ) return;
   if( (db->flags & SQLITE_InTrans)==0 ) return;
   pM = pParse->db->pBe->x;
   if( pM && pM->Commit ){
@@ -973,6 +1002,7 @@ void sqliteRollbackTransaction(Parse *pParse){
   DbbeMethods *pM;
   sqlite *db;
   if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
+  if( pParse->nErr || sqlite_malloc_failed ) return;
   if( (db->flags & SQLITE_InTrans)==0 ) return;
   pM = pParse->db->pBe->x;
   if( pM && pM->Rollback ){
index 7f0d3bf4d735118b1b89956e172971a4d4384f71..8c57cba6d9a068c66ce38694aff22eeca1352ac4 100644 (file)
@@ -30,7 +30,7 @@
 ** relatively simple to convert to a different database such
 ** as NDBM, SDBM, or BerkeleyDB.
 **
-** $Id: dbbe.c,v 1.26 2001/04/04 21:22:14 drh Exp $
+** $Id: dbbe.c,v 1.27 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 #include <unistd.h>
@@ -65,6 +65,7 @@ Dbbe *sqliteDbbeOpen(
   return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg);
 }
 
+#if 0  /* NOT USED */
 /*
 ** Translate the name of an SQL table (or index) into the name 
 ** of a file that holds the key/data pairs for that table or
@@ -115,3 +116,4 @@ char *sqliteDbbeNameToFile(
   zFile[i] = 0;
   return zFile;
 }
+#endif /* NOT USED */
index c91fd6eb276f61a21f189407216040b9a8e90251..142dd08632c73b9893b0f5829efb57401c1174f9 100644 (file)
@@ -30,7 +30,7 @@
 ** relatively simple to convert to a different database such
 ** as NDBM, SDBM, or BerkeleyDB.
 **
-** $Id: dbbegdbm.c,v 1.6 2001/04/04 11:48:57 drh Exp $
+** $Id: dbbegdbm.c,v 1.7 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 #include <gdbm.h>
@@ -185,6 +185,7 @@ static int sqliteGdbmOpenCursor(
   if( pCursr==0 ) return SQLITE_NOMEM;
   if( zTable ){
     zFile = sqliteFileOfTable(pBe, zTable);
+    if( zFile==0 ) return SQLITE_NOMEM;
     for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
       if( strcmp(pFile->zName,zFile)==0 ) break;
     }
index f90473e529354b9449503560a97ea5f8db8b38bd..b37b20e66fbf4ca66c8562c12ea418dd4e19ca03 100644 (file)
@@ -30,7 +30,7 @@
 ** Nothing is ever written to disk using this backend.  All information
 ** is forgotten when the program exits.
 **
-** $Id: dbbemem.c,v 1.13 2001/04/04 11:48:58 drh Exp $
+** $Id: dbbemem.c,v 1.14 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 #include <sys/stat.h>
@@ -156,6 +156,7 @@ static void ArrayRehash(Array *array, int new_size){
   ArrayElem *x;                   /* Element being copied to new hash table */
 
   new_ht = sqliteMalloc( new_size*sizeof(struct _Array_ht) );
+  if( new_ht==0 ){ ArrayClear(array); return; }
   if( array->ht ) sqliteFree(array->ht);
   array->ht = new_ht;
   array->htsize = new_size;
@@ -305,8 +306,13 @@ static Datum ArrayInsert(Array *array, Datum key, Datum data){
   memcpy(new_elem->key.p, key.p, key.n);
   array->count++;
   if( array->htsize==0 ) ArrayRehash(array,4);
+  if( array->htsize==0 ) return nil;
   if( array->count > array->htsize ){
     ArrayRehash(array,array->htsize*2);
+    if( array->htsize==0 ){
+      sqliteFree(new_elem);
+      return nil;
+    }
   }
   h = hraw & (array->htsize-1);
   elem = array->ht[h].chain;
@@ -468,6 +474,7 @@ static int sqliteMemOpenCursor(
   if( zTable ){
     Datum key;
     zName = sqliteNameOfTable(zTable);
+    if( zName==0 ) return SQLITE_NOMEM;
     key.p = zName;
     key.n = strlen(zName);
     pTble = ArrayFind(&pBe->tables, key).p;
@@ -690,6 +697,7 @@ static int sqliteMemPut(
   Datum data, key;
   data.n = nData;
   data.p = sqliteMalloc( data.n );
+  if( data.p==0 ) return SQLITE_NOMEM;
   memcpy(data.p, pData, data.n);
   key.n = nKey;
   key.p = pKey;
index c4da286220144b164189f065ac8cb795e31470df..75c64074710b8b8c276e5b421fcc2fb3ab382aca 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.8 2001/03/20 22:05:00 drh Exp $
+** $Id: delete.c,v 1.9 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -45,12 +45,18 @@ void sqliteDeleteFrom(
   Index *pIdx;           /* For looping over indices of the table */
   int base;              /* Index of the first available table cursor */
 
+  if( pParse->nErr || sqlite_malloc_failed ){
+    pTabList = 0;
+    goto delete_from_cleanup;
+  }
+
   /* Locate the table which we want to delete.  This table has to be
   ** put in an IdList structure because some of the subroutines we
   ** will be calling are designed to work with multiple tables and expect
   ** an IdList* parameter instead of just a Table* parameger.
   */
   pTabList = sqliteIdListAppend(0, pTableName);
+  if( pTabList==0 ) goto delete_from_cleanup;
   for(i=0; i<pTabList->nId; i++){
     pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
     if( pTabList->a[i].pTab==0 ){
index 0cad95c7c0141d899a78ce9194528834a32541ba..29ee44c5592673a8c8d9fd138140bbf0bd32232f 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions.
 **
-** $Id: expr.c,v 1.23 2001/04/04 21:22:14 drh Exp $
+** $Id: expr.c,v 1.24 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -123,13 +123,14 @@ static int sqliteIsRowid(const char *z){
 ** the number of errors seen and leaves an error message on pParse->zErrMsg.
 */
 int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
-  if( pExpr==0 ) return 0;
+  if( pExpr==0 || pTabList==0 ) return 0;
   switch( pExpr->op ){
     /* A lone identifier */
     case TK_ID: {
       int cnt = 0;      /* Number of matches */
       int i;            /* Loop counter */
       char *z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
+      if( z==0 ) return 1;
       for(i=0; i<pTabList->nId; i++){
         int j;
         Table *pTab = pTabList->a[i].pTab;
@@ -177,6 +178,11 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
       assert( pRight && pRight->op==TK_ID );
       zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n);
       zRight = sqliteStrNDup(pRight->token.z, pRight->token.n);
+      if( zLeft==0 || zRight==0 ){
+        sqliteFree(zLeft);
+        sqliteFree(zRight);
+        return 1;
+      }
       pExpr->iTable = -1;
       for(i=0; i<pTabList->nId; i++){
         int j;
@@ -480,6 +486,7 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
 void sqliteExprCode(Parse *pParse, Expr *pExpr){
   Vdbe *v = pParse->pVdbe;
   int op;
+  if( v==0 || pExpr==0 ) return;
   switch( pExpr->op ){
     case TK_PLUS:     op = OP_Add;      break;
     case TK_MINUS:    op = OP_Subtract; break;
@@ -683,6 +690,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
 void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
   Vdbe *v = pParse->pVdbe;
   int op = 0;
+  if( v==0 || pExpr==0 ) return;
   switch( pExpr->op ){
     case TK_LT:       op = OP_Lt;       break;
     case TK_LE:       op = OP_Le;       break;
@@ -769,6 +777,7 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
 void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
   Vdbe *v = pParse->pVdbe;
   int op = 0;
+  if( v==0 || pExpr==0 ) return;
   switch( pExpr->op ){
     case TK_LT:       op = OP_Ge;       break;
     case TK_LE:       op = OP_Gt;       break;
@@ -896,8 +905,7 @@ static int appendAggInfo(Parse *pParse){
     int amt = pParse->nAgg + 8;
     pParse->aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0]));
     if( pParse->aAgg==0 ){
-      sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
-      pParse->nErr++;
+      pParse->nAgg = 0;
       return -1;
     }
   }
index 553a1c85163f243548ea3c5a2cb015b47f04b78c..7756b10b94d8d5dbd57fe6db1f7219cd08398895 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements.
 **
-** $Id: insert.c,v 1.12 2001/01/15 22:51:11 drh Exp $
+** $Id: insert.c,v 1.13 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -60,9 +60,12 @@ void sqliteInsert(
   int base;             /* First available cursor */
   int iCont, iBreak;    /* Beginning and end of the loop over srcTab */
 
+  if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
+
   /* Locate the table into which we will be inserting new information.
   */
   zTab = sqliteTableNameFromToken(pTableName);
+  if( zTab==0 ) goto insert_cleanup;
   pTab = sqliteFindTable(pParse->db, zTab);
   sqliteFree(zTab);
   if( pTab==0 ){
@@ -94,10 +97,11 @@ void sqliteInsert(
     srcTab = pParse->nTab++;
     sqliteVdbeAddOp(v, OP_OpenTbl, srcTab, 1, 0, 0);
     rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab);
-    if( rc ) goto insert_cleanup;
+    if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
     assert( pSelect->pEList );
     nColumn = pSelect->pEList->nExpr;
   }else{
+    assert( pList!=0 );
     srcTab = -1;
     assert( pList );
     nColumn = pList->nExpr;
index faab88ee67dcc365edca10aea85704fd1cfd37ad..431aacea6eaf75afd5c3dc05713d4c9a9d8a2d9e 100644 (file)
@@ -26,7 +26,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.27 2001/04/06 16:13:43 drh Exp $
+** $Id: main.c,v 1.28 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 #include <unistd.h>
@@ -157,8 +157,8 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   */
   vdbe = sqliteVdbeCreate(db);
   if( vdbe==0 ){
-    sqliteSetString(pzErrMsg, "out of memory",0); 
-    return 1;
+    sqliteSetString(pzErrMsg, "out of memory");
+    return SQLITE_NOMEM;
   }
   sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
   rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg, 
@@ -179,8 +179,6 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
       pTab->readOnly = 1;
     }
     db->flags |= SQLITE_Initialized;
-  }else{
-    sqliteStrRealloc(pzErrMsg);
   }
   return rc;
 }
@@ -216,17 +214,13 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
   /* Allocate the sqlite data structure */
   db = sqliteMalloc( sizeof(sqlite) );
   if( pzErrMsg ) *pzErrMsg = 0;
-  if( db==0 ){
-    sqliteSetString(pzErrMsg, "out of memory", 0);
-    sqliteStrRealloc(pzErrMsg);
-    return 0;
-  }
+  if( db==0 ) goto no_mem_on_open;
   
   /* Open the backend database driver */
   db->pBe = sqliteDbbeOpen(zFilename, (mode&0222)!=0, mode!=0, pzErrMsg);
   if( db->pBe==0 ){
-    sqliteStrRealloc(pzErrMsg);
     sqliteFree(db);
+    sqliteStrRealloc(pzErrMsg);
     return 0;
   }
 
@@ -235,14 +229,21 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
 
   /* Attempt to read the schema */
   rc = sqliteInit(db, pzErrMsg);
-  if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
+  if( sqlite_malloc_failed ){
+    goto no_mem_on_open;
+  }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
     sqlite_close(db);
     return 0;
   }else /* if( pzErrMsg ) */{
-    free(*pzErrMsg);
+    sqliteFree(*pzErrMsg);
     *pzErrMsg = 0;
   }
   return db;
+
+no_mem_on_open:
+  sqliteSetString(pzErrMsg, "out of memory", 0);
+  sqliteStrRealloc(pzErrMsg);
+  return 0;
 }
 
 /*
@@ -336,13 +337,21 @@ int sqlite_exec(
   if( pzErrMsg ) *pzErrMsg = 0;
   if( (db->flags & SQLITE_Initialized)==0 ){
     int rc = sqliteInit(db, pzErrMsg);
-    if( rc!=SQLITE_OK ) return rc;
+    if( rc!=SQLITE_OK ){
+      sqliteStrRealloc(pzErrMsg);
+      return rc;
+    }
   }
   memset(&sParse, 0, sizeof(sParse));
   sParse.db = db;
   sParse.xCallback = xCallback;
   sParse.pArg = pArg;
   sqliteRunParser(&sParse, zSql, pzErrMsg);
+  if( sqlite_malloc_failed ){
+    sqliteSetString(pzErrMsg, "out of memory", 0);
+    sParse.rc = SQLITE_NOMEM;
+  }
+  sqliteStrRealloc(pzErrMsg);
   return sParse.rc;
 }
 
@@ -352,7 +361,7 @@ int sqlite_exec(
 ** an integer number of milliseconds passed in as the first
 ** argument.
 */
-static int sqlite_default_busy_callback(
+static int sqliteDefaultBusyCallback(
  void *Timeout,           /* Maximum amount of time to wait */
  const char *NotUsed,     /* The name of the table that is busy */
  int count                /* Number of times table has been busy */
@@ -407,7 +416,7 @@ void sqlite_busy_handler(
 */
 void sqlite_busy_timeout(sqlite *db, int ms){
   if( ms>0 ){
-    sqlite_busy_handler(db, sqlite_default_busy_callback, (void*)ms);
+    sqlite_busy_handler(db, sqliteDefaultBusyCallback, (void*)ms);
   }else{
     sqlite_busy_handler(db, 0, 0);
   }
index 68c30214e60277cdcc9f8f4bac385042d64a1c45..1049150f6df3b253e713fdbc2934b8a1dba6f014 100644 (file)
@@ -26,7 +26,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.27 2001/04/04 11:48:58 drh Exp $
+** @(#) $Id: parse.y,v 1.28 2001/04/11 14:28:42 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -170,9 +170,11 @@ cmd ::= select(X).  {
 
 select(A) ::= oneselect(X).                      {A = X;}
 select(A) ::= select(X) joinop(Y) oneselect(Z).  {
+  if( Z ){
     Z->op = Y;
     Z->pPrior = X;
-    A = Z;
+  }
+  A = Z;
 }
 %type joinop {int}
 joinop(A) ::= UNION.      {A = TK_UNION;}
@@ -236,11 +238,11 @@ orderby_opt(A) ::= .                          {A = 0;}
 orderby_opt(A) ::= ORDER BY sortlist(X).      {A = X;}
 sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). {
   A = sqliteExprListAppend(X,Y,0);
-  A->a[A->nExpr-1].sortOrder = Z;   /* 0 for ascending order, 1 for decending */
+  if( A ) A->a[A->nExpr-1].sortOrder = Z;  /* 0=ascending, 1=decending */
 }
 sortlist(A) ::= sortitem(Y) sortorder(Z). {
   A = sqliteExprListAppend(0,Y,0);
-  A->a[0].sortOrder = Z;
+  if( A ) A->a[0].sortOrder = Z;
 }
 sortitem(A) ::= expr(X).   {A = X;}
 
@@ -297,13 +299,13 @@ item(A) ::= INTEGER(X).      {A = sqliteExpr(TK_INTEGER, 0, 0, &X);}
 item(A) ::= PLUS INTEGER(X). {A = sqliteExpr(TK_INTEGER, 0, 0, &X);}
 item(A) ::= MINUS INTEGER(X). {
   A = sqliteExpr(TK_UMINUS, 0, 0, 0);
-  A->pLeft = sqliteExpr(TK_INTEGER, 0, 0, &X);
+  if( A ) A->pLeft = sqliteExpr(TK_INTEGER, 0, 0, &X);
 }
 item(A) ::= FLOAT(X).        {A = sqliteExpr(TK_FLOAT, 0, 0, &X);}
 item(A) ::= PLUS FLOAT(X).   {A = sqliteExpr(TK_FLOAT, 0, 0, &X);}
 item(A) ::= MINUS FLOAT(X).  {
   A = sqliteExpr(TK_UMINUS, 0, 0, 0);
-  A->pLeft = sqliteExpr(TK_FLOAT, 0, 0, &X);
+  if( A ) A->pLeft = sqliteExpr(TK_FLOAT, 0, 0, &X);
 }
 item(A) ::= STRING(X).       {A = sqliteExpr(TK_STRING, 0, 0, &X);}
 item(A) ::= NULL.            {A = sqliteExpr(TK_NULL, 0, 0, 0);}
@@ -397,43 +399,43 @@ expr(A) ::= PLUS(B) expr(X). [UMINUS] {
 }
 expr(A) ::= LP(B) select(X) RP(E). {
   A = sqliteExpr(TK_SELECT, 0, 0, 0);
-  A->pSelect = X;
+  if( A ) A->pSelect = X;
   sqliteExprSpan(A,&B,&E);
 }
 expr(A) ::= expr(W) BETWEEN expr(X) AND expr(Y). {
   ExprList *pList = sqliteExprListAppend(0, X, 0);
   pList = sqliteExprListAppend(pList, Y, 0);
   A = sqliteExpr(TK_BETWEEN, W, 0, 0);
-  A->pList = pList;
+  if( A ) A->pList = pList;
   sqliteExprSpan(A,&W->span,&Y->span);
 }
 expr(A) ::= expr(W) NOT BETWEEN expr(X) AND expr(Y). {
   ExprList *pList = sqliteExprListAppend(0, X, 0);
   pList = sqliteExprListAppend(pList, Y, 0);
   A = sqliteExpr(TK_BETWEEN, W, 0, 0);
-  A->pList = pList;
+  if( A ) A->pList = pList;
   A = sqliteExpr(TK_NOT, A, 0, 0);
   sqliteExprSpan(A,&W->span,&Y->span);
 }
 expr(A) ::= expr(X) IN LP exprlist(Y) RP(E).  {
   A = sqliteExpr(TK_IN, X, 0, 0);
-  A->pList = Y;
+  if( A ) A->pList = Y;
   sqliteExprSpan(A,&X->span,&E);
 }
 expr(A) ::= expr(X) IN LP select(Y) RP(E).  {
   A = sqliteExpr(TK_IN, X, 0, 0);
-  A->pSelect = Y;
+  if( A ) A->pSelect = Y;
   sqliteExprSpan(A,&X->span,&E);
 }
 expr(A) ::= expr(X) NOT IN LP exprlist(Y) RP(E).  {
   A = sqliteExpr(TK_IN, X, 0, 0);
-  A->pList = Y;
+  if( A ) A->pList = Y;
   A = sqliteExpr(TK_NOT, A, 0, 0);
   sqliteExprSpan(A,&X->span,&E);
 }
 expr(A) ::= expr(X) NOT IN LP select(Y) RP(E).  {
   A = sqliteExpr(TK_IN, X, 0, 0);
-  A->pSelect = Y;
+  if( A ) A->pSelect = Y;
   A = sqliteExpr(TK_NOT, A, 0, 0);
   sqliteExprSpan(A,&X->span,&E);
 }
index b099523dcc7a031163f1cfa7f08b828136542b6e..bbde9223438dff4318f95184000d0e1dc7aba8be 100644 (file)
@@ -563,6 +563,7 @@ static int vxprintf(
           n += i + 1;
           if( n>etBUFSIZE ){
             bufpt = zExtra = sqliteMalloc( n );
+            if( bufpt==0 ) return -1;
           }else{
             bufpt = buf;
           }
index c3abbe4e53977acb69d9e57c70f80797637e3d78..1a6eb4fefdf7bd13453e9b7278ab5a61d7322346 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements.
 **
-** $Id: select.c,v 1.30 2001/04/04 11:48:58 drh Exp $
+** $Id: select.c,v 1.31 2001/04/11 14:28:42 drh Exp $
 */
 #include "sqliteInt.h"
 
 ** structure.
 */
 Select *sqliteSelectNew(
-  ExprList *pEList,
-  IdList *pSrc,
-  Expr *pWhere,
-  ExprList *pGroupBy,
-  Expr *pHaving,
-  ExprList *pOrderBy,
-  int isDistinct
+  ExprList *pEList,     /* which columns to include in the result */
+  IdList *pSrc,         /* the FROM clause -- which tables to scan */
+  Expr *pWhere,         /* the WHERE clause */
+  ExprList *pGroupBy,   /* the GROUP BY clause */
+  Expr *pHaving,        /* the HAVING clause */
+  ExprList *pOrderBy,   /* the ORDER BY clause */
+  int isDistinct        /* true if the DISTINCT keyword is present */
 ){
   Select *pNew;
   pNew = sqliteMalloc( sizeof(*pNew) );
-  if( pNew==0 ) return 0;
-  pNew->pEList = pEList;
-  pNew->pSrc = pSrc;
-  pNew->pWhere = pWhere;
-  pNew->pGroupBy = pGroupBy;
-  pNew->pHaving = pHaving;
-  pNew->pOrderBy = pOrderBy;
-  pNew->isDistinct = isDistinct;
-  pNew->op = TK_SELECT;
+  if( pNew==0 ){
+    sqliteExprListDelete(pEList);
+    sqliteIdListDelete(pSrc);
+    sqliteExprDelete(pWhere);
+    sqliteExprListDelete(pGroupBy);
+    sqliteExprDelete(pHaving);
+    sqliteExprListDelete(pOrderBy);
+  }else{
+    pNew->pEList = pEList;
+    pNew->pSrc = pSrc;
+    pNew->pWhere = pWhere;
+    pNew->pGroupBy = pGroupBy;
+    pNew->pHaving = pHaving;
+    pNew->pOrderBy = pOrderBy;
+    pNew->isDistinct = isDistinct;
+    pNew->op = TK_SELECT;
+  }
   return pNew;
 }
 
@@ -103,6 +111,7 @@ static int selectInnerLoop(
 ){
   Vdbe *v = pParse->pVdbe;
   int i;
+  if( v==0 ) return 0;
 
   /* Pull the requested columns.
   */
@@ -117,8 +126,9 @@ static int selectInnerLoop(
     }
   }
 
-  /* If the current result is not distinct, skip the rest
-  ** of the processing for the current row.
+  /* If the DISTINCT keyword was present on the SELECT statement
+  ** and this row has been seen before, then do not make this row
+  ** part of the result.
   */
   if( distinct>=0 ){
     int lbl = sqliteVdbeMakeLabel(v);
@@ -229,7 +239,7 @@ static
 void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
   Vdbe *v = pParse->pVdbe;
   int i;
-  if( pParse->colNamesSet ) return;
+  if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
   pParse->colNamesSet = 1;
   sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0, 0, 0);
   for(i=0; i<pEList->nExpr; i++){
@@ -241,6 +251,7 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
       continue;
     }
     p = pEList->a[i].pExpr;
+    if( p==0 ) continue;
     if( p->span.z && p->span.z[0] ){
       addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0, 0, 0);
       sqliteVdbeChangeP3(v, addr, p->span.z, p->span.n);
@@ -299,8 +310,12 @@ static const char *selectOpName(int id){
 */
 static int fillInColumnList(Parse *pParse, Select *p){
   int i, j;
-  IdList *pTabList = p->pSrc;
-  ExprList *pEList = p->pEList;
+  IdList *pTabList;
+  ExprList *pEList;
+
+  if( p==0 || p->pSrc==0 ) return 1;
+  pTabList = p->pSrc;
+  pEList = p->pEList;
 
   /* Look up every table in the table list.
   */
@@ -309,6 +324,17 @@ static int fillInColumnList(Parse *pParse, Select *p){
       /* This routine has run before!  No need to continue */
       return 0;
     }
+    if( pTabList->a[i].zName==0 ){
+      /* No table name is given.  Instead, there is a (SELECT ...) statement
+      ** the results of which should be used in place of the table.  The
+      ** was this is implemented is that the (SELECT ...) writes its results
+      ** into a temporary table which is then scanned like any other table.
+      */
+      sqliteSetString(&pParse->zErrMsg, 
+          "(SELECT...) in a FROM clause is not yet implemented.", 0);
+      pParse->nErr++;
+      return 1;
+    }
     pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
     if( pTabList->a[i].pTab==0 ){
       sqliteSetString(&pParse->zErrMsg, "no such table: ", 
@@ -326,10 +352,13 @@ static int fillInColumnList(Parse *pParse, Select *p){
       Table *pTab = pTabList->a[i].pTab;
       for(j=0; j<pTab->nCol; j++){
         Expr *pExpr = sqliteExpr(TK_DOT, 0, 0, 0);
+        if( pExpr==0 ) break;
         pExpr->pLeft = sqliteExpr(TK_ID, 0, 0, 0);
+        if( pExpr->pLeft==0 ) break;
         pExpr->pLeft->token.z = pTab->zName;
         pExpr->pLeft->token.n = strlen(pTab->zName);
         pExpr->pRight = sqliteExpr(TK_ID, 0, 0, 0);
+        if( pExpr->pRight==0 ) break;
         pExpr->pRight->token.z = pTab->aCol[j].zName;
         pExpr->pRight->token.n = strlen(pTab->aCol[j].zName);
         pExpr->span.z = "";
@@ -366,7 +395,7 @@ static int matchOrderbyToColumn(
   int i, j;
   ExprList *pEList;
 
-  assert( pSelect && pOrderBy );
+  if( pSelect==0 || pOrderBy==0 ) return 1;
   if( mustComplete ){
     for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; }
   }
@@ -426,10 +455,6 @@ Vdbe *sqliteGetVdbe(Parse *pParse){
   if( v==0 ){
     v = pParse->pVdbe = sqliteVdbeCreate(pParse->db);
   }
-  if( v==0 ){
-    sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
-    pParse->nErr++;
-  }
   return v;
 }
     
@@ -447,7 +472,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
   /* Make sure there is no ORDER BY clause on prior SELECTs.  Only the 
   ** last SELECT in the series may have an ORDER BY.
   */
-  assert( p->pPrior!=0 );
+  if( p==0 || p->pPrior==0 ) return 1;
   pPrior = p->pPrior;
   if( pPrior->pOrderBy ){
     sqliteSetString(&pParse->zErrMsg,"ORDER BY clause should come after ",
@@ -651,6 +676,8 @@ int sqliteSelect(
   int distinct;          /* Table to use for the distinct set */
   int base;              /* First cursor available for use */
 
+  if( sqlite_malloc_failed || pParse->nErr || p==0 ) return 1;
+
   /* If there is are a sequence of queries, do the earlier ones first.
   */
   if( p->pPrior ){
@@ -686,6 +713,7 @@ int sqliteSelect(
     return 1;
   }
   pEList = p->pEList;
+  if( pEList==0 ) return 1;
 
   /* Allocate a temporary table to use for the DISTINCT set, if
   ** necessary.  This must be done early to allocate the cursor before
@@ -820,15 +848,8 @@ int sqliteSelect(
 
   /* Begin generating code.
   */
-  v = pParse->pVdbe;
-  if( v==0 ){
-    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db);
-  }
-  if( v==0 ){
-    sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
-    pParse->nErr++;
-    return 1;
-  }
+  v = sqliteGetVdbe(pParse);
+  if( v==0 ) return 1;
   if( pOrderBy ){
     sqliteVdbeAddOp(v, OP_SortOpen, 0, 0, 0, 0);
   }
index 8202b985cc2dca98660de2cd11bfd4af7af90ca8..d3f43f67186988b1586b6688614aa02bb42f50d5 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.30 2001/04/04 21:22:14 drh Exp $
+** $Id: shell.c,v 1.31 2001/04/11 14:28:42 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -60,7 +60,7 @@ static sqlite *db = 0;
 ** The interface is like "readline" but no command-line editing
 ** is done.
 */
-static char *getline(char *zPrompt){
+static char *getline(char *zPrompt, FILE *in){
   char *zLine;
   int nLine;
   int n;
@@ -81,7 +81,7 @@ static char *getline(char *zPrompt){
       zLine = realloc(zLine, nLine);
       if( zLine==0 ) return 0;
     }
-    if( fgets(&zLine[n], nLine - n, stdin)==0 ){
+    if( fgets(&zLine[n], nLine - n, in)==0 ){
       if( n==0 ){
         free(zLine);
         return 0;
@@ -110,11 +110,11 @@ static char *getline(char *zPrompt){
 ** zPrior is a string of prior text retrieved.  If not the empty
 ** string, then issue a continuation prompt.
 */
-static char *one_input_line(const char *zPrior, int isatty){
+static char *one_input_line(const char *zPrior, FILE *in){
   char *zPrompt;
   char *zResult;
-  if( !isatty ){
-    return getline(0);
+  if( in!=0 ){
+    return getline(0, in);
   }
   if( zPrior && zPrior[0] ){
     zPrompt = "   ...> ";
@@ -133,6 +133,7 @@ static char *one_input_line(const char *zPrior, int isatty){
 */
 struct callback_data {
   sqlite *db;            /* The database */
+  int echoOn;            /* True to echo input commands */
   int cnt;               /* Number of records displayed so far */
   FILE *out;             /* Write results here */
   int mode;              /* An output mode setting */
@@ -389,23 +390,23 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
 ** This routine should print text sufficient to recreate the table.
 */
 static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
-  struct callback_data *pData = (struct callback_data *)pArg;
+  struct callback_data *p = (struct callback_data *)pArg;
   if( nArg!=3 ) return 1;
-  fprintf(pData->out, "%s;\n", azArg[2]);
+  fprintf(p->out, "%s;\n", azArg[2]);
   if( strcmp(azArg[1],"table")==0 ){
     struct callback_data d2;
-    d2 = *pData;
+    d2 = *p;
     d2.mode = MODE_List;
     d2.escape = '\t';
     strcpy(d2.separator,"\t");
-    fprintf(pData->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
-    sqlite_exec_printf(pData->db, 
+    fprintf(p->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
+    sqlite_exec_printf(p->db, 
        "SELECT * FROM '%q'",
        callback, &d2, 0, azArg[0]
     );
-    fprintf(pData->out, "\\.\n");
+    fprintf(p->out, "\\.\n");
   }
-  fprintf(pData->out, "VACUUM '%s';\n", azArg[0]);
+  fprintf(p->out, "VACUUM '%s';\n", azArg[0]);
   return 0;
 }
 
@@ -414,6 +415,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
 */
 static char zHelp[] = 
   ".dump ?TABLE? ...      Dump the database in an text format\n"
+  ".echo ON|OFF           Turn command echo on or off\n"
   ".exit                  Exit this program\n"
   ".explain               Set output mode suitable for EXPLAIN\n"
   ".header ON|OFF         Turn display of headers on or off\n"
@@ -424,6 +426,9 @@ static char zHelp[] =
   ".mode insert TABLE     Generate SQL insert statements for TABLE\n"
   ".output FILENAME       Send output to FILENAME\n"
   ".output stdout         Send output to the screen\n"
+  ".read FILENAME         Execute SQL in FILENAME\n"
+  ".reindex ?TABLE?       Rebuild indices\n"
+/*  ".rename OLD NEW        Change the name of a table or index\n" */
   ".schema ?TABLE?        Show the CREATE statements\n"
   ".separator STRING      Change separator string for \"list\" mode\n"
   ".tables ?PATTERN?      List names of tables matching a pattern\n"
@@ -431,6 +436,9 @@ static char zHelp[] =
   ".width NUM NUM ...     Set column widths for \"column\" mode\n"
 ;
 
+/* Forward reference */
+static void process_input(struct callback_data *p, FILE *in);
+
 /*
 ** If an input line begins with "." then invoke this routine to
 ** process that line.
@@ -491,6 +499,21 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
     }
   }else
 
+  if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
+    int j;
+    char *z = azArg[1];
+    int val = atoi(azArg[1]);
+    for(j=0; z[j]; j++){
+      if( isupper(z[j]) ) z[j] = tolower(z[j]);
+    }
+    if( strcmp(z,"on")==0 ){
+      val = 1;
+    }else if( strcmp(z,"yes")==0 ){
+      val = 1;
+    } 
+    p->echoOn = val;
+  }else
+
   if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
     exit(0);
   }else
@@ -559,6 +582,8 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
       }else{
         sprintf(p->zDestTable,"table");
       }
+    }else {
+      fprintf(stderr,"mode should be on of: column html insert line list\n");
     }
   }else
 
@@ -577,6 +602,50 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
     }
   }else
 
+  if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
+    FILE *alt = fopen(azArg[1], "r");
+    if( alt==0 ){
+      fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
+    }else{
+      process_input(p, alt);
+      fclose(alt);
+    }
+  }else
+
+  if( c=='r' && strncmp(azArg[0], "reindex", n)==0 ){
+    char **azResult;
+    int nRow, rc;
+    char *zErrMsg;
+    int i;
+    char *zSql;
+    if( nArg==1 ){
+      rc = sqlite_get_table(db,
+        "SELECT name, sql FROM sqlite_master "
+        "WHERE type='index'",
+        &azResult, &nRow, 0, &zErrMsg
+      );
+    }else{
+      rc = sqlite_get_table_printf(db,
+        "SELECT name, sql FROM sqlite_master "
+        "WHERE type='index' AND tbl_name LIKE '%q'",
+        &azResult, &nRow, 0, &zErrMsg, azArg[1]
+      );
+    }
+    for(i=1; rc==SQLITE_OK && i<=nRow; i++){
+      extern char *sqlite_mprintf(const char *, ...);
+      zSql = sqlite_mprintf(
+         "DROP INDEX '%q';\n%s;\nVACUUM '%q';",
+         azResult[i*2], azResult[i*2+1], azResult[i*2]);
+      if( p->echoOn ) printf("%s\n", zSql);
+      rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg);
+    }
+    sqlite_free_table(azResult);
+    if( zErrMsg ){
+      fprintf(stderr,"Error: %s\n", zErrMsg);
+      free(zErrMsg);
+    }
+  }else
+
   if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
     struct callback_data data;
     char *zErrMsg = 0;
@@ -685,12 +754,64 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
   }
 }
 
+static char *Argv0;
+static void process_input(struct callback_data *p, FILE *in){
+  char *zLine;
+  char *zSql = 0;
+  int nSql = 0;
+  char *zErrMsg;
+  while( (zLine = one_input_line(zSql, in))!=0 ){
+    if( p->echoOn ) printf("%s\n", zLine);
+    if( zLine && zLine[0]=='.' ){
+      do_meta_command(zLine, db, p);
+      free(zLine);
+      continue;
+    }
+    if( zSql==0 ){
+      int i;
+      for(i=0; zLine[i] && isspace(zLine[i]); i++){}
+      if( zLine[i]!=0 ){
+        nSql = strlen(zLine);
+        zSql = malloc( nSql+1 );
+        strcpy(zSql, zLine);
+      }
+    }else{
+      int len = strlen(zLine);
+      zSql = realloc( zSql, nSql + len + 2 );
+      if( zSql==0 ){
+        fprintf(stderr,"%s: out of memory!\n", Argv0);
+        exit(1);
+      }
+      strcpy(&zSql[nSql++], "\n");
+      strcpy(&zSql[nSql], zLine);
+      nSql += len;
+    }
+    free(zLine);
+    if( zSql && sqlite_complete(zSql) ){
+      p->cnt = 0;
+      if( sqlite_exec(db, zSql, callback, p, &zErrMsg)!=0 
+           && zErrMsg!=0 ){
+        if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
+        printf("SQL error: %s\n", zErrMsg);
+        free(zErrMsg);
+        zErrMsg = 0;
+      }
+      free(zSql);
+      zSql = 0;
+      nSql = 0;
+    }
+  }
+  if( zSql ){
+    printf("Incomplete SQL: %s\n", zSql);
+    free(zSql);
+  }
+}
+
 int main(int argc, char **argv){
   char *zErrMsg = 0;
-  char *argv0 = argv[0];
   struct callback_data data;
-  int echo = 0;
 
+  Argv0 = argv[0];
   memset(&data, 0, sizeof(data));
   data.mode = MODE_List;
   strcpy(data.separator,"|");
@@ -724,16 +845,16 @@ int main(int argc, char **argv){
       argc--;
       argv++;
     }else if( strcmp(argv[1],"-echo")==0 ){
-      echo = 1;
+      data.echoOn = 1;
       argc--;
       argv++;
     }else{
-      fprintf(stderr,"%s: unknown option: %s\n", argv0, argv[1]);
+      fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]);
       return 1;
     }
   }
   if( argc!=2 && argc!=3 ){
-    fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", argv0);
+    fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", Argv0);
     exit(1);
   }
   data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
@@ -757,57 +878,15 @@ int main(int argc, char **argv){
       exit(1);
     }
   }else{
-    char *zLine;
-    char *zSql = 0;
-    int nSql = 0;
-    int istty = isatty(0);
-    if( istty ){
+    if( isatty(0) ){
       printf(
         "SQLite version %s\n"
         "Enter \".help\" for instructions\n",
         sqlite_version
       );
-    }
-    while( (zLine = one_input_line(zSql, istty))!=0 ){
-      if( echo ) printf("%s\n", zLine);
-      if( zLine && zLine[0]=='.' ){
-        do_meta_command(zLine, db, &data);
-        free(zLine);
-        continue;
-      }
-      if( zSql==0 ){
-        int i;
-        for(i=0; zLine[i] && isspace(zLine[i]); i++){}
-        if( zLine[i]!=0 ){
-          nSql = strlen(zLine);
-          zSql = malloc( nSql+1 );
-          strcpy(zSql, zLine);
-        }
-      }else{
-        int len = strlen(zLine);
-        zSql = realloc( zSql, nSql + len + 2 );
-        if( zSql==0 ){
-          fprintf(stderr,"%s: out of memory!\n", argv0);
-          exit(1);
-        }
-        strcpy(&zSql[nSql++], "\n");
-        strcpy(&zSql[nSql], zLine);
-        nSql += len;
-      }
-      free(zLine);
-      if( zSql && sqlite_complete(zSql) ){
-        data.cnt = 0;
-        if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0 
-             && zErrMsg!=0 ){
-          if( !istty && !echo ) printf("%s\n",zSql);
-          printf("SQL error: %s\n", zErrMsg);
-          free(zErrMsg);
-          zErrMsg = 0;
-        }
-        free(zSql);
-        zSql = 0;
-        nSql = 0;
-      }
+      process_input(&data, 0);
+    }else{
+      process_input(&data, stdin);
     }
   }
   sqlite_close(db);
index c78ba217468ec4472d9830e29a96ace7ab473ac5..4a62e124927e3f7dd8c6818dad784cdaf14a2db6 100644 (file)
@@ -23,7 +23,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.40 2001/04/07 15:24:33 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.41 2001/04/11 14:28:43 drh Exp $
 */
 #include "sqlite.h"
 #include "dbbe.h"
@@ -65,6 +65,12 @@ typedef unsigned int u32;
 # define sqliteStrRealloc(X)
 #endif
 
+/*
+** This variable gets set if malloc() ever fails.  After it gets set,
+** the SQLite library shuts down permanently.
+*/
+extern int sqlite_malloc_failed;
+
 /*
 ** The following global variables are used for testing and debugging
 ** only.  They only work if MEMORY_DEBUG is defined.
@@ -257,8 +263,9 @@ struct IdList {
   struct {
     char *zName;      /* Text of the identifier. */
     char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
-    Table *pTab;      /* An SQL table corresponding to zName */
     int idx;          /* Index in some Table.aCol[] of a column named zName */
+    Table *pTab;      /* An SQL table corresponding to zName */
+    Select *pSelect;  /* A SELECT statement used in place of a table name */
   } *a;            /* One entry for each identifier on the list */
 };
 
index d713ee1842fb39c3f946e569044a2d8bb96d2c1f..8f61d6f2f5669f5e3b13a837e42ff3296a435c45 100644 (file)
@@ -140,7 +140,7 @@ int sqlite_get_table(
   res.nRow = 0;
   res.nColumn = 0;
   res.nData = 1;
-  res.nAlloc = 200;
+  res.nAlloc = 20;
   res.rc = SQLITE_OK;
   res.azResult = malloc( sizeof(char*)*res.nAlloc );
   if( res.azResult==0 ){
index e976da0d86f82011a82fce9c0333fa484030c78b..64cf61cfc802d537b85986704c392e343bf991a4 100644 (file)
@@ -25,7 +25,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.1 2001/04/07 15:24:33 drh Exp $
+** $Id: test1.c,v 1.2 2001/04/11 14:28:43 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -267,6 +267,50 @@ static int sqlite_mprintf_double(
   return TCL_OK;
 }
 
+/*
+** Usage: sqlite_malloc_fail N
+**
+** Rig sqliteMalloc() to fail on the N-th call.  Turn of this mechanism
+** and reset the sqlite_malloc_failed variable is N==0.
+*/
+#ifdef MEMORY_DEBUG
+static int sqlite_malloc_fail(
+  void *NotUsed,
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int argc,              /* Number of arguments */
+  char **argv            /* Text of each argument */
+){
+  int n;
+  if( argc!=2 ){
+    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
+    return TCL_ERROR;
+  }
+  if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
+  sqlite_iMallocFail = n;
+  sqlite_malloc_failed = 0;
+  return TCL_OK;
+}
+#endif
+
+/*
+** Usage: sqlite_malloc_stat
+**
+** Return the number of prior calls to sqliteMalloc() and sqliteFree().
+*/
+#ifdef MEMORY_DEBUG
+static int sqlite_malloc_stat(
+  void *NotUsed,
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int argc,              /* Number of arguments */
+  char **argv            /* Text of each argument */
+){
+  char zBuf[200];
+  sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail);
+  Tcl_AppendResult(interp, zBuf, 0);
+  return TCL_OK;
+}
+#endif
+
 /*
 ** Register commands with the TCL interpreter.
 */
@@ -279,5 +323,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
   Tcl_CreateCommand(interp, "sqlite_get_table_printf", test_get_table_printf,
       0, 0);
   Tcl_CreateCommand(interp, "sqlite_close", sqlite_test_close, 0, 0);
+#ifdef MEMORY_DEBUG
+  Tcl_CreateCommand(interp, "sqlite_malloc_fail", sqlite_malloc_fail, 0, 0);
+  Tcl_CreateCommand(interp, "sqlite_malloc_stat", sqlite_malloc_stat, 0, 0);
+#endif
   return TCL_OK;
 }
index 164eadf0b0267cf4c8869eefa06de423d971227d..2572b96d1ee099ddfdf9794ca8ac45bc25edeed3 100644 (file)
@@ -27,7 +27,7 @@
 ** individual tokens and sends those tokens one-by-one over to the
 ** parser for analysis.
 **
-** $Id: tokenize.c,v 1.18 2001/04/04 11:48:58 drh Exp $
+** $Id: tokenize.c,v 1.19 2001/04/11 14:28:43 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -107,7 +107,7 @@ static Keyword aKeywordTable[] = {
 /*
 ** This is the hash table
 */
-#define KEY_HASH_SIZE 69
+#define KEY_HASH_SIZE 71
 static Keyword *apHashTable[KEY_HASH_SIZE];
 
 
@@ -328,7 +328,7 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
 #ifndef NDEBUG
   sqliteParserTrace(trace, "parser: ");
 #endif
-  while( nErr==0 && i>=0 && zSql[i]!=0 ){
+  while( sqlite_malloc_failed==0 && nErr==0 && i>=0 && zSql[i]!=0 ){
     int tokenType;
     
     if( (pParse->db->flags & SQLITE_Interrupt)!=0 ){
@@ -363,24 +363,6 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
           pParse->db->flags |= SQLITE_VdbeTrace;
         }else if( sqliteStrNICmp(z,"--vdbe-trace-off--", 18)==0 ){
           pParse->db->flags &= ~SQLITE_VdbeTrace;
-#ifdef MEMORY_DEBUG
-        }else if( sqliteStrNICmp(z,"--malloc-fail=",14)==0 ){
-          sqlite_iMallocFail = atoi(&z[14]);
-        }else if( sqliteStrNICmp(z,"--malloc-stats--", 16)==0 ){
-          if( pParse->xCallback ){
-            static char *azName[4] = {"malloc", "free", "to_fail", 0 };
-            char *azArg[4];
-            char zVal[3][30];
-            sprintf(zVal[0],"%d", sqlite_nMalloc);
-            sprintf(zVal[1],"%d", sqlite_nFree);
-            sprintf(zVal[2],"%d", sqlite_iMallocFail);
-            azArg[0] = zVal[0];
-            azArg[1] = zVal[1];
-            azArg[2] = zVal[2];
-            azArg[3] = 0;
-            pParse->xCallback(pParse->pArg, 3, azArg, azName);
-          }
-#endif
         }
 #endif
         break;
@@ -437,7 +419,6 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
     pParse->pNewTable = 0;
   }
   sqliteParseInfoReset(pParse);
-  sqliteStrRealloc(pzErrMsg);
   if( nErr>0 && pParse->rc==SQLITE_OK ){
     pParse->rc = SQLITE_ERROR;
   }
index 44ad930a5e4bcc5abe032049838959a14db6ad56..dbe7af7388e24ac7b8639cb017c8818266e08760 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.10 2001/03/14 12:35:57 drh Exp $
+** $Id: update.c,v 1.11 2001/04/11 14:28:43 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -51,12 +51,15 @@ void sqliteUpdate(
                          ** an expression for the i-th column of the table.
                          ** aXRef[i]==-1 if the i-th column is not changed. */
 
+  if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
+
   /* Locate the table which we want to update.  This table has to be
   ** put in an IdList structure because some of the subroutines we
   ** will be calling are designed to work with multiple tables and expect
   ** an IdList* parameter instead of just a Table* parameger.
   */
   pTabList = sqliteIdListAppend(0, pTableName);
+  if( pTabList==0 ) goto update_cleanup;
   for(i=0; i<pTabList->nId; i++){
     pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
     if( pTabList->a[i].pTab==0 ){
index 6eb9c235a0d04a78c5568f5756a168e57b3ece17..eed1f97e73eff25fc5601a37c8416ef4bfd0484a 100644 (file)
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.20 2001/04/05 15:57:13 drh Exp $
+** $Id: util.c,v 1.21 2001/04/11 14:28:43 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
 #include <ctype.h>
 
+/*
+** If malloc() ever fails, this global variable gets set to 1.
+** This causes the library to abort and never again function.
+*/
+int sqlite_malloc_failed = 0;
+
 /*
 ** If MEMORY_DEBUG is defined, then use versions of malloc() and
 ** free() that track memory usage and check for buffer overruns.
@@ -58,12 +64,18 @@ void *sqliteMalloc_(int n, char *zFile, int line){
   sqlite_nMalloc++;
   if( sqlite_iMallocFail>=0 ){
     sqlite_iMallocFail--;
-    if( sqlite_iMallocFail==0 ) return 0;
+    if( sqlite_iMallocFail==0 ){
+      sqlite_malloc_failed++;
+      return 0;
+    }
   }
   if( n==0 ) return 0;
   k = (n+sizeof(int)-1)/sizeof(int);
   pi = malloc( (3+k)*sizeof(int));
-  if( pi==0 ) return 0;
+  if( pi==0 ){
+    sqlite_malloc_failed++;
+    return 0;
+  }
   pi[0] = 0xdead1122;
   pi[1] = n;
   pi[k+2] = 0xdead3344;
@@ -131,6 +143,10 @@ void *sqliteRealloc_(void *oldP, int n, char *zFile, int line){
   }
   k = (n + sizeof(int) - 1)/sizeof(int);
   pi = malloc( (k+3)*sizeof(int) );
+  if( pi==0 ){
+    sqlite_malloc_failed++;
+    return 0;
+  }
   pi[0] = 0xdead1122;
   pi[1] = n;
   pi[k+2] = 0xdead3344;
@@ -151,12 +167,21 @@ void *sqliteRealloc_(void *oldP, int n, char *zFile, int line){
 /*
 ** Make a duplicate of a string into memory obtained from malloc()
 ** Free the original string using sqliteFree().
+**
+** This routine is called on all strings that are passed outside of
+** the SQLite library.  That way clients can free the string using free()
+** rather than having to call sqliteFree().
 */
 void sqliteStrRealloc(char **pz){
   char *zNew;
   if( pz==0 || *pz==0 ) return;
   zNew = malloc( strlen(*pz) + 1 );
-  if( zNew ) strcpy(zNew, *pz);
+  if( zNew==0 ){
+    sqlite_malloc_failed++;
+    sqliteFree(*pz);
+    *pz = 0;
+  }
+  strcpy(zNew, *pz);
   sqliteFree(*pz);
   *pz = zNew;
 }
@@ -191,7 +216,10 @@ char *sqliteStrNDup_(const char *z, int n, char *zFile, int line){
 */
 void *sqliteMalloc(int n){
   void *p = malloc(n);
-  if( p==0 ) return 0;
+  if( p==0 ){
+    sqlite_malloc_failed++;
+    return 0;
+  }
   memset(p, 0, n);
   return p;
 }
@@ -218,7 +246,11 @@ void *sqliteRealloc(void *p, int n){
     sqliteFree(p);
     return 0;
   }
-  return realloc(p, n);
+  p = realloc(p, n);
+  if( p==0 ){
+    sqlite_malloc_failed++;
+  }
+  return p;
 }
 
 /*
@@ -325,6 +357,7 @@ void sqliteSetNString(char **pz, ...){
 void sqliteDequote(char *z){
   int quote;
   int i, j;
+  if( z==0 ) return;
   quote = z[0];
   if( quote!='\'' && quote!='"' ) return;
   for(i=1, j=0; z[i]; i++){
index 8c0524582ac16510e1b2d54c91ab8918eaa4f89c..9df47ed04261abb8345ce03081aa91eb519a9af4 100644 (file)
@@ -41,7 +41,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.56 2001/04/05 15:57:13 drh Exp $
+** $Id: vdbe.c,v 1.57 2001/04/11 14:28:43 drh Exp $
 */
 #include "sqliteInt.h"
 #include <unistd.h>
@@ -223,8 +223,8 @@ struct Vdbe {
 */
 Vdbe *sqliteVdbeCreate(sqlite *db){
   Vdbe *p;
-
   p = sqliteMalloc( sizeof(Vdbe) );
+  if( p==0 ) return 0;
   p->pBe = db->pBe;
   p->db = db;
   return p;
@@ -368,7 +368,7 @@ void sqliteVdbeDequoteP3(Vdbe *p, int addr){
   char *z;
   if( addr<0 || addr>=p->nOp ) return;
   z = p->aOp[addr].p3;
-  sqliteDequote(z);
+  if( z ) sqliteDequote(z);
 }
 
 /*
@@ -381,6 +381,7 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
   int i, j;
   if( addr<0 || addr>=p->nOp ) return;
   z = p->aOp[addr].p3;
+  if( z==0 ) return;
   i = j = 0;
   while( isspace(z[i]) ){ i++; }
   while( z[i] ){
@@ -462,6 +463,10 @@ static void AggRehash(Agg *p, int nHash){
   if( p->nHash==nHash ) return;
   size = nHash * sizeof(AggElem*);
   p->apHash = sqliteRealloc(p->apHash, size );
+  if( p->apHash==0 ){
+    AggReset(p);
+    return;
+  }
   memset(p->apHash, 0, size);
   p->nHash = nHash;
   for(pElem=p->pFirst; pElem; pElem=pElem->pNext){
@@ -534,7 +539,10 @@ static void SetInsert(Set *p, char *zKey){
     if( strcmp(pElem->zKey, zKey)==0 ) return;
   }
   pElem = sqliteMalloc( sizeof(*pElem) + strlen(zKey) );
-  if( pElem==0 ) return;
+  if( pElem==0 ){
+    SetClear(p);
+    return;
+  }
   strcpy(pElem->zKey, zKey);
   pElem->pNext = p->pAll;
   p->pAll = pElem;
@@ -1004,6 +1012,7 @@ int sqliteVdbeExec(
   }
 #endif
   /* if( pzErrMsg ){ *pzErrMsg = 0; } */
+  if( sqlite_malloc_failed ) rc = SQLITE_NOMEM;
   for(pc=0; rc==SQLITE_OK && pc<p->nOp VERIFY(&& pc>=0); pc++){
     pOp = &p->aOp[pc];
 
@@ -1364,8 +1373,7 @@ int sqliteVdbeExec(
           Realify(p, nos);
           copy = aStack[tos].r>aStack[nos].r;
         }else{
-          Stringify(p, tos);
-          Stringify(p, nos);
+          if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
           copy = sqliteCompare(zStack[tos],zStack[nos])>0;
         }
         if( copy ){
@@ -1405,8 +1413,7 @@ int sqliteVdbeExec(
           Realify(p, nos);
           copy = aStack[tos].r<aStack[nos].r;
         }else{
-          Stringify(p, tos);
-          Stringify(p, nos);
+          if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
           copy = sqliteCompare(zStack[tos],zStack[nos])<0;
         }
         if( copy ){
@@ -1485,8 +1492,7 @@ int sqliteVdbeExec(
         if( (ft & fn)==STK_Int ){
           c = aStack[nos].i - aStack[tos].i;
         }else{
-          Stringify(p, tos);
-          Stringify(p, nos);
+          if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
           c = sqliteCompare(zStack[nos], zStack[tos]);
         }
         switch( pOp->opcode ){
@@ -1523,8 +1529,7 @@ int sqliteVdbeExec(
         int nos = tos - 1;
         int c;
         VERIFY( if( nos<0 ) goto not_enough_stack; )
-        Stringify(p, tos);
-        Stringify(p, nos);
+        if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
         c = sqliteLikeCompare(zStack[tos], zStack[nos]);
         POPSTACK;
         POPSTACK;
@@ -1556,8 +1561,7 @@ int sqliteVdbeExec(
         int nos = tos - 1;
         int c;
         VERIFY( if( nos<0 ) goto not_enough_stack; )
-        Stringify(p, tos);
-        Stringify(p, nos);
+        if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
         c = sqliteGlobCompare(zStack[tos], zStack[nos]);
         POPSTACK;
         POPSTACK;
@@ -3070,7 +3074,7 @@ int sqliteVdbeExec(
         int nKey;
 
         VERIFY( if( tos<0 ) goto not_enough_stack; )
-        Stringify(p, tos);
+        if( Stringify(p, tos) ) goto no_mem;
         zKey = zStack[tos]; 
         nKey = aStack[tos].n;
         if( p->agg.nHash<=0 ){
@@ -3086,6 +3090,7 @@ int sqliteVdbeExec(
           pc = pOp->p2 - 1;
         }else{
           AggInsert(&p->agg, zKey);
+          if( sqlite_malloc_failed ) goto no_mem;
         }
         POPSTACK;
         break; 
@@ -3241,10 +3246,11 @@ int sqliteVdbeExec(
         }else{
           int tos = p->tos;
           if( tos<0 ) goto not_enough_stack;
-          Stringify(p, tos);
+          if( Stringify(p, tos) ) goto no_mem;
           SetInsert(&p->aSet[i], zStack[tos]);
           POPSTACK;
         }
+        if( sqlite_malloc_failed ) goto no_mem;
         break;
       }
 
@@ -3258,7 +3264,7 @@ int sqliteVdbeExec(
         int i = pOp->p1;
         int tos = p->tos;
         VERIFY( if( tos<0 ) goto not_enough_stack; )
-        Stringify(p, tos);
+        if( Stringify(p, tos) ) goto no_mem;
         if( VERIFY( i>=0 && i<p->nSet &&) SetTest(&p->aSet[i], zStack[tos])){
           pc = pOp->p2 - 1;
         }
@@ -3276,7 +3282,7 @@ int sqliteVdbeExec(
         int i = pOp->p1;
         int tos = p->tos;
         VERIFY( if( tos<0 ) goto not_enough_stack; )
-        Stringify(p, tos);
+        if( Stringify(p, tos) ) goto no_mem;
         if(VERIFY( i>=0 && i<p->nSet &&) !SetTest(&p->aSet[i], zStack[tos])){
           pc = pOp->p2 - 1;
         }
@@ -3293,7 +3299,7 @@ int sqliteVdbeExec(
         int tos = p->tos;
         int len;
         VERIFY( if( tos<0 ) goto not_enough_stack; )
-        Stringify(p, tos);
+        if( Stringify(p, tos) ) goto no_mem;
 #ifdef SQLITE_UTF8
         {
           char *z = zStack[tos];
@@ -3351,7 +3357,7 @@ int sqliteVdbeExec(
           start = pOp->p1 - 1;
         }
         VERIFY( if( p->tos<0 ) goto not_enough_stack; )
-        Stringify(p, p->tos);
+        if( Stringify(p, p->tos) ) goto no_mem;
 
         /* "n" will be the number of characters in the input string.
         ** For iso8859, the number of characters is the number of bytes.
index fc0221d51d52d482b720037ea613a013c1a55f80..13914fc23a769480fec5368b52bb4ab65a4819a9 100644 (file)
@@ -25,7 +25,7 @@
 ** the WHERE clause of SQL statements.  Also found here are subroutines
 ** to generate VDBE code to evaluate expressions.
 **
-** $Id: where.c,v 1.13 2001/04/04 11:48:58 drh Exp $
+** $Id: where.c,v 1.14 2001/04/11 14:28:43 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -170,8 +170,9 @@ WhereInfo *sqliteWhereBegin(
   ** return value.
   */
   pWInfo = sqliteMalloc( sizeof(WhereInfo) );
-  if( pWInfo==0 ){
+  if( sqlite_malloc_failed ){
     sqliteFree(aOrder);
+    sqliteFree(pWInfo);
     return 0;
   }
   pWInfo->pParse = pParse;
index 6d04127f3e8963f357ae42e7775228d6f5497594..9aeb987ef3c053622d1cd50c20b688f418c4d7d5 100644 (file)
@@ -22,7 +22,7 @@
 #***********************************************************************
 # This file runs all tests.
 #
-# $Id: all.test,v 1.5 2000/12/10 18:23:51 drh Exp $
+# $Id: all.test,v 1.6 2001/04/11 14:28:43 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -53,6 +53,7 @@ for {set Counter 0} {$Counter<$COUNT} {incr Counter} {
     set dbprefix $p
     foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
       if {[file tail $testfile]=="all.test"} continue
+      if {[file tail $testfile]=="malloc.test"} continue
       source $testfile
     }
   }
@@ -79,4 +80,13 @@ if {$LeakList!=""} {
   puts " Ok"
 }
 
+if {[file readable $testdir/malloc.test]} {
+  for {set Counter 0} {$Counter<$COUNT} {incr Counter} {
+    foreach p $PREFIXES {
+      set dbprefix $p
+      source $testdir/malloc.test
+    }
+  }
+}
+
 really_finish_test
index 2fffeb2159059f93d6a575bfcd305428b9682b68..7941ab4c30b14d5ec381fc50c99c5da2e5d4f97c 100644 (file)
@@ -23,7 +23,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the sqlite_*_printf() interface.
 #
-# $Id: printf.test,v 1.1 2001/04/07 15:24:33 drh Exp $
+# $Id: printf.test,v 1.2 2001/04/11 14:28:43 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -39,6 +39,15 @@ foreach v {1 2 5 10 99 100 1000000 999999999 0 -1 -2 -5 -10 -99 -100 -9999999} {
   do_test printf-1.$n.3 [subst {
     sqlite_mprintf_int {Three integers: (%-6d) (%-6x) (%-6o)} $v $v $v
   }] [format {Three integers: (%-6d) (%-6x) (%-6o)} $v $v $v]
+  do_test printf-1.$n.4 [subst {
+    sqlite_mprintf_int {Three integers: (%+6d) (%+6x) (%+6o)} $v $v $v
+  }] [format {Three integers: (%+6d) (%+6x) (%+6o)} $v $v $v]
+  do_test printf-1.$n.5 [subst {
+    sqlite_mprintf_int {Three integers: (%06d) (%06x) (%06o)} $v $v $v
+  }] [format {Three integers: (%06d) (%06x) (%06o)} $v $v $v]
+  do_test printf-1.$n.6 [subst {
+    sqlite_mprintf_int {Three integers: (% 6d) (% 6x) (% 6o)} $v $v $v
+  }] [format {Three integers: (% 6d) (% 6x) (% 6o)} $v $v $v]
   incr n
 }
 
@@ -89,4 +98,15 @@ do_test printf-4.1 {
   sqlite_mprintf_str {%d %d A quoted string: '%q'} 1 2 {Hi Y'all}
 } {1 2 A quoted string: 'Hi Y''all'}
 
+do_test printf-5.1 {
+  set x [sqlite_mprintf_str {%d %d %100000s} 0 0 {Hello}]
+  string length $x
+} {994}
+do_test printf-5.2 {
+  sqlite_mprintf_str {%d %d (%-10.10s) %} -9 -10 {HelloHelloHello}
+} {-9 -10 (HelloHello) %}
+do_test printf-5.3 {
+  sqlite_mprintf_str {%% %d %d (%=10s)} 5 6 Hello
+} {% 5 6 (  Hello   )}
+
 finish_test
index c32b6b293565dc791d0e8449df1d6cd1b8a7082b..5cb6a79731bd6390e39940886f362d260333b367 100644 (file)
@@ -24,7 +24,7 @@
 # focus of this file is testing the sqlite_exec_printf() and
 # sqlite_get_table_printf() APIs.
 #
-# $Id: tableapi.test,v 1.1 2001/04/07 15:24:34 drh Exp $
+# $Id: tableapi.test,v 1.2 2001/04/11 14:28:43 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -48,6 +48,49 @@ do_test tableapi-2.1 {
     SELECT * FROM xyz WHERE b='%q'
   } {Hi Y'all}
 } {0 1 2 a b 1 {Hi Y'all}}
+do_test tableapi-2.2 {
+  sqlite_get_table_printf $::dbx {
+    SELECT * FROM xyz
+  } {}
+} {0 1 2 a b 1 {Hi Y'all}}
+do_test tableapi-2.3 {
+  for {set i 2} {$i<=50} {incr i} {
+    sqlite_get_table_printf $::dbx \
+       "INSERT INTO xyz VALUES($i,'(%s)')" $i
+  }
+  sqlite_get_table_printf $::dbx {
+    SELECT * FROM xyz ORDER BY a
+  } {}
+} {0 50 2 a b 1 {Hi Y'all} 2 (2) 3 (3) 4 (4) 5 (5) 6 (6) 7 (7) 8 (8) 9 (9) 10 (10) 11 (11) 12 (12) 13 (13) 14 (14) 15 (15) 16 (16) 17 (17) 18 (18) 19 (19) 20 (20) 21 (21) 22 (22) 23 (23) 24 (24) 25 (25) 26 (26) 27 (27) 28 (28) 29 (29) 30 (30) 31 (31) 32 (32) 33 (33) 34 (34) 35 (35) 36 (36) 37 (37) 38 (38) 39 (39) 40 (40) 41 (41) 42 (42) 43 (43) 44 (44) 45 (45) 46 (46) 47 (47) 48 (48) 49 (49) 50 (50)}
+do_test tableapi-2.3.1 {
+  sqlite_get_table_printf $::dbx {
+    SELECT * FROM xyz  WHERE a>49 ORDER BY a
+  } {}
+} {0 1 2 a b 50 (50)}
+do_test tableapi-2.3.2 {
+  sqlite_get_table_printf $::dbx {
+    SELECT * FROM xyz WHERE a>47 ORDER BY a
+  } {}
+} {0 3 2 a b 48 (48) 49 (49) 50 (50)}
+do_test tableapi-2.4 {
+  set ::big_str [sqlite_mprintf_str {%500'* Hello %500'*} 0 0 {}]
+  sqlite_get_table_printf $::dbx {
+    INSERT INTO xyz VALUES(51,'%q')
+  } $::big_str
+} {0 0 0}
+do_test tableapi-2.5 {
+  sqlite_get_table_printf $::dbx {
+    SELECT * FROM xyz WHERE a>49 ORDER BY a;
+  } {}
+} "0 2 2 a b 50 (50) 51 \173$::big_str\175"
+do_test tableapi-2.6 {
+  sqlite_get_table_printf $::dbx {
+    INSERT INTO xyz VALUES(52,NULL)
+  } {}
+  sqlite_get_table_printf $::dbx {
+    SELECT * FROM xyz WHERE a IN (42,50,52) ORDER BY a DESC
+  } {}
+} {0 3 2 a b 52 NULL 50 (50) 42 (42)}
 
 do_test tableapi-99.0 {
   sqlite_close $::dbx
index 9c86030ea0ec029a6b7b8327c999133178a8d7fc..120ce86e95e2b58d989c22d9a187e2c9c3259b4c 100644 (file)
@@ -23,7 +23,7 @@
 # This file implements some common TCL routines used for regression
 # testing the SQLite library
 #
-# $Id: tester.tcl,v 1.14 2001/04/06 16:13:43 drh Exp $
+# $Id: tester.tcl,v 1.15 2001/04/11 14:28:43 drh Exp $
 
 # Make sure tclsqlite was compiled correctly.  Abort now with an
 # error message if not.
@@ -183,7 +183,7 @@ proc testif {args} {
   set ::skip_test 1
 }
 
-# The procedure uses the special "--malloc-stats--" macro of SQLite
+# The procedure uses the special "sqlite_malloc_stat" command
 # (which is only available if SQLite is compiled with -DMEMORY_DEBUG=1)
 # to see how many malloc()s have not been free()ed.  The number
 # of surplus malloc()s is stored in the global variable $::Leak.
@@ -191,10 +191,10 @@ proc testif {args} {
 # in the library.
 #
 proc memleak_check {} {
-  set r [execsql {--malloc-stats--}]
-  if {$r==""} return
-  set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
-  # puts "*** $::Leak mallocs have not been freed ***"
+  if {[info command sqlite_malloc_stat]!=""} {
+    set r [sqlite_malloc_stat]
+    set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
+  }
 }
 
 # Run this routine last
index 8c2c258af9259e9ba06d613069282bf3185fcfd0..4dc8400b9a739be3c1003599da60e97bf988bf35 100644 (file)
@@ -17,7 +17,8 @@ proc chng {date desc} {
   puts "<DD><P><UL>$desc</UL></P></DD>"
 }
 
-chng {2001 Apr 6 (1.0.31)} {
+chng {2001 Apr 11 (1.0.31)} {
+<li>More robust handling of out-of-memory errors.</li>
 <li>New tests added to the test suite.</li>
 }