1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

better handling of out-of-memory errors (CVS 207)

FossilOrigin-Name: 86b30cd0975dfea9424b9f9f0d4194aa71ce508b
This commit is contained in:
drh
2001-04-11 14:28:42 +00:00
parent d1bf3512fa
commit daffd0e597
27 changed files with 590 additions and 266 deletions

View File

@@ -1,5 +1,5 @@
C Added\snew\stests\s(CVS\s206) C better\shandling\sof\sout-of-memory\serrors\s(CVS\s207)
D 2001-04-07T15:24:33 D 2001-04-11T14:28:42
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 4775f7fd1ed543606bb24fa3fada1bc90a23a6b9 F Makefile.in 4775f7fd1ed543606bb24fa3fada1bc90a23a6b9
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@@ -9,12 +9,12 @@ F configure.in 6940e3f88bf3d28a10c73b06ab99fd3a7e039a61
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e
F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4 F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
F src/build.c 4c5eede16695d5e74bb3004e51923492b66eae62 F src/build.c 6afbb6106c1e8c771ffcb81107b755e200310574
F src/dbbe.c dd318ba657bfc8c2fec00c8cf51ea29dbfd284bf F src/dbbe.c ec82c602c598748204a61a35ab0c31e34ca58223
F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8 F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8
F src/dbbegdbm.c d044b9e3a463608ac4f35283c78ac372d5da64c6 F src/dbbegdbm.c 9d3a3c18b27f9f2533a3aaa3741e8668bdda7e98
F src/dbbemem.c fa84058f79dd5e6af1ccbb0d41c85e05a6bc19ac F src/dbbemem.c b62821ba8cec4b1d7392157e94f72baf1ff015f2
F src/delete.c 7aa9dcb86d5e98c3eb9dee00a459e0ef9b73fbe3 F src/delete.c 40ddb169ee98013d976b2dadd140d98f7876f54f
F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a
F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7 F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7
F src/ex/db.h 3f2933ee20c147fe494835786e4c6f3a562def4e 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.c 2bbf6a94f37226d06337868b6bf4d7affc60197f
F src/ex/pg.h 23a4ac807b0546ec2bb6239ec8bd3e06926572cd F src/ex/pg.h 23a4ac807b0546ec2bb6239ec8bd3e06926572cd
F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7 F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7
F src/expr.c 745383609b65d504a2cc04ac4d9389e9c8e2bc80 F src/expr.c c4c24c3af1eba094a816522eb0e085bed518ee16
F src/insert.c 4bc1cab84f7805d560a1417734a532843e30b762 F src/insert.c aa528e20a787af85432a61daaea6df394bd251d7
F src/main.c fe5c26620c46770539056525d8a79e3afb6e75e8 F src/main.c 92ce30a89f622ba36cc8b7d912829e14a480722c
F src/pager.h 889c5cf517ad30704e295540793c893ac843fd5f F src/pager.h 889c5cf517ad30704e295540793c893ac843fd5f
F src/parse.y 1ba81d3b75f37ca868aa0ab990bb977fd41519eb F src/parse.y 8fc096948994a7ffbf61ba13129cc589f794a9cb
F src/printf.c af0dc65c293427272e1949c7807b1d88f10004fd F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a
F src/select.c a6bfdaa92d4614e79bf18129283c5163faa291fc F src/select.c 52bb7d081ac00dfad3687d52c917d2d90165331d
F src/shell.c c1785b4af18192056adbe894f8626a7e7bdf47aa F src/shell.c d9c64418765d90909e9e200b207ff9e355afb5c4
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 3e5906f72608f0fd4394dfbb1d7e8d35b8353677 F src/sqlite.h.in 3e5906f72608f0fd4394dfbb1d7e8d35b8353677
F src/sqliteInt.h 054c00c2b3deaedf4034b85d69287abeb4c15c96 F src/sqliteInt.h fc1000f023b41882bbdb8db4f80172f77b44307b
F src/table.c 5be76051a8ed6f6bfa641f4adc52529efa34fbf9 F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6
F src/tclsqlite.c 83dcbf015ea0319c2a97514b8b812a12d621e40a F src/tclsqlite.c 83dcbf015ea0319c2a97514b8b812a12d621e40a
F src/test1.c 7d88c76725ce5b881cff2a283662fe068d792002 F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4
F src/tokenize.c 8fc3936eefad84f1fff19e0892ed0542eb9ac7b3 F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf
F src/update.c 8365b3922ea098330d1e20862d6e64911e4e03d0 F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6
F src/util.c aec315b834bad444c9e0e90efd9d2eaeeb37c90c F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc
F src/vdbe.c 5f5be704686ed328275c35815e39d041a0c6cbb6 F src/vdbe.c ee5a6ab95c8c84497f6685ebde153da6fb06e825
F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437 F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437
F src/where.c 459bf37ac7849599da400420984b3306484b4cbb F src/where.c 0c542fc44bd85152dfb8507862cfe2e60c629e9f
F test/all.test 15cac2f6b2d4c55bf896212aff3cc9d6597b0490 F test/all.test 4ba0807feec7f29bf90c4f0ffd10b3801634461d
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c
F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf
@@ -56,7 +56,7 @@ F test/insert.test dbd3bd189edb61fddbe66c236694ef23352429f1
F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6 F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6
F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a
F test/main.test da635f9e078cd21ddf074e727381a715064489ff F test/main.test da635f9e078cd21ddf074e727381a715064489ff
F test/printf.test 18e44e4e154e13cba74d67b85202172d37ddb5ed F test/printf.test 4c71871e1a75a2dacb673945fc13ddb30168798f
F test/rowid.test 128453599def7435e988216f7fe89c7450b8a9a3 F test/rowid.test 128453599def7435e988216f7fe89c7450b8a9a3
F test/select1.test 824d9d5007dffd6a45edde79e89c0a04c36e3ebe F test/select1.test 824d9d5007dffd6a45edde79e89c0a04c36e3ebe
F test/select2.test 04ac3bd69298f58c7d0883159bab42ab9ad6021c F test/select2.test 04ac3bd69298f58c7d0883159bab42ab9ad6021c
@@ -66,9 +66,9 @@ F test/select5.test e2b9d51d88cbd6c307c2c05b0ef55fe7ba811ac2
F test/sort.test 838cd862642ed9a2c47e1a17b5c33da452b4552e F test/sort.test 838cd862642ed9a2c47e1a17b5c33da452b4552e
F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5 F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5
F test/table.test c1704fead1af27d67850a934d531848ce5bee4a7 F test/table.test c1704fead1af27d67850a934d531848ce5bee4a7
F test/tableapi.test 9ecb98590d1b6ebcb4b791697bd5275e73bba530 F test/tableapi.test 4778414470ba150983d03b9858334effe720c2e0
F test/tclsqlite.test d2aa55926874783b2401f0146e839f773c6796e1 F test/tclsqlite.test d2aa55926874783b2401f0146e839f773c6796e1
F test/tester.tcl dba25c97cc89f109a9350f12792f17b24202d65f F test/tester.tcl 39a707dac2b6048d9c9e07a98d3256d50069fe47
F test/trans.test 82556605d48f56ad4679e95478d70546a763f26a F test/trans.test 82556605d48f56ad4679e95478d70546a763f26a
F test/update.test 72c0c93310483b86dc904a992220c5b84c7ce100 F test/update.test 72c0c93310483b86dc904a992220c5b84c7ce100
F test/vacuum.test b95d8119a0a83dc6c4ac63888f8872f06199e065 F test/vacuum.test b95d8119a0a83dc6c4ac63888f8872f06199e065
@@ -86,7 +86,7 @@ F www/arch.fig 4f246003b7da23bd63b8b0af0618afb4ee3055c8
F www/arch.png 8dae0766d42ed3de9ed013c1341a5792bcf633e6 F www/arch.png 8dae0766d42ed3de9ed013c1341a5792bcf633e6
F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be
F www/c_interface.tcl ddca19005c47dd5a15882addc02fff5de83d8ed9 F www/c_interface.tcl ddca19005c47dd5a15882addc02fff5de83d8ed9
F www/changes.tcl 64e5779a681bda4b34d0403c33aaf8902d8cf056 F www/changes.tcl cad714ae8d6e5c19e8d14282dbfbe7c61c5cc4ee
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9 F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
@@ -97,7 +97,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2 F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
P 8f0d98193e4ba913fa31d5f8d5adc46ad9d346a1 P 2507ec40610d8034ccf9dcb58a16934065e6f120
R b4947cdaa9daf5e442bdf2c2d5dbb11c R 0329ee9c40e806471f7c325d51a23bb6
U drh U drh
Z 46e79499f1b58c1b58c6255886d7f82a Z 598daf9af8c7873df8fb5f69d495d703

View File

@@ -1 +1 @@
2507ec40610d8034ccf9dcb58a16934065e6f120 86b30cd0975dfea9424b9f9f0d4194aa71ce508b

View File

