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