diff options
Diffstat (limited to 'sql-bench/crash-me.sh')
-rw-r--r-- | sql-bench/crash-me.sh | 5024 |
1 files changed, 0 insertions, 5024 deletions
diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh deleted file mode 100644 index a40ef8fbc7d..00000000000 --- a/sql-bench/crash-me.sh +++ /dev/null @@ -1,5024 +0,0 @@ -#!@PERL@ -# -*- perl -*- -# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Library General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this library; if not, write to the Free -# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -# MA 02111-1307, USA - -# Written by Monty for the TCX/Monty Program/Detron benchmark suite. -# Empress and PostgreSQL patches by Luuk de Boer -# Extensions for ANSI SQL and Mimer by Bengt Gunne -# Some additions and corrections by Matthias Urlich -# -# This programs tries to find all limits for a sql server -# It gets the name from what it does to most servers :) -# -# Be sure to use --help before running this! -# -# If you want to add support for another server, add a new package for the -# server in server-cfg. You only have to support the 'new' and 'version' -# functions. new doesn't need to have any limits if one doesn't want to -# use the benchmarks. -# - -# TODO: -# CMT includes types and functions which are synonyms for other types -# and functions, including those in SQL9x. It should label those synonyms -# as such, and clarify ones such as "mediumint" with comments such as -# "3-byte int" or "same as xxx". - -$version="1.61"; - -use Cwd; -use DBI; -use Getopt::Long; -use POSIX; -$pwd = cwd(); $pwd = "." if ($pwd eq ''); -require "$pwd/server-cfg" || die "Can't read Configuration file: $!\n"; - -$opt_server="mysql"; $opt_host="localhost"; $opt_database="test"; -$opt_dir="limits"; -$opt_user=$opt_password="";$opt_verbose=1; -$opt_debug=$opt_help=$opt_Information=$opt_restart=$opt_force=$opt_quick=0; -$opt_log_all_queries=$opt_fix_limit_file=$opt_batch_mode=$opt_version=0; -$opt_db_start_cmd=""; # the db server start command -$opt_check_server=0; # Check if server is alive before each query -$opt_sleep=10; # time to sleep while starting the db server -$limit_changed=0; # For configure file -$reconnect_count=0; -$opt_suffix=""; -$opt_comment=$opt_config_file=$opt_log_queries_to_file=""; -$limits{'crash_me_safe'}='yes'; -$prompts{'crash_me_safe'}='crash me safe'; -$limits{'operating_system'}= machine(); -$prompts{'operating_system'}='crash-me tested on'; -$retry_limit=3; - -GetOptions("Information","help","server=s","debug","user=s","password=s", -"database=s","restart","force","quick","log-all-queries","comment=s", -"host=s","fix-limit-file","dir=s","db-start-cmd=s","sleep=s","suffix=s", -"batch-mode","config-file=s","log-queries-to-file=s","check-server", -"version", -"verbose!" => \$opt_verbose) || usage(); -usage() if ($opt_help || $opt_Information); -version() && exit(0) if ($opt_version); - -$opt_suffix = '-'.$opt_suffix if (length($opt_suffix) != 0); -$opt_config_file = "$pwd/$opt_dir/$opt_server$opt_suffix.cfg" - if (length($opt_config_file) == 0); -$log_prefix=' ###'; # prefix for log lines in result file -$safe_query_log=''; -$safe_query_result_log=''; -$log{"crash-me"}=""; - -#!!! - -if ($opt_fix_limit_file) -{ - print "Fixing limit file for $opt_server\n"; - read_config_data(); - $limit_changed=1; - save_all_config_data(); - exit 0; -} - -$server=get_server($opt_server,$opt_host,$opt_database); -$opt_server=$server->{'cmp_name'}; - -$|=1; # For debugging - -print "Running $0 $version on '",($server_version=$server->version()),"'\n\n"; -print "I hope you didn't have anything important running on this server....\n"; -read_config_data(); -if ($limit_changed) # Must have been restarted -{ - save_config_data('crash_me_safe','no',"crash me safe"); -} - -if (!$opt_force && !$opt_batch_mode) -{ - server_info(); -} -else -{ - print "Using --force. I assume you know what you are doing...\n"; -} -print "\n"; - -save_config_data('crash_me_version',$version,"crash me version"); -if ($server_version) -{ - save_config_data('server_version',$server_version,"server version"); -} -if (length($opt_comment)) -{ - save_config_data('user_comment',$opt_comment,"comment"); -} - -$opt_log=0; -if (length($opt_log_queries_to_file)) -{ - open(LOG,">$opt_log_queries_to_file") || - die "Can't open file $opt_log_queries_to_file\n"; - $opt_log=1; -} - -# -# Set up some limits that's regared as unlimited -# We don't want to take up all resources from the server... -# - -$max_connections="+1000"; # Number of simultaneous connections -$max_buffer_size="+16000000"; # size of communication buffer. -$max_string_size="+8000000"; # Enough for this test -$max_name_length="+512"; # Actually 256, but ... -$max_keys="+64"; # Probably too big. -$max_join_tables="+64"; # Probably too big. -$max_columns="+8192"; # Probably too big. -$max_row_length=$max_string_size; -$max_key_length="+8192"; # Big enough -$max_order_by="+64"; # Big enough -$max_expressions="+10000"; -$max_big_expressions="+100"; -$max_stacked_expressions="+2000"; -$query_size=$max_buffer_size; -$longreadlen=16000000; # For retrieval buffer - - -# -# First do some checks that needed for the rest of the benchmark -# -use sigtrap; # Must be removed with perl5.005_2 on Win98 -$SIG{PIPE} = 'IGNORE'; -$problem_counter=0; -$SIG{SEGV} = sub { - $problem_counter +=1; - if ($problem_counter >= 100) { - die("Too many problems, try to restart"); - } else { - warn('SEGFAULT'); - }; -}; -$dbh=safe_connect(); - -# -# Test if the database require RESTRICT/CASCADE after DROP TABLE -# - -# Really remove the crash_me table -$prompt="drop table require cascade/restrict"; -$drop_attr=""; -$dbh->do("drop table crash_me"); -$dbh->do("drop table crash_me cascade"); -if (!safe_query_l('drop_requires_cascade', - ["create table crash_me (a integer not null)", - "drop table crash_me"])) -{ - $dbh->do("drop table crash_me cascade"); - if (safe_query_l('drop_requires_cascade', - ["create table crash_me (a integer not null)", - "drop table crash_me cascade"])) - { - save_config_data('drop_requires_cascade',"yes","$prompt"); - $drop_attr="cascade"; - } - else - { - die "Can't create and drop table 'crash_me'\n"; - } -} -else -{ - save_config_data('drop_requires_cascade',"no","$prompt"); - $drop_attr=""; -} - -# Remove tables from old runs -$dbh->do("drop table crash_me $drop_attr"); -$dbh->do("drop table crash_me2 $drop_attr"); -$dbh->do("drop table crash_me3 $drop_attr"); -$dbh->do("drop table crash_q $drop_attr"); -$dbh->do("drop table crash_q1 $drop_attr"); - -$prompt="Tables without primary key"; -if (!safe_query_l('no_primary_key', - ["create table crash_me (a integer not null,b char(10) not null)", - "insert into crash_me (a,b) values (1,'a')"])) -{ - if (!safe_query_l('no_primary_key', - ["create table crash_me (a integer not null,b char(10) not null". - ", primary key (a))", - "insert into crash_me (a,b) values (1,'a')"])) - { - die "Can't create table 'crash_me' with one record: $DBI::errstr\n"; - } - save_config_data('no_primary_key',"no",$prompt); -} -else -{ - save_config_data('no_primary_key',"yes",$prompt); -} - -# -# Define strings for character NULL and numeric NULL used in expressions -# -$char_null=$server->{'char_null'}; -$numeric_null=$server->{'numeric_null'}; -if ($char_null eq '') -{ - $char_null="NULL"; -} -if ($numeric_null eq '') -{ - $numeric_null="NULL"; -} - -print "$prompt: $limits{'no_primary_key'}\n"; - -report("SELECT without FROM",'select_without_from',"select 1"); -if ($limits{'select_without_from'} ne "yes") -{ - $end_query=" from crash_me"; - $check_connect="select a from crash_me"; -} -else -{ - $end_query=""; - $check_connect="select 1"; -} - -assert($check_connect); -assert("select a from crash_me where b<'b'"); - -report("Select constants",'select_constants',"select 1 $end_query"); -report("Select table_name.*",'table_wildcard', - "select crash_me.* from crash_me"); -report("Allows \' and \" as string markers",'quote_with_"', - 'select a from crash_me where b<"c"'); -check_and_report("Double '' as ' in strings",'double_quotes',[], - "select 'Walker''s' $end_query",[],"Walker's",1); -check_and_report("Multiple line strings","multi_strings",[], - "select a from crash_me where b < 'a'\n'b'",[],"1",0); -check_and_report("\" as identifier quote (ANSI SQL)",'quote_ident_with_"',[], - 'select "A" from crash_me',[],"1",0); -check_and_report("\` as identifier quote",'quote_ident_with_`',[], - 'select `A` from crash_me',[],"1",0); -check_and_report("[] as identifier quote",'quote_ident_with_[',[], - 'select [A] from crash_me',[],"1",0); -report('Double "" in identifiers as "','quote_ident_with_dbl_"', - 'create table crash_me1 ("abc""d" integer)', - 'drop table crash_me1'); - -report("Column alias","column_alias","select a as ab from crash_me"); -report("Table alias","table_alias","select b.a from crash_me as b"); -report("Functions",'functions',"select 1+1 $end_query"); -report("Group functions",'group_functions',"select count(*) from crash_me"); -report("Group functions with distinct",'group_distinct_functions', - "select count(distinct a) from crash_me"); -report("Group functions with several distinct",'group_many_distinct_functions', - "select count(distinct a), count(distinct b) from crash_me"); -report("Group by",'group_by',"select a from crash_me group by a"); -report("Group by position",'group_by_position', - "select a from crash_me group by 1"); -report("Group by alias",'group_by_alias', - "select a as ab from crash_me group by ab"); -report("Group on unused column",'group_on_unused', - "select count(*) from crash_me group by a"); - -report("Order by",'order_by',"select a from crash_me order by a"); -report("Order by position",'order_by_position', - "select a from crash_me order by 1"); -report("Order by function","order_by_function", - "select a from crash_me order by a+1"); -report("Order by on unused column",'order_on_unused', - "select b from crash_me order by a"); -# little bit deprecated -#check_and_report("Order by DESC is remembered",'order_by_remember_desc', -# ["create table crash_q (s int,s1 int)", -# "insert into crash_q values(1,1)", -# "insert into crash_q values(3,1)", -# "insert into crash_q values(2,1)"], -# "select s,s1 from crash_q order by s1 DESC,s", -# ["drop table crash_q $drop_attr"],[3,2,1],7,undef(),3); -report("Compute",'compute', - "select a from crash_me order by a compute sum(a) by a"); -report("INSERT with Value lists",'insert_multi_value', - "create table crash_q (s char(10))", - "insert into crash_q values ('a'),('b')", - "drop table crash_q $drop_attr"); -report("INSERT with set syntax",'insert_with_set', - "create table crash_q (a integer)", - "insert into crash_q SET a=1", - "drop table crash_q $drop_attr"); -report("INSERT with DEFAULT","insert_with_default", - "create table crash_me_q (a int)", - "insert into crash_me_q (a) values (DEFAULT)", - "drop table crash_me_q $drop_attr"); - -report("INSERT with empty value list","insert_with_empty_value_list", - "create table crash_me_q (a int)", - "insert into crash_me_q (a) values ()", - "drop table crash_me_q $drop_attr"); - -report("INSERT DEFAULT VALUES","insert_default_values", - "create table crash_me_q (a int)", - "insert into crash_me_q DEFAULT VALUES", - "drop table crash_me_q $drop_attr"); - -report("allows end ';'","end_colon", "select * from crash_me;"); -try_and_report("LIMIT number of rows","select_limit", - ["with LIMIT", - "select * from crash_me limit 1"], - ["with TOP", - "select TOP 1 * from crash_me"]); -report("SELECT with LIMIT #,#","select_limit2", - "select * from crash_me limit 1,1"); -report("SELECT with LIMIT # OFFSET #", - "select_limit3", "select * from crash_me limit 1 offset 1"); - -# The following alter table commands MUST be kept together! -if ($dbh->do("create table crash_q (a integer, b integer,c1 CHAR(10))")) -{ - report("Alter table add column",'alter_add_col', - "alter table crash_q add d integer"); - report_one("Alter table add many columns",'alter_add_multi_col', - [["alter table crash_q add (f integer,g integer)","yes"], - ["alter table crash_q add f integer, add g integer","with add"], - ["alter table crash_q add f integer,g integer","without add"]] ); - report("Alter table change column",'alter_change_col', - "alter table crash_q change a e char(50)"); - - # informix can only change data type with modify - report_one("Alter table modify column",'alter_modify_col', - [["alter table crash_q modify c1 CHAR(20)","yes"], - ["alter table crash_q alter c1 CHAR(20)","with alter"]]); - report("Alter table alter column default",'alter_alter_col', - "alter table crash_q alter b set default 10"); - report_one("Alter table drop column",'alter_drop_col', - [["alter table crash_q drop column b","yes"], - ["alter table crash_q drop column b restrict", - "with restrict/cascade"]]); - report("Alter table rename table",'alter_rename_table', - "alter table crash_q rename to crash_q1"); -} -# Make sure both tables will be dropped, even if rename fails. -$dbh->do("drop table crash_q1 $drop_attr"); -$dbh->do("drop table crash_q $drop_attr"); - -report("rename table","rename_table", - "create table crash_q (a integer, b integer,c1 CHAR(10))", - "rename table crash_q to crash_q1", - "drop table crash_q1 $drop_attr"); -# Make sure both tables will be dropped, even if rename fails. -$dbh->do("drop table crash_q1 $drop_attr"); -$dbh->do("drop table crash_q $drop_attr"); - -report("truncate","truncate_table", - "create table crash_q (a integer, b integer,c1 CHAR(10))", - "truncate table crash_q", - "drop table crash_q $drop_attr"); - -if ($dbh->do("create table crash_q (a integer, b integer,c1 CHAR(10))") && - $dbh->do("create table crash_q1 (a integer, b integer,c1 CHAR(10) not null)")) -{ - report("Alter table add constraint",'alter_add_constraint', - "alter table crash_q add constraint c2 check(a > b)"); - report_one("Alter table drop constraint",'alter_drop_constraint', - [["alter table crash_q drop constraint c2","yes"], - ["alter table crash_q drop constraint c2 restrict", - "with restrict/cascade"]]); - report("Alter table add unique",'alter_add_unique', - "alter table crash_q add constraint u1 unique(c1)"); - try_and_report("Alter table drop unique",'alter_drop_unique', - ["with constraint", - "alter table crash_q drop constraint u1"], - ["with constraint and restrict/cascade", - "alter table crash_q drop constraint u1 restrict"], - ["with drop key", - "alter table crash_q drop key u1"]); - try_and_report("Alter table add primary key",'alter_add_primary_key', - ["with constraint", - "alter table crash_q1 add constraint p1 primary key(c1)"], - ["with add primary key", - "alter table crash_q1 add primary key(c1)"]); - report("Alter table add foreign key",'alter_add_foreign_key', - "alter table crash_q add constraint f1 foreign key(c1) references crash_q1(c1)"); - try_and_report("Alter table drop foreign key",'alter_drop_foreign_key', - ["with drop constraint", - "alter table crash_q drop constraint f1"], - ["with drop constraint and restrict/cascade", - "alter table crash_q drop constraint f1 restrict"], - ["with drop foreign key", - "alter table crash_q drop foreign key f1"]); - try_and_report("Alter table drop primary key",'alter_drop_primary_key', - ["drop constraint", - "alter table crash_q1 drop constraint p1 restrict"], - ["drop primary key", - "alter table crash_q1 drop primary key"]); -} -$dbh->do("drop table crash_q $drop_attr"); -$dbh->do("drop table crash_q1 $drop_attr"); - -check_and_report("Case insensitive compare","case_insensitive_strings", - [],"select b from crash_me where b = 'A'",[],'a',1); -check_and_report("Ignore end space in compare","ignore_end_space", - [],"select b from crash_me where b = 'a '",[],'a',1); -check_and_report("Group on column with null values",'group_by_null', - ["create table crash_q (s char(10))", - "insert into crash_q values(null)", - "insert into crash_q values(null)"], - "select count(*),s from crash_q group by s", - ["drop table crash_q $drop_attr"],2,0); - -$prompt="Having"; -if (!defined($limits{'having'})) -{ # Complicated because of postgreSQL - if (!safe_query_result_l("having", - "select a from crash_me group by a having a > 0",1,0)) - { - if (!safe_query_result_l("having", - "select a from crash_me group by a having a < 0", - 1,0)) - { save_config_data("having","error",$prompt); } - else - { save_config_data("having","yes",$prompt); } - } - else - { save_config_data("having","no",$prompt); } -} -print "$prompt: $limits{'having'}\n"; - -if ($limits{'having'} eq 'yes') -{ - report("Having with group function","having_with_group", - "select a from crash_me group by a having count(*) = 1"); -} - -if ($limits{'column_alias'} eq 'yes') -{ - report("Order by alias",'order_by_alias', - "select a as ab from crash_me order by ab"); - if ($limits{'having'} eq 'yes') - { - report("Having on alias","having_with_alias", - "select a as ab from crash_me group by a having ab > 0"); - } -} -report("binary numbers (0b1001)","binary_numbers","select 0b1001 $end_query"); -report("hex numbers (0x41)","hex_numbers","select 0x41 $end_query"); -report("binary strings (b'0110')","binary_strings","select b'0110' $end_query"); -report("hex strings (x'1ace')","hex_strings","select x'1ace' $end_query"); - -report_result("Value of logical operation (1=1)","logical_value", - "select (1=1) $end_query"); - -report_result("Value of TRUE","value_of_true","select TRUE $end_query"); -report_result("Value of FALSE","value_of_false","select FALSE $end_query"); - -$logical_value= $limits{'logical_value'}; - -$false=0; -$result="no"; -if ($res=safe_query_l('has_true_false',"select (1=1)=true $end_query")) { - $false="false"; - $result="yes"; -} -save_config_data('has_true_false',$result,"TRUE and FALSE"); - -# -# Check how many connections the server can handle: -# We can't test unlimited connections, because this may take down the -# server... -# - -$prompt="Simultaneous connections (installation default)"; -print "$prompt: "; -if (defined($limits{'connections'})) -{ - print "$limits{'connections'}\n"; -} -else -{ - @connect=($dbh); - - for ($i=1; $i < $max_connections ; $i++) - { - if (!($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password, - { PrintError => 0}))) - { - print "Last connect error: $DBI::errstr\n" if ($opt_debug); - last; - } - $dbh->{LongReadLen}= $longreadlen; # Set retrieval buffer - print "." if ($opt_debug); - push(@connect,$dbh); - } - print "$i\n"; - save_config_data('connections',$i,$prompt); - foreach $dbh (@connect) - { - print "#" if ($opt_debug); - $dbh->disconnect || warn $dbh->errstr; # close connection - } - - $#connect=-1; # Free connections - - if ($i == 0) - { - print "Can't connect to server: $DBI::errstr.". - " Please start it and try again\n"; - exit 1; - } - $dbh=retry_connect(); -} - - -# -# Check size of communication buffer, strings... -# - -$prompt="query size"; -print "$prompt: "; -if (!defined($limits{'query_size'})) -{ - $query="select "; - $first=64; - $end=$max_buffer_size; - $select= $limits{'select_without_from'} eq 'yes' ? 1 : 'a'; - - assert($query . "$select$end_query"); - - $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'}); - - if ($limits{'restart'}{'tohigh'}) - { - $end = $limits{'restart'}{'tohigh'} - 1; - print "\nRestarting this with low limit: $first and high limit: $end\n"; - delete $limits{'restart'}; - $first=$first+int(($end-$first+4)/5); # Prefere lower on errors - } - for ($i=$first ; $i < $end ; $i*=2) - { - last if (!safe_query($query . - (" " x ($i - length($query)-length($end_query) -1)) - . "$select$end_query")); - $first=$i; - save_config_data("restart",$i,"") if ($opt_restart); - } - $end=$i; - - if ($i < $max_buffer_size) - { - while ($first != $end) - { - $i=int(($first+$end+1)/2); - if (safe_query($query . - (" " x ($i - length($query)-length($end_query) -1)) . - "$select$end_query")) - { - $first=$i; - } - else - { - $end=$i-1; - } - } - } - save_config_data('query_size',$end,$prompt); -} -$query_size=$limits{'query_size'}; - -print "$limits{'query_size'}\n"; - -# -# Check for reserved words -# - -check_reserved_words($dbh); - -# -# Test database types -# - -@sql_types=("character(1)","char(1)","char varying(1)", "character varying(1)", - "boolean", - "varchar(1)", - "integer","int","smallint", - "numeric(9,2)","decimal(6,2)","dec(6,2)", - "bit", "bit(2)","bit varying(2)","float","float(8)","real", - "double precision", "date","time","timestamp", - "interval year", "interval year to month", - "interval month", - "interval day", "interval day to hour", "interval day to minute", - "interval day to second", - "interval hour", "interval hour to minute", - "interval hour to second", - "interval minute", "interval minute to second", - "interval second", - "national character varying(20)", - "national character(20)","nchar(1)", - "national char varying(20)","nchar varying(20)", - "national character varying(20)", - "timestamp with time zone"); -@odbc_types=("binary(1)","varbinary(1)","tinyint","bigint", - "datetime"); -@extra_types=("blob","byte","long varbinary","image","text","text(10)", - "mediumtext", - "long varchar(1)", "varchar2(257)", - "mediumint","middleint","int unsigned", - "int1","int2","int3","int4","int8","uint", - "money","smallmoney","float4","float8","smallfloat", - "float(6,2)","double", - "enum('red')","set('red')", "int(5) zerofill", "serial", - "char(10) binary","int not null auto_increment,unique(q)", - "abstime","year","datetime","smalldatetime","timespan","reltime", - # Sybase types - "int not null identity,unique(q)", - # postgres types - "box","bool","circle","polygon","point","line","lseg","path", - "interval", "inet", "cidr", "macaddr", - - # oracle types - "varchar2(16)","nvarchar2(16)","number(9,2)","number(9)", - "number", "long","raw(16)","long raw","rowid","mlslabel","clob", - "nclob","bfile" - ); - -@types=(["sql",\@sql_types], - ["odbc",\@odbc_types], - ["extra",\@extra_types]); - -foreach $types (@types) -{ - print "\nSupported $types->[0] types\n"; - $tmp=@$types->[1]; - foreach $use_type (@$tmp) - { - $type=$use_type; - $type =~ s/\(.*\)/(1 arg)/; - if (index($use_type,",")>= 0) - { - $type =~ s/\(1 arg\)/(2 arg)/; - } - if (($tmp2=index($type,",unique")) >= 0) - { - $type=substr($type,0,$tmp2); - } - $tmp2=$type; - $tmp2 =~ s/ /_/g; - $tmp2 =~ s/_not_null//g; - report("Type $type","type_$types->[0]_$tmp2", - "create table crash_q (q $use_type)", - "drop table crash_q $drop_attr"); - } -} - -# -# Test some type limits -# - - -check_and_report("Remembers end space in char()","remember_end_space", - ["create table crash_q (a char(10))", - "insert into crash_q values('hello ')"], - "select a from crash_q where a = 'hello '", - ["drop table crash_q $drop_attr"], - 'hello ',6); - -check_and_report("Remembers end space in varchar()", - "remember_end_space_varchar", - ["create table crash_q (a varchar(10))", - "insert into crash_q values('hello ')"], - "select a from crash_q where a = 'hello '", - ["drop table crash_q $drop_attr"], - 'hello ',6); - -if (($limits{'type_extra_float(2_arg)'} eq "yes" || - $limits{'type_sql_decimal(2_arg)'} eq "yes") && - (!defined($limits{'storage_of_float'}))) -{ - my $type=$limits{'type_extra_float(2_arg)'} eq "yes" ? "float(4,1)" : - "decimal(4,1)"; - my $result="undefined"; - if (execute_and_check("storage_of_float",["create table crash_q (q1 $type)", - "insert into crash_q values(1.14)"], - "select q1 from crash_q", - ["drop table crash_q $drop_attr"],1.1,0) && - execute_and_check("storage_of_float",["create table crash_q (q1 $type)", - "insert into crash_q values(1.16)"], - "select q1 from crash_q", - ["drop table crash_q $drop_attr"],1.1,0)) - { - $result="truncate"; - } - elsif (execute_and_check("storage_of_float",["create table crash_q (q1 $type)", - "insert into crash_q values(1.14)"], - "select q1 from crash_q", - ["drop table crash_q $drop_attr"],1.1,0) && - execute_and_check("storage_of_float",["create table crash_q (q1 $type)", - "insert into crash_q values(1.16)"], - "select q1 from crash_q", - ["drop table crash_q $drop_attr"],1.2,0)) - { - $result="round"; - } - elsif (execute_and_check("storage_of_float",["create table crash_q (q1 $type)", - "insert into crash_q values(1.14)"], - "select q1 from crash_q", - ["drop table crash_q $drop_attr"],1.14,0) && - execute_and_check("storage_of_float",["create table crash_q (q1 $type)", - "insert into crash_q values(1.16)"], - "select q1 from crash_q", - ["drop table crash_q $drop_attr"],1.16,0)) - { - $result="exact"; - } - $prompt="Storage of float values"; - print "$prompt: $result\n"; - save_config_data("storage_of_float", $result, $prompt); -} - -try_and_report("Type for row id", "rowid", - ["rowid", - "create table crash_q (a rowid)", - "drop table crash_q $drop_attr"], - ["auto_increment", - "create table crash_q (a int not null auto_increment". - ", primary key(a))","drop table crash_q $drop_attr"], - ["oid", - "create table crash_q (a oid, primary key(a))", - "drop table crash_q $drop_attr"], - ["serial", - "create table crash_q (a serial, primary key(a))", - "drop table crash_q $drop_attr"]); - -try_and_report("Automatic row id", "automatic_rowid", - ["_rowid", - "create table crash_q (a int not null, primary key(a))", - "insert into crash_q values (1)", - "select _rowid from crash_q", - "drop table crash_q $drop_attr"]); - -# -# Test functions -# - -@sql_functions= - (["+, -, * and /","+","5*3-4/2+1",14,0], - ["ANSI SQL SUBSTRING","substring","substring('abcd' from 2 for 2)","bc",1], - ["BIT_LENGTH","bit_length","bit_length('abc')",24,0], - ["searched CASE","searched_case", - "case when 1 > 2 then 'false' when 2 > 1 then 'true' end", "true",1], - ["simple CASE","simple_case", - "case 2 when 1 then 'false' when 2 then 'true' end", "true",1], - ["CAST","cast","CAST(1 as CHAR)","1",1], - ["CHARACTER_LENGTH","character_length","character_length('abcd')","4",0], - ["CHAR_LENGTH","char_length","char_length(b)","10",0], - ["CHAR_LENGTH(constant)","char_length(constant)", - "char_length('abcd')","4",0], - ["COALESCE","coalesce","coalesce($char_null,'bcd','qwe')","bcd",1], - ["CURRENT_DATE","current_date","current_date",0,2], - ["CURRENT_TIME","current_time","current_time",0,2], - ["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2], - ["EXTRACT","extract_sql", - "extract(minute from timestamp '2000-02-23 18:43:12.987')",43,0], - ["LOCALTIME","localtime","localtime",0,2], - ["LOCALTIMESTAMP","localtimestamp","localtimestamp",0,2], - ["LOWER","lower","LOWER('ABC')","abc",1], - ["NULLIF with strings","nullif_string", - "NULLIF(NULLIF('first','second'),'first')",undef(),4], - ["NULLIF with numbers","nullif_num","NULLIF(NULLIF(1,2),1)",undef(),4], - ["OCTET_LENGTH","octet_length","octet_length('abc')",3,0], - ["POSITION","position","position('ll' in 'hello')",3,0], - ["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",3], - ["UPPER","upper","UPPER('abc')","ABC",1], - ["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1], - ); - -@odbc_functions= - (["ASCII", "ascii", "ASCII('A')","65",0], - ["CHAR", "char", "CHAR(65)" ,"A",1], - ["CONCAT(2 arg)","concat", "concat('a','b')","ab",1], - ["DIFFERENCE()","difference","difference('abc','abe')",3,0], - ["INSERT","insert","insert('abcd',2,2,'ef')","aefd",1], - ["LEFT","left","left('abcd',2)","ab",1], - ["LTRIM","ltrim","ltrim(' abcd')","abcd",1], - ["REAL LENGTH","length","length('abcd ')","5",0], - ["ODBC LENGTH","length_without_space","length('abcd ')","4",0], - ["LOCATE(2 arg)","locate_2","locate('bcd','abcd')","2",0], - ["LOCATE(3 arg)","locate_3","locate('bcd','abcd',3)","0",0], - ["LCASE","lcase","lcase('ABC')","abc",1], - ["REPEAT","repeat","repeat('ab',3)","ababab",1], - ["REPLACE","replace","replace('abbaab','ab','ba')","bababa",1], - ["RIGHT","right","right('abcd',2)","cd",1], - ["RTRIM","rtrim","rtrim(' abcd ')"," abcd",1], - ["SPACE","space","space(5)"," ",3], - ["SOUNDEX","soundex","soundex('hello')",0,2], - ["ODBC SUBSTRING","substring","substring('abcd',3,2)","cd",1], - ["UCASE","ucase","ucase('abc')","ABC",1], - - ["ABS","abs","abs(-5)",5,0], - ["ACOS","acos","acos(0)","1.570796",0], - ["ASIN","asin","asin(1)","1.570796",0], - ["ATAN","atan","atan(1)","0.785398",0], - ["ATAN2","atan2","atan2(1,0)","1.570796",0], - ["CEILING","ceiling","ceiling(-4.5)",-4,0], - ["COS","cos","cos(0)","1.00000",0], - ["COT","cot","cot(1)","0.64209262",0], - ["DEGREES","degrees","degrees(6.283185)","360",0], - ["EXP","exp","exp(1.0)","2.718282",0], - ["FLOOR","floor","floor(2.5)","2",0], - ["LOG","log","log(2)","0.693147",0], - ["LOG10","log10","log10(10)","1",0], - ["MOD","mod","mod(11,7)","4",0], - ["PI","pi","pi()","3.141593",0], - ["POWER","power","power(2,4)","16",0], - ["RAND","rand","rand(1)",0,2], # Any value is acceptable - ["RADIANS","radians","radians(360)","6.283185",0], - ["ROUND(2 arg)","round","round(5.63,2)","5.6",0], - ["SIGN","sign","sign(-5)",-1,0], - ["SIN","sin","sin(1)","0.841471",0], - ["SQRT","sqrt","sqrt(4)",2,0], - ["TAN","tan","tan(1)","1.557408",0], - ["TRUNCATE","truncate","truncate(18.18,-1)",10,0], - ["NOW","now","now()",0,2], # Any value is acceptable - ["CURDATE","curdate","curdate()",0,2], - ["CURTIME","curtime","curtime()",0,2], - ["TIMESTAMPADD","timestampadd", - "timestampadd(SQL_TSI_SECOND,1,'1997-01-01 00:00:00')", - "1997-01-01 00:00:01",1], - ["TIMESTAMPDIFF","timestampdiff", - "timestampdiff(SQL_TSI_SECOND,'1997-01-01 00:00:02',". - " '1997-01-01 00:00:01')","1",0], - ["USER()","user()","user()",0,2], - ["DATABASE","database","database()",0,2], - ["IFNULL","ifnull","ifnull(2,3)",2,0], - ["ODBC syntax LEFT & RIGHT", "fn_left", - "{ fn LEFT( { fn RIGHT('abcd',2) },1) }","c",1], - ); - -@extra_functions= - ( - ["& (bitwise and)",'&',"5 & 3",1,0], - ["| (bitwise or)",'|',"1 | 2",3,0], - ["<< and >> (bitwise shifts)",'binary_shifts',"(1 << 4) >> 2",4,0], - ["<> in SELECT","<>","1<>1","0",0], - ["=","=","(1=1)",1,$logical_value], - ["~* (case insensitive compare)","~*","'hi' ~* 'HI'",1,$logical_value], - ["AND and OR in SELECT","and_or","1=1 AND 2=2",$logical_value,0], - ["AND as '&&'",'&&',"1=1 && 2=2",$logical_value,0], - ["ASCII_CHAR", "ascii_char", "ASCII_CHAR(65)","A",1], - ["ASCII_CODE", "ascii_code", "ASCII_CODE('A')","65",0], - ["ATN2","atn2","atn2(1,0)","1.570796",0], - ["BETWEEN in SELECT","between","5 between 4 and 6",$logical_value,0], - ["BIT_COUNT","bit_count","bit_count(5)",2,0], - ["CEIL","ceil","ceil(-4.5)",-4,0], # oracle - ["CHARINDEX","charindex","charindex('a','crash')",3,0], - ["CHR", "chr", "CHR(65)" ,"A",1], # oracle - ["CONCAT(list)","concat_list", "concat('a','b','c','d')","abcd",1], - ["CONVERT","convert","convert(CHAR,5)","5",1], - ["COSH","cosh","cosh(0)","1",0], # oracle hyperbolic cosine of n. - ["ELT","elt","elt(2,'ONE','TWO','THREE')","TWO",1], - ["ENCRYPT","encrypt","encrypt('hello')",0,2], - ["FIELD","field","field('IBM','NCA','ICL','SUN','IBM','DIGITAL')",4,0], - ["FORMAT","format","format(1234.5555,2)","1,234.56",1], - ["GETDATE","getdate","getdate()",0,2], - ["GREATEST","greatest","greatest('HARRY','HARRIOT','HAROLD')","HARRY",1], - ["IF","if", "if(5,6,7)",6,0], - ["IN on numbers in SELECT","in_num","2 in (3,2,5,9,5,1)",$logical_value,0], - ["IN on strings in SELECT","in_str","'monty' in ('david','monty','allan')", $logical_value,0], - ["INITCAP","initcap","initcap('the soap')","The Soap",1], - # oracle Returns char, with the first letter of each word in uppercase - ["INSTR (Oracle syntax)", "instr_oracle", "INSTR('CORPORATE FLOOR','OR',3,2)" ,"14",0], # oracle instring - ["INSTRB", "instrb", "INSTRB('CORPORATE FLOOR','OR',5,2)" ,"27",0], - # oracle instring in bytes - ["INTERVAL","interval","interval(55,10,20,30,40,50,60,70,80,90,100)",5,0], - ["LAST_INSERT_ID","last_insert_id","last_insert_id()",0,2], - ["LEAST","least","least('HARRY','HARRIOT','HAROLD')","HAROLD",1], - # oracle - ["LENGTHB","lengthb","lengthb('CANDIDE')","14",0], - # oracle length in bytes - ["LIKE ESCAPE in SELECT","like_escape", - "'%' like 'a%' escape 'a'",$logical_value,0], - ["LIKE in SELECT","like","'a' like 'a%'",$logical_value,0], - ["LN","ln","ln(95)","4.55387689",0], - # oracle natural logarithm of n - ["LOCATE as INSTR","instr","instr('hello','ll')",3,0], - ["LOG(m,n)","log(m_n)","log(10,100)","2",0], - # oracle logarithm, base m, of n - ["LOGN","logn","logn(2)","0.693147",0], - # informix - ["LPAD","lpad","lpad('hi',4,'??')",'??hi',3], - ["MOD as %","%","10%7","3",0], - ["NOT BETWEEN in SELECT","not_between","5 not between 4 and 6",0,0], - ["NOT LIKE in SELECT","not_like","'a' not like 'a%'",0,0], - ["NOT as '!' in SELECT","!","! 1",0,0], - ["NOT in SELECT","not","not $false",$logical_value,0], - ["ODBC CONVERT","odbc_convert","convert(5,SQL_CHAR)","5",1], - ["OR as '||'",'||',"1=0 || 1=1",$logical_value,0], - ["PASSWORD","password","password('hello')",0,2], - ["PASTE", "paste", "paste('ABCDEFG',3,2,'1234')","AB1234EFG",1], - ["PATINDEX","patindex","patindex('%a%','crash')",3,0], - ["POW","pow","pow(3,2)",9,0], - ["RANGE","range","range(a)","0.0",0], - # informix range(a) = max(a) - min(a) - ["REGEXP in SELECT","regexp","'a' regexp '^(a|b)*\$'",$logical_value,0], - ["REPLICATE","replicate","replicate('a',5)","aaaaa",1], - ["REVERSE","reverse","reverse('abcd')","dcba",1], - ["ROOT","root","root(4)",2,0], # informix - ["ROUND(1 arg)","round1","round(5.63)","6",0], - ["RPAD","rpad","rpad('hi',4,'??')",'hi??',3], - ["SINH","sinh","sinh(1)","1.17520119",0], # oracle hyperbolic sine of n - ["STR","str","str(123.45,5,1)",123.5,3], - ["STRCMP","strcmp","strcmp('abc','adc')",-1,0], - ["STUFF","stuff","stuff('abc',2,3,'xyz')",'axyz',3], - ["SUBSTRB", "substrb", "SUBSTRB('ABCDEFG',5,4.2)" ,"CD",1], - # oracle substring with bytes - ["SUBSTRING as MID","mid","mid('hello',3,2)","ll",1], - ["SUBSTRING_INDEX","substring_index", - "substring_index('www.tcx.se','.',-2)", "tcx.se",1], - ["SYSDATE","sysdate","sysdate()",0,2], - ["TAIL","tail","tail('ABCDEFG',3)","EFG",0], - ["TANH","tanh","tanh(1)","0.462117157",0], - # oracle hyperbolic tangent of n - ["TRANSLATE","translate","translate('abc','bc','de')",'ade',3], - ["TRIM; Many char extension", - "trim_many_char","trim(':!' FROM ':abc!')","abc",3], - ["TRIM; Substring extension", - "trim_substring","trim('cb' FROM 'abccb')","abc",3], - ["TRUNC","trunc","trunc(18.18,-1)",10,0], # oracle - ["UID","uid","uid",0,2], # oracle uid from user - ["UNIX_TIMESTAMP","unix_timestamp","unix_timestamp()",0,2], - ["USERENV","userenv","userenv",0,2], # oracle user enviroment - ["VERSION","version","version()",0,2], - ["automatic num->string convert","auto_num2string","concat('a',2)","a2",1], - ["automatic string->num convert","auto_string2num","'1'+2",3,0], - ["concatenation with +","concat_as_+","'abc' + 'def'","abcdef",1], - ["SUBSTR (2 arg)",'substr2arg',"substr('abcd',2)",'bcd',1], #sapdb func - ["SUBSTR (3 arg)",'substr3arg',"substr('abcd',2,2)",'bc',1], - ["LFILL (3 arg)",'lfill3arg',"lfill('abcd','.',6)",'..abcd',1], - ["RFILL (3 arg)",'rfill3arg',"rfill('abcd','.',6)",'abcd..',1], - ["RPAD (4 arg)",'rpad4arg',"rpad('abcd',2,'+-',8)",'abcd+-+-',1], - ["LPAD (4 arg)",'rpad4arg',"lpad('abcd',2,'+-',8)",'+-+-abcd',1], - ["TRIM (1 arg)",'trim1arg',"trim(' abcd ')",'abcd',1], - ["TRIM (2 arg)",'trim2arg',"trim('..abcd..','.')",'abcd',1], - ["LTRIM (2 arg)",'ltrim2arg',"ltrim('..abcd..','.')",'abcd..',1], - ["RTRIM (2 arg)",'rtrim2arg',"rtrim('..abcd..','.')",'..abcd',1], - ["EXPAND",'expand2arg',"expand('abcd',6)",'abcd ',0], - ["REPLACE (2 arg) ",'replace2arg',"replace('AbCd','bC')",'Ad',1], - ["MAPCHAR",'mapchar',"mapchar('Aâ')",'Aa',1], - ["ALPHA",'alpha',"alpha('Aâ',2)",'AA',1], - ["ASCII in string cast",'ascii_string',"ascii('a')",'a',1], - ["EBCDIC in string cast",'ebcdic_string',"ebcdic('a')",'a',1], - ["TRUNC (1 arg)",'trunc1arg',"trunc(222.6)",222,0], - ["FIXED",'fixed',"fixed(222.6666,10,2)",'222.67',0], - ["FLOAT",'float',"float(6666.66,4)",6667,0], - ["LENGTH",'length',"length(1)",2,0], - ["INDEX",'index',"index('abcdefg','cd',1,1)",3,0], - ["MICROSECOND",'microsecond', - "MICROSECOND('19630816200212111111')",'111111',0], - ["TIMESTAMP",'timestamp', - "timestamp('19630816','00200212')",'19630816200212000000',0], - ["VALUE",'value',"value(NULL,'WALRUS')",'WALRUS',0], - ["DECODE",'decode',"DECODE('S-103','T72',1,'S-103',2,'Leopard',3)",2,0], - ["NUM",'num',"NUM('2123')",2123,0], - ["CHR (any type to string)",'chr_str',"CHR(67)",'67',0], - ["HEX",'hex',"HEX('A')",41,0], - ); - - -@sql_group_functions= - ( - ["AVG","avg","avg(a)",1,0], - ["COUNT (*)","count_*","count(*)",1,0], - ["COUNT column name","count_column","count(a)",1,0], - ["COUNT(DISTINCT expr)","count_distinct","count(distinct a)",1,0], - ["MAX on numbers","max","max(a)",1,0], - ["MAX on strings","max_str","max(b)","a",1], - ["MIN on numbers","min","min(a)",1,0], - ["MIN on strings","min_str","min(b)","a",1], - ["SUM","sum","sum(a)",1,0], - ["ANY","any","any(a)",$logical_value,0], - ["EVERY","every","every(a)",$logical_value,0], - ["SOME","some","some(a)",$logical_value,0], - ); - -@extra_group_functions= - ( - ["BIT_AND",'bit_and',"bit_and(a)",1,0], - ["BIT_OR", 'bit_or', "bit_or(a)",1,0], - ["COUNT(DISTINCT expr,expr,...)", - "count_distinct_list","count(distinct a,b)",1,0], - ["STD","std","std(a)",0,0], - ["STDDEV","stddev","stddev(a)",0,0], - ["VARIANCE","variance","variance(a)",0,0], - ); - -@where_functions= -( - ["= ALL","eq_all","b =all (select b from crash_me)",1,0], - ["= ANY","eq_any","b =any (select b from crash_me)",1,0], - ["= SOME","eq_some","b =some (select b from crash_me)",1,0], - ["BETWEEN","between","5 between 4 and 6",1,0], - ["EXISTS","exists","exists (select * from crash_me)",1,0], - ["IN on numbers","in_num","2 in (3,2,5,9,5,1)",1,0], - ["LIKE ESCAPE","like_escape","b like '%' escape 'a'",1,0], - ["LIKE","like","b like 'a%'",1,0], - ["MATCH UNIQUE","match_unique", - "1 match unique (select a from crash_me)",1,0], - ["MATCH","match","1 match (select a from crash_me)",1,0], - ["MATCHES","matches","b matches 'a*'",1,0], - ["NOT BETWEEN","not_between","7 not between 4 and 6",1,0], - ["NOT EXISTS","not_exists", - "not exists (select * from crash_me where a = 2)",1,0], - ["NOT LIKE","not_like","b not like 'b%'",1,0], - ["NOT UNIQUE","not_unique", - "not unique (select * from crash_me where a = 2)",1,0], - ["UNIQUE","unique","unique (select * from crash_me)",1,0], - ); - -@types=(["sql",\@sql_functions,0], - ["odbc",\@odbc_functions,0], - ["extra",\@extra_functions,0], - ["where",\@where_functions,0]); - -@group_types=(["sql",\@sql_group_functions,0], - ["extra",\@extra_group_functions,0]); - - -foreach $types (@types) -{ - print "\nSupported $types->[0] functions\n"; - $tmp=@$types->[1]; - foreach $type (@$tmp) - { - if (defined($limits{"func_$types->[0]_$type->[1]"})) - { - next; - } - if ($types->[0] eq "where") - { - check_and_report("Function $type->[0]","func_$types->[0]_$type->[1]", - [],"select a from crash_me where $type->[2]",[], - $type->[3],$type->[4]); - } - elsif ($limits{'functions'} eq 'yes') - { - if (($type->[2] =~ /char_length\(b\)/) && (!$end_query)) - { - my $tmp= $type->[2]; - $tmp .= " from crash_me "; - undef($limits{"func_$types->[0]_$type->[1]"}); - check_and_report("Function $type->[0]", - "func_$types->[0]_$type->[1]", - [],"select $tmp ",[], - $type->[3],$type->[4]); - } - else - { - undef($limits{"func_$types->[0]_$type->[1]"}); - $result = check_and_report("Function $type->[0]", - "func_$types->[0]_$type->[1]", - [],"select $type->[2] $end_query",[], - $type->[3],$type->[4]); - if (!$result) - { - # check without type specifyer - if ($type->[2] =~ /DATE /) - { - my $tmp= $type->[2]; - $tmp =~ s/DATE //; - undef($limits{"func_$types->[0]_$type->[1]"}); - $result = check_and_report("Function $type->[0]", - "func_$types->[0]_$type->[1]", - [],"select $tmp $end_query",[], - $type->[3],$type->[4]); - } - if (!$result) - { - if ($types->[0] eq "odbc" && ! ($type->[2] =~ /\{fn/)) - { - my $tmp= $type->[2]; - # Check by converting to ODBC format - undef($limits{"func_$types->[0]_$type->[1]"}); - $tmp= "{fn $tmp }"; - $tmp =~ s/('1997-\d\d-\d\d \d\d:\d\d:\d\d')/{ts $1}/g; - $tmp =~ s/(DATE '1997-\d\d-\d\d')/{d $1}/g; - $tmp =~ s/(TIME '12:13:14')/{t $1}/g; - $tmp =~ s/DATE //; - $tmp =~ s/TIME //; - check_and_report("Function $type->[0]", - "func_$types->[0]_$type->[1]", - [],"select $tmp $end_query",[], - $type->[3],$type->[4]); - } - } - } - } - } - } -} - -if ($limits{'functions'} eq 'yes') -{ - foreach $types (@group_types) - { - print "\nSupported $types->[0] group functions\n"; - $tmp=@$types->[1]; - foreach $type (@$tmp) - { - check_and_report("Group function $type->[0]", - "group_func_$types->[0]_$type->[1]", - [],"select $type->[2],a from crash_me group by a",[], - $type->[3],$type->[4]); - } - } - print "\n"; - report("mixing of integer and float in expression","float_int_expr", - "select 1+1.0 $end_query"); - if ($limits{'func_odbc_exp'} eq 'yes') - { - report("No need to cast from integer to float", - "dont_require_cast_to_float", "select exp(1) $end_query"); - } - check_and_report("Is 1+NULL = NULL","null_num_expr", - [],"select 1+$numeric_null $end_query",[],undef(),4); - $tmp=sql_concat("'a'",$char_null); - if (defined($tmp)) - { - check_and_report("Is $tmp = NULL", "null_concat_expr", [], - "select $tmp $end_query",[], undef(),4); - } - $prompt="Need to cast NULL for arithmetic"; - add_log("Need_cast_for_null", - " Check if numeric_null ($numeric_null) is 'NULL'"); - save_config_data("Need_cast_for_null", - ($numeric_null eq "NULL") ? "no" : "yes", - $prompt); -} -else -{ - print "\n"; -} - - -# Test: NOROUND -{ - my $result = 'undefined'; - my $error; - print "NOROUND: "; - save_incomplete('func_extra_noround','Function NOROUND'); - -# 1) check if noround() function is supported - $error = safe_query_l('func_extra_noround',"select noround(22.6) $end_query"); - if ($error ne 1) # syntax error -- noround is not supported - { - $result = 'no' - } - else # Ok, now check if it really works - { - $error=safe_query_l('func_extra_noround', - ["create table crash_me_nr (a int)", - "insert into crash_me_nr values(noround(10.2))", - "drop table crash_me_nr $drop_attr"]); - if ($error == 1) - { - $result= "syntax only"; - } - else - { - $result= 'yes'; - } - } - print "$result\n"; - save_config_data('func_extra_noround',$result,"Function NOROUND"); -} - -check_parenthesis("func_sql_","CURRENT_USER"); -check_parenthesis("func_sql_","SESSION_USER"); -check_parenthesis("func_sql_","SYSTEM_USER"); -check_parenthesis("func_sql_","USER"); - - -if ($limits{'type_sql_date'} eq 'yes') -{ # - # Checking the format of date in result. - - safe_query("drop table crash_me_d $drop_attr"); - assert("create table crash_me_d (a date)"); - # find the example of date - my $dateexample; - if ($limits{'func_extra_sysdate'} eq 'yes') { - $dateexample=' sysdate() '; - } - elsif ($limits{'func_sql_current_date'} eq 'yes') { - $dateexample='CURRENT_DATE'; - } - elsif ($limits{'func_odbc_curdate'} eq 'yes') { - $dateexample='curdate()'; - } - elsif ($limits{'func_extra_getdate'} eq 'yes') { - $dateexample='getdate()'; - } - elsif ($limits{'func_odbc_now'} eq 'yes') { - $dateexample='now()'; - } else { - #try to guess - $dateexample="DATE '1963-08-16'"; - } ; - - my $key = 'date_format_inresult'; - my $prompt = "Date format in result"; - if (! safe_query_l('date_format_inresult', - "insert into crash_me_d values($dateexample) ")) - { - die "Cannot insert date ($dateexample):".$last_error; - }; - my $sth= $dbh->prepare("select a from crash_me_d"); - add_log('date_format_inresult',"< select a from crash_me_d"); - $sth->execute; - $_= $sth->fetchrow_array; - add_log('date_format_inresult',"> $_"); - safe_query_l($key,"delete from crash_me_d"); - if (/\d{4}-\d{2}-\d{2}/){ save_config_data($key,"iso",$prompt);} - elsif (/\d{2}-\d{2}-\d{2}/){ save_config_data($key,"short iso",$prompt);} - elsif (/\d{2}\.\d{2}\.\d{4}/){ save_config_data($key,"euro",$prompt);} - elsif (/\d{2}\.\d{2}\.\d{2}/){ save_config_data($key,"short euro",$prompt);} - elsif (/\d{2}\/\d{2}\/\d{4}/){ save_config_data($key,"usa",$prompt);} - elsif (/\d{2}\/\d{2}\/\d{2}/){ save_config_data($key,"short usa",$prompt);} - elsif (/\d*/){ save_config_data($key,"YYYYMMDD",$prompt);} - else { save_config_data($key,"unknown",$prompt);}; - $sth->finish; - - check_and_report("Supports YYYY-MM-DD (ISO) format","date_format_ISO", - [ "insert into crash_me_d(a) values ('1963-08-16')"], - "select a from crash_me_d", - ["delete from crash_me_d"], - make_date_r(1963,8,16),1); - - check_and_report("Supports DATE 'YYYY-MM-DD' (ISO) format", - "date_format_ISO_with_date", - [ "insert into crash_me_d(a) values (DATE '1963-08-16')"], - "select a from crash_me_d", - ["delete from crash_me_d"], - make_date_r(1963,8,16),1); - - check_and_report("Supports DD.MM.YYYY (EUR) format","date_format_EUR", - [ "insert into crash_me_d(a) values ('16.08.1963')"], - "select a from crash_me_d", - ["delete from crash_me_d"], - make_date_r(1963,8,16),1); - check_and_report("Supports DATE 'DD.MM.YYYY' (EUR) format", - "date_format_EUR_with_date", - [ "insert into crash_me_d(a) values (DATE '16.08.1963')"], - "select a from crash_me_d", - ["delete from crash_me_d"], - make_date_r(1963,8,16),1); - - check_and_report("Supports YYYYMMDD format", - "date_format_YYYYMMDD", - [ "insert into crash_me_d(a) values ('19630816')"], - "select a from crash_me_d", - ["delete from crash_me_d"], - make_date_r(1963,8,16),1); - check_and_report("Supports DATE 'YYYYMMDD' format", - "date_format_YYYYMMDD_with_date", - [ "insert into crash_me_d(a) values (DATE '19630816')"], - "select a from crash_me_d", - ["delete from crash_me_d"], - make_date_r(1963,8,16),1); - - check_and_report("Supports MM/DD/YYYY format", - "date_format_USA", - [ "insert into crash_me_d(a) values ('08/16/1963')"], - "select a from crash_me_d", - ["delete from crash_me_d"], - make_date_r(1963,8,16),1); - check_and_report("Supports DATE 'MM/DD/YYYY' format", - "date_format_USA_with_date", - [ "insert into crash_me_d(a) values (DATE '08/16/1963')"], - "select a from crash_me_d", - ["delete from crash_me_d"], - make_date_r(1963,8,16),1); - - - - - check_and_report("Supports 0000-00-00 dates","date_zero", - ["create table crash_me2 (a date not null)", - "insert into crash_me2 values (".make_date(0,0,0).")"], - "select a from crash_me2", - ["drop table crash_me2 $drop_attr"], - make_date_r(0,0,0),1); - - check_and_report("Supports 0001-01-01 dates","date_one", - ["create table crash_me2 (a date not null)", - "insert into crash_me2 values (".make_date(1,1,1).")"], - "select a from crash_me2", - ["drop table crash_me2 $drop_attr"], - make_date_r(1,1,1),1); - - check_and_report("Supports 9999-12-31 dates","date_last", - ["create table crash_me2 (a date not null)", - "insert into crash_me2 values (".make_date(9999,12,31).")"], - "select a from crash_me2", - ["drop table crash_me2 $drop_attr"], - make_date_r(9999,12,31),1); - - check_and_report("Supports 'infinity dates","date_infinity", - ["create table crash_me2 (a date not null)", - "insert into crash_me2 values ('infinity')"], - "select a from crash_me2", - ["drop table crash_me2 $drop_attr"], - "infinity",1); - - if (!defined($limits{'date_with_YY'})) - { - check_and_report("Supports YY-MM-DD dates","date_with_YY", - ["create table crash_me2 (a date not null)", - "insert into crash_me2 values ('98-03-03')"], - "select a from crash_me2", - ["drop table crash_me2 $drop_attr"], - make_date_r(1998,3,3),5); - if ($limits{'date_with_YY'} eq "yes") - { - undef($limits{'date_with_YY'}); - check_and_report("Supports YY-MM-DD 2000 compilant dates", - "date_with_YY", - ["create table crash_me2 (a date not null)", - "insert into crash_me2 values ('10-03-03')"], - "select a from crash_me2", - ["drop table crash_me2 $drop_attr"], - make_date_r(2010,3,3),5); - } - } - -# Test: WEEK() - { - my $result="no"; - my $error; - print "WEEK:"; - save_incomplete('func_odbc_week','WEEK'); - $error = safe_query_result_l('func_odbc_week', - "select week(".make_date(1997,2,1).") $end_query",5,0); - # actually this query must return 4 or 5 in the $last_result, - # $error can be 1 (not supported at all) , -1 ( probably USA weeks) - # and 0 - EURO weeks - if ($error == -1) { - if ($last_result == 4) { - $result = 'USA'; - } else { - $result='error'; - add_log('func_odbc_week', - " must return 4 or 5, but $last_result"); - } - } elsif ($error == 0) { - $result = 'EURO'; - } - print " $result\n"; - save_config_data('func_odbc_week',$result,"WEEK"); - } - - my $insert_query ='insert into crash_me_d values('. - make_date(1997,2,1).')'; - safe_query($insert_query); - - foreach $fn ( ( - ["DAYNAME","dayname","dayname(a)","",2], - ["MONTH","month","month(a)","",2], - ["MONTHNAME","monthname","monthname(a)","",2], - ["DAYOFMONTH","dayofmonth","dayofmonth(a)",1,0], - ["DAYOFWEEK","dayofweek","dayofweek(a)",7,0], - ["DAYOFYEAR","dayofyear","dayofyear(a)",32,0], - ["QUARTER","quarter","quarter(a)",1,0], - ["YEAR","year","year(a)",1997,0])) - { - $prompt='Function '.$fn->[0]; - $key='func_odbc_'.$fn->[1]; - add_log($key,"< ".$insert_query); - check_and_report($prompt,$key, - [],"select ".$fn->[2]." from crash_me_d",[], - $fn->[3],$fn->[4] - ); - - }; - safe_query(['delete from crash_me_d', - 'insert into crash_me_d values('.make_date(1963,8,16).')']); - foreach $fn (( - ["DATEADD","dateadd","dateadd(day,3,make_date(1997,11,30))",0,2], - ["MDY","mdy","mdy(7,1,1998)","make_date_r(1998,07,01)",0], # informix - ["DATEDIFF","datediff", - "datediff(month,'Oct 21 1997','Nov 30 1997')",0,2], - ["DATENAME","datename","datename(month,'Nov 30 1997')",0,2], - ["DATEPART","datepart","datepart(month,'July 20 1997')",0,2], - ["DATE_FORMAT","date_format", - "date_format('1997-01-02 03:04:05','M W D Y y m d h i s w')", 0,2], - ["FROM_DAYS","from_days", - "from_days(729024)","make_date_r(1996,1,1)",1], - ["FROM_UNIXTIME","from_unixtime","from_unixtime(0)",0,2], - ["MONTHS_BETWEEN","months_between", - "months_between(make_date(1997,2,2),make_date(1997,1,1))", - "1.03225806",0], # oracle number of months between 2 dates - ["PERIOD_ADD","period_add","period_add(9602,-12)",199502,0], - ["PERIOD_DIFF","period_diff","period_diff(199505,199404)",13,0], - ["WEEKDAY","weekday","weekday(make_date(1997,11,29))",5,0], - ["ADDDATE",'adddate', - "ADDDATE(make_date(2002,12,01),3)",'make_date_r(2002,12,04)',0], - ["SUBDATE",'subdate', - "SUBDATE(make_date(2002,12,04),3)",'make_date_r(2002,12,01)',0], - ["DATEDIFF (2 arg)",'datediff2arg', - "DATEDIFF(make_date(2002,12,04),make_date(2002,12,01))",'3',0], - ["WEEKOFYEAR",'weekofyear', - "WEEKOFYEAR(make_date(1963,08,16))",'33',0], -# table crash_me_d must contain record with 1963-08-16 (for CHAR) - ["CHAR (conversation date)",'char_date', - "CHAR(a,EUR)",'16.08.1963',0], - ["MAKEDATE",'makedate',"MAKEDATE(1963,228)" - ,'make_date_r(1963,08,16)',0], - ["TO_DAYS","to_days", - "to_days(make_date(1996,01,01))",729024,0], - ["ADD_MONTHS","add_months", - "add_months(make_date(1997,01,01),1)","make_date_r(1997,02,01)",0], - # oracle the date plus n months - ["LAST_DAY","last_day", - "last_day(make_date(1997,04,01))","make_date_r(1997,04,30)",0], - # oracle last day of month of date - ["DATE",'date',"date(make_date(1963,8,16))", - 'make_date_r(1963,8,16)',0], - ["DAY",'day',"DAY(make_date(2002,12,01))",1,0])) - { - $prompt='Function '.$fn->[0]; - $key='func_extra_'.$fn->[1]; - my $qry="select ".$fn->[2]." from crash_me_d"; - while( $qry =~ /^(.*)make_date\((\d+),(\d+),(\d+)\)(.*)$/) - { - my $dt= &make_date($2,$3,$4); - $qry=$1.$dt.$5; - }; - my $result=$fn->[3]; - while( $result =~ /^(.*)make_date_r\((\d+),(\d+),(\d+)\)(.*)$/) - { - my $dt= &make_date_r($2,$3,$4); - $result=$1.$dt.$5; - }; - check_and_report($prompt,$key, - [],$qry,[], - $result,$fn->[4] - ); - - } - - safe_query("drop table crash_me_d $drop_attr"); - -} - -if ($limits{'type_sql_time'} eq 'yes') -{ # - # Checking the format of date in result. - - safe_query("drop table crash_me_t $drop_attr"); - assert("create table crash_me_t (a time)"); - # find the example of time - my $timeexample; - if ($limits{'func_sql_current_time'} eq 'yes') { - $timeexample='CURRENT_TIME'; - } - elsif ($limits{'func_odbc_curtime'} eq 'yes') { - $timeexample='curtime()'; - } - elsif ($limits{'func_sql_localtime'} eq 'yes') { - $timeexample='localtime'; - } - elsif ($limits{'func_odbc_now'} eq 'yes') { - $timeexample='now()'; - } else { - #try to guess - $timeexample="'02:55:12'"; - } ; - - my $key = 'time_format_inresult'; - my $prompt = "Time format in result"; - if (! safe_query_l('time_format_inresult', - "insert into crash_me_t values($timeexample) ")) - { - die "Cannot insert time ($timeexample):".$last_error; - }; - my $sth= $dbh->prepare("select a from crash_me_t"); - add_log('time_format_inresult',"< select a from crash_me_t"); - $sth->execute; - $_= $sth->fetchrow_array; - add_log('time_format_inresult',"> $_"); - safe_query_l($key,"delete from crash_me_t"); - if (/\d{2}:\d{2}:\d{2}/){ save_config_data($key,"iso",$prompt);} - elsif (/\d{2}\.\d{2}\.\d{2}/){ save_config_data($key,"euro",$prompt);} - elsif (/\d{2}:\d{2}\s+(AM|PM)/i){ save_config_data($key,"usa",$prompt);} - elsif (/\d{8}$/){ save_config_data($key,"HHHHMMSS",$prompt);} - elsif (/\d{4}$/){ save_config_data($key,"HHMMSS",$prompt);} - else { save_config_data($key,"unknown",$prompt);}; - $sth->finish; - - check_and_report("Supports HH:MM:SS (ISO) time format","time_format_ISO", - [ "insert into crash_me_t(a) values ('20:08:16')"], - "select a from crash_me_t", - ["delete from crash_me_t"], - make_time_r(20,8,16),1); - - check_and_report("Supports HH.MM.SS (EUR) time format","time_format_EUR", - [ "insert into crash_me_t(a) values ('20.08.16')"], - "select a from crash_me_t", - ["delete from crash_me_t"], - make_time_r(20,8,16),1); - - check_and_report("Supports HHHHmmSS time format", - "time_format_HHHHMMSS", - [ "insert into crash_me_t(a) values ('00200816')"], - "select a from crash_me_t", - ["delete from crash_me_t"], - make_time_r(20,8,16),1); - - check_and_report("Supports HHmmSS time format", - "time_format_HHHHMMSS", - [ "insert into crash_me_t(a) values ('200816')"], - "select a from crash_me_t", - ["delete from crash_me_t"], - make_time_r(20,8,16),1); - - check_and_report("Supports HH:MM:SS (AM|PM) time format", - "time_format_USA", - [ "insert into crash_me_t(a) values ('08:08:16 PM')"], - "select a from crash_me_t", - ["delete from crash_me_t"], - make_time_r(20,8,16),1); - - my $insert_query ='insert into crash_me_t values('. - make_time(20,8,16).')'; - safe_query($insert_query); - - foreach $fn ( ( - ["HOUR","hour","hour('".make_time(12,13,14)."')",12,0], - ["ANSI HOUR","hour_time","hour(TIME '".make_time(12,13,14)."')",12,0], - ["MINUTE","minute","minute('".make_time(12,13,14)."')",13,0], - ["SECOND","second","second('".make_time(12,13,14)."')",14,0] - - )) - { - $prompt='Function '.$fn->[0]; - $key='func_odbc_'.$fn->[1]; - add_log($key,"< ".$insert_query); - check_and_report($prompt,$key, - [],"select ".$fn->[2]." $end_query",[], - $fn->[3],$fn->[4] - ); - - }; -# safe_query(['delete from crash_me_t', -# 'insert into crash_me_t values('.make_time(20,8,16).')']); - foreach $fn (( - ["TIME_TO_SEC","time_to_sec","time_to_sec('". - make_time(1,23,21)."')","5001",0], - ["SEC_TO_TIME","sec_to_time","sec_to_time(5001)", - make_time_r(01,23,21),1], - ["ADDTIME",'addtime',"ADDTIME('".make_time(20,2,12). - "','".make_time(0,0,3)."')",make_time_r(20,2,15),0], - ["SUBTIME",'subtime',"SUBTIME('".make_time(20,2,15) - ."','".make_time(0,0,3)."')",make_time_r(20,2,12),0], - ["TIMEDIFF",'timediff',"TIMEDIFF('".make_time(20,2,15)."','". - make_time(20,2,12)."')",make_time_r(0,0,3),0], - ["MAKETIME",'maketime',"MAKETIME(20,02,12)",make_time_r(20,2,12),0], - ["TIME",'time',"time('".make_time(20,2,12)."')",make_time_r(20,2,12),0] - )) - { - $prompt='Function '.$fn->[0]; - $key='func_extra_'.$fn->[1]; - my $qry="select ".$fn->[2]." $end_query"; - my $result=$fn->[3]; - check_and_report($prompt,$key, - [],$qry,[], - $result,$fn->[4] - ); - - } - - safe_query("drop table crash_me_t $drop_attr"); - -} - - -# NOT id BETWEEN a and b -if ($limits{'func_where_not_between'} eq 'yes') -{ - my $result = 'error'; - my $err; - my $key='not_id_between'; - my $prompt='NOT ID BETWEEN interprets as ID NOT BETWEEN'; - print "$prompt:"; - save_incomplete($key,$prompt); - safe_query_l($key,["create table crash_me_b (i int)", - "insert into crash_me_b values(2)", - "insert into crash_me_b values(5)"]); - $err =safe_query_result_l($key, - "select i from crash_me_b where not i between 1 and 3", - 5,0); - if ($err eq 1) { - if (not defined($last_result)) { - $result='no'; - }; - }; - if ( $err eq 0) { - $result = 'yes'; - }; - safe_query_l($key,["drop table crash_me_b"]); - save_config_data($key,$result,$prompt); - print "$result\n"; -}; - - - - -report("LIKE on numbers","like_with_number", - "create table crash_q (a int,b int)", - "insert into crash_q values(10,10)", - "select * from crash_q where a like '10'", - "drop table crash_q $drop_attr"); - -report("column LIKE column","like_with_column", - "create table crash_q (a char(10),b char(10))", - "insert into crash_q values('abc','abc')", - "select * from crash_q where a like b", - "drop table crash_q $drop_attr"); - -report("update of column= -column","NEG", - "create table crash_q (a integer)", - "insert into crash_q values(10)", - "update crash_q set a=-a", - "drop table crash_q $drop_attr"); - -if ($limits{'func_odbc_left'} eq 'yes' || - $limits{'func_odbc_substring'} eq 'yes') -{ - my $type= ($limits{'func_odbc_left'} eq 'yes' ? - "left(a,4)" : "substring(a for 4)"); - - check_and_report("String functions on date columns","date_as_string", - ["create table crash_me2 (a date not null)", - "insert into crash_me2 values ('1998-03-03')"], - "select $type from crash_me2", - ["drop table crash_me2 $drop_attr"], - "1998",1); -} - - -$tmp=sql_concat("b","b"); -if (defined($tmp)) -{ - check_and_report("char are space filled","char_is_space_filled", - [],"select $tmp from crash_me where b = 'a '",[], - 'a a ',6); -} - -if (!defined($limits{'multi_table_update'})) -{ - if (check_and_report("Update with many tables","multi_table_update", - ["create table crash_q (a integer,b char(10))", - "insert into crash_q values(1,'c')", - "update crash_q left join crash_me on crash_q.a=crash_me.a set crash_q.b=crash_me.b"], - "select b from crash_q", - ["drop table crash_q $drop_attr"], - "a",1,undef(),2)) - { - check_and_report("Update with many tables","multi_table_update", - ["create table crash_q (a integer,b char(10))", - "insert into crash_q values(1,'c')", - "update crash_q,crash_me set crash_q.b=crash_me.b ". - "where crash_q.a=crash_me.a"], - "select b from crash_q", - ["drop table crash_q $drop_attr"], - "a",1, - 1); - } -} - -report("DELETE FROM table1,table2...","multi_table_delete", - "create table crash_q (a integer,b char(10))", - "insert into crash_q values(1,'c')", - "delete crash_q.* from crash_q,crash_me where crash_q.a=crash_me.a", - "drop table crash_q $drop_attr"); - -check_and_report("Update with sub select","select_table_update", - ["create table crash_q (a integer,b char(10))", - "insert into crash_q values(1,'c')", - "update crash_q set b= ". - "(select b from crash_me where crash_q.a = crash_me.a)"], - "select b from crash_q", - ["drop table crash_q $drop_attr"], - "a",1); - -check_and_report("Calculate 1--1","minus_neg",[], - "select a--1 from crash_me",[],0,2); - -report("ANSI SQL simple joins","simple_joins", - "select crash_me.a from crash_me, crash_me t0"); - -# -# Check max string size, and expression limits -# -$found=undef; -foreach $type (('mediumtext','text','text()','blob','long')) -{ - if ($limits{"type_extra_$type"} eq 'yes') - { - $found=$type; - last; - } -} -if (defined($found)) -{ - $found =~ s/\(\)/\(%d\)/; - find_limit("max text or blob size","max_text_size", - new query_many(["create table crash_q (q $found)", - "insert into crash_q values ('%s')"], - "select * from crash_q","%s", - ["drop table crash_q $drop_attr"], - min($max_string_size,$limits{'query_size'}-30))); - -} - -# It doesn't make lots of sense to check for string lengths much bigger than -# what can be stored... - -find_limit(($prompt="constant string size in where"),"where_string_size", - new query_repeat([],"select a from crash_me where b >='", - "","","1","","'")); -if ($limits{'where_string_size'} == 10) -{ - save_config_data('where_string_size','nonstandard',$prompt); -} - -if ($limits{'select_constants'} eq 'yes') -{ - find_limit("constant string size in SELECT","select_string_size", - new query_repeat([],"select '","","","a","","'$end_query")); -} - -goto no_functions if ($limits{'functions'} ne "yes"); - -if ($limits{'func_odbc_repeat'} eq 'yes') -{ - find_limit("return string size from function","repeat_string_size", - new query_many([], - "select repeat('a',%d) $end_query","%s", - [], - $max_string_size,0)); -} - -$tmp=find_limit("simple expressions","max_expressions", - new query_repeat([],"select 1","","","+1","",$end_query, - undef(),$max_expressions)); - -if ($tmp > 10) -{ - $tmp= "(1" . ( '+1' x ($tmp-10) ) . ")"; - find_limit("big expressions", "max_big_expressions", - new query_repeat([],"select 0","","","+$tmp","",$end_query, - undef(),$max_big_expressions)); -} - -find_limit("stacked expressions", "max_stack_expression", - new query_repeat([],"select 1","","","+(1",")",$end_query, - undef(),$max_stacked_expressions)); - -no_functions: - -if (!defined($limits{'max_conditions'})) -{ - find_limit("OR and AND in WHERE","max_conditions", - new query_repeat([], - "select a from crash_me where a=1 and b='a'","", - "", " or a=%d and b='%d'","","","", - [],($query_size-42)/29,undef,2)); - $limits{'max_conditions'}*=2; -} -# The 42 is the length of the constant part. -# The 29 is the length of the variable part, plus two seven-digit numbers. - -find_limit("tables in join", "join_tables", - new query_repeat([], - "select crash_me.a",",t%d.a","from crash_me", - ",crash_me t%d","","",[],$max_join_tables,undef, - 1)); - -# Different CREATE TABLE options - -report("primary key in create table",'primary_key_in_create', - "create table crash_q (q integer not null,primary key (q))", - "drop table crash_q $drop_attr"); - -report("unique in create table",'unique_in_create', - "create table crash_q (q integer not null,unique (q))", - "drop table crash_q $drop_attr"); - -if ($limits{'unique_in_create'} eq 'yes') -{ - report("unique null in create",'unique_null_in_create', - "create table crash_q (q integer,unique (q))", - "insert into crash_q (q) values (NULL)", - "insert into crash_q (q) values (NULL)", - "insert into crash_q (q) values (1)", - "drop table crash_q $drop_attr"); -} - -report("default value for column",'create_default', - "create table crash_q (q integer default 10 not null)", - "drop table crash_q $drop_attr"); - -report("default value function for column",'create_default_func', - "create table crash_q (q integer not null,q1 integer default (1+1))", - "drop table crash_q $drop_attr"); - -report("temporary tables",'temporary_table', - "create temporary table crash_q (q integer not null)", - "drop table crash_q $drop_attr"); - -report_one("create table from select",'create_table_select', - [["create table crash_q SELECT * from crash_me","yes"], - ["create table crash_q AS SELECT * from crash_me","with AS"]]); -$dbh->do("drop table crash_q $drop_attr"); - -report("index in create table",'index_in_create', - "create table crash_q (q integer not null,index (q))", - "drop table crash_q $drop_attr"); - -# The following must be executed as we need the value of end_drop_keyword -# later -if (!(defined($limits{'create_index'}) && defined($limits{'drop_index'}))) -{ - if ($res=safe_query_l('create_index',"create index crash_q on crash_me (a)")) - { - $res="yes"; - $drop_res="yes"; - $end_drop_keyword=""; - if (!safe_query_l('drop_index',"drop index crash_q")) - { - # Can't drop the standard way; Check if mSQL - if (safe_query_l('drop_index',"drop index crash_q from crash_me")) - { - $drop_res="with 'FROM'"; # Drop is not ANSI SQL - $end_drop_keyword="drop index %i from %t"; - } - # else check if Access or MySQL - elsif (safe_query_l('drop_index',"drop index crash_q on crash_me")) - { - $drop_res="with 'ON'"; # Drop is not ANSI SQL - $end_drop_keyword="drop index %i on %t"; - } - # else check if MS-SQL - elsif (safe_query_l('drop_index',"drop index crash_me.crash_q")) - { - $drop_res="with 'table.index'"; # Drop is not ANSI SQL - $end_drop_keyword="drop index %t.%i"; - } - } - else - { - # Old MySQL 3.21 supports only the create index syntax - # This means that the second create doesn't give an error. - $res=safe_query_l('create_index',["create index crash_q on crash_me (a)", - "create index crash_q on crash_me (a)", - "drop index crash_q"]); - $res= $res ? 'ignored' : 'yes'; - } - } - else - { - $drop_res=$res='no'; - } - save_config_data('create_index',$res,"create index"); - save_config_data('drop_index',$drop_res,"drop index"); - - print "create index: $limits{'create_index'}\n"; - print "drop index: $limits{'drop_index'}\n"; -} - -# check if we can have 'NULL' as a key -check_and_report("null in index","null_in_index", - [create_table("crash_q",["a char(10)"],["(a)"]), - "insert into crash_q values (NULL)"], - "select * from crash_q", - ["drop table crash_q $drop_attr"], - undef(),4); - -if ($limits{'unique_in_create'} eq 'yes') -{ - report("null in unique index",'null_in_unique', - create_table("crash_q",["q integer"],["unique(q)"]), - "insert into crash_q (q) values(NULL)", - "insert into crash_q (q) values(NULL)", - "drop table crash_q $drop_attr"); - report("null combination in unique index",'nulls_in_unique', - create_table("crash_q",["q integer,q1 integer"],["unique(q,q1)"]), - "insert into crash_q (q,q1) values(1,NULL)", - "insert into crash_q (q,q1) values(1,NULL)", - "drop table crash_q $drop_attr"); -} - -if ($limits{'null_in_unique'} eq 'yes') -{ - report("null in unique index",'multi_null_in_unique', - create_table("crash_q",["q integer, x integer"],["unique(q)"]), - "insert into crash_q(x) values(1)", - "insert into crash_q(x) values(2)", - "drop table crash_q $drop_attr"); -} - -if ($limits{'create_index'} ne 'no') -{ - $end_drop=$end_drop_keyword; - $end_drop =~ s/%i/crash_q/; - $end_drop =~ s/%t/crash_me/; - report("index on column part (extension)","index_parts",, - "create index crash_q on crash_me (b(5))", - $end_drop); - $end_drop=$end_drop_keyword; - $end_drop =~ s/%i/crash_me/; - $end_drop =~ s/%t/crash_me/; - report("different namespace for index", - "index_namespace", - "create index crash_me on crash_me (b)", - $end_drop); -} - -if (!report("case independent table names","table_name_case", - "create table crash_q (q integer)", - "drop table CRASH_Q $drop_attr")) -{ - safe_query("drop table crash_q $drop_attr"); -} - -if (!report("case independent field names","field_name_case", - "create table crash_q (q integer)", - "insert into crash_q(Q) values (1)", - "drop table crash_q $drop_attr")) -{ - safe_query("drop table crash_q $drop_attr"); -} - -if (!report("drop table if exists","drop_if_exists", - "create table crash_q (q integer)", - "drop table if exists crash_q $drop_attr")) -{ - safe_query("drop table crash_q $drop_attr"); -} - -report("create table if not exists","create_if_not_exists", - "create table crash_q (q integer)", - "create table if not exists crash_q (q integer)"); -safe_query("drop table crash_q $drop_attr"); - -# -# test of different join types -# - -assert("create table crash_me2 (a integer not null,b char(10) not null,". - " c1 integer)"); -assert("insert into crash_me2 (a,b,c1) values (1,'b',1)"); -assert("create table crash_me3 (a integer not null,b char(10) not null)"); -assert("insert into crash_me3 (a,b) values (1,'b')"); - -report("inner join","inner_join", - "select crash_me.a from crash_me inner join crash_me2 ON ". - "crash_me.a=crash_me2.a"); -report("left outer join","left_outer_join", - "select crash_me.a from crash_me left join crash_me2 ON ". - "crash_me.a=crash_me2.a"); -report("natural left outer join","natural_left_outer_join", - "select c1 from crash_me natural left join crash_me2"); -report("left outer join using","left_outer_join_using", - "select c1 from crash_me left join crash_me2 using (a)"); -report("left outer join odbc style","odbc_left_outer_join", - "select crash_me.a from { oj crash_me left outer join crash_me2 ON". - " crash_me.a=crash_me2.a }"); -report("right outer join","right_outer_join", - "select crash_me.a from crash_me right join crash_me2 ON ". - "crash_me.a=crash_me2.a"); -report("full outer join","full_outer_join", - "select crash_me.a from crash_me full join crash_me2 ON "." - crash_me.a=crash_me2.a"); -report("cross join (same as from a,b)","cross_join", - "select crash_me.a from crash_me cross join crash_me3"); -report("natural join","natural_join", - "select * from crash_me natural join crash_me3"); -report("union","union", - "select * from crash_me union select a,b from crash_me3"); -report("union all","union_all", - "select * from crash_me union all select a,b from crash_me3"); -report("intersect","intersect", - "select * from crash_me intersect select * from crash_me3"); -report("intersect all","intersect_all", - "select * from crash_me intersect all select * from crash_me3"); -report("except","except", - "select * from crash_me except select * from crash_me3"); -report("except all","except_all", - "select * from crash_me except all select * from crash_me3"); -report("except","except", - "select * from crash_me except select * from crash_me3"); -report("except all","except_all", - "select * from crash_me except all select * from crash_me3"); -report("minus","minus", - "select * from crash_me minus select * from crash_me3"); # oracle ... - -report("natural join (incompatible lists)","natural_join_incompat", - "select c1 from crash_me natural join crash_me2"); -report("union (incompatible lists)","union_incompat", - "select * from crash_me union select a,b from crash_me2"); -report("union all (incompatible lists)","union_all_incompat", - "select * from crash_me union all select a,b from crash_me2"); -report("intersect (incompatible lists)","intersect_incompat", - "select * from crash_me intersect select * from crash_me2"); -report("intersect all (incompatible lists)","intersect_all_incompat", - "select * from crash_me intersect all select * from crash_me2"); -report("except (incompatible lists)","except_incompat", - "select * from crash_me except select * from crash_me2"); -report("except all (incompatible lists)","except_all_incompat", - "select * from crash_me except all select * from crash_me2"); -report("except (incompatible lists)","except_incompat", - "select * from crash_me except select * from crash_me2"); -report("except all (incompatible lists)","except_all_incompat", - "select * from crash_me except all select * from crash_me2"); -report("minus (incompatible lists)","minus_incompat", - "select * from crash_me minus select * from crash_me2"); # oracle ... - -assert("drop table crash_me2 $drop_attr"); -assert("drop table crash_me3 $drop_attr"); - -# somethings to be added here .... -# FOR UNION - INTERSECT - EXCEPT -> CORRESPONDING [ BY ] -# after subqueries: -# >ALL | ANY | SOME - EXISTS - UNIQUE - -if (report("subqueries","subqueries", - "select a from crash_me where crash_me.a in ". - "(select max(a) from crash_me)")) -{ - $tmp=new query_repeat([],"select a from crash_me","","", - " where a in (select a from crash_me",")", - "",[],$max_join_tables); - find_limit("recursive subqueries", "recursive_subqueries",$tmp); -} - -report("insert INTO ... SELECT ...","insert_select", - "create table crash_q (a int)", - "insert into crash_q (a) SELECT crash_me.a from crash_me", - "drop table crash_q $drop_attr"); - -if (!defined($limits{"transactions"})) -{ - my ($limit,$type); - $limit="transactions"; - $limit_r="rollback_metadata"; - print "$limit: "; - foreach $type (('', 'type=bdb', 'type=innodb', 'type=gemini')) - { - undef($limits{$limit}); - if (!report_trans($limit, - [create_table("crash_q",["a integer not null"],[], - $type), - "insert into crash_q values (1)"], - "select * from crash_q", - "drop table crash_q $drop_attr" - )) - { - report_rollback($limit_r, - [create_table("crash_q",["a integer not null"],[], - $type)], - "insert into crash_q values (1)", - "drop table crash_q $drop_attr" ); - last; - }; - } - print "$limits{$limit}\n"; - print "$limit_r: $limits{$limit_r}\n"; -} - -report("atomic updates","atomic_updates", - create_table("crash_q",["a integer not null"],["primary key (a)"]), - "insert into crash_q values (2)", - "insert into crash_q values (3)", - "insert into crash_q values (1)", - "update crash_q set a=a+1", - "drop table crash_q $drop_attr"); - -if ($limits{'atomic_updates'} eq 'yes') -{ - report_fail("atomic_updates_with_rollback","atomic_updates_with_rollback", - create_table("crash_q",["a integer not null"], - ["primary key (a)"]), - "insert into crash_q values (2)", - "insert into crash_q values (3)", - "insert into crash_q values (1)", - "update crash_q set a=a+1 where a < 3", - "drop table crash_q $drop_attr"); -} - -# To add with the views: -# DROP VIEW - CREAT VIEW *** [ WITH [ CASCADE | LOCAL ] CHECK OPTION ] -report("views","views", - "create view crash_q as select a from crash_me", - "drop view crash_q $drop_attr"); - -# Test: foreign key -{ - my $result = 'undefined'; - my $error; - print "foreign keys: "; - save_incomplete('foreign_key','foreign keys'); - -# 1) check if foreign keys are supported - safe_query_l('foreign_key', - create_table("crash_me_qf", - ["a integer not null"], - ["primary key (a)"])); - $error= safe_query_l('foreign_key', - create_table("crash_me_qf2", - ["a integer not null", - "foreign key (a) references crash_me_qf (a)"], - [])); - - if ($error == 1) # OK -- syntax is supported - { - $result = 'error'; - # now check if foreign key really works - safe_query_l('foreign_key', "insert into crash_me_qf values (1)"); - if (safe_query_l('foreign_key', "insert into crash_me_qf2 values (2)") eq 1) - { - $result = 'syntax only'; - } - else - { - $result = 'yes'; - } - } - else - { - $result = "no"; - } - safe_query_l('foreign_key', "drop table crash_me_qf2 $drop_attr"); - safe_query_l('foreign_key', "drop table crash_me_qf $drop_attr"); - print "$result\n"; - save_config_data('foreign_key',$result,"foreign keys"); -} - -if ($limits{'foreign_key'} eq 'yes') -{ - report("allows to update of foreign key values",'foreign_update', - "create table crash_me1 (a int not null primary key)", - "create table crash_me2 (a int not null," . - " foreign key (a) references crash_me1 (a))", - "insert into crash_me1 values (1)", - "insert into crash_me2 values (1)", - "update crash_me1 set a = 2", ## <- must fail - "drop table crash_me2 $drop_attr", - "drop table crash_me1 $drop_attr" - ); -} - -report("Create SCHEMA","create_schema", - "create schema crash_schema create table crash_q (a int) ". - "create table crash_q2(b int)", - "drop schema crash_schema cascade"); - -if ($limits{'foreign_key'} eq 'yes') -{ - if ($limits{'create_schema'} eq 'yes') - { - report("Circular foreign keys","foreign_key_circular", - "create schema crash_schema create table crash_q ". - "(a int primary key, b int, foreign key (b) references ". - "crash_q2(a)) create table crash_q2(a int, b int, ". - "primary key(a), foreign key (b) references crash_q(a))", - "drop schema crash_schema cascade"); - } -} - -if ($limits{'func_sql_character_length'} eq 'yes') -{ - my $result = 'error'; - my ($resultset); - my $key = 'length_of_varchar_field'; - my $prompt='CHARACTER_LENGTH(varchar_field)'; - print $prompt," = "; - if (!defined($limits{$key})) { - save_incomplete($key,$prompt); - safe_query_l($key,[ - "CREATE TABLE crash_me1 (S1 VARCHAR(100))", - "INSERT INTO crash_me1 VALUES ('X')" - ]); - my $recset = get_recordset($key, - "SELECT CHARACTER_LENGTH(S1) FROM crash_me1"); - print_recordset($key,$recset); - if (defined($recset)){ - if ( $recset->[0][0] eq 1 ) { - $result = 'actual length'; - } elsif( $recset->[0][0] eq 100 ) { - $result = 'defined length'; - }; - } else { - add_log($key,$DBI::errstr); - } - safe_query_l($key, "drop table crash_me1 $drop_attr"); - save_config_data($key,$result,$prompt); - } else { - $result = $limits{$key}; - }; - print "$result\n"; -} - - -check_constraint("Column constraints","constraint_check", - "create table crash_q (a int check (a>0))", - "insert into crash_q values(0)", - "drop table crash_q $drop_attr"); - - -check_constraint("Table constraints","constraint_check_table", - "create table crash_q (a int ,b int, check (a>b))", - "insert into crash_q values(0,0)", - "drop table crash_q $drop_attr"); - -check_constraint("Named constraints","constraint_check_named", - "create table crash_q (a int ,b int, constraint abc check (a>b))", - "insert into crash_q values(0,0)", - "drop table crash_q $drop_attr"); - - -report("NULL constraint (SyBase style)","constraint_null", - "create table crash_q (a int null)", - "drop table crash_q $drop_attr"); - -report("Triggers (ANSI SQL)","psm_trigger", - "create table crash_q (a int ,b int)", - "create trigger crash_trigger after insert on crash_q referencing ". - "new table as new_a when (localtime > time '18:00:00') ". - "begin atomic end", - "insert into crash_q values(1,2)", - "drop trigger crash_trigger", - "drop table crash_q $drop_attr"); - -report("PSM procedures (ANSI SQL)","psm_procedures", - "create table crash_q (a int,b int)", - "create procedure crash_proc(in a1 int, in b1 int) language ". - "sql modifies sql data begin declare c1 int; set c1 = a1 + b1;". - " insert into crash_q(a,b) values (a1,c1); end", - "call crash_proc(1,10)", - "drop procedure crash_proc", - "drop table crash_q $drop_attr"); - -report("PSM modules (ANSI SQL)","psm_modules", - "create table crash_q (a int,b int)", - "create module crash_m declare procedure ". - "crash_proc(in a1 int, in b1 int) language sql modifies sql ". - "data begin declare c1 int; set c1 = a1 + b1; ". - "insert into crash_q(a,b) values (a1,c1); end; ". - "declare procedure crash_proc2(INOUT a int, in b int) ". - "contains sql set a = b + 10; end module", - "call crash_proc(1,10)", - "drop module crash_m cascade", - "drop table crash_q cascade $drop_attr"); - -report("PSM functions (ANSI SQL)","psm_functions", - "create table crash_q (a int)", - "create function crash_func(in a1 int, in b1 int) returns int". - " language sql deterministic contains sql ". - " begin return a1 * b1; end", - "insert into crash_q values(crash_func(2,4))", - "select a,crash_func(a,2) from crash_q", - "drop function crash_func cascade", - "drop table crash_q $drop_attr"); - -report("Domains (ANSI SQL)","domains", - "create domain crash_d as varchar(10) default 'Empty' ". - "check (value <> 'abcd')", - "create table crash_q(a crash_d, b int)", - "insert into crash_q(a,b) values('xyz',10)", - "insert into crash_q(b) values(10)", - "drop table crash_q $drop_attr", - "drop domain crash_d"); - - -if (!defined($limits{'lock_tables'})) -{ - report("lock table","lock_tables", - "lock table crash_me READ", - "unlock tables"); - if ($limits{'lock_tables'} eq 'no') - { - delete $limits{'lock_tables'}; - report("lock table","lock_tables", - "lock table crash_me IN SHARE MODE"); - } -} - -if (!report("many tables to drop table","multi_drop", - "create table crash_q (a int)", - "create table crash_q2 (a int)", - "drop table crash_q,crash_q2 $drop_attr")) -{ - $dbh->do("drop table crash_q $drop_attr"); - $dbh->do("drop table crash_q2 $drop_attr"); -} - -if (!report("drop table with cascade/restrict","drop_restrict", - "create table crash_q (a int)", - "drop table crash_q restrict")) -{ - $dbh->do("drop table crash_q $drop_attr"); -} - - -report("-- as comment (ANSI)","comment_--", - "select * from crash_me -- Testing of comments"); -report("// as comment","comment_//", - "select * from crash_me // Testing of comments"); -report("# as comment","comment_#", - "select * from crash_me # Testing of comments"); -report("/* */ as comment","comment_/**/", - "select * from crash_me /* Testing of comments */"); - -# -# Check things that fails one some servers -# - -# Empress can't insert empty strings in a char() field -report("insert empty string","insert_empty_string", - create_table("crash_q",["a char(10) not null,b char(10)"],[]), - "insert into crash_q values ('','')", - "drop table crash_q $drop_attr"); - -report("Having with alias","having_with_alias", - create_table("crash_q",["a integer"],[]), - "insert into crash_q values (10)", - "select sum(a) as b from crash_q group by a having b > 0", - "drop table crash_q $drop_attr"); - -# -# test name limits -# - -find_limit("table name length","max_table_name", - new query_many(["create table crash_q%s (q integer)", - "insert into crash_q%s values(1)"], - "select * from crash_q%s",1, - ["drop table crash_q%s $drop_attr"], - $max_name_length,7,1)); - -find_limit("column name length","max_column_name", - new query_many(["create table crash_q (q%s integer)", - "insert into crash_q (q%s) values(1)"], - "select q%s from crash_q",1, - ["drop table crash_q $drop_attr"], - $max_name_length,1)); - -if ($limits{'column_alias'} eq 'yes') -{ - find_limit("select alias name length","max_select_alias_name", - new query_many(undef, - "select b as %s from crash_me",undef, - undef, $max_name_length)); -} - -find_limit("table alias name length","max_table_alias_name", - new query_many(undef, - "select %s.b from crash_me %s", - undef, - undef, $max_name_length)); - -$end_drop_keyword = "drop index %i" if (!$end_drop_keyword); -$end_drop=$end_drop_keyword; -$end_drop =~ s/%i/crash_q%s/; -$end_drop =~ s/%t/crash_me/; - -if ($limits{'create_index'} ne 'no') -{ - find_limit("index name length","max_index_name", - new query_many(["create index crash_q%s on crash_me (a)"], - undef,undef, - [$end_drop], - $max_name_length,7)); -} - -find_limit("max char() size","max_char_size", - new query_many(["create table crash_q (q char(%d))", - "insert into crash_q values ('%s')"], - "select * from crash_q","%s", - ["drop table crash_q $drop_attr"], - min($max_string_size,$limits{'query_size'}))); - -if ($limits{'type_sql_varchar(1_arg)'} eq 'yes') -{ - find_limit("max varchar() size","max_varchar_size", - new query_many(["create table crash_q (q varchar(%d))", - "insert into crash_q values ('%s')"], - "select * from crash_q","%s", - ["drop table crash_q $drop_attr"], - min($max_string_size,$limits{'query_size'}))); -} - -$found=undef; -foreach $type (('mediumtext','text','text()','blob','long')) -{ - if ($limits{"type_extra_$type"} eq 'yes') - { - $found=$type; - last; - } -} -if (defined($found)) -{ - $found =~ s/\(\)/\(%d\)/; - find_limit("max text or blob size","max_text_size", - new query_many(["create table crash_q (q $found)", - "insert into crash_q values ('%s')"], - "select * from crash_q","%s", - ["drop table crash_q $drop_attr"], - min($max_string_size,$limits{'query_size'}-30))); - -} - -$tmp=new query_repeat([],"create table crash_q (a integer","","", - ",a%d integer","",")",["drop table crash_q $drop_attr"], - $max_columns); -$tmp->{'offset'}=1; -find_limit("Columns in table","max_columns",$tmp); - -# Make a field definition to be used when testing keys - -$key_definitions="q0 integer not null"; -$key_fields="q0"; -for ($i=1; $i < min($limits{'max_columns'},$max_keys) ; $i++) -{ - $key_definitions.=",q$i integer not null"; - $key_fields.=",q$i"; -} -$key_values="1," x $i; -chop($key_values); - -if ($limits{'unique_in_create'} eq 'yes') -{ - find_limit("unique indexes","max_unique_index", - new query_table("create table crash_q (q integer", - ",q%d integer not null,unique (q%d)",")", - ["insert into crash_q (q,%f) values (1,%v)"], - "select q from crash_q",1, - "drop table crash_q $drop_attr", - $max_keys,0)); - - find_limit("index parts","max_index_parts", - new query_table("create table crash_q ". - "($key_definitions,unique (q0", - ",q%d","))", - ["insert into crash_q ($key_fields) values ($key_values)"], - "select q0 from crash_q",1, - "drop table crash_q $drop_attr", - $max_keys,1)); - - find_limit("max index part length","max_index_part_length", - new query_many(["create table crash_q (q char(%d) not null,". - "unique(q))", - "insert into crash_q (q) values ('%s')"], - "select q from crash_q","%s", - ["drop table crash_q $drop_attr"], - $limits{'max_char_size'},0)); - - if ($limits{'type_sql_varchar(1_arg)'} eq 'yes') - { - find_limit("index varchar part length","max_index_varchar_part_length", - new query_many(["create table crash_q (q varchar(%d) not null,". - "unique(q))", - "insert into crash_q (q) values ('%s')"], - "select q from crash_q","%s", - ["drop table crash_q $drop_attr"], - $limits{'max_varchar_size'},0)); - } -} - - -if ($limits{'create_index'} ne 'no') -{ - if ($limits{'create_index'} eq 'ignored' || - $limits{'unique_in_create'} eq 'yes') - { # This should be true - add_log('max_index', - " max_unique_index=$limits{'max_unique_index'} ,". - "so max_index must be same"); - save_config_data('max_index',$limits{'max_unique_index'},"max index"); - print "indexes: $limits{'max_index'}\n"; - } - else - { - if (!defined($limits{'max_index'})) - { - safe_query_l('max_index',"create table crash_q ($key_definitions)"); - for ($i=1; $i <= min($limits{'max_columns'},$max_keys) ; $i++) - { - last if (!safe_query_l('max_index', - "create index crash_q$i on crash_q (q$i)")); - } - save_config_data('max_index',$i == $max_keys ? $max_keys : $i, - "max index"); - while ( --$i > 0) - { - $end_drop=$end_drop_keyword; - $end_drop =~ s/%i/crash_q$i/; - $end_drop =~ s/%t/crash_q/; - assert($end_drop); - } - assert("drop table crash_q $drop_attr"); - } - print "indexs: $limits{'max_index'}\n"; - if (!defined($limits{'max_unique_index'})) - { - safe_query_l('max_unique_index', - "create table crash_q ($key_definitions)"); - for ($i=0; $i < min($limits{'max_columns'},$max_keys) ; $i++) - { - last if (!safe_query_l('max_unique_index', - "create unique index crash_q$i on crash_q (q$i)")); - } - save_config_data('max_unique_index',$i == $max_keys ? $max_keys : $i, - "max unique index"); - while ( --$i >= 0) - { - $end_drop=$end_drop_keyword; - $end_drop =~ s/%i/crash_q$i/; - $end_drop =~ s/%t/crash_q/; - assert($end_drop); - } - assert("drop table crash_q $drop_attr"); - } - print "unique indexes: $limits{'max_unique_index'}\n"; - if (!defined($limits{'max_index_parts'})) - { - safe_query_l('max_index_parts', - "create table crash_q ($key_definitions)"); - $end_drop=$end_drop_keyword; - $end_drop =~ s/%i/crash_q1%d/; - $end_drop =~ s/%t/crash_q/; - find_limit("index parts","max_index_parts", - new query_table("create index crash_q1%d on crash_q (q0", - ",q%d",")", - [], - undef,undef, - $end_drop, - $max_keys,1)); - assert("drop table crash_q $drop_attr"); - } - else - { - print "index parts: $limits{'max_index_parts'}\n"; - } - $end_drop=$end_drop_keyword; - $end_drop =~ s/%i/crash_q2%d/; - $end_drop =~ s/%t/crash_me/; - - find_limit("index part length","max_index_part_length", - new query_many(["create table crash_q (q char(%d))", - "create index crash_q2%d on crash_q (q)", - "insert into crash_q values('%s')"], - "select q from crash_q", - "%s", - [ $end_drop, - "drop table crash_q $drop_attr"], - min($limits{'max_char_size'},"+8192"))); - } -} - -find_limit("index length","max_index_length", - new query_index_length("create table crash_q ", - "drop table crash_q $drop_attr", - $max_key_length)); - -find_limit("max table row length (without blobs)","max_row_length", - new query_row_length("crash_q ", - "not null", - "drop table crash_q $drop_attr", - min($max_row_length, - $limits{'max_columns'}* - min($limits{'max_char_size'},255)))); - -find_limit("table row length with nulls (without blobs)", - "max_row_length_with_null", - new query_row_length("crash_q ", - "", - "drop table crash_q $drop_attr", - $limits{'max_row_length'}*2)); - -find_limit("number of columns in order by","columns_in_order_by", - new query_many(["create table crash_q (%F)", - "insert into crash_q values(%v)", - "insert into crash_q values(%v)"], - "select * from crash_q order by %f", - undef(), - ["drop table crash_q $drop_attr"], - $max_order_by)); - -find_limit("number of columns in group by","columns_in_group_by", - new query_many(["create table crash_q (%F)", - "insert into crash_q values(%v)", - "insert into crash_q values(%v)"], - "select %f from crash_q group by %f", - undef(), - ["drop table crash_q $drop_attr"], - $max_order_by)); - - - -# Safe arithmetic test - -$prompt="safe decimal arithmetic"; -$key="safe_decimal_arithmetic"; -if (!defined($limits{$key})) -{ - print "$prompt="; - save_incomplete($key,$prompt); - if (!safe_query_l($key,$server->create("crash_me_a", - ["a decimal(10,2)","b decimal(10,2)"]))) - { - print DBI->errstr(); - die "Can't create table 'crash_me_a' $DBI::errstr\n"; - }; - - if (!safe_query_l($key, - ["insert into crash_me_a (a,b) values (11.4,18.9)"])) - { - die "Can't insert into table 'crash_me_a' a record: $DBI::errstr\n"; - }; - - $arithmetic_safe = 'no'; - $arithmetic_safe = 'yes' - if ( (safe_query_result_l($key, - 'select count(*) from crash_me_a where a+b=30.3',1,0) == 0) - and (safe_query_result_l($key, - 'select count(*) from crash_me_a where a+b-30.3 = 0',1,0) == 0) - and (safe_query_result_l($key, - 'select count(*) from crash_me_a where a+b-30.3 < 0',0,0) == 0) - and (safe_query_result_l($key, - 'select count(*) from crash_me_a where a+b-30.3 > 0',0,0) == 0)); - save_config_data($key,$arithmetic_safe,$prompt); - print "$arithmetic_safe\n"; - assert("drop table crash_me_a $drop_attr"); -} - else -{ - print "$prompt=$limits{$key} (cached)\n"; -} - -# Check where is null values in sorted recordset -if (!safe_query($server->create("crash_me_n",["i integer","r integer"]))) - { - print DBI->errstr(); - die "Can't create table 'crash_me_n' $DBI::errstr\n"; - }; - -safe_query_l("position_of_null",["insert into crash_me_n (i) values(1)", -"insert into crash_me_n values(2,2)", -"insert into crash_me_n values(3,3)", -"insert into crash_me_n values(4,4)", -"insert into crash_me_n (i) values(5)"]); - -$key = "position_of_null"; -$prompt ="Where is null values in sorted recordset"; -if (!defined($limits{$key})) -{ - save_incomplete($key,$prompt); - print "$prompt="; - $sth=$dbh->prepare("select r from crash_me_n order by r "); - $sth->execute; - add_log($key,"< select r from crash_me_n order by r "); - $limit= detect_null_position($key,$sth); - $sth->finish; - print "$limit\n"; - save_config_data($key,$limit,$prompt); -} else { - print "$prompt=$limits{$key} (cache)\n"; -} - -$key = "position_of_null_desc"; -$prompt ="Where is null values in sorted recordset (DESC)"; -if (!defined($limits{$key})) -{ - save_incomplete($key,$prompt); - print "$prompt="; - $sth=$dbh->prepare("select r from crash_me_n order by r desc"); - $sth->execute; - add_log($key,"< select r from crash_me_n order by r desc"); - $limit= detect_null_position($key,$sth); - $sth->finish; - print "$limit\n"; - save_config_data($key,$limit,$prompt); -} else { - print "$prompt=$limits{$key} (cache)\n"; -} - - -assert("drop table crash_me_n $drop_attr"); - - - -$key = 'sorted_group_by'; -$prompt = 'Group by always sorted'; -if (!defined($limits{$key})) -{ - save_incomplete($key,$prompt); - print "$prompt="; - safe_query_l($key,[ - "create table crash_me_t1 (a int not null, b int not null)", - "insert into crash_me_t1 values (1,1)", - "insert into crash_me_t1 values (1,2)", - "insert into crash_me_t1 values (3,1)", - "insert into crash_me_t1 values (3,2)", - "insert into crash_me_t1 values (2,2)", - "insert into crash_me_t1 values (2,1)", - "create table crash_me_t2 (a int not null, b int not null)", - "create index crash_me_t2_ind on crash_me_t2 (a)", - "insert into crash_me_t2 values (1,3)", - "insert into crash_me_t2 values (3,1)", - "insert into crash_me_t2 values (2,2)", - "insert into crash_me_t2 values (1,1)"]); - - my $bigqry = "select crash_me_t1.a,crash_me_t2.b from ". - "crash_me_t1,crash_me_t2 where crash_me_t1.a=crash_me_t2.a ". - "group by crash_me_t1.a,crash_me_t2.b"; - - my $limit='no'; - my $rs = get_recordset($key,$bigqry); - print_recordset($key,$rs); - if ( defined ($rs)) { - if (compare_recordset($key,$rs,[[1,1],[1,3],[2,2],[3,1]]) eq 0) - { - $limit='yes' - } - } else { - add_log($key,"error: ".$DBI::errstr); - } - - print "$limit\n"; - safe_query_l($key,["drop table crash_me_t1", - "drop table crash_me_t2"]); - save_config_data($key,$limit,$prompt); - -} else { - print "$prompt=$limits{$key} (cashed)\n"; -} - - -# -# End of test -# - -$dbh->do("drop table crash_me $drop_attr"); # Remove temporary table - -print "crash-me safe: $limits{'crash_me_safe'}\n"; -print "reconnected $reconnect_count times\n"; - -$dbh->disconnect || warn $dbh->errstr; -save_all_config_data(); -exit 0; - -# End of test -# - -$dbh->do("drop table crash_me $drop_attr"); # Remove temporary table - -print "crash-me safe: $limits{'crash_me_safe'}\n"; -print "reconnected $reconnect_count times\n"; - -$dbh->disconnect || warn $dbh->errstr; -save_all_config_data(); -exit 0; - -# Check where is nulls in the sorted result (for) -# it expects exactly 5 rows in the result - -sub detect_null_position -{ - my $key = shift; - my $sth = shift; - my ($z,$r1,$r2,$r3,$r4,$r5); - $r1 = $sth->fetchrow_array; add_log($key,"> $r1"); - $r2 = $sth->fetchrow_array; add_log($key,"> $r2"); - $r3 = $sth->fetchrow_array; add_log($key,"> $r3"); - $r4 = $sth->fetchrow_array; add_log($key,"> $r4"); - $r5 = $sth->fetchrow_array; add_log($key,"> $r5"); - return "first" if ( !defined($r1) && !defined($r2) && defined($r3)); - return "last" if ( !defined($r5) && !defined($r4) && defined($r3)); - return "random"; -} - -sub check_parenthesis { - my $prefix=shift; - my $fn=shift; - my $result='no'; - my $param_name=$prefix.lc($fn); - my $r; - - save_incomplete($param_name,$fn); - $r = safe_query("select $fn $end_query"); - add_log($param_name,$safe_query_log); - if ($r == 1) - { - $result="yes"; - } - else{ - $r = safe_query("select $fn() $end_query"); - add_log($param_name,$safe_query_log); - if ( $r == 1) - { - $result="with_parenthesis"; - } - } - - save_config_data($param_name,$result,$fn); -} - -sub check_constraint { - my $prompt = shift; - my $key = shift; - my $create = shift; - my $check = shift; - my $drop = shift; - save_incomplete($key,$prompt); - print "$prompt="; - my $res = 'no'; - my $t; - $t=safe_query($create); - add_log($key,$safe_query_log); - if ( $t == 1) - { - $res='yes'; - $t= safe_query($check); - add_log($key,$safe_query_log); - if ($t == 1) - { - $res='syntax only'; - } - } - safe_query($drop); - add_log($key,$safe_query_log); - - save_config_data($key,$res,$prompt); - print "$res\n"; -} - -sub make_time_r { - my $hour=shift; - my $minute=shift; - my $second=shift; - $_ = $limits{'time_format_inresult'}; - return sprintf "%02d:%02d:%02d", ($hour%24),$minute,$second if (/^iso$/); - return sprintf "%02d.%02d.%02d", ($hour%24),$minute,$second if (/^euro/); - return sprintf "%02d:%02d %s", - ($hour >= 13? ($hour-12) : $hour),$minute,($hour >=13 ? 'PM':'AM') - if (/^usa/); - return sprintf "%02d%02d%02d", ($hour%24),$minute,$second if (/^HHMMSS/); - return sprintf "%04d%02d%02d", ($hour%24),$minute,$second if (/^HHHHMMSS/); - return "UNKNOWN FORMAT"; -} - -sub make_time { - my $hour=shift; - my $minute=shift; - my $second=shift; - return sprintf "%02d:%02d:%02d", ($hour%24),$minute,$second - if ($limits{'time_format_ISO'} eq "yes"); - return sprintf "%02d.%02d.%02d", ($hour%24),$minute,$second - if ($limits{'time_format_EUR'} eq "yes"); - return sprintf "%02d:%02d %s", - ($hour >= 13? ($hour-12) : $hour),$minute,($hour >=13 ? 'PM':'AM') - if ($limits{'time_format_USA'} eq "yes"); - return sprintf "%02d%02d%02d", ($hour%24),$minute,$second - if ($limits{'time_format_HHMMSS'} eq "yes"); - return sprintf "%04d%02d%02d", ($hour%24),$minute,$second - if ($limits{'time_format_HHHHMMSS'} eq "yes"); - return "UNKNOWN FORMAT"; -} - -sub make_date_r { - my $year=shift; - my $month=shift; - my $day=shift; - $_ = $limits{'date_format_inresult'}; - return sprintf "%02d-%02d-%02d", ($year%100),$month,$day if (/^short iso$/); - return sprintf "%04d-%02d-%02d", $year,$month,$day if (/^iso/); - return sprintf "%02d.%02d.%02d", $day,$month,($year%100) if (/^short euro/); - return sprintf "%02d.%02d.%04d", $day,$month,$year if (/^euro/); - return sprintf "%02d/%02d/%02d", $month,$day,($year%100) if (/^short usa/); - return sprintf "%02d/%02d/%04d", $month,$day,$year if (/^usa/); - return sprintf "%04d%02d%02d", $year,$month,$day if (/^YYYYMMDD/); - return "UNKNOWN FORMAT"; -} - - -sub make_date { - my $year=shift; - my $month=shift; - my $day=shift; - return sprintf "'%04d-%02d-%02d'", $year,$month,$day - if ($limits{'date_format_ISO'} eq yes); - return sprintf "DATE '%04d-%02d-%02d'", $year,$month,$day - if ($limits{'date_format_ISO_with_date'} eq yes); - return sprintf "'%02d.%02d.%04d'", $day,$month,$year - if ($limits{'date_format_EUR'} eq 'yes'); - return sprintf "DATE '%02d.%02d.%04d'", $day,$month,$year - if ($limits{'date_format_EUR_with_date'} eq 'yes'); - return sprintf "'%02d/%02d/%04d'", $month,$day,$year - if ($limits{'date_format_USA'} eq 'yes'); - return sprintf "DATE '%02d/%02d/%04d'", $month,$day,$year - if ($limits{'date_format_USA_with_date'} eq 'yes'); - return sprintf "'%04d%02d%02d'", $year,$month,$day - if ($limits{'date_format_YYYYMMDD'} eq 'yes'); - return sprintf "DATE '%04d%02d%02d'", $year,$month,$day - if ($limits{'date_format_YYYYMMDD_with_date'} eq 'yes'); - return "UNKNOWN FORMAT"; -} - - -sub print_recordset{ - my ($key,$recset) = @_; - my $rec; - foreach $rec (@$recset) - { - add_log($key, " > ".join(',', map(repr($_), @$rec))); - } -} - -# -# read result recordset from sql server. -# returns arrayref to (arrayref to) values -# or undef (in case of sql errors) -# -sub get_recordset{ - my ($key,$query) = @_; - add_log($key, "< $query"); - return $dbh->selectall_arrayref($query); -} - -# function for comparing recordset (that was returned by get_recordset) -# and arrayref of (arrayref of) values. -# -# returns : zero if recordset equal that array, 1 if it doesn't equal -# -# parameters: -# $key - current operation (for logging) -# $recset - recordset -# $mustbe - array of values that we expect -# -# example: $a=get_recordset('some_parameter','select a,b from c'); -# if (compare_recordset('some_parameter',$a,[[1,1],[1,2],[1,3]]) neq 0) -# { -# print "unexpected result\n"; -# } ; -# -sub compare_recordset { - my ($key,$recset,$mustbe) = @_; - my $rec,$recno,$fld,$fldno,$fcount; - add_log($key,"\n Check recordset:"); - $recno=0; - foreach $rec (@$recset) - { - add_log($key," " . join(',', map(repr($_),@$rec)) . " expected: " . - join(',', map(repr($_), @{$mustbe->[$recno]} ) )); - $fcount = @$rec; - $fcount--; - foreach $fldno (0 .. $fcount ) - { - if ($mustbe->[$recno][$fldno] ne $rec->[$fldno]) - { - add_log($key," Recordset doesn't correspond with template"); - return 1; - }; - } - $recno++; - } - add_log($key," Recordset corresponds with template"); - return 0; -} - -# -# converts inner perl value to printable representation -# for example: undef maps to 'NULL', -# string -> 'string' -# int -> int -# -sub repr { - my $s = shift; - return "'$s'"if ($s =~ /\D/); - return 'NULL'if ( not defined($s)); - return $s; -} - - -sub version -{ - print "$0 Ver $version\n"; -} - - -sub usage -{ - version(); - print <<EOF; - -This program tries to find all limits and capabilities for a SQL -server. As it will use the server in some 'unexpected' ways, one -shouldn\'t have anything important running on it at the same time this -program runs! There is a slight chance that something unexpected may -happen.... - -As all used queries are legal according to some SQL standard. any -reasonable SQL server should be able to run this test without any -problems. - -All questions is cached in $opt_dir/'server_name'[-suffix].cfg that -future runs will use limits found in previous runs. Remove this file -if you want to find the current limits for your version of the -database server. - -This program uses some table names while testing things. If you have any -tables with the name of 'crash_me' or 'crash_qxxxx' where 'x' is a number, -they will be deleted by this test! - -$0 takes the following options: - ---help or --Information - Shows this help - ---batch-mode - Don\'t ask any questions, quit on errors. - ---config-file='filename' - Read limit results from specific file - ---comment='some comment' - Add this comment to the crash-me limit file - ---check-server - Do a new connection to the server every time crash-me checks if the server - is alive. This can help in cases where the server starts returning wrong - data because of an earlier select. - ---database='database' (Default $opt_database) - Create test tables in this database. - ---dir='limits' - Save crash-me output in this directory - ---debug - Lots of printing to help debugging if something goes wrong. - ---fix-limit-file - Reformat the crash-me limit file. crash-me is not run! - ---force - Start test at once, without a warning screen and without questions. - This is a option for the very brave. - Use this in your cron scripts to test your database every night. - ---log-all-queries - Prints all queries that are executed. Mostly used for debugging crash-me. - ---log-queries-to-file='filename' - Log full queries to file. - ---host='hostname' (Default $opt_host) - Run tests on this host. - ---password='password' - Password for the current user. - ---restart - Save states during each limit tests. This will make it possible to continue - by restarting with the same options if there is some bug in the DBI or - DBD driver that caused $0 to die! - ---server='server name' (Default $opt_server) - Run the test on the given server. - Known servers names are: Access, Adabas, AdabasD, Empress, Oracle, - Informix, DB2, Mimer, mSQL, MS-SQL, MySQL, Pg, Solid or Sybase. - For others $0 can\'t report the server version. - ---suffix='suffix' (Default '') - Add suffix to the output filename. For instance if you run crash-me like - "crash-me --suffix="myisam", - then output filename will look "mysql-myisam.cfg". - ---user='user_name' - User name to log into the SQL server. - ---db-start-cmd='command to restart server' - Automaticly restarts server with this command if the database server dies. - ---sleep='time in seconds' (Default $opt_sleep) - Wait this long before restarting server. - ---verbose ---noverbose - Log into the result file queries performed for determination parameter value - -EOF - exit(0); -} - - -sub server_info -{ - my ($ok,$tmp); - $ok=0; - print "\nNOTE: You should be familiar with '$0 --help' before continuing!\n\n"; - if (lc($opt_server) eq "mysql") - { - $ok=1; - print <<EOF; -This test should not crash MySQL if it was distributed together with the -running MySQL version. -If this is the case you can probably continue without having to worry about -destroying something. -EOF - } - elsif (lc($opt_server) eq "msql") - { - print <<EOF; -This test will take down mSQL repeatedly while finding limits. -To make this test easier, start mSQL in another terminal with something like: - -while (true); do /usr/local/mSQL/bin/msql2d ; done - -You should be sure that no one is doing anything important with mSQL and that -you have privileges to restart it! -It may take awhile to determinate the number of joinable tables, so prepare to -wait! -EOF - } - elsif (lc($opt_server) eq "solid") - { - print <<EOF; -This test will take down Solid server repeatedly while finding limits. -You should be sure that no one is doing anything important with Solid -and that you have privileges to restart it! - -If you are running Solid without logging and/or backup YOU WILL LOSE! -Solid does not write data from the cache often enough. So if you continue -you may lose tables and data that you entered hours ago! - -Solid will also take a lot of memory running this test. You will nead -at least 234M free! - -When doing the connect test Solid server or the perl api will hang when -freeing connections. Kill this program and restart it to continue with the -test. You don\'t have to use --restart for this case. -EOF - if (!$opt_restart) - { - print "\nWhen DBI/Solid dies you should run this program repeatedly\n"; - print "with --restart until all tests have completed\n"; - } - } - elsif (lc($opt_server) eq "pg") - { - print <<EOF; -This test will crash postgreSQL when calculating the number of joinable tables! -You should be sure that no one is doing anything important with postgreSQL -and that you have privileges to restart it! -EOF - } - else - { - print <<EOF; -This test may crash $opt_server repeatedly while finding limits! -You should be sure that no one is doing anything important with $opt_server -and that you have privileges to restart it! -EOF - } - print <<EOF; - -Some of the tests you are about to execute may require a lot of -memory. Your tests WILL adversely affect system performance. It\'s -not uncommon that either this crash-me test program, or the actual -database back-end, will DIE with an out-of-memory error. So might -any other program on your system if it requests more memory at the -wrong time. - -Note also that while crash-me tries to find limits for the database server -it will make a lot of queries that can\'t be categorized as \'normal\'. It\'s -not unlikely that crash-me finds some limit bug in your server so if you -run this test you have to be prepared that your server may die during it! - -We, the creators of this utility, are not responsible in any way if your -database server unexpectedly crashes while this program tries to find the -limitations of your server. By accepting the following question with \'yes\', -you agree to the above! - -You have been warned! - -EOF - - # - # No default reply here so no one can blame us for starting the test - # automaticly. - # - for (;;) - { - print "Start test (yes/no) ? "; - $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp); - last if ($tmp =~ /^yes$/i); - exit 1 if ($tmp =~ /^n/i); - print "\n"; - } -} - -sub machine -{ - my @name = POSIX::uname(); - my $name= $name[0] . " " . $name[2] . " " . $name[4]; - return $name; -} - - -# -# Help functions that we need -# - -sub safe_connect -{ - my ($object)=@_; - my ($dbh,$tmp); - - for (;;) - { - if (($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password, - { PrintError => 0, AutoCommit => 1}))) - { - $dbh->{LongReadLen}= 16000000; # Set max retrieval buffer - return $dbh; - } - print "Error: $DBI::errstr; $server->{'data_source'} ". - " - '$opt_user' - '$opt_password'\n"; - print "I got the above error when connecting to $opt_server\n"; - if (defined($object) && defined($object->{'limit'})) - { - print "This check was done with limit: $object->{'limit'}.". - "\nNext check will be done with a smaller limit!\n"; - $object=undef(); - } - save_config_data('crash_me_safe','no',"crash me safe"); - if ($opt_db_start_cmd) - { - print "Restarting the db server with:\n'$opt_db_start_cmd'\n"; - system("$opt_db_start_cmd"); - print "Waiting $opt_sleep seconds so the server can initialize\n"; - sleep $opt_sleep; - } - else - { - exit(1) if ($opt_batch_mode); - print "Can you check/restart it so I can continue testing?\n"; - for (;;) - { - print "Continue test (yes/no) ? [yes] "; - $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp); - $tmp = "yes" if ($tmp eq ""); - last if (index("yes",$tmp) >= 0); - exit 1 if (index("no",$tmp) >= 0); - print "\n"; - } - } - } -} - -# -# Test connecting a couple of times before giving an error -# This is needed to get the server time to free old connections -# after the connect test -# - -sub retry_connect -{ - my ($dbh, $i); - for ($i=0 ; $i < 10 ; $i++) - { - if (($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password, - { PrintError => 0, AutoCommit => 1}))) - { - $dbh->{LongReadLen}= 16000000; # Set max retrieval buffer - return $dbh; - } - sleep(1); - } - return safe_connect(); -} - -# -# Check if the server is up and running. If not, ask the user to restart it -# - -sub check_connect -{ - my ($object)=@_; - my ($sth); - print "Checking connection\n" if ($opt_log_all_queries); - # The following line will not work properly with interbase - if ($opt_check_server && defined($check_connect) && $dbh->{AutoCommit} != 0) - { - - $dbh->disconnect; - $dbh=safe_connect($object); - return; - } - return if (defined($check_connect) && defined($dbh->do($check_connect))); - $dbh->disconnect || warn $dbh->errstr; - print "\nreconnecting\n" if ($opt_debug); - $reconnect_count++; - undef($dbh); - $dbh=safe_connect($object); -} - -# -# print query if debugging -# -sub repr_query { - my $query=shift; - if (length($query) > 130) - { - $query=substr($query,0,120) . "...(" . (length($query)-120) . ")"; - } - return $query; -} - -sub print_query -{ - my ($query)=@_; - $last_error=$DBI::errstr; - if ($opt_debug) - { - if (length($query) > 130) - { - $query=substr($query,0,120) . "...(" . (length($query)-120) . ")"; - } - printf "\nGot error from query: '%s'\n%s\n",$query,$DBI::errstr; - } -} - -# -# Do one or many queries. Return 1 if all was ok -# Note that all rows are executed -# (to ensure that we execute drop table commands) -# - -sub safe_query_l { - my $key = shift; - my $q = shift; - my $r = safe_query($q); - add_log($key,$safe_query_log); - return $r; -} - -sub safe_query -{ - my($queries)=@_; - my($query,$ok,$retry_ok,$retry,@tmp,$sth); - $safe_query_log=""; - $ok=1; - if (ref($queries) ne "ARRAY") - { - push(@tmp,$queries); - $queries= \@tmp; - } - foreach $query (@$queries) - { - printf "query1: %-80.80s ...(%d - %d)\n",$query, - length($query),$retry_limit if ($opt_log_all_queries); - print LOG "$query;\n" if ($opt_log); - $safe_query_log .= "< $query\n"; - if (length($query) > $query_size) - { - $ok=0; - $safe_query_log .= "Query is too long\n"; - next; - } - - $retry_ok=0; - for ($retry=0; $retry < $retry_limit ; $retry++) - { - if (! ($sth=$dbh->prepare($query))) - { - print_query($query); - $safe_query_log .= "> couldn't prepare:". $dbh->errstr. "\n"; - $retry=100 if (!$server->abort_if_fatal_error()); - # Force a reconnect because of Access drop table bug! - if ($retry == $retry_limit-2) - { - print "Forcing disconnect to retry query\n" if ($opt_debug); - $dbh->disconnect || warn $dbh->errstr; - } - check_connect(); # Check that server is still up - } - else - { - if (!$sth->execute()) - { - print_query($query); - $safe_query_log .= "> execute error:". $dbh->errstr. "\n"; - $retry=100 if (!$server->abort_if_fatal_error()); - # Force a reconnect because of Access drop table bug! - if ($retry == $retry_limit-2) - { - print "Forcing disconnect to retry query\n" if ($opt_debug); - $dbh->disconnect || warn $dbh->errstr; - } - check_connect(); # Check that server is still up - } - else - { - $retry = $retry_limit; - $retry_ok = 1; - $safe_query_log .= "> OK\n"; - } - $sth->finish; - } - } - $ok=0 if (!$retry_ok); - if ($query =~ /create/i && $server->reconnect_on_errors()) - { - print "Forcing disconnect to retry query\n" if ($opt_debug); - $dbh->disconnect || warn $dbh->errstr; - $dbh=safe_connect(); - } - } - return $ok; -} - -sub check_reserved_words -{ - my ($dbh)= @_; - - my $answer, $prompt, $config, $keyword_type; - - my @keywords_ext = ( "ansi-92/99", "ansi92", "ansi99", "extra"); - - my %reserved_words = ( - 'ABSOLUTE' => 0, 'ACTION' => 0, 'ADD' => 0, - 'AFTER' => 0, 'ALIAS' => 0, 'ALL' => 0, - 'ALLOCATE' => 0, 'ALTER' => 0, 'AND' => 0, - 'ANY' => 0, 'ARE' => 0, 'AS' => 0, - 'ASC' => 0, 'ASSERTION' => 0, 'AT' => 0, - 'AUTHORIZATION' => 0, 'BEFORE' => 0, 'BEGIN' => 0, - 'BIT' => 0, 'BOOLEAN' => 0, 'BOTH' => 0, - 'BREADTH' => 0, 'BY' => 0, 'CALL' => 0, - 'CASCADE' => 0, 'CASCADED' => 0, 'CASE' => 0, - 'CAST' => 0, 'CATALOG' => 0, 'CHAR' => 0, - 'CHARACTER' => 0, 'CHECK' => 0, 'CLOSE' => 0, - 'COLLATE' => 0, 'COLLATION' => 0, 'COLUMN' => 0, - 'COMMIT' => 0, 'COMPLETION' => 0, 'CONNECT' => 0, - 'CONNECTION' => 0, 'CONSTRAINT' => 0, 'CONSTRAINTS' => 0, - 'CONTINUE' => 0, 'CORRESPONDING' => 0, 'CREATE' => 0, - 'CROSS' => 0, 'CURRENT' => 0, 'CURRENT_DATE' => 0, - 'CURRENT_TIME' => 0,'CURRENT_TIMESTAMP' => 0, 'CURRENT_USER' => 0, - 'CURSOR' => 0, 'CYCLE' => 0, 'DATA' => 0, - 'DATE' => 0, 'DAY' => 0, 'DEALLOCATE' => 0, - 'DEC' => 0, 'DECIMAL' => 0, 'DECLARE' => 0, - 'DEFAULT' => 0, 'DEFERRABLE' => 0, 'DEFERRED' => 0, - 'DELETE' => 0, 'DEPTH' => 0, 'DESC' => 0, - 'DESCRIBE' => 0, 'DESCRIPTOR' => 0, 'DIAGNOSTICS' => 0, - 'DICTIONARY' => 0, 'DISCONNECT' => 0, 'DISTINCT' => 0, - 'DOMAIN' => 0, 'DOUBLE' => 0, 'DROP' => 0, - 'EACH' => 0, 'ELSE' => 0, 'ELSEIF' => 0, - 'END' => 0, 'END-EXEC' => 0, 'EQUALS' => 0, - 'ESCAPE' => 0, 'EXCEPT' => 0, 'EXCEPTION' => 0, - 'EXEC' => 0, 'EXECUTE' => 0, 'EXTERNAL' => 0, - 'FALSE' => 0, 'FETCH' => 0, 'FIRST' => 0, - 'FLOAT' => 0, 'FOR' => 0, 'FOREIGN' => 0, - 'FOUND' => 0, 'FROM' => 0, 'FULL' => 0, - 'GENERAL' => 0, 'GET' => 0, 'GLOBAL' => 0, - 'GO' => 0, 'GOTO' => 0, 'GRANT' => 0, - 'GROUP' => 0, 'HAVING' => 0, 'HOUR' => 0, - 'IDENTITY' => 0, 'IF' => 0, 'IGNORE' => 0, - 'IMMEDIATE' => 0, 'IN' => 0, 'INDICATOR' => 0, - 'INITIALLY' => 0, 'INNER' => 0, 'INPUT' => 0, - 'INSERT' => 0, 'INT' => 0, 'INTEGER' => 0, - 'INTERSECT' => 0, 'INTERVAL' => 0, 'INTO' => 0, - 'IS' => 0, 'ISOLATION' => 0, 'JOIN' => 0, - 'KEY' => 0, 'LANGUAGE' => 0, 'LAST' => 0, - 'LEADING' => 0, 'LEAVE' => 0, 'LEFT' => 0, - 'LESS' => 0, 'LEVEL' => 0, 'LIKE' => 0, - 'LIMIT' => 0, 'LOCAL' => 0, 'LOOP' => 0, - 'MATCH' => 0, 'MINUTE' => 0, 'MODIFY' => 0, - 'MODULE' => 0, 'MONTH' => 0, 'NAMES' => 0, - 'NATIONAL' => 0, 'NATURAL' => 0, 'NCHAR' => 0, - 'NEW' => 0, 'NEXT' => 0, 'NO' => 0, - 'NONE' => 0, 'NOT' => 0, 'NULL' => 0, - 'NUMERIC' => 0, 'OBJECT' => 0, 'OF' => 0, - 'OFF' => 0, 'OLD' => 0, 'ON' => 0, - 'ONLY' => 0, 'OPEN' => 0, 'OPERATION' => 0, - 'OPTION' => 0, 'OR' => 0, 'ORDER' => 0, - 'OUTER' => 0, 'OUTPUT' => 0, 'PAD' => 0, - 'PARAMETERS' => 0, 'PARTIAL' => 0, 'PRECISION' => 0, - 'PREORDER' => 0, 'PREPARE' => 0, 'PRESERVE' => 0, - 'PRIMARY' => 0, 'PRIOR' => 0, 'PRIVILEGES' => 0, - 'PROCEDURE' => 0, 'PUBLIC' => 0, 'READ' => 0, - 'REAL' => 0, 'RECURSIVE' => 0, 'REF' => 0, - 'REFERENCES' => 0, 'REFERENCING' => 0, 'RELATIVE' => 0, - 'RESIGNAL' => 0, 'RESTRICT' => 0, 'RETURN' => 0, - 'RETURNS' => 0, 'REVOKE' => 0, 'RIGHT' => 0, - 'ROLE' => 0, 'ROLLBACK' => 0, 'ROUTINE' => 0, - 'ROW' => 0, 'ROWS' => 0, 'SAVEPOINT' => 0, - 'SCHEMA' => 0, 'SCROLL' => 0, 'SEARCH' => 0, - 'SECOND' => 0, 'SECTION' => 0, 'SELECT' => 0, - 'SEQUENCE' => 0, 'SESSION' => 0, 'SESSION_USER' => 0, - 'SET' => 0, 'SIGNAL' => 0, 'SIZE' => 0, - 'SMALLINT' => 0, 'SOME' => 0, 'SPACE' => 0, - 'SQL' => 0, 'SQLEXCEPTION' => 0, 'SQLSTATE' => 0, - 'SQLWARNING' => 0, 'STRUCTURE' => 0, 'SYSTEM_USER' => 0, - 'TABLE' => 0, 'TEMPORARY' => 0, 'THEN' => 0, - 'TIME' => 0, 'TIMESTAMP' => 0, 'TIMEZONE_HOUR' => 0, - 'TIMEZONE_MINUTE' => 0, 'TO' => 0, 'TRAILING' => 0, - 'TRANSACTION' => 0, 'TRANSLATION' => 0, 'TRIGGER' => 0, - 'TRUE' => 0, 'UNDER' => 0, 'UNION' => 0, - 'UNIQUE' => 0, 'UNKNOWN' => 0, 'UPDATE' => 0, - 'USAGE' => 0, 'USER' => 0, 'USING' => 0, - 'VALUE' => 0, 'VALUES' => 0, 'VARCHAR' => 0, - 'VARIABLE' => 0, 'VARYING' => 0, 'VIEW' => 0, - 'WHEN' => 0, 'WHENEVER' => 0, 'WHERE' => 0, - 'WHILE' => 0, 'WITH' => 0, 'WITHOUT' => 0, - 'WORK' => 0, 'WRITE' => 0, 'YEAR' => 0, - 'ZONE' => 0, - - 'ASYNC' => 1, 'AVG' => 1, 'BETWEEN' => 1, - 'BIT_LENGTH' => 1,'CHARACTER_LENGTH' => 1, 'CHAR_LENGTH' => 1, - 'COALESCE' => 1, 'CONVERT' => 1, 'COUNT' => 1, - 'EXISTS' => 1, 'EXTRACT' => 1, 'INSENSITIVE' => 1, - 'LOWER' => 1, 'MAX' => 1, 'MIN' => 1, - 'NULLIF' => 1, 'OCTET_LENGTH' => 1, 'OID' => 1, - 'OPERATORS' => 1, 'OTHERS' => 1, 'OVERLAPS' => 1, - 'PENDANT' => 1, 'POSITION' => 1, 'PRIVATE' => 1, - 'PROTECTED' => 1, 'REPLACE' => 1, 'SENSITIVE' => 1, - 'SIMILAR' => 1, 'SQLCODE' => 1, 'SQLERROR' => 1, - 'SUBSTRING' => 1, 'SUM' => 1, 'TEST' => 1, - 'THERE' => 1, 'TRANSLATE' => 1, 'TRIM' => 1, - 'TYPE' => 1, 'UPPER' => 1, 'VIRTUAL' => 1, - 'VISIBLE' => 1, 'WAIT' => 1, - - 'ADMIN' => 2, 'AGGREGATE' => 2, 'ARRAY' => 2, - 'BINARY' => 2, 'BLOB' => 2, 'CLASS' => 2, - 'CLOB' => 2, 'CONDITION' => 2, 'CONSTRUCTOR' => 2, - 'CONTAINS' => 2, 'CUBE' => 2, 'CURRENT_PATH' => 2, - 'CURRENT_ROLE' => 2, 'DATALINK' => 2, 'DEREF' => 2, - 'DESTROY' => 2, 'DESTRUCTOR' => 2, 'DETERMINISTIC' => 2, - 'DO' => 2, 'DYNAMIC' => 2, 'EVERY' => 2, - 'EXIT' => 2, 'EXPAND' => 2, 'EXPANDING' => 2, - 'FREE' => 2, 'FUNCTION' => 2, 'GROUPING' => 2, - 'HANDLER' => 2, 'HAST' => 2, 'HOST' => 2, - 'INITIALIZE' => 2, 'INOUT' => 2, 'ITERATE' => 2, - 'LARGE' => 2, 'LATERAL' => 2, 'LOCALTIME' => 2, - 'LOCALTIMESTAMP' => 2, 'LOCATOR' => 2, 'MEETS' => 2, - 'MODIFIES' => 2, 'NCLOB' => 2, 'NORMALIZE' => 2, - 'ORDINALITY' => 2, 'OUT' => 2, 'PARAMETER' => 2, - 'PATH' => 2, 'PERIOD' => 2, 'POSTFIX' => 2, - 'PRECEDES' => 2, 'PREFIX' => 2, 'READS' => 2, - 'REDO' => 2, 'REPEAT' => 2, 'RESULT' => 2, - 'ROLLUP' => 2, 'SETS' => 2, 'SPECIFIC' => 2, - 'SPECIFICTYPE' => 2, 'START' => 2, 'STATE' => 2, - 'STATIC' => 2, 'SUCCEEDS' => 2, 'TERMINATE' => 2, - 'THAN' => 2, 'TREAT' => 2, 'UNDO' => 2, - 'UNTIL' => 2, - - 'ACCESS' => 3, 'ANALYZE' => 3, 'AUDIT' => 3, - 'AUTO_INCREMENT' => 3, 'BACKUP' => 3, 'BDB' => 3, - 'BERKELEYDB' => 3, 'BIGINT' => 3, 'BREAK' => 3, - 'BROWSE' => 3, 'BTREE' => 3, 'BULK' => 3, - 'CHANGE' => 3, 'CHECKPOINT' => 3, 'CLUSTER' => 3, - 'CLUSTERED' => 3, 'COLUMNS' => 3, 'COMMENT' => 3, - 'COMPRESS' => 3, 'COMPUTE' => 3, 'CONTAINSTABLE' => 3, - 'DATABASE' => 3, 'DATABASES' => 3, 'DAY_HOUR' => 3, - 'DAY_MINUTE' => 3, 'DAY_SECOND' => 3, 'DBCC' => 3, - 'DELAYED' => 3, 'DENY' => 3, 'DISK' => 3, - 'DISTINCTROW' => 3, 'DISTRIBUTED' => 3, 'DUMMY' => 3, - 'DUMP' => 3, 'ENCLOSED' => 3, 'ERRLVL' => 3, - 'ERRORS' => 3, 'ESCAPED' => 3, 'EXCLUSIVE' => 3, - 'EXPLAIN' => 3, 'FIELDS' => 3, 'FILE' => 3, - 'FILLFACTOR' => 3, 'FREETEXT' => 3, 'FREETEXTTABLE' => 3, - 'FULLTEXT' => 3, 'GEOMETRY' => 3, 'HASH' => 3, - 'HIGH_PRIORITY' => 3, 'HOLDLOCK' => 3, 'HOUR_MINUTE' => 3, - 'HOUR_SECOND' => 3, 'IDENTIFIED' => 3, 'IDENTITYCOL' => 3, - 'IDENTITY_INSERT' => 3, 'INCREMENT' => 3, 'INDEX' => 3, - 'INFILE' => 3, 'INITIAL' => 3, 'INNODB' => 3, - 'KEYS' => 3, 'KILL' => 3, 'LINENO' => 3, - 'LINES' => 3, 'LOAD' => 3, 'LOCK' => 3, - 'LONG' => 3, 'LONGBLOB' => 3, 'LONGTEXT' => 3, - 'LOW_PRIORITY' => 3, 'MASTER_SERVER_ID' => 3, 'MAXEXTENTS' => 3, - 'MEDIUMBLOB' => 3, 'MEDIUMINT' => 3, 'MEDIUMTEXT' => 3, - 'MIDDLEINT' => 3, 'MINUS' => 3, 'MINUTE_SECOND' => 3, - 'MLSLABEL' => 3, 'MODE' => 3, 'MRG_MYISAM' => 3, - 'NOAUDIT' => 3, 'NOCHECK' => 3, 'NOCOMPRESS' => 3, - 'NONCLUSTERED' => 3, 'NOWAIT' => 3, 'NUMBER' => 3, - 'OFFLINE' => 3, 'OFFSETS' => 3, 'ONLINE' => 3, - 'OPENDATASOURCE' => 3, 'OPENQUERY' => 3, 'OPENROWSET' => 3, - 'OPENXML' => 3, 'OPTIMIZE' => 3, 'OPTIONALLY' => 3, - 'OUTFILE' => 3, 'OVER' => 3, 'PCTFREE' => 3, - 'PERCENT' => 3, 'PLAN' => 3, 'PRINT' => 3, - 'PROC' => 3, 'PURGE' => 3, 'RAISERROR' => 3, - 'RAW' => 3, 'READTEXT' => 3, 'RECONFIGURE' => 3, - 'REGEXP' => 3, 'RENAME' => 3, 'REPLICATION' => 3, - 'REQUIRE' => 3, 'RESOURCE' => 3, 'RESTORE' => 3, - 'RLIKE' => 3, 'ROWCOUNT' => 3, 'ROWGUIDCOL' => 3, - 'ROWID' => 3, 'ROWNUM' => 3, 'RTREE' => 3, - 'RULE' => 3, 'SAVE' => 3, 'SETUSER' => 3, - 'SHARE' => 3, 'SHOW' => 3, 'SHUTDOWN' => 3, - 'SONAME' => 3, 'SPATIAL' => 3, 'SQL_BIG_RESULT' => 3, -'SQL_CALC_FOUND_ROWS' => 3,'SQL_SMALL_RESULT' => 3, 'SSL' => 3, - 'STARTING' => 3, 'STATISTICS' => 3, 'STRAIGHT_JOIN' => 3, - 'STRIPED' => 3, 'SUCCESSFUL' => 3, 'SYNONYM' => 3, - 'SYSDATE' => 3, 'TABLES' => 3, 'TERMINATED' => 3, - 'TEXTSIZE' => 3, 'TINYBLOB' => 3, 'TINYINT' => 3, - 'TINYTEXT' => 3, 'TOP' => 3, 'TRAN' => 3, - 'TRUNCATE' => 3, 'TSEQUAL' => 3, 'TYPES' => 3, - 'UID' => 3, 'UNLOCK' => 3, 'UNSIGNED' => 3, - 'UPDATETEXT' => 3, 'USE' => 3, 'USER_RESOURCES' => 3, - 'VALIDATE' => 3, 'VARBINARY' => 3, 'VARCHAR2' => 3, - 'WAITFOR' => 3, 'WARNINGS' => 3, 'WRITETEXT' => 3, - 'XOR' => 3, 'YEAR_MONTH' => 3, 'ZEROFILL' => 3 -); - - - safe_query("drop table crash_me10 $drop_attr"); - - foreach my $keyword (sort {$a cmp $b} keys %reserved_words) - { - $keyword_type= $reserved_words{$keyword}; - - $prompt= "Keyword ".$keyword; - $config= "reserved_word_".$keywords_ext[$keyword_type]."_".lc($keyword); - - report_fail($prompt,$config, - "create table crash_me10 ($keyword int not null)", - "drop table crash_me10 $drop_attr" - ); - } -} - -# -# Do a query on a query package object. -# - -sub limit_query -{ - my($object,$limit)=@_; - my ($query,$result,$retry,$sth); - - $query=$object->query($limit); - $result=safe_query($query); - if (!$result) - { - $object->cleanup(); - return 0; - } - if (defined($query=$object->check_query())) - { - for ($retry=0 ; $retry < $retry_limit ; $retry++) - { - printf "query2: %-80.80s\n",$query if ($opt_log_all_queries); - print LOG "$query;\n" if ($opt_log); - if (($sth= $dbh->prepare($query))) - { - if ($sth->execute) - { - $result= $object->check($sth); - $sth->finish; - $object->cleanup(); - return $result; - } - print_query($query); - $sth->finish; - } - else - { - print_query($query); - } - $retry=100 if (!$server->abort_if_fatal_error()); # No need to continue - if ($retry == $retry_limit-2) - { - print "Forcing discoennect to retry query\n" if ($opt_debug); - $dbh->disconnect || warn $dbh->errstr; - } - check_connect($object); # Check that server is still up - } - $result=0; # Query failed - } - $object->cleanup(); - return $result; # Server couldn't handle the query -} - - -sub report -{ - my ($prompt,$limit,@queries)=@_; - print "$prompt: "; - if (!defined($limits{$limit})) - { - my $queries_result = safe_query(\@queries); - add_log($limit, $safe_query_log); - my $report_result; - if ( $queries_result) { - $report_result= "yes"; - add_log($limit,"As far as all queries returned OK, result is YES"); - } else { - $report_result= "no"; - add_log($limit,"As far as some queries didnt return OK, result is NO"); - } - save_config_data($limit,$report_result,$prompt); - } - print "$limits{$limit}\n"; - return $limits{$limit} ne "no"; -} - -sub report_fail -{ - my ($prompt,$limit,@queries)=@_; - print "$prompt: "; - if (!defined($limits{$limit})) - { - my $queries_result = safe_query(\@queries); - add_log($limit, $safe_query_log); - my $report_result; - if ( $queries_result) { - $report_result= "no"; - add_log($limit,"As far as all queries returned OK, result is NO"); - } else { - $report_result= "yes"; - add_log($limit,"As far as some queries didnt return OK, result is YES"); - } - save_config_data($limit,$report_result,$prompt); - } - print "$limits{$limit}\n"; - return $limits{$limit} ne "no"; -} - - -# Return true if one of the queries is ok - -sub report_one -{ - my ($prompt,$limit,$queries)=@_; - my ($query,$res,$result); - print "$prompt: "; - if (!defined($limits{$limit})) - { - save_incomplete($limit,$prompt); - $result="no"; - foreach $query (@$queries) - { - if (safe_query_l($limit,$query->[0])) - { - $result= $query->[1]; - last; - } - } - save_config_data($limit,$result,$prompt); - } - print "$limits{$limit}\n"; - return $limits{$limit} ne "no"; -} - - -# Execute query and save result as limit value. - -sub report_result -{ - my ($prompt,$limit,$query)=@_; - my($error); - print "$prompt: "; - if (!defined($limits{$limit})) - { - save_incomplete($limit,$prompt); - $error=safe_query_result($query,"1",2); - add_log($limit,$safe_query_result_log); - save_config_data($limit,$error ? "not supported" :$last_result,$prompt); - } - print "$limits{$limit}\n"; - return $limits{$limit} ne "not supported"; -} - -sub report_trans -{ - my ($limit,$queries,$check,$clear)=@_; - if (!defined($limits{$limit})) - { - save_incomplete($limit,$prompt); - eval {undef($dbh->{AutoCommit})}; - if (!$@) - { - if (safe_query(\@$queries)) - { - $dbh->rollback; - $dbh->{AutoCommit} = 1; - if (safe_query_result($check,"","")) { - add_log($limit,$safe_query_result_log); - save_config_data($limit,"yes",$limit); - } - safe_query($clear); - } else { - add_log($limit,$safe_query_log); - save_config_data($limit,"error",$limit); - } - $dbh->{AutoCommit} = 1; - } - else - { - add_log($limit,"Couldnt undef autocommit ?? "); - save_config_data($limit,"no",$limit); - } - safe_query($clear); - } - return $limits{$limit} ne "yes"; -} - -sub report_rollback -{ - my ($limit,$queries,$check,$clear)=@_; - if (!defined($limits{$limit})) - { - save_incomplete($limit,$prompt); - eval {undef($dbh->{AutoCommit})}; - if (!$@) - { - if (safe_query(\@$queries)) - { - add_log($limit,$safe_query_log); - - $dbh->rollback; - $dbh->{AutoCommit} = 1; - if (safe_query($check)) { - add_log($limit,$safe_query_log); - save_config_data($limit,"no",$limit); - } else { - add_log($limit,$safe_query_log); - save_config_data($limit,"yes",$limit); - }; - safe_query($clear); - } else { - add_log($limit,$safe_query_log); - save_config_data($limit,"error",$limit); - } - } - else - { - add_log($limit,'Couldnt undef Autocommit??'); - save_config_data($limit,"error",$limit); - } - safe_query($clear); - } - $dbh->{AutoCommit} = 1; - return $limits{$limit} ne "yes"; -} - - -sub check_and_report -{ - my ($prompt,$limit,$pre,$query,$post,$answer,$string_type,$skip_prompt, - $function)=@_; - my ($tmp); - $function=0 if (!defined($function)); - - print "$prompt: " if (!defined($skip_prompt)); - if (!defined($limits{$limit})) - { - save_incomplete($limit,$prompt); - $tmp=1-safe_query(\@$pre); - add_log($limit,$safe_query_log); - if (!$tmp) - { - $tmp=safe_query_result($query,$answer,$string_type) ; - add_log($limit,$safe_query_result_log); - }; - safe_query(\@$post); - add_log($limit,$safe_query_log); - delete $limits{$limit}; - if ($function == 3) # Report error as 'no'. - { - $function=0; - $tmp= -$tmp; - } - if ($function == 0 || - $tmp != 0 && $function == 1 || - $tmp == 0 && $function== 2) - { - save_config_data($limit, $tmp == 0 ? "yes" : $tmp == 1 ? "no" : "error", - $prompt); - print "$limits{$limit}\n"; - return $function == 0 ? $limits{$limit} eq "yes" : 0; - } - return 1; # more things to check - } - print "$limits{$limit}\n"; - return 0 if ($function); - return $limits{$limit} eq "yes"; -} - - -sub try_and_report -{ - my ($prompt,$limit,@tests)=@_; - my ($tmp,$test,$type); - - print "$prompt: "; - - if (!defined($limits{$limit})) - { - save_incomplete($limit,$prompt); - $type="no"; # Not supported - foreach $test (@tests) - { - my $tmp_type= shift(@$test); - if (safe_query_l($limit,\@$test)) - { - $type=$tmp_type; - goto outer; - } - } - outer: - save_config_data($limit, $type, $prompt); - } - print "$limits{$limit}\n"; - return $limits{$limit} ne "no"; -} - -# -# Just execute the query and check values; Returns 1 if ok -# - -sub execute_and_check -{ - my ($key,$pre,$query,$post,$answer,$string_type)=@_; - my ($tmp); - - $tmp=safe_query_l($key,\@$pre); - - $tmp=safe_query_result_l($key,$query,$answer,$string_type) == 0 if ($tmp); - safe_query_l($key,\@$post); - return $tmp; -} - - -# returns 0 if ok, 1 if error, -1 if wrong answer -# Sets $last_result to value of query -sub safe_query_result_l{ - my ($key,$query,$answer,$result_type)=@_; - my $r = safe_query_result($query,$answer,$result_type); - add_log($key,$safe_query_result_log); - return $r; -} - -sub safe_query_result -{ -# result type can be -# 8 (must be empty), 2 (Any value), 0 (number) -# 1 (char, endspaces can differ), 3 (exact char), 4 (NULL) -# 5 (char with prefix), 6 (exact, errors are ignored) -# 7 (array of numbers) - my ($query,$answer,$result_type)=@_; - my ($sth,$row,$result,$retry); - undef($last_result); - $safe_query_result_log=""; - - printf "\nquery3: %-80.80s\n",$query if ($opt_log_all_queries); - print LOG "$query;\n" if ($opt_log); - $safe_query_result_log="<".$query."\n"; - - for ($retry=0; $retry < $retry_limit ; $retry++) - { - if (!($sth=$dbh->prepare($query))) - { - print_query($query); - $safe_query_result_log .= "> prepare failed:".$dbh->errstr."\n"; - - if ($server->abort_if_fatal_error()) - { - check_connect(); # Check that server is still up - next; # Retry again - } - check_connect(); # Check that server is still up - return 1; - } - if (!$sth->execute) - { - print_query($query); - $safe_query_result_log .= "> execute failed:".$dbh->errstr."\n"; - if ($server->abort_if_fatal_error()) - { - check_connect(); # Check that server is still up - next; # Retry again - } - check_connect(); # Check that server is still up - return 1; - } - else - { - last; - } - } - if (!($row=$sth->fetchrow_arrayref)) - { - print "\nquery: $query didn't return any result\n" if ($opt_debug); - $safe_query_result_log .= "> didn't return any result:".$dbh->errstr."\n"; - $sth->finish; - return ($result_type == 8) ? 0 : 1; - } - if ($result_type == 8) - { - $sth->finish; - return 1; - } - $result=0; # Ok - $last_result= $row->[0]; # Save for report_result; - $safe_query_result_log .= ">".$last_result."\n"; - # Note: - # if ($result_type == 2) We accept any return value as answer - - if ($result_type == 0) # Compare numbers - { - $row->[0] =~ s/,/./; # Fix if ',' is used instead of '.' - if ($row->[0] != $answer && (abs($row->[0]- $answer)/ - (abs($row->[0]) + abs($answer))) > 0.01) - { - $result=-1; - $safe_query_result_log .= - "We expected '$answer' but got '$last_result' \n"; - } - } - elsif ($result_type == 1) # Compare where end space may differ - { - $row->[0] =~ s/\s+$//; - if ($row->[0] ne $answer) - { - $result=-1; - $safe_query_result_log .= - "We expected '$answer' but got '$last_result' \n"; - } ; - } - elsif ($result_type == 3) # This should be a exact match - { - if ($row->[0] ne $answer) - { - $result= -1; - $safe_query_result_log .= - "We expected '$answer' but got '$last_result' \n"; - }; - } - elsif ($result_type == 4) # If results should be NULL - { - if (defined($row->[0])) - { - $result= -1; - $safe_query_result_log .= - "We expected NULL but got '$last_result' \n"; - }; - } - elsif ($result_type == 5) # Result should have given prefix - { - if (length($row->[0]) < length($answer) && - substr($row->[0],1,length($answer)) ne $answer) - { - $result= -1 ; - $safe_query_result_log .= - "Result must have prefix '$answer', but '$last_result' \n"; - }; - } - elsif ($result_type == 6) # Exact match but ignore errors - { - if ($row->[0] ne $answer) - { $result= 1; - $safe_query_result_log .= - "We expected '$answer' but got '$last_result' \n"; - } ; - } - elsif ($result_type == 7) # Compare against array of numbers - { - if ($row->[0] != $answer->[0]) - { - $safe_query_result_log .= "must be '$answer->[0]' \n"; - $result= -1; - } - else - { - my ($value); - shift @$answer; - while (($row=$sth->fetchrow_arrayref)) - { - $safe_query_result_log .= ">$row\n"; - - $value=shift(@$answer); - if (!defined($value)) - { - print "\nquery: $query returned to many results\n" - if ($opt_debug); - $safe_query_result_log .= "It returned to many results \n"; - $result= 1; - last; - } - if ($row->[0] != $value) - { - $safe_query_result_log .= "Must return $value here \n"; - $result= -1; - last; - } - } - if ($#$answer != -1) - { - print "\nquery: $query returned too few results\n" - if ($opt_debug); - $safe_query_result_log .= "It returned too few results \n"; - $result= 1; - } - } - } - $sth->finish; - print "\nquery: '$query' returned '$row->[0]' instead of '$answer'\n" - if ($opt_debug && $result && $result_type != 7); - return $result; -} - -# -# Find limit using binary search. This is a weighed binary search that -# will prefere lower limits to get the server to crash as -# few times as possible - - -sub find_limit() -{ - my ($prompt,$limit,$query)=@_; - my ($first,$end,$i,$tmp,@tmp_array, $queries); - print "$prompt: "; - if (defined($end=$limits{$limit})) - { - print "$end (cache)\n"; - return $end; - } - save_incomplete($limit,$prompt); - add_log($limit,"We are trying (example with N=5):"); - $queries = $query->query(5); - if (ref($queries) ne "ARRAY") - { - push(@tmp_array,$queries); - $queries= \@tmp_array; - } - foreach $tmp (@$queries) - { add_log($limit,repr_query($tmp)); } - - if (defined($queries = $query->check_query())) - { - if (ref($queries) ne "ARRAY") - { - @tmp_array=(); - push(@tmp_array,$queries); - $queries= \@tmp_array; - } - foreach $tmp (@$queries) - { add_log($limit,repr_query($tmp)); } - } - if (defined($query->{'init'}) && !defined($end=$limits{'restart'}{'tohigh'})) - { - if (!safe_query_l($limit,$query->{'init'})) - { - $query->cleanup(); - return "error"; - } - } - - if (!limit_query($query,1)) # This must work - { - print "\nMaybe fatal error: Can't check '$prompt' for limit=1\n". - "error: $last_error\n"; - return "error"; - } - - $first=0; - $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'}); - - if (defined($end=$limits{'restart'}{'tohigh'})) - { - $end--; - print "\nRestarting this with low limit: $first and high limit: $end\n"; - delete $limits{'restart'}; - $i=$first+int(($end-$first+4)/5); # Prefere lower on errors - } - else - { - $end= $query->max_limit(); - $i=int(($end+$first)/2); - } - my $log_str = ""; - unless(limit_query($query,0+$end)) { - while ($first < $end) - { - print "." if ($opt_debug); - save_config_data("restart",$i,"") if ($opt_restart); - if (limit_query($query,$i)) - { - $first=$i; - $log_str .= " $i:OK"; - $i=$first+int(($end-$first+1)/2); # to be a bit faster to go up - } - else - { - $end=$i-1; - $log_str .= " $i:FAIL"; - $i=$first+int(($end-$first+4)/5); # Prefere lower on errors - } - } - } - $end+=$query->{'offset'} if ($end && defined($query->{'offset'})); - if ($end >= $query->{'max_limit'} && - substr($query->{'max_limit'},0,1) eq '+') - { - $end= $query->{'max_limit'}; - } - print "$end\n"; - add_log($limit,$log_str); - save_config_data($limit,$end,$prompt); - delete $limits{'restart'}; - return $end; -} - -# -# Check that the query works! -# - -sub assert -{ - my($query)=@_; - - if (!safe_query($query)) - { - $query=join("; ",@$query) if (ref($query) eq "ARRAY"); - print "\nFatal error:\nquery: '$query'\nerror: $DBI::errstr\n"; - exit 1; - } -} - - -sub read_config_data -{ - my ($key,$limit,$prompt); - if (-e $opt_config_file) - { - open(CONFIG_FILE,"+<$opt_config_file") || - die "Can't open configure file $opt_config_file\n"; - print "Reading old values from cache: $opt_config_file\n"; - } - else - { - open(CONFIG_FILE,"+>>$opt_config_file") || - die "Can't create configure file $opt_config_file: $!\n"; - } - select CONFIG_FILE; - $|=1; - select STDOUT; - while (<CONFIG_FILE>) - { - chomp; - if (/^(\S+)=([^\#]*[^\#\s])\s*(\# .*)*$/) - { - $key=$1; $limit=$2 ; $prompt=$3; - if (!$opt_quick || $limit =~ /\d/ || $key =~ /crash_me/) - { - if ($key !~ /restart/i) - { - $limits{$key}=$limit eq "null"? undef : $limit; - $prompts{$key}=length($prompt) ? substr($prompt,2) : ""; - $last_read=$key; - delete $limits{'restart'}; - } - else - { - $limit_changed=1; - if ($limit > $limits{'restart'}{'tohigh'}) - { - $limits{'restart'}{'low'} = $limits{'restart'}{'tohigh'}; - } - $limits{'restart'}{'tohigh'} = $limit; - } - } - } - elsif (/\s*###(.*)$/) # log line - { - # add log line for previously read key - $log{$last_read} .= "$1\n"; - } - elsif (!/^\s*$/ && !/^\#/) - { - die "Wrong config row: $_\n"; - } - } -} - - -sub save_config_data -{ - my ($key,$limit,$prompt)=@_; - $prompts{$key}=$prompt; - return if (defined($limits{$key}) && $limits{$key} eq $limit); - if (!defined($limit) || $limit eq "") - { -# die "Undefined limit for $key\n"; - $limit = 'null'; - } - print CONFIG_FILE "$key=$limit\t# $prompt\n"; - $limits{$key}=$limit; - $limit_changed=1; -# now write log lines (immediatelly after limits) - my $line; - my $last_line_was_empty=0; - foreach $line (split /\n/, $log{$key}) - { - print CONFIG_FILE " ###$line\n" - unless ( ($last_line_was_empty eq 1) - && ($line =~ /^\s+$/) ); - $last_line_was_empty= ($line =~ /^\s+$/)?1:0; - }; - - if (($opt_restart && $limits{'operating_system'} =~ /windows/i) || - ($limits{'operating_system'} =~ /NT/)) - { - # If perl crashes in windows, everything is lost (Wonder why? :) - close CONFIG_FILE; - open(CONFIG_FILE,"+>>$opt_config_file") || - die "Can't reopen configure file $opt_config_file: $!\n"; - } -} - -sub add_log -{ - my $key = shift; - my $line = shift; - $log{$key} .= $line . "\n" if ($opt_verbose);; -} - -sub save_all_config_data -{ - my ($key,$tmp); - close CONFIG_FILE; - return if (!$limit_changed); - open(CONFIG_FILE,">$opt_config_file") || - die "Can't create configure file $opt_config_file: $!\n"; - select CONFIG_FILE; - $|=1; - select STDOUT; - delete $limits{'restart'}; - - print CONFIG_FILE - "#This file is automaticly generated by crash-me $version\n\n"; - foreach $key (sort keys %limits) - { - $tmp="$key=$limits{$key}"; - print CONFIG_FILE $tmp . ("\t" x (int((32-min(length($tmp),32)+7)/8)+1)) . - "# $prompts{$key}\n"; - my $line; - my $last_line_was_empty=0; - foreach $line (split /\n/, $log{$key}) - { - print CONFIG_FILE " ###$line\n" unless - ( ($last_line_was_empty eq 1) && ($line =~ /^\s*$/)); - $last_line_was_empty= ($line =~ /^\s*$/)?1:0; - }; - } - close CONFIG_FILE; -} - -# -# Save 'incomplete' in the limits file to be able to continue if -# crash-me dies because of a bug in perl/DBI - -sub save_incomplete -{ - my ($limit,$prompt)= @_; - save_config_data($limit,"incompleted",$prompt) if ($opt_restart); -} - - -sub check_repeat -{ - my ($sth,$limit)=@_; - my ($row); - - return 0 if (!($row=$sth->fetchrow_arrayref)); - return (defined($row->[0]) && ('a' x $limit) eq $row->[0]) ? 1 : 0; -} - - -sub min -{ - my($min)=$_[0]; - my($i); - for ($i=1 ; $i <= $#_; $i++) - { - $min=$_[$i] if ($min > $_[$i]); - } - return $min; -} - -sub sql_concat -{ - my ($a,$b)= @_; - return "$a || $b" if ($limits{'func_sql_concat_as_||'} eq 'yes'); - return "concat($a,$b)" if ($limits{'func_odbc_concat'} eq 'yes'); - return "$a + $b" if ($limits{'func_extra_concat_as_+'} eq 'yes'); - return undef; -} - -# -# Returns a list of statements to create a table in a portable manner -# but still utilizing features in the databases. -# - -sub create_table -{ - my($table_name,$fields,$index,$extra) = @_; - my($query,$nr,$parts,@queries,@index); - - $extra="" if (!defined($extra)); - - $query="create table $table_name ("; - $nr=0; - foreach $field (@$fields) - { - $query.= $field . ','; - } - foreach $index (@$index) - { - $index =~ /\(([^\(]*)\)$/i; - $parts=$1; - if ($index =~ /^primary key/) - { - if ($limits{'primary_key_in_create'} eq 'yes') - { - $query.= $index . ','; - } - else - { - push(@queries, - "create unique index ${table_name}_prim on $table_name ($parts)"); - } - } - elsif ($index =~ /^unique/) - { - if ($limits{'unique_in_create'} eq 'yes') - { - $query.= "unique ($parts),"; - } - else - { - $nr++; - push(@queries, - "create unique index ${table_name}_$nr on $table_name ($parts)"); - - } - } - else - { - if ($limits{'index_in_create'} eq 'yes') - { - $query.= "index ($parts),"; - } - else - { - $nr++; - push(@queries, - "create index ${table_name}_$nr on $table_name ($1)"); - } - } - } - chop($query); - $query.= ") $extra"; - unshift(@queries,$query); - return @queries; -} - - -# -# This is used by some query packages to change: -# %d -> limit -# %s -> 'a' x limit -# %v -> "1,1,1,1,1" where there are 'limit' number of ones -# %f -> q1,q2,q3.... -# %F -> q1 integer,q2 integer,q3 integer.... - -sub fix_query -{ - my ($query,$limit)=@_; - my ($repeat,$i); - - return $query if !(defined($query)); - $query =~ s/%d/$limit/g; - if ($query =~ /%s/) - { - $repeat= 'a' x $limit; - $query =~ s/%s/$repeat/g; - } - if ($query =~ /%v/) - { - $repeat= '1,' x $limit; - chop($repeat); - $query =~ s/%v/$repeat/g; - } - if ($query =~ /%f/) - { - $repeat=""; - for ($i=1 ; $i <= $limit ; $i++) - { - $repeat.="q$i,"; - } - chop($repeat); - $query =~ s/%f/$repeat/g; - } - if ($query =~ /%F/) - { - $repeat=""; - for ($i=1 ; $i <= $limit ; $i++) - { - $repeat.="q$i integer,"; - } - chop($repeat); - $query =~ s/%F/$repeat/g; - } - return $query; -} - - -# -# Different query packages -# - -package query_repeat; - -sub new -{ - my ($type,$init,$query,$add1,$add_mid,$add,$add_end,$end_query,$cleanup, - $max_limit, $check, $offset)=@_; - my $self={}; - if (defined($init) && $#$init != -1) - { - $self->{'init'}=$init; - } - $self->{'query'}=$query; - $self->{'add1'}=$add1; - $self->{'add_mid'}=$add_mid; - $self->{'add'}=$add; - $self->{'add_end'}=$add_end; - $self->{'end_query'}=$end_query; - $self->{'cleanup'}=$cleanup; - $self->{'max_limit'}=(defined($max_limit) ? $max_limit : $main::query_size); - $self->{'check'}=$check; - $self->{'offset'}=$offset; - $self->{'printf'}= ($add =~ /%d/); - bless $self; -} - -sub query -{ - my ($self,$limit)=@_; - if (!$self->{'printf'}) - { - return $self->{'query'} . ($self->{'add'} x $limit) . - ($self->{'add_end'} x $limit) . $self->{'end_query'}; - } - my ($tmp,$tmp2,$tmp3,$i); - $tmp=$self->{'query'}; - if ($self->{'add1'}) - { - for ($i=0; $i < $limit ; $i++) - { - $tmp3 = $self->{'add1'}; - $tmp3 =~ s/%d/$i/g; - $tmp .= $tmp3; - } - } - $tmp .= " ".$self->{'add_mid'}; - if ($self->{'add'}) - { - for ($i=0; $i < $limit ; $i++) - { - $tmp2 = $self->{'add'}; - $tmp2 =~ s/%d/$i/g; - $tmp .= $tmp2; - } - } - return ($tmp . - ($self->{'add_end'} x $limit) . $self->{'end_query'}); -} - -sub max_limit -{ - my ($self)=@_; - my $tmp; - $tmp=int(($main::limits{"query_size"}-length($self->{'query'}) - -length($self->{'add_mid'})-length($self->{'end_query'}))/ - (length($self->{'add1'})+ - length($self->{'add'})+length($self->{'add_end'}))); - return main::min($self->{'max_limit'},$tmp); -} - - -sub cleanup -{ - my ($self)=@_; - my($tmp,$statement); - $tmp=$self->{'cleanup'}; - foreach $statement (@$tmp) - { - main::safe_query($statement) if (defined($statement) && length($statement)); - } -} - -sub check -{ - my ($self,$sth)=@_; - my $check=$self->{'check'}; - return &$check($sth,$self->{'limit'}) if (defined($check)); - return 1; -} - -sub check_query -{ - return undef; -} - - -package query_num; - -sub new -{ - my ($type,$query,$end_query,$cleanup,$max_limit,$check)=@_; - my $self={}; - $self->{'query'}=$query; - $self->{'end_query'}=$end_query; - $self->{'cleanup'}=$cleanup; - $self->{'max_limit'}=$max_limit; - $self->{'check'}=$check; - bless $self; -} - -sub query -{ - my ($self,$i)=@_; - $self->{'limit'}=$i; - return "$self->{'query'}$i$self->{'end_query'}"; -} - -sub max_limit -{ - my ($self)=@_; - return $self->{'max_limit'}; -} - -sub cleanup -{ - my ($self)=@_; - my($statement); - foreach $statement ($self->{'$cleanup'}) - { - main::safe_query($statement) if (defined($statement) && length($statement)); - } -} - - -sub check -{ - my ($self,$sth)=@_; - my $check=$self->{'check'}; - return &$check($sth,$self->{'limit'}) if (defined($check)); - return 1; -} - -sub check_query -{ - return undef; -} - -# -# This package is used when testing CREATE TABLE! -# - -package query_table; - -sub new -{ - my ($type,$query, $add, $end_query, $extra_init, $safe_query, $check, - $cleanup, $max_limit, $offset)=@_; - my $self={}; - $self->{'query'}=$query; - $self->{'add'}=$add; - $self->{'end_query'}=$end_query; - $self->{'extra_init'}=$extra_init; - $self->{'safe_query'}=$safe_query; - $self->{'check'}=$check; - $self->{'cleanup'}=$cleanup; - $self->{'max_limit'}=$max_limit; - $self->{'offset'}=$offset; - bless $self; -} - - -sub query -{ - my ($self,$limit)=@_; - $self->{'limit'}=$limit; - $self->cleanup(); # Drop table before create - - my ($tmp,$tmp2,$i,$query,@res); - $tmp =$self->{'query'}; - $tmp =~ s/%d/$limit/g; - for ($i=1; $i <= $limit ; $i++) - { - $tmp2 = $self->{'add'}; - $tmp2 =~ s/%d/$i/g; - $tmp .= $tmp2; - } - push(@res,$tmp . $self->{'end_query'}); - $tmp=$self->{'extra_init'}; - foreach $query (@$tmp) - { - push(@res,main::fix_query($query,$limit)); - } - return \@res; -} - - -sub max_limit -{ - my ($self)=@_; - return $self->{'max_limit'}; -} - - -sub check_query -{ - my ($self)=@_; - return main::fix_query($self->{'safe_query'},$self->{'limit'}); -} - -sub check -{ - my ($self,$sth)=@_; - my $check=$self->{'check'}; - return 0 if (!($row=$sth->fetchrow_arrayref)); - if (defined($check)) - { - return (defined($row->[0]) && - $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0; - } - return 1; -} - - -# Remove table before and after create table query - -sub cleanup() -{ - my ($self)=@_; - main::safe_query(main::fix_query($self->{'cleanup'},$self->{'limit'})); -} - -# -# Package to do many queries with %d, and %s substitution -# - -package query_many; - -sub new -{ - my ($type,$query,$safe_query,$check_result,$cleanup,$max_limit,$offset, - $safe_cleanup)=@_; - my $self={}; - $self->{'query'}=$query; - $self->{'safe_query'}=$safe_query; - $self->{'check'}=$check_result; - $self->{'cleanup'}=$cleanup; - $self->{'max_limit'}=$max_limit; - $self->{'offset'}=$offset; - $self->{'safe_cleanup'}=$safe_cleanup; - bless $self; -} - - -sub query -{ - my ($self,$limit)=@_; - my ($queries,$query,@res); - $self->{'limit'}=$limit; - $self->cleanup() if (defined($self->{'safe_cleanup'})); - $queries=$self->{'query'}; - foreach $query (@$queries) - { - push(@res,main::fix_query($query,$limit)); - } - return \@res; -} - -sub check_query -{ - my ($self)=@_; - return main::fix_query($self->{'safe_query'},$self->{'limit'}); -} - -sub cleanup -{ - my ($self)=@_; - my($tmp,$statement); - return if (!defined($self->{'cleanup'})); - $tmp=$self->{'cleanup'}; - foreach $statement (@$tmp) - { - if (defined($statement) && length($statement)) - { - main::safe_query(main::fix_query($statement,$self->{'limit'})); - } - } -} - - -sub check -{ - my ($self,$sth)=@_; - my ($check,$row); - return 0 if (!($row=$sth->fetchrow_arrayref)); - $check=$self->{'check'}; - if (defined($check)) - { - return (defined($row->[0]) && - $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0; - } - return 1; -} - -sub max_limit -{ - my ($self)=@_; - return $self->{'max_limit'}; -} - -# -# Used to find max supported row length -# - -package query_row_length; - -sub new -{ - my ($type,$create,$null,$drop,$max_limit)=@_; - my $self={}; - $self->{'table_name'}=$create; - $self->{'null'}=$null; - $self->{'cleanup'}=$drop; - $self->{'max_limit'}=$max_limit; - bless $self; -} - - -sub query -{ - my ($self,$limit)=@_; - my ($res,$values,$size,$length,$i); - $self->{'limit'}=$limit; - - $res=""; - $size=main::min($main::limits{'max_char_size'},255); - $size = 255 if (!$size); # Safety - for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++) - { - $res.= "q$i char($size) $self->{'null'},"; - $values.="'" . ('a' x $size) . "',"; - } - if ($length < $limit) - { - $size=$limit-$length; - $res.= "q$i char($size) $self->{'null'},"; - $values.="'" . ('a' x $size) . "',"; - } - chop($res); - chop($values); - return ["create table " . $self->{'table_name'} . " ($res)", - "insert into " . $self->{'table_name'} . " values ($values)"]; -} - -sub max_limit -{ - my ($self)=@_; - return $self->{'max_limit'}; -} - -sub cleanup -{ - my ($self)=@_; - main::safe_query($self->{'cleanup'}); -} - - -sub check -{ - return 1; -} - -sub check_query -{ - return undef; -} - -# -# Used to find max supported index length -# - -package query_index_length; - -sub new -{ - my ($type,$create,$drop,$max_limit)=@_; - my $self={}; - $self->{'create'}=$create; - $self->{'cleanup'}=$drop; - $self->{'max_limit'}=$max_limit; - bless $self; -} - - -sub query -{ - my ($self,$limit)=@_; - my ($res,$size,$length,$i,$parts,$values); - $self->{'limit'}=$limit; - - $res=$parts=$values=""; - $size=main::min($main::limits{'max_index_part_length'}, - $main::limits{'max_char_size'}); - $size=1 if ($size == 0); # Avoid infinite loop errors - for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++) - { - $res.= "q$i char($size) not null,"; - $parts.= "q$i,"; - $values.= "'" . ('a' x $size) . "',"; - } - if ($length < $limit) - { - $size=$limit-$length; - $res.= "q$i char($size) not null,"; - $parts.="q$i,"; - $values.= "'" . ('a' x $size) . "',"; - } - chop($parts); - chop($res); - chop($values); - if ($main::limits{'unique_in_create'} eq 'yes') - { - return [$self->{'create'} . "($res,unique ($parts))", - "insert into crash_q values($values)"]; - } - return [$self->{'create'} . "($res)", - "create index crash_q_index on crash_q ($parts)", - "insert into crash_q values($values)"]; -} - -sub max_limit -{ - my ($self)=@_; - return $self->{'max_limit'}; -} - -sub cleanup -{ - my ($self)=@_; - main::safe_query($self->{'cleanup'}); -} - - -sub check -{ - return 1; -} - -sub check_query -{ - return undef; -} - - - -### TODO: -# OID test instead of / in addition to _rowid |