~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to tests/kewpie/sql-bench/crash-me

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-06-19 10:46:49 UTC
  • mfrom: (1.1.6)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20120619104649-e2l0ggd4oz3um0f4
Tags: upstream-7.1.36-stable
ImportĀ upstreamĀ versionĀ 7.1.36-stable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/perl    
 
2
# -*- perl -*-
 
3
# Copyright (C) 2000-2006 MySQL AB
 
4
#
 
5
# This library is free software; you can redistribute it and/or
 
6
# modify it under the terms of the GNU Library General Public
 
7
# License as published by the Free Software Foundation; version 2
 
8
# of the License.
 
9
#
 
10
# This library is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
# Library General Public License for more details.
 
14
#
 
15
# You should have received a copy of the GNU Library General Public
 
16
# License along with this library; if not, write to the Free
 
17
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 
18
# MA 02111-1307, USA
 
19
 
 
20
# Written by Monty for the TCX/Monty Program/Detron benchmark suite.
 
21
# Empress and PostgreSQL patches by Luuk de Boer
 
22
# Extensions for ANSI SQL and Mimer by Bengt Gunne
 
23
# Some additions and corrections by Matthias Urlich
 
24
#
 
25
# This programs tries to find all limits for a sql server
 
26
# It gets the name from what it does to most servers :)
 
27
#
 
28
# Be sure to use --help before running this!
 
29
#
 
30
# If you want to add support for another server, add a new package for the
 
31
# server in server-cfg.  You only have to support the 'new' and 'version'
 
32
# functions. new doesn't need to have any limits if one doesn't want to
 
33
# use the benchmarks.
 
34
#
 
35
 
 
36
# TODO:
 
37
# CMT includes types and functions which are synonyms for other types
 
38
# and functions, including those in SQL9x. It should label those synonyms
 
39
# as such, and clarify ones such as "mediumint" with comments such as
 
40
# "3-byte int" or "same as xxx".
 
41
 
 
42
$version="1.62";
 
43
 
 
44
use Cwd;
 
45
use DBI;
 
46
use Getopt::Long;
 
47
use POSIX;
 
48
$pwd = cwd(); $pwd = "." if ($pwd eq '');
 
49
require "$pwd/server-cfg" || die "Can't read Configuration file: $!\n";
 
50
 
 
51
our $opt_batch_mode=0;
 
52
our $opt_check_server=0;                # Check if server is alive before each query
 
53
our $opt_comment="";
 
54
our $opt_config_file="";
 
55
our $opt_connect_options="";
 
56
our $opt_database="test";
 
57
our $opt_db_start_cmd="";           # the db server start command
 
58
our $opt_debug=0;
 
59
our $opt_dir="limits";
 
60
our $opt_fix_limit_file=0;
 
61
our $opt_force=0;
 
62
our $opt_help=0;
 
63
our $opt_host="localhost"; 
 
64
our $opt_Information=0;
 
65
our $opt_log_all_queries=0;
 
66
our $opt_log_queries_to_file="";
 
67
our $opt_machine="";
 
68
our $opt_odbc="";
 
69
our $opt_password="";
 
70
our $opt_quick=0;
 
71
our $opt_restart=0;
 
72
our $opt_server="mysql"; 
 
73
our $opt_sleep=10;                  # time to sleep while starting the db server
 
74
our $opt_socket="";                  # time to sleep while starting the db server
 
75
our $opt_suffix="";
 
76
our $opt_user="";
 
77
our $opt_verbose=1;
 
78
our $opt_version=0;
 
79
 
 
80
$limit_changed=0;               # For configure file
 
81
$reconnect_count=0;
 
82
$limits{'crash_me_safe'}='yes';
 
83
$prompts{'crash_me_safe'}='crash me safe';
 
84
$limits{'operating_system'}= machine();
 
85
$prompts{'operating_system'}='crash-me tested on';
 
86
$retry_limit=3;
 
87
 
 
88
GetOptions("Information","help","server=s","debug","user=s","password=s",
 
89
"database=s","restart","force","quick","log-all-queries","comment=s",
 
90
"host=s","fix-limit-file","dir=s","db-start-cmd=s","sleep=s","suffix=s",
 
91
"batch-mode","config-file=s","log-queries-to-file=s","check-server",
 
92
"version", "connect-options=s", "machine=s", "socket=s",
 
93
"verbose!" => \$opt_verbose) || usage();
 
94
 
 
95
#
 
96
# Find limit using binary search.  This is a weighed binary search that
 
97
# will prefere lower limits to get the server to crash as 
 
98
# few times as possible
 
99
sub find_limit
 
100
{
 
101
  my ($prompt,$limit,$query)=@_;
 
102
  my ($first,$end,$i,$tmp,@tmp_array, $queries);
 
103
  print "$prompt: ";
 
104
  if (defined($end=$limits{$limit}))
 
105
  {
 
106
    print "$end (cache)\n";
 
107
    return $end;
 
108
  }
 
109
  save_incomplete($limit,$prompt);
 
110
  add_log($limit,"We are trying (example with N=5):");
 
111
  $queries = $query->query(5);
 
112
  if (ref($queries) ne "ARRAY")
 
113
  {
 
114
    push(@tmp_array,$queries);
 
115
    $queries= \@tmp_array;
 
116
  }
 
117
  foreach $tmp (@$queries)
 
118
  {   add_log($limit,repr_query($tmp));  }    
 
119
 
 
120
  if (defined($queries = $query->check_query()))
 
121
  { 
 
122
    if (ref($queries) ne "ARRAY")
 
123
    {
 
124
      @tmp_array=();
 
125
      push(@tmp_array,$queries); 
 
126
      $queries= \@tmp_array;
 
127
    }
 
128
    foreach $tmp (@$queries)
 
129
      {   add_log($limit,repr_query($tmp));  }    
 
130
  }
 
131
  if (defined($query->{'init'}) && !defined($end=$limits{'restart'}{'tohigh'}))
 
132
  {
 
133
    if (!safe_query_l($limit,$query->{'init'}))
 
134
    {
 
135
      $query->cleanup();
 
136
      return "error";
 
137
    }
 
138
  }
 
139
 
 
140
  if (!limit_query($query,1))           # This must work
 
141
  {
 
142
    print "\nMaybe fatal error: Can't check '$prompt' for limit=1\n".
 
143
    "error: $last_error\n";
 
144
    return "error";
 
145
  }
 
146
 
 
147
  $first=0;
 
148
  $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'});
 
149
 
 
150
  if (defined($end=$limits{'restart'}{'tohigh'}))
 
151
  {
 
152
    $end--;
 
153
    print "\nRestarting this with low limit: $first and high limit: $end\n";
 
154
    delete $limits{'restart'};
 
155
    $i=$first+int(($end-$first+4)/5);           # Prefere lower on errors
 
156
  }
 
157
  else
 
158
  {
 
159
    $end= $query->max_limit();
 
160
    $i=int(($end+$first)/2);
 
161
  }
 
162
  my $log_str = "";
 
163
  unless(limit_query($query,0+$end)) {
 
164
    while ($first < $end)
 
165
    {
 
166
      print "." if ($opt_debug);
 
167
      save_config_data("restart",$i,"") if ($opt_restart);
 
168
      if (limit_query($query,$i))
 
169
      {
 
170
        $first=$i;
 
171
        $log_str .= " $i:OK";
 
172
        $i=$first+int(($end-$first+1)/2); # to be a bit faster to go up
 
173
      }
 
174
      else
 
175
      { 
 
176
        $end=$i-1;
 
177
        $log_str .= " $i:FAIL";
 
178
        $i=$first+int(($end-$first+4)/5); # Prefere lower on errors
 
179
      }
 
180
    }
 
181
  }
 
182
  $end+=$query->{'offset'} if ($end && defined($query->{'offset'}));
 
183
  if ($end >= $query->{'max_limit'} &&
 
184
      substr($query->{'max_limit'},0,1) eq '+')
 
185
  {
 
186
    $end= $query->{'max_limit'};
 
187
  }
 
188
  print "$end\n";
 
189
  add_log($limit,$log_str);
 
190
  save_config_data($limit,$end,$prompt);
 
191
  delete $limits{'restart'};
 
192
  return $end;
 
193
}
 
194
 
 
195
usage() if ($opt_help || $opt_Information);
 
196
 
 
197
version() && exit(0) if ($opt_version);
 
198
 
 
199
$opt_suffix = '-'.$opt_suffix if (length($opt_suffix) != 0);
 
200
$opt_config_file = "$pwd/$opt_dir/$opt_server$opt_suffix.cfg"
 
201
  if (length($opt_config_file) == 0);
 
202
$safe_query_log='';
 
203
$safe_query_result_log='';
 
204
$log{"crash-me"}="";
 
205
 
 
206
#!!!
 
207
 
 
208
if ($opt_fix_limit_file)
 
209
{
 
210
  print "Fixing limit file for $opt_server\n";
 
211
  read_config_data();
 
212
  $limit_changed=1;
 
213
  save_all_config_data();
 
214
  exit 0;
 
215
}
 
216
 
 
217
$server=get_server($opt_server,$opt_host,$opt_database,$opt_odbc, machine_part(), $opt_socket, $opt_connect_options);
 
218
$opt_server=$server->{'cmp_name'};
 
219
 
 
220
$|=1;                           # For debugging
 
221
 
 
222
print "Running $0 $version on '",($server_version=$server->version()),"'\n\n";
 
223
print "I hope you didn't have anything important running on this server....\n";
 
224
read_config_data();
 
225
if ($limit_changed)             # Must have been restarted
 
226
{
 
227
  save_config_data('crash_me_safe','no',"crash me safe");
 
228
}
 
229
 
 
230
if (!$opt_force && !$opt_batch_mode)
 
231
{
 
232
  server_info();
 
233
}
 
234
else
 
235
{
 
236
  print "Using --force.  I assume you know what you are doing...\n";
 
237
}
 
238
print "\n";
 
239
 
 
240
save_config_data('crash_me_version',$version,"crash me version");
 
241
if ($server_version)
 
242
{
 
243
  save_config_data('server_version',$server_version,"server version");
 
244
}
 
245
if (length($opt_comment))
 
246
{
 
247
  save_config_data('user_comment',$opt_comment,"comment");
 
248
}
 
249
 
 
250
$opt_log=0;
 
251
if (length($opt_log_queries_to_file))
 
252
{
 
253
  open(LOG,">$opt_log_queries_to_file") || 
 
254
    die "Can't open file $opt_log_queries_to_file\n";
 
255
  $opt_log=1;
 
256
}
 
257
 
 
258
#
 
259
# Set up some limits that's regared as unlimited
 
260
# We don't want to take up all resources from the server...
 
261
#
 
262
 
 
263
$max_connections="+1000";       # Number of simultaneous connections
 
264
$max_buffer_size="+16000000";   # size of communication buffer.
 
265
$max_string_size="+8000000";    # Enough for this test
 
266
$max_name_length="+512";        # Actually 256, but ...
 
267
$max_keys="+64";                # Probably too big.
 
268
$max_join_tables="+64";         # Probably too big.
 
269
$max_columns="+8192";           # Probably too big.
 
270
$max_row_length=$max_string_size;
 
271
$max_key_length="+8192";        # Big enough
 
272
$max_order_by="+64";            # Big enough
 
273
$max_expressions="+10000";
 
274
$max_big_expressions="+100";
 
275
$max_stacked_expressions="+2000";
 
276
$query_size=$max_buffer_size;
 
277
$longreadlen=16000000;          # For retrieval buffer
 
278
 
 
279
 
 
280
#
 
281
# First do some checks that needed for the rest of the benchmark
 
282
#
 
283
use sigtrap;                   # Must be removed with perl5.005_2 on Win98
 
284
$SIG{PIPE} = 'IGNORE';
 
285
$problem_counter=0;
 
286
$SIG{SEGV} = sub {
 
287
  $problem_counter +=1;
 
288
  if ($problem_counter >= 100) {
 
289
    die("Too many problems, try to restart");
 
290
  } else {
 
291
    warn('SEGFAULT');
 
292
  };    
 
293
};
 
294
$dbh=safe_connect();
 
295
 
 
296
#
 
297
# Test if the database require RESTRICT/CASCADE after DROP TABLE
 
298
#
 
299
 
 
300
# Really remove the crash_me table
 
301
$prompt="drop table require cascade/restrict";
 
302
$drop_attr="";
 
303
$dbh->do("drop table crash_me");
 
304
$dbh->do("drop table crash_me cascade");
 
305
if (!safe_query_l('drop_requires_cascade',
 
306
         ["create table crash_me (a integer not null)",
 
307
                 "drop table crash_me"]))
 
308
{
 
309
  $dbh->do("drop table crash_me cascade");  
 
310
  if (safe_query_l('drop_requires_cascade',
 
311
        ["create table crash_me (a integer not null)",
 
312
                  "drop table crash_me cascade"]))
 
313
  {
 
314
    save_config_data('drop_requires_cascade',"yes","$prompt");
 
315
    $drop_attr="cascade";
 
316
  }
 
317
  else
 
318
  {
 
319
    die "Can't create and drop table 'crash_me'\n";
 
320
  }
 
321
}
 
322
else
 
323
{
 
324
  save_config_data('drop_requires_cascade',"no","$prompt");
 
325
  $drop_attr="";
 
326
}
 
327
 
 
328
# Remove tables from old runs
 
329
$dbh->do("drop table crash_me $drop_attr");
 
330
$dbh->do("drop table crash_me2 $drop_attr");
 
331
$dbh->do("drop table crash_me3 $drop_attr");
 
332
$dbh->do("drop table crash_q $drop_attr");
 
333
$dbh->do("drop table crash_q1 $drop_attr");
 
334
 
 
335
$prompt="Tables without primary key";
 
336
if (!safe_query_l('no_primary_key',
 
337
      ["create table crash_me (a integer not null,b char(10) not null)",
 
338
                 "insert into crash_me (a,b) values (1,'a')"]))
 
339
{
 
340
  if (!safe_query_l('no_primary_key',
 
341
      ["create table crash_me (a integer not null,b char(10) not null".
 
342
        ", primary key (a))",
 
343
         "insert into crash_me (a,b) values (1,'a')"]))
 
344
  {
 
345
    die "Can't create table 'crash_me' with one record: $DBI::errstr\n";
 
346
  }
 
347
  save_config_data('no_primary_key',"no",$prompt);
 
348
}
 
349
else
 
350
{
 
351
  save_config_data('no_primary_key',"yes",$prompt);
 
352
}
 
353
 
 
354
#
 
355
#  Define strings for character NULL and numeric NULL used in expressions
 
356
#
 
357
$char_null=$server->{'char_null'};
 
358
$numeric_null=$server->{'numeric_null'};
 
359
if ($char_null eq '')
 
360
{
 
361
  $char_null="NULL";
 
362
}
 
363
if ($numeric_null eq '')
 
364
{
 
365
  $numeric_null="NULL";
 
366
}
 
367
 
 
368
print "$prompt: $limits{'no_primary_key'}\n";
 
369
 
 
370
report("SELECT without FROM",'select_without_from',"select 1");
 
371
if ($limits{'select_without_from'} ne "yes")
 
372
{
 
373
  $end_query=" from crash_me";
 
374
  $check_connect="select a from crash_me";
 
375
}
 
376
else
 
377
{
 
378
  $end_query="";
 
379
  $check_connect="select 1";
 
380
}
 
381
 
 
382
assert_crash($check_connect);
 
383
assert_crash("select a from crash_me where b<'b'");
 
384
 
 
385
report("Select constants",'select_constants',"select 1 $end_query");
 
386
report("Select table_name.*",'table_wildcard',
 
387
       "select crash_me.* from crash_me");
 
388
report("Allows \' and \" as string markers",'quote_with_"',
 
389
       'select a from crash_me where b<"c"');
 
390
check_and_report("Double '' as ' in strings",'double_quotes',[],
 
391
                 "select 'Walker''s' $end_query",[],"Walker's",1);
 
392
check_and_report("Multiple line strings","multi_strings",[],
 
393
                 "select a from crash_me where b < 'a'\n'b'",[],"1",0);
 
394
check_and_report("\" as identifier quote (ANSI SQL)",'quote_ident_with_"',[],
 
395
                 'select "A" from crash_me',[],"A",0);
 
396
check_and_report("\` as identifier quote",'quote_ident_with_`',[],
 
397
                 'select `A` from crash_me',[],"1",0);
 
398
check_and_report("[] as identifier quote",'quote_ident_with_[',[],
 
399
                 'select [A] from crash_me',[],"1",0);
 
400
report('Double "" in identifiers as "','quote_ident_with_dbl_"',
 
401
        'create table crash_me1 ("abc""d" integer)',
 
402
        'drop table crash_me1');                 
 
403
 
 
404
report("Column alias","column_alias","select a as ab from crash_me");
 
405
report("Table alias","table_alias","select b.a from crash_me as b");
 
406
report("Functions",'functions',"select 1+1 $end_query");
 
407
report("Group functions",'group_functions',"select count(*) from crash_me");
 
408
report("Group functions with distinct",'group_distinct_functions',
 
409
       "select count(distinct a) from crash_me");
 
410
report("Group functions with several distinct",'group_many_distinct_functions',
 
411
       "select count(distinct a), count(distinct b) from crash_me");
 
412
report("Group by",'group_by',"select a from crash_me group by a");
 
413
report("Group by position",'group_by_position',
 
414
       "select a from crash_me group by 1");
 
415
report("Group by alias",'group_by_alias',
 
416
       "select a as ab from crash_me group by ab");
 
417
report("Group on unused column",'group_on_unused',
 
418
       "select count(*) from crash_me group by a");
 
419
 
 
420
report("Order by",'order_by',"select a from crash_me order by a");
 
421
report("Order by position",'order_by_position',
 
422
       "select a from crash_me order by 1");
 
423
report("Order by function","order_by_function",
 
424
       "select a from crash_me order by a+1");
 
425
report("Order by on unused column",'order_on_unused',
 
426
       "select b from crash_me order by a");
 
427
# little bit deprecated
 
428
#check_and_report("Order by DESC is remembered",'order_by_remember_desc',
 
429
#                ["create table crash_q (s int,s1 int)",
 
430
#                 "insert into crash_q values(1,1)",
 
431
#                 "insert into crash_q values(3,1)",
 
432
#                 "insert into crash_q values(2,1)"],
 
433
#                "select s,s1 from crash_q order by s1 DESC,s",
 
434
#                ["drop table crash_q $drop_attr"],[3,2,1],7,undef(),3);
 
435
report("Compute",'compute',
 
436
       "select a from crash_me order by a compute sum(a) by a");
 
437
report("INSERT with Value lists",'insert_multi_value',
 
438
       "create table crash_q (s char(10))",
 
439
       "insert into crash_q values ('a'),('b')",
 
440
       "drop table crash_q $drop_attr");
 
441
report("INSERT with set syntax",'insert_with_set',
 
442
       "create table crash_q (a integer)",
 
443
       "insert into crash_q SET a=1",
 
444
       "drop table crash_q $drop_attr");
 
445
report("INSERT with DEFAULT","insert_with_default",
 
446
       "create table crash_me_q (a int)",
 
447
       "insert into crash_me_q (a) values (DEFAULT)",
 
448
       "drop table crash_me_q $drop_attr");
 
449
 
 
450
report("INSERT with empty value list","insert_with_empty_value_list",
 
451
       "create table crash_me_q (a int)",
 
452
       "insert into crash_me_q (a) values ()",
 
453
       "drop table crash_me_q $drop_attr");
 
454
 
 
455
report("INSERT DEFAULT VALUES","insert_default_values",
 
456
       "create table crash_me_q (a int)",
 
457
       "insert into crash_me_q  DEFAULT VALUES",
 
458
       "drop table crash_me_q $drop_attr");
 
459
       
 
460
report("allows end ';'","end_colon", "select * from crash_me;");
 
461
try_and_report("LIMIT number of rows","select_limit",
 
462
               ["with LIMIT",
 
463
                "select * from crash_me limit 1"],
 
464
               ["with TOP",
 
465
                "select TOP 1 * from crash_me"]);
 
466
report("SELECT with LIMIT #,#","select_limit2", 
 
467
      "select * from crash_me limit 1,1");
 
468
report("SELECT with LIMIT # OFFSET #",
 
469
      "select_limit3", "select * from crash_me limit 1 offset 1");
 
470
 
 
471
# The following alter table commands MUST be kept together!
 
472
if ($dbh->do("create table crash_q (a integer, b integer,c1 CHAR(10))"))
 
473
{
 
474
  report("Alter table add column",'alter_add_col',
 
475
         "alter table crash_q add d integer");
 
476
  report_one("Alter table add many columns",'alter_add_multi_col',
 
477
             [["alter table crash_q add (f integer,g integer)","yes"],
 
478
              ["alter table crash_q add f integer, add g integer","with add"],
 
479
              ["alter table crash_q add f integer,g integer","without add"]] );
 
480
  report("Alter table change column",'alter_change_col',
 
481
         "alter table crash_q change a e char(50)");
 
482
 
 
483
  # informix can only change data type with modify
 
484
  report_one("Alter table modify column",'alter_modify_col',
 
485
             [["alter table crash_q modify c1 CHAR(20)","yes"],
 
486
              ["alter table crash_q alter c1 CHAR(20)","with alter"]]);
 
487
  report("Alter table alter column default",'alter_alter_col',
 
488
         "alter table crash_q alter b set default 10");
 
489
  report_one("Alter table drop column",'alter_drop_col',
 
490
             [["alter table crash_q drop column b","yes"],
 
491
              ["alter table crash_q drop column b restrict",
 
492
              "with restrict/cascade"]]);
 
493
  report("Alter table rename table",'alter_rename_table',
 
494
         "alter table crash_q rename to crash_q1");
 
495
}
 
496
# Make sure both tables will be dropped, even if rename fails.
 
497
$dbh->do("drop table crash_q1 $drop_attr");
 
498
$dbh->do("drop table crash_q $drop_attr");
 
499
 
 
500
report("rename table","rename_table",
 
501
       "create table crash_q (a integer, b integer,c1 CHAR(10))",
 
502
       "rename table crash_q to crash_q1",
 
503
       "drop table crash_q1 $drop_attr");
 
504
# Make sure both tables will be dropped, even if rename fails.
 
505
$dbh->do("drop table crash_q1 $drop_attr");
 
506
$dbh->do("drop table crash_q $drop_attr");
 
507
 
 
508
report("truncate","truncate_table",
 
509
       "create table crash_q (a integer, b integer,c1 CHAR(10))",
 
510
       "truncate table crash_q",
 
511
       "drop table crash_q $drop_attr");
 
512
 
 
513
if ($dbh->do("create table crash_q (a integer, b integer,c1 CHAR(10))") &&
 
514
 $dbh->do("create table crash_q1 (a integer, b integer,c1 CHAR(10) not null)"))
 
515
{
 
516
  report("Alter table add constraint",'alter_add_constraint',
 
517
         "alter table crash_q add constraint c2 check(a > b)");
 
518
  report_one("Alter table drop constraint",'alter_drop_constraint',
 
519
             [["alter table crash_q drop constraint c2","yes"],
 
520
              ["alter table crash_q drop constraint c2 restrict",
 
521
              "with restrict/cascade"]]);
 
522
  report("Alter table add unique",'alter_add_unique',
 
523
         "alter table crash_q add constraint u1 unique(c1)");
 
524
  try_and_report("Alter table drop unique",'alter_drop_unique',
 
525
                 ["with constraint",
 
526
                  "alter table crash_q drop constraint u1"],
 
527
                 ["with constraint and restrict/cascade",
 
528
                  "alter table crash_q drop constraint u1 restrict"],
 
529
                 ["with drop key",
 
530
                  "alter table crash_q drop key u1"]);
 
531
  try_and_report("Alter table add primary key",'alter_add_primary_key',
 
532
                 ["with constraint",
 
533
                  "alter table crash_q1 add constraint p1 primary key(c1)"],
 
534
                 ["with add primary key",
 
535
                  "alter table crash_q1 add primary key(c1)"]);
 
536
  report("Alter table add foreign key",'alter_add_foreign_key',
 
537
         "alter table crash_q add constraint f1 foreign key(c1) references crash_q1(c1)");
 
538
  try_and_report("Alter table drop foreign key",'alter_drop_foreign_key',
 
539
                 ["with drop constraint",
 
540
                  "alter table crash_q drop constraint f1"],
 
541
                 ["with drop constraint and restrict/cascade",
 
542
                  "alter table crash_q drop constraint f1 restrict"],
 
543
                 ["with drop foreign key",
 
544
                  "alter table crash_q drop foreign key f1"]);
 
545
  try_and_report("Alter table drop primary key",'alter_drop_primary_key',
 
546
                 ["drop constraint",
 
547
                  "alter table crash_q1 drop constraint p1 restrict"],
 
548
                 ["drop primary key",
 
549
                  "alter table crash_q1 drop primary key"]);
 
550
}
 
551
$dbh->do("drop table crash_q $drop_attr");
 
552
$dbh->do("drop table crash_q1 $drop_attr");
 
553
 
 
554
check_and_report("Case insensitive compare","case_insensitive_strings",
 
555
                 [],"select b from crash_me where b = 'A'",[],'a',1);
 
556
check_and_report("Ignore end space in compare","ignore_end_space",
 
557
                 [],"select b from crash_me where b = 'a '",[],'a',1);
 
558
check_and_report("Group on column with null values",'group_by_null',
 
559
                 ["create table crash_q (s char(10))",
 
560
                  "insert into crash_q values(null)",
 
561
                  "insert into crash_q values(null)"],
 
562
                 "select count(*),s from crash_q group by s",
 
563
                 ["drop table crash_q $drop_attr"],2,0);
 
564
 
 
565
$prompt="Having";
 
566
if (!defined($limits{'having'}))
 
567
{                               # Complicated because of postgreSQL
 
568
  if (!safe_query_result_l("having",
 
569
      "select a from crash_me group by a having a > 0",1,0))
 
570
  {
 
571
    if (!safe_query_result_l("having",
 
572
           "select a from crash_me group by a having a < 0",
 
573
            1,0))
 
574
    { save_config_data("having","error",$prompt); }
 
575
    else
 
576
    { save_config_data("having","yes",$prompt); }
 
577
  }
 
578
  else
 
579
  { save_config_data("having","no",$prompt); }
 
580
}
 
581
print "$prompt: $limits{'having'}\n";
 
582
 
 
583
if ($limits{'having'} eq 'yes')
 
584
{
 
585
  report("Having with group function","having_with_group",
 
586
         "select a from crash_me group by a having count(*) = 1");
 
587
}
 
588
 
 
589
if ($limits{'column_alias'} eq 'yes')
 
590
{
 
591
  report("Order by alias",'order_by_alias',
 
592
         "select a as ab from crash_me order by ab");
 
593
  if ($limits{'having'} eq 'yes')
 
594
  {
 
595
    report("Having on alias","having_with_alias",
 
596
           "select a as ab from crash_me group by a having ab > 0");
 
597
  }
 
598
}
 
599
report("binary numbers (0b1001)","binary_numbers","select 0b1001 $end_query");
 
600
report("hex numbers (0x41)","hex_numbers","select 0x41 $end_query");
 
601
report("binary strings (b'0110')","binary_strings","select b'0110' $end_query");
 
602
report("hex strings (x'1ace')","hex_strings","select x'1ace' $end_query");
 
603
 
 
604
report_result("Value of logical operation (1=1)","logical_value",
 
605
              "select (1=1) $end_query");
 
606
 
 
607
report_result("Value of TRUE","value_of_true","select TRUE $end_query");
 
608
report_result("Value of FALSE","value_of_false","select FALSE $end_query");
 
609
 
 
610
$logical_value= $limits{'logical_value'};
 
611
 
 
612
$false=0;
 
613
$result="no";
 
614
if ($res=safe_query_l('has_true_false',"select (1=1)=true $end_query")) {
 
615
  $false="false";
 
616
  $result="yes";
 
617
}
 
618
save_config_data('has_true_false',$result,"TRUE and FALSE");
 
619
 
 
620
#
 
621
# Check how many connections the server can handle:
 
622
# We can't test unlimited connections, because this may take down the
 
623
# server...
 
624
#
 
625
 
 
626
$prompt="Simultaneous connections (installation default)";
 
627
print "$prompt: ";
 
628
if (defined($limits{'connections'}))
 
629
{
 
630
  print "$limits{'connections'}\n";
 
631
}
 
632
else
 
633
{
 
634
  @connect=($dbh);
 
635
 
 
636
  for ($i=1; $i < $max_connections ; $i++)
 
637
  {
 
638
    if (!($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
 
639
                          { PrintError => 0})))
 
640
    {
 
641
      print "Last connect error: $DBI::errstr\n" if ($opt_debug);
 
642
      last;
 
643
    }
 
644
    $dbh->{LongReadLen}= $longreadlen; # Set retrieval buffer
 
645
    print "." if ($opt_debug);
 
646
    push(@connect,$dbh);
 
647
  }
 
648
  print "$i\n";
 
649
  save_config_data('connections',$i,$prompt);
 
650
  foreach $dbh (@connect)
 
651
  {
 
652
    print "#" if ($opt_debug);
 
653
    $dbh->disconnect || warn $dbh->errstr;           # close connection
 
654
  }
 
655
 
 
656
  $#connect=-1;                 # Free connections
 
657
 
 
658
  if ($i == 0)
 
659
  {
 
660
    print "Can't connect to server: $DBI::errstr.".
 
661
          "  Please start it and try again\n";
 
662
    exit 1;
 
663
  }
 
664
  $dbh=retry_connect();
 
665
}
 
666
 
 
667
 
 
668
#
 
669
# Check size of communication buffer, strings...
 
670
#
 
671
 
 
672
$prompt="query size";
 
673
print "$prompt: ";
 
674
if (!defined($limits{'query_size'}))
 
