Annotation of embedaddon/sqlite3/test/fuzz_common.tcl, revision 1.1
1.1 ! misho 1: # 2007 May 10
! 2: #
! 3: # The author disclaims copyright to this source code. In place of
! 4: # a legal notice, here is a blessing:
! 5: #
! 6: # May you do good and not evil.
! 7: # May you find forgiveness for yourself and forgive others.
! 8: # May you share freely, never taking more than you give.
! 9: #
! 10: #***********************************************************************
! 11: #
! 12: # $Id: fuzz_common.tcl,v 1.2 2009/01/05 19:36:30 drh Exp $
! 13:
! 14: proc fuzz {TemplateList} {
! 15: set n [llength $TemplateList]
! 16: set i [expr {int(rand()*$n)}]
! 17: set r [uplevel 1 subst -novar [list [lindex $TemplateList $i]]]
! 18:
! 19: string map {"\n" " "} $r
! 20: }
! 21:
! 22: # Fuzzy generation primitives:
! 23: #
! 24: # Literal
! 25: # UnaryOp
! 26: # BinaryOp
! 27: # Expr
! 28: # Table
! 29: # Select
! 30: # Insert
! 31: #
! 32:
! 33: # Returns a string representing an SQL literal.
! 34: #
! 35: proc Literal {} {
! 36: set TemplateList {
! 37: 456 0 -456 1 -1
! 38: 2147483648 2147483647 2147483649 -2147483647 -2147483648 -2147483649
! 39: 'The' 'first' 'experiments' 'in' 'hardware' 'fault' 'injection'
! 40: zeroblob(1000)
! 41: NULL
! 42: 56.1 -56.1
! 43: 123456789.1234567899
! 44: }
! 45: fuzz $TemplateList
! 46: }
! 47:
! 48: # Returns a string containing an SQL unary operator (e.g. "+" or "NOT").
! 49: #
! 50: proc UnaryOp {} {
! 51: set TemplateList {+ - NOT ~}
! 52: fuzz $TemplateList
! 53: }
! 54:
! 55: # Returns a string containing an SQL binary operator (e.g. "*" or "/").
! 56: #
! 57: proc BinaryOp {} {
! 58: set TemplateList {
! 59: || * / % + - << >> & | < <= > >= = == != <> AND OR
! 60: LIKE GLOB {NOT LIKE}
! 61: }
! 62: fuzz $TemplateList
! 63: }
! 64:
! 65: # Return the complete text of an SQL expression.
! 66: #
! 67: set ::ExprDepth 0
! 68: proc Expr { {c {}} } {
! 69: incr ::ExprDepth
! 70:
! 71: set TemplateList [concat $c $c $c {[Literal]}]
! 72: if {$::ExprDepth < 3} {
! 73: lappend TemplateList \
! 74: {[Expr $c] [BinaryOp] [Expr $c]} \
! 75: {[UnaryOp] [Expr $c]} \
! 76: {[Expr $c] ISNULL} \
! 77: {[Expr $c] NOTNULL} \
! 78: {CAST([Expr $c] AS blob)} \
! 79: {CAST([Expr $c] AS text)} \
! 80: {CAST([Expr $c] AS integer)} \
! 81: {CAST([Expr $c] AS real)} \
! 82: {abs([Expr])} \
! 83: {coalesce([Expr], [Expr])} \
! 84: {hex([Expr])} \
! 85: {length([Expr])} \
! 86: {lower([Expr])} \
! 87: {upper([Expr])} \
! 88: {quote([Expr])} \
! 89: {random()} \
! 90: {randomblob(min(max([Expr],1), 500))} \
! 91: {typeof([Expr])} \
! 92: {substr([Expr],[Expr],[Expr])} \
! 93: {CASE WHEN [Expr $c] THEN [Expr $c] ELSE [Expr $c] END} \
! 94: {[Literal]} {[Literal]} {[Literal]} \
! 95: {[Literal]} {[Literal]} {[Literal]} \
! 96: {[Literal]} {[Literal]} {[Literal]} \
! 97: {[Literal]} {[Literal]} {[Literal]}
! 98: }
! 99: if {$::SelectDepth < 4} {
! 100: lappend TemplateList \
! 101: {([Select 1])} \
! 102: {[Expr $c] IN ([Select 1])} \
! 103: {[Expr $c] NOT IN ([Select 1])} \
! 104: {EXISTS ([Select 1])} \
! 105: }
! 106: set res [fuzz $TemplateList]
! 107: incr ::ExprDepth -1
! 108: return $res
! 109: }
! 110:
! 111: # Return a valid table name.
! 112: #
! 113: set ::TableList [list]
! 114: proc Table {} {
! 115: set TemplateList [concat sqlite_master $::TableList]
! 116: fuzz $TemplateList
! 117: }
! 118:
! 119: # Return one of:
! 120: #
! 121: # "SELECT DISTINCT", "SELECT ALL" or "SELECT"
! 122: #
! 123: proc SelectKw {} {
! 124: set TemplateList {
! 125: "SELECT DISTINCT"
! 126: "SELECT ALL"
! 127: "SELECT"
! 128: }
! 129: fuzz $TemplateList
! 130: }
! 131:
! 132: # Return a result set for a SELECT statement.
! 133: #
! 134: proc ResultSet {{nRes 0} {c ""}} {
! 135: if {$nRes == 0} {
! 136: set nRes [expr {rand()*2 + 1}]
! 137: }
! 138:
! 139: set aRes [list]
! 140: for {set ii 0} {$ii < $nRes} {incr ii} {
! 141: lappend aRes [Expr $c]
! 142: }
! 143:
! 144: join $aRes ", "
! 145: }
! 146:
! 147: set ::SelectDepth 0
! 148: set ::ColumnList [list]
! 149: proc SimpleSelect {{nRes 0}} {
! 150:
! 151: set TemplateList {
! 152: {[SelectKw] [ResultSet $nRes]}
! 153: }
! 154:
! 155: # The ::SelectDepth variable contains the number of ancestor SELECT
! 156: # statements (i.e. for a top level SELECT it is set to 0, for a
! 157: # sub-select 1, for a sub-select of a sub-select 2 etc.).
! 158: #
! 159: # If this is already greater than 3, do not generate a complicated
! 160: # SELECT statement. This tends to cause parser stack overflow (too
! 161: # boring to bother with).
! 162: #
! 163: if {$::SelectDepth < 4} {
! 164: lappend TemplateList \
! 165: {[SelectKw] [ResultSet $nRes $::ColumnList] FROM ([Select])} \
! 166: {[SelectKw] [ResultSet $nRes] FROM ([Select])} \
! 167: {[SelectKw] [ResultSet $nRes $::ColumnList] FROM [Table]} \
! 168: {
! 169: [SelectKw] [ResultSet $nRes $::ColumnList]
! 170: FROM ([Select])
! 171: GROUP BY [Expr]
! 172: HAVING [Expr]
! 173: } \
! 174:
! 175: if {0 == $nRes} {
! 176: lappend TemplateList \
! 177: {[SelectKw] * FROM ([Select])} \
! 178: {[SelectKw] * FROM [Table]} \
! 179: {[SelectKw] * FROM [Table] WHERE [Expr $::ColumnList]} \
! 180: {
! 181: [SelectKw] *
! 182: FROM [Table],[Table] AS t2
! 183: WHERE [Expr $::ColumnList]
! 184: } {
! 185: [SelectKw] *
! 186: FROM [Table] LEFT OUTER JOIN [Table] AS t2
! 187: ON [Expr $::ColumnList]
! 188: WHERE [Expr $::ColumnList]
! 189: }
! 190: }
! 191: }
! 192:
! 193: fuzz $TemplateList
! 194: }
! 195:
! 196: # Return a SELECT statement.
! 197: #
! 198: # If boolean parameter $isExpr is set to true, make sure the
! 199: # returned SELECT statement returns a single column of data.
! 200: #
! 201: proc Select {{nMulti 0}} {
! 202: set TemplateList {
! 203: {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
! 204: {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
! 205: {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
! 206: {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]} {[SimpleSelect $nMulti]}
! 207: {[SimpleSelect $nMulti] ORDER BY [Expr] DESC}
! 208: {[SimpleSelect $nMulti] ORDER BY [Expr] ASC}
! 209: {[SimpleSelect $nMulti] ORDER BY [Expr] ASC, [Expr] DESC}
! 210: {[SimpleSelect $nMulti] ORDER BY [Expr] LIMIT [Expr] OFFSET [Expr]}
! 211: }
! 212:
! 213: if {$::SelectDepth < 4} {
! 214: if {$nMulti == 0} {
! 215: set nMulti [expr {(rand()*2)+1}]
! 216: }
! 217: lappend TemplateList \
! 218: {[SimpleSelect $nMulti] UNION [Select $nMulti]} \
! 219: {[SimpleSelect $nMulti] UNION ALL [Select $nMulti]} \
! 220: {[SimpleSelect $nMulti] EXCEPT [Select $nMulti]} \
! 221: {[SimpleSelect $nMulti] INTERSECT [Select $nMulti]}
! 222: }
! 223:
! 224: incr ::SelectDepth
! 225: set res [fuzz $TemplateList]
! 226: incr ::SelectDepth -1
! 227: set res
! 228: }
! 229:
! 230: # Generate and return a fuzzy INSERT statement.
! 231: #
! 232: proc Insert {} {
! 233: set TemplateList {
! 234: {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr]);}
! 235: {INSERT INTO [Table] VALUES([Expr], [Expr], [Expr], [Expr]);}
! 236: {INSERT INTO [Table] VALUES([Expr], [Expr]);}
! 237: }
! 238: fuzz $TemplateList
! 239: }
! 240:
! 241: proc Column {} {
! 242: fuzz $::ColumnList
! 243: }
! 244:
! 245: # Generate and return a fuzzy UPDATE statement.
! 246: #
! 247: proc Update {} {
! 248: set TemplateList {
! 249: {UPDATE [Table]
! 250: SET [Column] = [Expr $::ColumnList]
! 251: WHERE [Expr $::ColumnList]}
! 252: }
! 253: fuzz $TemplateList
! 254: }
! 255:
! 256: proc Delete {} {
! 257: set TemplateList {
! 258: {DELETE FROM [Table] WHERE [Expr $::ColumnList]}
! 259: }
! 260: fuzz $TemplateList
! 261: }
! 262:
! 263: proc Statement {} {
! 264: set TemplateList {
! 265: {[Update]}
! 266: {[Insert]}
! 267: {[Select]}
! 268: {[Delete]}
! 269: }
! 270: fuzz $TemplateList
! 271: }
! 272:
! 273: # Return an identifier. This just chooses randomly from a fixed set
! 274: # of strings.
! 275: proc Identifier {} {
! 276: set TemplateList {
! 277: This just chooses randomly a fixed
! 278: We would also thank the developers
! 279: for their analysis Samba
! 280: }
! 281: fuzz $TemplateList
! 282: }
! 283:
! 284: proc Check {} {
! 285: # Use a large value for $::SelectDepth, because sub-selects are
! 286: # not allowed in expressions used by CHECK constraints.
! 287: #
! 288: set sd $::SelectDepth
! 289: set ::SelectDepth 500
! 290: set TemplateList {
! 291: {}
! 292: {CHECK ([Expr])}
! 293: }
! 294: set res [fuzz $TemplateList]
! 295: set ::SelectDepth $sd
! 296: set res
! 297: }
! 298:
! 299: proc Coltype {} {
! 300: set TemplateList {
! 301: {INTEGER PRIMARY KEY}
! 302: {VARCHAR [Check]}
! 303: {PRIMARY KEY}
! 304: }
! 305: fuzz $TemplateList
! 306: }
! 307:
! 308: proc DropTable {} {
! 309: set TemplateList {
! 310: {DROP TABLE IF EXISTS [Identifier]}
! 311: }
! 312: fuzz $TemplateList
! 313: }
! 314:
! 315: proc CreateView {} {
! 316: set TemplateList {
! 317: {CREATE VIEW [Identifier] AS [Select]}
! 318: }
! 319: fuzz $TemplateList
! 320: }
! 321: proc DropView {} {
! 322: set TemplateList {
! 323: {DROP VIEW IF EXISTS [Identifier]}
! 324: }
! 325: fuzz $TemplateList
! 326: }
! 327:
! 328: proc CreateTable {} {
! 329: set TemplateList {
! 330: {CREATE TABLE [Identifier]([Identifier] [Coltype], [Identifier] [Coltype])}
! 331: {CREATE TEMP TABLE [Identifier]([Identifier] [Coltype])}
! 332: }
! 333: fuzz $TemplateList
! 334: }
! 335:
! 336: proc CreateOrDropTableOrView {} {
! 337: set TemplateList {
! 338: {[CreateTable]}
! 339: {[DropTable]}
! 340: {[CreateView]}
! 341: {[DropView]}
! 342: }
! 343: fuzz $TemplateList
! 344: }
! 345:
! 346: ########################################################################
! 347:
! 348: set ::log [open fuzzy.log w]
! 349:
! 350: #
! 351: # Usage: do_fuzzy_test <testname> ?<options>?
! 352: #
! 353: # -template
! 354: # -errorlist
! 355: # -repeats
! 356: #
! 357: proc do_fuzzy_test {testname args} {
! 358: set ::fuzzyopts(-errorlist) [list]
! 359: set ::fuzzyopts(-repeats) $::REPEATS
! 360: array set ::fuzzyopts $args
! 361:
! 362: lappend ::fuzzyopts(-errorlist) {parser stack overflow}
! 363: lappend ::fuzzyopts(-errorlist) {ORDER BY}
! 364: lappend ::fuzzyopts(-errorlist) {GROUP BY}
! 365: lappend ::fuzzyopts(-errorlist) {datatype mismatch}
! 366:
! 367: for {set ii 0} {$ii < $::fuzzyopts(-repeats)} {incr ii} {
! 368: do_test ${testname}.$ii {
! 369: set ::sql [subst $::fuzzyopts(-template)]
! 370: puts $::log $::sql
! 371: flush $::log
! 372: set rc [catch {execsql $::sql} msg]
! 373: set e 1
! 374: if {$rc} {
! 375: set e 0
! 376: foreach error $::fuzzyopts(-errorlist) {
! 377: if {[string first $error $msg]>=0} {
! 378: set e 1
! 379: break
! 380: }
! 381: }
! 382: }
! 383: if {$e == 0} {
! 384: puts ""
! 385: puts $::sql
! 386: puts $msg
! 387: }
! 388: set e
! 389: } {1}
! 390: }
! 391: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>