Annotation of embedaddon/sqlite3/test/fuzz_common.tcl, revision 1.1.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>