~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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