From 6d4abfbee5a90b8254f102236e2aefddf517d57e Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 22 Oct 2001 02:58:08 +0000 Subject: [PATCH] More changes for 2.0.7. (CVS 293) FossilOrigin-Name: f8328a5f11801c5124f9a8dace22df3c1cfb2191 --- manifest | 56 +++++++------- manifest.uuid | 2 +- src/btree.c | 4 +- src/build.c | 68 +++++++++++------ src/expr.c | 8 +- src/hash.c | 11 +-- src/main.c | 24 +++++- src/os.c | 9 ++- src/pager.c | 8 +- src/printf.c | 17 ++++- src/select.c | 6 +- src/sqlite.h.in | 5 +- src/sqliteInt.h | 7 +- src/table.c | 15 +++- src/tclsqlite.c | 115 +++++++++++++++++++++++------ src/tokenize.c | 11 +-- src/util.c | 22 ++++-- src/vdbe.c | 138 +++++++++++++++++++++-------------- test/all.test | 9 ++- test/btree2.test | 39 ++++++---- test/malloc.test | 173 ++++++++++++++++++++++++++++++++++++-------- test/quick.test | 3 +- test/tclsqlite.test | 27 ++++++- tool/memleak.awk | 1 + www/changes.tcl | 12 ++- 25 files changed, 567 insertions(+), 223 deletions(-) diff --git a/manifest b/manifest index 85f218768f..68b41ffcb3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C 2.0.7\s(CVS\s292) -D 2001-10-20T12:30:11 +C More\schanges\sfor\s2.0.7.\s(CVS\s293) +D 2001-10-22T02:58:09 F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd F Makefile.template 1fdb891f14083ee0b63cf7282f91529634438e7a F README 93d2977cc5c6595c448de16bdefc312b9d401533 @@ -19,43 +19,43 @@ F libtool c56e618713c9510a103bda6b95f3ea3900dcacd6 F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1 F publish.sh badcd69b8e3a8bc69b162c4c9d7c209b2a0b119e F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 -F src/btree.c 97653e88bc4b7396226b93c878b153c77f1d3d03 +F src/btree.c 89380aea55bd0d5c756d92ec9bee756203f63a6b F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7 -F src/build.c d18081e69b23390cb6baaaf6f6c804b93775a0be +F src/build.c 8857c16751a5e9c5ee845e1b3cf2da78935c8cb3 F src/delete.c 6fe2191c49c4a31336e2fac11b3ad665ddcd4246 -F src/expr.c c1381b8229a5573b0928ede962e45c1c49d067af -F src/hash.c b7ced0735287c142a3b2db46c3cae3e6826afb75 +F src/expr.c 2dd0252ced345c1e64db015b94dc6b5d7a57eef3 +F src/hash.c d0110e6da70a5962e21575fccf8206f7d9d75e00 F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac F src/insert.c b65c1d4b848e45d41e9dcccd2b226ca335de67b6 -F src/main.c 9a18e97290d41844e8c12e021fb7c42948a19dc9 +F src/main.c 47922699c75e24ffec071cdf300405436e5bb16e F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c -F src/os.c 2a501026a66416292a30ab5b0988ec75783340ae +F src/os.c 66b677479eae37e30bdfbe32deb0fe6a2efca983 F src/os.h bed702c9e3b768bc3cb1b12c90b83d099c1546be -F src/pager.c 5e2877673e93ad2fa83e6d49fcd8d9590f8f38a5 +F src/pager.c 0bd0b4b693edb43c72774e3e749d8667e2ae7094 F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca F src/parse.y 148e4cd134d3cbd816dcb0df50e49e498faa6ba4 -F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9 +F src/printf.c 167fbfb192b4dce48154398f22dbc614e9f5d088 F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b -F src/select.c 898b27a324afc067e253a9c04e63701f10b0af1c +F src/select.c d14511afacf788bf4a0c517011c2c53038539388 F src/shell.c 71597951753b56a97fea1c7a30908f31e635c00c F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e -F src/sqlite.h.in b95c161abf1d58bceb05290fa3f657d8f388fc11 -F src/sqliteInt.h 52577abf2805ba148972f69788ed49c64064fa31 -F src/table.c 7102da21a8e4b2f8a4df79378d6dc0b01aa76a33 -F src/tclsqlite.c 7d205aeda449047f86b39a6c55731a1ded7a7ab5 +F src/sqlite.h.in f2c40c869ff40ad3e60d8a3b1f72777fa28b32fc +F src/sqliteInt.h 9a18aebf42a805ba02f55eba2239beabe35f02b3 +F src/table.c be9c7bf883c731c6719f0fcc188ea2bac8ae7122 +F src/tclsqlite.c 4896e078495bf868742f5394dcf01c5efe5bea02 F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49 F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321 F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96 -F src/tokenize.c 59ddae1501de472e9a6274a1cbf451170c52488c +F src/tokenize.c 8f4c2b5e7fb471ba194979fb4dd5f947402fd792 F src/update.c c916182c6bfbc8a6f20c24920c4560fece6c9569 -F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387 -F src/vdbe.c 0aea4e858880867ffd59d9598da9b3f9ab5d97b9 +F src/util.c aa4d2de60cb2445239b71c79c3a8c0b7c0d3336a +F src/vdbe.c aa28392b908ef8ee338e77af49ce2903b85f7b22 F src/vdbe.h f8407fd6b644bc001b1e7c65460c9962f6a15f6b F src/where.c 22fe910c7c8e2736eb37e9861343e90c0b513c86 -F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd +F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0 F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce -F test/btree2.test 20ce47ab804f15b6563736528bdd38aabe5193dc +F test/btree2.test 08e9485619265cbaf5d11bd71f357cdc26bb87e0 F test/copy.test 768e6f1701a07d08090e1ca7f7dcce0a7a72b43e F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8 F test/expr.test b4171c84b767f7b7e94dbce4824ba8e981a1c72f @@ -67,11 +67,11 @@ F test/insert2.test d6901ca931e308fea7fca8c95ebe7dc957cc9fc2 F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1 F test/main.test 1626345b5f630c5398eede500d9354813b76b0fd -F test/malloc.test f1400a8d002eb96f1ca0a34abe56d2ab3e324740 +F test/malloc.test 70fdd0812e2a57eb746aaf015350f58bb8eee0b1 F test/misc1.test 50a5ca3481fc1f3cd6b978bcd6ed04c06f26a1e6 F test/pager.test 59bbc4e3d489529ed33db6e15595789e51056077 F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da -F test/quick.test b6ec50f808efc06595fd324bf4f3fabadb9c7e9c +F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05 F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435 F test/rowid.test 427bfbbe9684fe7a2f851aa05badaae6d4972ce8 F test/select1.test 75af194669ff9f4fe42c6fd070d9ec3b268354bb @@ -83,7 +83,7 @@ F test/sort.test 462c1161eee1abaa7cc93990e0b34d5fdb70ce19 F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78 F test/table.test 3ef4254d62ece31a3872ab11cdaec846f6fa8fd1 F test/tableapi.test 51d0c209aa6b1158cb952ec917c656d4ce66e9e4 -F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a +F test/tclsqlite.test feca0f2b23ba51d202d67d71e10ba7a8a1621f82 F test/temptable.test 37acd9e39781c2ff7cff2ba741b6b27ce020a44a F test/tester.tcl c7ddeebc14cc841abb37134cd5d40c1e3ad367c1 F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9 @@ -93,7 +93,7 @@ F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e F test/where.test 43d5ac94da3f3722375307f948884dc79b326a91 F tool/lemon.c 5533b63e5cdbb1efc939abac3c2f4f37ac839488 F tool/lempar.c 9b604e6a8b3d55c0b9cbcb130a7302fb8bafe2b9 -F tool/memleak.awk a0a11dd84bf4582acc81c3c61271021ae49b3f15 +F tool/memleak.awk 296dfbce7a9ca499b95ce04e30334e64a50052e0 F tool/opNames.awk 5ba1f48aa854ee3b7c3d2b54233665bc3e649ea2 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9 @@ -102,7 +102,7 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4 F www/arch.tcl 03b521d252575f93b9c52f7c8b0007011512fcfb F www/c_interface.tcl 6c5989670e014de44dce6580cbde0eea965dadbb -F www/changes.tcl 72923f6a051a2f6bdad639933e9e8e153b392123 +F www/changes.tcl fdd4f8b474bce2463b876c1bedb68c20bc3f5b34 F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e F www/download.tcl 3e51c9ff1326b0a182846134987301310dff7d60 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c @@ -114,7 +114,7 @@ F www/speed.tcl ab7d6d3bc898472bd94320a5d3c63de928d4804b F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44 -P c8535a0de90fb7a22df15018984db590a85decfb -R 04b0305eff69829eee3382ca64677b9c +P a835658e507fc7d0c684959c0f0afb9018b6a8d4 +R 123ebf892398ed7efe52cb42cd131987 U drh -Z 0c6d455d9482eaf63fb01fb72aa45066 +Z 5aa86d25974fbc02d84e2fe588bbca94 diff --git a/manifest.uuid b/manifest.uuid index 026af0b568..bdd5a0a5eb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a835658e507fc7d0c684959c0f0afb9018b6a8d4 \ No newline at end of file +f8328a5f11801c5124f9a8dace22df3c1cfb2191 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index c17ef14049..f505d033be 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.34 2001/10/15 00:44:35 drh Exp $ +** $Id: btree.c,v 1.35 2001/10/22 02:58:09 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -890,7 +890,7 @@ int sqliteBtreeCloseCursor(BtCursor *pCur){ } unlockBtreeIfUnused(pBt); nLock = (int)sqliteHashFind(&pBt->locks, 0, pCur->pgnoRoot); - assert( nLock!=0 ); + assert( nLock!=0 || sqlite_malloc_failed ); nLock = nLock<0 ? 0 : nLock-1; sqliteHashInsert(&pBt->locks, 0, pCur->pgnoRoot, (void*)nLock); sqliteFree(pCur); diff --git a/src/build.c b/src/build.c index a87a74b442..a0ef0ea14e 100644 --- a/src/build.c +++ b/src/build.c @@ -25,7 +25,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.51 2001/10/19 16:44:57 drh Exp $ +** $Id: build.c,v 1.52 2001/10/22 02:58:10 drh Exp $ */ #include "sqliteInt.h" #include @@ -72,7 +72,11 @@ void sqliteExec(Parse *pParse){ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){ Expr *pNew; pNew = sqliteMalloc( sizeof(Expr) ); - if( pNew==0 ) return 0; + if( pNew==0 ){ + sqliteExprDelete(pLeft); + sqliteExprDelete(pRight); + return 0; + } pNew->op = op; pNew->pLeft = pLeft; pNew->pRight = pRight; @@ -108,7 +112,10 @@ void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ Expr *sqliteExprFunction(ExprList *pList, Token *pToken){ Expr *pNew; pNew = sqliteMalloc( sizeof(Expr) ); - if( pNew==0 ) return 0; + if( pNew==0 ){ + sqliteExprListDelete(pList); + return 0; + } pNew->op = TK_FUNCTION; pNew->pList = pList; if( pToken ){ @@ -172,7 +179,7 @@ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){ ** the index from the index hash table and free its memory ** structures. */ -static void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){ +void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){ if( pIndex->pTable->pIndex==pIndex ){ pIndex->pTable->pIndex = pIndex->pNext; }else{ @@ -411,7 +418,10 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){ return; } pTable = sqliteMalloc( sizeof(Table) ); - if( pTable==0 ) return; + if( pTable==0 ){ + sqliteFree(zName); + return; + } pTable->zName = zName; pTable->nCol = 0; pTable->aCol = 0; @@ -445,11 +455,10 @@ void sqliteAddColumn(Parse *pParse, Token *pName){ char **pz; 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; - } + Column *aNew; + aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0])); + if( aNew==0 ) return; + p->aCol = aNew; } memset(&p->aCol[p->nCol], 0, sizeof(p->aCol[0])); pz = &p->aCol[p->nCol++].zName; @@ -576,7 +585,12 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){ */ assert( pParse->nameClash==0 || pParse->initFlag==1 ); if( pParse->explain==0 && pParse->nameClash==0 ){ - sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p); + Table *pOld; + pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p); + if( pOld ){ + assert( p==pOld ); /* Malloc must have failed */ + return; + } pParse->pNewTable = 0; db->nTable++; db->flags |= SQLITE_InternChanges; @@ -878,12 +892,18 @@ void sqliteCreateIndex( /* Link the new Index structure to its table and to the other ** in-memory database structures. */ - pIndex->pNext = pTab->pIndex; - pTab->pIndex = pIndex; if( !pParse->explain && !hideName ){ - sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex); + Index *p; + p = sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex); + if( p ){ + assert( p==pIndex ); /* Malloc must have failed */ + sqliteFree(pIndex); + goto exit_create_index; + } db->flags |= SQLITE_InternChanges; } + pIndex->pNext = pTab->pIndex; + pTab->pIndex = pIndex; /* If the initFlag is 1 it means we are reading the SQL off the ** "sqlite_master" table on the disk. So do not write to the disk @@ -1071,15 +1091,20 @@ ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){ int i; if( pList==0 ){ pList = sqliteMalloc( sizeof(ExprList) ); - if( pList==0 ) return 0; + if( pList==0 ){ + sqliteExprDelete(pExpr); + return 0; + } } if( (pList->nExpr & 7)==0 ){ int n = pList->nExpr + 8; - pList->a = sqliteRealloc(pList->a, n*sizeof(pList->a[0])); - if( pList->a==0 ){ - pList->nExpr = 0; + struct ExprList_item *a; + a = sqliteRealloc(pList->a, n*sizeof(pList->a[0])); + if( a==0 ){ + sqliteExprDelete(pExpr); return pList; } + pList->a = a; } if( pExpr ){ i = pList->nExpr++; @@ -1119,12 +1144,13 @@ IdList *sqliteIdListAppend(IdList *pList, Token *pToken){ if( pList==0 ) return 0; } if( (pList->nId & 7)==0 ){ - pList->a = sqliteRealloc(pList->a, (pList->nId+8)*sizeof(pList->a[0]) ); - if( pList->a==0 ){ - pList->nId = 0; + struct IdList_item *a; + a = sqliteRealloc(pList->a, (pList->nId+8)*sizeof(pList->a[0]) ); + if( a==0 ){ sqliteIdListDelete(pList); return 0; } + pList->a = a; } memset(&pList->a[pList->nId], 0, sizeof(pList->a[0])); if( pToken ){ diff --git a/src/expr.c b/src/expr.c index fdb45dc4f7..957f9e852d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.31 2001/10/13 02:59:09 drh Exp $ +** $Id: expr.c,v 1.32 2001/10/22 02:58:10 drh Exp $ */ #include "sqliteInt.h" @@ -935,11 +935,11 @@ int sqliteExprCompare(Expr *pA, Expr *pB){ static int appendAggInfo(Parse *pParse){ if( (pParse->nAgg & 0x7)==0 ){ int amt = pParse->nAgg + 8; - pParse->aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0])); - if( pParse->aAgg==0 ){ - pParse->nAgg = 0; + AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0])); + if( aAgg==0 ){ return -1; } + pParse->aAgg = aAgg; } memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0])); return pParse->nAgg++; diff --git a/src/hash.c b/src/hash.c index 945a919ed8..26d88e8f91 100644 --- a/src/hash.c +++ b/src/hash.c @@ -12,7 +12,7 @@ ** This is the implementation of generic hash-tables ** used in SQLite. ** -** $Id: hash.c,v 1.2 2001/10/12 17:30:05 drh Exp $ +** $Id: hash.c,v 1.3 2001/10/22 02:58:10 drh Exp $ */ #include "sqliteInt.h" #include @@ -254,7 +254,8 @@ void *sqliteHashFind(const Hash *pH, const void *pKey, int nKey){ ** ** If another element already exists with the same key, then the ** new data replaces the old data and the old data is returned. -** The key is not copied in this instance. +** The key is not copied in this instance. If a malloc fails, then +** new data is returned. ** ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the hash table. @@ -284,12 +285,12 @@ void *sqliteHashInsert(Hash *pH, void *pKey, int nKey, void *data){ } if( data==0 ) return 0; new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) ); - if( new_elem==0 ) return 0; + if( new_elem==0 ) return data; if( pH->copyKey && pKey!=0 ){ new_elem->pKey = sqliteMalloc( nKey ); if( new_elem->pKey==0 ){ sqliteFree(new_elem); - return 0; + return data; } memcpy((void*)new_elem->pKey, pKey, nKey); }else{ @@ -301,7 +302,7 @@ void *sqliteHashInsert(Hash *pH, void *pKey, int nKey, void *data){ if( pH->htsize==0 ){ pH->count = 0; sqliteFree(new_elem); - return 0; + return data; } if( pH->count > pH->htsize ){ rehash(pH,pH->htsize*2); diff --git a/src/main.c b/src/main.c index b9b44c1504..b4bf85592b 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.46 2001/10/12 17:30:05 drh Exp $ +** $Id: main.c,v 1.47 2001/10/22 02:58:10 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -204,7 +204,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){ */ vdbe = sqliteVdbeCreate(db); if( vdbe==0 ){ - sqliteSetString(pzErrMsg, "out of memory"); + sqliteSetString(pzErrMsg, "out of memory", 0); return SQLITE_NOMEM; } sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg); @@ -291,6 +291,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){ /* Attempt to read the schema */ rc = sqliteInit(db, pzErrMsg); if( sqlite_malloc_failed ){ + sqlite_close(db); goto no_mem_on_open; }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ sqlite_close(db); @@ -329,10 +330,21 @@ static void clearHashTable(sqlite *db, int preserveTemps){ Table *pTab = sqliteHashData(pElem); if( preserveTemps && pTab->isTemp ){ Index *pIdx; - sqliteHashInsert(&db->tblHash, pTab->zName, strlen(pTab->zName)+1, pTab); + int nName = strlen(pTab->zName); + Table *pOld = sqliteHashInsert(&db->tblHash, pTab->zName, nName+1, pTab); + if( pOld!=0 ){ + assert( pOld==pTab ); /* Malloc failed on the HashInsert */ + sqliteDeleteTable(db, pOld); + continue; + } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int n = strlen(pIdx->zName)+1; - sqliteHashInsert(&db->idxHash, pIdx->zName, n, pIdx); + Index *pOldIdx; + pOldIdx = sqliteHashInsert(&db->idxHash, pIdx->zName, n, pIdx); + if( pOld ){ + assert( pOldIdx==pIdx ); + sqliteUnlinkAndDeleteIndex(db, pOldIdx); + } } }else{ sqliteDeleteTable(db, pTab); @@ -440,6 +452,10 @@ int sqlite_exec( if( sqlite_malloc_failed ){ sqliteSetString(pzErrMsg, "out of memory", 0); sParse.rc = SQLITE_NOMEM; + sqliteBtreeRollback(db->pBe); + if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp); + db->flags &= ~SQLITE_InTrans; + clearHashTable(db, 0); } sqliteStrRealloc(pzErrMsg); if( sParse.rc==SQLITE_SCHEMA ){ diff --git a/src/os.c b/src/os.c index 07b2d1b661..68e66a4c7c 100644 --- a/src/os.c +++ b/src/os.c @@ -134,12 +134,18 @@ static struct lockInfo *findLockInfo(int fd){ key.ino = statbuf.st_ino; pInfo = (struct lockInfo*)sqliteHashFind(&lockHash, &key, sizeof(key)); if( pInfo==0 ){ + struct lockInfo *pOld; pInfo = sqliteMalloc( sizeof(*pInfo) ); if( pInfo==0 ) return 0; pInfo->key = key; pInfo->nRef = 1; pInfo->cnt = 0; - sqliteHashInsert(&lockHash, &pInfo->key, sizeof(key), pInfo); + pOld = sqliteHashInsert(&lockHash, &pInfo->key, sizeof(key), pInfo); + if( pOld!=0 ){ + assert( pOld==pInfo ); + sqliteFree(pInfo); + pInfo = 0; + } }else{ pInfo->nRef++; } @@ -315,6 +321,7 @@ int sqliteOsOpenExclusive(const char *zFilename, OsFile *pResult){ sqliteOsLeaveMutex(); if( s.pLock==0 ){ close(s.fd); + unlink(zFilename); return SQLITE_NOMEM; } *pResult = s; diff --git a/src/pager.c b/src/pager.c index 3beb7f4b65..f00ce88dd0 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.28 2001/10/18 12:34:47 drh Exp $ +** @(#) $Id: pager.c,v 1.29 2001/10/22 02:58:10 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -933,22 +933,28 @@ int sqlitepager_write(void *pData){ assert( pPager->aInJournal==0 ); pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInJournal==0 ){ + sqliteFree(pPager->aInJournal); return SQLITE_NOMEM; } rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd); if( rc!=SQLITE_OK ){ + sqliteFree(pPager->aInJournal); return SQLITE_CANTOPEN; } pPager->journalOpen = 1; pPager->needSync = 0; if( sqliteOsLock(pPager->jfd, 1)!=SQLITE_OK ){ + sqliteFree(pPager->aInJournal); sqliteOsClose(pPager->jfd); + sqliteOsDelete(pPager->zJournal); pPager->journalOpen = 0; return SQLITE_BUSY; } sqliteOsUnlock(pPager->fd); if( sqliteOsLock(pPager->fd, 1)!=SQLITE_OK ){ + sqliteFree(pPager->aInJournal); sqliteOsClose(pPager->jfd); + sqliteOsDelete(pPager->zJournal); pPager->journalOpen = 0; pPager->state = SQLITE_UNLOCK; pPager->errMask |= PAGER_ERR_LOCK; diff --git a/src/printf.c b/src/printf.c index bbde922343..7f687fa498 100644 --- a/src/printf.c +++ b/src/printf.c @@ -656,7 +656,13 @@ static void mout(void *arg, char *zNewText, int nNewChar){ pM->zText = sqliteMalloc(pM->nAlloc); if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar); }else{ - pM->zText = sqliteRealloc(pM->zText, pM->nAlloc); + char *z = sqliteRealloc(pM->zText, pM->nAlloc); + if( z==0 ){ + sqliteFree(pM->zText); + pM->nChar = 0; + pM->nAlloc = 0; + } + pM->zText = z; } } if( pM->zText ){ @@ -690,6 +696,9 @@ char *sqlite_mprintf(const char *zFormat, ...){ if( zNew ) strcpy(zNew,zBuf); }else{ zNew = sqliteRealloc(sMprintf.zText,sMprintf.nChar+1); + if( zNew==0 ){ + sqliteFree(sMprintf.zText); + } } return zNew; } @@ -709,7 +718,11 @@ char *sqlite_vmprintf(const char *zFormat, va_list ap){ sMprintf.zText = sqliteMalloc( strlen(zBuf)+1 ); if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf); }else{ - sMprintf.zText = sqliteRealloc(sMprintf.zText,sMprintf.nChar+1); + char *z = sqliteRealloc(sMprintf.zText,sMprintf.nChar+1); + if( z==0 ){ + sqliteFree(sMprintf.zText); + } + sMprintf.zText = z; } return sMprintf.zText; } diff --git a/src/select.c b/src/select.c index edb65d160e..5efd3054c7 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.43 2001/10/20 12:30:11 drh Exp $ +** $Id: select.c,v 1.44 2001/10/22 02:58:10 drh Exp $ */ #include "sqliteInt.h" @@ -359,11 +359,11 @@ static int fillInColumnList(Parse *pParse, Select *p){ 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; + if( pExpr->pLeft==0 ){ sqliteExprDelete(pExpr); 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; + if( pExpr->pRight==0 ){ sqliteExprDelete(pExpr); break; } pExpr->pRight->token.z = pTab->aCol[j].zName; pExpr->pRight->token.n = strlen(pTab->aCol[j].zName); pExpr->span.z = ""; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 4bf2fdd4de..e2df244611 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.21 2001/10/06 16:33:03 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.22 2001/10/22 02:58:10 drh Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -165,7 +165,8 @@ int sqlite_exec( ** defined above, then this routine returns a constant text string which ** descripts (in English) the meaning of the return value. */ -const char *sqliteErrStr(int); +const char *sqlite_error_string(int); +#define sqliteErrStr sqlite_error_string /* Legacy. Do not use in new code. */ /* This function causes any pending database operation to abort and ** return at its earliest opportunity. This routine is typically diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8054316ece..f54236401c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.64 2001/10/19 16:44:57 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.65 2001/10/22 02:58:10 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -269,7 +269,7 @@ struct Expr { */ struct ExprList { int nExpr; /* Number of expressions on the list */ - struct { + struct ExprList_item { Expr *pExpr; /* The list of expressions */ char *zName; /* Token associated with this expression */ char sortOrder; /* 1 for DESC or 0 for ASC */ @@ -283,7 +283,7 @@ struct ExprList { */ struct IdList { int nId; /* Number of identifiers on the list */ - struct { + struct IdList_item { char *zName; /* Text of the identifier. */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ int idx; /* Index in some Table.aCol[] of a column named zName */ @@ -454,6 +454,7 @@ void sqliteExprIfTrue(Parse*, Expr*, int); void sqliteExprIfFalse(Parse*, Expr*, int); Table *sqliteFindTable(sqlite*,char*); Index *sqliteFindIndex(sqlite*,char*); +void sqliteUnlinkAndDeleteIndex(sqlite*,Index*); void sqliteCopy(Parse*, Token*, Token*, Token*); void sqliteVacuum(Parse*, Token*); int sqliteGlobCompare(const unsigned char*,const unsigned char*); diff --git a/src/table.c b/src/table.c index b7a6fd9e50..1f2ae16f1d 100644 --- a/src/table.c +++ b/src/table.c @@ -53,12 +53,14 @@ static int sqlite_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ need = nCol; } if( p->nData + need >= p->nAlloc ){ + char **azNew; p->nAlloc = p->nAlloc*2 + need + 1; - p->azResult = realloc( p->azResult, sizeof(char*)*p->nAlloc ); - if( p->azResult==0 ){ + azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc ); + if( azNew==0 ){ p->rc = SQLITE_NOMEM; return 1; } + p->azResult = azNew; } /* If this is the first row, then generate an extra row containing @@ -150,8 +152,13 @@ int sqlite_get_table( return rc; } if( res.nAlloc>res.nData ){ - res.azResult = realloc( res.azResult, sizeof(char*)*(res.nData+1) ); - if( res.azResult==0 ) return SQLITE_NOMEM; + char **azNew; + azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) ); + if( res.azResult==0 ){ + sqlite_free_table(&res.azResult[1]); + return SQLITE_NOMEM; + } + res.azResult = azNew; } *pazResult = &res.azResult[1]; if( pnColumn ) *pnColumn = res.nColumn; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 19e7ddb279..4806a51d97 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.26 2001/10/19 16:44:57 drh Exp $ +** $Id: tclsqlite.c,v 1.27 2001/10/22 02:58:10 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -52,14 +52,17 @@ struct CallbackData { Tcl_Obj *pCode; /* The code to execute for each row */ int once; /* Set only for the first invocation of callback */ int tcl_rc; /* Return code from TCL script */ -#ifdef UTF_TRANSLATION_NEEDED int nColName; /* Number of entries in the azColName[] array */ char **azColName; /* Column names translated to UTF-8 */ -#endif }; +#ifdef UTF_TRANSLATION_NEEDED /* ** Called for each row of the result. +** +** This version is used when TCL expects UTF-8 data but the database +** uses the ISO8859 format. A translation must occur from ISO8859 into +** UTF-8. */ static int DbEvalCallback( void *clientData, /* An instance of CallbackData */ @@ -69,9 +72,79 @@ static int DbEvalCallback( ){ CallbackData *cbData = (CallbackData*)clientData; int i, rc; -#ifdef UTF_TRANSLATION_NEEDED Tcl_DString dCol; -#endif + Tcl_DStringInit(&dCol); + if( azCol==0 || (cbData->once && cbData->zArray[0]) ){ + Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0); + if( azCol ){ + cbData->azColName = malloc( nCol*sizeof(char*) ); + if( cbData->azColName==0 ){ return 1; } + } + cbData->nColName = nCol; + for(i=0; iazColName[i] = malloc( Tcl_DStringLength(&dCol) + 1); + if( cbData->azColName[i] ){ + strcpy(cbData->azColName[i], Tcl_DStringValue(&dCol)); + } + } + Tcl_SetVar2(cbData->interp, cbData->zArray, "*", Tcl_DStringValue(&dCol), + TCL_LIST_ELEMENT|TCL_APPEND_VALUE); + Tcl_DStringFree(&dCol); + } + cbData->once = 0; + } + if( azCol!=0 ){ + if( cbData->zArray[0] ){ + for(i=0; iinterp, cbData->zArray, cbData->azColName[i], + Tcl_DStringValue(&dCol), 0); + Tcl_DStringFree(&dCol); + } + }else{ + for(i=0; iinterp, cbData->azColName[i], + Tcl_DStringValue(&dCol), 0); + Tcl_DStringFree(&dCol); + } + } + } + rc = Tcl_EvalObj(cbData->interp, cbData->pCode); + if( rc==TCL_CONTINUE ) rc = TCL_OK; + cbData->tcl_rc = rc; + return rc!=TCL_OK; +} +#endif /* UTF_TRANSLATION_NEEDED */ + +#ifndef UTF_TRANSLATION_NEEDED +/* +** Called for each row of the result. +** +** This version is used when either of the following is true: +** +** (1) This version of TCL uses UTF-8 and the data in the +** SQLite database is already in the UTF-8 format. +** +** (2) This version of TCL uses ISO8859 and the data in the +** SQLite database is already in the ISO8859 format. +*/ +static int DbEvalCallback( + void *clientData, /* An instance of CallbackData */ + int nCol, /* Number of columns in the result */ + char ** azCol, /* Data for each column */ + char ** azN /* Name for each column */ +){ + CallbackData *cbData = (CallbackData*)clientData; + int i, rc; if( azCol==0 || (cbData->once && cbData->zArray[0]) ){ Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0); for(i=0; iinterp, cbData->zArray, azN[i], - Tcl_DStringValue(&dCol), 0); - Tcl_DStringFree(&dCol); -#else Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0); -#endif } }else{ for(i=0; iinterp, azN[i], Tcl_DStringValue(&dCol), 0); - Tcl_DStringFree(&dCol); -#else Tcl_SetVar(cbData->interp, azN[i], z, 0); -#endif } } } @@ -115,6 +173,7 @@ static int DbEvalCallback( cbData->tcl_rc = rc; return rc!=TCL_OK; } +#endif /* ** This is an alternative callback for database queries. Instead @@ -301,6 +360,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ int rc; #ifdef UTF_TRANSLATION_NEEDED Tcl_DString dSql; + int i; #endif if( objc!=5 && objc!=3 ){ @@ -321,6 +381,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ cbData.zArray = Tcl_GetStringFromObj(objv[3], 0); cbData.pCode = objv[4]; cbData.tcl_rc = TCL_OK; + cbData.nColName = 0; + cbData.azColName = 0; zErrMsg = 0; Tcl_IncrRefCount(objv[3]); Tcl_IncrRefCount(objv[4]); @@ -338,12 +400,21 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); free(zErrMsg); rc = TCL_ERROR; + }else if( rc!=SQLITE_OK && rc!=SQLITE_ABORT ){ + Tcl_AppendResult(interp, sqlite_error_string(rc), 0); + rc = TCL_ERROR; }else{ rc = cbData.tcl_rc; } Tcl_DecrRefCount(objv[2]); #ifdef UTF_TRANSLATION_NEEDED Tcl_DStringFree(&dSql); + if( objc==5 && cbData.azColName ){ + for(i=0; idb; extern void *sqliteParserAlloc(void*(*)(int)); extern void sqliteParserFree(void*, void(*)(void*)); extern int sqliteParser(void*, int, Token, Parse*); - pParse->db->flags &= ~SQLITE_Interrupt; + db->flags &= ~SQLITE_Interrupt; pParse->rc = SQLITE_OK; i = 0; sqliteParseInfoReset(pParse); @@ -367,7 +368,7 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){ while( sqlite_malloc_failed==0 && nErr==0 && i>=0 && zSql[i]!=0 ){ int tokenType; - if( (pParse->db->flags & SQLITE_Interrupt)!=0 ){ + if( (db->flags & SQLITE_Interrupt)!=0 ){ pParse->rc = SQLITE_INTERRUPT; sqliteSetString(pzErrMsg, "interrupt", 0); break; @@ -401,13 +402,13 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){ sqliteFree(pParse->zErrMsg); pParse->zErrMsg = 0; }else if( pParse->rc!=SQLITE_OK ){ - sqliteSetString(pzErrMsg, sqliteErrStr(pParse->rc), 0); + sqliteSetString(pzErrMsg, sqlite_error_string(pParse->rc), 0); nErr++; } break; } } - if( nErr==0 && (pParse->db->flags & SQLITE_Interrupt)==0 ){ + if( nErr==0 && (db->flags & SQLITE_Interrupt)==0 ){ sqliteParser(pEngine, 0, pParse->sLastToken, pParse); if( pParse->zErrMsg && pParse->sErrToken.z ){ sqliteSetNString(pzErrMsg, "near \"", -1, diff --git a/src/util.c b/src/util.c index 4d0205f63c..3d0fa4c9b7 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.29 2001/09/27 03:22:34 drh Exp $ +** $Id: util.c,v 1.30 2001/10/22 02:58:10 drh Exp $ */ #include "sqliteInt.h" #include @@ -49,11 +49,15 @@ void *sqliteMalloc_(int n, char *zFile, int line){ void *p; int *pi; int k; - sqlite_nMalloc++; if( sqlite_iMallocFail>=0 ){ sqlite_iMallocFail--; if( sqlite_iMallocFail==0 ){ sqlite_malloc_failed++; +#if MEMORY_DEBUG>1 + fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n", + n, zFile,line); +#endif + sqlite_iMallocFail--; return 0; } } @@ -64,6 +68,7 @@ void *sqliteMalloc_(int n, char *zFile, int line){ sqlite_malloc_failed++; return 0; } + sqlite_nMalloc++; pi[0] = 0xdead1122; pi[1] = n; pi[k+2] = 0xdead3344; @@ -227,6 +232,7 @@ void sqliteFree(void *p){ ** works just like sqliteFree(). */ void *sqliteRealloc(void *p, int n){ + void *p2; if( p==0 ){ return sqliteMalloc(n); } @@ -234,11 +240,11 @@ void *sqliteRealloc(void *p, int n){ sqliteFree(p); return 0; } - p = realloc(p, n); - if( p==0 ){ + p2 = realloc(p, n); + if( p2==0 ){ sqlite_malloc_failed++; } - return p; + return p2; } /* @@ -280,7 +286,9 @@ void sqliteSetString(char **pz, const char *zFirst, ...){ va_end(ap); sqliteFree(*pz); *pz = zResult = sqliteMalloc( nByte ); - if( zResult==0 ) return; + if( zResult==0 ){ + return; + } strcpy(zResult, zFirst); zResult += strlen(zResult); va_start(ap, zFirst); @@ -965,7 +973,7 @@ sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){ ** Return a static string that describes the kind of error specified in the ** argument. */ -const char *sqliteErrStr(int rc){ +const char *sqlite_error_string(int rc){ const char *z; switch( rc ){ case SQLITE_OK: z = "not an error"; break; diff --git a/src/vdbe.c b/src/vdbe.c index 2757ea59ec..10b6b3fa9c 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.88 2001/10/20 12:30:11 drh Exp $ +** $Id: vdbe.c,v 1.89 2001/10/22 02:58:10 drh Exp $ */ #include "sqliteInt.h" #include @@ -247,13 +247,14 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){ p->nOp++; if( i>=p->nOpAlloc ){ int oldSize = p->nOpAlloc; + Op *aNew; p->nOpAlloc = p->nOpAlloc*2 + 100; - p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); - if( p->aOp==0 ){ - p->nOp = 0; - p->nOpAlloc = 0; + aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); + if( aNew==0 ){ + p->nOpAlloc = oldSize; return 0; } + p->aOp = aNew; memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); } p->aOp[i].opcode = op; @@ -273,7 +274,7 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){ */ void sqliteVdbeResolveLabel(Vdbe *p, int x){ int j; - if( x<0 && (-x)<=p->nLabel ){ + if( x<0 && (-x)<=p->nLabel && p->aOp ){ p->aLabel[-1-x] = p->nOp; for(j=0; jnOp; j++){ if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp; @@ -296,13 +297,14 @@ int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){ int addr; if( p->nOp + nOp >= p->nOpAlloc ){ int oldSize = p->nOpAlloc; + Op *aNew; p->nOpAlloc = p->nOpAlloc*2 + nOp + 10; - p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); - if( p->aOp==0 ){ - p->nOp = 0; - p->nOpAlloc = 0; + aNew = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op)); + if( aNew==0 ){ + p->nOpAlloc = oldSize; return 0; } + p->aOp = aNew; memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op)); } addr = p->nOp; @@ -326,7 +328,7 @@ int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){ ** few minor changes to the program. */ void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){ - if( p && addr>=0 && p->nOp>addr ){ + if( p && addr>=0 && p->nOp>addr && p->aOp ){ p->aOp[addr].p1 = val; } } @@ -350,7 +352,7 @@ void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){ */ void sqliteVdbeChangeP3(Vdbe *p, int addr, char *zP3, int n){ Op *pOp; - if( p==0 ) return; + if( p==0 || p->aOp==0 ) return; if( addr<0 || addr>=p->nOp ){ addr = p->nOp - 1; if( addr<0 ) return; @@ -383,7 +385,7 @@ void sqliteVdbeChangeP3(Vdbe *p, int addr, char *zP3, int n){ */ void sqliteVdbeDequoteP3(Vdbe *p, int addr){ Op *pOp; - if( addr<0 || addr>=p->nOp ) return; + if( p->aOp==0 || addr<0 || addr>=p->nOp ) return; pOp = &p->aOp[addr]; if( pOp->p3==0 || pOp->p3[0]==0 ) return; if( pOp->p3type==P3_POINTER ) return; @@ -403,7 +405,7 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){ char *z; int i, j; Op *pOp; - if( addr<0 || addr>=p->nOp ) return; + if( p->aOp==0 || addr<0 || addr>=p->nOp ) return; pOp = &p->aOp[addr]; if( pOp->p3type!=P3_DYNAMIC ){ pOp->p3 = sqliteStrDup(pOp->p3); @@ -445,8 +447,13 @@ int sqliteVdbeMakeLabel(Vdbe *p){ int i; i = p->nLabel++; if( i>=p->nLabelAlloc ){ + int *aNew; p->nLabelAlloc = p->nLabelAlloc*2 + 10; - p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); + aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0])); + if( aNew==0 ){ + sqliteFree(p->aLabel); + } + p->aLabel = aNew; } if( p->aLabel==0 ){ p->nLabel = 0; @@ -484,7 +491,7 @@ static void AggReset(Agg *pAgg){ ** Return 0 on success and 1 if memory is exhausted. */ static int AggInsert(Agg *p, char *zKey, int nKey){ - AggElem *pElem; + AggElem *pElem, *pOld; int i; pElem = sqliteMalloc( sizeof(AggElem) + nKey + (p->nMem-1)*sizeof(pElem->aMem[0]) ); @@ -492,7 +499,12 @@ static int AggInsert(Agg *p, char *zKey, int nKey){ pElem->zKey = (char*)&pElem->aMem[p->nMem]; memcpy(pElem->zKey, zKey, nKey); pElem->nKey = nKey; - sqliteHashInsert(&p->hash, pElem->zKey, pElem->nKey, pElem); + pOld = sqliteHashInsert(&p->hash, pElem->zKey, pElem->nKey, pElem); + if( pOld!=0 ){ + assert( pOld==pElem ); /* Malloc failed on insert */ + sqliteFree(pOld); + return 0; + } for(i=0; inMem; i++){ pElem->aMem[i].s.flags = STK_Null; } @@ -638,18 +650,25 @@ static int hardNeedStack(Vdbe *p, int N){ int oldAlloc; int i; if( N>=p->nStackAlloc ){ + Stack *aNew; + char **zNew; oldAlloc = p->nStackAlloc; p->nStackAlloc = N + 20; - p->aStack = sqliteRealloc(p->aStack, p->nStackAlloc*sizeof(p->aStack[0])); - p->zStack = sqliteRealloc(p->zStack, p->nStackAlloc*sizeof(char*)); - if( p->aStack==0 || p->zStack==0 ){ + aNew = sqliteRealloc(p->aStack, p->nStackAlloc*sizeof(p->aStack[0])); + zNew = aNew ? sqliteRealloc(p->zStack, p->nStackAlloc*sizeof(char*)) : 0; + if( zNew==0 ){ + sqliteFree(aNew); sqliteFree(p->aStack); sqliteFree(p->zStack); p->aStack = 0; p->zStack = 0; p->nStackAlloc = 0; + p->aStack = 0; + p->zStack = 0; return 1; } + p->aStack = aNew; + p->zStack = zNew; for(i=oldAlloc; inStackAlloc; i++){ p->zStack[i] = 0; p->aStack[i].flags = 0; @@ -1013,8 +1032,9 @@ int sqliteVdbeExec( } #endif /* if( pzErrMsg ){ *pzErrMsg = 0; } */ - if( sqlite_malloc_failed ) rc = SQLITE_NOMEM; - for(pc=0; rc==SQLITE_OK && pcnOp VERIFY(&& pc>=0); pc++){ + if( sqlite_malloc_failed ) goto no_mem; + for(pc=0; !sqlite_malloc_failed && rc==SQLITE_OK && pcnOp + VERIFY(&& pc>=0); pc++){ pOp = &p->aOp[pc]; /* Interrupt processing if requested. @@ -1192,8 +1212,9 @@ case OP_Pull: { ** is done. If this value is wrong, a coredump can result. */ case OP_ColumnCount: { - p->azColName = sqliteRealloc(p->azColName, (pOp->p1+1)*sizeof(char*)); - if( p->azColName==0 ) goto no_mem; + char **az = sqliteRealloc(p->azColName, (pOp->p1+1)*sizeof(char*)); + if( az==0 ){ goto no_mem; } + p->azColName = az; p->azColName[pOp->p1] = 0; p->nCallback = 0; break; @@ -1237,6 +1258,7 @@ case OP_Callback: { p->nCallback++; } PopStack(p, pOp->p1); + if( sqlite_malloc_failed ) goto no_mem; break; } @@ -1263,6 +1285,7 @@ case OP_NullCallback: { } p->nCallback++; } + if( sqlite_malloc_failed ) goto no_mem; break; } @@ -2098,7 +2121,7 @@ case OP_Transaction: { switch( rc ){ case SQLITE_BUSY: { if( xBusy==0 || (*xBusy)(pBusyArg, "", ++busy)==0 ){ - sqliteSetString(pzErrMsg, sqliteErrStr(rc), 0); + sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); busy = 0; } break; @@ -2303,8 +2326,9 @@ case OP_Open: { VERIFY( if( i<0 ) goto bad_instruction; ) if( i>=p->nCursor ){ int j; - p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) ); - if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; } + Cursor *aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) ); + if( aCsr==0 ) goto no_mem; + p->aCsr = aCsr; for(j=p->nCursor; j<=i; j++){ memset(&p->aCsr[j], 0, sizeof(Cursor)); } @@ -2317,7 +2341,7 @@ case OP_Open: { switch( rc ){ case SQLITE_BUSY: { if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){ - sqliteSetString(pzErrMsg, sqliteErrStr(rc), 0); + sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); busy = 0; } break; @@ -2354,8 +2378,9 @@ case OP_OpenTemp: { VERIFY( if( i<0 ) goto bad_instruction; ) if( i>=p->nCursor ){ int j; - p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) ); - if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; } + Cursor *aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) ); + if( aCsr==0 ){ goto no_mem; } + p->aCsr = aCsr; for(j=p->nCursor; j<=i; j++){ memset(&p->aCsr[j], 0, sizeof(Cursor)); } @@ -2670,8 +2695,6 @@ case OP_Column: { (*xSize)(pCrsr, &payloadSize); if( payloadSize < sizeof(aHdr[0])*(p2+1) ){ rc = SQLITE_CORRUPT; -printf("keyasdata=%d ", p->aCsr[i].keyAsData); -printf("payloadSize=%d aHdr[0]=%d p2=%d\n", payloadSize, aHdr[0], p2); goto abort_due_to_error; } if( p2+1=p->nList ){ int j; - p->apList = sqliteRealloc( p->apList, (i+1)*sizeof(Keylist*) ); - if( p->apList==0 ){ p->nList = 0; goto no_mem; } + Keylist **apList = sqliteRealloc( p->apList, (i+1)*sizeof(Keylist*) ); + if( apList==0 ){ goto no_mem; } + p->apList = apList; for(j=p->nList; j<=i; j++) p->apList[j] = 0; p->nList = i+1; }else if( p->apList[i] ){ @@ -3177,8 +3201,9 @@ case OP_SortOpen: { VERIFY( if( i<0 ) goto bad_instruction; ) if( i>=p->nSort ){ int j; - p->apSort = sqliteRealloc( p->apSort, (i+1)*sizeof(Sorter*) ); - if( p->apSort==0 ){ p->nSort = 0; goto no_mem; } + Sorter **apSort = sqliteRealloc( p->apSort, (i+1)*sizeof(Sorter*) ); + if( apSort==0 ){ goto no_mem; } + p->apSort = apSort; for(j=p->nSort; j<=i; j++) p->apSort[j] = 0; p->nSort = i+1; } @@ -3295,7 +3320,7 @@ case OP_SortMakeKey: { zNewKey[j++] = 0; } zNewKey[j] = 0; - VERIFY( jtos+1); ) p->tos++; @@ -3409,6 +3434,7 @@ case OP_SortCallback: { p->nCallback++; } POPSTACK; + if( sqlite_malloc_failed ) goto no_mem; break; } @@ -3497,23 +3523,25 @@ case OP_FileRead: { nField = pOp->p1; if( nField<=0 ) goto fileread_jump; if( nField!=p->nField || p->azField==0 ){ - p->azField = sqliteRealloc(p->azField, sizeof(char*)*nField+1); - if( p->azField==0 ){ - p->nField = 0; - goto fileread_jump; - } + char **azField = sqliteRealloc(p->azField, sizeof(char*)*nField+1); + if( azField==0 ){ goto no_mem; } + p->azField = azField; p->nField = nField; } n = 0; eol = 0; while( eol==0 ){ if( p->zLine==0 || n+200>p->nLineAlloc ){ + char *zLine; p->nLineAlloc = p->nLineAlloc*2 + 300; - p->zLine = sqliteRealloc(p->zLine, p->nLineAlloc); - if( p->zLine==0 ){ + zLine = sqliteRealloc(p->zLine, p->nLineAlloc); + if( zLine==0 ){ p->nLineAlloc = 0; - goto fileread_jump; + sqliteFree(p->zLine); + p->zLine = 0; + goto no_mem; } + p->zLine = zLine; } if( fgets(&p->zLine[n], p->nLineAlloc-n, p->pFile)==0 ){ eol = 1; @@ -3606,9 +3634,11 @@ case OP_MemStore: { VERIFY( if( tos<0 ) goto not_enough_stack; ) if( i>=p->nMem ){ int nOld = p->nMem; + Mem *aMem; p->nMem = i + 5; - p->aMem = sqliteRealloc(p->aMem, p->nMem*sizeof(p->aMem[0])); - if( p->aMem==0 ) goto no_mem; + aMem = sqliteRealloc(p->aMem, p->nMem*sizeof(p->aMem[0])); + if( aMem==0 ) goto no_mem; + p->aMem = aMem; if( nOldnMem ){ memset(&p->aMem[nOld], 0, sizeof(p->aMem[0])*(p->nMem-nOld)); } @@ -3752,8 +3782,9 @@ case OP_AggSet: { pMem->s = aStack[tos]; if( pMem->s.flags & STK_Str ){ pMem->z = sqliteMalloc( aStack[tos].n ); - if( pMem->z==0 ) goto no_mem; - memcpy(pMem->z, zStack[tos], pMem->s.n); + if( pMem->z ){ + memcpy(pMem->z, zStack[tos], pMem->s.n); + } pMem->s.flags |= STK_Str|STK_Dyn; } if( zOld ) sqliteFree(zOld); @@ -3833,8 +3864,9 @@ case OP_SetInsert: { int i = pOp->p1; if( p->nSet<=i ){ int k; - p->aSet = sqliteRealloc(p->aSet, (i+1)*sizeof(p->aSet[0]) ); - if( p->aSet==0 ) goto no_mem; + Set *aSet = sqliteRealloc(p->aSet, (i+1)*sizeof(p->aSet[0]) ); + if( aSet==0 ) goto no_mem; + p->aSet = aSet; for(k=p->nSet; k<=i; k++){ sqliteHashInit(&p->aSet[k].hash, SQLITE_HASH_BINARY, 1); } @@ -4098,7 +4130,7 @@ cleanup: ** to fail on a modern VM computer, so this code is untested. */ no_mem: - sqliteSetString(pzErrMsg, "out or memory", 0); + sqliteSetString(pzErrMsg, "out of memory", 0); rc = SQLITE_NOMEM; goto cleanup; @@ -4106,7 +4138,7 @@ no_mem: ** should hold the error number. */ abort_due_to_error: - sqliteSetString(pzErrMsg, sqliteErrStr(rc), 0); + sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); goto cleanup; /* Jump to here if a operator is encountered that requires more stack diff --git a/test/all.test b/test/all.test index 3de46fba29..3f05ebc234 100644 --- a/test/all.test +++ b/test/all.test @@ -10,7 +10,7 @@ #*********************************************************************** # This file runs all tests. # -# $Id: all.test,v 1.10 2001/09/16 00:13:28 drh Exp $ +# $Id: all.test,v 1.11 2001/10/22 02:58:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -65,8 +65,9 @@ if {$LeakList!=""} { puts " Ok" } -if {[file readable $testdir/malloc.test]} { - source $testdir/malloc.test -} +# Run the malloc tests after memory leak detection. We do leak +# some if malloc fails. +# +catch {source $testdir/malloc.test} really_finish_test diff --git a/test/btree2.test b/test/btree2.test index 865d6b8bc6..2165b3d399 100644 --- a/test/btree2.test +++ b/test/btree2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # -# $Id: btree2.test,v 1.8 2001/09/23 02:35:53 drh Exp $ +# $Id: btree2.test,v 1.9 2001/10/22 02:58:11 drh Exp $ set testdir [file dirname $argv0] @@ -326,15 +326,8 @@ foreach {N L} { } {0} do_test btree2-$testno.7 { btree_close $::b - set ::b [btree_open test2.bt] - set ::c2 [btree_cursor $::b 2 1] - set ::c3 [btree_cursor $::b 3 1] - set ::c4 [btree_cursor $::b 4 1] - set ::c5 [btree_cursor $::b 5 1] - set ::c6 [btree_cursor $::b 6 1] - check_invariants } {} - +after 100 # For each database size, run various changes tests. # set num2 1 @@ -348,6 +341,16 @@ foreach {N L} { 2.0 1.0 0.0 0.0 } { set testid btree2-$testno.8.$num2 + set hash [md5file test2.bt] + do_test $testid.0 { + set ::b [btree_open test2.bt] + set ::c2 [btree_cursor $::b 2 1] + set ::c3 [btree_cursor $::b 3 1] + set ::c4 [btree_cursor $::b 4 1] + set ::c5 [btree_cursor $::b 5 1] + set ::c6 [btree_cursor $::b 6 1] + check_invariants + } {} set cnt 6 for {set i 2} {$i<=6} {incr i} { if {[lindex [btree_cursor_dump [set ::c$i]] 0]!=$i} {incr cnt} @@ -356,7 +359,6 @@ foreach {N L} { btree_begin_transaction $::b lindex [btree_pager_stats $::b] 1 } $cnt - set hash [md5file test2.bt] # exec cp test2.bt test2.bt.bu1 do_test $testid.2 [subst { random_changes $n $I $K $D @@ -409,14 +411,21 @@ foreach {N L} { set ::c6 [btree_cursor $::b 6 1] check_invariants } {} + do_test $testid.10 { + btree_close_cursor $::c2 + btree_close_cursor $::c3 + btree_close_cursor $::c4 + btree_close_cursor $::c5 + btree_close_cursor $::c6 + lindex [btree_pager_stats $::b] 1 + } {0} + do_test $testid.11 { + btree_close $::b + } {} incr num2 } - btree_close_cursor $::c2 - btree_close_cursor $::c3 - btree_close_cursor $::c4 - btree_close_cursor $::c5 - btree_close_cursor $::c6 incr testno + set ::b [btree_open test2.bt] } # Testing is complete. Shut everything down. diff --git a/test/malloc.test b/test/malloc.test index bc008e0b7e..9a02b742e8 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -10,11 +10,11 @@ #*********************************************************************** # This file attempts to check the library in an out-of-memory situation. # When compiled with -DMEMORY_DEBUG=1, the SQLite library accepts a special -# command (--malloc-fail=N) which causes the N-th malloc to fail. This +# command (sqlite_malloc_fail N) which causes the N-th malloc to fail. This # special feature is used to see what happens in the library if a malloc # were to really fail due to an out-of-memory situation. # -# $Id: malloc.test,v 1.3 2001/09/16 00:13:28 drh Exp $ +# $Id: malloc.test,v 1.4 2001/10/22 02:58:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -30,55 +30,164 @@ if {[info command sqlite_malloc_fail]==""} { for {set go 1; set i 1} {$go} {incr i} { do_test malloc-1.$i { sqlite_malloc_fail 0 - catch {execsql {DROP TABLE t1}} + catch {db close} + catch {file delete -force test.db} + catch {file delete -force test.db-journal} sqlite_malloc_fail $i - set v [catch {execsql { - CREATE TABLE t1( - a int, b float, c double, d text, e varchar(20), - primary key(a,b,c) - ); - CREATE INDEX i1 ON t1(a,b); - INSERT INTO t1 VALUES(1,2.3,4.5,'hi','there'); - INSERT INTO t1 VALUES(6,7.0,0.8,'hello','out yonder'); - SELECT * FROM t1; - SELECT avg(b) FROM t1 GROUP BY a HAVING b>20.0; - DELETE FROM t1 WHERE a==6; - SELECT count(*) FROM t1; - }} msg] - if {[lindex [sqlite_malloc_stat] 2]>0} { + set v [catch {sqlite db test.db} msg] + if {$v} { + set msg "" + } else { + set v [catch {execsql { + CREATE TABLE t1( + a int, b float, c double, d text, e varchar(20), + primary key(a,b,c) + ); + CREATE INDEX i1 ON t1(a,b); + INSERT INTO t1 VALUES(1,2.3,4.5,'hi','there'); + INSERT INTO t1 VALUES(6,7.0,0.8,'hello','out yonder'); + SELECT * FROM t1; + SELECT avg(b) FROM t1 GROUP BY a HAVING b>20.0; + DELETE FROM t1 WHERE a IN (SELECT min(a) FROM t1); + SELECT count(*) FROM t1; + }} msg] + } + set leftover [lindex [sqlite_malloc_stat] 2] + if {$leftover>0} { + if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} set ::go 0 set v {1 1} } else { - lappend v [expr {$msg=="" || $msg=="out of memory"}] + set v2 [expr {$msg=="" || $msg=="out of memory"}] + if {!$v2} {puts "\nError message returned: $msg"} + lappend v $v2 } } {1 1} } +finish_test +return + + set fd [open ./data.tmp w] -for {set i 1} {$i<=40} {incr i} { - puts $fd "$i\t[expr {$i*$i}]\t[expr {100-$i}]" +for {set i 1} {$i<=20} {incr i} { + puts $fd "$i\t[expr {$i*$i}]\t[expr {100-$i}] abcdefghijklmnopqrstuvwxyz" } close $fd for {set go 1; set i 1} {$go} {incr i} { do_test malloc-2.$i { sqlite_malloc_fail 0 - catch {execsql {DROP TABLE t1}} + catch {db close} + catch {file delete -force test.db} + catch {file delete -force test.db-journal} sqlite_malloc_fail $i - set v [catch {execsql { - CREATE TABLE t1(a int, b int, c int); - CREATE INDEX i1 ON t1(a,b); - COPY t1 FROM 'data.tmp'; - SELECT 'stuff', count(*) as 'other stuff' FROM t1; - UPDATE t1 SET b=a WHERE a in (10,12,22); - DROP INDEX i1; - VACUUM t1; - }} msg] - if {[lindex [sqlite_malloc_stat] 2]>0} { + set v [catch {sqlite db test.db} msg] + if {$v} { + set msg "" + } else { + set v [catch {execsql { + CREATE TABLE t1(a int, b int, c int); + CREATE INDEX i1 ON t1(a,b); + COPY t1 FROM 'data.tmp'; + SELECT 'stuff', count(*) as 'other stuff', max(a+10) FROM t1; + UPDATE t1 SET b=b||b||b||b; + UPDATE t1 SET b=a WHERE a in (10,12,22); + INSERT INTO t1(c,b,a) VALUES(20,10,5); + INSERT INTO t1 SELECT * FROM t1 + WHERE a IN (SELECT a FROM t1 WHERE a<10); + DELETE FROM t1 WHERE a>=10; + DROP INDEX i1; + DELETE FROM t1; + }} msg] + } + set leftover [lindex [sqlite_malloc_stat] 2] + if {$leftover>0} { + if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} set ::go 0 set v {1 1} } else { - lappend v [expr {$msg=="" || $msg=="out of memory"}] + set v2 [expr {$msg=="" || $msg=="out of memory"}] + if {!$v2} {puts "\nError message returned: $msg"} + lappend v $v2 + } + } {1 1} +} + +set fd [open ./data.tmp w] +for {set i 1} {$i<=10} {incr i} { + puts $fd "$i\t[expr {$i*$i}]\t[expr {100-$i}]" +} +close $fd + +for {set go 1; set i 1} {$go} {incr i} { + do_test malloc-3.$i { + sqlite_malloc_fail 0 + catch {db close} + catch {file delete -force test.db} + catch {file delete -force test.db-journal} + sqlite_malloc_fail $i + set v [catch {sqlite db test.db} msg] + if {$v} { + set msg "" + } else { + set v [catch {execsql { + BEGIN TRANSACTION; + CREATE TABLE t1(a int, b int, c int); + CREATE INDEX i1 ON t1(a,b); + COPY t1 FROM 'data.tmp'; + INSERT INTO t1(c,b,a) VALUES(20,10,5); + DELETE FROM t1 WHERE a>=10; + DROP INDEX i1; + DELETE FROM t1; + ROLLBACK; + }} msg] + } + set leftover [lindex [sqlite_malloc_stat] 2] + if {$leftover>0} { + if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} + set ::go 0 + set v {1 1} + } else { + set v2 [expr {$msg=="" || $msg=="out of memory"}] + if {!$v2} {puts "\nError message returned: $msg"} + lappend v $v2 + } + } {1 1} +} +for {set go 1; set i 1} {$go} {incr i} { + do_test malloc-4.$i { + sqlite_malloc_fail 0 + catch {db close} + catch {file delete -force test.db} + catch {file delete -force test.db-journal} + sqlite_malloc_fail $i + set v [catch {sqlite db test.db} msg] + if {$v} { + set msg "" + } else { + set v [catch {execsql { + BEGIN TRANSACTION; + CREATE TABLE t1(a int, b int, c int); + CREATE INDEX i1 ON t1(a,b); + COPY t1 FROM 'data.tmp'; + UPDATE t1 SET b=a WHERE a in (10,12,22); + INSERT INTO t1 SELECT * FROM t1 + WHERE a IN (SELECT a FROM t1 WHERE a<10); + DROP INDEX i1; + DELETE FROM t1; + COMMIT; + }} msg] + } + set leftover [lindex [sqlite_malloc_stat] 2] + if {$leftover>0} { + if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} + set ::go 0 + set v {1 1} + } else { + set v2 [expr {$msg=="" || $msg=="out of memory"}] + if {!$v2} {puts "\nError message returned: $msg"} + lappend v $v2 } } {1 1} } diff --git a/test/quick.test b/test/quick.test index 904b5ede51..feb8df13e4 100644 --- a/test/quick.test +++ b/test/quick.test @@ -10,7 +10,7 @@ #*********************************************************************** # This file runs all tests. # -# $Id: quick.test,v 1.1 2001/09/16 00:13:28 drh Exp $ +# $Id: quick.test,v 1.2 2001/10/22 02:58:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -21,6 +21,7 @@ set EXCLUDE { all.test quick.test btree2.test + malloc.test } foreach testfile [lsort -dictionary [glob $testdir/*.test]] { diff --git a/test/tclsqlite.test b/test/tclsqlite.test index ea79886b8c..35a66179df 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -15,7 +15,7 @@ # interface is pretty well tested. This file contains some addition # tests for fringe issues that the main test suite does not cover. # -# $Id: tclsqlite.test,v 1.2 2001/09/16 00:13:28 drh Exp $ +# $Id: tclsqlite.test,v 1.3 2001/10/22 02:58:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -65,4 +65,29 @@ do_test tcl-1.6 { lappend v $msg } {1 {syntax error in expression "x*"}} +if {[sqlite -encoding]=="UTF-8" && [sqlite -tcl-uses-utf]} { + do_test tcl-2.1 { + execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)" + execsql "PRAGMA table_info(t\u0123x)" + } "0 a int 0 {} 1 b\u1235 float 0 {}" + do_test tcl-2.2 { + execsql "INSERT INTO t\u0123x VALUES(1,2.3)" + db eval "SELECT * FROM t\u0123x" result break + set result(*) + } "a b\u1235" +} + +if {[sqlite -encoding]=="iso8859" && [sqlite -tcl-uses-utf]} { + do_test tcl-2.1 { + execsql "CREATE TABLE t\251x(a int, b\306 float)" + execsql "PRAGMA table_info(t\251x)" + } "0 a int 0 {} 1 b\306 float 0 {}" + do_test tcl-2.2 { + execsql "INSERT INTO t\251x VALUES(1,2.3)" + db eval "SELECT * FROM t\251x" result break + set result(*) + } "a b\306" +} + + finish_test diff --git a/tool/memleak.awk b/tool/memleak.awk index ca3366cf0d..b19787e834 100644 --- a/tool/memleak.awk +++ b/tool/memleak.awk @@ -11,6 +11,7 @@ } /^free / { mem[$5] = ""; + str[$5] = "" } /^string at / { addr = $3 diff --git a/www/changes.tcl b/www/changes.tcl index 9f73d4beba..0281d834b7 100644 --- a/www/changes.tcl +++ b/www/changes.tcl @@ -17,8 +17,16 @@ proc chng {date desc} { puts "

    $desc

" } -chng {2001 Oct 20 (2.0.7)} { -
  • Patches from Christian Werner
  • +chng {2001 Oct 21 (2.0.7)} { +
  • Any UTF-8 character or ISO8859 character can be used as part of + an identifier.
  • +
  • Patches from Christian Werner to improve ODBC compatibility and to + fix a bug in the round() function.
  • +
  • Plug some memory leaks that use to occur if malloc() failed. + We have been and continue to be memory leak free as long as + malloc() works.
  • +
  • Changes to some test scripts so that they work on Windows in + addition to Unix.
  • } chng {2001 Oct 19 (2.0.6)} {