675
{
 
676
  $query="select ";
 
677
  $first=64;
 
678
  $end=$max_buffer_size;
 
679
  $select= $limits{'select_without_from'} eq 'yes' ? 1 : 'a';
 
680
 
 
681
  assert_crash($query . "$select$end_query");
 
682
 
 
683
  $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'});
 
684
 
 
685
  if ($limits{'restart'}{'tohigh'})
 
686
  {
 
687
    $end = $limits{'restart'}{'tohigh'} - 1;
 
688
    print "\nRestarting this with low limit: $first and high limit: $end\n";
 
689
    delete $limits{'restart'};
 
690
    $first=$first+int(($end-$first+4)/5);           # Prefere lower on errors
 
691
  }
 
692
  for ($i=$first ; $i < $end ; $i*=2)
 
693
  {
 
694
    #printf "Trying query %s %d with %d spaces\n",$query,$select,($i - length($query)-length($end_query) -1);
 
695
    last if (!safe_query($query . 
 
696
            (" " x ($i - length($query)-length($end_query) -1)) 
 
697
              . "$select$end_query"));
 
698
    $first=$i;
 
699
    save_config_data("restart",$i,"") if ($opt_restart);
 
700
  }
 
701
  $end=$i;
 
702
 
 
703
  if ($i < $max_buffer_size)
 
704
  {
 
705
    while ($first != $end)
 
706
    {
 
707
      $i=int(($first+$end+1)/2);
 
708
      if (safe_query($query .
 
709
                     (" " x ($i - length($query)-length($end_query) -1)) .
 
710
                     "$select$end_query"))
 
711
      {
 
712
        $first=$i;
 
713
      }
 
714
      else
 
715
      {
 
716
        $end=$i-1;
 
717
      }
 
718
    }
 
719
  }
 
720
  save_config_data('query_size',$end,$prompt);
 
721
}
 
722
$query_size=$limits{'query_size'};
 
723
 
 
724
print "$limits{'query_size'}\n";
 
725
 
 
726
#
 
727
# Check for reserved words
 
728
#
 
729
 
 
730
check_reserved_words($dbh);
 
731
 
 
732
#
 
733
# Test database types
 
734
#
 
735
 
 
736
@sql_types=("character(1)","char(1)","char varying(1)", "character varying(1)",
 
737
            "boolean",
 
738
            "varchar(1)",
 
739
            "integer","int","smallint",
 
740
            "numeric(9,2)","decimal(6,2)","dec(6,2)",
 
741
            "bit", "bit(2)","bit varying(2)","float","float(8)","real",
 
742
            "double precision", "date","time","timestamp",
 
743
            "interval year", "interval year to month",
 
744
            "interval month",
 
745
            "interval day", "interval day to hour", "interval day to minute",
 
746
            "interval day to second",
 
747
            "interval hour", "interval hour to minute",
 
748
            "interval hour to second",
 
749
            "interval minute", "interval minute to second",
 
750
            "interval second",
 
751
            "national character varying(20)",
 
752
            "national character(20)","nchar(1)",
 
753
            "national char varying(20)","nchar varying(20)",
 
754
            "national character varying(20)",
 
755
            "timestamp with time zone");
 
756
@odbc_types=("binary(1)","varbinary(1)","tinyint","bigint",
 
757
             "datetime");
 
758
@extra_types=("blob","byte","long varbinary","image","text","text(10)",
 
759
              "mediumtext",
 
760
              "long varchar(1)", "varchar2(257)",
 
761
              "mediumint","middleint","int unsigned",
 
762
              "int1","int2","int3","int4","int8","uint",
 
763
              "money","smallmoney","float4","float8","smallfloat",
 
764
              "float(6,2)","double",
 
765
              "enum('red')","set('red')", "int(5) zerofill", "serial",
 
766
              "char(10) binary","int not null auto_increment,unique(q)",
 
767
              "abstime","year","datetime","smalldatetime","timespan","reltime",
 
768
              # Sybase types
 
769
              "int not null identity,unique(q)",
 
770
              # postgres types
 
771
              "box","bool","circle","polygon","point","line","lseg","path",
 
772
              "interval", "inet", "cidr", "macaddr",
 
773
 
 
774
              # oracle types
 
775
              "varchar2(16)","nvarchar2(16)","number(9,2)","number(9)",
 
776
              "number", "long","raw(16)","long raw","rowid","mlslabel","clob",
 
777
              "nclob","bfile"
 
778
              );
 
779
 
 
780
@types=(["sql",\@sql_types],
 
781
        ["odbc",\@odbc_types],
 
782
        ["extra",\@extra_types]);
 
783
 
 
784
foreach $types (@types)
 
785
{
 
786
  print "\nSupported $types->[0] types\n";
 
787
  $tmp=@$types->[1];
 
788
  foreach $use_type (@$tmp)
 
789
  {
 
790
    $type=$use_type;
 
791
    $type =~ s/\(.*\)/(1 arg)/;
 
792
    if (index($use_type,",")>= 0)
 
793
    {
 
794
      $type =~ s/\(1 arg\)/(2 arg)/;
 
795
    }
 
796
    if (($tmp2=index($type,",unique")) >= 0)
 
797
    {
 
798
      $type=substr($type,0,$tmp2);
 
799
    }
 
800
    $tmp2=$type;
 
801
    $tmp2 =~ s/ /_/g;
 
802
    $tmp2 =~ s/_not_null//g;
 
803
    report("Type $type","type_$types->[0]_$tmp2",
 
804
           "create table crash_q (q $use_type)",
 
805
           "drop table crash_q $drop_attr");
 
806
  }
 
807
}
 
808
 
 
809
#
 
810
# Test some type limits
 
811
#
 
812
 
 
813
 
 
814
check_and_report("Remembers end space in char()","remember_end_space",
 
815
                 ["create table crash_q (a char(10))",
 
816
                  "insert into crash_q values('hello ')"],
 
817
                 "select a from crash_q where a = 'hello '",
 
818
                 ["drop table crash_q $drop_attr"],
 
819
                 'hello ',6);
 
820
 
 
821
check_and_report("Remembers end space in varchar()",
 
822
                 "remember_end_space_varchar",
 
823
                 ["create table crash_q (a varchar(10))",
 
824
                  "insert into crash_q values('hello ')"],
 
825
                 "select a from crash_q where a = 'hello '",
 
826
                 ["drop table crash_q $drop_attr"],
 
827
                 'hello ',6);
 
828
 
 
829
if (($limits{'type_extra_float(2_arg)'} eq "yes" ||
 
830
    $limits{'type_sql_decimal(2_arg)'} eq "yes") &&
 
831
    (!defined($limits{'storage_of_float'})))
 
832
{
 
833
  my $type=$limits{'type_extra_float(2_arg)'} eq "yes" ? "float(4,1)" :
 
834
    "decimal(4,1)";
 
835
  my $result="undefined";
 
836
  if (execute_and_check("storage_of_float",["create table crash_q (q1 $type)",
 
837
                         "insert into crash_q values(1.14)"],
 
838
                        "select q1 from crash_q",
 
839
                        ["drop table crash_q $drop_attr"],1.1,0) &&
 
840
      execute_and_check("storage_of_float",["create table crash_q (q1 $type)",
 
841
                         "insert into crash_q values(1.16)"],
 
842
                        "select q1 from crash_q",
 
843
                        ["drop table crash_q $drop_attr"],1.1,0))
 
844
  {
 
845
    $result="truncate";
 
846
  }
 
847
  elsif (execute_and_check("storage_of_float",["create table crash_q (q1 $type)",
 
848
                            "insert into crash_q values(1.14)"],
 
849
                           "select q1 from crash_q",
 
850
                           ["drop table crash_q $drop_attr"],1.1,0) &&
 
851
         execute_and_check("storage_of_float",["create table crash_q (q1 $type)",
 
852
                            "insert into crash_q values(1.16)"],
 
853
                           "select q1 from crash_q",
 
854
                           ["drop table crash_q $drop_attr"],1.2,0))
 
855
  {
 
856
    $result="round";
 
857
  }
 
858
  elsif (execute_and_check("storage_of_float",["create table crash_q (q1 $type)",
 
859
                            "insert into crash_q values(1.14)"],
 
860
                           "select q1 from crash_q",
 
861
                           ["drop table crash_q $drop_attr"],1.14,0) &&
 
862
         execute_and_check("storage_of_float",["create table crash_q (q1 $type)",
 
863
                            "insert into crash_q values(1.16)"],
 
864
                           "select q1 from crash_q",
 
865
                           ["drop table crash_q $drop_attr"],1.16,0))
 
866
  {
 
867
    $result="exact";
 
868
  }
 
869
  $prompt="Storage of float values";
 
870
  print "$prompt: $result\n";
 
871
  save_config_data("storage_of_float", $result, $prompt);
 
872
}
 
873
 
 
874
try_and_report("Type for row id", "rowid",
 
875
               ["rowid",
 
876
                "create table crash_q (a rowid)",
 
877
                "drop table crash_q $drop_attr"],
 
878
               ["auto_increment",
 
879
                "create table crash_q (a int not null auto_increment".
 
880
                ", primary key(a))","drop table crash_q $drop_attr"],
 
881
               ["oid",
 
882
                "create table crash_q (a oid, primary key(a))",
 
883
                "drop table crash_q $drop_attr"],
 
884
               ["serial",
 
885
                "create table crash_q (a serial, primary key(a))",
 
886
                "drop table crash_q $drop_attr"]);
 
887
 
 
888
try_and_report("Automatic row id", "automatic_rowid",
 
889
               ["_rowid",
 
890
                "create table crash_q (a int not null, primary key(a))",
 
891
                "insert into crash_q values (1)",
 
892
                "select _rowid from crash_q",
 
893
                "drop table crash_q $drop_attr"]);
 
894
 
 
895
#
 
896
# Test functions
 
897
#
 
898
 
 
899
@sql_functions=
 
