~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to sql-bench/crash-me.sh

  • Committer: bk at mysql
  • Date: 2000-07-31 19:29:14 UTC
  • Revision ID: sp1r-bk@work.mysql.com-20000731192914-08846
Import changeset

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!@PERL@
 
2
# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
 
3
#
 
4
# This library is free software; you can redistribute it and/or
 
5
# modify it under the terms of the GNU Library General Public
 
6
# License as published by the Free Software Foundation; either
 
7
# version 2 of the License, or (at your option) any later version.
 
8
#
 
9
# This library is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
# Library General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU Library General Public
 
15
# License along with this library; if not, write to the Free
 
16
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 
17
# MA 02111-1307, USA
 
18
 
 
19
# Written by Monty for the TCX/Monty Program/Detron benchmark suite.
 
20
# Empress and PostgreSQL patches by Luuk de Boer
 
21
# Extensions for ANSI SQL and Mimer by Bengt Gunne
 
22
# Some additions and corrections by Matthias Urlich
 
23
#
 
24
# This programs tries to find all limits for a sql server
 
25
# It gets the name from what it does to most servers :)
 
26
#
 
27
# Be sure to use --help before running this!
 
28
#
 
29
# If you want to add support for another server, add a new package for the
 
30
# server in server-cfg.  You only have to support the 'new' and 'version'
 
31
# functions. new doesn't need to have any limits if one doesn't want to
 
32
# use the benchmarks.
 
33
#
 
34
 
 
35
# TODO:
 
36
# CMT includes types and functions which are synonyms for other types
 
37
# and functions, including those in SQL9x. It should label those synonyms
 
38
# as such, and clarify ones such as "mediumint" with comments such as
 
39
# "3-byte int" or "same as xxx".
 
40
 
 
41
 
 
42
$version="1.47";
 
43
 
 
44
use DBI;
 
45
use Getopt::Long;
 
46
chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
 
47
require "$pwd/server-cfg" || die "Can't read Configuration file: $!\n";
 
48
 
 
49
$opt_server="mysql"; $opt_host="localhost"; $opt_database="test";
 
50
$opt_dir="limits";
 
51
$opt_debug=$opt_help=$opt_Information=$opt_restart=$opt_force=$opt_quick=0;
 
52
$opt_log_all_queries=$opt_fix_limit_file=$opt_batch_mode=0;
 
53
$opt_db_start_cmd="";           # the db server start command
 
54
$opt_sleep=10;                  # time to sleep while starting the db server
 
55
$limit_changed=0;               # For configure file
 
56
$reconnect_count=0;
 
57
$opt_comment=$opt_config_file=$opt_log_queries_to_file="";
 
58
$limits{'crash_me_safe'}='yes';
 
59
$prompts{'crash_me_safe'}='crash me safe';
 
60
$limits{'operating_system'}= machine();
 
61
$prompts{'operating_system'}='crash-me tested on';
 
62
$retry_limit=3;
 
63
 
 
64
GetOptions("Information","help","server=s","debug","user=s","password=s","database=s","restart","force","quick","log-all-queries","comment=s","host=s","fix-limit-file","dir=s","db-start-cmd=s","sleep=s","batch-mode","config-file=s","log-queries-to-file=s") || usage();
 
65
usage() if ($opt_help || $opt_Information);
 
66
 
 
67
$opt_config_file="$pwd/$opt_dir/$opt_server.cfg" if (length($opt_config_file) == 0);
 
68
 
 
69
if ($opt_fix_limit_file)
 
70
{
 
71
  print "Fixing limit file for $opt_server\n";
 
72
  read_config_data();
 
73
  $limit_changed=1;
 
74
  save_all_config_data();
 
75
  exit 0;
 
76
}
 
77
 
 
78
$server=get_server($opt_server,$opt_host,$opt_database);
 
79
$opt_server=$server->{'cmp_name'};
 
80
 
 
81
$|=1;                           # For debugging
 
82
 
 
83
print "Running $0 $version on '",($server_version=$server->version()),"'\n\n";
 
84
print "I hope you didn't have anything important running on this server....\n";
 
85
read_config_data();
 
86
if ($limit_changed)             # Must have been restarted
 
87
{
 
88
  save_config_data('crash_me_safe','no',"crash me safe");
 
89
}
 
90
 
 
91
if (!$opt_force && !$opt_batch_mode)
 
92
{
 
93
  server_info();
 
94
}
 
95
else
 
96
{
 
97
  print "Using --force.  I assume you know what you are doing...\n";
 
98
}
 
99
print "\n";
 
100
 
 
101
save_config_data('crash_me_version',$version,"crash me version");
 
102
if ($server_version)
 
103
{
 
104
  save_config_data('server_version',$server_version,"server version");
 
105
}
 
106
if (length($opt_comment))
 
107
{
 
108
  save_config_data('user_comment',$opt_comment,"comment");
 
109
}
 
110
 
 
111
$opt_log=0;
 
112
if (length($opt_log_queries_to_file))
 
113
{
 
114
  open(LOG,">$opt_log_queries_to_file") || die "Can't open file $opt_log_queries_to_file\n";
 
115
  $opt_log=1;
 
116
}
 
117
 
 
118
#
 
119
# Set up some limits that's regared as unlimited
 
120
# We don't want to take up all resources from the server...
 
121
#
 
122
 
 
123
$max_connections="+1000";       # Number of simultaneous connections
 
124
$max_buffer_size="+16000000";   # size of communication buffer.
 
125
$max_string_size="+8000000";    # Enough for this test
 
126
$max_name_length="+512";        # Actually 256, but ...
 
127
$max_keys="+64";                # Probably too big.
 
128
$max_join_tables="+64";         # Probably too big.
 
129
$max_columns="+8192";           # Probably too big.
 
130
$max_row_length=$max_string_size;
 
131
$max_key_length="+8192";        # Big enough
 
132
$max_order_by="+64";            # Big enough
 
133
$max_expressions="+10000";
 
134
$max_big_expressions="+100";
 
135
$max_stacked_expressions="+2000";
 
136
$query_size=$max_buffer_size;
 
137
$longreadlen=16000000;          # For retrieval buffer
 
138
 
 
139
#
 
140
# First do some checks that needed for the rest of the benchmark
 
141
#
 
142
use sigtrap;                   # Must be removed with perl5.005_2 on Win98
 
143
$SIG{PIPE} = 'IGNORE';
 
144
$SIG{SEGV} = sub {warn('SEGFAULT')};
 
145
$dbh=safe_connect();
 
146
$dbh->do("drop table crash_me");        # Remove old run
 
147
$dbh->do("drop table crash_me2");        # Remove old run
 
148
$dbh->do("drop table crash_me3");        # Remove old run
 
149
$dbh->do("drop table crash_q");         # Remove old run
 
150
$dbh->do("drop table crash_q1");         # Remove old run
 
151
 
 
152
$prompt="Tables without primary key";
 
153
if (!safe_query(["create table crash_me (a integer not null,b char(10) not null)",
 
154
                 "insert into crash_me (a,b) values (1,'a')"]))
 
155
{
 
156
  if (!safe_query(["create table crash_me (a integer not null,b char(10) not null, primary key (a))",
 
157
                   "insert into crash_me (a,b) values (1,'a')"]))
 
158
  {
 
159
    die "Can't create table 'crash_me' with one record: $DBI::errstr\n";
 
160
  }
 
161
  save_config_data('no_primary_key',"no",$prompt);
 
162
}
 
163
else
 
164
{
 
165
  save_config_data('no_primary_key',"yes",$prompt);
 
166
}
 
167
#
 
168
#  Define strings for character NULL and numeric NULL used in expressions
 
169
#
 
170
$char_null=$server->{'char_null'};
 
171
$numeric_null=$server->{'numeric_null'};
 
172
if ($char_null eq '')
 
173
{
 
174
  $char_null="NULL";
 
175
}
 
176
if ($numeric_null eq '')
 
177
{
 
178
  $numeric_null="NULL";
 
179
}
 
180
 
 
181
print "$prompt: $limits{'no_primary_key'}\n";
 
182
 
 
183
report("SELECT without FROM",'select_without_from',"select 1");
 
184
if ($limits{'select_without_from'} ne "yes")
 
185
{
 
186
  $end_query=" from crash_me";
 
187
  $check_connect="select a from crash_me";
 
188
}
 
189
else
 
190
{
 
191
  $end_query="";
 
192
  $check_connect="select 1";
 
193
}
 
194
 
 
195
assert($check_connect);
 
196
assert("select a from crash_me where b<'b'");
 
197
 
 
198
report("Select constants",'select_constants',"select 1 $end_query");
 
199
report("Select table_name.*",'table_wildcard',
 
200
       "select crash_me.* from crash_me");
 
201
report("Allows \' and \" as string markers",'quote_with_"',
 
202
       'select a from crash_me where b<"c"');
 
203
check_and_report("Double '' as ' in strings",'double_quotes',[],
 
204
                 "select 'Walker''s' $end_query",[],"Walker's",1);
 
205
check_and_report("Multiple line strings","multi_strings",[],
 
206
                 "select a from crash_me where b < 'a'\n'b'",[],"1",0);
 
207
check_and_report("\" as identifier quote (ANSI SQL)",'quote_ident_with_"',[],
 
208
                 'select "A" from crash_me',[],"1",0);
 
209
check_and_report("\` as identifier quote",'quote_ident_with_`',[],
 
210
                 'select `A` from crash_me',[],"1",0);
 
211
check_and_report("[] as identifier quote",'quote_ident_with_[',[],
 
212
                 'select [A] from crash_me',[],"1",0);
 
213
 
 
214
report("Column alias","column_alias","select a as ab from crash_me");
 
215
report("Table alias","table_alias","select b.a from crash_me as b");
 
216
report("Functions",'functions',"select 1+1 $end_query");
 
217
report("Group functions",'group_functions',"select count(*) from crash_me");
 
218
report("Group functions with distinct",'group_distinct_functions',
 
219
       "select count(distinct a) from crash_me");
 
220
report("Group by",'group_by',"select a from crash_me group by a");
 
221
report("Group by position",'group_by_position',
 
222
       "select a from crash_me group by 1");
 
223
report("Group by alias",'group_by_alias',
 
224
       "select a as ab from crash_me group by ab");
 
225
report("Order by",'order_by',"select a from crash_me order by a");
 
226
report("Order by position",'order_by_position',
 
227
       "select a from crash_me order by 1");
 
228
report("Order by function","order_by_function",
 
229
       "select a from crash_me order by a+1");
 
230
check_and_report("Order by DESC is remembered",'order_by_remember_desc',
 
231
                 ["create table crash_q (s int,s1 int)",
 
232
                  "insert into crash_q values(1,1)",
 
233
                  "insert into crash_q values(3,1)",
 
234
                  "insert into crash_q values(2,1)"],
 
235
                 "select s,s1 from crash_q order by s1 DESC,s",
 
236
                 ["drop table crash_q"],[3,2,1],7,undef(),3);
 
237
report("Compute",'compute',
 
238
       "select a from crash_me order by a compute sum(a) by a");
 
239
report("Value lists in INSERT",'multi_value_insert',
 
240
       "create table crash_q (s char(10))",
 
241
       "insert into crash_q values ('a'),('b')",
 
242
       "drop table crash_q");
 
243
report("INSERT with set syntax",'insert_with_set',
 
244
       "create table crash_q (a integer)",
 
245
       "insert into crash_q SET a=1",
 
246
       "drop table crash_q");
 
247
report("allows end ';'","end_colon", "select * from crash_me;");
 
248
try_and_report("LIMIT number of rows","select_limit",
 
249
               ["with LIMIT",
 
250
                "select * from crash_me limit 1"],
 
251
               ["with TOP",
 
252
                "select TOP 1 * from crash_me"]);
 
253
report("SELECT with LIMIT #,#","select_limit2", "select * from crash_me limit 1,1");
 
254
 
 
255
# The following alter table commands MUST be kept together!
 
256
if ($dbh->do("create table crash_q (a integer, b integer,c CHAR(10))"))
 
257
{
 
258
  report("Alter table add column",'alter_add_col',
 
259
         "alter table crash_q add d integer");
 
260
  report_one("Alter table add many columns",'alter_add_multi_col',
 
261
             [["alter table crash_q add (f integer,g integer)","yes"],
 
262
              ["alter table crash_q add f integer, add g integer","with add"],
 
263
              ["alter table crash_q add f integer,g integer","without add"]] );
 
264
  report("Alter table change column",'alter_change_col',
 
265
         "alter table crash_q change a e char(50)");
 
266
 
 
267
  # informix can only change data type with modify
 
268
  report_one("Alter table modify column",'alter_modify_col',
 
269
             [["alter table crash_q modify c CHAR(20)","yes"],
 
270
              ["alter table crash_q alter c CHAR(20)","with alter"]]);
 
271
  report("Alter table alter column default",'alter_alter_col',
 
272
         "alter table crash_q alter b set default 10",
 
273
         "alter table crash_q alter b set default NULL");
 
274
  report("Alter table drop column",'alter_drop_col',
 
275
         "alter table crash_q drop column b");
 
276
  report("Alter table rename table",'alter_rename_table',
 
277
         "alter table crash_q rename to crash_q1");
 
278
}
 
279
# Make sure both tables will be dropped, even if rename fails.
 
280
$dbh->do("drop table crash_q1");
 
281
$dbh->do("drop table crash_q");
 
282
 
 
283
if ($dbh->do("create table crash_q (a integer, b integer,c CHAR(10))") &&
 
284
    $dbh->do("create table crash_q1 (a integer, b integer,c CHAR(10) not null)"))
 
285
{
 
286
  report("Alter table add constraint",'alter_add_constraint',
 
287
         "alter table crash_q add constraint c1 check(a > b)");
 
288
  report("Alter table drop constraint",'alter_drop_constraint',
 
289
         "alter table crash_q drop constraint c1");
 
290
  report("Alter table add unique",'alter_add_unique',
 
291
         "alter table crash_q add constraint u1 unique(c)");
 
292
  try_and_report("Alter table drop unique",'alter_drop_unique',
 
293
                 ["with constraint",
 
294
                  "alter table crash_q drop constraint u1"],
 
295
                 ["with drop key",
 
296
                  "alter table crash_q drop key c"]);
 
297
  try_and_report("Alter table add primary key",'alter_add_primary_key',
 
298
                 ["with constraint",
 
299
                  "alter table crash_q1 add constraint p1 primary key(c)"],
 
300
                 ["with add primary key",
 
301
                  "alter table crash_q1 add primary key(c)"]);
 
302
  report("Alter table add foreign key",'alter_add_foreign_key',
 
303
         "alter table crash_q add constraint f1 foreign key(c) references crash_q1(c)");
 
304
  try_and_report("Alter table drop foreign key",'alter_drop_foreign_key',
 
305
                 ["with drop constraint",
 
306
                  "alter table crash_q drop constraint f1"],
 
307
                 ["with drop foreign key",
 
308
                  "alter table crash_q drop foreign key f1"]);
 
309
  try_and_report("Alter table drop primary key",'alter_drop_primary_key',
 
310
                 ["drop constraint",
 
311
                  "alter table crash_q1 drop constraint p1 restrict"],
 
312
                 ["drop primary key",
 
313
                  "alter table crash_q1 drop primary key"]);
 
314
}
 
315
$dbh->do("drop table crash_q");
 
316
$dbh->do("drop table crash_q1");
 
317
 
 
318
check_and_report("case insensitive compare","case_insensitive_strings",
 
319
                 [],"select b from crash_me where b = 'A'",[],'a',1);
 
320
check_and_report("ignore end space in compare","ignore_end_space",
 
321
                 [],"select b from crash_me where b = 'a '",[],'a',1);
 
322
check_and_report("group on column with null values",'group_by_null',
 
323
                 ["create table crash_q (s char(10))",
 
324
                  "insert into crash_q values(null)",
 
325
                  "insert into crash_q values(null)"],
 
326
                 "select count(*) from crash_q group by s",
 
327
                 ["drop table crash_q"],2,0);
 
328
 
 
329
$prompt="Having";
 
330
if (!defined($limits{'having'}))
 
331
{                               # Complicated because of postgreSQL
 
332
  if (!safe_query_result("select a from crash_me group by a having a > 0",1,0))
 
333
  {
 
334
    if (!safe_query_result("select a from crash_me group by a having a < 0",
 
335
                           1,0))
 
336
    { save_config_data("having","error",$prompt); }
 
337
    else
 
338
    { save_config_data("having","yes",$prompt); }
 
339
  }
 
340
  else
 
341
  { save_config_data("having","no",$prompt); }
 
342
}
 
343
print "$prompt: $limits{'having'}\n";
 
344
 
 
345
if ($limits{'having'} eq 'yes')
 
346
{
 
347
  report("Having with group function","having_with_group",
 
348
         "select a from crash_me group by a having count(*) = 1");
 
349
}
 
350
 
 
351
if ($limits{'column_alias'} eq 'yes')
 
352
{
 
353
  report("Order by alias",'order_by_alias',
 
354
         "select a as ab from crash_me order by ab");
 
355
  if ($limits{'having'} eq 'yes')
 
356
  {
 
357
    report("Having on alias","having_with_alias",
 
358
           "select a as ab from crash_me group by a having ab > 0");
 
359
  }
 
360
}
 
361
report("binary numbers (0b1001)","binary_numbers","select 0b1001 $end_query");
 
362
report("hex numbers (0x41)","hex_numbers","select 0x41 $end_query");
 
363
report("binary strings (b'0110')","binary_strings","select b'0110' $end_query");
 
364
report("hex strings (x'1ace')","hex_strings","select x'1ace' $end_query");
 
365
 
 
366
report_result("Value of logical operation (1=1)","logical_value",
 
367
              "select (1=1) $end_query");
 
368
 
 
369
$logical_value= $limits{'logical_value'};
 
370
 
 
371
$false=0;
 
372
$result="no";
 
373
if ($res=safe_query("select (1=1)=true $end_query")) {
 
374
  $false="false";
 
375
  $result="yes";
 
376
}
 
377
save_config_data('has_true_false',$result,"TRUE and FALSE");
 
378
 
 
379
#
 
380
# Check how many connections the server can handle:
 
381
# We can't test unlimited connections, because this may take down the
 
382
# server...
 
383
#
 
384
 
 
385
$prompt="Simultaneous connections (installation default)";
 
386
print "$prompt: ";
 
387
if (defined($limits{'connections'}))
 
388
{
 
389
  print "$limits{'connections'}\n";
 
390
}
 
391
else
 
392
{
 
393
  @connect=($dbh);
 
394
 
 
395
  for ($i=1; $i < $max_connections ; $i++)
 
396
  {
 
397
    if (!($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
 
398
                          { PrintError => 0})))
 
399
    {
 
400
      print "Last connect error: $DBI::errstr\n" if ($opt_debug);
 
401
      last;
 
402
    }
 
403
    $dbh->{LongReadLen}= $longreadlen; # Set retrieval buffer
 
404
    print "." if ($opt_debug);
 
405
    push(@connect,$dbh);
 
406
  }
 
407
  print "$i\n";
 
408
  save_config_data('connections',$i,$prompt);
 
409
  foreach $dbh (@connect)
 
410
  {
 
411
    print "#" if ($opt_debug);
 
412
    $dbh->disconnect || warn $dbh->errstr;           # close connection
 
413
  }
 
414
 
 
415
  $#connect=-1;                 # Free connections
 
