mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-23 11:22:09 +03:00
Make the ANALYZE command robust in the face of malloc() failures. (CVS 3989)
FossilOrigin-Name: c08658e1f8598941ebddddb98942b98cfcb86e7a
This commit is contained in:
19
manifest
19
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
|
||||
|
@ -1 +1 @@
|
||||
260338c4b2b18c9f4da8bc7fe3eda306dcaa4e38
|
||||
c08658e1f8598941ebddddb98942b98cfcb86e7a
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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*);
|
||||
|
@ -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) */
|
||||
|
146
test/mallocA.test
Normal file
146
test/mallocA.test
Normal file
@ -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
|
Reference in New Issue
Block a user