aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--manifest19
-rw-r--r--manifest.uuid2
-rw-r--r--src/analyze.c27
-rw-r--r--src/sqliteInt.h4
-rw-r--r--src/vdbe.c4
-rw-r--r--test/mallocA.test146
6 files changed, 178 insertions, 24 deletions
diff --git a/manifest b/manifest
index ff604676e..04150e8fd 100644
--- a/manifest
+++ b/manifest
@@ -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