416
 
 
417
  if ($i == 0)
 
418
  {
 
419
    print "Can't connect to server: $DBI::errstr.  Please start it and try again\n";
 
420
    exit 1;
 
421
  }
 
422
  $dbh=safe_connect();
 
423
}
 
424
 
 
425
 
 
426
#
 
427
# Check size of communication buffer, strings...
 
428
#
 
429
 
 
430
$prompt="query size";
 
431
print "$prompt: ";
 
432
if (!defined($limits{'query_size'}))
 
433
{
 
434
  $query="select ";
 
435
  $first=64;
 
436
  $end=$max_buffer_size;
 
437
  $select= $limits{'select_without_from'} eq 'yes' ? 1 : 'a';
 
438
 
 
439
  assert($query . "$select$end_query");
 
440
 
 
441
  $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'});
 
442
 
 
443
  if ($limits{'restart'}{'tohigh'})
 
444
  {
 
445
    $end = $limits{'restart'}{'tohigh'} - 1;
 
446
    print "\nRestarting this with low limit: $first and high limit: $end\n";
 
447
    delete $limits{'restart'};
 
448
    $first=$first+int(($end-$first+4)/5);           # Prefere lower on errors
 
449
  }
 
450
  for ($i=$first ; $i < $end ; $i*=2)
 
451
  {
 
452
    last if (!safe_query($query . (" " x ($i - length($query)-length($end_query) -1)) . "$select$end_query"));
 
453
    $first=$i;
 
454
    save_config_data("restart",$i,"") if ($opt_restart);
 
455
  }
 
456
  $end=$i;
 
457
 
 
458
  if ($i < $max_buffer_size)
 
459
  {
 
460
    while ($first != $end)
 
461
    {
 
462
      $i=int(($first+$end+1)/2);
 
463
      if (safe_query($query .
 
464
                     (" " x ($i - length($query)-length($end_query) -1)) .
 
465
                     "$select$end_query"))
 
466
      {
 
467
        $first=$i;
 
468
      }
 
469
      else
 
470
      {
 
471
        $end=$i-1;
 
472
      }
 
473
    }
 
474
  }
 
475
  save_config_data('query_size',$end,$prompt);
 
476
}
 
477
$query_size=$limits{'query_size'};
 
478
 
 
479
print "$limits{'query_size'}\n";
 
480
#
 
481
# Test database types
 
482
#
 
483
 
 
484
@sql_types=("character(1)","char(1)","char varying(1)", "character varying(1)",
 
485
            "boolean",
 
486
            "varchar(1)",
 
487
            "integer","int","smallint",
 
488
            "numeric(9,2)","decimal(6,2)","dec(6,2)",
 
489
            "bit", "bit(2)","bit varying(2)","float","float(8)","real",
 
490
            "double precision", "date","time","timestamp",
 
491
            "interval year", "interval year to month",
 
492
            "interval month",
 
493
            "interval day", "interval day to hour", "interval day to minute",
 
494
            "interval day to second",
 
495
            "interval hour", "interval hour to minute", "interval hour to second",
 
496
            "interval minute", "interval minute to second",
 
497
            "interval second",
 
498
            "national character varying(20)",
 
499
            "national character(20)","nchar(1)",
 
500
            "national char varying(20)","nchar varying(20)",
 
501
            "national character varying(20)",
 
502
            "timestamp with time zone");
 
503
@odbc_types=("binary(1)","varbinary(1)","tinyint","bigint",
 
504
             "datetime");
 
505
@extra_types=("blob","byte","long varbinary","image","text","text(10)",
 
506
              "mediumtext",
 
507
              "long varchar(1)", "varchar2(257)",
 
508
              "mediumint","middleint","int unsigned",
 
509
              "int1","int2","int3","int4","int8","uint",
 
510
              "money","smallmoney","float4","float8","smallfloat",
 
511
              "float(6,2)","double",
 
512
              "enum('red')","set('red')", "int(5) zerofill", "serial",
 
513
              "char(10) binary","int not null auto_increment,unique(q)",
 
514
              "abstime","year","datetime","smalldatetime","timespan","reltime",
 
515
              # Sybase types
 
516
              "int not null identity,unique(q)",
 
517
              # postgres types
 
518
              "box","bool","circle","polygon","point","line","lseg","path",
 
519
              "interval", "serial", "inet", "cidr", "macaddr",
 
520
 
 
521
              # oracle types
 
522
              "varchar2(16)","nvarchar2(16)","number(9,2)","number(9)",
 
523
              "number", "long","raw(16)","long raw","rowid","mlslabel","clob",
 
524
              "nclob","bfile"
 
525
              );
 
526
 
 
527
@types=(["sql",\@sql_types],
 
528
        ["odbc",\@odbc_types],
 
529
        ["extra",\@extra_types]);
 
530
 
 
531
foreach $types (@types)
 
532
{
 
533
  print "\nSupported $types->[0] types\n";
 
534
  $tmp=@$types->[1];
 
535
  foreach $use_type (@$tmp)
 
536
  {
 
537
    $type=$use_type;
 
538
    $type =~ s/\(.*\)/(1 arg)/;
 
539
    if (index($use_type,",")>= 0)
 
540
    {
 
541
      $type =~ s/\(1 arg\)/(2 arg)/;
 
542
    }
 
543
    if (($tmp2=index($type,",unique")) >= 0)
 
544
    {
 
545
      $type=substr($type,0,$tmp2);
 
546
    }
 
547
    $tmp2=$type;
 
548
    $tmp2 =~ s/ /_/g;
 
549
    $tmp2 =~ s/_not_null//g;
 
550
    report("Type $type","type_$types->[0]_$tmp2",
 
551
           "create table crash_q (q $use_type)",
 
552
           "drop table crash_q");
 
553
  }
 
554
}
 
555
 
 
556
#
 
557
# Test some type limits
 
558
#
 
559
 
 
560
check_and_report("Remembers end space in char()","remember_end_space",
 
561
                 ["create table crash_q (a char(10))",
 
562
                  "insert into crash_q values('hello ')"],
 
563
                 "select a from crash_q where a = 'hello '",
 
564
                 ["drop table crash_q"],
 
565
                 'hello ',6);
 
566
 
 
567
check_and_report("Remembers end space in varchar()",
 
568
                 "remember_end_space_varchar",
 
569
                 ["create table crash_q (a varchar(10))",
 
570
                  "insert into crash_q values('hello ')"],
 
571
                 "select a from crash_q where a = 'hello '",
 
572
                 ["drop table crash_q"],
 
573
                 'hello ',6);
 
574
 
 
575
check_and_report("Supports 0000-00-00 dates","date_zero",
 
576
                 ["create table crash_me2 (a date not null)",
 
577
                  "insert into crash_me2 values ('0000-00-00')"],
 
578
                 "select a from crash_me2",
 
579
                 ["drop table crash_me2"],
 
580
                 "0000-00-00",1);
 
581
 
 
582
check_and_report("Supports 0001-01-01 dates","date_one",
 
583
                 ["create table crash_me2 (a date not null)",
 
584
                  "insert into crash_me2 values (DATE '0001-01-01')"],
 
585
                 "select a from crash_me2",
 
586
                 ["drop table crash_me2"],
 
587
                 "0001-01-01",1);
 
588
 
 
589
check_and_report("Supports 9999-12-31 dates","date_last",
 
590
                 ["create table crash_me2 (a date not null)",
 
591
                  "insert into crash_me2 values (DATE '9999-12-31')"],
 
592
                 "select a from crash_me2",
 
593
                 ["drop table crash_me2"],
 
594
                 "9999-12-31",1);
 
595
 
 
596
check_and_report("Supports 'infinity dates","date_infinity",
 
597
                 ["create table crash_me2 (a date not null)",
 
598
                  "insert into crash_me2 values ('infinity')"],
 
599
                 "select a from crash_me2",
 
600
                 ["drop table crash_me2"],
 
601
                 "infinity",1);
 
602
 
 
603
if (!defined($limits{'date_with_YY'}))
 
604
{
 
605
    check_and_report("Supports YY-MM-DD dates","date_with_YY",
 
606
                     ["create table crash_me2 (a date not null)",
 
607
                      "insert into crash_me2 values ('98-03-03')"],
 
608
                     "select a from crash_me2",
 
609
                     ["drop table crash_me2"],
 
610
                     "1998-03-03",5);
 
611
    if ($limits{'date_with_YY'} eq "yes")
 
612
    {
 
613
        undef($limits{'date_with_YY'});
 
614
        check_and_report("Supports YY-MM-DD 2000 compilant dates",
 
615
                         "date_with_YY",
 
616
                         ["create table crash_me2 (a date not null)",
 
617
                          "insert into crash_me2 values ('10-03-03')"],
 
618
                         "select a from crash_me2",
 
619
                         ["drop table crash_me2"],
 
620
                         "2010-03-03",5);
 
621
    }
 
622
}
 
623
 
 
624
if (($limits{'type_extra_float(2_arg)'} eq "yes" ||
 
625
    $limits{'type_sql_decimal(2_arg)'} eq "yes") &&
 
626
    (!defined($limits{'storage_of_float'})))
 
627
{
 
628
  my $type=$limits{'type_extra_float(2_arg)'} eq "yes" ? "float(4,1)" :
 
629
    "decimal(4,1)";
 
630
  my $result="undefined";
 
631
  if (execute_and_check(["create table crash_q (q1 $type)",
 
632
                         "insert into crash_q values(1.14)"],
 
633
                        "select q1 from crash_q",
 
634
                        ["drop table crash_q"],1.1,0) &&
 
635
      execute_and_check(["create table crash_q (q1 $type)",
 
636
                         "insert into crash_q values(1.16)"],
 
637
                        "select q1 from crash_q",
 
638
                        ["drop table crash_q"],1.1,0))
 
639
  {
 
640
    $result="truncate";
 
641
  }
 
642
  elsif (execute_and_check(["create table crash_q (q1 $type)",
 
643
                            "insert into crash_q values(1.14)"],
 
644
                           "select q1 from crash_q",
 
645
                           ["drop table crash_q"],1.1,0) &&
 
646
         execute_and_check(["create table crash_q (q1 $type)",
 
647
                            "insert into crash_q values(1.16)"],
 
648
                           "select q1 from crash_q",
 
649
                           ["drop table crash_q"],1.2,0))
 
650
  {
 
651
    $result="round";
 
652
  }
 
653
  elsif (execute_and_check(["create table crash_q (q1 $type)",
 
654
                            "insert into crash_q values(1.14)"],
 
655
                           "select q1 from crash_q",
 
656
                           ["drop table crash_q"],1.14,0) &&
 
657
         execute_and_check(["create table crash_q (q1 $type)",
 
658
                            "insert into crash_q values(1.16)"],
 
659
                           "select q1 from crash_q",
 
660
                           ["drop table crash_q"],1.16,0))
 
661
  {
 
662
    $result="exact";
 
663
  }
 
664
  $prompt="Storage of float values";
 
665
  print "$prompt: $result\n";
 
666
  save_config_data("storage_of_float", $result, $prompt);
 
667
}
 
668
 
 
669
try_and_report("Type for row id", "rowid",
 
670
               ["rowid",
 
671
                "create table crash_q (a rowid)","drop table crash_q"],
 
672
               ["auto_increment",
 
673
                "create table crash_q (a int not null auto_increment, primary key(a))","drop table crash_q"],
 
674
               ["oid",
 
675
                "create table crash_q (a oid, primary key(a))","drop table crash_q"],
 
676
               ["serial",
 
677
                "create table crash_q (a serial, primary key(a))","drop table crash_q"]);
 
678
 
 
679
try_and_report("Automatic rowid", "automatic_rowid",
 
680
               ["_rowid",
 
681
                "create table crash_q (a int not null, primary key(a))",
 
682
                "insert into crash_q values (1)",
 
683
                "select _rowid from crash_q",
 
684
                "drop table crash_q"]);
 
685
 
 
686
#
 
687
# Test functions
 
688
#
 
689
 
 
690
@sql_functions=
 
