summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql-bench/crash-me.sh284
-rw-r--r--sql-bench/server-cfg.sh215
2 files changed, 475 insertions, 24 deletions
diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh
index d66e8f47d6a..5fa67773566 100644
--- a/sql-bench/crash-me.sh
+++ b/sql-bench/crash-me.sh
@@ -38,7 +38,7 @@
# as such, and clarify ones such as "mediumint" with comments such as
# "3-byte int" or "same as xxx".
-$version="1.58";
+$version="1.59";
use DBI;
use Getopt::Long;
@@ -253,6 +253,9 @@ 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");
@@ -301,6 +304,7 @@ try_and_report("LIMIT number of rows","select_limit",
["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))"))
@@ -434,6 +438,9 @@ 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;
@@ -584,7 +591,7 @@ print "$limits{'query_size'}\n";
"int not null identity,unique(q)",
# postgres types
"box","bool","circle","polygon","point","line","lseg","path",
- "interval", "serial", "inet", "cidr", "macaddr",
+ "interval", "inet", "cidr", "macaddr",
# oracle types
"varchar2(16)","nvarchar2(16)","number(9,2)","number(9)",
@@ -769,7 +776,6 @@ try_and_report("Automatic row id", "automatic_rowid",
["CURRENT_DATE","current_date","current_date",0,2],
["CURRENT_TIME","current_time","current_time",0,2],
["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2],
- ["CURRENT_USER","current_user","current_user",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],
@@ -778,11 +784,8 @@ try_and_report("Automatic row id", "automatic_rowid",
["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],
- ["SESSION_USER","session_user","session_user",0,2],
- ["SYSTEM_USER","system_user","system_user",0,2],
["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",3],
["UPPER","upper","UPPER('abc')","ABC",1],
- ["USER","user","user"],
["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1],
);
@@ -960,8 +963,61 @@ try_and_report("Automatic row id", "automatic_rowid",
["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],
+ ["SAPDB compatible TRIM (1 arg)",'trim1arg',"trim(' abcd ')",'abcd',1],
+ ["SAPDB compatible 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],
+ ["NOROUND",'noround',"noround(222.6)",222.6,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],
+ ["ADDDATE",'adddate',"ADDDATE('20021201',3)",'20021204',0],
+ ["SUBDATE",'subdate',"SUBDATE('20021204',3)",'20021201',0],
+ ["DATEDIFF (2 arg)",'datediff2arg',"DATEDIFF('20021204','20021201')",'3',0], # sapdb
+ ["DAYOFWEEK with sapdb internal date as arg",'dayofweek_sapdb',"DAYOFWEEK('19630816')",'5',0],
+ ["WEEKOFYEAR",'weekofyear',"WEEKOFYEAR('19630816')",'33',0],
+ ["DAYOFMONTH with sapdb internal date as arg",'dayofmonth_sapdb',"dayofmonth('19630816')",'16',0],
+ ["DAYOFYEAR with sapdb internal date as arg",'dayofyear_sapdb',"DAYOFYEAR('19630816')",'228',0],
+ ["MAKEDATE",'makedate',"MAKEDATE(1963,228)",'19630816',0],
+ ["DAYNAME with sapdb internal date as arg",'dayname_sapdb',"DAYNAME('19630816')",'Friday',0],
+ ["MONTHNAME with sapdb internal date as arg",'monthname_sapdb',"MONTHNAME('19630816')",'August',0],
+ ["ADDTIME",'addtime',"ADDTIME('00200212','00000300')",'00200215',0],
+ ["SUBTIME",'subdate',"SUBDATE('00200215','00000300')",'00200212',0],
+ ["TIMEDIFF",'timediff',"TIMEDIFF('00200215','00200212')",'00000003',0],
+ ["MAKETIME",'maketime',"MAKETIME(20,02,12)",'00200212',0],
+ ["YEAR with sapdb internal date as arg",'year_sapdb',"YEAR('20021201')",'2002',0],
+ ["MONTH with sapdb internal date as arg",'month_sapdb',"MONTH('20021201')",'12',0],
+ ["DAY",'day',"DAY('20021201')",1,0],
+ ["HOUR with sapdb internal time as arg",'hour_sapdb',"HOUR('00200212')",20,0],
+ ["MINUTE with sapdb internal time as arg",'minute_sapdb',"MINUTE('00200212')",2,0],
+ ["SECOND with sapdb internal time as arg",'second_sapdb',"SECOND('00200212')",12,0],
+ ["MICROSECOND",'microsecond',"MICROSECOND('19630816200212111111')",'111111',0],
+ ["TIMESTAMP",'timestamp',"timestamp('19630816','00200212')",'19630816200212000000',0],
+ ["TIME",'time',"time('00200212')",'00200212',0],
+ ["DATE",'date',"date('19630816')",'19630816',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],
+ ["CHAR (conversation date)",'char_date',"CHAR(DATE('19630816'),EUR)",'16.08.1963',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],
@@ -1131,6 +1187,20 @@ else
}
+if ($limits{'func_extra_noround'} eq 'yes')
+{
+ report("Ignoring NOROUND","ignoring_noround",
+ "create table crash_q (a int)",
+ "insert into crash_q values(noround(10.22))",
+ "drop table crash_q $drop_attr");
+}
+
+check_parenthesis("func_sql_","CURRENT_USER");
+check_parenthesis("func_sql_","SESSION_USER");
+check_parenthesis("func_sql_","SYSTEM_USER");
+check_parenthesis("func_sql_","USER");
+
+
report("LIKE on numbers","like_with_number",
"create table crash_q (a int,b int)",
"insert into crash_q values(10,10)",
@@ -1561,19 +1631,29 @@ 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});
- last if (!report_trans($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",
@@ -1644,14 +1724,29 @@ report("Column constraints","constraint_check",
"create table crash_q (a int check (a>0))",
"drop table crash_q $drop_attr");
+report("Ignoring column constraints","ignoring_constraint_check",
+ "create table crash_q (a int check (a>0))",
+ "insert into crash_q values(0)",
+ "drop table crash_q $drop_attr") if ($limits{'constraint_check'} eq 'yes');
+
report("Table constraints","constraint_check_table",
"create table crash_q (a int ,b int, check (a>b))",
"drop table crash_q $drop_attr");
-report("Named constraints","constraint_check",
+report("Ignoring table constraints","ignoring_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") if ($limits{'constraint_check_table'} eq 'yes');
+
+report("Named constraints","constraint_check_named",
"create table crash_q (a int ,b int, constraint abc check (a>b))",
"drop table crash_q $drop_attr");
+report("Ignoring named constraints","ignoring_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") if ($limits{'constraint_check_named'} eq 'yes');
+
report("NULL constraint (SyBase style)","constraint_null",
"create table crash_q (a int null)",
"drop table crash_q $drop_attr");
@@ -2009,6 +2104,90 @@ find_limit("number of columns in group by","columns_in_group_by",
["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($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(["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('select count(*) from crash_me_a where a+b=30.3',1,0) == 0)
+ and (safe_query_result('select count(*) from crash_me_a where a+b-30.3 = 0',1,0) == 0)
+ and (safe_query_result('select count(*) from crash_me_a where a+b-30.3 < 0',0,0) == 0)
+ and (safe_query_result('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";
+ };
+assert("insert into crash_me_n (i) values(1)");
+assert("insert into crash_me_n values(2,2)");
+assert("insert into crash_me_n values(3,3)");
+assert("insert into crash_me_n values(4,4)");
+assert("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;
+ $limit= detect_null_position($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;
+ $limit= detect_null_position($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");
+
+
#
# End of test
#
@@ -2022,6 +2201,41 @@ $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 $sth = shift;
+ my ($z,$r1,$r2,$r3,$r4,$r5);
+ $r1 = $sth->fetchrow_array;
+ $r2 = $sth->fetchrow_array;
+ $r3 = $sth->fetchrow_array;
+ $r4 = $sth->fetchrow_array;
+ $r5 = $sth->fetchrow_array;
+ 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 $resultat='no';
+ my $param_name=$prefix.lc($fn);
+
+ save_incomplete($param_name,$fn);
+ if (safe_query("select $fn $end_query") == 1)
+ {
+ $resultat="yes";
+ }
+ elsif ( safe_query("select $fn() $end_query") == 1)
+ {
+ $resultat="with_parenthesis";
+ }
+ save_config_data($param_name,$resultat,$fn);
+}
+
sub usage
{
print <<EOF;
@@ -2524,10 +2738,10 @@ sub report_result
{
save_incomplete($limit,$prompt);
$error=safe_query_result($query,"1",2);
- save_config_data($limit,$error ? "not supported" : $last_result,$prompt);
+ save_config_data($limit,$error ? "not supported" :$last_result,$prompt);
}
print "$limits{$limit}\n";
- return $limits{$limit} ne "no";
+ return $limits{$limit} ne "not supported";
}
sub report_trans
@@ -2541,17 +2755,12 @@ sub report_trans
{
if (safe_query(\@$queries))
{
- $rc = $dbh->rollback;
- if ($rc) {
- $dbh->{AutoCommit} = 1;
+ $dbh->rollback;
+ $dbh->{AutoCommit} = 1;
if (safe_query_result($check,"","")) {
save_config_data($limit,"yes",$limit);
}
safe_query($clear);
- } else {
- $dbh->{AutoCommit} = 1;
- save_config_data($limit,"error",$limit);
- }
} else {
save_config_data($limit,"error",$limit);
}
@@ -2566,6 +2775,39 @@ sub report_trans
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))
+ {
+ $dbh->rollback;
+ $dbh->{AutoCommit} = 1;
+ if (safe_query($check)) {
+ save_config_data($limit,"no",$limit);
+ } else {
+ save_config_data($limit,"yes",$limit);
+ };
+ safe_query($clear);
+ } else {
+ save_config_data($limit,"error",$limit);
+ }
+ }
+ else
+ {
+ save_config_data($limit,"error",$limit);
+ }
+ safe_query($clear);
+ }
+ $dbh->{AutoCommit} = 1;
+ return $limits{$limit} ne "yes";
+}
+
sub check_and_report
{
@@ -2892,7 +3134,7 @@ sub read_config_data
{
if ($key !~ /restart/i)
{
- $limits{$key}=$limit;
+ $limits{$key}=$limit eq "null"? undef : $limit;
$prompts{$key}=length($prompt) ? substr($prompt,2) : "";
delete $limits{'restart'};
}
@@ -2922,7 +3164,8 @@ sub save_config_data
return if (defined($limits{$key}) && $limits{$key} eq $limit);
if (!defined($limit) || $limit eq "")
{
- die "Undefined limit for $key\n";
+# die "Undefined limit for $key\n";
+ $limit = 'null';
}
print CONFIG_FILE "$key=$limit\t# $prompt\n";
$limits{$key}=$limit;
@@ -3576,5 +3819,6 @@ sub check_query
}
+
### TODO:
# OID test instead of / in addition to _rowid
diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh
index e53190a75ec..213ecacea6f 100644
--- a/sql-bench/server-cfg.sh
+++ b/sql-bench/server-cfg.sh
@@ -69,11 +69,13 @@ sub get_server
{ $server= new db_db2($host,$database); }
elsif ($name =~ /Mimer/i)
{ $server= new db_Mimer($host,$database); }
+ elsif ($name =~ /Sapdb/i)
+ { $server= new db_sapdb($host,$database); }
elsif ($name =~ /interBase/i)
{ $server= new db_interbase($host,$database); }
else
{
- die "Unknown sql server name used: $name\nUse one of: Access, Adabas, AdabasD, Empress, FrontBase, Oracle, Informix, InterBase, DB2, mSQL, Mimer, MS-SQL, MySQL, Pg, Solid or Sybase.\nIf the connection is done trough ODBC the name must end with _ODBC\n";
+ die "Unknown sql server name used: $name\nUse one of: Access, Adabas, AdabasD, Empress, FrontBase, Oracle, Informix, InterBase, DB2, mSQL, Mimer, MS-SQL, MySQL, Pg, Solid, SAPDB or Sybase.\nIf the connection is done trough ODBC the name must end with _ODBC\n";
}
if ($name =~ /_ODBC$/i || defined($odbc) && $odbc)
{
@@ -94,7 +96,7 @@ sub get_server
sub all_servers
{
return ["Access", "Adabas", "DB2", "Empress", "FrontBase", "Oracle",
- "Informix", "InterBase", "Mimer", "mSQL", "MS-SQL", "MySQL", "Pg",
+ "Informix", "InterBase", "Mimer", "mSQL", "MS-SQL", "MySQL", "Pg","SAPDB",
"Solid", "Sybase"];
}
@@ -116,7 +118,6 @@ sub new
$self->{'data_source'} .= ";mysql_socket=$socket" if($socket);
$self->{'data_source'} .= ";$connect_options" if($connect_options);
$self->{'limits'} = \%limits;
- $self->{'smds'} = \%smds;
$self->{'blob'} = "blob";
$self->{'text'} = "text";
$self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
@@ -178,7 +179,6 @@ sub new
if (defined($main::opt_create_options) &&
$main::opt_create_options =~ /type=innodb/i)
{
- $limits{'max_text_size'} = 8000; # Limit in Innobase
$self->{'transactions'} = 1; # Transactions enabled
}
if (defined($main::opt_create_options) &&
@@ -3361,4 +3361,211 @@ sub fix_for_insert
return $cmd;
}
+#############################################################################
+# Configuration for SAPDB
+#############################################################################
+
+package db_Sapdb;
+
+sub new
+{
+ my ($type,$host,$database)= @_;
+ my $self= {};
+ my %limits;
+ bless $self;
+
+ $self->{'cmp_name'} = "sapdb";
+ $self->{'data_source'} = "DBI:SAP_DB:$database";
+ $self->{'limits'} = \%limits;
+ $self->{'blob'} = "LONG"; # *
+ $self->{'text'} = "LONG"; # *
+ $self->{'double_quotes'} = 1; # Can handle: 'Walker''s'
+ $self->{'drop_attr'} = "";
+ $self->{'transactions'} = 1; # Transactions enabled *
+ $self->{'char_null'} = "";
+ $self->{'numeric_null'} = "";
+
+ $limits{'max_conditions'} = 9999; # (Actually not a limit) *
+ $limits{'max_columns'} = 1023; # Max number of columns in table *
+ $limits{'max_tables'} = 65000; # Should be big enough * unlimited actually
+ $limits{'max_text_size'} = 15000; # Max size with default buffers.
+ $limits{'query_size'} = 64*1024; # Max size with default buffers. *64 kb by default. May be set by system variable
+ $limits{'max_index'} = 510; # Max number of keys *
+ $limits{'max_index_parts'} = 16; # Max segments/key *
+ $limits{'max_column_name'} = 32; # max table and column name *
+
+ $limits{'join_optimizer'} = 1; # Can optimize FROM tables *
+ $limits{'load_data_infile'} = 0; # Has load data infile *
+ $limits{'lock_tables'} = 1; # Has lock tables
+ $limits{'functions'} = 1; # Has simple functions (+/-) *
+ $limits{'group_functions'} = 1; # Have group functions *
+ $limits{'group_func_sql_min_str'} = 1; # Can execute MIN() and MAX() on strings *
+ $limits{'group_distinct_functions'}= 1; # Have count(distinct) *
+ $limits{'select_without_from'}= 0; # Cannot do 'select 1'; *
+ $limits{'multi_drop'} = 0; # Drop table cannot take many tables *
+ $limits{'subqueries'} = 1; # Supports sub-queries. *
+ $limits{'left_outer_join'} = 1; # Supports left outer joins *
+ $limits{'table_wildcard'} = 1; # Has SELECT table_name.*
+ $limits{'having_with_alias'} = 0; # Can use aliases in HAVING *
+ $limits{'having_with_group'} = 1; # Can use group functions in HAVING *
+ $limits{'like_with_column'} = 1; # Can use column1 LIKE column2 *
+ $limits{'order_by_position'} = 1; # Can use 'ORDER BY 1' *
+ $limits{'group_by_position'} = 0; # Cannot use 'GROUP BY 1' *
+ $limits{'alter_table'} = 1; # Have ALTER TABLE *
+ $limits{'alter_add_multi_col'}= 1; # Have ALTER TABLE t add a int,add b int; *
+ $limits{'alter_table_dropcol'}= 1; # Have ALTER TABLE DROP column *
+ $limits{'insert_multi_value'} = 0; # INSERT ... values (1,2),(3,4) *
+
+ $limits{'group_func_extra_std'} = 0; # Does not have group function std().
+
+ $limits{'func_odbc_mod'} = 0; # Have function mod. *
+ $limits{'func_extra_%'} = 0; # Does not have % as alias for mod() *
+ $limits{'func_odbc_floor'} = 1; # Has func_odbc_floor function *
+ $limits{'func_extra_if'} = 0; # Does not have function if. *
+ $limits{'column_alias'} = 1; # Alias for fields in select statement. *
+ $limits{'NEG'} = 1; # Supports -id *
+ $limits{'func_extra_in_num'} = 0; # Has function in *
+ $limits{'limit'} = 0; # Does not support the limit attribute *
+ $limits{'working_blobs'} = 1; # If big varchar/blobs works *
+ $limits{'order_by_unused'} = 1; #
+ $limits{'working_all_fields'} = 1; #
+
+
+ return $self;
+}
+
+#
+# Get the version number of the database
+#
+
+sub version
+{
+ my ($self)=@_;
+ my ($dbh,$sth,$version,@row);
+
+ $dbh=$self->connect();
+ $sth = $dbh->prepare("SELECT KERNEL FROM VERSIONS") or die $DBI::errstr;
+ $version="SAP DB (unknown)";
+ if ($sth->execute && (@row = $sth->fetchrow_array)
+ && $row[0] =~ /([\d\.]+)/)
+ {
+ $version="sap-db $1";
+ }
+ $sth->finish;
+ $dbh->disconnect;
+ return $version;
+}
+
+#
+# Connection with optional disabling of logging
+#
+
+sub connect
+{
+ my ($self)=@_;
+ my ($dbh);
+ $dbh=DBI->connect($self->{'data_source'}, $main::opt_user,
+ $main::opt_password,{ PrintError => 0, AutoCommit => 1}) ||
+ die "Got error: '$DBI::errstr' when connecting to " . $self->{'data_source'} ." with user: '$main::opt_user' password: '$main::opt_password'\n";
+
+ return $dbh;
+}
+
+#
+# Returns a list of statements to create a table
+# The field types are in ANSI SQL format.
+#
+
+sub create
+{
+ my($self,$table_name,$fields,$index,$options) = @_;
+ my($query,@queries,$nr);
+ my @index;
+ my @keys;
+
+ $query="create table $table_name (";
+ foreach $field (@$fields)
+ {
+ $field =~ s/\bmediumint\b/int/i;
+ $field =~ s/\btinyint\b/int/i;
+ $field =~ s/ int\(\d\)/ int/i;
+ $field =~ s/BLOB/LONG/i;
+ $field =~ s/INTEGER\s*\(\d+\)/INTEGER/i;
+ $field =~ s/SMALLINT\s*\(\d+\)/SMALLINT/i;
+ $field =~ s/FLOAT\s*\((\d+),\d+\)/FLOAT\($1\)/i;
+ $field =~ s/DOUBLE/FLOAT\(38\)/i;
+ $field =~ s/DOUBLE\s+PRECISION/FLOAT\(38\)/i;
+ $query.= $field . ',';
+ }
+ $nr=0;
+ foreach $ind (@$index)
+ {
+ if ( $ind =~ /\bKEY\b/i ){
+ push(@keys,"ALTER TABLE $table_name ADD $ind");
+ } elsif ($ind =~ /^unique.*\(([^\(]*)\)$/i) {
+ $nr++;
+ my $query="create unique index ${table_name}_$nr on $table_name ($1)";
+ push(@index,$query);
+ }else{
+ my @fields = split(' ',$ind);
+ my $query="CREATE INDEX $fields[1] ON $table_name $fields[2]";
+ print "$query \n";
+ push(@index,$query);
+ }
+ }
+ substr($query,-1)=")"; # Remove last ',';
+ $query.=" $options" if (defined($options));
+ push(@queries,$query);
+ push(@queries,@keys);
+ push(@queries,@index);
+ return @queries;
+}
+
+sub insert_file {
+ my($self,$dbname, $file) = @_;
+ print "insert of an ascii file isn't supported by SAPDB\n";
+ return 0;
+}
+
+#
+# Do any conversions to the ANSI SQL query so that the database can handle it
+#
+
+sub query {
+ my($self,$sql) = @_;
+ return $sql;
+}
+
+sub drop_index {
+ my ($self,$table,$index) = @_;
+ return "DROP INDEX $index";
+}
+
+#
+# Abort if the server has crashed
+# return: 0 if ok
+# 1 question should be retried
+#
+
+sub abort_if_fatal_error
+{
+ return 0;
+}
+
+sub small_rollback_segment
+{
+ return 0;
+}
+
+sub reconnect_on_errors
+{
+ return 0;
+}
+
+sub fix_for_insert
+{
+ my ($self,$cmd) = @_;
+ return $cmd;
+}
+
1;