diff options
-rw-r--r-- | manifest | 19 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/analyze.c | 27 | ||||
-rw-r--r-- | src/sqliteInt.h | 4 | ||||
-rw-r--r-- | src/vdbe.c | 4 | ||||
-rw-r--r-- | test/mallocA.test | 146 |
6 files changed, 178 insertions, 24 deletions
@@ -1,5 +1,5 @@ -C Fix\sanother\svariant\sof\sthe\s"IN\s(...)"\sb-tree\sproblem.\s(CVS\s3988) -D 2007-05-12T10:41:48 +C Make\sthe\sANALYZE\scommand\srobust\sin\sthe\sface\sof\smalloc()\sfailures.\s(CVS\s3989) +D 2007-05-12T12:08:51 F Makefile.in 87b200ad9970907f76df734d29dff3d294c10935 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -58,7 +58,7 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/alter.c ca8fc4a3c7359379598dc12589b65c32eb88defd -F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 +F src/analyze.c e8fcb1c35ace8418615eb18d9601f321ac86b2ec F src/attach.c ba628db0c2b6a362f036d017bf1196cdfe4ebb37 F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f F src/btree.c 0c2f9b06c90d7c59925c03153c9d47fd739c8ca5 @@ -104,7 +104,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c d07ae326b3815d80f71c69b3c7584382e47f6447 F src/sqlite.h.in 664b8702c27dc742584788823c548491ac8935d6 F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890 -F src/sqliteInt.h 10becea12cf7771a05d67eda7df8ece362da8e29 +F src/sqliteInt.h c31c9526bc602c3c71ddc45c548e987530826f11 F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d F src/tclsqlite.c f425c7583665ef78dd8397b2de0b8e0028e80ce2 F src/test1.c 16938b7e76469abf957745743dd0287d5dee476d @@ -132,7 +132,7 @@ F src/update.c 3359041db390a8f856d67272f299600e2104f350 F src/utf.c be7c64eed83fa3c01e0c42905e1c311dcd1be704 F src/util.c 4f6bbcec2b2b1884d652b82c9f8949ede4618d68 F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef -F src/vdbe.c 8dcd02c2ee383db5bd09488436322e0fee1b78dd +F src/vdbe.c 5deb4cdccd57065ccf8a2e5c704e8473c90d204b F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3 F src/vdbeInt.h bddb7931fc1216fda6f6720e18d2a9b1e0f8fc96 F src/vdbeapi.c 3ca7808c67a10b5c20150108b431d520d141e93e @@ -296,6 +296,7 @@ F test/malloc6.test 025ae0b78542e0ddd000d23f79d93e9be9ba0f15 F test/malloc7.test 1cf52834509eac7ebeb92105dacd4669f9ca9869 F test/malloc8.test e4054ca2a87ab1d42255bec009b177ba20b5a487 F test/malloc9.test 8381041fd89c31fba60c8a1a1c776bb022108572 +F test/mallocA.test d8b8de87bf2e605e6d4507f96b87fa1d891693e2 F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8 F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217 @@ -489,7 +490,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 96c7232f8b208cd1c50063f7946bb6dbc386abd6 -R e2d831528bd9b1aa18f85c2d481b3b12 -U danielk1977 -Z 0924774789a8e6d243ad58907ec918b8 +P 260338c4b2b18c9f4da8bc7fe3eda306dcaa4e38 +R f6d6bb84867a23616a67a2ab24e70c0a +U drh +Z 29e801396d63998d48f02963b7838607 diff --git a/manifest.uuid b/manifest.uuid index e5a06b082..abd9bcc1e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -260338c4b2b18c9f4da8bc7fe3eda306dcaa4e38
\ No newline at end of file +c08658e1f8598941ebddddb98942b98cfcb86e7a
\ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index abbbf0fd5..3501fddc3 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.17 2007/03/29 05:51:49 drh Exp $ +** @(#) $Id: analyze.c,v 1.18 2007/05/12 12:08:51 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -36,6 +36,7 @@ static void openStatTable( Table *pStat; Vdbe *v = sqlite3GetVdbe(pParse); + if( v==0 ) return; pDb = &db->aDb[iDb]; if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){ /* The sqlite_stat1 tables does not exist. Create it. @@ -95,7 +96,7 @@ static void analyzeOneTable( int iDb; /* Index of database containing pTab */ v = sqlite3GetVdbe(pParse); - if( pTab==0 || pTab->pIndex==0 ){ + if( v==0 || pTab==0 || pTab->pIndex==0 ){ /* Do no analysis for tables that have no indices */ return; } @@ -222,7 +223,9 @@ static void analyzeOneTable( */ static void loadAnalysis(Parse *pParse, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); - sqlite3VdbeAddOp(v, OP_LoadAnalysis, iDb, 0); + if( v ){ + sqlite3VdbeAddOp(v, OP_LoadAnalysis, iDb, 0); + } } /* @@ -314,10 +317,12 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ if( iDb>=0 ){ zDb = db->aDb[iDb].zName; z = sqlite3NameFromToken(pTableName); - pTab = sqlite3LocateTable(pParse, z, zDb); - sqliteFree(z); - if( pTab ){ - analyzeTable(pParse, pTab); + if( z ){ + pTab = sqlite3LocateTable(pParse, z, zDb); + sqliteFree(z); + if( pTab ){ + analyzeTable(pParse, pTab); + } } } } @@ -371,10 +376,11 @@ static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){ /* ** Load the content of the sqlite_stat1 table into the index hash tables. */ -void sqlite3AnalysisLoad(sqlite3 *db, int iDb){ +int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ analysisInfo sInfo; HashElem *i; char *zSql; + int rc; /* Clear any prior statistics */ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ @@ -386,7 +392,7 @@ void sqlite3AnalysisLoad(sqlite3 *db, int iDb){ sInfo.db = db; sInfo.zDatabase = db->aDb[iDb].zName; if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){ - return; + return SQLITE_ERROR; } @@ -394,9 +400,10 @@ void sqlite3AnalysisLoad(sqlite3 *db, int iDb){ zSql = sqlite3MPrintf("SELECT idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase); sqlite3SafetyOff(db); - sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); + rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); sqlite3SafetyOn(db); sqliteFree(zSql); + return rc; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b227f6a75..a550ca8ab 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.565 2007/05/11 12:30:04 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.566 2007/05/12 12:08:51 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1804,7 +1804,7 @@ char sqlite3AffinityType(const Token*); void sqlite3Analyze(Parse*, Token*, Token*); int sqlite3InvokeBusyHandler(BusyHandler*); int sqlite3FindDb(sqlite3*, Token*); -void sqlite3AnalysisLoad(sqlite3*,int iDB); +int sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); diff --git a/src/vdbe.c b/src/vdbe.c index 3171a10f1..68279dbba 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.617 2007/05/11 10:10:33 danielk1977 Exp $ +** $Id: vdbe.c,v 1.618 2007/05/12 12:08:51 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -4196,7 +4196,7 @@ case OP_ParseSchema: { /* no-push */ case OP_LoadAnalysis: { /* no-push */ int iDb = pOp->p1; assert( iDb>=0 && iDb<db->nDb ); - sqlite3AnalysisLoad(db, iDb); + rc = sqlite3AnalysisLoad(db, iDb); break; } #endif /* !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER) */ diff --git a/test/mallocA.test b/test/mallocA.test new file mode 100644 index 000000000..507b90727 --- /dev/null +++ b/test/mallocA.test @@ -0,0 +1,146 @@ +# 2007 April 30 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file contains additional out-of-memory checks (see malloc.tcl). +# +# $Id: mallocA.test,v 1.1 2007/05/12 12:08:51 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Only run these tests if memory debugging is turned on. +# +if {[info command sqlite_malloc_stat]==""} { + puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." + finish_test + return +} + +# Usage: do_malloc_test <test number> <options...> +# +# The first argument, <test number>, is an integer used to name the +# tests executed by this proc. Options are as follows: +# +# -tclprep TCL script to run to prepare test. +# -sqlprep SQL script to run to prepare test. +# -tclbody TCL script to run with malloc failure simulation. +# -sqlbody TCL script to run with malloc failure simulation. +# -cleanup TCL script to run after the test. +# +# This command runs a series of tests to verify SQLite's ability +# to handle an out-of-memory condition gracefully. It is assumed +# that if this condition occurs a malloc() call will return a +# NULL pointer. Linux, for example, doesn't do that by default. See +# the "BUGS" section of malloc(3). +# +# Each iteration of a loop, the TCL commands in any argument passed +# to the -tclbody switch, followed by the SQL commands in any argument +# passed to the -sqlbody switch are executed. Each iteration the +# Nth call to sqliteMalloc() is made to fail, where N is increased +# each time the loop runs starting from 1. When all commands execute +# successfully, the loop ends. +# +proc do_malloc_test {tn args} { + array unset ::mallocopts + array set ::mallocopts $args + + set ::go 1 + for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { + do_test mallocA-$tn.$::n { + + sqlite_malloc_fail 0 + catch {db close} + catch {file delete -force test.db test.db-journal} + catch {file copy test.db.bu test.db} + sqlite3 db test.db + set ::DB [sqlite3_connection_pointer db] + + # Execute any -tclprep and -sqlprep scripts. + # + if {[info exists ::mallocopts(-tclprep)]} { + eval $::mallocopts(-tclprep) + } + if {[info exists ::mallocopts(-sqlprep)]} { + execsql $::mallocopts(-sqlprep) + } + + # Now set the ${::n}th malloc() to fail and execute the -tclbody and + # -sqlbody scripts. + # + sqlite_malloc_fail $::n + set ::mallocbody {} + if {[info exists ::mallocopts(-tclbody)]} { + append ::mallocbody "$::mallocopts(-tclbody)\n" + } + if {[info exists ::mallocopts(-sqlbody)]} { + append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" + } + set v [catch $::mallocbody msg] + + # If the test fails (if $v!=0) and the database connection actually + # exists, make sure the failure code is SQLITE_NOMEM. + if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)] + && [db errorcode]!=7} { + set v 999 + } + + set leftover [lindex [sqlite_malloc_stat] 2] + if {$leftover>0} { + if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} + set ::go 0 + if {$v} { + puts "\nError message returned: $msg" + } else { + set v {1 1} + } + } else { + set v2 [expr {$msg=="" || [regexp {out of memory} $msg]}] + if {!$v2} {puts "\nError message returned: $msg"} + lappend v $v2 + } + } {1 1} + + if {[info exists ::mallocopts(-cleanup)]} { + catch [list uplevel #0 $::mallocopts(-cleanup)] msg + } + } + unset ::mallocopts +} + +# Construct a test database +# +file delete -force test.db.bu +db eval { + CREATE TABLE t1(a,b,c); + INSERT INTO t1 VALUES(1,2,3); + INSERT INTO t1 VALUES(1,2,4); + INSERT INTO t1 VALUES(2,3,4); + CREATE INDEX t1i1 ON t1(a); + CREATE INDEX t1i2 ON t1(b,c); + CREATE TABLE t2(x,y,z); +} +db close +file copy test.db test.db.bu +sqlite3 db test.db + + +do_malloc_test 1 -sqlbody { + ANALYZE +} + +# Ensure that no file descriptors were leaked. +do_test malloc-99.X { + catch {db close} + set sqlite_open_file_count +} {0} + +file delete -force test.db.bu +sqlite_malloc_fail 0 +finish_test |