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:
60
manifest
60
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
|
||||
|
@@ -1 +1 @@
|
||||
2507ec40610d8034ccf9dcb58a16934065e6f120
|
||||
86b30cd0975dfea9424b9f9f0d4194aa71ce508b
|
80
src/build.c
80
src/build.c
@@ -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,9 +97,11 @@ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
|
||||
** text between the two given tokens.
|
||||
*/
|
||||
void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
|
||||
if( pExpr ){
|
||||
pExpr->span.z = pLeft->z;
|
||||
pExpr->span.n = pRight->n + (int)pRight->z - (int)pLeft->z;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Construct a new expression node for a function with multiple
|
||||
@@ -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,11 +280,11 @@ 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;
|
||||
}
|
||||
}
|
||||
memset(&p->aCol[p->nCol], 0, sizeof(p->aCol[0]));
|
||||
pz = &p->aCol[p->nCol++].zName;
|
||||
sqliteSetNString(pz, pName->z, pName->n, 0);
|
||||
@@ -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->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 ){
|
||||
|
@@ -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 */
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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 ){
|
||||
|
16
src/expr.c
16
src/expr.c
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
41
src/main.c
41
src/main.c
@@ -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);
|
||||
}
|
||||
|
26
src/parse.y
26
src/parse.y
@@ -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,8 +170,10 @@ 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;
|
||||
}
|
||||
%type joinop {int}
|
||||
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
79
src/select.c
79
src/select.c
@@ -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"
|
||||
|
||||
@@ -33,17 +33,24 @@
|
||||
** 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;
|
||||
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;
|
||||
@@ -52,6 +59,7 @@ Select *sqliteSelectNew(
|
||||
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);
|
||||
}
|
||||
|
205
src/shell.c
205
src/shell.c
@@ -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);
|
||||
}
|
||||
process_input(&data, 0);
|
||||
}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, stdin);
|
||||
}
|
||||
}
|
||||
sqlite_close(db);
|
||||
|
@@ -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 */
|
||||
};
|
||||
|
||||
|
@@ -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 ){
|
||||
|
50
src/test1.c
50
src/test1.c
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 ){
|
||||
|
45
src/util.c
45
src/util.c
@@ -26,12 +26,18 @@
|
||||
** 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++){
|
||||
|
46
src/vdbe.c
46
src/vdbe.c
@@ -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.
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
if {[info command sqlite_malloc_stat]!=""} {
|
||||
set r [sqlite_malloc_stat]
|
||||
set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
|
||||
# puts "*** $::Leak mallocs have not been freed ***"
|
||||
}
|
||||
}
|
||||
|
||||
# Run this routine last
|
||||
|
@@ -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>
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user