900
  (["+, -, * and /","+","5*3-4/2+1",14,0],
 
901
   ["ANSI SQL SUBSTRING","substring","substring('abcd' from 2 for 2)","bc",1],
 
902
   ["BIT_LENGTH","bit_length","bit_length('abc')",24,0],
 
903
   ["searched CASE","searched_case",
 
904
     "case when 1 > 2 then 'false' when 2 > 1 then 'true' end", "true",1],
 
905
   ["simple CASE","simple_case",
 
906
     "case 2 when 1 then 'false' when 2 then 'true' end", "true",1],
 
907
   ["CAST","cast","CAST(1 as CHAR)","1",1],
 
908
   ["CHARACTER_LENGTH","character_length","character_length('abcd')","4",0],
 
909
   ["CHAR_LENGTH","char_length","char_length(b)","1",0],
 
910
   ["CHAR_LENGTH(constant)","char_length(constant)",
 
911
     "char_length('abcd')","4",0],
 
912
   ["COALESCE","coalesce","coalesce($char_null,'bcd','qwe')","bcd",1],
 
913
   ["CURRENT_DATE","current_date","current_date",0,2],
 
914
   ["CURRENT_TIME","current_time","current_time",0,2],
 
915
   ["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2],
 
916
   ["EXTRACT","extract_sql",
 
917
     "extract(minute from timestamp '2000-02-23 18:43:12.987')",43,0],
 
918
   ["LOCALTIME","localtime","localtime",0,2],
 
919
   ["LOCALTIMESTAMP","localtimestamp","localtimestamp",0,2],
 
920
   ["LOWER","lower","LOWER('ABC')","abc",1],
 
921
   ["NULLIF with strings","nullif_string",
 
922
       "NULLIF(NULLIF('first','second'),'first')",undef(),4],
 
923
   ["NULLIF with numbers","nullif_num","NULLIF(NULLIF(1,2),1)",undef(),4],
 
924
   ["OCTET_LENGTH","octet_length","octet_length('abc')",3,0],
 
925
   ["POSITION","position","position('ll' in 'hello')",3,0],
 
926
   ["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",3],
 
927
   ["UPPER","upper","UPPER('abc')","ABC",1],
 
928
   ["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1],
 
929
   );
 
930
 
 
931
@odbc_functions=
 
932
  (["ASCII", "ascii", "ASCII('A')","65",0],
 
933
   ["CHAR", "char", "CHAR(65)"  ,"A",1],
 
934
   ["CONCAT(2 arg)","concat", "concat('a','b')","ab",1],
 
935
   ["DIFFERENCE()","difference","difference('abc','abe')",3,0],
 
936
   ["INSERT","insert","insert('abcd',2,2,'ef')","aefd",1],
 
937
   ["LEFT","left","left('abcd',2)","ab",1],
 
938
   ["LTRIM","ltrim","ltrim('   abcd')","abcd",1],
 
939
   ["REAL LENGTH","length","length('abcd ')","5",0],
 
940
   ["ODBC LENGTH","length_without_space","length('abcd')","4",0],
 
941
   ["LOCATE(2 arg)","locate_2","locate('bcd','abcd')","2",0],
 
942
   ["LOCATE(3 arg)","locate_3","locate('bcd','abcd',3)","0",0],
 
943
   ["LCASE","lcase","lcase('ABC')","abc",1],
 
944
   ["REPEAT","repeat","repeat('ab',3)","ababab",1],
 
945
   ["REPLACE","replace","replace('abbaab','ab','ba')","bababa",1],
 
946
   ["RIGHT","right","right('abcd',2)","cd",1],
 
947
   ["RTRIM","rtrim","rtrim(' abcd  ')"," abcd",1],
 
948
   ["SPACE","space","space(5)","     ",3],
 
949
   ["SOUNDEX","soundex","soundex('hello')",0,2],
 
950
   ["ODBC SUBSTRING","substring","substring('abcd',3,2)","cd",1],
 
951
   ["UCASE","ucase","ucase('abc')","ABC",1],
 
952
 
 
953
   ["ABS","abs","abs(-5)",5,0],
 
954
   ["ACOS","acos","acos(0)","1.570796",0],
 
955
   ["ASIN","asin","asin(1)","1.570796",0],
 
956
   ["ATAN","atan","atan(1)","0.785398",0],
 
957
   ["ATAN2","atan2","atan2(1,0)","1.570796",0],
 
958
   ["CEILING","ceiling","ceiling(-4.5)",-4,0],
 
959
   ["COS","cos","cos(0)","1.00000",0],
 
960
   ["COT","cot","cot(1)","0.64209262",0],
 
961
   ["DEGREES","degrees","degrees(6.283185)","360",0],
 
962
   ["EXP","exp","exp(1.0)","2.718282",0],
 
963
   ["FLOOR","floor","floor(2.5)","2",0],
 
964
   ["LOG","log","log(2)","0.693147",0],
 
965
   ["LOG10","log10","log10(10)","1",0],
 
966
   ["MOD","mod","mod(11,7)","4",0],
 
967
   ["PI","pi","pi()","3.141593",0],
 
968
   ["POWER","power","power(2,4)","16",0],
 
969
   ["RAND","rand","rand(1)",0,2],       # Any value is acceptable
 
970
   ["RADIANS","radians","radians(360)","6.283185",0],
 
971
   ["ROUND(2 arg)","round","round(5.63,2)","5.6",0],
 
972
   ["SIGN","sign","sign(-5)",-1,0],
 
973
   ["SIN","sin","sin(1)","0.841471",0],
 
974
   ["SQRT","sqrt","sqrt(4)",2,0],
 
975
   ["TAN","tan","tan(1)","1.557408",0],
 
976
   ["TRUNCATE","truncate","truncate(18.18,-1)",10,0],
 
977
   ["NOW","now","now()",0,2],           # Any value is acceptable
 
978
   ["CURDATE","curdate","curdate()",0,2],
 
979
   ["CURTIME","curtime","curtime()",0,2],
 
980
   # Drizzle is different than MySQL in displaying timestamps
 
981
   # ["TIMESTAMPADD","timestampadd",
 
982
   #  "timestampadd(SQL_TSI_SECOND,1,'1997-01-01 00:00:00')",
 
983
   #  "1997-01-01 00:00:01",1],
 
984
   ["TIMESTAMPADD","timestampadd",
 
985
    "timestampadd(SQL_TSI_SECOND,1,'1997-01-01 00:00:00')",
 
986
     "1997-01-01 00:00:01.000000",1],
 
987
   ["TIMESTAMPDIFF","timestampdiff",
 
988
    "timestampdiff(SQL_TSI_SECOND,'1997-01-01 00:00:01',".
 
989
     " '1997-01-01 00:00:02')","1",0],
 
990
   ["USER()","user()","user()",0,2],
 
991
   ["DATABASE","database","database()",0,2],
 
992
   ["IFNULL","ifnull","ifnull(2,3)",2,0],
 
993
   ["ODBC syntax LEFT & RIGHT", "fn_left",
 
994
    "{ fn LEFT( { fn RIGHT('abcd',2) },1) }","c",1],
 
995
   );
 
996
 
 
997
@extra_functions=
 
998
  (
 
999
   ["& (bitwise and)",'&',"5 & 3",1,0],
 
1000
   ["| (bitwise or)",'|',"1 | 2",3,0],
 
1001
   ["<< and >> (bitwise shifts)",'binary_shifts',"(1 << 4) >> 2",4,0],
 
1002
   ["<> in SELECT","<>","1<>1","0",0],
 
1003
   ["=","=","(1=1)",1,$logical_value],
 
1004
   ["~* (case insensitive compare)","~*","'hi' ~* 'HI'",1,$logical_value],
 
1005
   ["AND and OR in SELECT","and_or","1=1 AND 2=2",$logical_value,0],
 
1006
   ["AND as '&&'",'&&',"1=1 && 2=2",$logical_value,0],
 
1007
   ["ASCII_CHAR", "ascii_char", "ASCII_CHAR(65)","A",1],
 
1008
   ["ASCII_CODE", "ascii_code", "ASCII_CODE('A')","65",0],
 
1009
   ["ATN2","atn2","atn2(1,0)","1.570796",0],
 
1010
   ["BETWEEN in SELECT","between","5 between 4 and 6",$logical_value,0],
 
1011
   ["BIT_COUNT","bit_count","bit_count(5)",2,0],
 
1012
   ["CEIL","ceil","ceil(-4.5)",-4,0], # oracle
 
1013
   ["CHARINDEX","charindex","charindex('a','crash')",3,0],
 
1014
   ["CHR", "chr", "CHR(65)"  ,"A",1], # oracle
 
1015
   ["CONCAT(list)","concat_list", "concat('a','b','c','d')","abcd",1],
 
1016
   ["CONVERT","convert","convert(CHAR,5)","5",1],
 
1017
   ["COSH","cosh","cosh(0)","1",0], # oracle hyperbolic cosine of n.
 
1018
   ["ELT","elt","elt(2,'ONE','TWO','THREE')","TWO",1],
 
1019
   ["ENCRYPT","encrypt","encrypt('hello')",0,2],
 
1020
   ["FIELD","field","field('IBM','NCA','ICL','SUN','IBM','DIGITAL')",4,0],
 
1021
   ["FORMAT","format","format(1234.5555,2)","1,234.56",1],
 
1022
   ["GETDATE","getdate","getdate()",0,2],
 
1023
   ["GREATEST","greatest","greatest('HARRY','HARRIOT','HAROLD')","HARRY",1],
 
1024
   ["IF","if", "if(5,6,7)",6,0],
 
1025
   ["IN on numbers in SELECT","in_num","2 in (3,2,5,9,5,1)",$logical_value,0],
 
1026
   ["IN on strings in SELECT","in_str","'monty' in ('david','monty','allan')", $logical_value,0],
 
1027
   ["INITCAP","initcap","initcap('the soap')","The Soap",1], 
 
1028
       # oracle Returns char, with the first letter of each word in uppercase
 
1029
   ["INSTR (Oracle syntax)", "instr_oracle", "INSTR('CORPORATE FLOOR','OR',3,2)"  ,"14",0], # oracle instring
 
1030
   ["INSTRB", "instrb", "INSTRB('CORPORATE FLOOR','OR',5,2)"  ,"27",0], 
 
1031
      # oracle instring in bytes
 
1032
   ["INTERVAL","interval","interval(55,10,20,30,40,50,60,70,80,90,100)",5,0],
 
1033
   ["LAST_INSERT_ID","last_insert_id","last_insert_id()",0,2],
 
1034
   ["LEAST","least","least('HARRY','HARRIOT','HAROLD')","HAROLD",1], 
 
1035
      # oracle
 
1036
   ["LENGTHB","lengthb","lengthb('CANDIDE')","14",0], 
 
1037
      # oracle length in bytes
 
1038
   ["LIKE ESCAPE in SELECT","like_escape",
 
1039
     "'%' like 'a%' escape 'a'",$logical_value,0],
 
1040
   ["LIKE in SELECT","like","'a' like 'a%'",$logical_value,0],
 
1041
   ["LN","ln","ln(95)","4.55387689",0], 
 
1042
      # oracle natural logarithm of n
 
1043
   ["LOCATE as INSTR","instr","instr('hello','ll')",3,0],
 
1044
   ["LOG(m,n)","log(m_n)","log(10,100)","2",0], 
 
1045
      # oracle logarithm, base m, of n
 
1046
   ["LOGN","logn","logn(2)","0.693147",0], 
 
1047
      # informix
 
1048
   ["LPAD","lpad","lpad('hi',4,'??')",'??hi',3],
 
1049
   ["MOD as %","%","10%7","3",0],
 
1050
   ["NOT BETWEEN in SELECT","not_between","5 not between 4 and 6",0,0],
 
1051
   ["NOT LIKE in SELECT","not_like","'a' not like 'a%'",0,0],
 
1052
   ["NOT as '!' in SELECT","!","! 1",0,0],
 
1053
   ["NOT in SELECT","not","not $false",$logical_value,0],
 
1054
   ["ODBC CONVERT","odbc_convert","convert(5,SQL_CHAR)","5",1],
 
1055
   ["OR as '||'",'||',"1=0 || 1=1",$logical_value,0],
 
1056
   ["PASSWORD","password","password('hello')",0,2],
 
1057
   ["PASTE", "paste", "paste('ABCDEFG',3,2,'1234')","AB1234EFG",1],
 
1058
   ["PATINDEX","patindex","patindex('%a%','crash')",3,0],
 
1059
   ["POW","pow","pow(3,2)",9,0],
 
1060
   ["RANGE","range","range(a)","0.0",0], 
 
1061
       # informix range(a) = max(a) - min(a)
 
1062
   ["REGEXP in SELECT","regexp","'a' regexp '^(a|b)*\$'",$logical_value,0],
 
1063
   ["REPLICATE","replicate","replicate('a',5)","aaaaa",1],
 
1064
   ["REVERSE","reverse","reverse('abcd')","dcba",1],
 
1065
   ["ROOT","root","root(4)",2,0], # informix
 
1066
   ["ROUND(1 arg)","round1","round(5.63)","6",0],
 
1067
   ["RPAD","rpad","rpad('hi',4,'??')",'hi??',3],
 
1068
   ["SINH","sinh","sinh(1)","1.17520119",0], # oracle hyperbolic sine of n
 
1069
   ["STR","str","str(123.45,5,1)",123.5,3],
 
1070
   ["STRCMP","strcmp","strcmp('abc','adc')",-1,0],
 
1071
   ["STUFF","stuff","stuff('abc',2,3,'xyz')",'axyz',3],
 
1072
   ["SUBSTRB", "substrb", "SUBSTRB('ABCDEFG',5,4.2)"  ,"CD",1], 
 
1073
      # oracle substring with bytes
 
1074
   ["SUBSTRING as MID","mid","mid('hello',3,2)","ll",1],
 
1075
   ["SUBSTRING_INDEX","substring_index",
 
1076
     "substring_index('www.tcx.se','.',-2)", "tcx.se",1],
 
1077
   ["SYSDATE","sysdate","sysdate()",0,2],
 
1078
   ["TAIL","tail","tail('ABCDEFG',3)","EFG",0],
 
1079
   ["TANH","tanh","tanh(1)","0.462117157",0], 
 
1080
      # oracle hyperbolic tangent of n
 
1081
   ["TRANSLATE","translate","translate('abc','bc','de')",'ade',3],
 
1082
   ["TRIM; Leading char extension", "trim_leading_char","trim(LEADING ':' FROM ':abc!')","abc!",3],
 
1083
   ["TRIM; Trailing char extension", "trim_trailing_char","trim(TRAILING'!' FROM ':abc!')",":abc",3],
 
1084
   ["TRIM; Substring extension",
 
1085
     "trim_substring","trim('cb' FROM 'abccb')","abc",3],
 
1086
   ["TRUNC","trunc","trunc(18.18,-1)",10,0], # oracle
 
1087
   ["UID","uid","uid",0,2], # oracle uid from user
 
1088
   ["UNIX_TIMESTAMP","unix_timestamp","unix_timestamp()",0,2],
 
1089
   ["USERENV","userenv","userenv",0,2], # oracle user enviroment
 
1090
   ["VERSION","version","version()",0,2],
 
1091
   ["automatic num->string convert","auto_num2string","concat('a',2)","a2",1],
 
1092
   ["automatic string->num convert","auto_string2num","'1'+2",3,0],
 
1093
   ["concatenation with +","concat_as_+","'abc' + 'def'","abcdef",1],
 
1094
   ["SUBSTR (2 arg)",'substr2arg',"substr('abcd',2)",'bcd',1],  #sapdb func
 
1095
   ["SUBSTR (3 arg)",'substr3arg',"substr('abcd',2,2)",'bc',1],
 
1096
   ["LFILL (3 arg)",'lfill3arg',"lfill('abcd','.',6)",'..abcd',1],
 
1097
   ["RFILL (3 arg)",'rfill3arg',"rfill('abcd','.',6)",'abcd..',1],
 
1098
   ["RPAD (4 arg)",'rpad4arg',"rpad('abcd',2,'+-',8)",'abcd+-+-',1],
 
1099
   ["LPAD (4 arg)",'rpad4arg',"lpad('abcd',2,'+-',8)",'+-+-abcd',1],
 
1100
   ["TRIM (1 arg)",'trim1arg',"trim(' abcd ')",'abcd',1],
 
1101
   ["TRIM (2 arg)",'trim2arg',"trim('..abcd..','.')",'abcd',1],
 
1102
   ["LTRIM (2 arg)",'ltrim2arg',"ltrim('..abcd..','.')",'abcd..',1],
 
1103
   ["RTRIM (2 arg)",'rtrim2arg',"rtrim('..abcd..','.')",'..abcd',1],
 
1104
   ["EXPAND",'expand2arg',"expand('abcd',6)",'abcd  ',0],
 
1105
   ["REPLACE (2 arg) ",'replace2arg',"replace('AbCd','bC')",'Ad',1],
 
1106
   ["MAPCHAR",'mapchar',"mapchar('Aļæ½')",'Aa',1],
 
1107
   ["ALPHA",'alpha',"alpha('Aļæ½',2)",'AA',1],
 
1108
   ["ASCII in string cast",'ascii_string',"ascii('a')",'97',1],
 
1109
   ["EBCDIC in string cast",'ebcdic_string',"ebcdic('a')",'a',1],
 
1110
   ["TRUNC (1 arg)",'trunc1arg',"trunc(222.6)",222,0],
 
1111
   ["FIXED",'fixed',"fixed(222.6666,10,2)",'222.67',0],
 
1112
   ["FLOAT",'float',"float(6666.66,4)",6667,0],
 
1113
   ["LENGTH",'length',"length(1)",1,0],
 
1114
   ["INDEX",'index',"index('abcdefg','cd',1,1)",3,0],
 
1115
   ["MICROSECOND",'microsecond',
 
1116
      "MICROSECOND('19630816200212111111')",'111111',0],
 
1117
   ["TIMESTAMP",'timestamp',
 
1118
      "timestamp('19630816','00200212')",'19630816200212000000',0],
 
1119
   ["VALUE",'value',"value(NULL,'WALRUS')",'WALRUS',0],
 
1120
   ["DECODE",'decode',"DECODE('S-103','T72',1,'S-103',2,'Leopard',3)",2,0],
 
1121
   ["NUM",'num',"NUM('2123')",2123,0],
 
1122
   ["CHR (any type to string)",'chr_str',"CHR(67)",'67',0],
 
1123
   ["HEX",'hex',"HEX('A')",41,0],
 
1124
   );
 
1125
 
 
1126
 
 
1127
@sql_group_functions=
 
1128
  (
 
1129
   ["AVG","avg","avg(a)",1,0],
 
1130
   ["COUNT (*)","count_*","count(*)",1,0],
 
1131
   ["COUNT column name","count_column","count(a)",1,0],
 
1132
   ["COUNT(DISTINCT expr)","count_distinct","count(distinct a)",1,0],
 
1133
   ["MAX on numbers","max","max(a)",1,0],
 
1134
   ["MAX on strings","max_str","max(b)","a",1],
 
1135
   ["MIN on numbers","min","min(a)",1,0],
 
1136
   ["MIN on strings","min_str","min(b)","a",1],
 
1137
   ["SUM","sum","sum(a)",1,0],
 
1138
   ["ANY","any","any(a)",$logical_value,0],
 
1139
   ["EVERY","every","every(a)",$logical_value,0],
 
1140
   ["SOME","some","some(a)",$logical_value,0],
 
1141
   );
 
1142
 
 
1143
@extra_group_functions=
 
1144
  (
 
1145
   ["BIT_AND",'bit_and',"bit_and(a)",1,0],
 
1146
   ["BIT_OR", 'bit_or', "bit_or(a)",1,0],
 
1147
   ["COUNT(DISTINCT expr,expr,...)",
 
1148
     "count_distinct_list","count(distinct a,b)",1,0],
 
1149
   ["STD","std","std(a)",0,0],
 
1150
   ["STDDEV","stddev","stddev(a)",0,0],
 
1151
   ["VARIANCE","variance","variance(a)",0,0],
 
1152
   );
 
1153
 
 
1154
@where_functions=
 
1155
(
 
1156
 ["= ALL","eq_all","b =all (select b from crash_me)",1,0],
 
1157
 ["= ANY","eq_any","b =any (select b from crash_me)",1,0],
 
1158
 ["= SOME","eq_some","b =some (select b from crash_me)",1,0],
 
1159
 ["BETWEEN","between","5 between 4 and 6",1,0],
 
1160
 ["EXISTS","exists","exists (select * from crash_me)",1,0],
 
1161
 ["IN on numbers","in_num","2 in (3,2,5,9,5,1)",1,0],
 
1162
 ["LIKE ESCAPE","like_escape","b like '%' escape 'a'",1,0],
 
1163
 ["LIKE","like","b like 'a%'",1,0],
 
1164
 ["MATCH UNIQUE","match_unique",
 
1165
   "1 match unique (select a from crash_me)",1,0],
 
1166
 ["MATCH","match","1 match (select a from crash_me)",1,0],
 
1167
 ["MATCHES","matches","b matches 'a*'",1,0],
 
1168
 ["NOT BETWEEN","not_between","7 not between 4 and 6",1,0],
 
1169
 ["NOT EXISTS","not_exists",
 
1170
   "not exists (select * from crash_me where a = 2)",1,0],
 
1171
 ["NOT LIKE","not_like","b not like 'b%'",1,0],
 
1172
 ["NOT UNIQUE","not_unique",
 
1173
   "not unique (select * from crash_me where a = 2)",1,0],
 
1174
 ["UNIQUE","unique","unique (select * from crash_me)",1,0],
 
1175
 );
 
1176
 
 
1177
@types=(["sql",\@sql_functions,0],
 
1178
        ["odbc",\@odbc_functions,0],
 
1179
        ["extra",\@extra_functions,0],
 
1180
        ["where",\@where_functions,0]);
 
1181
 
 
1182
@group_types=(["sql",\@sql_group_functions,0],
 
1183
              ["extra",\@extra_group_functions,0]);
 
1184
 
 
1185
 
 
1186
foreach $types (@types)
 
1187
{
 
1188
  print "\nSupported $types->[0] functions\n";
 
1189
  $tmp=@$types->[1];
 
1190
  foreach $type (@$tmp)
 
1191
  {
 
1192
    if (defined($limits{"func_$types->[0]_$type->[1]"}))
 
1193
    {
 
1194
      next;
 
1195
    }
 
1196
    if ($types->[0] eq "where")
 
1197
    {
 
1198
      check_and_report("Function $type->[0]","func_$types->[0]_$type->[1]",
 
1199
                       [],"select a from crash_me where $type->[2]",[],
 
1200
                       $type->[3],$type->[4]);
 
1201
    }
 
1202
    elsif ($limits{'functions'} eq 'yes')
 
1203
    {
 
1204
      if (($type->[2] =~ /char_length\(b\)/) && (!$end_query))
 
1205
      {
 
1206
        my $tmp= $type->[2];
 
1207
        $tmp .= " from crash_me ";
 
1208
        undef($limits{"func_$types->[0]_$type->[1]"});
 
1209
        check_and_report("Function $type->[0]",
 
1210
                         "func_$types->[0]_$type->[1]",
 
1211
                         [],"select $tmp ",[],
 
1212
                         $type->[3],$type->[4]);
 
1213
      }
 
1214
      else
 
1215
      {
 
1216
        undef($limits{"func_$types->[0]_$type->[1]"});
 
1217
        $result = check_and_report("Function $type->[0]",
 
1218
                            "func_$types->[0]_$type->[1]",
 
1219
                            [],"select $type->[2] $end_query",[],
 
1220
                            $type->[3],$type->[4]);
 
1221
        if (!$result)
 
1222
        {
 
1223
          # check without type specifyer
 
1224
          if ($type->[2] =~ /DATE /)
 
1225
          {
 
1226
            my $tmp= $type->[2];
 
1227
            $tmp =~ s/DATE //;
 
1228
            undef($limits{"func_$types->[0]_$type->[1]"});
 
1229
            $result = check_and_report("Function $type->[0]",
 
1230
                                  "func_$types->[0]_$type->[1]",
 
1231
                                  [],"select $tmp $end_query",[],
 
1232
                                  $type->[3],$type->[4]);
 
1233
          }
 
1234
          if (!$result)
 
1235
          {
 
1236
            if ($types->[0] eq "odbc" && ! ($type->[2] =~ /\{fn/))
 
1237
            {
 
1238
             my $tmp= $type->[2];
 
1239
             # Check by converting to ODBC format
 
1240
             undef($limits{"func_$types->[0]_$type->[1]"});
 
1241
             $tmp= "{fn $tmp }";
 
1242
             $tmp =~ s/('1997-\d\d-\d\d \d\d:\d\d:\d\d')/{ts $1}/g;
 
1243
             $tmp =~ s/(DATE '1997-\d\d-\d\d')/{d $1}/g;
 
1244
             $tmp =~ s/(TIME '12:13:14')/{t $1}/g;
 
1245
             $tmp =~ s/DATE //;
 
1246
             $tmp =~ s/TIME //;
 
1247
             check_and_report("Function $type->[0]",
 
1248
                              "func_$types->[0]_$type->[1]",
 
1249
                              [],"select $tmp $end_query",[],
 
1250
                              $type->[3],$type->[4]);
 
1251
            }
 
1252
          }
 
1253
        }
 
1254
      }
 
1255
    }
 
1256
  }
 
1257
}
 
1258
 
 
1259
if ($limits{'functions'} eq 'yes')
 
1260
{
 
1261
  foreach $types (@group_types)
 
1262
  {
 
1263
    print "\nSupported $types->[0] group functions\n";
 
1264
    $tmp=@$types->[1];
 
1265
    foreach $type (@$tmp)
 
1266
    {
 
1267
      check_and_report("Group function $type->[0]",
 
1268
                       "group_func_$types->[0]_$type->[1]",
 
1269
                       [],"select $type->[2],a from crash_me group by a",[],
 
1270
                       $type->[3],$type->[4]);
 
1271
    }
 
1272
  }
 
1273
  print "\n";
 
1274
  report("mixing of integer and float in expression","float_int_expr",
 
1275
         "select 1+1.0 $end_query");
 
1276
  if ($limits{'func_odbc_exp'} eq 'yes')
 
1277
  {
 
1278
    report("No need to cast from integer to float",
 
1279
           "dont_require_cast_to_float", "select exp(1) $end_query");
 
1280
  }
 
1281
  check_and_report("Is 1+NULL = NULL","null_num_expr",
 
1282
                   [],"select 1+$numeric_null $end_query",[],undef(),4);
 
1283
  $tmp=sql_concat("'a'",$char_null);
 
1284
  if (defined($tmp))
 
1285
  {
 
1286
    check_and_report("Is $tmp = NULL", "null_concat_expr", [],
 
1287
                     "select $tmp $end_query",[], undef(),4);
 
1288
  }
 
1289
  $prompt="Need to cast NULL for arithmetic";
 
1290
  add_log("Need_cast_for_null",
 
1291
    " Check if numeric_null ($numeric_null) is 'NULL'");
 
1292
  save_config_data("Need_cast_for_null",
 
1293
                   ($numeric_null eq "NULL") ? "no" : "yes",
 
1294
                   $prompt);
 
1295
}
 
1296
else
 
1297
{
 
1298
  print "\n";
 
1299
}
 
1300
 
 
1301
 
 
1302
#  Test: NOROUND 
 
1303
{
 
1304
 my $result = 'undefined';
 
1305
 my $error;
 
1306
 print "NOROUND: ";
 
1307
 save_incomplete('func_extra_noround','Function NOROUND');
 
1308
 
 
1309
# 1) check if noround() function is supported
 
1310
 $error = safe_query_l('func_extra_noround',"select noround(22.6) $end_query");
 
1311
 if ($error ne 1)         # syntax error -- noround is not supported 
 
1312
 {
 
1313
   $result = 'no'
 
1314
 }
 
1315
 else                   # Ok, now check if it really works
 
1316
 {
 
1317
   $error=safe_query_l('func_extra_noround', 
 
1318
     ["create table crash_me_nr (a int)",
 
1319
    "insert into crash_me_nr values(noround(10.2))",
 
1320
    "drop table crash_me_nr $drop_attr"]);
 
1321
   if ($error == 1)
 
1322
   {
 
1323
     $result= "syntax only";
 
1324
   }
 
1325
   else
 
1326
   {
 
1327
     $result= 'yes';
 
1328
   }
 
1329
 }
 
1330
 print "$result\n";
 
1331
 save_config_data('func_extra_noround',$result,"Function NOROUND");
 
1332
}
 
1333
 
 
1334
check_parenthesis("func_sql_","CURRENT_USER");
 
1335
check_parenthesis("func_sql_","SESSION_USER");
 
1336
check_parenthesis("func_sql_","SYSTEM_USER");
 
1337
check_parenthesis("func_sql_","USER");
 
1338
 
 
1339
 
 
1340
if ($limits{'type_sql_date'} eq 'yes')
 
1341
{  # 
 
1342
   # Checking the format of date in result. 
 
1343
   
 
1344
    safe_query("drop table crash_me_d $drop_attr");
 
1345
    assert_crash("create table crash_me_d (a date)");
 
1346
    # find the example of date
 
1347
    my $dateexample;
 
1348
    if ($limits{'func_extra_sysdate'} eq 'yes') {
 
1349
     $dateexample=' sysdate() ';
 
1350
    } 
 
1351
    elsif ($limits{'func_sql_current_date'} eq 'yes') {
 
1352
     $dateexample='CURRENT_DATE';
 
1353
    } 
 
1354
    elsif ($limits{'func_odbc_curdate'} eq 'yes') {
 
1355
     $dateexample='curdate()';
 
1356
    } 
 
1357
    elsif ($limits{'func_extra_getdate'} eq 'yes') {
 
1358
        $dateexample='getdate()';
 
1359
    }
 
1360
    elsif ($limits{'func_odbc_now'} eq 'yes') {
 
1361
        $dateexample='now()';
 
1362
    } else {
 
1363
        #try to guess 
 
1364
        $dateexample="DATE '1963-08-16'";
 
1365
    } ;
 
1366
    
 
1367
    my $key = 'date_format_inresult';
 
1368
    my $prompt = "Date format in result";
 
1369
    if (! safe_query_l('date_format_inresult',
 
1370
       "insert into crash_me_d values($dateexample) "))
 
1371
    { 
 
1372
        die "Cannot insert date ($dateexample):".$last_error; 
 
1373
    };
 
1374
    my $sth= $dbh->prepare("select a from crash_me_d");
 
1375
    add_log('date_format_inresult',"< select a from crash_me_d");
 
1376
    $sth->execute;
 
1377
    $_= $sth->fetchrow_array;
 
1378
    add_log('date_format_inresult',"> $_");
 
1379
    safe_query_l($key,"delete from crash_me_d");   
 
1380
    if (/\d{4}-\d{2}-\d{2}/){ save_config_data($key,"iso",$prompt);} 
 
1381
    elsif (/\d{2}-\d{2}-\d{2}/){ save_config_data($key,"short iso",$prompt);}
 
1382
    elsif (/\d{2}\.\d{2}\.\d{4}/){ save_config_data($key,"euro",$prompt);}
 
1383
    elsif (/\d{2}\.\d{2}\.\d{2}/){ save_config_data($key,"short euro",$prompt);}
 
1384
    elsif (/\d{2}\/\d{2}\/\d{4}/){ save_config_data($key,"usa",$prompt);}
 
1385
    elsif (/\d{2}\/\d{2}\/\d{2}/){ save_config_data($key,"short usa",$prompt);}
 
1386
    elsif (/\d*/){ save_config_data($key,"YYYYMMDD",$prompt);}
 
1387
    else  { save_config_data($key,"unknown",$prompt);};
 
1388
    $sth->finish;
 
1389
 
 
1390
    check_and_report("Supports YYYY-MM-DD (ISO) format","date_format_ISO",
 
1391
                     [ "insert into crash_me_d(a)  values ('1963-08-16')"],
 
1392
                     "select a from crash_me_d",
 
1393
                     ["delete from crash_me_d"],
 
1394
                     make_date_r(1963,8,16),1);
 
1395
 
 
1396
    check_and_report("Supports DATE 'YYYY-MM-DD' (ISO) format",
 
1397
                     "date_format_ISO_with_date",
 
1398
                     [ "insert into crash_me_d(a) values (DATE '1963-08-16')"],
 
1399
                     "select a from crash_me_d",
 
1400
                     ["delete from crash_me_d"],
 
1401
                     make_date_r(1963,8,16),1);
 
1402
 
 
1403
    check_and_report("Supports DD.MM.YYYY (EUR) format","date_format_EUR",
 
1404
                     [ "insert into crash_me_d(a) values ('16.08.1963')"],
 
1405
                     "select a from crash_me_d",
 
1406
                     ["delete from crash_me_d"],
 
1407
                     make_date_r(1963,8,16),1);
 
1408
    check_and_report("Supports DATE 'DD.MM.YYYY' (EUR) format",
 
1409
                     "date_format_EUR_with_date",
 
1410
                     [ "insert into crash_me_d(a) values (DATE '16.08.1963')"],
 
1411
                     "select a from crash_me_d",
 
1412
                     ["delete from crash_me_d"],
 
1413
                     make_date_r(1963,8,16),1);
 
1414
 
 
1415
    check_and_report("Supports YYYYMMDD format",
 
1416
         "date_format_YYYYMMDD",
 
1417
         [ "insert into crash_me_d(a) values ('19630816')"],
 
1418
         "select a from crash_me_d",
 
1419
         ["delete from crash_me_d"],
 
1420
         make_date_r(1963,8,16),1);
 
1421
    check_and_report("Supports DATE 'YYYYMMDD' format",
 
1422
         "date_format_YYYYMMDD_with_date",
 
1423
         [ "insert into crash_me_d(a) values (DATE '19630816')"],
 
1424
         "select a from crash_me_d",
 
1425
         ["delete from crash_me_d"],
 
1426
         make_date_r(1963,8,16),1);
 
1427
 
 
1428
    check_and_report("Supports MM/DD/YYYY format",
 
1429
         "date_format_USA",
 
1430
         [ "insert into crash_me_d(a) values ('08/16/1963')"],
 
1431
         "select a from crash_me_d",
 
1432
         ["delete from crash_me_d"],
 
1433
         make_date_r(1963,8,16),1);
 
1434
    check_and_report("Supports DATE 'MM/DD/YYYY' format",
 
1435
         "date_format_USA_with_date",
 
1436
         [ "insert into crash_me_d(a) values (DATE '08/16/1963')"],
 
1437
         "select a from crash_me_d",
 
1438
         ["delete from crash_me_d"],
 
1439
         make_date_r(1963,8,16),1);
 
1440
 
 
1441
 
 
1442
 
 
1443
 
 
1444
    check_and_report("Supports 0000-00-00 dates","date_zero",
 
1445
         ["create table crash_me2 (a date not null)",
 
1446
          "insert into crash_me2 values (".make_date(0,0,0).")"],
 
1447
         "select a from crash_me2",
 
1448
         ["drop table crash_me2 $drop_attr"],
 
1449
         make_date_r(0,0,0),1);
 
1450
 
 
1451
    check_and_report("Supports 0001-01-01 dates","date_one",
 
1452
         ["create table crash_me2 (a date not null)",
 
1453
          "insert into crash_me2 values (".make_date(1,1,1).")"],
 
1454
         "select a from crash_me2",
 
1455
         ["drop table crash_me2 $drop_attr"],
 
1456
         make_date_r(1,1,1),1);
 
1457
    
 
1458
    check_and_report("Supports 9999-12-31 dates","date_last",
 
1459
        ["create table crash_me2 (a date not null)",
 
1460
        "insert into crash_me2 values (".make_date(9999,12,31).")"],
 
1461
        "select a from crash_me2",
 
1462
        ["drop table crash_me2 $drop_attr"],
 
1463
        make_date_r(9999,12,31),1);
 
1464
    
 
1465
    check_and_report("Supports 'infinity dates","date_infinity",
 
1466
         ["create table crash_me2 (a date not null)",
 
1467
         "insert into crash_me2 values ('infinity')"],
 
1468
         "select a from crash_me2",
 
1469
         ["drop table crash_me2 $drop_attr"],
 
1470
         "infinity",1);
 
1471
    
 
1472
    if (!defined($limits{'date_with_YY'}))
 
1473
    {
 
1474
        check_and_report("Supports YY-MM-DD dates","date_with_YY",
 
1475
           ["create table crash_me2 (a date not null)",
 
1476
           "insert into crash_me2 values ('98-03-03')"],
 
1477
           "select a from crash_me2",
 
1478
           ["drop table crash_me2 $drop_attr"],
 
1479
           make_date_r(1998,3,3),5);
 
1480
        if ($limits{'date_with_YY'} eq "yes")
 
1481
        {
 
1482
            undef($limits{'date_with_YY'});
 
1483
            check_and_report("Supports YY-MM-DD 2000 compilant dates",
 
1484
               "date_with_YY",
 
1485
               ["create table crash_me2 (a date not null)",
 
1486
               "insert into crash_me2 values ('10-03-03')"],
 
1487
               "select a from crash_me2",
 
1488
               ["drop table crash_me2 $drop_attr"],
 
1489
               make_date_r(2010,3,3),5);
 
1490
        }
 
1491
    }
 
1492
    
 
1493
# Test: WEEK()
 
1494
    {
 
1495
        my $result="no";
 
1496
        my $error;
 
1497
        print "WEEK:";
 
1498
        save_incomplete('func_odbc_week','WEEK');
 
1499
        $error = safe_query_result_l('func_odbc_week',
 
1500
             "select week(".make_date(1997,2,1).") $end_query",5,0);
 
1501
        # actually this query must return 4 or 5 in the $last_result,
 
1502
        # $error can be 1 (not supported at all) , -1 ( probably USA weeks)
 
1503
        # and 0 - EURO weeks
 
1504
        if ($error == -1) { 
 
1505
            if ($last_result == 4) {
 
1506
                $result = 'USA';
 
1507
            } else {
 
1508
                $result='error';
 
1509
                add_log('func_odbc_week',
 
1510
                  " must return 4 or 5, but $last_result");
 
1511
            }
 
1512
        } elsif ($error == 0) {
 
1513
            $result = 'EURO';
 
1514
        }
 
1515
        print " $result\n";
 
1516
        save_config_data('func_odbc_week',$result,"WEEK");
 
1517
    }
 
1518
    
 
1519
    my $insert_query ='insert into crash_me_d values('.
 
1520
        make_date(1997,2,1).')';
 
1521
    safe_query($insert_query);
 
1522
    
 
1523
    foreach $fn ( (
 
1524
                   ["DAYNAME","dayname","dayname(a)","",2],
 
1525
                   ["MONTH","month","month(a)","",2],
 
1526
                   ["MONTHNAME","monthname","monthname(a)","",2],
 
1527
                   ["DAYOFMONTH","dayofmonth","dayofmonth(a)",1,0],
 
1528
                   ["DAYOFWEEK","dayofweek","dayofweek(a)",7,0],
 
1529
                   ["DAYOFYEAR","dayofyear","dayofyear(a)",32,0],
 
1530
                   ["QUARTER","quarter","quarter(a)",1,0],
 
1531
                   ["YEAR","year","year(a)",1997,0]))
 
1532
    {
 
1533
        $prompt='Function '.$fn->[0];
 
1534
        $key='func_odbc_'.$fn->[1];
 
1535
        add_log($key,"< ".$insert_query);
 
1536
        check_and_report($prompt,$key,
 
1537
                         [],"select ".$fn->[2]." from crash_me_d",[],
 
1538
                         $fn->[3],$fn->[4]
 
1539
                         );
 
1540
        
 
1541
    };
 
1542
    safe_query(['delete from crash_me_d', 
 
1543
                'insert into crash_me_d values('.make_date(1963,8,16).')']);
 
1544
    foreach $fn ((
 
1545
          ["DATEADD","dateadd","dateadd(day,3,make_date(1997,11,30))",0,2],
 
1546
          ["MDY","mdy","mdy(7,1,1998)","make_date_r(1998,07,01)",0], # informix
 
1547
          ["DATEDIFF","datediff",
 
1548
             "datediff(month,'Oct 21 1997','Nov 30 1997')",0,2],
 
1549
          ["DATENAME","datename","datename(month,'Nov 30 1997')",0,2],
 
1550
          ["DATEPART","datepart","datepart(month,'July 20 1997')",0,2],
 
1551
          ["DATE_FORMAT","date_format", 
 
1552
            "date_format('1997-01-02 03:04:05','M W D Y y m d h i s w')", 0,2],
 
1553
          ["FROM_DAYS","from_days",
 
1554
            "from_days(729024)","make_date_r(1996,1,1)",1],
 
1555
          ["FROM_UNIXTIME","from_unixtime","from_unixtime(0)",0,2],
 
1556
          ["MONTHS_BETWEEN","months_between",
 
1557
           "months_between(make_date(1997,2,2),make_date(1997,1,1))",
 
1558
           "1.03225806",0], # oracle number of months between 2 dates
 
1559
          ["PERIOD_ADD","period_add","period_add(9602,-12)",199502,0],
 
1560
          ["PERIOD_DIFF","period_diff","period_diff(199505,199404)",13,0],
 
1561
          ["WEEKDAY","weekday","weekday(make_date(1997,11,29))",5,0],
 
1562
          ["ADDDATE",'adddate',
 
1563
           "ADDDATE(make_date(2002,12,01),3)",'make_date_r(2002,12,04)',0],
 
1564
          ["SUBDATE",'subdate',
 
1565
           "SUBDATE(make_date(2002,12,04),3)",'make_date_r(2002,12,01)',0],
 
1566
          ["DATEDIFF (2 arg)",'datediff2arg',
 
1567
           "DATEDIFF(make_date(2002,12,04),make_date(2002,12,01))",'3',0],
 
1568
          ["WEEKOFYEAR",'weekofyear',
 
1569
           "WEEKOFYEAR(make_date(1963,08,16))",'33',0],
 
1570
# table crash_me_d must contain  record with 1963-08-16 (for CHAR)
 
1571
          ["CHAR (conversation date)",'char_date',
 
1572
           "CHAR(a,EUR)",'16.08.1963',0],
 
1573
          ["MAKEDATE",'makedate',"MAKEDATE(1963,228)"
 
1574
           ,'make_date_r(1963,08,16)',0],
 
1575
          # Drizzle is different than MySQL in handling TO_DAYS
 
1576
          # Drizzle calculates the Julian Day Number
 
1577
          # ["TO_DAYS","to_days",
 
1578
          #   "to_days(make_date(1996,01,01))",729024,0],
 
1579
          ["TO_DAYS","to_days",
 
1580
            "to_days(make_date(1996,01,01))",2450084,0],
 
1581
          ["ADD_MONTHS","add_months",
 
1582
           "add_months(make_date(1997,01,01),1)","make_date_r(1997,02,01)",0], 
 
1583
              # oracle the date plus n months
 
1584
          ["LAST_DAY","last_day",
 
1585
          "last_day(make_date(1997,04,01))","make_date_r(1997,04,30)",0], 
 
1586
              # oracle last day of month of date
 
1587
          ["DATE",'date',"date(make_date(1963,8,16))",
 
1588
             'make_date_r(1963,8,16)',0],
 
1589
          ["DAY",'day',"DAY(make_date(2002,12,01))",1,0]))
 
1590
    {
 
1591
        $prompt='Function '.$fn->[0];
 
1592
        $key='func_extra_'.$fn->[1];
 
1593
        my $qry="select ".$fn->[2]." from crash_me_d";
 
1594
        while( $qry =~ /^(.*)make_date\((\d+),(\d+),(\d+)\)(.*)$/)
 
1595
        {
 
1596
            my $dt= &make_date($2,$3,$4);
 
1597
            $qry=$1.$dt.$5;
 
1598
        };
 
1599
        my $result=$fn->[3];
 
1600
        while( $result =~ /^(.*)make_date_r\((\d+),(\d+),(\d+)\)(.*)$/)
 
1601
        {
 
1602
            my $dt= &make_date_r($2,$3,$4);
 
1603
            $result=$1.$dt.$5;
 
1604
        };
 
1605
        check_and_report($prompt,$key,
 
1606
                         [],$qry,[],
 
1607
                         $result,$fn->[4]
 
1608
                         );
 
1609
        
 
1610
    }
 
1611
    
 
1612
    safe_query("drop table crash_me_d $drop_attr");    
 
1613
    
 
1614
}
 
1615
 
 
1616
if ($limits{'type_sql_time'} eq 'yes')
 
1617
{  # 
 
1618
   # Checking the format of date in result. 
 
1619
   
 
1620
    safe_query("drop table crash_me_t $drop_attr");
 
1621
    assert_crash("create table crash_me_t (a time)");
 
1622
    # find the example of time
 
1623
    my $timeexample;
 
1624
    if ($limits{'func_sql_current_time'} eq 'yes') {
 
1625
     $timeexample='CURRENT_TIME';
 
1626
    } 
 
1627
    elsif ($limits{'func_odbc_curtime'} eq 'yes') {
 
1628
     $timeexample='curtime()';
 
1629
    } 
 
1630
    elsif ($limits{'func_sql_localtime'} eq 'yes') {
 
1631
        $timeexample='localtime';
 
1632
    }
 
1633
    elsif ($limits{'func_odbc_now'} eq 'yes') {
 
1634
        $timeexample='now()';
 
1635
    } else {
 
1636
        #try to guess 
 
1637
        $timeexample="'02:55:12'";
 
1638
    } ;
 
1639
    
 
1640
    my $key = 'time_format_inresult';
 
1641
    my $prompt = "Time format in result";
 
1642
    if (! safe_query_l('time_format_inresult',
 
1643
       "insert into crash_me_t values($timeexample) "))
 
1644
    { 
 
1645
        die "Cannot insert time ($timeexample):".$last_error; 
 
1646
    };
 
1647
    my $sth= $dbh->prepare("select a from crash_me_t");
 
1648
    add_log('time_format_inresult',"< select a from crash_me_t");
 
1649
    $sth->execute;
 
1650
    $_= $sth->fetchrow_array;
 
1651
    add_log('time_format_inresult',"> $_");
 
1652
    safe_query_l($key,"delete from crash_me_t");   
 
1653
    if (/\d{2}:\d{2}:\d{2}/){ save_config_data($key,"iso",$prompt);} 
 
1654
    elsif (/\d{2}\.\d{2}\.\d{2}/){ save_config_data($key,"euro",$prompt);}
 
1655
    elsif (/\d{2}:\d{2}\s+(AM|PM)/i){ save_config_data($key,"usa",$prompt);}
 
1656
    elsif (/\d{8}$/){ save_config_data($key,"HHHHMMSS",$prompt);}
 
1657
    elsif (/\d{4}$/){ save_config_data($key,"HHMMSS",$prompt);}
 
1658
    else  { save_config_data($key,"unknown",$prompt);};
 
1659
    $sth->finish;
 
1660
 
 
1661
    check_and_report("Supports HH:MM:SS (ISO) time format","time_format_ISO",
 
1662
                     [ "insert into crash_me_t(a)  values ('20:08:16')"],
 
1663
                     "select a from crash_me_t",
 
1664
                     ["delete from crash_me_t"],
 
1665
                     make_time_r(20,8,16),1);
 
1666
 
 
1667
    check_and_report("Supports HH.MM.SS (EUR) time format","time_format_EUR",
 
1668
                     [ "insert into crash_me_t(a) values ('20.08.16')"],
 
1669
                     "select a from crash_me_t",
 
1670
                     ["delete from crash_me_t"],
 
1671
                     make_time_r(20,8,16),1);
 
1672
 
 
1673
    check_and_report("Supports HHHHmmSS time format",
 
1674
         "time_format_HHHHMMSS",
 
1675
         [ "insert into crash_me_t(a) values ('00200816')"],
 
1676
         "select a from crash_me_t",
 
1677
         ["delete from crash_me_t"],
 
1678
         make_time_r(20,8,16),1);
 
1679
 
 
1680
    check_and_report("Supports HHmmSS time format",
 
1681
         "time_format_HHHHMMSS",
 
1682
         [ "insert into crash_me_t(a) values ('200816')"],
 
1683
         "select a from crash_me_t",
 
1684
         ["delete from crash_me_t"],
 
1685
         make_time_r(20,8,16),1);
 
1686
         
 
1687
    check_and_report("Supports HH:MM:SS (AM|PM) time format",
 
1688
         "time_format_USA",
 
1689
         [ "insert into crash_me_t(a) values ('08:08:16 PM')"],
 
1690
         "select a from crash_me_t",
 
1691
         ["delete from crash_me_t"],
 
1692
         make_time_r(20,8,16),1);        
 
1693
    
 
1694
    my $insert_query ='insert into crash_me_t values('.
 
1695
        make_time(20,8,16).')';
 
1696
    safe_query($insert_query);
 
1697
    
 
1698
    foreach $fn ( (
 
1699
            ["HOUR","hour","hour('".make_time(12,13,14)."')",12,0],
 
1700
            ["ANSI HOUR","hour_time","hour(TIME '".make_time(12,13,14)."')",12,0],
 
1701
            ["MINUTE","minute","minute('".make_time(12,13,14)."')",13,0],
 
1702
            ["SECOND","second","second('".make_time(12,13,14)."')",14,0]
 
1703
 
 
1704
    ))
 
1705
    {
 
1706
        $prompt='Function '.$fn->[0];
 
1707
        $key='func_odbc_'.$fn->[1];
 
1708
        add_log($key,"< ".$insert_query);
 
1709
        check_and_report($prompt,$key,
 
1710
                         [],"select ".$fn->[2]." $end_query",[],
 
1711
                         $fn->[3],$fn->[4]
 
1712
                         );
 
1713
        
 
1714
    };
 
1715
#    safe_query(['delete from crash_me_t', 
 
1716
#               'insert into crash_me_t values('.make_time(20,8,16).')']);
 
1717
    foreach $fn ((
 
1718
         ["TIME_TO_SEC","time_to_sec","time_to_sec('".
 
1719
                  make_time(1,23,21)."')","5001",0],
 
1720
         ["SEC_TO_TIME","sec_to_time","sec_to_time(5001)",
 
1721
              make_time_r(01,23,21),1],
 
1722
         ["ADDTIME",'addtime',"ADDTIME('".make_time(20,2,12).
 
1723
            "','".make_time(0,0,3)."')",make_time_r(20,2,15),0],
 
1724
         ["SUBTIME",'subtime',"SUBTIME('".make_time(20,2,15)
 
1725
                  ."','".make_time(0,0,3)."')",make_time_r(20,2,12),0],
 
1726
         ["TIMEDIFF",'timediff',"TIMEDIFF('".make_time(20,2,15)."','".
 
1727
         make_time(20,2,12)."')",make_time_r(0,0,3),0],
 
1728
         ["MAKETIME",'maketime',"MAKETIME(20,02,12)",make_time_r(20,2,12),0],
 
1729
         ["TIME",'time',"time('".make_time(20,2,12)."')",make_time_r(20,2,12),0]
 
1730
    ))
 
1731
    {
 
1732
        $prompt='Function '.$fn->[0];
 
1733
        $key='func_extra_'.$fn->[1];
 
1734
        my $qry="select ".$fn->[2]." $end_query";
 
1735
        my $result=$fn->[3];
 
1736
        check_and_report($prompt,$key,
 
1737
                         [],$qry,[],
 
1738
                         $result,$fn->[4]
 
1739
                         );
 
1740
        
 
1741
    }
 
1742
    
 
1743
    safe_query("drop table crash_me_t $drop_attr");    
 
1744
    
 
1745
}
 
1746
 
 
1747
 
 
1748
# NOT id BETWEEN a and b
 
1749
if ($limits{'func_where_not_between'} eq 'yes')
 
1750
{
 
1751
   my $result = 'error';
 
1752
   my $err;
 
1753
   my $key='not_id_between';
 
1754
   my $prompt='NOT ID BETWEEN interprets as ID NOT BETWEEN';
 
1755
   print "$prompt:";
 
1756
   save_incomplete($key,$prompt);
 
1757
   safe_query_l($key,["create table crash_me_b (i int)",
 
1758
         "insert into crash_me_b values(2)",
 
1759
         "insert into crash_me_b values(5)"]);
 
1760
   $err =safe_query_result_l($key,
 
1761
    "select i from crash_me_b where not i between 1 and 3",
 
1762
     5,0);
 
1763
   if ($err eq 1) {
 
1764
      if (not defined($last_result)) {
 
1765
        $result='no';
 
1766
      };
 
1767
   };
 
1768
   if ( $err eq 0) {
 
1769
      $result = 'yes';
 
1770
   };
 
1771
   safe_query_l($key,["drop table crash_me_b"]);
 
1772
   save_config_data($key,$result,$prompt);
 
1773
   print "$result\n";
 
1774
};
 
1775
 
 
1776
 
 
1777
 
 
1778
 
 
1779
report("LIKE on numbers","like_with_number",
 
1780
       "create table crash_q (a int,b int)",
 
1781
       "insert into crash_q values(10,10)",
 
1782
       "select * from crash_q where a like '10'",
 
1783
       "drop table crash_q $drop_attr");
 
1784
 
 
1785
report("column LIKE column","like_with_column",
 
1786
       "create table crash_q (a char(10),b char(10))",
 
1787
       "insert into crash_q values('abc','abc')",
 
1788
       "select * from crash_q where a like b",
 
1789
       "drop table crash_q $drop_attr");
 
1790
 
 
1791
report("update of column= -column","NEG",
 
1792
       "create table crash_q (a integer)",
 
1793
       "insert into crash_q values(10)",
 
1794
       "update crash_q set a=-a",
 
1795
       "drop table crash_q $drop_attr");
 
1796
 
 
1797
if ($limits{'func_odbc_left'} eq 'yes' ||
 
1798
    $limits{'func_odbc_substring'} eq 'yes')
 
1799
{
 
1800
  my $type= ($limits{'func_odbc_left'} eq 'yes' ?
 
1801
             "left(a,4)" : "substring(a for 4)");
 
1802
 
 
1803
    check_and_report("String functions on date columns","date_as_string",
 
1804
                     ["create table crash_me2 (a date not null)",
 
1805
                      "insert into crash_me2 values ('1998-03-03')"],
 
1806
                     "select $type from crash_me2",
 
1807
                     ["drop table crash_me2 $drop_attr"],
 
1808
                     "1998",1);
 
1809
}
 
1810
 
 
1811
 
 
1812
$tmp=sql_concat("b","b");
 
1813
if (defined($tmp))
 
1814
{
 
1815
  check_and_report("char are space filled","char_is_space_filled",
 
1816
                   [],"select $tmp from crash_me where b = 'a         '",[],
 
1817
                   'a         a         ',6);
 
1818
}
 
1819
 
 
1820
if (!defined($limits{'multi_table_update'}))
 
1821
{
 
1822
  if (check_and_report("Update with many tables","multi_table_update",
 
1823
           ["create table crash_q (a integer,b char(10))",
 
1824
            "insert into crash_q values(1,'c')",
 
1825
            "update crash_q left join crash_me on crash_q.a=crash_me.a set crash_q.b=crash_me.b"],
 
1826
            "select b from crash_q",
 
1827
           ["drop table crash_q $drop_attr"],
 
1828
           "a",1,undef(),2))
 
1829
  {
 
1830
    check_and_report("Update with many tables","multi_table_update",
 
1831
             ["create table crash_q (a integer,b char(10))",
 
1832
              "insert into crash_q values(1,'c')",
 
1833
              "update crash_q,crash_me set crash_q.b=crash_me.b ".
 
1834
              "where crash_q.a=crash_me.a"],
 
1835
             "select b from crash_q",
 
1836
             ["drop table crash_q $drop_attr"],
 
1837
                     "a",1,
 
1838
                    1);
 
1839
  }
 
1840
}
 
1841
 
 
1842
report("DELETE FROM table1,table2...","multi_table_delete",
 
1843
       "create table crash_q (a integer,b char(10))",
 
1844
       "insert into crash_q values(1,'c')",
 
1845
       "delete crash_q.* from crash_q,crash_me where crash_q.a=crash_me.a",
 
1846
       "drop table crash_q $drop_attr");
 
1847
 
 
1848
check_and_report("Update with sub select","select_table_update",
 
1849
                 ["create table crash_q (a integer,b char(10))",
 
1850
                  "insert into crash_q values(1,'c')",
 
1851
                  "update crash_q set b= ".
 
1852
                  "(select b from crash_me where crash_q.a = crash_me.a)"],
 
1853
                 "select b from crash_q",
 
1854
                 ["drop table crash_q $drop_attr"],
 
1855
                 "a",1);
 
1856
 
 
1857
check_and_report("Calculate 1--1","minus_neg",[],
 
1858
                 "select a--1 from crash_me",[],0,2);
 
1859
 
 
1860
report("ANSI SQL simple joins","simple_joins",
 
1861
       "select crash_me.a from crash_me, crash_me t0");
 
1862
 
 
1863
#
 
1864
# Check max string size, and expression limits
 
1865
#
 
1866
$found=undef;
 
1867
foreach $type (('mediumtext','text','text()','blob','long'))
 
1868
{
 
1869
  if ($limits{"type_extra_$type"} eq 'yes')
 
1870
  {
 
1871
    $found=$type;
 
1872
    last;
 
1873
  }
 
1874
}
 
1875
if (defined($found))
 
1876
{
 
1877
  $found =~ s/\(\)/\(%d\)/;
 
1878
  find_limit("max text or blob size","max_text_size",
 
1879
             new query_many(["create table crash_q (q $found)",
 
1880
                             "insert into crash_q values ('%s')"],
 
1881
                            "select * from crash_q","%s",
 
1882
                            ["drop table crash_q $drop_attr"],
 
1883
                            min($max_string_size,$limits{'query_size'}-30)));
 
1884
 
 
1885
}
 
1886
 
 
1887
# It doesn't make lots of sense to check for string lengths much bigger than
 
1888
# what can be stored...
 
1889
 
 
1890
find_limit(($prompt="constant string size in where"),"where_string_size",
 
1891
           new query_repeat([],"select a from crash_me where b >='",
 
1892
                            "","","1","","'"));
 
1893
if ($limits{'where_string_size'} == 10)
 
1894
{
 
1895
  save_config_data('where_string_size','nonstandard',$prompt);
 
1896
}
 
1897
 
 
1898
if ($limits{'select_constants'} eq 'yes')
 
1899
{
 
1900
  find_limit("constant string size in SELECT","select_string_size",
 
1901
             new query_repeat([],"select '","","","a","","'$end_query"));
 
1902
}
 
1903
 
 
1904
goto no_functions if ($limits{'functions'} ne "yes");
 
1905
 
 
1906
if ($limits{'func_odbc_repeat'} eq 'yes')
 
1907
{
 
1908
  find_limit("return string size from function","repeat_string_size",
 
1909
             new query_many([],
 
1910
                            "select repeat('a',%d) $end_query","%s",
 
1911
                            [],
 
1912
                            $max_string_size,0));
 
1913
}
 
1914
 
 
1915
$tmp=find_limit("simple expressions","max_expressions",
 
1916
                new query_repeat([],"select 1","","","+1","",$end_query,
 
1917
                                 undef(),$max_expressions));
 
1918
 
 
1919
if ($tmp > 10)
 
1920
{
 
1921
  $tmp= "(1" . ( '+1' x ($tmp-10) ) . ")";
 
1922
  find_limit("big expressions", "max_big_expressions",
 
1923
             new query_repeat([],"select 0","","","+$tmp","",$end_query,
 
1924
                              undef(),$max_big_expressions));
 
1925
}
 
1926
 
 
1927
find_limit("stacked expressions", "max_stack_expression",
 
1928
           new query_repeat([],"select 1","","","+(1",")",$end_query,
 
1929
                                undef(),$max_stacked_expressions));
 
1930
 
 
1931
no_functions:
 
1932
 
 
1933
if (!defined($limits{'max_conditions'}))
 
1934
{
 
1935
  find_limit("OR and AND in WHERE","max_conditions",
 
1936
             new query_repeat([],
 
1937
                              "select a from crash_me where a=1 and b='a'","",
 
1938
                              "", " or a=%d and b='%d'","","","",
 
1939
                              [],($query_size-42)/29,undef,2));
 
1940
  $limits{'max_conditions'}*=2;
 
1941
}
 
1942
# The 42 is the length of the constant part.
 
1943
# The 29 is the length of the variable part, plus two seven-digit numbers.
 
1944
 
 
1945
find_limit("tables in join", "join_tables",
 
1946
           new query_repeat([],
 
1947
                            "select crash_me.a",",t%d.a","from crash_me",
 
1948
                            ",crash_me t%d","","",[],$max_join_tables,undef,
 
1949
                            1));
 
1950
 
 
1951
# Different CREATE TABLE options
 
1952
 
 
1953
report("primary key in create table",'primary_key_in_create',
 
1954
       "create table crash_q (q integer not null,primary key (q))",
 
1955
       "drop table crash_q $drop_attr");
 
1956
 
 
1957
report("unique in create table",'unique_in_create',
 
1958
       "create table crash_q (q integer not null,unique (q))",
 
1959
       "drop table crash_q $drop_attr");
 
1960
 
 
1961
if ($limits{'unique_in_create'} eq 'yes')
 
1962
{
 
1963
  report("unique null in create",'unique_null_in_create',
 
1964
         "create table crash_q (q integer,unique (q))",
 
1965
         "insert into crash_q (q) values (NULL)",
 
1966
         "insert into crash_q (q) values (NULL)",
 
1967
         "insert into crash_q (q) values (1)",
 
1968
         "drop table crash_q $drop_attr");
 
1969
}
 
1970
 
 
1971
report("default value for column",'create_default',
 
1972
       "create table crash_q (q integer default 10 not null)",
 
1973
       "drop table crash_q $drop_attr");
 
1974
 
 
1975
report("default value function for column",'create_default_func',
 
1976
       "create table crash_q (q integer not null,q1 integer default (1+1))",
 
1977
       "drop table crash_q $drop_attr");
 
1978
 
 
1979
report("temporary tables",'temporary_table',
 
1980
       "create temporary table crash_q (q integer not null)",
 
1981
       "drop table crash_q $drop_attr");
 
1982
 
 
1983
report_one("create table from select",'create_table_select',
 
1984
           [["create table crash_q SELECT * from crash_me","yes"],
 
1985
            ["create table crash_q AS SELECT * from crash_me","with AS"]]);
 
1986
$dbh->do("drop table crash_q $drop_attr");
 
1987
 
 
1988
report("index in create table",'index_in_create',
 
1989
       "create table crash_q (q integer not null,index (q))",
 
1990
       "drop table crash_q $drop_attr");
 
1991
 
 
1992
# The following must be executed as we need the value of end_drop_keyword
 
1993
# later
 
1994
if (!(defined($limits{'create_index'}) && defined($limits{'drop_index'})))
 
1995
{
 
1996
  if ($res=safe_query_l('create_index',"create index crash_q on crash_me (a)"))
 
1997
  {
 
1998
    $res="yes";
 
1999
    $drop_res="yes";
 
2000
    $end_drop_keyword="";
 
2001
    if (!safe_query_l('drop_index',"drop index crash_q"))
 
2002
    {
 
2003
      # Can't drop the standard way; Check if mSQL
 
2004
      if (safe_query_l('drop_index',"drop index crash_q from crash_me"))
 
2005
      {
 
2006
        $drop_res="with 'FROM'";        # Drop is not ANSI SQL
 
2007
        $end_drop_keyword="drop index %i from %t";
 
2008
      }
 
2009
      # else check if Access or MySQL
 
2010
      elsif (safe_query_l('drop_index',"drop index crash_q on crash_me"))
 
2011
      {
 
2012
        $drop_res="with 'ON'";  # Drop is not ANSI SQL
 
2013
        $end_drop_keyword="drop index %i on %t";
 
2014
      }
 
2015
      # else check if MS-SQL
 
2016
      elsif (safe_query_l('drop_index',"drop index crash_me.crash_q"))
 
2017
      {
 
2018
        $drop_res="with 'table.index'"; # Drop is not ANSI SQL
 
2019
        $end_drop_keyword="drop index %t.%i";
 
2020
      }
 
2021
    }
 
2022
    else
 
2023
    {
 
2024
      # Old MySQL 3.21 supports only the create index syntax
 
2025
      # This means that the second create doesn't give an error.
 
2026
      $res=safe_query_l('create_index',["create index crash_q on crash_me (a)",
 
2027
                     "create index crash_q on crash_me (a)",
 
2028
                     "drop index crash_q"]);
 
2029
      $res= $res ? 'ignored' : 'yes';
 
2030
    }
 
2031
  }
 
2032
  else
 
2033
  {
 
2034
    $drop_res=$res='no';
 
2035
  }
 
2036
  save_config_data('create_index',$res,"create index");
 
2037
  save_config_data('drop_index',$drop_res,"drop index");
 
2038
 
 
2039
  print "create index: $limits{'create_index'}\n";
 
2040
  print "drop index: $limits{'drop_index'}\n";
 
2041
}
 
2042
 
 
2043
# check if we can have 'NULL' as a key
 
2044
check_and_report("null in index","null_in_index",
 
2045
                 [create_table("crash_q",["a char(10)"],["(a)"]),
 
2046
                  "insert into crash_q values (NULL)"],
 
2047
                 "select * from crash_q",
 
2048
                 ["drop table crash_q $drop_attr"],
 
2049
                 undef(),4);
 
2050
 
 
2051
if ($limits{'unique_in_create'} eq 'yes')
 
2052
{
 
2053
  report("null in unique index",'null_in_unique',
 
2054
          create_table("crash_q",["q integer"],["unique(q)"]),
 
2055
         "insert into crash_q (q) values(NULL)",
 
2056
         "insert into crash_q (q) values(NULL)",
 
2057
         "drop table crash_q $drop_attr");
 
2058
  report("null combination in unique index",'nulls_in_unique',
 
2059
          create_table("crash_q",["q integer,q1 integer"],["unique(q,q1)"]),
 
2060
         "insert into crash_q (q,q1) values(1,NULL)",
 
2061
         "insert into crash_q (q,q1) values(1,NULL)",
 
2062
         "drop table crash_q $drop_attr");
 
2063
}
 
2064
 
 
2065
if ($limits{'null_in_unique'} eq 'yes')
 
2066
{
 
2067
  report("null in unique index",'multi_null_in_unique',
 
2068
          create_table("crash_q",["q integer, x integer"],["unique(q)"]),
 
2069
         "insert into crash_q(x) values(1)",
 
2070
         "insert into crash_q(x) values(2)",
 
2071
         "drop table crash_q $drop_attr");
 
2072
}
 
2073
 
 
2074
if ($limits{'create_index'} ne 'no')
 
2075
{
 
2076
  $end_drop=$end_drop_keyword;
 
2077
  $end_drop =~ s/%i/crash_q/;
 
2078
  $end_drop =~ s/%t/crash_me/;
 
2079
  report("index on column part (extension)","index_parts",,
 
2080
         "create index crash_q on crash_me (b(5))",
 
2081
         $end_drop);
 
2082
  $end_drop=$end_drop_keyword;
 
2083
  $end_drop =~ s/%i/crash_me/;
 
2084
  $end_drop =~ s/%t/crash_me/;
 
2085
  report("different namespace for index",
 
2086
         "index_namespace",
 
2087
         "create index crash_me on crash_me (b)",
 
2088
         $end_drop);
 
2089
}
 
2090
 
 
2091
if (!report("case independent table names","table_name_case",
 
2092
            "create table crash_q (q integer)",
 
2093
            "drop table CRASH_Q $drop_attr"))
 
2094
{
 
2095
  safe_query("drop table crash_q $drop_attr");
 
2096
}
 
2097
 
 
2098
if (!report("case independent field names","field_name_case",
 
2099
            "create table crash_q (q integer)",
 
2100
            "insert into crash_q(Q) values (1)",
 
2101
            "drop table crash_q $drop_attr"))
 
2102
{
 
2103
  safe_query("drop table crash_q $drop_attr");
 
2104
}
 
2105
 
 
2106
if (!report("drop table if exists","drop_if_exists",
 
2107
            "create table crash_q (q integer)",
 
2108
            "drop table if exists crash_q $drop_attr"))
 
2109
{
 
2110
  safe_query("drop table crash_q $drop_attr");
 
2111
}
 
2112
 
 
2113
report("create table if not exists","create_if_not_exists",
 
2114
       "create table crash_q (q integer)",
 
2115
       "create table if not exists crash_q (q integer)");
 
2116
safe_query("drop table crash_q $drop_attr");
 
2117
 
 
2118
#
 
2119
# test of different join types
 
2120
#
 
2121
 
 
2122
assert_crash("create table crash_me2 (a integer not null,b char(10) not null,".
 
2123
       " c1 integer)");
 
2124
assert_crash("insert into crash_me2 (a,b,c1) values (1,'b',1)");
 
2125
assert_crash("create table crash_me3 (a integer not null,b char(10) not null)");
 
2126
assert_crash("insert into crash_me3 (a,b) values (1,'b')");
 
2127
 
 
2128
report("inner join","inner_join",
 
2129
       "select crash_me.a from crash_me inner join crash_me2 ON ".
 
2130
       "crash_me.a=crash_me2.a");
 
2131
report("left outer join","left_outer_join",
 
2132
       "select crash_me.a from crash_me left join crash_me2 ON ".
 
2133
       "crash_me.a=crash_me2.a");
 
2134
report("natural left outer join","natural_left_outer_join",
 
2135
       "select c1 from crash_me natural left join crash_me2");
 
2136
report("left outer join using","left_outer_join_using",
 
2137
       "select c1 from crash_me left join crash_me2 using (a)");
 
2138
report("left outer join odbc style","odbc_left_outer_join",
 
2139
       "select crash_me.a from { oj crash_me left outer join crash_me2 ON".
 
2140
       " crash_me.a=crash_me2.a }");
 
2141
report("right outer join","right_outer_join",
 
2142
       "select crash_me.a from crash_me right join crash_me2 ON ".
 
2143
       "crash_me.a=crash_me2.a");
 
2144
report("full outer join","full_outer_join",
 
2145
       "select crash_me.a from crash_me full join crash_me2 ON "."
 
2146
       crash_me.a=crash_me2.a");
 
2147
report("cross join (same as from a,b)","cross_join",
 
2148
       "select crash_me.a from crash_me cross join crash_me3");
 
2149
report("natural join","natural_join",
 
2150
       "select * from crash_me natural join crash_me3");
 
2151
report("union","union",
 
2152
       "select * from crash_me union select a,b from crash_me3");
 
2153
report("union all","union_all",
 
2154
       "select * from crash_me union all select a,b from crash_me3");
 
2155
report("intersect","intersect",
 
2156
       "select * from crash_me intersect select * from crash_me3");
 
2157
report("intersect all","intersect_all",
 
2158
       "select * from crash_me intersect all select * from crash_me3");
 
2159
report("except","except",
 
2160
       "select * from crash_me except select * from crash_me3");
 
2161
report("except all","except_all",
 
2162
       "select * from crash_me except all select * from crash_me3");
 
2163
report("except","except",
 
2164
       "select * from crash_me except select * from crash_me3");
 
2165
report("except all","except_all",
 
2166
       "select * from crash_me except all select * from crash_me3");
 
2167
report("minus","minus",
 
2168
       "select * from crash_me minus select * from crash_me3"); # oracle ...
 
2169
 
 
2170
report("natural join (incompatible lists)","natural_join_incompat",
 
2171
       "select c1 from crash_me natural join crash_me2");
 
2172
report("union (incompatible lists)","union_incompat",
 
2173
       "select * from crash_me union select a,b from crash_me2");
 
2174
report("union all (incompatible lists)","union_all_incompat",
 
2175
       "select * from crash_me union all select a,b from crash_me2");
 
2176
report("intersect (incompatible lists)","intersect_incompat",
 
2177
       "select * from crash_me intersect select * from crash_me2");
 
2178
report("intersect all (incompatible lists)","intersect_all_incompat",
 
2179
       "select * from crash_me intersect all select * from crash_me2");
 
2180
report("except (incompatible lists)","except_incompat",
 
2181
       "select * from crash_me except select * from crash_me2");
 
2182
report("except all (incompatible lists)","except_all_incompat",
 
2183
       "select * from crash_me except all select * from crash_me2");
 
2184
report("except (incompatible lists)","except_incompat",
 
2185
       "select * from crash_me except select * from crash_me2");
 
2186
report("except all (incompatible lists)","except_all_incompat",
 
2187
       "select * from crash_me except all select * from crash_me2");
 
2188
report("minus (incompatible lists)","minus_incompat",
 
2189
       "select * from crash_me minus select * from crash_me2"); # oracle ...
 
2190
 
 
2191
assert_crash("drop table crash_me2 $drop_attr");
 
2192
assert_crash("drop table crash_me3 $drop_attr");
 
2193
 
 
2194
# somethings to be added here ....
 
2195
# FOR UNION - INTERSECT - EXCEPT -> CORRESPONDING [ BY ]
 
2196
# after subqueries:
 
2197
# >ALL | ANY | SOME - EXISTS - UNIQUE
 
2198
 
 
2199
if (report("subqueries","subqueries",
 
2200
           "select a from crash_me where crash_me.a in ".
 
2201
           "(select max(a) from crash_me)"))
 
2202
{
 
2203
    $tmp=new query_repeat([],"select a from crash_me","","",
 
2204
                          " where a in (select a from crash_me",")",
 
2205
                          "",[],$max_join_tables);
 
2206
    find_limit("recursive subqueries", "recursive_subqueries",$tmp);
 
2207
}
 
2208
 
 
2209
report("insert INTO ... SELECT ...","insert_select",
 
2210
       "create table crash_q (a int)",
 
2211
       "insert into crash_q (a) SELECT crash_me.a from crash_me",
 
2212
       "drop table crash_q $drop_attr");
 
2213
 
 
2214
if (!defined($limits{"transactions"}))
 
2215
{
 
2216
  my ($limit,$type);
 
2217
  $limit="transactions";
 
2218
  $limit_r="rollback_metadata";
 
2219
  print "$limit: ";
 
2220
  foreach $type (('', 'type=bdb', 'type=innodb', 'type=gemini'))
 
2221
  {
 
2222
    undef($limits{$limit});
 
2223
    if (!report_trans($limit,
 
2224
                           [create_table("crash_q",["a integer not null"],[],
 
2225
                                         $type),
 
2226
                            "insert into crash_q values (1)"],
 
2227
                           "select * from crash_q",
 
2228
                           "drop table crash_q $drop_attr"
 
2229
                          ))
 
2230
     {
 
2231
       report_rollback($limit_r,
 
2232
              [create_table("crash_q",["a integer not null"],[],
 
2233
                                 $type)],
 
2234
                            "insert into crash_q values (1)",
 
2235
                           "drop table crash_q $drop_attr" );
 
2236
     last;
 
2237
     };
 
2238
  }
 
2239
  print "$limits{$limit}\n";
 
2240
  print "$limit_r: $limits{$limit_r}\n";
 
2241
}
 
2242
 
 
2243
report("atomic updates","atomic_updates",
 
2244
       create_table("crash_q",["a integer not null"],["primary key (a)"]),
 
2245
       "insert into crash_q values (2)",
 
2246
       "insert into crash_q values (3)",
 
2247
       "insert into crash_q values (1)",
 
2248
       "update crash_q set a=a+1",
 
2249
       "drop table crash_q $drop_attr");
 
2250
 
 
2251
if ($limits{'atomic_updates'} eq 'yes')
 
2252
{
 
2253
  report_fail("atomic_updates_with_rollback","atomic_updates_with_rollback",
 
2254
              create_table("crash_q",["a integer not null"],
 
2255
                           ["primary key (a)"]),
 
2256
              "insert into crash_q values (2)",
 
2257
              "insert into crash_q values (3)",
 
2258
              "insert into crash_q values (1)",
 
2259
              "update crash_q set a=a+1 where a < 3",
 
2260
              "drop table crash_q $drop_attr");
 
2261
}
 
2262
 
 
2263
# To add with the views:
 
2264
# DROP VIEW - CREAT VIEW *** [ WITH [ CASCADE | LOCAL ] CHECK OPTION ]
 
2265
report("views","views",
 
2266
       "create view crash_q as select a from crash_me",
 
2267
       "drop view crash_q $drop_attr");
 
2268
 
 
2269
#  Test: foreign key
 
2270
{
 
2271
 my $result = 'undefined';
 
2272
 my $error;
 
2273
 print "foreign keys: ";
 
2274
 save_incomplete('foreign_key','foreign keys');
 
2275
 
 
2276
# 1) check if foreign keys are supported
 
2277
 safe_query_l('foreign_key',
 
2278
              create_table("crash_me_qf",
 
2279
                           ["a integer not null"],
 
2280
                           ["primary key (a)"]));
 
2281
 $error= safe_query_l('foreign_key',
 
2282
                      create_table("crash_me_qf2",
 
2283
                                   ["a integer not null",
 
2284
                                    "foreign key (a) references crash_me_qf (a)"],
 
2285
                                   []));
 
2286
 
 
2287
 if ($error == 1)         # OK  -- syntax is supported 
 
2288
 {
 
2289
   $result = 'error';
 
2290
   # now check if foreign key really works
 
2291
   safe_query_l('foreign_key', "insert into crash_me_qf values (1)");
 
2292
   if (safe_query_l('foreign_key', "insert into crash_me_qf2 values (2)") eq 1)
 
2293
   {
 
2294
     $result = 'syntax only';
 
2295
   }
 
2296
   else
 
2297
   {
 
2298
     $result = 'yes';
 
2299
   }
 
2300
 }
 
2301
 else
 
2302
 {
 
2303
   $result = "no";
 
2304
 }
 
2305
 safe_query_l('foreign_key', "drop table crash_me_qf2 $drop_attr");
 
2306
 safe_query_l('foreign_key', "drop table crash_me_qf $drop_attr");
 
2307
 print "$result\n";
 
2308
 save_config_data('foreign_key',$result,"foreign keys");
 
2309
}
 
2310
 
 
2311
if ($limits{'foreign_key'} eq 'yes')
 
2312
{
 
2313
  report("allows to update of foreign key values",'foreign_update',
 
2314
   "create table crash_me1 (a int not null primary key)",
 
2315
   "create table crash_me2 (a int not null," .
 
2316
      " foreign key (a) references crash_me1 (a))",
 
2317
   "insert into crash_me1 values (1)",
 
2318
   "insert into crash_me2 values (1)",
 
2319
   "update crash_me1 set a = 2",       ## <- must fail 
 
2320
   "drop table crash_me2 $drop_attr", 
 
2321
   "drop table crash_me1 $drop_attr" 
 
2322
  );
 
2323
}
 
2324
 
 
2325
report("Create SCHEMA","create_schema",
 
2326
       "create schema crash_schema create table crash_q (a int) ".
 
2327
       "create table crash_q2(b int)",
 
2328
       "drop schema crash_schema cascade");
 
2329
 
 
2330
if ($limits{'foreign_key'} eq 'yes')
 
2331
{
 
2332
  if ($limits{'create_schema'} eq 'yes')
 
2333
  {
 
2334
    report("Circular foreign keys","foreign_key_circular",
 
2335
           "create schema crash_schema create table crash_q ".
 
2336
           "(a int primary key, b int, foreign key (b) references ".
 
2337
           "crash_q2(a)) create table crash_q2(a int, b int, ".
 
2338
           "primary key(a), foreign key (b) references crash_q(a))",
 
2339
           "drop schema crash_schema cascade");
 
2340
  }
 
2341
}
 
2342
 
 
2343
if ($limits{'func_sql_character_length'} eq 'yes')
 
2344
{
 
2345
  my $result = 'error';
 
2346
  my ($resultset);
 
2347
  my $key = 'length_of_varchar_field';
 
2348
  my $prompt='CHARACTER_LENGTH(varchar_field)';
 
2349
  print $prompt," = ";
 
2350
  if (!defined($limits{$key})) {
 
2351
    save_incomplete($key,$prompt);
 
2352
    safe_query_l($key,[
 
2353
                       "CREATE TABLE crash_me1 (S1 VARCHAR(100))",
 
2354
                       "INSERT INTO crash_me1 VALUES ('X')"
 
2355
                       ]);
 
2356
    my $recset = get_recordset($key,
 
2357
                               "SELECT CHARACTER_LENGTH(S1) FROM crash_me1");
 
2358
    print_recordset($key,$recset);
 
2359
    if (defined($recset)){
 
2360
      if ( $recset->[0][0] eq 1 ) {
 
2361
                $result = 'actual length';
 
2362
              } elsif( $recset->[0][0] eq 100 ) {
 
2363
                $result = 'defined length';
 
2364
              };
 
2365
    } else {
 
2366
      add_log($key,$DBI::errstr);
 
2367
    }
 
2368
    safe_query_l($key, "drop table crash_me1 $drop_attr");
 
2369
    save_config_data($key,$result,$prompt);
 
2370
  } else {
 
2371
    $result = $limits{$key};
 
2372
  };
 
2373
  print "$result\n";
 
2374
}
 
2375
 
 
2376
 
 
2377
check_constraint("Column constraints","constraint_check",
 
2378
           "create table crash_q (a int check (a>0))",
 
2379
           "insert into crash_q values(0)",
 
2380
           "drop table crash_q $drop_attr");
 
2381
 
 
2382
 
 
2383
check_constraint("Table constraints","constraint_check_table",
 
2384
       "create table crash_q (a int ,b int, check (a>b))",
 
2385
       "insert into crash_q values(0,0)",
 
2386
       "drop table crash_q $drop_attr");
 
2387
 
 
2388
check_constraint("Named constraints","constraint_check_named",
 
2389
       "create table crash_q (a int ,b int, constraint abc check (a>b))",
 
2390
       "insert into crash_q values(0,0)",
 
2391
       "drop table crash_q $drop_attr");
 
2392
 
 
2393
 
 
2394
report("NULL constraint (SyBase style)","constraint_null",
 
2395
       "create table crash_q (a int null)",
 
2396
       "drop table crash_q $drop_attr");
 
2397
 
 
2398
report("Triggers (ANSI SQL)","psm_trigger",
 
2399
       "create table crash_q (a int ,b int)",
 
2400
       "create trigger crash_trigger after insert on crash_q referencing ".
 
2401
       "new table as new_a when (localtime > time '18:00:00') ".
 
2402
       "begin atomic end",
 
2403
       "insert into crash_q values(1,2)",
 
2404
       "drop trigger crash_trigger",
 
2405
       "drop table crash_q $drop_attr");
 
2406
 
 
2407
report("PSM procedures (ANSI SQL)","psm_procedures",
 
2408
       "create table crash_q (a int,b int)",
 
2409
       "create procedure crash_proc(in a1 int, in b1 int) language ".
 
2410
       "sql modifies sql data begin declare c1 int; set c1 = a1 + b1;".
 
2411
       " insert into crash_q(a,b) values (a1,c1); end",
 
2412
       "call crash_proc(1,10)",
 
2413
       "drop procedure crash_proc",
 
2414
       "drop table crash_q $drop_attr");
 
2415
 
 
2416
report("PSM modules (ANSI SQL)","psm_modules",
 
2417
       "create table crash_q (a int,b int)",
 
2418
       "create module crash_m declare procedure ".
 
2419
         "crash_proc(in a1 int, in b1 int) language sql modifies sql ".
 
2420
         "data begin declare c1 int; set c1 = a1 + b1; ".
 
2421
         "insert into crash_q(a,b) values (a1,c1); end; ".
 
2422
         "declare procedure crash_proc2(INOUT a int, in b int) ".
 
2423
         "contains sql set a = b + 10; end module",
 
2424
       "call crash_proc(1,10)",
 
2425
       "drop module crash_m cascade",
 
2426
       "drop table crash_q cascade $drop_attr");
 
2427
 
 
2428
report("PSM functions (ANSI SQL)","psm_functions",
 
2429
       "create table crash_q (a int)",
 
2430
       "create function crash_func(in a1 int, in b1 int) returns int".
 
2431
         " language sql deterministic contains sql ".
 
2432
         " begin return a1 * b1; end",
 
2433
       "insert into crash_q values(crash_func(2,4))",
 
2434
       "select a,crash_func(a,2) from crash_q",
 
2435
       "drop function crash_func cascade",
 
2436
       "drop table crash_q $drop_attr");
 
2437
 
 
2438
report("Domains (ANSI SQL)","domains",
 
2439
       "create domain crash_d as varchar(10) default 'Empty' ".
 
2440
         "check (value <> 'abcd')",
 
2441
       "create table crash_q(a crash_d, b int)",
 
2442
       "insert into crash_q(a,b) values('xyz',10)",
 
2443
       "insert into crash_q(b) values(10)",
 
2444
       "drop table crash_q $drop_attr",
 
2445
       "drop domain crash_d");
 
2446
 
 
2447
 
 
2448
if (!defined($limits{'lock_tables'}))
 
2449
{
 
2450
  report("lock table","lock_tables",
 
2451
         "lock table crash_me READ",
 
2452
         "unlock tables");
 
2453
  if ($limits{'lock_tables'} eq 'no')
 
2454
  {
 
2455
    delete $limits{'lock_tables'};
 
2456
    report("lock table","lock_tables",
 
2457
           "lock table crash_me IN SHARE MODE");
 
2458
  }
 
2459
}
 
2460
 
 
2461
if (!report("many tables to drop table","multi_drop",
 
2462
           "create table crash_q (a int)",
 
2463
           "create table crash_q2 (a int)",
 
2464
           "drop table crash_q,crash_q2 $drop_attr"))
 
2465
{
 
2466
  $dbh->do("drop table crash_q $drop_attr");
 
2467
  $dbh->do("drop table crash_q2 $drop_attr");
 
2468
}
 
2469
 
 
2470
if (!report("drop table with cascade/restrict","drop_restrict",
 
2471
           "create table crash_q (a int)",
 
2472
           "drop table crash_q restrict"))
 
2473
{
 
2474
  $dbh->do("drop table crash_q $drop_attr");
 
2475
}
 
2476
 
 
2477
 
 
2478
report("-- as comment (ANSI)","comment_--",
 
2479
       "select * from crash_me -- Testing of comments");
 
2480
report("// as comment","comment_//",
 
2481
       "select * from crash_me // Testing of comments");
 
2482
report("# as comment","comment_#",
 
2483
       "select * from crash_me # Testing of comments");
 
2484
report("/* */ as comment","comment_/**/",
 
2485
       "select * from crash_me /* Testing of comments */");
 
2486
 
 
2487
#
 
2488
# Check things that fails one some servers
 
2489
#
 
2490
 
 
2491
# Empress can't insert empty strings in a char() field
 
2492
report("insert empty string","insert_empty_string",
 
2493
       create_table("crash_q",["a char(10) not null,b char(10)"],[]),
 
2494
       "insert into crash_q values ('','')",
 
2495
       "drop table crash_q $drop_attr");
 
2496
 
 
2497
report("Having with alias","having_with_alias",
 
2498
       create_table("crash_q",["a integer"],[]),
 
2499
       "insert into crash_q values (10)",
 
2500
       "select sum(a) as b from crash_q group by a having b > 0",
 
2501
       "drop table crash_q $drop_attr");
 
2502
 
 
2503
#
 
2504
# test name limits
 
2505
#
 
2506
 
 
2507
find_limit("table name length","max_table_name",
 
2508
           new query_many(["create table crash_q%s (q integer)",
 
2509
                           "insert into crash_q%s values(1)"],
 
2510
                           "select * from crash_q%s",1,
 
2511
                           ["drop table crash_q%s $drop_attr"],
 
2512
                           $max_name_length,7,1));
 
2513
 
 
2514
find_limit("column name length","max_column_name",
 
2515
           new query_many(["create table crash_q (q%s integer)",
 
2516
                          "insert into crash_q (q%s) values(1)"],
 
2517
                          "select q%s from crash_q",1,
 
2518
                          ["drop table crash_q $drop_attr"],
 
2519
                           $max_name_length,1));
 
2520
 
 
2521
if ($limits{'column_alias'} eq 'yes')
 
2522
{
 
2523
  find_limit("select alias name length","max_select_alias_name",
 
2524
           new query_many(undef,
 
2525
                          "select b as %s from crash_me",undef,
 
2526
                          undef, $max_name_length));
 
2527
}
 
2528
 
 
2529
find_limit("table alias name length","max_table_alias_name",
 
2530
           new query_many(undef,
 
2531
                          "select %s.b from crash_me %s",
 
2532
                          undef,
 
2533
                          undef, $max_name_length));
 
2534
 
 
2535
$end_drop_keyword = "drop index %i" if (!$end_drop_keyword);
 
2536
$end_drop=$end_drop_keyword;
 
2537
$end_drop =~ s/%i/crash_q%s/;
 
2538
$end_drop =~ s/%t/crash_me/;
 
2539
 
 
2540
if ($limits{'create_index'} ne 'no')
 
2541
{
 
2542
  find_limit("index name length","max_index_name",
 
2543
             new query_many(["create index crash_q%s on crash_me (a)"],
 
2544
                            undef,undef,
 
2545
                            [$end_drop],
 
2546
                            $max_name_length,7));
 
2547
}
 
2548
 
 
2549
find_limit("max char() size","max_char_size",
 
2550
           new query_many(["create table crash_q (q char(%d))",
 
2551
                           "insert into crash_q values ('%s')"],
 
2552
                          "select * from crash_q","%s",
 
2553
                          ["drop table crash_q $drop_attr"],
 
2554
                          min($max_string_size,$limits{'query_size'})));
 
2555
 
 
2556
if ($limits{'type_sql_varchar(1_arg)'} eq 'yes')
 
2557
{
 
2558
  find_limit("max varchar() size","max_varchar_size",
 
2559
             new query_many(["create table crash_q (q varchar(%d))",
 
2560
                             "insert into crash_q values ('%s')"],
 
2561
                            "select * from crash_q","%s",
 
2562
                            ["drop table crash_q $drop_attr"],
 
2563
                            min($max_string_size,$limits{'query_size'})));
 
2564
}
 
2565
 
 
2566
$found=undef;
 
2567
foreach $type (('mediumtext','text','text()','blob','long'))
 
2568
{
 
2569
  if ($limits{"type_extra_$type"} eq 'yes')
 
2570
  {
 
2571
    $found=$type;
 
2572
    last;
 
2573
  }
 
2574
}
 
2575
if (defined($found))
 
2576
{
 
2577
  $found =~ s/\(\)/\(%d\)/;
 
2578
  find_limit("max text or blob size","max_text_size",
 
2579
             new query_many(["create table crash_q (q $found)",
 
2580
                             "insert into crash_q values ('%s')"],
 
2581
                            "select * from crash_q","%s",
 
2582
                            ["drop table crash_q $drop_attr"],
 
2583
                            min($max_string_size,$limits{'query_size'}-30)));
 
2584
 
 
2585
}
 
2586
 
 
2587
$tmp=new query_repeat([],"create table crash_q (a integer","","",
 
2588
                      ",a%d integer","",")",["drop table crash_q $drop_attr"],
 
2589
                      $max_columns);
 
2590
$tmp->{'offset'}=1;
 
2591
find_limit("Columns in table","max_columns",$tmp);
 
2592
 
 
2593
# Make a field definition to be used when testing keys
 
2594
 
 
2595
$key_definitions="q0 integer not null";
 
2596
$key_fields="q0";
 
2597
for ($i=1; $i < min($limits{'max_columns'},$max_keys) ; $i++)
 
2598
{
 
2599
  $key_definitions.=",q$i integer not null";
 
2600
  $key_fields.=",q$i";
 
2601
}
 
2602
$key_values="1," x $i;
 
2603
chop($key_values);
 
2604
 
 
2605
if ($limits{'unique_in_create'} eq 'yes')
 
2606
{
 
2607
  find_limit("unique indexes","max_unique_index",
 
2608
             new query_table("create table crash_q (q integer",
 
2609
                             ",q%d integer not null,unique (q%d)",")",
 
2610
                             ["insert into crash_q (q,%f) values (1,%v)"],
 
2611
                             "select q from crash_q",1,
 
2612
                             "drop table crash_q $drop_attr",
 
2613
                             $max_keys,0));
 
2614
 
 
2615
  find_limit("index parts","max_index_parts",
 
2616
             new query_table("create table crash_q ".
 
2617
                 "($key_definitions,unique (q0",
 
2618
                             ",q%d","))",
 
2619
             ["insert into crash_q ($key_fields) values ($key_values)"],
 
2620
             "select q0 from crash_q",1,
 
2621
             "drop table crash_q $drop_attr",
 
2622
             $max_keys,1));
 
2623
 
 
2624
  find_limit("max index part length","max_index_part_length",
 
2625
             new query_many(["create table crash_q (q char(%d) not null,".
 
2626
                   "unique(q))",
 
2627
                     "insert into crash_q (q) values ('%s')"],
 
2628
                    "select q from crash_q","%s",
 
2629
                    ["drop table crash_q $drop_attr"],
 
2630
                    $limits{'max_char_size'},0));
 
2631
 
 
2632
  if ($limits{'type_sql_varchar(1_arg)'} eq 'yes')
 
2633
  {
 
2634
    find_limit("index varchar part length","max_index_varchar_part_length",
 
2635
             new query_many(["create table crash_q (q varchar(%d) not null,".
 
2636
                        "unique(q))",
 
2637
                         "insert into crash_q (q) values ('%s')"],
 
2638
                        "select q from crash_q","%s",
 
2639
                        ["drop table crash_q $drop_attr"],
 
2640
                        $limits{'max_varchar_size'},0));
 
2641
  }
 
2642
}
 
2643
 
 
2644
 
 
2645
if ($limits{'create_index'} ne 'no')
 
2646
{
 
2647
  if ($limits{'create_index'} eq 'ignored' ||
 
2648
      $limits{'unique_in_create'} eq 'yes')
 
2649
  {                                     # This should be true
 
2650
    add_log('max_index',
 
2651
     " max_unique_index=$limits{'max_unique_index'} ,".
 
2652
     "so max_index must be same");
 
2653
    save_config_data('max_index',$limits{'max_unique_index'},"max index");
 
2654
    print "indexes: $limits{'max_index'}\n";
 
2655
  }
 
2656
  else
 
2657
  {
 
2658
    if (!defined($limits{'max_index'}))
 
2659
    {
 
2660
      safe_query_l('max_index',"create table crash_q ($key_definitions)");
 
2661
      for ($i=1; $i <= min($limits{'max_columns'},$max_keys) ; $i++)
 
2662
      {
 
2663
        last if (!safe_query_l('max_index',
 
2664
             "create index crash_q$i on crash_q (q$i)"));
 
2665
      }
 
2666
      save_config_data('max_index',$i == $max_keys ? $max_keys : $i,
 
2667
                       "max index");
 
2668
      while ( --$i > 0)
 
2669
      {
 
2670
        $end_drop=$end_drop_keyword;
 
2671
        $end_drop =~ s/%i/crash_q$i/;
 
2672
        $end_drop =~ s/%t/crash_q/;
 
2673
        assert_crash($end_drop);
 
2674
      }
 
2675
      assert_crash("drop table crash_q $drop_attr");
 
2676
    }
 
2677
    print "indexs: $limits{'max_index'}\n";
 
2678
    if (!defined($limits{'max_unique_index'}))
 
2679
    {
 
2680
      safe_query_l('max_unique_index',
 
2681
           "create table crash_q ($key_definitions)");
 
2682
      for ($i=0; $i < min($limits{'max_columns'},$max_keys) ; $i++)
 
2683
      {
 
2684
        last if (!safe_query_l('max_unique_index',
 
2685
            "create unique index crash_q$i on crash_q (q$i)"));
 
2686
      }
 
2687
      save_config_data('max_unique_index',$i == $max_keys ? $max_keys : $i,
 
2688
                       "max unique index");
 
2689
      while ( --$i >= 0)
 
2690
      {
 
2691
        $end_drop=$end_drop_keyword;
 
2692
        $end_drop =~ s/%i/crash_q$i/;
 
2693
        $end_drop =~ s/%t/crash_q/;
 
2694
        assert_crash($end_drop);
 
2695
      }
 
2696
      assert_crash("drop table crash_q $drop_attr");
 
2697
    }
 
2698
    print "unique indexes: $limits{'max_unique_index'}\n";
 
2699
    if (!defined($limits{'max_index_parts'}))
 
2700
    {
 
2701
      safe_query_l('max_index_parts',
 
2702
            "create table crash_q ($key_definitions)");
 
2703
      $end_drop=$end_drop_keyword;
 
2704
      $end_drop =~ s/%i/crash_q1%d/;
 
2705
      $end_drop =~ s/%t/crash_q/;
 
2706
      find_limit("index parts","max_index_parts",
 
2707
                 new query_table("create index crash_q1%d on crash_q (q0",
 
2708
                                 ",q%d",")",
 
2709
                                 [],
 
2710
                                 undef,undef,
 
2711
                                 $end_drop,
 
2712
                                 $max_keys,1));
 
2713
      assert_crash("drop table crash_q $drop_attr");
 
2714
    }
 
2715
    else
 
2716
    {
 
2717
      print "index parts: $limits{'max_index_parts'}\n";
 
2718
    }
 
2719
    $end_drop=$end_drop_keyword;
 
2720
    $end_drop =~ s/%i/crash_q2%d/;
 
2721
    $end_drop =~ s/%t/crash_me/;
 
2722
 
 
2723
    find_limit("index part length","max_index_part_length",
 
2724
               new query_many(["create table crash_q (q char(%d))",
 
2725
                               "create index crash_q2%d on crash_q (q)",
 
2726
                               "insert into crash_q values('%s')"],
 
2727
                              "select q from crash_q",
 
2728
                              "%s",
 
2729
                              [ $end_drop,
 
2730
                               "drop table crash_q $drop_attr"],
 
2731
                              min($limits{'max_char_size'},"+8192")));
 
2732
  }
 
2733
}
 
2734
 
 
2735
find_limit("index length","max_index_length",
 
2736
           new query_index_length("create table crash_q ",
 
2737
                                  "drop table crash_q $drop_attr",
 
2738
                                  $max_key_length));
 
2739
 
 
2740
find_limit("max table row length (without blobs)","max_row_length",
 
2741
           new query_row_length("crash_q ",
 
2742
                                "not null",
 
2743
                                "drop table crash_q $drop_attr",
 
2744
                                min($max_row_length,
 
2745
                                    $limits{'max_columns'}*
 
2746
                                    min($limits{'max_char_size'},255))));
 
2747
 
 
2748
find_limit("table row length with nulls (without blobs)",
 
2749
           "max_row_length_with_null",
 
2750
           new query_row_length("crash_q ",
 
2751
                                "",
 
2752
                                "drop table crash_q $drop_attr",
 
2753
                                $limits{'max_row_length'}*2));
 
2754
 
 
2755
find_limit("number of columns in order by","columns_in_order_by",
 
2756
           new query_many(["create table crash_q (%F)",
 
2757
                           "insert into crash_q values(%v)",
 
2758
                           "insert into crash_q values(%v)"],
 
2759
                          "select * from crash_q order by %f",
 
2760
                          undef(),
 
2761
                          ["drop table crash_q $drop_attr"],
 
2762
                          $max_order_by));
 
2763
 
 
2764
find_limit("number of columns in group by","columns_in_group_by",
 
2765
           new query_many(["create table crash_q (%F)",
 
2766
                           "insert into crash_q values(%v)",
 
2767
                           "insert into crash_q values(%v)"],
 
2768
                          "select %f from crash_q group by %f",
 
2769
                          undef(),
 
2770
                          ["drop table crash_q $drop_attr"],
 
2771
                          $max_order_by));
 
2772
 
 
2773
 
 
2774
 
 
2775
# Safe arithmetic test
 
2776
 
 
2777
$prompt="safe decimal arithmetic";
 
2778
$key="safe_decimal_arithmetic";
 
2779
if (!defined($limits{$key}))
 
2780
{
 
2781
   print "$prompt=";
 
2782
   save_incomplete($key,$prompt);       
 
2783
   if (!safe_query_l($key,$server->create("crash_me_a",
 
2784
         ["a decimal(10,2)","b decimal(10,2)"]))) 
 
2785
     {
 
2786
       print DBI->errstr();
 
2787
       die "Can't create table 'crash_me_a' $DBI::errstr\n";
 
2788
     };
 
2789
   
 
2790
   if (!safe_query_l($key,
 
2791
       ["insert into crash_me_a (a,b) values (11.4,18.9)"]))
 
2792
     {
 
2793
       die "Can't insert into table 'crash_me_a' a  record: $DBI::errstr\n";
 
2794
     };
 
2795
     
 
2796
   $arithmetic_safe = 'no'; 
 
2797
   $arithmetic_safe = 'yes' 
 
2798
   if ( (safe_query_result_l($key,
 
2799
            'select count(*) from crash_me_a where a+b=30.3',1,0) == 0) 
 
2800
      and (safe_query_result_l($key,
 
2801
            'select count(*) from crash_me_a where a+b-30.3 = 0',1,0) == 0)  
 
2802
      and (safe_query_result_l($key,
 
2803
            'select count(*) from crash_me_a where a+b-30.3 < 0',0,0) == 0)
 
2804
      and (safe_query_result_l($key,
 
2805
            'select count(*) from crash_me_a where a+b-30.3 > 0',0,0) == 0));
 
2806
   save_config_data($key,$arithmetic_safe,$prompt);
 
2807
   print "$arithmetic_safe\n";
 
2808
   assert_crash("drop table crash_me_a $drop_attr");
 
2809
}
 
2810
 else
 
2811
{
 
2812
  print "$prompt=$limits{$key} (cached)\n";
 
2813
}
 
2814
 
 
2815
# Check where is null values in sorted recordset
 
2816
if (!safe_query($server->create("crash_me_n",["i integer","r integer"]))) 
 
2817
 {
 
2818
   print DBI->errstr();
 
2819
   die "Can't create table 'crash_me_n' $DBI::errstr\n";
 
2820
 };
 
2821
 
 
2822
safe_query_l("position_of_null",["insert into crash_me_n (i) values(1)",
 
2823
"insert into crash_me_n values(2,2)",
 
2824
"insert into crash_me_n values(3,3)",
 
2825
"insert into crash_me_n values(4,4)",
 
2826
"insert into crash_me_n (i) values(5)"]);
 
2827
 
 
2828
$key = "position_of_null";
 
2829
$prompt ="Where is null values in sorted recordset";
 
2830
if (!defined($limits{$key}))
 
2831
{
 
2832
 save_incomplete($key,$prompt); 
 
2833
 print "$prompt=";
 
2834
 $sth=$dbh->prepare("select r from crash_me_n order by r ");
 
2835
 $sth->execute;
 
2836
 add_log($key,"< select r from crash_me_n order by r ");
 
2837
 $limit= detect_null_position($key,$sth);
 
2838
 $sth->finish;
 
2839
 print "$limit\n";
 
2840
 save_config_data($key,$limit,$prompt);
 
2841
} else {
 
2842
  print "$prompt=$limits{$key} (cache)\n";
 
2843
}
 
2844
 
 
2845
$key = "position_of_null_desc";
 
2846
$prompt ="Where is null values in sorted recordset (DESC)";
 
2847
if (!defined($limits{$key}))
 
2848
{
 
2849
 save_incomplete($key,$prompt); 
 
2850
 print "$prompt=";
 
2851
 $sth=$dbh->prepare("select r from crash_me_n order by r desc");
 
2852
 $sth->execute;
 
2853
 add_log($key,"< select r from crash_me_n order by r  desc");
 
2854
 $limit= detect_null_position($key,$sth);
 
2855
 $sth->finish;
 
2856
 print "$limit\n";
 
2857
 save_config_data($key,$limit,$prompt);
 
2858
} else {
 
2859
  print "$prompt=$limits{$key} (cache)\n";
 
2860
}
 
2861
 
 
2862
 
 
2863
assert_crash("drop table  crash_me_n $drop_attr");
 
2864
 
 
2865
 
 
2866
 
 
2867
$key = 'sorted_group_by';
 
2868
$prompt = 'Group by always sorted';
 
2869
if (!defined($limits{$key}))
 
2870
{
 
2871
 save_incomplete($key,$prompt);
 
2872
 print "$prompt=";
 
2873
 safe_query_l($key,[  
 
2874
                         "create table crash_me_t1 (a int not null, b int not null)",
 
2875
                         "insert into crash_me_t1 values (1,1)",
 
2876
                         "insert into crash_me_t1 values (1,2)",
 
2877
                         "insert into crash_me_t1 values (3,1)",
 
2878
                         "insert into crash_me_t1 values (3,2)",
 
2879
                         "insert into crash_me_t1 values (2,2)",
 
2880
                         "insert into crash_me_t1 values (2,1)",
 
2881
                         "create table crash_me_t2 (a int not null, b int not null)",
 
2882
                         "create index crash_me_t2_ind on crash_me_t2 (a)",
 
2883
                         "insert into crash_me_t2 values (1,3)",
 
2884
                         "insert into crash_me_t2 values (3,1)",
 
2885
                         "insert into crash_me_t2 values (2,2)",
 
2886
                         "insert into crash_me_t2 values (1,1)"]);
 
2887
 
 
2888
 my $bigqry = "select crash_me_t1.a,crash_me_t2.b from ".
 
2889
             "crash_me_t1,crash_me_t2 where crash_me_t1.a=crash_me_t2.a ".
 
2890
             "group by crash_me_t1.a,crash_me_t2.b";
 
2891
 
 
2892
 my $limit='no';
 
2893
 my $rs = get_recordset($key,$bigqry);
 
2894
 print_recordset($key,$rs); 
 
2895
 if ( defined ($rs)) { 
 
2896
   if (compare_recordset($key,$rs,[[1,1],[1,3],[2,2],[3,1]]) eq 0)
 
2897
   {
 
2898
     $limit='yes'
 
2899
   }
 
2900
 } else {
 
2901
  add_log($key,"error: ".$DBI::errstr);
 
2902
 } 
 
2903
 
 
2904
 print "$limit\n";
 
2905
 safe_query_l($key,["drop table crash_me_t1",
 
2906
                       "drop table crash_me_t2"]);
 
2907
 save_config_data($key,$limit,$prompt);         
 
2908
 
 
2909
} else {
 
2910
 print "$prompt=$limits{$key} (cashed)\n";
 
2911
}
 
2912
 
 
2913
 
 
2914
#
 
2915
# End of test
 
2916
#
 
2917
 
 
2918
$dbh->do("drop table crash_me $drop_attr");        # Remove temporary table
 
2919
 
 
2920
print "crash-me safe: $limits{'crash_me_safe'}\n";
 
2921
print "reconnected $reconnect_count times\n";
 
2922
 
 
2923
$dbh->disconnect || warn $dbh->errstr;
 
2924
save_all_config_data();
 
2925
exit 0;
 
2926
 
 
2927
# End of test
 
2928
#
 
2929
 
 
2930
$dbh->do("drop table crash_me $drop_attr");        # Remove temporary table
 
2931
 
 
2932
print "crash-me safe: $limits{'crash_me_safe'}\n";
 
2933
print "reconnected $reconnect_count times\n";
 
2934
 
 
2935
$dbh->disconnect || warn $dbh->errstr;
 
2936
save_all_config_data();
 
2937
exit 0;
 
2938
 
 
2939
# Check where is nulls in the sorted result (for)
 
2940
# it expects exactly 5 rows in the result
 
2941
 
 
2942
sub detect_null_position
 
2943
{
 
2944
  my $key = shift;
 
2945
  my $sth = shift;
 
2946
  my ($z,$r1,$r2,$r3,$r4,$r5);
 
2947
 $r1 = $sth->fetchrow_array; add_log($key,"> $r1");
 
2948
 $r2 = $sth->fetchrow_array; add_log($key,"> $r2");
 
2949
 $r3 = $sth->fetchrow_array; add_log($key,"> $r3");
 
2950
 $r4 = $sth->fetchrow_array; add_log($key,"> $r4");
 
2951
 $r5 = $sth->fetchrow_array; add_log($key,"> $r5");
 
2952
 return "first" if ( !defined($r1) && !defined($r2) && defined($r3));
 
2953
 return "last" if ( !defined($r5) && !defined($r4) && defined($r3));
 
2954
 return "random";
 
2955
}
 
2956
 
 
2957
sub check_parenthesis {
 
2958
 my $prefix=shift;
 
2959
 my $fn=shift;
 
2960
 my $result='no';
 
2961
 my $param_name=$prefix.lc($fn);
 
2962
 my $r;
 
2963
 
 
2964
 save_incomplete($param_name,$fn);
 
2965
 $r = safe_query("select $fn $end_query"); 
 
2966
 add_log($param_name,$safe_query_log);
 
2967
 if ($r == 1)
 
2968
  {
 
2969
    $result="yes";
 
2970
  } 
 
2971
  else{
 
2972
   $r = safe_query("select $fn() $end_query");
 
2973
   add_log($param_name,$safe_query_log);
 
2974
   if ( $r  == 1)   
 
2975
    {    
 
2976
       $result="with_parenthesis";
 
2977
    }
 
2978
  }
 
2979
 
 
2980
  save_config_data($param_name,$result,$fn);
 
2981
}
 
2982
 
 
2983
sub check_constraint {
 
2984
 my $prompt = shift;
 
2985
 my $key = shift;
 
2986
 my $create = shift;
 
2987
 my $check = shift;
 
2988
 my $drop = shift;
 
2989
 save_incomplete($key,$prompt);
 
2990
 print "$prompt=";
 
2991
 my $res = 'no';
 
2992
 my $t;
 
2993
 $t=safe_query($create);
 
2994
 add_log($key,$safe_query_log);
 
2995
 if ( $t == 1)
 
2996
 {
 
2997
   $res='yes';
 
2998
   $t= safe_query($check);
 
2999
   add_log($key,$safe_query_log);
 
3000
   if ($t == 1)
 
3001
   {
 
3002
     $res='syntax only';
 
3003
   }
 
3004
 }        
 
3005
 safe_query($drop);
 
3006
 add_log($key,$safe_query_log);
 
3007
 
 
3008
 save_config_data($key,$res,$prompt);
 
3009
 print "$res\n";
 
3010
}
 
3011
 
 
3012
sub make_time_r {
 
3013
  my $hour=shift;
 
3014
  my $minute=shift;
 
3015
  my $second=shift;
 
3016
  $_ = $limits{'time_format_inresult'};
 
3017
  return sprintf "%02d:%02d:%02d", ($hour%24),$minute,$second if (/^iso$/);
 
3018
  return sprintf "%02d.%02d.%02d", ($hour%24),$minute,$second if (/^euro/);
 
3019
  return sprintf "%02d:%02d %s", 
 
3020
        ($hour >= 13? ($hour-12) : $hour),$minute,($hour >=13 ? 'PM':'AM') 
 
3021
                        if (/^usa/);
 
3022
  return sprintf "%02d%02d%02d", ($hour%24),$minute,$second if (/^HHMMSS/);
 
3023
  return sprintf "%04d%02d%02d", ($hour%24),$minute,$second if (/^HHHHMMSS/);
 
3024
  return "UNKNOWN FORMAT";
 
3025
}
 
3026
 
 
3027
sub make_time {
 
3028
  my $hour=shift;
 
3029
  my $minute=shift;
 
3030
  my $second=shift;
 
3031
  return sprintf "%02d:%02d:%02d", ($hour%24),$minute,$second 
 
3032
      if ($limits{'time_format_ISO'} eq "yes");
 
3033
  return sprintf "%02d.%02d.%02d", ($hour%24),$minute,$second 
 
3034
      if ($limits{'time_format_EUR'} eq "yes");
 
3035
  return sprintf "%02d:%02d %s", 
 
3036
        ($hour >= 13? ($hour-12) : $hour),$minute,($hour >=13 ? 'PM':'AM') 
 
3037
      if ($limits{'time_format_USA'} eq "yes");
 
3038
  return sprintf "%02d%02d%02d", ($hour%24),$minute,$second 
 
3039
      if ($limits{'time_format_HHMMSS'} eq "yes");
 
3040
  return sprintf "%04d%02d%02d", ($hour%24),$minute,$second 
 
3041
      if ($limits{'time_format_HHHHMMSS'} eq "yes");
 
3042
  return "UNKNOWN FORMAT";
 
3043
}
 
3044
 
 
3045
sub make_date_r {
 
3046
  my $year=shift;
 
3047
  my $month=shift;
 
3048
  my $day=shift;
 
3049
  $_ = $limits{'date_format_inresult'};
 
3050
  return sprintf "%02d-%02d-%02d", ($year%100),$month,$day if (/^short iso$/);
 
3051
  return sprintf "%04d-%02d-%02d", $year,$month,$day if (/^iso/);
 
3052
  return sprintf "%02d.%02d.%02d", $day,$month,($year%100) if (/^short euro/);
 
3053
  return sprintf "%02d.%02d.%04d", $day,$month,$year if (/^euro/);
 
3054
  return sprintf "%02d/%02d/%02d", $month,$day,($year%100) if (/^short usa/);
 
3055
  return sprintf "%02d/%02d/%04d", $month,$day,$year if (/^usa/);
 
3056
  return sprintf "%04d%02d%02d", $year,$month,$day if (/^YYYYMMDD/);
 
3057
  return "UNKNOWN FORMAT";
 
3058
}
 
3059
 
 
3060
 
 
3061
sub make_date {
 
3062
  my $year=shift;
 
3063
  my $month=shift;
 
3064
  my $day=shift;
 
3065
  return sprintf "'%04d-%02d-%02d'", $year,$month,$day 
 
3066
      if ($limits{'date_format_ISO'} eq 'yes');
 
3067
  return sprintf "DATE '%04d-%02d-%02d'", $year,$month,$day 
 
3068
      if ($limits{'date_format_ISO_with_date'} eq 'yes');
 
3069
  return sprintf "'%02d.%02d.%04d'", $day,$month,$year 
 
3070
      if ($limits{'date_format_EUR'} eq 'yes');
 
3071
  return sprintf "DATE '%02d.%02d.%04d'", $day,$month,$year 
 
3072
      if ($limits{'date_format_EUR_with_date'} eq 'yes');
 
3073
  return sprintf "'%02d/%02d/%04d'", $month,$day,$year 
 
3074
      if ($limits{'date_format_USA'} eq 'yes');
 
3075
  return sprintf "DATE '%02d/%02d/%04d'", $month,$day,$year 
 
3076
      if ($limits{'date_format_USA_with_date'} eq 'yes');
 
3077
  return sprintf "'%04d%02d%02d'", $year,$month,$day 
 
3078
      if ($limits{'date_format_YYYYMMDD'} eq 'yes');
 
3079
  return sprintf "DATE '%04d%02d%02d'", $year,$month,$day 
 
3080
      if ($limits{'date_format_YYYYMMDD_with_date'} eq 'yes');
 
3081
  return "UNKNOWN FORMAT";
 
3082
}
 
3083
 
 
3084
 
 
3085
sub print_recordset{
 
3086
  my ($key,$recset) = @_;
 
3087
  my $rec;
 
3088
  foreach $rec (@$recset)
 
3089
  {
 
3090
    add_log($key, " > ".join(',', map(repr($_), @$rec)));
 
3091
  }
 
3092
}
 
3093
 
 
3094
#
 
3095
# read result recordset from sql server. 
 
3096
# returns arrayref to (arrayref to) values
 
3097
# or undef (in case of sql errors)
 
3098
#
 
3099
sub get_recordset{
 
3100
  my ($key,$query) = @_;
 
3101
  add_log($key, "< $query");
 
3102
  return $dbh->selectall_arrayref($query);
 
3103
}
 
3104
 
 
3105
# function for comparing recordset (that was returned by get_recordset)
 
3106
# and arrayref of (arrayref of) values.
 
3107
#
 
3108
# returns : zero if recordset equal that array, 1 if it doesn't equal
 
3109
#
 
3110
# parameters:
 
3111
# $key - current operation (for logging)
 
3112
# $recset - recordset
 
3113
# $mustbe - array of values that we expect
 
3114
#
 
3115
# example: $a=get_recordset('some_parameter','select a,b from c');
 
3116
# if (compare_recordset('some_parameter',$a,[[1,1],[1,2],[1,3]]) neq 0) 
 
3117
# {
 
3118
#   print "unexpected result\n";
 
3119
# } ;
 
3120
#
 
3121
sub compare_recordset {
 
3122
  my ($key,$recset,$mustbe) = @_;
 
3123
  my ($rec,$recno,$fldno,$fcount);
 
3124
  add_log($key,"\n Check recordset:");
 
3125
  $recno=0;
 
3126
  foreach $rec (@$recset)
 
3127
  {
 
3128
    add_log($key," " . join(',', map(repr($_),@$rec)) . " expected: " .
 
3129
            join(',', map(repr($_), @{$mustbe->[$recno]} ) ));
 
3130
    $fcount = @$rec;
 
3131
    $fcount--;
 
3132
    foreach $fldno (0 .. $fcount )
 
3133
    {
 
3134
      if ($mustbe->[$recno][$fldno] ne $rec->[$fldno])
 
3135
      {
 
3136
        add_log($key," Recordset doesn't correspond with template");
 
3137
        return 1;
 
3138
      };
 
3139
    }
 
3140
    $recno++;
 
3141
  }
 
3142
  add_log($key," Recordset corresponds with template");
 
3143
  return 0;
 
3144
}
 
3145
 
 
3146
#
 
3147
# converts inner perl value to printable representation
 
3148
# for example: undef maps to 'NULL',
 
3149
# string -> 'string'
 
3150
# int -> int
 
3151
 
3152
sub repr {
 
3153
  my $s = shift;
 
3154
  return "'$s'"if ($s =~ /\D/);
 
3155
  return 'NULL'if ( not defined($s));
 
3156
  return $s;
 
3157
}
 
3158
 
 
3159
 
 
3160
sub version
 
3161
{
 
3162
  print "$0  Ver $version\n";
 
3163
}
 
3164
 
 
3165
 
 
3166
sub usage
 
3167
{
 
3168
  version();
 
3169
    print <<EOF;
 
3170
 
 
3171
This program tries to find all limits and capabilities for a SQL
 
3172
server.  As it will use the server in some 'unexpected' ways, one
 
3173
shouldn\'t have anything important running on it at the same time this
 
3174
program runs!  There is a slight chance that something unexpected may
 
3175
happen....
 
3176
 
 
3177
As all used queries are legal according to some SQL standard. any
 
3178
reasonable SQL server should be able to run this test without any
 
3179
problems.
 
3180
 
 
3181
All questions is cached in $opt_dir/'server_name'[-suffix].cfg that
 
3182
future runs will use limits found in previous runs. Remove this file
 
3183
if you want to find the current limits for your version of the
 
3184
database server.
 
3185
 
 
3186
This program uses some table names while testing things. If you have any
 
3187
tables with the name of 'crash_me' or 'crash_qxxxx' where 'x' is a number,
 
3188
they will be deleted by this test!
 
3189
 
 
3190
$0 takes the following options:
 
3191
 
 
3192
--help or --Information
 
3193
  Shows this help
 
3194
 
 
3195
--batch-mode
 
3196
  Don\'t ask any questions, quit on errors.
 
3197
 
 
3198
--check-server
 
3199
  Do a new connection to the server every time crash-me checks if the server
 
3200
  is alive.  This can help in cases where the server starts returning wrong
 
3201
  data because of an earlier select.
 
3202
 
 
3203
--comment='some comment'
 
3204
  Add this comment to the crash-me limit file
 
3205
 
 
3206
--config-file='filename'
 
3207
  Read limit results from specific file
 
3208
 
 
3209
--connect-options='some connect options'
 
3210
  Add options, which uses at DBI connect.
 
3211
  For example --connect-options=mysql_read_default_file=/etc/my.cnf.
 
3212
 
 
3213
--database='database' (Default $opt_database)
 
3214
  Create test tables in this database.
 
3215
 
 
3216
--debug
 
3217
  Lots of printing to help debugging if something goes wrong.
 
3218
 
 
3219
--dir='limits'
 
3220
  Save crash-me output in this directory
 
3221
 
 
3222
--fix-limit-file
 
3223
  Reformat the crash-me limit file.  crash-me is not run!
 
3224
 
 
3225
--force
 
3226
  Start test at once, without a warning screen and without questions.
 
3227
  This is a option for the very brave.
 
3228
  Use this in your cron scripts to test your database every night.
 
3229
 
 
3230
--log-all-queries
 
3231
  Prints all queries that are executed. Mostly used for debugging crash-me.
 
3232
 
 
3233
--log-queries-to-file='filename'
 
3234
  Log full queries to file.
 
3235
 
 
3236
--host='hostname' (Default $opt_host)
 
3237
  Run tests on this host.
 
3238
 
 
3239
--password='password'
 
3240
  Password for the current user.
 
3241
   
 
3242
--restart
 
3243
  Save states during each limit tests. This will make it possible to continue
 
3244
  by restarting with the same options if there is some bug in the DBI or
 
3245
  DBD driver that caused $0 to die!
 
3246
 
 
3247
--server='server name'  (Default $opt_server)
 
3248
  Run the test on the given server.
 
3249
  Known servers names are: Access, Adabas, AdabasD, Empress, Oracle, 
 
3250
  Informix, DB2, Mimer, mSQL, MS-SQL, MySQL, Pg, Solid or Sybase.
 
3251
  For others $0 can\'t report the server version.
 
3252
 
 
3253
--suffix='suffix' (Default '')
 
3254
  Add suffix to the output filename. For instance if you run crash-me like
 
3255
  "crash-me --suffix="myisam",
 
3256
  then output filename will look "mysql-myisam.cfg".
 
3257
 
 
3258
--user='user_name'
 
3259
  User name to log into the SQL server.
 
3260
 
 
3261
--db-start-cmd='command to restart server'
 
3262
  Automaticly restarts server with this command if the database server dies.
 
3263
 
 
3264
--sleep='time in seconds' (Default $opt_sleep)
 
3265
  Wait this long before restarting server.
 
3266
 
 
3267
--verbose
 
3268
--noverbose
 
3269
  Log into the result file queries performed for determination parameter value
 
3270
 
 
3271
EOF
 
3272
  exit(0);
 
3273
}
 
3274
 
 
3275
 
 
3276
sub server_info
 
3277
{
 
3278
  my ($ok,$tmp);
 
3279
  $ok=0;
 
3280
  print "\nNOTE: You should be familiar with '$0 --help' before continuing!\n\n";
 
3281
  if (lc($opt_server) eq "mysql")
 
3282
  {
 
3283
    $ok=1;
 
3284
    print <<EOF;
 
3285
This test should not crash MySQL if it was distributed together with the
 
3286
running MySQL version.
 
3287
If this is the case you can probably continue without having to worry about
 
3288
destroying something.
 
3289
EOF
 
3290
  }
 
3291
  elsif (lc($opt_server) eq "msql")
 
3292
  {
 
3293
    print <<EOF;
 
3294
This test will take down mSQL repeatedly while finding limits.
 
3295
To make this test easier, start mSQL in another terminal with something like:
 
3296
 
 
3297
while (true); do /usr/local/mSQL/bin/msql2d ; done
 
3298
 
 
3299
You should be sure that no one is doing anything important with mSQL and that
 
3300
you have privileges to restart it!
 
3301
It may take awhile to determinate the number of joinable tables, so prepare to
 
3302
wait!
 
3303
EOF
 
3304
  }
 
3305
  elsif (lc($opt_server) eq "solid")
 
3306
  {
 
3307
    print <<EOF;
 
3308
This test will take down Solid server repeatedly while finding limits.
 
3309
You should be sure that no one is doing anything important with Solid
 
3310
and that you have privileges to restart it!
 
3311
 
 
3312
If you are running Solid without logging and/or backup YOU WILL LOSE!
 
3313
Solid does not write data from the cache often enough. So if you continue
 
3314
you may lose tables and data that you entered hours ago!
 
3315
 
 
3316
Solid will also take a lot of memory running this test. You will nead
 
3317
at least 234M free!
 
3318
 
 
3319
When doing the connect test Solid server or the perl api will hang when
 
3320
freeing connections. Kill this program and restart it to continue with the
 
3321
test. You don\'t have to use --restart for this case.
 
3322
EOF
 
3323
    if (!$opt_restart)
 
3324
    {
 
3325
      print "\nWhen DBI/Solid dies you should run this program repeatedly\n";
 
3326
      print "with --restart until all tests have completed\n";
 
3327
    }
 
3328
  }
 
3329
  elsif (lc($opt_server) eq "pg")
 
3330
  {
 
3331
    print <<EOF;
 
3332
This test will crash postgreSQL when calculating the number of joinable tables!
 
3333
You should be sure that no one is doing anything important with postgreSQL
 
3334
and that you have privileges to restart it!
 
3335
EOF
 
3336
  }
 
3337
  else
 
3338
  {
 
3339
    print <<EOF;
 
3340
This test may crash $opt_server repeatedly while finding limits!
 
3341
You should be sure that no one is doing anything important with $opt_server
 
3342
and that you have privileges to restart it!
 
3343
EOF
 
3344
  }
 
3345
  print <<EOF;
 
3346
 
 
3347
Some of the tests you are about to execute may require a lot of
 
3348
memory.  Your tests WILL adversely affect system performance. It\'s
 
3349
not uncommon that either this crash-me test program, or the actual
 
3350
database back-end, will DIE with an out-of-memory error. So might
 
3351
any other program on your system if it requests more memory at the
 
3352
wrong time.
 
3353
 
 
3354
Note also that while crash-me tries to find limits for the database server
 
3355
it will make a lot of queries that can\'t be categorized as \'normal\'.  It\'s
 
3356
not unlikely that crash-me finds some limit bug in your server so if you
 
3357
run this test you have to be prepared that your server may die during it!
 
3358
 
 
3359
We, the creators of this utility, are not responsible in any way if your
 
3360
database server unexpectedly crashes while this program tries to find the
 
3361
limitations of your server. By accepting the following question with \'yes\',
 
3362
you agree to the above!
 
3363
 
 
3364
You have been warned!
 
3365
 
 
3366
EOF
 
3367
 
 
3368
  #
 
3369
  # No default reply here so no one can blame us for starting the test
 
3370
  # automaticly.
 
3371
  #
 
3372
  for (;;)
 
3373
  {
 
3374
    print "Start test (yes/no) ? ";
 
3375
    $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
 
3376
    last if ($tmp =~ /^yes$/i);
 
3377
    exit 1 if ($tmp =~ /^n/i);
 
3378
    print "\n";
 
3379
  }
 
3380
}
 
3381
 
 
3382
#sub machine
 
3383
#{
 
3384
#  my @name = POSIX::uname();
 
3385
#  my $name= $name[0] . " " . $name[2] . " " . $name[4];
 
3386
#  return $name;
 
3387
#}
 
3388
 
 
3389
 
 
3390
#
 
3391
# Help functions that we need
 
3392
#
 
3393
 
 
3394
sub safe_connect
 
3395
{
 
3396
  my ($object)=@_;
 
3397
  my ($dbh,$tmp);
 
3398
 
 
3399
  for (;;)
 
3400
  {
 
3401
    if (($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
 
3402
                           { PrintError => 0, AutoCommit => 1})))
 
3403
    {
 
3404
      $dbh->{LongReadLen}= 16000000; # Set max retrieval buffer
 
3405
      return $dbh;
 
3406
    }
 
3407
    print "Error: $DBI::errstr;  $server->{'data_source'} ".
 
3408
        " - '$opt_user' - '$opt_password'\n";
 
3409
    print "I got the above error when connecting to $opt_server\n";
 
3410
    if (defined($object) && defined($object->{'limit'}))
 
3411
    {
 
3412
      print "This check was done with limit: $object->{'limit'}.".
 
3413
          "\nNext check will be done with a smaller limit!\n";
 
3414
      $object=undef();
 
3415
    }
 
3416
    save_config_data('crash_me_safe','no',"crash me safe");
 
3417
    if ($opt_db_start_cmd)
 
3418
    {
 
3419
      print "Restarting the db server with:\n'$opt_db_start_cmd'\n";
 
3420
      system("$opt_db_start_cmd");
 
3421
      print "Waiting $opt_sleep seconds so the server can initialize\n";
 
3422
      sleep $opt_sleep;
 
3423
    }
 
3424
    else
 
3425
    {
 
3426
      exit(1) if ($opt_batch_mode);
 
3427
      print "Can you check/restart it so I can continue testing?\n";
 
3428
      for (;;)
 
3429
      {
 
3430
        print "Continue test (yes/no) ? [yes] ";
 
3431
        $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
 
3432
        $tmp = "yes" if ($tmp eq "");
 
3433
        last if (index("yes",$tmp) >= 0);
 
3434
        exit 1 if (index("no",$tmp) >= 0);
 
3435
        print "\n";
 
3436
      }
 
3437
    }
 
3438
  }
 
3439
}
 
3440
 
 
3441
#
 
3442
# Test connecting a couple of times before giving an error
 
3443
# This is needed to get the server time to free old connections
 
3444
# after the connect test
 
3445
#
 
3446
 
 
3447
sub retry_connect
 
3448
{
 
3449
  my ($dbh, $i);
 
3450
  for ($i=0 ; $i < 10 ; $i++)
 
3451
  {
 
3452
    if (($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
 
3453
                         { PrintError => 0, AutoCommit => 1})))
 
3454
    {
 
3455
      $dbh->{LongReadLen}= 16000000; # Set max retrieval buffer
 
3456
      return $dbh;
 
3457
    }
 
3458
    sleep(1);
 
3459
  }
 
3460
  return safe_connect();
 
3461
}
 
3462
 
 
3463
#
 
3464
# Check if the server is up and running. If not, ask the user to restart it
 
3465
#
 
3466
 
 
3467
sub check_connect
 
3468
{
 
3469
  my ($object)=@_;
 
3470
  my ($sth);
 
3471
  print "Checking connection\n" if ($opt_log_all_queries);
 
3472
  # The following line will not work properly with interbase
 
3473
  if ($opt_check_server && defined($check_connect) && $dbh->{AutoCommit} != 0)
 
3474
  {
 
3475
    
 
3476
    $dbh->disconnect;
 
3477
    $dbh=safe_connect($object);
 
3478
    return;
 
3479
  }
 
3480
  return if (defined($check_connect) && defined($dbh->do($check_connect)));
 
3481
  $dbh->disconnect || warn $dbh->errstr;
 
3482
  print "\nreconnecting\n" if ($opt_debug);
 
3483
  $reconnect_count++;
 
3484
  undef($dbh);
 
3485
  $dbh=safe_connect($object);
 
3486
}
 
3487
 
 
3488
#
 
3489
# print query if debugging
 
3490
#
 
3491
sub repr_query {
 
3492
  my $query=shift;
 
3493
 if (length($query) > 130)
 
3494
 {
 
3495
   $query=substr($query,0,120) . "...(" . (length($query)-120) . ")";
 
3496
 }
 
3497
 return $query;
 
3498
}  
 
3499
 
 
3500
sub print_query
 
3501
{
 
3502
  my ($query)=@_;
 
3503
  $last_error=$DBI::errstr;
 
3504
  if ($opt_debug)
 
3505
  {
 
3506
    if (length($query) > 130)
 
3507
    {
 
3508
      $query=substr($query,0,120) . "...(" . (length($query)-120) . ")";
 
3509
    }
 
3510
    printf "\nGot error from query: '%s'\n%s\n",$query,$DBI::errstr;
 
3511
  }
 
3512
}
 
3513
 
 
3514
#
 
3515
# Do one or many queries. Return 1 if all was ok
 
3516
# Note that all rows are executed 
 
3517
# (to ensure that we execute drop table commands)
 
3518
#
 
3519
 
 
3520
sub safe_query_l {
 
3521
  my $key = shift;
 
3522
  my $q = shift;
 
3523
  my $r = safe_query($q);
 
3524
  add_log($key,$safe_query_log);
 
3525
  return $r;
 
3526
}
 
3527
 
 
3528
sub safe_query
 
3529
{
 
3530
  my($queries)=@_;
 
3531
  my($query,$ok,$retry_ok,$retry,@tmp,$sth);
 
3532
  $safe_query_log="";
 
3533
  $ok=1;
 
3534
  if (ref($queries) ne "ARRAY")
 
3535
  {
 
3536
    push(@tmp,$queries);
 
3537
    $queries= \@tmp;
 
3538
  }
 
3539
  foreach $query (@$queries)
 
3540
  {
 
3541
    printf "query1: %-80.80s ...(%d - %d)\n",$query,
 
3542
          length($query),$retry_limit  if ($opt_log_all_queries);
 
3543
    print LOG "$query;\n" if ($opt_log);
 
3544
    $safe_query_log .= "< $query\n";
 
3545
    if (length($query) > $query_size)
 
3546
    {
 
3547
      $ok=0;
 
3548
      $safe_query_log .= "Query is too long\n";
 
3549
      next;
 
3550
    }
 
3551
 
 
3552
    $retry_ok=0;
 
3553
    for ($retry=0; $retry < $retry_limit ; $retry++)
 
3554
    {
 
3555
      if (! ($sth=$dbh->prepare($query)))
 
3556
      {
 
3557
        print_query($query);
 
3558
        $safe_query_log .= "> couldn't prepare:". $dbh->errstr. "\n";
 
3559
        $retry=100 if (!$server->abort_if_fatal_error());
 
3560
        # Force a reconnect because of Access drop table bug!
 
3561
        if ($retry == $retry_limit-2)
 
3562
        {
 
3563
          print "Forcing disconnect to retry query\n" if ($opt_debug);
 
3564
          $dbh->disconnect || warn $dbh->errstr;
 
3565
        }
 
3566
        check_connect();        # Check that server is still up
 
3567
      }
 
3568
      else
 
3569
      {
 
3570
        if (!$sth->execute())
 
3571
        {
 
3572
          print_query($query);
 
3573
          $safe_query_log .= "> execute error:". $dbh->errstr. "\n";
 
3574
          $retry=100 if (!$server->abort_if_fatal_error());
 
3575
          # Force a reconnect because of Access drop table bug!
 
3576
          if ($retry == $retry_limit-2)
 
3577
          {
 
3578
            print "Forcing disconnect to retry query\n" if ($opt_debug);
 
3579
            $dbh->disconnect || warn $dbh->errstr;
 
3580
          }
 
3581
          check_connect();        # Check that server is still up
 
3582
        }
 
3583
        else
 
3584
        {
 
3585
          $retry = $retry_limit;
 
3586
          $retry_ok = 1;
 
3587
          $safe_query_log .= "> OK\n";
 
3588
        }
 
3589
        $sth->finish;
 
3590
      }
 
3591
    }
 
3592
    $ok=0 if (!$retry_ok);
 
3593
    if ($query =~ /create/i && $server->reconnect_on_errors())
 
3594
    {
 
3595
      print "Forcing disconnect to retry query\n" if ($opt_debug);
 
3596
      $dbh->disconnect || warn $dbh->errstr;
 
3597
      $dbh=safe_connect();
 
3598
    }
 
3599
  }
 
3600
  return $ok;
 
3601
}
 
3602
 
 
3603
sub check_reserved_words
 
3604
{
 
3605
  my ($dbh)= @_;
 
3606
 
 
3607
  my ($answer, $prompt, $config, $keyword_type);
 
3608
 
 
3609
  my @keywords_ext  = ( "ansi-92/99", "ansi92", "ansi99", "extra");
 
3610
 
 
3611
  my %reserved_words = (
 
3612
        'ABSOLUTE' =>  0,          'ACTION' =>  0,             'ADD' =>  0,
 
3613
           'AFTER' =>  0,           'ALIAS' =>  0,             'ALL' =>  0,
 
3614
        'ALLOCATE' =>  0,           'ALTER' =>  0,             'AND' =>  0,
 
3615
             'ANY' =>  0,             'ARE' =>  0,              'AS' =>  0,
 
3616
             'ASC' =>  0,       'ASSERTION' =>  0,              'AT' =>  0,
 
3617
   'AUTHORIZATION' =>  0,          'BEFORE' =>  0,           'BEGIN' =>  0,
 
3618
             'BIT' =>  0,         'BOOLEAN' =>  0,            'BOTH' =>  0,
 
3619
         'BREADTH' =>  0,              'BY' =>  0,            'CALL' =>  0,
 
3620
         'CASCADE' =>  0,        'CASCADED' =>  0,            'CASE' =>  0,
 
3621
            'CAST' =>  0,         'CATALOG' =>  0,            'CHAR' =>  0,
 
3622
       'CHARACTER' =>  0,           'CHECK' =>  0,           'CLOSE' =>  0,
 
3623
         'COLLATE' =>  0,       'COLLATION' =>  0,          'COLUMN' =>  0,
 
3624
          'COMMIT' =>  0,      'COMPLETION' =>  0,         'CONNECT' =>  0,
 
3625
      'CONNECTION' =>  0,      'CONSTRAINT' =>  0,     'CONSTRAINTS' =>  0,
 
3626
        'CONTINUE' =>  0,   'CORRESPONDING' =>  0,          'CREATE' =>  0,
 
3627
           'CROSS' =>  0,         'CURRENT' =>  0,    'CURRENT_DATE' =>  0,
 
3628
    'CURRENT_TIME' =>  0,'CURRENT_TIMESTAMP' =>  0,   'CURRENT_USER' =>  0,
 
3629
          'CURSOR' =>  0,           'CYCLE' =>  0,            'DATA' =>  0,
 
3630
            'DATE' =>  0,             'DAY' =>  0,      'DEALLOCATE' =>  0,
 
3631
             'DEC' =>  0,         'DECIMAL' =>  0,         'DECLARE' =>  0,
 
3632
         'DEFAULT' =>  0,      'DEFERRABLE' =>  0,        'DEFERRED' =>  0,
 
3633
          'DELETE' =>  0,           'DEPTH' =>  0,            'DESC' =>  0,
 
3634
        'DESCRIBE' =>  0,      'DESCRIPTOR' =>  0,     'DIAGNOSTICS' =>  0,
 
3635
      'DICTIONARY' =>  0,      'DISCONNECT' =>  0,        'DISTINCT' =>  0,
 
3636
          'DOMAIN' =>  0,          'DOUBLE' =>  0,            'DROP' =>  0,
 
3637
            'EACH' =>  0,            'ELSE' =>  0,          'ELSEIF' =>  0,
 
3638
             'END' =>  0,        'END-EXEC' =>  0,          'EQUALS' =>  0,
 
3639
          'ESCAPE' =>  0,          'EXCEPT' =>  0,       'EXCEPTION' =>  0,
 
3640
            'EXEC' =>  0,         'EXECUTE' =>  0,        'EXTERNAL' =>  0,
 
3641
           'FALSE' =>  0,           'FETCH' =>  0,           'FIRST' =>  0,
 
3642
           'FLOAT' =>  0,             'FOR' =>  0,         'FOREIGN' =>  0,
 
3643
           'FOUND' =>  0,            'FROM' =>  0,            'FULL' =>  0,
 
3644
         'GENERAL' =>  0,             'GET' =>  0,          'GLOBAL' =>  0,
 
3645
              'GO' =>  0,            'GOTO' =>  0,           'GRANT' =>  0,
 
3646
           'GROUP' =>  0,          'HAVING' =>  0,            'HOUR' =>  0,
 
3647
        'IDENTITY' =>  0,              'IF' =>  0,          'IGNORE' =>  0,
 
3648
       'IMMEDIATE' =>  0,              'IN' =>  0,       'INDICATOR' =>  0,
 
3649
       'INITIALLY' =>  0,           'INNER' =>  0,           'INPUT' =>  0,
 
3650
          'INSERT' =>  0,             'INT' =>  0,         'INTEGER' =>  0,
 
3651
       'INTERSECT' =>  0,        'INTERVAL' =>  0,            'INTO' =>  0,
 
3652
              'IS' =>  0,       'ISOLATION' =>  0,            'JOIN' =>  0,
 
3653
             'KEY' =>  0,        'LANGUAGE' =>  0,            'LAST' =>  0,
 
3654
         'LEADING' =>  0,           'LEAVE' =>  0,            'LEFT' =>  0,
 
3655
            'LESS' =>  0,           'LEVEL' =>  0,            'LIKE' =>  0,
 
3656
           'LIMIT' =>  0,           'LOCAL' =>  0,            'LOOP' =>  0,
 
3657
           'MATCH' =>  0,          'MINUTE' =>  0,          'MODIFY' =>  0,
 
3658
          'MODULE' =>  0,           'MONTH' =>  0,           'NAMES' =>  0,
 
3659
        'NATIONAL' =>  0,         'NATURAL' =>  0,           'NCHAR' =>  0,
 
3660
             'NEW' =>  0,            'NEXT' =>  0,              'NO' =>  0,
 
3661
            'NONE' =>  0,             'NOT' =>  0,            'NULL' =>  0,
 
3662
         'NUMERIC' =>  0,          'OBJECT' =>  0,              'OF' =>  0,
 
3663
             'OFF' =>  0,             'OLD' =>  0,              'ON' =>  0,
 
3664
            'ONLY' =>  0,            'OPEN' =>  0,       'OPERATION' =>  0,
 
3665
          'OPTION' =>  0,              'OR' =>  0,           'ORDER' =>  0,
 
3666
           'OUTER' =>  0,          'OUTPUT' =>  0,             'PAD' =>  0,
 
3667
      'PARAMETERS' =>  0,         'PARTIAL' =>  0,       'PRECISION' =>  0,
 
3668
        'PREORDER' =>  0,         'PREPARE' =>  0,        'PRESERVE' =>  0,
 
3669
         'PRIMARY' =>  0,           'PRIOR' =>  0,      'PRIVILEGES' =>  0,
 
3670
       'PROCEDURE' =>  0,          'PUBLIC' =>  0,            'READ' =>  0,
 
3671
            'REAL' =>  0,       'RECURSIVE' =>  0,             'REF' =>  0,
 
3672
      'REFERENCES' =>  0,     'REFERENCING' =>  0,        'RELATIVE' =>  0,
 
3673
        'RESIGNAL' =>  0,        'RESTRICT' =>  0,          'RETURN' =>  0,
 
3674
         'RETURNS' =>  0,          'REVOKE' =>  0,           'RIGHT' =>  0,
 
3675
            'ROLE' =>  0,        'ROLLBACK' =>  0,         'ROUTINE' =>  0,
 
3676
             'ROW' =>  0,            'ROWS' =>  0,       'SAVEPOINT' =>  0,
 
3677
          'SCHEMA' =>  0,          'SCROLL' =>  0,          'SEARCH' =>  0,
 
3678
          'SECOND' =>  0,         'SECTION' =>  0,          'SELECT' =>  0,
 
3679
        'SEQUENCE' =>  0,         'SESSION' =>  0,    'SESSION_USER' =>  0,
 
3680
             'SET' =>  0,          'SIGNAL' =>  0,            'SIZE' =>  0,
 
3681
        'SMALLINT' =>  0,            'SOME' =>  0,           'SPACE' =>  0,
 
3682
             'SQL' =>  0,    'SQLEXCEPTION' =>  0,        'SQLSTATE' =>  0,
 
3683
      'SQLWARNING' =>  0,       'STRUCTURE' =>  0,     'SYSTEM_USER' =>  0,
 
3684
           'TABLE' =>  0,       'TEMPORARY' =>  0,            'THEN' =>  0,
 
3685
            'TIME' =>  0,       'TIMESTAMP' =>  0,   'TIMEZONE_HOUR' =>  0,
 
3686
 'TIMEZONE_MINUTE' =>  0,              'TO' =>  0,        'TRAILING' =>  0,
 
3687
     'TRANSACTION' =>  0,     'TRANSLATION' =>  0,         'TRIGGER' =>  0,
 
3688
            'TRUE' =>  0,           'UNDER' =>  0,           'UNION' =>  0,
 
3689
          'UNIQUE' =>  0,         'UNKNOWN' =>  0,          'UPDATE' =>  0,
 
3690
           'USAGE' =>  0,            'USER' =>  0,           'USING' =>  0,
 
3691
           'VALUE' =>  0,          'VALUES' =>  0,         'VARCHAR' =>  0,
 
3692
        'VARIABLE' =>  0,         'VARYING' =>  0,            'VIEW' =>  0,
 
3693
            'WHEN' =>  0,        'WHENEVER' =>  0,           'WHERE' =>  0,
 
3694
           'WHILE' =>  0,            'WITH' =>  0,         'WITHOUT' =>  0,
 
3695
            'WORK' =>  0,           'WRITE' =>  0,            'YEAR' =>  0,
 
3696
            'ZONE' =>  0,
 
3697
 
 
3698
           'ASYNC' =>  1,             'AVG' =>  1,         'BETWEEN' =>  1,
 
3699
      'BIT_LENGTH' =>  1,'CHARACTER_LENGTH' =>  1,     'CHAR_LENGTH' =>  1,
 
3700
        'COALESCE' =>  1,         'CONVERT' =>  1,           'COUNT' =>  1,
 
3701
          'EXISTS' =>  1,         'EXTRACT' =>  1,     'INSENSITIVE' =>  1,
 
3702
           'LOWER' =>  1,             'MAX' =>  1,             'MIN' =>  1,
 
3703
          'NULLIF' =>  1,    'OCTET_LENGTH' =>  1,             'OID' =>  1,
 
3704
       'OPERATORS' =>  1,          'OTHERS' =>  1,        'OVERLAPS' =>  1,
 
3705
         'PENDANT' =>  1,        'POSITION' =>  1,         'PRIVATE' =>  1,
 
3706
       'PROTECTED' =>  1,         'REPLACE' =>  1,       'SENSITIVE' =>  1,
 
3707
         'SIMILAR' =>  1,         'SQLCODE' =>  1,        'SQLERROR' =>  1,
 
3708
       'SUBSTRING' =>  1,             'SUM' =>  1,            'TEST' =>  1,
 
3709
           'THERE' =>  1,       'TRANSLATE' =>  1,            'TRIM' =>  1,
 
3710
            'TYPE' =>  1,           'UPPER' =>  1,         'VIRTUAL' =>  1,
 
3711
         'VISIBLE' =>  1,            'WAIT' =>  1,
 
3712
 
 
3713
           'ADMIN' =>  2,       'AGGREGATE' =>  2,           'ARRAY' =>  2,
 
3714
          'BINARY' =>  2,            'BLOB' =>  2,           'CLASS' =>  2,
 
3715
            'CLOB' =>  2,       'CONDITION' =>  2,     'CONSTRUCTOR' =>  2,
 
3716
        'CONTAINS' =>  2,            'CUBE' =>  2,    'CURRENT_PATH' =>  2,
 
3717
    'CURRENT_ROLE' =>  2,        'DATALINK' =>  2,           'DEREF' =>  2,
 
3718
         'DESTROY' =>  2,      'DESTRUCTOR' =>  2,   'DETERMINISTIC' =>  2,
 
3719
              'DO' =>  2,         'DYNAMIC' =>  2,           'EVERY' =>  2,
 
3720
            'EXIT' =>  2,          'EXPAND' =>  2,       'EXPANDING' =>  2,
 
3721
            'FREE' =>  2,        'FUNCTION' =>  2,        'GROUPING' =>  2,
 
3722
         'HANDLER' =>  2,            'HAST' =>  2,            'HOST' =>  2,
 
3723
      'INITIALIZE' =>  2,           'INOUT' =>  2,         'ITERATE' =>  2,
 
3724
           'LARGE' =>  2,         'LATERAL' =>  2,       'LOCALTIME' =>  2,
 
3725
  'LOCALTIMESTAMP' =>  2,         'LOCATOR' =>  2,           'MEETS' =>  2,
 
3726
        'MODIFIES' =>  2,           'NCLOB' =>  2,       'NORMALIZE' =>  2,
 
3727
      'ORDINALITY' =>  2,             'OUT' =>  2,       'PARAMETER' =>  2,
 
3728
            'PATH' =>  2,          'PERIOD' =>  2,         'POSTFIX' =>  2,
 
3729
        'PRECEDES' =>  2,          'PREFIX' =>  2,           'READS' =>  2,
 
3730
            'REDO' =>  2,          'REPEAT' =>  2,          'RESULT' =>  2,
 
3731
          'ROLLUP' =>  2,            'SETS' =>  2,        'SPECIFIC' =>  2,
 
3732
    'SPECIFICTYPE' =>  2,           'START' =>  2,           'STATE' =>  2,
 
3733
          'STATIC' =>  2,        'SUCCEEDS' =>  2,       'TERMINATE' =>  2,
 
3734
            'THAN' =>  2,           'TREAT' =>  2,            'UNDO' =>  2,
 
3735
           'UNTIL' =>  2,
 
3736
 
 
3737
          'ACCESS' =>  3,         'ANALYZE' =>  3,           'AUDIT' =>  3,
 
3738
  'AUTO_INCREMENT' =>  3,          'BACKUP' =>  3,             'BDB' =>  3,
 
3739
      'BERKELEYDB' =>  3,          'BIGINT' =>  3,           'BREAK' =>  3,
 
3740
          'BROWSE' =>  3,           'BTREE' =>  3,            'BULK' =>  3,
 
3741
          'CHANGE' =>  3,      'CHECKPOINT' =>  3,         'CLUSTER' =>  3,
 
3742
       'CLUSTERED' =>  3,         'COLUMNS' =>  3,         'COMMENT' =>  3,
 
3743
        'COMPRESS' =>  3,         'COMPUTE' =>  3,   'CONTAINSTABLE' =>  3,
 
3744
        'DATABASE' =>  3,       'DATABASES' =>  3,        'DAY_HOUR' =>  3,
 
3745
      'DAY_MINUTE' =>  3,      'DAY_SECOND' =>  3,            'DBCC' =>  3,
 
3746
         'DELAYED' =>  3,            'DENY' =>  3,            'DISK' =>  3,
 
3747
     'DISTINCTROW' =>  3,     'DISTRIBUTED' =>  3,           'DUMMY' =>  3,
 
3748
            'DUMP' =>  3,        'ENCLOSED' =>  3,          'ERRLVL' =>  3,
 
3749
          'ERRORS' =>  3,         'ESCAPED' =>  3,       'EXCLUSIVE' =>  3,
 
3750
         'EXPLAIN' =>  3,          'FIELDS' =>  3,            'FILE' =>  3,
 
3751
      'FILLFACTOR' =>  3,        'FREETEXT' =>  3,   'FREETEXTTABLE' =>  3,
 
3752
        'FULLTEXT' =>  3,        'GEOMETRY' =>  3,            'HASH' =>  3,
 
3753
   'HIGH_PRIORITY' =>  3,        'HOLDLOCK' =>  3,     'HOUR_MINUTE' =>  3,
 
3754
     'HOUR_SECOND' =>  3,      'IDENTIFIED' =>  3,     'IDENTITYCOL' =>  3,
 
3755
 'IDENTITY_INSERT' =>  3,       'INCREMENT' =>  3,           'INDEX' =>  3,
 
3756
          'INFILE' =>  3,         'INITIAL' =>  3,          'INNODB' =>  3,
 
3757
            'KEYS' =>  3,            'KILL' =>  3,          'LINENO' =>  3,
 
3758
           'LINES' =>  3,            'LOAD' =>  3,            'LOCK' =>  3,
 
3759
            'LONG' =>  3,        'LONGBLOB' =>  3,        'LONGTEXT' =>  3,
 
3760
    'LOW_PRIORITY' =>  3, 'MASTER_SERVER_ID' =>  3,      'MAXEXTENTS' =>  3,
 
3761
      'MEDIUMBLOB' =>  3,       'MEDIUMINT' =>  3,      'MEDIUMTEXT' =>  3,
 
3762
       'MIDDLEINT' =>  3,           'MINUS' =>  3,   'MINUTE_SECOND' =>  3,
 
3763
        'MLSLABEL' =>  3,            'MODE' =>  3,      'MRG_MYISAM' =>  3,
 
3764
         'NOAUDIT' =>  3,         'NOCHECK' =>  3,      'NOCOMPRESS' =>  3,
 
3765
    'NONCLUSTERED' =>  3,          'NOWAIT' =>  3,          'NUMBER' =>  3,
 
3766
         'OFFLINE' =>  3,         'OFFSETS' =>  3,          'ONLINE' =>  3,
 
3767
  'OPENDATASOURCE' =>  3,       'OPENQUERY' =>  3,      'OPENROWSET' =>  3,
 
3768
         'OPENXML' =>  3,        'OPTIMIZE' =>  3,      'OPTIONALLY' =>  3,
 
3769
         'OUTFILE' =>  3,            'OVER' =>  3,         'PCTFREE' =>  3,
 
3770
         'PERCENT' =>  3,            'PLAN' =>  3,           'PRINT' =>  3,
 
3771
            'PROC' =>  3,           'PURGE' =>  3,       'RAISERROR' =>  3,
 
3772
             'RAW' =>  3,        'READTEXT' =>  3,     'RECONFIGURE' =>  3,
 
3773
          'REGEXP' =>  3,          'RENAME' =>  3,     'REPLICATION' =>  3,
 
3774
         'REQUIRE' =>  3,        'RESOURCE' =>  3,         'RESTORE' =>  3,
 
3775
           'RLIKE' =>  3,        'ROWCOUNT' =>  3,      'ROWGUIDCOL' =>  3,
 
3776
           'ROWID' =>  3,          'ROWNUM' =>  3,           'RTREE' =>  3,
 
3777
            'RULE' =>  3,            'SAVE' =>  3,         'SETUSER' =>  3,
 
3778
           'SHARE' =>  3,            'SHOW' =>  3,        'SHUTDOWN' =>  3,
 
3779
          'SONAME' =>  3,         'SPATIAL' =>  3,  'SQL_BIG_RESULT' =>  3,
 
3780
'SQL_CALC_FOUND_ROWS' =>  3,'SQL_SMALL_RESULT' =>  3,        'SSL' =>  3,
 
3781
        'STARTING' =>  3,      'STATISTICS' =>  3,   'STRAIGHT_JOIN' =>  3,
 
3782
         'STRIPED' =>  3,      'SUCCESSFUL' =>  3,         'SYNONYM' =>  3,
 
3783
         'SYSDATE' =>  3,          'TABLES' =>  3,      'TERMINATED' =>  3,
 
3784
        'TEXTSIZE' =>  3,        'TINYBLOB' =>  3,         'TINYINT' =>  3,
 
3785
        'TINYTEXT' =>  3,             'TOP' =>  3,            'TRAN' =>  3,
 
3786
        'TRUNCATE' =>  3,         'TSEQUAL' =>  3,           'TYPES' =>  3,
 
3787
             'UID' =>  3,          'UNLOCK' =>  3,        'UNSIGNED' =>  3,
 
3788
      'UPDATETEXT' =>  3,             'USE' =>  3,  'USER_RESOURCES' =>  3,
 
3789
        'VALIDATE' =>  3,       'VARBINARY' =>  3,        'VARCHAR2' =>  3,
 
3790
         'WAITFOR' =>  3,        'WARNINGS' =>  3,       'WRITETEXT' =>  3,
 
3791
             'XOR' =>  3,      'YEAR_MONTH' =>  3,        'ZEROFILL' =>  3
 
3792
);
 
3793
 
 
3794
 
 
3795
  safe_query("drop table crash_me10 $drop_attr");
 
3796
 
 
3797
  foreach my $keyword (sort {$a cmp $b} keys %reserved_words)
 
3798
  {
 
3799
    $keyword_type= $reserved_words{$keyword};
 
3800
 
 
3801
    $prompt= "Keyword ".$keyword;
 
3802
    $config= "reserved_word_".$keywords_ext[$keyword_type]."_".lc($keyword);
 
3803
 
 
3804
    report_fail($prompt,$config,
 
3805
      "create table crash_me10 ($keyword int not null)",
 
3806
      "drop table crash_me10 $drop_attr"
 
3807
    );
 
3808
  }
 
3809
}
 
3810
 
 
3811
#
 
3812
# Do a query on a query package object.
 
3813
#
 
3814
 
 
3815
sub limit_query
 
3816
{
 
3817
  my($object,$limit)=@_;
 
3818
  my ($query,$result,$retry,$sth);
 
3819
 
 
3820
  $query=$object->query($limit);
 
3821
  $result=safe_query($query);
 
3822
  if (!$result)
 
3823
  {
 
3824
    $object->cleanup();
 
3825
    return 0;
 
3826
  }
 
3827
  if (defined($query=$object->check_query()))
 
3828
  {
 
3829
    for ($retry=0 ; $retry < $retry_limit ; $retry++)
 
3830
    {
 
3831
      printf "query2: %-80.80s\n",$query if ($opt_log_all_queries);
 
3832
      print LOG "$query;\n" if ($opt_log);
 
3833
      if (($sth= $dbh->prepare($query)))
 
3834
      {
 
3835
        if ($sth->execute)
 
3836
        {
 
3837
          $result= $object->check($sth);
 
3838
          $sth->finish;
 
3839
          $object->cleanup();
 
3840
          return $result;
 
3841
        }
 
3842
        print_query($query);
 
3843
        $sth->finish;
 
3844
      }
 
3845
      else
 
3846
      {
 
3847
        print_query($query);
 
3848
      }
 
3849
      $retry=100 if (!$server->abort_if_fatal_error()); # No need to continue
 
3850
      if ($retry == $retry_limit-2)
 
3851
      {
 
3852
        print "Forcing discoennect to retry query\n" if ($opt_debug);
 
3853
        $dbh->disconnect || warn $dbh->errstr;
 
3854
      }
 
3855
      check_connect($object);   # Check that server is still up
 
3856
    }
 
3857
    $result=0;                  # Query failed
 
3858
  }
 
3859
  $object->cleanup();
 
3860
  return $result;               # Server couldn't handle the query
 
3861
}
 
3862
 
 
3863
 
 
3864
sub report
 
3865
{
 
3866
  my ($prompt,$limit,@queries)=@_;
 
3867
  print "$prompt: ";
 
3868
  if (!defined($limits{$limit}))
 
3869
  {
 
3870
    #print "Found limits for $prompt $limit\n";
 
3871
    my $queries_result = safe_query(\@queries);
 
3872
    add_log($limit, $safe_query_log);
 
3873
    my $report_result;
 
3874
    if ( $queries_result) {
 
3875
      $report_result= "yes";
 
3876
      add_log($limit,"As far as all queries returned OK, result is YES");
 
3877
    } else {
 
3878
      $report_result= "no";
 
3879
      add_log($limit,"As far as some queries didnt return OK, result is NO");
 
3880
    } 
 
3881
    save_config_data($limit,$report_result,$prompt);
 
3882
  }
 
3883
  print "REPORT $prompt $limits{$limit}\n";
 
3884
  return $limits{$limit} ne "no";
 
3885
}
 
3886
 
 
3887
sub report_fail
 
3888
{
 
3889
  my ($prompt,$limit,@queries)=@_;
 
3890
  print "$prompt: ";
 
3891
  if (!defined($limits{$limit}))
 
3892
  {
 
3893
    my $queries_result = safe_query(\@queries);
 
3894
    add_log($limit, $safe_query_log);
 
3895
    my $report_result;
 
3896
    if ( $queries_result) {
 
3897
      $report_result= "no";
 
3898
      add_log($limit,"As far as all queries returned OK, result is NO");
 
3899
    } else {
 
3900
      $report_result= "yes";
 
3901
      add_log($limit,"As far as some queries didnt return OK, result is YES");
 
3902
    } 
 
3903
    save_config_data($limit,$report_result,$prompt);
 
3904
  }
 
3905
  print "$limits{$limit}\n";
 
3906
  return $limits{$limit} ne "no";
 
3907
}
 
3908
 
 
3909
 
 
3910
# Return true if one of the queries is ok
 
3911
 
 
3912
sub report_one
 
3913
{
 
3914
  my ($prompt,$limit,$queries)=@_;
 
3915
  my ($query,$res,$result);
 
3916
  print "$prompt: ";
 
3917
  if (!defined($limits{$limit}))
 
3918
  {
 
3919
    save_incomplete($limit,$prompt);
 
3920
    $result="no";
 
3921
    foreach $query (@$queries)
 
3922
    {
 
3923
      if (safe_query_l($limit,$query->[0]))
 
3924
      {
 
3925
        $result= $query->[1];
 
3926
        last;
 
3927
      }
 
3928
    }
 
3929
    save_config_data($limit,$result,$prompt);
 
3930
  }
 
3931
  print "$limits{$limit}\n";
 
3932
  return $limits{$limit} ne "no";
 
3933
}
 
3934
 
 
3935
 
 
3936
# Execute query and save result as limit value.
 
3937
 
 
3938
sub report_result
 
3939
{
 
3940
  my ($prompt,$limit,$query)=@_;
 
3941
  my($error);
 
3942
  print "$prompt: ";
 
3943
  if (!defined($limits{$limit}))
 
3944
  {
 
3945
    save_incomplete($limit,$prompt);
 
3946
    $error=safe_query_result($query,"1",2);
 
3947
    add_log($limit,$safe_query_result_log);
 
3948
    save_config_data($limit,$error ? "not supported" :$last_result,$prompt);
 
3949
  }
 
3950
  print "$limits{$limit}\n";
 
3951
  return $limits{$limit} ne "not supported";
 
3952
}
 
3953
 
 
3954
sub report_trans
 
3955
{
 
3956
  my ($limit,$queries,$check,$clear)=@_;
 
3957
  if (!defined($limits{$limit}))
 
3958
  {
 
3959
    save_incomplete($limit,$prompt);
 
3960
    eval {undef($dbh->{AutoCommit})};
 
3961
    if (!$@)
 
3962
    {
 
3963
      if (safe_query(\@$queries))
 
3964
      {
 
3965
          $dbh->rollback;
 
3966
          $dbh->{AutoCommit} = 1;
 
3967
            if (safe_query_result($check,"","")) {
 
3968
              add_log($limit,$safe_query_result_log);       
 
3969
              save_config_data($limit,"yes",$limit);
 
3970
            }
 
3971
            safe_query($clear);
 
3972
      } else {
 
3973
        add_log($limit,$safe_query_log);
 
3974
        save_config_data($limit,"error",$limit);
 
3975
      }
 
3976
      $dbh->{AutoCommit} = 1;
 
3977
    }
 
3978
    else
 
3979
    {
 
3980
      add_log($limit,"Couldnt undef autocommit ?? ");
 
3981
      save_config_data($limit,"no",$limit);
 
3982
    }
 
3983
    safe_query($clear);
 
3984
  }
 
3985
  return $limits{$limit} ne "yes";
 
3986
}
 
3987
 
 
3988
sub report_rollback
 
3989
{
 
3990
  my ($limit,$queries,$check,$clear)=@_;
 
3991
  if (!defined($limits{$limit}))
 
3992
  {
 
3993
    save_incomplete($limit,$prompt);
 
3994
    eval {undef($dbh->{AutoCommit})};
 
3995
    if (!$@)
 
3996
    {
 
3997
      if (safe_query(\@$queries))
 
3998
      {
 
3999
          add_log($limit,$safe_query_log);
 
4000
 
 
4001
          $dbh->rollback;
 
4002
           $dbh->{AutoCommit} = 1;
 
4003
           if (safe_query($check)) {
 
4004
              add_log($limit,$safe_query_log);
 
4005
              save_config_data($limit,"no",$limit);
 
4006
            }  else  {
 
4007
              add_log($limit,$safe_query_log);
 
4008
              save_config_data($limit,"yes",$limit);
 
4009
            };
 
4010
            safe_query($clear);
 
4011
      } else {
 
4012
        add_log($limit,$safe_query_log);
 
4013
        save_config_data($limit,"error",$limit);
 
4014
      }
 
4015
    }
 
4016
    else
 
4017
    {
 
4018
      add_log($limit,'Couldnt undef Autocommit??');
 
4019
      save_config_data($limit,"error",$limit);
 
4020
    }
 
4021
    safe_query($clear);
 
4022
  }
 
4023
  $dbh->{AutoCommit} = 1;
 
4024
  return $limits{$limit} ne "yes";
 
4025
}
 
4026
 
 
4027
 
 
4028
sub check_and_report
 
4029
{
 
4030
  my ($prompt,$limit,$pre,$query,$post,$answer,$string_type,$skip_prompt,
 
4031
      $function)=@_;
 
4032
  my ($tmp);
 
4033
  $function=0 if (!defined($function));
 
4034
 
 
4035
  print "$prompt: " if (!defined($skip_prompt));
 
4036
  if (!defined($limits{$limit}))
 
4037
  {
 
4038
    save_incomplete($limit,$prompt);
 
4039
    $tmp=1-safe_query(\@$pre);
 
4040
    add_log($limit,$safe_query_log);
 
4041
    if (!$tmp) 
 
4042
    {
 
4043
        $tmp=safe_query_result($query,$answer,$string_type) ;
 
4044
        add_log($limit,$safe_query_result_log);
 
4045
    };  
 
4046
    safe_query(\@$post);
 
4047
    add_log($limit,$safe_query_log);
 
4048
    delete $limits{$limit};
 
4049
    if ($function == 3)         # Report error as 'no'.
 
4050
    {
 
4051
      $function=0;
 
4052
      $tmp= -$tmp;
 
4053
    }
 
4054
    if ($function == 0 ||
 
4055
        $tmp != 0 && $function == 1 ||
 
4056
        $tmp == 0 && $function== 2)
 
4057
    {
 
4058
      save_config_data($limit, $tmp == 0 ? "yes" : $tmp == 1 ? "no" : "error",
 
4059
                       $prompt);
 
4060
      print "$limits{$limit}\n";
 
4061
      return $function == 0 ? $limits{$limit} eq "yes" : 0;
 
4062
    }
 
4063
    return 1;                   # more things to check
 
4064
  }
 
4065
  print "$limits{$limit}\n";
 
4066
  return 0 if ($function);
 
4067
  return $limits{$limit} eq "yes";
 
4068
}
 
4069
 
 
4070
 
 
4071
sub try_and_report
 
4072
{
 
4073
  my ($prompt,$limit,@tests)=@_;
 
4074
  my ($tmp,$test,$type);
 
4075
 
 
4076
  print "$prompt: ";
 
4077
 
 
4078
  if (!defined($limits{$limit}))
 
4079
  {
 
4080
    save_incomplete($limit,$prompt);
 
4081
    $type="no";                 # Not supported
 
4082
    foreach $test (@tests)
 
4083
    {
 
4084
      my $tmp_type= shift(@$test);
 
4085
      if (safe_query_l($limit,\@$test))
 
4086
      {
 
4087
        $type=$tmp_type;
 
4088
        goto outer;
 
4089
      }
 
4090
    }
 
4091
  outer:
 
4092
    save_config_data($limit, $type, $prompt);
 
4093
  }
 
4094
  print "$limits{$limit}\n";
 
4095
  return $limits{$limit} ne "no";
 
4096
}
 
4097
 
 
4098
#
 
4099
# Just execute the query and check values;  Returns 1 if ok
 
4100
#
 
4101
 
 
4102
sub execute_and_check
 
4103
{
 
4104
  my ($key,$pre,$query,$post,$answer,$string_type)=@_;
 
4105
  my ($tmp);
 
4106
 
 
4107
  $tmp=safe_query_l($key,\@$pre);
 
4108
 
 
4109
  $tmp=safe_query_result_l($key,$query,$answer,$string_type) == 0 if ($tmp);
 
4110
  safe_query_l($key,\@$post);
 
4111
  return $tmp;
 
4112
}
 
4113
 
 
4114
 
 
4115
# returns 0 if ok, 1 if error, -1 if wrong answer
 
4116
# Sets $last_result to value of query
 
4117
sub safe_query_result_l{
 
4118
  my ($key,$query,$answer,$result_type)=@_;
 
4119
  my $r = safe_query_result($query,$answer,$result_type);
 
4120
  add_log($key,$safe_query_result_log);
 
4121
  return $r;
 
4122
}  
 
4123
 
 
4124
sub safe_query_result
 
4125
{
 
4126
# result type can be 
 
4127
#  8 (must be empty), 2 (Any value), 0 (number)
 
4128
#  1 (char, endspaces can differ), 3 (exact char), 4 (NULL)
 
4129
#  5 (char with prefix), 6 (exact, errors are ignored)
 
4130
#  7 (array of numbers)
 
4131
  my ($query,$answer,$result_type)=@_;
 
4132
  my ($sth,$row,$result,$retry);
 
4133
  undef($last_result);
 
4134
  $safe_query_result_log="";
 
4135
  
 
4136
  printf "\nquery3: %-80.80s\n",$query  if ($opt_log_all_queries);
 
4137
  print LOG "$query;\n" if ($opt_log);
 
4138
  $safe_query_result_log="<".$query."\n";
 
4139
 
 
4140
  for ($retry=0; $retry < $retry_limit ; $retry++)
 
4141
  {
 
4142
    if (!($sth=$dbh->prepare($query)))
 
4143
    {
 
4144
      print_query($query);
 
4145
      $safe_query_result_log .= "> prepare failed:".$dbh->errstr."\n";
 
4146
      
 
4147
      if ($server->abort_if_fatal_error())
 
4148
      {
 
4149
        check_connect();        # Check that server is still up
 
4150
        next;                   # Retry again
 
4151
      }
 
4152
      check_connect();          # Check that server is still up
 
4153
      return 1;
 
4154
    }
 
4155
    if (!$sth->execute)
 
4156
    {
 
4157
      print_query($query);
 
4158
      $safe_query_result_log .= "> execute failed:".$dbh->errstr."\n";
 
4159
      if ($server->abort_if_fatal_error())
 
4160
      {
 
4161
        check_connect();        # Check that server is still up
 
4162
        next;                   # Retry again
 
4163
      }
 
4164
      check_connect();          # Check that server is still up
 
4165
      return 1;
 
4166
    }
 
4167
    else
 
4168
    {
 
4169
      last;
 
4170
    }
 
4171
  }
 
4172
  if (!($row=$sth->fetchrow_arrayref))
 
4173
  {
 
4174
    print "\nquery: $query didn't return any result\n" if ($opt_debug);
 
4175
    $safe_query_result_log .= "> didn't return any result:".$dbh->errstr."\n";    
 
4176
    $sth->finish;
 
4177
    return ($result_type == 8) ? 0 : 1;
 
4178
  }
 
4179
  if ($result_type == 8)
 
4180
  {
 
4181
    $sth->finish;
 
4182
    return 1;
 
4183
  }
 
4184
  $result=0;                    # Ok
 
4185
  $last_result= $row->[0];      # Save for report_result;
 
4186
  $safe_query_result_log .= ">".$last_result."\n";    
 
4187
  # Note:
 
4188
  # if ($result_type == 2)        We accept any return value as answer
 
4189
 
 
4190
  if ($result_type == 0)        # Compare numbers
 
4191
  {
 
4192
    $row->[0] =~ s/,/./;        # Fix if ',' is used instead of '.'
 
4193
    if ($row->[0] != $answer && (abs($row->[0]- $answer)/
 
4194
                                 (abs($row->[0]) + abs($answer))) > 0.01)
 
4195
    {
 
4196
      $result=-1;
 
4197
      $safe_query_result_log .= 
 
4198
          "We expected '$answer' but got '$last_result' \n";    
 
4199
    }
 
4200
  }
 
4201
  elsif ($result_type == 1)     # Compare where end space may differ
 
4202
  {
 
4203
    $row->[0] =~ s/\s+$//;
 
4204
    if ($row->[0] ne $answer)
 
4205
    {
 
4206
     $result=-1;
 
4207
     $safe_query_result_log .= 
 
4208
         "We expected '$answer' but got '$last_result' \n";    
 
4209
    } ;
 
4210
  }
 
4211
  elsif ($result_type == 3)     # This should be a exact match
 
4212
  {
 
4213
     if ($row->[0] ne $answer)
 
4214
     { 
 
4215
      $result= -1; 
 
4216
      $safe_query_result_log .= 
 
4217
          "We expected '$answer' but got '$last_result' \n";    
 
4218
    };
 
4219
  }
 
4220
  elsif ($result_type == 4)     # If results should be NULL
 
4221
  {
 
4222
    if (defined($row->[0]))
 
4223
    { 
 
4224
     $result= -1; 
 
4225
     $safe_query_result_log .= 
 
4226
         "We expected NULL but got '$last_result' \n";    
 
4227
    };
 
4228
  }
 
4229
  elsif ($result_type == 5)     # Result should have given prefix
 
4230
  {
 
4231
     if (length($row->[0]) < length($answer) &&
 
4232
                    substr($row->[0],1,length($answer)) ne $answer)
 
4233
     { 
 
4234
      $result= -1 ;
 
4235
      $safe_query_result_log .= 
 
4236
        "Result must have prefix '$answer', but  '$last_result' \n";    
 
4237
     };
 
4238
  }
 
4239
  elsif ($result_type == 6)     # Exact match but ignore errors
 
4240
  {
 
4241
    if ($row->[0] ne $answer)    
 
4242
    { $result= 1;
 
4243
      $safe_query_result_log .= 
 
4244
          "We expected '$answer' but got '$last_result' \n";    
 
4245
    } ;
 
4246
  }
 
4247
  elsif ($result_type == 7)     # Compare against array of numbers
 
4248
  {
 
4249
    if ($row->[0] != $answer->[0])
 
4250
    {
 
4251
      $safe_query_result_log .= "must be '$answer->[0]' \n";    
 
4252
      $result= -1;
 
4253
    }
 
4254
    else
 
4255
    {
 
4256
      my ($value);
 
4257
      shift @$answer;
 
4258
      while (($row=$sth->fetchrow_arrayref))
 
4259
      {
 
4260
       $safe_query_result_log .= ">$row\n";    
 
4261
 
 
4262
        $value=shift(@$answer);
 
4263
        if (!defined($value))
 
4264
        {
 
4265
          print "\nquery: $query returned to many results\n"
 
4266
            if ($opt_debug);
 
4267
          $safe_query_result_log .= "It returned to many results \n";               
 
4268
          $result= 1;
 
4269
          last;
 
4270
        }
 
4271
        if ($row->[0] != $value)
 
4272
        {
 
4273
          $safe_query_result_log .= "Must return $value here \n";           
 
4274
          $result= -1;
 
4275
          last;
 
4276
        }
 
4277
      }
 
4278
      if ($#$answer != -1)
 
4279
      {
 
4280
        print "\nquery: $query returned too few results\n"
 
4281
          if ($opt_debug);
 
4282
        $safe_query_result_log .= "It returned too few results \n";         
 
4283
        $result= 1;
 
4284
      }
 
4285
    }
 
4286
  }
 
4287
  $sth->finish;
 
4288
  print "\nquery: '$query' returned '$row->[0]' instead of '$answer'\n"
 
4289
    if ($opt_debug && $result && $result_type != 7);
 
4290
  return $result;
 
4291
}
 
4292
 
 
4293
#
 
4294
# Check that the query works!
 
4295
#
 
4296
 
 
4297
sub assert_crash
 
4298
{
 
4299
  my($query)=@_;
 
4300
 
 
4301
  if (!safe_query($query))
 
4302
  {
 
4303
    $query=join("; ",@$query) if (ref($query) eq "ARRAY");
 
4304
    print "\nFatal error:\nquery: '$query'\nerror: $DBI::errstr\n";
 
4305
    exit 1;
 
4306
  }
 
4307
}
 
4308
 
 
4309
 
 
4310
sub read_config_data
 
4311
{
 
4312
  my ($key,$limit,$prompt);
 
4313
  if (-e $opt_config_file)
 
4314
  {
 
4315
    open(CONFIG_FILE,"+<$opt_config_file") ||
 
4316
      die "Can't open configure file $opt_config_file\n";
 
4317
    print "Reading old values from cache: $opt_config_file\n";
 
4318
  }
 
4319
  else
 
4320
  {
 
4321
    open(CONFIG_FILE,"+>>$opt_config_file") ||
 
4322
      die "Can't create configure file $opt_config_file: $!\n";
 
4323
  }
 
4324
  select CONFIG_FILE;
 
4325
  $|=1;
 
4326
  select STDOUT;
 
4327
  while (<CONFIG_FILE>)
 
4328
  {
 
4329
    chomp;
 
4330
    if (/^(\S+)=([^\#]*[^\#\s])\s*(\# .*)*$/)
 
4331
    {
 
4332
      $key=$1; $limit=$2 ; $prompt=$3;
 
4333
      if (!$opt_quick || $limit =~ /\d/ || $key =~ /crash_me/)
 
4334
      {
 
4335
        if ($key !~ /restart/i)
 
4336
        {
 
4337
          $limits{$key}=$limit eq "null"? undef : $limit;
 
4338
          $prompts{$key}=length($prompt) ? substr($prompt,2) : "";
 
4339
          $last_read=$key;
 
4340
          delete $limits{'restart'};
 
4341
        }
 
4342
        else
 
4343
        {
 
4344
          $limit_changed=1;
 
4345
          if ($limit > $limits{'restart'}{'tohigh'})
 
4346
          {
 
4347
            $limits{'restart'}{'low'} = $limits{'restart'}{'tohigh'};
 
4348
          }
 
4349
          $limits{'restart'}{'tohigh'} = $limit;
 
4350
        }
 
4351
      }
 
4352
    }
 
4353
    elsif (/\s*###(.*)$/)    # log line
 
4354
    {
 
4355
       # add log line for previously read key
 
4356
       $log{$last_read} .= "$1\n";
 
4357
    }
 
4358
    elsif (!/^\s*$/ && !/^\#/)
 
4359
    {
 
4360
      die "Wrong config row: $_\n";
 
4361
    }
 
4362
  }
 
4363
}
 
4364
 
 
4365
 
 
4366
sub save_config_data
 
4367
{
 
4368
  my ($key,$limit,$prompt)=@_;
 
4369
  $prompts{$key}=$prompt;
 
4370
  return if (defined($limits{$key}) && $limits{$key} eq $limit);
 
4371
  if (!defined($limit) || $limit eq "")
 
4372
  {
 
4373
#    die "Undefined limit for $key\n";
 
4374
     $limit = 'null'; 
 
4375
  }
 
4376
  print CONFIG_FILE "$key=$limit\t# $prompt\n";
 
4377
  $limits{$key}=$limit;
 
4378
  $limit_changed=1;
 
4379
# now write log lines (immediatelly after limits)
 
4380
  my $line;
 
4381
  my $last_line_was_empty=0;
 
4382
  foreach $line (split /\n/, $log{$key})
 
4383
  {
 
4384
    print CONFIG_FILE "   ###$line\n" 
 
4385
        unless ( ($last_line_was_empty eq 1)  
 
4386
                 && ($line =~ /^\s+$/)  );
 
4387
    $last_line_was_empty= ($line =~ /^\s+$/)?1:0;
 
4388
  };     
 
4389
 
 
4390
  if (($opt_restart && $limits{'operating_system'} =~ /windows/i) ||
 
4391
                       ($limits{'operating_system'} =~ /NT/))
 
4392
  {
 
4393
    # If perl crashes in windows, everything is lost (Wonder why? :)
 
4394
    close CONFIG_FILE;
 
4395
    open(CONFIG_FILE,"+>>$opt_config_file") ||
 
4396
      die "Can't reopen configure file $opt_config_file: $!\n";
 
4397
  }
 
4398
}
 
4399
 
 
4400
sub add_log
 
4401
{
 
4402
  my $key = shift;
 
4403
  my $line = shift;
 
4404
  $log{$key} .= $line . "\n" if ($opt_verbose);;  
 
4405
}
 
4406
 
 
4407
sub save_all_config_data
 
4408
{
 
4409
  my ($key,$tmp);
 
4410
  close CONFIG_FILE;
 
4411
  return if (!$limit_changed);
 
4412
  open(CONFIG_FILE,">$opt_config_file") ||
 
4413
    die "Can't create configure file $opt_config_file: $!\n";
 
4414
  select CONFIG_FILE;
 
4415
  $|=1;
 
4416
  select STDOUT;
 
4417
  delete $limits{'restart'};
 
4418
 
 
4419
  print CONFIG_FILE 
 
4420
       "#This file is automaticly generated by crash-me $version\n\n";
 
4421
  foreach $key (sort keys %limits)
 
4422
  {
 
4423
    $tmp="$key=$limits{$key}";
 
4424
    print CONFIG_FILE $tmp . ("\t" x (int((32-min(length($tmp),32)+7)/8)+1)) .
 
4425
      "# $prompts{$key}\n";
 
4426
     my $line;
 
4427
     my $log;
 
4428
     my $last_line_was_empty=0;
 
4429
     foreach $line (split /\n/, $log{$key})
 
4430
     {
 
4431
        print CONFIG_FILE "   ###$line\n" unless 
 
4432
              ( ($last_line_was_empty eq 1) && ($line =~ /^\s*$/));
 
4433
        $last_line_was_empty= ($line =~ /^\s*$/)?1:0;
 
4434
     };     
 
4435
  }
 
4436
  close CONFIG_FILE;
 
4437
}
 
4438
 
 
4439
#
 
4440
# Save 'incomplete' in the limits file to be able to continue if
 
4441
# crash-me dies because of a bug in perl/DBI
 
4442
 
 
4443
sub save_incomplete
 
4444
{
 
4445
  my ($limit,$prompt)= @_;
 
4446
  save_config_data($limit,"incompleted",$prompt) if ($opt_restart);
 
4447
}
 
4448
 
 
4449
 
 
4450
sub check_repeat
 
4451
{
 
4452
  my ($sth,$limit)=@_;
 
4453
  my ($row);
 
4454
 
 
4455
  return 0 if (!($row=$sth->fetchrow_arrayref));
 
4456
  return (defined($row->[0]) && ('a' x $limit) eq $row->[0]) ? 1 : 0;
 
4457
}
 
4458
 
 
4459
 
 
4460
sub min
 
4461
{
 
4462
  my($min)=$_[0];
 
4463
  my($i);
 
4464
  for ($i=1 ; $i <= $#_; $i++)
 
4465
  {
 
4466
    $min=$_[$i] if ($min > $_[$i]);
 
4467
  }
 
4468
  return $min;
 
4469
}
 
4470
 
 
4471
sub sql_concat
 
4472
{
 
4473
  my ($a,$b)= @_;
 
4474
  return "$a || $b" if ($limits{'func_sql_concat_as_||'} eq 'yes');
 
4475
  return "concat($a,$b)" if ($limits{'func_odbc_concat'} eq 'yes');
 
4476
  return "$a + $b" if ($limits{'func_extra_concat_as_+'} eq 'yes');
 
4477
  return undef;
 
4478
}
 
4479
 
 
4480
#
 
4481
# Returns a list of statements to create a table in a portable manner
 
4482
# but still utilizing features in the databases.
 
4483
#
 
4484
 
 
4485
sub create_table
 
4486
{
 
4487
  my($table_name,$fields,$index,$extra) = @_;
 
4488
  my($query,$nr,$parts,@queries,@index);
 
4489
 
 
4490
  $extra="" if (!defined($extra));
 
4491
 
 
4492
  $query="create table $table_name (";
 
4493
  $nr=0;
 
4494
  foreach $field (@$fields)
 
4495
  {
 
4496
    $query.= $field . ',';
 
4497
  }
 
4498
  foreach $index (@$index)
 
4499
  {
 
4500
    $index =~ /\(([^\(]*)\)$/i;
 
4501
    $parts=$1;
 
4502
    if ($index =~ /^primary key/)
 
4503
    {
 
4504
      if ($limits{'primary_key_in_create'} eq 'yes')
 
4505
      {
 
4506
        $query.= $index . ',';
 
4507
      }
 
4508
      else
 
4509
      {
 
4510
        push(@queries,
 
4511
             "create unique index ${table_name}_prim on $table_name ($parts)");
 
4512
      }
 
4513
    }
 
4514
    elsif ($index =~ /^unique/)
 
4515
    {
 
4516
      if ($limits{'unique_in_create'} eq 'yes')
 
4517
      {
 
4518
        $query.= "unique ($parts),";
 
4519
      }
 
4520
      else
 
4521
      {
 
4522
        $nr++;
 
4523
        push(@queries,
 
4524
             "create unique index ${table_name}_$nr on $table_name ($parts)");
 
4525
 
 
4526
      }
 
4527
    }
 
4528
    else
 
4529
    {
 
4530
      if ($limits{'index_in_create'} eq 'yes')
 
4531
      {
 
4532
        $query.= "index ($parts),";
 
4533
      }
 
4534
      else
 
4535
      {
 
4536
        $nr++;
 
4537
        push(@queries,
 
4538
             "create index ${table_name}_$nr on $table_name ($1)");
 
4539
      }
 
4540
    }
 
4541
  }
 
4542
  chop($query);
 
4543
  $query.= ") $extra";
 
4544
  unshift(@queries,$query);
 
4545
  return @queries;
 
4546
}
 
4547
 
 
4548
 
 
4549
#
 
4550
# This is used by some query packages to change:
 
4551
# %d -> limit
 
4552
# %s -> 'a' x limit
 
4553
# %v -> "1,1,1,1,1" where there are 'limit' number of ones
 
4554
# %f -> q1,q2,q3....
 
4555
# %F -> q1 integer,q2 integer,q3 integer....
 
4556
 
 
4557
sub fix_query
 
4558
{
 
4559
  my ($query,$limit)=@_;
 
4560
  my ($repeat,$i);
 
4561
 
 
4562
  return $query if !(defined($query));
 
4563
  $query =~ s/%d/$limit/g;
 
4564
  if ($query =~ /%s/)
 
4565
  {
 
4566
    $repeat= 'a' x $limit;
 
4567
    $query =~ s/%s/$repeat/g;
 
4568
  }
 
4569
  if ($query =~ /%v/)
 
4570
  {
 
4571
    $repeat= '1,' x $limit;
 
4572
    chop($repeat);
 
4573
    $query =~ s/%v/$repeat/g;
 
4574
  }
 
4575
  if ($query =~ /%f/)
 
4576
  {
 
4577
    $repeat="";
 
4578
    for ($i=1 ; $i <= $limit ; $i++)
 
4579
    {
 
4580
      $repeat.="q$i,";
 
4581
    }
 
4582
    chop($repeat);
 
4583
    $query =~ s/%f/$repeat/g;
 
4584
  }
 
4585
  if ($query =~ /%F/)
 
4586
  {
 
4587
    $repeat="";
 
4588
    for ($i=1 ; $i <= $limit ; $i++)
 
4589
    {
 
4590
      $repeat.="q$i integer,";
 
4591
    }
 
4592
    chop($repeat);
 
4593
    $query =~ s/%F/$repeat/g;
 
4594
  }
 
4595
  return $query;
 
4596
}
 
4597
 
 
4598
 
 
4599
#
 
4600
# Different query packages
 
4601
#
 
4602
 
 
4603
package query_repeat;
 
4604
 
 
4605
sub new
 
4606
{
 
4607
  my ($type,$init,$query,$add1,$add_mid,$add,$add_end,$end_query,$cleanup,
 
4608
      $max_limit, $check, $offset)=@_;
 
4609
  my $self={};
 
4610
  if (defined($init) && $#$init != -1)
 
4611
  {
 
4612
    $self->{'init'}=$init;
 
4613
  }
 
4614
  $self->{'query'}=$query;
 
4615
  $self->{'add1'}=$add1;
 
4616
  $self->{'add_mid'}=$add_mid;
 
4617
  $self->{'add'}=$add;
 
4618
  $self->{'add_end'}=$add_end;
 
4619
  $self->{'end_query'}=$end_query;
 
4620
  $self->{'cleanup'}=$cleanup;
 
4621
  $self->{'max_limit'}=(defined($max_limit) ? $max_limit : $main::query_size);
 
4622
  $self->{'check'}=$check;
 
4623
  $self->{'offset'}=$offset;
 
4624
  $self->{'printf'}= ($add =~ /%d/);
 
4625
  bless $self;
 
4626
}
 
4627
 
 
4628
sub query
 
4629
{
 
4630
  my ($self,$limit)=@_;
 
4631
  if (!$self->{'printf'})
 
4632
  {
 
4633
    return $self->{'query'} . ($self->{'add'} x $limit) .
 
4634
      ($self->{'add_end'} x $limit) . $self->{'end_query'};
 
4635
  }
 
4636
  my ($tmp,$tmp2,$tmp3,$i);
 
4637
  $tmp=$self->{'query'};
 
4638
  if ($self->{'add1'})
 
4639
  {
 
4640
    for ($i=0; $i < $limit ; $i++)
 
4641
    {
 
4642
      $tmp3 = $self->{'add1'};
 
4643
      $tmp3 =~ s/%d/$i/g;
 
4644
      $tmp  .= $tmp3;
 
4645
    }
 
4646
  }
 
4647
  $tmp .= " ".$self->{'add_mid'};
 
4648
  if ($self->{'add'})
 
4649
  {
 
4650
    for ($i=0; $i < $limit ; $i++)
 
4651
    {
 
4652
      $tmp2 = $self->{'add'};
 
4653
      $tmp2 =~ s/%d/$i/g;
 
4654
      $tmp  .= $tmp2;
 
4655
    }
 
4656
  }
 
4657
  return ($tmp .
 
4658
          ($self->{'add_end'} x $limit) . $self->{'end_query'});
 
4659
}
 
4660
 
 
4661
sub max_limit
 
4662
{
 
4663
  my ($self)=@_;
 
4664
  my $tmp;
 
4665
  $tmp=int(($main::limits{"query_size"}-length($self->{'query'})
 
4666
            -length($self->{'add_mid'})-length($self->{'end_query'}))/
 
4667
           (length($self->{'add1'})+
 
4668
           length($self->{'add'})+length($self->{'add_end'})));
 
4669
  return main::min($self->{'max_limit'},$tmp);
 
4670
}
 
4671
 
 
4672
 
 
4673
sub cleanup
 
4674
{
 
4675
  my ($self)=@_;
 
4676
  my($tmp,$statement);
 
4677
  $tmp=$self->{'cleanup'};
 
4678
  foreach $statement (@$tmp)
 
4679
  {
 
4680
    main::safe_query($statement) if (defined($statement) && length($statement));
 
4681
  }
 
4682
}
 
4683
 
 
4684
sub check
 
4685
{
 
4686
  my ($self,$sth)=@_;
 
4687
  my $check=$self->{'check'};
 
4688
  return &$check($sth,$self->{'limit'}) if (defined($check));
 
4689
  return 1;
 
4690
}
 
4691
 
 
4692
sub check_query
 
4693
{
 
4694
  return undef;
 
4695
}
 
4696
 
 
4697
 
 
4698
package query_num;
 
4699
 
 
4700
sub new
 
4701
{
 
4702
  my ($type,$query,$end_query,$cleanup,$max_limit,$check)=@_;
 
4703
  my $self={};
 
4704
  $self->{'query'}=$query;
 
4705
  $self->{'end_query'}=$end_query;
 
4706
  $self->{'cleanup'}=$cleanup;
 
4707
  $self->{'max_limit'}=$max_limit;
 
4708
  $self->{'check'}=$check;
 
4709
  bless $self;
 
4710
}
 
4711
 
 
4712
sub query
 
4713
{
 
4714
  my ($self,$i)=@_;
 
4715
  $self->{'limit'}=$i;
 
4716
  return "$self->{'query'}$i$self->{'end_query'}";
 
4717
}
 
4718
 
 
4719
sub max_limit
 
4720
{
 
4721
  my ($self)=@_;
 
4722
  return $self->{'max_limit'};
 
4723
}
 
4724
 
 
4725
sub cleanup
 
4726
{
 
4727
  my ($self)=@_;
 
4728
  my($statement);
 
4729
  foreach $statement ($self->{'$cleanup'})
 
4730
  {
 
4731
    main::safe_query($statement) if (defined($statement) && length($statement));
 
4732
  }
 
4733
}
 
4734
 
 
4735
 
 
4736
sub check
 
4737
{
 
4738
  my ($self,$sth)=@_;
 
4739
  my $check=$self->{'check'};
 
4740
  return &$check($sth,$self->{'limit'}) if (defined($check));
 
4741
  return 1;
 
4742
}
 
4743
 
 
4744
sub check_query
 
4745
{
 
4746
  return undef;
 
4747
}
 
4748
 
 
4749
#
 
4750
# This package is used when testing CREATE TABLE!
 
4751
#
 
4752
 
 
4753
package query_table;
 
4754
 
 
4755
sub new
 
4756
{
 
4757
  my ($type,$query, $add, $end_query, $extra_init, $safe_query, $check,
 
4758
      $cleanup, $max_limit, $offset)=@_;
 
4759
  my $self={};
 
4760
  $self->{'query'}=$query;
 
4761
  $self->{'add'}=$add;
 
4762
  $self->{'end_query'}=$end_query;
 
4763
  $self->{'extra_init'}=$extra_init;
 
4764
  $self->{'safe_query'}=$safe_query;
 
4765
  $self->{'check'}=$check;
 
4766
  $self->{'cleanup'}=$cleanup;
 
4767
  $self->{'max_limit'}=$max_limit;
 
4768
  $self->{'offset'}=$offset;
 
4769
  bless $self;
 
4770
}
 
4771
 
 
4772
 
 
4773
sub query
 
4774
{
 
4775
  my ($self,$limit)=@_;
 
4776
  $self->{'limit'}=$limit;
 
4777
  $self->cleanup();     # Drop table before create
 
4778
 
 
4779
  my ($tmp,$tmp2,$i,$query,@res);
 
4780
  $tmp =$self->{'query'};
 
4781
  $tmp =~ s/%d/$limit/g;
 
4782
  for ($i=1; $i <= $limit ; $i++)
 
4783
  {
 
4784
    $tmp2 = $self->{'add'};
 
4785
    $tmp2 =~ s/%d/$i/g;
 
4786
    $tmp  .= $tmp2;
 
4787
  }
 
4788
  push(@res,$tmp . $self->{'end_query'});
 
4789
  $tmp=$self->{'extra_init'};
 
4790
  foreach $query (@$tmp)
 
4791
  {
 
4792
    push(@res,main::fix_query($query,$limit));
 
4793
  }
 
4794
  return \@res;
 
4795
}
 
4796
 
 
4797
 
 
4798
sub max_limit
 
4799
{
 
4800
  my ($self)=@_;
 
4801
  return $self->{'max_limit'};
 
4802
}
 
4803
 
 
4804
 
 
4805
sub check_query
 
4806
{
 
4807
  my ($self)=@_;
 
4808
  return main::fix_query($self->{'safe_query'},$self->{'limit'});
 
4809
}
 
4810
 
 
4811
sub check
 
4812
{
 
4813
  my ($self,$sth)=@_;
 
4814
  my $check=$self->{'check'};
 
4815
  return 0 if (!($row=$sth->fetchrow_arrayref));
 
4816
  if (defined($check))
 
4817
  {
 
4818
    return (defined($row->[0]) &&
 
4819
            $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0;
 
4820
  }
 
4821
  return 1;
 
4822
}
 
4823
 
 
4824
 
 
4825
# Remove table before and after create table query
 
4826
 
 
4827
sub cleanup()
 
4828
{
 
4829
  my ($self)=@_;
 
4830
  main::safe_query(main::fix_query($self->{'cleanup'},$self->{'limit'}));
 
4831
}
 
4832
 
 
4833
#
 
4834
# Package to do many queries with %d, and %s substitution
 
4835
#
 
4836
 
 
4837
package query_many;
 
4838
 
 
4839
sub new
 
4840
{
 
4841
  my ($type,$query,$safe_query,$check_result,$cleanup,$max_limit,$offset,
 
4842
      $safe_cleanup)=@_;
 
4843
  my $self={};
 
4844
  $self->{'query'}=$query;
 
4845
  $self->{'safe_query'}=$safe_query;
 
4846
  $self->{'check'}=$check_result;
 
4847
  $self->{'cleanup'}=$cleanup;
 
4848
  $self->{'max_limit'}=$max_limit;
 
4849
  $self->{'offset'}=$offset;
 
4850
  $self->{'safe_cleanup'}=$safe_cleanup;
 
4851
  bless $self;
 
4852
}
 
4853
 
 
4854
 
 
4855
sub query
 
4856
{
 
4857
  my ($self,$limit)=@_;
 
4858
  my ($queries,$query,@res);
 
4859
  $self->{'limit'}=$limit;
 
4860
  $self->cleanup() if (defined($self->{'safe_cleanup'}));
 
4861
  $queries=$self->{'query'};
 
4862
  foreach $query (@$queries)
 
4863
  {
 
4864
    push(@res,main::fix_query($query,$limit));
 
4865
  }
 
4866
  return \@res;
 
4867
}
 
4868
 
 
4869
sub check_query
 
4870
{
 
4871
  my ($self)=@_;
 
4872
  return main::fix_query($self->{'safe_query'},$self->{'limit'});
 
4873
}
 
4874
 
 
4875
sub cleanup
 
4876
{
 
4877
  my ($self)=@_;
 
4878
  my($tmp,$statement);
 
4879
  return if (!defined($self->{'cleanup'}));
 
4880
  $tmp=$self->{'cleanup'};
 
4881
  foreach $statement (@$tmp)
 
4882
  {
 
4883
    if (defined($statement) && length($statement))
 
4884
    {
 
4885
      main::safe_query(main::fix_query($statement,$self->{'limit'}));
 
4886
    }
 
4887
  }
 
4888
}
 
4889
 
 
4890
 
 
4891
sub check
 
4892
{
 
4893
  my ($self,$sth)=@_;
 
4894
  my ($check,$row);
 
4895
  return 0 if (!($row=$sth->fetchrow_arrayref));
 
4896
  $check=$self->{'check'};
 
4897
  if (defined($check))
 
4898
  {
 
4899
    return (defined($row->[0]) &&
 
4900
            $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0;
 
4901
  }
 
4902
  return 1;
 
4903
}
 
4904
 
 
4905
sub max_limit
 
4906
{
 
4907
  my ($self)=@_;
 
4908
  return $self->{'max_limit'};
 
4909
}
 
4910
 
 
4911
#
 
4912
# Used to find max supported row length
 
4913
#
 
4914
 
 
4915
package query_row_length;
 
4916
 
 
4917
sub new
 
4918
{
 
4919
  my ($type,$create,$null,$drop,$max_limit)=@_;
 
4920
  my $self={};
 
4921
  $self->{'table_name'}=$create;
 
4922
  $self->{'null'}=$null;
 
4923
  $self->{'cleanup'}=$drop;
 
4924
  $self->{'max_limit'}=$max_limit;
 
4925
  bless $self;
 
4926
}
 
4927
 
 
4928
 
 
4929
sub query
 
4930
{
 
4931
  my ($self,$limit)=@_;
 
4932
  my ($res,$values,$size,$length,$i);
 
4933
  $self->{'limit'}=$limit;
 
4934
 
 
4935
  $res="";
 
4936
  $size=main::min($main::limits{'max_char_size'},255);
 
4937
  $size = 255 if (!$size); # Safety
 
4938
  for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++)
 
4939
  {
 
4940
    $res.= "q$i char($size) $self->{'null'},";
 
4941
    $values.="'" . ('a' x $size) . "',";
 
4942
  }
 
4943
  if ($length < $limit)
 
4944
  {
 
4945
    $size=$limit-$length;
 
4946
    $res.= "q$i char($size) $self->{'null'},";
 
4947
    $values.="'" . ('a' x $size) . "',";
 
4948
  }
 
4949
  chop($res);
 
4950
  chop($values);
 
4951
  return ["create table " . $self->{'table_name'} . " ($res)",
 
4952
          "insert into " . $self->{'table_name'} . " values ($values)"];
 
4953
}
 
4954
 
 
4955
sub max_limit
 
4956
{
 
4957
  my ($self)=@_;
 
4958
  return $self->{'max_limit'};
 
4959
}
 
4960
 
 
4961
sub cleanup
 
4962
{
 
4963
  my ($self)=@_;
 
4964
  main::safe_query($self->{'cleanup'});
 
4965
}
 
4966
 
 
4967
 
 
4968
sub check
 
4969
{
 
4970
  return 1;
 
4971
}
 
4972
 
 
4973
sub check_query
 
4974
{
 
4975
  return undef;
 
4976
}
 
4977
 
 
4978
#
 
4979
# Used to find max supported index length
 
4980
#
 
4981
 
 
4982
package query_index_length;
 
4983
 
 
4984
sub new
 
4985
{
 
4986
  my ($type,$create,$drop,$max_limit)=@_;
 
4987
  my $self={};
 
4988
  $self->{'create'}=$create;
 
4989
  $self->{'cleanup'}=$drop;
 
4990
  $self->{'max_limit'}=$max_limit;
 
4991
  bless $self;
 
4992
}
 
4993
 
 
4994
 
 
4995
sub query
 
4996
{
 
4997
  my ($self,$limit)=@_;
 
4998
  my ($res,$size,$length,$i,$parts,$values);
 
4999
  $self->{'limit'}=$limit;
 
5000
 
 
5001
  $res=$parts=$values="";
 
5002
  $size=main::min($main::limits{'max_index_part_length'},
 
5003
       $main::limits{'max_char_size'});
 
5004
  $size=1 if ($size == 0);      # Avoid infinite loop errors
 
5005
  for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++)
 
5006
  {
 
5007
    $res.= "q$i char($size) not null,";
 
5008
    $parts.= "q$i,";
 
5009
    $values.= "'" . ('a' x $size) . "',";
 
5010
  }
 
5011
  if ($length < $limit)
 
5012
  {
 
5013
    $size=$limit-$length;
 
5014
    $res.= "q$i char($size) not null,";
 
5015
    $parts.="q$i,";
 
5016
    $values.= "'" . ('a' x $size) . "',";
 
5017
  }
 
5018
  chop($parts);
 
5019
  chop($res);
 
5020
  chop($values);
 
5021
  if ($main::limits{'unique_in_create'} eq 'yes')
 
5022
  {
 
5023
    return [$self->{'create'} . "($res,unique ($parts))",
 
5024
            "insert into crash_q values($values)"];
 
5025
  }
 
5026
  return [$self->{'create'} . "($res)",
 
5027
          "create index crash_q_index on crash_q ($parts)",
 
5028
          "insert into crash_q values($values)"];
 
5029
}
 
5030
 
 
5031
sub max_limit
 
5032
{
 
5033
  my ($self)=@_;
 
5034
  return $self->{'max_limit'};
 
5035
}
 
5036
 
 
5037
sub cleanup
 
5038
{
 
5039
  my ($self)=@_;
 
5040
  main::safe_query($self->{'cleanup'});
 
5041
}
 
5042
 
 
5043
 
 
5044
sub check
 
5045
{
 
5046
  return 1;
 
5047
}
 
5048
 
 
5049
sub check_query
 
5050
{
 
5051
  return undef;
 
5052
}
 
5053
 
 
5054
 
 
5055
 
 
5056
### TODO:
 
5057
# OID test instead of / in addition to _rowid