691
  (["+, -, * and /","+","5*3-4/2+1",14,0],
 
692
   ["ANSI SQL SUBSTRING","substring","substring('abcd' from 2 for 2)","bc",1],
 
693
   ["BIT_LENGTH","bit_length","bit_length('abc')",24,0],
 
694
   ["searched CASE","searched_case","case when 1 > 2 then 'false' when 2 > 1 then 'true' end", "true",1],
 
695
   ["simple CASE","simple_case","case 2 when 1 then 'false' when 2 then 'true' end", "true",1],
 
696
   ["CAST","cast","CAST(1 as CHAR)","1",1],
 
697
   ["CHARACTER_LENGTH","character_length","character_length('abcd')","4",0],
 
698
   ["CHAR_LENGTH","char_length","char_length(b)","10",0],
 
699
   ["CHAR_LENGTH(constant)","char_length(constant)","char_length('abcd')","4",0],
 
700
   ["COALESCE","coalesce","coalesce($char_null,'bcd','qwe')","bcd",1],
 
701
   ["CURRENT_DATE","current_date","current_date",0,2],
 
702
   ["CURRENT_TIME","current_time","current_time",0,2],
 
703
   ["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2],
 
704
   ["CURRENT_USER","current_user","current_user",0,2],
 
705
   ["EXTRACT","extract_sql","extract(minute from timestamp '2000-02-23 18:43:12.987')",43,0],
 
706
   ["LOCALTIME","localtime","localtime",0,2],
 
707
   ["LOCALTIMESTAMP","localtimestamp","localtimestamp",0,2],
 
708
   ["LOWER","lower","LOWER('ABC')","abc",1],
 
709
   ["NULLIF with strings","nullif_string","NULLIF(NULLIF('first','second'),'first')",undef(),4],
 
710
   ["NULLIF with numbers","nullif_num","NULLIF(NULLIF(1,2),1)",undef(),4],
 
711
   ["OCTET_LENGTH","octet_length","octet_length('abc')",3,0],
 
712
   ["POSITION","position","position('ll' in 'hello')",3,0],
 
713
   ["SESSION_USER","session_user","session_user",0,2],
 
714
   ["SYSTEM_USER","system_user","system_user",0,2],
 
715
   ["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",3],
 
716
   ["UPPER","upper","UPPER('abc')","ABC",1],
 
717
   ["USER","user","user"],
 
718
   ["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1],
 
719
   );
 
720
 
 
721
@odbc_functions=
 
722
  (["ASCII", "ascii", "ASCII('A')","65",0],
 
723
   ["CHAR", "char", "CHAR(65)"  ,"A",1],
 
724
   ["CONCAT(2 arg)","concat", "concat('a','b')","ab",1],
 
725
   ["DIFFERENCE()","difference","difference('abc','abe')",0,2],
 
726
   ["INSERT","insert","insert('abcd',2,2,'ef')","aefd",1],
 
727
   ["LEFT","left","left('abcd',2)","ab",1],
 
728
   ["LTRIM","ltrim","ltrim('   abcd')","abcd",1],
 
729
   ["REAL LENGTH","length","length('abcd ')","5",0],
 
730
   ["ODBC LENGTH","length_without_space","length('abcd ')","4",0],
 
731
   ["LOCATE(2 arg)","locate_2","locate('bcd','abcd')","2",0],
 
732
   ["LOCATE(3 arg)","locate_3","locate('bcd','abcd',3)","0",0],
 
733
   ["LCASE","lcase","lcase('ABC')","abc",1],
 
734
   ["REPEAT","repeat","repeat('ab',3)","ababab",1],
 
735
   ["REPLACE","replace","replace('abbaab','ab','ba')","bababa",1],
 
736
   ["RIGHT","right","right('abcd',2)","cd",1],
 
737
   ["RTRIM","rtrim","rtrim(' abcd  ')"," abcd",1],
 
738
   ["SPACE","space","space(5)","     ",3],
 
739
   ["SOUNDEX","soundex","soundex('hello')",0,2],
 
740
   ["ODBC SUBSTRING","substring","substring('abcd',3,2)","cd",1],
 
741
   ["UCASE","ucase","ucase('abc')","ABC",1],
 
742
 
 
743
   ["ABS","abs","abs(-5)",5,0],
 
744
   ["ACOS","acos","acos(0)","1.570796",0],
 
745
   ["ASIN","asin","asin(1)","1.570796",0],
 
746
   ["ATAN","atan","atan(1)","0.785398",0],
 
747
   ["ATAN2","atan2","atan2(1,0)","1.570796",0],
 
748
   ["CEILING","ceiling","ceiling(-4.5)",-4,0],
 
749
   ["COS","cos","cos(0)","1.00000",0],
 
750
   ["COT","cot","cot(1)","0.64209262",0],
 
751
   ["DEGREES","degrees","degrees(6.283185)","360",0],
 
752
   ["EXP","exp","exp(1)","2.718282",0],
 
753
   ["FLOOR","floor","floor(2.5)","2",0],
 
754
   ["LOG","log","log(2)","0.693147",0],
 
755
   ["LOG10","log10","log10(10)","1",0],
 
756
   ["MOD","mod","mod(11,7)","4",0],
 
757
   ["PI","pi","pi()","3.141593",0],
 
758
   ["POWER","power","power(2,4)","16",0],
 
759
   ["RAND","rand","rand(1)",0,2],       # Any value is acceptable
 
760
   ["RADIANS","radians","radians(360)","6.283185",0],
 
761
   ["ROUND(2 arg)","round","round(5.63,2)","5.6",0],
 
762
   ["SIGN","sign","sign(-5)",-1,0],
 
763
   ["SIN","sin","sin(1)","0.841471",0],
 
764
   ["SQRT","sqrt","sqrt(4)",2,0],
 
765
   ["TAN","tan","tan(1)","1.557408",0],
 
766
   ["TRUNCATE","truncate","truncate(18.18,-1)",10,0],
 
767
   ["NOW","now","now()",0,2],           # Any value is acceptable
 
768
   ["CURDATE","curdate","curdate()",0,2],
 
769
   ["DAYNAME","dayname","dayname(DATE '1997-02-01')","",2],
 
770
   ["MONTH","month","month(DATE '1997-02-01')","",2],
 
771
   ["MONTHNAME","monthname","monthname(DATE '1997-02-01')","",2],
 
772
   ["DAYOFMONTH","dayofmonth","dayofmonth(DATE '1997-02-01')",1,0],
 
773
   ["DAYOFWEEK","dayofweek","dayofweek(DATE '1997-02-01')",7,0],
 
774
   ["DAYOFYEAR","dayofyear","dayofyear(DATE '1997-02-01')",32,0],
 
775
   ["QUARTER","quarter","quarter(DATE '1997-02-01')",1,0],
 
776
   ["WEEK","week","week(DATE '1997-02-01')",5,0],
 
777
   ["YEAR","year","year(DATE '1997-02-01')",1997,0],
 
778
   ["CURTIME","curtime","curtime()",0,2],
 
779
   ["HOUR","hour","hour('12:13:14')",12,0],
 
780
   ["ANSI HOUR","hour_time","hour(TIME '12:13:14')",12,0],
 
781
   ["MINUTE","minute","minute('12:13:14')",13,0],
 
782
   ["SECOND","second","second('12:13:14')",14,0],
 
783
   ["TIMESTAMPADD","timestampadd",
 
784
    "timestampadd(SQL_TSI_SECOND,1,'1997-01-01 00:00:00')",
 
785
    "1997-01-01 00:00:01",1],
 
786
   ["TIMESTAMPDIFF","timestampdiff",
 
787
    "timestampdiff(SQL_TSI_SECOND,'1997-01-01 00:00:02', '1997-01-01 00:00:01')","1",0],
 
788
   ["USER()","user()","user()",0,2],
 
789
   ["DATABASE","database","database()",0,2],
 
790
   ["IFNULL","ifnull","ifnull(2,3)",2,0],
 
791
   ["ODBC syntax LEFT & RIGHT", "fn_left",
 
792
    "{ fn LEFT( { fn RIGHT('abcd',2) },1) }","c",1],
 
793
   );
 
794
 
 
795
@extra_functions=
 
796
  (
 
797
   ["& (bitwise and)",'&',"5 & 3",1,0],
 
798
   ["| (bitwise or)",'|',"1 | 2",3,0],
 
799
   ["<< and >> (bitwise shifts)",'binary_shifts',"(1 << 4) >> 2",4,0],
 
800
   ["<> in SELECT","<>","1<>1","0",0],
 
801
   ["=","=","(1=1)",1,$logical_value],
 
802
   ["~* (case insensitive compare)","~*","'hi' ~* 'HI'",1,$logical_value],
 
803
   ["ADD_MONTHS","add_months","add_months('1997-01-01',1)","1997-02-01",0], # oracle the date plus n months
 
804
   ["AND and OR in SELECT","and_or","1=1 AND 2=2",$logical_value,0],
 
805
   ["AND as '&&'",'&&',"1=1 && 2=2",$logical_value,0],
 
806
   ["ASCII_CHAR", "ascii_char", "ASCII_CHAR(65)","A",1],
 
807
   ["ASCII_CODE", "ascii_code", "ASCII_CODE('A')","65",0],
 
808
   ["ATN2","atn2","atn2(1,0)","1.570796",0],
 
809
   ["BETWEEN in SELECT","between","5 between 4 and 6",$logical_value,0],
 
810
   ["BIT_COUNT","bit_count","bit_count(5)",2,0],
 
811
   ["CEIL","ceil","ceil(-4.5)",-4,0], # oracle
 
812
   ["CHARINDEX","charindex","charindex('a','crash')",3,0],
 
813
   ["CHR", "chr", "CHR(65)"  ,"A",1], # oracle
 
814
   ["CONCAT(list)","concat_list", "concat('a','b','c','d')","abcd",1],
 
815
   ["CONVERT","convert","convert(CHAR,5)","5",1],
 
816
   ["COSH","cosh","cosh(0)","1",0], # oracle hyperbolic cosine of n.
 
817
   ["DATEADD","dateadd","dateadd(day,3,'Nov 30 1997')",0,2],
 
818
   ["DATEDIFF","datediff","datediff(month,'Oct 21 1997','Nov 30 1997')",0,2],
 
819
   ["DATENAME","datename","datename(month,'Nov 30 1997')",0,2],
 
820
   ["DATEPART","datepart","datepart(month,'July 20 1997')",0,2],
 
821
   ["DATE_FORMAT","date_format", "date_format('1997-01-02 03:04:05','M W D Y y m d h i s w')", 0,2],
 
822
   ["ELT","elt","elt(2,'ONE','TWO','THREE')","TWO",1],
 
823
   ["ENCRYPT","encrypt","encrypt('hello')",0,2],
 
824
   ["FIELD","field","field('IBM','NCA','ICL','SUN','IBM','DIGITAL')",4,0],
 
825
   ["FORMAT","format","format(1234.5555,2)","1,234.56",1],
 
826
   ["FROM_DAYS","from_days","from_days(729024)","1996-01-01",1],
 
827
   ["FROM_UNIXTIME","from_unixtime","from_unixtime(0)",0,2],
 
828
   ["GETDATE","getdate","getdate()",0,2],
 
829
   ["GREATEST","greatest","greatest('HARRY','HARRIOT','HAROLD')","HARRY",1], # oracle
 
830
   ["IF","if", "if(5,6,7)",6,0],
 
831
   ["IN on numbers in SELECT","in_num","2 in (3,2,5,9,5,1)",$logical_value,0],
 
832
   ["IN on strings in SELECT","in_str","'monty' in ('david','monty','allan')", $logical_value,0],
 
833
   ["INITCAP","initcap","initcap('the soap')","The Soap",1], # oracle Returns char, with the first letter of each word in uppercase
 
834
   ["INSTR (Oracle syntax)", "instr_oracle", "INSTR('CORPORATE FLOOR','OR',3,2)"  ,"14",0], # oracle instring
 
835
   ["INSTRB", "instrb", "INSTRB('CORPORATE FLOOR','OR',5,2)"  ,"27",0], # oracle instring in bytes
 
836
   ["INTERVAL","interval","interval(55,10,20,30,40,50,60,70,80,90,100)",5,0],
 
837
   ["LAST_DAY","last_day","last_day('1997-04-01')","1997-04-30",0], # oracle last day of month of date
 
838
   ["LAST_INSERT_ID","last_insert_id","last_insert_id()",0,2],
 
839
   ["LEAST","least","least('HARRY','HARRIOT','HAROLD')","HAROLD",1], # oracle
 
840
   ["LENGTHB","lengthb","lengthb('CANDIDE')","14",0], # oracle length in bytes
 
841
   ["LIKE ESCAPE in SELECT","like_escape","'%' like 'a%' escape 'a'",$logical_value,0],
 
842
   ["LIKE in SELECT","like","'a' like 'a%'",$logical_value,0],
 
843
   ["LN","ln","ln(95)","4.55387689",0], # oracle natural logarithm of n
 
844
   ["LOCATE as INSTR","instr","instr('hello','ll')",3,0],
 
845
   ["LOG(m,n)","log(m_n)","log(10,100)","2",0], # oracle logarithm, base m, of n
 
846
   ["LOGN","logn","logn(2)","0.693147",0], # informix
 
847
   ["LPAD","lpad","lpad('hi',4,'??')",'??hi',3],
 
848
   ["MDY","mdy","mdy(7,1,1998)","1998-07-01",0], # informix
 
849
   ["MOD as %","%","10%7","3",0],
 
850
   ["MONTHS_BETWEEN","months_between","months_between('1997-02-02','1997-01-01')","1.03225806",0], # oracle number of months between 2 dates
 
851
   ["NOT BETWEEN in SELECT","not_between","5 not between 4 and 6",0,0],
 
852
   ["NOT LIKE in SELECT","not_like","'a' not like 'a%'",0,0],
 
853
   ["NOT as '!' in SELECT","!","! 1",0,0],
 
854
   ["NOT in SELECT","not","not $false",$logical_value,0],
 
855
   ["ODBC CONVERT","odbc_convert","convert(5,SQL_CHAR)","5",1],
 
856
   ["OR as '||'",'||',"1=0 || 1=1",$logical_value,0],
 
857
   ["PASSWORD","password","password('hello')",0,2],
 
858
   ["PASTE", "paste", "paste('ABCDEFG',3,2,'1234')","AB1234EFG",1],
 
859
   ["PATINDEX","patindex","patindex('%a%','crash')",3,0],
 
860
   ["PERIOD_ADD","period_add","period_add(9602,-12)",199502,0],
 
861
   ["PERIOD_DIFF","period_diff","period_diff(199505,199404)",13,0],
 
862
   ["POW","pow","pow(3,2)",9,0],
 
863
   ["RANGE","range","range(a)","0.0",0], # informix range(a) = max(a) - min(a)
 
864
   ["REGEXP in SELECT","regexp","'a' regexp '^(a|b)*\$'",$logical_value,0],
 
865
   ["REPLICATE","replicate","replicate('a',5)","aaaaa",1],
 
866
   ["REVERSE","reverse","reverse('abcd')","dcba",1],
 
867
   ["ROOT","root","root(4)",2,0], # informix
 
868
   ["ROUND(1 arg)","round1","round(5.63)","6",0],
 
869
   ["RPAD","rpad","rpad('hi',4,'??')",'hi??',3],
 
870
   ["SEC_TO_TIME","sec_to_time","sec_to_time(5001)","01:23:21",1],
 
871
   ["SINH","sinh","sinh(1)","1.17520119",0], # oracle hyperbolic sine of n
 
872
   ["STR","str","str(123.45,5,1)",123.5,3],
 
873
   ["STRCMP","strcmp","strcmp('abc','adc')",-1,0],
 
874
   ["STUFF","stuff","stuff('abc',2,3,'xyz')",'axyz',3],
 
875
   ["SUBSTRB", "substrb", "SUBSTRB('ABCDEFG',5,4.2)"  ,"CD",1], # oracle substring with bytes
 
876
   ["SUBSTRING as MID","mid","mid('hello',3,2)","ll",1],
 
877
   ["SUBSTRING_INDEX","substring_index","substring_index('www.tcx.se','.',-2)", "tcx.se",1],
 
878
   ["SYSDATE","sysdate","sysdate()",0,2],
 
879
   ["TAIL","tail","tail('ABCDEFG',3)","EFG",0],
 
880
   ["TANH","tanh","tanh(1)","0.462117157",0], # oracle hyperbolic tangent of n
 
881
   ["TIME_TO_SEC","time_to_sec","time_to_sec('01:23:21')","5001",0],
 
882
   ["TO_DAYS","to_days","to_days(DATE '1996-01-01')",729024,0],
 
883
   ["TRANSLATE","translate","translate('abc','bc','de')",'ade',3],
 
884
   ["TRIM; Many char extension","trim_many_char","trim(':!' FROM ':abc!')","abc",3],
 
885
   ["TRIM; Substring extension","trim_substring","trim('cb' FROM 'abccb')","abc",3],
 
886
   ["TRUNC","trunc","trunc(18.18,-1)",10,0], # oracle
 
887
   ["UID","uid","uid",0,2], # oracle uid from user
 
888
   ["UNIX_TIMESTAMP","unix_timestamp","unix_timestamp()",0,2],
 
889
   ["USERENV","userenv","userenv",0,2], # oracle user enviroment
 
890
   ["VERSION","version","version()",0,2],
 
891
   ["WEEKDAY","weekday","weekday(DATE '1997-11-29')",5,0],
 
892
   ["automatic num->string convert","auto_num2string","concat('a',2)","a2",1],
 
893
   ["automatic string->num convert","auto_string2num","'1'+2",3,0],
 
894
   ["concatenation with +","concat_as_+","'abc' + 'def'","abcdef",1],
 
895
   );
 
896
 
 
897
@sql_group_functions=
 
898
  (
 
899
   ["AVG","avg","avg(a)",1,0],
 
900
   ["COUNT (*)","count_*","count(*)",1,0],
 
901
   ["COUNT column name","count_column","count(a)",1,0],
 
902
   ["COUNT(DISTINCT expr)","count_distinct","count(distinct a)",1,0],
 
903
   ["MAX on numbers","max","max(a)",1,0],
 
904
   ["MAX on strings","max_str","max(b)","a",1],
 
905
   ["MIN on numbers","min","min(a)",1,0],
 
906
   ["MIN on strings","min_str","min(b)","a",1],
 
907
   ["SUM","sum","sum(a)",1,0],
 
908
   );
 
909
 
 
910
@extra_group_functions=
 
911
  (
 
912
   ["BIT_AND",'bit_and',"bit_and(a)",1,0],
 
913
   ["BIT_OR", 'bit_or', "bit_or(a)",1,0],
 
914
   ["COUNT(DISTINCT expr,expr,...)","count_distinct_list","count(distinct a,b)",1,0],
 
915
   ["STD","std","std(a)",0,0],
 
916
   ["STDDEV","stddev","stddev(a)",0,0],
 
917
   ["VARIANCE","variance","variance(a)",0,0],
 
918
   );
 
919
 
 
920
@where_functions=
 
921
(
 
922
 ["= ALL","eq_all","b =all (select b from crash_me)",1,0],
 
923
 ["= ANY","eq_any","b =any (select b from crash_me)",1,0],
 
924
 ["= SOME","eq_some","b =some (select b from crash_me)",1,0],
 
925
 ["BETWEEN","between","5 between 4 and 6",1,0],
 
926
 ["EXISTS","exists","exists (select * from crash_me)",1,0],
 
927
 ["IN on numbers","in_num","2 in (3,2,5,9,5,1)",1,0],
 
928
 ["LIKE ESCAPE","like_escape","b like '%' escape 'a'",1,0],
 
929
 ["LIKE","like","b like 'a%'",1,0],
 
930
 ["MATCH UNIQUE","match_unique","1 match unique (select a from crash_me)",1,0],
 
931
 ["MATCH","match","1 match (select a from crash_me)",1,0],
 
932
 ["MATCHES","matches","b matcjhes 'a*'",1,0],
 
933
 ["NOT BETWEEN","not_between","7 not between 4 and 6",1,0],
 
934
 ["NOT EXISTS","not_exists","not exists (select * from crash_me where a = 2)",1,0],
 
935
 ["NOT LIKE","not_like","b not like 'b%'",1,0],
 
936
 ["NOT UNIQUE","not_unique","not unique (select * from crash_me where a = 2)",1,0],
 
937
 ["UNIQUE","unique","unique (select * from crash_me)",1,0],
 
938
 );
 
939
 
 
940
@types=(["sql",\@sql_functions,0],
 
941
        ["odbc",\@odbc_functions,0],
 
942
        ["extra",\@extra_functions,0],
 
943
        ["where",\@where_functions,0]);
 
944
 
 
945
@group_types=(["sql",\@sql_group_functions,0],
 
946
              ["extra",\@extra_group_functions,0]);
 
947
 
 
948
 
 
949
foreach $types (@types)
 
950
{
 
951
  print "\nSupported $types->[0] functions\n";
 
952
  $tmp=@$types->[1];
 
953
  foreach $type (@$tmp)
 
954
  {
 
955
    if (defined($limits{"func_$types->[0]_$type->[1]"}))
 
956
    {
 
957
      next;
 
958
    }
 
959
    if ($types->[0] eq "where")
 
960
    {
 
961
      check_and_report("Function $type->[0]","func_$types->[0]_$type->[1]",
 
962
                       [],"select a from crash_me where $type->[2]",[],
 
963
                       $type->[3],$type->[4]);
 
964
    }
 
965
    elsif ($limits{'functions'} eq 'yes')
 
966
    {
 
967
      if (($type->[2] =~ /char_length\(b\)/) && (!$end_query))
 
968
      {
 
969
        my $tmp= $type->[2];
 
970
        $tmp .= " from crash_me ";
 
971
        undef($limits{"func_$types->[0]_$type->[1]"});
 
972
        check_and_report("Function $type->[0]",
 
973
                         "func_$types->[0]_$type->[1]",
 
974
                         [],"select $tmp ",[],
 
975
                         $type->[3],$type->[4]);
 
976
      }
 
977
      else
 
978
      {
 
979
        undef($limits{"func_$types->[0]_$type->[1]"});
 
980
        $result = check_and_report("Function $type->[0]",
 
981
                            "func_$types->[0]_$type->[1]",
 
982
                            [],"select $type->[2] $end_query",[],
 
983
                            $type->[3],$type->[4]);
 
984
        if (!$result)
 
985
        {
 
986
          # check without type specifyer
 
987
          if ($type->[2] =~ /DATE /)
 
988
          {
 
989
            my $tmp= $type->[2];
 
990
            $tmp =~ s/DATE //;
 
991
            undef($limits{"func_$types->[0]_$type->[1]"});
 
992
            $result = check_and_report("Function $type->[0]",
 
993
                                  "func_$types->[0]_$type->[1]",
 
994
                                  [],"select $tmp $end_query",[],
 
995
                                  $type->[3],$type->[4]);
 
996
          }
 
997
          if (!$result)
 
998
          {
 
999
            if ($types->[0] eq "odbc" && ! ($type->[2] =~ /\{fn/))
 
1000
            {
 
1001
             my $tmp= $type->[2];
 
1002
             # Check by converting to ODBC format
 
1003
             undef($limits{"func_$types->[0]_$type->[1]"});
 
1004
             $tmp= "{fn $tmp }";
 
1005
             $tmp =~ s/('1997-\d\d-\d\d \d\d:\d\d:\d\d')/{ts $1}/g;
 
1006
             $tmp =~ s/(DATE '1997-\d\d-\d\d')/{d $1}/g;
 
1007
             $tmp =~ s/(TIME '12:13:14')/{t $1}/g;
 
1008
             $tmp =~ s/DATE //;
 
1009
             $tmp =~ s/TIME //;
 
1010
             check_and_report("Function $type->[0]",
 
1011
                              "func_$types->[0]_$type->[1]",
 
1012
                              [],"select $tmp $end_query",[],
 
1013
                              $type->[3],$type->[4]);
 
1014
            }
 
1015
          }
 
1016
        }
 
1017
      }
 
1018
    }
 
1019
  }
 
1020
}
 
1021
 
 
1022
if ($limits{'functions'} eq 'yes')
 
1023
{
 
1024
  foreach $types (@group_types)
 
1025
  {
 
1026
    print "\nSupported $types->[0] group functions\n";
 
1027
    $tmp=@$types->[1];
 
1028
    foreach $type (@$tmp)
 
1029
    {
 
1030
      check_and_report("Group function $type->[0]",
 
1031
                       "group_func_$types->[0]_$type->[1]",
 
1032
                       [],"select $type->[2],a from crash_me group by a",[],
 
1033
                       $type->[3],$type->[4]);
 
1034
    }
 
1035
  }
 
1036
  print "\n";
 
1037
  report("mixing of integer and float in expression","float_int_expr",
 
1038
         "select 1+1.0 $end_query");
 
1039
 
 
1040
  check_and_report("Is 1+NULL = NULL","null_num_expr",
 
1041
                   [],"select 1+$numeric_null $end_query",[],undef(),4);
 
1042
  $tmp=sql_concat("'a'",$char_null);
 
1043
  if (defined($tmp))
 
1044
  {
 
1045
    check_and_report("Is $tmp = NULL", "null_concat_expr", [],
 
1046
                     "select $tmp $end_query",[], undef(),4);
 
1047
  }
 
1048
  $prompt="Need to cast NULL for arithmetic";
 
1049
  save_config_data("Need_cast_for_null",
 
1050
                   ($numeric_null eq "NULL") ? "no" : "yes",
 
1051
                   $prompt);
 
1052
}
 
1053
else
 
1054
{
 
1055
  print "\n";
 
1056
}
 
1057
 
 
1058
 
 
1059
report("LIKE on numbers","like_with_number",
 
1060
       "create table crash_q (a int,b int)",
 
1061
       "insert into crash_q values(10,10)",
 
1062
       "select * from crash_q where a like '10'",
 
1063
       "drop table crash_q");
 
1064
 
 
1065
report("column LIKE column","like_with_column",
 
1066
       "create table crash_q (a char(10),b char(10))",
 
1067
       "insert into crash_q values('abc','abc')",
 
1068
       "select * from crash_q where a like b",
 
1069
       "drop table crash_q");
 
1070
 
 
1071
report("update of column= -column","NEG",
 
1072
       "create table crash_q (a integer)",
 
1073
       "insert into crash_q values(10)",
 
1074
       "update crash_q set a=-a",
 
1075
       "drop table crash_q");
 
1076
 
 
1077
if ($limits{'func_odbc_left'} eq 'yes' ||
 
1078
    $limits{'func_odbc_substring'} eq 'yes')
 
1079
{
 
1080
  my $type= ($limits{'func_odbc_left'} eq 'yes' ?
 
1081
             "left(a,4)" : "substring(a for 4)");
 
1082
 
 
1083
    check_and_report("String functions on date columns","date_as_string",
 
1084
                     ["create table crash_me2 (a date not null)",
 
1085
                      "insert into crash_me2 values ('1998-03-03')"],
 
1086
                     "select $type from crash_me2",
 
1087
                     ["drop table crash_me2"],
 
1088
                     "1998",1);
 
1089
}
 
1090
 
 
1091
 
 
1092
$tmp=sql_concat("b","b");
 
1093
if (defined($tmp))
 
1094
{
 
1095
  check_and_report("char are space filled","char_is_space_filled",
 
1096
                   [],"select $tmp from crash_me where b = 'a         '",[],
 
1097
                   'a         a         ',6);
 
1098
}
 
1099
 
 
1100
if (!defined($limits{'multi_table_update'}))
 
1101
{
 
1102
  if (check_and_report("Update with many tables","multi_table_update",
 
1103
                   ["create table crash_q (a integer,b char(10))",
 
1104
                    "insert into crash_q values(1,'c')",
 
1105
                    "update crash_q left join crash_me on crash_q.a=crash_me.a set crash_q.b=crash_me.b"],
 
1106
                   "select b from crash_q",
 
1107
                   ["drop table crash_q"],
 
1108
                   "a",1,undef(),2))
 
1109
  {
 
1110
    check_and_report("Update with many tables","multi_table_update",
 
1111
                     ["create table crash_q (a integer,b char(10))",
 
1112
                      "insert into crash_q values(1,'c')",
 
1113
                      "update crash_q,crash_me set crash_q.b=crash_me.b where crash_q.a=crash_me.a"],
 
1114
                     "select b from crash_q",
 
1115
                     ["drop table crash_q"],
 
1116
                     "a",1,
 
1117
                    1);
 
1118
  }
 
1119
}
 
1120
 
 
1121
report("DELETE FROM table1,table2...","multi_table_delete",
 
1122
       "create table crash_q (a integer,b char(10))",
 
1123
       "insert into crash_q values(1,'c')",
 
1124
       "delete crash_q.* from crash_q,crash_me where crash_q.a=crash_me.a",
 
1125
       "drop table crash_q");
 
1126
 
 
1127
check_and_report("Update with sub select","select_table_update",
 
1128
                 ["create table crash_q (a integer,b char(10))",
 
1129
                  "insert into crash_q values(1,'c')",
 
1130
                  "update crash_q set b= (select b from crash_me where crash_q.a = crash_me.a)"],
 
1131
                 "select b from crash_q",
 
1132
                 ["drop table crash_q"],
 
1133
                 "a",1);
 
1134
 
 
1135
check_and_report("Calculate 1--1","minus_neg",[],
 
1136
                 "select a--1 from crash_me",[],0,2);
 
1137
 
 
1138
report("ANSI SQL simple joins","simple_joins",
 
1139
       "select crash_me.a from crash_me, crash_me t0");
 
1140
 
 
1141
#
 
1142
# Check max string size, and expression limits
 
1143
#
 
1144
$found=undef;
 
1145
foreach $type (('mediumtext','text','text()','blob','long'))
 
1146
{
 
1147
  if ($limits{"type_extra_$type"} eq 'yes')
 
1148
  {
 
1149
    $found=$type;
 
1150
    last;
 
1151
  }
 
1152
}
 
1153
if (defined($found))
 
1154
{
 
1155
  $found =~ s/\(\)/\(%d\)/;
 
1156
  find_limit("max text or blob size","max_text_size",
 
1157
             new query_many(["create table crash_q (q $found)",
 
1158
                             "insert into crash_q values ('%s')"],
 
1159
                            "select * from crash_q","%s",
 
1160
                            ["drop table crash_q"],
 
1161
                            min($max_string_size,$limits{'query_size'}-30)));
 
1162
 
 
1163
}
 
1164
 
 
1165
# It doesn't make lots of sense to check for string lengths much bigger than
 
1166
# what can be stored...
 
1167
 
 
1168
find_limit(($prompt="constant string size in where"),"where_string_size",
 
1169
           new query_repeat([],"select a from crash_me where b <'",
 
1170
                            "","","a","","'"));
 
1171
if ($limits{'where_string_size'} == 10)
 
1172
{
 
1173
  save_config_data('where_string_size','nonstandard',$prompt);
 
1174
}
 
1175
 
 
1176
if ($limits{'select_constants'} eq 'yes')
 
1177
{
 
1178
  find_limit("constant string size in SELECT","select_string_size",
 
1179
             new query_repeat([],"select '","","","a","","'$end_query"));
 
1180
}
 
1181
 
 
1182
goto no_functions if ($limits{'functions'} ne "yes");
 
1183
 
 
1184
if ($limits{'func_odbc_repeat'} eq 'yes')
 
1185
{
 
1186
  find_limit("return string size from function","repeat_string_size",
 
1187
             new query_many([],
 
1188
                            "select repeat('a',%d) $end_query","%s",
 
1189
                            [],
 
1190
                            $max_string_size,0));
 
1191
}
 
1192
 
 
1193
$tmp=find_limit("simple expressions","max_expressions",
 
1194
                new query_repeat([],"select 1","","","+1","",$end_query,
 
1195
                                 undef(),$max_expressions));
 
1196
 
 
1197
if ($tmp > 10)
 
1198
{
 
1199
  $tmp= "(1" . ( '+1' x ($tmp-10) ) . ")";
 
1200
  find_limit("big expressions", "max_big_expressions",
 
1201
             new query_repeat([],"select 0","","","+$tmp","",$end_query,
 
1202
                              undef(),$max_big_expressions));
 
1203
}
 
1204
 
 
1205
find_limit("stacked expressions", "max_stack_expression",
 
1206
           new query_repeat([],"select 1","","","+(1",")",$end_query,
 
1207
                                undef(),$max_stacked_expressions));
 
1208
 
 
1209
no_functions:
 
1210
 
 
1211
if (!defined($limits{'max_conditions'}))
 
1212
{
 
1213
  find_limit("OR and AND in WHERE","max_conditions",
 
1214
             new query_repeat([],
 
1215
                              "select a from crash_me where a=1 and b='a'","",
 
1216
                              "", " or a=%d and b='%d'","","","",
 
1217
                              [],($query_size-42)/29,undef,2));
 
1218
  $limits{'max_conditions'}*=2;
 
1219
}
 
1220
# The 42 is the length of the constant part.
 
1221
# The 29 is the length of the variable part, plus two seven-digit numbers.
 
1222
 
 
1223
find_limit("tables in join", "join_tables",
 
1224
           new query_repeat([],
 
1225
                            "select crash_me.a",",t%d.a","from crash_me",
 
1226
                            ",crash_me t%d","","",[],$max_join_tables,undef,
 
1227
                            1));
 
1228
 
 
1229
# Different CREATE TABLE options
 
1230
 
 
1231
report("primary key in create table",'primary_key_in_create',
 
1232
       "create table crash_q (q integer not null,primary key (q))",
 
1233
       "drop table crash_q");
 
1234
 
 
1235
report("unique in create table",'unique_in_create',
 
1236
       "create table crash_q (q integer not null,unique (q))",
 
1237
       "drop table crash_q");
 
1238
 
 
1239
if ($limits{'unique_in_create'} eq 'yes')
 
1240
{
 
1241
  report("unique null in create",'unique_null_in_create',
 
1242
         "create table crash_q (q integer,unique (q))",
 
1243
         "insert into crash_q (q) values (NULL)",
 
1244
         "insert into crash_q (q) values (NULL)",
 
1245
         "insert into crash_q (q) values (1)",
 
1246
         "drop table crash_q");
 
1247
}
 
1248
 
 
1249
report("default value for column",'create_default',
 
1250
       "create table crash_q (q integer default 10 not null)",
 
1251
       "drop table crash_q");
 
1252
 
 
1253
report("default value function for column",'create_default_func',
 
1254
       "create table crash_q (q integer not null,q1 integer default (1+1)",
 
1255
       "drop table crash_q");
 
1256
 
 
1257
report("temporary tables",'tempoary_table',
 
1258
       "create temporary table crash_q (q integer not null)",
 
1259
       "drop table crash_q");
 
1260
 
 
1261
report("create table from select",'create_table_select',
 
1262
       "create table crash_q SELECT * from crash_me",
 
1263
       "drop table crash_q");
 
1264
 
 
1265
report("index in create table",'index_in_create',
 
1266
       "create table crash_q (q integer not null,index (q))",
 
1267
       "drop table crash_q");
 
1268
 
 
1269
# The following must be executed as we need the value of end_drop_keyword
 
1270
# later
 
1271
if (! defined($limits{'create_index'}) &&
 
1272
        ! defined($limits{'drop_index'}) )
 
1273
{
 
1274
  if ($res=safe_query("create index crash_q on crash_me (a)"))
 
1275
  {
 
1276
    $res="yes";
 
1277
    $drop_res="yes";
 
1278
    $end_drop_keyword="";
 
1279
    if (!safe_query("drop index crash_q"))
 
1280
    {
 
1281
      # Can't drop the standard way; Check if mSQL
 
1282
      if (safe_query("drop index crash_q from crash_me"))
 
1283
      {
 
1284
        $drop_res="with 'FROM'";        # Drop is not ANSI SQL
 
1285
        $end_drop_keyword="drop index %i from %t";
 
1286
      }
 
1287
      # else check if Access or MySQL
 
1288
      elsif (safe_query("drop index crash_q on crash_me"))
 
1289
      {
 
1290
        $drop_res="with 'ON'";  # Drop is not ANSI SQL
 
1291
        $end_drop_keyword="drop index %i on %t";
 
1292
      }
 
1293
      # else check if MS-SQL
 
1294
      elsif (safe_query("drop index crash_me.crash_q"))
 
1295
      {
 
1296
        $drop_res="with 'table.index'"; # Drop is not ANSI SQL
 
1297
        $end_drop_keyword="drop index %t.%i";
 
1298
      }
 
1299
    }
 
1300
    else
 
1301
    {
 
1302
      # Old MySQL 3.21 supports only the create index syntax
 
1303
      # This means that the second create doesn't give an error.
 
1304
      $res=safe_query(["create index crash_q on crash_me (a)",
 
1305
                     "create index crash_q on crash_me (a)",
 
1306
                     "drop index crash_q"]);
 
1307
      $res= $res ? 'ignored' : 'yes';
 
1308
    }
 
1309
  }
 
1310
  else
 
1311
  {
 
1312
    $drop_res=$res='no';
 
1313
  }
 
1314
  save_config_data('create_index',$res,"create index");
 
1315
  save_config_data('drop_index',$drop_res,"drop index");
 
1316
 
 
1317
  print "create index: $limits{'create_index'}\n";
 
1318
  print "drop index: $limits{'drop_index'}\n";
 
1319
}
 
1320
 
 
1321
# check if we can have 'NULL' as a key
 
1322
check_and_report("null in index","null_in_index",
 
1323
                 [create_table("crash_q",["a char(10)"],["(a)"]),
 
1324
                  "insert into crash_q values (NULL)"],
 
1325
                 "select * from crash_q",
 
1326
                 ["drop table crash_q"],
 
1327
                 undef(),4);
 
1328
 
 
1329
if ($limits{'unique_in_create'} eq 'yes')
 
1330
{
 
1331
  report("null in unique index",'null_in_unique',
 
1332
          create_table("crash_q",["q integer"],["unique(q)"]),
 
1333
         "insert into crash_q (q) values(NULL)",
 
1334
         "insert into crash_q (q) values(NULL)",
 
1335
         "drop table crash_q");
 
1336
}
 
1337
 
 
1338
if ($limits{'null_in_unique'} eq 'yes')
 
1339
{
 
1340
  report("null in unique index",'multi_null_in_unique',
 
1341
          create_table("crash_q",["q integer, x integer"],["unique(q)"]),
 
1342
         "insert into crash_q(x) values(1)",
 
1343
         "insert into crash_q(x) values(2)",
 
1344
         "drop table crash_q");
 
1345
}
 
1346
 
 
1347
if ($limits{'create_index'} ne 'no')
 
1348
{
 
1349
  $end_drop=$end_drop_keyword;
 
1350
  $end_drop =~ s/%i/crash_q/;
 
1351
  $end_drop =~ s/%t/crash_me/;
 
1352
  report("index on column part (extension)","index_parts",,
 
1353
         "create index crash_q on crash_me (b(5))",
 
1354
         $end_drop);
 
1355
  $end_drop=$end_drop_keyword;
 
1356
  $end_drop =~ s/%i/crash_me/;
 
1357
  $end_drop =~ s/%t/crash_me/;
 
1358
  report("different namespace for index",
 
1359
         "index_namespace",
 
1360
         "create index crash_me on crash_me (b)",
 
1361
         $end_drop);
 
1362
}
 
1363
 
 
1364
if (!report("case independent table names","table_name_case",
 
1365
            "create table crash_q (q integer)",
 
1366
            "drop table CRASH_Q"))
 
1367
{
 
1368
  safe_query("drop table crash_q");
 
1369
}
 
1370
 
 
1371
if (!report("drop table if exists","drop_if_exists",
 
1372
            "create table crash_q (q integer)",
 
1373
            "drop table if exists crash_q"))
 
1374
{
 
1375
  safe_query("drop table crash_q");
 
1376
}
 
1377
 
 
1378
report("create table if not exists","create_if_not_exists",
 
1379
       "create table crash_q (q integer)",
 
1380
       "create table if not exists crash_q (q integer)");
 
1381
safe_query("drop table crash_q");
 
1382
 
 
1383
#
 
1384
# test of different join types
 
1385
#
 
1386
 
 
1387
assert("create table crash_me2 (a integer not null,b char(10) not null, c integer)");
 
1388
assert("insert into crash_me2 (a,b,c) values (1,'b',1)");
 
1389
assert("create table crash_me3 (a integer not null,b char(10) not null)");
 
1390
assert("insert into crash_me3 (a,b) values (1,'b')");
 
1391
 
 
1392
report("inner join","inner_join",
 
1393
       "select crash_me.a from crash_me inner join crash_me2 ON crash_me.a=crash_me2.a");
 
1394
report("left outer join","left_outer_join",
 
1395
       "select crash_me.a from crash_me left join crash_me2 ON crash_me.a=crash_me2.a");
 
1396
report("natural left outer join","natural_left_outer_join",
 
1397
       "select c from crash_me natural left join crash_me2");
 
1398
report("left outer join using","left_outer_join_using",
 
1399
       "select c from crash_me left join crash_me2 using (a)");
 
1400
report("left outer join odbc style","odbc_left_outer_join",
 
1401
       "select crash_me.a from { oj crash_me left outer join crash_me2 ON crash_me.a=crash_me2.a }");
 
1402
report("right outer join","right_outer_join",
 
1403
       "select crash_me.a from crash_me right join crash_me2 ON crash_me.a=crash_me2.a");
 
1404
report("full outer join","full_outer_join",
 
1405
       "select crash_me.a from crash_me full join crash_me2 ON crash_me.a=crash_me2.a");
 
1406
report("cross join (same as from a,b)","cross_join",
 
1407
       "select crash_me.a from crash_me cross join crash_me3");
 
1408
report("natural join","natural_join",
 
1409
       "select * from crash_me natural join crash_me3");
 
1410
report("union","union",
 
1411
       "select * from crash_me union select a,b from crash_me3");
 
1412
report("union all","union_all",
 
1413
       "select * from crash_me union all select a,b from crash_me3");
 
1414
report("intersect","intersect",
 
1415
       "select * from crash_me intersect select * from crash_me3");
 
1416
report("intersect all","intersect_all",
 
1417
       "select * from crash_me intersect all select * from crash_me3");
 
1418
report("except","except",
 
1419
       "select * from crash_me except select * from crash_me3");
 
1420
report("except all","except_all",
 
1421
       "select * from crash_me except all select * from crash_me3");
 
1422
report("except","except",
 
1423
       "select * from crash_me except select * from crash_me3");
 
1424
report("except all","except_all",
 
1425
       "select * from crash_me except all select * from crash_me3");
 
1426
report("minus","minus",
 
1427
       "select * from crash_me minus select * from crash_me3"); # oracle ...
 
1428
 
 
1429
report("natural join (incompatible lists)","natural_join_incompat",
 
1430
       "select c from crash_me natural join crash_me2");
 
1431
report("union (incompatible lists)","union_incompat",
 
1432
       "select * from crash_me union select a,b from crash_me2");
 
1433
report("union all (incompatible lists)","union_all_incompat",
 
1434
       "select * from crash_me union all select a,b from crash_me2");
 
1435
report("intersect (incompatible lists)","intersect_incompat",
 
1436
       "select * from crash_me intersect select * from crash_me2");
 
1437
report("intersect all (incompatible lists)","intersect_all_incompat",
 
1438
       "select * from crash_me intersect all select * from crash_me2");
 
1439
report("except (incompatible lists)","except_incompat",
 
1440
       "select * from crash_me except select * from crash_me2");
 
1441
report("except all (incompatible lists)","except_all_incompat",
 
1442
       "select * from crash_me except all select * from crash_me2");
 
1443
report("except (incompatible lists)","except_incompat",
 
1444
       "select * from crash_me except select * from crash_me2");
 
1445
report("except all (incompatible lists)","except_all_incompat",
 
1446
       "select * from crash_me except all select * from crash_me2");
 
1447
report("minus (incompatible lists)","minus_incompat",
 
1448
       "select * from crash_me minus select * from crash_me2"); # oracle ...
 
1449
 
 
1450
assert("drop table crash_me2");
 
1451
assert("drop table crash_me3");
 
1452
 
 
1453
# somethings to be added here ....
 
1454
# FOR UNION - INTERSECT - EXCEPT -> CORRESPONDING [ BY ]
 
1455
# after subqueries:
 
1456
# >ALL | ANY | SOME - EXISTS - UNIQUE
 
1457
 
 
1458
if (report("subqueries","subqueries",
 
1459
           "select a from crash_me where crash_me.a in (select max(a) from crash_me)"))
 
1460
{
 
1461
    $tmp=new query_repeat([],"select a from crash_me","","",
 
1462
                          " where a in (select a from crash_me",")",
 
1463
                          "",[],$max_join_tables);
 
1464
    find_limit("recursive subqueries", "recursive_subqueries",$tmp);
 
1465
}
 
1466
 
 
1467
report("insert INTO ... SELECT ...","insert_select",
 
1468
       "create table crash_q (a int)",
 
1469
       "insert into crash_q (a) SELECT crash_me.a from crash_me",
 
1470
       "drop table crash_q");
 
1471
 
 
1472
report_trans("transactions","transactions",
 
1473
             [create_table("crash_q",["a integer not null"],[]),
 
1474
              "insert into crash_q values (1)"],
 
1475
             "select * from crash_q",
 
1476
             "drop table crash_q"
 
1477
            );
 
1478
 
 
1479
report("atomic updates","atomic_updates",
 
1480
       create_table("crash_q",["a integer not null"],["primary key (a)"]),
 
1481
       "insert into crash_q values (2)",
 
1482
       "insert into crash_q values (3)",
 
1483
       "insert into crash_q values (1)",
 
1484
       "update crash_q set a=a+1",
 
1485
       "drop table crash_q");
 
1486
 
 
1487
if ($limits{'atomic_updates'} eq 'yes')
 
1488
{
 
1489
  report_fail("atomic_updates_with_rollback","atomic_updates_with_rollback",
 
1490
              create_table("crash_q",["a integer not null"],
 
1491
                           ["primary key (a)"]),
 
1492
              "insert into crash_q values (2)",
 
1493
              "insert into crash_q values (3)",
 
1494
              "insert into crash_q values (1)",
 
1495
              "update crash_q set a=a+1 where a < 3",
 
1496
              "drop table crash_q");
 
1497
}
 
1498
 
 
1499
# To add with the views:
 
1500
# DROP VIEW - CREAT VIEW *** [ WITH [ CASCADE | LOCAL ] CHECK OPTION ]
 
1501
report("views","views",
 
1502
       "create view crash_q as select a from crash_me",
 
1503
       "drop view crash_q");
 
1504
 
 
1505
report("foreign key syntax","foreign_key_syntax",
 
1506
       create_table("crash_q",["a integer not null"],["primary key (a)"]),
 
1507
       create_table("crash_q2",["a integer not null",
 
1508
                                "foreign key (a) references crash_q (a)"],
 
1509
                    []),
 
1510
       "insert into crash_q values (1)",
 
1511
       "insert into crash_q2 values (1)",
 
1512
       "drop table crash_q2",
 
1513
       "drop table crash_q");
 
1514
 
 
1515
if ($limits{'foreign_key_syntax'} eq 'yes')
 
1516
{
 
1517
  report_fail("foreign keys","foreign_key",
 
1518
              create_table("crash_q",["a integer not null"],
 
1519
                           ["primary key (a)"]),
 
1520
              create_table("crash_q2",["a integer not null",
 
1521
                                       "foreign key (a) references crash_q (a)"],
 
1522
                           []),
 
1523
              "insert into crash_q values (1)",
 
1524
              "insert into crash_q2 values (2)",
 
1525
              "drop table crash_q2",
 
1526
              "drop table crash_q");
 
1527
}
 
1528
 
 
1529
report("Create SCHEMA","create_schema",
 
1530
       "create schema crash_schema create table crash_q (a int) create table crash_q2(b int)",
 
1531
       "drop schema crash_schema cascade");
 
1532
 
 
1533
if ($limits{'foreign_key'} eq 'yes')
 
1534
{
 
1535
  if ($limits{'create_schema'} eq 'yes')
 
1536
  {
 
1537
    report("Circular foreign keys","foreign_key_circular",
 
1538
           "create schema crash_schema create table crash_q (a int primary key, b int, foreign key (b) references crash_q2(a)) create table crash_q2(a int, b int, primary key(a), foreign key (b) references crash_q(a))",
 
1539
           "drop schema crash_schema cascade");
 
1540
  }
 
1541
}
 
1542
 
 
1543
report("Column constraints","constraint_check",
 
1544
       "create table crash_q (a int check (a>0))",
 
1545
       "drop table crash_q");
 
1546
 
 
1547
report("Table constraints","constraint_check_table",
 
1548
       "create table crash_q (a int ,b int, check (a>b))",
 
1549
       "drop table crash_q");
 
1550
 
 
1551
report("Named constraints","constraint_check",
 
1552
       "create table crash_q (a int ,b int, constraint abc check (a>b))",
 
1553
       "drop table crash_q");
 
1554
 
 
1555
report("NULL constraint (SyBase style)","constraint_null",
 
1556
       "create table crash_q (a int null)",
 
1557
       "drop table crash_q");
 
1558
 
 
1559
report("Triggers (ANSI SQL)","psm_trigger",
 
1560
       "create table crash_q (a int ,b int)",
 
1561
       "create trigger crash_trigger after insert on crash_q referencing new table as new_a when (localtime > time '18:00:00') begin atomic end",
 
1562
       "insert into crash_q values(1,2)",
 
1563
       "drop trigger crash_trigger",
 
1564
       "drop table crash_q");
 
1565
 
 
1566
report("PSM procedures (ANSI SQL)","psm_procedures",
 
1567
       "create table crash_q (a int,b int)",
 
1568
       "create procedure crash_proc(in a1 int, in b1 int) language sql modifies sql data begin declare c1 int; set c1 = a1 + b1; insert into crash_q(a,b) values (a1,c1); end",
 
1569
       "call crash_proc(1,10)",
 
1570
       "drop procedure crash_proc",
 
1571
       "drop table crash_q");
 
1572
 
 
1573
report("PSM modules (ANSI SQL)","psm_modules",
 
1574
       "create table crash_q (a int,b int)",
 
1575
       "create module crash_m declare procedure crash_proc(in a1 int, in b1 int) language sql modifies sql data begin declare c1 int; set c1 = a1 + b1; insert into crash_q(a,b) values (a1,c1); end; declare procedure crash_proc2(INOUT a int, in b int) contains sql set a = b + 10; end module",
 
1576
       "call crash_proc(1,10)",
 
1577
       "drop module crash_m cascade",
 
1578
       "drop table crash_q cascade");
 
1579
 
 
1580
report("PSM functions (ANSI SQL)","psm_functions",
 
1581
       "create table crash_q (a int)",
 
1582
       "create function crash_func(in a1 int, in b1 int) returns int language sql deterministic contains sql begin return a1 * b1; end",
 
1583
       "insert into crash_q values(crash_func(2,4))",
 
1584
       "select a,crash_func(a,2) from crash_q",
 
1585
       "drop function crash_func cascade",
 
1586
       "drop table crash_q");
 
1587
 
 
1588
report("Domains (ANSI SQL)","domains",
 
1589
       "create domain crash_d as varchar(10) default 'Empty' check (value <> 'abcd')",
 
1590
       "create table crash_q(a crash_d, b int)",
 
1591
       "insert into crash_q(a,b) values('xyz',10)",
 
1592
       "insert into crash_q(b) values(10)",
 
1593
       "drop table crash_q",
 
1594
       "drop domain crash_d");
 
1595
 
 
1596
 
 
1597
if (!defined($limits{'lock_tables'}))
 
1598
{
 
1599
  report("lock table","lock_tables",
 
1600
         "lock table crash_me READ",
 
1601
         "unlock tables");
 
1602
  if ($limits{'lock_tables'} eq 'no')
 
1603
  {
 
1604
    delete $limits{'lock_tables'};
 
1605
    report("lock table","lock_tables",
 
1606
           "lock table crash_me IN SHARE MODE");
 
1607
  }
 
1608
}
 
1609
 
 
1610
if (!report("many tables to drop table","multi_drop",
 
1611
           "create table crash_q (a int)",
 
1612
           "create table crash_q2 (a int)",
 
1613
           "drop table crash_q,crash_q2"))
 
1614
{
 
1615
  $dbh->do("drop table crash_q");
 
1616
  $dbh->do("drop table crash_q2");
 
1617
}
 
1618
 
 
1619
 
 
1620
report("-- as comment","comment_--",
 
1621
       "select * from crash_me -- Testing of comments");
 
1622
report("// as comment","comment_//",
 
1623
       "select * from crash_me // Testing of comments");
 
1624
report("# as comment","comment_#",
 
1625
       "select * from crash_me # Testing of comments");
 
1626
report("/* */ as comment","comment_/**/",
 
1627
       "select * from crash_me /* Testing of comments */");
 
1628
 
 
1629
#
 
1630
# Check things that fails one some servers
 
1631
#
 
1632
 
 
1633
# Empress can't insert empty strings in a char() field
 
1634
report("insert empty string","insert_empty_string",
 
1635
       create_table("crash_q",["a char(10) not null,b char(10)"],[]),
 
1636
       "insert into crash_q values ('','')",
 
1637
       "drop table crash_q");
 
1638
 
 
1639
report("Having with alias","having_with_alias",
 
1640
       create_table("crash_q",["a integer"],[]),
 
1641
       "insert into crash_q values (10)",
 
1642
       "select sum(a) as b from crash_q group by a having b > 0",
 
1643
       "drop table crash_q");
 
1644
 
 
1645
#
 
1646
# test name limits
 
1647
#
 
1648
 
 
1649
find_limit("table name length","max_table_name",
 
1650
           new query_many(["create table crash_q%s (q integer)",
 
1651
                           "insert into crash_q%s values(1)"],
 
1652
                           "select * from crash_q%s",1,
 
1653
                           ["drop table crash_q%s"],
 
1654
                           $max_name_length,7,1));
 
1655
 
 
1656
find_limit("column name length","max_column_name",
 
1657
           new query_many(["create table crash_q (q%s integer)",
 
1658
                          "insert into crash_q (q%s) values(1)"],
 
1659
                          "select q%s from crash_q",1,
 
1660
                          ["drop table crash_q"],
 
1661
                           $max_name_length,1));
 
1662
 
 
1663
if ($limits{'column_alias'} eq 'yes')
 
1664
{
 
1665
  find_limit("select alias name length","max_select_alias_name",
 
1666
           new query_many(undef,
 
1667
                          "select b as %s from crash_me",undef,
 
1668
                          undef, $max_name_length));
 
1669
}
 
1670
 
 
1671
find_limit("table alias name length","max_table_alias_name",
 
1672
           new query_many(undef,
 
1673
                          "select %s.b from crash_me %s",
 
1674
                          undef,
 
1675
                          undef, $max_name_length));
 
1676
 
 
1677
$end_drop_keyword = "drop index %i" if (!$end_drop_keyword);
 
1678
$end_drop=$end_drop_keyword;
 
1679
$end_drop =~ s/%i/crash_q%s/;
 
1680
$end_drop =~ s/%t/crash_me/;
 
1681
 
 
1682
if ($limits{'create_index'} ne 'no')
 
1683
{
 
1684
  find_limit("index name length","max_index_name",
 
1685
             new query_many(["create index crash_q%s on crash_me (a)"],
 
1686
                            undef,undef,
 
1687
                            [$end_drop],
 
1688
                            $max_name_length,7));
 
1689
}
 
1690
 
 
1691
find_limit("max char() size","max_char_size",
 
1692
           new query_many(["create table crash_q (q char(%d))",
 
1693
                           "insert into crash_q values ('%s')"],
 
1694
                          "select * from crash_q","%s",
 
1695
                          ["drop table crash_q"],
 
1696
                          min($max_string_size,$limits{'query_size'})));
 
1697
 
 
1698
if ($limits{'type_sql_varchar(1_arg)'} eq 'yes')
 
1699
{
 
1700
  find_limit("max varchar() size","max_varchar_size",
 
1701
             new query_many(["create table crash_q (q varchar(%d))",
 
1702
                             "insert into crash_q values ('%s')"],
 
1703
                            "select * from crash_q","%s",
 
1704
                            ["drop table crash_q"],
 
1705
                            min($max_string_size,$limits{'query_size'})));
 
1706
}
 
1707
 
 
1708
$found=undef;
 
1709
foreach $type (('mediumtext','text','text()','blob','long'))
 
1710
{
 
1711
  if ($limits{"type_extra_$type"} eq 'yes')
 
1712
  {
 
1713
    $found=$type;
 
1714
    last;
 
1715
  }
 
1716
}
 
1717
if (defined($found))
 
1718
{
 
1719
  $found =~ s/\(\)/\(%d\)/;
 
1720
  find_limit("max text or blob size","max_text_size",
 
1721
             new query_many(["create table crash_q (q $found)",
 
1722
                             "insert into crash_q values ('%s')"],
 
1723
                            "select * from crash_q","%s",
 
1724
                            ["drop table crash_q"],
 
1725
                            min($max_string_size,$limits{'query_size'}-30)));
 
1726
 
 
1727
}
 
1728
 
 
1729
$tmp=new query_repeat([],"create table crash_q (a integer","","",
 
1730
                      ",a%d integer","",")",["drop table crash_q"],
 
1731
                      $max_columns);
 
1732
$tmp->{'offset'}=1;
 
1733
find_limit("Columns in table","max_columns",$tmp);
 
1734
 
 
1735
# Make a field definition to be used when testing keys
 
1736
 
 
1737
$key_definitions="q0 integer not null";
 
1738
$key_fields="q0";
 
1739
for ($i=1; $i < min($limits{'max_columns'},$max_keys) ; $i++)
 
1740
{
 
1741
  $key_definitions.=",q$i integer not null";
 
1742
  $key_fields.=",q$i";
 
1743
}
 
1744
$key_values="1," x $i;
 
1745
chop($key_values);
 
1746
 
 
1747
if ($limits{'unique_in_create'} eq 'yes')
 
1748
{
 
1749
  find_limit("unique indexes","max_unique_index",
 
1750
             new query_table("create table crash_q (q integer",
 
1751
                             ",q%d integer not null,unique (q%d)",")",
 
1752
                             ["insert into crash_q (q,%f) values (1,%v)"],
 
1753
                             "select q from crash_q",1,
 
1754
                             "drop table crash_q",
 
1755
                             $max_keys,0));
 
1756
 
 
1757
  find_limit("index parts","max_index_parts",
 
1758
             new query_table("create table crash_q ($key_definitions,unique (q0",
 
1759
                             ",q%d","))",
 
1760
                             ["insert into crash_q ($key_fields) values ($key_values)"],
 
1761
                             "select q0 from crash_q",1,
 
1762
                             "drop table crash_q",
 
1763
                             $max_keys,1));
 
1764
 
 
1765
  find_limit("max index part length","max_index_part_length",
 
1766
             new query_many(["create table crash_q (q char(%d) not null,unique(q))",
 
1767
                             "insert into crash_q (q) values ('%s')"],
 
1768
                            "select q from crash_q","%s",
 
1769
                            ["drop table crash_q"],
 
1770
                            $limits{'max_char_size'},0));
 
1771
 
 
1772
  if ($limits{'type_sql_varchar(1_arg)'} eq 'yes')
 
1773
  {
 
1774
    find_limit("index varchar part length","max_index_varchar_part_length",
 
1775
             new query_many(["create table crash_q (q varchar(%d) not null,unique(q))",
 
1776
                             "insert into crash_q (q) values ('%s')"],
 
1777
                            "select q from crash_q","%s",
 
1778
                            ["drop table crash_q"],
 
1779
                            $limits{'max_varchar_size'},0));
 
1780
  }
 
1781
}
 
1782
 
 
1783
 
 
1784
if ($limits{'create_index'} ne 'no')
 
1785
{
 
1786
  if ($limits{'create_index'} eq 'ignored' ||
 
1787
      $limits{'unique_in_create'} eq 'yes')
 
1788
  {                                     # This should be true
 
1789
    save_config_data('max_index',$limits{'max_unique_index'},"max index");
 
1790
    print "indexes: $limits{'max_index'}\n";
 
1791
  }
 
1792
  else
 
1793
  {
 
1794
    if (!defined($limits{'max_index'}))
 
1795
    {
 
1796
      assert("create table crash_q ($key_definitions)");
 
1797
      for ($i=1; $i <= min($limits{'max_columns'},$max_keys) ; $i++)
 
1798
      {
 
1799
        last if (!safe_query("create index crash_q$i on crash_q (q$i)"));
 
1800
      }
 
1801
      save_config_data('max_index',$i == $max_keys ? $max_keys : $i,
 
1802
                       "max index");
 
1803
      while ( --$i > 0)
 
1804
      {
 
1805
        $end_drop=$end_drop_keyword;
 
1806
        $end_drop =~ s/%i/crash_q$i/;
 
1807
        $end_drop =~ s/%t/crash_q/;
 
1808
        assert($end_drop);
 
1809
      }
 
1810
      assert("drop table crash_q");
 
1811
    }
 
1812
    print "indexs: $limits{'max_index'}\n";
 
1813
    if (!defined($limits{'max_unique_index'}))
 
1814
    {
 
1815
      assert("create table crash_q ($key_definitions)");
 
1816
      for ($i=0; $i < min($limits{'max_columns'},$max_keys) ; $i++)
 
1817
      {
 
1818
        last if (!safe_query("create unique index crash_q$i on crash_q (q$i)"));
 
1819
      }
 
1820
      save_config_data('max_unique_index',$i == $max_keys ? $max_keys : $i,
 
1821
                       "max unique index");
 
1822
      while ( --$i >= 0)
 
1823
      {
 
1824
        $end_drop=$end_drop_keyword;
 
1825
        $end_drop =~ s/%i/crash_q$i/;
 
1826
        $end_drop =~ s/%t/crash_q/;
 
1827
        assert($end_drop);
 
1828
      }
 
1829
      assert("drop table crash_q");
 
1830
    }
 
1831
    print "unique indexes: $limits{'max_unique_index'}\n";
 
1832
    if (!defined($limits{'max_index_parts'}))
 
1833
    {
 
1834
      assert("create table crash_q ($key_definitions)");
 
1835
      $end_drop=$end_drop_keyword;
 
1836
      $end_drop =~ s/%i/crash_q1%d/;
 
1837
      $end_drop =~ s/%t/crash_q/;
 
1838
      find_limit("index parts","max_index_parts",
 
1839
                 new query_table("create index crash_q1%d on crash_q (q0",
 
1840
                                 ",q%d",")",
 
1841
                                 [],
 
1842
                                 undef,undef,
 
1843
                                 $end_drop,
 
1844
                                 $max_keys,1));
 
1845
      assert("drop table crash_q");
 
1846
    }
 
1847
    else
 
1848
    {
 
1849
      print "index parts: $limits{'max_index_parts'}\n";
 
1850
    }
 
1851
    $end_drop=$end_drop_keyword;
 
1852
    $end_drop =~ s/%i/crash_q2%d/;
 
1853
    $end_drop =~ s/%t/crash_me/;
 
1854
 
 
1855
    find_limit("index part length","max_index_part_length",
 
1856
               new query_many(["create table crash_q (q char(%d))",
 
1857
                               "create index crash_q2%d on crash_q (q)",
 
1858
                               "insert into crash_q values('%s')"],
 
1859
                              "select q from crash_q",
 
1860
                              "%s",
 
1861
                              [ $end_drop,
 
1862
                               "drop table crash_q"],
 
1863
                              min($limits{'max_char_size'},"+8192")));
 
1864
  }
 
1865
}
 
1866
 
 
1867
find_limit("index length","max_index_length",
 
1868
           new query_index_length("create table crash_q ",
 
1869
                                  "drop table crash_q",
 
1870
                                  $max_key_length));
 
1871
 
 
1872
find_limit("max table row length (without blobs)","max_row_length",
 
1873
           new query_row_length("crash_q ",
 
1874
                                "not null",
 
1875
                                "drop table crash_q",
 
1876
                                min($max_row_length,
 
1877
                                    $limits{'max_columns'}*
 
1878
                                    min($limits{'max_char_size'},255))));
 
1879
 
 
1880
find_limit("table row length with nulls (without blobs)",
 
1881
           "max_row_length_with_null",
 
1882
           new query_row_length("crash_q ",
 
1883
                                "",
 
1884
                                "drop table crash_q",
 
1885
                                $limits{'max_row_length'}*2));
 
1886
 
 
1887
find_limit("number of columns in order by","columns_in_order_by",
 
1888
           new query_many(["create table crash_q (%F)",
 
1889
                           "insert into crash_q values(%v)",
 
1890
                           "insert into crash_q values(%v)"],
 
1891
                          "select * from crash_q order by %f",
 
1892
                          undef(),
 
1893
                          ["drop table crash_q"],
 
1894
                          $max_order_by));
 
1895
 
 
1896
find_limit("number of columns in group by","columns_in_group_by",
 
1897
           new query_many(["create table crash_q (%F)",
 
1898
                           "insert into crash_q values(%v)",
 
1899
                           "insert into crash_q values(%v)"],
 
1900
                          "select %f from crash_q group by %f",
 
1901
                          undef(),
 
1902
                          ["drop table crash_q"],
 
1903
                          $max_order_by));
 
1904
 
 
1905
#
 
1906
# End of test
 
1907
#
 
1908
 
 
1909
$dbh->do("drop table crash_me");        # Remove temporary table
 
1910
 
 
1911
print "crash-me safe: $limits{'crash_me_safe'}\n";
 
1912
print "reconnected $reconnect_count times\n";
 
1913
 
 
1914
$dbh->disconnect || warn $dbh->errstr;
 
1915
save_all_config_data();
 
1916
exit 0;
 
1917
 
 
1918
sub usage
 
1919
{
 
1920
    print <<EOF;
 
1921
$0  Ver $version
 
1922
 
 
1923
This program tries to find all limits and capabilities for a SQL
 
1924
server.  As it will use the server in some 'unexpected' ways, one
 
1925
shouldn\'t have anything important running on it at the same time this
 
1926
program runs!  There is a slight chance that something unexpected may
 
1927
happen....
 
1928
 
 
1929
As all used queries are legal according to some SQL standard. any
 
1930
reasonable SQL server should be able to run this test without any
 
1931
problems.
 
1932
 
 
1933
All questions is cached in $opt_dir/'server_name'.cfg that future runs will use
 
1934
limits found in previous runs. Remove this file if you want to find the
 
1935
current limits for your version of the database server.
 
1936
 
 
1937
This program uses some table names while testing things. If you have any
 
1938
tables with the name of 'crash_me' or 'crash_qxxxx' where 'x' is a number,
 
1939
they will be deleted by this test!
 
1940
 
 
1941
$0 takes the following options:
 
1942
 
 
1943
--help or --Information
 
1944
  Shows this help
 
1945
 
 
1946
--batch-mode
 
1947
  Don\'t ask any questions, quit on errors.
 
1948
 
 
1949
--comment='some comment'
 
1950
  Add this comment to the crash-me limit file
 
1951
 
 
1952
--database='database' (Default $opt_database)
 
1953
  Create test tables in this database.
 
1954
 
 
1955
--dir='limits'
 
1956
  Save crash-me output in this directory
 
1957
 
 
1958
--debug
 
1959
  Lots of printing to help debugging if something goes wrong.
 
1960
 
 
1961
--fix-limit-file
 
1962
  Reformat the crash-me limit file.  crash-me is not run!
 
1963
 
 
1964
--force
 
1965
  Start test at once, without a warning screen and without questions.
 
1966
  This is a option for the very brave.
 
1967
  Use this in your cron scripts to test your database every night.
 
1968
 
 
1969
--log-all-queries
 
1970
  Prints all queries that are executed. Mostly used for debugging crash-me.
 
1971
 
 
1972
--log-queries-to-file='filename'
 
1973
  Log full queries to file.
 
1974
 
 
1975
--host='hostname' (Default $opt_host)
 
1976
  Run tests on this host.
 
1977
 
 
1978
--password='password'
 
1979
  Password for the current user.
 
1980
 
 
1981
--restart
 
1982
  Save states during each limit tests. This will make it possible to continue
 
1983
  by restarting with the same options if there is some bug in the DBI or
 
1984
  DBD driver that caused $0 to die!
 
1985
 
 
1986
--server='server name'  (Default $opt_server)
 
1987
  Run the test on the given server.
 
1988
  Known servers names are: Access, Adabas, AdabasD, Empress, Oracle, Informix, DB2, Mimer, mSQL, MS-SQL, MySQL, Pg, Solid or Sybase.
 
1989
  For others $0 can\'t report the server version.
 
1990
 
 
1991
--user='user_name'
 
1992
  User name to log into the SQL server.
 
1993
 
 
1994
--start-cmd='command to restart server'
 
1995
  Automaticly restarts server with this command if the server dies.
 
1996
 
 
1997
--sleep='time in seconds' (Default $opt_sleep)
 
1998
  Wait this long before restarting server.
 
1999
 
 
2000
EOF
 
2001
  exit(0);
 
2002
}
 
2003
 
 
2004
 
 
2005
sub server_info
 
2006
{
 
2007
  my ($ok,$tmp);
 
2008
  $ok=0;
 
2009
  print "\nNOTE: You should be familiar with '$0 --help' before continuing!\n\n";
 
2010
  if (lc($opt_server) eq "mysql")
 
2011
  {
 
2012
    $ok=1;
 
2013
    print <<EOF;
 
2014
This test should not crash MySQL if it was distributed together with the
 
2015
running MySQL version.
 
2016
If this is the case you can probably continue without having to worry about
 
2017
destroying something.
 
2018
EOF
 
2019
  }
 
2020
  elsif (lc($opt_server) eq "msql")
 
2021
  {
 
2022
    print <<EOF;
 
2023
This test will take down mSQL repeatedly while finding limits.
 
2024
To make this test easier, start mSQL in another terminal with something like:
 
2025
 
 
2026
while (true); do /usr/local/mSQL/bin/msql2d ; done
 
2027
 
 
2028
You should be sure that no one is doing anything important with mSQL and that
 
2029
you have privileges to restart it!
 
2030
It may take awhile to determinate the number of joinable tables, so prepare to
 
2031
wait!
 
2032
EOF
 
2033
  }
 
2034
  elsif (lc($opt_server) eq "solid")
 
2035
  {
 
2036
    print <<EOF;
 
2037
This test will take down Solid server repeatedly while finding limits.
 
2038
You should be sure that no one is doing anything important with Solid
 
2039
and that you have privileges to restart it!
 
2040
 
 
2041
If you are running Solid without logging and/or backup YOU WILL LOSE!
 
2042
Solid does not write data from the cache often enough. So if you continue
 
2043
you may lose tables and data that you entered hours ago!
 
2044
 
 
2045
Solid will also take a lot of memory running this test. You will nead
 
2046
at least 234M free!
 
2047
 
 
2048
When doing the connect test Solid server or the perl api will hang when
 
2049
freeing connections. Kill this program and restart it to continue with the
 
2050
test. You don\'t have to use --restart for this case.
 
2051
EOF
 
2052
    if (!$opt_restart)
 
2053
    {
 
2054
      print "\nWhen DBI/Solid dies you should run this program repeatedly\n";
 
2055
      print "with --restart until all tests have completed\n";
 
2056
    }
 
2057
  }
 
2058
  elsif (lc($opt_server) eq "pg")
 
2059
  {
 
2060
    print <<EOF;
 
2061
This test will crash postgreSQL when calculating the number of joinable tables!
 
2062
You should be sure that no one is doing anything important with postgreSQL
 
2063
and that you have privileges to restart it!
 
2064
EOF
 
2065
  }
 
2066
  else
 
2067
  {
 
2068
    print <<EOF;
 
2069
This test may crash $opt_server repeatedly while finding limits!
 
2070
You should be sure that no one is doing anything important with $opt_server
 
2071
and that you have privileges to restart it!
 
2072
EOF
 
2073
  }
 
2074
  print <<EOF;
 
2075
 
 
2076
Some of the tests you are about to execute may require a lot of
 
2077
memory.  Your tests WILL adversely affect system performance. It's
 
2078
not uncommon that either this crash-me test program, or the actual
 
2079
database back-end, will DIE with an out-of-memory error. So might
 
2080
any other program on your system if it requests more memory at the
 
2081
wrong time.
 
2082
 
 
2083
Note also that while crash-me tries to find limits for the database server
 
2084
it will make a lot of queries that can't be categorized as 'normal'.  It's
 
2085
not unlikely that crash-me finds some limit bug in your server so if you
 
2086
run this test you have to be prepared that your server may die during it!
 
2087
 
 
2088
We, the creators of this utility, are not responsible in any way if your
 
2089
database server unexpectedly crashes while this program tries to find the
 
2090
limitations of your server. By accepting the following question with 'yes',
 
2091
you agree to the above!
 
2092
 
 
2093
You have been warned!
 
2094
 
 
2095
EOF
 
2096
 
 
2097
  #
 
2098
  # No default reply here so no one can blame us for starting the test
 
2099
  # automaticly.
 
2100
  #
 
2101
  for (;;)
 
2102
  {
 
2103
    print "Start test (yes/no) ? ";
 
2104
    $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
 
2105
    last if ($tmp =~ /^yes$/i);
 
2106
    exit 1 if ($tmp =~ /^n/i);
 
2107
    print "\n";
 
2108
  }
 
2109
}
 
2110
 
 
2111
sub machine
 
2112
{
 
2113
  $name= `uname -s -r -m`;
 
2114
  if ($?)
 
2115
  {
 
2116
    $name= `uname -s -m`;
 
2117
  }
 
2118
  if ($?)
 
2119
  {
 
2120
    $name= `uname -s`;
 
2121
  }
 
2122
  if ($?)
 
2123
  {
 
2124
    $name= `uname`;
 
2125
  }
 
2126
  if ($?)
 
2127
  {
 
2128
    $name="unknown";
 
2129
  }
 
2130
  chomp($name); $name =~ s/[\n\r]//g;
 
2131
  return $name;
 
2132
}
 
2133
 
 
2134
 
 
2135
#
 
2136
# Help functions that we need
 
2137
#
 
2138
 
 
2139
sub safe_connect
 
2140
{
 
2141
  my ($object)=@_;
 
2142
  my ($dbh,$tmp);
 
2143
 
 
2144
  for (;;)
 
2145
  {
 
2146
    if (($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
 
2147
                           { PrintError => 0, AutoCommit => 1})))
 
2148
    {
 
2149
      $dbh->{LongReadLen}= 16000000; # Set max retrieval buffer
 
2150
      return $dbh;
 
2151
    }
 
2152
    print "Error: $DBI::errstr;  $server->{'data_source'}  - '$opt_user' - '$opt_password'\n";
 
2153
    print "I got the above error when connecting to $opt_server\n";
 
2154
    if (defined($object) && defined($object->{'limit'}))
 
2155
    {
 
2156
      print "This check was done with limit: $object->{'limit'}.\nNext check will be done with a smaller limit!\n";
 
2157
      $object=undef();
 
2158
    }
 
2159
    save_config_data('crash_me_safe','no',"crash me safe");
 
2160
    if ($opt_db_start_cmd)
 
2161
    {
 
2162
      print "Restarting the db server with:\n'$opt_db_start_cmd'\n";
 
2163
      system("$opt_db_start_cmd");
 
2164
      print "Waiting $opt_sleep seconds so the server can initialize\n";
 
2165
      sleep $opt_sleep;
 
2166
    }
 
2167
    else
 
2168
    {
 
2169
      exit(1) if ($opt_batch_mode);
 
2170
      print "Can you check/restart it so I can continue testing?\n";
 
2171
      for (;;)
 
2172
      {
 
2173
        print "Continue test (yes/no) ? [yes] ";
 
2174
        $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
 
2175
        $tmp = "yes" if ($tmp eq "");
 
2176
        last if (index("yes",$tmp) >= 0);
 
2177
        exit 1 if (index("no",$tmp) >= 0);
 
2178
        print "\n";
 
2179
      }
 
2180
    }
 
2181
  }
 
2182
}
 
2183
 
 
2184
#
 
2185
# Check if the server is upp and running. If not, ask the user to restart it
 
2186
#
 
2187
 
 
2188
sub check_connect
 
2189
{
 
2190
  my ($object)=@_;
 
2191
  my ($sth);
 
2192
  print "Checking connection\n" if ($opt_log_all_queries);
 
2193
  # The following line will not work properly with interbase
 
2194
  return if (defined($check_connect) && defined($dbh->do($check_connect)));
 
2195
  $dbh->disconnect || warn $dbh->errstr;
 
2196
  print "\nreconnecting\n" if ($opt_debug);
 
2197
  $reconnect_count++;
 
2198
  undef($dbh);
 
2199
  $dbh=safe_connect($object);
 
2200
}
 
2201
 
 
2202
#
 
2203
# print query if debugging
 
2204
#
 
2205
sub print_query
 
2206
{
 
2207
  my ($query)=@_;
 
2208
  $last_error=$DBI::errstr;
 
2209
  if ($opt_debug)
 
2210
  {
 
2211
    if (length($query) > 130)
 
2212
    {
 
2213
      $query=substr($query,0,120) . "...(" . (length($query)-120) . ")";
 
2214
    }
 
2215
    printf "\nGot error from query: '%s'\n%s\n",$query,$DBI::errstr;
 
2216
  }
 
2217
}
 
2218
 
 
2219
#
 
2220
# Do one or many queries. Return 1 if all was ok
 
2221
# Note that all rows are executed (to ensure that we execute drop table commands)
 
2222
#
 
2223
 
 
2224
sub safe_query
 
2225
{
 
2226
  my($queries)=@_;
 
2227
  my($query,$ok,$retry_ok,$retry,@tmp,$sth);
 
2228
  $ok=1;
 
2229
  if (ref($queries) ne "ARRAY")
 
2230
  {
 
2231
    push(@tmp,$queries);
 
2232
    $queries= \@tmp;
 
2233
  }
 
2234
  foreach $query (@$queries)
 
2235
  {
 
2236
    printf "query1: %-80.80s ...(%d - %d)\n",$query,length($query),$retry_limit  if ($opt_log_all_queries);
 
2237
    print LOG "$query;\n" if ($opt_log);
 
2238
    if (length($query) > $query_size)
 
2239
    {
 
2240
      $ok=0;
 
2241
      next;
 
2242
    }
 
2243
 
 
2244
    $retry_ok=0;
 
2245
    for ($retry=0; $retry < $retry_limit ; $retry++)
 
2246
    {
 
2247
      if (! ($sth=$dbh->prepare($query)))
 
2248
      {
 
2249
        print_query($query);
 
2250
        $retry=100 if (!$server->abort_if_fatal_error());
 
2251
        # Force a reconnect because of Access drop table bug!
 
2252
        if ($retry == $retry_limit-2)
 
2253
        {
 
2254
          print "Forcing disconnect to retry query\n" if ($opt_debug);
 
2255
          $dbh->disconnect || warn $dbh->errstr;
 
2256
        }
 
2257
        check_connect();        # Check that server is still up
 
2258
      }
 
2259
      else
 
2260
      {
 
2261
        if (!$sth->execute())
 
2262
        {
 
2263
          print_query($query);
 
2264
          $retry=100 if (!$server->abort_if_fatal_error());
 
2265
          # Force a reconnect because of Access drop table bug!
 
2266
          if ($retry == $retry_limit-2)
 
2267
          {
 
2268
            print "Forcing disconnect to retry query\n" if ($opt_debug);
 
2269
            $dbh->disconnect || warn $dbh->errstr;
 
2270
          }
 
2271
          check_connect();        # Check that server is still up
 
2272
        }
 
2273
        else
 
2274
        {
 
2275
          $retry = $retry_limit;
 
2276
          $retry_ok = 1;
 
2277
        }
 
2278
        $sth->finish;
 
2279
      }
 
2280
    }
 
2281
    $ok=0 if (!$retry_ok);
 
2282
    if ($query =~ /create/i && $server->reconnect_on_errors())
 
2283
    {
 
2284
      print "Forcing disconnect to retry query\n" if ($opt_debug);
 
2285
      $dbh->disconnect || warn $dbh->errstr;
 
2286
      $dbh=safe_connect();
 
2287
    }
 
2288
  }
 
2289
  return $ok;
 
2290
}
 
2291
 
 
2292
 
 
2293
#
 
2294
# Do a query on a query package object.
 
2295
#
 
2296
 
 
2297
sub limit_query
 
2298
{
 
2299
  my($object,$limit)=@_;
 
2300
  my ($query,$result,$retry,$sth);
 
2301
 
 
2302
  $query=$object->query($limit);
 
2303
  $result=safe_query($query);
 
2304
  if (!$result)
 
2305
  {
 
2306
    $object->cleanup();
 
2307
    return 0;
 
2308
  }
 
2309
  if (defined($query=$object->check_query()))
 
2310
  {
 
2311
    for ($retry=0 ; $retry < $retry_limit ; $retry++)
 
2312
    {
 
2313
      printf "query2: %-80.80s\n",$query if ($opt_log_all_queries);
 
2314
      print LOG "$query;\n" if ($opt_log);
 
2315
      if (($sth= $dbh->prepare($query)))
 
2316
      {
 
2317
        if ($sth->execute)
 
2318
        {
 
2319
          $result= $object->check($sth);
 
2320
          $sth->finish;
 
2321
          $object->cleanup();
 
2322
          return $result;
 
2323
        }
 
2324
        print_query($query);
 
2325
        $sth->finish;
 
2326
      }
 
2327
      else
 
2328
      {
 
2329
        print_query($query);
 
2330
      }
 
2331
      $retry=100 if (!$server->abort_if_fatal_error()); # No need to continue
 
2332
      if ($retry == $retry_limit-2)
 
2333
      {
 
2334
        print "Forcing discoennect to retry query\n" if ($opt_debug);
 
2335
        $dbh->disconnect || warn $dbh->errstr;
 
2336
      }
 
2337
      check_connect($object);   # Check that server is still up
 
2338
    }
 
2339
    $result=0;                  # Query failed
 
2340
  }
 
2341
  $object->cleanup();
 
2342
  return $result;               # Server couldn't handle the query
 
2343
}
 
2344
 
 
2345
 
 
2346
sub report
 
2347
{
 
2348
  my ($prompt,$limit,@queries)=@_;
 
2349
  print "$prompt: ";
 
2350
  if (!defined($limits{$limit}))
 
2351
  {
 
2352
    save_config_data($limit,safe_query(\@queries) ? "yes" : "no",$prompt);
 
2353
  }
 
2354
  print "$limits{$limit}\n";
 
2355
  return $limits{$limit} ne "no";
 
2356
}
 
2357
 
 
2358
sub report_fail
 
2359
{
 
2360
  my ($prompt,$limit,@queries)=@_;
 
2361
  print "$prompt: ";
 
2362
  if (!defined($limits{$limit}))
 
2363
  {
 
2364
    save_config_data($limit,safe_query(\@queries) ? "no" : "yes",$prompt);
 
2365
  }
 
2366
  print "$limits{$limit}\n";
 
2367
  return $limits{$limit} ne "no";
 
2368
}
 
2369
 
 
2370
 
 
2371
# Return true if one of the queries is ok
 
2372
 
 
2373
sub report_one
 
2374
{
 
2375
  my ($prompt,$limit,$queries)=@_;
 
2376
  my ($query,$res,$result);
 
2377
  print "$prompt: ";
 
2378
  if (!defined($limits{$limit}))
 
2379
  {
 
2380
    $result="no";
 
2381
    foreach $query (@$queries)
 
2382
    {
 
2383
      if (safe_query($query->[0]))
 
2384
      {
 
2385
        $result= $query->[1];
 
2386
        last;
 
2387
      }
 
2388
    }
 
2389
    save_config_data($limit,$result,$prompt);
 
2390
  }
 
2391
  print "$limits{$limit}\n";
 
2392
  return $limits{$limit} ne "no";
 
2393
}
 
2394
 
 
2395
 
 
2396
# Execute query and save result as limit value.
 
2397
 
 
2398
sub report_result
 
2399
{
 
2400
  my ($prompt,$limit,$query)=@_;
 
2401
  my($error);
 
2402
  print "$prompt: ";
 
2403
  if (!defined($limits{$limit}))
 
2404
  {
 
2405
    $error=safe_query_result($query,"1",2);
 
2406
    save_config_data($limit,$error ? "not supported" : $last_result,$prompt);
 
2407
  }
 
2408
  print "$limits{$limit}\n";
 
2409
  return $limits{$limit} ne "no";
 
2410
}
 
2411
 
 
2412
sub report_trans
 
2413
{
 
2414
  my ($prompt,$limit,$queries,$check,$clear)=@_;
 
2415
  print "$prompt: ";
 
2416
  if (!defined($limits{$limit}))
 
2417
  {
 
2418
    eval {undef($dbh->{AutoCommit})};
 
2419
    if (!$@)
 
2420
    {
 
2421
      if (safe_query(\@$queries))
 
2422
      {
 
2423
          $rc = $dbh->rollback;
 
2424
          if ($rc) {
 
2425
            $dbh->{AutoCommit} = 1;
 
2426
            if (safe_query_result($check,"","")) {
 
2427
              save_config_data($limit,"yes",$prompt);
 
2428
            }
 
2429
            safe_query($clear);
 
2430
          } else {
 
2431
            $dbh->{AutoCommit} = 1;
 
2432
            safe_query($clear);
 
2433
            save_config_data($limit,"error",$prompt);
 
2434
          }
 
2435
      } else {
 
2436
        save_config_data($limit,"error",$prompt);
 
2437
      }
 
2438
      $dbh->{AutoCommit} = 1;
 
2439
    }
 
2440
    else
 
2441
    {
 
2442
      save_config_data($limit,"no",$prompt);
 
2443
    }
 
2444
    safe_query($clear);
 
2445
  }
 
2446
  print "$limits{$limit}\n";
 
2447
  return $limits{$limit} ne "no";
 
2448
}
 
2449
 
 
2450
 
 
2451
sub check_and_report
 
2452
{
 
2453
  my ($prompt,$limit,$pre,$query,$post,$answer,$string_type,$skip_prompt,
 
2454
      $function)=@_;
 
2455
  my ($tmp);
 
2456
  $function=0 if (!defined($function));
 
2457
 
 
2458
  print "$prompt: " if (!defined($skip_prompt));
 
2459
  if (!defined($limits{$limit}))
 
2460
  {
 
2461
    $tmp=1-safe_query(\@$pre);
 
2462
    $tmp=safe_query_result($query,$answer,$string_type) if (!$tmp);
 
2463
    safe_query(\@$post);
 
2464
    if ($function == 3)         # Report error as 'no'.
 
2465
    {
 
2466
      $function=0;
 
2467
      $tmp= -$tmp;
 
2468
    }
 
2469
    if ($function == 0 ||
 
2470
        $tmp != 0 && $function == 1 ||
 
2471
        $tmp == 0 && $function== 2)
 
2472
    {
 
2473
      save_config_data($limit, $tmp == 0 ? "yes" : $tmp == 1 ? "no" : "error",
 
2474
                       $prompt);
 
2475
      print "$limits{$limit}\n";
 
2476
      return $function == 0 ? $limits{$limit} eq "yes" : 0;
 
2477
    }
 
2478
    return 1;                   # more things to check
 
2479
  }
 
2480
  print "$limits{$limit}\n";
 
2481
  return 0 if ($function);
 
2482
  return $limits{$limit} eq "yes";
 
2483
}
 
2484
 
 
2485
 
 
2486
sub try_and_report
 
2487
{
 
2488
  my ($prompt,$limit,@tests)=@_;
 
2489
  my ($tmp,$test,$type);
 
2490
 
 
2491
  print "$prompt: ";
 
2492
  if (!defined($limits{$limit}))
 
2493
  {
 
2494
    $type="no";                 # Not supported
 
2495
    foreach $test (@tests)
 
2496
    {
 
2497
      my $tmp_type= shift(@$test);
 
2498
      if (safe_query(\@$test))
 
2499
      {
 
2500
        $type=$tmp_type;
 
2501
        goto outer;
 
2502
      }
 
2503
    }
 
2504
  outer:
 
2505
    save_config_data($limit, $type, $prompt);
 
2506
  }
 
2507
  print "$limits{$limit}\n";
 
2508
  return $limits{$limit} ne "no";
 
2509
}
 
2510
 
 
2511
#
 
2512
# Just execute the query and check values;  Returns 1 if ok
 
2513
#
 
2514
 
 
2515
sub execute_and_check
 
2516
{
 
2517
  my ($pre,$query,$post,$answer,$string_type)=@_;
 
2518
  my ($tmp);
 
2519
 
 
2520
  $tmp=safe_query(\@$pre);
 
2521
  $tmp=safe_query_result($query,$answer,$string_type) == 0 if ($tmp);
 
2522
  safe_query(\@$post);
 
2523
  return $tmp;
 
2524
}
 
2525
 
 
2526
 
 
2527
# returns 0 if ok, 1 if error, -1 if wrong answer
 
2528
# Sets $last_result to value of query
 
2529
 
 
2530
sub safe_query_result
 
2531
{
 
2532
  my ($query,$answer,$result_type)=@_;
 
2533
  my ($sth,$row,$result,$retry);
 
2534
  undef($last_result);
 
2535
 
 
2536
  printf "\nquery3: %-80.80s\n",$query  if ($opt_log_all_queries);
 
2537
  print LOG "$query;\n" if ($opt_log);
 
2538
  for ($retry=0; $retry < $retry_limit ; $retry++)
 
2539
  {
 
2540
    if (!($sth=$dbh->prepare($query)))
 
2541
    {
 
2542
      print_query($query);
 
2543
      if ($server->abort_if_fatal_error())
 
2544
      {
 
2545
        check_connect();        # Check that server is still up
 
2546
        next;                   # Retry again
 
2547
      }
 
2548
      check_connect();          # Check that server is still up
 
2549
      return 1;
 
2550
    }
 
2551
    if (!$sth->execute)
 
2552
    {
 
2553
      print_query($query);
 
2554
      if ($server->abort_if_fatal_error())
 
2555
      {
 
2556
        check_connect();        # Check that server is still up
 
2557
        next;                   # Retry again
 
2558
      }
 
2559
      check_connect();          # Check that server is still up
 
2560
      return 1;
 
2561
    }
 
2562
    else
 
2563
    {
 
2564
      last;
 
2565
    }
 
2566
  }
 
2567
  if (!($row=$sth->fetchrow_arrayref))
 
2568
  {
 
2569
    print "\nquery: $query didn't return any result\n" if ($opt_debug);
 
2570
    $sth->finish;
 
2571
    return ($result_type == 8) ? 0 : 1;
 
2572
  }
 
2573
  if(result_type == 8) {
 
2574
    $sth->finish;
 
2575
    return 1;
 
2576
  }
 
2577
  $result=0;                    # Ok
 
2578
  $last_result= $row->[0];      # Save for report_result;
 
2579
  if ($result_type == 0)        # Compare numbers
 
2580
  {
 
2581
    $row->[0] =~ s/,/,/;        # Fix if ',' is used instead of '.'
 
2582
    if ($row->[0] != $answer && (abs($row->[0]- $answer)/
 
2583
                                 (abs($row->[0]) + abs($answer))) > 0.01)
 
2584
    {
 
2585
      $result=-1;
 
2586
    }
 
2587
  }
 
2588
  elsif ($result_type == 1)     # Compare where end space may differ
 
2589
  {
 
2590
    $row->[0] =~ s/\s+$//;
 
2591
    $result=-1 if ($row->[0] ne $answer);
 
2592
  }
 
2593
  elsif ($result_type == 3)     # This should be a exact match
 
2594
  {
 
2595
    $result= -1 if ($row->[0] ne $answer);
 
2596
  }
 
2597
  elsif ($result_type == 4)     # If results should be NULL
 
2598
  {
 
2599
    $result= -1 if (defined($row->[0]));
 
2600
  }
 
2601
  elsif ($result_type == 5)     # Result should have given prefix
 
2602
  {
 
2603
    $result= -1 if (length($row->[0]) < length($answer) &&
 
2604
                    substring($row->[0],1,length($answer)) ne $answer);
 
2605
  }
 
2606
  elsif ($result_type == 6)     # Exact match but ignore errors
 
2607
  {
 
2608
    $result= 1 if ($row->[0] ne $answer);
 
2609
  }
 
2610
  elsif ($result_type == 7)     # Compare against array of numbers
 
2611
  {
 
2612
    if ($row->[0] != $answer->[0])
 
2613
    {
 
2614
      $result= -1;
 
2615
    }
 
2616
    else
 
2617
    {
 
2618
      my ($value);
 
2619
      shift @$answer;
 
2620
      while (($row=$sth->fetchrow_arrayref))
 
2621
      {
 
2622
        $value=shift(@$answer);
 
2623
        if (!defined($value))
 
2624
        {
 
2625
          print "\nquery: $query returned to many results\n"
 
2626
            if ($opt_debug);
 
2627
          $result= 1;
 
2628
          last;
 
2629
        }
 
2630
        if ($row->[0] != $value)
 
2631
        {
 
2632
          $result= -1;
 
2633
          last;
 
2634
        }
 
2635
      }
 
2636
      if ($#$answer != -1)
 
2637
      {
 
2638
        print "\nquery: $query returned too few results\n"
 
2639
          if ($opt_debug);
 
2640
        $result= 1;
 
2641
      }
 
2642
    }
 
2643
  }
 
2644
  $sth->finish;
 
2645
  print "\nquery: '$query' returned '$row->[0]' instead of '$answer'\n"
 
2646
    if ($opt_debug && $result && $result_type != 7);
 
2647
  return $result;
 
2648
}
 
2649
 
 
2650
#
 
2651
# Find limit using binary search.  This is a weighed binary search that
 
2652
# will prefere lower limits to get the server to crash as few times as possible
 
2653
#
 
2654
 
 
2655
sub find_limit()
 
2656
{
 
2657
  my ($prompt,$limit,$query)=@_;
 
2658
  my ($first,$end,$i,$tmp);
 
2659
  print "$prompt: ";
 
2660
  if (defined($end=$limits{$limit}))
 
2661
  {
 
2662
    print "$end (cache)\n";
 
2663
    return $end;
 
2664
  }
 
2665
  if (defined($query->{'init'}) && !defined($end=$limits{'restart'}{'tohigh'}))
 
2666
  {
 
2667
    if (!safe_query($query->{'init'}))
 
2668
    {
 
2669
      $query->cleanup();
 
2670
      return "error";
 
2671
    }
 
2672
  }
 
2673
 
 
2674
  if (!limit_query($query,1))           # This must work
 
2675
  {
 
2676
    print "\nMaybe fatal error: Can't check '$prompt' for limit=1\nerror: $last_error\n";
 
2677
    return "error";
 
2678
  }
 
2679
 
 
2680
  $first=0;
 
2681
  $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'});
 
2682
 
 
2683
  if (defined($end=$limits{'restart'}{'tohigh'}))
 
2684
  {
 
2685
    $end--;
 
2686
    print "\nRestarting this with low limit: $first and high limit: $end\n";
 
2687
    delete $limits{'restart'};
 
2688
    $i=$first+int(($end-$first+4)/5);           # Prefere lower on errors
 
2689
  }
 
2690
  else
 
2691
  {
 
2692
    $end= $query->max_limit();
 
2693
    $i=int(($end+$first)/2);
 
2694
  }
 
2695
 
 
2696
  unless(limit_query($query,0+$end)) {
 
2697
    while ($first < $end)
 
2698
    {
 
2699
      print "." if ($opt_debug);
 
2700
      save_config_data("restart",$i,"") if ($opt_restart);
 
2701
      if (limit_query($query,$i))
 
2702
      {
 
2703
        $first=$i;
 
2704
        $i=$first+int(($end-$first+1)/2); # to be a bit faster to go up
 
2705
      }
 
2706
      else
 
2707
      {
 
2708
        $end=$i-1;
 
2709
        $i=$first+int(($end-$first+4)/5); # Prefere lower on errors
 
2710
      }
 
2711
    }
 
2712
  }
 
2713
  $end+=$query->{'offset'} if ($end && defined($query->{'offset'}));
 
2714
  if ($end >= $query->{'max_limit'} &&
 
2715
      substr($query->{'max_limit'},0,1) eq '+')
 
2716
  {
 
2717
    $end= $query->{'max_limit'};
 
2718
  }
 
2719
  print "$end\n";
 
2720
  save_config_data($limit,$end,$prompt);
 
2721
  delete $limits{'restart'};
 
2722
  return $end;
 
2723
}
 
2724
 
 
2725
#
 
2726
# Check that the query works!
 
2727
#
 
2728
 
 
2729
sub assert
 
2730
{
 
2731
  my($query)=@_;
 
2732
 
 
2733
  if (!safe_query($query))
 
2734
  {
 
2735
    $query=join("; ",@$query) if (ref($query) eq "ARRAY");
 
2736
    print "\nFatal error:\nquery: '$query'\nerror: $DBI::errstr\n";
 
2737
    exit 1;
 
2738
  }
 
2739
}
 
2740
 
 
2741
 
 
2742
sub read_config_data
 
2743
{
 
2744
  my ($key,$limit,$prompt);
 
2745
  if (-e $opt_config_file)
 
2746
  {
 
2747
    open(CONFIG_FILE,"+<$opt_config_file") ||
 
2748
      die "Can't open configure file $opt_config_file\n";
 
2749
    print "Reading old values from cache: $opt_config_file\n";
 
2750
  }
 
2751
  else
 
2752
  {
 
2753
    open(CONFIG_FILE,"+>>$opt_config_file") ||
 
2754
      die "Can't create configure file $opt_config_file: $!\n";
 
2755
  }
 
2756
  select CONFIG_FILE;
 
2757
  $|=1;
 
2758
  select STDOUT;
 
2759
  while (<CONFIG_FILE>)
 
2760
  {
 
2761
    chomp;
 
2762
    if (/^(\S+)=([^\#]*[^\#\s])\s*(\# .*)*$/)
 
2763
    {
 
2764
      $key=$1; $limit=$2 ; $prompt=$3;
 
2765
      if (!$opt_quick || $limit =~ /\d/ || $key =~ /crash_me/)
 
2766
      {
 
2767
        if ($key !~ /restart/i)
 
2768
        {
 
2769
          $limits{$key}=$limit;
 
2770
          $prompts{$key}=length($prompt) ? substr($prompt,2) : "";
 
2771
          delete $limits{'restart'};
 
2772
        }
 
2773
        else
 
2774
        {
 
2775
          $limit_changed=1;
 
2776
          if ($limit > $limits{'restart'}{'tohigh'})
 
2777
          {
 
2778
            $limits{'restart'}{'low'} = $limits{'restart'}{'tohigh'};
 
2779
          }
 
2780
          $limits{'restart'}{'tohigh'} = $limit;
 
2781
        }
 
2782
      }
 
2783
    }
 
2784
    elsif (!/^\s*$/ && !/^\#/)
 
2785
    {
 
2786
      die "Wrong config row: $_\n";
 
2787
    }
 
2788
  }
 
2789
}
 
2790
 
 
2791
 
 
2792
sub save_config_data
 
2793
{
 
2794
  my ($key,$limit,$prompt)=@_;
 
2795
  $prompts{$key}=$prompt;
 
2796
  return if (defined($limits{$key}) && $limits{$key} eq $limit);
 
2797
  if (!defined($limit) || $limit eq "")
 
2798
  {
 
2799
    die "Undefined limit for $key\n";
 
2800
  }
 
2801
  print CONFIG_FILE "$key=$limit\t# $prompt\n";
 
2802
  $limits{$key}=$limit;
 
2803
  $limit_changed=1;
 
2804
  if (($opt_restart && $limits{'operating_system'} =~ /windows/i) ||
 
2805
                       ($limits{'operating_system'} =~ /NT/))
 
2806
  {
 
2807
    # If perl crashes in windows, everything is lost (Wonder why? :)
 
2808
    close CONFIG_FILE;
 
2809
    open(CONFIG_FILE,"+>>$opt_config_file") ||
 
2810
      die "Can't reopen configure file $opt_config_file: $!\n";
 
2811
  }
 
2812
}
 
2813
 
 
2814
 
 
2815
sub save_all_config_data
 
2816
{
 
2817
  my ($key,$tmp);
 
2818
  close CONFIG_FILE;
 
2819
  return if (!$limit_changed);
 
2820
  open(CONFIG_FILE,">$opt_config_file") ||
 
2821
    die "Can't create configure file $opt_config_file: $!\n";
 
2822
  select CONFIG_FILE;
 
2823
  $|=1;
 
2824
  select STDOUT;
 
2825
  delete $limits{'restart'};
 
2826
 
 
2827
  print CONFIG_FILE "#This file is automaticly generated by crash-me $version\n\n";
 
2828
  foreach $key (sort keys %limits)
 
2829
  {
 
2830
    $tmp="$key=$limits{$key}";
 
2831
    print CONFIG_FILE $tmp . ("\t" x (int((32-min(length($tmp),32)+7)/8)+1)) .
 
2832
      "# $prompts{$key}\n";
 
2833
  }
 
2834
  close CONFIG_FILE;
 
2835
}
 
2836
 
 
2837
 
 
2838
sub check_repeat
 
2839
{
 
2840
  my ($sth,$limit)=@_;
 
2841
  my ($row);
 
2842
 
 
2843
  return 0 if (!($row=$sth->fetchrow_arrayref));
 
2844
  return (defined($row->[0]) && ('a' x $limit) eq $row->[0]) ? 1 : 0;
 
2845
}
 
2846
 
 
2847
 
 
2848
sub min
 
2849
{
 
2850
  my($min)=$_[0];
 
2851
  my($i);
 
2852
  for ($i=1 ; $i <= $#_; $i++)
 
2853
  {
 
2854
    $min=$_[$i] if ($min > $_[$i]);
 
2855
  }
 
2856
  return $min;
 
2857
}
 
2858
 
 
2859
sub sql_concat
 
2860
{
 
2861
  my ($a,$b)= @_;
 
2862
  return "$a || $b" if ($limits{'func_sql_concat_as_||'} eq 'yes');
 
2863
  return "concat($a,$b)" if ($limits{'func_odbc_concat'} eq 'yes');
 
2864
  return "$a + $b" if ($limits{'func_extra_concat_as_+'} eq 'yes');
 
2865
  return undef;
 
2866
}
 
2867
 
 
2868
#
 
2869
# Returns a list of statements to create a table in a portable manner
 
2870
# but still utilizing features in the databases.
 
2871
#
 
2872
 
 
2873
sub create_table
 
2874
{
 
2875
  my($table_name,$fields,$index) = @_;
 
2876
  my($query,$nr,$parts,@queries,@index);
 
2877
 
 
2878
  $query="create table $table_name (";
 
2879
  $nr=0;
 
2880
  foreach $field (@$fields)
 
2881
  {
 
2882
    $query.= $field . ',';
 
2883
  }
 
2884
  foreach $index (@$index)
 
2885
  {
 
2886
    $index =~ /\(([^\(]*)\)$/i;
 
2887
    $parts=$1;
 
2888
    if ($index =~ /^primary key/)
 
2889
    {
 
2890
      if ($limits{'primary_key_in_create'} eq 'yes')
 
2891
      {
 
2892
        $query.= $index . ',';
 
2893
      }
 
2894
      else
 
2895
      {
 
2896
        push(@queries,
 
2897
             "create unique index ${table_name}_prim on $table_name ($parts)");
 
2898
      }
 
2899
    }
 
2900
    elsif ($index =~ /^unique/)
 
2901
    {
 
2902
      if ($limits{'unique_in_create'} eq 'yes')
 
2903
      {
 
2904
        $query.= "unique ($parts),";
 
2905
      }
 
2906
      else
 
2907
      {
 
2908
        $nr++;
 
2909
        push(@queries,
 
2910
             "create unique index ${table_name}_$nr on $table_name ($parts)");
 
2911
 
 
2912
      }
 
2913
    }
 
2914
    else
 
2915
    {
 
2916
      if ($limits{'index_in_create'} eq 'yes')
 
2917
      {
 
2918
        $query.= "index ($parts),";
 
2919
      }
 
2920
      else
 
2921
      {
 
2922
        $nr++;
 
2923
        push(@queries,
 
2924
             "create index ${table_name}_$nr on $table_name ($1)");
 
2925
      }
 
2926
    }
 
2927
  }
 
2928
  chop($query);
 
2929
  $query.= ')';
 
2930
  unshift(@queries,$query);
 
2931
  return @queries;
 
2932
}
 
2933
 
 
2934
 
 
2935
#
 
2936
# This is used by some query packages to change:
 
2937
# %d -> limit
 
2938
# %s -> 'a' x limit
 
2939
# %v -> "1,1,1,1,1" where there are 'limit' number of ones
 
2940
# %f -> q1,q2,q3....
 
2941
# %F -> q1 integer,q2 integer,q3 integer....
 
2942
 
 
2943
sub fix_query
 
2944
{
 
2945
  my ($query,$limit)=@_;
 
2946
  my ($repeat,$i);
 
2947
 
 
2948
  return $query if !(defined($query));
 
2949
  $query =~ s/%d/$limit/g;
 
2950
  if ($query =~ /%s/)
 
2951
  {
 
2952
    $repeat= 'a' x $limit;
 
2953
    $query =~ s/%s/$repeat/g;
 
2954
  }
 
2955
  if ($query =~ /%v/)
 
2956
  {
 
2957
    $repeat= '1,' x $limit;
 
2958
    chop($repeat);
 
2959
    $query =~ s/%v/$repeat/g;
 
2960
  }
 
2961
  if ($query =~ /%f/)
 
2962
  {
 
2963
    $repeat="";
 
2964
    for ($i=1 ; $i <= $limit ; $i++)
 
2965
    {
 
2966
      $repeat.="q$i,";
 
2967
    }
 
2968
    chop($repeat);
 
2969
    $query =~ s/%f/$repeat/g;
 
2970
  }
 
2971
  if ($query =~ /%F/)
 
2972
  {
 
2973
    $repeat="";
 
2974
    for ($i=1 ; $i <= $limit ; $i++)
 
2975
    {
 
2976
      $repeat.="q$i integer,";
 
2977
    }
 
2978
    chop($repeat);
 
2979
    $query =~ s/%F/$repeat/g;
 
2980
  }
 
2981
  return $query;
 
2982
}
 
2983
 
 
2984
 
 
2985
#
 
2986
# Different query packages
 
2987
#
 
2988
 
 
2989
package query_repeat;
 
2990
 
 
2991
sub new
 
2992
{
 
2993
  my ($type,$init,$query,$add1,$add_mid,$add,$add_end,$end_query,$cleanup,
 
2994
      $max_limit, $check, $offset)=@_;
 
2995
  my $self={};
 
2996
  if (defined($init) && $#$init != -1)
 
2997
  {
 
2998
    $self->{'init'}=$init;
 
2999
  }
 
3000
  $self->{'query'}=$query;
 
3001
  $self->{'add1'}=$add1;
 
3002
  $self->{'add_mid'}=$add_mid;
 
3003
  $self->{'add'}=$add;
 
3004
  $self->{'add_end'}=$add_end;
 
3005
  $self->{'end_query'}=$end_query;
 
3006
  $self->{'cleanup'}=$cleanup;
 
3007
  $self->{'max_limit'}=(defined($max_limit) ? $max_limit : $main::query_size);
 
3008
  $self->{'check'}=$check;
 
3009
  $self->{'offset'}=$offset;
 
3010
  $self->{'printf'}= ($add =~ /%d/);
 
3011
  bless $self;
 
3012
}
 
3013
 
 
3014
sub query
 
3015
{
 
3016
  my ($self,$limit)=@_;
 
3017
  if (!$self->{'printf'})
 
3018
  {
 
3019
    return $self->{'query'} . ($self->{'add'} x $limit) .
 
3020
      ($self->{'add_end'} x $limit) . $self->{'end_query'};
 
3021
  }
 
3022
  my ($tmp,$tmp2,$tmp3,$i);
 
3023
  $tmp=$self->{'query'};
 
3024
  if ($self->{'add1'})
 
3025
  {
 
3026
    for ($i=0; $i < $limit ; $i++)
 
3027
    {
 
3028
      $tmp3 = $self->{'add1'};
 
3029
      $tmp3 =~ s/%d/$i/g;
 
3030
      $tmp  .= $tmp3;
 
3031
    }
 
3032
  }
 
3033
  $tmp .= " ".$self->{'add_mid'};
 
3034
  if ($self->{'add'})
 
3035
  {
 
3036
    for ($i=0; $i < $limit ; $i++)
 
3037
    {
 
3038
      $tmp2 = $self->{'add'};
 
3039
      $tmp2 =~ s/%d/$i/g;
 
3040
      $tmp  .= $tmp2;
 
3041
    }
 
3042
  }
 
3043
  return ($tmp .
 
3044
          ($self->{'add_end'} x $limit) . $self->{'end_query'});
 
3045
}
 
3046
 
 
3047
sub max_limit
 
3048
{
 
3049
  my ($self)=@_;
 
3050
  my $tmp;
 
3051
  $tmp=int(($main::limits{"query_size"}-length($self->{'query'})
 
3052
            -length($self->{'add_mid'})-length($self->{'end_query'}))/
 
3053
           (length($self->{'add1'})+
 
3054
           length($self->{'add'})+length($self->{'add_end'})));
 
3055
  return main::min($self->{'max_limit'},$tmp);
 
3056
}
 
3057
 
 
3058
 
 
3059
sub cleanup
 
3060
{
 
3061
  my ($self)=@_;
 
3062
  my($tmp,$statement);
 
3063
  $tmp=$self->{'cleanup'};
 
3064
  foreach $statement (@$tmp)
 
3065
  {
 
3066
    main::safe_query($statement) if (defined($statement) && length($statement));
 
3067
  }
 
3068
}
 
3069
 
 
3070
sub check
 
3071
{
 
3072
  my ($self,$sth)=@_;
 
3073
  my $check=$self->{'check'};
 
3074
  return &$check($sth,$self->{'limit'}) if (defined($check));
 
3075
  return 1;
 
3076
}
 
3077
 
 
3078
sub check_query
 
3079
{
 
3080
  return undef;
 
3081
}
 
3082
 
 
3083
 
 
3084
package query_num;
 
3085
 
 
3086
sub new
 
3087
{
 
3088
  my ($type,$query,$end_query,$cleanup,$max_limit,$check)=@_;
 
3089
  my $self={};
 
3090
  $self->{'query'}=$query;
 
3091
  $self->{'end_query'}=$end_query;
 
3092
  $self->{'cleanup'}=$cleanup;
 
3093
  $self->{'max_limit'}=$max_limit;
 
3094
  $self->{'check'}=$check;
 
3095
  bless $self;
 
3096
}
 
3097
 
 
3098
 
 
3099
sub query
 
3100
{
 
3101
  my ($self,$i)=@_;
 
3102
  $self->{'limit'}=$i;
 
3103
  return "$self->{'query'}$i$self->{'end_query'}";
 
3104
}
 
3105
 
 
3106
sub max_limit
 
3107
{
 
3108
  my ($self)=@_;
 
3109
  return $self->{'max_limit'};
 
3110
}
 
3111
 
 
3112
sub cleanup
 
3113
{
 
3114
  my ($self)=@_;
 
3115
  my($statement);
 
3116
  foreach $statement ($self->{'$cleanup'})
 
3117
  {
 
3118
    main::safe_query($statement) if (defined($statement) && length($statement));
 
3119
  }
 
3120
}
 
3121
 
 
3122
 
 
3123
sub check
 
3124
{
 
3125
  my ($self,$sth)=@_;
 
3126
  my $check=$self->{'check'};
 
3127
  return &$check($sth,$self->{'limit'}) if (defined($check));
 
3128
  return 1;
 
3129
}
 
3130
 
 
3131
sub check_query
 
3132
{
 
3133
  return undef;
 
3134
}
 
3135
 
 
3136
#
 
3137
# This package is used when testing CREATE TABLE!
 
3138
#
 
3139
 
 
3140
package query_table;
 
3141
 
 
3142
sub new
 
3143
{
 
3144
  my ($type,$query, $add, $end_query, $extra_init, $safe_query, $check,
 
3145
      $cleanup, $max_limit, $offset)=@_;
 
3146
  my $self={};
 
3147
  $self->{'query'}=$query;
 
3148
  $self->{'add'}=$add;
 
3149
  $self->{'end_query'}=$end_query;
 
3150
  $self->{'extra_init'}=$extra_init;
 
3151
  $self->{'safe_query'}=$safe_query;
 
3152
  $self->{'check'}=$check;
 
3153
  $self->{'cleanup'}=$cleanup;
 
3154
  $self->{'max_limit'}=$max_limit;
 
3155
  $self->{'offset'}=$offset;
 
3156
  bless $self;
 
3157
}
 
3158
 
 
3159
 
 
3160
sub query
 
3161
{
 
3162
  my ($self,$limit)=@_;
 
3163
  $self->{'limit'}=$limit;
 
3164
  $self->cleanup();     # Drop table before create
 
3165
 
 
3166
  my ($tmp,$tmp2,$i,$query,@res);
 
3167
  $tmp =$self->{'query'};
 
3168
  $tmp =~ s/%d/$limit/g;
 
3169
  for ($i=1; $i <= $limit ; $i++)
 
3170
  {
 
3171
    $tmp2 = $self->{'add'};
 
3172
    $tmp2 =~ s/%d/$i/g;
 
3173
    $tmp  .= $tmp2;
 
3174
  }
 
3175
  push(@res,$tmp . $self->{'end_query'});
 
3176
  $tmp=$self->{'extra_init'};
 
3177
  foreach $query (@$tmp)
 
3178
  {
 
3179
    push(@res,main::fix_query($query,$limit));
 
3180
  }
 
3181
  return \@res;
 
3182
}
 
3183
 
 
3184
 
 
3185
sub max_limit
 
3186
{
 
3187
  my ($self)=@_;
 
3188
  return $self->{'max_limit'};
 
3189
}
 
3190
 
 
3191
 
 
3192
sub check_query
 
3193
{
 
3194
  my ($self)=@_;
 
3195
  return main::fix_query($self->{'safe_query'},$self->{'limit'});
 
3196
}
 
3197
 
 
3198
sub check
 
3199
{
 
3200
  my ($self,$sth)=@_;
 
3201
  my $check=$self->{'check'};
 
3202
  return 0 if (!($row=$sth->fetchrow_arrayref));
 
3203
  if (defined($check))
 
3204
  {
 
3205
    return (defined($row->[0]) &&
 
3206
            $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0;
 
3207
  }
 
3208
  return 1;
 
3209
}
 
3210
 
 
3211
 
 
3212
# Remove table before and after create table query
 
3213
 
 
3214
sub cleanup()
 
3215
{
 
3216
  my ($self)=@_;
 
3217
  main::safe_query(main::fix_query($self->{'cleanup'},$self->{'limit'}));
 
3218
}
 
3219
 
 
3220
#
 
3221
# Package to do many queries with %d, and %s substitution
 
3222
#
 
3223
 
 
3224
package query_many;
 
3225
 
 
3226
sub new
 
3227
{
 
3228
  my ($type,$query,$safe_query,$check_result,$cleanup,$max_limit,$offset,
 
3229
      $safe_cleanup)=@_;
 
3230
  my $self={};
 
3231
  $self->{'query'}=$query;
 
3232
  $self->{'safe_query'}=$safe_query;
 
3233
  $self->{'check'}=$check_result;
 
3234
  $self->{'cleanup'}=$cleanup;
 
3235
  $self->{'max_limit'}=$max_limit;
 
3236
  $self->{'offset'}=$offset;
 
3237
  $self->{'safe_cleanup'}=$safe_cleanup;
 
3238
  bless $self;
 
3239
}
 
3240
 
 
3241
 
 
3242
sub query
 
3243
{
 
3244
  my ($self,$limit)=@_;
 
3245
  my ($queries,$query,@res);
 
3246
  $self->{'limit'}=$limit;
 
3247
  $self->cleanup() if (defined($self->{'safe_cleanup'}));
 
3248
  $queries=$self->{'query'};
 
3249
  foreach $query (@$queries)
 
3250
  {
 
3251
    push(@res,main::fix_query($query,$limit));
 
3252
  }
 
3253
  return \@res;
 
3254
}
 
3255
 
 
3256
sub check_query
 
3257
{
 
3258
  my ($self)=@_;
 
3259
  return main::fix_query($self->{'safe_query'},$self->{'limit'});
 
3260
}
 
3261
 
 
3262
sub cleanup
 
3263
{
 
3264
  my ($self)=@_;
 
3265
  my($tmp,$statement);
 
3266
  return if (!defined($self->{'cleanup'}));
 
3267
  $tmp=$self->{'cleanup'};
 
3268
  foreach $statement (@$tmp)
 
3269
  {
 
3270
    if (defined($statement) && length($statement))
 
3271
    {
 
3272
      main::safe_query(main::fix_query($statement,$self->{'limit'}));
 
3273
    }
 
3274
  }
 
3275
}
 
3276
 
 
3277
 
 
3278
sub check
 
3279
{
 
3280
  my ($self,$sth)=@_;
 
3281
  my ($check,$row);
 
3282
  return 0 if (!($row=$sth->fetchrow_arrayref));
 
3283
  $check=$self->{'check'};
 
3284
  if (defined($check))
 
3285
  {
 
3286
    return (defined($row->[0]) &&
 
3287
            $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0;
 
3288
  }
 
3289
  return 1;
 
3290
}
 
3291
 
 
3292
sub max_limit
 
3293
{
 
3294
  my ($self)=@_;
 
3295
  return $self->{'max_limit'};
 
3296
}
 
3297
 
 
3298
#
 
3299
# Used to find max supported row length
 
3300
#
 
3301
 
 
3302
package query_row_length;
 
3303
 
 
3304
sub new
 
3305
{
 
3306
  my ($type,$create,$null,$drop,$max_limit)=@_;
 
3307
  my $self={};
 
3308
  $self->{'table_name'}=$create;
 
3309
  $self->{'null'}=$null;
 
3310
  $self->{'cleanup'}=$drop;
 
3311
  $self->{'max_limit'}=$max_limit;
 
3312
  bless $self;
 
3313
}
 
3314
 
 
3315
 
 
3316
sub query
 
3317
{
 
3318
  my ($self,$limit)=@_;
 
3319
  my ($res,$values,$size,$length,$i);
 
3320
  $self->{'limit'}=$limit;
 
3321
 
 
3322
  $res="";
 
3323
  $size=main::min($main::limits{'max_char_size'},255);
 
3324
  $size = 255 if (!$size); # Safety
 
3325
  for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++)
 
3326
  {
 
3327
    $res.= "q$i char($size) $self->{'null'},";
 
3328
    $values.="'" . ('a' x $size) . "',";
 
3329
  }
 
3330
  if ($length < $limit)
 
3331
  {
 
3332
    $size=$limit-$length;
 
3333
    $res.= "q$i char($size) $self->{'null'},";
 
3334
    $values.="'" . ('a' x $size) . "',";
 
3335
  }
 
3336
  chop($res);
 
3337
  chop($values);
 
3338
  return ["create table " . $self->{'table_name'} . " ($res)",
 
3339
          "insert into " . $self->{'table_name'} . " values ($values)"];
 
3340
}
 
3341
 
 
3342
sub max_limit
 
3343
{
 
3344
  my ($self)=@_;
 
3345
  return $self->{'max_limit'};
 
3346
}
 
3347
 
 
3348
sub cleanup
 
3349
{
 
3350
  my ($self)=@_;
 
3351
  main::safe_query($self->{'cleanup'});
 
3352
}
 
3353
 
 
3354
 
 
3355
sub check
 
3356
{
 
3357
  return 1;
 
3358
}
 
3359
 
 
3360
sub check_query
 
3361
{
 
3362
  return undef;
 
3363
}
 
3364
 
 
3365
#
 
3366
# Used to find max supported index length
 
3367
#
 
3368
 
 
3369
package query_index_length;
 
3370
 
 
3371
sub new
 
3372
{
 
3373
  my ($type,$create,$drop,$max_limit)=@_;
 
3374
  my $self={};
 
3375
  $self->{'create'}=$create;
 
3376
  $self->{'cleanup'}=$drop;
 
3377
  $self->{'max_limit'}=$max_limit;
 
3378
  bless $self;
 
3379
}
 
3380
 
 
3381
 
 
3382
sub query
 
3383
{
 
3384
  my ($self,$limit)=@_;
 
3385
  my ($res,$size,$length,$i,$parts,$values);
 
3386
  $self->{'limit'}=$limit;
 
3387
 
 
3388
  $res=$parts=$values="";
 
3389
  $size=main::min($main::limits{'max_index_part_length'},$main::limits{'max_char_size'});
 
3390
  $size=1 if ($size == 0);      # Avoid infinite loop errors
 
3391
  for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++)
 
3392
  {
 
3393
    $res.= "q$i char($size) not null,";
 
3394
    $parts.= "q$i,";
 
3395
    $values.= "'" . ('a' x $size) . "',";
 
3396
  }
 
3397
  if ($length < $limit)
 
3398
  {
 
3399
    $size=$limit-$length;
 
3400
    $res.= "q$i char($size) not null,";
 
3401
    $parts.="q$i,";
 
3402
    $values.= "'" . ('a' x $size) . "',";
 
3403
  }
 
3404
  chop($parts);
 
3405
  chop($res);
 
3406
  chop($values);
 
3407
  if ($main::limits{'unique_in_create'} eq 'yes')
 
3408
  {
 
3409
    return [$self->{'create'} . "($res,unique ($parts))",
 
3410
            "insert into crash_q values($values)"];
 
3411
  }
 
3412
  return [$self->{'create'} . "($res)",
 
3413
          "create index crash_q_index on crash_q ($parts)",
 
3414
          "insert into crash_q values($values)"];
 
3415
}
 
3416
 
 
3417
sub max_limit
 
3418
{
 
3419
  my ($self)=@_;
 
3420
  return $self->{'max_limit'};
 
3421
}
 
3422
 
 
3423
sub cleanup
 
3424
{
 
3425
  my ($self)=@_;
 
3426
  main::safe_query($self->{'cleanup'});
 
3427
}
 
3428
 
 
3429
 
 
3430
sub check
 
3431
{
 
3432
  return 1;
 
3433
}
 
3434
 
 
3435
sub check_query
 
3436
{
 
3437
  return undef;
 
3438
}
 
3439
 
 
3440
 
 
3441
### TODO:
 
3442
# OID test instead of / in addition to _rowid