@@ -33,7 +33,7 @@
** COPY ** COPY
** VACUUM ** 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" #include "sqliteInt.h"
@@ -49,6 +49,7 @@
*/ */
void sqliteExec(Parse *pParse){ void sqliteExec(Parse *pParse){
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( sqlite_malloc_failed ) return;
if( pParse->pVdbe ){ if( pParse->pVdbe ){
if( pParse->explain ){ if( pParse->explain ){
rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, 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. ** text between the two given tokens.
*/ */
void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
pExpr->span.z = pLeft->z; if( pExpr ){
pExpr->span.n = pRight->n + (int)pRight->z - (int)pLeft->z; 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 ** Remove the given index from the index hash table, and free
** its memory structures. ** its memory structures.
** **
** The index is removed from the database hash table, but it is ** The index is removed from the database hash table if db!=NULL.
** not unlinked from the Table that is being indexed. Unlinking ** But it is not unlinked from the Table that is being indexed.
** from the Table must be done by the calling function. ** Unlinking from the Table must be done by the calling function.
*/ */
static void sqliteDeleteIndex(sqlite *db, Index *pIndex){ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
int h; int h;
if( pIndex->zName ){ if( pIndex->zName && db ){
h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH; h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH;
if( db->apIdxHash[h]==pIndex ){ if( db->apIdxHash[h]==pIndex ){
db->apIdxHash[h] = pIndex->pHash; 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 ** This routine just deletes the data structure. It does not unlink
** the table data structure from the hash table. But does it destroy ** the table data structure from the hash table. But does it destroy
** memory structures of the indices associated with the table. ** 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){ void sqliteDeleteTable(sqlite *db, Table *pTable){
int i; int i;
@@ -236,6 +244,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
pParse->sFirstToken = *pStart; pParse->sFirstToken = *pStart;
zName = sqliteTableNameFromToken(pName); zName = sqliteTableNameFromToken(pName);
if( zName==0 ) return;
pTable = sqliteFindTable(pParse->db, zName); pTable = sqliteFindTable(pParse->db, zName);
if( pTable!=0 ){ if( pTable!=0 ){
sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
@@ -252,11 +261,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
return; return;
} }
pTable = sqliteMalloc( sizeof(Table) ); pTable = sqliteMalloc( sizeof(Table) );
if( pTable==0 ){ if( pTable==0 ) return;
sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
pParse->nErr++;
return;
}
pTable->zName = zName; pTable->zName = zName;
pTable->pHash = 0; pTable->pHash = 0;
pTable->nCol = 0; pTable->nCol = 0;
@@ -275,10 +280,10 @@ void sqliteAddColumn(Parse *pParse, Token *pName){
if( (p = pParse->pNewTable)==0 ) return; if( (p = pParse->pNewTable)==0 ) return;
if( (p->nCol & 0x7)==0 ){ if( (p->nCol & 0x7)==0 ){
p->aCol = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0])); p->aCol = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0]));
} if( p->aCol==0 ){
if( p->aCol==0 ){ p->nCol = 0;
p->nCol = 0; return;
return; }
} }
memset(&p->aCol[p->nCol], 0, sizeof(p->aCol[0])); memset(&p->aCol[p->nCol], 0, sizeof(p->aCol[0]));
pz = &p->aCol[p->nCol++].zName; pz = &p->aCol[p->nCol++].zName;
@@ -323,13 +328,14 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
int h; int h;
int addMeta; /* True to insert a meta records into the file */ 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; 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 /* 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; h = sqliteHashNoCase(p->zName, 0) % N_HASH;
p->pHash = pParse->db->apTblHash[h]; p->pHash = pParse->db->apTblHash[h];
pParse->db->apTblHash[h] = p; 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. ** an error for the parser to find and return NULL.
*/ */
Table *sqliteTableFromToken(Parse *pParse, Token *pTok){ Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
char *zName = sqliteTableNameFromToken(pTok); char *zName;
Table *pTab = sqliteFindTable(pParse->db, zName); Table *pTab;
zName = sqliteTableNameFromToken(pTok);
if( zName==0 ) return 0;
pTab = sqliteFindTable(pParse->db, zName);
sqliteFree(zName); sqliteFree(zName);
if( pTab==0 ){ if( pTab==0 ){
sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0,
@@ -401,6 +410,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
Vdbe *v; Vdbe *v;
int base; int base;
if( pParse->nErr || sqlite_malloc_failed ) return;
pTable = sqliteTableFromToken(pParse, pName); pTable = sqliteTableFromToken(pParse, pName);
if( pTable==0 ) return; if( pTable==0 ) return;
if( pTable->readOnly ){ if( pTable->readOnly ){
@@ -486,6 +496,8 @@ void sqliteCreateIndex(
int i, j, h; int i, j, h;
Token nullId; /* Fake token for an empty ID list */ 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. ** Find the table that is to be indexed. Return early if not found.
*/ */
@@ -512,6 +524,7 @@ void sqliteCreateIndex(
zName = 0; zName = 0;
sqliteSetString(&zName, pTab->zName, "__primary_key", 0); sqliteSetString(&zName, pTab->zName, "__primary_key", 0);
} }
if( zName==0 ) goto exit_create_index;
if( sqliteFindIndex(pParse->db, zName) ){ if( sqliteFindIndex(pParse->db, zName) ){
sqliteSetString(&pParse->zErrMsg, "index ", zName, sqliteSetString(&pParse->zErrMsg, "index ", zName,
" already exists", 0); " already exists", 0);
@@ -541,11 +554,7 @@ void sqliteCreateIndex(
*/ */
pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
sizeof(int)*pList->nId ); sizeof(int)*pList->nId );
if( pIndex==0 ){ if( pIndex==0 ) goto exit_create_index;
sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
pParse->nErr++;
goto exit_create_index;
}
pIndex->aiColumn = (int*)&pIndex[1]; pIndex->aiColumn = (int*)&pIndex[1];
pIndex->zName = (char*)&pIndex->aiColumn[pList->nId]; pIndex->zName = (char*)&pIndex->aiColumn[pList->nId];
strcpy(pIndex->zName, zName); strcpy(pIndex->zName, zName);
@@ -656,7 +665,9 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
char *zName; char *zName;
Vdbe *v; Vdbe *v;
if( pParse->nErr || sqlite_malloc_failed ) return;
zName = sqliteTableNameFromToken(pName); zName = sqliteTableNameFromToken(pName);
if( zName==0 ) return;
pIndex = sqliteFindIndex(pParse->db, zName); pIndex = sqliteFindIndex(pParse->db, zName);
sqliteFree(zName); sqliteFree(zName);
if( pIndex==0 ){ if( pIndex==0 ){
@@ -714,8 +725,8 @@ ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
int i; int i;
if( pList==0 ){ if( pList==0 ){
pList = sqliteMalloc( sizeof(ExprList) ); pList = sqliteMalloc( sizeof(ExprList) );
if( pList==0 ) return 0;
} }
if( pList==0 ) return 0;
if( (pList->nExpr & 7)==0 ){ if( (pList->nExpr & 7)==0 ){
int n = pList->nExpr + 8; int n = pList->nExpr + 8;
pList->a = sqliteRealloc(pList->a, n*sizeof(pList->a[0])); 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 ** Append a new element to the given IdList. Create a new IdList if
** need be. ** need be.
**
** A new IdList is returned, or NULL if malloc() fails.
*/ */
IdList *sqliteIdListAppend(IdList *pList, Token *pToken){ IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
if( pList==0 ){ 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]) ); pList->a = sqliteRealloc(pList->a, (pList->nId+8)*sizeof(pList->a[0]) );
if( pList->a==0 ){ if( pList->a==0 ){
pList->nId = 0; pList->nId = 0;
return pList; sqliteIdListDelete(pList);
return 0;
} }
} }
memset(&pList->a[pList->nId], 0, sizeof(pList->a[0])); memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
if( pToken ){ if( pToken ){
sqliteSetNString(&pList->a[pList->nId].zName, pToken->z, pToken->n, 0); char **pz = &pList->a[pList->nId].zName;
sqliteDequote(pList->a[pList->nId].zName); sqliteSetNString(pz, pToken->z, pToken->n, 0);
if( *pz==0 ){
sqliteIdListDelete(pList);
return 0;
}else{
sqliteDequote(*pz);
}
} }
pList->nId++; pList->nId++;
return pList; return pList;
@@ -793,6 +813,11 @@ void sqliteIdListDelete(IdList *pList){
for(i=0; i<pList->nId; i++){ for(i=0; i<pList->nId; i++){
sqliteFree(pList->a[i].zName); sqliteFree(pList->a[i].zName);
sqliteFree(pList->a[i].zAlias); 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->a);
sqliteFree(pList); sqliteFree(pList);
@@ -824,6 +849,7 @@ void sqliteCopy(
Index *pIdx; Index *pIdx;
zTab = sqliteTableNameFromToken(pTableName); zTab = sqliteTableNameFromToken(pTableName);
if( sqlite_malloc_failed || zTab==0 ) goto copy_cleanup;
pTab = sqliteFindTable(pParse->db, zTab); pTab = sqliteFindTable(pParse->db, zTab);
sqliteFree(zTab); sqliteFree(zTab);
if( pTab==0 ){ if( pTab==0 ){
@@ -891,6 +917,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
char *zName; char *zName;
Vdbe *v; Vdbe *v;
if( pParse->nErr || sqlite_malloc_failed ) return;
if( pTableName ){ if( pTableName ){
zName = sqliteTableNameFromToken(pTableName); zName = sqliteTableNameFromToken(pTableName);
}else{ }else{
@@ -933,6 +960,7 @@ void sqliteBeginTransaction(Parse *pParse){
DbbeMethods *pM; DbbeMethods *pM;
sqlite *db; sqlite *db;
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return; if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
if( pParse->nErr || sqlite_malloc_failed ) return;
if( db->flags & SQLITE_InTrans ) return; if( db->flags & SQLITE_InTrans ) return;
pM = pParse->db->pBe->x; pM = pParse->db->pBe->x;
if( pM && pM->BeginTransaction ){ if( pM && pM->BeginTransaction ){
@@ -953,6 +981,7 @@ void sqliteCommitTransaction(Parse *pParse){
DbbeMethods *pM; DbbeMethods *pM;
sqlite *db; sqlite *db;
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return; 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; if( (db->flags & SQLITE_InTrans)==0 ) return;
pM = pParse->db->pBe->x; pM = pParse->db->pBe->x;
if( pM && pM->Commit ){ if( pM && pM->Commit ){
@@ -973,6 +1002,7 @@ void sqliteRollbackTransaction(Parse *pParse){
DbbeMethods *pM; DbbeMethods *pM;
sqlite *db; sqlite *db;
if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return; 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; if( (db->flags & SQLITE_InTrans)==0 ) return;
pM = pParse->db->pBe->x; pM = pParse->db->pBe->x;
if( pM && pM->Rollback ){ if( pM && pM->Rollback ){

View File

@@ -30,7 +30,7 @@
** relatively simple to convert to a different database such ** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB. ** 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 "sqliteInt.h"
#include <unistd.h> #include <unistd.h>
@@ -65,6 +65,7 @@ Dbbe *sqliteDbbeOpen(
return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg); return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg);
} }
#if 0 /* NOT USED */
/* /*
** Translate the name of an SQL table (or index) into the name ** 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 ** of a file that holds the key/data pairs for that table or
@@ -115,3 +116,4 @@ char *sqliteDbbeNameToFile(
zFile[i] = 0; zFile[i] = 0;
return zFile; return zFile;
} }
#endif /* NOT USED */

View File

@@ -30,7 +30,7 @@
** relatively simple to convert to a different database such ** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB. ** 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 "sqliteInt.h"
#include <gdbm.h> #include <gdbm.h>
@@ -185,6 +185,7 @@ static int sqliteGdbmOpenCursor(
if( pCursr==0 ) return SQLITE_NOMEM; if( pCursr==0 ) return SQLITE_NOMEM;
if( zTable ){ if( zTable ){
zFile = sqliteFileOfTable(pBe, zTable); zFile = sqliteFileOfTable(pBe, zTable);
if( zFile==0 ) return SQLITE_NOMEM;
for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){ for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
if( strcmp(pFile->zName,zFile)==0 ) break; if( strcmp(pFile->zName,zFile)==0 ) break;
} }

View File

@@ -30,7 +30,7 @@
** Nothing is ever written to disk using this backend. All information ** Nothing is ever written to disk using this backend. All information
** is forgotten when the program exits. ** 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 "sqliteInt.h"
#include <sys/stat.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 */ ArrayElem *x; /* Element being copied to new hash table */
new_ht = sqliteMalloc( new_size*sizeof(struct _Array_ht) ); new_ht = sqliteMalloc( new_size*sizeof(struct _Array_ht) );
if( new_ht==0 ){ ArrayClear(array); return; }
if( array->ht ) sqliteFree(array->ht); if( array->ht ) sqliteFree(array->ht);
array->ht = new_ht; array->ht = new_ht;
array->htsize = new_size; 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); memcpy(new_elem->key.p, key.p, key.n);
array->count++; array->count++;
if( array->htsize==0 ) ArrayRehash(array,4); if( array->htsize==0 ) ArrayRehash(array,4);
if( array->htsize==0 ) return nil;
if( array->count > array->htsize ){ if( array->count > array->htsize ){
ArrayRehash(array,array->htsize*2); ArrayRehash(array,array->htsize*2);
if( array->htsize==0 ){
sqliteFree(new_elem);
return nil;
}
} }
h = hraw & (array->htsize-1); h = hraw & (array->htsize-1);
elem = array->ht[h].chain; elem = array->ht[h].chain;
@@ -468,6 +474,7 @@ static int sqliteMemOpenCursor(
if( zTable ){ if( zTable ){
Datum key; Datum key;
zName = sqliteNameOfTable(zTable); zName = sqliteNameOfTable(zTable);
if( zName==0 ) return SQLITE_NOMEM;
key.p = zName; key.p = zName;
key.n = strlen(zName); key.n = strlen(zName);
pTble = ArrayFind(&pBe->tables, key).p; pTble = ArrayFind(&pBe->tables, key).p;
@@ -690,6 +697,7 @@ static int sqliteMemPut(
Datum data, key; Datum data, key;
data.n = nData; data.n = nData;
data.p = sqliteMalloc( data.n ); data.p = sqliteMalloc( data.n );
if( data.p==0 ) return SQLITE_NOMEM;
memcpy(data.p, pData, data.n); memcpy(data.p, pData, data.n);
key.n = nKey; key.n = nKey;
key.p = pKey; key.p = pKey;

View File

@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements. ** 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" #include "sqliteInt.h"
@@ -45,12 +45,18 @@ void sqliteDeleteFrom(
Index *pIdx; /* For looping over indices of the table */ Index *pIdx; /* For looping over indices of the table */
int base; /* Index of the first available table cursor */ 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 /* Locate the table which we want to delete. This table has to be
** put in an IdList structure because some of the subroutines we ** put in an IdList structure because some of the subroutines we
** will be calling are designed to work with multiple tables and expect ** will be calling are designed to work with multiple tables and expect
** an IdList* parameter instead of just a Table* parameger. ** an IdList* parameter instead of just a Table* parameger.
*/ */
pTabList = sqliteIdListAppend(0, pTableName); pTabList = sqliteIdListAppend(0, pTableName);
if( pTabList==0 ) goto delete_from_cleanup;
for(i=0; i<pTabList->nId; i++){ for(i=0; i<pTabList->nId; i++){
pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName); pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
if( pTabList->a[i].pTab==0 ){ if( pTabList->a[i].pTab==0 ){

View File

@@ -24,7 +24,7 @@
** This file contains routines used for analyzing expressions and ** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions. ** 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" #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. ** the number of errors seen and leaves an error message on pParse->zErrMsg.
*/ */
int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
if( pExpr==0 ) return 0; if( pExpr==0 || pTabList==0 ) return 0;
switch( pExpr->op ){ switch( pExpr->op ){
/* A lone identifier */ /* A lone identifier */
case TK_ID: { case TK_ID: {
int cnt = 0; /* Number of matches */ int cnt = 0; /* Number of matches */
int i; /* Loop counter */ int i; /* Loop counter */
char *z = sqliteStrNDup(pExpr->token.z, pExpr->token.n); char *z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
if( z==0 ) return 1;
for(i=0; i<pTabList->nId; i++){ for(i=0; i<pTabList->nId; i++){
int j; int j;
Table *pTab = pTabList->a[i].pTab; Table *pTab = pTabList->a[i].pTab;
@@ -177,6 +178,11 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
assert( pRight && pRight->op==TK_ID ); assert( pRight && pRight->op==TK_ID );
zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n); zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n);
zRight = sqliteStrNDup(pRight->token.z, pRight->token.n); zRight = sqliteStrNDup(pRight->token.z, pRight->token.n);
if( zLeft==0 || zRight==0 ){
sqliteFree(zLeft);
sqliteFree(zRight);
return 1;
}
pExpr->iTable = -1; pExpr->iTable = -1;
for(i=0; i<pTabList->nId; i++){ for(i=0; i<pTabList->nId; i++){
int j; int j;
@@ -480,6 +486,7 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
void sqliteExprCode(Parse *pParse, Expr *pExpr){ void sqliteExprCode(Parse *pParse, Expr *pExpr){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int op; int op;
if( v==0 || pExpr==0 ) return;
switch( pExpr->op ){ switch( pExpr->op ){
case TK_PLUS: op = OP_Add; break; case TK_PLUS: op = OP_Add; break;
case TK_MINUS: op = OP_Subtract; 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){ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int op = 0; int op = 0;
if( v==0 || pExpr==0 ) return;
switch( pExpr->op ){ switch( pExpr->op ){
case TK_LT: op = OP_Lt; break; case TK_LT: op = OP_Lt; break;
case TK_LE: op = OP_Le; 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){ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int op = 0; int op = 0;
if( v==0 || pExpr==0 ) return;
switch( pExpr->op ){ switch( pExpr->op ){
case TK_LT: op = OP_Ge; break; case TK_LT: op = OP_Ge; break;
case TK_LE: op = OP_Gt; break; case TK_LE: op = OP_Gt; break;
@@ -896,8 +905,7 @@ static int appendAggInfo(Parse *pParse){
int amt = pParse->nAgg + 8; int amt = pParse->nAgg + 8;
pParse->aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0])); pParse->aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0]));
if( pParse->aAgg==0 ){ if( pParse->aAgg==0 ){
sqliteSetString(&pParse->zErrMsg, "out of memory", 0); pParse->nAgg = 0;
pParse->nErr++;
return -1; return -1;
} }
} }

View File

@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle INSERT statements. ** 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" #include "sqliteInt.h"
@@ -60,9 +60,12 @@ void sqliteInsert(
int base; /* First available cursor */ int base; /* First available cursor */
int iCont, iBreak; /* Beginning and end of the loop over srcTab */ 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. /* Locate the table into which we will be inserting new information.
*/ */
zTab = sqliteTableNameFromToken(pTableName); zTab = sqliteTableNameFromToken(pTableName);
if( zTab==0 ) goto insert_cleanup;
pTab = sqliteFindTable(pParse->db, zTab); pTab = sqliteFindTable(pParse->db, zTab);
sqliteFree(zTab); sqliteFree(zTab);
if( pTab==0 ){ if( pTab==0 ){
@@ -94,10 +97,11 @@ void sqliteInsert(
srcTab = pParse->nTab++; srcTab = pParse->nTab++;
sqliteVdbeAddOp(v, OP_OpenTbl, srcTab, 1, 0, 0); sqliteVdbeAddOp(v, OP_OpenTbl, srcTab, 1, 0, 0);
rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab); 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 ); assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr; nColumn = pSelect->pEList->nExpr;
}else{ }else{
assert( pList!=0 );
srcTab = -1; srcTab = -1;
assert( pList ); assert( pList );
nColumn = pList->nExpr; nColumn = pList->nExpr;

View File

@@ -26,7 +26,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** 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 "sqliteInt.h"
#include <unistd.h> #include <unistd.h>
@@ -157,8 +157,8 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
*/ */
vdbe = sqliteVdbeCreate(db); vdbe = sqliteVdbeCreate(db);
if( vdbe==0 ){ if( vdbe==0 ){
sqliteSetString(pzErrMsg, "out of memory",0); sqliteSetString(pzErrMsg, "out of memory");
return 1; return SQLITE_NOMEM;
} }
sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg); sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg, rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg,
@@ -179,8 +179,6 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
pTab->readOnly = 1; pTab->readOnly = 1;
} }
db->flags |= SQLITE_Initialized; db->flags |= SQLITE_Initialized;
}else{
sqliteStrRealloc(pzErrMsg);
} }
return rc; return rc;
} }
@@ -216,17 +214,13 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
/* Allocate the sqlite data structure */ /* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite) ); db = sqliteMalloc( sizeof(sqlite) );
if( pzErrMsg ) *pzErrMsg = 0; if( pzErrMsg ) *pzErrMsg = 0;
if( db==0 ){ if( db==0 ) goto no_mem_on_open;
sqliteSetString(pzErrMsg, "out of memory", 0);
sqliteStrRealloc(pzErrMsg);
return 0;
}
/* Open the backend database driver */ /* Open the backend database driver */
db->pBe = sqliteDbbeOpen(zFilename, (mode&0222)!=0, mode!=0, pzErrMsg); db->pBe = sqliteDbbeOpen(zFilename, (mode&0222)!=0, mode!=0, pzErrMsg);
if( db->pBe==0 ){ if( db->pBe==0 ){
sqliteStrRealloc(pzErrMsg);
sqliteFree(db); sqliteFree(db);
sqliteStrRealloc(pzErrMsg);
return 0; return 0;
} }
@@ -235,14 +229,21 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
/* Attempt to read the schema */ /* Attempt to read the schema */
rc = sqliteInit(db, pzErrMsg); 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); sqlite_close(db);
return 0; return 0;
}else /* if( pzErrMsg ) */{ }else /* if( pzErrMsg ) */{
free(*pzErrMsg); sqliteFree(*pzErrMsg);
*pzErrMsg = 0; *pzErrMsg = 0;
} }
return db; 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( pzErrMsg ) *pzErrMsg = 0;
if( (db->flags & SQLITE_Initialized)==0 ){ if( (db->flags & SQLITE_Initialized)==0 ){
int rc = sqliteInit(db, pzErrMsg); int rc = sqliteInit(db, pzErrMsg);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ){
sqliteStrRealloc(pzErrMsg);
return rc;
}
} }
memset(&sParse, 0, sizeof(sParse)); memset(&sParse, 0, sizeof(sParse));
sParse.db = db; sParse.db = db;
sParse.xCallback = xCallback; sParse.xCallback = xCallback;
sParse.pArg = pArg; sParse.pArg = pArg;
sqliteRunParser(&sParse, zSql, pzErrMsg); sqliteRunParser(&sParse, zSql, pzErrMsg);
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", 0);
sParse.rc = SQLITE_NOMEM;
}
sqliteStrRealloc(pzErrMsg);
return sParse.rc; return sParse.rc;
} }
@@ -352,7 +361,7 @@ int sqlite_exec(
** an integer number of milliseconds passed in as the first ** an integer number of milliseconds passed in as the first
** argument. ** argument.
*/ */
static int sqlite_default_busy_callback( static int sqliteDefaultBusyCallback(
void *Timeout, /* Maximum amount of time to wait */ void *Timeout, /* Maximum amount of time to wait */
const char *NotUsed, /* The name of the table that is busy */ const char *NotUsed, /* The name of the table that is busy */
int count /* Number of times table has been 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){ void sqlite_busy_timeout(sqlite *db, int ms){
if( ms>0 ){ if( ms>0 ){
sqlite_busy_handler(db, sqlite_default_busy_callback, (void*)ms); sqlite_busy_handler(db, sqliteDefaultBusyCallback, (void*)ms);
}else{ }else{
sqlite_busy_handler(db, 0, 0); sqlite_busy_handler(db, 0, 0);
} }

View File

@@ -26,7 +26,7 @@
** the parser. Lemon will also generate a header file containing ** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens. ** 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_prefix TK_
%token_type {Token} %token_type {Token}
@@ -170,9 +170,11 @@ cmd ::= select(X). {
select(A) ::= oneselect(X). {A = X;} select(A) ::= oneselect(X). {A = X;}
select(A) ::= select(X) joinop(Y) oneselect(Z). { select(A) ::= select(X) joinop(Y) oneselect(Z). {
if( Z ){
Z->op = Y; Z->op = Y;
Z->pPrior = X; Z->pPrior = X;
A = Z; }
A = Z;
} }
%type joinop {int} %type joinop {int}
joinop(A) ::= UNION. {A = TK_UNION;} joinop(A) ::= UNION. {A = TK_UNION;}
@@ -236,11 +238,11 @@ orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). { sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). {
A = sqliteExprListAppend(X,Y,0); 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). { sortlist(A) ::= sortitem(Y) sortorder(Z). {
A = sqliteExprListAppend(0,Y,0); A = sqliteExprListAppend(0,Y,0);
A->a[0].sortOrder = Z; if( A ) A->a[0].sortOrder = Z;
} }
sortitem(A) ::= expr(X). {A = X;} 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) ::= PLUS INTEGER(X). {A = sqliteExpr(TK_INTEGER, 0, 0, &X);}
item(A) ::= MINUS INTEGER(X). { item(A) ::= MINUS INTEGER(X). {
A = sqliteExpr(TK_UMINUS, 0, 0, 0); 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) ::= FLOAT(X). {A = sqliteExpr(TK_FLOAT, 0, 0, &X);}
item(A) ::= PLUS 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). { item(A) ::= MINUS FLOAT(X). {
A = sqliteExpr(TK_UMINUS, 0, 0, 0); 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) ::= STRING(X). {A = sqliteExpr(TK_STRING, 0, 0, &X);}
item(A) ::= NULL. {A = sqliteExpr(TK_NULL, 0, 0, 0);} 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). { expr(A) ::= LP(B) select(X) RP(E). {
A = sqliteExpr(TK_SELECT, 0, 0, 0); A = sqliteExpr(TK_SELECT, 0, 0, 0);
A->pSelect = X; if( A ) A->pSelect = X;
sqliteExprSpan(A,&B,&E); sqliteExprSpan(A,&B,&E);
} }
expr(A) ::= expr(W) BETWEEN expr(X) AND expr(Y). { expr(A) ::= expr(W) BETWEEN expr(X) AND expr(Y). {
ExprList *pList = sqliteExprListAppend(0, X, 0); ExprList *pList = sqliteExprListAppend(0, X, 0);
pList = sqliteExprListAppend(pList, Y, 0); pList = sqliteExprListAppend(pList, Y, 0);
A = sqliteExpr(TK_BETWEEN, W, 0, 0); A = sqliteExpr(TK_BETWEEN, W, 0, 0);
A->pList = pList; if( A ) A->pList = pList;
sqliteExprSpan(A,&W->span,&Y->span); sqliteExprSpan(A,&W->span,&Y->span);
} }
expr(A) ::= expr(W) NOT BETWEEN expr(X) AND expr(Y). { expr(A) ::= expr(W) NOT BETWEEN expr(X) AND expr(Y). {
ExprList *pList = sqliteExprListAppend(0, X, 0); ExprList *pList = sqliteExprListAppend(0, X, 0);
pList = sqliteExprListAppend(pList, Y, 0); pList = sqliteExprListAppend(pList, Y, 0);
A = sqliteExpr(TK_BETWEEN, W, 0, 0); A = sqliteExpr(TK_BETWEEN, W, 0, 0);
A->pList = pList; if( A ) A->pList = pList;
A = sqliteExpr(TK_NOT, A, 0, 0); A = sqliteExpr(TK_NOT, A, 0, 0);
sqliteExprSpan(A,&W->span,&Y->span); sqliteExprSpan(A,&W->span,&Y->span);
} }
expr(A) ::= expr(X) IN LP exprlist(Y) RP(E). { expr(A) ::= expr(X) IN LP exprlist(Y) RP(E). {
A = sqliteExpr(TK_IN, X, 0, 0); A = sqliteExpr(TK_IN, X, 0, 0);
A->pList = Y; if( A ) A->pList = Y;
sqliteExprSpan(A,&X->span,&E); sqliteExprSpan(A,&X->span,&E);
} }
expr(A) ::= expr(X) IN LP select(Y) RP(E). { expr(A) ::= expr(X) IN LP select(Y) RP(E). {
A = sqliteExpr(TK_IN, X, 0, 0); A = sqliteExpr(TK_IN, X, 0, 0);
A->pSelect = Y; if( A ) A->pSelect = Y;
sqliteExprSpan(A,&X->span,&E); sqliteExprSpan(A,&X->span,&E);
} }
expr(A) ::= expr(X) NOT IN LP exprlist(Y) RP(E). { expr(A) ::= expr(X) NOT IN LP exprlist(Y) RP(E). {
A = sqliteExpr(TK_IN, X, 0, 0); A = sqliteExpr(TK_IN, X, 0, 0);
A->pList = Y; if( A ) A->pList = Y;
A = sqliteExpr(TK_NOT, A, 0, 0); A = sqliteExpr(TK_NOT, A, 0, 0);
sqliteExprSpan(A,&X->span,&E); sqliteExprSpan(A,&X->span,&E);
} }
expr(A) ::= expr(X) NOT IN LP select(Y) RP(E). { expr(A) ::= expr(X) NOT IN LP select(Y) RP(E). {
A = sqliteExpr(TK_IN, X, 0, 0); A = sqliteExpr(TK_IN, X, 0, 0);
A->pSelect = Y; if( A ) A->pSelect = Y;
A = sqliteExpr(TK_NOT, A, 0, 0); A = sqliteExpr(TK_NOT, A, 0, 0);
sqliteExprSpan(A,&X->span,&E); sqliteExprSpan(A,&X->span,&E);
} }

View File

@@ -563,6 +563,7 @@ static int vxprintf(
n += i + 1; n += i + 1;
if( n>etBUFSIZE ){ if( n>etBUFSIZE ){
bufpt = zExtra = sqliteMalloc( n ); bufpt = zExtra = sqliteMalloc( n );
if( bufpt==0 ) return -1;
}else{ }else{
bufpt = buf; bufpt = buf;
} }

View File

@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle SELECT statements. ** 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" #include "sqliteInt.h"
@@ -33,25 +33,33 @@
** structure. ** structure.
*/ */
Select *sqliteSelectNew( Select *sqliteSelectNew(
ExprList *pEList, ExprList *pEList, /* which columns to include in the result */
IdList *pSrc, IdList *pSrc, /* the FROM clause -- which tables to scan */
Expr *pWhere, Expr *pWhere, /* the WHERE clause */
ExprList *pGroupBy, ExprList *pGroupBy, /* the GROUP BY clause */
Expr *pHaving, Expr *pHaving, /* the HAVING clause */
ExprList *pOrderBy, ExprList *pOrderBy, /* the ORDER BY clause */
int isDistinct int isDistinct /* true if the DISTINCT keyword is present */
){ ){
Select *pNew; Select *pNew;
pNew = sqliteMalloc( sizeof(*pNew) ); pNew = sqliteMalloc( sizeof(*pNew) );
if( pNew==0 ) return 0; if( pNew==0 ){
pNew->pEList = pEList; sqliteExprListDelete(pEList);
pNew->pSrc = pSrc; sqliteIdListDelete(pSrc);
pNew->pWhere = pWhere; sqliteExprDelete(pWhere);
pNew->pGroupBy = pGroupBy; sqliteExprListDelete(pGroupBy);
pNew->pHaving = pHaving; sqliteExprDelete(pHaving);
pNew->pOrderBy = pOrderBy; sqliteExprListDelete(pOrderBy);
pNew->isDistinct = isDistinct; }else{
pNew->op = TK_SELECT; 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; return pNew;
} }
@@ -103,6 +111,7 @@ static int selectInnerLoop(
){ ){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int i; int i;
if( v==0 ) return 0;
/* Pull the requested columns. /* Pull the requested columns.
*/ */
@@ -117,8 +126,9 @@ static int selectInnerLoop(
} }
} }
/* If the current result is not distinct, skip the rest /* If the DISTINCT keyword was present on the SELECT statement
** of the processing for the current row. ** and this row has been seen before, then do not make this row
** part of the result.
*/ */
if( distinct>=0 ){ if( distinct>=0 ){
int lbl = sqliteVdbeMakeLabel(v); int lbl = sqliteVdbeMakeLabel(v);
@@ -229,7 +239,7 @@ static
void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int i; int i;
if( pParse->colNamesSet ) return; if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
pParse->colNamesSet = 1; pParse->colNamesSet = 1;
sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0, 0, 0); sqliteVdbeAddOp(v, OP_ColumnCount, pEList->nExpr, 0, 0, 0);
for(i=0; i<pEList->nExpr; i++){ for(i=0; i<pEList->nExpr; i++){
@@ -241,6 +251,7 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
continue; continue;
} }
p = pEList->a[i].pExpr; p = pEList->a[i].pExpr;
if( p==0 ) continue;
if( p->span.z && p->span.z[0] ){ if( p->span.z && p->span.z[0] ){
addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0, 0, 0); addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0, 0, 0);
sqliteVdbeChangeP3(v, addr, p->span.z, p->span.n); 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){ static int fillInColumnList(Parse *pParse, Select *p){
int i, j; int i, j;
IdList *pTabList = p->pSrc; IdList *pTabList;
ExprList *pEList = p->pEList; ExprList *pEList;
if( p==0 || p->pSrc==0 ) return 1;
pTabList = p->pSrc;
pEList = p->pEList;
/* Look up every table in the table list. /* 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 */ /* This routine has run before! No need to continue */
return 0; 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); pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
if( pTabList->a[i].pTab==0 ){ if( pTabList->a[i].pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ", sqliteSetString(&pParse->zErrMsg, "no such table: ",
@@ -326,10 +352,13 @@ static int fillInColumnList(Parse *pParse, Select *p){
Table *pTab = pTabList->a[i].pTab; Table *pTab = pTabList->a[i].pTab;
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
Expr *pExpr = sqliteExpr(TK_DOT, 0, 0, 0); Expr *pExpr = sqliteExpr(TK_DOT, 0, 0, 0);
if( pExpr==0 ) break;
pExpr->pLeft = sqliteExpr(TK_ID, 0, 0, 0); pExpr->pLeft = sqliteExpr(TK_ID, 0, 0, 0);
if( pExpr->pLeft==0 ) break;
pExpr->pLeft->token.z = pTab->zName; pExpr->pLeft->token.z = pTab->zName;
pExpr->pLeft->token.n = strlen(pTab->zName); pExpr->pLeft->token.n = strlen(pTab->zName);
pExpr->pRight = sqliteExpr(TK_ID, 0, 0, 0); pExpr->pRight = sqliteExpr(TK_ID, 0, 0, 0);
if( pExpr->pRight==0 ) break;
pExpr->pRight->token.z = pTab->aCol[j].zName; pExpr->pRight->token.z = pTab->aCol[j].zName;
pExpr->pRight->token.n = strlen(pTab->aCol[j].zName); pExpr->pRight->token.n = strlen(pTab->aCol[j].zName);
pExpr->span.z = ""; pExpr->span.z = "";
@@ -366,7 +395,7 @@ static int matchOrderbyToColumn(
int i, j; int i, j;
ExprList *pEList; ExprList *pEList;
assert( pSelect && pOrderBy ); if( pSelect==0 || pOrderBy==0 ) return 1;
if( mustComplete ){ if( mustComplete ){
for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; } for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; }
} }
@@ -426,10 +455,6 @@ Vdbe *sqliteGetVdbe(Parse *pParse){
if( v==0 ){ if( v==0 ){
v = pParse->pVdbe = sqliteVdbeCreate(pParse->db); v = pParse->pVdbe = sqliteVdbeCreate(pParse->db);
} }
if( v==0 ){
sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
pParse->nErr++;
}
return v; 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 /* Make sure there is no ORDER BY clause on prior SELECTs. Only the
** last SELECT in the series may have an ORDER BY. ** 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; pPrior = p->pPrior;
if( pPrior->pOrderBy ){ if( pPrior->pOrderBy ){
sqliteSetString(&pParse->zErrMsg,"ORDER BY clause should come after ", 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 distinct; /* Table to use for the distinct set */
int base; /* First cursor available for use */ 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 there is are a sequence of queries, do the earlier ones first.
*/ */
if( p->pPrior ){ if( p->pPrior ){
@@ -686,6 +713,7 @@ int sqliteSelect(
return 1; return 1;
} }
pEList = p->pEList; pEList = p->pEList;
if( pEList==0 ) return 1;
/* Allocate a temporary table to use for the DISTINCT set, if /* Allocate a temporary table to use for the DISTINCT set, if
** necessary. This must be done early to allocate the cursor before ** necessary. This must be done early to allocate the cursor before
@@ -820,15 +848,8 @@ int sqliteSelect(
/* Begin generating code. /* Begin generating code.
*/ */
v = pParse->pVdbe; v = sqliteGetVdbe(pParse);
if( v==0 ){ if( v==0 ) return 1;
v = pParse->pVdbe = sqliteVdbeCreate(pParse->db);
}
if( v==0 ){
sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
pParse->nErr++;
return 1;
}
if( pOrderBy ){ if( pOrderBy ){
sqliteVdbeAddOp(v, OP_SortOpen, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_SortOpen, 0, 0, 0, 0);
} }

View File

@@ -24,7 +24,7 @@
** This file contains code to implement the "sqlite" command line ** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases. ** 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 <stdlib.h>
#include <string.h> #include <string.h>
@@ -60,7 +60,7 @@ static sqlite *db = 0;
** The interface is like "readline" but no command-line editing ** The interface is like "readline" but no command-line editing
** is done. ** is done.
*/ */
static char *getline(char *zPrompt){ static char *getline(char *zPrompt, FILE *in){
char *zLine; char *zLine;
int nLine; int nLine;
int n; int n;
@@ -81,7 +81,7 @@ static char *getline(char *zPrompt){
zLine = realloc(zLine, nLine); zLine = realloc(zLine, nLine);
if( zLine==0 ) return 0; if( zLine==0 ) return 0;
} }
if( fgets(&zLine[n], nLine - n, stdin)==0 ){ if( fgets(&zLine[n], nLine - n, in)==0 ){
if( n==0 ){ if( n==0 ){
free(zLine); free(zLine);
return 0; return 0;
@@ -110,11 +110,11 @@ static char *getline(char *zPrompt){
** zPrior is a string of prior text retrieved. If not the empty ** zPrior is a string of prior text retrieved. If not the empty
** string, then issue a continuation prompt. ** 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 *zPrompt;
char *zResult; char *zResult;
if( !isatty ){ if( in!=0 ){
return getline(0); return getline(0, in);
} }
if( zPrior && zPrior[0] ){ if( zPrior && zPrior[0] ){
zPrompt = " ...> "; zPrompt = " ...> ";
@@ -133,6 +133,7 @@ static char *one_input_line(const char *zPrior, int isatty){
*/ */
struct callback_data { struct callback_data {
sqlite *db; /* The database */ sqlite *db; /* The database */
int echoOn; /* True to echo input commands */
int cnt; /* Number of records displayed so far */ int cnt; /* Number of records displayed so far */
FILE *out; /* Write results here */ FILE *out; /* Write results here */
int mode; /* An output mode setting */ 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. ** This routine should print text sufficient to recreate the table.
*/ */
static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ 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; 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 ){ if( strcmp(azArg[1],"table")==0 ){
struct callback_data d2; struct callback_data d2;
d2 = *pData; d2 = *p;
d2.mode = MODE_List; d2.mode = MODE_List;
d2.escape = '\t'; d2.escape = '\t';
strcpy(d2.separator,"\t"); strcpy(d2.separator,"\t");
fprintf(pData->out, "COPY '%s' FROM STDIN;\n", azArg[0]); fprintf(p->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
sqlite_exec_printf(pData->db, sqlite_exec_printf(p->db,
"SELECT * FROM '%q'", "SELECT * FROM '%q'",
callback, &d2, 0, azArg[0] 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; return 0;
} }
@@ -414,6 +415,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
*/ */
static char zHelp[] = static char zHelp[] =
".dump ?TABLE? ... Dump the database in an text format\n" ".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" ".exit Exit this program\n"
".explain Set output mode suitable for EXPLAIN\n" ".explain Set output mode suitable for EXPLAIN\n"
".header ON|OFF Turn display of headers on or off\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" ".mode insert TABLE Generate SQL insert statements for TABLE\n"
".output FILENAME Send output to FILENAME\n" ".output FILENAME Send output to FILENAME\n"
".output stdout Send output to the screen\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" ".schema ?TABLE? Show the CREATE statements\n"
".separator STRING Change separator string for \"list\" mode\n" ".separator STRING Change separator string for \"list\" mode\n"
".tables ?PATTERN? List names of tables matching a pattern\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" ".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 ** If an input line begins with "." then invoke this routine to
** process that line. ** process that line.
@@ -491,6 +499,21 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
} }
}else }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 ){ if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
exit(0); exit(0);
}else }else
@@ -559,6 +582,8 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
}else{ }else{
sprintf(p->zDestTable,"table"); sprintf(p->zDestTable,"table");
} }
}else {
fprintf(stderr,"mode should be on of: column html insert line list\n");
} }
}else }else
@@ -577,6 +602,50 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
} }
}else }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 ){ if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
struct callback_data data; struct callback_data data;
char *zErrMsg = 0; 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){ int main(int argc, char **argv){
char *zErrMsg = 0; char *zErrMsg = 0;
char *argv0 = argv[0];
struct callback_data data; struct callback_data data;
int echo = 0;
Argv0 = argv[0];
memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(data));
data.mode = MODE_List; data.mode = MODE_List;
strcpy(data.separator,"|"); strcpy(data.separator,"|");
@@ -724,16 +845,16 @@ int main(int argc, char **argv){
argc--; argc--;
argv++; argv++;
}else if( strcmp(argv[1],"-echo")==0 ){ }else if( strcmp(argv[1],"-echo")==0 ){
echo = 1; data.echoOn = 1;
argc--; argc--;
argv++; argv++;
}else{ }else{
fprintf(stderr,"%s: unknown option: %s\n", argv0, argv[1]); fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]);
return 1; return 1;
} }
} }
if( argc!=2 && argc!=3 ){ 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); exit(1);
} }
data.db = db = sqlite_open(argv[1], 0666, &zErrMsg); data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
@@ -757,57 +878,15 @@ int main(int argc, char **argv){
exit(1); exit(1);
} }
}else{ }else{
char *zLine; if( isatty(0) ){
char *zSql = 0;
int nSql = 0;
int istty = isatty(0);
if( istty ){
printf( printf(
"SQLite version %s\n" "SQLite version %s\n"
"Enter \".help\" for instructions\n", "Enter \".help\" for instructions\n",
sqlite_version sqlite_version
); );
} process_input(&data, 0);
while( (zLine = one_input_line(zSql, istty))!=0 ){ }else{
if( echo ) printf("%s\n", zLine); process_input(&data, stdin);
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;
}
} }
} }
sqlite_close(db); sqlite_close(db);

View File

@@ -23,7 +23,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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 "sqlite.h"
#include "dbbe.h" #include "dbbe.h"
@@ -65,6 +65,12 @@ typedef unsigned int u32;
# define sqliteStrRealloc(X) # define sqliteStrRealloc(X)
#endif #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 ** The following global variables are used for testing and debugging
** only. They only work if MEMORY_DEBUG is defined. ** only. They only work if MEMORY_DEBUG is defined.
@@ -257,8 +263,9 @@ struct IdList {
struct { struct {
char *zName; /* Text of the identifier. */ char *zName; /* Text of the identifier. */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ 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 */ 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 */ } *a; /* One entry for each identifier on the list */
}; };

View File

@@ -140,7 +140,7 @@ int sqlite_get_table(
res.nRow = 0; res.nRow = 0;
res.nColumn = 0; res.nColumn = 0;
res.nData = 1; res.nData = 1;
res.nAlloc = 200; res.nAlloc = 20;
res.rc = SQLITE_OK; res.rc = SQLITE_OK;
res.azResult = malloc( sizeof(char*)*res.nAlloc ); res.azResult = malloc( sizeof(char*)*res.nAlloc );
if( res.azResult==0 ){ if( res.azResult==0 ){

View File

@@ -25,7 +25,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** 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 "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@@ -267,6 +267,50 @@ static int sqlite_mprintf_double(
return TCL_OK; 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. ** 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, Tcl_CreateCommand(interp, "sqlite_get_table_printf", test_get_table_printf,
0, 0); 0, 0);
Tcl_CreateCommand(interp, "sqlite_close", sqlite_test_close, 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; return TCL_OK;
} }

View File

@@ -27,7 +27,7 @@
** individual tokens and sends those tokens one-by-one over to the ** individual tokens and sends those tokens one-by-one over to the
** parser for analysis. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -107,7 +107,7 @@ static Keyword aKeywordTable[] = {
/* /*
** This is the hash table ** This is the hash table
*/ */
#define KEY_HASH_SIZE 69 #define KEY_HASH_SIZE 71
static Keyword *apHashTable[KEY_HASH_SIZE]; static Keyword *apHashTable[KEY_HASH_SIZE];
@@ -328,7 +328,7 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
#ifndef NDEBUG #ifndef NDEBUG
sqliteParserTrace(trace, "parser: "); sqliteParserTrace(trace, "parser: ");
#endif #endif
while( nErr==0 && i>=0 && zSql[i]!=0 ){ while( sqlite_malloc_failed==0 && nErr==0 && i>=0 && zSql[i]!=0 ){
int tokenType; int tokenType;
if( (pParse->db->flags & SQLITE_Interrupt)!=0 ){ if( (pParse->db->flags & SQLITE_Interrupt)!=0 ){
@@ -363,24 +363,6 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
pParse->db->flags |= SQLITE_VdbeTrace; pParse->db->flags |= SQLITE_VdbeTrace;
}else if( sqliteStrNICmp(z,"--vdbe-trace-off--", 18)==0 ){ }else if( sqliteStrNICmp(z,"--vdbe-trace-off--", 18)==0 ){
pParse->db->flags &= ~SQLITE_VdbeTrace; 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 #endif
break; break;
@@ -437,7 +419,6 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
pParse->pNewTable = 0; pParse->pNewTable = 0;
} }
sqliteParseInfoReset(pParse); sqliteParseInfoReset(pParse);
sqliteStrRealloc(pzErrMsg);
if( nErr>0 && pParse->rc==SQLITE_OK ){ if( nErr>0 && pParse->rc==SQLITE_OK ){
pParse->rc = SQLITE_ERROR; pParse->rc = SQLITE_ERROR;
} }

View File

@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle UPDATE statements. ** 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" #include "sqliteInt.h"
@@ -51,12 +51,15 @@ void sqliteUpdate(
** an expression for the i-th column of the table. ** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */ ** 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 /* Locate the table which we want to update. This table has to be
** put in an IdList structure because some of the subroutines we ** put in an IdList structure because some of the subroutines we
** will be calling are designed to work with multiple tables and expect ** will be calling are designed to work with multiple tables and expect
** an IdList* parameter instead of just a Table* parameger. ** an IdList* parameter instead of just a Table* parameger.
*/ */
pTabList = sqliteIdListAppend(0, pTableName); pTabList = sqliteIdListAppend(0, pTableName);
if( pTabList==0 ) goto update_cleanup;
for(i=0; i<pTabList->nId; i++){ for(i=0; i<pTabList->nId; i++){
pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName); pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
if( pTabList->a[i].pTab==0 ){ if( pTabList->a[i].pTab==0 ){

View File

@@ -26,12 +26,18 @@
** This file contains functions for allocating memory, comparing ** This file contains functions for allocating memory, comparing
** strings, and stuff like that. ** 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 "sqliteInt.h"
#include <stdarg.h> #include <stdarg.h>
#include <ctype.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 ** If MEMORY_DEBUG is defined, then use versions of malloc() and
** free() that track memory usage and check for buffer overruns. ** free() that track memory usage and check for buffer overruns.
@@ -58,12 +64,18 @@ void *sqliteMalloc_(int n, char *zFile, int line){
sqlite_nMalloc++; sqlite_nMalloc++;
if( sqlite_iMallocFail>=0 ){ if( sqlite_iMallocFail>=0 ){
sqlite_iMallocFail--; sqlite_iMallocFail--;
if( sqlite_iMallocFail==0 ) return 0; if( sqlite_iMallocFail==0 ){
sqlite_malloc_failed++;
return 0;
}
} }
if( n==0 ) return 0; if( n==0 ) return 0;
k = (n+sizeof(int)-1)/sizeof(int); k = (n+sizeof(int)-1)/sizeof(int);
pi = malloc( (3+k)*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[0] = 0xdead1122;
pi[1] = n; pi[1] = n;
pi[k+2] = 0xdead3344; 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); k = (n + sizeof(int) - 1)/sizeof(int);
pi = malloc( (k+3)*sizeof(int) ); pi = malloc( (k+3)*sizeof(int) );
if( pi==0 ){
sqlite_malloc_failed++;
return 0;
}
pi[0] = 0xdead1122; pi[0] = 0xdead1122;
pi[1] = n; pi[1] = n;
pi[k+2] = 0xdead3344; 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() ** Make a duplicate of a string into memory obtained from malloc()
** Free the original string using sqliteFree(). ** 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){ void sqliteStrRealloc(char **pz){
char *zNew; char *zNew;
if( pz==0 || *pz==0 ) return; if( pz==0 || *pz==0 ) return;
zNew = malloc( strlen(*pz) + 1 ); 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); sqliteFree(*pz);
*pz = zNew; *pz = zNew;
} }
@@ -191,7 +216,10 @@ char *sqliteStrNDup_(const char *z, int n, char *zFile, int line){
*/ */
void *sqliteMalloc(int n){ void *sqliteMalloc(int n){
void *p = malloc(n); void *p = malloc(n);
if( p==0 ) return 0; if( p==0 ){
sqlite_malloc_failed++;
return 0;
}
memset(p, 0, n); memset(p, 0, n);
return p; return p;
} }
@@ -218,7 +246,11 @@ void *sqliteRealloc(void *p, int n){
sqliteFree(p); sqliteFree(p);
return 0; 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){ void sqliteDequote(char *z){
int quote; int quote;
int i, j; int i, j;
if( z==0 ) return;
quote = z[0]; quote = z[0];
if( quote!='\'' && quote!='"' ) return; if( quote!='\'' && quote!='"' ) return;
for(i=1, j=0; z[i]; i++){ for(i=1, j=0; z[i]; i++){

View File

@@ -41,7 +41,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** 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 "sqliteInt.h"
#include <unistd.h> #include <unistd.h>
@@ -223,8 +223,8 @@ struct Vdbe {
*/ */
Vdbe *sqliteVdbeCreate(sqlite *db){ Vdbe *sqliteVdbeCreate(sqlite *db){
Vdbe *p; Vdbe *p;
p = sqliteMalloc( sizeof(Vdbe) ); p = sqliteMalloc( sizeof(Vdbe) );
if( p==0 ) return 0;
p->pBe = db->pBe; p->pBe = db->pBe;
p->db = db; p->db = db;
return p; return p;
@@ -368,7 +368,7 @@ void sqliteVdbeDequoteP3(Vdbe *p, int addr){
char *z; char *z;
if( addr<0 || addr>=p->nOp ) return; if( addr<0 || addr>=p->nOp ) return;
z = p->aOp[addr].p3; z = p->aOp[addr].p3;
sqliteDequote(z); if( z ) sqliteDequote(z);
} }
/* /*
@@ -381,6 +381,7 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
int i, j; int i, j;
if( addr<0 || addr>=p->nOp ) return; if( addr<0 || addr>=p->nOp ) return;
z = p->aOp[addr].p3; z = p->aOp[addr].p3;
if( z==0 ) return;
i = j = 0; i = j = 0;
while( isspace(z[i]) ){ i++; } while( isspace(z[i]) ){ i++; }
while( z[i] ){ while( z[i] ){
@@ -462,6 +463,10 @@ static void AggRehash(Agg *p, int nHash){
if( p->nHash==nHash ) return; if( p->nHash==nHash ) return;
size = nHash * sizeof(AggElem*); size = nHash * sizeof(AggElem*);
p->apHash = sqliteRealloc(p->apHash, size ); p->apHash = sqliteRealloc(p->apHash, size );
if( p->apHash==0 ){
AggReset(p);
return;
}
memset(p->apHash, 0, size); memset(p->apHash, 0, size);
p->nHash = nHash; p->nHash = nHash;
for(pElem=p->pFirst; pElem; pElem=pElem->pNext){ 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; if( strcmp(pElem->zKey, zKey)==0 ) return;
} }
pElem = sqliteMalloc( sizeof(*pElem) + strlen(zKey) ); pElem = sqliteMalloc( sizeof(*pElem) + strlen(zKey) );
if( pElem==0 ) return; if( pElem==0 ){
SetClear(p);
return;
}
strcpy(pElem->zKey, zKey); strcpy(pElem->zKey, zKey);
pElem->pNext = p->pAll; pElem->pNext = p->pAll;
p->pAll = pElem; p->pAll = pElem;
@@ -1004,6 +1012,7 @@ int sqliteVdbeExec(
} }
#endif #endif
/* if( pzErrMsg ){ *pzErrMsg = 0; } */ /* if( pzErrMsg ){ *pzErrMsg = 0; } */
if( sqlite_malloc_failed ) rc = SQLITE_NOMEM;
for(pc=0; rc==SQLITE_OK && pc<p->nOp VERIFY(&& pc>=0); pc++){ for(pc=0; rc==SQLITE_OK && pc<p->nOp VERIFY(&& pc>=0); pc++){
pOp = &p->aOp[pc]; pOp = &p->aOp[pc];
@@ -1364,8 +1373,7 @@ int sqliteVdbeExec(
Realify(p, nos); Realify(p, nos);
copy = aStack[tos].r>aStack[nos].r; copy = aStack[tos].r>aStack[nos].r;
}else{ }else{
Stringify(p, tos); if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
Stringify(p, nos);
copy = sqliteCompare(zStack[tos],zStack[nos])>0; copy = sqliteCompare(zStack[tos],zStack[nos])>0;
} }
if( copy ){ if( copy ){
@@ -1405,8 +1413,7 @@ int sqliteVdbeExec(
Realify(p, nos); Realify(p, nos);
copy = aStack[tos].r<aStack[nos].r; copy = aStack[tos].r<aStack[nos].r;
}else{ }else{
Stringify(p, tos); if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
Stringify(p, nos);
copy = sqliteCompare(zStack[tos],zStack[nos])<0; copy = sqliteCompare(zStack[tos],zStack[nos])<0;
} }
if( copy ){ if( copy ){
@@ -1485,8 +1492,7 @@ int sqliteVdbeExec(
if( (ft & fn)==STK_Int ){ if( (ft & fn)==STK_Int ){
c = aStack[nos].i - aStack[tos].i; c = aStack[nos].i - aStack[tos].i;
}else{ }else{
Stringify(p, tos); if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
Stringify(p, nos);
c = sqliteCompare(zStack[nos], zStack[tos]); c = sqliteCompare(zStack[nos], zStack[tos]);
} }
switch( pOp->opcode ){ switch( pOp->opcode ){
@@ -1523,8 +1529,7 @@ int sqliteVdbeExec(
int nos = tos - 1; int nos = tos - 1;
int c; int c;
VERIFY( if( nos<0 ) goto not_enough_stack; ) VERIFY( if( nos<0 ) goto not_enough_stack; )
Stringify(p, tos); if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
Stringify(p, nos);
c = sqliteLikeCompare(zStack[tos], zStack[nos]); c = sqliteLikeCompare(zStack[tos], zStack[nos]);
POPSTACK; POPSTACK;
POPSTACK; POPSTACK;
@@ -1556,8 +1561,7 @@ int sqliteVdbeExec(
int nos = tos - 1; int nos = tos - 1;
int c; int c;
VERIFY( if( nos<0 ) goto not_enough_stack; ) VERIFY( if( nos<0 ) goto not_enough_stack; )
Stringify(p, tos); if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
Stringify(p, nos);
c = sqliteGlobCompare(zStack[tos], zStack[nos]); c = sqliteGlobCompare(zStack[tos], zStack[nos]);
POPSTACK; POPSTACK;
POPSTACK; POPSTACK;
@@ -3070,7 +3074,7 @@ int sqliteVdbeExec(
int nKey; int nKey;
VERIFY( if( tos<0 ) goto not_enough_stack; ) VERIFY( if( tos<0 ) goto not_enough_stack; )
Stringify(p, tos); if( Stringify(p, tos) ) goto no_mem;
zKey = zStack[tos]; zKey = zStack[tos];
nKey = aStack[tos].n; nKey = aStack[tos].n;
if( p->agg.nHash<=0 ){ if( p->agg.nHash<=0 ){
@@ -3086,6 +3090,7 @@ int sqliteVdbeExec(
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
}else{ }else{
AggInsert(&p->agg, zKey); AggInsert(&p->agg, zKey);
if( sqlite_malloc_failed ) goto no_mem;
} }
POPSTACK; POPSTACK;
break; break;
@@ -3241,10 +3246,11 @@ int sqliteVdbeExec(
}else{ }else{
int tos = p->tos; int tos = p->tos;
if( tos<0 ) goto not_enough_stack; if( tos<0 ) goto not_enough_stack;
Stringify(p, tos); if( Stringify(p, tos) ) goto no_mem;
SetInsert(&p->aSet[i], zStack[tos]); SetInsert(&p->aSet[i], zStack[tos]);
POPSTACK; POPSTACK;
} }
if( sqlite_malloc_failed ) goto no_mem;
break; break;
} }
@@ -3258,7 +3264,7 @@ int sqliteVdbeExec(
int i = pOp->p1; int i = pOp->p1;
int tos = p->tos; int tos = p->tos;
VERIFY( if( tos<0 ) goto not_enough_stack; ) 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])){ if( VERIFY( i>=0 && i<p->nSet &&) SetTest(&p->aSet[i], zStack[tos])){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
} }
@@ -3276,7 +3282,7 @@ int sqliteVdbeExec(
int i = pOp->p1; int i = pOp->p1;
int tos = p->tos; int tos = p->tos;
VERIFY( if( tos<0 ) goto not_enough_stack; ) 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])){ if(VERIFY( i>=0 && i<p->nSet &&) !SetTest(&p->aSet[i], zStack[tos])){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
} }
@@ -3293,7 +3299,7 @@ int sqliteVdbeExec(
int tos = p->tos; int tos = p->tos;
int len; int len;
VERIFY( if( tos<0 ) goto not_enough_stack; ) VERIFY( if( tos<0 ) goto not_enough_stack; )
Stringify(p, tos); if( Stringify(p, tos) ) goto no_mem;
#ifdef SQLITE_UTF8 #ifdef SQLITE_UTF8
{ {
char *z = zStack[tos]; char *z = zStack[tos];
@@ -3351,7 +3357,7 @@ int sqliteVdbeExec(
start = pOp->p1 - 1; start = pOp->p1 - 1;
} }
VERIFY( if( p->tos<0 ) goto not_enough_stack; ) 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. /* "n" will be the number of characters in the input string.
** For iso8859, the number of characters is the number of bytes. ** For iso8859, the number of characters is the number of bytes.

View File

@@ -25,7 +25,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines ** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions. ** 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" #include "sqliteInt.h"
@@ -170,8 +170,9 @@ WhereInfo *sqliteWhereBegin(
** return value. ** return value.
*/ */
pWInfo = sqliteMalloc( sizeof(WhereInfo) ); pWInfo = sqliteMalloc( sizeof(WhereInfo) );
if( pWInfo==0 ){ if( sqlite_malloc_failed ){
sqliteFree(aOrder); sqliteFree(aOrder);
sqliteFree(pWInfo);
return 0; return 0;
} }
pWInfo->pParse = pParse; pWInfo->pParse = pParse;

View File

@@ -22,7 +22,7 @@
#*********************************************************************** #***********************************************************************
# This file runs all tests. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -53,6 +53,7 @@ for {set Counter 0} {$Counter<$COUNT} {incr Counter} {
set dbprefix $p set dbprefix $p
foreach testfile [lsort -dictionary [glob $testdir/*.test]] { foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
if {[file tail $testfile]=="all.test"} continue if {[file tail $testfile]=="all.test"} continue
if {[file tail $testfile]=="malloc.test"} continue
source $testfile source $testfile
} }
} }
@@ -79,4 +80,13 @@ if {$LeakList!=""} {
puts " Ok" 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 really_finish_test

View File

@@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the sqlite_*_printf() interface. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl 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 { do_test printf-1.$n.3 [subst {
sqlite_mprintf_int {Three integers: (%-6d) (%-6x) (%-6o)} $v $v $v sqlite_mprintf_int {Three integers: (%-6d) (%-6x) (%-6o)} $v $v $v
}] [format {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 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} sqlite_mprintf_str {%d %d A quoted string: '%q'} 1 2 {Hi Y'all}
} {1 2 A quoted string: '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 finish_test

View File

@@ -24,7 +24,7 @@
# focus of this file is testing the sqlite_exec_printf() and # focus of this file is testing the sqlite_exec_printf() and
# sqlite_get_table_printf() APIs. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -48,6 +48,49 @@ do_test tableapi-2.1 {
SELECT * FROM xyz WHERE b='%q' SELECT * FROM xyz WHERE b='%q'
} {Hi Y'all} } {Hi Y'all}
} {0 1 2 a b 1 {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 { do_test tableapi-99.0 {
sqlite_close $::dbx sqlite_close $::dbx

View File

@@ -23,7 +23,7 @@
# This file implements some common TCL routines used for regression # This file implements some common TCL routines used for regression
# testing the SQLite library # 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 # Make sure tclsqlite was compiled correctly. Abort now with an
# error message if not. # error message if not.
@@ -183,7 +183,7 @@ proc testif {args} {
set ::skip_test 1 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) # (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 # to see how many malloc()s have not been free()ed. The number
# of surplus malloc()s is stored in the global variable $::Leak. # of surplus malloc()s is stored in the global variable $::Leak.
@@ -191,10 +191,10 @@ proc testif {args} {
# in the library. # in the library.
# #
proc memleak_check {} { proc memleak_check {} {
set r [execsql {--malloc-stats--}] if {[info command sqlite_malloc_stat]!=""} {
if {$r==""} return set r [sqlite_malloc_stat]
set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}] set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
# puts "*** $::Leak mallocs have not been freed ***" }
} }
# Run this routine last # Run this routine last

View File

@@ -17,7 +17,8 @@ proc chng {date desc} {
puts "<DD><P><UL>$desc</UL></P></DD>" 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> <li>New tests added to the test suite.</li>
} }