-C Add\sthe\sstart\sof\sthe\ssoak-test\sinfrastructure.\s(CVS\s4042)
-D 2007-05-30T08:18:04
+C Add\ssome\sextra\stests\sfor\smalloc\sfailure\sduring\sexpression\sparsing\sand\sexecution\susing\sfuzzily\sgenerated\sSQL.\s(CVS\s4043)
+D 2007-05-30T10:36:47
F Makefile.in a42354804b50c2708ce72cf79e4daa30f50191b5
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/date.c 6049db7d5a8fdf2c677ff7d58fa31d4f6593c988
F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
-F src/expr.c 7243b6c01b976662873bbba397640fb4cbed76bc
+F src/expr.c fb386ee80026e221869f49159c0963e851c184c9
F src/func.c dfd0dd496dac46c2b14a88292cd9e141aae3ba63
F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c a193f8f0783e33ea0aa1965e951c3daa2b2c9c4e
F src/pager.h 94110a5570dca30d54a883e880a3633b2e4c05ae
-F src/parse.y e276a0c35d6579938708f0842d0eba4e9b6866e6
+F src/parse.y e3d8e3f748bd3915523f77f704f303c7f0de613b
F src/pragma.c 0d25dad58bdfd6789943a10f1b9663c2eb85b96d
F src/prepare.c 87c23644986b5e41a58bc76f05abebd899e00089
F src/printf.c cd91e057fa7e2661673eecd4eeecf4900b1e5cfe
F src/vdbe.c 74a82e8dc0cd84416fcca63d158c5ab8715f158d
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
F src/vdbeInt.h 7d2bf163d6d4e815724a457f2216dd8e38c3955c
-F src/vdbeapi.c f89d6bc5264e66f44589e454fbeeee96854d0dd3
+F src/vdbeapi.c 3747e4c3bc3139ff688bb3df462b10e42c084d16
F src/vdbeaux.c a978d170b2ca99c8ff3da8a91f116a66da2600ac
F src/vdbeblob.c 96f3572fdc45eda5be06e6372b612bc30742d9f0
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
F test/fts2m.test 4b30142ead6f3ed076e880a2a464064c5ad58c51
F test/fts2n.test a70357e72742681eaebfdbe9007b87ff3b771638
F test/func.test 605989453d1b42cec1d05c17aa232dc98e3e04e6
-F test/fuzz.test 9fdb668167bd38eb7137d49c8e9c250994bdbd5b
+F test/fuzz.test 62fc19dd36a427777fd671b569df07166548628a
F test/fuzz2.test ea38692ce2da99ad79fe0be5eb1a452c1c4d37bb
+F test/fuzz_common.tcl ff4bc2dfc465f6878f8e2d819620914365382731
+F test/fuzz_malloc.test 41ef1135f2c319b4963b1524f1bdd4a3553b827d
F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a
F test/icu.test e6bfae7f625c88fd14df6f540fe835bdfc1e4329
F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d
F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9
F test/lock4.test 49e22396b9be6e047b3d35469f233be79153c9d5
F test/main.test e7212ce1023957c7209778cc87fa932bd79ba89a
-F test/malloc.test c468c018eecba78d1832cb9aaa23a7f824f07179
+F test/malloc.test 45a81af6328381d0630ab0a3d8cb8c58551603f7
F test/malloc2.test 4ed7d719542c4570dec9c2ebe2bbdf3a9f3b0d05
F test/malloc3.test e965954b6f808876a63d3101fd70370320b509a7
F test/malloc4.test 59cd02f71b363302a04c4e77b97c0a1572eaa210
F test/malloc8.test e4054ca2a87ab1d42255bec009b177ba20b5a487
F test/malloc9.test 8381041fd89c31fba60c8a1a1c776bb022108572
F test/mallocA.test 525674e6e0775a9bf85a33f1da1c6bbddc712c30
+F test/mallocB.test 5a96951a5f06cfdbd48d61ac3add8aa77461b812
+F test/malloc_common.tcl 3cda97d63fbf370061ffa9795a24e5027367fef3
F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8
F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
F test/printf.test 69d8cb0771a1a5e4d9d5dece12fc2c16179ac5e5
F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x
F test/ptrchng.test 1c712dd6516e1377471744fa765e41c79a357da6
-F test/quick.test 41052ccf861fa49145496c9e9db62df4b0a2b6b8
+F test/quick.test 73a81a29fc28661c9c3fee2dcc3ded83cb1f1834
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
F test/shared2.test 8b48f8d33494413ef4cf250110d89403e2bf6b23
F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749
F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821
-F test/soak.test dac7ec07bdedd8f924de69ba029ed1dacbc1082a
+F test/soak.test 64f9b27fbcdec43335a88c546ce1983e6ba40d7b
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/speed1.test 22e1b27af0683ed44dcd2f93ed817a9c3e65084a
F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 03750a2a6b5186689f7db6650c0a889429790b03
-R cd63e6e2215c48b174d5e94a02b48d9a
+P 5d0b247ca1667f5d773bda337cb6f58c3b14676a
+R a618a8ac57ff1c991566b3aa8912d34a
U danielk1977
-Z 17f10a57e39853a2feb0d4c1a0988d68
+Z 5fc3b63bae0e892acacf6621f7949f54
-5d0b247ca1667f5d773bda337cb6f58c3b14676a
\ No newline at end of file
+7522d2fb3204d107b8b4816d7f39c88741f20230
\ No newline at end of file
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.295 2007/05/29 12:11:30 danielk1977 Exp $
+** $Id: expr.c,v 1.296 2007/05/30 10:36:47 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
** text z[0..n-1] on the stack.
*/
static void codeInteger(Vdbe *v, const char *z, int n){
- int i;
- if( sqlite3GetInt32(z, &i) ){
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- }else if( sqlite3FitsIn64Bits(z) ){
- sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n);
- }else{
- sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n);
+ assert( z || sqlite3MallocFailed() );
+ if( z ){
+ int i;
+ if( sqlite3GetInt32(z, &i) ){
+ sqlite3VdbeAddOp(v, OP_Integer, i, 0);
+ }else if( sqlite3FitsIn64Bits(z) ){
+ sqlite3VdbeOp3(v, OP_Int64, 0, 0, z, n);
+ }else{
+ sqlite3VdbeOp3(v, OP_Real, 0, 0, z, n);
+ }
}
}
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.228 2007/05/15 16:51:37 drh Exp $
+** @(#) $Id: parse.y,v 1.229 2007/05/30 10:36:47 danielk1977 Exp $
*/
// All token codes are small integers with #defines that begin with "TK_"
}
%endif SQLITE_OMIT_CAST
expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
- if( Y->nExpr>SQLITE_MAX_FUNCTION_ARG ){
+ if( Y && Y->nExpr>SQLITE_MAX_FUNCTION_ARG ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
}
A = sqlite3ExprFunction(Y, &X);
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
const void *val;
val = sqlite3_value_blob( columnMem(pStmt,i) );
+ /* Even though there is no encoding conversion, value_blob() might
+ ** need to call malloc() to expand the result of a zeroblob()
+ ** expression.
+ */
+ columnMallocFailure(pStmt);
return val;
}
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
#
# The most complicated trees are for SELECT statements.
#
-# $Id: fuzz.test,v 1.13 2007/05/30 08:18:04 danielk1977 Exp $
+# $Id: fuzz.test,v 1.14 2007/05/30 10:36:47 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {$::ISQUICK} { set ::REPEATS 20 }
}
-proc fuzz {TemplateList} {
- set n [llength $TemplateList]
- set i [expr {int(rand()*$n)}]
- set r [uplevel 1 subst -novar [list [lindex $TemplateList $i]]]
-
- string map {"\n" " "} $r
-}
-
-# Fuzzy generation primitives:
-#
-# Literal
-# UnaryOp
-# BinaryOp
-# Expr
-# Table
-# Select
-# Insert
-#
-
-# Returns a string representing an SQL literal.
-#
-proc Literal {} {
- set TemplateList {
- 456 0 -456 1 -1
- 2147483648 2147483647 2147483649 -2147483647 -2147483648 -2147483649
- 'The' 'first' 'experiments' 'in' 'hardware' 'fault' 'injection'
- zeroblob(1000)
- NULL
- 56.1 -56.1
- 123456789.1234567899
- }
- fuzz $TemplateList
-}
-
-# Returns a string containing an SQL unary operator (e.g. "+" or "NOT").
-#
-proc UnaryOp {} {
- set TemplateList {+ - NOT ~}
- fuzz $TemplateList
-}
-
-# Returns a string containing an SQL binary operator (e.g. "*" or "/").
-#
-proc BinaryOp {} {
- set TemplateList {
- || * / % + - << >> & | < <= > >= = == != <> AND OR
- LIKE GLOB {NOT LIKE}
- }
- fuzz $TemplateList
-}
-
-# Return the complete text of an SQL expression.
-#
-set ::ExprDepth 0
-proc Expr { {c {}} } {
- incr ::ExprDepth
-
- set TemplateList [concat $c $c $c {[Literal]}]
- if {$::ExprDepth < 3} {
- lappend TemplateList \
- {[Expr $c] [BinaryOp] [Expr $c]} \
- {[UnaryOp] [Expr $c]} \
- {[Expr $c] ISNULL} \
- {[Expr $c] NOTNULL} \
- {CAST([Expr $c] AS blob)} \
- {CAST([Expr $c] AS text)} \
- {CAST([Expr $c] AS integer)} \
- {CAST([Expr $c] AS real)} \
- {abs([Expr])} \
- {coalesce([Expr], [Expr])} \
- {hex([Expr])} \
- {length([Expr])} \
- {lower([Expr])} \
- {upper([Expr])} \
- {quote([Expr])} \
- {random()} \
- {randomblob(min(max([Expr],1), 500))} \
- {typeof([Expr])} \
- {substr([Expr],[Expr],[Expr])} \
- {CASE WHEN [Expr $c] THEN [Expr $c] ELSE [Expr $c] END} \
- {[Literal]} {[Literal]} {[Literal]} \
- {[Literal]} {[Literal]} {[Literal]} \
- {[Literal]} {[Literal]} {[Literal]} \
- {[Literal]} {[Literal]} {[Literal]}
- }
- if {$::SelectDepth < 4} {
- lappend TemplateList \
- {([Select 1])} \
- {[Expr $c] IN ([Select 1])} \
- {[Expr $c] NOT IN ([Select 1])} \
- {EXISTS ([Select 1])} \
- }
- set res [fuzz $TemplateList]
- incr ::ExprDepth -1
- return $res
-}
-
-# Return a valid table name.
-#
-set ::TableList [list]
-proc Table {} {
- set TemplateList [concat sqlite_master $::TableList]
- fuzz $TemplateList
-}
-
-# Return one of:
-#
-# "SELECT DISTINCT", "SELECT ALL" or "SELECT"
-#
-proc SelectKw {} {
- set TemplateList {
- "SELECT DISTINCT"
- "SELECT ALL"
- "SELECT"
- }
- fuzz $TemplateList
-}
-
-# Return a result set for a SELECT statement.
-#
-proc ResultSet {{nRes 0} {c ""}} {
- if {$nRes == 0} {
- set nRes [expr {rand()*2 + 1}]
- }
-
- set aRes [list]
- for {set ii 0} {$ii < $nRes} {incr ii} {
- lappend aRes [Expr $c]
- }
-
- join $aRes ", "
-}
-
-set ::SelectDepth 0
-set ::ColumnList [list]
-proc SimpleSelect {{nRes 0}} {
-
- set TemplateList {
- {[SelectKw] [ResultSet $nRes]}
- }
-
- # The ::SelectDepth variable contains the number of ancestor SELECT
- # statements (i.e. for a top level SELECT it is set to 0, for a
- # sub-select 1, for a sub-select of a sub-select 2 etc.).
- #
- # If this is already greater than 3, do not generate a complicated
- # SELECT statement. This tends to cause parser stack overflow (too
- # boring to bother with).
- #
- if {$::SelectDepth < 4} {
- lappend TemplateList \
- {[SelectKw] [ResultSet $nRes $::ColumnList] FROM ([Select])} \
- {[SelectKw] [ResultSet $nRes] FROM ([Select])} \
- {[SelectKw] [ResultSet $nRes $::ColumnList] FROM [Table]} \
- {
- [SelectKw] [ResultSet $nRes $::ColumnList]
- FROM ([Select])
- GROUP BY [Expr]
- HAVING [Expr]
- } \
-
- if {0 == $nRes} {
- lappend TemplateList \
- {[SelectKw] * FROM ([Select])} \
- {[SelectKw] * FROM [Table]} \
- {[SelectKw] * FROM [Table] WHERE [Expr $::ColumnList]} \
- {
- [SelectKw] *
- FROM [Table],[Table] AS t2
- WHERE [Expr $::ColumnList]
- } {
- [SelectKw] *
- FROM [Table] LEFT OUTER JOIN [Table] AS t2
- ON [Expr $::ColumnList]
- WHERE [Expr $::ColumnList]
- }
- }
- }
-
- fuzz $TemplateList
-}
-
-# Return a SELECT statement.
-#
-# If boolean parameter $isExpr is set to true, make sure the
-# returned SELECT statement returns a single column of data.
-#
-proc Select {{nMulti 0}} {
- set TemplateList {
- {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
- {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
- {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
- {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
- {[SimpleSelect $nMulti] ORDER BY [Expr] DESC}
- {[SimpleSelect $nMulti] ORDER BY [Expr] ASC}
- {[SimpleSelect $nMulti] ORDER BY [Expr] ASC, [Expr] DESC}
- {[SimpleSelect $nMulti] ORDER BY [Expr] LIMIT [Expr] OFFSET [Expr]}
- }
-
- if {$::SelectDepth < 4} {
- if {$nMulti == 0} {
- set nMulti [expr {(rand()*2)+1}]
- }
- lappend TemplateList \
- {[SimpleSelect $nMulti] UNION [Select $nMulti]} \
- {[SimpleSelect $nMulti] UNION ALL [Select $nMulti]} \
- {[SimpleSelect $nMulti] EXCEPT [Select $nMulti]} \
- {[SimpleSelect $nMulti] INTERSECT [Select $nMulti]}
- }
-
- incr ::SelectDepth
- set res [fuzz $TemplateList]
- incr ::SelectDepth -1
- set res
-}
-
-# Generate and return a fuzzy INSERT statement.
-#
-proc Insert {} {
- set TemplateList {
- {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr]);}
- {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr], [Expr]);}
- {INSERT INTO [Table] VALUES([Expr], [Expr]);}
- }
- fuzz $TemplateList
-}
-
-proc Column {} {
- fuzz $::ColumnList
-}
-
-# Generate and return a fuzzy UPDATE statement.
-#
-proc Update {} {
- set TemplateList {
- {UPDATE [Table]
- SET [Column] = [Expr $::ColumnList]
- WHERE [Expr $::ColumnList]}
- }
- fuzz $TemplateList
-}
-
-proc Delete {} {
- set TemplateList {
- {DELETE FROM [Table] WHERE [Expr $::ColumnList]}
- }
- fuzz $TemplateList
-}
-
-proc Statement {} {
- set TemplateList {
- {[Update]}
- {[Insert]}
- {[Select]}
- {[Delete]}
- }
- fuzz $TemplateList
-}
-
-# Return an identifier. This just chooses randomly from a fixed set
-# of strings.
-proc Identifier {} {
- set TemplateList {
- This just chooses randomly a fixed
- We would also thank the developers
- for their analysis Samba
- }
- fuzz $TemplateList
-}
-
-proc Check {} {
- # Use a large value for $::SelectDepth, because sub-selects are
- # not allowed in expressions used by CHECK constraints.
- #
- set sd $::SelectDepth
- set ::SelectDepth 500
- set TemplateList {
- {}
- {CHECK ([Expr])}
- }
- set res [fuzz $TemplateList]
- set ::SelectDepth $sd
- set res
-}
-
-proc Coltype {} {
- set TemplateList {
- {INTEGER PRIMARY KEY}
- {VARCHAR [Check]}
- {PRIMARY KEY}
- }
- fuzz $TemplateList
-}
-
-proc DropTable {} {
- set TemplateList {
- {DROP TABLE IF EXISTS [Identifier]}
- }
- fuzz $TemplateList
-}
-
-proc CreateView {} {
- set TemplateList {
- {CREATE VIEW [Identifier] AS [Select]}
- }
- fuzz $TemplateList
-}
-proc DropView {} {
- set TemplateList {
- {DROP VIEW IF EXISTS [Identifier]}
- }
- fuzz $TemplateList
-}
-
-proc CreateTable {} {
- set TemplateList {
- {CREATE TABLE [Identifier]([Identifier] [Coltype], [Identifier] [Coltype])}
- {CREATE TEMP TABLE [Identifier]([Identifier] [Coltype])}
- }
- fuzz $TemplateList
-}
-
-proc CreateOrDropTableOrView {} {
- set TemplateList {
- {[CreateTable]}
- {[DropTable]}
- {[CreateView]}
- {[DropView]}
- }
- fuzz $TemplateList
-}
-
-########################################################################
-
-set ::log [open fuzzy.log w]
-
-#
-# Usage: do_fuzzy_test <testname> ?<options>?
-#
-# -template
-# -errorlist
-# -repeats
-#
-proc do_fuzzy_test {testname args} {
- set ::fuzzyopts(-errorlist) [list]
- set ::fuzzyopts(-repeats) $::REPEATS
- array set ::fuzzyopts $args
-
- lappend ::fuzzyopts(-errorlist) {parser stack overflow}
- lappend ::fuzzyopts(-errorlist) {ORDER BY}
- lappend ::fuzzyopts(-errorlist) {GROUP BY}
- lappend ::fuzzyopts(-errorlist) {datatype mismatch}
-
- for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} {
- do_test ${testname}.$ii {
- set ::sql [subst $::fuzzyopts(-template)]
- puts $::log $::sql
- flush $::log
- set rc [catch {execsql $::sql} msg]
- set e 1
- if {$rc} {
- set e 0
- foreach error $::fuzzyopts(-errorlist) {
- if {0 == [string first $error $msg]} {
- set e 1
- break
- }
- }
- }
- if {$e == 0} {
- puts ""
- puts $::sql
- puts $msg
- }
- set e
- } {1}
- }
-}
+source $testdir/fuzz_common.tcl
#----------------------------------------------------------------
# These tests caused errors that were first caught by the tests
--- /dev/null
+# 2007 May 10
+#
+# 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.
+#
+#***********************************************************************
+#
+# $Id: fuzz_common.tcl,v 1.1 2007/05/30 10:36:47 danielk1977 Exp $
+
+proc fuzz {TemplateList} {
+ set n [llength $TemplateList]
+ set i [expr {int(rand()*$n)}]
+ set r [uplevel 1 subst -novar [list [lindex $TemplateList $i]]]
+
+ string map {"\n" " "} $r
+}
+
+# Fuzzy generation primitives:
+#
+# Literal
+# UnaryOp
+# BinaryOp
+# Expr
+# Table
+# Select
+# Insert
+#
+
+# Returns a string representing an SQL literal.
+#
+proc Literal {} {
+ set TemplateList {
+ 456 0 -456 1 -1
+ 2147483648 2147483647 2147483649 -2147483647 -2147483648 -2147483649
+ 'The' 'first' 'experiments' 'in' 'hardware' 'fault' 'injection'
+ zeroblob(1000)
+ NULL
+ 56.1 -56.1
+ 123456789.1234567899
+ }
+ fuzz $TemplateList
+}
+
+# Returns a string containing an SQL unary operator (e.g. "+" or "NOT").
+#
+proc UnaryOp {} {
+ set TemplateList {+ - NOT ~}
+ fuzz $TemplateList
+}
+
+# Returns a string containing an SQL binary operator (e.g. "*" or "/").
+#
+proc BinaryOp {} {
+ set TemplateList {
+ || * / % + - << >> & | < <= > >= = == != <> AND OR
+ LIKE GLOB {NOT LIKE}
+ }
+ fuzz $TemplateList
+}
+
+# Return the complete text of an SQL expression.
+#
+set ::ExprDepth 0
+proc Expr { {c {}} } {
+ incr ::ExprDepth
+
+ set TemplateList [concat $c $c $c {[Literal]}]
+ if {$::ExprDepth < 3} {
+ lappend TemplateList \
+ {[Expr $c] [BinaryOp] [Expr $c]} \
+ {[UnaryOp] [Expr $c]} \
+ {[Expr $c] ISNULL} \
+ {[Expr $c] NOTNULL} \
+ {CAST([Expr $c] AS blob)} \
+ {CAST([Expr $c] AS text)} \
+ {CAST([Expr $c] AS integer)} \
+ {CAST([Expr $c] AS real)} \
+ {abs([Expr])} \
+ {coalesce([Expr], [Expr])} \
+ {hex([Expr])} \
+ {length([Expr])} \
+ {lower([Expr])} \
+ {upper([Expr])} \
+ {quote([Expr])} \
+ {random()} \
+ {randomblob(min(max([Expr],1), 500))} \
+ {typeof([Expr])} \
+ {substr([Expr],[Expr],[Expr])} \
+ {CASE WHEN [Expr $c] THEN [Expr $c] ELSE [Expr $c] END} \
+ {[Literal]} {[Literal]} {[Literal]} \
+ {[Literal]} {[Literal]} {[Literal]} \
+ {[Literal]} {[Literal]} {[Literal]} \
+ {[Literal]} {[Literal]} {[Literal]}
+ }
+ if {$::SelectDepth < 4} {
+ lappend TemplateList \
+ {([Select 1])} \
+ {[Expr $c] IN ([Select 1])} \
+ {[Expr $c] NOT IN ([Select 1])} \
+ {EXISTS ([Select 1])} \
+ }
+ set res [fuzz $TemplateList]
+ incr ::ExprDepth -1
+ return $res
+}
+
+# Return a valid table name.
+#
+set ::TableList [list]
+proc Table {} {
+ set TemplateList [concat sqlite_master $::TableList]
+ fuzz $TemplateList
+}
+
+# Return one of:
+#
+# "SELECT DISTINCT", "SELECT ALL" or "SELECT"
+#
+proc SelectKw {} {
+ set TemplateList {
+ "SELECT DISTINCT"
+ "SELECT ALL"
+ "SELECT"
+ }
+ fuzz $TemplateList
+}
+
+# Return a result set for a SELECT statement.
+#
+proc ResultSet {{nRes 0} {c ""}} {
+ if {$nRes == 0} {
+ set nRes [expr {rand()*2 + 1}]
+ }
+
+ set aRes [list]
+ for {set ii 0} {$ii < $nRes} {incr ii} {
+ lappend aRes [Expr $c]
+ }
+
+ join $aRes ", "
+}
+
+set ::SelectDepth 0
+set ::ColumnList [list]
+proc SimpleSelect {{nRes 0}} {
+
+ set TemplateList {
+ {[SelectKw] [ResultSet $nRes]}
+ }
+
+ # The ::SelectDepth variable contains the number of ancestor SELECT
+ # statements (i.e. for a top level SELECT it is set to 0, for a
+ # sub-select 1, for a sub-select of a sub-select 2 etc.).
+ #
+ # If this is already greater than 3, do not generate a complicated
+ # SELECT statement. This tends to cause parser stack overflow (too
+ # boring to bother with).
+ #
+ if {$::SelectDepth < 4} {
+ lappend TemplateList \
+ {[SelectKw] [ResultSet $nRes $::ColumnList] FROM ([Select])} \
+ {[SelectKw] [ResultSet $nRes] FROM ([Select])} \
+ {[SelectKw] [ResultSet $nRes $::ColumnList] FROM [Table]} \
+ {
+ [SelectKw] [ResultSet $nRes $::ColumnList]
+ FROM ([Select])
+ GROUP BY [Expr]
+ HAVING [Expr]
+ } \
+
+ if {0 == $nRes} {
+ lappend TemplateList \
+ {[SelectKw] * FROM ([Select])} \
+ {[SelectKw] * FROM [Table]} \
+ {[SelectKw] * FROM [Table] WHERE [Expr $::ColumnList]} \
+ {
+ [SelectKw] *
+ FROM [Table],[Table] AS t2
+ WHERE [Expr $::ColumnList]
+ } {
+ [SelectKw] *
+ FROM [Table] LEFT OUTER JOIN [Table] AS t2
+ ON [Expr $::ColumnList]
+ WHERE [Expr $::ColumnList]
+ }
+ }
+ }
+
+ fuzz $TemplateList
+}
+
+# Return a SELECT statement.
+#
+# If boolean parameter $isExpr is set to true, make sure the
+# returned SELECT statement returns a single column of data.
+#
+proc Select {{nMulti 0}} {
+ set TemplateList {
+ {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
+ {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
+ {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
+ {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
+ {[SimpleSelect $nMulti] ORDER BY [Expr] DESC}
+ {[SimpleSelect $nMulti] ORDER BY [Expr] ASC}
+ {[SimpleSelect $nMulti] ORDER BY [Expr] ASC, [Expr] DESC}
+ {[SimpleSelect $nMulti] ORDER BY [Expr] LIMIT [Expr] OFFSET [Expr]}
+ }
+
+ if {$::SelectDepth < 4} {
+ if {$nMulti == 0} {
+ set nMulti [expr {(rand()*2)+1}]
+ }
+ lappend TemplateList \
+ {[SimpleSelect $nMulti] UNION [Select $nMulti]} \
+ {[SimpleSelect $nMulti] UNION ALL [Select $nMulti]} \
+ {[SimpleSelect $nMulti] EXCEPT [Select $nMulti]} \
+ {[SimpleSelect $nMulti] INTERSECT [Select $nMulti]}
+ }
+
+ incr ::SelectDepth
+ set res [fuzz $TemplateList]
+ incr ::SelectDepth -1
+ set res
+}
+
+# Generate and return a fuzzy INSERT statement.
+#
+proc Insert {} {
+ set TemplateList {
+ {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr]);}
+ {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr], [Expr]);}
+ {INSERT INTO [Table] VALUES([Expr], [Expr]);}
+ }
+ fuzz $TemplateList
+}
+
+proc Column {} {
+ fuzz $::ColumnList
+}
+
+# Generate and return a fuzzy UPDATE statement.
+#
+proc Update {} {
+ set TemplateList {
+ {UPDATE [Table]
+ SET [Column] = [Expr $::ColumnList]
+ WHERE [Expr $::ColumnList]}
+ }
+ fuzz $TemplateList
+}
+
+proc Delete {} {
+ set TemplateList {
+ {DELETE FROM [Table] WHERE [Expr $::ColumnList]}
+ }
+ fuzz $TemplateList
+}
+
+proc Statement {} {
+ set TemplateList {
+ {[Update]}
+ {[Insert]}
+ {[Select]}
+ {[Delete]}
+ }
+ fuzz $TemplateList
+}
+
+# Return an identifier. This just chooses randomly from a fixed set
+# of strings.
+proc Identifier {} {
+ set TemplateList {
+ This just chooses randomly a fixed
+ We would also thank the developers
+ for their analysis Samba
+ }
+ fuzz $TemplateList
+}
+
+proc Check {} {
+ # Use a large value for $::SelectDepth, because sub-selects are
+ # not allowed in expressions used by CHECK constraints.
+ #
+ set sd $::SelectDepth
+ set ::SelectDepth 500
+ set TemplateList {
+ {}
+ {CHECK ([Expr])}
+ }
+ set res [fuzz $TemplateList]
+ set ::SelectDepth $sd
+ set res
+}
+
+proc Coltype {} {
+ set TemplateList {
+ {INTEGER PRIMARY KEY}
+ {VARCHAR [Check]}
+ {PRIMARY KEY}
+ }
+ fuzz $TemplateList
+}
+
+proc DropTable {} {
+ set TemplateList {
+ {DROP TABLE IF EXISTS [Identifier]}
+ }
+ fuzz $TemplateList
+}
+
+proc CreateView {} {
+ set TemplateList {
+ {CREATE VIEW [Identifier] AS [Select]}
+ }
+ fuzz $TemplateList
+}
+proc DropView {} {
+ set TemplateList {
+ {DROP VIEW IF EXISTS [Identifier]}
+ }
+ fuzz $TemplateList
+}
+
+proc CreateTable {} {
+ set TemplateList {
+ {CREATE TABLE [Identifier]([Identifier] [Coltype], [Identifier] [Coltype])}
+ {CREATE TEMP TABLE [Identifier]([Identifier] [Coltype])}
+ }
+ fuzz $TemplateList
+}
+
+proc CreateOrDropTableOrView {} {
+ set TemplateList {
+ {[CreateTable]}
+ {[DropTable]}
+ {[CreateView]}
+ {[DropView]}
+ }
+ fuzz $TemplateList
+}
+
+########################################################################
+
+set ::log [open fuzzy.log w]
+
+#
+# Usage: do_fuzzy_test <testname> ?<options>?
+#
+# -template
+# -errorlist
+# -repeats
+#
+proc do_fuzzy_test {testname args} {
+ set ::fuzzyopts(-errorlist) [list]
+ set ::fuzzyopts(-repeats) $::REPEATS
+ array set ::fuzzyopts $args
+
+ lappend ::fuzzyopts(-errorlist) {parser stack overflow}
+ lappend ::fuzzyopts(-errorlist) {ORDER BY}
+ lappend ::fuzzyopts(-errorlist) {GROUP BY}
+ lappend ::fuzzyopts(-errorlist) {datatype mismatch}
+
+ for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} {
+ do_test ${testname}.$ii {
+ set ::sql [subst $::fuzzyopts(-template)]
+ puts $::log $::sql
+ flush $::log
+ set rc [catch {execsql $::sql} msg]
+ set e 1
+ if {$rc} {
+ set e 0
+ foreach error $::fuzzyopts(-errorlist) {
+ if {0 == [string first $error $msg]} {
+ set e 1
+ break
+ }
+ }
+ }
+ if {$e == 0} {
+ puts ""
+ puts $::sql
+ puts $msg
+ }
+ set e
+ } {1}
+ }
+}
+
--- /dev/null
+#
+# 2007 May 10
+#
+# 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 tests malloc failures in concert with fuzzy SQL generation.
+#
+# $Id: fuzz_malloc.test,v 1.1 2007/05/30 10:36:47 danielk1977 Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/fuzz_common.tcl
+source $testdir/malloc_common.tcl
+
+set ::REPEATS 20
+
+#
+# Usage: do_fuzzy_malloc_test <testname> ?<options>?
+#
+# -template
+# -repeats
+#
+proc do_fuzzy_malloc_test {testname args} {
+ set ::fuzzyopts(-repeats) $::REPEATS
+ array set ::fuzzyopts $args
+
+ for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} {
+ set ::sql [subst $::fuzzyopts(-template)]
+ # puts $::sql
+ foreach {rc res} [catchsql $::sql] {}
+ if {$rc==0} {
+ do_malloc_test $testname-$ii -sqlbody $::sql
+ } else {
+ incr ii -1
+ }
+ }
+}
+
+#----------------------------------------------------------------
+# Test malloc failure during parsing (and execution) of a fuzzily
+# generated expressions.
+#
+do_fuzzy_malloc_test fuzzy_malloc-1 -template {Select [Expr]}
+
+sqlite_malloc_fail 0
+finish_test
# 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.41 2007/04/19 11:09:02 danielk1977 Exp $
+# $Id: malloc.test,v 1.42 2007/05/30 10:36:47 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
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 malloc-$tn.$::n {
-
- # Remove all traces of database files test.db and test2.db from the files
- # system. Then open (empty database) "test.db" with the handle [db].
- #
- sqlite_malloc_fail 0
- catch {db close}
- catch {file delete -force test.db}
- catch {file delete -force test.db-journal}
- catch {file delete -force test2.db}
- catch {file delete -force test2.db-journal}
- catch {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=="" || $msg=="out of memory"}]
- 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
-}
+source $testdir/malloc_common.tcl
do_malloc_test 1 -tclprep {
db close
--- /dev/null
+# 2007 May 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).
+# These were all discovered by fuzzy generation of SQL. Apart from
+# that they have little in common.
+#
+# $Id: mallocB.test,v 1.1 2007/05/30 10:36:47 danielk1977 Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/malloc_common.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
+}
+
+do_malloc_test mallocB-1 -sqlbody {SELECT - 456}
+do_malloc_test mallocB-2 -sqlbody {SELECT - 456.1}
+do_malloc_test mallocB-3 -sqlbody {SELECT random()}
+do_malloc_test mallocB-4 -sqlbody {SELECT zeroblob(1000)}
+
+sqlite_malloc_fail 0
+finish_test
--- /dev/null
+
+# 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
+
+ if {[string is integer $tn]} {
+ set tn malloc-$tn
+ }
+
+ set ::go 1
+ for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
+ do_test $tn.$::n {
+
+ # Remove all traces of database files test.db and test2.db from the files
+ # system. Then open (empty database) "test.db" with the handle [db].
+ #
+ sqlite_malloc_fail 0
+ catch {db close}
+ catch {file delete -force test.db}
+ catch {file delete -force test.db-journal}
+ catch {file delete -force test2.db}
+ catch {file delete -force test2.db-journal}
+ catch {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=="" || $msg=="out of memory"}]
+ 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
+}
+
#***********************************************************************
# This file runs all tests.
#
-# $Id: quick.test,v 1.57 2007/05/30 08:18:04 danielk1977 Exp $
+# $Id: quick.test,v 1.58 2007/05/30 10:36:47 danielk1977 Exp $
proc lshift {lvar} {
upvar $lvar l
crash2.test
exclusive3.test
fuzz.test
+ fuzz_malloc.test
in2.test
loadext.test
malloc.test
# This file is the driver for the "soak" tests. It is a peer of the
# quick.test and all.test scripts.
#
-# $Id: soak.test,v 1.1 2007/05/30 08:18:04 danielk1977 Exp $
+# $Id: soak.test,v 1.2 2007/05/30 10:36:47 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
#
set SOAKTESTS {
fuzz.test
+ fuzz_malloc.test
trans.test
}