diff options
author | Michael Widenius <monty@askmonty.org> | 2009-04-09 00:16:10 +0300 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2009-04-09 00:16:10 +0300 |
commit | 7e44eb89a0eef0200449d11af73def41c6fa817b (patch) | |
tree | 882c1d0bb907dd8ea20711e33fd65aef1a1035e2 | |
parent | b09c0acd4ef124c33111c48a76be987500ff39f9 (diff) | |
parent | 83290da1e6b553d69711d7eb4e302aaeb608f362 (diff) | |
download | mariadb-git-7e44eb89a0eef0200449d11af73def41c6fa817b.tar.gz |
Merge with Trunk
436 files changed, 164860 insertions, 390 deletions
diff --git a/dbug/dbug.c b/dbug/dbug.c index 79d58d715f8..dc92aa3d768 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -506,6 +506,9 @@ int DbugParse(CODE_STATE *cs, const char *control) rel= control[0] == '+' || control[0] == '-'; if ((!rel || (!stack->out_file && !stack->next))) { + /* If overwriting previous state, be sure to free old to avoid leak. */ + if (stack->out_file) + FreeState(cs, stack, 0); stack->flags= 0; stack->delay= 0; stack->maxdepth= 0; @@ -1648,10 +1651,12 @@ static void FreeState(CODE_STATE *cs, struct settings *state, int free_state) FreeList(state->processes); if (!is_shared(state, p_functions)) FreeList(state->p_functions); - if (!is_shared(state, out_file)) + if (!is_shared(state, out_file) && + state->out_file != stderr && state->out_file != stdout) DBUGCloseFile(cs, state->out_file); (void) fflush(cs->stack->out_file); - if (state->prof_file) + if (state->prof_file && + state->prof_file != stderr && state->prof_file != stdout) DBUGCloseFile(cs, state->prof_file); if (free_state) free((void*) state); diff --git a/include/my_global.h b/include/my_global.h index 554b26a1602..37bcab244ff 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -569,6 +569,12 @@ int __void__; #define PURIFY_OR_LINT_INIT(var) #endif +#ifdef HAVE_purify +#define IF_PURIFY(A,B) (A) +#else +#define IF_PURIFY(A,B) (B) +#endif + #if !defined(HAVE_UINT) #undef HAVE_UINT #define HAVE_UINT diff --git a/mysql-test/extra/rpl_tests/rpl_auto_increment.test b/mysql-test/extra/rpl_tests/rpl_auto_increment.test index 24448a38408..4bcb10c165e 100644 --- a/mysql-test/extra/rpl_tests/rpl_auto_increment.test +++ b/mysql-test/extra/rpl_tests/rpl_auto_increment.test @@ -34,7 +34,7 @@ connection master; drop table t1; set @@session.auto_increment_increment=100, @@session.auto_increment_offset=10; -show variables like "%auto_inc%"; +show variables like "auto_inc%"; eval create table t1 (a int not null auto_increment, primary key (a)) engine=$engine_type2; # Insert with 2 insert statements to get better testing of logging diff --git a/mysql-test/include/have_pbxt.inc b/mysql-test/include/have_pbxt.inc new file mode 100644 index 00000000000..a8afc2c8324 --- /dev/null +++ b/mysql-test/include/have_pbxt.inc @@ -0,0 +1,4 @@ +disable_query_log; +--require r/true.require +select (support = 'YES' or support = 'DEFAULT') as `TRUE` from information_schema.engines where engine = 'pbxt'; +enable_query_log; diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm index 2e8d4715098..04a3aeeef7f 100644 --- a/mysql-test/lib/mtr_report.pm +++ b/mysql-test/lib/mtr_report.pm @@ -187,8 +187,10 @@ sub mtr_report_test ($) { } -sub mtr_report_stats ($) { +sub mtr_report_stats ($$$) { + my $fail= shift; my $tests= shift; + my $extra_warnings= shift; # ---------------------------------------------------------------------- # Find out how we where doing @@ -325,10 +327,27 @@ sub mtr_report_stats ($) { print "All $tot_tests tests were successful.\n\n"; } + if (@$extra_warnings) + { + print <<MSG; +Errors/warnings were found in logfiles during server shutdown after running the +following sequence(s) of tests: +MSG + print " $_\n" for @$extra_warnings; + } + if ( $tot_failed != 0 || $found_problems) { mtr_error("there were failing test cases"); } + elsif (@$extra_warnings) + { + mtr_error("There were errors/warnings in server logs after running test cases."); + } + elsif ($fail) + { + mtr_error("Test suite failure, see messages above for possible cause(s)."); + } } diff --git a/mysql-test/lib/mtr_unique.pm b/mysql-test/lib/mtr_unique.pm index b4093ab1dce..49d1598a562 100644 --- a/mysql-test/lib/mtr_unique.pm +++ b/mysql-test/lib/mtr_unique.pm @@ -62,13 +62,14 @@ sub mtr_get_unique_id($$) { die 'lock file is a symbolic link'; } - chmod 0777, "$file.sem"; open SEM, ">", "$file.sem" or die "can't write to $file.sem"; + chmod 0777, "$file.sem"; flock SEM, LOCK_EX or die "can't lock $file.sem"; if(! -e $file) { open FILE, ">", $file or die "can't create $file"; close FILE; } + chmod 0777, $file; msg("HAVE THE LOCK"); @@ -76,7 +77,6 @@ sub mtr_get_unique_id($$) { die 'lock file is a symbolic link'; } - chmod 0777, $file; open FILE, "+<", $file or die "can't open $file"; #select undef,undef,undef,0.2; seek FILE, 0, 0; @@ -136,6 +136,7 @@ sub mtr_release_unique_id($) { } open SEM, ">", "$file.sem" or die "can't write to $file.sem"; + chmod 0777, "$file.sem"; flock SEM, LOCK_EX or die "can't lock $file.sem"; msg("HAVE THE LOCK"); @@ -148,6 +149,7 @@ sub mtr_release_unique_id($) { open FILE, ">", $file or die "can't create $file"; close FILE; } + chmod 0777, "$file.sem"; open FILE, "+<", $file or die "can't open $file"; #select undef,undef,undef,0.2; seek FILE, 0, 0; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7d5b5ee17b2..ca317d79f13 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -357,7 +357,8 @@ sub main { mtr_print_thick_line(); mtr_print_header(); - my ($completed, $fail)= run_test_server($server, $tests, $opt_parallel); + my ($fail, $completed, $extra_warnings)= + run_test_server($server, $tests, $opt_parallel); # Send Ctrl-C to any children still running kill("INT", keys(%children)); @@ -393,10 +394,6 @@ sub main { mtr_error("Not all tests completed"); } - if ($fail) { - mtr_error("Test suite failure."); - } - mtr_print_line(); if ( $opt_gcov ) { @@ -404,7 +401,7 @@ sub main { $opt_gcov_msg, $opt_gcov_err); } - mtr_report_stats($completed); + mtr_report_stats($fail, $completed, $extra_warnings); exit(0); } @@ -416,7 +413,8 @@ sub run_test_server ($$$) { my $num_saved_cores= 0; # Number of core files saved in vardir/log/ so far. my $num_saved_datadir= 0; # Number of datadirs saved in vardir/log/ so far. my $num_failed_test= 0; # Number of tests failed so far - my $test_failure= 0; + my $test_failure= 0; # Set true if test suite failed + my $extra_warnings= []; # Warnings found during server shutdowns # Scheduler variables my $max_ndb= $childs / 2; @@ -450,7 +448,7 @@ sub run_test_server ($$$) { $s->remove($sock); if (--$childs == 0){ $suite_timeout_proc->kill(); - return ($completed, $test_failure); + return ($test_failure, $completed, $extra_warnings); } next; } @@ -519,14 +517,14 @@ sub run_test_server ($$$) { # Test has failed, force is off $suite_timeout_proc->kill(); push(@$completed, $result); - return ($completed, 1); + return (1, $completed, $extra_warnings); } elsif ($opt_max_test_fail > 0 and $num_failed_test >= $opt_max_test_fail) { $suite_timeout_proc->kill(); mtr_report("Too many tests($num_failed_test) failed!", "Terminating..."); - return (undef, 1); + return (1, $completed, $extra_warnings); } $num_failed_test++; } @@ -580,13 +578,14 @@ sub run_test_server ($$$) { elsif ($line eq 'WARNINGS'){ my $fake_test= My::Test::read_test($sock); my $test_list= join (" ", @{$fake_test->{testnames}}); + push @$extra_warnings, $test_list; mtr_report("***Warnings generated in error logs during shutdown ". "after running tests: $test_list"); $test_failure= 1; if ( !$opt_force ) { # Test failure due to warnings, force is off $suite_timeout_proc->kill(); - return ($completed, 1); + return (1, $completed, $extra_warnings); } } else { mtr_error("Unknown response: '$line' from client"); @@ -666,7 +665,7 @@ sub run_test_server ($$$) { if ( ! $suite_timeout_proc->wait_one(0) ) { mtr_report("Test suite timeout! Terminating..."); - return (undef, 1); + return (1, $completed, $extra_warnings); } } } @@ -758,7 +757,9 @@ sub run_worker ($) { } } - die "Internal error: should not reach this place."; + stop_all_servers(); + + exit(1); } diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 6320b6d7ad3..4b102ec85dc 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -40,7 +40,8 @@ create view v1 (c) as SELECT table_name FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND -table_name<>'ndb_apply_status'; +table_name<>'ndb_apply_status' AND +NOT (table_schema = 'INFORMATION_SCHEMA' AND table_name LIKE 'PBXT_%'); select * from v1; c CHARACTER_SETS @@ -850,10 +851,6 @@ VIEWS TABLE_NAME select delete from mysql.user where user='mysqltest_4'; delete from mysql.db where user='mysqltest_4'; flush privileges; -SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; -table_schema count(*) -information_schema 28 -mysql 22 create table t1 (i int, j int); create trigger trg1 before insert on t1 for each row begin @@ -1224,92 +1221,6 @@ f1() DROP FUNCTION f1; DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; -SELECT t.table_name, c1.column_name -FROM information_schema.tables t -INNER JOIN -information_schema.columns c1 -ON t.table_schema = c1.table_schema AND -t.table_name = c1.table_name -WHERE t.table_schema = 'information_schema' AND -c1.ordinal_position = -( SELECT COALESCE(MIN(c2.ordinal_position),1) -FROM information_schema.columns c2 -WHERE c2.table_schema = t.table_schema AND -c2.table_name = t.table_name AND -c2.column_name LIKE '%SCHEMA%' - ); -table_name column_name -CHARACTER_SETS CHARACTER_SET_NAME -COLLATIONS COLLATION_NAME -COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME -COLUMNS TABLE_SCHEMA -COLUMN_PRIVILEGES TABLE_SCHEMA -ENGINES ENGINE -EVENTS EVENT_SCHEMA -FILES TABLE_SCHEMA -GLOBAL_STATUS VARIABLE_NAME -GLOBAL_VARIABLES VARIABLE_NAME -KEY_COLUMN_USAGE CONSTRAINT_SCHEMA -PARTITIONS TABLE_SCHEMA -PLUGINS PLUGIN_NAME -PROCESSLIST ID -PROFILING QUERY_ID -REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA -ROUTINES ROUTINE_SCHEMA -SCHEMATA SCHEMA_NAME -SCHEMA_PRIVILEGES TABLE_SCHEMA -SESSION_STATUS VARIABLE_NAME -SESSION_VARIABLES VARIABLE_NAME -STATISTICS TABLE_SCHEMA -TABLES TABLE_SCHEMA -TABLE_CONSTRAINTS CONSTRAINT_SCHEMA -TABLE_PRIVILEGES TABLE_SCHEMA -TRIGGERS TRIGGER_SCHEMA -USER_PRIVILEGES GRANTEE -VIEWS TABLE_SCHEMA -SELECT t.table_name, c1.column_name -FROM information_schema.tables t -INNER JOIN -information_schema.columns c1 -ON t.table_schema = c1.table_schema AND -t.table_name = c1.table_name -WHERE t.table_schema = 'information_schema' AND -c1.ordinal_position = -( SELECT COALESCE(MIN(c2.ordinal_position),1) -FROM information_schema.columns c2 -WHERE c2.table_schema = 'information_schema' AND -c2.table_name = t.table_name AND -c2.column_name LIKE '%SCHEMA%' - ); -table_name column_name -CHARACTER_SETS CHARACTER_SET_NAME -COLLATIONS COLLATION_NAME -COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME -COLUMNS TABLE_SCHEMA -COLUMN_PRIVILEGES TABLE_SCHEMA -ENGINES ENGINE -EVENTS EVENT_SCHEMA -FILES TABLE_SCHEMA -GLOBAL_STATUS VARIABLE_NAME -GLOBAL_VARIABLES VARIABLE_NAME -KEY_COLUMN_USAGE CONSTRAINT_SCHEMA -PARTITIONS TABLE_SCHEMA -PLUGINS PLUGIN_NAME -PROCESSLIST ID -PROFILING QUERY_ID -REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA -ROUTINES ROUTINE_SCHEMA -SCHEMATA SCHEMA_NAME -SCHEMA_PRIVILEGES TABLE_SCHEMA -SESSION_STATUS VARIABLE_NAME -SESSION_VARIABLES VARIABLE_NAME -STATISTICS TABLE_SCHEMA -TABLES TABLE_SCHEMA -TABLE_CONSTRAINTS CONSTRAINT_SCHEMA -TABLE_PRIVILEGES TABLE_SCHEMA -TRIGGERS TRIGGER_SCHEMA -USER_PRIVILEGES GRANTEE -VIEWS TABLE_SCHEMA SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test'); MAX(table_name) VIEWS @@ -1355,55 +1266,6 @@ table_name t1 t2 drop table t1,t2; -select 1 as f1 from information_schema.tables where "CHARACTER_SETS"= -(select cast(table_name as char) from information_schema.tables -order by table_name limit 1) limit 1; -f1 -1 -select t.table_name, group_concat(t.table_schema, '.', t.table_name), -count(*) as num1 -from information_schema.tables t -inner join information_schema.columns c1 -on t.table_schema = c1.table_schema AND t.table_name = c1.table_name -where t.table_schema = 'information_schema' and -c1.ordinal_position = -(select isnull(c2.column_type) - -isnull(group_concat(c2.table_schema, '.', c2.table_name)) + -count(*) as num -from information_schema.columns c2 where -c2.table_schema='information_schema' and -(c2.column_type = 'varchar(7)' or c2.column_type = 'varchar(20)') -group by c2.column_type order by num limit 1) -group by t.table_name order by num1, t.table_name; -table_name group_concat(t.table_schema, '.', t.table_name) num1 -CHARACTER_SETS information_schema.CHARACTER_SETS 1 -COLLATIONS information_schema.COLLATIONS 1 -COLLATION_CHARACTER_SET_APPLICABILITY information_schema.COLLATION_CHARACTER_SET_APPLICABILITY 1 -COLUMNS information_schema.COLUMNS 1 -COLUMN_PRIVILEGES information_schema.COLUMN_PRIVILEGES 1 -ENGINES information_schema.ENGINES 1 -EVENTS information_schema.EVENTS 1 -FILES information_schema.FILES 1 -GLOBAL_STATUS information_schema.GLOBAL_STATUS 1 -GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1 -KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1 -PARTITIONS information_schema.PARTITIONS 1 -PLUGINS information_schema.PLUGINS 1 -PROCESSLIST information_schema.PROCESSLIST 1 -PROFILING information_schema.PROFILING 1 -REFERENTIAL_CONSTRAINTS information_schema.REFERENTIAL_CONSTRAINTS 1 -ROUTINES information_schema.ROUTINES 1 -SCHEMATA information_schema.SCHEMATA 1 -SCHEMA_PRIVILEGES information_schema.SCHEMA_PRIVILEGES 1 -SESSION_STATUS information_schema.SESSION_STATUS 1 -SESSION_VARIABLES information_schema.SESSION_VARIABLES 1 -STATISTICS information_schema.STATISTICS 1 -TABLES information_schema.TABLES 1 -TABLE_CONSTRAINTS information_schema.TABLE_CONSTRAINTS 1 -TABLE_PRIVILEGES information_schema.TABLE_PRIVILEGES 1 -TRIGGERS information_schema.TRIGGERS 1 -USER_PRIVILEGES information_schema.USER_PRIVILEGES 1 -VIEWS information_schema.VIEWS 1 create table t1(f1 int); create view v1 as select f1+1 as a from t1; create table t2 (f1 int, f2 int); diff --git a/mysql-test/r/information_schema_all_engines.result b/mysql-test/r/information_schema_all_engines.result new file mode 100644 index 00000000000..4ffaa12fd61 --- /dev/null +++ b/mysql-test/r/information_schema_all_engines.result @@ -0,0 +1,248 @@ +use INFORMATION_SCHEMA; +show tables; +Tables_in_information_schema +CHARACTER_SETS +COLLATIONS +COLLATION_CHARACTER_SET_APPLICABILITY +COLUMNS +COLUMN_PRIVILEGES +ENGINES +EVENTS +FILES +GLOBAL_STATUS +GLOBAL_VARIABLES +KEY_COLUMN_USAGE +PARTITIONS +PLUGINS +PROCESSLIST +PROFILING +REFERENTIAL_CONSTRAINTS +ROUTINES +SCHEMATA +SCHEMA_PRIVILEGES +SESSION_STATUS +SESSION_VARIABLES +STATISTICS +TABLES +TABLE_CONSTRAINTS +TABLE_PRIVILEGES +TRIGGERS +USER_PRIVILEGES +VIEWS +PBXT_STATISTICS +SELECT t.table_name, c1.column_name +FROM information_schema.tables t +INNER JOIN +information_schema.columns c1 +ON t.table_schema = c1.table_schema AND +t.table_name = c1.table_name +WHERE t.table_schema = 'information_schema' AND +c1.ordinal_position = +( SELECT COALESCE(MIN(c2.ordinal_position),1) +FROM information_schema.columns c2 +WHERE c2.table_schema = t.table_schema AND +c2.table_name = t.table_name AND +c2.column_name LIKE '%SCHEMA%' + ); +table_name column_name +CHARACTER_SETS CHARACTER_SET_NAME +COLLATIONS COLLATION_NAME +COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME +COLUMNS TABLE_SCHEMA +COLUMN_PRIVILEGES TABLE_SCHEMA +ENGINES ENGINE +EVENTS EVENT_SCHEMA +FILES TABLE_SCHEMA +GLOBAL_STATUS VARIABLE_NAME +GLOBAL_VARIABLES VARIABLE_NAME +KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +PARTITIONS TABLE_SCHEMA +PLUGINS PLUGIN_NAME +PROCESSLIST ID +PROFILING QUERY_ID +REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA +ROUTINES ROUTINE_SCHEMA +SCHEMATA SCHEMA_NAME +SCHEMA_PRIVILEGES TABLE_SCHEMA +SESSION_STATUS VARIABLE_NAME +SESSION_VARIABLES VARIABLE_NAME +STATISTICS TABLE_SCHEMA +TABLES TABLE_SCHEMA +TABLE_CONSTRAINTS CONSTRAINT_SCHEMA +TABLE_PRIVILEGES TABLE_SCHEMA +TRIGGERS TRIGGER_SCHEMA +USER_PRIVILEGES GRANTEE +VIEWS TABLE_SCHEMA +PBXT_STATISTICS ID +SELECT t.table_name, c1.column_name +FROM information_schema.tables t +INNER JOIN +information_schema.columns c1 +ON t.table_schema = c1.table_schema AND +t.table_name = c1.table_name +WHERE t.table_schema = 'information_schema' AND +c1.ordinal_position = +( SELECT COALESCE(MIN(c2.ordinal_position),1) +FROM information_schema.columns c2 +WHERE c2.table_schema = 'information_schema' AND +c2.table_name = t.table_name AND +c2.column_name LIKE '%SCHEMA%' + ); +table_name column_name +CHARACTER_SETS CHARACTER_SET_NAME +COLLATIONS COLLATION_NAME +COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME +COLUMNS TABLE_SCHEMA +COLUMN_PRIVILEGES TABLE_SCHEMA +ENGINES ENGINE +EVENTS EVENT_SCHEMA +FILES TABLE_SCHEMA +GLOBAL_STATUS VARIABLE_NAME +GLOBAL_VARIABLES VARIABLE_NAME +KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +PARTITIONS TABLE_SCHEMA +PLUGINS PLUGIN_NAME +PROCESSLIST ID +PROFILING QUERY_ID +REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA +ROUTINES ROUTINE_SCHEMA +SCHEMATA SCHEMA_NAME +SCHEMA_PRIVILEGES TABLE_SCHEMA +SESSION_STATUS VARIABLE_NAME +SESSION_VARIABLES VARIABLE_NAME +STATISTICS TABLE_SCHEMA +TABLES TABLE_SCHEMA +TABLE_CONSTRAINTS CONSTRAINT_SCHEMA +TABLE_PRIVILEGES TABLE_SCHEMA +TRIGGERS TRIGGER_SCHEMA +USER_PRIVILEGES GRANTEE +VIEWS TABLE_SCHEMA +PBXT_STATISTICS ID +select 1 as f1 from information_schema.tables where "CHARACTER_SETS"= +(select cast(table_name as char) from information_schema.tables +order by table_name limit 1) limit 1; +f1 +1 +select t.table_name, group_concat(t.table_schema, '.', t.table_name), +count(*) as num1 +from information_schema.tables t +inner join information_schema.columns c1 +on t.table_schema = c1.table_schema AND t.table_name = c1.table_name +where t.table_schema = 'information_schema' and +c1.ordinal_position = +(select isnull(c2.column_type) - +isnull(group_concat(c2.table_schema, '.', c2.table_name)) + +count(*) as num +from information_schema.columns c2 where +c2.table_schema='information_schema' and +(c2.column_type = 'varchar(7)' or c2.column_type = 'varchar(20)') +group by c2.column_type order by num limit 1) +group by t.table_name order by num1, t.table_name; +table_name group_concat(t.table_schema, '.', t.table_name) num1 +CHARACTER_SETS information_schema.CHARACTER_SETS 1 +COLLATIONS information_schema.COLLATIONS 1 +COLLATION_CHARACTER_SET_APPLICABILITY information_schema.COLLATION_CHARACTER_SET_APPLICABILITY 1 +COLUMNS information_schema.COLUMNS 1 +COLUMN_PRIVILEGES information_schema.COLUMN_PRIVILEGES 1 +ENGINES information_schema.ENGINES 1 +EVENTS information_schema.EVENTS 1 +FILES information_schema.FILES 1 +GLOBAL_STATUS information_schema.GLOBAL_STATUS 1 +GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1 +KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1 +PARTITIONS information_schema.PARTITIONS 1 +PBXT_STATISTICS information_schema.PBXT_STATISTICS 1 +PLUGINS information_schema.PLUGINS 1 +PROCESSLIST information_schema.PROCESSLIST 1 +PROFILING information_schema.PROFILING 1 +REFERENTIAL_CONSTRAINTS information_schema.REFERENTIAL_CONSTRAINTS 1 +ROUTINES information_schema.ROUTINES 1 +SCHEMATA information_schema.SCHEMATA 1 +SCHEMA_PRIVILEGES information_schema.SCHEMA_PRIVILEGES 1 +SESSION_STATUS information_schema.SESSION_STATUS 1 +SESSION_VARIABLES information_schema.SESSION_VARIABLES 1 +STATISTICS information_schema.STATISTICS 1 +TABLES information_schema.TABLES 1 +TABLE_CONSTRAINTS information_schema.TABLE_CONSTRAINTS 1 +TABLE_PRIVILEGES information_schema.TABLE_PRIVILEGES 1 +TRIGGERS information_schema.TRIGGERS 1 +USER_PRIVILEGES information_schema.USER_PRIVILEGES 1 +VIEWS information_schema.VIEWS 1 +Database: information_schema ++---------------------------------------+ +| Tables | ++---------------------------------------+ +| CHARACTER_SETS | +| COLLATIONS | +| COLLATION_CHARACTER_SET_APPLICABILITY | +| COLUMNS | +| COLUMN_PRIVILEGES | +| ENGINES | +| EVENTS | +| FILES | +| GLOBAL_STATUS | +| GLOBAL_VARIABLES | +| KEY_COLUMN_USAGE | +| PARTITIONS | +| PLUGINS | +| PROCESSLIST | +| PROFILING | +| REFERENTIAL_CONSTRAINTS | +| ROUTINES | +| SCHEMATA | +| SCHEMA_PRIVILEGES | +| SESSION_STATUS | +| SESSION_VARIABLES | +| STATISTICS | +| TABLES | +| TABLE_CONSTRAINTS | +| TABLE_PRIVILEGES | +| TRIGGERS | +| USER_PRIVILEGES | +| VIEWS | +| PBXT_STATISTICS | ++---------------------------------------+ +Database: INFORMATION_SCHEMA ++---------------------------------------+ +| Tables | ++---------------------------------------+ +| CHARACTER_SETS | +| COLLATIONS | +| COLLATION_CHARACTER_SET_APPLICABILITY | +| COLUMNS | +| COLUMN_PRIVILEGES | +| ENGINES | +| EVENTS | +| FILES | +| GLOBAL_STATUS | +| GLOBAL_VARIABLES | +| KEY_COLUMN_USAGE | +| PARTITIONS | +| PLUGINS | +| PROCESSLIST | +| PROFILING | +| REFERENTIAL_CONSTRAINTS | +| ROUTINES | +| SCHEMATA | +| SCHEMA_PRIVILEGES | +| SESSION_STATUS | +| SESSION_VARIABLES | +| STATISTICS | +| TABLES | +| TABLE_CONSTRAINTS | +| TABLE_PRIVILEGES | +| TRIGGERS | +| USER_PRIVILEGES | +| VIEWS | +| PBXT_STATISTICS | ++---------------------------------------+ +Wildcard: inf_rmation_schema ++--------------------+ +| Databases | ++--------------------+ +| information_schema | ++--------------------+ +SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; +table_schema count(*) +information_schema 29 +mysql 22 diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 83b8217b570..de9dcea117c 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -2,37 +2,6 @@ drop table if exists t1,t2; drop view if exists v1,v2; drop function if exists f1; drop function if exists f2; -use INFORMATION_SCHEMA; -show tables; -Tables_in_information_schema -CHARACTER_SETS -COLLATIONS -COLLATION_CHARACTER_SET_APPLICABILITY -COLUMNS -COLUMN_PRIVILEGES -ENGINES -EVENTS -FILES -GLOBAL_STATUS -GLOBAL_VARIABLES -KEY_COLUMN_USAGE -PARTITIONS -PLUGINS -PROCESSLIST -PROFILING -REFERENTIAL_CONSTRAINTS -ROUTINES -SCHEMATA -SCHEMA_PRIVILEGES -SESSION_STATUS -SESSION_VARIABLES -STATISTICS -TABLES -TABLE_CONSTRAINTS -TABLE_PRIVILEGES -TRIGGERS -USER_PRIVILEGES -VIEWS show tables from INFORMATION_SCHEMA like 'T%'; Tables_in_information_schema (T%) TABLES diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index 1e4b088c6cd..df4707a78c7 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -197,7 +197,7 @@ c1 c2 5 9 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -230,7 +230,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -269,7 +269,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -282,7 +282,7 @@ SELECT * FROM t1; c1 -1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -315,7 +315,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -330,7 +330,7 @@ SELECT * FROM t1; c1 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -370,7 +370,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -385,7 +385,7 @@ SELECT * FROM t1; c1 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -419,7 +419,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -434,7 +434,7 @@ c1 1 9223372036854775794 SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 2 auto_increment_offset 10 @@ -452,7 +452,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -467,7 +467,7 @@ c1 1 18446744073709551603 SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 2 auto_increment_offset 10 @@ -485,7 +485,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -500,7 +500,7 @@ c1 1 18446744073709551603 SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 5 auto_increment_offset 7 @@ -514,7 +514,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -533,7 +533,7 @@ c1 -9223372036854775806 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 3 auto_increment_offset 3 @@ -550,7 +550,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -568,7 +568,7 @@ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCRE Warnings: Warning 1292 Truncated incorrect auto_increment_increment value: '1152921504606846976' Warning 1292 Truncated incorrect auto_increment_offset value: '1152921504606846976' -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; Variable_name Value auto_increment_increment 65535 auto_increment_offset 65535 diff --git a/mysql-test/r/mysqlshow.result b/mysql-test/r/mysqlshow.result index 42081c309d0..609fb771bb8 100644 --- a/mysql-test/r/mysqlshow.result +++ b/mysql-test/r/mysqlshow.result @@ -75,76 +75,4 @@ Database: test 2 rows in set. DROP TABLE t1, t2; -Database: information_schema -+---------------------------------------+ -| Tables | -+---------------------------------------+ -| CHARACTER_SETS | -| COLLATIONS | -| COLLATION_CHARACTER_SET_APPLICABILITY | -| COLUMNS | -| COLUMN_PRIVILEGES | -| ENGINES | -| EVENTS | -| FILES | -| GLOBAL_STATUS | -| GLOBAL_VARIABLES | -| KEY_COLUMN_USAGE | -| PARTITIONS | -| PLUGINS | -| PROCESSLIST | -| PROFILING | -| REFERENTIAL_CONSTRAINTS | -| ROUTINES | -| SCHEMATA | -| SCHEMA_PRIVILEGES | -| SESSION_STATUS | -| SESSION_VARIABLES | -| STATISTICS | -| TABLES | -| TABLE_CONSTRAINTS | -| TABLE_PRIVILEGES | -| TRIGGERS | -| USER_PRIVILEGES | -| VIEWS | -+---------------------------------------+ -Database: INFORMATION_SCHEMA -+---------------------------------------+ -| Tables | -+---------------------------------------+ -| CHARACTER_SETS | -| COLLATIONS | -| COLLATION_CHARACTER_SET_APPLICABILITY | -| COLUMNS | -| COLUMN_PRIVILEGES | -| ENGINES | -| EVENTS | -| FILES | -| GLOBAL_STATUS | -| GLOBAL_VARIABLES | -| KEY_COLUMN_USAGE | -| PARTITIONS | -| PLUGINS | -| PROCESSLIST | -| PROFILING | -| REFERENTIAL_CONSTRAINTS | -| ROUTINES | -| SCHEMATA | -| SCHEMA_PRIVILEGES | -| SESSION_STATUS | -| SESSION_VARIABLES | -| STATISTICS | -| TABLES | -| TABLE_CONSTRAINTS | -| TABLE_PRIVILEGES | -| TRIGGERS | -| USER_PRIVILEGES | -| VIEWS | -+---------------------------------------+ -Wildcard: inf_rmation_schema -+--------------------+ -| Databases | -+--------------------+ -| information_schema | -+--------------------+ End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/alias.result b/mysql-test/suite/pbxt/r/alias.result new file mode 100644 index 00000000000..6f0315da234 --- /dev/null +++ b/mysql-test/suite/pbxt/r/alias.result @@ -0,0 +1,75 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +cont_nr int(11) NOT NULL auto_increment, +ver_nr int(11) NOT NULL default '0', +aufnr int(11) NOT NULL default '0', +username varchar(50) NOT NULL default '', +hdl_nr int(11) NOT NULL default '0', +eintrag date NOT NULL default '0000-00-00', +st_klasse varchar(40) NOT NULL default '', +st_wert varchar(40) NOT NULL default '', +st_zusatz varchar(40) NOT NULL default '', +st_bemerkung varchar(255) NOT NULL default '', +kunden_art varchar(40) NOT NULL default '', +mcbs_knr int(11) default NULL, +mcbs_aufnr int(11) NOT NULL default '0', +schufa_status char(1) default '?', +bemerkung text, +wirknetz text, +wf_igz int(11) NOT NULL default '0', +tarifcode varchar(80) default NULL, +recycle char(1) default NULL, +sim varchar(30) default NULL, +mcbs_tpl varchar(30) default NULL, +emp_nr int(11) NOT NULL default '0', +laufzeit int(11) default NULL, +hdl_name varchar(30) default NULL, +prov_hdl_nr int(11) NOT NULL default '0', +auto_wirknetz varchar(50) default NULL, +auto_billing varchar(50) default NULL, +touch timestamp NOT NULL, +kategorie varchar(50) default NULL, +kundentyp varchar(20) NOT NULL default '', +sammel_rech_msisdn varchar(30) NOT NULL default '', +p_nr varchar(9) NOT NULL default '', +suffix char(3) NOT NULL default '', +PRIMARY KEY (cont_nr), +KEY idx_aufnr(aufnr), +KEY idx_hdl_nr(hdl_nr), +KEY idx_st_klasse(st_klasse), +KEY ver_nr(ver_nr), +KEY eintrag_idx(eintrag), +KEY emp_nr_idx(emp_nr), +KEY wf_igz(wf_igz), +KEY touch(touch), +KEY hdl_tag(eintrag,hdl_nr), +KEY prov_hdl_nr(prov_hdl_nr), +KEY mcbs_aufnr(mcbs_aufnr), +KEY kundentyp(kundentyp), +KEY p_nr(p_nr,suffix) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (3359356,405,3359356,'Mustermann Musterfrau',52500,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1485525,2122316,'+','','N',1909160,'MobilComSuper92000D2',NULL,NULL,'MS9ND2',3,24,'MobilCom Shop Koeln',52500,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359357,468,3359357,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1503580,2139699,'+','','P',1909171,'MobilComSuper9D1T10SFreisprech(Akquise)',NULL,NULL,'MS9NS1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359358,407,3359358,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1501358,2137473,'N','','N',1909159,'MobilComSuper92000D2',NULL,NULL,'MS9ND2',325,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359359,468,3359359,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1507831,2143894,'+','','P',1909162,'MobilComSuper9D1T10SFreisprech(Akquise)',NULL,NULL,'MS9NS1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359360,0,0,'Mustermann Musterfrau',29674907,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1900169997,2414578,'+',NULL,'N',1909148,'',NULL,NULL,'RV99066_2',20,NULL,'POS',29674907,NULL,NULL,20010202105916,'Mobilfunk','','','97317481','007'); +INSERT INTO t1 VALUES (3359361,406,3359361,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag storniert','','(7001-84):Storno, Kd. möchte nicht mehr','privat',NULL,0,'+','','P',1909150,'MobilComSuper92000D1(Akquise)',NULL,NULL,'MS9ND1',325,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359362,406,3359362,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1509984,2145874,'+','','P',1909154,'MobilComSuper92000D1(Akquise)',NULL,NULL,'MS9ND1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +SELECT ELT(FIELD(kundentyp,'PP','PPA','PG','PGA','FK','FKA','FP','FPA','K','KA','V','VA',''), 'Privat (Private Nutzung)','Privat (Private Nutzung) Sitz im Ausland','Privat (geschaeftliche Nutzung)','Privat (geschaeftliche Nutzung) Sitz im Ausland','Firma (Kapitalgesellschaft)','Firma (Kapitalgesellschaft) Sitz im Ausland','Firma (Personengesellschaft)','Firma (Personengesellschaft) Sitz im Ausland','oeff. rechtl. Koerperschaft','oeff. rechtl. Koerperschaft Sitz im Ausland','Eingetragener Verein','Eingetragener Verein Sitz im Ausland','Typ unbekannt') AS Kundentyp ,kategorie FROM t1 WHERE hdl_nr < 2000000 AND kategorie IN ('Prepaid','Mobilfunk') AND st_klasse = 'Workflow' GROUP BY kundentyp ORDER BY kategorie; +Kundentyp kategorie +Privat (Private Nutzung) Mobilfunk +Warnings: +Warning 1052 Column 'kundentyp' in group statement is ambiguous +drop table t1; +CREATE TABLE t1 ( +AUFNR varchar(12) NOT NULL default '', +PLNFL varchar(6) NOT NULL default '', +VORNR varchar(4) NOT NULL default '', +xstatus_vor smallint(5) unsigned NOT NULL default '0' +); +INSERT INTO t1 VALUES ('40004712','000001','0010',9); +INSERT INTO t1 VALUES ('40004712','000001','0020',0); +UPDATE t1 SET t1.xstatus_vor = Greatest(t1.xstatus_vor,1) WHERE t1.aufnr = +"40004712" AND t1.plnfl = "000001" AND t1.vornr > "0010" ORDER BY t1.vornr +ASC LIMIT 1; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/alter_table.result b/mysql-test/suite/pbxt/r/alter_table.result new file mode 100644 index 00000000000..467bb54a2a9 --- /dev/null +++ b/mysql-test/suite/pbxt/r/alter_table.result @@ -0,0 +1,913 @@ +drop table if exists t1,t2; +drop database if exists mysqltest; +create table t1 ( +col1 int not null auto_increment primary key, +col2 varchar(30) not null, +col3 varchar (20) not null, +col4 varchar(4) not null, +col5 enum('PENDING', 'ACTIVE', 'DISABLED') not null, +col6 int not null, to_be_deleted int); +insert into t1 values (2,4,3,5,"PENDING",1,7); +alter table t1 +add column col4_5 varchar(20) not null after col4, +add column col7 varchar(30) not null after col5, +add column col8 datetime not null, drop column to_be_deleted, +change column col2 fourth varchar(30) not null after col3, +modify column col6 int not null first; +select * from t1; +col6 col1 col3 fourth col4 col4_5 col5 col7 col8 +1 2 3 4 5 PENDING 0000-00-00 00:00:00 +drop table t1; +create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); +insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12); +alter table t1 add column new_col int, order by payoutid,bandid; +select * from t1; +bandID payoutID new_col +6 1 NULL +3 4 NULL +1 6 NULL +2 6 NULL +4 9 NULL +5 10 NULL +7 12 NULL +8 12 NULL +alter table t1 order by bandid,payoutid; +select * from t1; +bandID payoutID new_col +1 6 NULL +2 6 NULL +3 4 NULL +4 9 NULL +5 10 NULL +6 1 NULL +7 12 NULL +8 12 NULL +drop table t1; +CREATE TABLE t1 ( +GROUP_ID int(10) unsigned DEFAULT '0' NOT NULL, +LANG_ID smallint(5) unsigned DEFAULT '0' NOT NULL, +NAME varchar(80) DEFAULT '' NOT NULL, +PRIMARY KEY (GROUP_ID,LANG_ID), +KEY NAME (NAME)); +ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null; +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +GROUP_ID int(10) unsigned NULL NO PRI 0 # +LANG_ID smallint(5) unsigned NULL NO PRI 0 # +NAME char(80) latin1_swedish_ci NO MUL NULL # +DROP TABLE t1; +create table t1 (n int); +insert into t1 values(9),(3),(12),(10); +alter table t1 order by n; +select * from t1; +n +3 +9 +10 +12 +drop table t1; +CREATE TABLE t1 ( +id int(11) unsigned NOT NULL default '0', +category_id tinyint(4) unsigned NOT NULL default '0', +type_id tinyint(4) unsigned NOT NULL default '0', +body text NOT NULL, +user_id int(11) unsigned NOT NULL default '0', +status enum('new','old') NOT NULL default 'new', +PRIMARY KEY (id) +) ENGINE=MyISAM; +ALTER TABLE t1 ORDER BY t1.id, t1.status, t1.type_id, t1.user_id, t1.body; +DROP TABLE t1; +CREATE TABLE t1 (AnamneseId int(10) unsigned NOT NULL auto_increment,B BLOB,PRIMARY KEY (AnamneseId)) engine=myisam; +insert into t1 values (null,"hello"); +LOCK TABLES t1 WRITE; +ALTER TABLE t1 ADD Column new_col int not null; +UNLOCK TABLES; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +DROP TABLE t1; +create table t1 (i int unsigned not null auto_increment primary key); +insert into t1 values (null),(null),(null),(null); +alter table t1 drop i,add i int unsigned not null auto_increment, drop primary key, add primary key (i); +select * from t1; +i +1 +2 +3 +4 +drop table t1; +create table t1 (name char(15)); +insert into t1 (name) values ("current"); +create database mysqltest; +create table mysqltest.t1 (name char(15)); +insert into mysqltest.t1 (name) values ("mysqltest"); +select * from t1; +name +current +select * from mysqltest.t1; +name +mysqltest +alter table t1 rename mysqltest.t1; +ERROR 42S01: Table 't1' already exists +select * from t1; +name +current +select * from mysqltest.t1; +name +mysqltest +drop table t1; +drop database mysqltest; +create table t1 (n1 int not null, n2 int, n3 int, n4 float, +unique(n1), +key (n1, n2, n3, n4), +key (n2, n3, n4, n1), +key (n3, n4, n1, n2), +key (n4, n1, n2, n3) ); +alter table t1 disable keys; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 n1 1 n1 NULL 0 NULL NULL BTREE +t1 1 n1_2 1 n1 NULL NULL NULL NULL BTREE +t1 1 n1_2 2 n2 NULL NULL NULL NULL YES BTREE +t1 1 n1_2 3 n3 NULL NULL NULL NULL YES BTREE +t1 1 n1_2 4 n4 NULL NULL NULL NULL YES BTREE +t1 1 n2 1 n2 NULL NULL NULL NULL YES BTREE +t1 1 n2 2 n3 NULL NULL NULL NULL YES BTREE +t1 1 n2 3 n4 NULL NULL NULL NULL YES BTREE +t1 1 n2 4 n1 NULL NULL NULL NULL BTREE +t1 1 n3 1 n3 NULL NULL NULL NULL YES BTREE +t1 1 n3 2 n4 NULL NULL NULL NULL YES BTREE +t1 1 n3 3 n1 NULL NULL NULL NULL BTREE +t1 1 n3 4 n2 NULL NULL NULL NULL YES BTREE +t1 1 n4 1 n4 NULL NULL NULL NULL YES BTREE +t1 1 n4 2 n1 NULL NULL NULL NULL BTREE +t1 1 n4 3 n2 NULL NULL NULL NULL YES BTREE +t1 1 n4 4 n3 NULL NULL NULL NULL YES BTREE +insert into t1 values(10,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(9,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(8,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(7,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(6,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(5,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(4,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(3,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(2,RAND()*1000,RAND()*1000,RAND()); +insert into t1 values(1,RAND()*1000,RAND()*1000,RAND()); +alter table t1 enable keys; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 n1 1 n1 NULL 10 NULL NULL BTREE +t1 1 n1_2 1 n1 NULL NULL NULL NULL BTREE +t1 1 n1_2 2 n2 NULL NULL NULL NULL YES BTREE +t1 1 n1_2 3 n3 NULL NULL NULL NULL YES BTREE +t1 1 n1_2 4 n4 NULL NULL NULL NULL YES BTREE +t1 1 n2 1 n2 NULL NULL NULL NULL YES BTREE +t1 1 n2 2 n3 NULL NULL NULL NULL YES BTREE +t1 1 n2 3 n4 NULL NULL NULL NULL YES BTREE +t1 1 n2 4 n1 NULL NULL NULL NULL BTREE +t1 1 n3 1 n3 NULL NULL NULL NULL YES BTREE +t1 1 n3 2 n4 NULL NULL NULL NULL YES BTREE +t1 1 n3 3 n1 NULL NULL NULL NULL BTREE +t1 1 n3 4 n2 NULL NULL NULL NULL YES BTREE +t1 1 n4 1 n4 NULL NULL NULL NULL YES BTREE +t1 1 n4 2 n1 NULL NULL NULL NULL BTREE +t1 1 n4 3 n2 NULL NULL NULL NULL YES BTREE +t1 1 n4 4 n3 NULL NULL NULL NULL YES BTREE +drop table t1; +create table t1 (i int unsigned not null auto_increment primary key); +alter table t1 rename t2; +alter table t2 rename t1, add c char(10) comment "no comment"; +show columns from t1; +Field Type Null Key Default Extra +i int(10) unsigned NO PRI NULL auto_increment +c char(10) YES NULL +drop table t1; +create table t1 (a int, b int); +insert into t1 values(1,100), (2,100), (3, 100); +insert into t1 values(1,99), (2,99), (3, 99); +insert into t1 values(1,98), (2,98), (3, 98); +insert into t1 values(1,97), (2,97), (3, 97); +insert into t1 values(1,96), (2,96), (3, 96); +insert into t1 values(1,95), (2,95), (3, 95); +insert into t1 values(1,94), (2,94), (3, 94); +insert into t1 values(1,93), (2,93), (3, 93); +insert into t1 values(1,92), (2,92), (3, 92); +insert into t1 values(1,91), (2,91), (3, 91); +insert into t1 values(1,90), (2,90), (3, 90); +insert into t1 values(1,89), (2,89), (3, 89); +insert into t1 values(1,88), (2,88), (3, 88); +insert into t1 values(1,87), (2,87), (3, 87); +insert into t1 values(1,86), (2,86), (3, 86); +insert into t1 values(1,85), (2,85), (3, 85); +insert into t1 values(1,84), (2,84), (3, 84); +insert into t1 values(1,83), (2,83), (3, 83); +insert into t1 values(1,82), (2,82), (3, 82); +insert into t1 values(1,81), (2,81), (3, 81); +insert into t1 values(1,80), (2,80), (3, 80); +insert into t1 values(1,79), (2,79), (3, 79); +insert into t1 values(1,78), (2,78), (3, 78); +insert into t1 values(1,77), (2,77), (3, 77); +insert into t1 values(1,76), (2,76), (3, 76); +insert into t1 values(1,75), (2,75), (3, 75); +insert into t1 values(1,74), (2,74), (3, 74); +insert into t1 values(1,73), (2,73), (3, 73); +insert into t1 values(1,72), (2,72), (3, 72); +insert into t1 values(1,71), (2,71), (3, 71); +insert into t1 values(1,70), (2,70), (3, 70); +insert into t1 values(1,69), (2,69), (3, 69); +insert into t1 values(1,68), (2,68), (3, 68); +insert into t1 values(1,67), (2,67), (3, 67); +insert into t1 values(1,66), (2,66), (3, 66); +insert into t1 values(1,65), (2,65), (3, 65); +insert into t1 values(1,64), (2,64), (3, 64); +insert into t1 values(1,63), (2,63), (3, 63); +insert into t1 values(1,62), (2,62), (3, 62); +insert into t1 values(1,61), (2,61), (3, 61); +insert into t1 values(1,60), (2,60), (3, 60); +insert into t1 values(1,59), (2,59), (3, 59); +insert into t1 values(1,58), (2,58), (3, 58); +insert into t1 values(1,57), (2,57), (3, 57); +insert into t1 values(1,56), (2,56), (3, 56); +insert into t1 values(1,55), (2,55), (3, 55); +insert into t1 values(1,54), (2,54), (3, 54); +insert into t1 values(1,53), (2,53), (3, 53); +insert into t1 values(1,52), (2,52), (3, 52); +insert into t1 values(1,51), (2,51), (3, 51); +insert into t1 values(1,50), (2,50), (3, 50); +insert into t1 values(1,49), (2,49), (3, 49); +insert into t1 values(1,48), (2,48), (3, 48); +insert into t1 values(1,47), (2,47), (3, 47); +insert into t1 values(1,46), (2,46), (3, 46); +insert into t1 values(1,45), (2,45), (3, 45); +insert into t1 values(1,44), (2,44), (3, 44); +insert into t1 values(1,43), (2,43), (3, 43); +insert into t1 values(1,42), (2,42), (3, 42); +insert into t1 values(1,41), (2,41), (3, 41); +insert into t1 values(1,40), (2,40), (3, 40); +insert into t1 values(1,39), (2,39), (3, 39); +insert into t1 values(1,38), (2,38), (3, 38); +insert into t1 values(1,37), (2,37), (3, 37); +insert into t1 values(1,36), (2,36), (3, 36); +insert into t1 values(1,35), (2,35), (3, 35); +insert into t1 values(1,34), (2,34), (3, 34); +insert into t1 values(1,33), (2,33), (3, 33); +insert into t1 values(1,32), (2,32), (3, 32); +insert into t1 values(1,31), (2,31), (3, 31); +insert into t1 values(1,30), (2,30), (3, 30); +insert into t1 values(1,29), (2,29), (3, 29); +insert into t1 values(1,28), (2,28), (3, 28); +insert into t1 values(1,27), (2,27), (3, 27); +insert into t1 values(1,26), (2,26), (3, 26); +insert into t1 values(1,25), (2,25), (3, 25); +insert into t1 values(1,24), (2,24), (3, 24); +insert into t1 values(1,23), (2,23), (3, 23); +insert into t1 values(1,22), (2,22), (3, 22); +insert into t1 values(1,21), (2,21), (3, 21); +insert into t1 values(1,20), (2,20), (3, 20); +insert into t1 values(1,19), (2,19), (3, 19); +insert into t1 values(1,18), (2,18), (3, 18); +insert into t1 values(1,17), (2,17), (3, 17); +insert into t1 values(1,16), (2,16), (3, 16); +insert into t1 values(1,15), (2,15), (3, 15); +insert into t1 values(1,14), (2,14), (3, 14); +insert into t1 values(1,13), (2,13), (3, 13); +insert into t1 values(1,12), (2,12), (3, 12); +insert into t1 values(1,11), (2,11), (3, 11); +insert into t1 values(1,10), (2,10), (3, 10); +insert into t1 values(1,9), (2,9), (3, 9); +insert into t1 values(1,8), (2,8), (3, 8); +insert into t1 values(1,7), (2,7), (3, 7); +insert into t1 values(1,6), (2,6), (3, 6); +insert into t1 values(1,5), (2,5), (3, 5); +insert into t1 values(1,4), (2,4), (3, 4); +insert into t1 values(1,3), (2,3), (3, 3); +insert into t1 values(1,2), (2,2), (3, 2); +insert into t1 values(1,1), (2,1), (3, 1); +alter table t1 add unique (a,b), add key (b); +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 0 a 2 b A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 0 a 2 b A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +drop table t1; +CREATE TABLE t1 (i int(10), index(i) ); +ALTER TABLE t1 DISABLE KEYS; +INSERT INTO t1 VALUES(1),(2),(3); +ALTER TABLE t1 ENABLE KEYS; +drop table t1; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User) +) ENGINE=MyISAM; +ALTER TABLE t1 DISABLE KEYS; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty'); +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +ALTER TABLE t1 ENABLE KEYS; +UNLOCK TABLES; +CHECK TABLES t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User), +KEY (Host) +) ENGINE=MyISAM; +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''); +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +ALTER TABLE t1 ENABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 2 NULL NULL BTREE +t1 1 Host 1 Host A 1 NULL NULL BTREE +UNLOCK TABLES; +CHECK TABLES t1; +Table Op Msg_type Msg_text +test.t1 check status OK +LOCK TABLES t1 WRITE; +ALTER TABLE t1 RENAME t2; +UNLOCK TABLES; +select * from t2; +Host User +localhost +localhost root +DROP TABLE t2; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User), +KEY (Host) +) ENGINE=MyISAM; +LOCK TABLES t1 WRITE; +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +DROP TABLE t1; +create table t1 (a int); +alter table t1 rename to ``; +ERROR 42000: Incorrect table name '' +rename table t1 to ``; +ERROR 42000: Incorrect table name '' +drop table t1; +drop table if exists t1, t2; +Warnings: +Note 1051 Unknown table 't1' +Note 1051 Unknown table 't2' +create table t1 ( a varchar(10) not null primary key ) engine=myisam; +create table t2 ( a varchar(10) not null primary key ) engine=merge union=(t1); +flush tables; +alter table t1 modify a varchar(10); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(10) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`) +flush tables; +alter table t1 modify a varchar(10) not null; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(10) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`) +drop table if exists t1, t2; +create table t1 (a int, b int, c int, d int, e int, f int, g int, h int,i int, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM; +insert into t1 (a) values(1); +show table status like 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 37 X X X X X X X X latin1_swedish_ci NULL +alter table t1 modify a int; +show table status like 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 37 X X X X X X X X latin1_swedish_ci NULL +drop table t1; +create table t1 (a int not null, b int not null, c int not null, d int not null, e int not null, f int not null, g int not null, h int not null,i int not null, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM; +insert into t1 (a) values(1); +Warnings: +Warning 1364 Field 'b' doesn't have a default value +Warning 1364 Field 'c' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'e' doesn't have a default value +Warning 1364 Field 'f' doesn't have a default value +Warning 1364 Field 'g' doesn't have a default value +Warning 1364 Field 'h' doesn't have a default value +Warning 1364 Field 'i' doesn't have a default value +show table status like 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 10 Fixed 1 37 X X X X X X X X latin1_swedish_ci NULL +drop table t1; +set names koi8r; +create table t1 (a char(10) character set koi8r); +insert into t1 values ('ÔÅÓÔ'); +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ D4C5D3D4 +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ F2E5F1F2 +alter table t1 change a a binary(4); +select a,hex(a) from t1; +a hex(a) +òåñò F2E5F1F2 +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ D4C5D3D4 +alter table t1 change a a varchar(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ D4C5D3D4 +alter table t1 change a a text character set cp1251; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ D4C5D3D4 +delete from t1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) CHARACTER SET koi8r DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table t1 DEFAULT CHARACTER SET latin1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) CHARACTER SET koi8r DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table t1 CONVERT TO CHARACTER SET latin1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table t1 DEFAULT CHARACTER SET cp1251; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) CHARACTER SET latin1 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=cp1251 +drop table t1; +create table t1 (myblob longblob,mytext longtext) +default charset latin1 collate latin1_general_cs; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `myblob` longblob, + `mytext` longtext COLLATE latin1_general_cs +) ENGINE=PBXT DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs +alter table t1 character set latin2; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `myblob` longblob, + `mytext` longtext CHARACTER SET latin1 COLLATE latin1_general_cs +) ENGINE=PBXT DEFAULT CHARSET=latin2 +drop table t1; +CREATE TABLE t1 (a int PRIMARY KEY, b INT UNIQUE); +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) DEFAULT NULL, + UNIQUE KEY `b` (`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +ALTER TABLE t1 DROP PRIMARY KEY; +ERROR 42000: Can't DROP 'PRIMARY'; check that column/key exists +DROP TABLE t1; +create table t1 (a int, b int, key(a)); +insert into t1 values (1,1), (2,2); +alter table t1 drop key no_such_key; +ERROR 42000: Can't DROP 'no_such_key'; check that column/key exists +alter table t1 drop key a; +drop table t1; +CREATE TABLE T12207(a int) ENGINE=MYISAM; +ALTER TABLE T12207 DISCARD TABLESPACE; +ERROR HY000: Table storage engine for 'T12207' doesn't have this option +DROP TABLE T12207; +create table t1 (a text) character set koi8r; +insert into t1 values (_koi8r'ÔÅÓÔ'); +select hex(a) from t1; +hex(a) +D4C5D3D4 +alter table t1 convert to character set cp1251; +select hex(a) from t1; +hex(a) +F2E5F1F2 +drop table t1; +create table t1 ( a timestamp ); +alter table t1 add unique ( a(1) ); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +drop table t1; +drop table if exists t1; +create table t1 (a int, key(a)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +"this used not to disable the index" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a NULL NULL NULL NULL YES BTREE +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a NULL NULL NULL NULL YES BTREE +alter table t1 add b char(10), disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +alter table t1 add c decimal(10,2), enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +"this however did" +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a NULL NULL NULL NULL YES BTREE +desc t1; +Field Type Null Key Default Extra +a bigint(20) YES MUL NULL +b char(10) YES NULL +c decimal(10,2) YES NULL +alter table t1 add d decimal(15,5); +"The key should still be disabled" +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +drop table t1; +"Now will test with one unique index" +create table t1(a int, b char(10), unique(a)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a NULL 0 NULL NULL YES BTREE +alter table t1 enable keys; +"If no copy on noop change, this won't touch the data file" +"Unique index, no change" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +"Change the type implying data copy" +"Unique index, no change" +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +alter table t1 modify a bigint; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +drop table t1; +"Now will test with one unique and one non-unique index" +create table t1(a int, b char(10), unique(a), key(b)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a NULL 0 NULL NULL YES BTREE +t1 1 b 1 b NULL NULL NULL NULL YES BTREE +alter table t1 enable keys; +"If no copy on noop change, this won't touch the data file" +"The non-unique index will be disabled" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a NULL 0 NULL NULL YES BTREE +t1 1 b 1 b NULL NULL NULL NULL YES BTREE +"Change the type implying data copy" +"The non-unique index will be disabled" +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +"Change again the type, but leave the indexes as_is" +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +"Try the same. When data is no copied on similar tables, this is noop" +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 0 NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +drop table t1; +create database mysqltest; +create table t1 (c1 int); +alter table t1 rename mysqltest.t1; +drop table t1; +ERROR 42S02: Unknown table 't1' +alter table mysqltest.t1 rename t1; +drop table t1; +create table t1 (c1 int); +use mysqltest; +drop database mysqltest; +alter table test.t1 rename t1; +ERROR 3D000: No database selected +alter table test.t1 rename test.t1; +use test; +drop table t1; +CREATE TABLE t1(a INT) ROW_FORMAT=FIXED; +CREATE INDEX i1 ON t1(a); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + KEY `i1` (`a`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED +DROP INDEX i1 ON t1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED +DROP TABLE t1; +DROP TABLE IF EXISTS bug24219; +DROP TABLE IF EXISTS bug24219_2; +CREATE TABLE bug24219 (a INT, INDEX(a)); +SHOW INDEX FROM bug24219; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +bug24219 1 a 1 a A NULL NULL NULL YES BTREE +ALTER TABLE bug24219 RENAME TO bug24219_2, DISABLE KEYS; +SHOW INDEX FROM bug24219_2; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +bug24219_2 1 a 1 a A NULL NULL NULL YES BTREE +DROP TABLE bug24219_2; +create table t1 (mycol int(10) not null); +alter table t1 alter column mycol set default 0; +desc t1; +Field Type Null Key Default Extra +mycol int(10) NO 0 +drop table t1; +create table t1 (v varchar(32)); +insert into t1 values ('def'),('abc'),('hij'),('3r4f'); +select * from t1; +v +def +abc +hij +3r4f +alter table t1 change v v2 varchar(32); +select * from t1; +v2 +def +abc +hij +3r4f +alter table t1 change v2 v varchar(64); +select * from t1; +v +def +abc +hij +3r4f +update t1 set v = 'lmn' where v = 'hij'; +select * from t1; +v +def +abc +3r4f +lmn +alter table t1 add i int auto_increment not null primary key first; +select * from t1; +i v +1 def +2 abc +3 3r4f +4 lmn +update t1 set i=5 where i=3; +select * from t1; +i v +1 def +2 abc +4 lmn +5 3r4f +alter table t1 change i i bigint; +select * from t1; +i v +1 def +2 abc +4 lmn +5 3r4f +alter table t1 add unique key (i, v); +select * from t1 where i between 2 and 4 and v in ('def','3r4f','lmn'); +i v +4 lmn +drop table t1; +create table t1 (t varchar(255) default null, key t (t(80))) +engine=myisam default charset=latin1; +alter table t1 change t t text; +drop table t1; +CREATE TABLE t1 (s CHAR(8) BINARY); +INSERT INTO t1 VALUES ('test'); +SELECT LENGTH(s) FROM t1; +LENGTH(s) +4 +ALTER TABLE t1 MODIFY s CHAR(10) BINARY; +SELECT LENGTH(s) FROM t1; +LENGTH(s) +4 +DROP TABLE t1; +CREATE TABLE t1 (s BINARY(8)); +INSERT INTO t1 VALUES ('test'); +SELECT LENGTH(s) FROM t1; +LENGTH(s) +8 +SELECT HEX(s) FROM t1; +HEX(s) +7465737400000000 +ALTER TABLE t1 MODIFY s BINARY(10); +SELECT HEX(s) FROM t1; +HEX(s) +74657374000000000000 +SELECT LENGTH(s) FROM t1; +LENGTH(s) +10 +DROP TABLE t1; +CREATE TABLE t1 (v VARCHAR(3), b INT); +INSERT INTO t1 VALUES ('abc', 5); +SELECT * FROM t1; +v b +abc 5 +ALTER TABLE t1 MODIFY COLUMN v VARCHAR(4); +SELECT * FROM t1; +v b +abc 5 +DROP TABLE t1; +DROP TABLE IF EXISTS `t+1`, `t+2`; +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +ERROR 42S01: Table 't+2' already exists +DROP TABLE `t+1`, `t+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +ERROR 42S01: Table 'tt+2' already exists +SHOW CREATE TABLE `tt+1`; +Table Create Table +tt+1 CREATE TEMPORARY TABLE `tt+1` ( + `c1` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +SHOW CREATE TABLE `tt+2`; +Table Create Table +tt+2 CREATE TEMPORARY TABLE `tt+2` ( + `c1` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLE `tt+1`, `tt+2`; +CREATE TABLE `#sql1` (c1 INT); +CREATE TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +Tables_in_test +#sql1 +@0023sql2 +RENAME TABLE `#sql1` TO `@0023sql1`; +RENAME TABLE `@0023sql2` TO `#sql2`; +SHOW TABLES; +Tables_in_test +#sql2 +@0023sql1 +ALTER TABLE `@0023sql1` RENAME `#sql-1`; +ALTER TABLE `#sql2` RENAME `@0023sql-2`; +SHOW TABLES; +Tables_in_test +#sql-1 +@0023sql-2 +INSERT INTO `#sql-1` VALUES (1); +INSERT INTO `@0023sql-2` VALUES (2); +DROP TABLE `#sql-1`, `@0023sql-2`; +CREATE TEMPORARY TABLE `#sql1` (c1 INT); +CREATE TEMPORARY TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +Tables_in_test +ALTER TABLE `#sql1` RENAME `@0023sql1`; +ALTER TABLE `@0023sql2` RENAME `#sql2`; +SHOW TABLES; +Tables_in_test +INSERT INTO `#sql2` VALUES (1); +INSERT INTO `@0023sql1` VALUES (2); +SHOW CREATE TABLE `#sql2`; +Table Create Table +#sql2 CREATE TEMPORARY TABLE `#sql2` ( + `c1` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +SHOW CREATE TABLE `@0023sql1`; +Table Create Table +@0023sql1 CREATE TEMPORARY TABLE `@0023sql1` ( + `c1` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLE `#sql2`, `@0023sql1`; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +CREATE TABLE t1 ( +int_field INTEGER UNSIGNED NOT NULL, +char_field CHAR(10), +INDEX(`int_field`) +); +DESCRIBE t1; +Field Type Null Key Default Extra +int_field int(10) unsigned NO MUL NULL +char_field char(10) YES NULL +SHOW INDEXES FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 int_field 1 int_field A NULL NULL NULL BTREE +INSERT INTO t1 VALUES (1, "edno"), (1, "edno"), (2, "dve"), (3, "tri"), (5, "pet"); +"Non-copy data change - new frm, but old data and index files" +ALTER TABLE t1 +CHANGE int_field unsigned_int_field INTEGER UNSIGNED NOT NULL, +RENAME t2; +SELECT * FROM t1 ORDER BY int_field; +ERROR 42S02: Table 'test.t1' doesn't exist +SELECT * FROM t2 ORDER BY unsigned_int_field; +unsigned_int_field char_field +1 edno +1 edno +2 dve +3 tri +5 pet +DESCRIBE t2; +Field Type Null Key Default Extra +unsigned_int_field int(10) unsigned NO MUL NULL +char_field char(10) YES NULL +DESCRIBE t2; +Field Type Null Key Default Extra +unsigned_int_field int(10) unsigned NO MUL NULL +char_field char(10) YES NULL +ALTER TABLE t2 MODIFY unsigned_int_field BIGINT UNSIGNED NOT NULL; +DESCRIBE t2; +Field Type Null Key Default Extra +unsigned_int_field bigint(20) unsigned NO MUL NULL +char_field char(10) YES NULL +DROP TABLE t2; diff --git a/mysql-test/suite/pbxt/r/analyse.result b/mysql-test/suite/pbxt/r/analyse.result new file mode 100644 index 00000000000..c3484937f0a --- /dev/null +++ b/mysql-test/suite/pbxt/r/analyse.result @@ -0,0 +1,156 @@ +drop table if exists t1,t2; +create table t1 (i int, j int, empty_string char(10), bool char(1), d date); +insert into t1 values (1,2,"","Y","2002-03-03"), (3,4,"","N","2002-03-04"), (5,6,"","Y","2002-03-04"), (7,8,"","N","2002-03-05"); +select count(*) from t1 procedure analyse(); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +count(*) 4 4 1 1 0 0 4.0000 0.0000 ENUM('4') NOT NULL +select * from t1 procedure analyse(); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL +test.t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL +test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL +test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL +test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL +select * from t1 procedure analyse(2); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.i 1 7 1 1 0 0 4.0000 2.2361 TINYINT(1) UNSIGNED NOT NULL +test.t1.j 2 8 1 1 0 0 5.0000 2.2361 TINYINT(1) UNSIGNED NOT NULL +test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL +test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL +test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL +create table t2 select * from t1 procedure analyse(); +select * from t2; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL +test.t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL +test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL +test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL +test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL +drop table t1,t2; +EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> system NULL NULL NULL NULL 1 +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +create table t1 (a int not null); +create table t2 select * from t1 where 0=1 procedure analyse(); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `Field_name` varbinary(255) NOT NULL DEFAULT '', + `Min_value` varbinary(255) DEFAULT NULL, + `Max_value` varbinary(255) DEFAULT NULL, + `Min_length` bigint(11) NOT NULL DEFAULT '0', + `Max_length` bigint(11) NOT NULL DEFAULT '0', + `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', + `Nulls` bigint(11) NOT NULL DEFAULT '0', + `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', + `Std` varbinary(255) DEFAULT NULL, + `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t1 where 0=1 procedure analyse(); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +insert into t1 values(1); +drop table t2; +create table t2 select * from t1 where 0=1 procedure analyse(); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `Field_name` varbinary(255) NOT NULL DEFAULT '', + `Min_value` varbinary(255) DEFAULT NULL, + `Max_value` varbinary(255) DEFAULT NULL, + `Min_length` bigint(11) NOT NULL DEFAULT '0', + `Max_length` bigint(11) NOT NULL DEFAULT '0', + `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', + `Nulls` bigint(11) NOT NULL DEFAULT '0', + `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', + `Std` varbinary(255) DEFAULT NULL, + `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t2; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +insert into t2 select * from t1 procedure analyse(); +select * from t2; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.a 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL +insert into t1 values(2); +drop table t2; +create table t2 select * from t1 where 0=1 procedure analyse(); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `Field_name` varbinary(255) NOT NULL DEFAULT '', + `Min_value` varbinary(255) DEFAULT NULL, + `Max_value` varbinary(255) DEFAULT NULL, + `Min_length` bigint(11) NOT NULL DEFAULT '0', + `Max_length` bigint(11) NOT NULL DEFAULT '0', + `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', + `Nulls` bigint(11) NOT NULL DEFAULT '0', + `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', + `Std` varbinary(255) DEFAULT NULL, + `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t2; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +insert into t2 select * from t1 procedure analyse(); +select * from t2; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.a 1 2 1 1 0 0 1.5000 0.5000 ENUM('1','2') NOT NULL +drop table t1,t2; +create table t1 (v varchar(128)); +insert into t1 values ('abc'),('abc\'def\\hij\"klm\0opq'),('\''),('\"'),('\\'),('a\0'),('b\''),('c\"'),('d\\'),('\'b'),('\"c'),('\\d'),('a\0\0\0b'),('a\'\'\'\'b'),('a\"\"\"\"b'),('a\\\\\\\\b'),('\'\0\\\"'),('\'\''),('\"\"'),('\\\\'),('The\ZEnd'); +select * from t1 procedure analyse(); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.v " \\ 1 19 0 0 3.7619 NULL ENUM('"','""','"c','\'\0\\"','\'','\'\'','\'b','a\0\0\0b','a\0','a""""b','a\'\'\'\'b','abc','abc\'def\\hij"klm\0opq','a\\\\\\\\b','b\'','c"','d\\','The\ZEnd','\\','\\d','\\\\') NOT NULL +drop table t1; +create table t1 (df decimal(5,1)); +insert into t1 values(1.1); +insert into t1 values(2.2); +select * from t1 procedure analyse(); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.df 1.1 2.2 13 13 0 0 1.65000 0.55000 ENUM('1.1','2.2') NOT NULL +drop table t1; +create table t1 (d double); +insert into t1 values (100000); +select * from t1 procedure analyse (1,1); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.d 100000 100000 6 6 0 0 100000 0 MEDIUMINT(6) UNSIGNED NOT NULL +drop table t1; +create table t1 (product varchar(32), country_id int not null, year int, +profit int); +insert into t1 values ( 'Computer', 2,2000, 1200), +( 'TV', 1, 1999, 150), +( 'Calculator', 1, 1999,50), +( 'Computer', 1, 1999,1500), +( 'Computer', 1, 2000,1500), +( 'TV', 1, 2000, 150), +( 'TV', 2, 2000, 100), +( 'TV', 2, 2000, 100), +( 'Calculator', 1, 2000,75), +( 'Calculator', 2, 2000,75), +( 'TV', 1, 1999, 100), +( 'Computer', 1, 1999,1200), +( 'Computer', 2, 2000,1500), +( 'Calculator', 2, 2000,75), +( 'Phone', 3, 2003,10) +; +create table t2 (country_id int primary key, country char(20) not null); +insert into t2 values (1, 'USA'),(2,'India'), (3,'Finland'); +select product, sum(profit),avg(profit) from t1 group by product with rollup procedure analyse(); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.product Computer TV 2 8 0 0 4.2500 NULL ENUM('Computer','Phone','TV') NOT NULL +sum(profit) 10 6900 11 11 0 0 1946.2500 2867.6719 ENUM('10','275','600','6900') NOT NULL +avg(profit) 10.0000 1380.0000 16 16 0 0 394.68750000 570.20033144 ENUM('10.0000','68.7500','120.0000','1380.0000') NOT NULL +drop table t1,t2; +create table t1 (f1 double(10,5), f2 char(10), f3 double(10,5)); +insert into t1 values (5.999, "5.9999", 5.99999), (9.555, "9.5555", 9.55555); +select f1 from t1 procedure analyse(1, 1); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.f1 5.99900 9.55500 7 7 0 0 7.77700 1.77800 FLOAT(4,3) NOT NULL +select f2 from t1 procedure analyse(1, 1); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.f2 5.9999 9.5555 6 6 0 0 6.0000 NULL FLOAT(5,4) UNSIGNED NOT NULL +select f3 from t1 procedure analyse(1, 1); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.f3 5.99999 9.55555 7 7 0 0 7.77777 1.77778 FLOAT(6,5) NOT NULL +drop table t1; +End of 4.1 tests diff --git a/mysql-test/suite/pbxt/r/analyze.result b/mysql-test/suite/pbxt/r/analyze.result new file mode 100644 index 00000000000..4e769b6c5b5 --- /dev/null +++ b/mysql-test/suite/pbxt/r/analyze.result @@ -0,0 +1,60 @@ +create table t1 (a bigint); +lock tables t1 write; +insert into t1 values(0); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +unlock tables; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (a bigint); +insert into t1 values(0); +lock tables t1 write; +delete from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +unlock tables; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (a bigint); +insert into t1 values(0); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (a mediumtext, fulltext key key1(a)) charset utf8 collate utf8_general_ci engine myisam; +insert into t1 values ('hello'); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status Table is already up to date +drop table t1; +CREATE TABLE t1 (a int); +prepare stmt1 from "SELECT * FROM t1 PROCEDURE ANALYSE()"; +execute stmt1; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.a NULL NULL 0 0 0 0 0.0 0.0 CHAR(0) NOT NULL +execute stmt1; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.a NULL NULL 0 0 0 0 0.0 0.0 CHAR(0) NOT NULL +deallocate prepare stmt1; +drop table t1; +create temporary table t1(a int, index(a)); +insert into t1 values('1'),('2'),('3'),('4'),('5'); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +drop table t1; diff --git a/mysql-test/suite/pbxt/r/ansi.result b/mysql-test/suite/pbxt/r/ansi.result new file mode 100644 index 00000000000..0d8f6222709 --- /dev/null +++ b/mysql-test/suite/pbxt/r/ansi.result @@ -0,0 +1,48 @@ +drop table if exists t1; +set sql_mode="MySQL40"; +select @@sql_mode; +@@sql_mode +MYSQL40,HIGH_NOT_PRECEDENCE +set @@sql_mode="ANSI"; +select @@sql_mode; +@@sql_mode +REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI +SELECT 'A' || 'B'; +'A' || 'B' +AB +CREATE TABLE t1 (id INT, id2 int); +SELECT id,NULL,1,1.1,'a' FROM t1 GROUP BY id; +id NULL 1 1.1 a +SELECT id FROM t1 GROUP BY id2; +id +drop table t1; +SET @@SQL_MODE=""; +CREATE TABLE t1 (i int auto_increment NOT NULL, PRIMARY KEY (i)); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`i`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +SET @@SQL_MODE="MYSQL323"; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`i`) +) TYPE=PBXT +SET @@SQL_MODE="MYSQL40"; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`i`) +) TYPE=PBXT +SET @@SQL_MODE="NO_FIELD_OPTIONS"; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) NOT NULL, + PRIMARY KEY (`i`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/auto_increment.result b/mysql-test/suite/pbxt/r/auto_increment.result new file mode 100644 index 00000000000..a945ecebbcc --- /dev/null +++ b/mysql-test/suite/pbxt/r/auto_increment.result @@ -0,0 +1,454 @@ +drop table if exists t1; +drop table if exists t2; +SET SQL_WARNINGS=1; +create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam auto_increment=3; +insert into t1 values (1,1),(NULL,3),(NULL,4); +delete from t1 where a=4; +insert into t1 values (NULL,5),(NULL,6); +select * from t1; +a b +1 1 +3 3 +5 5 +6 6 +delete from t1 where a=6; +replace t1 values (3,1); +ALTER TABLE t1 add c int; +replace t1 values (3,3,3); +insert into t1 values (NULL,7,7); +update t1 set a=8,b=b+1,c=c+1 where a=7; +insert into t1 values (NULL,9,9); +select * from t1; +a b c +1 1 NULL +3 3 3 +5 5 NULL +8 8 8 +9 9 9 +drop table t1; +create table t1 ( +skey tinyint unsigned NOT NULL auto_increment PRIMARY KEY, +sval char(20) +); +insert into t1 values (NULL, "hello"); +insert into t1 values (NULL, "hey"); +select * from t1; +skey sval +1 hello +2 hey +select _rowid,t1._rowid,skey,sval from t1; +_rowid _rowid skey sval +1 1 1 hello +2 2 2 hey +drop table t1; +create table t1 (a char(10) not null, b int not null auto_increment, primary key(a,b)); +insert into t1 values ("a",1),("b",2),("a",2),("c",1); +insert into t1 values ("a",NULL),("b",NULL),("c",NULL),("e",NULL); +insert into t1 (a) values ("a"),("b"),("c"),("d"); +insert into t1 (a) values ('k'),('d'); +insert into t1 (a) values ("a"); +insert into t1 values ("d",last_insert_id()); +select * from t1; +a b +a 1 +a 2 +a 3 +a 7 +a 13 +b 2 +b 4 +b 8 +c 1 +c 5 +c 9 +d 10 +d 12 +d 13 +e 6 +k 11 +drop table t1; +create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ordid), index(ord,ordid)); +insert into t1 (ordid,ord) values (NULL,'sdj'),(NULL,'sdj'); +select * from t1; +ordid ord +1 sdj +2 sdj +drop table t1; +create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)); +insert into t1 values (NULL,'sdj'),(NULL,'sdj'),(NULL,"abc"),(NULL,'abc'),(NULL,'zzz'),(NULL,'sdj'),(NULL,'abc'); +select * from t1; +ordid ord +3 abc +4 abc +7 abc +1 sdj +2 sdj +6 sdj +5 zzz +drop table t1; +create table t1 (sid char(5), id int(2) NOT NULL auto_increment, key(sid, id)); +create table t2 (sid char(20), id int(2)); +insert into t2 values ('skr',NULL),('skr',NULL),('test',NULL); +insert into t1 select * from t2; +select * from t1; +sid id +skr 1 +skr 2 +test 3 +drop table t1,t2; +create table t1 (a int not null primary key auto_increment); +insert into t1 values (0); +update t1 set a=0; +select * from t1; +a +0 +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (a int not null auto_increment primary key); +insert into t1 values (NULL); +insert into t1 values (-1); +select last_insert_id(); +last_insert_id() +1 +insert into t1 values (NULL); +select * from t1; +a +-1 +1 +2 +drop table t1; +create table t1 (a int not null auto_increment primary key) /*!40102 engine=heap */; +insert into t1 values (NULL); +insert into t1 values (-1); +select last_insert_id(); +last_insert_id() +1 +insert into t1 values (NULL); +select * from t1; +a +1 +-1 +2 +drop table t1; +create table t1 (i tinyint unsigned not null auto_increment primary key); +insert into t1 set i = 254; +insert into t1 set i = null; +select last_insert_id(); +last_insert_id() +255 +explain extended select last_insert_id(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select last_insert_id() AS `last_insert_id()` +insert into t1 set i = 254; +ERROR 23000: Duplicate entry '254' for key 'PRIMARY' +select last_insert_id(); +last_insert_id() +255 +insert into t1 set i = null; +ERROR HY000: Failed to read auto-increment value from storage engine +select last_insert_id(); +last_insert_id() +255 +drop table t1; +create table t1 (i tinyint unsigned not null auto_increment, key (i)); +insert into t1 set i = 254; +insert into t1 set i = null; +select last_insert_id(); +last_insert_id() +255 +insert into t1 set i = null; +ERROR HY000: Failed to read auto-increment value from storage engine +select last_insert_id(); +last_insert_id() +255 +drop table t1; +create table t1 (i tinyint unsigned not null auto_increment primary key, b int, unique (b)); +insert into t1 values (NULL, 10); +select last_insert_id(); +last_insert_id() +1 +insert into t1 values (NULL, 15); +select last_insert_id(); +last_insert_id() +2 +insert into t1 values (NULL, 10); +ERROR 23000: Duplicate entry '10' for key 'b' +select last_insert_id(); +last_insert_id() +2 +drop table t1; +create table t1(a int auto_increment,b int null,primary key(a)); +SET SQL_MODE=NO_AUTO_VALUE_ON_ZERO; +insert into t1(a,b)values(NULL,1); +insert into t1(a,b)values(200,2); +insert into t1(a,b)values(0,3); +insert into t1(b)values(4); +insert into t1(b)values(5); +insert into t1(b)values(6); +insert into t1(b)values(7); +select * from t1 order by b; +a b +1 1 +200 2 +0 3 +201 4 +202 5 +203 6 +204 7 +alter table t1 modify b mediumint; +select * from t1 order by b; +a b +1 1 +200 2 +0 3 +201 4 +202 5 +203 6 +204 7 +create table t2 (a int); +insert t2 values (1),(2); +alter table t2 add b int auto_increment primary key; +select * from t2; +a b +1 1 +2 2 +drop table t2; +delete from t1 where a=0; +update t1 set a=0 where b=5; +select * from t1 order by b; +a b +1 1 +200 2 +201 4 +0 5 +203 6 +204 7 +delete from t1 where a=0; +update t1 set a=NULL where b=6; +ERROR 23000: Column 'a' cannot be null +update t1 set a=300 where b=7; +SET SQL_MODE=''; +insert into t1(a,b)values(NULL,8); +insert into t1(a,b)values(400,9); +insert into t1(a,b)values(0,10); +insert into t1(b)values(11); +insert into t1(b)values(12); +insert into t1(b)values(13); +insert into t1(b)values(14); +select * from t1 order by b; +a b +1 1 +200 2 +201 4 +203 6 +300 7 +301 8 +400 9 +401 10 +402 11 +403 12 +404 13 +405 14 +delete from t1 where a=0; +update t1 set a=0 where b=12; +select * from t1 order by b; +a b +1 1 +200 2 +201 4 +203 6 +300 7 +301 8 +400 9 +401 10 +402 11 +0 12 +404 13 +405 14 +delete from t1 where a=0; +update t1 set a=NULL where b=13; +ERROR 23000: Column 'a' cannot be null +update t1 set a=500 where b=14; +select * from t1 order by b; +a b +1 1 +200 2 +201 4 +203 6 +300 7 +301 8 +400 9 +401 10 +402 11 +404 13 +500 14 +drop table t1; +create table t1 (a bigint); +insert into t1 values (1), (2), (3), (NULL), (NULL); +alter table t1 modify a bigint not null auto_increment primary key; +select * from t1; +a +1 +2 +3 +4 +5 +drop table t1; +create table t1 (a bigint); +insert into t1 values (1), (2), (3), (0), (0); +alter table t1 modify a bigint not null auto_increment primary key; +select * from t1; +a +1 +2 +3 +4 +5 +drop table t1; +create table t1 (a bigint); +insert into t1 values (0), (1), (2), (3); +set sql_mode=NO_AUTO_VALUE_ON_ZERO; +alter table t1 modify a bigint not null auto_increment primary key; +set sql_mode= ''; +select * from t1; +a +0 +1 +2 +3 +drop table t1; +create table t1 (a int auto_increment primary key , b int null); +set sql_mode=NO_AUTO_VALUE_ON_ZERO; +insert into t1 values (0,1),(1,2),(2,3); +select * from t1; +a b +0 1 +1 2 +2 3 +set sql_mode= ''; +alter table t1 modify b varchar(255); +insert into t1 values (0,4); +select * from t1; +a b +0 1 +1 2 +2 3 +3 4 +drop table t1; +CREATE TABLE t1 ( a INT AUTO_INCREMENT, b BLOB, PRIMARY KEY (a,b(10))); +INSERT INTO t1 (b) VALUES ('aaaa'); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (b) VALUES (''); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +INSERT INTO t1 (b) VALUES ('bbbb'); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE IF EXISTS t1; +CREATE TABLE `t1` ( +t1_name VARCHAR(255) DEFAULT NULL, +t1_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, +KEY (t1_name), +PRIMARY KEY (t1_id) +) AUTO_INCREMENT = 1000; +INSERT INTO t1 (t1_name) VALUES('MySQL'); +INSERT INTO t1 (t1_name) VALUES('MySQL'); +INSERT INTO t1 (t1_name) VALUES('MySQL'); +SELECT * from t1; +t1_name t1_id +MySQL 1000 +MySQL 1001 +MySQL 1002 +SHOW CREATE TABLE `t1`; +Table Create Table +t1 CREATE TABLE `t1` ( + `t1_name` varchar(255) DEFAULT NULL, + `t1_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`t1_id`), + KEY `t1_name` (`t1_name`) +) ENGINE=PBXT AUTO_INCREMENT=1000 DEFAULT CHARSET=latin1 +DROP TABLE `t1`; +create table t1(a int not null auto_increment primary key); +create table t2(a int not null auto_increment primary key, t1a int); +insert into t1 values(NULL); +insert into t2 values (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()); +insert into t1 values (NULL); +insert into t2 values (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()), +(NULL, LAST_INSERT_ID()); +insert into t1 values (NULL); +insert into t2 values (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()), +(NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()); +select * from t2; +a t1a +1 1 +2 1 +3 2 +4 2 +5 2 +6 3 +7 3 +8 3 +9 3 +drop table t1, t2; +End of 4.1 tests +CREATE TABLE t1 ( `a` int(11) NOT NULL auto_increment, `b` int(11) default NULL,PRIMARY KEY (`a`),UNIQUE KEY `b` (`b`)); +insert into t1 (b) values (1); +replace into t1 (b) values (2), (1), (3); +select * from t1; +a b +2 2 +3 1 +4 3 +truncate table t1; +insert into t1 (b) values (1); +replace into t1 (b) values (2); +replace into t1 (b) values (1); +replace into t1 (b) values (3); +select * from t1 order by a; +a b +2 2 +3 1 +4 3 +drop table t1; +create table t1 (rowid int not null auto_increment, val int not null,primary +key (rowid), unique(val)); +replace into t1 (val) values ('1'),('2'); +replace into t1 (val) values ('1'),('2'); +insert into t1 (val) values ('1'),('2'); +ERROR 23000: Duplicate entry '1' for key 'val' +select * from t1; +rowid val +3 1 +4 2 +drop table t1; +create table t1 (a int not null auto_increment primary key, val int); +insert into t1 (val) values (1); +update t1 set a=2 where a=1; +insert into t1 (val) values (1); +select * from t1 order by a; +a val +2 1 +3 1 +drop table t1; +CREATE TABLE t1 (t1 INT(10) PRIMARY KEY, t2 INT(10)); +INSERT INTO t1 VALUES(0, 0); +INSERT INTO t1 VALUES(1, 1); +ALTER TABLE t1 CHANGE t1 t1 INT(10) auto_increment; +ERROR 23000: ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '1' for key 'PRIMARY' +DROP TABLE t1; +create table t1 (a int primary key auto_increment, b int, c int, d timestamp default current_timestamp, unique(b),unique(c)); +insert into t1 values(null,1,1,now()); +insert into t1 values(null,0,0,null); +replace into t1 values(null,1,0,null); +select last_insert_id(); +last_insert_id() +3 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/bench_count_distinct.result b/mysql-test/suite/pbxt/r/bench_count_distinct.result new file mode 100644 index 00000000000..79e12afd237 --- /dev/null +++ b/mysql-test/suite/pbxt/r/bench_count_distinct.result @@ -0,0 +1,11 @@ +drop table if exists t1; +create table t1(n int not null, key(n)) delay_key_write = 1; +select count(distinct n) from t1; +count(distinct n) +100 +explain extended select count(distinct n) from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL n 4 NULL 200 100.00 Using index +Warnings: +Note 1003 select count(distinct `test`.`t1`.`n`) AS `count(distinct n)` from `test`.`t1` +drop table t1; diff --git a/mysql-test/suite/pbxt/r/bigint.result b/mysql-test/suite/pbxt/r/bigint.result new file mode 100644 index 00000000000..100d439d460 --- /dev/null +++ b/mysql-test/suite/pbxt/r/bigint.result @@ -0,0 +1,354 @@ +drop table if exists t1, t2; +select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296; +0 256 00000000000000065536 2147483647 -2147483648 2147483648 4294967296 +0 256 65536 2147483647 -2147483648 2147483648 4294967296 +select 9223372036854775807,-009223372036854775808; +9223372036854775807 -009223372036854775808 +9223372036854775807 -9223372036854775808 +select +9999999999999999999,-9999999999999999999; +9999999999999999999 -9999999999999999999 +9999999999999999999 -9999999999999999999 +select cast(9223372036854775808 as unsigned)+1; +cast(9223372036854775808 as unsigned)+1 +9223372036854775809 +select 9223372036854775808+1; +9223372036854775808+1 +9223372036854775809 +select -(0-3),round(-(0-3)), round(9999999999999999999); +-(0-3) round(-(0-3)) round(9999999999999999999) +3 3 9999999999999999999 +select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001; +1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001 +1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001 +select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001; +-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001 +-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001 +select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16); +conv(1,10,16) conv((1<<2)-1,10,16) conv((1<<10)-2,10,16) conv((1<<16)-3,10,16) conv((1<<25)-4,10,16) conv((1<<31)-5,10,16) conv((1<<36)-6,10,16) conv((1<<47)-7,10,16) conv((1<<48)-8,10,16) conv((1<<55)-9,10,16) conv((1<<56)-10,10,16) conv((1<<63)-11,10,16) +1 3 3FE FFFD 1FFFFFC 7FFFFFFB FFFFFFFFA 7FFFFFFFFFF9 FFFFFFFFFFF8 7FFFFFFFFFFFF7 FFFFFFFFFFFFF6 7FFFFFFFFFFFFFF5 +create table t1 (a bigint unsigned not null, primary key(a)); +insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612); +select * from t1; +a +18446744073709551612 +18446744073709551613 +18446744073709551614 +18446744073709551615 +select * from t1 where a=18446744073709551615; +a +18446744073709551615 +delete from t1 where a=18446744073709551615; +select * from t1; +a +18446744073709551612 +18446744073709551613 +18446744073709551614 +drop table t1; +create table t1 ( a int not null default 1, big bigint ); +insert into t1 (big) values (-1),(12345678901234567),(9223372036854775807),(18446744073709551615); +Warnings: +Warning 1264 Out of range value for column 'big' at row 4 +select * from t1; +a big +1 -1 +1 12345678901234567 +1 9223372036854775807 +1 9223372036854775807 +select min(big),max(big),max(big)-1 from t1; +min(big) max(big) max(big)-1 +-1 9223372036854775807 9223372036854775806 +select min(big),max(big),max(big)-1 from t1 group by a; +min(big) max(big) max(big)-1 +-1 9223372036854775807 9223372036854775806 +alter table t1 modify big bigint unsigned not null; +Warnings: +Warning 1264 Out of range value for column 'big' at row 1 +select min(big),max(big),max(big)-1 from t1; +min(big) max(big) max(big)-1 +0 9223372036854775807 9223372036854775806 +select min(big),max(big),max(big)-1 from t1 group by a; +min(big) max(big) max(big)-1 +0 9223372036854775807 9223372036854775806 +insert into t1 (big) values (18446744073709551615); +select * from t1; +a big +1 0 +1 12345678901234567 +1 9223372036854775807 +1 9223372036854775807 +1 18446744073709551615 +select min(big),max(big),max(big)-1 from t1; +min(big) max(big) max(big)-1 +0 18446744073709551615 18446744073709551614 +select min(big),max(big),max(big)-1 from t1 group by a; +min(big) max(big) max(big)-1 +0 18446744073709551615 18446744073709551614 +alter table t1 add key (big); +select min(big),max(big),max(big)-1 from t1; +min(big) max(big) max(big)-1 +0 18446744073709551615 18446744073709551614 +select min(big),max(big),max(big)-1 from t1 group by a; +min(big) max(big) max(big)-1 +0 18446744073709551615 18446744073709551614 +alter table t1 modify big bigint not null; +Warnings: +Warning 1264 Out of range value for column 'big' at row 5 +select * from t1; +a big +1 0 +1 12345678901234567 +1 9223372036854775807 +1 9223372036854775807 +1 9223372036854775807 +select min(big),max(big),max(big)-1 from t1; +min(big) max(big) max(big)-1 +0 9223372036854775807 9223372036854775806 +select min(big),max(big),max(big)-1 from t1 group by a; +min(big) max(big) max(big)-1 +0 9223372036854775807 9223372036854775806 +drop table t1; +create table t1 (id bigint auto_increment primary key, a int) auto_increment=9999999999; +insert into t1 values (null,1); +select * from t1; +id a +9999999999 1 +select * from t1 limit 9999999999; +id a +9999999999 1 +drop table t1; +CREATE TABLE t1 ( quantity decimal(60,0)); +insert into t1 values (10000000000000000000); +insert into t1 values (10000000000000000000.0); +insert into t1 values ('10000000000000000000'); +select * from t1; +quantity +10000000000000000000 +10000000000000000000 +10000000000000000000 +drop table t1; +SELECT '0x8000000000000001'+0; +'0x8000000000000001'+0 +0 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: '0x8000000000000001' +create table t1 ( +value64 bigint unsigned not null, +value32 integer not null, +primary key(value64, value32) +); +create table t2 ( +value64 bigint unsigned not null, +value32 integer not null, +primary key(value64, value32) +); +insert into t1 values(17156792991891826145, 1); +insert into t1 values( 9223372036854775807, 2); +insert into t2 values(17156792991891826145, 3); +insert into t2 values( 9223372036854775807, 4); +select * from t1; +value64 value32 +9223372036854775807 2 +17156792991891826145 1 +select * from t2; +value64 value32 +9223372036854775807 4 +17156792991891826145 3 +select * from t1, t2 where t1.value64=17156792991891826145 and +t2.value64=17156792991891826145; +value64 value32 value64 value32 +17156792991891826145 1 17156792991891826145 3 +select * from t1, t2 where t1.value64=17156792991891826145 and +t2.value64=t1.value64; +value64 value32 value64 value32 +17156792991891826145 1 17156792991891826145 3 +select * from t1, t2 where t1.value64= 9223372036854775807 and +t2.value64=9223372036854775807; +value64 value32 value64 value32 +9223372036854775807 2 9223372036854775807 4 +select * from t1, t2 where t1.value64= 9223372036854775807 and +t2.value64=t1.value64; +value64 value32 value64 value32 +9223372036854775807 2 9223372036854775807 4 +drop table t1, t2; +create table t1 select 1 as 'a'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(1) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select 9223372036854775809 as 'a'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(19) unsigned NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t1; +a +9223372036854775809 +drop table t1; +DROP DATABASE IF EXISTS `scott`; +Warnings: +Note 1008 Can't drop database 'scott'; database doesn't exist +create table t1 (a char(100), b varchar(100), c text, d blob); +insert into t1 values( +18446744073709551615,18446744073709551615, +18446744073709551615, 18446744073709551615 +); +insert into t1 values (-1 | 0,-1 | 0,-1 | 0 ,-1 | 0); +select * from t1; +a b c d +18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +18446744073709551615 18446744073709551615 18446744073709551615 18446744073709551615 +drop table t1; +create table t1 ( quantity decimal(2) unsigned); +insert into t1 values (500), (-500), (~0), (-1); +Warnings: +Warning 1264 Out of range value for column 'quantity' at row 1 +Warning 1264 Out of range value for column 'quantity' at row 2 +Warning 1264 Out of range value for column 'quantity' at row 3 +Warning 1264 Out of range value for column 'quantity' at row 4 +select * from t1; +quantity +99 +0 +99 +0 +drop table t1; +CREATE TABLE t1 ( +`col1` INT(1) NULL, +`col2` INT(2) NULL, +`col3` INT(3) NULL, +`col4` INT(4) NULL, +`col5` INT(5) NULL, +`col6` INT(6) NULL, +`col7` INT(7) NULL, +`col8` INT(8) NULL, +`col9` INT(9) NULL, +`col10` BIGINT(10) NULL, +`col11` BIGINT(11) NULL, +`col12` BIGINT(12) NULL, +`col13` BIGINT(13) NULL, +`col14` BIGINT(14) NULL, +`col15` BIGINT(15) NULL, +`col16` BIGINT(16) NULL, +`col17` BIGINT(17) NULL, +`col18` BIGINT(18) NULL, +`col19` DECIMAL(19, 0) NULL, +`col20` DECIMAL(20, 0) NULL, +`col21` DECIMAL(21, 0) NULL, +`col22` DECIMAL(22, 0) NULL, +`col23` DECIMAL(23, 0) NULL, +`col24` DECIMAL(24, 0) NULL, +`col25` DECIMAL(25, 0) NULL, +`col26` DECIMAL(26, 0) NULL, +`col27` DECIMAL(27, 0) NULL, +`col28` DECIMAL(28, 0) NULL, +`col29` DECIMAL(29, 0) NULL, +`col30` DECIMAL(30, 0) NULL, +`col31` DECIMAL(31, 0) NULL, +`col32` DECIMAL(32, 0) NULL, +`col33` DECIMAL(33, 0) NULL, +`col34` DECIMAL(34, 0) NULL, +`col35` DECIMAL(35, 0) NULL, +`col36` DECIMAL(36, 0) NULL, +`col37` DECIMAL(37, 0) NULL, +`col38` DECIMAL(38, 0) NULL, +`fix1` DECIMAL(38, 1) NULL, +`fix2` DECIMAL(38, 2) NULL, +`fix3` DECIMAL(38, 3) NULL, +`fix4` DECIMAL(38, 4) NULL, +`fix5` DECIMAL(38, 5) NULL, +`fix6` DECIMAL(38, 6) NULL, +`fix7` DECIMAL(38, 7) NULL, +`fix8` DECIMAL(38, 8) NULL, +`fix9` DECIMAL(38, 9) NULL, +`fix10` DECIMAL(38, 10) NULL, +`fix11` DECIMAL(38, 11) NULL, +`fix12` DECIMAL(38, 12) NULL, +`fix13` DECIMAL(38, 13) NULL, +`fix14` DECIMAL(38, 14) NULL, +`fix15` DECIMAL(38, 15) NULL, +`fix16` DECIMAL(38, 16) NULL, +`fix17` DECIMAL(38, 17) NULL, +`fix18` DECIMAL(38, 18) NULL, +`fix19` DECIMAL(38, 19) NULL, +`fix20` DECIMAL(38, 20) NULL, +`fix21` DECIMAL(38, 21) NULL, +`fix22` DECIMAL(38, 22) NULL, +`fix23` DECIMAL(38, 23) NULL, +`fix24` DECIMAL(38, 24) NULL, +`fix25` DECIMAL(38, 25) NULL, +`fix26` DECIMAL(38, 26) NULL, +`fix27` DECIMAL(38, 27) NULL, +`fix28` DECIMAL(38, 28) NULL, +`fix29` DECIMAL(38, 29) NULL, +`fix30` DECIMAL(38, 30) NULL +); +INSERT INTO t1(`col1`, `col2`, `col3`, `col4`, `col5`, `col6`, `col7`, `col8`, `col9`, `col10`, `col11`, `col12`, `col13`, `col14`, `col15`, `col16`, `col17`, `col18`, `col19`, `col20`, `col21`, `col22`, `col23`, `col24`, `col25`, `col26`, `col27`, `col28`, `col29`, `col30`, `col31`, `col32`, `col33`, `col34`, `col35`, `col36`, `col37`, `col38`, `fix1`, `fix2`, `fix3`, `fix4`, `fix5`, `fix6`, `fix7`, `fix8`, `fix9`, `fix10`, `fix11`, `fix12`, `fix13`, `fix14`, `fix15`, `fix16`, `fix17`, `fix18`, `fix19`, `fix20`, `fix21`, `fix22`, `fix23`, `fix24`, `fix25`, `fix26`, `fix27`, `fix28`, `fix29`, `fix30`) +VALUES (9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, +9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, +999999999999999, 9999999999999999, 99999999999999999, 999999999999999999, +9999999999999999999, 99999999999999999999, 999999999999999999999, +9999999999999999999999, 99999999999999999999999, 999999999999999999999999, +9999999999999999999999999, 99999999999999999999999999, +999999999999999999999999999, 9999999999999999999999999999, +99999999999999999999999999999, 999999999999999999999999999999, +9999999999999999999999999999999, 99999999999999999999999999999999, +999999999999999999999999999999999, 9999999999999999999999999999999999, +99999999999999999999999999999999999, 999999999999999999999999999999999999, +9999999999999999999999999999999999999, 99999999999999999999999999999999999999, +9999999999999999999999999999999999999.9, +999999999999999999999999999999999999.99, +99999999999999999999999999999999999.999, +9999999999999999999999999999999999.9999, +999999999999999999999999999999999.99999, +99999999999999999999999999999999.999999, +9999999999999999999999999999999.9999999, +999999999999999999999999999999.99999999, +99999999999999999999999999999.999999999, +9999999999999999999999999999.9999999999, +999999999999999999999999999.99999999999, +99999999999999999999999999.999999999999, +9999999999999999999999999.9999999999999, +999999999999999999999999.99999999999999, +99999999999999999999999.999999999999999, +9999999999999999999999.9999999999999999, +999999999999999999999.99999999999999999, +99999999999999999999.999999999999999999, +9999999999999999999.9999999999999999999, +999999999999999999.99999999999999999999, +99999999999999999.999999999999999999999, +9999999999999999.9999999999999999999999, +999999999999999.99999999999999999999999, +99999999999999.999999999999999999999999, +9999999999999.9999999999999999999999999, +999999999999.99999999999999999999999999, +99999999999.999999999999999999999999999, +9999999999.9999999999999999999999999999, +999999999.99999999999999999999999999999, +99999999.999999999999999999999999999999); +SELECT * FROM t1; +col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 col11 col12 col13 col14 col15 col16 col17 col18 col19 col20 col21 col22 col23 col24 col25 col26 col27 col28 col29 col30 col31 col32 col33 col34 col35 col36 col37 col38 fix1 fix2 fix3 fix4 fix5 fix6 fix7 fix8 fix9 fix10 fix11 fix12 fix13 fix14 fix15 fix16 fix17 fix18 fix19 fix20 fix21 fix22 fix23 fix24 fix25 fix26 fix27 fix28 fix29 fix30 +9 99 999 9999 99999 999999 9999999 99999999 999999999 9999999999 99999999999 999999999999 9999999999999 99999999999999 999999999999999 9999999999999999 99999999999999999 999999999999999999 9999999999999999999 99999999999999999999 999999999999999999999 9999999999999999999999 99999999999999999999999 999999999999999999999999 9999999999999999999999999 99999999999999999999999999 999999999999999999999999999 9999999999999999999999999999 99999999999999999999999999999 999999999999999999999999999999 9999999999999999999999999999999 99999999999999999999999999999999 999999999999999999999999999999999 9999999999999999999999999999999999 99999999999999999999999999999999999 999999999999999999999999999999999999 9999999999999999999999999999999999999 99999999999999999999999999999999999999 9999999999999999999999999999999999999.9 999999999999999999999999999999999999.99 99999999999999999999999999999999999.999 9999999999999999999999999999999999.9999 999999999999999999999999999999999.99999 99999999999999999999999999999999.999999 9999999999999999999999999999999.9999999 999999999999999999999999999999.99999999 99999999999999999999999999999.999999999 9999999999999999999999999999.9999999999 999999999999999999999999999.99999999999 99999999999999999999999999.999999999999 9999999999999999999999999.9999999999999 999999999999999999999999.99999999999999 99999999999999999999999.999999999999999 9999999999999999999999.9999999999999999 999999999999999999999.99999999999999999 99999999999999999999.999999999999999999 9999999999999999999.9999999999999999999 999999999999999999.99999999999999999999 99999999999999999.999999999999999999999 9999999999999999.9999999999999999999999 999999999999999.99999999999999999999999 99999999999999.999999999999999999999999 9999999999999.9999999999999999999999999 999999999999.99999999999999999999999999 99999999999.999999999999999999999999999 9999999999.9999999999999999999999999999 999999999.99999999999999999999999999999 99999999.999999999999999999999999999999 +DROP TABLE t1; +create table t1 (bigint_col bigint unsigned); +insert into t1 values (17666000000000000000); +select * from t1 where bigint_col=17666000000000000000; +bigint_col +17666000000000000000 +select * from t1 where bigint_col='17666000000000000000'; +bigint_col +17666000000000000000 +drop table t1; + +bug 19955 -- mod is signed with bigint +select cast(10000002383263201056 as unsigned) mod 50 as result; +result +6 +create table t1 (c1 bigint unsigned); +insert into t1 values (10000002383263201056); +select c1 mod 50 as result from t1; +result +6 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/binary.result b/mysql-test/suite/pbxt/r/binary.result new file mode 100644 index 00000000000..880965a8877 --- /dev/null +++ b/mysql-test/suite/pbxt/r/binary.result @@ -0,0 +1,162 @@ +drop table if exists t1,t2; +create table t1 (name char(20) not null, primary key (name)); +create table t2 (name char(20) binary not null, primary key (name)); +insert into t1 values ("å"); +insert into t1 values ("ä"); +insert into t1 values ("ö"); +insert into t2 select * from t1; +select * from t1 order by name; +name +å +ä +ö +select concat("*",name,"*") from t1 order by 1; +concat("*",name,"*") +*å* +*ä* +*ö* +select min(name),min(concat("*",name,"*")),max(name),max(concat("*",name,"*")) from t1; +min(name) min(concat("*",name,"*")) max(name) max(concat("*",name,"*")) +å *å* ö *ö* +select * from t2 order by name; +name +ä +å +ö +select concat("*",name,"*") from t2 order by 1; +concat("*",name,"*") +*ä* +*å* +*ö* +select min(name),min(concat("*",name,"*")),max(name),max(concat("*",name,"*")) from t2; +min(name) min(concat("*",name,"*")) max(name) max(concat("*",name,"*")) +ä *ä* ö *ö* +select name from t1 where name between 'Ä' and 'Ö'; +name +ä +ö +select name from t2 where name between 'ä' and 'ö'; +name +ä +å +ö +select name from t2 where name between 'Ä' and 'Ö'; +name +drop table t1,t2; +create table t1 (a char(10) not null, b char(10) binary not null,key (a), key(b)); +insert into t1 values ("hello ","hello "),("hello2 ","hello2 "); +select concat("-",a,"-",b,"-") from t1 where a="hello"; +concat("-",a,"-",b,"-") +-hello-hello- +select concat("-",a,"-",b,"-") from t1 where a="hello "; +concat("-",a,"-",b,"-") +-hello-hello- +select concat("-",a,"-",b,"-") from t1 ignore index (a) where a="hello "; +concat("-",a,"-",b,"-") +-hello-hello- +select concat("-",a,"-",b,"-") from t1 where b="hello"; +concat("-",a,"-",b,"-") +-hello-hello- +select concat("-",a,"-",b,"-") from t1 where b="hello "; +concat("-",a,"-",b,"-") +-hello-hello- +select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; +concat("-",a,"-",b,"-") +-hello-hello- +alter table t1 modify b tinytext not null, drop key b, add key (b(100)); +select concat("-",a,"-",b,"-") from t1; +concat("-",a,"-",b,"-") +-hello-hello- +-hello2-hello2- +select concat("-",a,"-",b,"-") from t1 where b="hello "; +concat("-",a,"-",b,"-") +-hello-hello- +select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; +concat("-",a,"-",b,"-") +-hello-hello- +drop table t1; +create table t1 (b char(8)); +insert into t1 values(NULL); +select b from t1 where binary b like ''; +b +select b from t1 group by binary b like ''; +b +NULL +select b from t1 having binary b like ''; +b +drop table t1; +create table t1 (a char(3) binary, b binary(3)); +insert into t1 values ('aaa','bbb'),('AAA','BBB'); +select upper(a),upper(b) from t1; +upper(a) upper(b) +AAA bbb +AAA BBB +select lower(a),lower(b) from t1; +lower(a) lower(b) +aaa bbb +aaa BBB +select * from t1 where upper(a)='AAA'; +a b +aaa bbb +AAA BBB +select * from t1 where lower(a)='aaa'; +a b +aaa bbb +AAA BBB +select * from t1 where upper(b)='BBB'; +a b +AAA BBB +select * from t1 where lower(b)='bbb'; +a b +aaa bbb +select charset(a), charset(b), charset(binary 'ccc') from t1 limit 1; +charset(a) charset(b) charset(binary 'ccc') +latin1 binary binary +select collation(a), collation(b), collation(binary 'ccc') from t1 limit 1; +collation(a) collation(b) collation(binary 'ccc') +latin1_bin binary binary +drop table t1; +create table t1( firstname char(20), lastname char(20)); +insert into t1 values ("john","doe"),("John","Doe"); +select * from t1 where firstname='john' and firstname like binary 'john'; +firstname lastname +john doe +select * from t1 where firstname='john' and binary 'john' = firstname; +firstname lastname +john doe +select * from t1 where firstname='john' and firstname = binary 'john'; +firstname lastname +john doe +select * from t1 where firstname='John' and firstname like binary 'john'; +firstname lastname +john doe +select * from t1 where firstname='john' and firstname like binary 'John'; +firstname lastname +John Doe +drop table t1; +create table t1 (a binary); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` binary(1) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (col1 binary(4)); +insert into t1 values ('a'),('a '); +select hex(col1) from t1; +hex(col1) +61000000 +61200000 +alter table t1 modify col1 binary(10); +select hex(col1) from t1; +hex(col1) +61000000000000000000 +61200000000000000000 +insert into t1 values ('b'),('b '); +select hex(col1) from t1; +hex(col1) +61000000000000000000 +61200000000000000000 +62000000000000000000 +62200000000000000000 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/bool.result b/mysql-test/suite/pbxt/r/bool.result new file mode 100644 index 00000000000..184046a2d6f --- /dev/null +++ b/mysql-test/suite/pbxt/r/bool.result @@ -0,0 +1,88 @@ +DROP TABLE IF EXISTS t1; +SELECT IF(NULL AND 1, 1, 2), IF(1 AND NULL, 1, 2); +IF(NULL AND 1, 1, 2) IF(1 AND NULL, 1, 2) +2 2 +SELECT NULL AND 1, 1 AND NULL, 0 AND NULL, NULL and 0; +NULL AND 1 1 AND NULL 0 AND NULL NULL and 0 +NULL NULL 0 0 +create table t1 (a int); +insert into t1 values (0),(1),(NULL); +SELECT * FROM t1 WHERE IF(a AND 1, 0, 1); +a +0 +NULL +SELECT * FROM t1 WHERE IF(1 AND a, 0, 1); +a +0 +NULL +SELECT * FROM t1 where NOT(a AND 1); +a +0 +SELECT * FROM t1 where NOT(1 AND a); +a +0 +SELECT * FROM t1 where (a AND 1)=0; +a +0 +SELECT * FROM t1 where (1 AND a)=0; +a +0 +SELECT * FROM t1 where (1 AND a)=1; +a +1 +SELECT * FROM t1 where (1 AND a) IS NULL; +a +NULL +set sql_mode='high_not_precedence'; +select * from t1 where not a between 2 and 3; +a +set sql_mode=default; +select * from t1 where not a between 2 and 3; +a +0 +1 +select a, a is false, a is true, a is unknown from t1; +a a is false a is true a is unknown +0 1 0 0 +1 0 1 0 +NULL 0 0 1 +select a, a is not false, a is not true, a is not unknown from t1; +a a is not false a is not true a is not unknown +0 0 1 1 +1 1 0 1 +NULL 1 1 0 +SET @a=0, @b=0; +SELECT * FROM t1 WHERE NULL AND (@a:=@a+1); +a +SELECT * FROM t1 WHERE NOT(a>=0 AND NULL AND (@b:=@b+1)); +a +SELECT * FROM t1 WHERE a=2 OR (NULL AND (@a:=@a+1)); +a +SELECT * FROM t1 WHERE NOT(a=2 OR (NULL AND (@b:=@b+1))); +a +DROP TABLE t1; +create table t1 (a int, b int); +insert into t1 values(null, null), (0, null), (1, null), (null, 0), (null, 1), (0, 0), (0, 1), (1, 0), (1, 1); +select ifnull(A, 'N') as A, ifnull(B, 'N') as B, ifnull(not A, 'N') as nA, ifnull(not B, 'N') as nB, ifnull(A and B, 'N') as AB, ifnull(not (A and B), 'N') as `n(AB)`, ifnull((not A or not B), 'N') as nAonB, ifnull(A or B, 'N') as AoB, ifnull(not(A or B), 'N') as `n(AoB)`, ifnull(not A and not B, 'N') as nAnB from t1; +A B nA nB AB n(AB) nAonB AoB n(AoB) nAnB +N N N N N N N N N N +0 N 1 N 0 1 1 N N N +1 N 0 N N N N 1 0 0 +N 0 N 1 0 1 1 N N N +N 1 N 0 N N N 1 0 0 +0 0 1 1 0 1 1 0 1 1 +0 1 1 0 0 1 1 1 0 0 +1 0 0 1 0 1 1 1 0 0 +1 1 0 0 1 0 0 1 0 0 +select ifnull(A=1, 'N') as A, ifnull(B=1, 'N') as B, ifnull(not (A=1), 'N') as nA, ifnull(not (B=1), 'N') as nB, ifnull((A=1) and (B=1), 'N') as AB, ifnull(not ((A=1) and (B=1)), 'N') as `n(AB)`, ifnull((not (A=1) or not (B=1)), 'N') as nAonB, ifnull((A=1) or (B=1), 'N') as AoB, ifnull(not((A=1) or (B=1)), 'N') as `n(AoB)`, ifnull(not (A=1) and not (B=1), 'N') as nAnB from t1; +A B nA nB AB n(AB) nAonB AoB n(AoB) nAnB +N N N N N N N N N N +0 N 1 N 0 1 1 N N N +1 N 0 N N N N 1 0 0 +N 0 N 1 0 1 1 N N N +N 1 N 0 N N N 1 0 0 +0 0 1 1 0 1 1 0 1 1 +0 1 1 0 0 1 1 1 0 0 +1 0 0 1 0 1 1 1 0 0 +1 1 0 0 1 0 0 1 0 0 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/bulk_replace.result b/mysql-test/suite/pbxt/r/bulk_replace.result new file mode 100644 index 00000000000..6a010f75abb --- /dev/null +++ b/mysql-test/suite/pbxt/r/bulk_replace.result @@ -0,0 +1,11 @@ +drop table if exists t1; +CREATE TABLE t1 (a int, unique (a), b int not null, unique(b), c int not null, index(c)); +replace into t1 values (1,1,1),(2,2,2),(3,1,3); +select * from t1 order by a; +a b c +2 2 2 +3 1 3 +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; diff --git a/mysql-test/suite/pbxt/r/case.result b/mysql-test/suite/pbxt/r/case.result new file mode 100644 index 00000000000..82485673e33 --- /dev/null +++ b/mysql-test/suite/pbxt/r/case.result @@ -0,0 +1,202 @@ +drop table if exists t1,t2; +select CASE "b" when "a" then 1 when "b" then 2 END; +CASE "b" when "a" then 1 when "b" then 2 END +2 +select CASE "c" when "a" then 1 when "b" then 2 END; +CASE "c" when "a" then 1 when "b" then 2 END +NULL +select CASE "c" when "a" then 1 when "b" then 2 ELSE 3 END; +CASE "c" when "a" then 1 when "b" then 2 ELSE 3 END +3 +select CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END; +CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END +ok +select CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END; +CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END +ok +select CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end; +CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end +a +select CASE when 1=0 then "true" else "false" END; +CASE when 1=0 then "true" else "false" END +false +select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END; +CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END +one +explain extended select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select (case 1 when 1 then 'one' when 2 then 'two' else 'more' end) AS `CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END` +select CASE 2.0 when 1 then "one" WHEN 2.0 then "two" ELSE "more" END; +CASE 2.0 when 1 then "one" WHEN 2.0 then "two" ELSE "more" END +two +select (CASE "two" when "one" then "1" WHEN "two" then "2" END) | 0; +(CASE "two" when "one" then "1" WHEN "two" then "2" END) | 0 +2 +select (CASE "two" when "one" then 1.00 WHEN "two" then 2.00 END) +0.0; +(CASE "two" when "one" then 1.00 WHEN "two" then 2.00 END) +0.0 +2.00 +select case 1/0 when "a" then "true" else "false" END; +case 1/0 when "a" then "true" else "false" END +false +select case 1/0 when "a" then "true" END; +case 1/0 when "a" then "true" END +NULL +select (case 1/0 when "a" then "true" END) | 0; +(case 1/0 when "a" then "true" END) | 0 +NULL +select (case 1/0 when "a" then "true" END) + 0.0; +(case 1/0 when "a" then "true" END) + 0.0 +NULL +select case when 1>0 then "TRUE" else "FALSE" END; +case when 1>0 then "TRUE" else "FALSE" END +TRUE +select case when 1<0 then "TRUE" else "FALSE" END; +case when 1<0 then "TRUE" else "FALSE" END +FALSE +create table t1 (a int); +insert into t1 values(1),(2),(3),(4); +select case a when 1 then 2 when 2 then 3 else 0 end as fcase, count(*) from t1 group by fcase; +fcase count(*) +0 2 +2 1 +3 1 +explain extended select case a when 1 then 2 when 2 then 3 else 0 end as fcase, count(*) from t1 group by fcase; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using temporary; Using filesort +Warnings: +Note 1003 select (case `test`.`t1`.`a` when 1 then 2 when 2 then 3 else 0 end) AS `fcase`,count(0) AS `count(*)` from `test`.`t1` group by (case `test`.`t1`.`a` when 1 then 2 when 2 then 3 else 0 end) +select case a when 1 then "one" when 2 then "two" else "nothing" end as fcase, count(*) from t1 group by fcase; +fcase count(*) +nothing 2 +one 1 +two 1 +drop table t1; +create table t1 (row int not null, col int not null, val varchar(255) not null); +insert into t1 values (1,1,'orange'),(1,2,'large'),(2,1,'yellow'),(2,2,'medium'),(3,1,'green'),(3,2,'small'); +select max(case col when 1 then val else null end) as color from t1 group by row; +color +orange +yellow +green +drop table t1; +SET NAMES latin1; +CREATE TABLE t1 SELECT +CASE WHEN 1 THEN _latin1'a' COLLATE latin1_danish_ci ELSE _latin1'a' END AS c1, +CASE WHEN 1 THEN _latin1'a' ELSE _latin1'a' COLLATE latin1_danish_ci END AS c2, +CASE WHEN 1 THEN 'a' ELSE 1 END AS c3, +CASE WHEN 1 THEN 1 ELSE 'a' END AS c4, +CASE WHEN 1 THEN 'a' ELSE 1.0 END AS c5, +CASE WHEN 1 THEN 1.0 ELSE 'a' END AS c6, +CASE WHEN 1 THEN 1 ELSE 1.0 END AS c7, +CASE WHEN 1 THEN 1.0 ELSE 1 END AS c8, +CASE WHEN 1 THEN 1.0 END AS c9, +CASE WHEN 1 THEN 0.1e1 else 0.1 END AS c10, +CASE WHEN 1 THEN 0.1e1 else 1 END AS c11, +CASE WHEN 1 THEN 0.1e1 else '1' END AS c12 +; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(1) CHARACTER SET latin1 COLLATE latin1_danish_ci NOT NULL DEFAULT '', + `c2` varchar(1) CHARACTER SET latin1 COLLATE latin1_danish_ci NOT NULL DEFAULT '', + `c3` varbinary(1) NOT NULL DEFAULT '', + `c4` varbinary(1) NOT NULL DEFAULT '', + `c5` varbinary(4) NOT NULL DEFAULT '', + `c6` varbinary(4) NOT NULL DEFAULT '', + `c7` decimal(2,1) NOT NULL DEFAULT '0.0', + `c8` decimal(2,1) NOT NULL DEFAULT '0.0', + `c9` decimal(2,1) DEFAULT NULL, + `c10` double NOT NULL DEFAULT '0', + `c11` double NOT NULL DEFAULT '0', + `c12` varbinary(5) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLE t1; +SELECT CASE +WHEN 1 +THEN _latin1'a' COLLATE latin1_danish_ci +ELSE _latin1'a' COLLATE latin1_swedish_ci +END; +ERROR HY000: Illegal mix of collations (latin1_danish_ci,EXPLICIT) and (latin1_swedish_ci,EXPLICIT) for operation 'case' +SELECT CASE _latin1'a' COLLATE latin1_general_ci +WHEN _latin1'a' COLLATE latin1_danish_ci THEN 1 +WHEN _latin1'a' COLLATE latin1_swedish_ci THEN 2 +END; +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_danish_ci,EXPLICIT), (latin1_swedish_ci,EXPLICIT) for operation 'case' +SELECT +CASE _latin1'a' COLLATE latin1_general_ci WHEN _latin1'A' THEN '1' ELSE 2 END, +CASE _latin1'a' COLLATE latin1_bin WHEN _latin1'A' THEN '1' ELSE 2 END, +CASE _latin1'a' WHEN _latin1'A' COLLATE latin1_swedish_ci THEN '1' ELSE 2 END, +CASE _latin1'a' WHEN _latin1'A' COLLATE latin1_bin THEN '1' ELSE 2 END +; +CASE _latin1'a' COLLATE latin1_general_ci WHEN _latin1'A' THEN '1' ELSE 2 END CASE _latin1'a' COLLATE latin1_bin WHEN _latin1'A' THEN '1' ELSE 2 END CASE _latin1'a' WHEN _latin1'A' COLLATE latin1_swedish_ci THEN '1' ELSE 2 END CASE _latin1'a' WHEN _latin1'A' COLLATE latin1_bin THEN '1' ELSE 2 END +1 2 1 2 +CREATE TABLE t1 SELECT COALESCE(_latin1'a',_latin2'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'coalesce' +CREATE TABLE t1 SELECT COALESCE('a' COLLATE latin1_swedish_ci,'b' COLLATE latin1_bin); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'coalesce' +CREATE TABLE t1 SELECT +COALESCE(1), COALESCE(1.0),COALESCE('a'), +COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), +COALESCE('a' COLLATE latin1_bin,'b'); +explain extended SELECT +COALESCE(1), COALESCE(1.0),COALESCE('a'), +COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), +COALESCE('a' COLLATE latin1_bin,'b'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select coalesce(1) AS `COALESCE(1)`,coalesce(1.0) AS `COALESCE(1.0)`,coalesce('a') AS `COALESCE('a')`,coalesce(1,1.0) AS `COALESCE(1,1.0)`,coalesce(1,'1') AS `COALESCE(1,'1')`,coalesce(1.1,'1') AS `COALESCE(1.1,'1')`,coalesce(('a' collate latin1_bin),'b') AS `COALESCE('a' COLLATE latin1_bin,'b')` +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `COALESCE(1)` int(1) NOT NULL DEFAULT '0', + `COALESCE(1.0)` decimal(2,1) NOT NULL DEFAULT '0.0', + `COALESCE('a')` varchar(1) NOT NULL DEFAULT '', + `COALESCE(1,1.0)` decimal(2,1) NOT NULL DEFAULT '0.0', + `COALESCE(1,'1')` varbinary(1) NOT NULL DEFAULT '', + `COALESCE(1.1,'1')` varbinary(4) NOT NULL DEFAULT '', + `COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLE t1; +SELECT 'case+union+test' +UNION +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; +case+union+test +case+union+test +nobug +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; +CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END +nobug +SELECT 'case+union+test' +UNION +SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; +case+union+test +case+union+test +nobug +create table t1(a float, b int default 3); +insert into t1 (a) values (2), (11), (8); +select min(a), min(case when 1=1 then a else NULL end), +min(case when 1!=1 then NULL else a end) +from t1 where b=3 group by b; +min(a) min(case when 1=1 then a else NULL end) min(case when 1!=1 then NULL else a end) +2 2 2 +drop table t1; +CREATE TABLE t1 (EMPNUM INT); +INSERT INTO t1 VALUES (0), (2); +CREATE TABLE t2 (EMPNUM DECIMAL (4, 2)); +INSERT INTO t2 VALUES (0.0), (9.0); +SELECT COALESCE(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, +t1.EMPNUM AS EMPMUM1, t2.EMPNUM AS EMPNUM2 +FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; +CEMPNUM EMPMUM1 EMPNUM2 +0.00 0 0.00 +2.00 2 NULL +SELECT IFNULL(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, +t1.EMPNUM AS EMPMUM1, t2.EMPNUM AS EMPNUM2 +FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; +CEMPNUM EMPMUM1 EMPNUM2 +0.00 0 0.00 +2.00 2 NULL +DROP TABLE t1,t2; diff --git a/mysql-test/suite/pbxt/r/cast.result b/mysql-test/suite/pbxt/r/cast.result new file mode 100644 index 00000000000..bc0c983c8e1 --- /dev/null +++ b/mysql-test/suite/pbxt/r/cast.result @@ -0,0 +1,396 @@ +select CAST(1-2 AS UNSIGNED); +CAST(1-2 AS UNSIGNED) +18446744073709551615 +select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER); +CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER) +-1 +select CAST('10 ' as unsigned integer); +CAST('10 ' as unsigned integer) +10 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '10 ' +select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; +cast(-5 as unsigned) | 1 cast(-5 as unsigned) & -1 +18446744073709551611 18446744073709551611 +select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1; +cast(-5 as unsigned) -1 cast(-5 as unsigned) + 1 +18446744073709551610 18446744073709551612 +select ~5, cast(~5 as signed); +~5 cast(~5 as signed) +18446744073709551610 -6 +explain extended select ~5, cast(~5 as signed); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select ~(5) AS `~5`,cast(~(5) as signed) AS `cast(~5 as signed)` +select cast(5 as unsigned) -6.0; +cast(5 as unsigned) -6.0 +-1.0 +select cast(NULL as signed), cast(1/0 as signed); +cast(NULL as signed) cast(1/0 as signed) +NULL NULL +select cast(NULL as unsigned), cast(1/0 as unsigned); +cast(NULL as unsigned) cast(1/0 as unsigned) +NULL NULL +select cast("A" as binary) = "a", cast(BINARY "a" as CHAR) = "A"; +cast("A" as binary) = "a" cast(BINARY "a" as CHAR) = "A" +0 1 +select cast("2001-1-1" as DATE), cast("2001-1-1" as DATETIME); +cast("2001-1-1" as DATE) cast("2001-1-1" as DATETIME) +2001-01-01 2001-01-01 00:00:00 +select cast("1:2:3" as TIME); +cast("1:2:3" as TIME) +01:02:03 +select CONVERT("2004-01-22 21:45:33",DATE); +CONVERT("2004-01-22 21:45:33",DATE) +2004-01-22 +select 10+'10'; +10+'10' +20 +select 10.0+'10'; +10.0+'10' +20 +select 10E+0+'10'; +10E+0+'10' +20 +select CONVERT(DATE "2004-01-22 21:45:33" USING latin1); +CONVERT(DATE "2004-01-22 21:45:33" USING latin1) +2004-01-22 21:45:33 +select CONVERT(DATE "2004-01-22 21:45:33",CHAR); +CONVERT(DATE "2004-01-22 21:45:33",CHAR) +2004-01-22 21:45:33 +select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4)); +CONVERT(DATE "2004-01-22 21:45:33",CHAR(4)) +2004 +Warnings: +Warning 1292 Truncated incorrect CHAR(4) value: '2004-01-22 21:45:33' +select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)); +CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)) +2004 +Warnings: +Warning 1292 Truncated incorrect BINARY(4) value: '2004-01-22 21:45:33' +select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); +CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)) +2004 +Warnings: +Warning 1292 Truncated incorrect BINARY(4) value: '2004-01-22 21:45:33' +select CAST(0xb3 as signed); +CAST(0xb3 as signed) +179 +select CAST(0x8fffffffffffffff as signed); +CAST(0x8fffffffffffffff as signed) +-8070450532247928833 +select CAST(0xffffffffffffffff as unsigned); +CAST(0xffffffffffffffff as unsigned) +18446744073709551615 +select CAST(0xfffffffffffffffe as signed); +CAST(0xfffffffffffffffe as signed) +-2 +select cast('-10a' as signed integer); +cast('-10a' as signed integer) +-10 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '-10a' +select cast('a10' as unsigned integer); +cast('a10' as unsigned integer) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'a10' +select 10+'a'; +10+'a' +10 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +select 10.0+cast('a' as decimal); +10.0+cast('a' as decimal) +10.0 +Warnings: +Warning 1292 Truncated incorrect DECIMAL value: 'a' +select 10E+0+'a'; +10E+0+'a' +10 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +select cast('18446744073709551616' as unsigned); +cast('18446744073709551616' as unsigned) +18446744073709551615 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '18446744073709551616' +select cast('18446744073709551616' as signed); +cast('18446744073709551616' as signed) +-1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '18446744073709551616' +select cast('9223372036854775809' as signed); +cast('9223372036854775809' as signed) +-9223372036854775807 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast('-1' as unsigned); +cast('-1' as unsigned) +18446744073709551615 +Warnings: +Warning 1105 Cast to unsigned converted negative integer to it's positive complement +select cast('abc' as signed); +cast('abc' as signed) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'abc' +select cast('1a' as signed); +cast('1a' as signed) +1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '1a' +select cast('' as signed); +cast('' as signed) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' +set names binary; +select cast(_latin1'test' as char character set latin2); +cast(_latin1'test' as char character set latin2) +test +select cast(_koi8r'ÔÅÓÔ' as char character set cp1251); +cast(_koi8r'ÔÅÓÔ' as char character set cp1251) +òåñò +create table t1 select cast(_koi8r'ÔÅÓÔ' as char character set cp1251) as t; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t` varchar(4) CHARACTER SET cp1251 NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +select +cast(_latin1'ab' AS char) as c1, +cast(_latin1'a ' AS char) as c2, +cast(_latin1'abc' AS char(2)) as c3, +cast(_latin1'a ' AS char(2)) as c4, +hex(cast(_latin1'a' AS char(2))) as c5; +c1 c2 c3 c4 c5 +ab a ab a 6100 +Warnings: +Warning 1292 Truncated incorrect BINARY(2) value: 'abc' +Warning 1292 Truncated incorrect BINARY(2) value: 'a ' +select cast(1000 as CHAR(3)); +cast(1000 as CHAR(3)) +100 +Warnings: +Warning 1292 Truncated incorrect BINARY(3) value: '1000' +create table t1 select +cast(_latin1'ab' AS char) as c1, +cast(_latin1'a ' AS char) as c2, +cast(_latin1'abc' AS char(2)) as c3, +cast(_latin1'a ' AS char(2)) as c4, +cast(_latin1'a' AS char(2)) as c5; +Warnings: +Warning 1292 Truncated incorrect BINARY(2) value: 'abc' +Warning 1292 Truncated incorrect BINARY(2) value: 'a ' +select c1,c2,c3,c4,hex(c5) from t1; +c1 c2 c3 c4 hex(c5) +ab a ab a 6100 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varbinary(2) NOT NULL DEFAULT '', + `c2` varbinary(2) NOT NULL DEFAULT '', + `c3` varbinary(2) NOT NULL DEFAULT '', + `c4` varbinary(2) NOT NULL DEFAULT '', + `c5` varbinary(2) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +select +cast(_koi8r'ÆÇ' AS nchar) as c1, +cast(_koi8r'Æ ' AS nchar) as c2, +cast(_koi8r'ÆÇÈ' AS nchar(2)) as c3, +cast(_koi8r'Æ ' AS nchar(2)) as c4, +cast(_koi8r'Æ' AS nchar(2)) as c5; +c1 c2 c3 c4 c5 +фг Ñ„ фг Ñ„ Ñ„ +Warnings: +Warning 1292 Truncated incorrect CHAR(4) value: 'фгх' +Warning 1292 Truncated incorrect CHAR(3) value: 'Ñ„ ' +create table t1 select +cast(_koi8r'ÆÇ' AS nchar) as c1, +cast(_koi8r'Æ ' AS nchar) as c2, +cast(_koi8r'ÆÇÈ' AS nchar(2)) as c3, +cast(_koi8r'Æ ' AS nchar(2)) as c4, +cast(_koi8r'Æ' AS nchar(2)) as c5; +Warnings: +Warning 1292 Truncated incorrect CHAR(4) value: 'фгх' +Warning 1292 Truncated incorrect CHAR(3) value: 'Ñ„ ' +select * from t1; +c1 c2 c3 c4 c5 +фг Ñ„ фг Ñ„ Ñ„ +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(2) CHARACTER SET utf8 NOT NULL DEFAULT '', + `c2` varchar(2) CHARACTER SET utf8 NOT NULL DEFAULT '', + `c3` varchar(2) CHARACTER SET utf8 NOT NULL DEFAULT '', + `c4` varchar(2) CHARACTER SET utf8 NOT NULL DEFAULT '', + `c5` varchar(2) CHARACTER SET utf8 NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a binary(4), b char(4) character set koi8r); +insert into t1 values (_binary'ÔÅÓÔ',_binary'ÔÅÓÔ'); +select a,b,cast(a as char character set cp1251),cast(b as binary) from t1; +a b cast(a as char character set cp1251) cast(b as binary) +ÔÅÓÔ ÔÅÓÔ ÔÅÓÔ ÔÅÓÔ +set names koi8r; +select a,b,cast(a as char character set cp1251),cast(b as binary) from t1; +a b cast(a as char character set cp1251) cast(b as binary) +ÔÅÓÔ ÔÅÓÔ æåõæ ÔÅÓÔ +set names cp1251; +select a,b,cast(a as char character set cp1251),cast(b as binary) from t1; +a b cast(a as char character set cp1251) cast(b as binary) +ÔÅÓÔ òåñò ÔÅÓÔ ÔÅÓÔ +drop table t1; +set names binary; +select cast("2001-1-1" as date) = "2001-01-01"; +cast("2001-1-1" as date) = "2001-01-01" +1 +select cast("2001-1-1" as datetime) = "2001-01-01 00:00:00"; +cast("2001-1-1" as datetime) = "2001-01-01 00:00:00" +1 +select cast("1:2:3" as TIME) = "1:02:03"; +cast("1:2:3" as TIME) = "1:02:03" +0 +select cast(NULL as DATE); +cast(NULL as DATE) +NULL +select cast(NULL as BINARY); +cast(NULL as BINARY) +NULL +CREATE TABLE t1 (a enum ('aac','aab','aaa') not null); +INSERT INTO t1 VALUES ('aaa'),('aab'),('aac'); +SELECT a, CAST(a AS CHAR) FROM t1 ORDER BY CAST(a AS UNSIGNED) ; +a CAST(a AS CHAR) +aac aac +aab aab +aaa aaa +SELECT a, CAST(a AS CHAR(3)) FROM t1 ORDER BY CAST(a AS CHAR(2)), a; +a CAST(a AS CHAR(3)) +aac aac +aab aab +aaa aaa +Warnings: +Warning 1292 Truncated incorrect BINARY(2) value: 'aaa' +Warning 1292 Truncated incorrect BINARY(2) value: 'aab' +Warning 1292 Truncated incorrect BINARY(2) value: 'aac' +SELECT a, CAST(a AS UNSIGNED) FROM t1 ORDER BY CAST(a AS CHAR) ; +a CAST(a AS UNSIGNED) +aaa 3 +aab 2 +aac 1 +SELECT a, CAST(a AS CHAR(2)) FROM t1 ORDER BY CAST(a AS CHAR(3)), a; +a CAST(a AS CHAR(2)) +aaa aa +aab aa +aac aa +Warnings: +Warning 1292 Truncated incorrect BINARY(2) value: 'aaa' +Warning 1292 Truncated incorrect BINARY(2) value: 'aab' +Warning 1292 Truncated incorrect BINARY(2) value: 'aac' +DROP TABLE t1; +select date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour); +date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour) +2004-12-30 00:00:00 +select timediff(cast('2004-12-30 12:00:00' as time), '12:00:00'); +timediff(cast('2004-12-30 12:00:00' as time), '12:00:00') +00:00:00 +select timediff(cast('1 12:00:00' as time), '12:00:00'); +timediff(cast('1 12:00:00' as time), '12:00:00') +24:00:00 +select cast(18446744073709551615 as unsigned); +cast(18446744073709551615 as unsigned) +18446744073709551615 +select cast(18446744073709551615 as signed); +cast(18446744073709551615 as signed) +-1 +select cast('18446744073709551615' as unsigned); +cast('18446744073709551615' as unsigned) +18446744073709551615 +select cast('18446744073709551615' as signed); +cast('18446744073709551615' as signed) +-1 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast('9223372036854775807' as signed); +cast('9223372036854775807' as signed) +9223372036854775807 +select cast(concat('184467440','73709551615') as unsigned); +cast(concat('184467440','73709551615') as unsigned) +18446744073709551615 +select cast(concat('184467440','73709551615') as signed); +cast(concat('184467440','73709551615') as signed) +-1 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast(repeat('1',20) as unsigned); +cast(repeat('1',20) as unsigned) +11111111111111111111 +select cast(repeat('1',20) as signed); +cast(repeat('1',20) as signed) +-7335632962598440505 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast(1.0e+300 as signed int); +cast(1.0e+300 as signed int) +9223372036854775807 +CREATE TABLE t1 (f1 double); +INSERT INTO t1 SET f1 = -1.0e+30 ; +INSERT INTO t1 SET f1 = +1.0e+30 ; +SELECT f1 AS double_val, CAST(f1 AS SIGNED INT) AS cast_val FROM t1; +double_val cast_val +-1e+30 -9223372036854775808 +1e+30 9223372036854775807 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '-1e+30' +Warning 1292 Truncated incorrect INTEGER value: '1e+30' +DROP TABLE t1; +select cast('1.2' as decimal(3,2)); +cast('1.2' as decimal(3,2)) +1.20 +select 1e18 * cast('1.2' as decimal(3,2)); +1e18 * cast('1.2' as decimal(3,2)) +1.2e+18 +select cast(cast('1.2' as decimal(3,2)) as signed); +cast(cast('1.2' as decimal(3,2)) as signed) +1 +set @v1=1e18; +select cast(@v1 as decimal(22, 2)); +cast(@v1 as decimal(22, 2)) +1000000000000000000.00 +select cast(-1e18 as decimal(22,2)); +cast(-1e18 as decimal(22,2)) +-1000000000000000000.00 +create table t1(s1 time); +insert into t1 values ('11:11:11'); +select cast(s1 as decimal(7,2)) from t1; +cast(s1 as decimal(7,2)) +99999.99 +Warnings: +Error 1264 Out of range value for column 'cast(s1 as decimal(7,2))' at row 1 +drop table t1; +CREATE TABLE t1 (v varchar(10), tt tinytext, t text, +mt mediumtext, lt longtext); +INSERT INTO t1 VALUES ('1.01', '2.02', '3.03', '4.04', '5.05'); +SELECT CAST(v AS DECIMAL), CAST(tt AS DECIMAL), CAST(t AS DECIMAL), +CAST(mt AS DECIMAL), CAST(lt AS DECIMAL) from t1; +CAST(v AS DECIMAL) CAST(tt AS DECIMAL) CAST(t AS DECIMAL) CAST(mt AS DECIMAL) CAST(lt AS DECIMAL) +1 2 3 4 5 +DROP TABLE t1; +select cast(NULL as decimal(6)) as t1; +t1 +NULL +set names latin1; +select hex(cast('a' as char(2) binary)); +hex(cast('a' as char(2) binary)) +61 +select hex(cast('a' as binary(2))); +hex(cast('a' as binary(2))) +6100 +select hex(cast('a' as char(2) binary)); +hex(cast('a' as char(2) binary)) +61 +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/check.result b/mysql-test/suite/pbxt/r/check.result new file mode 100644 index 00000000000..60806e7393e --- /dev/null +++ b/mysql-test/suite/pbxt/r/check.result @@ -0,0 +1,16 @@ +drop table if exists t1; +create table t1(n int not null, key(n), key(n), key(n), key(n)); +check table t1 extended; +insert into t1 values (200000); +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +Create table t1(f1 int); +Create table t2(f1 int); +Create view v1 as Select * from t1; +Check Table v1,t2; +Table Op Msg_type Msg_text +test.v1 check status OK +test.t2 check status OK +drop view v1; +drop table t1, t2; diff --git a/mysql-test/suite/pbxt/r/client_xml.result b/mysql-test/suite/pbxt/r/client_xml.result new file mode 100644 index 00000000000..6a148954fcd --- /dev/null +++ b/mysql-test/suite/pbxt/r/client_xml.result @@ -0,0 +1,74 @@ +create table t1 ( +`a&b` int, +`a<b` int, +`a>b` text +); +insert into t1 values (1, 2, 'a&b a<b a>b'); +<?xml version="1.0"?> + +<resultset statement="select * from t1 +" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <row> + <field name="a&b">1</field> + <field name="a<b">2</field> + <field name="a>b">a&b a<b a>b</field> + </row> +</resultset> +<?xml version="1.0"?> +<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<database name="test"> + <table_structure name="t1"> + <field Field="a&b" Type="int(11)" Null="YES" Key="" Extra="" /> + <field Field="a<b" Type="int(11)" Null="YES" Key="" Extra="" /> + <field Field="a>b" Type="text" Null="YES" Key="" Extra="" /> + </table_structure> + <table_data name="t1"> + <row> + <field name="a&b">1</field> + <field name="a<b">2</field> + <field name="a>b">a&b a<b a>b</field> + </row> + </table_data> +</database> +</mysqldump> +<?xml version="1.0"?> + +<resultset statement="select count(*) from t1 +" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <row> + <field name="count(*)">1</field> + </row> +</resultset> +<?xml version="1.0"?> + +<resultset statement="select 1 < 2 from dual +" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <row> + <field name="1 < 2">1</field> + </row> +</resultset> +<?xml version="1.0"?> + +<resultset statement="select 1 > 2 from dual +" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <row> + <field name="1 > 2">0</field> + </row> +</resultset> +<?xml version="1.0"?> + +<resultset statement="select 1 & 3 from dual +" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <row> + <field name="1 & 3">1</field> + </row> +</resultset> +<?xml version="1.0"?> + +<resultset statement="select null from dual +" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <row> + <field name="NULL" xsi:nil="true" /> + </row> +</resultset> +drop table t1; diff --git a/mysql-test/suite/pbxt/r/comments.result b/mysql-test/suite/pbxt/r/comments.result new file mode 100644 index 00000000000..13dcd2f18f6 --- /dev/null +++ b/mysql-test/suite/pbxt/r/comments.result @@ -0,0 +1,28 @@ +select 1+2/*hello*/+3; +1+2/*hello*/+3 +6 +select 1 /* long +multi line comment */; +1 +1 +; +ERROR 42000: Query was empty +select 1 /*!32301 +1 */; +1 +1 +2 +select 1 /*!52301 +1 */; +1 +1 +select 1--1; +1--1 +2 +select 1 --2 ++1; +1 --2 ++1 +4 +select 1 # The rest of the row will be ignored +; +1 +1 +/* line with only comment */; diff --git a/mysql-test/suite/pbxt/r/compare.result b/mysql-test/suite/pbxt/r/compare.result new file mode 100644 index 00000000000..c141b255716 --- /dev/null +++ b/mysql-test/suite/pbxt/r/compare.result @@ -0,0 +1,55 @@ +drop table if exists t1; +CREATE TABLE t1 (id CHAR(12) not null, PRIMARY KEY (id)); +insert into t1 values ('000000000001'),('000000000002'); +explain select * from t1 where id=000000000001; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 12 NULL 2 Using where; Using index +select * from t1 where id=000000000001; +id +000000000001 +delete from t1 where id=000000000002; +select * from t1; +id +000000000001 +drop table t1; +SELECT 'a' = 'a '; +'a' = 'a ' +1 +SELECT 'a\0' < 'a'; +'a\0' < 'a' +1 +SELECT 'a\0' < 'a '; +'a\0' < 'a ' +1 +SELECT 'a\t' < 'a'; +'a\t' < 'a' +1 +SELECT 'a\t' < 'a '; +'a\t' < 'a ' +1 +CREATE TABLE t1 (a char(10) not null); +INSERT INTO t1 VALUES ('a'),('a\0'),('a\t'),('a '); +SELECT hex(a),STRCMP(a,'a'), STRCMP(a,'a ') FROM t1; +hex(a) STRCMP(a,'a') STRCMP(a,'a ') +61 0 0 +6100 -1 -1 +6109 -1 -1 +61 0 0 +DROP TABLE t1; +SELECT CHAR(31) = '', '' = CHAR(31); +CHAR(31) = '' '' = CHAR(31) +0 0 +SELECT CHAR(30) = '', '' = CHAR(30); +CHAR(30) = '' '' = CHAR(30) +0 0 +create table t1 (a tinyint(1),b binary(1)); +insert into t1 values (0x01,0x01); +select * from t1 where a=b; +a b +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: '' +select * from t1 where a=b and b=0x01; +a b +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: '' +drop table if exists t1; diff --git a/mysql-test/suite/pbxt/r/connect.result b/mysql-test/suite/pbxt/r/connect.result new file mode 100644 index 00000000000..25cf4f90e6d --- /dev/null +++ b/mysql-test/suite/pbxt/r/connect.result @@ -0,0 +1,117 @@ +drop table if exists t1,t2; +show tables; +Tables_in_mysql +columns_priv +db +event +func +general_log +help_category +help_keyword +help_relation +help_topic +host +ndb_binlog_index +plugin +proc +procs_priv +servers +slow_log +tables_priv +time_zone +time_zone_leap_second +time_zone_name +time_zone_transition +time_zone_transition_type +user +show tables; +Tables_in_test +connect(localhost,root,z,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'root'@'localhost' (using password: YES) +connect(localhost,root,z,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'root'@'localhost' (using password: YES) +grant ALL on *.* to test@localhost identified by "gambling"; +grant ALL on *.* to test@127.0.0.1 identified by "gambling"; +show tables; +Tables_in_mysql +columns_priv +db +event +func +general_log +help_category +help_keyword +help_relation +help_topic +host +ndb_binlog_index +plugin +proc +procs_priv +servers +slow_log +tables_priv +time_zone +time_zone_leap_second +time_zone_name +time_zone_transition +time_zone_transition_type +user +show tables; +Tables_in_test +connect(localhost,test,,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) +connect(localhost,test,,"",MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) +connect(localhost,test,zorro,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) +connect(localhost,test,zorro,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) +update mysql.user set password=old_password("gambling2") where user=_binary"test"; +flush privileges; +set password=""; +set password='gambling3'; +ERROR HY000: Password hash should be a 41-digit hexadecimal number +set password=old_password('gambling3'); +show tables; +Tables_in_mysql +columns_priv +db +event +func +general_log +help_category +help_keyword +help_relation +help_topic +host +ndb_binlog_index +plugin +proc +procs_priv +servers +slow_log +tables_priv +time_zone +time_zone_leap_second +time_zone_name +time_zone_transition +time_zone_transition_type +user +show tables; +Tables_in_test +connect(localhost,test,,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) +connect(localhost,test,,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) +connect(localhost,test,zorro,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) +connect(localhost,test,zorro,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) +delete from mysql.user where user=_binary"test"; +flush privileges; +create table t1 (id integer not null auto_increment primary key); +create temporary table t2(id integer not null auto_increment primary key); +set @id := 1; +delete from t1 where id like @id; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/consistent_snapshot.result b/mysql-test/suite/pbxt/r/consistent_snapshot.result new file mode 100644 index 00000000000..90606abbe4e --- /dev/null +++ b/mysql-test/suite/pbxt/r/consistent_snapshot.result @@ -0,0 +1,15 @@ +drop table if exists t1; +create table t1 (a int) engine=innodb; +start transaction with consistent snapshot; +insert into t1 values(1); +select * from t1; +a +commit; +delete from t1; +start transaction; +insert into t1 values(1); +select * from t1; +a +1 +commit; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/constraints.result b/mysql-test/suite/pbxt/r/constraints.result new file mode 100644 index 00000000000..344abc454fe --- /dev/null +++ b/mysql-test/suite/pbxt/r/constraints.result @@ -0,0 +1,29 @@ +drop table if exists t1; +create table t1 (a int check (a>0)); +insert into t1 values (1); +insert into t1 values (0); +drop table t1; +create table t1 (a int ,b int, check a>b); +insert into t1 values (1,0); +insert into t1 values (0,1); +drop table t1; +create table t1 (a int ,b int, constraint abc check (a>b)); +insert into t1 values (1,0); +insert into t1 values (0,1); +drop table t1; +create table t1 (a int null); +insert into t1 values (1),(NULL); +drop table t1; +create table t1 (a int null); +alter table t1 add constraint constraint_1 unique (a); +alter table t1 add constraint unique key_1(a); +alter table t1 add constraint constraint_2 unique key_2(a); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + UNIQUE KEY `constraint_1` (`a`), + UNIQUE KEY `key_1` (`a`), + UNIQUE KEY `key_2` (`a`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/contributors.result b/mysql-test/suite/pbxt/r/contributors.result new file mode 100644 index 00000000000..5739c2244c3 --- /dev/null +++ b/mysql-test/suite/pbxt/r/contributors.result @@ -0,0 +1,5 @@ +SHOW CONTRIBUTORS; +Name Location Comment +Ronald Bradford Brisbane, Australia EFF contribution for UC2006 Auction +Sheeri Kritzer Boston, Mass. USA EFF contribution for UC2006 Auction +Mark Shuttleworth London, UK. EFF contribution for UC2006 Auction diff --git a/mysql-test/suite/pbxt/r/count_distinct.result b/mysql-test/suite/pbxt/r/count_distinct.result new file mode 100644 index 00000000000..a21748359b9 --- /dev/null +++ b/mysql-test/suite/pbxt/r/count_distinct.result @@ -0,0 +1,68 @@ +drop table if exists t1,t2,t3; +create table t1 (libname varchar(21) not null, city text, primary key (libname)); +create table t2 (isbn varchar(21) not null, author text, title text, primary key (isbn)); +create table t3 (isbn varchar(21) not null, libname varchar(21) not null, quantity int ,primary key (isbn,libname)); +insert into t2 values ('001','Daffy','A duck''s life'); +insert into t2 values ('002','Bugs','A rabbit\'s life'); +insert into t2 values ('003','Cowboy','Life on the range'); +insert into t2 values ('000','Anonymous','Wanna buy this book?'); +insert into t2 values ('004','Best Seller','One Heckuva book'); +insert into t2 values ('005','EveryoneBuys','This very book'); +insert into t2 values ('006','San Fran','It is a san fran lifestyle'); +insert into t2 values ('007','BerkAuthor','Cool.Berkley.the.book'); +insert into t3 values('000','New York Public Libra','1'); +insert into t3 values('001','New York Public Libra','2'); +insert into t3 values('002','New York Public Libra','3'); +insert into t3 values('003','New York Public Libra','4'); +insert into t3 values('004','New York Public Libra','5'); +insert into t3 values('005','New York Public Libra','6'); +insert into t3 values('006','San Fransisco Public','5'); +insert into t3 values('007','Berkeley Public1','3'); +insert into t3 values('007','Berkeley Public2','3'); +insert into t3 values('001','NYC Lib','8'); +insert into t1 values ('New York Public Libra','New York'); +insert into t1 values ('San Fransisco Public','San Fran'); +insert into t1 values ('Berkeley Public1','Berkeley'); +insert into t1 values ('Berkeley Public2','Berkeley'); +insert into t1 values ('NYC Lib','New York'); +select t2.isbn,city,t1.libname,count(t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city,t1.libname; +isbn city libname a +007 Berkeley Berkeley Public1 1 +007 Berkeley Berkeley Public2 1 +000 New York New York Public Libra 6 +001 New York NYC Lib 1 +006 San Fran San Fransisco Public 1 +select t2.isbn,city,t1.libname,count(distinct t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city having count(distinct t1.libname) > 1; +isbn city libname a +007 Berkeley Berkeley Public1 2 +000 New York New York Public Libra 2 +select t2.isbn,city,t1.libname,count(distinct t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city having count(distinct concat(t1.libname,'a')) > 1; +isbn city libname a +007 Berkeley Berkeley Public1 2 +000 New York New York Public Libra 2 +drop table t1, t2, t3; +create table t1 (f1 int); +insert into t1 values (1); +create table t2 (f1 int,f2 int); +select t1.f1,count(distinct t2.f2),count(distinct 1,NULL) from t1 left join t2 on t1.f1=t2.f1 group by t1.f1; +f1 count(distinct t2.f2) count(distinct 1,NULL) +1 0 0 +drop table t1,t2; +create table t1 (f int); +select count(distinct f) from t1; +count(distinct f) +0 +drop table t1; +create table t1 (a char(3), b char(20), primary key (a, b)); +insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English'); +select count(distinct a) from t1 group by b; +count(distinct a) +1 +1 +drop table t1; +create table t1 (f1 int, f2 int); +insert into t1 values (0,1),(1,2); +select count(distinct if(f1,3,f2)) from t1; +count(distinct if(f1,3,f2)) +2 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/count_distinct2.result b/mysql-test/suite/pbxt/r/count_distinct2.result new file mode 100644 index 00000000000..b92665b5c56 --- /dev/null +++ b/mysql-test/suite/pbxt/r/count_distinct2.result @@ -0,0 +1,129 @@ +drop table if exists t1; +create table t1(n1 int, n2 int, s char(20), vs varchar(20), t text); +insert into t1 values (1,11, 'one','eleven', 'eleven'), +(1,11, 'one','eleven', 'eleven'), +(2,11, 'two','eleven', 'eleven'), +(2,12, 'two','twevle', 'twelve'), +(2,13, 'two','thirteen', 'foo'), +(2,13, 'two','thirteen', 'foo'), +(2,13, 'two','thirteen', 'bar'), +(NULL,13, 'two','thirteen', 'bar'), +(2,NULL, 'two','thirteen', 'bar'), +(2,13, NULL,'thirteen', 'bar'), +(2,13, 'two',NULL, 'bar'), +(2,13, 'two','thirteen', NULL); +select distinct n1 from t1; +n1 +1 +2 +NULL +select count(distinct n1) from t1; +count(distinct n1) +2 +select distinct n2 from t1; +n2 +11 +12 +13 +NULL +select count(distinct n2) from t1; +count(distinct n2) +3 +select distinct s from t1; +s +one +two +NULL +select count(distinct s) from t1; +count(distinct s) +2 +select distinct vs from t1; +vs +eleven +twevle +thirteen +NULL +select count(distinct vs) from t1; +count(distinct vs) +3 +select distinct t from t1; +t +eleven +twelve +foo +bar +NULL +select count(distinct t) from t1; +count(distinct t) +4 +select distinct n1,n2 from t1; +n1 n2 +1 11 +2 11 +2 12 +2 13 +NULL 13 +2 NULL +select count(distinct n1,n2) from t1; +count(distinct n1,n2) +4 +select distinct n1,s from t1; +n1 s +1 one +2 two +NULL two +2 NULL +select count(distinct n1,s) from t1; +count(distinct n1,s) +2 +select distinct s,n1,vs from t1; +s n1 vs +one 1 eleven +two 2 eleven +two 2 twevle +two 2 thirteen +two NULL thirteen +NULL 2 thirteen +two 2 NULL +select count(distinct s,n1,vs) from t1; +count(distinct s,n1,vs) +4 +select distinct s,t from t1; +s t +one eleven +two eleven +two twelve +two foo +two bar +NULL bar +two NULL +select count(distinct s,t) from t1; +count(distinct s,t) +5 +select count(distinct n1), count(distinct n2) from t1; +count(distinct n1) count(distinct n2) +2 3 +select count(distinct n2), n1 from t1 group by n1; +count(distinct n2) n1 +1 NULL +1 1 +3 2 +drop table t1; +create table t1 (n int default NULL); +flush status; +select count(distinct n) from t1; +count(distinct n) +5000 +show status like 'Created_tmp_disk_tables'; +Variable_name Value +Created_tmp_disk_tables 0 +drop table t1; +create table t1 (s text); +flush status; +select count(distinct s) from t1; +count(distinct s) +5000 +show status like 'Created_tmp_disk_tables'; +Variable_name Value +Created_tmp_disk_tables 1 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/count_distinct3.result b/mysql-test/suite/pbxt/r/count_distinct3.result new file mode 100644 index 00000000000..086e1360b0c --- /dev/null +++ b/mysql-test/suite/pbxt/r/count_distinct3.result @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (id INTEGER, grp TINYINT, id_rev INTEGER); +SELECT COUNT(*) FROM t1; +COUNT(*) +4181000 +SELECT COUNT(DISTINCT id) FROM t1 GROUP BY grp; +DROP TABLE t1; +set @@read_buffer_size=default; diff --git a/mysql-test/suite/pbxt/r/create.result b/mysql-test/suite/pbxt/r/create.result new file mode 100644 index 00000000000..afdbf318195 --- /dev/null +++ b/mysql-test/suite/pbxt/r/create.result @@ -0,0 +1,837 @@ +drop table if exists t1,t2,t3,t4,t5; +drop database if exists mysqltest; +create table t1 (b char(0)); +insert into t1 values (""),(null); +select * from t1; +b + +NULL +drop table if exists t1; +create table t1 (b char(0) not null); +create table if not exists t1 (b char(0) not null); +Warnings: +Note 1050 Table 't1' already exists +insert into t1 values (""),(null); +Warnings: +Warning 1048 Column 'b' cannot be null +select * from t1; +b + + +drop table t1; +create table t1 (a int not null auto_increment,primary key (a)) engine=heap; +drop table t1; +create table t2 engine=heap select * from t1; +ERROR 42S02: Table 'test.t1' doesn't exist +create table t2 select auto+1 from t1; +ERROR 42S02: Table 'test.t1' doesn't exist +drop table if exists t1,t2; +Warnings: +Note 1051 Unknown table 't1' +Note 1051 Unknown table 't2' +create table t1 (b char(0) not null, index(b)); +ERROR 42000: The used storage engine can't index column 'b' +create table t1 (a int not null,b text) engine=heap; +ERROR 42000: The used table type doesn't support BLOB/TEXT columns +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) engine=heap; +ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key +create table not_existing_database.test (a int); +ERROR 42000: Unknown database 'not_existing_database' +create table `a/a` (a int); +show create table `a/a`; +Table Create Table +a/a CREATE TABLE `a/a` ( + `a` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +create table t1 like `a/a`; +drop table `a/a`; +drop table `t1`; +create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int); +ERROR 42000: Incorrect table name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int); +ERROR 42000: Identifier name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' is too long +create table t1 (a datetime default now()); +ERROR 42000: Invalid default value for 'a' +create table t1 (a datetime on update now()); +ERROR HY000: Invalid ON UPDATE clause for 'a' column +create table t1 (a int default 100 auto_increment); +ERROR 42000: Invalid default value for 'a' +create table t1 (a tinyint default 1000); +ERROR 42000: Invalid default value for 'a' +create table t1 (a varchar(5) default 'abcdef'); +ERROR 42000: Invalid default value for 'a' +create table t1 (a varchar(5) default 'abcde'); +insert into t1 values(); +select * from t1; +a +abcde +alter table t1 alter column a set default 'abcdef'; +ERROR 42000: Invalid default value for 'a' +drop table t1; +create table 1ea10 (1a20 int,1e int); +insert into 1ea10 values(1,1); +select 1ea10.1a20,1e+ 1e+10 from 1ea10; +1a20 1e+ 1e+10 +1 10000000001 +drop table 1ea10; +create table t1 (t1.index int); +drop table t1; +drop database if exists mysqltest; +Warnings: +Note 1008 Can't drop database 'mysqltest'; database doesn't exist +create database mysqltest; +create table mysqltest.$test1 (a$1 int, $b int, c$ int); +insert into mysqltest.$test1 values (1,2,3); +select a$1, $b, c$ from mysqltest.$test1; +a$1 $b c$ +1 2 3 +create table mysqltest.test2$ (a int); +drop table mysqltest.test2$; +drop database mysqltest; +create table `` (a int); +ERROR 42000: Incorrect table name '' +drop table if exists ``; +ERROR 42000: Incorrect table name '' +create table t1 (`` int); +ERROR 42000: Incorrect column name '' +create table t1 (i int, index `` (i)); +ERROR 42000: Incorrect index name '' +create table t1 (a int auto_increment not null primary key, B CHAR(20)); +insert into t1 (b) values ("hello"),("my"),("world"); +create table t2 (key (b)) select * from t1; +explain select * from t2 where b="world"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref B B 21 const 1 Using where +select * from t2 where b="world"; +a B +3 world +drop table t1,t2; +create table t1(x varchar(50) ); +create table t2 select x from t1 where 1=2; +describe t1; +Field Type Null Key Default Extra +x varchar(50) YES NULL +describe t2; +Field Type Null Key Default Extra +x varchar(50) YES NULL +drop table t2; +create table t2 select now() as a , curtime() as b, curdate() as c , 1+1 as d , 1.0 + 1 as e , 33333333333333333 + 3 as f; +describe t2; +Field Type Null Key Default Extra +a datetime NO 0000-00-00 00:00:00 +b time NO 00:00:00 +c date NO 0000-00-00 +d int(3) NO 0 +e decimal(3,1) NO 0.0 +f bigint(19) NO 0 +drop table t2; +create table t2 select CAST("2001-12-29" AS DATE) as d, CAST("20:45:11" AS TIME) as t, CAST("2001-12-29 20:45:11" AS DATETIME) as dt; +describe t2; +Field Type Null Key Default Extra +d date YES NULL +t time YES NULL +dt datetime YES NULL +drop table t1,t2; +create table t1 (a tinyint); +create table t2 (a int) select * from t1; +describe t1; +Field Type Null Key Default Extra +a tinyint(4) YES NULL +describe t2; +Field Type Null Key Default Extra +a int(11) YES NULL +drop table if exists t2; +create table t2 (a int, a float) select * from t1; +ERROR 42S21: Duplicate column name 'a' +drop table if exists t2; +Warnings: +Note 1051 Unknown table 't2' +create table t2 (a int) select a as b, a+1 as b from t1; +ERROR 42S21: Duplicate column name 'b' +drop table if exists t2; +Warnings: +Note 1051 Unknown table 't2' +create table t2 (b int) select a as b, a+1 as b from t1; +ERROR 42S21: Duplicate column name 'b' +drop table if exists t1,t2; +Warnings: +Note 1051 Unknown table 't2' +CREATE TABLE t1 (a int not null); +INSERT INTO t1 values (1),(2),(1); +CREATE TABLE t2 (primary key(a)) SELECT * FROM t1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +SELECT * from t2; +ERROR 42S02: Table 'test.t2' doesn't exist +DROP TABLE t1; +DROP TABLE IF EXISTS t2; +Warnings: +Note 1051 Unknown table 't2' +create table t1 (a int not null, b int, primary key(a), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`), + KEY `b_2` (`b`), + KEY `b_3` (`b`), + KEY `b_4` (`b`), + KEY `b_5` (`b`), + KEY `b_6` (`b`), + KEY `b_7` (`b`), + KEY `b_8` (`b`), + KEY `b_9` (`b`), + KEY `b_10` (`b`), + KEY `b_11` (`b`), + KEY `b_12` (`b`), + KEY `b_13` (`b`), + KEY `b_14` (`b`), + KEY `b_15` (`b`), + KEY `b_16` (`b`), + KEY `b_17` (`b`), + KEY `b_18` (`b`), + KEY `b_19` (`b`), + KEY `b_20` (`b`), + KEY `b_21` (`b`), + KEY `b_22` (`b`), + KEY `b_23` (`b`), + KEY `b_24` (`b`), + KEY `b_25` (`b`), + KEY `b_26` (`b`), + KEY `b_27` (`b`), + KEY `b_28` (`b`), + KEY `b_29` (`b`), + KEY `b_30` (`b`), + KEY `b_31` (`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select if(1,'1','0'), month("2002-08-02"); +drop table t1; +create table t1 select if('2002'='2002','Y','N'); +select * from t1; +if('2002'='2002','Y','N') +Y +drop table if exists t1; +SET SESSION storage_engine="heap"; +SELECT @@storage_engine; +@@storage_engine +MEMORY +CREATE TABLE t1 (a int not null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +drop table t1; +SET SESSION storage_engine="gemini"; +ERROR 42000: Unknown table engine 'gemini' +SELECT @@storage_engine; +@@storage_engine +MEMORY +CREATE TABLE t1 (a int not null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +SET SESSION storage_engine=default; +drop table t1; +create table t1 ( k1 varchar(2), k2 int, primary key(k1,k2)); +insert into t1 values ("a", 1), ("b", 2); +insert into t1 values ("c", NULL); +ERROR 23000: Column 'k2' cannot be null +insert into t1 values (NULL, 3); +ERROR 23000: Column 'k1' cannot be null +insert into t1 values (NULL, NULL); +ERROR 23000: Column 'k1' cannot be null +drop table t1; +create table t1 select x'4132'; +drop table t1; +create table t1 select 1,2,3; +create table if not exists t1 select 1,2; +Warnings: +Note 1050 Table 't1' already exists +create table if not exists t1 select 1,2,3,4; +ERROR 21S01: Column count doesn't match value count at row 1 +create table if not exists t1 select 1; +Warnings: +Note 1050 Table 't1' already exists +select * from t1; +1 2 3 +1 2 3 +0 1 2 +0 0 1 +drop table t1; +flush status; +create table t1 (a int not null, b int, primary key (a)); +insert into t1 values (1,1); +create table if not exists t1 select 2; +Warnings: +Note 1050 Table 't1' already exists +Warning 1364 Field 'a' doesn't have a default value +select * from t1; +a b +1 1 +0 2 +create table if not exists t1 select 3 as 'a',4 as 'b'; +Warnings: +Note 1050 Table 't1' already exists +create table if not exists t1 select 3 as 'a',3 as 'b'; +ERROR 23000: Duplicate entry '3' for key 'PRIMARY' +show warnings; +Level Code Message +Note 1050 Table 't1' already exists +Error 1062 Duplicate entry '3' for key 'PRIMARY' +show status like "Opened_tables"; +Variable_name Value +Opened_tables 3 +select * from t1; +a b +1 1 +0 2 +3 4 +drop table t1; +create table `t1 `(a int); +ERROR 42000: Incorrect table name 't1 ' +create database `db1 `; +ERROR 42000: Incorrect database name 'db1 ' +create table t1(`a ` int); +ERROR 42000: Incorrect column name 'a ' +create table t1 (a int,); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1 +create table t1 (a int,,b int); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'b int)' at line 1 +create table t1 (,b int); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'b int)' at line 1 +create table t1 (a int, key(a)); +create table t2 (b int, foreign key(b) references t1(a), key(b)); +drop table if exists t2,t1; +create table t1(id int not null, name char(20)); +insert into t1 values(10,'mysql'),(20,'monty- the creator'); +create table t2(id int not null); +insert into t2 values(10),(20); +create table t3 like t1; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `id` int(11) NOT NULL, + `name` char(20) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t3; +id name +create table if not exists t3 like t1; +Warnings: +Note 1050 Table 't3' already exists +select @@warning_count; +@@warning_count +1 +create temporary table t3 like t2; +show create table t3; +Table Create Table +t3 CREATE TEMPORARY TABLE `t3` ( + `id` int(11) NOT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t3; +id +drop table t3; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `id` int(11) NOT NULL, + `name` char(20) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t3; +id name +drop table t2, t3; +create database mysqltest; +alter table t1; +create table mysqltest.t3 like t1; +create temporary table t3 like mysqltest.t3; +show create table t3; +Table Create Table +t3 CREATE TEMPORARY TABLE `t3` ( + `id` int(11) NOT NULL, + `name` char(20) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +create table t2 like t3; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(11) NOT NULL, + `name` char(20) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t2; +id name +create table t3 like t1; +create table t3 like mysqltest.t3; +ERROR 42S01: Table 't3' already exists +create table non_existing_database.t1 like t1; +ERROR 42000: Unknown database 'non_existing_database' +create table t3 like non_existing_table; +ERROR 42S02: Table 'test.non_existing_table' doesn't exist +create temporary table t3 like t1; +ERROR 42S01: Table 't3' already exists +drop table t1, t2, t3; +drop table t3; +drop database mysqltest; +SET SESSION storage_engine="heap"; +SELECT @@storage_engine; +@@storage_engine +MEMORY +CREATE TABLE t1 (a int not null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +drop table t1; +SET SESSION storage_engine="gemini"; +ERROR 42000: Unknown table engine 'gemini' +SELECT @@storage_engine; +@@storage_engine +MEMORY +CREATE TABLE t1 (a int not null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +SET SESSION storage_engine=default; +drop table t1; +create table t1(a int,b int,c int unsigned,d date,e char,f datetime,g time,h blob); +insert into t1(a)values(1); +insert into t1(a,b,c,d,e,f,g,h) +values(2,-2,2,'1825-12-14','a','2003-1-1 3:2:1','4:3:2','binary data'); +select * from t1; +a b c d e f g h +1 NULL NULL NULL NULL NULL NULL NULL +2 -2 2 1825-12-14 a 2003-01-01 03:02:01 04:03:02 binary data +select a, +ifnull(b,cast(-7 as signed)) as b, +ifnull(c,cast(7 as unsigned)) as c, +ifnull(d,cast('2000-01-01' as date)) as d, +ifnull(e,cast('b' as char)) as e, +ifnull(f,cast('2000-01-01' as datetime)) as f, +ifnull(g,cast('5:4:3' as time)) as g, +ifnull(h,cast('yet another binary data' as binary)) as h, +addtime(cast('1:0:0' as time),cast('1:0:0' as time)) as dd +from t1; +a b c d e f g h dd +1 -7 7 2000-01-01 b 2000-01-01 00:00:00 05:04:03 yet another binary data 02:00:00 +2 -2 2 1825-12-14 a 2003-01-01 03:02:01 04:03:02 binary data 02:00:00 +create table t2 +select +a, +ifnull(b,cast(-7 as signed)) as b, +ifnull(c,cast(7 as unsigned)) as c, +ifnull(d,cast('2000-01-01' as date)) as d, +ifnull(e,cast('b' as char)) as e, +ifnull(f,cast('2000-01-01' as datetime)) as f, +ifnull(g,cast('5:4:3' as time)) as g, +ifnull(h,cast('yet another binary data' as binary)) as h, +addtime(cast('1:0:0' as time),cast('1:0:0' as time)) as dd +from t1; +explain t2; +Field Type Null Key Default Extra +a int(11) YES NULL +b bigint(11) NO 0 +c bigint(11) unsigned NO 0 +d date YES NULL +e varchar(1) NO +f datetime YES NULL +g time YES NULL +h longblob NO NULL +dd time YES NULL +select * from t2; +a b c d e f g h dd +1 -7 7 2000-01-01 b 2000-01-01 00:00:00 05:04:03 yet another binary data 02:00:00 +2 -2 2 1825-12-14 a 2003-01-01 03:02:01 04:03:02 binary data 02:00:00 +drop table t1, t2; +create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp, l datetime, m enum('a','b'), n set('a','b'), o char(10)); +create table t2 select ifnull(a,a), ifnull(b,b), ifnull(c,c), ifnull(d,d), ifnull(e,e), ifnull(f,f), ifnull(g,g), ifnull(h,h), ifnull(i,i), ifnull(j,j), ifnull(k,k), ifnull(l,l), ifnull(m,m), ifnull(n,n), ifnull(o,o) from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `ifnull(a,a)` tinyint(4) DEFAULT NULL, + `ifnull(b,b)` smallint(6) DEFAULT NULL, + `ifnull(c,c)` mediumint(8) DEFAULT NULL, + `ifnull(d,d)` int(11) DEFAULT NULL, + `ifnull(e,e)` bigint(20) DEFAULT NULL, + `ifnull(f,f)` float(3,2) DEFAULT NULL, + `ifnull(g,g)` double(4,3) DEFAULT NULL, + `ifnull(h,h)` decimal(5,4) DEFAULT NULL, + `ifnull(i,i)` year(4) DEFAULT NULL, + `ifnull(j,j)` date DEFAULT NULL, + `ifnull(k,k)` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `ifnull(l,l)` datetime DEFAULT NULL, + `ifnull(m,m)` varchar(1) DEFAULT NULL, + `ifnull(n,n)` varchar(3) DEFAULT NULL, + `ifnull(o,o)` varchar(10) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1,t2; +create table t1(str varchar(10) default 'def',strnull varchar(10),intg int default '10',rel double default '3.14'); +insert into t1 values ('','',0,0.0); +describe t1; +Field Type Null Key Default Extra +str varchar(10) YES def +strnull varchar(10) YES NULL +intg int(11) YES 10 +rel double YES 3.14 +create table t2 select default(str) as str, default(strnull) as strnull, default(intg) as intg, default(rel) as rel from t1; +describe t2; +Field Type Null Key Default Extra +str varchar(10) YES NULL +strnull varchar(10) YES NULL +intg int(11) YES NULL +rel double YES NULL +drop table t1, t2; +create table t1(name varchar(10), age smallint default -1); +describe t1; +Field Type Null Key Default Extra +name varchar(10) YES NULL +age smallint(6) YES -1 +create table t2(name varchar(10), age smallint default - 1); +describe t2; +Field Type Null Key Default Extra +name varchar(10) YES NULL +age smallint(6) YES -1 +drop table t1, t2; +create table t1(cenum enum('a'), cset set('b')); +create table t2(cenum enum('a','a'), cset set('b','b')); +Warnings: +Note 1291 Column 'cenum' has duplicated value 'a' in ENUM +Note 1291 Column 'cset' has duplicated value 'b' in SET +create table t3(cenum enum('a','A','a','c','c'), cset set('b','B','b','d','d')); +Warnings: +Note 1291 Column 'cenum' has duplicated value 'a' in ENUM +Note 1291 Column 'cenum' has duplicated value 'A' in ENUM +Note 1291 Column 'cenum' has duplicated value 'c' in ENUM +Note 1291 Column 'cset' has duplicated value 'b' in SET +Note 1291 Column 'cset' has duplicated value 'B' in SET +Note 1291 Column 'cset' has duplicated value 'd' in SET +drop table t1, t2, t3; +create database mysqltest; +use mysqltest; +select database(); +database() +mysqltest +drop database mysqltest; +select database(); +database() +NULL +create user mysqltest_1; +select database(), user(); +database() user() +NULL mysqltest_1@localhost +drop user mysqltest_1; +use test; +create table t1 (a int, index `primary` (a)); +ERROR 42000: Incorrect index name 'primary' +create table t1 (a int, index `PRIMARY` (a)); +ERROR 42000: Incorrect index name 'PRIMARY' +create table t1 (`primary` int, index(`primary`)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `primary` int(11) DEFAULT NULL, + KEY `primary_2` (`primary`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +create table t2 (`PRIMARY` int, index(`PRIMARY`)); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `PRIMARY` int(11) DEFAULT NULL, + KEY `PRIMARY_2` (`PRIMARY`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +create table t3 (a int); +alter table t3 add index `primary` (a); +ERROR 42000: Incorrect index name 'primary' +alter table t3 add index `PRIMARY` (a); +ERROR 42000: Incorrect index name 'PRIMARY' +create table t4 (`primary` int); +alter table t4 add index(`primary`); +show create table t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `primary` int(11) DEFAULT NULL, + KEY `primary_2` (`primary`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +create table t5 (`PRIMARY` int); +alter table t5 add index(`PRIMARY`); +show create table t5; +Table Create Table +t5 CREATE TABLE `t5` ( + `PRIMARY` int(11) DEFAULT NULL, + KEY `PRIMARY_2` (`PRIMARY`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1, t2, t3, t4, t5; +CREATE TABLE t1(id varchar(10) NOT NULL PRIMARY KEY, dsc longtext); +INSERT INTO t1 VALUES ('5000000001', NULL),('5000000003', 'Test'),('5000000004', NULL); +CREATE TABLE t2(id varchar(15) NOT NULL, proc varchar(100) NOT NULL, runID varchar(16) NOT NULL, start datetime NOT NULL, PRIMARY KEY (id,proc,runID,start)); +INSERT INTO t2 VALUES ('5000000001', 'proc01', '20031029090650', '2003-10-29 13:38:40'),('5000000001', 'proc02', '20031029090650', '2003-10-29 13:38:51'),('5000000001', 'proc03', '20031029090650', '2003-10-29 13:38:11'),('5000000002', 'proc09', '20031024013310', '2003-10-24 01:33:11'),('5000000002', 'proc09', '20031024153537', '2003-10-24 15:36:04'),('5000000004', 'proc01', '20031024013641', '2003-10-24 01:37:29'),('5000000004', 'proc02', '20031024013641', '2003-10-24 01:37:39'); +CREATE TABLE t3 SELECT t1.dsc,COUNT(DISTINCT t2.id) AS countOfRuns FROM t1 LEFT JOIN t2 ON (t1.id=t2.id) GROUP BY t1.id; +SELECT * FROM t3; +dsc countOfRuns +NULL 1 +Test 0 +NULL 1 +drop table t1, t2, t3; +create table t1 (b bool not null default false); +create table t2 (b bool not null default true); +insert into t1 values (); +insert into t2 values (); +select * from t1; +b +0 +select * from t2; +b +1 +drop table t1,t2; +create table t1 (a int); +create table t1 select * from t1; +ERROR HY000: You can't specify target table 't1' for update in FROM clause +create table t2 union = (t1) select * from t1; +ERROR HY000: 'test.t2' is not BASE TABLE +flush tables with read lock; +unlock tables; +drop table t1; +create table t1(column.name int); +ERROR 42000: Incorrect table name 'column' +create table t1(test.column.name int); +ERROR 42000: Incorrect table name 'column' +create table t1(xyz.t1.name int); +ERROR 42000: Incorrect database name 'xyz' +create table t1(t1.name int); +create table t2(test.t2.name int); +drop table t1,t2; +CREATE TABLE t1 (f1 VARCHAR(255) CHARACTER SET utf8); +CREATE TABLE t2 AS SELECT LEFT(f1,171) AS f2 FROM t1 UNION SELECT LEFT(f1,171) AS f2 FROM t1; +DESC t2; +Field Type Null Key Default Extra +f2 varchar(171) YES NULL +DROP TABLE t1,t2; +CREATE TABLE t12913 (f1 ENUM ('a','b')) AS SELECT 'a' AS f1; +SELECT * FROM t12913; +f1 +a +DROP TABLE t12913; +create database mysqltest; +use mysqltest; +drop database mysqltest; +create table test.t1 like x; +ERROR 3D000: No database selected +drop table if exists test.t1; +create database mysqltest; +use mysqltest; +create view v1 as select 'foo' from dual; +create table t1 like v1; +ERROR HY000: 'mysqltest.v1' is not BASE TABLE +drop view v1; +drop database mysqltest; +create database mysqltest; +create database if not exists mysqltest character set latin2; +Warnings: +Note 1007 Can't create database 'mysqltest'; database exists +show create database mysqltest; +Database Create Database +mysqltest CREATE DATABASE `mysqltest` /*!40100 DEFAULT CHARACTER SET latin1 */ +drop database mysqltest; +use test; +create table t1 (a int); +create table if not exists t1 (a int); +Warnings: +Note 1050 Table 't1' already exists +drop table t1; +create table t1 ( +a varchar(112) charset utf8 collate utf8_bin not null, +primary key (a) +) select 'test' as a ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(112) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +CREATE TABLE t2 ( +a int(11) default NULL +); +insert into t2 values(111); +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin not null, +b int not null, primary key (a) +) select a, 1 as b from t2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(12) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `b` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin not null, +b int not null, primary key (a) +) select a, 1 as c from t2 ; +Warnings: +Warning 1364 Field 'b' doesn't have a default value +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) NOT NULL, + `a` varchar(12) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `c` int(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`a`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin not null, +b int null, primary key (a) +) select a, 1 as c from t2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL, + `a` varchar(12) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `c` int(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`a`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin not null, +b int not null, primary key (a) +) select 'a' as a , 1 as b from t2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(12) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + `b` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin, +b int not null, primary key (a) +) select 'a' as a , 1 as b from t2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(12) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `b` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1, t2; +create table t1 ( +a1 int not null, +a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +); +insert into t1 values (1,1,1, 1,1,1, 1,1,1); +create table t2 ( +a1 varchar(12) charset utf8 collate utf8_bin not null, +a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, +primary key (a1) +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +drop table t2; +create table t2 ( +a1 varchar(12) charset utf8 collate utf8_bin, +a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1; +drop table t1, t2; +create table t1 ( +a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +); +insert into t1 values (1,1,1, 1,1,1, 1,1,1); +create table t2 ( +a1 varchar(12) charset utf8 collate utf8_bin not null, +a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, +primary key (a1) +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +drop table t2; +create table t2 ( a int default 3, b int default 3) +select a1,a2 from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) DEFAULT '3', + `b` int(11) DEFAULT '3', + `a1` int(11) DEFAULT NULL, + `a2` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1, t2; +create table t1(a set("a,b","c,d") not null); +ERROR 22007: Illegal set 'a,b' value found during parsing +create table t1 (i int) engine=myisam max_rows=100000000000; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=4294967295 +alter table t1 max_rows=100; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=100 +alter table t1 max_rows=100000000000; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=4294967295 +drop table t1; +create table t1 (upgrade int); +drop table t1; +CREATE TABLE t1 (a int, b int); +insert into t1 values (1,1),(1,2); +CREATE TABLE t2 (primary key (a)) select * from t1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +drop table if exists t2; +Warnings: +Note 1051 Unknown table 't2' +CREATE TEMPORARY TABLE t2 (primary key (a)) select * from t1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +drop table if exists t2; +Warnings: +Note 1051 Unknown table 't2' +CREATE TABLE t2 (a int, b int, primary key (a)); +CREATE TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +SELECT * from t2; +a b +TRUNCATE table t2; +INSERT INTO t2 select * from t1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +SELECT * from t2; +a b +drop table t2; +CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a)); +CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +SELECT * from t2; +a b +TRUNCATE table t2; +INSERT INTO t2 select * from t1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +SELECT * from t2; +a b +drop table t1,t2; +CREATE DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +DROP DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +RENAME DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa TO a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at line 1 +RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at line 1 +create database mysqltest; +RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at line 1 +drop database mysqltest; +USE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +SHOW CREATE DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' diff --git a/mysql-test/suite/pbxt/r/date_formats.result b/mysql-test/suite/pbxt/r/date_formats.result new file mode 100644 index 00000000000..808c84d7c13 --- /dev/null +++ b/mysql-test/suite/pbxt/r/date_formats.result @@ -0,0 +1,584 @@ +drop table if exists t1; +SHOW GLOBAL VARIABLES LIKE "%_format%"; +Variable_name Value +binlog_format <format> +date_format %Y-%m-%d +datetime_format %Y-%m-%d %H:%i:%s +default_week_format 0 +time_format %H:%i:%s +SHOW SESSION VARIABLES LIKE "%_format%"; +Variable_name Value +binlog_format <format> +date_format %Y-%m-%d +datetime_format %Y-%m-%d %H:%i:%s +default_week_format 0 +time_format %H:%i:%s +SET time_format='%H%i%s'; +SET time_format='%H:%i:%s.%f'; +SET time_format='%h-%i-%s.%f%p'; +SET time_format='%h:%i:%s.%f %p'; +SET time_format='%h:%i:%s%p'; +SET date_format='%Y%m%d'; +SET date_format='%Y.%m.%d'; +SET date_format='%d.%m.%Y'; +SET date_format='%m-%d-%Y'; +set datetime_format= '%Y%m%d%H%i%s'; +set datetime_format= '%Y-%m-%d %H:%i:%s'; +set datetime_format= '%m-%d-%y %H:%i:%s.%f'; +set datetime_format= '%d-%m-%Y %h:%i:%s%p'; +set datetime_format= '%H:%i:%s %Y-%m-%d'; +set datetime_format= '%H:%i:%s.%f %m-%d-%Y'; +set datetime_format= '%h:%i:%s %p %Y-%m-%d'; +set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d'; +SHOW SESSION VARIABLES LIKE "%format"; +Variable_name Value +binlog_format <format> +date_format %m-%d-%Y +datetime_format %h:%i:%s.%f %p %Y-%m-%d +default_week_format 0 +time_format %h:%i:%s%p +SET time_format='%h:%i:%s'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%h:%i:%s' +SET time_format='%H %i:%s'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H %i:%s' +SET time_format='%H::%i:%s'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H::%i:%s' +SET time_format='%H:%i:%s%f'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i:%s%f' +SET time_format='%H:%i.%f:%s'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i.%f:%s' +SET time_format='%H:%i:%s%p'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i:%s%p' +SET time_format='%h:%i:%s.%f %p %Y-%m-%d'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%h:%i:%s.%f %p %Y-%m-%d' +SET time_format='%H%i%s.%f'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H%i%s.%f' +SET time_format='%H:%i-%s.%f'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i-%s.%f' +SET date_format='%d.%m.%d'; +ERROR 42000: Variable 'date_format' can't be set to the value of '%d.%m.%d' +SET datetime_format='%h.%m.%y %d.%i.%s'; +ERROR 42000: Variable 'datetime_format' can't be set to the value of '%h.%m.%y %d.%i.%s' +set datetime_format= '%H:%i:%s.%f %p %Y-%m-%d'; +ERROR 42000: Variable 'datetime_format' can't be set to the value of '%H:%i:%s.%f %p %Y-%m-%d' +set GLOBAL datetime_format= '%H:%i:%s %Y-%m-%d'; +SET SESSION datetime_format=default; +select @@global.datetime_format, @@session.datetime_format; +@@global.datetime_format @@session.datetime_format +%H:%i:%s %Y-%m-%d %H:%i:%s %Y-%m-%d +SET GLOBAL datetime_format=default; +SET SESSION datetime_format=default; +select @@global.datetime_format, @@session.datetime_format; +@@global.datetime_format @@session.datetime_format +%Y-%m-%d %H:%i:%s %Y-%m-%d %H:%i:%s +SET GLOBAL date_format=default; +SET GLOBAL time_format=default; +SET GLOBAL datetime_format=default; +SET time_format=default; +SET date_format=default; +SET datetime_format=default; +select str_to_date(concat('15-01-2001',' 2:59:58.999'), +concat('%d-%m-%Y',' ','%H:%i:%s.%f')); +str_to_date(concat('15-01-2001',' 2:59:58.999'), +concat('%d-%m-%Y',' ','%H:%i:%s.%f')) +2001-01-15 02:59:58.999000 +select STR_TO_DATE('2004.12.12 22.30.61','%Y.%m.%d %T'); +STR_TO_DATE('2004.12.12 22.30.61','%Y.%m.%d %T') +NULL +Warnings: +Error 1411 Incorrect time value: '22.30.61' for function str_to_date +create table t1 (date char(30), format char(30) not null); +insert into t1 values +('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'), +('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S.%#'), +('2003-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'), +('2003-01-02 01:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f%p'), +('2003-01-02 02:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f %p'), +('2003-01-02 12:11:12.12345 am', '%Y-%m-%d %h:%i:%S.%f%p'), +('2003-01-02 11:11:12Pm', '%Y-%m-%d %h:%i:%S%p'), +('10:20:10', '%H:%i:%s'), +('10:20:10', '%h:%i:%s.%f'), +('10:20:10', '%T'), +('10:20:10AM', '%h:%i:%s%p'), +('10:20:10AM', '%r'), +('10:20:10.44AM', '%h:%i:%s.%f%p'), +('15-01-2001 12:59:58', '%d-%m-%Y %H:%i:%S'), +('15 September 2001', '%d %M %Y'), +('15 SEPTEMB 2001', '%d %M %Y'), +('15 MAY 2001', '%d %b %Y'), +('15th May 2001', '%D %b %Y'), +('Sunday 15 MAY 2001', '%W %d %b %Y'), +('Sund 15 MAY 2001', '%W %d %b %Y'), +('Tuesday 00 2002', '%W %U %Y'), +('Thursday 53 1998', '%W %u %Y'), +('Sunday 01 2001', '%W %v %x'), +('Tuesday 52 2001', '%W %V %X'), +('060 2004', '%j %Y'), +('4 53 1998', '%w %u %Y'), +('15-01-2001', '%d-%m-%Y %H:%i:%S'), +('15-01-20', '%d-%m-%y'), +('15-2001-1', '%d-%Y-%c'); +select date,format,str_to_date(date, format) as str_to_date from t1; +date format str_to_date +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12 +10:20:10 %H:%i:%s 0000-00-00 10:20:10 +10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10 +10:20:10 %T 0000-00-00 10:20:10 +10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10 +10:20:10AM %r 0000-00-00 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58 +15 September 2001 %d %M %Y 2001-09-15 00:00:00 +15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00 +15 MAY 2001 %d %b %Y 2001-05-15 00:00:00 +15th May 2001 %D %b %Y 2001-05-15 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00 +Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00 +Sunday 01 2001 %W %v %x 2001-01-07 00:00:00 +Tuesday 52 2001 %W %V %X 2002-01-01 00:00:00 +060 2004 %j %Y 2004-02-29 00:00:00 +4 53 1998 %w %u %Y 1998-12-31 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00 +15-01-20 %d-%m-%y 2020-01-15 00:00:00 +15-2001-1 %d-%Y-%c 2001-01-15 00:00:00 +select date,format,concat('',str_to_date(date, format)) as con from t1; +date format con +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12 +10:20:10 %H:%i:%s 0000-00-00 10:20:10 +10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10 +10:20:10 %T 0000-00-00 10:20:10 +10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10 +10:20:10AM %r 0000-00-00 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58 +15 September 2001 %d %M %Y 2001-09-15 00:00:00 +15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00 +15 MAY 2001 %d %b %Y 2001-05-15 00:00:00 +15th May 2001 %D %b %Y 2001-05-15 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00 +Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00 +Sunday 01 2001 %W %v %x 2001-01-07 00:00:00 +Tuesday 52 2001 %W %V %X 2002-01-01 00:00:00 +060 2004 %j %Y 2004-02-29 00:00:00 +4 53 1998 %w %u %Y 1998-12-31 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00 +15-01-20 %d-%m-%y 2020-01-15 00:00:00 +15-2001-1 %d-%Y-%c 2001-01-15 00:00:00 +select date,format,cast(str_to_date(date, format) as datetime) as datetime from t1; +date format datetime +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.123450 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.123450 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.123450 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12 +10:20:10 %H:%i:%s 0000-00-00 10:20:10 +10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10 +10:20:10 %T 0000-00-00 10:20:10 +10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10 +10:20:10AM %r 0000-00-00 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.440000 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58 +15 September 2001 %d %M %Y 2001-09-15 00:00:00 +15 SEPTEMB 2001 %d %M %Y 2001-09-15 00:00:00 +15 MAY 2001 %d %b %Y 2001-05-15 00:00:00 +15th May 2001 %D %b %Y 2001-05-15 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00 +Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00 +Sunday 01 2001 %W %v %x 2001-01-07 00:00:00 +Tuesday 52 2001 %W %V %X 2002-01-01 00:00:00 +060 2004 %j %Y 2004-02-29 00:00:00 +4 53 1998 %w %u %Y 1998-12-31 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00 +15-01-20 %d-%m-%y 2020-01-15 00:00:00 +15-2001-1 %d-%Y-%c 2001-01-15 00:00:00 +select date,format,DATE(str_to_date(date, format)) as date2 from t1; +date format date2 +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 2003-01-02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 +10:20:10 %H:%i:%s 0000-00-00 +10:20:10 %h:%i:%s.%f 0000-00-00 +10:20:10 %T 0000-00-00 +10:20:10AM %h:%i:%s%p 0000-00-00 +10:20:10AM %r 0000-00-00 +10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 +15 September 2001 %d %M %Y 2001-09-15 +15 SEPTEMB 2001 %d %M %Y 2001-09-15 +15 MAY 2001 %d %b %Y 2001-05-15 +15th May 2001 %D %b %Y 2001-05-15 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 +Tuesday 00 2002 %W %U %Y 2002-01-01 +Thursday 53 1998 %W %u %Y 1998-12-31 +Sunday 01 2001 %W %v %x 2001-01-07 +Tuesday 52 2001 %W %V %X 2002-01-01 +060 2004 %j %Y 2004-02-29 +4 53 1998 %w %u %Y 1998-12-31 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 +15-01-20 %d-%m-%y 2020-01-15 +15-2001-1 %d-%Y-%c 2001-01-15 +select date,format,TIME(str_to_date(date, format)) as time from t1; +date format time +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.123450 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.123450 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.123450 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 23:11:12 +10:20:10 %H:%i:%s 10:20:10 +10:20:10 %h:%i:%s.%f 10:20:10 +10:20:10 %T 10:20:10 +10:20:10AM %h:%i:%s%p 10:20:10 +10:20:10AM %r 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 10:20:10.440000 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 12:59:58 +15 September 2001 %d %M %Y 00:00:00 +15 SEPTEMB 2001 %d %M %Y 00:00:00 +15 MAY 2001 %d %b %Y 00:00:00 +15th May 2001 %D %b %Y 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 00:00:00 +Tuesday 00 2002 %W %U %Y 00:00:00 +Thursday 53 1998 %W %u %Y 00:00:00 +Sunday 01 2001 %W %v %x 00:00:00 +Tuesday 52 2001 %W %V %X 00:00:00 +060 2004 %j %Y 00:00:00 +4 53 1998 %w %u %Y 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00 +15-01-20 %d-%m-%y 00:00:00 +15-2001-1 %d-%Y-%c 00:00:00 +select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1; +date format time2 +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S.%# 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.123450 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.123450 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.123450 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 23:11:12 +10:20:10 %H:%i:%s 10:20:10 +10:20:10 %h:%i:%s.%f 10:20:10 +10:20:10 %T 10:20:10 +10:20:10AM %h:%i:%s%p 10:20:10 +10:20:10AM %r 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 10:20:10.440000 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 12:59:58 +15 September 2001 %d %M %Y 00:00:00 +15 SEPTEMB 2001 %d %M %Y 00:00:00 +15 MAY 2001 %d %b %Y 00:00:00 +15th May 2001 %D %b %Y 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 00:00:00 +Tuesday 00 2002 %W %U %Y 00:00:00 +Thursday 53 1998 %W %u %Y 00:00:00 +Sunday 01 2001 %W %v %x 00:00:00 +Tuesday 52 2001 %W %V %X 00:00:00 +060 2004 %j %Y 00:00:00 +4 53 1998 %w %u %Y 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00 +15-01-20 %d-%m-%y 00:00:00 +15-2001-1 %d-%Y-%c 00:00:00 +select concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d')); +concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d')) +2003-01-02 08:11:02.123456 +truncate table t1; +insert into t1 values +('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'), +('2003-01-02 10:11:12.123456', '%Y-%m-%d %h:%i:%S %p'), +('2003-01-02 10:11:12AM', '%Y-%m-%d %h:%i:%S.%f %p'), +('2003-01-02 10:11:12AN', '%Y-%m-%d %h:%i:%S%p'), +('2003-01-02 10:11:12 PM', '%y-%m-%d %H:%i:%S %p'), +('10:20:10AM', '%H:%i:%s%p'), +('15 Septembei 2001', '%d %M %Y'), +('15 Ju 2001', '%d %M %Y'), +('Sund 15 MA', '%W %d %b %Y'), +('Thursdai 12 1998', '%W %u %Y'), +('Sunday 01 2001', '%W %v %X'), +('Tuesday 52 2001', '%W %V %x'), +('Tuesday 52 2001', '%W %V %Y'), +('Tuesday 52 2001', '%W %u %x'), +('7 53 1998', '%w %u %Y'), +(NULL, get_format(DATE,'USA')); +select date,format,str_to_date(date, format) as str_to_date from t1; +date format str_to_date +2003-01-02 10:11:12 PM %Y-%m-%d %H:%i:%S %p NULL +2003-01-02 10:11:12.123456 %Y-%m-%d %h:%i:%S %p NULL +2003-01-02 10:11:12AM %Y-%m-%d %h:%i:%S.%f %p NULL +2003-01-02 10:11:12AN %Y-%m-%d %h:%i:%S%p NULL +2003-01-02 10:11:12 PM %y-%m-%d %H:%i:%S %p NULL +10:20:10AM %H:%i:%s%p NULL +15 Septembei 2001 %d %M %Y NULL +15 Ju 2001 %d %M %Y NULL +Sund 15 MA %W %d %b %Y NULL +Thursdai 12 1998 %W %u %Y NULL +Sunday 01 2001 %W %v %X NULL +Tuesday 52 2001 %W %V %x NULL +Tuesday 52 2001 %W %V %Y NULL +Tuesday 52 2001 %W %u %x NULL +7 53 1998 %w %u %Y NULL +NULL %m.%d.%Y NULL +Warnings: +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12.123456' for function str_to_date +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AM' for function str_to_date +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AN' for function str_to_date +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date +Error 1411 Incorrect datetime value: '10:20:10AM' for function str_to_date +Error 1411 Incorrect datetime value: '15 Septembei 2001' for function str_to_date +Error 1411 Incorrect datetime value: '15 Ju 2001' for function str_to_date +Error 1411 Incorrect datetime value: 'Sund 15 MA' for function str_to_date +Error 1411 Incorrect datetime value: 'Thursdai 12 1998' for function str_to_date +Error 1411 Incorrect datetime value: 'Sunday 01 2001' for function str_to_date +Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Error 1411 Incorrect datetime value: '7 53 1998' for function str_to_date +select date,format,concat(str_to_date(date, format),'') as con from t1; +date format con +2003-01-02 10:11:12 PM %Y-%m-%d %H:%i:%S %p NULL +2003-01-02 10:11:12.123456 %Y-%m-%d %h:%i:%S %p NULL +2003-01-02 10:11:12AM %Y-%m-%d %h:%i:%S.%f %p NULL +2003-01-02 10:11:12AN %Y-%m-%d %h:%i:%S%p NULL +2003-01-02 10:11:12 PM %y-%m-%d %H:%i:%S %p NULL +10:20:10AM %H:%i:%s%p NULL +15 Septembei 2001 %d %M %Y NULL +15 Ju 2001 %d %M %Y NULL +Sund 15 MA %W %d %b %Y NULL +Thursdai 12 1998 %W %u %Y NULL +Sunday 01 2001 %W %v %X NULL +Tuesday 52 2001 %W %V %x NULL +Tuesday 52 2001 %W %V %Y NULL +Tuesday 52 2001 %W %u %x NULL +7 53 1998 %w %u %Y NULL +NULL %m.%d.%Y NULL +Warnings: +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12.123456' for function str_to_date +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AM' for function str_to_date +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AN' for function str_to_date +Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date +Error 1411 Incorrect datetime value: '10:20:10AM' for function str_to_date +Error 1411 Incorrect datetime value: '15 Septembei 2001' for function str_to_date +Error 1411 Incorrect datetime value: '15 Ju 2001' for function str_to_date +Error 1411 Incorrect datetime value: 'Sund 15 MA' for function str_to_date +Error 1411 Incorrect datetime value: 'Thursdai 12 1998' for function str_to_date +Error 1411 Incorrect datetime value: 'Sunday 01 2001' for function str_to_date +Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Error 1411 Incorrect datetime value: '7 53 1998' for function str_to_date +truncate table t1; +insert into t1 values +('10:20:10AM', '%h:%i:%s'), +('2003-01-02 10:11:12', '%Y-%m-%d %h:%i:%S'), +('03-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'); +select date,format,str_to_date(date, format) as str_to_date from t1; +date format str_to_date +10:20:10AM %h:%i:%s 0000-00-00 10:20:10 +2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12 +03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +Warnings: +Warning 1292 Incorrect datetime value: '10:20:10AM' +select date,format,concat(str_to_date(date, format),'') as con from t1; +date format con +10:20:10AM %h:%i:%s 0000-00-00 10:20:10 +2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12 +03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +Warnings: +Warning 1292 Incorrect datetime value: '10:20:10AM' +drop table t1; +select get_format(DATE, 'USA') as a; +a +%m.%d.%Y +select get_format(TIME, 'internal') as a; +a +%H%i%s +select get_format(DATETIME, 'eur') as a; +a +%Y-%m-%d %H.%i.%s +select get_format(TIMESTAMP, 'eur') as a; +a +%Y-%m-%d %H.%i.%s +select get_format(DATE, 'TEST') as a; +a +NULL +select str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA')); +str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA')) +NULL +Warnings: +Error 1411 Incorrect datetime value: '15-01-2001 12:59:59' for function str_to_date +explain extended select makedate(1997,1), addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM"),cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME), maketime(23,11,12),microsecond("1997-12-31 23:59:59.000001"); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select makedate(1997,1) AS `makedate(1997,1)`,addtime('31.12.97 11.59.59.999999 PM','1 1.1.1.000002') AS `addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")`,subtime('31.12.97 11.59.59.999999 PM','1 1.1.1.000002') AS `subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")`,timediff('01.01.97 11:59:59.000001 PM','31.12.95 11:59:59.000002 PM') AS `timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM")`,cast(str_to_date('15-01-2001 12:59:59','%d-%m-%Y %H:%i:%S') as time) AS `cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME)`,maketime(23,11,12) AS `maketime(23,11,12)`,microsecond('1997-12-31 23:59:59.000001') AS `microsecond("1997-12-31 23:59:59.000001")` +create table t1 (d date); +insert into t1 values ('2004-07-14'),('2005-07-14'); +select date_format(d,"%d") from t1 order by 1; +date_format(d,"%d") +14 +14 +drop table t1; +select str_to_date("2003-....01ABCD-02 10:11:12.0012", "%Y-%.%m%@-%d %H:%i:%S.%f") as a; +a +2003-01-02 10:11:12.001200 +create table t1 select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1, +str_to_date("10:11:12.0012", "%H:%i:%S.%f") as f2, +str_to_date("2003-01-02", "%Y-%m-%d") as f3, +str_to_date("02", "%d") as f4, str_to_date("02 10", "%d %H") as f5; +describe t1; +Field Type Null Key Default Extra +f1 datetime YES NULL +f2 time YES NULL +f3 date YES NULL +f4 date YES NULL +f5 time YES NULL +select * from t1; +f1 f2 f3 f4 f5 +2003-01-02 10:11:12 10:11:12 2003-01-02 0000-00-02 58:00:00 +drop table t1; +create table t1 select "02 10" as a, "%d %H" as b; +select str_to_date(a,b) from t1; +str_to_date(a,b) +0000-00-02 10:00:00 +create table t2 select str_to_date(a,b) from t1; +describe t2; +Field Type Null Key Default Extra +str_to_date(a,b) datetime YES NULL +select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1, +str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S") as f2, +str_to_date("2003-01-02", "%Y-%m-%d") as f3, +str_to_date("02 10:11:12", "%d %H:%i:%S.%f") as f4, +str_to_date("02 10:11:12", "%d %H:%i:%S") as f5, +str_to_date("02 10", "%d %f") as f6; +f1 f2 f3 f4 f5 f6 +2003-01-02 10:11:12.001200 2003-01-02 10:11:12 2003-01-02 58:11:12 58:11:12 48:00:00.100000 +Warnings: +Warning 1292 Truncated incorrect datetime value: '2003-01-02 10:11:12.0012' +drop table t1, t2; +select str_to_date("2003-01-02 10:11:12.0012ABCD", "%Y-%m-%d %H:%i:%S.%f") as f1, +addtime("-01:01:01.01 GGG", "-23:59:59.1") as f2, +microsecond("1997-12-31 23:59:59.01XXXX") as f3; +f1 f2 f3 +2003-01-02 10:11:12.001200 -25:01:00.110000 10000 +Warnings: +Warning 1292 Truncated incorrect datetime value: '2003-01-02 10:11:12.0012ABCD' +Warning 1292 Truncated incorrect time value: '-01:01:01.01 GGG' +Warning 1292 Truncated incorrect time value: '1997-12-31 23:59:59.01XXXX' +select str_to_date("2003-04-05 g", "%Y-%m-%d") as f1, +str_to_date("2003-04-05 10:11:12.101010234567", "%Y-%m-%d %H:%i:%S.%f") as f2; +f1 f2 +2003-04-05 2003-04-05 10:11:12.101010 +Warnings: +Warning 1292 Truncated incorrect date value: '2003-04-05 g' +Warning 1292 Truncated incorrect datetime value: '2003-04-05 10:11:12.101010234567' +set names latin1; +select date_format('2004-01-01','%W (%a), %e %M (%b) %Y'); +date_format('2004-01-01','%W (%a), %e %M (%b) %Y') +Thursday (Thu), 1 January (Jan) 2004 +set lc_time_names=ru_RU; +set names koi8r; +select date_format('2004-01-01','%W (%a), %e %M (%b) %Y'); +date_format('2004-01-01','%W (%a), %e %M (%b) %Y') +þÅÔ×ÅÒÇ (þÔ×), 1 ñÎ×ÁÒÑ (ñÎ×) 2004 +set lc_time_names=de_DE; +set names latin1; +select date_format('2004-01-01','%W (%a), %e %M (%b) %Y'); +date_format('2004-01-01','%W (%a), %e %M (%b) %Y') +Donnerstag (Do), 1 Januar (Jan) 2004 +set names latin1; +set lc_time_names=en_US; +create table t1 (f1 datetime); +insert into t1 (f1) values ("2005-01-01"); +insert into t1 (f1) values ("2005-02-01"); +select date_format(f1, "%m") as d1, date_format(f1, "%M") as d2 from t1 order by date_format(f1, "%M"); +d1 d2 +02 February +01 January +drop table t1; +select str_to_date( 1, NULL ); +str_to_date( 1, NULL ) +NULL +select str_to_date( NULL, 1 ); +str_to_date( NULL, 1 ) +NULL +select str_to_date( 1, IF(1=1,NULL,NULL) ); +str_to_date( 1, IF(1=1,NULL,NULL) ) +NULL +SELECT TIME_FORMAT("24:00:00", '%r'); +TIME_FORMAT("24:00:00", '%r') +12:00:00 AM +SELECT TIME_FORMAT("00:00:00", '%r'); +TIME_FORMAT("00:00:00", '%r') +12:00:00 AM +SELECT TIME_FORMAT("12:00:00", '%r'); +TIME_FORMAT("12:00:00", '%r') +12:00:00 PM +SELECT TIME_FORMAT("15:00:00", '%r'); +TIME_FORMAT("15:00:00", '%r') +03:00:00 PM +SELECT TIME_FORMAT("01:00:00", '%r'); +TIME_FORMAT("01:00:00", '%r') +01:00:00 AM +SELECT TIME_FORMAT("25:00:00", '%r'); +TIME_FORMAT("25:00:00", '%r') +01:00:00 AM +SELECT TIME_FORMAT("00:00:00", '%l %p'); +TIME_FORMAT("00:00:00", '%l %p') +12 AM +SELECT TIME_FORMAT("01:00:00", '%l %p'); +TIME_FORMAT("01:00:00", '%l %p') +1 AM +SELECT TIME_FORMAT("12:00:00", '%l %p'); +TIME_FORMAT("12:00:00", '%l %p') +12 PM +SELECT TIME_FORMAT("23:00:00", '%l %p'); +TIME_FORMAT("23:00:00", '%l %p') +11 PM +SELECT TIME_FORMAT("24:00:00", '%l %p'); +TIME_FORMAT("24:00:00", '%l %p') +12 AM +SELECT TIME_FORMAT("25:00:00", '%l %p'); +TIME_FORMAT("25:00:00", '%l %p') +1 AM +SELECT DATE_FORMAT('%Y-%m-%d %H:%i:%s', 1151414896); +DATE_FORMAT('%Y-%m-%d %H:%i:%s', 1151414896) +NULL +Warnings: +Warning 1292 Incorrect datetime value: '%Y-%m-%d %H:%i:%s' +select str_to_date('04 /30/2004', '%m /%d/%Y'); +str_to_date('04 /30/2004', '%m /%d/%Y') +2004-04-30 +select str_to_date('04/30 /2004', '%m /%d /%Y'); +str_to_date('04/30 /2004', '%m /%d /%Y') +2004-04-30 +select str_to_date('04/30/2004 ', '%m/%d/%Y '); +str_to_date('04/30/2004 ', '%m/%d/%Y ') +2004-04-30 +"End of 4.1 tests" diff --git a/mysql-test/suite/pbxt/r/default.result b/mysql-test/suite/pbxt/r/default.result new file mode 100644 index 00000000000..0accb8ecf85 --- /dev/null +++ b/mysql-test/suite/pbxt/r/default.result @@ -0,0 +1,198 @@ +drop table if exists t1,t2,t3,t4,t5,t6; +drop database if exists mysqltest; +CREATE TABLE t1 (a varchar(30) binary NOT NULL DEFAULT ' ', +b varchar(1) binary NOT NULL DEFAULT ' ', +c varchar(4) binary NOT NULL DEFAULT '0000', +d tinyblob NULL, +e tinyblob NULL, +f tinyblob NULL, +g tinyblob NULL, +h tinyblob NULL, +i tinyblob NULL, +j tinyblob NULL, +k tinyblob NULL, +l tinyblob NULL, +m tinyblob NULL, +n tinyblob NULL, +o tinyblob NULL, +p tinyblob NULL, +q varchar(30) binary NOT NULL DEFAULT ' ', +r varchar(30) binary NOT NULL DEFAULT ' ', +s tinyblob NULL, +t varchar(4) binary NOT NULL DEFAULT ' ', +u varchar(1) binary NOT NULL DEFAULT ' ', +v varchar(30) binary NOT NULL DEFAULT ' ', +w varchar(30) binary NOT NULL DEFAULT ' ', +x tinyblob NULL, +y varchar(5) binary NOT NULL DEFAULT ' ', +z varchar(20) binary NOT NULL DEFAULT ' ', +a1 varchar(30) binary NOT NULL DEFAULT ' ', +b1 tinyblob NULL) +ENGINE=InnoDB DEFAULT CHARACTER SET = latin1 COLLATE latin1_bin; +INSERT into t1 (b) values ('1'); +SHOW WARNINGS; +Level Code Message +SELECT * from t1; +a b c d e f g h i j k l m n o p q r s t u v w x y z a1 b1 + 1 0000 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL +CREATE TABLE t2 (a varchar(30) binary NOT NULL DEFAULT ' ', +b varchar(1) binary NOT NULL DEFAULT ' ', +c varchar(4) binary NOT NULL DEFAULT '0000', +d tinyblob NULL, +e tinyblob NULL, +f tinyblob NULL, +g tinyblob NULL, +h tinyblob NULL, +i tinyblob NULL, +j tinyblob NULL, +k tinyblob NULL, +l tinyblob NULL, +m tinyblob NULL, +n tinyblob NULL, +o tinyblob NULL, +p tinyblob NULL, +q varchar(30) binary NOT NULL DEFAULT ' ', +r varchar(30) binary NOT NULL DEFAULT ' ', +s tinyblob NULL, +t varchar(4) binary NOT NULL DEFAULT ' ', +u varchar(1) binary NOT NULL DEFAULT ' ', +v varchar(30) binary NOT NULL DEFAULT ' ', +w varchar(30) binary NOT NULL DEFAULT ' ', +x tinyblob NULL, +y varchar(5) binary NOT NULL DEFAULT ' ', +z varchar(20) binary NOT NULL DEFAULT ' ', +a1 varchar(30) binary NOT NULL DEFAULT ' ', +b1 tinyblob NULL) +ENGINE=MyISAM DEFAULT CHARACTER SET = latin1 COLLATE latin1_bin; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(30) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `b` varchar(1) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `c` varchar(4) COLLATE latin1_bin NOT NULL DEFAULT '0000', + `d` tinyblob, + `e` tinyblob, + `f` tinyblob, + `g` tinyblob, + `h` tinyblob, + `i` tinyblob, + `j` tinyblob, + `k` tinyblob, + `l` tinyblob, + `m` tinyblob, + `n` tinyblob, + `o` tinyblob, + `p` tinyblob, + `q` varchar(30) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `r` varchar(30) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `s` tinyblob, + `t` varchar(4) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `u` varchar(1) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `v` varchar(30) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `w` varchar(30) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `x` tinyblob, + `y` varchar(5) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `z` varchar(20) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `a1` varchar(30) COLLATE latin1_bin NOT NULL DEFAULT ' ', + `b1` tinyblob +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_bin +INSERT into t2 (b) values ('1'); +SHOW WARNINGS; +Level Code Message +SELECT * from t2; +a b c d e f g h i j k l m n o p q r s t u v w x y z a1 b1 + 1 0000 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL +drop table t1; +drop table t2; +create table bug20691 (i int, d datetime NOT NULL, dn datetime not null default '0000-00-00 00:00:00'); +insert into bug20691 values (1, DEFAULT, DEFAULT), (1, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (1, DEFAULT, DEFAULT); +Warnings: +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +insert into bug20691 (i) values (2); +Warnings: +Warning 1364 Field 'd' doesn't have a default value +desc bug20691; +Field Type Null Key Default Extra +i int(11) YES NULL +d datetime NO NULL +dn datetime NO 0000-00-00 00:00:00 +insert into bug20691 values (3, DEFAULT, DEFAULT), (3, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (3, DEFAULT, DEFAULT); +Warnings: +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +insert into bug20691 (i) values (4); +Warnings: +Warning 1364 Field 'd' doesn't have a default value +insert into bug20691 values (5, DEFAULT, DEFAULT), (5, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (5, DEFAULT, DEFAULT); +Warnings: +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +SET sql_mode = 'ALLOW_INVALID_DATES'; +insert into bug20691 values (6, DEFAULT, DEFAULT), (6, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (6, DEFAULT, DEFAULT); +Warnings: +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +SET sql_mode = 'STRICT_ALL_TABLES'; +insert into bug20691 values (7, DEFAULT, DEFAULT), (7, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (7, DEFAULT, DEFAULT); +ERROR HY000: Field 'd' doesn't have a default value +select * from bug20691 order by i asc; +i d dn +1 0000-00-00 00:00:00 0000-00-00 00:00:00 +1 1975-07-10 07:10:03 1978-01-13 14:08:51 +1 0000-00-00 00:00:00 0000-00-00 00:00:00 +2 0000-00-00 00:00:00 0000-00-00 00:00:00 +3 0000-00-00 00:00:00 0000-00-00 00:00:00 +3 1975-07-10 07:10:03 1978-01-13 14:08:51 +3 0000-00-00 00:00:00 0000-00-00 00:00:00 +4 0000-00-00 00:00:00 0000-00-00 00:00:00 +5 0000-00-00 00:00:00 0000-00-00 00:00:00 +5 1975-07-10 07:10:03 1978-01-13 14:08:51 +5 0000-00-00 00:00:00 0000-00-00 00:00:00 +6 0000-00-00 00:00:00 0000-00-00 00:00:00 +6 1975-07-10 07:10:03 1978-01-13 14:08:51 +6 0000-00-00 00:00:00 0000-00-00 00:00:00 +drop table bug20691; +SET sql_mode = ''; +create table bug20691 ( +a set('one', 'two', 'three') not null, +b enum('small', 'medium', 'large', 'enormous', 'ellisonego') not null, +c time not null, +d date not null, +e int not null, +f long not null, +g blob not null, +h datetime not null, +i decimal not null, +x int); +insert into bug20691 values (2, 3, 5, '0007-01-01', 11, 13, 17, '0019-01-01 00:00:00', 23, 1); +insert into bug20691 (x) values (2); +Warnings: +Warning 1364 Field 'a' doesn't have a default value +Warning 1364 Field 'c' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'e' doesn't have a default value +Warning 1364 Field 'f' doesn't have a default value +Warning 1364 Field 'g' doesn't have a default value +Warning 1364 Field 'h' doesn't have a default value +Warning 1364 Field 'i' doesn't have a default value +insert into bug20691 values (2, 3, 5, '0007-01-01', 11, 13, 17, '0019-01-01 00:00:00', 23, 3); +insert into bug20691 values (DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 4); +Warnings: +Warning 1364 Field 'a' doesn't have a default value +Warning 1364 Field 'b' doesn't have a default value +Warning 1364 Field 'c' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'e' doesn't have a default value +Warning 1364 Field 'f' doesn't have a default value +Warning 1364 Field 'g' doesn't have a default value +Warning 1364 Field 'h' doesn't have a default value +Warning 1364 Field 'i' doesn't have a default value +select * from bug20691 order by x asc; +a b c d e f g h i x +two large 00:00:05 0007-01-01 11 13 17 0019-01-01 00:00:00 23 1 + small 00:00:00 0000-00-00 0 0000-00-00 00:00:00 0 2 +two large 00:00:05 0007-01-01 11 13 17 0019-01-01 00:00:00 23 3 + 00:00:00 0000-00-00 0 0000-00-00 00:00:00 0 4 +drop table bug20691; +End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/r/delete.result b/mysql-test/suite/pbxt/r/delete.result new file mode 100644 index 00000000000..9d337a1ed34 --- /dev/null +++ b/mysql-test/suite/pbxt/r/delete.result @@ -0,0 +1,208 @@ +drop table if exists t1,t2,t3,t11,t12; +CREATE TABLE t1 (a tinyint(3), b tinyint(5)); +INSERT INTO t1 VALUES (1,1); +INSERT LOW_PRIORITY INTO t1 VALUES (1,2); +INSERT INTO t1 VALUES (1,3); +DELETE from t1 where a=1 limit 1; +DELETE LOW_PRIORITY from t1 where a=1; +INSERT INTO t1 VALUES (1,1); +DELETE from t1; +LOCK TABLE t1 write; +INSERT INTO t1 VALUES (1,2); +DELETE from t1; +UNLOCK TABLES; +INSERT INTO t1 VALUES (1,2); +SET AUTOCOMMIT=0; +DELETE from t1; +SET AUTOCOMMIT=1; +drop table t1; +create table t1 ( +a bigint not null, +b bigint not null default 0, +c bigint not null default 0, +d bigint not null default 0, +e bigint not null default 0, +f bigint not null default 0, +g bigint not null default 0, +h bigint not null default 0, +i bigint not null default 0, +j bigint not null default 0, +primary key (a,b,c,d,e,f,g,h,i,j)); +insert into t1 (a) values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23); +delete from t1 where a=26; +drop table t1; +create table t1 ( +a bigint not null, +b bigint not null default 0, +c bigint not null default 0, +d bigint not null default 0, +e bigint not null default 0, +f bigint not null default 0, +g bigint not null default 0, +h bigint not null default 0, +i bigint not null default 0, +j bigint not null default 0, +primary key (a,b,c,d,e,f,g,h,i,j)); +insert into t1 (a) values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23),(27); +delete from t1 where a=27; +drop table t1; +CREATE TABLE `t1` ( +`i` int(10) NOT NULL default '0', +`i2` int(10) NOT NULL default '0', +PRIMARY KEY (`i`) +); +DELETE FROM t1 USING t1 WHERE post='1'; +ERROR 42S22: Unknown column 'post' in 'where clause' +drop table t1; +CREATE TABLE t1 ( +bool char(0) default NULL, +not_null varchar(20) binary NOT NULL default '', +misc integer not null, +PRIMARY KEY (not_null) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (NULL,'a',4), (NULL,'b',5), (NULL,'c',6), (NULL,'d',7); +select * from t1 where misc > 5 and bool is null; +bool not_null misc +NULL c 6 +NULL d 7 +delete from t1 where misc > 5 and bool is null; +select * from t1 where misc > 5 and bool is null; +bool not_null misc +select count(*) from t1; +count(*) +2 +delete from t1 where 1 > 2; +select count(*) from t1; +count(*) +2 +delete from t1 where 3 > 2; +select count(*) from t1; +count(*) +0 +drop table t1; +create table t1 (a int not null auto_increment primary key, b char(32)); +insert into t1 (b) values ('apple'), ('apple'); +select * from t1; +a b +1 apple +2 apple +delete t1 from t1, t1 as t2 where t1.b = t2.b and t1.a > t2.a; +select * from t1; +a b +1 apple +drop table t1; +create table t11 (a int NOT NULL, b int, primary key (a)); +create table t12 (a int NOT NULL, b int, primary key (a)); +create table t2 (a int NOT NULL, b int, primary key (a)); +insert into t11 values (0, 10),(1, 11),(2, 12); +insert into t12 values (33, 10),(0, 11),(2, 12); +insert into t2 values (1, 21),(2, 12),(3, 23); +select * from t11; +a b +0 10 +1 11 +2 12 +select * from t12; +a b +33 10 +0 11 +2 12 +select * from t2; +a b +1 21 +2 12 +3 23 +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b <> (select b from t2 where t11.a < t2.a); +ERROR 21000: Subquery returns more than 1 row +select * from t11; +a b +0 10 +1 11 +2 12 +select * from t12; +a b +33 10 +0 11 +2 12 +delete ignore t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b <> (select b from t2 where t11.a < t2.a); +Warnings: +Error 1242 Subquery returns more than 1 row +Error 1242 Subquery returns more than 1 row +select * from t11; +a b +0 10 +1 11 +select * from t12; +a b +33 10 +0 11 +insert into t11 values (2, 12); +delete from t11 where t11.b <> (select b from t2 where t11.a < t2.a); +ERROR 21000: Subquery returns more than 1 row +select * from t11; +a b +0 10 +1 11 +2 12 +delete ignore from t11 where t11.b <> (select b from t2 where t11.a < t2.a); +Warnings: +Error 1242 Subquery returns more than 1 row +Error 1242 Subquery returns more than 1 row +select * from t11; +a b +0 10 +1 11 +drop table t11, t12, t2; +create table t1 (a int, b int, unique key (a), key (b)); +insert into t1 values (3, 3), (7, 7); +delete t1 from t1 where a = 3; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select * from t1; +a b +7 7 +drop table t1; +CREATE TABLE t1 ( a int PRIMARY KEY ); +DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a; +INSERT INTO t1 VALUES (0),(1),(2); +DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a LIMIT 1; +SELECT * FROM t1; +a +0 +2 +DROP TABLE t1; +create table t1 (a int); +delete `4.t1` from t1 as `4.t1` where `4.t1`.a = 5; +delete FROM `4.t1` USING t1 as `4.t1` where `4.t1`.a = 5; +drop table t1; +CREATE TABLE t1 (a int not null,b int not null); +CREATE TABLE t2 (a int not null, b int not null, primary key (a,b)); +CREATE TABLE t3 (a int not null, b int not null, primary key (a,b)); +insert into t1 values (1,1),(2,1),(1,3); +insert into t2 values (1,1),(2,2),(3,3); +insert into t3 values (1,1),(2,1),(1,3); +select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b; +a b a b a b +1 1 1 1 1 1 +2 1 2 2 2 1 +1 3 1 1 1 3 +explain select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a 1 Using index +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 8 test.t2.b,test.t1.b 1 Using index +delete t2.*,t3.* from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b; +select * from t3; +a b +drop table t1,t2,t3; +create table t1(a date not null); +insert into t1 values (0); +select * from t1 where a is null; +a +0000-00-00 +delete from t1 where a is null; +select count(*) from t1; +count(*) +0 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/derived.result b/mysql-test/suite/pbxt/r/derived.result new file mode 100644 index 00000000000..fb723c45c0f --- /dev/null +++ b/mysql-test/suite/pbxt/r/derived.result @@ -0,0 +1,391 @@ +drop table if exists t1,t2,t3; +select * from (select 2 from DUAL) b; +2 +2 +SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; +ERROR 42S22: Unknown column 'a' in 'field list' +SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; +ERROR 42S22: Unknown column 'a' in 'field list' +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); +select t1.a,t3.y from t1,(select a as y from t2 where b='c') as t3 where t1.a = t3.y; +a y +3 3 +3 3 +select t1.a,t3.a from t1,(select * from t2 where b='c') as t3 where t1.a = t3.a; +a a +3 3 +3 3 +CREATE TABLE t3 (a int not null, b char (10) not null); +insert into t3 values (3,'f'),(4,'y'),(5,'z'),(6,'c'); +select t1.a,t4.y from t1,(select t2.a as y from t2,(select t3.b from t3 where t3.a>3) as t5 where t2.b=t5.b) as t4 where t1.a = t4.y; +a y +3 3 +3 3 +SELECT a FROM (SELECT 1 FROM (SELECT 1) a HAVING a=1) b; +ERROR 42S22: Unknown column 'a' in 'having clause' +SELECT a,b as a FROM (SELECT '1' as a,'2' as b) b HAVING a=1; +ERROR 23000: Column 'a' in having clause is ambiguous +SELECT a,2 as a FROM (SELECT '1' as a) b HAVING a=2; +a a +1 2 +SELECT a,2 as a FROM (SELECT '1' as a) b HAVING a=1; +a a +SELECT 1 FROM (SELECT 1) a WHERE a=2; +ERROR 42S22: Unknown column 'a' in 'where clause' +SELECT (SELECT 1) as a FROM (SELECT 1 FROM t1 HAVING a=1) as a; +ERROR 42S22: Unknown column 'a' in 'having clause' +select * from t1 as x1, (select * from t1) as x2; +a b a b +1 a 1 a +2 b 1 a +3 c 1 a +3 c 1 a +1 a 2 b +2 b 2 b +3 c 2 b +3 c 2 b +1 a 3 c +2 b 3 c +3 c 3 c +3 c 3 c +1 a 3 c +2 b 3 c +3 c 3 c +3 c 3 c +explain select * from t1 as x1, (select * from t1) as x2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY x1 ALL NULL NULL NULL NULL 4 +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4 Using join buffer +2 DERIVED t1 ALL NULL NULL NULL NULL 4 +drop table if exists t2,t3; +select * from (select 1) as a; +1 +1 +select a from (select 1 as a) as b; +a +1 +select 1 from (select 1) as a; +1 +1 +select * from (select * from t1 union select * from t1) a; +a b +1 a +2 b +3 c +select * from (select * from t1 union all select * from t1) a; +a b +1 a +2 b +3 c +3 c +1 a +2 b +3 c +3 c +select * from (select * from t1 union all select * from t1 limit 2) a; +a b +1 a +2 b +explain select * from (select * from t1 union select * from t1) a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 +2 DERIVED t1 ALL NULL NULL NULL NULL 4 +3 UNION t1 ALL NULL NULL NULL NULL 4 +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL +explain select * from (select * from t1 union all select * from t1) a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 8 +2 DERIVED t1 ALL NULL NULL NULL NULL 4 +3 UNION t1 ALL NULL NULL NULL NULL 4 +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL +CREATE TABLE t2 (a int not null); +insert into t2 values(1); +select * from (select * from t1 where t1.a=(select a from t2 where t2.a=t1.a)) a; +a b +1 a +select * from (select * from t1 where t1.a=(select t2.a from t2 where t2.a=t1.a) union select t1.a, t1.b from t1) a; +a b +1 a +2 b +3 c +explain select * from (select t1.*, t2.a as t2a from t1,t2 where t1.a=t2.a) t1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> system NULL NULL NULL NULL 1 +2 DERIVED t2 ALL NULL NULL NULL NULL 1 +2 DERIVED t1 ALL NULL NULL NULL NULL 4 Using where; Using join buffer +drop table t1, t2; +create table t1(a int not null, t char(8), index(a)); +SELECT * FROM (SELECT * FROM t1) as b ORDER BY a ASC LIMIT 0,20; +a t +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +explain select count(*) from t1 as tt1, (select * from t1) as tt2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY tt1 index NULL a 4 NULL 10000 Using index +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 10000 Using join buffer +2 DERIVED t1 ALL NULL NULL NULL NULL 10000 +drop table t1; +SELECT * FROM (SELECT (SELECT * FROM (SELECT 1 as a) as a )) as b; +(SELECT * FROM (SELECT 1 as a) as a ) +1 +select * from (select 1 as a) b left join (select 2 as a) c using(a); +a +1 +SELECT * FROM (SELECT 1 UNION SELECT a) b; +ERROR 42S22: Unknown column 'a' in 'field list' +SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; +ERROR 42S22: Unknown column 'a' in 'field list' +SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; +ERROR 42S22: Unknown column 'a' in 'field list' +select 1 from (select 2) a order by 0; +ERROR 42S22: Unknown column '0' in 'order clause' +create table t1 (id int); +insert into t1 values (1),(2),(3); +describe select * from (select * from t1 group by id) bar; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 +2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary; Using filesort +drop table t1; +create table t1 (mat_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, matintnum CHAR(6) NOT NULL, test MEDIUMINT UNSIGNED NULL); +create table t2 (mat_id MEDIUMINT UNSIGNED NOT NULL, pla_id MEDIUMINT UNSIGNED NOT NULL); +insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd', 4), (NULL, 'e', 5), (NULL, 'f', 6), (NULL, 'g', 7), (NULL, 'h', 8), (NULL, 'i', 9); +insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105); +SELECT STRAIGHT_JOIN d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +pla_id mat_id +100 1 +101 1 +102 1 +103 2 +104 2 +105 3 +SELECT STRAIGHT_JOIN d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +pla_id test +100 1 +101 1 +102 1 +103 2 +104 2 +105 3 +explain SELECT STRAIGHT_JOIN d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY m2 ALL NULL NULL NULL NULL 9 +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 6 Using where; Using join buffer +2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort +2 DERIVED m1 eq_ref PRIMARY PRIMARY 3 test.mp.mat_id 1 +explain SELECT STRAIGHT_JOIN d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY m2 ALL NULL NULL NULL NULL 9 +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 6 Using where; Using join buffer +2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort +2 DERIVED m1 eq_ref PRIMARY PRIMARY 3 test.mp.mat_id 1 +drop table t1,t2; +SELECT a.x FROM (SELECT 1 AS x) AS a HAVING a.x = 1; +x +1 +create user mysqltest_1; +create table t1 select 1 as a; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select 2 as a from (select * from t1) b; +ERROR 3D000: No database selected +use test; +select 2 as a from (select * from t1) b; +a +2 +drop table t1; +select mail_id, if(folder.f_description!='', folder.f_description, folder.f_name) as folder_name, date, address_id, phrase, address, subject from folder, (select mail.mail_id as mail_id, date_format(mail.h_date, '%b %e, %Y %h:%i') as date, mail.folder_id, sender.address_id as address_id, sender.phrase as phrase, sender.address as address, mail.h_subject as subject from mail left join mxa as mxa_sender on mail.mail_id=mxa_sender.mail_id and mxa_sender.type='from' left join address as sender on mxa_sender.address_id=sender.address_id mxa as mxa_recipient, address as recipient, where 1 and mail.mail_id=mxa_recipient.mail_id and mxa_recipient.address_id=recipient.address_id and mxa_recipient.type='to' and match(sender.phrase, sender.address, sender.comment) against ('jeremy' in boolean mode) and match(recipient.phrase, recipient.address, recipient.comment) against ('monty' in boolean mode) order by mail.h_date desc limit 0, 25 ) as query where query.folder_id=folder.folder_id; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'mxa as mxa_recipient, address as recipient, where 1 and mail.mail_id=mxa_r' at line 1 +create table t1 (a int); +insert into t1 values (1),(2),(3); +update (select * from t1) as t1 set a = 5; +ERROR HY000: The target table t1 of the UPDATE is not updatable +delete from (select * from t1); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(select * from t1)' at line 1 +insert into (select * from t1) values (5); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(select * from t1) values (5)' at line 1 +drop table t1; +create table t1 (E1 INTEGER UNSIGNED NOT NULL, E2 INTEGER UNSIGNED NOT NULL, E3 INTEGER UNSIGNED NOT NULL, PRIMARY KEY(E1) +); +insert into t1 VALUES(1,1,1), (2,2,1); +select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2; +count(*) +2 +explain select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 THEMAX.E2 1 Using where +2 DERIVED A ALL NULL NULL NULL NULL 2 Using where +3 DEPENDENT SUBQUERY B ALL NULL NULL NULL NULL 2 Using where +drop table t1; +create table t1 (a int); +insert into t1 values (1),(2); +select * from ( select * from t1 union select * from t1) a,(select * from t1 union select * from t1) b; +a a +1 1 +2 1 +1 2 +2 2 +explain select * from ( select * from t1 union select * from t1) a,(select * from t1 union select * from t1) b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 +1 PRIMARY <derived4> ALL NULL NULL NULL NULL 2 Using join buffer +4 DERIVED t1 ALL NULL NULL NULL NULL 2 +5 UNION t1 ALL NULL NULL NULL NULL 2 +NULL UNION RESULT <union4,5> ALL NULL NULL NULL NULL NULL +2 DERIVED t1 ALL NULL NULL NULL NULL 2 +3 UNION t1 ALL NULL NULL NULL NULL 2 +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL +drop table t1; +CREATE TABLE `t1` ( +`N` int(11) unsigned NOT NULL default '0', +`M` tinyint(1) default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO `t1` (N, M) VALUES (1, 0),(1, 0),(1, 0),(2, 0),(2, 0),(3, 0); +UPDATE `t1` AS P1 INNER JOIN (SELECT N FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N SET P1.M = 2; +select * from t1; +N M +1 2 +1 2 +1 2 +2 2 +2 2 +3 0 +UPDATE `t1` AS P1 INNER JOIN (SELECT N FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N SET P1.M = 2, P2.N = 2; +ERROR HY000: The target table P2 of the UPDATE is not updatable +UPDATE `t1` AS P1 INNER JOIN (SELECT aaaa FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N SET P1.M = 2; +ERROR 42S22: Unknown column 'aaaa' in 'field list' +delete P1.* from `t1` AS P1 INNER JOIN (SELECT N FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N; +select * from t1; +N M +3 0 +delete P1.*,p2.* from `t1` AS P1 INNER JOIN (SELECT N FROM `t1` GROUP BY N HAVING Count(M) > 1) AS p2 ON P1.N = p2.N; +ERROR 42S02: Unknown table 'p2' in MULTI DELETE +delete P1.* from `t1` AS P1 INNER JOIN (SELECT aaa FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N; +ERROR 42S22: Unknown column 'aaa' in 'field list' +drop table t1; +CREATE TABLE t1 ( +OBJECTID int(11) NOT NULL default '0', +SORTORDER int(11) NOT NULL auto_increment, +KEY t1_SortIndex (SORTORDER), +KEY t1_IdIndex (OBJECTID) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +CREATE TABLE t2 ( +ID int(11) default NULL, +PARID int(11) default NULL, +UNIQUE KEY t2_ID_IDX (ID), +KEY t2_PARID_IDX (PARID) +) engine=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO t2 VALUES (1000,0),(1001,0),(1002,0),(1003,0),(1008,1),(1009,1),(1010,1),(1011,1),(1016,2); +CREATE TABLE t3 ( +ID int(11) default NULL, +DATA decimal(10,2) default NULL, +UNIQUE KEY t3_ID_IDX (ID) +) engine=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO t3 VALUES (1000,0.00),(1001,0.25),(1002,0.50),(1003,0.75),(1008,1.00),(1009,1.25),(1010,1.50),(1011,1.75); +select 497, TMP.ID, NULL from (select 497 as ID, MAX(t3.DATA) as DATA from t1 join t2 on (t1.ObjectID = t2.ID) join t3 on (t1.ObjectID = t3.ID) group by t2.ParID order by DATA DESC) as TMP; +497 ID NULL +drop table t1, t2, t3; +CREATE TABLE t1 (name char(1) default NULL, val int(5) default NULL); +INSERT INTO t1 VALUES ('a',1), ('a',2), ('a',2), ('a',2), ('a',3), ('a',6), ('a',7), ('a',11), ('a',11), ('a',12), ('a',13), ('a',13), ('a',20), ('b',2), ('b',3), ('b',4), ('b',5); +SELECT s.name, AVG(s.val) AS median FROM (SELECT x.name, x.val FROM t1 x, t1 y WHERE x.name=y.name GROUP BY x.name, x.val HAVING SUM(y.val <= x.val) >= COUNT(*)/2 AND SUM(y.val >= x.val) >= COUNT(*)/2) AS s GROUP BY s.name; +name median +a 7.0000 +b 3.5000 +explain SELECT s.name, AVG(s.val) AS median FROM (SELECT x.name, x.val FROM t1 x, t1 y WHERE x.name=y.name GROUP BY x.name, x.val HAVING SUM(y.val <= x.val) >= COUNT(*)/2 AND SUM(y.val >= x.val) >= COUNT(*)/2) AS s GROUP BY s.name; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 Using temporary; Using filesort +2 DERIVED x ALL NULL NULL NULL NULL 17 Using temporary; Using filesort +2 DERIVED y ALL NULL NULL NULL NULL 17 Using where; Using join buffer +drop table t1; +create table t2 (a int, b int, primary key (a)); +insert into t2 values (1,7),(2,7); +explain select a from t2 where a>1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index PRIMARY PRIMARY 4 NULL 2 Using where; Using index +explain select a from (select a from t2 where a>1) tt; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> system NULL NULL NULL NULL 1 +2 DERIVED t2 index PRIMARY PRIMARY 4 NULL 2 Using where; Using index +drop table t2; +CREATE TABLE `t1` ( `itemid` int(11) NOT NULL default '0', `grpid` varchar(15) NOT NULL default '', `vendor` int(11) NOT NULL default '0', `date_` date NOT NULL default '0000-00-00', `price` decimal(12,2) NOT NULL default '0.00', PRIMARY KEY (`itemid`,`grpid`,`vendor`,`date_`), KEY `itemid` (`itemid`,`vendor`), KEY `itemid_2` (`itemid`,`date_`)); +insert into t1 values (128, 'rozn', 2, now(), 10),(128, 'rozn', 1, now(), 10); +Warnings: +Note 1265 Data truncated for column 'date_' at row 1 +Note 1265 Data truncated for column 'date_' at row 2 +SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MAX(concat(date_,";",price)), 12) price FROM t1 WHERE itemid=128 AND grpid='rozn' GROUP BY itemid, grpid, vendor) lastprices; +min max avg +10.00 10.00 10 +DROP TABLE t1; +create table t1 (a integer, b integer); +insert into t1 values (1,4), (2,2),(2,2), (4,1),(4,1),(4,1),(4,1); +select distinct sum(b) from t1 group by a; +sum(b) +4 +select distinct sum(b) from (select a,b from t1) y group by a; +sum(b) +4 +drop table t1; +CREATE TABLE t1 (a char(10), b char(10)); +INSERT INTO t1 VALUES ('root','localhost'), ('root','%'); +SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c; +ERROR 21000: Subquery returns more than 1 row +DROP TABLE t1; +create table t1(a int); +create table t2(a int); +create table t3(a int); +insert into t1 values(1),(1); +insert into t2 values(2),(2); +insert into t3 values(3),(3); +select * from t1 union distinct select * from t2 union all select * from t3; +a +1 +2 +3 +3 +select * from (select * from t1 union distinct select * from t2 union all select * from t3) X; +a +1 +2 +3 +3 +drop table t1, t2, t3; +create table t1 (a int); +create table t2 (a int); +select * from (select * from t1,t2) foo; +ERROR 42S21: Duplicate column name 'a' +drop table t1,t2; +create table t1 (ID int unsigned not null auto_increment, +DATA varchar(5) not null, primary key (ID)); +create table t2 (ID int unsigned not null auto_increment, +DATA varchar(5) not null, FID int unsigned not null, +primary key (ID)); +select A.* from (t1 inner join (select * from t2) as A on t1.ID = A.FID); +ID DATA FID +select t2.* from ((select * from t1) as A inner join t2 on A.ID = t2.FID); +ID DATA FID +select t2.* from (select * from t1) as A inner join t2 on A.ID = t2.FID; +ID DATA FID +drop table t1, t2; +drop user mysqltest_1; diff --git a/mysql-test/suite/pbxt/r/dirty_close.result b/mysql-test/suite/pbxt/r/dirty_close.result new file mode 100644 index 00000000000..c4fc19a35f8 --- /dev/null +++ b/mysql-test/suite/pbxt/r/dirty_close.result @@ -0,0 +1,9 @@ +drop table if exists t1; +create table t1 (n int); +insert into t1 values (1),(2),(3); +select * from t1; +n +1 +2 +3 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/distinct.result b/mysql-test/suite/pbxt/r/distinct.result new file mode 100644 index 00000000000..7da52ea4bd1 --- /dev/null +++ b/mysql-test/suite/pbxt/r/distinct.result @@ -0,0 +1,646 @@ +drop table if exists t1,t2,t3; +CREATE TABLE t1 (id int,facility char(20)); +CREATE TABLE t2 (facility char(20)); +INSERT INTO t1 VALUES (NULL,NULL); +INSERT INTO t1 VALUES (-1,''); +INSERT INTO t1 VALUES (0,''); +INSERT INTO t1 VALUES (1,'/L'); +INSERT INTO t1 VALUES (2,'A01'); +INSERT INTO t1 VALUES (3,'ANC'); +INSERT INTO t1 VALUES (4,'F01'); +INSERT INTO t1 VALUES (5,'FBX'); +INSERT INTO t1 VALUES (6,'MT'); +INSERT INTO t1 VALUES (7,'P'); +INSERT INTO t1 VALUES (8,'RV'); +INSERT INTO t1 VALUES (9,'SRV'); +INSERT INTO t1 VALUES (10,'VMT'); +INSERT INTO t2 SELECT DISTINCT FACILITY FROM t1; +select id from t1 group by id; +id +NULL +-1 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +select * from t1 order by id; +id facility +NULL NULL +-1 +0 +1 /L +2 A01 +3 ANC +4 F01 +5 FBX +6 MT +7 P +8 RV +9 SRV +10 VMT +select id-5,facility from t1 order by "id-5"; +id-5 facility +NULL NULL +-6 +-5 +-4 /L +-3 A01 +-2 ANC +-1 F01 +0 FBX +1 MT +2 P +3 RV +4 SRV +5 VMT +select id,concat(facility) from t1 group by id ; +id concat(facility) +NULL NULL +-1 +0 +1 /L +2 A01 +3 ANC +4 F01 +5 FBX +6 MT +7 P +8 RV +9 SRV +10 VMT +select id+0 as a,max(id),concat(facility) as b from t1 group by a order by b desc,a; +a max(id) b +10 10 VMT +9 9 SRV +8 8 RV +7 7 P +6 6 MT +5 5 FBX +4 4 F01 +3 3 ANC +2 2 A01 +1 1 /L +-1 -1 +0 0 +NULL NULL NULL +select id >= 0 and id <= 5 as grp,count(*) from t1 group by grp; +grp count(*) +NULL 1 +0 6 +1 6 +SELECT DISTINCT FACILITY FROM t1; +FACILITY +NULL + +/L +A01 +ANC +F01 +FBX +MT +P +RV +SRV +VMT +SELECT FACILITY FROM t2; +FACILITY +NULL + +/L +A01 +ANC +F01 +FBX +MT +P +RV +SRV +VMT +SELECT count(*) from t1,t2 where t1.facility=t2.facility; +count(*) +12 +select count(facility) from t1; +count(facility) +12 +select count(*) from t1; +count(*) +13 +select count(*) from t1 where facility IS NULL; +count(*) +1 +select count(*) from t1 where facility = NULL; +count(*) +0 +select count(*) from t1 where facility IS NOT NULL; +count(*) +12 +select count(*) from t1 where id IS NULL; +count(*) +1 +select count(*) from t1 where id IS NOT NULL; +count(*) +12 +drop table t1,t2; +CREATE TABLE t1 (UserId int(11) DEFAULT '0' NOT NULL); +INSERT INTO t1 VALUES (20); +INSERT INTO t1 VALUES (27); +SELECT UserId FROM t1 WHERE Userid=22; +UserId +SELECT UserId FROM t1 WHERE UserId=22 group by Userid; +UserId +SELECT DISTINCT UserId FROM t1 WHERE UserId=22 group by Userid; +UserId +SELECT DISTINCT UserId FROM t1 WHERE UserId=22; +UserId +drop table t1; +CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned); +INSERT INTO t1 VALUES (1,1),(2,1),(3,1),(4,1); +CREATE TABLE t2 (a int(10) unsigned not null, key (A)); +INSERT INTO t2 VALUES (1),(2); +CREATE TABLE t3 (a int(10) unsigned, key(A), b text); +INSERT INTO t3 VALUES (1,'1'),(2,'2'); +SELECT DISTINCT t3.b FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; +b +1 +INSERT INTO t2 values (1),(2),(3); +INSERT INTO t3 VALUES (1,'1'),(2,'2'),(1,'1'),(2,'2'); +explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 4 Using temporary +1 SIMPLE t3 ref a a 5 test.t1.b 2 Using where; Using index +1 SIMPLE t2 index a a 4 NULL 5 Using where; Using index; Distinct; Using join buffer +SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; +a +1 +create temporary table t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +explain select distinct t1.a from t1,t3 where t1.a=t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 4 Using index; Using temporary +1 SIMPLE t3 ref a a 5 test.t1.a 11 Using where; Using index; Distinct +select distinct t1.a from t1,t3 where t1.a=t3.a; +a +1 +2 +select distinct 1 from t1,t3 where t1.a=t3.a; +1 +1 +explain SELECT distinct t1.a from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index +explain SELECT distinct t1.a from t1 order by a desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index +explain SELECT t1.a from t1 group by a order by a desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index +explain SELECT distinct t1.a from t1 order by a desc limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 Using index +explain SELECT distinct a from t3 order by a desc limit 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 index NULL a 5 NULL 40 Using index +explain SELECT distinct a,b from t3 order by a+1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort +explain SELECT distinct a,b from t3 order by a limit 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort +explain SELECT a,b from t3 group by a,b order by a+1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort +drop table t1,t2,t3,t4; +CREATE TABLE t1 (name varchar(255)); +INSERT INTO t1 VALUES ('aa'),('ab'),('ac'),('ad'),('ae'); +SELECT DISTINCT * FROM t1 LIMIT 2; +name +aa +ab +SELECT DISTINCT name FROM t1 LIMIT 2; +name +aa +ab +SELECT DISTINCT 1 FROM t1 LIMIT 2; +1 +1 +drop table t1; +CREATE TABLE t1 ( +ID int(11) NOT NULL auto_increment, +NAME varchar(75) DEFAULT '' NOT NULL, +LINK_ID int(11) DEFAULT '0' NOT NULL, +PRIMARY KEY (ID), +KEY NAME (NAME), +KEY LINK_ID (LINK_ID) +); +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0),(2,'Jack',0),(3,'Bill',0); +CREATE TABLE t2 ( +ID int(11) NOT NULL auto_increment, +NAME varchar(150) DEFAULT '' NOT NULL, +PRIMARY KEY (ID), +KEY NAME (NAME) +); +SELECT DISTINCT +t2.id AS key_link_id, +t2.name AS link +FROM t1 +LEFT JOIN t2 ON t1.link_id=t2.id +GROUP BY t1.id +ORDER BY link; +key_link_id link +NULL NULL +drop table t1,t2; +create table t1 ( +id int not null, +name tinytext not null, +unique (id) +); +create table t2 ( +id int not null, +idx int not null, +unique (id, idx) +); +create table t3 ( +id int not null, +idx int not null, +unique (id, idx) +); +insert into t1 values (1,'yes'), (2,'no'); +insert into t2 values (1,1); +insert into t3 values (1,1); +EXPLAIN +SELECT DISTINCT +t1.id +from +t1 +straight_join +t2 +straight_join +t3 +straight_join +t1 as j_lj_t2 left join t2 as t2_lj +on j_lj_t2.id=t2_lj.id +straight_join +t1 as j_lj_t3 left join t3 as t3_lj +on j_lj_t3.id=t3_lj.id +WHERE +((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2)) +AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index id id 4 NULL 2 Using index; Using temporary +1 SIMPLE t2 index id id 8 NULL 1 Using index; Distinct; Using join buffer +1 SIMPLE t3 index id id 8 NULL 1 Using index; Distinct; Using join buffer +1 SIMPLE j_lj_t2 index id id 4 NULL 2 Using where; Using index; Distinct; Using join buffer +1 SIMPLE t2_lj ref id id 4 test.j_lj_t2.id 1 Using where; Using index; Distinct +1 SIMPLE j_lj_t3 index id id 4 NULL 2 Using where; Using index; Distinct; Using join buffer +1 SIMPLE t3_lj ref id id 4 test.j_lj_t3.id 1 Using where; Using index; Distinct +SELECT DISTINCT +t1.id +from +t1 +straight_join +t2 +straight_join +t3 +straight_join +t1 as j_lj_t2 left join t2 as t2_lj +on j_lj_t2.id=t2_lj.id +straight_join +t1 as j_lj_t3 left join t3 as t3_lj +on j_lj_t3.id=t3_lj.id +WHERE +((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2)) +AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); +id +2 +drop table t1,t2,t3; +create table t1 (a int not null, b int not null, t time); +insert into t1 values (1,1,"00:06:15"),(1,2,"00:06:15"),(1,2,"00:30:15"),(1,3,"00:06:15"),(1,3,"00:30:15"); +select a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b; +a sec_to_time(sum(time_to_sec(t))) +1 00:06:15 +1 00:36:30 +1 00:36:30 +select distinct a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b; +a sec_to_time(sum(time_to_sec(t))) +1 00:06:15 +1 00:36:30 +create table t2 (a int not null primary key, b int); +insert into t2 values (1,1),(2,2),(3,3); +select t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b; +a sec_to_time(sum(time_to_sec(t))) +1 00:06:15 +1 00:36:30 +1 00:36:30 +select distinct t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b; +a sec_to_time(sum(time_to_sec(t))) +1 00:06:15 +1 00:36:30 +drop table t1,t2; +create table t1 (a int not null,b char(5), c text); +insert into t1 (a) values (1),(2),(3),(4),(1),(2),(3),(4); +select distinct a from t1 group by b,a having a > 2 order by a desc; +a +4 +3 +select distinct a,c from t1 group by b,c,a having a > 2 order by a desc; +a c +4 NULL +3 NULL +drop table t1; +create table t1 (a char(1), key(a)) engine=myisam; +insert into t1 values('1'),('1'); +select * from t1 where a >= '1'; +a +1 +1 +select distinct a from t1 order by a desc; +a +1 +select distinct a from t1 where a >= '1' order by a desc; +a +1 +drop table t1; +CREATE TABLE t1 (email varchar(50), infoID BIGINT, dateentered DATETIME); +CREATE TABLE t2 (infoID BIGINT, shipcode varchar(10)); +INSERT INTO t1 (email, infoID, dateentered) VALUES +('test1@testdomain.com', 1, '2002-07-30 22:56:38'), +('test1@testdomain.com', 1, '2002-07-27 22:58:16'), +('test2@testdomain.com', 1, '2002-06-19 15:22:19'), +('test2@testdomain.com', 2, '2002-06-18 14:23:47'), +('test3@testdomain.com', 1, '2002-05-19 22:17:32'); +INSERT INTO t2(infoID, shipcode) VALUES +(1, 'Z001'), +(2, 'R002'); +SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID; +email shipcode +test1@testdomain.com Z001 +test2@testdomain.com Z001 +test2@testdomain.com R002 +test3@testdomain.com Z001 +SELECT DISTINCTROW email FROM t1 ORDER BY dateentered DESC; +email +test1@testdomain.com +test2@testdomain.com +test3@testdomain.com +SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID ORDER BY dateentered DESC; +email shipcode +test1@testdomain.com Z001 +test2@testdomain.com Z001 +test2@testdomain.com R002 +test3@testdomain.com Z001 +drop table t1,t2; +CREATE TABLE t1 (privatemessageid int(10) unsigned NOT NULL auto_increment, folderid smallint(6) NOT NULL default '0', userid int(10) unsigned NOT NULL default '0', touserid int(10) unsigned NOT NULL default '0', fromuserid int(10) unsigned NOT NULL default '0', title varchar(250) NOT NULL default '', message mediumtext NOT NULL, dateline int(10) unsigned NOT NULL default '0', showsignature smallint(6) NOT NULL default '0', iconid smallint(5) unsigned NOT NULL default '0', messageread smallint(6) NOT NULL default '0', readtime int(10) unsigned NOT NULL default '0', receipt smallint(6) unsigned NOT NULL default '0', deleteprompt smallint(6) unsigned NOT NULL default '0', multiplerecipients smallint(6) unsigned NOT NULL default '0', PRIMARY KEY (privatemessageid), KEY userid (userid)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (128,0,33,33,8,':D','',996121863,1,0,2,996122850,2,0,0); +CREATE TABLE t2 (userid int(10) unsigned NOT NULL auto_increment, usergroupid smallint(5) unsigned NOT NULL default '0', username varchar(50) NOT NULL default '', password varchar(50) NOT NULL default '', email varchar(50) NOT NULL default '', styleid smallint(5) unsigned NOT NULL default '0', parentemail varchar(50) NOT NULL default '', coppauser smallint(6) NOT NULL default '0', homepage varchar(100) NOT NULL default '', icq varchar(20) NOT NULL default '', aim varchar(20) NOT NULL default '', yahoo varchar(20) NOT NULL default '', signature mediumtext NOT NULL, adminemail smallint(6) NOT NULL default '0', showemail smallint(6) NOT NULL default '0', invisible smallint(6) NOT NULL default '0', usertitle varchar(250) NOT NULL default '', customtitle smallint(6) NOT NULL default '0', joindate int(10) unsigned NOT NULL default '0', cookieuser smallint(6) NOT NULL default '0', daysprune smallint(6) NOT NULL default '0', lastvisit int(10) unsigned NOT NULL default '0', lastactivity int(10) unsigned NOT NULL default '0', lastpost int(10) unsigned NOT NULL default '0', posts smallint(5) unsigned NOT NULL default '0', timezoneoffset varchar(4) NOT NULL default '', emailnotification smallint(6) NOT NULL default '0', buddylist mediumtext NOT NULL, ignorelist mediumtext NOT NULL, pmfolders mediumtext NOT NULL, receivepm smallint(6) NOT NULL default '0', emailonpm smallint(6) NOT NULL default '0', pmpopup smallint(6) NOT NULL default '0', avatarid smallint(6) NOT NULL default '0', avatarrevision int(6) unsigned NOT NULL default '0', options smallint(6) NOT NULL default '15', birthday date NOT NULL default '0000-00-00', maxposts smallint(6) NOT NULL default '-1', startofweek smallint(6) NOT NULL default '1', ipaddress varchar(20) NOT NULL default '', referrerid int(10) unsigned NOT NULL default '0', nosessionhash smallint(6) NOT NULL default '0', autorefresh smallint(6) NOT NULL default '-1', messagepopup tinyint(2) NOT NULL default '0', inforum smallint(5) unsigned NOT NULL default '0', ratenum smallint(5) unsigned NOT NULL default '0', ratetotal smallint(5) unsigned NOT NULL default '0', allowrate smallint(5) unsigned NOT NULL default '1', PRIMARY KEY (userid), KEY usergroupid (usergroupid), KEY username (username), KEY inforum (inforum)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (33,6,'Kevin','0','kevin@stileproject.com',1,'',0,'http://www.stileproject.com','','','','',1,1,0,'Administrator',0,996120694,1,-1,1030996168,1031027028,1030599436,36,'-6',0,'','','',1,0,1,0,0,15,'0000-00-00',-1,1,'64.0.0.0',0,1,-1,0,0,4,19,1); +SELECT DISTINCT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t2.userid = t1.touserid); +privatemessageid folderid userid touserid fromuserid title message dateline showsignature iconid messageread readtime receipt deleteprompt multiplerecipients userid usergroupid username password email styleid parentemail coppauser homepage icq aim yahoo signature adminemail showemail invisible usertitle customtitle joindate cookieuser daysprune lastvisit lastactivity lastpost posts timezoneoffset emailnotification buddylist ignorelist pmfolders receivepm emailonpm pmpopup avatarid avatarrevision options birthday maxposts startofweek ipaddress referrerid nosessionhash autorefresh messagepopup inforum ratenum ratetotal allowrate +128 0 33 33 8 :D 996121863 1 0 2 996122850 2 0 0 33 6 Kevin 0 kevin@stileproject.com 1 0 http://www.stileproject.com 1 1 0 Administrator 0 996120694 1 -1 1030996168 1031027028 1030599436 36 -6 0 1 0 1 0 0 15 0000-00-00 -1 1 64.0.0.0 0 1 -1 0 0 4 19 1 +DROP TABLE t1,t2; +CREATE TABLE t1 (a int primary key, b int, c int); +INSERT t1 VALUES (1,2,3); +CREATE TABLE t2 (a int primary key, b int, c int); +INSERT t2 VALUES (3,4,5); +SELECT DISTINCT t1.a, t2.b FROM t1, t2 WHERE t1.a=1 ORDER BY t2.c; +a b +1 4 +DROP TABLE t1,t2; +CREATE table t1 ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL default '', PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=3 ; +INSERT INTO t1 VALUES (1, 'aaaaa'); +INSERT INTO t1 VALUES (3, 'aaaaa'); +INSERT INTO t1 VALUES (2, 'eeeeeee'); +select distinct left(name,1) as name from t1; +name +a +e +drop table t1; +CREATE TABLE t1 ( +ID int(11) NOT NULL auto_increment, +NAME varchar(75) DEFAULT '' NOT NULL, +LINK_ID int(11) DEFAULT '0' NOT NULL, +PRIMARY KEY (ID), +KEY NAME (NAME), +KEY LINK_ID (LINK_ID) +); +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0); +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (2,'Jack',0); +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (3,'Bill',0); +CREATE TABLE t2 ( +ID int(11) NOT NULL auto_increment, +NAME varchar(150) DEFAULT '' NOT NULL, +PRIMARY KEY (ID), +KEY NAME (NAME) +); +SELECT DISTINCT +t2.id AS key_link_id, +t2.name AS link +FROM t1 +LEFT JOIN t2 ON t1.link_id=t2.id +GROUP BY t1.id +ORDER BY link; +key_link_id link +NULL NULL +drop table t1,t2; +CREATE TABLE t1 ( +html varchar(5) default NULL, +rin int(11) default '0', +rout int(11) default '0' +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('1',1,0); +SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; +html prod +1 0.0000 +drop table t1; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5); +SELECT DISTINCT a, 1 FROM t1; +a 1 +1 1 +2 1 +3 1 +4 1 +5 1 +SELECT DISTINCT 1, a FROM t1; +1 a +1 1 +1 2 +1 3 +1 4 +1 5 +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES (1,1),(2,2),(2,3),(2,4),(3,5); +SELECT DISTINCT a, b, 2 FROM t2; +a b 2 +1 1 2 +2 2 2 +2 3 2 +2 4 2 +3 5 2 +SELECT DISTINCT 2, a, b FROM t2; +2 a b +2 1 1 +2 2 2 +2 2 3 +2 2 4 +2 3 5 +SELECT DISTINCT a, 2, b FROM t2; +a 2 b +1 2 1 +2 2 2 +2 2 3 +2 2 4 +3 2 5 +DROP TABLE t1,t2; +CREATE TABLE t1(a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,1), (3,1); +EXPLAIN SELECT DISTINCT a FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 3 Using index +EXPLAIN SELECT DISTINCT a,b FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +EXPLAIN SELECT DISTINCT t1_1.a, t1_1.b FROM t1 t1_1, t1 t1_2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1_1 ALL NULL NULL NULL NULL 3 Using temporary +1 SIMPLE t1_2 index NULL PRIMARY 4 NULL 3 Using index; Distinct; Using join buffer +EXPLAIN SELECT DISTINCT t1_1.a, t1_1.b FROM t1 t1_1, t1 t1_2 +WHERE t1_1.a = t1_2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1_1 ALL PRIMARY NULL NULL NULL 3 Using temporary +1 SIMPLE t1_2 eq_ref PRIMARY PRIMARY 4 test.t1_1.a 1 Using index; Distinct +EXPLAIN SELECT a FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 3 Using index +EXPLAIN SELECT a,b FROM t1 GROUP BY a,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +EXPLAIN SELECT DISTINCT a,b FROM t1 GROUP BY a,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +CREATE TABLE t2(a INT, b INT, c INT, d INT, PRIMARY KEY (a,b)); +INSERT INTO t2 VALUES (1,1,1,50), (1,2,3,40), (2,1,3,4); +EXPLAIN SELECT DISTINCT a FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL PRIMARY 8 NULL 3 Using index +EXPLAIN SELECT DISTINCT a,a FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL PRIMARY 8 NULL 3 Using index +EXPLAIN SELECT DISTINCT b,a FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL PRIMARY 8 NULL 3 Using index +EXPLAIN SELECT DISTINCT a,c FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using temporary +EXPLAIN SELECT DISTINCT c,a,b FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 +EXPLAIN SELECT DISTINCT a,b,d FROM t2 GROUP BY c,b,d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using temporary; Using filesort +CREATE UNIQUE INDEX c_b_unq ON t2 (c,b); +EXPLAIN SELECT DISTINCT a,b,d FROM t2 GROUP BY c,b,d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using temporary; Using filesort +DROP TABLE t1,t2; +create table t1 (id int, dsc varchar(50)); +insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three"); +select distinct id, IFNULL(dsc, '-') from t1; +id IFNULL(dsc, '-') +1 line number one +2 line number two +3 line number three +drop table t1; +CREATE TABLE t1 (a int primary key, b int); +INSERT INTO t1 (a,b) values (1,1), (2,3), (3,2); +explain SELECT DISTINCT a, b FROM t1 ORDER BY b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +SELECT DISTINCT a, b FROM t1 ORDER BY b; +a b +1 1 +3 2 +2 3 +DROP TABLE t1; +CREATE TABLE t1 ( +ID int(11) NOT NULL auto_increment, +x varchar(20) default NULL, +y decimal(10,0) default NULL, +PRIMARY KEY (ID), +KEY (y) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO t1 VALUES +(1,'ba','-1'), +(2,'ba','1150'), +(306,'ba','-1'), +(307,'ba','1150'), +(611,'ba','-1'), +(612,'ba','1150'); +select count(distinct x,y) from t1; +count(distinct x,y) +2 +select count(distinct concat(x,y)) from t1; +count(distinct concat(x,y)) +2 +drop table t1; +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a,b)); +INSERT INTO t1 VALUES (1, 101); +INSERT INTO t1 SELECT a + 1, a + 101 FROM t1; +INSERT INTO t1 SELECT a + 2, a + 102 FROM t1; +INSERT INTO t1 SELECT a + 4, a + 104 FROM t1; +INSERT INTO t1 SELECT a + 8, a + 108 FROM t1; +EXPLAIN SELECT DISTINCT a,a FROM t1 WHERE b < 12 ORDER BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 8 NULL 16 Using where; Using index +SELECT DISTINCT a,a FROM t1 WHERE b < 12 ORDER BY a; +a a +DROP TABLE t1; +CREATE TABLE t1 (a CHAR(1)); +INSERT INTO t1 VALUES('A'), (0); +SELECT a FROM t1 WHERE a=0; +a +A +0 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'A' +SELECT DISTINCT a FROM t1 WHERE a=0; +a +A +0 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'A' +DROP TABLE t1; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('1972-07-29'), ('1972-02-06'); +EXPLAIN SELECT (SELECT DISTINCT a FROM t1 WHERE a = '2002-08-03'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where +EXPLAIN SELECT (SELECT DISTINCT ADDDATE(a,1) FROM t1 +WHERE ADDDATE(a,1) = '2002-08-03'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where +CREATE TABLE t2 (a CHAR(5) CHARACTER SET latin1 COLLATE latin1_general_ci); +INSERT INTO t2 VALUES (0xf6); +INSERT INTO t2 VALUES ('oe'); +SELECT COUNT(*) FROM (SELECT DISTINCT a FROM t2) dt; +COUNT(*) +2 +SELECT COUNT(*) FROM +(SELECT DISTINCT a FROM t2 WHERE a='oe' COLLATE latin1_german2_ci) dt; +COUNT(*) +2 +DROP TABLE t1, t2; diff --git a/mysql-test/suite/pbxt/r/drop.result b/mysql-test/suite/pbxt/r/drop.result new file mode 100644 index 00000000000..6e90d9a34e4 --- /dev/null +++ b/mysql-test/suite/pbxt/r/drop.result @@ -0,0 +1,91 @@ +drop table if exists t1; +drop database if exists mysqltest; +drop database if exists client_test_db; +drop table t1; +ERROR 42S02: Unknown table 't1' +create table t1(n int); +insert into t1 values(1); +create temporary table t1( n int); +insert into t1 values(2); +create table t1(n int); +ERROR 42S01: Table 't1' already exists +drop table t1; +select * from t1; +n +1 +create database mysqltest; +drop database if exists mysqltest; +create database mysqltest; +create table mysqltest.mysqltest (n int); +insert into mysqltest.mysqltest values (4); +select * from mysqltest.mysqltest; +n +4 +drop database if exists mysqltest; +affected rows: 1 +create database mysqltest; +use mysqltest; +drop table table1, table2, table3, table4, table5, table6, +table7, table8, table9, table10, table11, table12, table13, +table14, table15, table16, table17, table18, table19, table20, +table21, table22, table23, table24, table25, table26, table27, +table28; +ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table' +drop table table1, table2, table3, table4, table5, table6, +table7, table8, table9, table10, table11, table12, table13, +table14, table15, table16, table17, table18, table19, table20, +table21, table22, table23, table24, table25, table26, table27, +table28, table29, table30; +ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table' +use test; +drop database mysqltest; +flush tables with read lock; +create database mysqltest; +Got one of the listed errors +unlock tables; +create database mysqltest; +show databases; +Database +information_schema +mtr +mysql +mysqltest +pbxt +test +flush tables with read lock; +drop database mysqltest; +Got one of the listed errors +unlock tables; +drop database mysqltest; +show databases; +Database +information_schema +mtr +mysql +pbxt +test +drop database mysqltest; +ERROR HY000: Can't drop database 'mysqltest'; database doesn't exist +drop table t1; +flush tables with read lock; +create table t1(n int); +ERROR HY000: Can't execute the query because you have a conflicting read lock +unlock tables; +create table t1(n int); +show tables; +Tables_in_test +t1 +drop table t1; +drop database if exists mysqltest; +drop table if exists t1; +create table t1 (i int); +lock tables t1 read; +create database mysqltest; +drop table t1; +show open tables; +drop database mysqltest; +select 1; +1 +1 +unlock tables; +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/empty_table.result b/mysql-test/suite/pbxt/r/empty_table.result new file mode 100644 index 00000000000..cea787f4abd --- /dev/null +++ b/mysql-test/suite/pbxt/r/empty_table.result @@ -0,0 +1,10 @@ +drop table if exists t1; +create table t1 (nr int(5) not null auto_increment,b blob,str char(10), primary key (nr)); +select count(*) from t1; +count(*) +0 +select * from t1; +nr b str +select * from t1 limit 0; +nr b str +drop table t1; diff --git a/mysql-test/suite/pbxt/r/endspace.result b/mysql-test/suite/pbxt/r/endspace.result new file mode 100644 index 00000000000..c9a2db8bbfe --- /dev/null +++ b/mysql-test/suite/pbxt/r/endspace.result @@ -0,0 +1,217 @@ +drop table if exists t1; +select 'a' = 'a', 'a' = 'a ', 'a ' = 'a'; +'a' = 'a' 'a' = 'a ' 'a ' = 'a' +1 1 1 +select 'a\0' = 'a', 'a\0' < 'a', 'a\0' > 'a'; +'a\0' = 'a' 'a\0' < 'a' 'a\0' > 'a' +0 1 0 +select 'a' = 'a\0', 'a' < 'a\0', 'a' > 'a\0'; +'a' = 'a\0' 'a' < 'a\0' 'a' > 'a\0' +0 0 1 +select 'a\0' = 'a ', 'a\0' < 'a ', 'a\0' > 'a '; +'a\0' = 'a ' 'a\0' < 'a ' 'a\0' > 'a ' +0 1 0 +select 'a ' = 'a\0', 'a ' < 'a\0', 'a ' > 'a\0'; +'a ' = 'a\0' 'a ' < 'a\0' 'a ' > 'a\0' +0 0 1 +select 'a a' > 'a', 'a \0' < 'a'; +'a a' > 'a' 'a \0' < 'a' +1 1 +select binary 'a a' > 'a', binary 'a \0' > 'a', binary 'a\0' > 'a'; +binary 'a a' > 'a' binary 'a \0' > 'a' binary 'a\0' > 'a' +1 1 1 +create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)); +insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +text1 +teststring +teststring +select * from t1 where text1='teststring' or text1 like 'teststring_%'; +text1 +teststring +teststring +select * from t1 where text1='teststring' or text1 > 'teststring\t'; +text1 +teststring +select * from t1 order by text1; +text1 +nothing +teststring +teststring +explain select * from t1 order by text1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL key1 34 NULL 3 Using index +alter table t1 modify text1 char(32) binary not null; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +text1 +teststring +teststring +select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; +concat('|', text1, '|') +|teststring | +|teststring| +select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t'; +concat('|', text1, '|') +|teststring| +select text1, length(text1) from t1 order by text1; +text1 length(text1) +nothing 7 +teststring 11 +teststring 10 +select text1, length(text1) from t1 order by binary text1; +text1 length(text1) +nothing 7 +teststring 10 +teststring 11 +alter table t1 modify text1 blob not null, drop key key1, add key key1 (text1(20)); +insert into t1 values ('teststring '); +select concat('|', text1, '|') from t1 order by text1; +concat('|', text1, '|') +|nothing| +|teststring| +|teststring | +|teststring | +select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t'; +concat('|', text1, '|') +|teststring| +|teststring | +select concat('|', text1, '|') from t1 where text1='teststring'; +concat('|', text1, '|') +|teststring| +select concat('|', text1, '|') from t1 where text1='teststring '; +concat('|', text1, '|') +|teststring | +alter table t1 modify text1 text not null, pack_keys=1; +select concat('|', text1, '|') from t1 where text1='teststring'; +concat('|', text1, '|') +|teststring| +|teststring | +select concat('|', text1, '|') from t1 where text1='teststring '; +concat('|', text1, '|') +|teststring| +|teststring | +explain select concat('|', text1, '|') from t1 where text1='teststring '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref key1 key1 22 const 1 Using where +select concat('|', text1, '|') from t1 where text1 like 'teststring_%'; +concat('|', text1, '|') +|teststring | +|teststring | +select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; +concat('|', text1, '|') +|teststring | +|teststring| +|teststring | +select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t'; +concat('|', text1, '|') +|teststring| +|teststring | +select concat('|', text1, '|') from t1 order by text1; +concat('|', text1, '|') +|nothing| +|teststring | +|teststring| +|teststring | +drop table t1; +create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)) pack_keys=0; +insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); +select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; +concat('|', text1, '|') +|teststring | +|teststring| +select concat('|', text1, '|') from t1 where text1='teststring' or text1 >= 'teststring\t'; +concat('|', text1, '|') +|teststring | +|teststring| +drop table t1; +create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap; +insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); +select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +text1 +teststring +teststring +select * from t1 where text1='teststring' or text1 like 'teststring_%'; +text1 +teststring +teststring +select * from t1 where text1='teststring' or text1 >= 'teststring\t'; +text1 +teststring +teststring +select * from t1 order by text1; +text1 +nothing +teststring +teststring +explain select * from t1 order by text1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +alter table t1 modify text1 char(32) binary not null; +select * from t1 order by text1; +text1 +nothing +teststring +teststring +drop table t1; +create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)) engine=innodb; +insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select * from t1 where text1='teststring' or text1 like 'teststring_%'; +text1 +teststring +teststring +select * from t1 where text1='teststring' or text1 > 'teststring\t'; +text1 +teststring +select * from t1 order by text1; +text1 +nothing +teststring +teststring +explain select * from t1 order by text1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL key1 34 NULL 3 Using index +alter table t1 modify text1 char(32) binary not null; +select * from t1 order by text1; +text1 +nothing +teststring +teststring +alter table t1 modify text1 blob not null, drop key key1, add key key1 (text1(20)); +insert into t1 values ('teststring '); +select concat('|', text1, '|') from t1 order by text1; +concat('|', text1, '|') +|nothing| +|teststring| +|teststring | +|teststring | +alter table t1 modify text1 text not null, pack_keys=1; +select * from t1 where text1 like 'teststring_%'; +text1 +teststring +teststring +select text1, length(text1) from t1 where text1='teststring' or text1 like 'teststring_%'; +text1 length(text1) +teststring 11 +teststring 10 +teststring 11 +select text1, length(text1) from t1 where text1='teststring' or text1 >= 'teststring\t'; +text1 length(text1) +teststring 11 +teststring 10 +teststring 11 +select concat('|', text1, '|') from t1 order by text1; +concat('|', text1, '|') +|nothing| +|teststring | +|teststring| +|teststring | +drop table t1; diff --git a/mysql-test/suite/pbxt/r/errors.result b/mysql-test/suite/pbxt/r/errors.result new file mode 100644 index 00000000000..0c84f24a2e4 --- /dev/null +++ b/mysql-test/suite/pbxt/r/errors.result @@ -0,0 +1,30 @@ +drop table if exists t1; +insert into t1 values(1); +ERROR 42S02: Table 'test.t1' doesn't exist +delete from t1; +ERROR 42S02: Table 'test.t1' doesn't exist +update t1 set a=1; +ERROR 42S02: Table 'test.t1' doesn't exist +create table t1 (a int); +select count(test.t1.b) from t1; +ERROR 42S22: Unknown column 'test.t1.b' in 'field list' +select count(not_existing_database.t1) from t1; +ERROR 42S22: Unknown column 'not_existing_database.t1' in 'field list' +select count(not_existing_database.t1.a) from t1; +ERROR 42S22: Unknown column 'not_existing_database.t1.a' in 'field list' +select count(not_existing_database.t1.a) from not_existing_database.t1; +Got one of the listed errors +select 1 from t1 order by 2; +ERROR 42S22: Unknown column '2' in 'order clause' +select 1 from t1 group by 2; +ERROR 42S22: Unknown column '2' in 'group statement' +select 1 from t1 order by t1.b; +ERROR 42S22: Unknown column 't1.b' in 'order clause' +select count(*),b from t1; +ERROR 42S22: Unknown column 'b' in 'field list' +drop table t1; +create table t1 (a int(256)); +ERROR 42000: Display width out of range for column 'a' (max = 255) +set sql_mode='traditional'; +create table t1 (a varchar(66000)); +ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead diff --git a/mysql-test/suite/pbxt/r/explain.result b/mysql-test/suite/pbxt/r/explain.result new file mode 100644 index 00000000000..a9907aa33fe --- /dev/null +++ b/mysql-test/suite/pbxt/r/explain.result @@ -0,0 +1,59 @@ +drop table if exists t1; +create table t1 (id int not null, str char(10), unique(str)); +explain select * from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 0 +insert into t1 values (1, null),(2, null),(3, "foo"),(4, "bar"); +select * from t1 where str is null; +id str +1 NULL +2 NULL +select * from t1 where str="foo"; +id str +3 foo +explain select * from t1 where str is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref str str 11 const 1 Using where +explain select * from t1 where str="foo"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const str str 11 const 1 +explain select * from t1 ignore key (str) where str="foo"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +explain select * from t1 use key (str,str) where str="foo"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const str str 11 const 1 +explain select * from t1 use key (str,str,foo) where str="foo"; +ERROR 42000: Key 'foo' doesn't exist in table 't1' +explain select * from t1 ignore key (str,str,foo) where str="foo"; +ERROR 42000: Key 'foo' doesn't exist in table 't1' +drop table t1; +explain select 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used +create table t1 (a int not null); +explain select count(*) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 0 +insert into t1 values(1); +explain select count(*) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 +insert into t1 values(1); +explain select count(*) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +drop table t1; +set names koi8r; +create table ÔÁ (ËÏÌ0 int, ËÏÌ1 int, key ÉÎÄ0 (ËÏÌ0), key ÉÎÄ01 (ËÏÌ0,ËÏÌ1)); +insert into ÔÁ (ËÏÌ0) values (1); +insert into ÔÁ (ËÏÌ0) values (2); +explain select ËÏÌ0 from ÔÁ where ËÏÌ0=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE ÔÁ ref ÉÎÄ0,ÉÎÄ01 ÉÎÄ0 5 const 1 Using where; Using index +drop table ÔÁÂ; +set names latin1; +select 3 into @v1; +explain select 3 into @v1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/suite/pbxt/r/flush.result b/mysql-test/suite/pbxt/r/flush.result new file mode 100644 index 00000000000..7eb7fd16edb --- /dev/null +++ b/mysql-test/suite/pbxt/r/flush.result @@ -0,0 +1,57 @@ +drop table if exists t1,t2; +drop database if exists mysqltest; +create temporary table t1(n int not null primary key); +create table t2(n int); +insert into t2 values(3); +select * from t1; +n +3 +flush tables with read lock; +drop table t2; +ERROR HY000: Can't execute the query because you have a conflicting read lock +drop table t2; +unlock tables; +create database mysqltest; +create table mysqltest.t1(n int); +insert into mysqltest.t1 values (23); +flush tables with read lock; +drop database mysqltest; +select * from mysqltest.t1; +n +23 +unlock tables; +create table t1 (n int); +flush tables with read lock; +insert into t1 values (345); +select * from t1; +n +345 +drop table t1; +create table t1 (c1 int); +lock table t1 write; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +lock table t1 read; +flush tables with read lock; +lock table t1 write; +ERROR HY000: Can't execute the query because you have a conflicting read lock +lock table t1 read; +lock table t1 write; +ERROR HY000: Can't execute the query because you have a conflicting read lock +unlock tables; +create table t2 (c1 int); +create table t3 (c1 int); +lock table t1 read, t2 read, t3 write; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +lock table t1 read, t2 read, t3 read; +flush tables with read lock; +unlock tables; +drop table t1, t2, t3; +create table t1 (c1 int); +create table t2 (c1 int); +lock table t1 write; +flush tables with read lock; +insert into t2 values(1); +unlock tables; +drop table t1, t2; diff --git a/mysql-test/suite/pbxt/r/flush_read_lock_kill.result b/mysql-test/suite/pbxt/r/flush_read_lock_kill.result new file mode 100644 index 00000000000..ba4b66f4b1f --- /dev/null +++ b/mysql-test/suite/pbxt/r/flush_read_lock_kill.result @@ -0,0 +1,12 @@ +drop table if exists t1; +create table t1 (kill_id int); +insert into t1 values(connection_id()); +select kill_id-kill_id from t1; +kill_id-kill_id +0 +flush tables with read lock; +select ((@id := kill_id) - kill_id) from t1; +((@id := kill_id) - kill_id) +0 +kill connection @id; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/flush_table.result b/mysql-test/suite/pbxt/r/flush_table.result new file mode 100644 index 00000000000..8821bade6b4 --- /dev/null +++ b/mysql-test/suite/pbxt/r/flush_table.result @@ -0,0 +1,137 @@ +drop table if exists t1,t2; +create table t1 (a int not null auto_increment primary key); +insert into t1 values(0); +lock table t1 read; +flush table t1; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +unlock tables; +lock table t1 read; +lock table t1 read; +flush table t1; +select * from t1; +a +1 +unlock tables; +select * from t1; +a +1 +unlock tables; +lock table t1 write; +lock table t1 read; +flush table t1; +select * from t1; +a +1 +unlock tables; +unlock tables; +lock table t1 read; +lock table t1 write; +flush table t1; +select * from t1; +a +1 +unlock tables; +unlock tables; +select * from t1; +a +1 +drop table t1; +create table t1(table_id char(20) primary key); +create table t2(table_id char(20) primary key); +insert into t1 values ('test.t1'); +insert into t1 values (''); +insert into t2 values ('test.t2'); +insert into t2 values (''); +handler t1 open as a1; +handler t1 open as a2; +handler t2 open; +handler a1 read first limit 9; +table_id +test.t1 + +handler a2 read first limit 9; +table_id +test.t1 + +handler t2 read first limit 9; +table_id +test.t2 + +flush tables; +handler a1 read first limit 9; +table_id +test.t1 + +handler a2 read first limit 9; +table_id +test.t1 + +handler t2 read first limit 9; +table_id +test.t2 + +handler t1 open as a1; +ERROR 42000: Not unique table/alias: 'a1' +handler t1 open as a2; +ERROR 42000: Not unique table/alias: 'a2' +handler t2 open; +ERROR 42000: Not unique table/alias: 't2' +handler a1 read first limit 9; +table_id +test.t1 + +handler a2 read first limit 9; +table_id +test.t1 + +handler t2 read first limit 9; +table_id +test.t2 + +flush table t1; +handler a1 read first limit 9; +table_id +test.t1 + +handler a2 read first limit 9; +table_id +test.t1 + +handler t2 read first limit 9; +table_id +test.t2 + +flush table t2; +handler t2 close; +drop table t1; +drop table t2; +create table t1(table_id char(20) primary key); +insert into t1 values ('Record-01'); +insert into t1 values ('Record-02'); +insert into t1 values ('Record-03'); +insert into t1 values ('Record-04'); +insert into t1 values ('Record-05'); +handler t1 open; +handler t1 read first limit 1; +table_id +Record-01 +handler t1 read next limit 1; +table_id +Record-02 +handler t1 read next limit 1; +table_id +Record-03 +flush table t1; +handler t1 read next limit 1; +table_id +Record-01 +handler t1 read next limit 1; +table_id +Record-02 +handler t1 close; +drop table t1; +FLUSH TABLES WITH READ LOCK ; +FLUSH TABLES WITH READ LOCK ; +UNLOCK TABLES; diff --git a/mysql-test/suite/pbxt/r/foreign_key.result b/mysql-test/suite/pbxt/r/foreign_key.result new file mode 100644 index 00000000000..a34f05a0c14 --- /dev/null +++ b/mysql-test/suite/pbxt/r/foreign_key.result @@ -0,0 +1,18 @@ +drop table if exists t1; +set foreign_key_checks = 0; +create table t1 ( +a int not null references t2, +b int not null references t2 (c), +c int, +primary key (a,b), +foreign key (a) references t3 match full, +foreign key (a) references t3 match partial, +foreign key (a,b) references t3 (c,d) on delete no action +on update no action, +foreign key (a,b) references t3 (c,d) on update cascade, +foreign key (a,b) references t3 (c,d) on delete set default, +foreign key (c) references t3 (e) on update set null); +create index a on t1 (a); +create unique index b on t1 (a,b); +drop table t1; +set foreign_key_checks = 1; diff --git a/mysql-test/suite/pbxt/r/func_concat.result b/mysql-test/suite/pbxt/r/func_concat.result new file mode 100644 index 00000000000..66808afd4e9 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_concat.result @@ -0,0 +1,84 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( number INT NOT NULL, alpha CHAR(6) NOT NULL ); +INSERT INTO t1 VALUES (1413006,'idlfmv'), +(1413065,'smpsfz'),(1413127,'sljrhx'),(1413304,'qerfnd'); +SELECT number, alpha, CONCAT_WS('<---->',number,alpha) AS new +FROM t1 GROUP BY number; +number alpha new +1413006 idlfmv 1413006<---->idlfmv +1413065 smpsfz 1413065<---->smpsfz +1413127 sljrhx 1413127<---->sljrhx +1413304 qerfnd 1413304<---->qerfnd +SELECT CONCAT_WS('<---->',number,alpha) AS new +FROM t1 GROUP BY new LIMIT 1; +new +1413006<---->idlfmv +SELECT number, alpha, CONCAT_WS('<->',number,alpha) AS new +FROM t1 GROUP BY new LIMIT 1; +number alpha new +1413006 idlfmv 1413006<->idlfmv +SELECT number, alpha, CONCAT_WS('-',number,alpha,alpha,alpha,alpha,alpha,alpha,alpha) AS new +FROM t1 GROUP BY new LIMIT 1; +number alpha new +1413006 idlfmv 1413006-idlfmv-idlfmv-idlfmv-idlfmv-idlfmv-idlfmv-idlfmv +SELECT number, alpha, CONCAT_WS('<------------------>',number,alpha) AS new +FROM t1 GROUP BY new LIMIT 1; +number alpha new +1413006 idlfmv 1413006<------------------>idlfmv +drop table t1; +create table t1 (a char(4), b double, c date, d tinyint(4)); +insert into t1 values ('AAAA', 105, '2003-03-01', 1); +select * from t1 where concat(A,C,B,D) = 'AAAA2003-03-011051'; +a b c d +AAAA 105 2003-03-01 1 +drop table t1; +select 'a' union select concat('a', -4); +a +a +a-4 +select 'a' union select concat('a', -4.5); +a +a +a-4.5 +select 'a' union select concat('a', -(4 + 1)); +a +a +a-5 +select 'a' union select concat('a', 4 - 5); +a +a +a-1 +select 'a' union select concat('a', -'3'); +a +a +a-3 +select 'a' union select concat('a', -concat('3',4)); +a +a +a-34 +select 'a' union select concat('a', -0); +a +a +a0 +select 'a' union select concat('a', -0.0); +a +a +a0.0 +select 'a' union select concat('a', -0.0000); +a +a +a0.0000 +select concat((select x from (select 'a' as x) as t1 ), +(select y from (select 'b' as y) as t2 )) from (select 1 union select 2 ) +as t3; +concat((select x from (select 'a' as x) as t1 ), +(select y from (select 'b' as y) as t2 )) +ab +ab +create table t1(f1 varchar(6)) charset=utf8; +insert into t1 values ("123456"); +select concat(f1, 2) a from t1 union select 'x' a from t1; +a +1234562 +x +drop table t1; diff --git a/mysql-test/suite/pbxt/r/func_crypt.result b/mysql-test/suite/pbxt/r/func_crypt.result new file mode 100644 index 00000000000..25b921681c5 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_crypt.result @@ -0,0 +1,97 @@ +drop table if exists t1; +select length(encrypt('foo', 'ff')) <> 0; +length(encrypt('foo', 'ff')) <> 0 +1 +create table t1 (name varchar(50), pw varchar(64)); +insert into t1 values ('tom', password('my_pass')); +set @pass='my_pass'; +select name from t1 where name='tom' and pw=password(@pass); +name +tom +select name from t1 where name='tom' and pw=password(@undefined); +name +drop table t1; +select password('abc'); +password('abc') +*0D3CED9BEC10A777AEC23CCC353A8C08A633045E +select password(''); +password('') + +select old_password('abc'); +old_password('abc') +7cd2b5942be28759 +select old_password(''); +old_password('') + +select password('gabbagabbahey'); +password('gabbagabbahey') +*B0F99D2963660DD7E16B751EC9EE2F17B6A68FA6 +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +select length(password('1')); +length(password('1')) +41 +select length(encrypt('test')); +length(encrypt('test')) +13 +select encrypt('test','aa'); +encrypt('test','aa') +aaqPiZY5xR5l. +select old_password(NULL); +old_password(NULL) +NULL +select password(NULL); +password(NULL) +NULL +set global old_passwords=on; +select password(''); +password('') + +select old_password(''); +old_password('') + +select password('idkfa'); +password('idkfa') +*B669C9DAC3AA6F2254B03CDEF8DFDD6B2D1054BA +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +set old_passwords=on; +select password('idkfa'); +password('idkfa') +5c078dc54ca0fcca +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +set global old_passwords=off; +select password('idkfa'); +password('idkfa') +5c078dc54ca0fcca +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +set old_passwords=off; +select password('idkfa '); +password('idkfa ') +*2DC31D90647B4C1ABC9231563D2236E96C9A2DB2 +select password('idkfa'); +password('idkfa') +*B669C9DAC3AA6F2254B03CDEF8DFDD6B2D1054BA +select password(' idkfa'); +password(' idkfa') +*12B099E56BB7FE8D43C78FD834A9D1D11178D045 +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +select old_password(' i d k f a '); +old_password(' i d k f a ') +5c078dc54ca0fcca +explain extended select password('idkfa '), old_password('idkfa'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select password('idkfa ') AS `password('idkfa ')`,old_password('idkfa') AS `old_password('idkfa')` +select encrypt('1234','_.'); +encrypt('1234','_.') +# diff --git a/mysql-test/suite/pbxt/r/func_date_add.result b/mysql-test/suite/pbxt/r/func_date_add.result new file mode 100644 index 00000000000..ac5709260fd --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_date_add.result @@ -0,0 +1,87 @@ +drop table if exists t1; +CREATE TABLE t1 ( +visitor_id int(10) unsigned DEFAULT '0' NOT NULL, +group_id int(10) unsigned DEFAULT '0' NOT NULL, +hits int(10) unsigned DEFAULT '0' NOT NULL, +sessions int(10) unsigned DEFAULT '0' NOT NULL, +ts timestamp, +PRIMARY KEY (visitor_id,group_id) +)/*! engine=MyISAM */; +INSERT INTO t1 VALUES (465931136,7,2,2,20000318160952); +INSERT INTO t1 VALUES (173865424,2,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,8,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,39,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,7,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,3,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,6,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,60,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,1502,2,2,20000318233615); +INSERT INTO t1 VALUES (48985536,2,2,2,20000319013932); +INSERT INTO t1 VALUES (48985536,8,2,2,20000319013932); +INSERT INTO t1 VALUES (48985536,39,2,2,20000319013932); +INSERT INTO t1 VALUES (48985536,7,2,2,20000319013932); +INSERT INTO t1 VALUES (465931136,3,2,2,20000318160951); +INSERT INTO t1 VALUES (465931136,119,1,1,20000318160953); +INSERT INTO t1 VALUES (465931136,2,1,1,20000318160950); +INSERT INTO t1 VALUES (465931136,8,1,1,20000318160950); +INSERT INTO t1 VALUES (465931136,39,1,1,20000318160950); +INSERT INTO t1 VALUES (1092858576,14,1,1,20000319013445); +INSERT INTO t1 VALUES (357917728,3,2,2,20000319145026); +INSERT INTO t1 VALUES (357917728,7,2,2,20000319145027); +select visitor_id,max(ts) as mts from t1 group by visitor_id +having mts < DATE_SUB(NOW(),INTERVAL 3 MONTH); +visitor_id mts +48985536 2000-03-19 01:39:32 +173865424 2000-03-18 23:36:15 +357917728 2000-03-19 14:50:27 +465931136 2000-03-18 16:09:53 +1092858576 2000-03-19 01:34:45 +select visitor_id,max(ts) as mts from t1 group by visitor_id +having DATE_ADD(mts,INTERVAL 3 MONTH) < NOW(); +visitor_id mts +48985536 2000-03-19 01:39:32 +173865424 2000-03-18 23:36:15 +357917728 2000-03-19 14:50:27 +465931136 2000-03-18 16:09:53 +1092858576 2000-03-19 01:34:45 +drop table t1; +set sql_mode='traditional'; +create table t1 (d date); +insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); +ERROR 22008: Datetime function: datetime field overflow +insert into t1 (d) select date_add('2000-01-01',interval 8000 year); +ERROR 22008: Datetime function: datetime field overflow +insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); +insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); +set sql_mode=''; +insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); +Warnings: +Warning 1441 Datetime function: datetime field overflow +insert into t1 (d) select date_add('2000-01-01',interval 8000 year); +Warnings: +Warning 1441 Datetime function: datetime field overflow +insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); +insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); +select * from t1; +d +NULL +NULL +NULL +NULL +NULL +NULL +drop table t1; +End of 4.1 tests +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 DAY; +CAST('2006-09-26' AS DATE) + INTERVAL 1 DAY +2006-09-27 +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 MONTH; +CAST('2006-09-26' AS DATE) + INTERVAL 1 MONTH +2006-10-26 +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 YEAR; +CAST('2006-09-26' AS DATE) + INTERVAL 1 YEAR +2007-09-26 +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 WEEK; +CAST('2006-09-26' AS DATE) + INTERVAL 1 WEEK +2006-10-03 +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/func_default.result b/mysql-test/suite/pbxt/r/func_default.result new file mode 100644 index 00000000000..b35c26fac61 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_default.result @@ -0,0 +1,23 @@ +drop table if exists t1,t2; +create table t1(str varchar(10) default 'def',strnull varchar(10),intg int default '10',rel double default '3.14'); +insert into t1 values ('','',0,0.0); +select default(str), default(strnull), default(intg), default(rel) from t1; +default(str) default(strnull) default(intg) default(rel) +def NULL 10 3.14 +explain extended select default(str), default(strnull), default(intg), default(rel) from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 select default(`test`.`t1`.`str`) AS `default(str)`,default(`test`.`t1`.`strnull`) AS `default(strnull)`,default(`test`.`t1`.`intg`) AS `default(intg)`,default(`test`.`t1`.`rel`) AS `default(rel)` from `test`.`t1` +select * from t1 where str <> default(str); +str strnull intg rel + 0 0 +explain select * from t1 where str <> default(str); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 Using where +drop table t1; +CREATE TABLE t1 (id int(11), s varchar(20)); +INSERT INTO t1 VALUES (1, 'one'), (2, 'two'), (3, 'three'); +SELECT s, 32 AS mi FROM t1 GROUP BY s HAVING DEFAULT(mi) IS NULL; +ERROR HY000: Field 'mi' doesn't have a default value +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/func_equal.result b/mysql-test/suite/pbxt/r/func_equal.result new file mode 100644 index 00000000000..4750af6e8d8 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_equal.result @@ -0,0 +1,44 @@ +drop table if exists t1,t2; +select 0<=>0,0.0<=>0.0,0E0=0E0,"A"<=>"A",NULL<=>NULL; +0<=>0 0.0<=>0.0 0E0=0E0 "A"<=>"A" NULL<=>NULL +1 1 1 1 1 +select 1<=>0,0<=>NULL,NULL<=>0; +1<=>0 0<=>NULL NULL<=>0 +0 0 0 +select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0; +1.0<=>0.0 0.0<=>NULL NULL<=>0.0 +0 0 0 +select "A"<=>"B","A"<=>NULL,NULL<=>"A"; +"A"<=>"B" "A"<=>NULL NULL<=>"A" +0 0 0 +select 0<=>0.0, 0.0<=>0E0, 0E0<=>"0", 10.0<=>1E1, 10<=>10.0, 10<=>1E1; +0<=>0.0 0.0<=>0E0 0E0<=>"0" 10.0<=>1E1 10<=>10.0 10<=>1E1 +1 1 1 1 1 1 +select 1.0<=>0E1,10<=>NULL,NULL<=>0.0, NULL<=>0E0; +1.0<=>0E1 10<=>NULL NULL<=>0.0 NULL<=>0E0 +0 0 0 0 +create table t1 (id int, value int); +create table t2 (id int, value int); +insert into t1 values (1,null); +insert into t2 values (1,null); +select t1.*, t2.*, t1.value<=>t2.value from t1, t2 where t1.id=t2.id and t1.id=1; +id value id value t1.value<=>t2.value +1 NULL 1 NULL 1 +select * from t1 where id <=>id; +id value +1 NULL +select * from t1 where value <=> value; +id value +1 NULL +select * from t1 where id <=> value or value<=>id; +id value +drop table t1,t2; +create table t1 (a bigint unsigned); +insert into t1 values (4828532208463511553); +select * from t1 where a = '4828532208463511553'; +a +4828532208463511553 +select * from t1 where a in ('4828532208463511553'); +a +4828532208463511553 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/func_gconcat.result b/mysql-test/suite/pbxt/r/func_gconcat.result new file mode 100644 index 00000000000..2a05198d050 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_gconcat.result @@ -0,0 +1,736 @@ +drop table if exists t1, t2; +create table t1 (grp int, a bigint unsigned, c char(10) not null, d char(10) not null); +insert into t1 values (1,1,"a","a"); +insert into t1 values (2,2,"b","a"); +insert into t1 values (2,3,"c","b"); +insert into t1 values (3,4,"E","a"); +insert into t1 values (3,5,"C","b"); +insert into t1 values (3,6,"D","b"); +insert into t1 values (3,7,"d","d"); +insert into t1 values (3,8,"d","d"); +insert into t1 values (3,9,"D","c"); +select grp,group_concat(c) from t1 group by grp; +grp group_concat(c) +1 a +2 b,c +3 E,C,D,d,d,D +explain extended select grp,group_concat(c) from t1 group by grp; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 100.00 Using filesort +Warnings: +Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(`test`.`t1`.`c` separator ',') AS `group_concat(c)` from `test`.`t1` group by `test`.`t1`.`grp` +select grp,group_concat(a,c) from t1 group by grp; +grp group_concat(a,c) +1 1a +2 2b,3c +3 4E,5C,6D,7d,8d,9D +select grp,group_concat("(",a,":",c,")") from t1 group by grp; +grp group_concat("(",a,":",c,")") +1 (1:a) +2 (2:b),(3:c) +3 (4:E),(5:C),(6:D),(7:d),(8:d),(9:D) +select grp,group_concat(c separator ",") from t1 group by grp; +grp group_concat(c separator ",") +1 a +2 b,c +3 E,C,D,d,d,D +select grp,group_concat(c separator "---->") from t1 group by grp; +grp group_concat(c separator "---->") +1 a +2 b---->c +3 E---->C---->D---->d---->d---->D +select grp,group_concat(c order by c) from t1 group by grp; +grp group_concat(c order by c) +1 a +2 b,c +3 C,D,d,d,D,E +select grp,group_concat(c order by c desc) from t1 group by grp; +grp group_concat(c order by c desc) +1 a +2 c,b +3 E,D,d,d,D,C +select grp,group_concat(d order by a) from t1 group by grp; +grp group_concat(d order by a) +1 a +2 a,b +3 a,b,b,d,d,c +select grp,group_concat(d order by a desc) from t1 group by grp; +grp group_concat(d order by a desc) +1 a +2 b,a +3 c,d,d,b,b,a +select grp,group_concat(a order by a,d+c-ascii(c)-a) from t1 group by grp; +grp group_concat(a order by a,d+c-ascii(c)-a) +1 1 +2 2,3 +3 4,5,6,7,8,9 +select grp,group_concat(a order by d+c-ascii(c),a) from t1 group by grp; +grp group_concat(a order by d+c-ascii(c),a) +1 1 +2 3,2 +3 7,8,4,6,9,5 +select grp,group_concat(c order by 1) from t1 group by grp; +grp group_concat(c order by 1) +1 a +2 b,c +3 C,D,d,d,D,E +select grp,group_concat(distinct c order by c) from t1 group by grp; +grp group_concat(distinct c order by c) +1 a +2 b,c +3 C,D,E +select grp,group_concat(distinct c order by c desc) from t1 group by grp; +grp group_concat(distinct c order by c desc) +1 a +2 c,b +3 E,D,C +explain extended select grp,group_concat(distinct c order by c desc) from t1 group by grp; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 100.00 Using filesort +Warnings: +Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(distinct `test`.`t1`.`c` order by `test`.`t1`.`c` DESC separator ',') AS `group_concat(distinct c order by c desc)` from `test`.`t1` group by `test`.`t1`.`grp` +select grp,group_concat(c order by c separator ",") from t1 group by grp; +grp group_concat(c order by c separator ",") +1 a +2 b,c +3 C,D,d,d,D,E +select grp,group_concat(c order by c desc separator ",") from t1 group by grp; +grp group_concat(c order by c desc separator ",") +1 a +2 c,b +3 E,D,d,d,D,C +select grp,group_concat(distinct c order by c separator ",") from t1 group by grp; +grp group_concat(distinct c order by c separator ",") +1 a +2 b,c +3 C,D,E +explain extended select grp,group_concat(distinct c order by c separator ",") from t1 group by grp; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 100.00 Using filesort +Warnings: +Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(distinct `test`.`t1`.`c` order by `test`.`t1`.`c` ASC separator ',') AS `group_concat(distinct c order by c separator ",")` from `test`.`t1` group by `test`.`t1`.`grp` +select grp,group_concat(distinct c order by c desc separator ",") from t1 group by grp; +grp group_concat(distinct c order by c desc separator ",") +1 a +2 c,b +3 E,D,C +select grp,group_concat(c order by grp desc) from t1 group by grp order by grp; +grp group_concat(c order by grp desc) +1 a +2 c,b +3 D,d,d,D,C,E +select grp, group_concat(a separator "")+0 from t1 group by grp; +grp group_concat(a separator "")+0 +1 1 +2 23 +3 456789 +select grp, group_concat(a separator "")+0.0 from t1 group by grp; +grp group_concat(a separator "")+0.0 +1 1.0 +2 23.0 +3 456789.0 +select grp, ROUND(group_concat(a separator "")) from t1 group by grp; +grp ROUND(group_concat(a separator "")) +1 1 +2 23 +3 456789 +drop table t1; +create table t1 (grp int, c char(10)); +insert into t1 values (1,NULL),(2,"b"),(2,NULL),(3,"E"),(3,NULL),(3,"D"),(3,NULL),(3,NULL),(3,"D"),(4,""),(5,NULL); +select grp,group_concat(c order by c) from t1 group by grp; +grp group_concat(c order by c) +1 NULL +2 b +3 D,D,E +4 +5 NULL +set group_concat_max_len = 4; +select grp,group_concat(c) from t1 group by grp; +grp group_concat(c) +1 NULL +2 b +3 E,D, +4 +5 NULL +Warnings: +Warning 1260 1 line(s) were cut by GROUP_CONCAT() +show warnings; +Level Code Message +Warning 1260 1 line(s) were cut by GROUP_CONCAT() +set group_concat_max_len = 1024; +select group_concat(sum(c)) from t1 group by grp; +ERROR HY000: Invalid use of group function +select grp,group_concat(c order by 2) from t1 group by grp; +ERROR 42S22: Unknown column '2' in 'order clause' +drop table t1; +create table t1 ( URL_ID int(11), URL varchar(80)); +create table t2 ( REQ_ID int(11), URL_ID int(11)); +insert into t1 values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); +insert into t2 values (1,4), (5,4), (5,5); +select REQ_ID, Group_Concat(URL) as URL from t1, t2 where +t2.URL_ID = t1.URL_ID group by REQ_ID; +REQ_ID URL +1 X +5 X,X,X +select REQ_ID, Group_Concat(URL) as URL, Min(t1.URL_ID) urll, +Max(t1.URL_ID) urlg from t1, t2 where t2.URL_ID = t1.URL_ID group by REQ_ID; +REQ_ID URL urll urlg +1 X 4 4 +5 X,X,X 4 5 +drop table t1; +drop table t2; +create table t1 (id int, name varchar(16)); +insert into t1 values (1,'longername'),(1,'evenlongername'); +select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; +without distinct: how it should be +1:longername,1:evenlongername +select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1; +with distinct: cutoff at length of shortname +1:longername,1:evenlongername +drop table t1; +create table t1(id int); +create table t2(id int); +insert into t1 values(0),(1); +select group_concat(t1.id) FROM t1,t2; +group_concat(t1.id) +NULL +drop table t1; +drop table t2; +create table t1 (bar varchar(32)); +insert into t1 values('test1'),('test2'); +select group_concat(bar order by concat(bar,bar)) from t1; +group_concat(bar order by concat(bar,bar)) +test1,test2 +select group_concat(bar order by concat(bar,bar) desc) from t1; +group_concat(bar order by concat(bar,bar) desc) +test2,test1 +select bar from t1 having group_concat(bar)=''; +bar +select bar from t1 having instr(group_concat(bar), "test") > 0; +bar +test1 +select bar from t1 having instr(group_concat(bar order by concat(bar,bar) desc), "test2,test1") > 0; +bar +test1 +drop table t1; +create table t1 (a int, a1 varchar(10)); +create table t2 (a0 int); +insert into t1 values (0,"a"),(0,"b"),(1,"c"); +insert into t2 values (1),(2),(3); +select group_concat(a1 order by (t1.a IN (select a0 from t2))) from t1; +group_concat(a1 order by (t1.a IN (select a0 from t2))) +b,a,c +select group_concat(a1 order by (t1.a)) from t1; +group_concat(a1 order by (t1.a)) +b,a,c +drop table t1, t2; +CREATE TABLE t1 (id1 tinyint(4) NOT NULL, id2 tinyint(4) NOT NULL); +INSERT INTO t1 VALUES (1, 1),(1, 2),(1, 3),(1, 4),(1, 5),(2, 1),(2, 2),(2, 3); +CREATE TABLE t2 (id1 tinyint(4) NOT NULL); +INSERT INTO t2 VALUES (1),(2),(3),(4),(5); +SELECT t1.id1, GROUP_CONCAT(t1.id2 ORDER BY t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 AND t1.id1=1 GROUP BY t1.id1; +id1 concat_id +1 1,2,3,4,5 +SELECT t1.id1, GROUP_CONCAT(t1.id2 ORDER BY t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +id1 concat_id +1 1,2,3,4,5 +2 1,2,3 +SELECT t1.id1, GROUP_CONCAT(t1.id2 ORDER BY t1.id2 DESC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +id1 concat_id +1 5,4,3,2,1 +2 3,2,1 +SELECT t1.id1, GROUP_CONCAT(t1.id2 ORDER BY 6-t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +id1 concat_id +1 5,4,3,2,1 +2 3,2,1 +SELECT t1.id1, GROUP_CONCAT(t1.id2,6-t1.id2 ORDER BY 6-t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +id1 concat_id +1 51,42,33,24,15 +2 33,24,15 +SELECT t1.id1, GROUP_CONCAT(t1.id2,6-t1.id2 ORDER BY 6-t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +id1 concat_id +1 51,42,33,24,15 +2 33,24,15 +SELECT t1.id1, GROUP_CONCAT(t1.id2,"/",6-t1.id2 ORDER BY 1+0,6-t1.id2,t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +id1 concat_id +1 5/1,4/2,3/3,2/4,1/5 +2 3/3,2/4,1/5 +drop table t1,t2; +create table t1 (s1 char(10), s2 int not null); +insert into t1 values ('a',2),('b',2),('c',1),('a',3),('b',4),('c',4); +select distinct s1 from t1 order by s2,s1; +s1 +c +a +b +select group_concat(distinct s1) from t1; +group_concat(distinct s1) +a,b,c +select group_concat(distinct s1 order by s2) from t1 where s2 < 4; +group_concat(distinct s1 order by s2) +c,b,a +select group_concat(distinct s1 order by s2) from t1; +group_concat(distinct s1 order by s2) +c,b,a +drop table t1; +create table t1 (a int, c int); +insert into t1 values (1, 2), (2, 3), (2, 4), (3, 5); +create table t2 (a int, c int); +insert into t2 values (1, 5), (2, 4), (3, 3), (3,3); +select group_concat(c) from t1; +group_concat(c) +2,3,4,5 +select group_concat(c order by (select c from t2 where t2.a=t1.a limit 1)) as grp from t1; +grp +5,4,3,2 +select group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a)) as grp from t1; +grp +5,4,3,2 +select group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1; +grp +2,4,3,5 +select t1.a, group_concat(c order by (select c from t2 where t2.a=t1.a limit 1)) as grp from t1 group by 1; +a grp +1 2 +2 4,3 +3 5 +select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a)) as grp from t1 group by 1; +a grp +1 2 +2 4,3 +3 5 +select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1 group by 1; +a grp +1 2 +2 4,3 +3 5 +select group_concat(c order by (select concat(5-t1.c,group_concat(c order by a)) from t2 where t2.a=t1.a)) as grp from t1; +grp +5,4,3,2 +select group_concat(c order by (select concat(t1.c,group_concat(c)) from t2 where a=t1.a)) as grp from t1; +grp +2,3,4,5 +select a,c,(select group_concat(c order by a) from t2 where a=t1.a) as grp from t1 order by grp; +a c grp +3 5 3,3 +2 3 4 +2 4 4 +1 2 5 +drop table t1,t2; +CREATE TABLE t1 ( a int ); +CREATE TABLE t2 ( a int ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +SELECT GROUP_CONCAT(t1.a*t2.a ORDER BY t2.a) FROM t1, t2 GROUP BY t1.a; +GROUP_CONCAT(t1.a*t2.a ORDER BY t2.a) +1,2 +2,4 +DROP TABLE t1, t2; +CREATE TABLE t1 (a char(4)); +INSERT INTO t1 VALUES ('John'), ('Anna'), ('Bill'); +SELECT GROUP_CONCAT(a SEPARATOR '||') AS names FROM t1 +HAVING names LIKE '%An%'; +names +John||Anna||Bill +SELECT GROUP_CONCAT(a SEPARATOR '###') AS names FROM t1 +HAVING LEFT(names, 1) ='J'; +names +John###Anna###Bill +DROP TABLE t1; +CREATE TABLE t1 ( a int, b TEXT ); +INSERT INTO t1 VALUES (1,'First Row'), (2,'Second Row'); +SELECT GROUP_CONCAT(b ORDER BY b) FROM t1 GROUP BY a; +GROUP_CONCAT(b ORDER BY b) +First Row +Second Row +DROP TABLE t1; +CREATE TABLE t1 (A_ID INT NOT NULL,A_DESC CHAR(3) NOT NULL,PRIMARY KEY (A_ID)); +INSERT INTO t1 VALUES (1,'ABC'), (2,'EFG'), (3,'HIJ'); +CREATE TABLE t2 (A_ID INT NOT NULL,B_DESC CHAR(3) NOT NULL,PRIMARY KEY (A_ID,B_DESC)); +INSERT INTO t2 VALUES (1,'A'),(1,'B'),(3,'F'); +SELECT t1.A_ID, GROUP_CONCAT(t2.B_DESC) AS B_DESC FROM t1 LEFT JOIN t2 ON t1.A_ID=t2.A_ID GROUP BY t1.A_ID ORDER BY t1.A_DESC; +A_ID B_DESC +1 A,B +2 NULL +3 F +DROP TABLE t1; +DROP TABLE t2; +create table t1 (a int, b text); +insert into t1 values (1, 'bb'), (1, 'ccc'), (1, 'a'), (1, 'bb'), (1, 'ccc'); +insert into t1 values (2, 'BB'), (2, 'CCC'), (2, 'A'), (2, 'BB'), (2, 'CCC'); +select group_concat(b) from t1 group by a; +group_concat(b) +bb,ccc,a,bb,ccc +BB,CCC,A,BB,CCC +select group_concat(distinct b) from t1 group by a; +group_concat(distinct b) +bb,ccc,a +BB,CCC,A +select group_concat(b order by b) from t1 group by a; +group_concat(b order by b) +a,bb,bb,ccc,ccc +A,BB,BB,CCC,CCC +select group_concat(distinct b order by b) from t1 group by a; +group_concat(distinct b order by b) +a,bb,ccc +A,BB,CCC +set local group_concat_max_len=4; +select group_concat(b) from t1 group by a; +group_concat(b) +bb,c +BB,C +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(distinct b) from t1 group by a; +group_concat(distinct b) +bb,c +BB,C +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(b order by b) from t1 group by a; +group_concat(b order by b) +a,bb +A,BB +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(distinct b order by b) from t1 group by a; +group_concat(distinct b order by b) +a,bb +A,BB +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +insert into t1 values (1, concat(repeat('1', 300), '2')), +(1, concat(repeat('1', 300), '2')), (1, concat(repeat('0', 300), '1')), +(2, concat(repeat('1', 300), '2')), (2, concat(repeat('1', 300), '2')), +(2, concat(repeat('0', 300), '1')); +set local group_concat_max_len=1024; +select group_concat(b) from t1 group by a; +group_concat(b) +bb,ccc,a,bb,ccc,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +BB,CCC,A,BB,CCC,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +select group_concat(distinct b) from t1 group by a; +group_concat(distinct b) +bb,ccc,a,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +BB,CCC,A,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +select group_concat(b order by b) from t1 group by a; +group_concat(b order by b) +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,a,bb,bb,ccc,ccc +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,A,BB,BB,CCC,CCC +select group_concat(distinct b order by b) from t1 group by a; +group_concat(distinct b order by b) +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,a,bb,ccc +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,A,BB,CCC +set local group_concat_max_len=400; +select group_concat(b) from t1 group by a; +group_concat(b) +bb,ccc,a,bb,ccc,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,1111111111111111111111111111111111111111111111111111111111111111111111111111111111 +BB,CCC,A,BB,CCC,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,1111111111111111111111111111111111111111111111111111111111111111111111111111111111 +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(distinct b) from t1 group by a; +group_concat(distinct b) +bb,ccc,a,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +BB,CCC,A,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(b order by b) from t1 group by a; +group_concat(b order by b) +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(distinct b order by b) from t1 group by a; +group_concat(distinct b order by b) +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +drop table t1; +create table t1 (a varchar(255) character set cp1250 collate cp1250_general_ci, +b varchar(255) character set koi8r); +insert into t1 values ('xxx','yyy'); +select collation(a) from t1; +collation(a) +cp1250_general_ci +select collation(group_concat(a)) from t1; +collation(group_concat(a)) +cp1250_general_ci +create table t2 select group_concat(a) as a from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(400) CHARACTER SET cp1250 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select collation(group_concat(a,_koi8r'test')) from t1; +collation(group_concat(a,_koi8r'test')) +cp1250_general_ci +select collation(group_concat(a,_koi8r 0xC1C2)) from t1; +ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,COERCIBLE) for operation 'group_concat' +select collation(group_concat(a,b)) from t1; +ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat' +drop table t1; +drop table t2; +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +a +À +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +À +DROP TABLE t1; +CREATE TABLE t1 (id int); +SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; +gc +NULL +DROP TABLE t1; +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2); +select b x, (select group_concat(x) from t2) from t2; +x (select group_concat(x) from t2) +1 1,1 +2 2,2 +drop table t2; +create table t1 (d int not null auto_increment,primary key(d), a int, b int, c int); +insert into t1(a,b) values (1,3), (1,4), (1,2), (2,7), (1,1), (1,2), (2,3), (2,3); +select d,a,b from t1 order by a; +d a b +1 1 3 +2 1 4 +3 1 2 +5 1 1 +6 1 2 +4 2 7 +7 2 3 +8 2 3 +explain select a, group_concat(b) from t1 group by a with rollup; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using filesort +select a, group_concat(b) from t1 group by a with rollup; +a group_concat(b) +1 3,4,2,1,2 +2 7,3,3 +NULL 3,4,2,1,2,7,3,3 +select a, group_concat(distinct b) from t1 group by a with rollup; +a group_concat(distinct b) +1 3,4,2,1 +2 7,3 +NULL 3,4,2,1,7 +select a, group_concat(b order by b) from t1 group by a with rollup; +a group_concat(b order by b) +1 1,2,2,3,4 +2 3,3,7 +NULL 1,2,2,3,3,3,4,7 +select a, group_concat(distinct b order by b) from t1 group by a with rollup; +a group_concat(distinct b order by b) +1 1,2,3,4 +2 3,7 +NULL 1,2,3,4,7 +drop table t1; +create table t1 (a char(3), b char(20), primary key (a, b)); +insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English'); +select group_concat(a) from t1 group by b; +group_concat(a) +ABW +ABW +drop table t1; +CREATE TABLE t1 ( +aID smallint(5) unsigned NOT NULL auto_increment, +sometitle varchar(255) NOT NULL default '', +bID smallint(5) unsigned NOT NULL, +PRIMARY KEY (aID), +UNIQUE KEY sometitle (sometitle) +); +INSERT INTO t1 SET sometitle = 'title1', bID = 1; +INSERT INTO t1 SET sometitle = 'title2', bID = 1; +CREATE TABLE t2 ( +bID smallint(5) unsigned NOT NULL auto_increment, +somename varchar(255) NOT NULL default '', +PRIMARY KEY (bID), +UNIQUE KEY somename (somename) +); +INSERT INTO t2 SET somename = 'test'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +FROM t1 JOIN t2 ON t1.bID = t2.bID; +COUNT(*) GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +2 test +INSERT INTO t2 SET somename = 'test2'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +FROM t1 JOIN t2 ON t1.bID = t2.bID; +COUNT(*) GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +2 test +DELETE FROM t2 WHERE somename = 'test2'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +FROM t1 JOIN t2 ON t1.bID = t2.bID; +COUNT(*) GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +2 test +DROP TABLE t1,t2; +select * from (select group_concat('c') from DUAL) t; +group_concat('c') +c +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +group_concat(a) +NULL +select group_concat('x') UNION ALL select 1; +group_concat('x') +x +1 +drop table t1; +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES +(2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +,,x,y,z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; +GROUP_CONCAT(a ORDER BY a) +,,,x,y,z +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +GROUP_CONCAT(a) +,y +,x +z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; +GROUP_CONCAT(a ORDER BY a) +,y +,x +,z +DROP TABLE t1; +create table t1(f1 int); +insert into t1 values(1),(2),(3); +select f1, group_concat(f1+1) from t1 group by f1 with rollup; +f1 group_concat(f1+1) +1 2 +2 3 +3 4 +NULL 2,3,4 +select count(distinct (f1+1)) from t1 group by f1 with rollup; +count(distinct (f1+1)) +1 +1 +1 +3 +drop table t1; +create table t1 (f1 int unsigned, f2 varchar(255)); +insert into t1 values (1,repeat('a',255)),(2,repeat('b',255)); +select f2,group_concat(f1) from t1 group by f2; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 f2 f2 253 255 255 Y 0 0 8 +def group_concat(f1) 253 400 1 Y 128 0 63 +f2 group_concat(f1) +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1 +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 2 +drop table t1; +set names latin1; +create table t1 (a char, b char); +insert into t1 values ('a', 'a'), ('a', 'b'), ('b', 'a'), ('b', 'b'); +create table t2 select group_concat(b) as a from t1 where a = 'a'; +create table t3 (select group_concat(a) as a from t1 where a = 'a') union +(select group_concat(b) as a from t1 where a = 'b'); +select charset(a) from t2; +charset(a) +latin1 +select charset(a) from t3; +charset(a) +latin1 +latin1 +drop table t1, t2, t3; +set names default; +create table t1 (c1 varchar(10), c2 int); +select charset(group_concat(c1 order by c2)) from t1; +charset(group_concat(c1 order by c2)) +latin1 +drop table t1; +CREATE TABLE t1 (a INT(10), b LONGTEXT, PRIMARY KEY (a)); +SET GROUP_CONCAT_MAX_LEN = 20000000; +INSERT INTO t1 VALUES (1,REPEAT(CONCAT('A',CAST(CHAR(0) AS BINARY),'B'), 40000)); +INSERT INTO t1 SELECT a + 1, b FROM t1; +SELECT a, CHAR_LENGTH(b) FROM t1; +a CHAR_LENGTH(b) +1 120000 +2 120000 +SELECT CHAR_LENGTH( GROUP_CONCAT(b) ) FROM t1; +CHAR_LENGTH( GROUP_CONCAT(b) ) +240001 +SET GROUP_CONCAT_MAX_LEN = 1024; +DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (2,1), (1,2), (2,2), (1,3); +SELECT GROUP_CONCAT(a), x +FROM (SELECT a, GROUP_CONCAT(b) x FROM t1 GROUP BY a) AS s +GROUP BY x; +GROUP_CONCAT(a) x +2 1,2 +1 2,3 +DROP TABLE t1; +set names utf8; +create table t1 +( +x text character set utf8 not null, +y integer not null +); +insert into t1 values (repeat('a', 1022), 0), (repeat(_utf8 0xc3b7, 4), 0); +set group_concat_max_len= 1022 + 10; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1032 1031 1027 aaaaaaa,÷÷÷÷ C3B7C3B7C3B7 +set group_concat_max_len= 1022 + 9; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1031 1031 1027 aaaaaaa,÷÷÷÷ C3B7C3B7C3B7 +set group_concat_max_len= 1022 + 8; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1030 1029 1026 aaaaaaaa,÷÷÷ C3B7C3B7C3B7 +set group_concat_max_len= 1022 + 7; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1029 1029 1026 aaaaaaaa,÷÷÷ C3B7C3B7C3B7 +set group_concat_max_len= 1022 + 6; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1028 1027 1025 aaaaaaaaa,÷÷ 612CC3B7C3B7 +set group_concat_max_len= 1022 + 5; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1027 1027 1025 aaaaaaaaa,÷÷ 612CC3B7C3B7 +set group_concat_max_len= 1022 + 4; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1026 1025 1024 aaaaaaaaaa,÷ 6161612CC3B7 +set group_concat_max_len= 1022 + 3; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1025 1025 1024 aaaaaaaaaa,÷ 6161612CC3B7 +set group_concat_max_len= 1022 + 2; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1024 1023 1023 aaaaaaaaaaa, 61616161612C +set group_concat_max_len= 1022 + 1; +select @x:=group_concat(x) from t1 group by y; +select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); +@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12) +1023 1023 1023 aaaaaaaaaaa, 61616161612C +drop table t1; +set group_concat_max_len=1024; +set names latin1; +create table t1 (f1 int unsigned, f2 varchar(255)); +insert into t1 values (1,repeat('a',255)),(2,repeat('b',255)); +select f2,group_concat(f1) from t1 group by f2; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 f2 f2 253 255 255 Y 0 0 8 +def group_concat(f1) 252 1024 1 Y 128 0 63 +f2 group_concat(f1) +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1 +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 2 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/func_group.result b/mysql-test/suite/pbxt/r/func_group.result new file mode 100644 index 00000000000..d5f804dee03 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_group.result @@ -0,0 +1,1315 @@ +drop table if exists t1,t2; +set @sav_dpi= @@div_precision_increment; +set div_precision_increment= 5; +show variables like 'div_precision_increment'; +Variable_name Value +div_precision_increment 5 +create table t1 (grp int, a bigint unsigned, c char(10) not null); +insert into t1 values (1,1,"a"); +insert into t1 values (2,2,"b"); +insert into t1 values (2,3,"c"); +insert into t1 values (3,4,"E"); +insert into t1 values (3,5,"C"); +insert into t1 values (3,6,"D"); +select a,c,sum(a) from t1 group by a; +a c sum(a) +1 a 1 +2 b 2 +3 c 3 +4 E 4 +5 C 5 +6 D 6 +select a,c,sum(a) from t1 where a > 10 group by a; +a c sum(a) +select sum(a) from t1 where a > 10; +sum(a) +NULL +select a from t1 order by rand(10); +a +2 +6 +1 +3 +5 +4 +select distinct a from t1 order by rand(10); +a +2 +6 +1 +3 +5 +4 +select count(distinct a),count(distinct grp) from t1; +count(distinct a) count(distinct grp) +6 3 +insert into t1 values (null,null,''); +select count(distinct a),count(distinct grp) from t1; +count(distinct a) count(distinct grp) +6 3 +select sum(all a),count(all a),avg(all a),std(all a),variance(all a),bit_or(all a),bit_and(all a),min(all a),max(all a),min(all c),max(all c) from t1; +sum(all a) count(all a) avg(all a) std(all a) variance(all a) bit_or(all a) bit_and(all a) min(all a) max(all a) min(all c) max(all c) +21 6 3.50000 1.70783 2.91667 7 0 1 6 E +select grp, sum(a),count(a),avg(a),std(a),variance(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp; +grp sum(a) count(a) avg(a) std(a) variance(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c) +NULL NULL 0 NULL NULL NULL 0 18446744073709551615 NULL NULL +1 1 1 1.00000 0.00000 0.00000 1 1 1 1 a a +2 5 2 2.50000 0.50000 0.25000 3 2 2 3 b c +3 15 3 5.00000 0.81650 0.66667 7 4 4 6 C E +select grp, sum(a)+count(a)+avg(a)+std(a)+variance(a)+bit_or(a)+bit_and(a)+min(a)+max(a)+min(c)+max(c) as sum from t1 group by grp; +grp sum +NULL NULL +1 7 +2 20.25 +3 45.483163247594 +create table t2 (grp int, a bigint unsigned, c char(10)); +insert into t2 select grp,max(a)+max(grp),max(c) from t1 group by grp; +replace into t2 select grp, a, c from t1 limit 2,1; +select * from t2; +grp a c +NULL NULL +1 2 a +2 5 c +3 9 E +2 3 c +drop table t1,t2; +CREATE TABLE t1 (id int(11),value1 float(10,2)); +INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00); +CREATE TABLE t2 (id int(11),name char(20)); +INSERT INTO t2 VALUES (1,'Set One'),(2,'Set Two'); +select id, avg(value1), std(value1), variance(value1) from t1 group by id; +id avg(value1) std(value1) variance(value1) +1 1.0000000 0.816497 0.666667 +2 11.0000000 0.816497 0.666667 +select name, avg(value1), std(value1), variance(value1) from t1, t2 where t1.id = t2.id group by t1.id; +name avg(value1) std(value1) variance(value1) +Set One 1.0000000 0.816497 0.666667 +Set Two 11.0000000 0.816497 0.666667 +drop table t1,t2; +create table t1 (id int not null); +create table t2 (id int not null,rating int null); +insert into t1 values(1),(2),(3); +insert into t2 values(1, 3),(2, NULL),(2, NULL),(3, 2),(3, NULL); +select t1.id, avg(rating) from t1 left join t2 on ( t1.id = t2.id ) group by t1.id; +id avg(rating) +1 3.00000 +2 NULL +3 2.00000 +select sql_small_result t2.id, avg(rating) from t2 group by t2.id; +id avg(rating) +1 3.00000 +2 NULL +3 2.00000 +select sql_big_result t2.id, avg(rating) from t2 group by t2.id; +id avg(rating) +1 3.00000 +2 NULL +3 2.00000 +select sql_small_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +id avg(rating+0.0e0) +1 3 +2 NULL +3 2 +select sql_big_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +id avg(rating+0.0e0) +1 3 +2 NULL +3 2 +drop table t1,t2; +create table t1 (a smallint(6) primary key, c char(10), b text); +INSERT INTO t1 VALUES (1,'1','1'); +INSERT INTO t1 VALUES (2,'2','2'); +INSERT INTO t1 VALUES (4,'4','4'); +select count(*) from t1; +count(*) +3 +select count(*) from t1 where a = 1; +count(*) +1 +select count(*) from t1 where a = 100; +count(*) +0 +select count(*) from t1 where a >= 10; +count(*) +0 +select count(a) from t1 where a = 1; +count(a) +1 +select count(a) from t1 where a = 100; +count(a) +0 +select count(a) from t1 where a >= 10; +count(a) +0 +select count(b) from t1 where b >= 2; +count(b) +2 +select count(b) from t1 where b >= 10; +count(b) +0 +select count(c) from t1 where c = 10; +count(c) +0 +drop table t1; +CREATE TABLE t1 (d DATETIME, i INT); +INSERT INTO t1 VALUES (NOW(), 1); +SELECT COUNT(i), i, COUNT(i)*i FROM t1 GROUP BY i; +COUNT(i) i COUNT(i)*i +1 1 1 +SELECT COUNT(i), (i+0), COUNT(i)*(i+0) FROM t1 GROUP BY i; +COUNT(i) (i+0) COUNT(i)*(i+0) +1 1 1 +DROP TABLE t1; +create table t1 ( +num float(5,2), +user char(20) +); +insert into t1 values (10.3,'nem'),(20.53,'monty'),(30.23,'sinisa'); +insert into t1 values (30.13,'nem'),(20.98,'monty'),(10.45,'sinisa'); +insert into t1 values (5.2,'nem'),(8.64,'monty'),(11.12,'sinisa'); +select sum(num) from t1; +sum(num) +147.58 +select sum(num) from t1 group by user; +sum(num) +50.15 +45.63 +51.80 +drop table t1; +create table t1 (a1 int, a2 char(3), key k1(a1), key k2(a2)); +insert into t1 values(10,'aaa'), (10,null), (10,'bbb'), (20,'zzz'); +create table t2(a1 char(3), a2 int, a3 real, key k1(a1), key k2(a2, a1)); +select * from t1; +a1 a2 +10 aaa +10 NULL +10 bbb +20 zzz +select min(a2) from t1; +min(a2) +aaa +select max(t1.a1), max(t2.a2) from t1, t2; +max(t1.a1) max(t2.a2) +NULL NULL +select max(t1.a1) from t1, t2; +max(t1.a1) +NULL +select max(t2.a2), max(t1.a1) from t1, t2; +max(t2.a2) max(t1.a1) +NULL NULL +explain select min(a2) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(t1.a1), max(t2.a2) from t1, t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No matching min/max row +insert into t2 values('AAA', 10, 0.5); +insert into t2 values('BBB', 20, 1.0); +select t1.a1, t1.a2, t2.a1, t2.a2 from t1,t2; +a1 a2 a1 a2 +10 aaa AAA 10 +10 aaa BBB 20 +10 NULL AAA 10 +10 NULL BBB 20 +10 bbb AAA 10 +10 bbb BBB 20 +20 zzz AAA 10 +20 zzz BBB 20 +select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9; +max(t1.a1) max(t2.a1) +NULL NULL +select max(t2.a1), max(t1.a1) from t1, t2 where t2.a2=9; +max(t2.a1) max(t1.a1) +NULL NULL +select t1.a1, t1.a2, t2.a1, t2.a2 from t1 left outer join t2 on t1.a1=10; +a1 a2 a1 a2 +10 aaa AAA 10 +10 aaa BBB 20 +10 NULL AAA 10 +10 NULL BBB 20 +10 bbb AAA 10 +10 bbb BBB 20 +20 zzz NULL NULL +select max(t1.a2) from t1 left outer join t2 on t1.a1=10; +max(t1.a2) +zzz +select max(t2.a1) from t2 left outer join t1 on t2.a2=10 where t2.a2=20; +max(t2.a1) +BBB +select max(t2.a1) from t2 left outer join t1 on t2.a2=10 where t2.a2=10; +max(t2.a1) +AAA +select max(t2.a1) from t1 left outer join t2 on t1.a2=t2.a1 and 1=0 where t2.a1='AAA'; +max(t2.a1) +NULL +select max(t1.a2),max(t2.a1) from t1 left outer join t2 on t1.a1=10; +max(t1.a2) max(t2.a1) +zzz BBB +drop table t1,t2; +CREATE TABLE t1 (a int, b int); +select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; +count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +0 NULL NULL NULL NULL NULL 18446744073709551615 0 +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +insert into t1 values (1,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +insert into t1 values (1,null); +insert into t1 values (2,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +insert into t1 values (2,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 1 1 1.00000 0.00000 1 1 1 1 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 1 1 1.00000 0.00000 1 1 1 1 +insert into t1 values (3,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 1 1 1.00000 0.00000 1 1 1 1 +3 1 1 1.00000 0.00000 1 1 1 1 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) bit_xor(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 0 +2 1 1 1.00000 0.00000 1 1 1 1 1 +3 1 1 1.00000 0.00000 1 1 1 1 1 +explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using filesort +Warnings: +Note 1003 select sql_big_result `test`.`t1`.`a` AS `a`,count(`test`.`t1`.`b`) AS `count(b)`,sum(`test`.`t1`.`b`) AS `sum(b)`,avg(`test`.`t1`.`b`) AS `avg(b)`,std(`test`.`t1`.`b`) AS `std(b)`,min(`test`.`t1`.`b`) AS `min(b)`,max(`test`.`t1`.`b`) AS `max(b)`,bit_and(`test`.`t1`.`b`) AS `bit_and(b)`,bit_or(`test`.`t1`.`b`) AS `bit_or(b)`,bit_xor(`test`.`t1`.`b`) AS `bit_xor(b)` from `test`.`t1` group by `test`.`t1`.`a` +drop table t1; +create table t1 (col int); +insert into t1 values (-1), (-2), (-3); +select bit_and(col), bit_or(col) from t1; +bit_and(col) bit_or(col) +18446744073709551612 18446744073709551615 +select SQL_BIG_RESULT bit_and(col), bit_or(col) from t1 group by col; +bit_and(col) bit_or(col) +18446744073709551613 18446744073709551613 +18446744073709551614 18446744073709551614 +18446744073709551615 18446744073709551615 +drop table t1; +create table t1 (a int); +select avg(2) from t1; +avg(2) +NULL +drop table t1; +create table t1( +a1 char(3) primary key, +a2 smallint, +a3 char(3), +a4 real, +a5 date, +key k1(a2,a3), +key k2(a4 desc,a1), +key k3(a5,a1) +); +create table t2( +a1 char(3) primary key, +a2 char(17), +a3 char(2), +a4 char(3), +key k1(a3, a2), +key k2(a4) +); +insert into t1 values('AME',0,'SEA',0.100,date'1942-02-19'); +insert into t1 values('HBR',1,'SEA',0.085,date'1948-03-05'); +insert into t1 values('BOT',2,'SEA',0.085,date'1951-11-29'); +insert into t1 values('BMC',3,'SEA',0.085,date'1958-09-08'); +insert into t1 values('TWU',0,'LAX',0.080,date'1969-10-05'); +insert into t1 values('BDL',0,'DEN',0.080,date'1960-11-27'); +insert into t1 values('DTX',1,'NYC',0.080,date'1961-05-04'); +insert into t1 values('PLS',1,'WDC',0.075,date'1949-01-02'); +insert into t1 values('ZAJ',2,'CHI',0.075,date'1960-06-15'); +insert into t1 values('VVV',2,'MIN',0.075,date'1959-06-28'); +insert into t1 values('GTM',3,'DAL',0.070,date'1977-09-23'); +insert into t1 values('SSJ',null,'CHI',null,date'1974-03-19'); +insert into t1 values('KKK',3,'ATL',null,null); +insert into t1 values('XXX',null,'MIN',null,null); +insert into t1 values('WWW',1,'LED',null,null); +insert into t2 values('TKF','Seattle','WA','AME'); +insert into t2 values('LCC','Los Angeles','CA','TWU'); +insert into t2 values('DEN','Denver','CO','BDL'); +insert into t2 values('SDC','San Diego','CA','TWU'); +insert into t2 values('NOL','New Orleans','LA','GTM'); +insert into t2 values('LAK','Los Angeles','CA','TWU'); +insert into t2 values('AAA','AAA','AA','AME'); +select * from t1; +a1 a2 a3 a4 a5 +AME 0 SEA 0.1 1942-02-19 +HBR 1 SEA 0.085 1948-03-05 +BOT 2 SEA 0.085 1951-11-29 +BMC 3 SEA 0.085 1958-09-08 +TWU 0 LAX 0.08 1969-10-05 +BDL 0 DEN 0.08 1960-11-27 +DTX 1 NYC 0.08 1961-05-04 +PLS 1 WDC 0.075 1949-01-02 +ZAJ 2 CHI 0.075 1960-06-15 +VVV 2 MIN 0.075 1959-06-28 +GTM 3 DAL 0.07 1977-09-23 +SSJ NULL CHI NULL 1974-03-19 +KKK 3 ATL NULL NULL +XXX NULL MIN NULL NULL +WWW 1 LED NULL NULL +select * from t2; +a1 a2 a3 a4 +TKF Seattle WA AME +LCC Los Angeles CA TWU +DEN Denver CO BDL +SDC San Diego CA TWU +NOL New Orleans LA GTM +LAK Los Angeles CA TWU +AAA AAA AA AME +explain +select min(a1) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a1) from t1; +min(a1) +AME +explain +select max(a4) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a4) from t1; +max(a4) +0.1 +explain +select min(a5), max(a5) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a5), max(a5) from t1; +min(a5) max(a5) +1942-02-19 1977-09-23 +explain +select min(a3) from t1 where a2 = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a3) from t1 where a2 = 2; +min(a3) +CHI +explain +select min(a1), max(a1) from t1 where a4 = 0.080; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a1), max(a1) from t1 where a4 = 0.080; +min(a1) max(a1) +BDL TWU +explain +select min(t1.a5), max(t2.a3) from t1, t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(t1.a5), max(t2.a3) from t1, t2; +min(t1.a5) max(t2.a3) +1942-02-19 WA +explain +select min(t1.a3), max(t2.a2) from t1, t2 where t1.a2 = 0 and t2.a3 = 'CA'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(t1.a3), max(t2.a2) from t1, t2 where t1.a2 = 0 and t2.a3 = 'CA'; +min(t1.a3) max(t2.a2) +DEN San Diego +explain +select min(a1) from t1 where a1 > 'KKK'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a1) from t1 where a1 > 'KKK'; +min(a1) +PLS +explain +select min(a1) from t1 where a1 >= 'KKK'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a1) from t1 where a1 >= 'KKK'; +min(a1) +KKK +explain +select max(a3) from t1 where a2 = 2 and a3 < 'SEA'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a3) from t1 where a2 = 2 and a3 < 'SEA'; +max(a3) +MIN +explain +select max(a5) from t1 where a5 < date'1970-01-01'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a5) from t1 where a5 < date'1970-01-01'; +max(a5) +1969-10-05 +explain +select max(a3) from t1 where a2 is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a3) from t1 where a2 is null; +max(a3) +MIN +explain +select max(a3) from t1 where a2 = 0 and a3 between 'K' and 'Q'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a3) from t1 where a2 = 0 and a3 between 'K' and 'Q'; +max(a3) +LAX +explain +select min(a1), max(a1) from t1 where a1 between 'A' and 'P'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a1), max(a1) from t1 where a1 between 'A' and 'P'; +min(a1) max(a1) +AME KKK +explain +select max(a3) from t1 where a3 < 'SEA' and a2 = 2 and a3 <= 'MIN'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a3) from t1 where a3 < 'SEA' and a2 = 2 and a3 <= 'MIN'; +max(a3) +MIN +explain +select max(a3) from t1 where a3 = 'MIN' and a2 = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a3) from t1 where a3 = 'MIN' and a2 = 2; +max(a3) +MIN +explain +select max(a3) from t1 where a3 = 'DEN' and a2 = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select max(a3) from t1 where a3 = 'DEN' and a2 = 2; +max(a3) +NULL +explain +select max(t1.a3), min(t2.a2) from t1, t2 where t1.a2 = 2 and t1.a3 < 'MIN' and t2.a3 = 'CA'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(t1.a3), min(t2.a2) from t1, t2 where t1.a2 = 2 and t1.a3 < 'MIN' and t2.a3 = 'CA'; +max(t1.a3) min(t2.a2) +CHI Los Angeles +explain +select max(a3) from t1 where a2 is null and a2 = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +select max(a3) from t1 where a2 is null and a2 = 2; +max(a3) +NULL +explain +select max(a2) from t1 where a2 >= 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a2) from t1 where a2 >= 1; +max(a2) +3 +explain +select min(a3) from t1 where a2 = 2 and a3 < 'SEA'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a3) from t1 where a2 = 2 and a3 < 'SEA'; +min(a3) +CHI +explain +select min(a3) from t1 where a2 = 4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select min(a3) from t1 where a2 = 4; +min(a3) +NULL +explain +select min(a3) from t1 where a2 = 2 and a3 > 'SEA'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select min(a3) from t1 where a2 = 2 and a3 > 'SEA'; +min(a3) +NULL +explain +select (min(a4)+max(a4))/2 from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select (min(a4)+max(a4))/2 from t1; +(min(a4)+max(a4))/2 +0.085 +explain +select min(a3) from t1 where 2 = a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a3) from t1 where 2 = a2; +min(a3) +CHI +explain +select max(a3) from t1 where a2 = 2 and 'SEA' > a3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(a3) from t1 where a2 = 2 and 'SEA' > a3; +max(a3) +MIN +explain +select max(a3) from t1 where a2 = 2 and 'SEA' < a3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No matching min/max row +select max(a3) from t1 where a2 = 2 and 'SEA' < a3; +max(a3) +NULL +explain +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI'; +min(a3) +CHI +explain +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI' and a3 < 'SEA'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI' and a3 < 'SEA'; +min(a3) +CHI +explain +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI' and a3 = 'MIN'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI' and a3 = 'MIN'; +min(a3) +MIN +explain +select min(a3) from t1 where a2 = 2 and a3 >= 'SEA' and a3 = 'MIN'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +select min(a3) from t1 where a2 = 2 and a3 >= 'SEA' and a3 = 'MIN'; +min(a3) +NULL +explain +select min(t1.a1), min(t2.a4) from t1,t2 where t1.a1 < 'KKK' and t2.a4 < 'KKK'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(t1.a1), min(t2.a4) from t1,t2 where t1.a1 < 'KKK' and t2.a4 < 'KKK'; +min(t1.a1) min(t2.a4) +AME AME +explain +select min(a1) from t1 where a1 > 'KKK' or a1 < 'XXX'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 0 NULL 1 Using where; Using index +explain +select min(a1) from t1 where a1 != 'KKK'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 3 NULL 15 Using where; Using index +explain +select max(a3) from t1 where a2 < 2 and a3 < 'SEA'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range k1 k1 3 NULL 1 Using where; Using index +explain +select max(t1.a3), min(t2.a2) from t1, t2 where t1.a2 = 2 and t1.a3 < 'MIN' and t2.a3 > 'CA'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range k1 k1 3 NULL 1 Using where; Using index +1 SIMPLE t1 range k1 k1 7 NULL 1 Using where; Using index; Using join buffer +explain +select min(a4 - 0.01) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL k2 12 NULL 15 Using index +explain +select max(a4 + 0.01) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL k2 12 NULL 15 Using index +explain +select min(a3) from t1 where (a2 +1 ) is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL k1 7 NULL 15 Using where; Using index +explain +select min(a3) from t1 where (a2 + 1) = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL k1 7 NULL 15 Using where; Using index +explain +select min(a3) from t1 where 2 = (a2 + 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL k1 7 NULL 15 Using where; Using index +explain +select min(a2) from t1 where a2 < 2 * a2 - 8; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL k1 7 NULL 15 Using where; Using index +explain +select min(a1) from t1 where a1 between a3 and 'KKK'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 15 Using where +explain +select min(a4) from t1 where (a4 + 0.01) between 0.07 and 0.08; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL k2 12 NULL 15 Using where; Using index +explain +select concat(min(t1.a1),min(t2.a4)) from t1, t2 where t2.a4 <> 'AME'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index k2 k2 4 NULL 7 Using where; Using index +1 SIMPLE t1 index NULL PRIMARY 3 NULL 15 Using index; Using join buffer +drop table t1, t2; +create table t1 (a char(10)); +insert into t1 values ('a'),('b'),('c'); +select coercibility(max(a)) from t1; +coercibility(max(a)) +2 +drop table t1; +create table t1 (a char character set latin2); +insert into t1 values ('a'),('b'); +select charset(max(a)), coercibility(max(a)), +charset(min(a)), coercibility(min(a)) from t1; +charset(max(a)) coercibility(max(a)) charset(min(a)) coercibility(min(a)) +latin2 2 latin2 2 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(1) CHARACTER SET latin2 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +create table t2 select max(a),min(a) from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `max(a)` char(1) CHARACTER SET latin2 DEFAULT NULL, + `min(a)` char(1) CHARACTER SET latin2 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t2; +create table t2 select concat(a) from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `concat(a)` varchar(1) CHARACTER SET latin2 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t2,t1; +create table t1 (a int); +insert into t1 values (1); +select max(a) as b from t1 having b=1; +b +1 +select a from t1 having a=1; +a +1 +drop table t1; +create table t1 (a int); +select variance(2) from t1; +variance(2) +NULL +select stddev(2) from t1; +stddev(2) +NULL +drop table t1; +create table t1 (a int); +insert into t1 values (1),(2); +prepare stmt1 from 'SELECT COUNT(*) FROM t1'; +execute stmt1; +COUNT(*) +2 +execute stmt1; +COUNT(*) +2 +execute stmt1; +COUNT(*) +2 +deallocate prepare stmt1; +drop table t1; +create table t1 (a int, primary key(a)); +insert into t1 values (1),(2); +prepare stmt1 from 'SELECT max(a) FROM t1'; +execute stmt1; +max(a) +2 +execute stmt1; +max(a) +2 +execute stmt1; +max(a) +2 +deallocate prepare stmt1; +drop table t1; +CREATE TABLE t1 (a int primary key); +INSERT INTO t1 VALUES (1),(2),(3),(4); +SELECT MAX(a) FROM t1 WHERE a > 5; +MAX(a) +NULL +SELECT MIN(a) FROM t1 WHERE a < 0; +MIN(a) +NULL +DROP TABLE t1; +CREATE TABLE t1 ( +id int(10) unsigned NOT NULL auto_increment, +val enum('one','two','three') NOT NULL default 'one', +PRIMARY KEY (id) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES +(1,'one'),(2,'two'),(3,'three'),(4,'one'),(5,'two'); +select val, count(*) from t1 group by val; +val count(*) +one 2 +two 2 +three 1 +drop table t1; +CREATE TABLE t1 ( +id int(10) unsigned NOT NULL auto_increment, +val set('one','two','three') NOT NULL default 'one', +PRIMARY KEY (id) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES +(1,'one'),(2,'two'),(3,'three'),(4,'one'),(5,'two'); +select val, count(*) from t1 group by val; +val count(*) +one 2 +two 2 +three 1 +drop table t1; +create table t1(a int, b datetime); +insert into t1 values (1, NOW()), (2, NOW()); +create table t2 select MAX(b) from t1 group by a; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `MAX(b)` datetime DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1, t2; +create table t1(f1 datetime); +insert into t1 values (now()); +create table t2 select f2 from (select max(now()) f2 from t1) a; +show columns from t2; +Field Type Null Key Default Extra +f2 datetime YES NULL +drop table t2; +create table t2 select f2 from (select now() f2 from t1) a; +show columns from t2; +Field Type Null Key Default Extra +f2 datetime NO 0000-00-00 00:00:00 +drop table t2, t1; +CREATE TABLE t1( +id int PRIMARY KEY, +a int, +b int, +INDEX i_b_id(a,b,id), +INDEX i_id(a,id) +); +INSERT INTO t1 VALUES +(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); +SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; +MAX(id) +NULL +DROP TABLE t1; +CREATE TABLE t1( +id int PRIMARY KEY, +a int, +b int, +INDEX i_id(a,id), +INDEX i_b_id(a,b,id) +); +INSERT INTO t1 VALUES +(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); +SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; +MAX(id) +NULL +DROP TABLE t1; +CREATE TABLE t1 (id int PRIMARY KEY, b char(3), INDEX(b)); +INSERT INTO t1 VALUES (1,'xx'), (2,'aa'); +SELECT * FROM t1; +id b +1 xx +2 aa +SELECT MAX(b) FROM t1 WHERE b < 'ppppp'; +MAX(b) +aa +SHOW WARNINGS; +Level Code Message +SELECT MAX(b) FROM t1 WHERE b < 'pp'; +MAX(b) +aa +DROP TABLE t1; +CREATE TABLE t1 (id int PRIMARY KEY, b char(16), INDEX(b(4))); +INSERT INTO t1 VALUES (1, 'xxxxbbbb'), (2, 'xxxxaaaa'); +SELECT MAX(b) FROM t1; +MAX(b) +xxxxbbbb +EXPLAIN SELECT MAX(b) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +DROP TABLE t1; +CREATE TABLE t1 (id int , b varchar(512), INDEX(b(250))) COLLATE latin1_bin; +INSERT INTO t1 VALUES +(1,CONCAT(REPEAT('_', 250), "qq")), (1,CONCAT(REPEAT('_', 250), "zz")), +(1,CONCAT(REPEAT('_', 250), "aa")), (1,CONCAT(REPEAT('_', 250), "ff")); +SELECT MAX(b) FROM t1; +MAX(b) +__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________zz +EXPLAIN SELECT MAX(b) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,1),(1,2),(2,3); +SELECT (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a; +(SELECT COUNT(DISTINCT t1.b)) +2 +1 +SELECT (SELECT COUNT(DISTINCT 12)) FROM t1 GROUP BY t1.a; +(SELECT COUNT(DISTINCT 12)) +1 +1 +SELECT AVG(2), BIT_AND(2), BIT_OR(2), BIT_XOR(2), COUNT(*), COUNT(12), +COUNT(DISTINCT 12), MIN(2),MAX(2),STD(2), VARIANCE(2),SUM(2), +GROUP_CONCAT(2),GROUP_CONCAT(DISTINCT 2); +AVG(2) BIT_AND(2) BIT_OR(2) BIT_XOR(2) COUNT(*) COUNT(12) COUNT(DISTINCT 12) MIN(2) MAX(2) STD(2) VARIANCE(2) SUM(2) GROUP_CONCAT(2) GROUP_CONCAT(DISTINCT 2) +2.00000 2 2 2 1 1 1 2 2 0.00000 0.00000 2 2 2 +DROP TABLE t1; +create table t2 (ff double); +insert into t2 values (2.2); +select cast(sum(distinct ff) as decimal(5,2)) from t2; +cast(sum(distinct ff) as decimal(5,2)) +2.20 +select cast(sum(distinct ff) as signed) from t2; +cast(sum(distinct ff) as signed) +2 +select cast(variance(ff) as decimal(10,3)) from t2; +cast(variance(ff) as decimal(10,3)) +0.000 +select cast(min(ff) as decimal(5,2)) from t2; +cast(min(ff) as decimal(5,2)) +2.20 +create table t1 (df decimal(5,1)); +insert into t1 values(1.1); +insert into t1 values(2.2); +select cast(sum(distinct df) as signed) from t1; +cast(sum(distinct df) as signed) +3 +select cast(min(df) as signed) from t1; +cast(min(df) as signed) +0 +select 1e8 * sum(distinct df) from t1; +1e8 * sum(distinct df) +330000000 +select 1e8 * min(df) from t1; +1e8 * min(df) +110000000 +create table t3 (ifl int); +insert into t3 values(1), (2); +select cast(min(ifl) as decimal(5,2)) from t3; +cast(min(ifl) as decimal(5,2)) +1.00 +drop table t1, t2, t3; +CREATE TABLE t1 (id int(11),value1 float(10,2)); +INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00), (2,13.00); +select id, stddev_pop(value1), var_pop(value1), stddev_samp(value1), var_samp(value1) from t1 group by id; +id stddev_pop(value1) var_pop(value1) stddev_samp(value1) var_samp(value1) +1 0.816497 0.666667 1.000000 1.000000 +2 1.118034 1.250000 1.290994 1.666667 +DROP TABLE t1; +CREATE TABLE t1 (col1 decimal(16,12)); +INSERT INTO t1 VALUES (-5.00000000001),(-5.00000000002),(-5.00000000003),(-5.00000000000),(-5.00000000001),(-5.00000000002); +insert into t1 select * from t1; +select col1,count(col1),sum(col1),avg(col1) from t1 group by col1; +col1 count(col1) sum(col1) avg(col1) +-5.000000000030 2 -10.000000000060 -5.00000000003000000 +-5.000000000020 4 -20.000000000080 -5.00000000002000000 +-5.000000000010 4 -20.000000000040 -5.00000000001000000 +-5.000000000000 2 -10.000000000000 -5.00000000000000000 +DROP TABLE t1; +create table t1 (col1 decimal(16,12)); +insert into t1 values (-5.00000000001); +insert into t1 values (-5.00000000001); +select col1,sum(col1),max(col1),min(col1) from t1 group by col1; +col1 sum(col1) max(col1) min(col1) +-5.000000000010 -10.000000000020 -5.000000000010 -5.000000000010 +delete from t1; +insert into t1 values (5.00000000001); +insert into t1 values (5.00000000001); +select col1,sum(col1),max(col1),min(col1) from t1 group by col1; +col1 sum(col1) max(col1) min(col1) +5.000000000010 10.000000000020 5.000000000010 5.000000000010 +DROP TABLE t1; +CREATE TABLE t1 (a VARCHAR(400)); +INSERT INTO t1 (a) VALUES ("A"), ("a"), ("a "), ("a "), +("B"), ("b"), ("b "), ("b "); +SELECT COUNT(DISTINCT a) FROM t1; +COUNT(DISTINCT a) +2 +DROP TABLE t1; +CREATE TABLE t1 (a int, b int, c int); +INSERT INTO t1 (a, b, c) VALUES +(1,1,1), (1,1,2), (1,1,3), +(1,2,1), (1,2,2), (1,2,3), +(1,3,1), (1,3,2), (1,3,3), +(2,1,1), (2,1,2), (2,1,3), +(2,2,1), (2,2,2), (2,2,3), +(2,3,1), (2,3,2), (2,3,3), +(3,1,1), (3,1,2), (3,1,3), +(3,2,1), (3,2,2), (3,2,3), +(3,3,1), (3,3,2), (3,3,3); +SELECT b/c as v, a FROM t1 ORDER BY v, a; +v a +0.33333 1 +0.33333 2 +0.33333 3 +0.50000 1 +0.50000 2 +0.50000 3 +0.66667 1 +0.66667 2 +0.66667 3 +1.00000 1 +1.00000 1 +1.00000 1 +1.00000 2 +1.00000 2 +1.00000 2 +1.00000 3 +1.00000 3 +1.00000 3 +1.50000 1 +1.50000 2 +1.50000 3 +2.00000 1 +2.00000 2 +2.00000 3 +3.00000 1 +3.00000 2 +3.00000 3 +SELECT b/c as v, SUM(a) FROM t1 GROUP BY v; +v SUM(a) +0.33333 6 +0.50000 6 +0.66667 6 +1.00000 18 +1.50000 6 +2.00000 6 +3.00000 6 +SELECT SUM(a) FROM t1 GROUP BY b/c; +SUM(a) +6 +6 +6 +18 +6 +6 +6 +DROP TABLE t1; +set div_precision_increment= @sav_dpi; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); +CREATE TABLE t2 (a INT PRIMARY KEY, b INT); +INSERT INTO t2 VALUES (1,1), (3,3); +SELECT SQL_NO_CACHE +(SELECT SUM(c.a) FROM t1 ttt, t2 ccc +WHERE ttt.a = ccc.b AND ttt.a = t.a GROUP BY ttt.a) AS minid +FROM t1 t, t2 c WHERE t.a = c.b; +minid +1 +DROP TABLE t1,t2; +create table t1 select variance(0); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `variance(0)` double(8,4) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select stddev(0); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `stddev(0)` double(8,4) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table bug22555 (i smallint primary key auto_increment, s1 smallint, s2 smallint, e decimal(30,10), o double); +insert into bug22555 (s1, s2, e, o) values (53, 78, 11.4276528, 6.828112), (17, 78, 5.916793, 1.8502951), (18, 76, 2.679231, 9.17975591), (31, 62, 6.07831, 0.1), (19, 41, 5.37463, 15.1), (83, 73, 14.567426, 7.959222), (92, 53, 6.10151, 13.1856852), (7, 12, 13.92272, 3.442007), (92, 35, 11.95358909, 6.01376678), (38, 84, 2.572, 7.904571); +select std(s1/s2) from bug22555 group by i; +std(s1/s2) +0.00000000 +0.00000000 +0.00000000 +0.00000000 +0.00000000 +0.00000000 +0.00000000 +0.00000000 +0.00000000 +0.00000000 +select std(e) from bug22555 group by i; +std(e) +0.00000000000000 +0.00000000000000 +0.00000000000000 +0.00000000000000 +0.00000000000000 +0.00000000000000 +0.00000000000000 +0.00000000000000 +0.00000000000000 +0.00000000000000 +select std(o) from bug22555 group by i; +std(o) +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +drop table bug22555; +create table bug22555 (i smallint, s1 smallint, s2 smallint, o1 double, o2 double, e1 decimal, e2 decimal); +insert into bug22555 values (1,53,78,53,78,53,78),(2,17,78,17,78,17,78),(3,18,76,18,76,18,76); +select i, count(*) from bug22555 group by i; +i count(*) +1 1 +2 1 +3 1 +select std(s1/s2) from bug22555 where i=1; +std(s1/s2) +0.00000000 +select std(s1/s2) from bug22555 where i=2; +std(s1/s2) +0.00000000 +select std(s1/s2) from bug22555 where i=3; +std(s1/s2) +0.00000000 +select std(s1/s2) from bug22555 where i=1 group by i; +std(s1/s2) +0.00000000 +select std(s1/s2) from bug22555 where i=2 group by i; +std(s1/s2) +0.00000000 +select std(s1/s2) from bug22555 where i=3 group by i; +std(s1/s2) +0.00000000 +select std(s1/s2) from bug22555 group by i order by i; +std(s1/s2) +0.00000000 +0.00000000 +0.00000000 +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +i count(*) std(o1/o2) +1 1 0 +2 1 0 +3 1 0 +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +i count(*) std(e1/e2) +1 1 0.00000000 +2 1 0.00000000 +3 1 0.00000000 +set @saved_div_precision_increment=@@div_precision_increment; +set div_precision_increment=19; +select i, count(*), variance(s1/s2) from bug22555 group by i order by i; +i count(*) variance(s1/s2) +1 1 0.000000000000000000000000000000 +2 1 0.000000000000000000000000000000 +3 1 0.000000000000000000000000000000 +select i, count(*), variance(o1/o2) from bug22555 group by i order by i; +i count(*) variance(o1/o2) +1 1 0 +2 1 0 +3 1 0 +select i, count(*), variance(e1/e2) from bug22555 group by i order by i; +i count(*) variance(e1/e2) +1 1 0.000000000000000000000000000000 +2 1 0.000000000000000000000000000000 +3 1 0.000000000000000000000000000000 +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +i count(*) std(s1/s2) +1 1 0.000000000000000000000000000000 +2 1 0.000000000000000000000000000000 +3 1 0.000000000000000000000000000000 +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +i count(*) std(o1/o2) +1 1 0 +2 1 0 +3 1 0 +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +i count(*) std(e1/e2) +1 1 0.000000000000000000000000000000 +2 1 0.000000000000000000000000000000 +3 1 0.000000000000000000000000000000 +set div_precision_increment=20; +select i, count(*), variance(s1/s2) from bug22555 group by i order by i; +i count(*) variance(s1/s2) +1 1 0.000000000000000000000000000000 +2 1 0.000000000000000000000000000000 +3 1 0.000000000000000000000000000000 +select i, count(*), variance(o1/o2) from bug22555 group by i order by i; +i count(*) variance(o1/o2) +1 1 0 +2 1 0 +3 1 0 +select i, count(*), variance(e1/e2) from bug22555 group by i order by i; +i count(*) variance(e1/e2) +1 1 0.000000000000000000000000000000 +2 1 0.000000000000000000000000000000 +3 1 0.000000000000000000000000000000 +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +i count(*) std(s1/s2) +1 1 0.000000000000000000000000000000 +2 1 0.000000000000000000000000000000 +3 1 0.000000000000000000000000000000 +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +i count(*) std(o1/o2) +1 1 0 +2 1 0 +3 1 0 +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +i count(*) std(e1/e2) +1 1 0.000000000000000000000000000000 +2 1 0.000000000000000000000000000000 +3 1 0.000000000000000000000000000000 +set @@div_precision_increment=@saved_div_precision_increment; +insert into bug22555 values (1,53,78,53,78,53,78),(2,17,78,17,78,17,78),(3,18,76,18,76,18,76); +insert into bug22555 values (1,53,78,53,78,53,78),(2,17,78,17,78,17,78),(3,18,76,18,76,18,76); +insert into bug22555 values (1,53,78,53,78,53,78),(2,17,78,17,78,17,78),(3,18,76,18,76,18,76); +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +i count(*) std(s1/s2) +1 4 0.00000000 +2 4 0.00000000 +3 4 0.00000000 +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +i count(*) std(o1/o2) +1 4 0 +2 4 0 +3 4 0 +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +i count(*) std(e1/e2) +1 4 0.00000000 +2 4 0.00000000 +3 4 0.00000000 +select std(s1/s2) from bug22555; +std(s1/s2) +0.21325764 +select std(o1/o2) from bug22555; +std(o1/o2) +0.21325763586649 +select std(e1/e2) from bug22555; +std(e1/e2) +0.21325764 +set @saved_div_precision_increment=@@div_precision_increment; +set div_precision_increment=19; +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +i count(*) std(s1/s2) +1 4 0.000000000000000000000000000000 +2 4 0.000000000000000000000000000000 +3 4 0.000000000000000000000000000000 +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +i count(*) std(o1/o2) +1 4 0 +2 4 0 +3 4 0 +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +i count(*) std(e1/e2) +1 4 0.000000000000000000000000000000 +2 4 0.000000000000000000000000000000 +3 4 0.000000000000000000000000000000 +select round(std(s1/s2), 17) from bug22555; +round(std(s1/s2), 17) +0.21325763586649341 +select std(o1/o2) from bug22555; +std(o1/o2) +0.21325763586649 +select round(std(e1/e2), 17) from bug22555; +round(std(e1/e2), 17) +0.21325763586649341 +set div_precision_increment=20; +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +i count(*) std(s1/s2) +1 4 0.000000000000000000000000000000 +2 4 0.000000000000000000000000000000 +3 4 0.000000000000000000000000000000 +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +i count(*) std(o1/o2) +1 4 0 +2 4 0 +3 4 0 +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +i count(*) std(e1/e2) +1 4 0.000000000000000000000000000000 +2 4 0.000000000000000000000000000000 +3 4 0.000000000000000000000000000000 +select round(std(s1/s2), 17) from bug22555; +round(std(s1/s2), 17) +0.21325763586649341 +select std(o1/o2) from bug22555; +std(o1/o2) +0.21325763586649 +select round(std(e1/e2), 17) from bug22555; +round(std(e1/e2), 17) +0.21325763586649341 +set @@div_precision_increment=@saved_div_precision_increment; +drop table bug22555; +create table bug22555 (s smallint, o double, e decimal); +insert into bug22555 values (1,1,1),(2,2,2),(3,3,3),(6,6,6),(7,7,7); +select var_samp(s), var_pop(s) from bug22555; +var_samp(s) var_pop(s) +6.7000 5.3600 +select var_samp(o), var_pop(o) from bug22555; +var_samp(o) var_pop(o) +6.7 5.36 +select var_samp(e), var_pop(e) from bug22555; +var_samp(e) var_pop(e) +6.7000 5.3600 +drop table bug22555; +create table bug22555 (s smallint, o double, e decimal); +insert into bug22555 values (null,null,null),(null,null,null); +select var_samp(s) as 'null', var_pop(s) as 'null' from bug22555; +null null +NULL NULL +select var_samp(o) as 'null', var_pop(o) as 'null' from bug22555; +null null +NULL NULL +select var_samp(e) as 'null', var_pop(e) as 'null' from bug22555; +null null +NULL NULL +insert into bug22555 values (1,1,1); +select var_samp(s) as 'null', var_pop(s) as '0' from bug22555; +null 0 +NULL 0.0000 +select var_samp(o) as 'null', var_pop(o) as '0' from bug22555; +null 0 +NULL 0 +select var_samp(e) as 'null', var_pop(e) as '0' from bug22555; +null 0 +NULL 0.0000 +insert into bug22555 values (2,2,2); +select var_samp(s) as '0.5', var_pop(s) as '0.25' from bug22555; +0.5 0.25 +0.5000 0.2500 +select var_samp(o) as '0.5', var_pop(o) as '0.25' from bug22555; +0.5 0.25 +0.5 0.25 +select var_samp(e) as '0.5', var_pop(e) as '0.25' from bug22555; +0.5 0.25 +0.5000 0.2500 +drop table bug22555; +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8); +INSERT INTO t1 SELECT a, b+8 FROM t1; +INSERT INTO t1 SELECT a, b+16 FROM t1; +INSERT INTO t1 SELECT a, b+32 FROM t1; +INSERT INTO t1 SELECT a, b+64 FROM t1; +INSERT INTO t1 SELECT a, b+128 FROM t1; +INSERT INTO t1 SELECT a, b+256 FROM t1; +INSERT INTO t1 SELECT a, b+512 FROM t1; +INSERT INTO t1 SELECT a, b+1024 FROM t1; +INSERT INTO t1 SELECT a, b+2048 FROM t1; +INSERT INTO t1 SELECT a, b+4096 FROM t1; +INSERT INTO t1 SELECT a, b+8192 FROM t1; +INSERT INTO t1 SELECT a, b+16384 FROM t1; +INSERT INTO t1 SELECT a, b+32768 FROM t1; +SELECT a,COUNT(DISTINCT b) AS cnt FROM t1 GROUP BY a HAVING cnt > 50; +a cnt +1 65536 +SELECT a,SUM(DISTINCT b) AS sumation FROM t1 GROUP BY a HAVING sumation > 50; +a sumation +1 2147516416 +SELECT a,AVG(DISTINCT b) AS average FROM t1 GROUP BY a HAVING average > 50; +a average +1 32768.5000 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/func_if.result b/mysql-test/suite/pbxt/r/func_if.result new file mode 100644 index 00000000000..e1879daf662 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_if.result @@ -0,0 +1,130 @@ +drop table if exists t1; +select IF(0,"ERROR","this"),IF(1,"is","ERROR"),IF(NULL,"ERROR","a"),IF(1,2,3)|0,IF(1,2.0,3.0)+0 ; +IF(0,"ERROR","this") IF(1,"is","ERROR") IF(NULL,"ERROR","a") IF(1,2,3)|0 IF(1,2.0,3.0)+0 +this is a 2 2.0 +CREATE TABLE t1 (st varchar(255) NOT NULL, u int(11) NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('a',1),('A',1),('aa',1),('AA',1),('a',1),('aaa',0),('BBB',0); +select if(1,st,st) s from t1 order by s; +s +a +A +a +aa +AA +aaa +BBB +select if(u=1,st,st) s from t1 order by s; +s +a +A +a +aa +AA +aaa +BBB +select if(u=1,binary st,st) s from t1 order by s; +s +A +AA +BBB +a +a +aa +aaa +select if(u=1,st,binary st) s from t1 where st like "%a%" order by s; +s +A +AA +a +a +aa +aaa +explain extended select if(u=1,st,binary st) s from t1 where st like "%a%" order by s; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00 Using where; Using filesort +Warnings: +Note 1003 select if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,cast(`test`.`t1`.`st` as char charset binary)) AS `s` from `test`.`t1` where (`test`.`t1`.`st` like '%a%') order by if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,cast(`test`.`t1`.`st` as char charset binary)) +select nullif(u, 1) from t1; +nullif(u, 1) +NULL +NULL +NULL +NULL +NULL +0 +0 +explain extended select nullif(u, 1) from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00 +Warnings: +Note 1003 select nullif(`test`.`t1`.`u`,1) AS `nullif(u, 1)` from `test`.`t1` +drop table t1; +select nullif(1,'test'); +nullif(1,'test') +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'test' +select NULLIF(NULL,NULL), NULLIF(NULL,1), NULLIF(NULL,1.0), NULLIF(NULL,"test"); +NULLIF(NULL,NULL) NULLIF(NULL,1) NULLIF(NULL,1.0) NULLIF(NULL,"test") +NULL NULL NULL NULL +select NULLIF(1,NULL), NULLIF(1.0, NULL), NULLIF("test", NULL); +NULLIF(1,NULL) NULLIF(1.0, NULL) NULLIF("test", NULL) +1 1.0 test +create table t1 (num double(12,2)); +insert into t1 values (144.54); +select sum(if(num is null,0.00,num)) from t1; +sum(if(num is null,0.00,num)) +144.54 +drop table t1; +create table t1 (x int, y int); +insert into t1 values (0,6),(10,16),(20,26),(30,10),(40,46),(50,56); +select min(if(y -x > 5,y,NULL)), max(if(y - x > 5,y,NULL)) from t1; +min(if(y -x > 5,y,NULL)) max(if(y - x > 5,y,NULL)) +6 56 +drop table t1; +create table t1 (a int); +insert t1 values (1),(2); +select if(1>2,a,avg(a)) from t1; +if(1>2,a,avg(a)) +1.5000 +drop table t1; +SELECT NULLIF(5,5) IS NULL, NULLIF(5,5) IS NOT NULL; +NULLIF(5,5) IS NULL NULLIF(5,5) IS NOT NULL +1 0 +CREATE TABLE `t1` ( +`id` int(11) NOT NULL , +`date` int(10) default NULL, +`text` varchar(32) NOT NULL +); +INSERT INTO t1 VALUES (1,1110000000,'Day 1'),(2,1111000000,'Day 2'),(3,1112000000,'Day 3'); +SELECT id, IF(date IS NULL, '-', FROM_UNIXTIME(date, '%d-%m-%Y')) AS date_ord, text FROM t1 ORDER BY date_ord ASC; +id date_ord text +1 05-03-2005 Day 1 +2 16-03-2005 Day 2 +3 28-03-2005 Day 3 +SELECT id, IF(date IS NULL, '-', FROM_UNIXTIME(date, '%d-%m-%Y')) AS date_ord, text FROM t1 ORDER BY date_ord DESC; +id date_ord text +3 28-03-2005 Day 3 +2 16-03-2005 Day 2 +1 05-03-2005 Day 1 +DROP TABLE t1; +CREATE TABLE t1 (a CHAR(10)); +INSERT INTO t1 VALUES ('aaa'), (NULL), (''), ('bbb'); +SELECT a, NULLIF(a,'') FROM t1; +a NULLIF(a,'') +aaa aaa +NULL NULL + NULL +bbb bbb +SELECT a, NULLIF(a,'') FROM t1 WHERE NULLIF(a,'') IS NULL; +a NULLIF(a,'') +NULL NULL + NULL +DROP TABLE t1; +create table t1 (f1 int, f2 int); +insert into t1 values(1,1),(0,0); +select f1, f2, if(f1, 40.0, 5.00) from t1 group by f1 order by f2; +f1 f2 if(f1, 40.0, 5.00) +0 0 5.00 +1 1 40.00 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/func_in.result b/mysql-test/suite/pbxt/r/func_in.result new file mode 100644 index 00000000000..167f75240a7 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_in.result @@ -0,0 +1,442 @@ +drop table if exists t1, t2; +select 1 in (1,2,3); +1 in (1,2,3) +1 +select 10 in (1,2,3); +10 in (1,2,3) +0 +select NULL in (1,2,3); +NULL in (1,2,3) +NULL +select 1 in (1,NULL,3); +1 in (1,NULL,3) +1 +select 3 in (1,NULL,3); +3 in (1,NULL,3) +1 +select 10 in (1,NULL,3); +10 in (1,NULL,3) +NULL +select 1.5 in (1.5,2.5,3.5); +1.5 in (1.5,2.5,3.5) +1 +select 10.5 in (1.5,2.5,3.5); +10.5 in (1.5,2.5,3.5) +0 +select NULL in (1.5,2.5,3.5); +NULL in (1.5,2.5,3.5) +NULL +select 1.5 in (1.5,NULL,3.5); +1.5 in (1.5,NULL,3.5) +1 +select 3.5 in (1.5,NULL,3.5); +3.5 in (1.5,NULL,3.5) +1 +select 10.5 in (1.5,NULL,3.5); +10.5 in (1.5,NULL,3.5) +NULL +CREATE TABLE t1 (a int, b int, c int); +insert into t1 values (1,2,3), (1,NULL,3); +select 1 in (a,b,c) from t1; +1 in (a,b,c) +1 +1 +select 3 in (a,b,c) from t1; +3 in (a,b,c) +1 +1 +select 10 in (a,b,c) from t1; +10 in (a,b,c) +0 +NULL +select NULL in (a,b,c) from t1; +NULL in (a,b,c) +NULL +NULL +drop table t1; +CREATE TABLE t1 (a float, b float, c float); +insert into t1 values (1.5,2.5,3.5), (1.5,NULL,3.5); +select 1.5 in (a,b,c) from t1; +1.5 in (a,b,c) +1 +1 +select 3.5 in (a,b,c) from t1; +3.5 in (a,b,c) +1 +1 +select 10.5 in (a,b,c) from t1; +10.5 in (a,b,c) +0 +NULL +drop table t1; +CREATE TABLE t1 (a varchar(10), b varchar(10), c varchar(10)); +insert into t1 values ('A','BC','EFD'), ('A',NULL,'EFD'); +select 'A' in (a,b,c) from t1; +'A' in (a,b,c) +1 +1 +select 'EFD' in (a,b,c) from t1; +'EFD' in (a,b,c) +1 +1 +select 'XSFGGHF' in (a,b,c) from t1; +'XSFGGHF' in (a,b,c) +0 +NULL +drop table t1; +CREATE TABLE t1 (field char(1)); +INSERT INTO t1 VALUES ('A'),(NULL); +SELECT * from t1 WHERE field IN (NULL); +field +SELECT * from t1 WHERE field NOT IN (NULL); +field +SELECT * from t1 where field = field; +field +A +SELECT * from t1 where field <=> field; +field +A +NULL +DELETE FROM t1 WHERE field NOT IN (NULL); +SELECT * FROM t1; +field +A +NULL +drop table t1; +create table t1 (id int(10) primary key); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9); +select * from t1 where id in (2,5,9); +id +2 +5 +9 +drop table t1; +create table t1 ( +a char(1) character set latin1 collate latin1_general_ci, +b char(1) character set latin1 collate latin1_swedish_ci, +c char(1) character set latin1 collate latin1_danish_ci +); +insert into t1 values ('A','B','C'); +insert into t1 values ('a','c','c'); +select * from t1 where a in (b); +ERROR HY000: Illegal mix of collations (latin1_general_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '=' +select * from t1 where a in (b,c); +ERROR HY000: Illegal mix of collations (latin1_general_ci,IMPLICIT), (latin1_swedish_ci,IMPLICIT), (latin1_danish_ci,IMPLICIT) for operation ' IN ' +select * from t1 where 'a' in (a,b,c); +ERROR HY000: Illegal mix of collations for operation ' IN ' +select * from t1 where 'a' in (a); +a b c +A B C +a c c +select * from t1 where a in ('a'); +a b c +A B C +a c c +select * from t1 where 'a' collate latin1_general_ci in (a,b,c); +a b c +A B C +a c c +select * from t1 where 'a' collate latin1_bin in (a,b,c); +a b c +a c c +select * from t1 where 'a' in (a,b,c collate latin1_bin); +a b c +a c c +explain extended select * from t1 where 'a' in (a,b,c collate latin1_bin); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where ('a' in (`test`.`t1`.`a`,`test`.`t1`.`b`,(`test`.`t1`.`c` collate latin1_bin))) +drop table t1; +set names utf8; +create table t1 (a char(10) character set utf8 not null); +insert into t1 values ('bbbb'),(_koi8r'ÃÃÃÃ'),(_latin1'ÄÄÄÄ'); +select a from t1 where a in ('bbbb',_koi8r'ÃÃÃÃ',_latin1'ÄÄÄÄ') order by a; +a +ÄÄÄÄ +bbbb +цццц +drop table t1; +create table t1 (a char(10) character set latin1 not null); +insert into t1 values ('a'),('b'),('c'); +select a from t1 where a IN ('a','b','c') order by a; +a +a +b +c +drop table t1; +set names latin1; +select '1.0' in (1,2); +'1.0' in (1,2) +1 +select 1 in ('1.0',2); +1 in ('1.0',2) +1 +select 1 in (1,'2.0'); +1 in (1,'2.0') +1 +select 1 in ('1.0',2.0); +1 in ('1.0',2.0) +1 +select 1 in (1.0,'2.0'); +1 in (1.0,'2.0') +1 +select 1 in ('1.1',2); +1 in ('1.1',2) +0 +select 1 in ('1.1',2.0); +1 in ('1.1',2.0) +0 +create table t1 (a char(2) character set binary); +insert into t1 values ('aa'), ('bb'); +select * from t1 where a in (NULL, 'aa'); +a +aa +drop table t1; +create table t1 (id int, key(id)); +insert into t1 values (1),(2),(3); +select count(*) from t1 where id not in (1); +count(*) +2 +select count(*) from t1 where id not in (1,2); +count(*) +1 +drop table t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 SELECT 1 IN (2, NULL); +SELECT should return NULL. +SELECT * FROM t1; +1 IN (2, NULL) +NULL +DROP TABLE t1; +End of 4.1 tests +CREATE TABLE t1 (a int PRIMARY KEY); +INSERT INTO t1 VALUES (44), (45), (46); +SELECT * FROM t1 WHERE a IN (45); +a +45 +SELECT * FROM t1 WHERE a NOT IN (0, 45); +a +44 +46 +SELECT * FROM t1 WHERE a NOT IN (45); +a +44 +46 +CREATE VIEW v1 AS SELECT * FROM t1 WHERE a NOT IN (45); +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` where (`t1`.`a` <> 45) latin1 latin1_swedish_ci +SELECT * FROM v1; +a +44 +46 +DROP VIEW v1; +DROP TABLE t1; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, filler char(200), key(a)); +insert into t2 select C.a*2, 'no' from t1 A, t1 B, t1 C; +insert into t2 select C.a*2+1, 'yes' from t1 C; +explain +select * from t2 where a NOT IN (0, 2,4,6,8,10,12,14,16,18); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 5 NULL 11 Using where +select * from t2 where a NOT IN (0, 2,4,6,8,10,12,14,16,18); +a filler +1 yes +3 yes +5 yes +7 yes +9 yes +11 yes +13 yes +15 yes +17 yes +19 yes +explain select * from t2 force index(a) where a NOT IN (2,2,2,2,2,2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 5 NULL # Using where +explain select * from t2 force index(a) where a <> 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 5 NULL # Using where +drop table t2; +create table t2 (a datetime, filler char(200), key(a)); +insert into t2 select '2006-04-25 10:00:00' + interval C.a minute, +'no' from t1 A, t1 B, t1 C where C.a % 2 = 0; +insert into t2 select '2006-04-25 10:00:00' + interval C.a*2+1 minute, +'yes' from t1 C; +explain +select * from t2 where a NOT IN ( +'2006-04-25 10:00:00','2006-04-25 10:02:00','2006-04-25 10:04:00', +'2006-04-25 10:06:00', '2006-04-25 10:08:00'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 9 NULL 6 Using where +select * from t2 where a NOT IN ( +'2006-04-25 10:00:00','2006-04-25 10:02:00','2006-04-25 10:04:00', +'2006-04-25 10:06:00', '2006-04-25 10:08:00'); +a filler +2006-04-25 10:01:00 yes +2006-04-25 10:03:00 yes +2006-04-25 10:05:00 yes +2006-04-25 10:07:00 yes +2006-04-25 10:09:00 yes +2006-04-25 10:11:00 yes +2006-04-25 10:13:00 yes +2006-04-25 10:15:00 yes +2006-04-25 10:17:00 yes +2006-04-25 10:19:00 yes +drop table t2; +create table t2 (a varchar(10), filler char(200), key(a)); +insert into t2 select 'foo', 'no' from t1 A, t1 B; +insert into t2 select 'barbar', 'no' from t1 A, t1 B; +insert into t2 select 'bazbazbaz', 'no' from t1 A, t1 B; +insert into t2 values ('fon', '1'), ('fop','1'), ('barbaq','1'), +('barbas','1'), ('bazbazbay', '1'),('zz','1'); +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +explain select * from t2 where a not in('foo','barbar', 'bazbazbaz'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 13 NULL 4 Using where +drop table t2; +create table t2 (a decimal(10,5), filler char(200), key(a)); +insert into t2 select 345.67890, 'no' from t1 A, t1 B; +insert into t2 select 43245.34, 'no' from t1 A, t1 B; +insert into t2 select 64224.56344, 'no' from t1 A, t1 B; +insert into t2 values (0, '1'), (22334.123,'1'), (33333,'1'), +(55555,'1'), (77777, '1'); +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +explain +select * from t2 where a not in (345.67890, 43245.34, 64224.56344); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 7 NULL 4 Using where +select * from t2 where a not in (345.67890, 43245.34, 64224.56344); +a filler +0.00000 1 +22334.12300 1 +33333.00000 1 +55555.00000 1 +77777.00000 1 +drop table t2; +create table t2 (a int, key(a), b int); +insert into t2 values (1,1),(2,2); +set @cnt= 1; +set @str="update t2 set b=1 where a not in ("; +select count(*) from ( +select @str:=concat(@str, @cnt:=@cnt+1, ",") +from t1 A, t1 B, t1 C, t1 D) Z; +count(*) +10000 +set @str:=concat(@str, "10000)"); +select substr(@str, 1, 50); +substr(@str, 1, 50) +update t2 set b=1 where a not in (2,3,4,5,6,7,8,9, +prepare s from @str; +execute s; +deallocate prepare s; +set @str=NULL; +drop table t2; +drop table t1; +create table t1 ( +some_id smallint(5) unsigned, +key (some_id) +); +insert into t1 values (1),(2); +select some_id from t1 where some_id not in(2,-1); +some_id +1 +select some_id from t1 where some_id not in(-4,-1,-4); +some_id +1 +2 +select some_id from t1 where some_id not in(-4,-1,3423534,2342342); +some_id +1 +2 +select some_id from t1 where some_id not in('-1', '0'); +some_id +1 +2 +drop table t1; +End of 5.0 tests +create table t1(f1 char(1)); +insert into t1 values ('a'),('b'),('1'); +select f1 from t1 where f1 in ('a',1); +f1 +a +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'b' +select f1, case f1 when 'a' then '+' when 1 then '-' end from t1; +f1 case f1 when 'a' then '+' when 1 then '-' end +a + +b NULL +1 - +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'b' +create index t1f1_idx on t1(f1); +select f1 from t1 where f1 in ('a',1); +f1 +1 +a +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'b' +explain select f1 from t1 where f1 in ('a',1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index +select f1 from t1 where f1 in ('a','b'); +f1 +a +b +explain select f1 from t1 where f1 in ('a','b'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index +select f1 from t1 where f1 in (2,1); +f1 +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'b' +explain select f1 from t1 where f1 in (2,1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index +create table t2(f2 int, index t2f2(f2)); +insert into t2 values(0),(1),(2); +select f2 from t2 where f2 in ('a',2); +f2 +0 +2 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'a' +explain select f2 from t2 where f2 in ('a',2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index t2f2 t2f2 5 NULL 3 Using where; Using index +select f2 from t2 where f2 in ('a','b'); +f2 +0 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'b' +explain select f2 from t2 where f2 in ('a','b'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index t2f2 t2f2 5 NULL 3 Using where; Using index +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +Warning 1292 Truncated incorrect DOUBLE value: 'b' +select f2 from t2 where f2 in (1,'b'); +f2 +0 +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'b' +Warning 1292 Truncated incorrect DOUBLE value: 'b' +explain select f2 from t2 where f2 in (1,'b'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index t2f2 t2f2 5 NULL 3 Using where; Using index +drop table t1, t2; +End of 5.1 tests diff --git a/mysql-test/suite/pbxt/r/func_isnull.result b/mysql-test/suite/pbxt/r/func_isnull.result new file mode 100644 index 00000000000..20ddc87ee78 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_isnull.result @@ -0,0 +1,7 @@ +drop table if exists t1; +create table t1 (id int auto_increment primary key not null, mydate date not null); +insert into t1 values (0,"2002-05-01"),(0,"2002-05-01"),(0,"2002-05-01"); +flush tables; +select * from t1 where isnull(to_days(mydate)); +id mydate +drop table t1; diff --git a/mysql-test/suite/pbxt/r/func_like.result b/mysql-test/suite/pbxt/r/func_like.result new file mode 100644 index 00000000000..9338a76e320 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_like.result @@ -0,0 +1,171 @@ +drop table if exists t1; +create table t1 (a varchar(10), key(a)); +insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test"); +explain extended select * from t1 where a like 'abc%'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index a a 13 NULL 5 20.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` like 'abc%') +explain extended select * from t1 where a like concat('abc','%'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index a a 13 NULL 5 20.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` like concat('abc','%')) +select * from t1 where a like "abc%"; +a +abc +abcd +select * from t1 where a like concat("abc","%"); +a +abc +abcd +select * from t1 where a like "ABC%"; +a +abc +abcd +select * from t1 where a like "test%"; +a +test +select * from t1 where a like "te_t"; +a +test +select * from t1 where a like "%a%"; +a +a +abc +abcd +select * from t1 where a like "%abcd%"; +a +abcd +select * from t1 where a like "%abc\d%"; +a +abcd +drop table t1; +create table t1 (a varchar(10), key(a)); +insert into t1 values ('a'), ('a\\b'); +select * from t1 where a like 'a\\%' escape '#'; +a +a\b +select * from t1 where a like 'a\\%' escape '#' and a like 'a\\\\b'; +a +a\b +prepare stmt1 from 'select * from t1 where a like \'a\\%\' escape ?'; +set @esc='#'; +execute stmt1 using @esc; +a +a\b +deallocate prepare stmt1; +drop table t1; +create table t1 (a datetime); +insert into t1 values ('2004-03-11 12:00:21'); +select * from t1 where a like '2004-03-11 12:00:21'; +a +2004-03-11 12:00:21 +drop table t1; +SET NAMES koi8r; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET koi8r); +INSERT INTO t1 VALUES ('ÆÙ×Á'),('æÙ×Á'),('Æù×Á'),('ÆÙ÷Á'),('ÆÙ×á'),('æù÷á'); +INSERT INTO t1 VALUES ('ÆÙ×ÁÐÒÏÌÄÖ'),('æÙ×ÁÐÒÏÌÄÖ'),('Æù×ÁÐÒÏÌÄÖ'),('ÆÙ÷ÁÐÒÏÌÄÖ'); +INSERT INTO t1 VALUES ('ÆÙ×áÐÒÏÌÄÖ'),('ÆÙ×ÁðÒÏÌÄÖ'),('ÆÙ×ÁÐòÏÌÄÖ'),('ÆÙ×ÁÐÒïÌÄÖ'); +INSERT INTO t1 VALUES ('ÆÙ×ÁÐÒÏìÄÖ'),('ÆÙ×ÁÐÒÏÌäÖ'),('ÆÙ×ÁÐÒÏÌÄö'),('æù÷áðòïìäö'); +SELECT * FROM t1 WHERE a LIKE '%Æù×Á%'; +a +ÆÙ×Á +æÙ×Á +Æù×Á +ÆÙ÷Á +ÆÙ×á +æù÷á +ÆÙ×ÁÐÒÏÌÄÖ +æÙ×ÁÐÒÏÌÄÖ +Æù×ÁÐÒÏÌÄÖ +ÆÙ÷ÁÐÒÏÌÄÖ +ÆÙ×áÐÒÏÌÄÖ +ÆÙ×ÁðÒÏÌÄÖ +ÆÙ×ÁÐòÏÌÄÖ +ÆÙ×ÁÐÒïÌÄÖ +ÆÙ×ÁÐÒÏìÄÖ +ÆÙ×ÁÐÒÏÌäÖ +ÆÙ×ÁÐÒÏÌÄö +æù÷áðòïìäö +SELECT * FROM t1 WHERE a LIKE '%Æù×%'; +a +ÆÙ×Á +æÙ×Á +Æù×Á +ÆÙ÷Á +ÆÙ×á +æù÷á +ÆÙ×ÁÐÒÏÌÄÖ +æÙ×ÁÐÒÏÌÄÖ +Æù×ÁÐÒÏÌÄÖ +ÆÙ÷ÁÐÒÏÌÄÖ +ÆÙ×áÐÒÏÌÄÖ +ÆÙ×ÁðÒÏÌÄÖ +ÆÙ×ÁÐòÏÌÄÖ +ÆÙ×ÁÐÒïÌÄÖ +ÆÙ×ÁÐÒÏìÄÖ +ÆÙ×ÁÐÒÏÌäÖ +ÆÙ×ÁÐÒÏÌÄö +æù÷áðòïìäö +SELECT * FROM t1 WHERE a LIKE 'Æù×Á%'; +a +ÆÙ×Á +æÙ×Á +Æù×Á +ÆÙ÷Á +ÆÙ×á +æù÷á +ÆÙ×ÁÐÒÏÌÄÖ +æÙ×ÁÐÒÏÌÄÖ +Æù×ÁÐÒÏÌÄÖ +ÆÙ÷ÁÐÒÏÌÄÖ +ÆÙ×áÐÒÏÌÄÖ +ÆÙ×ÁðÒÏÌÄÖ +ÆÙ×ÁÐòÏÌÄÖ +ÆÙ×ÁÐÒïÌÄÖ +ÆÙ×ÁÐÒÏìÄÖ +ÆÙ×ÁÐÒÏÌäÖ +ÆÙ×ÁÐÒÏÌÄö +æù÷áðòïìäö +DROP TABLE t1; +SET NAMES cp1250; +CREATE TABLE t1 (a varchar(250) NOT NULL) DEFAULT CHARACTER SET=cp1250; +INSERT INTO t1 VALUES +('Techni Tapes Sp. z o.o.'), +('Pojazdy Szynowe PESA Bydgoszcz SA Holding'), +('AKAPESTER 1 P.P.H.U.'), +('Pojazdy Szynowe PESA Bydgoszcz S A Holding'), +('PPUH PESKA-I Maria Struniarska'); +select * from t1 where a like '%PESA%'; +a +Pojazdy Szynowe PESA Bydgoszcz SA Holding +Pojazdy Szynowe PESA Bydgoszcz S A Holding +select * from t1 where a like '%PESA %'; +a +Pojazdy Szynowe PESA Bydgoszcz SA Holding +Pojazdy Szynowe PESA Bydgoszcz S A Holding +select * from t1 where a like '%PES%'; +a +Techni Tapes Sp. z o.o. +Pojazdy Szynowe PESA Bydgoszcz SA Holding +AKAPESTER 1 P.P.H.U. +Pojazdy Szynowe PESA Bydgoszcz S A Holding +PPUH PESKA-I Maria Struniarska +select * from t1 where a like '%PESKA%'; +a +PPUH PESKA-I Maria Struniarska +select * from t1 where a like '%ESKA%'; +a +PPUH PESKA-I Maria Struniarska +DROP TABLE t1; +select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; +_cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin +1 +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; +'andre%' like 'andreÊ%' escape 'Ê' +1 +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; +_cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê' +1 diff --git a/mysql-test/suite/pbxt/r/func_math.result b/mysql-test/suite/pbxt/r/func_math.result new file mode 100644 index 00000000000..d1cdb7cb76e --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_math.result @@ -0,0 +1,287 @@ +drop table if exists t1; +select floor(5.5),floor(-5.5); +floor(5.5) floor(-5.5) +5 -6 +explain extended select floor(5.5),floor(-5.5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select floor(5.5) AS `floor(5.5)`,floor(-(5.5)) AS `floor(-5.5)` +select ceiling(5.5),ceiling(-5.5); +ceiling(5.5) ceiling(-5.5) +6 -5 +explain extended select ceiling(5.5),ceiling(-5.5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select ceiling(5.5) AS `ceiling(5.5)`,ceiling(-(5.5)) AS `ceiling(-5.5)` +select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2), truncate(-52.64,1),truncate(-52.64,-1); +truncate(52.64,1) truncate(52.64,2) truncate(52.64,-1) truncate(52.64,-2) truncate(-52.64,1) truncate(-52.64,-1) +52.6 52.64 50 0 -52.6 -50 +explain extended select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2), truncate(-52.64,1),truncate(-52.64,-1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select truncate(52.64,1) AS `truncate(52.64,1)`,truncate(52.64,2) AS `truncate(52.64,2)`,truncate(52.64,-(1)) AS `truncate(52.64,-1)`,truncate(52.64,-(2)) AS `truncate(52.64,-2)`,truncate(-(52.64),1) AS `truncate(-52.64,1)`,truncate(-(52.64),-(1)) AS `truncate(-52.64,-1)` +select round(5.5),round(-5.5); +round(5.5) round(-5.5) +6 -6 +explain extended select round(5.5),round(-5.5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select round(5.5,0) AS `round(5.5)`,round(-(5.5),0) AS `round(-5.5)` +select round(5.64,1),round(5.64,2),round(5.64,-1),round(5.64,-2); +round(5.64,1) round(5.64,2) round(5.64,-1) round(5.64,-2) +5.6 5.64 10 0 +select abs(-10), sign(-5), sign(5), sign(0); +abs(-10) sign(-5) sign(5) sign(0) +10 -1 1 0 +explain extended select abs(-10), sign(-5), sign(5), sign(0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select abs(-(10)) AS `abs(-10)`,sign(-(5)) AS `sign(-5)`,sign(5) AS `sign(5)`,sign(0) AS `sign(0)` +select log(exp(10)),exp(log(sqrt(10))*2),log(-1),log(NULL),log(1,1),log(3,9),log(-1,2),log(NULL,2); +log(exp(10)) exp(log(sqrt(10))*2) log(-1) log(NULL) log(1,1) log(3,9) log(-1,2) log(NULL,2) +10 10 NULL NULL NULL 2 NULL NULL +explain extended select log(exp(10)),exp(log(sqrt(10))*2),log(-1),log(NULL),log(1,1),log(3,9),log(-1,2),log(NULL,2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select log(exp(10)) AS `log(exp(10))`,exp((log(sqrt(10)) * 2)) AS `exp(log(sqrt(10))*2)`,log(-(1)) AS `log(-1)`,log(NULL) AS `log(NULL)`,log(1,1) AS `log(1,1)`,log(3,9) AS `log(3,9)`,log(-(1),2) AS `log(-1,2)`,log(NULL,2) AS `log(NULL,2)` +select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL); +ln(exp(10)) exp(ln(sqrt(10))*2) ln(-1) ln(0) ln(NULL) +10 10 NULL NULL NULL +explain extended select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select ln(exp(10)) AS `ln(exp(10))`,exp((ln(sqrt(10)) * 2)) AS `exp(ln(sqrt(10))*2)`,ln(-(1)) AS `ln(-1)`,ln(0) AS `ln(0)`,ln(NULL) AS `ln(NULL)` +select log2(8),log2(15),log2(-2),log2(0),log2(NULL); +log2(8) log2(15) log2(-2) log2(0) log2(NULL) +3 3.9068905956085 NULL NULL NULL +explain extended select log2(8),log2(15),log2(-2),log2(0),log2(NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select log2(8) AS `log2(8)`,log2(15) AS `log2(15)`,log2(-(2)) AS `log2(-2)`,log2(0) AS `log2(0)`,log2(NULL) AS `log2(NULL)` +select log10(100),log10(18),log10(-4),log10(0),log10(NULL); +log10(100) log10(18) log10(-4) log10(0) log10(NULL) +2 1.2552725051033 NULL NULL NULL +explain extended select log10(100),log10(18),log10(-4),log10(0),log10(NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select log10(100) AS `log10(100)`,log10(18) AS `log10(18)`,log10(-(4)) AS `log10(-4)`,log10(0) AS `log10(0)`,log10(NULL) AS `log10(NULL)` +select pow(10,log10(10)),power(2,4); +pow(10,log10(10)) power(2,4) +10 16 +explain extended select pow(10,log10(10)),power(2,4); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select pow(10,log10(10)) AS `pow(10,log10(10))`,pow(2,4) AS `power(2,4)` +set @@rand_seed1=10000000,@@rand_seed2=1000000; +select rand(999999),rand(); +rand(999999) rand() +0.014231365187309 0.028870999839968 +explain extended select rand(999999),rand(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select rand(999999) AS `rand(999999)`,rand() AS `rand()` +select pi(),format(sin(pi()/2),6),format(cos(pi()/2),6),format(abs(tan(pi())),6),format(cot(1),6),format(asin(1),6),format(acos(0),6),format(atan(1),6); +pi() format(sin(pi()/2),6) format(cos(pi()/2),6) format(abs(tan(pi())),6) format(cot(1),6) format(asin(1),6) format(acos(0),6) format(atan(1),6) +3.141593 1.000000 0.000000 0.000000 0.642093 1.570796 1.570796 0.785398 +explain extended select pi(),format(sin(pi()/2),6),format(cos(pi()/2),6),format(abs(tan(pi())),6),format(cot(1),6),format(asin(1),6),format(acos(0),6),format(atan(1),6); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select pi() AS `pi()`,format(sin((pi() / 2)),6) AS `format(sin(pi()/2),6)`,format(cos((pi() / 2)),6) AS `format(cos(pi()/2),6)`,format(abs(tan(pi())),6) AS `format(abs(tan(pi())),6)`,format((1 / tan(1)),6) AS `format(cot(1),6)`,format(asin(1),6) AS `format(asin(1),6)`,format(acos(0),6) AS `format(acos(0),6)`,format(atan(1),6) AS `format(atan(1),6)` +select degrees(pi()),radians(360); +degrees(pi()) radians(360) +180 6.2831853071796 +select format(atan(-2, 2), 6); +format(atan(-2, 2), 6) +-0.785398 +select format(atan(pi(), 0), 6); +format(atan(pi(), 0), 6) +1.570796 +select format(atan2(-2, 2), 6); +format(atan2(-2, 2), 6) +-0.785398 +select format(atan2(pi(), 0), 6); +format(atan2(pi(), 0), 6) +1.570796 +SELECT ACOS(1.0); +ACOS(1.0) +0 +SELECT ASIN(1.0); +ASIN(1.0) +1.5707963267949 +SELECT ACOS(0.2*5.0); +ACOS(0.2*5.0) +0 +SELECT ACOS(0.5*2.0); +ACOS(0.5*2.0) +0 +SELECT ASIN(0.8+0.2); +ASIN(0.8+0.2) +1.5707963267949 +SELECT ASIN(1.2-0.2); +ASIN(1.2-0.2) +1.5707963267949 +select format(4.55, 1), format(4.551, 1); +format(4.55, 1) format(4.551, 1) +4.6 4.6 +explain extended select degrees(pi()),radians(360); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select degrees(pi()) AS `degrees(pi())`,radians(360) AS `radians(360)` +select rand(rand); +ERROR 42S22: Unknown column 'rand' in 'field list' +create table t1 (col1 int, col2 decimal(60,30)); +insert into t1 values(1,1234567890.12345); +select format(col2,7) from t1; +format(col2,7) +1,234,567,890.1234500 +select format(col2,8) from t1; +format(col2,8) +1,234,567,890.12345000 +insert into t1 values(7,1234567890123456.12345); +select format(col2,6) from t1 where col1=7; +format(col2,6) +1,234,567,890,123,456.123450 +drop table t1; +select round(150, 2); +round(150, 2) +150 +select ceil(0.09); +ceil(0.09) +1 +select ceil(0.000000000000000009); +ceil(0.000000000000000009) +1 +create table t1 select round(1, 6); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `round(1, 6)` int(1) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t1; +round(1, 6) +1 +drop table t1; +select abs(-2) * -2; +abs(-2) * -2 +-4 +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(1),(1),(2); +SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(a) * 1000 AS UNSIGNED) +FROM t1; +CAST(RAND(2) * 1000 AS UNSIGNED) CAST(RAND(a) * 1000 AS UNSIGNED) +656 405 +122 405 +645 405 +858 656 +SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(a) * 1000 AS UNSIGNED) +FROM t1 WHERE a = 1; +CAST(RAND(2) * 1000 AS UNSIGNED) CAST(RAND(a) * 1000 AS UNSIGNED) +656 405 +122 405 +645 405 +INSERT INTO t1 VALUES (3); +SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(a) * 1000 AS UNSIGNED) +FROM t1; +CAST(RAND(2) * 1000 AS UNSIGNED) CAST(RAND(a) * 1000 AS UNSIGNED) +656 405 +122 405 +645 405 +858 656 +354 906 +SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(a) * 1000 AS UNSIGNED) +FROM t1 WHERE a = 1; +CAST(RAND(2) * 1000 AS UNSIGNED) CAST(RAND(a) * 1000 AS UNSIGNED) +656 405 +122 405 +645 405 +PREPARE stmt FROM +"SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(?) * 1000 AS UNSIGNED) + FROM t1 WHERE a = 1"; +set @var=2; +EXECUTE stmt USING @var; +CAST(RAND(2) * 1000 AS UNSIGNED) CAST(RAND(?) * 1000 AS UNSIGNED) +656 656 +122 122 +645 645 +DROP TABLE t1; +create table t1 (a varchar(90), ts datetime not null, index (a)) engine=innodb default charset=utf8; +insert into t1 values ('http://www.foo.com/', now()); +select a from t1 where a='http://www.foo.com/' order by abs(timediff(ts, 0)); +a +http://www.foo.com/ +drop table t1; +set sql_mode='traditional'; +select ln(-1); +ln(-1) +NULL +Warnings: +Error 1365 Division by 0 +select log10(-1); +log10(-1) +NULL +Warnings: +Error 1365 Division by 0 +select log2(-1); +log2(-1) +NULL +Warnings: +Error 1365 Division by 0 +select log(2,-1); +log(2,-1) +NULL +Warnings: +Error 1365 Division by 0 +select log(-2,1); +log(-2,1) +NULL +Warnings: +Error 1365 Division by 0 +set sql_mode=''; +select round(111,-10); +round(111,-10) +0 +select round(-5000111000111000155,-1); +round(-5000111000111000155,-1) +-5000111000111000160 +select round(15000111000111000155,-1); +round(15000111000111000155,-1) +15000111000111000160 +select truncate(-5000111000111000155,-1); +truncate(-5000111000111000155,-1) +-5000111000111000150 +select truncate(15000111000111000155,-1); +truncate(15000111000111000155,-1) +15000111000111000150 +set names utf8; +create table t1 +(f1 varchar(32) not null, +f2 smallint(5) unsigned not null, +f3 int(10) unsigned not null default '0') +engine=myisam default charset=utf8; +insert into t1 values ('zombie',0,0),('gold',1,10000),('silver',2,10000); +create table t2 +(f1 int(10) unsigned not null, +f2 int(10) unsigned not null, +f3 smallint(5) unsigned not null) +engine=myisam default charset=utf8; +insert into t2 values (16777216,16787215,1),(33554432,33564431,2); +select format(t2.f2-t2.f1+1,0) from t1,t2 +where t1.f2 = t2.f3 order by t1.f1; +format(t2.f2-t2.f1+1,0) +10,000 +10,000 +drop table t1, t2; +set names default; diff --git a/mysql-test/suite/pbxt/r/func_misc.result b/mysql-test/suite/pbxt/r/func_misc.result new file mode 100644 index 00000000000..6cec0aea5f3 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_misc.result @@ -0,0 +1,144 @@ +select format(1.5555,0),format(123.5555,1),format(1234.5555,2),format(12345.55555,3),format(123456.5555,4),format(1234567.5555,5),format("12345.2399",2); +format(1.5555,0) format(123.5555,1) format(1234.5555,2) format(12345.55555,3) format(123456.5555,4) format(1234567.5555,5) format("12345.2399",2) +2 123.6 1,234.56 12,345.556 123,456.5555 1,234,567.55550 12,345.24 +select inet_ntoa(inet_aton("255.255.255.255.255.255.255.255")); +inet_ntoa(inet_aton("255.255.255.255.255.255.255.255")) +NULL +select inet_aton("255.255.255.255.255"),inet_aton("255.255.1.255"),inet_aton("0.1.255"); +inet_aton("255.255.255.255.255") inet_aton("255.255.1.255") inet_aton("0.1.255") +1099511627775 4294902271 65791 +select inet_ntoa(1099511627775),inet_ntoa(4294902271),inet_ntoa(511); +inet_ntoa(1099511627775) inet_ntoa(4294902271) inet_ntoa(511) +NULL 255.255.1.255 0.0.1.255 +select hex(inet_aton('127')); +hex(inet_aton('127')) +7F +select hex(inet_aton('127.1')); +hex(inet_aton('127.1')) +7F000001 +select hex(inet_aton('127.1.1')); +hex(inet_aton('127.1.1')) +7F010001 +select length(uuid()), charset(uuid()), length(unhex(replace(uuid(),_utf8'-',_utf8''))); +length(uuid()) charset(uuid()) length(unhex(replace(uuid(),_utf8'-',_utf8''))) +36 utf8 16 +select length(format('nan', 2)) > 0; +length(format('nan', 2)) > 0 +1 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'nan' +select concat("$",format(2500,2)); +concat("$",format(2500,2)) +$2,500.00 +create table t1 ( a timestamp ); +insert into t1 values ( '2004-01-06 12:34' ); +select a from t1 where left(a+0,6) in ( left(20040106,6) ); +a +2004-01-06 12:34:00 +select a from t1 where left(a+0,6) = ( left(20040106,6) ); +a +2004-01-06 12:34:00 +select a from t1 where right(a+0,6) in ( right(20040106123400,6) ); +a +2004-01-06 12:34:00 +select a from t1 where right(a+0,6) = ( right(20040106123400,6) ); +a +2004-01-06 12:34:00 +select a from t1 where mid(a+0,6,3) in ( mid(20040106123400,6,3) ); +a +2004-01-06 12:34:00 +select a from t1 where mid(a+0,6,3) = ( mid(20040106123400,6,3) ); +a +2004-01-06 12:34:00 +drop table t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (conn CHAR(7), connection_id INT); +INSERT INTO t1 VALUES ('default', CONNECTION_ID()); +SELECT GET_LOCK('bug16501',600); +GET_LOCK('bug16501',600) +1 +INSERT INTO t1 VALUES ('con1', CONNECTION_ID()); +SELECT IS_USED_LOCK('bug16501') = connection_id +FROM t1 +WHERE conn = 'default'; +IS_USED_LOCK('bug16501') = connection_id +1 +SELECT GET_LOCK('bug16501',600); +SELECT IS_USED_LOCK('bug16501') = CONNECTION_ID(); +IS_USED_LOCK('bug16501') = CONNECTION_ID() +1 +SELECT RELEASE_LOCK('bug16501'); +RELEASE_LOCK('bug16501') +1 +GET_LOCK('bug16501',600) +1 +SELECT IS_USED_LOCK('bug16501') = connection_id +FROM t1 +WHERE conn = 'con1'; +IS_USED_LOCK('bug16501') = connection_id +1 +SELECT IS_USED_LOCK('bug16501') = CONNECTION_ID(); +IS_USED_LOCK('bug16501') = CONNECTION_ID() +1 +SELECT RELEASE_LOCK('bug16501'); +RELEASE_LOCK('bug16501') +1 +SELECT IS_USED_LOCK('bug16501'); +IS_USED_LOCK('bug16501') +NULL +DROP TABLE t1; +select export_set(3, _latin1'foo', _utf8'bar', ',', 4); +export_set(3, _latin1'foo', _utf8'bar', ',', 4) +foo,foo,bar,bar +End of 4.1 tests +create table t1 as select uuid(), length(uuid()); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `uuid()` varchar(36) CHARACTER SET utf8 NOT NULL DEFAULT '', + `length(uuid())` int(10) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a timestamp default '2005-05-05 01:01:01', +b timestamp default '2005-05-05 01:01:01'); +insert into t1 set a = now(); +select sleep(3); +sleep(3) +0 +update t1 set b = now(); +select timediff(b, a) >= '00:00:03' from t1; +timediff(b, a) >= '00:00:03' +1 +drop table t1; +set global query_cache_size=1355776; +create table t1 (a int); +insert into t1 values (1),(1),(1); +create table t2 (a datetime default null, b datetime default null); +insert into t2 set a = now(); +select a from t1 where sleep(1); +a +update t2 set b = now() where b is null; +insert into t2 set a = now(); +select a from t1 where sleep(a); +a +update t2 set b = now() where b is null; +insert into t2 set a = now(); +select a from t1 where sleep(1); +a +update t2 set b = now() where b is null; +select timediff(b, a) >= '00:00:03' from t2; +timediff(b, a) >= '00:00:03' +1 +1 +1 +drop table t2; +drop table t1; +set global query_cache_size=default; +create table t1 select INET_ATON('255.255.0.1') as `a`; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(21) unsigned DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/func_op.result b/mysql-test/suite/pbxt/r/func_op.result new file mode 100644 index 00000000000..636163e6b29 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_op.result @@ -0,0 +1,48 @@ +select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; +1+1 1-1 1+1*2 8/5 8%5 mod(8,5) mod(8,5)|0 -(1+1)*-2 +2 0 3 1.6000 3 3 3 4 +explain extended select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select (1 + 1) AS `1+1`,(1 - 1) AS `1-1`,(1 + (1 * 2)) AS `1+1*2`,(8 / 5) AS `8/5`,(8 % 5) AS `8%5`,(8 % 5) AS `mod(8,5)`,((8 % 5) | 0) AS `mod(8,5)|0`,(-((1 + 1)) * -(2)) AS `-(1+1)*-2` +select 1 | (1+1),5 & 3,bit_count(7) ; +1 | (1+1) 5 & 3 bit_count(7) +3 1 3 +explain extended select 1 | (1+1),5 & 3,bit_count(7) ; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select (1 | (1 + 1)) AS `1 | (1+1)`,(5 & 3) AS `5 & 3`,bit_count(7) AS `bit_count(7)` +select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60; +1 << 32 1 << 63 1 << 64 4 >> 2 4 >> 63 1<< 63 >> 60 +4294967296 9223372036854775808 0 1 0 8 +select -1 | 0, -1 ^ 0, -1 & 0; +-1 | 0 -1 ^ 0 -1 & 0 +18446744073709551615 18446744073709551615 0 +select -1 | 1, -1 ^ 1, -1 & 1; +-1 | 1 -1 ^ 1 -1 & 1 +18446744073709551615 18446744073709551614 1 +select 1 | -1, 1 ^ -1, 1 & -1; +1 | -1 1 ^ -1 1 & -1 +18446744073709551615 18446744073709551614 1 +select 0 | -1, 0 ^ -1, 0 & -1; +0 | -1 0 ^ -1 0 & -1 +18446744073709551615 18446744073709551615 0 +select -1 >> 0, -1 << 0; +-1 >> 0 -1 << 0 +18446744073709551615 18446744073709551615 +select -1 >> 1, -1 << 1; +-1 >> 1 -1 << 1 +9223372036854775807 18446744073709551614 +drop table if exists t1,t2; +create table t1(a int); +create table t2(a int, b int); +insert into t1 values (1), (2), (3); +insert into t2 values (1, 7), (3, 7); +select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; +a a b bit_count(t2.b) +1 1 7 3 +2 NULL NULL NULL +3 3 7 3 +drop table t1, t2; diff --git a/mysql-test/suite/pbxt/r/func_regexp.result b/mysql-test/suite/pbxt/r/func_regexp.result new file mode 100644 index 00000000000..e1d29b4f4ee --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_regexp.result @@ -0,0 +1,100 @@ +drop table if exists t1; +create table t1 (s1 char(64),s2 char(64)); +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +create table t1 (xxx char(128)); +insert into t1 (xxx) values('this is a test of some long text to see what happens'); +select * from t1 where xxx regexp('is a test of some long text to'); +xxx +this is a test of some long text to see what happens +explain extended select * from t1 where xxx regexp('is a test of some long text to'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`xxx` AS `xxx` from `test`.`t1` where (`test`.`t1`.`xxx` regexp 'is a test of some long text to') +select * from t1 where xxx regexp('is a test of some long text to '); +xxx +this is a test of some long text to see what happens +select * from t1 where xxx regexp('is a test of some long text to s'); +xxx +this is a test of some long text to see what happens +select * from t1 where xxx regexp('is a test of some long text to se'); +xxx +this is a test of some long text to see what happens +drop table t1; +create table t1 (xxx char(128)); +insert into t1 (xxx) values('this is some text: to test - out.reg exp (22/45)'); +select * from t1 where xxx REGEXP '^this is some text: to test - out\\.reg exp [[(][0-9]+[/\\][0-9]+[])][ ]*$'; +xxx +this is some text: to test - out.reg exp (22/45) +drop table t1; +select _latin1 0xFF regexp _latin1 '[[:lower:]]' COLLATE latin1_bin; +_latin1 0xFF regexp _latin1 '[[:lower:]]' COLLATE latin1_bin +1 +select _koi8r 0xFF regexp _koi8r '[[:lower:]]' COLLATE koi8r_bin; +_koi8r 0xFF regexp _koi8r '[[:lower:]]' COLLATE koi8r_bin +0 +select _latin1 0xFF regexp _latin1 '[[:upper:]]' COLLATE latin1_bin; +_latin1 0xFF regexp _latin1 '[[:upper:]]' COLLATE latin1_bin +0 +select _koi8r 0xFF regexp _koi8r '[[:upper:]]' COLLATE koi8r_bin; +_koi8r 0xFF regexp _koi8r '[[:upper:]]' COLLATE koi8r_bin +1 +select _latin1 0xF7 regexp _latin1 '[[:alpha:]]'; +_latin1 0xF7 regexp _latin1 '[[:alpha:]]' +0 +select _koi8r 0xF7 regexp _koi8r '[[:alpha:]]'; +_koi8r 0xF7 regexp _koi8r '[[:alpha:]]' +1 +select _latin1'a' regexp _latin1'A' collate latin1_general_ci; +_latin1'a' regexp _latin1'A' collate latin1_general_ci +1 +select _latin1'a' regexp _latin1'A' collate latin1_bin; +_latin1'a' regexp _latin1'A' collate latin1_bin +0 +create table t1 (a varchar(40)); +insert into t1 values ('C1'),('C2'),('R1'),('C3'),('R2'),('R3'); +prepare stmt1 from 'select a from t1 where a rlike ? order by a'; +set @a="^C.*"; +execute stmt1 using @a; +a +C1 +C2 +C3 +set @a="^R.*"; +execute stmt1 using @a; +a +R1 +R2 +R3 +deallocate prepare stmt1; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/func_sapdb.result b/mysql-test/suite/pbxt/r/func_sapdb.result new file mode 100644 index 00000000000..7a61f434d2f --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_sapdb.result @@ -0,0 +1,249 @@ +drop table if exists t1, test; +select extract(DAY_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(DAY_MICROSECOND FROM "1999-01-02 10:11:12.000123") +2101112000123 +select extract(HOUR_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(HOUR_MICROSECOND FROM "1999-01-02 10:11:12.000123") +101112000123 +select extract(MINUTE_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(MINUTE_MICROSECOND FROM "1999-01-02 10:11:12.000123") +1112000123 +select extract(SECOND_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(SECOND_MICROSECOND FROM "1999-01-02 10:11:12.000123") +12000123 +select extract(MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(MICROSECOND FROM "1999-01-02 10:11:12.000123") +123 +select date_format("1997-12-31 23:59:59.000002", "%f"); +date_format("1997-12-31 23:59:59.000002", "%f") +000002 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000 99:99:99.999999" DAY_MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "10000 99:99:99.999999" DAY_MICROSECOND) +2025-05-23 04:40:39.000001 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99:99.999999" HOUR_MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99:99.999999" HOUR_MICROSECOND) +1999-02-21 17:40:39.000001 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99.999999" MINUTE_MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99.999999" MINUTE_MICROSECOND) +1998-01-07 22:41:39.000001 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000.999999" SECOND_MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "10000.999999" SECOND_MICROSECOND) +1998-01-01 02:46:40.000001 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "999999" MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "999999" MICROSECOND) +1998-01-01 00:00:00.000001 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1 1:1:1.000002" DAY_MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "1 1:1:1.000002" DAY_MICROSECOND) +1997-12-30 22:58:58.999999 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1:1.000002" HOUR_MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1:1.000002" HOUR_MICROSECOND) +1997-12-31 22:58:58.999999 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1.000002" MINUTE_MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1.000002" MINUTE_MICROSECOND) +1997-12-31 23:58:58.999999 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1.000002" SECOND_MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "1.000002" SECOND_MICROSECOND) +1997-12-31 23:59:58.999999 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "000002" MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "000002" MICROSECOND) +1997-12-31 23:59:59.999999 +select adddate("1997-12-31 23:59:59.000001", 10); +adddate("1997-12-31 23:59:59.000001", 10) +1998-01-10 23:59:59.000001 +select subdate("1997-12-31 23:59:59.000001", 10); +subdate("1997-12-31 23:59:59.000001", 10) +1997-12-21 23:59:59.000001 +select datediff("1997-12-31 23:59:59.000001","1997-12-30"); +datediff("1997-12-31 23:59:59.000001","1997-12-30") +1 +select datediff("1997-11-30 23:59:59.000001","1997-12-31"); +datediff("1997-11-30 23:59:59.000001","1997-12-31") +-31 +SET @@SQL_MODE="ALLOW_INVALID_DATES"; +select datediff("1997-11-31 23:59:59.000001","1997-12-31"); +datediff("1997-11-31 23:59:59.000001","1997-12-31") +-30 +SET @@SQL_MODE=""; +select datediff("1997-11-31 23:59:59.000001","1997-12-31"); +datediff("1997-11-31 23:59:59.000001","1997-12-31") +NULL +Warnings: +Warning 1292 Incorrect datetime value: '1997-11-31 23:59:59.000001' +select datediff("1997-11-30 23:59:59.000001",null); +datediff("1997-11-30 23:59:59.000001",null) +NULL +select weekofyear("1997-11-30 23:59:59.000001"); +weekofyear("1997-11-30 23:59:59.000001") +48 +select makedate(1997,1); +makedate(1997,1) +1997-01-01 +select makedate(1997,0); +makedate(1997,0) +NULL +select makedate(9999,365); +makedate(9999,365) +9999-12-31 +select makedate(9999,366); +makedate(9999,366) +NULL +select addtime("1997-12-31 23:59:59.999999", "1 1:1:1.000002"); +addtime("1997-12-31 23:59:59.999999", "1 1:1:1.000002") +1998-01-02 01:01:01.000001 +select subtime("1997-12-31 23:59:59.000001", "1 1:1:1.000002"); +subtime("1997-12-31 23:59:59.000001", "1 1:1:1.000002") +1997-12-30 22:58:57.999999 +select addtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); +addtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999") +NULL +select subtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); +subtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999") +NULL +select subtime("01:00:00.999999", "02:00:00.999998"); +subtime("01:00:00.999999", "02:00:00.999998") +-00:59:59.999999 +select subtime("02:01:01.999999", "01:01:01.999999"); +subtime("02:01:01.999999", "01:01:01.999999") +01:00:00.000000 +select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); +timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002") +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '8807:59:59.999999' +select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); +timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") +46:58:57.999999 +select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); +timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") +-24:00:00.000001 +select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); +timediff("1997-12-31 23:59:59.000001","23:59:59.000001") +NULL +select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); +timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001") +-00:00:00.000001 +select timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50"); +timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50") +-00:00:00.000001 +select maketime(10,11,12); +maketime(10,11,12) +10:11:12 +select maketime(25,11,12); +maketime(25,11,12) +25:11:12 +select maketime(-25,11,12); +maketime(-25,11,12) +-25:11:12 +select timestamp("2001-12-01", "01:01:01.999999"); +timestamp("2001-12-01", "01:01:01.999999") +2001-12-01 01:01:01.999999 +select timestamp("2001-13-01", "01:01:01.000001"); +timestamp("2001-13-01", "01:01:01.000001") +NULL +Warnings: +Warning 1292 Incorrect datetime value: '2001-13-01' +select timestamp("2001-12-01", "25:01:01"); +timestamp("2001-12-01", "25:01:01") +2001-12-02 01:01:01 +select timestamp("2001-12-01 01:01:01.000100"); +timestamp("2001-12-01 01:01:01.000100") +2001-12-01 01:01:01.000100 +select timestamp("2001-12-01"); +timestamp("2001-12-01") +2001-12-01 00:00:00 +select day("1997-12-31 23:59:59.000001"); +day("1997-12-31 23:59:59.000001") +31 +select date("1997-12-31 23:59:59.000001"); +date("1997-12-31 23:59:59.000001") +1997-12-31 +select date("1997-13-31 23:59:59.000001"); +date("1997-13-31 23:59:59.000001") +NULL +Warnings: +Warning 1292 Incorrect datetime value: '1997-13-31 23:59:59.000001' +select time("1997-12-31 23:59:59.000001"); +time("1997-12-31 23:59:59.000001") +23:59:59.000001 +select time("1997-12-31 25:59:59.000001"); +time("1997-12-31 25:59:59.000001") +NULL +Warnings: +Warning 1292 Truncated incorrect time value: '1997-12-31 25:59:59.000001' +select microsecond("1997-12-31 23:59:59.000001"); +microsecond("1997-12-31 23:59:59.000001") +1 +create table t1 +select makedate(1997,1) as f1, +addtime(cast("1997-12-31 23:59:59.000001" as datetime), "1 1:1:1.000002") as f2, +addtime(cast("23:59:59.999999" as time) , "1 1:1:1.000002") as f3, +timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") as f4, +timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") as f5, +maketime(10,11,12) as f6, +timestamp(cast("2001-12-01" as date), "01:01:01") as f7, +date("1997-12-31 23:59:59.000001") as f8, +time("1997-12-31 23:59:59.000001") as f9; +describe t1; +Field Type Null Key Default Extra +f1 date NO 0000-00-00 +f2 datetime YES NULL +f3 time YES NULL +f4 time YES NULL +f5 time YES NULL +f6 time YES NULL +f7 datetime YES NULL +f8 date YES NULL +f9 time YES NULL +select * from t1; +f1 f2 f3 f4 f5 f6 f7 f8 f9 +1997-01-01 1998-01-02 01:01:00 49:01:01 46:58:57 -24:00:00 10:11:12 2001-12-01 01:01:01 1997-12-31 23:59:59 +create table test(t1 datetime, t2 time, t3 time, t4 datetime); +insert into test values +('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'), +('2001-01-01 01:01:01', '-01:01:01', '-23:59:59', "1997-12-31 23:59:59.000001"), +('1997-12-31 23:59:59.000001', '-23:59:59', '-01:01:01', '2001-01-01 01:01:01'), +('2001-01-01 01:01:01', '01:01:01', '-1 01:01:01', null), +('2001-01-01 01:01:01', '-01:01:01', '1 01:01:01', '2001-01-01 01:01:01'), +('2001-01-01 01:01:01', null, '-1 01:01:01', null), +(null, null, null, null), +('2001-01-01 01:01:01', '01:01:01', '1 01:01:01', '2001-01-01 01:01:01'); +SELECT ADDTIME(t1,t2) As ttt, ADDTIME(t2, t3) As qqq from test; +ttt qqq +2001-01-01 02:02:02 NULL +2001-01-01 00:00:00 -25:01:00 +1997-12-31 00:00:00 -25:01:00 +2001-01-01 02:02:02 -24:00:00 +2001-01-01 00:00:00 24:00:00 +NULL NULL +NULL NULL +2001-01-01 02:02:02 26:02:02 +SELECT TIMEDIFF(t1, t4) As ttt, TIMEDIFF(t2, t3) As qqq, +TIMEDIFF(t3, t2) As eee, TIMEDIFF(t2, t4) As rrr from test; +ttt qqq eee rrr +-744:00:00 NULL NULL NULL +838:59:59 22:58:58 -22:58:58 NULL +-838:59:59 -22:58:58 22:58:58 NULL +NULL 26:02:02 -26:02:02 NULL +00:00:00 -26:02:02 26:02:02 NULL +NULL NULL NULL NULL +NULL NULL NULL NULL +00:00:00 -24:00:00 24:00:00 NULL +Warnings: +Warning 1292 Truncated incorrect time value: '26305:01:02' +Warning 1292 Truncated incorrect time value: '-26305:01:02' +drop table t1, test; +select addtime("-01:01:01.01", "-23:59:59.1") as a; +a +-25:01:00.110000 +select microsecond("1997-12-31 23:59:59.01") as a; +a +10000 +select microsecond(19971231235959.01) as a; +a +10000 +select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a; +a +1997-12-31 00:00:10.090000 +select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f"); +str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") +2003-01-02 10:11:12.001200 diff --git a/mysql-test/suite/pbxt/r/func_set.result b/mysql-test/suite/pbxt/r/func_set.result new file mode 100644 index 00000000000..aeeb6434bc2 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_set.result @@ -0,0 +1,75 @@ +select interval(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0; +interval(55,10,20,30,40,50,60,70,80,90,100) interval(3,1,1+1,1+1+1+1) field("IBM","NCA","ICL","SUN","IBM","DIGITAL") field("A","B","C") elt(2,"ONE","TWO","THREE") interval(0,1,2,3,4) elt(1,1,2,3)|0 elt(1,1.1,1.2,1.3)+0 +5 2 4 0 TWO 0 1 1.1 +explain extended select INTERVAL(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select interval((55,10,20,30,40,50,60,70,80,90,100)) AS `INTERVAL(55,10,20,30,40,50,60,70,80,90,100)`,interval((3,1,(1 + 1),(((1 + 1) + 1) + 1))) AS `interval(3,1,1+1,1+1+1+1)`,field('IBM','NCA','ICL','SUN','IBM','DIGITAL') AS `field("IBM","NCA","ICL","SUN","IBM","DIGITAL")`,field('A','B','C') AS `field("A","B","C")`,elt(2,'ONE','TWO','THREE') AS `elt(2,"ONE","TWO","THREE")`,interval((0,1,2,3,4)) AS `interval(0,1,2,3,4)`,(elt(1,1,2,3) | 0) AS `elt(1,1,2,3)|0`,(elt(1,1.1,1.2,1.3) + 0) AS `elt(1,1.1,1.2,1.3)+0` +SELECT INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56); +INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56) +1 +SELECT INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56, 77); +INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56, 77) +1 +select find_in_set("b","a,b,c"),find_in_set("c","a,b,c"),find_in_set("dd","a,bbb,dd"),find_in_set("bbb","a,bbb,dd"); +find_in_set("b","a,b,c") find_in_set("c","a,b,c") find_in_set("dd","a,bbb,dd") find_in_set("bbb","a,bbb,dd") +2 3 3 2 +select find_in_set("d","a,b,c"),find_in_set("dd","a,bbb,d"),find_in_set("bb","a,bbb,dd"); +find_in_set("d","a,b,c") find_in_set("dd","a,bbb,d") find_in_set("bb","a,bbb,dd") +0 0 0 +select make_set(0,'a','b','c'),make_set(-1,'a','b','c'),make_set(1,'a','b','c'),make_set(2,'a','b','c'),make_set(1+2,concat('a','b'),'c'); +make_set(0,'a','b','c') make_set(-1,'a','b','c') make_set(1,'a','b','c') make_set(2,'a','b','c') make_set(1+2,concat('a','b'),'c') + a,b,c a b ab,c +select make_set(NULL,'a','b','c'),make_set(1|4,'a',NULL,'c'),make_set(1+2,'a',NULL,'c'); +make_set(NULL,'a','b','c') make_set(1|4,'a',NULL,'c') make_set(1+2,'a',NULL,'c') +NULL a,c a +select export_set(9,"Y","N","-",5),export_set(9,"Y","N"),export_set(9,"Y","N",""); +export_set(9,"Y","N","-",5) export_set(9,"Y","N") export_set(9,"Y","N","") +Y-N-N-Y-N Y,N,N,Y,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N YNNYNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN +select elt(2,1),field(NULL,"a","b","c"); +elt(2,1) field(NULL,"a","b","c") +NULL 0 +select field("b","a",NULL),field(1,0,NULL)+0,field(1.0,0.0,NULL)+0.0,field(1.0e1,0.0e1,NULL)+0.0e1; +field("b","a",NULL) field(1,0,NULL)+0 field(1.0,0.0,NULL)+0.0 field(1.0e1,0.0e1,NULL)+0.0e1 +0 0 0.0 0 +select field(NULL,"a",NULL),field(NULL,0,NULL)+0,field(NULL,0.0,NULL)+0.0,field(NULL,0.0e1,NULL)+0.0e1; +field(NULL,"a",NULL) field(NULL,0,NULL)+0 field(NULL,0.0,NULL)+0.0 field(NULL,0.0e1,NULL)+0.0e1 +0 0 0.0 0 +select find_in_set("","a,b,c"),find_in_set("","a,b,c,"),find_in_set("",",a,b,c"); +find_in_set("","a,b,c") find_in_set("","a,b,c,") find_in_set("",",a,b,c") +0 4 1 +select find_in_set("abc","abc"),find_in_set("ab","abc"),find_in_set("abcd","abc"); +find_in_set("abc","abc") find_in_set("ab","abc") find_in_set("abcd","abc") +1 0 0 +select interval(null, 1, 10, 100); +interval(null, 1, 10, 100) +-1 +drop table if exists t1,t2; +create table t1 (id int(10) not null unique); +create table t2 (id int(10) not null primary key, val int(10) not null); +insert into t1 values (1),(2),(4); +insert into t2 values (1,1),(2,1),(3,1),(4,2); +select one.id, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id; +id elt(two.val,'one','two') +1 one +2 one +4 two +select one.id, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id order by one.id; +id elt(two.val,'one','two') +1 one +2 one +4 two +drop table t1,t2; +select find_in_set(binary 'a',binary 'A,B,C'); +find_in_set(binary 'a',binary 'A,B,C') +0 +select find_in_set('a',binary 'A,B,C'); +find_in_set('a',binary 'A,B,C') +0 +select find_in_set(binary 'a', 'A,B,C'); +find_in_set(binary 'a', 'A,B,C') +0 +select find_in_set('1','3,1,'); +find_in_set('1','3,1,') +2 diff --git a/mysql-test/suite/pbxt/r/func_str.result b/mysql-test/suite/pbxt/r/func_str.result new file mode 100644 index 00000000000..59d7b23f9df --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_str.result @@ -0,0 +1,2262 @@ +drop table if exists t1,t2; +set names latin1; +select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; +hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo +hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo +select 'hello' 'monty'; +hello +hellomonty +select length('\n\t\r\b\0\_\%\\'); +length('\n\t\r\b\0\_\%\\') +10 +select bit_length('\n\t\r\b\0\_\%\\'); +bit_length('\n\t\r\b\0\_\%\\') +80 +select char_length('\n\t\r\b\0\_\%\\'); +char_length('\n\t\r\b\0\_\%\\') +10 +select length(_latin1'\n\t\n\b\0\\_\\%\\'); +length(_latin1'\n\t\n\b\0\\_\\%\\') +10 +select concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'); +concat('monty',' was here ','again') length('hello') char(ascii('h')) ord('h') +monty was here again 5 h 104 +select hex(char(256)); +hex(char(256)) +0100 +select locate('he','hello'),locate('he','hello',2),locate('lo','hello',2) ; +locate('he','hello') locate('he','hello',2) locate('lo','hello',2) +1 0 4 +select instr('hello','HE'), instr('hello',binary 'HE'), instr(binary 'hello','HE'); +instr('hello','HE') instr('hello',binary 'HE') instr(binary 'hello','HE') +1 0 0 +select position(binary 'll' in 'hello'),position('a' in binary 'hello'); +position(binary 'll' in 'hello') position('a' in binary 'hello') +3 0 +select left('hello',null), right('hello',null); +left('hello',null) right('hello',null) +NULL NULL +select left('hello',2),right('hello',2),substring('hello',2,2),mid('hello',1,5) ; +left('hello',2) right('hello',2) substring('hello',2,2) mid('hello',1,5) +he lo el hello +select concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',substring('monty',5,1)) ; +concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',substring('monty',5,1)) +happy +select substring_index('www.tcx.se','.',-2),substring_index('www.tcx.se','.',1); +substring_index('www.tcx.se','.',-2) substring_index('www.tcx.se','.',1) +tcx.se www +select substring_index('www.tcx.se','tcx',1),substring_index('www.tcx.se','tcx',-1); +substring_index('www.tcx.se','tcx',1) substring_index('www.tcx.se','tcx',-1) +www. .se +select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1); +substring_index('.tcx.se','.',-2) substring_index('.tcx.se','.tcx',-1) +tcx.se .se +select substring_index('aaaaaaaaa1','a',1); +substring_index('aaaaaaaaa1','a',1) + +select substring_index('aaaaaaaaa1','aa',1); +substring_index('aaaaaaaaa1','aa',1) + +select substring_index('aaaaaaaaa1','aa',2); +substring_index('aaaaaaaaa1','aa',2) +aa +select substring_index('aaaaaaaaa1','aa',3); +substring_index('aaaaaaaaa1','aa',3) +aaaa +select substring_index('aaaaaaaaa1','aa',4); +substring_index('aaaaaaaaa1','aa',4) +aaaaaa +select substring_index('aaaaaaaaa1','aa',5); +substring_index('aaaaaaaaa1','aa',5) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaa',1); +substring_index('aaaaaaaaa1','aaa',1) + +select substring_index('aaaaaaaaa1','aaa',2); +substring_index('aaaaaaaaa1','aaa',2) +aaa +select substring_index('aaaaaaaaa1','aaa',3); +substring_index('aaaaaaaaa1','aaa',3) +aaaaaa +select substring_index('aaaaaaaaa1','aaa',4); +substring_index('aaaaaaaaa1','aaa',4) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaaa',1); +substring_index('aaaaaaaaa1','aaaa',1) + +select substring_index('aaaaaaaaa1','aaaa',2); +substring_index('aaaaaaaaa1','aaaa',2) +aaaa +select substring_index('aaaaaaaaa1','1',1); +substring_index('aaaaaaaaa1','1',1) +aaaaaaaaa +select substring_index('aaaaaaaaa1','a',-1); +substring_index('aaaaaaaaa1','a',-1) +1 +select substring_index('aaaaaaaaa1','aa',-1); +substring_index('aaaaaaaaa1','aa',-1) +1 +select substring_index('aaaaaaaaa1','aa',-2); +substring_index('aaaaaaaaa1','aa',-2) +aa1 +select substring_index('aaaaaaaaa1','aa',-3); +substring_index('aaaaaaaaa1','aa',-3) +aaaa1 +select substring_index('aaaaaaaaa1','aa',-4); +substring_index('aaaaaaaaa1','aa',-4) +aaaaaa1 +select substring_index('aaaaaaaaa1','aa',-5); +substring_index('aaaaaaaaa1','aa',-5) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaa',-1); +substring_index('aaaaaaaaa1','aaa',-1) +1 +select substring_index('aaaaaaaaa1','aaa',-2); +substring_index('aaaaaaaaa1','aaa',-2) +aaa1 +select substring_index('aaaaaaaaa1','aaa',-3); +substring_index('aaaaaaaaa1','aaa',-3) +aaaaaa1 +select substring_index('aaaaaaaaa1','aaa',-4); +substring_index('aaaaaaaaa1','aaa',-4) + +select substring_index('the king of thethe hill','the',-2); +substring_index('the king of thethe hill','the',-2) +the hill +select substring_index('the king of the the hill','the',-2); +substring_index('the king of the the hill','the',-2) + the hill +select substring_index('the king of the the hill','the',-2); +substring_index('the king of the the hill','the',-2) + the hill +select substring_index('the king of the the hill',' the ',-1); +substring_index('the king of the the hill',' the ',-1) +hill +select substring_index('the king of the the hill',' the ',-2); +substring_index('the king of the the hill',' the ',-2) + the hill +select substring_index('the king of the the hill',' ',-1); +substring_index('the king of the the hill',' ',-1) +hill +select substring_index('the king of the the hill',' ',-2); +substring_index('the king of the the hill',' ',-2) +the hill +select substring_index('the king of the the hill',' ',-3); +substring_index('the king of the the hill',' ',-3) + the hill +select substring_index('the king of the the hill',' ',-4); +substring_index('the king of the the hill',' ',-4) +the the hill +select substring_index('the king of the the hill',' ',-5); +substring_index('the king of the the hill',' ',-5) +of the the hill +select substring_index('the king of the.the hill','the',-2); +substring_index('the king of the.the hill','the',-2) +.the hill +select substring_index('the king of thethethe.the hill','the',-3); +substring_index('the king of thethethe.the hill','the',-3) +the.the hill +select substring_index('the king of thethethe.the hill','the',-1); +substring_index('the king of thethethe.the hill','the',-1) + hill +select substring_index('the king of the the hill','the',1); +substring_index('the king of the the hill','the',1) + +select substring_index('the king of the the hill','the',2); +substring_index('the king of the the hill','the',2) +the king of +select substring_index('the king of the the hill','the',3); +substring_index('the king of the the hill','the',3) +the king of the +select concat(':',ltrim(' left '),':',rtrim(' right '),':'); +concat(':',ltrim(' left '),':',rtrim(' right '),':') +:left : right: +select concat(':',trim(leading from ' left '),':',trim(trailing from ' right '),':'); +concat(':',trim(leading from ' left '),':',trim(trailing from ' right '),':') +:left : right: +select concat(':',trim(LEADING FROM ' left'),':',trim(TRAILING FROM ' right '),':'); +concat(':',trim(LEADING FROM ' left'),':',trim(TRAILING FROM ' right '),':') +:left: right: +select concat(':',trim(' m '),':',trim(BOTH FROM ' y '),':',trim('*' FROM '*s*'),':'); +concat(':',trim(' m '),':',trim(BOTH FROM ' y '),':',trim('*' FROM '*s*'),':') +:m:y:s: +select concat(':',trim(BOTH 'ab' FROM 'ababmyabab'),':',trim(BOTH '*' FROM '***sql'),':'); +concat(':',trim(BOTH 'ab' FROM 'ababmyabab'),':',trim(BOTH '*' FROM '***sql'),':') +:my:sql: +select concat(':',trim(LEADING '.*' FROM '.*my'),':',trim(TRAILING '.*' FROM 'sql.*.*'),':'); +concat(':',trim(LEADING '.*' FROM '.*my'),':',trim(TRAILING '.*' FROM 'sql.*.*'),':') +:my:sql: +select TRIM("foo" FROM "foo"), TRIM("foo" FROM "foook"), TRIM("foo" FROM "okfoo"); +TRIM("foo" FROM "foo") TRIM("foo" FROM "foook") TRIM("foo" FROM "okfoo") + ok ok +select concat_ws(', ','monty','was here','again'); +concat_ws(', ','monty','was here','again') +monty, was here, again +select concat_ws(NULL,'a'),concat_ws(',',NULL,''); +concat_ws(NULL,'a') concat_ws(',',NULL,'') +NULL +select concat_ws(',','',NULL,'a'); +concat_ws(',','',NULL,'a') +,a +SELECT CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"'); +CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"') +"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +select insert('txs',2,1,'hi'),insert('is ',4,0,'a'),insert('txxxxt',2,4,'es'); +insert('txs',2,1,'hi') insert('is ',4,0,'a') insert('txxxxt',2,4,'es') +this is a test +select replace('aaaa','a','b'),replace('aaaa','aa','b'),replace('aaaa','a','bb'),replace('aaaa','','b'),replace('bbbb','a','c'); +replace('aaaa','a','b') replace('aaaa','aa','b') replace('aaaa','a','bb') replace('aaaa','','b') replace('bbbb','a','c') +bbbb bb bbbbbbbb aaaa bbbb +select replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL') ; +replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL') +this is a REAL test +select soundex(''),soundex('he'),soundex('hello all folks'),soundex('#3556 in bugdb'); +soundex('') soundex('he') soundex('hello all folks') soundex('#3556 in bugdb') + H000 H4142 I51231 +select 'mood' sounds like 'mud'; +'mood' sounds like 'mud' +1 +select 'Glazgo' sounds like 'Liverpool'; +'Glazgo' sounds like 'Liverpool' +0 +select null sounds like 'null'; +null sounds like 'null' +NULL +select 'null' sounds like null; +'null' sounds like null +NULL +select null sounds like null; +null sounds like null +NULL +select md5('hello'); +md5('hello') +5d41402abc4b2a76b9719d911017c592 +select crc32("123"); +crc32("123") +2286445522 +select sha('abc'); +sha('abc') +a9993e364706816aba3e25717850c26c9cd0d89d +select sha1('abc'); +sha1('abc') +a9993e364706816aba3e25717850c26c9cd0d89d +select aes_decrypt(aes_encrypt('abc','1'),'1'); +aes_decrypt(aes_encrypt('abc','1'),'1') +abc +select aes_decrypt(aes_encrypt('abc','1'),1); +aes_decrypt(aes_encrypt('abc','1'),1) +abc +select aes_encrypt(NULL,"a"); +aes_encrypt(NULL,"a") +NULL +select aes_encrypt("a",NULL); +aes_encrypt("a",NULL) +NULL +select aes_decrypt(NULL,"a"); +aes_decrypt(NULL,"a") +NULL +select aes_decrypt("a",NULL); +aes_decrypt("a",NULL) +NULL +select aes_decrypt("a","a"); +aes_decrypt("a","a") +NULL +select aes_decrypt(aes_encrypt("","a"),"a"); +aes_decrypt(aes_encrypt("","a"),"a") + +select repeat('monty',5),concat('*',space(5),'*'); +repeat('monty',5) concat('*',space(5),'*') +montymontymontymontymonty * * +select reverse('abc'),reverse('abcd'); +reverse('abc') reverse('abcd') +cba dcba +select rpad('a',4,'1'),rpad('a',4,'12'),rpad('abcd',3,'12'), rpad(11, 10 , 22), rpad("ab", 10, 22); +rpad('a',4,'1') rpad('a',4,'12') rpad('abcd',3,'12') rpad(11, 10 , 22) rpad("ab", 10, 22) +a111 a121 abc 1122222222 ab22222222 +select lpad('a',4,'1'),lpad('a',4,'12'),lpad('abcd',3,'12'), lpad(11, 10 , 22); +lpad('a',4,'1') lpad('a',4,'12') lpad('abcd',3,'12') lpad(11, 10 , 22) +111a 121a abc 2222222211 +select rpad(741653838,17,'0'),lpad(741653838,17,'0'); +rpad(741653838,17,'0') lpad(741653838,17,'0') +74165383800000000 00000000741653838 +select rpad('abcd',7,'ab'),lpad('abcd',7,'ab'); +rpad('abcd',7,'ab') lpad('abcd',7,'ab') +abcdaba abaabcd +select rpad('abcd',1,'ab'),lpad('abcd',1,'ab'); +rpad('abcd',1,'ab') lpad('abcd',1,'ab') +a a +select rpad('STRING', 20, CONCAT('p','a','d') ); +rpad('STRING', 20, CONCAT('p','a','d') ) +STRINGpadpadpadpadpa +select lpad('STRING', 20, CONCAT('p','a','d') ); +lpad('STRING', 20, CONCAT('p','a','d') ) +padpadpadpadpaSTRING +select LEAST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'),GREATEST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'); +LEAST(NULL,'HARRY','HARRIOT',NULL,'HAROLD') GREATEST(NULL,'HARRY','HARRIOT',NULL,'HAROLD') +NULL NULL +select least(1,2,3) | greatest(16,32,8), least(5,4)*1,greatest(-1.0,1.0)*1,least(3,2,1)*1.0,greatest(1,1.1,1.0),least("10",9),greatest("A","B","0"); +least(1,2,3) | greatest(16,32,8) least(5,4)*1 greatest(-1.0,1.0)*1 least(3,2,1)*1.0 greatest(1,1.1,1.0) least("10",9) greatest("A","B","0") +33 4 1.0 1.0 1.1 9 B +select decode(encode(repeat("a",100000),"monty"),"monty")=repeat("a",100000); +decode(encode(repeat("a",100000),"monty"),"monty")=repeat("a",100000) +1 +select decode(encode("abcdef","monty"),"monty")="abcdef"; +decode(encode("abcdef","monty"),"monty")="abcdef" +1 +select quote('\'\"\\test'); +quote('\'\"\\test') +'\'"\\test' +select quote(concat('abc\'', '\\cba')); +quote(concat('abc\'', '\\cba')) +'abc\'\\cba' +select quote(1/0), quote('\0\Z'); +quote(1/0) quote('\0\Z') +NULL '\0\Z' +select length(quote(concat(char(0),"test"))); +length(quote(concat(char(0),"test"))) +8 +select hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))); +hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))) +27E0E3E6E7E8EAEB27 +select unhex(hex("foobar")), hex(unhex("1234567890ABCDEF")), unhex("345678"), unhex(NULL); +unhex(hex("foobar")) hex(unhex("1234567890ABCDEF")) unhex("345678") unhex(NULL) +foobar 1234567890ABCDEF 4Vx NULL +select hex(unhex("1")), hex(unhex("12")), hex(unhex("123")), hex(unhex("1234")), hex(unhex("12345")), hex(unhex("123456")); +hex(unhex("1")) hex(unhex("12")) hex(unhex("123")) hex(unhex("1234")) hex(unhex("12345")) hex(unhex("123456")) +01 12 0123 1234 012345 123456 +select length(unhex(md5("abrakadabra"))); +length(unhex(md5("abrakadabra"))) +16 +select concat('a', quote(NULL)); +concat('a', quote(NULL)) +aNULL +select reverse(""); +reverse("") + +select insert("aa",100,1,"b"),insert("aa",1,3,"b"),left("aa",-1),substring("a",1,2); +insert("aa",100,1,"b") insert("aa",1,3,"b") left("aa",-1) substring("a",1,2) +aa b a +select elt(2,1),field(NULL,"a","b","c"),reverse(""); +elt(2,1) field(NULL,"a","b","c") reverse("") +NULL 0 +select locate("a","b",2),locate("","a",1); +locate("a","b",2) locate("","a",1) +0 1 +select ltrim("a"),rtrim("a"),trim(BOTH "" from "a"),trim(BOTH " " from "a"); +ltrim("a") rtrim("a") trim(BOTH "" from "a") trim(BOTH " " from "a") +a a a a +select concat("1","2")|0,concat("1",".5")+0.0; +concat("1","2")|0 concat("1",".5")+0.0 +12 1.5 +select substring_index("www.tcx.se","",3); +substring_index("www.tcx.se","",3) + +select length(repeat("a",100000000)),length(repeat("a",1000*64)); +length(repeat("a",100000000)) length(repeat("a",1000*64)) +NULL 64000 +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select position("0" in "baaa" in (1)),position("0" in "1" in (1,2,3)),position("sql" in ("mysql")); +position("0" in "baaa" in (1)) position("0" in "1" in (1,2,3)) position("sql" in ("mysql")) +1 0 3 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'baaa' +select position(("1" in (1,2,3)) in "01"); +position(("1" in (1,2,3)) in "01") +2 +select length(repeat("a",65500)),length(concat(repeat("a",32000),repeat("a",32000))),length(replace("aaaaa","a",concat(repeat("a",10000)))),length(insert(repeat("a",40000),1,30000,repeat("b",50000))); +length(repeat("a",65500)) length(concat(repeat("a",32000),repeat("a",32000))) length(replace("aaaaa","a",concat(repeat("a",10000)))) length(insert(repeat("a",40000),1,30000,repeat("b",50000))) +65500 64000 50000 60000 +select length(repeat("a",1000000)),length(concat(repeat("a",32000),repeat("a",32000),repeat("a",32000))),length(replace("aaaaa","a",concat(repeat("a",32000)))),length(insert(repeat("a",48000),1,1000,repeat("a",48000))); +length(repeat("a",1000000)) length(concat(repeat("a",32000),repeat("a",32000),repeat("a",32000))) length(replace("aaaaa","a",concat(repeat("a",32000)))) length(insert(repeat("a",48000),1,1000,repeat("a",48000))) +1000000 96000 160000 95000 +create table t1 ( domain char(50) ); +insert into t1 VALUES ("hello.de" ), ("test.de" ); +select domain from t1 where concat('@', trim(leading '.' from concat('.', domain))) = '@hello.de'; +domain +hello.de +select domain from t1 where concat('@', trim(leading '.' from concat('.', domain))) = '@test.de'; +domain +test.de +drop table t1; +CREATE TABLE t1 ( +id int(10) unsigned NOT NULL, +title varchar(255) default NULL, +prio int(10) unsigned default NULL, +category int(10) unsigned default NULL, +program int(10) unsigned default NULL, +bugdesc text, +created datetime default NULL, +modified timestamp NOT NULL, +bugstatus int(10) unsigned default NULL, +submitter int(10) unsigned default NULL +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,'Link',1,1,1,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','2001-02-28 08:40:16',20010228084016,0,4); +SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter), '"') FROM t1; +CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter), '"') +"Link";"1";"1";"1";"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"2001-02-28 08:40:16";"20010228084016";"0";"4" +SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugstatus,submitter), '"') FROM t1; +CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugstatus,submitter), '"') +"Link";"1";"1";"1";"0";"4" +SELECT CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter) FROM t1; +CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter) +Link";"1";"1";"1";"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"2001-02-28 08:40:16";"20010228084016";"0";"4 +SELECT bugdesc, REPLACE(bugdesc, 'xxxxxxxxxxxxxxxxxxxx', 'bbbbbbbbbbbbbbbbbbbb') from t1 group by bugdesc; +bugdesc REPLACE(bugdesc, 'xxxxxxxxxxxxxxxxxxxx', 'bbbbbbbbbbbbbbbbbbbb') +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +drop table t1; +CREATE TABLE t1 (id int(11) NOT NULL auto_increment, tmp text NOT NULL, KEY id (id)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 'a545f661efdd1fb66fdee3aab79945bf'); +SELECT 1 FROM t1 WHERE tmp=AES_DECRYPT(tmp,"password"); +1 +DROP TABLE t1; +CREATE TABLE t1 ( +wid int(10) unsigned NOT NULL auto_increment, +data_podp date default NULL, +status_wnio enum('nowy','podp','real','arch') NOT NULL default 'nowy', +PRIMARY KEY(wid) +); +INSERT INTO t1 VALUES (8,NULL,'real'); +INSERT INTO t1 VALUES (9,NULL,'nowy'); +SELECT elt(status_wnio,data_podp) FROM t1 GROUP BY wid; +elt(status_wnio,data_podp) +NULL +NULL +DROP TABLE t1; +CREATE TABLE t1 (title text) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('Congress reconvenes in September to debate welfare and adult education'); +INSERT INTO t1 VALUES ('House passes the CAREERS bill'); +SELECT CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) from t1; +CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) +NULL +</a>.......................... +DROP TABLE t1; +CREATE TABLE t1 (i int, j int); +INSERT INTO t1 VALUES (1,1),(2,2); +SELECT DISTINCT i, ELT(j, '345', '34') FROM t1; +i ELT(j, '345', '34') +1 345 +2 34 +DROP TABLE t1; +create table t1(a char(4)); +insert into t1 values ('one'),(NULL),('two'),('four'); +select a, quote(a), isnull(quote(a)), quote(a) is null, ifnull(quote(a), 'n') from t1; +a quote(a) isnull(quote(a)) quote(a) is null ifnull(quote(a), 'n') +one 'one' 0 0 'one' +NULL NULL 0 0 NULL +two 'two' 0 0 'two' +four 'four' 0 0 'four' +drop table t1; +select trim(trailing 'foo' from 'foo'); +trim(trailing 'foo' from 'foo') + +select trim(leading 'foo' from 'foo'); +trim(leading 'foo' from 'foo') + +select quote(ltrim(concat(' ', 'a'))); +quote(ltrim(concat(' ', 'a'))) +'a' +select quote(trim(concat(' ', 'a'))); +quote(trim(concat(' ', 'a'))) +'a' +CREATE TABLE t1 SELECT 1 UNION SELECT 2 UNION SELECT 3; +SELECT QUOTE('A') FROM t1; +QUOTE('A') +'A' +'A' +'A' +DROP TABLE t1; +select 1=_latin1'1'; +1=_latin1'1' +1 +select _latin1'1'=1; +_latin1'1'=1 +1 +select _latin2'1'=1; +_latin2'1'=1 +1 +select 1=_latin2'1'; +1=_latin2'1' +1 +select _latin1'1'=_latin2'1'; +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation '=' +select row('a','b','c') = row('a','b','c'); +row('a','b','c') = row('a','b','c') +1 +select row('A','b','c') = row('a','b','c'); +row('A','b','c') = row('a','b','c') +1 +select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c'); +row('A' COLLATE latin1_bin,'b','c') = row('a','b','c') +0 +select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); +row('A','b','c') = row('a' COLLATE latin1_bin,'b','c') +0 +select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '=' +select concat(_latin1'a',_latin2'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat' +select concat(_latin1'a',_latin2'a',_latin5'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin5_turkish_ci,COERCIBLE) for operation 'concat' +select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a'); +ERROR HY000: Illegal mix of collations for operation 'concat' +select concat_ws(_latin1'a',_latin2'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat_ws' +select FIELD('b','A','B'); +FIELD('b','A','B') +2 +select FIELD('B','A','B'); +FIELD('B','A','B') +2 +select FIELD('b' COLLATE latin1_bin,'A','B'); +FIELD('b' COLLATE latin1_bin,'A','B') +0 +select FIELD('b','A' COLLATE latin1_bin,'B'); +FIELD('b','A' COLLATE latin1_bin,'B') +0 +select FIELD(_latin2'b','A','B'); +ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' +select FIELD('b',_latin2'A','B'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' +select FIELD('1',_latin2'3','2',1); +FIELD('1',_latin2'3','2',1) +3 +select POSITION(_latin1'B' IN _latin1'abcd'); +POSITION(_latin1'B' IN _latin1'abcd') +2 +select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); +POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin) +0 +select POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd'); +POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd') +0 +select POSITION(_latin1'B' COLLATE latin1_general_ci IN _latin1'abcd' COLLATE latin1_bin); +ERROR HY000: Illegal mix of collations (latin1_bin,EXPLICIT) and (latin1_general_ci,EXPLICIT) for operation 'locate' +select POSITION(_latin1'B' IN _latin2'abcd'); +ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE) and (latin1_swedish_ci,COERCIBLE) for operation 'locate' +select FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'); +FIND_IN_SET(_latin1'B',_latin1'a,b,c,d') +2 +select FIND_IN_SET(_latin1'B' COLLATE latin1_general_ci,_latin1'a,b,c,d' COLLATE latin1_bin); +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'find_in_set' +select FIND_IN_SET(_latin1'B',_latin2'a,b,c,d'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'find_in_set' +select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin1'd',2); +SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin1'd',2) +abcdabc +select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin2'd',2); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'substring_index' +select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_general_ci,_latin1'd' COLLATE latin1_bin,2); +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'substring_index' +select _latin1'B' between _latin1'a' and _latin1'c'; +_latin1'B' between _latin1'a' and _latin1'c' +1 +select _latin1'B' collate latin1_bin between _latin1'a' and _latin1'c'; +_latin1'B' collate latin1_bin between _latin1'a' and _latin1'c' +0 +select _latin1'B' between _latin1'a' collate latin1_bin and _latin1'c'; +_latin1'B' between _latin1'a' collate latin1_bin and _latin1'c' +0 +select _latin1'B' between _latin1'a' and _latin1'c' collate latin1_bin; +_latin1'B' between _latin1'a' and _latin1'c' collate latin1_bin +0 +select _latin2'B' between _latin1'a' and _latin1'b'; +ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'between' +select _latin1'B' between _latin2'a' and _latin1'b'; +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'between' +select _latin1'B' between _latin1'a' and _latin2'b'; +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE) for operation 'between' +select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b'; +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_bin,EXPLICIT), (latin1_swedish_ci,COERCIBLE) for operation 'between' +select _latin1'B' in (_latin1'a',_latin1'b'); +_latin1'B' in (_latin1'a',_latin1'b') +1 +select _latin1'B' collate latin1_bin in (_latin1'a',_latin1'b'); +_latin1'B' collate latin1_bin in (_latin1'a',_latin1'b') +0 +select _latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b'); +_latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b') +0 +select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin); +_latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin) +0 +select _latin2'B' in (_latin1'a',_latin1'b'); +ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' +select _latin1'B' in (_latin2'a',_latin1'b'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' +select _latin1'B' in (_latin1'a',_latin2'b'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE) for operation ' IN ' +select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b'); +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_bin,EXPLICIT), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' +select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin); +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_swedish_ci,COERCIBLE), (latin1_bin,EXPLICIT) for operation ' IN ' +select collation(bin(130)), coercibility(bin(130)); +collation(bin(130)) coercibility(bin(130)) +latin1_swedish_ci 4 +select collation(oct(130)), coercibility(oct(130)); +collation(oct(130)) coercibility(oct(130)) +latin1_swedish_ci 4 +select collation(conv(130,16,10)), coercibility(conv(130,16,10)); +collation(conv(130,16,10)) coercibility(conv(130,16,10)) +latin1_swedish_ci 4 +select collation(hex(130)), coercibility(hex(130)); +collation(hex(130)) coercibility(hex(130)) +latin1_swedish_ci 4 +select collation(char(130)), coercibility(hex(130)); +collation(char(130)) coercibility(hex(130)) +binary 4 +select collation(format(130,10)), coercibility(format(130,10)); +collation(format(130,10)) coercibility(format(130,10)) +latin1_swedish_ci 4 +select collation(lcase(_latin2'a')), coercibility(lcase(_latin2'a')); +collation(lcase(_latin2'a')) coercibility(lcase(_latin2'a')) +latin2_general_ci 4 +select collation(ucase(_latin2'a')), coercibility(ucase(_latin2'a')); +collation(ucase(_latin2'a')) coercibility(ucase(_latin2'a')) +latin2_general_ci 4 +select collation(left(_latin2'a',1)), coercibility(left(_latin2'a',1)); +collation(left(_latin2'a',1)) coercibility(left(_latin2'a',1)) +latin2_general_ci 4 +select collation(right(_latin2'a',1)), coercibility(right(_latin2'a',1)); +collation(right(_latin2'a',1)) coercibility(right(_latin2'a',1)) +latin2_general_ci 4 +select collation(substring(_latin2'a',1,1)), coercibility(substring(_latin2'a',1,1)); +collation(substring(_latin2'a',1,1)) coercibility(substring(_latin2'a',1,1)) +latin2_general_ci 4 +select collation(concat(_latin2'a',_latin2'b')), coercibility(concat(_latin2'a',_latin2'b')); +collation(concat(_latin2'a',_latin2'b')) coercibility(concat(_latin2'a',_latin2'b')) +latin2_general_ci 4 +select collation(lpad(_latin2'a',4,_latin2'b')), coercibility(lpad(_latin2'a',4,_latin2'b')); +collation(lpad(_latin2'a',4,_latin2'b')) coercibility(lpad(_latin2'a',4,_latin2'b')) +latin2_general_ci 4 +select collation(rpad(_latin2'a',4,_latin2'b')), coercibility(rpad(_latin2'a',4,_latin2'b')); +collation(rpad(_latin2'a',4,_latin2'b')) coercibility(rpad(_latin2'a',4,_latin2'b')) +latin2_general_ci 4 +select collation(concat_ws(_latin2'a',_latin2'b')), coercibility(concat_ws(_latin2'a',_latin2'b')); +collation(concat_ws(_latin2'a',_latin2'b')) coercibility(concat_ws(_latin2'a',_latin2'b')) +latin2_general_ci 4 +select collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')), coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c')); +collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')) coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c')) +latin2_general_ci 4 +select collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')), coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' ')); +collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')) coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' ')) +latin2_general_ci 4 +select collation(trim(_latin2' a ')), coercibility(trim(_latin2' a ')); +collation(trim(_latin2' a ')) coercibility(trim(_latin2' a ')) +latin2_general_ci 4 +select collation(ltrim(_latin2' a ')), coercibility(ltrim(_latin2' a ')); +collation(ltrim(_latin2' a ')) coercibility(ltrim(_latin2' a ')) +latin2_general_ci 4 +select collation(rtrim(_latin2' a ')), coercibility(rtrim(_latin2' a ')); +collation(rtrim(_latin2' a ')) coercibility(rtrim(_latin2' a ')) +latin2_general_ci 4 +select collation(trim(LEADING _latin2' ' FROM _latin2'a')), coercibility(trim(LEADING _latin2'a' FROM _latin2'a')); +collation(trim(LEADING _latin2' ' FROM _latin2'a')) coercibility(trim(LEADING _latin2'a' FROM _latin2'a')) +latin2_general_ci 4 +select collation(trim(TRAILING _latin2' ' FROM _latin2'a')), coercibility(trim(TRAILING _latin2'a' FROM _latin2'a')); +collation(trim(TRAILING _latin2' ' FROM _latin2'a')) coercibility(trim(TRAILING _latin2'a' FROM _latin2'a')) +latin2_general_ci 4 +select collation(trim(BOTH _latin2' ' FROM _latin2'a')), coercibility(trim(BOTH _latin2'a' FROM _latin2'a')); +collation(trim(BOTH _latin2' ' FROM _latin2'a')) coercibility(trim(BOTH _latin2'a' FROM _latin2'a')) +latin2_general_ci 4 +select collation(repeat(_latin2'a',10)), coercibility(repeat(_latin2'a',10)); +collation(repeat(_latin2'a',10)) coercibility(repeat(_latin2'a',10)) +latin2_general_ci 4 +select collation(reverse(_latin2'ab')), coercibility(reverse(_latin2'ab')); +collation(reverse(_latin2'ab')) coercibility(reverse(_latin2'ab')) +latin2_general_ci 4 +select collation(quote(_latin2'ab')), coercibility(quote(_latin2'ab')); +collation(quote(_latin2'ab')) coercibility(quote(_latin2'ab')) +latin2_general_ci 4 +select collation(soundex(_latin2'ab')), coercibility(soundex(_latin2'ab')); +collation(soundex(_latin2'ab')) coercibility(soundex(_latin2'ab')) +latin2_general_ci 4 +select collation(substring(_latin2'ab',1)), coercibility(substring(_latin2'ab',1)); +collation(substring(_latin2'ab',1)) coercibility(substring(_latin2'ab',1)) +latin2_general_ci 4 +select collation(insert(_latin2'abcd',2,3,_latin2'ef')), coercibility(insert(_latin2'abcd',2,3,_latin2'ef')); +collation(insert(_latin2'abcd',2,3,_latin2'ef')) coercibility(insert(_latin2'abcd',2,3,_latin2'ef')) +latin2_general_ci 4 +select collation(replace(_latin2'abcd',_latin2'b',_latin2'B')), coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B')); +collation(replace(_latin2'abcd',_latin2'b',_latin2'B')) coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B')) +latin2_general_ci 4 +select collation(encode('abcd','ab')), coercibility(encode('abcd','ab')); +collation(encode('abcd','ab')) coercibility(encode('abcd','ab')) +binary 4 +create table t1 +select +bin(130), +oct(130), +conv(130,16,10), +hex(130), +char(130), +format(130,10), +left(_latin2'a',1), +right(_latin2'a',1), +lcase(_latin2'a'), +ucase(_latin2'a'), +substring(_latin2'a',1,1), +concat(_latin2'a',_latin2'b'), +lpad(_latin2'a',4,_latin2'b'), +rpad(_latin2'a',4,_latin2'b'), +concat_ws(_latin2'a',_latin2'b'), +make_set(255,_latin2'a',_latin2'b',_latin2'c'), +export_set(255,_latin2'y',_latin2'n',_latin2' '), +trim(_latin2' a '), +ltrim(_latin2' a '), +rtrim(_latin2' a '), +trim(LEADING _latin2' ' FROM _latin2' a '), +trim(TRAILING _latin2' ' FROM _latin2' a '), +trim(BOTH _latin2' ' FROM _latin2' a '), +repeat(_latin2'a',10), +reverse(_latin2'ab'), +quote(_latin2'ab'), +soundex(_latin2'ab'), +substring(_latin2'ab',1), +insert(_latin2'abcd',2,3,_latin2'ef'), +replace(_latin2'abcd',_latin2'b',_latin2'B'), +encode('abcd','ab') +; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `bin(130)` varchar(64) DEFAULT NULL, + `oct(130)` varchar(64) DEFAULT NULL, + `conv(130,16,10)` varchar(64) DEFAULT NULL, + `hex(130)` varchar(6) NOT NULL DEFAULT '', + `char(130)` varbinary(4) NOT NULL DEFAULT '', + `format(130,10)` varchar(37) NOT NULL DEFAULT '', + `left(_latin2'a',1)` varchar(1) CHARACTER SET latin2 NOT NULL DEFAULT '', + `right(_latin2'a',1)` varchar(1) CHARACTER SET latin2 NOT NULL DEFAULT '', + `lcase(_latin2'a')` varchar(1) CHARACTER SET latin2 NOT NULL DEFAULT '', + `ucase(_latin2'a')` varchar(1) CHARACTER SET latin2 NOT NULL DEFAULT '', + `substring(_latin2'a',1,1)` varchar(1) CHARACTER SET latin2 NOT NULL DEFAULT '', + `concat(_latin2'a',_latin2'b')` varchar(2) CHARACTER SET latin2 NOT NULL DEFAULT '', + `lpad(_latin2'a',4,_latin2'b')` varchar(4) CHARACTER SET latin2 NOT NULL DEFAULT '', + `rpad(_latin2'a',4,_latin2'b')` varchar(4) CHARACTER SET latin2 NOT NULL DEFAULT '', + `concat_ws(_latin2'a',_latin2'b')` varchar(1) CHARACTER SET latin2 NOT NULL DEFAULT '', + `make_set(255,_latin2'a',_latin2'b',_latin2'c')` varchar(5) CHARACTER SET latin2 NOT NULL DEFAULT '', + `export_set(255,_latin2'y',_latin2'n',_latin2' ')` varchar(127) CHARACTER SET latin2 NOT NULL DEFAULT '', + `trim(_latin2' a ')` varchar(3) CHARACTER SET latin2 NOT NULL DEFAULT '', + `ltrim(_latin2' a ')` varchar(3) CHARACTER SET latin2 NOT NULL DEFAULT '', + `rtrim(_latin2' a ')` varchar(3) CHARACTER SET latin2 NOT NULL DEFAULT '', + `trim(LEADING _latin2' ' FROM _latin2' a ')` varchar(3) CHARACTER SET latin2 NOT NULL DEFAULT '', + `trim(TRAILING _latin2' ' FROM _latin2' a ')` varchar(3) CHARACTER SET latin2 NOT NULL DEFAULT '', + `trim(BOTH _latin2' ' FROM _latin2' a ')` varchar(3) CHARACTER SET latin2 NOT NULL DEFAULT '', + `repeat(_latin2'a',10)` varchar(10) CHARACTER SET latin2 NOT NULL DEFAULT '', + `reverse(_latin2'ab')` varchar(2) CHARACTER SET latin2 NOT NULL DEFAULT '', + `quote(_latin2'ab')` varchar(6) CHARACTER SET latin2 NOT NULL DEFAULT '', + `soundex(_latin2'ab')` varchar(4) CHARACTER SET latin2 NOT NULL DEFAULT '', + `substring(_latin2'ab',1)` varchar(2) CHARACTER SET latin2 NOT NULL DEFAULT '', + `insert(_latin2'abcd',2,3,_latin2'ef')` varchar(6) CHARACTER SET latin2 NOT NULL DEFAULT '', + `replace(_latin2'abcd',_latin2'b',_latin2'B')` varchar(4) CHARACTER SET latin2 NOT NULL DEFAULT '', + `encode('abcd','ab')` varbinary(4) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a char character set latin2); +insert into t1 values (null); +select charset(a), collation(a), coercibility(a) from t1; +charset(a) collation(a) coercibility(a) +latin2 latin2_general_ci 2 +drop table t1; +select charset(null), collation(null), coercibility(null); +charset(null) collation(null) coercibility(null) +binary binary 5 +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (a int, b int); +INSERT INTO t1 VALUES (1,1),(2,2); +INSERT INTO t2 VALUES (2,2),(3,3); +select t1.*,t2.* from t1 left join t2 on (t1.b=t2.b) +where collation(t2.a) = _utf8'binary' order by t1.a,t2.a; +a b a b +1 1 NULL NULL +2 2 2 2 +select t1.*,t2.* from t1 left join t2 on (t1.b=t2.b) +where charset(t2.a) = _utf8'binary' order by t1.a,t2.a; +a b a b +1 1 NULL NULL +2 2 2 2 +select t1.*,t2.* from t1 left join t2 on (t1.b=t2.b) +where coercibility(t2.a) = 2 order by t1.a,t2.a; +a b a b +1 1 NULL NULL +2 2 2 2 +DROP TABLE t1, t2; +select SUBSTR('abcdefg',3,2); +SUBSTR('abcdefg',3,2) +cd +select SUBSTRING('abcdefg',3,2); +SUBSTRING('abcdefg',3,2) +cd +select SUBSTR('abcdefg',-3,2) FROM DUAL; +SUBSTR('abcdefg',-3,2) +ef +select SUBSTR('abcdefg',-1,5) FROM DUAL; +SUBSTR('abcdefg',-1,5) +g +select SUBSTR('abcdefg',0,0) FROM DUAL; +SUBSTR('abcdefg',0,0) + +select SUBSTR('abcdefg',-1,-1) FROM DUAL; +SUBSTR('abcdefg',-1,-1) + +select SUBSTR('abcdefg',1,-1) FROM DUAL; +SUBSTR('abcdefg',1,-1) + +create table t7 (s1 char); +select * from t7 +where concat(s1 collate latin1_general_ci,s1 collate latin1_swedish_ci) = 'AA'; +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_swedish_ci,EXPLICIT) for operation 'concat' +drop table t7; +select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2); +substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2) substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2) +1abcd;2abcd 3abcd;4abcd +explain extended select md5('hello'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select md5('hello') AS `md5('hello')` +explain extended select sha('abc'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select sha('abc') AS `sha('abc')` +explain extended select sha1('abc'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select sha('abc') AS `sha1('abc')` +explain extended select soundex(''); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select soundex('') AS `soundex('')` +explain extended select 'mood' sounds like 'mud'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select (soundex('mood') = soundex('mud')) AS `'mood' sounds like 'mud'` +explain extended select aes_decrypt(aes_encrypt('abc','1'),'1'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select aes_decrypt(aes_encrypt('abc','1'),'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')` +explain extended select concat('*',space(5),'*'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select concat('*',repeat(' ',5),'*') AS `concat('*',space(5),'*')` +explain extended select reverse('abc'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select reverse('abc') AS `reverse('abc')` +explain extended select rpad('a',4,'1'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select rpad('a',4,'1') AS `rpad('a',4,'1')` +explain extended select lpad('a',4,'1'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select lpad('a',4,'1') AS `lpad('a',4,'1')` +explain extended select concat_ws(',','',NULL,'a'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select concat_ws(',','',NULL,'a') AS `concat_ws(',','',NULL,'a')` +explain extended select make_set(255,_latin2'a', _latin2'b', _latin2'c'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a', _latin2'b', _latin2'c')` +explain extended select elt(2,1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select elt(2,1) AS `elt(2,1)` +explain extended select locate("a","b",2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select locate('a','b',2) AS `locate("a","b",2)` +explain extended select format(130,10); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select format(130,10) AS `format(130,10)` +explain extended select char(0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select char(0) AS `char(0)` +explain extended select conv(130,16,10); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select conv(130,16,10) AS `conv(130,16,10)` +explain extended select hex(130); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select hex(130) AS `hex(130)` +explain extended select binary 'HE'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select cast('HE' as char charset binary) AS `binary 'HE'` +explain extended select export_set(255,_latin2'y', _latin2'n', _latin2' '); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y', _latin2'n', _latin2' ')` +explain extended select FIELD('b' COLLATE latin1_bin,'A','B'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select field(('b' collate latin1_bin),'A','B') AS `FIELD('b' COLLATE latin1_bin,'A','B')` +explain extended select FIND_IN_SET(_latin1'B', _latin1'a,b,c,d'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B', _latin1'a,b,c,d')` +explain extended select collation(conv(130,16,10)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select collation(conv(130,16,10)) AS `collation(conv(130,16,10))` +explain extended select coercibility(conv(130,16,10)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))` +explain extended select length('\n\t\r\b\0\_\%\\'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select length('\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')` +explain extended select bit_length('\n\t\r\b\0\_\%\\'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select bit_length('\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')` +explain extended select bit_length('\n\t\r\b\0\_\%\\'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select bit_length('\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')` +explain extended select concat('monty',' was here ','again'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select concat('monty',' was here ','again') AS `concat('monty',' was here ','again')` +explain extended select length('hello'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select length('hello') AS `length('hello')` +explain extended select char(ascii('h')); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select char(ascii('h')) AS `char(ascii('h'))` +explain extended select ord('h'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select ord('h') AS `ord('h')` +explain extended select quote(1/0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select quote((1 / 0)) AS `quote(1/0)` +explain extended select crc32("123"); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select crc32('123') AS `crc32("123")` +explain extended select replace('aaaa','a','b'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select replace('aaaa','a','b') AS `replace('aaaa','a','b')` +explain extended select insert('txs',2,1,'hi'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select insert('txs',2,1,'hi') AS `insert('txs',2,1,'hi')` +explain extended select left(_latin2'a',1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select left(_latin2'a',1) AS `left(_latin2'a',1)` +explain extended select right(_latin2'a',1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select right(_latin2'a',1) AS `right(_latin2'a',1)` +explain extended select lcase(_latin2'a'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select lcase(_latin2'a') AS `lcase(_latin2'a')` +explain extended select ucase(_latin2'a'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select ucase(_latin2'a') AS `ucase(_latin2'a')` +explain extended select SUBSTR('abcdefg',3,2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select substr('abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)` +explain extended select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select substring_index('1abcd;2abcd;3abcd;4abcd',';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)` +explain extended select trim(_latin2' a '); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select trim(_latin2' a ') AS `trim(_latin2' a ')` +explain extended select ltrim(_latin2' a '); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select ltrim(_latin2' a ') AS `ltrim(_latin2' a ')` +explain extended select rtrim(_latin2' a '); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select rtrim(_latin2' a ') AS `rtrim(_latin2' a ')` +explain extended select decode(encode(repeat("a",100000),"monty"),"monty"); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select decode(encode(repeat('a',100000),'monty'),'monty') AS `decode(encode(repeat("a",100000),"monty"),"monty")` +SELECT lpad(12345, 5, "#"); +lpad(12345, 5, "#") +12345 +SELECT conv(71, 10, 36), conv('1Z', 36, 10); +conv(71, 10, 36) conv('1Z', 36, 10) +1Z 71 +SELECT conv(71, 10, 37), conv('1Z', 37, 10), conv(0,1,10),conv(0,0,10), conv(0,-1,10); +conv(71, 10, 37) conv('1Z', 37, 10) conv(0,1,10) conv(0,0,10) conv(0,-1,10) +NULL NULL NULL NULL NULL +create table t1 (id int(1), str varchar(10)) DEFAULT CHARSET=utf8; +insert into t1 values (1,'aaaaaaaaaa'), (2,'bbbbbbbbbb'); +create table t2 (id int(1), str varchar(10)) DEFAULT CHARSET=utf8; +insert into t2 values (1,'cccccccccc'), (2,'dddddddddd'); +select substring(concat(t1.str, t2.str), 1, 15) "name" from t1, t2 +where t2.id=t1.id order by name; +name +aaaaaaaaaaccccc +bbbbbbbbbbddddd +drop table t1, t2; +create table t1 (c1 INT, c2 INT UNSIGNED); +insert into t1 values ('21474836461','21474836461'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +Warning 1264 Out of range value for column 'c2' at row 1 +insert into t1 values ('-21474836461','-21474836461'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +Warning 1264 Out of range value for column 'c2' at row 1 +show warnings; +Level Code Message +Warning 1264 Out of range value for column 'c1' at row 1 +Warning 1264 Out of range value for column 'c2' at row 1 +select * from t1; +c1 c2 +2147483647 4294967295 +-2147483648 0 +drop table t1; +select left(1234, 3) + 0; +left(1234, 3) + 0 +123 +create table t1 (a int not null primary key, b varchar(40), c datetime); +insert into t1 (a,b,c) values (1,'Tom','2004-12-10 12:13:14'),(2,'ball games','2004-12-10 12:13:14'), (3,'Basil','2004-12-10 12:13:14'), (4,'Dean','2004-12-10 12:13:14'),(5,'Ellis','2004-12-10 12:13:14'), (6,'Serg','2004-12-10 12:13:14'), (7,'Sergei','2004-12-10 12:13:14'),(8,'Georg','2004-12-10 12:13:14'),(9,'Salle','2004-12-10 12:13:14'),(10,'Sinisa','2004-12-10 12:13:14'); +select count(*) as total, left(c,10) as reg from t1 group by reg order by reg desc limit 0,12; +total reg +10 2004-12-10 +drop table t1; +select trim(null from 'kate') as "must_be_null"; +must_be_null +NULL +select trim('xyz' from null) as "must_be_null"; +must_be_null +NULL +select trim(leading NULL from 'kate') as "must_be_null"; +must_be_null +NULL +select trim(trailing NULL from 'xyz') as "must_be_null"; +must_be_null +NULL +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +a bigint(20) unsigned default NULL, +PRIMARY KEY (id) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES +('0','16307858876001849059'); +SELECT CONV('e251273eb74a8ee3', 16, 10); +CONV('e251273eb74a8ee3', 16, 10) +16307858876001849059 +EXPLAIN +SELECT id +FROM t1 +WHERE a = 16307858876001849059; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +EXPLAIN +SELECT id +FROM t1 +WHERE a = CONV('e251273eb74a8ee3', 16, 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +DROP TABLE t1; +SELECT CHAR(NULL,121,83,81,'76') as my_column; +my_column +ySQL +SELECT CHAR_LENGTH(CHAR(NULL,121,83,81,'76')) as my_column; +my_column +4 +CREATE TABLE t1 (id int PRIMARY KEY, str char(255) NOT NULL); +CREATE TABLE t2 (id int NOT NULL UNIQUE); +INSERT INTO t2 VALUES (1),(2); +INSERT INTO t1 VALUES (1, aes_encrypt('foo', 'bar')); +INSERT INTO t1 VALUES (2, 'not valid'); +SELECT t1.id, aes_decrypt(str, 'bar') FROM t1, t2 WHERE t1.id = t2.id; +id aes_decrypt(str, 'bar') +1 foo +2 NULL +SELECT t1.id, aes_decrypt(str, 'bar') FROM t1, t2 WHERE t1.id = t2.id +ORDER BY t1.id; +id aes_decrypt(str, 'bar') +1 foo +2 NULL +DROP TABLE t1, t2; +select field(0,NULL,1,0), field("",NULL,"bar",""), field(0.0,NULL,1.0,0.0); +field(0,NULL,1,0) field("",NULL,"bar","") field(0.0,NULL,1.0,0.0) +3 3 3 +select field(NULL,1,2,NULL), field(NULL,1,2,0); +field(NULL,1,2,NULL) field(NULL,1,2,0) +0 0 +CREATE TABLE t1 (str varchar(20) PRIMARY KEY); +CREATE TABLE t2 (num int primary key); +INSERT INTO t1 VALUES ('notnumber'); +INSERT INTO t2 VALUES (0), (1); +SELECT * FROM t1, t2 WHERE num=str; +str num +notnumber 0 +SELECT * FROM t1, t2 WHERE num=substring(str from 1 for 6); +str num +notnumber 0 +DROP TABLE t1,t2; +CREATE TABLE t1( +id int(11) NOT NULL auto_increment, +pc int(11) NOT NULL default '0', +title varchar(20) default NULL, +PRIMARY KEY (id) +); +INSERT INTO t1 VALUES +(1, 0, 'Main'), +(2, 1, 'Toys'), +(3, 1, 'Games'); +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 +FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id +LEFT JOIN t1 AS t3 ON t2.pc=t3.id; +id col1 +1 Main +2 Main->Toys +3 Main->Games +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 +FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id +LEFT JOIN t1 AS t3 ON t2.pc=t3.id +WHERE CONCAT_WS('->', t3.title, t2.title, t1.title) LIKE '%Toys%'; +id col1 +2 Main->Toys +DROP TABLE t1; +CREATE TABLE t1( +trackid int(10) unsigned NOT NULL auto_increment, +trackname varchar(100) NOT NULL default '', +PRIMARY KEY (trackid) +); +CREATE TABLE t2( +artistid int(10) unsigned NOT NULL auto_increment, +artistname varchar(100) NOT NULL default '', +PRIMARY KEY (artistid) +); +CREATE TABLE t3( +trackid int(10) unsigned NOT NULL, +artistid int(10) unsigned NOT NULL, +PRIMARY KEY (trackid,artistid) +); +INSERT INTO t1 VALUES (1, 'April In Paris'), (2, 'Autumn In New York'); +INSERT INTO t2 VALUES (1, 'Vernon Duke'); +INSERT INTO t3 VALUES (1,1); +SELECT CONCAT_WS(' ', trackname, artistname) trackname, artistname +FROM t1 LEFT JOIN t3 ON t1.trackid=t3.trackid +LEFT JOIN t2 ON t2.artistid=t3.artistid +WHERE CONCAT_WS(' ', trackname, artistname) LIKE '%In%'; +trackname artistname +April In Paris Vernon Duke Vernon Duke +Autumn In New York NULL +DROP TABLE t1,t2,t3; +create table t1 (b varchar(5)); +insert t1 values ('ab'), ('abc'), ('abcd'), ('abcde'); +select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1; +b substring(b,1) substring(b,-1) substring(b,-2) substring(b,-3) substring(b,-4) substring(b,-5) +ab ab b ab +abc abc c bc abc +abcd abcd d cd bcd abcd +abcde abcde e de cde bcde abcde +select * from (select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1) t; +b substring(b,1) substring(b,-1) substring(b,-2) substring(b,-3) substring(b,-4) substring(b,-5) +ab ab b ab +abc abc c bc abc +abcd abcd d cd bcd abcd +abcde abcde e de cde bcde abcde +drop table t1; +select hex(29223372036854775809), hex(-29223372036854775809); +hex(29223372036854775809) hex(-29223372036854775809) +FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF +create table t1 (i int); +insert into t1 values (1000000000),(1); +select lpad(i, 7, ' ') as t from t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def t 253 7 7 Y 128 31 63 +t +1000000 + 1 +select rpad(i, 7, ' ') as t from t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def t 253 7 7 Y 128 31 63 +t +1000000 +1 +drop table t1; +select load_file("lkjlkj"); +load_file("lkjlkj") +NULL +select ifnull(load_file("lkjlkj"),"it's null"); +ifnull(load_file("lkjlkj"),"it's null") +it's null +create table t1 (f1 varchar(4), f2 varchar(64), unique key k1 (f1,f2)); +insert into t1 values ( 'test',md5('test')), ('test', sha('test')); +select * from t1 where f1='test' and (f2= md5("test") or f2= md5("TEST")); +f1 f2 +test 098f6bcd4621d373cade4e832627b4f6 +select * from t1 where f1='test' and (f2= md5("TEST") or f2= md5("test")); +f1 f2 +test 098f6bcd4621d373cade4e832627b4f6 +select * from t1 where f1='test' and (f2= sha("test") or f2= sha("TEST")); +f1 f2 +test a94a8fe5ccb19ba61c4c0873d391e987982fbbd3 +select * from t1 where f1='test' and (f2= sha("TEST") or f2= sha("test")); +f1 f2 +test a94a8fe5ccb19ba61c4c0873d391e987982fbbd3 +drop table t1; +CREATE TABLE t1 (a varchar(10)); +INSERT INTO t1 VALUES ('abc'), ('xyz'); +SELECT a, CONCAT(a,' ',a) AS c FROM t1 +HAVING LEFT(c,LENGTH(c)-INSTR(REVERSE(c)," ")) = a; +a c +abc abc abc +xyz xyz xyz +SELECT a, CONCAT(a,' ',a) AS c FROM t1 +HAVING LEFT(CONCAT(a,' ',a), +LENGTH(CONCAT(a,' ',a))- +INSTR(REVERSE(CONCAT(a,' ',a))," ")) = a; +a c +abc abc abc +xyz xyz xyz +DROP TABLE t1; +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yaddy'); +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(s) > 'ab'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(`test`.`t1`.`s`) > 'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM('y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(both 'y' from `test`.`t1`.`s`) > 'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(LEADING 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(leading 'y' from `test`.`t1`.`s`) > 'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(TRAILING 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(trailing 'y' from `test`.`t1`.`s`) > 'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(BOTH 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(both 'y' from `test`.`t1`.`s`) > 'ab') +DROP TABLE t1; +End of 4.1 tests +create table t1 (d decimal default null); +insert into t1 values (null); +select format(d, 2) from t1; +format(d, 2) +NULL +drop table t1; +create table t1 (c varchar(40)); +insert into t1 values ('y,abc'),('y,abc'); +select c, substring_index(lcase(c), @q:=',', -1) as res from t1; +c res +y,abc abc +y,abc abc +drop table t1; +select cast(rtrim(' 20.06 ') as decimal(19,2)); +cast(rtrim(' 20.06 ') as decimal(19,2)) +20.06 +select cast(ltrim(' 20.06 ') as decimal(19,2)); +cast(ltrim(' 20.06 ') as decimal(19,2)) +20.06 +select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)); +cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)) +20.06 +select conv("18383815659218730760",10,10) + 0; +conv("18383815659218730760",10,10) + 0 +1.8383815659219e+19 +select "18383815659218730760" + 0; +"18383815659218730760" + 0 +1.8383815659219e+19 +CREATE TABLE t1 (code varchar(10)); +INSERT INTO t1 VALUES ('a12'), ('A12'), ('a13'); +SELECT ASCII(code), code FROM t1 WHERE code='A12'; +ASCII(code) code +97 a12 +65 A12 +SELECT ASCII(code), code FROM t1 WHERE code='A12' AND ASCII(code)=65; +ASCII(code) code +65 A12 +INSERT INTO t1 VALUES ('a12 '), ('A12 '); +SELECT LENGTH(code), code FROM t1 WHERE code='A12'; +LENGTH(code) code +3 a12 +3 A12 +4 a12 +5 A12 +SELECT LENGTH(code), code FROM t1 WHERE code='A12' AND LENGTH(code)=5; +LENGTH(code) code +5 A12 +ALTER TABLE t1 ADD INDEX (code); +CREATE TABLE t2 (id varchar(10) PRIMARY KEY); +INSERT INTO t2 VALUES ('a11'), ('a12'), ('a13'), ('a14'); +SELECT * FROM t1 INNER JOIN t2 ON t1.code=t2.id +WHERE t2.id='a12' AND (LENGTH(code)=5 OR code < 'a00'); +code id +A12 a12 +EXPLAIN EXTENDED +SELECT * FROM t1 INNER JOIN t2 ON code=id +WHERE id='a12' AND (LENGTH(code)=5 OR code < 'a00'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 const PRIMARY PRIMARY 12 const 1 100.00 Using index +1 SIMPLE t1 ref code code 13 const 1 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`code` AS `code`,'a12' AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`code` = 'a12') and (length(`test`.`t1`.`code`) = 5)) +DROP TABLE t1,t2; +select encode(NULL, NULL); +encode(NULL, NULL) +NULL +select encode("data", NULL); +encode("data", NULL) +NULL +select encode(NULL, "password"); +encode(NULL, "password") +NULL +select decode(NULL, NULL); +decode(NULL, NULL) +NULL +select decode("data", NULL); +decode("data", NULL) +NULL +select decode(NULL, "password"); +decode(NULL, "password") +NULL +select format(NULL, NULL); +format(NULL, NULL) +NULL +select format(pi(), NULL); +format(pi(), NULL) +NULL +select format(NULL, 2); +format(NULL, 2) +NULL +select benchmark(NULL, NULL); +benchmark(NULL, NULL) +NULL +select benchmark(0, NULL); +benchmark(0, NULL) +0 +select benchmark(100, NULL); +benchmark(100, NULL) +0 +select benchmark(NULL, 1+1); +benchmark(NULL, 1+1) +NULL +set @password="password"; +set @my_data="clear text to encode"; +select md5(encode(@my_data, "password")); +md5(encode(@my_data, "password")) +44320fd2b4a0ec92faa2da2122def917 +select md5(encode(@my_data, _utf8 "password")); +md5(encode(@my_data, _utf8 "password")) +44320fd2b4a0ec92faa2da2122def917 +select md5(encode(@my_data, binary "password")); +md5(encode(@my_data, binary "password")) +44320fd2b4a0ec92faa2da2122def917 +select md5(encode(@my_data, _latin1 "password")); +md5(encode(@my_data, _latin1 "password")) +44320fd2b4a0ec92faa2da2122def917 +select md5(encode(@my_data, _koi8r "password")); +md5(encode(@my_data, _koi8r "password")) +44320fd2b4a0ec92faa2da2122def917 +select md5(encode(@my_data, (select "password" from dual))); +md5(encode(@my_data, (select "password" from dual))) +44320fd2b4a0ec92faa2da2122def917 +select md5(encode(@my_data, concat("pass", "word"))); +md5(encode(@my_data, concat("pass", "word"))) +44320fd2b4a0ec92faa2da2122def917 +select md5(encode(@my_data, @password)); +md5(encode(@my_data, @password)) +44320fd2b4a0ec92faa2da2122def917 +set @my_data="binary encoded data"; +select md5(decode(@my_data, "password")); +md5(decode(@my_data, "password")) +5bea8c394368dbc03b76684483b7756b +select md5(decode(@my_data, _utf8 "password")); +md5(decode(@my_data, _utf8 "password")) +5bea8c394368dbc03b76684483b7756b +select md5(decode(@my_data, binary "password")); +md5(decode(@my_data, binary "password")) +5bea8c394368dbc03b76684483b7756b +select md5(decode(@my_data, _latin1 "password")); +md5(decode(@my_data, _latin1 "password")) +5bea8c394368dbc03b76684483b7756b +select md5(decode(@my_data, _koi8r "password")); +md5(decode(@my_data, _koi8r "password")) +5bea8c394368dbc03b76684483b7756b +select md5(decode(@my_data, (select "password" from dual))); +md5(decode(@my_data, (select "password" from dual))) +5bea8c394368dbc03b76684483b7756b +select md5(decode(@my_data, concat("pass", "word"))); +md5(decode(@my_data, concat("pass", "word"))) +5bea8c394368dbc03b76684483b7756b +select md5(decode(@my_data, @password)); +md5(decode(@my_data, @password)) +5bea8c394368dbc03b76684483b7756b +set @dec=5; +select format(pi(), (1+1)); +format(pi(), (1+1)) +3.14 +select format(pi(), (select 3 from dual)); +format(pi(), (select 3 from dual)) +3.142 +select format(pi(), @dec); +format(pi(), @dec) +3.14159 +set @bench_count=10; +select benchmark(10, pi()); +benchmark(10, pi()) +0 +select benchmark(5+5, pi()); +benchmark(5+5, pi()) +0 +select benchmark((select 10 from dual), pi()); +benchmark((select 10 from dual), pi()) +0 +select benchmark(@bench_count, pi()); +benchmark(@bench_count, pi()) +0 +select locate('he','hello',-2); +locate('he','hello',-2) +0 +select locate('lo','hello',-4294967295); +locate('lo','hello',-4294967295) +0 +select locate('lo','hello',4294967295); +locate('lo','hello',4294967295) +0 +select locate('lo','hello',-4294967296); +locate('lo','hello',-4294967296) +0 +select locate('lo','hello',4294967296); +locate('lo','hello',4294967296) +0 +select locate('lo','hello',-4294967297); +locate('lo','hello',-4294967297) +0 +select locate('lo','hello',4294967297); +locate('lo','hello',4294967297) +0 +select locate('lo','hello',-18446744073709551615); +locate('lo','hello',-18446744073709551615) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select locate('lo','hello',18446744073709551615); +locate('lo','hello',18446744073709551615) +0 +select locate('lo','hello',-18446744073709551616); +locate('lo','hello',-18446744073709551616) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select locate('lo','hello',18446744073709551616); +locate('lo','hello',18446744073709551616) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select locate('lo','hello',-18446744073709551617); +locate('lo','hello',-18446744073709551617) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select locate('lo','hello',18446744073709551617); +locate('lo','hello',18446744073709551617) +0 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', 10); +left('hello', 10) +hello +select left('hello', 0); +left('hello', 0) + +select left('hello', -1); +left('hello', -1) + +select left('hello', -4294967295); +left('hello', -4294967295) + +select left('hello', 4294967295); +left('hello', 4294967295) +hello +select left('hello', -4294967296); +left('hello', -4294967296) + +select left('hello', 4294967296); +left('hello', 4294967296) +hello +select left('hello', -4294967297); +left('hello', -4294967297) + +select left('hello', 4294967297); +left('hello', 4294967297) +hello +select left('hello', -18446744073709551615); +left('hello', -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', 18446744073709551615); +left('hello', 18446744073709551615) +hello +select left('hello', -18446744073709551616); +left('hello', -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', 18446744073709551616); +left('hello', 18446744073709551616) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', -18446744073709551617); +left('hello', -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select left('hello', 18446744073709551617); +left('hello', 18446744073709551617) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', 10); +right('hello', 10) +hello +select right('hello', 0); +right('hello', 0) + +select right('hello', -1); +right('hello', -1) + +select right('hello', -4294967295); +right('hello', -4294967295) + +select right('hello', 4294967295); +right('hello', 4294967295) +hello +select right('hello', -4294967296); +right('hello', -4294967296) + +select right('hello', 4294967296); +right('hello', 4294967296) +hello +select right('hello', -4294967297); +right('hello', -4294967297) + +select right('hello', 4294967297); +right('hello', 4294967297) +hello +select right('hello', -18446744073709551615); +right('hello', -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', 18446744073709551615); +right('hello', 18446744073709551615) +hello +select right('hello', -18446744073709551616); +right('hello', -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', 18446744073709551616); +right('hello', 18446744073709551616) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', -18446744073709551617); +right('hello', -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select right('hello', 18446744073709551617); +right('hello', 18446744073709551617) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 2, -1); +substring('hello', 2, -1) + +select substring('hello', -1, 1); +substring('hello', -1, 1) +o +select substring('hello', -2, 1); +substring('hello', -2, 1) +l +select substring('hello', -4294967295, 1); +substring('hello', -4294967295, 1) + +select substring('hello', 4294967295, 1); +substring('hello', 4294967295, 1) + +select substring('hello', -4294967296, 1); +substring('hello', -4294967296, 1) + +select substring('hello', 4294967296, 1); +substring('hello', 4294967296, 1) + +select substring('hello', -4294967297, 1); +substring('hello', -4294967297, 1) + +select substring('hello', 4294967297, 1); +substring('hello', 4294967297, 1) + +select substring('hello', -18446744073709551615, 1); +substring('hello', -18446744073709551615, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551615, 1); +substring('hello', 18446744073709551615, 1) + +select substring('hello', -18446744073709551616, 1); +substring('hello', -18446744073709551616, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551616, 1); +substring('hello', 18446744073709551616, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', -18446744073709551617, 1); +substring('hello', -18446744073709551617, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551617, 1); +substring('hello', 18446744073709551617, 1) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, -1); +substring('hello', 1, -1) + +select substring('hello', 1, -4294967295); +substring('hello', 1, -4294967295) + +select substring('hello', 1, 4294967295); +substring('hello', 1, 4294967295) +hello +select substring('hello', 1, -4294967296); +substring('hello', 1, -4294967296) + +select substring('hello', 1, 4294967296); +substring('hello', 1, 4294967296) +hello +select substring('hello', 1, -4294967297); +substring('hello', 1, -4294967297) + +select substring('hello', 1, 4294967297); +substring('hello', 1, 4294967297) +hello +select substring('hello', 1, -18446744073709551615); +substring('hello', 1, -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, 18446744073709551615); +substring('hello', 1, 18446744073709551615) +hello +select substring('hello', 1, -18446744073709551616); +substring('hello', 1, -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, 18446744073709551616); +substring('hello', 1, 18446744073709551616) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, -18446744073709551617); +substring('hello', 1, -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 1, 18446744073709551617); +substring('hello', 1, 18446744073709551617) +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', -1, -1); +substring('hello', -1, -1) + +select substring('hello', -4294967295, -4294967295); +substring('hello', -4294967295, -4294967295) + +select substring('hello', 4294967295, 4294967295); +substring('hello', 4294967295, 4294967295) + +select substring('hello', -4294967296, -4294967296); +substring('hello', -4294967296, -4294967296) + +select substring('hello', 4294967296, 4294967296); +substring('hello', 4294967296, 4294967296) + +select substring('hello', -4294967297, -4294967297); +substring('hello', -4294967297, -4294967297) + +select substring('hello', 4294967297, 4294967297); +substring('hello', 4294967297, 4294967297) + +select substring('hello', -18446744073709551615, -18446744073709551615); +substring('hello', -18446744073709551615, -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551615, 18446744073709551615); +substring('hello', 18446744073709551615, 18446744073709551615) + +select substring('hello', -18446744073709551616, -18446744073709551616); +substring('hello', -18446744073709551616, -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551616, 18446744073709551616); +substring('hello', 18446744073709551616, 18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', -18446744073709551617, -18446744073709551617); +substring('hello', -18446744073709551617, -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select substring('hello', 18446744073709551617, 18446744073709551617); +substring('hello', 18446744073709551617, 18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', -1, 1, 'hi'); +insert('hello', -1, 1, 'hi') +hello +select insert('hello', -4294967295, 1, 'hi'); +insert('hello', -4294967295, 1, 'hi') +hello +select insert('hello', 4294967295, 1, 'hi'); +insert('hello', 4294967295, 1, 'hi') +hello +select insert('hello', -4294967296, 1, 'hi'); +insert('hello', -4294967296, 1, 'hi') +hello +select insert('hello', 4294967296, 1, 'hi'); +insert('hello', 4294967296, 1, 'hi') +hello +select insert('hello', -4294967297, 1, 'hi'); +insert('hello', -4294967297, 1, 'hi') +hello +select insert('hello', 4294967297, 1, 'hi'); +insert('hello', 4294967297, 1, 'hi') +hello +select insert('hello', -18446744073709551615, 1, 'hi'); +insert('hello', -18446744073709551615, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551615, 1, 'hi'); +insert('hello', 18446744073709551615, 1, 'hi') +hello +select insert('hello', -18446744073709551616, 1, 'hi'); +insert('hello', -18446744073709551616, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551616, 1, 'hi'); +insert('hello', 18446744073709551616, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', -18446744073709551617, 1, 'hi'); +insert('hello', -18446744073709551617, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551617, 1, 'hi'); +insert('hello', 18446744073709551617, 1, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, -1, 'hi'); +insert('hello', 1, -1, 'hi') +hi +select insert('hello', 1, -4294967295, 'hi'); +insert('hello', 1, -4294967295, 'hi') +hi +select insert('hello', 1, 4294967295, 'hi'); +insert('hello', 1, 4294967295, 'hi') +hi +select insert('hello', 1, -4294967296, 'hi'); +insert('hello', 1, -4294967296, 'hi') +hi +select insert('hello', 1, 4294967296, 'hi'); +insert('hello', 1, 4294967296, 'hi') +hi +select insert('hello', 1, -4294967297, 'hi'); +insert('hello', 1, -4294967297, 'hi') +hi +select insert('hello', 1, 4294967297, 'hi'); +insert('hello', 1, 4294967297, 'hi') +hi +select insert('hello', 1, -18446744073709551615, 'hi'); +insert('hello', 1, -18446744073709551615, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, 18446744073709551615, 'hi'); +insert('hello', 1, 18446744073709551615, 'hi') +hi +select insert('hello', 1, -18446744073709551616, 'hi'); +insert('hello', 1, -18446744073709551616, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, 18446744073709551616, 'hi'); +insert('hello', 1, 18446744073709551616, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, -18446744073709551617, 'hi'); +insert('hello', 1, -18446744073709551617, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 1, 18446744073709551617, 'hi'); +insert('hello', 1, 18446744073709551617, 'hi') +hi +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', -1, -1, 'hi'); +insert('hello', -1, -1, 'hi') +hello +select insert('hello', -4294967295, -4294967295, 'hi'); +insert('hello', -4294967295, -4294967295, 'hi') +hello +select insert('hello', 4294967295, 4294967295, 'hi'); +insert('hello', 4294967295, 4294967295, 'hi') +hello +select insert('hello', -4294967296, -4294967296, 'hi'); +insert('hello', -4294967296, -4294967296, 'hi') +hello +select insert('hello', 4294967296, 4294967296, 'hi'); +insert('hello', 4294967296, 4294967296, 'hi') +hello +select insert('hello', -4294967297, -4294967297, 'hi'); +insert('hello', -4294967297, -4294967297, 'hi') +hello +select insert('hello', 4294967297, 4294967297, 'hi'); +insert('hello', 4294967297, 4294967297, 'hi') +hello +select insert('hello', -18446744073709551615, -18446744073709551615, 'hi'); +insert('hello', -18446744073709551615, -18446744073709551615, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551615, 18446744073709551615, 'hi'); +insert('hello', 18446744073709551615, 18446744073709551615, 'hi') +hello +select insert('hello', -18446744073709551616, -18446744073709551616, 'hi'); +insert('hello', -18446744073709551616, -18446744073709551616, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551616, 18446744073709551616, 'hi'); +insert('hello', 18446744073709551616, 18446744073709551616, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', -18446744073709551617, -18446744073709551617, 'hi'); +insert('hello', -18446744073709551617, -18446744073709551617, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select insert('hello', 18446744073709551617, 18446744073709551617, 'hi'); +insert('hello', 18446744073709551617, 18446744073709551617, 'hi') +hello +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select repeat('hello', -1); +repeat('hello', -1) + +select repeat('hello', -4294967295); +repeat('hello', -4294967295) + +select repeat('hello', 4294967295); +repeat('hello', 4294967295) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -4294967296); +repeat('hello', -4294967296) + +select repeat('hello', 4294967296); +repeat('hello', 4294967296) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -4294967297); +repeat('hello', -4294967297) + +select repeat('hello', 4294967297); +repeat('hello', 4294967297) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -18446744073709551615); +repeat('hello', -18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select repeat('hello', 18446744073709551615); +repeat('hello', 18446744073709551615) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -18446744073709551616); +repeat('hello', -18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select repeat('hello', 18446744073709551616); +repeat('hello', 18446744073709551616) +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select repeat('hello', -18446744073709551617); +repeat('hello', -18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select repeat('hello', 18446744073709551617); +repeat('hello', 18446744073709551617) +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-1); +space(-1) + +select space(-4294967295); +space(-4294967295) + +select space(4294967295); +space(4294967295) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-4294967296); +space(-4294967296) + +select space(4294967296); +space(4294967296) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-4294967297); +space(-4294967297) + +select space(4294967297); +space(4294967297) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-18446744073709551615); +space(-18446744073709551615) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select space(18446744073709551615); +space(18446744073709551615) +NULL +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-18446744073709551616); +space(-18446744073709551616) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select space(18446744073709551616); +space(18446744073709551616) +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select space(-18446744073709551617); +space(-18446744073709551617) + +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select space(18446744073709551617); +space(18446744073709551617) +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -1, '1'); +rpad('hello', -1, '1') +NULL +select rpad('hello', -4294967295, '1'); +rpad('hello', -4294967295, '1') +NULL +select rpad('hello', 4294967295, '1'); +rpad('hello', 4294967295, '1') +NULL +Warnings: +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -4294967296, '1'); +rpad('hello', -4294967296, '1') +NULL +select rpad('hello', 4294967296, '1'); +rpad('hello', 4294967296, '1') +NULL +Warnings: +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -4294967297, '1'); +rpad('hello', -4294967297, '1') +NULL +select rpad('hello', 4294967297, '1'); +rpad('hello', 4294967297, '1') +NULL +Warnings: +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -18446744073709551615, '1'); +rpad('hello', -18446744073709551615, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select rpad('hello', 18446744073709551615, '1'); +rpad('hello', 18446744073709551615, '1') +NULL +Warnings: +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -18446744073709551616, '1'); +rpad('hello', -18446744073709551616, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select rpad('hello', 18446744073709551616, '1'); +rpad('hello', 18446744073709551616, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select rpad('hello', -18446744073709551617, '1'); +rpad('hello', -18446744073709551617, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select rpad('hello', 18446744073709551617, '1'); +rpad('hello', 18446744073709551617, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -1, '1'); +lpad('hello', -1, '1') +NULL +select lpad('hello', -4294967295, '1'); +lpad('hello', -4294967295, '1') +NULL +select lpad('hello', 4294967295, '1'); +lpad('hello', 4294967295, '1') +NULL +Warnings: +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -4294967296, '1'); +lpad('hello', -4294967296, '1') +NULL +select lpad('hello', 4294967296, '1'); +lpad('hello', 4294967296, '1') +NULL +Warnings: +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -4294967297, '1'); +lpad('hello', -4294967297, '1') +NULL +select lpad('hello', 4294967297, '1'); +lpad('hello', 4294967297, '1') +NULL +Warnings: +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -18446744073709551615, '1'); +lpad('hello', -18446744073709551615, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select lpad('hello', 18446744073709551615, '1'); +lpad('hello', 18446744073709551615, '1') +NULL +Warnings: +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -18446744073709551616, '1'); +lpad('hello', -18446744073709551616, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select lpad('hello', 18446744073709551616, '1'); +lpad('hello', 18446744073709551616, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +select lpad('hello', -18446744073709551617, '1'); +lpad('hello', -18446744073709551617, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +select lpad('hello', 18446744073709551617, '1'); +lpad('hello', 18446744073709551617, '1') +NULL +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated +SET @orig_sql_mode = @@SQL_MODE; +SET SQL_MODE=traditional; +SELECT CHAR(0xff,0x8f USING utf8); +CHAR(0xff,0x8f USING utf8) +NULL +Warnings: +Error 1300 Invalid utf8 character string: 'FF8F' +SELECT CHAR(0xff,0x8f USING utf8) IS NULL; +CHAR(0xff,0x8f USING utf8) IS NULL +1 +Warnings: +Error 1300 Invalid utf8 character string: 'FF8F' +SET SQL_MODE=@orig_sql_mode; +select substring('abc', cast(2 as unsigned int)); +substring('abc', cast(2 as unsigned int)) +bc +select repeat('a', cast(2 as unsigned int)); +repeat('a', cast(2 as unsigned int)) +aa +select rpad('abc', cast(5 as unsigned integer), 'x'); +rpad('abc', cast(5 as unsigned integer), 'x') +abcxx +select lpad('abc', cast(5 as unsigned integer), 'x'); +lpad('abc', cast(5 as unsigned integer), 'x') +xxabc +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/func_system.result b/mysql-test/suite/pbxt/r/func_system.result new file mode 100644 index 00000000000..7021c0f7c71 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_system.result @@ -0,0 +1,97 @@ +select database(); +database() +test +select charset(database()); +charset(database()) +utf8 +select database() = "test"; +database() = "test" +1 +select database() = _utf8"test"; +database() = _utf8"test" +1 +select database() = _latin1"test"; +database() = _latin1"test" +1 +select user() like "%@%"; +user() like "%@%" +1 +select user() like _utf8"%@%"; +user() like _utf8"%@%" +1 +select user() like _latin1"%@%"; +user() like _latin1"%@%" +1 +select charset(user()); +charset(user()) +utf8 +select version()>="3.23.29"; +version()>="3.23.29" +1 +select version()>=_utf8"3.23.29"; +version()>=_utf8"3.23.29" +1 +select version()>=_latin1"3.23.29"; +version()>=_latin1"3.23.29" +1 +select charset(version()); +charset(version()) +utf8 +explain extended select database(), user(); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select database() AS `database()`,user() AS `user()` +create table t1 (version char(60)) select database(), user(), version() as 'version'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `database()` varchar(34) CHARACTER SET utf8 DEFAULT NULL, + `user()` varchar(77) CHARACTER SET utf8 NOT NULL DEFAULT '', + `version` char(60) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +select charset(charset(_utf8'a')), charset(collation(_utf8'a')); +charset(charset(_utf8'a')) charset(collation(_utf8'a')) +utf8 utf8 +select collation(charset(_utf8'a')), collation(collation(_utf8'a')); +collation(charset(_utf8'a')) collation(collation(_utf8'a')) +utf8_general_ci utf8_general_ci +create table t1 select charset(_utf8'a'), collation(_utf8'a'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `charset(_utf8'a')` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', + `collation(_utf8'a')` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +select TRUE,FALSE,NULL; +TRUE FALSE NULL +1 0 NULL +create table t1 (c1 char(5)) character set=latin1; +insert into t1 values('row 1'); +insert into t1 values('row 2'); +insert into t1 values('row 3'); +select concat(user(), '--', c1) from t1; +concat(user(), '--', c1) +root@localhost--row 1 +root@localhost--row 2 +root@localhost--row 3 +select concat(database(), '--', c1) from t1; +concat(database(), '--', c1) +test--row 1 +test--row 2 +test--row 3 +drop table t1; +create table t1 (a char(10)) character set latin1; +select * from t1 where a=version(); +a +select * from t1 where a=database(); +a +select * from t1 where a=user(); +a +insert into t1 values ('a'); +select left(concat(a,version()),1) from t1; +left(concat(a,version()),1) +a +drop table t1; diff --git a/mysql-test/suite/pbxt/r/func_timestamp.result b/mysql-test/suite/pbxt/r/func_timestamp.result new file mode 100644 index 00000000000..495fedea9e6 --- /dev/null +++ b/mysql-test/suite/pbxt/r/func_timestamp.result @@ -0,0 +1,13 @@ +drop table if exists t1; +set time_zone="+03:00"; +create table t1 (Zeit time, Tag tinyint not null, Monat tinyint not null, +Jahr smallint not null, index(Tag), index(Monat), index(Jahr) ); +insert into t1 values ("09:26:00",16,9,1998),("09:26:00",16,9,1998); +SELECT CONCAT(Jahr,'-',Monat,'-',Tag,' ',Zeit) AS Date, +UNIX_TIMESTAMP(CONCAT(Jahr,'-',Monat,'-',Tag,' ',Zeit)) AS Unix +FROM t1; +Date Unix +1998-9-16 09:26:00 905927160 +1998-9-16 09:26:00 905927160 +drop table t1; +set time_zone= @@global.time_zone; diff --git a/mysql-test/suite/pbxt/r/gcc296.result b/mysql-test/suite/pbxt/r/gcc296.result new file mode 100644 index 00000000000..d6795e4c98c --- /dev/null +++ b/mysql-test/suite/pbxt/r/gcc296.result @@ -0,0 +1,20 @@ +drop table if exists t1; +CREATE TABLE t1 ( +kodoboru varchar(10) default NULL, +obor tinytext, +aobor tinytext, +UNIQUE INDEX kodoboru (kodoboru), +FULLTEXT KEY obor (obor), +FULLTEXT KEY aobor (aobor) +) engine=myisam; +INSERT INTO t1 VALUES ('0101000000','aaa','AAA'); +INSERT INTO t1 VALUES ('0102000000','bbb','BBB'); +INSERT INTO t1 VALUES ('0103000000','ccc','CCC'); +INSERT INTO t1 VALUES ('0104000000','xxx','XXX'); +select * from t1; +kodoboru obor aobor +0101000000 aaa AAA +0102000000 bbb BBB +0103000000 ccc CCC +0104000000 xxx XXX +drop table t1; diff --git a/mysql-test/suite/pbxt/r/grant.result b/mysql-test/suite/pbxt/r/grant.result new file mode 100644 index 00000000000..24a2b9b4d55 --- /dev/null +++ b/mysql-test/suite/pbxt/r/grant.result @@ -0,0 +1,1040 @@ +drop table if exists t1; +drop database if exists mysqltest; +SET NAMES binary; +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +flush privileges; +grant select on mysqltest.* to mysqltest_1@localhost require cipher "EDH-RSA-DES-CBC3-SHA"; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +grant delete on mysqltest.* to mysqltest_1@localhost; +select * from mysql.user where user="mysqltest_1"; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 0 +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' +GRANT SELECT, DELETE ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +revoke delete on mysqltest.* from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +grant select on mysqltest.* to mysqltest_1@localhost require NONE; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +grant USAGE on mysqltest.* to mysqltest_1@localhost require cipher "EDH-RSA-DES-CBC3-SHA" AND SUBJECT "testsubject" ISSUER "MySQL AB"; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE ISSUER 'MySQL AB' SUBJECT 'testsubject' CIPHER 'EDH-RSA-DES-CBC3-SHA' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE ISSUER 'MySQL AB' SUBJECT 'testsubject' CIPHER 'EDH-RSA-DES-CBC3-SHA' +delete from mysql.user where user='mysqltest_1'; +flush privileges; +delete from mysql.user where user='mysqltest_1'; +flush privileges; +grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10; +select * from mysql.user where user="mysqltest_1"; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 0 0 0 +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 +grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30; +select * from mysql.user where user="mysqltest_1"; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv Event_priv Trigger_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 0 +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 +flush privileges; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 +delete from mysql.user where user='mysqltest_1'; +flush privileges; +grant CREATE TEMPORARY TABLES, LOCK TABLES on mysqltest.* to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT CREATE TEMPORARY TABLES, LOCK TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +flush privileges; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT CREATE TEMPORARY TABLES, LOCK TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +revoke CREATE TEMPORARY TABLES on mysqltest.* from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT LOCK TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +grant ALL PRIVILEGES on mysqltest.* to mysqltest_1@localhost with GRANT OPTION; +flush privileges; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +flush privileges; +grant usage on test.* to mysqltest_1@localhost with grant option; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT USAGE ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +GRANT USAGE ON `test`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +delete from mysql.tables_priv where user='mysqltest_1'; +delete from mysql.columns_priv where user='mysqltest_1'; +flush privileges; +show grants for mysqltest_1@localhost; +ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host 'localhost' +create table t1 (a int); +GRANT select,update,insert on t1 to mysqltest_1@localhost; +GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, SELECT (a), INSERT, INSERT (a), UPDATE, UPDATE (a), REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +table_priv column_priv +Select,Insert,Update Select,Insert,Update,References +REVOKE select (a), update on t1 from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, INSERT (a), REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +REVOKE select,update,insert,insert (a) on t1 from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +GRANT select,references on t1 to mysqltest_1@localhost; +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +table_priv column_priv +Select,References References +grant all on test.* to mysqltest_3@localhost with grant option; +revoke all on test.* from mysqltest_3@localhost; +show grants for mysqltest_3@localhost; +Grants for mysqltest_3@localhost +GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost' +GRANT USAGE ON `test`.* TO 'mysqltest_3'@'localhost' WITH GRANT OPTION +revoke grant option on test.* from mysqltest_3@localhost; +show grants for mysqltest_3@localhost; +Grants for mysqltest_3@localhost +GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost' +grant all on test.t1 to mysqltest_2@localhost with grant option; +revoke all on test.t1 from mysqltest_2@localhost; +show grants for mysqltest_2@localhost; +Grants for mysqltest_2@localhost +GRANT USAGE ON *.* TO 'mysqltest_2'@'localhost' +GRANT USAGE ON `test`.`t1` TO 'mysqltest_2'@'localhost' WITH GRANT OPTION +revoke grant option on test.t1 from mysqltest_2@localhost; +show grants for mysqltest_2@localhost; +Grants for mysqltest_2@localhost +GRANT USAGE ON *.* TO 'mysqltest_2'@'localhost' +delete from mysql.user where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.db where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.tables_priv where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.columns_priv where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +flush privileges; +drop table t1; +GRANT FILE on mysqltest.* to mysqltest_1@localhost; +ERROR HY000: Incorrect usage of DB GRANT and GLOBAL PRIVILEGES +select 1; +1 +1 +insert into mysql.user (host, user) values ('localhost', 'test11'); +Warnings: +Warning 1364 Field 'ssl_cipher' doesn't have a default value +Warning 1364 Field 'x509_issuer' doesn't have a default value +Warning 1364 Field 'x509_subject' doesn't have a default value +insert into mysql.db (host, db, user, select_priv) values +('localhost', 'a%', 'test11', 'Y'), ('localhost', 'ab%', 'test11', 'Y'); +alter table mysql.db order by db asc; +flush privileges; +show grants for test11@localhost; +Grants for test11@localhost +GRANT USAGE ON *.* TO 'test11'@'localhost' +GRANT SELECT ON `ab%`.* TO 'test11'@'localhost' +GRANT SELECT ON `a%`.* TO 'test11'@'localhost' +alter table mysql.db order by db desc; +flush privileges; +show grants for test11@localhost; +Grants for test11@localhost +GRANT USAGE ON *.* TO 'test11'@'localhost' +GRANT SELECT ON `ab%`.* TO 'test11'@'localhost' +GRANT SELECT ON `a%`.* TO 'test11'@'localhost' +delete from mysql.user where user='test11'; +delete from mysql.db where user='test11'; +create database mysqltest1; +grant usage on mysqltest1.* to test6123 identified by 'magic123'; +select host,db,user,select_priv,insert_priv from mysql.db where db="mysqltest1"; +host db user select_priv insert_priv +delete from mysql.user where user='test6123'; +drop database mysqltest1; +create table t1 (a int); +grant ALL PRIVILEGES on *.* to drop_user2@localhost with GRANT OPTION; +show grants for drop_user2@localhost; +Grants for drop_user2@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user2'@'localhost' WITH GRANT OPTION +revoke all privileges, grant option from drop_user2@localhost; +drop user drop_user2@localhost; +grant ALL PRIVILEGES on *.* to drop_user@localhost with GRANT OPTION; +grant ALL PRIVILEGES on test.* to drop_user@localhost with GRANT OPTION; +grant select(a) on test.t1 to drop_user@localhost; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON `test`.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON `test`.`t1` TO 'drop_user'@'localhost' +set sql_mode=ansi_quotes; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON "test".* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON "test"."t1" TO 'drop_user'@'localhost' +set sql_mode=default; +set sql_quote_show_create=0; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON test.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON test.t1 TO 'drop_user'@'localhost' +set sql_mode="ansi_quotes"; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON test.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON test.t1 TO 'drop_user'@'localhost' +set sql_quote_show_create=1; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON "test".* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON "test"."t1" TO 'drop_user'@'localhost' +set sql_mode=""; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON `test`.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON `test`.`t1` TO 'drop_user'@'localhost' +revoke all privileges, grant option from drop_user@localhost; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT USAGE ON *.* TO 'drop_user'@'localhost' +drop user drop_user@localhost; +revoke all privileges, grant option from drop_user@localhost; +ERROR HY000: Can't revoke all privileges for one or more of the requested users +grant select(a) on test.t1 to drop_user1@localhost; +grant select on test.t1 to drop_user2@localhost; +grant select on test.* to drop_user3@localhost; +grant select on *.* to drop_user4@localhost; +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost, +drop_user3@localhost, drop_user4@localhost; +ERROR HY000: Can't revoke all privileges for one or more of the requested users +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +ERROR HY000: Operation DROP USER failed for 'drop_user1'@'localhost','drop_user2'@'localhost','drop_user3'@'localhost','drop_user4'@'localhost' +drop table t1; +grant usage on *.* to mysqltest_1@localhost identified by "password"; +grant select, update, insert on test.* to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19' +GRANT SELECT, INSERT, UPDATE ON `test`.* TO 'mysqltest_1'@'localhost' +drop user mysqltest_1@localhost; +SET NAMES koi8r; +CREATE DATABASE ÂÄ; +USE ÂÄ; +CREATE TABLE ÔÁ (ËÏÌ int); +GRANT SELECT ON ÂÄ.* TO ÀÚÅÒ@localhost; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +Grants for ÀÚÅÒ@localhost +GRANT USAGE ON *.* TO 'ÀÚÅÒ'@'localhost' +GRANT SELECT ON `ÂÄ`.* TO 'ÀÚÅÒ'@'localhost' +REVOKE SELECT ON ÂÄ.* FROM ÀÚÅÒ@localhost; +GRANT SELECT ON ÂÄ.ÔÁ TO ÀÚÅÒ@localhost; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +Grants for ÀÚÅÒ@localhost +GRANT USAGE ON *.* TO 'ÀÚÅÒ'@'localhost' +GRANT SELECT ON `ÂÄ`.`ÔÁÂ` TO 'ÀÚÅÒ'@'localhost' +REVOKE SELECT ON ÂÄ.ÔÁ FROM ÀÚÅÒ@localhost; +GRANT SELECT (ËÏÌ) ON ÂÄ.ÔÁ TO ÀÚÅÒ@localhost; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +Grants for ÀÚÅÒ@localhost +GRANT USAGE ON *.* TO 'ÀÚÅÒ'@'localhost' +GRANT SELECT (ËÏÌ) ON `ÂÄ`.`ÔÁÂ` TO 'ÀÚÅÒ'@'localhost' +REVOKE SELECT (ËÏÌ) ON ÂÄ.ÔÁ FROM ÀÚÅÒ@localhost; +DROP USER ÀÚÅÒ@localhost; +DROP DATABASE ÂÄ; +SET NAMES latin1; +USE test; +CREATE TABLE t1 (a int ); +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 LIKE t1; +CREATE TABLE t4 LIKE t1; +CREATE TABLE t5 LIKE t1; +CREATE TABLE t6 LIKE t1; +CREATE TABLE t7 LIKE t1; +CREATE TABLE t8 LIKE t1; +CREATE TABLE t9 LIKE t1; +CREATE TABLE t10 LIKE t1; +CREATE DATABASE testdb1; +CREATE DATABASE testdb2; +CREATE DATABASE testdb3; +CREATE DATABASE testdb4; +CREATE DATABASE testdb5; +CREATE DATABASE testdb6; +CREATE DATABASE testdb7; +CREATE DATABASE testdb8; +CREATE DATABASE testdb9; +CREATE DATABASE testdb10; +GRANT ALL ON testdb1.* TO testuser@localhost; +GRANT ALL ON testdb2.* TO testuser@localhost; +GRANT ALL ON testdb3.* TO testuser@localhost; +GRANT ALL ON testdb4.* TO testuser@localhost; +GRANT ALL ON testdb5.* TO testuser@localhost; +GRANT ALL ON testdb6.* TO testuser@localhost; +GRANT ALL ON testdb7.* TO testuser@localhost; +GRANT ALL ON testdb8.* TO testuser@localhost; +GRANT ALL ON testdb9.* TO testuser@localhost; +GRANT ALL ON testdb10.* TO testuser@localhost; +GRANT SELECT ON test.t1 TO testuser@localhost; +GRANT SELECT ON test.t2 TO testuser@localhost; +GRANT SELECT ON test.t3 TO testuser@localhost; +GRANT SELECT ON test.t4 TO testuser@localhost; +GRANT SELECT ON test.t5 TO testuser@localhost; +GRANT SELECT ON test.t6 TO testuser@localhost; +GRANT SELECT ON test.t7 TO testuser@localhost; +GRANT SELECT ON test.t8 TO testuser@localhost; +GRANT SELECT ON test.t9 TO testuser@localhost; +GRANT SELECT ON test.t10 TO testuser@localhost; +GRANT SELECT (a) ON test.t1 TO testuser@localhost; +GRANT SELECT (a) ON test.t2 TO testuser@localhost; +GRANT SELECT (a) ON test.t3 TO testuser@localhost; +GRANT SELECT (a) ON test.t4 TO testuser@localhost; +GRANT SELECT (a) ON test.t5 TO testuser@localhost; +GRANT SELECT (a) ON test.t6 TO testuser@localhost; +GRANT SELECT (a) ON test.t7 TO testuser@localhost; +GRANT SELECT (a) ON test.t8 TO testuser@localhost; +GRANT SELECT (a) ON test.t9 TO testuser@localhost; +GRANT SELECT (a) ON test.t10 TO testuser@localhost; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM testuser@localhost; +SHOW GRANTS FOR testuser@localhost; +Grants for testuser@localhost +GRANT USAGE ON *.* TO 'testuser'@'localhost' +DROP USER testuser@localhost; +DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8,t9,t10; +DROP DATABASE testdb1; +DROP DATABASE testdb2; +DROP DATABASE testdb3; +DROP DATABASE testdb4; +DROP DATABASE testdb5; +DROP DATABASE testdb6; +DROP DATABASE testdb7; +DROP DATABASE testdb8; +DROP DATABASE testdb9; +DROP DATABASE testdb10; +create table t1(a int, b int, c int, d int); +grant insert(b), insert(c), insert(d), insert(a) on t1 to grant_user@localhost; +show grants for grant_user@localhost; +Grants for grant_user@localhost +GRANT USAGE ON *.* TO 'grant_user'@'localhost' +GRANT INSERT (a, d, c, b) ON `test`.`t1` TO 'grant_user'@'localhost' +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name; +Host Db User Table_name Column_name Column_priv +localhost test grant_user t1 a Insert +localhost test grant_user t1 b Insert +localhost test grant_user t1 c Insert +localhost test grant_user t1 d Insert +revoke ALL PRIVILEGES on t1 from grant_user@localhost; +show grants for grant_user@localhost; +Grants for grant_user@localhost +GRANT USAGE ON *.* TO 'grant_user'@'localhost' +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; +Host Db User Table_name Column_name Column_priv +drop user grant_user@localhost; +drop table t1; +create database mysqltest_1; +create database mysqltest_2; +create table mysqltest_1.t1 select 1 a, 2 q; +create table mysqltest_1.t2 select 1 b, 2 r; +create table mysqltest_2.t1 select 1 c, 2 s; +create table mysqltest_2.t2 select 1 d, 2 t; +grant update (a) on mysqltest_1.t1 to mysqltest_3@localhost; +grant select (b) on mysqltest_1.t2 to mysqltest_3@localhost; +grant select (c) on mysqltest_2.t1 to mysqltest_3@localhost; +grant update (d) on mysqltest_2.t2 to mysqltest_3@localhost; +SELECT * FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES +WHERE GRANTEE = '''mysqltest_3''@''localhost''' +ORDER BY TABLE_NAME,COLUMN_NAME,PRIVILEGE_TYPE; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_3'@'localhost' NULL mysqltest_1 t1 a UPDATE NO +'mysqltest_3'@'localhost' NULL mysqltest_2 t1 c SELECT NO +'mysqltest_3'@'localhost' NULL mysqltest_1 t2 b SELECT NO +'mysqltest_3'@'localhost' NULL mysqltest_2 t2 d UPDATE NO +SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES +WHERE GRANTEE = '''mysqltest_3''@''localhost''' +ORDER BY TABLE_NAME,PRIVILEGE_TYPE; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE +SELECT * from INFORMATION_SCHEMA.SCHEMA_PRIVILEGES +WHERE GRANTEE = '''mysqltest_3''@''localhost''' +ORDER BY TABLE_SCHEMA,PRIVILEGE_TYPE; +GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE +SELECT * from INFORMATION_SCHEMA.USER_PRIVILEGES +WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_CATALOG,PRIVILEGE_TYPE; +GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_3'@'localhost' NULL USAGE NO +update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1; +ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for column 'q' in table 't1' +update mysqltest_1.t2, mysqltest_2.t2 set d=20 where d=1; +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'd' in table 't2' +update mysqltest_1.t1, mysqltest_2.t2 set d=20 where d=1; +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 't1' +update mysqltest_2.t1, mysqltest_1.t2 set c=20 where b=1; +ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't1' +update mysqltest_2.t1, mysqltest_2.t2 set d=10 where s=2; +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 's' in table 't1' +update mysqltest_1.t1, mysqltest_2.t2 set a=10,d=10; +update mysqltest_1.t1, mysqltest_2.t1 set a=20 where c=20; +select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2; +a q b r +10 2 1 2 +select t1.*,t2.* from mysqltest_2.t1,mysqltest_2.t2; +c s d t +1 2 10 2 +revoke all on mysqltest_1.t1 from mysqltest_3@localhost; +revoke all on mysqltest_1.t2 from mysqltest_3@localhost; +revoke all on mysqltest_2.t1 from mysqltest_3@localhost; +revoke all on mysqltest_2.t2 from mysqltest_3@localhost; +grant all on mysqltest_2.* to mysqltest_3@localhost; +grant select on *.* to mysqltest_3@localhost; +grant select on mysqltest_2.t1 to mysqltest_3@localhost; +flush privileges; +use mysqltest_1; +update mysqltest_2.t1, mysqltest_2.t2 set c=500,d=600; +update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200; +ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't1' +use mysqltest_2; +update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200; +ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't1' +update mysqltest_2.t1, mysqltest_1.t2 set c=100,b=200; +ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't2' +update mysqltest_1.t1, mysqltest_2.t2 set a=100,d=200; +ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't1' +select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2; +a q b r +10 2 1 2 +select t1.*,t2.* from mysqltest_2.t1,mysqltest_2.t2; +c s d t +500 2 600 2 +delete from mysql.user where user='mysqltest_3'; +delete from mysql.db where user="mysqltest_3"; +delete from mysql.tables_priv where user="mysqltest_3"; +delete from mysql.columns_priv where user="mysqltest_3"; +flush privileges; +drop database mysqltest_1; +drop database mysqltest_2; +SHOW PRIVILEGES; +Privilege Context Comment +Alter Tables To alter the table +Alter routine Functions,Procedures To alter or drop stored functions/procedures +Create Databases,Tables,Indexes To create new databases and tables +Create routine Functions,Procedures To use CREATE FUNCTION/PROCEDURE +Create temporary tables Databases To use CREATE TEMPORARY TABLE +Create view Tables To create new views +Create user Server Admin To create new users +Delete Tables To delete existing rows +Drop Databases,Tables To drop databases, tables, and views +Event Server Admin To create, alter, drop and execute events +Execute Functions,Procedures To execute stored routines +File File access on server To read and write files on the server +Grant option Databases,Tables,Functions,Procedures To give to other users those privileges you possess +Index Tables To create or drop indexes +Insert Tables To insert data into tables +Lock tables Databases To use LOCK TABLES (together with SELECT privilege) +Process Server Admin To view the plain text of currently executing queries +References Databases,Tables To have references on tables +Reload Server Admin To reload or refresh tables, logs and privileges +Replication client Server Admin To ask where the slave or master servers are +Replication slave Server Admin To read binary log events from the master +Select Tables To retrieve rows from table +Show databases Server Admin To see all databases with SHOW DATABASES +Show view Tables To see views with SHOW CREATE VIEW +Shutdown Server Admin To shut down the server +Super Server Admin To use KILL thread, SET GLOBAL, CHANGE MASTER, etc. +Trigger Tables To use triggers +Update Tables To update existing rows +Usage Server Admin No privileges - allow connect only +create database mysqltest; +create table mysqltest.t1 (a int,b int,c int); +grant all on mysqltest.t1 to mysqltest_1@localhost; +alter table t1 rename t2; +ERROR 42000: INSERT,CREATE command denied to user 'mysqltest_1'@'localhost' for table 't2' +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +delete from mysql.user where user=_binary'mysqltest_1'; +drop database mysqltest; +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT ALL PRIVILEGES ON mysqltest.dummytable TO dummy@localhost; +GRANT ALL PRIVILEGES ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +SHOW FIELDS FROM mysql.tables_priv; +Field Type Null Key Default Extra +Host char(60) NO PRI +Db char(64) NO PRI +User char(16) NO PRI +Table_name char(64) NO PRI +Grantor char(77) NO MUL +Timestamp timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP +Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') NO +Column_priv set('Select','Insert','Update','References') NO +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT CREATE VIEW ON mysqltest.dummytable TO dummy@localhost; +GRANT CREATE VIEW ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT CREATE VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT CREATE VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable CREATE VIEW +mysqltest dummyview CREATE VIEW +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT CREATE VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT CREATE VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable CREATE VIEW +mysqltest dummyview CREATE VIEW +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT SHOW VIEW ON mysqltest.dummytable TO dummy@localhost; +GRANT SHOW VIEW ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT SHOW VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT SHOW VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable SHOW VIEW +mysqltest dummyview SHOW VIEW +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT SHOW VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT SHOW VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable SHOW VIEW +mysqltest dummyview SHOW VIEW +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +use mysql; +insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_grantor',CURRENT_TIMESTAMP,'Select','Select'); +flush privileges; +delete from tables_priv where host = '' and user = 'mysqltest_1'; +flush privileges; +use test; +set @user123="non-existent"; +select * from mysql.db where user=@user123; +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv +set names koi8r; +create database ÂÄ; +grant select on ÂÄ.* to root@localhost; +select hex(Db) from mysql.db where Db='ÂÄ'; +hex(Db) +D0B1D0B4 +show grants for root@localhost; +Grants for root@localhost +GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION +GRANT SELECT ON `ÂÄ`.* TO 'root'@'localhost' +flush privileges; +show grants for root@localhost; +Grants for root@localhost +GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION +GRANT SELECT ON `ÂÄ`.* TO 'root'@'localhost' +drop database ÂÄ; +revoke all privileges on ÂÄ.* from root@localhost; +show grants for root@localhost; +Grants for root@localhost +GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION +set names latin1; +create user mysqltest_7@; +set password for mysqltest_7@ = password('systpass'); +show grants for mysqltest_7@; +Grants for mysqltest_7@ +GRANT USAGE ON *.* TO 'mysqltest_7'@'' IDENTIFIED BY PASSWORD '*2FB071A056F9BB745219D9C876814231DAF46517' +drop user mysqltest_7@; +show grants for mysqltest_7@; +ERROR 42000: There is no such grant defined for user 'mysqltest_7' on host '' +create database mysqltest; +use mysqltest; +create table t1(f1 int); +GRANT DELETE ON mysqltest.t1 TO mysqltest1@'%'; +GRANT SELECT ON mysqltest.t1 TO mysqltest1@'192.%'; +show grants for mysqltest1@'192.%'; +Grants for mysqltest1@192.% +GRANT USAGE ON *.* TO 'mysqltest1'@'192.%' +GRANT SELECT ON `mysqltest`.`t1` TO 'mysqltest1'@'192.%' +show grants for mysqltest1@'%'; +Grants for mysqltest1@% +GRANT USAGE ON *.* TO 'mysqltest1'@'%' +GRANT DELETE ON `mysqltest`.`t1` TO 'mysqltest1'@'%' +delete from mysql.user where user='mysqltest1'; +delete from mysql.db where user='mysqltest1'; +delete from mysql.tables_priv where user='mysqltest1'; +flush privileges; +drop database mysqltest; +use test; +create table t1 (a int); +create table t2 as select * from mysql.user where user=''; +delete from mysql.user where user=''; +flush privileges; +create user mysqltest_8@''; +create user mysqltest_8; +create user mysqltest_8@host8; +create user mysqltest_8@''; +ERROR HY000: Operation CREATE USER failed for 'mysqltest_8'@'' +create user mysqltest_8; +ERROR HY000: Operation CREATE USER failed for 'mysqltest_8'@'%' +create user mysqltest_8@host8; +ERROR HY000: Operation CREATE USER failed for 'mysqltest_8'@'host8' +select user, QUOTE(host) from mysql.user where user="mysqltest_8"; +user QUOTE(host) +mysqltest_8 '' +mysqltest_8 '%' +mysqltest_8 'host8' +Schema privileges +grant select on mysqltest.* to mysqltest_8@''; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_8'@'' +grant select on mysqltest.* to mysqltest_8@; +show grants for mysqltest_8@; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_8'@'' +grant select on mysqltest.* to mysqltest_8; +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_8'@'%' +select * from information_schema.schema_privileges +where grantee like "'mysqltest_8'%"; +GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_8'@'%' NULL mysqltest SELECT NO +'mysqltest_8'@'' NULL mysqltest SELECT NO +select * from t1; +a +revoke select on mysqltest.* from mysqltest_8@''; +revoke select on mysqltest.* from mysqltest_8; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +select * from information_schema.schema_privileges +where grantee like "'mysqltest_8'%"; +GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE +flush privileges; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +show grants for mysqltest_8@; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +grant select on mysqltest.* to mysqltest_8@''; +flush privileges; +show grants for mysqltest_8@; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_8'@'' +revoke select on mysqltest.* from mysqltest_8@''; +flush privileges; +Column privileges +grant update (a) on t1 to mysqltest_8@''; +grant update (a) on t1 to mysqltest_8; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +GRANT UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@'%' +flush privileges; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +GRANT UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@'%' +select * from information_schema.column_privileges; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_8'@'%' NULL test t1 a UPDATE NO +'mysqltest_8'@'' NULL test t1 a UPDATE NO +select * from t1; +a +revoke update (a) on t1 from mysqltest_8@''; +revoke update (a) on t1 from mysqltest_8; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +select * from information_schema.column_privileges; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE +flush privileges; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +Table privileges +grant update on t1 to mysqltest_8@''; +grant update on t1 to mysqltest_8; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT UPDATE ON `test`.`t1` TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +GRANT UPDATE ON `test`.`t1` TO 'mysqltest_8'@'%' +flush privileges; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT UPDATE ON `test`.`t1` TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +GRANT UPDATE ON `test`.`t1` TO 'mysqltest_8'@'%' +select * from information_schema.table_privileges; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_8'@'%' NULL test t1 UPDATE NO +'mysqltest_8'@'' NULL test t1 UPDATE NO +select * from t1; +a +revoke update on t1 from mysqltest_8@''; +revoke update on t1 from mysqltest_8; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +select * from information_schema.table_privileges; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE +flush privileges; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +"DROP USER" should clear privileges +grant all privileges on mysqltest.* to mysqltest_8@''; +grant select on mysqltest.* to mysqltest_8@''; +grant update on t1 to mysqltest_8@''; +grant update (a) on t1 to mysqltest_8@''; +grant all privileges on mysqltest.* to mysqltest_8; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@'' +GRANT UPDATE, UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@'%' +select * from information_schema.user_privileges +where grantee like "'mysqltest_8'%"; +GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_8'@'host8' NULL USAGE NO +'mysqltest_8'@'%' NULL USAGE NO +'mysqltest_8'@'' NULL USAGE NO +select * from t1; +a +flush privileges; +show grants for mysqltest_8@''; +Grants for mysqltest_8@ +GRANT USAGE ON *.* TO 'mysqltest_8'@'' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@'' +GRANT UPDATE, UPDATE (a) ON `test`.`t1` TO 'mysqltest_8'@'' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@'%' +drop user mysqltest_8@''; +show grants for mysqltest_8@''; +ERROR 42000: There is no such grant defined for user 'mysqltest_8' on host '' +show grants for mysqltest_8; +Grants for mysqltest_8@% +GRANT USAGE ON *.* TO 'mysqltest_8'@'%' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_8'@'%' +select * from information_schema.user_privileges +where grantee like "'mysqltest_8'%"; +GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_8'@'host8' NULL USAGE NO +'mysqltest_8'@'%' NULL USAGE NO +drop user mysqltest_8; +connect(localhost,mysqltest_8,,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'mysqltest_8'@'localhost' (using password: NO) +show grants for mysqltest_8; +ERROR 42000: There is no such grant defined for user 'mysqltest_8' on host '%' +drop user mysqltest_8@host8; +show grants for mysqltest_8@host8; +ERROR 42000: There is no such grant defined for user 'mysqltest_8' on host 'host8' +insert into mysql.user select * from t2; +flush privileges; +drop table t2; +drop table t1; +CREATE DATABASE mysqltest3; +use mysqltest3; +CREATE TABLE t_nn (c1 INT); +CREATE VIEW v_nn AS SELECT * FROM t_nn; +CREATE DATABASE mysqltest2; +use mysqltest2; +CREATE TABLE t_nn (c1 INT); +CREATE VIEW v_nn AS SELECT * FROM t_nn; +CREATE VIEW v_yn AS SELECT * FROM t_nn; +CREATE VIEW v_gy AS SELECT * FROM t_nn; +CREATE VIEW v_ny AS SELECT * FROM t_nn; +CREATE VIEW v_yy AS SELECT * FROM t_nn WHERE c1=55; +GRANT SHOW VIEW ON mysqltest2.v_ny TO 'mysqltest_1'@'localhost' IDENTIFIED BY 'mysqltest_1'; +GRANT SELECT ON mysqltest2.v_yn TO 'mysqltest_1'@'localhost' IDENTIFIED BY 'mysqltest_1'; +GRANT SELECT ON mysqltest2.* TO 'mysqltest_1'@'localhost' IDENTIFIED BY 'mysqltest_1'; +GRANT SHOW VIEW,SELECT ON mysqltest2.v_yy TO 'mysqltest_1'@'localhost' IDENTIFIED BY 'mysqltest_1'; +SHOW CREATE VIEW mysqltest2.v_nn; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v_nn' +SHOW CREATE TABLE mysqltest2.v_nn; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v_nn' +SHOW CREATE VIEW mysqltest2.v_yn; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v_yn' +SHOW CREATE TABLE mysqltest2.v_yn; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v_yn' +SHOW CREATE TABLE mysqltest2.v_ny; +View Create View character_set_client collation_connection +v_ny CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest2`.`v_ny` AS select `mysqltest2`.`t_nn`.`c1` AS `c1` from `mysqltest2`.`t_nn` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest2.v_ny; +View Create View character_set_client collation_connection +v_ny CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest2`.`v_ny` AS select `mysqltest2`.`t_nn`.`c1` AS `c1` from `mysqltest2`.`t_nn` latin1 latin1_swedish_ci +SHOW CREATE TABLE mysqltest3.t_nn; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 't_nn' +SHOW CREATE VIEW mysqltest3.t_nn; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 't_nn' +SHOW CREATE VIEW mysqltest3.v_nn; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'v_nn' +SHOW CREATE TABLE mysqltest3.v_nn; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'v_nn' +SHOW CREATE TABLE mysqltest2.t_nn; +Table Create Table +t_nn CREATE TABLE `t_nn` ( + `c1` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +SHOW CREATE VIEW mysqltest2.t_nn; +ERROR HY000: 'mysqltest2.t_nn' is not VIEW +SHOW CREATE VIEW mysqltest2.v_yy; +View Create View character_set_client collation_connection +v_yy CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest2`.`v_yy` AS select `mysqltest2`.`t_nn`.`c1` AS `c1` from `mysqltest2`.`t_nn` where (`mysqltest2`.`t_nn`.`c1` = 55) latin1 latin1_swedish_ci +SHOW CREATE TABLE mysqltest2.v_yy; +View Create View character_set_client collation_connection +v_yy CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest2`.`v_yy` AS select `mysqltest2`.`t_nn`.`c1` AS `c1` from `mysqltest2`.`t_nn` where (`mysqltest2`.`t_nn`.`c1` = 55) latin1 latin1_swedish_ci +SHOW CREATE TABLE mysqltest2.v_nn; +View Create View character_set_client collation_connection +v_nn CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_nn` AS select `t_nn`.`c1` AS `c1` from `t_nn` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest2.v_nn; +View Create View character_set_client collation_connection +v_nn CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_nn` AS select `t_nn`.`c1` AS `c1` from `t_nn` latin1 latin1_swedish_ci +SHOW CREATE TABLE mysqltest2.t_nn; +Table Create Table +t_nn CREATE TABLE `t_nn` ( + `c1` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +SHOW CREATE VIEW mysqltest2.t_nn; +ERROR HY000: 'mysqltest2.t_nn' is not VIEW +DROP VIEW mysqltest2.v_nn; +DROP VIEW mysqltest2.v_yn; +DROP VIEW mysqltest2.v_ny; +DROP VIEW mysqltest2.v_yy; +DROP TABLE mysqltest2.t_nn; +DROP DATABASE mysqltest2; +DROP VIEW mysqltest3.v_nn; +DROP TABLE mysqltest3.t_nn; +DROP DATABASE mysqltest3; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'mysqltest_1'@'localhost'; +DROP USER 'mysqltest_1'@'localhost'; +use test; +create user mysqltest1_thisisreallytoolong; +ERROR HY000: String 'mysqltest1_thisisreallytoolong' is too long for user name (should be no longer than 16) +CREATE DATABASE mysqltest1; +CREATE TABLE mysqltest1.t1 ( +int_field INTEGER UNSIGNED NOT NULL, +char_field CHAR(10), +INDEX(`int_field`) +); +CREATE TABLE mysqltest1.t2 (int_field INT); +"Now check that we require equivalent grants for " +"RENAME TABLE and ALTER TABLE" +CREATE USER mysqltest_1@localhost; +GRANT SELECT ON mysqltest1.t1 TO mysqltest_1@localhost; +SELECT USER(); +USER() +mysqltest_1@localhost +SHOW GRANTS; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT ON `mysqltest1`.`t1` TO 'mysqltest_1'@'localhost' +RENAME TABLE t1 TO t2; +ERROR 42000: DROP,ALTER command denied to user 'mysqltest_1'@'localhost' for table 't1' +ALTER TABLE t1 RENAME TO t2; +ERROR 42000: DROP,ALTER command denied to user 'mysqltest_1'@'localhost' for table 't1' +GRANT DROP ON mysqltest1.t1 TO mysqltest_1@localhost; +RENAME TABLE t1 TO t2; +ERROR 42000: ALTER command denied to user 'mysqltest_1'@'localhost' for table 't1' +ALTER TABLE t1 RENAME TO t2; +ERROR 42000: ALTER command denied to user 'mysqltest_1'@'localhost' for table 't1' +GRANT ALTER ON mysqltest1.t1 TO mysqltest_1@localhost; +SHOW GRANTS; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, DROP, ALTER ON `mysqltest1`.`t1` TO 'mysqltest_1'@'localhost' +RENAME TABLE t1 TO t2; +ERROR 42000: INSERT,CREATE command denied to user 'mysqltest_1'@'localhost' for table 't2' +ALTER TABLE t1 RENAME TO t2; +ERROR 42000: INSERT,CREATE command denied to user 'mysqltest_1'@'localhost' for table 't2' +GRANT INSERT, CREATE ON mysqltest1.t1 TO mysqltest_1@localhost; +SHOW GRANTS; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, CREATE, DROP, ALTER ON `mysqltest1`.`t1` TO 'mysqltest_1'@'localhost' +GRANT INSERT, SELECT, CREATE, ALTER, DROP ON mysqltest1.t2 TO mysqltest_1@localhost; +DROP TABLE mysqltest1.t2; +SHOW GRANTS; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, CREATE, DROP, ALTER ON `mysqltest1`.`t2` TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, CREATE, DROP, ALTER ON `mysqltest1`.`t1` TO 'mysqltest_1'@'localhost' +RENAME TABLE t1 TO t2; +RENAME TABLE t2 TO t1; +ALTER TABLE t1 RENAME TO t2; +ALTER TABLE t2 RENAME TO t1; +REVOKE DROP, INSERT ON mysqltest1.t1 FROM mysqltest_1@localhost; +REVOKE DROP, INSERT ON mysqltest1.t2 FROM mysqltest_1@localhost; +SHOW GRANTS; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, CREATE, ALTER ON `mysqltest1`.`t2` TO 'mysqltest_1'@'localhost' +GRANT SELECT, CREATE, ALTER ON `mysqltest1`.`t1` TO 'mysqltest_1'@'localhost' +RENAME TABLE t1 TO t2; +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1' +ALTER TABLE t1 RENAME TO t2; +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1' +DROP USER mysqltest_1@localhost; +DROP DATABASE mysqltest1; +GRANT CREATE ON mysqltest.* TO 1234567890abcdefGHIKL@localhost; +ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16) +GRANT CREATE ON mysqltest.* TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; +ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) +REVOKE CREATE ON mysqltest.* FROM 1234567890abcdefGHIKL@localhost; +ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16) +REVOKE CREATE ON mysqltest.* FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; +ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) +GRANT CREATE ON t1 TO 1234567890abcdefGHIKL@localhost; +ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16) +GRANT CREATE ON t1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; +ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) +REVOKE CREATE ON t1 FROM 1234567890abcdefGHIKL@localhost; +ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16) +REVOKE CREATE ON t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; +ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) +GRANT EXECUTE ON PROCEDURE p1 TO 1234567890abcdefGHIKL@localhost; +ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16) +GRANT EXECUTE ON PROCEDURE p1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; +ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) +REVOKE EXECUTE ON PROCEDURE p1 FROM 1234567890abcdefGHIKL@localhost; +ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16) +REVOKE EXECUTE ON PROCEDURE t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; +ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/grant_cache.result b/mysql-test/suite/pbxt/r/grant_cache.result new file mode 100644 index 00000000000..500965fd646 --- /dev/null +++ b/mysql-test/suite/pbxt/r/grant_cache.result @@ -0,0 +1,210 @@ +drop table if exists test.t1,mysqltest.t1,mysqltest.t2; +drop database if exists mysqltest; +set GLOBAL query_cache_size=1355776; +reset query cache; +flush status; +show grants for current_user; +Grants for root@localhost +GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION +show grants; +Grants for root@localhost +GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION +create database if not exists mysqltest; +create table mysqltest.t1 (a int,b int,c int); +create table mysqltest.t2 (a int,b int,c int); +insert into mysqltest.t1 values (1,1,1),(2,2,2); +insert into mysqltest.t2 values (3,3,3); +create table test.t1 (a char (10)) engine=myisam; +insert into test.t1 values ("test.t1"); +select * from t1; +a +test.t1 +select * from t1; +a b c +1 1 1 +2 2 2 +select a from t1; +a +1 +2 +select c from t1; +c +1 +2 +select * from t2; +a b c +3 3 3 +select * from mysqltest.t1,test.t1; +a b c a +1 1 1 test.t1 +2 2 2 test.t1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_hits%"; +Variable_name Value +Qcache_hits 0 +grant SELECT on mysqltest.* to mysqltest_1@localhost; +grant SELECT on mysqltest.t1 to mysqltest_2@localhost; +grant SELECT on test.t1 to mysqltest_2@localhost; +grant SELECT(a) on mysqltest.t1 to mysqltest_3@localhost; +show grants for current_user(); +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +show status like "Qcache_not_cached"; +Variable_name Value +Qcache_not_cached 0 +select "user1"; +user1 +user1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +show status like "Qcache_not_cached"; +Variable_name Value +Qcache_not_cached 1 +select * from t1; +a b c +1 1 1 +2 2 2 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +show status like "Qcache_not_cached"; +Variable_name Value +Qcache_not_cached 1 +select a from t1 ; +a +1 +2 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +show status like "Qcache_not_cached"; +Variable_name Value +Qcache_not_cached 1 +select c from t1; +c +1 +2 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +show status like "Qcache_not_cached"; +Variable_name Value +Qcache_not_cached 1 +show grants for current_user(); +Grants for @localhost +GRANT USAGE ON *.* TO ''@'localhost' +select "user2"; +user2 +user2 +select * from t1; +a b c +1 1 1 +2 2 2 +select a from t1; +a +1 +2 +select c from t1; +c +1 +2 +select * from mysqltest.t1,test.t1; +a b c a +1 1 1 test.t1 +2 2 2 test.t1 +select * from t2; +ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't2' +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +show status like "Qcache_not_cached"; +Variable_name Value +Qcache_not_cached 2 +select "user3"; +user3 +user3 +select * from t1; +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 't1' +select a from t1; +a +1 +2 +select c from t1; +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'c' in table 't1' +select * from t2; +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 't2' +select mysqltest.t1.c from test.t1,mysqltest.t1; +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'c' in table 't1' +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 7 +show status like "Qcache_not_cached"; +Variable_name Value +Qcache_not_cached 7 +select "user4"; +user4 +user4 +show grants; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +select a from t1; +ERROR 3D000: No database selected +select * from mysqltest.t1,test.t1; +a b c a +1 1 1 test.t1 +2 2 2 test.t1 +select a from mysqltest.t1; +a +1 +2 +select a from mysqltest.t1; +a +1 +2 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 8 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 8 +show status like "Qcache_not_cached"; +Variable_name Value +Qcache_not_cached 8 +set names binary; +delete from mysql.user where user in ("mysqltest_1","mysqltest_2","mysqltest_3"); +delete from mysql.db where user in ("mysqltest_1","mysqltest_2","mysqltest_3"); +delete from mysql.tables_priv where user in ("mysqltest_1","mysqltest_2","mysqltest_3"); +delete from mysql.columns_priv where user in ("mysqltest_1","mysqltest_2","mysqltest_3"); +flush privileges; +drop table test.t1,mysqltest.t1,mysqltest.t2; +drop database mysqltest; +set GLOBAL query_cache_size=default; diff --git a/mysql-test/suite/pbxt/r/greedy_optimizer.result b/mysql-test/suite/pbxt/r/greedy_optimizer.result new file mode 100644 index 00000000000..1d3e42b70fb --- /dev/null +++ b/mysql-test/suite/pbxt/r/greedy_optimizer.result @@ -0,0 +1,657 @@ +drop table if exists t1,t2,t3,t4,t5,t6,t7; +create table t1 ( +c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer, +primary key (c11) +); +create table t2 ( +c21 integer,c22 integer,c23 integer,c24 integer,c25 integer,c26 integer +); +create table t3 ( +c31 integer,c32 integer,c33 integer,c34 integer,c35 integer,c36 integer, +primary key (c31) +); +create table t4 ( +c41 integer,c42 integer,c43 integer,c44 integer,c45 integer,c46 integer +); +create table t5 ( +c51 integer,c52 integer,c53 integer,c54 integer,c55 integer,c56 integer, +primary key (c51) +); +create table t6 ( +c61 integer,c62 integer,c63 integer,c64 integer,c65 integer,c66 integer +); +create table t7 ( +c71 integer,c72 integer,c73 integer,c74 integer,c75 integer,c76 integer, +primary key (c71) +); +insert into t1 values (1,2,3,4,5,6); +insert into t1 values (2,2,3,4,5,6); +insert into t1 values (3,2,3,4,5,6); +insert into t2 values (1,2,3,4,5,6); +insert into t2 values (2,2,3,4,5,6); +insert into t2 values (3,2,3,4,5,6); +insert into t2 values (4,2,3,4,5,6); +insert into t2 values (5,2,3,4,5,6); +insert into t2 values (6,2,3,4,5,6); +insert into t3 values (1,2,3,4,5,6); +insert into t3 values (2,2,3,4,5,6); +insert into t3 values (3,2,3,4,5,6); +insert into t3 values (4,2,3,4,5,6); +insert into t3 values (5,2,3,4,5,6); +insert into t3 values (6,2,3,4,5,6); +insert into t3 values (7,2,3,4,5,6); +insert into t3 values (8,2,3,4,5,6); +insert into t3 values (9,2,3,4,5,6); +insert into t4 values (1,2,3,4,5,6); +insert into t4 values (2,2,3,4,5,6); +insert into t4 values (3,2,3,4,5,6); +insert into t4 values (4,2,3,4,5,6); +insert into t4 values (5,2,3,4,5,6); +insert into t4 values (6,2,3,4,5,6); +insert into t4 values (7,2,3,4,5,6); +insert into t4 values (8,2,3,4,5,6); +insert into t4 values (9,2,3,4,5,6); +insert into t4 values (10,2,3,4,5,6); +insert into t4 values (11,2,3,4,5,6); +insert into t4 values (12,2,3,4,5,6); +insert into t5 values (1,2,3,4,5,6); +insert into t5 values (2,2,3,4,5,6); +insert into t5 values (3,2,3,4,5,6); +insert into t5 values (4,2,3,4,5,6); +insert into t5 values (5,2,3,4,5,6); +insert into t5 values (6,2,3,4,5,6); +insert into t5 values (7,2,3,4,5,6); +insert into t5 values (8,2,3,4,5,6); +insert into t5 values (9,2,3,4,5,6); +insert into t5 values (10,2,3,4,5,6); +insert into t5 values (11,2,3,4,5,6); +insert into t5 values (12,2,3,4,5,6); +insert into t5 values (13,2,3,4,5,6); +insert into t5 values (14,2,3,4,5,6); +insert into t5 values (15,2,3,4,5,6); +insert into t6 values (1,2,3,4,5,6); +insert into t6 values (2,2,3,4,5,6); +insert into t6 values (3,2,3,4,5,6); +insert into t6 values (4,2,3,4,5,6); +insert into t6 values (5,2,3,4,5,6); +insert into t6 values (6,2,3,4,5,6); +insert into t6 values (7,2,3,4,5,6); +insert into t6 values (8,2,3,4,5,6); +insert into t6 values (9,2,3,4,5,6); +insert into t6 values (10,2,3,4,5,6); +insert into t6 values (11,2,3,4,5,6); +insert into t6 values (12,2,3,4,5,6); +insert into t6 values (13,2,3,4,5,6); +insert into t6 values (14,2,3,4,5,6); +insert into t6 values (15,2,3,4,5,6); +insert into t6 values (16,2,3,4,5,6); +insert into t6 values (17,2,3,4,5,6); +insert into t6 values (18,2,3,4,5,6); +insert into t7 values (1,2,3,4,5,6); +insert into t7 values (2,2,3,4,5,6); +insert into t7 values (3,2,3,4,5,6); +insert into t7 values (4,2,3,4,5,6); +insert into t7 values (5,2,3,4,5,6); +insert into t7 values (6,2,3,4,5,6); +insert into t7 values (7,2,3,4,5,6); +insert into t7 values (8,2,3,4,5,6); +insert into t7 values (9,2,3,4,5,6); +insert into t7 values (10,2,3,4,5,6); +insert into t7 values (11,2,3,4,5,6); +insert into t7 values (12,2,3,4,5,6); +insert into t7 values (13,2,3,4,5,6); +insert into t7 values (14,2,3,4,5,6); +insert into t7 values (15,2,3,4,5,6); +insert into t7 values (16,2,3,4,5,6); +insert into t7 values (17,2,3,4,5,6); +insert into t7 values (18,2,3,4,5,6); +insert into t7 values (19,2,3,4,5,6); +insert into t7 values (20,2,3,4,5,6); +insert into t7 values (21,2,3,4,5,6); +select @@optimizer_search_depth; +@@optimizer_search_depth +62 +select @@optimizer_prune_level; +@@optimizer_prune_level +1 +set optimizer_search_depth=63; +select @@optimizer_search_depth; +@@optimizer_search_depth +63 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +set optimizer_prune_level=0; +select @@optimizer_prune_level; +@@optimizer_prune_level +0 +set optimizer_search_depth=0; +select @@optimizer_search_depth; +@@optimizer_search_depth +0 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using join buffer +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 290.146368 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using join buffer +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 290.146368 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 290.146368 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 290.146368 +set optimizer_search_depth=1; +select @@optimizer_search_depth; +@@optimizer_search_depth +1 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +set optimizer_search_depth=62; +select @@optimizer_search_depth; +@@optimizer_search_depth +62 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using join buffer +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 290.146368 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using join buffer +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 290.146368 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 290.146368 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 290.146368 +set optimizer_prune_level=1; +select @@optimizer_prune_level; +@@optimizer_prune_level +1 +set optimizer_search_depth=0; +select @@optimizer_search_depth; +@@optimizer_search_depth +0 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +set optimizer_search_depth=1; +select @@optimizer_search_depth; +@@optimizer_search_depth +1 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +set optimizer_search_depth=62; +select @@optimizer_search_depth; +@@optimizer_search_depth +62 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1 +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1 +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 822.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using join buffer +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where; Using join buffer +1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where; Using join buffer +1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where +show status like 'Last_query_cost'; +Variable_name Value +Last_query_cost 795.625316 +drop table t1,t2,t3,t4,t5,t6,t7; diff --git a/mysql-test/suite/pbxt/r/group_by.result b/mysql-test/suite/pbxt/r/group_by.result new file mode 100644 index 00000000000..c5c9099af0d --- /dev/null +++ b/mysql-test/suite/pbxt/r/group_by.result @@ -0,0 +1,944 @@ +drop table if exists t1,t2,t3; +SELECT 1 FROM (SELECT 1) as a GROUP BY SUM(1); +ERROR HY000: Invalid use of group function +CREATE TABLE t1 ( +spID int(10) unsigned, +userID int(10) unsigned, +score smallint(5) unsigned, +lsg char(40), +date date +); +INSERT INTO t1 VALUES (1,1,1,'','0000-00-00'); +INSERT INTO t1 VALUES (2,2,2,'','0000-00-00'); +INSERT INTO t1 VALUES (2,1,1,'','0000-00-00'); +INSERT INTO t1 VALUES (3,3,3,'','0000-00-00'); +CREATE TABLE t2 ( +userID int(10) unsigned NOT NULL auto_increment, +niName char(15), +passwd char(8), +mail char(50), +isAukt enum('N','Y') DEFAULT 'N', +vName char(30), +nName char(40), +adr char(60), +plz char(5), +ort char(35), +land char(20), +PRIMARY KEY (userID) +); +INSERT INTO t2 VALUES (1,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (2,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (3,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (4,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (5,'name','pass','mail','Y','v','n','adr','1','1','1'); +SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID GROUP BY t2.userid; +userid MIN(t1.score) +1 1 +2 2 +3 3 +SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID GROUP BY t2.userid ORDER BY NULL; +userid MIN(t1.score) +1 1 +2 2 +3 3 +SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid; +userid MIN(t1.score) +1 1 +2 2 +SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid; +userid MIN(t1.score+0.0) +1 1.0 +2 2.0 +SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; +userid MIN(t1.score+0.0) +2 2.0 +1 1.0 +EXPLAIN SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where; Using temporary +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.userID 1 Using index +drop table t1,t2; +CREATE TABLE t1 ( +PID int(10) unsigned NOT NULL auto_increment, +payDate date DEFAULT '0000-00-00' NOT NULL, +recDate datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, +URID int(10) unsigned DEFAULT '0' NOT NULL, +CRID int(10) unsigned DEFAULT '0' NOT NULL, +amount int(10) unsigned DEFAULT '0' NOT NULL, +operator int(10) unsigned, +method enum('unknown','cash','dealer','check','card','lazy','delayed','test') DEFAULT 'unknown' NOT NULL, +DIID int(10) unsigned, +reason char(1) binary DEFAULT '' NOT NULL, +code_id int(10) unsigned, +qty mediumint(8) unsigned DEFAULT '0' NOT NULL, +PRIMARY KEY (PID), +KEY URID (URID), +KEY reason (reason), +KEY method (method), +KEY payDate (payDate) +); +INSERT INTO t1 VALUES (1,'1970-01-01','1997-10-17 00:00:00',2529,1,21000,11886,'check',0,'F',16200,6); +SELECT COUNT(P.URID),SUM(P.amount),P.method, MIN(PP.recdate+0) > 19980501000000 AS IsNew FROM t1 AS P JOIN t1 as PP WHERE P.URID = PP.URID GROUP BY method,IsNew; +ERROR 42000: Can't group on 'IsNew' +drop table t1; +CREATE TABLE t1 ( +cid mediumint(9) NOT NULL auto_increment, +firstname varchar(32) DEFAULT '' NOT NULL, +surname varchar(32) DEFAULT '' NOT NULL, +PRIMARY KEY (cid) +); +INSERT INTO t1 VALUES (1,'That','Guy'); +INSERT INTO t1 VALUES (2,'Another','Gent'); +CREATE TABLE t2 ( +call_id mediumint(8) NOT NULL auto_increment, +contact_id mediumint(8) DEFAULT '0' NOT NULL, +PRIMARY KEY (call_id), +KEY contact_id (contact_id) +); +lock tables t1 read,t2 write; +INSERT INTO t2 VALUES (10,2); +INSERT INTO t2 VALUES (18,2); +INSERT INTO t2 VALUES (62,2); +INSERT INTO t2 VALUES (91,2); +INSERT INTO t2 VALUES (92,2); +SELECT cid, CONCAT(firstname, ' ', surname), COUNT(call_id) FROM t1 LEFT JOIN t2 ON cid=contact_id WHERE firstname like '%foo%' GROUP BY cid; +cid CONCAT(firstname, ' ', surname) COUNT(call_id) +SELECT cid, CONCAT(firstname, ' ', surname), COUNT(call_id) FROM t1 LEFT JOIN t2 ON cid=contact_id WHERE firstname like '%foo%' GROUP BY cid ORDER BY NULL; +cid CONCAT(firstname, ' ', surname) COUNT(call_id) +SELECT HIGH_PRIORITY cid, CONCAT(firstname, ' ', surname), COUNT(call_id) FROM t1 LEFT JOIN t2 ON cid=contact_id WHERE firstname like '%foo%' GROUP BY cid ORDER BY surname, firstname; +cid CONCAT(firstname, ' ', surname) COUNT(call_id) +drop table t1,t2; +unlock tables; +CREATE TABLE t1 ( +bug_id mediumint(9) NOT NULL auto_increment, +groupset bigint(20) DEFAULT '0' NOT NULL, +assigned_to mediumint(9) DEFAULT '0' NOT NULL, +bug_file_loc text, +bug_severity enum('blocker','critical','major','normal','minor','trivial','enhancement') DEFAULT 'blocker' NOT NULL, +bug_status enum('','NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED') DEFAULT 'NEW' NOT NULL, +creation_ts datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, +delta_ts timestamp, +short_desc mediumtext, +long_desc mediumtext, +op_sys enum('All','Windows 3.1','Windows 95','Windows 98','Windows NT','Windows 2000','Linux','other') DEFAULT 'All' NOT NULL, +priority enum('P1','P2','P3','P4','P5') DEFAULT 'P1' NOT NULL, +product varchar(64) DEFAULT '' NOT NULL, +rep_platform enum('All','PC','VTD-8','Other'), +reporter mediumint(9) DEFAULT '0' NOT NULL, +version varchar(16) DEFAULT '' NOT NULL, +component varchar(50) DEFAULT '' NOT NULL, +resolution enum('','FIXED','INVALID','WONTFIX','LATER','REMIND','DUPLICATE','WORKSFORME') DEFAULT '' NOT NULL, +target_milestone varchar(20) DEFAULT '' NOT NULL, +qa_contact mediumint(9) DEFAULT '0' NOT NULL, +status_whiteboard mediumtext NOT NULL, +votes mediumint(9) DEFAULT '0' NOT NULL, +PRIMARY KEY (bug_id), +KEY assigned_to (assigned_to), +KEY creation_ts (creation_ts), +KEY delta_ts (delta_ts), +KEY bug_severity (bug_severity), +KEY bug_status (bug_status), +KEY op_sys (op_sys), +KEY priority (priority), +KEY product (product), +KEY reporter (reporter), +KEY version (version), +KEY component (component), +KEY resolution (resolution), +KEY target_milestone (target_milestone), +KEY qa_contact (qa_contact), +KEY votes (votes) +); +INSERT INTO t1 VALUES (1,0,0,'','normal','','2000-02-10 09:25:12',20000321114747,'','','Linux','P1','TestProduct','PC',3,'other','TestComponent','','M1',0,'',0); +INSERT INTO t1 VALUES (9,0,0,'','enhancement','','2000-03-10 11:49:36',20000321114747,'','','All','P5','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - conversion','','',0,'',0); +INSERT INTO t1 VALUES (10,0,0,'','enhancement','','2000-03-10 18:10:16',20000321114747,'','','All','P4','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - conversion','','',0,'',0); +INSERT INTO t1 VALUES (7,0,0,'','critical','','2000-03-09 10:50:21',20000321114747,'','','All','P1','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - generic','','',0,'',0); +INSERT INTO t1 VALUES (6,0,0,'','normal','','2000-03-09 10:42:44',20000321114747,'','','All','P2','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0); +INSERT INTO t1 VALUES (8,0,0,'','major','','2000-03-09 11:32:14',20000321114747,'','','All','P3','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0); +INSERT INTO t1 VALUES (5,0,0,'','enhancement','','2000-03-09 10:38:59',20000321114747,'','','All','P5','CCC/CCCCCC','PC',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (4,0,0,'','normal','','2000-03-08 18:32:14',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent2','','',0,'',0); +INSERT INTO t1 VALUES (3,0,0,'','normal','','2000-03-08 18:30:52',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent','','',0,'',0); +INSERT INTO t1 VALUES (2,0,0,'','enhancement','','2000-03-08 18:24:51',20000321114747,'','','All','P2','TestProduct','Other',4,'other','TestComponent2','','',0,'',0); +INSERT INTO t1 VALUES (11,0,0,'','blocker','','2000-03-13 09:43:41',20000321114747,'','','All','P2','CCC/CCCCCC','PC',5,'7.00','DDDDDDDDD','','',0,'',0); +INSERT INTO t1 VALUES (12,0,0,'','normal','','2000-03-13 16:14:31',20000321114747,'','','All','P2','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0); +INSERT INTO t1 VALUES (13,0,0,'','normal','','2000-03-15 16:20:44',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent','','',0,'',0); +INSERT INTO t1 VALUES (14,0,0,'','blocker','','2000-03-15 18:13:47',20000321114747,'','','All','P1','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - generic','','',0,'',0); +INSERT INTO t1 VALUES (15,0,0,'','minor','','2000-03-16 18:03:28',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','DDDDDDDDD','','',0,'',0); +INSERT INTO t1 VALUES (16,0,0,'','normal','','2000-03-16 18:33:41',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (17,0,0,'','normal','','2000-03-16 18:34:18',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (18,0,0,'','normal','','2000-03-16 18:34:56',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (19,0,0,'','enhancement','','2000-03-16 18:35:34',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (20,0,0,'','enhancement','','2000-03-16 18:36:23',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (21,0,0,'','enhancement','','2000-03-16 18:37:23',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (22,0,0,'','enhancement','','2000-03-16 18:38:16',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (23,0,0,'','normal','','2000-03-16 18:58:12',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','DDDDDDDDD','','',0,'',0); +INSERT INTO t1 VALUES (24,0,0,'','normal','','2000-03-17 11:08:10',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0); +INSERT INTO t1 VALUES (25,0,0,'','normal','','2000-03-17 11:10:45',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0); +INSERT INTO t1 VALUES (26,0,0,'','normal','','2000-03-17 11:15:47',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0); +INSERT INTO t1 VALUES (27,0,0,'','normal','','2000-03-17 17:45:41',20000321114747,'','','All','P2','CCC/CCCCCC','PC',5,'7.00','DDDDDDDDD','','',0,'',0); +INSERT INTO t1 VALUES (28,0,0,'','normal','','2000-03-20 09:51:45',20000321114747,'','','Windows NT','P2','TestProduct','PC',8,'other','TestComponent','','',0,'',0); +INSERT INTO t1 VALUES (29,0,0,'','normal','','2000-03-20 11:15:09',20000321114747,'','','All','P5','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0); +CREATE TABLE t2 ( +value tinytext, +program varchar(64), +initialowner tinytext NOT NULL, +initialqacontact tinytext NOT NULL, +description mediumtext NOT NULL +); +INSERT INTO t2 VALUES ('TestComponent','TestProduct','id0001','',''); +INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - conversion','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - generic','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('TestComponent2','TestProduct','id0001','',''); +INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - eeeeeeeee','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('kkkkkkkkkkk lllllllllll','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('Test Procedures','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('Documentation','AAAAA','id0003','',''); +INSERT INTO t2 VALUES ('DDDDDDDDD','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Eeeeeeee Lite','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Eeeeeeee Full','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Administration','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Distribution','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Setup','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Unspecified','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Web Interface','AAAAAAAA-AAA','id0001','',''); +INSERT INTO t2 VALUES ('Host communication','AAAAA','id0001','',''); +select value,description,bug_id from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA"; +value description bug_id +BBBBBBBBBBBBB - conversion 9 +BBBBBBBBBBBBB - conversion 10 +BBBBBBBBBBBBB - generic 7 +BBBBBBBBBBBBB - generic 14 +BBBBBBBBBBBBB - eeeeeeeee NULL +kkkkkkkkkkk lllllllllll 6 +kkkkkkkkkkk lllllllllll 8 +kkkkkkkkkkk lllllllllll 12 +Test Procedures NULL +Documentation NULL +Host communication NULL +select value,description,COUNT(bug_id) from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA" group by value; +value description COUNT(bug_id) +BBBBBBBBBBBBB - conversion 2 +BBBBBBBBBBBBB - eeeeeeeee 0 +BBBBBBBBBBBBB - generic 2 +Documentation 0 +Host communication 0 +kkkkkkkkkkk lllllllllll 3 +Test Procedures 0 +select value,description,COUNT(bug_id) from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA" group by value having COUNT(bug_id) IN (0,2); +value description COUNT(bug_id) +BBBBBBBBBBBBB - conversion 2 +BBBBBBBBBBBBB - eeeeeeeee 0 +BBBBBBBBBBBBB - generic 2 +Documentation 0 +Host communication 0 +Test Procedures 0 +drop table t1,t2; +create table t1 (foo int); +insert into t1 values (1); +select 1+1, "a",count(*) from t1 where foo in (2); +1+1 a count(*) +2 a 0 +insert into t1 values (1); +select 1+1,"a",count(*) from t1 where foo in (2); +1+1 a count(*) +2 a 0 +drop table t1; +CREATE TABLE t1 ( +spID int(10) unsigned, +userID int(10) unsigned, +score smallint(5) unsigned, +key (spid), +key (score) +); +INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3),(6,3,3),(7,3,3); +explain select userid,count(*) from t1 group by userid desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using temporary; Using filesort +explain select userid,count(*) from t1 group by userid desc order by null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using temporary +select userid,count(*) from t1 group by userid desc; +userid count(*) +3 5 +2 1 +1 2 +select userid,count(*) from t1 group by userid desc having (count(*)+1) IN (4,3); +userid count(*) +1 2 +select userid,count(*) from t1 group by userid desc having 3 IN (1,COUNT(*)); +userid count(*) +explain select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range spID spID 5 NULL 1 Using where; Using index +explain select spid,count(*) from t1 where spid between 1 and 2 group by spid; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range spID spID 5 NULL 1 Using where; Using index +explain select spid,count(*) from t1 where spid between 1 and 2 group by spid order by null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range spID spID 5 NULL 1 Using where; Using index +select spid,count(*) from t1 where spid between 1 and 2 group by spid; +spid count(*) +1 1 +2 2 +select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; +spid count(*) +2 2 +1 1 +explain extended select sql_big_result spid,sum(userid) from t1 group by spid desc; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using filesort +Warnings: +Note 1003 select sql_big_result `test`.`t1`.`spID` AS `spid`,sum(`test`.`t1`.`userID`) AS `sum(userid)` from `test`.`t1` group by `test`.`t1`.`spID` desc +explain select sql_big_result spid,sum(userid) from t1 group by spid desc order by null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using filesort +select sql_big_result spid,sum(userid) from t1 group by spid desc; +spid sum(userid) +7 3 +6 3 +5 3 +4 3 +3 3 +2 3 +1 1 +explain select sql_big_result score,count(*) from t1 group by score desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL score 3 NULL 8 Using index; Using filesort +explain select sql_big_result score,count(*) from t1 group by score desc order by null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL score 3 NULL 8 Using index; Using filesort +select sql_big_result score,count(*) from t1 group by score desc; +score count(*) +3 5 +2 1 +1 2 +drop table t1; +create table t1 (a date default null, b date default null); +insert t1 values ('1999-10-01','2000-01-10'), ('1997-01-01','1998-10-01'); +select a,min(b) c,count(distinct rand()) from t1 group by a having c<a + interval 1 day; +a c count(distinct rand()) +drop table t1; +CREATE TABLE t1 (a char(1)); +INSERT INTO t1 VALUES ('A'),('B'),('A'),('B'),('A'),('B'),(NULL),('a'),('b'),(NULL),('A'),('B'),(NULL); +SELECT a FROM t1 GROUP BY a; +a +NULL +A +B +SELECT a,count(*) FROM t1 GROUP BY a; +a count(*) +NULL 3 +A 5 +B 5 +SELECT a FROM t1 GROUP BY binary a; +a +NULL +A +B +a +b +SELECT a,count(*) FROM t1 GROUP BY binary a; +a count(*) +NULL 3 +A 4 +B 4 +a 1 +b 1 +SELECT binary a FROM t1 GROUP BY 1; +binary a +NULL +A +B +a +b +SELECT binary a,count(*) FROM t1 GROUP BY 1; +binary a count(*) +NULL 3 +A 4 +B 4 +a 1 +b 1 +SET SQL_BIG_TABLES=1; +SELECT a FROM t1 GROUP BY a; +a +NULL +A +B +SELECT a,count(*) FROM t1 GROUP BY a; +a count(*) +NULL 3 +A 5 +B 5 +SELECT a FROM t1 GROUP BY binary a; +a +NULL +A +B +a +b +SELECT a,count(*) FROM t1 GROUP BY binary a; +a count(*) +NULL 3 +A 4 +B 4 +a 1 +b 1 +SELECT binary a FROM t1 GROUP BY 1; +binary a +NULL +A +B +a +b +SELECT binary a,count(*) FROM t1 GROUP BY 1; +binary a count(*) +NULL 3 +A 4 +B 4 +a 1 +b 1 +SET SQL_BIG_TABLES=0; +drop table t1; +CREATE TABLE t1 ( +`a` char(193) default NULL, +`b` char(63) default NULL +); +INSERT INTO t1 VALUES ('abc','def'),('hij','klm'); +SELECT CONCAT(a, b) FROM t1 GROUP BY 1; +CONCAT(a, b) +abcdef +hijklm +SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1; +CONCAT(a, b) count(*) +abcdef 1 +hijklm 1 +SELECT CONCAT(a, b),count(distinct a) FROM t1 GROUP BY 1; +CONCAT(a, b) count(distinct a) +abcdef 1 +hijklm 1 +SELECT 1 FROM t1 GROUP BY CONCAT(a, b); +1 +1 +1 +INSERT INTO t1 values ('hij','klm'); +SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1; +CONCAT(a, b) count(*) +abcdef 1 +hijklm 2 +DROP TABLE t1; +create table t1 (One int unsigned, Two int unsigned, Three int unsigned, Four int unsigned); +insert into t1 values (1,2,1,4),(1,2,2,4),(1,2,3,4),(1,2,4,4),(1,1,1,4),(1,1,2,4),(1,1,3,4),(1,1,4,4),(1,3,1,4),(1,3,2,4),(1,3,3,4),(1,3,4,4); +select One, Two, sum(Four) from t1 group by One,Two; +One Two sum(Four) +1 1 16 +1 2 16 +1 3 16 +drop table t1; +create table t1 (id integer primary key not null auto_increment, gender char(1)); +insert into t1 values (NULL, 'M'), (NULL, 'F'),(NULL, 'F'),(NULL, 'F'),(NULL, 'M'); +create table t2 (user_id integer not null, date date); +insert into t2 values (1, '2002-06-09'),(2, '2002-06-09'),(1, '2002-06-09'),(3, '2002-06-09'),(4, '2002-06-09'),(4, '2002-06-09'); +select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender; +gender dist_count percentage +F 3 60.0000 +M 1 20.0000 +select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender order by percentage; +gender dist_count percentage +M 1 20.0000 +F 3 60.0000 +drop table t1,t2; +CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID +)); +insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); +select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; +xID xID1 +1 1 +2 2 +2 2 +3 134 +3 134 +3 134 +4 185 +4 185 +4 185 +4 185 +select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1; +xID xID1 Level +1 1 * +2 2 ** +3 134 *** +4 185 **** +drop table t1; +CREATE TABLE t1 ( +pid int(11) unsigned NOT NULL default '0', +c1id int(11) unsigned default NULL, +c2id int(11) unsigned default NULL, +value int(11) unsigned NOT NULL default '0', +UNIQUE KEY pid2 (pid,c1id,c2id), +UNIQUE KEY pid (pid,value) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 1, NULL, 1),(1, 2, NULL, 2),(1, NULL, 3, 3),(1, 4, NULL, 4),(1, 5, NULL, 5); +CREATE TABLE t2 ( +id int(11) unsigned NOT NULL default '0', +active enum('Yes','No') NOT NULL default 'Yes', +PRIMARY KEY (id) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1, 'Yes'),(2, 'No'),(4, 'Yes'),(5, 'No'); +CREATE TABLE t3 ( +id int(11) unsigned NOT NULL default '0', +active enum('Yes','No') NOT NULL default 'Yes', +PRIMARY KEY (id) +); +INSERT INTO t3 VALUES (3, 'Yes'); +select * from t1 AS m LEFT JOIN t2 AS c1 ON m.c1id = +c1.id AND c1.active = 'Yes' LEFT JOIN t3 AS c2 ON m.c2id = c2.id AND +c2.active = 'Yes' WHERE m.pid=1 AND (c1.id IS NOT NULL OR c2.id IS NOT NULL); +pid c1id c2id value id active id active +1 1 NULL 1 1 Yes NULL NULL +1 NULL 3 3 NULL NULL 3 Yes +1 4 NULL 4 4 Yes NULL NULL +select max(value) from t1 AS m LEFT JOIN t2 AS c1 ON +m.c1id = c1.id AND c1.active = 'Yes' LEFT JOIN t3 AS c2 ON m.c2id = +c2.id AND c2.active = 'Yes' WHERE m.pid=1 AND (c1.id IS NOT NULL OR c2.id IS +NOT NULL); +max(value) +4 +drop table t1,t2,t3; +create table t1 (a blob null); +insert into t1 values (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(""),(""),(""),("b"); +select a,count(*) from t1 group by a; +a count(*) +NULL 9 + 3 +b 1 +set option sql_big_tables=1; +select a,count(*) from t1 group by a; +a count(*) +NULL 9 + 3 +b 1 +drop table t1; +create table t1 (a int not null, b int not null); +insert into t1 values (1,1),(1,2),(3,1),(3,2),(2,2),(2,1); +create table t2 (a int not null, b int not null, key(a)); +insert into t2 values (1,3),(3,1),(2,2),(1,1); +select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b; +a b +1 1 +1 3 +2 2 +3 1 +select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b ORDER BY NULL; +a b +1 3 +3 1 +2 2 +1 1 +explain select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary; Using filesort +1 SIMPLE t2 ALL a NULL NULL NULL 4 Using where; Using join buffer +explain select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b ORDER BY NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary +1 SIMPLE t2 ALL a NULL NULL NULL 4 Using where; Using join buffer +drop table t1,t2; +create table t1 (a int, b int); +insert into t1 values (1, 4),(10, 40),(1, 4),(10, 43),(1, 4),(10, 41),(1, 4),(10, 43),(1, 4); +select a, MAX(b), INTERVAL (MAX(b), 1,3,10,30,39,40,50,60,100,1000) from t1 group by a; +a MAX(b) INTERVAL (MAX(b), 1,3,10,30,39,40,50,60,100,1000) +1 4 2 +10 43 6 +select a, MAX(b), CASE MAX(b) when 4 then 4 when 43 then 43 else 0 end from t1 group by a; +a MAX(b) CASE MAX(b) when 4 then 4 when 43 then 43 else 0 end +1 4 4 +10 43 43 +select a, MAX(b), FIELD(MAX(b), '43', '4', '5') from t1 group by a; +a MAX(b) FIELD(MAX(b), '43', '4', '5') +1 4 2 +10 43 1 +select a, MAX(b), CONCAT_WS(MAX(b), '43', '4', '5') from t1 group by a; +a MAX(b) CONCAT_WS(MAX(b), '43', '4', '5') +1 4 434445 +10 43 43434435 +select a, MAX(b), ELT(MAX(b), 'a', 'b', 'c', 'd', 'e', 'f') from t1 group by a; +a MAX(b) ELT(MAX(b), 'a', 'b', 'c', 'd', 'e', 'f') +1 4 d +10 43 NULL +select a, MAX(b), MAKE_SET(MAX(b), 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h') from t1 group by a; +a MAX(b) MAKE_SET(MAX(b), 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h') +1 4 c +10 43 a,b,d,f +drop table t1; +create table t1 (id int not null, qty int not null); +insert into t1 values (1,2),(1,3),(2,4),(2,5); +select id, sum(qty) as sqty, count(qty) as cqty from t1 group by id having sum(qty)>2 and cqty>1; +id sqty cqty +1 5 2 +2 9 2 +select id, sum(qty) as sqty from t1 group by id having sqty>2 and count(qty)>1; +id sqty +1 5 +2 9 +select id, sum(qty) as sqty, count(qty) as cqty from t1 group by id having sqty>2 and cqty>1; +id sqty cqty +1 5 2 +2 9 2 +select id, sum(qty) as sqty, count(qty) as cqty from t1 group by id having sum(qty)>2 and count(qty)>1; +id sqty cqty +1 5 2 +2 9 2 +select count(*), case interval(qty,2,3,4,5,6,7,8) when -1 then NULL when 0 then "zero" when 1 then "one" when 2 then "two" end as category from t1 group by category; +count(*) category +2 NULL +1 one +1 two +select count(*), interval(qty,2,3,4,5,6,7,8) as category from t1 group by category; +count(*) category +1 1 +1 2 +1 3 +1 4 +drop table t1; +CREATE TABLE t1 ( +userid int(10) unsigned, +score smallint(5) unsigned, +key (score) +); +INSERT INTO t1 VALUES (1,1),(2,2),(1,1),(3,3),(3,3),(3,3),(3,3),(3,3); +SELECT userid,count(*) FROM t1 GROUP BY userid DESC; +userid count(*) +3 5 +2 1 +1 2 +EXPLAIN SELECT userid,count(*) FROM t1 GROUP BY userid DESC; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using temporary; Using filesort +DROP TABLE t1; +CREATE TABLE t1 ( +i int(11) default NULL, +j int(11) default NULL +); +INSERT INTO t1 VALUES (1,2),(2,3),(4,5),(3,5),(1,5),(23,5); +SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; +i COUNT(DISTINCT(i)) +1 1 +2 1 +4 4 +explain SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort +DROP TABLE t1; +create table t1 (a int); +insert into t1 values(null); +select min(a) is null from t1; +min(a) is null +1 +select min(a) is null or null from t1; +min(a) is null or null +1 +select 1 and min(a) is null from t1; +1 and min(a) is null +1 +drop table t1; +create table t1 ( col1 int, col2 int ); +insert into t1 values (1,1),(1,2),(1,3),(2,1),(2,2); +select group_concat( distinct col1 ) as alias from t1 +group by col2 having alias like '%'; +alias +1,2 +1,2 +1 +drop table t1; +create table t1 (a integer, b integer, c integer); +insert into t1 (a,b) values (1,2),(1,3),(2,5); +select a, 0.1*0+1 r2, sum(1) r1 from t1 where a = 1 group by a having r1>1 and r2=1; +a r2 r1 +1 1.0 2 +select a, round(rand(100)*10) r2, sum(1) r1 from t1 where a = 1 group by a having r1>1 and r2<=2; +a r2 r1 +1 2 2 +select a,sum(b) from t1 where a=1 group by c; +a sum(b) +1 5 +select a*sum(b) from t1 where a=1 group by c; +a*sum(b) +5 +select sum(a)*sum(b) from t1 where a=1 group by c; +sum(a)*sum(b) +10 +select a,sum(b) from t1 where a=1 group by c having a=1; +a sum(b) +1 5 +select a as d,sum(b) from t1 where a=1 group by c having d=1; +d sum(b) +1 5 +select sum(a)*sum(b) as d from t1 where a=1 group by c having d > 0; +d +10 +drop table t1; +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(8),(9); +create table t2 ( +a int, +b varchar(200) NOT NULL, +c varchar(50) NOT NULL, +d varchar(100) NOT NULL, +primary key (a,b(132),c,d), +key a (a,b) +) charset=utf8; +insert into t2 select +x3.a, -- 3 +concat('val-', x3.a + 3*x4.a), -- 12 +concat('val-', @a:=x3.a + 3*x4.a + 12*C.a), -- 120 +concat('val-', @a + 120*D.a) +from t1 x3, t1 x4, t1 C, t1 D where x3.a < 3 and x4.a < 4 and D.a < 4; +delete from t2 where a = 2 and b = 'val-2' order by a,b,c,d limit 30; +explain select c from t2 where a = 2 and b = 'val-2' group by c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref PRIMARY,a PRIMARY 402 const,const # Using where +select c from t2 where a = 2 and b = 'val-2' group by c; +c +val-74 +val-98 +drop table t1,t2; +create table t1 (b int4 unsigned not null); +insert into t1 values(3000000000); +select * from t1; +b +3000000000 +select min(b) from t1; +min(b) +3000000000 +drop table t1; +CREATE TABLE t1 (id int PRIMARY KEY, user_id int, hostname longtext); +INSERT INTO t1 VALUES +(1, 7, 'cache-dtc-af05.proxy.aol.com'), +(2, 3, 'what.ever.com'), +(3, 7, 'cache-dtc-af05.proxy.aol.com'), +(4, 7, 'cache-dtc-af05.proxy.aol.com'); +SELECT hostname, COUNT(DISTINCT user_id) as no FROM t1 +WHERE hostname LIKE '%aol%' + GROUP BY hostname; +hostname no +cache-dtc-af05.proxy.aol.com 1 +DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,2), (1,3); +SELECT a, b FROM t1 GROUP BY 'const'; +a b +1 2 +SELECT DISTINCT a, b FROM t1 GROUP BY 'const'; +a b +1 2 +DROP TABLE t1; +CREATE TABLE t1 (id INT, dt DATETIME); +INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); +INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); +INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); +INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); +SELECT dt DIV 1 AS f, id FROM t1 GROUP BY f; +f id +20050501123000 1 +DROP TABLE t1; +CREATE TABLE t1 (id varchar(20) NOT NULL); +INSERT INTO t1 VALUES ('trans1'), ('trans2'); +CREATE TABLE t2 (id varchar(20) NOT NULL, err_comment blob NOT NULL); +INSERT INTO t2 VALUES ('trans1', 'a problem'); +SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment +FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; +COUNT(DISTINCT(t1.id)) comment +1 NULL +1 a problem +DROP TABLE t1, t2; +create table t1 (f1 date); +insert into t1 values('2005-06-06'); +insert into t1 values('2005-06-06'); +select date(left(f1+0,8)) from t1 group by 1; +date(left(f1+0,8)) +2005-06-06 +drop table t1; +CREATE TABLE t1 (n int); +INSERT INTO t1 VALUES (1); +SELECT n+1 AS n FROM t1 GROUP BY n; +n +2 +Warnings: +Warning 1052 Column 'n' in group statement is ambiguous +DROP TABLE t1; +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +max(f1) is null +0 +select sql_buffer_result max(f1)+1 from t1; +max(f1)+1 +3 +drop table t1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1),(2); +SELECT a FROM t1 GROUP BY 'a'; +a +1 +SELECT a FROM t1 GROUP BY "a"; +a +1 +SELECT a FROM t1 GROUP BY `a`; +a +1 +2 +set sql_mode=ANSI_QUOTES; +SELECT a FROM t1 GROUP BY "a"; +a +1 +2 +SELECT a FROM t1 GROUP BY 'a'; +a +1 +SELECT a FROM t1 GROUP BY `a`; +a +1 +2 +set sql_mode=''; +SELECT a FROM t1 HAVING 'a' > 1; +a +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +SELECT a FROM t1 HAVING "a" > 1; +a +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'a' +SELECT a FROM t1 HAVING `a` > 1; +a +2 +SELECT a FROM t1 ORDER BY 'a' DESC; +a +1 +2 +SELECT a FROM t1 ORDER BY "a" DESC; +a +1 +2 +SELECT a FROM t1 ORDER BY `a` DESC; +a +2 +1 +DROP TABLE t1; +create table t1 (c1 char(3), c2 char(3)); +create table t2 (c3 char(3), c4 char(3)); +insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); +insert into t2 values ('aaa', 'bb1'), ('aaa', 'bb2'); +select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 +group by c2; +c2 +aaa +aaa +Warnings: +Warning 1052 Column 'c2' in group statement is ambiguous +show warnings; +Level Code Message +Warning 1052 Column 'c2' in group statement is ambiguous +select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 +group by t1.c1; +c2 +aaa +show warnings; +Level Code Message +drop table t1, t2; +CREATE TABLE t1 (a tinyint(3), b varchar(255), PRIMARY KEY (a)); +INSERT INTO t1 VALUES (1,'-----'), (6,'Allemagne'), (17,'Autriche'), +(25,'Belgique'), (54,'Danemark'), (62,'Espagne'), (68,'France'); +CREATE TABLE t2 (a tinyint(3), b tinyint(3), PRIMARY KEY (a), KEY b (b)); +INSERT INTO t2 VALUES (1,1), (2,1), (6,6), (18,17), (15,25), (16,25), +(17,25), (10,54), (5,62),(3,68); +CREATE VIEW v1 AS select t1.a, concat(t1.b,'') AS b, t1.b as real_b from t1; +explain +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 2 NULL 10 Using index +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 1 test.t2.b 1 +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +a b real_b +1 ----- ----- +6 Allemagne Allemagne +17 Autriche Autriche +25 Belgique Belgique +54 Danemark Danemark +62 Espagne Espagne +68 France France +DROP VIEW v1; +DROP TABLE t1,t2; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT, key (b)); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 SELECT a + 1 , MOD(a + 1 , 20) FROM t1; +INSERT INTO t1 SELECT a + 2 , MOD(a + 2 , 20) FROM t1; +INSERT INTO t1 SELECT a + 4 , MOD(a + 4 , 20) FROM t1; +INSERT INTO t1 SELECT a + 8 , MOD(a + 8 , 20) FROM t1; +INSERT INTO t1 SELECT a + 16, MOD(a + 16, 20) FROM t1; +INSERT INTO t1 SELECT a + 32, MOD(a + 32, 20) FROM t1; +INSERT INTO t1 SELECT a + 64, MOD(a + 64, 20) FROM t1; +SELECT MIN(b), MAX(b) from t1; +MIN(b) MAX(b) +0 19 +EXPLAIN SELECT b, sum(1) FROM t1 GROUP BY b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL b 5 NULL 128 Using index +EXPLAIN SELECT SQL_BIG_RESULT b, sum(1) FROM t1 GROUP BY b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL b 5 NULL 128 Using index; Using filesort +SELECT b, sum(1) FROM t1 GROUP BY b; +b sum(1) +0 6 +1 7 +2 7 +3 7 +4 7 +5 7 +6 7 +7 7 +8 7 +9 6 +10 6 +11 6 +12 6 +13 6 +14 6 +15 6 +16 6 +17 6 +18 6 +19 6 +SELECT SQL_BIG_RESULT b, sum(1) FROM t1 GROUP BY b; +b sum(1) +0 6 +1 7 +2 7 +3 7 +4 7 +5 7 +6 7 +7 7 +8 7 +9 6 +10 6 +11 6 +12 6 +13 6 +14 6 +15 6 +16 6 +17 6 +18 6 +19 6 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT, KEY(a)); +INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4); +EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 2 +EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/group_min_max.result b/mysql-test/suite/pbxt/r/group_min_max.result new file mode 100644 index 00000000000..e8bd3d98834 --- /dev/null +++ b/mysql-test/suite/pbxt/r/group_min_max.result @@ -0,0 +1,2375 @@ +drop table if exists t1; +create table t1 ( +a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +); +insert into t1 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'), +('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'), +('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'), +('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'), +('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'), +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'), +('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'), +('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'), +('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'), +('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'); +create index idx_t1_0 on t1 (a1); +create index idx_t1_1 on t1 (a1,a2,b,c); +create index idx_t1_2 on t1 (a1,a2,b); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +drop table if exists t2; +create table t2 ( +a1 char(64), a2 char(64) not null, b char(16), c char(16), d char(16), dummy char(64) default ' ' +); +insert into t2 select * from t1; +insert into t2 (a1, a2, b, c, d) values +('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'), +('a','a','a',NULL,'xyz'), +('a','a','b',NULL,'xyz'), +('a','b','a',NULL,'xyz'), +('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'), +('d','b','b',NULL,'xyz'), +('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'), +('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'), +('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'), +('a','a','a',NULL,'xyz'), +('a','a','b',NULL,'xyz'), +('a','b','a',NULL,'xyz'), +('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'), +('d','b','b',NULL,'xyz'), +('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'), +('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'); +create index idx_t2_0 on t2 (a1); +create index idx_t2_1 on t2 (a1,a2,b,c); +create index idx_t2_2 on t2 (a1,a2,b); +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +drop table if exists t3; +create table t3 ( +a1 char(1), a2 char(1), b char(1), c char(4) not null, d char(3), dummy char(1) default ' ' +); +insert into t3 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'); +insert into t3 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'); +insert into t3 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'); +insert into t3 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'); +create index idx_t3_0 on t3 (a1); +create index idx_t3_1 on t3 (a1,a2,b,c); +create index idx_t3_2 on t3 (a1,a2,b); +analyze table t3; +Table Op Msg_type Msg_text +test.t3 analyze status OK +explain select a1, min(a2) from t1 group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 130 NULL 10 Using index for group-by +explain select a1, max(a2) from t1 group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 65 NULL 10 Using index for group-by +explain select a1, min(a2), max(a2) from t1 group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 130 NULL 10 Using index for group-by +explain select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using index for group-by +explain select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using index for group-by +explain select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 # NULL # Using index for group-by +explain select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 130 NULL 10 Using index for group-by +explain select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using index for group-by +explain select min(a2) from t1 group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 130 NULL 10 Using index for group-by +explain select a2, min(c), max(c) from t1 group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using index for group-by +select a1, min(a2) from t1 group by a1; +a1 min(a2) +a a +b a +c a +d a +select a1, max(a2) from t1 group by a1; +a1 max(a2) +a b +b b +c b +d b +select a1, min(a2), max(a2) from t1 group by a1; +a1 min(a2) max(a2) +a a b +b a b +c a b +d a b +select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a a111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b; +a1 a2 b max(c) min(c) +a a a d111 a111 +a a b h112 e112 +a b a l121 i121 +a b b p122 m122 +b a a d211 a211 +b a b h212 e212 +b b a l221 i221 +b b b p222 m222 +c a a d311 a311 +c a b h312 e312 +c b a l321 i321 +c b b p322 m322 +d a a d411 a411 +d a b h412 e412 +d b a l421 i421 +d b b p422 m422 +select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b; +a1 a2 b max(c) min(c) +a a NULL a999 a777 +a a a d111 a111 +a a b h112 e112 +a b a l121 i121 +a b b p122 m122 +b a a d211 a211 +b a b h212 e212 +b b a l221 i221 +b b b p222 m222 +c a NULL c999 c777 +c a a d311 a311 +c a b h312 e312 +c b a l321 i321 +c b b p322 m322 +d a a d411 a411 +d a b h412 e412 +d b a l421 i421 +d b b p422 m422 +e a a NULL NULL +e a b NULL NULL +select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1; +min(a2) a1 max(a2) min(a2) a1 +a a b a a +a b b a b +a c b a c +a d b a d +select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b; +a1 b min(c) a1 max(c) b a2 max(c) max(c) +a a a111 a d111 a a d111 d111 +a b e112 a h112 b a h112 h112 +a a i121 a l121 a b l121 l121 +a b m122 a p122 b b p122 p122 +b a a211 b d211 a a d211 d211 +b b e212 b h212 b a h212 h212 +b a i221 b l221 a b l221 l221 +b b m222 b p222 b b p222 p222 +c a a311 c d311 a a d311 d311 +c b e312 c h312 b a h312 h312 +c a i321 c l321 a b l321 l321 +c b m322 c p322 b b p322 p322 +d a a411 d d411 a a d411 d411 +d b e412 d h412 b a h412 h412 +d a i421 d l421 a b l421 l421 +d b m422 d p422 b b p422 p422 +select min(a2) from t1 group by a1; +min(a2) +a +a +a +a +select a2, min(c), max(c) from t1 group by a1,a2,b; +a2 min(c) max(c) +a a111 d111 +a e112 h112 +b i121 l121 +b m122 p122 +a a211 d211 +a e212 h212 +b i221 l221 +b m222 p222 +a a311 d311 +a e312 h312 +b i321 l321 +b m322 p322 +a a411 d411 +a e412 h412 +b i421 l421 +b m422 p422 +explain select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 Using where +explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 Using where +explain select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 1 Using where; Using index for group-by +explain select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 1 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 65 NULL 3 Using where; Using index +explain select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 65 NULL 3 Using where; Using index +explain select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 130 NULL 4 Using where; Using index +explain select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 130 NULL 4 Using where; Using index +explain select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 Using where +explain select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 65 NULL 3 Using where; Using index +explain select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 65 NULL # Using where +explain select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 65 NULL # Using where +explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 65 NULL # Using where +explain select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL # Using where; Using index for group-by +explain select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 65 NULL # Using where; Using index +explain select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 65 NULL # Using where; Using index +explain select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 129 NULL # Using where; Using index +explain select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 129 NULL # Using where; Using index +explain select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 65 NULL # Using where +explain select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 65 NULL # Using where; Using index +select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a a111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; +a1 a2 b min(c) max(c) +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +a1 a2 b max(c) +a a a d111 +a a b h112 +a b a l121 +a b b p122 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +a1 max(c) +a d111 +a h112 +a l121 +a p122 +c d311 +c h312 +c l321 +c p322 +d d411 +d h412 +d l421 +d p422 +select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a a111 d111 +a a b e112 h112 +b a a a211 d211 +b a b e212 h212 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +a1 a2 b max(c) +b a a d211 +b a b h212 +b b a l221 +b b b p222 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +a1 a2 b min(c) max(c) +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +a1 a2 b max(c) +a b a l121 +a b b p122 +b b a l221 +b b b p222 +c b a l321 +c b b p322 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +a1 a2 b min(c) max(c) +a b a i121 l121 +a b b m122 p122 +b b a i221 l221 +b b b m222 p222 +c b a i321 l321 +c b b m322 p322 +d b a i421 l421 +d b b m422 p422 +select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; +a1 min(c) max(c) +b a211 d211 +b e212 h212 +b i221 l221 +b m222 p222 +c a311 d311 +c e312 h312 +c i321 l321 +c m322 p322 +d a411 d411 +d e412 h412 +d i421 l421 +d m422 p422 +select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b; +a1 max(c) +a d111 +a h112 +a l121 +a p122 +b d211 +b h212 +b l221 +b p222 +d d411 +d h412 +d l421 +d p422 +select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b; +a1 a2 b max(c) +a a NULL a999 +a a a d111 +a a b h112 +a b a l121 +a b b p122 +b a a d211 +b a b h212 +b b a l221 +b b b p222 +c a NULL c999 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b; +a1 a2 b min(c) max(c) +a a NULL a777 a999 +a a a a111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a NULL c777 c999 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; +a1 a2 b min(c) max(c) +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a NULL c777 c999 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +e a a NULL NULL +e a b NULL NULL +select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +a1 a2 b max(c) +a a NULL a999 +a a a d111 +a a b h112 +a b a l121 +a b b p122 +c a NULL c999 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +e a a NULL +e a b NULL +select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +a1 max(c) +a a999 +a d111 +a h112 +a l121 +a p122 +c c999 +c d311 +c h312 +c l321 +c p322 +d d411 +d h412 +d l421 +d p422 +e NULL +e NULL +select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; +a1 a2 b min(c) max(c) +a a NULL a777 a999 +a a a a111 d111 +a a b e112 h112 +b a a a211 d211 +b a b e212 h212 +c a NULL c777 c999 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +e a a NULL NULL +e a b NULL NULL +select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +a1 a2 b max(c) +b a a d211 +b a b h212 +b b a l221 +b b b p222 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +a1 a2 b min(c) max(c) +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +a1 a2 b max(c) +a b a l121 +a b b p122 +b b a l221 +b b b p222 +c b a l321 +c b b p322 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +a1 a2 b min(c) max(c) +a b a i121 l121 +a b b m122 p122 +b b a i221 l221 +b b b m222 p222 +c b a i321 l321 +c b b m322 p322 +d b a i421 l421 +d b b m422 p422 +select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; +a1 min(c) max(c) +b a211 d211 +b e212 h212 +b i221 l221 +b m222 p222 +c c777 c999 +c a311 d311 +c e312 h312 +c i321 l321 +c m322 p322 +d a411 d411 +d e412 h412 +d i421 l421 +d m422 p422 +e NULL NULL +e NULL NULL +select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b; +a1 max(c) +a a999 +a d111 +a h112 +a l121 +a p122 +b d211 +b h212 +b l221 +b p222 +d d411 +d h412 +d l421 +d p422 +explain select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by +explain select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 146 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 146 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range NULL idx_t3_1 6 NULL 10 Using where; Using index for group-by +explain select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range NULL idx_t3_1 6 NULL 10 Using where; Using index for group-by +select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1; +a1 a2 b max(c) min(c) +a a b h112 e112 +b a b h212 e212 +c a b h312 e312 +d a b h412 e412 +select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1; +a1 max(c) min(c) +a h112 e112 +b h212 e212 +c h312 e312 +d h412 e412 +select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2; +a1 a2 b max(c) +a a b h112 +a b b p122 +b a b h212 +b b b p222 +c a b h312 +c b b p322 +d a b h412 +d b b p422 +select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2; +a1 a2 b min(c) max(c) +a a b e112 h112 +a b b m122 p122 +b a b e212 h212 +b b b m222 p222 +c a b e312 h312 +c b b m322 p322 +d a b e412 h412 +d b b m422 p422 +select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2; +a1 a2 max(c) +a a h112 +a b p122 +b a h212 +b b p222 +c a h312 +c b p322 +d a h412 +d b p422 +select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1; +a1 a2 b max(c) min(c) +a a b h112 e112 +b a b h212 e212 +c a b h312 e312 +d a b h412 e412 +e a b NULL NULL +select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1; +a1 max(c) min(c) +a h112 e112 +b h212 e212 +c h312 e312 +d h412 e412 +e NULL NULL +select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2; +a1 a2 b max(c) +a a b h112 +a b b p122 +b a b h212 +b b b p222 +c a b h312 +c b b p322 +d a b h412 +d b b p422 +e a b NULL +select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2; +a1 a2 b min(c) max(c) +a a b e112 h112 +a b b m122 p122 +b a b e212 h212 +b b b m222 p222 +c a b e312 h312 +c b b m322 p322 +d a b e412 h412 +d b b m422 p422 +e a b NULL NULL +select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2; +a1 a2 max(c) +a a h112 +a b p122 +b a h212 +b b p222 +c a h312 +c b p322 +d a h412 +d b p422 +e a NULL +select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1; +a1 a2 b max(c) min(c) +a a b h112 e112 +b a b h212 e212 +c a b h312 e312 +select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1; +a1 max(c) min(c) +a h112 e112 +b h212 e212 +c h312 e312 +explain select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 146 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 146 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by +select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1; +a1 a2 b min(c) +a a NULL a777 +c a NULL c777 +select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1; +a1 a2 b max(c) +a a NULL a999 +c a NULL c999 +select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2; +a1 a2 b min(c) +a a NULL a777 +c a NULL c777 +select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2; +a1 a2 b max(c) +a a NULL a999 +c a NULL c999 +select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2; +a1 a2 b min(c) max(c) +a a NULL a777 a999 +c a NULL c777 c999 +select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2; +a1 a2 b min(c) max(c) +a a NULL a777 a999 +c a NULL c777 c999 +explain select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b; +a1 a2 b max(c) +a a a d111 +a a b h112 +a b a l121 +a b b p122 +b a a d211 +b a b h212 +b b a l221 +b b b p222 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a b111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a b211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a a b311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a b411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b; +a1 a2 b max(c) +a a b h112 +a b a l121 +a b b p122 +b a b h212 +b b a l221 +b b b p222 +c a b h312 +c b a l321 +c b b p322 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a b g112 h112 +a b a i121 l121 +a b b m122 p122 +b a b f212 h212 +b b a i221 l221 +b b b m222 p222 +c a b f312 h312 +c b a i321 l321 +c b b m322 p322 +d a b f412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b; +a1 a2 b max(c) +select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b; +a1 a2 b min(c) max(c) +select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b; +a1 a2 b max(c) +a a a d111 +a a b h112 +a b a k121 +b a a d211 +b a b h212 +b b a k221 +c a a d311 +c a b h312 +c b a j321 +d a a d411 +d a b h412 +d b a j421 +select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a a111 d111 +a a b e112 h112 +a b a i121 k121 +b a a a211 d211 +b a b e212 h212 +b b a i221 k221 +c a a a311 d311 +c a b e312 h312 +c b a i321 j321 +d a a a411 d411 +d a b e412 h412 +d b a i421 j421 +select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +a1 a2 b max(c) +a a a d111 +a a b h112 +a b a l121 +a b b p122 +b a a d211 +b a b h212 +b b a l221 +b b b p222 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a b111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a b211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a a b311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a b411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +a1 a2 b max(c) +a a a d111 +a a b h112 +a b a l121 +a b b p122 +b a a d211 +b a b h212 +b b a l221 +b b b p222 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a a111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a c111 d111 +a a b e112 g112 +b a a b211 d211 +b a b e212 f212 +c a a b311 d311 +c a b e312 f312 +d a a b411 d411 +d a b e412 f412 +select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a a111 c111 +b a a a211 c211 +c a a a311 c311 +d a a a411 c411 +d a b g412 g412 +d b a k421 k421 +select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a c111 d111 +a a b e112 h112 +b a a b211 d211 +b a b e212 h212 +c a a b311 d311 +c a b e312 h312 +d a a b411 d411 +d a b e412 h412 +select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a b111 d111 +a a b e112 h112 +b a a b211 d211 +b a b e212 h212 +c a a b311 d311 +c a b e312 h312 +d a a b411 d411 +d a b e412 h412 +select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b; +a1 a2 b max(c) +a a a d111 +a a b h112 +a b a l121 +a b b p122 +b a a d211 +b a b h212 +b b a l221 +b b b p222 +c a NULL c999 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a b111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a b211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a NULL c777 c999 +c a a b311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a b411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b; +a1 a2 b max(c) +a a b h112 +a b a l121 +a b b p122 +b a b h212 +b b a l221 +b b b p222 +c a b h312 +c b a l321 +c b b p322 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a b g112 h112 +a b a i121 l121 +a b b m122 p122 +b a b f212 h212 +b b a i221 l221 +b b b m222 p222 +c a b f312 h312 +c b a i321 l321 +c b b m322 p322 +d a b f412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b; +a1 a2 b max(c) +select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b; +a1 a2 b min(c) max(c) +select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b; +a1 a2 b max(c) +a a NULL a999 +a a a d111 +a a b h112 +a b a k121 +b a a d211 +b a b h212 +b b a k221 +c a NULL c999 +c a a d311 +c a b h312 +c b a j321 +d a a d411 +d a b h412 +d b a j421 +select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a NULL a777 a999 +a a a a111 d111 +a a b e112 h112 +a b a i121 k121 +b a a a211 d211 +b a b e212 h212 +b b a i221 k221 +c a NULL c777 c999 +c a a a311 d311 +c a b e312 h312 +c b a i321 j321 +d a a a411 d411 +d a b e412 h412 +d b a i421 j421 +select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +a1 a2 b max(c) +a a a d111 +a a b h112 +a b a l121 +a b b p122 +b a a d211 +b a b h212 +b b a l221 +b b b p222 +c a NULL c999 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a b111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a b211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a NULL c777 c999 +c a a b311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a b411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +a1 a2 b max(c) +a a NULL a999 +a a a d111 +a a b h112 +a b a l121 +a b b p122 +b a a d211 +b a b h212 +b b a l221 +b b b p222 +c a NULL c999 +c a a d311 +c a b h312 +c b a l321 +c b b p322 +d a a d411 +d a b h412 +d b a l421 +d b b p422 +select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a NULL a777 a999 +a a a a111 d111 +a a b e112 h112 +a b a i121 l121 +a b b m122 p122 +b a a a211 d211 +b a b e212 h212 +b b a i221 l221 +b b b m222 p222 +c a NULL c777 c999 +c a a a311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a a411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a c111 d111 +a a b e112 g112 +b a a b211 d211 +b a b e212 f212 +c a NULL c777 c999 +c a a b311 d311 +c a b e312 f312 +d a a b411 d411 +d a b e412 f412 +select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a NULL a777 a999 +a a a a111 c111 +b a a a211 c211 +c a a a311 c311 +d a a a411 c411 +d a b g412 g412 +d b a k421 k421 +select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a c111 d111 +a a b e112 h112 +b a a b211 d211 +b a b e212 h212 +c a NULL c777 c999 +c a a b311 d311 +c a b e312 h312 +d a a b411 d411 +d a b e412 h412 +explain select a1,a2,b,min(c),max(c) from t1 +where exists ( select * from t2 where t2.c = t1.c ) +group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index +2 DEPENDENT SUBQUERY t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index +explain select a1,a2,b,min(c),max(c) from t1 +where exists ( select * from t2 where t2.c > 'b1' ) +group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range NULL idx_t1_1 147 NULL 10 Using index for group-by +2 SUBQUERY t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index +explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 1 Using where; Using index for group-by +explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 1 Using where; Using index for group-by +explain select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 Using where +explain select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 65 NULL # Using where +select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a b e112 h112 +b a b e212 h212 +c a b e312 h312 +c b b m322 p322 +d a b e412 h412 +d b b m422 p422 +select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a c111 d111 +a a b e112 h112 +b a a b211 d211 +b a b e212 h212 +c a a b311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a b411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b; +a1 a2 b min(c) max(c) +a b a i121 l121 +b b a i221 l221 +c b a i321 l321 +d b a i421 l421 +select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; +a1 a2 b min(c) +b b a k221 +c b a k321 +d b a k421 +select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; +a1 a2 b min(c) +b b a k221 +c b a k321 +d b a k421 +select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +a1 a2 b min(c) +select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b; +a1 a2 b min(c) +select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a b e112 h112 +b a b e212 h212 +c a b e312 h312 +c b b m322 p322 +d a b e412 h412 +d b b m422 p422 +e a b NULL NULL +select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b; +a1 a2 b min(c) max(c) +a a a c111 d111 +a a b e112 h112 +b a a b211 d211 +b a b e212 h212 +c a NULL c777 c999 +c a a b311 d311 +c a b e312 h312 +c b a i321 l321 +c b b m322 p322 +d a a b411 d411 +d a b e412 h412 +d b a i421 l421 +d b b m422 p422 +select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b; +a1 a2 b min(c) max(c) +a b a i121 l121 +b b a i221 l221 +c b a i321 l321 +d b a i421 l421 +select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; +a1 a2 b min(c) +b b a k221 +c b a k321 +d b a k421 +select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; +a1 a2 b min(c) +b b a k221 +c b a k321 +d b a k421 +select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +a1 a2 b min(c) +explain select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 1 Using where +explain select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 146 NULL # Using where; Using index for group-by +explain select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_2 146 NULL # Using where; Using index for group-by +explain select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 146 NULL # Using where +select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +a1 a2 b +a a b +b a b +c a b +c b b +d a b +d b b +select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +a1 a2 b +a b a +b b a +c b a +d b a +select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +a1 a2 b c +a b a i121 +select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +a1 a2 b +select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +a1 a2 b +a a b +b a b +c a b +c b b +d a b +d b b +e a b +select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +a1 a2 b +a b a +b b a +c b a +d b a +select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +a1 a2 b c +a b a i121 +select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +a1 a2 b +explain select distinct a1,a2,b from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using index for group-by +explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain extended select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 100.00 Using where; Using index for group-by +Warnings: +Note 1003 select distinct `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where ((`test`.`t1`.`c` = 'i121') and (`test`.`t1`.`b` = 'a') and (`test`.`t1`.`a2` >= 'b')) +explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 1 Using where +explain select distinct b from t1 where (a2 >= 'b') and (b = 'a'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +explain select distinct a1,a2,b from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_2 146 NULL # Using index for group-by +explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_2 146 NULL # Using where; Using index for group-by +explain extended select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 100.00 Using where; Using index for group-by +Warnings: +Note 1003 select distinct `test`.`t2`.`a1` AS `a1`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`c` = 'i121') and (`test`.`t2`.`b` = 'a') and (`test`.`t2`.`a2` >= 'b')) +explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 146 NULL # Using where +explain select distinct b from t2 where (a2 >= 'b') and (b = 'a'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL idx_t2_2 146 NULL 164 Using where; Using index +select distinct a1,a2,b from t1; +a1 a2 b +a a a +a a b +a b a +a b b +b a a +b a b +b b a +b b b +c a a +c a b +c b a +c b b +d a a +d a b +d b a +d b b +select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a'); +a1 a2 b +a b a +b b a +c b a +d b a +select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +a1 a2 b c +a b a i121 +select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +a1 a2 b +select distinct b from t1 where (a2 >= 'b') and (b = 'a'); +b +a +select distinct a1,a2,b from t2; +a1 a2 b +a a NULL +a a a +a a b +a b a +a b b +b a a +b a b +b b a +b b b +c a NULL +c a a +c a b +c b a +c b b +d a a +d a b +d b a +d b b +e a a +e a b +select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a'); +a1 a2 b +a b a +b b a +c b a +d b a +select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +a1 a2 b c +a b a i121 +select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +a1 a2 b +select distinct b from t2 where (a2 >= 'b') and (b = 'a'); +b +a +select distinct t_00.a1 +from t1 t_00 +where exists ( select * from t2 where a1 = t_00.a1 ); +a1 +a +b +c +d +select distinct a1,a1 from t1; +a1 a1 +a a +b b +c c +d d +select distinct a2,a1,a2,a1 from t1; +a2 a1 a2 a1 +a a a a +b a b a +a b a b +b b b b +a c a c +b c b c +a d a d +b d b d +select distinct t1.a1,t2.a1 from t1,t2; +a1 a1 +a a +b a +c a +d a +a b +b b +c b +d b +a c +b c +c c +d c +a d +b d +c d +d d +a e +b e +c e +d e +explain select distinct a1,a2,b from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using index for group-by +explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by +explain select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 10 Using where; Using index for group-by +explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 1 Using where +explain select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using where; Using index for group-by; Using temporary; Using filesort +explain select distinct a1,a2,b from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_2 146 NULL # Using index for group-by +explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_2 146 NULL # Using where; Using index for group-by +explain select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by +explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_2 146 NULL # Using where +explain select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL idx_t2_2 146 NULL # Using where; Using index for group-by; Using temporary; Using filesort +select distinct a1,a2,b from t1; +a1 a2 b +a a a +a a b +a b a +a b b +b a a +b a b +b b a +b b b +c a a +c a b +c b a +c b b +d a a +d a b +d b a +d b b +select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +a1 a2 b +a b a +b b a +c b a +d b a +select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +a1 a2 b c +a b a i121 +select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +a1 a2 b +select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +b +a +select distinct a1,a2,b from t2; +a1 a2 b +a a NULL +a a a +a a b +a b a +a b b +b a a +b a b +b b a +b b b +c a NULL +c a a +c a b +c b a +c b b +d a a +d a b +d b a +d b b +e a a +e a b +select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +a1 a2 b +a b a +b b a +c b a +d b a +select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +a1 a2 b c +a b a i121 +select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +a1 a2 b +select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +b +a +explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index +explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_0 65 NULL 1 100.00 Using where +Warnings: +Note 1003 select count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`) AS `count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`b` = 'c') and (`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a')) +explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +explain extended select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_0 65 NULL 1 100.00 Using where +Warnings: +Note 1003 select (ord(`test`.`t1`.`a1`) + count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`)) AS `ord(a1) + count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a')) +select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); +count(distinct a1,a2,b) +4 +select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +count(distinct a1,a2,b,c) +1 +select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +count(distinct a1,a2,b) +0 +select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a'); +count(distinct b) +1 +select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); +ord(a1) + count(distinct a1,a2,b) +104 +explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 Using where +explain select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 Using where +explain select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 Using where +explain select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 Using where +explain select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 10 Using index for group-by +select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b; +a1 a2 b concat(min(c), max(c)) +a a a a111d111 +a a b e112h112 +a b a i121l121 +a b b m122p122 +b a a a211d211 +b a b e212h212 +b b a i221l221 +b b b m222p222 +c a a a311d311 +c a b e312h312 +c b a i321l321 +c b b m322p322 +select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b; +concat(a1,min(c)) b +aa111 a +ae112 b +ai121 a +am122 b +ba211 a +be212 b +bi221 a +bm222 b +ca311 a +ce312 b +ci321 a +cm322 b +select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b; +concat(a1,min(c)) b max(c) +aa111 a d111 +ae112 b h112 +ai121 a l121 +am122 b p122 +ba211 a d211 +be212 b h212 +bi221 a l221 +bm222 b p222 +ca311 a d311 +ce312 b h312 +ci321 a l321 +cm322 b p322 +select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; +concat(a1,a2) b min(c) max(c) +aa a a111 d111 +aa b e112 h112 +ab a i121 l121 +ab b m122 p122 +ba a a211 d211 +ba b e212 h212 +bb a i221 l221 +bb b m222 p222 +ca a a311 d311 +ca b e312 h312 +cb a i321 l321 +cb b m322 p322 +select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2; +concat(ord(min(b)),ord(max(b))) min(b) max(b) +9798 a b +9798 a b +9798 a b +9798 a b +9798 a b +9798 a b +9798 a b +9798 a b +explain select a1,a2,b,d,min(c),max(c) from t1 group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 128 Using temporary; Using filesort +explain select a1,a2,b,d from t1 group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 128 Using temporary; Using filesort +explain extended select a1,a2,min(b),max(b) from t1 +where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 130 NULL 4 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,min(`test`.`t1`.`b`) AS `min(b)`,max(`test`.`t1`.`b`) AS `max(b)` from `test`.`t1` where (((`test`.`t1`.`a1` = 'b') or (`test`.`t1`.`a1` = 'd') or (`test`.`t1`.`a1` = 'a') or (`test`.`t1`.`a1` = 'c')) and (`test`.`t1`.`a2` > 'a') and (`test`.`t1`.`c` > 'a111')) group by `test`.`t1`.`a1`,`test`.`t1`.`a2` +explain extended select a1,a2,b,min(c),max(c) from t1 +where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 130 NULL 4 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t1`.`b` AS `b`,min(`test`.`t1`.`c`) AS `min(c)`,max(`test`.`t1`.`c`) AS `max(c)` from `test`.`t1` where (((`test`.`t1`.`a1` = 'b') or (`test`.`t1`.`a1` = 'd') or (`test`.`t1`.`a1` = 'a') or (`test`.`t1`.`a1` = 'c')) and (`test`.`t1`.`a2` > 'a') and (`test`.`t1`.`d` > 'xy2')) group by `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b` +explain extended select a1,a2,b,c from t1 +where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b,c; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 130 NULL 4 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (((`test`.`t1`.`a1` = 'b') or (`test`.`t1`.`a1` = 'd') or (`test`.`t1`.`a1` = 'a') or (`test`.`t1`.`a1` = 'c')) and (`test`.`t1`.`a2` > 'a') and (`test`.`t1`.`d` > 'xy2')) group by `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`,`test`.`t1`.`c` +explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b < 'b') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index +explain extended select a1,a2,b from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 130 NULL 4 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (((`test`.`t1`.`a1` = 'b') or (`test`.`t1`.`a1` = 'd') or (`test`.`t1`.`a1` = 'a') or (`test`.`t1`.`a1` = 'c')) and (`test`.`t1`.`a2` > 'a') and (`test`.`t1`.`c` > 'a111')) group by `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b` +explain select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index +select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1; +a1 a2 min(b) c +a a a a111 +explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b = 'a') group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index +explain select a1,a2,b,min(c),max(c) from t2 +where (c > 'a000') and (c <= 'd999') and (c like '_8__') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index +explain select a1, a2, b, c, min(d), max(d) from t1 group by a1,a2,b,c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 128 Using temporary; Using filesort +explain select a1,a2,count(a2) from t1 group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using index +explain extended select a1,a2,count(a2) from t1 where (a1 > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,count(`test`.`t1`.`a2`) AS `count(a2)` from `test`.`t1` where (`test`.`t1`.`a1` > 'a') group by `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b` +explain extended select sum(ord(a1)) from t1 where (a1 > 'a') group by a1,a2,b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 65 NULL 1 100.00 Using where +Warnings: +Note 1003 select sum(ord(`test`.`t1`.`a1`)) AS `sum(ord(a1))` from `test`.`t1` where (`test`.`t1`.`a1` > 'a') group by `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b` +explain select distinct(a1) from t1 where ord(a2) = 98; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +select distinct(a1) from t1 where ord(a2) = 98; +a1 +a +b +c +d +explain select a1 from t1 where a2 = 'b' group by a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 130 NULL 10 Using where; Using index for group-by +select a1 from t1 where a2 = 'b' group by a1; +a1 +a +b +c +d +explain select distinct a1 from t1 where a2 = 'b'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx_t1_1 130 NULL 10 Using where; Using index for group-by +select distinct a1 from t1 where a2 = 'b'; +a1 +a +b +c +d +drop table t1,t2,t3; +create table t1 (c1 int not null,c2 int not null, primary key(c1,c2)); +insert into t1 (c1,c2) values +(10,1),(10,2),(10,3),(20,4),(20,5),(20,6),(30,7),(30,8),(30,9); +select distinct c1, c2 from t1 order by c2; +c1 c2 +10 1 +10 2 +10 3 +20 4 +20 5 +20 6 +30 7 +30 8 +30 9 +select c1,min(c2) as c2 from t1 group by c1 order by c2; +c1 c2 +10 1 +20 4 +30 7 +select c1,c2 from t1 group by c1,c2 order by c2; +c1 c2 +10 1 +10 2 +10 3 +20 4 +20 5 +20 6 +30 7 +30 8 +30 9 +drop table t1; +CREATE TABLE t1 (a varchar(5), b int(11), PRIMARY KEY (a,b)); +INSERT INTO t1 VALUES ('AA',1), ('AA',2), ('AA',3), ('BB',1), ('AA',4); +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +SELECT a FROM t1 WHERE a='AA' GROUP BY a; +a +AA +SELECT a FROM t1 WHERE a='BB' GROUP BY a; +a +BB +EXPLAIN SELECT a FROM t1 WHERE a='AA' GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref PRIMARY PRIMARY 7 const 1 Using where; Using index +EXPLAIN SELECT a FROM t1 WHERE a='BB' GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref PRIMARY PRIMARY 7 const 1 Using where; Using index +SELECT DISTINCT a FROM t1 WHERE a='BB'; +a +BB +SELECT DISTINCT a FROM t1 WHERE a LIKE 'B%'; +a +BB +SELECT a FROM t1 WHERE a LIKE 'B%' GROUP BY a; +a +BB +DROP TABLE t1; +CREATE TABLE t1 ( +a int(11) NOT NULL DEFAULT '0', +b varchar(16) COLLATE latin1_general_ci NOT NULL DEFAULT '', +PRIMARY KEY (a,b) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +CREATE PROCEDURE a(x INT) +BEGIN +DECLARE rnd INT; +DECLARE cnt INT; +WHILE x > 0 DO +SET rnd= x % 100; +SET cnt = (SELECT COUNT(*) FROM t1 WHERE a = rnd); +INSERT INTO t1(a,b) VALUES (rnd, CAST(cnt AS CHAR)); +SET x= x - 1; +END WHILE; +END| +CALL a(1000); +SELECT a FROM t1 WHERE a=0; +a +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +SELECT DISTINCT a FROM t1 WHERE a=0; +a +0 +SELECT COUNT(DISTINCT a) FROM t1 WHERE a=0; +COUNT(DISTINCT a) +1 +DROP TABLE t1; +DROP PROCEDURE a; +CREATE TABLE t1 (a varchar(64) NOT NULL default '', PRIMARY KEY(a)); +INSERT INTO t1 (a) VALUES +(''), ('CENTRAL'), ('EASTERN'), ('GREATER LONDON'), +('NORTH CENTRAL'), ('NORTH EAST'), ('NORTH WEST'), ('SCOTLAND'), +('SOUTH EAST'), ('SOUTH WEST'), ('WESTERN'); +EXPLAIN SELECT DISTINCT a,a FROM t1 ORDER BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 66 NULL 11 Using index +SELECT DISTINCT a,a FROM t1 ORDER BY a; +a a + +CENTRAL CENTRAL +EASTERN EASTERN +GREATER LONDON GREATER LONDON +NORTH CENTRAL NORTH CENTRAL +NORTH EAST NORTH EAST +NORTH WEST NORTH WEST +SCOTLAND SCOTLAND +SOUTH EAST SOUTH EAST +SOUTH WEST SOUTH WEST +WESTERN WESTERN +DROP TABLE t1; +CREATE TABLE t1 (id1 INT, id2 INT); +CREATE TABLE t2 (id2 INT, id3 INT, id5 INT); +CREATE TABLE t3 (id3 INT, id4 INT); +CREATE TABLE t4 (id4 INT); +CREATE TABLE t5 (id5 INT, id6 INT); +CREATE TABLE t6 (id6 INT); +INSERT INTO t1 VALUES(1,1); +INSERT INTO t2 VALUES(1,1,1); +INSERT INTO t3 VALUES(1,1); +INSERT INTO t4 VALUES(1); +INSERT INTO t5 VALUES(1,1); +INSERT INTO t6 VALUES(1); +SELECT * FROM +t1 +NATURAL JOIN +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); +id2 id1 id3 id5 id4 id3 id6 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM +t1 +NATURAL JOIN +(((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6) on t3.id4 = t5.id5) JOIN t2 +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); +id2 id1 id4 id3 id6 id5 id3 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM t1 NATURAL JOIN ((t3 join (t5 NATURAL JOIN t6)) JOIN t2); +id2 id1 id3 id4 id6 id5 id3 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)) +NATURAL JOIN +t1; +id2 id3 id5 id4 id3 id6 id5 id1 +1 1 1 1 1 1 1 1 +SELECT * FROM +(t2 JOIN ((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6))) +NATURAL JOIN +t1; +id2 id3 id5 id4 id3 id6 id5 id1 +1 1 1 1 1 1 1 1 +DROP TABLE t1,t2,t3,t4,t5,t6; +CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b), KEY b (b)); +INSERT INTO t1 VALUES (1,1),(1,2),(1,0),(1,3); +explain SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY,b PRIMARY 8 NULL 1 Using where; Using index for group-by +SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a; +MAX(b) a +1 1 +SELECT MIN(b), a FROM t1 WHERE b > 1 AND a = 1 GROUP BY a; +MIN(b) a +2 1 +CREATE TABLE t2 (a int, b int, c int, PRIMARY KEY (a,b,c)); +INSERT INTO t2 SELECT a,b,b FROM t1; +explain SELECT MIN(c) FROM t2 WHERE b = 2 and a = 1 and c > 1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range PRIMARY PRIMARY 12 NULL 1 Using where; Using index for group-by +SELECT MIN(c) FROM t2 WHERE b = 2 and a = 1 and c > 1 GROUP BY a; +MIN(c) +2 +DROP TABLE t1,t2; +CREATE TABLE t1 (a INT, b INT, INDEX (a,b)); +INSERT INTO t1 (a, b) VALUES (1,1), (1,2), (1,3), (1,4), (1,5), +(2,2), (2,3), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4), (4,5), (4,6); +EXPLAIN SELECT max(b), a FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 5 NULL 8 Using index for group-by +FLUSH STATUS; +SELECT max(b), a FROM t1 GROUP BY a; +max(b) a +5 1 +3 2 +1 3 +6 4 +SHOW STATUS LIKE 'handler_read__e%'; +Variable_name Value +Handler_read_key 0 +Handler_read_next 0 +EXPLAIN SELECT max(b), a FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 5 NULL 8 Using index for group-by +FLUSH STATUS; +CREATE TABLE t2 SELECT max(b), a FROM t1 GROUP BY a; +SHOW STATUS LIKE 'handler_read__e%'; +Variable_name Value +Handler_read_key 0 +Handler_read_next 0 +FLUSH STATUS; +SELECT * FROM (SELECT max(b), a FROM t1 GROUP BY a) b; +max(b) a +5 1 +3 2 +1 3 +6 4 +SHOW STATUS LIKE 'handler_read__e%'; +Variable_name Value +Handler_read_key 0 +Handler_read_next 0 +FLUSH STATUS; +(SELECT max(b), a FROM t1 GROUP BY a) UNION +(SELECT max(b), a FROM t1 GROUP BY a); +max(b) a +5 1 +3 2 +1 3 +6 4 +SHOW STATUS LIKE 'handler_read__e%'; +Variable_name Value +Handler_read_key 0 +Handler_read_next 0 +EXPLAIN (SELECT max(b), a FROM t1 GROUP BY a) UNION +(SELECT max(b), a FROM t1 GROUP BY a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range NULL a 5 NULL 8 Using index for group-by +2 UNION t1 range NULL a 5 NULL 8 Using index for group-by +NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL +EXPLAIN SELECT (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) x +FROM t1 AS t1_outer; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1_outer index NULL a 10 NULL 15 Using index +2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by +EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE EXISTS +(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1_outer index NULL a 10 NULL 15 Using index +2 SUBQUERY t1 index NULL a 10 NULL 15 Using index +EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE +(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by +EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE +a IN (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1_outer index NULL a 10 NULL 15 Using where; Using index +2 DEPENDENT SUBQUERY t1 index NULL a 10 NULL 1 Using index +EXPLAIN SELECT 1 FROM t1 AS t1_outer GROUP BY a HAVING +a > (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1_outer range NULL a 5 NULL 8 Using index for group-by +2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by +EXPLAIN SELECT 1 FROM t1 AS t1_outer1 JOIN t1 AS t1_outer2 +ON t1_outer1.a = (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) +AND t1_outer1.b = t1_outer2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1_outer1 ref a a 5 const 1 Using where; Using index +1 PRIMARY t1_outer2 index NULL a 10 NULL 15 Using where; Using index; Using join buffer +2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by +EXPLAIN SELECT (SELECT (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) x +FROM t1 AS t1_outer) x2 FROM t1 AS t1_outer2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1_outer2 index NULL a 10 NULL 15 Using index +2 SUBQUERY t1_outer index NULL a 10 NULL 15 Using index +3 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by +CREATE TABLE t3 LIKE t1; +FLUSH STATUS; +INSERT INTO t3 SELECT a,MAX(b) FROM t1 GROUP BY a; +SHOW STATUS LIKE 'handler_read__e%'; +Variable_name Value +Handler_read_key 0 +Handler_read_next 0 +DELETE FROM t3; +FLUSH STATUS; +INSERT INTO t3 SELECT 1, (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) +FROM t1 LIMIT 1; +SHOW STATUS LIKE 'handler_read__e%'; +Variable_name Value +Handler_read_key 0 +Handler_read_next 0 +FLUSH STATUS; +DELETE FROM t3 WHERE (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) > 10000; +SHOW STATUS LIKE 'handler_read__e%'; +Variable_name Value +Handler_read_key 0 +Handler_read_next 0 +FLUSH STATUS; +DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x +FROM t1) > 10000; +ERROR 21000: Subquery returns more than 1 row +SHOW STATUS LIKE 'handler_read__e%'; +Variable_name Value +Handler_read_key 0 +Handler_read_next 0 +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (a int, INDEX idx(a)); +INSERT INTO t1 VALUES +(4), (2), (1), (2), (4), (2), (1), (4), +(4), (2), (1), (2), (2), (4), (1), (4); +EXPLAIN SELECT DISTINCT(a) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx 5 NULL 9 Using index for group-by +SELECT DISTINCT(a) FROM t1; +a +1 +2 +4 +EXPLAIN SELECT SQL_BIG_RESULT DISTINCT(a) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL idx 5 NULL 9 Using index for group-by +SELECT SQL_BIG_RESULT DISTINCT(a) FROM t1; +a +1 +2 +4 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 (a, b) VALUES (1,1), (1,2), (1,3); +INSERT INTO t1 SELECT a + 1, b FROM t1; +INSERT INTO t1 SELECT a + 2, b FROM t1; +EXPLAIN +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a DESC; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using temporary; Using filesort +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a DESC; +a MIN(b) MAX(b) +4 1 3 +3 1 3 +2 1 3 +1 1 3 +CREATE INDEX break_it ON t1 (a, b); +EXPLAIN +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL break_it 10 NULL 7 Using index for group-by +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a; +a MIN(b) MAX(b) +1 1 3 +2 1 3 +3 1 3 +4 1 3 +EXPLAIN +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a DESC; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL break_it 10 NULL 7 Using index for group-by; Using temporary; Using filesort +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a DESC; +a MIN(b) MAX(b) +4 1 3 +3 1 3 +2 1 3 +1 1 3 +EXPLAIN +SELECT a, MIN(b), MAX(b), AVG(b) FROM t1 GROUP BY a ORDER BY a DESC; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL break_it 10 NULL 12 Using index +SELECT a, MIN(b), MAX(b), AVG(b) FROM t1 GROUP BY a ORDER BY a DESC; +a MIN(b) MAX(b) AVG(b) +4 1 3 2.0000 +3 1 3 2.0000 +2 1 3 2.0000 +1 1 3 2.0000 +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/having.result b/mysql-test/suite/pbxt/r/having.result new file mode 100644 index 00000000000..d76cd81022b --- /dev/null +++ b/mysql-test/suite/pbxt/r/having.result @@ -0,0 +1,407 @@ +drop table if exists t1,t2,t3; +create table t1 (a int); +select count(a) as b from t1 where a=0 having b > 0; +b +insert into t1 values (null); +select count(a) as b from t1 where a=0 having b > 0; +b +select count(a) as b from t1 where a=0 having b >=0; +b +0 +explain extended select count(a) as b from t1 where a=0 having b >=0; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 Using where +Warnings: +Note 1003 select count(`test`.`t1`.`a`) AS `b` from `test`.`t1` where (`test`.`t1`.`a` = 0) having (`b` >= 0) +drop table t1; +CREATE TABLE t1 ( +raw_id int(10) NOT NULL default '0', +chr_start int(10) NOT NULL default '0', +chr_end int(10) NOT NULL default '0', +raw_start int(10) NOT NULL default '0', +raw_end int(10) NOT NULL default '0', +raw_ori int(2) NOT NULL default '0' +); +INSERT INTO t1 VALUES (469713,1,164123,1,164123,1),(317330,164124,317193,101,153170,1),(469434,317194,375620,101,58527,1),(591816,375621,484273,1,108653,1),(591807,484274,534671,91,50488,1),(318885,534672,649362,101,114791,1),(318728,649363,775520,102,126259,1),(336829,775521,813997,101,38577,1),(317740,813998,953227,101,139330,1),(1,813998,953227,101,139330,1); +CREATE TABLE t2 ( +id int(10) unsigned NOT NULL default '0', +contig_id int(10) unsigned NOT NULL default '0', +seq_start int(10) NOT NULL default '0', +seq_end int(10) NOT NULL default '0', +strand tinyint(2) NOT NULL default '0', +KEY id (id) +); +INSERT INTO t2 VALUES (133195,469713,61327,61384,1),(133196,469713,64113,64387,1),(133197,1,1,1,0),(133197,1,1,1,-2); +SELECT e.id, +MIN( IF(sgp.raw_ori=1, +(e.seq_start+sgp.chr_start-sgp.raw_start), +(sgp.chr_start+sgp.raw_end-e.seq_end))) as start, +MAX( IF(sgp.raw_ori=1, +(e.seq_end+sgp.chr_start-sgp.raw_start), +(sgp.chr_start+sgp.raw_end-e.seq_start))) as end, +AVG(IF (sgp.raw_ori=1,e.strand,(-e.strand))) as chr_strand +FROM t1 sgp, +t2 e +WHERE sgp.raw_id=e.contig_id +GROUP BY e.id +HAVING chr_strand= -1 and end >= 0 +AND start <= 999660; +id start end chr_strand +133197 813898 813898 -1.0000 +drop table t1,t2; +CREATE TABLE t1 (Fld1 int(11) default NULL,Fld2 int(11) default NULL); +INSERT INTO t1 VALUES (1,10),(1,20),(2,NULL),(2,NULL),(3,50); +select Fld1, max(Fld2) as q from t1 group by Fld1 having q is not null; +Fld1 q +1 20 +3 50 +select Fld1, max(Fld2) from t1 group by Fld1 having max(Fld2) is not null; +Fld1 max(Fld2) +1 20 +3 50 +select Fld1, max(Fld2) from t1 group by Fld1 having avg(Fld2) is not null; +Fld1 max(Fld2) +1 20 +3 50 +select Fld1, max(Fld2) from t1 group by Fld1 having std(Fld2) is not null; +Fld1 max(Fld2) +1 20 +3 50 +select Fld1, max(Fld2) from t1 group by Fld1 having variance(Fld2) is not null; +Fld1 max(Fld2) +1 20 +3 50 +drop table t1; +create table t1 (id int not null, qty int not null); +insert into t1 values (1,2),(1,3),(2,4),(2,5); +select id, sum(qty) as sqty from t1 group by id having sqty>2; +id sqty +1 5 +2 9 +select sum(qty) as sqty from t1 group by id having count(id) > 0; +sqty +5 +9 +select sum(qty) as sqty from t1 group by id having count(distinct id) > 0; +sqty +5 +9 +drop table t1; +CREATE TABLE t1 ( +`id` bigint(20) NOT NULL default '0', +`description` text +) ENGINE=MyISAM; +CREATE TABLE t2 ( +`id` bigint(20) NOT NULL default '0', +`description` varchar(20) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 'test'); +INSERT INTO t2 VALUES (1, 'test'); +CREATE TABLE t3 ( +`id` bigint(20) NOT NULL default '0', +`order_id` bigint(20) NOT NULL default '0' +) ENGINE=MyISAM; +select +a.id, a.description, +count(b.id) as c +from t1 a left join t3 b on a.id=b.order_id +group by a.id, a.description +having (a.description is not null) and (c=0); +id description c +1 test 0 +select +a.*, +count(b.id) as c +from t2 a left join t3 b on a.id=b.order_id +group by a.id, a.description +having (a.description is not null) and (c=0); +id description c +1 test 0 +INSERT INTO t1 VALUES (2, 'test2'); +select +a.id, a.description, +count(b.id) as c +from t1 a left join t3 b on a.id=b.order_id +group by a.id, a.description +having (a.description is not null) and (c=0); +id description c +1 test 0 +2 test2 0 +drop table t1,t2,t3; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3), (4), (1), (3), (1); +SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a)>0; +SUM(a) +2 +6 +4 +SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a); +SUM(a) +2 +6 +4 +DROP TABLE t1; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2), (1), (3), (2), (1); +SELECT a FROM t1 GROUP BY a HAVING a > 1; +a +2 +3 +SELECT a FROM t1 GROUP BY a HAVING 1 != 1 AND a > 1; +a +SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1; +x a +EXPLAIN SELECT a FROM t1 GROUP BY a HAVING 1 != 1 AND a > 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +EXPLAIN SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible HAVING +DROP table t1; +create table t1 (col1 int, col2 varchar(5), col_t1 int); +create table t2 (col1 int, col2 varchar(5), col_t2 int); +create table t3 (col1 int, col2 varchar(5), col_t3 int); +insert into t1 values(10,'hello',10); +insert into t1 values(20,'hello',20); +insert into t1 values(30,'hello',30); +insert into t1 values(10,'bye',10); +insert into t1 values(10,'sam',10); +insert into t1 values(10,'bob',10); +insert into t2 select * from t1; +insert into t3 select * from t1; +select count(*) from t1 group by col1 having col1 = 10; +count(*) +4 +select count(*) as count_col1 from t1 group by col1 having col1 = 10; +count_col1 +4 +select count(*) as count_col1 from t1 as tmp1 group by col1 having col1 = 10; +count_col1 +4 +select count(*) from t1 group by col2 having col2 = 'hello'; +count(*) +3 +select count(*) from t1 group by col2 having col1 = 10; +ERROR 42S22: Unknown column 'col1' in 'having clause' +select col1 as count_col1 from t1 as tmp1 group by col1 having col1 = 10; +count_col1 +10 +select col1 as count_col1 from t1 as tmp1 group by col1 having count_col1 = 10; +count_col1 +10 +select col1 as count_col1 from t1 as tmp1 group by count_col1 having col1 = 10; +count_col1 +10 +select col1 as count_col1 from t1 as tmp1 group by count_col1 having count_col1 = 10; +count_col1 +10 +select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having col1 = 10; +count_col1 col2 +10 bob +10 bye +10 hello +10 sam +select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having count_col1 = 10; +count_col1 col2 +10 bob +10 bye +10 hello +10 sam +select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having col2 = 'hello'; +count_col1 col2 +10 hello +20 hello +30 hello +select col1 as count_col1,col2 as group_col2 from t1 as tmp1 group by col1,col2 having group_col2 = 'hello'; +count_col1 group_col2 +10 hello +20 hello +30 hello +select sum(col1) as co12 from t1 group by col2 having col2 10; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '10' at line 1 +select sum(col1) as co2, count(col2) as cc from t1 group by col1 having col1 =10; +co2 cc +40 4 +select t2.col2 from t2 group by t2.col1, t2.col2 having t1.col1 <= 10; +ERROR 42S22: Unknown column 't1.col1' in 'having clause' +select t1.col1 from t1 +where t1.col2 in +(select t2.col2 from t2 +group by t2.col1, t2.col2 having t2.col1 <= 10); +col1 +10 +20 +30 +10 +10 +10 +select t1.col1 from t1 +where t1.col2 in +(select t2.col2 from t2 +group by t2.col1, t2.col2 +having t2.col1 <= +(select min(t3.col1) from t3)); +col1 +10 +20 +30 +10 +10 +10 +select t1.col1 from t1 +where t1.col2 in +(select t2.col2 from t2 +group by t2.col1, t2.col2 having t1.col1 <= 10); +col1 +10 +10 +10 +10 +select t1.col1 as tmp_col from t1 +where t1.col2 in +(select t2.col2 from t2 +group by t2.col1, t2.col2 having tmp_col <= 10); +tmp_col +10 +10 +10 +10 +select t1.col1 from t1 +where t1.col2 in +(select t2.col2 from t2 +group by t2.col1, t2.col2 having col_t1 <= 10); +col1 +10 +10 +10 +10 +select sum(col1) from t1 +group by col_t1 +having (select col_t1 from t2 where col_t1 = col_t2 order by col_t2 limit 1); +sum(col1) +40 +20 +30 +select t1.col1 from t1 +where t1.col2 in +(select t2.col2 from t2 +group by t2.col1, t2.col2 having col_t1 <= 10) +having col_t1 <= 20; +ERROR 42S22: Unknown column 'col_t1' in 'having clause' +select t1.col1 from t1 +where t1.col2 in +(select t2.col2 from t2 +group by t2.col1, t2.col2 having col_t1 <= 10) +group by col_t1 +having col_t1 <= 20; +col1 +10 +select col_t1, sum(col1) from t1 +group by col_t1 +having col_t1 > 10 and +exists (select sum(t2.col1) from t2 +group by t2.col2 having t2.col2 > 'b'); +col_t1 sum(col1) +20 20 +30 30 +select sum(col1) from t1 +group by col_t1 +having col_t1 in (select sum(t2.col1) from t2 +group by t2.col2, t2.col1 having t2.col1 = t1.col1); +ERROR 42S22: Unknown column 't1.col1' in 'having clause' +select sum(col1) from t1 +group by col_t1 +having col_t1 in (select sum(t2.col1) from t2 +group by t2.col2, t2.col1 having t2.col1 = col_t1); +sum(col1) +40 +20 +30 +select t1.col1, t2.col1 from t1, t2 where t1.col1 = t2.col1 +group by t1.col1, t2.col1 having col1 = 2; +ERROR 23000: Column 'col1' in having clause is ambiguous +select t1.col1*10+t2.col1 from t1,t2 where t1.col1=t2.col1 +group by t1.col1, t2.col1 having col1 = 2; +ERROR 23000: Column 'col1' in having clause is ambiguous +drop table t1, t2, t3; +create table t1 (s1 int); +insert into t1 values (1),(2),(3); +select count(*) from t1 group by s1 having s1 is null; +count(*) +select s1*0 as s1 from t1 group by s1 having s1 <> 0; +s1 +0 +0 +0 +Warnings: +Warning 1052 Column 's1' in group statement is ambiguous +Warning 1052 Column 's1' in having clause is ambiguous +select s1*0 from t1 group by s1 having s1 = 0; +s1*0 +select s1 from t1 group by 1 having 1 = 0; +s1 +select count(s1) from t1 group by s1 having count(1+1)=2; +count(s1) +select count(s1) from t1 group by s1 having s1*0=0; +count(s1) +1 +1 +1 +select * from t1 a, t1 b group by a.s1 having s1 is null; +ERROR 23000: Column 's1' in having clause is ambiguous +drop table t1; +create table t1 (s1 char character set latin1 collate latin1_german1_ci); +insert into t1 values ('ü'),('y'); +Warnings: +Warning 1265 Data truncated for column 's1' at row 1 +select s1,count(s1) from t1 +group by s1 collate latin1_swedish_ci having s1 = 'y'; +s1 count(s1) +y 1 +drop table t1; +DROP SCHEMA IF EXISTS HU; +CREATE SCHEMA HU ; +USE HU ; +CREATE TABLE STAFF +(EMPNUM CHAR(3) NOT NULL UNIQUE, +EMPNAME CHAR(20), +GRADE DECIMAL(4), +CITY CHAR(15)); +CREATE TABLE PROJ +(PNUM CHAR(3) NOT NULL UNIQUE, +PNAME CHAR(20), +PTYPE CHAR(6), +BUDGET DECIMAL(9), +CITY CHAR(15)); +INSERT INTO STAFF VALUES ('E1','Alice',12,'Deale'); +INSERT INTO STAFF VALUES ('E2','Betty',10,'Vienna'); +INSERT INTO STAFF VALUES ('E3','Carmen',13,'Vienna'); +INSERT INTO STAFF VALUES ('E4','Don',12,'Deale'); +INSERT INTO STAFF VALUES ('E5','Ed',13,'Akron'); +INSERT INTO PROJ VALUES ('P1','MXSS','Design',10000,'Deale'); +INSERT INTO PROJ VALUES ('P2','CALM','Code',30000,'Vienna'); +INSERT INTO PROJ VALUES ('P3','SDP','Test',30000,'Tampa'); +INSERT INTO PROJ VALUES ('P4','SDP','Design',20000,'Deale'); +INSERT INTO PROJ VALUES ('P5','IRM','Test',10000,'Vienna'); +INSERT INTO PROJ VALUES ('P6','PAYR','Design',50000,'Deale'); +SELECT EMPNUM, GRADE*1000 +FROM HU.STAFF WHERE GRADE * 1000 > +ANY (SELECT SUM(BUDGET) FROM HU.PROJ +GROUP BY CITY, PTYPE +HAVING HU.PROJ.CITY = HU.STAFF.CITY); +EMPNUM GRADE*1000 +E3 13000 +DROP SCHEMA HU; +USE test; +create table t1(f1 int); +select f1 from t1 having max(f1)=f1; +f1 +select f1 from t1 group by f1 having max(f1)=f1; +f1 +set session sql_mode='ONLY_FULL_GROUP_BY'; +select f1 from t1 having max(f1)=f1; +ERROR 42000: non-grouping field 'f1' is used in HAVING clause +select f1 from t1 group by f1 having max(f1)=f1; +f1 +set session sql_mode=''; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/heap.result b/mysql-test/suite/pbxt/r/heap.result new file mode 100644 index 00000000000..57109f0d4c8 --- /dev/null +++ b/mysql-test/suite/pbxt/r/heap.result @@ -0,0 +1,733 @@ +drop table if exists t1,t2,t3; +create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a=1 or a=0; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 a NULL 3 NULL NULL HASH +select * from t1; +a b +2 2 +3 3 +4 4 +select * from t1 where a=4; +a b +4 4 +update t1 set b=5 where a=4; +update t1 set b=b+1 where a>=3; +replace t1 values (3,3); +select * from t1; +a b +2 2 +3 3 +4 6 +alter table t1 add c int not null, add key (c,a); +drop table t1; +create table t1 (a int not null,b int not null, primary key (a)) engine=memory comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a > 0; +select * from t1; +a b +drop table t1; +create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +alter table t1 modify a int not null auto_increment, engine=myisam, comment="new myisam table"; +select * from t1; +a b +1 1 +2 2 +3 3 +4 4 +drop table t1; +create table t1 (a int not null) engine=heap; +insert into t1 values (869751),(736494),(226312),(802616),(728912); +select * from t1 where a > 736494; +a +869751 +802616 +alter table t1 add unique uniq_id(a); +select * from t1 where a > 736494; +a +869751 +802616 +select * from t1 where a = 736494; +a +736494 +select * from t1 where a=869751 or a=736494; +a +736494 +869751 +select * from t1 where a in (869751,736494,226312,802616); +a +226312 +736494 +802616 +869751 +alter table t1 engine=myisam; +explain select * from t1 where a in (869751,736494,226312,802616); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range uniq_id uniq_id 4 NULL 4 Using where; Using index +drop table t1; +create table t1 (x int not null, y int not null, key x (x), unique y (y)) +engine=heap; +insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6); +select * from t1 where x=1; +x y +1 3 +1 1 +select * from t1,t1 as t2 where t1.x=t2.y; +x y x y +1 1 1 1 +2 2 2 2 +1 3 1 1 +2 4 2 2 +2 5 2 2 +2 6 2 2 +explain select * from t1,t1 as t2 where t1.x=t2.y; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL x NULL NULL NULL 6 +1 SIMPLE t2 eq_ref y y 4 test.t1.x 1 +drop table t1; +create table t1 (a int) engine=heap; +insert into t1 values(1); +select max(a) from t1; +max(a) +1 +drop table t1; +CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key(a), key(b) ) ENGINE=HEAP; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +a b +1 6 +1 5 +1 4 +1 3 +1 2 +1 1 +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +a b +1 6 +1 5 +1 4 +1 3 +1 2 +1 1 +1 6 +1 5 +1 4 +1 3 +1 2 +1 1 +drop table t1; +create table t1 (id int unsigned not null, primary key (id)) engine=HEAP; +insert into t1 values(1); +select max(id) from t1; +max(id) +1 +insert into t1 values(2); +select max(id) from t1; +max(id) +2 +replace into t1 values(1); +drop table t1; +create table t1 (n int) engine=heap; +drop table t1; +create table t1 (n int) engine=heap; +drop table if exists t1; +CREATE table t1(f1 int not null,f2 char(20) not +null,index(f2)) engine=heap; +INSERT into t1 set f1=12,f2="bill"; +INSERT into t1 set f1=13,f2="bill"; +INSERT into t1 set f1=14,f2="bill"; +INSERT into t1 set f1=15,f2="bill"; +INSERT into t1 set f1=16,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +delete from t1 where f2="bill"; +select * from t1; +f1 f2 +16 ted +12 ted +12 ted +12 ted +12 ted +drop table t1; +create table t1 (btn char(10) not null, key(btn)) engine=heap; +insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i"); +explain select * from t1 where btn like "q%"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL btn NULL NULL NULL 14 Using where +select * from t1 where btn like "q%"; +btn +alter table t1 add column new_col char(1) not null, add key (btn,new_col), drop key btn; +update t1 set new_col=left(btn,1); +explain select * from t1 where btn="a"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL btn NULL NULL NULL 14 Using where +explain select * from t1 where btn="a" and new_col="a"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref btn btn 11 const,const 2 Using where +drop table t1; +CREATE TABLE t1 ( +a int default NULL, +b int default NULL, +KEY a (a), +UNIQUE b (b) +) engine=heap; +INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3); +SELECT * FROM t1 WHERE a=NULL; +a b +explain SELECT * FROM t1 WHERE a IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 2 Using where +SELECT * FROM t1 WHERE a<=>NULL; +a b +NULL 99 +SELECT * FROM t1 WHERE b=NULL; +a b +explain SELECT * FROM t1 WHERE b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref b b 5 const 1 Using where +SELECT * FROM t1 WHERE b<=>NULL; +a b +99 NULL +INSERT INTO t1 VALUES (1,3); +ERROR 23000: Duplicate entry '3' for key 'b' +DROP TABLE t1; +CREATE TABLE t1 ( +a int default NULL, +key a (a) +) ENGINE=HEAP; +INSERT INTO t1 VALUES (10), (10), (10); +EXPLAIN SELECT * FROM t1 WHERE a=10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 3 Using where +SELECT * FROM t1 WHERE a=10; +a +10 +10 +10 +DROP TABLE t1; +CREATE TABLE t1 (a int not null, primary key(a)) engine=heap; +INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); +DELETE from t1 where a < 100; +SELECT * from t1; +a +DROP TABLE t1; +CREATE TABLE `job_titles` ( +`job_title_id` int(6) unsigned NOT NULL default '0', +`job_title` char(18) NOT NULL default '', +PRIMARY KEY (`job_title_id`), +UNIQUE KEY `job_title_id` (`job_title_id`,`job_title`) +) ENGINE=HEAP; +SELECT MAX(job_title_id) FROM job_titles; +MAX(job_title_id) +NULL +DROP TABLE job_titles; +CREATE TABLE t1 (a INT NOT NULL, B INT, KEY(B)) ENGINE=HEAP; +INSERT INTO t1 VALUES(1,1), (1,NULL); +SELECT * FROM t1 WHERE B is not null; +a B +1 1 +DROP TABLE t1; +CREATE TABLE t1 (pseudo char(35) PRIMARY KEY, date int(10) unsigned NOT NULL) ENGINE=HEAP; +INSERT INTO t1 VALUES ('massecot',1101106491),('altec',1101106492),('stitch+',1101106304),('Seb Corgan',1101106305),('beerfilou',1101106263),('flaker',1101106529),('joce8',5),('M4vrick',1101106418),('gabay008',1101106525),('Vamp irX',1101106291),('ZoomZip',1101106546),('rip666',1101106502),('CBP ',1101106397),('guezpard',1101106496); +DELETE FROM t1 WHERE date<1101106546; +SELECT * FROM t1; +pseudo date +ZoomZip 1101106546 +DROP TABLE t1; +create table t1(a char(2)) engine=memory; +insert into t1 values (NULL), (NULL); +delete from t1 where a is null; +insert into t1 values ('2'), ('3'); +select * from t1; +a +3 +2 +drop table t1; +set storage_engine=HEAP; +create table t1 (v varchar(10), c char(10), t varchar(50)); +insert into t1 values('+ ', '+ ', '+ '); +set @a=repeat(' ',20); +insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a)); +Warnings: +Note 1265 Data truncated for column 'v' at row 1 +select concat('*',v,'*',c,'*',t,'*') from t1; +concat('*',v,'*',c,'*',t,'*') +*+ *+*+ * +*+ *+*+ * +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` varchar(10) DEFAULT NULL, + `c` char(10) DEFAULT NULL, + `t` varchar(50) DEFAULT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +create table t2 like t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `v` varchar(10) DEFAULT NULL, + `c` char(10) DEFAULT NULL, + `t` varchar(50) DEFAULT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +create table t3 select * from t1; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `v` varchar(10) DEFAULT NULL, + `c` char(10) DEFAULT NULL, + `t` varchar(50) DEFAULT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +alter table t1 modify c varchar(10); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` varchar(10) DEFAULT NULL, + `c` varchar(10) DEFAULT NULL, + `t` varchar(50) DEFAULT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +alter table t1 modify v char(10); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` char(10) DEFAULT NULL, + `c` varchar(10) DEFAULT NULL, + `t` varchar(50) DEFAULT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +alter table t1 modify t varchar(10); +Warnings: +Warning 1265 Data truncated for column 't' at row 2 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` char(10) DEFAULT NULL, + `c` varchar(10) DEFAULT NULL, + `t` varchar(10) DEFAULT NULL +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +select concat('*',v,'*',c,'*',t,'*') from t1; +concat('*',v,'*',c,'*',t,'*') +*+*+*+ * +*+*+*+ * +drop table t1,t2,t3; +create table t1 (v varchar(10), c char(10), t varchar(50), key(v), key(c), key(t(10))); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` varchar(10) DEFAULT NULL, + `c` char(10) DEFAULT NULL, + `t` varchar(50) DEFAULT NULL, + KEY `v` (`v`), + KEY `c` (`c`), + KEY `t` (`t`(10)) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +270 +insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); +select count(*) from t1 where v='a'; +count(*) +10 +select count(*) from t1 where c='a'; +count(*) +10 +select count(*) from t1 where t='a'; +count(*) +10 +select count(*) from t1 where v='a '; +count(*) +10 +select count(*) from t1 where c='a '; +count(*) +10 +select count(*) from t1 where t='a '; +count(*) +10 +select count(*) from t1 where v between 'a' and 'a '; +count(*) +10 +select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; +count(*) +10 +select count(*) from t1 where v like 'a%'; +count(*) +11 +select count(*) from t1 where c like 'a%'; +count(*) +11 +select count(*) from t1 where t like 'a%'; +count(*) +11 +select count(*) from t1 where v like 'a %'; +count(*) +9 +explain select count(*) from t1 where v='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref v v 13 const 10 Using where +explain select count(*) from t1 where c='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c c 11 const 10 Using where +explain select count(*) from t1 where t='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref t t 13 const 10 Using where +explain select count(*) from t1 where v like 'a%'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where +explain select count(*) from t1 where v between 'a' and 'a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref v v 13 const 10 Using where +explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref v v 13 const 10 Using where +alter table t1 add unique(v); +ERROR 23000: Duplicate entry '{ ' for key 'v_2' +select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); +qq +*a*a*a* +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +explain select * from t1 where v='a'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref v v 13 const 10 Using where +select v,count(*) from t1 group by v limit 10; +v count(*) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select v,count(t) from t1 group by v limit 10; +v count(t) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select v,count(c) from t1 group by v limit 10; +v count(c) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select sql_big_result trim(v),count(t) from t1 group by v limit 10; +trim(v) count(t) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select sql_big_result trim(v),count(c) from t1 group by v limit 10; +trim(v) count(c) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select c,count(*) from t1 group by c limit 10; +c count(*) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select c,count(t) from t1 group by c limit 10; +c count(t) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select sql_big_result c,count(t) from t1 group by c limit 10; +c count(t) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select t,count(*) from t1 group by t limit 10; +t count(*) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select t,count(t) from t1 group by t limit 10; +t count(t) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +select sql_big_result trim(t),count(t) from t1 group by t limit 10; +trim(t) count(t) +a 1 +a 10 +b 10 +c 10 +d 10 +e 10 +f 10 +g 10 +h 10 +i 10 +drop table t1; +create table t1 (a char(10), unique (a)); +insert into t1 values ('a'); +insert into t1 values ('a '); +ERROR 23000: Duplicate entry 'a' for key 'a' +alter table t1 modify a varchar(10); +insert into t1 values ('a '),('a '),('a '),('a '); +ERROR 23000: Duplicate entry 'a ' for key 'a' +insert into t1 values ('a '); +ERROR 23000: Duplicate entry 'a ' for key 'a' +insert into t1 values ('a '); +ERROR 23000: Duplicate entry 'a ' for key 'a' +insert into t1 values ('a '); +ERROR 23000: Duplicate entry 'a ' for key 'a' +update t1 set a='a ' where a like 'a '; +update t1 set a='a ' where a like 'a '; +drop table t1; +create table t1 (v varchar(10), c char(10), t varchar(50), key using btree (v), key using btree (c), key using btree (t(10))); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` varchar(10) DEFAULT NULL, + `c` char(10) DEFAULT NULL, + `t` varchar(50) DEFAULT NULL, + KEY `v` (`v`) USING BTREE, + KEY `c` (`c`) USING BTREE, + KEY `t` (`t`(10)) USING BTREE +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +270 +insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); +select count(*) from t1 where v='a'; +count(*) +10 +select count(*) from t1 where c='a'; +count(*) +10 +select count(*) from t1 where t='a'; +count(*) +10 +select count(*) from t1 where v='a '; +count(*) +10 +select count(*) from t1 where c='a '; +count(*) +10 +select count(*) from t1 where t='a '; +count(*) +10 +select count(*) from t1 where v between 'a' and 'a '; +count(*) +10 +select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; +count(*) +10 +explain select count(*) from t1 where v='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref v v 13 const # Using where +explain select count(*) from t1 where c='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c c 11 const # Using where +explain select count(*) from t1 where t='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref t t 13 const # Using where +explain select count(*) from t1 where v like 'a%'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range v v 13 NULL # Using where +explain select count(*) from t1 where v between 'a' and 'a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref v v 13 const # Using where +explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref v v 13 const # Using where +alter table t1 add unique(v); +ERROR 23000: Duplicate entry '{ ' for key 'v_2' +select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); +qq +*a*a*a* +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +*a *a*a * +explain select * from t1 where v='a'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref v v 13 const # Using where +drop table t1; +create table t1 (a char(10), unique using btree (a)) engine=heap; +insert into t1 values ('a'); +insert into t1 values ('a '); +ERROR 23000: Duplicate entry 'a' for key 'a' +alter table t1 modify a varchar(10); +insert into t1 values ('a '),('a '),('a '),('a '); +ERROR 23000: Duplicate entry 'a ' for key 'a' +insert into t1 values ('a '); +ERROR 23000: Duplicate entry 'a ' for key 'a' +insert into t1 values ('a '); +ERROR 23000: Duplicate entry 'a ' for key 'a' +insert into t1 values ('a '); +ERROR 23000: Duplicate entry 'a ' for key 'a' +update t1 set a='a ' where a like 'a '; +update t1 set a='a ' where a like 'a '; +drop table t1; +create table t1 (v varchar(10), c char(10), t varchar(50), key(v(5)), key(c(5)), key(t(5))); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` varchar(10) DEFAULT NULL, + `c` char(10) DEFAULT NULL, + `t` varchar(50) DEFAULT NULL, + KEY `v` (`v`(5)), + KEY `c` (`c`(5)), + KEY `t` (`t`(5)) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (v varchar(65530), key(v(10))); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `v` varchar(65530) DEFAULT NULL, + KEY `v` (`v`(10)) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +insert into t1 values(repeat('a',65530)); +select length(v) from t1 where v=repeat('a',65530); +length(v) +65530 +drop table t1; +set storage_engine=PBXT; +create table t1 (a bigint unsigned auto_increment primary key, b int, +key (b, a)) engine=heap; +insert t1 (b) values (1),(1),(1),(1),(1),(1),(1),(1); +select * from t1; +a b +1 1 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +drop table t1; +create table t1 (a int not null, b int not null auto_increment, +primary key(a, b), key(b)) engine=heap; +insert t1 (a) values (1),(1),(1),(1),(1),(1),(1),(1); +select * from t1; +a b +1 1 +1 2 +1 3 +1 4 +1 5 +1 6 +1 7 +1 8 +drop table t1; +create table t1 (a int not null, b int not null auto_increment, +primary key(a, b)) engine=heap; +ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key +create table t1 (c char(255), primary key(c(90))); +insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); +insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); +ERROR 23000: Duplicate entry 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl' for key 'PRIMARY' +drop table t1; +CREATE TABLE t1 (a int, key(a)) engine=heap; +insert into t1 values (0); +delete from t1; +select * from t1; +a +insert into t1 values (0), (1); +select * from t1 where a = 0; +a +0 +drop table t1; +create table t1 (c char(10)) engine=memory; +create table t2 (c varchar(10)) engine=memory; +show table status like 't_'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL +drop table t1, t2; +CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256), +KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY; +INSERT INTO t1 VALUES('a','aa',REPEAT('a', 256)),('a','aa',REPEAT('a',256)); +SELECT COUNT(*) FROM t1 WHERE a='a'; +COUNT(*) +2 +SELECT COUNT(*) FROM t1 WHERE b='aa'; +COUNT(*) +2 +SELECT COUNT(*) FROM t1 WHERE c=REPEAT('a',256); +COUNT(*) +2 +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/heap_auto_increment.result b/mysql-test/suite/pbxt/r/heap_auto_increment.result new file mode 100644 index 00000000000..5b04a77e9eb --- /dev/null +++ b/mysql-test/suite/pbxt/r/heap_auto_increment.result @@ -0,0 +1,41 @@ +drop table if exists t1; +create table t1 (a int not null auto_increment,b int, primary key (a)) engine=heap auto_increment=3; +insert into t1 values (1,1),(NULL,3),(NULL,4); +delete from t1 where a=4; +insert into t1 values (NULL,5),(NULL,6); +select * from t1; +a b +1 1 +3 3 +5 5 +6 6 +delete from t1 where a=6; +replace t1 values (3,1); +ALTER TABLE t1 add c int; +replace t1 values (3,3,3); +insert into t1 values (NULL,7,7); +update t1 set a=8,b=b+1,c=c+1 where a=7; +insert into t1 values (NULL,9,9); +select * from t1; +a b c +1 1 NULL +3 3 3 +5 5 NULL +8 8 8 +9 9 9 +drop table t1; +create table t1 ( +skey tinyint unsigned NOT NULL auto_increment PRIMARY KEY, +sval char(20) +) engine=heap; +insert into t1 values (NULL, "hello"); +insert into t1 values (NULL, "hey"); +select * from t1; +skey sval +1 hello +2 hey +select _rowid,t1._rowid,skey,sval from t1; +_rowid _rowid skey sval +1 1 1 hello +2 2 2 hey +drop table t1; diff --git a/mysql-test/suite/pbxt/r/heap_btree.result b/mysql-test/suite/pbxt/r/heap_btree.result new file mode 100644 index 00000000000..fd789a39d88 --- /dev/null +++ b/mysql-test/suite/pbxt/r/heap_btree.result @@ -0,0 +1,297 @@ +drop table if exists t1; +create table t1 (a int not null,b int not null, primary key using BTREE (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a=1 or a=0; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 a A NULL NULL NULL BTREE +select * from t1; +a b +2 2 +3 3 +4 4 +select * from t1 where a=4; +a b +4 4 +update t1 set b=5 where a=4; +update t1 set b=b+1 where a>=3; +replace t1 values (3,3); +select * from t1; +a b +2 2 +3 3 +4 6 +alter table t1 add c int not null, add key using BTREE (c,a); +drop table t1; +create table t1 (a int not null,b int not null, primary key using BTREE (a)) engine=heap comment="testing heaps"; +insert into t1 values(-2,-2),(-1,-1),(0,0),(1,1),(2,2),(3,3),(4,4); +delete from t1 where a > -3; +select * from t1; +a b +drop table t1; +create table t1 (a int not null,b int not null, primary key using BTREE (a)) engine=heap comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +alter table t1 modify a int not null auto_increment, engine=myisam, comment="new myisam table"; +select * from t1; +a b +1 1 +2 2 +3 3 +4 4 +drop table t1; +create table t1 (a int not null) engine=heap; +insert into t1 values (869751),(736494),(226312),(802616),(728912); +select * from t1 where a > 736494; +a +869751 +802616 +alter table t1 add unique uniq_id using BTREE (a); +select * from t1 where a > 736494; +a +802616 +869751 +select * from t1 where a = 736494; +a +736494 +select * from t1 where a=869751 or a=736494; +a +736494 +869751 +select * from t1 where a in (869751,736494,226312,802616); +a +226312 +736494 +802616 +869751 +alter table t1 engine=myisam; +explain select * from t1 where a in (869751,736494,226312,802616); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range uniq_id uniq_id 4 NULL 4 Using where; Using index +drop table t1; +create table t1 (x int not null, y int not null, key x using BTREE (x,y), unique y using BTREE (y)) +engine=heap; +insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6); +explain select * from t1 where x=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref x x 4 const 1 +select * from t1 where x=1; +x y +1 1 +1 3 +select * from t1,t1 as t2 where t1.x=t2.y; +x y x y +1 1 1 1 +2 2 2 2 +1 3 1 1 +2 4 2 2 +2 5 2 2 +2 6 2 2 +explain select * from t1,t1 as t2 where t1.x=t2.y; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL x NULL NULL NULL 6 +1 SIMPLE t2 eq_ref y y 4 test.t1.x 1 +drop table t1; +create table t1 (a int) engine=heap; +insert into t1 values(1); +select max(a) from t1; +max(a) +1 +drop table t1; +CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key using BTREE (a,b), key using BTREE (b) ) ENGINE=HEAP; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +a b +1 1 +1 2 +1 3 +1 4 +1 5 +1 6 +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +a b +1 1 +1 1 +1 2 +1 2 +1 3 +1 3 +1 4 +1 4 +1 5 +1 5 +1 6 +1 6 +explain select * from tx where a=x order by a,b; +id select_type table type possible_keys key key_len ref rows Extra +x SIMPLE tx ref a a x const x Using where +explain select * from tx where a=x order by b; +id select_type table type possible_keys key key_len ref rows Extra +x SIMPLE tx ref a a x const x Using where +select * from t1 where b=1; +a b +1 1 +1 1 +explain select * from tx where b=x; +id select_type table type possible_keys key key_len ref rows Extra +x SIMPLE tx ref b b x const x +drop table t1; +create table t1 (id int unsigned not null, primary key using BTREE (id)) engine=HEAP; +insert into t1 values(1); +select max(id) from t1; +max(id) +1 +insert into t1 values(2); +select max(id) from t1; +max(id) +2 +replace into t1 values(1); +drop table t1; +create table t1 (n int) engine=heap; +drop table t1; +create table t1 (n int) engine=heap; +drop table if exists t1; +CREATE table t1(f1 int not null,f2 char(20) not +null,index(f2)) engine=heap; +INSERT into t1 set f1=12,f2="bill"; +INSERT into t1 set f1=13,f2="bill"; +INSERT into t1 set f1=14,f2="bill"; +INSERT into t1 set f1=15,f2="bill"; +INSERT into t1 set f1=16,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +delete from t1 where f2="bill"; +select * from t1; +f1 f2 +16 ted +12 ted +12 ted +12 ted +12 ted +drop table t1; +create table t1 (btn char(10) not null, key using BTREE (btn)) engine=heap; +insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i"); +explain select * from t1 where btn like "i%"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range btn btn 10 NULL 1 Using where +explain select * from t1 where btn like "h%"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range btn btn 10 NULL # Using where +explain select * from t1 where btn like "a%"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range btn btn 10 NULL 1 Using where +explain select * from t1 where btn like "b%"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range btn btn 10 NULL 1 Using where +select * from t1 where btn like "ff%"; +btn +select * from t1 where btn like " %"; +btn +select * from t1 where btn like "q%"; +btn +alter table t1 add column new_col char(1) not null, add key using BTREE (btn,new_col), drop key btn; +update t1 set new_col=left(btn,1); +explain select * from t1 where btn="a"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref btn btn 10 const 1 Using where +explain select * from t1 where btn="a" and new_col="a"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref btn btn 11 const,const 1 Using where +drop table t1; +CREATE TABLE t1 ( +a int default NULL, +b int default NULL, +KEY a using BTREE (a), +UNIQUE b using BTREE (b) +) engine=heap; +INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3); +SELECT * FROM t1 WHERE a=NULL; +a b +explain SELECT * FROM t1 WHERE a IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 1 Using where +SELECT * FROM t1 WHERE a<=>NULL; +a b +NULL 99 +SELECT * FROM t1 WHERE b=NULL; +a b +explain SELECT * FROM t1 WHERE b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref b b 5 const 1 Using where +SELECT * FROM t1 WHERE b<=>NULL; +a b +99 NULL +INSERT INTO t1 VALUES (1,3); +ERROR 23000: Duplicate entry '3' for key 'b' +DROP TABLE t1; +CREATE TABLE t1 (a int, b int, c int, key using BTREE (a, b, c)) engine=heap; +INSERT INTO t1 VALUES (1, NULL, NULL), (1, 1, NULL), (1, NULL, 1); +SELECT * FROM t1 WHERE a=1 and b IS NULL; +a b c +1 NULL NULL +1 NULL 1 +SELECT * FROM t1 WHERE a=1 and c IS NULL; +a b c +1 NULL NULL +1 1 NULL +SELECT * FROM t1 WHERE a=1 and b IS NULL and c IS NULL; +a b c +1 NULL NULL +DROP TABLE t1; +CREATE TABLE t1 (a int not null, primary key using BTREE (a)) engine=heap; +INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); +DELETE from t1 where a < 100; +SELECT * from t1; +a +DROP TABLE t1; +create table t1(a int not null, key using btree(a)) engine=heap; +insert into t1 values (2), (2), (2), (1), (1), (3), (3), (3), (3); +select a from t1 where a > 2 order by a; +a +3 +3 +3 +3 +delete from t1 where a < 4; +select a from t1 order by a; +a +insert into t1 values (2), (2), (2), (1), (1), (3), (3), (3), (3); +select a from t1 where a > 4 order by a; +a +delete from t1 where a > 4; +select a from t1 order by a; +a +1 +1 +2 +2 +2 +3 +3 +3 +3 +select a from t1 where a > 3 order by a; +a +delete from t1 where a >= 2; +select a from t1 order by a; +a +1 +1 +drop table t1; +End of 4.1 tests +CREATE TABLE t1(val INT, KEY USING BTREE(val)) ENGINE=memory; +INSERT INTO t1 VALUES(0); +SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='t1'; +INDEX_LENGTH +21 +UPDATE t1 SET val=1; +SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='t1'; +INDEX_LENGTH +21 +DROP TABLE t1; +CREATE TABLE t1 (a INT, UNIQUE USING BTREE(a)) ENGINE=MEMORY; +INSERT INTO t1 VALUES(NULL),(NULL); +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/heap_hash.result b/mysql-test/suite/pbxt/r/heap_hash.result new file mode 100644 index 00000000000..41f00fd2ad8 --- /dev/null +++ b/mysql-test/suite/pbxt/r/heap_hash.result @@ -0,0 +1,368 @@ +drop table if exists t1,t2; +create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a=1 or a=0; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 a NULL 3 NULL NULL HASH +select * from t1; +a b +2 2 +3 3 +4 4 +select * from t1 where a=4; +a b +4 4 +update t1 set b=5 where a=4; +update t1 set b=b+1 where a>=3; +replace t1 values (3,3); +select * from t1; +a b +2 2 +3 3 +4 6 +alter table t1 add c int not null, add key using HASH (c,a); +drop table t1; +create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a > 0; +select * from t1; +a b +drop table t1; +create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +alter table t1 modify a int not null auto_increment, engine=myisam, comment="new myisam table"; +select * from t1; +a b +1 1 +2 2 +3 3 +4 4 +drop table t1; +create table t1 (a int not null) engine=heap; +insert into t1 values (869751),(736494),(226312),(802616),(728912); +select * from t1 where a > 736494; +a +869751 +802616 +alter table t1 add unique uniq_id using HASH (a); +select * from t1 where a > 736494; +a +869751 +802616 +select * from t1 where a = 736494; +a +736494 +select * from t1 where a=869751 or a=736494; +a +736494 +869751 +select * from t1 where a in (869751,736494,226312,802616); +a +226312 +736494 +802616 +869751 +alter table t1 engine=myisam; +explain select * from t1 where a in (869751,736494,226312,802616); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range uniq_id uniq_id 4 NULL 4 Using where; Using index +drop table t1; +create table t1 (x int not null, y int not null, key x using HASH (x), unique y using HASH (y)) +engine=heap; +insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6); +select * from t1 where x=1; +x y +1 3 +1 1 +select * from t1,t1 as t2 where t1.x=t2.y; +x y x y +1 1 1 1 +2 2 2 2 +1 3 1 1 +2 4 2 2 +2 5 2 2 +2 6 2 2 +explain select * from t1,t1 as t2 where t1.x=t2.y; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL x NULL NULL NULL 6 +1 SIMPLE t2 eq_ref y y 4 test.t1.x 1 +drop table t1; +create table t1 (a int) engine=heap; +insert into t1 values(1); +select max(a) from t1; +max(a) +1 +drop table t1; +CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key using HASH (a), key using HASH (b) ) ENGINE=HEAP; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +a b +1 6 +1 5 +1 4 +1 3 +1 2 +1 1 +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +a b +1 6 +1 5 +1 4 +1 3 +1 2 +1 1 +1 6 +1 5 +1 4 +1 3 +1 2 +1 1 +drop table t1; +create table t1 (id int unsigned not null, primary key using HASH (id)) engine=HEAP; +insert into t1 values(1); +select max(id) from t1; +max(id) +1 +insert into t1 values(2); +select max(id) from t1; +max(id) +2 +replace into t1 values(1); +drop table t1; +create table t1 (n int) engine=heap; +drop table t1; +create table t1 (n int) engine=heap; +drop table if exists t1; +CREATE table t1(f1 int not null,f2 char(20) not +null,index(f2)) engine=heap; +INSERT into t1 set f1=12,f2="bill"; +INSERT into t1 set f1=13,f2="bill"; +INSERT into t1 set f1=14,f2="bill"; +INSERT into t1 set f1=15,f2="bill"; +INSERT into t1 set f1=16,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +delete from t1 where f2="bill"; +select * from t1; +f1 f2 +16 ted +12 ted +12 ted +12 ted +12 ted +drop table t1; +create table t1 (btn char(10) not null, key using HASH (btn)) engine=heap; +insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i"); +explain select * from t1 where btn like "q%"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL btn NULL NULL NULL 14 Using where +select * from t1 where btn like "q%"; +btn +alter table t1 add column new_col char(1) not null, add key using HASH (btn,new_col), drop key btn; +update t1 set new_col=left(btn,1); +explain select * from t1 where btn="a"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL btn NULL NULL NULL 14 Using where +explain select * from t1 where btn="a" and new_col="a"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref btn btn 11 const,const 2 Using where +drop table t1; +CREATE TABLE t1 ( +a int default NULL, +b int default NULL, +KEY a using HASH (a), +UNIQUE b using HASH (b) +) engine=heap; +INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3); +SELECT * FROM t1 WHERE a=NULL; +a b +explain SELECT * FROM t1 WHERE a IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 2 Using where +SELECT * FROM t1 WHERE a<=>NULL; +a b +NULL 99 +SELECT * FROM t1 WHERE b=NULL; +a b +explain SELECT * FROM t1 WHERE b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref b b 5 const 1 Using where +SELECT * FROM t1 WHERE b<=>NULL; +a b +99 NULL +INSERT INTO t1 VALUES (1,3); +ERROR 23000: Duplicate entry '3' for key 'b' +DROP TABLE t1; +CREATE TABLE t1 (a int not null, primary key using HASH (a)) engine=heap; +INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); +DELETE from t1 where a < 100; +SELECT * from t1; +a +DROP TABLE t1; +create table t1 +( +a char(8) not null, +b char(20) not null, +c int not null, +key (a) +) engine=heap; +insert into t1 values ('aaaa', 'prefill-hash=5',0); +insert into t1 values ('aaab', 'prefill-hash=0',0); +insert into t1 values ('aaac', 'prefill-hash=7',0); +insert into t1 values ('aaad', 'prefill-hash=2',0); +insert into t1 values ('aaae', 'prefill-hash=1',0); +insert into t1 values ('aaaf', 'prefill-hash=4',0); +insert into t1 values ('aaag', 'prefill-hash=3',0); +insert into t1 values ('aaah', 'prefill-hash=6',0); +explain select * from t1 where a='aaaa'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaac'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaad'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +insert into t1 select * from t1; +flush tables; +explain select * from t1 where a='aaaa'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaac'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaad'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +flush tables; +explain select * from t1 where a='aaaa'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaac'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaad'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +create table t2 as select * from t1; +delete from t1; +insert into t1 select * from t2; +explain select * from t1 where a='aaaa'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaac'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +explain select * from t1 where a='aaad'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 8 const 2 Using where +drop table t1, t2; +create table t1 ( +id int unsigned not null primary key auto_increment, +name varchar(20) not null, +index heap_idx(name), +index btree_idx using btree(name) +) engine=heap; +create table t2 ( +id int unsigned not null primary key auto_increment, +name varchar(20) not null, +index btree_idx using btree(name), +index heap_idx(name) +) engine=heap; +insert into t1 (name) values ('Matt'), ('Lilu'), ('Corbin'), ('Carly'), +('Suzy'), ('Hoppy'), ('Burrito'), ('Mimi'), ('Sherry'), ('Ben'), ('Phil'), +('Emily'), ('Mike'); +insert into t2 select * from t1; +explain select * from t1 where name='matt'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref heap_idx,btree_idx btree_idx 22 const 1 Using where +explain select * from t2 where name='matt'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 22 const 1 Using where +explain select * from t1 where name='Lilu'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref heap_idx,btree_idx btree_idx 22 const 1 Using where +explain select * from t2 where name='Lilu'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 22 const 1 Using where +explain select * from t1 where name='Phil'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref heap_idx,btree_idx btree_idx 22 const 1 Using where +explain select * from t2 where name='Phil'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 22 const 1 Using where +explain select * from t1 where name='Lilu'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref heap_idx,btree_idx btree_idx 22 const 1 Using where +explain select * from t2 where name='Lilu'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 22 const 1 Using where +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +flush tables; +select count(*) from t1 where name='Matt'; +count(*) +7 +explain select * from t1 ignore index (btree_idx) where name='matt'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 id NULL 91 NULL NULL HASH +t1 1 heap_idx 1 name NULL 13 NULL NULL HASH +t1 1 btree_idx 1 name A NULL NULL NULL BTREE +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 id NULL 91 NULL NULL HASH +t1 1 heap_idx 1 name NULL 13 NULL NULL HASH +t1 1 btree_idx 1 name A NULL NULL NULL BTREE +create table t3 +( +a varchar(20) not null, +b varchar(20) not null, +key (a,b) +) engine=heap; +insert into t3 select name, name from t1; +show index from t3; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t3 1 a 1 a NULL NULL NULL NULL HASH +t3 1 a 2 b NULL 13 NULL NULL HASH +show index from t3; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t3 1 a 1 a NULL NULL NULL NULL HASH +t3 1 a 2 b NULL 13 NULL NULL HASH +explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where +1 SIMPLE t3 ref a a 44 func,const 7 Using where +drop table t1, t2, t3; +create temporary table t1 ( a int, index (a) ) engine=memory; +insert into t1 values (1),(2),(3),(4),(5); +select a from t1 where a in (1,3); +a +1 +3 +explain select a from t1 where a in (1,3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 4 Using where +drop table t1; diff --git a/mysql-test/suite/pbxt/r/help.result b/mysql-test/suite/pbxt/r/help.result new file mode 100644 index 00000000000..16719cc8193 --- /dev/null +++ b/mysql-test/suite/pbxt/r/help.result @@ -0,0 +1,268 @@ +insert into mysql.help_category(help_category_id,name)values(10001,'impossible_category_1'); +Warnings: +Warning 1364 Field 'url' doesn't have a default value +select @category1_id:= 10001; +@category1_id:= 10001 +10001 +insert into mysql.help_category(help_category_id,name)values(10002,'impossible_category_2'); +Warnings: +Warning 1364 Field 'url' doesn't have a default value +select @category2_id:= 10002; +@category2_id:= 10002 +10002 +insert into mysql.help_category(help_category_id,name,parent_category_id)values(10003,'impossible_category_3',@category2_id); +Warnings: +Warning 1364 Field 'url' doesn't have a default value +select @category3_id:= 10003; +@category3_id:= 10003 +10003 +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10101,'impossible_function_1',@category1_id,'description of \n impossible_function1\n','example of \n impossible_function1'); +Warnings: +Warning 1364 Field 'url' doesn't have a default value +select @topic1_id:= 10101; +@topic1_id:= 10101 +10101 +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10102,'impossible_function_2',@category1_id,'description of \n impossible_function2\n','example of \n impossible_function2'); +Warnings: +Warning 1364 Field 'url' doesn't have a default value +select @topic2_id:= 10102; +@topic2_id:= 10102 +10102 +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10103,'impossible_function_3',@category2_id,'description of \n impossible_function3\n','example of \n impossible_function3'); +Warnings: +Warning 1364 Field 'url' doesn't have a default value +select @topic3_id:= 10103; +@topic3_id:= 10103 +10103 +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10104,'impossible_function_4',@category2_id,'description of \n impossible_function4\n','example of \n impossible_function4'); +Warnings: +Warning 1364 Field 'url' doesn't have a default value +select @topic4_id:= 10104; +@topic4_id:= 10104 +10104 +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10105,'impossible_function_7',@category3_id,'description of \n impossible_function5\n','example of \n impossible_function7'); +Warnings: +Warning 1364 Field 'url' doesn't have a default value +select @topic5_id:= 10105; +@topic5_id:= 10105 +10105 +insert into mysql.help_keyword(help_keyword_id,name)values(10201,'impossible_function_1'); +select @keyword1_id:= 10201; +@keyword1_id:= 10201 +10201 +insert into mysql.help_keyword(help_keyword_id,name)values(10202,'impossible_function_5'); +select @keyword2_id:= 10202; +@keyword2_id:= 10202 +10202 +insert into mysql.help_keyword(help_keyword_id,name)values(10203,'impossible_function_6'); +select @keyword3_id:= 10203; +@keyword3_id:= 10203 +10203 +insert into mysql.help_relation(help_keyword_id,help_topic_id)values(@keyword1_id,@topic2_id); +insert into mysql.help_relation(help_keyword_id,help_topic_id)values(@keyword2_id,@topic1_id); +insert into mysql.help_relation(help_keyword_id,help_topic_id)values(@keyword3_id,@topic3_id); +insert into mysql.help_relation(help_keyword_id,help_topic_id)values(@keyword3_id,@topic4_id); +help 'function_of_my_dream'; +name is_it_category +help '%possible_f%'; +name is_it_category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +impossible_function_4 N +impossible_function_7 N +help 'impossible_func%'; +name is_it_category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +impossible_function_4 N +impossible_function_7 N +help 'impossible_category%'; +name is_it_category +impossible_category_1 Y +impossible_category_2 Y +impossible_category_3 Y +help 'impossible_%'; +name is_it_category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +impossible_function_4 N +impossible_function_7 N +impossible_category_1 Y +impossible_category_2 Y +impossible_category_3 Y +help '%function_1'; +name description example +impossible_function_1 description of + impossible_function1 + example of + impossible_function1 +help '%function_2'; +name description example +impossible_function_2 description of + impossible_function2 + example of + impossible_function2 +help '%function_3'; +name description example +impossible_function_3 description of + impossible_function3 + example of + impossible_function3 +help '%function_4'; +name description example +impossible_function_4 description of + impossible_function4 + example of + impossible_function4 +help '%function_5'; +name description example +impossible_function_1 description of + impossible_function1 + example of + impossible_function1 +help '%function_6'; +name is_it_category +impossible_function_3 N +impossible_function_4 N +help '%function_7'; +name description example +impossible_function_7 description of + impossible_function5 + example of + impossible_function7 +help '%category_2'; +source_category_name name is_it_category +impossible_category_2 impossible_function_3 N +impossible_category_2 impossible_function_4 N +impossible_category_2 impossible_category_3 Y +help 'impossible_function_1'; +name description example +impossible_function_1 description of + impossible_function1 + example of + impossible_function1 +help 'impossible_category_1'; +source_category_name name is_it_category +impossible_category_1 impossible_function_1 N +impossible_category_1 impossible_function_2 N +alter table mysql.help_relation engine=innodb; +alter table mysql.help_keyword engine=innodb; +alter table mysql.help_topic engine=innodb; +alter table mysql.help_category engine=innodb; +help 'function_of_my_dream'; +name is_it_category +help '%possible_f%'; +name is_it_category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +impossible_function_4 N +impossible_function_7 N +help 'impossible_func%'; +name is_it_category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +impossible_function_4 N +impossible_function_7 N +help 'impossible_category%'; +name is_it_category +impossible_category_1 Y +impossible_category_2 Y +impossible_category_3 Y +help 'impossible_%'; +name is_it_category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +impossible_function_4 N +impossible_function_7 N +impossible_category_1 Y +impossible_category_2 Y +impossible_category_3 Y +help '%function_1'; +name description example +impossible_function_1 description of + impossible_function1 + example of + impossible_function1 +help '%function_2'; +name description example +impossible_function_2 description of + impossible_function2 + example of + impossible_function2 +help '%function_3'; +name description example +impossible_function_3 description of + impossible_function3 + example of + impossible_function3 +help '%function_4'; +name description example +impossible_function_4 description of + impossible_function4 + example of + impossible_function4 +help '%function_5'; +name description example +impossible_function_1 description of + impossible_function1 + example of + impossible_function1 +help '%function_6'; +name is_it_category +impossible_function_3 N +impossible_function_4 N +help '%function_7'; +name description example +impossible_function_7 description of + impossible_function5 + example of + impossible_function7 +help '%category_2'; +source_category_name name is_it_category +impossible_category_2 impossible_function_3 N +impossible_category_2 impossible_function_4 N +impossible_category_2 impossible_category_3 Y +help 'impossible_function_1'; +name description example +impossible_function_1 description of + impossible_function1 + example of + impossible_function1 +help 'impossible_category_1'; +source_category_name name is_it_category +impossible_category_1 impossible_function_1 N +impossible_category_1 impossible_function_2 N +alter table mysql.help_relation engine=myisam; +alter table mysql.help_keyword engine=myisam; +alter table mysql.help_topic engine=myisam; +alter table mysql.help_category engine=myisam; +delete from mysql.help_topic where help_topic_id=@topic1_id; +delete from mysql.help_topic where help_topic_id=@topic2_id; +delete from mysql.help_topic where help_topic_id=@topic3_id; +delete from mysql.help_topic where help_topic_id=@topic4_id; +delete from mysql.help_topic where help_topic_id=@topic5_id; +delete from mysql.help_category where help_category_id=@category3_id; +delete from mysql.help_category where help_category_id=@category2_id; +delete from mysql.help_category where help_category_id=@category1_id; +delete from mysql.help_keyword where help_keyword_id=@keyword1_id; +delete from mysql.help_keyword where help_keyword_id=@keyword2_id; +delete from mysql.help_keyword where help_keyword_id=@keyword3_id; +delete from mysql.help_relation where help_keyword_id=@keyword1_id and help_topic_id=@topic2_id; +delete from mysql.help_relation where help_keyword_id=@keyword2_id and help_topic_id=@topic1_id; +delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic3_id; +delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic4_id; +End of 4.1 tests. +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i INT); +LOCK TABLES t1 WRITE; +HELP no_such_topic; +name is_it_category +UNLOCK TABLES; +DROP TABLE t1; +End of 5.1 tests. diff --git a/mysql-test/suite/pbxt/r/insert.result b/mysql-test/suite/pbxt/r/insert.result new file mode 100644 index 00000000000..dbe38c24345 --- /dev/null +++ b/mysql-test/suite/pbxt/r/insert.result @@ -0,0 +1,364 @@ +drop table if exists t1,t2,t3; +create table t1 (a int not null); +insert into t1 values (1); +insert into t1 values (a+2); +insert into t1 values (a+3),(a+4); +insert into t1 values (5),(a+6); +select * from t1; +a +1 +2 +3 +4 +5 +6 +drop table t1; +create table t1 (id int not null auto_increment primary key, username varchar(32) not null, unique (username)); +insert into t1 values (0,"mysql"); +insert into t1 values (0,"mysql ab"); +insert into t1 values (0,"mysql a"); +insert into t1 values (0,"r1manic"); +insert into t1 values (0,"r1man"); +drop table t1; +create table t1 (a int not null auto_increment, primary key (a), t timestamp, c char(10) default "hello", i int); +insert into t1 values (default,default,default,default), (default,default,default,default), (4,0,"a",5),(default,default,default,default); +select a,t>0,c,i from t1; +a t>0 c i +1 1 hello NULL +2 1 hello NULL +4 0 a 5 +5 1 hello NULL +truncate table t1; +insert into t1 set a=default,t=default,c=default; +insert into t1 set a=default,t=default,c=default,i=default; +insert into t1 set a=4,t=0,c="a",i=5; +insert into t1 set a=5,t=0,c="a",i=null; +insert into t1 set a=default,t=default,c=default,i=default; +select a,t>0,c,i from t1; +a t>0 c i +1 1 hello NULL +2 1 hello NULL +4 0 a 5 +5 0 a NULL +6 1 hello NULL +drop table t1; +create table t1 (sid char(20), id int(2) NOT NULL auto_increment, key(sid, id)); +insert into t1 values ('skr',NULL),('skr',NULL),('test',NULL); +select * from t1; +sid id +skr 1 +skr 2 +test 3 +insert into t1 values ('rts',NULL),('rts',NULL),('test',NULL); +select * from t1; +sid id +rts 4 +rts 5 +skr 1 +skr 2 +test 3 +test 6 +drop table t1; +create table t1 (id int NOT NULL DEFAULT 8); +insert into t1 values(NULL); +ERROR 23000: Column 'id' cannot be null +insert into t1 values (1), (NULL), (2); +Warnings: +Warning 1048 Column 'id' cannot be null +select * from t1; +id +1 +0 +2 +drop table t1; +create table t1 (email varchar(50)); +insert into t1 values ('sasha@mysql.com'),('monty@mysql.com'),('foo@hotmail.com'),('foo@aol.com'),('bar@aol.com'); +create table t2(id int not null auto_increment primary key, t2 varchar(50), unique(t2)); +insert into t2 (t2) select distinct substring(email, locate('@', email)+1) from t1; +select * from t2; +id t2 +1 mysql.com +2 hotmail.com +3 aol.com +drop table t1,t2; +drop database if exists mysqltest; +create database mysqltest; +use mysqltest; +create table t1 (c int); +insert into mysqltest.t1 set mysqltest.t1.c = '1'; +drop database mysqltest; +use test; +create table t1(number int auto_increment primary key, original_value varchar(50), f_double double, f_float float, f_double_7_2 double(7,2), f_float_4_3 float (4,3), f_double_u double unsigned, f_float_u float unsigned, f_double_15_1_u double(15,1) unsigned, f_float_3_1_u float (3,1) unsigned); +set @value= "aa"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +Warnings: +Warning 1265 Data truncated for column 'f_double' at row 1 +Warning 1265 Data truncated for column 'f_float' at row 1 +Warning 1265 Data truncated for column 'f_double_7_2' at row 1 +Warning 1265 Data truncated for column 'f_float_4_3' at row 1 +Warning 1265 Data truncated for column 'f_double_u' at row 1 +Warning 1265 Data truncated for column 'f_float_u' at row 1 +Warning 1265 Data truncated for column 'f_double_15_1_u' at row 1 +Warning 1265 Data truncated for column 'f_float_3_1_u' at row 1 +select * from t1 where number =last_insert_id(); +number 1 +original_value aa +f_double 0 +f_float 0 +f_double_7_2 0.00 +f_float_4_3 0.000 +f_double_u 0 +f_float_u 0 +f_double_15_1_u 0.0 +f_float_3_1_u 0.0 +set @value= "1aa"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +Warnings: +Warning 1265 Data truncated for column 'f_double' at row 1 +Warning 1265 Data truncated for column 'f_float' at row 1 +Warning 1265 Data truncated for column 'f_double_7_2' at row 1 +Warning 1265 Data truncated for column 'f_float_4_3' at row 1 +Warning 1265 Data truncated for column 'f_double_u' at row 1 +Warning 1265 Data truncated for column 'f_float_u' at row 1 +Warning 1265 Data truncated for column 'f_double_15_1_u' at row 1 +Warning 1265 Data truncated for column 'f_float_3_1_u' at row 1 +select * from t1 where number =last_insert_id(); +number 2 +original_value 1aa +f_double 1 +f_float 1 +f_double_7_2 1.00 +f_float_4_3 1.000 +f_double_u 1 +f_float_u 1 +f_double_15_1_u 1.0 +f_float_3_1_u 1.0 +set @value= "aa1"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +Warnings: +Warning 1265 Data truncated for column 'f_double' at row 1 +Warning 1265 Data truncated for column 'f_float' at row 1 +Warning 1265 Data truncated for column 'f_double_7_2' at row 1 +Warning 1265 Data truncated for column 'f_float_4_3' at row 1 +Warning 1265 Data truncated for column 'f_double_u' at row 1 +Warning 1265 Data truncated for column 'f_float_u' at row 1 +Warning 1265 Data truncated for column 'f_double_15_1_u' at row 1 +Warning 1265 Data truncated for column 'f_float_3_1_u' at row 1 +select * from t1 where number =last_insert_id(); +number 3 +original_value aa1 +f_double 0 +f_float 0 +f_double_7_2 0.00 +f_float_4_3 0.000 +f_double_u 0 +f_float_u 0 +f_double_15_1_u 0.0 +f_float_3_1_u 0.0 +set @value= "1e+1111111111a"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +Warnings: +Warning 1264 Out of range value for column 'f_double' at row 1 +Warning 1264 Out of range value for column 'f_float' at row 1 +Warning 1264 Out of range value for column 'f_float' at row 1 +Warning 1264 Out of range value for column 'f_double_7_2' at row 1 +Warning 1264 Out of range value for column 'f_double_7_2' at row 1 +Warning 1264 Out of range value for column 'f_float_4_3' at row 1 +Warning 1264 Out of range value for column 'f_float_4_3' at row 1 +Warning 1264 Out of range value for column 'f_double_u' at row 1 +Warning 1264 Out of range value for column 'f_float_u' at row 1 +Warning 1264 Out of range value for column 'f_float_u' at row 1 +Warning 1264 Out of range value for column 'f_double_15_1_u' at row 1 +Warning 1264 Out of range value for column 'f_double_15_1_u' at row 1 +Warning 1264 Out of range value for column 'f_float_3_1_u' at row 1 +Warning 1264 Out of range value for column 'f_float_3_1_u' at row 1 +select * from t1 where number =last_insert_id(); +number 4 +original_value 1e+1111111111a +f_double 1.79769313486232e+308 +f_float 3.40282e+38 +f_double_7_2 99999.99 +f_float_4_3 9.999 +f_double_u 1.79769313486232e+308 +f_float_u 3.40282e+38 +f_double_15_1_u 99999999999999.9 +f_float_3_1_u 99.9 +set @value= "-1e+1111111111a"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +Warnings: +Warning 1264 Out of range value for column 'f_double' at row 1 +Warning 1264 Out of range value for column 'f_float' at row 1 +Warning 1264 Out of range value for column 'f_float' at row 1 +Warning 1264 Out of range value for column 'f_double_7_2' at row 1 +Warning 1264 Out of range value for column 'f_double_7_2' at row 1 +Warning 1264 Out of range value for column 'f_float_4_3' at row 1 +Warning 1264 Out of range value for column 'f_float_4_3' at row 1 +Warning 1264 Out of range value for column 'f_double_u' at row 1 +Warning 1264 Out of range value for column 'f_double_u' at row 1 +Warning 1264 Out of range value for column 'f_float_u' at row 1 +Warning 1264 Out of range value for column 'f_float_u' at row 1 +Warning 1264 Out of range value for column 'f_double_15_1_u' at row 1 +Warning 1264 Out of range value for column 'f_double_15_1_u' at row 1 +Warning 1264 Out of range value for column 'f_float_3_1_u' at row 1 +Warning 1264 Out of range value for column 'f_float_3_1_u' at row 1 +select * from t1 where number =last_insert_id(); +number 5 +original_value -1e+1111111111a +f_double -1.79769313486232e+308 +f_float -3.40282e+38 +f_double_7_2 -99999.99 +f_float_4_3 -9.999 +f_double_u 0 +f_float_u 0 +f_double_15_1_u 0.0 +f_float_3_1_u 0.0 +set @value= 1e+1111111111; +ERROR 22007: Illegal double '1e+1111111111' value found during parsing +set @value= -1e+1111111111; +ERROR 22007: Illegal double '1e+1111111111' value found during parsing +set @value= 1e+111; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +Warnings: +Warning 1264 Out of range value for column 'f_float' at row 1 +Warning 1264 Out of range value for column 'f_double_7_2' at row 1 +Warning 1264 Out of range value for column 'f_float_4_3' at row 1 +Warning 1264 Out of range value for column 'f_float_u' at row 1 +Warning 1264 Out of range value for column 'f_double_15_1_u' at row 1 +Warning 1264 Out of range value for column 'f_float_3_1_u' at row 1 +select * from t1 where number =last_insert_id(); +number 6 +original_value 1e+111 +f_double 1e+111 +f_float 3.40282e+38 +f_double_7_2 99999.99 +f_float_4_3 9.999 +f_double_u 1e+111 +f_float_u 3.40282e+38 +f_double_15_1_u 99999999999999.9 +f_float_3_1_u 99.9 +set @value= -1e+111; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +Warnings: +Warning 1264 Out of range value for column 'f_float' at row 1 +Warning 1264 Out of range value for column 'f_double_7_2' at row 1 +Warning 1264 Out of range value for column 'f_float_4_3' at row 1 +Warning 1264 Out of range value for column 'f_double_u' at row 1 +Warning 1264 Out of range value for column 'f_float_u' at row 1 +Warning 1264 Out of range value for column 'f_double_15_1_u' at row 1 +Warning 1264 Out of range value for column 'f_float_3_1_u' at row 1 +select * from t1 where number =last_insert_id(); +number 7 +original_value -1e+111 +f_double -1e+111 +f_float -3.40282e+38 +f_double_7_2 -99999.99 +f_float_4_3 -9.999 +f_double_u 0 +f_float_u 0 +f_double_15_1_u 0.0 +f_float_3_1_u 0.0 +set @value= 1; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +select * from t1 where number =last_insert_id(); +number 8 +original_value 1 +f_double 1 +f_float 1 +f_double_7_2 1.00 +f_float_4_3 1.000 +f_double_u 1 +f_float_u 1 +f_double_15_1_u 1.0 +f_float_3_1_u 1.0 +set @value= -1; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +Warnings: +Warning 1264 Out of range value for column 'f_double_u' at row 1 +Warning 1264 Out of range value for column 'f_float_u' at row 1 +Warning 1264 Out of range value for column 'f_double_15_1_u' at row 1 +Warning 1264 Out of range value for column 'f_float_3_1_u' at row 1 +select * from t1 where number =last_insert_id(); +number 9 +original_value -1 +f_double -1 +f_float -1 +f_double_7_2 -1.00 +f_float_4_3 -1.000 +f_double_u 0 +f_float_u 0 +f_double_15_1_u 0.0 +f_float_3_1_u 0.0 +drop table t1; +create table t1(id1 int not null auto_increment primary key, t char(12)); +create table t2(id2 int not null, t char(12)); +create table t3(id3 int not null, t char(12), index(id3)); +select count(*) from t2; +count(*) +500 +insert into t2 select t1.* from t1, t2 t, t3 where t1.id1 = t.id2 and t.id2 = t3.id3; +select count(*) from t2; +count(*) +25500 +drop table t1,t2,t3; +create table t1 (a int, b int); +insert into t1 (a,b) values (a,b); +insert into t1 SET a=1, b=a+1; +insert into t1 (a,b) select 1,2; +INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a); +prepare stmt1 from ' replace into t1 (a,a) select 100, ''hundred'' '; +execute stmt1; +ERROR 42000: Column 'a' specified twice +insert into t1 (a,b,b) values (1,1,1); +ERROR 42000: Column 'b' specified twice +insert into t1 (a,a) values (1,1,1); +ERROR 21S01: Column count doesn't match value count at row 1 +insert into t1 (a,a) values (1,1); +ERROR 42000: Column 'a' specified twice +insert into t1 SET a=1,b=2,a=1; +ERROR 42000: Column 'a' specified twice +insert into t1 (b,b) select 1,2; +ERROR 42000: Column 'b' specified twice +INSERT INTO t1 (b,b) SELECT 0,0 ON DUPLICATE KEY UPDATE a = a + VALUES (a); +ERROR 42000: Column 'b' specified twice +drop table t1; +create table t1 (id int primary key, data int); +insert into t1 values (1, 1), (2, 2), (3, 3); +select row_count(); +row_count() +3 +insert ignore into t1 values (1, 1); +select row_count(); +row_count() +0 +replace into t1 values (1, 11); +select row_count(); +row_count() +2 +replace into t1 values (4, 4); +select row_count(); +row_count() +1 +insert into t1 values (2, 2) on duplicate key update data= data + 10; +select row_count(); +row_count() +2 +insert into t1 values (5, 5) on duplicate key update data= data + 10; +select row_count(); +row_count() +1 +drop table t1; +create table t1 (id int primary key auto_increment, data int, unique(data)); +insert ignore into t1 values(NULL,100),(NULL,110),(NULL,120); +insert ignore into t1 values(NULL,10),(NULL,20),(NULL,110),(NULL,120),(NULL,100),(NULL,90); +insert ignore into t1 values(NULL,130),(NULL,140),(500,110),(550,120),(450,100),(NULL,150); +select * from t1 order by id; +id data +1 100 +2 110 +3 120 +4 10 +5 20 +6 90 +7 130 +8 140 +551 150 diff --git a/mysql-test/suite/pbxt/r/insert_select.result b/mysql-test/suite/pbxt/r/insert_select.result new file mode 100644 index 00000000000..ce5a8be5a88 --- /dev/null +++ b/mysql-test/suite/pbxt/r/insert_select.result @@ -0,0 +1,706 @@ +drop table if exists t1,t2,t3; +create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); +insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12); +create table t2 (payoutID SMALLINT UNSIGNED NOT NULL PRIMARY KEY); +insert into t2 (payoutID) SELECT DISTINCT payoutID FROM t1; +insert into t2 (payoutID) SELECT payoutID+10 FROM t1; +ERROR 23000: Duplicate entry '16' for key 'PRIMARY' +insert ignore into t2 (payoutID) SELECT payoutID+10 FROM t1; +select * from t2; +payoutID +1 +4 +6 +9 +10 +11 +12 +14 +16 +19 +20 +22 +drop table t1,t2; +CREATE TABLE `t1` ( +`numeropost` bigint(20) unsigned NOT NULL default '0', +`icone` tinyint(4) unsigned NOT NULL default '0', +`numreponse` bigint(20) unsigned NOT NULL auto_increment, +`contenu` text NOT NULL, +`pseudo` varchar(50) NOT NULL default '', +`date` datetime NOT NULL default '0000-00-00 00:00:00', +`ip` bigint(11) NOT NULL default '0', +`signature` tinyint(1) unsigned NOT NULL default '0', +PRIMARY KEY (`numeropost`,`numreponse`) +,KEY `ip` (`ip`), +KEY `date` (`date`), +KEY `pseudo` (`pseudo`), +KEY `numreponse` (`numreponse`) +) ENGINE=MyISAM; +CREATE TABLE `t2` ( +`numeropost` bigint(20) unsigned NOT NULL default '0', +`icone` tinyint(4) unsigned NOT NULL default '0', +`numreponse` bigint(20) unsigned NOT NULL auto_increment, +`contenu` text NOT NULL, +`pseudo` varchar(50) NOT NULL default '', +`date` datetime NOT NULL default '0000-00-00 00:00:00', +`ip` bigint(11) NOT NULL default '0', +`signature` tinyint(1) unsigned NOT NULL default '0', +PRIMARY KEY (`numeropost`,`numreponse`), +KEY `ip` (`ip`), +KEY `date` (`date`), +KEY `pseudo` (`pseudo`), +KEY `numreponse` (`numreponse`) +) ENGINE=MyISAM; +INSERT INTO t2 +(numeropost,icone,numreponse,contenu,pseudo,date,ip,signature) VALUES +(9,1,56,'test','joce','2001-07-25 13:50:53' +,3649052399,0); +INSERT INTO t1 (numeropost,icone,contenu,pseudo,date,signature,ip) +SELECT 1618,icone,contenu,pseudo,date,signature,ip FROM t2 +WHERE numeropost=9 ORDER BY numreponse ASC; +show variables like '%bulk%'; +Variable_name Value +bulk_insert_buffer_size 8388608 +INSERT INTO t1 (numeropost,icone,contenu,pseudo,date,signature,ip) +SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM t2 +WHERE numeropost=9 ORDER BY numreponse ASC; +DROP TABLE t1,t2; +create table t1 (a int not null); +create table t2 (a int not null); +insert into t1 values (1); +insert into t1 values (a+2); +insert into t1 values (a+3); +insert into t1 values (4),(a+5); +insert into t1 select * from t1; +select * from t1; +a +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +insert into t1 select * from t1 as t2; +select * from t1; +a +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +insert into t2 select * from t1 as t2; +select * from t1; +a +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +insert into t1 select t2.a from t1,t2; +select * from t1; +a +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +2 +3 +4 +5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +insert into t1 select * from t1,t1; +ERROR 42000: Not unique table/alias: 't1' +drop table t1,t2; +create table t1 (a int not null primary key, b char(10)); +create table t2 (a int not null, b char(10)); +insert into t1 values (1,"t1:1"),(3,"t1:3"); +insert into t2 values (2,"t2:2"), (3,"t2:3"); +insert into t1 select * from t2; +ERROR 23000: Duplicate entry '3' for key 'PRIMARY' +select * from t1; +a b +1 t1:1 +3 t1:3 +replace into t1 select * from t2; +select * from t1; +a b +1 t1:1 +2 t2:2 +3 t2:3 +drop table t1,t2; +CREATE TABLE t1 ( USID INTEGER UNSIGNED, ServerID TINYINT UNSIGNED, State ENUM ('unknown', 'Access-Granted', 'Session-Active', 'Session-Closed' ) NOT NULL DEFAULT 'unknown', SessionID CHAR(32), User CHAR(32) NOT NULL DEFAULT '<UNKNOWN>', NASAddr INTEGER UNSIGNED, NASPort INTEGER UNSIGNED, NASPortType INTEGER UNSIGNED, ConnectSpeed INTEGER UNSIGNED, CarrierType CHAR(32), CallingStationID CHAR(32), CalledStationID CHAR(32), AssignedAddr INTEGER UNSIGNED, SessionTime INTEGER UNSIGNED, PacketsIn INTEGER UNSIGNED, OctetsIn INTEGER UNSIGNED, PacketsOut INTEGER UNSIGNED, OctetsOut INTEGER UNSIGNED, TerminateCause INTEGER UNSIGNED, UnauthTime TINYINT UNSIGNED, AccessRequestTime DATETIME, AcctStartTime DATETIME, AcctLastTime DATETIME, LastModification TIMESTAMP NOT NULL); +CREATE TABLE t2 ( USID INTEGER UNSIGNED AUTO_INCREMENT, ServerID TINYINT UNSIGNED, State ENUM ('unknown', 'Access-Granted', 'Session-Active', 'Session-Closed' ) NOT NULL DEFAULT 'unknown', SessionID CHAR(32), User TEXT NOT NULL, NASAddr INTEGER UNSIGNED, NASPort INTEGER UNSIGNED, NASPortType INTEGER UNSIGNED, ConnectSpeed INTEGER UNSIGNED, CarrierType CHAR(32), CallingStationID CHAR(32), CalledStationID CHAR(32), AssignedAddr INTEGER UNSIGNED, SessionTime INTEGER UNSIGNED, PacketsIn INTEGER UNSIGNED, OctetsIn INTEGER UNSIGNED, PacketsOut INTEGER UNSIGNED, OctetsOut INTEGER UNSIGNED, TerminateCause INTEGER UNSIGNED, UnauthTime TINYINT UNSIGNED, AccessRequestTime DATETIME, AcctStartTime DATETIME, AcctLastTime DATETIME, LastModification TIMESTAMP NOT NULL, INDEX(USID,ServerID,NASAddr,SessionID), INDEX(AssignedAddr)); +INSERT INTO t1 VALUES (39,42,'Access-Granted','46','491721000045',2130706433,17690,NULL,NULL,'Localnet','491721000045','49172200000',754974766,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2003-07-18 00:11:21',NULL,NULL,20030718001121); +INSERT INTO t2 SELECT USID, ServerID, State, SessionID, User, NASAddr, NASPort, NASPortType, ConnectSpeed, CarrierType, CallingStationID, CalledStationID, AssignedAddr, SessionTime, PacketsIn, OctetsIn, PacketsOut, OctetsOut, TerminateCause, UnauthTime, AccessRequestTime, AcctStartTime, AcctLastTime, LastModification from t1 LIMIT 1; +drop table t1,t2; +CREATE TABLE t1( +Month date NOT NULL, +Type tinyint(3) unsigned NOT NULL auto_increment, +Field int(10) unsigned NOT NULL, +Count int(10) unsigned NOT NULL, +UNIQUE KEY Month (Month,Type,Field) +); +insert into t1 Values +(20030901, 1, 1, 100), +(20030901, 1, 2, 100), +(20030901, 2, 1, 100), +(20030901, 2, 2, 100), +(20030901, 3, 1, 100); +select * from t1; +Month Type Field Count +2003-09-01 1 1 100 +2003-09-01 1 2 100 +2003-09-01 2 1 100 +2003-09-01 2 2 100 +2003-09-01 3 1 100 +Select null, Field, Count From t1 Where Month=20030901 and Type=2; +NULL Field Count +NULL 1 100 +NULL 2 100 +create table t2(No int not null, Field int not null, Count int not null); +insert into t2 Select null, Field, Count From t1 Where Month=20030901 and Type=2; +Warnings: +Warning 1048 Column 'No' cannot be null +Warning 1048 Column 'No' cannot be null +select * from t2; +No Field Count +0 1 100 +0 2 100 +drop table t1, t2; +CREATE TABLE t1 ( +ID int(11) NOT NULL auto_increment, +NO int(11) NOT NULL default '0', +SEQ int(11) NOT NULL default '0', +PRIMARY KEY (ID), +KEY t1$NO (SEQ,NO) +) ENGINE=MyISAM; +INSERT INTO t1 (SEQ, NO) SELECT "1" AS SEQ, IF(MAX(NO) IS NULL, 0, MAX(NO)) + 1 AS NO FROM t1 WHERE (SEQ = 1); +select SQL_BUFFER_RESULT * from t1 WHERE (SEQ = 1); +ID NO SEQ +1 1 1 +drop table t1; +create table t1 (f1 int); +create table t2 (ff1 int unique, ff2 int default 1); +insert into t1 values (1),(1),(2); +insert into t2(ff1) select f1 from t1 on duplicate key update ff2=ff2+1; +select * from t2; +ff1 ff2 +1 2 +2 1 +drop table t1, t2; +create table t1 (a int unique); +create table t2 (a int, b int); +create table t3 (c int, d int); +insert into t1 values (1),(2); +insert into t2 values (1,2); +insert into t3 values (1,6),(3,7); +select * from t1; +a +1 +2 +insert into t1 select a from t2 on duplicate key update a= t1.a + t2.b; +select * from t1; +a +2 +3 +insert into t1 select a+1 from t2 on duplicate key update t1.a= t1.a + t2.b+1; +select * from t1; +a +3 +5 +insert into t1 select t3.c from t3 on duplicate key update a= a + t3.d; +select * from t1; +a +1 +5 +10 +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + 10; +insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +ERROR 23000: Column 'a' in field list is ambiguous +insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; +ERROR 42S22: Unknown column 't2.a' in 'field list' +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; +ERROR 42S22: Unknown column 't2.b' in 'field list' +drop table t1,t2,t3; +create table t1(f1 varchar(5) key); +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +select * from t1; +f1 +2000 +2001 +2002 +drop table t1; +create table t1(x int, y int); +create table t2(x int, z int); +insert into t1(x,y) select x,z from t2 on duplicate key update x=values(x); +insert into t1(x,y) select x,z from t2 on duplicate key update x=values(z); +ERROR 42S22: Unknown column 'z' in 'field list' +insert into t1(x,y) select x,z from t2 on duplicate key update x=values(t2.x); +ERROR 42S22: Unknown column 't2.x' in 'field list' +drop table t1,t2; +CREATE TABLE t1 (a int PRIMARY KEY); +INSERT INTO t1 values (1), (2); +INSERT INTO t1 SELECT a + 2 FROM t1 LIMIT 1; +DROP TABLE t1; +CREATE TABLE t1 (x int, y int); +CREATE TABLE t2 (z int, y int); +CREATE TABLE t3 (a int, b int); +INSERT INTO t3 (SELECT x, y FROM t1 JOIN t2 USING (y) WHERE z = 1); +DROP TABLE IF EXISTS t1,t2,t3; +CREATE DATABASE bug21774_1; +CREATE DATABASE bug21774_2; +CREATE TABLE bug21774_1.t1(id VARCHAR(10) NOT NULL,label VARCHAR(255)); +CREATE TABLE bug21774_2.t1(id VARCHAR(10) NOT NULL,label VARCHAR(255)); +CREATE TABLE bug21774_1.t2(id VARCHAR(10) NOT NULL,label VARCHAR(255)); +INSERT INTO bug21774_2.t1 SELECT t1.* FROM bug21774_1.t1; +use bug21774_1; +INSERT INTO bug21774_2.t1 SELECT t1.* FROM t1; +DROP DATABASE bug21774_1; +DROP DATABASE bug21774_2; diff --git a/mysql-test/suite/pbxt/r/insert_update.result b/mysql-test/suite/pbxt/r/insert_update.result new file mode 100644 index 00000000000..7c2890fc672 --- /dev/null +++ b/mysql-test/suite/pbxt/r/insert_update.result @@ -0,0 +1,221 @@ +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B)); +INSERT t1 VALUES (1,2,10), (3,4,20); +INSERT t1 VALUES (5,6,30) ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1; +a b c +1 2 10 +3 4 20 +5 6 30 +INSERT t1 VALUES (5,7,40) ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1; +a b c +1 2 10 +3 4 20 +5 6 130 +INSERT t1 VALUES (8,4,50) ON DUPLICATE KEY UPDATE c=c+1000; +SELECT * FROM t1 order by a; +a b c +1 2 10 +3 4 1020 +5 6 130 +INSERT t1 VALUES (1,4,60) ON DUPLICATE KEY UPDATE c=c+10000; +SELECT * FROM t1 order by a; +a b c +1 2 10010 +3 4 1020 +5 6 130 +INSERT t1 VALUES (1,9,70) ON DUPLICATE KEY UPDATE c=c+100000, b=4; +ERROR 23000: Duplicate entry '4' for key 'b' +SELECT * FROM t1 order by a; +a b c +1 2 10010 +3 4 1020 +5 6 130 +TRUNCATE TABLE t1; +INSERT t1 VALUES (1,2,10), (3,4,20); +INSERT t1 VALUES (5,6,30), (7,4,40), (8,9,60) ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1; +a b c +1 2 10 +5 6 30 +3 4 120 +8 9 60 +INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0; +SELECT * FROM t1 order by a; +a b c +1 2 10 +3 4 120 +5 0 30 +8 9 60 +INSERT t1 VALUES (2,1,11), (7,4,40) ON DUPLICATE KEY UPDATE c=c+VALUES(a); +SELECT *, VALUES(a) FROM t1 order by a; +a b c VALUES(a) +1 2 10 NULL +2 1 11 NULL +3 4 127 NULL +5 0 30 NULL +8 9 60 NULL +explain extended SELECT *, VALUES(a) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL ROWS 100.00 +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c`,values(`test`.`t1`.`a`) AS `VALUES(a)` from `test`.`t1` +explain extended select * from t1 where values(a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL ROWS 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where values(`test`.`t1`.`a`) +DROP TABLE t1; +create table t1(a int primary key, b int); +insert into t1 values(1,1),(2,2),(3,3),(4,4),(5,5); +select * from t1; +a b +1 1 +2 2 +3 3 +4 4 +5 5 +insert into t1 values(4,14),(5,15),(6,16),(7,17),(8,18) +on duplicate key update b=b+10; +affected rows: 7 +info: Records: 5 Duplicates: 2 Warnings: 0 +select * from t1; +a b +1 1 +2 2 +3 3 +4 14 +5 15 +6 16 +7 17 +8 18 +replace into t1 values(5,25),(6,26),(7,27),(8,28),(9,29); +affected rows: 9 +info: Records: 5 Duplicates: 4 Warnings: 0 +select * from t1 order by a; +a b +1 1 +2 2 +3 3 +4 14 +5 25 +6 26 +7 27 +8 28 +9 29 +drop table t1; +CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B)); +INSERT t1 VALUES (1,2,10), (3,4,20); +INSERT t1 SELECT 5,6,30 FROM DUAL ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1 order by a; +a b c +1 2 10 +3 4 20 +5 6 30 +INSERT t1 SELECT 5,7,40 FROM DUAL ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1 order by a; +a b c +1 2 10 +3 4 20 +5 6 130 +INSERT t1 SELECT 8,4,50 FROM DUAL ON DUPLICATE KEY UPDATE c=c+1000; +SELECT * FROM t1 order by a; +a b c +1 2 10 +3 4 1020 +5 6 130 +INSERT t1 SELECT 1,4,60 FROM DUAL ON DUPLICATE KEY UPDATE c=c+10000; +SELECT * FROM t1 order by a; +a b c +1 2 10010 +3 4 1020 +5 6 130 +INSERT t1 SELECT 1,9,70 FROM DUAL ON DUPLICATE KEY UPDATE c=c+100000, b=4; +ERROR 23000: Duplicate entry '4' for key 'b' +SELECT * FROM t1 order by a; +a b c +1 2 10010 +3 4 1020 +5 6 130 +TRUNCATE TABLE t1; +INSERT t1 VALUES (1,2,10), (3,4,20); +CREATE TABLE t2 (a INT, b INT, c INT, d INT); +INSERT t2 VALUES (5,6,30,1), (7,4,40,1), (8,9,60,1); +INSERT t2 VALUES (2,1,11,2), (7,4,40,2); +INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100; +SELECT * FROM t1; +a b c +1 2 10 +5 6 30 +3 4 120 +8 9 60 +INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0; +SELECT * FROM t1 order by a; +a b c +1 2 10 +3 4 120 +5 0 30 +8 9 60 +INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a); +ERROR 23000: Column 'c' in field list is ambiguous +INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a); +SELECT *, VALUES(a) FROM t1 order by a; +a b c VALUES(a) +1 2 10 NULL +2 1 11 NULL +3 4 127 NULL +5 0 30 NULL +8 9 60 NULL +DROP TABLE t1; +DROP TABLE t2; +create table t1 (a int not null unique) engine=myisam; +insert into t1 values (1),(2); +insert ignore into t1 select 1 on duplicate key update a=2; +select * from t1; +a +1 +2 +insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ; +select * from t1; +a +1 +3 +insert into t1 select 1 on duplicate key update a=2; +select * from t1; +a +2 +3 +insert into t1 select a from t1 on duplicate key update a=a+1 ; +ERROR 23000: Column 'a' in field list is ambiguous +insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; +ERROR 23000: Column 't1.a' in field list is ambiguous +drop table t1; +CREATE TABLE t1 ( +a BIGINT(20) NOT NULL DEFAULT 0, +PRIMARY KEY (a) +) ENGINE=MyISAM; +INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a) ; +DROP TABLE t1; +CREATE TABLE t1 +( +a BIGINT UNSIGNED, +b BIGINT UNSIGNED, +PRIMARY KEY (a) +); +INSERT INTO t1 VALUES (45, 1) ON DUPLICATE KEY UPDATE b = +IF(VALUES(b) > t1.b, VALUES(b), t1.b); +SELECT * FROM t1; +a b +45 1 +INSERT INTO t1 VALUES (45, 2) ON DUPLICATE KEY UPDATE b = +IF(VALUES(b) > t1.b, VALUES(b), t1.b); +SELECT * FROM t1; +a b +45 2 +INSERT INTO t1 VALUES (45, 1) ON DUPLICATE KEY UPDATE b = +IF(VALUES(b) > t1.b, VALUES(b), t1.b); +SELECT * FROM t1; +a b +45 2 +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/join.result b/mysql-test/suite/pbxt/r/join.result new file mode 100644 index 00000000000..3adcb4fd27a --- /dev/null +++ b/mysql-test/suite/pbxt/r/join.result @@ -0,0 +1,822 @@ +drop table if exists t1,t2,t3; +CREATE TABLE t1 (S1 INT); +CREATE TABLE t2 (S1 INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t1 JOIN t2; +S1 S1 +1 2 +SELECT * FROM t1 INNER JOIN t2; +S1 S1 +1 2 +SELECT * from t1 JOIN t2 USING (S1); +S1 +SELECT * FROM t1 INNER JOIN t2 USING (S1); +S1 +SELECT * from t1 CROSS JOIN t2; +S1 S1 +1 2 +SELECT * from t1 LEFT JOIN t2 USING(S1); +S1 +1 +SELECT * from t1 LEFT JOIN t2 ON(t2.S1=2); +S1 S1 +1 2 +SELECT * from t1 RIGHT JOIN t2 USING(S1); +S1 +2 +SELECT * from t1 RIGHT JOIN t2 ON(t1.S1=1); +S1 S1 +1 2 +drop table t1,t2; +create table t1 (id int primary key); +create table t2 (id int); +insert into t1 values (75); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +replace into t1 values (76); +replace into t1 values (76); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (105); +insert into t1 values (106); +insert into t1 values (107); +insert into t2 values (107),(75),(1000); +select t1.id, t2.id from t1, t2 where t2.id = t1.id; +id id +107 107 +75 75 +select t1.id, count(t2.id) from t1,t2 where t2.id = t1.id group by t1.id; +id count(t2.id) +75 1 +107 1 +select t1.id, count(t2.id) from t1,t2 where t2.id = t1.id group by t2.id; +id count(t2.id) +75 1 +107 1 +select t1.id,t2.id from t2 left join t1 on t1.id>=74 and t1.id<=0 where t2.id=75 and t1.id is null; +id id +NULL 75 +explain select t1.id,t2.id from t2 left join t1 on t1.id>=74 and t1.id<=0 where t2.id=75 and t1.id is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY NULL NULL NULL 1 Impossible ON condition +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where +explain select t1.id, t2.id from t1, t2 where t2.id = t1.id and t1.id <0 and t1.id > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +drop table t1,t2; +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +token varchar(100) DEFAULT '' NOT NULL, +count int(11) DEFAULT '0' NOT NULL, +qty int(11), +phone char(1) DEFAULT '' NOT NULL, +timestamp datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, +PRIMARY KEY (id), +KEY token (token(15)), +KEY timestamp (timestamp), +UNIQUE token_2 (token(75),count,phone) +); +INSERT INTO t1 VALUES (21,'e45703b64de71482360de8fec94c3ade',3,7800,'n','1999-12-23 17:22:21'); +INSERT INTO t1 VALUES (22,'e45703b64de71482360de8fec94c3ade',4,5000,'y','1999-12-23 17:22:21'); +INSERT INTO t1 VALUES (18,'346d1cb63c89285b2351f0ca4de40eda',3,13200,'b','1999-12-23 11:58:04'); +INSERT INTO t1 VALUES (17,'ca6ddeb689e1b48a04146b1b5b6f936a',4,15000,'b','1999-12-23 11:36:53'); +INSERT INTO t1 VALUES (16,'ca6ddeb689e1b48a04146b1b5b6f936a',3,13200,'b','1999-12-23 11:36:53'); +INSERT INTO t1 VALUES (26,'a71250b7ed780f6ef3185bfffe027983',5,1500,'b','1999-12-27 09:44:24'); +INSERT INTO t1 VALUES (24,'4d75906f3c37ecff478a1eb56637aa09',3,5400,'y','1999-12-23 17:29:12'); +INSERT INTO t1 VALUES (25,'4d75906f3c37ecff478a1eb56637aa09',4,6500,'y','1999-12-23 17:29:12'); +INSERT INTO t1 VALUES (27,'a71250b7ed780f6ef3185bfffe027983',3,6200,'b','1999-12-27 09:44:24'); +INSERT INTO t1 VALUES (28,'a71250b7ed780f6ef3185bfffe027983',3,5400,'y','1999-12-27 09:44:36'); +INSERT INTO t1 VALUES (29,'a71250b7ed780f6ef3185bfffe027983',4,17700,'b','1999-12-27 09:45:05'); +CREATE TABLE t2 ( +id int(11) NOT NULL auto_increment, +category int(11) DEFAULT '0' NOT NULL, +county int(11) DEFAULT '0' NOT NULL, +state int(11) DEFAULT '0' NOT NULL, +phones int(11) DEFAULT '0' NOT NULL, +nophones int(11) DEFAULT '0' NOT NULL, +PRIMARY KEY (id), +KEY category (category,county,state) +); +INSERT INTO t2 VALUES (3,2,11,12,5400,7800); +INSERT INTO t2 VALUES (4,2,25,12,6500,11200); +INSERT INTO t2 VALUES (5,1,37,6,10000,12000); +select a.id, b.category as catid, b.state as stateid, b.county as countyid from t1 a, t2 b ignore index (primary) where (a.token ='a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id); +id catid stateid countyid +27 2 12 11 +28 2 12 11 +29 2 12 25 +26 1 6 37 +select a.id, b.category as catid, b.state as stateid, b.county as +countyid from t1 a, t2 b where (a.token = +'a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id) order by a.id; +id catid stateid countyid +26 1 6 37 +27 2 12 11 +28 2 12 11 +29 2 12 25 +drop table t1, t2; +create table t1 (a int primary key); +insert into t1 values(1),(2); +select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +a +1 +2 +select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); +ERROR HY000: Too many tables; MySQL can only use XX tables in a join +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +a +1 +2 +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); +ERROR HY000: Too many tables; MySQL can only use XX tables in a join +drop table t1; +CREATE TABLE t1 ( +a int(11) NOT NULL, +b int(11) NOT NULL, +PRIMARY KEY (a,b) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(2,3); +CREATE TABLE t2 ( +a int(11) default NULL +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (2),(3); +SELECT t1.a,t2.a,b FROM t1,t2 WHERE t1.a=t2.a AND (t1.a=1 OR t1.a=2) AND b>=1 AND b<=3; +a a b +2 2 3 +DROP TABLE t1, t2; +CREATE TABLE t1 (d DATE NOT NULL); +CREATE TABLE t2 (d DATE NOT NULL); +INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00'); +SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL; +d +2001-08-01 +0000-00-00 +SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE d IS NULL; +d +0000-00-00 +SELECT * from t1 WHERE t1.d IS NULL; +d +0000-00-00 +SELECT * FROM t1 WHERE 1/0 IS NULL; +d +2001-08-01 +0000-00-00 +DROP TABLE t1,t2; +CREATE TABLE t1 ( +Document_ID varchar(50) NOT NULL default '', +Contractor_ID varchar(6) NOT NULL default '', +Language_ID char(3) NOT NULL default '', +Expiration_Date datetime default NULL, +Publishing_Date datetime default NULL, +Title text, +Column_ID varchar(50) NOT NULL default '', +PRIMARY KEY (Language_ID,Document_ID,Contractor_ID) +); +INSERT INTO t1 VALUES ('xep80','1','ger','2001-12-31 20:00:00','2001-11-12 10:58:00','Kartenbestellung - jetzt auch online','anle'),('','999998','',NULL,NULL,NULL,''); +CREATE TABLE t2 ( +Contractor_ID char(6) NOT NULL default '', +Language_ID char(3) NOT NULL default '', +Document_ID char(50) NOT NULL default '', +CanRead char(1) default NULL, +Customer_ID int(11) NOT NULL default '0', +PRIMARY KEY (Contractor_ID,Language_ID,Document_ID,Customer_ID) +); +INSERT INTO t2 VALUES ('5','ger','xep80','1',999999),('1','ger','xep80','1',999999); +CREATE TABLE t3 ( +Language_ID char(3) NOT NULL default '', +Column_ID char(50) NOT NULL default '', +Contractor_ID char(6) NOT NULL default '', +CanRead char(1) default NULL, +Active char(1) default NULL, +PRIMARY KEY (Language_ID,Column_ID,Contractor_ID) +); +INSERT INTO t3 VALUES ('ger','home','1','1','1'),('ger','Test','1','0','0'),('ger','derclu','1','0','0'),('ger','clubne','1','0','0'),('ger','philos','1','0','0'),('ger','clubko','1','0','0'),('ger','clubim','1','1','1'),('ger','progra','1','0','0'),('ger','progvo','1','0','0'),('ger','progsp','1','0','0'),('ger','progau','1','0','0'),('ger','progku','1','0','0'),('ger','progss','1','0','0'),('ger','nachl','1','0','0'),('ger','mitgli','1','0','0'),('ger','mitsu','1','0','0'),('ger','mitbus','1','0','0'),('ger','ergmar','1','1','1'),('ger','home','4','1','1'),('ger','derclu','4','1','1'),('ger','clubne','4','0','0'),('ger','philos','4','1','1'),('ger','clubko','4','1','1'),('ger','clubim','4','1','1'),('ger','progra','4','1','1'),('ger','progvo','4','1','1'),('ger','progsp','4','1','1'),('ger','progau','4','0','0'),('ger','progku','4','1','1'),('ger','progss','4','1','1'),('ger','nachl','4','1','1'),('ger','mitgli','4','0','0'),('ger','mitsu','4','0','0'),('ger','mitbus','4','0','0'),('ger','ergmar','4','1','1'),('ger','progra2','1','0','0'),('ger','archiv','4','1','1'),('ger','anmeld','4','1','1'),('ger','thema','4','1','1'),('ger','edito','4','1','1'),('ger','madis','4','1','1'),('ger','enma','4','1','1'),('ger','madis','1','1','1'),('ger','enma','1','1','1'),('ger','vorsch','4','0','0'),('ger','veranst','4','0','0'),('ger','anle','4','1','1'),('ger','redak','4','1','1'),('ger','nele','4','1','1'),('ger','aukt','4','1','1'),('ger','callcenter','4','1','1'),('ger','anle','1','0','0'); +delete from t1 where Contractor_ID='999998'; +insert into t1 (Contractor_ID) Values ('999998'); +SELECT DISTINCT COUNT(t1.Title) FROM t1, +t2, t3 WHERE +t1.Document_ID='xep80' AND t1.Contractor_ID='1' AND +t1.Language_ID='ger' AND '2001-12-21 23:14:24' >= +Publishing_Date AND '2001-12-21 23:14:24' <= Expiration_Date AND +t1.Document_ID = t2.Document_ID AND +t1.Language_ID = t2.Language_ID AND +t1.Contractor_ID = t2.Contractor_ID AND ( +t2.Customer_ID = '4' OR +t2.Customer_ID = '999999' OR +t2.Customer_ID = '1' )AND t2.CanRead += '1' AND t1.Column_ID=t3.Column_ID AND +t1.Language_ID=t3.Language_ID AND ( +t3.Contractor_ID = '4' OR +t3.Contractor_ID = '999999' OR +t3.Contractor_ID = '1') AND +t3.CanRead='1' AND t3.Active='1'; +COUNT(t1.Title) +1 +SELECT DISTINCT COUNT(t1.Title) FROM t1, +t2, t3 WHERE +t1.Document_ID='xep80' AND t1.Contractor_ID='1' AND +t1.Language_ID='ger' AND '2001-12-21 23:14:24' >= +Publishing_Date AND '2001-12-21 23:14:24' <= Expiration_Date AND +t1.Document_ID = t2.Document_ID AND +t1.Language_ID = t2.Language_ID AND +t1.Contractor_ID = t2.Contractor_ID AND ( +t2.Customer_ID = '4' OR +t2.Customer_ID = '999999' OR +t2.Customer_ID = '1' )AND t2.CanRead += '1' AND t1.Column_ID=t3.Column_ID AND +t1.Language_ID=t3.Language_ID AND ( +t3.Contractor_ID = '4' OR +t3.Contractor_ID = '999999' OR +t3.Contractor_ID = '1') AND +t3.CanRead='1' AND t3.Active='1'; +COUNT(t1.Title) +1 +drop table t1,t2,t3; +CREATE TABLE t1 ( +t1_id int(11) default NULL, +t2_id int(11) default NULL, +type enum('Cost','Percent') default NULL, +cost_unit enum('Cost','Unit') default NULL, +min_value double default NULL, +max_value double default NULL, +t3_id int(11) default NULL, +item_id int(11) default NULL +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (12,5,'Percent','Cost',-1,0,-1,-1),(14,4,'Percent','Cost',-1,0,-1,-1),(18,5,'Percent','Cost',-1,0,-1,-1),(19,4,'Percent','Cost',-1,0,-1,-1),(20,5,'Percent','Cost',100,-1,22,291),(21,5,'Percent','Cost',100,-1,18,291),(22,1,'Percent','Cost',100,-1,6,291),(23,1,'Percent','Cost',100,-1,21,291),(24,1,'Percent','Cost',100,-1,9,291),(25,1,'Percent','Cost',100,-1,4,291),(26,1,'Percent','Cost',100,-1,20,291),(27,4,'Percent','Cost',100,-1,7,202),(28,1,'Percent','Cost',50,-1,-1,137),(29,2,'Percent','Cost',100,-1,4,354),(30,2,'Percent','Cost',100,-1,9,137),(93,2,'Cost','Cost',-1,10000000,-1,-1); +CREATE TABLE t2 ( +id int(10) unsigned NOT NULL auto_increment, +name varchar(255) default NULL, +PRIMARY KEY (id) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,'s1'),(2,'s2'),(3,'s3'),(4,'s4'),(5,'s5'); +select t1.*, t2.* from t1, t2 where t2.id=t1.t2_id limit 2; +t1_id t2_id type cost_unit min_value max_value t3_id item_id id name +22 1 Percent Cost 100 -1 6 291 1 s1 +23 1 Percent Cost 100 -1 21 291 1 s1 +drop table t1,t2; +CREATE TABLE t1 ( +siteid varchar(25) NOT NULL default '', +emp_id varchar(30) NOT NULL default '', +rate_code varchar(10) default NULL, +UNIQUE KEY site_emp (siteid,emp_id), +KEY siteid (siteid) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('rivercats','psmith','cust'), ('rivercats','KWalker','cust'); +CREATE TABLE t2 ( +siteid varchar(25) NOT NULL default '', +rate_code varchar(10) NOT NULL default '', +base_rate float NOT NULL default '0', +PRIMARY KEY (siteid,rate_code), +FULLTEXT KEY rate_code (rate_code) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES ('rivercats','cust',20); +SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND lr.siteid = 'rivercats'; +rate_code base_rate +cust 20 +SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith'; +rate_code base_rate +cust 20 +SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND siteid = 'rivercats'; +rate_code base_rate +cust 20 +SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE siteid = 'rivercats' AND emp.emp_id = 'psmith'; +rate_code base_rate +cust 20 +drop table t1,t2; +CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, Value1 VARCHAR(255)); +CREATE TABLE t2 (ID INTEGER NOT NULL PRIMARY KEY, Value2 VARCHAR(255)); +INSERT INTO t1 VALUES (1, 'A'); +INSERT INTO t2 VALUES (1, 'B'); +SELECT * FROM t1 NATURAL JOIN t2 WHERE 1 AND (Value1 = 'A' AND Value2 <> 'B'); +ID Value1 Value2 +SELECT * FROM t1 NATURAL JOIN t2 WHERE 1 AND Value1 = 'A' AND Value2 <> 'B'; +ID Value1 Value2 +SELECT * FROM t1 NATURAL JOIN t2 WHERE (Value1 = 'A' AND Value2 <> 'B') AND 1; +ID Value1 Value2 +drop table t1,t2; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +CREATE TABLE t3 (c int); +SELECT * FROM t1 NATURAL JOIN t2 NATURAL JOIN t3; +a b c +DROP TABLE t1, t2, t3; +create table t1 (i int); +create table t2 (i int); +create table t3 (i int); +insert into t1 values(1),(2); +insert into t2 values(2),(3); +insert into t3 values (2),(4); +select * from t1 natural left join t2; +i +1 +2 +select * from t1 left join t2 on (t1.i=t2.i); +i i +1 NULL +2 2 +select * from t1 natural left join t2 natural left join t3; +i +1 +2 +select * from t1 left join t2 on (t1.i=t2.i) left join t3 on (t2.i=t3.i); +i i i +1 NULL NULL +2 2 2 +select * from t3 natural right join t2; +i +2 +3 +select * from t3 right join t2 on (t3.i=t2.i); +i i +2 2 +NULL 3 +select * from t3 natural right join t2 natural right join t1; +i +1 +2 +select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i); +i i i +NULL NULL 1 +2 2 2 +select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i; +i i +1 2 +1 3 +2 2 +2 3 +select * from t1,t2 left join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; +i i i +1 2 2 +1 3 NULL +2 2 2 +2 3 NULL +select t1.i,t2.i,t3.i from t2 natural left join t3,t1 order by t1.i,t2.i,t3.i; +i i i +1 2 2 +1 3 NULL +2 2 2 +2 3 NULL +select t1.i,t2.i,t3.i from t2 left join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; +i i i +1 2 2 +1 3 NULL +2 2 2 +2 3 NULL +select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i; +i i +1 4 +1 2 +2 4 +2 2 +select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; +i i i +1 NULL 4 +1 2 2 +2 NULL 4 +2 2 2 +select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; +i i i +1 NULL 4 +1 2 2 +2 NULL 4 +2 2 2 +select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; +i i i +1 NULL 4 +1 2 2 +2 NULL 4 +2 2 2 +drop table t1,t2,t3; +create table t1 (c int, b int); +create table t2 (a int, b int); +create table t3 (b int, c int); +create table t4 (y int, c int); +create table t5 (y int, z int); +create table t6 (a int, c int); +insert into t1 values (10,1); +insert into t1 values (3 ,1); +insert into t1 values (3 ,2); +insert into t2 values (2, 1); +insert into t3 values (1, 3); +insert into t3 values (1,10); +insert into t4 values (11,3); +insert into t4 values (2, 3); +insert into t5 values (11,4); +insert into t6 values (2, 3); +create algorithm=merge view v1a as +select * from t1 natural join t2; +create algorithm=merge view v1b(a,b,c) as +select * from t1 natural join t2; +create algorithm=merge view v1c as +select b as a, c as b, a as c from t1 natural join t2; +create algorithm=merge view v1d(b, a, c) as +select a as c, c as b, b as a from t1 natural join t2; +create algorithm=merge view v2a as +select t1.c, t1.b, t2.a from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c; +create algorithm=merge view v2b as +select t1.c as b, t1.b as a, t2.a as c +from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c; +create algorithm=merge view v3a as +select * from t1 natural join t2 natural join t3; +create algorithm=merge view v3b as +select * from t1 natural join (t2 natural join t3); +create algorithm=merge view v4 as +select * from v2a natural join v3a; +select * from (t1 natural join t2) natural join (t3 natural join t4); +b c a y +1 3 2 11 +1 3 2 2 +select * from (t1 natural join t2) natural left join (t3 natural join t4); +b c a y +1 10 2 NULL +1 3 2 11 +1 3 2 2 +select * from (t3 natural join t4) natural right join (t1 natural join t2); +b c a y +1 10 2 NULL +1 3 2 11 +1 3 2 2 +select * from (t1 natural left join t2) natural left join (t3 natural left join t4); +b c a y +1 10 2 NULL +1 3 2 11 +1 3 2 2 +2 3 NULL NULL +select * from (t4 natural right join t3) natural right join (t2 natural right join t1); +b c a y +1 10 2 NULL +1 3 2 11 +1 3 2 2 +2 3 NULL NULL +select * from t1 natural join t2 natural join t3 natural join t4; +c b a y +3 1 2 11 +3 1 2 2 +select * from ((t1 natural join t2) natural join t3) natural join t4; +c b a y +3 1 2 11 +3 1 2 2 +select * from t1 natural join (t2 natural join (t3 natural join t4)); +c b a y +3 1 2 11 +3 1 2 2 +select * from t5 natural right join (t4 natural right join ((t2 natural right join t1) natural right join t3)); +y c b a z +11 3 1 2 4 +2 3 1 2 NULL +NULL 10 1 2 NULL +select * from (t1 natural join t2), (t3 natural join t4); +b c a c b y +1 10 2 3 1 11 +1 10 2 3 1 2 +1 3 2 3 1 11 +1 3 2 3 1 2 +select * from t5 natural join ((t1 natural join t2), (t3 natural join t4)); +y z b c a c b +11 4 1 10 2 3 1 +11 4 1 3 2 3 1 +select * from ((t1 natural join t2), (t3 natural join t4)) natural join t5; +y b c a c b z +11 1 10 2 3 1 4 +11 1 3 2 3 1 4 +select * from t5 natural join ((t1 natural join t2) cross join (t3 natural join t4)); +y z b c a c b +11 4 1 10 2 3 1 +11 4 1 3 2 3 1 +select * from ((t1 natural join t2) cross join (t3 natural join t4)) natural join t5; +y b c a c b z +11 1 10 2 3 1 4 +11 1 3 2 3 1 4 +select * from (t1 join t2 using (b)) join (t3 join t4 using (c)) using (c); +c b a b y +3 1 2 1 11 +3 1 2 1 2 +select * from (t1 join t2 using (b)) natural join (t3 join t4 using (c)); +b c a y +1 3 2 11 +1 3 2 2 +select a,b,c from (t1 natural join t2) natural join (t3 natural join t4) +where b + 1 = y or b + 10 = y group by b,c,a having min(b) < max(y) order by a; +a b c +2 1 3 +select * from (t1 natural join t2) natural left join (t3 natural join t4) +where b + 1 = y or b + 10 = y group by b,c,a,y having min(b) < max(y) order by a, y; +b c a y +1 3 2 2 +1 3 2 11 +select * from (t3 natural join t4) natural right join (t1 natural join t2) +where b + 1 = y or b + 10 = y group by b,c,a,y having min(b) < max(y) order by a, y; +b c a y +1 3 2 2 +1 3 2 11 +select * from t1 natural join t2 where t1.c > t2.a; +b c a +1 10 2 +1 3 2 +select * from t1 natural join t2 where t1.b > t2.b; +b c a +select * from t1 natural left join (t4 natural join t5) where t5.z is not NULL; +c b y z +3 1 11 4 +3 2 11 4 +select * from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c; +c b a b y c +3 1 2 1 2 3 +3 2 2 1 2 3 +select * from (t2 join t4 on b + 1 = y) join t1 on t1.c = t4.c; +a b y c c b +2 1 2 3 3 1 +2 1 2 3 3 2 +select * from t1 natural join (t2 join t4 on b + 1 = y); +c b a y +3 1 2 2 +select * from (t1 cross join t2) join (t3 cross join t4) on (a < y and t2.b < t3.c); +c b a b b c y c +10 1 2 1 1 3 11 3 +10 1 2 1 1 10 11 3 +3 1 2 1 1 3 11 3 +3 1 2 1 1 10 11 3 +3 2 2 1 1 3 11 3 +3 2 2 1 1 10 11 3 +select * from (t1, t2) join (t3, t4) on (a < y and t2.b < t3.c); +c b a b b c y c +10 1 2 1 1 3 11 3 +10 1 2 1 1 10 11 3 +3 1 2 1 1 3 11 3 +3 1 2 1 1 10 11 3 +3 2 2 1 1 3 11 3 +3 2 2 1 1 10 11 3 +select * from (t1 natural join t2) join (t3 natural join t4) on a = y; +b c a c b y +1 10 2 3 1 2 +1 3 2 3 1 2 +select * from ((t3 join (t1 join t2 on c > a) on t3.b < t2.a) join t4 on y > t1.c) join t5 on z = t1.b + 3; +b c c b a b y c y z +1 3 10 1 2 1 11 3 11 4 +1 10 10 1 2 1 11 3 11 4 +1 3 3 1 2 1 11 3 11 4 +1 10 3 1 2 1 11 3 11 4 +select * from t1 natural join t2 where t1.b > 0; +b c a +1 10 2 +1 3 2 +select * from t1 natural join (t4 natural join t5) where t4.y > 7; +c b y z +3 1 11 4 +3 2 11 4 +select * from (t4 natural join t5) natural join t1 where t4.y > 7; +c y z b +3 11 4 1 +3 11 4 2 +select * from t1 natural left join (t4 natural join t5) where t4.y > 7; +c b y z +3 1 11 4 +3 2 11 4 +select * from (t4 natural join t5) natural right join t1 where t4.y > 7; +c b y z +3 1 11 4 +3 2 11 4 +select * from (t1 natural join t2) join (t3 natural join t4) on t1.b = t3.b; +b c a c b y +1 10 2 3 1 11 +1 10 2 3 1 2 +1 3 2 3 1 11 +1 3 2 3 1 2 +select t1.*, t2.* from t1 natural join t2; +c b a b +10 1 2 1 +3 1 2 1 +select t1.*, t2.*, t3.*, t4.* from (t1 natural join t2) natural join (t3 natural join t4); +c b a b b c y c +3 1 2 1 1 3 11 3 +3 1 2 1 1 3 2 3 +select * from (select * from t1 natural join t2) as t12 +natural join +(select * from t3 natural join t4) as t34; +b c a y +1 3 2 11 +1 3 2 2 +select * from (select * from t1 natural join t2) as t12 +natural left join +(select * from t3 natural join t4) as t34; +b c a y +1 10 2 NULL +1 3 2 11 +1 3 2 2 +select * from (select * from t3 natural join t4) as t34 +natural right join +(select * from t1 natural join t2) as t12; +b c a y +1 10 2 NULL +1 3 2 11 +1 3 2 2 +select * from v1a; +b c a +1 10 2 +1 3 2 +select * from v1b; +a b c +1 10 2 +1 3 2 +select * from v1c; +a b c +1 10 2 +1 3 2 +select * from v1d; +b a c +2 10 1 +2 3 1 +select * from v2a; +c b a +3 1 2 +3 2 2 +select * from v2b; +b a c +3 1 2 +3 2 2 +select * from v3a; +b c a +1 10 2 +1 3 2 +select * from v3b; +c b a +10 1 2 +3 1 2 +select * from v4; +c b a +3 1 2 +select * from v1a natural join v2a; +b c a +1 3 2 +select v2a.* from v1a natural join v2a; +c b a +3 1 2 +select * from v1b join v2a on v1b.b = v2a.c; +a b c c b a +1 3 2 3 1 2 +1 3 2 3 2 2 +select * from v1c join v2a on v1c.b = v2a.c; +a b c c b a +1 3 2 3 1 2 +1 3 2 3 2 2 +select * from v1d join v2a on v1d.a = v2a.c; +b a c c b a +2 3 1 3 1 2 +2 3 1 3 2 2 +select * from v1a join (t3 natural join t4) on a = y; +b c a c b y +1 10 2 3 1 2 +1 3 2 3 1 2 +select * from t1 natural join (t3 cross join t4); +ERROR 23000: Column 'c' in from clause is ambiguous +select * from (t3 cross join t4) natural join t1; +ERROR 23000: Column 'c' in from clause is ambiguous +select * from t1 join (t2, t3) using (b); +ERROR 23000: Column 'b' in from clause is ambiguous +select * from ((t1 natural join t2), (t3 natural join t4)) natural join t6; +ERROR 23000: Column 'c' in from clause is ambiguous +select * from ((t1 natural join t2), (t3 natural join t4)) natural join t6; +ERROR 23000: Column 'c' in from clause is ambiguous +select * from t6 natural join ((t1 natural join t2), (t3 natural join t4)); +ERROR 23000: Column 'c' in from clause is ambiguous +select * from (t1 join t2 on t1.b=t2.b) natural join (t3 natural join t4); +ERROR 23000: Column 'b' in from clause is ambiguous +select * from (t3 natural join t4) natural join (t1 join t2 on t1.b=t2.b); +ERROR 23000: Column 'b' in from clause is ambiguous +select * from (t3 join (t4 natural join t5) on (b < z)) +natural join +(t1 natural join t2); +ERROR 23000: Column 'c' in from clause is ambiguous +select * from (t1 natural join t2) natural join (t3 join (t4 natural join t5) on (b < z)); +ERROR 23000: Column 'c' in from clause is ambiguous +select t1.b from v1a; +ERROR 42S22: Unknown column 't1.b' in 'field list' +select * from v1a join v1b on t1.b = t2.b; +ERROR 42S22: Unknown column 't1.b' in 'on clause' +select * from information_schema.statistics join information_schema.columns +using(table_name,column_name) where table_name='user'; +TABLE_NAME COLUMN_NAME TABLE_CATALOG TABLE_SCHEMA NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT TABLE_CATALOG TABLE_SCHEMA ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT +user Host NULL mysql 0 mysql PRIMARY 1 A NULL NULL NULL BTREE NULL mysql 1 NO char 60 180 NULL NULL utf8 utf8_bin char(60) PRI # +user User NULL mysql 0 mysql PRIMARY 2 A 3 NULL NULL BTREE NULL mysql 2 NO char 16 48 NULL NULL utf8 utf8_bin char(16) PRI # +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; +drop table t6; +drop view v1a; +drop view v1b; +drop view v1c; +drop view v1d; +drop view v2a; +drop view v2b; +drop view v3a; +drop view v3b; +drop view v4; +create table t1 (a1 int, a2 int); +create table t2 (a1 int, b int); +create table t3 (c1 int, c2 int); +create table t4 (c2 int); +insert into t1 values (1,1); +insert into t2 values (1,1); +insert into t3 values (1,1); +insert into t4 values (1); +select * from t1 join t2 using (a1) join t3 on b=c1 join t4 using (c2); +c2 a1 a2 b c1 +1 1 1 1 1 +select * from t3 join (t1 join t2 using (a1)) on b=c1 join t4 using (c2); +c2 c1 a1 a2 b +1 1 1 1 1 +select a2 from t1 join t2 using (a1) join t3 on b=c1 join t4 using (c2); +a2 +1 +select a2 from t3 join (t1 join t2 using (a1)) on b=c1 join t4 using (c2); +a2 +1 +select a2 from ((t1 join t2 using (a1)) join t3 on b=c1) join t4 using (c2); +a2 +1 +select a2 from ((t1 natural join t2) join t3 on b=c1) natural join t4; +a2 +1 +drop table t1,t2,t3,t4; +create table t1 (c int, b int); +create table t2 (a int, b int); +create table t3 (b int, c int); +create table t4 (y int, c int); +create table t5 (y int, z int); +insert into t1 values (3,2); +insert into t2 values (1,2); +insert into t3 values (2,3); +insert into t4 values (1,3); +insert into t5 values (1,4); +prepare stmt1 from "select * from ((t3 natural join (t1 natural join t2)) +natural join t4) natural join t5"; +execute stmt1; +y c b a z +1 3 2 1 4 +select * from ((t3 natural join (t1 natural join t2)) natural join t4) +natural join t5; +y c b a z +1 3 2 1 4 +drop table t1, t2, t3, t4, t5; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, filler char(100), key(a), key(b)); +create table t3 (a int, b int, filler char(100), key(a), key(b)); +insert into t2 +select @a:= A.a + 10*(B.a + 10*C.a), @a, 'filler' from t1 A, t1 B, t1 C; +insert into t3 select * from t2 where a < 800; +explain select * from t2,t3 where t2.a < 200 and t2.b=t3.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a,b a 5 NULL 1 Using where +1 SIMPLE t3 ref b b 5 test.t2.b 11 Using where +drop table t1, t2, t3; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, primary key(a)); +insert into t2 select @v:=A.a+10*B.a, @v from t1 A, t1 B; +explain select * from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 +show status like '%cost%'; +Variable_name Value +Last_query_cost 4.262158 +select 'The cost of accessing t1 (dont care if it changes' '^'; +The cost of accessing t1 (dont care if it changes +The cost of accessing t1 (dont care if it changes^ +select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z; +Z +vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv +explain select * from t1, t2 A, t2 B where A.a = t1.a and B.a=A.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 +1 SIMPLE A eq_ref PRIMARY PRIMARY 4 test.t1.a 1 +1 SIMPLE B eq_ref PRIMARY PRIMARY 4 test.A.b 1 +show status like '%cost%'; +Variable_name Value +Last_query_cost 24.262158 +select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z; +Z +^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error +drop table t1, t2; +CREATE TABLE t1 (ID INTEGER, Name VARCHAR(50)); +CREATE TABLE t2 (Test_ID INTEGER); +CREATE VIEW v1 (Test_ID, Description) AS SELECT ID, Name FROM t1; +CREATE TABLE tv1 SELECT Description AS Name FROM v1 JOIN t2 +USING (Test_ID); +DESCRIBE tv1; +Field Type Null Key Default Extra +Name varchar(50) YES NULL +CREATE TABLE tv2 SELECT Description AS Name FROM v1 JOIN t2 +ON v1.Test_ID = t2.Test_ID; +DESCRIBE tv2; +Field Type Null Key Default Extra +Name varchar(50) YES NULL +DROP VIEW v1; +DROP TABLE t1,t2,tv1,tv2; +End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/r/join_crash.result b/mysql-test/suite/pbxt/r/join_crash.result new file mode 100644 index 00000000000..f1a3b4956a8 --- /dev/null +++ b/mysql-test/suite/pbxt/r/join_crash.result @@ -0,0 +1,103 @@ +DROP TABLE IF EXISTS t1,t2,t3,t4; +CREATE TABLE t1 ( +project_id int(11) NOT NULL auto_increment, +project_row_lock int(11) NOT NULL default '0', +project_name varchar(80) NOT NULL default '', +client_ptr int(11) NOT NULL default '0', +project_contact_ptr int(11) default NULL, +client_contact_ptr int(11) default NULL, +billing_contact_ptr int(11) default NULL, +comments mediumtext, +PRIMARY KEY (project_id), +UNIQUE KEY project (client_ptr,project_name) +) ENGINE=MyISAM PACK_KEYS=1; +INSERT INTO t1 VALUES (1,0,'Rejected Time',1,NULL,NULL,NULL,NULL); +INSERT INTO t1 VALUES (209,0,'MDGRAD Proposal/Investigation',97,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (208,0,'Font 9 Design',84,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (207,0,'Web Based Order Processing',95,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (205,0,'Mac Screen Saver',95,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (206,0,'Web Site',96,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (204,0,'Magnafire Glue',94,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (203,0,'Print Bid',93,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (202,0,'EPOC Port',92,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (201,0,'TravelMate',88,NULL,NULL,NULL,''); +CREATE TABLE t2 ( +period_id int(11) NOT NULL auto_increment, +period_type enum('user_table','client_table','role_table','member_table','project_table') default NULL, +period_key int(11) default NULL, +start_date datetime default NULL, +end_date datetime default NULL, +work_load int(11) default NULL, +PRIMARY KEY (period_id), +KEY period_index (period_type,period_key), +KEY date_index (start_date,end_date) +) ENGINE=MyISAM PACK_KEYS=1; +INSERT INTO t2 VALUES (1,'user_table',98,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (2,'user_table',99,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (3,'user_table',100,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (49,'project_table',148,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (50,'client_table',68,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (51,'project_table',149,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (52,'project_table',150,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (53,'client_table',69,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (54,'project_table',151,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (55,'client_table',70,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (155,'role_table',1,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (156,'role_table',2,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (160,'member_table',1,'2000-01-01 00:00:00',NULL,1); +INSERT INTO t2 VALUES (161,'member_table',2,'2000-01-01 00:00:00',NULL,1); +INSERT INTO t2 VALUES (162,'member_table',3,'2000-01-01 00:00:00',NULL,1); +CREATE TABLE t3 ( +budget_id int(11) NOT NULL auto_increment, +project_ptr int(11) NOT NULL default '0', +po_number varchar(20) NOT NULL default '', +status enum('open','closed') default NULL, +date_received datetime default NULL, +amount_received float(10,2) default NULL, +adjustment float(10,2) default NULL, +PRIMARY KEY (budget_id), +UNIQUE KEY po (project_ptr,po_number) +) ENGINE=MyISAM PACK_KEYS=1; +CREATE TABLE t4 ( +client_id int(11) NOT NULL auto_increment, +client_row_lock int(11) NOT NULL default '0', +client_name varchar(80) NOT NULL default '', +contact_ptr int(11) default NULL, +comments mediumtext, +PRIMARY KEY (client_id), +UNIQUE KEY client_name (client_name) +) ENGINE=MyISAM PACK_KEYS=1; +INSERT INTO t4 VALUES (1,0,'CPS',NULL,NULL); +select distinct +t1.project_id as project_id, +t1.project_name as project_name, +t1.client_ptr as client_ptr, +t1.comments as comments, +sum( t3.amount_received ) + sum( t3.adjustment ) as total_budget +from +t2 as client_period , +t2 as project_period, +t3 left join t1 on (t3.project_ptr = t1.project_id and +t3.date_received <= '2001-03-22 14:15:09') +left join t4 on t4.client_id = t1.client_ptr +where +1 +and ( client_period.period_type = 'client_table' + and client_period.period_key = t4.client_id +and ( client_period.start_date <= '2001-03-22 14:15:09' or isnull( client_period.start_date )) +and ( client_period.end_date > '2001-03-21 14:15:09' or isnull( client_period.end_date )) +) +and ( project_period.period_type = 'project_table' + and project_period.period_key = t1.project_id +and ( project_period.start_date <= '2001-03-22 14:15:09' or isnull( project_period.start_date )) +and ( project_period.end_date > '2001-03-21 14:15:09' or isnull( project_period.end_date )) ) +group by +client_id, +project_id , +client_period.period_id , +project_period.period_id +order by +client_name asc, +project_name asc; +project_id project_name client_ptr comments total_budget +DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/suite/pbxt/r/join_nested.result b/mysql-test/suite/pbxt/r/join_nested.result new file mode 100644 index 00000000000..a2a2bc6299f --- /dev/null +++ b/mysql-test/suite/pbxt/r/join_nested.result @@ -0,0 +1,1613 @@ +DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; +CREATE TABLE t0 (a int, b int, c int); +CREATE TABLE t1 (a int, b int, c int); +CREATE TABLE t2 (a int, b int, c int); +CREATE TABLE t3 (a int, b int, c int); +CREATE TABLE t4 (a int, b int, c int); +CREATE TABLE t5 (a int, b int, c int); +CREATE TABLE t6 (a int, b int, c int); +CREATE TABLE t7 (a int, b int, c int); +CREATE TABLE t8 (a int, b int, c int); +CREATE TABLE t9 (a int, b int, c int); +INSERT INTO t0 VALUES (1,1,0), (1,2,0), (2,2,0); +INSERT INTO t1 VALUES (1,3,0), (2,2,0), (3,2,0); +INSERT INTO t2 VALUES (3,3,0), (4,2,0), (5,3,0); +INSERT INTO t3 VALUES (1,2,0), (2,2,0); +INSERT INTO t4 VALUES (3,2,0), (4,2,0); +INSERT INTO t5 VALUES (3,1,0), (2,2,0), (3,3,0); +INSERT INTO t6 VALUES (3,2,0), (6,2,0), (6,1,0); +INSERT INTO t7 VALUES (1,1,0), (2,2,0); +INSERT INTO t8 VALUES (0,2,0), (1,2,0); +INSERT INTO t9 VALUES (1,1,0), (1,2,0), (3,3,0); +SELECT t2.a,t2.b +FROM t2; +a b +3 3 +4 2 +5 3 +SELECT t3.a,t3.b +FROM t3; +a b +1 2 +2 2 +SELECT t4.a,t4.b +FROM t4; +a b +3 2 +4 2 +SELECT t3.a,t3.b,t4.a,t4.b +FROM t3,t4; +a b a b +1 2 3 2 +2 2 3 2 +1 2 4 2 +2 2 4 2 +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t2.b=t4.b; +a b a b a b +3 3 NULL NULL NULL NULL +4 2 1 2 3 2 +4 2 1 2 4 2 +4 2 2 2 3 2 +4 2 2 2 4 2 +5 3 NULL NULL NULL NULL +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b; +a b a b a b +3 3 NULL NULL NULL NULL +4 2 1 2 3 2 +4 2 1 2 4 2 +5 3 NULL NULL NULL NULL +EXPLAIN EXTENDED +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t2.b=t4.b +WHERE t3.a=1 OR t3.c IS NULL; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t2` left join (`test`.`t3` join `test`.`t4`) on((`test`.`t4`.`b` = `test`.`t2`.`b`)) where ((`test`.`t3`.`a` = 1) or isnull(`test`.`t3`.`c`)) +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t2.b=t4.b +WHERE t3.a=1 OR t3.c IS NULL; +a b a b a b +3 3 NULL NULL NULL NULL +4 2 1 2 3 2 +4 2 1 2 4 2 +5 3 NULL NULL NULL NULL +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t2.b=t4.b +WHERE t3.a>1 OR t3.c IS NULL; +a b a b a b +3 3 NULL NULL NULL NULL +4 2 2 2 3 2 +4 2 2 2 4 2 +5 3 NULL NULL NULL NULL +SELECT t5.a,t5.b +FROM t5; +a b +3 1 +2 2 +3 3 +SELECT t3.a,t3.b,t4.a,t4.b,t5.a,t5.b +FROM t3,t4,t5; +a b a b a b +1 2 3 2 3 1 +2 2 3 2 3 1 +1 2 4 2 3 1 +2 2 4 2 3 1 +1 2 3 2 2 2 +2 2 3 2 2 2 +1 2 4 2 2 2 +2 2 4 2 2 2 +1 2 3 2 3 3 +2 2 3 2 3 3 +1 2 4 2 3 3 +2 2 4 2 3 3 +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b +FROM t2 +LEFT JOIN +(t3, t4, t5) +ON t2.b=t4.b; +a b a b a b a b +3 3 NULL NULL NULL NULL NULL NULL +4 2 1 2 3 2 3 1 +4 2 1 2 3 2 2 2 +4 2 1 2 3 2 3 3 +4 2 1 2 4 2 3 1 +4 2 1 2 4 2 2 2 +4 2 1 2 4 2 3 3 +4 2 2 2 3 2 3 1 +4 2 2 2 3 2 2 2 +4 2 2 2 3 2 3 3 +4 2 2 2 4 2 3 1 +4 2 2 2 4 2 2 2 +4 2 2 2 4 2 3 3 +5 3 NULL NULL NULL NULL NULL NULL +EXPLAIN EXTENDED +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b +FROM t2 +LEFT JOIN +(t3, t4, t5) +ON t2.b=t4.b +WHERE t3.a>1 OR t3.c IS NULL; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t5 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b` from `test`.`t2` left join (`test`.`t3` join `test`.`t4` join `test`.`t5`) on((`test`.`t4`.`b` = `test`.`t2`.`b`)) where ((`test`.`t3`.`a` > 1) or isnull(`test`.`t3`.`c`)) +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b +FROM t2 +LEFT JOIN +(t3, t4, t5) +ON t2.b=t4.b +WHERE t3.a>1 OR t3.c IS NULL; +a b a b a b a b +3 3 NULL NULL NULL NULL NULL NULL +4 2 2 2 3 2 3 1 +4 2 2 2 3 2 2 2 +4 2 2 2 3 2 3 3 +4 2 2 2 4 2 3 1 +4 2 2 2 4 2 2 2 +4 2 2 2 4 2 3 3 +5 3 NULL NULL NULL NULL NULL NULL +EXPLAIN EXTENDED +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b +FROM t2 +LEFT JOIN +(t3, t4, t5) +ON t2.b=t4.b +WHERE (t3.a>1 OR t3.c IS NULL) AND +(t5.a<3 OR t5.c IS NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t5 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b` from `test`.`t2` left join (`test`.`t3` join `test`.`t4` join `test`.`t5`) on((`test`.`t4`.`b` = `test`.`t2`.`b`)) where (((`test`.`t3`.`a` > 1) or isnull(`test`.`t3`.`c`)) and ((`test`.`t5`.`a` < 3) or isnull(`test`.`t5`.`c`))) +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b +FROM t2 +LEFT JOIN +(t3, t4, t5) +ON t2.b=t4.b +WHERE (t3.a>1 OR t3.c IS NULL) AND +(t5.a<3 OR t5.c IS NULL); +a b a b a b a b +3 3 NULL NULL NULL NULL NULL NULL +4 2 2 2 3 2 2 2 +4 2 2 2 4 2 2 2 +5 3 NULL NULL NULL NULL NULL NULL +SELECT t6.a,t6.b +FROM t6; +a b +3 2 +6 2 +6 1 +SELECT t7.a,t7.b +FROM t7; +a b +1 1 +2 2 +SELECT t6.a,t6.b,t7.a,t7.b +FROM t6,t7; +a b a b +3 2 1 1 +3 2 2 2 +6 2 1 1 +6 2 2 2 +6 1 1 1 +6 1 2 2 +SELECT t8.a,t8.b +FROM t8; +a b +0 2 +1 2 +EXPLAIN EXTENDED +SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM (t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t7 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using join buffer +1 SIMPLE t8 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select `test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b` from `test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t7`.`b` = `test`.`t8`.`b`) and (`test`.`t6`.`b` < 10))) where 1 +SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM (t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10; +a b a b a b +3 2 1 1 NULL NULL +3 2 2 2 0 2 +3 2 2 2 1 2 +6 2 1 1 NULL NULL +6 2 2 2 0 2 +6 2 2 2 1 2 +6 1 1 1 NULL NULL +6 1 2 2 0 2 +6 1 2 2 1 2 +SELECT t5.a,t5.b +FROM t5; +a b +3 1 +2 2 +3 3 +SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b; +a b a b a b a b +3 1 3 2 1 1 NULL NULL +3 1 6 2 1 1 NULL NULL +2 2 3 2 2 2 0 2 +2 2 3 2 2 2 1 2 +2 2 6 2 2 2 0 2 +2 2 6 2 2 2 1 2 +3 3 NULL NULL NULL NULL NULL NULL +SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b AND +(t8.a < 1 OR t8.c IS NULL); +a b a b a b a b +3 1 3 2 1 1 NULL NULL +3 1 6 2 1 1 NULL NULL +2 2 3 2 2 2 0 2 +2 2 6 2 2 2 0 2 +3 3 NULL NULL NULL NULL NULL NULL +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b; +a b a b a b +3 3 NULL NULL NULL NULL +4 2 1 2 3 2 +4 2 1 2 4 2 +5 3 NULL NULL NULL NULL +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b; +a b a b a b a b a b a b a b +3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL +4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL +4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL +4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL +5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +4 2 1 2 3 2 2 2 3 2 2 2 0 2 +4 2 1 2 3 2 2 2 3 2 2 2 1 2 +4 2 1 2 3 2 2 2 6 2 2 2 0 2 +4 2 1 2 3 2 2 2 6 2 2 2 1 2 +4 2 1 2 4 2 2 2 3 2 2 2 0 2 +4 2 1 2 4 2 2 2 3 2 2 2 1 2 +4 2 1 2 4 2 2 2 6 2 2 2 0 2 +4 2 1 2 4 2 2 2 6 2 2 2 1 2 +5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL +4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL +5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +WHERE t2.a > 3 AND +(t6.a < 6 OR t6.c IS NULL); +a b a b a b a b a b a b a b +4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL +4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL +5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +4 2 1 2 3 2 2 2 3 2 2 2 0 2 +4 2 1 2 3 2 2 2 3 2 2 2 1 2 +4 2 1 2 4 2 2 2 3 2 2 2 0 2 +4 2 1 2 4 2 2 2 3 2 2 2 1 2 +5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL +4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL +5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +SELECT t1.a,t1.b +FROM t1; +a b +1 3 +2 2 +3 2 +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2); +a b a b a b a b a b a b a b a b +1 3 3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +1 3 3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +1 3 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +1 3 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +1 3 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +1 3 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +1 3 3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +1 3 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL +1 3 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL +1 3 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL +1 3 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL +1 3 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL +1 3 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL +1 3 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +1 3 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +1 3 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL +3 2 3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +3 2 3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +3 2 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +3 2 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +3 2 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +3 2 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +3 2 3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL +3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL +3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2 +3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2 +3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 +3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2 +3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL +3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL +3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL +3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2 +3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2 +3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 +3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2 +3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL +3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2) +WHERE (t2.a >= 4 OR t2.c IS NULL); +a b a b a b a b a b a b a b a b +1 3 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL +1 3 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL +1 3 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL +1 3 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL +1 3 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL +1 3 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL +1 3 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +1 3 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +1 3 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL +3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL +3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL +3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2 +3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2 +3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 +3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2 +3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL +3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL +3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL +3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2 +3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2 +3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 +3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2 +3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL +3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +SELECT t0.a,t0.b +FROM t0; +a b +1 1 +1 2 +2 2 +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2) +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t5 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t7 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t8 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) where ((`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`))) +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2) +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL); +a b a b a b a b a b a b a b a b a b +1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL +1 2 3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL +1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL +1 2 3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2 +1 2 3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2 +1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 +1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2 +1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL +1 2 3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL +1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL +1 2 3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2 +1 2 3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2 +1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 +1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2 +1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL +1 2 3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL +1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL +1 2 3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2 +1 2 3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2 +1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 +1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2 +1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2), +t9 +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL) AND +(t3.a < 5 OR t3.c IS NULL) AND +(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND +(t5.a >=2 OR t5.c IS NULL) AND +(t6.a >=4 OR t6.c IS NULL) AND +(t7.a <= 2 OR t7.c IS NULL) AND +(t8.a < 1 OR t8.c IS NULL) AND +(t8.b=t9.b OR t8.c IS NULL) AND +(t9.a=1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t5 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t7 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t8 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +Warnings: +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`))) +SELECT t9.a,t9.b +FROM t9; +a b +1 1 +1 2 +3 3 +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2), +t9 +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL) AND +(t3.a < 5 OR t3.c IS NULL) AND +(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND +(t5.a >=2 OR t5.c IS NULL) AND +(t6.a >=4 OR t6.c IS NULL) AND +(t7.a <= 2 OR t7.c IS NULL) AND +(t8.a < 1 OR t8.c IS NULL) AND +(t8.b=t9.b OR t8.c IS NULL) AND +(t9.a=1); +a b a b a b a b a b a b a b a b a b a b +1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 1 +1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 1 +1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 1 +1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 1 +1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 1 +1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 1 +1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 1 +1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 2 +1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 2 +1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 1 2 +1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 2 +1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 2 +1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 1 2 +1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 2 +1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 2 +1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 1 2 +1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 2 +SELECT t1.a,t1.b +FROM t1; +a b +1 3 +2 2 +3 2 +SELECT t2.a,t2.b +FROM t2; +a b +3 3 +4 2 +5 3 +SELECT t3.a,t3.b +FROM t3; +a b +1 2 +2 2 +SELECT t2.a,t2.b,t3.a,t3.b +FROM t2 +LEFT JOIN +t3 +ON t2.b=t3.b; +a b a b +3 3 NULL NULL +4 2 1 2 +4 2 2 2 +5 3 NULL NULL +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b +FROM t1, t2 +LEFT JOIN +t3 +ON t2.b=t3.b +WHERE t1.a <= 2; +a b a b a b +1 3 3 3 NULL NULL +2 2 3 3 NULL NULL +1 3 4 2 1 2 +1 3 4 2 2 2 +2 2 4 2 1 2 +2 2 4 2 2 2 +1 3 5 3 NULL NULL +2 2 5 3 NULL NULL +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b +FROM t1, t3 +RIGHT JOIN +t2 +ON t2.b=t3.b +WHERE t1.a <= 2; +a b a b a b +1 3 3 3 NULL NULL +2 2 3 3 NULL NULL +1 3 4 2 1 2 +1 3 4 2 2 2 +2 2 4 2 1 2 +2 2 4 2 2 2 +1 3 5 3 NULL NULL +2 2 5 3 NULL NULL +SELECT t3.a,t3.b,t4.a,t4.b +FROM t3,t4; +a b a b +1 2 3 2 +2 2 3 2 +1 2 4 2 +2 2 4 2 +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b; +a b a b a b +3 3 NULL NULL NULL NULL +4 2 1 2 3 2 +4 2 1 2 4 2 +5 3 NULL NULL NULL NULL +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t1, t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b +WHERE t1.a <= 2; +a b a b a b a b +1 3 3 3 NULL NULL NULL NULL +2 2 3 3 NULL NULL NULL NULL +1 3 4 2 1 2 3 2 +1 3 4 2 1 2 4 2 +2 2 4 2 1 2 3 2 +2 2 4 2 1 2 4 2 +1 3 5 3 NULL NULL NULL NULL +2 2 5 3 NULL NULL NULL NULL +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t1, (t3, t4) +RIGHT JOIN +t2 +ON t3.a=1 AND t2.b=t4.b +WHERE t1.a <= 2; +a b a b a b a b +1 3 3 3 NULL NULL NULL NULL +2 2 3 3 NULL NULL NULL NULL +1 3 4 2 1 2 3 2 +1 3 4 2 1 2 4 2 +2 2 4 2 1 2 3 2 +2 2 4 2 1 2 4 2 +1 3 5 3 NULL NULL NULL NULL +2 2 5 3 NULL NULL NULL NULL +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t1, (t3, t4) +RIGHT JOIN +t2 +ON t3.a=1 AND t2.b=t4.b +WHERE t1.a <= 2; +a b a b a b a b +1 3 3 3 NULL NULL NULL NULL +2 2 3 3 NULL NULL NULL NULL +1 3 4 2 1 2 3 2 +1 3 4 2 1 2 4 2 +2 2 4 2 1 2 3 2 +2 2 4 2 1 2 4 2 +1 3 5 3 NULL NULL NULL NULL +2 2 5 3 NULL NULL NULL NULL +EXPLAIN EXTENDED +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM t1, (t3, t4) +RIGHT JOIN +t2 +ON t3.a=1 AND t2.b=t4.b +WHERE t1.a <= 2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using join buffer +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t1` join `test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) where (`test`.`t1`.`a` <= 2) +CREATE INDEX idx_b ON t2(b); +EXPLAIN EXTENDED +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM (t3,t4) +LEFT JOIN +(t1,t2) +ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 Using join buffer +1 SIMPLE t2 ref idx_b idx_b 5 test.t3.b 2 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t3` join `test`.`t4` left join (`test`.`t1` join `test`.`t2`) on(((`test`.`t3`.`a` = 1) and (`test`.`t3`.`b` = `test`.`t2`.`b`) and (`test`.`t2`.`b` = `test`.`t4`.`b`))) where 1 +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b +FROM (t3,t4) +LEFT JOIN +(t1,t2) +ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b; +a b a b a b +4 2 1 2 3 2 +4 2 1 2 3 2 +4 2 1 2 3 2 +NULL NULL 2 2 3 2 +4 2 1 2 4 2 +4 2 1 2 4 2 +4 2 1 2 4 2 +NULL NULL 2 2 4 2 +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2), +t9 +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL) AND +(t3.a < 5 OR t3.c IS NULL) AND +(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND +(t5.a >=2 OR t5.c IS NULL) AND +(t6.a >=4 OR t6.c IS NULL) AND +(t7.a <= 2 OR t7.c IS NULL) AND +(t8.a < 1 OR t8.c IS NULL) AND +(t8.b=t9.b OR t8.c IS NULL) AND +(t9.a=1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t5 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t7 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t8 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +Warnings: +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`))) +CREATE INDEX idx_b ON t4(b); +CREATE INDEX idx_b ON t5(b); +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2), +t9 +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL) AND +(t3.a < 5 OR t3.c IS NULL) AND +(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND +(t5.a >=2 OR t5.c IS NULL) AND +(t6.a >=4 OR t6.c IS NULL) AND +(t7.a <= 2 OR t7.c IS NULL) AND +(t8.a < 1 OR t8.c IS NULL) AND +(t8.b=t9.b OR t8.c IS NULL) AND +(t9.a=1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 100.00 Using where +1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 100.00 Using where +1 SIMPLE t7 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t8 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +Warnings: +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`))) +CREATE INDEX idx_b ON t8(b); +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2), +t9 +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL) AND +(t3.a < 5 OR t3.c IS NULL) AND +(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND +(t5.a >=2 OR t5.c IS NULL) AND +(t6.a >=4 OR t6.c IS NULL) AND +(t7.a <= 2 OR t7.c IS NULL) AND +(t8.a < 1 OR t8.c IS NULL) AND +(t8.b=t9.b OR t8.c IS NULL) AND +(t9.a=1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 100.00 Using where +1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 100.00 Using where +1 SIMPLE t7 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 2 100.00 Using where +1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +Warnings: +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`))) +CREATE INDEX idx_b ON t1(b); +CREATE INDEX idx_a ON t0(a); +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2), +t9 +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL) AND +(t3.a < 5 OR t3.c IS NULL) AND +(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND +(t5.a >=2 OR t5.c IS NULL) AND +(t6.a >=4 OR t6.c IS NULL) AND +(t7.a <= 2 OR t7.c IS NULL) AND +(t8.a < 1 OR t8.c IS NULL) AND +(t8.b=t9.b OR t8.c IS NULL) AND +(t9.a=1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t0 ref idx_a idx_a 5 const 1 100.00 Using where +1 SIMPLE t1 ref idx_b idx_b 5 test.t0.b 2 100.00 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 100.00 Using where +1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 100.00 Using where +1 SIMPLE t7 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 2 100.00 Using where +1 SIMPLE t9 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +Warnings: +Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`))) +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, +t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b +FROM t0,t1 +LEFT JOIN +( +t2 +LEFT JOIN +(t3, t4) +ON t3.a=1 AND t2.b=t4.b, +t5 +LEFT JOIN +( +(t6, t7) +LEFT JOIN +t8 +ON t7.b=t8.b AND t6.b < 10 +) +ON t6.b >= 2 AND t5.b=t7.b +) +ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND +(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND +(t1.a != 2), +t9 +WHERE t0.a=1 AND +t0.b=t1.b AND +(t2.a >= 4 OR t2.c IS NULL) AND +(t3.a < 5 OR t3.c IS NULL) AND +(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND +(t5.a >=2 OR t5.c IS NULL) AND +(t6.a >=4 OR t6.c IS NULL) AND +(t7.a <= 2 OR t7.c IS NULL) AND +(t8.a < 1 OR t8.c IS NULL) AND +(t8.b=t9.b OR t8.c IS NULL) AND +(t9.a=1); +a b a b a b a b a b a b a b a b a b a b +1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 1 +1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 1 +1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 1 +1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 1 +1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 1 +1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 1 +1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 1 +1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 2 +1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 2 +1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 1 2 +1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 2 +1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 2 +1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 1 2 +1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 2 +1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 2 +1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 1 2 +1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 2 +SELECT t2.a,t2.b +FROM t2; +a b +3 3 +4 2 +5 3 +SELECT t3.a,t3.b +FROM t3; +a b +1 2 +2 2 +SELECT t2.a,t2.b,t3.a,t3.b +FROM t2 LEFT JOIN t3 ON t2.b=t3.b +WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL); +a b a b +4 2 1 2 +4 2 2 2 +5 3 NULL NULL +SELECT t2.a,t2.b,t3.a,t3.b +FROM t2 LEFT JOIN (t3) ON t2.b=t3.b +WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL); +a b a b +4 2 1 2 +4 2 2 2 +5 3 NULL NULL +ALTER TABLE t3 +CHANGE COLUMN a a1 int, +CHANGE COLUMN c c1 int; +SELECT t2.a,t2.b,t3.a1,t3.b +FROM t2 LEFT JOIN t3 ON t2.b=t3.b +WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); +a b a1 b +4 2 1 2 +4 2 2 2 +5 3 NULL NULL +SELECT t2.a,t2.b,t3.a1,t3.b +FROM t2 NATURAL LEFT JOIN t3 +WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); +a b a1 b +4 2 1 2 +4 2 2 2 +5 3 NULL NULL +DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +CREATE TABLE t3 (a int); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (2); +INSERT INTO t1 VALUES (2); +SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.a=t3.a; +a a a +1 NULL NULL +2 2 2 +SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a; +a a a +1 NULL NULL +2 2 2 +DELETE FROM t1 WHERE a=2; +SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a; +a a a +1 NULL NULL +DELETE FROM t2; +SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a; +a a a +1 NULL NULL +DROP TABLE t1,t2,t3; +CREATE TABLE t1(a int, key (a)); +CREATE TABLE t2(b int, key (b)); +CREATE TABLE t3(c int, key (c)); +INSERT INTO t1 VALUES (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(10), (11), (12), (13), (14), (15), (16), (17), (18), (19); +INSERT INTO t2 VALUES (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(10), (11), (12), (13), (14), (15), (16), (17), (18), (19); +INSERT INTO t3 VALUES (0), (1), (2), (3), (4), (5); +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +analyze table t3; +Table Op Msg_type Msg_text +test.t3 analyze status OK +EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON c < 3 and b = c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 21 Using index +1 SIMPLE t3 index c c 5 NULL 6 Using index +1 SIMPLE t2 ref b b 5 test.t3.c 2 Using index +EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL # Using index +1 SIMPLE t3 index c c 5 NULL # Using index +1 SIMPLE t2 ref b b 5 test.t3.c # Using index +SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c; +a b c +NULL 0 0 +NULL 1 1 +NULL 2 2 +0 0 0 +0 1 1 +0 2 2 +1 0 0 +1 1 1 +1 2 2 +2 0 0 +2 1 1 +2 2 2 +3 0 0 +3 1 1 +3 2 2 +4 0 0 +4 1 1 +4 2 2 +5 0 0 +5 1 1 +5 2 2 +6 0 0 +6 1 1 +6 2 2 +7 0 0 +7 1 1 +7 2 2 +8 0 0 +8 1 1 +8 2 2 +9 0 0 +9 1 1 +9 2 2 +10 0 0 +10 1 1 +10 2 2 +11 0 0 +11 1 1 +11 2 2 +12 0 0 +12 1 1 +12 2 2 +13 0 0 +13 1 1 +13 2 2 +14 0 0 +14 1 1 +14 2 2 +15 0 0 +15 1 1 +15 2 2 +16 0 0 +16 1 1 +16 2 2 +17 0 0 +17 1 1 +17 2 2 +18 0 0 +18 1 1 +18 2 2 +19 0 0 +19 1 1 +19 2 2 +DELETE FROM t3; +EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL # Using index +1 SIMPLE t3 index c c 5 NULL # Using index +1 SIMPLE t2 ref b b 5 test.t3.c # Using index +SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c; +a b c +NULL NULL NULL +0 NULL NULL +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +5 NULL NULL +6 NULL NULL +7 NULL NULL +8 NULL NULL +9 NULL NULL +10 NULL NULL +11 NULL NULL +12 NULL NULL +13 NULL NULL +14 NULL NULL +15 NULL NULL +16 NULL NULL +17 NULL NULL +18 NULL NULL +19 NULL NULL +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (c11 int); +CREATE TABLE t2 (c21 int); +CREATE TABLE t3 (c31 int); +INSERT INTO t1 VALUES (4), (5); +SELECT * FROM t1 LEFT JOIN t2 ON c11=c21; +c11 c21 +4 NULL +5 NULL +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON c11=c21; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 system NULL NULL NULL NULL 0 const row not found +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON c21=c31) ON c11=c21; +c11 c21 c31 +4 NULL NULL +5 NULL NULL +EXPLAIN SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON c21=c31) ON c11=c21; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL NULL NULL NULL NULL 0 +1 SIMPLE t3 ALL NULL NULL NULL NULL 0 +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (goods int(12) NOT NULL, price varchar(128) NOT NULL); +INSERT INTO t1 VALUES (23, 2340), (26, 9900); +CREATE TABLE t2 (goods int(12), name varchar(50), shop char(2)); +INSERT INTO t2 VALUES (23, 'as300', 'fr'), (26, 'as600', 'fr'); +create table t3 (groupid int(12) NOT NULL, goodsid int(12) NOT NULL); +INSERT INTO t3 VALUES (3,23), (6,26); +CREATE TABLE t4 (groupid int(12)); +INSERT INTO t4 VALUES (1), (2), (3), (4), (5), (6); +SELECT * FROM +(SELECT DISTINCT gl.groupid, gp.price +FROM t4 gl +LEFT JOIN +(t3 g INNER JOIN t2 p ON g.goodsid = p.goods +INNER JOIN t1 gp ON p.goods = gp.goods) +ON gl.groupid = g.groupid and p.shop = 'fr') t; +groupid price +1 NULL +2 NULL +3 2340 +4 NULL +5 NULL +6 9900 +CREATE VIEW v1 AS +SELECT g.groupid groupid, p.goods goods, +p.name name, p.shop shop, +gp.price price +FROM t3 g INNER JOIN t2 p ON g.goodsid = p.goods +INNER JOIN t1 gp on p.goods = gp.goods; +CREATE VIEW v2 AS +SELECT DISTINCT g.groupid, fr.price +FROM t4 g +LEFT JOIN +v1 fr on g.groupid = fr.groupid and fr.shop = 'fr'; +SELECT * FROM v2; +groupid price +1 NULL +2 NULL +3 2340 +4 NULL +5 NULL +6 9900 +SELECT * FROM +(SELECT DISTINCT g.groupid, fr.price +FROM t4 g +LEFT JOIN +v1 fr on g.groupid = fr.groupid and fr.shop = 'fr') t; +groupid price +1 NULL +2 NULL +3 2340 +4 NULL +5 NULL +6 9900 +DROP VIEW v1,v2; +DROP TABLE t1,t2,t3,t4; +CREATE TABLE t1(a int); +CREATE TABLE t2(b int); +CREATE TABLE t3(c int, d int); +CREATE TABLE t4(d int); +CREATE TABLE t5(e int, f int); +CREATE TABLE t6(f int); +CREATE VIEW v1 AS +SELECT e FROM t5 JOIN t6 ON t5.e=t6.f; +CREATE VIEW v2 AS +SELECT e FROM t5 NATURAL JOIN t6; +SELECT t1.a FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c JOIN t4 USING(d); +a +SELECT t1.x FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c JOIN t4 USING(d); +ERROR 42S22: Unknown column 't1.x' in 'field list' +SELECT t1.a FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c NATURAL JOIN t4; +a +SELECT t1.x FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c NATURAL JOIN t4; +ERROR 42S22: Unknown column 't1.x' in 'field list' +SELECT v1.e FROM v1 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +e +SELECT v1.x FROM v1 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +ERROR 42S22: Unknown column 'v1.x' in 'field list' +SELECT v2.e FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +e +SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +ERROR 42S22: Unknown column 'v2.x' in 'field list' +DROP VIEW v1, v2; +DROP TABLE t1, t2, t3, t4, t5, t6; +create table t1 (id1 int(11) not null); +insert into t1 values (1),(2); +create table t2 (id2 int(11) not null); +insert into t2 values (1),(2),(3),(4); +create table t3 (id3 char(16) not null); +insert into t3 values ('100'); +create table t4 (id2 int(11) not null, id3 char(16)); +create table t5 (id1 int(11) not null, key (id1)); +insert into t5 values (1),(2),(1); +create view v1 as +select t4.id3 from t4 join t2 on t4.id2 = t2.id2; +select t1.id1 from t1 inner join (t3 left join v1 on t3.id3 = v1.id3); +id1 +1 +2 +drop view v1; +drop table t1, t2, t3, t4, t5; +create table t0 (a int); +insert into t0 values (0),(1),(2),(3); +create table t1(a int); +insert into t1 select A.a + 10*(B.a) from t0 A, t0 B; +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2), (3,3); +create table t3(a int, b int, filler char(200), key(a)); +insert into t3 select a,a,'filler' from t1; +insert into t3 select a,a,'filler' from t1; +create table t4 like t3; +insert into t4 select * from t3; +insert into t4 select * from t3; +create table t5 like t4; +insert into t5 select * from t4; +insert into t5 select * from t4; +create table t6 like t5; +insert into t6 select * from t5; +insert into t6 select * from t5; +create table t7 like t6; +insert into t7 select * from t6; +insert into t7 select * from t6; +explain select * from t4 join +t2 left join (t3 join t5 on t5.a=t3.b) on t3.a=t2.b where t4.a<=>t3.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X +1 SIMPLE t5 ref a a 5 test.t3.b X +1 SIMPLE t4 ref a a 5 test.t3.b X Using where +explain select * from (t4 join t6 on t6.a=t4.b) right join t3 on t4.a=t3.b +join t2 left join (t5 join t7 on t7.a=t5.b) on t5.a=t2.b where t3.a<=>t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X Using where +1 SIMPLE t4 ref a a 5 test.t3.b X +1 SIMPLE t6 ref a a 5 test.t4.b X +1 SIMPLE t5 ref a a 5 test.t2.b X +1 SIMPLE t7 ref a a 5 test.t5.b X +explain select * from t2 left join +(t3 left join (t4 join t6 on t6.a=t4.b) on t4.a=t3.b +join t5 on t5.a=t3.b) on t3.a=t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL X +1 SIMPLE t3 ref a a 5 test.t2.b X +1 SIMPLE t4 ref a a 5 test.t3.b X +1 SIMPLE t6 ref a a 5 test.t4.b X +1 SIMPLE t5 ref a a 5 test.t3.b X +drop table t0, t1, t2, t3, t4, t5, t6, t7; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, filler char(100), key(a)); +insert into t2 select A.a + 10*B.a, '' from t1 A, t1 B; +create table t3 like t2; +insert into t3 select * from t2; +explain select * from t1 left join +(t2 left join t3 on (t2.a = t3.a)) +on (t1.a = t2.a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 +1 SIMPLE t2 ref a a 5 test.t1.a 11 +1 SIMPLE t3 ref a a 5 test.t2.a 11 +drop table t1, t2, t3; +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, type varchar(10)); +CREATE TABLE t2 (pid int NOT NULL PRIMARY KEY, type varchar(10)); +CREATE TABLE t3 (cid int NOT NULL PRIMARY KEY, +id int NOT NULL, +pid int NOT NULL); +INSERT INTO t1 VALUES (1, 'A'), (3, 'C'); +INSERT INTO t2 VALUES (1, 'A'), (3, 'C'); +INSERT INTO t3 VALUES (1, 1, 1), (3, 3, 3); +SELECT * FROM t1 p LEFT JOIN (t3 JOIN t1) +ON (t1.id=t3.id AND t1.type='B' AND p.id=t3.id) +LEFT JOIN t2 ON (t3.pid=t2.pid) +WHERE p.id=1; +id type cid id pid id type pid type +1 A NULL NULL NULL NULL NULL NULL NULL +CREATE VIEW v1 AS +SELECT t3.* FROM t3 JOIN t1 ON t1.id=t3.id AND t1.type='B'; +SELECT * FROM t1 p LEFT JOIN v1 ON p.id=v1.id +LEFT JOIN t2 ON v1.pid=t2.pid +WHERE p.id=1; +id type cid id pid pid type +1 A NULL NULL NULL NULL NULL +DROP VIEW v1; +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (id1 int PRIMARY KEY, id2 int); +CREATE TABLE t2 (id1 int PRIMARY KEY, id2 int); +CREATE TABLE t3 (id1 int PRIMARY KEY, id2 int); +CREATE TABLE t4 (id1 int PRIMARY KEY, id2 int); +CREATE TABLE t5 (id1 int PRIMARY KEY, id2 int); +SELECT t1.id1 AS id, t5.id1 AS ngroupbynsa +FROM t1 INNER JOIN t2 ON t2.id2 = t1.id1 +LEFT OUTER JOIN +(t3 INNER JOIN t4 ON t4.id1 = t3.id2 INNER JOIN t5 ON t4.id2 = t5.id1) +ON t3.id2 IS NOT NULL +WHERE t1.id1=2; +id ngroupbynsa +PREPARE stmt FROM +"SELECT t1.id1 AS id, t5.id1 AS ngroupbynsa + FROM t1 INNER JOIN t2 ON t2.id2 = t1.id1 + LEFT OUTER JOIN + (t3 INNER JOIN t4 ON t4.id1 = t3.id2 INNER JOIN t5 ON t4.id2 = t5.id1) + ON t3.id2 IS NOT NULL + WHERE t1.id1=2"; +EXECUTE stmt; +id ngroupbynsa +EXECUTE stmt; +id ngroupbynsa +EXECUTE stmt; +id ngroupbynsa +EXECUTE stmt; +id ngroupbynsa +INSERT INTO t1 VALUES (1,1), (2,1), (3,2); +INSERT INTO t2 VALUES (2,1), (3,2), (4,3); +INSERT INTO t3 VALUES (1,1), (3,2), (2,NULL); +INSERT INTO t4 VALUES (1,1), (2,1), (3,3); +INSERT INTO t5 VALUES (1,1), (2,2), (3,3), (4,3); +EXECUTE stmt; +id ngroupbynsa +2 1 +2 1 +EXECUTE stmt; +id ngroupbynsa +2 1 +2 1 +EXECUTE stmt; +id ngroupbynsa +2 1 +2 1 +EXECUTE stmt; +id ngroupbynsa +2 1 +2 1 +SELECT t1.id1 AS id, t5.id1 AS ngroupbynsa +FROM t1 INNER JOIN t2 ON t2.id2 = t1.id1 +LEFT OUTER JOIN +(t3 INNER JOIN t4 ON t4.id1 = t3.id2 INNER JOIN t5 ON t4.id2 = t5.id1) +ON t3.id2 IS NOT NULL +WHERE t1.id1=2; +id ngroupbynsa +2 1 +2 1 +DROP TABLE t1,t2,t3,t4,t5; +CREATE TABLE t1 ( +id int NOT NULL PRIMARY KEY, +ct int DEFAULT NULL, +pc int DEFAULT NULL, +INDEX idx_ct (ct), +INDEX idx_pc (pc) +); +INSERT INTO t1 VALUES +(1,NULL,NULL),(2,NULL,NULL),(3,NULL,NULL),(4,NULL,NULL),(5,NULL,NULL); +CREATE TABLE t2 ( +id int NOT NULL PRIMARY KEY, +sr int NOT NULL, +nm varchar(255) NOT NULL, +INDEX idx_sr (sr) +); +INSERT INTO t2 VALUES +(2441905,4308,'LesAbymes'),(2441906,4308,'Anse-Bertrand'); +CREATE TABLE t3 ( +id int NOT NULL PRIMARY KEY, +ct int NOT NULL, +ln int NOT NULL, +INDEX idx_ct (ct), +INDEX idx_ln (ln) +); +CREATE TABLE t4 ( +id int NOT NULL PRIMARY KEY, +nm varchar(255) NOT NULL +); +INSERT INTO t4 VALUES (4308,'Guadeloupe'),(4309,'Martinique'); +SELECT t1.* +FROM t1 LEFT JOIN +(t2 LEFT JOIN t3 ON t3.ct=t2.id AND t3.ln='5') ON t1.ct=t2.id +WHERE t1.id='5'; +id ct pc +5 NULL NULL +SELECT t1.*, t4.nm +FROM t1 LEFT JOIN +(t2 LEFT JOIN t3 ON t3.ct=t2.id AND t3.ln='5') ON t1.ct=t2.id +LEFT JOIN t4 ON t2.sr=t4.id +WHERE t1.id='5'; +id ct pc nm +5 NULL NULL NULL +DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/suite/pbxt/r/join_outer.result b/mysql-test/suite/pbxt/r/join_outer.result new file mode 100644 index 00000000000..31813a4f06c --- /dev/null +++ b/mysql-test/suite/pbxt/r/join_outer.result @@ -0,0 +1,1196 @@ +drop table if exists t0,t1,t2,t3,t4,t5; +CREATE TABLE t1 ( +grp int(11) default NULL, +a bigint(20) unsigned default NULL, +c char(10) NOT NULL default '' +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,1,'a'),(2,2,'b'),(2,3,'c'),(3,4,'E'),(3,5,'C'),(3,6,'D'),(NULL,NULL,''); +create table t2 (id int, a bigint unsigned not null, c char(10), d int, primary key (a)); +insert into t2 values (1,1,"a",1),(3,4,"A",4),(3,5,"B",5),(3,6,"C",6),(4,7,"D",7); +select t1.*,t2.* from t1 JOIN t2 where t1.a=t2.a; +grp a c id a c d +1 1 a 1 1 a 1 +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) order by t1.grp,t1.a,t2.c; +grp a c id a c d +NULL NULL NULL NULL NULL NULL +1 1 a 1 1 a 1 +2 2 b NULL NULL NULL NULL +2 3 c NULL NULL NULL NULL +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +select t1.*,t2.* from { oj t2 left outer join t1 on (t1.a=t2.a) }; +grp a c id a c d +1 1 a 1 1 a 1 +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +NULL NULL NULL 4 7 D 7 +select t1.*,t2.* from t1 as t0,{ oj t2 left outer join t1 on (t1.a=t2.a) } WHERE t0.a=2; +grp a c id a c d +1 1 a 1 1 a 1 +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +NULL NULL NULL 4 7 D 7 +select t1.*,t2.* from t1 left join t2 using (a); +grp a c id a c d +1 1 a 1 1 a 1 +2 2 b NULL NULL NULL NULL +2 3 c NULL NULL NULL NULL +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +NULL NULL NULL NULL NULL NULL +select t1.*,t2.* from t1 left join t2 using (a) where t1.a=t2.a; +grp a c id a c d +1 1 a 1 1 a 1 +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +select t1.*,t2.* from t1 left join t2 using (a,c); +grp a c id a c d +1 1 a 1 1 a 1 +2 2 b NULL NULL NULL NULL +2 3 c NULL NULL NULL NULL +3 4 E NULL NULL NULL NULL +3 5 C NULL NULL NULL NULL +3 6 D NULL NULL NULL NULL +NULL NULL NULL NULL NULL NULL +select t1.*,t2.* from t1 left join t2 using (c); +grp a c id a c d +1 1 a 1 1 a 1 +1 1 a 3 4 A 4 +2 2 b 3 5 B 5 +2 3 c 3 6 C 6 +3 4 E NULL NULL NULL NULL +3 5 C 3 6 C 6 +3 6 D 4 7 D 7 +NULL NULL NULL NULL NULL NULL +select t1.*,t2.* from t1 natural left outer join t2; +grp a c id a c d +1 1 a 1 1 a 1 +2 2 b NULL NULL NULL NULL +2 3 c NULL NULL NULL NULL +3 4 E NULL NULL NULL NULL +3 5 C NULL NULL NULL NULL +3 6 D NULL NULL NULL NULL +NULL NULL NULL NULL NULL NULL +select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id=3; +grp a c id a c d +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id is null; +grp a c id a c d +2 2 b NULL NULL NULL NULL +2 3 c NULL NULL NULL NULL +NULL NULL NULL NULL NULL NULL +explain select t1.*,t2.* from t1,t2 where t1.a=t2.a and isnull(t2.a)=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 7 +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 8 test.t1.a 1 Using where +select t1.*,t2.*,t3.a from t1 left join t2 on (t1.a=t2.a) left join t1 as t3 on (t2.a=t3.a); +grp a c id a c d a +1 1 a 1 1 a 1 1 +2 2 b NULL NULL NULL NULL NULL +2 3 c NULL NULL NULL NULL NULL +3 4 E 3 4 A 4 4 +3 5 C 3 5 B 5 5 +3 6 D 3 6 C 6 6 +NULL NULL NULL NULL NULL NULL NULL +explain select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); +ERROR 42S22: Unknown column 't3.a' in 'on clause' +select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); +ERROR 42S22: Unknown column 't3.a' in 'on clause' +select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a); +ERROR 42S22: Unknown column 't3.a' in 'on clause' +select t1.*,t2.* from t1 inner join t2 using (a); +grp a c id a c d +1 1 a 1 1 a 1 +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +select t1.*,t2.* from t1 inner join t2 on (t1.a=t2.a); +grp a c id a c d +1 1 a 1 1 a 1 +3 4 E 3 4 A 4 +3 5 C 3 5 B 5 +3 6 D 3 6 C 6 +select t1.*,t2.* from t1 natural join t2; +grp a c id a c d +1 1 a 1 1 a 1 +drop table t1,t2; +CREATE TABLE t1 ( +usr_id INT unsigned NOT NULL, +uniq_id INT unsigned NOT NULL AUTO_INCREMENT, +start_num INT unsigned NOT NULL DEFAULT 1, +increment INT unsigned NOT NULL DEFAULT 1, +PRIMARY KEY (uniq_id), +INDEX usr_uniq_idx (usr_id, uniq_id), +INDEX uniq_usr_idx (uniq_id, usr_id) +); +CREATE TABLE t2 ( +id INT unsigned NOT NULL DEFAULT 0, +usr2_id INT unsigned NOT NULL DEFAULT 0, +max INT unsigned NOT NULL DEFAULT 0, +c_amount INT unsigned NOT NULL DEFAULT 0, +d_max INT unsigned NOT NULL DEFAULT 0, +d_num INT unsigned NOT NULL DEFAULT 0, +orig_time INT unsigned NOT NULL DEFAULT 0, +c_time INT unsigned NOT NULL DEFAULT 0, +active ENUM ("no","yes") NOT NULL, +PRIMARY KEY (id,usr2_id), +INDEX id_idx (id), +INDEX usr2_idx (usr2_id) +); +INSERT INTO t1 VALUES (3,NULL,0,50),(3,NULL,0,200),(3,NULL,0,25),(3,NULL,0,84676),(3,NULL,0,235),(3,NULL,0,10),(3,NULL,0,3098),(3,NULL,0,2947),(3,NULL,0,8987),(3,NULL,0,8347654),(3,NULL,0,20398),(3,NULL,0,8976),(3,NULL,0,500),(3,NULL,0,198); +SELECT t1.usr_id,t1.uniq_id,t1.increment, +t2.usr2_id,t2.c_amount,t2.max +FROM t1 +LEFT JOIN t2 ON t2.id = t1.uniq_id +WHERE t1.uniq_id = 4 +ORDER BY t2.c_amount; +usr_id uniq_id increment usr2_id c_amount max +3 4 84676 NULL NULL NULL +SELECT t1.usr_id,t1.uniq_id,t1.increment, +t2.usr2_id,t2.c_amount,t2.max +FROM t2 +RIGHT JOIN t1 ON t2.id = t1.uniq_id +WHERE t1.uniq_id = 4 +ORDER BY t2.c_amount; +usr_id uniq_id increment usr2_id c_amount max +3 4 84676 NULL NULL NULL +INSERT INTO t2 VALUES (2,3,3000,6000,0,0,746584,837484,'yes'); +INSERT INTO t2 VALUES (2,3,3000,6000,0,0,746584,837484,'yes'); +ERROR 23000: Duplicate entry '2-3' for key 'PRIMARY' +INSERT INTO t2 VALUES (7,3,1000,2000,0,0,746294,937484,'yes'); +SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4 ORDER BY t2.c_amount; +usr_id uniq_id increment usr2_id c_amount max +3 4 84676 NULL NULL NULL +SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4 GROUP BY t2.c_amount; +usr_id uniq_id increment usr2_id c_amount max +3 4 84676 NULL NULL NULL +SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4; +usr_id uniq_id increment usr2_id c_amount max +3 4 84676 NULL NULL NULL +drop table t1,t2; +CREATE TABLE t1 ( +cod_asig int(11) DEFAULT '0' NOT NULL, +desc_larga_cat varchar(80) DEFAULT '' NOT NULL, +desc_larga_cas varchar(80) DEFAULT '' NOT NULL, +desc_corta_cat varchar(40) DEFAULT '' NOT NULL, +desc_corta_cas varchar(40) DEFAULT '' NOT NULL, +cred_total double(3,1) DEFAULT '0.0' NOT NULL, +pre_requisit int(11), +co_requisit int(11), +preco_requisit int(11), +PRIMARY KEY (cod_asig) +); +INSERT INTO t1 VALUES (10360,'asdfggfg','Introduccion a los Ordenadores I','asdfggfg','Introduccio Ordinadors I',6.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (10361,'Components i Circuits Electronics I','Componentes y Circuitos Electronicos I','Components i Circuits Electronics I','Comp. i Circ. Electr. I',6.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (10362,'Laboratori d`Ordinadors','Laboratorio de Ordenadores','Laboratori d`Ordinadors','Laboratori Ordinadors',4.5,NULL,NULL,NULL); +INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas de Comunicacion Oral y Escrita','Tecniques de Comunicacio Oral i Escrita','Tec. Com. Oral i Escrita',4.5,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL); +CREATE TABLE t2 ( +idAssignatura int(11) DEFAULT '0' NOT NULL, +Grup int(11) DEFAULT '0' NOT NULL, +Places smallint(6) DEFAULT '0' NOT NULL, +PlacesOcupades int(11) DEFAULT '0', +PRIMARY KEY (idAssignatura,Grup) +); +INSERT INTO t2 VALUES (10360,12,333,0); +INSERT INTO t2 VALUES (10361,30,2,0); +INSERT INTO t2 VALUES (10361,40,3,0); +INSERT INTO t2 VALUES (10360,45,10,0); +INSERT INTO t2 VALUES (10362,10,12,0); +INSERT INTO t2 VALUES (10360,55,2,0); +INSERT INTO t2 VALUES (10360,70,0,0); +INSERT INTO t2 VALUES (10360,565656,0,0); +INSERT INTO t2 VALUES (10360,32767,7,0); +INSERT INTO t2 VALUES (10360,33,8,0); +INSERT INTO t2 VALUES (10360,7887,85,0); +INSERT INTO t2 VALUES (11405,88,8,0); +INSERT INTO t2 VALUES (10360,0,55,0); +INSERT INTO t2 VALUES (10360,99,0,0); +INSERT INTO t2 VALUES (11411,30,10,0); +INSERT INTO t2 VALUES (11404,0,0,0); +INSERT INTO t2 VALUES (10362,11,111,0); +INSERT INTO t2 VALUES (10363,33,333,0); +INSERT INTO t2 VALUES (11412,55,0,0); +INSERT INTO t2 VALUES (50003,66,6,0); +INSERT INTO t2 VALUES (11403,5,0,0); +INSERT INTO t2 VALUES (11406,11,11,0); +INSERT INTO t2 VALUES (11410,11410,131,0); +INSERT INTO t2 VALUES (11416,11416,32767,0); +INSERT INTO t2 VALUES (11409,0,0,0); +CREATE TABLE t3 ( +id int(11) NOT NULL auto_increment, +dni_pasaporte char(16) DEFAULT '' NOT NULL, +idPla int(11) DEFAULT '0' NOT NULL, +cod_asig int(11) DEFAULT '0' NOT NULL, +any smallint(6) DEFAULT '0' NOT NULL, +quatrimestre smallint(6) DEFAULT '0' NOT NULL, +estat char(1) DEFAULT 'M' NOT NULL, +PRIMARY KEY (id), +UNIQUE dni_pasaporte (dni_pasaporte,idPla), +UNIQUE dni_pasaporte_2 (dni_pasaporte,idPla,cod_asig,any,quatrimestre) +); +INSERT INTO t3 VALUES (1,'11111111',1,10362,98,1,'M'); +CREATE TABLE t4 ( +id int(11) NOT NULL auto_increment, +papa int(11) DEFAULT '0' NOT NULL, +fill int(11) DEFAULT '0' NOT NULL, +idPla int(11) DEFAULT '0' NOT NULL, +PRIMARY KEY (id), +KEY papa (idPla,papa), +UNIQUE papa_2 (idPla,papa,fill) +); +INSERT INTO t4 VALUES (1,-1,10360,1); +INSERT INTO t4 VALUES (2,-1,10361,1); +INSERT INTO t4 VALUES (3,-1,10362,1); +SELECT DISTINCT fill,desc_larga_cat,cred_total,Grup,Places,PlacesOcupades FROM t4 LEFT JOIN t3 ON t3.cod_asig=fill AND estat='S' AND dni_pasaporte='11111111' AND t3.idPla=1 , t2,t1 WHERE fill=t1.cod_asig AND Places>PlacesOcupades AND fill=idAssignatura AND t4.idPla=1 AND papa=-1; +fill desc_larga_cat cred_total Grup Places PlacesOcupades +10360 asdfggfg 6.0 0 55 0 +10360 asdfggfg 6.0 12 333 0 +10360 asdfggfg 6.0 33 8 0 +10360 asdfggfg 6.0 45 10 0 +10360 asdfggfg 6.0 55 2 0 +10360 asdfggfg 6.0 7887 85 0 +10360 asdfggfg 6.0 32767 7 0 +10361 Components i Circuits Electronics I 6.0 30 2 0 +10361 Components i Circuits Electronics I 6.0 40 3 0 +10362 Laboratori d`Ordinadors 4.5 10 12 0 +10362 Laboratori d`Ordinadors 4.5 11 111 0 +SELECT DISTINCT fill,t3.idPla FROM t4 LEFT JOIN t3 ON t3.cod_asig=t4.fill AND t3.estat='S' AND t3.dni_pasaporte='1234' AND t3.idPla=1 ; +fill idPla +10360 NULL +10361 NULL +10362 NULL +INSERT INTO t3 VALUES (3,'1234',1,10360,98,1,'S'); +SELECT DISTINCT fill,t3.idPla FROM t4 LEFT JOIN t3 ON t3.cod_asig=t4.fill AND t3.estat='S' AND t3.dni_pasaporte='1234' AND t3.idPla=1 ; +fill idPla +10360 1 +10361 NULL +10362 NULL +drop table t1,t2,t3,test.t4; +CREATE TABLE t1 ( +id smallint(5) unsigned NOT NULL auto_increment, +name char(60) DEFAULT '' NOT NULL, +PRIMARY KEY (id) +); +INSERT INTO t1 VALUES (1,'Antonio Paz'); +INSERT INTO t1 VALUES (2,'Lilliana Angelovska'); +INSERT INTO t1 VALUES (3,'Thimble Smith'); +CREATE TABLE t2 ( +id smallint(5) unsigned NOT NULL auto_increment, +owner smallint(5) unsigned DEFAULT '0' NOT NULL, +name char(60), +PRIMARY KEY (id) +); +INSERT INTO t2 VALUES (1,1,'El Gato'); +INSERT INTO t2 VALUES (2,1,'Perrito'); +INSERT INTO t2 VALUES (3,3,'Happy'); +select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner); +name name id +Antonio Paz El Gato 1 +Antonio Paz Perrito 2 +Lilliana Angelovska NULL NULL +Thimble Smith Happy 3 +select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.id is null; +name name id +Lilliana Angelovska NULL NULL +explain select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.id is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where; Not exists +explain select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.name is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where +select count(*) from t1 left join t2 on (t1.id = t2.owner); +count(*) +4 +select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner); +name name id +Antonio Paz El Gato 1 +Antonio Paz Perrito 2 +Lilliana Angelovska NULL NULL +Thimble Smith Happy 3 +select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.id is null; +name name id +Lilliana Angelovska NULL NULL +explain select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.id is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where; Not exists +explain select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.name is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where +select count(*) from t2 right join t1 on (t1.id = t2.owner); +count(*) +4 +select t1.name, t2.name, t2.id,t3.id from t2 right join t1 on (t1.id = t2.owner) left join t1 as t3 on t3.id=t2.owner; +name name id id +Antonio Paz El Gato 1 1 +Antonio Paz Perrito 2 1 +Lilliana Angelovska NULL NULL NULL +Thimble Smith Happy 3 3 +select t1.name, t2.name, t2.id,t3.id from t1 right join t2 on (t1.id = t2.owner) right join t1 as t3 on t3.id=t2.owner; +name name id id +Antonio Paz El Gato 1 1 +Antonio Paz Perrito 2 1 +NULL NULL NULL 2 +Thimble Smith Happy 3 3 +select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id = t2.owner) right join t1 as t3 on t3.id=t2.owner; +name name id owner id +Antonio Paz El Gato 1 1 1 +Antonio Paz Perrito 2 1 1 +NULL NULL NULL NULL 2 +Thimble Smith Happy 3 3 3 +drop table t1,t2; +create table t1 (id int not null, str char(10), index(str)); +insert into t1 values (1, null), (2, null), (3, "foo"), (4, "bar"); +select * from t1 where str is not null order by id; +id str +3 foo +4 bar +select * from t1 where str is null; +id str +1 NULL +2 NULL +drop table t1; +CREATE TABLE t1 ( +t1_id bigint(21) NOT NULL auto_increment, +PRIMARY KEY (t1_id) +); +CREATE TABLE t2 ( +t2_id bigint(21) NOT NULL auto_increment, +PRIMARY KEY (t2_id) +); +CREATE TABLE t3 ( +t3_id bigint(21) NOT NULL auto_increment, +PRIMARY KEY (t3_id) +); +CREATE TABLE t4 ( +seq_0_id bigint(21) DEFAULT '0' NOT NULL, +seq_1_id bigint(21) DEFAULT '0' NOT NULL, +KEY seq_0_id (seq_0_id), +KEY seq_1_id (seq_1_id) +); +CREATE TABLE t5 ( +seq_0_id bigint(21) DEFAULT '0' NOT NULL, +seq_1_id bigint(21) DEFAULT '0' NOT NULL, +KEY seq_1_id (seq_1_id), +KEY seq_0_id (seq_0_id) +); +insert into t1 values (1); +insert into t2 values (1); +insert into t3 values (1); +insert into t4 values (1,1); +insert into t5 values (1,1); +explain select * from t3 left join t4 on t4.seq_1_id = t2.t2_id left join t1 on t1.t1_id = t4.seq_0_id left join t5 on t5.seq_0_id = t1.t1_id left join t2 on t2.t2_id = t5.seq_1_id where t3.t3_id = 23; +ERROR 42S22: Unknown column 't2.t2_id' in 'on clause' +drop table t1,t2,t3,t4,t5; +create table t1 (n int, m int, o int, key(n)); +create table t2 (n int not null, m int, o int, primary key(n)); +insert into t1 values (1, 2, 11), (1, 2, 7), (2, 2, 8), (1,2,9),(1,3,9); +insert into t2 values (1, 2, 3),(2, 2, 8), (4,3,9),(3,2,10); +select t1.*, t2.* from t1 left join t2 on t1.n = t2.n and +t1.m = t2.m where t1.n = 1; +n m o n m o +1 2 11 1 2 3 +1 2 7 1 2 3 +1 2 9 1 2 3 +1 3 9 NULL NULL NULL +select t1.*, t2.* from t1 left join t2 on t1.n = t2.n and +t1.m = t2.m where t1.n = 1 order by t1.o; +n m o n m o +1 2 7 1 2 3 +1 2 9 1 2 3 +1 3 9 NULL NULL NULL +1 2 11 1 2 3 +drop table t1,t2; +CREATE TABLE t1 (id1 INT NOT NULL PRIMARY KEY, dat1 CHAR(1), id2 INT); +INSERT INTO t1 VALUES (1,'a',1); +INSERT INTO t1 VALUES (2,'b',1); +INSERT INTO t1 VALUES (3,'c',2); +CREATE TABLE t2 (id2 INT NOT NULL PRIMARY KEY, dat2 CHAR(1)); +INSERT INTO t2 VALUES (1,'x'); +INSERT INTO t2 VALUES (2,'y'); +INSERT INTO t2 VALUES (3,'z'); +SELECT t2.id2 FROM t2 LEFT OUTER JOIN t1 ON t1.id2 = t2.id2 WHERE id1 IS NULL; +id2 +3 +SELECT t2.id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; +id2 +3 +drop table t1,t2; +create table t1 ( color varchar(20), name varchar(20) ); +insert into t1 values ( 'red', 'apple' ); +insert into t1 values ( 'yellow', 'banana' ); +insert into t1 values ( 'green', 'lime' ); +insert into t1 values ( 'black', 'grape' ); +insert into t1 values ( 'blue', 'blueberry' ); +create table t2 ( count int, color varchar(20) ); +insert into t2 values (10, 'green'); +insert into t2 values (5, 'black'); +insert into t2 values (15, 'white'); +insert into t2 values (7, 'green'); +select * from t1; +color name +red apple +yellow banana +green lime +black grape +blue blueberry +select * from t2; +count color +10 green +5 black +15 white +7 green +select * from t2 natural join t1; +color count name +green 10 lime +green 7 lime +black 5 grape +select t2.count, t1.name from t2 natural join t1; +count name +10 lime +7 lime +5 grape +select t2.count, t1.name from t2 inner join t1 using (color); +count name +10 lime +7 lime +5 grape +drop table t1; +drop table t2; +CREATE TABLE t1 ( +pcode varchar(8) DEFAULT '' NOT NULL +); +INSERT INTO t1 VALUES ('kvw2000'),('kvw2001'),('kvw3000'),('kvw3001'),('kvw3002'),('kvw3500'),('kvw3501'),('kvw3502'),('kvw3800'),('kvw3801'),('kvw3802'),('kvw3900'),('kvw3901'),('kvw3902'),('kvw4000'),('kvw4001'),('kvw4002'),('kvw4200'),('kvw4500'),('kvw5000'),('kvw5001'),('kvw5500'),('kvw5510'),('kvw5600'),('kvw5601'),('kvw6000'),('klw1000'),('klw1020'),('klw1500'),('klw2000'),('klw2001'),('klw2002'),('kld2000'),('klw2500'),('kmw1000'),('kmw1500'),('kmw2000'),('kmw2001'),('kmw2100'),('kmw3000'),('kmw3200'); +CREATE TABLE t2 ( +pcode varchar(8) DEFAULT '' NOT NULL, +KEY pcode (pcode) +); +INSERT INTO t2 VALUES ('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw6000'),('kvw6000'),('kld2000'); +SELECT t1.pcode, IF(ISNULL(t2.pcode), 0, COUNT(*)) AS count FROM t1 +LEFT JOIN t2 ON t1.pcode = t2.pcode GROUP BY t1.pcode; +pcode count +kld2000 1 +klw1000 0 +klw1020 0 +klw1500 0 +klw2000 0 +klw2001 0 +klw2002 0 +klw2500 0 +kmw1000 0 +kmw1500 0 +kmw2000 0 +kmw2001 0 +kmw2100 0 +kmw3000 0 +kmw3200 0 +kvw2000 26 +kvw2001 0 +kvw3000 36 +kvw3001 0 +kvw3002 0 +kvw3500 26 +kvw3501 0 +kvw3502 0 +kvw3800 0 +kvw3801 0 +kvw3802 0 +kvw3900 0 +kvw3901 0 +kvw3902 0 +kvw4000 0 +kvw4001 0 +kvw4002 0 +kvw4200 0 +kvw4500 0 +kvw5000 0 +kvw5001 0 +kvw5500 0 +kvw5510 0 +kvw5600 0 +kvw5601 0 +kvw6000 2 +SELECT SQL_BIG_RESULT t1.pcode, IF(ISNULL(t2.pcode), 0, COUNT(*)) AS count FROM t1 LEFT JOIN t2 ON t1.pcode = t2.pcode GROUP BY t1.pcode; +pcode count +kld2000 1 +klw1000 0 +klw1020 0 +klw1500 0 +klw2000 0 +klw2001 0 +klw2002 0 +klw2500 0 +kmw1000 0 +kmw1500 0 +kmw2000 0 +kmw2001 0 +kmw2100 0 +kmw3000 0 +kmw3200 0 +kvw2000 26 +kvw2001 0 +kvw3000 36 +kvw3001 0 +kvw3002 0 +kvw3500 26 +kvw3501 0 +kvw3502 0 +kvw3800 0 +kvw3801 0 +kvw3802 0 +kvw3900 0 +kvw3901 0 +kvw3902 0 +kvw4000 0 +kvw4001 0 +kvw4002 0 +kvw4200 0 +kvw4500 0 +kvw5000 0 +kvw5001 0 +kvw5500 0 +kvw5510 0 +kvw5600 0 +kvw5601 0 +kvw6000 2 +drop table t1,t2; +CREATE TABLE t1 ( +id int(11), +pid int(11), +rep_del tinyint(4), +KEY id (id), +KEY pid (pid) +); +INSERT INTO t1 VALUES (1,NULL,NULL); +INSERT INTO t1 VALUES (2,1,NULL); +select * from t1 LEFT JOIN t1 t2 ON (t1.id=t2.pid) AND t2.rep_del IS NULL; +id pid rep_del id pid rep_del +1 NULL NULL 2 1 NULL +2 1 NULL NULL NULL NULL +create index rep_del ON t1(rep_del); +select * from t1 LEFT JOIN t1 t2 ON (t1.id=t2.pid) AND t2.rep_del IS NULL; +id pid rep_del id pid rep_del +1 NULL NULL 2 1 NULL +2 1 NULL NULL NULL NULL +drop table t1; +CREATE TABLE t1 ( +id int(11) DEFAULT '0' NOT NULL, +name tinytext DEFAULT '' NOT NULL, +UNIQUE id (id) +); +Warnings: +Warning 1101 BLOB/TEXT column 'name' can't have a default value +INSERT INTO t1 VALUES (1,'yes'),(2,'no'); +CREATE TABLE t2 ( +id int(11) DEFAULT '0' NOT NULL, +idx int(11) DEFAULT '0' NOT NULL, +UNIQUE id (id,idx) +); +INSERT INTO t2 VALUES (1,1); +explain SELECT * from t1 left join t2 on t1.id=t2.id where t2.id IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ref id id 4 test.t1.id 1 Using where; Using index; Not exists +SELECT * from t1 left join t2 on t1.id=t2.id where t2.id IS NULL; +id name id idx +2 no NULL NULL +drop table t1,t2; +create table t1 (bug_id mediumint, reporter mediumint); +create table t2 (bug_id mediumint, who mediumint, index(who)); +insert into t2 values (1,1),(1,2); +insert into t1 values (1,1),(2,1); +SELECT * FROM t1 LEFT JOIN t2 ON (t1.bug_id = t2.bug_id AND t2.who = 2) WHERE (t1.reporter = 2 OR t2.who = 2); +bug_id reporter bug_id who +1 1 1 2 +drop table t1,t2; +create table t1 (fooID smallint unsigned auto_increment, primary key (fooID)); +create table t2 (fooID smallint unsigned not null, barID smallint unsigned not null, primary key (fooID,barID)); +insert into t1 (fooID) values (10),(20),(30); +insert into t2 values (10,1),(20,2),(30,3); +explain select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL PRIMARY 4 NULL 3 Using index +1 SIMPLE t1 const PRIMARY PRIMARY 2 const 1 Using index +select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30; +fooID barID fooID +10 1 NULL +20 2 NULL +30 3 30 +select * from t2 left join t1 ignore index(primary) on t1.fooID = t2.fooID and t1.fooID = 30; +fooID barID fooID +10 1 NULL +20 2 NULL +30 3 30 +drop table t1,t2; +create table t1 (i int); +create table t2 (i int); +create table t3 (i int); +insert into t1 values(1),(2); +insert into t2 values(2),(3); +insert into t3 values(2),(4); +select * from t1 natural left join t2 natural left join t3; +i +1 +2 +select * from t1 natural left join t2 where (t2.i is not null)=0; +i +1 +select * from t1 natural left join t2 where (t2.i is not null) is not null; +i +1 +2 +select * from t1 natural left join t2 where (i is not null)=0; +i +select * from t1 natural left join t2 where (i is not null) is not null; +i +1 +2 +drop table t1,t2,t3; +create table t1 (f1 integer,f2 integer,f3 integer); +create table t2 (f2 integer,f4 integer); +create table t3 (f3 integer,f5 integer); +select * from t1 +left outer join t2 using (f2) +left outer join t3 using (f3); +f3 f2 f1 f4 f5 +drop table t1,t2,t3; +create table t1 (a1 int, a2 int); +create table t2 (b1 int not null, b2 int); +create table t3 (c1 int, c2 int); +insert into t1 values (1,2), (2,2), (3,2); +insert into t2 values (1,3), (2,3); +insert into t3 values (2,4), (3,4); +select * from t1 left join t2 on b1 = a1 left join t3 on c1 = a1 and b1 is null; +a1 a2 b1 b2 c1 c2 +1 2 1 3 NULL NULL +2 2 2 3 NULL NULL +3 2 NULL NULL 3 4 +explain select * from t1 left join t2 on b1 = a1 left join t3 on c1 = a1 and b1 is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 +drop table t1, t2, t3; +create table t1 ( +a int(11), +b char(10), +key (a) +); +insert into t1 (a) values (1),(2),(3),(4); +create table t2 (a int); +select * from t1 left join t2 on t1.a=t2.a where not (t2.a <=> t1.a); +a b a +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +select * from t1 left join t2 on t1.a=t2.a having not (t2.a <=> t1.a); +a b a +1 NULL NULL +2 NULL NULL +3 NULL NULL +4 NULL NULL +drop table t1,t2; +create table t1 ( +match_id tinyint(3) unsigned not null auto_increment, +home tinyint(3) unsigned default '0', +unique key match_id (match_id), +key match_id_2 (match_id) +); +insert into t1 values("1", "2"); +create table t2 ( +player_id tinyint(3) unsigned default '0', +match_1_h tinyint(3) unsigned default '0', +key player_id (player_id) +); +insert into t2 values("1", "5"); +insert into t2 values("2", "9"); +insert into t2 values("3", "3"); +insert into t2 values("4", "7"); +insert into t2 values("5", "6"); +insert into t2 values("6", "8"); +insert into t2 values("7", "4"); +insert into t2 values("8", "12"); +insert into t2 values("9", "11"); +insert into t2 values("10", "10"); +explain select s.*, '*', m.*, (s.match_1_h - m.home) UUX from +(t2 s left join t1 m on m.match_id = 1) +order by m.match_id desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE s ALL NULL NULL NULL NULL 10 Using temporary; Using filesort +1 SIMPLE m const match_id,match_id_2 match_id 1 const 1 +explain select s.*, '*', m.*, (s.match_1_h - m.home) UUX from +(t2 s left join t1 m on m.match_id = 1) +order by UUX desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE s ALL NULL NULL NULL NULL 10 Using temporary; Using filesort +1 SIMPLE m const match_id,match_id_2 match_id 1 const 1 +select s.*, '*', m.*, (s.match_1_h - m.home) UUX from +(t2 s left join t1 m on m.match_id = 1) +order by UUX desc; +player_id match_1_h * match_id home UUX +8 12 * 1 2 10 +9 11 * 1 2 9 +10 10 * 1 2 8 +2 9 * 1 2 7 +6 8 * 1 2 6 +4 7 * 1 2 5 +5 6 * 1 2 4 +1 5 * 1 2 3 +7 4 * 1 2 2 +3 3 * 1 2 1 +explain select s.*, '*', m.*, (s.match_1_h - m.home) UUX from +t2 s straight_join t1 m where m.match_id = 1 +order by UUX desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE s ALL NULL NULL NULL NULL 10 Using temporary; Using filesort +1 SIMPLE m const match_id,match_id_2 match_id 1 const 1 +select s.*, '*', m.*, (s.match_1_h - m.home) UUX from +t2 s straight_join t1 m where m.match_id = 1 +order by UUX desc; +player_id match_1_h * match_id home UUX +8 12 * 1 2 10 +9 11 * 1 2 9 +10 10 * 1 2 8 +2 9 * 1 2 7 +6 8 * 1 2 6 +4 7 * 1 2 5 +5 6 * 1 2 4 +1 5 * 1 2 3 +7 4 * 1 2 2 +3 3 * 1 2 1 +drop table t1, t2; +create table t1 (a int, b int, unique index idx (a, b)); +create table t2 (a int, b int, c int, unique index idx (a, b)); +insert into t1 values (1, 10), (1,11), (2,10), (2,11); +insert into t2 values (1,10,3); +select t1.a, t1.b, t2.c from t1 left join t2 +on t1.a=t2.a and t1.b=t2.b and t2.c=3 +where t1.a=1 and t2.c is null; +a b c +1 11 NULL +drop table t1, t2; +CREATE TABLE t1 ( +ts_id bigint(20) default NULL, +inst_id tinyint(4) default NULL, +flag_name varchar(64) default NULL, +flag_value text, +UNIQUE KEY ts_id (ts_id,inst_id,flag_name) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( +ts_id bigint(20) default NULL, +inst_id tinyint(4) default NULL, +flag_name varchar(64) default NULL, +flag_value text, +UNIQUE KEY ts_id (ts_id,inst_id,flag_name) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES +(111056548820001, 0, 'flag1', NULL), +(111056548820001, 0, 'flag2', NULL), +(2, 0, 'other_flag', NULL); +INSERT INTO t2 VALUES +(111056548820001, 3, 'flag1', 'sss'); +SELECT t1.flag_name,t2.flag_value +FROM t1 LEFT JOIN t2 +ON (t1.ts_id = t2.ts_id AND t1.flag_name = t2.flag_name AND +t2.inst_id = 3) +WHERE t1.inst_id = 0 AND t1.ts_id=111056548820001 AND +t2.flag_value IS NULL; +flag_name flag_value +flag2 NULL +DROP TABLE t1,t2; +CREATE TABLE t1 ( +id int(11) unsigned NOT NULL auto_increment, +text_id int(10) unsigned default NULL, +PRIMARY KEY (id) +); +INSERT INTO t1 VALUES("1", "0"); +INSERT INTO t1 VALUES("2", "10"); +CREATE TABLE t2 ( +text_id char(3) NOT NULL default '', +language_id char(3) NOT NULL default '', +text_data text, +PRIMARY KEY (text_id,language_id) +); +INSERT INTO t2 VALUES("0", "EN", "0-EN"); +INSERT INTO t2 VALUES("0", "SV", "0-SV"); +INSERT INTO t2 VALUES("10", "EN", "10-EN"); +INSERT INTO t2 VALUES("10", "SV", "10-SV"); +SELECT t1.id, t1.text_id, t2.text_data +FROM t1 LEFT JOIN t2 +ON t1.text_id = t2.text_id +AND t2.language_id = 'SV' + WHERE (t1.id LIKE '%' OR t2.text_data LIKE '%'); +id text_id text_data +1 0 0-SV +2 10 10-SV +DROP TABLE t1, t2; +CREATE TABLE t0 (a0 int PRIMARY KEY); +CREATE TABLE t1 (a1 int PRIMARY KEY); +CREATE TABLE t2 (a2 int); +CREATE TABLE t3 (a3 int); +INSERT INTO t0 VALUES (1); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); +SELECT * FROM t1 LEFT JOIN t2 ON a1=0; +a1 a2 +1 NULL +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON a1=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0; +a1 a2 a3 +1 NULL NULL +EXPLAIN SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 +SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1; +a0 a1 a2 a3 +1 1 NULL NULL +EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 index PRIMARY PRIMARY 4 NULL 1 Using index +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t0.a0 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 +INSERT INTO t0 VALUES (0); +INSERT INTO t1 VALUES (0); +SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1; +a0 a1 a2 a3 +1 1 NULL NULL +EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 const PRIMARY PRIMARY 4 const 1 Using index +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 +drop table t1,t2; +create table t1 (a int, b int); +insert into t1 values (1,1),(2,2),(3,3); +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2); +select * from t2 right join t1 on t2.a=t1.a; +a b a b +1 1 1 1 +2 2 2 2 +NULL NULL 3 3 +select straight_join * from t2 right join t1 on t2.a=t1.a; +a b a b +1 1 1 1 +2 2 2 2 +NULL NULL 3 3 +DROP TABLE t0,t1,t2,t3; +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (4,2); +INSERT INTO t2 VALUES (1,2), (2,2); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a; +a b a b +1 1 1 2 +2 1 2 2 +3 1 NULL NULL +4 2 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE t1.b=1; +a b a b +1 1 1 2 +2 1 2 2 +3 1 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a +WHERE t1.b=1 XOR (NOT ISNULL(t2.a) AND t2.b=1); +a b a b +1 1 1 2 +2 1 2 2 +3 1 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE not(0+(t1.a=30 and t2.b=1)); +a b a b +1 1 1 2 +2 1 2 2 +3 1 NULL NULL +4 2 NULL NULL +DROP TABLE t1,t2; +set group_concat_max_len=5; +create table t1 (a int, b varchar(20)); +create table t2 (a int, c varchar(20)); +insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); +insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); +select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; +group_concat(t1.b,t2.c) +aaaaa +bbbbb +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; +group_concat(t1.b,t2.c) +aaaaa +bbbbb +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; +group_concat(t1.b,t2.c) +aaaaa +bbbbb +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a; +group_concat(t1.b,t2.c) +aaaaa +bbbbb +Warnings: +Warning 1260 2 line(s) were cut by GROUP_CONCAT() +drop table t1, t2; +set group_concat_max_len=default; +create table t1 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, art int(11) not null, primary key (gid,x,y)); +insert t1 values (1, -5, -8, 2), (1, 2, 2, 1), (1, 1, 1, 1); +create table t2 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, id int(11) not null, primary key (gid,id,x,y), key id (id)); +insert t2 values (1, -5, -8, 1), (1, 1, 1, 1), (1, 2, 2, 1); +create table t3 ( set_id smallint(5) unsigned not null, id tinyint(4) unsigned not null, name char(12) not null, primary key (id,set_id)); +insert t3 values (0, 1, 'a'), (1, 1, 'b'), (0, 2, 'c'), (1, 2, 'd'), (1, 3, 'e'), (1, 4, 'f'), (1, 5, 'g'), (1, 6, 'h'); +explain select name from t1 left join t2 on t1.x = t2.x and t1.y = t2.y +left join t3 on t1.art = t3.id where t2.id =1 and t2.x = -5 and t2.y =-8 +and t1.gid =1 and t2.gid =1 and t3.set_id =1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 10 const,const,const 1 +1 SIMPLE t2 const PRIMARY,id PRIMARY 14 const,const,const,const 1 Using index +1 SIMPLE t3 const PRIMARY PRIMARY 3 const,const 1 +drop tables t1,t2,t3; +CREATE TABLE t1 (EMPNUM INT, GRP INT); +INSERT INTO t1 VALUES (0, 10); +INSERT INTO t1 VALUES (2, 30); +CREATE TABLE t2 (EMPNUM INT, NAME CHAR(5)); +INSERT INTO t2 VALUES (0, 'KERI'); +INSERT INTO t2 VALUES (9, 'BARRY'); +CREATE VIEW v1 AS +SELECT COALESCE(t2.EMPNUM,t1.EMPNUM) AS EMPNUM, NAME, GRP +FROM t2 LEFT OUTER JOIN t1 ON t2.EMPNUM=t1.EMPNUM; +SELECT * FROM v1; +EMPNUM NAME GRP +0 KERI 10 +9 BARRY NULL +SELECT * FROM v1 WHERE EMPNUM < 10; +EMPNUM NAME GRP +0 KERI 10 +9 BARRY NULL +DROP VIEW v1; +DROP TABLE t1,t2; +CREATE TABLE t1 (c11 int); +CREATE TABLE t2 (c21 int); +INSERT INTO t1 VALUES (30), (40), (50); +INSERT INTO t2 VALUES (300), (400), (500); +SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40; +c11 c21 +40 NULL +DROP TABLE t1, t2; +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +DROP TABLE t1,t2; +DROP VIEW IF EXISTS v1,v2; +DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (a int); +CREATE table t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (1), (1), (3); +INSERT INTO t2 VALUES (2), (3); +CREATE VIEW v1 AS SELECT a FROM t1 JOIN t2 ON t1.a=t2.b; +CREATE VIEW v2 AS SELECT b FROM t2 JOIN t1 ON t2.b=t1.a; +SELECT v1.a, v2. b +FROM v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) +GROUP BY v1.a; +a b +2 NULL +3 3 +SELECT v1.a, v2. b +FROM { OJ v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) } +GROUP BY v1.a; +a b +2 NULL +3 3 +DROP VIEW v1,v2; +DROP TABLE t1,t2; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (2), (3); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1); +a b +1 NULL +2 2 +3 3 +4 NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1 OR 1); +a b +1 NULL +2 2 +3 3 +4 NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (0 OR 1); +a b +1 NULL +2 2 +3 3 +4 NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 2=2); +a b +1 NULL +2 2 +3 3 +4 NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 1=0); +a b +1 NULL +2 2 +3 3 +4 NULL +DROP TABLE t1,t2; diff --git a/mysql-test/suite/pbxt/r/key.result b/mysql-test/suite/pbxt/r/key.result new file mode 100644 index 00000000000..0b964a84a4b --- /dev/null +++ b/mysql-test/suite/pbxt/r/key.result @@ -0,0 +1,484 @@ +drop table if exists t1,t2,t3; +SET SQL_WARNINGS=1; +CREATE TABLE t1 ( +ID CHAR(32) NOT NULL, +name CHAR(32) NOT NULL, +value CHAR(255), +INDEX indexIDname (ID(8),name(8)) +) ; +INSERT INTO t1 VALUES +('keyword','indexdir','/export/home/local/www/database/indexes/keyword'); +INSERT INTO t1 VALUES ('keyword','urlprefix','text/ /text'); +INSERT INTO t1 VALUES ('keyword','urlmap','/text/ /'); +INSERT INTO t1 VALUES ('keyword','attr','personal employee company'); +INSERT INTO t1 VALUES +('emailgids','indexdir','/export/home/local/www/database/indexes/emailgids'); +INSERT INTO t1 VALUES ('emailgids','urlprefix','text/ /text'); +INSERT INTO t1 VALUES ('emailgids','urlmap','/text/ /'); +INSERT INTO t1 VALUES ('emailgids','attr','personal employee company'); +SELECT value FROM t1 WHERE ID='emailgids' AND name='attr'; +value +personal employee company +drop table t1; +CREATE TABLE t1 ( +price int(5) DEFAULT '0' NOT NULL, +area varchar(40) DEFAULT '' NOT NULL, +type varchar(40) DEFAULT '' NOT NULL, +transityes enum('Y','N') DEFAULT 'Y' NOT NULL, +shopsyes enum('Y','N') DEFAULT 'Y' NOT NULL, +schoolsyes enum('Y','N') DEFAULT 'Y' NOT NULL, +petsyes enum('Y','N') DEFAULT 'Y' NOT NULL, +KEY price (price,area,type,transityes,shopsyes,schoolsyes,petsyes) +); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','N','N','N','N'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','N','N','N','N'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','','','',''); +Warnings: +Warning 1265 Data truncated for column 'transityes' at row 1 +Warning 1265 Data truncated for column 'shopsyes' at row 1 +Warning 1265 Data truncated for column 'schoolsyes' at row 1 +Warning 1265 Data truncated for column 'petsyes' at row 1 +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +SELECT * FROM t1 WHERE area='Vancouver' and transityes='y' and schoolsyes='y' and ( ((type='1 Bedroom' or type='Studio/Bach') and (price<=500)) or ((type='2 Bedroom') and (price<=550)) or ((type='Shared/Roomate') and (price<=300)) or ((type='Room and Board') and (price<=500)) ) and price <= 400; +price area type transityes shopsyes schoolsyes petsyes +drop table t1; +CREATE TABLE t1 (program enum('signup','unique','sliding') not null, type enum('basic','sliding','signup'), sites set('mt'), PRIMARY KEY (program)); +ALTER TABLE t1 modify program enum('signup','unique','sliding'); +drop table t1; +CREATE TABLE t1 ( +name varchar(50) DEFAULT '' NOT NULL, +author varchar(50) DEFAULT '' NOT NULL, +category decimal(10,0) DEFAULT '0' NOT NULL, +email varchar(50), +password varchar(50), +proxy varchar(50), +bitmap varchar(20), +msg varchar(255), +urlscol varchar(127), +urlhttp varchar(127), +timeout decimal(10,0), +nbcnx decimal(10,0), +creation decimal(10,0), +livinguntil decimal(10,0), +lang decimal(10,0), +type decimal(10,0), +subcat decimal(10,0), +subtype decimal(10,0), +reg char(1), +scs varchar(255), +capacity decimal(10,0), +userISP varchar(50), +CCident varchar(50) DEFAULT '' NOT NULL, +PRIMARY KEY (name,author,category) +); +INSERT INTO t1 VALUES +('patnom','patauteur',0,'p.favre@cryo-networks.fr',NULL,NULL,'#p2sndnq6ae5g1u6t','essai salut','scol://195.242.78.119:patauteur.patnom',NULL,NULL,NULL,950036174,-882087474,NULL,3,0,3,'1','Pub/patnom/futur_divers.scs',NULL,'pat','CC1'); +INSERT INTO t1 VALUES +('LeNomDeMonSite','Marc',0,'m.barilley@cryo-networks.fr',NULL,NULL,NULL,NULL,'scol://195.242.78.119:Marc.LeNomDeMonSite',NULL,NULL,NULL,950560434,-881563214,NULL,3,0,3,'1','Pub/LeNomDeMonSite/domus_hibere.scs',NULL,'Marq','CC1'); +select * from t1 where name='patnom' and author='patauteur' and category=0; +name author category email password proxy bitmap msg urlscol urlhttp timeout nbcnx creation livinguntil lang type subcat subtype reg scs capacity userISP CCident +patnom patauteur 0 p.favre@cryo-networks.fr NULL NULL #p2sndnq6ae5g1u6t essai salut scol://195.242.78.119:patauteur.patnom NULL NULL NULL 950036174 -882087474 NULL 3 0 3 1 Pub/patnom/futur_divers.scs NULL pat CC1 +drop table t1; +create table t1 +( +name_id int not null auto_increment, +name blob, +INDEX name_idx (name(5)), +primary key (name_id) +); +INSERT t1 VALUES(NULL,'/'); +INSERT t1 VALUES(NULL,'[T,U]_axpby'); +SELECT * FROM t1 WHERE name='[T,U]_axpy'; +name_id name +SELECT * FROM t1 WHERE name='[T,U]_axpby'; +name_id name +2 [T,U]_axpby +create table t2 +( +name_id int not null auto_increment, +name char(255) binary, +INDEX name_idx (name(5)), +primary key (name_id) +); +INSERT t2 select * from t1; +SELECT * FROM t2 WHERE name='[T,U]_axpy'; +name_id name +SELECT * FROM t2 WHERE name='[T,U]_axpby'; +name_id name +2 [T,U]_axpby +CREATE TABLE t3 SELECT * FROM t2 WHERE name='[T,U]_axpby'; +SELECT * FROM t2 WHERE name='[T,U]_axpby'; +name_id name +2 [T,U]_axpby +drop table t1,t2,t3; +create table t1 +( +SEQNO numeric(12 ) not null, +MOTYPEID numeric(12 ) not null, +MOINSTANCEID numeric(12 ) not null, +ATTRID numeric(12 ) not null, +VALUE varchar(120) not null, +primary key (SEQNO, MOTYPEID, MOINSTANCEID, ATTRID, VALUE ) +); +INSERT INTO t1 VALUES (1, 1, 1, 1, 'a'); +INSERT INTO t1 VALUES (1, 1, 1, 1, 'b'); +INSERT INTO t1 VALUES (1, 1, 1, 1, 'a'); +ERROR 23000: Duplicate entry '1-1-1-1-a' for key 'PRIMARY' +drop table t1; +CREATE TABLE t1 ( +a tinytext NOT NULL, +b tinyint(3) unsigned NOT NULL default '0', +PRIMARY KEY (a(32),b) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('a',1),('a',2); +SELECT * FROM t1 WHERE a='a' AND b=2; +a b +a 2 +SELECT * FROM t1 WHERE a='a' AND b in (2); +a b +a 2 +SELECT * FROM t1 WHERE a='a' AND b in (1,2); +a b +a 1 +a 2 +drop table t1; +create table t1 (a int not null unique, b int unique, c int, d int not null primary key, key(c), e int not null unique); +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 d A 0 NULL NULL BTREE +t1 0 a 1 a A 0 NULL NULL BTREE +t1 0 e 1 e A 0 NULL NULL BTREE +t1 0 b 1 b A 0 NULL NULL YES BTREE +t1 1 c 1 c A NULL NULL NULL YES BTREE +drop table t1; +CREATE TABLE t1 (c CHAR(10) NOT NULL,i INT NOT NULL AUTO_INCREMENT, +UNIQUE (c,i)); +INSERT INTO t1 (c) VALUES (NULL),(NULL); +Warnings: +Warning 1048 Column 'c' cannot be null +Warning 1048 Column 'c' cannot be null +SELECT * FROM t1; +c i + 1 + 2 +INSERT INTO t1 (c) VALUES ('a'),('a'); +SELECT * FROM t1; +c i + 1 + 2 +a 3 +a 4 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c CHAR(10) NULL, i INT NOT NULL AUTO_INCREMENT, +UNIQUE (c,i)); +INSERT INTO t1 (c) VALUES (NULL),(NULL); +SELECT * FROM t1; +c i +NULL 1 +NULL 2 +INSERT INTO t1 (c) VALUES ('a'),('a'); +SELECT * FROM t1; +c i +NULL 1 +NULL 2 +a 3 +a 4 +drop table t1; +create table t1 (i int, a char(200), b text, unique (a), unique (b(300))) charset utf8; +insert t1 values (1, repeat('a',210), repeat('b', 310)); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +insert t1 values (2, repeat(0xD0B1,215), repeat(0xD0B1, 310)); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +select i, length(a), length(b), char_length(a), char_length(b) from t1; +i length(a) length(b) char_length(a) char_length(b) +1 200 310 200 310 +2 400 620 200 310 +select i from t1 where a=repeat(_utf8 'a',200); +i +1 +select i from t1 where a=repeat(_utf8 0xD0B1,200); +i +2 +select i from t1 where b=repeat(_utf8 'b',310); +i +1 +drop table t1; +CREATE TABLE t1 (id int unsigned auto_increment, name char(50), primary key (id)) engine=myisam; +insert into t1 (name) values ('a'), ('b'),('c'),('d'),('e'),('f'),('g'); +explain select 1 from t1 where id =2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index +explain select 1 from t1 where id =2 or id=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 7 Using where; Using index +explain select name from t1 where id =2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +ALTER TABLE t1 DROP PRIMARY KEY, ADD INDEX (id); +explain select 1 from t1 where id =2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref id id 4 const 1 Using index +drop table t1; +CREATE TABLE t1 (numeropost mediumint(8) unsigned NOT NULL default '0', numreponse int(10) unsigned NOT NULL auto_increment, PRIMARY KEY (numeropost,numreponse), UNIQUE KEY numreponse (numreponse)); +INSERT INTO t1 (numeropost,numreponse) VALUES ('1','1'),('1','2'),('2','3'),('2','4'); +SELECT numeropost FROM t1 WHERE numreponse='1'; +numeropost +1 +EXPLAIN SELECT numeropost FROM t1 WHERE numreponse='1'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const numreponse numreponse 4 const 1 Using index +FLUSH TABLES; +SELECT numeropost FROM t1 WHERE numreponse='1'; +numeropost +1 +drop table t1; +create table t1 (c varchar(30) character set utf8, t text character set utf8, unique (c(2)), unique (t(3))) engine=myisam; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` varchar(30) CHARACTER SET utf8 DEFAULT NULL, + `t` text CHARACTER SET utf8, + UNIQUE KEY `c` (`c`(2)), + UNIQUE KEY `t` (`t`(3)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert t1 values ('cccc', 'tttt'), +(0xD0B1212223D0B1D0B1D0B1D0B1D0B1, 0xD0B1D0B1212223D0B1D0B1D0B1D0B1), +(0xD0B1222123D0B1D0B1D0B1D0B1D0B1, 0xD0B1D0B1222123D0B1D0B1D0B1D0B1); +insert t1 (c) values ('cc22'); +ERROR 23000: Duplicate entry 'cc22' for key 'c' +insert t1 (t) values ('ttt22'); +ERROR 23000: Duplicate entry 'ttt22' for key 't' +insert t1 (c) values (0xD0B1212322D0B1D0B1D0B1D0B1D0B1); +ERROR 23000: Duplicate entry 'б!#"Ð' for key 'c' +insert t1 (t) values (0xD0B1D0B1212322D0B1D0B1D0B1D0B1); +ERROR 23000: Duplicate entry 'бб!#"б' for key 't' +select c from t1 where c='cccc'; +c +cccc +select t from t1 where t='tttt'; +t +tttt +select c from t1 where c=0xD0B1212223D0B1D0B1D0B1D0B1D0B1; +c +?!"#????? +select t from t1 where t=0xD0B1D0B1212223D0B1D0B1D0B1D0B1; +t +??!"#???? +drop table t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 ( +c1 int, +c2 varbinary(240), +UNIQUE KEY (c1), +KEY (c2) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,'\Z\Z\Z\Z'); +INSERT INTO t1 VALUES (2,'\Z\Z\Z\Z\Z\Z'); +INSERT INTO t1 VALUES (3,'\Z\Z\Z\Z'); +select c1 from t1 where c2='\Z\Z\Z\Z'; +c1 +1 +3 +DELETE FROM t1 WHERE (c1 = 1); +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select c1 from t1 where c2='\Z\Z\Z\Z'; +c1 +3 +DELETE FROM t1 WHERE (c1 = 3); +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +select c1 from t1 where c2='\Z\Z\Z\Z'; +c1 +truncate table t1; +insert into t1 values(1,"aaaa"),(2,"aaab"),(3,"aaac"),(4,"aaccc"); +delete from t1 where c1=3; +delete from t1 where c1=1; +delete from t1 where c1=4; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (c char(10), index (c(0))); +ERROR HY000: Key part 'c' length cannot be 0 +create table t1 (c char(10), index (c,c)); +ERROR 42S21: Duplicate column name 'c' +create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)); +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10), index (c1,c1,c2)); +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10), index (c2,c1,c1)); +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10)); +alter table t1 add key (c1,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c2,c1,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c1,c2,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c1,c1,c2); +ERROR 42S21: Duplicate column name 'c1' +drop table t1; +create table t1 ( +i1 INT NOT NULL, +i2 INT NOT NULL, +UNIQUE i1idx (i1), +UNIQUE i2idx (i2)); +desc t1; +Field Type Null Key Default Extra +i1 int(11) NO PRI NULL +i2 int(11) NO UNI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i1` int(11) NOT NULL, + `i2` int(11) NOT NULL, + UNIQUE KEY `i1idx` (`i1`), + UNIQUE KEY `i2idx` (`i2`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +c1 int, +c2 varchar(20) not null, +primary key (c1), +key (c2(10)) +) engine=myisam; +insert into t1 values (1,''); +insert into t1 values (2,' \t\tTest String'); +insert into t1 values (3,' \n\tTest String'); +update t1 set c2 = 'New Test String' where c1 = 1; +select * from t1; +c1 c2 +1 New Test String +2 Test String +3 + Test String +drop table t1; +create table t1 (a varchar(10), b varchar(10), key(a(10),b(10))); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(10) DEFAULT NULL, + `b` varchar(10) DEFAULT NULL, + KEY `a` (`a`,`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table t1 modify b varchar(20); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(10) DEFAULT NULL, + `b` varchar(20) DEFAULT NULL, + KEY `a` (`a`,`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table t1 modify a varchar(20); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(20) DEFAULT NULL, + `b` varchar(20) DEFAULT NULL, + KEY `a` (`a`,`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null unique); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI NULL +b varchar(20) NO UNI NULL +drop table t1; +create table t1 (a int not null primary key, b int not null unique); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI NULL +b int(11) NO UNI NULL +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null, unique (b(10))); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI NULL +b varchar(20) NO UNI NULL +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null, c varchar(20) not null, unique(b(10),c(10))); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI NULL +b varchar(20) NO MUL NULL +c varchar(20) NO NULL +drop table t1; +create table t1 ( +c1 int, +c2 char(12), +c3 varchar(123), +c4 timestamp, +index (c1), +index i1 (c1), +index i2 (c2), +index i3 (c3), +unique i4 (c4), +index i5 (c1, c2, c3, c4), +primary key (c2, c3), +index (c2, c4)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) DEFAULT NULL, + `c2` char(12) NOT NULL DEFAULT '', + `c3` varchar(123) NOT NULL DEFAULT '', + `c4` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`c2`,`c3`), + UNIQUE KEY `i4` (`c4`), + KEY `c1` (`c1`), + KEY `i1` (`c1`), + KEY `i2` (`c2`), + KEY `i3` (`c3`), + KEY `i5` (`c1`,`c2`,`c3`,`c4`), + KEY `c2` (`c2`,`c4`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table t1 drop index c1; +alter table t1 add index (c1); +alter table t1 add index (c1); +alter table t1 drop index i3; +alter table t1 add index i3 (c3); +alter table t1 drop index i2, drop index i4; +alter table t1 add index i2 (c2), add index i4 (c4); +alter table t1 drop index i2, drop index i4, add index i6 (c2, c4); +alter table t1 add index i2 (c2), add index i4 (c4), drop index i6; +alter table t1 drop index i2, drop index i4, add unique i4 (c4); +alter table t1 add index i2 (c2), drop index i4, add index i4 (c4); +alter table t1 drop index c2, add index (c2(4),c3(7)); +alter table t1 drop index c2, add index (c2(4),c3(7)); +alter table t1 add primary key (c1, c2), drop primary key; +alter table t1 drop primary key; +alter table t1 add primary key (c1, c2), drop primary key; +ERROR 42000: Can't DROP 'PRIMARY'; check that column/key exists +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL DEFAULT '0', + `c2` char(12) NOT NULL DEFAULT '', + `c3` varchar(123) NOT NULL DEFAULT '', + `c4` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + KEY `i1` (`c1`), + KEY `i5` (`c1`,`c2`,`c3`,`c4`), + KEY `c1` (`c1`), + KEY `c1_2` (`c1`), + KEY `i3` (`c3`), + KEY `i2` (`c2`), + KEY `i4` (`c4`), + KEY `c2` (`c2`(4),`c3`(7)) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert into t1 values(1, 'a', 'a', NULL); +insert into t1 values(1, 'b', 'b', NULL); +alter table t1 drop index i3, drop index i2, drop index i1; +alter table t1 add index i3 (c3), add index i2 (c2), add unique index i1 (c1); +ERROR 23000: Duplicate entry '1' for key 'i1' +drop table t1; diff --git a/mysql-test/suite/pbxt/r/key_cache.result b/mysql-test/suite/pbxt/r/key_cache.result new file mode 100644 index 00000000000..8d71c6ce930 --- /dev/null +++ b/mysql-test/suite/pbxt/r/key_cache.result @@ -0,0 +1,324 @@ +drop table if exists t1, t2, t3; +SET @save_key_buffer=@@key_buffer_size; +SELECT @@key_buffer_size, @@small.key_buffer_size; +@@key_buffer_size @@small.key_buffer_size +1048576 0 +SET @@global.key_buffer_size=16*1024*1024; +SET @@global.default.key_buffer_size=16*1024*1024; +SET @@global.default.key_buffer_size=16*1024*1024; +SET @@global.small.key_buffer_size=1*1024*1024; +SET @@global.medium.key_buffer_size=4*1024*1024; +SET @@global.medium.key_buffer_size=0; +SET @@global.medium.key_buffer_size=0; +SHOW VARIABLES like "key_buffer_size"; +Variable_name Value +key_buffer_size 16777216 +SELECT @@key_buffer_size; +@@key_buffer_size +16777216 +SELECT @@global.key_buffer_size; +@@global.key_buffer_size +16777216 +SELECT @@global.default.key_buffer_size; +@@global.default.key_buffer_size +16777216 +SELECT @@global.default.`key_buffer_size`; +@@global.default.`key_buffer_size` +16777216 +SELECT @@global.`default`.`key_buffer_size`; +@@global.`default`.`key_buffer_size` +16777216 +SELECT @@`default`.key_buffer_size; +@@`default`.key_buffer_size +16777216 +SELECT @@small.key_buffer_size; +@@small.key_buffer_size +1048576 +SELECT @@medium.key_buffer_size; +@@medium.key_buffer_size +0 +SET @@global.key_buffer_size=@save_key_buffer; +SELECT @@default.key_buffer_size; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'default.key_buffer_size' at line 1 +SELECT @@skr.storage_engine="test"; +ERROR HY000: Variable 'storage_engine' is not a variable component (can't be used as XXXX.variable_name) +select @@keycache1.key_cache_block_size; +@@keycache1.key_cache_block_size +0 +select @@keycache1.key_buffer_size; +@@keycache1.key_buffer_size +0 +set global keycache1.key_cache_block_size=2048; +select @@keycache1.key_buffer_size; +@@keycache1.key_buffer_size +0 +select @@keycache1.key_cache_block_size; +@@keycache1.key_cache_block_size +2048 +set global keycache1.key_buffer_size=1*1024*1024; +select @@keycache1.key_buffer_size; +@@keycache1.key_buffer_size +1048576 +select @@keycache1.key_cache_block_size; +@@keycache1.key_cache_block_size +2048 +set global keycache2.key_buffer_size=4*1024*1024; +select @@keycache2.key_buffer_size; +@@keycache2.key_buffer_size +4194304 +select @@keycache2.key_cache_block_size; +@@keycache2.key_cache_block_size +1024 +set global keycache1.key_buffer_size=0; +select @@keycache1.key_buffer_size; +@@keycache1.key_buffer_size +0 +select @@keycache1.key_cache_block_size; +@@keycache1.key_cache_block_size +2048 +select @@key_buffer_size; +@@key_buffer_size +1048576 +select @@key_cache_block_size; +@@key_cache_block_size +1024 +set global keycache1.key_buffer_size=1024*1024; +create table t1 (p int primary key, a char(10)) delay_key_write=1; +create table t2 (p int primary key, i int, a char(10), key k1(i), key k2(a)); +insert into t1 values (1, 'qqqq'), (11, 'yyyy'); +insert into t2 values (1, 1, 'qqqq'), (2, 1, 'pppp'), +(3, 1, 'yyyy'), (4, 3, 'zzzz'); +select * from t1; +p a +1 qqqq +11 yyyy +select * from t2; +p i a +1 1 qqqq +2 1 pppp +3 1 yyyy +4 3 zzzz +update t1 set p=2 where p=1; +update t2 set i=2 where i=1; +cache index t1 key (`primary`) in keycache1; +Table Op Msg_type Msg_text +test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +explain select p from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index +select p from t1; +p +2 +11 +explain select i from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL k1 5 NULL 4 Using index +select i from t2; +i +2 +2 +2 +3 +explain select count(*) from t1, t2 where t1.p = t2.i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 2 Using index +1 SIMPLE t2 ref k1 k1 5 test.t1.p 2 Using where; Using index +select count(*) from t1, t2 where t1.p = t2.i; +count(*) +3 +cache index t2 in keycache1; +Table Op Msg_type Msg_text +test.t2 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +update t2 set p=p+1000, i=2 where a='qqqq'; +cache index t2 in keycache2; +Table Op Msg_type Msg_text +test.t2 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +insert into t2 values (2000, 3, 'yyyy'); +cache index t2 in keycache1; +Table Op Msg_type Msg_text +test.t2 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +update t2 set p=3000 where a='zzzz'; +select * from t2 order by p; +p i a +2 2 pppp +3 2 yyyy +1001 2 qqqq +2000 3 yyyy +3000 3 zzzz +explain select p from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL PRIMARY 4 NULL 5 Using index +select p from t2; +p +2 +3 +1001 +2000 +3000 +explain select i from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL k1 5 NULL 5 Using index +select i from t2; +i +2 +2 +2 +3 +3 +explain select a from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL k2 11 NULL 5 Using index +select a from t2; +a +pppp +qqqq +yyyy +yyyy +zzzz +cache index t1 in unknown_key_cache; +ERROR HY000: Unknown key cache 'unknown_key_cache' +cache index t1 key (unknown_key) in keycache1; +Table Op Msg_type Msg_text +test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +select @@keycache2.key_buffer_size; +@@keycache2.key_buffer_size +4194304 +select @@keycache2.key_cache_block_size; +@@keycache2.key_cache_block_size +1024 +set global keycache2.key_buffer_size=0; +select @@keycache2.key_buffer_size; +@@keycache2.key_buffer_size +0 +select @@keycache2.key_cache_block_size; +@@keycache2.key_cache_block_size +1024 +set global keycache2.key_buffer_size=1024*1024; +select @@keycache2.key_buffer_size; +@@keycache2.key_buffer_size +1048576 +update t2 set p=4000 where a='zzzz'; +update t1 set p=p+1; +set global keycache1.key_buffer_size=0; +select * from t2 order by p; +p i a +2 2 pppp +3 2 yyyy +1001 2 qqqq +2000 3 yyyy +4000 3 zzzz +select p from t2 order by p; +p +2 +3 +1001 +2000 +4000 +explain select i from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL k1 5 NULL 5 Using index +select i from t2; +i +2 +2 +2 +3 +3 +explain select a from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL k2 11 NULL 5 Using index +select a from t2; +a +pppp +qqqq +yyyy +yyyy +zzzz +select * from t1; +p a +12 yyyy +3 qqqq +select p from t1; +p +3 +12 +create table t3 (like t1); +cache index t3 in small; +Table Op Msg_type Msg_text +test.t3 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +insert into t3 select * from t1; +cache index t3 in keycache2; +Table Op Msg_type Msg_text +test.t3 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +cache index t1,t2 in default; +Table Op Msg_type Msg_text +test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +test.t2 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache +drop table t1,t2,t3; +set global keycache2.key_buffer_size=0; +set global keycache3.key_buffer_size=100; +Warnings: +Warning 1292 Truncated incorrect key_buffer_size value: '100' +set global keycache3.key_buffer_size=0; +create table t1 (mytext text, FULLTEXT (mytext)) engine=myisam; +insert t1 values ('aaabbb'); +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +set @my_key_cache_block_size= @@global.key_cache_block_size; +set GLOBAL key_cache_block_size=2048; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +set global key_cache_block_size= @my_key_cache_block_size; +CREATE TABLE t1(a int NOT NULL AUTO_INCREMENT PRIMARY KEY); +SET @my_key_cache_block_size= @@global.key_cache_block_size; +SET GLOBAL key_cache_block_size=1536; +INSERT INTO t1 VALUES (1); +SELECT @@key_cache_block_size; +@@key_cache_block_size +1536 +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +CREATE TABLE t1(a int NOT NULL AUTO_INCREMENT PRIMARY KEY, b int); +CREATE TABLE t2(a int NOT NULL AUTO_INCREMENT PRIMARY KEY, b int); +SET GLOBAL key_cache_block_size=1536; +INSERT INTO t1 VALUES (1,0); +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +SELECT COUNT(*) FROM t1; +COUNT(*) +4181 +SELECT @@key_cache_block_size; +@@key_cache_block_size +1536 +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1,t2; +set global key_cache_block_size= @my_key_cache_block_size; +set @@global.key_buffer_size=0; +Warnings: +Warning 1438 Cannot drop default keycache +select @@global.key_buffer_size; +@@global.key_buffer_size +1048576 diff --git a/mysql-test/suite/pbxt/r/key_diff.result b/mysql-test/suite/pbxt/r/key_diff.result new file mode 100644 index 00000000000..9d26bee4557 --- /dev/null +++ b/mysql-test/suite/pbxt/r/key_diff.result @@ -0,0 +1,52 @@ +drop table if exists t1; +CREATE TABLE t1 ( +a char(5) NOT NULL, +b char(4) NOT NULL, +KEY (a), +KEY (b) +); +INSERT INTO t1 VALUES ('A','B'),('b','A'),('C','c'),('D','E'),('a','a'); +select * from t1,t1 as t2; +a b a b +A B A B +b A A B +C c A B +D E A B +a a A B +A B b A +b A b A +C c b A +D E b A +a a b A +A B C c +b A C c +C c C c +D E C c +a a C c +A B D E +b A D E +C c D E +D E D E +a a D E +A B a a +b A a a +C c a a +D E a a +a a a a +explain select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 5 +1 SIMPLE t2 ALL b NULL NULL NULL 5 Using where; Using join buffer +select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B order by binary t1.a,t2.a; +a b a b +A B a a +A B b A +C c C c +a a a a +a a b A +b A A B +select * from t1 where a='a'; +a b +A B +a a +drop table t1; diff --git a/mysql-test/suite/pbxt/r/key_primary.result b/mysql-test/suite/pbxt/r/key_primary.result new file mode 100644 index 00000000000..7726a8e1d63 --- /dev/null +++ b/mysql-test/suite/pbxt/r/key_primary.result @@ -0,0 +1,20 @@ +drop table if exists t1; +create table t1 (t1 char(3) primary key); +insert into t1 values("ABC"); +insert into t1 values("ABA"); +insert into t1 values("AB%"); +select * from t1 where t1="ABC"; +t1 +ABC +select * from t1 where t1="ABCD"; +t1 +select * from t1 where t1 like "a_\%"; +t1 +AB% +describe select * from t1 where t1="ABC"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 3 const 1 Using index +describe select * from t1 where t1="ABCD"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +drop table t1; diff --git a/mysql-test/suite/pbxt/r/keywords.result b/mysql-test/suite/pbxt/r/keywords.result new file mode 100644 index 00000000000..597983dab7e --- /dev/null +++ b/mysql-test/suite/pbxt/r/keywords.result @@ -0,0 +1,34 @@ +drop table if exists t1; +create table t1 (time time, date date, timestamp timestamp, +quarter int, week int, year int, timestampadd int, timestampdiff int); +insert into t1 values ("12:22:22","97:02:03","1997-01-02",1,2,3,4,5); +select * from t1; +time date timestamp quarter week year timestampadd timestampdiff +12:22:22 1997-02-03 1997-01-02 00:00:00 1 2 3 4 5 +select t1.time+0,t1.date+0,t1.timestamp+0,concat(date," ",time), +t1.quarter+t1.week, t1.year+timestampadd, timestampdiff from t1; +t1.time+0 t1.date+0 t1.timestamp+0 concat(date," ",time) t1.quarter+t1.week t1.year+timestampadd timestampdiff +122222 19970203 19970102000000 1997-02-03 12:22:22 3 7 5 +drop table t1; +create table events(binlog int); +insert into events values(1); +select events.binlog from events; +binlog +1 +drop table events; +create procedure p1() +begin +declare n int default 2; +authors: while n > 0 do +set n = n -1; +end while authors; +end| +create procedure p2() +begin +declare n int default 2; +contributors: while n > 0 do +set n = n -1; +end while contributors; +end| +drop procedure p1; +drop procedure p2; diff --git a/mysql-test/suite/pbxt/r/limit.result b/mysql-test/suite/pbxt/r/limit.result new file mode 100644 index 00000000000..9bbf54fcfe9 --- /dev/null +++ b/mysql-test/suite/pbxt/r/limit.result @@ -0,0 +1,93 @@ +drop table if exists t1; +create table t1 (a int not null default 0 primary key, b int not null default 0); +insert into t1 () values (); +insert into t1 values (1,1),(2,1),(3,1); +update t1 set a=4 where b=1 limit 1; +select * from t1 order by a; +a b +0 0 +2 1 +3 1 +4 1 +update t1 set b=2 where b=1 limit 2; +select * from t1 order by a; +a b +0 0 +2 2 +3 2 +4 1 +update t1 set b=4 where b=1; +select * from t1 order by a; +a b +0 0 +2 2 +3 2 +4 4 +delete from t1 where b=2 limit 1; +select * from t1 order by a; +a b +0 0 +3 2 +4 4 +delete from t1 limit 1; +select * from t1 order by a; +a b +3 2 +4 4 +drop table t1; +create table t1 (i int); +insert into t1 (i) values(1),(1),(1); +delete from t1 limit 1; +update t1 set i=2 limit 1; +delete from t1 limit 0; +update t1 set i=3 limit 0; +select * from t1; +i +1 +2 +drop table t1; +select 0 limit 0; +0 +CREATE TABLE t1(id int auto_increment primary key, id2 int, index(id2)); +INSERT INTO t1 (id2) values (0),(0),(0); +DELETE FROM t1 WHERE id=1; +INSERT INTO t1 SET id2=0; +SELECT * FROM t1; +id id2 +2 0 +3 0 +4 0 +DELETE FROM t1 WHERE id2 = 0 ORDER BY id LIMIT 1; +SELECT * FROM t1; +id id2 +3 0 +4 0 +DELETE FROM t1 WHERE id2 = 0 ORDER BY id desc LIMIT 1; +SELECT * FROM t1; +id id2 +3 0 +DROP TABLE t1; +create table t1 (a integer); +insert into t1 values (1); +select 1 as a from t1 union all select 1 from dual limit 1; +a +1 +(select 1 as a from t1) union all (select 1 from dual) limit 1; +a +1 +drop table t1; +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6),(7); +explain select count(*) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where; Using temporary +select count(*) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3; +c +7 +explain select sum(a) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where; Using temporary +select sum(a) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3; +c +28 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/lock.result b/mysql-test/suite/pbxt/r/lock.result new file mode 100644 index 00000000000..2ece0b36b0c --- /dev/null +++ b/mysql-test/suite/pbxt/r/lock.result @@ -0,0 +1,78 @@ +drop table if exists t1,t2; +CREATE TABLE t1 ( `id` int(11) NOT NULL default '0', `id2` int(11) NOT NULL default '0', `id3` int(11) NOT NULL default '0', `dummy1` char(30) default NULL, PRIMARY KEY (`id`,`id2`), KEY `index_id3` (`id3`)) ENGINE=MyISAM; +insert into t1 (id,id2) values (1,1),(1,2),(1,3); +LOCK TABLE t1 WRITE; +select dummy1,count(distinct id) from t1 group by dummy1; +dummy1 count(distinct id) +NULL 1 +update t1 set id=-1 where id=1; +LOCK TABLE t1 READ; +update t1 set id=1 where id=1; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +create table t2 SELECT * from t1; +ERROR HY000: Table 't2' was not locked with LOCK TABLES +create temporary table t2 SELECT * from t1; +drop table if exists t2; +unlock tables; +create table t2 SELECT * from t1; +LOCK TABLE t1 WRITE,t2 write; +insert into t2 SELECT * from t1; +update t1 set id=1 where id=-1; +drop table t1,t2; +CREATE TABLE t1 ( +index1 smallint(6) default NULL, +nr smallint(6) default NULL, +KEY index1(index1) +) ENGINE=MyISAM; +CREATE TABLE t2 ( +nr smallint(6) default NULL, +name varchar(20) default NULL +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,'item1'); +INSERT INTO t2 VALUES (2,'item2'); +lock tables t1 write, t2 read; +insert into t1 select 1,nr from t2 where name='item1'; +insert into t1 select 2,nr from t2 where name='item2'; +unlock tables; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +lock tables t1 write; +check table t2; +Table Op Msg_type Msg_text +test.t2 check Error Table 't2' was not locked with LOCK TABLES +test.t2 check error Corrupt +insert into t1 select index1,nr from t1; +ERROR HY000: Table 't1' was not locked with LOCK TABLES +unlock tables; +lock tables t1 write, t1 as t1_alias read; +insert into t1 select index1,nr from t1 as t1_alias; +drop table t1,t2; +create table t1 (c1 int); +create table t2 (c1 int); +create table t3 (c1 int); +lock tables t1 write, t2 write, t3 write; +drop table t2, t3, t1; +create table t1 (c1 int); +create table t2 (c1 int); +create table t3 (c1 int); +lock tables t1 write, t2 write, t3 write, t1 as t4 read; +alter table t2 add column c2 int; +drop table t1, t2, t3; +create table t1 ( a int(11) not null auto_increment, primary key(a)); +create table t2 ( a int(11) not null auto_increment, primary key(a)); +lock tables t1 write, t2 read; +delete from t1 using t1,t2 where t1.a=t2.a; +delete t1 from t1,t2 where t1.a=t2.a; +delete from t2 using t1,t2 where t1.a=t2.a; +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +delete t2 from t1,t2 where t1.a=t2.a; +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +drop table t1,t2; +drop table if exists t1; +create table t1 (a int); +lock table t1 write; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +unlock tables; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/lock_multi.result b/mysql-test/suite/pbxt/r/lock_multi.result new file mode 100644 index 00000000000..3bb11bdf6ea --- /dev/null +++ b/mysql-test/suite/pbxt/r/lock_multi.result @@ -0,0 +1,96 @@ +drop table if exists t1,t2; +create table t1(n int); +insert into t1 values (1); +lock tables t1 write; +update low_priority t1 set n = 4; +select n from t1; +unlock tables; +n +1 +drop table t1; +create table t1(n int); +insert into t1 values (1); +lock tables t1 read; +update low_priority t1 set n = 4; +select n from t1; +unlock tables; +n +1 +drop table t1; +create table t1 (a int, b int); +create table t2 (c int, d int); +insert into t1 values(1,1); +insert into t1 values(2,2); +insert into t2 values(1,2); +lock table t1 read; +update t1,t2 set c=a where b=d; +select c from t2; +c +2 +drop table t1; +drop table t2; +create table t1 (a int); +create table t2 (a int); +lock table t1 write, t2 write; +insert t1 select * from t2; +drop table t2; +ERROR 42S02: Table 'test.t2' doesn't exist +drop table t1; +create table t1 (a int); +create table t2 (a int); +lock table t1 write, t2 write, t1 as t1_2 write, t2 as t2_2 write; +insert t1 select * from t2; +drop table t2; +ERROR 42S02: Table 'test.t2' doesn't exist +drop table t1; +create table t1(a int); +lock tables t1 write; +show columns from t1; +Field Type Null Key Default Extra +a int(11) YES NULL +unlock tables; +drop table t1; +use mysql; +LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; +FLUSH TABLES; +use mysql; +SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; +OPTIMIZE TABLES columns_priv, db, host, user; +Table Op Msg_type Msg_text +mysql.columns_priv optimize status OK +mysql.db optimize status OK +mysql.host optimize status OK +mysql.user optimize status OK +UNLOCK TABLES; +Select_priv +use test; +use test; +CREATE TABLE t1 (c1 int); +LOCK TABLE t1 WRITE; +FLUSH TABLES WITH READ LOCK; +CREATE TABLE t2 (c1 int); +UNLOCK TABLES; +UNLOCK TABLES; +DROP TABLE t1, t2; +CREATE TABLE t1 (c1 int); +LOCK TABLE t1 WRITE; +FLUSH TABLES WITH READ LOCK; +CREATE TABLE t2 AS SELECT * FROM t1; +ERROR HY000: Table 't2' was not locked with LOCK TABLES +UNLOCK TABLES; +UNLOCK TABLES; +DROP TABLE t1; +CREATE DATABASE mysqltest_1; +FLUSH TABLES WITH READ LOCK; +DROP DATABASE mysqltest_1; +DROP DATABASE mysqltest_1; +ERROR HY000: Can't execute the query because you have a conflicting read lock +UNLOCK TABLES; +DROP DATABASE mysqltest_1; +ERROR HY000: Can't drop database 'mysqltest_1'; database doesn't exist +create table t1 (f1 int(12) unsigned not null auto_increment, primary key(f1)) engine=innodb; +lock tables t1 write; +alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // +alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // +unlock tables; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/lock_tables_lost_commit.result b/mysql-test/suite/pbxt/r/lock_tables_lost_commit.result new file mode 100644 index 00000000000..22885d93d40 --- /dev/null +++ b/mysql-test/suite/pbxt/r/lock_tables_lost_commit.result @@ -0,0 +1,8 @@ +drop table if exists t1; +create table t1(a int) engine=innodb; +lock tables t1 write; +insert into t1 values(10); +select * from t1; +a +10 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/lowercase_table2.result b/mysql-test/suite/pbxt/r/lowercase_table2.result new file mode 100644 index 00000000000..98b5abaf754 --- /dev/null +++ b/mysql-test/suite/pbxt/r/lowercase_table2.result @@ -0,0 +1,176 @@ +DROP TABLE IF EXISTS t1,t2,t3,t2aA,t1Aa; +DROP DATABASE IF EXISTS `TEST_$1`; +DROP DATABASE IF EXISTS `test_$1`; +DROP DATABASE IF EXISTS mysqltest_LC2; +CREATE TABLE T1 (a int); +INSERT INTO T1 VALUES (1); +SHOW TABLES LIKE "T1"; +Tables_in_test (T1) +T1 +SHOW TABLES LIKE "t1"; +Tables_in_test (t1) +T1 +SHOW CREATE TABLE T1; +Table Create Table +T1 CREATE TABLE `T1` ( + `a` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +RENAME TABLE T1 TO T2; +SHOW TABLES LIKE "T2"; +Tables_in_test (T2) +T2 +SELECT * FROM t2; +a +1 +RENAME TABLE T2 TO t3; +SHOW TABLES LIKE "T3"; +Tables_in_test (T3) +t3 +RENAME TABLE T3 TO T1; +SHOW TABLES LIKE "T1"; +Tables_in_test (T1) +T1 +ALTER TABLE T1 add b int; +SHOW TABLES LIKE "T1"; +Tables_in_test (T1) +T1 +ALTER TABLE T1 RENAME T2; +SHOW TABLES LIKE "T2"; +Tables_in_test (T2) +T2 +LOCK TABLE T2 WRITE; +ALTER TABLE T2 drop b; +SHOW TABLES LIKE "T2"; +Tables_in_test (T2) +T2 +UNLOCK TABLES; +RENAME TABLE T2 TO T1; +SHOW TABLES LIKE "T1"; +Tables_in_test (T1) +T1 +SELECT * from T1; +a +1 +DROP TABLE T1; +CREATE DATABASE `TEST_$1`; +SHOW DATABASES LIKE "TEST%"; +Database (TEST%) +TEST_$1 +DROP DATABASE `test_$1`; +CREATE TABLE T1 (a int) engine=innodb; +INSERT INTO T1 VALUES (1); +SHOW TABLES LIKE "T1"; +Tables_in_test (T1) +T1 +SHOW TABLES LIKE "t1"; +Tables_in_test (t1) +T1 +SHOW CREATE TABLE T1; +Table Create Table +T1 CREATE TABLE `T1` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +RENAME TABLE T1 TO T2; +SHOW TABLES LIKE "T2"; +Tables_in_test (T2) +T2 +SELECT * FROM t2; +a +1 +RENAME TABLE T2 TO t3; +SHOW TABLES LIKE "T3"; +Tables_in_test (T3) +t3 +RENAME TABLE T3 TO T1; +SHOW TABLES LIKE "T1"; +Tables_in_test (T1) +T1 +ALTER TABLE T1 add b int; +SHOW TABLES LIKE "T1"; +Tables_in_test (T1) +T1 +ALTER TABLE T1 RENAME T2; +SHOW TABLES LIKE "T2"; +Tables_in_test (T2) +T2 +LOCK TABLE T2 WRITE; +ALTER TABLE T2 drop b; +SHOW TABLES LIKE "T2"; +Tables_in_test (T2) +T2 +UNLOCK TABLES; +RENAME TABLE T2 TO T1; +SHOW TABLES LIKE "T1"; +Tables_in_test (T1) +T1 +SELECT * from T1; +a +1 +DROP TABLE T1; +create table T1 (EVENT_ID int auto_increment primary key, LOCATION char(20)); +insert into T1 values (NULL,"Mic-4"),(NULL,"Mic-5"),(NULL,"Mic-6"); +SELECT LOCATION FROM T1 WHERE EVENT_ID=2 UNION ALL SELECT LOCATION FROM T1 WHERE EVENT_ID=3; +LOCATION +Mic-5 +Mic-6 +SELECT LOCATION FROM T1 WHERE EVENT_ID=2 UNION ALL SELECT LOCATION FROM T1 WHERE EVENT_ID=3; +LOCATION +Mic-5 +Mic-6 +SELECT LOCATION FROM T1 WHERE EVENT_ID=2 UNION ALL SELECT LOCATION FROM T1 WHERE EVENT_ID=3; +LOCATION +Mic-5 +Mic-6 +drop table T1; +create table T1 (A int); +alter table T1 add index (A); +show tables like 'T1%'; +Tables_in_test (T1%) +T1 +alter table t1 add index (A); +show tables like 't1%'; +Tables_in_test (t1%) +t1 +drop table t1; +create temporary table T1(a int(11), b varchar(8)); +insert into T1 values (1, 'abc'); +select * from T1; +a b +1 abc +alter table T1 add index (a); +select * from T1; +a b +1 abc +drop table T1; +create database mysqltest_LC2; +use mysqltest_LC2; +create table myUC (i int); +insert into myUC values (1),(2),(3); +select * from myUC; +i +1 +2 +3 +use test; +drop database mysqltest_LC2; +create database mysqltest_LC2; +use mysqltest_LC2; +create table myUC (i int); +select * from myUC; +i +use test; +drop database mysqltest_LC2; +create table t2aA (col1 int); +create table t1Aa (col1 int); +select t1Aa.col1 from t1aA,t2Aa where t1Aa.col1 = t2aA.col1; +col1 +drop table t2aA, t1Aa; +create database mysqltest_LC2; +use mysqltest_LC2; +create table myUC (i int); +select TABLE_SCHEMA,TABLE_NAME FROM information_schema.TABLES +where TABLE_SCHEMA ='mysqltest_LC2'; +TABLE_SCHEMA TABLE_NAME +mysqltest_LC2 myUC +use test; +drop database mysqltest_LC2; diff --git a/mysql-test/suite/pbxt/r/lowercase_table_grant.result b/mysql-test/suite/pbxt/r/lowercase_table_grant.result new file mode 100644 index 00000000000..afb54f8c472 --- /dev/null +++ b/mysql-test/suite/pbxt/r/lowercase_table_grant.result @@ -0,0 +1,23 @@ +use mysql; +create database MYSQLtest; +grant all on MySQLtest.* to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +select * from db where user = 'mysqltest_1'; +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv +localhost mysqltest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y +update db set db = 'MYSQLtest' where db = 'mysqltest' and user = 'mysqltest_1' and host = 'localhost'; +flush privileges; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +select * from db where user = 'mysqltest_1'; +Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv +localhost MYSQLtest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y +delete from db where db = 'MYSQLtest' and user = 'mysqltest_1' and host = 'localhost'; +flush privileges; +drop user mysqltest_1@localhost; +drop database MYSQLtest; diff --git a/mysql-test/suite/pbxt/r/lowercase_table_qcache.result b/mysql-test/suite/pbxt/r/lowercase_table_qcache.result new file mode 100644 index 00000000000..f8d34e0f592 --- /dev/null +++ b/mysql-test/suite/pbxt/r/lowercase_table_qcache.result @@ -0,0 +1,24 @@ +set GLOBAL query_cache_size=1355776; +drop database if exists MySQLtesT; +create database MySQLtesT; +create table MySQLtesT.t1 (a int); +select * from MySQLtesT.t1; +a +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +drop database mysqltest; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +use MySQL; +select * from db; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +use test; +select * from MySQL.db; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +set GLOBAL query_cache_size=0; diff --git a/mysql-test/suite/pbxt/r/lowercase_view.result b/mysql-test/suite/pbxt/r/lowercase_view.result new file mode 100644 index 00000000000..0debf20108a --- /dev/null +++ b/mysql-test/suite/pbxt/r/lowercase_view.result @@ -0,0 +1,150 @@ +drop table if exists t1Aa,t2Aa,v1Aa,v2Aa; +drop view if exists t1Aa,t2Aa,v1Aa,v2Aa; +drop database if exists MySQLTest; +create database MySQLTest; +use MySQLTest; +create table TaB (Field int); +create view ViE as select * from TAb; +show create table VIe; +View Create View character_set_client collation_connection +vie CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vie` AS select `tab`.`Field` AS `Field` from `tab` latin1 latin1_swedish_ci +drop database MySQLTest; +use test; +create table t1Aa (col1 int); +create table t2aA (col1 int); +create view v1Aa as select * from t1aA; +create view v2aA as select * from v1aA; +create view v3Aa as select v2Aa.col1 from v2aA,t2Aa where v2Aa.col1 = t2aA.col1; +update v2aA set col1 = (select max(col1) from v1Aa); +ERROR HY000: The definition of table 'v1Aa' prevents operation UPDATE on table 'v2aA'. +update v2Aa set col1 = (select max(col1) from t1Aa); +ERROR HY000: The definition of table 'v2Aa' prevents operation UPDATE on table 'v2Aa'. +update v2aA set col1 = (select max(col1) from v2Aa); +ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause +update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 'v2aA'. +update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v1Aa) where t1aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1Aa' prevents operation UPDATE on table 't1aA'. +update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 'v1aA' for update in FROM clause +update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from v1aA) where v2Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 't2Aa'. +update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v1Aa) where t1Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1Aa' prevents operation UPDATE on table 't2Aa'. +update t2Aa,v1aA set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 't2Aa'. +update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from t1aA) where v2aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 'v2aA'. +update t1Aa,t2Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 't1Aa' for update in FROM clause +update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from t1Aa) where v1aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 'v1aA'. +update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from t1aA) where v2Aa.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause +update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause +update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from t1Aa) where v1Aa.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause +update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause +update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v2aA) where t1aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 't1aA'. +update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v2Aa) where v1aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2Aa' prevents operation UPDATE on table 'v1aA'. +update t2Aa,v2aA set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 't2Aa'. +update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v2aA) where t1Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 't2Aa'. +update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from v2Aa) where v1Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2Aa' prevents operation UPDATE on table 't2Aa'. +update v3aA set v3Aa.col1 = (select max(col1) from v1aA); +ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 'v3aA'. +update v3aA set v3Aa.col1 = (select max(col1) from t1aA); +ERROR HY000: The definition of table 'v3aA' prevents operation UPDATE on table 'v3aA'. +update v3aA set v3Aa.col1 = (select max(col1) from v2aA); +ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 'v3aA'. +update v3aA set v3Aa.col1 = (select max(col1) from v3aA); +ERROR HY000: You can't specify target table 'v3aA' for update in FROM clause +delete from v2Aa where col1 = (select max(col1) from v1Aa); +ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 'v2Aa'. +delete from v2aA where col1 = (select max(col1) from t1Aa); +ERROR HY000: The definition of table 'v2aA' prevents operation DELETE on table 'v2aA'. +delete from v2Aa where col1 = (select max(col1) from v2aA); +ERROR HY000: You can't specify target table 'v2Aa' for update in FROM clause +delete v2Aa from v2aA,t2Aa where (select max(col1) from v1aA) > 0 and v2Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1aA' prevents operation DELETE on table 'v2aA'. +delete t1aA from t1Aa,t2Aa where (select max(col1) from v1Aa) > 0 and t1aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 't1Aa'. +delete v1aA from v1Aa,t2Aa where (select max(col1) from v1aA) > 0 and v1Aa.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 'v1Aa' for update in FROM clause +delete v2aA from v2Aa,t2Aa where (select max(col1) from t1Aa) > 0 and v2aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2Aa' prevents operation DELETE on table 'v2Aa'. +delete t1aA from t1Aa,t2Aa where (select max(col1) from t1aA) > 0 and t1Aa.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 't1Aa' for update in FROM clause +delete v1aA from v1Aa,t2Aa where (select max(col1) from t1aA) > 0 and v1aA.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 'v1Aa'. +delete v2Aa from v2aA,t2Aa where (select max(col1) from v2Aa) > 0 and v2aA.col1 = t2aA.col1; +ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause +delete t1Aa from t1aA,t2Aa where (select max(col1) from v2Aa) > 0 and t1Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2Aa' prevents operation DELETE on table 't1aA'. +delete v1Aa from v1aA,t2Aa where (select max(col1) from v2aA) > 0 and v1Aa.col1 = t2aA.col1; +ERROR HY000: The definition of table 'v2aA' prevents operation DELETE on table 'v1aA'. +insert into v2Aa values ((select max(col1) from v1aA)); +ERROR HY000: The definition of table 'v1aA' prevents operation INSERT on table 'v2Aa'. +insert into t1aA values ((select max(col1) from v1Aa)); +ERROR HY000: The definition of table 'v1Aa' prevents operation INSERT on table 't1aA'. +insert into v2aA values ((select max(col1) from v1aA)); +ERROR HY000: The definition of table 'v1aA' prevents operation INSERT on table 'v2aA'. +insert into v2Aa values ((select max(col1) from t1Aa)); +ERROR HY000: The definition of table 'v2Aa' prevents operation INSERT on table 'v2Aa'. +insert into t1aA values ((select max(col1) from t1Aa)); +ERROR HY000: You can't specify target table 't1aA' for update in FROM clause +insert into v2aA values ((select max(col1) from t1aA)); +ERROR HY000: The definition of table 'v2aA' prevents operation INSERT on table 'v2aA'. +insert into v2Aa values ((select max(col1) from v2aA)); +ERROR HY000: You can't specify target table 'v2Aa' for update in FROM clause +insert into t1Aa values ((select max(col1) from v2Aa)); +ERROR HY000: The definition of table 'v2Aa' prevents operation INSERT on table 't1Aa'. +insert into v2aA values ((select max(col1) from v2Aa)); +ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause +insert into v3Aa (col1) values ((select max(col1) from v1Aa)); +ERROR HY000: The definition of table 'v1Aa' prevents operation INSERT on table 'v3Aa'. +insert into v3aA (col1) values ((select max(col1) from t1aA)); +ERROR HY000: The definition of table 'v3aA' prevents operation INSERT on table 'v3aA'. +insert into v3Aa (col1) values ((select max(col1) from v2aA)); +ERROR HY000: The definition of table 'v2aA' prevents operation INSERT on table 'v3Aa'. +drop view v3aA,v2Aa,v1aA; +drop table t1Aa,t2Aa; +create table t1Aa (col1 int); +create view v1Aa as select col1 from t1Aa as AaA; +show create view v1AA; +View Create View character_set_client collation_connection +v1aa CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1aa` AS select `AaA`.`col1` AS `col1` from `t1aa` `AaA` latin1 latin1_swedish_ci +drop view v1AA; +select Aaa.col1 from t1Aa as AaA; +col1 +create view v1Aa as select Aaa.col1 from t1Aa as AaA; +drop view v1AA; +create view v1Aa as select AaA.col1 from t1Aa as AaA; +show create view v1AA; +View Create View character_set_client collation_connection +v1aa CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1aa` AS select `AaA`.`col1` AS `col1` from `t1aa` `AaA` latin1 latin1_swedish_ci +drop view v1AA; +drop table t1Aa; +CREATE TABLE t1 (a int, b int); +select X.a from t1 AS X group by X.b having (X.a = 1); +a +select X.a from t1 AS X group by X.b having (x.a = 1); +a +select X.a from t1 AS X group by X.b having (x.b = 1); +a +CREATE OR REPLACE VIEW v1 AS +select X.a from t1 AS X group by X.b having (X.a = 1); +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `X`.`a` AS `a` from `t1` `X` group by `X`.`b` having (`X`.`a` = 1) latin1 latin1_swedish_ci +SELECT * FROM v1; +a +DROP VIEW v1; +DROP TABLE t1; +End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/r/metadata.result b/mysql-test/suite/pbxt/r/metadata.result new file mode 100644 index 00000000000..c46c6e26ce4 --- /dev/null +++ b/mysql-test/suite/pbxt/r/metadata.result @@ -0,0 +1,132 @@ +drop table if exists t1,t2; +select 1, 1.0, -1, "hello", NULL; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def 1 8 1 1 N 32897 0 63 +def 1.0 246 4 3 N 129 1 63 +def -1 8 2 2 N 32897 0 63 +def hello 253 5 5 N 1 31 8 +def NULL 6 0 0 Y 32896 0 63 +1 1.0 -1 hello NULL +1 1.0 -1 hello NULL +create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp, l datetime, m enum('a','b'), n set('a','b'), o char(10)); +select * from t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 a a 1 4 0 Y 32768 0 63 +def test t1 t1 b b 2 6 0 Y 32768 0 63 +def test t1 t1 c c 9 9 0 Y 32768 0 63 +def test t1 t1 d d 3 11 0 Y 32768 0 63 +def test t1 t1 e e 8 20 0 Y 32768 0 63 +def test t1 t1 f f 4 3 0 Y 32768 2 63 +def test t1 t1 g g 5 4 0 Y 32768 3 63 +def test t1 t1 h h 246 7 0 Y 0 4 63 +def test t1 t1 i i 13 4 0 Y 32864 0 63 +def test t1 t1 j j 10 10 0 Y 128 0 63 +def test t1 t1 k k 7 19 0 N 9441 0 63 +def test t1 t1 l l 12 19 0 Y 128 0 63 +def test t1 t1 m m 254 1 0 Y 256 0 8 +def test t1 t1 n n 254 3 0 Y 2048 0 8 +def test t1 t1 o o 254 10 0 Y 0 0 8 +a b c d e f g h i j k l m n o +select a b, b c from t1 as t2; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t2 a b 1 4 0 Y 32768 0 63 +def test t1 t2 b c 2 6 0 Y 32768 0 63 +b c +drop table t1; +CREATE TABLE t1 (id tinyint(3) default NULL, data varchar(255) default NULL); +INSERT INTO t1 VALUES (1,'male'),(2,'female'); +CREATE TABLE t2 (id tinyint(3) unsigned default NULL, data char(3) default '0'); +INSERT INTO t2 VALUES (1,'yes'),(2,'no'); +select t1.id, t1.data, t2.data from t1, t2 where t1.id = t2.id; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 id id 1 3 1 Y 32768 0 63 +def test t1 t1 data data 253 255 6 Y 0 0 8 +def test t2 t2 data data 254 3 3 Y 0 0 8 +id data data +1 male yes +2 female no +select t1.id, t1.data, t2.data from t1, t2 where t1.id = t2.id order by t1.id; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 id id 1 3 1 Y 32768 0 63 +def test t1 t1 data data 253 255 6 Y 0 0 8 +def test t2 t2 data data 254 3 3 Y 0 0 8 +id data data +1 male yes +2 female no +select t1.id from t1 union select t2.id from t2; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def id id 1 4 1 Y 32768 0 63 +id +1 +2 +drop table t1,t2; +create table t1 ( a int, b varchar(30), primary key(a)); +insert into t1 values (1,'one'); +insert into t1 values (2,'two'); +set @arg00=1 ; +select @arg00 FROM t1 where a=1 union distinct select 1 FROM t1 where a=1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def @arg00 @arg00 8 20 1 Y 32768 0 63 +@arg00 +1 +select * from (select @arg00) aaa; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def aaa @arg00 @arg00 8 20 1 Y 32768 0 63 +@arg00 +1 +select 1 union select 1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def 1 1 8 20 1 N 32769 0 63 +1 +1 +select * from (select 1 union select 1) aaa; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def aaa 1 1 8 20 1 N 32769 0 63 +1 +1 +drop table t1; +create table t1 (i int); +insert into t1 values (1),(2),(3); +select * from t1 where i = 2; +drop table t1;// +affected rows: 0 +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 +i +2 +affected rows: 1 +affected rows: 0 +create table t1 (id int(10)); +insert into t1 values (1); +CREATE VIEW v1 AS select t1.id as id from t1; +CREATE VIEW v2 AS select t1.id as renamed from t1; +CREATE VIEW v3 AS select t1.id + 12 as renamed from t1; +select * from v1 group by id limit 1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 v1 id id 3 10 1 Y 32768 0 63 +id +1 +select * from v1 group by id limit 0; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test v1 v1 id id 3 10 0 Y 32768 0 63 +id +select * from v1 where id=1000 group by id; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 v1 id id 3 10 0 Y 32768 0 63 +id +select * from v1 where id=1 group by id; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 v1 id id 3 10 1 Y 32768 0 63 +id +1 +select * from v2 where renamed=1 group by renamed; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 v2 id renamed 3 10 1 Y 32768 0 63 +renamed +1 +select * from v3 where renamed=1 group by renamed; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def renamed 8 12 0 Y 32896 0 63 +renamed +drop table t1; +drop view v1,v2,v3; diff --git a/mysql-test/suite/pbxt/r/multi_statement.result b/mysql-test/suite/pbxt/r/multi_statement.result new file mode 100644 index 00000000000..21a62e01bca --- /dev/null +++ b/mysql-test/suite/pbxt/r/multi_statement.result @@ -0,0 +1,51 @@ +DROP TABLE IF EXISTS t1; +select 1; +1 +1 +select 2; +select 3; +select 4|||| +2 +2 +3 +3 +4 +4 +select 5; +select 6; +select 50, 'abc';'abcd' +5 +5 +6 +6 +50 abc +50 abc +select "abcd'";'abcd' +abcd' +abcd' +select "'abcd";'abcd' +'abcd +'abcd +select 5'abcd' +5 +5 +select 'finish'; +finish +finish +flush status; +create table t1 (i int); +insert into t1 values (1); +select * from t1 where i = 1; +insert into t1 values (2),(3),(4); +select * from t1 where i = 2; +select * from t1 where i = 3|||| +i +1 +i +2 +i +3 +show status like 'Slow_queries'|||| +Variable_name Value +Slow_queries 0 +drop table t1|||| diff --git a/mysql-test/suite/pbxt/r/multi_update.result b/mysql-test/suite/pbxt/r/multi_update.result new file mode 100644 index 00000000000..3ccbb74a01a --- /dev/null +++ b/mysql-test/suite/pbxt/r/multi_update.result @@ -0,0 +1,615 @@ +drop table if exists t1,t2,t3; +drop database if exists mysqltest; +drop view if exists v1; +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +delete from mysql.user where user=_binary'mysqltest_1'; +create table t1(id1 int not null auto_increment primary key, t char(12)); +create table t2(id2 int not null, t char(12)); +create table t3(id3 int not null, t char(12), index(id3)); +select count(*) from t1 where id1 > 95; +count(*) +5 +select count(*) from t2 where id2 > 95; +count(*) +25 +select count(*) from t3 where id3 > 95; +count(*) +250 +update t1,t2,t3 set t1.t="aaa", t2.t="bbb", t3.t="cc" where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 90; +select count(*) from t1 where t = "aaa"; +count(*) +10 +select count(*) from t1 where id1 > 90; +count(*) +10 +select count(*) from t2 where t = "bbb"; +count(*) +50 +select count(*) from t2 where id2 > 90; +count(*) +50 +select count(*) from t3 where t = "cc"; +count(*) +500 +select count(*) from t3 where id3 > 90; +count(*) +500 +delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 95; +check table t1, t2, t3; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +test.t3 check status OK +select count(*) from t1 where id1 > 95; +count(*) +0 +select count(*) from t2 where id2 > 95; +count(*) +0 +select count(*) from t3 where id3 > 95; +count(*) +0 +delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 5; +select count(*) from t1 where id1 > 5; +count(*) +0 +select count(*) from t2 where id2 > 5; +count(*) +0 +select count(*) from t3 where id3 > 5; +count(*) +0 +delete from t1, t2, t3 using t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0; +select count(*) from t1 where id1; +count(*) +0 +select count(*) from t2 where id2; +count(*) +0 +select count(*) from t3 where id3; +count(*) +0 +drop table t1,t2,t3; +create table t1(id1 int not null primary key, t varchar(100)) pack_keys = 1; +create table t2(id2 int not null, t varchar(100), index(id2)) pack_keys = 1; +delete t1 from t1,t2 where t1.id1 = t2.id2 and t1.id1 > 500; +drop table t1,t2; +CREATE TABLE t1 ( +id int(11) NOT NULL default '0', +name varchar(10) default NULL, +PRIMARY KEY (id) +) ENGINE=PBXT; +INSERT INTO t1 VALUES (1,'aaa'),(2,'aaa'),(3,'aaa'); +CREATE TABLE t2 ( +id int(11) NOT NULL default '0', +name varchar(10) default NULL, +PRIMARY KEY (id) +) ENGINE=PBXT; +INSERT INTO t2 VALUES (2,'bbb'),(3,'bbb'),(4,'bbb'); +CREATE TABLE t3 ( +id int(11) NOT NULL default '0', +mydate datetime default NULL, +PRIMARY KEY (id) +) ENGINE=PBXT; +INSERT INTO t3 VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22 +00:00:00'),(7,'2002-07-22 00:00:00'); +delete t1,t2,t3 from t1,t2,t3 where to_days(now())-to_days(t3.mydate)>=30 and t3.id=t1.id and t3.id=t2.id; +select * from t3; +id mydate +1 2002-02-04 00:00:00 +5 2002-05-12 00:00:00 +6 2002-06-22 00:00:00 +7 2002-07-22 00:00:00 +DROP TABLE t1,t2,t3; +CREATE TABLE IF NOT EXISTS `t1` ( +`id` int(11) NOT NULL auto_increment, +`tst` text, +`tst1` text, +PRIMARY KEY (`id`) +) ENGINE=PBXT; +CREATE TABLE IF NOT EXISTS `t2` ( +`ID` int(11) NOT NULL auto_increment, +`ParId` int(11) default NULL, +`tst` text, +`tst1` text, +PRIMARY KEY (`ID`), +KEY `IX_ParId_t2` (`ParId`), +FOREIGN KEY (`ParId`) REFERENCES `t1` (`id`) +) ENGINE=PBXT; +INSERT INTO t1(tst,tst1) VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE"); +INSERT INTO t2(ParId) VALUES(1), (2), (3); +select * from t2; +ID ParId tst tst1 +1 1 NULL NULL +2 2 NULL NULL +3 3 NULL NULL +UPDATE t2, t1 SET t2.tst = t1.tst, t2.tst1 = t1.tst1 WHERE t2.ParId = t1.Id; +select * from t2; +ID ParId tst tst1 +1 1 MySQL MySQL AB +2 2 MSSQL Microsoft +3 3 ORACLE ORACLE +drop table t2, t1 ; +create table t1 (n numeric(10)); +create table t2 (n numeric(10)); +insert into t2 values (1),(2),(4),(8),(16),(32); +select * from t2 left outer join t1 using (n); +n +1 +2 +4 +8 +16 +32 +delete t1,t2 from t2 left outer join t1 using (n); +select * from t2 left outer join t1 using (n); +n +drop table t1,t2 ; +create table t1 (n int(10) not null primary key, d int(10)); +create table t2 (n int(10) not null primary key, d int(10)); +insert into t1 values(1,1); +insert into t2 values(1,10),(2,20); +LOCK TABLES t1 write, t2 read; +DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n; +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +unlock tables; +LOCK TABLES t1 write, t2 write; +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +select * from t1; +n d +1 10 +DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n; +select * from t1; +n d +select * from t2; +n d +2 20 +unlock tables; +drop table t1,t2; +set sql_safe_updates=1; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1); +insert into t2 values(1,10),(2,20); +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +set sql_safe_updates=0; +drop table t1,t2; +set timestamp=1038401397; +create table t1 (n int(10) not null primary key, d int(10), t timestamp); +create table t2 (n int(10) not null primary key, d int(10), t timestamp); +insert into t1 values(1,1,NULL); +insert into t2 values(1,10,NULL),(2,20,NULL); +set timestamp=1038000000; +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +select n,d,unix_timestamp(t) from t1; +n d unix_timestamp(t) +1 10 1038000000 +select n,d,unix_timestamp(t) from t2; +n d unix_timestamp(t) +1 10 1038401397 +2 20 1038401397 +UPDATE t1,t2 SET 1=2 WHERE t1.n=t2.n; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1=2 WHERE t1.n=t2.n' at line 1 +drop table t1,t2; +set timestamp=0; +set sql_safe_updates=0; +create table t1 (n int(10) not null primary key, d int(10)); +create table t2 (n int(10) not null primary key, d int(10)); +insert into t1 values(1,1), (3,3); +insert into t2 values(1,10),(2,20); +UPDATE t2 left outer join t1 on t1.n=t2.n SET t1.d=t2.d; +select * from t1 order by n; +n d +1 10 +3 3 +select * from t2 order by n; +n d +1 10 +2 20 +drop table t1,t2; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1),(1,2); +insert into t2 values(1,10),(2,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1 order by n; +n d +1 10 +1 10 +select * from t2 order by n; +n d +1 30 +2 20 +drop table t1,t2; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1),(3,2); +insert into t2 values(1,10),(1,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1 order by n; +n d +1 10 +3 2 +select * from t2 order by n; +n d +1 30 +1 30 +UPDATE t1 a ,t2 b SET a.d=b.d,b.d=30 WHERE a.n=b.n; +select * from t1 order by n; +n d +1 30 +3 2 +select * from t2 order by n; +n d +1 30 +1 30 +DELETE a, b FROM t1 a,t2 b where a.n=b.n; +select * from t1 order by n; +n d +3 2 +select * from t2 order by n; +n d +drop table t1,t2; +CREATE TABLE t1 ( broj int(4) unsigned NOT NULL default '0', naziv char(25) NOT NULL default 'NEPOZNAT', PRIMARY KEY (broj)) ENGINE=PBXT; +INSERT INTO t1 VALUES (1,'jedan'),(2,'dva'),(3,'tri'),(4,'xxxxxxxxxx'),(5,'a'),(10,''),(11,''),(12,''),(13,''); +CREATE TABLE t2 ( broj int(4) unsigned NOT NULL default '0', naziv char(25) NOT NULL default 'NEPOZNAT', PRIMARY KEY (broj)) ENGINE=PBXT; +INSERT INTO t2 VALUES (1,'jedan'),(2,'dva'),(3,'tri'),(4,'xxxxxxxxxx'),(5,'a'); +CREATE TABLE t3 ( broj int(4) unsigned NOT NULL default '0', naziv char(25) NOT NULL default 'NEPOZNAT', PRIMARY KEY (broj)) ENGINE=PBXT; +INSERT INTO t3 VALUES (1,'jedan'),(2,'dva'); +update t1,t2 set t1.naziv="aaaa" where t1.broj=t2.broj; +update t1,t2,t3 set t1.naziv="bbbb", t2.naziv="aaaa" where t1.broj=t2.broj and t2.broj=t3.broj; +drop table t1,t2,t3; +CREATE TABLE t1 (a int not null primary key, b int not null, key (b)); +CREATE TABLE t2 (a int not null primary key, b int not null, key (b)); +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); +INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); +update t1,t2 set t1.a=t1.a+100; +select * from t1 order by a; +a b +101 1 +102 2 +103 3 +104 4 +105 5 +106 6 +107 7 +108 8 +109 9 +update t1,t2 set t1.a=t1.a+100 where t1.a=101; +select * from t1 order by a; +a b +102 2 +103 3 +104 4 +105 5 +106 6 +107 7 +108 8 +109 9 +201 1 +update t1,t2 set t1.b=t1.b+10 where t1.b=2; +select * from t1 order by a; +a b +102 12 +103 3 +104 4 +105 5 +106 6 +107 7 +108 8 +109 9 +201 1 +update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t2.a=t1.a-100; +select * from t1 order by a; +a b +102 12 +103 5 +104 6 +105 7 +106 6 +107 7 +108 8 +109 9 +201 1 +select * from t2 order by a; +a b +1 1 +2 2 +3 13 +4 14 +5 15 +6 6 +7 7 +8 8 +9 9 +update t1,t2 set t1.b=t2.b, t1.a=t2.a where t1.a=t2.a and not exists (select * from t2 where t2.a > 10); +drop table t1,t2; +CREATE TABLE t3 ( KEY1 varchar(50) NOT NULL default '', PARAM_CORR_DISTANCE_RUSH double default NULL, PARAM_CORR_DISTANCE_GEM double default NULL, PARAM_AVG_TARE double default NULL, PARAM_AVG_NB_DAYS double default NULL, PARAM_DEFAULT_PROP_GEM_SRVC varchar(50) default NULL, PARAM_DEFAULT_PROP_GEM_NO_ETIK varchar(50) default NULL, PARAM_SCENARIO_COSTS varchar(50) default NULL, PARAM_DEFAULT_WAGON_COST double default NULL, tmp int(11) default NULL, PRIMARY KEY (KEY1)) ENGINE=PBXT; +INSERT INTO t3 VALUES ('A',1,1,22,3.2,'R','R','BASE2',0.24,NULL); +create table t1 (A varchar(1)); +insert into t1 values ("A") ,("B"),("C"),("D"); +create table t2(Z varchar(15)); +insert into t2(Z) select concat(a.a,b.a,c.a,d.a) from t1 as a, t1 as b, t1 as c, t1 as d; +update t2,t3 set Z =param_scenario_costs; +drop table t1,t2,t3; +create table t1 (a int, b int); +create table t2 (a int, b int); +insert into t1 values (1,1),(2,1),(3,1); +insert into t2 values (1,1), (3,1); +update t1 left join t2 on t1.a=t2.a set t1.b=2, t2.b=2 where t1.b=1 and t2.b=1 or t2.a is NULL; +select t1.a, t1.b,t2.a, t2.b from t1 left join t2 on t1.a=t2.a where t1.b=1 and t2.b=1 or t2.a is NULL; +a b a b +2 2 NULL NULL +drop table t1,t2; +create table t1 (a int not null auto_increment primary key, b int not null); +insert into t1 (b) values (1),(2),(3),(4); +update t1, t1 as t2 set t1.b=t2.b+1 where t1.a=t2.a; +select * from t1; +a b +1 2 +2 3 +3 4 +4 5 +drop table t1; +create table t1(id1 smallint(5), field char(5)); +create table t2(id2 smallint(5), field char(5)); +insert into t1 values (1, 'a'), (2, 'aa'); +insert into t2 values (1, 'b'), (2, 'bb'); +select * from t1; +id1 field +1 a +2 aa +select * from t2; +id2 field +1 b +2 bb +update t2 inner join t1 on t1.id1=t2.id2 +set t2.field=t1.field +where 0=1; +update t2, t1 set t2.field=t1.field +where t1.id1=t2.id2 and 0=1; +delete t1, t2 from t2 inner join t1 on t1.id1=t2.id2 +where 0=1; +delete t1, t2 from t2,t1 +where t1.id1=t2.id2 and 0=1; +drop table t1,t2; +create table t1 ( a int not null, b int not null) ; +alter table t1 add index i1(a); +delete from t1 where a > 2000000; +create table t2 like t1; +insert into t2 select * from t1; +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +select 't2 rows before small delete', count(*) from t1; +t2 rows before small delete count(*) +t2 rows before small delete 2000000 +delete t1,t2 from t1,t2 where t1.b=t2.a and t1.a < 2; +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +select 't2 rows after small delete', count(*) from t2; +t2 rows after small delete count(*) +t2 rows after small delete 1999999 +select 't1 rows after small delete', count(*) from t1; +t1 rows after small delete count(*) +t1 rows after small delete 1999999 +delete t1,t2 from t1,t2 where t1.b=t2.a and t1.a < 100*1000; +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +select 't2 rows after big delete', count(*) from t2; +t2 rows after big delete count(*) +t2 rows after big delete 1900001 +select 't1 rows after big delete', count(*) from t1; +t1 rows after big delete count(*) +t1 rows after big delete 1900001 +drop table t1,t2; +CREATE TABLE t1 ( a int ); +CREATE TABLE t2 ( a int ); +DELETE t1 FROM t1, t2 AS t3; +DELETE t4 FROM t1, t1 AS t4; +DELETE t3 FROM t1 AS t3, t1 AS t4; +DELETE t1 FROM t1 AS t3, t2 AS t4; +ERROR 42S02: Unknown table 't1' in MULTI DELETE +INSERT INTO t1 values (1),(2); +INSERT INTO t2 values (1),(2); +DELETE t1 FROM t1 AS t2, t2 AS t1 where t1.a=t2.a and t1.a=1; +SELECT * from t1; +a +1 +2 +SELECT * from t2; +a +2 +DELETE t2 FROM t1 AS t2, t2 AS t1 where t1.a=t2.a and t1.a=2; +SELECT * from t1; +a +1 +SELECT * from t2; +a +2 +DROP TABLE t1,t2; +create table `t1` (`p_id` int(10) unsigned NOT NULL auto_increment, `p_code` varchar(20) NOT NULL default '', `p_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`p_id`) ); +create table `t2` (`c2_id` int(10) unsigned NULL auto_increment, `c2_p_id` int(10) unsigned NOT NULL default '0', `c2_note` text NOT NULL, `c2_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`c2_id`), KEY `c2_p_id` (`c2_p_id`) ); +insert into t1 values (0,'A01-Comp',1); +insert into t1 values (0,'B01-Comp',1); +insert into t2 values (0,1,'A Note',1); +update t1 left join t2 on p_id = c2_p_id set c2_note = 'asdf-1' where p_id = 2; +select * from t1; +p_id p_code p_active +1 A01-Comp 1 +2 B01-Comp 1 +select * from t2; +c2_id c2_p_id c2_note c2_active +1 1 A Note 1 +drop table t1, t2; +create database mysqltest; +create table mysqltest.t1 (a int, b int, primary key (a)); +create table mysqltest.t2 (a int, b int, primary key (a)); +create table mysqltest.t3 (a int, b int, primary key (a)); +grant select on mysqltest.* to mysqltest_1@localhost; +grant update on mysqltest.t1 to mysqltest_1@localhost; +update t1, t2 set t1.b=1 where t1.a=t2.a; +update t1, t2 set t1.b=(select t3.b from t3 where t1.a=t3.a) where t1.a=t2.a; +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +delete from mysql.user where user=_binary'mysqltest_1'; +drop database mysqltest; +create table t1 (a int, primary key (a)); +create table t2 (a int, primary key (a)); +create table t3 (a int, primary key (a)); +delete t1,t3 from t1,t2 where t1.a=t2.a and t2.a=(select t3.a from t3 where t1.a=t3.a); +ERROR 42S02: Unknown table 't3' in MULTI DELETE +drop table t1, t2, t3; +create table t1 (col1 int); +create table t2 (col1 int); +update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; +ERROR HY000: You can't specify target table 't1' for update in FROM clause +delete t1 from t1,t2 where t1.col1 < (select max(col1) from t1) and t1.col1 = t2.col1; +ERROR HY000: You can't specify target table 't1' for update in FROM clause +drop table t1,t2; +create table t1 ( +aclid bigint not null primary key, +status tinyint(1) not null +); +create table t2 ( +refid bigint not null primary key, +aclid bigint, index idx_acl(aclid) +); +insert into t2 values(1,null); +delete t2, t1 from t2 left join t1 on (t2.aclid=t1.aclid) where t2.refid='1'; +drop table t1, t2; +create table t1(a int); +create table t2(a int); +delete from t1,t2 using t1,t2 where t1.a=(select a from t1); +ERROR HY000: You can't specify target table 't1' for update in FROM clause +drop table t1, t2; +create table t1 ( c char(8) not null ) engine=pbxt; +insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); +insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); +alter table t1 add b char(8) not null; +alter table t1 add a char(8) not null; +alter table t1 add primary key (a,b,c); +update t1 set a=c, b=c; +create table t2 like t1; +insert into t2 select * from t1; +delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; +drop table t1,t2; +create table t1 ( c char(8) not null ) engine=pbxt; +insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); +insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); +alter table t1 add b char(8) not null; +alter table t1 add a char(8) not null; +alter table t1 add primary key (a,b,c); +update t1 set a=c, b=c; +create table t2 like t1; +insert into t2 select * from t1; +delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; +drop table t1,t2; +create table t1 (a int, b int); +insert into t1 values (1, 2), (2, 3), (3, 4); +create table t2 (a int); +insert into t2 values (10), (20), (30); +create view v1 as select a as b, a/10 as a from t2; +lock table t1 write; +alter table t1 add column c int default 100 after a; +update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a; +unlock tables; +select * from t1; +a c b +1 100 13 +2 100 25 +3 100 37 +select * from t2; +a +10 +20 +30 +drop view v1; +drop table t1, t2; +create table t1 (i1 int, i2 int, i3 int); +create table t2 (id int, c1 varchar(20), c2 varchar(20)); +insert into t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2); +insert into t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test"); +select * from t1 order by i1; +i1 i2 i3 +1 5 10 +2 2 2 +3 7 12 +4 5 2 +9 10 15 +select * from t2; +id c1 c2 +9 abc def +5 opq lmn +2 test t t test +update t1,t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id; +select * from t1 order by i1; +i1 i2 i3 +1 5 10 +2 15 2 +3 7 12 +4 5 2 +9 15 15 +select * from t2 order by id; +id c1 c2 +2 test t ppc +5 opq lmn +9 abc ppc +delete t1.*,t2.* from t1,t2 where t1.i2=t2.id; +select * from t1 order by i1; +i1 i2 i3 +2 15 2 +3 7 12 +9 15 15 +select * from t2 order by id; +id c1 c2 +2 test t ppc +9 abc ppc +drop table t1, t2; +create table t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)); +create table t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)); +insert into t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2); +insert into t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test"); +select * from t1 order by i1; +i1 i2 i3 +1 5 10 +2 2 2 +3 7 12 +4 5 2 +9 10 15 +select * from t2 order by id; +id c1 c2 +2 test t t test +5 opq lmn +9 abc def +update t1,t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id; +select * from t1 order by i1; +i1 i2 i3 +1 5 10 +2 15 2 +3 7 12 +4 5 2 +9 15 15 +select * from t2 order by id; +id c1 c2 +2 test t ppc +5 opq lmn +9 abc ppc +delete t1.*,t2.* from t1,t2 where t1.i2=t2.id; +select * from t1 order by i1; +i1 i2 i3 +2 15 2 +3 7 12 +9 15 15 +select * from t2 order by id; +id c1 c2 +2 test t ppc +9 abc ppc +drop table t1, t2; diff --git a/mysql-test/suite/pbxt/r/mysql_protocols.result b/mysql-test/suite/pbxt/r/mysql_protocols.result new file mode 100644 index 00000000000..c6207c4f4f5 --- /dev/null +++ b/mysql-test/suite/pbxt/r/mysql_protocols.result @@ -0,0 +1,10 @@ +<default> + ok +TCP + ok +SOCKET + ok +ERROR 2047 (HY000): Wrong or unknown protocol +ERROR 2047 (HY000): Wrong or unknown protocol +Unknown option to protocol: NullS +Alternatives are: 'TCP','SOCKET','PIPE','MEMORY' diff --git a/mysql-test/suite/pbxt/r/mysqlshow.result b/mysql-test/suite/pbxt/r/mysqlshow.result new file mode 100644 index 00000000000..0e1915dc47a --- /dev/null +++ b/mysql-test/suite/pbxt/r/mysqlshow.result @@ -0,0 +1,152 @@ +DROP TABLE IF EXISTS t1,t2,test1,test2; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1),(2),(3); +CREATE TABLE t2 (a int, b int); +show tables; +Tables_in_test +t1 +t2 +select "--------------------" as ""; + +-------------------- +Database: test ++--------+ +| Tables | ++--------+ +| t1 | +| t2 | ++--------+ +select "---- -v ------------" as ""; + +---- -v ------------ +Database: test ++--------+----------+ +| Tables | Columns | ++--------+----------+ +| t1 | 1 | +| t2 | 2 | ++--------+----------+ +2 rows in set. + +select "---- -v -v ---------" as ""; + +---- -v -v --------- +Database: test ++--------+----------+------------+ +| Tables | Columns | Total Rows | ++--------+----------+------------+ +| t1 | 1 | 3 | +| t2 | 2 | 0 | ++--------+----------+------------+ +2 rows in set. + +select "----- -t -----------" as ""; + +----- -t ----------- +Database: test ++--------+------------+ +| Tables | table_type | ++--------+------------+ +| t1 | BASE TABLE | +| t2 | BASE TABLE | ++--------+------------+ +select "---- -v -t ---------" as ""; + +---- -v -t --------- +Database: test ++--------+------------+----------+ +| Tables | table_type | Columns | ++--------+------------+----------+ +| t1 | BASE TABLE | 1 | +| t2 | BASE TABLE | 2 | ++--------+------------+----------+ +2 rows in set. + +select "---- -v -v -t ------" as ""; + +---- -v -v -t ------ +Database: test ++--------+------------+----------+------------+ +| Tables | table_type | Columns | Total Rows | ++--------+------------+----------+------------+ +| t1 | BASE TABLE | 1 | 3 | +| t2 | BASE TABLE | 2 | 0 | ++--------+------------+----------+------------+ +2 rows in set. + +DROP TABLE t1, t2; +Database: information_schema ++---------------------------------------+ +| Tables | ++---------------------------------------+ +| CHARACTER_SETS | +| COLLATIONS | +| COLLATION_CHARACTER_SET_APPLICABILITY | +| COLUMNS | +| COLUMN_PRIVILEGES | +| ENGINES | +| EVENTS | +| FILES | +| GLOBAL_STATUS | +| GLOBAL_VARIABLES | +| KEY_COLUMN_USAGE | +| PARTITIONS | +| PLUGINS | +| PROCESSLIST | +| PROFILING | +| REFERENTIAL_CONSTRAINTS | +| ROUTINES | +| SCHEMATA | +| SCHEMA_PRIVILEGES | +| SESSION_STATUS | +| SESSION_VARIABLES | +| STATISTICS | +| TABLES | +| TABLE_CONSTRAINTS | +| TABLE_PRIVILEGES | +| TRIGGERS | +| USER_PRIVILEGES | +| VIEWS | +| PBXT_STATISTICS | ++---------------------------------------+ +Database: INFORMATION_SCHEMA ++---------------------------------------+ +| Tables | ++---------------------------------------+ +| CHARACTER_SETS | +| COLLATIONS | +| COLLATION_CHARACTER_SET_APPLICABILITY | +| COLUMNS | +| COLUMN_PRIVILEGES | +| ENGINES | +| EVENTS | +| FILES | +| GLOBAL_STATUS | +| GLOBAL_VARIABLES | +| KEY_COLUMN_USAGE | +| PARTITIONS | +| PLUGINS | +| PROCESSLIST | +| PROFILING | +| REFERENTIAL_CONSTRAINTS | +| ROUTINES | +| SCHEMATA | +| SCHEMA_PRIVILEGES | +| SESSION_STATUS | +| SESSION_VARIABLES | +| STATISTICS | +| TABLES | +| TABLE_CONSTRAINTS | +| TABLE_PRIVILEGES | +| TRIGGERS | +| USER_PRIVILEGES | +| VIEWS | +| PBXT_STATISTICS | ++---------------------------------------+ +Wildcard: inf_rmation_schema ++--------------------+ +| Databases | ++--------------------+ +| information_schema | ++--------------------+ +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/mysqlslap.result b/mysql-test/suite/pbxt/r/mysqlslap.result new file mode 100644 index 00000000000..7f2d4396c68 --- /dev/null +++ b/mysql-test/suite/pbxt/r/mysqlslap.result @@ -0,0 +1,221 @@ +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +CREATE TABLE t1 (id int, name varchar(64)); +INSERT INTO t1 VALUES (1, 'This is a test'); +select * from t1; +DROP SCHEMA IF EXISTS `mysqlslap`; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +set storage_engine=`heap`; +CREATE TABLE t1 (id int, name varchar(64)); +create table t2(foo1 varchar(32), foo2 varchar(32)); +INSERT INTO t1 VALUES (1, 'This is a test'); +insert into t2 values ('test', 'test2'); +select * from t1; +select * from t2; +DROP SCHEMA IF EXISTS `mysqlslap`; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +set storage_engine=`myisam`; +CREATE TABLE t1 (id int, name varchar(64)); +create table t2(foo1 varchar(32), foo2 varchar(32)); +INSERT INTO t1 VALUES (1, 'This is a test'); +insert into t2 values ('test', 'test2'); +select * from t1; +select * from t2; +DROP SCHEMA IF EXISTS `mysqlslap`; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +set storage_engine=`heap`; +CREATE TABLE t1 (id int, name varchar(64)); +create table t2(foo1 varchar(32), foo2 varchar(32)); +INSERT INTO t1 VALUES (1, 'This is a test'); +insert into t2 values ('test', 'test2'); +SHOW TABLES; +select * from t1; +select * from t2; +SHOW TABLES; +DROP SCHEMA IF EXISTS `mysqlslap`; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +set storage_engine=`myisam`; +CREATE TABLE t1 (id int, name varchar(64)); +create table t2(foo1 varchar(32), foo2 varchar(32)); +INSERT INTO t1 VALUES (1, 'This is a test'); +insert into t2 values ('test', 'test2'); +SHOW TABLES; +select * from t1; +select * from t2; +SHOW TABLES; +DROP SCHEMA IF EXISTS `mysqlslap`; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +set storage_engine=`heap`; +CREATE TABLE t1 (id int, name varchar(64)); +create table t2(foo1 varchar(32), foo2 varchar(32)); +INSERT INTO t1 VALUES (1, 'This is a test'); +insert into t2 values ('test', 'test2'); +SET AUTOCOMMIT=0; +SHOW TABLES; +SET AUTOCOMMIT=0; +select * from t1; +COMMIT; +select * from t2; +COMMIT; +select * from t1; +COMMIT; +select * from t2; +COMMIT; +select * from t1; +COMMIT; +select * from t2; +COMMIT; +COMMIT; +SHOW TABLES; +DROP SCHEMA IF EXISTS `mysqlslap`; +DROP SCHEMA IF EXISTS `mysqlslap`; +CREATE SCHEMA `mysqlslap`; +use mysqlslap; +set storage_engine=`myisam`; +CREATE TABLE t1 (id int, name varchar(64)); +create table t2(foo1 varchar(32), foo2 varchar(32)); +INSERT INTO t1 VALUES (1, 'This is a test'); +insert into t2 values ('test', 'test2'); +SET AUTOCOMMIT=0; +SHOW TABLES; +SET AUTOCOMMIT=0; +select * from t1; +COMMIT; +select * from t2; +COMMIT; +select * from t1; +COMMIT; +select * from t2; +COMMIT; +select * from t1; +COMMIT; +select * from t2; +COMMIT; +COMMIT; +SHOW TABLES; +DROP SCHEMA IF EXISTS `mysqlslap`; diff --git a/mysql-test/suite/pbxt/r/negation_elimination.result b/mysql-test/suite/pbxt/r/negation_elimination.result new file mode 100644 index 00000000000..f8a6b0f764d --- /dev/null +++ b/mysql-test/suite/pbxt/r/negation_elimination.result @@ -0,0 +1,394 @@ +drop table if exists t1; +create table t1 (a int, key (a)); +insert into t1 values (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(10), (11), (12), (13), (14), (15), (16), (17), (18), (19); +explain select * from t1 where not(not(a)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 21 Using where; Using index +select * from t1 where not(not(a)); +a +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where not(not(not(a > 10))); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(not(not(a > 10))); +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +explain select * from t1 where not(not(not(a < 5) and not(a > 10))); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(not(not(a < 5) and not(a > 10))); +a +5 +6 +7 +8 +9 +10 +explain select * from t1 where not(a = 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using index +select * from t1 where not(a = 10); +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where not(a != 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 1 Using where; Using index +select * from t1 where not(a != 1); +a +1 +explain select * from t1 where not(a < 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(a < 10); +a +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where not(a >= 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(a >= 10); +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +explain select * from t1 where not(a > 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(a > 10); +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +explain select * from t1 where not(a <= 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(a <= 10); +a +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where not(a is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(a is null); +a +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where not(a is not null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 1 Using where; Using index +select * from t1 where not(a is not null); +a +NULL +explain select * from t1 where not(a < 5 or a > 15); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(a < 5 or a > 15); +a +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +explain select * from t1 where not(a < 15 and a > 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using index +select * from t1 where not(a < 15 and a > 5); +a +0 +1 +2 +3 +4 +5 +15 +16 +17 +18 +19 +explain select * from t1 where a = 2 or not(a < 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using index +select * from t1 where a = 2 or not(a < 10); +a +2 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where a > 5 and not(a > 10); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where a > 5 and not(a > 10); +a +6 +7 +8 +9 +10 +explain select * from t1 where a > 5 xor a < 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 21 Using where; Using index +select * from t1 where a > 5 xor a < 10; +a +0 +1 +2 +3 +4 +5 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where a = 2 or not(a < 5 or a > 15); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using index +select * from t1 where a = 2 or not(a < 5 or a > 15); +a +2 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +explain select * from t1 where a = 7 or not(a < 15 and a > 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +select * from t1 where a = 7 or not(a < 15 and a > 5); +a +0 +1 +2 +3 +4 +5 +7 +15 +16 +17 +18 +19 +explain select * from t1 where NULL or not(a < 15 and a > 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using index +select * from t1 where NULL or not(a < 15 and a > 5); +a +0 +1 +2 +3 +4 +5 +15 +16 +17 +18 +19 +explain select * from t1 where not(NULL and a > 5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not(NULL and a > 5); +a +0 +1 +2 +3 +4 +5 +explain select * from t1 where not(NULL or a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +select * from t1 where not(NULL or a); +a +explain select * from t1 where not(NULL and a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 21 Using where; Using index +select * from t1 where not(NULL and a); +a +0 +explain select * from t1 where not((a < 5 or a < 10) and (not(a > 16) or a > 17)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not((a < 5 or a < 10) and (not(a > 16) or a > 17)); +a +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where not((a < 5 and a < 10) and (not(a > 16) or a > 17)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where not((a < 5 and a < 10) and (not(a > 16) or a > 17)); +a +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +explain select * from t1 where ((a between 5 and 15) and (not(a like 10))); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where ((a between 5 and 15) and (not(a like 10))); +a +5 +6 +7 +8 +9 +11 +12 +13 +14 +15 +delete from t1 where a > 3; +select a, not(not(a)) from t1; +a not(not(a)) +NULL NULL +0 0 +1 1 +2 1 +3 1 +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "1"), not (a not in (1,2)), not(a != 2) from t1 where not(not(a)) having not(not(a)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL a 5 NULL 5 100.00 Using where; Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a` <> 0) AS `not(not(a))`,((`test`.`t1`.`a` > 2) or `test`.`t1`.`a`) AS `not(a <= 2 and not(a))`,(`test`.`t1`.`a` like '1') AS `not(a not like "1")`,(`test`.`t1`.`a` in (1,2)) AS `not (a not in (1,2))`,(`test`.`t1`.`a` = 2) AS `not(a != 2)` from `test`.`t1` where `test`.`t1`.`a` having `test`.`t1`.`a` +drop table t1; diff --git a/mysql-test/suite/pbxt/r/null.result b/mysql-test/suite/pbxt/r/null.result new file mode 100644 index 00000000000..775d169a39a --- /dev/null +++ b/mysql-test/suite/pbxt/r/null.result @@ -0,0 +1,320 @@ +drop table if exists t1, t2; +select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null; +NULL NULL isnull(null) isnull(1/0) isnull(1/0 = null) ifnull(null,1) ifnull(null,"TRUE") ifnull("TRUE","ERROR") 1/0 is null 1 is not null +NULL NULL 1 1 1 1 TRUE TRUE 1 1 +explain extended select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select NULL AS `NULL`,NULL AS `NULL`,isnull(NULL) AS `isnull(null)`,isnull((1 / 0)) AS `isnull(1/0)`,isnull(((1 / 0) = NULL)) AS `isnull(1/0 = null)`,ifnull(NULL,1) AS `ifnull(null,1)`,ifnull(NULL,'TRUE') AS `ifnull(null,"TRUE")`,ifnull('TRUE','ERROR') AS `ifnull("TRUE","ERROR")`,isnull((1 / 0)) AS `1/0 is null`,(1 is not null) AS `1 is not null` +select 1 | NULL,1 & NULL,1+NULL,1-NULL; +1 | NULL 1 & NULL 1+NULL 1-NULL +NULL NULL NULL NULL +select NULL=NULL,NULL<>NULL,IFNULL(NULL,1.1)+0,IFNULL(NULL,1) | 0; +NULL=NULL NULL<>NULL IFNULL(NULL,1.1)+0 IFNULL(NULL,1) | 0 +NULL NULL 1.1 1 +select strcmp("a",NULL),(1<NULL)+0.0,NULL regexp "a",null like "a%","a%" like null; +strcmp("a",NULL) (1<NULL)+0.0 NULL regexp "a" null like "a%" "a%" like null +NULL NULL NULL NULL NULL +select concat("a",NULL),replace(NULL,"a","b"),replace("string","i",NULL),replace("string",NULL,"i"),insert("abc",1,1,NULL),left(NULL,1); +concat("a",NULL) replace(NULL,"a","b") replace("string","i",NULL) replace("string",NULL,"i") insert("abc",1,1,NULL) left(NULL,1) +NULL NULL NULL NULL NULL NULL +select repeat("a",0),repeat("ab",5+5),repeat("ab",-1),reverse(NULL); +repeat("a",0) repeat("ab",5+5) repeat("ab",-1) reverse(NULL) + abababababababababab NULL +select field(NULL,"a","b","c"); +field(NULL,"a","b","c") +0 +select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null; +2 between null and 1 2 between 3 AND NULL NULL between 1 and 2 2 between NULL and 3 2 between 1 AND null +0 0 NULL NULL NULL +explain extended select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select (2 between NULL and 1) AS `2 between null and 1`,(2 between 3 and NULL) AS `2 between 3 AND NULL`,(NULL between 1 and 2) AS `NULL between 1 and 2`,(2 between NULL and 3) AS `2 between NULL and 3`,(2 between 1 and NULL) AS `2 between 1 AND null` +SELECT NULL AND NULL, 1 AND NULL, NULL AND 1, NULL OR NULL, 0 OR NULL, NULL OR 0; +NULL AND NULL 1 AND NULL NULL AND 1 NULL OR NULL 0 OR NULL NULL OR 0 +NULL NULL NULL NULL NULL NULL +SELECT (NULL OR NULL) IS NULL; +(NULL OR NULL) IS NULL +1 +select NULL AND 0, 0 and NULL; +NULL AND 0 0 and NULL +0 0 +select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton(""); +inet_ntoa(null) inet_aton(null) inet_aton("122.256") inet_aton("122.226.") inet_aton("") +NULL NULL NULL NULL NULL +explain extended select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton(""); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select inet_ntoa(NULL) AS `inet_ntoa(null)`,inet_aton(NULL) AS `inet_aton(null)`,inet_aton('122.256') AS `inet_aton("122.256")`,inet_aton('122.226.') AS `inet_aton("122.226.")`,inet_aton('') AS `inet_aton("")` +create table t1 (x int); +insert into t1 values (null); +select * from t1 where x != 0; +x +drop table t1; +CREATE TABLE t1 ( +indexed_field int default NULL, +KEY indexed_field (indexed_field) +); +INSERT INTO t1 VALUES (NULL),(NULL); +SELECT * FROM t1 WHERE indexed_field=NULL; +indexed_field +SELECT * FROM t1 WHERE indexed_field IS NULL; +indexed_field +NULL +NULL +SELECT * FROM t1 WHERE indexed_field<=>NULL; +indexed_field +NULL +NULL +DROP TABLE t1; +create table t1 (a int, b int) engine=myisam; +insert into t1 values(20,null); +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a; +b ifnull(t2.b,"this is null") +NULL this is null +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a order by 1; +b ifnull(t2.b,"this is null") +NULL this is null +insert into t1 values(10,null); +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a order by 1; +b ifnull(t2.b,"this is null") +NULL this is null +NULL this is null +drop table t1; +CREATE TABLE t1 (a varchar(16) NOT NULL default '', b smallint(6) NOT NULL default 0, c datetime NOT NULL default '0000-00-00 00:00:00', d smallint(6) NOT NULL default 0); +INSERT INTO t1 SET a = "", d= "2003-01-14 03:54:55"; +Warnings: +Warning 1265 Data truncated for column 'd' at row 1 +UPDATE t1 SET d=1/NULL; +ERROR 23000: Column 'd' cannot be null +UPDATE t1 SET d=NULL; +ERROR 23000: Column 'd' cannot be null +INSERT INTO t1 (a) values (null); +ERROR 23000: Column 'a' cannot be null +INSERT INTO t1 (a) values (1/null); +ERROR 23000: Column 'a' cannot be null +INSERT INTO t1 (a) values (null),(null); +Warnings: +Warning 1048 Column 'a' cannot be null +Warning 1048 Column 'a' cannot be null +INSERT INTO t1 (b) values (null); +ERROR 23000: Column 'b' cannot be null +INSERT INTO t1 (b) values (1/null); +ERROR 23000: Column 'b' cannot be null +INSERT INTO t1 (b) values (null),(null); +Warnings: +Warning 1048 Column 'b' cannot be null +Warning 1048 Column 'b' cannot be null +INSERT INTO t1 (c) values (null); +ERROR 23000: Column 'c' cannot be null +INSERT INTO t1 (c) values (1/null); +ERROR 23000: Column 'c' cannot be null +INSERT INTO t1 (c) values (null),(null); +Warnings: +Warning 1048 Column 'c' cannot be null +Warning 1048 Column 'c' cannot be null +INSERT INTO t1 (d) values (null); +ERROR 23000: Column 'd' cannot be null +INSERT INTO t1 (d) values (1/null); +ERROR 23000: Column 'd' cannot be null +INSERT INTO t1 (d) values (null),(null); +Warnings: +Warning 1048 Column 'd' cannot be null +Warning 1048 Column 'd' cannot be null +select * from t1; +a b c d + 0 0000-00-00 00:00:00 2003 + 0 0000-00-00 00:00:00 0 + 0 0000-00-00 00:00:00 0 + 0 0000-00-00 00:00:00 0 + 0 0000-00-00 00:00:00 0 + 0 0000-00-00 00:00:00 0 + 0 0000-00-00 00:00:00 0 + 0 0000-00-00 00:00:00 0 + 0 0000-00-00 00:00:00 0 +drop table t1; +create table t1 (a int not null, b int not null, index idx(a)); +insert into t1 values +(1,1), (2,2), (3,3), (4,4), (5,5), (6,6), +(7,7), (8,8), (9,9), (10,10), (11,11), (12,12); +explain select * from t1 where a between 2 and 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 4 NULL 1 Using where +explain select * from t1 where a between 2 and 3 or b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 4 NULL 1 Using where +drop table t1; +select cast(NULL as signed); +cast(NULL as signed) +NULL +create table t1(i int, key(i)); +insert into t1 values(1); +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 values(null); +explain select * from t1 where i=2 or i is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null i i 5 const # Using where; Using index +select count(*) from t1 where i=2 or i is null; +count(*) +10 +alter table t1 change i i int not null; +Warnings: +Warning 1265 Data truncated for column 'i' at row 513 +explain select * from t1 where i=2 or i is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref i i 4 const 1 Using index +select count(*) from t1 where i=2 or i is null; +count(*) +9 +drop table t1; +set names latin2; +create table t1 select +null as c00, +if(1, null, 'string') as c01, +if(0, null, 'string') as c02, +ifnull(null, 'string') as c03, +ifnull('string', null) as c04, +case when 0 then null else 'string' end as c05, +case when 1 then null else 'string' end as c06, +coalesce(null, 'string') as c07, +coalesce('string', null) as c08, +least('string',null) as c09, +least(null, 'string') as c10, +greatest('string',null) as c11, +greatest(null, 'string') as c12, +nullif('string', null) as c13, +nullif(null, 'string') as c14, +trim('string' from null) as c15, +trim(null from 'string') as c16, +substring_index('string', null, 1) as c17, +substring_index(null, 'string', 1) as c18, +elt(1, null, 'string') as c19, +elt(1, 'string', null) as c20, +concat('string', null) as c21, +concat(null, 'string') as c22, +concat_ws('sep', 'string', null) as c23, +concat_ws('sep', null, 'string') as c24, +concat_ws(null, 'string', 'string') as c25, +make_set(3, 'string', null) as c26, +make_set(3, null, 'string') as c27, +export_set(3, null, 'off', 'sep') as c29, +export_set(3, 'on', null, 'sep') as c30, +export_set(3, 'on', 'off', null) as c31, +replace(null, 'from', 'to') as c32, +replace('str', null, 'to') as c33, +replace('str', 'from', null) as c34, +insert('str', 1, 2, null) as c35, +insert(null, 1, 2, 'str') as c36, +lpad('str', 10, null) as c37, +rpad(null, 10, 'str') as c38; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c00` binary(0) DEFAULT NULL, + `c01` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c02` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c03` varchar(6) CHARACTER SET latin2 NOT NULL DEFAULT '', + `c04` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c05` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c06` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c07` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c08` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c09` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c10` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c11` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c12` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c13` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c14` char(0) CHARACTER SET latin2 DEFAULT NULL, + `c15` char(0) CHARACTER SET latin2 DEFAULT NULL, + `c16` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c17` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c18` char(0) CHARACTER SET latin2 DEFAULT NULL, + `c19` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c20` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c21` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c22` varchar(6) CHARACTER SET latin2 DEFAULT NULL, + `c23` varchar(9) CHARACTER SET latin2 DEFAULT NULL, + `c24` varchar(9) CHARACTER SET latin2 DEFAULT NULL, + `c25` varchar(12) CHARACTER SET latin2 DEFAULT NULL, + `c26` varchar(7) CHARACTER SET latin2 DEFAULT NULL, + `c27` varchar(7) CHARACTER SET latin2 DEFAULT NULL, + `c29` varchar(381) CHARACTER SET latin2 DEFAULT NULL, + `c30` varchar(317) CHARACTER SET latin2 DEFAULT NULL, + `c31` varchar(192) CHARACTER SET latin2 DEFAULT NULL, + `c32` char(0) CHARACTER SET latin2 DEFAULT NULL, + `c33` varchar(3) CHARACTER SET latin2 DEFAULT NULL, + `c34` varchar(3) CHARACTER SET latin2 DEFAULT NULL, + `c35` varchar(3) CHARACTER SET latin2 DEFAULT NULL, + `c36` varchar(3) CHARACTER SET latin2 DEFAULT NULL, + `c37` varchar(10) CHARACTER SET latin2 DEFAULT NULL, + `c38` varchar(10) CHARACTER SET latin2 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +select +case 'str' when 'STR' then 'str' when null then 'null' end as c01, +case 'str' when null then 'null' when 'STR' then 'str' end as c02, +field(null, 'str1', 'str2') as c03, +field('str1','STR1', null) as c04, +field('str1', null, 'STR1') as c05, +'string' in ('STRING', null) as c08, +'string' in (null, 'STRING') as c09; +c01 c02 c03 c04 c05 c08 c09 +str str 0 1 2 1 1 +set names latin1; +create table bug19145a (e enum('a','b','c') default 'b' , s set('x', 'y', 'z') default 'y' ) engine=MyISAM; +create table bug19145b (e enum('a','b','c') default null, s set('x', 'y', 'z') default null) engine=MyISAM; +create table bug19145c (e enum('a','b','c') not null default 'b' , s set('x', 'y', 'z') not null default 'y' ) engine=MyISAM; +create table bug19145setnotnulldefaultnull (e enum('a','b','c') default null, s set('x', 'y', 'z') not null default null) engine=MyISAM; +ERROR 42000: Invalid default value for 's' +create table bug19145enumnotnulldefaultnull (e enum('a','b','c') not null default null, s set('x', 'y', 'z') default null) engine=MyISAM; +ERROR 42000: Invalid default value for 'e' +alter table bug19145a alter column e set default null; +alter table bug19145a alter column s set default null; +alter table bug19145a add column (i int); +alter table bug19145b alter column e set default null; +alter table bug19145b alter column s set default null; +alter table bug19145b add column (i int); +alter table bug19145c alter column e set default null; +ERROR 42000: Invalid default value for 'e' +alter table bug19145c alter column s set default null; +ERROR 42000: Invalid default value for 's' +alter table bug19145c add column (i int); +show create table bug19145a; +Table Create Table +bug19145a CREATE TABLE `bug19145a` ( + `e` enum('a','b','c') DEFAULT NULL, + `s` set('x','y','z') DEFAULT NULL, + `i` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create table bug19145b; +Table Create Table +bug19145b CREATE TABLE `bug19145b` ( + `e` enum('a','b','c') DEFAULT NULL, + `s` set('x','y','z') DEFAULT NULL, + `i` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create table bug19145c; +Table Create Table +bug19145c CREATE TABLE `bug19145c` ( + `e` enum('a','b','c') NOT NULL DEFAULT 'b', + `s` set('x','y','z') NOT NULL DEFAULT 'y', + `i` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table bug19145a; +drop table bug19145b; +drop table bug19145c; diff --git a/mysql-test/suite/pbxt/r/null_key.result b/mysql-test/suite/pbxt/r/null_key.result new file mode 100644 index 00000000000..c01e0337b32 --- /dev/null +++ b/mysql-test/suite/pbxt/r/null_key.result @@ -0,0 +1,431 @@ +drop table if exists t1,t2; +create table t1 (a int, b int not null,unique key (a,b),index(b)) engine=myisam; +insert ignore into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(null,7),(9,9),(8,8),(7,7),(null,9),(null,9),(6,6); +explain select * from t1 where a is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 3 Using where; Using index +explain select * from t1 where a is null and b = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 9 const,const 1 Using where; Using index +explain select * from t1 where a is null and b = 7; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 9 const,const 1 Using where; Using index +explain select * from t1 where a=2 and b = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const a,b a 9 const,const 1 Using index +explain select * from t1 where a<=>b limit 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 9 NULL 12 Using where; Using index +explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a,b a 9 NULL 3 Using where; Using index +explain select * from t1 where (a is null or a = 7) and b=7; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a,b a 9 const,const 2 Using where; Using index +explain select * from t1 where (a is null or a = 7) and b=7 order by a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a,b a 9 const,const 2 Using where; Using index; Using filesort +explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 5 const 3 Using where; Using index +explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a,b a 9 NULL 3 Using where; Using index +explain select * from t1 where a > 1 and a < 3 limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +explain select * from t1 where a > 8 and a < 9; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index +select * from t1 where a is null; +a b +NULL 7 +NULL 9 +NULL 9 +select * from t1 where a is null and b = 7; +a b +NULL 7 +select * from t1 where a<=>b limit 2; +a b +1 1 +2 2 +select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3; +a b +1 1 +2 2 +select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3; +a b +NULL 9 +NULL 9 +select * from t1 where (a is null or a = 7) and b=7; +a b +7 7 +NULL 7 +select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +a b +NULL 7 +NULL 9 +NULL 9 +select * from t1 where a > 1 and a < 3 limit 1; +a b +2 2 +select * from t1 where a > 8 and a < 9; +a b +create table t2 like t1; +insert into t2 select * from t1; +alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10)); +explain select * from t1 where a is null and b = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 5 const 3 Using where +explain select * from t1 where a is null and b = 2 and c=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 5 const 3 Using where +explain select * from t1 where a is null and b = 7 and c=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 5 const 3 Using where +explain select * from t1 where a=2 and b = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 5 const 1 Using where +explain select * from t1 where a<=>b limit 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where +explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 and c=0 limit 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a,b a 5 NULL 5 Using where +explain select * from t1 where (a is null or a = 7) and b=7 and c=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using where +explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 5 const 3 Using where +explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a,b a 5 const 3 Using where +explain select * from t1 where a > 1 and a < 3 limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where +explain select * from t1 where a is null and b=7 or a > 1 and a < 3 limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a,b a 5 NULL 4 Using where +explain select * from t1 where a > 8 and a < 9; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 1 Using where +explain select * from t1 where b like "6%"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range b b 12 NULL 1 Using where +select * from t1 where a is null; +a b c +NULL 7 0 +NULL 9 0 +NULL 9 0 +select * from t1 where a is null and b = 7 and c=0; +a b c +NULL 7 0 +select * from t1 where a<=>b limit 2; +a b c +1 1 0 +2 2 0 +select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3; +a b c +1 1 0 +2 2 0 +select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3; +a b c +NULL 9 0 +NULL 9 0 +select * from t1 where (a is null or a = 7) and b=7 and c=0; +a b c +7 7 0 +NULL 7 0 +select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +a b c +NULL 7 0 +NULL 9 0 +NULL 9 0 +select * from t1 where b like "6%"; +a b c +6 6 0 +drop table t1; +rename table t2 to t1; +alter table t1 modify b int null; +insert into t1 values (7,null), (8,null), (8,7); +explain select * from t1 where a = 7 and (b=7 or b is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a,b a 10 const,const 2 Using where; Using index +select * from t1 where a = 7 and (b=7 or b is null); +a b +7 7 +7 NULL +explain select * from t1 where (a = 7 or a is null) and (b=7 or b is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using where; Using index +select * from t1 where (a = 7 or a is null) and (b=7 or b is null); +a b +7 NULL +7 7 +NULL 7 +explain select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a a 5 const 5 Using where; Using index +select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); +a b +7 NULL +7 7 +NULL 7 +NULL 9 +NULL 9 +create table t2 (a int); +insert into t2 values (7),(8); +explain select * from t2 straight_join t1 where t1.a=t2.a and b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref a,b a 10 test.t2.a,const 2 Using where; Using index +drop index b on t1; +explain select * from t2,t1 where t1.a=t2.a and b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref a a 10 test.t2.a,const 2 Using where; Using index +select * from t2,t1 where t1.a=t2.a and b is null; +a a b +7 7 NULL +8 8 NULL +explain select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref_or_null a a 10 test.t2.a,const 4 Using where; Using index +select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null); +a a b +7 7 7 +7 7 NULL +8 8 7 +8 8 NULL +explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref_or_null a a 10 test.t2.a,const 4 Using where; Using index +select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7; +a a b +7 7 7 +7 NULL 7 +8 8 7 +8 NULL 7 +explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index +select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null); +a a b +7 7 NULL +7 7 7 +7 NULL 7 +8 8 NULL +8 8 7 +8 NULL 7 +insert into t2 values (null),(6); +delete from t1 where a=8; +explain select * from t2,t1 where t1.a=t2.a or t1.a is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 4 +1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index +explain select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 4 +1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index +select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9); +a a b +7 7 NULL +7 7 7 +7 NULL 7 +8 NULL 7 +NULL NULL 7 +NULL NULL 9 +NULL NULL 9 +6 6 6 +6 NULL 7 +drop table t1,t2; +CREATE TABLE t1 ( +id int(10) unsigned NOT NULL auto_increment, +uniq_id int(10) unsigned default NULL, +PRIMARY KEY (id), +UNIQUE KEY idx1 (uniq_id) +) ENGINE=MyISAM; +CREATE TABLE t2 ( +id int(10) unsigned NOT NULL auto_increment, +uniq_id int(10) unsigned default NULL, +PRIMARY KEY (id) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,NULL),(2,NULL),(3,1),(4,2),(5,NULL),(6,NULL),(7,3),(8,4),(9,NULL),(10,NULL); +INSERT INTO t2 VALUES (1,NULL),(2,NULL),(3,1),(4,2),(5,NULL),(6,NULL),(7,3),(8,4),(9,NULL),(10,NULL); +explain select id from t1 where uniq_id is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref idx1 idx1 5 const 5 Using where +explain select id from t1 where uniq_id =1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const idx1 idx1 5 const 1 +UPDATE t1 SET id=id+100 where uniq_id is null; +UPDATE t2 SET id=id+100 where uniq_id is null; +select id from t1 where uniq_id is null; +id +101 +102 +105 +106 +109 +110 +select id from t2 where uniq_id is null; +id +101 +102 +105 +106 +109 +110 +DELETE FROM t1 WHERE uniq_id IS NULL; +DELETE FROM t2 WHERE uniq_id IS NULL; +SELECT * FROM t1 ORDER BY uniq_id, id; +id uniq_id +3 1 +4 2 +7 3 +8 4 +SELECT * FROM t2 ORDER BY uniq_id, id; +id uniq_id +3 1 +4 2 +7 3 +8 4 +DROP table t1,t2; +CREATE TABLE `t1` ( +`order_id` char(32) NOT NULL default '', +`product_id` char(32) NOT NULL default '', +`product_type` int(11) NOT NULL default '0', +PRIMARY KEY (`order_id`,`product_id`,`product_type`) +) ENGINE=MyISAM; +CREATE TABLE `t2` ( +`order_id` char(32) NOT NULL default '', +`product_id` char(32) NOT NULL default '', +`product_type` int(11) NOT NULL default '0', +PRIMARY KEY (`order_id`,`product_id`,`product_type`) +) ENGINE=MyISAM; +INSERT INTO t1 (order_id, product_id, product_type) VALUES +('3d7ce39b5d4b3e3d22aaafe9b633de51',1206029, 3), +('3d7ce39b5d4b3e3d22aaafe9b633de51',5880836, 3), +('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); +INSERT INTO t2 (order_id, product_id, product_type) VALUES +('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); +select t1.* from t1 +left join t2 using(order_id, product_id, product_type) +where t2.order_id=NULL; +order_id product_id product_type +select t1.* from t1 +left join t2 using(order_id, product_id, product_type) +where t2.order_id is NULL; +order_id product_id product_type +3d7ce39b5d4b3e3d22aaafe9b633de51 1206029 3 +3d7ce39b5d4b3e3d22aaafe9b633de51 5880836 3 +drop table t1,t2; +create table t1 (id int); +insert into t1 values (null), (0); +create table t2 (id int); +insert into t2 values (null); +select * from t1, t2 where t1.id = t2.id; +id id +alter table t1 add key id (id); +select * from t1, t2 where t1.id = t2.id; +id id +drop table t1,t2; +create table t1 ( +id integer, +id2 integer not null, +index (id), +index (id2) +); +insert into t1 values(null,null),(1,1); +Warnings: +Warning 1048 Column 'id2' cannot be null +select * from t1; +id id2 +NULL 0 +1 1 +select * from t1 where id <=> null; +id id2 +NULL 0 +select * from t1 where id <=> null or id > 0; +id id2 +NULL 0 +1 1 +select * from t1 where id is null or id > 0; +id id2 +NULL 0 +1 1 +select * from t1 where id2 <=> null or id2 > 0; +id id2 +1 1 +select * from t1 where id2 is null or id2 > 0; +id id2 +1 1 +delete from t1 where id <=> NULL; +select * from t1; +id id2 +1 1 +drop table t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int, b int, INDEX idx(a)); +CREATE TABLE t3 (b int, INDEX idx(b)); +CREATE TABLE t4 (b int, INDEX idx(b)); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (1, 1), (3, 1); +INSERT INTO t3 VALUES +(NULL), (NULL), (NULL), (NULL), (NULL), +(NULL), (NULL), (NULL), (NULL), (NULL); +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t3 VALUES (2), (3); +ANALYZE table t1, t2, t3; +Table Op Msg_type Msg_text +test.t1 analyze status OK +test.t2 analyze status OK +test.t3 analyze status OK +SELECT COUNT(*) FROM t3; +COUNT(*) +15972 +EXPLAIN SELECT SQL_CALC_FOUND_ROWS * FROM t1 LEFT JOIN t2 ON t1.a=t2.a +LEFT JOIN t3 ON t2.b=t3.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 +1 SIMPLE t2 ref idx idx 5 test.t1.a 2 +1 SIMPLE t3 ref idx idx 5 test.t2.b 186 Using index +FLUSH STATUS ; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LEFT JOIN t2 ON t1.a=t2.a +LEFT JOIN t3 ON t2.b=t3.b; +a a b b +1 1 1 NULL +2 NULL NULL NULL +3 3 1 NULL +4 NULL NULL NULL +SELECT FOUND_ROWS(); +FOUND_ROWS() +4 +SHOW STATUS LIKE "handler_read%"; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/suite/pbxt/r/odbc.result b/mysql-test/suite/pbxt/r/odbc.result new file mode 100644 index 00000000000..5629d3dab33 --- /dev/null +++ b/mysql-test/suite/pbxt/r/odbc.result @@ -0,0 +1,27 @@ +drop table if exists t1; +select {fn length("hello")}, { date "1997-10-20" }; +{fn length("hello")} 1997-10-20 +5 1997-10-20 +create table t1 (a int not null auto_increment,b int not null,primary key (a,b)); +insert into t1 SET A=NULL,B=1; +insert into t1 SET a=null,b=2; +select * from t1 where a is null and b=2; +a b +2 2 +select * from t1 where a is null; +a b +explain select * from t1 where b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +drop table t1; +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (NULL); +SELECT sql_no_cache a, last_insert_id() FROM t1 WHERE a IS NULL; +a last_insert_id() +1 1 +SELECT sql_no_cache a, last_insert_id() FROM t1 WHERE a IS NULL; +a last_insert_id() +SELECT sql_no_cache a, last_insert_id() FROM t1; +a last_insert_id() +1 1 +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/olap.result b/mysql-test/suite/pbxt/r/olap.result new file mode 100644 index 00000000000..0959ebb135f --- /dev/null +++ b/mysql-test/suite/pbxt/r/olap.result @@ -0,0 +1,647 @@ +drop table if exists t1,t2; +set @sav_dpi= @@div_precision_increment; +set div_precision_increment= 5; +show variables like 'div_precision_increment'; +Variable_name Value +div_precision_increment 5 +create table t1 (product varchar(32), country_id int not null, year int, profit int); +insert into t1 values ( 'Computer', 2,2000, 1200), +( 'TV', 1, 1999, 150), +( 'Calculator', 1, 1999,50), +( 'Computer', 1, 1999,1500), +( 'Computer', 1, 2000,1500), +( 'TV', 1, 2000, 150), +( 'TV', 2, 2000, 100), +( 'TV', 2, 2000, 100), +( 'Calculator', 1, 2000,75), +( 'Calculator', 2, 2000,75), +( 'TV', 1, 1999, 100), +( 'Computer', 1, 1999,1200), +( 'Computer', 2, 2000,1500), +( 'Calculator', 2, 2000,75), +( 'Phone', 3, 2003,10) +; +create table t2 (country_id int primary key, country char(20) not null); +insert into t2 values (1, 'USA'),(2,'India'), (3,'Finland'); +select product, sum(profit) from t1 group by product; +product sum(profit) +Calculator 275 +Computer 6900 +Phone 10 +TV 600 +select product, sum(profit) from t1 group by product with rollup; +product sum(profit) +Calculator 275 +Computer 6900 +Phone 10 +TV 600 +NULL 7785 +select product, sum(profit) from t1 group by 1 with rollup; +product sum(profit) +Calculator 275 +Computer 6900 +Phone 10 +TV 600 +NULL 7785 +select product, sum(profit),avg(profit) from t1 group by product with rollup; +product sum(profit) avg(profit) +Calculator 275 68.75000 +Computer 6900 1380.00000 +Phone 10 10.00000 +TV 600 120.00000 +NULL 7785 519.00000 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year; +product country_id year sum(profit) +Calculator 1 1999 50 +Calculator 1 2000 75 +Calculator 2 2000 150 +Computer 1 1999 2700 +Computer 1 2000 1500 +Computer 2 2000 2700 +Phone 3 2003 10 +TV 1 1999 250 +TV 1 2000 150 +TV 2 2000 200 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +product country_id year sum(profit) +Calculator 1 1999 50 +Calculator 1 2000 75 +Calculator 1 NULL 125 +Calculator 2 2000 150 +Calculator 2 NULL 150 +Calculator NULL NULL 275 +Computer 1 1999 2700 +Computer 1 2000 1500 +Computer 1 NULL 4200 +Computer 2 2000 2700 +Computer 2 NULL 2700 +Computer NULL NULL 6900 +Phone 3 2003 10 +Phone 3 NULL 10 +Phone NULL NULL 10 +TV 1 1999 250 +TV 1 2000 150 +TV 1 NULL 400 +TV 2 2000 200 +TV 2 NULL 200 +TV NULL NULL 600 +NULL NULL NULL 7785 +explain extended select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 15 100.00 Using filesort +Warnings: +Note 1003 select `test`.`t1`.`product` AS `product`,`test`.`t1`.`country_id` AS `country_id`,`test`.`t1`.`year` AS `year`,sum(`test`.`t1`.`profit`) AS `sum(profit)` from `test`.`t1` group by `test`.`t1`.`product`,`test`.`t1`.`country_id`,`test`.`t1`.`year` with rollup +select product, country_id , sum(profit) from t1 group by product desc, country_id with rollup; +product country_id sum(profit) +TV 1 400 +TV 2 200 +TV NULL 600 +Phone 3 10 +Phone NULL 10 +Computer 1 4200 +Computer 2 2700 +Computer NULL 6900 +Calculator 1 125 +Calculator 2 150 +Calculator NULL 275 +NULL NULL 7785 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup limit 5; +product country_id year sum(profit) +Calculator 1 1999 50 +Calculator 1 2000 75 +Calculator 1 NULL 125 +Calculator 2 2000 150 +Calculator 2 NULL 150 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup limit 3,3; +product country_id year sum(profit) +Calculator 2 2000 150 +Calculator 2 NULL 150 +Calculator NULL NULL 275 +select product, country_id, count(*), count(distinct year) from t1 group by product, country_id; +product country_id count(*) count(distinct year) +Calculator 1 2 2 +Calculator 2 2 1 +Computer 1 3 2 +Computer 2 2 1 +Phone 3 1 1 +TV 1 3 2 +TV 2 2 1 +select product, country_id, count(*), count(distinct year) from t1 group by product, country_id with rollup; +product country_id count(*) count(distinct year) +Calculator 1 2 2 +Calculator 2 2 1 +Calculator NULL 4 2 +Computer 1 3 2 +Computer 2 2 1 +Computer NULL 5 2 +Phone 3 1 1 +Phone NULL 1 1 +TV 1 3 2 +TV 2 2 1 +TV NULL 5 2 +NULL NULL 15 3 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having country_id = 1; +product country_id year sum(profit) +Calculator 1 1999 50 +Calculator 1 2000 75 +Calculator 1 NULL 125 +Computer 1 1999 2700 +Computer 1 2000 1500 +Computer 1 NULL 4200 +TV 1 1999 250 +TV 1 2000 150 +TV 1 NULL 400 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having sum(profit) > 200; +product country_id year sum(profit) +Calculator NULL NULL 275 +Computer 1 1999 2700 +Computer 1 2000 1500 +Computer 1 NULL 4200 +Computer 2 2000 2700 +Computer 2 NULL 2700 +Computer NULL NULL 6900 +TV 1 1999 250 +TV 1 NULL 400 +TV NULL NULL 600 +NULL NULL NULL 7785 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having sum(profit) > 7000; +product country_id year sum(profit) +NULL NULL NULL 7785 +select concat(product,':',country_id) as 'prod', concat(":",year,":") as 'year',1+1, sum(profit)/count(*) from t1 group by 1,2 with rollup; +prod year 1+1 sum(profit)/count(*) +Calculator:1 :1999: 2 50.00000 +Calculator:1 :2000: 2 75.00000 +Calculator:1 NULL 2 62.50000 +Calculator:2 :2000: 2 75.00000 +Calculator:2 NULL 2 75.00000 +Computer:1 :1999: 2 1350.00000 +Computer:1 :2000: 2 1500.00000 +Computer:1 NULL 2 1400.00000 +Computer:2 :2000: 2 1350.00000 +Computer:2 NULL 2 1350.00000 +Phone:3 :2003: 2 10.00000 +Phone:3 NULL 2 10.00000 +TV:1 :1999: 2 125.00000 +TV:1 :2000: 2 150.00000 +TV:1 NULL 2 133.33333 +TV:2 :2000: 2 100.00000 +TV:2 NULL 2 100.00000 +NULL NULL 2 519.00000 +select product, sum(profit)/count(*) from t1 group by product with rollup; +product sum(profit)/count(*) +Calculator 68.75000 +Computer 1380.00000 +Phone 10.00000 +TV 120.00000 +NULL 519.00000 +select left(product,4) as prod, sum(profit)/count(*) from t1 group by prod with rollup; +prod sum(profit)/count(*) +Calc 68.75000 +Comp 1380.00000 +Phon 10.00000 +TV 120.00000 +NULL 519.00000 +select concat(product,':',country_id), 1+1, sum(profit)/count(*) from t1 group by concat(product,':',country_id) with rollup; +concat(product,':',country_id) 1+1 sum(profit)/count(*) +Calculator:1 2 62.50000 +Calculator:2 2 75.00000 +Computer:1 2 1400.00000 +Computer:2 2 1350.00000 +Phone:3 2 10.00000 +TV:1 2 133.33333 +TV:2 2 100.00000 +NULL 2 519.00000 +select product, country , year, sum(profit) from t1,t2 where t1.country_id=t2.country_id group by product, country, year with rollup; +product country year sum(profit) +Calculator India 2000 150 +Calculator India NULL 150 +Calculator USA 1999 50 +Calculator USA 2000 75 +Calculator USA NULL 125 +Calculator NULL NULL 275 +Computer India 2000 2700 +Computer India NULL 2700 +Computer USA 1999 2700 +Computer USA 2000 1500 +Computer USA NULL 4200 +Computer NULL NULL 6900 +Phone Finland 2003 10 +Phone Finland NULL 10 +Phone NULL NULL 10 +TV India 2000 200 +TV India NULL 200 +TV USA 1999 250 +TV USA 2000 150 +TV USA NULL 400 +TV NULL NULL 600 +NULL NULL NULL 7785 +select product, `sum` from (select product, sum(profit) as 'sum' from t1 group by product with rollup) as tmp where product is null; +product sum +NULL 7785 +select product from t1 where exists (select product, country_id , sum(profit) from t1 as t2 where t1.product=t2.product group by product, country_id with rollup having sum(profit) > 6000); +product +Computer +Computer +Computer +Computer +Computer +select product, country_id , year, sum(profit) from t1 group by product, country_id, year having country_id is NULL; +product country_id year sum(profit) +select concat(':',product,':'), sum(profit),avg(profit) from t1 group by product with rollup; +concat(':',product,':') sum(profit) avg(profit) +:Calculator: 275 68.75000 +:Computer: 6900 1380.00000 +:Phone: 10 10.00000 +:TV: 600 120.00000 +NULL 7785 519.00000 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; +ERROR 42000: This version of MySQL doesn't yet support 'CUBE' +explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; +ERROR 42000: This version of MySQL doesn't yet support 'CUBE' +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube union all select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +ERROR 42000: This version of MySQL doesn't yet support 'CUBE' +drop table t1,t2; +CREATE TABLE t1 (i int); +INSERT INTO t1 VALUES(100); +CREATE TABLE t2 (i int); +INSERT INTO t2 VALUES (100),(200); +SELECT i, COUNT(*) FROM t1 GROUP BY i WITH ROLLUP; +i COUNT(*) +100 1 +NULL 1 +SELECT t1.i, t2.i, COUNT(*) FROM t1,t2 GROUP BY t1.i,t2.i WITH ROLLUP; +i i COUNT(*) +100 100 1 +100 200 1 +100 NULL 2 +NULL NULL 2 +drop table t1,t2; +CREATE TABLE user_day( +user_id INT NOT NULL, +date DATE NOT NULL, +UNIQUE INDEX user_date (user_id, date) +); +INSERT INTO user_day VALUES +(1, '2004-06-06' ), +(1, '2004-06-07' ), +(2, '2004-06-06' ); +SELECT +d.date AS day, +COUNT(d.user_id) as sample, +COUNT(next_day.user_id) AS not_cancelled +FROM user_day d +LEFT JOIN user_day next_day +ON next_day.user_id=d.user_id AND +next_day.date= DATE_ADD( d.date, interval 1 day ) +GROUP BY day; +day sample not_cancelled +2004-06-06 2 1 +2004-06-07 1 0 +SELECT +d.date AS day, +COUNT(d.user_id) as sample, +COUNT(next_day.user_id) AS not_cancelled +FROM user_day d +LEFT JOIN user_day next_day +ON next_day.user_id=d.user_id AND +next_day.date= DATE_ADD( d.date, interval 1 day ) +GROUP BY day +WITH ROLLUP; +day sample not_cancelled +2004-06-06 2 1 +2004-06-07 1 0 +NULL 3 1 +DROP TABLE user_day; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES +(1,4), +(2,2), (2,2), +(4,1), (4,1), (4,1), (4,1), +(2,1), (2,1); +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) +4 +6 +4 +14 +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) +4 +6 +14 +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) +4 1 +6 2 +4 1 +14 3 +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) +4 1 +6 2 +14 3 +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(*) +4 1 +6 4 +4 4 +14 9 +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(*) +4 1 +6 4 +4 4 +14 9 +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) COUNT(*) +4 1 1 +6 2 4 +4 1 4 +14 3 9 +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 +GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) COUNT(*) +4 1 1 +6 2 4 +4 1 4 +14 3 9 +SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +a sum(b) +1 4 +1 4 +2 2 +2 4 +2 6 +4 4 +4 4 +NULL 14 +SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +a sum(b) +1 4 +2 2 +2 4 +2 6 +4 4 +NULL 14 +SELECT b, a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +b a sum(b) +4 1 4 +NULL 1 4 +1 2 2 +2 2 4 +NULL 2 6 +1 4 4 +NULL 4 4 +NULL NULL 14 +SELECT DISTINCT b,a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +b a sum(b) +4 1 4 +NULL 1 4 +1 2 2 +2 2 4 +NULL 2 6 +1 4 4 +NULL 4 4 +NULL NULL 14 +ALTER TABLE t1 ADD COLUMN c INT; +SELECT a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP; +a b sum(c) +1 4 NULL +1 4 NULL +1 NULL NULL +2 1 NULL +2 1 NULL +2 2 NULL +2 2 NULL +2 NULL NULL +4 1 NULL +4 1 NULL +4 NULL NULL +NULL NULL NULL +SELECT distinct a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP; +a b sum(c) +1 4 NULL +1 NULL NULL +2 1 NULL +2 2 NULL +2 NULL NULL +4 1 NULL +4 NULL NULL +NULL NULL NULL +DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES +(1,4), +(2,2), (2,2), +(4,1), (4,1), (4,1), (4,1), +(2,1), (2,1); +SELECT a, SUM(b) FROM t1 GROUP BY a WITH ROLLUP LIMIT 1; +a SUM(b) +1 4 +SELECT SQL_CALC_FOUND_ROWS a, SUM(b) FROM t1 GROUP BY a WITH ROLLUP LIMIT 1; +a SUM(b) +1 4 +DROP TABLE t1; +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +SELECT a, SUM(a) m FROM t1 GROUP BY a WITH ROLLUP; +a m +1 1 +2 2 +NULL 3 +SELECT * FROM ( SELECT a, SUM(a) m FROM t1 GROUP BY a WITH ROLLUP ) t2; +a m +1 1 +2 2 +NULL 3 +DROP TABLE t1; +set div_precision_increment= @sav_dpi; +CREATE TABLE t1 (a int(11)); +INSERT INTO t1 VALUES (1),(2); +SELECT a, SUM(a), SUM(a)+1 FROM (SELECT a FROM t1 UNION select 2) d +GROUP BY a; +a SUM(a) SUM(a)+1 +1 1 2 +2 2 3 +SELECT a, SUM(a), SUM(a)+1 FROM (SELECT a FROM t1 UNION select 2) d +GROUP BY a WITH ROLLUP; +a SUM(a) SUM(a)+1 +1 1 2 +2 2 3 +NULL 3 4 +SELECT a, SUM(a), SUM(a)+1 FROM (SELECT 1 a UNION select 2) d +GROUP BY a; +a SUM(a) SUM(a)+1 +1 1 2 +2 2 3 +SELECT a, SUM(a), SUM(a)+1 FROM (SELECT 1 a UNION select 2) d +GROUP BY a WITH ROLLUP; +a SUM(a) SUM(a)+1 +1 1 2 +2 2 3 +NULL 3 4 +SELECT a, SUM(a), SUM(a)+1, CONCAT(SUM(a),'x'), SUM(a)+SUM(a), SUM(a) +FROM (SELECT 1 a, 2 b UNION SELECT 2,3 UNION SELECT 5,6 ) d +GROUP BY a WITH ROLLUP; +a SUM(a) SUM(a)+1 CONCAT(SUM(a),'x') SUM(a)+SUM(a) SUM(a) +1 1 2 1x 2 1 +2 2 3 2x 4 2 +5 5 6 5x 10 5 +NULL 8 9 8x 16 8 +DROP TABLE t1; +CREATE TABLE t1 (a int(11)); +INSERT INTO t1 VALUES (1),(2); +SELECT a, a+1, SUM(a) FROM t1 GROUP BY a WITH ROLLUP; +a a+1 SUM(a) +1 2 1 +2 3 2 +NULL NULL 3 +SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP; +a+1 +2 +3 +NULL +SELECT a+SUM(a) FROM t1 GROUP BY a WITH ROLLUP; +a+SUM(a) +2 +4 +NULL +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b > 2; +a b +2 3 +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING a IS NULL; +a b +NULL NULL +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b IS NULL; +a b +NULL NULL +SELECT IFNULL(a, 'TEST') FROM t1 GROUP BY a WITH ROLLUP; +IFNULL(a, 'TEST') +1 +2 +TEST +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES +(1,4), +(2,2), (2,2), +(4,1), (4,1), (4,1), (4,1), +(2,1), (2,1); +SELECT a,b,SUM(b) FROM t2 GROUP BY a,b WITH ROLLUP; +a b SUM(b) +1 4 4 +1 NULL 4 +2 1 2 +2 2 4 +2 NULL 6 +4 1 4 +4 NULL 4 +NULL NULL 14 +SELECT a,b,SUM(b), a+b as c FROM t2 +GROUP BY a,b WITH ROLLUP HAVING c IS NULL; +a b SUM(b) c +1 NULL 4 NULL +2 NULL 6 NULL +4 NULL 4 NULL +NULL NULL 14 NULL +SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 +GROUP BY a, b WITH ROLLUP; +IFNULL(a, 'TEST') COALESCE(b, 'TEST') +1 4 +1 TEST +2 1 +2 2 +2 TEST +4 1 +4 TEST +TEST TEST +DROP TABLE t1,t2; +CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (1, 2); +SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; +a b c count +1 1 1 1 +1 1 NULL 1 +1 2 1 1 +1 2 NULL 1 +1 NULL NULL 2 +NULL NULL NULL 2 +DROP TABLE t1; +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a a + 1 COUNT(*) +1 2 1 +2 3 1 +NULL NULL 2 +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP TABLE t1; +create table t1 ( a varchar(9), b int ); +insert into t1 values('a',1),(null,2); +select a, max(b) from t1 group by a with rollup; +a max(b) +NULL 2 +a 1 +NULL 2 +select distinct a, max(b) from t1 group by a with rollup; +a max(b) +NULL 2 +a 1 +drop table t1; +create table t1 (a varchar(22) not null , b int); +insert into t1 values ("2006-07-01 21:30", 1), ("2006-07-01 23:30", 10); +select left(a,10), a, sum(b) from t1 group by 1,2 with rollup; +left(a,10) a sum(b) +2006-07-01 2006-07-01 21:30 1 +2006-07-01 2006-07-01 23:30 10 +2006-07-01 NULL 11 +NULL NULL 11 +select left(a,10) x, a, sum(b) from t1 group by x,a with rollup; +x a sum(b) +2006-07-01 2006-07-01 21:30 1 +2006-07-01 2006-07-01 23:30 10 +2006-07-01 NULL 11 +NULL NULL 11 +drop table t1; +CREATE TABLE t1(id int, type char(1)); +INSERT INTO t1 VALUES +(1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), +(6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C"); +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT type FROM t1 GROUP BY type WITH ROLLUP; +type +A +B +C +NULL +SELECT type FROM v1 GROUP BY type WITH ROLLUP; +type +A +B +C +NULL +EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using filesort +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +CREATE VIEW v1 AS +SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +DESC v1; +Field Type Null Key Default Extra +a bigint(11) YES NULL +LENGTH(a) bigint(10) YES NULL +COUNT(*) bigint(21) NO 0 +SELECT * FROM v1; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/order_by.result b/mysql-test/suite/pbxt/r/order_by.result new file mode 100644 index 00000000000..54a0b2616ae --- /dev/null +++ b/mysql-test/suite/pbxt/r/order_by.result @@ -0,0 +1,929 @@ +drop table if exists t1,t2,t3; +CREATE TABLE t1 ( +id int(6) DEFAULT '0' NOT NULL, +idservice int(5), +clee char(20) NOT NULL, +flag char(1), +KEY id (id), +PRIMARY KEY (clee) +); +INSERT INTO t1 VALUES (2,4,'6067169d','Y'); +INSERT INTO t1 VALUES (2,5,'606716d1','Y'); +INSERT INTO t1 VALUES (2,1,'606717c1','Y'); +INSERT INTO t1 VALUES (3,1,'6067178d','Y'); +INSERT INTO t1 VALUES (2,6,'60671515','Y'); +INSERT INTO t1 VALUES (2,7,'60671569','Y'); +INSERT INTO t1 VALUES (2,3,'dd','Y'); +CREATE TABLE t2 ( +id int(6) NOT NULL auto_increment, +description varchar(40) NOT NULL, +idform varchar(40), +ordre int(6) unsigned DEFAULT '0' NOT NULL, +image varchar(60), +PRIMARY KEY (id), +KEY id (id,ordre) +); +INSERT INTO t2 VALUES (1,'Emettre un appel d''offres','en_construction.html',10,'emettre.gif'); +INSERT INTO t2 VALUES (2,'Emettre des soumissions','en_construction.html',20,'emettre.gif'); +INSERT INTO t2 VALUES (7,'Liste des t2','t2_liste_form.phtml',51060,'link.gif'); +INSERT INTO t2 VALUES (8,'Consulter les soumissions','consulter_soumissions.phtml',200,'link.gif'); +INSERT INTO t2 VALUES (9,'Ajouter un type de materiel','typeMateriel_ajoute_form.phtml',51000,'link.gif'); +INSERT INTO t2 VALUES (10,'Lister/modifier un type de materiel','typeMateriel_liste_form.phtml',51010,'link.gif'); +INSERT INTO t2 VALUES (3,'Créer une fiche de client','clients_ajoute_form.phtml',40000,'link.gif'); +INSERT INTO t2 VALUES (4,'Modifier des clients','en_construction.html',40010,'link.gif'); +INSERT INTO t2 VALUES (5,'Effacer des clients','en_construction.html',40020,'link.gif'); +INSERT INTO t2 VALUES (6,'Ajouter un service','t2_ajoute_form.phtml',51050,'link.gif'); +select t1.id,t1.idservice,t2.ordre,t2.description from t1, t2 where t1.id = 2 and t1.idservice = t2.id order by t2.ordre; +id idservice ordre description +2 1 10 Emettre un appel d'offres +2 3 40000 Créer une fiche de client +2 4 40010 Modifier des clients +2 5 40020 Effacer des clients +2 6 51050 Ajouter un service +2 7 51060 Liste des t2 +drop table t1,t2; +create table t1 (first char(10),last char(10)); +insert into t1 values ("Michael","Widenius"); +insert into t1 values ("Allan","Larsson"); +insert into t1 values ("David","Axmark"); +select concat(first," ",last) as name from t1 order by name; +name +Allan Larsson +David Axmark +Michael Widenius +select concat(last," ",first) as name from t1 order by name; +name +Axmark David +Larsson Allan +Widenius Michael +drop table t1; +create table t1 (i int); +insert into t1 values(1),(2),(1),(2),(1),(2),(3); +select distinct i from t1; +i +1 +2 +3 +select distinct i from t1 order by rand(5); +i +1 +3 +2 +select distinct i from t1 order by i desc; +i +3 +2 +1 +select distinct i from t1 order by 1-i; +i +3 +2 +1 +select distinct i from t1 order by mod(i,2),i; +i +2 +1 +3 +drop table t1; +create table t1 ( pk int primary key, name varchar(255) not null, number varchar(255) not null); +insert into t1 values (1, 'Gamma', '123'), (2, 'Gamma Ext', '123a'), (3, 'Alpha', '001'), (4, 'Beta', '200c'); +select distinct t1.name as 'Building Name',t1.number as 'Building Number' from t1 order by t1.name asc; +Building Name Building Number +Alpha 001 +Beta 200c +Gamma 123 +Gamma Ext 123a +drop table t1; +create table t1 (id int not null,col1 int not null,col2 int not null,index(col1)); +insert into t1 values(1,2,2),(2,2,1),(3,1,2),(4,1,1),(5,1,4),(6,2,3),(7,3,1),(8,2,4); +select * from t1 order by col1,col2; +id col1 col2 +4 1 1 +3 1 2 +5 1 4 +2 2 1 +1 2 2 +6 2 3 +8 2 4 +7 3 1 +select col1 from t1 order by id; +col1 +2 +2 +1 +1 +1 +2 +3 +2 +select col1 as id from t1 order by id; +id +1 +1 +1 +2 +2 +2 +2 +3 +select concat(col1) as id from t1 order by id; +id +1 +1 +1 +2 +2 +2 +2 +3 +drop table t1; +CREATE TABLE t1 (id int auto_increment primary key,aika varchar(40),aikakentta timestamp); +insert into t1 (aika) values ('Keskiviikko'); +insert into t1 (aika) values ('Tiistai'); +insert into t1 (aika) values ('Maanantai'); +insert into t1 (aika) values ('Sunnuntai'); +SELECT FIELD(SUBSTRING(t1.aika,1,2),'Ma','Ti','Ke','To','Pe','La','Su') AS test FROM t1 ORDER by test; +test +1 +2 +3 +7 +drop table t1; +CREATE TABLE t1 +( +a int unsigned NOT NULL, +b int unsigned NOT NULL, +c int unsigned NOT NULL, +UNIQUE(a), +INDEX(b), +INDEX(c) +); +CREATE TABLE t2 +( +c int unsigned NOT NULL, +i int unsigned NOT NULL, +INDEX(c) +); +CREATE TABLE t3 +( +c int unsigned NOT NULL, +v varchar(64), +INDEX(c) +); +INSERT INTO t1 VALUES (1,1,1); +INSERT INTO t1 VALUES (2,1,2); +INSERT INTO t1 VALUES (3,2,1); +INSERT INTO t1 VALUES (4,2,2); +INSERT INTO t2 VALUES (1,50); +INSERT INTO t2 VALUES (2,25); +INSERT INTO t3 VALUES (1,'123 Park Place'); +INSERT INTO t3 VALUES (2,'453 Boardwalk'); +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 USING(c) +LEFT JOIN t3 ON t3.c = t1.c; +a b if(b = 1,i,if(b = 2,v,'')) +1 1 50 +2 1 25 +3 2 123 Park Place +4 2 453 Boardwalk +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 ON t1.c = t2.c +LEFT JOIN t3 ON t3.c = t1.c; +a b if(b = 1,i,if(b = 2,v,'')) +1 1 50 +2 1 25 +3 2 123 Park Place +4 2 453 Boardwalk +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 USING(c) +LEFT JOIN t3 ON t3.c = t1.c +ORDER BY a; +a b if(b = 1,i,if(b = 2,v,'')) +1 1 50 +2 1 25 +3 2 123 Park Place +4 2 453 Boardwalk +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 ON t1.c = t2.c +LEFT JOIN t3 ON t3.c = t1.c +ORDER BY a; +a b if(b = 1,i,if(b = 2,v,'')) +1 1 50 +2 1 25 +3 2 123 Park Place +4 2 453 Boardwalk +drop table t1,t2,t3; +create table t1 (ID int not null primary key, TransactionID int not null); +insert into t1 (ID, TransactionID) values (1, 87), (2, 89), (3, 92), (4, 94), (5, 486), (6, 490), (7, 753), (9, 828), (10, 832), (11, 834), (12, 840); +create table t2 (ID int not null primary key, GroupID int not null); +insert into t2 (ID, GroupID) values (87, 87), (89, 89), (92, 92), (94, 94), (486, 486), (490, 490),(753, 753), (828, 828), (832, 832), (834, 834), (840, 840); +create table t3 (ID int not null primary key, DateOfAction date not null); +insert into t3 (ID, DateOfAction) values (87, '1999-07-19'), (89, '1999-07-19'), (92, '1999-07-19'), (94, '1999-07-19'), (486, '1999-07-18'), (490, '2000-03-27'), (753, '2000-03-28'), (828, '1999-07-27'), (832, '1999-07-27'),(834, '1999-07-27'), (840, '1999-07-27'); +select t3.DateOfAction, t1.TransactionID from t1 join t2 join t3 where t2.ID = t1.TransactionID and t3.ID = t2.GroupID order by t3.DateOfAction, t1.TransactionID; +DateOfAction TransactionID +1999-07-18 486 +1999-07-19 87 +1999-07-19 89 +1999-07-19 92 +1999-07-19 94 +1999-07-27 828 +1999-07-27 832 +1999-07-27 834 +1999-07-27 840 +2000-03-27 490 +2000-03-28 753 +select t3.DateOfAction, t1.TransactionID from t1 join t2 join t3 where t2.ID = t1.TransactionID and t3.ID = t2.GroupID order by t1.TransactionID,t3.DateOfAction; +DateOfAction TransactionID +1999-07-19 87 +1999-07-19 89 +1999-07-19 92 +1999-07-19 94 +1999-07-18 486 +2000-03-27 490 +2000-03-28 753 +1999-07-27 828 +1999-07-27 832 +1999-07-27 834 +1999-07-27 840 +drop table t1,t2,t3; +CREATE TABLE t1 ( +member_id int(11) NOT NULL auto_increment, +inschrijf_datum varchar(20) NOT NULL default '', +lastchange_datum varchar(20) NOT NULL default '', +nickname varchar(20) NOT NULL default '', +password varchar(8) NOT NULL default '', +voornaam varchar(30) NOT NULL default '', +tussenvoegsels varchar(10) NOT NULL default '', +achternaam varchar(50) NOT NULL default '', +straat varchar(100) NOT NULL default '', +postcode varchar(10) NOT NULL default '', +wijk varchar(40) NOT NULL default '', +plaats varchar(50) NOT NULL default '', +telefoon varchar(10) NOT NULL default '', +geboortedatum date NOT NULL default '0000-00-00', +geslacht varchar(5) NOT NULL default '', +email varchar(80) NOT NULL default '', +uin varchar(15) NOT NULL default '', +homepage varchar(100) NOT NULL default '', +internet varchar(15) NOT NULL default '', +scherk varchar(30) NOT NULL default '', +favo_boek varchar(50) NOT NULL default '', +favo_tijdschrift varchar(50) NOT NULL default '', +favo_tv varchar(50) NOT NULL default '', +favo_eten varchar(50) NOT NULL default '', +favo_muziek varchar(30) NOT NULL default '', +info text NOT NULL default '', +ipnr varchar(30) NOT NULL default '', +PRIMARY KEY (member_id) +) ENGINE=MyISAM PACK_KEYS=1; +Warnings: +Warning 1101 BLOB/TEXT column 'info' can't have a default value +insert into t1 (member_id) values (1),(2),(3); +select member_id, nickname, voornaam FROM t1 +ORDER by lastchange_datum DESC LIMIT 2; +member_id nickname voornaam +1 +2 +drop table t1; +create table t1 (a int not null, b int, c varchar(10), key (a, b, c)); +insert into t1 values (1, NULL, NULL), (1, NULL, 'b'), (1, 1, NULL), (1, 1, 'b'), (1, 1, 'b'), (2, 1, 'a'), (2, 1, 'b'), (2, 2, 'a'), (2, 2, 'b'), (2, 3, 'c'),(1,3,'b'); +explain select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index a a 22 NULL 11 Using where; Using index +select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc; +a b c +1 NULL b +explain select * from t1 where a >= 1 and a < 3 order by a desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 4 NULL 1 Using where; Using index +select * from t1 where a >= 1 and a < 3 order by a desc; +a b c +2 3 c +2 2 b +2 2 a +2 1 b +2 1 a +1 3 b +1 1 b +1 1 b +1 1 NULL +1 NULL b +1 NULL NULL +explain select * from t1 where a = 1 order by a desc, b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 4 const 1 Using where; Using index +select * from t1 where a = 1 order by a desc, b desc; +a b c +1 3 b +1 1 b +1 1 b +1 1 NULL +1 NULL b +1 NULL NULL +explain select * from t1 where a = 1 and b is null order by a desc, b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 9 const,const 1 Using where; Using index; Using filesort +select * from t1 where a = 1 and b is null order by a desc, b desc; +a b c +1 NULL NULL +1 NULL b +explain select * from t1 where a >= 1 and a < 3 and b >0 order by a desc,b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 9 NULL 1 Using where; Using index +explain select * from t1 where a = 2 and b >0 order by a desc,b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 9 NULL 1 Using where; Using index +explain select * from t1 where a = 2 and b is null order by a desc,b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 9 const,const 1 Using where; Using index; Using filesort +explain select * from t1 where a = 2 and (b is null or b > 0) order by a +desc,b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 4 const 2 Using where; Using index +explain select * from t1 where a = 2 and b > 0 order by a desc,b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 9 NULL 1 Using where; Using index +explain select * from t1 where a = 2 and b < 2 order by a desc,b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 9 NULL 1 Using where; Using index +explain select * from t1 where a = 1 order by b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 4 const 1 Using where; Using index +select * from t1 where a = 1 order by b desc; +a b c +1 3 b +1 1 b +1 1 b +1 1 NULL +1 NULL b +1 NULL NULL +alter table t1 modify b int not null, modify c varchar(10) not null; +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'c' at row 1 +Warning 1265 Data truncated for column 'b' at row 2 +Warning 1265 Data truncated for column 'c' at row 3 +explain select * from t1 order by a, b, c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 20 NULL 11 Using index +select * from t1 order by a, b, c; +a b c +1 0 +1 0 b +1 1 +1 1 b +1 1 b +1 3 b +2 1 a +2 1 b +2 2 a +2 2 b +2 3 c +explain select * from t1 order by a desc, b desc, c desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 20 NULL 11 Using index +select * from t1 order by a desc, b desc, c desc; +a b c +2 3 c +2 2 b +2 2 a +2 1 b +2 1 a +1 3 b +1 1 b +1 1 b +1 1 +1 0 b +1 0 +explain select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index a a 20 NULL 11 Using where; Using index +select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc; +a b c +1 1 b +1 1 b +explain select * from t1 where a < 2 and b <= 1 order by a desc, b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 4 NULL 1 Using where; Using index +select * from t1 where a < 2 and b <= 1 order by a desc, b desc; +a b c +1 1 b +1 1 b +1 1 +1 0 b +1 0 +select count(*) from t1 where a < 5 and b > 0; +count(*) +9 +select * from t1 where a < 5 and b > 0 order by a desc,b desc; +a b c +2 3 c +2 2 b +2 2 a +2 1 b +2 1 a +1 3 b +1 1 b +1 1 b +1 1 +explain select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 8 NULL 1 Using where; Using index +select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc; +a b c +2 1 b +2 1 a +1 1 b +1 1 b +1 1 +1 0 b +1 0 +explain select * from t1 where a between 0 and 1 order by a desc, b desc; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 4 NULL 1 Using where; Using index +select * from t1 where a between 0 and 1 order by a desc, b desc; +a b c +1 3 b +1 1 b +1 1 b +1 1 +1 0 b +1 0 +drop table t1; +CREATE TABLE t1 ( +gid int(10) unsigned NOT NULL auto_increment, +cid smallint(5) unsigned NOT NULL default '0', +PRIMARY KEY (gid), +KEY component_id (cid) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (103853,108),(103867,108),(103962,108),(104505,108),(104619,108),(104620,108); +ALTER TABLE t1 add skr int(10) not null; +CREATE TABLE t2 ( +gid int(10) unsigned NOT NULL default '0', +uid smallint(5) unsigned NOT NULL default '1', +sid tinyint(3) unsigned NOT NULL default '1', +PRIMARY KEY (gid), +KEY uid (uid), +KEY status_id (sid) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (103853,250,5),(103867,27,5),(103962,27,5),(104505,117,5),(104619,75,5),(104620,15,5); +CREATE TABLE t3 ( +uid smallint(6) NOT NULL auto_increment, +PRIMARY KEY (uid) +) ENGINE=MyISAM; +INSERT INTO t3 VALUES (1),(15),(27),(75),(117),(250); +ALTER TABLE t3 add skr int(10) not null; +select t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid; +gid sid uid +104620 5 15 +103867 5 27 +103962 5 27 +104619 5 75 +104505 5 117 +103853 5 250 +select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid; +gid sid uid +104620 5 15 +103867 5 27 +103962 5 27 +104619 5 75 +104505 5 117 +103853 5 250 +EXPLAIN select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t1.gid, t3.uid; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY,uid NULL NULL NULL 6 Using temporary; Using filesort +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t2.uid 1 Using where; Using index +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.gid 1 Using index +EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t1.gid,t3.skr; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL PRIMARY NULL NULL NULL 6 Using temporary; Using filesort +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t3.uid 1 Using where; Using index +EXPLAIN SELECT t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY,uid NULL NULL NULL 6 Using temporary; Using filesort +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.gid 1 Using index +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t2.uid 1 Using where; Using index +EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t3.skr,t1.gid; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL PRIMARY NULL NULL NULL 6 Using temporary; Using filesort +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t3.uid 1 Using where; Using index +EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.skr = t3.uid order by t1.gid,t3.skr; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary; Using filesort +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t1.skr 1 Using where +drop table t1,t2,t3; +CREATE TABLE t1 ( +`titre` char(80) NOT NULL default '', +`numeropost` mediumint(8) unsigned NOT NULL auto_increment, +`date` datetime NOT NULL default '0000-00-00 00:00:00', +`auteur` char(35) NOT NULL default '', +`icone` tinyint(2) unsigned NOT NULL default '0', +`lastauteur` char(35) NOT NULL default '', +`nbrep` smallint(6) unsigned NOT NULL default '0', +`dest` char(35) NOT NULL default '', +`lu` tinyint(1) unsigned NOT NULL default '0', +`vue` mediumint(8) unsigned NOT NULL default '0', +`ludest` tinyint(1) unsigned NOT NULL default '0', +`ouvert` tinyint(1) unsigned NOT NULL default '1', +PRIMARY KEY (`numeropost`), +KEY `date` (`date`), +KEY `dest` (`dest`,`ludest`), +KEY `auteur` (`auteur`,`lu`), +KEY `auteur_2` (`auteur`,`date`), +KEY `dest_2` (`dest`,`date`) +) CHECKSUM=1; +CREATE TABLE t2 ( +`numeropost` mediumint(8) unsigned NOT NULL default '0', +`pseudo` char(35) NOT NULL default '', +PRIMARY KEY (`numeropost`,`pseudo`), +KEY `pseudo` (`pseudo`) +); +INSERT INTO t1 (titre,auteur,dest) VALUES ('test','joce','bug'); +INSERT INTO t2 (numeropost,pseudo) VALUES (1,'joce'),(1,'bug'); +SELECT titre,t1.numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest +test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug +SELECT titre,numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest +test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug +SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest +test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug +SELECT titre,numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest +test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug +drop table t1,t2; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1, 2); +INSERT INTO t1 VALUES (3, 4); +INSERT INTO t1 VALUES (5, NULL); +SELECT * FROM t1 ORDER BY b; +a b +5 NULL +1 2 +3 4 +SELECT * FROM t1 ORDER BY b DESC; +a b +3 4 +1 2 +5 NULL +SELECT * FROM t1 ORDER BY (a + b); +a b +5 NULL +1 2 +3 4 +SELECT * FROM t1 ORDER BY (a + b) DESC; +a b +3 4 +1 2 +5 NULL +DROP TABLE t1; +create table t1(id int not null auto_increment primary key, t char(12)); +explain select id,t from t1 order by id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1000 Using filesort +explain select id,t from t1 force index (primary) order by id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 1000 +drop table t1; +CREATE TABLE t1 ( +FieldKey varchar(36) NOT NULL default '', +LongVal bigint(20) default NULL, +StringVal mediumtext, +KEY FieldKey (FieldKey), +KEY LongField (FieldKey,LongVal), +KEY StringField (FieldKey,StringVal(32)) +); +INSERT INTO t1 VALUES ('0',3,'0'),('0',2,'1'),('0',1,'2'),('1',2,'1'),('1',1,'3'), ('1',0,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('3',2,'1'),('3',1,'2'),('3','3','3'); +EXPLAIN SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref FieldKey,LongField,StringField LongField 38 const 1 Using where +SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal; +FieldKey LongVal StringVal +1 0 2 +1 1 3 +1 2 1 +EXPLAIN SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range FieldKey,LongField,StringField FieldKey 38 NULL 1 Using where; Using filesort +SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal; +FieldKey LongVal StringVal +3 1 2 +3 2 1 +3 3 3 +EXPLAIN SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY FieldKey, LongVal; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range FieldKey,LongField,StringField LongField 38 NULL 1 Using where +SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY FieldKey, LongVal; +FieldKey LongVal StringVal +3 1 2 +3 2 1 +3 3 3 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT); +SET @id=0; +UPDATE t1 SET a=0 ORDER BY (a=@id), b; +DROP TABLE t1; +CREATE TABLE t1 ( id smallint(6) unsigned NOT NULL default '0', menu tinyint(4) NOT NULL default '0', KEY id (id), KEY menu (menu)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (11384, 2),(11392, 2); +SELECT id FROM t1 WHERE id <11984 AND menu =2 ORDER BY id DESC LIMIT 1 ; +id +11392 +drop table t1; +create table t1(a int, b int, index(b)); +insert into t1 values (2, 1), (1, 1), (4, NULL), (3, NULL), (6, 2), (5, 2); +explain select * from t1 where b=1 or b is null order by a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null b b 5 const 2 Using where; Using filesort +select * from t1 where b=1 or b is null order by a; +a b +1 1 +2 1 +3 NULL +4 NULL +explain select * from t1 where b=2 or b is null order by a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null b b 5 const 2 Using where; Using filesort +select * from t1 where b=2 or b is null order by a; +a b +3 NULL +4 NULL +5 2 +6 2 +drop table t1; +create table t1 (a int not null auto_increment, b int not null, c int not null, d int not null, +key(a,b,d), key(c,b,a)); +create table t2 like t1; +insert into t1 values (NULL, 1, 2, 0), (NULL, 2, 1, 1), (NULL, 3, 4, 2), (NULL, 4, 3, 3); +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +set @row=10; +insert into t1 select 1, b, c + (@row:=@row - 1) * 10, d - @row from t2 limit 10; +select * from t1 where a=1 and b in (1) order by c, b, a; +a b c d +1 1 2 0 +1 1 12 -1 +1 1 52 -5 +1 1 92 -9 +select * from t1 where a=1 and b in (1); +a b c d +1 1 92 -9 +1 1 52 -5 +1 1 12 -1 +1 1 2 0 +drop table t1, t2; +create table t1 (col1 int, col int); +create table t2 (col2 int, col int); +insert into t1 values (1,1),(2,2),(3,3); +insert into t2 values (1,3),(2,2),(3,1); +select t1.* , t2.col as t2_col from t1 left join t2 on (t1.col1=t2.col2) +order by col; +col1 col t2_col +1 1 3 +2 2 2 +3 3 1 +select col1 as col, col from t1 order by col; +ERROR 23000: Column 'col' in order clause is ambiguous +select t1.col as c1, t2.col as c2 from t1, t2 where t1.col1=t2.col2 +order by col; +ERROR 23000: Column 'col' in order clause is ambiguous +select t1.col as c1, t2.col as c2 from t1, t2 where t1.col1=t2.col2 +order by col; +ERROR 23000: Column 'col' in order clause is ambiguous +select col1 from t1, t2 where t1.col1=t2.col2 order by col; +ERROR 23000: Column 'col' in order clause is ambiguous +select t1.col as t1_col, t2.col2 from t1, t2 where t1.col1=t2.col2 +order by col; +ERROR 23000: Column 'col' in order clause is ambiguous +select t1.col as t1_col, t2.col from t1, t2 where t1.col1=t2.col2 +order by col; +t1_col col +3 1 +2 2 +1 3 +select col2 as c, col as c from t2 order by col; +c c +3 1 +2 2 +1 3 +select col2 as col, col as col2 from t2 order by col; +col col2 +1 3 +2 2 +3 1 +select t2.col2, t2.col, t2.col from t2 order by col; +col2 col col +3 1 1 +2 2 2 +1 3 3 +select t2.col2 as col from t2 order by t2.col; +col +3 +2 +1 +select t2.col2 as col, t2.col from t2 order by t2.col; +col col +3 1 +2 2 +1 3 +select t2.col2, t2.col, t2.col from t2 order by t2.col; +col2 col col +3 1 1 +2 2 2 +1 3 3 +drop table t1, t2; +create table t1 (a char(25)); +insert into t1 set a = repeat('x', 20); +insert into t1 set a = concat(repeat('x', 19), 'z'); +insert into t1 set a = concat(repeat('x', 19), 'ab'); +insert into t1 set a = concat(repeat('x', 19), 'aa'); +set max_sort_length=20; +select a from t1 order by a; +a +xxxxxxxxxxxxxxxxxxxab +xxxxxxxxxxxxxxxxxxxaa +xxxxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxz +drop table t1; +create table t1 ( +`sid` decimal(8,0) default null, +`wnid` varchar(11) not null default '', +key `wnid14` (`wnid`(4)), +key `wnid` (`wnid`) +) engine=myisam default charset=latin1; +insert into t1 (`sid`, `wnid`) values +('10100','01019000000'),('37986','01019000000'),('37987','01019010000'), +('39560','01019090000'),('37989','01019000000'),('37990','01019011000'), +('37991','01019011000'),('37992','01019019000'),('37993','01019030000'), +('37994','01019090000'),('475','02070000000'),('25253','02071100000'), +('25255','02071100000'),('25256','02071110000'),('25258','02071130000'), +('25259','02071190000'),('25260','02071200000'),('25261','02071210000'), +('25262','02071290000'),('25263','02071300000'),('25264','02071310000'), +('25265','02071310000'),('25266','02071320000'),('25267','02071320000'), +('25269','02071330000'),('25270','02071340000'),('25271','02071350000'), +('25272','02071360000'),('25273','02071370000'),('25281','02071391000'), +('25282','02071391000'),('25283','02071399000'),('25284','02071400000'), +('25285','02071410000'),('25286','02071410000'),('25287','02071420000'), +('25288','02071420000'),('25291','02071430000'),('25290','02071440000'), +('25292','02071450000'),('25293','02071460000'),('25294','02071470000'), +('25295','02071491000'),('25296','02071491000'),('25297','02071499000'); +explain select * from t1 where wnid like '0101%' order by wnid; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range wnid14,wnid wnid 13 NULL 10 Using where +select * from t1 where wnid like '0101%' order by wnid; +sid wnid +10100 01019000000 +37986 01019000000 +37989 01019000000 +37987 01019010000 +37990 01019011000 +37991 01019011000 +37992 01019019000 +37993 01019030000 +39560 01019090000 +37994 01019090000 +drop table t1; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (2), (1), (1), (2), (1); +SELECT a FROM t1 ORDER BY a; +a +1 +1 +1 +2 +2 +(SELECT a FROM t1) ORDER BY a; +a +1 +1 +1 +2 +2 +DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,30), (2,20), (1,10), (2,30), (1,20), (2,10); +(SELECT b,a FROM t1 ORDER BY a,b) ORDER BY b,a; +b a +10 1 +10 2 +20 1 +20 2 +30 1 +30 2 +(SELECT b FROM t1 ORDER BY b DESC) ORDER BY b ASC; +b +10 +10 +20 +20 +30 +30 +(SELECT b,a FROM t1 ORDER BY b,a) ORDER BY a,b; +b a +10 1 +20 1 +30 1 +10 2 +20 2 +30 2 +(SELECT b,a FROM t1 ORDER by b,a LIMIT 3) ORDER by a,b; +b a +10 1 +20 1 +10 2 +DROP TABLE t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +SELECT a + 1 AS num FROM t1 ORDER BY 30 - num; +num +3 +2 +SELECT CONCAT('test', a) AS str FROM t1 ORDER BY UPPER(str); +str +test1 +test2 +SELECT a + 1 AS num FROM t1 GROUP BY 30 - num; +num +3 +2 +SELECT a + 1 AS num FROM t1 HAVING 30 - num; +num +2 +3 +SELECT a + 1 AS num, num + 1 FROM t1; +ERROR 42S22: Unknown column 'num' in 'field list' +SELECT a + 1 AS num, (select num + 2 FROM t1 LIMIT 1) FROM t1; +num (select num + 2 FROM t1 LIMIT 1) +2 4 +3 5 +SELECT a.a + 1 AS num FROM t1 a JOIN t1 b ON num = b.a; +ERROR 42S22: Unknown column 'num' in 'on clause' +DROP TABLE t1; +CREATE TABLE t1 (a int); +SELECT p.a AS val, q.a AS val1 FROM t1 p, t1 q ORDER BY val > 1; +val val1 +SELECT p.a AS val, q.a AS val FROM t1 p, t1 q ORDER BY val; +ERROR 23000: Column 'val' in order clause is ambiguous +SELECT p.a AS val, q.a AS val FROM t1 p, t1 q ORDER BY val > 1; +ERROR 23000: Column 'val' in order clause is ambiguous +DROP TABLE t1; +create table t1 (a int not null, b int not null, c int not null); +insert t1 values (1,1,1),(1,1,2),(1,2,1); +select a, b from t1 group by a, b order by sum(c); +a b +1 2 +1 1 +drop table t1; +CREATE TABLE t1 (a int, b int, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3); +explain SELECT t1.b as a, t2.b as c FROM +t1 LEFT JOIN t1 t2 ON (t1.a = t2.a AND t2.a = 2) +ORDER BY c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using temporary; Using filesort +1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 +SELECT t2.b as c FROM +t1 LEFT JOIN t1 t2 ON (t1.a = t2.a AND t2.a = 2) +ORDER BY c; +c +NULL +NULL +2 +explain SELECT t1.b as a, t2.b as c FROM +t1 JOIN t1 t2 ON (t1.a = t2.a AND t2.a = 2) +ORDER BY c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 +CREATE TABLE t2 LIKE t1; +INSERT INTO t2 SELECT * from t1; +CREATE TABLE t3 LIKE t1; +INSERT INTO t3 SELECT * from t1; +CREATE TABLE t4 LIKE t1; +INSERT INTO t4 SELECT * from t1; +INSERT INTO t1 values (0,0),(4,4); +SELECT t2.b FROM t1 LEFT JOIN (t2, t3 LEFT JOIN t4 ON t3.a=t4.a) +ON (t1.a=t2.a AND t1.b=t3.b) order by t2.b; +b +NULL +NULL +1 +2 +3 +DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/suite/pbxt/r/order_fill_sortbuf.result b/mysql-test/suite/pbxt/r/order_fill_sortbuf.result new file mode 100644 index 00000000000..2226e842901 --- /dev/null +++ b/mysql-test/suite/pbxt/r/order_fill_sortbuf.result @@ -0,0 +1,10 @@ +drop table if exists t1,t2; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL default '0', +`id2` int(11) NOT NULL default '0', +`id3` int(11) NOT NULL default '0'); +create table t2 select id2 from t1 order by id3; +select count(*) from t2; +count(*) +4000 +drop table t1,t2; diff --git a/mysql-test/suite/pbxt/r/overflow.result b/mysql-test/suite/pbxt/r/overflow.result new file mode 100644 index 00000000000..a5fa7154833 --- /dev/null +++ b/mysql-test/suite/pbxt/r/overflow.result @@ -0,0 +1,2 @@ +drop database AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; +Got one of the listed errors diff --git a/mysql-test/suite/pbxt/r/partition_charset.result b/mysql-test/suite/pbxt/r/partition_charset.result new file mode 100644 index 00000000000..665e5d55f8f --- /dev/null +++ b/mysql-test/suite/pbxt/r/partition_charset.result @@ -0,0 +1,18 @@ +drop table if exists t1; +set names utf8; +create table t1 (s1 int) +partition by list (s1) +(partition c values in (1), +partition Ç values in (3)); +insert into t1 values (1),(3); +select * from t1; +s1 +1 +3 +flush tables; +set names latin1; +select * from t1; +s1 +1 +3 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/partition_error.result b/mysql-test/suite/pbxt/r/partition_error.result new file mode 100644 index 00000000000..af708fb01b0 --- /dev/null +++ b/mysql-test/suite/pbxt/r/partition_error.result @@ -0,0 +1,622 @@ +drop table if exists t1; +partition by list (a) +partitions 3 +(partition x1 values in (1,2,9,4) tablespace ts1, +partition x2 values in (3, 11, 5, 7) tablespace ts2, +partition x3 values in (16, 8, 5+19, 70-43) tablespace ts3); +ERROR 42000: Partitioning can not be used stand-alone in query near 'partition by list (a) +partitions 3 +(partition x1 values in (1,2,9,4) tablespace ' at line 1 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2; +ERROR HY000: For LIST partitions each partition must be defined +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (sin(a)) +partitions 3 +(partition x1 values in (1,2,9,4) tablespace ts1, +partition x2 values in (3, 11, 5, 7) tablespace ts2, +partition x3 values in (16, 8, 5+19, 70-43) tablespace ts3); +ERROR HY000: This partition function is not allowed +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a+2) +partitions 3 +(partition x1 tablespace ts1, +partition x2 tablespace ts2, +partition x3 tablespace ts3); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '+2) +partitions 3 +(partition x1 tablespace ts1, +partition x2 tablespace ts2, +part' at line 6 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a) +partitions 3 +(partition tablespace ts1, +partition x2 tablespace ts2, +partition x3 tablespace ts3); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ts1, +partition x2 tablespace ts2, +partition x3 tablespace ts3)' at line 8 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a,d) +partitions 3 +(partition x1 tablespace ts1, +partition x2 tablespace ts2, +partition x3 tablespace ts3); +ERROR HY000: Field in list of fields for partition function not found in table +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a + d) +partitions 3 +(partition x1 tablespace ts1, +partition x2 tablespace ts2, +partition x3 tablespace ts3); +ERROR 42S22: Unknown column 'd' in 'partition function' +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (sin(a)) +partitions 3 +(partition x1 tablespace ts1, +partition x2 tablespace ts2, +partition x3 tablespace ts3); +ERROR HY000: This partition function is not allowed +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a) +partitions 3 +(partition x1, partition x2); +ERROR 42000: Wrong number of partitions defined, mismatch with previous setting near ')' at line 8 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (rand(a)) +partitions 2 +(partition x1, partition x2); +ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ') +partitions 2 +(partition x1, partition x2)' at line 6 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (rand(a)) +partitions 2 +(partition x1 values less than (0), partition x2 values less than (2)); +ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ') +partitions 2 +(partition x1 values less than (0), partition x2 values less than' at line 6 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (rand(a)) +partitions 2 +(partition x1 values in (1), partition x2 values in (2)); +ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ') +partitions 2 +(partition x1 values in (1), partition x2 values in (2))' at line 6 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a) +partitions 2 +(partition x1 values less than (4), +partition x2 values less than (5)); +ERROR HY000: Only RANGE PARTITIONING can use VALUES LESS THAN in partition definition +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a) +partitions 2 +(partition x1 values in (4), +partition x2 values in (5)); +ERROR HY000: Only LIST PARTITIONING can use VALUES IN in partition definition +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a) +partitions 2 +(partition x1 values in (4,6), +partition x2 values in (5,7)); +ERROR HY000: Only LIST PARTITIONING can use VALUES IN in partition definition +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by key (b); +ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by key (a, b); +ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (a+b); +ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by key (b); +ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by key (a, b); +ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (a+b); +ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (rand(a+b)); +ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ')' at line 7 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (sin(a+b)) +(partition x1 (subpartition x11, subpartition x12), +partition x2 (subpartition x21, subpartition x22)); +ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by key (a+b) +(partition x1 values less than (1) (subpartition x11, subpartition x12), +partition x2 values less than (2) (subpartition x21, subpartition x22)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '+b) +(partition x1 values less than (1) (subpartition x11, subpartition x12), +par' at line 7 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by key (a,d) +(partition x1 values less than (1) (subpartition x11, subpartition x12), +partition x2 values less than (2) (subpartition x21, subpartition x22)); +ERROR HY000: Field in list of fields for partition function not found in table +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (3+4); +ERROR HY000: It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+d) +(partition x1 values less than (1) (subpartition x11, subpartition x12), +partition x2 values less than (2) (subpartition x21, subpartition x22)); +ERROR 42S22: Unknown column 'd' in 'partition function' +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a); +ERROR HY000: For RANGE partitions each partition must be defined +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par') +NULL +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a+d) +partitions 2 +(partition x1 values less than (4) tablespace ts1, +partition x2 values less than (8) tablespace ts2); +ERROR 42S22: Unknown column 'd' in 'partition function' +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than (4.0) tablespace ts1, +partition x2 values less than (8) tablespace ts2); +ERROR 42000: VALUES value must be of same type as partition function near ') tablespace ts1, +partition x2 values less than (8) tablespace ts2)' at line 8 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (3+4) +partitions 2 +(partition x1 values less than (4) tablespace ts1, +partition x2 values less than (8) tablespace ts2); +ERROR HY000: Constant/Random expression in (sub)partitioning function is not allowed +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than (4), +partition x2); +ERROR HY000: Syntax error: RANGE PARTITIONING requires definition of VALUES LESS THAN for each partition +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values in (4), +partition x2); +ERROR HY000: Only LIST PARTITIONING can use VALUES IN in partition definition +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values in (4), +partition x2 values less than (5)); +ERROR HY000: Only LIST PARTITIONING can use VALUES IN in partition definition +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values less than 4, +partition x2 values less than (5)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '4, +partition x2 values less than (5))' at line 8 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than maxvalue, +partition x2 values less than (5)); +ERROR 42000: MAXVALUE can only be used in last partition definition near '))' at line 9 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than maxvalue, +partition x2 values less than maxvalue); +ERROR 42000: MAXVALUE can only be used in last partition definition near 'maxvalue)' at line 9 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than (4), +partition x2 values less than (3)); +ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (sin(a)) +partitions 2 +(partition x1 values less than (4), +partition x2 values less than (5)); +ERROR HY000: This partition function is not allowed +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by list (a) +subpartition by hash (a+b) +subpartitions 3 +( partition x1 values in (1,2,4) +( subpartition x11 nodegroup 0, +subpartition x12 nodegroup 1), +partition x2 values in (3,5,6) +( subpartition x21 nodegroup 0, +subpartition x22 nodegroup 1) +); +ERROR 42000: Wrong number of subpartitions defined, mismatch with previous setting near '), +partition x2 values in (3,5,6) +( subpartition x21 nodegroup 0, +subpartition x' at line 11 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by list (a) +subpartition by hash (a+b) +( partition x1 values in (1) +( subpartition x11 nodegroup 0, +subpartition xextra, +subpartition x12 nodegroup 1), +partition x2 values in (2) +( subpartition x21 nodegroup 0, +subpartition x22 nodegroup 1) +); +ERROR 42000: Wrong number of subpartitions defined, mismatch with previous setting near ') +)' at line 14 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by list (a+b) +( partition x1 +( subpartition x11 engine myisam, +subpartition x12 engine myisam), +partition x2 +( subpartition x21 engine myisam, +subpartition x22 engine myisam) +); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'list (a+b) +( partition x1 +( subpartition x11 engine myisam, +subpartition x12 eng' at line 7 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by list (a+b) +( partition x1 +( subpartition x11 engine myisam values in (0), +subpartition x12 engine myisam values in (1)), +partition x2 +( subpartition x21 engine myisam values in (0), +subpartition x22 engine myisam values in (1)) +); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'list (a+b) +( partition x1 +( subpartition x11 engine myisam values in (0), +subpar' at line 7 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a); +ERROR HY000: For LIST partitions each partition must be defined +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (3+4) +partitions 2 +(partition x1 values in (4) tablespace ts1, +partition x2 values in (8) tablespace ts2); +ERROR HY000: Constant/Random expression in (sub)partitioning function is not allowed +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a+d) +partitions 2 +(partition x1 values in (4) tablespace ts1, +partition x2 values in (8) tablespace ts2); +ERROR 42S22: Unknown column 'd' in 'partition function' +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4), +partition x2); +ERROR HY000: Syntax error: LIST PARTITIONING requires definition of VALUES IN for each partition +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4), +partition x2 values less than (5)); +ERROR HY000: Only RANGE PARTITIONING can use VALUES LESS THAN in partition definition +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4,6), +partition x2); +ERROR HY000: Syntax error: LIST PARTITIONING requires definition of VALUES IN for each partition +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4, 12+9), +partition x2 values in (3, 21)); +ERROR HY000: Multiple definition of same constant in list partitioning +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4.0, 12+8), +partition x2 values in (3, 21)); +ERROR 42000: VALUES value must be of same type as partition function near ' 12+8), +partition x2 values in (3, 21))' at line 8 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in 4, +partition x2 values in (5)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '4, +partition x2 values in (5))' at line 8 +CREATE TABLE t1 (a int) +PARTITION BY RANGE (a) +(PARTITION p0 VALUES LESS THAN (x1)); +ERROR 42S22: Unknown column 'x1' in 'partition function' +CREATE TABLE t1(a int) +PARTITION BY RANGE (a) (PARTITION p1 VALUES LESS THAN(5)); +insert into t1 values (10); +ERROR HY000: Table has no partition for value 10 +drop table t1; +create table t1 (a bigint unsigned) +partition by range (a) +(partition p0 values less than (-1)); +ERROR HY000: Partition constant is out of partition function domain +create table t1 (v varchar(12)) +partition by range (ascii(v)) +(partition p0 values less than (10)); +ERROR HY000: This partition function is not allowed +create table t1 (a int) +partition by hash (rand(a)); +ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ')' at line 2 +create table t1 (a int) +partition by hash(CURTIME() + a); +ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ')' at line 2 +create table t1 (a int) +partition by hash (NOW()+a); +ERROR 42000: Constant/Random expression in (sub)partitioning function is not allowed near ')' at line 2 +create table t1 (a int) +partition by hash (extract(hour from convert_tz(a, '+00:00', '+00:00'))); +ERROR HY000: This partition function is not allowed +create table t1 (a int) +partition by range (a + (select count(*) from t1)) +(partition p1 values less than (1)); +ERROR HY000: This partition function is not allowed +create table t1 (a char(10)) +partition by hash (extractvalue(a,'a')); +ERROR HY000: This partition function is not allowed diff --git a/mysql-test/suite/pbxt/r/partition_grant.result b/mysql-test/suite/pbxt/r/partition_grant.result new file mode 100644 index 00000000000..e88427e5396 --- /dev/null +++ b/mysql-test/suite/pbxt/r/partition_grant.result @@ -0,0 +1,25 @@ +drop schema if exists mysqltest_1; +create schema mysqltest_1; +use mysqltest_1; +create table t1 (a int) partition by list (a) (partition p1 values in (1), partition p2 values in (2), partition p3 values in (3)); +insert into t1 values (1),(2); +grant usage on *.* to mysqltest_1@localhost; +revoke all privileges on *.* from mysqltest_1@localhost; +grant select,alter on mysqltest_1.* to mysqltest_1@localhost; +show grants for current_user; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, ALTER ON `mysqltest_1`.* TO 'mysqltest_1'@'localhost' +alter table t1 add b int; +alter table t1 drop partition p2; +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1' +grant drop on mysqltest_1.* to mysqltest_1@localhost; +alter table t1 drop partition p2; +revoke alter on mysqltest_1.* from mysqltest_1@localhost; +alter table t1 drop partition p3; +ERROR 42000: ALTER command denied to user 'mysqltest_1'@'localhost' for table 't1' +revoke select,alter,drop on mysqltest_1.* from mysqltest_1@localhost; +drop user mysqltest_1@localhost; +drop table t1; +drop schema mysqltest_1; +End of 5.1 tests diff --git a/mysql-test/suite/pbxt/r/partition_hash.result b/mysql-test/suite/pbxt/r/partition_hash.result new file mode 100644 index 00000000000..c32c27bf9c6 --- /dev/null +++ b/mysql-test/suite/pbxt/r/partition_hash.result @@ -0,0 +1,185 @@ +drop table if exists t1; +create table t1 (a int unsigned) +partition by hash(a div 2) +partitions 4; +insert into t1 values (null),(0),(1),(2),(3),(4),(5),(6),(7); +select * from t1 where a < 0; +a +select * from t1 where a is null or (a >= 5 and a <= 7); +a +NULL +5 +6 +7 +select * from t1 where a is null; +a +NULL +select * from t1 where a is not null; +a +0 +1 +2 +3 +4 +5 +6 +7 +select * from t1 where a >= 1 and a < 3; +a +1 +2 +select * from t1 where a >= 3 and a <= 5; +a +3 +4 +5 +select * from t1 where a > 2 and a < 4; +a +3 +select * from t1 where a > 3 and a <= 6; +a +4 +5 +6 +select * from t1 where a > 5; +a +6 +7 +select * from t1 where a >= 1 and a <= 5; +a +1 +2 +3 +4 +5 +explain partitions select * from t1 where a < 0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1,p2,p3 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a is null or (a >= 5 and a <= 7); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p2,p3 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a is null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a is not null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1,p2,p3 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a >= 1 and a < 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a >= 3 and a <= 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1,p2 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a > 2 and a < 4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a > 3 and a <= 6; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2,p3 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a > 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1,p2,p3 ALL NULL NULL NULL NULL 9 Using where +explain partitions select * from t1 where a >= 1 and a <= 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1,p2,p3 ALL NULL NULL NULL NULL 9 Using where +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a + 2) +partitions 3 +(partition x1 tablespace ts1, +partition x2 tablespace ts2, +partition x3 tablespace ts3); +insert into t1 values (1,1,1); +insert into t1 values (2,1,1); +insert into t1 values (3,1,1); +insert into t1 values (4,1,1); +insert into t1 values (5,1,1); +select * from t1; +a b c +1 1 1 +4 1 1 +2 1 1 +5 1 1 +3 1 1 +update t1 set c=3 where b=1; +select * from t1; +a b c +1 1 3 +4 1 3 +2 1 3 +5 1 3 +3 1 3 +select b from t1 where a=3; +b +1 +select b,c from t1 where a=1 AND b=1; +b c +1 3 +delete from t1 where a=1; +delete from t1 where c=3; +select * from t1; +a b c +ALTER TABLE t1 +partition by hash (a + 3) +partitions 3 +(partition x1 tablespace ts1, +partition x2 tablespace ts2, +partition x3 tablespace ts3); +select * from t1; +a b c +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a) +(partition x1); +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a) +(partition x1); +drop table t1; +CREATE TABLE t1 (f1 INTEGER, f2 char(20)) ENGINE = 'MYISAM' PARTITION BY HASH(f1) PARTITIONS 2; +INSERT INTO t1 SET f1 = 0 - 1, f2 = '#######'; +select * from t1; +f1 f2 +-1 ####### +drop table t1; +CREATE TABLE t1 (s1 int) ENGINE=BLACKHOLE PARTITION BY HASH (s1); +INSERT INTO t1 VALUES (0); +DROP TABLE t1; +create table t1 (c1 int DEFAULT NULL, +c2 varchar (30) DEFAULT NULL, +c3 date DEFAULT NULL) +engine = myisam +partition by hash (to_days(c3)) +partitions 12; +insert into t1 values +(136,'abc','2002-01-05'),(142,'abc','2002-02-14'),(162,'abc','2002-06-28'), +(182,'abc','2002-11-09'),(158,'abc','2002-06-01'),(184,'abc','2002-11-22'); +select * from t1; +c1 c2 c3 +136 abc 2002-01-05 +158 abc 2002-06-01 +142 abc 2002-02-14 +162 abc 2002-06-28 +182 abc 2002-11-09 +184 abc 2002-11-22 +select * from t1 where c3 between '2002-01-01' and '2002-12-31'; +c1 c2 c3 +136 abc 2002-01-05 +158 abc 2002-06-01 +142 abc 2002-02-14 +162 abc 2002-06-28 +182 abc 2002-11-09 +184 abc 2002-11-22 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/partition_list.result b/mysql-test/suite/pbxt/r/partition_list.result new file mode 100644 index 00000000000..58ec635cf80 --- /dev/null +++ b/mysql-test/suite/pbxt/r/partition_list.result @@ -0,0 +1,297 @@ +drop table if exists t1; +create table t1 (a int unsigned) +partition by list (a) +(partition p0 values in (0), +partition p1 values in (1), +partition pnull values in (null), +partition p2 values in (2)); +insert into t1 values (null),(0),(1),(2); +select * from t1 where a < 2; +a +0 +1 +select * from t1 where a <= 0; +a +0 +select * from t1 where a < 1; +a +0 +select * from t1 where a > 0; +a +1 +2 +select * from t1 where a > 1; +a +2 +select * from t1 where a >= 0; +a +0 +1 +2 +select * from t1 where a >= 1; +a +1 +2 +select * from t1 where a is null; +a +NULL +select * from t1 where a is not null; +a +0 +1 +2 +select * from t1 where a is null or a > 0; +a +1 +NULL +2 +drop table t1; +create table t1 (a int unsigned, b int) +partition by list (a) +subpartition by hash (b) +subpartitions 2 +(partition p0 values in (0), +partition p1 values in (1), +partition pnull values in (null, 2), +partition p3 values in (3)); +insert into t1 values (0,0),(0,1),(1,0),(1,1),(null,0),(null,1); +insert into t1 values (2,0),(2,1),(3,0),(3,1); +explain partitions select * from t1 where a is null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pnull_pnullsp0,pnull_pnullsp1 ALL NULL NULL NULL NULL 4 Using where +select * from t1 where a is null; +a b +NULL 0 +NULL 1 +explain partitions select * from t1 where a = 2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pnull_pnullsp0,pnull_pnullsp1 ALL NULL NULL NULL NULL 4 Using where +select * from t1 where a = 2; +a b +2 0 +2 1 +select * from t1 where a <= 0; +a b +0 0 +0 1 +select * from t1 where a < 3; +a b +0 0 +0 1 +1 0 +1 1 +2 0 +2 1 +select * from t1 where a >= 1 or a is null; +a b +1 0 +1 1 +NULL 0 +2 0 +NULL 1 +2 1 +3 0 +3 1 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null) +partition by list(a) +partitions 2 +(partition x123 values in (1,5,6), +partition x234 values in (4,7,8)); +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (2,1,1); +ERROR HY000: Table has no partition for value 2 +INSERT into t1 VALUES (3,1,1); +ERROR HY000: Table has no partition for value 3 +INSERT into t1 VALUES (4,1,1); +INSERT into t1 VALUES (5,1,1); +INSERT into t1 VALUES (6,1,1); +INSERT into t1 VALUES (7,1,1); +INSERT into t1 VALUES (8,1,1); +INSERT into t1 VALUES (9,1,1); +ERROR HY000: Table has no partition for value 9 +INSERT into t1 VALUES (1,2,1); +INSERT into t1 VALUES (1,3,1); +INSERT into t1 VALUES (1,4,1); +INSERT into t1 VALUES (7,2,1); +INSERT into t1 VALUES (7,3,1); +INSERT into t1 VALUES (7,4,1); +SELECT * from t1; +a b c +1 1 1 +5 1 1 +6 1 1 +1 2 1 +1 3 1 +1 4 1 +4 1 1 +7 1 1 +8 1 1 +7 2 1 +7 3 1 +7 4 1 +SELECT * from t1 WHERE a=1; +a b c +1 1 1 +1 2 1 +1 3 1 +1 4 1 +SELECT * from t1 WHERE a=7; +a b c +7 1 1 +7 2 1 +7 3 1 +7 4 1 +SELECT * from t1 WHERE b=2; +a b c +1 2 1 +7 2 1 +UPDATE t1 SET a=8 WHERE a=7 AND b=3; +SELECT * from t1 order by a, b; +a b c +1 1 1 +1 2 1 +1 3 1 +1 4 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +7 2 1 +7 4 1 +8 1 1 +8 3 1 +UPDATE t1 SET a=8 WHERE a=5 AND b=1; +SELECT * from t1 order by a, b; +a b c +1 1 1 +1 2 1 +1 3 1 +1 4 1 +4 1 1 +6 1 1 +7 1 1 +7 2 1 +7 4 1 +8 1 1 +8 1 1 +8 3 1 +DELETE from t1 WHERE a=8; +SELECT * from t1 order by a, b; +a b c +1 1 1 +1 2 1 +1 3 1 +1 4 1 +4 1 1 +6 1 1 +7 1 1 +7 2 1 +7 4 1 +DELETE from t1 WHERE a=2; +SELECT * from t1 order by a, b; +a b c +1 1 1 +1 2 1 +1 3 1 +1 4 1 +4 1 1 +6 1 1 +7 1 1 +7 2 1 +7 4 1 +DELETE from t1 WHERE a=5 OR a=6; +SELECT * from t1 order by a, b; +a b c +1 1 1 +1 2 1 +1 3 1 +1 4 1 +4 1 1 +7 1 1 +7 2 1 +7 4 1 +ALTER TABLE t1 +partition by list(a) +partitions 2 +(partition x123 values in (1,5,6), +partition x234 values in (4,7,8)); +SELECT * from t1; +a b c +1 1 1 +1 2 1 +1 3 1 +1 4 1 +4 1 1 +7 1 1 +7 2 1 +7 4 1 +INSERT into t1 VALUES (6,2,1); +INSERT into t1 VALUES (2,2,1); +ERROR HY000: Table has no partition for value 2 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by list (a) +subpartition by hash (a+b) +( partition x1 values in (1,2,3) +( subpartition x11 nodegroup 0, +subpartition x12 nodegroup 1), +partition x2 values in (4,5,6) +( subpartition x21 nodegroup 0, +subpartition x22 nodegroup 1) +); +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +INSERT into t1 VALUES (7,1,1); +ERROR HY000: Table has no partition for value 7 +UPDATE t1 SET a=5 WHERE a=1; +SELECT * from t1; +a b c +5 1 1 +4 1 1 +UPDATE t1 SET a=6 WHERE a=4; +SELECT * from t1; +a b c +5 1 1 +6 1 1 +DELETE from t1 WHERE a=6; +SELECT * from t1; +a b c +5 1 1 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +(partition x1 values in (1,2,9,4) tablespace ts1); +drop table t1; +CREATE TABLE t1 (s1 int) PARTITION BY LIST (s1) +(PARTITION p1 VALUES IN (1), +PARTITION p2 VALUES IN (2), +PARTITION p3 VALUES IN (3), +PARTITION p4 VALUES IN (4), +PARTITION p5 VALUES IN (5)); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +SELECT COUNT(*) FROM t1 WHERE s1 < 3; +COUNT(*) +2 +DROP TABLE t1; +create table t1 (a int auto_increment primary key) +auto_increment=100 +partition by list (a) +(partition p0 values in (1, 100)); +create index inx on t1 (a); +insert into t1 values (null); +select * from t1; +a +100 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/partition_order.result b/mysql-test/suite/pbxt/r/partition_order.result new file mode 100644 index 00000000000..78ff7cd3121 --- /dev/null +++ b/mysql-test/suite/pbxt/r/partition_order.result @@ -0,0 +1,785 @@ +drop table if exists t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 order by b; +a b +1 1 +35 2 +30 4 +2 5 +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b tinyint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b tinyint unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b smallint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b smallint unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b mediumint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b mediumint unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b bigint unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b bigint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b bigint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b float not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b double not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b double unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b float unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b double precision not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b double precision unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b decimal not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b char(10) not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b > 0 order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b varchar(10) not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b > '0' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b varchar(10) not null, +primary key(a), +index (b(5))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b > '0' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b varchar(10) binary not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b > '0' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b tinytext not null, +primary key(a), +index (b(10))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b > '0' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b text not null, +primary key(a), +index (b(10))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b > '0' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b mediumtext not null, +primary key(a), +index (b(10))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b > '0' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b longtext not null, +primary key(a), +index (b(10))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b > '0' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b enum('1','2', '4', '5') not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b >= '1' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b set('1','2', '4', '5') not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); +select * from t1 force index (b) where b >= '1' order by b; +a b +1 1 +35 2 +30 4 +2 5 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b date not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '2001-01-01'); +INSERT into t1 values (2, '2005-01-01'); +INSERT into t1 values (30, '2004-01-01'); +INSERT into t1 values (35, '2002-01-01'); +select * from t1 force index (b) where b > '2000-01-01' order by b; +a b +1 2001-01-01 +35 2002-01-01 +30 2004-01-01 +2 2005-01-01 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b datetime not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '2001-01-01 00:00:00'); +INSERT into t1 values (2, '2005-01-01 00:00:00'); +INSERT into t1 values (30, '2004-01-01 00:00:00'); +INSERT into t1 values (35, '2002-01-01 00:00:00'); +select * from t1 force index (b) where b > '2000-01-01 00:00:00' order by b; +a b +1 2001-01-01 00:00:00 +35 2002-01-01 00:00:00 +30 2004-01-01 00:00:00 +2 2005-01-01 00:00:00 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b timestamp not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '2001-01-01 00:00:00'); +INSERT into t1 values (2, '2005-01-01 00:00:00'); +INSERT into t1 values (30, '2004-01-01 00:00:00'); +INSERT into t1 values (35, '2002-01-01 00:00:00'); +select * from t1 force index (b) where b > '2000-01-01 00:00:00' order by b; +a b +1 2001-01-01 00:00:00 +35 2002-01-01 00:00:00 +30 2004-01-01 00:00:00 +2 2005-01-01 00:00:00 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b time not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, '01:00:00'); +INSERT into t1 values (2, '05:00:00'); +INSERT into t1 values (30, '04:00:00'); +INSERT into t1 values (35, '02:00:00'); +select * from t1 force index (b) where b > '00:00:00' order by b; +a b +1 01:00:00 +35 02:00:00 +30 04:00:00 +2 05:00:00 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b year not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 2001); +INSERT into t1 values (2, 2005); +INSERT into t1 values (30, 2004); +INSERT into t1 values (35, 2002); +select * from t1 force index (b) where b > 2000 order by b; +a b +1 2001 +35 2002 +30 2004 +2 2005 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b bit(5) not null, +c int, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, b'00001', NULL); +INSERT into t1 values (2, b'00101', 2); +INSERT into t1 values (30, b'00100', 2); +INSERT into t1 values (35, b'00010', NULL); +select a from t1 force index (b) where b > b'00000' order by b; +a +1 +35 +30 +2 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b bit(15) not null, +c int, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, b'000000000000001', NULL); +INSERT into t1 values (2, b'001010000000101', 2); +INSERT into t1 values (30, b'001000000000100', 2); +INSERT into t1 values (35, b'000100000000010', NULL); +select a from t1 force index (b) where b > b'000000000000000' order by b; +a +1 +35 +30 +2 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), +partition x2 values less than (100)); +INSERT into t1 values (1, 1); +INSERT into t1 values (5, NULL); +INSERT into t1 values (2, 4); +INSERT into t1 values (3, 3); +INSERT into t1 values (4, 5); +INSERT into t1 values (7, 1); +INSERT into t1 values (6, 6); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +INSERT into t1 values (40, NULL); +select * from t1 force index (b) where b < 10 OR b IS NULL order by b; +a b +5 NULL +40 NULL +1 1 +7 1 +35 2 +3 3 +2 4 +30 4 +4 5 +6 6 +select * from t1 force index (b) where b < 10 ORDER BY b; +a b +1 1 +7 1 +35 2 +3 3 +2 4 +30 4 +4 5 +6 6 +select * from t1 force index (b) where b < 10 ORDER BY b DESC; +a b +6 6 +4 5 +2 4 +30 4 +3 3 +35 2 +7 1 +1 1 +drop table t1; +create table t1 (a int not null, b int, c varchar(20), key (a,b,c)) +partition by range (b) +(partition p0 values less than (5), +partition p1 values less than (10)); +INSERT into t1 values (1,1,'1'),(2,2,'2'),(1,3,'3'),(2,4,'4'),(1,5,'5'); +INSERT into t1 values (2,6,'6'),(1,7,'7'),(2,8,'8'),(1,9,'9'); +INSERT into t1 values (1, NULL, NULL), (2, NULL, '10'); +select * from t1 where a = 1 order by a desc, b desc; +a b c +1 9 9 +1 7 7 +1 5 5 +1 3 3 +1 1 1 +1 NULL NULL +select * from t1 where a = 1 order by b desc; +a b c +1 9 9 +1 7 7 +1 5 5 +1 3 3 +1 1 1 +1 NULL NULL +drop table t1; diff --git a/mysql-test/suite/pbxt/r/partition_pruning.result b/mysql-test/suite/pbxt/r/partition_pruning.result new file mode 100644 index 00000000000..f003f62c163 --- /dev/null +++ b/mysql-test/suite/pbxt/r/partition_pruning.result @@ -0,0 +1,916 @@ +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +create table t1 ( a int not null) partition by hash(a) partitions 2; +insert into t1 values (1),(2),(3); +explain select * from t1 where a=5 and a=6; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +drop table t1; +create table t1 ( +a int(11) not null +) partition by hash (a) partitions 2; +insert into t1 values (1),(2),(3); +explain partitions select * from t1 where a=1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t1 where a=2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t1 where a=1 or a=2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 3 Using where +create table t2 ( +a int not null, +b int not null +) partition by key(a,b) partitions 2; +insert into t2 values (1,1),(2,2),(3,3); +explain partitions select * from t2 where a=1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t2 where b=1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t2 where a=1 and b=1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 3 Using where +create table t3 ( +a int +) +partition by range (a*1) ( +partition p0 values less than (10), +partition p1 values less than (20) +); +insert into t3 values (5),(15); +explain partitions select * from t3 where a=11; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t3 p1 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t3 where a=10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t3 p1 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t3 where a=20; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t3 where a=30; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 1 Using where +create table t4 (a int not null, b int not null) partition by LIST (a+b) ( +partition p0 values in (12), +partition p1 values in (14) +); +insert into t4 values (10,2), (10,4); +explain partitions select * from t4 where (a=10 and b=1) or (a=10 and b=2); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t4 p0 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t4 +where (a=10 and b=1) or (a=10 and b=2) or (a=10 and b = 3); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t4 p0 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t4 where (a=10 and b=2) or (a=10 and b=3) +or (a=10 and b = 4); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t4 p0,p1 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t4 where (a=10 and b=1) or a=11; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t4 p0,p1 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t4 where (a=10 and b=2) or a=11; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t4 p0,p1 ALL NULL NULL NULL NULL 2 Using where +drop table t1, t2, t3, t4; +create table t5 (a int not null, b int not null, +c int not null, d int not null) +partition by LIST(a+b) subpartition by HASH (c+d) subpartitions 2 +( +partition p0 values in (12), +partition p1 values in (14) +); +insert into t5 values (10,2,0,0), (10,4,0,0), (10,2,0,1), (10,4,0,1); +explain partitions select * from t5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t5 p0_p0sp0,p0_p0sp1,p1_p1sp0,p1_p1sp1 ALL NULL NULL NULL NULL 4 +explain partitions select * from t5 +where (a=10 and b=1) or (a=10 and b=2) or (a=10 and b = 3); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t5 p0_p0sp0,p0_p0sp1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t5 where (a=10 and b=2) or (a=10 and b=3) +or (a=10 and b = 4); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t5 p0_p0sp0,p0_p0sp1,p1_p1sp0,p1_p1sp1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t5 where (c=1 and d=1); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t5 p0_p0sp0,p1_p1sp0 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t5 where (c=2 and d=1); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t5 p0_p0sp1,p1_p1sp1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t5 where (a=10 and b=2 and c=1 and d=1) or +(c=2 and d=1); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t5 p0_p0sp0,p0_p0sp1,p1_p1sp1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t5 where (a=10 and b=2 and c=1 and d=1) or +(b=2 and c=2 and d=1); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t5 p0_p0sp0,p0_p0sp1,p1_p1sp1 ALL NULL NULL NULL NULL 4 Using where +create table t6 (a int not null) partition by LIST(a) ( +partition p1 values in (1), +partition p3 values in (3), +partition p5 values in (5), +partition p7 values in (7), +partition p9 values in (9) +); +insert into t6 values (1),(3),(5); +explain partitions select * from t6 where a < 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 ALL NULL NULL NULL NULL 0 Using where +explain partitions select * from t6 where a <= 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p1 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t6 where a > 9; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t6 where a >= 9; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p9 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t6 where a > 0 and a < 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p1,p3 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t6 where a > 5 and a < 12; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p7,p9 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t6 where a > 3 and a < 8 ; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p5,p7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t6 where a >= 0 and a <= 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p1,p3,p5 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t6 where a >= 5 and a <= 12; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p5,p7,p9 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t6 where a >= 3 and a <= 8; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p3,p5,p7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t6 where a > 3 and a < 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where +drop table t6; +create table t6 (a int unsigned not null) partition by LIST(a) ( +partition p1 values in (1), +partition p3 values in (3), +partition p5 values in (5), +partition p7 values in (7), +partition p9 values in (9) +); +insert into t6 values (1),(3),(5); +explain partitions select * from t6 where a < 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 ALL NULL NULL NULL NULL 0 Using where +explain partitions select * from t6 where a <= 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p1 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t6 where a > 9; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t6 where a >= 9; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p9 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t6 where a > 0 and a < 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p1,p3 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t6 where a > 5 and a < 12; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p7,p9 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t6 where a > 3 and a < 8 ; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p5,p7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t6 where a >= 0 and a <= 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p1,p3,p5 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t6 where a >= 5 and a <= 12; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p5,p7,p9 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t6 where a >= 3 and a <= 8; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 p3,p5,p7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t6 where a > 3 and a < 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where +create table t7 (a int not null) partition by RANGE(a) ( +partition p10 values less than (10), +partition p30 values less than (30), +partition p50 values less than (50), +partition p70 values less than (70), +partition p90 values less than (90) +); +insert into t7 values (10),(30),(50); +explain partitions select * from t7 where a < 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p10 ALL NULL NULL NULL NULL 0 Using where +explain partitions select * from t7 where a < 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p10 ALL NULL NULL NULL NULL 0 Using where +explain partitions select * from t7 where a <= 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p10,p30 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t7 where a = 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p30 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t7 where a < 90; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p10,p30,p50,p70,p90 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t7 where a = 90; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t7 where a > 90; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t7 where a >= 90; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t7 where a > 11 and a < 29; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p30 ALL NULL NULL NULL NULL 3 Using where +drop table t7; +create table t7 (a int unsigned not null) partition by RANGE(a) ( +partition p10 values less than (10), +partition p30 values less than (30), +partition p50 values less than (50), +partition p70 values less than (70), +partition p90 values less than (90) +); +insert into t7 values (10),(30),(50); +explain partitions select * from t7 where a < 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p10 ALL NULL NULL NULL NULL 0 Using where +explain partitions select * from t7 where a < 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p10 ALL NULL NULL NULL NULL 0 Using where +explain partitions select * from t7 where a <= 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p10,p30 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t7 where a = 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p30 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t7 where a < 90; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p10,p30,p50,p70,p90 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t7 where a = 90; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t7 where a > 90; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t7 where a >= 90; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t7 where a > 11 and a < 29; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t7 p30 ALL NULL NULL NULL NULL 3 Using where +create table t8 (a date not null) partition by RANGE(YEAR(a)) ( +partition p0 values less than (1980), +partition p1 values less than (1990), +partition p2 values less than (2000) +); +insert into t8 values ('1985-05-05'),('1995-05-05'); +explain partitions select * from t8 where a < '1980-02-02'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t8 p0,p1 ALL NULL NULL NULL NULL 1 Using where +create table t9 (a date not null) partition by RANGE(TO_DAYS(a)) ( +partition p0 values less than (732299), -- 2004-12-19 +partition p1 values less than (732468), -- 2005-06-06 +partition p2 values less than (732664) -- 2005-12-19 +); +insert into t9 values ('2005-05-05'), ('2005-04-04'); +explain partitions select * from t9 where a < '2004-12-19'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t9 p0 ALL NULL NULL NULL NULL 0 Using where +explain partitions select * from t9 where a <= '2004-12-19'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t9 p0,p1 ALL NULL NULL NULL NULL 2 Using where +drop table t5,t6,t7,t8,t9; +create table t1 ( +a1 int not null +) +partition by range (a1) ( +partition p0 values less than (3), +partition p1 values less than (6), +partition p2 values less than (9) +); +insert into t1 values (1),(2),(3); +explain partitions select * from t1 where a1 > 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1,p2 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t1 where a1 >= 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1,p2 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t1 where a1 < 3 and a1 > 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 Using where +drop table t1; +create table t3 (a int, b int) +partition by list(a) subpartition by hash(b) subpartitions 4 ( +partition p0 values in (1), +partition p1 values in (2), +partition p2 values in (3), +partition p3 values in (4) +); +insert into t3 values (1,1),(2,2),(3,3); +explain partitions select * from t3 where a=2 or b=1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t3 p0_p0sp1,p1_p1sp0,p1_p1sp1,p1_p1sp2,p1_p1sp3,p2_p2sp1,p3_p3sp1 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t3 where a=4 or b=2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t3 p0_p0sp2,p1_p1sp2,p2_p2sp2,p3_p3sp0,p3_p3sp1,p3_p3sp2,p3_p3sp3 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t3 where (a=2 or b=1) and (a=4 or b=2) ; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t3 p1_p1sp2,p3_p3sp1 ALL NULL NULL NULL NULL 2 Using where +drop table t3; +create table t1 (a int) partition by hash(a) partitions 2; +insert into t1 values (1),(2); +explain partitions select * from t1 where a is null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t1 where a is not null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 2 Using where +drop table t1; +create table t1 (a int not null, b int not null, key(a), key(b)) +partition by hash(a) partitions 4; +insert into t1 values (1,1),(2,2),(3,3),(4,4); +explain partitions +select * from t1 X, t1 Y +where X.b = Y.b and (X.a=1 or X.a=2) and (Y.a=2 or Y.a=3); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE X p1,p2 ALL a,b NULL NULL NULL 2 Using where +1 SIMPLE Y p2,p3 ref a,b b 4 test.X.b 2 Using where +explain partitions +select * from t1 X, t1 Y where X.a = Y.a and (X.a=1 or X.a=2); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE X p1,p2 ALL a NULL NULL NULL 4 Using where +1 SIMPLE Y p1,p2 ref a a 4 test.X.a 2 +drop table t1; +create table t1 (a int) partition by hash(a) partitions 20; +insert into t1 values (1),(2),(3); +explain partitions select * from t1 where a > 1 and a < 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t1 where a >= 1 and a < 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1,p2 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t1 where a > 1 and a <= 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2,p3 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t1 where a >= 1 and a <= 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1,p2,p3 ALL NULL NULL NULL NULL 3 Using where +drop table t1; +create table t1 (a int, b int) +partition by list(a) subpartition by hash(b) subpartitions 20 +( +partition p0 values in (0), +partition p1 values in (1), +partition p2 values in (2), +partition p3 values in (3) +); +insert into t1 values (1,1),(2,2),(3,3); +explain partitions select * from t1 where b > 1 and b < 3; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0_p0sp2,p1_p1sp2,p2_p2sp2,p3_p3sp2 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t1 where b > 1 and b < 3 and (a =1 or a =2); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1_p1sp2,p2_p2sp2 ALL NULL NULL NULL NULL 1 Using where +drop table t1; +create table t1 (a int) partition by list(a) ( +partition p0 values in (1,2), +partition p1 values in (3,4) +); +insert into t1 values (1),(1),(2),(2),(3),(4),(3),(4); +flush status; +update t1 set a=100 where a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +update t1 set a=100 where a+1=5+1; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +delete from t1 where a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +delete from t1 where a+1=5+1; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +create table t2 like t1; +insert into t2 select * from t2; +flush status; +update t1,t2 set t1.a=1000, t2.a=1000 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +delete t1,t2 from t1, t2 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +drop table t1,t2; +CREATE TABLE `t1` ( +`a` int(11) default NULL +); +INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +CREATE TABLE `t2` ( +`a` int(11) default NULL, +KEY `a` (`a`) +) ; +insert into t2 select A.a + 10*(B.a + 10* C.a) from t1 A, t1 B, t1 C ; +insert into t1 select a from t2; +drop table t2; +CREATE TABLE `t2` ( +`a` int(11) default NULL, +`b` int(11) default NULL +) +PARTITION BY RANGE (a) ( +PARTITION p0 VALUES LESS THAN (200), +PARTITION p1 VALUES LESS THAN (400), +PARTITION p2 VALUES LESS THAN (600), +PARTITION p3 VALUES LESS THAN (800), +PARTITION p4 VALUES LESS THAN (1001)); +insert into t2 select a,1 from t1 where a < 200; +insert into t2 select a,2 from t1 where a >= 200 and a < 400; +insert into t2 select a,3 from t1 where a >= 400 and a < 600; +insert into t2 select a,4 from t1 where a >= 600 and a < 800; +insert into t2 select a,5 from t1 where a >= 800 and a < 1001; +explain partitions select * from t2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 ALL NULL NULL NULL NULL 1010 +explain partitions select * from t2 where a < 801 and a > 200; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p1,p2,p3,p4 ALL NULL NULL NULL NULL 1010 Using where +explain partitions select * from t2 where a < 801 and a > 800; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p4 ALL NULL NULL NULL NULL 1010 Using where +explain partitions select * from t2 where a > 600; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p3,p4 ALL NULL NULL NULL NULL 1010 Using where +explain partitions select * from t2 where a > 600 and b = 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p3,p4 ALL NULL NULL NULL NULL 1010 Using where +explain partitions select * from t2 where a > 600 and b = 4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p3,p4 ALL NULL NULL NULL NULL 1010 Using where +explain partitions select * from t2 where a > 600 and b = 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p3,p4 ALL NULL NULL NULL NULL 1010 Using where +explain partitions select * from t2 where b = 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 ALL NULL NULL NULL NULL 1010 Using where +flush status; +update t2 set b = 100 where b = 6; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +update t2 set a = 1002 where a = 1001; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +update t2 set b = 6 where a = 600; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +update t2 set b = 6 where a > 600 and a < 800; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +flush status; +delete from t2 where a > 600; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +drop table t2; +CREATE TABLE `t2` ( +`a` int(11) default NULL, +`b` int(11) default NULL, +index (b) +) +PARTITION BY RANGE (a) ( +PARTITION p0 VALUES LESS THAN (200), +PARTITION p1 VALUES LESS THAN (400), +PARTITION p2 VALUES LESS THAN (600), +PARTITION p3 VALUES LESS THAN (800), +PARTITION p4 VALUES LESS THAN (1001)); +insert into t2 select a,1 from t1 where a < 100; +insert into t2 select a,2 from t1 where a >= 200 and a < 300; +insert into t2 select a,3 from t1 where a >= 300 and a < 400; +insert into t2 select a,4 from t1 where a >= 400 and a < 500; +insert into t2 select a,5 from t1 where a >= 500 and a < 600; +insert into t2 select a,6 from t1 where a >= 600 and a < 700; +insert into t2 select a,7 from t1 where a >= 700 and a < 800; +insert into t2 select a,8 from t1 where a >= 800 and a < 900; +insert into t2 select a,9 from t1 where a >= 900 and a < 1001; +explain partitions select * from t2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 ALL NULL NULL NULL NULL 910 +explain partitions select * from t2 where a = 101; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 910 Using where +explain partitions select * from t2 where a = 550; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p2 ALL NULL NULL NULL NULL 910 Using where +explain partitions select * from t2 where a = 833; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p4 ALL NULL NULL NULL NULL 910 Using where +explain partitions select * from t2 where (a = 100 OR a = 900); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p4 ALL NULL NULL NULL NULL 910 Using where +explain partitions select * from t2 where (a > 100 AND a < 600); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3 ALL NULL NULL NULL NULL 910 Using where +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +explain partitions select * from t2 where b = 4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 ref b b 5 const 5 Using where +explain extended select * from t2 where b = 6; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ref b b 5 const 5 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` = 6) +explain partitions select * from t2 where b = 6; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 ref b b 5 const 5 Using where +explain extended select * from t2 where b in (1,3,5); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range b b 5 NULL 15 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` in (1,3,5)) +explain partitions select * from t2 where b in (1,3,5); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 range b b 5 NULL 15 Using where +explain extended select * from t2 where b in (2,4,6); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range b b 5 NULL 15 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` in (2,4,6)) +explain partitions select * from t2 where b in (2,4,6); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 range b b 5 NULL 15 Using where +explain extended select * from t2 where b in (7,8,9); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range b b 5 NULL 15 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` in (7,8,9)) +explain partitions select * from t2 where b in (7,8,9); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 range b b 5 NULL 15 Using where +explain extended select * from t2 where b > 5; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range b b 5 NULL 5 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` > 5) +explain partitions select * from t2 where b > 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 range b b 5 NULL 5 Using where +explain extended select * from t2 where b > 5 and b < 8; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range b b 5 NULL 5 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where ((`test`.`t2`.`b` > 5) and (`test`.`t2`.`b` < 8)) +explain partitions select * from t2 where b > 5 and b < 8; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 range b b 5 NULL 5 Using where +explain extended select * from t2 where b > 5 and b < 7; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range b b 5 NULL 5 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where ((`test`.`t2`.`b` > 5) and (`test`.`t2`.`b` < 7)) +explain partitions select * from t2 where b > 5 and b < 7; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 range b b 5 NULL 5 Using where +explain extended select * from t2 where b > 0 and b < 5; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 range b b 5 NULL 5 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where ((`test`.`t2`.`b` > 0) and (`test`.`t2`.`b` < 5)) +explain partitions select * from t2 where b > 0 and b < 5; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1,p2,p3,p4 range b b 5 NULL 5 Using where +flush status; +update t2 set a = 111 where b = 10; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +show status like 'Handler_read_key'; +Variable_name Value +Handler_read_key 0 +flush status; +update t2 set a = 111 where b in (5,6); +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +show status like 'Handler_read_key'; +Variable_name Value +Handler_read_key 0 +flush status; +update t2 set a = 222 where b = 7; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +show status like 'Handler_read_key'; +Variable_name Value +Handler_read_key 0 +flush status; +delete from t2 where b = 7; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +show status like 'Handler_read_key'; +Variable_name Value +Handler_read_key 0 +flush status; +delete from t2 where b > 5; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +show status like 'Handler_read_key'; +Variable_name Value +Handler_read_key 0 +show status like 'Handler_read_prev'; +Variable_name Value +Handler_read_prev 0 +show status like 'Handler_read_next'; +Variable_name Value +Handler_read_next 0 +flush status; +delete from t2 where b < 5 or b > 3; +show status like 'Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 0 +show status like 'Handler_read_key'; +Variable_name Value +Handler_read_key 0 +show status like 'Handler_read_prev'; +Variable_name Value +Handler_read_prev 0 +show status like 'Handler_read_next'; +Variable_name Value +Handler_read_next 0 +drop table t1, t2; +create table t1 ( f_int1 mediumint, f_int2 integer) +partition by list(mod(f_int1,4)) ( +partition p_3 values in (-3), +partition p_2 values in (-2), +partition p_1 values in (-1), +partition p0 values in (0), +partition p1 values in (1), +partition p2 values in (2), +partition p3 values in (3) +); +insert into t1 values (9, 9), (8, 8), (7, 7), (6, 6), (5, 5), +(4, 4), (3, 3), (2, 2), (1, 1); +select * from t1 where f_int1 between 5 and 15 order by f_int1; +f_int1 f_int2 +5 5 +6 6 +7 7 +8 8 +9 9 +drop table t1; +create table t1 (f_int1 integer) partition by list(abs(mod(f_int1,2))) +subpartition by hash(f_int1) subpartitions 2 +( +partition part1 values in (0), +partition part2 values in (1), +partition part4 values in (null) +); +insert into t1 set f_int1 = null; +select * from t1 where f_int1 is null; +f_int1 +NULL +explain partitions select * from t1 where f_int1 is null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 part4_part4sp0 ALL NULL NULL NULL NULL 1 Using where +drop table t1; +create table t1 (a int not null, b int not null) +partition by list(a) +subpartition by hash(b) subpartitions 4 +( +partition p0 values in (1), +partition p1 values in (2), +partition p2 values in (3) +); +insert into t1 values (1,1),(1,2),(1,3),(1,4), +(2,1),(2,2),(2,3),(2,4); +explain partitions select * from t1 where a=1 AND (b=1 OR b=2); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0_p0sp1,p0_p0sp2 ALL NULL NULL NULL NULL 2 Using where +drop table t1; +create table t1 (a int, b int not null) +partition by list(a) +subpartition by hash(b) subpartitions 2 +( +partition p0 values in (1), +partition p1 values in (2), +partition p2 values in (3), +partition pn values in (NULL) +); +insert into t1 values (1,1),(1,2),(1,3),(1,4), +(2,1),(2,2),(2,3),(2,4), (NULL,1); +explain partitions select * from t1 where a IS NULL AND (b=1 OR b=2); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pn_pnsp0,pn_pnsp1 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t1 where (a IS NULL or a < 1) AND (b=1 OR b=2); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pn_pnsp0,pn_pnsp1 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t1 where (a IS NULL or a < 2) AND (b=1 OR b=2); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0_p0sp0,p0_p0sp1,pn_pnsp0,pn_pnsp1 ALL NULL NULL NULL NULL 5 Using where +explain partitions select * from t1 where (a IS NULL or a <= 1) AND (b=1 OR b=2); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0_p0sp0,p0_p0sp1,pn_pnsp0,pn_pnsp1 ALL NULL NULL NULL NULL 5 Using where +drop table t1; +create table t1 ( a int) partition by list (MOD(a, 10)) +( partition p0 values in (0), partition p1 values in (1), +partition p2 values in (2), partition p3 values in (3), +partition p4 values in (4), partition p5 values in (5), +partition p6 values in (6), partition pn values in (NULL) +); +insert into t1 values (NULL), (0),(1),(2),(3),(4),(5),(6); +explain partitions select * from t1 where a is null or a < 2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1,p2,p3,p4,p5,p6,pn ALL NULL NULL NULL NULL 8 Using where +drop table t1; +create table t1 (s1 int) partition by list (s1) +(partition p1 values in (0), +partition p2 values in (1), +partition p3 values in (null)); +insert into t1 values (0),(1),(null); +select count(*) from t1 where s1 < 0 or s1 is null; +count(*) +1 +explain partitions select count(*) from t1 where s1 < 0 or s1 is null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p3 ALL NULL NULL NULL NULL 1 Using where +drop table t1; +create table t1 (a char(32) primary key) +partition by key() +partitions 100; +insert into t1 values ('na'); +select * from t1; +a +na +select * from t1 where a like 'n%'; +a +na +drop table t1; +create table t1 (s1 varchar(15)) partition by key (s1); +select * from t1 where s1 = 0 or s1 is null; +s1 +insert into t1 values ('aa'),('bb'),('0'); +explain partitions select * from t1 where s1 = 0 or s1 is null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 3 Using where +drop table t1; +create table t2 (a int, b int) +partition by LIST(a) +subpartition by HASH(b) subpartitions 40 +( partition p_0_long_partition_name values in(1), +partition p_1_long_partition_name values in(2)); +insert into t2 values (1,1),(2,2); +explain partitions select * from t2; +id 1 +select_type SIMPLE +table t2 +partitions p_0_long_partition_name_p_0_long_partition_namesp0,p_0_long_partition_name_p_0_long_partition_namesp1,p_0_long_partition_name_p_0_long_partition_namesp2,p_0_long_partition_name_p_0_long_partition_namesp3,p_0_long_partition_name_p_0_long_partition_namesp4,p_0_long_partition_name_p_0_long_partition_namesp5,p_0_long_partition_name_p_0_long_partition_namesp6,p_0_long_partition_name_p_0_long_partition_namesp7,p_0_long_partition_name_p_0_long_partition_namesp8,p_0_long_partition_name_p_0_long_partition_namesp9,p_0_long_partition_name_p_0_long_partition_namesp10,p_0_long_partition_name_p_0_long_partition_namesp11,p_0_long_partition_name_p_0_long_partition_namesp12,p_0_long_partition_name_p_0_long_partition_namesp13,p_0_long_partition_name_p_0_long_partition_namesp14,p_0_long_partition_name_p_0_long_partition_namesp15,p_0_long_partition_name_p_0_long_partition_namesp16,p_0_long_partition_name_p_0_long_partition_namesp17,p_0_long_partition_name_p_0_long_partition_namesp18,p_0_long_partition_name_p_0_long_partition_namesp19,p_0_long_partition_name_p_0_long_partition_namesp20,p_0_long_partition_name_p_0_long_partition_namesp21,p_0_long_partition_name_p_0_long_partition_namesp22,p_0_long_partition_name_p_0_long_partition_namesp23,p_0_long_partition_name_p_0_long_partition_namesp24,p_0_long_partition_name_p_0_long_partition_namesp25,p_0_long_partition_name_p_0_long_partition_namesp26,p_0_long_partition_name_p_0_long_partition_namesp27,p_0_long_partition_name_p_0_long_partition_namesp28,p_0_long_partition_name_p_0_long_partition_namesp29,p_0_long_partition_name_p_0_long_partition_namesp30,p_0_long_partition_name_p_0_long_partition_namesp31,p_0_long_partition_name_p_0_long_partition_namesp32,p_0_long_partition_name_p_0_long_partition_namesp33,p_0_long_partition_name_p_0_long_partition_namesp34,p_0_long_partition_name_p_0_long_partition_namesp35,p_0_long_partition_name_p_0_long_partition_namesp36,p_0_long_partition_name_p_0_long_partition_namesp37,p_0_long_partition_name_p_0_long_partition_namesp38,p_0_long_partition_name_p_0_long_partition_namesp39,p_1_long_partition_name_p_1_long_partition_namesp0,p_1_long_partition_name_p_1_long_partition_namesp1,p_1_long_partition_name_p_1_long_partition_namesp2,p_1_long_partition_name_p_1_long_partition_namesp3,p_1_long_partition_name_p_1_long_partition_namesp4,p_1_long_partition_name_p_1_long_partition_namesp5,p_1_long_partition_name_p_1_long_partition_namesp6,p_1_long_partition_name_p_1_long_partition_namesp7,p_1_long_partition_name_p_1_long_partition_namesp8,p_1_long_partition_name_p_1_long_partition_namesp9,p_1_long_partition_name_p_1_long_partition_namesp10,p_1_long_partition_name_p_1_long_partition_namesp11,p_1_long_partition_name_p_1_long_partition_namesp12,p_1_long_partition_name_p_1_long_partition_namesp13,p_1_long_partition_name_p_1_long_partition_namesp14,p_1_long_partition_name_p_1_long_partition_namesp15,p_1_long_partition_name_p_1_long_partition_namesp16,p_1_long_partition_name_p_1_long_partition_namesp17,p_1_long_partition_name_p_1_long_partition_namesp18,p_1_long_partition_name_p_1_long_partition_namesp19,p_1_long_partition_name_p_1_long_partition_namesp20,p_1_long_partition_name_p_1_long_partition_namesp21,p_1_long_partition_name_p_1_long_partition_namesp22,p_1_long_partition_name_p_1_long_partition_namesp23,p_1_long_partition_name_p_1_long_partition_namesp24,p_1_long_partition_name_p_1_long_partition_namesp25,p_1_long_partition_name_p_1_long_partition_namesp26,p_1_long_partition_name_p_1_long_partition_namesp27,p_1_long_partition_name_p_1_long_partition_namesp28,p_1_long_partition_name_p_1_long_partition_namesp29,p_1_long_partition_name_p_1_long_partition_namesp30,p_1_long_partition_name_p_1_long_partition_namesp31,p_1_long_partition_name_p_1_long_partition_namesp32,p_1_long_partition_name_p_1_long_partition_namesp33,p_1_long_partition_name_p_1_long_partition_namesp34,p_1_long_partition_name_p_1_long_partition_namesp35,p_1_long_partition_name_p_1_long_partition_namesp36,p_1_long_partition_name_p_1_long_partition_namesp37,p_1_long_partition_name_p_1_long_partition_namesp38,p_1_long_partition_name_p_1_long_partition_namesp39 +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows 2 +Extra +drop table t2; +create table t1 (s1 int); +explain partitions select 1 from t1 union all select 2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 PRIMARY t1 NULL ALL NULL NULL NULL NULL 0 +2 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT <union1,2> NULL ALL NULL NULL NULL NULL NULL +drop table t1; +create table t1 (a bigint unsigned not null) partition by range(a) ( +partition p0 values less than (10), +partition p1 values less than (100), +partition p2 values less than (1000), +partition p3 values less than (18446744073709551000), +partition p4 values less than (18446744073709551614) +); +insert into t1 values (5),(15),(105),(1005); +insert into t1 values (18446744073709551000+1); +insert into t1 values (18446744073709551614-1); +explain partitions select * from t1 where a < 10; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 1 Using where +explain partitions select * from t1 +where a >= 18446744073709551000-1 and a <= 18446744073709551000+1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p3,p4 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 +where a between 18446744073709551001 and 18446744073709551002; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p4 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a = 18446744073709551000; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p4 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a = 18446744073709551613; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p4 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a = 18446744073709551614; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +drop table t1; +create table t1 (a int) +partition by range(a) ( +partition p0 values less than (64), +partition p1 values less than (128), +partition p2 values less than (255) +); +create table t2 (a int) +partition by range(a+0) ( +partition p0 values less than (64), +partition p1 values less than (128), +partition p2 values less than (255) +); +insert into t1 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE); +insert into t2 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE); +explain partitions select * from t1 where a=0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t2 where a=0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t1 where a=0xFE; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t2 where a=0xFE; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p2 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a > 0xFE AND a <= 0xFF; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t2 where a > 0xFE AND a <= 0xFF; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a >= 0xFE AND a <= 0xFF; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t2 where a >= 0xFE AND a <= 0xFF; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p2 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a < 64 AND a >= 63; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t2 where a < 64 AND a >= 63; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a <= 64 AND a >= 63; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 6 Using where +explain partitions select * from t2 where a <= 64 AND a >= 63; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p0,p1 ALL NULL NULL NULL NULL 6 Using where +drop table t1; +drop table t2; +create table t1(a bigint unsigned not null) partition by range(a+0) ( +partition p1 values less than (10), +partition p2 values less than (20), +partition p3 values less than (2305561538531885056), +partition p4 values less than (2305561538531950591) +); +insert into t1 values (9),(19),(0xFFFF0000FFFF000-1), (0xFFFF0000FFFFFFF-1); +insert into t1 values (9),(19),(0xFFFF0000FFFF000-1), (0xFFFF0000FFFFFFF-1); +explain partitions select * from t1 where +a >= 2305561538531885056-10 and a <= 2305561538531885056-8; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p3 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where +a > 0xFFFFFFFFFFFFFFEC and a < 0xFFFFFFFFFFFFFFEE; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a>=0 and a <= 0xFFFFFFFFFFFFFFFF; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1,p2,p3,p4 ALL NULL NULL NULL NULL 8 Using where +drop table t1; +create table t1 (a bigint) partition by range(a+0) ( +partition p1 values less than (-1000), +partition p2 values less than (-10), +partition p3 values less than (10), +partition p4 values less than (1000) +); +insert into t1 values (-15),(-5),(5),(15),(-15),(-5),(5),(15); +explain partitions select * from t1 where a>-2 and a <=0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p3 ALL NULL NULL NULL NULL 4 Using where +drop table t1; diff --git a/mysql-test/suite/pbxt/r/partition_range.result b/mysql-test/suite/pbxt/r/partition_range.result new file mode 100644 index 00000000000..f204be71e4f --- /dev/null +++ b/mysql-test/suite/pbxt/r/partition_range.result @@ -0,0 +1,741 @@ +drop table if exists t1; +create table t1 (a int unsigned) +partition by range (a) +(partition pnull values less than (0), +partition p0 values less than (1), +partition p1 values less than(2)); +insert into t1 values (null),(0),(1); +select * from t1 where a is null; +a +NULL +select * from t1 where a >= 0; +a +0 +1 +select * from t1 where a < 0; +a +select * from t1 where a <= 0; +a +0 +select * from t1 where a > 1; +a +explain partitions select * from t1 where a is null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pnull ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t1 where a >= 0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t1 where a < 0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pnull ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t1 where a <= 0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pnull,p0 ALL NULL NULL NULL NULL 3 Using where +explain partitions select * from t1 where a > 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +drop table t1; +create table t1 (a int unsigned, b int unsigned) +partition by range (a) +subpartition by hash (b) +subpartitions 2 +(partition pnull values less than (0), +partition p0 values less than (1), +partition p1 values less than(2)); +insert into t1 values (null,0),(null,1),(0,0),(0,1),(1,0),(1,1); +select * from t1 where a is null; +a b +NULL 0 +NULL 1 +select * from t1 where a >= 0; +a b +0 0 +0 1 +1 0 +1 1 +select * from t1 where a < 0; +a b +select * from t1 where a <= 0; +a b +0 0 +0 1 +select * from t1 where a > 1; +a b +explain partitions select * from t1 where a is null; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pnull_pnullsp0,pnull_pnullsp1 ALL NULL NULL NULL NULL 6 Using where +explain partitions select * from t1 where a >= 0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0_p0sp0,p0_p0sp1,p1_p1sp0,p1_p1sp1 ALL NULL NULL NULL NULL 6 Using where +explain partitions select * from t1 where a < 0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pnull_pnullsp0,pnull_pnullsp1 ALL NULL NULL NULL NULL 6 Using where +explain partitions select * from t1 where a <= 0; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pnull_pnullsp0,pnull_pnullsp1,p0_p0sp0,p0_p0sp1 ALL NULL NULL NULL NULL 6 Using where +explain partitions select * from t1 where a > 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using where +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, +partition x2 values less than (10) tablespace ts2, +partition x3 values less than maxvalue tablespace ts3); +INSERT into t1 values (1, 1, 1); +INSERT into t1 values (6, 1, 1); +INSERT into t1 values (10, 1, 1); +INSERT into t1 values (15, 1, 1); +select * from t1; +a b c +1 1 1 +6 1 1 +10 1 1 +15 1 1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) NOT NULL, + `c` int(11) NOT NULL, + PRIMARY KEY (`a`,`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION x1 VALUES LESS THAN (5) TABLESPACE = ts1 ENGINE = PBXT, + PARTITION x2 VALUES LESS THAN (10) TABLESPACE = ts2 ENGINE = PBXT, + PARTITION x3 VALUES LESS THAN MAXVALUE TABLESPACE = ts3 ENGINE = PBXT) */ +ALTER TABLE t1 +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, +partition x2 values less than (10) tablespace ts2, +partition x3 values less than maxvalue tablespace ts3); +select * from t1; +a b c +1 1 1 +6 1 1 +10 1 1 +15 1 1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) NOT NULL, + `c` int(11) NOT NULL, + PRIMARY KEY (`a`,`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION x1 VALUES LESS THAN (5) TABLESPACE = ts1 ENGINE = PBXT, + PARTITION x2 VALUES LESS THAN (10) TABLESPACE = ts2 ENGINE = PBXT, + PARTITION x3 VALUES LESS THAN MAXVALUE TABLESPACE = ts3 ENGINE = PBXT) */ +drop table if exists t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null) +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, +partition x2 values less than (10) tablespace ts2, +partition x3 values less than maxvalue tablespace ts3); +INSERT into t1 values (1, 1, 1); +INSERT into t1 values (6, 1, 1); +INSERT into t1 values (10, 1, 1); +INSERT into t1 values (15, 1, 1); +select * from t1; +a b c +1 1 1 +6 1 1 +10 1 1 +15 1 1 +ALTER TABLE t1 +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, +partition x2 values less than (10) tablespace ts2, +partition x3 values less than maxvalue tablespace ts3); +select * from t1; +a b c +1 1 1 +6 1 1 +10 1 1 +15 1 1 +drop table if exists t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, +partition x2 values less than (10) tablespace ts2, +partition x3 values less than (15) tablespace ts3); +INSERT into t1 values (1, 1, 1); +INSERT into t1 values (6, 1, 1); +INSERT into t1 values (10, 1, 1); +INSERT into t1 values (15, 1, 1); +ERROR HY000: Table has no partition for value 15 +select * from t1; +a b c +1 1 1 +6 1 1 +10 1 1 +ALTER TABLE t1 +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, +partition x2 values less than (10) tablespace ts2, +partition x3 values less than (15) tablespace ts3); +select * from t1; +a b c +1 1 1 +6 1 1 +10 1 1 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +(partition x1 values less than (1)); +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11, +subpartition x12), +partition x2 values less than (5) +( subpartition x21, +subpartition x22) +); +SELECT * from t1; +a b c +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) NOT NULL, + `c` int(11) NOT NULL, + PRIMARY KEY (`a`,`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a+b) +(PARTITION x1 VALUES LESS THAN (1) + (SUBPARTITION x11 ENGINE = PBXT, + SUBPARTITION x12 ENGINE = PBXT), + PARTITION x2 VALUES LESS THAN (5) + (SUBPARTITION x21 ENGINE = PBXT, + SUBPARTITION x22 ENGINE = PBXT)) */ +ALTER TABLE t1 ADD COLUMN d int; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) NOT NULL, + `c` int(11) NOT NULL, + `d` int(11) DEFAULT NULL, + PRIMARY KEY (`a`,`b`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a+b) +(PARTITION x1 VALUES LESS THAN (1) + (SUBPARTITION x11 ENGINE = PBXT, + SUBPARTITION x12 ENGINE = PBXT), + PARTITION x2 VALUES LESS THAN (5) + (SUBPARTITION x21 ENGINE = PBXT, + SUBPARTITION x22 ENGINE = PBXT)) */ +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11 tablespace t1 nodegroup 0, +subpartition x12 tablespace t2 nodegroup 1), +partition x2 values less than (5) +( subpartition x21 tablespace t1 nodegroup 0, +subpartition x22 tablespace t2 nodegroup 1) +); +SELECT * from t1; +a b c +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11 tablespace t1 nodegroup 0, +subpartition x12 tablespace t2 nodegroup 1), +partition x2 values less than (5) +( subpartition x21 tablespace t1 nodegroup 0, +subpartition x22 tablespace t2 nodegroup 1) +); +SELECT * from t1; +a b c +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11 nodegroup 0, +subpartition x12 nodegroup 1), +partition x2 values less than (5) +( subpartition x21 nodegroup 0, +subpartition x22 nodegroup 1) +); +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +INSERT into t1 VALUES (5,1,1); +ERROR HY000: Table has no partition for value 5 +SELECT * from t1; +a b c +1 1 1 +4 1 1 +ALTER TABLE t1 +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11 nodegroup 0, +subpartition x12 nodegroup 1), +partition x2 values less than (5) +( subpartition x21 nodegroup 0, +subpartition x22 nodegroup 1) +); +SELECT * from t1; +a b c +1 1 1 +4 1 1 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11 tablespace t1, +subpartition x12 tablespace t2), +partition x2 values less than (5) +( subpartition x21 tablespace t1, +subpartition x22 tablespace t2) +); +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +INSERT into t1 VALUES (5,1,1); +ERROR HY000: Table has no partition for value 5 +SELECT * from t1; +a b c +1 1 1 +4 1 1 +ALTER TABLE t1 +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11 tablespace t1, +subpartition x12 tablespace t2), +partition x2 values less than (5) +( subpartition x21 tablespace t1, +subpartition x22 tablespace t2) +); +SELECT * from t1; +a b c +1 1 1 +4 1 1 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11 tablespace t1, +subpartition x12 tablespace t2), +partition x2 values less than (5) +( subpartition x21 tablespace t1, +subpartition x22 tablespace t2) +); +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +INSERT into t1 VALUES (5,1,1); +ERROR HY000: Table has no partition for value 5 +SELECT * from t1; +a b c +1 1 1 +4 1 1 +ALTER TABLE t1 +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11 tablespace t1, +subpartition x12 tablespace t2), +partition x2 values less than (5) +( subpartition x21 tablespace t1, +subpartition x22 tablespace t2) +); +SELECT * from t1; +a b c +1 1 1 +4 1 1 +drop table t1; +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11, +subpartition x12), +partition x2 values less than (5) +( subpartition x21, +subpartition x22) +); +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +INSERT into t1 VALUES (5,1,1); +ERROR HY000: Table has no partition for value 5 +SELECT * from t1; +a b c +1 1 1 +4 1 1 +ALTER TABLE t1 +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) +( subpartition x11, +subpartition x12), +partition x2 values less than (5) +( subpartition x21, +subpartition x22) +); +SELECT * from t1; +a b c +1 1 1 +4 1 1 +drop table t1; +CREATE TABLE t1 (c1 int default NULL, c2 varchar(30) default NULL, +c3 date default NULL) engine=myisam +PARTITION BY RANGE (year(c3)) (PARTITION p0 VALUES LESS THAN (1995), +PARTITION p1 VALUES LESS THAN (1996) , PARTITION p2 VALUES LESS THAN (1997) , +PARTITION p3 VALUES LESS THAN (1998) , PARTITION p4 VALUES LESS THAN (1999) , +PARTITION p5 VALUES LESS THAN (2000) , PARTITION p6 VALUES LESS THAN (2001) , +PARTITION p7 VALUES LESS THAN (2002) , PARTITION p8 VALUES LESS THAN (2003) , +PARTITION p9 VALUES LESS THAN (2004) , PARTITION p10 VALUES LESS THAN (2010), +PARTITION p11 VALUES LESS THAN MAXVALUE ); +INSERT INTO t1 VALUES (1, 'testing partitions', '1995-07-17'), +(3, 'testing partitions','1995-07-31'), +(5, 'testing partitions','1995-08-13'), +(7, 'testing partitions','1995-08-26'), +(9, 'testing partitions','1995-09-09'), +(0, 'testing partitions','2000-07-10'), +(2, 'testing partitions','2000-07-23'), +(4, 'testing partitions','2000-08-05'), +(6, 'testing partitions','2000-08-19'), +(8, 'testing partitions','2000-09-01'); +SELECT COUNT(*) FROM t1 WHERE c3 BETWEEN '1996-12-31' AND '2000-12-31'; +COUNT(*) +5 +SELECT COUNT(*) FROM t1 WHERE c3 < '2000-12-31'; +COUNT(*) +10 +DROP TABLE t1; +create table t1 (a bigint unsigned) +partition by range (a) +(partition p0 values less than (10), +partition p1 values less than (0)); +ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition +create table t1 (a bigint unsigned) +partition by range (a) +(partition p0 values less than (0), +partition p1 values less than (10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) unsigned DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION p0 VALUES LESS THAN (0) ENGINE = PBXT, + PARTITION p1 VALUES LESS THAN (10) ENGINE = PBXT) */ +drop table t1; +create table t1 (a bigint unsigned) +partition by range (a) +(partition p0 values less than (2), +partition p1 values less than (10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) unsigned DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION p0 VALUES LESS THAN (2) ENGINE = PBXT, + PARTITION p1 VALUES LESS THAN (10) ENGINE = PBXT) */ +insert into t1 values (0xFFFFFFFFFFFFFFFF); +ERROR HY000: Table has no partition for value 18446744073709551615 +drop table t1; +create table t1 (a int) +partition by range (MOD(a,3)) +subpartition by hash(a) +subpartitions 2 +(partition p0 values less than (1), +partition p1 values less than (2), +partition p2 values less than (3), +partition p3 values less than (4)); +ALTER TABLE t1 DROP PARTITION p3; +ALTER TABLE t1 DROP PARTITION p1; +ALTER TABLE t1 DROP PARTITION p2; +drop table t1; +create table t1 (a int) +partition by range (MOD(a,3)) +subpartition by hash(a) +subpartitions 2 +(partition p0 values less than (1), +partition p1 values less than (2), +partition p2 values less than (3), +partition p3 values less than (4)); +ALTER TABLE t1 DROP PARTITION p0; +ALTER TABLE t1 DROP PARTITION p1; +ALTER TABLE t1 DROP PARTITION p2; +drop table t1; +create table t1 (a int DEFAULT NULL, +b varchar(30) DEFAULT NULL, +c date DEFAULT NULL) +ENGINE=MYISAM DEFAULT CHARSET=latin1; +insert into t1 values (1, 'abc', '1995-01-01'); +insert into t1 values (1, 'abc', '1995-01-02'); +insert into t1 values (1, 'abc', '1995-01-03'); +insert into t1 values (1, 'abc', '1995-01-04'); +insert into t1 values (1, 'abc', '1995-01-05'); +insert into t1 values (1, 'abc', '1995-01-06'); +insert into t1 values (1, 'abc', '1995-01-07'); +insert into t1 values (1, 'abc', '1995-01-08'); +insert into t1 values (1, 'abc', '1995-01-09'); +insert into t1 values (1, 'abc', '1995-01-10'); +insert into t1 values (1, 'abc', '1995-01-11'); +insert into t1 values (1, 'abc', '1995-01-12'); +insert into t1 values (1, 'abc', '1995-01-13'); +insert into t1 values (1, 'abc', '1995-01-14'); +insert into t1 values (1, 'abc', '1995-01-15'); +insert into t1 values (1, 'abc', '1997-01-01'); +insert into t1 values (1, 'abc', '1997-01-02'); +insert into t1 values (1, 'abc', '1997-01-03'); +insert into t1 values (1, 'abc', '1997-01-04'); +insert into t1 values (1, 'abc', '1997-01-05'); +insert into t1 values (1, 'abc', '1997-01-06'); +insert into t1 values (1, 'abc', '1997-01-07'); +insert into t1 values (1, 'abc', '1997-01-08'); +insert into t1 values (1, 'abc', '1997-01-09'); +insert into t1 values (1, 'abc', '1997-01-10'); +insert into t1 values (1, 'abc', '1997-01-11'); +insert into t1 values (1, 'abc', '1997-01-12'); +insert into t1 values (1, 'abc', '1997-01-13'); +insert into t1 values (1, 'abc', '1997-01-14'); +insert into t1 values (1, 'abc', '1997-01-15'); +insert into t1 values (1, 'abc', '1998-01-01'); +insert into t1 values (1, 'abc', '1998-01-02'); +insert into t1 values (1, 'abc', '1998-01-03'); +insert into t1 values (1, 'abc', '1998-01-04'); +insert into t1 values (1, 'abc', '1998-01-05'); +insert into t1 values (1, 'abc', '1998-01-06'); +insert into t1 values (1, 'abc', '1998-01-07'); +insert into t1 values (1, 'abc', '1998-01-08'); +insert into t1 values (1, 'abc', '1998-01-09'); +insert into t1 values (1, 'abc', '1998-01-10'); +insert into t1 values (1, 'abc', '1998-01-11'); +insert into t1 values (1, 'abc', '1998-01-12'); +insert into t1 values (1, 'abc', '1998-01-13'); +insert into t1 values (1, 'abc', '1998-01-14'); +insert into t1 values (1, 'abc', '1998-01-15'); +insert into t1 values (1, 'abc', '1999-01-01'); +insert into t1 values (1, 'abc', '1999-01-02'); +insert into t1 values (1, 'abc', '1999-01-03'); +insert into t1 values (1, 'abc', '1999-01-04'); +insert into t1 values (1, 'abc', '1999-01-05'); +insert into t1 values (1, 'abc', '1999-01-06'); +insert into t1 values (1, 'abc', '1999-01-07'); +insert into t1 values (1, 'abc', '1999-01-08'); +insert into t1 values (1, 'abc', '1999-01-09'); +insert into t1 values (1, 'abc', '1999-01-10'); +insert into t1 values (1, 'abc', '1999-01-11'); +insert into t1 values (1, 'abc', '1999-01-12'); +insert into t1 values (1, 'abc', '1999-01-13'); +insert into t1 values (1, 'abc', '1999-01-14'); +insert into t1 values (1, 'abc', '1999-01-15'); +insert into t1 values (1, 'abc', '2000-01-01'); +insert into t1 values (1, 'abc', '2000-01-02'); +insert into t1 values (1, 'abc', '2000-01-03'); +insert into t1 values (1, 'abc', '2000-01-04'); +insert into t1 values (1, 'abc', '2000-01-05'); +insert into t1 values (1, 'abc', '2000-01-06'); +insert into t1 values (1, 'abc', '2000-01-07'); +insert into t1 values (1, 'abc', '2000-01-08'); +insert into t1 values (1, 'abc', '2000-01-09'); +insert into t1 values (1, 'abc', '2000-01-15'); +insert into t1 values (1, 'abc', '2000-01-11'); +insert into t1 values (1, 'abc', '2000-01-12'); +insert into t1 values (1, 'abc', '2000-01-13'); +insert into t1 values (1, 'abc', '2000-01-14'); +insert into t1 values (1, 'abc', '2000-01-15'); +insert into t1 values (1, 'abc', '2001-01-01'); +insert into t1 values (1, 'abc', '2001-01-02'); +insert into t1 values (1, 'abc', '2001-01-03'); +insert into t1 values (1, 'abc', '2001-01-04'); +insert into t1 values (1, 'abc', '2001-01-05'); +insert into t1 values (1, 'abc', '2001-01-06'); +insert into t1 values (1, 'abc', '2001-01-07'); +insert into t1 values (1, 'abc', '2001-01-08'); +insert into t1 values (1, 'abc', '2001-01-09'); +insert into t1 values (1, 'abc', '2001-01-15'); +insert into t1 values (1, 'abc', '2001-01-11'); +insert into t1 values (1, 'abc', '2001-01-12'); +insert into t1 values (1, 'abc', '2001-01-13'); +insert into t1 values (1, 'abc', '2001-01-14'); +insert into t1 values (1, 'abc', '2001-01-15'); +alter table t1 +partition by range (year(c)) +(partition p5 values less than (2000), partition p10 values less than (2010)); +alter table t1 +reorganize partition p5 into +(partition p1 values less than (1996), +partition p2 values less than (1997), +partition p3 values less than (1998), +partition p4 values less than (1999), +partition p5 values less than (2000)); +drop table t1; +CREATE TABLE t1 (a date) +PARTITION BY RANGE (TO_DAYS(a)) +(PARTITION p3xx VALUES LESS THAN (TO_DAYS('2004-01-01')), +PARTITION p401 VALUES LESS THAN (TO_DAYS('2004-02-01')), +PARTITION p402 VALUES LESS THAN (TO_DAYS('2004-03-01')), +PARTITION p403 VALUES LESS THAN (TO_DAYS('2004-04-01')), +PARTITION p404 VALUES LESS THAN (TO_DAYS('2004-05-01')), +PARTITION p405 VALUES LESS THAN (TO_DAYS('2004-06-01')), +PARTITION p406 VALUES LESS THAN (TO_DAYS('2004-07-01')), +PARTITION p407 VALUES LESS THAN (TO_DAYS('2004-08-01')), +PARTITION p408 VALUES LESS THAN (TO_DAYS('2004-09-01')), +PARTITION p409 VALUES LESS THAN (TO_DAYS('2004-10-01')), +PARTITION p410 VALUES LESS THAN (TO_DAYS('2004-11-01')), +PARTITION p411 VALUES LESS THAN (TO_DAYS('2004-12-01')), +PARTITION p412 VALUES LESS THAN (TO_DAYS('2005-01-01')), +PARTITION p501 VALUES LESS THAN (TO_DAYS('2005-02-01')), +PARTITION p502 VALUES LESS THAN (TO_DAYS('2005-03-01')), +PARTITION p503 VALUES LESS THAN (TO_DAYS('2005-04-01')), +PARTITION p504 VALUES LESS THAN (TO_DAYS('2005-05-01')), +PARTITION p505 VALUES LESS THAN (TO_DAYS('2005-06-01')), +PARTITION p506 VALUES LESS THAN (TO_DAYS('2005-07-01')), +PARTITION p507 VALUES LESS THAN (TO_DAYS('2005-08-01')), +PARTITION p508 VALUES LESS THAN (TO_DAYS('2005-09-01')), +PARTITION p509 VALUES LESS THAN (TO_DAYS('2005-10-01')), +PARTITION p510 VALUES LESS THAN (TO_DAYS('2005-11-01')), +PARTITION p511 VALUES LESS THAN (TO_DAYS('2005-12-01')), +PARTITION p512 VALUES LESS THAN (TO_DAYS('2006-01-01')), +PARTITION p601 VALUES LESS THAN (TO_DAYS('2006-02-01')), +PARTITION p602 VALUES LESS THAN (TO_DAYS('2006-03-01')), +PARTITION p603 VALUES LESS THAN (TO_DAYS('2006-04-01')), +PARTITION p604 VALUES LESS THAN (TO_DAYS('2006-05-01')), +PARTITION p605 VALUES LESS THAN (TO_DAYS('2006-06-01')), +PARTITION p606 VALUES LESS THAN (TO_DAYS('2006-07-01')), +PARTITION p607 VALUES LESS THAN (TO_DAYS('2006-08-01'))); +INSERT INTO t1 VALUES ('2003-01-13'),('2003-06-20'),('2003-08-30'); +INSERT INTO t1 VALUES ('2003-04-13'),('2003-07-20'),('2003-10-30'); +INSERT INTO t1 VALUES ('2003-05-13'),('2003-11-20'),('2003-12-30'); +INSERT INTO t1 VALUES ('2004-01-13'),('2004-01-20'),('2004-01-30'); +INSERT INTO t1 VALUES ('2004-02-13'),('2004-02-20'),('2004-02-28'); +INSERT INTO t1 VALUES ('2004-03-13'),('2004-03-20'),('2004-03-30'); +INSERT INTO t1 VALUES ('2004-04-13'),('2004-04-20'),('2004-04-30'); +INSERT INTO t1 VALUES ('2004-05-13'),('2004-05-20'),('2004-05-30'); +INSERT INTO t1 VALUES ('2004-06-13'),('2004-06-20'),('2004-06-30'); +INSERT INTO t1 VALUES ('2004-07-13'),('2004-07-20'),('2004-07-30'); +INSERT INTO t1 VALUES ('2004-08-13'),('2004-08-20'),('2004-08-30'); +INSERT INTO t1 VALUES ('2004-09-13'),('2004-09-20'),('2004-09-30'); +INSERT INTO t1 VALUES ('2004-10-13'),('2004-10-20'),('2004-10-30'); +INSERT INTO t1 VALUES ('2004-11-13'),('2004-11-20'),('2004-11-30'); +INSERT INTO t1 VALUES ('2004-12-13'),('2004-12-20'),('2004-12-30'); +INSERT INTO t1 VALUES ('2005-01-13'),('2005-01-20'),('2005-01-30'); +INSERT INTO t1 VALUES ('2005-02-13'),('2005-02-20'),('2005-02-28'); +INSERT INTO t1 VALUES ('2005-03-13'),('2005-03-20'),('2005-03-30'); +INSERT INTO t1 VALUES ('2005-04-13'),('2005-04-20'),('2005-04-30'); +INSERT INTO t1 VALUES ('2005-05-13'),('2005-05-20'),('2005-05-30'); +INSERT INTO t1 VALUES ('2005-06-13'),('2005-06-20'),('2005-06-30'); +INSERT INTO t1 VALUES ('2005-07-13'),('2005-07-20'),('2005-07-30'); +INSERT INTO t1 VALUES ('2005-08-13'),('2005-08-20'),('2005-08-30'); +INSERT INTO t1 VALUES ('2005-09-13'),('2005-09-20'),('2005-09-30'); +INSERT INTO t1 VALUES ('2005-10-13'),('2005-10-20'),('2005-10-30'); +INSERT INTO t1 VALUES ('2005-11-13'),('2005-11-20'),('2005-11-30'); +INSERT INTO t1 VALUES ('2005-12-13'),('2005-12-20'),('2005-12-30'); +INSERT INTO t1 VALUES ('2006-01-13'),('2006-01-20'),('2006-01-30'); +INSERT INTO t1 VALUES ('2006-02-13'),('2006-02-20'),('2006-02-28'); +INSERT INTO t1 VALUES ('2006-03-13'),('2006-03-20'),('2006-03-30'); +INSERT INTO t1 VALUES ('2006-04-13'),('2006-04-20'),('2006-04-30'); +INSERT INTO t1 VALUES ('2006-05-13'),('2006-05-20'),('2006-05-30'); +INSERT INTO t1 VALUES ('2006-06-13'),('2006-06-20'),('2006-06-30'); +INSERT INTO t1 VALUES ('2006-07-13'),('2006-07-20'),('2006-07-30'); +SELECT * FROM t1 +WHERE a >= '2004-07-01' AND a <= '2004-09-30'; +a +2004-07-13 +2004-07-20 +2004-07-30 +2004-08-13 +2004-08-20 +2004-08-30 +2004-09-13 +2004-09-20 +2004-09-30 +EXPLAIN PARTITIONS SELECT * FROM t1 +WHERE a >= '2004-07-01' AND a <= '2004-09-30'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p407,p408,p409 ALL NULL NULL NULL NULL 9 Using where +SELECT * from t1 +WHERE (a >= '2004-07-01' AND a <= '2004-09-30') OR +(a >= '2005-07-01' AND a <= '2005-09-30'); +a +2004-07-13 +2004-07-20 +2004-07-30 +2004-08-13 +2004-08-20 +2004-08-30 +2004-09-13 +2004-09-20 +2004-09-30 +2005-07-13 +2005-07-20 +2005-07-30 +2005-08-13 +2005-08-20 +2005-08-30 +2005-09-13 +2005-09-20 +2005-09-30 +EXPLAIN PARTITIONS SELECT * from t1 +WHERE (a >= '2004-07-01' AND a <= '2004-09-30') OR +(a >= '2005-07-01' AND a <= '2005-09-30'); +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p407,p408,p409,p507,p508,p509 ALL NULL NULL NULL NULL 18 Using where +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/pbxt_assertions.result b/mysql-test/suite/pbxt/r/pbxt_assertions.result new file mode 100644 index 00000000000..e34b83c68e7 --- /dev/null +++ b/mysql-test/suite/pbxt/r/pbxt_assertions.result @@ -0,0 +1,14 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 VARCHAR(255), c2 VARCHAR(255), c3 INT); +INSERT INTO t1 VALUES (REPEAT('x', 255), REPEAT('y', 255), 1); +INSERT INTO t1 VALUES (REPEAT('x', 255), REPEAT('y', 255), 2); +INSERT INTO t1 VALUES (REPEAT('x', 255), REPEAT('y', 255), 3); +SELECT COUNT(*) FROM t1; +COUNT(*) +3 +drop table if exists t1; +create table t1 (a int, unique index indexa (a)); +insert into t1 values (-1), (-4), (-2), (NULL); +select -10 IN (select a from t1 FORCE INDEX (indexa)); +-10 IN (select a from t1 FORCE INDEX (indexa)) +NULL diff --git a/mysql-test/suite/pbxt/r/pbxt_bugs.result b/mysql-test/suite/pbxt/r/pbxt_bugs.result new file mode 100644 index 00000000000..6ebb8459c75 --- /dev/null +++ b/mysql-test/suite/pbxt/r/pbxt_bugs.result @@ -0,0 +1,1220 @@ +drop table if exists t1,t2,t3; +create table t1 (id int auto_increment key) engine=pbxt auto_increment=200; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=PBXT AUTO_INCREMENT=200 DEFAULT CHARSET=latin1 +alter table t1 add column text char(40); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `text` char(40) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=PBXT AUTO_INCREMENT=200 DEFAULT CHARSET=latin1 +alter table t1 auto_increment = 100; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `text` char(40) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=PBXT AUTO_INCREMENT=100 DEFAULT CHARSET=latin1 +drop table if exists t1; +create table t1 ( +id int, +c_char char(3), +c_varchar varchar(3), +c_char_bin char(3) binary, +c_varchar_bin varchar(3) binary, +c_char_uni char(3) unicode, +c_varchar_uni varchar(3) unicode, +c_dec decimal(3), +index(c_char), +index(c_varchar), +index(c_char_bin), +index(c_varchar_bin), +index(c_char_uni), +index(c_varchar_uni), +index(c_dec) +) engine=pbxt; +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", 12); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", 123); +select c_char from t1 where c_char = "ab"; +c_char +ab +ab +select c_varchar from t1 where c_varchar = "ab"; +c_varchar +ab +ab +select c_char_bin from t1 where c_char_bin = "ab"; +c_char_bin +ab +ab +select c_varchar_bin from t1 where c_varchar_bin = "ab"; +c_varchar_bin +ab +ab +select c_char_uni from t1 where c_char_uni = "ab"; +c_char_uni +ab +ab +select c_varchar_uni from t1 where c_varchar_uni = "ab"; +c_varchar_uni +ab +ab +select c_dec from t1 where c_dec = 12; +c_dec +12 +select * from t1 where c_char = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_char_bin = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar_bin = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_char_uni = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar_uni = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_dec = 123; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +2 ab ab ab ab ab ab 123 +drop table if exists t1; +create table t1 ( +id int, +c_char char(100), +c_varchar varchar(100), +c_char_bin char(100) binary, +c_varchar_bin varchar(100) binary, +c_char_uni char(100) unicode, +c_varchar_uni varchar(100) unicode, +c_dec decimal(65), +index(c_char), +index(c_varchar), +index(c_char_bin), +index(c_varchar_bin), +index(c_char_uni), +index(c_varchar_uni), +index(c_dec) +) engine=pbxt; +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", 12); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", 123); +select * from t1 where c_char = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_char_bin = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar_bin = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_char_uni = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar_uni = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_dec = 12; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +select c_char from t1 where c_char = "ab "; +c_char +ab +ab +select c_varchar from t1 where c_varchar = "ab "; +c_varchar +ab +ab +select c_char_bin from t1 where c_char_bin = "ab "; +c_char_bin +ab +ab +select c_varchar_bin from t1 where c_varchar_bin = "ab "; +c_varchar_bin +ab +ab +select c_char_uni from t1 where c_char_uni = "ab "; +c_char_uni +ab +ab +select c_varchar_uni from t1 where c_varchar_uni = "ab "; +c_varchar_uni +ab +ab +select c_dec from t1 where c_dec = 123; +c_dec +123 +drop table if exists t1; +create table t1 ( +id int, +c_varchar varchar(300), +c_varchar_bin varchar(300) binary, +c_varchar_uni varchar(300) unicode, +c_ttext TINYTEXT, +c_text TEXT, +c_mtext MEDIUMTEXT, +c_ltext LONGTEXT, +index(c_varchar), +index(c_varchar_bin), +index(c_varchar_uni), +index(c_ttext(100)), +index(c_text(100)), +index(c_mtext(100)), +index(c_ltext(100)) +) engine=pbxt; +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", "ab"); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", "ab "); +select c_varchar from t1 where c_varchar = "ab"; +c_varchar +ab +ab +select c_varchar_bin from t1 where c_varchar_bin = "ab"; +c_varchar_bin +ab +ab +select c_varchar_uni from t1 where c_varchar_uni = "ab"; +c_varchar_uni +ab +ab +select c_ttext from t1 where c_ttext = "ab"; +c_ttext +ab +ab +select c_text from t1 where c_text = "ab"; +c_text +ab +ab +select c_mtext from t1 where c_mtext = "ab"; +c_mtext +ab +ab +select c_ltext from t1 where c_ltext = "ab"; +c_ltext +ab +ab +select * from t1 where c_varchar = "ab "; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_varchar_bin = "ab "; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_varchar_uni = "ab "; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_ttext = "ab "; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_text = "ab "; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_mtext = "ab "; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_ltext = "ab "; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +drop table if exists t1; +create table t1 ( +id int not null, +c_char char(3) not null, +c_varchar varchar(3) not null, +c_char_bin char(3) binary not null, +c_varchar_bin varchar(3) binary not null, +c_char_uni char(3) unicode not null, +c_varchar_uni varchar(3) unicode not null, +c_dec decimal(3) not null, +index(c_char), +index(c_varchar), +index(c_char_bin), +index(c_varchar_bin), +index(c_char_uni), +index(c_varchar_uni), +index(c_dec) +) engine=pbxt; +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", 12); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", 123); +select * from t1 where c_char = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_char_bin = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar_bin = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_char_uni = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar_uni = "ab"; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_dec = 12; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +select c_char from t1 where c_char = "ab "; +c_char +ab +ab +select c_varchar from t1 where c_varchar = "ab "; +c_varchar +ab +ab +select c_char_bin from t1 where c_char_bin = "ab "; +c_char_bin +ab +ab +select c_varchar_bin from t1 where c_varchar_bin = "ab "; +c_varchar_bin +ab +ab +select c_char_uni from t1 where c_char_uni = "ab "; +c_char_uni +ab +ab +select c_varchar_uni from t1 where c_varchar_uni = "ab "; +c_varchar_uni +ab +ab +select c_dec from t1 where c_dec = 123; +c_dec +123 +drop table if exists t1; +create table t1 ( +id int not null, +c_char char(100) not null, +c_varchar varchar(100) not null, +c_char_bin char(100) binary not null, +c_varchar_bin varchar(100) binary not null, +c_char_uni char(100) unicode not null, +c_varchar_uni varchar(100) unicode not null, +c_dec decimal(65), +index(c_char), +index(c_varchar), +index(c_char_bin), +index(c_varchar_bin), +index(c_char_uni), +index(c_varchar_uni), +index(c_dec) +) engine=pbxt; +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", 12); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", 123); +select c_char from t1 where c_char = "ab"; +c_char +ab +ab +select c_varchar from t1 where c_varchar = "ab"; +c_varchar +ab +ab +select c_char_bin from t1 where c_char_bin = "ab"; +c_char_bin +ab +ab +select c_varchar_bin from t1 where c_varchar_bin = "ab"; +c_varchar_bin +ab +ab +select c_char_uni from t1 where c_char_uni = "ab"; +c_char_uni +ab +ab +select c_varchar_uni from t1 where c_varchar_uni = "ab"; +c_varchar_uni +ab +ab +select c_dec from t1 where c_dec = 12; +c_dec +12 +select * from t1 where c_char = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_char_bin = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar_bin = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_char_uni = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_varchar_uni = "ab "; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +1 ab ab ab ab ab ab 12 +2 ab ab ab ab ab ab 123 +select * from t1 where c_dec = 123; +id c_char c_varchar c_char_bin c_varchar_bin c_char_uni c_varchar_uni c_dec +2 ab ab ab ab ab ab 123 +drop table if exists t1; +create table t1 ( +id int, +c_varchar varchar(300) not null, +c_varchar_bin varchar(300) binary not null, +c_varchar_uni varchar(300) unicode not null, +c_ttext TINYTEXT not null, +c_text TEXT not null, +c_mtext MEDIUMTEXT not null, +c_ltext LONGTEXT not null, +index(c_varchar), +index(c_varchar_bin), +index(c_varchar_uni), +index(c_ttext(100)), +index(c_text(100)), +index(c_mtext(100)), +index(c_ltext(100)) +) engine=pbxt; +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", "ab"); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", "ab "); +select * from t1 where c_varchar = "ab"; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_varchar_bin = "ab"; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_varchar_uni = "ab"; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_ttext = "ab"; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_text = "ab"; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_mtext = "ab"; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select * from t1 where c_ltext = "ab"; +id c_varchar c_varchar_bin c_varchar_uni c_ttext c_text c_mtext c_ltext +1 ab ab ab ab ab ab ab +2 ab ab ab ab ab ab ab +select c_varchar from t1 where c_varchar = "ab "; +c_varchar +ab +ab +select c_varchar_bin from t1 where c_varchar_bin = "ab "; +c_varchar_bin +ab +ab +select c_varchar_uni from t1 where c_varchar_uni = "ab "; +c_varchar_uni +ab +ab +select c_ttext from t1 where c_ttext = "ab "; +c_ttext +ab +ab +select c_text from t1 where c_text = "ab "; +c_text +ab +ab +select c_mtext from t1 where c_mtext = "ab "; +c_mtext +ab +ab +select c_ltext from t1 where c_ltext = "ab "; +c_ltext +ab +ab +drop table if exists t1; +create table t1 ( +id int, +c_char_suni char(4) unicode, +c_varchar_suni varchar(4) unicode, +c_char_uni char(255) unicode, +c_varchar_uni varchar(300) unicode, +index(c_char_suni), +index(c_varchar_suni), +index(c_char_uni), +index(c_varchar_uni) +) engine=pbxt; +insert t1 values (1, "ab", "ab", "ab", "ab"); +insert t1 values (1, "abcd", "abcd", "abcd", "abcd"); +insert t1 values (1, "ab ", "ab ", "abcd123123123123123123123123123123123123", "abcd123123123123123123123123123123123123"); +select * from t1 where c_char_suni = "ab"; +id c_char_suni c_varchar_suni c_char_uni c_varchar_uni +1 ab ab ab ab +1 ab ab abcd123123123123123123123123123123123123 abcd123123123123123123123123123123123123 +select * from t1 where c_varchar_suni = "ab"; +id c_char_suni c_varchar_suni c_char_uni c_varchar_uni +1 ab ab ab ab +1 ab ab abcd123123123123123123123123123123123123 abcd123123123123123123123123123123123123 +select * from t1 where c_char_uni = "ab"; +id c_char_suni c_varchar_suni c_char_uni c_varchar_uni +1 ab ab ab ab +select * from t1 where c_varchar_uni = "ab"; +id c_char_suni c_varchar_suni c_char_uni c_varchar_uni +1 ab ab ab ab +drop table if exists t1; +create table t1 (id int, name char(10) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +ERROR 23000: Duplicate entry 'ab' for key 'PRIMARY' +drop table if exists t1; +create table t1 (id int, name char(100) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +ERROR 23000: Duplicate entry 'ab' for key 'PRIMARY' +drop table if exists t1; +create table t1 (id int, name varchar(10) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +ERROR 23000: Duplicate entry 'ab ' for key 'PRIMARY' +drop table if exists t1; +create table t1 (id int, name varchar(100) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +ERROR 23000: Duplicate entry 'ab ' for key 'PRIMARY' +drop table if exists t1; +create table t1 (id int, name varchar(400) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +ERROR 23000: Duplicate entry 'ab ' for key 'PRIMARY' +drop table if exists t1; +create table t1 (id int, name char(10) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +ERROR 23000: Duplicate entry 'ab' for key 'PRIMARY' +drop table if exists t1; +create table t1 (id int, name char(100) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +ERROR 23000: Duplicate entry 'ab' for key 'PRIMARY' +drop table if exists t1; +create table t1 (id int, name varchar(10), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +id name +1 ab +2 ab +3 ab +insert t1 values (4, "ab "); +drop table if exists t1; +create table t1 (id int, name varchar(100), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +id name +1 ab +2 ab +3 ab +insert t1 values (4, "ab "); +drop table if exists t1; +create table t1 (id int, name varchar(400), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +id name +1 ab +2 ab +3 ab +insert t1 values (4, "ab "); +drop table if exists t1; +create table t1 (id int, name char(10), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +id name +1 ab +2 ab +3 ab +insert t1 values (4, "ab "); +drop table if exists t1; +create table t1 (id int, name char(100), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +id name +1 ab +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +id name +1 ab +2 ab +3 ab +insert t1 values (4, "ab "); +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( id int, name varchar(300)) engine=pbxt; +begin; +insert t1(id, name) values(1, "aaa"); +update t1 set name=REPEAT('A', 300) where id = 1; +commit; +flush tables; +select * from t1; +id name +1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( id int, name varchar(300)) engine=pbxt; +begin; +insert t1(id, name) values(1, REPEAT('A', 300)); +update t1 set name="aaa" where id = 1; +commit; +flush tables; +select * from t1; +id name +1 aaa +drop table if exists t1, t2; +create table t1 (s1 int primary key) engine = pbxt; +insert into t1 values (1); +create table t2 (s1 int, foreign key (s1) references t1 (s1)) engine = pbxt; +insert into t2 values (1); +truncate table t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (Constraint: `FOREIGN_1`) +alter table t1 engine myisam; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` int(11) NOT NULL, + PRIMARY KEY (`s1`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table if exists t1, t2; +create table t1 (s1 int primary key, s2 int unique not null) engine = pbxt; +create table t2 (s1 int, foreign key (s1) references t1 (s1)) engine = pbxt; +select * from information_schema.table_constraints +where constraint_type = 'FOREIGN KEY' and table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +NULL test FOREIGN_1 test t2 FOREIGN KEY +select * from information_schema.referential_constraints where table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME +NULL test FOREIGN_1 NULL test PRIMARY NONE RESTRICT RESTRICT t2 t1 +drop table t2, t1; +create table t1 (s1 int, s2 int, unique key ix1 (s1, s2)) engine = pbxt; +create table t2 (s1 int, s2 int, foreign key (s1, s2) references t1 (s1, s2)) engine = pbxt; +select * from information_schema.table_constraints +where constraint_type = 'FOREIGN KEY' and table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +NULL test FOREIGN_1 test t2 FOREIGN KEY +select * from information_schema.referential_constraints where table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME +NULL test FOREIGN_1 NULL test ix1 NONE RESTRICT RESTRICT t2 t1 +drop table t2, t1; +create table t1 (s1 int, s2 int, unique key ix1 (s1, s2), unique key ix2 (s1, s2)) engine = pbxt; +create table t2 (s1 int, s2 int, foreign key (s1, s2) references t1 (s1, s2)) engine = pbxt; +select * from information_schema.table_constraints +where constraint_type = 'FOREIGN KEY' and table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +NULL test FOREIGN_1 test t2 FOREIGN KEY +select * from information_schema.referential_constraints where table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME +NULL test FOREIGN_1 NULL test ix1 NONE RESTRICT RESTRICT t2 t1 +drop table t2, t1; +create table t1 (s1 int, s2 int, unique key ix1 (s1, s2)) engine = pbxt; +create table t2 (s1 int, s2 int, +foreign key (s1, s2) references t1 (s1, s2) on delete cascade on update set null) engine = pbxt; +select * from information_schema.table_constraints +where constraint_type = 'FOREIGN KEY' and table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +NULL test FOREIGN_1 test t2 FOREIGN KEY +select * from information_schema.referential_constraints where table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME +NULL test FOREIGN_1 NULL test ix1 NONE SET NULL CASCADE t2 t1 +drop table t2, t1; +create table t2 (s1 int, s2 int, s3 int, s4 int, unique key ix34 (s3, s4), +foreign key (s1, s2) references t2 (s3, s4)) engine = pbxt; +select * from information_schema.table_constraints +where constraint_type = 'FOREIGN KEY' and table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +NULL test FOREIGN_1 test t2 FOREIGN KEY +select * from information_schema.referential_constraints where table_name = 't2'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME +NULL test FOREIGN_1 NULL test ix34 NONE RESTRICT RESTRICT t2 t2 +drop table t2; +create table t1 (s1 int, s2 int, unique key ix1 (s1, s2)) engine = pbxt; +create table t2 (s1 int, s2 int, +foreign key (s1, s2) references t1 (s1, s2)) engine = pbxt; +alter table t1 add constraint s2 foreign key (s1, s2) references t2 (s1, s2); +select * from information_schema.table_constraints +where constraint_type = 'FOREIGN KEY' and (table_name = 't1' or table_name = 't2'); +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +NULL test s2 test t1 FOREIGN KEY +NULL test FOREIGN_1 test t2 FOREIGN KEY +select * from information_schema.referential_constraints where (table_name = 't1' or table_name = 't2'); +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME +NULL test s2 NULL test s1 NONE RESTRICT RESTRICT t1 t2 +NULL test FOREIGN_1 NULL test ix1 NONE RESTRICT RESTRICT t2 t1 +set foreign_key_checks = 0; +drop table t2, t1; +set foreign_key_checks = 1; +create table t1 (id int primary key, s1 int, foreign key (s1) references t1 (id)) engine = pbxt; +select * from information_schema.table_constraints +where constraint_type = 'FOREIGN KEY' and table_name = 't1'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +NULL test FOREIGN_1 test t1 FOREIGN KEY +select * from information_schema.referential_constraints where table_name = 't1'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME +NULL test FOREIGN_1 NULL test PRIMARY NONE RESTRICT RESTRICT t1 t1 +drop table t1; +drop table if exists t2,t1; +create table t1 (s1 int primary key) engine = pbxt; +create table t2 (s1 int primary key, foreign key (s1) references t1 (s1) on update cascade) engine = pbxt; +set @@autocommit = 0; +insert into t1 values (1); +insert into t2 values (1); +update t1 set s1 = 2; +set @@autocommit = 1; +select * from t1, t2; +s1 s1 +2 2 +drop table t2, t1; +create table t1 (s1 int primary key, s2 int, key (s1, s2)) engine = pbxt; +create table t2 (s1 int primary key, s2 int, key (s1, s2), foreign key (s1) references t1 (s1) on update cascade) engine = pbxt; +set @@autocommit = 0; +insert into t1 values (1, 5); +insert into t2 values (1, 6); +update t1 set s1 = 2; +set @@autocommit = 1; +select * from t1, t2; +s1 s2 s1 s2 +2 5 2 6 +drop table t2, t1; +set @@autocommit = 1; +SET foreign_key_checks = 0; +DROP TABLE IF EXISTS t15,t14,t13,t12,t11,t10,t9,t8,t7,t6,t5,t4,t3,t2,t1; +SET foreign_key_checks = 1; +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 INT) engine = pbxt; +CREATE TABLE t2 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t3 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t2 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t4 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t3 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t5 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t4 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t6 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t5 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t7 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t6 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t8 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t7 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t9 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t8 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t10(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t9 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t11(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t10(s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t12(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t11(s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t13(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t12(s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t14(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t13(s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t15(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t14(s1) ON UPDATE CASCADE) engine = pbxt; +ALTER TABLE t1 ADD FOREIGN KEY (s2) REFERENCES t15(s1) ON UPDATE CASCADE; +SET foreign_key_checks = 0; +INSERT INTO t1 VALUES (1,NULL); +INSERT INTO t2 VALUES (1); +INSERT INTO t3 VALUES (1); +INSERT INTO t4 VALUES (1); +INSERT INTO t5 VALUES (1); +INSERT INTO t6 VALUES (1); +INSERT INTO t7 VALUES (1); +INSERT INTO t8 VALUES (1); +INSERT INTO t9 VALUES (1); +INSERT INTO t10 VALUES (1); +INSERT INTO t11 VALUES (1); +INSERT INTO t12 VALUES (1); +INSERT INTO t13 VALUES (1); +INSERT INTO t14 VALUES (1); +INSERT INTO t15 VALUES (1); +SET foreign_key_checks = 1; +UPDATE t1 SET s1 = 2; +select * from t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15; +s1 s2 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 +2 NULL 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +UPDATE t1 SET s2 = 2; +select * from t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15; +s1 s2 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +UPDATE t1 SET s1 = 3; +select * from t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15; +s1 s2 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 s1 +3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 +SET foreign_key_checks = 0; +DROP TABLE IF EXISTS t15,t14,t13,t12,t11,t10,t9,t8,t7,t6,t5,t4,t3,t2,t1; +SET foreign_key_checks = 1; +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 ENUM('A','B'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +DROP TABLE t2,t1; +CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 ENUM('A','B', 'C'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +ERROR HY000: Can't create table 'test.t2' (errno: 151) +DROP TABLE t1; +CREATE TABLE t1 (s1 ENUM('a','b','c') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 ENUM('d','e','f'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +DROP TABLE t2,t1; +CREATE TABLE t1 (s1 SET('a','b') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 SET('A','B'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +DROP TABLE t2,t1; +CREATE TABLE t1 (s1 SET('a','b') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 SET('A','B', 'C'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +ERROR HY000: Can't create table 'test.t2' (errno: 151) +DROP TABLE t1; +CREATE TABLE t1 (s1 SET('a','b','c') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 SET('d','e','f'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +DROP TABLE t2,t1; +CREATE TABLE t1 (s1 SET('a','b') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 ENUM('a','b'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +ERROR HY000: Can't create table 'test.t2' (errno: 151) +DROP TABLE t1; +CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 SET('a','b'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +ERROR HY000: Can't create table 'test.t2' (errno: 151) +DROP TABLE t1; +DROP TABLE IF EXISTS t2, t1; +Warnings: +Note 1051 Unknown table 't2' +Note 1051 Unknown table 't1' +CREATE TABLE t1 (s1 VARCHAR(50) PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 VARCHAR(50), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; +INSERT INTO t1 VALUES ('A'); +INSERT INTO t2 VALUES ('A '); +UPDATE t1 SET s1 = 'A '; +DELETE FROM t2; +DELETE FROM t1; +INSERT INTO t1 VALUES ('A'); +INSERT INTO t2 VALUES ('A'); +UPDATE t1 SET s1 = 'A '; +UPDATE t2 SET s1 = 'A '; +UPDATE t1 SET s1 = 'a'; +UPDATE t2 SET s1 = 'a'; +DROP TABLE t2, t1; +DROP TABLE IF EXISTS t2,t1; +Warnings: +Note 1051 Unknown table 't2' +Note 1051 Unknown table 't1' +CREATE TABLE t1 (s1 INT PRIMARY KEY); +CREATE TABLE t2 (s1 INT DEFAULT 2, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +SELECT * FROM t2; +s1 +2 +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 DATE NOT NULL UNIQUE); +CREATE TABLE t2 (s1 DATE DEFAULT '2000-01-01', FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE SET DEFAULT); +INSERT INTO t1 VALUES ('2001-01-01'); +INSERT INTO t2 VALUES ('2001-01-01'); +UPDATE t1 SET s1 = '2001-01-02'; +SELECT * FROM t2; +s1 +2000-01-01 +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 INT PRIMARY KEY); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +SELECT * FROM t2; +s1 +NULL +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 VARCHAR(45) primary key); +CREATE TABLE t2 (s1 VARCHAR(45) DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +SELECT * FROM t2; +s1 +NULL +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 VARCHAR(45), INDEX (s1(10))); +CREATE TABLE t2 (s1 VARCHAR(45) DEFAULT "12345678901", FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +SELECT * FROM t2; +s1 +12345678901 +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 INT); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +ERROR HY000: Got temporary error -1 'Matching index required for '`t1` (s1)'' from PBXT +DROP TABLE IF EXISTS t3,t2,t1; +CREATE TABLE t1 (s1 INT primary key); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET NULL); +CREATE TABLE t3 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t2 (s1) ON DELETE SET NULL); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +INSERT INTO t3 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (Constraint: `FOREIGN_1`) +SELECT * FROM t1; +s1 +1 +2 +SELECT * FROM t2; +s1 +1 +SELECT * FROM t3; +s1 +1 +DROP TABLE IF EXISTS t3,t2,t1; +CREATE TABLE t1 (s1 INT primary key); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +CREATE TABLE t3 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t2 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +INSERT INTO t3 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (Constraint: `FOREIGN_1`) +SELECT * FROM t1; +s1 +1 +2 +SELECT * FROM t2; +s1 +1 +SELECT * FROM t3; +s1 +1 +DROP TABLE IF EXISTS t3,t2,t1; +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 char(1)); +CREATE TABLE t2 (s1 INT, s2 INT PRIMARY KEY, +FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE CASCADE); +INSERT INTO t1 VALUES (1,'a'); +INSERT INTO t2 VALUES (1,1); +REPLACE INTO t1 VALUES (1,'b'); +SELECT COUNT(*) FROM t2; +COUNT(*) +0 +set foreign_key_checks = 0; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 char(1)); +set foreign_key_checks = 1; +INSERT INTO t1 VALUES (1,'a'); +REPLACE INTO t1 VALUES (1,'b'); +DROP TABLE IF EXISTS t3,t2,t1; +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 INT); +CREATE TABLE t2 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE CASCADE); +CREATE TABLE t3 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t2 (s1) ON UPDATE CASCADE); +DROP TABLE IF EXISTS t3,t2,t1; +CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY); +CREATE TABLE t2 (s1 ENUM('A','B','C'), FOREIGN KEY (s1) REFERENCES t1 (s1)); +ERROR HY000: Can't create table 'test.t2' (errno: 151) +DROP TABLE IF EXISTS t2,t1; +Warnings: +Note 1051 Unknown table 't2' +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 INT); +CREATE TABLE t2 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE CASCADE); +DROP TABLE IF EXISTS t2,t1; +create table t1 (s1 varchar(40) primary key); +create table t2 (s1 VARCHAR(30), foreign key (s1) references t1 (s1)); +insert into t1 values ("1"); +insert into t2 values ("1"); +DROP TABLE IF EXISTS t2,t1; +DROP TABLE IF EXISTS t5; +CREATE TABLE t5 ( +c1 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, +c2 BIGINT SIGNED NULL, +c3 BIGINT SIGNED NOT NULL, +c4 TINYINT, c5 SMALLINT, +c6 MEDIUMINT, +c7 INT, +c8 INTEGER, +PRIMARY KEY(c1,c2), UNIQUE INDEX(c3)); +INSERT INTO t5 VALUES +(0,-9223372036854775808,1,2,3,4,5,5), +(255,-2147483648,6,7,8,9,10,10), +(65535,-8388608,11,12,13,14,15,15), +(16777215,-32768,16,17,18,19,20,20), +(4294967295,-128,21,22,23,24,25,25), +(18446744073709551615,9223372036854775807,26,27,28,29,30,30); +INSERT INTO t5(c2,c3) VALUES(33,34) /* tries to increment out of range */; +ERROR HY000: Failed to read auto-increment value from storage engine +INSERT INTO t5(c2,c3) VALUES(33,34); +ERROR HY000: Failed to read auto-increment value from storage engine +SELECT * FROM t5; +c1 c2 c3 c4 c5 c6 c7 c8 +1 -9223372036854775808 1 2 3 4 5 5 +255 -2147483648 6 7 8 9 10 10 +65535 -8388608 11 12 13 14 15 15 +16777215 -32768 16 17 18 19 20 20 +4294967295 -128 21 22 23 24 25 25 +18446744073709551615 9223372036854775807 26 27 28 29 30 30 +DROP TABLE t5; +/* same test as above with signed bigint */ +CREATE TABLE t5 ( +c1 BIGINT SIGNED NOT NULL AUTO_INCREMENT, +c2 BIGINT SIGNED NULL, +c3 BIGINT SIGNED NOT NULL, +c4 TINYINT, c5 SMALLINT, +c6 MEDIUMINT, +c7 INT, +c8 INTEGER, +PRIMARY KEY(c1,c2), UNIQUE INDEX(c3)); +INSERT INTO t5 VALUES +(0,-9223372036854775808,1,2,3,4,5,5), +(255,-2147483648,6,7,8,9,10,10), +(65535,-8388608,11,12,13,14,15,15), +(16777215,-32768,16,17,18,19,20,20), +(4294967295,-128,21,22,23,24,25,25), +(9223372036854775807,9223372036854775807,26,27,28,29,30,30); +INSERT INTO t5(c2,c3) VALUES(33,34) /* tries to increment out of range */; +ERROR HY000: Failed to read auto-increment value from storage engine +INSERT INTO t5(c2,c3) VALUES(33,34); +ERROR HY000: Failed to read auto-increment value from storage engine +SELECT * FROM t5; +c1 c2 c3 c4 c5 c6 c7 c8 +1 -9223372036854775808 1 2 3 4 5 5 +255 -2147483648 6 7 8 9 10 10 +65535 -8388608 11 12 13 14 15 15 +16777215 -32768 16 17 18 19 20 20 +4294967295 -128 21 22 23 24 25 25 +9223372036854775807 9223372036854775807 26 27 28 29 30 30 +CREATE TABLE t2(c1 INT SIGNED NOT NULL, c2 INT UNSIGNED NULL, c3 INT, KEY(c1), KEY(c2)); +INSERT INTO t2 VALUES(-1,1,1),(-2,2,2),(-3,3,3),(-4,4,4),(-5,5,5),(-6,6,6),(-7,7,7),(-8,8,8),(-9,9,9),(10,10,10),(-11,NULL,11),(-12,12,12); +INSERT INTO t2 VALUES(-2147483648,0,13),(2147483647,4294967295,14),(0,2147483648,15),(2147483647,2147483647,16); +SELECT * FROM t2; +c1 c2 c3 +-1 1 1 +-11 NULL 11 +-12 12 12 +-2 2 2 +-2147483648 0 13 +-3 3 3 +-4 4 4 +-5 5 5 +-6 6 6 +-7 7 7 +-8 8 8 +-9 9 9 +0 2147483648 15 +10 10 10 +2147483647 2147483647 16 +2147483647 4294967295 14 +EXPLAIN SELECT c1 FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL c1 4 NULL 16 Using index +SELECT c1 FROM t2; +c1 +-1 +-11 +-12 +-2 +-2147483648 +-3 +-4 +-5 +-6 +-7 +-8 +-9 +0 +10 +2147483647 +2147483647 +UPDATE t2 SET c1=-2147483648 WHERE c2 <> 0 ORDER BY c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 <> 0 ORDER BY c2; +c1 c2 c3 +-12 12 12 +-2147483648 1 1 +-2147483648 2 2 +-3 3 3 +-4 4 4 +-5 5 5 +-6 6 6 +-7 7 7 +-8 8 8 +-9 9 9 +0 2147483648 15 +10 10 10 +2147483647 2147483647 16 +2147483647 4294967295 14 +UPDATE t2 SET c1=-2147483648 WHERE c2 >= 0 ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 >= 0 ORDER BY c2 DESC; +c1 c2 c3 +-12 12 12 +-2147483648 0 13 +-2147483648 1 1 +-2147483648 2 2 +-2147483648 2147483648 15 +-2147483648 4294967295 14 +-3 3 3 +-4 4 4 +-5 5 5 +-6 6 6 +-7 7 7 +-8 8 8 +-9 9 9 +10 10 10 +2147483647 2147483647 16 +UPDATE t2 SET c1=-2147483648 WHERE c2 <= 3 ORDER BY c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 <= 3 ORDER BY c2; +c1 c2 c3 +-2147483648 0 13 +-2147483648 1 1 +-2147483648 2 2 +-3 3 3 +UPDATE t2 SET c1=-2147483648 WHERE c2 <=> 4 ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 <=> 4 ORDER BY c2; +c1 c2 c3 +-2147483648 4 4 +UPDATE t2 SET c1=-2147483648 WHERE c2 BETWEEN 4 AND 7 ORDER BY c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 BETWEEN 4 AND 7 ORDER BY c2; +c1 c2 c3 +-2147483648 4 4 +-2147483648 5 5 +-6 6 6 +-7 7 7 +UPDATE t2 SET c1=-2147483648 WHERE c2 IN(8,9) ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 IN(8,9) ORDER BY c2 DESC; +c1 c2 c3 +-2147483648 8 8 +-2147483648 9 9 +UPDATE t2 SET c1=-2147483648 WHERE c2 IS NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c2; +c1 c2 c3 +-2147483648 NULL 11 +UPDATE t2 SET c1=-2147483648 WHERE c2>= 6 AND c2 < 9 ORDER BY c2 LIMIT 2; +SELECT * FROM t2 WHERE c2>= 6 AND c2 < 9 ORDER BY c2; +c1 c2 c3 +-2147483648 6 6 +-2147483648 7 7 +-2147483648 8 8 +UPDATE t2 SET c1=-2147483648 WHERE c1=-12 OR c2=1; +SELECT * FROM t2 WHERE c1=-2147483648; +c1 c2 c3 +-2147483648 0 13 +-2147483648 1 1 +-2147483648 12 12 +-2147483648 2 2 +-2147483648 2147483648 15 +-2147483648 4 4 +-2147483648 4294967295 14 +-2147483648 5 5 +-2147483648 6 6 +-2147483648 7 7 +-2147483648 8 8 +-2147483648 9 9 +-2147483648 NULL 11 +SELECT * FROM t2; +c1 c2 c3 +-2147483648 0 13 +-2147483648 1 1 +-2147483648 12 12 +-2147483648 2 2 +-2147483648 2147483648 15 +-2147483648 4 4 +-2147483648 4294967295 14 +-2147483648 5 5 +-2147483648 6 6 +-2147483648 7 7 +-2147483648 8 8 +-2147483648 9 9 +-2147483648 NULL 11 +-3 3 3 +10 10 10 +2147483647 2147483647 16 +EXPLAIN SELECT c1 FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL c1 4 NULL 16 Using index +SELECT c1 FROM t2; +c1 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-2147483648 +-3 +10 +2147483647 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INTEGER NOT NULL PRIMARY KEY, c2 VARCHAR(255)); +LOAD DATA LOCAL INFILE 'suite/pbxt/t/load_unique_error1.inc' REPLACE INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (@c1,c2) SET c1 = @c1 % 2; +SELECT * FROM t1 ORDER BY c1; +c1 c2 +0 opq +1 jkl +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/pbxt_locking.result b/mysql-test/suite/pbxt/r/pbxt_locking.result new file mode 100644 index 00000000000..5da337c62d1 --- /dev/null +++ b/mysql-test/suite/pbxt/r/pbxt_locking.result @@ -0,0 +1,88 @@ +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (id int, index (id)) engine = pbxt; +insert into t1 values (1), (2), (3), (4), (5); +begin; +select * from t1 where id < 5 for update; +id +1 +2 +3 +4 +update t1 set id = 8 where id = 5; +update t1 set id = 8 where id = 4; +show processlist; +Id User Host db Command Time State Info +x root x test Query x NULL show processlist +x root x test Query x Searching rows for update update t1 set id = 8 where id = 4 +commit; +select * from t1; +id +1 +2 +3 +8 +8 +drop table if exists t1; +create table t1 (id int) engine = pbxt; +insert into t1 values (1), (2), (3), (4), (5); +begin; +select * from t1 where id > 10 for update; +id +update t1 set id = 8; +commit; +select * from t1; +id +8 +8 +8 +8 +8 +drop table if exists t1; +create table t1 (id int, index (id)) engine = pbxt; +insert into t1 values (1), (2), (3), (4), (5); +begin; +select * from t1 where id = 5 for update; +id +5 +update t1 set id = 8 where id < 4; +update t1 set id = 8 where id = 5; +show processlist; +Id User Host db Command Time State Info +x root x test Query x NULL show processlist +x root x test Query x Searching rows for update update t1 set id = 8 where id = 5 +commit; +select * from t1; +id +4 +8 +8 +8 +8 +drop table if exists t1; +create table t1 (id int, index (id)) engine = pbxt; +insert into t1 values (1), (2), (3), (4), (5); +select * from t1 for update; +id +1 +2 +3 +4 +5 +update t1 set id = 8; +drop table if exists t1; +create table t1 (id int, index (id)) engine = pbxt; +insert into t1 values (1), (2), (3), (4), (5); +create procedure p1 () +begin +select * from t1 for update; +end| +call p1 (); +id +1 +2 +3 +4 +5 +update t1 set id = 8; diff --git a/mysql-test/suite/pbxt/r/pbxt_my_fail2.result b/mysql-test/suite/pbxt/r/pbxt_my_fail2.result new file mode 100644 index 00000000000..75b3073c2cb --- /dev/null +++ b/mysql-test/suite/pbxt/r/pbxt_my_fail2.result @@ -0,0 +1,46 @@ +drop table if exists t4| +create table t4 ( +a mediumint(8) unsigned not null auto_increment, +b smallint(5) unsigned not null, +c char(32) not null, +primary key (a) +) engine=myisam default charset=latin1| +insert into t4 values (1, 2, 'oneword')| +insert into t4 values (2, 2, 'anotherword')| +drop table if exists t3| +create table t3 ( x int unique ) engine=pbxt| +create procedure bug7049_1() +begin +insert into t3 values (42); +insert into t3 values (42); +end| +create procedure bug7049_2() +begin +declare exit handler for sqlexception +select 'Caught it' as 'Result'; +call bug7049_1(); +select 'Missed it' as 'Result'; +end| +create function bug7049_1() +returns int +begin +insert into t3 values (42); +insert into t3 values (42); +return 42; +end| +create function bug7049_2() +returns int +begin +declare x int default 0; +declare continue handler for sqlexception +set x = 1; +set x = bug7049_1(); +return x; +end| +call bug7049_2()| +Result +Caught it +drop procedure bug7049_1| +drop function bug7049_1| +drop procedure bug7049_2| +drop function bug7049_2| diff --git a/mysql-test/suite/pbxt/r/pbxt_ref_int.result b/mysql-test/suite/pbxt/r/pbxt_ref_int.result new file mode 100644 index 00000000000..cd86d122452 --- /dev/null +++ b/mysql-test/suite/pbxt/r/pbxt_ref_int.result @@ -0,0 +1,404 @@ +drop table if exists t1, t2; +CREATE TABLE t1 +( +id INT PRIMARY KEY +) ENGINE=pbxt; +CREATE TABLE t2 +( +v INT, +CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) +) ENGINE=pbxt; +INSERT INTO t2 VALUES(2); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (Constraint: `c1`) +set foreign_key_checks = 0; +drop table t1; +set foreign_key_checks = 1; +INSERT INTO t2 VALUES(2); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (Referenced table `t1` not found) +drop table if exists parent, child, child_child; +CREATE TABLE parent ( +id INT NOT NULL, +PRIMARY KEY (id) +) ENGINE=PBXT; +CREATE TABLE child ( +id INT PRIMARY KEY, +parent_id INT, +INDEX par_ind (parent_id), +FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE SET NULL ON UPDATE SET NULL +) ENGINE=PBXT; +insert parent values(1); +insert parent values(2); +insert child values(100, 1); +insert child values(200, 1); +insert child values(300, 2); +insert child values(400, 2); +update parent set id = 3 where id = 1; +select * from parent; +id +2 +3 +select * from child order by id; +id parent_id +100 NULL +200 NULL +300 2 +400 2 +delete from parent where id = 2; +select * from parent; +id +3 +select * from child order by id; +id parent_id +100 NULL +200 NULL +300 NULL +400 NULL +set foreign_key_checks = 0; +drop table if exists parent, child, child_child; +set foreign_key_checks = 1; +CREATE TABLE parent ( +id INT NOT NULL, +PRIMARY KEY (id) +) ENGINE=PBXT; +CREATE TABLE child ( +id INT PRIMARY KEY, +parent_id INT, +INDEX par_ind (parent_id), +FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=PBXT; +CREATE TABLE child_child ( +id INT PRIMARY KEY, +child_id INT, +INDEX (child_id), +FOREIGN KEY (child_id) REFERENCES child(id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=PBXT; +delete from parent; +delete from child; +delete from child_child; +insert parent values(1); +insert parent values(2); +insert child values(100, 1); +insert child values(200, 1); +insert child values(300, 2); +insert child values(400, 2); +insert child_child values(1000, 100); +insert child_child values(2000, 200); +insert child_child values(3000, 300); +insert child_child values(4000, 300); +insert child_child values(5000, 400); +select * from parent; +id +1 +2 +select * from child order by id; +id parent_id +100 1 +200 1 +300 2 +400 2 +select * from child_child; +id child_id +1000 100 +2000 200 +3000 300 +4000 300 +5000 400 +update parent set id = 3 where id = 1; +select * from parent; +id +2 +3 +select * from child order by id; +id parent_id +100 3 +200 3 +300 2 +400 2 +delete from parent where id = 2; +select * from parent; +id +3 +select * from child order by id; +id parent_id +100 3 +200 3 +select * from child_child; +id child_id +1000 100 +2000 200 +set foreign_key_checks = 0; +drop table if exists parent, child, child_child; +set foreign_key_checks = 1; +CREATE TABLE parent ( +id INT NOT NULL, +PRIMARY KEY (id) +) ENGINE=PBXT; +CREATE TABLE child ( +id INT, +parent_id INT, +INDEX par_ind (parent_id), +FOREIGN KEY (parent_id) REFERENCES parent(id) +) ENGINE=PBXT; +insert parent values(2); +insert parent values(1); +insert child values(100, 1); +insert child values(200, 1); +update parent set id = 3 where id = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (Constraint: `FOREIGN_1`) +delete from parent where id = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (Constraint: `FOREIGN_1`) +select * from parent; +id +1 +2 +select * from child order by id; +id parent_id +100 1 +200 1 +delete from child; +insert child values(100, 1); +insert child values(200, 1); +create index child_ind on child(id); +show create table child; +Table Create Table +child CREATE TABLE `child` ( + `id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + KEY `par_ind` (`parent_id`), + KEY `child_ind` (`id`), + CONSTRAINT `FOREIGN_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop index child_ind on child; +show create table child; +Table Create Table +child CREATE TABLE `child` ( + `id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + KEY `par_ind` (`parent_id`), + CONSTRAINT `FOREIGN_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table parent add column c1 varchar(40); +insert child values(2000, 2); +select * from parent; +id c1 +2 NULL +1 NULL +select * from child order by id; +id parent_id +100 1 +200 1 +2000 2 +show create table parent; +Table Create Table +parent CREATE TABLE `parent` ( + `id` int(11) NOT NULL, + `c1` varchar(40) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table parent drop column c1; +select * from parent; +id +1 +2 +show create table parent; +Table Create Table +parent CREATE TABLE `parent` ( + `id` int(11) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table parent add column c1 int; +alter table parent drop column id; +insert child values(300, 1); +ERROR HY000: Cannot add foreign key constraint +alter table parent add column id int, add index (id); +select * from parent; +c1 id +NULL NULL +NULL NULL +insert child values(300, 1); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (Constraint: `FOREIGN_1`) +update parent set id = 1 where id is null limit 1; +update parent set id = 2 where id is null limit 1; +insert child values(300, 1); +select * from parent order by id; +c1 id +NULL 1 +NULL 2 +select * from child order by id; +id parent_id +100 1 +200 1 +300 1 +2000 2 +show create table parent; +Table Create Table +parent CREATE TABLE `parent` ( + `c1` int(11) DEFAULT NULL, + `id` int(11) DEFAULT NULL, + KEY `id` (`id`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show create table child; +Table Create Table +child CREATE TABLE `child` ( + `id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + KEY `par_ind` (`parent_id`), + CONSTRAINT `FOREIGN_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +alter table child add column c1 varchar(40); +insert child values(400, 1, "asd"); +select * from parent order by id; +c1 id +NULL 1 +NULL 2 +select * from child order by id; +id parent_id c1 +100 1 NULL +200 1 NULL +300 1 NULL +400 1 asd +2000 2 NULL +alter table child drop key par_ind, drop column parent_id, add column parent_id int, add key par_ind (parent_id); +insert child (id, parent_id, c1) values(500, 1, "asd"); +drop table if exists child, parent; +CREATE TABLE parent ( +id INT NOT NULL, +PRIMARY KEY (id) +) ENGINE=PBXT; +CREATE TABLE child ( +id INT, +parent_id INT, +INDEX par_ind (parent_id), +FOREIGN KEY (parent_id) +REFERENCES parent(id) ON DELETE CASCADE +) ENGINE=PBXT; +show create table parent; +Table Create Table +parent CREATE TABLE `parent` ( + `id` int(11) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show create table child; +Table Create Table +child CREATE TABLE `child` ( + `id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + KEY `par_ind` (`parent_id`), + CONSTRAINT `FOREIGN_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert parent values(1); +insert child values(100, 1); +insert child values(102, 2); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (Constraint: `FOREIGN_1`) +set foreign_key_checks = 0; +drop table if exists parent, child; +set foreign_key_checks = 1; +CREATE TABLE parent ( +id INT NOT NULL, +PRIMARY KEY (id) +) ENGINE=PBXT; +CREATE TABLE child ( +id INT, +parent_id INT, +INDEX par_ind (parent_id), +FOREIGN KEY (parent_id) +REFERENCES parent(glump) ON DELETE CASCADE +) ENGINE=PBXT; +insert parent values(1); +insert child values(100, 1); +ERROR HY000: Cannot add foreign key constraint +drop table if exists test1; +CREATE TABLE test1 ( +id INT NOT NULL, +c1 varchar(30), +PRIMARY KEY (id) +) ENGINE=pbxt; +insert test1 values(1, "asd"); +insert test1 values(2, "qwer"); +alter table test1 drop column id, drop primary key, add column id int; +show create table test1; +Table Create Table +test1 CREATE TABLE `test1` ( + `c1` varchar(30) DEFAULT NULL, + `id` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from test1; +c1 id +asd NULL +qwer NULL +drop table if exists `ÔÁÂÌÉÃÁ`, t2; +create table `ÔÁÂÌÉÃÁ` ( +id int primary key +) engine=pbxt; +CREATE TABLE t2 +( +ÐÏÌÅ int NOT NULL, +cc varchar(20), +foreign key (ÐÏÌÅ) references `ÔÁÂÌÉÃÁ` (id), +index (ÐÏÌÅ) +) engine=pbxt; +insert `ÔÁÂÌÉÃÁ` values (1); +insert t2 values (1, "asd"); +select * from `ÔÁÂÌÉÃÁ`; +id +1 +set foreign_key_checks = 0; +drop table if exists test1, parent, child, child_child, `ÔÁÂÌÉÃÁ`, t2; +set foreign_key_checks = 1; +SET CHARACTER SET koi8r; +SET NAMES binary; +create table `теÑÑ‚` ( +id int primary key +) engine=pbxt; +CREATE TABLE `2теÑÑ‚` ( +`теÑÑ‚` int, +foreign key (`теÑÑ‚`) references `теÑÑ‚`(id), +index (`теÑÑ‚`) +) engine=pbxt; +select * from `теÑÑ‚`; +id +select * from `2теÑÑ‚`; +теÑÑ‚ +set foreign_key_checks = 0; +drop table if exists `теÑÑ‚`, `2теÑÑ‚`; +set foreign_key_checks = 1; +drop table if exists t2, t1; +set foreign_key_checks = 1; +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1)); +ERROR HY000: Can't create table 'test.t2' (errno: 151) +set foreign_key_checks = 0; +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1)); +set foreign_key_checks = 1; +insert into t2 values (1); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (Referenced table `t1` not found) +set foreign_key_checks = 0; +insert into t2 values (1); +CREATE TABLE t1 (s1 INT PRIMARY KEY); +set foreign_key_checks = 1; +DROP TABLE t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails +set foreign_key_checks = 0; +DROP TABLE t1; +DROP TABLE t2; +set foreign_key_checks = 1; +CREATE TABLE t1 (s1 INT DEFAULT NULL, s2 INT DEFAULT NULL, s3 INT DEFAULT NULL, s4 INT DEFAULT NULL, +INDEX (s1), INDEX (s2), INDEX (s3), INDEX (s4), +FOREIGN KEY (s1) REFERENCES t1 (s2), +FOREIGN KEY (s2) REFERENCES t1 (s3), +FOREIGN KEY (s3) REFERENCES t1 (s4)); +DROP TABLE t1; +CREATE TABLE t1 (s1 INT DEFAULT NULL, s2 INT DEFAULT NULL, s3 INT DEFAULT NULL, s4 INT DEFAULT NULL, +INDEX (s1), INDEX (s2), INDEX (s3), INDEX (s4), +FOREIGN KEY (s1) REFERENCES t1 (s2), +FOREIGN KEY (s2) REFERENCES t1 (s3), +FOREIGN KEY (s3) REFERENCES t1 (s4)); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1)); +DROP TABLE t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t2 (s1 INT, INDEX (s1)); +set foreign_key_checks = 0; +ALTER TABLE t2 ADD FOREIGN KEY (s1) REFERENCES t1 (s1); +DROP TABLE IF EXISTS t2, t1; +set foreign_key_checks = 1; diff --git a/mysql-test/suite/pbxt/r/pbxt_transactions.result b/mysql-test/suite/pbxt/r/pbxt_transactions.result new file mode 100644 index 00000000000..be38920c205 --- /dev/null +++ b/mysql-test/suite/pbxt/r/pbxt_transactions.result @@ -0,0 +1,564 @@ +drop table if exists t1, t2, t3; +create table `t1` (`id` int( 11 ) not null ,primary key ( `id` )) engine = pbxt; +insert into `t1`values ( 1 ) ; +create table `t2` (`id` int( 11 ) not null default '0',unique key `id` ( `id` ) ,constraint `t1_id_fk` foreign key ( `id` ) references `t1` (`id` )) engine = pbxt; +insert into `t2`values ( 1 ) ; +create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = pbxt; +insert into `t3`values ( 1 ) ; +select * from t1; +id +1 +select * from t2; +id +1 +select * from t3; +id +1 +update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (Constraint: `t1_id_fk`) +select * from t1; +id +1 +select * from t2; +id +1 +select * from t3; +id +1 +delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (Constraint: `t1_id_fk`) +select * from t1; +id +1 +select * from t2; +id +1 +select * from t3; +id +1 +drop table if exists t3, t2, t1; +create table t1 (id int primary key) engine = pbxt; +create table t2 (id int) engine = pbxt; +insert into t1 values ( 1 ) ; +insert into t1 values ( 2 ) ; +insert into t2 values ( 1 ) ; +insert into t2 values ( 2 ) ; +select * from t1; +id +1 +2 +select * from t2; +id +1 +2 +update t1 set t1.id=1 where t1.id=2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select * from t1; +id +1 +2 +select * from t2; +id +1 +2 +update t1,t2 set t1.id=3, t2.id=3 where t1.id=2 and t2.id = t1.id; +select * from t1; +id +1 +3 +select * from t2; +id +1 +3 +update t1,t2 set t1.id=1, t2.id=1 where t1.id=3 and t2.id = t1.id; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select * from t1; +id +1 +3 +select * from t2; +id +1 +3 +update t1 set t1.id=1 where t1.id=3; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select * from t1; +id +1 +3 +select * from t2; +id +1 +3 +drop table if exists t1, t2, t3; +create table t1 (c1 int); +insert t1 values (1); +select * from t1; +c1 +1 +rename table t1 to t2; +create table t1 (a text character set utf8, b text character set latin1); +insert t1 values (0x4F736E616272C3BC636B, 0x4BF66C6E); +select * from t1; +a b +Osnabrück Köln +test.t1: Records: 1 Deleted: 0 Skipped: 0 Warnings: 0 +select * from t1 for update; +a b +Osnabrück Köln +drop table if exists t1,t3; +create table t1 ( +id char(16) not null default '', +data int not null +); +insert into t1 values ("foo", 3), ("bar", 2), ("zip", 5), ("zap", 1)| +create table t3 ( +v char(16) not null primary key, +c int unsigned not null +)| +create function getcount(s char(16)) returns int +begin +declare x int; +select count(*) into x from t3 where v = s; +if x = 0 then +insert into t3 values (s, 1); +else +update t3 set c = c+1 where v = s; +end if; +return x; +end| +select * from t1| +id data +foo 3 +bar 2 +zip 5 +zap 1 +select * from t3| +v c +select * from t1 where data = getcount("bar")| +id data +zap 1 +select * from t1| +id data +foo 3 +bar 2 +zip 5 +zap 1 +select * from t3| +v c +bar 4 +drop table t1,t3| +drop function getcount; +drop tables if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (id int); +lock tables t1 write; +insert t1 values (1); +insert t1 values (2); +select id from t1; +id +1 +2 +unlock tables; +select id from t1; +id +1 +2 +DROP TABLE if exists t1; +create table t1 (id int primary key); +insert t1 values (100); +LOCK TABLES t1 WRITE; +insert t1 values (98); +insert into t1 values (99),(100); +ERROR 23000: Duplicate entry '100' for key 'PRIMARY' +select id from t1; +id +98 +100 +UNLOCK TABLES; +select id from t1; +id +98 +100 +DROP TABLE if exists t1; +create table t1 (id int primary key); +insert t1 values (100); +begin; +insert t1 values (98); +insert into t1 values (99),(100); +ERROR 23000: Duplicate entry '100' for key 'PRIMARY' +select id from t1; +id +98 +99 +100 +rollback; +select id from t1; +id +100 +DROP TABLE if exists t1; +create table t1 (id int primary key); +insert t1 values (100); +insert t1 values (98); +insert into t1 values (99),(100); +ERROR 23000: Duplicate entry '100' for key 'PRIMARY' +select id from t1; +id +98 +100 +DROP TABLE if exists t1, t2; +create table t1 (id int primary key); +insert t1 values (100); +create table t2 (id int primary key); +insert t2 values (100); +LOCK TABLES t1 WRITE, t2 READ; +insert t1 values (98); +select * from t1, t2 where t1.id = t2.id; +id id +100 100 +insert t1 values (97); +insert into t1 values (99),(100); +ERROR 23000: Duplicate entry '100' for key 'PRIMARY' +select id from t1; +id +97 +98 +100 +UNLOCK TABLES; +select id from t1; +id +97 +98 +100 +DROP TABLE t1; +drop table if exists t1, t2, t3; +create table t1 (a int, b int); +insert into t1 values (1, 2), (2, 3), (3, 4); +create table t2 (a int); +insert into t2 values (10), (20), (30); +create view v1 as select a as b, a/10 as a from t2; +lock table t1 write; +alter table t1 add column c int default 100 after a; +update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a; +unlock tables; +select * from t1; +a c b +1 100 13 +2 100 25 +3 100 37 +select * from t2; +a +10 +20 +30 +drop view v1; +drop table t1, t2; +drop table if exists t1, t4; +create table t1 ( +a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +) engine=pbxt; +insert t1 values ("a1", "a2", "b", "c", "d", "dummy"); +create table t4 ( +pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +) engine=pbxt; +insert into t4 (a1, a2, b, c, d, dummy) select * from t1; +create index idx12672_0 on t4 (a1); +create index idx12672_1 on t4 (a1,a2,b,c); +create index idx12672_2 on t4 (a1,a2,b); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +use test; +drop table if exists t1; +drop database if exists mysqltest; +create database mysqltest; +use mysqltest; +create table t1 (id int); +create trigger t1_bi before insert on t1 for each row set @a:=new.id; +insert into t1 values (101); +alter table t1 rename to test.t1, add column val int default 0; +Got one of the listed errors +drop database mysqltest; +use test; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +id fk +2 NULL +3 NULL +4 NULL +5 NULL +1 69 +drop table t9; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +lock tables t9 write; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9 order by id; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +unlock tables; +SELECT * from t9 order by id; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +drop table t9; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +create procedure auto_test() +begin +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +end| +call auto_test(); +id fk +2 NULL +3 NULL +4 NULL +5 NULL +1 69 +SELECT * from t9; +id fk +2 NULL +3 NULL +4 NULL +5 NULL +1 69 +drop procedure auto_test; +drop table t9; +SET AUTOCOMMIT=0; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +drop table t9; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +lock tables t9 write; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +unlock tables; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +drop table t9; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +create procedure auto_test() +begin +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +end| +call auto_test(); +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +drop procedure auto_test; +drop table t9; +SET AUTOCOMMIT=1; +SET AUTOCOMMIT=0; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +commit; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +drop table t9; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +lock tables t9 write; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +unlock tables; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +commit; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +drop table t9; +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +create procedure auto_test() +begin +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +end| +call auto_test(); +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +commit; +SELECT * from t9; +id fk +1 69 +2 NULL +3 NULL +4 NULL +5 NULL +drop procedure auto_test; +drop table t9; +SET AUTOCOMMIT=1; +drop table if exists t1,t3| +create table t1 ( +id char(16) not null default '', +data int not null +)| +insert t1 value ("one", 1), ("two", 2)| +drop function if exists bug12472| +create function bug12472() returns int +begin +declare a int; +declare b int; +set a = (select count(*) from t1); +set b = (select count(*) from t1); +return (a + b); +end| +create table t3 as select bug12472() as i| +show create table t3| +Table Create Table +t3 CREATE TABLE `t3` ( + `i` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t3| +i +4 +drop table t3| +create view v1 as select bug12472() as j| +create table t3 as select * from v1| +show create table t3| +Table Create Table +t3 CREATE TABLE `t3` ( + `j` int(11) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select * from t3| +j +4 +drop table t3| +drop view v1| +drop function bug12472| +drop table t1| +drop table if exists t1, t3| +drop procedure if exists t3_update| +drop function if exists t3_update| +create table t3 (a smallint primary key) engine=pbxt| +insert into t3 (a) values (1)| +create procedure t3_update() +deterministic +begin +declare continue handler for 1062 -- ER_DUP_ENTRY +select 'Outer (bad)' as 't3_update'; +begin +declare continue handler for 1062 -- ER_DUP_ENTRY +select 'Inner (good)' as 't3_update'; +insert into t3 values (1); +end; +end| +call t3_update()| +t3_update +Inner (good) +begin| +call t3_update()| +t3_update +Inner (good) +commit| +drop table if exists t3| +drop procedure if exists t3_update| +drop function if exists t3_update| +create table t3 (a smallint primary key) engine=pbxt| +insert into t3 (a) values (40)| +insert into t3 (a) values (50)| +create function t3_update() returns int +begin +insert into t3 values (10); +insert into t3 values (40); +insert into t3 values (500); +return 100; +end| +select * from t3| +a +40 +50 +begin| +insert into t3 values (10)| +select t3_update()| +rollback| +ERROR 23000: Duplicate entry '40' for key 'PRIMARY' +select * from t3| +a +40 +50 +drop function t3_update| +drop table if exists t1, t2, t3, t4| diff --git a/mysql-test/suite/pbxt/r/pbxt_updates.result b/mysql-test/suite/pbxt/r/pbxt_updates.result new file mode 100644 index 00000000000..e84330f2d2d --- /dev/null +++ b/mysql-test/suite/pbxt/r/pbxt_updates.result @@ -0,0 +1,139 @@ +drop table if exists t1, t2; +CREATE TABLE t1 +( +id INT PRIMARY KEY, +number INT, +string VARCHAR(20), +UNIQUE INDEX (number) +) ENGINE=pbxt; +truncate table t1; +insert t1 values (1, 1, 'abc'); +begin; +update t1 set string = 'def' where id = 1; +update t1 set string = 'HIJ' where id = 1; +select * from t1 where id = 1; +id number string +1 1 HIJ +select * from t1 where number = 1; +id number string +1 1 HIJ +update t1 set string = '123', number=2 where id = 1; +select * from t1 where id = 1; +id number string +1 2 123 +select * from t1 where number = 2; +id number string +1 2 123 +commit; +insert t1 values (2, 2, 'abc'); +ERROR 23000: Duplicate entry '2' for key 'number' +insert t1 values (2, 3, 'abc'); +select * from t1 order by id; +id number string +1 2 123 +2 3 abc +begin; +update t1 set number = 1 where id = 1; +select * from t1 order by id; +id number string +1 1 123 +2 3 abc +update t1 set number = 3 where id = 1; +ERROR 23000: Duplicate entry '3' for key 'number' +select * from t1 where id = 1; +id number string +1 1 123 +select * from t1 where id = 2; +id number string +2 3 abc +select * from t1 where number = 1; +id number string +1 1 123 +select * from t1 where number = 3; +id number string +2 3 abc +select * from t1 order by id; +id number string +1 1 123 +2 3 abc +commit; +select * from t1 order by id; +id number string +1 1 123 +2 3 abc +drop table t1; +CREATE TABLE t1 +( +id INT PRIMARY KEY, +number INT, +string VARCHAR(300), +UNIQUE INDEX (number) +) ENGINE=pbxt; +truncate table t1; +insert t1 values (1, 1, 'abc01234567890123456789012345678901234567890123456789$$$'); +begin; +update t1 set string = 'def01234567890123456789012345678901234567890123456789---' where id = 1; +update t1 set string = 'HIJ01234567890123456789012345678901234567890123456789***' where id = 1; +select * from t1 where id = 1; +id number string +1 1 HIJ01234567890123456789012345678901234567890123456789*** +select * from t1 where number = 1; +id number string +1 1 HIJ01234567890123456789012345678901234567890123456789*** +update t1 set string = '12301234567890123456789012345678901234567890123456789+++', number=2 where id = 1; +select * from t1 where id = 1; +id number string +1 2 12301234567890123456789012345678901234567890123456789+++ +select * from t1 where number = 2; +id number string +1 2 12301234567890123456789012345678901234567890123456789+++ +commit; +insert t1 values (2, 2, 'abc01234567890123456789012345678901234567890123456789==='); +ERROR 23000: Duplicate entry '2' for key 'number' +insert t1 values (2, 3, 'abc01234567890123456789012345678901234567890123456789+++'); +select * from t1 order by id; +id number string +1 2 12301234567890123456789012345678901234567890123456789+++ +2 3 abc01234567890123456789012345678901234567890123456789+++ +begin; +update t1 set number = 1 where id = 1; +select * from t1 order by id; +id number string +1 1 12301234567890123456789012345678901234567890123456789+++ +2 3 abc01234567890123456789012345678901234567890123456789+++ +update t1 set number = 3 where id = 1; +ERROR 23000: Duplicate entry '3' for key 'number' +select * from t1 where id = 1; +id number string +1 1 12301234567890123456789012345678901234567890123456789+++ +select * from t1 where id = 2; +id number string +2 3 abc01234567890123456789012345678901234567890123456789+++ +select * from t1 where number = 1; +id number string +1 1 12301234567890123456789012345678901234567890123456789+++ +select * from t1 where number = 3; +id number string +2 3 abc01234567890123456789012345678901234567890123456789+++ +select * from t1 order by id; +id number string +1 1 12301234567890123456789012345678901234567890123456789+++ +2 3 abc01234567890123456789012345678901234567890123456789+++ +rollback; +select * from t1 order by id; +id number string +1 2 12301234567890123456789012345678901234567890123456789+++ +2 3 abc01234567890123456789012345678901234567890123456789+++ +drop table t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 ( id int, name varchar(300)) engine=pbxt; +begin; +insert t1(id, name) values(1, "aaa"); +update t1 set name=REPEAT('A', 300) where id = 1; +commit; +select * from t1; +id name +1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +drop table t1; diff --git a/mysql-test/suite/pbxt/r/perror.result b/mysql-test/suite/pbxt/r/perror.result new file mode 100644 index 00000000000..4946523bc42 --- /dev/null +++ b/mysql-test/suite/pbxt/r/perror.result @@ -0,0 +1 @@ +Illegal error code: 10000 diff --git a/mysql-test/suite/pbxt/r/preload.result b/mysql-test/suite/pbxt/r/preload.result new file mode 100644 index 00000000000..285b58e210e --- /dev/null +++ b/mysql-test/suite/pbxt/r/preload.result @@ -0,0 +1,168 @@ +drop table if exists t1, t2; +create table t1 ( +a int not null auto_increment, +b char(16) not null, +primary key (a), +key (b) +); +create table t2( +a int not null auto_increment, +b char(16) not null, +primary key (a), +key (b) +); +insert into t1(b) values +('test0'), +('test1'), +('test2'), +('test3'), +('test4'), +('test5'), +('test6'), +('test7'); +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +select count(*) from t1; +count(*) +33448 +select count(*) from t2; +count(*) +20672 +flush tables; +flush status; +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +select count(*) from t1 where b = 'test1'; +count(*) +4181 +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +select count(*) from t1 where b = 'test1'; +count(*) +4181 +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +flush tables; +flush status; +select @@preload_buffer_size; +@@preload_buffer_size +32768 +load index into cache t1; +Table Op Msg_type Msg_text +test.t1 preload_keys note The storage engine for the table doesn't support preload_keys +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +select count(*) from t1 where b = 'test1'; +count(*) +4181 +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +flush tables; +flush status; +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +set session preload_buffer_size=256*1024; +select @@preload_buffer_size; +@@preload_buffer_size +262144 +load index into cache t1 ignore leaves; +Table Op Msg_type Msg_text +test.t1 preload_keys note The storage engine for the table doesn't support preload_keys +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +select count(*) from t1 where b = 'test1'; +count(*) +4181 +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +flush tables; +flush status; +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +set session preload_buffer_size=1*1024; +select @@preload_buffer_size; +@@preload_buffer_size +1024 +load index into cache t1, t2 key (primary,b) ignore leaves; +Table Op Msg_type Msg_text +test.t1 preload_keys note The storage engine for the table doesn't support preload_keys +test.t2 preload_keys note The storage engine for the table doesn't support preload_keys +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +select count(*) from t1 where b = 'test1'; +count(*) +4181 +select count(*) from t2 where b = 'test1'; +count(*) +2584 +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +flush tables; +flush status; +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +load index into cache t3, t2 key (primary,b) ; +Table Op Msg_type Msg_text +test.t3 preload_keys Error Table 'test.t3' doesn't exist +test.t3 preload_keys error Corrupt +test.t2 preload_keys note The storage engine for the table doesn't support preload_keys +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +flush tables; +flush status; +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +load index into cache t3 key (b), t2 key (c) ; +Table Op Msg_type Msg_text +test.t3 preload_keys Error Table 'test.t3' doesn't exist +test.t3 preload_keys error Corrupt +test.t2 preload_keys note The storage engine for the table doesn't support preload_keys +show status like "key_read%"; +Variable_name Value +Key_read_requests 0 +Key_reads 0 +drop table t1, t2; diff --git a/mysql-test/suite/pbxt/r/ps_10nestset.result b/mysql-test/suite/pbxt/r/ps_10nestset.result new file mode 100644 index 00000000000..bbfc662a510 --- /dev/null +++ b/mysql-test/suite/pbxt/r/ps_10nestset.result @@ -0,0 +1,76 @@ +drop table if exists t1; +create table t1 ( +id INTEGER AUTO_INCREMENT PRIMARY KEY, +emp CHAR(10) NOT NULL, +salary DECIMAL(6,2) NOT NULL, +l INTEGER NOT NULL, +r INTEGER NOT NULL); +prepare st_ins from 'insert into t1 set emp = ?, salary = ?, l = ?, r = ?'; +set @arg_nam= 'Jerry'; +set @arg_sal= 1000; +set @arg_l= 1; +set @arg_r= 12; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Bert'; +set @arg_sal= 900; +set @arg_l= 2; +set @arg_r= 3; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Chuck'; +set @arg_sal= 900; +set @arg_l= 4; +set @arg_r= 11; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Donna'; +set @arg_sal= 800; +set @arg_l= 5; +set @arg_r= 6; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Eddie'; +set @arg_sal= 700; +set @arg_l= 7; +set @arg_r= 8; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Fred'; +set @arg_sal= 600; +set @arg_l= 9; +set @arg_r= 10; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +select * from t1; +id emp salary l r +1 Jerry 1000.00 1 12 +2 Bert 900.00 2 3 +3 Chuck 900.00 4 11 +4 Donna 800.00 5 6 +5 Eddie 700.00 7 8 +6 Fred 600.00 9 10 +prepare st_raise_base from 'update t1 set salary = salary * ( 1 + ? ) where r - l = 1'; +prepare st_raise_mgr from 'update t1 set salary = salary + ? where r - l > 1'; +set @arg_percent= .10; +set @arg_amount= 100; +execute st_raise_base using @arg_percent; +execute st_raise_mgr using @arg_amount; +execute st_raise_base using @arg_percent; +execute st_raise_mgr using @arg_amount; +execute st_raise_base using @arg_percent; +execute st_raise_mgr using @arg_amount; +select * from t1 order by id; +id emp salary l r +1 Jerry 1300.00 1 12 +2 Bert 1197.90 2 3 +3 Chuck 1200.00 4 11 +4 Donna 1064.80 5 6 +5 Eddie 931.70 7 8 +6 Fred 798.60 9 10 +prepare st_round from 'update t1 set salary = salary + ? - ( salary MOD ? )'; +set @arg_round= 50; +execute st_round using @arg_round, @arg_round; +select * from t1 order by id; +id emp salary l r +1 Jerry 1350.00 1 12 +2 Bert 1200.00 2 3 +3 Chuck 1250.00 4 11 +4 Donna 1100.00 5 6 +5 Eddie 950.00 7 8 +6 Fred 800.00 9 10 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/ps_11bugs.result b/mysql-test/suite/pbxt/r/ps_11bugs.result new file mode 100644 index 00000000000..ebe161f46b3 --- /dev/null +++ b/mysql-test/suite/pbxt/r/ps_11bugs.result @@ -0,0 +1,165 @@ +drop table if exists t1, t2; +CREATE TABLE t1(session_id char(9) NOT NULL); +INSERT INTO t1 VALUES ("abc"); +SELECT * FROM t1; +session_id +abc +prepare st_1180 from 'SELECT * FROM t1 WHERE ?="1111" and session_id = "abc"'; +set @arg1= 'abc'; +execute st_1180 using @arg1; +session_id +set @arg1= '1111'; +execute st_1180 using @arg1; +session_id +abc +set @arg1= 'abc'; +execute st_1180 using @arg1; +session_id +drop table t1; +create table t1 ( +c_01 char(6), c_02 integer, c_03 real, c_04 int(3), c_05 varchar(20), +c_06 date, c_07 char(1), c_08 real, c_09 int(11), c_10 time, +c_11 char(6), c_12 integer, c_13 real, c_14 int(3), c_15 varchar(20), +c_16 date, c_17 char(1), c_18 real, c_19 int(11), c_20 text); +prepare st_1644 from 'insert into t1 values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; +set @arg01= 'row_1'; +set @arg02= 1; +set @arg03= 1.1; +set @arg04= 111; +set @arg05= 'row_one'; +set @arg06= '2004-10-12'; +set @arg07= '1'; +set @arg08= 1.1; +set @arg09= '100100100'; +set @arg10= '12:34:56'; +set @arg11= 'row_1'; +set @arg12= 1; +set @arg13= 1.1; +set @arg14= 111; +set @arg15= 'row_one'; +set @arg16= '2004-10-12'; +set @arg17= '1'; +set @arg18= 1.1; +set @arg19= '100100100'; +set @arg20= '12:34:56'; +execute st_1644 using @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08, @arg09, @arg10, +@arg11, @arg12, @arg13, @arg14, @arg15, @arg16, @arg17, @arg18, @arg19, @arg20; +set @arg01= NULL; +set @arg02= NULL; +set @arg03= NULL; +set @arg04= NULL; +set @arg05= NULL; +set @arg06= NULL; +set @arg07= NULL; +set @arg08= NULL; +set @arg09= NULL; +set @arg10= NULL; +set @arg11= NULL; +set @arg12= NULL; +set @arg13= NULL; +set @arg14= NULL; +set @arg15= NULL; +set @arg16= NULL; +set @arg17= NULL; +set @arg18= NULL; +set @arg19= NULL; +set @arg20= NULL; +execute st_1644 using @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08, @arg09, @arg10, +@arg11, @arg12, @arg13, @arg14, @arg15, @arg16, @arg17, @arg18, @arg19, @arg20; +set @arg01= 'row_3'; +set @arg02= 3; +set @arg03= 3.3; +set @arg04= 333; +set @arg05= 'row_three'; +set @arg06= '2004-10-12'; +set @arg07= '3'; +set @arg08= 3.3; +set @arg09= '300300300'; +set @arg10= '12:34:56'; +set @arg11= 'row_3'; +set @arg12= 3; +set @arg13= 3.3; +set @arg14= 333; +set @arg15= 'row_three'; +set @arg16= '2004-10-12'; +set @arg17= '3'; +set @arg18= 3.3; +set @arg19= '300300300'; +set @arg20= '12:34:56'; +execute st_1644 using @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08, @arg09, @arg10, +@arg11, @arg12, @arg13, @arg14, @arg15, @arg16, @arg17, @arg18, @arg19, @arg20; +select * from t1; +c_01 c_02 c_03 c_04 c_05 c_06 c_07 c_08 c_09 c_10 c_11 c_12 c_13 c_14 c_15 c_16 c_17 c_18 c_19 c_20 +row_1 1 1.1 111 row_one 2004-10-12 1 1.1 100100100 12:34:56 row_1 1 1.1 111 row_one 2004-10-12 1 1.1 100100100 12:34:56 +NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL +row_3 3 3.3 333 row_three 2004-10-12 3 3.3 300300300 12:34:56 row_3 3 3.3 333 row_three 2004-10-12 3 3.3 300300300 12:34:56 +drop table t1; +create table t1( +cola varchar(50) not null, +colb varchar(8) not null, +colc varchar(12) not null, +cold varchar(2) not null, +primary key (cola, colb, cold)); +create table t2( +cola varchar(50) not null, +colb varchar(8) not null, +colc varchar(2) not null, +cold float, +primary key (cold)); +insert into t1 values ('aaaa', 'yyyy', 'yyyy-dd-mm', 'R'); +insert into t2 values ('aaaa', 'yyyy', 'R', 203), ('bbbb', 'zzzz', 'C', 201); +prepare st_1676 from 'select a.cola, a.colb, a.cold from t1 a, t2 b where a.cola = ? and a.colb = ? and a.cold = ? and b.cola = a.cola and b.colb = a.colb and b.colc = a.cold'; +set @arg0= "aaaa"; +set @arg1= "yyyy"; +set @arg2= "R"; +execute st_1676 using @arg0, @arg1, @arg2; +cola colb cold +aaaa yyyy R +drop table t1, t2; +create table t1 (a int primary key); +insert into t1 values (1); +explain select * from t1 where 3 in (select (1+1) union select 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used +3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL +select * from t1 where 3 in (select (1+1) union select 1); +a +prepare st_18492 from 'select * from t1 where 3 in (select (1+1) union select 1)'; +execute st_18492; +a +drop table t1; +create table t1 (a int, b varchar(4)); +create table t2 (a int, b varchar(4), primary key(a)); +prepare stmt1 from 'insert into t1 (a, b) values (?, ?)'; +prepare stmt2 from 'insert into t2 (a, b) values (?, ?)'; +set @intarg= 11; +set @varchararg= '2222'; +execute stmt1 using @intarg, @varchararg; +execute stmt2 using @intarg, @varchararg; +set @intarg= 12; +execute stmt1 using @intarg, @UNDEFINED; +execute stmt2 using @intarg, @UNDEFINED; +set @intarg= 13; +execute stmt1 using @UNDEFINED, @varchararg; +execute stmt2 using @UNDEFINED, @varchararg; +ERROR 23000: Column 'a' cannot be null +set @intarg= 14; +set @nullarg= Null; +execute stmt1 using @UNDEFINED, @nullarg; +execute stmt2 using @nullarg, @varchararg; +ERROR 23000: Column 'a' cannot be null +select * from t1; +a b +11 2222 +12 NULL +NULL 2222 +NULL NULL +select * from t2; +a b +11 2222 +12 NULL +drop table t1; +drop table t2; +End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/r/ps_1general.result b/mysql-test/suite/pbxt/r/ps_1general.result new file mode 100644 index 00000000000..6584274ecf6 --- /dev/null +++ b/mysql-test/suite/pbxt/r/ps_1general.result @@ -0,0 +1,777 @@ +drop table if exists t5, t6, t7, t8; +drop database if exists mysqltest ; +drop database if exists client_test_db; +drop database if exists testtets; +drop table if exists t1Aa,t2Aa,v1Aa,v2Aa; +drop view if exists t1Aa,t2Aa,v1Aa,v2Aa; +test_sequence +------ basic tests ------ +drop table if exists t1, t9 ; +create table t1 +( +a int, b varchar(30), +primary key(a) +) engine = 'MYISAM' ; +create table t9 +( +c1 tinyint, c2 smallint, c3 mediumint, c4 int, +c5 integer, c6 bigint, c7 float, c8 double, +c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), +c13 date, c14 datetime, c15 timestamp, c16 time, +c17 year, c18 tinyint, c19 bool, c20 char, +c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, +c25 blob, c26 text, c27 mediumblob, c28 mediumtext, +c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'), +c32 set('monday', 'tuesday', 'wednesday'), +primary key(c1) +) engine = 'MYISAM' ; +delete from t1 ; +insert into t1 values (1,'one'); +insert into t1 values (2,'two'); +insert into t1 values (3,'three'); +insert into t1 values (4,'four'); +commit ; +delete from t9 ; +insert into t9 +set c1= 1, c2= 1, c3= 1, c4= 1, c5= 1, c6= 1, c7= 1, c8= 1, c9= 1, +c10= 1, c11= 1, c12 = 1, +c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11', +c16= '11:11:11', c17= '2004', +c18= 1, c19=true, c20= 'a', c21= '123456789a', +c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext', +c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext', +c29= 'longblob', c30= 'longtext', c31='one', c32= 'monday'; +insert into t9 +set c1= 9, c2= 9, c3= 9, c4= 9, c5= 9, c6= 9, c7= 9, c8= 9, c9= 9, +c10= 9, c11= 9, c12 = 9, +c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11', +c16= '11:11:11', c17= '2004', +c18= 1, c19=false, c20= 'a', c21= '123456789a', +c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext', +c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext', +c29= 'longblob', c30= 'longtext', c31='two', c32= 'tuesday'; +commit ; +PREPARE stmt FROM ' select * from t1 where a = ? ' ; +SET @var= 2 ; +EXECUTE stmt USING @var ; +a b +2 two +select * from t1 where a = @var ; +a b +2 two +DEALLOCATE PREPARE stmt ; +prepare stmt1 from ' select 1 as my_col ' ; +prepare stmt1 from ' select ? as my_col ' ; +prepare ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 +prepare stmt1 ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 +prepare stmt1 from ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 +prepare_garbage stmt1 from ' select 1 ' ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'prepare_garbage stmt1 from ' select 1 '' at line 1 +prepare stmt1 from_garbage ' select 1 ' ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from_garbage ' select 1 '' at line 1 +prepare stmt1 from ' select_garbage 1 ' ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select_garbage 1' at line 1 +prepare from ' select 1 ' ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from ' select 1 '' at line 1 +prepare stmt1 ' select 1 ' ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' select 1 '' at line 1 +prepare ? from ' select ? as my_col ' ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from ' select ? as my_col '' at line 1 +set @arg00='select 1 as my_col'; +prepare stmt1 from @arg00; +set @arg00=''; +prepare stmt1 from @arg00; +ERROR 42000: Query was empty +set @arg00=NULL; +prepare stmt1 from @arg01; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL' at line 1 +prepare stmt1 from ' select * from t1 where a <= 2 ' ; +prepare stmt1 from ' select * from t1 where x <= 2 ' ; +ERROR 42S22: Unknown column 'x' in 'where clause' +prepare stmt1 from ' insert into t1(a,x) values(?,?) ' ; +ERROR 42S22: Unknown column 'x' in 'field list' +prepare stmt1 from ' insert into t1(x,a) values(?,?) ' ; +ERROR 42S22: Unknown column 'x' in 'field list' +drop table if exists not_exist ; +prepare stmt1 from ' select * from not_exist where a <= 2 ' ; +ERROR 42S02: Table 'test.not_exist' doesn't exist +prepare stmt1 from ' insert into t1 values(? ' ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 +prepare stmt1 from ' select a, b from t1 + where a=? and where ' ; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where' at line 2 +execute never_prepared ; +ERROR HY000: Unknown prepared statement handler (never_prepared) given to EXECUTE +prepare stmt1 from ' select * from t1 where a <= 2 ' ; +prepare stmt1 from ' select * from not_exist where a <= 2 ' ; +ERROR 42S02: Table 'test.not_exist' doesn't exist +execute stmt1 ; +ERROR HY000: Unknown prepared statement handler (stmt1) given to EXECUTE +create table t5 +( +a int primary key, +b char(30), +c int +); +insert into t5( a, b, c) values( 1, 'original table', 1); +prepare stmt2 from ' select * from t5 ' ; +execute stmt2 ; +a b c +1 original table 1 +drop table t5 ; +execute stmt2 ; +ERROR 42S02: Table 'test.t5' doesn't exist +create table t5 +( +a int primary key, +b char(30), +c int +); +insert into t5( a, b, c) values( 9, 'recreated table', 9); +execute stmt2 ; +a b c +9 recreated table 9 +drop table t5 ; +create table t5 +( +a int primary key, +c int, +b char(30) +); +insert into t5( a, b, c) values( 9, 'recreated table', 9); +execute stmt2 ; +a c b +9 9 recreated table +drop table t5 ; +create table t5 +( +a int primary key, +b char(30), +c int, +d timestamp default '2008-02-23 09:23:45' +); +insert into t5( a, b, c) values( 9, 'recreated table', 9); +execute stmt2 ; +a b c d +9 recreated table 9 2008-02-23 09:23:45 +drop table t5 ; +create table t5 +( +a int primary key, +d timestamp default '2008-02-23 09:23:45', +b char(30), +c int +); +insert into t5( a, b, c) values( 9, 'recreated table', 9); +execute stmt2 ; +a d b c +9 2008-02-23 09:23:45 recreated table 9 +drop table t5 ; +create table t5 +( +a timestamp default '2004-02-29 18:01:59', +b char(30), +c int +); +insert into t5( b, c) values( 'recreated table', 9); +execute stmt2 ; +a b c +2004-02-29 18:01:59 recreated table 9 +drop table t5 ; +create table t5 +( +f1 int primary key, +f2 char(30), +f3 int +); +insert into t5( f1, f2, f3) values( 9, 'recreated table', 9); +execute stmt2 ; +f1 f2 f3 +9 recreated table 9 +drop table t5 ; +prepare stmt1 from ' select * from t1 where a <= 2 ' ; +execute stmt1 ; +a b +1 one +2 two +set @arg00=1 ; +set @arg01='two' ; +prepare stmt1 from ' select * from t1 where a <= ? ' ; +execute stmt1 using @arg00; +a b +1 one +execute stmt1 ; +ERROR HY000: Incorrect arguments to EXECUTE +execute stmt1 using @arg00, @arg01; +ERROR HY000: Incorrect arguments to EXECUTE +execute stmt1 using @not_set; +a b +deallocate prepare never_prepared ; +ERROR HY000: Unknown prepared statement handler (never_prepared) given to DEALLOCATE PREPARE +prepare stmt1 from ' select * from t1 where a <= 2 ' ; +prepare stmt1 from ' select * from not_exist where a <= 2 ' ; +ERROR 42S02: Table 'test.not_exist' doesn't exist +deallocate prepare stmt1; +ERROR HY000: Unknown prepared statement handler (stmt1) given to DEALLOCATE PREPARE +create table t5 +( +a int primary key, +b char(10) +); +prepare stmt2 from ' select a,b from t5 where a <= 2 ' ; +drop table t5 ; +deallocate prepare stmt2; +prepare stmt1 from ' select a from t1 where a <= 2 ' ; +prepare stmt2 from ' select b from t1 where a <= 2 ' ; +execute stmt2 ; +b +one +two +execute stmt1 ; +a +1 +2 +prepare stmt1 from ' select a from t1 where a <= 2 ' ; +prepare stmt2 from ' select a from t1 where a <= 2 ' ; +execute stmt2 ; +a +1 +2 +execute stmt1 ; +a +1 +2 +deallocate prepare stmt1 ; +execute stmt2 ; +a +1 +2 +test_sequence +------ show and misc tests ------ +drop table if exists t2; +create table t2 +( +a int primary key, b char(10) +); +prepare stmt4 from ' show databases '; +execute stmt4; +Database +information_schema +mtr +mysql +pbxt +test +prepare stmt4 from ' show tables from test like ''t2%'' '; +execute stmt4; +Tables_in_test (t2%) +t2 +prepare stmt4 from ' show columns from t2 where field in (select ?) '; +SET @arg00="a"; +execute stmt4 using @arg00; +Field Type Null Key Default Extra +a int(11) NO PRI NULL +SET @arg00="b"; +execute stmt4 using @arg00; +Field Type Null Key Default Extra +b char(10) YES NULL +SET @arg00=1; +execute stmt4 using @arg00; +Field Type Null Key Default Extra +prepare stmt4 from ' show columns from t2 from test like ''a%'' '; +execute stmt4; +Field Type Null Key Default Extra +a int(11) NO PRI NULL +create index t2_idx on t2(b); +prepare stmt4 from ' show index from t2 from test '; +execute stmt4; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t2 0 PRIMARY 1 a A 0 NULL NULL BTREE +t2 1 t2_idx 1 b A NULL NULL NULL YES BTREE +prepare stmt4 from ' show table status from test like ''t2%'' '; +execute stmt4; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t2 PBXT 10 Fixed 0 29 1 # 4096 0 NULL # # # latin1_swedish_ci NULL +prepare stmt4 from ' show table status from test like ''t9%'' '; +execute stmt4; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t9 MyISAM 10 Dynamic 2 216 432 # 2048 0 NULL # # # latin1_swedish_ci NULL +prepare stmt4 from ' show status like ''Threads_running'' '; +execute stmt4; +Variable_name Value +Threads_running # +prepare stmt4 from ' show variables like ''sql_mode'' '; +execute stmt4; +Variable_name Value +sql_mode +prepare stmt4 from ' show engine pbxt logs '; +execute stmt4; +prepare stmt4 from ' show grants for user '; +prepare stmt4 from ' show create table t2 '; +prepare stmt4 from ' show master status '; +prepare stmt4 from ' show master logs '; +prepare stmt4 from ' show slave status '; +prepare stmt4 from ' show warnings limit 20 '; +prepare stmt4 from ' show errors limit 20 '; +prepare stmt4 from ' show storage engines '; +execute stmt4; +drop table if exists t5; +prepare stmt1 from ' drop table if exists t5 ' ; +execute stmt1 ; +Warnings: +Note 1051 Unknown table 't5' +prepare stmt1 from ' drop table t5 ' ; +execute stmt1 ; +ERROR 42S02: Unknown table 't5' +prepare stmt1 from ' SELECT @@version ' ; +execute stmt1 ; +@@version +<version> +prepare stmt_do from ' do @var:= (1 in (select a from t1)) ' ; +prepare stmt_set from ' set @var= (1 in (select a from t1)) ' ; +execute stmt_do ; +content of @var is: +1 +execute stmt_set ; +content of @var is: +1 +execute stmt_do ; +content of @var is: +1 +execute stmt_set ; +content of @var is: +1 +execute stmt_do ; +content of @var is: +1 +execute stmt_set ; +content of @var is: +1 +drop table if exists t5 ; +create table t5 (a int) ; +prepare stmt_do from ' do @var:= (1 in (select a from t5)) ' ; +prepare stmt_set from ' set @var= (1 in (select a from t5)) ' ; +execute stmt_do ; +content of @var is: +0 +execute stmt_set ; +content of @var is: +0 +execute stmt_do ; +content of @var is: +0 +execute stmt_set ; +content of @var is: +0 +execute stmt_do ; +content of @var is: +0 +execute stmt_set ; +content of @var is: +0 +drop table t5 ; +deallocate prepare stmt_do ; +deallocate prepare stmt_set ; +prepare stmt1 from ' prepare stmt2 from '' select 1 '' ' ; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt1 from ' execute stmt2 ' ; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt1 from ' deallocate prepare never_prepared ' ; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt1 from 'alter view v1 as select 2'; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt4 from ' use test ' ; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt3 from ' create database mysqltest '; +create database mysqltest ; +prepare stmt3 from ' drop database mysqltest '; +drop database mysqltest ; +prepare stmt3 from ' describe t2 '; +execute stmt3; +Field Type Null Key Default Extra +a int(11) NO PRI NULL +b char(10) YES MUL NULL +drop table t2 ; +execute stmt3; +ERROR 42S02: Table 'test.t2' doesn't exist +prepare stmt3 from ' lock tables t1 read ' ; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt3 from ' unlock tables ' ; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt1 from ' load data infile ''data.txt'' +into table t1 fields terminated by ''\t'' '; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt1 from ' select * into outfile ''data.txt'' from t1 '; +execute stmt1 ; +prepare stmt1 from ' optimize table t1 ' ; +prepare stmt1 from ' analyze table t1 ' ; +prepare stmt1 from ' checksum table t1 ' ; +prepare stmt1 from ' repair table t1 ' ; +prepare stmt1 from ' restore table t1 from ''data.txt'' ' ; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt1 from ' handler t1 open '; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt3 from ' commit ' ; +prepare stmt3 from ' rollback ' ; +prepare stmt4 from ' SET sql_mode=ansi '; +execute stmt4; +select 'a' || 'b' ; +'a' || 'b' +ab +prepare stmt4 from ' SET sql_mode="" '; +execute stmt4; +select '2' || '3' ; +'2' || '3' +1 +prepare stmt5 from ' select ''2'' || ''3'' ' ; +execute stmt5; +'2' || '3' +1 +SET sql_mode=ansi; +execute stmt5; +'2' || '3' +1 +SET sql_mode=""; +prepare stmt1 from ' flush local privileges ' ; +prepare stmt1 from ' reset query cache ' ; +prepare stmt1 from ' KILL 0 '; +prepare stmt1 from ' explain select a from t1 order by b '; +execute stmt1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def id 8 3 1 N 32929 0 63 +def select_type 253 19 6 N 1 31 8 +def table 253 64 2 Y 0 31 8 +def type 253 10 3 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 +def key 253 64 0 Y 0 31 8 +def key_len 253 4096 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 +def rows 8 10 1 Y 32928 0 63 +def Extra 253 255 14 N 1 31 8 +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using filesort +SET @arg00=1 ; +prepare stmt1 from ' explain select a from t1 where a > ? order by b '; +execute stmt1 using @arg00; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def id 8 3 1 N 32929 0 63 +def select_type 253 19 6 N 1 31 8 +def table 253 64 2 Y 0 31 8 +def type 253 10 5 Y 0 31 8 +def possible_keys 253 4096 7 Y 0 31 8 +def key 253 64 7 Y 0 31 8 +def key_len 253 4096 1 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 +def rows 8 10 1 Y 32928 0 63 +def Extra 253 255 27 N 1 31 8 +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where; Using filesort +drop table if exists t2; +create table t2 (id smallint, name varchar(20)) ; +prepare stmt1 from ' insert into t2 values(?, ?) ' ; +set @id= 9876 ; +set @arg00= 'MySQL - Open Source Database' ; +set @arg01= "'" ; +set @arg02= '"' ; +set @arg03= "my'sql'" ; +set @arg04= 'my"sql"' ; +insert into t2 values ( @id , @arg00 ); +Warnings: +Warning 1265 Data truncated for column 'name' at row 1 +insert into t2 values ( @id , @arg01 ); +insert into t2 values ( @id , @arg02 ); +insert into t2 values ( @id , @arg03 ); +insert into t2 values ( @id , @arg04 ); +prepare stmt1 from ' select * from t2 where id= ? and name= ? '; +execute stmt1 using @id, @arg00 ; +id name +execute stmt1 using @id, @arg01 ; +id name +9876 ' +execute stmt1 using @id, @arg02 ; +id name +9876 " +execute stmt1 using @id, @arg03 ; +id name +9876 my'sql' +execute stmt1 using @id, @arg04 ; +id name +9876 my"sql" +drop table t2; +test_sequence +------ create/drop/alter/rename tests ------ +drop table if exists t2, t3; +prepare stmt_drop from ' drop table if exists t2 ' ; +execute stmt_drop; +prepare stmt_create from ' create table t2 ( + a int primary key, b char(10)) '; +execute stmt_create; +prepare stmt3 from ' create table t3 like t2 '; +execute stmt3; +drop table t3; +set @arg00=1; +prepare stmt3 from ' create table t3 (m int) select ? as m ' ; +execute stmt3 using @arg00; +select m from t3; +m +1 +drop table t3; +prepare stmt3 from ' create index t2_idx on t2(b) '; +prepare stmt3 from ' drop index t2_idx on t2 ' ; +prepare stmt3 from ' alter table t2 drop primary key '; +drop table if exists new_t2; +prepare stmt3 from ' rename table t2 to new_t2 '; +execute stmt3; +execute stmt3; +ERROR 42S01: Table 'new_t2' already exists +rename table new_t2 to t2; +drop table t2; +prepare stmt1 from ' rename table t5 to t6, t7 to t8 ' ; +create table t5 (a int) ; +execute stmt1 ; +ERROR HY000: Can't find file: './test/t7' (errno: 2) +create table t7 (a int) ; +execute stmt1 ; +execute stmt1 ; +ERROR 42S01: Table 't6' already exists +rename table t6 to t5, t8 to t7 ; +execute stmt1 ; +drop table t6, t8 ; +test_sequence +------ big statement tests ------ +(select 'ABC' as my_const_col from t1 where +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 ) ; +my_const_col +ABC +ABC +ABC +ABC +prepare stmt1 from "select 'ABC' as my_const_col from t1 where +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 " ; +execute stmt1 ; +my_const_col +ABC +ABC +ABC +ABC +execute stmt1 ; +my_const_col +ABC +ABC +ABC +ABC +(select 'ABC' as my_const_col FROM t1 WHERE +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' ) ; +my_const_col +ABC +ABC +ABC +ABC +prepare stmt1 from "select 'ABC' as my_const_col FROM t1 WHERE +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' " ; +execute stmt1 ; +my_const_col +ABC +ABC +ABC +ABC +execute stmt1 ; +my_const_col +ABC +ABC +ABC +ABC +select 'ABC' as my_const_col FROM t1 WHERE +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 ; +my_const_col +ABC +ABC +ABC +ABC +prepare stmt1 from ' select ''ABC'' as my_const_col FROM t1 WHERE + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? ' ; +execute stmt1 using +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00; +my_const_col +ABC +ABC +ABC +ABC +execute stmt1 using +@arg00, @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, +@arg10, @arg11, @arg12, @arg13, @arg14, @arg15, @arg16, @arg17, +@arg20, @arg21, @arg22, @arg23, @arg24, @arg25, @arg26, @arg27, +@arg30, @arg31, @arg32, @arg33, @arg34, @arg35, @arg36, @arg37, +@arg40, @arg41, @arg42, @arg43, @arg44, @arg45, @arg46, @arg47, +@arg50, @arg51, @arg52, @arg53, @arg54, @arg55, @arg56, @arg57, +@arg60, @arg61 ; +my_const_col +ABC +ABC +ABC +ABC +drop table if exists t5 ; +set @col_num= 1000 ; +select @string as "" ; + +create table t5( c999 int,c998 int,c997 int,c996 int,c995 int,c994 int,c993 int,c992 int,c991 int,c990 int,c989 int,c988 int,c987 int,c986 int,c985 int,c984 int,c983 int,c982 int,c981 int,c980 int,c979 int,c978 int,c977 int,c976 int,c975 int,c974 int,c973 int,c972 int,c971 int,c970 int,c969 int,c968 int,c967 int,c966 int,c965 int,c964 int,c963 int,c962 int,c961 int,c960 int,c959 int,c958 int,c957 int,c956 int,c955 int,c954 int,c953 int,c952 int,c951 int,c950 int,c949 int,c948 int,c947 int,c946 int,c945 int,c944 int,c943 int,c942 int,c941 int,c940 int,c939 int,c938 int,c937 int,c936 int,c935 int,c934 int,c933 int,c932 int,c931 int,c930 int,c929 int,c928 int,c927 int,c926 int,c925 int,c924 int,c923 int,c922 int,c921 int,c920 int,c919 int,c918 int,c917 int,c916 int,c915 int,c914 int,c913 int,c912 int,c911 int,c910 int,c909 int,c908 int,c907 int,c906 int,c905 int,c904 int,c903 int,c902 int,c901 int,c900 int,c899 int,c898 int,c897 int,c896 int,c895 int,c894 int,c893 int,c892 int,c891 int,c890 int,c889 int,c888 int,c887 int,c886 int,c885 int,c884 int,c883 int,c882 int,c881 int,c880 int,c879 int,c878 int,c877 int,c876 int,c875 int,c874 int,c873 int,c872 int,c871 int,c870 int,c869 int,c868 int,c867 int,c866 int,c865 int,c864 int,c863 int,c862 int,c861 int,c860 int,c859 int,c858 int,c857 int,c856 int,c855 int,c854 int,c853 int,c852 int,c851 int,c850 int,c849 int,c848 int,c847 int,c846 int,c845 int,c844 int,c843 int,c842 int,c841 int,c840 int,c839 int,c838 int,c837 int,c836 int,c835 int,c834 int,c833 int,c832 int,c831 int,c830 int,c829 int,c828 int,c827 int,c826 int,c825 int,c824 int,c823 int,c822 int,c821 int,c820 int,c819 int,c818 int,c817 int,c816 int,c815 int,c814 int,c813 int,c812 int,c811 int,c810 int,c809 int,c808 int,c807 int,c806 int,c805 int,c804 int,c803 int,c802 int,c801 int,c800 int,c799 int,c798 int,c797 int,c796 int,c795 int,c794 int,c793 int,c792 int,c791 int,c790 int,c789 int,c788 int,c787 int,c786 int,c785 int,c784 int,c783 int,c782 int,c781 int,c780 int,c779 int,c778 int,c777 int,c776 int,c775 int,c774 int,c773 int,c772 int,c771 int,c770 int,c769 int,c768 int,c767 int,c766 int,c765 int,c764 int,c763 int,c762 int,c761 int,c760 int,c759 int,c758 int,c757 int,c756 int,c755 int,c754 int,c753 int,c752 int,c751 int,c750 int,c749 int,c748 int,c747 int,c746 int,c745 int,c744 int,c743 int,c742 int,c741 int,c740 int,c739 int,c738 int,c737 int,c736 int,c735 int,c734 int,c733 int,c732 int,c731 int,c730 int,c729 int,c728 int,c727 int,c726 int,c725 int,c724 int,c723 int,c722 int,c721 int,c720 int,c719 int,c718 int,c717 int,c716 int,c715 int,c714 int,c713 int,c712 int,c711 int,c710 int,c709 int,c708 int,c707 int,c706 int,c705 int,c704 int,c703 int,c702 int,c701 int,c700 int,c699 int,c698 int,c697 int,c696 int,c695 int,c694 int,c693 int,c692 int,c691 int,c690 int,c689 int,c688 int,c687 int,c686 int,c685 int,c684 int,c683 int,c682 int,c681 int,c680 int,c679 int,c678 int,c677 int,c676 int,c675 int,c674 int,c673 int,c672 int,c671 int,c670 int,c669 int,c668 int,c667 int,c666 int,c665 int,c664 int,c663 int,c662 int,c661 int,c660 int,c659 int,c658 int,c657 int,c656 int,c655 int,c654 int,c653 int,c652 int,c651 int,c650 int,c649 int,c648 int,c647 int,c646 int,c645 int,c644 int,c643 int,c642 int,c641 int,c640 int,c639 int,c638 int,c637 int,c636 int,c635 int,c634 int,c633 int,c632 int,c631 int,c630 int,c629 int,c628 int,c627 int,c626 int,c625 int,c624 int,c623 int,c622 int,c621 int,c620 int,c619 int,c618 int,c617 int,c616 int,c615 int,c614 int,c613 int,c612 int,c611 int,c610 int,c609 int,c608 int,c607 int,c606 int,c605 int,c604 int,c603 int,c602 int,c601 int,c600 int,c599 int,c598 int,c597 int,c596 int,c595 int,c594 int,c593 int,c592 int,c591 int,c590 int,c589 int,c588 int,c587 int,c586 int,c585 int,c584 int,c583 int,c582 int,c581 int,c580 int,c579 int,c578 int,c577 int,c576 int,c575 int,c574 int,c573 int,c572 int,c571 int,c570 int,c569 int,c568 int,c567 int,c566 int,c565 int,c564 int,c563 int,c562 int,c561 int,c560 int,c559 int,c558 int,c557 int,c556 int,c555 int,c554 int,c553 int,c552 int,c551 int,c550 int,c549 int,c548 int,c547 int,c546 int,c545 int,c544 int,c543 int,c542 int,c541 int,c540 int,c539 int,c538 int,c537 int,c536 int,c535 int,c534 int,c533 int,c532 int,c531 int,c530 int,c529 int,c528 int,c527 int,c526 int,c525 int,c524 int,c523 int,c522 int,c521 int,c520 int,c519 int,c518 int,c517 int,c516 int,c515 int,c514 int,c513 int,c512 int,c511 int,c510 int,c509 int,c508 int,c507 int,c506 int,c505 int,c504 int,c503 int,c502 int,c501 int,c500 int,c499 int,c498 int,c497 int,c496 int,c495 int,c494 int,c493 int,c492 int,c491 int,c490 int,c489 int,c488 int,c487 int,c486 int,c485 int,c484 int,c483 int,c482 int,c481 int,c480 int,c479 int,c478 int,c477 int,c476 int,c475 int,c474 int,c473 int,c472 int,c471 int,c470 int,c469 int,c468 int,c467 int,c466 int,c465 int,c464 int,c463 int,c462 int,c461 int,c460 int,c459 int,c458 int,c457 int,c456 int,c455 int,c454 int,c453 int,c452 int,c451 int,c450 int,c449 int,c448 int,c447 int,c446 int,c445 int,c444 int,c443 int,c442 int,c441 int,c440 int,c439 int,c438 int,c437 int,c436 int,c435 int,c434 int,c433 int,c432 int,c431 int,c430 int,c429 int,c428 int,c427 int,c426 int,c425 int,c424 int,c423 int,c422 int,c421 int,c420 int,c419 int,c418 int,c417 int,c416 int,c415 int,c414 int,c413 int,c412 int,c411 int,c410 int,c409 int,c408 int,c407 int,c406 int,c405 int,c404 int,c403 int,c402 int,c401 int,c400 int,c399 int,c398 int,c397 int,c396 int,c395 int,c394 int,c393 int,c392 int,c391 int,c390 int,c389 int,c388 int,c387 int,c386 int,c385 int,c384 int,c383 int,c382 int,c381 int,c380 int,c379 int,c378 int,c377 int,c376 int,c375 int,c374 int,c373 int,c372 int,c371 int,c370 int,c369 int,c368 int,c367 int,c366 int,c365 int,c364 int,c363 int,c362 int,c361 int,c360 int,c359 int,c358 int,c357 int,c356 int,c355 int,c354 int,c353 int,c352 int,c351 int,c350 int,c349 int,c348 int,c347 int,c346 int,c345 int,c344 int,c343 int,c342 int,c341 int,c340 int,c339 int,c338 int,c337 int,c336 int,c335 int,c334 int,c333 int,c332 int,c331 int,c330 int,c329 int,c328 int,c327 int,c326 int,c325 int,c324 int,c323 int,c322 int,c321 int,c320 int,c319 int,c318 int,c317 int,c316 int,c315 int,c314 int,c313 int,c312 int,c311 int,c310 int,c309 int,c308 int,c307 int,c306 int,c305 int,c304 int,c303 int,c302 int,c301 int,c300 int,c299 int,c298 int,c297 int,c296 int,c295 int,c294 int,c293 int,c292 int,c291 int,c290 int,c289 int,c288 int,c287 int,c286 int,c285 int,c284 int,c283 int,c282 int,c281 int,c280 int,c279 int,c278 int,c277 int,c276 int,c275 int,c274 int,c273 int,c272 int,c271 int,c270 int,c269 int,c268 int,c267 int,c266 int,c265 int,c264 int,c263 int,c262 int,c261 int,c260 int,c259 int,c258 int,c257 int,c256 int,c255 int,c254 int,c253 int,c252 int,c251 int,c250 int,c249 int,c248 int,c247 int,c246 int,c245 int,c244 int,c243 int,c242 int,c241 int,c240 int,c239 int,c238 int,c237 int,c236 int,c235 int,c234 int,c233 int,c232 int,c231 int,c230 int,c229 int,c228 int,c227 int,c226 int,c225 int,c224 int,c223 int,c222 int,c221 int,c220 int,c219 int,c218 int,c217 int,c216 int,c215 int,c214 int,c213 int,c212 int,c211 int,c210 int,c209 int,c208 int,c207 int,c206 int,c205 int,c204 int,c203 int,c202 int,c201 int,c200 int,c199 int,c198 int,c197 int,c196 int,c195 int,c194 int,c193 int,c192 int,c191 int,c190 int,c189 int,c188 int,c187 int,c186 int,c185 int,c184 int,c183 int,c182 int,c181 int,c180 int,c179 int,c178 int,c177 int,c176 int,c175 int,c174 int,c173 int,c172 int,c171 int,c170 int,c169 int,c168 int,c167 int,c166 int,c165 int,c164 int,c163 int,c162 int,c161 int,c160 int,c159 int,c158 int,c157 int,c156 int,c155 int,c154 int,c153 int,c152 int,c151 int,c150 int,c149 int,c148 int,c147 int,c146 int,c145 int,c144 int,c143 int,c142 int,c141 int,c140 int,c139 int,c138 int,c137 int,c136 int,c135 int,c134 int,c133 int,c132 int,c131 int,c130 int,c129 int,c128 int,c127 int,c126 int,c125 int,c124 int,c123 int,c122 int,c121 int,c120 int,c119 int,c118 int,c117 int,c116 int,c115 int,c114 int,c113 int,c112 int,c111 int,c110 int,c109 int,c108 int,c107 int,c106 int,c105 int,c104 int,c103 int,c102 int,c101 int,c100 int,c99 int,c98 int,c97 int,c96 int,c95 int,c94 int,c93 int,c92 int,c91 int,c90 int,c89 int,c88 int,c87 int,c86 int,c85 int,c84 int,c83 int,c82 int,c81 int,c80 int,c79 int,c78 int,c77 int,c76 int,c75 int,c74 int,c73 int,c72 int,c71 int,c70 int,c69 int,c68 int,c67 int,c66 int,c65 int,c64 int,c63 int,c62 int,c61 int,c60 int,c59 int,c58 int,c57 int,c56 int,c55 int,c54 int,c53 int,c52 int,c51 int,c50 int,c49 int,c48 int,c47 int,c46 int,c45 int,c44 int,c43 int,c42 int,c41 int,c40 int,c39 int,c38 int,c37 int,c36 int,c35 int,c34 int,c33 int,c32 int,c31 int,c30 int,c29 int,c28 int,c27 int,c26 int,c25 int,c24 int,c23 int,c22 int,c21 int,c20 int,c19 int,c18 int,c17 int,c16 int,c15 int,c14 int,c13 int,c12 int,c11 int,c10 int,c9 int,c8 int,c7 int,c6 int,c5 int,c4 int,c3 int,c2 int,c1 int,c0 int) +prepare stmt1 from @string ; +execute stmt1 ; +select @string as "" ; + +insert into t5 values(1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ) +prepare stmt1 from @string ; +execute stmt1 ; +prepare stmt1 from ' select * from t5 ' ; +execute stmt1 ; +drop table t1, t5, t9; diff --git a/mysql-test/suite/pbxt/r/ps_grant.result b/mysql-test/suite/pbxt/r/ps_grant.result new file mode 100644 index 00000000000..8b16123ccea --- /dev/null +++ b/mysql-test/suite/pbxt/r/ps_grant.result @@ -0,0 +1,87 @@ +test_sequence +------ grant/revoke/drop affects a parallel session test ------ +show grants for second_user@localhost ; +ERROR 42000: There is no such grant defined for user 'second_user' on host 'localhost' +create database mysqltest; +use mysqltest; +use test; +grant usage on mysqltest.* to second_user@localhost +identified by 'looser' ; +grant select on mysqltest.t9 to second_user@localhost +identified by 'looser' ; +show grants for second_user@localhost ; +Grants for second_user@localhost +GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' +GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +select current_user(); +current_user() +second_user@localhost +show grants for current_user(); +Grants for second_user@localhost +GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' +GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +prepare s_t9 from 'select c1 as my_col + from t9 where c1= 1' ; +execute s_t9 ; +my_col +1 +select a as my_col from t1; +ERROR 42000: SELECT command denied to user 'second_user'@'localhost' for table 't1' +grant select on mysqltest.t1 to second_user@localhost +identified by 'looser' ; +show grants for second_user@localhost ; +Grants for second_user@localhost +GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' +GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' +GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +drop table mysqltest.t9 ; +show grants for second_user@localhost ; +Grants for second_user@localhost +GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' +GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' +GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +show grants for second_user@localhost ; +Grants for second_user@localhost +GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' +GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' +GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +prepare s_t1 from 'select a as my_col from t1' ; +execute s_t1 ; +my_col +1 +2 +3 +4 +execute s_t9 ; +ERROR 42S02: Table 'mysqltest.t9' doesn't exist +deallocate prepare s_t9; +revoke all privileges on mysqltest.t1 from second_user@localhost +identified by 'looser' ; +show grants for second_user@localhost ; +Grants for second_user@localhost +GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' +GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +show grants for second_user@localhost ; +Grants for second_user@localhost +GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' +GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +execute s_t1 ; +ERROR 42000: SELECT command denied to user 'second_user'@'localhost' for table 't1' +revoke all privileges, grant option from second_user@localhost ; +show grants for second_user@localhost ; +Grants for second_user@localhost +GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' +drop user second_user@localhost ; +commit ; +show grants for second_user@localhost ; +ERROR 42000: There is no such grant defined for user 'second_user' on host 'localhost' +drop database mysqltest; +prepare stmt3 from ' grant all on test.t1 to drop_user@localhost +identified by ''looser'' '; +grant all on test.t1 to drop_user@localhost +identified by 'looser' ; +prepare stmt3 from ' revoke all privileges on test.t1 from +drop_user@localhost '; +revoke all privileges on test.t1 from drop_user@localhost ; +prepare stmt3 from ' drop user drop_user@localhost '; +drop user drop_user@localhost; diff --git a/mysql-test/suite/pbxt/r/range.result b/mysql-test/suite/pbxt/r/range.result new file mode 100644 index 00000000000..758c2a064de --- /dev/null +++ b/mysql-test/suite/pbxt/r/range.result @@ -0,0 +1,968 @@ +drop table if exists t1, t2, t3; +CREATE TABLE t1 ( +event_date date DEFAULT '0000-00-00' NOT NULL, +type int(11) DEFAULT '0' NOT NULL, +event_id int(11) DEFAULT '0' NOT NULL, +PRIMARY KEY (event_date,type,event_id) +); +INSERT INTO t1 VALUES ('1999-07-10',100100,24), ('1999-07-11',100100,25), +('1999-07-13',100600,0), ('1999-07-13',100600,4), ('1999-07-13',100600,26), +('1999-07-14',100600,10), ('1999-07-15',100600,16), ('1999-07-15',100800,45), +('1999-07-15',101000,47), ('1999-07-16',100800,46), ('1999-07-20',100600,5), +('1999-07-20',100600,27), ('1999-07-21',100600,11), ('1999-07-22',100600,17), +('1999-07-23',100100,39), ('1999-07-24',100100,39), ('1999-07-24',100500,40), +('1999-07-25',100100,39), ('1999-07-27',100600,1), ('1999-07-27',100600,6), +('1999-07-27',100600,28), ('1999-07-28',100600,12), ('1999-07-29',100500,41), +('1999-07-29',100600,18), ('1999-07-30',100500,41), ('1999-07-31',100500,41), +('1999-08-01',100700,34), ('1999-08-03',100600,7), ('1999-08-03',100600,29), +('1999-08-04',100600,13), ('1999-08-05',100500,42), ('1999-08-05',100600,19), +('1999-08-06',100500,42), ('1999-08-07',100500,42), ('1999-08-08',100500,42), +('1999-08-10',100600,2), ('1999-08-10',100600,9), ('1999-08-10',100600,30), +('1999-08-11',100600,14), ('1999-08-12',100600,20), ('1999-08-17',100500,8), +('1999-08-17',100600,31), ('1999-08-18',100600,15), ('1999-08-19',100600,22), +('1999-08-24',100600,3), ('1999-08-24',100600,32), ('1999-08-27',100500,43), +('1999-08-31',100600,33), ('1999-09-17',100100,37), ('1999-09-18',100100,37), +('1999-09-19',100100,37), ('2000-12-18',100700,38); +select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date; +event_date type event_id +1999-07-10 100100 24 +1999-07-11 100100 25 +1999-07-13 100600 0 +1999-07-13 100600 4 +1999-07-13 100600 26 +1999-07-14 100600 10 +explain select event_date,type,event_id from t1 WHERE type = 100601 and event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date <= "1999-07-15" AND (type=100600 OR type=100100) or event_date >= "1999-07-01" AND event_date <= "1999-07-15" AND type=100099; +event_date type event_id +1999-07-10 100100 24 +1999-07-11 100100 25 +1999-07-13 100600 0 +1999-07-13 100600 4 +1999-07-13 100600 26 +1999-07-14 100600 10 +1999-07-15 100600 16 +drop table t1; +CREATE TABLE t1 ( +PAPER_ID smallint(6) DEFAULT '0' NOT NULL, +YEAR smallint(6) DEFAULT '0' NOT NULL, +ISSUE smallint(6) DEFAULT '0' NOT NULL, +CLOSED tinyint(4) DEFAULT '0' NOT NULL, +ISS_DATE date DEFAULT '0000-00-00' NOT NULL, +PRIMARY KEY (PAPER_ID,YEAR,ISSUE) +); +INSERT INTO t1 VALUES (3,1999,34,0,'1999-07-12'), (1,1999,111,0,'1999-03-23'), +(1,1999,222,0,'1999-03-23'), (3,1999,33,0,'1999-07-12'), +(3,1999,32,0,'1999-07-12'), (3,1999,31,0,'1999-07-12'), +(3,1999,30,0,'1999-07-12'), (3,1999,29,0,'1999-07-12'), +(3,1999,28,0,'1999-07-12'), (1,1999,40,1,'1999-05-01'), +(1,1999,41,1,'1999-05-01'), (1,1999,42,1,'1999-05-01'), +(1,1999,46,1,'1999-05-01'), (1,1999,47,1,'1999-05-01'), +(1,1999,48,1,'1999-05-01'), (1,1999,49,1,'1999-05-01'), +(1,1999,50,0,'1999-05-01'), (1,1999,51,0,'1999-05-01'), +(1,1999,200,0,'1999-06-28'), (1,1999,52,0,'1999-06-28'), +(1,1999,53,0,'1999-06-28'), (1,1999,54,0,'1999-06-28'), +(1,1999,55,0,'1999-06-28'), (1,1999,56,0,'1999-07-01'), +(1,1999,57,0,'1999-07-01'), (1,1999,58,0,'1999-07-01'), +(1,1999,59,0,'1999-07-01'), (1,1999,60,0,'1999-07-01'), +(3,1999,35,0,'1999-07-12'); +select YEAR,ISSUE from t1 where PAPER_ID=3 and (YEAR>1999 or (YEAR=1999 and ISSUE>28)) order by YEAR,ISSUE; +YEAR ISSUE +1999 29 +1999 30 +1999 31 +1999 32 +1999 33 +1999 34 +1999 35 +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +repair table t1; +Table Op Msg_type Msg_text +test.t1 repair note Table does not support optimize, doing recreate + analyze instead +test.t1 repair status OK +drop table t1; +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +parent_id int(11) DEFAULT '0' NOT NULL, +level tinyint(4) DEFAULT '0' NOT NULL, +PRIMARY KEY (id), +KEY parent_id (parent_id), +KEY level (level) +); +INSERT INTO t1 VALUES (1,0,0), (3,1,1), (4,1,1), (8,2,2), (9,2,2), (17,3,2), +(22,4,2), (24,4,2), (28,5,2), (29,5,2), (30,5,2), (31,6,2), (32,6,2), (33,6,2), +(203,7,2), (202,7,2), (20,3,2), (157,0,0), (193,5,2), (40,7,2), (2,1,1), +(15,2,2), (6,1,1), (34,6,2), (35,6,2), (16,3,2), (7,1,1), (36,7,2), (18,3,2), +(26,5,2), (27,5,2), (183,4,2), (38,7,2), (25,5,2), (37,7,2), (21,4,2), +(19,3,2), (5,1,1), (179,5,2); +SELECT * FROM t1 WHERE level = 1 AND parent_id = 1; +id parent_id level +3 1 1 +4 1 1 +2 1 1 +6 1 1 +7 1 1 +5 1 1 +SELECT * FROM t1 WHERE level = 1 AND parent_id = 1 order by id; +id parent_id level +2 1 1 +3 1 1 +4 1 1 +5 1 1 +6 1 1 +7 1 1 +drop table t1; +create table t1( +Satellite varchar(25) not null, +SensorMode varchar(25) not null, +FullImageCornersUpperLeftLongitude double not null, +FullImageCornersUpperRightLongitude double not null, +FullImageCornersUpperRightLatitude double not null, +FullImageCornersLowerRightLatitude double not null, +index two (Satellite, SensorMode, FullImageCornersUpperLeftLongitude, FullImageCornersUpperRightLongitude, FullImageCornersUpperRightLatitude, FullImageCornersLowerRightLatitude)); +insert into t1 values("OV-3","PAN1",91,-92,40,50); +insert into t1 values("OV-4","PAN1",91,-92,40,50); +select * from t1 where t1.Satellite = "OV-3" and t1.SensorMode = "PAN1" and t1.FullImageCornersUpperLeftLongitude > -90.000000 and t1.FullImageCornersUpperRightLongitude < -82.000000; +Satellite SensorMode FullImageCornersUpperLeftLongitude FullImageCornersUpperRightLongitude FullImageCornersUpperRightLatitude FullImageCornersLowerRightLatitude +OV-3 PAN1 91 -92 40 50 +drop table t1; +create table t1 ( aString char(100) not null default "", key aString (aString(10)) ); +insert t1 (aString) values ( "believe in myself" ), ( "believe" ), ("baaa" ), ( "believe in love"); +select * from t1 where aString < "believe in myself" order by aString; +aString +baaa +believe +believe in love +select * from t1 where aString > "believe in love" order by aString; +aString +believe in myself +alter table t1 drop key aString; +select * from t1 where aString < "believe in myself" order by aString; +aString +baaa +believe +believe in love +select * from t1 where aString > "believe in love" order by aString; +aString +believe in myself +drop table t1; +CREATE TABLE t1 ( +t1ID int(10) unsigned NOT NULL auto_increment, +art binary(1) NOT NULL default '', +KNR char(5) NOT NULL default '', +RECHNR char(6) NOT NULL default '', +POSNR char(2) NOT NULL default '', +ARTNR char(10) NOT NULL default '', +TEX char(70) NOT NULL default '', +PRIMARY KEY (t1ID), +KEY IdxArt (art), +KEY IdxKnr (KNR), +KEY IdxArtnr (ARTNR) +) ENGINE=MyISAM; +INSERT INTO t1 (art) VALUES ('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'); +select count(*) from t1 where upper(art) = 'J'; +count(*) +213 +select count(*) from t1 where art = 'J' or art = 'j'; +count(*) +602 +select count(*) from t1 where art = 'j' or art = 'J'; +count(*) +602 +select count(*) from t1 where art = 'j'; +count(*) +389 +select count(*) from t1 where art = 'J'; +count(*) +213 +drop table t1; +create table t1 (x int, y int, index(x), index(y)); +insert into t1 (x) values (1),(2),(3),(4),(5),(6),(7),(8),(9); +update t1 set y=x; +explain select * from t1, t1 t2 where t1.y = 8 and t2.x between 7 and t1.y+0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref y y 5 const 1 Using where +1 SIMPLE t2 range x x 5 NULL 1 Using where; Using join buffer +explain select * from t1, t1 t2 where t1.y = 8 and t2.x >= 7 and t2.x <= t1.y+0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref y y 5 const 1 Using where +1 SIMPLE t2 range x x 5 NULL 1 Using where; Using join buffer +explain select * from t1, t1 t2 where t1.y = 2 and t2.x between t1.y-1 and t1.y+1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref y y 5 const 1 Using where +1 SIMPLE t2 range x x 5 NULL 1 Using where; Using join buffer +explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= t1.y-1 and t2.x <= t1.y+1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref y y 5 const 1 Using where +1 SIMPLE t2 range x x 5 NULL 1 Using where; Using join buffer +explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 0 and t1.y; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref y y 5 const 1 Using where +1 SIMPLE t2 range x x 5 NULL 1 Using where; Using join buffer +explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 0 and t2.x <= t1.y; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref y y 5 const 1 Using where +1 SIMPLE t2 range x x 5 NULL 1 Using where; Using join buffer +explain select count(*) from t1 where x in (1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref x x 5 const 1 Using where; Using index +explain select count(*) from t1 where x in (1,2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index x x 5 NULL 9 Using where; Using index +drop table t1; +CREATE TABLE t1 (key1 int(11) NOT NULL default '0', KEY i1 (key1)); +INSERT INTO t1 VALUES (0),(0),(0),(0),(0),(1),(1); +CREATE TABLE t2 (keya int(11) NOT NULL default '0', KEY j1 (keya)); +INSERT INTO t2 VALUES (0),(0),(1),(1),(2),(2); +explain select * from t1, t2 where (t1.key1 <t2.keya + 1) and t2.keya=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range i1 i1 4 NULL 1 Using where; Using index +1 SIMPLE t2 ref j1 j1 4 const 1 Using index +explain select * from t1 force index(i1), t2 force index(j1) where +(t1.key1 <t2.keya + 1) and t2.keya=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range i1 i1 4 NULL 1 Using where; Using index +1 SIMPLE t2 ref j1 j1 4 const 1 Using index +DROP TABLE t1,t2; +CREATE TABLE t1 ( +a int(11) default NULL, +b int(11) default NULL, +KEY a (a), +KEY b (b) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES +(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(10,2), +(13,2),(14,2),(15,2),(16,2),(17,3),(17,3),(16,3),(17,3),(19,3),(20,3), +(21,4),(22,5),(23,5),(24,5),(25,5),(26,5),(30,5),(31,5),(32,5),(33,5), +(33,5),(33,5),(33,5),(33,5),(34,5),(35,5); +EXPLAIN SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a,b a 5 NULL 2 Using where +SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +a b +DROP TABLE t1; +CREATE TABLE t1 (a int, b int, c int, INDEX (c,a,b)); +INSERT INTO t1 VALUES (1,0,0),(1,0,0),(1,0,0); +INSERT INTO t1 VALUES (0,1,0),(0,1,0),(0,1,0); +SELECT COUNT(*) FROM t1 WHERE (c=0 and a=1) or (c=0 and b=1); +COUNT(*) +6 +SELECT COUNT(*) FROM t1 WHERE (c=0 and b=1) or (c=0 and a=1); +COUNT(*) +6 +DROP TABLE t1; +CREATE TABLE t1 ( a int not null, b int not null, INDEX ab(a,b) ); +INSERT INTO t1 VALUES (47,1), (70,1), (15,1), (15, 4); +SELECT * FROM t1 +WHERE +( +( b =1 AND a BETWEEN 14 AND 21 ) OR +( b =2 AND a BETWEEN 16 AND 18 ) OR +( b =3 AND a BETWEEN 15 AND 19 ) OR +(a BETWEEN 19 AND 47) +); +a b +15 1 +47 1 +DROP TABLE t1; +CREATE TABLE t1 ( +id int( 11 ) unsigned NOT NULL AUTO_INCREMENT , +line int( 5 ) unsigned NOT NULL default '0', +columnid int( 3 ) unsigned NOT NULL default '0', +owner int( 3 ) unsigned NOT NULL default '0', +ordinal int( 3 ) unsigned NOT NULL default '0', +showid smallint( 6 ) unsigned NOT NULL default '1', +tableid int( 1 ) unsigned NOT NULL default '1', +content int( 5 ) unsigned NOT NULL default '188', +PRIMARY KEY ( owner, id ) , +KEY menu( owner, showid, columnid ) , +KEY `COLUMN` ( owner, columnid, line ) , +KEY `LINES` ( owner, tableid, content, id ) , +KEY recount( owner, line ) +) ENGINE = MYISAM; +INSERT into t1 (owner,id,columnid,line) values (11,15,15,1),(11,13,13,5); +SELECT id, columnid, tableid, content, showid, line, ordinal FROM t1 WHERE owner=11 AND ((columnid IN ( 15, 13, 14 ) AND line IN ( 1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 31 )) OR (columnid IN ( 13, 14 ) AND line IN ( 15 ))) LIMIT 0 , 30; +id columnid tableid content showid line ordinal +13 13 1 188 1 5 0 +15 15 1 188 1 1 0 +drop table t1; +create table t1 (id int(10) primary key); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9); +select id from t1 where id in (2,5,9) ; +id +2 +5 +9 +select id from t1 where id=2 or id=5 or id=9 ; +id +2 +5 +9 +drop table t1; +create table t1 ( id1 int not null, id2 int not null, idnull int null, c char(20), primary key (id1,id2)); +insert into t1 values (0,1,NULL,"aaa"), (1,1,NULL,"aaa"), (2,1,NULL,"aaa"), +(3,1,NULL,"aaa"), (4,1,NULL,"aaa"), (5,1,NULL,"aaa"), +(6,1,NULL,"aaa"), (7,1,NULL,"aaa"), (8,1,NULL,"aaa"), +(9,1,NULL,"aaa"), (10,1,NULL,"aaa"), (11,1,NULL,"aaa"), +(12,1,NULL,"aaa"), (13,1,NULL,"aaa"), (14,1,NULL,"aaa"), +(15,1,NULL,"aaa"), (16,1,NULL,"aaa"), (17,1,NULL,"aaa"), +(18,1,NULL,"aaa"), (19,1,NULL,"aaa"), (20,1,NULL,"aaa"); +select a.id1, b.idnull from t1 as a, t1 as b where a.id2=1 and a.id1=1 and b.id1=a.idnull order by b.id2 desc limit 1; +id1 idnull +drop table t1; +create table t1 ( +id int not null auto_increment, +name char(1) not null, +uid int not null, +primary key (id), +index uid_index (uid)); +create table t2 ( +id int not null auto_increment, +name char(1) not null, +uid int not null, +primary key (id), +index uid_index (uid)); +insert into t1(id, uid, name) values(1, 0, ' '); +insert into t1(uid, name) values(0, ' '); +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t2(uid, name) select uid, name from t1; +insert into t2(uid, name) select uid, name from t1; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +delete from t2; +insert into t2(uid, name) values +(1, CHAR(64+1)), +(2, CHAR(64+2)), +(3, CHAR(64+3)), +(4, CHAR(64+4)), +(5, CHAR(64+5)), +(6, CHAR(64+6)), +(7, CHAR(64+7)), +(8, CHAR(64+8)), +(9, CHAR(64+9)), +(10, CHAR(64+10)), +(11, CHAR(64+11)), +(12, CHAR(64+12)), +(13, CHAR(64+13)), +(14, CHAR(64+14)), +(15, CHAR(64+15)), +(16, CHAR(64+16)), +(17, CHAR(64+17)), +(18, CHAR(64+18)), +(19, CHAR(64+19)), +(20, CHAR(64+20)), +(21, CHAR(64+21)), +(22, CHAR(64+22)), +(23, CHAR(64+23)), +(24, CHAR(64+24)), +(25, CHAR(64+25)), +(26, CHAR(64+26)); +insert into t1(uid, name) select uid, name from t2 order by uid; +delete from t2; +insert into t2(id, uid, name) select id, uid, name from t1; +select count(*) from t1; +count(*) +1026 +select count(*) from t2; +count(*) +1026 +analyze table t1,t2; +Table Op Msg_type Msg_text +test.t1 analyze status OK +test.t2 analyze status OK +explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range uid_index uid_index 4 NULL 1 Using where +1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 12 +explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range uid_index uid_index 4 NULL 1 Using where +1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 12 +explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range uid_index uid_index 4 NULL 2 Using where +1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 12 +explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid != 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range uid_index uid_index 4 NULL 2 Using where +1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 12 +select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0; +id name uid id name uid +1001 A 1 1001 A 1 +1002 B 2 1002 B 2 +1003 C 3 1003 C 3 +1004 D 4 1004 D 4 +1005 E 5 1005 E 5 +1006 F 6 1006 F 6 +1007 G 7 1007 G 7 +1008 H 8 1008 H 8 +1009 I 9 1009 I 9 +1010 J 10 1010 J 10 +1011 K 11 1011 K 11 +1012 L 12 1012 L 12 +1013 M 13 1013 M 13 +1014 N 14 1014 N 14 +1015 O 15 1015 O 15 +1016 P 16 1016 P 16 +1017 Q 17 1017 Q 17 +1018 R 18 1018 R 18 +1019 S 19 1019 S 19 +1020 T 20 1020 T 20 +1021 U 21 1021 U 21 +1022 V 22 1022 V 22 +1023 W 23 1023 W 23 +1024 X 24 1024 X 24 +1025 Y 25 1025 Y 25 +1026 Z 26 1026 Z 26 +select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0; +id name uid id name uid +1001 A 1 1001 A 1 +1002 B 2 1002 B 2 +1003 C 3 1003 C 3 +1004 D 4 1004 D 4 +1005 E 5 1005 E 5 +1006 F 6 1006 F 6 +1007 G 7 1007 G 7 +1008 H 8 1008 H 8 +1009 I 9 1009 I 9 +1010 J 10 1010 J 10 +1011 K 11 1011 K 11 +1012 L 12 1012 L 12 +1013 M 13 1013 M 13 +1014 N 14 1014 N 14 +1015 O 15 1015 O 15 +1016 P 16 1016 P 16 +1017 Q 17 1017 Q 17 +1018 R 18 1018 R 18 +1019 S 19 1019 S 19 +1020 T 20 1020 T 20 +1021 U 21 1021 U 21 +1022 V 22 1022 V 22 +1023 W 23 1023 W 23 +1024 X 24 1024 X 24 +1025 Y 25 1025 Y 25 +1026 Z 26 1026 Z 26 +drop table t1,t2; +create table t1 (x bigint unsigned not null); +insert into t1(x) values (0xfffffffffffffff0); +insert into t1(x) values (0xfffffffffffffff1); +select * from t1; +x +18446744073709551600 +18446744073709551601 +select count(*) from t1 where x>0; +count(*) +2 +select count(*) from t1 where x=0; +count(*) +0 +select count(*) from t1 where x<0; +count(*) +0 +select count(*) from t1 where x < -16; +count(*) +0 +select count(*) from t1 where x = -16; +count(*) +0 +select count(*) from t1 where x > -16; +count(*) +2 +select count(*) from t1 where x = 18446744073709551601; +count(*) +1 +create table t2 (x bigint not null); +insert into t2(x) values (-16); +insert into t2(x) values (-15); +select * from t2; +x +-16 +-15 +select count(*) from t2 where x>0; +count(*) +0 +select count(*) from t2 where x=0; +count(*) +0 +select count(*) from t2 where x<0; +count(*) +2 +select count(*) from t2 where x < -16; +count(*) +0 +select count(*) from t2 where x = -16; +count(*) +1 +select count(*) from t2 where x > -16; +count(*) +1 +select count(*) from t2 where x = 18446744073709551601; +count(*) +0 +drop table t1,t2; +create table t1 (x bigint unsigned not null primary key) engine=innodb; +insert into t1(x) values (0xfffffffffffffff0); +insert into t1(x) values (0xfffffffffffffff1); +select * from t1; +x +18446744073709551600 +18446744073709551601 +select count(*) from t1 where x>0; +count(*) +2 +select count(*) from t1 where x=0; +count(*) +0 +select count(*) from t1 where x<0; +count(*) +0 +select count(*) from t1 where x < -16; +count(*) +0 +select count(*) from t1 where x = -16; +count(*) +0 +select count(*) from t1 where x > -16; +count(*) +2 +select count(*) from t1 where x = 18446744073709551601; +count(*) +1 +drop table t1; +create table t1 (a bigint unsigned); +create index t1i on t1(a); +insert into t1 select 18446744073709551615; +insert into t1 select 18446744073709551614; +explain select * from t1 where a <> -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index +select * from t1 where a <> -1; +a +18446744073709551614 +18446744073709551615 +explain select * from t1 where a > -1 or a < -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index +select * from t1 where a > -1 or a < -1; +a +18446744073709551614 +18446744073709551615 +explain select * from t1 where a > -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index +select * from t1 where a > -1; +a +18446744073709551614 +18446744073709551615 +explain select * from t1 where a < -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select * from t1 where a < -1; +a +drop table t1; +set names latin1; +create table t1 (a char(10), b text, key (a)) character set latin1; +INSERT INTO t1 (a) VALUES +('111'),('222'),('222'),('222'),('222'),('444'),('aaa'),('AAA'),('bbb'); +explain select * from t1 where a='aaa'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 11 const 1 Using where +explain select * from t1 where a=binary 'aaa'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 11 NULL 1 Using where +explain select * from t1 where a='aaa' collate latin1_bin; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 11 NULL 1 Using where +explain select * from t1 where a='aaa' collate latin1_german1_ci; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 9 Using where +drop table t1; +CREATE TABLE t1 ( +`CLIENT` char(3) character set latin1 collate latin1_bin NOT NULL default '000', +`ARG1` char(3) character set latin1 collate latin1_bin NOT NULL default '', +`ARG2` char(3) character set latin1 collate latin1_bin NOT NULL default '', +`FUNCTION` varchar(10) character set latin1 collate latin1_bin NOT NULL default '', +`FUNCTINT` int(11) NOT NULL default '0', +KEY `VERI_CLNT~2` (`ARG1`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +INSERT INTO t1 VALUES ('000',' 0',' 0','Text 001',0), ('000',' 0',' 1','Text 002',0), +('000',' 1',' 2','Text 003',0), ('000',' 2',' 3','Text 004',0), +('001',' 3',' 0','Text 017',0); +SELECT count(*) FROM t1 WHERE CLIENT='000' AND (ARG1 != ' 1' OR ARG1 != ' 2'); +count(*) +4 +SELECT count(*) FROM t1 WHERE CLIENT='000' AND (ARG1 != ' 2' OR ARG1 != ' 1'); +count(*) +4 +drop table t1; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +CREATE TABLE t2 ( +pk1 int(11) NOT NULL, +pk2 int(11) NOT NULL, +pk3 int(11) NOT NULL, +pk4 int(11) NOT NULL, +filler char(82), +PRIMARY KEY (pk1,pk2,pk3,pk4) +) DEFAULT CHARSET=latin1; +insert into t2 select 1, A.a+10*B.a, 432, 44, 'fillerZ' from t1 A, t1 B; +INSERT INTO t2 VALUES (2621, 2635, 0, 0,'filler'), (2621, 2635, 1, 0,'filler'), +(2621, 2635, 10, 0,'filler'), (2621, 2635, 11, 0,'filler'), +(2621, 2635, 14, 0,'filler'), (2621, 2635, 1000015, 0,'filler'); +SELECT * FROM t2 +WHERE ((((pk4 =0) AND (pk1 =2621) AND (pk2 =2635))) +OR ((pk4 =1) AND (((pk1 IN ( 7, 2, 1 ))) OR (pk1 =522)) AND ((pk2 IN ( 0, 2635)))) +) AND (pk3 >=1000000); +pk1 pk2 pk3 pk4 filler +2621 2635 1000015 0 filler +drop table t1, t2; +create table t1(a char(2), key(a(1))); +insert into t1 values ('x'), ('xx'); +explain select a from t1 where a > 'x'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 2 NULL 1 Using where +select a from t1 where a > 'x'; +a +xx +drop table t1; +End of 4.1 tests +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +status varchar(20), +PRIMARY KEY (id), +KEY (status) +); +INSERT INTO t1 VALUES +(1,'B'), (2,'B'), (3,'B'), (4,'B'), (5,'B'), (6,'B'), +(7,'B'), (8,'B'), (9,'B'), (10,'B'), (11,'B'), (12,'B'), +(13,'B'), (14,'B'), (15,'B'), (16,'B'), (17,'B'), (18,'B'), +(19,'B'), (20,'B'), (21,'B'), (22,'B'), (23,'B'), (24,'B'), +(25,'A'), (26,'A'), (27,'A'), (28,'A'), (29,'A'), (30,'A'), +(31,'A'), (32,'A'), (33,'A'), (34,'A'), (35,'A'), (36,'A'), +(37,'A'), (38,'A'), (39,'A'), (40,'A'), (41,'A'), (42,'A'), +(43,'A'), (44,'A'), (45,'A'), (46,'A'), (47,'A'), (48,'A'), +(49,'A'), (50,'A'), (51,'A'), (52,'A'), (53,'C'), (54,'C'), +(55,'C'), (56,'C'), (57,'C'), (58,'C'), (59,'C'), (60,'C'); +EXPLAIN SELECT * FROM t1 WHERE status <> 'A' AND status <> 'B'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range status status 23 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE status NOT IN ('A','B'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range status status 23 NULL 3 Using where +SELECT * FROM t1 WHERE status <> 'A' AND status <> 'B'; +id status +53 C +54 C +55 C +56 C +57 C +58 C +59 C +60 C +SELECT * FROM t1 WHERE status NOT IN ('A','B'); +id status +53 C +54 C +55 C +56 C +57 C +58 C +59 C +60 C +EXPLAIN SELECT status FROM t1 WHERE status <> 'A' AND status <> 'B'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range status status 23 NULL 3 Using where; Using index +EXPLAIN SELECT status FROM t1 WHERE status NOT IN ('A','B'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range status status 23 NULL 3 Using where; Using index +EXPLAIN SELECT * FROM t1 WHERE status NOT BETWEEN 'A' AND 'B'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range status status 23 NULL 2 Using where +EXPLAIN SELECT * FROM t1 WHERE status < 'A' OR status > 'B'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range status status 23 NULL 2 Using where +SELECT * FROM t1 WHERE status NOT BETWEEN 'A' AND 'B'; +id status +53 C +54 C +55 C +56 C +57 C +58 C +59 C +60 C +SELECT * FROM t1 WHERE status < 'A' OR status > 'B'; +id status +53 C +54 C +55 C +56 C +57 C +58 C +59 C +60 C +DROP TABLE t1; +CREATE TABLE t1 (a int, b int, primary key(a,b)); +INSERT INTO t1 VALUES +(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3); +CREATE VIEW v1 as SELECT a,b FROM t1 WHERE b=3; +EXPLAIN SELECT a,b FROM t1 WHERE a < 2 and b=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 Using where; Using index +EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 Using where; Using index +EXPLAIN SELECT a,b FROM t1 WHERE a < 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 Using where; Using index +EXPLAIN SELECT a,b FROM v1 WHERE a < 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 Using where; Using index +SELECT a,b FROM t1 WHERE a < 2 and b=3; +a b +1 3 +SELECT a,b FROM v1 WHERE a < 2 and b=3; +a b +1 3 +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (name varchar(15) NOT NULL, KEY idx(name)); +INSERT INTO t1 VALUES ('Betty'), ('Anna'); +SELECT * FROM t1; +name +Anna +Betty +DELETE FROM t1 WHERE name NOT LIKE 'A%a'; +SELECT * FROM t1; +name +Anna +DROP TABLE t1; +CREATE TABLE t1 (a int, KEY idx(a)); +INSERT INTO t1 VALUES (NULL), (1), (2), (3); +SELECT * FROM t1; +a +NULL +1 +2 +3 +DELETE FROM t1 WHERE NOT(a <=> 2); +SELECT * FROM t1; +a +2 +DROP TABLE t1; +create table t1 (a int, b int, primary key(a,b)); +create view v1 as select a, b from t1; +INSERT INTO `t1` VALUES +(0,0),(1,0),(2,0),(3,0),(4,0),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(11,2),(12,2) +,(13,2),(14,2),(15,3),(16,3),(17,3),(18,3),(19,3); +explain select * from t1 where a in (3,4) and b in (1,2,3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index +explain select * from v1 where a in (3,4) and b in (1,2,3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index +explain select * from t1 where a between 3 and 4 and b between 1 and 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index +explain select * from v1 where a between 3 and 4 and b between 1 and 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index +drop view v1; +drop table t1; +create table t3 (a int); +insert into t3 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a varchar(10), filler char(200), key(a)) charset=binary; +insert into t1 values ('a',''); +insert into t1 values ('a ',''); +insert into t1 values ('a ', ''); +insert into t1 select concat('a', 1000 + A.a + 10 * (B.a + 10 * C.a)), '' + from t3 A, t3 B, t3 C; +create table t2 (a varchar(10), filler char(200), key(a)); +insert into t2 select * from t1; +explain select * from t1 where a between 'a' and 'a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 13 NULL # Using where +explain select * from t1 where a = 'a' or a='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 13 NULL # Using where +explain select * from t2 where a between 'a' and 'a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref a a 13 const # Using where +explain select * from t2 where a = 'a' or a='a '; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref a a 13 const # Using where +update t1 set a='b' where a<>'a'; +explain select * from t1 where a not between 'b' and 'b'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 13 NULL # Using where +select a, hex(filler) from t1 where a not between 'b' and 'b'; +a hex(filler) +a 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +drop table t1,t2,t3; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, key(a)); +insert into t2 select 2*(A.a + 10*(B.a + 10*C.a)) from t1 A, t1 B, t1 C; +set @a="select * from t2 force index (a) where a NOT IN(0"; +select count(*) from (select @a:=concat(@a, ',', a) from t2 ) Z; +count(*) +1000 +set @a=concat(@a, ')'); +insert into t2 values (11),(13),(15); +set @b= concat("explain ", @a); +prepare stmt1 from @b; +execute stmt1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index a a 5 NULL 1003 Using where; Using index +prepare stmt1 from @a; +execute stmt1; +a +11 +13 +15 +drop table t1, t2; +CREATE TABLE t1 ( +id int NOT NULL DEFAULT '0', +b int NOT NULL DEFAULT '0', +c int NOT NULL DEFAULT '0', +INDEX idx1(b,c), INDEX idx2(c)); +INSERT INTO t1(id) VALUES (1), (2), (3), (4), (5), (6), (7), (8); +INSERT INTO t1(b,c) VALUES (3,4), (3,4); +SELECT * FROM t1 WHERE b<=3 AND 3<=c; +id b c +0 3 4 +0 3 4 +SELECT * FROM t1 WHERE 3 BETWEEN b AND c; +id b c +0 3 4 +0 3 4 +EXPLAIN SELECT * FROM t1 WHERE b<=3 AND 3<=c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 4 NULL 1 Using where +EXPLAIN SELECT * FROM t1 WHERE 3 BETWEEN b AND c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx1,idx2 idx1 4 NULL 1 Using where +SELECT * FROM t1 WHERE 0 < b OR 0 > c; +id b c +0 3 4 +0 3 4 +SELECT * FROM t1 WHERE 0 NOT BETWEEN b AND c; +id b c +0 3 4 +0 3 4 +EXPLAIN SELECT * FROM t1 WHERE 0 < b OR 0 > c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge idx1,idx2 idx1,idx2 4,4 NULL 2 Using sort_union(idx1,idx2); Using where +EXPLAIN SELECT * FROM t1 WHERE 0 NOT BETWEEN b AND c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge idx1,idx2 idx1,idx2 4,4 NULL 2 Using sort_union(idx1,idx2); Using where +DROP TABLE t1; +CREATE TABLE t1 ( +item char(20) NOT NULL default '', +started datetime NOT NULL default '0000-00-00 00:00:00', +price decimal(16,3) NOT NULL default '0.000', +PRIMARY KEY (item,started) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES +('A1','2005-11-01 08:00:00',1000), +('A1','2005-11-15 00:00:00',2000), +('A1','2005-12-12 08:00:00',3000), +('A2','2005-12-01 08:00:00',1000); +EXPLAIN SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-01 24:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref PRIMARY PRIMARY 20 const 2 Using where +Warnings: +Warning 1292 Incorrect datetime value: '2005-12-01 24:00:00' for column 'started' at row 1 +Warning 1292 Incorrect datetime value: '2005-12-01 24:00:00' for column 'started' at row 1 +SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-01 24:00:00'; +item started price +A1 2005-11-01 08:00:00 1000.000 +A1 2005-11-15 00:00:00 2000.000 +Warnings: +Warning 1292 Incorrect datetime value: '2005-12-01 24:00:00' for column 'started' at row 1 +Warning 1292 Incorrect datetime value: '2005-12-01 24:00:00' for column 'started' at row 1 +SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-02 00:00:00'; +item started price +A1 2005-11-01 08:00:00 1000.000 +A1 2005-11-15 00:00:00 2000.000 +DROP INDEX `PRIMARY` ON t1; +EXPLAIN SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-01 24:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where +Warnings: +Warning 1292 Incorrect datetime value: '2005-12-01 24:00:00' for column 'started' at row 1 +SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-01 24:00:00'; +item started price +A1 2005-11-01 08:00:00 1000.000 +A1 2005-11-15 00:00:00 2000.000 +Warnings: +Warning 1292 Incorrect datetime value: '2005-12-01 24:00:00' for column 'started' at row 1 +SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-02 00:00:00'; +item started price +A1 2005-11-01 08:00:00 1000.000 +A1 2005-11-15 00:00:00 2000.000 +DROP TABLE t1; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, filler char(100)); +insert into t2 select A.a + 10 * (B.a + 10 * C.a), 10, 'filler' from t1 A, +t1 B, t1 C where A.a < 5; +insert into t2 select 1000, b, 'filler' from t2; +alter table t2 add index (a,b); +select 'In following EXPLAIN the access method should be ref, #rows~=500 (and not 2)' Z; +Z +In following EXPLAIN the access method should be ref, #rows~=500 (and not 2) +explain select * from t2 where a=1000 and b<11; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 10 NULL 1 Using where +drop table t1, t2; diff --git a/mysql-test/suite/pbxt/r/read_only.result b/mysql-test/suite/pbxt/r/read_only.result new file mode 100644 index 00000000000..2eecb0a891d --- /dev/null +++ b/mysql-test/suite/pbxt/r/read_only.result @@ -0,0 +1,99 @@ +DROP TABLE IF EXISTS t1,t2,t3; +grant CREATE, SELECT, DROP on *.* to test@localhost; +set global read_only=0; +create table t1 (a int); +insert into t1 values(1); +create table t2 select * from t1; +set global read_only=1; +create table t3 (a int); +drop table t3; +select @@global.read_only; +@@global.read_only +1 +create table t3 (a int); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +insert into t1 values(1); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1 set a=1 where 1=0; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1,t2 set t1.a=t2.a+1 where t1.a=t2.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +delete t1,t2 from t1,t2 where t1.a=t2.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +create temporary table t3 (a int) engine=myisam; +create temporary table t4 (a int) engine=myisam select * from t3; +insert into t3 values(1); +insert into t4 select * from t3; +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +update t1,t3 set t3.a=t1.a+1 where t1.a=t3.a; +update t4,t3 set t4.a=t3.a+1 where t4.a=t3.a; +delete t1 from t1,t3 where t1.a=t3.a; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +delete t3 from t1,t3 where t1.a=t3.a; +delete t4 from t3,t4 where t4.a=t3.a; +create temporary table t1 (a int) engine=myisam; +insert into t1 values(1); +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; +delete t1 from t1,t3 where t1.a=t3.a; +drop table t1; +insert into t1 values(1); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +set global read_only=0; +lock table t1 write; +lock table t2 write; +set global read_only=1; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +unlock tables ; +set global read_only=1; +select @@global.read_only; +@@global.read_only +0 +unlock tables ; +select @@global.read_only; +@@global.read_only +1 +set global read_only=0; +lock table t1 read; +lock table t2 read; +set global read_only=1; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +unlock tables ; +set global read_only=1; +select @@global.read_only; +@@global.read_only +0 +unlock tables ; +select @@global.read_only; +@@global.read_only +1 +set global read_only=0; +BEGIN; +BEGIN; +set global read_only=1; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +ROLLBACK; +set global read_only=1; +select @@global.read_only; +@@global.read_only +1 +ROLLBACK; +set global read_only=0; +flush tables with read lock; +set global read_only=1; +unlock tables; +set global read_only=0; +flush tables with read lock; +set global read_only=1; +select @@global.read_only; +@@global.read_only +1 +unlock tables; +drop temporary table ttt; +ERROR 42S02: Unknown table 'ttt' +drop temporary table if exists ttt; +Warnings: +Note 1051 Unknown table 'ttt' +set global read_only=0; +drop table t1,t2; +drop user test@localhost; diff --git a/mysql-test/suite/pbxt/r/rename.result b/mysql-test/suite/pbxt/r/rename.result new file mode 100644 index 00000000000..1257a668cce --- /dev/null +++ b/mysql-test/suite/pbxt/r/rename.result @@ -0,0 +1,68 @@ +drop table if exists t0,t1,t2,t3,t4; +drop table if exists t0,t5,t6,t7,t8,t9,t1_1,t1_2,t9_1,t9_2; +create table t0 SELECT 1,"table 1"; +create table t2 SELECT 2,"table 2"; +create table t3 SELECT 3,"table 3"; +rename table t0 to t1; +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +select * from t1; +3 table 3 +3 table 3 +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +select * from t1; +1 table 1 +1 table 1 +rename table t1 to t2; +Got one of the listed errors +rename table t1 to t1; +Got one of the listed errors +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t2; +Got one of the listed errors +show tables like "t_"; +Tables_in_test (t_) +t1 +t2 +t3 +rename table t3 to t1, t2 to t3, t1 to t2, t4 to t1; +Got one of the listed errors +rename table t3 to t4, t5 to t3, t1 to t2, t4 to t1; +Got one of the listed errors +select * from t1; +1 table 1 +1 table 1 +select * from t2; +2 table 2 +2 table 2 +select * from t3; +3 table 3 +3 table 3 +drop table if exists t1,t2,t3,t4; +Warnings: +Note 1051 Unknown table 't4' +CREATE TABLE t1 (a int); +CREATE TABLE t3 (a int); +FLUSH TABLES WITH READ LOCK; +RENAME TABLE t1 TO t2, t3 to t4; +show tables; +Tables_in_test +t1 +t3 +UNLOCK TABLES; +show tables; +Tables_in_test +t2 +t4 +drop table t2, t4; +End of 4.1 tests +create table t1(f1 int); +create view v1 as select * from t1; +alter table v1 rename to v2; +alter table v1 rename to v2; +ERROR 42S02: Table 'test.v1' doesn't exist +rename table v2 to v1; +rename table v2 to v1; +ERROR 42S01: Table 'v1' already exists +drop view v1; +drop table t1; +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/renamedb.result b/mysql-test/suite/pbxt/r/renamedb.result new file mode 100644 index 00000000000..ff8f89592fc --- /dev/null +++ b/mysql-test/suite/pbxt/r/renamedb.result @@ -0,0 +1,12 @@ +rename database testdb1 to testdb2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'database testdb1 to testdb2' at line 1 +ALTER DATABASE wrong UPGRADE DATA DIRECTORY NAME; +ERROR HY000: Incorrect usage of ALTER DATABASE UPGRADE DATA DIRECTORY NAME and name +ALTER DATABASE `#mysql41#not-supported` UPGRADE DATA DIRECTORY NAME; +ERROR HY000: Incorrect usage of ALTER DATABASE UPGRADE DATA DIRECTORY NAME and name +ALTER DATABASE `#mysql51#not-yet` UPGRADE DATA DIRECTORY NAME; +ERROR HY000: Incorrect usage of ALTER DATABASE UPGRADE DATA DIRECTORY NAME and name +ALTER DATABASE `#mysql50#` UPGRADE DATA DIRECTORY NAME; +ERROR HY000: Incorrect usage of ALTER DATABASE UPGRADE DATA DIRECTORY NAME and name +ALTER DATABASE `#mysql50#upgrade-me` UPGRADE DATA DIRECTORY NAME; +ERROR 42000: Unknown database '#mysql50#upgrade-me' diff --git a/mysql-test/suite/pbxt/r/replace.result b/mysql-test/suite/pbxt/r/replace.result new file mode 100644 index 00000000000..a72269d7333 --- /dev/null +++ b/mysql-test/suite/pbxt/r/replace.result @@ -0,0 +1,32 @@ +drop table if exists t1; +CREATE TABLE t1 ( +gesuchnr int(11) DEFAULT '0' NOT NULL, +benutzer_id int(11) DEFAULT '0' NOT NULL, +PRIMARY KEY (gesuchnr,benutzer_id) +); +replace into t1 (gesuchnr,benutzer_id) values (2,1); +replace into t1 (gesuchnr,benutzer_id) values (1,1); +replace into t1 (gesuchnr,benutzer_id) values (1,1); +alter table t1 engine=heap; +replace into t1 (gesuchnr,benutzer_id) values (1,1); +drop table t1; +create table t1 (a tinyint not null auto_increment primary key, b char(20) default "default_value"); +insert into t1 values (126,"first"),(63, "middle"),(0,"last"); +insert into t1 values (0,"error"); +ERROR HY000: Failed to read auto-increment value from storage engine +replace into t1 values (0,"error"); +ERROR HY000: Failed to read auto-increment value from storage engine +replace into t1 values (126,"first updated"); +replace into t1 values (63,default); +select * from t1 order by a; +a b +63 default_value +126 first updated +127 last +drop table t1; +CREATE TABLE t1 (f1 INT); +CREATE VIEW v1 AS SELECT f1 FROM t1 WHERE f1 = 0 WITH CHECK OPTION; +REPLACE INTO v1 (f1) VALUES (1); +ERROR HY000: CHECK OPTION failed 'test.v1' +DROP TABLE t1; +DROP VIEW v1; diff --git a/mysql-test/suite/pbxt/r/rollback.result b/mysql-test/suite/pbxt/r/rollback.result new file mode 100644 index 00000000000..e562b73c981 --- /dev/null +++ b/mysql-test/suite/pbxt/r/rollback.result @@ -0,0 +1,29 @@ +drop table if exists t1; +create table t1 (n int not null primary key) engine=myisam; +begin work; +insert into t1 values (4); +insert into t1 values (5); +rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +select @@warning_count; +@@warning_count +1 +select @@error_count; +@@error_count +0 +show warnings; +Level Code Message +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show errors; +Level Code Message +select * from t1; +n +4 +5 +select @@warning_count; +@@warning_count +0 +show warnings; +Level Code Message +drop table t1; diff --git a/mysql-test/suite/pbxt/r/schema.result b/mysql-test/suite/pbxt/r/schema.result new file mode 100644 index 00000000000..564fb3626df --- /dev/null +++ b/mysql-test/suite/pbxt/r/schema.result @@ -0,0 +1,13 @@ +drop database if exists mysqltest1; +create schema foo; +show create schema foo; +Database Create Database +foo CREATE DATABASE `foo` /*!40100 DEFAULT CHARACTER SET latin1 */ +show schemas; +Database +information_schema +foo +mtr +mysql +test +drop schema foo; diff --git a/mysql-test/suite/pbxt/r/select.result b/mysql-test/suite/pbxt/r/select.result new file mode 100644 index 00000000000..53127fb0dab --- /dev/null +++ b/mysql-test/suite/pbxt/r/select.result @@ -0,0 +1,3644 @@ +drop table if exists t1,t2,t3,t4,t11; +drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; +drop view if exists v1; +CREATE TABLE t1 ( +Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, +Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL +); +INSERT INTO t1 VALUES (9410,9412); +select period from t1; +period +9410 +select * from t1; +Period Varor_period +9410 9412 +select t1.* from t1; +Period Varor_period +9410 9412 +CREATE TABLE t2 ( +auto int not null auto_increment, +fld1 int(6) unsigned zerofill DEFAULT '000000' NOT NULL, +companynr tinyint(2) unsigned zerofill DEFAULT '00' NOT NULL, +fld3 char(30) DEFAULT '' NOT NULL, +fld4 char(35) DEFAULT '' NOT NULL, +fld5 char(35) DEFAULT '' NOT NULL, +fld6 char(4) DEFAULT '' NOT NULL, +UNIQUE fld1 (fld1), +KEY fld3 (fld3), +PRIMARY KEY (auto) +); +select t2.fld3 from t2 where companynr = 58 and fld3 like "%imaginable%"; +fld3 +imaginable +select fld3 from t2 where fld3 like "%cultivation" ; +fld3 +cultivation +select t2.fld3,companynr from t2 where companynr = 57+1 order by fld3; +fld3 companynr +concoct 58 +druggists 58 +engrossing 58 +Eurydice 58 +exclaimers 58 +ferociousness 58 +hopelessness 58 +Huey 58 +imaginable 58 +judges 58 +merging 58 +ostrich 58 +peering 58 +Phelps 58 +presumes 58 +Ruth 58 +sentences 58 +Shylock 58 +straggled 58 +synergy 58 +thanking 58 +tying 58 +unlocks 58 +select fld3,companynr from t2 where companynr = 58 order by fld3; +fld3 companynr +concoct 58 +druggists 58 +engrossing 58 +Eurydice 58 +exclaimers 58 +ferociousness 58 +hopelessness 58 +Huey 58 +imaginable 58 +judges 58 +merging 58 +ostrich 58 +peering 58 +Phelps 58 +presumes 58 +Ruth 58 +sentences 58 +Shylock 58 +straggled 58 +synergy 58 +thanking 58 +tying 58 +unlocks 58 +select fld3 from t2 order by fld3 desc limit 10; +fld3 +youthfulness +yelped +Wotan +workers +Witt +witchcraft +Winsett +Willy +willed +wildcats +select fld3 from t2 order by fld3 desc limit 5; +fld3 +youthfulness +yelped +Wotan +workers +Witt +select fld3 from t2 order by fld3 desc limit 5,5; +fld3 +witchcraft +Winsett +Willy +willed +wildcats +select t2.fld3 from t2 where fld3 = 'honeysuckle'; +fld3 +honeysuckle +select t2.fld3 from t2 where fld3 LIKE 'honeysuckl_'; +fld3 +honeysuckle +select t2.fld3 from t2 where fld3 LIKE 'hon_ysuckl_'; +fld3 +honeysuckle +select t2.fld3 from t2 where fld3 LIKE 'honeysuckle%'; +fld3 +honeysuckle +select t2.fld3 from t2 where fld3 LIKE 'h%le'; +fld3 +honeysuckle +select t2.fld3 from t2 where fld3 LIKE 'honeysuckle_'; +fld3 +select t2.fld3 from t2 where fld3 LIKE 'don_t_find_me_please%'; +fld3 +explain select t2.fld3 from t2 where fld3 = 'honeysuckle'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref fld3 fld3 30 const 1 Using where; Using index +explain select fld3 from t2 ignore index (fld3) where fld3 = 'honeysuckle'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +explain select fld3 from t2 use index (fld1) where fld3 = 'honeysuckle'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +explain select fld3 from t2 use index (fld3) where fld3 = 'honeysuckle'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref fld3 fld3 30 const 1 Using where; Using index +explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref fld3 fld3 30 const 1 Using where; Using index +explain select fld3 from t2 ignore index (fld3,not_used); +ERROR 42000: Key 'not_used' doesn't exist in table 't2' +explain select fld3 from t2 use index (not_used); +ERROR 42000: Key 'not_used' doesn't exist in table 't2' +select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3; +fld3 +honeysuckle +honoring +explain select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range fld3 fld3 30 NULL 1 Using where; Using index +select fld1,fld3 from t2 where fld3="Colombo" or fld3 = "nondecreasing" order by fld3; +fld1 fld3 +148504 Colombo +068305 Colombo +000000 nondecreasing +select fld1,fld3 from t2 where companynr = 37 and fld3 = 'appendixes'; +fld1 fld3 +232605 appendixes +1232605 appendixes +1232606 appendixes +1232607 appendixes +1232608 appendixes +1232609 appendixes +select fld1 from t2 where fld1=250501 or fld1="250502"; +fld1 +250501 +250502 +explain select fld1 from t2 where fld1=250501 or fld1="250502"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range fld1 fld1 4 NULL 2 Using where; Using index +select fld1 from t2 where fld1=250501 or fld1=250502 or fld1 >= 250505 and fld1 <= 250601 or fld1 between 250501 and 250502; +fld1 +250501 +250502 +250505 +250601 +explain select fld1 from t2 where fld1=250501 or fld1=250502 or fld1 >= 250505 and fld1 <= 250601 or fld1 between 250501 and 250502; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range fld1 fld1 4 NULL 2 Using where; Using index +select fld1,fld3 from t2 where companynr = 37 and fld3 like 'f%'; +fld1 fld3 +218401 faithful +018007 fanatic +228311 fated +018017 featherweight +218022 feed +088303 feminine +058004 Fenton +038017 fetched +018054 fetters +208101 fiftieth +238007 filial +013606 fingerings +218008 finishers +038205 firearm +188505 fitting +202301 Fitzpatrick +238008 fixedly +012001 flanking +018103 flint +018104 flopping +188007 flurried +013602 foldout +226205 foothill +232102 forgivably +228306 forthcoming +186002 freakish +208113 freest +231315 freezes +036002 funereal +226209 furnishings +198006 furthermore +select fld3 from t2 where fld3 like "L%" and fld3 = "ok"; +fld3 +select fld3 from t2 where (fld3 like "C%" and fld3 = "Chantilly"); +fld3 +Chantilly +select fld1,fld3 from t2 where fld1 like "25050%"; +fld1 fld3 +250501 poisoning +250502 Iraqis +250503 heaving +250504 population +250505 bomb +select fld1,fld3 from t2 where fld1 like "25050_"; +fld1 fld3 +250501 poisoning +250502 Iraqis +250503 heaving +250504 population +250505 bomb +select distinct companynr from t2; +companynr +00 +37 +36 +50 +58 +29 +40 +53 +65 +41 +34 +68 +select distinct companynr from t2 order by companynr; +companynr +00 +29 +34 +36 +37 +40 +41 +50 +53 +58 +65 +68 +select distinct companynr from t2 order by companynr desc; +companynr +68 +65 +58 +53 +50 +41 +40 +37 +36 +34 +29 +00 +select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; +fld3 period +obliterates 9410 +offload 9410 +opaquely 9410 +organizer 9410 +overestimating 9410 +overlay 9410 +select distinct fld3 from t2 where companynr = 34 order by fld3; +fld3 +absentee +accessed +ahead +alphabetic +Asiaticizations +attitude +aye +bankruptcies +belays +Blythe +bomb +boulevard +bulldozes +cannot +caressing +charcoal +checksumming +chess +clubroom +colorful +cosy +creator +crying +Darius +diffusing +duality +Eiffel +Epiphany +Ernestine +explorers +exterminated +famine +forked +Gershwins +heaving +Hodges +Iraqis +Italianization +Lagos +landslide +libretto +Majorca +mastering +narrowed +occurred +offerers +Palestine +Peruvianizes +pharmaceutic +poisoning +population +Pygmalion +rats +realest +recording +regimented +retransmitting +reviver +rouses +scars +sicker +sleepwalk +stopped +sugars +translatable +uncles +unexpected +uprisings +versatility +vest +select distinct fld3 from t2 limit 10; +fld3 +abates +abiding +Abraham +abrogating +absentee +abut +accessed +accruing +accumulating +accuracies +select distinct fld3 from t2 having fld3 like "A%" limit 10; +fld3 +abates +abiding +Abraham +abrogating +absentee +abut +accessed +accruing +accumulating +accuracies +select distinct substring(fld3,1,3) from t2 where fld3 like "A%"; +substring(fld3,1,3) +aba +abi +Abr +abs +abu +acc +acq +acu +Ade +adj +Adl +adm +Ado +ads +adv +aer +aff +afi +afl +afo +agi +ahe +aim +air +Ald +alg +ali +all +alp +alr +ama +ame +amm +ana +and +ane +Ang +ani +Ann +Ant +api +app +aqu +Ara +arc +Arm +arr +Art +Asi +ask +asp +ass +ast +att +aud +Aug +aut +ave +avo +awe +aye +Azt +select distinct substring(fld3,1,3) as a from t2 having a like "A%" order by a limit 10; +a +aba +abi +Abr +abs +abu +acc +acq +acu +Ade +adj +select distinct substring(fld3,1,3) from t2 where fld3 like "A%" limit 10; +substring(fld3,1,3) +aba +abi +Abr +abs +abu +acc +acq +acu +Ade +adj +select distinct substring(fld3,1,3) as a from t2 having a like "A%" limit 10; +a +aba +abi +Abr +abs +abu +acc +acq +acu +Ade +adj +create table t3 ( +period int not null, +name char(32) not null, +companynr int not null, +price double(11,0), +price2 double(11,0), +key (period), +key (name) +); +create temporary table tmp engine = myisam select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +alter table t3 add t2nr int not null auto_increment primary key first; +drop table tmp; +SET SQL_BIG_TABLES=1; +select distinct concat(fld3," ",fld3) as namn from t2,t3 where t2.fld1=t3.t2nr order by namn limit 10; +namn +Abraham Abraham +abrogating abrogating +admonishing admonishing +Adolph Adolph +afield afield +aging aging +ammonium ammonium +analyzable analyzable +animals animals +animized animized +SET SQL_BIG_TABLES=0; +select distinct concat(fld3," ",fld3) from t2,t3 where t2.fld1=t3.t2nr order by fld3 limit 10; +concat(fld3," ",fld3) +Abraham Abraham +abrogating abrogating +admonishing admonishing +Adolph Adolph +afield afield +aging aging +ammonium ammonium +analyzable analyzable +animals animals +animized animized +select distinct fld5 from t2 limit 10; +fld5 +neat +Steinberg +jarring +tinily +balled +persist +attainments +fanatic +measures +rightfulness +select distinct fld3,count(*) from t2 group by companynr,fld3 limit 10; +fld3 count(*) +affixed 1 +and 1 +annoyers 1 +Anthony 1 +assayed 1 +assurers 1 +attendants 1 +bedlam 1 +bedpost 1 +boasted 1 +SET SQL_BIG_TABLES=1; +select distinct fld3,count(*) from t2 group by companynr,fld3 limit 10; +fld3 count(*) +affixed 1 +and 1 +annoyers 1 +Anthony 1 +assayed 1 +assurers 1 +attendants 1 +bedlam 1 +bedpost 1 +boasted 1 +SET SQL_BIG_TABLES=0; +select distinct fld3,repeat("a",length(fld3)),count(*) from t2 group by companynr,fld3 limit 100,10; +fld3 repeat("a",length(fld3)) count(*) +circus aaaaaa 1 +cited aaaaa 1 +Colombo aaaaaaa 1 +congresswoman aaaaaaaaaaaaa 1 +contrition aaaaaaaaaa 1 +corny aaaaa 1 +cultivation aaaaaaaaaaa 1 +definiteness aaaaaaaaaaaa 1 +demultiplex aaaaaaaaaaa 1 +disappointing aaaaaaaaaaaaa 1 +select distinct companynr,rtrim(space(512+companynr)) from t3 order by 1,2; +companynr rtrim(space(512+companynr)) +37 +78 +101 +154 +311 +447 +512 +select distinct fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2nr order by fld3; +fld3 +explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2nr order by t3.t2nr,fld3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index +explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using temporary; Using filesort +1 SIMPLE t3 ref period period 4 test.t1.period 18 +explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 index period period 4 NULL 1 +1 SIMPLE t1 ref period period 4 test.t3.period 18 +explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index period period 4 NULL 1 +1 SIMPLE t3 ref period period 4 test.t1.period 18 +select period from t1; +period +9410 +select period from t1 where period=1900; +period +select fld3,period from t1,t2 where fld1 = 011401 order by period; +fld3 period +breaking 9410 +select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; +fld3 period +breaking 1001 +explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 const fld1 fld1 4 const 1 +1 SIMPLE t3 const PRIMARY,period PRIMARY 4 const 1 +select fld3,period from t2,t1 where companynr*10 = 37*10; +fld3 period +breaking 9410 +Romans 9410 +intercepted 9410 +bewilderingly 9410 +astound 9410 +admonishing 9410 +sumac 9410 +flanking 9410 +combed 9410 +subjective 9410 +scatterbrain 9410 +Eulerian 9410 +Kane 9410 +overlay 9410 +perturb 9410 +goblins 9410 +annihilates 9410 +Wotan 9410 +snatching 9410 +concludes 9410 +laterally 9410 +yelped 9410 +grazing 9410 +Baird 9410 +celery 9410 +misunderstander 9410 +handgun 9410 +foldout 9410 +mystic 9410 +succumbed 9410 +Nabisco 9410 +fingerings 9410 +aging 9410 +afield 9410 +ammonium 9410 +boat 9410 +intelligibility 9410 +Augustine 9410 +teethe 9410 +dreaded 9410 +scholastics 9410 +audiology 9410 +wallet 9410 +parters 9410 +eschew 9410 +quitter 9410 +neat 9410 +Steinberg 9410 +jarring 9410 +tinily 9410 +balled 9410 +persist 9410 +attainments 9410 +fanatic 9410 +measures 9410 +rightfulness 9410 +capably 9410 +impulsive 9410 +starlet 9410 +terminators 9410 +untying 9410 +announces 9410 +featherweight 9410 +pessimist 9410 +daughter 9410 +decliner 9410 +lawgiver 9410 +stated 9410 +readable 9410 +attrition 9410 +cascade 9410 +motors 9410 +interrogate 9410 +pests 9410 +stairway 9410 +dopers 9410 +testicle 9410 +Parsifal 9410 +leavings 9410 +postulation 9410 +squeaking 9410 +contrasted 9410 +leftover 9410 +whiteners 9410 +erases 9410 +Punjab 9410 +Merritt 9410 +Quixotism 9410 +sweetish 9410 +dogging 9410 +scornfully 9410 +bellow 9410 +bills 9410 +cupboard 9410 +sureties 9410 +puddings 9410 +fetters 9410 +bivalves 9410 +incurring 9410 +Adolph 9410 +pithed 9410 +Miles 9410 +trimmings 9410 +tragedies 9410 +skulking 9410 +flint 9410 +flopping 9410 +relaxing 9410 +offload 9410 +suites 9410 +lists 9410 +animized 9410 +multilayer 9410 +standardizes 9410 +Judas 9410 +vacuuming 9410 +dentally 9410 +humanness 9410 +inch 9410 +Weissmuller 9410 +irresponsibly 9410 +luckily 9410 +culled 9410 +medical 9410 +bloodbath 9410 +subschema 9410 +animals 9410 +Micronesia 9410 +repetitions 9410 +Antares 9410 +ventilate 9410 +pityingly 9410 +interdependent 9410 +Graves 9410 +neonatal 9410 +chafe 9410 +honoring 9410 +realtor 9410 +elite 9410 +funereal 9410 +abrogating 9410 +sorters 9410 +Conley 9410 +lectured 9410 +Abraham 9410 +Hawaii 9410 +cage 9410 +hushes 9410 +Simla 9410 +reporters 9410 +Dutchman 9410 +descendants 9410 +groupings 9410 +dissociate 9410 +coexist 9410 +Beebe 9410 +Taoism 9410 +Connally 9410 +fetched 9410 +checkpoints 9410 +rusting 9410 +galling 9410 +obliterates 9410 +traitor 9410 +resumes 9410 +analyzable 9410 +terminator 9410 +gritty 9410 +firearm 9410 +minima 9410 +Selfridge 9410 +disable 9410 +witchcraft 9410 +betroth 9410 +Manhattanize 9410 +imprint 9410 +peeked 9410 +swelling 9410 +interrelationships 9410 +riser 9410 +Gandhian 9410 +peacock 9410 +bee 9410 +kanji 9410 +dental 9410 +scarf 9410 +chasm 9410 +insolence 9410 +syndicate 9410 +alike 9410 +imperial 9410 +convulsion 9410 +railway 9410 +validate 9410 +normalizes 9410 +comprehensive 9410 +chewing 9410 +denizen 9410 +schemer 9410 +chronicle 9410 +Kline 9410 +Anatole 9410 +partridges 9410 +brunch 9410 +recruited 9410 +dimensions 9410 +Chicana 9410 +announced 9410 +praised 9410 +employing 9410 +linear 9410 +quagmire 9410 +western 9410 +relishing 9410 +serving 9410 +scheduling 9410 +lore 9410 +eventful 9410 +arteriole 9410 +disentangle 9410 +cured 9410 +Fenton 9410 +avoidable 9410 +drains 9410 +detectably 9410 +husky 9410 +impelling 9410 +undoes 9410 +evened 9410 +squeezes 9410 +destroyer 9410 +rudeness 9410 +beaner 9410 +boorish 9410 +Everhart 9410 +encompass 9410 +mushrooms 9410 +Alison 9410 +externally 9410 +pellagra 9410 +cult 9410 +creek 9410 +Huffman 9410 +Majorca 9410 +governing 9410 +gadfly 9410 +reassigned 9410 +intentness 9410 +craziness 9410 +psychic 9410 +squabbled 9410 +burlesque 9410 +capped 9410 +extracted 9410 +DiMaggio 9410 +exclamation 9410 +subdirectory 9410 +Gothicism 9410 +feminine 9410 +metaphysically 9410 +sanding 9410 +Miltonism 9410 +freakish 9410 +index 9410 +straight 9410 +flurried 9410 +denotative 9410 +coming 9410 +commencements 9410 +gentleman 9410 +gifted 9410 +Shanghais 9410 +sportswriting 9410 +sloping 9410 +navies 9410 +leaflet 9410 +shooter 9410 +Joplin 9410 +babies 9410 +assails 9410 +admiring 9410 +swaying 9410 +Goldstine 9410 +fitting 9410 +Norwalk 9410 +analogy 9410 +deludes 9410 +cokes 9410 +Clayton 9410 +exhausts 9410 +causality 9410 +sating 9410 +icon 9410 +throttles 9410 +communicants 9410 +dehydrate 9410 +priceless 9410 +publicly 9410 +incidentals 9410 +commonplace 9410 +mumbles 9410 +furthermore 9410 +cautioned 9410 +parametrized 9410 +registration 9410 +sadly 9410 +positioning 9410 +babysitting 9410 +eternal 9410 +hoarder 9410 +congregates 9410 +rains 9410 +workers 9410 +sags 9410 +unplug 9410 +garage 9410 +boulder 9410 +specifics 9410 +Teresa 9410 +Winsett 9410 +convenient 9410 +buckboards 9410 +amenities 9410 +resplendent 9410 +sews 9410 +participated 9410 +Simon 9410 +certificates 9410 +Fitzpatrick 9410 +Evanston 9410 +misted 9410 +textures 9410 +save 9410 +count 9410 +rightful 9410 +chaperone 9410 +Lizzy 9410 +clenched 9410 +effortlessly 9410 +accessed 9410 +beaters 9410 +Hornblower 9410 +vests 9410 +indulgences 9410 +infallibly 9410 +unwilling 9410 +excrete 9410 +spools 9410 +crunches 9410 +overestimating 9410 +ineffective 9410 +humiliation 9410 +sophomore 9410 +star 9410 +rifles 9410 +dialysis 9410 +arriving 9410 +indulge 9410 +clockers 9410 +languages 9410 +Antarctica 9410 +percentage 9410 +ceiling 9410 +specification 9410 +regimented 9410 +ciphers 9410 +pictures 9410 +serpents 9410 +allot 9410 +realized 9410 +mayoral 9410 +opaquely 9410 +hostess 9410 +fiftieth 9410 +incorrectly 9410 +decomposition 9410 +stranglings 9410 +mixture 9410 +electroencephalography 9410 +similarities 9410 +charges 9410 +freest 9410 +Greenberg 9410 +tinting 9410 +expelled 9410 +warm 9410 +smoothed 9410 +deductions 9410 +Romano 9410 +bitterroot 9410 +corset 9410 +securing 9410 +environing 9410 +cute 9410 +Crays 9410 +heiress 9410 +inform 9410 +avenge 9410 +universals 9410 +Kinsey 9410 +ravines 9410 +bestseller 9410 +equilibrium 9410 +extents 9410 +relatively 9410 +pressure 9410 +critiques 9410 +befouled 9410 +rightfully 9410 +mechanizing 9410 +Latinizes 9410 +timesharing 9410 +Aden 9410 +embassies 9410 +males 9410 +shapelessly 9410 +mastering 9410 +Newtonian 9410 +finishers 9410 +abates 9410 +teem 9410 +kiting 9410 +stodgy 9410 +feed 9410 +guitars 9410 +airships 9410 +store 9410 +denounces 9410 +Pyle 9410 +Saxony 9410 +serializations 9410 +Peruvian 9410 +taxonomically 9410 +kingdom 9410 +stint 9410 +Sault 9410 +faithful 9410 +Ganymede 9410 +tidiness 9410 +gainful 9410 +contrary 9410 +Tipperary 9410 +tropics 9410 +theorizers 9410 +renew 9410 +already 9410 +terminal 9410 +Hegelian 9410 +hypothesizer 9410 +warningly 9410 +journalizing 9410 +nested 9410 +Lars 9410 +saplings 9410 +foothill 9410 +labeled 9410 +imperiously 9410 +reporters 9410 +furnishings 9410 +precipitable 9410 +discounts 9410 +excises 9410 +Stalin 9410 +despot 9410 +ripeness 9410 +Arabia 9410 +unruly 9410 +mournfulness 9410 +boom 9410 +slaughter 9410 +Sabine 9410 +handy 9410 +rural 9410 +organizer 9410 +shipyard 9410 +civics 9410 +inaccuracy 9410 +rules 9410 +juveniles 9410 +comprised 9410 +investigations 9410 +stabilizes 9410 +seminaries 9410 +Hunter 9410 +sporty 9410 +test 9410 +weasels 9410 +CERN 9410 +tempering 9410 +afore 9410 +Galatean 9410 +techniques 9410 +error 9410 +veranda 9410 +severely 9410 +Cassites 9410 +forthcoming 9410 +guides 9410 +vanish 9410 +lied 9410 +sawtooth 9410 +fated 9410 +gradually 9410 +widens 9410 +preclude 9410 +evenhandedly 9410 +percentage 9410 +disobedience 9410 +humility 9410 +gleaning 9410 +petted 9410 +bloater 9410 +minion 9410 +marginal 9410 +apiary 9410 +measures 9410 +precaution 9410 +repelled 9410 +primary 9410 +coverings 9410 +Artemia 9410 +navigate 9410 +spatial 9410 +Gurkha 9410 +meanwhile 9410 +Melinda 9410 +Butterfield 9410 +Aldrich 9410 +previewing 9410 +glut 9410 +unaffected 9410 +inmate 9410 +mineral 9410 +impending 9410 +meditation 9410 +ideas 9410 +miniaturizes 9410 +lewdly 9410 +title 9410 +youthfulness 9410 +creak 9410 +Chippewa 9410 +clamored 9410 +freezes 9410 +forgivably 9410 +reduce 9410 +McGovern 9410 +Nazis 9410 +epistle 9410 +socializes 9410 +conceptions 9410 +Kevin 9410 +uncovering 9410 +chews 9410 +appendixes 9410 +appendixes 9410 +appendixes 9410 +appendixes 9410 +appendixes 9410 +appendixes 9410 +raining 9410 +infest 9410 +compartment 9410 +minting 9410 +ducks 9410 +roped 9410 +waltz 9410 +Lillian 9410 +repressions 9410 +chillingly 9410 +noncritical 9410 +lithograph 9410 +spongers 9410 +parenthood 9410 +posed 9410 +instruments 9410 +filial 9410 +fixedly 9410 +relives 9410 +Pandora 9410 +watering 9410 +ungrateful 9410 +secures 9410 +poison 9410 +dusted 9410 +encompasses 9410 +presentation 9410 +Kantian 9410 +select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; +fld3 period price price2 +admonishing 1002 28357832 8723648 +analyzable 1002 28357832 8723648 +annihilates 1001 5987435 234724 +Antares 1002 28357832 8723648 +astound 1001 5987435 234724 +audiology 1001 5987435 234724 +Augustine 1002 28357832 8723648 +Baird 1002 28357832 8723648 +bewilderingly 1001 5987435 234724 +breaking 1001 5987435 234724 +Conley 1001 5987435 234724 +dentally 1002 28357832 8723648 +dissociate 1002 28357832 8723648 +elite 1001 5987435 234724 +eschew 1001 5987435 234724 +Eulerian 1001 5987435 234724 +flanking 1001 5987435 234724 +foldout 1002 28357832 8723648 +funereal 1002 28357832 8723648 +galling 1002 28357832 8723648 +Graves 1001 5987435 234724 +grazing 1001 5987435 234724 +groupings 1001 5987435 234724 +handgun 1001 5987435 234724 +humility 1002 28357832 8723648 +impulsive 1002 28357832 8723648 +inch 1001 5987435 234724 +intelligibility 1001 5987435 234724 +jarring 1001 5987435 234724 +lawgiver 1001 5987435 234724 +lectured 1002 28357832 8723648 +Merritt 1002 28357832 8723648 +neonatal 1001 5987435 234724 +offload 1002 28357832 8723648 +parters 1002 28357832 8723648 +pityingly 1002 28357832 8723648 +puddings 1002 28357832 8723648 +Punjab 1001 5987435 234724 +quitter 1002 28357832 8723648 +realtor 1001 5987435 234724 +relaxing 1001 5987435 234724 +repetitions 1001 5987435 234724 +resumes 1001 5987435 234724 +Romans 1002 28357832 8723648 +rusting 1001 5987435 234724 +scholastics 1001 5987435 234724 +skulking 1002 28357832 8723648 +stated 1002 28357832 8723648 +suites 1002 28357832 8723648 +sureties 1001 5987435 234724 +testicle 1002 28357832 8723648 +tinily 1002 28357832 8723648 +tragedies 1001 5987435 234724 +trimmings 1001 5987435 234724 +vacuuming 1001 5987435 234724 +ventilate 1001 5987435 234724 +wallet 1001 5987435 234724 +Weissmuller 1002 28357832 8723648 +Wotan 1002 28357832 8723648 +select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; +fld1 fld3 period price price2 +018201 relaxing 1001 5987435 234724 +018601 vacuuming 1001 5987435 234724 +018801 inch 1001 5987435 234724 +018811 repetitions 1001 5987435 234724 +create table t4 ( +companynr tinyint(2) unsigned zerofill NOT NULL default '00', +companyname char(30) NOT NULL default '', +PRIMARY KEY (companynr), +UNIQUE KEY companyname(companyname) +) ENGINE=MyISAM MAX_ROWS=50 PACK_KEYS=1 COMMENT='companynames'; +select STRAIGHT_JOIN t2.companynr,companyname from t4,t2 where t2.companynr=t4.companynr group by t2.companynr; +companynr companyname +00 Unknown +29 company 1 +34 company 2 +36 company 3 +37 company 4 +40 company 5 +41 company 6 +50 company 11 +53 company 7 +58 company 8 +65 company 9 +68 company 10 +select SQL_SMALL_RESULT t2.companynr,companyname from t4,t2 where t2.companynr=t4.companynr group by t2.companynr; +companynr companyname +00 Unknown +29 company 1 +34 company 2 +36 company 3 +37 company 4 +40 company 5 +41 company 6 +50 company 11 +53 company 7 +58 company 8 +65 company 9 +68 company 10 +select * from t1,t1 t12; +Period Varor_period Period Varor_period +9410 9412 9410 9412 +select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; +fld1 fld1 +250501 250501 +250502 250501 +250503 250501 +250504 250501 +250505 250501 +250501 250502 +250502 250502 +250503 250502 +250504 250502 +250505 250502 +250501 250503 +250502 250503 +250503 250503 +250504 250503 +250505 250503 +250501 250504 +250502 250504 +250503 250504 +250504 250504 +250505 250504 +250501 250505 +250502 250505 +250503 250505 +250504 250505 +250505 250505 +insert into t2 (fld1, companynr) values (999999,99); +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +companynr companyname +99 NULL +select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null; +count(*) +1199 +explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 +1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where; Not exists +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1200 Using where; Not exists +select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; +companynr companyname +select count(*) from t2 left join t4 using (companynr) where companynr is not null; +count(*) +1200 +explain select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +delete from t2 where fld1=999999; +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL PRIMARY NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; +companynr companynr +37 36 +41 40 +explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where; Using join buffer +select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; +fld1 companynr fld3 period +038008 37 reporters 1008 +038208 37 Selfridge 1008 +select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; +fld1 companynr fld3 period +038008 37 reporters 1008 +038208 37 Selfridge 1008 +select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; +fld1 companynr fld3 period +038008 37 reporters 1008 +038208 37 Selfridge 1008 +select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); +period +9410 +select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); +period +9410 +select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; +fld1 +250501 +250502 +250503 +250505 +select fld1 from t2 where fld1 in (250502,98005,98006,250503,250605,250606) and fld1 >=250502 and fld1 not in (250605,250606); +fld1 +250502 +250503 +select fld1 from t2 where fld1 between 250502 and 250504; +fld1 +250502 +250503 +250504 +select fld3 from t2 where (((fld3 like "_%L%" ) or (fld3 like "%ok%")) and ( fld3 like "L%" or fld3 like "G%")) and fld3 like "L%" ; +fld3 +label +labeled +labeled +landslide +laterally +leaflet +lewdly +Lillian +luckily +select count(*) from t1; +count(*) +1 +select companynr,count(*),sum(fld1) from t2 group by companynr; +companynr count(*) sum(fld1) +00 82 10355753 +29 95 14473298 +34 70 17788966 +36 215 22786296 +37 588 83602098 +40 37 6618386 +41 52 12816335 +50 11 1595438 +53 4 793210 +58 23 2254293 +65 10 2284055 +68 12 3097288 +select companynr,count(*) from t2 group by companynr order by companynr desc limit 5; +companynr count(*) +68 12 +65 10 +58 23 +53 4 +50 11 +select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; +count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1) +70 absentee vest 17788966 254128.0857 3272.5940 10709871.3069 +explain extended select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 100.00 Using where +Warnings: +Note 1003 select count(0) AS `count(*)`,min(`test`.`t2`.`fld4`) AS `min(fld4)`,max(`test`.`t2`.`fld4`) AS `max(fld4)`,sum(`test`.`t2`.`fld1`) AS `sum(fld1)`,avg(`test`.`t2`.`fld1`) AS `avg(fld1)`,std(`test`.`t2`.`fld1`) AS `std(fld1)`,variance(`test`.`t2`.`fld1`) AS `variance(fld1)` from `test`.`t2` where ((`test`.`t2`.`companynr` = 34) and (`test`.`t2`.`fld4` <> '')) +select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3; +companynr count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1) +00 82 Anthony windmills 10355753 126289.6707 115550.9757 13352027981.7087 +29 95 abut wetness 14473298 152350.5053 8368.5480 70032594.9026 +34 70 absentee vest 17788966 254128.0857 3272.5940 10709871.3069 +select companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; +companynr t2nr count(price) sum(price) min(price) max(price) avg(price) +37 1 1 5987435 5987435 5987435 5987435.0000 +37 2 1 28357832 28357832 28357832 28357832.0000 +37 3 1 39654943 39654943 39654943 39654943.0000 +37 11 1 5987435 5987435 5987435 5987435.0000 +37 12 1 28357832 28357832 28357832 28357832.0000 +37 13 1 39654943 39654943 39654943 39654943.0000 +37 21 1 5987435 5987435 5987435 5987435.0000 +37 22 1 28357832 28357832 28357832 28357832.0000 +37 23 1 39654943 39654943 39654943 39654943.0000 +37 31 1 5987435 5987435 5987435 5987435.0000 +select /*! SQL_SMALL_RESULT */ companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; +companynr t2nr count(price) sum(price) min(price) max(price) avg(price) +37 1 1 5987435 5987435 5987435 5987435.0000 +37 2 1 28357832 28357832 28357832 28357832.0000 +37 3 1 39654943 39654943 39654943 39654943.0000 +37 11 1 5987435 5987435 5987435 5987435.0000 +37 12 1 28357832 28357832 28357832 28357832.0000 +37 13 1 39654943 39654943 39654943 39654943.0000 +37 21 1 5987435 5987435 5987435 5987435.0000 +37 22 1 28357832 28357832 28357832 28357832.0000 +37 23 1 39654943 39654943 39654943 39654943.0000 +37 31 1 5987435 5987435 5987435 5987435.0000 +select companynr,count(price),sum(price),min(price),max(price),avg(price) from t3 group by companynr ; +companynr count(price) sum(price) min(price) max(price) avg(price) +37 12543 309394878010 5987435 39654943 24666736.6667 +78 8362 414611089292 726498 98439034 49582766.0000 +101 4181 3489454238 834598 834598 834598.0000 +154 4181 4112197254950 983543950 983543950 983543950.0000 +311 4181 979599938 234298 234298 234298.0000 +447 4181 9929180954 2374834 2374834 2374834.0000 +512 4181 3288532102 786542 786542 786542.0000 +select distinct mod(companynr,10) from t4 group by companynr; +mod(companynr,10) +0 +9 +4 +6 +7 +1 +3 +8 +5 +select distinct 1 from t4 group by companynr; +1 +1 +select count(distinct fld1) from t2; +count(distinct fld1) +1199 +select companynr,count(distinct fld1) from t2 group by companynr; +companynr count(distinct fld1) +00 82 +29 95 +34 70 +36 215 +37 588 +40 37 +41 52 +50 11 +53 4 +58 23 +65 10 +68 12 +select companynr,count(*) from t2 group by companynr; +companynr count(*) +00 82 +29 95 +34 70 +36 215 +37 588 +40 37 +41 52 +50 11 +53 4 +58 23 +65 10 +68 12 +select companynr,count(distinct concat(fld1,repeat(65,1000))) from t2 group by companynr; +companynr count(distinct concat(fld1,repeat(65,1000))) +00 82 +29 95 +34 70 +36 215 +37 588 +40 37 +41 52 +50 11 +53 4 +58 23 +65 10 +68 12 +select companynr,count(distinct concat(fld1,repeat(65,200))) from t2 group by companynr; +companynr count(distinct concat(fld1,repeat(65,200))) +00 82 +29 95 +34 70 +36 215 +37 588 +40 37 +41 52 +50 11 +53 4 +58 23 +65 10 +68 12 +select companynr,count(distinct floor(fld1/100)) from t2 group by companynr; +companynr count(distinct floor(fld1/100)) +00 47 +29 35 +34 14 +36 69 +37 108 +40 16 +41 11 +50 9 +53 1 +58 1 +65 1 +68 1 +select companynr,count(distinct concat(repeat(65,1000),floor(fld1/100))) from t2 group by companynr; +companynr count(distinct concat(repeat(65,1000),floor(fld1/100))) +00 47 +29 35 +34 14 +36 69 +37 108 +40 16 +41 11 +50 9 +53 1 +58 1 +65 1 +68 1 +select sum(fld1),fld3 from t2 where fld3="Romans" group by fld1 limit 10; +sum(fld1) fld3 +11402 Romans +select name,count(*) from t3 where name='cloakroom' group by name; +name count(*) +cloakroom 4181 +select name,count(*) from t3 where name='cloakroom' and price>10 group by name; +name count(*) +cloakroom 4181 +select count(*) from t3 where name='cloakroom' and price2=823742; +count(*) +4181 +select name,count(*) from t3 where name='cloakroom' and price2=823742 group by name; +name count(*) +cloakroom 4181 +select name,count(*) from t3 where name >= "extramarital" and price <= 39654943 group by name; +name count(*) +extramarital 4181 +gazer 4181 +gems 4181 +Iranizes 4181 +spates 4181 +tucked 4181 +violinist 4181 +select t2.fld3,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; +fld3 count(*) +spates 4181 +select companynr|0,companyname from t4 group by 1; +companynr|0 companyname +0 Unknown +29 company 1 +34 company 2 +36 company 3 +37 company 4 +40 company 5 +41 company 6 +50 company 11 +53 company 7 +58 company 8 +65 company 9 +68 company 10 +select t2.companynr,companyname,count(*) from t2,t4 where t2.companynr=t4.companynr group by t2.companynr order by companyname; +companynr companyname count(*) +29 company 1 95 +68 company 10 12 +50 company 11 11 +34 company 2 70 +36 company 3 215 +37 company 4 588 +40 company 5 37 +41 company 6 52 +53 company 7 4 +58 company 8 23 +65 company 9 10 +00 Unknown 82 +select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; +fld1 count(*) +158402 4181 +select sum(Period)/count(*) from t1; +sum(Period)/count(*) +9410.0000 +select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; +companynr count sum diff func +37 12543 309394878010 0.0000 464091 +78 8362 414611089292 0.0000 652236 +101 4181 3489454238 0.0000 422281 +154 4181 4112197254950 0.0000 643874 +311 4181 979599938 0.0000 1300291 +447 4181 9929180954 0.0000 1868907 +512 4181 3288532102 0.0000 2140672 +select companynr,sum(price)/count(price) as avg from t3 group by companynr having avg > 70000000 order by avg; +companynr avg +154 983543950.0000 +select companynr,count(*) from t2 group by companynr order by 2 desc; +companynr count(*) +37 588 +36 215 +29 95 +00 82 +34 70 +41 52 +40 37 +58 23 +68 12 +50 11 +65 10 +53 4 +select companynr,count(*) from t2 where companynr > 40 group by companynr order by 2 desc; +companynr count(*) +41 52 +58 23 +68 12 +50 11 +65 10 +53 4 +select t2.fld4,t2.fld1,count(price),sum(price),min(price),max(price),avg(price) from t3,t2 where t3.companynr = 37 and t2.fld1 = t3.t2nr group by fld1,t2.fld4; +fld4 fld1 count(price) sum(price) min(price) max(price) avg(price) +teethe 000001 1 5987435 5987435 5987435 5987435.0000 +dreaded 011401 1 5987435 5987435 5987435 5987435.0000 +scholastics 011402 1 28357832 28357832 28357832 28357832.0000 +audiology 011403 1 39654943 39654943 39654943 39654943.0000 +wallet 011501 1 5987435 5987435 5987435 5987435.0000 +parters 011701 1 5987435 5987435 5987435 5987435.0000 +eschew 011702 1 28357832 28357832 28357832 28357832.0000 +quitter 011703 1 39654943 39654943 39654943 39654943.0000 +neat 012001 1 5987435 5987435 5987435 5987435.0000 +Steinberg 012003 1 39654943 39654943 39654943 39654943.0000 +balled 012301 1 5987435 5987435 5987435 5987435.0000 +persist 012302 1 28357832 28357832 28357832 28357832.0000 +attainments 012303 1 39654943 39654943 39654943 39654943.0000 +capably 012501 1 5987435 5987435 5987435 5987435.0000 +impulsive 012602 1 28357832 28357832 28357832 28357832.0000 +starlet 012603 1 39654943 39654943 39654943 39654943.0000 +featherweight 012701 1 5987435 5987435 5987435 5987435.0000 +pessimist 012702 1 28357832 28357832 28357832 28357832.0000 +daughter 012703 1 39654943 39654943 39654943 39654943.0000 +lawgiver 013601 1 5987435 5987435 5987435 5987435.0000 +stated 013602 1 28357832 28357832 28357832 28357832.0000 +readable 013603 1 39654943 39654943 39654943 39654943.0000 +testicle 013801 1 5987435 5987435 5987435 5987435.0000 +Parsifal 013802 1 28357832 28357832 28357832 28357832.0000 +leavings 013803 1 39654943 39654943 39654943 39654943.0000 +squeaking 013901 1 5987435 5987435 5987435 5987435.0000 +contrasted 016001 1 5987435 5987435 5987435 5987435.0000 +leftover 016201 1 5987435 5987435 5987435 5987435.0000 +whiteners 016202 1 28357832 28357832 28357832 28357832.0000 +erases 016301 1 5987435 5987435 5987435 5987435.0000 +Punjab 016302 1 28357832 28357832 28357832 28357832.0000 +Merritt 016303 1 39654943 39654943 39654943 39654943.0000 +sweetish 018001 1 5987435 5987435 5987435 5987435.0000 +dogging 018002 1 28357832 28357832 28357832 28357832.0000 +scornfully 018003 1 39654943 39654943 39654943 39654943.0000 +fetters 018012 1 28357832 28357832 28357832 28357832.0000 +bivalves 018013 1 39654943 39654943 39654943 39654943.0000 +skulking 018021 1 5987435 5987435 5987435 5987435.0000 +flint 018022 1 28357832 28357832 28357832 28357832.0000 +flopping 018023 1 39654943 39654943 39654943 39654943.0000 +Judas 018032 1 28357832 28357832 28357832 28357832.0000 +vacuuming 018033 1 39654943 39654943 39654943 39654943.0000 +medical 018041 1 5987435 5987435 5987435 5987435.0000 +bloodbath 018042 1 28357832 28357832 28357832 28357832.0000 +subschema 018043 1 39654943 39654943 39654943 39654943.0000 +interdependent 018051 1 5987435 5987435 5987435 5987435.0000 +Graves 018052 1 28357832 28357832 28357832 28357832.0000 +neonatal 018053 1 39654943 39654943 39654943 39654943.0000 +sorters 018061 1 5987435 5987435 5987435 5987435.0000 +epistle 018062 1 28357832 28357832 28357832 28357832.0000 +Conley 018101 1 5987435 5987435 5987435 5987435.0000 +lectured 018102 1 28357832 28357832 28357832 28357832.0000 +Abraham 018103 1 39654943 39654943 39654943 39654943.0000 +cage 018201 1 5987435 5987435 5987435 5987435.0000 +hushes 018202 1 28357832 28357832 28357832 28357832.0000 +Simla 018402 1 28357832 28357832 28357832 28357832.0000 +reporters 018403 1 39654943 39654943 39654943 39654943.0000 +coexist 018601 1 5987435 5987435 5987435 5987435.0000 +Beebe 018602 1 28357832 28357832 28357832 28357832.0000 +Taoism 018603 1 39654943 39654943 39654943 39654943.0000 +Connally 018801 1 5987435 5987435 5987435 5987435.0000 +fetched 018802 1 28357832 28357832 28357832 28357832.0000 +checkpoints 018803 1 39654943 39654943 39654943 39654943.0000 +gritty 018811 1 5987435 5987435 5987435 5987435.0000 +firearm 018812 1 28357832 28357832 28357832 28357832.0000 +minima 019101 1 5987435 5987435 5987435 5987435.0000 +Selfridge 019102 1 28357832 28357832 28357832 28357832.0000 +disable 019103 1 39654943 39654943 39654943 39654943.0000 +witchcraft 019201 1 5987435 5987435 5987435 5987435.0000 +betroth 030501 1 5987435 5987435 5987435 5987435.0000 +Manhattanize 030502 1 28357832 28357832 28357832 28357832.0000 +imprint 030503 1 39654943 39654943 39654943 39654943.0000 +swelling 031901 1 5987435 5987435 5987435 5987435.0000 +interrelationships 036001 1 5987435 5987435 5987435 5987435.0000 +riser 036002 1 28357832 28357832 28357832 28357832.0000 +bee 038001 1 5987435 5987435 5987435 5987435.0000 +kanji 038002 1 28357832 28357832 28357832 28357832.0000 +dental 038003 1 39654943 39654943 39654943 39654943.0000 +railway 038011 1 5987435 5987435 5987435 5987435.0000 +validate 038012 1 28357832 28357832 28357832 28357832.0000 +normalizes 038013 1 39654943 39654943 39654943 39654943.0000 +Kline 038101 1 5987435 5987435 5987435 5987435.0000 +Anatole 038102 1 28357832 28357832 28357832 28357832.0000 +partridges 038103 1 39654943 39654943 39654943 39654943.0000 +recruited 038201 1 5987435 5987435 5987435 5987435.0000 +dimensions 038202 1 28357832 28357832 28357832 28357832.0000 +Chicana 038203 1 39654943 39654943 39654943 39654943.0000 +select t3.companynr,fld3,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 group by companynr,fld3; +companynr fld3 sum(price) +512 boat 786542 +512 capably 786542 +512 cupboard 786542 +512 decliner 786542 +512 descendants 786542 +512 dopers 786542 +512 erases 786542 +512 Micronesia 786542 +512 Miles 786542 +512 skies 786542 +select t2.companynr,count(*),min(fld3),max(fld3),sum(price),avg(price) from t2,t3 where t3.companynr >= 30 and t3.companynr <= 58 and t3.t2nr = t2.fld1 and 1+1=2 group by t2.companynr; +companynr count(*) min(fld3) max(fld3) sum(price) avg(price) +00 1 Omaha Omaha 5987435 5987435.0000 +36 1 dubbed dubbed 28357832 28357832.0000 +37 83 Abraham Wotan 1908978016 22999735.1325 +50 2 scribbled tapestry 68012775 34006387.5000 +select t3.companynr+0,t3.t2nr,fld3,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 37 group by 1,t3.t2nr,fld3,fld3,fld3,fld3,fld3 order by fld1; +t3.companynr+0 t2nr fld3 sum(price) +37 1 Omaha 5987435 +37 11401 breaking 5987435 +37 11402 Romans 28357832 +37 11403 intercepted 39654943 +37 11501 bewilderingly 5987435 +37 11701 astound 5987435 +37 11702 admonishing 28357832 +37 11703 sumac 39654943 +37 12001 flanking 5987435 +37 12003 combed 39654943 +37 12301 Eulerian 5987435 +37 12302 dubbed 28357832 +37 12303 Kane 39654943 +37 12501 annihilates 5987435 +37 12602 Wotan 28357832 +37 12603 snatching 39654943 +37 12701 grazing 5987435 +37 12702 Baird 28357832 +37 12703 celery 39654943 +37 13601 handgun 5987435 +37 13602 foldout 28357832 +37 13603 mystic 39654943 +37 13801 intelligibility 5987435 +37 13802 Augustine 28357832 +37 13803 teethe 39654943 +37 13901 scholastics 5987435 +37 16001 audiology 5987435 +37 16201 wallet 5987435 +37 16202 parters 28357832 +37 16301 eschew 5987435 +37 16302 quitter 28357832 +37 16303 neat 39654943 +37 18001 jarring 5987435 +37 18002 tinily 28357832 +37 18003 balled 39654943 +37 18012 impulsive 28357832 +37 18013 starlet 39654943 +37 18021 lawgiver 5987435 +37 18022 stated 28357832 +37 18023 readable 39654943 +37 18032 testicle 28357832 +37 18033 Parsifal 39654943 +37 18041 Punjab 5987435 +37 18042 Merritt 28357832 +37 18043 Quixotism 39654943 +37 18051 sureties 5987435 +37 18052 puddings 28357832 +37 18053 tapestry 39654943 +37 18061 trimmings 5987435 +37 18062 humility 28357832 +37 18101 tragedies 5987435 +37 18102 skulking 28357832 +37 18103 flint 39654943 +37 18201 relaxing 5987435 +37 18202 offload 28357832 +37 18402 suites 28357832 +37 18403 lists 39654943 +37 18601 vacuuming 5987435 +37 18602 dentally 28357832 +37 18603 humanness 39654943 +37 18801 inch 5987435 +37 18802 Weissmuller 28357832 +37 18803 irresponsibly 39654943 +37 18811 repetitions 5987435 +37 18812 Antares 28357832 +37 19101 ventilate 5987435 +37 19102 pityingly 28357832 +37 19103 interdependent 39654943 +37 19201 Graves 5987435 +37 30501 neonatal 5987435 +37 30502 scribbled 28357832 +37 30503 chafe 39654943 +37 31901 realtor 5987435 +37 36001 elite 5987435 +37 36002 funereal 28357832 +37 38001 Conley 5987435 +37 38002 lectured 28357832 +37 38003 Abraham 39654943 +37 38011 groupings 5987435 +37 38012 dissociate 28357832 +37 38013 coexist 39654943 +37 38101 rusting 5987435 +37 38102 galling 28357832 +37 38103 obliterates 39654943 +37 38201 resumes 5987435 +37 38202 analyzable 28357832 +37 38203 terminator 39654943 +select sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 and t3.t2nr = 38008 and t2.fld1 = 38008 or t2.fld1= t3.t2nr and t3.t2nr = 38008 and t2.fld1 = 38008; +sum(price) +234298 +select t2.fld1,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 and t3.t2nr = 38008 and t2.fld1 = 38008 or t2.fld1 = t3.t2nr and t3.t2nr = 38008 and t2.fld1 = 38008 or t3.t2nr = t2.fld1 and t2.fld1 = 38008 group by t2.fld1; +fld1 sum(price) +038008 234298 +explain select fld3 from t2 where 1>2 or 2>3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain select fld3 from t2 where fld1=fld1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 +select companynr,fld1 from t2 HAVING fld1=250501 or fld1=250502; +companynr fld1 +34 250501 +34 250502 +select companynr,fld1 from t2 WHERE fld1>=250501 HAVING fld1<=250502; +companynr fld1 +34 250501 +34 250502 +select companynr,count(*) as count,sum(fld1) as sum from t2 group by companynr having count > 40 and sum/count >= 120000; +companynr count sum +00 82 10355753 +29 95 14473298 +34 70 17788966 +37 588 83602098 +41 52 12816335 +select companynr from t2 group by companynr having count(*) > 40 and sum(fld1)/count(*) >= 120000 ; +companynr +00 +29 +34 +37 +41 +select t2.companynr,companyname,count(*) from t2,t4 where t2.companynr=t4.companynr group by companyname having t2.companynr >= 40; +companynr companyname count(*) +68 company 10 12 +50 company 11 11 +40 company 5 37 +41 company 6 52 +53 company 7 4 +58 company 8 23 +65 company 9 10 +select count(*) from t2; +count(*) +1199 +select count(*) from t2 where fld1 < 098024; +count(*) +387 +select min(fld1) from t2 where fld1>= 098024; +min(fld1) +98024 +select max(fld1) from t2 where fld1>= 098024; +max(fld1) +1232609 +select count(*) from t3 where price2=76234234; +count(*) +4181 +select count(*) from t3 where companynr=512 and price2=76234234; +count(*) +4181 +explain select min(fld1),max(fld1),count(*) from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL fld1 4 NULL 1199 Using index +select min(fld1),max(fld1),count(*) from t2; +min(fld1) max(fld1) count(*) +0 1232609 1199 +select min(t2nr),max(t2nr) from t3 where t2nr=2115 and price2=823742; +min(t2nr) max(t2nr) +2115 2115 +select count(*),min(t2nr),max(t2nr) from t3 where name='spates' and companynr=78; +count(*) min(t2nr) max(t2nr) +4181 4 41804 +select t2nr,count(*) from t3 where name='gems' group by t2nr limit 20; +t2nr count(*) +9 1 +19 1 +29 1 +39 1 +49 1 +59 1 +69 1 +79 1 +89 1 +99 1 +109 1 +119 1 +129 1 +139 1 +149 1 +159 1 +169 1 +179 1 +189 1 +199 1 +select max(t2nr) from t3 where price=983543950; +max(t2nr) +41807 +select t1.period from t3 = t1 limit 1; +period +1001 +select t1.period from t1 as t1 limit 1; +period +9410 +select t1.period as "Nuvarande period" from t1 as t1 limit 1; +Nuvarande period +9410 +select period as ok_period from t1 limit 1; +ok_period +9410 +select period as ok_period from t1 group by ok_period limit 1; +ok_period +9410 +select 1+1 as summa from t1 group by summa limit 1; +summa +2 +select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; +Nuvarande period +9410 +show tables; +Tables_in_test +t1 +t2 +t3 +t4 +show tables from test like "s%"; +Tables_in_test (s%) +show tables from test like "t?"; +Tables_in_test (t?) +show full columns from t2; +Field Type Collation Null Key Default Extra Privileges Comment +auto int(11) NULL NO PRI NULL auto_increment # +fld1 int(6) unsigned zerofill NULL NO UNI 000000 # +companynr tinyint(2) unsigned zerofill NULL NO 00 # +fld3 char(30) latin1_swedish_ci NO MUL # +fld4 char(35) latin1_swedish_ci NO # +fld5 char(35) latin1_swedish_ci NO # +fld6 char(4) latin1_swedish_ci NO # +show full columns from t2 from test like 'f%'; +Field Type Collation Null Key Default Extra Privileges Comment +fld1 int(6) unsigned zerofill NULL NO UNI 000000 # +fld3 char(30) latin1_swedish_ci NO MUL # +fld4 char(35) latin1_swedish_ci NO # +fld5 char(35) latin1_swedish_ci NO # +fld6 char(4) latin1_swedish_ci NO # +show full columns from t2 from test like 's%'; +Field Type Collation Null Key Default Extra Privileges Comment +show keys from t2; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t2 0 PRIMARY 1 auto A 1199 NULL NULL BTREE +t2 0 fld1 1 fld1 A 1199 NULL NULL BTREE +t2 1 fld3 1 fld3 A NULL NULL NULL BTREE +drop table t4, t3, t2, t1; +DO 1; +DO benchmark(100,1+1),1,1; +do default; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 +do foobar; +ERROR 42S22: Unknown column 'foobar' in 'field list' +CREATE TABLE t1 ( +id mediumint(8) unsigned NOT NULL auto_increment, +pseudo varchar(35) NOT NULL default '', +PRIMARY KEY (id), +UNIQUE KEY pseudo (pseudo) +); +INSERT INTO t1 (pseudo) VALUES ('test'); +INSERT INTO t1 (pseudo) VALUES ('test1'); +SELECT 1 as rnd1 from t1 where rand() > 2; +rnd1 +DROP TABLE t1; +CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (200001,2,1,1,100,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\E$',''),(200002,2,2,1,101,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\C$',''),(200003,1,3,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,0,1,20020425060427,'c:',NULL); +CREATE TABLE t2 ( hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, sampletid smallint(5) unsigned default NULL, sampletime datetime default NULL, samplevalue bigint(20) unsigned default NULL, KEY idx1 (hmid,volid,sampletid,sampletime)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,3,10,'2002-06-01 08:00:00',35),(1,3,1010,'2002-06-01 12:00:01',35); +SELECT a.gvid, (SUM(CASE b.sampletid WHEN 140 THEN b.samplevalue ELSE 0 END)) as the_success,(SUM(CASE b.sampletid WHEN 141 THEN b.samplevalue ELSE 0 END)) as the_fail,(SUM(CASE b.sampletid WHEN 142 THEN b.samplevalue ELSE 0 END)) as the_size,(SUM(CASE b.sampletid WHEN 143 THEN b.samplevalue ELSE 0 END)) as the_time FROM t1 a, t2 b WHERE a.hmid = b.hmid AND a.volid = b.volid AND b.sampletime >= 'wrong-date-value' AND b.sampletime < 'wrong-date-value' AND b.sampletid IN (140, 141, 142, 143) GROUP BY a.gvid; +gvid the_success the_fail the_size the_time +Warnings: +Warning 1292 Incorrect datetime value: 'wrong-date-value' for column 'sampletime' at row 1 +Warning 1292 Incorrect datetime value: 'wrong-date-value' for column 'sampletime' at row 1 +SELECT a.gvid, (SUM(CASE b.sampletid WHEN 140 THEN b.samplevalue ELSE 0 END)) as the_success,(SUM(CASE b.sampletid WHEN 141 THEN b.samplevalue ELSE 0 END)) as the_fail,(SUM(CASE b.sampletid WHEN 142 THEN b.samplevalue ELSE 0 END)) as the_size,(SUM(CASE b.sampletid WHEN 143 THEN b.samplevalue ELSE 0 END)) as the_time FROM t1 a, t2 b WHERE a.hmid = b.hmid AND a.volid = b.volid AND b.sampletime >= NULL AND b.sampletime < NULL AND b.sampletid IN (140, 141, 142, 143) GROUP BY a.gvid; +gvid the_success the_fail the_size the_time +DROP TABLE t1,t2; +create table t1 ( A_Id bigint(20) NOT NULL default '0', A_UpdateBy char(10) NOT NULL default '', A_UpdateDate bigint(20) NOT NULL default '0', A_UpdateSerial int(11) NOT NULL default '0', other_types bigint(20) NOT NULL default '0', wss_type bigint(20) NOT NULL default '0'); +INSERT INTO t1 VALUES (102935998719055004,'brade',1029359987,2,102935229116544068,102935229216544093); +select wss_type from t1 where wss_type ='102935229216544106'; +wss_type +select wss_type from t1 where wss_type ='102935229216544105'; +wss_type +select wss_type from t1 where wss_type ='102935229216544104'; +wss_type +select wss_type from t1 where wss_type ='102935229216544093'; +wss_type +102935229216544093 +select wss_type from t1 where wss_type =102935229216544093; +wss_type +102935229216544093 +drop table t1; +select 1+2,"aaaa",3.13*2.0 into @a,@b,@c; +select @a; +@a +3 +select @b; +@b +aaaa +select @c; +@c +6.260 +create table t1 (a int not null auto_increment primary key); +insert into t1 values (); +insert into t1 values (); +insert into t1 values (); +select * from (t1 as t2 left join t1 as t3 using (a)), t1; +a a +1 1 +2 1 +3 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 +select * from t1, (t1 as t2 left join t1 as t3 using (a)); +a a +1 1 +2 1 +3 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 +select * from (t1 as t2 left join t1 as t3 using (a)) straight_join t1; +a a +1 1 +2 1 +3 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 +select * from t1 straight_join (t1 as t2 left join t1 as t3 using (a)); +a a +1 1 +2 1 +3 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 +select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; +a a +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 +select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +a a +2 1 +3 1 +2 2 +3 2 +2 3 +3 3 +select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a ); +a +1 +2 +3 +select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) using ( a ); +a +1 +2 +3 +select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1; +a a +1 2 +1 3 +2 2 +2 3 +3 2 +3 3 +select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +a a +1 NULL +2 1 +2 2 +2 3 +3 1 +3 2 +3 3 +select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a ); +a +1 +2 +3 +select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a ); +a +1 +2 +3 +select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; +a +1 +2 +3 +select * from t1 natural left join (t1 as t2 left join t1 as t3 using (a)); +a +1 +2 +3 +select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; +a a +NULL 1 +1 2 +2 2 +3 2 +1 3 +2 3 +3 3 +select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +a a +2 1 +3 1 +2 2 +3 2 +2 3 +3 3 +select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a ); +a +1 +2 +3 +select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a ); +a +1 +2 +3 +select * from (t1 as t2 left join t1 as t3 using (a)) natural right join t1; +a +1 +2 +3 +select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a)); +a +1 +2 +3 +select * from t1 natural join (t1 as t2 left join t1 as t3 using (a)); +a +1 +2 +3 +select * from (t1 as t2 left join t1 as t3 using (a)) natural join t1; +a +1 +2 +3 +drop table t1; +CREATE TABLE t1 ( aa char(2), id int(11) NOT NULL auto_increment, t2_id int(11) NOT NULL default '0', PRIMARY KEY (id), KEY replace_id (t2_id)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ("1",8264,2506),("2",8299,2517),("3",8301,2518),("4",8302,2519),("5",8303,2520),("6",8304,2521),("7",8305,2522); +CREATE TABLE t2 ( id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (2517), (2518), (2519), (2520), (2521), (2522); +select * from t1, t2 WHERE t1.t2_id = t2.id and t1.t2_id > 0 order by t1.id LIMIT 0, 5; +aa id t2_id id +2 8299 2517 2517 +3 8301 2518 2518 +4 8302 2519 2519 +5 8303 2520 2520 +6 8304 2521 2521 +drop table t1,t2; +create table t1 (id1 int NOT NULL); +create table t2 (id2 int NOT NULL); +create table t3 (id3 int NOT NULL); +create table t4 (id4 int NOT NULL, id44 int NOT NULL, KEY (id4)); +insert into t1 values (1); +insert into t1 values (2); +insert into t2 values (1); +insert into t4 values (1,1); +explain select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3 +left join t4 on id3 = id4 where id2 = 1 or id4 = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 system NULL NULL NULL NULL 0 const row not found +1 SIMPLE t4 const id4 NULL NULL NULL 1 +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL NULL NULL NULL NULL 1 Using where +select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3 +left join t4 on id3 = id4 where id2 = 1 or id4 = 1; +id1 id2 id3 id4 id44 +1 1 NULL NULL NULL +drop table t1,t2,t3,t4; +create table t1(s varchar(10) not null); +create table t2(s varchar(10) not null primary key); +create table t3(s varchar(10) not null primary key); +insert into t1 values ('one\t'), ('two\t'); +insert into t2 values ('one\r'), ('two\t'); +insert into t3 values ('one '), ('two\t'); +select * from t1 where s = 'one'; +s +select * from t2 where s = 'one'; +s +select * from t3 where s = 'one'; +s +one +select * from t1,t2 where t1.s = t2.s; +s s +two two +select * from t2,t3 where t2.s = t3.s; +s s +two two +drop table t1, t2, t3; +create table t1 (a integer, b integer, index(a), index(b)); +create table t2 (c integer, d integer, index(c), index(d)); +insert into t1 values (1,2), (2,2), (3,2), (4,2); +insert into t2 values (1,3), (2,3), (3,4), (4,4); +explain select * from t1 left join t2 on a=c where d in (4); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref c,d d 5 const 1 Using where +1 SIMPLE t1 ref a a 5 test.t2.c 2 Using where +select * from t1 left join t2 on a=c where d in (4); +a b c d +3 2 3 4 +4 2 4 4 +explain select * from t1 left join t2 on a=c where d = 4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref c,d d 5 const 1 Using where +1 SIMPLE t1 ref a a 5 test.t2.c 2 Using where +select * from t1 left join t2 on a=c where d = 4; +a b c d +3 2 3 4 +4 2 4 4 +drop table t1, t2; +CREATE TABLE t1 ( +i int(11) NOT NULL default '0', +c char(10) NOT NULL default '', +PRIMARY KEY (i), +UNIQUE KEY c (c) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,'a'); +INSERT INTO t1 VALUES (2,'b'); +INSERT INTO t1 VALUES (3,'c'); +EXPLAIN SELECT i FROM t1 WHERE i=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index +DROP TABLE t1; +CREATE TABLE t1 ( a BLOB, INDEX (a(20)) ); +CREATE TABLE t2 ( a BLOB, INDEX (a(20)) ); +INSERT INTO t1 VALUES ('one'),('two'),('three'),('four'),('five'); +INSERT INTO t2 VALUES ('one'),('two'),('three'),('four'),('five'); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 USE INDEX (a) ON t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 +1 SIMPLE t2 ref a a 23 test.t1.a 2 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 +1 SIMPLE t2 ref a a 23 test.t1.a 2 +DROP TABLE t1, t2; +CREATE TABLE t1 ( city char(30) ); +INSERT INTO t1 VALUES ('London'); +INSERT INTO t1 VALUES ('Paris'); +SELECT * FROM t1 WHERE city='London'; +city +London +SELECT * FROM t1 WHERE city='london'; +city +London +EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t1 WHERE city='London' AND city='london'; +city +London +EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +city +London +DROP TABLE t1; +create table t1 (a int(11) unsigned, b int(11) unsigned); +insert into t1 values (1,0), (1,1), (1,2); +select a-b from t1 order by 1; +a-b +0 +1 +18446744073709551615 +select a-b , (a-b < 0) from t1 order by 1; +a-b (a-b < 0) +0 0 +1 0 +18446744073709551615 0 +select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; +d (a-b >= 0) b +1 1 0 +0 1 1 +18446744073709551615 1 2 +select cast((a - b) as unsigned) from t1 order by 1; +cast((a - b) as unsigned) +0 +1 +18446744073709551615 +drop table t1; +create table t1 (a int(11)); +select all all * from t1; +a +select distinct distinct * from t1; +a +select all distinct * from t1; +ERROR HY000: Incorrect usage of ALL and DISTINCT +select distinct all * from t1; +ERROR HY000: Incorrect usage of ALL and DISTINCT +drop table t1; +CREATE TABLE t1 ( +kunde_intern_id int(10) unsigned NOT NULL default '0', +kunde_id int(10) unsigned NOT NULL default '0', +FK_firma_id int(10) unsigned NOT NULL default '0', +aktuell enum('Ja','Nein') NOT NULL default 'Ja', +vorname varchar(128) NOT NULL default '', +nachname varchar(128) NOT NULL default '', +geloescht enum('Ja','Nein') NOT NULL default 'Nein', +firma varchar(128) NOT NULL default '' +); +INSERT INTO t1 VALUES +(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), +(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 +WHERE +( +( +( '' != '' AND firma LIKE CONCAT('%', '', '%')) +OR +(vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND +'Vorname1' != '' AND 'xxxx' != '') +) +AND +( +aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 +) +) +; +kunde_id FK_firma_id aktuell vorname nachname geloescht +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, +geloescht FROM t1 +WHERE +( +( +aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 +) +AND +( +( '' != '' AND firma LIKE CONCAT('%', '', '%') ) +OR +( vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND +'xxxx' != '') +) +) +; +kunde_id FK_firma_id aktuell vorname nachname geloescht +SELECT COUNT(*) FROM t1 WHERE +( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) +AND FK_firma_id = 2; +COUNT(*) +0 +drop table t1; +CREATE TABLE t1 (b BIGINT(20) UNSIGNED NOT NULL, PRIMARY KEY (b)); +INSERT INTO t1 VALUES (0x8000000000000000); +SELECT b FROM t1 WHERE b=0x8000000000000000; +b +9223372036854775808 +DROP TABLE t1; +CREATE TABLE `t1` ( `gid` int(11) default NULL, `uid` int(11) default NULL); +CREATE TABLE `t2` ( `ident` int(11) default NULL, `level` char(16) default NULL); +INSERT INTO `t2` VALUES (0,'READ'); +CREATE TABLE `t3` ( `id` int(11) default NULL, `name` char(16) default NULL); +INSERT INTO `t3` VALUES (1,'fs'); +select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid, t3.id, 0); +id name gid uid ident level +1 fs NULL NULL 0 READ +drop table t1,t2,t3; +CREATE TABLE t1 ( +acct_id int(11) NOT NULL default '0', +profile_id smallint(6) default NULL, +UNIQUE KEY t1$acct_id (acct_id), +KEY t1$profile_id (profile_id) +); +INSERT INTO t1 VALUES (132,17),(133,18); +CREATE TABLE t2 ( +profile_id smallint(6) default NULL, +queue_id int(11) default NULL, +seq int(11) default NULL, +KEY t2$queue_id (queue_id) +); +INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1); +CREATE TABLE t3 ( +id int(11) NOT NULL default '0', +qtype int(11) default NULL, +seq int(11) default NULL, +warn_lvl int(11) default NULL, +crit_lvl int(11) default NULL, +rr1 tinyint(4) NOT NULL default '0', +rr2 int(11) default NULL, +default_queue tinyint(4) NOT NULL default '0', +KEY t3$qtype (qtype), +KEY t3$id (id) +); +INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0), +(36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0); +SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q +WHERE +(pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND +(pq.queue_id = q.id) AND (q.rr1 <> 1); +COUNT(*) +4 +drop table t1,t2,t3; +create table t1 (f1 int); +insert into t1 values (1),(NULL); +create table t2 (f2 int, f3 int, f4 int); +create index idx1 on t2 (f4); +insert into t2 values (1,2,3),(2,4,6); +select A.f2 from t1 left join t2 A on A.f2 = f1 where A.f3=(select min(f3) +from t2 C where A.f4 = C.f4) or A.f3 IS NULL; +f2 +1 +NULL +drop table t1,t2; +create table t2 (a tinyint unsigned); +create index t2i on t2(a); +insert into t2 values (0), (254), (255); +explain select * from t2 where a > -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index t2i t2i 2 NULL 3 Using where; Using index +select * from t2 where a > -1; +a +0 +254 +255 +drop table t2; +CREATE TABLE t1 (a int, b int, c int); +INSERT INTO t1 +SELECT 50, 3, 3 FROM DUAL +WHERE NOT EXISTS +(SELECT * FROM t1 WHERE a = 50 AND b = 3); +SELECT * FROM t1; +a b c +50 3 3 +INSERT INTO t1 +SELECT 50, 3, 3 FROM DUAL +WHERE NOT EXISTS +(SELECT * FROM t1 WHERE a = 50 AND b = 3); +select found_rows(); +found_rows() +0 +SELECT * FROM t1; +a b c +50 3 3 +select count(*) from t1; +count(*) +1 +select found_rows(); +found_rows() +1 +select count(*) from t1 limit 2,3; +count(*) +select found_rows(); +found_rows() +1 +select SQL_CALC_FOUND_ROWS count(*) from t1 limit 2,3; +count(*) +select found_rows(); +found_rows() +1 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT); +(SELECT a, b AS c FROM t1) ORDER BY c+1; +a c +(SELECT a, b AS c FROM t1) ORDER BY b+1; +a c +SELECT a, b AS c FROM t1 ORDER BY c+1; +a c +SELECT a, b AS c FROM t1 ORDER BY b+1; +a c +drop table t1; +create table t1(f1 int, f2 int); +create table t2(f3 int); +select f1 from t1,t2 where f1=f2 and (f1,f2) = ((1,1)); +f1 +select f1 from t1,t2 where f1=f2 and (f1,NULL) = ((1,1)); +f1 +select f1 from t1,t2 where f1=f2 and (f1,f2) = ((1,NULL)); +f1 +insert into t1 values(1,1),(2,null); +insert into t2 values(2); +select * from t1,t2 where f1=f3 and (f1,f2) = (2,null); +f1 f2 f3 +select * from t1,t2 where f1=f3 and (f1,f2) <=> (2,null); +f1 f2 f3 +2 NULL 2 +drop table t1,t2; +create table t1 (f1 int not null auto_increment primary key, f2 varchar(10)); +create table t11 like t1; +insert into t1 values(1,""),(2,""); +show table status like 't1%'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 PBXT 10 Dynamic 2 30 X X X X X X X X latin1_swedish_ci NULL +t11 PBXT 10 Dynamic 0 30 X X X X X X X X latin1_swedish_ci NULL +select 123 as a from t1 where f1 is null; +a +drop table t1,t11; +CREATE TABLE t1 ( a INT NOT NULL, b INT NOT NULL, UNIQUE idx (a,b) ); +INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4); +CREATE TABLE t2 ( a INT NOT NULL, b INT NOT NULL, e INT ); +INSERT INTO t2 VALUES ( 1,10,1), (1,10,2), (1,11,1), (1,11,2), (1,2,1), (1,2,2),(1,2,3); +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY a, b, c; +a b c d +1 2 1 1 +1 2 2 1 +1 2 3 1 +1 10 2 +1 11 2 +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY t1.a, t1.b, c; +a b c d +1 10 4 +1 2 1 1 +1 2 2 1 +1 2 3 1 +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY t2.a, t2.b, c; +a b c d +1 2 1 1 +1 2 2 1 +1 2 3 1 +1 10 2 +1 11 2 +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2,t1 +WHERE t2.a = t1.a AND t2.b = t1.b GROUP BY a, b, c; +a b c d +1 2 1 1 +1 2 2 1 +1 2 3 1 +DROP TABLE IF EXISTS t1, t2; +create table t1 (f1 int primary key, f2 int); +create table t2 (f3 int, f4 int, primary key(f3,f4)); +insert into t1 values (1,1); +insert into t2 values (1,1),(1,2); +select distinct count(f2) >0 from t1 left join t2 on f1=f3 group by f1; +count(f2) >0 +1 +drop table t1,t2; +create table t1 (f1 int,f2 int); +insert into t1 values(1,1); +create table t2 (f3 int, f4 int, primary key(f3,f4)); +insert into t2 values(1,1); +select * from t1 where f1 in (select f3 from t2 where (f3,f4)= (select f3,f4 from t2)); +f1 f2 +1 1 +drop table t1,t2; +CREATE TABLE t1(a int, b int, c int, KEY b(b), KEY c(c)); +insert into t1 values (1,0,0),(2,0,0); +CREATE TABLE t2 (a int, b varchar(2), c varchar(2), PRIMARY KEY(a)); +insert into t2 values (1,'',''), (2,'',''); +CREATE TABLE t3 (a int, b int, PRIMARY KEY (a,b), KEY a (a), KEY b (b)); +insert into t3 values (1,1),(1,2); +explain select straight_join DISTINCT t2.a,t2.b, t1.c from t1, t3, t2 +where (t1.c=t2.a or (t1.c=t3.a and t2.a=t3.b)) and t1.b=556476786 and +t2.b like '%%' order by t2.b limit 0,1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref b,c b 5 const 1 Using where; Using temporary; Using filesort +1 SIMPLE t3 index PRIMARY,a,b PRIMARY 8 NULL 2 Using index; Using join buffer +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 2 Range checked for each record (index map: 0x1) +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (a int, INDEX idx(a)); +INSERT INTO t1 VALUES (2), (3), (1); +EXPLAIN SELECT * FROM t1 IGNORE INDEX (idx); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +EXPLAIN SELECT * FROM t1 IGNORE INDEX (a); +ERROR 42000: Key 'a' doesn't exist in table 't1' +EXPLAIN SELECT * FROM t1 FORCE INDEX (a); +ERROR 42000: Key 'a' doesn't exist in table 't1' +DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (4,10); +CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); +INSERT INTO t2 VALUES (1,NULL), (2,10); +ALTER TABLE t1 ENABLE KEYS; +Warnings: +Note 1031 Table storage engine for 't1' doesn't have this option +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (key1 float default NULL, UNIQUE KEY key1 (key1)); +CREATE TABLE t2 (key2 float default NULL, UNIQUE KEY key2 (key2)); +INSERT INTO t1 VALUES (0.3762),(0.3845),(0.6158),(0.7941); +INSERT INTO t2 VALUES (1.3762),(1.3845),(1.6158),(1.7941); +explain select max(key1) from t1 where key1 <= 0.6158; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key2) from t2 where key2 <= 1.6158; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key1) from t1 where key1 >= 0.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key2) from t2 where key2 >= 1.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(key1) from t1 where key1 <= 0.6158; +max(key1) +0.61580002307892 +select max(key2) from t2 where key2 <= 1.6158; +max(key2) +1.6158000230789 +select min(key1) from t1 where key1 >= 0.3762; +min(key1) +0.37619999051094 +select min(key2) from t2 where key2 >= 1.3762; +min(key2) +1.3761999607086 +select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +max(key1) min(key2) +0.61580002307892 1.3761999607086 +select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +max(key1) +0.61580002307892 +select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; +min(key1) +0.37619999051094 +DROP TABLE t1,t2; +CREATE TABLE t1 (i BIGINT UNSIGNED NOT NULL); +INSERT INTO t1 VALUES (10); +SELECT i='1e+01',i=1e+01, i in (1e+01,1e+01), i in ('1e+01','1e+01') FROM t1; +i='1e+01' i=1e+01 i in (1e+01,1e+01) i in ('1e+01','1e+01') +1 1 1 1 +DROP TABLE t1; +create table t1(a bigint unsigned, b bigint); +insert into t1 values (0xfffffffffffffffff, 0xfffffffffffffffff), +(0x10000000000000000, 0x10000000000000000), +(0x8fffffffffffffff, 0x8fffffffffffffff); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'b' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'b' at row 2 +Warning 1264 Out of range value for column 'b' at row 3 +select hex(a), hex(b) from t1; +hex(a) hex(b) +FFFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF +8FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF +drop table t1; +End of 4.1 tests +CREATE TABLE t1 ( +K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', +K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000', +F2I4 int(11) NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO t1 VALUES +('W%RT', '0100', 1), +('W-RT', '0100', 1), +('WART', '0100', 1), +('WART', '0200', 1), +('WERT', '0100', 2), +('WORT','0200', 2), +('WT', '0100', 2), +('W_RT', '0100', 2), +('WaRT', '0100', 3), +('WART', '0300', 3), +('WRT' , '0400', 3), +('WURM', '0500', 3), +('W%T', '0600', 4), +('WA%T', '0700', 4), +('WA_T', '0800', 4); +SELECT K2C4, K4N4, F2I4 FROM t1 +WHERE K2C4 = 'WART' AND +(F2I4 = 2 AND K2C4 = 'WART' OR (F2I4 = 2 OR K4N4 = '0200')); +K2C4 K4N4 F2I4 +WART 0200 1 +SELECT K2C4, K4N4, F2I4 FROM t1 +WHERE K2C4 = 'WART' AND (K2C4 = 'WART' OR K4N4 = '0200'); +K2C4 K4N4 F2I4 +WART 0100 1 +WART 0200 1 +WART 0300 3 +DROP TABLE t1; +create table t1 (a int, b int); +create table t2 like t1; +select t1.a from (t1 inner join t2 on t1.a=t2.a) where t2.a=1; +a +select t1.a from ((t1 inner join t2 on t1.a=t2.a)) where t2.a=1; +a +select x.a, y.a, z.a from ( (t1 x inner join t2 y on x.a=y.a) inner join t2 z on y.a=z.a) WHERE x.a=1; +a a a +drop table t1,t2; +create table t1 (s1 varchar(5)); +insert into t1 values ('Wall'); +select min(s1) from t1 group by s1 with rollup; +min(s1) +Wall +Wall +drop table t1; +create table t1 (s1 int) engine=myisam; +insert into t1 values (0); +select avg(distinct s1) from t1 group by s1 with rollup; +avg(distinct s1) +0.0000 +0.0000 +drop table t1; +create table t1 (s1 int); +insert into t1 values (null),(1); +select distinct avg(s1) as x from t1 group by s1 with rollup; +x +NULL +1.0000 +drop table t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +INSERT INTO t2 VALUES (2), (4), (6); +SELECT t1.a FROM t1 STRAIGHT_JOIN t2 ON t1.a=t2.a; +a +2 +4 +EXPLAIN SELECT t1.a FROM t1 STRAIGHT_JOIN t2 ON t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where; Using join buffer +EXPLAIN SELECT t1.a FROM t1 INNER JOIN t2 ON t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using join buffer +DROP TABLE t1,t2; +select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; +x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0 +16 16 2 2 +create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null); +create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4)); +insert into t1 values (" 2", 2); +insert into t2 values (" 2", " one "),(" 2", " two "); +select * from t1 left join t2 on f1 = f3; +f1 f2 f3 f4 + 2 2 2 one + 2 2 2 two +drop table t1,t2; +create table t1 (empnum smallint, grp int); +create table t2 (empnum int, name char(5)); +insert into t1 values(1,1); +insert into t2 values(1,'bob'); +create view v1 as select * from t2 inner join t1 using (empnum); +select * from v1; +empnum name grp +1 bob 1 +drop table t1,t2; +drop view v1; +create table t1 (pk int primary key, b int); +create table t2 (pk int primary key, c int); +select pk from t1 inner join t2 using (pk); +pk +drop table t1,t2; +create table t1 (s1 int, s2 char(5), s3 decimal(10)); +create view v1 as select s1, s2, 'x' as s3 from t1; +select * from t1 natural join v1; +s1 s2 s3 +insert into t1 values (1,'x',5); +select * from t1 natural join v1; +s1 s2 s3 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'x' +drop table t1; +drop view v1; +create table t1(a1 int); +create table t2(a2 int); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +create view v2 (c) as select a1 from t1; +select * from t1 natural left join t2; +a1 a2 +1 1 +1 2 +2 1 +2 2 +select * from t1 natural right join t2; +a2 a1 +1 1 +1 2 +2 1 +2 2 +select * from v2 natural left join t2; +c a2 +1 1 +1 2 +2 1 +2 2 +select * from v2 natural right join t2; +a2 c +1 1 +1 2 +2 1 +2 2 +drop table t1, t2; +drop view v2; +create table t1 (a int(10), t1_val int(10)); +create table t2 (b int(10), t2_val int(10)); +create table t3 (a int(10), b int(10)); +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(2,2),(3,3); +insert into t3 values (1,1),(2,1),(3,1),(4,1); +select * from t1 natural join t2 natural join t3; +a b t1_val t2_val +1 1 1 1 +2 1 2 1 +select * from t1 natural join t3 natural join t2; +b a t1_val t2_val +1 1 1 1 +1 2 2 1 +drop table t1, t2, t3; +DO IFNULL(NULL, NULL); +SELECT CAST(IFNULL(NULL, NULL) AS DECIMAL); +CAST(IFNULL(NULL, NULL) AS DECIMAL) +NULL +SELECT ABS(IFNULL(NULL, NULL)); +ABS(IFNULL(NULL, NULL)) +NULL +SELECT IFNULL(NULL, NULL); +IFNULL(NULL, NULL) +NULL +SET @OLD_SQL_MODE12595=@@SQL_MODE, @@SQL_MODE=''; +SHOW LOCAL VARIABLES LIKE 'SQL_MODE'; +Variable_name Value +sql_mode +CREATE TABLE BUG_12595(a varchar(100)); +INSERT INTO BUG_12595 VALUES ('hakan%'), ('hakank'), ("ha%an"); +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%'; +a +hakan% +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +a +hakan% +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan%' ESCAPE ''; +a +hakan% +hakank +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%' ESCAPE ''; +a +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE 0x5c; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'ha%%an' ESCAPE '%'; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE '\\'; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'ha|%an' ESCAPE '|'; +a +ha%an +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +SHOW LOCAL VARIABLES LIKE 'SQL_MODE'; +Variable_name Value +sql_mode NO_BACKSLASH_ESCAPES +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%'; +a +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +a +hakan% +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%' ESCAPE '\\'; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan%' ESCAPE ''; +ERROR HY000: Incorrect arguments to ESCAPE +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE 0x5c; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'ha|%an' ESCAPE '|'; +a +ha%an +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\n%' ESCAPE '\n'; +ERROR HY000: Incorrect arguments to ESCAPE +SET @@SQL_MODE=@OLD_SQL_MODE12595; +DROP TABLE BUG_12595; +create table t1 (a char(1)); +create table t2 (a char(1)); +insert into t1 values ('a'),('b'),('c'); +insert into t2 values ('b'),('c'),('d'); +select a from t1 natural join t2; +a +b +c +select * from t1 natural join t2 where a = 'b'; +a +b +drop table t1, t2; +CREATE TABLE t1 (`id` TINYINT); +CREATE TABLE t2 (`id` TINYINT); +CREATE TABLE t3 (`id` TINYINT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.notacolumn=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT id,t3.id FROM (t1 JOIN t2 ON (t2.id=t1.id)) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +drop table t1, t2, t3; +create table t1 (a int(10),b int(10)); +create table t2 (a int(10),b int(10)); +insert into t1 values (1,10),(2,20),(3,30); +insert into t2 values (1,10); +select * from t1 inner join t2 using (A); +a b b +1 10 10 +select * from t1 inner join t2 using (a); +a b b +1 10 10 +drop table t1, t2; +create table t1 (a int, c int); +create table t2 (b int); +create table t3 (b int, a int); +create table t4 (c int); +insert into t1 values (1,1); +insert into t2 values (1); +insert into t3 values (1,1); +insert into t4 values (1); +select * from t1 join t2 join t3 on (t2.b = t3.b and t1.a = t3.a); +a c b b a +1 1 1 1 1 +select * from t1, t2 join t3 on (t2.b = t3.b and t1.a = t3.a); +ERROR 42S22: Unknown column 't1.a' in 'on clause' +select * from t1 join t2 join t3 join t4 on (t1.a = t4.c and t2.b = t4.c); +a c b b a c +1 1 1 1 1 1 +select * from t1 join t2 join t4 using (c); +c a b +1 1 1 +drop table t1, t2, t3, t4; +create table t1(x int, y int); +create table t2(x int, y int); +create table t3(x int, primary key(x)); +insert into t1 values (1, 1), (2, 1), (3, 1), (4, 3), (5, 6), (6, 6); +insert into t2 values (1, 1), (2, 1), (3, 3), (4, 6), (5, 6); +insert into t3 values (1), (2), (3), (4), (5); +select t1.x, t3.x from t1, t2, t3 where t1.x = t2.x and t3.x >= t1.y and t3.x <= t2.y; +x x +1 1 +2 1 +3 1 +3 2 +3 3 +4 3 +4 4 +4 5 +drop table t1,t2,t3; +create table t1 (id char(16) not null default '', primary key (id)); +insert into t1 values ('100'),('101'),('102'); +create table t2 (id char(16) default null); +insert into t2 values (1); +create view v1 as select t1.id from t1; +create view v2 as select t2.id from t2; +create view v3 as select (t1.id+2) as id from t1 natural left join t2; +select t1.id from t1 left join v2 using (id); +id +100 +101 +102 +select t1.id from v2 right join t1 using (id); +id +100 +101 +102 +select t1.id from t1 left join v3 using (id); +id +100 +101 +102 +select * from t1 left join v2 using (id); +id +100 +101 +102 +select * from v2 right join t1 using (id); +id +100 +101 +102 +select * from t1 left join v3 using (id); +id +100 +101 +102 +select v1.id from v1 left join v2 using (id); +id +100 +101 +102 +select v1.id from v2 right join v1 using (id); +id +100 +101 +102 +select v1.id from v1 left join v3 using (id); +id +100 +101 +102 +select * from v1 left join v2 using (id); +id +100 +101 +102 +select * from v2 right join v1 using (id); +id +100 +101 +102 +select * from v1 left join v3 using (id); +id +100 +101 +102 +drop table t1, t2; +drop view v1, v2, v3; +create table t1 (id int(11) not null default '0'); +insert into t1 values (123),(191),(192); +create table t2 (id char(16) character set utf8 not null); +insert into t2 values ('58013'),('58014'),('58015'),('58016'); +create table t3 (a_id int(11) not null, b_id char(16) character set utf8); +insert into t3 values (123,null),(123,null),(123,null),(123,null),(123,null),(123,'58013'); +select count(*) +from t1 inner join (t3 left join t2 on t2.id = t3.b_id) on t1.id = t3.a_id; +count(*) +6 +select count(*) +from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; +count(*) +6 +drop table t1,t2,t3; +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +select * from t1 join t2 join t3 on (t1.a=t3.c); +a b c +select * from t1 join t2 left join t3 on (t1.a=t3.c); +a b c +select * from t1 join t2 right join t3 on (t1.a=t3.c); +a b c +select * from t1 join t2 straight_join t3 on (t1.a=t3.c); +a b c +drop table t1, t2 ,t3; +create table t1(f1 int, f2 date); +insert into t1 values(1,'2005-01-01'),(2,'2005-09-01'),(3,'2005-09-30'), +(4,'2005-10-01'),(5,'2005-12-30'); +select * from t1 where f2 >= 0; +f1 f2 +1 2005-01-01 +2 2005-09-01 +3 2005-09-30 +4 2005-10-01 +5 2005-12-30 +select * from t1 where f2 >= '0000-00-00'; +f1 f2 +1 2005-01-01 +2 2005-09-01 +3 2005-09-30 +4 2005-10-01 +5 2005-12-30 +select * from t1 where f2 >= '2005-09-31'; +f1 f2 +4 2005-10-01 +5 2005-12-30 +select * from t1 where f2 >= '2005-09-3a'; +f1 f2 +3 2005-09-30 +4 2005-10-01 +5 2005-12-30 +Warnings: +Warning 1292 Incorrect date value: '2005-09-3a' for column 'f2' at row 1 +select * from t1 where f2 <= '2005-09-31'; +f1 f2 +1 2005-01-01 +2 2005-09-01 +3 2005-09-30 +select * from t1 where f2 <= '2005-09-3a'; +f1 f2 +1 2005-01-01 +2 2005-09-01 +Warnings: +Warning 1292 Incorrect date value: '2005-09-3a' for column 'f2' at row 1 +drop table t1; +create table t1 (f1 int, f2 int); +insert into t1 values (1, 30), (2, 20), (3, 10); +create algorithm=merge view v1 as select f1, f2 from t1; +create algorithm=merge view v2 (f2, f1) as select f1, f2 from t1; +create algorithm=merge view v3 as select t1.f1 as f2, t1.f2 as f1 from t1; +select t1.f1 as x1, f1 from t1 order by t1.f1; +x1 f1 +1 1 +2 2 +3 3 +select v1.f1 as x1, f1 from v1 order by v1.f1; +x1 f1 +1 1 +2 2 +3 3 +select v2.f1 as x1, f1 from v2 order by v2.f1; +x1 f1 +10 10 +20 20 +30 30 +select v3.f1 as x1, f1 from v3 order by v3.f1; +x1 f1 +10 10 +20 20 +30 30 +select f1, f2, v1.f1 as x1 from v1 order by v1.f1; +f1 f2 x1 +1 30 1 +2 20 2 +3 10 3 +select f1, f2, v2.f1 as x1 from v2 order by v2.f1; +f1 f2 x1 +10 3 10 +20 2 20 +30 1 30 +select f1, f2, v3.f1 as x1 from v3 order by v3.f1; +f1 f2 x1 +10 3 10 +20 2 20 +30 1 30 +drop table t1; +drop view v1, v2, v3; +CREATE TABLE t1(key_a int4 NOT NULL, optimus varchar(32), PRIMARY KEY(key_a)); +CREATE TABLE t2(key_a int4 NOT NULL, prime varchar(32), PRIMARY KEY(key_a)); +CREATE table t3(key_a int4 NOT NULL, key_b int4 NOT NULL, foo varchar(32), +PRIMARY KEY(key_a,key_b)); +INSERT INTO t1 VALUES (0,''); +INSERT INTO t1 VALUES (1,'i'); +INSERT INTO t1 VALUES (2,'j'); +INSERT INTO t1 VALUES (3,'k'); +INSERT INTO t2 VALUES (1,'r'); +INSERT INTO t2 VALUES (2,'s'); +INSERT INTO t2 VALUES (3,'t'); +INSERT INTO t3 VALUES (1,5,'x'); +INSERT INTO t3 VALUES (1,6,'y'); +INSERT INTO t3 VALUES (2,5,'xx'); +INSERT INTO t3 VALUES (2,6,'yy'); +INSERT INTO t3 VALUES (2,7,'zz'); +INSERT INTO t3 VALUES (3,5,'xxx'); +SELECT t2.key_a,foo +FROM t1 INNER JOIN t2 ON t1.key_a = t2.key_a +INNER JOIN t3 ON t1.key_a = t3.key_a +WHERE t2.key_a=2 and key_b=5; +key_a foo +2 xx +EXPLAIN SELECT t2.key_a,foo +FROM t1 INNER JOIN t2 ON t1.key_a = t2.key_a +INNER JOIN t3 ON t1.key_a = t3.key_a +WHERE t2.key_a=2 and key_b=5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index +1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 Using index +1 SIMPLE t3 const PRIMARY PRIMARY 8 const,const 1 +SELECT t2.key_a,foo +FROM t1 INNER JOIN t2 ON t2.key_a = t1.key_a +INNER JOIN t3 ON t1.key_a = t3.key_a +WHERE t2.key_a=2 and key_b=5; +key_a foo +2 xx +EXPLAIN SELECT t2.key_a,foo +FROM t1 INNER JOIN t2 ON t2.key_a = t1.key_a +INNER JOIN t3 ON t1.key_a = t3.key_a +WHERE t2.key_a=2 and key_b=5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index +1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 Using index +1 SIMPLE t3 const PRIMARY PRIMARY 8 const,const 1 +DROP TABLE t1,t2,t3; +create table t1 (f1 int); +insert into t1 values(1),(2); +create table t2 (f2 int, f3 int, key(f2)); +insert into t2 values(1,1),(2,2); +create table t3 (f4 int not null); +insert into t3 values (2),(2),(2); +select f1,(select count(*) from t2,t3 where f2=f1 and f3=f4) as count from t1; +f1 count +1 0 +2 3 +drop table t1,t2,t3; +create table t1 (f1 int unique); +create table t2 (f2 int unique); +create table t3 (f3 int unique); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +insert into t3 values(1),(NULL); +select * from t3 where f3 is null; +f3 +NULL +select t2.f2 from t1 left join t2 on f1=f2 join t3 on f1=f3 where f1=1; +f2 +1 +drop table t1,t2,t3; +create table t1(f1 char, f2 char not null); +insert into t1 values(null,'a'); +create table t2 (f2 char not null); +insert into t2 values('b'); +select * from t1 left join t2 on f1=t2.f2 where t1.f2='a'; +f1 f2 f2 +NULL a NULL +drop table t1,t2; +select * from (select * left join t on f1=f2) tt; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'on f1=f2) tt' at line 1 +CREATE TABLE t1 (sku int PRIMARY KEY, pr int); +CREATE TABLE t2 (sku int PRIMARY KEY, sppr int, name varchar(255)); +INSERT INTO t1 VALUES +(10, 10), (20, 10), (30, 20), (40, 30), (50, 10), (60, 10); +INSERT INTO t2 VALUES +(10, 10, 'aaa'), (20, 10, 'bbb'), (30, 10, 'ccc'), (40, 20, 'ddd'), +(50, 10, 'eee'), (60, 20, 'fff'), (70, 20, 'ggg'), (80, 30, 'hhh'); +SELECT t2.sku, t2.sppr, t2.name, t1.sku, t1.pr +FROM t2, t1 WHERE t2.sku=20 AND (t2.sku=t1.sku OR t2.sppr=t1.sku); +sku sppr name sku pr +20 10 bbb 10 10 +20 10 bbb 20 10 +EXPLAIN +SELECT t2.sku, t2.sppr, t2.name, t1.sku, t1.pr +FROM t2, t1 WHERE t2.sku=20 AND (t2.sku=t1.sku OR t2.sppr=t1.sku); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 2 Using where +DROP TABLE t1,t2; +CREATE TABLE t1 (i TINYINT UNSIGNED NOT NULL); +INSERT t1 SET i = 0; +UPDATE t1 SET i = -1; +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +SELECT * FROM t1; +i +0 +UPDATE t1 SET i = CAST(i - 1 AS SIGNED); +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +SELECT * FROM t1; +i +0 +UPDATE t1 SET i = i - 1; +Warnings: +Warning 1264 Out of range value for column 'i' at row 1 +SELECT * FROM t1; +i +255 +DROP TABLE t1; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, c int, e int, primary key(a,b,c)); +insert into t2 select A.a, B.a, C.a, C.a from t1 A, t1 B, t1 C; +analyze table t2; +Table Op Msg_type Msg_text +test.t2 analyze status OK +select 'In next EXPLAIN, B.rows must be exactly 10:' Z; +Z +In next EXPLAIN, B.rows must be exactly 10: +explain select * from t2 A, t2 B where A.a=5 and A.b=5 and A.C<5 +and B.a=5 and B.b=A.e and (B.b =1 or B.b = 3 or B.b=5); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A range PRIMARY PRIMARY 12 NULL 1 Using where +1 SIMPLE B ref PRIMARY PRIMARY 8 const,test.A.e 11 +drop table t1, t2; +CREATE TABLE t1 (a int PRIMARY KEY, b int, INDEX(b)); +INSERT INTO t1 VALUES (1, 3), (9,4), (7,5), (4,5), (6,2), +(3,1), (5,1), (8,9), (2,2), (0,9); +CREATE TABLE t2 (c int, d int, f int, INDEX(c,f)); +INSERT INTO t2 VALUES +(1,0,0), (1,0,1), (2,0,0), (2,0,1), (3,0,0), (4,0,1), +(5,0,0), (5,0,1), (6,0,0), (0,0,1), (7,0,0), (7,0,1), +(0,0,0), (0,0,1), (8,0,0), (8,0,1), (9,0,0), (9,0,1); +EXPLAIN +SELECT a, c, d, f FROM t1,t2 WHERE a=c AND b BETWEEN 4 AND 6; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY,b b 5 NULL 1 Using where +1 SIMPLE t2 ref c c 5 test.t1.a 2 Using where +EXPLAIN +SELECT a, c, d, f FROM t1,t2 WHERE a=c AND b BETWEEN 4 AND 6 AND a > 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY,b PRIMARY 4 NULL 1 Using where +1 SIMPLE t2 ref c c 5 test.t1.a 2 Using where +DROP TABLE t1, t2; +create table t1 ( +a int unsigned not null auto_increment primary key, +b bit not null, +c bit not null +); +create table t2 ( +a int unsigned not null auto_increment primary key, +b bit not null, +c int unsigned not null, +d varchar(50) +); +insert into t1 (b,c) values (0,1), (0,1); +insert into t2 (b,c) values (0,1); +select t1.a, t1.b + 0, t1.c + 0, t2.a, t2.b + 0, t2.c, t2.d +from t1 left outer join t2 on t1.a = t2.c and t2.b <> 1 +where t1.b <> 1 order by t1.a; +a t1.b + 0 t1.c + 0 a t2.b + 0 c d +1 0 1 1 0 1 NULL +2 0 1 NULL NULL NULL NULL +drop table t1,t2; +SELECT 0.9888889889 * 1.011111411911; +0.9888889889 * 1.011111411911 +0.9998769417899202067879 +prepare stmt from 'select 1 as " a "'; +Warnings: +Warning 1466 Leading spaces are removed from name ' a ' +execute stmt; +a +1 +CREATE TABLE t1 (a int NOT NULL PRIMARY KEY, b int NOT NULL); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +CREATE TABLE t2 (c int NOT NULL, INDEX idx(c)); +INSERT INTO t2 VALUES +(1), (1), (1), (1), (1), (1), (1), (1), +(2), (2), (2), (2), +(3), (3), +(4); +EXPLAIN SELECT b FROM t1, t2 WHERE b=c AND a=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 ref idx idx 4 const 1 Using index +EXPLAIN SELECT b FROM t1, t2 WHERE b=c AND a=4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 ref idx idx 4 const 1 Using index +DROP TABLE t1, t2; +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a int); +INSERT INTO t1 VALUES (1,2), (2,NULL), (3,2); +CREATE TABLE t2 (b int, c INT, INDEX idx1(b)); +INSERT INTO t2 VALUES (2,1), (3,2); +CREATE TABLE t3 (d int, e int, INDEX idx1(d)); +INSERT INTO t3 VALUES (2,10), (2,20), (1,30), (2,40), (2,50); +EXPLAIN +SELECT * FROM t1 LEFT JOIN t2 ON t2.b=t1.a INNER JOIN t3 ON t3.d=t1.id +WHERE t1.id=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 const idx1 NULL NULL NULL 1 +1 SIMPLE t3 ref idx1 idx1 5 const 1 Using where +SELECT * FROM t1 LEFT JOIN t2 ON t2.b=t1.a INNER JOIN t3 ON t3.d=t1.id +WHERE t1.id=2; +id a b c d e +2 NULL NULL NULL 2 10 +2 NULL NULL NULL 2 20 +2 NULL NULL NULL 2 40 +2 NULL NULL NULL 2 50 +DROP TABLE t1,t2,t3; +create table t1 (c1 varchar(1), c2 int, c3 int, c4 int, c5 int, c6 int, +c7 int, c8 int, c9 int, fulltext key (`c1`)) engine=myisam; +select distinct match (`c1`) against ('z') , c2, c3, c4,c5, c6,c7, c8 +from t1 where c9=1 order by c2, c2; +match (`c1`) against ('z') c2 c3 c4 c5 c6 c7 c8 +drop table t1; +CREATE TABLE t1 (pk varchar(10) PRIMARY KEY, fk varchar(16)); +CREATE TABLE t2 (pk varchar(16) PRIMARY KEY, fk varchar(10)); +INSERT INTO t1 VALUES +('d','dddd'), ('i','iii'), ('a','aa'), ('b','bb'), ('g','gg'), +('e','eee'), ('c','cccc'), ('h','hhh'), ('j','jjj'), ('f','fff'); +INSERT INTO t2 VALUES +('jjj', 'j'), ('cc','c'), ('ccc','c'), ('aaa', 'a'), ('jjjj','j'), +('hhh','h'), ('gg','g'), ('fff','f'), ('ee','e'), ('ffff','f'), +('bbb','b'), ('ff','f'), ('cccc','c'), ('dddd','d'), ('jj','j'), +('aaaa','a'), ('bb','b'), ('eeee','e'), ('aa','a'), ('hh','h'); +EXPLAIN SELECT t2.* +FROM t1 JOIN t2 ON t2.fk=t1.pk +WHERE t2.fk < 'c' AND t2.pk=t1.fk; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 1 Using where +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where +EXPLAIN SELECT t2.* +FROM t1 JOIN t2 ON t2.fk=t1.pk +WHERE t2.fk BETWEEN 'a' AND 'b' AND t2.pk=t1.fk; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 1 Using where +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where +EXPLAIN SELECT t2.* +FROM t1 JOIN t2 ON t2.fk=t1.pk +WHERE t2.fk IN ('a','b') AND t2.pk=t1.fk; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 12 NULL 2 Using where +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 18 test.t1.fk 1 Using where +DROP TABLE t1,t2; +CREATE TABLE t1 (a int, b varchar(20) NOT NULL, PRIMARY KEY(a)); +CREATE TABLE t2 (a int, b varchar(20) NOT NULL, +PRIMARY KEY (a), UNIQUE KEY (b)); +INSERT INTO t1 VALUES (1,'a'),(2,'b'),(3,'c'); +INSERT INTO t2 VALUES (1,'a'),(2,'b'),(3,'c'); +EXPLAIN SELECT t1.a FROM t1 LEFT JOIN t2 ON t2.b=t1.b WHERE t1.a=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 const b b 22 const 1 Using index +DROP TABLE t1,t2; +CREATE TABLE t1(id int PRIMARY KEY, b int, e int); +CREATE TABLE t2(i int, a int, INDEX si(i), INDEX ai(a)); +CREATE TABLE t3(a int PRIMARY KEY, c char(4), INDEX ci(c)); +INSERT INTO t1 VALUES +(1,10,19), (2,20,22), (4,41,42), (9,93,95), (7, 77,79), +(6,63,67), (5,55,58), (3,38,39), (8,81,89); +INSERT INTO t2 VALUES +(21,210), (41,410), (82,820), (83,830), (84,840), +(65,650), (51,510), (37,370), (94,940), (76,760), +(22,220), (33,330), (40,400), (95,950), (38,380), +(67,670), (88,880), (57,570), (96,960), (97,970); +INSERT INTO t3 VALUES +(210,'bb'), (950,'ii'), (400,'ab'), (500,'ee'), (220,'gg'), +(440,'gg'), (310,'eg'), (380,'ee'), (840,'bb'), (830,'ff'), +(230,'aa'), (960,'ii'), (410,'aa'), (510,'ee'), (290,'bb'), +(450,'gg'), (320,'dd'), (390,'hh'), (850,'jj'), (860,'ff'); +EXPLAIN +SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3 +WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND +t3.a=t2.a AND t3.c IN ('bb','ee'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 range si si 5 NULL 1 Using where +1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where +EXPLAIN +SELECT t3.a FROM t1,t2,t3 +WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND +t3.a=t2.a AND t3.c IN ('bb','ee') ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 range si,ai si 5 NULL 1 Using where +1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where +EXPLAIN +SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3 +WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND +t3.c IN ('bb','ee'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 range si si 5 NULL 2 Using where +1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where +EXPLAIN +SELECT t3.a FROM t1,t2,t3 +WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND +t3.c IN ('bb','ee'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 range si,ai si 5 NULL 2 Using where +1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where +DROP TABLE t1,t2,t3; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(a int); +INSERT into t1 values (1), (2), (3); +SELECT * FROM t1 LIMIT 2, -1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1' at line 1 +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/select_found.result b/mysql-test/suite/pbxt/r/select_found.result new file mode 100644 index 00000000000..7896f8a9f4e --- /dev/null +++ b/mysql-test/suite/pbxt/r/select_found.result @@ -0,0 +1,282 @@ +drop table if exists t1,t2; +create table t1 (a int not null auto_increment, b int not null, primary key(a)); +insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9); +select SQL_CALC_FOUND_ROWS * from t1; +a b +1 2 +2 3 +3 5 +4 5 +5 5 +6 6 +7 7 +8 9 +select found_rows(); +found_rows() +8 +select SQL_CALC_FOUND_ROWS * from t1 limit 1; +a b +1 2 +select found_rows(); +found_rows() +8 +select SQL_BUFFER_RESULT SQL_CALC_FOUND_ROWS * from t1 limit 1; +a b +1 2 +select found_rows(); +found_rows() +8 +select SQL_CALC_FOUND_ROWS * from t1 order by b desc limit 1; +a b +8 9 +select found_rows(); +found_rows() +8 +select SQL_CALC_FOUND_ROWS distinct b from t1 limit 1; +b +2 +select found_rows(); +found_rows() +6 +select SQL_CALC_FOUND_ROWS b,count(*) as c from t1 group by b order by c desc limit 1; +b c +5 3 +select found_rows(); +found_rows() +6 +select SQL_CALC_FOUND_ROWS * from t1 left join t1 as t2 on (t1.b=t2.a) limit 2,1; +a b a b +3 5 5 5 +select found_rows(); +found_rows() +8 +drop table t1; +create table t1 (a int not null primary key); +insert into t1 values (1),(2),(3),(4),(5); +select sql_calc_found_rows a from t1 where a in (1,2,3) order by a desc limit 0,2; +a +3 +2 +select FOUND_ROWS(); +FOUND_ROWS() +3 +select sql_calc_found_rows a from t1 where a in (1,2,3) order by a+2 desc limit 0,2; +a +3 +2 +select FOUND_ROWS(); +FOUND_ROWS() +3 +drop table t1; +CREATE TABLE t1 ( +`id` smallint(5) unsigned NOT NULL auto_increment, +`kid` smallint(5) unsigned NOT NULL default '0', +PRIMARY KEY (`id`), +KEY `kid` (`kid`) +); +CREATE TABLE t2 ( +id smallint(5) unsigned NOT NULL auto_increment, +name varchar(50) NOT NULL default '', +email varchar(50) NOT NULL default '', +PRIMARY KEY (id), +UNIQUE KEY e_n (email,name) +); +EXPLAIN SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system PRIMARY,kid NULL NULL NULL 0 const row not found +1 SIMPLE t2 index NULL e_n 104 NULL 10 +SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; +email +email1 +email10 +email100 +email101 +email102 +email103 +email104 +email105 +email106 +email107 +SELECT FOUND_ROWS(); +FOUND_ROWS() +200 +SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL order by email LIMIT 10; +email +email1 +email10 +email100 +email101 +email102 +email103 +email104 +email105 +email106 +email107 +SELECT FOUND_ROWS(); +FOUND_ROWS() +200 +SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; +email +email1 +email2 +email3 +email4 +email5 +email6 +email7 +email8 +email9 +email10 +SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL ORDER BY email LIMIT 10; +email +email1 +email10 +email100 +email101 +email102 +email103 +email104 +email105 +email106 +email107 +INSERT INTO `t1` (`id`, `kid`) VALUES ('0', '150'); +SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; +email +email1 +email2 +email3 +email4 +email5 +email6 +email7 +email8 +email9 +email10 +SELECT FOUND_ROWS(); +FOUND_ROWS() +199 +drop table t1,t2; +CREATE TABLE `t1` ( +`titre` char(80) NOT NULL default '', +`numeropost` mediumint(8) unsigned NOT NULL auto_increment, +`maxnumrep` int(10) unsigned NOT NULL default '0', +PRIMARY KEY (`numeropost`), +KEY `maxnumrep` (`maxnumrep`) +) ENGINE=MyISAM ROW_FORMAT=FIXED; +INSERT INTO t1 (titre,maxnumrep) VALUES +('test1','1'),('test2','2'),('test3','3'); +SELECT SQL_CALC_FOUND_ROWS titre,numeropost,maxnumrep FROM t1 WHERE numeropost IN (1,2) ORDER BY maxnumrep DESC LIMIT 0, 1; +titre numeropost maxnumrep +test2 2 2 +SELECT FOUND_ROWS(); +FOUND_ROWS() +2 +SELECT SQL_CALC_FOUND_ROWS 1 FROM (SELECT 1) as a LIMIT 0; +1 +SELECT FOUND_ROWS(); +FOUND_ROWS() +1 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE numeropost > 1 LIMIT 0; +titre numeropost maxnumrep +SELECT FOUND_ROWS(); +FOUND_ROWS() +2 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 0; +titre numeropost maxnumrep +SELECT FOUND_ROWS(); +FOUND_ROWS() +3 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 ORDER BY numeropost LIMIT 0; +titre numeropost maxnumrep +SELECT FOUND_ROWS(); +FOUND_ROWS() +3 +drop table t1; +create table t1 (id int, primary key (id)); +insert into t1 values (1), (2), (3), (4), (5); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 limit 0, 1; +id +4 +select FOUND_ROWS(); +FOUND_ROWS() +2 +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 AND 1=2 limit 0, 1; +id +select FOUND_ROWS(); +FOUND_ROWS() +0 +select SQL_CALC_FOUND_ROWS * from t1 where id > 6 limit 0, 1; +id +select FOUND_ROWS(); +FOUND_ROWS() +0 +drop table t1; +CREATE TABLE t1 ( a int not null, b int not null, KEY ab(a,b) ); +INSERT INTO t1 VALUES ( 47, 1 ); +INSERT INTO t1 VALUES ( 70, 1 ); +SELECT * FROM t1 +WHERE +( +( b =1 AND a BETWEEN 14 AND 21 ) OR +( b =2 AND a BETWEEN 16 AND 18 ) OR +( b =3 AND a BETWEEN 15 AND 19 ) +); +a b +DROP TABLE t1; +CREATE TABLE t1 ( a integer, u varchar(15), r integer, key uao_idx( r, a, u)); +DELETE FROM t1 +WHERE ( r = 1 AND a IN ( 1, 2 ) AND ( u = 'w' OR u LIKE 'w/%' ) ) +OR ( r = 1 AND a IN ( 3 ) AND ( u = 'w/U' OR u LIKE 'w/U/%' ) ) +OR ( r = 1 AND a IN ( 1, 2, 3 ) AND ( u = 'w' ) ); +drop table t1; +CREATE TABLE t1 (a VARCHAR(16), UNIQUE(a)); +INSERT INTO t1 VALUES ('1'), ('2'), ('3'); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a = '2' LIMIT 0, 1; +a +2 +SELECT FOUND_ROWS(); +FOUND_ROWS() +1 +DROP TABLE t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (0), (0), (1), (2); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a = 0 GROUP BY a HAVING a > 10; +a +SELECT FOUND_ROWS(); +FOUND_ROWS() +0 +DROP TABLE t1; +SELECT 'foo'; +foo +foo +SELECT FOUND_ROWS(); +FOUND_ROWS() +1 +SELECT SQL_CALC_FOUND_ROWS 'foo'; +foo +foo +SELECT FOUND_ROWS(); +FOUND_ROWS() +1 +SELECT SQL_CALC_FOUND_ROWS 'foo' limit 0; +foo +SELECT FOUND_ROWS(); +FOUND_ROWS() +1 +SELECT FOUND_ROWS(); +FOUND_ROWS() +1 +SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0; +foo +SELECT FOUND_ROWS(); +FOUND_ROWS() +2 +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,2), (1,3), (1,4), (1,5); +SELECT SQL_CALC_FOUND_ROWS DISTINCT 'a' FROM t1 GROUP BY b LIMIT 2; +a +a +SELECT FOUND_ROWS(); +FOUND_ROWS() +1 +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/select_safe.result b/mysql-test/suite/pbxt/r/select_safe.result new file mode 100644 index 00000000000..468eb6cc5a9 --- /dev/null +++ b/mysql-test/suite/pbxt/r/select_safe.result @@ -0,0 +1,96 @@ +drop table if exists t1; +SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=4, SQL_MAX_JOIN_SIZE=9; +create table t1 (a int auto_increment primary key, b char(20)); +insert into t1 values(1,"test"); +SELECT SQL_BUFFER_RESULT * from t1; +a b +1 test +update t1 set b="a" where a=1; +delete from t1 where a=1; +insert into t1 values(1,"test"),(2,"test2"); +SELECT SQL_BUFFER_RESULT * from t1 order by a; +a b +1 test +2 test2 +update t1 set b="a" where a=1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select 1 from t1,t1 as t2,t1 as t3; +1 +1 +1 +1 +1 +update t1 set b="a"; +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +update t1 set b="a" where b="test"; +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +delete from t1; +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +delete from t1 where b="test"; +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +delete from t1 where a+0=1; +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +update t1 set b="a" order by a limit 1; +update t1 set b="a" where b="b" order by a limit 2; +delete from t1 where b="test" order by a limit 1; +delete from t1 where a+0=1 order by a limit 2; +alter table t1 add key b (b); +SET MAX_JOIN_SIZE=2; +SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; +@@MAX_JOIN_SIZE @@SQL_BIG_SELECTS +2 0 +insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); +SELECT * from t1 order by a; +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +SET SQL_BIG_SELECTS=1; +SELECT * from t1 order by a; +a b +2 test2 +3 a +4 a +5 a +SET MAX_JOIN_SIZE=2; +SELECT * from t1; +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +SET MAX_JOIN_SIZE=DEFAULT; +SELECT * from t1; +a b +2 test2 +3 a +4 a +5 a +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); +explain select STRAIGHT_JOIN * from t1,t1 as t2 where t1.b=t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL b NULL NULL NULL 21 +1 SIMPLE t2 ref b b 21 test.t1.b 2 Using where +set MAX_SEEKS_FOR_KEY=1; +explain select STRAIGHT_JOIN * from t1,t1 as t2 where t1.b=t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL b NULL NULL NULL 21 +1 SIMPLE t2 ref b b 21 test.t1.b 2 Using where +SET MAX_SEEKS_FOR_KEY=DEFAULT; +drop table t1; +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5); +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; +set local max_join_size=8; +select * from (select * from t1) x; +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +set local max_join_size=1; +select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x; +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +set local max_join_size=1; +select * from (select 1 union select 2 union select 3) x; +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +drop table t1; +SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; diff --git a/mysql-test/suite/pbxt/r/skip_grants.result b/mysql-test/suite/pbxt/r/skip_grants.result new file mode 100644 index 00000000000..15c5b38f00f --- /dev/null +++ b/mysql-test/suite/pbxt/r/skip_grants.result @@ -0,0 +1,78 @@ +use test; +DROP VIEW IF EXISTS v1; +DROP VIEW IF EXISTS v2; +DROP VIEW IF EXISTS v3; +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +CREATE TABLE t1(c INT); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 +FOR EACH ROW +SET @a = 1; +CREATE VIEW v1 AS SELECT * FROM t1; +CREATE PROCEDURE p1() +SELECT 1; +CREATE FUNCTION f1() RETURNS INT +RETURN 1; +CREATE DEFINER=a@b TRIGGER ti_ai AFTER INSERT ON t1 +FOR EACH ROW +SET @b = 1; +Warnings: +Note 1449 The user specified as a definer ('a'@'b') does not exist +CREATE DEFINER=a@b VIEW v2 AS SELECT * FROM t1; +Warnings: +Note 1449 The user specified as a definer ('a'@'b') does not exist +CREATE DEFINER=a@b PROCEDURE p2() +SELECT 2; +Warnings: +Note 1449 The user specified as a definer ('a'@'b') does not exist +CREATE DEFINER=a@b FUNCTION f2() RETURNS INT +RETURN 2; +Warnings: +Note 1449 The user specified as a definer ('a'@'b') does not exist +CREATE DEFINER=a@'' TRIGGER ti_bu BEFORE UPDATE ON t1 +FOR EACH ROW +SET @c = 1; +Warnings: +Note 1449 The user specified as a definer ('a'@'') does not exist +CREATE DEFINER=a@'' VIEW v3 AS SELECT * FROM t1; +Warnings: +Note 1449 The user specified as a definer ('a'@'') does not exist +CREATE DEFINER=a@'' PROCEDURE p3() +SELECT 3; +Warnings: +Note 1449 The user specified as a definer ('a'@'') does not exist +CREATE DEFINER=a@'' FUNCTION f3() RETURNS INT +RETURN 3; +Warnings: +Note 1449 The user specified as a definer ('a'@'') does not exist +SHOW CREATE VIEW v3; +View Create View character_set_client collation_connection +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`a`@`` SQL SECURITY DEFINER VIEW `v3` AS select `test`.`t1`.`c` AS `c` from `t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE PROCEDURE p3; +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +p3 CREATE DEFINER=`a`@`` PROCEDURE `p3`() +SELECT 3 latin1 latin1_swedish_ci latin1_swedish_ci +SHOW CREATE FUNCTION f3; +Function sql_mode Create Function character_set_client collation_connection Database Collation +f3 CREATE DEFINER=`a`@`` FUNCTION `f3`() RETURNS int(11) +RETURN 3 latin1 latin1_swedish_ci latin1_swedish_ci +DROP TRIGGER t1_bi; +DROP TRIGGER ti_ai; +DROP TRIGGER ti_bu; +DROP VIEW v1; +DROP VIEW v2; +DROP VIEW v3; +DROP TABLE t1; +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP PROCEDURE p3; +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP FUNCTION f3; diff --git a/mysql-test/suite/pbxt/r/skip_name_resolve.result b/mysql-test/suite/pbxt/r/skip_name_resolve.result new file mode 100644 index 00000000000..8ef52e75238 --- /dev/null +++ b/mysql-test/suite/pbxt/r/skip_name_resolve.result @@ -0,0 +1,14 @@ +GRANT ALL ON test.* TO mysqltest_1@'127.0.0.1/255.255.255.255'; +SHOW GRANTS FOR mysqltest_1@'127.0.0.1/255.255.255.255'; +Grants for mysqltest_1@127.0.0.1/255.255.255.255 +GRANT USAGE ON *.* TO 'mysqltest_1'@'127.0.0.1/255.255.255.255' +GRANT ALL PRIVILEGES ON `test`.* TO 'mysqltest_1'@'127.0.0.1/255.255.255.255' +REVOKE ALL ON test.* FROM mysqltest_1@'127.0.0.1/255.255.255.255'; +DROP USER mysqltest_1@'127.0.0.1/255.255.255.255'; +select user(); +user() +# +show processlist; +Id User Host db Command Time State Info +<id> root <host> test <command> <time> <state> <info> +<id> root <host> test <command> <time> <state> <info> diff --git a/mysql-test/suite/pbxt/r/sql_mode.result b/mysql-test/suite/pbxt/r/sql_mode.result new file mode 100644 index 00000000000..0ee438dc15f --- /dev/null +++ b/mysql-test/suite/pbxt/r/sql_mode.result @@ -0,0 +1,482 @@ +drop table if exists t1,t2,v1,v2; +drop view if exists t1,t2,v1,v2; +CREATE TABLE `t1` ( +a int not null auto_increment, +`pseudo` varchar(35) character set latin2 NOT NULL default '', +`email` varchar(60) character set latin2 NOT NULL default '', +PRIMARY KEY (a), +UNIQUE KEY `email` USING BTREE (`email`) +) ENGINE=HEAP CHARSET=latin1 ROW_FORMAT DYNAMIC; +set @@sql_mode=""; +show variables like 'sql_mode'; +Variable_name Value +sql_mode +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL AUTO_INCREMENT, + `pseudo` varchar(35) CHARACTER SET latin2 NOT NULL DEFAULT '', + `email` varchar(60) CHARACTER SET latin2 NOT NULL DEFAULT '', + PRIMARY KEY (`a`), + UNIQUE KEY `email` (`email`) USING BTREE +) ENGINE=MEMORY DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC +set @@sql_mode="ansi_quotes"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode ANSI_QUOTES +show create table t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "a" int(11) NOT NULL AUTO_INCREMENT, + "pseudo" varchar(35) CHARACTER SET latin2 NOT NULL DEFAULT '', + "email" varchar(60) CHARACTER SET latin2 NOT NULL DEFAULT '', + PRIMARY KEY ("a"), + UNIQUE KEY "email" ("email") USING BTREE +) ENGINE=MEMORY DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC +set @@sql_mode="no_table_options"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode NO_TABLE_OPTIONS +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL AUTO_INCREMENT, + `pseudo` varchar(35) CHARACTER SET latin2 NOT NULL DEFAULT '', + `email` varchar(60) CHARACTER SET latin2 NOT NULL DEFAULT '', + PRIMARY KEY (`a`), + UNIQUE KEY `email` (`email`) USING BTREE +) +set @@sql_mode="no_key_options"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode NO_KEY_OPTIONS +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL AUTO_INCREMENT, + `pseudo` varchar(35) CHARACTER SET latin2 NOT NULL DEFAULT '', + `email` varchar(60) CHARACTER SET latin2 NOT NULL DEFAULT '', + PRIMARY KEY (`a`), + UNIQUE KEY `email` (`email`) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC +set @@sql_mode="no_field_options,mysql323,mysql40"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode NO_FIELD_OPTIONS,MYSQL323,MYSQL40,HIGH_NOT_PRECEDENCE +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `pseudo` varchar(35) NOT NULL DEFAULT '', + `email` varchar(60) NOT NULL DEFAULT '', + PRIMARY KEY (`a`), + UNIQUE KEY `email` (`email`) +) TYPE=HEAP ROW_FORMAT=DYNAMIC +set sql_mode="postgresql,oracle,mssql,db2,maxdb"; +select @@sql_mode; +@@sql_mode +PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,POSTGRESQL,ORACLE,MSSQL,DB2,MAXDB,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER +show create table t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "a" int(11) NOT NULL, + "pseudo" varchar(35) CHARACTER SET latin2 NOT NULL DEFAULT '', + "email" varchar(60) CHARACTER SET latin2 NOT NULL DEFAULT '', + PRIMARY KEY ("a"), + UNIQUE KEY "email" ("email") +) +drop table t1; +CREATE TABLE t1 ( +a char(10), +b char(10) collate latin1_bin, +c binary(10) +) character set latin1; +set @@sql_mode=""; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) DEFAULT NULL, + `b` char(10) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL, + `c` binary(10) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +set @@sql_mode="mysql323"; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) DEFAULT NULL, + `b` char(10) binary DEFAULT NULL, + `c` binary(10) DEFAULT NULL +) TYPE=PBXT +set @@sql_mode="mysql40"; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) DEFAULT NULL, + `b` char(10) binary DEFAULT NULL, + `c` binary(10) DEFAULT NULL +) TYPE=PBXT +drop table t1; +set session sql_mode = ''; +create table t1 ( min_num dec(6,6) default .000001); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `min_num` decimal(6,6) DEFAULT '0.000001' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1 ; +set session sql_mode = 'IGNORE_SPACE'; +create table t1 ( min_num dec(6,6) default 0.000001); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `min_num` decimal(6,6) DEFAULT '0.000001' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1 ; +create table t1 ( min_num dec(6,6) default .000001); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `min_num` decimal(6,6) DEFAULT '0.000001' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1 ; +set @@SQL_MODE=NULL; +ERROR 42000: Variable 'sql_mode' can't be set to the value of 'NULL' +set session sql_mode=ansi; +create table t1 +(f1 integer auto_increment primary key, +f2 timestamp default current_timestamp on update current_timestamp); +show create table t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "f1" int(11) NOT NULL AUTO_INCREMENT, + "f2" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY ("f1") +) +set session sql_mode=no_field_options; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + `f2` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`f1`) +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=''; +show local variables like 'SQL_MODE'; +Variable_name Value +sql_mode +CREATE TABLE t1 (p int not null auto_increment, a varchar(20), primary key(p)); +INSERT t1 (a) VALUES +('\\'), +('\n'), +('\b'), +('\r'), +('\t'), +('\x'), +('\a'), +('\aa'), +('\\a'), +('\\aa'), +('_'), +('\_'), +('\\_'), +('\\\_'), +('\\\\_'), +('%'), +('\%'), +('\\%'), +('\\\%'), +('\\\\%') +; +SELECT p, hex(a) FROM t1; +p hex(a) +1 5C +2 0A +3 08 +4 0D +5 09 +6 78 +7 61 +8 6161 +9 5C61 +10 5C6161 +11 5F +12 5C5F +13 5C5F +14 5C5C5F +15 5C5C5F +16 25 +17 5C25 +18 5C25 +19 5C5C25 +20 5C5C25 +delete from t1 where a in ('\n','\r','\t', '\b'); +select +masks.p, +masks.a as mask, +examples.a as example +from +t1 as masks +left join t1 as examples on examples.a LIKE masks.a +order by masks.p, example; +p mask example +1 \ \ +6 x x +7 a a +8 aa aa +9 \a a +10 \aa aa +11 _ % +11 _ a +11 _ x +11 _ \ +11 _ _ +12 \_ _ +13 \_ _ +14 \\_ \% +14 \\_ \% +14 \\_ \a +14 \\_ \_ +14 \\_ \_ +15 \\_ \% +15 \\_ \% +15 \\_ \a +15 \\_ \_ +15 \\_ \_ +16 % % +16 % a +16 % aa +16 % x +16 % \ +16 % \% +16 % \% +16 % \a +16 % \aa +16 % \\% +16 % \\% +16 % \\_ +16 % \\_ +16 % \_ +16 % \_ +16 % _ +17 \% % +18 \% % +19 \\% \ +19 \\% \% +19 \\% \% +19 \\% \a +19 \\% \aa +19 \\% \\% +19 \\% \\% +19 \\% \\_ +19 \\% \\_ +19 \\% \_ +19 \\% \_ +20 \\% \ +20 \\% \% +20 \\% \% +20 \\% \a +20 \\% \aa +20 \\% \\% +20 \\% \\% +20 \\% \\_ +20 \\% \\_ +20 \\% \_ +20 \\% \_ +DROP TABLE t1; +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +show local variables like 'SQL_MODE'; +Variable_name Value +sql_mode NO_BACKSLASH_ESCAPES +CREATE TABLE t1 (p int not null auto_increment, a varchar(20), primary key(p)); +INSERT t1 (a) VALUES +('\\'), +('\n'), +('\b'), +('\r'), +('\t'), +('\x'), +('\a'), +('\aa'), +('\\a'), +('\\aa'), +('_'), +('\_'), +('\\_'), +('\\\_'), +('\\\\_'), +('%'), +('\%'), +('\\%'), +('\\\%'), +('\\\\%') +; +SELECT p, hex(a) FROM t1; +p hex(a) +1 5C5C +2 5C6E +3 5C62 +4 5C72 +5 5C74 +6 5C78 +7 5C61 +8 5C6161 +9 5C5C61 +10 5C5C6161 +11 5F +12 5C5F +13 5C5C5F +14 5C5C5C5F +15 5C5C5C5C5F +16 25 +17 5C25 +18 5C5C25 +19 5C5C5C25 +20 5C5C5C5C25 +delete from t1 where a in ('\n','\r','\t', '\b'); +select +masks.p, +masks.a as mask, +examples.a as example +from +t1 as masks +left join t1 as examples on examples.a LIKE masks.a +order by masks.p, example; +p mask example +1 \\ \\ +6 \x \x +7 \a \a +8 \aa \aa +9 \\a \\a +10 \\aa \\aa +11 _ % +11 _ _ +12 \_ \% +12 \_ \a +12 \_ \x +12 \_ \\ +12 \_ \_ +13 \\_ \\% +13 \\_ \\a +13 \\_ \\_ +14 \\\_ \\\% +14 \\\_ \\\_ +15 \\\\_ \\\\% +15 \\\\_ \\\\_ +16 % % +16 % \% +16 % \a +16 % \aa +16 % \x +16 % \\ +16 % \\% +16 % \\a +16 % \\aa +16 % \\\% +16 % \\\\% +16 % \\\\_ +16 % \\\_ +16 % \\_ +16 % \_ +16 % _ +17 \% \% +17 \% \a +17 \% \aa +17 \% \x +17 \% \\ +17 \% \\% +17 \% \\a +17 \% \\aa +17 \% \\\% +17 \% \\\\% +17 \% \\\\_ +17 \% \\\_ +17 \% \\_ +17 \% \_ +18 \\% \\ +18 \\% \\% +18 \\% \\a +18 \\% \\aa +18 \\% \\\% +18 \\% \\\\% +18 \\% \\\\_ +18 \\% \\\_ +18 \\% \\_ +19 \\\% \\\% +19 \\\% \\\\% +19 \\\% \\\\_ +19 \\\% \\\_ +20 \\\\% \\\\% +20 \\\\% \\\\_ +DROP TABLE t1; +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; +a\\b a\\\"b a'\\b a'\\\"b +a\\b a\\\"b a'\\b a'\\\"b +SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; +a\\b a\\\'b a"\\b a"\\\'b +a\\b a\\\'b a"\\b a"\\\'b +SET @@SQL_MODE=''; +SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; +a\b a\"b a'\b a'\"b +a\b a\"b a'\b a'\"b +SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; +a\b a\'b a"\b a"\'b +a\b a\'b a"\b a"\'b +SET @@SQL_MODE=''; +create function `foo` () returns int return 5; +show create function `foo`; +Function sql_mode Create Function character_set_client collation_connection Database Collation +foo CREATE DEFINER=`root`@`localhost` FUNCTION `foo`() RETURNS int(11) +return 5 latin1 latin1_swedish_ci latin1_swedish_ci +SET @@SQL_MODE='ANSI_QUOTES'; +show create function `foo`; +Function sql_mode Create Function character_set_client collation_connection Database Collation +foo CREATE DEFINER=`root`@`localhost` FUNCTION `foo`() RETURNS int(11) +return 5 latin1 latin1_swedish_ci latin1_swedish_ci +drop function `foo`; +create function `foo` () returns int return 5; +show create function `foo`; +Function sql_mode Create Function character_set_client collation_connection Database Collation +foo ANSI_QUOTES CREATE DEFINER="root"@"localhost" FUNCTION "foo"() RETURNS int(11) +return 5 latin1 latin1_swedish_ci latin1_swedish_ci +SET @@SQL_MODE=''; +show create function `foo`; +Function sql_mode Create Function character_set_client collation_connection Database Collation +foo ANSI_QUOTES CREATE DEFINER="root"@"localhost" FUNCTION "foo"() RETURNS int(11) +return 5 latin1 latin1_swedish_ci latin1_swedish_ci +drop function `foo`; +SET @@SQL_MODE=''; +create table t1 (a int); +create table t2 (a int); +create view v1 as select a from t1; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci +SET @@SQL_MODE='ANSI_QUOTES'; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER="root"@"localhost" SQL SECURITY DEFINER VIEW "v1" AS select "t1"."a" AS "a" from "t1" latin1 latin1_swedish_ci +create view v2 as select a from t2 where a in (select a from v1); +drop view v2, v1; +drop table t1, t2; +select @@sql_mode; +@@sql_mode +ANSI_QUOTES +set sql_mode=2097152; +select @@sql_mode; +@@sql_mode +STRICT_TRANS_TABLES +set sql_mode=4194304; +select @@sql_mode; +@@sql_mode +STRICT_ALL_TABLES +set sql_mode=16384+(65536*4); +select @@sql_mode; +@@sql_mode +REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,NO_TABLE_OPTIONS,ANSI +set sql_mode=2147483648; +select @@sql_mode; +@@sql_mode +PAD_CHAR_TO_FULL_LENGTH +SET @@SQL_MODE=@OLD_SQL_MODE; diff --git a/mysql-test/suite/pbxt/r/status.result b/mysql-test/suite/pbxt/r/status.result new file mode 100644 index 00000000000..519a55301a3 --- /dev/null +++ b/mysql-test/suite/pbxt/r/status.result @@ -0,0 +1,121 @@ +flush status; +show status like 'Table_lock%'; +Variable_name Value +Table_locks_immediate 1 +Table_locks_waited 0 +select * from information_schema.session_status where variable_name like 'Table_lock%'; +VARIABLE_NAME VARIABLE_VALUE +TABLE_LOCKS_IMMEDIATE 2 +TABLE_LOCKS_WAITED 0 +SET SQL_LOG_BIN=0; +drop table if exists t1; +create table t1(n int) engine=myisam; +insert into t1 values(1); +select * from t1; +n +1 +lock tables t1 read; +unlock tables; +lock tables t1 read; +update t1 set n = 3; +unlock tables; +show status like 'Table_lock%'; +Variable_name Value +Table_locks_immediate 17 +Table_locks_waited 1 +select * from information_schema.session_status where variable_name like 'Table_lock%'; +VARIABLE_NAME VARIABLE_VALUE +TABLE_LOCKS_IMMEDIATE 18 +TABLE_LOCKS_WAITED 1 +drop table t1; +select 1; +1 +1 +show status like 'last_query_cost'; +Variable_name Value +Last_query_cost 0.000000 +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +select * from t1 where a=6; +a +6 +6 +6 +6 +6 +show status like 'last_query_cost'; +Variable_name Value +Last_query_cost 13.314789 +show status like 'last_query_cost'; +Variable_name Value +Last_query_cost 13.314789 +select 1; +1 +1 +show status like 'last_query_cost'; +Variable_name Value +Last_query_cost 0.000000 +drop table t1; +FLUSH STATUS; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 1 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; +VARIABLE_NAME VARIABLE_VALUE +MAX_USED_CONNECTIONS 1 +SET @save_thread_cache_size=@@thread_cache_size; +SET GLOBAL thread_cache_size=3; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 3 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; +VARIABLE_NAME VARIABLE_VALUE +MAX_USED_CONNECTIONS 3 +FLUSH STATUS; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 2 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; +VARIABLE_NAME VARIABLE_VALUE +MAX_USED_CONNECTIONS 2 +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 3 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; +VARIABLE_NAME VARIABLE_VALUE +MAX_USED_CONNECTIONS 3 +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 4 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; +VARIABLE_NAME VARIABLE_VALUE +MAX_USED_CONNECTIONS 4 +SET GLOBAL thread_cache_size=@save_thread_cache_size; +show status like 'com_show_status'; +Variable_name Value +Com_show_status 3 +show status like 'hand%write%'; +Variable_name Value +Handler_write 5 +show status like '%tmp%'; +Variable_name Value +Created_tmp_disk_tables 0 +Created_tmp_files 0 +Created_tmp_tables 0 +show status like 'hand%write%'; +Variable_name Value +Handler_write 7 +show status like '%tmp%'; +Variable_name Value +Created_tmp_disk_tables 0 +Created_tmp_files 0 +Created_tmp_tables 0 +show status like 'com_show_status'; +Variable_name Value +Com_show_status 8 +rnd_diff tmp_table_diff +20 8 diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result new file mode 100644 index 00000000000..395770111ff --- /dev/null +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -0,0 +1,4323 @@ +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12; +select (select 2); +(select 2) +2 +explain extended select (select 2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1249 Select 2 was reduced during optimization +Note 1003 select 2 AS `(select 2)` +SELECT (SELECT 1) UNION SELECT (SELECT 2); +(SELECT 1) +1 +2 +explain extended SELECT (SELECT 1) UNION SELECT (SELECT 2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +3 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT <union1,3> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1249 Select 2 was reduced during optimization +Note 1249 Select 4 was reduced during optimization +Note 1003 select 1 AS `(SELECT 1)` union select 2 AS `(SELECT 2)` +SELECT (SELECT (SELECT 0 UNION SELECT 0)); +(SELECT (SELECT 0 UNION SELECT 0)) +0 +explain extended SELECT (SELECT (SELECT 0 UNION SELECT 0)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT <union3,4> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1249 Select 2 was reduced during optimization +Note 1003 select (select 0 AS `0` union select 0 AS `0`) AS `(SELECT (SELECT 0 UNION SELECT 0))` +SELECT (SELECT 1 FROM (SELECT 1) as b HAVING a=1) as a; +ERROR 42S22: Reference 'a' not supported (forward reference in item list) +SELECT (SELECT 1 FROM (SELECT 1) as b HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) as c HAVING a=1) as b; +ERROR 42S22: Reference 'b' not supported (forward reference in item list) +SELECT (SELECT 1),MAX(1) FROM (SELECT 1) as a; +(SELECT 1) MAX(1) +1 1 +SELECT (SELECT a) as a; +ERROR 42S22: Reference 'a' not supported (forward reference in item list) +EXPLAIN EXTENDED SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY <derived2> system NULL NULL NULL NULL 1 100.00 +3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1276 Field or reference 'b.a' of SELECT #3 was resolved in SELECT #1 +Note 1276 Field or reference 'b.a' of SELECT #3 was resolved in SELECT #1 +Note 1003 select 1 AS `1` from (select 1 AS `a`) `b` having ((select '1' AS `a`) = 1) +SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; +1 +1 +SELECT (SELECT 1), a; +ERROR 42S22: Unknown column 'a' in 'field list' +SELECT 1 as a FROM (SELECT 1) as b HAVING (SELECT a)=1; +a +1 +SELECT 1 FROM (SELECT (SELECT a) b) c; +ERROR 42S22: Unknown column 'a' in 'field list' +SELECT * FROM (SELECT 1 as id) b WHERE id IN (SELECT * FROM (SELECT 1 as id) c ORDER BY id); +id +1 +SELECT * FROM (SELECT 1) a WHERE 1 IN (SELECT 1,1); +ERROR 21000: Operand should contain 1 column(s) +SELECT 1 IN (SELECT 1); +1 IN (SELECT 1) +1 +SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); +1 +1 +select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); +ERROR HY000: Incorrect usage of PROCEDURE and subquery +SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); +ERROR HY000: Incorrect parameters to procedure 'ANALYSE' +SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; +ERROR 42S22: Unknown column 'a' in 'field list' +SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; +ERROR 42S22: Unknown column 'a' in 'field list' +SELECT (SELECT 1,2,3) = ROW(1,2,3); +(SELECT 1,2,3) = ROW(1,2,3) +1 +SELECT (SELECT 1,2,3) = ROW(1,2,1); +(SELECT 1,2,3) = ROW(1,2,1) +0 +SELECT (SELECT 1,2,3) < ROW(1,2,1); +(SELECT 1,2,3) < ROW(1,2,1) +0 +SELECT (SELECT 1,2,3) > ROW(1,2,1); +(SELECT 1,2,3) > ROW(1,2,1) +1 +SELECT (SELECT 1,2,3) = ROW(1,2,NULL); +(SELECT 1,2,3) = ROW(1,2,NULL) +NULL +SELECT ROW(1,2,3) = (SELECT 1,2,3); +ROW(1,2,3) = (SELECT 1,2,3) +1 +SELECT ROW(1,2,3) = (SELECT 1,2,1); +ROW(1,2,3) = (SELECT 1,2,1) +0 +SELECT ROW(1,2,3) < (SELECT 1,2,1); +ROW(1,2,3) < (SELECT 1,2,1) +0 +SELECT ROW(1,2,3) > (SELECT 1,2,1); +ROW(1,2,3) > (SELECT 1,2,1) +1 +SELECT ROW(1,2,3) = (SELECT 1,2,NULL); +ROW(1,2,3) = (SELECT 1,2,NULL) +NULL +SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'a'); +(SELECT 1.5,2,'a') = ROW(1.5,2,'a') +1 +SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'b'); +(SELECT 1.5,2,'a') = ROW(1.5,2,'b') +0 +SELECT (SELECT 1.5,2,'a') = ROW('1.5b',2,'b'); +(SELECT 1.5,2,'a') = ROW('1.5b',2,'b') +0 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: '1.5b' +SELECT (SELECT 'b',2,'a') = ROW(1.5,2,'a'); +(SELECT 'b',2,'a') = ROW(1.5,2,'a') +0 +SELECT (SELECT 1.5,2,'a') = ROW(1.5,'2','a'); +(SELECT 1.5,2,'a') = ROW(1.5,'2','a') +1 +SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a'); +(SELECT 1.5,'c','a') = ROW(1.5,2,'a') +0 +SELECT (SELECT * FROM (SELECT 'test' a,'test' b) a); +ERROR 21000: Operand should contain 1 column(s) +SELECT 1 as a,(SELECT a+a) b,(SELECT b); +a b (SELECT b) +1 2 2 +create table t1 (a int); +create table t2 (a int, b int); +create table t3 (a int); +create table t4 (a int not null, b int not null); +insert into t1 values (2); +insert into t2 values (1,7),(2,7); +insert into t4 values (4,8),(3,8),(5,9); +select (select a from t1 where t1.a = a1) as a2, (select b from t2 where t2.b=a2) as a1; +ERROR 42S22: Reference 'a1' not supported (forward reference in item list) +select (select a from t1 where t1.a=t2.a), a from t2; +(select a from t1 where t1.a=t2.a) a +NULL 1 +2 2 +select (select a from t1 where t1.a=t2.b), a from t2; +(select a from t1 where t1.a=t2.b) a +NULL 1 +NULL 2 +select (select a from t1), a, (select 1 union select 2 limit 1) from t2; +(select a from t1) a (select 1 union select 2 limit 1) +2 1 1 +2 2 1 +select (select a from t3), a from t2; +(select a from t3) a +NULL 1 +NULL 2 +select * from t2 where t2.a=(select a from t1); +a b +2 7 +insert into t3 values (6),(7),(3); +select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1); +a b +1 7 +2 7 +(select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 order by a limit 2) limit 3; +a b +1 7 +2 7 +3 8 +(select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +a b +1 7 +2 7 +4 8 +3 8 +explain extended (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where +2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using filesort +3 UNION t4 ALL NULL NULL NULL NULL 3 100.00 Using where +4 SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 +NULL UNION RESULT <union1,3> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1003 (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` = (select `test`.`t3`.`a` AS `a` from `test`.`t3` order by 1 desc limit 1))) union (select `test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t4` where (`test`.`t4`.`b` = (select (max(`test`.`t2`.`a`) * 4) AS `max(t2.a)*4` from `test`.`t2`)) order by `a`) +select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2; +(select a from t3 where a<t2.a*4 order by 1 desc limit 1) a +3 1 +7 2 +select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from +(select * from t2 where a>1) as tt; +(select t3.a from t3 where a<8 order by 1 desc limit 1) a +7 2 +explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from +(select * from t2 where a>1) as tt; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY <derived3> system NULL NULL NULL NULL 1 100.00 +3 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00 Using where +2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using filesort +Warnings: +Note 1003 select (select `test`.`t3`.`a` AS `a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,'2' AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` +select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); +a +2 +select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a > t1.a) order by 1 desc limit 1); +a +2 +select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a < t1.a) order by 1 desc limit 1); +a +select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; +b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) +8 7.5000 +8 4.5000 +9 7.5000 +explain extended select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t4 ALL NULL NULL NULL NULL 3 100.00 +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 +3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1276 Field or reference 'test.t4.a' of SELECT #3 was resolved in SELECT #1 +Note 1003 select `test`.`t4`.`b` AS `b`,(select avg((`test`.`t2`.`a` + (select min(`test`.`t3`.`a`) AS `min(t3.a)` from `test`.`t3` where (`test`.`t3`.`a` >= `test`.`t4`.`a`)))) AS `avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a))` from `test`.`t2`) AS `(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)` from `test`.`t4` +select * from t3 where exists (select * from t2 where t2.b=t3.a); +a +7 +select * from t3 where not exists (select * from t2 where t2.b=t3.a); +a +6 +3 +select * from t3 where a in (select b from t2); +a +7 +select * from t3 where a not in (select b from t2); +a +6 +3 +select * from t3 where a = some (select b from t2); +a +7 +select * from t3 where a <> any (select b from t2); +a +6 +3 +select * from t3 where a = all (select b from t2); +a +7 +select * from t3 where a <> all (select b from t2); +a +6 +3 +insert into t2 values (100, 5); +select * from t3 where a < any (select b from t2); +a +6 +3 +select * from t3 where a < all (select b from t2); +a +3 +select * from t3 where a >= any (select b from t2); +a +6 +7 +explain extended select * from t3 where a >= any (select b from t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <nop>((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +select * from t3 where a >= all (select b from t2); +a +7 +delete from t2 where a=100; +select * from t3 where a in (select a,b from t2); +ERROR 21000: Operand should contain 1 column(s) +select * from t3 where a in (select * from t2); +ERROR 21000: Operand should contain 1 column(s) +insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9),(1,10); +select b,max(a) as ma from t4 group by b having b < (select max(t2.a) from t2 where t2.b=t4.b); +b ma +insert into t2 values (2,10); +select b,max(a) as ma from t4 group by b having ma < (select max(t2.a) from t2 where t2.b=t4.b); +b ma +10 1 +delete from t2 where a=2 and b=10; +select b,max(a) as ma from t4 group by b having b >= (select max(t2.a) from t2 where t2.b=t4.b); +b ma +7 12 +create table t5 (a int); +select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a) a +NULL 1 +2 2 +insert into t5 values (5); +select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a) a +NULL 1 +2 2 +insert into t5 values (2); +select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a) a +NULL 1 +2 2 +explain extended select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL # 100.00 +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL # 100.00 Using where +3 DEPENDENT UNION t5 ALL NULL NULL NULL NULL # 100.00 Using where +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL # NULL +Warnings: +Note 1276 Field or reference 'test.t2.a' of SELECT #2 was resolved in SELECT #1 +Note 1276 Field or reference 'test.t2.a' of SELECT #3 was resolved in SELECT #1 +Note 1003 select (select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = `test`.`t2`.`a`) union select `test`.`t5`.`a` AS `a` from `test`.`t5` where (`test`.`t5`.`a` = `test`.`t2`.`a`)) AS `(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a)`,`test`.`t2`.`a` AS `a` from `test`.`t2` +select (select a from t1 where t1.a=t2.a union all select a from t5 where t5.a=t2.a), a from t2; +ERROR 21000: Subquery returns more than 1 row +create table t6 (patient_uq int, clinic_uq int, index i1 (clinic_uq)); +create table t7( uq int primary key, name char(25)); +insert into t7 values(1,"Oblastnaia bolnitsa"),(2,"Bolnitsa Krasnogo Kresta"); +insert into t6 values (1,1),(1,2),(2,2),(1,3); +select * from t6 where exists (select * from t7 where uq = clinic_uq); +patient_uq clinic_uq +1 1 +1 2 +2 2 +explain extended select * from t6 where exists (select * from t7 where uq = clinic_uq); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t6 ALL NULL NULL NULL NULL 4 100.00 Using where +2 DEPENDENT SUBQUERY t7 eq_ref PRIMARY PRIMARY 4 test.t6.clinic_uq 1 100.00 Using index +Warnings: +Note 1276 Field or reference 'test.t6.clinic_uq' of SELECT #2 was resolved in SELECT #1 +Note 1003 select `test`.`t6`.`patient_uq` AS `patient_uq`,`test`.`t6`.`clinic_uq` AS `clinic_uq` from `test`.`t6` where exists(select 1 AS `Not_used` from `test`.`t7` where (`test`.`t7`.`uq` = `test`.`t6`.`clinic_uq`)) +select * from t1 where a= (select a from t2,t4 where t2.b=t4.b); +ERROR 23000: Column 'a' in field list is ambiguous +drop table t1,t2,t3; +CREATE TABLE t3 (a varchar(20),b char(1) NOT NULL default '0'); +INSERT INTO t3 VALUES ('W','a'),('A','c'),('J','b'); +CREATE TABLE t2 (a varchar(20),b int NOT NULL default '0'); +INSERT INTO t2 VALUES ('W','1'),('A','3'),('J','2'); +CREATE TABLE t1 (a varchar(20),b date NOT NULL default '0000-00-00'); +INSERT INTO t1 VALUES ('W','1732-02-22'),('A','1735-10-30'),('J','1743-04-13'); +SELECT * FROM t1 WHERE b = (SELECT MIN(b) FROM t1); +a b +W 1732-02-22 +SELECT * FROM t2 WHERE b = (SELECT MIN(b) FROM t2); +a b +W 1 +SELECT * FROM t3 WHERE b = (SELECT MIN(b) FROM t3); +a b +W a +CREATE TABLE `t8` ( +`pseudo` varchar(35) character set latin1 NOT NULL default '', +`email` varchar(60) character set latin1 NOT NULL default '', +PRIMARY KEY (`pseudo`), +UNIQUE KEY `email` (`email`) +) ENGINE=MyISAM CHARSET=latin1 ROW_FORMAT=DYNAMIC; +INSERT INTO t8 (pseudo,email) VALUES ('joce','test'); +INSERT INTO t8 (pseudo,email) VALUES ('joce1','test1'); +INSERT INTO t8 (pseudo,email) VALUES ('2joce1','2test1'); +EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t8 const PRIMARY PRIMARY 37 const 1 100.00 Using index +4 SUBQUERY t8 const PRIMARY PRIMARY 37 1 100.00 Using index +2 SUBQUERY t8 const PRIMARY PRIMARY 37 const 1 100.00 +3 SUBQUERY t8 const PRIMARY PRIMARY 37 1 100.00 Using index +Warnings: +Note 1003 select 'joce' AS `pseudo`,(select 'test' AS `email` from `test`.`t8` where 1) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))` from `test`.`t8` where 1 +SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM +t8 WHERE pseudo='joce'); +ERROR 21000: Operand should contain 1 column(s) +SELECT pseudo FROM t8 WHERE pseudo=(SELECT * FROM t8 WHERE +pseudo='joce'); +ERROR 21000: Operand should contain 1 column(s) +SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); +pseudo +joce +SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo LIKE '%joce%'); +ERROR 21000: Subquery returns more than 1 row +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8; +CREATE TABLE `t1` ( +`topic` mediumint(8) unsigned NOT NULL default '0', +`date` date NOT NULL default '0000-00-00', +`pseudo` varchar(35) character set latin1 NOT NULL default '', +PRIMARY KEY (`pseudo`,`date`,`topic`), +KEY `topic` (`topic`) +) ENGINE=MyISAM ROW_FORMAT=DYNAMIC; +INSERT INTO t1 (topic,date,pseudo) VALUES +('43506','2002-10-02','joce'),('40143','2002-08-03','joce'); +EXPLAIN EXTENDED SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 index NULL PRIMARY 43 NULL 2 100.00 Using where; Using index +Warnings: +Note 1003 select distinct `test`.`t1`.`date` AS `date` from `test`.`t1` where (`test`.`t1`.`date` = '2002-08-03') +EXPLAIN EXTENDED SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +2 SUBQUERY t1 index NULL PRIMARY 43 NULL 2 100.00 Using where; Using index +Warnings: +Note 1003 select (select distinct `test`.`t1`.`date` AS `date` from `test`.`t1` where (`test`.`t1`.`date` = '2002-08-03')) AS `(SELECT DISTINCT date FROM t1 WHERE date='2002-08-03')` +SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; +date +2002-08-03 +SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); +(SELECT DISTINCT date FROM t1 WHERE date='2002-08-03') +2002-08-03 +SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1) UNION ALL SELECT 1; +1 +1 +1 +1 +SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1) UNION SELECT 1; +ERROR 21000: Subquery returns more than 1 row +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index NULL topic 3 NULL 2 100.00 Using index +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +3 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1003 select 1 AS `1` from `test`.`t1` where 1 +drop table t1; +CREATE TABLE `t1` ( +`numeropost` mediumint(8) unsigned NOT NULL auto_increment, +`maxnumrep` int(10) unsigned NOT NULL default '0', +PRIMARY KEY (`numeropost`), +UNIQUE KEY `maxnumrep` (`maxnumrep`) +) ENGINE=MyISAM ROW_FORMAT=FIXED; +INSERT INTO t1 (numeropost,maxnumrep) VALUES (40143,1),(43506,2); +CREATE TABLE `t2` ( +`mot` varchar(30) NOT NULL default '', +`topic` mediumint(8) unsigned NOT NULL default '0', +`date` date NOT NULL default '0000-00-00', +`pseudo` varchar(35) NOT NULL default '', +PRIMARY KEY (`mot`,`pseudo`,`date`,`topic`) +) ENGINE=MyISAM ROW_FORMAT=DYNAMIC; +INSERT INTO t2 (mot,topic,date,pseudo) VALUES ('joce','40143','2002-10-22','joce'), ('joce','43506','2002-10-22','joce'); +select numeropost as a FROM t1 GROUP BY (SELECT 1 FROM t1 HAVING a=1); +a +40143 +SELECT numeropost,maxnumrep FROM t1 WHERE exists (SELECT 1 FROM t2 WHERE (mot='joce') AND date >= '2002-10-21' AND t1.numeropost = t2.topic) ORDER BY maxnumrep DESC LIMIT 0, 20; +numeropost maxnumrep +43506 2 +40143 1 +SELECT (SELECT 1) as a FROM (SELECT 1 FROM t1 HAVING a=1) b; +ERROR 42S22: Unknown column 'a' in 'having clause' +SELECT 1 IN (SELECT 1 FROM t2 HAVING a); +ERROR 42S22: Unknown column 'a' in 'having clause' +SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY topic); +mot topic date pseudo +joce 40143 2002-10-22 joce +joce 43506 2002-10-22 joce +SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100); +mot topic date pseudo +SELECT * from t2 where topic IN (SELECT SUM(topic) FROM t1); +mot topic date pseudo +SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY topic); +mot topic date pseudo +joce 40143 2002-10-22 joce +joce 43506 2002-10-22 joce +SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100); +mot topic date pseudo +SELECT * from t2 where topic = any (SELECT SUM(topic) FROM t1); +mot topic date pseudo +SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY topic); +mot topic date pseudo +SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100); +mot topic date pseudo +joce 40143 2002-10-22 joce +joce 43506 2002-10-22 joce +SELECT *, topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100) from t2; +mot topic date pseudo topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100) +joce 40143 2002-10-22 joce 1 +joce 43506 2002-10-22 joce 1 +SELECT * from t2 where topic = all (SELECT SUM(topic) FROM t2); +mot topic date pseudo +SELECT * from t2 where topic <> any (SELECT SUM(topic) FROM t2); +mot topic date pseudo +joce 40143 2002-10-22 joce +joce 43506 2002-10-22 joce +SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000); +mot topic date pseudo +joce 40143 2002-10-22 joce +SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000); +mot topic date pseudo +joce 40143 2002-10-22 joce +SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000); +mot topic date pseudo +joce 40143 2002-10-22 joce +SELECT *, topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000) from t2; +mot topic date pseudo topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000) +joce 40143 2002-10-22 joce 1 +joce 43506 2002-10-22 joce 0 +drop table t1,t2; +CREATE TABLE `t1` ( +`numeropost` mediumint(8) unsigned NOT NULL auto_increment, +`maxnumrep` int(10) unsigned NOT NULL default '0', +PRIMARY KEY (`numeropost`), +UNIQUE KEY `maxnumrep` (`maxnumrep`) +) ENGINE=MyISAM ROW_FORMAT=FIXED; +INSERT INTO t1 (numeropost,maxnumrep) VALUES (1,0),(2,1); +select numeropost as a FROM t1 GROUP BY (SELECT 1 FROM t1 HAVING a=1); +ERROR 21000: Subquery returns more than 1 row +select numeropost as a FROM t1 ORDER BY (SELECT 1 FROM t1 HAVING a=1); +ERROR 21000: Subquery returns more than 1 row +drop table t1; +create table t1 (a int); +insert into t1 values (1),(2),(3); +(select * from t1) union (select * from t1) order by (select a from t1 limit 1); +a +1 +2 +3 +drop table t1; +CREATE TABLE t1 (field char(1) NOT NULL DEFAULT 'b'); +INSERT INTO t1 VALUES (); +SELECT field FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1 FROM (SELECT 1) a HAVING field='b'); +ERROR 21000: Subquery returns more than 1 row +drop table t1; +CREATE TABLE `t1` ( +`numeropost` mediumint(8) unsigned NOT NULL default '0', +`numreponse` int(10) unsigned NOT NULL auto_increment, +`pseudo` varchar(35) NOT NULL default '', +PRIMARY KEY (`numeropost`,`numreponse`), +UNIQUE KEY `numreponse` (`numreponse`), +KEY `pseudo` (`pseudo`,`numeropost`) +) ENGINE=MyISAM; +SELECT (SELECT numeropost FROM t1 HAVING numreponse=a),numreponse FROM (SELECT * FROM t1) as a; +ERROR 42S22: Reference 'numreponse' not supported (forward reference in item list) +SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=a) FROM (SELECT * FROM t1) as a; +ERROR 42S22: Unknown column 'a' in 'having clause' +SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=1) FROM (SELECT * FROM t1) as a; +numreponse (SELECT numeropost FROM t1 HAVING numreponse=1) +INSERT INTO t1 (numeropost,numreponse,pseudo) VALUES (1,1,'joce'),(1,2,'joce'),(1,3,'test'); +EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM t1 WHERE numeropost='1'); +ERROR 21000: Subquery returns more than 1 row +EXPLAIN EXTENDED SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +Warnings: +Note 1003 select max(`test`.`t1`.`numreponse`) AS `MAX(numreponse)` from `test`.`t1` where (`test`.`t1`.`numeropost` = '1') +EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 const PRIMARY,numreponse PRIMARY 7 const,const 1 100.00 Using index +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +Warnings: +Note 1003 select '3' AS `numreponse` from `test`.`t1` where (('1' = '1')) +drop table t1; +CREATE TABLE t1 (a int(1)); +INSERT INTO t1 VALUES (1); +SELECT 1 FROM (SELECT a FROM t1) b HAVING (SELECT b.a)=1; +1 +1 +drop table t1; +create table t1 (a int NOT NULL, b int, primary key (a)); +create table t2 (a int NOT NULL, b int, primary key (a)); +insert into t1 values (0, 10),(1, 11),(2, 12); +insert into t2 values (1, 21),(2, 22),(3, 23); +select * from t1; +a b +0 10 +1 11 +2 12 +update t1 set b= (select b from t1); +ERROR HY000: You can't specify target table 't1' for update in FROM clause +update t1 set b= (select b from t2); +ERROR 21000: Subquery returns more than 1 row +update t1 set b= (select b from t2 where t1.a = t2.a); +select * from t1; +a b +0 NULL +1 21 +2 22 +drop table t1, t2; +create table t1 (a int NOT NULL, b int, primary key (a)); +create table t2 (a int NOT NULL, b int, primary key (a)); +insert into t1 values (0, 10),(1, 11),(2, 12); +insert into t2 values (1, 21),(2, 12),(3, 23); +select * from t1; +a b +0 10 +1 11 +2 12 +select * from t1 where b = (select b from t2 where t1.a = t2.a); +a b +2 12 +delete from t1 where b = (select b from t1); +ERROR HY000: You can't specify target table 't1' for update in FROM clause +delete from t1 where b = (select b from t2); +ERROR 21000: Subquery returns more than 1 row +delete from t1 where b = (select b from t2 where t1.a = t2.a); +select * from t1; +a b +0 10 +1 11 +drop table t1, t2; +create table t11 (a int NOT NULL, b int, primary key (a)); +create table t12 (a int NOT NULL, b int, primary key (a)); +create table t2 (a int NOT NULL, b int, primary key (a)); +insert into t11 values (0, 10),(1, 11),(2, 12); +insert into t12 values (33, 10),(22, 11),(2, 12); +insert into t2 values (1, 21),(2, 12),(3, 23); +select * from t11; +a b +0 10 +1 11 +2 12 +select * from t12; +a b +33 10 +22 11 +2 12 +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); +ERROR HY000: You can't specify target table 't12' for update in FROM clause +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); +ERROR 21000: Subquery returns more than 1 row +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); +select * from t11; +a b +0 10 +1 11 +select * from t12; +a b +33 10 +22 11 +drop table t11, t12, t2; +CREATE TABLE t1 (x int); +create table t2 (a int); +create table t3 (b int); +insert into t2 values (1); +insert into t3 values (1),(2); +INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); +ERROR HY000: You can't specify target table 't1' for update in FROM clause +INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); +ERROR 21000: Subquery returns more than 1 row +INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); +select * from t1; +x +1 +insert into t2 values (1); +INSERT INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); +select * from t1; +x +1 +2 +INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2; +select * from t1; +x +1 +2 +3 +3 +INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2; +select * from t1; +x +1 +2 +3 +3 +11 +11 +INSERT INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2)); +ERROR 42S22: Unknown column 'x' in 'field list' +INSERT INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); +select * from t1; +x +1 +2 +3 +3 +11 +11 +2 +drop table t1, t2, t3; +CREATE TABLE t1 (x int not null, y int, primary key (x)); +create table t2 (a int); +create table t3 (a int); +insert into t2 values (1); +insert into t3 values (1),(2); +select * from t1; +x y +replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); +ERROR HY000: You can't specify target table 't1' for update in FROM clause +replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); +ERROR 21000: Subquery returns more than 1 row +replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); +select * from t1; +x y +1 2 +replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+2 FROM t2)); +select * from t1; +x y +1 3 +replace into t1 (x, y) VALUES ((SELECT a+3 FROM t2), (SELECT a FROM t2)); +select * from t1 order by x; +x y +1 3 +4 1 +replace into t1 (x, y) VALUES ((SELECT a+3 FROM t2), (SELECT a+1 FROM t2)); +select * from t1 order by x; +x y +1 3 +4 2 +replace LOW_PRIORITY into t1 (x, y) VALUES ((SELECT a+1 FROM t2), (SELECT a FROM t2)); +select * from t1 order by x; +x y +1 3 +2 1 +4 2 +drop table t1, t2, t3; +SELECT * FROM (SELECT 1) b WHERE 1 IN (SELECT *); +ERROR HY000: No tables used +CREATE TABLE t2 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t2 VALUES (1),(2); +SELECT * FROM t2 WHERE id IN (SELECT 1); +id +1 +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ref id id 5 const 1 100.00 Using where; Using index +Warnings: +Note 1249 Select 2 was reduced during optimization +Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = 1) +SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); +id +1 +SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); +id +2 +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 ref id id 5 const 1 100.00 Using where; Using index +Warnings: +Note 1249 Select 3 was reduced during optimization +Note 1249 Select 2 was reduced during optimization +Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = (1 + 1)) +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL id 5 NULL 2 100.00 Using where; Using index +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`id`,<exists>(select 1 AS `1` having (<cache>(`test`.`t2`.`id`) = <ref_null_helper>(1)) union select 3 AS `3` having (<cache>(`test`.`t2`.`id`) = <ref_null_helper>(3)))) +SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 3); +id +SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); +id +2 +INSERT INTO t2 VALUES ((SELECT * FROM t2)); +ERROR HY000: You can't specify target table 't2' for update in FROM clause +INSERT INTO t2 VALUES ((SELECT id FROM t2)); +ERROR HY000: You can't specify target table 't2' for update in FROM clause +SELECT * FROM t2; +id +1 +2 +CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 values (1),(1); +UPDATE t2 SET id=(SELECT * FROM t1); +ERROR 21000: Subquery returns more than 1 row +drop table t2, t1; +create table t1 (a int); +insert into t1 values (1),(2),(3); +select 1 IN (SELECT * from t1); +1 IN (SELECT * from t1) +1 +select 10 IN (SELECT * from t1); +10 IN (SELECT * from t1) +0 +select NULL IN (SELECT * from t1); +NULL IN (SELECT * from t1) +NULL +update t1 set a=NULL where a=2; +select 1 IN (SELECT * from t1); +1 IN (SELECT * from t1) +1 +select 3 IN (SELECT * from t1); +3 IN (SELECT * from t1) +1 +select 10 IN (SELECT * from t1); +10 IN (SELECT * from t1) +NULL +select 1 > ALL (SELECT * from t1); +1 > ALL (SELECT * from t1) +0 +select 10 > ALL (SELECT * from t1); +10 > ALL (SELECT * from t1) +NULL +select 1 > ANY (SELECT * from t1); +1 > ANY (SELECT * from t1) +NULL +select 10 > ANY (SELECT * from t1); +10 > ANY (SELECT * from t1) +1 +drop table t1; +create table t1 (a varchar(20)); +insert into t1 values ('A'),('BC'),('DEF'); +select 'A' IN (SELECT * from t1); +'A' IN (SELECT * from t1) +1 +select 'XYZS' IN (SELECT * from t1); +'XYZS' IN (SELECT * from t1) +0 +select NULL IN (SELECT * from t1); +NULL IN (SELECT * from t1) +NULL +update t1 set a=NULL where a='BC'; +select 'A' IN (SELECT * from t1); +'A' IN (SELECT * from t1) +1 +select 'DEF' IN (SELECT * from t1); +'DEF' IN (SELECT * from t1) +1 +select 'XYZS' IN (SELECT * from t1); +'XYZS' IN (SELECT * from t1) +NULL +select 'A' > ALL (SELECT * from t1); +'A' > ALL (SELECT * from t1) +0 +select 'XYZS' > ALL (SELECT * from t1); +'XYZS' > ALL (SELECT * from t1) +NULL +select 'A' > ANY (SELECT * from t1); +'A' > ANY (SELECT * from t1) +NULL +select 'XYZS' > ANY (SELECT * from t1); +'XYZS' > ANY (SELECT * from t1) +1 +drop table t1; +create table t1 (a float); +insert into t1 values (1.5),(2.5),(3.5); +select 1.5 IN (SELECT * from t1); +1.5 IN (SELECT * from t1) +1 +select 10.5 IN (SELECT * from t1); +10.5 IN (SELECT * from t1) +0 +select NULL IN (SELECT * from t1); +NULL IN (SELECT * from t1) +NULL +update t1 set a=NULL where a=2.5; +select 1.5 IN (SELECT * from t1); +1.5 IN (SELECT * from t1) +1 +select 3.5 IN (SELECT * from t1); +3.5 IN (SELECT * from t1) +1 +select 10.5 IN (SELECT * from t1); +10.5 IN (SELECT * from t1) +NULL +select 1.5 > ALL (SELECT * from t1); +1.5 > ALL (SELECT * from t1) +0 +select 10.5 > ALL (SELECT * from t1); +10.5 > ALL (SELECT * from t1) +NULL +select 1.5 > ANY (SELECT * from t1); +1.5 > ANY (SELECT * from t1) +NULL +select 10.5 > ANY (SELECT * from t1); +10.5 > ANY (SELECT * from t1) +1 +explain extended select (select a+1) from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1249 Select 2 was reduced during optimization +Note 1003 select (`test`.`t1`.`a` + 1) AS `(select a+1)` from `test`.`t1` +select (select a+1) from t1; +(select a+1) +2.5 +4.5 +NULL +drop table t1; +CREATE TABLE t1 (a int(11) NOT NULL default '0', PRIMARY KEY (a)); +CREATE TABLE t2 (a int(11) default '0', INDEX (a)); +INSERT INTO t1 VALUES (1),(2),(3),(4); +INSERT INTO t2 VALUES (1),(2),(3); +SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; +a t1.a in (select t2.a from t2) +1 1 +2 1 +3 1 +4 0 +explain extended SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +2 DEPENDENT SUBQUERY t2 index_subquery a a 5 func 2 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t2 on a checking NULL having <is_not_null_test>(`test`.`t2`.`a`)))) AS `t1.a in (select t2.a from t2)` from `test`.`t1` +CREATE TABLE t3 (a int(11) default '0'); +INSERT INTO t3 VALUES (1),(2),(3); +SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; +a t1.a in (select t2.a from t2,t3 where t3.a=t2.a) +1 1 +2 1 +3 1 +4 0 +explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 100.00 Using index +2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 func 2 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(select 1 AS `Not_used` from `test`.`t2` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t2`.`a`) and ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`))) having <is_not_null_test>(`test`.`t2`.`a`))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1` +drop table t1,t2,t3; +create table t1 (a float); +select 10.5 IN (SELECT * from t1 LIMIT 1); +ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' +select 10.5 IN (SELECT * from t1 LIMIT 1 UNION SELECT 1.5); +ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' +drop table t1; +create table t1 (a int, b int, c varchar(10)); +create table t2 (a int); +insert into t1 values (1,2,'a'),(2,3,'b'),(3,4,'c'); +insert into t2 values (1),(2),(NULL); +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t1 where a=t2.a) from t2; +a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a') (select c from t1 where a=t2.a) +1 1 a +2 0 b +NULL 0 NULL +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2; +a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b') (select c from t1 where a=t2.a) +1 0 a +2 1 b +NULL NULL NULL +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t1 where a=t2.a) from t2; +a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c') (select c from t1 where a=t2.a) +1 0 a +2 0 b +NULL 0 NULL +drop table t1,t2; +create table t1 (a int, b real, c varchar(10)); +insert into t1 values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b'); +select ROW(1, 1, 'a') IN (select a,b,c from t1); +ROW(1, 1, 'a') IN (select a,b,c from t1) +1 +select ROW(1, 2, 'a') IN (select a,b,c from t1); +ROW(1, 2, 'a') IN (select a,b,c from t1) +0 +select ROW(1, 1, 'a') IN (select b,a,c from t1); +ROW(1, 1, 'a') IN (select b,a,c from t1) +1 +select ROW(1, 1, 'a') IN (select a,b,c from t1 where a is not null); +ROW(1, 1, 'a') IN (select a,b,c from t1 where a is not null) +1 +select ROW(1, 2, 'a') IN (select a,b,c from t1 where a is not null); +ROW(1, 2, 'a') IN (select a,b,c from t1 where a is not null) +0 +select ROW(1, 1, 'a') IN (select b,a,c from t1 where a is not null); +ROW(1, 1, 'a') IN (select b,a,c from t1 where a is not null) +1 +select ROW(1, 1, 'a') IN (select a,b,c from t1 where c='b' or c='a'); +ROW(1, 1, 'a') IN (select a,b,c from t1 where c='b' or c='a') +1 +select ROW(1, 2, 'a') IN (select a,b,c from t1 where c='b' or c='a'); +ROW(1, 2, 'a') IN (select a,b,c from t1 where c='b' or c='a') +0 +select ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a'); +ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a') +1 +select ROW(1, 1, 'a') IN (select b,a,c from t1 limit 2); +ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' +drop table t1; +create table t1 (a int); +insert into t1 values (1); +do @a:=(SELECT a from t1); +select @a; +@a +1 +set @a:=2; +set @a:=(SELECT a from t1); +select @a; +@a +1 +drop table t1; +do (SELECT a from t1); +ERROR 42S02: Table 'test.t1' doesn't exist +set @a:=(SELECT a from t1); +ERROR 42S02: Table 'test.t1' doesn't exist +CREATE TABLE t1 (a int, KEY(a)); +HANDLER t1 OPEN; +HANDLER t1 READ a=((SELECT 1)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT 1))' at line 1 +HANDLER t1 CLOSE; +drop table t1; +create table t1 (a int); +create table t2 (b int); +insert into t1 values (1),(2); +insert into t2 values (1); +select a from t1 where a in (select a from t1 where a in (select b from t2)); +a +1 +drop table t1, t2; +create table t1 (a int, b int); +create table t2 like t1; +insert into t1 values (1,2),(1,3),(1,4),(1,5); +insert into t2 values (1,2),(1,3); +select * from t1 where row(a,b) in (select a,b from t2); +a b +1 2 +1 3 +drop table t1, t2; +CREATE TABLE `t1` (`i` int(11) NOT NULL default '0',PRIMARY KEY (`i`)) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES (1); +UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); +select * from t1; +i +2 +drop table t1; +CREATE TABLE t1 (a int(1)); +EXPLAIN EXTENDED SELECT (SELECT RAND() FROM t1) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 0 0.00 +2 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 0 0.00 +Warnings: +Note 1003 select (select rand() AS `RAND()` from `test`.`t1`) AS `(SELECT RAND() FROM t1)` from `test`.`t1` +EXPLAIN EXTENDED SELECT (SELECT ENCRYPT('test') FROM t1) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 0 0.00 +2 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 0 0.00 +Warnings: +Note 1003 select (select encrypt('test') AS `ENCRYPT('test')` from `test`.`t1`) AS `(SELECT ENCRYPT('test') FROM t1)` from `test`.`t1` +EXPLAIN EXTENDED SELECT (SELECT BENCHMARK(1,1) FROM t1) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 0 0.00 +2 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 0 0.00 +Warnings: +Note 1003 select (select benchmark(1,1) AS `BENCHMARK(1,1)` from `test`.`t1`) AS `(SELECT BENCHMARK(1,1) FROM t1)` from `test`.`t1` +drop table t1; +CREATE TABLE `t1` ( +`mot` varchar(30) character set latin1 NOT NULL default '', +`topic` mediumint(8) unsigned NOT NULL default '0', +`date` date NOT NULL default '0000-00-00', +`pseudo` varchar(35) character set latin1 NOT NULL default '', +PRIMARY KEY (`mot`,`pseudo`,`date`,`topic`), +KEY `pseudo` (`pseudo`,`date`,`topic`), +KEY `topic` (`topic`) +) ENGINE=MyISAM CHARSET=latin1 ROW_FORMAT=DYNAMIC; +CREATE TABLE `t2` ( +`mot` varchar(30) character set latin1 NOT NULL default '', +`topic` mediumint(8) unsigned NOT NULL default '0', +`date` date NOT NULL default '0000-00-00', +`pseudo` varchar(35) character set latin1 NOT NULL default '', +PRIMARY KEY (`mot`,`pseudo`,`date`,`topic`), +KEY `pseudo` (`pseudo`,`date`,`topic`), +KEY `topic` (`topic`) +) ENGINE=MyISAM CHARSET=latin1 ROW_FORMAT=DYNAMIC; +CREATE TABLE `t3` ( +`numeropost` mediumint(8) unsigned NOT NULL auto_increment, +`maxnumrep` int(10) unsigned NOT NULL default '0', +PRIMARY KEY (`numeropost`), +UNIQUE KEY `maxnumrep` (`maxnumrep`) +) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES ('joce','1','','joce'),('test','2','','test'); +Warnings: +Warning 1265 Data truncated for column 'date' at row 1 +Warning 1265 Data truncated for column 'date' at row 2 +INSERT INTO t2 VALUES ('joce','1','','joce'),('test','2','','test'); +Warnings: +Warning 1265 Data truncated for column 'date' at row 1 +Warning 1265 Data truncated for column 'date' at row 2 +INSERT INTO t3 VALUES (1,1); +SELECT DISTINCT topic FROM t2 WHERE NOT EXISTS(SELECT * FROM t3 WHERE +numeropost=topic); +topic +2 +select * from t1; +mot topic date pseudo +joce 1 0000-00-00 joce +test 2 0000-00-00 test +DELETE FROM t1 WHERE topic IN (SELECT DISTINCT topic FROM t2 WHERE NOT +EXISTS(SELECT * FROM t3 WHERE numeropost=topic)); +select * from t1; +mot topic date pseudo +joce 1 0000-00-00 joce +drop table t1, t2, t3; +SELECT * FROM (SELECT 1 as a,(SELECT a)) a; +a (SELECT a) +1 1 +CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT 1)) a; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(1) NOT NULL DEFAULT '0', + `(SELECT 1)` int(1) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a)) a; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(1) NOT NULL DEFAULT '0', + `(SELECT a)` int(1) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a+0)) a; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(1) NOT NULL DEFAULT '0', + `(SELECT a+0)` int(3) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a; +select * from t1; +a +2 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a int); +insert into t1 values (1), (2), (3); +explain extended select a,(select (select rand() from t1 limit 1) from t1 limit 1) +from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +2 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 +3 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 3 100.00 +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,(select (select rand() AS `rand()` from `test`.`t1` limit 1) AS `(select rand() from t1 limit 1)` from `test`.`t1` limit 1) AS `(select (select rand() from t1 limit 1) from t1 limit 1)` from `test`.`t1` +drop table t1; +select t1.Continent, t2.Name, t2.Population from t1 LEFT JOIN t2 ON t1.Code = t2.Country where t2.Population IN (select max(t2.Population) AS Population from t2, t1 where t2.Country = t1.Code group by Continent); +ERROR 42S02: Table 'test.t1' doesn't exist +CREATE TABLE t1 ( +ID int(11) NOT NULL auto_increment, +name char(35) NOT NULL default '', +t2 char(3) NOT NULL default '', +District char(20) NOT NULL default '', +Population int(11) NOT NULL default '0', +PRIMARY KEY (ID) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (130,'Sydney','AUS','New South Wales',3276207); +INSERT INTO t1 VALUES (131,'Melbourne','AUS','Victoria',2865329); +INSERT INTO t1 VALUES (132,'Brisbane','AUS','Queensland',1291117); +CREATE TABLE t2 ( +Code char(3) NOT NULL default '', +Name char(52) NOT NULL default '', +Continent enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') NOT NULL default 'Asia', +Region char(26) NOT NULL default '', +SurfaceArea float(10,2) NOT NULL default '0.00', +IndepYear smallint(6) default NULL, +Population int(11) NOT NULL default '0', +LifeExpectancy float(3,1) default NULL, +GNP float(10,2) default NULL, +GNPOld float(10,2) default NULL, +LocalName char(45) NOT NULL default '', +GovernmentForm char(45) NOT NULL default '', +HeadOfState char(60) default NULL, +Capital int(11) default NULL, +Code2 char(2) NOT NULL default '', +PRIMARY KEY (Code) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES ('AUS','Australia','Oceania','Australia and New Zealand',7741220.00,1901,18886000,79.8,351182.00,392911.00,'Australia','Constitutional Monarchy, Federation','Elisabeth II',135,'AU'); +INSERT INTO t2 VALUES ('AZE','Azerbaijan','Asia','Middle East',86600.00,1991,7734000,62.9,4127.00,4100.00,'Azärbaycan','Federal Republic','Heydär Äliyev',144,'AZ'); +select t2.Continent, t1.Name, t1.Population from t2 LEFT JOIN t1 ON t2.Code = t1.t2 where t1.Population IN (select max(t1.Population) AS Population from t1, t2 where t1.t2 = t2.Code group by Continent); +Continent Name Population +Oceania Sydney 3276207 +drop table t1, t2; +CREATE TABLE `t1` ( +`id` mediumint(8) unsigned NOT NULL auto_increment, +`pseudo` varchar(35) character set latin1 NOT NULL default '', +PRIMARY KEY (`id`), +UNIQUE KEY `pseudo` (`pseudo`) +) ENGINE=MyISAM PACK_KEYS=1 ROW_FORMAT=DYNAMIC; +INSERT INTO t1 (pseudo) VALUES ('test'); +SELECT 0 IN (SELECT 1 FROM t1 a); +0 IN (SELECT 1 FROM t1 a) +0 +EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +Warnings: +Note 1003 select <in_optimizer>(0,<exists>(select 1 AS `Not_used` from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` +INSERT INTO t1 (pseudo) VALUES ('test1'); +SELECT 0 IN (SELECT 1 FROM t1 a); +0 IN (SELECT 1 FROM t1 a) +0 +EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +Warnings: +Note 1003 select <in_optimizer>(0,<exists>(select 1 AS `Not_used` from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` +drop table t1; +CREATE TABLE `t1` ( +`i` int(11) NOT NULL default '0', +PRIMARY KEY (`i`) +) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES (1); +UPDATE t1 SET i=i+(SELECT MAX(i) FROM (SELECT 1) t) WHERE i=(SELECT MAX(i)); +UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); +UPDATE t1 SET t.i=i+(SELECT MAX(i) FROM (SELECT 1) t); +ERROR 42S22: Unknown column 't.i' in 'field list' +select * from t1; +i +3 +drop table t1; +CREATE TABLE t1 ( +id int(11) default NULL +) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES (1),(1),(2),(2),(1),(3); +CREATE TABLE t2 ( +id int(11) default NULL, +name varchar(15) default NULL +) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t2 VALUES (4,'vita'), (1,'vita'), (2,'vita'), (1,'vita'); +update t1, t2 set t2.name='lenka' where t2.id in (select id from t1); +select * from t2; +id name +4 vita +1 lenka +2 lenka +1 lenka +drop table t1,t2; +create table t1 (a int, unique index indexa (a)); +insert into t1 values (-1), (-4), (-2), (NULL); +select -10 IN (select a from t1 FORCE INDEX (indexa)); +-10 IN (select a from t1 FORCE INDEX (indexa)) +NULL +drop table t1; +create table t1 (id int not null auto_increment primary key, salary int, key(salary)); +insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); +explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ref salary salary 5 const 1 100.00 Using where +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +Warnings: +Note 1003 select `test`.`t1`.`id` AS `id` from `test`.`t1` where (`test`.`t1`.`salary` = (select max(`test`.`t1`.`salary`) AS `MAX(salary)` from `test`.`t1`)) +drop table t1; +CREATE TABLE t1 ( +ID int(10) unsigned NOT NULL auto_increment, +SUB_ID int(3) unsigned NOT NULL default '0', +REF_ID int(10) unsigned default NULL, +REF_SUB int(3) unsigned default '0', +PRIMARY KEY (ID,SUB_ID), +UNIQUE KEY t1_PK (ID,SUB_ID), +KEY t1_FK (REF_ID,REF_SUB), +KEY t1_REFID (REF_ID) +) ENGINE=MyISAM CHARSET=cp1251; +INSERT INTO t1 VALUES (1,0,NULL,NULL),(2,0,NULL,NULL); +SELECT DISTINCT REF_ID FROM t1 WHERE ID= (SELECT DISTINCT REF_ID FROM t1 WHERE ID=2); +REF_ID +DROP TABLE t1; +create table t1 (a int, b int); +create table t2 (a int, b int); +insert into t1 values (1,0), (2,0), (3,0); +insert into t2 values (1,1), (2,1), (3,1), (2,2); +update ignore t1 set b=(select b from t2 where t1.a=t2.a); +Warnings: +Error 1242 Subquery returns more than 1 row +select * from t1; +a b +1 1 +2 NULL +3 1 +drop table t1, t2; +CREATE TABLE `t1` ( +`id` mediumint(8) unsigned NOT NULL auto_increment, +`pseudo` varchar(35) NOT NULL default '', +`email` varchar(60) NOT NULL default '', +PRIMARY KEY (`id`), +UNIQUE KEY `email` (`email`), +UNIQUE KEY `pseudo` (`pseudo`) +) ENGINE=MyISAM CHARSET=latin1 PACK_KEYS=1 ROW_FORMAT=DYNAMIC; +INSERT INTO t1 (id,pseudo,email) VALUES (1,'test','test'),(2,'test1','test1'); +SELECT pseudo as a, pseudo as b FROM t1 GROUP BY (SELECT a) ORDER BY (SELECT id*1); +a b +test test +test1 test1 +drop table if exists t1; +(SELECT 1 as a) UNION (SELECT 1) ORDER BY (SELECT a+0); +a +1 +create table t1 (a int not null, b int, primary key (a)); +create table t2 (a int not null, primary key (a)); +create table t3 (a int not null, b int, primary key (a)); +insert into t1 values (1,10), (2,20), (3,30), (4,40); +insert into t2 values (2), (3), (4), (5); +insert into t3 values (10,3), (20,4), (30,5); +select * from t2 where t2.a in (select a from t1); +a +2 +3 +4 +explain extended select * from t2 where t2.a in (select a from t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY))) +select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +a +2 +4 +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY where ((`test`.`t1`.`b` <> 30) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`))))) +select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +a +2 +3 +explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 100.00 +2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(select 1 AS `Not_used` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`)))) +drop table t1, t2, t3; +create table t1 (a int, b int, index a (a,b)); +create table t2 (a int, index a (a)); +create table t3 (a int, b int, index a (a)); +insert into t1 values (1,10), (2,20), (3,30), (4,40); +insert into t2 values (2), (3), (4), (5); +insert into t3 values (10,3), (20,4), (30,5); +select * from t2 where t2.a in (select a from t1); +a +2 +3 +4 +explain extended select * from t2 where t2.a in (select a from t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 5 NULL 4 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 100.00 Using index; Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on a where (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`)))) +select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +a +2 +4 +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 5 NULL 4 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 100.00 Using index; Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on a where ((`test`.`t1`.`b` <> 30) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`))))) +select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +a +2 +3 +explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 5 NULL 4 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 ref a a 5 func 1001 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 100.00 Using where; Using index; Using join buffer +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(select 1 AS `Not_used` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`)))) +insert into t1 values (3,31); +select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +a +2 +3 +4 +select * from t2 where t2.a in (select a from t1 where t1.b <> 30 and t1.b <> 31); +a +2 +4 +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t2 index NULL a 5 NULL 4 100.00 Using where; Using index +2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 100.00 Using index; Using where +Warnings: +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on a where ((`test`.`t1`.`b` <> 30) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`))))) +drop table t1, t2, t3; +create table t1 (a int, b int); +create table t2 (a int, b int); +create table t3 (a int, b int); +insert into t1 values (0,100),(1,2), (1,3), (2,2), (2,7), (2,-1), (3,10); +insert into t2 values (0,0), (1,1), (2,1), (3,1), (4,1); +insert into t3 values (3,3), (2,2), (1,1); +select a,(select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3; +a (select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) +3 1 +2 2 +1 2 +drop table t1,t2,t3; +create table t1 (s1 int); +create table t2 (s1 int); +insert into t1 values (1); +insert into t2 values (1); +select * from t1 where exists (select s1 from t2 having max(t2.s1)=t1.s1); +s1 +1 +drop table t1,t2; +create table t1 (s1 int); +create table t2 (s1 int); +insert into t1 values (1); +insert into t2 values (1); +update t1 set s1 = s1 + 1 where 1 = (select x.s1 as A from t2 WHERE t2.s1 > t1.s1 order by A); +ERROR 42S22: Unknown column 'x.s1' in 'field list' +DROP TABLE t1, t2; +CREATE TABLE t1 (s1 CHAR(5) COLLATE latin1_german1_ci, +s2 CHAR(5) COLLATE latin1_swedish_ci); +INSERT INTO t1 VALUES ('z','?'); +select * from t1 where s1 > (select max(s2) from t1); +ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '>' +select * from t1 where s1 > any (select max(s2) from t1); +ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '>' +drop table t1; +create table t1(toid int,rd int); +create table t2(userid int,pmnew int,pmtotal int); +insert into t2 values(1,0,0),(2,0,0); +insert into t1 values(1,0),(1,0),(1,0),(1,12),(1,15),(1,123),(1,12312),(1,12312),(1,123),(2,0),(2,0),(2,1),(2,2); +select userid,pmtotal,pmnew, (select count(rd) from t1 where toid=t2.userid) calc_total, (select count(rd) from t1 where rd=0 and toid=t2.userid) calc_new from t2 where userid in (select distinct toid from t1); +userid pmtotal pmnew calc_total calc_new +1 0 0 9 3 +2 0 0 4 2 +drop table t1, t2; +create table t1 (s1 char(5)); +select (select 'a','b' from t1 union select 'a','b' from t1) from t1; +ERROR 21000: Operand should contain 1 column(s) +insert into t1 values ('tttt'); +select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); +s1 +tttt +explain extended (select * from t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 (select `test`.`t1`.`s1` AS `s1` from `test`.`t1`) +(select * from t1); +s1 +tttt +drop table t1; +create table t1 (s1 char(5), index s1(s1)); +create table t2 (s1 char(5), index s1(s1)); +insert into t1 values ('a1'),('a2'),('a3'); +insert into t2 values ('a1'),('a2'); +select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; +s1 s1 NOT IN (SELECT s1 FROM t2) +a1 0 +a2 0 +a3 1 +select s1, s1 = ANY (SELECT s1 FROM t2) from t1; +s1 s1 = ANY (SELECT s1 FROM t2) +a1 1 +a2 1 +a3 0 +select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; +s1 s1 <> ALL (SELECT s1 FROM t2) +a1 0 +a2 0 +a3 1 +select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; +s1 s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') +a1 0 +a2 1 +a3 1 +explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index +2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key +Warnings: +Note 1003 select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond(<is_not_null_test>(`test`.`t2`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1` +explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index +2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key +Warnings: +Note 1003 select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond(<is_not_null_test>(`test`.`t2`.`s1`))))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1` +explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index +2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Full scan on NULL key +Warnings: +Note 1003 select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL having trigcond(<is_not_null_test>(`test`.`t2`.`s1`))))))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1` +explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 index NULL s1 6 NULL 3 100.00 Using index +2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 100.00 Using index; Using where; Full scan on NULL key +Warnings: +Note 1003 select `test`.`t1`.`s1` AS `s1`,(not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL where (`test`.`t2`.`s1` < 'a2') having trigcond(<is_not_null_test>(`test`.`t2`.`s1`))))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1` +drop table t1,t2; +create table t2 (a int, b int); +create table t3 (a int); +insert into t3 values (6),(7),(3); +select * from t3 where a >= all (select b from t2); +a +6 +7 +3 +explain extended select * from t3 where a >= all (select b from t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <not>((`test`.`t3`.`a` < (select max(`test`.`t2`.`b`) from `test`.`t2`))) +select * from t3 where a >= some (select b from t2); +a +explain extended select * from t3 where a >= some (select b from t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <nop>((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +select * from t3 where a >= all (select b from t2 group by 1); +a +6 +7 +3 +explain extended select * from t3 where a >= all (select b from t2 group by 1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary; Using filesort +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <not>((`test`.`t3`.`a` < <max>(select `test`.`t2`.`b` AS `b` from `test`.`t2` group by 1))) +select * from t3 where a >= some (select b from t2 group by 1); +a +explain extended select * from t3 where a >= some (select b from t2 group by 1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary; Using filesort +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <nop>((`test`.`t3`.`a` >= <min>(select `test`.`t2`.`b` AS `b` from `test`.`t2` group by 1))) +select * from t3 where NULL >= any (select b from t2); +a +explain extended select * from t3 where NULL >= any (select b from t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where 0 +select * from t3 where NULL >= any (select b from t2 group by 1); +a +explain extended select * from t3 where NULL >= any (select b from t2 group by 1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary; Using filesort +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where 0 +select * from t3 where NULL >= some (select b from t2); +a +explain extended select * from t3 where NULL >= some (select b from t2); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where 0 +select * from t3 where NULL >= some (select b from t2 group by 1); +a +explain extended select * from t3 where NULL >= some (select b from t2 group by 1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary; Using filesort +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where 0 +insert into t2 values (2,2), (2,1), (3,3), (3,1); +select * from t3 where a > all (select max(b) from t2 group by a); +a +6 +7 +explain extended select * from t3 where a > all (select max(b) from t2 group by a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where +2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 100.00 Using temporary; Using filesort +Warnings: +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <not>((`test`.`t3`.`a` <= <max>(select max(`test`.`t2`.`b`) AS `max(b)` from `test`.`t2` group by `test`.`t2`.`a`))) +drop table t2, t3; +CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ; +INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now()); +CREATE TABLE `t2` (`db_id` int(11) NOT NULL auto_increment,`name` varchar(200) NOT NULL default '',`primary_uid` smallint(6) NOT NULL default '0',`secondary_uid` smallint(6) NOT NULL default '0',PRIMARY KEY (`db_id`),UNIQUE KEY `name_2` (`name`),FULLTEXT KEY `name` (`name`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=2147483647; +INSERT INTO `t2` (`db_id`, `name`, `primary_uid`, `secondary_uid`) VALUES (18, 'Not Set 1', 0, 0),(19, 'Valid', 1, 2),(20, 'Valid 2', 1, 2),(21, 'Should Not Return', 1, 2),(26, 'Not Set 2', 0, 0),(-1, 'ALL DB\'S', 0, 0); +CREATE TABLE `t3` (`taskgenid` mediumint(9) NOT NULL auto_increment,`dbid` int(11) NOT NULL default '0',`taskid` int(11) NOT NULL default '0',`mon` tinyint(4) NOT NULL default '1',`tues` tinyint(4) NOT NULL default '1',`wed` tinyint(4) NOT NULL default '1',`thur` tinyint(4) NOT NULL default '1',`fri` tinyint(4) NOT NULL default '1',`sat` tinyint(4) NOT NULL default '0',`sun` tinyint(4) NOT NULL default '0',`how_often` smallint(6) NOT NULL default '1',`userid` smallint(6) NOT NULL default '0',`active` tinyint(4) NOT NULL default '1',PRIMARY KEY (`taskgenid`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=2 ; +INSERT INTO `t3` (`taskgenid`, `dbid`, `taskid`, `mon`, `tues`,`wed`, `thur`, `fri`, `sat`, `sun`, `how_often`, `userid`, `active`) VALUES (1,-1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1); +CREATE TABLE `t4` (`task_id` smallint(6) NOT NULL default '0',`description` varchar(200) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; +INSERT INTO `t4` (`task_id`, `description`) VALUES (1, 'Daily Check List'),(2, 'Weekly Status'); +select dbid, name, (date_format(now() , '%Y-%m-%d') - INTERVAL how_often DAY) >= ifnull((SELECT date_format(max(create_date),'%Y-%m-%d') FROM t1 WHERE dbid = b.db_id AND taskid = a.taskgenid), '1950-01-01') from t3 a, t2 b, t4 WHERE dbid = - 1 AND primary_uid = '1' AND t4.task_id = taskid; +dbid name (date_format(now() , '%Y-%m-%d') - INTERVAL how_often DAY) >= ifnull((SELECT date_format(max(create_date),'%Y-%m-%d') FROM t1 WHERE dbid = b.db_id AND taskid = a.taskgenid), '1950-01-01') +-1 Valid 1 +-1 Valid 2 1 +-1 Should Not Return 0 +SELECT dbid, name FROM t3 a, t2 b, t4 WHERE dbid = - 1 AND primary_uid = '1' AND ((date_format(now() , '%Y-%m-%d') - INTERVAL how_often DAY) >= ifnull((SELECT date_format(max(create_date),'%Y-%m-%d') FROM t1 WHERE dbid = b.db_id AND taskid = a.taskgenid), '1950-01-01')) AND t4.task_id = taskid; +dbid name +-1 Valid +-1 Valid 2 +drop table t1,t2,t3,t4; +CREATE TABLE t1 (id int(11) default NULL) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 (id int(11) default NULL) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t2 VALUES (2),(6); +select * from t1 where (1,2,6) in (select * from t2); +ERROR 21000: Operand should contain 3 column(s) +DROP TABLE t1,t2; +create table t1 (s1 int); +insert into t1 values (1); +insert into t1 values (2); +set sort_buffer_size = (select s1 from t1); +ERROR 21000: Subquery returns more than 1 row +do (select * from t1); +Warnings: +Error 1242 Subquery returns more than 1 row +drop table t1; +create table t1 (s1 char); +insert into t1 values ('e'); +select * from t1 where 'f' > any (select s1 from t1); +s1 +e +select * from t1 where 'f' > any (select s1 from t1 union select s1 from t1); +s1 +e +explain extended select * from t1 where 'f' > any (select s1 from t1 union select s1 from t1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 1 100.00 +2 SUBQUERY t1 ALL NULL NULL NULL NULL 1 100.00 +3 UNION t1 ALL NULL NULL NULL NULL 1 100.00 +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1003 select `test`.`t1`.`s1` AS `s1` from `test`.`t1` where 1 +drop table t1; +CREATE TABLE t1 (number char(11) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES ('69294728265'),('18621828126'),('89356874041'),('95895001874'); +CREATE TABLE t2 (code char(5) NOT NULL default '',UNIQUE KEY code (code)) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t2 VALUES ('1'),('1226'),('1245'),('1862'),('18623'),('1874'),('1967'),('6'); +select c.number as phone,(select p.code from t2 p where c.number like concat(p.code, '%') order by length(p.code) desc limit 1) as code from t1 c; +phone code +69294728265 6 +18621828126 1862 +89356874041 NULL +95895001874 NULL +drop table t1, t2; +create table t1 (s1 int); +create table t2 (s1 int); +select * from t1 where (select count(*) from t2 where t1.s2) = 1; +ERROR 42S22: Unknown column 't1.s2' in 'where clause' +select * from t1 where (select count(*) from t2 group by t1.s2) = 1; +ERROR 42S22: Unknown column 't1.s2' in 'group statement' +select count(*) from t2 group by t1.s2; +ERROR 42S22: Unknown column 't1.s2' in 'group statement' +drop table t1, t2; +CREATE TABLE t1(COLA FLOAT NOT NULL,COLB FLOAT NOT NULL,COLC VARCHAR(20) DEFAULT NULL,PRIMARY KEY (COLA, COLB)); +CREATE TABLE t2(COLA FLOAT NOT NULL,COLB FLOAT NOT NULL,COLC CHAR(1) NOT NULL,PRIMARY KEY (COLA)); +INSERT INTO t1 VALUES (1,1,'1A3240'), (1,2,'4W2365'); +INSERT INTO t2 VALUES (100, 200, 'C'); +SELECT DISTINCT COLC FROM t1 WHERE COLA = (SELECT COLA FROM t2 WHERE COLB = 200 AND COLC ='C' LIMIT 1); +COLC +DROP TABLE t1, t2; +CREATE TABLE t1 (a int(1)); +INSERT INTO t1 VALUES (1),(1),(1),(1),(1),(2),(3),(4),(5); +SELECT DISTINCT (SELECT a) FROM t1 LIMIT 100; +(SELECT a) +1 +2 +3 +4 +5 +DROP TABLE t1; +create table t1 (a int, b decimal(13, 3)); +insert into t1 values (1, 0.123); +select a, (select max(b) from t1) into outfile "subselect.out.file.1" from t1; +delete from t1; +load data infile "subselect.out.file.1" into table t1; +select * from t1; +a b +1 0.123 +drop table t1; +CREATE TABLE `t1` ( +`id` int(11) NOT NULL auto_increment, +`id_cns` tinyint(3) unsigned NOT NULL default '0', +`tipo` enum('','UNO','DUE') NOT NULL default '', +`anno_dep` smallint(4) unsigned zerofill NOT NULL default '0000', +`particolare` mediumint(8) unsigned NOT NULL default '0', +`generale` mediumint(8) unsigned NOT NULL default '0', +`bis` tinyint(3) unsigned NOT NULL default '0', +PRIMARY KEY (`id`), +UNIQUE KEY `idx_cns_gen_anno` (`anno_dep`,`id_cns`,`generale`,`particolare`), +UNIQUE KEY `idx_cns_par_anno` (`id_cns`,`anno_dep`,`tipo`,`particolare`,`bis`) +); +INSERT INTO `t1` VALUES (1,16,'UNO',1987,2048,9681,0),(2,50,'UNO',1987,1536,13987,0),(3,16,'UNO',1987,2432,14594,0),(4,16,'UNO',1987,1792,13422,0),(5,16,'UNO',1987,1025,10240,0),(6,16,'UNO',1987,1026,7089,0); +CREATE TABLE `t2` ( +`id` tinyint(3) unsigned NOT NULL auto_increment, +`max_anno_dep` smallint(6) unsigned NOT NULL default '0', +PRIMARY KEY (`id`) +); +INSERT INTO `t2` VALUES (16,1987),(50,1990),(51,1990); +SELECT cns.id, cns.max_anno_dep, cns.max_anno_dep = (SELECT s.anno_dep FROM t1 AS s WHERE s.id_cns = cns.id ORDER BY s.anno_dep DESC LIMIT 1) AS PIPPO FROM t2 AS cns; +id max_anno_dep PIPPO +16 1987 1 +50 1990 0 +51 1990 NULL +DROP TABLE t1, t2; +create table t1 (a int); +insert into t1 values (1), (2), (3); +SET SQL_SELECT_LIMIT=1; +select sum(a) from (select * from t1) as a; +sum(a) +6 +select 2 in (select * from t1); +2 in (select * from t1) +1 +SET SQL_SELECT_LIMIT=default; +drop table t1; +CREATE TABLE t1 (a int, b int, INDEX (a)); +INSERT INTO t1 VALUES (1, 1), (1, 2), (1, 3); +SELECT * FROM t1 WHERE a = (SELECT MAX(a) FROM t1 WHERE a = 1) ORDER BY b; +a b +1 1 +1 2 +1 3 +DROP TABLE t1; +create table t1(val varchar(10)); +insert into t1 values ('aaa'), ('bbb'),('eee'),('mmm'),('ppp'); +select count(*) from t1 as w1 where w1.val in (select w2.val from t1 as w2 where w2.val like 'm%') and w1.val in (select w3.val from t1 as w3 where w3.val like 'e%'); +count(*) +0 +drop table t1; +create table t1 (id int not null, text varchar(20) not null default '', primary key (id)); +insert into t1 (id, text) values (1, 'text1'), (2, 'text2'), (3, 'text3'), (4, 'text4'), (5, 'text5'), (6, 'text6'), (7, 'text7'), (8, 'text8'), (9, 'text9'), (10, 'text10'), (11, 'text11'), (12, 'text12'); +select * from t1 where id not in (select id from t1 where id < 8); +id text +8 text8 +9 text9 +10 text10 +11 text11 +12 text12 +select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null); +id text +8 text8 +9 text9 +10 text10 +11 text11 +12 text12 +explain extended select * from t1 where id not in (select id from t1 where id < 8); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 12 100.00 Using where +2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 100.00 Using index; Using where +Warnings: +Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`id`,<exists>(<primary_index_lookup>(<cache>(`test`.`t1`.`id`) in t1 on PRIMARY where ((`test`.`t1`.`id` < 8) and (<cache>(`test`.`t1`.`id`) = `test`.`t1`.`id`))))))) +explain extended select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY tt ALL NULL NULL NULL NULL 12 100.00 Using where +2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 test.tt.id 1 100.00 Using where; Using index +Warnings: +Note 1276 Field or reference 'test.tt.id' of SELECT #2 was resolved in SELECT #1 +Note 1003 select `test`.`tt`.`id` AS `id`,`test`.`tt`.`text` AS `text` from `test`.`t1` `tt` where (not(exists(select `test`.`t1`.`id` AS `id` from `test`.`t1` where ((`test`.`t1`.`id` < 8) and (`test`.`t1`.`id` = `test`.`tt`.`id`)) having (`test`.`t1`.`id` is not null)))) +insert into t1 (id, text) values (1000, 'text1000'), (1001, 'text1001'); +create table t2 (id int not null, text varchar(20) not null default '', primary key (id)); +insert into t2 (id, text) values (1, 'text1'), (2, 'text2'), (3, 'text3'), (4, 'text4'), (5, 'text5'), (6, 'text6'), (7, 'text7'), (8, 'text8'), (9, 'text9'), (10, 'text10'), (11, 'text1'), (12, 'text2'), (13, 'text3'), (14, 'text4'), (15, 'text5'), (16, 'text6'), (17, 'text7'), (18, 'text8'), (19, 'text9'), (20, 'text10'),(21, 'text1'), (22, 'text2'), (23, 'text3'), (24, 'text4'), (25, 'text5'), (26, 'text6'), (27, 'text7'), (28, 'text8'), (29, 'text9'), (30, 'text10'), (31, 'text1'), (32, 'text2'), (33, 'text3'), (34, 'text4'), (35, 'text5'), (36, 'text6'), (37, 'text7'), (38, 'text8'), (39, 'text9'), (40, 'text10'), (41, 'text1'), (42, 'text2'), (43, 'text3'), (44, 'text4'), (45, 'text5'), (46, 'text6'), (47, 'text7'), (48, 'text8'), (49, 'text9'), (50, 'text10'); +select * from t1 a left join t2 b on (a.id=b.id or b.id is null) join t1 c on (if(isnull(b.id), 1000, b.id)=c.id); +id text id text id text +1 text1 1 text1 1 text1 +2 text2 2 text2 2 text2 +3 text3 3 text3 3 text3 +4 text4 4 text4 4 text4 +5 text5 5 text5 5 text5 +6 text6 6 text6 6 text6 +7 text7 7 text7 7 text7 +8 text8 8 text8 8 text8 +9 text9 9 text9 9 text9 +10 text10 10 text10 10 text10 +11 text11 11 text1 11 text11 +12 text12 12 text2 12 text12 +1000 text1000 NULL NULL 1000 text1000 +1001 text1001 NULL NULL 1000 text1000 +explain extended select * from t1 a left join t2 b on (a.id=b.id or b.id is null) join t1 c on (if(isnull(b.id), 1000, b.id)=c.id); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE a ALL NULL NULL NULL NULL 14 100.00 +1 SIMPLE b eq_ref PRIMARY PRIMARY 4 test.a.id 2 100.00 +1 SIMPLE c eq_ref PRIMARY PRIMARY 4 func 1 100.00 Using where +Warnings: +Note 1003 select `test`.`a`.`id` AS `id`,`test`.`a`.`text` AS `text`,`test`.`b`.`id` AS `id`,`test`.`b`.`text` AS `text`,`test`.`c`.`id` AS `id`,`test`.`c`.`text` AS `text` from `test`.`t1` `a` left join `test`.`t2` `b` on(((`test`.`b`.`id` = `test`.`a`.`id`) or isnull(`test`.`b`.`id`))) join `test`.`t1` `c` where (if(isnull(`test`.`b`.`id`),1000,`test`.`b`.`id`) = `test`.`c`.`id`) +drop table t1,t2; +create table t1 (a int); +insert into t1 values (1); +explain select benchmark(1000, (select a from t1 where a=sha(rand()))); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +2 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 1 Using where +drop table t1; +create table t1(id int); +create table t2(id int); +create table t3(flag int); +select (select * from t3 where id not null) from t1, t2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'null) from t1, t2' at line 1 +drop table t1,t2,t3; +CREATE TABLE t1 (id INT); +CREATE TABLE t2 (id INT); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1); +SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); +id c +1 1 +2 0 +SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); +id c +1 1 +2 0 +SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY t1.id; +id c +1 1 +2 0 +SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY id; +id c +1 1 +2 0 +DROP TABLE t1,t2; +CREATE TABLE t1 ( a int, b int ); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +SELECT a FROM t1 WHERE a > ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +3 +SELECT a FROM t1 WHERE a < ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +SELECT a FROM t1 WHERE a = ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +2 +SELECT a FROM t1 WHERE a >= ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +3 +SELECT a FROM t1 WHERE a < ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +SELECT a FROM t1 WHERE a = ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +2 +SELECT a FROM t1 WHERE a >= ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +3 +ALTER TABLE t1 ADD INDEX (a); +SELECT a FROM t1 WHERE a > ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +3 +SELECT a FROM t1 WHERE a < ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +SELECT a FROM t1 WHERE a = ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +2 +SELECT a FROM t1 WHERE a >= ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +3 +SELECT a FROM t1 WHERE a < ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +SELECT a FROM t1 WHERE a = ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +2 +SELECT a FROM t1 WHERE a >= ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL ( SELECT a FROM t1 WHERE b = 2 ); +a +1 +3 +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 HAVING a = 2); +a +3 +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 HAVING a = 2); +a +1 +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 HAVING a = 2); +a +2 +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 HAVING a = 2); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 HAVING a = 2); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 HAVING a = 2); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 HAVING a = 2); +a +3 +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 HAVING a = 2); +a +1 +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 HAVING a = 2); +a +2 +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 HAVING a = 2); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 HAVING a = 2); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 HAVING a = 2); +a +1 +3 +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +3 +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +1 +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +2 +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +3 +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +1 +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +2 +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +a +1 +3 +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +3 +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +1 +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +2 +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +3 +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +1 +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +2 +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +a +1 +3 +SELECT a FROM t1 WHERE (1,2) > ANY (SELECT a FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE a > ANY (SELECT a,2 FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE (1,2) > ANY (SELECT a,2 FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE (1,2) > ALL (SELECT a FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE a > ALL (SELECT a,2 FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE (1,2) > ALL (SELECT a,2 FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE (1,2) = ALL (SELECT a,2 FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE (1,2) <> ANY (SELECT a,2 FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE (1,2) = ANY (SELECT a FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 2 column(s) +SELECT a FROM t1 WHERE a = ANY (SELECT a,2 FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE (1,2) = ANY (SELECT a,2 FROM t1 WHERE b = 2); +a +SELECT a FROM t1 WHERE (1,2) <> ALL (SELECT a FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 2 column(s) +SELECT a FROM t1 WHERE a <> ALL (SELECT a,2 FROM t1 WHERE b = 2); +ERROR 21000: Operand should contain 1 column(s) +SELECT a FROM t1 WHERE (1,2) <> ALL (SELECT a,2 FROM t1 WHERE b = 2); +a +1 +2 +3 +SELECT a FROM t1 WHERE (a,1) = ANY (SELECT a,1 FROM t1 WHERE b = 2); +a +2 +SELECT a FROM t1 WHERE (a,1) <> ALL (SELECT a,1 FROM t1 WHERE b = 2); +a +1 +3 +SELECT a FROM t1 WHERE (a,1) = ANY (SELECT a,1 FROM t1 HAVING a = 2); +a +2 +SELECT a FROM t1 WHERE (a,1) <> ALL (SELECT a,1 FROM t1 HAVING a = 2); +a +1 +3 +SELECT a FROM t1 WHERE (a,1) = ANY (SELECT a,1 FROM t1 WHERE b = 2 UNION SELECT a,1 FROM t1 WHERE b = 2); +a +2 +SELECT a FROM t1 WHERE (a,1) <> ALL (SELECT a,1 FROM t1 WHERE b = 2 UNION SELECT a,1 FROM t1 WHERE b = 2); +a +1 +3 +SELECT a FROM t1 WHERE (a,1) = ANY (SELECT a,1 FROM t1 HAVING a = 2 UNION SELECT a,1 FROM t1 HAVING a = 2); +a +2 +SELECT a FROM t1 WHERE (a,1) <> ALL (SELECT a,1 FROM t1 HAVING a = 2 UNION SELECT a,1 FROM t1 HAVING a = 2); +a +1 +3 +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 WHERE b = 2 group by a); +a +3 +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 WHERE b = 2 group by a); +a +1 +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 WHERE b = 2 group by a); +a +2 +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 WHERE b = 2 group by a); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 WHERE b = 2 group by a); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 WHERE b = 2 group by a); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 WHERE b = 2 group by a); +a +3 +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 WHERE b = 2 group by a); +a +1 +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 WHERE b = 2 group by a); +a +2 +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 WHERE b = 2 group by a); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 WHERE b = 2 group by a); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 WHERE b = 2 group by a); +a +1 +3 +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 group by a HAVING a = 2); +a +3 +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 group by a HAVING a = 2); +a +1 +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 group by a HAVING a = 2); +a +2 +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 group by a HAVING a = 2); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 group by a HAVING a = 2); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 group by a HAVING a = 2); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 group by a HAVING a = 2); +a +3 +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 group by a HAVING a = 2); +a +1 +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 group by a HAVING a = 2); +a +2 +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 group by a HAVING a = 2); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 group by a HAVING a = 2); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 group by a HAVING a = 2); +a +1 +3 +SELECT concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a > t1.a), '-') from t1 a; +concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a > t1.a), '-') +0- +0- +1- +SELECT concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a < t1.a), '-') from t1 a; +concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a < t1.a), '-') +1- +0- +0- +SELECT concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a = t1.a), '-') from t1 a; +concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a = t1.a), '-') +0- +1- +0- +DROP TABLE t1; +CREATE TABLE t1 ( a double, b double ); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 WHERE b = 2e0); +a +3 +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 WHERE b = 2e0); +a +1 +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 WHERE b = 2e0); +a +2 +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 WHERE b = 2e0); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 WHERE b = 2e0); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 WHERE b = 2e0); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 WHERE b = 2e0); +a +3 +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 WHERE b = 2e0); +a +1 +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 WHERE b = 2e0); +a +2 +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 WHERE b = 2e0); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 WHERE b = 2e0); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 WHERE b = 2e0); +a +1 +3 +DROP TABLE t1; +CREATE TABLE t1 ( a char(1), b char(1)); +INSERT INTO t1 VALUES ('1','1'),('2','2'),('3','3'); +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 WHERE b = '2'); +a +3 +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 WHERE b = '2'); +a +1 +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 WHERE b = '2'); +a +2 +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 WHERE b = '2'); +a +2 +3 +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 WHERE b = '2'); +a +1 +2 +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 WHERE b = '2'); +a +1 +3 +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 WHERE b = '2'); +a +3 +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 WHERE b = '2'); +a +1 +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 WHERE b = '2'); +a +2 +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 WHERE b = '2'); +a +2 +3 +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 WHERE b = '2'); +a +1 +2 +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 WHERE b = '2'); +a +1 +3 +DROP TABLE t1; +create table t1 (a int, b int); +insert into t1 values (1,2),(3,4); +select * from t1 up where exists (select * from t1 where t1.a=up.a); +a b +1 2 +3 4 +explain extended select * from t1 up where exists (select * from t1 where t1.a=up.a); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY up ALL NULL NULL NULL NULL 2 100.00 Using where +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1276 Field or reference 'test.up.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select `test`.`up`.`a` AS `a`,`test`.`up`.`b` AS `b` from `test`.`t1` `up` where exists(select 1 AS `Not_used` from `test`.`t1` where (`test`.`t1`.`a` = `test`.`up`.`a`)) +drop table t1; +CREATE TABLE t1 (t1_a int); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (t2_a int, t2_b int, PRIMARY KEY (t2_a, t2_b)); +INSERT INTO t2 VALUES (1, 1), (1, 2); +SELECT * FROM t1, t2 table2 WHERE t1_a = 1 AND table2.t2_a = 1 +HAVING table2.t2_b = (SELECT MAX(t2_b) FROM t2 WHERE t2_a = table2.t2_a); +t1_a t2_a t2_b +1 1 2 +DROP TABLE t1, t2; +CREATE TABLE t1 (id int(11) default NULL,name varchar(10) default NULL); +INSERT INTO t1 VALUES (1,'Tim'),(2,'Rebecca'),(3,NULL); +CREATE TABLE t2 (id int(11) default NULL, pet varchar(10) default NULL); +INSERT INTO t2 VALUES (1,'Fido'),(2,'Spot'),(3,'Felix'); +SELECT a.*, b.* FROM (SELECT * FROM t1) AS a JOIN t2 as b on a.id=b.id; +id name id pet +1 Tim 1 Fido +2 Rebecca 2 Spot +3 NULL 3 Felix +drop table t1,t2; +CREATE TABLE t1 ( a int, b int ); +CREATE TABLE t2 ( c int, d int ); +INSERT INTO t1 VALUES (1,2), (2,3), (3,4); +SELECT a AS abc, b FROM t1 outr WHERE b = +(SELECT MIN(b) FROM t1 WHERE a=outr.a); +abc b +1 2 +2 3 +3 4 +INSERT INTO t2 SELECT a AS abc, b FROM t1 outr WHERE b = +(SELECT MIN(b) FROM t1 WHERE a=outr.a); +select * from t2; +c d +1 2 +2 3 +3 4 +CREATE TABLE t3 SELECT a AS abc, b FROM t1 outr WHERE b = +(SELECT MIN(b) FROM t1 WHERE a=outr.a); +select * from t3; +abc b +1 2 +2 3 +3 4 +prepare stmt1 from "INSERT INTO t2 SELECT a AS abc, b FROM t1 outr WHERE b = (SELECT MIN(b) FROM t1 WHERE a=outr.a);"; +execute stmt1; +deallocate prepare stmt1; +select * from t2; +c d +1 2 +2 3 +3 4 +1 2 +2 3 +3 4 +drop table t3; +prepare stmt1 from "CREATE TABLE t3 SELECT a AS abc, b FROM t1 outr WHERE b = (SELECT MIN(b) FROM t1 WHERE a=outr.a);"; +execute stmt1; +select * from t3; +abc b +1 2 +2 3 +3 4 +deallocate prepare stmt1; +DROP TABLE t1, t2, t3; +CREATE TABLE `t1` ( `a` int(11) default NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1; +insert into t1 values (1); +CREATE TABLE `t2` ( `b` int(11) default NULL, `a` int(11) default NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1; +insert into t2 values (1,2); +select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL (SELECT count(*) FROM t2 t001 WHERE t001.a=1); +a C +1 1 +drop table t1,t2; +create table t1 (a int not null auto_increment primary key, b varchar(40), fulltext(b)) engine=myisam; +insert into t1 (b) values ('ball'),('ball games'), ('games'), ('foo'), ('foobar'), ('Serg'), ('Sergei'),('Georg'), ('Patrik'),('Hakan'); +create table t2 (a int); +insert into t2 values (1),(3),(2),(7); +select a,b from t1 where match(b) against ('Ball') > 0; +a b +1 ball +2 ball games +select a from t2 where a in (select a from t1 where match(b) against ('Ball') > 0); +a +1 +2 +drop table t1,t2; +CREATE TABLE t1(`IZAVORGANG_ID` VARCHAR(11) CHARACTER SET latin1 COLLATE latin1_bin,`KUERZEL` VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_bin,`IZAANALYSEART_ID` VARCHAR(11) CHARACTER SET latin1 COLLATE latin1_bin,`IZAPMKZ_ID` VARCHAR(11) CHARACTER SET latin1 COLLATE latin1_bin); +CREATE INDEX AK01IZAVORGANG ON t1(izaAnalyseart_id,Kuerzel); +INSERT INTO t1(`IZAVORGANG_ID`,`KUERZEL`,`IZAANALYSEART_ID`,`IZAPMKZ_ID`)VALUES('D0000000001','601','D0000000001','I0000000001'); +INSERT INTO t1(`IZAVORGANG_ID`,`KUERZEL`,`IZAANALYSEART_ID`,`IZAPMKZ_ID`)VALUES('D0000000002','602','D0000000001','I0000000001'); +INSERT INTO t1(`IZAVORGANG_ID`,`KUERZEL`,`IZAANALYSEART_ID`,`IZAPMKZ_ID`)VALUES('D0000000003','603','D0000000001','I0000000001'); +INSERT INTO t1(`IZAVORGANG_ID`,`KUERZEL`,`IZAANALYSEART_ID`,`IZAPMKZ_ID`)VALUES('D0000000004','101','D0000000001','I0000000001'); +SELECT `IZAVORGANG_ID` FROM t1 WHERE `KUERZEL` IN(SELECT MIN(`KUERZEL`)`Feld1` FROM t1 WHERE `KUERZEL` LIKE'601%'And`IZAANALYSEART_ID`='D0000000001'); +IZAVORGANG_ID +D0000000001 +drop table t1; +CREATE TABLE `t1` ( `aid` int(11) NOT NULL default '0', `bid` int(11) NOT NULL default '0', PRIMARY KEY (`aid`,`bid`)); +CREATE TABLE `t2` ( `aid` int(11) NOT NULL default '0', `bid` int(11) NOT NULL default '0', PRIMARY KEY (`aid`,`bid`)); +insert into t1 values (1,1),(1,2),(2,1),(2,2); +insert into t2 values (1,2),(2,2); +select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid); +aid bid +1 1 +2 1 +alter table t2 drop primary key; +alter table t2 add key KEY1 (aid, bid); +select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid); +aid bid +1 1 +2 1 +alter table t2 drop key KEY1; +alter table t2 add primary key (bid, aid); +select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid); +aid bid +1 1 +2 1 +drop table t1,t2; +CREATE TABLE t1 (howmanyvalues bigint, avalue int); +INSERT INTO t1 VALUES (1, 1),(2, 1),(2, 2),(3, 1),(3, 2),(3, 3),(4, 1),(4, 2),(4, 3),(4, 4); +SELECT howmanyvalues, count(*) from t1 group by howmanyvalues; +howmanyvalues count(*) +1 1 +2 2 +3 3 +4 4 +SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues = a.howmanyvalues) as mycount from t1 a group by a.howmanyvalues; +howmanyvalues mycount +1 1 +2 2 +3 3 +4 4 +CREATE INDEX t1_howmanyvalues_idx ON t1 (howmanyvalues); +SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues+1 = a.howmanyvalues+1) as mycount from t1 a group by a.howmanyvalues; +howmanyvalues mycount +1 1 +2 2 +3 3 +4 4 +SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues = a.howmanyvalues) as mycount from t1 a group by a.howmanyvalues; +howmanyvalues mycount +1 1 +2 2 +3 3 +4 4 +SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues = a.avalue) as mycount from t1 a group by a.howmanyvalues; +howmanyvalues mycount +1 1 +2 1 +3 1 +4 1 +drop table t1; +create table t1 (x int); +select (select b.x from t1 as b where b.x=a.x) from t1 as a where a.x=2 group by a.x; +(select b.x from t1 as b where b.x=a.x) +drop table t1; +CREATE TABLE `t1` ( `master` int(10) unsigned NOT NULL default '0', `map` smallint(6) unsigned NOT NULL default '0', `slave` int(10) unsigned NOT NULL default '0', `access` int(10) unsigned NOT NULL default '0', UNIQUE KEY `access_u` (`master`,`map`,`slave`)); +INSERT INTO `t1` VALUES (1,0,0,700),(1,1,1,400),(1,5,5,400),(1,12,12,400),(1,12,32,400),(4,12,32,400); +CREATE TABLE `t2` ( `id` int(10) unsigned NOT NULL default '0', `pid` int(10) unsigned NOT NULL default '0', `map` smallint(6) unsigned NOT NULL default '0', `level` tinyint(4) unsigned NOT NULL default '0', `title` varchar(255) default NULL, PRIMARY KEY (`id`,`pid`,`map`), KEY `level` (`level`), KEY `id` (`id`,`map`)) ; +INSERT INTO `t2` VALUES (6,5,12,7,'a'),(12,0,0,7,'a'),(12,1,0,7,'a'),(12,5,5,7,'a'),(12,5,12,7,'a'); +SELECT b.sc FROM (SELECT (SELECT a.access FROM t1 a WHERE a.map = op.map AND a.slave = op.pid AND a.master = 1) ac FROM t2 op WHERE op.id = 12 AND op.map = 0) b; +ERROR 42S22: Unknown column 'b.sc' in 'field list' +SELECT b.ac FROM (SELECT (SELECT a.access FROM t1 a WHERE a.map = op.map AND a.slave = op.pid AND a.master = 1) ac FROM t2 op WHERE op.id = 12 AND op.map = 0) b; +ac +700 +NULL +drop tables t1,t2; +create table t1 (a int not null, b int not null, c int, primary key (a,b)); +insert into t1 values (1,1,1), (2,2,2), (3,3,3); +set @b:= 0; +explain select sum(a) from t1 where b > @b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 8 NULL 3 Using where; Using index +set @a:= (select sum(a) from t1 where b > @b); +explain select a from t1 where c=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +do @a:= (select sum(a) from t1 where b > @b); +explain select a from t1 where c=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +drop table t1; +set @got_val= (SELECT 1 FROM (SELECT 'A' as my_col) as T1 ) ; +create table t1 (a int, b int); +create table t2 (a int, b int); +insert into t1 values (1,1),(1,2),(1,3),(2,4),(2,5); +insert into t2 values (1,3),(2,1); +select distinct a,b, (select max(b) from t2 where t1.b=t2.a) from t1 order by t1.b; +a b (select max(b) from t2 where t1.b=t2.a) +1 1 3 +1 2 1 +1 3 NULL +2 4 NULL +2 5 NULL +drop table t1, t2; +create table t1 (id int); +create table t2 (id int, body text, fulltext (body)) engine=myisam; +insert into t1 values(1),(2),(3); +insert into t2 values (1,'test'), (2,'mysql'), (3,'test'), (4,'test'); +select count(distinct id) from t1 where id in (select id from t2 where match(body) against ('mysql' in boolean mode)); +count(distinct id) +1 +drop table t2,t1; +create table t1 (s1 int,s2 int); +insert into t1 values (20,15); +select * from t1 where (('a',null) <=> (select 'a',s2 from t1 where s1 = 0)); +s1 s2 +drop table t1; +create table t1 (s1 int); +insert into t1 values (1),(null); +select * from t1 where s1 < all (select s1 from t1); +s1 +select s1, s1 < all (select s1 from t1) from t1; +s1 s1 < all (select s1 from t1) +1 0 +NULL NULL +drop table t1; +CREATE TABLE t1 ( +Code char(3) NOT NULL default '', +Name char(52) NOT NULL default '', +Continent enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') NOT NULL default 'Asia', +Region char(26) NOT NULL default '', +SurfaceArea float(10,2) NOT NULL default '0.00', +IndepYear smallint(6) default NULL, +Population int(11) NOT NULL default '0', +LifeExpectancy float(3,1) default NULL, +GNP float(10,2) default NULL, +GNPOld float(10,2) default NULL, +LocalName char(45) NOT NULL default '', +GovernmentForm char(45) NOT NULL default '', +HeadOfState char(60) default NULL, +Capital int(11) default NULL, +Code2 char(2) NOT NULL default '' +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('XXX','Xxxxx','Oceania','Xxxxxx',26.00,0,0,0,0,0,'Xxxxx','Xxxxx','Xxxxx',NULL,'XX'); +INSERT INTO t1 VALUES ('ASM','American Samoa','Oceania','Polynesia',199.00,0,68000,75.1,334.00,NULL,'Amerika Samoa','US Territory','George W. Bush',54,'AS'); +INSERT INTO t1 VALUES ('ATF','French Southern territories','Antarctica','Antarctica',7780.00,0,0,NULL,0.00,NULL,'Terres australes françaises','Nonmetropolitan Territory of France','Jacques Chirac',NULL,'TF'); +INSERT INTO t1 VALUES ('UMI','United States Minor Outlying Islands','Oceania','Micronesia/Caribbean',16.00,0,0,NULL,0.00,NULL,'United States Minor Outlying Islands','Dependent Territory of the US','George W. Bush',NULL,'UM'); +/*!40000 ALTER TABLE t1 ENABLE KEYS */; +SELECT DISTINCT Continent AS c FROM t1 outr WHERE +Code <> SOME ( SELECT Code FROM t1 WHERE Continent = outr.Continent AND +Population < 200); +c +Oceania +drop table t1; +create table t1 (a1 int); +create table t2 (b1 int); +select * from t1 where a2 > any(select b1 from t2); +ERROR 42S22: Unknown column 'a2' in 'IN/ALL/ANY subquery' +select * from t1 where a1 > any(select b1 from t2); +a1 +drop table t1,t2; +create table t1 (a integer, b integer); +select (select * from t1) = (select 1,2); +(select * from t1) = (select 1,2) +NULL +select (select 1,2) = (select * from t1); +(select 1,2) = (select * from t1) +NULL +select row(1,2) = ANY (select * from t1); +row(1,2) = ANY (select * from t1) +0 +select row(1,2) != ALL (select * from t1); +row(1,2) != ALL (select * from t1) +1 +drop table t1; +create table t1 (a integer, b integer); +select row(1,(2,2)) in (select * from t1 ); +ERROR 21000: Operand should contain 2 column(s) +select row(1,(2,2)) = (select * from t1 ); +ERROR 21000: Operand should contain 2 column(s) +select (select * from t1) = row(1,(2,2)); +ERROR 21000: Operand should contain 1 column(s) +drop table t1; +create table t1 (a integer); +insert into t1 values (1); +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx ; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 as xx, 1 = ALL ( select 1 from t1 where 1 = xx ); +xx 1 = ALL ( select 1 from t1 where 1 = xx ) +1 1 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx from DUAL; +ERROR 42S22: Reference 'xx' not supported (forward reference in item list) +drop table t1; +CREATE TABLE t1 ( +categoryId int(11) NOT NULL, +courseId int(11) NOT NULL, +startDate datetime NOT NULL, +endDate datetime NOT NULL, +createDate datetime NOT NULL, +modifyDate timestamp NOT NULL, +attributes text NOT NULL +); +INSERT INTO t1 VALUES (1,41,'2004-02-09','2010-01-01','2004-02-09','2004-02-09',''), +(1,86,'2004-08-16','2004-08-16','2004-08-16','2004-08-16',''), +(1,87,'2004-08-16','2004-08-16','2004-08-16','2004-08-16',''), +(2,52,'2004-03-15','2004-10-01','2004-03-15','2004-09-17',''), +(2,53,'2004-03-16','2004-10-01','2004-03-16','2004-09-17',''), +(2,88,'2004-08-16','2004-08-16','2004-08-16','2004-08-16',''), +(2,89,'2004-08-16','2004-08-16','2004-08-16','2004-08-16',''), +(3,51,'2004-02-09','2010-01-01','2004-02-09','2004-02-09',''), +(5,12,'2004-02-18','2010-01-01','2004-02-18','2004-02-18',''); +CREATE TABLE t2 ( +userId int(11) NOT NULL, +courseId int(11) NOT NULL, +date datetime NOT NULL +); +INSERT INTO t2 VALUES (5141,71,'2003-11-18'), +(5141,72,'2003-11-25'),(5141,41,'2004-08-06'), +(5141,52,'2004-08-06'),(5141,53,'2004-08-06'), +(5141,12,'2004-08-06'),(5141,86,'2004-10-21'), +(5141,87,'2004-10-21'),(5141,88,'2004-10-21'), +(5141,89,'2004-10-22'),(5141,51,'2004-10-26'); +CREATE TABLE t3 ( +groupId int(11) NOT NULL, +parentId int(11) NOT NULL, +startDate datetime NOT NULL, +endDate datetime NOT NULL, +createDate datetime NOT NULL, +modifyDate timestamp NOT NULL, +ordering int(11) +); +INSERT INTO t3 VALUES (12,9,'1000-01-01','3999-12-31','2004-01-29','2004-01-29',NULL); +CREATE TABLE t4 ( +id int(11) NOT NULL, +groupTypeId int(11) NOT NULL, +groupKey varchar(50) NOT NULL, +name text, +ordering int(11), +description text, +createDate datetime NOT NULL, +modifyDate timestamp NOT NULL +); +INSERT INTO t4 VALUES (9,5,'stationer','stationer',0,'Stationer','2004-01-29','2004-01-29'), +(12,5,'group2','group2',0,'group2','2004-01-29','2004-01-29'); +CREATE TABLE t5 ( +userId int(11) NOT NULL, +groupId int(11) NOT NULL, +createDate datetime NOT NULL, +modifyDate timestamp NOT NULL +); +INSERT INTO t5 VALUES (5141,12,'2004-08-06','2004-08-06'); +select +count(distinct t2.userid) pass, +groupstuff.*, +count(t2.courseid) crse, +t1.categoryid, +t2.courseid, +date_format(date, '%b%y') as colhead +from t2 +join t1 on t2.courseid=t1.courseid +join +( +select +t5.userid, +parentid, +parentgroup, +childid, +groupname, +grouptypeid +from t5 +join +( +select t4.id as parentid, +t4.name as parentgroup, +t4.id as childid, +t4.name as groupname, +t4.grouptypeid +from t4 +) as gin on t5.groupid=gin.childid +) as groupstuff on t2.userid = groupstuff.userid +group by +groupstuff.groupname, colhead , t2.courseid; +pass userid parentid parentgroup childid groupname grouptypeid crse categoryid courseid colhead +1 5141 12 group2 12 group2 5 1 5 12 Aug04 +1 5141 12 group2 12 group2 5 1 1 41 Aug04 +1 5141 12 group2 12 group2 5 1 2 52 Aug04 +1 5141 12 group2 12 group2 5 1 2 53 Aug04 +1 5141 12 group2 12 group2 5 1 3 51 Oct04 +1 5141 12 group2 12 group2 5 1 1 86 Oct04 +1 5141 12 group2 12 group2 5 1 1 87 Oct04 +1 5141 12 group2 12 group2 5 1 2 88 Oct04 +1 5141 12 group2 12 group2 5 1 2 89 Oct04 +drop table t1, t2, t3, t4, t5; +create table t1 (a int); +insert into t1 values (1), (2), (3); +SELECT 1 FROM t1 WHERE (SELECT 1) in (SELECT 1); +1 +1 +1 +1 +drop table t1; +create table t1 (a int); +create table t2 (a int); +insert into t1 values (1),(2); +insert into t2 values (0),(1),(2),(3); +select a from t2 where a in (select a from t1); +a +1 +2 +select a from t2 having a in (select a from t1); +a +1 +2 +prepare stmt1 from "select a from t2 where a in (select a from t1)"; +execute stmt1; +a +1 +2 +execute stmt1; +a +1 +2 +deallocate prepare stmt1; +prepare stmt1 from "select a from t2 having a in (select a from t1)"; +execute stmt1; +a +1 +2 +execute stmt1; +a +1 +2 +deallocate prepare stmt1; +drop table t1, t2; +create table t1 (a int, b int); +insert into t1 values (1,2); +select 1 = (select * from t1); +ERROR 21000: Operand should contain 1 column(s) +select (select * from t1) = 1; +ERROR 21000: Operand should contain 2 column(s) +select (1,2) = (select a from t1); +ERROR 21000: Operand should contain 2 column(s) +select (select a from t1) = (1,2); +ERROR 21000: Operand should contain 1 column(s) +select (1,2,3) = (select * from t1); +ERROR 21000: Operand should contain 3 column(s) +select (select * from t1) = (1,2,3); +ERROR 21000: Operand should contain 2 column(s) +drop table t1; +CREATE TABLE `t1` ( +`itemid` bigint(20) unsigned NOT NULL auto_increment, +`sessionid` bigint(20) unsigned default NULL, +`time` int(10) unsigned NOT NULL default '0', +`type` set('A','D','E','F','G','I','L','N','U') collate latin1_general_ci NOT +NULL default '', +`data` text collate latin1_general_ci NOT NULL, +PRIMARY KEY (`itemid`) +) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +INSERT INTO `t1` VALUES (1, 1, 1, 'D', ''); +CREATE TABLE `t2` ( +`sessionid` bigint(20) unsigned NOT NULL auto_increment, +`pid` int(10) unsigned NOT NULL default '0', +`date` int(10) unsigned NOT NULL default '0', +`ip` varchar(15) collate latin1_general_ci NOT NULL default '', +PRIMARY KEY (`sessionid`) +) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +INSERT INTO `t2` VALUES (1, 1, 1, '10.10.10.1'); +SELECT s.ip, count( e.itemid ) FROM `t1` e JOIN t2 s ON s.sessionid = e.sessionid WHERE e.sessionid = ( SELECT sessionid FROM t2 ORDER BY sessionid DESC LIMIT 1 ) GROUP BY s.ip HAVING count( e.itemid ) >0 LIMIT 0 , 30; +ip count( e.itemid ) +10.10.10.1 1 +drop tables t1,t2; +create table t1 (fld enum('0','1')); +insert into t1 values ('1'); +select * from (select max(fld) from t1) as foo; +max(fld) +1 +drop table t1; +CREATE TABLE t1 (one int, two int, flag char(1)); +CREATE TABLE t2 (one int, two int, flag char(1)); +INSERT INTO t1 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); +INSERT INTO t2 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); +SELECT * FROM t1 +WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t2 WHERE flag = 'N'); +one two flag +5 6 N +7 8 N +SELECT * FROM t1 +WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); +one two flag +5 6 N +7 8 N +insert into t2 values (null,null,'N'); +insert into t2 values (null,3,'0'); +insert into t2 values (null,5,'0'); +insert into t2 values (10,null,'0'); +insert into t1 values (10,3,'0'); +insert into t1 values (10,5,'0'); +insert into t1 values (10,10,'0'); +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1; +one two test +1 2 NULL +2 3 NULL +3 4 NULL +5 6 1 +7 8 1 +10 3 NULL +10 5 NULL +10 10 NULL +SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); +one two +5 6 +7 8 +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1; +one two test +1 2 NULL +2 3 NULL +3 4 NULL +5 6 1 +7 8 1 +10 3 NULL +10 5 NULL +10 10 NULL +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; +one two test +1 2 0 +2 3 NULL +3 4 0 +5 6 0 +7 8 0 +10 3 NULL +10 5 NULL +10 10 NULL +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; +one two test +1 2 0 +2 3 NULL +3 4 0 +5 6 0 +7 8 0 +10 3 NULL +10 5 NULL +10 10 NULL +explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond(((<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond(((<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond(<is_not_null_test>(`test`.`t2`.`one`)) and trigcond(<is_not_null_test>(`test`.`t2`.`two`))))) AS `test` from `test`.`t1` +explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = 'N') and (<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) and (<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`)))) +explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 8 100.00 +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 9 100.00 Using where; Using temporary; Using filesort +Warnings: +Note 1003 select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where (`test`.`t2`.`flag` = '0') group by `test`.`t2`.`one`,`test`.`t2`.`two` having (trigcond(((<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond(((<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`))) and trigcond(<is_not_null_test>(`test`.`t2`.`one`)) and trigcond(<is_not_null_test>(`test`.`t2`.`two`))))) AS `test` from `test`.`t1` +DROP TABLE t1,t2; +CREATE TABLE t1 (a char(5), b char(5)); +INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa'); +SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb')); +a b +aaa aaa +DROP TABLE t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int, b int); +CREATE TABLE t3 (b int NOT NULL); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (1,10), (3,30); +SELECT * FROM t2 LEFT JOIN t3 ON t2.b=t3.b +WHERE t3.b IS NOT NULL OR t2.a > 10; +a b b +SELECT * FROM t1 +WHERE t1.a NOT IN (SELECT a FROM t2 LEFT JOIN t3 ON t2.b=t3.b +WHERE t3.b IS NOT NULL OR t2.a > 10); +a +1 +2 +3 +4 +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (f1 INT); +CREATE TABLE t2 (f2 INT); +INSERT INTO t1 VALUES (1); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2); +f1 +1 +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2 WHERE 1=0); +f1 +1 +INSERT INTO t2 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2 WHERE f2=0); +f1 +1 +DROP TABLE t1, t2; +select 1 from dual where 1 < any (select 2); +1 +1 +select 1 from dual where 1 < all (select 2); +1 +1 +select 1 from dual where 2 > any (select 1); +1 +1 +select 1 from dual where 2 > all (select 1); +1 +1 +select 1 from dual where 1 < any (select 2 from dual); +1 +1 +select 1 from dual where 1 < all (select 2 from dual where 1!=1); +1 +1 +create table t1 (s1 char); +insert into t1 values (1),(2); +select * from t1 where (s1 < any (select s1 from t1)); +s1 +1 +select * from t1 where not (s1 < any (select s1 from t1)); +s1 +2 +select * from t1 where (s1 < ALL (select s1+1 from t1)); +s1 +1 +select * from t1 where not(s1 < ALL (select s1+1 from t1)); +s1 +2 +select * from t1 where (s1+1 = ANY (select s1 from t1)); +s1 +1 +select * from t1 where NOT(s1+1 = ANY (select s1 from t1)); +s1 +2 +select * from t1 where (s1 = ALL (select s1/s1 from t1)); +s1 +1 +select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); +s1 +2 +drop table t1; +create table t1 ( +retailerID varchar(8) NOT NULL, +statusID int(10) unsigned NOT NULL, +changed datetime NOT NULL, +UNIQUE KEY retailerID (retailerID, statusID, changed) +); +INSERT INTO t1 VALUES("0026", "1", "2005-12-06 12:18:56"); +INSERT INTO t1 VALUES("0026", "2", "2006-01-06 12:25:53"); +INSERT INTO t1 VALUES("0037", "1", "2005-12-06 12:18:56"); +INSERT INTO t1 VALUES("0037", "2", "2006-01-06 12:25:53"); +INSERT INTO t1 VALUES("0048", "1", "2006-01-06 12:37:50"); +INSERT INTO t1 VALUES("0059", "1", "2006-01-06 12:37:50"); +select * from t1 r1 +where (r1.retailerID,(r1.changed)) in +(SELECT r2.retailerId,(max(changed)) from t1 r2 +group by r2.retailerId); +retailerID statusID changed +0026 2 2006-01-06 12:25:53 +0037 2 2006-01-06 12:25:53 +0048 1 2006-01-06 12:37:50 +0059 1 2006-01-06 12:37:50 +drop table t1; +create table t1(a int, primary key (a)); +insert into t1 values (10); +create table t2 (a int primary key, b varchar(32), c int, unique key b(c, b)); +insert into t2(a, c, b) values (1,10,'359'), (2,10,'35988'), (3,10,'35989'); +explain SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r +ON r.a = (SELECT t2.a FROM t2 WHERE t2.c = t1.a AND t2.b <= '359899' +ORDER BY t2.c DESC, t2.b DESC LIMIT 1) WHERE t1.a = 10; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 Using index +1 PRIMARY r const PRIMARY PRIMARY 4 const 1 +2 DEPENDENT SUBQUERY t2 range b b 40 NULL 1 Using where +SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r +ON r.a = (SELECT t2.a FROM t2 WHERE t2.c = t1.a AND t2.b <= '359899' +ORDER BY t2.c DESC, t2.b DESC LIMIT 1) WHERE t1.a = 10; +a a b +10 3 35989 +explain SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r +ON r.a = (SELECT t2.a FROM t2 WHERE t2.c = t1.a AND t2.b <= '359899' +ORDER BY t2.c, t2.b LIMIT 1) WHERE t1.a = 10; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 Using index +1 PRIMARY r const PRIMARY PRIMARY 4 const 1 +2 DEPENDENT SUBQUERY t2 range b b 40 NULL 1 Using where +SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r +ON r.a = (SELECT t2.a FROM t2 WHERE t2.c = t1.a AND t2.b <= '359899' +ORDER BY t2.c, t2.b LIMIT 1) WHERE t1.a = 10; +a a b +10 1 359 +drop table t1,t2; +CREATE TABLE t1 ( +field1 int NOT NULL, +field2 int NOT NULL, +field3 int NOT NULL, +PRIMARY KEY (field1,field2,field3) +); +CREATE TABLE t2 ( +fieldA int NOT NULL, +fieldB int NOT NULL, +PRIMARY KEY (fieldA,fieldB) +); +INSERT INTO t1 VALUES +(1,1,1), (1,1,2), (1,2,1), (1,2,2), (1,2,3), (1,3,1); +INSERT INTO t2 VALUES (1,1), (1,2), (1,3); +SELECT field1, field2, COUNT(*) +FROM t1 GROUP BY field1, field2; +field1 field2 COUNT(*) +1 1 2 +1 2 3 +1 3 1 +SELECT field1, field2 +FROM t1 +GROUP BY field1, field2 +HAVING COUNT(*) >= ALL (SELECT fieldB +FROM t2 WHERE fieldA = field1); +field1 field2 +1 2 +SELECT field1, field2 +FROM t1 +GROUP BY field1, field2 +HAVING COUNT(*) < ANY (SELECT fieldB +FROM t2 WHERE fieldA = field1); +field1 field2 +1 1 +1 3 +DROP TABLE t1, t2; +CREATE TABLE t1(a int, INDEX (a)); +INSERT INTO t1 VALUES (1), (3), (5), (7); +INSERT INTO t1 VALUES (NULL); +CREATE TABLE t2(a int); +INSERT INTO t2 VALUES (1),(2),(3); +EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 +2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 2 Using index; Full scan on NULL key +SELECT a, a IN (SELECT a FROM t1) FROM t2; +a a IN (SELECT a FROM t1) +1 1 +2 NULL +3 1 +DROP TABLE t1,t2; +CREATE TABLE t1 (a DATETIME); +INSERT INTO t1 VALUES ('1998-09-23'), ('2003-03-25'); +CREATE TABLE t2 AS SELECT +(SELECT a FROM t1 WHERE a < '2000-01-01') AS sub_a +FROM t1 WHERE a > '2000-01-01'; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `sub_a` datetime DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +CREATE TABLE t3 AS (SELECT a FROM t1 WHERE a < '2000-01-01') UNION (SELECT a FROM t1 WHERE a > '2000-01-01'); +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` datetime DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); +SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) > 0; +a +SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL; +a +1 +2 +EXPLAIN SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +DROP TABLE t1; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (2), (4), (1), (3); +CREATE TABLE t2 (b int, c int); +INSERT INTO t2 VALUES +(2,1), (1,3), (2,1), (4,4), (2,2), (1,4); +SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2 ); +a +2 +4 +1 +3 +SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1); +ERROR 21000: Subquery returns more than 1 row +SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2), a; +a +1 +2 +3 +4 +SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1), a; +ERROR 21000: Subquery returns more than 1 row +SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 2); +b MAX(c) +1 4 +2 2 +4 4 +SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 1); +ERROR 21000: Subquery returns more than 1 row +SELECT a FROM t1 GROUP BY a +HAVING IFNULL((SELECT b FROM t2 WHERE b > 2), +(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3; +a +1 +2 +3 +4 +SELECT a FROM t1 GROUP BY a +HAVING IFNULL((SELECT b FROM t2 WHERE b > 1), +(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3; +ERROR 21000: Subquery returns more than 1 row +SELECT a FROM t1 GROUP BY a +HAVING IFNULL((SELECT b FROM t2 WHERE b > 4), +(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3; +a +4 +SELECT a FROM t1 GROUP BY a +HAVING IFNULL((SELECT b FROM t2 WHERE b > 4), +(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)) > 3; +ERROR 21000: Subquery returns more than 1 row +SELECT a FROM t1 +ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 2), +(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)); +a +2 +4 +1 +3 +SELECT a FROM t1 +ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 1), +(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)); +ERROR 21000: Subquery returns more than 1 row +SELECT a FROM t1 +ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4), +(SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)); +a +2 +1 +3 +4 +SELECT a FROM t1 +ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4), +(SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)); +ERROR 21000: Subquery returns more than 1 row +DROP TABLE t1,t2; +create table t1 (df decimal(5,1)); +insert into t1 values(1.1); +insert into t1 values(2.2); +select * from t1 where df <= all (select avg(df) from t1 group by df); +df +1.1 +select * from t1 where df >= all (select avg(df) from t1 group by df); +df +2.2 +drop table t1; +create table t1 (df decimal(5,1)); +insert into t1 values(1.1); +select 1.1 * exists(select * from t1); +1.1 * exists(select * from t1) +1.1 +drop table t1; +CREATE TABLE t1 ( +grp int(11) default NULL, +a decimal(10,2) default NULL); +insert into t1 values (1, 1), (2, 2), (2, 3), (3, 4), (3, 5), (3, 6), (NULL, NULL); +select * from t1; +grp a +1 1.00 +2 2.00 +2 3.00 +3 4.00 +3 5.00 +3 6.00 +NULL NULL +select min(a) from t1 group by grp; +min(a) +NULL +1.00 +2.00 +4.00 +drop table t1; +CREATE table t1 ( c1 integer ); +INSERT INTO t1 VALUES ( 1 ); +INSERT INTO t1 VALUES ( 2 ); +INSERT INTO t1 VALUES ( 3 ); +CREATE TABLE t2 ( c2 integer ); +INSERT INTO t2 VALUES ( 1 ); +INSERT INTO t2 VALUES ( 4 ); +INSERT INTO t2 VALUES ( 5 ); +SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2 WHERE c2 IN (1); +c1 c2 +1 1 +SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2 +WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2 IN ( 1 ) ); +c1 c2 +1 1 +DROP TABLE t1,t2; +CREATE TABLE t1 ( c1 integer ); +INSERT INTO t1 VALUES ( 1 ); +INSERT INTO t1 VALUES ( 2 ); +INSERT INTO t1 VALUES ( 3 ); +INSERT INTO t1 VALUES ( 6 ); +CREATE TABLE t2 ( c2 integer ); +INSERT INTO t2 VALUES ( 1 ); +INSERT INTO t2 VALUES ( 4 ); +INSERT INTO t2 VALUES ( 5 ); +INSERT INTO t2 VALUES ( 6 ); +CREATE TABLE t3 ( c3 integer ); +INSERT INTO t3 VALUES ( 7 ); +INSERT INTO t3 VALUES ( 8 ); +SELECT c1,c2 FROM t1 LEFT JOIN t2 ON c1 = c2 +WHERE EXISTS (SELECT c3 FROM t3 WHERE c2 IS NULL ); +c1 c2 +2 NULL +3 NULL +DROP TABLE t1,t2,t3; +CREATE TABLE `t1` ( +`itemid` bigint(20) unsigned NOT NULL auto_increment, +`sessionid` bigint(20) unsigned default NULL, +`time` int(10) unsigned NOT NULL default '0', +`type` set('A','D','E','F','G','I','L','N','U') collate latin1_general_ci NOT +NULL default '', +`data` text collate latin1_general_ci NOT NULL, +PRIMARY KEY (`itemid`) +) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +INSERT INTO `t1` VALUES (1, 1, 1, 'D', ''); +CREATE TABLE `t2` ( +`sessionid` bigint(20) unsigned NOT NULL auto_increment, +`pid` int(10) unsigned NOT NULL default '0', +`date` int(10) unsigned NOT NULL default '0', +`ip` varchar(15) collate latin1_general_ci NOT NULL default '', +PRIMARY KEY (`sessionid`) +) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +INSERT INTO `t2` VALUES (1, 1, 1, '10.10.10.1'); +SELECT s.ip, count( e.itemid ) FROM `t1` e JOIN t2 s ON s.sessionid = e.sessionid WHERE e.sessionid = ( SELECT sessionid FROM t2 ORDER BY sessionid DESC LIMIT 1 ) GROUP BY s.ip HAVING count( e.itemid ) >0 LIMIT 0 , 30; +ip count( e.itemid ) +10.10.10.1 1 +drop tables t1,t2; +CREATE TABLE t1 (EMPNUM CHAR(3)); +CREATE TABLE t2 (EMPNUM CHAR(3) ); +INSERT INTO t1 VALUES ('E1'),('E2'); +INSERT INTO t2 VALUES ('E1'); +DELETE FROM t1 +WHERE t1.EMPNUM NOT IN +(SELECT t2.EMPNUM +FROM t2 +WHERE t1.EMPNUM = t2.EMPNUM); +select * from t1; +EMPNUM +E1 +DROP TABLE t1,t2; +CREATE TABLE t1(select_id BIGINT, values_id BIGINT); +INSERT INTO t1 VALUES (1, 1); +CREATE TABLE t2 (select_id BIGINT, values_id BIGINT, +PRIMARY KEY(select_id,values_id)); +INSERT INTO t2 VALUES (0, 1), (0, 2), (0, 3), (1, 5); +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 +WHERE select_id IN (1, 0)); +values_id +1 +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 +WHERE select_id BETWEEN 0 AND 1); +values_id +1 +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 +WHERE select_id = 0 OR select_id = 1); +values_id +1 +DROP TABLE t1, t2; +create table t1 (fld enum('0','1')); +insert into t1 values ('1'); +select * from (select max(fld) from t1) as foo; +max(fld) +1 +drop table t1; +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (c int, d int); +CREATE TABLE t3 (e int); +INSERT INTO t1 VALUES +(1,10), (2,10), (1,20), (2,20), (3,20), (2,30), (4,40); +INSERT INTO t2 VALUES +(2,10), (2,20), (4,10), (5,10), (3,20), (2,40); +INSERT INTO t3 VALUES (10), (30), (10), (20) ; +SELECT a, MAX(b), MIN(b) FROM t1 GROUP BY a; +a MAX(b) MIN(b) +1 20 10 +2 30 10 +3 20 20 +4 40 40 +SELECT * FROM t2; +c d +2 10 +2 20 +4 10 +5 10 +3 20 +2 40 +SELECT * FROM t3; +e +10 +30 +10 +20 +SELECT a FROM t1 GROUP BY a +HAVING a IN (SELECT c FROM t2 WHERE MAX(b)>20); +a +2 +4 +SELECT a FROM t1 GROUP BY a +HAVING a IN (SELECT c FROM t2 WHERE MAX(b)<d); +a +2 +SELECT a FROM t1 GROUP BY a +HAVING a IN (SELECT c FROM t2 WHERE MAX(b)>d); +a +2 +4 +SELECT a FROM t1 GROUP BY a +HAVING a IN (SELECT c FROM t2 +WHERE d >= SOME(SELECT e FROM t3 WHERE MAX(b)=e)); +a +2 +3 +SELECT a FROM t1 GROUP BY a +HAVING a IN (SELECT c FROM t2 +WHERE EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e <= d)); +a +2 +3 +SELECT a FROM t1 GROUP BY a +HAVING a IN (SELECT c FROM t2 +WHERE d > SOME(SELECT e FROM t3 WHERE MAX(b)=e)); +a +2 +SELECT a FROM t1 GROUP BY a +HAVING a IN (SELECT c FROM t2 +WHERE EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e < d)); +a +2 +SELECT a FROM t1 GROUP BY a +HAVING a IN (SELECT c FROM t2 +WHERE MIN(b) < d AND +EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e <= d)); +a +2 +SELECT a, SUM(a) FROM t1 GROUP BY a; +a SUM(a) +1 2 +2 6 +3 3 +4 4 +SELECT a FROM t1 +WHERE EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) = c) GROUP BY a; +a +3 +4 +SELECT a FROM t1 GROUP BY a +HAVING EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) = c); +a +1 +3 +4 +SELECT a FROM t1 +WHERE a < 3 AND +EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) != c) GROUP BY a; +a +1 +2 +SELECT a FROM t1 +WHERE a < 3 AND +EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) != c); +a +1 +2 +1 +2 +2 +SELECT t1.a FROM t1 GROUP BY t1.a +HAVING t1.a < ALL(SELECT t2.c FROM t2 GROUP BY t2.c +HAVING EXISTS(SELECT t3.e FROM t3 GROUP BY t3.e +HAVING SUM(t1.a+t2.c) < t3.e/4)); +a +1 +2 +SELECT t1.a FROM t1 GROUP BY t1.a +HAVING t1.a > ALL(SELECT t2.c FROM t2 +WHERE EXISTS(SELECT t3.e FROM t3 GROUP BY t3.e +HAVING SUM(t1.a+t2.c) < t3.e/4)); +a +4 +SELECT t1.a FROM t1 GROUP BY t1.a +HAVING t1.a > ALL(SELECT t2.c FROM t2 +WHERE EXISTS(SELECT t3.e FROM t3 +WHERE SUM(t1.a+t2.c) < t3.e/4)); +ERROR HY000: Invalid use of group function +SELECT t1.a from t1 GROUP BY t1.a HAVING AVG(SUM(t1.b)) > 20; +ERROR HY000: Invalid use of group function +SELECT t1.a FROM t1 GROUP BY t1.a +HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c +HAVING AVG(t2.c+SUM(t1.b)) > 20); +a +2 +3 +4 +SELECT t1.a FROM t1 GROUP BY t1.a +HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c +HAVING AVG(SUM(t1.b)) > 20); +a +2 +4 +SELECT t1.a, SUM(b) AS sum FROM t1 GROUP BY t1.a +HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c +HAVING t2.c+sum > 20); +a sum +2 60 +3 20 +4 40 +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (a varchar(5), b varchar(10)); +INSERT INTO t1 VALUES +('AAA', 5), ('BBB', 4), ('BBB', 1), ('CCC', 2), +('CCC', 7), ('AAA', 2), ('AAA', 4), ('BBB', 3), ('AAA', 8); +SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); +a b +BBB 4 +CCC 7 +AAA 8 +EXPLAIN +SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 9 Using where +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 9 Using temporary; Using filesort +ALTER TABLE t1 ADD INDEX(a); +SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); +a b +BBB 4 +CCC 7 +AAA 8 +EXPLAIN +SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 9 Using where +2 DEPENDENT SUBQUERY t1 index NULL a 8 NULL 1 Using filesort +DROP TABLE t1; +create table t1( f1 int,f2 int); +insert into t1 values (1,1),(2,2); +select tt.t from (select 'crash1' as t, f2 from t1) as tt left join t1 on tt.t = 'crash2' and tt.f2 = t1.f2 where tt.t = 'crash1'; +t +crash1 +crash1 +drop table t1; +create table t1 (c int, key(c)); +insert into t1 values (1142477582), (1142455969); +create table t2 (a int, b int); +insert into t2 values (2, 1), (1, 0); +delete from t1 where c <= 1140006215 and (select b from t2 where a = 2) = 1; +drop table t1, t2; +CREATE TABLE t1 (a INT); +CREATE VIEW v1 AS SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'where clause' +CREATE VIEW v2 AS SELECT * FROM t1 WHERE no_such_column = (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'where clause' +SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'IN/ALL/ANY subquery' +DROP TABLE t1; +create table t1 (i int, j bigint); +insert into t1 values (1, 2), (2, 2), (3, 2); +select * from (select min(i) from t1 where j=(select * from (select min(j) from t1) t2)) t3; +min(i) +1 +drop table t1; +CREATE TABLE t1 (i BIGINT UNSIGNED); +INSERT INTO t1 VALUES (10000000000000000000); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (i BIGINT UNSIGNED); +INSERT INTO t2 VALUES (10000000000000000000); +INSERT INTO t2 VALUES (1); +/* simple test */ +SELECT t1.i FROM t1 JOIN t2 ON t1.i = t2.i; +i +10000000000000000000 +1 +/* subquery test */ +SELECT t1.i FROM t1 WHERE t1.i = (SELECT MAX(i) FROM t2); +i +10000000000000000000 +/* subquery test with cast*/ +SELECT t1.i FROM t1 WHERE t1.i = CAST((SELECT MAX(i) FROM t2) AS UNSIGNED); +i +10000000000000000000 +DROP TABLE t1; +DROP TABLE t2; +CREATE TABLE t1 ( +id bigint(20) unsigned NOT NULL auto_increment, +name varchar(255) NOT NULL, +PRIMARY KEY (id) +); +INSERT INTO t1 VALUES +(1, 'Balazs'), (2, 'Joe'), (3, 'Frank'); +CREATE TABLE t2 ( +id bigint(20) unsigned NOT NULL auto_increment, +mid bigint(20) unsigned NOT NULL, +date date NOT NULL, +PRIMARY KEY (id) +); +INSERT INTO t2 VALUES +(1, 1, '2006-03-30'), (2, 2, '2006-04-06'), (3, 3, '2006-04-13'), +(4, 2, '2006-04-20'), (5, 1, '2006-05-01'); +SELECT *, +(SELECT date FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 0, 1) AS date_last, +(SELECT date FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 3, 1) AS date_next_to_last +FROM t1; +id name date_last date_next_to_last +1 Balazs 2006-05-01 NULL +2 Joe 2006-04-20 NULL +3 Frank 2006-04-13 NULL +SELECT *, +(SELECT COUNT(*) FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 1, 1) AS date_count +FROM t1; +id name date_count +1 Balazs NULL +2 Joe NULL +3 Frank NULL +SELECT *, +(SELECT date FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 0, 1) AS date_last, +(SELECT date FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 1, 1) AS date_next_to_last +FROM t1; +id name date_last date_next_to_last +1 Balazs 2006-05-01 2006-03-30 +2 Joe 2006-04-20 2006-04-06 +3 Frank 2006-04-13 NULL +DROP TABLE t1,t2; +CREATE TABLE t1 ( +i1 int(11) NOT NULL default '0', +i2 int(11) NOT NULL default '0', +t datetime NOT NULL default '0000-00-00 00:00:00', +PRIMARY KEY (i1,i2,t) +); +INSERT INTO t1 VALUES +(24,1,'2005-03-03 16:31:31'),(24,1,'2005-05-27 12:40:07'), +(24,1,'2005-05-27 12:40:08'),(24,1,'2005-05-27 12:40:10'), +(24,1,'2005-05-27 12:40:25'),(24,1,'2005-05-27 12:40:30'), +(24,2,'2005-03-03 13:43:05'),(24,2,'2005-03-03 16:23:31'), +(24,2,'2005-03-03 16:31:30'),(24,2,'2005-05-27 12:37:02'), +(24,2,'2005-05-27 12:40:06'); +CREATE TABLE t2 ( +i1 int(11) NOT NULL default '0', +i2 int(11) NOT NULL default '0', +t datetime default NULL, +PRIMARY KEY (i1) +); +INSERT INTO t2 VALUES (24,1,'2006-06-20 12:29:40'); +EXPLAIN +SELECT * FROM t1,t2 +WHERE t1.t = (SELECT t1.t FROM t1 +WHERE t1.t < t2.t AND t1.i2=1 AND t2.i1=t1.i1 +ORDER BY t1.t DESC LIMIT 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 1 +1 PRIMARY t1 index NULL PRIMARY 16 NULL 11 Using where; Using index; Using join buffer +2 DEPENDENT SUBQUERY t1 ref PRIMARY PRIMARY 8 test.t2.i1,const 2 Using where; Using index; Using filesort +SELECT * FROM t1,t2 +WHERE t1.t = (SELECT t1.t FROM t1 +WHERE t1.t < t2.t AND t1.i2=1 AND t2.i1=t1.i1 +ORDER BY t1.t DESC LIMIT 1); +i1 i2 t i1 i2 t +24 1 2005-05-27 12:40:30 24 1 2006-06-20 12:29:40 +DROP TABLE t1, t2; +CREATE TABLE t1 (i INT); +(SELECT i FROM t1) UNION (SELECT i FROM t1); +i +SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS +( +(SELECT i FROM t1) UNION +(SELECT i FROM t1) +); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION +(SELECT i FROM t1) +)' at line 3 +SELECT * FROM t1 +WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1))); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION (SELECT i FROM t1)))' at line 2 +explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) +from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'union (select t12.i from t1 t12)) +from t1' at line 1 +explain select * from t1 where not exists +((select t11.i from t1 t11) union (select t12.i from t1 t12)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'union (select t12.i from t1 t12))' at line 2 +DROP TABLE t1; +CREATE TABLE t1 (a VARCHAR(250), b INT auto_increment, PRIMARY KEY (b)); +insert into t1 (a) values (FLOOR(rand() * 100)); +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +SELECT a, +(SELECT REPEAT(' ',250) FROM t1 i1 +WHERE i1.b=t1.a ORDER BY RAND() LIMIT 1) AS a +FROM t1 ORDER BY a LIMIT 5; +a a +0 NULL +0 NULL +0 NULL +0 NULL +0 NULL +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT); +CREATE TABLE t2 (a INT); +INSERT INTO t2 values (1); +INSERT INTO t1 VALUES (1,1),(1,2),(2,3),(3,4); +SELECT (SELECT COUNT(DISTINCT t1.b) from t2) FROM t1 GROUP BY t1.a; +(SELECT COUNT(DISTINCT t1.b) from t2) +2 +1 +1 +SELECT (SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3) +FROM t1 GROUP BY t1.a; +(SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3) +2 +1 +1 +SELECT COUNT(DISTINCT t1.b), (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a; +COUNT(DISTINCT t1.b) (SELECT COUNT(DISTINCT t1.b)) +2 2 +1 1 +1 1 +SELECT COUNT(DISTINCT t1.b), +(SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3) +FROM t1 GROUP BY t1.a; +COUNT(DISTINCT t1.b) (SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3) +2 2 +1 1 +1 1 +SELECT ( +SELECT ( +SELECT COUNT(DISTINCT t1.b) +) +) +FROM t1 GROUP BY t1.a; +( +SELECT ( +SELECT COUNT(DISTINCT t1.b) +) +) +2 +1 +1 +SELECT ( +SELECT ( +SELECT ( +SELECT COUNT(DISTINCT t1.b) +) +) +FROM t1 GROUP BY t1.a LIMIT 1) +FROM t1 t2 +GROUP BY t2.a; +( +SELECT ( +SELECT ( +SELECT COUNT(DISTINCT t1.b) +) +) +FROM t1 GROUP BY t1.a LIMIT 1) +2 +2 +2 +DROP TABLE t1,t2; +CREATE TABLE t1 (a int, b int auto_increment, PRIMARY KEY (b)); +CREATE TABLE t2 (x int auto_increment, y int, z int, +PRIMARY KEY (x), FOREIGN KEY (y) REFERENCES t1 (b)); +SET SESSION sort_buffer_size = 32 * 1024; +Warnings: +Warning 1292 Truncated incorrect sort_buffer_size value: '32768' +SELECT SQL_NO_CACHE COUNT(*) +FROM (SELECT a, b, (SELECT x FROM t2 WHERE y=b ORDER BY z DESC LIMIT 1) c +FROM t1) t; +COUNT(*) +3000 +SET SESSION sort_buffer_size = 8 * 1024 * 1024; +SELECT SQL_NO_CACHE COUNT(*) +FROM (SELECT a, b, (SELECT x FROM t2 WHERE y=b ORDER BY z DESC LIMIT 1) c +FROM t1) t; +COUNT(*) +3000 +DROP TABLE t2,t1; +CREATE TABLE t1 (id char(4) PRIMARY KEY, c int); +CREATE TABLE t2 (c int); +INSERT INTO t1 VALUES ('aa', 1); +INSERT INTO t2 VALUES (1); +SELECT * FROM t1 +WHERE EXISTS (SELECT c FROM t2 WHERE c=1 +UNION +SELECT c from t2 WHERE c=t1.c); +id c +aa 1 +INSERT INTO t1 VALUES ('bb', 2), ('cc', 3), ('dd',1); +SELECT * FROM t1 +WHERE EXISTS (SELECT c FROM t2 WHERE c=1 +UNION +SELECT c from t2 WHERE c=t1.c); +id c +aa 1 +bb 2 +cc 3 +dd 1 +INSERT INTO t2 VALUES (2); +CREATE TABLE t3 (c int); +INSERT INTO t3 VALUES (1); +SELECT * FROM t1 +WHERE EXISTS (SELECT t2.c FROM t2 JOIN t3 ON t2.c=t3.c WHERE t2.c=1 +UNION +SELECT c from t2 WHERE c=t1.c); +id c +aa 1 +bb 2 +cc 3 +dd 1 +DROP TABLE t1,t2,t3; +CREATE TABLE t1(f1 int); +CREATE TABLE t2(f2 int, f21 int, f3 timestamp); +INSERT INTO t1 VALUES (1),(1),(2),(2); +INSERT INTO t2 VALUES (1,1,"2004-02-29 11:11:11"), (2,2,"2004-02-29 11:11:11"); +SELECT ((SELECT f2 FROM t2 WHERE f21=f1 LIMIT 1) * COUNT(f1)) AS sq FROM t1 GROUP BY f1; +sq +2 +4 +SELECT (SELECT SUM(1) FROM t2 ttt GROUP BY t2.f3 LIMIT 1) AS tt FROM t2; +tt +2 +2 +PREPARE stmt1 FROM 'SELECT ((SELECT f2 FROM t2 WHERE f21=f1 LIMIT 1) * COUNT(f1)) AS sq FROM t1 GROUP BY f1'; +EXECUTE stmt1; +sq +2 +4 +EXECUTE stmt1; +sq +2 +4 +DEALLOCATE PREPARE stmt1; +SELECT f2, AVG(f21), +(SELECT t.f3 FROM t2 AS t WHERE t2.f2=t.f2 AND t.f3=MAX(t2.f3)) AS test +FROM t2 GROUP BY f2; +f2 AVG(f21) test +1 1.0000 2004-02-29 11:11:11 +2 2.0000 2004-02-29 11:11:11 +DROP TABLE t1,t2; +CREATE TABLE t1 (a int, b INT, c CHAR(10) NOT NULL); +INSERT INTO t1 VALUES +(1,1,'a'), (1,2,'b'), (1,3,'c'), (1,4,'d'), (1,5,'e'), +(2,1,'f'), (2,2,'g'), (2,3,'h'), (3,4,'i'), (3,3,'j'), +(3,2,'k'), (3,1,'l'), (1,9,'m'); +SELECT a, MAX(b), +(SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b)) AS test +FROM t1 GROUP BY a; +a MAX(b) test +1 9 m +2 3 h +3 4 i +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t1xt2; +CREATE TABLE t1 ( +id_1 int(5) NOT NULL, +t varchar(4) DEFAULT NULL +); +CREATE TABLE t2 ( +id_2 int(5) NOT NULL, +t varchar(4) DEFAULT NULL +); +CREATE TABLE t1xt2 ( +id_1 int(5) NOT NULL, +id_2 int(5) NOT NULL +); +INSERT INTO t1 VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'); +INSERT INTO t2 VALUES (2, 'bb'), (3, 'cc'), (4, 'dd'), (12, 'aa'); +INSERT INTO t1xt2 VALUES (2, 2), (3, 3), (4, 4); +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); +id_1 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); +id_1 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); +id_1 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); +id_1 +1 +2 +3 +4 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 where t1.id_1 = t1xt2.id_1))); +id_1 +1 +2 +3 +4 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 where t1.id_1 = t1xt2.id_1)))); +id_1 +1 +2 +3 +4 +insert INTO t1xt2 VALUES (1, 12); +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); +id_1 +1 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); +id_1 +1 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); +id_1 +1 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); +id_1 +2 +3 +4 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); +id_1 +2 +3 +4 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); +id_1 +2 +3 +4 +insert INTO t1xt2 VALUES (2, 12); +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); +id_1 +1 +2 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); +id_1 +1 +2 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); +id_1 +1 +2 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); +id_1 +3 +4 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); +id_1 +3 +4 +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); +id_1 +3 +4 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t1xt2; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3), (1), (2); +SELECT 'this is ' 'a test.' AS col1, a AS col2 FROM t1; +col1 col2 +this is a test. 3 +this is a test. 1 +this is a test. 2 +SELECT * FROM (SELECT 'this is ' 'a test.' AS col1, a AS t2 FROM t1) t; +col1 t2 +this is a test. 3 +this is a test. 1 +this is a test. 2 +DROP table t1; +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (m int, n int); +INSERT INTO t1 VALUES (2,2), (2,2), (3,3), (3,3), (3,3), (4,4); +INSERT INTO t2 VALUES (1,11), (2,22), (3,32), (4,44), (4,44); +SELECT COUNT(*), a, +(SELECT m FROM t2 WHERE m = count(*) LIMIT 1) +FROM t1 GROUP BY a; +COUNT(*) a (SELECT m FROM t2 WHERE m = count(*) LIMIT 1) +2 2 2 +3 3 3 +1 4 1 +SELECT COUNT(*), a, +(SELECT MIN(m) FROM t2 WHERE m = count(*)) +FROM t1 GROUP BY a; +COUNT(*) a (SELECT MIN(m) FROM t2 WHERE m = count(*)) +2 2 2 +3 3 3 +1 4 1 +SELECT COUNT(*), a +FROM t1 GROUP BY a +HAVING (SELECT MIN(m) FROM t2 WHERE m = count(*)) > 1; +COUNT(*) a +2 2 +3 3 +DROP TABLE t1,t2; +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (m int, n int); +INSERT INTO t1 VALUES (2,2), (2,2), (3,3), (3,3), (3,3), (4,4); +INSERT INTO t2 VALUES (1,11), (2,22), (3,32), (4,44), (4,44); +SELECT COUNT(*) c, a, +(SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a) +FROM t1 GROUP BY a; +c a (SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a) +2 2 2 +3 3 3 +1 4 1,1 +SELECT COUNT(*) c, a, +(SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a) +FROM t1 GROUP BY a; +c a (SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a) +2 2 3 +3 3 4 +1 4 2,2 +DROP table t1,t2; +CREATE TABLE t1 (a int, b INT, d INT, c CHAR(10) NOT NULL, PRIMARY KEY (a, b)); +INSERT INTO t1 VALUES (1,1,0,'a'), (1,2,0,'b'), (1,3,0,'c'), (1,4,0,'d'), +(1,5,0,'e'), (2,1,0,'f'), (2,2,0,'g'), (2,3,0,'h'), (3,4,0,'i'), (3,3,0,'j'), +(3,2,0,'k'), (3,1,0,'l'), (1,9,0,'m'), (1,0,10,'n'), (2,0,5,'o'), (3,0,7,'p'); +SELECT a, MAX(b), +(SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b + 0)) as test +FROM t1 GROUP BY a; +a MAX(b) test +1 9 m +2 3 h +3 4 i +SELECT a x, MAX(b), +(SELECT t.c FROM t1 AS t WHERE x=t.a AND t.b=MAX(t1.b + 0)) as test +FROM t1 GROUP BY a; +x MAX(b) test +1 9 m +2 3 h +3 4 i +SELECT a, AVG(b), +(SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=AVG(t1.b)) AS test +FROM t1 WHERE t1.d=0 GROUP BY a; +a AVG(b) test +1 4.0000 d +2 2.0000 g +3 2.5000 NULL +SELECT tt.a, +(SELECT (SELECT c FROM t1 as t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a) +LIMIT 1) FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1) as test +FROM t1 as tt; +a test +1 n +1 n +1 n +1 n +1 n +1 n +1 n +2 o +2 o +2 o +2 o +3 p +3 p +3 p +3 p +3 p +SELECT tt.a, +(SELECT (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a) +LIMIT 1) +FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1) as test +FROM t1 as tt GROUP BY tt.a; +a test +1 n +2 o +3 p +SELECT tt.a, MAX( +(SELECT (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a) +LIMIT 1) +FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1)) as test +FROM t1 as tt GROUP BY tt.a; +a test +1 n +2 o +3 p +DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (2,22),(1,11),(2,22); +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +a +1 +2 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; +a +SELECT a FROM t1 t0 +WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; +a +1 +2 +SET @@sql_mode='ansi'; +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +ERROR HY000: Invalid use of group function +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; +ERROR HY000: Invalid use of group function +SELECT a FROM t1 t0 +WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; +ERROR HY000: Invalid use of group function +SET @@sql_mode=default; +DROP TABLE t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 values (1),(1),(1),(1); +CREATE TABLE t2 (x INT); +INSERT INTO t1 values (1000),(1001),(1002); +SELECT SUM( (SELECT COUNT(a) FROM t2) ) FROM t1; +ERROR HY000: Invalid use of group function +SELECT SUM( (SELECT SUM(COUNT(a)) FROM t2) ) FROM t1; +ERROR HY000: Invalid use of group function +SELECT COUNT(1) FROM DUAL; +COUNT(1) +1 +SELECT SUM( (SELECT AVG( (SELECT t1.a FROM t2) ) FROM DUAL) ) FROM t1; +ERROR HY000: Invalid use of group function +SELECT +SUM( (SELECT AVG( (SELECT COUNT(*) FROM t1 t HAVING t1.a < 12) ) FROM t2) ) +FROM t1; +ERROR HY000: Invalid use of group function +SELECT t1.a as XXA, +SUM( (SELECT AVG( (SELECT COUNT(*) FROM t1 t HAVING XXA < 12) ) FROM t2) ) +FROM t1; +ERROR HY000: Invalid use of group function +DROP TABLE t1,t2; +CREATE TABLE t1 (a int, b int, KEY (a)); +INSERT INTO t1 VALUES (1,1),(2,1); +EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ref a a 5 const 1 Using where; Using index +2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort +DROP TABLE t1; +CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id)); +INSERT INTO t1 VALUES +(3,'FL'), (2,'GA'), (4,'FL'), (1,'GA'), (5,'NY'), (7,'FL'), (6,'NY'); +CREATE TABLE t2 (id int NOT NULL, INDEX idx(id)); +INSERT INTO t2 VALUES (7), (5), (1), (3); +SELECT id, st FROM t1 +WHERE st IN ('GA','FL') AND EXISTS(SELECT 1 FROM t2 WHERE t2.id=t1.id); +id st +3 FL +1 GA +7 FL +SELECT id, st FROM t1 +WHERE st IN ('GA','FL') AND EXISTS(SELECT 1 FROM t2 WHERE t2.id=t1.id) +GROUP BY id; +id st +1 GA +3 FL +7 FL +SELECT id, st FROM t1 +WHERE st IN ('GA','FL') AND NOT EXISTS(SELECT 1 FROM t2 WHERE t2.id=t1.id); +id st +2 GA +4 FL +SELECT id, st FROM t1 +WHERE st IN ('GA','FL') AND NOT EXISTS(SELECT 1 FROM t2 WHERE t2.id=t1.id) +GROUP BY id; +id st +2 GA +4 FL +DROP TABLE t1,t2; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); +EXPLAIN EXTENDED +SELECT * FROM (SELECT count(*) FROM t1 GROUP BY a) as res; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00 +2 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +Warnings: +Note 1003 select `res`.`count(*)` AS `count(*)` from (select count(0) AS `count(*)` from `test`.`t1` group by `test`.`t1`.`a`) `res` +DROP TABLE t1; +CREATE TABLE t1 ( +a varchar(255) default NULL, +b timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, +INDEX idx(a,b) +); +CREATE TABLE t2 ( +a varchar(255) default NULL +); +INSERT INTO t1 VALUES ('abcdefghijk','2007-05-07 06:00:24'); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO `t1` VALUES ('asdf','2007-02-08 01:11:26'); +INSERT INTO `t2` VALUES ('abcdefghijk'); +INSERT INTO `t2` VALUES ('asdf'); +SET session sort_buffer_size=8192; +Warnings: +Warning 1292 Truncated incorrect sort_buffer_size value: '8192' +SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.a ORDER BY t1.b LIMIT 1) AS d1 FROM t2; +d1 +1 +1 +DROP TABLE t1,t2; +CREATE TABLE t1 (a INTEGER, b INTEGER); +CREATE TABLE t2 (x INTEGER); +INSERT INTO t1 VALUES (1,11), (2,22), (2,22); +INSERT INTO t2 VALUES (1), (2); +SELECT a, COUNT(b), (SELECT COUNT(b) FROM t2) FROM t1 GROUP BY a; +ERROR 21000: Subquery returns more than 1 row +SELECT a, COUNT(b), (SELECT COUNT(b)+0 FROM t2) FROM t1 GROUP BY a; +ERROR 21000: Subquery returns more than 1 row +SELECT (SELECT SUM(t1.a)/AVG(t2.x) FROM t2) FROM t1; +(SELECT SUM(t1.a)/AVG(t2.x) FROM t2) +3.3333 +DROP TABLE t1,t2; +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1, 2), (1,3), (1,4), (2,1), (2,2); +SELECT a1.a, COUNT(*) FROM t1 a1 WHERE a1.a = 1 +AND EXISTS( SELECT a2.a FROM t1 a2 WHERE a2.a = a1.a) +GROUP BY a1.a; +a COUNT(*) +1 3 +DROP TABLE t1; +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=0) FROM t1; +(SELECT SUM(t1.a) FROM t2 WHERE a=0) +NULL +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a!=0) FROM t1; +ERROR 21000: Subquery returns more than 1 row +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=1) FROM t1; +(SELECT SUM(t1.a) FROM t2 WHERE a=1) +3 +DROP TABLE t1,t2; +CREATE TABLE t1 (a1 INT, a2 INT); +CREATE TABLE t2 (b1 INT, b2 INT); +INSERT INTO t1 VALUES (100, 200); +INSERT INTO t1 VALUES (101, 201); +INSERT INTO t2 VALUES (101, 201); +INSERT INTO t2 VALUES (103, 203); +SELECT ((a1,a2) IN (SELECT * FROM t2 WHERE b2 > 0)) IS NULL FROM t1; +((a1,a2) IN (SELECT * FROM t2 WHERE b2 > 0)) IS NULL +0 +0 +DROP TABLE t1, t2; +CREATE TABLE t1 (s1 BINARY(5), s2 VARBINARY(5)); +INSERT INTO t1 VALUES (0x41,0x41), (0x42,0x42), (0x43,0x43); +SELECT s1, s2 FROM t1 WHERE s2 IN (SELECT s1 FROM t1); +s1 s2 +SELECT s1, s2 FROM t1 WHERE (s2, 10) IN (SELECT s1, 10 FROM t1); +s1 s2 +CREATE INDEX I1 ON t1 (s1); +CREATE INDEX I2 ON t1 (s2); +SELECT s1, s2 FROM t1 WHERE s2 IN (SELECT s1 FROM t1); +s1 s2 +SELECT s1, s2 FROM t1 WHERE (s2, 10) IN (SELECT s1, 10 FROM t1); +s1 s2 +TRUNCATE t1; +INSERT INTO t1 VALUES (0x41,0x41); +SELECT * FROM t1 WHERE s1 = (SELECT s2 FROM t1); +s1 s2 +DROP TABLE t1; +CREATE TABLE t1 (a1 VARBINARY(2) NOT NULL DEFAULT '0', PRIMARY KEY (a1)); +CREATE TABLE t2 (a2 BINARY(2) default '0', INDEX (a2)); +CREATE TABLE t3 (a3 BINARY(2) default '0'); +INSERT INTO t1 VALUES (1),(2),(3),(4); +INSERT INTO t2 VALUES (1),(2),(3); +INSERT INTO t3 VALUES (1),(2),(3); +SELECT LEFT(t2.a2, 1) FROM t2,t3 WHERE t3.a3=t2.a2; +LEFT(t2.a2, 1) +1 +2 +3 +SELECT t1.a1, t1.a1 in (SELECT t2.a2 FROM t2,t3 WHERE t3.a3=t2.a2) FROM t1; +a1 t1.a1 in (SELECT t2.a2 FROM t2,t3 WHERE t3.a3=t2.a2) +1 0 +2 0 +3 0 +4 0 +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (a1 BINARY(3) PRIMARY KEY, b1 VARBINARY(3)); +CREATE TABLE t2 (a2 VARBINARY(3) PRIMARY KEY); +CREATE TABLE t3 (a3 VARBINARY(3) PRIMARY KEY); +INSERT INTO t1 VALUES (1,10), (2,20), (3,30), (4,40); +INSERT INTO t2 VALUES (2), (3), (4), (5); +INSERT INTO t3 VALUES (10), (20), (30); +SELECT LEFT(t1.a1,1) FROM t1,t3 WHERE t1.b1=t3.a3; +LEFT(t1.a1,1) +1 +2 +3 +SELECT a2 FROM t2 WHERE t2.a2 IN (SELECT t1.a1 FROM t1,t3 WHERE t1.b1=t3.a3); +a2 +DROP TABLE t1, t2, t3; +CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); +INSERT INTO t1 VALUES ('a', 'aa'); +INSERT INTO t1 VALUES ('a', 'aaa'); +SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); +a b +CREATE INDEX I1 ON t1 (a); +CREATE INDEX I2 ON t1 (b); +EXPLAIN SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t1 index_subquery I1 I1 2 func 2 Using index; Using where +SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); +a b +CREATE TABLE t2 (a VARCHAR(1), b VARCHAR(10)); +INSERT INTO t2 SELECT * FROM t1; +CREATE INDEX I1 ON t2 (a); +CREATE INDEX I2 ON t2 (b); +EXPLAIN SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t2 index_subquery I1 I1 4 func 2 Using index; Using where +SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2); +a b +EXPLAIN +SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t1 index_subquery I1 I1 2 func 2 Using index; Using where +SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); +a b +DROP TABLE t1,t2; +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 VALUES (1,1), (1,2), (2,3), (2,4); +EXPLAIN +SELECT a AS out_a, MIN(b) FROM t1 +WHERE b > (SELECT MIN(b) FROM t1 WHERE a = out_a) +GROUP BY a; +ERROR 42S22: Unknown column 'out_a' in 'where clause' +SELECT a AS out_a, MIN(b) FROM t1 +WHERE b > (SELECT MIN(b) FROM t1 WHERE a = out_a) +GROUP BY a; +ERROR 42S22: Unknown column 'out_a' in 'where clause' +EXPLAIN +SELECT a AS out_a, MIN(b) FROM t1 t1_outer +WHERE b > (SELECT MIN(b) FROM t1 WHERE a = t1_outer.a) +GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1_outer ALL NULL NULL NULL NULL 4 Using where; Using temporary; Using filesort +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 4 Using where +SELECT a AS out_a, MIN(b) FROM t1 t1_outer +WHERE b > (SELECT MIN(b) FROM t1 WHERE a = t1_outer.a) +GROUP BY a; +out_a MIN(b) +1 2 +2 4 +DROP TABLE t1; +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a)); +2 +2 +2 +EXPLAIN EXTENDED +SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a)); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1003 select 2 AS `2` from `test`.`t1` where exists(select 1 AS `1` from `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`)) +EXPLAIN EXTENDED +SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a) UNION +(SELECT 1 FROM t2 WHERE t1.a = t2.a)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION +(SELECT 1 FROM t2 WHERE t1.a = t2.a))' at line 2 +DROP TABLE t1,t2; +create table t1(f11 int, f12 int); +create table t2(f21 int unsigned not null, f22 int, f23 varchar(10)); +insert into t1 values(1,1),(2,2), (3, 3); +set session sort_buffer_size= 33*1024; +select count(*) from t1 where f12 = +(select f22 from t2 where f22 = f12 order by f21 desc, f22, f23 limit 1); +count(*) +3 +drop table t1,t2; +End of 5.0 tests. +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (2,22),(1,11),(2,22); +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +a +1 +2 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; +a +SELECT a FROM t1 t0 +WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; +a +1 +2 +SET @@sql_mode='ansi'; +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +ERROR HY000: Invalid use of group function +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; +ERROR HY000: Invalid use of group function +SELECT a FROM t1 t0 +WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; +ERROR HY000: Invalid use of group function +SET @@sql_mode=default; +DROP TABLE t1; +CREATE TABLE t1 (s1 char(1)); +INSERT INTO t1 VALUES ('a'); +SELECT * FROM t1 WHERE _utf8'a' = ANY (SELECT s1 FROM t1); +s1 +a +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/sum_distinct.result b/mysql-test/suite/pbxt/r/sum_distinct.result new file mode 100644 index 00000000000..c615817f52d --- /dev/null +++ b/mysql-test/suite/pbxt/r/sum_distinct.result @@ -0,0 +1,97 @@ +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 ( +id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, +gender CHAR(1), +name VARCHAR(20) +); +SELECT SUM(DISTINCT LENGTH(name)) s1 FROM t1; +s1 +NULL +INSERT INTO t1 (gender, name) VALUES (NULL, NULL); +INSERT INTO t1 (gender, name) VALUES (NULL, NULL); +INSERT INTO t1 (gender, name) VALUES (NULL, NULL); +SELECT SUM(DISTINCT LENGTH(name)) s1 FROM t1; +s1 +NULL +INSERT INTO t1 (gender, name) VALUES ('F', 'Helen'), ('F', 'Anastasia'), +('F', 'Katherine'), ('F', 'Margo'), ('F', 'Magdalene'), ('F', 'Mary'); +CREATE TABLE t2 SELECT name FROM t1; +SELECT (SELECT SUM(DISTINCT LENGTH(name)) FROM t1) FROM t2; +(SELECT SUM(DISTINCT LENGTH(name)) FROM t1) +18 +18 +18 +18 +18 +18 +18 +18 +18 +DROP TABLE t2; +INSERT INTO t1 (gender, name) VALUES ('F', 'Eva'), ('F', 'Sofia'), +('F', 'Sara'), ('F', 'Golda'), ('F', 'Toba'), ('F', 'Victory'), +('F', 'Faina'), ('F', 'Miriam'), ('F', 'Beki'), ('F', 'America'), +('F', 'Susan'), ('F', 'Glory'), ('F', 'Priscilla'), ('F', 'Rosmary'), +('F', 'Rose'), ('F', 'Margareth'), ('F', 'Elizabeth'), ('F', 'Meredith'), +('F', 'Julie'), ('F', 'Xenia'), ('F', 'Zena'), ('F', 'Olga'), +('F', 'Brunhilda'), ('F', 'Nataly'), ('F', 'Lara'), ('F', 'Svetlana'), +('F', 'Grethem'), ('F', 'Irene'); +SELECT +SUM(DISTINCT LENGTH(name)) s1, +SUM(DISTINCT SUBSTRING(NAME, 1, 3)) s2, +SUM(DISTINCT LENGTH(SUBSTRING(name, 1, 4))) s3 +FROM t1; +s1 s2 s3 +42 0 7 +SELECT +SUM(DISTINCT LENGTH(g1.name)) s1, +SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2, +SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3 +FROM t1 g1, t1 g2, t1 g3; +s1 s2 s3 +42 0 7 +SELECT +SUM(DISTINCT LENGTH(g1.name)) s1, +SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2, +SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3 +FROM t1 g1, t1 g2, t1 g3 GROUP BY LENGTH(SUBSTRING(g3.name, 5, 10)); +s1 s2 s3 +42 0 NULL +42 0 7 +42 0 4 +42 0 4 +42 0 4 +42 0 4 +42 0 4 +SELECT SQL_BUFFER_RESULT +SUM(DISTINCT LENGTH(name)) s1, +SUM(DISTINCT SUBSTRING(NAME, 1, 3)) s2, +SUM(DISTINCT LENGTH(SUBSTRING(name, 1, 4))) s3 +FROM t1; +s1 s2 s3 +42 0 7 +SELECT SQL_BUFFER_RESULT +SUM(DISTINCT LENGTH(g1.name)) s1, +SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2, +SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3 +FROM t1 g1, t1 g2, t1 g3 GROUP BY LENGTH(SUBSTRING(g3.name, 5, 10)); +s1 s2 s3 +42 0 NULL +42 0 7 +42 0 4 +42 0 4 +42 0 4 +42 0 4 +42 0 4 +SET @l=1; +UPDATE t1 SET name=CONCAT(name, @l:=@l+1); +SELECT SUM(DISTINCT RIGHT(name, 1)) FROM t1; +SUM(DISTINCT RIGHT(name, 1)) +45 +SELECT SUM(DISTINCT id) FROM t1; +SUM(DISTINCT id) +703 +SELECT SUM(DISTINCT id % 11) FROM t1; +SUM(DISTINCT id % 11) +55 +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/temp_table.result b/mysql-test/suite/pbxt/r/temp_table.result new file mode 100644 index 00000000000..7d8f248eb5b --- /dev/null +++ b/mysql-test/suite/pbxt/r/temp_table.result @@ -0,0 +1,165 @@ +drop table if exists t1,t2; +drop view if exists v1; +CREATE TABLE t1 (c int not null, d char (10) not null); +insert into t1 values(1,""),(2,"a"),(3,"b"); +CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(4,"e"),(5,"f"),(6,"g"); +alter table t1 rename t2; +select * from t1; +c d +1 +2 a +3 b +select * from t2; +a b +4 e +5 f +6 g +CREATE TABLE t2 (x int not null, y int not null); +alter table t2 rename t1; +select * from t1; +a b +4 e +5 f +6 g +create TEMPORARY TABLE t2 engine=heap select * from t1; +create TEMPORARY TABLE IF NOT EXISTS t2 (a int) engine=heap; +Warnings: +Note 1050 Table 't2' already exists +CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null); +ERROR 42S01: Table 't1' already exists +ALTER TABLE t1 RENAME t2; +ERROR 42S01: Table 't2' already exists +select * from t2; +a b +4 e +5 f +6 g +alter table t2 add primary key (a,b); +drop table t1,t2; +select * from t1; +c d +1 +2 a +3 b +drop table t2; +create temporary table t1 engine=myisam select *,2 as "e" from t1; +select * from t1; +c d e +1 2 +2 a 2 +3 b 2 +drop table t1; +drop table t1; +CREATE TABLE t1 (pkCrash INTEGER PRIMARY KEY,strCrash VARCHAR(255)); +INSERT INTO t1 ( pkCrash, strCrash ) VALUES ( 1, '1'); +SELECT CONCAT_WS(pkCrash, strCrash) FROM t1; +CONCAT_WS(pkCrash, strCrash) +1 +drop table t1; +create temporary table t1 select 1 as 'x'; +drop table t1; +CREATE TABLE t1 (x INT); +INSERT INTO t1 VALUES (1), (2), (3); +CREATE TEMPORARY TABLE tmp engine=myisam SELECT *, NULL FROM t1; +drop table t1; +create temporary table t1 (id int(10) not null unique); +create temporary table t2 (id int(10) not null primary key, +val int(10) not null); +insert into t1 values (1),(2),(4); +insert into t2 values (1,1),(2,1),(3,1),(4,2); +select one.id, two.val, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id order by one.id; +id val elt(two.val,'one','two') +1 1 one +2 1 one +4 2 two +drop table t1,t2; +create temporary table t1 (a int not null); +insert into t1 values (1),(1); +alter table t1 add primary key (a); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +drop table t1; +CREATE TABLE t1 ( +d datetime default NULL +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2002-10-24 14:50:32'),('2002-10-24 14:50:33'),('2002-10-24 14:50:34'),('2002-10-24 14:50:34'),('2002-10-24 14:50:34'),('2002-10-24 14:50:35'),('2002-10-24 14:50:35'),('2002-10-24 14:50:35'),('2002-10-24 14:50:35'),('2002-10-24 14:50:36'),('2002-10-24 14:50:36'),('2002-10-24 14:50:36'),('2002-10-24 14:50:36'),('2002-10-24 14:50:37'),('2002-10-24 14:50:37'),('2002-10-24 14:50:37'),('2002-10-24 14:50:37'),('2002-10-24 14:50:38'),('2002-10-24 14:50:38'),('2002-10-24 14:50:38'),('2002-10-24 14:50:39'),('2002-10-24 14:50:39'),('2002-10-24 14:50:39'),('2002-10-24 14:50:39'),('2002-10-24 14:50:40'),('2002-10-24 14:50:40'),('2002-10-24 14:50:40'); +flush status; +select * from t1 group by d; +d +2002-10-24 14:50:32 +2002-10-24 14:50:33 +2002-10-24 14:50:34 +2002-10-24 14:50:35 +2002-10-24 14:50:36 +2002-10-24 14:50:37 +2002-10-24 14:50:38 +2002-10-24 14:50:39 +2002-10-24 14:50:40 +show status like "created_tmp%tables"; +Variable_name Value +Created_tmp_disk_tables 0 +Created_tmp_tables 1 +drop table t1; +create temporary table v1 as select 'This is temp. table' A; +create view v1 as select 'This is view' A; +select * from v1; +A +This is temp. table +show create table v1; +Table Create Table +v1 CREATE TEMPORARY TABLE `v1` ( + `A` varchar(19) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 'This is view' AS `A` latin1 latin1_swedish_ci +drop view v1; +select * from v1; +A +This is temp. table +create view v1 as select 'This is view again' A; +select * from v1; +A +This is temp. table +drop table v1; +select * from v1; +A +This is view again +drop view v1; +create table t1 (a int, b int, index(a), index(b)); +create table t2 (c int auto_increment, d varchar(255), primary key (c)); +insert into t1 values (3,1),(3,2); +insert into t2 values (NULL, 'foo'), (NULL, 'bar'); +select d, c from t1 left join t2 on b = c where a = 3 order by d; +d c +bar 2 +foo 1 +drop table t1, t2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i INT); +LOCK TABLE t1 WRITE; +CREATE TEMPORARY TABLE t1 (i INT); +The following command should not block +DROP TEMPORARY TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (i INT); +CREATE TEMPORARY TABLE t2 (i INT); +DROP TEMPORARY TABLE t2, t1; +ERROR 42S02: Unknown table 't1' +SELECT * FROM t2; +ERROR 42S02: Table 'test.t2' doesn't exist +SELECT * FROM t1; +i +DROP TABLE t1; +End of 4.1 tests. +create temporary table t1 (a int); +insert into t1 values (4711); +select * from t1; +a +4711 +truncate t1; +insert into t1 values (42); +select * from t1; +a +42 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/truncate.result b/mysql-test/suite/pbxt/r/truncate.result new file mode 100644 index 00000000000..74a6cb72cc6 --- /dev/null +++ b/mysql-test/suite/pbxt/r/truncate.result @@ -0,0 +1,55 @@ +drop table if exists t1; +create table t1 (a integer, b integer,c1 CHAR(10)); +insert into t1 (a) values (1),(2); +truncate table t1; +select count(*) from t1; +count(*) +0 +insert into t1 values(1,2,"test"); +select count(*) from t1; +count(*) +1 +delete from t1; +select * from t1; +a b c1 +drop table t1; +select count(*) from t1; +ERROR 42S02: Table 'test.t1' doesn't exist +create temporary table t1 (n int); +insert into t1 values (1),(2),(3); +truncate table t1; +select * from t1; +n +drop table t1; +truncate non_existing_table; +ERROR 42S02: Table 'test.non_existing_table' doesn't exist +create table t1 (a integer auto_increment primary key); +insert into t1 (a) values (NULL),(NULL); +truncate table t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +a +1 +2 +delete from t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +a +3 +4 +drop table t1; +create temporary table t1 (a integer auto_increment primary key); +insert into t1 (a) values (NULL),(NULL); +truncate table t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +a +1 +2 +delete from t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +a +3 +4 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/type_binary.result b/mysql-test/suite/pbxt/r/type_binary.result new file mode 100644 index 00000000000..a83ebf5c25d --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_binary.result @@ -0,0 +1,148 @@ +create table t1 (s1 binary(3)); +insert into t1 values (0x61), (0x6120), (0x612020); +select hex(s1) from t1; +hex(s1) +610000 +612000 +612020 +drop table t1; +create table t1 (s1 binary(2), s2 varbinary(2)); +insert into t1 values (0x4100,0x4100); +select length(concat('*',s1,'*',s2,'*')) from t1; +length(concat('*',s1,'*',s2,'*')) +7 +delete from t1; +insert into t1 values (0x4120,0x4120); +select length(concat('*',s1,'*',s2,'*')) from t1; +length(concat('*',s1,'*',s2,'*')) +7 +drop table t1; +create table t1 (s1 varbinary(20), s2 varbinary(20)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varbinary(20) DEFAULT NULL, + `s2` varbinary(20) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert into t1 values (0x41,0x4100),(0x41,0x4120),(0x4100,0x4120); +select hex(s1), hex(s2) from t1; +hex(s1) hex(s2) +41 4100 +41 4120 +4100 4120 +select count(*) from t1 where s1 < s2; +count(*) +3 +drop table t1; +create table t1 (s1 varbinary(2), s2 varchar(1)); +insert into t1 values (0x41,'a'), (0x4100,'b'), (0x41,'c'), (0x4100,'d'); +select hex(s1),s2 from t1 order by s1,s2; +hex(s1) s2 +41 a +41 c +4100 b +4100 d +drop table t1; +create table t1 (s1 binary(2) primary key); +insert into t1 values (0x01); +insert into t1 values (0x0120); +insert into t1 values (0x0100); +ERROR 23000: Duplicate entry '' for key 'PRIMARY' +select hex(s1) from t1 order by s1; +hex(s1) +0100 +0120 +select hex(s1) from t1 where s1=0x01; +hex(s1) +select hex(s1) from t1 where s1=0x0120; +hex(s1) +0120 +select hex(s1) from t1 where s1=0x0100; +hex(s1) +0100 +select count(distinct s1) from t1; +count(distinct s1) +2 +alter table t1 drop primary key; +select hex(s1) from t1 where s1=0x01; +hex(s1) +select hex(s1) from t1 where s1=0x0120; +hex(s1) +0120 +select hex(s1) from t1 where s1=0x0100; +hex(s1) +0100 +select count(distinct s1) from t1; +count(distinct s1) +2 +drop table t1; +create table t1 (s1 varbinary(2) primary key); +insert into t1 values (0x01); +insert into t1 values (0x0120); +insert into t1 values (0x0100); +select hex(s1) from t1 order by s1; +hex(s1) +01 +0100 +0120 +select hex(s1) from t1 where s1=0x01; +hex(s1) +01 +select hex(s1) from t1 where s1=0x0120; +hex(s1) +0120 +select hex(s1) from t1 where s1=0x0100; +hex(s1) +0100 +select count(distinct s1) from t1; +count(distinct s1) +3 +alter table t1 drop primary key; +select hex(s1) from t1 where s1=0x01; +hex(s1) +01 +select hex(s1) from t1 where s1=0x0120; +hex(s1) +0120 +select hex(s1) from t1 where s1=0x0100; +hex(s1) +0100 +select count(distinct s1) from t1; +count(distinct s1) +3 +drop table t1; +select hex(cast(0x10 as binary(2))); +hex(cast(0x10 as binary(2))) +1000 +create table t1 (b binary(2), vb varbinary(2)); +insert into t1 values(0x4120, 0x4120); +insert into t1 values(0x412020, 0x412020); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'vb' at row 1 +drop table t1; +create table t1 (c char(2), vc varchar(2)); +insert into t1 values(0x4120, 0x4120); +insert into t1 values(0x412020, 0x412020); +Warnings: +Note 1265 Data truncated for column 'vc' at row 1 +drop table t1; +set @old_sql_mode= @@sql_mode, sql_mode= 'traditional'; +create table t1 (b binary(2), vb varbinary(2)); +insert into t1 values(0x4120, 0x4120); +insert into t1 values(0x412020, NULL); +ERROR 22001: Data too long for column 'b' at row 1 +insert into t1 values(NULL, 0x412020); +ERROR 22001: Data too long for column 'vb' at row 1 +drop table t1; +set @@sql_mode= @old_sql_mode; +create table t1(f1 int, f2 binary(2) not null, f3 char(2) not null); +insert into t1 set f1=1; +Warnings: +Warning 1364 Field 'f2' doesn't have a default value +Warning 1364 Field 'f3' doesn't have a default value +select hex(f2), hex(f3) from t1; +hex(f2) hex(f3) +0000 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/type_bit.result b/mysql-test/suite/pbxt/r/type_bit.result new file mode 100644 index 00000000000..c2969d00f74 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_bit.result @@ -0,0 +1,623 @@ +select 0 + b'1'; +0 + b'1' +1 +select 0 + b'0'; +0 + b'0' +0 +select 0 + b'000001'; +0 + b'000001' +1 +select 0 + b'000011'; +0 + b'000011' +3 +select 0 + b'000101'; +0 + b'000101' +5 +select 0 + b'000000'; +0 + b'000000' +0 +select 0 + b'10000000'; +0 + b'10000000' +128 +select 0 + b'11111111'; +0 + b'11111111' +255 +select 0 + b'10000001'; +0 + b'10000001' +129 +select 0 + b'1000000000000000'; +0 + b'1000000000000000' +32768 +select 0 + b'1111111111111111'; +0 + b'1111111111111111' +65535 +select 0 + b'1000000000000001'; +0 + b'1000000000000001' +32769 +drop table if exists t1,t2; +create table t1 (a bit(65)); +ERROR 42000: Display width out of range for column 'a' (max = 64) +create table t1 (a bit(0)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bit(1) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a bit(64)); +insert into t1 values +(b'1111111111111111111111111111111111111111111111111111111111111111'), +(b'1000000000000000000000000000000000000000000000000000000000000000'), +(b'0000000000000000000000000000000000000000000000000000000000000001'), +(b'1010101010101010101010101010101010101010101010101010101010101010'), +(b'0101010101010101010101010101010101010101010101010101010101010101'); +select hex(a) from t1; +hex(a) +FFFFFFFFFFFFFFFF +8000000000000000 +1 +AAAAAAAAAAAAAAAA +5555555555555555 +drop table t1; +create table t1 (a bit); +insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001'); +Warnings: +Warning 1264 Out of range value for column 'a' at row 4 +select hex(a) from t1; +hex(a) +0 +1 +0 +1 +1 +alter table t1 add unique (a); +ERROR 23000: Duplicate entry '' for key 'a' +drop table t1; +create table t1 (a bit(2)); +insert into t1 values (b'00'), (b'01'), (b'10'), (b'100'); +Warnings: +Warning 1264 Out of range value for column 'a' at row 4 +select a+0 from t1; +a+0 +0 +1 +2 +3 +alter table t1 add key (a); +explain select a+0 from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 2 NULL 4 Using index +select a+0 from t1; +a+0 +0 +1 +2 +3 +drop table t1; +create table t1 (a bit(7), b bit(9), key(a, b)); +insert into t1 values +(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177), +(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380), +(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36), +(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499), +(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403), +(44, 307), (68, 454), (57, 135); +explain select a+0 from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 38 Using index +select a+0 from t1; +a+0 +0 +4 +5 +9 +23 +24 +28 +29 +30 +31 +34 +44 +49 +56 +57 +59 +60 +61 +68 +68 +75 +77 +78 +79 +87 +88 +94 +94 +104 +106 +108 +111 +116 +118 +119 +122 +123 +127 +explain select b+0 from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 38 Using index +select b+0 from t1; +b+0 +177 +245 +178 +363 +36 +398 +499 +399 +83 +438 +202 +307 +345 +379 +135 +188 +343 +152 +206 +454 +42 +133 +123 +349 +351 +411 +46 +468 +280 +446 +67 +368 +390 +380 +368 +118 +411 +403 +explain select a+0, b+0 from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 5 NULL 38 Using index +select a+0, b+0 from t1; +a+0 b+0 +0 177 +4 245 +5 178 +9 363 +23 36 +24 398 +28 499 +29 399 +30 83 +31 438 +34 202 +44 307 +49 345 +56 379 +57 135 +59 188 +60 343 +61 152 +68 206 +68 454 +75 42 +77 133 +78 123 +79 349 +87 351 +88 411 +94 46 +94 468 +104 280 +106 446 +108 67 +111 368 +116 390 +118 380 +119 368 +122 118 +123 411 +127 403 +explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 2 NULL 1 Using where; Using index; Using filesort +select a+0, b+0 from t1 where a > 40 and b > 200 order by 1; +a+0 b+0 +44 307 +49 345 +56 379 +60 343 +68 206 +68 454 +79 349 +87 351 +88 411 +94 468 +104 280 +106 446 +111 368 +116 390 +118 380 +119 368 +123 411 +127 403 +explain select a+0, b+0 from t1 where a > 40 and a < 70 order by 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 2 NULL 1 Using where; Using index; Using filesort +select a+0, b+0 from t1 where a > 40 and a < 70 order by 2; +a+0 b+0 +57 135 +61 152 +59 188 +68 206 +44 307 +60 343 +49 345 +56 379 +68 454 +set @@max_length_for_sort_data=0; +Warnings: +Warning 1292 Truncated incorrect max_length_for_sort_data value: '0' +select a+0, b+0 from t1 where a > 40 and a < 70 order by 2; +a+0 b+0 +57 135 +61 152 +59 188 +68 206 +44 307 +60 343 +49 345 +56 379 +68 454 +select hex(min(a)) from t1; +hex(min(a)) +0 +select hex(min(b)) from t1; +hex(min(b)) +24 +select hex(min(a)), hex(max(a)), hex(min(b)), hex(max(b)) from t1; +hex(min(a)) hex(max(a)) hex(min(b)) hex(max(b)) +0 7F 24 1F3 +drop table t1; +create table t1 (a int not null, b bit, c bit(9), key(a, b, c)); +insert into t1 values +(4, NULL, 1), (4, 0, 3), (2, 1, 4), (1, 1, 100), (4, 0, 23), (4, 0, 54), +(56, 0, 22), (4, 1, 100), (23, 0, 1), (4, 0, 34); +select a+0, b+0, c+0 from t1; +a+0 b+0 c+0 +1 1 100 +2 1 4 +4 NULL 1 +4 0 3 +4 0 23 +4 0 34 +4 0 54 +4 1 100 +23 0 1 +56 0 22 +select hex(min(b)) from t1 where a = 4; +hex(min(b)) +0 +select hex(min(c)) from t1 where a = 4 and b = 0; +hex(min(c)) +3 +select hex(max(b)) from t1; +hex(max(b)) +1 +select a+0, b+0, c+0 from t1 where a = 4 and b = 0 limit 2; +a+0 b+0 c+0 +4 0 3 +4 0 23 +select a+0, b+0, c+0 from t1 where a = 4 and b = 1; +a+0 b+0 c+0 +4 1 100 +select a+0, b+0, c+0 from t1 where a = 4 and b = 1 and c=100; +a+0 b+0 c+0 +4 1 100 +select a+0, b+0, c+0 from t1 order by b desc; +a+0 b+0 c+0 +2 1 4 +1 1 100 +4 1 100 +4 0 3 +4 0 23 +4 0 54 +56 0 22 +23 0 1 +4 0 34 +4 NULL 1 +select a+0, b+0, c+0 from t1 order by c; +a+0 b+0 c+0 +4 NULL 1 +23 0 1 +4 0 3 +2 1 4 +56 0 22 +4 0 23 +4 0 34 +4 0 54 +1 1 100 +4 1 100 +drop table t1; +create table t1(a bit(2), b bit(2)); +insert into t1 (a) values (0x01), (0x03), (0x02); +update t1 set b= concat(a); +select a+0, b+0 from t1; +a+0 b+0 +1 1 +3 3 +2 2 +drop table t1; +create table t1 (a bit(7), key(a)); +insert into t1 values (44), (57); +select a+0 from t1; +a+0 +44 +57 +drop table t1; +create table t1 (a bit(3), b bit(12)); +insert into t1 values (7,(1<<12)-2), (0x01,0x01ff); +select hex(a),hex(b) from t1; +hex(a) hex(b) +7 FFE +1 1FF +select hex(concat(a)),hex(concat(b)) from t1; +hex(concat(a)) hex(concat(b)) +07 0FFE +01 01FF +drop table t1; +create table t1(a int, b bit not null); +alter table t1 add primary key (a); +drop table t1; +create table t1 (a bit(19), b bit(5)); +insert into t1 values (1000, 10), (3, 8), (200, 6), (2303, 2), (12345, 4), (1, 0); +select a+0, b+0 from t1; +a+0 b+0 +1000 10 +3 8 +200 6 +2303 2 +12345 4 +1 0 +alter table t1 engine=heap; +select a+0, b+0 from t1; +a+0 b+0 +1000 10 +3 8 +200 6 +2303 2 +12345 4 +1 0 +alter table t1 add key(a, b); +select a+0, b+0 from t1; +a+0 b+0 +1000 10 +3 8 +200 6 +2303 2 +12345 4 +1 0 +alter table t1 engine=myisam; +select a+0, b+0 from t1; +a+0 b+0 +1 0 +3 8 +200 6 +1000 10 +2303 2 +12345 4 +create table t2 engine=heap select * from t1; +select a+0, b+0 from t2; +a+0 b+0 +1 0 +3 8 +200 6 +1000 10 +2303 2 +12345 4 +drop table t1; +create table t1 select * from t2; +select a+0, b+0 from t1; +a+0 b+0 +1 0 +3 8 +200 6 +1000 10 +2303 2 +12345 4 +drop table t1, t2; +create table t1 (a int, b time, c tinyint, d bool, e char(10), f bit(1), +g bit(1) NOT NULL default 1, h char(1) default 'a'); +insert into t1 set a=1; +select hex(g), h from t1; +hex(g) h +1 a +drop table t1; +create table t1 (a int, b time, c tinyint, d bool, e char(10), f bit(1), +g bit(1) NOT NULL default 1); +insert into t1 set a=1; +select hex(g) from t1; +hex(g) +1 +drop table t1; +create table t1 (a int, b time, c tinyint, d bool, e char(10), f bit(1), +h char(1) default 'a') engine=myisam; +insert into t1 set a=1; +select h from t1; +h +a +drop table t1; +create table t1 (a bit(8)) engine=heap; +insert into t1 values ('1111100000'); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select a+0 from t1; +a+0 +255 +drop table t1; +create table t1 (a bit(7)); +insert into t1 values (120), (0), (111); +select a+0 from t1 union select a+0 from t1; +a+0 +120 +0 +111 +select a+0 from t1 union select NULL; +a+0 +120 +0 +111 +NULL +select NULL union select a+0 from t1; +NULL +NULL +120 +0 +111 +create table t2 select a from t1 union select a from t1; +select a+0 from t2; +a+0 +120 +0 +111 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bit(7) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1, t2; +create table t1 (id1 int(11), b1 bit(1)); +create table t2 (id2 int(11), b2 bit(1)); +insert into t1 values (1, 1), (2, 0), (3, 1); +insert into t2 values (2, 1), (3, 0), (4, 0); +create algorithm=undefined view v1 as +select b1+0, b2+0 from t1, t2 where id1 = id2 and b1 = 0 +union +select b1+0, b2+0 from t1, t2 where id1 = id2 and b2 = 1; +select * from v1; +b1+0 b2+0 +0 1 +drop table t1, t2; +drop view v1; +create table t1(a bit(4)); +insert into t1(a) values (1), (2), (5), (4), (3); +insert into t1 select * from t1; +select a+0 from t1; +a+0 +1 +2 +5 +4 +3 +1 +2 +5 +4 +3 +drop table t1; +create table t1 (a1 int(11), b1 bit(2)); +create table t2 (a2 int(11), b2 bit(2)); +insert into t1 values (1, 1), (2, 0), (3, 1), (4, 2); +insert into t2 values (2, 1), (3, 0), (4, 1), (5, 2); +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2; +a1 a2 b1+0 b2+0 +2 2 0 1 +3 3 1 0 +4 4 2 1 +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1; +a1 a2 b1+0 b2+0 +2 2 0 1 +3 3 1 0 +4 4 2 1 +select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2; +a1 a2 b1+0 b2+0 +1 2 1 1 +3 2 1 1 +2 3 0 0 +1 4 1 1 +3 4 1 1 +4 5 2 2 +select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1; +sum(a1) b1+0 b2+0 +2 0 0 +4 2 2 +8 1 1 +select 1 from t1 join t2 on b1 = b2 group by b1 order by 1; +1 +1 +1 +1 +select b1+0,sum(b1), sum(b2) from t1 join t2 on b1 = b2 group by b1 order by 1; +b1+0 sum(b1) sum(b2) +0 0 0 +1 4 4 +2 2 2 +drop table t1, t2; +create table t1 (a bit(7)); +insert into t1 values (0x60); +select * from t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 a a 16 7 1 Y 32 0 63 +a +` +drop table t1; +create table bug15583(b BIT(8), n INT); +insert into bug15583 values(128, 128); +insert into bug15583 values(null, null); +insert into bug15583 values(0, 0); +insert into bug15583 values(255, 255); +select hex(b), bin(b), oct(b), hex(n), bin(n), oct(n) from bug15583; +hex(b) bin(b) oct(b) hex(n) bin(n) oct(n) +80 10000000 200 80 10000000 200 +NULL NULL NULL NULL NULL NULL +0 0 0 0 0 0 +FF 11111111 377 FF 11111111 377 +select hex(b)=hex(n) as should_be_onetrue, bin(b)=bin(n) as should_be_onetrue, oct(b)=oct(n) as should_be_onetrue from bug15583; +should_be_onetrue should_be_onetrue should_be_onetrue +1 1 1 +NULL NULL NULL +1 1 1 +1 1 1 +select hex(b + 0), bin(b + 0), oct(b + 0), hex(n), bin(n), oct(n) from bug15583; +hex(b + 0) bin(b + 0) oct(b + 0) hex(n) bin(n) oct(n) +80 10000000 200 80 10000000 200 +NULL NULL NULL NULL NULL NULL +0 0 0 0 0 0 +FF 11111111 377 FF 11111111 377 +select conv(b, 10, 2), conv(b + 0, 10, 2) from bug15583; +conv(b, 10, 2) conv(b + 0, 10, 2) +10000000 10000000 +NULL NULL +0 0 +11111111 11111111 +drop table bug15583; +create table t1(a bit(1), b smallint unsigned); +insert into t1 (b, a) values ('2', '1'); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select hex(a), b from t1; +hex(a) b +1 2 +drop table t1; +create table t1(bit_field bit(2), int_field int, key a(bit_field)); +insert into t1 values (1,2); +handler t1 open as t1; +handler t1 read a=(1); +bit_field int_field + 2 +handler t1 close; +drop table t1; +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/type_date.result b/mysql-test/suite/pbxt/r/type_date.result new file mode 100644 index 00000000000..644d4d971c6 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_date.result @@ -0,0 +1,112 @@ +drop table if exists t1,t2; +create table t1 (a char(16), b date, c datetime); +insert into t1 SET a='test 2000-01-01', b='2000-01-01', c='2000-01-01'; +select * from t1 where c = '2000-01-01'; +a b c +test 2000-01-01 2000-01-01 2000-01-01 00:00:00 +select * from t1 where b = '2000-01-01'; +a b c +test 2000-01-01 2000-01-01 2000-01-01 00:00:00 +drop table t1; +CREATE TABLE t1 (name char(6),cdate date); +INSERT INTO t1 VALUES ('name1','1998-01-01'); +INSERT INTO t1 VALUES ('name2','1998-01-01'); +INSERT INTO t1 VALUES ('name1','1998-01-02'); +INSERT INTO t1 VALUES ('name2','1998-01-02'); +CREATE TABLE t2 (cdate date, note char(6)); +INSERT INTO t2 VALUES ('1998-01-01','note01'); +INSERT INTO t2 VALUES ('1998-01-02','note02'); +select name,t1.cdate,note from t1,t2 where t1.cdate=t2.cdate and t1.cdate='1998-01-01'; +name cdate note +name1 1998-01-01 note01 +name2 1998-01-01 note01 +drop table t1,t2; +CREATE TABLE t1 ( datum DATE ); +INSERT INTO t1 VALUES ( "2000-1-1" ); +INSERT INTO t1 VALUES ( "2000-1-2" ); +INSERT INTO t1 VALUES ( "2000-1-3" ); +INSERT INTO t1 VALUES ( "2000-1-4" ); +INSERT INTO t1 VALUES ( "2000-1-5" ); +SELECT * FROM t1 WHERE datum BETWEEN cast("2000-1-2" as date) AND cast("2000-1-4" as date); +datum +2000-01-02 +2000-01-03 +2000-01-04 +SELECT * FROM t1 WHERE datum BETWEEN cast("2000-1-2" as date) AND datum - INTERVAL 100 DAY; +datum +DROP TABLE t1; +CREATE TABLE t1 ( +user_id char(10), +summa int(11), +rdate date +); +INSERT INTO t1 VALUES ('aaa',100,'1998-01-01'); +INSERT INTO t1 VALUES ('aaa',200,'1998-01-03'); +INSERT INTO t1 VALUES ('bbb',50,'1998-01-02'); +INSERT INTO t1 VALUES ('bbb',200,'1998-01-04'); +select max(rdate) as s from t1 where rdate < '1998-01-03' having s> "1998-01-01"; +s +1998-01-02 +select max(rdate) as s from t1 having s="1998-01-04"; +s +1998-01-04 +select max(rdate+0) as s from t1 having s="19980104"; +s +19980104 +drop table t1; +create table t1 (date date); +insert into t1 values ("2000-08-10"),("2000-08-11"); +select date_add(date,INTERVAL 1 DAY),date_add(date,INTERVAL 1 SECOND) from t1; +date_add(date,INTERVAL 1 DAY) date_add(date,INTERVAL 1 SECOND) +2000-08-11 2000-08-10 00:00:01 +2000-08-12 2000-08-11 00:00:01 +drop table t1; +CREATE TABLE t1(AFIELD INT); +INSERT INTO t1 VALUES(1); +CREATE TABLE t2(GMT VARCHAR(32)); +INSERT INTO t2 VALUES('GMT-0800'); +SELECT DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) FROM t1, t2 GROUP BY t1.AFIELD; +DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) +Wed, 06 March 2002 10:11:12 GMT-0800 +INSERT INTO t1 VALUES(1); +SELECT DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)), DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) FROM t1,t2 GROUP BY t1.AFIELD; +DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) +Wed, 06 March 2002 10:11:12 GMT-0800 Wed, 06 March 2002 10:11:12 GMT-0800 +drop table t1,t2; +CREATE TABLE t1 (f1 time default NULL, f2 time default NULL); +INSERT INTO t1 (f1, f2) VALUES ('09:00', '12:00'); +SELECT DATE_FORMAT(f1, "%l.%i %p") , DATE_FORMAT(f2, "%l.%i %p") FROM t1; +DATE_FORMAT(f1, "%l.%i %p") DATE_FORMAT(f2, "%l.%i %p") +9.00 AM 12.00 PM +DROP TABLE t1; +CREATE TABLE t1 (f1 DATE); +CREATE TABLE t2 (f2 VARCHAR(8)); +CREATE TABLE t3 (f2 CHAR(8)); +INSERT INTO t1 VALUES ('1978-11-26'); +INSERT INTO t2 SELECT f1+0 FROM t1; +INSERT INTO t2 SELECT f1+0 FROM t1 UNION SELECT f1+0 FROM t1; +INSERT INTO t3 SELECT f1+0 FROM t1; +INSERT INTO t3 SELECT f1+0 FROM t1 UNION SELECT f1+0 FROM t1; +SELECT * FROM t2; +f2 +19781126 +19781126 +SELECT * FROM t3; +f2 +19781126 +19781126 +DROP TABLE t1, t2, t3; +CREATE TABLE t1 (y YEAR); +INSERT INTO t1 VALUES ('abc'); +Warnings: +Warning 1366 Incorrect integer value: 'abc' for column 'y' at row 1 +SELECT * FROM t1; +y +0000 +DROP TABLE t1; +create table t1(start_date date, end_date date); +insert into t1 values ('2000-01-01','2000-01-02'); +select 1 from t1 where cast('2000-01-01 12:01:01' as datetime) between start_date and end_date; +1 +1 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/type_datetime.result b/mysql-test/suite/pbxt/r/type_datetime.result new file mode 100644 index 00000000000..4ad10269211 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_datetime.result @@ -0,0 +1,194 @@ +drop table if exists t1; +create table t1 (t datetime); +insert into t1 values (101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030100000000),(20030000000000); +select * from t1; +t +2000-01-01 00:00:00 +2069-12-31 00:00:00 +1970-01-01 00:00:00 +1999-12-31 00:00:00 +1000-01-01 00:00:00 +9999-12-31 00:00:00 +2000-01-01 00:00:00 +2069-12-31 00:00:00 +1970-01-01 00:00:00 +1999-12-31 23:59:59 +1000-01-01 00:00:00 +9999-12-31 23:59:59 +2003-01-00 00:00:00 +2003-00-00 00:00:00 +delete from t1 where t > 0; +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +delete from t1; +insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030100000000"),("20030000000000"); +insert into t1 values ("2003-003-03"); +insert into t1 values ("20030102T131415"),("2001-01-01T01:01:01"), ("2001-1-1T1:01:01"); +select * from t1; +t +2000-01-01 00:00:00 +2069-12-31 00:00:00 +1970-01-01 00:00:00 +1999-12-31 00:00:00 +0000-01-01 00:00:00 +0001-01-01 00:00:00 +9999-12-31 00:00:00 +2000-10-10 00:00:00 +2069-12-31 00:00:00 +1970-01-01 00:00:00 +1999-12-31 23:59:59 +1000-01-01 00:00:00 +9999-12-31 23:59:59 +2003-01-00 00:00:00 +2003-00-00 00:00:00 +2003-03-03 00:00:00 +2003-01-02 13:14:15 +2001-01-01 01:01:01 +2001-01-01 01:01:01 +truncate table t1; +insert into t1 values("2003-0303 12:13:14"); +Warnings: +Warning 1264 Out of range value for column 't' at row 1 +select * from t1; +t +0000-00-00 00:00:00 +drop table t1; +CREATE TABLE t1 (a timestamp, b date, c time, d datetime); +insert into t1 (b,c,d) values(now(),curtime(),now()); +Warnings: +Note 1265 Data truncated for column 'b' at row 1 +select date_format(a,"%Y-%m-%d")=b,right(a+0,6)=c+0,a=d+0 from t1; +date_format(a,"%Y-%m-%d")=b right(a+0,6)=c+0 a=d+0 +1 1 1 +drop table t1; +CREATE TABLE t1 (a datetime not null); +insert into t1 values (0); +select * from t1 where a is null; +a +0000-00-00 00:00:00 +drop table t1; +create table t1 (id int, dt datetime); +insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00"),(4,"2003-09-15 01:20:30"); +select * from t1 where dt='2001-08-14 00:00:00' and dt = if(id=1,'2001-08-14 00:00:00','1999-08-15'); +id dt +1 2001-08-14 00:00:00 +create index dt on t1 (dt); +select * from t1 where dt > 20021020; +id dt +4 2003-09-15 01:20:30 +select * from t1 ignore index (dt) where dt > 20021020; +id dt +4 2003-09-15 01:20:30 +drop table t1; +CREATE TABLE `t1` ( +`date` datetime NOT NULL default '0000-00-00 00:00:00', +`numfacture` int(6) unsigned NOT NULL default '0', +`expedition` datetime NOT NULL default '0000-00-00 00:00:00', +PRIMARY KEY (`numfacture`), +KEY `date` (`date`), +KEY `expedition` (`expedition`) +) ENGINE=MyISAM; +INSERT INTO t1 (expedition) VALUES ('0001-00-00 00:00:00'); +SELECT * FROM t1 WHERE expedition='0001-00-00 00:00:00'; +date numfacture expedition +0000-00-00 00:00:00 0 0001-00-00 00:00:00 +INSERT INTO t1 (numfacture,expedition) VALUES ('1212','0001-00-00 00:00:00'); +SELECT * FROM t1 WHERE expedition='0001-00-00 00:00:00'; +date numfacture expedition +0000-00-00 00:00:00 0 0001-00-00 00:00:00 +0000-00-00 00:00:00 1212 0001-00-00 00:00:00 +EXPLAIN SELECT * FROM t1 WHERE expedition='0001-00-00 00:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref expedition expedition 8 const 1 +drop table t1; +create table t1 (a datetime not null, b datetime not null); +insert into t1 values (now(), now()); +insert into t1 values (now(), now()); +select * from t1 where a is null or b is null; +a b +drop table t1; +create table t1 (t datetime); +insert into t1 values (20030102030460),(20030102036301),(20030102240401), +(20030132030401),(20031302030401),(100001202030401); +Warnings: +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't' at row 2 +Warning 1264 Out of range value for column 't' at row 3 +Warning 1264 Out of range value for column 't' at row 4 +Warning 1264 Out of range value for column 't' at row 5 +Warning 1264 Out of range value for column 't' at row 6 +select * from t1; +t +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +delete from t1; +insert into t1 values +("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"), +("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00"); +Warnings: +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't' at row 2 +Warning 1264 Out of range value for column 't' at row 3 +Warning 1264 Out of range value for column 't' at row 4 +Warning 1264 Out of range value for column 't' at row 5 +Warning 1264 Out of range value for column 't' at row 6 +select * from t1; +t +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +delete from t1; +insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer"); +Warnings: +Warning 1264 Out of range value for column 't' at row 1 +Warning 1264 Out of range value for column 't' at row 2 +select * from t1 order by t; +t +0000-00-00 00:00:00 +2003-01-01 00:00:00 +drop table t1; +create table t1 (dt datetime); +insert into t1 values ("12-00-00"), ("00-00-00 01:00:00"); +insert into t1 values ("00-00-00"), ("00-00-00 00:00:00"); +select * from t1; +dt +2012-00-00 00:00:00 +2000-00-00 01:00:00 +0000-00-00 00:00:00 +0000-00-00 00:00:00 +drop table t1; +CREATE TABLE t1(a DATETIME NOT NULL); +INSERT INTO t1 VALUES ('20060606155555'); +SELECT a FROM t1 WHERE a=(SELECT MAX(a) FROM t1) AND (a="20060606155555"); +a +2006-06-06 15:55:55 +PREPARE s FROM 'SELECT a FROM t1 WHERE a=(SELECT MAX(a) FROM t1) AND (a="20060606155555")'; +EXECUTE s; +a +2006-06-06 15:55:55 +DROP PREPARE s; +DROP TABLE t1; +SELECT CAST(CAST('2006-08-10' AS DATE) AS DECIMAL(20,6)); +CAST(CAST('2006-08-10' AS DATE) AS DECIMAL(20,6)) +20060810.000000 +SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) AS DECIMAL(20,6)); +CAST(CAST('2006-08-10 10:11:12' AS DATETIME) AS DECIMAL(20,6)) +20060810101112.000000 +SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) + INTERVAL 14 MICROSECOND AS DECIMAL(20,6)); +CAST(CAST('2006-08-10 10:11:12' AS DATETIME) + INTERVAL 14 MICROSECOND AS DECIMAL(20,6)) +20060810101112.000014 +SELECT CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6)); +CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6)) +101112.098700 diff --git a/mysql-test/suite/pbxt/r/type_decimal.result b/mysql-test/suite/pbxt/r/type_decimal.result new file mode 100644 index 00000000000..a478a369404 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_decimal.result @@ -0,0 +1,788 @@ +DROP TABLE IF EXISTS t1, t2; +SET SQL_WARNINGS=1; +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +datatype_id int(11) DEFAULT '0' NOT NULL, +minvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL, +maxvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL, +valuename varchar(20), +forecolor int(11), +backcolor int(11), +PRIMARY KEY (id), +UNIQUE datatype_id (datatype_id, minvalue, maxvalue) +); +INSERT INTO t1 VALUES ( '1', '4', '0.0000000000', '0.0000000000', 'Ei saja', '0', '16776960'); +INSERT INTO t1 VALUES ( '2', '4', '1.0000000000', '1.0000000000', 'Sajab', '16777215', '255'); +INSERT INTO t1 VALUES ( '3', '1', '2.0000000000', '49.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '60', '11', '0.0000000000', '0.0000000000', 'Rikkis', '16777215', '16711680'); +INSERT INTO t1 VALUES ( '4', '12', '1.0000000000', '1.0000000000', 'nork sadu', '65280', '14474460'); +INSERT INTO t1 VALUES ( '5', '12', '2.0000000000', '2.0000000000', 'keskmine sadu', '255', '14474460'); +INSERT INTO t1 VALUES ( '6', '12', '3.0000000000', '3.0000000000', 'tugev sadu', '127', '14474460'); +INSERT INTO t1 VALUES ( '43', '39', '6.0000000000', '6.0000000000', 'lobjakas', '13107327', '16763080'); +INSERT INTO t1 VALUES ( '40', '39', '2.0000000000', '2.0000000000', 'vihm', '8355839', '16777215'); +INSERT INTO t1 VALUES ( '53', '1', '-35.0000000000', '-5.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '41', '39', '3.0000000000', '3.0000000000', 'külm vihm', '120', '16763080'); +INSERT INTO t1 VALUES ( '12', '21', '21.0000000000', '21.0000000000', 'Kuiv', '13158600', '16777215'); +INSERT INTO t1 VALUES ( '13', '21', '13.0000000000', '13.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '14', '21', '22.0000000000', '22.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '19', '21', '33.0000000000', '33.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '15', '21', '23.0000000000', '23.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '16', '21', '31.0000000000', '31.0000000000', 'Kuiv', '13158600', '16777215'); +INSERT INTO t1 VALUES ( '17', '21', '12.0000000000', '12.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '18', '21', '32.0000000000', '32.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '20', '21', '331.0000000000', '331.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '21', '21', '11.0000000000', '11.0000000000', 'Kuiv', '13158600', '16777215'); +INSERT INTO t1 VALUES ( '22', '33', '21.0000000000', '21.0000000000', 'Pilves, kuiv', '8355711', '12632256'); +INSERT INTO t1 VALUES ( '23', '33', '13.0000000000', '13.0000000000', 'Sajab, märg', '0', '8355839'); +INSERT INTO t1 VALUES ( '24', '33', '22.0000000000', '22.0000000000', 'Pilves, niiske', '8355711', '12632319'); +INSERT INTO t1 VALUES ( '29', '33', '33.0000000000', '33.0000000000', 'Selge, märg', '16777215', '8355839'); +INSERT INTO t1 VALUES ( '25', '33', '23.0000000000', '23.0000000000', 'Pilves, märg', '8355711', '8355839'); +INSERT INTO t1 VALUES ( '26', '33', '31.0000000000', '31.0000000000', 'Selge, kuiv', '16777215', '12632256'); +INSERT INTO t1 VALUES ( '27', '33', '12.0000000000', '12.0000000000', 'Sajab, niiske', '0', '12632319'); +INSERT INTO t1 VALUES ( '28', '33', '32.0000000000', '32.0000000000', 'Selge, niiske', '16777215', '12632319'); +INSERT INTO t1 VALUES ( '30', '33', '331.0000000000', '331.0000000000', 'Härmatis! selge,kuiv', '16711680', '12632256'); +INSERT INTO t1 VALUES ( '31', '33', '11.0000000000', '11.0000000000', 'Sajab, kuiv', '0', '12632256'); +INSERT INTO t1 VALUES ( '32', '11', '1.0000000000', '1.0000000000', 'Korras', '16777215', '49152'); +INSERT INTO t1 VALUES ( '33', '21', '335.0000000000', '335.0000000000', 'Härmatis!', '14448840', '11842740'); +INSERT INTO t1 VALUES ( '34', '21', '134.0000000000', '134.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '35', '21', '133.0000000000', '133.0000000000', 'Hoiatus, märg!', '5263615', '13158600'); +INSERT INTO t1 VALUES ( '36', '21', '135.0000000000', '135.0000000000', 'Härmatis!', '14448840', '11842740'); +INSERT INTO t1 VALUES ( '37', '21', '334.0000000000', '334.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '38', '21', '132.0000000000', '132.0000000000', 'Hoiatus, niiske!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '39', '39', '1.0000000000', '1.0000000000', 'ei saja', '11206570', '16777215'); +INSERT INTO t1 VALUES ( '44', '39', '4.0000000000', '5.0000000000', 'lumi', '16711680', '16763080'); +INSERT INTO t1 VALUES ( '45', '12', '0.0000000000', '0.0000000000', '', '16777215', '14474460'); +INSERT INTO t1 VALUES ( '46', '39', '8.0000000000', '8.0000000000', 'rahe', '9830400', '16763080'); +INSERT INTO t1 VALUES ( '47', '39', '9.0000000000', '9.0000000000', 'tüüp ebaselge', '12582912', '16777215'); +INSERT INTO t1 VALUES ( '48', '39', '7.0000000000', '7.0000000000', 'lumetuisk', '7209070', '16763080'); +INSERT INTO t1 VALUES ( '142', '15', '2.0000000000', '49.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '52', '1', '-4.9000000000', '-0.1000000000', '', '0', '15774720'); +INSERT INTO t1 VALUES ( '141', '15', '-4.9000000000', '-0.1000000000', '', '0', '15774720'); +INSERT INTO t1 VALUES ( '55', '8', '0.0000000000', '0.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '56', '8', '0.0100000000', '0.1000000000', '', '0', '16770560'); +INSERT INTO t1 VALUES ( '57', '8', '0.1100000000', '25.0000000000', '', '0', '15774720'); +INSERT INTO t1 VALUES ( '58', '2', '90.0000000000', '94.9000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '59', '6', '0.0000000000', '360.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '61', '21', '38.0000000000', '38.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '62', '38', '500.0000000000', '999.0000000000', '', '0', '16770560'); +INSERT INTO t1 VALUES ( '63', '38', '1000.0000000000', '2000.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '64', '17', '0.0000000000', '0.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '65', '17', '0.1000000000', '10.0000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '67', '21', '412.0000000000', '412.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '68', '21', '413.0000000000', '413.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '69', '21', '113.0000000000', '113.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '70', '21', '416.0000000000', '416.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '71', '38', '0.0000000000', '499.0000000000', '', NULL, '16711680'); +INSERT INTO t1 VALUES ( '72', '22', '-49.0000000000', '49.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '73', '13', '0.0000000000', '9.9000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '74', '13', '10.0000000000', '14.9000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '75', '7', '0.0000000000', '50.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '76', '18', '0.0000000000', '0.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '77', '18', '0.1000000000', '10.0000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '78', '19', '300.0000000000', '400.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '79', '19', '0.0000000000', '299.0000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '80', '23', '0.0000000000', '100.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '81', '24', '0.0000000000', '200.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '82', '26', '0.0000000000', '0.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '83', '26', '0.1000000000', '5.0000000000', '', NULL, '16776960'); +INSERT INTO t1 VALUES ( '84', '21', '422.0000000000', '422.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '85', '21', '411.0000000000', '411.0000000000', 'Saju hoiat.,kuiv!', '16777215', '13158600'); +INSERT INTO t1 VALUES ( '86', '21', '423.0000000000', '423.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '144', '16', '-49.0000000000', '-5.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '88', '16', '2.0000000000', '49.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '89', '21', '338.0000000000', '338.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '90', '21', '332.0000000000', '332.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '91', '21', '114.0000000000', '114.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '92', '21', '117.0000000000', '117.0000000000', 'Hoiatus, JÄÄ!', '14448840', '16711680'); +INSERT INTO t1 VALUES ( '93', '21', '116.0000000000', '116.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '94', '21', '414.0000000000', '414.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '95', '21', '325.0000000000', '325.0000000000', 'Härmatis!', '14448840', '11842740'); +INSERT INTO t1 VALUES ( '96', '21', '321.0000000000', '321.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '97', '21', '328.0000000000', '328.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '98', '21', '28.0000000000', '28.0000000000', 'Niiske ja sool', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '99', '21', '118.0000000000', '118.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '100', '21', '418.0000000000', '418.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '101', '21', '322.0000000000', '322.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '102', '21', '428.0000000000', '428.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '103', '21', '432.0000000000', '432.0000000000', 'Hoiatus, niiske!', '7895240', '13158600'); +INSERT INTO t1 VALUES ( '104', '21', '421.0000000000', '421.0000000000', 'Saju hoiat.,kuiv!', '16777215', '13158600'); +INSERT INTO t1 VALUES ( '105', '21', '24.0000000000', '24.0000000000', 'Märg ja sool', '255', '16777215'); +INSERT INTO t1 VALUES ( '106', '21', '438.0000000000', '438.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '107', '21', '112.0000000000', '112.0000000000', 'Hoiatus, niiske!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '108', '21', '34.0000000000', '34.0000000000', 'Märg ja sool', '255', '16777215'); +INSERT INTO t1 VALUES ( '109', '21', '434.0000000000', '434.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '110', '21', '124.0000000000', '124.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '111', '21', '424.0000000000', '424.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '112', '21', '123.0000000000', '123.0000000000', 'Hoiatus, märg!', '5263615', '13158600'); +INSERT INTO t1 VALUES ( '140', '15', '-49.0000000000', '-5.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '114', '21', '18.0000000000', '18.0000000000', 'Niiske ja sool', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '115', '21', '122.0000000000', '122.0000000000', 'Hoiatus, niiske!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '116', '21', '14.0000000000', '14.0000000000', 'Märg ja sool', '255', '16777215'); +INSERT INTO t1 VALUES ( '117', '21', '311.0000000000', '311.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '121', '2', '95.0000000000', '100.0000000000', '', NULL, '15774720'); +INSERT INTO t1 VALUES ( '118', '2', '0.0000000000', '89.9000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '119', '21', '16.0000000000', '16.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '120', '21', '26.0000000000', '26.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '122', '13', '15.0000000000', '50.0000000000', '', NULL, '15774720'); +INSERT INTO t1 VALUES ( '123', '5', '0.0000000000', '9.9000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '124', '5', '10.0000000000', '14.9000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '125', '5', '15.0000000000', '50.0000000000', '', NULL, '15774720'); +INSERT INTO t1 VALUES ( '126', '21', '128.0000000000', '128.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '127', '21', '318.0000000000', '318.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '128', '21', '312.0000000000', '312.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '129', '21', '126.0000000000', '126.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '130', '21', '324.0000000000', '324.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '131', '21', '316.0000000000', '316.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '132', '1', '0.0000000000', '1.9000000000', '', NULL, '16769024'); +INSERT INTO t1 VALUES ( '134', '3', '-50.0000000000', '50.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '135', '8', '26.0000000000', '2000.0000000000', '', '9868950', '15774720'); +INSERT INTO t1 VALUES ( '136', '21', '426.0000000000', '426.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '137', '21', '127.0000000000', '127.0000000000', 'Hoiatus, JÄÄ!', '14448840', '16711680'); +INSERT INTO t1 VALUES ( '138', '21', '121.0000000000', '121.0000000000', 'Kuiv', '13158600', '16777215'); +INSERT INTO t1 VALUES ( '139', '21', '326.0000000000', '326.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '143', '16', '-4.9000000000', '-0.1000000000', '', NULL, '15774720'); +INSERT INTO t1 VALUES ( '145', '15', '0.0000000000', '1.9000000000', '', '0', '16769024'); +INSERT INTO t1 VALUES ( '146', '16', '0.0000000000', '1.9000000000', '', '0', '16769024'); +select * from t1 where minvalue<=1 and maxvalue>=-1 and datatype_id=16; +id datatype_id minvalue maxvalue valuename forecolor backcolor +143 16 -4.9000000000 -0.1000000000 NULL 15774720 +146 16 0.0000000000 1.9000000000 0 16769024 +select * from t1 where minvalue<=-1 and maxvalue>=-1 and datatype_id=16; +id datatype_id minvalue maxvalue valuename forecolor backcolor +143 16 -4.9000000000 -0.1000000000 NULL 15774720 +drop table t1; +create table t1 (a decimal(10,2)); +insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0"); +insert into t1 values ("-.1"),("+.1"),(".1"); +insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); +insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("1e+4294967296"),("1e-4294967296"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 2 +insert into t1 values ("1e+18446744073709551615"),("1e+18446744073709551616"),("1e-9223372036854775807"),("1e-9223372036854775809"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1366 Incorrect decimal value: '1e+18446744073709551616' for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 3 +Warning 1366 Incorrect decimal value: '1e-9223372036854775809' for column 'a' at row 4 +insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); +Warnings: +Note 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 3 +select * from t1; +a +0.00 +0.00 +0.00 +1.00 +1.00 +-1.00 +-0.10 +0.10 +0.10 +1.00 +1.00 +-1.00 +99999999.99 +99999999.99 +-11111111.11 +-99999999.99 +99999999.99 +99999999.99 +99999999.99 +0.00 +-99999999.99 +99999999.99 +0.00 +99999999.99 +0.00 +0.00 +0.00 +123.40 +12340.00 +1.23 +1230.00 +123.00 +drop table t1; +create table t1 (a decimal(10,2) unsigned); +insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 6 +insert into t1 values ("-.1"),("+.1"),(".1"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); +Warnings: +Note 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 3 +select * from t1; +a +0.00 +0.00 +0.00 +1.00 +1.00 +0.00 +0.00 +0.10 +0.10 +1.00 +1.00 +0.00 +99999999.99 +99999999.99 +0.00 +0.00 +99999999.99 +99999999.99 +99999999.99 +0.00 +0.00 +123.40 +12340.00 +1.23 +1230.00 +123.00 +drop table t1; +create table t1 (a decimal(10,2) zerofill); +insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 6 +insert into t1 values ("-.1"),("+.1"),(".1"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); +Warnings: +Note 1265 Data truncated for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 3 +select * from t1; +a +00000000.00 +00000000.00 +00000000.00 +00000001.00 +00000001.00 +00000000.00 +00000000.00 +00000000.10 +00000000.10 +00000001.00 +00000001.00 +00000000.00 +99999999.99 +99999999.99 +00000000.00 +00000000.00 +99999999.99 +99999999.99 +99999999.99 +00000000.00 +00000000.00 +00000123.40 +00012340.00 +00000001.23 +00001230.00 +00000123.00 +drop table t1; +create table t1 (a decimal(10,2)); +insert into t1 values (0.0),("-0.0"),(+0.0),(01.0),(+01.0),(-01.0); +insert into t1 values (-.1),(+.1),(.1); +insert into t1 values (00000000000001),(+0000000000001),(-0000000000001); +insert into t1 values (+111111111.11),(111111111.11),(-11111111.11); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +insert into t1 values (-111111111.11),(+1111111111.11),(1111111111.11); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values (1e+100),(1e-100),(-1e+100); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0); +Warnings: +Note 1265 Data truncated for column 'a' at row 3 +insert into t1 values (MID("987",1,2)),("987 "),("987.6e+2 "); +select * from t1; +a +0.00 +0.00 +0.00 +1.00 +1.00 +-1.00 +-0.10 +0.10 +0.10 +1.00 +1.00 +-1.00 +99999999.99 +99999999.99 +-11111111.11 +-99999999.99 +99999999.99 +99999999.99 +99999999.99 +0.00 +-99999999.99 +123.40 +12340.00 +1.23 +1230.00 +123.00 +98.00 +987.00 +98760.00 +drop table t1; +create table t1 (a decimal); +insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 6 +Warning 1264 Out of range value for column 'a' at row 7 +select * from t1; +a +-9999999999 +-1 +1 +1 +1 +9999999999 +9999999999 +drop table t1; +create table t1 (a decimal unsigned); +insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 7 +select * from t1; +a +0 +0 +1 +1 +1 +1234567890 +9999999999 +drop table t1; +create table t1 (a decimal zerofill); +insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 7 +select * from t1; +a +0000000000 +0000000000 +0000000001 +0000000001 +0000000001 +1234567890 +9999999999 +drop table t1; +create table t1 (a decimal unsigned zerofill); +insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 7 +select * from t1; +a +0000000000 +0000000000 +0000000001 +0000000001 +0000000001 +1234567890 +9999999999 +drop table t1; +create table t1(a decimal(10,0)); +insert into t1 values ("1e4294967295"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +9999999999 +delete from t1; +insert into t1 values("1e4294967297"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +9999999999 +drop table t1; +CREATE TABLE t1 (a_dec DECIMAL(-1,0)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1,0))' at line 1 +CREATE TABLE t1 (a_dec DECIMAL(-2,1)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-2,1))' at line 1 +CREATE TABLE t1 (a_dec DECIMAL(-1,1)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1,1))' at line 1 +CREATE TABLE t1 (a_dec DECIMAL(0,11)); +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a_dec'). +create table t1(a decimal(7,3)); +insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000'); +select * from t1; +a +1.000 +1.000 +-1.000 +1.000 +1.000 +-1.000 +10.000 +10.000 +-10.000 +10.000 +10.000 +-10.000 +100.000 +100.000 +-100.000 +100.000 +100.000 +-100.000 +1000.000 +1000.000 +-1000.000 +1000.000 +1000.000 +-1000.000 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +9999.999 +9999.999 +-9999.999 +drop table t1; +create table t1(a decimal(7,3) unsigned); +insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000'); +select * from t1; +a +1.000 +1.000 +0.000 +1.000 +1.000 +0.000 +10.000 +10.000 +0.000 +10.000 +10.000 +0.000 +100.000 +100.000 +0.000 +100.000 +100.000 +0.000 +1000.000 +1000.000 +0.000 +1000.000 +1000.000 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +9999.999 +9999.999 +0.000 +drop table t1; +create table t1(a decimal(7,3) zerofill); +insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000'); +select * from t1; +a +0001.000 +0001.000 +0000.000 +0001.000 +0001.000 +0000.000 +0010.000 +0010.000 +0000.000 +0010.000 +0010.000 +0000.000 +0100.000 +0100.000 +0000.000 +0100.000 +0100.000 +0000.000 +1000.000 +1000.000 +0000.000 +1000.000 +1000.000 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +9999.999 +9999.999 +0000.000 +drop table t1; +create table t1(a decimal(10,5), b decimal(10,1)); +insert into t1 values(123.12345, 123.12345); +Warnings: +Note 1265 Data truncated for column 'b' at row 1 +update t1 set b=a; +Warnings: +Note 1265 Data truncated for column 'b' at row 1 +select * from t1; +a b +123.12345 123.1 +drop table t1; +CREATE TABLE t1 +(EMPNUM CHAR(3) NOT NULL, +HOURS DECIMAL(5)); +CREATE TABLE t2 +(EMPNUM CHAR(3) NOT NULL, +HOURS BIGINT); +INSERT INTO t1 VALUES ('E1',40); +INSERT INTO t1 VALUES ('E8',NULL); +INSERT INTO t2 VALUES ('E1',40); +SELECT EMPNUM FROM t1 WHERE HOURS IN (SELECT HOURS FROM t2); +EMPNUM +E1 +SELECT EMPNUM FROM t1 WHERE HOURS IN (SELECT HOURS FROM t1); +EMPNUM +E1 +DROP TABLE t1,t2; +create table t1 (d decimal(64,0)); +insert into t1 values (1); +select * from t1; +d +1 +drop table t1; +create table t1 (d decimal(5)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d` decimal(5,0) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (d decimal); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d` decimal(10,0) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (d decimal(66,0)); +ERROR 42000: Too big precision 66 specified for column 'd'. Maximum is 65. +CREATE TABLE t1 (i INT, d1 DECIMAL(9,2), d2 DECIMAL(9,2)); +INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00), +(2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40), +(2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00), +(4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00), +(5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20), +(6, 0.00, 0.00), (6, -51.40, 0.00); +SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1 GROUP BY i HAVING a <> b; +i a b +6 -51.40 0.00 +SELECT i, ROUND(SUM(d1), 2) AS a, ROUND(SUM(d2), 2) AS b FROM t1 GROUP BY i +HAVING a <> b; +i a b +6 -51.40 0.00 +drop table t1; +create table t1 (c1 varchar(100), c2 longtext); +insert into t1 set c1= 'non PS, 1.0 as constant', c2=1.0; +prepare stmt from "insert into t1 set c1='PS, 1.0 as constant ', c2=1.0"; +execute stmt; +set @a=1.0; +insert into t1 set c1='non PS, 1.0 in parameter', c2=@a; +prepare stmt from "insert into t1 set c1='PS, 1.0 in parameter ', c2=?"; +execute stmt using @a; +select * from t1; +c1 c2 +non PS, 1.0 as constant 1.0 +PS, 1.0 as constant 1.0 +non PS, 1.0 in parameter 1.0 +PS, 1.0 in parameter 1.0 +deallocate prepare stmt; +drop table t1; +create table t1 ( +strippedproductid char(15) not null default '', +zlevelprice decimal(10,2) default null, +primary key (strippedproductid) +); +create table t2 ( +productid char(15) not null default '', +zlevelprice char(21) default null, +primary key (productid) +); +insert into t1 values ('002trans','49.99'); +insert into t1 values ('003trans','39.98'); +insert into t1 values ('004trans','31.18'); +insert INTO t2 SELECT * FROM t1; +select * from t2; +productid zlevelprice +002trans 49.99 +003trans 39.98 +004trans 31.18 +drop table t1, t2; +create table t1 (f1 decimal(5)); +insert into t1 values (40); +flush tables; +select f1 from t1 where f1 in (select f1 from t1); +f1 +40 +drop table t1; +create table t1 as +select from_days(s) as date,t +from (select 1 as s,'t' as t union select null, null ) as sub1; +select group_concat(t) from t1 group by week(date)/10; +group_concat(t) +t +drop table t1; diff --git a/mysql-test/suite/pbxt/r/type_enum.result b/mysql-test/suite/pbxt/r/type_enum.result new file mode 100644 index 00000000000..7cfb227e6c5 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_enum.result @@ -0,0 +1,1783 @@ +DROP TABLE if exists t1; +CREATE TABLE t1 ( +field enum('001001','001004','001010','001018','001019','001020','001021','001027','001028','001029','001030','001031','001100','002003','002004','002005','002007','002008','002009','002012','002013','002014','003002','003003','003004','003005','003006','003007','003008','003009','003010','003011','003012','003013','003014','003015','003016','003017','003018','003019','004002','004003','004005','004006','004007','004008','004010','004012','004014','004016','004017','004020','004021','004022','004023','004024','004025','004026','006002','006004','006006','006010','006011','006012','006013','006014','007001','007002','007003','007004','007005','007006','007007','007008','007009','007010','007011','007012','007013','007014','007015','007016','007017','007018','007019','007020','007021','007022','007023','007024','007025','007026','007027','007028','007029','007030','007031','007032','007033','007034','007035','007036','007037','007038','007039','007040','007043','007044','009001','009002','009004','009005','009006','009007','009008','009009','009010','009011','009012','009013','010002','010003','010004','010005','010006','010007','010008','010009','010010','010011','010012','010013','010015','010016','010017','010018','010019','010020','010021','010022','010023','010024','010025','010026','010027','010028','011001','011002','011003','011004','011006','011012','011013','011014','011015','011016','012017','012018','012019','012023','012027','012028','012029','012030','012031','012032','012033','012034','012035','012036','012037','012038','012039','014001','016002','016003','016004','016007','016010','016011','016016','016019','016020','016021','016022','016023','016024','016026','016027','016028','016029','016030','016031','016032','016033','016034','017002','018001','019002','019004','020001','020003','020004','020005','020006','020007','020008','020009','022001','022002','022003','023001','023002','023003','023004','023005','023006','023007','023008','023010','023011','023012','023017','023019','023020','023021','023025','023026','023027','023028','023029','023030','023031','023032','023033','023034','023035','025001','025003','025004','025005','025006','025007','025008','025009','025010','025011','025012','025013','025014','025015','025016','025017','025018','025019','025020','025021','025022','025023','025024','025025','025026','025027','025028','025029','025030','025031','025032','025033','025034','025035','025036','025037','025038','025039','025040','025041','025042','025043','025044','025045','025046','025047','025048','025049','025050','025051','025052','025053','025054','025055','025056','025057','025058','025059','025060','025061','025062','025063','027001','027002','027011','035008','035012','036001','037001','037003','037004','037005','037006','037007','037008','037009','038004','038005','038006','038007','038009','039001','039002','039003','039004','039005','039006','046001','046002','046003','046004','046005','046007','046008','046009','046010','046011','046012','046013','046014','047001','047002','048001','051001','051002','051003','051004','052001','052002','052005','053015','053016','053019','053020','053023','053024','053026','053028','053029','053033','053034','053036','053037','053038','053039','053041','053042','053043','053045','053046','053047','053048','053051','053052','053054','053055','053056','053057','053068','053069','053070','053073','053074','053075','053086','053094','053095','053096','053097','053098','053099','053100','053101','053102','053103','053104','053105','053107','053122','053123','053124','053125','053127','053128','054001','054002','054003','054004','054005','054006','054007','054009','054010','056001','056002','056003','056004','056005','056006','056009','056010','056011','056016','056017','056018','056019','056020','056021','056022','057001','057002','057003','057004','058002','058003','058004','058005','060001','060003','060004','060005','060006','060007','061002','061003','061004','061005','061006','069006','069007','069010','069011','069012','069013','069014','069015','069016','069017','069018','069020','069021','069022','069023','069024','071002','071003','071004','071005','071006','071008','071011','071013','071020','071021','071022','072001','073001','073002','073003','073004','074001','074002','074003','074004','074005','074006','074007','074008','074009','074010','074011','074012','075001','075007','076101','076102','076103','077001','077002','077003','077004','077006','077007','077008','077009','078005','079002','079003','079004','079005','079006','079007','081001','082006','082007','082011','082013','082014','082015','082016','082017','082021','082022','082023','082024','082025','082026','082027','082028','082029','082030','082031','082032','082033','082034','082035','082036','082037','082038','082039','082040','082041','082042','082043','082044','084001','084002','084003','084004','084005','084007','084008','084009','084011','084013','084014','084016','084017','084027','084031','084032','084033','084035','084036','084037','084038','084039','084040','084041','084042','084043','084044','084045','084046','084047','084048','084049','084050','084051','085001','085002','085003','085004','085005','085006','085007','085009','085011','085012','085013','085014','085015','085016','085017','085018','085019','085020','085021','085022','085023','085028','085029','085030','085031','085033','085034','085035','085036','085037','085038','085040','085041','085042','085043','085044','085045','085046','085047','085048','085063','085064','085065','085068','085070','085071','085073','085082','085083','085086','085088','085089','085090','085091','085092','085093','085094','085095','085096','085097','085098','085099','085100','085101','085102','085103','085104','085105','085106','085107','085108','085109','085110','085111','085112','085113','085115','085119','085120','085121','085122','085123','085124','085125','085126','085127','085128','085129','085130','085132','085133','085134','085135','085136','085137','086001','086002','086003','086004','086005','088001','088003','088005','088006','088007','088008','088009','089001','090001','090002','090003','090004','090005','090006','090007','090008','090009','090010','090013','090015','090016','090017','090018','090019','090022','090027','090028','091001','091002','091005','091008','091009','091010','091011','091012','091013','091014','091015','091016','091017','091018','093001','093003','093098','093100','093102','093104','093141','093142','093146','093151','093153','093167','093168','093176','094001','094002','094004','094005','095004','099001','099002','100001','101001','102002','102003','105001','105002','106001','113001','113002','113003','113004','113005','113006','113007','113008','113009','113010','113011','113012','113013','113014','113015','113016','113017','113018','113019','113020','113021','113022','113023','113024','113025','113026','113027','113028','114001','115001','115002','115003','115004','115005','115006','115007','115008','115009','115010','115011','115012','115013','115014','115015','115016','115017','115018','115020','115021','115022','115023','115025','115026','115027','115028','115029','115030','115031','115032','115033','115034','115035','115036','115039','115040','115041','115042','115043','115044','115045','115046','115047','115048','115049','115050','115051','115052','115053','115054','115055','115056','115057','115059','115060','115061','115062','115063','115064','115065','115066','115067','115068','115069','115070','115071','115072','115073','115075','115076','115081','115082','115085','115086','115087','115088','115095','115096','115097','115098','115099','115101','115102','115103','115104','115105','115106','115108','115109','115110','115111','115112','115113','115114','115115','115116','115117','115118','115119','115120','115121','115122','116001','116002','116003','116004','116005','116006','116007','116008','116009','116010','116011','116012','117001','117002','117003','123001','124010','124014','124015','124019','124024','124025','124026','124027','124028','124029','124030','124031','124032','124033','124035','124036','124037','124038','124039','124040','124041','124042','124043','124044','124045','124046','124047','124048','124049','124050','124051','124052','124053','124054','124055','124056','124057','124058','124059','124060','124061','124062','124063','124064','124065','126001','126002','126003','126004','126005','126006','126007','126008','126009','126010','126011','126012','130001','132001','132002','132003','133001','133008','133009','133010','133011','133012','133013','133014','133015','133016','133017','133018','133019','133020','133021','133022','133023','133024','133025','133027','133028','133029','133030','133031','134001','135001','135002','135003','135004','135005','135006','135007','135008','135009','135010','136001','137009','137010','137011','137012','137013','137014','137015','137016','137017','137018','137019','138001','138002','138003','138004','139001','139003','140001','141001','141002','141003','141006','141007','141008','141009','141011','141012','141014','141015','141016','141017','141018','141019','141020','141021','141022','141023','141024','141025','141026','141027','141028','142001','142002','142003','142004','142005','142006','142007','142008','142010','142011','142012','144001','145001','145002','145003','145004','145005','145006','145007','145008','145009','145010','145011','145012','145013','145014','145015','145016','147001','150003','150005','150009','150013','150014','150015','150016','150017','150020','150021','152001','152002','152003','152004','152005','152006','152007','154001','154002','154003','155001','155002','155003','155004','155005','155006','159001','159002','159003','159004','160001','160002','160003','161001','162001','162002','162003','162004','162007','162010','162011','162012','163001','163002','163003','163005','163010','163011','163014','163015','163016','165001','165002','165003','165004','165005','165006','165007','165008','165009','165010','165011','165012','165013','165014','165015','165016','165017','165018','165019','165020','165021','165022','165023','165024','165025','165026','165027','165028','165029','165030','165031','165032','165033','165034','165035','165036','167001','168001','168002','168003','168004','168005','168007','168008','168009','168010','168011','168012','168013','168014','169001','169002','169003','169007','169008','169009','169010','170001','171001','171002','171003','171004','171005','171006','171007','171008','171009','172001','174001','174002','174003','176001','176002','176003','177001','177002','179001','179002','179003','179004','179005','179006','179007','179008','179009','179010','179011','179012','179013','179014','179015','179016','179017','179018','179019','179020','179021','179022','179023','179024','179025','179026','179027','179028','179029','179030','179031','179032','179033','179034','179035','179036','179037','179038','179039','179040','179041','179042','179043','179044','179045','179046','179047','180001','180010','180012','180013','180014','180015','180016','180017','180018','180019','180020','180021','180022','180023','180024','180025','180026','180027','180028','180030','180031','180032','180033','180034','180035','180036','180037','180038','180039','180041','180042','180043','180044','180045','180046','180047','180048','180049','180050','180051','180052','180053','180054','180055','180056','180057','180058','180059','180060','180061','180062','180063','180064','180065','180066','180067','180068','180069','180070','180071','182001','184001','184002','184005','184006','184007','184008','184009','184010','184011','185001','185003','187001','188001','188002','188003','188004','188005','188006','188007','188008','188009','188010','188011','191001','191002','192002','194001','194002','194003','194004','194005','194006','194007','195001','195002','195003','195004','195005','195006','195007','196001','196002','197001','197002','197003','197004','197005','197006','198001','198003','198004','198005','198006','198007','198008','198009','198010','198011','198012','198013','198014','198015','198016','198017','201001','201002','201005','202001','203001','203002','203003','203017','203018','203019','204001','204002','204003','205001','208001','208002','208003','208004','208005','209001','209002','209003','210001','210002','210003','210004','210005','210006','210007','210008','210009','210010','210011','210012','210013','211017','212001','212002','212003','212004','212005','212006','212007','212008','212009','212010','212011','212012','212013','218001','218003','218004','218006','218007','218008','218009','218011','218015','218016','218017','218018','218019','218020','218021','218022','218023','218024','218025','218026','218027','218028','218029','218030','218031','218032','218033','218034','218035','218036','221001','221002','221003','221004','221005','221006','221007','221008','221009','221010','221011','221012','221013','223001','223002','223003','224001','224002','224003','224006','224007','224008','225001','225002','225003','225004','225005','225006','225007','225008','225009','225010','225011','225012','225013','226001','226002','226003','226004','226005','226006','226007','226008','226009','227001','227002','227003','227004','227005','227006','227007','227008','227009','227010','227011','227012','227013','227014','227015','227016','227017','227018','227019','227020','227021','227022','227023','227024','227025','227026','227027','227028','227029','227030','227031','227032','227033','227034','227035','227036','227037','227038','227039','227040','227041','227042','227043','227044','227045','227046','227047','227048','227049','227050','227051','227052','227053','227054','227055','227056','227057','227058','227059','227060','227061','227062','227063','227064','227065','227066','227067','227068','227069','227070','227071','227072','227073','227074','227075','227076','227077','227078','227079','227080','227081','227082','227083','227084','227085','227086','227087','227088','227089','227090','227091','227092','227093','227094','227095','227096','227097','227098','227099','227100','227101','227102','227103','227104','227105','227106','227107','227108','227109','227110','227111','227112','227113','227114','227115','227116','227117','227118','227119','227120','227122','227123','227124','227125','227126','227127','227128','227129','227130','227131','227132','227133','227134','227135','227136','227137','227138','227139','227140','227141','227142','227143','227144','227145','227146','227147','227148','227149','227150','227151','227152','228001','229001','229002','229003','229004','229005','230001','230002','232001','233001','233002','233003','233004','233005','233006','233007','233008','234001','234002','234003','234004','234005','234006','234007','234008','234009','234010','234011','234012','234013','234014','234015','234016','234017','234018','234019','234020','234021','234022','234023','234024','234025','234026','234027','234028','234029','234030','235001','235002','235003','235004','235005','236001','236002','236003','237001','238002','238003','238004','238005','238006','238007','238008','333013','333014','333015','333016','333017','333018','333019','333020','333021','333022','333023','333024','333025','333030','333031','333032','333033','333034','333035','334001','334002','334003','334004','334005','334006','334007','336004','337001','337002','337003','337004','339001','339002','343001','344001','344002','344003','344004','344005','345001','345002','345003','347001','347002','348001','348002','348003','348004','348005','349001','349002','349003','350001','353001','353002','353003','353004','355001','355002','355003','355004','355005','355006','356001','358001','359001','359002','360001','360002','360003','360004','360005','366001','366002','366003','366004','369001','373001','373002','373003','373004','373005','373006','373007','373008','373009','373010','373011','373012','373013','373014','373015','373016','373017','373018','373019','373020','373021','374001','374002','374003','374004','374005','374006','374007','374008','374009','374010','374011','374012','374013','374014','374015','374016','376001','376002','376003','376004','376005','376006','376007','376008','376009','376010','376011','376012','376013','376016','376017','376018','376019','376020','376021','379003','382001','382002','383001','384001','384002','385001','385002','386001','386002','386003','386004','386005','386006','386007','386008','386009','386010','386011','386012','386013','386014','387001','389001','389002','389003','389004','392001','393001','393002','393003','393004','395001','396001','397001','397002','399001','399002','399003','400001','400002','401001','401002','401003','402001','402002','402003','402004','402005','403001','403002','403003','504001','504002','504004','504005','504006','504007','504008','504009','504010','504011','504012','504013','504014','504017','504018','504019','504021','504022','504023','504024','504025','506001','506002','508001','508002','511001','511002','511003','511004','511005','511006','511007','511008','511009','511010','511011','511012','511013','511014','511017','511018','511020','511021','511022','511024','511028','511029','513001','513002','513003','513004','514001','515001','515002','515003','515007','515008','515009','515010','515011','515012','515013','515014','515015','518001','518002','518003','520001','520002','521001','521002','521003','521004','521005','521006','521007','521008','521009','521010','521011','521012','521013','521014','521015','521016','523001','523002','523003','523004','523005','523006','523007','524001','700001','701001','701002','701003','702001','702002','702003','702004','702005','702006','702007','702008','703001','703002','703003','704001','704002','704003','704004','705001','706001','706002','707001','707002','707003','708001','709001','709002','710001','710002','711001','711002','712001','713001','713002','714001','714002','715001','716001','718001','718002','719001','719002','991001','991002','991003','991004','991005','991006','991007','991008','992001','995001','996001','996002','996003','998001','998002','998003','998004','998005','998006','998007','999001','999002','011017','011018','034001','034002','071010','208006','239001','519001','519003','126013','184012','053071','374017','374018','374019','374020','374021','404001','405002','405001','405003','405007','405006','405005','405004','240011','240010','240009','240008','240007','240006','240005','240004','240003','240002','240001','240012','240013','240014','240015','240016','240017','357001','235006','235007','712002','355008','355007','056023','999999','046015','019005','126014','241003','241002','241001','240018','240020','240019','242001','242002','242003','242004','242005','242006','089002','406001','406002','406003','406004','406005','406006','243001','243002','243003','243004','243005','243006','243007','243008','010030','010029','407001','407006','407005','407004','407003','407002','408001','366005','133032','016035','077010','996004','025064','011019','407007','407008','407009','409001','115123','504026','039007','039009','039008','039010','039011','039012','180072','240021','240023','408002','405008','235008','525001','525002','525003','525004','410001','410002','410003','410004','410005','410006','410007','410008','410009','410010','410011','410012','410013','410014','410015','410016','344006','240031','240030','240029','240028','240027','240026','240025','240024','240034','240033','240032','410017','410018','411001','411002','411003','411004','411005','411006','411007','411008','203020','203021','203022','412001','412002','412003','412004','069025','244001','244002','244009','244008','244007','244006','244005','244004','244003','244015','244014','244013','244012','244011','244010','244016','244017','240042','240041','240040','240039','240038','240037','240036','240035','405009','405010','240043','504034','504033','504032','504031','504030','504029','504028','504027','504042','504041','504040','504039','504038','504037','504036','504035','800001','410019','410020','410021','244018','244019','244020','399004','413001','504043','198018','198019','344007','082045','010031','010032','010033','010034','010035','504044','515016','801002','801003','801004','801005','802001','801001','414001','414002','414003','141029','141030','803001','803002','803003','803004','803005','803006','803007','803008','803009','803010','803011','803012','803013','803014','803015','803016','803017','410022','410023','803018','803019','803020','415002','415001','244021','011020','011023','011022','011021','025065','165037','165038','165039','416001','416002','416003','417001','418001','504045','803022','803021','240022','419001','420001','804010','804009','804008','804007','804006','804005','804004','804003','804002','804001','804020','804019','804018','804017','804016','804015','804014','804013','804012','804011','804024','804021','804023','804022','511019','511016','511015','511032','511031','511030','511027','511026','511025','511033','511023','133034','133033','169011','344008','344009','244022','244026','244025','244030','244023','244024','244027','244028','244029','244031','082046','082047','082048','126015','126016','416004','416005','421001','421002','016037','016036','115124','115125','115126','240049','240048','240047','240046','240045','240044','244032','244033','422001','422002','422003','422004','422005','184013','239002','805001','805002','805003','805004','805005','056024','423001','344010','235009','212014','056025','056026','802002','244034','244035','244036','244037','244038','244039','515017','504046','203015','245002','245001','071023','056027','056028','056029','056030','056031','056032','424001','056034','056033','805006','805007','805008','805009','805010','422008','422007','422006','422010','422009','422011','209004','150022','150023','100002','056035','023036','185004','185005','246001','247001','247002','425001','416006','165042','165041','165040','165043','010040','010039','010038','010037','010036','422012','422013','422014','422015','426000','248001','248002','248003','248004','248005','249001','249002','249003','249004','249005','249006','250007','250001','250002','250003','250004','250005','250006','250008','250009','250010','250011','250012','250013','251001','251002','422016','422017','422018','806001','806002','116013','235010','235011','091026','091027','091028','091029','091019','091020','091021','091022','091023','091024','091025','252001','243009','249007','249008','249009','011024','011025','427001','428002','428001','169012','429001','429002','429003') DEFAULT '001001' NOT NULL, +KEY field (field) +); +INSERT INTO t1 VALUES ('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001010'),('001010'),('001010'),('001010'),('001010'),('001018'),('001018'),('001018'),('001018'),('001018'),('001018'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001021'),('001021'),('001021'),('001021'),('001021'),('001021'),('001027'),('001027'),('001028'),('001030'),('001030'),('001030'),('001030'),('001031'),('001031'),('001031'),('001031'),('001031'),('001100'),('001100'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002007'),('002007'),('002007'),('002007'),('002007'),('002007'),('002007'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002012'),('002012'),('002012'),('002012'),('002012'),('002012'),('002012'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('003002'),('003002'),('003002'),('003002'),('003002'),('003002'),('003003'),('003003'),('003003'),('003003'),('003003'),('003003'),('003004'),('003004'),('003004'),('003004'),('003004'),('003004'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003007'),('003007'),('003007'),('003007'),('003007'),('003008'),('003008'),('003008'),('003008'),('003008'),('003008'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003015'),('003015'),('003015'),('003015'),('003015'),('003015'),('003016'),('003016'),('003016'),('003016'),('003016'),('003016'),('003017'),('003017'),('003017'),('003017'),('003017'),('003018'),('003018'),('003018'),('003018'),('003018'),('003019'),('003019'),('004003'),('004005'),('004005'),('004005'),('004005'),('004005'),('004005'),('004006'),('004008'),('004010'),('004012'),('004012'),('004014'),('004014'),('004014'),('004014'),('004014'),('004016'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004020'),('004020'),('004020'),('004020'),('004020'),('004020'),('004021'),('004021'),('004021'),('004021'),('004021'),('004021'),('004021'),('004022'),('004023'),('004023'),('004023'),('004023'),('004023'),('004023'),('004023'),('004025'),('004026'),('004026'),('004026'),('004026'),('004026'),('006004'),('006006'),('006010'),('006010'),('006010'),('006010'),('006010'),('006010'),('006010'),('006011'),('006011'),('006011'),('006011'),('006011'),('006011'),('006012'),('006012'),('006012'),('006012'),('006012'),('006012'),('006014'),('006014'),('006014'),('007001'),('007001'),('007002'),('007003'),('007005'),('007007'),('007008'),('007009'),('007011'),('007012'),('007013'),('007015'),('007016'),('007017'),('007018'),('007019'),('007019'),('007020'),('007021'),('007021'),('007022'),('007023'),('007023'),('007025'),('007025'),('007025'),('007027'),('007029'),('007031'),('007031'),('007032'),('007034'),('007034'),('007036'),('007036'),('007036'),('007037'),('007037'),('007038'),('007040'),('007040'),('007040'),('007043'),('009001'),('009001'),('009001'),('009001'),('009001'),('009001'),('009001'),('009002'),('009002'),('009002'),('009002'),('009002'),('009004'),('009004'),('009004'),('009004'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009006'),('009006'),('009006'),('009006'),('009007'),('009007'),('009007'),('009007'),('009007'),('009007'),('009008'),('009010'),('009010'),('009010'),('009010'),('009010'),('009010'),('009011'),('009011'),('009011'),('009011'),('009011'),('009012'),('009013'),('009013'),('009013'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010005'),('010005'),('010005'),('010005'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010007'),('010007'),('010007'),('010007'),('010007'),('010007'),('010008'),('010008'),('010008'),('010008'),('010008'),('010008'),('010008'),('010009'),('010009'),('010009'),('010009'),('010009'),('010009'),('010010'),('010010'),('010010'),('010010'),('010010'),('010010'),('010010'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010012'),('010012'),('010012'),('010012'),('010012'),('010012'),('010012'),('010013'),('010013'),('010013'),('010013'),('010013'),('010013'),('010015'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010017'),('010017'),('010017'),('010017'),('010017'),('010017'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010019'),('010019'),('010019'),('010019'),('010019'),('010019'),('010020'),('010020'),('010020'),('010021'),('010021'),('010021'),('010021'),('010021'),('010021'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010026'),('010027'),('010028'),('010028'),('011001'),('011001'),('011001'),('011001'),('011001'),('011001'),('011001'),('011002'),('011002'),('011002'),('011002'),('011002'),('011002'),('011002'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011004'),('011004'),('011004'),('011004'),('011004'),('011004'),('011004'),('011006'),('011006'),('011006'),('011006'),('011006'),('011006'),('011006'),('011012'),('011012'),('011012'),('011013'),('011013'),('011013'),('011013'),('011013'),('011013'),('011014'),('011014'),('011014'),('011014'),('011015'),('011015'),('011015'),('011015'),('011015'),('011016'),('011016'),('011016'),('011016'),('011016'),('012017'),('012017'),('012027'),('012027'),('012032'),('012034'),('012036'),('012036'),('012037'),('012037'),('012038'),('012039'),('014001'),('014001'),('016016'),('016016'),('016016'),('016019'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016021'),('016021'),('016021'),('016021'),('016021'),('016021'),('016021'),('016022'),('016022'),('016022'),('016023'),('016023'),('016023'),('016024'),('016024'),('016024'),('016024'),('016024'),('016024'),('016024'),('016026'),('016026'),('016026'),('016026'),('016026'),('016026'),('016028'),('016028'),('016028'),('016028'),('016028'),('016028'),('016028'),('016029'),('016029'),('016030'),('016031'),('016032'),('016032'),('016032'),('016032'),('016032'),('016032'),('016032'),('016033'),('016033'),('016033'),('016033'),('016033'),('016034'),('016034'),('016034'),('016034'),('016034'),('017002'),('017002'),('017002'),('017002'),('017002'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('019002'),('019002'),('019002'),('019002'),('019002'),('019002'),('019004'),('019004'),('019004'),('019004'),('019004'),('019004'),('020001'),('020001'),('020001'),('020001'),('020004'),('020006'),('020006'),('020006'),('020006'),('020006'),('020006'),('020008'),('020009'),('020009'),('020009'),('020009'),('020009'),('022001'),('022001'),('022001'),('022001'),('022002'),('022002'),('022002'),('022002'),('022003'),('022003'),('022003'),('022003'),('023001'),('023002'),('023002'),('023002'),('023002'),('023002'),('023002'),('023003'),('023003'),('023003'),('023003'),('023004'),('023004'),('023005'),('023005'),('023006'),('023006'),('023006'),('023006'),('023006'),('023006'),('023007'),('023007'),('023010'),('023010'),('023011'),('023011'),('023017'),('023019'),('023019'),('023019'),('023020'),('023020'),('023025'),('023025'),('023025'),('023026'),('023026'),('023026'),('023027'),('023027'),('023027'),('023028'),('023028'),('023029'),('023029'),('023030'),('023030'),('023032'),('023033'),('023033'),('023033'),('023033'),('023033'),('023033'),('023034'),('023035'),('023035'),('025001'),('025001'),('025001'),('025001'),('025001'),('025001'),('025001'),('025003'),('025003'),('025004'),('025004'),('025005'),('025005'),('025007'),('025007'),('025008'),('025008'),('025009'),('025010'),('025010'),('025010'),('025011'),('025011'),('025012'),('025012'),('025013'),('025013'),('025013'),('025014'),('025015'),('025016'),('025018'),('025018'),('025019'),('025019'),('025020'),('025020'),('025021'),('025022'),('025022'),('025023'),('025023'),('025024'),('025025'),('025025'),('025026'),('025026'),('025027'),('025027'),('025027'),('025028'),('025030'),('025031'),('025033'),('025034'),('025035'),('025037'),('025041'),('025042'),('025043'),('025046'),('025048'),('025048'),('025048'),('025049'),('025049'),('025049'),('025050'),('025050'),('025050'),('025051'),('025051'),('025052'),('025052'),('025052'),('025053'),('025053'),('025054'),('025054'),('025054'),('025054'),('025055'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025057'),('025057'),('025058'),('025058'),('025060'),('025060'),('025061'),('025062'),('025063'),('027001'),('027002'),('027011'),('036001'),('036001'),('036001'),('036001'),('036001'),('037003'),('037006'),('037007'),('037008'),('037008'),('038009'),('039001'),('039001'),('039001'),('039001'),('039001'),('039001'),('039002'),('039002'),('039002'),('039002'),('039002'),('039003'),('039003'),('039003'),('039003'),('039003'),('039003'),('039004'),('039004'),('039004'),('039004'),('039004'),('039005'),('039005'),('039005'),('039005'),('039005'),('039006'),('039006'),('039006'),('039006'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046003'),('046003'),('046003'),('046003'),('046003'),('046003'),('046003'),('046005'),('046005'),('046005'),('046005'),('046005'),('046005'),('046005'),('046007'),('046007'),('046007'),('046007'),('046007'),('046007'),('046008'),('046008'),('046008'),('046008'),('046008'),('046009'),('046009'),('046009'),('046010'),('046012'),('046012'),('046012'),('046013'),('046014'),('046014'),('046014'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('051003'),('051003'),('051003'),('051003'),('051003'),('051004'),('051004'),('051004'),('051004'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052002'),('052002'),('052005'),('052005'),('052005'),('052005'),('052005'),('052005'),('053016'),('053019'),('053019'),('053023'),('053023'),('053023'),('053023'),('053024'),('053024'),('053024'),('053026'),('053026'),('053026'),('053026'),('053028'),('053028'),('053029'),('053029'),('053029'),('053029'),('053033'),('053033'),('053033'),('053045'),('053046'),('053051'),('053051'),('053051'),('053054'),('053054'),('053054'),('053054'),('053057'),('053069'),('053069'),('053097'),('053107'),('053125'),('053125'),('053127'),('054001'),('054001'),('054001'),('054001'),('054001'),('054001'),('054001'),('054002'),('054002'),('054002'),('054002'),('054002'),('054002'),('054003'),('054003'),('054003'),('054003'),('054003'),('054003'),('054003'),('054004'),('054004'),('054004'),('054004'),('054004'),('054004'),('054004'),('054006'),('054006'),('054006'),('054007'),('054007'),('054007'),('054007'),('054007'),('054009'),('054009'),('054009'),('054009'),('054010'),('054010'),('054010'),('054010'),('054010'),('054010'),('054010'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056003'),('056003'),('056003'),('056003'),('056003'),('056003'),('056004'),('056004'),('056004'),('056004'),('056004'),('056004'),('056004'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056009'),('056009'),('056009'),('056011'),('056016'),('056016'),('056016'),('056016'),('056016'),('056016'),('056016'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056018'),('056018'),('056018'),('056018'),('056018'),('056018'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056020'),('056020'),('056020'),('056020'),('056022'),('056022'),('056022'),('056022'),('056022'),('057003'),('057003'),('057004'),('058002'),('058002'),('058002'),('058002'),('058003'),('058003'),('058003'),('058003'),('058004'),('058004'),('058004'),('058005'),('058005'),('058005'),('060001'),('060001'),('060001'),('060001'),('060001'),('060004'),('060004'),('060004'),('060004'),('060004'),('060004'),('060005'),('060005'),('060005'),('060005'),('060005'),('060005'),('060007'),('060007'),('060007'),('060007'),('060007'),('060007'),('060007'),('061004'),('061004'),('061004'),('061004'),('061004'),('061004'),('061006'),('061006'),('061006'),('061006'),('061006'),('061006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069010'),('069010'),('069010'),('069010'),('069010'),('069010'),('069011'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069016'),('069016'),('069016'),('069016'),('069016'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069020'),('069020'),('069020'),('069020'),('069021'),('069023'),('071002'),('071002'),('071002'),('071002'),('071002'),('071003'),('071003'),('071003'),('071003'),('071003'),('071004'),('071004'),('071004'),('071004'),('071004'),('071005'),('071005'),('071005'),('071005'),('071005'),('071005'),('071006'),('071006'),('071006'),('071006'),('071008'),('071008'),('071008'),('071008'),('071008'),('071008'),('071011'),('071011'),('071011'),('071011'),('071011'),('071020'),('071020'),('071020'),('071020'),('071020'),('071021'),('071022'),('071022'),('071022'),('072001'),('072001'),('074001'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074012'),('074012'),('074012'),('074012'),('074012'),('074012'),('074012'),('075001'),('075001'),('075001'),('075007'),('075007'),('075007'),('075007'),('076101'),('076101'),('076101'),('076101'),('076102'),('076102'),('076102'),('076103'),('076103'),('076103'),('076103'),('076103'),('077001'),('077001'),('077001'),('077002'),('077002'),('077002'),('077002'),('077002'),('077002'),('077002'),('077003'),('077003'),('077003'),('077003'),('077003'),('077003'),('077003'),('077004'),('077004'),('077004'),('077004'),('077004'),('077004'),('077006'),('077006'),('077008'),('077008'),('077008'),('077008'),('077008'),('077008'),('077008'),('077009'),('077009'),('077009'),('077009'),('077009'),('077009'),('077009'),('078005'),('078005'),('078005'),('079002'),('079002'),('079002'),('079002'),('079002'),('079002'),('079002'),('079003'),('079003'),('079004'),('079004'),('079005'),('079005'),('079005'),('079005'),('079005'),('079005'),('079006'),('079006'),('079006'),('079006'),('079007'),('079007'),('079007'),('079007'),('079007'),('081001'),('081001'),('081001'),('081001'),('081001'),('082011'),('082011'),('082011'),('082011'),('082011'),('082013'),('082013'),('082013'),('082013'),('082013'),('082013'),('082014'),('082014'),('082014'),('082014'),('082014'),('082014'),('082014'),('082015'),('082015'),('082015'),('082015'),('082015'),('082016'),('082016'),('082016'),('082016'),('082016'),('082016'),('082017'),('082017'),('082017'),('082017'),('082017'),('082017'),('082017'),('082021'),('082021'),('082022'),('082022'),('082022'),('082022'),('082022'),('082023'),('082023'),('082023'),('082023'),('082023'),('082024'),('082024'),('082024'),('082024'),('082024'),('082025'),('082025'),('082025'),('082025'),('082025'),('082026'),('082026'),('082026'),('082026'),('082026'),('082027'),('082027'),('082027'),('082027'),('082027'),('082028'),('082028'),('082028'),('082028'),('082029'),('082029'),('082029'),('082029'),('082029'),('082030'),('082030'),('082030'),('082030'),('082031'),('082031'),('082031'),('082031'),('082031'),('082032'),('082032'),('082032'),('082033'),('082033'),('082034'),('082034'),('082034'),('082034'),('082034'),('082034'),('082034'),('082035'),('082035'),('082035'),('082036'),('082036'),('082036'),('082036'),('082037'),('082037'),('082037'),('082038'),('082038'),('082038'),('082038'),('082039'),('082039'),('082039'),('082039'),('082040'),('082040'),('082040'),('082040'),('082040'),('082041'),('082041'),('082041'),('082041'),('082042'),('082042'),('082043'),('082043'),('082043'),('082043'),('082043'),('082044'),('082044'),('082044'),('082044'),('084001'),('084002'),('084002'),('084002'),('084002'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084004'),('084004'),('084004'),('084004'),('084004'),('084005'),('084005'),('084005'),('084005'),('084005'),('084007'),('084007'),('084007'),('084007'),('084007'),('084007'),('084008'),('084008'),('084008'),('084008'),('084008'),('084008'),('084009'),('084009'),('084009'),('084009'),('084009'),('084009'),('084011'),('084013'),('084013'),('084013'),('084013'),('084013'),('084014'),('084014'),('084014'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084027'),('084027'),('084027'),('084027'),('084027'),('084027'),('084032'),('084032'),('084033'),('084033'),('084033'),('084035'),('084035'),('084035'),('084036'),('084036'),('084036'),('084036'),('084036'),('084036'),('084037'),('084037'),('084038'),('084038'),('084038'),('084038'),('084038'),('084038'),('084039'),('084039'),('084039'),('084039'),('084040'),('084040'),('084040'),('084040'),('084040'),('084041'),('084041'),('084041'),('084041'),('084042'),('084042'),('084043'),('084043'),('084043'),('084043'),('084044'),('084044'),('084044'),('084044'),('084044'),('084045'),('084046'),('084046'),('084046'),('084047'),('084048'),('084048'),('084049'),('084049'),('084050'),('084051'),('084051'),('085001'),('085001'),('085001'),('085001'),('085001'),('085001'),('085002'),('085002'),('085002'),('085002'),('085003'),('085003'),('085003'),('085003'),('085003'),('085003'),('085003'),('085004'),('085004'),('085004'),('085004'),('085004'),('085004'),('085004'),('085005'),('085005'),('085005'),('085005'),('085005'),('085005'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085007'),('085007'),('085007'),('085007'),('085007'),('085007'),('085007'),('085009'),('085009'),('085009'),('085009'),('085009'),('085009'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085012'),('085012'),('085012'),('085012'),('085012'),('085012'),('085012'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085017'),('085017'),('085017'),('085017'),('085017'),('085018'),('085018'),('085018'),('085018'),('085018'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085020'),('085020'),('085020'),('085020'),('085020'),('085020'),('085022'),('085022'),('085022'),('085022'),('085022'),('085022'),('085023'),('085023'),('085023'),('085023'),('085023'),('085028'),('085028'),('085028'),('085028'),('085028'),('085028'),('085028'),('085029'),('085029'),('085029'),('085029'),('085029'),('085029'),('085029'),('085030'),('085030'),('085030'),('085030'),('085030'),('085030'),('085030'),('085031'),('085031'),('085031'),('085031'),('085031'),('085031'),('085031'),('085033'),('085034'),('085034'),('085034'),('085034'),('085034'),('085034'),('085034'),('085035'),('085035'),('085035'),('085035'),('085035'),('085035'),('085036'),('085036'),('085036'),('085036'),('085036'),('085036'),('085037'),('085037'),('085037'),('085037'),('085037'),('085037'),('085038'),('085038'),('085038'),('085038'),('085038'),('085038'),('085038'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085042'),('085042'),('085042'),('085042'),('085042'),('085042'),('085042'),('085043'),('085043'),('085043'),('085043'),('085043'),('085043'),('085044'),('085044'),('085044'),('085044'),('085044'),('085044'),('085044'),('085045'),('085045'),('085045'),('085045'),('085045'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085048'),('085048'),('085048'),('085048'),('085048'),('085048'),('085048'),('085063'),('085063'),('085063'),('085063'),('085063'),('085064'),('085064'),('085064'),('085064'),('085064'),('085065'),('085065'),('085068'),('085068'),('085068'),('085068'),('085068'),('085068'),('085071'),('085071'),('085071'),('085071'),('085071'),('085071'),('085073'),('085073'),('085082'),('085082'),('085082'),('085082'),('085082'),('085086'),('085086'),('085086'),('085088'),('085088'),('085088'),('085088'),('085088'),('085088'),('085088'),('085089'),('085089'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085091'),('085091'),('085091'),('085091'),('085091'),('085092'),('085092'),('085092'),('085093'),('085093'),('085095'),('085095'),('085095'),('085095'),('085095'),('085096'),('085096'),('085096'),('085096'),('085096'),('085096'),('085097'),('085097'),('085097'),('085097'),('085097'),('085098'),('085098'),('085098'),('085098'),('085098'),('085098'),('085098'),('085099'),('085099'),('085099'),('085099'),('085099'),('085099'),('085099'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085102'),('085102'),('085103'),('085103'),('085103'),('085104'),('085104'),('085104'),('085104'),('085104'),('085105'),('085105'),('085106'),('085106'),('085106'),('085106'),('085106'),('085106'),('085108'),('085108'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085110'),('085110'),('085110'),('085110'),('085110'),('085111'),('085111'),('085111'),('085112'),('085112'),('085112'),('085112'),('085113'),('085113'),('085113'),('085113'),('085113'),('085115'),('085120'),('085121'),('085121'),('085121'),('085121'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085125'),('085125'),('085125'),('085125'),('085125'),('085126'),('085126'),('085126'),('085126'),('085126'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085128'),('085128'),('085128'),('085128'),('085128'),('085129'),('085129'),('085129'),('085129'),('085129'),('085130'),('085130'),('085130'),('085130'),('085130'),('085132'),('085132'),('085132'),('085132'),('085132'),('085132'),('085133'),('085133'),('085133'),('085133'),('085133'),('085134'),('085134'),('085134'),('085135'),('085135'),('085135'),('085136'),('085136'),('085136'),('085136'),('085137'),('085137'),('085137'),('085137'),('085137'),('085137'),('085137'),('086002'),('086002'),('086002'),('086002'),('086003'),('086003'),('086003'),('086003'),('086005'),('088001'),('088001'),('088001'),('088001'),('088001'),('088003'),('088003'),('088003'),('088003'),('088003'),('088003'),('088005'),('088005'),('088005'),('088005'),('088005'),('088006'),('088006'),('088006'),('088006'),('088006'),('088007'),('088007'),('088007'),('088008'),('088008'),('088008'),('088008'),('088009'),('088009'),('088009'),('088009'),('088009'),('089001'),('089001'),('089001'),('089001'),('089001'),('089001'),('089001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090002'),('090002'),('090002'),('090002'),('090002'),('090002'),('090003'),('090003'),('090003'),('090003'),('090003'),('090003'),('090003'),('090004'),('090004'),('090004'),('090004'),('090004'),('090004'),('090004'),('090006'),('090006'),('090006'),('090006'),('090006'),('090006'),('090006'),('090008'),('090008'),('090008'),('090008'),('090008'),('090009'),('090009'),('090009'),('090009'),('090009'),('090010'),('090010'),('090013'),('090013'),('090013'),('090016'),('090016'),('090017'),('090018'),('090022'),('090027'),('091001'),('091001'),('091001'),('091001'),('091001'),('091001'),('091002'),('091002'),('091002'),('091002'),('091002'),('091002'),('091009'),('091009'),('091009'),('091009'),('091009'),('091011'),('091011'),('091011'),('091011'),('091011'),('091011'),('091011'),('091012'),('091012'),('091013'),('091013'),('091013'),('091013'),('091013'),('091013'),('091015'),('091015'),('091015'),('091015'),('091015'),('091015'),('091016'),('091016'),('091016'),('091016'),('091016'),('091017'),('091017'),('091018'),('091018'),('091018'),('091018'),('093003'),('093003'),('093003'),('093003'),('093003'),('093003'),('099001'),('099001'),('099001'),('099001'),('099001'),('099001'),('099001'),('100001'),('100001'),('100001'),('100001'),('106001'),('113005'),('113005'),('113005'),('113006'),('113006'),('113018'),('113019'),('113020'),('115001'),('115001'),('115001'),('115002'),('115002'),('115003'),('115004'),('115004'),('115004'),('115004'),('115005'),('115005'),('115005'),('115006'),('115006'),('115006'),('115007'),('115007'),('115007'),('115007'),('115007'),('115008'),('115008'),('115008'),('115009'),('115010'),('115010'),('115010'),('115010'),('115010'),('115011'),('115011'),('115011'),('115011'),('115012'),('115012'),('115013'),('115013'),('115013'),('115014'),('115014'),('115014'),('115014'),('115015'),('115015'),('115015'),('115016'),('115016'),('115016'),('115016'),('115017'),('115017'),('115017'),('115017'),('115017'),('115018'),('115018'),('115020'),('115020'),('115021'),('115021'),('115022'),('115022'),('115022'),('115023'),('115023'),('115023'),('115023'),('115023'),('115025'),('115025'),('115025'),('115026'),('115026'),('115027'),('115027'),('115027'),('115028'),('115028'),('115028'),('115028'),('115029'),('115029'),('115029'),('115030'),('115030'),('115030'),('115031'),('115031'),('115032'),('115032'),('115032'),('115033'),('115033'),('115033'),('115033'),('115034'),('115034'),('115034'),('115035'),('115035'),('115036'),('115036'),('115036'),('115036'),('115036'),('115039'),('115040'),('115040'),('115040'),('115041'),('115041'),('115041'),('115041'),('115041'),('115042'),('115042'),('115042'),('115042'),('115042'),('115043'),('115043'),('115043'),('115044'),('115044'),('115044'),('115044'),('115046'),('115046'),('115046'),('115047'),('115048'),('115050'),('115050'),('115050'),('115050'),('115050'),('115051'),('115051'),('115051'),('115052'),('115053'),('115053'),('115054'),('115054'),('115054'),('115055'),('115055'),('115055'),('115057'),('115059'),('115059'),('115059'),('115059'),('115060'),('115060'),('115060'),('115060'),('115060'),('115060'),('115061'),('115061'),('115061'),('115062'),('115062'),('115062'),('115062'),('115064'),('115064'),('115064'),('115065'),('115065'),('115065'),('115065'),('115066'),('115066'),('115066'),('115067'),('115067'),('115067'),('115068'),('115068'),('115068'),('115069'),('115069'),('115069'),('115069'),('115069'),('115070'),('115070'),('115070'),('115071'),('115071'),('115071'),('115072'),('115072'),('115072'),('115073'),('115073'),('115075'),('115075'),('115075'),('115076'),('115076'),('115076'),('115076'),('115076'),('115076'),('115081'),('115081'),('115081'),('115082'),('115082'),('115082'),('115085'),('115085'),('115085'),('115085'),('115085'),('115086'),('115086'),('115086'),('115087'),('115087'),('115088'),('115088'),('115088'),('115088'),('115088'),('115095'),('115095'),('115095'),('115096'),('115096'),('115097'),('115097'),('115098'),('115098'),('115099'),('115101'),('115102'),('115102'),('115102'),('115103'),('115103'),('115104'),('115104'),('115104'),('115104'),('115105'),('115105'),('115106'),('115106'),('115106'),('115106'),('115106'),('115108'),('115109'),('115111'),('115111'),('115111'),('115111'),('115112'),('115112'),('115112'),('115112'),('115112'),('115113'),('115113'),('115113'),('115114'),('115114'),('115114'),('115114'),('115114'),('115115'),('115115'),('115115'),('115115'),('115116'),('115117'),('115117'),('115117'),('115118'),('115118'),('115119'),('115119'),('115119'),('115119'),('115120'),('115121'),('115121'),('115122'),('115122'),('116001'),('116003'),('116003'),('116003'),('116003'),('116004'),('116004'),('116005'),('116005'),('116006'),('116006'),('116006'),('116007'),('116007'),('116008'),('116008'),('116009'),('116009'),('116009'),('116010'),('116010'),('116010'),('116010'),('116011'),('116011'),('116011'),('116011'),('116012'),('116012'),('123001'),('123001'),('123001'),('123001'),('123001'),('124065'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126007'),('126007'),('126007'),('126007'),('126007'),('126007'),('126007'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126011'),('126011'),('126011'),('126011'),('126011'),('126011'),('126011'),('126012'),('126012'),('126012'),('126012'),('130001'),('130001'),('130001'),('130001'),('132001'),('132001'),('132001'),('132001'),('132001'),('132002'),('132002'),('132002'),('132002'),('132002'),('132002'),('132002'),('133001'),('133001'),('133008'),('133009'),('133010'),('133011'),('133011'),('133011'),('133011'),('133011'),('133011'),('133012'),('133015'),('133015'),('133015'),('133015'),('133016'),('133018'),('133018'),('133018'),('133018'),('133018'),('133019'),('133021'),('133021'),('133022'),('133022'),('133023'),('133023'),('133024'),('133024'),('133024'),('133024'),('133024'),('133024'),('133025'),('133027'),('133027'),('133027'),('133027'),('133027'),('133028'),('133028'),('133028'),('133029'),('133029'),('133029'),('133029'),('133029'),('133029'),('133030'),('133030'),('133031'),('133031'),('133031'),('134001'),('134001'),('134001'),('135001'),('135001'),('135001'),('135001'),('135001'),('135002'),('135002'),('135002'),('135004'),('135010'),('135010'),('135010'),('135010'),('135010'),('135010'),('137010'),('137011'),('137012'),('137014'),('137015'),('137015'),('137016'),('137019'),('139001'),('140001'),('140001'),('140001'),('140001'),('140001'),('140001'),('141001'),('141001'),('141001'),('141001'),('141001'),('141002'),('141002'),('141002'),('141002'),('141002'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141007'),('141007'),('141007'),('141007'),('141007'),('141009'),('141009'),('141009'),('141009'),('141009'),('141011'),('141011'),('141011'),('141011'),('141011'),('141011'),('141012'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141015'),('141015'),('141015'),('141015'),('141015'),('141016'),('141016'),('141016'),('141016'),('141016'),('141016'),('141017'),('141017'),('141017'),('141017'),('141017'),('141017'),('141018'),('141018'),('141018'),('141018'),('141019'),('141019'),('141019'),('141019'),('141020'),('141020'),('141020'),('141020'),('141020'),('141020'),('141020'),('141021'),('141021'),('141021'),('141021'),('141021'),('141021'),('141022'),('141022'),('141022'),('141022'),('141022'),('141022'),('141023'),('141023'),('141023'),('141023'),('141023'),('141023'),('141023'),('141024'),('141025'),('141025'),('141025'),('141026'),('141026'),('141026'),('141026'),('141026'),('141026'),('141027'),('141027'),('141027'),('141027'),('141027'),('141028'),('141028'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145009'),('145009'),('145009'),('145009'),('145009'),('145009'),('145009'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145013'),('145013'),('145013'),('145013'),('145013'),('145013'),('145013'),('150009'),('150013'),('150014'),('150015'),('150015'),('150015'),('150016'),('150016'),('150017'),('150017'),('150017'),('150017'),('150020'),('152001'),('152001'),('152001'),('152002'),('152003'),('152003'),('152003'),('152003'),('152004'),('152005'),('152006'),('152006'),('152006'),('152006'),('152007'),('154001'),('154002'),('154002'),('155001'),('155001'),('155002'),('155003'),('155004'),('155004'),('155006'),('159001'),('159003'),('160001'),('160001'),('160001'),('160001'),('160002'),('160002'),('161001'),('162002'),('162002'),('162003'),('162003'),('162003'),('162003'),('162003'),('162007'),('162012'),('162012'),('162012'),('163001'),('163001'),('163001'),('163011'),('163015'),('163016'),('163016'),('165001'),('165001'),('165001'),('165001'),('165002'),('165002'),('165002'),('165002'),('165003'),('165003'),('165003'),('165004'),('165004'),('165004'),('165005'),('165005'),('165005'),('165006'),('165006'),('165006'),('165006'),('165007'),('165007'),('165007'),('165007'),('165008'),('165008'),('165008'),('165008'),('165009'),('165009'),('165009'),('165009'),('165010'),('165010'),('165010'),('165011'),('165011'),('165012'),('165012'),('165012'),('165013'),('165013'),('165013'),('165014'),('165014'),('165014'),('165015'),('165015'),('165015'),('165015'),('165016'),('165016'),('165016'),('165017'),('165017'),('165017'),('165017'),('165018'),('165018'),('165018'),('165018'),('165019'),('165019'),('165019'),('165019'),('165020'),('165020'),('165020'),('165020'),('165021'),('165021'),('165021'),('165021'),('165022'),('165022'),('165022'),('165023'),('165024'),('165024'),('165024'),('165025'),('165025'),('165025'),('165026'),('165026'),('165026'),('165028'),('165029'),('165030'),('165030'),('165030'),('165031'),('165031'),('165033'),('165033'),('165034'),('165034'),('165034'),('165035'),('165035'),('165035'),('165036'),('165036'),('165036'),('168003'),('168003'),('168004'),('168005'),('168014'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169003'),('169003'),('169003'),('169003'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169008'),('169008'),('169008'),('169008'),('169008'),('169008'),('169008'),('169009'),('169009'),('169009'),('169009'),('169010'),('171006'),('171006'),('171007'),('171007'),('171008'),('171008'),('171008'),('171009'),('171009'),('171009'),('172001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176002'),('176002'),('176002'),('176002'),('176002'),('176003'),('176003'),('176003'),('176003'),('176003'),('176003'),('177001'),('177001'),('177001'),('177001'),('177001'),('177001'),('179007'),('179007'),('179012'),('179012'),('179012'),('179012'),('179012'),('179012'),('179013'),('179013'),('179013'),('179013'),('179013'),('179013'),('179042'),('179044'),('179045'),('180001'),('180013'),('180014'),('180014'),('180015'),('180017'),('180018'),('180020'),('180020'),('180021'),('180021'),('180027'),('180030'),('180033'),('180035'),('180036'),('180037'),('180038'),('180041'),('180042'),('180045'),('180045'),('180047'),('180048'),('180049'),('180050'),('180054'),('180060'),('180066'),('180067'),('180068'),('180070'),('182001'),('184001'),('184002'),('184005'),('184005'),('184005'),('184005'),('184006'),('184006'),('184006'),('184006'),('184008'),('184008'),('184008'),('184008'),('184009'),('184009'),('184009'),('184009'),('184010'),('184010'),('184010'),('184010'),('184011'),('184011'),('184011'),('184011'),('185001'),('185001'),('185001'),('185001'),('185001'),('185001'),('185001'),('185003'),('185003'),('185003'),('185003'),('185003'),('185003'),('185003'),('187001'),('191002'),('191002'),('192002'),('194003'),('197001'),('197001'),('197001'),('197001'),('197001'),('197001'),('197001'),('197002'),('197002'),('197002'),('197002'),('197002'),('197002'),('197002'),('197003'),('197003'),('197003'),('197003'),('197003'),('197003'),('197003'),('197004'),('197004'),('197004'),('197004'),('197004'),('197004'),('197004'),('197005'),('197005'),('197005'),('197005'),('197005'),('197005'),('197006'),('197006'),('197006'),('197006'),('197006'),('198001'),('198001'),('198001'),('198001'),('198001'),('198001'),('198003'),('198003'),('198003'),('198004'),('198004'),('198004'),('198004'),('198004'),('198004'),('198005'),('198005'),('198005'),('198005'),('198005'),('198005'),('198005'),('198006'),('198006'),('198006'),('198006'),('198006'),('198006'),('198007'),('198007'),('198007'),('198007'),('198007'),('198007'),('198007'),('198008'),('198008'),('198008'),('198008'),('198008'),('198008'),('198009'),('198009'),('198009'),('198009'),('198009'),('198009'),('198009'),('198010'),('198010'),('198010'),('198010'),('198010'),('198010'),('198011'),('198012'),('198012'),('198012'),('198012'),('198015'),('198015'),('198016'),('198016'),('198016'),('198016'),('198016'),('198016'),('198017'),('198017'),('198017'),('198017'),('198017'),('198017'),('201001'),('201001'),('201001'),('201001'),('201001'),('201002'),('202001'),('202001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203002'),('203002'),('203002'),('203002'),('203003'),('203003'),('203003'),('203003'),('203003'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203018'),('203018'),('203018'),('203018'),('203018'),('203019'),('203019'),('203019'),('203019'),('203019'),('204001'),('204002'),('205001'),('205001'),('205001'),('205001'),('205001'),('205001'),('205001'),('208001'),('208001'),('208002'),('208002'),('208002'),('208003'),('208003'),('208003'),('208004'),('208004'),('208004'),('208004'),('208004'),('208004'),('208004'),('208005'),('208005'),('208005'),('208005'),('208005'),('209001'),('209001'),('209001'),('209001'),('209001'),('209002'),('209002'),('209002'),('209002'),('209002'),('209003'),('209003'),('209003'),('209003'),('209003'),('210001'),('210001'),('210001'),('210001'),('210001'),('210004'),('210004'),('210004'),('210004'),('210004'),('210004'),('210009'),('210010'),('212001'),('212001'),('212002'),('212002'),('212002'),('212002'),('212003'),('212003'),('212003'),('212004'),('212004'),('212004'),('212005'),('212005'),('212005'),('212005'),('212005'),('212006'),('212006'),('212006'),('212007'),('212007'),('212008'),('212008'),('212008'),('212008'),('212009'),('212009'),('212009'),('212009'),('212010'),('212010'),('212010'),('212010'),('212011'),('212011'),('212012'),('212012'),('212013'),('212013'),('212013'),('218001'),('218004'),('218009'),('218011'),('218011'),('218015'),('218020'),('218021'),('218021'),('218022'),('218022'),('218022'),('218023'),('218024'),('218025'),('218026'),('218026'),('218027'),('218028'),('218029'),('218029'),('218029'),('218030'),('218031'),('221001'),('221001'),('221001'),('221001'),('221001'),('221001'),('221002'),('221002'),('221002'),('221002'),('221002'),('221002'),('221003'),('221003'),('221003'),('221003'),('221003'),('221003'),('221004'),('221004'),('221004'),('221004'),('221004'),('221004'),('221005'),('221005'),('221005'),('221005'),('221005'),('221006'),('221006'),('221006'),('221006'),('221006'),('221007'),('221007'),('221007'),('221007'),('221007'),('221007'),('221008'),('221008'),('221008'),('221008'),('221008'),('221008'),('221009'),('221009'),('221009'),('221009'),('221009'),('221009'),('221010'),('221010'),('221010'),('221010'),('221011'),('221011'),('221011'),('221011'),('221012'),('221012'),('221012'),('221012'),('221012'),('221012'),('221013'),('221013'),('221013'),('221013'),('221013'),('221013'),('223003'),('223003'),('224001'),('224001'),('224002'),('224002'),('224003'),('224007'),('224008'),('225001'),('225002'),('225002'),('225002'),('225003'),('225003'),('225003'),('225003'),('225004'),('225004'),('225004'),('225005'),('225005'),('225005'),('225005'),('225005'),('225005'),('225006'),('225006'),('225006'),('225007'),('225007'),('225007'),('225008'),('225008'),('225008'),('225008'),('225008'),('225009'),('225009'),('225009'),('225010'),('225010'),('225010'),('225011'),('225011'),('225011'),('225011'),('225011'),('225012'),('225012'),('225012'),('225012'),('225012'),('225012'),('225013'),('225013'),('226001'),('226002'),('226003'),('226003'),('226005'),('226005'),('226006'),('226007'),('226007'),('226007'),('226007'),('227011'),('227015'),('227015'),('227041'),('227045'),('227052'),('227056'),('227063'),('227064'),('227066'),('227067'),('227069'),('227071'),('227073'),('227085'),('227116'),('227119'),('227131'),('227133'),('227147'),('229005'),('229005'),('229005'),('233003'),('233004'),('235001'),('235001'),('235002'),('235003'),('235003'),('235003'),('235004'),('235005'),('235005'),('235005'),('235005'),('235005'),('235005'),('235005'),('236001'),('236001'),('236001'),('236001'),('236002'),('236003'),('236003'),('236003'),('236003'),('236003'),('236003'),('238002'),('238002'),('238002'),('238002'),('238002'),('238002'),('238003'),('238003'),('238003'),('238003'),('238003'),('238003'),('238004'),('238004'),('238004'),('238004'),('238004'),('238005'),('238005'),('238005'),('238007'),('238007'),('238007'),('238007'),('238007'),('238007'),('238007'),('238008'),('238008'),('238008'),('238008'),('238008'),('238008'),('238008'),('334005'),('334006'),('337001'),('337001'),('337001'),('337002'),('337002'),('337003'),('337003'),('337003'),('337004'),('343001'),('343001'),('344001'),('344002'),('344003'),('344004'),('344005'),('344005'),('345001'),('345001'),('348001'),('348004'),('348005'),('348005'),('349001'),('349001'),('349002'),('349002'),('349002'),('350001'),('353002'),('353002'),('353002'),('353003'),('355001'),('355002'),('355005'),('355006'),('355006'),('356001'),('358001'),('358001'),('358001'),('359001'),('359001'),('359002'),('359002'),('359002'),('359002'),('360001'),('360001'),('360002'),('360002'),('360003'),('360003'),('360004'),('360004'),('360005'),('360005'),('360005'),('366001'),('366002'),('366002'),('366003'),('366004'),('369001'),('369001'),('373001'),('373002'),('373002'),('373003'),('373003'),('373005'),('373007'),('373008'),('373009'),('373009'),('373010'),('373010'),('373010'),('373011'),('373011'),('373011'),('373011'),('373012'),('373012'),('373012'),('373013'),('373013'),('373014'),('373014'),('373015'),('373015'),('373015'),('373015'),('373017'),('373017'),('373017'),('373017'),('373018'),('373021'),('374002'),('374004'),('374006'),('374007'),('374008'),('374009'),('374010'),('374011'),('374012'),('374015'),('374016'),('382001'),('382002'),('382002'),('384001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386002'),('386002'),('386002'),('386002'),('386002'),('386002'),('386002'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386005'),('386005'),('386005'),('386005'),('386005'),('386005'),('386005'),('386006'),('386006'),('386006'),('386006'),('386006'),('386006'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386009'),('386009'),('386009'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386013'),('386013'),('386013'),('386013'),('386013'),('386013'),('386013'),('386014'),('386014'),('386014'),('386014'),('389001'),('389002'),('389002'),('389003'),('389003'),('389003'),('389003'),('389004'),('389004'),('389004'),('389004'),('392001'),('393001'),('393002'),('393002'),('393003'),('393004'),('395001'),('395001'),('397001'),('397001'),('397001'),('397002'),('399001'),('399001'),('399001'),('399001'),('399001'),('399001'),('399001'),('399002'),('399002'),('399002'),('399002'),('399002'),('399002'),('399002'),('399003'),('400001'),('400001'),('400001'),('400001'),('400002'),('403002'),('504001'),('504001'),('504002'),('504002'),('504002'),('504004'),('504004'),('504005'),('504006'),('504007'),('504007'),('504007'),('504008'),('504008'),('504009'),('504009'),('504009'),('504009'),('504009'),('504010'),('504011'),('504011'),('504012'),('504012'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504017'),('504017'),('504021'),('504021'),('504021'),('504021'),('504021'),('504021'),('504021'),('504022'),('504023'),('504023'),('504024'),('504024'),('504025'),('504025'),('506001'),('506001'),('506001'),('506001'),('506001'),('506001'),('506002'),('506002'),('506002'),('506002'),('506002'),('511001'),('511001'),('511001'),('511001'),('511001'),('511001'),('511001'),('511002'),('511002'),('511002'),('511002'),('511002'),('511002'),('511002'),('511003'),('511003'),('511003'),('511003'),('511003'),('511003'),('511004'),('511004'),('511004'),('511004'),('511004'),('511004'),('511004'),('511005'),('511005'),('511005'),('511005'),('511005'),('511005'),('511005'),('511006'),('511006'),('511006'),('511006'),('511006'),('511006'),('511006'),('511007'),('511007'),('511007'),('511007'),('511007'),('511008'),('511008'),('511008'),('511008'),('511008'),('511008'),('511009'),('511009'),('511009'),('511009'),('511009'),('511009'),('511010'),('511010'),('511010'),('511010'),('511010'),('511010'),('511011'),('511011'),('511011'),('511011'),('511011'),('511011'),('511012'),('511012'),('511012'),('511012'),('511012'),('511012'),('511012'),('511013'),('511013'),('511013'),('511013'),('511013'),('511013'),('511013'),('511014'),('511014'),('511014'),('511014'),('511014'),('511017'),('511018'),('511020'),('511021'),('511022'),('511024'),('511028'),('511029'),('511029'),('511029'),('511029'),('511029'),('511029'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513002'),('513002'),('513002'),('513002'),('513002'),('513002'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513004'),('513004'),('513004'),('515001'),('515001'),('515001'),('515001'),('515001'),('515002'),('515002'),('515003'),('515003'),('515007'),('515007'),('515008'),('515011'),('515011'),('515011'),('515011'),('515011'),('515011'),('515012'),('515012'),('515012'),('515012'),('515013'),('515013'),('515013'),('515013'),('515013'),('515014'),('515014'),('515014'),('515014'),('515014'),('515015'),('515015'),('515015'),('515015'),('515015'),('518001'),('518002'),('521001'),('521002'),('521002'),('521002'),('521003'),('521003'),('521003'),('521003'),('521004'),('521004'),('521004'),('521004'),('521005'),('521005'),('521005'),('521005'),('521006'),('521006'),('521006'),('521009'),('521010'),('521010'),('521010'),('521010'),('521011'),('521011'),('521011'),('521011'),('521012'),('521013'),('521013'),('521015'),('521016'),('521016'),('523001'),('523001'),('523001'),('523001'),('523001'),('523001'),('523001'),('523002'),('523002'),('523002'),('523002'),('523002'),('523002'),('523003'),('523003'),('523003'),('523003'),('523003'),('523003'),('523003'),('523004'),('523004'),('523004'),('523004'),('523004'),('523004'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523006'),('523006'),('523006'),('523006'),('523006'),('523006'),('523006'),('523007'),('523007'),('523007'),('523007'),('523007'),('523007'),('523007'),('524001'),('700001'),('701001'),('701002'),('701003'),('702001'),('702002'),('702004'),('702005'),('704001'),('704004'),('705001'),('706001'),('706002'),('707001'),('707002'),('707003'),('708001'),('710001'),('710002'),('711001'),('711002'),('712001'),('714001'),('714002'),('715001'),('719001'),('719002'),('991002'),('991002'),('991002'),('991003'),('991003'),('991003'),('991003'),('991003'),('991003'),('991003'),('991004'),('991004'),('991004'),('991005'),('991005'),('991005'),('991006'),('991007'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996002'),('996002'),('996003'),('996003'),('996003'),('996003'),('996003'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998004'),('998004'),('998005'),('998005'),('998006'),('998007'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999002'),('999002'),('011017'),('011017'),('011017'),('011017'),('011017'),('011017'),('011017'),('011018'),('011018'),('011018'),('011018'),('034001'),('034001'),('034002'),('034002'),('071010'),('071010'),('071010'),('519001'),('126013'),('126013'),('126013'),('126013'),('126013'),('184012'),('184012'),('184012'),('404001'),('405002'),('405002'),('405001'),('405003'),('405006'),('240011'),('240011'),('240011'),('240011'),('240011'),('240011'),('240010'),('240010'),('240010'),('240009'),('240009'),('240009'),('240009'),('240008'),('240008'),('240008'),('240007'),('240007'),('240007'),('240007'),('240007'),('240007'),('240005'),('240005'),('240005'),('240005'),('240005'),('240004'),('240004'),('240004'),('240004'),('240004'),('240003'),('240003'),('240003'),('240003'),('240002'),('240002'),('240002'),('240002'),('240002'),('240002'),('240002'),('240001'),('240001'),('240001'),('240001'),('240001'),('240012'),('240012'),('240012'),('240012'),('240012'),('240013'),('240014'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240016'),('240016'),('240016'),('240016'),('240016'),('240016'),('240017'),('240017'),('240017'),('357001'),('357001'),('235006'),('235006'),('235007'),('235007'),('235007'),('235007'),('235007'),('056023'),('056023'),('056023'),('056023'),('056023'),('046015'),('019005'),('019005'),('126014'),('126014'),('126014'),('126014'),('126014'),('126014'),('241003'),('241003'),('241003'),('241003'),('241003'),('241003'),('241002'),('241002'),('241002'),('241002'),('241002'),('241002'),('241001'),('241001'),('241001'),('241001'),('241001'),('240020'),('240020'),('240020'),('240020'),('240020'),('240020'),('240019'),('240019'),('240019'),('242001'),('242002'),('242004'),('242005'),('242006'),('089002'),('089002'),('089002'),('089002'),('089002'),('089002'),('406001'),('406002'),('406003'),('406004'),('406004'),('243001'),('243005'),('243006'),('243007'),('243008'),('408001'),('408001'),('408001'),('408001'),('408001'),('366005'),('366005'),('016035'),('016035'),('016035'),('016035'),('077010'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('025064'),('025064'),('025064'),('025064'),('011019'),('011019'),('011019'),('011019'),('011019'),('115123'),('115123'),('504026'),('039007'),('039009'),('039008'),('039008'),('039010'),('039010'),('039011'),('039012'),('180072'),('240021'),('240021'),('240021'),('240021'),('240021'),('240021'),('240021'),('240023'),('240023'),('240023'),('240023'),('405008'),('405008'),('525002'),('410002'),('410002'),('410004'),('410005'),('410005'),('410006'),('410007'),('410007'),('410008'),('410009'),('410010'),('410011'),('410011'),('410012'),('410012'),('410013'),('410013'),('410014'),('410014'),('410016'),('410016'),('344006'),('240031'),('240031'),('240031'),('240031'),('240030'),('240030'),('240030'),('240030'),('240029'),('240029'),('240029'),('240029'),('240028'),('240028'),('240028'),('240028'),('240027'),('240027'),('240026'),('240026'),('240026'),('240025'),('240025'),('240025'),('240025'),('240024'),('240024'),('240034'),('240034'),('240034'),('240033'),('240033'),('240033'),('240032'),('240032'),('240032'),('240032'),('411001'),('411002'),('203020'),('069025'),('069025'),('069025'),('069025'),('069025'),('069025'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('240040'),('240037'),('405009'),('405009'),('405009'),('405010'),('405010'),('240043'),('240043'),('504028'),('504040'),('800001'),('410019'),('410019'),('410020'),('410020'),('410020'),('410021'),('410021'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('413001'),('344007'),('082045'),('082045'),('082045'),('082045'),('082045'),('010031'),('010031'),('010031'),('010031'),('010032'),('010032'),('010032'),('010032'),('010033'),('010033'),('010033'),('010033'),('010033'),('010034'),('010034'),('010034'),('010034'),('010035'),('010035'),('010035'),('010035'),('504044'),('515016'),('515016'),('515016'),('515016'),('801002'),('801003'),('801004'),('801005'),('802001'),('801001'),('414001'),('141029'),('803001'),('803002'),('803004'),('803005'),('803006'),('803007'),('803008'),('803009'),('803013'),('803014'),('803015'),('803016'),('803017'),('410022'),('410023'),('410023'),('803019'),('415002'),('415001'),('244021'),('244021'),('244021'),('244021'),('244021'),('244021'),('244021'),('011020'),('011020'),('011020'),('011020'),('011023'),('011023'),('011023'),('011023'),('011022'),('011022'),('011022'),('011022'),('011022'),('011022'),('011021'),('011021'),('011021'),('011021'),('025065'),('025065'),('025065'),('025065'),('165037'),('165037'),('165038'),('165038'),('165038'),('165039'),('416001'),('416001'),('416001'),('416001'),('416001'),('416002'),('416003'),('417001'),('418001'),('504045'),('504045'),('504045'),('803022'),('240022'),('240022'),('240022'),('240022'),('420001'),('420001'),('420001'),('420001'),('804010'),('804005'),('804002'),('804018'),('804013'),('511019'),('511016'),('511015'),('511032'),('511031'),('511030'),('511027'),('511026'),('511025'),('511033'),('511023'),('133034'),('133034'),('133034'),('133033'),('169011'),('169011'),('169011'),('169011'),('169011'),('344008'),('244022'),('244022'),('244022'),('244022'),('244022'),('244022'),('244022'),('244026'),('244026'),('244026'),('244026'),('244026'),('244026'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244023'),('244023'),('244023'),('244023'),('244023'),('244023'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('082046'),('082046'),('082046'),('082046'),('082047'),('082047'),('082048'),('082048'),('126015'),('126015'),('126016'),('126016'),('126016'),('126016'),('126016'),('416005'),('421001'),('421001'),('421002'),('016037'),('016037'),('016037'),('016037'),('016036'),('016036'),('016036'),('016036'),('115124'),('115124'),('115126'),('240049'),('240049'),('240048'),('240048'),('240047'),('240047'),('240046'),('240046'),('240045'),('240044'),('244032'),('244033'),('422002'),('422004'),('422004'),('422004'),('422005'),('422005'),('184013'),('184013'),('184013'),('805001'),('805002'),('805003'),('805004'),('805005'),('056024'),('056024'),('056024'),('423001'),('344010'),('235009'),('235009'),('235009'),('235009'),('212014'),('212014'),('056025'),('056025'),('056025'),('056026'),('056026'),('056026'),('056026'),('056026'),('056026'),('244034'),('244034'),('244034'),('244034'),('244034'),('244034'),('244035'),('244035'),('244035'),('244035'),('244035'),('244035'),('244035'),('244036'),('244036'),('244036'),('244036'),('244036'),('244036'),('244036'),('244037'),('244037'),('244037'),('244037'),('244037'),('244037'),('244037'),('244038'),('244038'),('244038'),('244038'),('244038'),('244038'),('244038'),('244039'),('244039'),('244039'),('244039'),('244039'),('244039'),('244039'),('203015'),('245002'),('245002'),('245001'),('245001'),('056029'),('056030'),('056032'),('424001'),('056034'),('056034'),('056034'),('056034'),('056033'),('056033'),('056033'),('805006'),('805007'),('805008'),('805009'),('805010'),('422008'),('422008'),('422007'),('422007'),('422006'),('422006'),('422010'),('422009'),('422009'),('422011'),('422011'),('209004'),('209004'),('150022'),('100002'),('056035'),('056035'),('056035'),('023036'),('023036'),('185005'),('246001'),('246001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247002'),('247002'),('425001'),('416006'),('416006'),('165042'),('165041'),('165040'),('165043'),('010040'),('010039'),('010038'),('010036'),('248001'),('248002'),('248003'),('248004'),('248005'),('249001'),('249003'),('249004'),('249005'),('250007'),('250001'),('250002'),('250003'),('250004'),('250005'),('250006'),('250008'),('250009'),('250010'),('250011'),('250012'),('250013'),('251001'),('251002'),('806001'),('806002'),('235010'),('243009'),('249007'),('249008'),('249009'),('011024'),('011025'),('429001'),('429001'),('429002'),('429002'),('429003'),('429003'); +select field from t1 group by field; +field +001001 +001010 +001018 +001020 +001021 +001027 +001028 +001030 +001031 +001100 +002003 +002004 +002005 +002007 +002008 +002009 +002012 +002013 +002014 +003002 +003003 +003004 +003005 +003006 +003007 +003008 +003009 +003010 +003011 +003012 +003013 +003014 +003015 +003016 +003017 +003018 +003019 +004003 +004005 +004006 +004008 +004010 +004012 +004014 +004016 +004017 +004020 +004021 +004022 +004023 +004025 +004026 +006004 +006006 +006010 +006011 +006012 +006014 +007001 +007002 +007003 +007005 +007007 +007008 +007009 +007011 +007012 +007013 +007015 +007016 +007017 +007018 +007019 +007020 +007021 +007022 +007023 +007025 +007027 +007029 +007031 +007032 +007034 +007036 +007037 +007038 +007040 +007043 +009001 +009002 +009004 +009005 +009006 +009007 +009008 +009010 +009011 +009012 +009013 +010002 +010003 +010004 +010005 +010006 +010007 +010008 +010009 +010010 +010011 +010012 +010013 +010015 +010016 +010017 +010018 +010019 +010020 +010021 +010022 +010023 +010026 +010027 +010028 +011001 +011002 +011003 +011004 +011006 +011012 +011013 +011014 +011015 +011016 +012017 +012027 +012032 +012034 +012036 +012037 +012038 +012039 +014001 +016016 +016019 +016020 +016021 +016022 +016023 +016024 +016026 +016028 +016029 +016030 +016031 +016032 +016033 +016034 +017002 +018001 +019002 +019004 +020001 +020004 +020006 +020008 +020009 +022001 +022002 +022003 +023001 +023002 +023003 +023004 +023005 +023006 +023007 +023010 +023011 +023017 +023019 +023020 +023025 +023026 +023027 +023028 +023029 +023030 +023032 +023033 +023034 +023035 +025001 +025003 +025004 +025005 +025007 +025008 +025009 +025010 +025011 +025012 +025013 +025014 +025015 +025016 +025018 +025019 +025020 +025021 +025022 +025023 +025024 +025025 +025026 +025027 +025028 +025030 +025031 +025033 +025034 +025035 +025037 +025041 +025042 +025043 +025046 +025048 +025049 +025050 +025051 +025052 +025053 +025054 +025055 +025056 +025057 +025058 +025060 +025061 +025062 +025063 +027001 +027002 +027011 +036001 +037003 +037006 +037007 +037008 +038009 +039001 +039002 +039003 +039004 +039005 +039006 +046001 +046002 +046003 +046005 +046007 +046008 +046009 +046010 +046012 +046013 +046014 +047001 +047002 +048001 +051003 +051004 +052001 +052002 +052005 +053016 +053019 +053023 +053024 +053026 +053028 +053029 +053033 +053045 +053046 +053051 +053054 +053057 +053069 +053097 +053107 +053125 +053127 +054001 +054002 +054003 +054004 +054006 +054007 +054009 +054010 +056001 +056002 +056003 +056004 +056005 +056006 +056009 +056011 +056016 +056017 +056018 +056019 +056020 +056022 +057003 +057004 +058002 +058003 +058004 +058005 +060001 +060004 +060005 +060007 +061004 +061006 +069006 +069007 +069010 +069011 +069012 +069013 +069014 +069015 +069016 +069018 +069020 +069021 +069023 +071002 +071003 +071004 +071005 +071006 +071008 +071011 +071020 +071021 +071022 +072001 +074001 +074002 +074003 +074004 +074005 +074006 +074007 +074008 +074009 +074010 +074011 +074012 +075001 +075007 +076101 +076102 +076103 +077001 +077002 +077003 +077004 +077006 +077008 +077009 +078005 +079002 +079003 +079004 +079005 +079006 +079007 +081001 +082011 +082013 +082014 +082015 +082016 +082017 +082021 +082022 +082023 +082024 +082025 +082026 +082027 +082028 +082029 +082030 +082031 +082032 +082033 +082034 +082035 +082036 +082037 +082038 +082039 +082040 +082041 +082042 +082043 +082044 +084001 +084002 +084003 +084004 +084005 +084007 +084008 +084009 +084011 +084013 +084014 +084016 +084017 +084027 +084032 +084033 +084035 +084036 +084037 +084038 +084039 +084040 +084041 +084042 +084043 +084044 +084045 +084046 +084047 +084048 +084049 +084050 +084051 +085001 +085002 +085003 +085004 +085005 +085006 +085007 +085009 +085011 +085012 +085014 +085015 +085016 +085017 +085018 +085019 +085020 +085022 +085023 +085028 +085029 +085030 +085031 +085033 +085034 +085035 +085036 +085037 +085038 +085040 +085041 +085042 +085043 +085044 +085045 +085046 +085047 +085048 +085063 +085064 +085065 +085068 +085071 +085073 +085082 +085086 +085088 +085089 +085090 +085091 +085092 +085093 +085095 +085096 +085097 +085098 +085099 +085100 +085101 +085102 +085103 +085104 +085105 +085106 +085108 +085109 +085110 +085111 +085112 +085113 +085115 +085120 +085121 +085122 +085123 +085125 +085126 +085127 +085128 +085129 +085130 +085132 +085133 +085134 +085135 +085136 +085137 +086002 +086003 +086005 +088001 +088003 +088005 +088006 +088007 +088008 +088009 +089001 +090001 +090002 +090003 +090004 +090006 +090008 +090009 +090010 +090013 +090016 +090017 +090018 +090022 +090027 +091001 +091002 +091009 +091011 +091012 +091013 +091015 +091016 +091017 +091018 +093003 +099001 +100001 +106001 +113005 +113006 +113018 +113019 +113020 +115001 +115002 +115003 +115004 +115005 +115006 +115007 +115008 +115009 +115010 +115011 +115012 +115013 +115014 +115015 +115016 +115017 +115018 +115020 +115021 +115022 +115023 +115025 +115026 +115027 +115028 +115029 +115030 +115031 +115032 +115033 +115034 +115035 +115036 +115039 +115040 +115041 +115042 +115043 +115044 +115046 +115047 +115048 +115050 +115051 +115052 +115053 +115054 +115055 +115057 +115059 +115060 +115061 +115062 +115064 +115065 +115066 +115067 +115068 +115069 +115070 +115071 +115072 +115073 +115075 +115076 +115081 +115082 +115085 +115086 +115087 +115088 +115095 +115096 +115097 +115098 +115099 +115101 +115102 +115103 +115104 +115105 +115106 +115108 +115109 +115111 +115112 +115113 +115114 +115115 +115116 +115117 +115118 +115119 +115120 +115121 +115122 +116001 +116003 +116004 +116005 +116006 +116007 +116008 +116009 +116010 +116011 +116012 +123001 +124065 +126001 +126002 +126003 +126004 +126005 +126006 +126007 +126008 +126009 +126010 +126011 +126012 +130001 +132001 +132002 +133001 +133008 +133009 +133010 +133011 +133012 +133015 +133016 +133018 +133019 +133021 +133022 +133023 +133024 +133025 +133027 +133028 +133029 +133030 +133031 +134001 +135001 +135002 +135004 +135010 +137010 +137011 +137012 +137014 +137015 +137016 +137019 +139001 +140001 +141001 +141002 +141003 +141006 +141007 +141009 +141011 +141012 +141014 +141015 +141016 +141017 +141018 +141019 +141020 +141021 +141022 +141023 +141024 +141025 +141026 +141027 +141028 +145001 +145002 +145003 +145004 +145005 +145006 +145008 +145009 +145011 +145012 +145013 +150009 +150013 +150014 +150015 +150016 +150017 +150020 +152001 +152002 +152003 +152004 +152005 +152006 +152007 +154001 +154002 +155001 +155002 +155003 +155004 +155006 +159001 +159003 +160001 +160002 +161001 +162002 +162003 +162007 +162012 +163001 +163011 +163015 +163016 +165001 +165002 +165003 +165004 +165005 +165006 +165007 +165008 +165009 +165010 +165011 +165012 +165013 +165014 +165015 +165016 +165017 +165018 +165019 +165020 +165021 +165022 +165023 +165024 +165025 +165026 +165028 +165029 +165030 +165031 +165033 +165034 +165035 +165036 +168003 +168004 +168005 +168014 +169001 +169002 +169003 +169007 +169008 +169009 +169010 +171006 +171007 +171008 +171009 +172001 +176001 +176002 +176003 +177001 +179007 +179012 +179013 +179042 +179044 +179045 +180001 +180013 +180014 +180015 +180017 +180018 +180020 +180021 +180027 +180030 +180033 +180035 +180036 +180037 +180038 +180041 +180042 +180045 +180047 +180048 +180049 +180050 +180054 +180060 +180066 +180067 +180068 +180070 +182001 +184001 +184002 +184005 +184006 +184008 +184009 +184010 +184011 +185001 +185003 +187001 +191002 +192002 +194003 +197001 +197002 +197003 +197004 +197005 +197006 +198001 +198003 +198004 +198005 +198006 +198007 +198008 +198009 +198010 +198011 +198012 +198015 +198016 +198017 +201001 +201002 +202001 +203001 +203002 +203003 +203017 +203018 +203019 +204001 +204002 +205001 +208001 +208002 +208003 +208004 +208005 +209001 +209002 +209003 +210001 +210004 +210009 +210010 +212001 +212002 +212003 +212004 +212005 +212006 +212007 +212008 +212009 +212010 +212011 +212012 +212013 +218001 +218004 +218009 +218011 +218015 +218020 +218021 +218022 +218023 +218024 +218025 +218026 +218027 +218028 +218029 +218030 +218031 +221001 +221002 +221003 +221004 +221005 +221006 +221007 +221008 +221009 +221010 +221011 +221012 +221013 +223003 +224001 +224002 +224003 +224007 +224008 +225001 +225002 +225003 +225004 +225005 +225006 +225007 +225008 +225009 +225010 +225011 +225012 +225013 +226001 +226002 +226003 +226005 +226006 +226007 +227011 +227015 +227041 +227045 +227052 +227056 +227063 +227064 +227066 +227067 +227069 +227071 +227073 +227085 +227116 +227119 +227131 +227133 +227147 +229005 +233003 +233004 +235001 +235002 +235003 +235004 +235005 +236001 +236002 +236003 +238002 +238003 +238004 +238005 +238007 +238008 +334005 +334006 +337001 +337002 +337003 +337004 +343001 +344001 +344002 +344003 +344004 +344005 +345001 +348001 +348004 +348005 +349001 +349002 +350001 +353002 +353003 +355001 +355002 +355005 +355006 +356001 +358001 +359001 +359002 +360001 +360002 +360003 +360004 +360005 +366001 +366002 +366003 +366004 +369001 +373001 +373002 +373003 +373005 +373007 +373008 +373009 +373010 +373011 +373012 +373013 +373014 +373015 +373017 +373018 +373021 +374002 +374004 +374006 +374007 +374008 +374009 +374010 +374011 +374012 +374015 +374016 +382001 +382002 +384001 +386001 +386002 +386003 +386004 +386005 +386006 +386007 +386008 +386009 +386010 +386011 +386012 +386013 +386014 +389001 +389002 +389003 +389004 +392001 +393001 +393002 +393003 +393004 +395001 +397001 +397002 +399001 +399002 +399003 +400001 +400002 +403002 +504001 +504002 +504004 +504005 +504006 +504007 +504008 +504009 +504010 +504011 +504012 +504014 +504017 +504021 +504022 +504023 +504024 +504025 +506001 +506002 +511001 +511002 +511003 +511004 +511005 +511006 +511007 +511008 +511009 +511010 +511011 +511012 +511013 +511014 +511017 +511018 +511020 +511021 +511022 +511024 +511028 +511029 +513001 +513002 +513003 +513004 +515001 +515002 +515003 +515007 +515008 +515011 +515012 +515013 +515014 +515015 +518001 +518002 +521001 +521002 +521003 +521004 +521005 +521006 +521009 +521010 +521011 +521012 +521013 +521015 +521016 +523001 +523002 +523003 +523004 +523005 +523006 +523007 +524001 +700001 +701001 +701002 +701003 +702001 +702002 +702004 +702005 +704001 +704004 +705001 +706001 +706002 +707001 +707002 +707003 +708001 +710001 +710002 +711001 +711002 +712001 +714001 +714002 +715001 +719001 +719002 +991002 +991003 +991004 +991005 +991006 +991007 +995001 +996001 +996002 +996003 +998001 +998002 +998003 +998004 +998005 +998006 +998007 +999001 +999002 +011017 +011018 +034001 +034002 +071010 +519001 +126013 +184012 +404001 +405002 +405001 +405003 +405006 +240011 +240010 +240009 +240008 +240007 +240005 +240004 +240003 +240002 +240001 +240012 +240013 +240014 +240015 +240016 +240017 +357001 +235006 +235007 +056023 +046015 +019005 +126014 +241003 +241002 +241001 +240020 +240019 +242001 +242002 +242004 +242005 +242006 +089002 +406001 +406002 +406003 +406004 +243001 +243005 +243006 +243007 +243008 +408001 +366005 +016035 +077010 +996004 +025064 +011019 +115123 +504026 +039007 +039009 +039008 +039010 +039011 +039012 +180072 +240021 +240023 +405008 +525002 +410002 +410004 +410005 +410006 +410007 +410008 +410009 +410010 +410011 +410012 +410013 +410014 +410016 +344006 +240031 +240030 +240029 +240028 +240027 +240026 +240025 +240024 +240034 +240033 +240032 +411001 +411002 +203020 +069025 +244001 +244002 +244009 +244008 +244007 +244006 +244004 +244003 +244014 +244013 +244012 +244011 +244016 +244017 +240040 +240037 +405009 +405010 +240043 +504028 +504040 +800001 +410019 +410020 +410021 +244018 +244019 +244020 +413001 +344007 +082045 +010031 +010032 +010033 +010034 +010035 +504044 +515016 +801002 +801003 +801004 +801005 +802001 +801001 +414001 +141029 +803001 +803002 +803004 +803005 +803006 +803007 +803008 +803009 +803013 +803014 +803015 +803016 +803017 +410022 +410023 +803019 +415002 +415001 +244021 +011020 +011023 +011022 +011021 +025065 +165037 +165038 +165039 +416001 +416002 +416003 +417001 +418001 +504045 +803022 +240022 +420001 +804010 +804005 +804002 +804018 +804013 +511019 +511016 +511015 +511032 +511031 +511030 +511027 +511026 +511025 +511033 +511023 +133034 +133033 +169011 +344008 +244022 +244026 +244025 +244030 +244023 +244024 +244027 +244028 +244029 +244031 +082046 +082047 +082048 +126015 +126016 +416005 +421001 +421002 +016037 +016036 +115124 +115126 +240049 +240048 +240047 +240046 +240045 +240044 +244032 +244033 +422002 +422004 +422005 +184013 +805001 +805002 +805003 +805004 +805005 +056024 +423001 +344010 +235009 +212014 +056025 +056026 +244034 +244035 +244036 +244037 +244038 +244039 +203015 +245002 +245001 +056029 +056030 +056032 +424001 +056034 +056033 +805006 +805007 +805008 +805009 +805010 +422008 +422007 +422006 +422010 +422009 +422011 +209004 +150022 +100002 +056035 +023036 +185005 +246001 +247001 +247002 +425001 +416006 +165042 +165041 +165040 +165043 +010040 +010039 +010038 +010036 +248001 +248002 +248003 +248004 +248005 +249001 +249003 +249004 +249005 +250007 +250001 +250002 +250003 +250004 +250005 +250006 +250008 +250009 +250010 +250011 +250012 +250013 +251001 +251002 +806001 +806002 +235010 +243009 +249007 +249008 +249009 +011024 +011025 +429001 +429002 +429003 +drop table t1; +create table t1 (a enum (' ','a','b') not null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` enum('','a','b') NOT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a enum (' ','a','b ') not null default 'b '); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` enum('','a','b') NOT NULL DEFAULT 'b' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a enum ('0','1')); +insert into t1 set a='foobar'; +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +select * from t1; +a + +update t1 set a = replace(a,'x','y'); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +select * from t1; +a + +drop table t1; +set names latin1; +create table t1 (a enum(0xE4, '1', '2') not null default 0xE4); +show columns from t1; +Field Type Null Key Default Extra +a enum('ä','1','2') NO ä +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` enum('ä','1','2') NOT NULL DEFAULT 'ä' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +set names latin1; +CREATE TABLE t1 ( +a INT default 1, +b ENUM('value','öäü_value','ÊÃÕ') character set latin1 NOT NULL +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT '1', + `b` enum('value','öäü_value','ÊÃÕ') NOT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show columns from t1; +Field Type Null Key Default Extra +a int(11) YES 1 +b enum('value','öäü_value','ÊÃÕ') NO NULL +drop table t1; +CREATE TABLE t1 (c enum('a', 'A') BINARY); +INSERT INTO t1 VALUES ('a'),('A'); +SELECT * FROM t1; +c +a +A +DROP TABLE t1; +CREATE TABLE t1 (c enum('ae','oe','ue','ss') collate latin1_german2_ci); +INSERT INTO t1 VALUES ('ä'),('ö'),('ü'),('ß'); +SELECT * FROM t1; +c +ae +oe +ue +ss +DROP TABLE t1; +CREATE TABLE t1 ( +a ENUM('ä','ö','ü') character set utf8 default 'ü' +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` enum('ä','ö','ü') CHARACTER SET utf8 DEFAULT 'ü' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert into t1 values ('ä'), ('ö'), ('ü'); +select a from t1 order by a; +a +ä +ö +ü +drop table t1; +set names utf8; +CREATE TABLE t1 ( +a ENUM('ä','ö','ü') character set latin1 default 'ü' +); +insert into t1 values ('ä'),('ö'),('ü'); +set names latin1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` enum('ä','ö','ü') DEFAULT 'ü' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select a from t1 order by a; +a +ä +ö +ü +drop table t1; +create table t1 (a enum ('Y','N') CHARACTER SET utf8 COLLATE utf8_bin); +insert into t1 values ('Y'); +alter table t1 add b set ('Y','N') CHARACTER SET utf8 COLLATE utf8_bin; +alter table t1 add c enum ('Y','N') CHARACTER SET utf8 COLLATE utf8_bin; +select * from t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 a a 254 1 1 Y 384 0 8 +def test t1 t1 b b 254 3 0 Y 2176 0 8 +def test t1 t1 c c 254 1 0 Y 384 0 8 +a b c +Y NULL NULL +drop table t1; +create table t1 (a enum('x','y') default 'x'); +alter table t1 alter a set default 'z'; +ERROR 42000: Invalid default value for 'a' +drop table t1; +create table t1 (a set('x','y') default 'x'); +alter table t1 alter a set default 'z'; +ERROR 42000: Invalid default value for 'a' +drop table t1; +create table t1 (f1 int); +alter table t1 add f2 enum(0xFFFF); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) DEFAULT NULL, + `f2` enum('ÿÿ') DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +End of 4.1 tests +create table t1(russian enum('E','F','EÿF','FÿE') NOT NULL DEFAULT'E'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `russian` enum('E','F','EÿF','FÿE') NOT NULL DEFAULT 'E' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1(denormal enum('E','F','E,F','F,E') NOT NULL DEFAULT'E'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `denormal` enum('E','F','E,F','F,E') NOT NULL DEFAULT 'E' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1(russian_deviant enum('E','F','EÿF','F,E') NOT NULL DEFAULT'E'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `russian_deviant` enum('E','F','EÿF','F,E') NOT NULL DEFAULT 'E' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1(exhausting_charset enum('ABCDEFGHIJKLMNOPQRSTUVWXYZ',' + + !"','#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~','xx\','yy\€','zz‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ')); +ERROR HY000: Can't create table 'test.t1' (errno: -1) +End of 5.1 tests diff --git a/mysql-test/suite/pbxt/r/type_float.result b/mysql-test/suite/pbxt/r/type_float.result new file mode 100644 index 00000000000..4029909bce3 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_float.result @@ -0,0 +1,275 @@ +drop table if exists t1,t2; +SELECT 10,10.0,10.,.1e+2,100.0e-1; +10 10.0 10. .1e+2 100.0e-1 +10 10.0 10 10 10 +SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000; +6e-05 -6e-05 --6e-05 -6e-05+1.000000 +6e-05 -6e-05 6e-05 0.99994 +SELECT 1e1,1.e1,1.0e1,1e+1,1.e+1,1.0e+1,1e-1,1.e-1,1.0e-1; +1e1 1.e1 1.0e1 1e+1 1.e+1 1.0e+1 1e-1 1.e-1 1.0e-1 +10 10 10 10 10 10 0.1 0.1 0.1 +SELECT 0.001e+1,0.001e-1, -0.001e+01,-0.001e-01; +0.001e+1 0.001e-1 -0.001e+01 -0.001e-01 +0.01 0.0001 -0.01 -0.0001 +SELECT 123.23E+02,-123.23E-02,"123.23E+02"+0.0,"-123.23E-02"+0.0; +123.23E+02 -123.23E-02 "123.23E+02"+0.0 "-123.23E-02"+0.0 +12323 -1.2323 12323 -1.2323 +SELECT 2147483647E+02,21474836.47E+06; +2147483647E+02 21474836.47E+06 +214748364700 21474836470000 +create table t1 (f1 float(24),f2 float(52)); +show full columns from t1; +Field Type Collation Null Key Default Extra Privileges Comment +f1 float NULL YES NULL # +f2 double NULL YES NULL # +insert into t1 values(10,10),(1e+5,1e+5),(1234567890,1234567890),(1e+10,1e+10),(1e+15,1e+15),(1e+20,1e+20),(1e+50,1e+50),(1e+150,1e+150); +Warnings: +Warning 1264 Out of range value for column 'f1' at row 7 +Warning 1264 Out of range value for column 'f1' at row 8 +insert into t1 values(-10,-10),(1e-5,1e-5),(1e-10,1e-10),(1e-15,1e-15),(1e-20,1e-20),(1e-50,1e-50),(1e-150,1e-150); +select * from t1; +f1 f2 +10 10 +100000 100000 +1.23457e+09 1234567890 +1e+10 10000000000 +1e+15 1e+15 +1e+20 1e+20 +3.40282e+38 1e+50 +3.40282e+38 1e+150 +-10 -10 +1e-05 1e-05 +1e-10 1e-10 +1e-15 1e-15 +1e-20 1e-20 +0 1e-50 +0 1e-150 +drop table t1; +create table t1 (datum double); +insert into t1 values (0.5),(1.0),(1.5),(2.0),(2.5); +select * from t1; +datum +0.5 +1 +1.5 +2 +2.5 +select * from t1 where datum < 1.5; +datum +0.5 +1 +select * from t1 where datum > 1.5; +datum +2 +2.5 +select * from t1 where datum = 1.5; +datum +1.5 +drop table t1; +create table t1 (a decimal(7,3) not null, key (a)); +insert into t1 values ("0"),("-0.00"),("-0.01"),("-0.002"),("1"); +select a from t1 order by a; +a +-0.010 +-0.002 +0.000 +0.000 +1.000 +select min(a) from t1; +min(a) +-0.010 +drop table t1; +create table t1 (c1 double, c2 varchar(20)); +insert t1 values (121,"16"); +select c1 + c1 * (c2 / 100) as col from t1; +col +140.36 +create table t2 select c1 + c1 * (c2 / 100) as col1, round(c1, 5) as col2, round(c1, 35) as col3, sqrt(c1*1e-15) col4 from t1; +select * from t2; +col1 col2 col3 col4 +140.36 121.00000 121 3.47850542618522e-07 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `col1` double DEFAULT NULL, + `col2` double(22,5) DEFAULT NULL, + `col3` double DEFAULT NULL, + `col4` double DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1,t2; +create table t1 (a float); +insert into t1 values (1); +select max(a),min(a),avg(a) from t1; +max(a) min(a) avg(a) +1 1 1 +drop table t1; +create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(7,6)); +show full columns from t1; +Field Type Collation Null Key Default Extra Privileges Comment +f float NULL YES NULL # +f2 float NULL YES NULL # +f3 float(6,2) NULL YES NULL # +d double NULL YES NULL # +d2 double NULL YES NULL # +d3 double(10,3) NULL YES NULL # +de decimal(10,0) NULL YES NULL # +de2 decimal(6,0) NULL YES NULL # +de3 decimal(5,2) NULL YES NULL # +n decimal(10,0) NULL YES NULL # +n2 decimal(8,0) NULL YES NULL # +n3 decimal(7,6) NULL YES NULL # +drop table t1; +create table t1 (a decimal(7,3) not null, key (a)); +insert into t1 values ("0"),("-0.00"),("-0.01"),("-0.002"),("1"); +select a from t1 order by a; +a +-0.010 +-0.002 +0.000 +0.000 +1.000 +select min(a) from t1; +min(a) +-0.010 +drop table t1; +create table t1 (a float(200,100), b double(200,100)); +ERROR 42000: Too big scale 100 specified for column 'a'. Maximum is 30. +create table t1 (c20 char); +insert into t1 values (5000.0); +Warnings: +Warning 1265 Data truncated for column 'c20' at row 1 +insert into t1 values (0.5e4); +Warnings: +Warning 1265 Data truncated for column 'c20' at row 1 +drop table t1; +create table t1 (f float(54)); +ERROR 42000: Incorrect column specifier for column 'f' +drop table if exists t1; +create table t1 (d1 double, d2 double unsigned); +insert into t1 set d1 = -1.0; +update t1 set d2 = d1; +Warnings: +Warning 1264 Out of range value for column 'd2' at row 1 +select * from t1; +d1 d2 +-1 0 +drop table t1; +create table t1 (f float(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +Warnings: +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f' at row 2 +Warning 1264 Out of range value for column 'f' at row 3 +Warning 1264 Out of range value for column 'f' at row 4 +Warning 1264 Out of range value for column 'f' at row 5 +Warning 1264 Out of range value for column 'f' at row 6 +select * from t1; +f +-9.999 +-9.999 +-9.999 +9.999 +9.999 +9.999 +drop table if exists t1; +create table t1 (f double(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +Warnings: +Warning 1264 Out of range value for column 'f' at row 1 +Warning 1264 Out of range value for column 'f' at row 2 +Warning 1264 Out of range value for column 'f' at row 3 +Warning 1264 Out of range value for column 'f' at row 4 +Warning 1264 Out of range value for column 'f' at row 5 +Warning 1264 Out of range value for column 'f' at row 6 +select * from t1; +f +-9.999 +-9.999 +-9.999 +9.999 +9.999 +9.999 +drop table if exists t1; +create table t1 (c char(20)); +insert into t1 values (5e-28); +select * from t1; +c +5e-28 +drop table t1; +create table t1 (c char(6)); +insert into t1 values (2e5),(2e6),(2e-4),(2e-5); +select * from t1; +c +200000 +2e+06 +0.0002 +2e-05 +drop table t1; +CREATE TABLE t1 ( +reckey int unsigned NOT NULL, +recdesc varchar(50) NOT NULL, +PRIMARY KEY (reckey) +) ENGINE=PBXT DEFAULT CHARSET=latin1; +INSERT INTO t1 VALUES (108, 'Has 108 as key'); +INSERT INTO t1 VALUES (109, 'Has 109 as key'); +select * from t1 where reckey=108; +reckey recdesc +108 Has 108 as key +select * from t1 where reckey=1.08E2; +reckey recdesc +108 Has 108 as key +select * from t1 where reckey=109; +reckey recdesc +109 Has 109 as key +select * from t1 where reckey=1.09E2; +reckey recdesc +109 Has 109 as key +drop table t1; +create table t1 (d double(10,1)); +create table t2 (d double(10,9)); +insert into t1 values ("100000000.0"); +insert into t2 values ("1.23456780"); +create table t3 select * from t2 union select * from t1; +select * from t3; +d +1.2345678 +100000000 +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `d` double DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1, t2, t3; +create table t1 select 105213674794682365.00 + 0.0 x; +show warnings; +Level Code Message +desc t1; +Field Type Null Key Default Extra +x decimal(21,2) NO 0.00 +drop table t1; +create table t1 select 0.0 x; +desc t1; +Field Type Null Key Default Extra +x decimal(2,1) NO 0.0 +create table t2 select 105213674794682365.00 y; +desc t2; +Field Type Null Key Default Extra +y decimal(20,2) NO 0.00 +create table t3 select x+y a from t1,t2; +show warnings; +Level Code Message +desc t3; +Field Type Null Key Default Extra +a decimal(21,2) NO 0.00 +drop table t1,t2,t3; +select 1e-308, 1.00000001e-300, 100000000e-300; +1e-308 1.00000001e-300 100000000e-300 +1e-308 1.00000001e-300 1e-292 +select 10e307; +10e307 +1e+308 +End of 4.1 tests +create table t1 (s1 float(0,2)); +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1'). +create table t1 (s1 float(1,2)); +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1'). diff --git a/mysql-test/suite/pbxt/r/type_nchar.result b/mysql-test/suite/pbxt/r/type_nchar.result new file mode 100644 index 00000000000..4b315a674ca --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_nchar.result @@ -0,0 +1,50 @@ +drop table if exists t1; +create table t1 (c nchar(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` char(10) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (c national char(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` char(10) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (c national varchar(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` varchar(10) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (c nvarchar(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` varchar(10) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (c nchar varchar(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` varchar(10) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (c national character varying(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` varchar(10) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (c nchar varying(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` varchar(10) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/type_newdecimal.result b/mysql-test/suite/pbxt/r/type_newdecimal.result new file mode 100644 index 00000000000..4978a244c76 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_newdecimal.result @@ -0,0 +1,1450 @@ +drop table if exists t1; +select 1.1 IN (1.0, 1.2); +1.1 IN (1.0, 1.2) +0 +select 1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5); +1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5) +1 +select 1.1 IN (1.0, 1.2, NULL, 1.4, 0.5); +1.1 IN (1.0, 1.2, NULL, 1.4, 0.5) +NULL +select 0.5 IN (1.0, 1.2, NULL, 1.4, 0.5); +0.5 IN (1.0, 1.2, NULL, 1.4, 0.5) +1 +select 1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5); +1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5) +1 +select 1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5); +1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5) +NULL +select case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END +b +select case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END +a +select case 1 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 1 when 0.1 then "a" when 1.0 then "b" else "c" END +b +select case 1.0 when 0.1 then "a" when 1 then "b" else "c" END; +case 1.0 when 0.1 then "a" when 1 then "b" else "c" END +b +select case 1.001 when 0.1 then "a" when 1 then "b" else "c" END; +case 1.001 when 0.1 then "a" when 1 then "b" else "c" END +c +create table t1 (a decimal(6,3)); +insert into t1 values (1.0), (NULL), (0.1); +select * from t1; +a +1.000 +NULL +0.100 +select 0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) from t1; +0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) +0 +NULL +1 +drop table t1; +create table t1 select if(1, 1.1, 1.2), if(0, 1.1, 1.2), if(0.1, 1.1, 1.2), if(0, 1, 1.1), if(0, NULL, 1.2), if(1, 0.22e1, 1.1), if(1E0, 1.1, 1.2); +select * from t1; +if(1, 1.1, 1.2) if(0, 1.1, 1.2) if(0.1, 1.1, 1.2) if(0, 1, 1.1) if(0, NULL, 1.2) if(1, 0.22e1, 1.1) if(1E0, 1.1, 1.2) +1.1 1.2 1.1 1.1 1.2 2.2 1.1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `if(1, 1.1, 1.2)` decimal(2,1) NOT NULL DEFAULT '0.0', + `if(0, 1.1, 1.2)` decimal(2,1) NOT NULL DEFAULT '0.0', + `if(0.1, 1.1, 1.2)` decimal(2,1) NOT NULL DEFAULT '0.0', + `if(0, 1, 1.1)` decimal(2,1) NOT NULL DEFAULT '0.0', + `if(0, NULL, 1.2)` decimal(2,1) DEFAULT NULL, + `if(1, 0.22e1, 1.1)` double NOT NULL DEFAULT '0', + `if(1E0, 1.1, 1.2)` decimal(2,1) NOT NULL DEFAULT '0.0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select nullif(1.1, 1.1), nullif(1.1, 1.2), nullif(1.1, 0.11e1), nullif(1.0, 1), nullif(1, 1.0), nullif(1, 1.1); +select * from t1; +nullif(1.1, 1.1) nullif(1.1, 1.2) nullif(1.1, 0.11e1) nullif(1.0, 1) nullif(1, 1.0) nullif(1, 1.1) +NULL 1.1 NULL NULL NULL 1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `nullif(1.1, 1.1)` decimal(2,1) DEFAULT NULL, + `nullif(1.1, 1.2)` decimal(2,1) DEFAULT NULL, + `nullif(1.1, 0.11e1)` decimal(2,1) DEFAULT NULL, + `nullif(1.0, 1)` decimal(2,1) DEFAULT NULL, + `nullif(1, 1.0)` int(1) DEFAULT NULL, + `nullif(1, 1.1)` int(1) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a decimal(4,2)); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +Warning 1264 Out of range value for column 'a' at row 4 +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +Warning 1264 Out of range value for column 'a' at row 4 +select a from t1; +a +99.99 +99.99 +99.99 +99.99 +-99.99 +-99.99 +-99.99 +-99.99 +drop table t1; +create table t1 (a decimal(4,2) unsigned); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +Warning 1264 Out of range value for column 'a' at row 4 +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 2 +Warning 1264 Out of range value for column 'a' at row 3 +Warning 1264 Out of range value for column 'a' at row 4 +select a from t1; +a +99.99 +99.99 +99.99 +99.99 +0.00 +0.00 +0.00 +0.00 +drop table t1; +create table t1 (a bigint); +insert into t1 values (18446744073709551615.0); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +insert into t1 values (9223372036854775808.0); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +insert into t1 values (-18446744073709551615.0); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +9223372036854775807 +9223372036854775807 +-9223372036854775808 +drop table t1; +create table t1 (a bigint unsigned); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (9999999999999999999999999.000); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +insert into t1 values (-1.0); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +18446744073709551615 +9223372036854775808 +18446744073709551615 +0 +drop table t1; +create table t1 (a tinyint); +insert into t1 values (18446744073709551615.0); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 1 +insert into t1 values (9223372036854775808.0); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 1264 Out of range value for column 'a' at row 1 +select * from t1; +a +127 +127 +drop table t1; +create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(-1.1); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `round(15.4,-1)` decimal(3,0) NOT NULL DEFAULT '0', + `truncate(-5678.123451,-3)` decimal(4,0) NOT NULL DEFAULT '0', + `abs(-1.1)` decimal(3,1) NOT NULL DEFAULT '0.0', + `-(-1.1)` decimal(2,1) NOT NULL DEFAULT '0.0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +set session sql_mode='traditional'; +select 1e10/0e0; +1e10/0e0 +NULL +Warnings: +Error 1365 Division by 0 +create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10)); +insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890); +select * from wl1612; +col1 col2 col3 +1 12345678901234567890.1234567890 12345678901234567890.1234567890 +insert into wl1612 values(2,01234567890123456789.0123456789,01234567890123456789.0123456789); +select * from wl1612 where col1=2; +col1 col2 col3 +2 1234567890123456789.0123456789 1234567890123456789.0123456789 +insert into wl1612 values(3,1234567890123456789012345678.0123456789,1234567890123456789012345678.0123456789); +select * from wl1612 where col1=3; +col1 col2 col3 +3 1234567890123456789012345678.0123456789 1234567890123456789012345678.0123456789 +select col1/0 from wl1612; +col1/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +select col2/0 from wl1612; +col2/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +select col3/0 from wl1612; +col3/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +insert into wl1612 values(5,5000.0005,5000.0005); +insert into wl1612 values(6,5000.0005,5000.0005); +select sum(col2),sum(col3) from wl1612; +sum(col2) sum(col3) +1234567903703703580370380357.1491481468 1234567903703703580370380357.1491481468 +insert into wl1612 values(7,500000.000005,500000.000005); +insert into wl1612 values(8,500000.000005,500000.000005); +select sum(col2),sum(col3) from wl1612 where col1>4; +sum(col2) sum(col3) +1010000.0010100000 1010000.0010100000 +insert into wl1612 (col1, col2) values(9,1.01234567891); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(10,1.01234567894); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(11,1.01234567895); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(12,1.01234567896); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +select col1,col2 from wl1612 where col1>8; +col1 col2 +9 1.0123456789 +10 1.0123456789 +11 1.0123456790 +12 1.0123456790 +insert into wl1612 (col1, col3) values(13,1.01234567891); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(14,1.01234567894); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(15,1.01234567895); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(16,1.01234567896); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +select col1,col3 from wl1612 where col1>12; +col1 col3 +13 1.0123456789 +14 1.0123456789 +15 1.0123456790 +16 1.0123456790 +select col1 from wl1612 where col1>4 and col2=1.01234567891; +col1 +select col1 from wl1612 where col1>4 and col2=1.0123456789; +col1 +9 +10 +select col1 from wl1612 where col1>4 and col2<>1.0123456789; +col1 +5 +6 +7 +8 +11 +12 +select col1 from wl1612 where col1>4 and col2<1.0123456789; +col1 +select col1 from wl1612 where col1>4 and col2<=1.0123456789; +col1 +9 +10 +select col1 from wl1612 where col1>4 and col2>1.0123456789; +col1 +5 +6 +7 +8 +11 +12 +select col1 from wl1612 where col1>4 and col2>=1.0123456789; +col1 +5 +6 +7 +8 +9 +10 +11 +12 +select col1 from wl1612 where col1>4 and col2=1.012345679; +col1 +11 +12 +select col1 from wl1612 where col1>4 and col2<>1.012345679; +col1 +5 +6 +7 +8 +9 +10 +select col1 from wl1612 where col1>4 and col3=1.01234567891; +col1 +select col1 from wl1612 where col1>4 and col3=1.0123456789; +col1 +13 +14 +select col1 from wl1612 where col1>4 and col3<>1.0123456789; +col1 +5 +6 +7 +8 +15 +16 +select col1 from wl1612 where col1>4 and col3<1.0123456789; +col1 +select col1 from wl1612 where col1>4 and col3<=1.0123456789; +col1 +13 +14 +select col1 from wl1612 where col1>4 and col3>1.0123456789; +col1 +5 +6 +7 +8 +15 +16 +select col1 from wl1612 where col1>4 and col3>=1.0123456789; +col1 +5 +6 +7 +8 +13 +14 +15 +16 +select col1 from wl1612 where col1>4 and col3=1.012345679; +col1 +15 +16 +select col1 from wl1612 where col1>4 and col3<>1.012345679; +col1 +5 +6 +7 +8 +13 +14 +drop table wl1612; +select 1/3; +1/3 +0.3333 +select 0.8=0.7+0.1; +0.8=0.7+0.1 +1 +select 0.7+0.1; +0.7+0.1 +0.8 +create table wl1612_1 (col1 int); +insert into wl1612_1 values(10); +select * from wl1612_1 where 0.8=0.7+0.1; +col1 +10 +select 0.07+0.07 from wl1612_1; +0.07+0.07 +0.14 +select 0.07-0.07 from wl1612_1; +0.07-0.07 +0.00 +select 0.07*0.07 from wl1612_1; +0.07*0.07 +0.0049 +select 0.07/0.07 from wl1612_1; +0.07/0.07 +1.000000 +drop table wl1612_1; +create table wl1612_2 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_2 values(1,1); +insert into wl1612_2 values(+1,+1); +insert into wl1612_2 values(+01,+01); +insert into wl1612_2 values(+001,+001); +select col1,count(*) from wl1612_2 group by col1; +col1 count(*) +1.00 4 +select col2,count(*) from wl1612_2 group by col2; +col2 count(*) +1.00 4 +drop table wl1612_2; +create table wl1612_3 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_3 values('1','1'); +insert into wl1612_3 values('+1','+1'); +insert into wl1612_3 values('+01','+01'); +insert into wl1612_3 values('+001','+001'); +select col1,count(*) from wl1612_3 group by col1; +col1 count(*) +1.00 4 +select col2,count(*) from wl1612_3 group by col2; +col2 count(*) +1.00 4 +drop table wl1612_3; +select mod(234,10) ; +mod(234,10) +4 +select mod(234.567,10.555); +mod(234.567,10.555) +2.357 +select mod(-234.567,10.555); +mod(-234.567,10.555) +-2.357 +select mod(234.567,-10.555); +mod(234.567,-10.555) +2.357 +select round(15.1); +round(15.1) +15 +select round(15.4); +round(15.4) +15 +select round(15.5); +round(15.5) +16 +select round(15.6); +round(15.6) +16 +select round(15.9); +round(15.9) +16 +select round(-15.1); +round(-15.1) +-15 +select round(-15.4); +round(-15.4) +-15 +select round(-15.5); +round(-15.5) +-16 +select round(-15.6); +round(-15.6) +-16 +select round(-15.9); +round(-15.9) +-16 +select round(15.1,1); +round(15.1,1) +15.1 +select round(15.4,1); +round(15.4,1) +15.4 +select round(15.5,1); +round(15.5,1) +15.5 +select round(15.6,1); +round(15.6,1) +15.6 +select round(15.9,1); +round(15.9,1) +15.9 +select round(-15.1,1); +round(-15.1,1) +-15.1 +select round(-15.4,1); +round(-15.4,1) +-15.4 +select round(-15.5,1); +round(-15.5,1) +-15.5 +select round(-15.6,1); +round(-15.6,1) +-15.6 +select round(-15.9,1); +round(-15.9,1) +-15.9 +select round(15.1,0); +round(15.1,0) +15 +select round(15.4,0); +round(15.4,0) +15 +select round(15.5,0); +round(15.5,0) +16 +select round(15.6,0); +round(15.6,0) +16 +select round(15.9,0); +round(15.9,0) +16 +select round(-15.1,0); +round(-15.1,0) +-15 +select round(-15.4,0); +round(-15.4,0) +-15 +select round(-15.5,0); +round(-15.5,0) +-16 +select round(-15.6,0); +round(-15.6,0) +-16 +select round(-15.9,0); +round(-15.9,0) +-16 +select round(15.1,-1); +round(15.1,-1) +20 +select round(15.4,-1); +round(15.4,-1) +20 +select round(15.5,-1); +round(15.5,-1) +20 +select round(15.6,-1); +round(15.6,-1) +20 +select round(15.9,-1); +round(15.9,-1) +20 +select round(-15.1,-1); +round(-15.1,-1) +-20 +select round(-15.4,-1); +round(-15.4,-1) +-20 +select round(-15.5,-1); +round(-15.5,-1) +-20 +select round(-15.6,-1); +round(-15.6,-1) +-20 +select round(-15.91,-1); +round(-15.91,-1) +-20 +select truncate(5678.123451,0); +truncate(5678.123451,0) +5678 +select truncate(5678.123451,1); +truncate(5678.123451,1) +5678.1 +select truncate(5678.123451,2); +truncate(5678.123451,2) +5678.12 +select truncate(5678.123451,3); +truncate(5678.123451,3) +5678.123 +select truncate(5678.123451,4); +truncate(5678.123451,4) +5678.1234 +select truncate(5678.123451,5); +truncate(5678.123451,5) +5678.12345 +select truncate(5678.123451,6); +truncate(5678.123451,6) +5678.123451 +select truncate(5678.123451,-1); +truncate(5678.123451,-1) +5670 +select truncate(5678.123451,-2); +truncate(5678.123451,-2) +5600 +select truncate(5678.123451,-3); +truncate(5678.123451,-3) +5000 +select truncate(5678.123451,-4); +truncate(5678.123451,-4) +0 +select truncate(-5678.123451,0); +truncate(-5678.123451,0) +-5678 +select truncate(-5678.123451,1); +truncate(-5678.123451,1) +-5678.1 +select truncate(-5678.123451,2); +truncate(-5678.123451,2) +-5678.12 +select truncate(-5678.123451,3); +truncate(-5678.123451,3) +-5678.123 +select truncate(-5678.123451,4); +truncate(-5678.123451,4) +-5678.1234 +select truncate(-5678.123451,5); +truncate(-5678.123451,5) +-5678.12345 +select truncate(-5678.123451,6); +truncate(-5678.123451,6) +-5678.123451 +select truncate(-5678.123451,-1); +truncate(-5678.123451,-1) +-5670 +select truncate(-5678.123451,-2); +truncate(-5678.123451,-2) +-5600 +select truncate(-5678.123451,-3); +truncate(-5678.123451,-3) +-5000 +select truncate(-5678.123451,-4); +truncate(-5678.123451,-4) +0 +create table wl1612_4 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); +insert into wl1612_4 values(1,0.0123456789012345678912345,0.0123456789012345678912345); +select col2/9999999999 from wl1612_4 where col1=1; +col2/9999999999 +0.00000000000123456789024691358 +select col3/9999999999 from wl1612_4 where col1=1; +col3/9999999999 +0.00000000000123456789024691358 +select 9999999999/col2 from wl1612_4 where col1=1; +9999999999/col2 +810000007209.0001 +select 9999999999/col3 from wl1612_4 where col1=1; +9999999999/col3 +810000007209.0001 +select col2*9999999999 from wl1612_4 where col1=1; +col2*9999999999 +123456789.0000000000111104321087655 +select col3*9999999999 from wl1612_4 where col1=1; +col3*9999999999 +123456789.0000000000111104321087655 +insert into wl1612_4 values(2,55555.0123456789012345678912345,55555.0123456789012345678912345); +select col2/9999999999 from wl1612_4 where col1=2; +col2/9999999999 +0.00000555550123512344024696913 +select col3/9999999999 from wl1612_4 where col1=2; +col3/9999999999 +0.00000555550123512344024696913 +select 9999999999/col2 from wl1612_4 where col1=2; +9999999999/col2 +180001.7600 +select 9999999999/col3 from wl1612_4 where col1=2; +9999999999/col3 +180001.7600 +select col2*9999999999 from wl1612_4 where col1=2; +col2*9999999999 +555550123401234.0000000000111104321087655 +select col3*9999999999 from wl1612_4 where col1=2; +col3*9999999999 +555550123401234.0000000000111104321087655 +drop table wl1612_4; +set sql_mode=''; +select 23.4 + (-41.7), 23.4 - (41.7) = -18.3; +23.4 + (-41.7) 23.4 - (41.7) = -18.3 +-18.3 1 +select -18.3=-18.3; +-18.3=-18.3 +1 +select 18.3=18.3; +18.3=18.3 +1 +select -18.3=18.3; +-18.3=18.3 +0 +select 0.8 = 0.7 + 0.1; +0.8 = 0.7 + 0.1 +1 +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (col1 decimal(38)); +insert into t1 values (12345678901234567890123456789012345678); +select * from t1; +col1 +12345678901234567890123456789012345678 +drop table t1; +create table t1 (col1 decimal(31,30)); +insert into t1 values (0.00000000001); +select * from t1; +col1 +0.000000000010000000000000000000 +drop table t1; +select 7777777777777777777777777777777777777 * 10; +7777777777777777777777777777777777777 * 10 +77777777777777777777777777777777777770 +select .7777777777777777777777777777777777777 * +1000000000000000000; +.7777777777777777777777777777777777777 * +1000000000000000000 +777777777777777777.777777777777777777700000000000 +select .7777777777777777777777777777777777777 - 0.1; +.7777777777777777777777777777777777777 - 0.1 +0.6777777777777777777777777777777777777 +select .343434343434343434 + .343434343434343434; +.343434343434343434 + .343434343434343434 +0.686868686868686868 +select abs(9999999999999999999999); +abs(9999999999999999999999) +9999999999999999999999 +select abs(-9999999999999999999999); +abs(-9999999999999999999999) +9999999999999999999999 +select ceiling(999999999999999999); +ceiling(999999999999999999) +999999999999999999 +select ceiling(99999999999999999999); +ceiling(99999999999999999999) +99999999999999999999 +select ceiling(9.9999999999999999999); +ceiling(9.9999999999999999999) +10 +select ceiling(-9.9999999999999999999); +ceiling(-9.9999999999999999999) +-9 +select floor(999999999999999999); +floor(999999999999999999) +999999999999999999 +select floor(9999999999999999999999); +floor(9999999999999999999999) +9999999999999999999999 +select floor(9.999999999999999999999); +floor(9.999999999999999999999) +9 +select floor(-9.999999999999999999999); +floor(-9.999999999999999999999) +-10 +select floor(-999999999999999999999.999); +floor(-999999999999999999999.999) +-1000000000000000000000 +select ceiling(999999999999999999999.999); +ceiling(999999999999999999999.999) +1000000000000000000000 +select 99999999999999999999999999999999999999 mod 3; +99999999999999999999999999999999999999 mod 3 +0 +select round(99999999999999999.999); +round(99999999999999999.999) +100000000000000000 +select round(-99999999999999999.999); +round(-99999999999999999.999) +-100000000000000000 +select round(99999999999999999.999,3); +round(99999999999999999.999,3) +99999999999999999.999 +select round(-99999999999999999.999,3); +round(-99999999999999999.999,3) +-99999999999999999.999 +select truncate(99999999999999999999999999999999999999,31); +truncate(99999999999999999999999999999999999999,31) +99999999999999999999999999999999999999.000000000000000000000000000000 +select truncate(99.999999999999999999999999999999999999,31); +truncate(99.999999999999999999999999999999999999,31) +99.999999999999999999999999999999 +select truncate(99999999999999999999999999999999999999,-31); +truncate(99999999999999999999999999999999999999,-31) +99999990000000000000000000000000000000 +create table t1 as select 0.5; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `0.5` decimal(2,1) NOT NULL DEFAULT '0.0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +select round(1.5),round(2.5); +round(1.5) round(2.5) +2 3 +select 0.07 * 0.07; +0.07 * 0.07 +0.0049 +set sql_mode='traditional'; +select 1E-500 = 0; +1E-500 = 0 +1 +select 1 / 1E-500; +1 / 1E-500 +NULL +Warnings: +Error 1365 Division by 0 +select 1 / 0; +1 / 0 +NULL +Warnings: +Error 1365 Division by 0 +set sql_mode='ansi,traditional'; +CREATE TABLE Sow6_2f (col1 NUMERIC(4,2)); +INSERT INTO Sow6_2f VALUES (10.55); +INSERT INTO Sow6_2f VALUES (10.5555); +Warnings: +Note 1265 Data truncated for column 'col1' at row 1 +INSERT INTO Sow6_2f VALUES (-10.55); +INSERT INTO Sow6_2f VALUES (-10.5555); +Warnings: +Note 1265 Data truncated for column 'col1' at row 1 +INSERT INTO Sow6_2f VALUES (11); +INSERT INTO Sow6_2f VALUES (101.55); +ERROR 22003: Out of range value for column 'col1' at row 1 +UPDATE Sow6_2f SET col1 = col1 * 50 WHERE col1 = 11; +ERROR 22003: Out of range value for column 'col1' at row 5 +UPDATE Sow6_2f SET col1 = col1 / 0 WHERE col1 > 0; +ERROR 22012: Division by 0 +SELECT MOD(col1,0) FROM Sow6_2f; +MOD(col1,0) +NULL +NULL +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +INSERT INTO Sow6_2f VALUES ('a59b'); +ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1 +drop table Sow6_2f; +select 10.3330000000000/12.34500000; +10.3330000000000/12.34500000 +0.83701903604698258 +set sql_mode=''; +select 0/0; +0/0 +NULL +select 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 as x; +x +99999999999999999999999999999999999999999999999999999999999999999 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + 1 as x; +x +100000000000000000000000000000000000000000000000000000000000000000 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +select 0.190287977636363637 + 0.040372670 * 0 - 0; +0.190287977636363637 + 0.040372670 * 0 - 0 +0.190287977636363637 +select -0.123 * 0; +-0.123 * 0 +0.000 +CREATE TABLE t1 (f1 DECIMAL (12,9), f2 DECIMAL(2,2)); +INSERT INTO t1 VALUES (10.5, 0); +UPDATE t1 SET f1 = 4.5; +SELECT * FROM t1; +f1 f2 +4.500000000 0.00 +DROP TABLE t1; +CREATE TABLE t1 (f1 DECIMAL (64,20), f2 DECIMAL(2,2)); +INSERT INTO t1 VALUES (9999999999999999999999999999999999, 0); +SELECT * FROM t1; +f1 f2 +9999999999999999999999999999999999.00000000000000000000 0.00 +DROP TABLE t1; +select abs(10/0); +abs(10/0) +NULL +select abs(NULL); +abs(NULL) +NULL +set @@sql_mode='traditional'; +create table t1( d1 decimal(18) unsigned, d2 decimal(20) unsigned, d3 decimal (22) unsigned); +insert into t1 values(1,-1,-1); +ERROR 22003: Out of range value for column 'd2' at row 1 +drop table t1; +create table t1 (col1 decimal(5,2), col2 numeric(5,2)); +insert into t1 values (999.999,999.999); +ERROR 22003: Out of range value for column 'col1' at row 1 +insert into t1 values (-999.999,-999.999); +ERROR 22003: Out of range value for column 'col1' at row 1 +select * from t1; +col1 col2 +drop table t1; +set sql_mode=''; +set @sav_dpi= @@div_precision_increment; +set @@div_precision_increment=15; +create table t1 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); +insert into t1 values (1,0.0123456789012345678912345,0.0123456789012345678912345); +select col2/9999999999 from t1 where col1=1; +col2/9999999999 +0.000000000001234567890246913578 +select 9999999999/col2 from t1 where col1=1; +9999999999/col2 +810000007209.000065537105051 +select 77777777/7777777; +77777777/7777777 +10.000000900000090 +drop table t1; +set div_precision_increment= @sav_dpi; +create table t1 (a decimal(4,2)); +insert into t1 values (0.00); +select * from t1 where a > -0.00; +a +select * from t1 where a = -0.00; +a +0.00 +drop table t1; +create table t1 (col1 bigint default -9223372036854775808); +insert into t1 values (default); +select * from t1; +col1 +-9223372036854775808 +drop table t1; +select cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15)); +cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15)) +0.000000000100000 +select ln(14000) c1, convert(ln(14000),decimal(5,3)) c2, cast(ln(14000) as decimal(5,3)) c3; +c1 c2 c3 +9.5468126085974 9.547 9.547 +select convert(ln(14000),decimal(2,3)) c1; +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column ''). +select cast(ln(14000) as decimal(2,3)) c1; +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column ''). +create table t1 (sl decimal(70,30)); +ERROR 42000: Too big precision 70 specified for column 'sl'. Maximum is 65. +create table t1 (sl decimal(32,31)); +ERROR 42000: Too big scale 31 specified for column 'sl'. Maximum is 30. +create table t1 (sl decimal(0,38)); +ERROR 42000: Too big scale 38 specified for column 'sl'. Maximum is 30. +create table t1 (sl decimal(0,30)); +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'sl'). +create table t1 (sl decimal(5, 5)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sl` decimal(5,5) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (sl decimal(65, 30)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sl` decimal(65,30) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +f1 decimal unsigned not null default 17.49, +f2 decimal unsigned not null default 17.68, +f3 decimal unsigned not null default 99.2, +f4 decimal unsigned not null default 99.7, +f5 decimal unsigned not null default 104.49, +f6 decimal unsigned not null default 199.91, +f7 decimal unsigned not null default 999.9, +f8 decimal unsigned not null default 9999.99); +Warnings: +Note 1265 Data truncated for column 'f1' at row 1 +Note 1265 Data truncated for column 'f2' at row 1 +Note 1265 Data truncated for column 'f3' at row 1 +Note 1265 Data truncated for column 'f4' at row 1 +Note 1265 Data truncated for column 'f5' at row 1 +Note 1265 Data truncated for column 'f6' at row 1 +Note 1265 Data truncated for column 'f7' at row 1 +Note 1265 Data truncated for column 'f8' at row 1 +insert into t1 (f1) values (1); +select * from t1; +f1 f2 f3 f4 f5 f6 f7 f8 +1 18 99 100 104 200 1000 10000 +drop table t1; +create table t1 ( +f0 decimal (30,30) zerofill not null DEFAULT 0, +f1 decimal (0,0) zerofill not null default 0); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f0` decimal(30,30) unsigned zerofill NOT NULL DEFAULT '0.000000000000000000000000000000', + `f1` decimal(10,0) unsigned zerofill NOT NULL DEFAULT '0000000000' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +drop procedure if exists wg2; +create procedure wg2() +begin +declare v int default 1; +declare tdec decimal(5) default 0; +while v <= 9 do set tdec =tdec * 10; +select v, tdec; +set v = v + 1; +end while; +end// +call wg2()// +v tdec +1 0 +v tdec +2 0 +v tdec +3 0 +v tdec +4 0 +v tdec +5 0 +v tdec +6 0 +v tdec +7 0 +v tdec +8 0 +v tdec +9 0 +drop procedure wg2; +select cast(@non_existing_user_var/2 as DECIMAL); +cast(@non_existing_user_var/2 as DECIMAL) +NULL +create table t (d decimal(0,10)); +ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'd'). +CREATE TABLE t1 ( +my_float FLOAT, +my_double DOUBLE, +my_varchar VARCHAR(50), +my_decimal DECIMAL(65,30) +); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `my_float` float DEFAULT NULL, + `my_double` double DEFAULT NULL, + `my_varchar` varchar(50) DEFAULT NULL, + `my_decimal` decimal(65,30) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +INSERT INTO t1 SET my_float = 1.175494345e-32, +my_double = 1.175494345e-32, +my_varchar = '1.175494345e-32'; +INSERT INTO t1 SET my_float = 1.175494345e-31, +my_double = 1.175494345e-31, +my_varchar = '1.175494345e-31'; +INSERT INTO t1 SET my_float = 1.175494345e-30, +my_double = 1.175494345e-30, +my_varchar = '1.175494345e-30'; +INSERT INTO t1 SET my_float = 1.175494345e-29, +my_double = 1.175494345e-29, +my_varchar = '1.175494345e-29'; +INSERT INTO t1 SET my_float = 1.175494345e-28, +my_double = 1.175494345e-28, +my_varchar = '1.175494345e-28'; +INSERT INTO t1 SET my_float = 1.175494345e-27, +my_double = 1.175494345e-27, +my_varchar = '1.175494345e-27'; +INSERT INTO t1 SET my_float = 1.175494345e-26, +my_double = 1.175494345e-26, +my_varchar = '1.175494345e-26'; +INSERT INTO t1 SET my_float = 1.175494345e-25, +my_double = 1.175494345e-25, +my_varchar = '1.175494345e-25'; +INSERT INTO t1 SET my_float = 1.175494345e-24, +my_double = 1.175494345e-24, +my_varchar = '1.175494345e-24'; +INSERT INTO t1 SET my_float = 1.175494345e-23, +my_double = 1.175494345e-23, +my_varchar = '1.175494345e-23'; +INSERT INTO t1 SET my_float = 1.175494345e-22, +my_double = 1.175494345e-22, +my_varchar = '1.175494345e-22'; +INSERT INTO t1 SET my_float = 1.175494345e-21, +my_double = 1.175494345e-21, +my_varchar = '1.175494345e-21'; +INSERT INTO t1 SET my_float = 1.175494345e-20, +my_double = 1.175494345e-20, +my_varchar = '1.175494345e-20'; +INSERT INTO t1 SET my_float = 1.175494345e-19, +my_double = 1.175494345e-19, +my_varchar = '1.175494345e-19'; +INSERT INTO t1 SET my_float = 1.175494345e-18, +my_double = 1.175494345e-18, +my_varchar = '1.175494345e-18'; +INSERT INTO t1 SET my_float = 1.175494345e-17, +my_double = 1.175494345e-17, +my_varchar = '1.175494345e-17'; +INSERT INTO t1 SET my_float = 1.175494345e-16, +my_double = 1.175494345e-16, +my_varchar = '1.175494345e-16'; +INSERT INTO t1 SET my_float = 1.175494345e-15, +my_double = 1.175494345e-15, +my_varchar = '1.175494345e-15'; +INSERT INTO t1 SET my_float = 1.175494345e-14, +my_double = 1.175494345e-14, +my_varchar = '1.175494345e-14'; +INSERT INTO t1 SET my_float = 1.175494345e-13, +my_double = 1.175494345e-13, +my_varchar = '1.175494345e-13'; +INSERT INTO t1 SET my_float = 1.175494345e-12, +my_double = 1.175494345e-12, +my_varchar = '1.175494345e-12'; +INSERT INTO t1 SET my_float = 1.175494345e-11, +my_double = 1.175494345e-11, +my_varchar = '1.175494345e-11'; +INSERT INTO t1 SET my_float = 1.175494345e-10, +my_double = 1.175494345e-10, +my_varchar = '1.175494345e-10'; +INSERT INTO t1 SET my_float = 1.175494345e-9, +my_double = 1.175494345e-9, +my_varchar = '1.175494345e-9'; +INSERT INTO t1 SET my_float = 1.175494345e-8, +my_double = 1.175494345e-8, +my_varchar = '1.175494345e-8'; +INSERT INTO t1 SET my_float = 1.175494345e-7, +my_double = 1.175494345e-7, +my_varchar = '1.175494345e-7'; +INSERT INTO t1 SET my_float = 1.175494345e-6, +my_double = 1.175494345e-6, +my_varchar = '1.175494345e-6'; +INSERT INTO t1 SET my_float = 1.175494345e-5, +my_double = 1.175494345e-5, +my_varchar = '1.175494345e-5'; +INSERT INTO t1 SET my_float = 1.175494345e-4, +my_double = 1.175494345e-4, +my_varchar = '1.175494345e-4'; +INSERT INTO t1 SET my_float = 1.175494345e-3, +my_double = 1.175494345e-3, +my_varchar = '1.175494345e-3'; +INSERT INTO t1 SET my_float = 1.175494345e-2, +my_double = 1.175494345e-2, +my_varchar = '1.175494345e-2'; +INSERT INTO t1 SET my_float = 1.175494345e-1, +my_double = 1.175494345e-1, +my_varchar = '1.175494345e-1'; +SELECT my_float, my_double, my_varchar FROM t1; +my_float my_double my_varchar +1.17549e-32 1.175494345e-32 1.175494345e-32 +1.17549e-31 1.175494345e-31 1.175494345e-31 +1.17549e-30 1.175494345e-30 1.175494345e-30 +1.17549e-29 1.175494345e-29 1.175494345e-29 +1.17549e-28 1.175494345e-28 1.175494345e-28 +1.17549e-27 1.175494345e-27 1.175494345e-27 +1.17549e-26 1.175494345e-26 1.175494345e-26 +1.17549e-25 1.175494345e-25 1.175494345e-25 +1.17549e-24 1.175494345e-24 1.175494345e-24 +1.17549e-23 1.175494345e-23 1.175494345e-23 +1.17549e-22 1.175494345e-22 1.175494345e-22 +1.17549e-21 1.175494345e-21 1.175494345e-21 +1.17549e-20 1.175494345e-20 1.175494345e-20 +1.17549e-19 1.175494345e-19 1.175494345e-19 +1.17549e-18 1.175494345e-18 1.175494345e-18 +1.17549e-17 1.175494345e-17 1.175494345e-17 +1.17549e-16 1.175494345e-16 1.175494345e-16 +1.17549e-15 1.175494345e-15 1.175494345e-15 +1.17549e-14 1.175494345e-14 1.175494345e-14 +1.17549e-13 1.175494345e-13 1.175494345e-13 +1.17549e-12 1.175494345e-12 1.175494345e-12 +1.17549e-11 1.175494345e-11 1.175494345e-11 +1.17549e-10 1.175494345e-10 1.175494345e-10 +1.17549e-09 1.175494345e-09 1.175494345e-9 +1.17549e-08 1.175494345e-08 1.175494345e-8 +1.17549e-07 1.175494345e-07 1.175494345e-7 +1.17549e-06 1.175494345e-06 1.175494345e-6 +1.17549e-05 1.175494345e-05 1.175494345e-5 +0.000117549 0.0001175494345 1.175494345e-4 +0.00117549 0.001175494345 1.175494345e-3 +0.0117549 0.01175494345 1.175494345e-2 +0.117549 0.1175494345 1.175494345e-1 +SELECT CAST(my_float AS DECIMAL(65,30)), my_float FROM t1; +CAST(my_float AS DECIMAL(65,30)) my_float +0.000000000000000000000000000000 1.17549e-32 +0.000000000000000000000000000000 1.17549e-31 +0.000000000000000000000000000001 1.17549e-30 +0.000000000000000000000000000012 1.17549e-29 +0.000000000000000000000000000118 1.17549e-28 +0.000000000000000000000000001175 1.17549e-27 +0.000000000000000000000000011755 1.17549e-26 +0.000000000000000000000000117549 1.17549e-25 +0.000000000000000000000001175494 1.17549e-24 +0.000000000000000000000011754943 1.17549e-23 +0.000000000000000000000117549438 1.17549e-22 +0.000000000000000000001175494332 1.17549e-21 +0.000000000000000000011754943324 1.17549e-20 +0.000000000000000000117549434853 1.17549e-19 +0.000000000000000001175494374380 1.17549e-18 +0.000000000000000011754943743802 1.17549e-17 +0.000000000000000117549432474939 1.17549e-16 +0.000000000000001175494324749389 1.17549e-15 +0.000000000000011754943671010360 1.17549e-14 +0.000000000000117549429933840000 1.17549e-13 +0.000000000001175494380653563000 1.17549e-12 +0.000000000011754943372854760000 1.17549e-11 +0.000000000117549428524377200000 1.17549e-10 +0.000000001175494368510499000000 1.17549e-09 +0.000000011754943685104990000000 1.17549e-08 +0.000000117549433298336200000000 1.17549e-07 +0.000001175494389826781000000000 1.17549e-06 +0.000011754943443520460000000000 1.17549e-05 +0.000117549432616215200000000000 0.000117549 +0.001175494398921728000000000000 0.00117549 +0.011754943057894710000000000000 0.0117549 +0.117549434304237400000000000000 0.117549 +SELECT CAST(my_double AS DECIMAL(65,30)), my_double FROM t1; +CAST(my_double AS DECIMAL(65,30)) my_double +0.000000000000000000000000000000 1.175494345e-32 +0.000000000000000000000000000000 1.175494345e-31 +0.000000000000000000000000000001 1.175494345e-30 +0.000000000000000000000000000012 1.175494345e-29 +0.000000000000000000000000000118 1.175494345e-28 +0.000000000000000000000000001175 1.175494345e-27 +0.000000000000000000000000011755 1.175494345e-26 +0.000000000000000000000000117549 1.175494345e-25 +0.000000000000000000000001175494 1.175494345e-24 +0.000000000000000000000011754943 1.175494345e-23 +0.000000000000000000000117549435 1.175494345e-22 +0.000000000000000000001175494345 1.175494345e-21 +0.000000000000000000011754943450 1.175494345e-20 +0.000000000000000000117549434500 1.175494345e-19 +0.000000000000000001175494345000 1.175494345e-18 +0.000000000000000011754943450000 1.175494345e-17 +0.000000000000000117549434500000 1.175494345e-16 +0.000000000000001175494345000000 1.175494345e-15 +0.000000000000011754943450000000 1.175494345e-14 +0.000000000000117549434500000000 1.175494345e-13 +0.000000000001175494345000000000 1.175494345e-12 +0.000000000011754943450000000000 1.175494345e-11 +0.000000000117549434500000000000 1.175494345e-10 +0.000000001175494345000000000000 1.175494345e-09 +0.000000011754943450000000000000 1.175494345e-08 +0.000000117549434500000000000000 1.175494345e-07 +0.000001175494345000000000000000 1.175494345e-06 +0.000011754943450000000000000000 1.175494345e-05 +0.000117549434500000000000000000 0.0001175494345 +0.001175494345000000000000000000 0.001175494345 +0.011754943450000000000000000000 0.01175494345 +0.117549434500000000000000000000 0.1175494345 +SELECT CAST(my_varchar AS DECIMAL(65,30)), my_varchar FROM t1; +CAST(my_varchar AS DECIMAL(65,30)) my_varchar +0.000000000000000000000000000000 1.175494345e-32 +0.000000000000000000000000000000 1.175494345e-31 +0.000000000000000000000000000001 1.175494345e-30 +0.000000000000000000000000000012 1.175494345e-29 +0.000000000000000000000000000118 1.175494345e-28 +0.000000000000000000000000001175 1.175494345e-27 +0.000000000000000000000000011755 1.175494345e-26 +0.000000000000000000000000117549 1.175494345e-25 +0.000000000000000000000001175494 1.175494345e-24 +0.000000000000000000000011754943 1.175494345e-23 +0.000000000000000000000117549435 1.175494345e-22 +0.000000000000000000001175494345 1.175494345e-21 +0.000000000000000000011754943450 1.175494345e-20 +0.000000000000000000117549434500 1.175494345e-19 +0.000000000000000001175494345000 1.175494345e-18 +0.000000000000000011754943450000 1.175494345e-17 +0.000000000000000117549434500000 1.175494345e-16 +0.000000000000001175494345000000 1.175494345e-15 +0.000000000000011754943450000000 1.175494345e-14 +0.000000000000117549434500000000 1.175494345e-13 +0.000000000001175494345000000000 1.175494345e-12 +0.000000000011754943450000000000 1.175494345e-11 +0.000000000117549434500000000000 1.175494345e-10 +0.000000001175494345000000000000 1.175494345e-9 +0.000000011754943450000000000000 1.175494345e-8 +0.000000117549434500000000000000 1.175494345e-7 +0.000001175494345000000000000000 1.175494345e-6 +0.000011754943450000000000000000 1.175494345e-5 +0.000117549434500000000000000000 1.175494345e-4 +0.001175494345000000000000000000 1.175494345e-3 +0.011754943450000000000000000000 1.175494345e-2 +0.117549434500000000000000000000 1.175494345e-1 +UPDATE t1 SET my_decimal = my_float; +SELECT my_decimal, my_float FROM t1; +my_decimal my_float +0.000000000000000000000000000000 1.17549e-32 +0.000000000000000000000000000000 1.17549e-31 +0.000000000000000000000000000001 1.17549e-30 +0.000000000000000000000000000012 1.17549e-29 +0.000000000000000000000000000118 1.17549e-28 +0.000000000000000000000000001175 1.17549e-27 +0.000000000000000000000000011755 1.17549e-26 +0.000000000000000000000000117549 1.17549e-25 +0.000000000000000000000001175494 1.17549e-24 +0.000000000000000000000011754943 1.17549e-23 +0.000000000000000000000117549438 1.17549e-22 +0.000000000000000000001175494332 1.17549e-21 +0.000000000000000000011754943324 1.17549e-20 +0.000000000000000000117549434853 1.17549e-19 +0.000000000000000001175494374380 1.17549e-18 +0.000000000000000011754943743802 1.17549e-17 +0.000000000000000117549432474939 1.17549e-16 +0.000000000000001175494324749389 1.17549e-15 +0.000000000000011754943671010360 1.17549e-14 +0.000000000000117549429933840000 1.17549e-13 +0.000000000001175494380653563000 1.17549e-12 +0.000000000011754943372854760000 1.17549e-11 +0.000000000117549428524377200000 1.17549e-10 +0.000000001175494368510499000000 1.17549e-09 +0.000000011754943685104990000000 1.17549e-08 +0.000000117549433298336200000000 1.17549e-07 +0.000001175494389826781000000000 1.17549e-06 +0.000011754943443520460000000000 1.17549e-05 +0.000117549432616215200000000000 0.000117549 +0.001175494398921728000000000000 0.00117549 +0.011754943057894710000000000000 0.0117549 +0.117549434304237400000000000000 0.117549 +UPDATE t1 SET my_decimal = my_double; +SELECT my_decimal, my_double FROM t1 order by my_decimal; +my_decimal my_double +0.000000000000000000000000000000 1.175494345e-32 +0.000000000000000000000000000000 1.175494345e-31 +0.000000000000000000000000000001 1.175494345e-30 +0.000000000000000000000000000012 1.175494345e-29 +0.000000000000000000000000000118 1.175494345e-28 +0.000000000000000000000000001175 1.175494345e-27 +0.000000000000000000000000011755 1.175494345e-26 +0.000000000000000000000000117549 1.175494345e-25 +0.000000000000000000000001175494 1.175494345e-24 +0.000000000000000000000011754943 1.175494345e-23 +0.000000000000000000000117549435 1.175494345e-22 +0.000000000000000000001175494345 1.175494345e-21 +0.000000000000000000011754943450 1.175494345e-20 +0.000000000000000000117549434500 1.175494345e-19 +0.000000000000000001175494345000 1.175494345e-18 +0.000000000000000011754943450000 1.175494345e-17 +0.000000000000000117549434500000 1.175494345e-16 +0.000000000000001175494345000000 1.175494345e-15 +0.000000000000011754943450000000 1.175494345e-14 +0.000000000000117549434500000000 1.175494345e-13 +0.000000000001175494345000000000 1.175494345e-12 +0.000000000011754943450000000000 1.175494345e-11 +0.000000000117549434500000000000 1.175494345e-10 +0.000000001175494345000000000000 1.175494345e-09 +0.000000011754943450000000000000 1.175494345e-08 +0.000000117549434500000000000000 1.175494345e-07 +0.000001175494345000000000000000 1.175494345e-06 +0.000011754943450000000000000000 1.175494345e-05 +0.000117549434500000000000000000 0.0001175494345 +0.001175494345000000000000000000 0.001175494345 +0.011754943450000000000000000000 0.01175494345 +0.117549434500000000000000000000 0.1175494345 +UPDATE t1 SET my_decimal = my_varchar; +SELECT my_decimal, my_varchar FROM t1 order by my_decimal, my_varchar; +my_decimal my_varchar +0.000000000000000000000000000000 1.175494345e-31 +0.000000000000000000000000000000 1.175494345e-32 +0.000000000000000000000000000001 1.175494345e-30 +0.000000000000000000000000000012 1.175494345e-29 +0.000000000000000000000000000118 1.175494345e-28 +0.000000000000000000000000001175 1.175494345e-27 +0.000000000000000000000000011755 1.175494345e-26 +0.000000000000000000000000117549 1.175494345e-25 +0.000000000000000000000001175494 1.175494345e-24 +0.000000000000000000000011754943 1.175494345e-23 +0.000000000000000000000117549435 1.175494345e-22 +0.000000000000000000001175494345 1.175494345e-21 +0.000000000000000000011754943450 1.175494345e-20 +0.000000000000000000117549434500 1.175494345e-19 +0.000000000000000001175494345000 1.175494345e-18 +0.000000000000000011754943450000 1.175494345e-17 +0.000000000000000117549434500000 1.175494345e-16 +0.000000000000001175494345000000 1.175494345e-15 +0.000000000000011754943450000000 1.175494345e-14 +0.000000000000117549434500000000 1.175494345e-13 +0.000000000001175494345000000000 1.175494345e-12 +0.000000000011754943450000000000 1.175494345e-11 +0.000000000117549434500000000000 1.175494345e-10 +0.000000001175494345000000000000 1.175494345e-9 +0.000000011754943450000000000000 1.175494345e-8 +0.000000117549434500000000000000 1.175494345e-7 +0.000001175494345000000000000000 1.175494345e-6 +0.000011754943450000000000000000 1.175494345e-5 +0.000117549434500000000000000000 1.175494345e-4 +0.001175494345000000000000000000 1.175494345e-3 +0.011754943450000000000000000000 1.175494345e-2 +0.117549434500000000000000000000 1.175494345e-1 +DROP TABLE t1; +create table t1 (c1 decimal(64)); +insert into t1 values( +89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000); +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'c1' at row 1 +insert into t1 values( +99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * +99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999); +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'c1' at row 1 +insert into t1 values(1e100); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +select * from t1; +c1 +9999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999 +drop table t1; +create table t1(a decimal(7,2)); +insert into t1 values(123.12); +select * from t1; +a +123.12 +alter table t1 modify a decimal(10,2); +select * from t1; +a +123.12 +drop table t1; +create table t1 (i int, j int); +insert into t1 values (1,1), (1,2), (2,3), (2,4); +select i, count(distinct j) from t1 group by i; +i count(distinct j) +1 2 +2 2 +select i+0.0 as i2, count(distinct j) from t1 group by i2; +i2 count(distinct j) +1.0 2 +2.0 2 +drop table t1; +create table t1(f1 decimal(20,6)); +insert into t1 values (CAST('10:11:12' AS date) + interval 14 microsecond); +insert into t1 values (CAST('10:11:12' AS time)); +select * from t1; +f1 +20101112000000.000014 +101112.000000 +drop table t1; +select cast(143.481 as decimal(4,1)); +cast(143.481 as decimal(4,1)) +143.5 +select cast(143.481 as decimal(4,0)); +cast(143.481 as decimal(4,0)) +143 +select cast(143.481 as decimal(2,1)); +cast(143.481 as decimal(2,1)) +9.9 +Warnings: +Error 1264 Out of range value for column 'cast(143.481 as decimal(2,1))' at row 1 +select cast(-3.4 as decimal(2,1)); +cast(-3.4 as decimal(2,1)) +-3.4 +select cast(99.6 as decimal(2,0)); +cast(99.6 as decimal(2,0)) +99 +Warnings: +Error 1264 Out of range value for column 'cast(99.6 as decimal(2,0))' at row 1 +select cast(-13.4 as decimal(2,1)); +cast(-13.4 as decimal(2,1)) +-9.9 +Warnings: +Error 1264 Out of range value for column 'cast(-13.4 as decimal(2,1))' at row 1 +select cast(98.6 as decimal(2,0)); +cast(98.6 as decimal(2,0)) +99 +select cast(19999999999999999999 as unsigned); +cast(19999999999999999999 as unsigned) +18446744073709551615 +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' diff --git a/mysql-test/suite/pbxt/r/type_ranges.result b/mysql-test/suite/pbxt/r/type_ranges.result new file mode 100644 index 00000000000..34cabd64bcf --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_ranges.result @@ -0,0 +1,343 @@ +drop table if exists t1,t2,t3; +SET SQL_WARNINGS=1; +CREATE TABLE t1 ( +auto int(5) unsigned NOT NULL auto_increment, +string char(10) default "hello", +tiny tinyint(4) DEFAULT '0' NOT NULL , +short smallint(6) DEFAULT '1' NOT NULL , +medium mediumint(8) DEFAULT '0' NOT NULL, +long_int int(11) DEFAULT '0' NOT NULL, +longlong bigint(13) DEFAULT '0' NOT NULL, +real_float float(13,1) DEFAULT 0.0 NOT NULL, +real_double double(16,4), +utiny tinyint(3) unsigned DEFAULT '0' NOT NULL, +ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL, +umedium mediumint(8) unsigned DEFAULT '0' NOT NULL, +ulong int(11) unsigned DEFAULT '0' NOT NULL, +ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL, +time_stamp timestamp, +date_field date, +time_field time, +date_time datetime, +blob_col blob, +tinyblob_col tinyblob, +mediumblob_col mediumblob not null default '', +longblob_col longblob not null default '', +options enum('one','two','tree') not null , +flags set('one','two','tree') not null default '', +PRIMARY KEY (auto), +KEY (utiny), +KEY (tiny), +KEY (short), +KEY any_name (medium), +KEY (longlong), +KEY (real_float), +KEY (ushort), +KEY (umedium), +KEY (ulong), +KEY (ulonglong,ulong), +KEY (options,flags) +); +Warnings: +Warning 1101 BLOB/TEXT column 'mediumblob_col' can't have a default value +Warning 1101 BLOB/TEXT column 'longblob_col' can't have a default value +show full fields from t1; +Field Type Collation Null Key Default Extra Privileges Comment +auto int(5) unsigned NULL NO PRI NULL auto_increment # +string char(10) latin1_swedish_ci YES hello # +tiny tinyint(4) NULL NO MUL 0 # +short smallint(6) NULL NO MUL 1 # +medium mediumint(8) NULL NO MUL 0 # +long_int int(11) NULL NO 0 # +longlong bigint(13) NULL NO MUL 0 # +real_float float(13,1) NULL NO MUL 0.0 # +real_double double(16,4) NULL YES NULL # +utiny tinyint(3) unsigned NULL NO MUL 0 # +ushort smallint(5) unsigned zerofill NULL NO MUL 00000 # +umedium mediumint(8) unsigned NULL NO MUL 0 # +ulong int(11) unsigned NULL NO MUL 0 # +ulonglong bigint(13) unsigned NULL NO MUL 0 # +time_stamp timestamp NULL NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP # +date_field date NULL YES NULL # +time_field time NULL YES NULL # +date_time datetime NULL YES NULL # +blob_col blob NULL YES NULL # +tinyblob_col tinyblob NULL YES NULL # +mediumblob_col mediumblob NULL NO NULL # +longblob_col longblob NULL NO NULL # +options enum('one','two','tree') latin1_swedish_ci NO MUL NULL # +flags set('one','two','tree') latin1_swedish_ci NO # +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 PRIMARY 1 auto A 0 NULL NULL BTREE +t1 1 utiny 1 utiny A NULL NULL NULL BTREE +t1 1 tiny 1 tiny A NULL NULL NULL BTREE +t1 1 short 1 short A NULL NULL NULL BTREE +t1 1 any_name 1 medium A NULL NULL NULL BTREE +t1 1 longlong 1 longlong A NULL NULL NULL BTREE +t1 1 real_float 1 real_float A NULL NULL NULL BTREE +t1 1 ushort 1 ushort A NULL NULL NULL BTREE +t1 1 umedium 1 umedium A NULL NULL NULL BTREE +t1 1 ulong 1 ulong A NULL NULL NULL BTREE +t1 1 ulonglong 1 ulonglong A NULL NULL NULL BTREE +t1 1 ulonglong 2 ulong A NULL NULL NULL BTREE +t1 1 options 1 options A NULL NULL NULL BTREE +t1 1 options 2 flags A NULL NULL NULL BTREE +CREATE UNIQUE INDEX test on t1 ( auto ) ; +CREATE INDEX test2 on t1 ( ulonglong,ulong) ; +CREATE INDEX test3 on t1 ( medium ) ; +DROP INDEX test ON t1; +insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one'); +insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one'); +insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); +Warnings: +Warning 1265 Data truncated for column 'string' at row 1 +insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); +Warnings: +Warning 1264 Out of range value for column 'utiny' at row 1 +Warning 1264 Out of range value for column 'ushort' at row 1 +Warning 1264 Out of range value for column 'umedium' at row 1 +Warning 1264 Out of range value for column 'ulong' at row 1 +Warning 1264 Out of range value for column 'ulonglong' at row 1 +Warning 1265 Data truncated for column 'options' at row 1 +Warning 1265 Data truncated for column 'flags' at row 1 +insert into t1 values (0,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,NULL,0,0,0,-4294967295,-4294967295,-4294967295,'-4294967295',0,"one,two,tree"); +Warnings: +Warning 1265 Data truncated for column 'string' at row 1 +Warning 1264 Out of range value for column 'tiny' at row 1 +Warning 1264 Out of range value for column 'short' at row 1 +Warning 1264 Out of range value for column 'medium' at row 1 +Warning 1264 Out of range value for column 'long_int' at row 1 +Warning 1264 Out of range value for column 'utiny' at row 1 +Warning 1264 Out of range value for column 'ushort' at row 1 +Warning 1264 Out of range value for column 'umedium' at row 1 +Warning 1264 Out of range value for column 'ulong' at row 1 +Warning 1264 Out of range value for column 'ulonglong' at row 1 +Warning 1265 Data truncated for column 'options' at row 1 +insert into t1 values (0,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,NULL,0,0,0,4294967295,4294967295,4294967295,'4294967295',0,0); +Warnings: +Warning 1264 Out of range value for column 'tiny' at row 1 +Warning 1264 Out of range value for column 'short' at row 1 +Warning 1264 Out of range value for column 'medium' at row 1 +Warning 1264 Out of range value for column 'long_int' at row 1 +Warning 1264 Out of range value for column 'utiny' at row 1 +Warning 1264 Out of range value for column 'ushort' at row 1 +Warning 1264 Out of range value for column 'umedium' at row 1 +Warning 1265 Data truncated for column 'options' at row 1 +insert into t1 (tiny) values (1); +select auto,string,tiny,short,medium,long_int,longlong,real_float,real_double,utiny,ushort,umedium,ulong,ulonglong,mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000),date_field,time_field,date_time,blob_col,tinyblob_col,mediumblob_col,longblob_col from t1; +auto string tiny short medium long_int longlong real_float real_double utiny ushort umedium ulong ulonglong mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000) date_field time_field date_time blob_col tinyblob_col mediumblob_col longblob_col +10 1 1 1 1 1 1 1.0 1.0000 1 00001 1 1 1 0 0000-00-00 00:00:00 0000-00-00 00:00:00 1 1 1 1 +11 2 2 2 2 2 2 2.0 2.0000 2 00002 2 2 2 0 NULL NULL NULL NULL NULL 2 2 +12 0.33333333 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3 +13 -1 -1 -1 -1 -1 -1 -1.0 -1.0000 0 00000 0 0 0 0 1997-08-07 08:07:06 1997-04-03 09:08:07 -1 -1 -1 -1 +14 -429496729 -128 -32768 -8388608 -2147483648 -4294967295 -4294967296.0 -4294967295.0000 0 00000 0 0 0 0 0000-00-00 00:00:00 0000-00-00 00:00:00 -4294967295 -4294967295 -4294967295 -4294967295 +15 4294967295 127 32767 8388607 2147483647 4294967295 4294967296.0 4294967295.0000 255 65535 16777215 4294967295 4294967295 0 0000-00-00 00:00:00 0000-00-00 00:00:00 4294967295 4294967295 4294967295 4294967295 +16 hello 1 1 0 0 0 0.0 NULL 0 00000 0 0 0 0 NULL NULL NULL NULL NULL +ALTER TABLE t1 +add new_field char(10) default "new" not null, +change blob_col new_blob_col varchar(20), +change date_field date_field char(10), +alter column string set default "newdefault", +alter short drop default, +DROP INDEX utiny, +DROP INDEX ushort, +DROP PRIMARY KEY, +DROP FOREIGN KEY any_name, +ADD INDEX (auto); +LOCK TABLES t1 WRITE; +ALTER TABLE t1 +RENAME as t2, +DROP longblob_col; +UNLOCK TABLES; +ALTER TABLE t2 rename as t3; +LOCK TABLES t3 WRITE ; +ALTER TABLE t3 rename as t1; +UNLOCK TABLES; +select auto,new_field,new_blob_col,date_field from t1 ; +auto new_field new_blob_col date_field +10 new 1 0000-00-00 +11 new NULL NULL +12 new 1997-03-03 +13 new -1 1997-08-07 +14 new -4294967295 0000-00-00 +15 new 4294967295 0000-00-00 +16 new NULL NULL +CREATE TABLE t2 ( +auto int(5) unsigned NOT NULL auto_increment, +string char(20), +mediumblob_col mediumblob not null, +new_field char(2), +PRIMARY KEY (auto) +); +INSERT INTO t2 (string,mediumblob_col,new_field) SELECT string,mediumblob_col,new_field from t1 where auto > 10; +Warnings: +Warning 1265 Data truncated for column 'new_field' at row 1 +Warning 1265 Data truncated for column 'new_field' at row 2 +Warning 1265 Data truncated for column 'new_field' at row 3 +Warning 1265 Data truncated for column 'new_field' at row 4 +Warning 1265 Data truncated for column 'new_field' at row 5 +Warning 1265 Data truncated for column 'new_field' at row 6 +select * from t2; +auto string mediumblob_col new_field +1 2 2 ne +2 0.33333333 ne +3 -1 -1 ne +4 -429496729 -4294967295 ne +5 4294967295 4294967295 ne +6 hello ne +select distinct flags from t1; +flags + +one,two,tree +one +one,two +select flags from t1 where find_in_set("two",flags)>0; +flags +one,two,tree +one,two,tree +one,two +one,two +select flags from t1 where find_in_set("unknown",flags)>0; +flags +select options,flags from t1 where options="ONE" and flags="ONE"; +options flags +one one +select options,flags from t1 where options="one" and flags="one"; +options flags +one one +drop table t2; +create table t2 select * from t1; +update t2 set string="changed" where auto=16; +show full columns from t1; +Field Type Collation Null Key Default Extra Privileges Comment +auto int(5) unsigned NULL NO MUL NULL auto_increment # +string char(10) latin1_swedish_ci YES newdefault # +tiny tinyint(4) NULL NO MUL 0 # +short smallint(6) NULL NO MUL NULL # +medium mediumint(8) NULL NO MUL 0 # +long_int int(11) NULL NO 0 # +longlong bigint(13) NULL NO MUL 0 # +real_float float(13,1) NULL NO MUL 0.0 # +real_double double(16,4) NULL YES NULL # +utiny tinyint(3) unsigned NULL NO 0 # +ushort smallint(5) unsigned zerofill NULL NO 00000 # +umedium mediumint(8) unsigned NULL NO MUL 0 # +ulong int(11) unsigned NULL NO MUL 0 # +ulonglong bigint(13) unsigned NULL NO MUL 0 # +time_stamp timestamp NULL NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP # +date_field char(10) latin1_swedish_ci YES NULL # +time_field time NULL YES NULL # +date_time datetime NULL YES NULL # +new_blob_col varchar(20) latin1_swedish_ci YES NULL # +tinyblob_col tinyblob NULL YES NULL # +mediumblob_col mediumblob NULL NO NULL # +options enum('one','two','tree') latin1_swedish_ci NO MUL NULL # +flags set('one','two','tree') latin1_swedish_ci NO # +new_field char(10) latin1_swedish_ci NO new # +show full columns from t2; +Field Type Collation Null Key Default Extra Privileges Comment +auto int(5) unsigned NULL NO 0 # +string char(10) latin1_swedish_ci YES newdefault # +tiny tinyint(4) NULL NO 0 # +short smallint(6) NULL NO NULL # +medium mediumint(8) NULL NO 0 # +long_int int(11) NULL NO 0 # +longlong bigint(13) NULL NO 0 # +real_float float(13,1) NULL NO 0.0 # +real_double double(16,4) NULL YES NULL # +utiny tinyint(3) unsigned NULL NO 0 # +ushort smallint(5) unsigned zerofill NULL NO 00000 # +umedium mediumint(8) unsigned NULL NO 0 # +ulong int(11) unsigned NULL NO 0 # +ulonglong bigint(13) unsigned NULL NO 0 # +time_stamp timestamp NULL NO 0000-00-00 00:00:00 # +date_field char(10) latin1_swedish_ci YES NULL # +time_field time NULL YES NULL # +date_time datetime NULL YES NULL # +new_blob_col varchar(20) latin1_swedish_ci YES NULL # +tinyblob_col tinyblob NULL YES NULL # +mediumblob_col mediumblob NULL NO NULL # +options enum('one','two','tree') latin1_swedish_ci NO NULL # +flags set('one','two','tree') latin1_swedish_ci NO # +new_field char(10) latin1_swedish_ci NO new # +select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and ((t1.string<>t2.string and (t1.string is not null or t2.string is not null)) or (t1.tiny<>t2.tiny and (t1.tiny is not null or t2.tiny is not null)) or (t1.short<>t2.short and (t1.short is not null or t2.short is not null)) or (t1.medium<>t2.medium and (t1.medium is not null or t2.medium is not null)) or (t1.long_int<>t2.long_int and (t1.long_int is not null or t2.long_int is not null)) or (t1.longlong<>t2.longlong and (t1.longlong is not null or t2.longlong is not null)) or (t1.real_float<>t2.real_float and (t1.real_float is not null or t2.real_float is not null)) or (t1.real_double<>t2.real_double and (t1.real_double is not null or t2.real_double is not null)) or (t1.utiny<>t2.utiny and (t1.utiny is not null or t2.utiny is not null)) or (t1.ushort<>t2.ushort and (t1.ushort is not null or t2.ushort is not null)) or (t1.umedium<>t2.umedium and (t1.umedium is not null or t2.umedium is not null)) or (t1.ulong<>t2.ulong and (t1.ulong is not null or t2.ulong is not null)) or (t1.ulonglong<>t2.ulonglong and (t1.ulonglong is not null or t2.ulonglong is not null)) or (t1.time_stamp<>t2.time_stamp and (t1.time_stamp is not null or t2.time_stamp is not null)) or (t1.date_field<>t2.date_field and (t1.date_field is not null or t2.date_field is not null)) or (t1.time_field<>t2.time_field and (t1.time_field is not null or t2.time_field is not null)) or (t1.date_time<>t2.date_time and (t1.date_time is not null or t2.date_time is not null)) or (t1.new_blob_col<>t2.new_blob_col and (t1.new_blob_col is not null or t2.new_blob_col is not null)) or (t1.tinyblob_col<>t2.tinyblob_col and (t1.tinyblob_col is not null or t2.tinyblob_col is not null)) or (t1.mediumblob_col<>t2.mediumblob_col and (t1.mediumblob_col is not null or t2.mediumblob_col is not null)) or (t1.options<>t2.options and (t1.options is not null or t2.options is not null)) or (t1.flags<>t2.flags and (t1.flags is not null or t2.flags is not null)) or (t1.new_field<>t2.new_field and (t1.new_field is not null or t2.new_field is not null))); +auto auto +16 16 +select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and not (t1.string<=>t2.string and t1.tiny<=>t2.tiny and t1.short<=>t2.short and t1.medium<=>t2.medium and t1.long_int<=>t2.long_int and t1.longlong<=>t2.longlong and t1.real_float<=>t2.real_float and t1.real_double<=>t2.real_double and t1.utiny<=>t2.utiny and t1.ushort<=>t2.ushort and t1.umedium<=>t2.umedium and t1.ulong<=>t2.ulong and t1.ulonglong<=>t2.ulonglong and t1.time_stamp<=>t2.time_stamp and t1.date_field<=>t2.date_field and t1.time_field<=>t2.time_field and t1.date_time<=>t2.date_time and t1.new_blob_col<=>t2.new_blob_col and t1.tinyblob_col<=>t2.tinyblob_col and t1.mediumblob_col<=>t2.mediumblob_col and t1.options<=>t2.options and t1.flags<=>t2.flags and t1.new_field<=>t2.new_field); +auto auto +16 16 +drop table t2; +create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1; +show full columns from t2; +Field Type Collation Null Key Default Extra Privileges Comment +auto bigint(12) unsigned NULL NO PRI 0 # +t1 int(1) NULL NO 0 # +t2 varchar(1) latin1_swedish_ci NO # +t3 varchar(256) latin1_swedish_ci NO # +t4 varbinary(256) NULL NO # +t5 longtext latin1_swedish_ci NO NULL # +t6 longblob NULL NO NULL # +t7 char(0) latin1_swedish_ci NO # +t8 binary(0) NULL NO # +select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2; +t1 t2 length(t3) length(t4) length(t5) length(t6) t7 t8 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +1 a 256 256 4096 4096 +drop table t1,t2; +create table t1 (c int); +insert into t1 values(1),(2); +create table t2 select * from t1; +create table t3 select * from t1, t2; +ERROR 42S21: Duplicate column name 'c' +create table t3 select t1.c AS c1, t2.c AS c2,1 as "const" from t1, t2; +show full columns from t3; +Field Type Collation Null Key Default Extra Privileges Comment +c1 int(11) NULL YES NULL # +c2 int(11) NULL YES NULL # +const int(1) NULL NO 0 # +drop table t1,t2,t3; +create table t1 ( myfield INT NOT NULL, UNIQUE INDEX (myfield), unique (myfield), index(myfield)); +drop table t1; +create table t1 ( id integer unsigned not null primary key ); +create table t2 ( id integer unsigned not null primary key ); +insert into t1 values (1), (2); +insert into t2 values (1); +select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +id_A id_B +1 1 +2 NULL +select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); +id_A id_B +1 1 +2 NULL +create table t3 (id_A integer unsigned not null, id_B integer unsigned null ); +insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select * from t3; +id_A id_B +1 1 +2 NULL +truncate table t3; +insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); +select * from t3; +id_A id_B +1 1 +2 NULL +drop table t3; +create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select * from t3; +id_A id_B +1 1 +2 NULL +drop table t3; +create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); +select * from t3; +id_A id_B +1 1 +2 NULL +drop table t1,t2,t3; diff --git a/mysql-test/suite/pbxt/r/type_set.result b/mysql-test/suite/pbxt/r/type_set.result new file mode 100644 index 00000000000..d9b5327d20f --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_set.result @@ -0,0 +1,68 @@ +drop table if exists t1; +create table t1 (a set (' ','a','b') not null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` set('','a','b') NOT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a set (' ','a','b ') not null default 'b '); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` set('','a','b') NOT NULL DEFAULT 'b' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +CREATE TABLE t1 ( user varchar(64) NOT NULL default '', path varchar(255) NOT NULL default '', privilege set('select','RESERVED30','RESERVED29','RESERVED28','RESERVED27','RESERVED26', 'RESERVED25','RESERVED24','data.delete','RESERVED22','RESERVED21', 'RESERVED20','data.insert.none','data.insert.approve', 'data.insert.delete','data.insert.move','data.insert.propose', 'data.insert.reject','RESERVED13','RESERVED12','RESERVED11','RESERVED10', 'RESERVED09','data.update','RESERVED07','RESERVED06','RESERVED05', 'RESERVED04','metadata.delete','metadata.put','RESERVED01','RESERVED00') NOT NULL default '', KEY user (user) ) ENGINE=MyISAM CHARSET=utf8; +DROP TABLE t1; +set names latin1; +create table t1 (s set ('a','A') character set latin1 collate latin1_bin); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s` set('a','A') CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert into t1 values ('a'),('a,A'),('A,a'),('A'); +select s from t1 order by s; +s +a +A +a,A +a,A +select s from t1 order by concat(s); +s +A +a +a,A +a,A +drop table t1; +CREATE TABLE t1 (c set('ae','oe','ue','ss') collate latin1_german2_ci); +INSERT INTO t1 VALUES ('ä'),('ö'),('ü'),('ß'); +INSERT INTO t1 VALUES ('ae'),('oe'),('ue'),('ss'); +INSERT INTO t1 VALUES ('ä,ö,ü,ß'); +INSERT INTO t1 VALUES ('ae,oe,ue,ss'); +SELECT c FROM t1 ORDER BY c; +c +ae +ae +oe +oe +ue +ue +ss +ss +ae,oe,ue,ss +ae,oe,ue,ss +SELECT c FROM t1 ORDER BY concat(c); +c +ae +ae +ae,oe,ue,ss +ae,oe,ue,ss +oe +oe +ss +ss +ue +ue +DROP TABLE t1; diff --git a/mysql-test/suite/pbxt/r/type_time.result b/mysql-test/suite/pbxt/r/type_time.result new file mode 100644 index 00000000000..ce820c0cb8e --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_time.result @@ -0,0 +1,87 @@ +drop table if exists t1; +create table t1 (t time); +insert into t1 values("10:22:33"),("12:34:56.78"),(10),(1234),(123456.78),(1234559.99),("1"),("1:23"),("1:23:45"), ("10.22"), ("-10 1:22:33.45"),("20 10:22:33"),("1999-02-03 20:33:34"); +insert t1 values (30),(1230),("1230"),("12:30"),("12:30:35"),("1 12:30:31.32"); +select * from t1; +t +10:22:33 +12:34:56 +00:00:10 +00:12:34 +12:34:56 +123:45:59 +00:00:01 +01:23:00 +01:23:45 +00:00:10 +-241:22:33 +490:22:33 +20:33:34 +00:00:30 +00:12:30 +00:12:30 +12:30:00 +12:30:35 +36:30:31 +insert into t1 values("10.22.22"),(1234567),(123456789),(123456789.10),("10 22:22"),("12.45a"); +Warnings: +Warning 1265 Data truncated for column 't' at row 1 +Warning 1264 Out of range value for column 't' at row 2 +Warning 1264 Out of range value for column 't' at row 3 +Warning 1264 Out of range value for column 't' at row 4 +Warning 1265 Data truncated for column 't' at row 6 +select * from t1; +t +10:22:33 +12:34:56 +00:00:10 +00:12:34 +12:34:56 +123:45:59 +00:00:01 +01:23:00 +01:23:45 +00:00:10 +-241:22:33 +490:22:33 +20:33:34 +00:00:30 +00:12:30 +00:12:30 +12:30:00 +12:30:35 +36:30:31 +00:00:10 +00:00:00 +838:59:59 +838:59:59 +262:22:00 +00:00:12 +drop table t1; +create table t1 (t time); +insert into t1 values ('09:00:00'),('13:00:00'),('19:38:34'), ('13:00:00'),('09:00:00'),('09:00:00'),('13:00:00'),('13:00:00'),('13:00:00'),('09:00:00'); +select t, time_to_sec(t),sec_to_time(time_to_sec(t)) from t1; +t time_to_sec(t) sec_to_time(time_to_sec(t)) +09:00:00 32400 09:00:00 +13:00:00 46800 13:00:00 +19:38:34 70714 19:38:34 +13:00:00 46800 13:00:00 +09:00:00 32400 09:00:00 +09:00:00 32400 09:00:00 +13:00:00 46800 13:00:00 +13:00:00 46800 13:00:00 +13:00:00 46800 13:00:00 +09:00:00 32400 09:00:00 +select sec_to_time(time_to_sec(t)) from t1; +sec_to_time(time_to_sec(t)) +09:00:00 +13:00:00 +19:38:34 +13:00:00 +09:00:00 +09:00:00 +13:00:00 +13:00:00 +13:00:00 +09:00:00 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/type_timestamp.result b/mysql-test/suite/pbxt/r/type_timestamp.result new file mode 100644 index 00000000000..2e5a6f46276 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_timestamp.result @@ -0,0 +1,510 @@ +drop table if exists t1,t2; +set time_zone="+03:00"; +CREATE TABLE t1 (a int, t timestamp); +CREATE TABLE t2 (a int, t datetime); +SET TIMESTAMP=1234; +insert into t1 values(1,NULL); +insert into t1 values(2,"2002-03-03"); +SET TIMESTAMP=1235; +insert into t1 values(3,NULL); +SET TIMESTAMP=1236; +insert into t1 (a) values(4); +insert into t2 values(5,"2002-03-04"),(6,NULL),(7,"2002-03-05"),(8,"00-00-00"); +SET TIMESTAMP=1237; +insert into t1 select * from t2; +SET TIMESTAMP=1238; +insert into t1 (a) select a+1 from t2 where a=8; +select * from t1; +a t +1 1970-01-01 03:20:34 +2 2002-03-03 00:00:00 +3 1970-01-01 03:20:35 +4 1970-01-01 03:20:36 +5 2002-03-04 00:00:00 +6 1970-01-01 03:20:37 +7 2002-03-05 00:00:00 +8 0000-00-00 00:00:00 +9 1970-01-01 03:20:38 +drop table t1,t2; +SET TIMESTAMP=1234; +CREATE TABLE t1 (value TEXT NOT NULL, id VARCHAR(32) NOT NULL, stamp timestamp, PRIMARY KEY (id)); +INSERT INTO t1 VALUES ("my value", "myKey","1999-04-02 00:00:00"); +SELECT stamp FROM t1 WHERE id="myKey"; +stamp +1999-04-02 00:00:00 +UPDATE t1 SET value="my value" WHERE id="myKey"; +SELECT stamp FROM t1 WHERE id="myKey"; +stamp +1999-04-02 00:00:00 +UPDATE t1 SET id="myKey" WHERE value="my value"; +SELECT stamp FROM t1 WHERE id="myKey"; +stamp +1999-04-02 00:00:00 +drop table t1; +create table t1 (a timestamp); +insert into t1 values (now()); +select date_format(a,"%Y %y"),year(a),year(now()) from t1; +date_format(a,"%Y %y") year(a) year(now()) +1970 70 1970 1970 +drop table t1; +create table t1 (ix timestamp); +insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000); +select ix+0 from t1; +ix+0 +19991101000000 +19990102030405 +19990630232922 +19990601000000 +19990930232922 +19990531232922 +19990501000000 +19991101000000 +19990501000000 +truncate table t1; +insert into t1 values ("19991101000000"),("19990102030405"),("19990630232922"),("19990601000000"); +select ix+0 from t1; +ix+0 +19991101000000 +19990102030405 +19990630232922 +19990601000000 +drop table t1; +CREATE TABLE t1 (date date, date_time datetime, time_stamp timestamp); +INSERT INTO t1 VALUES ("1998-12-31","1998-12-31 23:59:59",19981231235959); +INSERT INTO t1 VALUES ("1999-01-01","1999-01-01 00:00:00",19990101000000); +INSERT INTO t1 VALUES ("1999-09-09","1999-09-09 23:59:59",19990909235959); +INSERT INTO t1 VALUES ("2000-01-01","2000-01-01 00:00:00",20000101000000); +INSERT INTO t1 VALUES ("2000-02-28","2000-02-28 00:00:00",20000228000000); +INSERT INTO t1 VALUES ("2000-02-29","2000-02-29 00:00:00",20000229000000); +INSERT INTO t1 VALUES ("2000-03-01","2000-03-01 00:00:00",20000301000000); +INSERT INTO t1 VALUES ("2000-12-31","2000-12-31 23:59:59",20001231235959); +INSERT INTO t1 VALUES ("2001-01-01","2001-01-01 00:00:00",20010101000000); +INSERT INTO t1 VALUES ("2004-12-31","2004-12-31 23:59:59",20041231235959); +INSERT INTO t1 VALUES ("2005-01-01","2005-01-01 00:00:00",20050101000000); +INSERT INTO t1 VALUES ("2030-01-01","2030-01-01 00:00:00",20300101000000); +SELECT * FROM t1; +date date_time time_stamp +1998-12-31 1998-12-31 23:59:59 1998-12-31 23:59:59 +1999-01-01 1999-01-01 00:00:00 1999-01-01 00:00:00 +1999-09-09 1999-09-09 23:59:59 1999-09-09 23:59:59 +2000-01-01 2000-01-01 00:00:00 2000-01-01 00:00:00 +2000-02-28 2000-02-28 00:00:00 2000-02-28 00:00:00 +2000-02-29 2000-02-29 00:00:00 2000-02-29 00:00:00 +2000-03-01 2000-03-01 00:00:00 2000-03-01 00:00:00 +2000-12-31 2000-12-31 23:59:59 2000-12-31 23:59:59 +2001-01-01 2001-01-01 00:00:00 2001-01-01 00:00:00 +2004-12-31 2004-12-31 23:59:59 2004-12-31 23:59:59 +2005-01-01 2005-01-01 00:00:00 2005-01-01 00:00:00 +2030-01-01 2030-01-01 00:00:00 2030-01-01 00:00:00 +drop table t1; +create table t1 (t2 timestamp(2), t4 timestamp(4), t6 timestamp(6), +t8 timestamp(8), t10 timestamp(10), t12 timestamp(12), +t14 timestamp(14)); +Warnings: +Warning 1287 The syntax 'TIMESTAMP(2)' is deprecated and will be removed in MySQL 5.2. Please use 'TIMESTAMP' instead +Warning 1287 The syntax 'TIMESTAMP(4)' is deprecated and will be removed in MySQL 5.2. Please use 'TIMESTAMP' instead +Warning 1287 The syntax 'TIMESTAMP(6)' is deprecated and will be removed in MySQL 5.2. Please use 'TIMESTAMP' instead +Warning 1287 The syntax 'TIMESTAMP(8)' is deprecated and will be removed in MySQL 5.2. Please use 'TIMESTAMP' instead +Warning 1287 The syntax 'TIMESTAMP(10)' is deprecated and will be removed in MySQL 5.2. Please use 'TIMESTAMP' instead +Warning 1287 The syntax 'TIMESTAMP(12)' is deprecated and will be removed in MySQL 5.2. Please use 'TIMESTAMP' instead +Warning 1287 The syntax 'TIMESTAMP(14)' is deprecated and will be removed in MySQL 5.2. Please use 'TIMESTAMP' instead +insert t1 values (0,0,0,0,0,0,0), +("1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", +"1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", +"1997-12-31 23:47:59"); +select * from t1; +t2 t4 t6 t8 t10 t12 t14 +0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 +1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 +select * from t1; +t2 t4 t6 t8 t10 t12 t14 +0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 +1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 +drop table t1; +create table t1 (ix timestamp); +insert into t1 values (0),(20030101010160),(20030101016001),(20030101240101),(20030132010101),(20031301010101),(20031200000000),(20030000000000); +Warnings: +Warning 1265 Data truncated for column 'ix' at row 2 +Warning 1265 Data truncated for column 'ix' at row 3 +Warning 1265 Data truncated for column 'ix' at row 4 +Warning 1265 Data truncated for column 'ix' at row 5 +Warning 1265 Data truncated for column 'ix' at row 6 +Warning 1265 Data truncated for column 'ix' at row 7 +Warning 1265 Data truncated for column 'ix' at row 8 +select ix+0 from t1; +ix+0 +0 +0 +0 +0 +0 +0 +0 +0 +truncate table t1; +insert into t1 values ("00000000000000"),("20030101010160"),("20030101016001"),("20030101240101"),("20030132010101"),("20031301010101"),("20031200000000"),("20030000000000"); +Warnings: +Warning 1265 Data truncated for column 'ix' at row 2 +Warning 1265 Data truncated for column 'ix' at row 3 +Warning 1265 Data truncated for column 'ix' at row 4 +Warning 1265 Data truncated for column 'ix' at row 5 +Warning 1265 Data truncated for column 'ix' at row 6 +Warning 1265 Data truncated for column 'ix' at row 7 +Warning 1265 Data truncated for column 'ix' at row 8 +select ix+0 from t1; +ix+0 +0 +0 +0 +0 +0 +0 +0 +0 +truncate table t1; +insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer"); +Warnings: +Warning 1265 Data truncated for column 'ix' at row 1 +Warning 1265 Data truncated for column 'ix' at row 2 +select ix+0 from t1; +ix+0 +0 +20030101000000 +drop table t1; +create table t1 (t1 timestamp, t2 timestamp default now()); +ERROR HY000: Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause +create table t1 (t1 timestamp, t2 timestamp on update now()); +ERROR HY000: Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause +create table t1 (t1 timestamp, t2 timestamp default now() on update now()); +ERROR HY000: Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause +create table t1 (t1 timestamp default now(), t2 timestamp on update now()); +ERROR HY000: Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause +create table t1 (t1 timestamp on update now(), t2 timestamp default now() on update now()); +ERROR HY000: Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause +create table t1 (t1 timestamp default '2003-01-01 00:00:00', t2 datetime, t3 timestamp); +SET TIMESTAMP=1000000000; +insert into t1 values (); +SET TIMESTAMP=1000000001; +update t1 set t2=now(); +SET TIMESTAMP=1000000002; +insert into t1 (t1,t3) values (default, default); +select * from t1 order by t2; +t1 t2 t3 +2003-01-01 00:00:00 NULL 0000-00-00 00:00:00 +2003-01-01 00:00:00 2001-09-09 04:46:41 0000-00-00 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t1` timestamp NOT NULL DEFAULT '2003-01-01 00:00:00', + `t2` datetime DEFAULT NULL, + `t3` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show columns from t1; +Field Type Null Key Default Extra +t1 timestamp NO 2003-01-01 00:00:00 +t2 datetime YES NULL +t3 timestamp NO 0000-00-00 00:00:00 +drop table t1; +create table t1 (t1 timestamp default now(), t2 datetime, t3 timestamp); +SET TIMESTAMP=1000000002; +insert into t1 values (); +SET TIMESTAMP=1000000003; +update t1 set t2=now(); +SET TIMESTAMP=1000000003; +insert into t1 (t1,t3) values (default, default); +select * from t1 order by t1; +t1 t2 t3 +2001-09-09 04:46:42 2001-09-09 04:46:43 0000-00-00 00:00:00 +2001-09-09 04:46:43 NULL 0000-00-00 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `t2` datetime DEFAULT NULL, + `t3` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show columns from t1; +Field Type Null Key Default Extra +t1 timestamp NO CURRENT_TIMESTAMP +t2 datetime YES NULL +t3 timestamp NO 0000-00-00 00:00:00 +drop table t1; +create table t1 (t1 timestamp default '2003-01-01 00:00:00' on update now(), t2 datetime); +SET TIMESTAMP=1000000004; +insert into t1 values (); +select * from t1; +t1 t2 +2003-01-01 00:00:00 NULL +SET TIMESTAMP=1000000005; +update t1 set t2=now(); +SET TIMESTAMP=1000000005; +insert into t1 (t1) values (default); +select * from t1 order by t1; +t1 t2 +2001-09-09 04:46:45 2001-09-09 04:46:45 +2003-01-01 00:00:00 NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t1` timestamp NOT NULL DEFAULT '2003-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP, + `t2` datetime DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show columns from t1; +Field Type Null Key Default Extra +t1 timestamp NO 2003-01-01 00:00:00 on update CURRENT_TIMESTAMP +t2 datetime YES NULL +drop table t1; +create table t1 (t1 timestamp default now() on update now(), t2 datetime); +SET TIMESTAMP=1000000006; +insert into t1 values (); +select * from t1; +t1 t2 +2001-09-09 04:46:46 NULL +SET TIMESTAMP=1000000007; +update t1 set t2=now(); +SET TIMESTAMP=1000000007; +insert into t1 (t1) values (default); +select * from t1 order by t2; +t1 t2 +2001-09-09 04:46:47 NULL +2001-09-09 04:46:47 2001-09-09 04:46:47 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `t2` datetime DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show columns from t1; +Field Type Null Key Default Extra +t1 timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP +t2 datetime YES NULL +drop table t1; +create table t1 (t1 timestamp, t2 datetime, t3 timestamp); +SET TIMESTAMP=1000000007; +insert into t1 values (); +select * from t1; +t1 t2 t3 +2001-09-09 04:46:47 NULL 0000-00-00 00:00:00 +SET TIMESTAMP=1000000008; +update t1 set t2=now(); +SET TIMESTAMP=1000000008; +insert into t1 (t1,t3) values (default, default); +select * from t1 order by t2; +t1 t2 t3 +2001-09-09 04:46:48 NULL 0000-00-00 00:00:00 +2001-09-09 04:46:48 2001-09-09 04:46:48 0000-00-00 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `t2` datetime DEFAULT NULL, + `t3` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show columns from t1; +Field Type Null Key Default Extra +t1 timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP +t2 datetime YES NULL +t3 timestamp NO 0000-00-00 00:00:00 +drop table t1; +create table t1 (t1 timestamp default current_timestamp on update current_timestamp, t2 datetime); +SET TIMESTAMP=1000000009; +insert into t1 values (); +select * from t1; +t1 t2 +2001-09-09 04:46:49 NULL +SET TIMESTAMP=1000000010; +update t1 set t2=now(); +SET TIMESTAMP=1000000011; +insert into t1 (t1) values (default); +select * from t1 order by t1; +t1 t2 +2001-09-09 04:46:50 2001-09-09 04:46:50 +2001-09-09 04:46:51 NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `t2` datetime DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +show columns from t1; +Field Type Null Key Default Extra +t1 timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP +t2 datetime YES NULL +truncate table t1; +insert into t1 values ('2004-04-01 00:00:00', '2004-04-01 00:00:00'); +SET TIMESTAMP=1000000012; +update t1 set t1= '2004-04-02 00:00:00'; +select * from t1; +t1 t2 +2004-04-02 00:00:00 2004-04-01 00:00:00 +update t1 as ta, t1 as tb set tb.t1= '2004-04-03 00:00:00'; +select * from t1; +t1 t2 +2004-04-03 00:00:00 2004-04-01 00:00:00 +drop table t1; +create table t1 (pk int primary key, t1 timestamp default current_timestamp on update current_timestamp, bulk int); +insert into t1 values (1, '2004-04-01 00:00:00', 10); +SET TIMESTAMP=1000000013; +replace into t1 set pk = 1, bulk= 20; +select * from t1; +pk t1 bulk +1 2001-09-09 04:46:53 20 +drop table t1; +create table t1 (pk int primary key, t1 timestamp default '2003-01-01 00:00:00' on update current_timestamp, bulk int); +insert into t1 values (1, '2004-04-01 00:00:00', 10); +SET TIMESTAMP=1000000014; +replace into t1 set pk = 1, bulk= 20; +select * from t1; +pk t1 bulk +1 2003-01-01 00:00:00 20 +drop table t1; +create table t1 (pk int primary key, t1 timestamp default current_timestamp, bulk int); +insert into t1 values (1, '2004-04-01 00:00:00', 10); +SET TIMESTAMP=1000000015; +replace into t1 set pk = 1, bulk= 20; +select * from t1; +pk t1 bulk +1 2001-09-09 04:46:55 20 +drop table t1; +create table t1 (t1 timestamp default current_timestamp on update current_timestamp); +insert into t1 values ('2004-04-01 00:00:00'); +SET TIMESTAMP=1000000016; +alter table t1 add i int default 10; +select * from t1; +t1 i +2004-04-01 00:00:00 10 +drop table t1; +create table t1 (a timestamp null, b timestamp null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NULL DEFAULT NULL, + `b` timestamp NULL DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert into t1 values (NULL, NULL); +SET TIMESTAMP=1000000017; +insert into t1 values (); +select * from t1; +a b +NULL NULL +NULL NULL +drop table t1; +create table t1 (a timestamp null default current_timestamp on update current_timestamp, b timestamp null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `b` timestamp NULL DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert into t1 values (NULL, NULL); +SET TIMESTAMP=1000000018; +insert into t1 values (); +select * from t1; +a b +NULL NULL +2001-09-09 04:46:58 NULL +drop table t1; +create table t1 (a timestamp null default null, b timestamp null default '2003-01-01 00:00:00'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NULL DEFAULT NULL, + `b` timestamp NULL DEFAULT '2003-01-01 00:00:00' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert into t1 values (NULL, NULL); +insert into t1 values (DEFAULT, DEFAULT); +select * from t1; +a b +NULL NULL +NULL 2003-01-01 00:00:00 +drop table t1; +create table t1 (a bigint, b bigint); +insert into t1 values (NULL, NULL), (20030101000000, 20030102000000); +set timestamp=1000000019; +alter table t1 modify a timestamp, modify b timestamp; +select * from t1; +a b +2001-09-09 04:46:59 2001-09-09 04:46:59 +2003-01-01 00:00:00 2003-01-02 00:00:00 +drop table t1; +create table t1 (a char(2), t timestamp); +insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00'), +('b', '2004-02-01 00:00:00'); +select max(t) from t1 group by a; +max(t) +2004-01-01 01:00:00 +2004-02-01 00:00:00 +drop table t1; +set sql_mode='maxdb'; +create table t1 (a timestamp, b timestamp(19)); +show create table t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "a" datetime DEFAULT NULL, + "b" datetime DEFAULT NULL +) +set sql_mode=''; +drop table t1; +create table t1 (a int auto_increment primary key, b int, c timestamp); +insert into t1 (a, b, c) values (1, 0, '2001-01-01 01:01:01'), +(2, 0, '2002-02-02 02:02:02'), (3, 0, '2003-03-03 03:03:03'); +select * from t1; +a b c +1 0 2001-01-01 01:01:01 +2 0 2002-02-02 02:02:02 +3 0 2003-03-03 03:03:03 +update t1 set b = 2, c = c where a = 2; +select * from t1; +a b c +1 0 2001-01-01 01:01:01 +3 0 2003-03-03 03:03:03 +2 2 2002-02-02 02:02:02 +insert into t1 (a) values (4); +select * from t1 order by a; +a b c +1 0 2001-01-01 01:01:01 +2 2 2002-02-02 02:02:02 +3 0 2003-03-03 03:03:03 +4 NULL 2001-09-09 04:46:59 +update t1 set c = '2004-04-04 04:04:04' where a = 4; +select * from t1 order by a; +a b c +1 0 2001-01-01 01:01:01 +2 2 2002-02-02 02:02:02 +3 0 2003-03-03 03:03:03 +4 NULL 2004-04-04 04:04:04 +insert into t1 (a) values (3), (5) on duplicate key update b = 3, c = c; +select * from t1 order by a; +a b c +1 0 2001-01-01 01:01:01 +2 2 2002-02-02 02:02:02 +3 3 2003-03-03 03:03:03 +4 NULL 2004-04-04 04:04:04 +5 NULL 2001-09-09 04:46:59 +insert into t1 (a, c) values (4, '2004-04-04 00:00:00'), +(6, '2006-06-06 06:06:06') on duplicate key update b = 4; +select * from t1 order by a; +a b c +1 0 2001-01-01 01:01:01 +2 2 2002-02-02 02:02:02 +3 3 2003-03-03 03:03:03 +4 4 2001-09-09 04:46:59 +5 NULL 2001-09-09 04:46:59 +6 NULL 2006-06-06 06:06:06 +drop table t1; +set time_zone= @@global.time_zone; +CREATE TABLE t1 ( +`id` int(11) NOT NULL auto_increment, +`username` varchar(80) NOT NULL default '', +`posted_on` timestamp NOT NULL default '0000-00-00 00:00:00', +PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; +show fields from t1; +Field Type Null Key Default Extra +id int(11) NO PRI NULL auto_increment +username varchar(80) NO +posted_on timestamp NO 0000-00-00 00:00:00 +select is_nullable from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='t1' and COLUMN_NAME='posted_on'; +is_nullable +NO +drop table t1; diff --git a/mysql-test/suite/pbxt/r/type_uint.result b/mysql-test/suite/pbxt/r/type_uint.result new file mode 100644 index 00000000000..e08605fb237 --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_uint.result @@ -0,0 +1,16 @@ +drop table if exists t1; +SET SQL_WARNINGS=1; +create table t1 (this int unsigned); +insert into t1 values (1); +insert into t1 values (-1); +Warnings: +Warning 1264 Out of range value for column 'this' at row 1 +insert into t1 values ('5000000000'); +Warnings: +Warning 1264 Out of range value for column 'this' at row 1 +select * from t1; +this +1 +0 +4294967295 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/type_year.result b/mysql-test/suite/pbxt/r/type_year.result new file mode 100644 index 00000000000..84b688429db --- /dev/null +++ b/mysql-test/suite/pbxt/r/type_year.result @@ -0,0 +1,36 @@ +drop table if exists t1; +create table t1 (y year,y2 year(2)); +insert into t1 values (0,0),(1999,1999),(2000,2000),(2001,2001),(70,70),(69,69); +select * from t1; +y y2 +0000 00 +1999 99 +2000 00 +2001 01 +1970 70 +2069 69 +select * from t1 order by y; +y y2 +0000 00 +1970 70 +1999 99 +2000 00 +2001 01 +2069 69 +select * from t1 order by y2; +y y2 +1970 70 +1999 99 +0000 00 +2000 00 +2001 01 +2069 69 +drop table t1; +create table t1 (y year); +insert into t1 values (now()); +Warnings: +Warning 1265 Data truncated for column 'y' at row 1 +select if(y = now(), 1, 0) from t1; +if(y = now(), 1, 0) +1 +drop table t1; diff --git a/mysql-test/suite/pbxt/r/udf.result b/mysql-test/suite/pbxt/r/udf.result new file mode 100644 index 00000000000..15410ac2039 --- /dev/null +++ b/mysql-test/suite/pbxt/r/udf.result @@ -0,0 +1,395 @@ +drop table if exists t1; +CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +CREATE FUNCTION myfunc_double RETURNS REAL SONAME "UDF_EXAMPLE_LIB"; +CREATE FUNCTION myfunc_nonexist RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB"; +ERROR HY000: Can't find symbol 'myfunc_nonexist' in library +CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB"; +CREATE FUNCTION sequence RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB"; +CREATE FUNCTION lookup RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +CREATE FUNCTION reverse_lookup +RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +CREATE AGGREGATE FUNCTION avgcost +RETURNS REAL SONAME "UDF_EXAMPLE_LIB"; +select myfunc_double(); +ERROR HY000: Can't initialize function 'myfunc_double'; myfunc_double must have at least one argument +select myfunc_double(1); +myfunc_double(1) +49.00 +select myfunc_double(78654); +myfunc_double(78654) +54.00 +select myfunc_nonexist(); +ERROR 42000: FUNCTION test.myfunc_nonexist does not exist +select myfunc_int(); +myfunc_int() +0 +select lookup(); +ERROR HY000: Can't initialize function 'lookup'; Wrong arguments to lookup; Use the source +select lookup("127.0.0.1"); +lookup("127.0.0.1") +127.0.0.1 +select lookup(127,0,0,1); +ERROR HY000: Can't initialize function 'lookup'; Wrong arguments to lookup; Use the source +select lookup("localhost"); +lookup("localhost") +127.0.0.1 +select reverse_lookup(); +ERROR HY000: Can't initialize function 'reverse_lookup'; Wrong number of arguments to reverse_lookup; Use the source +select reverse_lookup("127.0.0.1"); +select reverse_lookup(127,0,0,1); +select reverse_lookup("localhost"); +reverse_lookup("localhost") +NULL +select avgcost(); +ERROR HY000: Can't initialize function 'avgcost'; wrong number of arguments: AVGCOST() requires two arguments +select avgcost(100,23.76); +ERROR HY000: Can't initialize function 'avgcost'; wrong argument type: AVGCOST() requires an INT and a REAL +create table t1(sum int, price float(24)); +insert into t1 values(100, 50.00), (100, 100.00); +select avgcost(sum, price) from t1; +avgcost(sum, price) +75.0000 +delete from t1; +insert into t1 values(100, 54.33), (200, 199.99); +select avgcost(sum, price) from t1; +avgcost(sum, price) +151.4367 +drop table t1; +select metaphon('hello'); +metaphon('hello') +HL +CREATE PROCEDURE `XXX1`(in testval varchar(10)) +begin +select metaphon(testval); +end// +call XXX1('hello'); +metaphon(testval) +HL +drop procedure xxx1; +CREATE PROCEDURE `XXX2`() +begin +declare testval varchar(10); +set testval = 'hello'; +select metaphon(testval); +end// +call XXX2(); +metaphon(testval) +HL +drop procedure xxx2; +CREATE TABLE bug19904(n INT, v varchar(10)); +INSERT INTO bug19904 VALUES (1,'one'),(2,'two'),(NULL,NULL),(3,'three'),(4,'four'); +SELECT myfunc_double(n) AS f FROM bug19904; +f +49.00 +50.00 +NULL +51.00 +52.00 +SELECT metaphon(v) AS f FROM bug19904; +f +ON +TW +NULL +0R +FR +DROP TABLE bug19904; +CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse +RETURNS STRING SONAME "should_not_parse.so"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNS STRING SONAME "should_not_parse.so"' at line 2 +CREATE DEFINER=someone@somewhere FUNCTION should_not_parse +RETURNS STRING SONAME "should_not_parse.so"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNS STRING SONAME "should_not_parse.so"' at line 2 +create table t1(f1 int); +insert into t1 values(1),(2); +explain select myfunc_int(f1) from t1 order by 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort +drop table t1; +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 values (1,1),(2,2); +CREATE FUNCTION fn(a int) RETURNS int DETERMINISTIC +BEGIN +RETURN a; +END +|| +CREATE VIEW v1 AS SELECT a, fn(MIN(b)) as c FROM t1 GROUP BY a; +SELECT myfunc_int(a AS attr_name) FROM t1; +myfunc_int(a AS attr_name) +1 +2 +EXPLAIN EXTENDED SELECT myfunc_int(a AS attr_name) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select myfunc_int(`test`.`t1`.`a` AS `attr_name`) AS `myfunc_int(a AS attr_name)` from `test`.`t1` +EXPLAIN EXTENDED SELECT myfunc_int(a) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 +Warnings: +Note 1003 select myfunc_int(`test`.`t1`.`a` AS `a`) AS `myfunc_int(a)` from `test`.`t1` +SELECT a,c FROM v1; +a c +1 1 +2 2 +SELECT a, fn(MIN(b) xx) as c FROM t1 GROUP BY a; +ERROR 42000: Incorrect parameters in the call to stored function 'fn' +SELECT myfunc_int(fn(MIN(b) xx)) as c FROM t1 GROUP BY a; +ERROR 42000: Incorrect parameters in the call to stored function 'fn' +SELECT myfunc_int(test.fn(MIN(b) xx)) as c FROM t1 GROUP BY a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xx)) as c FROM t1 GROUP BY a' at line 1 +SELECT myfunc_int(fn(MIN(b)) xx) as c FROM t1 GROUP BY a; +c +1 +2 +SELECT myfunc_int(test.fn(MIN(b)) xx) as c FROM t1 GROUP BY a; +c +1 +2 +EXPLAIN EXTENDED SELECT myfunc_int(MIN(b) xx) as c FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +Warnings: +Note 1003 select myfunc_int(min(`test`.`t1`.`b`) AS `xx`) AS `c` from `test`.`t1` group by `test`.`t1`.`a` +EXPLAIN EXTENDED SELECT test.fn(MIN(b)) as c FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +Warnings: +Note 1003 select `test`.`fn`(min(`test`.`t1`.`b`)) AS `c` from `test`.`t1` group by `test`.`t1`.`a` +EXPLAIN EXTENDED SELECT myfunc_int(fn(MIN(b))) as c FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +Warnings: +Note 1003 select myfunc_int(`fn`(min(`test`.`t1`.`b`)) AS `fn(MIN(b))`) AS `c` from `test`.`t1` group by `test`.`t1`.`a` +EXPLAIN EXTENDED SELECT myfunc_int(test.fn(MIN(b))) as c FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort +Warnings: +Note 1003 select myfunc_int(`test`.`fn`(min(`test`.`t1`.`b`)) AS `test.fn(MIN(b))`) AS `c` from `test`.`t1` group by `test`.`t1`.`a` +SELECT myfunc_int(MIN(b) xx) as c FROM t1 GROUP BY a; +c +1 +2 +SELECT test.fn(MIN(b)) as c FROM t1 GROUP BY a; +c +1 +2 +SELECT myfunc_int(fn(MIN(b))) as c FROM t1 GROUP BY a; +c +1 +2 +SELECT myfunc_int(test.fn(MIN(b))) as c FROM t1 GROUP BY a; +c +1 +2 +DROP VIEW v1; +DROP TABLE t1; +DROP FUNCTION fn; +End of 5.0 tests. +select myfunc_double(3); +myfunc_double(3) +51.00 +select myfunc_double(3 AS three); +myfunc_double(3 AS three) +51.00 +select myfunc_double(abs(3)); +myfunc_double(abs(3)) +51.00 +select myfunc_double(abs(3) AS named_param); +myfunc_double(abs(3) AS named_param) +51.00 +select abs(myfunc_double(3)); +abs(myfunc_double(3)) +51.00 +select abs(myfunc_double(3 AS three)); +abs(myfunc_double(3 AS three)) +51.00 +select myfunc_double(abs(3 AS wrong)); +ERROR 42000: Incorrect parameters in the call to native function 'abs' +select abs(myfunc_double(3) AS wrong); +ERROR 42000: Incorrect parameters in the call to native function 'abs' +drop function if exists pi; +CREATE FUNCTION pi RETURNS STRING SONAME "should_not_parse.so"; +ERROR HY000: This function 'pi' has the same name as a native function +DROP FUNCTION IF EXISTS metaphon; +CREATE FUNCTION metaphon(a int) RETURNS int +return 0; +CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +DROP FUNCTION metaphon; +DROP FUNCTION metaphon; +CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +CREATE FUNCTION metaphon(a int) RETURNS int +return 0; +ERROR HY000: Function 'metaphon' already exists +CREATE FUNCTION test.metaphon(a int) RETURNS int +return 0; +ERROR HY000: Function 'metaphon' already exists +DROP FUNCTION metaphon; +DROP FUNCTION myfunc_double; +DROP FUNCTION myfunc_nonexist; +ERROR 42000: FUNCTION test.myfunc_nonexist does not exist +DROP FUNCTION myfunc_int; +DROP FUNCTION sequence; +DROP FUNCTION lookup; +DROP FUNCTION reverse_lookup; +DROP FUNCTION avgcost; +select * from mysql.func; +name ret dl type +CREATE FUNCTION is_const RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +select IS_const(3); +IS_const(3) +const +drop function IS_const; +select * from mysql.func; +name ret dl type +select is_const(3); +ERROR 42000: FUNCTION test.is_const does not exist +CREATE FUNCTION is_const RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +select +is_const(3) as const, +is_const(3.14) as const, +is_const('fnord') as const, +is_const(2+3) as const, +is_const(rand()) as 'nc rand()', +is_const(sin(3.14)) as const, +is_const(upper('test')) as const; +const const const const nc rand() const const +const const const const not const const const +create table bug18761 (n int); +insert into bug18761 values (null),(2); +select +is_const(3) as const, +is_const(3.14) as const, +is_const('fnord') as const, +is_const(2+3) as const, +is_const(2+n) as 'nc 2+n ', +is_const(sin(n)) as 'nc sin(n)', +is_const(sin(3.14)) as const, +is_const(upper('test')) as const, +is_const(rand()) as 'nc rand()', +is_const(n) as 'nc n ', +is_const(is_const(n)) as 'nc ic?(n)', +is_const(is_const('c')) as const +from +bug18761; +const const const const nc 2+n nc sin(n) const const nc rand() nc n nc ic?(n) const +const const const const not const not const const const not const not const not const const +const const const const not const not const const const not const not const not const const +drop table bug18761; +select is_const((1,2,3)); +ERROR 21000: Operand should contain 1 column(s) +drop function if exists is_const; +CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +CREATE FUNCTION myfunc_double RETURNS REAL SONAME "UDF_EXAMPLE_LIB"; +CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB"; +create function f1(p1 varchar(255)) +returns varchar(255) +begin +return metaphon(p1); +end// +create function f2(p1 varchar(255)) +returns double +begin +return myfunc_double(p1); +end// +create function f3(p1 varchar(255)) +returns double +begin +return myfunc_int(p1); +end// +select f3(NULL); +f3(NULL) +0 +select f2(NULL); +f2(NULL) +NULL +select f1(NULL); +f1(NULL) +NULL +drop function f1; +drop function f2; +drop function f3; +drop function metaphon; +drop function myfunc_double; +drop function myfunc_int; +CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +create table t1 (a char); +set GLOBAL query_cache_size=1355776; +reset query cache; +select metaphon('MySQL') from t1; +metaphon('MySQL') +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select metaphon('MySQL') from t1; +metaphon('MySQL') +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +drop table t1; +drop function metaphon; +set GLOBAL query_cache_size=default; +DROP DATABASE IF EXISTS mysqltest; +CREATE DATABASE mysqltest; +USE mysqltest; +DROP DATABASE mysqltest; +CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; +DROP FUNCTION metaphon; +USE test; +CREATE TABLE const_len_bug ( +str_const varchar(4000), +result1 varchar(4000), +result2 varchar(4000) +); +CREATE TRIGGER check_const_len_trigger BEFORE INSERT ON const_len_bug FOR EACH ROW BEGIN +set NEW.str_const = 'bar'; +set NEW.result2 = check_const_len(NEW.str_const); +END | +CREATE PROCEDURE check_const_len_sp (IN str_const VARCHAR(4000)) +BEGIN +DECLARE result VARCHAR(4000); +SET result = check_const_len(str_const); +insert into const_len_bug values(str_const, result, ""); +END | +CREATE FUNCTION check_const_len RETURNS string SONAME "UDF_EXAMPLE_LIB"; +CALL check_const_len_sp("foo"); +SELECT * from const_len_bug; +str_const result1 result2 +bar Correct length Correct length +DROP FUNCTION check_const_len; +DROP PROCEDURE check_const_len_sp; +DROP TRIGGER check_const_len_trigger; +DROP TABLE const_len_bug; +CREATE FUNCTION sequence RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB"; +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (4),(3),(2),(1); +INSERT INTO t2 SELECT * FROM t1; +SELECT sequence() AS seq, a FROM t1 ORDER BY seq ASC; +seq a +1 4 +2 3 +3 2 +4 1 +SELECT sequence() AS seq, a FROM t1 ORDER BY seq DESC; +seq a +4 1 +3 2 +2 3 +1 4 +SELECT * FROM t1 WHERE a = sequence(); +a +SELECT * FROM t2 WHERE a = sequence(); +a +1 +2 +3 +4 +DROP FUNCTION sequence; +DROP TABLE t1,t2; +End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/r/union.result b/mysql-test/suite/pbxt/r/union.result new file mode 100644 index 00000000000..85fd7203488 --- /dev/null +++ b/mysql-test/suite/pbxt/r/union.result @@ -0,0 +1,1426 @@ +drop table if exists t1,t2,t3,t4,t5,t6; +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); +select a,b from t1 union distinct select a,b from t2; +a b +1 a +2 b +3 c +4 d +5 f +6 e +select a,b from t1 union all select a,b from t2; +a b +1 a +2 b +3 c +3 c +3 c +4 d +5 f +6 e +select a,b from t1 union all select a,b from t2 order by b; +a b +1 a +2 b +3 c +3 c +3 c +4 d +6 e +5 f +select a,b from t1 union all select a,b from t2 union select 7,'g'; +a b +1 a +2 b +3 c +4 d +5 f +6 e +7 g +select 0,'#' union select a,b from t1 union all select a,b from t2 union select 7,'gg'; +0 # +0 # +1 a +2 b +3 c +4 d +5 f +6 e +7 gg +select a,b from t1 union select a,b from t1; +a b +1 a +2 b +3 c +select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 group by b; +t1 b count(*) +t1 a 1 +t1 b 1 +t1 c 2 +t2 c 1 +t2 d 1 +t2 e 1 +t2 f 1 +(select a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 4; +a b +1 a +2 b +3 c +4 d +(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1); +a b +1 a +2 b +3 c +(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; +a b +3 c +2 b +1 a +(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; +ERROR 42000: Table 't1' from one of the SELECTs cannot be used in global ORDER clause +explain extended (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 100.00 +2 UNION t2 ALL NULL NULL NULL NULL 4 100.00 Using filesort +NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL NULL Using filesort +Warnings: +Note 1003 (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` limit 2) union all (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` order by `test`.`t2`.`a` limit 1) order by `b` desc +(select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; +a b +1 a +2 b +select found_rows(); +found_rows() +6 +select sql_calc_found_rows a,b from t1 union all select a,b from t2 limit 2; +a b +1 a +2 b +select found_rows(); +found_rows() +8 +explain select a,b from t1 union all select a,b from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +2 UNION t2 ALL NULL NULL NULL NULL 4 +NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL +explain select xx from t1 union select 1; +ERROR 42S22: Unknown column 'xx' in 'field list' +explain select a,b from t1 union select 1; +ERROR 21000: The used SELECT statements have a different number of columns +explain select 1 union select a,b from t1 union select 1; +ERROR 21000: The used SELECT statements have a different number of columns +explain select a,b from t1 union select 1 limit 0; +ERROR 21000: The used SELECT statements have a different number of columns +select a,b from t1 into outfile 'skr' union select a,b from t2; +ERROR HY000: Incorrect usage of UNION and INTO +select a,b from t1 order by a union select a,b from t2; +ERROR HY000: Incorrect usage of UNION and ORDER BY +insert into t3 select a from t1 order by a union select a from t2; +ERROR HY000: Incorrect usage of UNION and ORDER BY +create table t3 select a,b from t1 union select a from t2; +ERROR 21000: The used SELECT statements have a different number of columns +select a,b from t1 union select a from t2; +ERROR 21000: The used SELECT statements have a different number of columns +select * from t1 union select a from t2; +ERROR 21000: The used SELECT statements have a different number of columns +select a from t1 union select * from t2; +ERROR 21000: The used SELECT statements have a different number of columns +select * from t1 union select SQL_BUFFER_RESULT * from t2; +ERROR 42000: Incorrect usage/placement of 'SQL_BUFFER_RESULT' +create table t3 select a,b from t1 union all select a,b from t2; +insert into t3 select a,b from t1 union all select a,b from t2; +replace into t3 select a,b as c from t1 union all select a,b from t2; +drop table t1,t2,t3; +select * union select 1; +ERROR HY000: No tables used +select 1 as a,(select a union select a); +a (select a union select a) +1 1 +(select 1) union (select 2) order by 0; +ERROR 42S22: Unknown column '0' in 'order clause' +SELECT @a:=1 UNION SELECT @a:=@a+1; +@a:=1 +1 +2 +(SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a); +ERROR 42S22: Unknown column 'a' in 'field list' +(SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2); +1 3 +1 3 +2 1 +CREATE TABLE t1 ( +`pseudo` char(35) NOT NULL default '', +`pseudo1` char(35) NOT NULL default '', +`same` tinyint(1) unsigned NOT NULL default '1', +PRIMARY KEY (`pseudo1`), +KEY `pseudo` (`pseudo`) +) ENGINE=MyISAM; +INSERT INTO t1 (pseudo,pseudo1,same) VALUES ('joce', 'testtt', 1),('joce', 'tsestset', 1),('dekad', 'joce', 1); +SELECT pseudo FROM t1 WHERE pseudo1='joce' UNION SELECT pseudo FROM t1 WHERE pseudo='joce'; +pseudo +dekad +joce +SELECT pseudo1 FROM t1 WHERE pseudo1='joce' UNION SELECT pseudo1 FROM t1 WHERE pseudo='joce'; +pseudo1 +joce +testtt +tsestset +SELECT * FROM t1 WHERE pseudo1='joce' UNION SELECT * FROM t1 WHERE pseudo='joce' order by pseudo desc,pseudo1 desc; +pseudo pseudo1 same +joce tsestset 1 +joce testtt 1 +dekad joce 1 +SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION SELECT pseudo FROM t1 WHERE pseudo1='joce'; +pseudo1 +testtt +tsestset +dekad +SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION ALL SELECT pseudo FROM t1 WHERE pseudo1='joce'; +pseudo1 +testtt +tsestset +dekad +SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION SELECT 1; +pseudo1 +testtt +tsestset +1 +drop table t1; +create table t1 (a int); +create table t2 (a int); +insert into t1 values (1),(2),(3),(4),(5); +insert into t2 values (11),(12),(13),(14),(15); +(select * from t1 limit 2) union (select * from t2 limit 3) limit 4; +a +1 +2 +11 +12 +(select * from t1 limit 2) union (select * from t2 limit 3); +a +1 +2 +11 +12 +13 +(select * from t1 limit 2) union (select * from t2 limit 20,3); +a +1 +2 +set SQL_SELECT_LIMIT=2; +(select * from t1 limit 1) union (select * from t2 limit 3); +a +1 +11 +set SQL_SELECT_LIMIT=DEFAULT; +drop table t1,t2; +CREATE TABLE t1 ( +cid smallint(5) unsigned NOT NULL default '0', +cv varchar(250) NOT NULL default '', +PRIMARY KEY (cid), +UNIQUE KEY cv (cv) +) ; +INSERT INTO t1 VALUES (8,'dummy'); +CREATE TABLE t2 ( +cid bigint(20) unsigned NOT NULL auto_increment, +cap varchar(255) NOT NULL default '', +PRIMARY KEY (cid), +KEY cap (cap) +) ; +CREATE TABLE t3 ( +gid bigint(20) unsigned NOT NULL auto_increment, +gn varchar(255) NOT NULL default '', +must tinyint(4) default NULL, +PRIMARY KEY (gid), +KEY gn (gn) +) ; +INSERT INTO t3 VALUES (1,'V1',NULL); +CREATE TABLE t4 ( +uid bigint(20) unsigned NOT NULL default '0', +gid bigint(20) unsigned default NULL, +rid bigint(20) unsigned default NULL, +cid bigint(20) unsigned default NULL, +UNIQUE KEY m (uid,gid,rid,cid), +KEY uid (uid), +KEY rid (rid), +KEY cid (cid), +KEY container (gid,rid,cid) +) ; +INSERT INTO t4 VALUES (1,1,NULL,NULL); +CREATE TABLE t5 ( +rid bigint(20) unsigned NOT NULL auto_increment, +rl varchar(255) NOT NULL default '', +PRIMARY KEY (rid), +KEY rl (rl) +) ; +CREATE TABLE t6 ( +uid bigint(20) unsigned NOT NULL auto_increment, +un varchar(250) NOT NULL default '', +uc smallint(5) unsigned NOT NULL default '0', +PRIMARY KEY (uid), +UNIQUE KEY nc (un,uc), +KEY un (un) +) ; +INSERT INTO t6 VALUES (1,'test',8); +SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"; +uid rl g1 cid gg +1 NULL V1 NULL 1 +SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t3.must IS NOT NULL AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"; +uid rl g1 cid gg +(SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t3.must IS NOT NULL AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test") UNION (SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"); +uid rl g1 cid gg +1 NULL V1 NULL 1 +drop table t1,t2,t3,t4,t5,t6; +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); +create table t3 select a,b from t1 union select a,b from t2; +create table t4 (select a,b from t1) union (select a,b from t2) limit 2; +insert into t4 select a,b from t1 union select a,b from t2; +insert into t3 (select a,b from t1) union (select a,b from t2) limit 2; +select * from t3; +a b +1 a +2 b +3 c +4 d +5 f +6 e +1 a +2 b +select * from t4; +a b +1 a +2 b +1 a +2 b +3 c +4 d +5 f +6 e +drop table t1,t2,t3,t4; +create table t1 (a int); +insert into t1 values (1),(2),(3); +create table t2 (a int); +insert into t2 values (3),(4),(5); +(SELECT SQL_CALC_FOUND_ROWS * FROM t1) UNION all (SELECT * FROM t2) LIMIT 1; +a +1 +select found_rows(); +found_rows() +6 +(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION all (SELECT * FROM t2) LIMIT 2; +a +1 +3 +select found_rows(); +found_rows() +4 +(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION all (SELECT * FROM t2); +a +1 +3 +4 +5 +select found_rows(); +found_rows() +4 +(SELECT SQL_CALC_FOUND_ROWS * FROM t1) UNION all (SELECT * FROM t2 LIMIT 1); +a +1 +2 +3 +3 +select found_rows(); +found_rows() +4 +(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION SELECT * FROM t2 LIMIT 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION all SELECT * FROM t2 LIMIT 2; +a +1 +3 +select found_rows(); +found_rows() +6 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION all SELECT * FROM t2 LIMIT 2; +a +1 +2 +select found_rows(); +found_rows() +6 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2; +a +1 +2 +select found_rows(); +found_rows() +6 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 100; +a +1 +2 +3 +4 +5 +select found_rows(); +found_rows() +6 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 100 UNION SELECT * FROM t2; +a +1 +2 +3 +4 +5 +select found_rows(); +found_rows() +5 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION SELECT * FROM t2; +a +1 +3 +4 +5 +select found_rows(); +found_rows() +6 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION SELECT * FROM t2 LIMIT 2; +a +1 +3 +select found_rows(); +found_rows() +6 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2,2; +a +3 +4 +select found_rows(); +found_rows() +6 +SELECT SQL_CALC_FOUND_ROWS * FROM t1 limit 2,2 UNION SELECT * FROM t2; +a +3 +4 +5 +select found_rows(); +found_rows() +5 +SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a desc LIMIT 1; +a +5 +(SELECT * FROM t1 ORDER by a) UNION ALL (SELECT * FROM t2 ORDER BY a) ORDER BY A desc LIMIT 4; +a +5 +4 +3 +3 +(SELECT * FROM t1) UNION all (SELECT SQL_CALC_FOUND_ROWS * FROM t2) LIMIT 1; +ERROR 42000: Incorrect usage/placement of 'SQL_CALC_FOUND_ROWS' +create temporary table t1 engine=myisam select a from t1 union select a from t2; +drop temporary table t1; +create table t1 select a from t1 union select a from t2; +ERROR HY000: You can't specify target table 't1' for update in FROM clause +select a from t1 union select a from t2 order by t2.a; +ERROR 42S22: Unknown column 't2.a' in 'order clause' +drop table t1,t2; +select length(version()) > 1 as `*` UNION select 2; +* +1 +2 +create table t1 (a int); +insert into t1 values (0), (3), (1), (2); +explain (select * from t1) union (select * from t1) order by a; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 4 +2 UNION t1 ALL NULL NULL NULL NULL 4 +NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL Using filesort +drop table t1; +CREATE TABLE t1 ( id int(3) unsigned default '0') ENGINE=MyISAM; +INSERT INTO t1 (id) VALUES("1"); +CREATE TABLE t2 ( id int(3) unsigned default '0', id_master int(5) default '0', text1 varchar(5) default NULL, text2 varchar(5) default NULL) ENGINE=MyISAM; +INSERT INTO t2 (id, id_master, text1, text2) VALUES("1", "1", +"foo1", "bar1"); +INSERT INTO t2 (id, id_master, text1, text2) VALUES("2", "1", +"foo2", "bar2"); +INSERT INTO t2 (id, id_master, text1, text2) VALUES("3", "1", NULL, +"bar3"); +INSERT INTO t2 (id, id_master, text1, text2) VALUES("4", "1", +"foo4", "bar4"); +SELECT 1 AS id_master, 1 AS id, NULL AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; +id_master id text1 text2 +1 1 NULL ABCDE +1 1 foo1 bar1 +1 2 foo2 bar2 +1 3 NULL bar3 +1 4 foo4 bar4 +SELECT 1 AS id_master, 1 AS id, 'ABCDE' AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; +id_master id text1 text2 +1 1 ABCDE ABCDE +1 1 foo1 bar1 +1 2 foo2 bar2 +1 3 NULL bar3 +1 4 foo4 bar4 +drop table if exists t1,t2; +create table t1 (a int not null primary key auto_increment, b int, key(b)); +create table t2 (a int not null primary key auto_increment, b int); +insert into t1 (b) values (1),(2),(2),(3); +insert into t2 (b) values (10),(11),(12),(13); +explain extended (select * from t1 where a=1) union (select * from t2 where a=1); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 100.00 +2 UNION t2 const PRIMARY PRIMARY 4 const 1 100.00 +NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1003 (select '1' AS `a`,'1' AS `b` from `test`.`t1` where ('1' = 1)) union (select '1' AS `a`,'10' AS `b` from `test`.`t2` where ('1' = 1)) +(select * from t1 where a=5) union (select * from t2 where a=1); +a b +1 10 +(select * from t1 where a=5 and a=6) union (select * from t2 where a=1); +a b +1 10 +(select t1.a,t1.b from t1,t2 where t1.a=5) union (select * from t2 where a=1); +a b +1 10 +(select * from t1 where a=1) union (select t1.a,t2.a from t1,t2 where t1.a=t2.a); +a b +1 1 +2 2 +3 3 +4 4 +explain (select * from t1 where a=1 and b=10) union (select straight_join t1.a,t2.a from t1,t2 where t1.a=t2.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 UNION t1 index PRIMARY PRIMARY 4 NULL 4 Using index +2 UNION t2 index PRIMARY PRIMARY 4 NULL 4 Using where; Using index; Using join buffer +NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL +explain (select * from t1 where a=1) union (select * from t1 where b=1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 +2 UNION t1 ref b b 5 const 1 Using where +NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL +drop table t1,t2; +create table t1 ( id int not null auto_increment, primary key (id) ,user_name text ); +create table t2 ( id int not null auto_increment, primary key (id) ,group_name text ); +create table t3 ( id int not null auto_increment, primary key (id) ,user_id int ,index user_idx (user_id) ,foreign key (user_id) references t1(id) ,group_id int ,index group_idx (group_id) ,foreign key (group_id) references t2(id) ); +insert into t1 (user_name) values ('Tester'); +insert into t2 (group_name) values ('Group A'); +insert into t2 (group_name) values ('Group B'); +insert into t3 (user_id, group_id) values (1,1); +select 1 'is_in_group', a.user_name, c.group_name, b.id from t1 a, t3 b, t2 c where a.id = b.user_id and b.group_id = c.id UNION select 0 'is_in_group', a.user_name, c.group_name, null from t1 a, t2 c; +is_in_group user_name group_name id +1 Tester Group A 1 +0 Tester Group A NULL +0 Tester Group B NULL +drop table t3, t2, t1; +create table t1 (mat_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, matintnum CHAR(6) NOT NULL, test MEDIUMINT UNSIGNED NULL); +create table t2 (mat_id MEDIUMINT UNSIGNED NOT NULL, pla_id MEDIUMINT UNSIGNED NOT NULL); +insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd', 4), (NULL, 'e', 5), (NULL, 'f', 6), (NULL, 'g', 7), (NULL, 'h', 8), (NULL, 'i', 9); +insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105); +SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id union SELECT 0, 0; +pla_id matintnum +100 a +101 a +102 a +103 b +104 b +105 c +0 0 +drop table t1, t2; +create table t1 SELECT "a" as a UNION select "aa" as a; +select * from t1; +a +a +aa +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(2) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT 12 as a UNION select "aa" as a; +select * from t1; +a +12 +aa +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varbinary(2) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT 12 as a UNION select 12.2 as a; +select * from t1; +a +12.0 +12.2 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` decimal(3,1) NOT NULL DEFAULT '0.0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob, tx text); +insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'testc', 'testv', 'tetetetetest', 'teeeeeeeeeeeest'); +create table t1 SELECT it2 from t2 UNION select it1 from t2; +select * from t1; +it2 +1 +NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `it2` tinyint(4) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT it2 from t2 UNION select i from t2; +select * from t1; +it2 +1 +3 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `it2` int(11) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT i from t2 UNION select f from t2; +select * from t1; +i +3 +1.5 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` double DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT f from t2 UNION select d from t2; +select * from t1; +f +1.5 +2.5 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` double DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT ib from t2 UNION select f from t2; +select * from t1; +ib +4 +1.5 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ib` double DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT ib from t2 UNION select d from t2; +select * from t1; +ib +4 +2.5 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ib` double DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT f from t2 UNION select y from t2; +select * from t1; +f +1.5 +1972 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` float DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT f from t2 UNION select da from t2; +select * from t1; +f +1.5 +1972-10-22 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` varbinary(12) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT y from t2 UNION select da from t2; +select * from t1; +y +1972 +1972-10-22 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `y` varbinary(10) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT y from t2 UNION select dt from t2; +select * from t1; +y +1972 +1972-10-22 11:50:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `y` varbinary(19) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT da from t2 UNION select dt from t2; +select * from t1; +da +1972-10-22 00:00:00 +1972-10-22 11:50:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `da` datetime DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT dt from t2 UNION select trim(sc) from t2; +select trim(dt) from t1; +trim(dt) +1972-10-22 11:50:00 +testc +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `dt` varbinary(19) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT dt from t2 UNION select sv from t2; +select * from t1; +dt +1972-10-22 11:50:00 +testv +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `dt` varbinary(19) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT sc from t2 UNION select sv from t2; +select * from t1; +sc +testc +testv +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sc` varchar(10) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT dt from t2 UNION select b from t2; +select * from t1; +dt +1972-10-22 11:50:00 +tetetetetest +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `dt` blob +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT sv from t2 UNION select b from t2; +select * from t1; +sv +testv +tetetetetest +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sv` blob +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT i from t2 UNION select d from t2 UNION select b from t2; +select * from t1; +i +3 +2.5 +tetetetetest +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` blob +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT sv from t2 UNION select tx from t2; +select * from t1; +sv +testv +teeeeeeeeeeeest +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sv` text +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT b from t2 UNION select tx from t2; +select * from t1; +b +tetetetetest +teeeeeeeeeeeest +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` blob +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1,t2; +create table t1 select 1 union select -1; +select * from t1; +1 +1 +-1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` bigint(20) NOT NULL DEFAULT '0' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select _latin1"test" union select _latin2"testt" ; +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'UNION' +create table t1 select _latin2"test" union select _latin2"testt" ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `test` varchar(5) CHARACTER SET latin2 NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (s char(200)); +insert into t1 values (repeat("1",200)); +create table t2 select * from t1; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +set local tmp_table_size=1024; +select count(*) from (select * from t1 union all select * from t2 order by 1) b; +count(*) +21 +select count(*) from t1; +count(*) +8 +select count(*) from t2; +count(*) +13 +drop table t1,t2; +set local tmp_table_size=default; +create table t1 (a int, index (a), b int); +insert t1 values (1,1),(2,2),(3,3),(4,4),(5,5); +insert t1 select a+1, a+b from t1; +insert t1 select a+1, a+b from t1; +insert t1 select a+1, a+b from t1; +insert t1 select a+1, a+b from t1; +insert t1 select a+1, a+b from t1; +FLUSH STATUS; +show status like 'Slow_queries'; +Variable_name Value +Slow_queries 0 +select count(*) from t1 where a=7; +count(*) +26 +show status like 'Slow_queries'; +Variable_name Value +Slow_queries 0 +select count(*) from t1 where b=13; +count(*) +10 +show status like 'Slow_queries'; +Variable_name Value +Slow_queries 0 +select count(*) from t1 where b=13 union select count(*) from t1 where a=7; +count(*) +10 +26 +show status like 'Slow_queries'; +Variable_name Value +Slow_queries 0 +select count(*) from t1 where a=7 union select count(*) from t1 where b=13; +count(*) +26 +10 +show status like 'Slow_queries'; +Variable_name Value +Slow_queries 0 +flush status; +select a from t1 where b not in (1,2,3) union select a from t1 where b not in (4,5,6); +a +4 +5 +3 +6 +7 +8 +9 +10 +1 +2 +show status like 'Slow_queries'; +Variable_name Value +Slow_queries 0 +drop table t1; +create table t1 ( RID int(11) not null default '0', IID int(11) not null default '0', nada varchar(50) not null,NAME varchar(50) not null,PHONE varchar(50) not null) engine=MyISAM; +insert into t1 ( RID,IID,nada,NAME,PHONE) values (1, 1, 'main', 'a', '111'), (2, 1, 'main', 'b', '222'), (3, 1, 'main', 'c', '333'), (4, 1, 'main', 'd', '444'), (5, 1, 'main', 'e', '555'), (6, 2, 'main', 'c', '333'), (7, 2, 'main', 'd', '454'), (8, 2, 'main', 'e', '555'), (9, 2, 'main', 'f', '666'), (10, 2, 'main', 'g', '777'); +select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 A left join t1 B on A.NAME = B.NAME and B.IID = 2 where A.IID = 1 and (A.PHONE <> B.PHONE or B.NAME is null) union select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 B left join t1 A on B.NAME = A.NAME and A.IID = 1 where B.IID = 2 and (A.PHONE <> B.PHONE or A.NAME is null); +NAME PHONE NAME PHONE +a 111 NULL NULL +b 222 NULL NULL +d 444 d 454 +NULL NULL f 666 +NULL NULL g 777 +drop table t1; +create table t1 (col1 tinyint unsigned, col2 tinyint unsigned); +insert into t1 values (1,2),(3,4),(5,6),(7,8),(9,10); +select col1 n from t1 union select col2 n from t1 order by n; +n +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +alter table t1 add index myindex (col2); +select col1 n from t1 union select col2 n from t1 order by n; +n +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +drop table t1; +create table t1 (i int); +insert into t1 values (1); +select * from t1 UNION select * from t1; +i +1 +select * from t1 UNION ALL select * from t1; +i +1 +1 +select * from t1 UNION select * from t1 UNION ALL select * from t1; +i +1 +1 +drop table t1; +select 1 as a union all select 1 union all select 2 union select 1 union all select 2; +a +1 +2 +2 +set sql_select_limit=1; +select 1 union select 2; +1 +1 +(select 1) union (select 2); +1 +1 +(select 1) union (select 2) union (select 3) limit 2; +1 +1 +2 +set sql_select_limit=default; +create table t1 (a int); +insert into t1 values (100), (1); +create table t2 (a int); +insert into t2 values (100); +select a from t1 union select a from t2 order by a; +a +1 +100 +SET SQL_SELECT_LIMIT=1; +select a from t1 union select a from t2 order by a; +a +1 +drop table t1, t2; +set sql_select_limit=default; +CREATE TABLE t1 (i int(11) default NULL,c char(1) default NULL,KEY i (i)); +CREATE TABLE t2 (i int(11) default NULL,c char(1) default NULL,KEY i (i)); +explain (select * from t1) union (select * from t2) order by not_existing_column; +ERROR 42S22: Unknown column 'not_existing_column' in 'order clause' +drop table t1, t2; +CREATE TABLE t1 (uid int(1)); +INSERT INTO t1 SELECT 150; +SELECT 'a' UNION SELECT uid FROM t1; +a +a +150 +drop table t1; +CREATE TABLE t1 ( ID1 int(10) unsigned NOT NULL DEFAULT '0' , ID2 datetime NOT NULL DEFAULT '0000-00-00 00:00:00' , DATA1 varchar(10) , DATA2 double(5,4) , DATA3 datetime , PRIMARY KEY (ID1,ID2)); +CREATE TABLE t2 ( ID int(3) unsigned NOT NULL DEFAULT '0' , DATA1 timestamp DEFAULT '0000-00-00 00:00:00' , PRIMARY KEY (ID)); +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1); +ID1 ID2 DATA1 DATA2 DATA3 ID DATA1 +drop table t1,t2; +create table t1 (a ENUM('Yes', 'No') NOT NULL); +create table t2 (a ENUM('aaa', 'bbb') NOT NULL); +insert into t1 values ('No'); +insert into t2 values ('bbb'); +create table t3 (a SET('Yes', 'No') NOT NULL); +create table t4 (a SET('aaa', 'bbb') NOT NULL); +insert into t3 values (1); +insert into t4 values (3); +select "1" as a union select a from t1; +a +1 +No +select a as a from t1 union select "1"; +a +No +1 +select a as a from t2 union select a from t1; +a +bbb +No +select "1" as a union select a from t3; +a +1 +Yes +select a as a from t3 union select "1"; +a +Yes +1 +select a as a from t4 union select a from t3; +a +aaa,bbb +Yes +select a as a from t1 union select a from t4; +a +No +aaa,bbb +drop table t1,t2,t3,t4; +create table t1 as +(select _latin1'test') union +(select _latin1'TEST') union +(select _latin1'TeST'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `test` varchar(4) NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +1 +drop table t1; +create table t1 as +(select _latin1'test' collate latin1_bin) union +(select _latin1'TEST') union +(select _latin1'TeST'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `_latin1'test' collate latin1_bin` varchar(4) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +3 +drop table t1; +create table t1 as +(select _latin1'test') union +(select _latin1'TEST' collate latin1_bin) union +(select _latin1'TeST'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `test` varchar(4) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +3 +drop table t1; +create table t1 as +(select _latin1'test') union +(select _latin1'TEST') union +(select _latin1'TeST' collate latin1_bin); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `test` varchar(4) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '' +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +3 +drop table t1; +create table t2 ( +a char character set latin1 collate latin1_swedish_ci, +b char character set latin1 collate latin1_german1_ci); +create table t1 as +(select a from t2) union +(select b from t2); +ERROR HY000: Illegal mix of collations for operation 'UNION' +create table t1 as +(select a collate latin1_german1_ci from t2) union +(select b from t2); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a collate latin1_german1_ci` varchar(1) CHARACTER SET latin1 COLLATE latin1_german1_ci DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 as +(select a from t2) union +(select b collate latin1_german1_ci from t2); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(1) CHARACTER SET latin1 COLLATE latin1_german1_ci DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +create table t1 as +(select a from t2) union +(select b from t2) union +(select 'c' collate latin1_german1_ci from t2); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(1) CHARACTER SET latin1 COLLATE latin1_german1_ci DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +drop table t2; +create table t1(a1 int, f1 char(10)); +create table t2 +select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a +union +select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a +order by f2, a1; +show columns from t2; +Field Type Null Key Default Extra +f2 date YES NULL +a1 int(11) YES NULL +drop table t1, t2; +create table t1 (f1 int); +create table t2 (f1 int, f2 int ,f3 date); +create table t3 (f1 int, f2 char(10)); +create table t4 +( +select t2.f3 as sdate +from t1 +left outer join t2 on (t1.f1 = t2.f1) +inner join t3 on (t2.f2 = t3.f1) +order by t1.f1, t3.f1, t2.f3 +) +union +( +select cast('2004-12-31' as date) as sdate +from t1 +left outer join t2 on (t1.f1 = t2.f1) +inner join t3 on (t2.f2 = t3.f1) +group by t1.f1 +order by t1.f1, t3.f1, t2.f3 +) +order by sdate; +show columns from t4; +Field Type Null Key Default Extra +sdate date YES NULL +drop table t1, t2, t3, t4; +create table t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +select * from ((select * from t1 limit 1)) a; +a b +1 a +select * from ((select * from t1 limit 1) union (select * from t1 limit 1)) a; +a b +1 a +select * from ((select * from t1 limit 1) union (select * from t1 limit 1) union (select * from t1 limit 1)) a; +a b +1 a +select * from ((((select * from t1))) union (select * from t1) union (select * from t1)) a; +a b +1 a +2 b +3 c +select * from ((select * from t1) union (((select * from t1))) union (select * from t1)) a; +a b +1 a +2 b +3 c +drop table t1; +set @val:=6; +select concat('value is: ', @val) union select 'some text'; +concat('value is: ', @val) +value is: 6 +some text +select concat(_latin1'a', _ascii'b' collate ascii_bin); +concat(_latin1'a', _ascii'b' collate ascii_bin) +ab +create table t1 (foo varchar(100)) collate ascii_bin; +insert into t1 (foo) values ("foo"); +select foo from t1 union select 'bar' as foo from dual; +foo +foo +bar +drop table t1; +CREATE TABLE t1 ( +a ENUM('ä','ö','ü') character set utf8 not null default 'ü', +b ENUM("one", "two") character set utf8, +c ENUM("one", "two") +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` enum('ä','ö','ü') CHARACTER SET utf8 NOT NULL DEFAULT 'ü', + `b` enum('one','two') CHARACTER SET utf8 DEFAULT NULL, + `c` enum('one','two') DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +insert into t1 values ('ä', 'one', 'one'), ('ö', 'two', 'one'), ('ü', NULL, NULL); +create table t2 select NULL union select a from t1; +show columns from t2; +Field Type Null Key Default Extra +NULL enum('ä','ö','ü') YES NULL +drop table t2; +create table t2 select a from t1 union select NULL; +show columns from t2; +Field Type Null Key Default Extra +a enum('ä','ö','ü') YES NULL +drop table t2; +create table t2 select a from t1 union select a from t1; +show columns from t2; +Field Type Null Key Default Extra +a varchar(1) NO +drop table t2; +create table t2 select a from t1 union select c from t1; +drop table t2; +create table t2 select a from t1 union select b from t1; +show columns from t2; +Field Type Null Key Default Extra +a varchar(3) YES NULL +drop table t2, t1; +create table t1 (f1 decimal(60,25), f2 decimal(60,25)); +insert into t1 values (0.0,0.0); +select f1 from t1 union all select f2 from t1; +f1 +0.0000000000000000000000000 +0.0000000000000000000000000 +select 'XXXXXXXXXXXXXXXXXXXX' as description, f1 from t1 +union all +select 'YYYYYYYYYYYYYYYYYYYY' as description, f2 from t1; +description f1 +XXXXXXXXXXXXXXXXXXXX 0.0000000000000000000000000 +YYYYYYYYYYYYYYYYYYYY 0.0000000000000000000000000 +drop table t1; +create table t1 (f1 decimal(60,24), f2 decimal(60,24)); +insert into t1 values (0.0,0.0); +select f1 from t1 union all select f2 from t1; +f1 +0.000000000000000000000000 +0.000000000000000000000000 +select 'XXXXXXXXXXXXXXXXXXXX' as description, f1 from t1 +union all +select 'YYYYYYYYYYYYYYYYYYYY' as description, f2 from t1; +description f1 +XXXXXXXXXXXXXXXXXXXX 0.000000000000000000000000 +YYYYYYYYYYYYYYYYYYYY 0.000000000000000000000000 +drop table t1; +create table t1 (a varchar(5)); +create table t2 select * from t1 union select 'abcdefghijkl'; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(12) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +select row_format from information_schema.TABLES where table_schema="test" and table_name="t2"; +row_format +Dynamic +alter table t2 ROW_FORMAT=fixed; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(12) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED +drop table t1,t2; +CREATE TABLE t1 (a mediumtext); +CREATE TABLE t2 (b varchar(20)); +INSERT INTO t1 VALUES ('a'),('b'); +SELECT left(a,100000000) FROM t1 UNION SELECT b FROM t2; +left(a,100000000) +a +b +create table t3 SELECT left(a,100000000) FROM t1 UNION SELECT b FROM t2; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `left(a,100000000)` mediumtext +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop tables t1,t2,t3; +CREATE TABLE t1 (a longtext); +CREATE TABLE t2 (b varchar(20)); +INSERT INTO t1 VALUES ('a'),('b'); +SELECT left(a,100000000) FROM t1 UNION SELECT b FROM t2; +left(a,100000000) +a +b +create table t3 SELECT left(a,100000000) FROM t1 UNION SELECT b FROM t2; +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `left(a,100000000)` longtext +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop tables t1,t2,t3; +CREATE TABLE t1 (a mediumtext); +CREATE TABLE t2 (b varchar(20)); +INSERT INTO t1 VALUES ('a'); +CREATE TABLE t3 SELECT REPEAT(a,20000000) AS a FROM t1 UNION SELECT b FROM t2; +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` longtext +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLES t1,t3; +CREATE TABLE t1 (a tinytext); +INSERT INTO t1 VALUES ('a'); +CREATE TABLE t3 SELECT REPEAT(a,2) AS a FROM t1 UNION SELECT b FROM t2; +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` varchar(510) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLES t1,t3; +CREATE TABLE t1 (a mediumtext); +INSERT INTO t1 VALUES ('a'); +CREATE TABLE t3 SELECT REPEAT(a,2) AS a FROM t1 UNION SELECT b FROM t2; +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` longtext +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLES t1,t3; +CREATE TABLE t1 (a tinyblob); +INSERT INTO t1 VALUES ('a'); +CREATE TABLE t3 SELECT REPEAT(a,2) AS a FROM t1 UNION SELECT b FROM t2; +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` varbinary(510) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +DROP TABLES t1,t2,t3; +create table t1 ( id int not null auto_increment, primary key (id), col1 int); +insert into t1 (col1) values (2),(3),(4),(5),(6); +select 99 union all select id from t1 order by 1; +99 +1 +2 +3 +4 +5 +99 +select id from t1 union all select 99 order by 1; +id +1 +2 +3 +4 +5 +99 +drop table t1; +create table t1(f1 char(1), f2 char(5), f3 binary(1), f4 binary(5), f5 timestamp, f6 varchar(1) character set utf8 collate utf8_general_ci, f7 text); +create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `f1` char(1) DEFAULT NULL, + `f2` char(5) DEFAULT NULL, + `f3` binary(1) DEFAULT NULL, + `f4` binary(5) DEFAULT NULL, + `f5` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `f6` varchar(1) CHARACTER SET utf8 DEFAULT NULL, + `f7` text, + `f8` mediumtext CHARACTER SET utf8 +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1, t2; +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)); +avg(1) +1.0000 +select _utf8'12' union select _latin1'12345'; +12 +12 +12345 +End of 5.0 tests diff --git a/mysql-test/suite/pbxt/r/update.result b/mysql-test/suite/pbxt/r/update.result new file mode 100644 index 00000000000..3a690709c28 --- /dev/null +++ b/mysql-test/suite/pbxt/r/update.result @@ -0,0 +1,384 @@ +drop table if exists t1,t2; +create table t1 (a int auto_increment , primary key (a)); +insert into t1 values (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +update t1 set a=a+10 where a > 34; +update t1 set a=a+100 where a > 0; +update t1 set a=a+100 where a=1 and a=2; +update t1 set a=b+100 where a=1 and a=2; +ERROR 42S22: Unknown column 'b' in 'field list' +update t1 set a=b+100 where c=1 and a=2; +ERROR 42S22: Unknown column 'c' in 'where clause' +update t1 set d=a+100 where a=1; +ERROR 42S22: Unknown column 'd' in 'field list' +select * from t1; +a +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +145 +146 +drop table t1; +CREATE TABLE t1 +( +place_id int (10) unsigned NOT NULL, +shows int(10) unsigned DEFAULT '0' NOT NULL, +ishows int(10) unsigned DEFAULT '0' NOT NULL, +ushows int(10) unsigned DEFAULT '0' NOT NULL, +clicks int(10) unsigned DEFAULT '0' NOT NULL, +iclicks int(10) unsigned DEFAULT '0' NOT NULL, +uclicks int(10) unsigned DEFAULT '0' NOT NULL, +ts timestamp, +PRIMARY KEY (place_id,ts) +); +INSERT INTO t1 (place_id,shows,ishows,ushows,clicks,iclicks,uclicks,ts) +VALUES (1,0,0,0,0,0,0,20000928174434); +UPDATE t1 SET shows=shows+1,ishows=ishows+1,ushows=ushows+1,clicks=clicks+1,iclicks=iclicks+1,uclicks=uclicks+1 WHERE place_id=1 AND ts>="2000-09-28 00:00:00"; +select place_id,shows from t1; +place_id shows +1 1 +drop table t1; +CREATE TABLE t1 ( +lfdnr int(10) unsigned NOT NULL default '0', +ticket int(10) unsigned NOT NULL default '0', +client varchar(255) NOT NULL default '', +replyto varchar(255) NOT NULL default '', +subject varchar(100) NOT NULL default '', +timestamp int(10) unsigned NOT NULL default '0', +tstamp timestamp NOT NULL, +status int(3) NOT NULL default '0', +type varchar(15) NOT NULL default '', +assignment int(10) unsigned NOT NULL default '0', +fupcount int(4) unsigned NOT NULL default '0', +parent int(10) unsigned NOT NULL default '0', +activity int(10) unsigned NOT NULL default '0', +priority tinyint(1) unsigned NOT NULL default '1', +cc varchar(255) NOT NULL default '', +bcc varchar(255) NOT NULL default '', +body text NOT NULL, +comment text, +header text, +PRIMARY KEY (lfdnr), +KEY k1 (timestamp), +KEY k2 (type), +KEY k3 (parent), +KEY k4 (assignment), +KEY ticket (ticket) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (773,773,'','','',980257344,20010318180652,0,'Open',10,0,0,0,1,'','','','',''); +alter table t1 change lfdnr lfdnr int(10) unsigned not null auto_increment; +update t1 set status=1 where type='Open'; +select status from t1; +status +1 +drop table t1; +create table t1 (a int not null, b int not null, key (a)); +insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); +SET @tmp=0; +update t1 set b=(@tmp:=@tmp+1) order by a; +update t1 set b=99 where a=1 order by b asc limit 1; +select * from t1 order by a,b; +a b +1 2 +1 3 +1 99 +2 4 +2 5 +2 6 +3 7 +3 8 +3 9 +3 10 +3 11 +3 12 +update t1 set b=100 where a=1 order by b desc limit 2; +update t1 set a=a+10+b where a=1 order by b; +select * from t1 order by a,b; +a b +2 4 +2 5 +2 6 +3 7 +3 8 +3 9 +3 10 +3 11 +3 12 +13 2 +111 100 +111 100 +create table t2 (a int not null, b int not null); +insert into t2 values (1,1),(1,2),(1,3); +update t1 set b=(select distinct 1 from (select * from t2) a); +drop table t1,t2; +CREATE TABLE t1 ( +`id_param` smallint(3) unsigned NOT NULL default '0', +`nom_option` char(40) NOT NULL default '', +`valid` tinyint(1) NOT NULL default '0', +KEY `id_param` (`id_param`,`nom_option`) +) ENGINE=MyISAM; +INSERT INTO t1 (id_param,nom_option,valid) VALUES (185,'600x1200',1); +UPDATE t1 SET nom_option='test' WHERE id_param=185 AND nom_option='600x1200' AND valid=1 LIMIT 1; +select * from t1; +id_param nom_option valid +185 test 1 +drop table t1; +create table t1 (F1 VARCHAR(30), F2 VARCHAR(30), F3 VARCHAR(30), cnt int, groupid int, KEY groupid_index (groupid)); +insert into t1 (F1,F2,F3,cnt,groupid) values ('0','0','0',1,6), +('0','1','2',1,5), ('0','2','0',1,3), ('1','0','1',1,2), +('1','2','1',1,1), ('1','2','2',1,1), ('2','0','1',2,4), +('2','2','0',1,7); +delete from m1 using t1 m1,t1 m2 where m1.groupid=m2.groupid and (m1.cnt < m2.cnt or m1.cnt=m2.cnt and m1.F3>m2.F3); +select * from t1; +F1 F2 F3 cnt groupid +0 0 0 1 6 +0 1 2 1 5 +0 2 0 1 3 +1 0 1 1 2 +1 2 1 1 1 +2 0 1 2 4 +2 2 0 1 7 +drop table t1; +CREATE TABLE t1 ( +`colA` int(10) unsigned NOT NULL auto_increment, +`colB` int(11) NOT NULL default '0', +PRIMARY KEY (`colA`) +); +INSERT INTO t1 VALUES (4433,5424); +CREATE TABLE t2 ( +`colC` int(10) unsigned NOT NULL default '0', +`colA` int(10) unsigned NOT NULL default '0', +`colD` int(10) unsigned NOT NULL default '0', +`colE` int(10) unsigned NOT NULL default '0', +`colF` int(10) unsigned NOT NULL default '0', +PRIMARY KEY (`colC`,`colA`,`colD`,`colE`) +); +INSERT INTO t2 VALUES (3,4433,10005,495,500); +INSERT INTO t2 VALUES (3,4433,10005,496,500); +INSERT INTO t2 VALUES (3,4433,10009,494,500); +INSERT INTO t2 VALUES (3,4433,10011,494,500); +INSERT INTO t2 VALUES (3,4433,10005,497,500); +INSERT INTO t2 VALUES (3,4433,10013,489,500); +INSERT INTO t2 VALUES (3,4433,10005,494,500); +INSERT INTO t2 VALUES (3,4433,10005,493,500); +INSERT INTO t2 VALUES (3,4433,10005,492,500); +UPDATE IGNORE t2,t1 set t2.colE = t2.colE + 1,colF=0 WHERE t1.colA = t2.colA AND (t1.colB & 4096) > 0 AND (colE + 1) < colF; +SELECT * FROM t2; +colC colA colD colE colF +3 4433 10005 495 500 +3 4433 10005 496 500 +3 4433 10009 495 0 +3 4433 10011 495 0 +3 4433 10005 498 0 +3 4433 10013 490 0 +3 4433 10005 494 500 +3 4433 10005 493 500 +3 4433 10005 492 500 +DROP TABLE t1; +DROP TABLE t2; +create table t1 (c1 int, c2 char(6), c3 int); +create table t2 (c1 int, c2 char(6)); +insert into t1 values (1, "t1c2-1", 10), (2, "t1c2-2", 20); +update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1"; +update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1" where t1.c3 = 10; +drop table t1, t2; +create table t1 (id int not null auto_increment primary key, id_str varchar(32)); +insert into t1 (id_str) values ("test"); +update t1 set id_str = concat(id_str, id) where id = last_insert_id(); +select * from t1; +id id_str +1 test1 +drop table t1; +create table t1 (a int, b char(255), key(a, b(20))); +insert into t1 values (0, '1'); +update t1 set b = b + 1 where a = 0; +select * from t1; +a b +0 2 +drop table t1; +create table t1 (a int, b varchar(10), key b(b(5))) engine=myisam; +create table t2 (a int, b varchar(10)) engine=myisam; +insert into t1 values ( 1, 'abcd1e'); +insert into t1 values ( 2, 'abcd2e'); +insert into t2 values ( 1, 'abcd1e'); +insert into t2 values ( 2, 'abcd2e'); +analyze table t1,t2; +Table Op Msg_type Msg_text +test.t1 analyze status OK +test.t2 analyze status OK +update t1, t2 set t1.a = t2.a where t2.b = t1.b; +show warnings; +Level Code Message +drop table t1, t2; +create table t1(f1 int, f2 int); +create table t2(f3 int, f4 int); +create index idx on t2(f3); +insert into t1 values(1,0),(2,0); +insert into t2 values(1,1),(2,2); +UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); +select * from t1; +f1 f2 +1 1 +2 2 +drop table t1,t2; +create table t1(f1 int); +select DATABASE(); +DATABASE() +test +update t1 set f1=1 where count(*)=1; +ERROR HY000: Invalid use of group function +select DATABASE(); +DATABASE() +test +delete from t1 where count(*)=1; +ERROR HY000: Invalid use of group function +drop table t1; +create table t1 ( a int, b int default 0, index (a) ); +insert into t1 (a) values (0),(0),(0),(0),(0),(0),(0),(0); +flush status; +select a from t1 order by a limit 1; +a +0 +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +flush status; +update t1 set a=9999 order by a limit 1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +update t1 set b=9999 order by a desc limit 1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +flush status; +delete from t1 order by a limit 1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +flush status; +delete from t1 order by a desc limit 1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +alter table t1 disable keys; +Warnings: +Note 1031 Table storage engine for 't1' doesn't have this option +flush status; +delete from t1 order by a limit 1; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +select * from t1; +a b +0 0 +0 0 +0 0 +0 0 +0 0 +update t1 set a=a+10,b=1 order by a limit 3; +update t1 set a=a+11,b=2 order by a limit 3; +update t1 set a=a+12,b=3 order by a limit 3; +select * from t1 order by a; +a b +11 2 +21 2 +22 3 +22 3 +23 3 +drop table t1; +create table t1 (f1 date not null); +insert into t1 values('2000-01-01'),('0000-00-00'); +update t1 set f1='2002-02-02' where f1 is null; +select * from t1; +f1 +2000-01-01 +2002-02-02 +drop table t1; +create table t1 (f1 int); +create table t2 (f2 int); +insert into t1 values(1),(2); +insert into t2 values(1),(1); +update t1,t2 set f1=3,f2=3 where f1=f2 and f1=1; +affected rows: 3 +info: Rows matched: 3 Changed: 3 Warnings: 0 +update t2 set f2=1; +update t1 set f1=1 where f1=3; +update t2,t1 set f1=3,f2=3 where f1=f2 and f1=1; +affected rows: 3 +info: Rows matched: 3 Changed: 3 Warnings: 0 +drop table t1,t2; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, filler1 char(200), filler2 char(200), key(a)); +insert into t2 select A.a + 10*B.a, 'filler','filler' from t1 A, t1 B; +flush status; +update t2 set a=3 where a=2; +show status like 'handler_read%'; +Variable_name Value +Handler_read_first 0 +Handler_read_key 0 +Handler_read_next 0 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 0 +drop table t1, t2; +create table t1(f1 int, `*f2` int); +insert into t1 values (1,1); +update t1 set `*f2`=1; +drop table t1; diff --git a/mysql-test/suite/pbxt/r/user_var.result b/mysql-test/suite/pbxt/r/user_var.result new file mode 100644 index 00000000000..f932ba4d86b --- /dev/null +++ b/mysql-test/suite/pbxt/r/user_var.result @@ -0,0 +1,319 @@ +drop table if exists t1,t2; +set @a := foo; +ERROR 42S22: Unknown column 'foo' in 'field list' +set @a := connection_id() + 3; +select @a - connection_id(); +@a - connection_id() +3 +set @b := 1; +select @b; +@b +1 +CREATE TABLE t1 ( i int not null, v int not null,index (i)); +insert into t1 values (1,1),(1,3),(2,1); +create table t2 (i int not null, unique (i)); +insert into t2 select distinct i from t1; +select * from t2; +i +1 +2 +select distinct t2.i,@vv1:=if(sv1.i,1,0),@vv2:=if(sv2.i,1,0),@vv3:=if(sv3.i,1,0), @vv1+@vv2+@vv3 from t2 left join t1 as sv1 on sv1.i=t2.i and sv1.v=1 left join t1 as sv2 on sv2.i=t2.i and sv2.v=2 left join t1 as sv3 on sv3.i=t2.i and sv3.v=3; +i @vv1:=if(sv1.i,1,0) @vv2:=if(sv2.i,1,0) @vv3:=if(sv3.i,1,0) @vv1+@vv2+@vv3 +1 1 0 1 2 +2 1 0 0 1 +explain select * from t1 where i=@vv1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref i i 4 const 1 +select @vv1,i,v from t1 where i=@vv1; +@vv1 i v +1 1 1 +1 1 3 +explain select * from t1 where @vv1:=@vv1+1 and i=@vv1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +explain select @vv1:=i from t1 where i=@vv1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL i 4 NULL 3 Using where; Using index +explain select * from t1 where i=@vv1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref i i 4 const 1 +drop table t1,t2; +set @a=0,@b=0; +select @a:=10, @b:=1, @a > @b, @a < @b; +@a:=10 @b:=1 @a > @b @a < @b +10 1 1 0 +select @a:="10", @b:="1", @a > @b, @a < @b; +@a:="10" @b:="1" @a > @b @a < @b +10 1 1 0 +select @a:=10, @b:=2, @a > @b, @a < @b; +@a:=10 @b:=2 @a > @b @a < @b +10 2 0 1 +select @a:="10", @b:="2", @a > @b, @a < @b; +@a:="10" @b:="2" @a > @b @a < @b +10 2 1 0 +select @a:=1; +@a:=1 +1 +select @a, @a:=1; +@a @a:=1 +1 1 +create table t1 (id int, d double, c char(10)); +insert into t1 values (1,2.0, "test"); +select @c:=0; +@c:=0 +0 +update t1 SET id=(@c:=@c+1); +select @c; +@c +1 +select @c:=0; +@c:=0 +0 +update t1 set id=(@c:=@c+1); +select @c; +@c +1 +select @c:=0; +@c:=0 +0 +select @c:=@c+1; +@c:=@c+1 +1 +select @d,(@d:=id),@d from t1; +@d (@d:=id) @d +NULL 1 1 +select @e,(@e:=d),@e from t1; +@e (@e:=d) @e +NULL 2 2 +select @f,(@f:=c),@f from t1; +@f (@f:=c) @f +NULL test test +set @g=1; +select @g,(@g:=c),@g from t1; +@g (@g:=c) @g +1 test 0 +select @c, @d, @e, @f; +@c @d @e @f +1 1 2 test +select @d:=id, @e:=id, @f:=id, @g:=@id from t1; +@d:=id @e:=id @f:=id @g:=@id +1 1 1 NULL +select @c, @d, @e, @f, @g; +@c @d @e @f @g +1 1 1 1 NULL +drop table t1; +select @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b, @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b; +@a:=10 @b:=2 @a>@b @a:="10" @b:="2" @a>@b @a:=10 @b:=2 @a>@b @a:="10" @b:="2" @a>@b +10 2 1 10 2 1 10 2 1 10 2 1 +create table t1 (i int not null); +insert t1 values (1),(2),(2),(3),(3),(3); +select @a:=0; +@a:=0 +0 +select @a, @a:=@a+count(*), count(*), @a from t1 group by i; +@a @a:=@a+count(*) count(*) @a +0 1 1 0 +0 2 2 0 +0 3 3 0 +select @a:=0; +@a:=0 +0 +select @a+0, @a:=@a+0+count(*), count(*), @a+0 from t1 group by i; +@a+0 @a:=@a+0+count(*) count(*) @a+0 +0 1 1 0 +0 2 2 0 +0 3 3 0 +set @a=0; +select @a,@a:="hello",@a,@a:=3,@a,@a:="hello again" from t1 group by i; +@a @a:="hello" @a @a:=3 @a @a:="hello again" +0 hello 0 3 0 hello again +0 hello 0 3 0 hello again +0 hello 0 3 0 hello again +select @a,@a:="hello",@a,@a:=3,@a,@a:="hello again" from t1 group by i; +@a @a:="hello" @a @a:=3 @a @a:="hello again" +hello again hello hello again 3 hello again hello again +hello again hello hello again 3 hello again hello again +hello again hello hello again 3 hello again hello again +drop table t1; +set @a=_latin2'test'; +select charset(@a),collation(@a),coercibility(@a); +charset(@a) collation(@a) coercibility(@a) +latin2 latin2_general_ci 2 +select @a=_latin2'TEST'; +@a=_latin2'TEST' +1 +select @a=_latin2'TEST' collate latin2_bin; +@a=_latin2'TEST' collate latin2_bin +0 +set @a=_latin2'test' collate latin2_general_ci; +select charset(@a),collation(@a),coercibility(@a); +charset(@a) collation(@a) coercibility(@a) +latin2 latin2_general_ci 2 +select @a=_latin2'TEST'; +@a=_latin2'TEST' +1 +select @a=_latin2'TEST' collate latin2_bin; +@a=_latin2'TEST' collate latin2_bin +0 +select charset(@a:=_latin2'test'); +charset(@a:=_latin2'test') +latin2 +select collation(@a:=_latin2'test'); +collation(@a:=_latin2'test') +latin2_general_ci +select coercibility(@a:=_latin2'test'); +coercibility(@a:=_latin2'test') +2 +select collation(@a:=_latin2'test' collate latin2_bin); +collation(@a:=_latin2'test' collate latin2_bin) +latin2_bin +select coercibility(@a:=_latin2'test' collate latin2_bin); +coercibility(@a:=_latin2'test' collate latin2_bin) +2 +select (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST'; +(@a:=_latin2'test' collate latin2_bin) = _latin2'TEST' +0 +select charset(@a),collation(@a),coercibility(@a); +charset(@a) collation(@a) coercibility(@a) +latin2 latin2_bin 2 +select (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST' collate latin2_general_ci; +(@a:=_latin2'test' collate latin2_bin) = _latin2'TEST' collate latin2_general_ci +1 +set @var= NULL ; +select FIELD( @var,'1it','Hit') as my_column; +my_column +0 +select @v, coercibility(@v); +@v coercibility(@v) +NULL 2 +set @v1=null, @v2=1, @v3=1.1, @v4=now(); +select coercibility(@v1),coercibility(@v2),coercibility(@v3),coercibility(@v4); +coercibility(@v1) coercibility(@v2) coercibility(@v3) coercibility(@v4) +2 2 2 2 +set session @honk=99; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@honk=99' at line 1 +set one_shot @honk=99; +ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server +select @@local.max_allowed_packet; +@@local.max_allowed_packet +# +select @@session.max_allowed_packet; +@@session.max_allowed_packet +# +select @@global.max_allowed_packet; +@@global.max_allowed_packet +# +select @@max_allowed_packet; +@@max_allowed_packet +# +select @@Max_Allowed_Packet; +@@Max_Allowed_Packet +# +select @@version; +@@version +# +select @@global.version; +@@global.version +# +End of 4.1 tests +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longblob +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= cast(NULL as signed integer); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` bigint(20) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` bigint(20) DEFAULT NULL +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= concat(NULL); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longblob +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +set @first_var=1; +set @first_var= cast(NULL as CHAR); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longtext +) ENGINE=PBXT DEFAULT CHARSET=latin1 +drop table t1; +set @a=18446744071710965857; +select @a; +@a +18446744071710965857 +CREATE TABLE `bigfailure` ( +`afield` BIGINT UNSIGNED NOT NULL +); +INSERT INTO `bigfailure` VALUES (18446744071710965857); +SELECT * FROM bigfailure; +afield +18446744071710965857 +select * from (SELECT afield FROM bigfailure) as b; +afield +18446744071710965857 +select * from bigfailure where afield = (SELECT afield FROM bigfailure); +afield +18446744071710965857 +select * from bigfailure where afield = 18446744071710965857; +afield +18446744071710965857 +select * from bigfailure where afield = 18446744071710965856+1; +afield +18446744071710965857 +SET @a := (SELECT afield FROM bigfailure); +SELECT @a; +@a +18446744071710965857 +SET @a := (select afield from (SELECT afield FROM bigfailure) as b); +SELECT @a; +@a +18446744071710965857 +SET @a := (select * from bigfailure where afield = (SELECT afield FROM bigfailure)); +SELECT @a; +@a +18446744071710965857 +drop table bigfailure; +create table t1(f1 int, f2 int); +insert into t1 values (1,2),(2,3),(3,1); +select @var:=f2 from t1 group by f1 order by f2 desc limit 1; +@var:=f2 +3 +select @var; +@var +3 +create table t2 as select @var:=f2 from t1 group by f1 order by f2 desc limit 1; +select * from t2; +@var:=f2 +3 +select @var; +@var +3 +drop table t1,t2; +insert into city 'blah'; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''blah'' at line 1 +SHOW COUNT(*) WARNINGS; +@@session.warning_count +1 +SHOW COUNT(*) ERRORS; +@@session.error_count +1 diff --git a/mysql-test/suite/pbxt/r/view_grant.result b/mysql-test/suite/pbxt/r/view_grant.result new file mode 100644 index 00000000000..0847967eb87 --- /dev/null +++ b/mysql-test/suite/pbxt/r/view_grant.result @@ -0,0 +1,958 @@ +drop database if exists mysqltest; +drop view if exists v1,v2,v3; +grant create view on test.* to test@localhost; +show grants for test@localhost; +Grants for test@localhost +GRANT USAGE ON *.* TO 'test'@'localhost' +GRANT CREATE VIEW ON `test`.* TO 'test'@'localhost' +revoke create view on test.* from test@localhost; +show grants for test@localhost; +Grants for test@localhost +GRANT USAGE ON *.* TO 'test'@'localhost' +drop user test@localhost; +create database mysqltest; +create table mysqltest.t1 (a int, b int); +create table mysqltest.t2 (a int, b int); +grant select on mysqltest.t1 to mysqltest_1@localhost; +grant create view,select on test.* to mysqltest_1@localhost; +create definer=root@localhost view v1 as select * from mysqltest.t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +create view v1 as select * from mysqltest.t1; +alter view v1 as select * from mysqltest.t1; +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1' +create or replace view v1 as select * from mysqltest.t1; +ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1' +create view mysqltest.v2 as select * from mysqltest.t1; +ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2' +create view v2 as select * from mysqltest.t2; +ERROR 42000: ANY command denied to user 'mysqltest_1'@'localhost' for table 't2' +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_1`@`localhost` SQL SECURITY DEFINER VIEW `test`.`v1` AS select `mysqltest`.`t1`.`a` AS `a`,`mysqltest`.`t1`.`b` AS `b` from `mysqltest`.`t1` latin1 latin1_swedish_ci +grant create view,drop,select on test.* to mysqltest_1@localhost; +use test; +alter view v1 as select * from mysqltest.t1; +create or replace view v1 as select * from mysqltest.t1; +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +revoke all privileges on test.* from mysqltest_1@localhost; +drop database mysqltest; +drop view test.v1; +create database mysqltest; +create table mysqltest.t1 (a int, b int); +create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; +grant select (c) on mysqltest.v1 to mysqltest_1@localhost; +select c from mysqltest.v1; +c +select d from mysqltest.v1; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'd' in table 'v1' +revoke all privileges on mysqltest.v1 from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +drop database mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int, b int); +create algorithm=temptable view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; +grant select (c) on mysqltest.v1 to mysqltest_1@localhost; +select c from mysqltest.v1; +c +select d from mysqltest.v1; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'd' in table 'v1' +revoke all privileges on mysqltest.v1 from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +drop database mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int, b int); +create table mysqltest.t2 (a int, b int); +create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; +create algorithm=temptable view mysqltest.v2 (c,d) as select a+1,b+1 from mysqltest.t1; +create view mysqltest.v3 (c,d) as select a+1,b+1 from mysqltest.t2; +create algorithm=temptable view mysqltest.v4 (c,d) as select a+1,b+1 from mysqltest.t2; +grant select on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.v2 to mysqltest_1@localhost; +grant select on mysqltest.v3 to mysqltest_1@localhost; +grant select on mysqltest.v4 to mysqltest_1@localhost; +select c from mysqltest.v1; +c +select c from mysqltest.v2; +c +select c from mysqltest.v3; +c +select c from mysqltest.v4; +c +show columns from mysqltest.v1; +Field Type Null Key Default Extra +c bigint(12) YES NULL +d bigint(12) YES NULL +show columns from mysqltest.v2; +Field Type Null Key Default Extra +c bigint(12) YES NULL +d bigint(12) YES NULL +explain select c from mysqltest.v1; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +show create view mysqltest.v1; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' +explain select c from mysqltest.v2; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +show create view mysqltest.v2; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2' +explain select c from mysqltest.v3; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +show create view mysqltest.v3; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v3' +explain select c from mysqltest.v4; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +show create view mysqltest.v4; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v4' +grant select on mysqltest.t1 to mysqltest_1@localhost; +explain select c from mysqltest.v1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 0 +show create view mysqltest.v1; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' +explain select c from mysqltest.v2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found +2 DERIVED t1 ALL NULL NULL NULL NULL 0 +show create view mysqltest.v2; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2' +explain select c from mysqltest.v3; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +show create view mysqltest.v3; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v3' +explain select c from mysqltest.v4; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +show create view mysqltest.v4; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v4' +grant show view on mysqltest.* to mysqltest_1@localhost; +explain select c from mysqltest.v1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 0 +show create view mysqltest.v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v1` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` latin1 latin1_swedish_ci +explain select c from mysqltest.v2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found +2 DERIVED t1 ALL NULL NULL NULL NULL 0 +show create view mysqltest.v2; +View Create View character_set_client collation_connection +v2 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1` latin1 latin1_swedish_ci +explain select c from mysqltest.v3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 0 +show create view mysqltest.v3; +View Create View character_set_client collation_connection +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v3` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` latin1 latin1_swedish_ci +explain select c from mysqltest.v4; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found +2 DERIVED t2 ALL NULL NULL NULL NULL 0 +show create view mysqltest.v4; +View Create View character_set_client collation_connection +v4 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v4` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2` latin1 latin1_swedish_ci +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +drop database mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int, b int, primary key(a)); +insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10); +create table mysqltest.t2 (x int); +insert into mysqltest.t2 values (3), (4), (5), (6); +create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; +create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; +create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1; +grant update (a) on mysqltest.v2 to mysqltest_1@localhost; +grant update on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.* to mysqltest_1@localhost; +use mysqltest; +update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.c; +select * from t1 order by a; +a b +13 2 +24 3 +35 4 +46 5 +50 10 +update v1 set a=a+c; +select * from t1 order by a; +a b +16 2 +28 3 +40 4 +52 5 +61 10 +update t2,v2 set v2.a=v2.a+v2.c where t2.x=v2.c; +select * from t1 order by a; +a b +16 2 +31 3 +44 4 +57 5 +61 10 +update v2 set a=a+c; +select * from t1 order by a; +a b +18 2 +34 3 +48 4 +62 5 +71 10 +update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c; +ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for column 'c' in table 'v2' +update v2 set c=a+c; +ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for column 'c' in table 'v2' +update t2,v3 set v3.a=v3.a+v3.c where t2.x=v3.c; +ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for table 'v3' +update v3 set a=a+c; +ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for table 'v3' +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int, b int, primary key(a)); +insert into mysqltest.t1 values (1,2), (2,3), (3,4), (4,5), (5,10); +create table mysqltest.t2 (x int); +insert into mysqltest.t2 values (3), (4), (5), (6); +create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; +create view mysqltest.v2 (a,c) as select a, b+1 from mysqltest.t1; +grant delete on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.* to mysqltest_1@localhost; +use mysqltest; +delete from v1 where c < 4; +select * from t1; +a b +2 3 +3 4 +4 5 +5 10 +delete v1 from t2,v1 where t2.x=v1.c; +select * from t1; +a b +5 10 +delete v2 from t2,v2 where t2.x=v2.c; +ERROR 42000: DELETE command denied to user 'mysqltest_1'@'localhost' for table 'v2' +delete from v2 where c < 4; +ERROR 42000: DELETE command denied to user 'mysqltest_1'@'localhost' for table 'v2' +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int, b int, primary key(a)); +insert into mysqltest.t1 values (1,2), (2,3); +create table mysqltest.t2 (x int, y int); +insert into mysqltest.t2 values (3,4); +create view mysqltest.v1 (a,c) as select a, b from mysqltest.t1; +create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; +grant insert on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.* to mysqltest_1@localhost; +use mysqltest; +insert into v1 values (5,6); +select * from t1; +a b +1 2 +2 3 +5 6 +insert into v1 select x,y from t2; +select * from t1; +a b +1 2 +2 3 +5 6 +3 4 +insert into v2 values (5,6); +ERROR 42000: INSERT command denied to user 'mysqltest_1'@'localhost' for table 'v2' +insert into v2 select x,y from t2; +ERROR 42000: INSERT command denied to user 'mysqltest_1'@'localhost' for table 'v2' +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int, b int); +create table mysqltest.t2 (a int, b int); +grant update on mysqltest.t1 to mysqltest_1@localhost; +grant update(b) on mysqltest.t2 to mysqltest_1@localhost; +grant create view,update on test.* to mysqltest_1@localhost; +create view v1 as select * from mysqltest.t1; +create view v2 as select b from mysqltest.t2; +create view mysqltest.v1 as select * from mysqltest.t1; +ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' +create view v3 as select a from mysqltest.t2; +ERROR 42000: ANY command denied to user 'mysqltest_1'@'localhost' for column 'a' in table 't2' +create table mysqltest.v3 (b int); +grant create view on mysqltest.v3 to mysqltest_1@localhost; +drop table mysqltest.v3; +create view mysqltest.v3 as select b from mysqltest.t2; +grant create view, update on mysqltest.v3 to mysqltest_1@localhost; +drop view mysqltest.v3; +create view mysqltest.v3 as select b from mysqltest.t2; +create view v4 as select b+1 from mysqltest.t2; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 't2' +grant create view,update,select on test.* to mysqltest_1@localhost; +create view v4 as select b+1 from mysqltest.t2; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 't2' +grant update,select(b) on mysqltest.t2 to mysqltest_1@localhost; +create view v4 as select b+1 from mysqltest.t2; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +drop view v1,v2,v4; +create database mysqltest; +create table mysqltest.t1 (a int); +grant all privileges on mysqltest.* to mysqltest_1@localhost; +use mysqltest; +create view v1 as select * from t1; +use test; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +drop database mysqltest; +create database mysqltest; +create table mysqltest.t1 (a int, b int); +grant select on mysqltest.t1 to mysqltest_1@localhost; +grant create view,select on test.* to mysqltest_1@localhost; +create view v1 as select * from mysqltest.t1; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_1`@`localhost` SQL SECURITY DEFINER VIEW `test`.`v1` AS select `mysqltest`.`t1`.`a` AS `a`,`mysqltest`.`t1`.`b` AS `b` from `mysqltest`.`t1` latin1 latin1_swedish_ci +revoke select on mysqltest.t1 from mysqltest_1@localhost; +select * from v1; +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +grant select on mysqltest.t1 to mysqltest_1@localhost; +select * from v1; +a b +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop view v1; +drop database mysqltest; +create database mysqltest; +use mysqltest; +create table t1 (a int); +insert into t1 values (1); +create table t2 (s1 int); +drop function if exists f2; +create function f2 () returns int begin declare v int; select s1 from t2 +into v; return v; end// +create algorithm=TEMPTABLE view v1 as select f2() from t1; +create algorithm=MERGE view v2 as select f2() from t1; +create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1; +create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1; +create SQL SECURITY INVOKER view v5 as select * from v4; +grant select on v1 to mysqltest_1@localhost; +grant select on v2 to mysqltest_1@localhost; +grant select on v3 to mysqltest_1@localhost; +grant select on v4 to mysqltest_1@localhost; +grant select on v5 to mysqltest_1@localhost; +use mysqltest; +select * from v1; +f2() +NULL +Warnings: +Warning 1329 No data - zero rows fetched, selected, or processed +select * from v2; +f2() +NULL +Warnings: +Warning 1329 No data - zero rows fetched, selected, or processed +select * from v3; +ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +select * from v4; +ERROR HY000: View 'mysqltest.v4' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +select * from v5; +ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +use test; +drop view v1, v2, v3, v4, v5; +drop function f2; +drop table t1, t2; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +create database mysqltest; +use mysqltest; +create table t1 (a int); +insert into t1 values (1); +create table t2 (s1 int); +drop function if exists f2; +create function f2 () returns int begin declare v int; select s1 from t2 +into v; return v; end// +grant select on t1 to mysqltest_1@localhost; +grant execute on function f2 to mysqltest_1@localhost; +grant create view on mysqltest.* to mysqltest_1@localhost; +use mysqltest; +create algorithm=TEMPTABLE view v1 as select f2() from t1; +create algorithm=MERGE view v2 as select f2() from t1; +create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1; +create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1; +use test; +create view v5 as select * from v1; +revoke execute on function f2 from mysqltest_1@localhost; +select * from v1; +ERROR HY000: View 'mysqltest.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +select * from v2; +ERROR HY000: View 'mysqltest.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +select * from v3; +f2() +NULL +Warnings: +Warning 1329 No data - zero rows fetched, selected, or processed +select * from v4; +f2() +NULL +Warnings: +Warning 1329 No data - zero rows fetched, selected, or processed +select * from v5; +ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +drop view v1, v2, v3, v4, v5; +drop function f2; +drop table t1, t2; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +create database mysqltest; +use mysqltest; +create table t1 (a int); +create table v1 (a int); +insert into t1 values (1); +grant select on t1 to mysqltest_1@localhost; +grant select on v1 to mysqltest_1@localhost; +grant create view on mysqltest.* to mysqltest_1@localhost; +drop table v1; +use mysqltest; +create algorithm=TEMPTABLE view v1 as select *, a as b from t1; +create algorithm=MERGE view v2 as select *, a as b from t1; +create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1; +create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1; +create view v5 as select * from v1; +use test; +revoke select on t1 from mysqltest_1@localhost; +select * from v1; +ERROR HY000: View 'mysqltest.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +select * from v2; +ERROR HY000: View 'mysqltest.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +select * from v3; +a b +1 1 +select * from v4; +a b +1 1 +select * from v5; +ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +drop table t1; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +create database mysqltest; +use mysqltest; +create table t1 (a int); +insert into t1 values (1); +create algorithm=TEMPTABLE view v1 as select *, a as b from t1; +create algorithm=MERGE view v2 as select *, a as b from t1; +create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1; +create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1; +create SQL SECURITY INVOKER view v5 as select * from v4; +grant select on v1 to mysqltest_1@localhost; +grant select on v2 to mysqltest_1@localhost; +grant select on v3 to mysqltest_1@localhost; +grant select on v4 to mysqltest_1@localhost; +grant select on v5 to mysqltest_1@localhost; +use mysqltest; +select * from v1; +a b +1 1 +select * from v2; +a b +1 1 +select * from v3; +ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +select * from v4; +ERROR HY000: View 'mysqltest.v4' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +select * from v5; +ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +use test; +drop view v1, v2, v3, v4, v5; +drop table t1; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +drop view if exists v1; +create table t1 as select * from mysql.user where user=''; +delete from mysql.user where user=''; +flush privileges; +grant all on test.* to 'test14256'@'%'; +use test; +create view v1 as select 42; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`test14256`@`%` SQL SECURITY DEFINER VIEW `v1` AS select 42 AS `42` latin1 latin1_swedish_ci +select definer into @v1def1 from information_schema.views +where table_schema = 'test' and table_name='v1'; +drop view v1; +create definer=`test14256`@`%` view v1 as select 42; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`test14256`@`%` SQL SECURITY DEFINER VIEW `v1` AS select 42 AS `42` latin1 latin1_swedish_ci +select definer into @v1def2 from information_schema.views +where table_schema = 'test' and table_name='v1'; +drop view v1; +select @v1def1, @v1def2, @v1def1=@v1def2; +@v1def1 @v1def2 @v1def1=@v1def2 +test14256@% test14256@% 1 +drop user test14256; +insert into mysql.user select * from t1; +flush privileges; +drop table t1; +create database mysqltest; +use mysqltest; +CREATE TABLE t1 (i INT); +CREATE VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci +GRANT SELECT, LOCK TABLES ON mysqltest.* TO mysqltest_1@localhost; +use mysqltest; +LOCK TABLES v1 READ; +SHOW CREATE TABLE v1; +ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1' +UNLOCK TABLES; +use test; +use test; +drop user mysqltest_1@localhost; +drop database mysqltest; +create definer=some_user@`` sql security invoker view v1 as select 1; +Warnings: +Note 1449 The user specified as a definer ('some_user'@'') does not exist +create definer=some_user@localhost sql security invoker view v2 as select 1; +Warnings: +Note 1449 The user specified as a definer ('some_user'@'localhost') does not exist +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` latin1 latin1_swedish_ci +show create view v2; +View Create View character_set_client collation_connection +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select 1 AS `1` latin1 latin1_swedish_ci +drop view v1; +drop view v2; +CREATE DATABASE mysqltest1; +CREATE USER readonly@localhost; +CREATE TABLE mysqltest1.t1 (x INT); +INSERT INTO mysqltest1.t1 VALUES (1), (2); +CREATE SQL SECURITY INVOKER VIEW mysqltest1.v_t1 AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ts AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ti AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tu AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tus AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_td AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tds AS SELECT * FROM mysqltest1.t1; +GRANT SELECT, INSERT, UPDATE, DELETE ON mysqltest1.v_t1 TO readonly@localhost; +GRANT SELECT ON mysqltest1.v_ts TO readonly@localhost; +GRANT INSERT ON mysqltest1.v_ti TO readonly@localhost; +GRANT UPDATE ON mysqltest1.v_tu TO readonly@localhost; +GRANT UPDATE,SELECT ON mysqltest1.v_tus TO readonly@localhost; +GRANT DELETE ON mysqltest1.v_td TO readonly@localhost; +GRANT DELETE,SELECT ON mysqltest1.v_tds TO readonly@localhost; +SELECT * FROM mysqltest1.v_t1; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +INSERT INTO mysqltest1.v_t1 VALUES(4); +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DELETE FROM mysqltest1.v_t1 WHERE x = 1; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +UPDATE mysqltest1.v_t1 SET x = 3 WHERE x = 2; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +UPDATE mysqltest1.v_t1 SET x = 3; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DELETE FROM mysqltest1.v_t1; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SELECT 1 FROM mysqltest1.v_t1; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SELECT * FROM mysqltest1.t1; +ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 't1' +SELECT * FROM mysqltest1.v_ts; +x +1 +2 +SELECT * FROM mysqltest1.v_ts, mysqltest1.t1 WHERE mysqltest1.t1.x = mysqltest1.v_ts.x; +ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 't1' +SELECT * FROM mysqltest1.v_ti; +ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 'v_ti' +INSERT INTO mysqltest1.v_ts VALUES (100); +ERROR 42000: INSERT command denied to user 'readonly'@'localhost' for table 'v_ts' +INSERT INTO mysqltest1.v_ti VALUES (100); +UPDATE mysqltest1.v_ts SET x= 200 WHERE x = 100; +ERROR 42000: UPDATE command denied to user 'readonly'@'localhost' for table 'v_ts' +UPDATE mysqltest1.v_ts SET x= 200; +ERROR 42000: UPDATE command denied to user 'readonly'@'localhost' for table 'v_ts' +UPDATE mysqltest1.v_tu SET x= 200 WHERE x = 100; +UPDATE mysqltest1.v_tus SET x= 200 WHERE x = 100; +UPDATE mysqltest1.v_tu SET x= 200; +DELETE FROM mysqltest1.v_ts WHERE x= 200; +ERROR 42000: DELETE command denied to user 'readonly'@'localhost' for table 'v_ts' +DELETE FROM mysqltest1.v_ts; +ERROR 42000: DELETE command denied to user 'readonly'@'localhost' for table 'v_ts' +DELETE FROM mysqltest1.v_td WHERE x= 200; +ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for column 'x' in table 'v_td' +DELETE FROM mysqltest1.v_tds WHERE x= 200; +DELETE FROM mysqltest1.v_td; +DROP VIEW mysqltest1.v_tds; +DROP VIEW mysqltest1.v_td; +DROP VIEW mysqltest1.v_tus; +DROP VIEW mysqltest1.v_tu; +DROP VIEW mysqltest1.v_ti; +DROP VIEW mysqltest1.v_ts; +DROP VIEW mysqltest1.v_t1; +DROP TABLE mysqltest1.t1; +DROP USER readonly@localhost; +DROP DATABASE mysqltest1; +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1), (2), (3); +CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1; +Warnings: +Note 1449 The user specified as a definer ('no-such-user'@'localhost') does not exist +SHOW CREATE VIEW v; +View Create View character_set_client collation_connection +v CREATE ALGORITHM=UNDEFINED DEFINER=`no-such-user`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `test`.`t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'test.v' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SELECT * FROM v; +ERROR HY000: The user specified as a definer ('no-such-user'@'localhost') does not exist +DROP VIEW v; +DROP TABLE t1; +USE test; +CREATE USER mysqltest_db1@localhost identified by 'PWD'; +GRANT ALL ON mysqltest_db1.* TO mysqltest_db1@localhost WITH GRANT OPTION; +CREATE SCHEMA mysqltest_db1 ; +USE mysqltest_db1 ; +CREATE TABLE t1 (f1 INTEGER); +CREATE VIEW view1 AS +SELECT * FROM t1; +SHOW CREATE VIEW view1; +View Create View character_set_client collation_connection +view1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_db1`@`localhost` SQL SECURITY DEFINER VIEW `view1` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci +CREATE VIEW view2 AS +SELECT * FROM view1; +# Here comes a suspicious warning +SHOW CREATE VIEW view2; +View Create View character_set_client collation_connection +view2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqltest_db1`@`localhost` SQL SECURITY DEFINER VIEW `view2` AS select `view1`.`f1` AS `f1` from `view1` latin1 latin1_swedish_ci +# But the view view2 is usable +SELECT * FROM view2; +f1 +CREATE VIEW view3 AS +SELECT * FROM view2; +SELECT * from view3; +f1 +DROP VIEW mysqltest_db1.view3; +DROP VIEW mysqltest_db1.view2; +DROP VIEW mysqltest_db1.view1; +DROP TABLE mysqltest_db1.t1; +DROP SCHEMA mysqltest_db1; +DROP USER mysqltest_db1@localhost; +CREATE DATABASE test1; +CREATE DATABASE test2; +CREATE TABLE test1.t0 (a VARCHAR(20)) engine=myisam; +CREATE TABLE test2.t1 (a VARCHAR(20)); +CREATE VIEW test2.t3 AS SELECT * FROM test1.t0; +CREATE OR REPLACE VIEW test.v1 AS +SELECT ta.a AS col1, tb.a AS col2 FROM test2.t3 ta, test2.t1 tb; +DROP VIEW test.v1; +DROP VIEW test2.t3; +DROP TABLE test2.t1, test1.t0; +DROP DATABASE test2; +DROP DATABASE test1; +DROP VIEW IF EXISTS v1; +DROP VIEW IF EXISTS v2; +DROP VIEW IF EXISTS v3; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP PROCEDURE IF EXISTS p1; +CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT CURRENT_USER() AS cu; +CREATE FUNCTION f1() RETURNS VARCHAR(77) SQL SECURITY INVOKER +RETURN CURRENT_USER(); +CREATE SQL SECURITY DEFINER VIEW v2 AS SELECT f1() AS cu; +CREATE PROCEDURE p1(OUT cu VARCHAR(77)) SQL SECURITY INVOKER +SET cu= CURRENT_USER(); +CREATE FUNCTION f2() RETURNS VARCHAR(77) SQL SECURITY INVOKER +BEGIN +DECLARE cu VARCHAR(77); +CALL p1(cu); +RETURN cu; +END| +CREATE SQL SECURITY DEFINER VIEW v3 AS SELECT f2() AS cu; +CREATE USER mysqltest_u1@localhost; +GRANT ALL ON test.* TO mysqltest_u1@localhost; + +The following tests should all return 1. + +SELECT CURRENT_USER() = 'mysqltest_u1@localhost'; +CURRENT_USER() = 'mysqltest_u1@localhost' +1 +SELECT f1() = 'mysqltest_u1@localhost'; +f1() = 'mysqltest_u1@localhost' +1 +CALL p1(@cu); +SELECT @cu = 'mysqltest_u1@localhost'; +@cu = 'mysqltest_u1@localhost' +1 +SELECT f2() = 'mysqltest_u1@localhost'; +f2() = 'mysqltest_u1@localhost' +1 +SELECT cu = 'root@localhost' FROM v1; +cu = 'root@localhost' +1 +SELECT cu = 'root@localhost' FROM v2; +cu = 'root@localhost' +1 +SELECT cu = 'root@localhost' FROM v3; +cu = 'root@localhost' +1 +DROP VIEW v3; +DROP FUNCTION f2; +DROP PROCEDURE p1; +DROP FUNCTION f1; +DROP VIEW v2; +DROP VIEW v1; +DROP USER mysqltest_u1@localhost; +CREATE DATABASE db17254; +USE db17254; +CREATE TABLE t1 (f1 INT); +INSERT INTO t1 VALUES (10),(20); +CREATE USER def_17254@localhost; +GRANT SELECT ON db17254.* TO def_17254@localhost; +CREATE USER inv_17254@localhost; +GRANT SELECT ON db17254.t1 TO inv_17254@localhost; +GRANT CREATE VIEW ON db17254.* TO def_17254@localhost; +CREATE VIEW v1 AS SELECT * FROM t1; +DROP USER def_17254@localhost; +for a user +SELECT * FROM v1; +ERROR 42000: SELECT command denied to user 'inv_17254'@'localhost' for table 'v1' +for a superuser +SELECT * FROM v1; +ERROR HY000: The user specified as a definer ('def_17254'@'localhost') does not exist +DROP USER inv_17254@localhost; +DROP DATABASE db17254; +DROP DATABASE IF EXISTS mysqltest_db1; +DROP DATABASE IF EXISTS mysqltest_db2; +DROP USER mysqltest_u1; +DROP USER mysqltest_u2; +CREATE USER mysqltest_u1@localhost; +CREATE USER mysqltest_u2@localhost; +CREATE DATABASE mysqltest_db1; +CREATE DATABASE mysqltest_db2; +GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost WITH GRANT OPTION; +GRANT ALL ON mysqltest_db2.* TO mysqltest_u2@localhost; +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1); +CREATE VIEW v1 AS SELECT i FROM t1 WHERE 1 IN (SELECT * FROM t1); +CREATE TABLE t2 (s CHAR(7)); +INSERT INTO t2 VALUES ('public'); +GRANT SELECT ON v1 TO mysqltest_u2@localhost; +GRANT SELECT ON t2 TO mysqltest_u2@localhost; +SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; +i s +1 public +PREPARE stmt1 FROM "SELECT * FROM mysqltest_db1.t2"; +EXECUTE stmt1; +s +public +PREPARE stmt2 FROM "SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2"; +EXECUTE stmt2; +i s +1 public +REVOKE SELECT ON t2 FROM mysqltest_u2@localhost; +UPDATE t2 SET s = 'private' WHERE s = 'public'; +SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; +ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' +EXECUTE stmt1; +ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' +EXECUTE stmt2; +ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' +REVOKE ALL ON mysqltest_db1.* FROM mysqltest_u1@localhost; +REVOKE ALL ON mysqltest_db2.* FROM mysqltest_u2@localhost; +DROP DATABASE mysqltest_db1; +DROP DATABASE mysqltest_db2; +DROP USER mysqltest_u1@localhost; +DROP USER mysqltest_u2@localhost; +CREATE DATABASE db26813; +USE db26813; +CREATE TABLE t1(f1 INT, f2 INT); +CREATE VIEW v1 AS SELECT f1 FROM t1; +CREATE VIEW v2 AS SELECT f1 FROM t1; +CREATE VIEW v3 AS SELECT f1 FROM t1; +CREATE USER u26813@localhost; +GRANT DROP ON db26813.v1 TO u26813@localhost; +GRANT CREATE VIEW ON db26813.v2 TO u26813@localhost; +GRANT DROP, CREATE VIEW ON db26813.v3 TO u26813@localhost; +GRANT SELECT ON db26813.t1 TO u26813@localhost; +ALTER VIEW v1 AS SELECT f2 FROM t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +ALTER VIEW v2 AS SELECT f2 FROM t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +ALTER VIEW v3 AS SELECT f2 FROM t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +SHOW CREATE VIEW v3; +View Create View character_set_client collation_connection +v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci +DROP USER u26813@localhost; +DROP DATABASE db26813; +# +# Bug#29908: A user can gain additional access through the ALTER VIEW. +# +CREATE DATABASE mysqltest_29908; +USE mysqltest_29908; +CREATE TABLE t1(f1 INT, f2 INT); +CREATE USER u29908_1@localhost; +CREATE DEFINER = u29908_1@localhost VIEW v1 AS SELECT f1 FROM t1; +CREATE DEFINER = u29908_1@localhost SQL SECURITY INVOKER VIEW v2 AS +SELECT f1 FROM t1; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v1 TO u29908_1@localhost; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_1@localhost; +GRANT SELECT ON mysqltest_29908.t1 TO u29908_1@localhost; +CREATE USER u29908_2@localhost; +GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; +GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; +ALTER VIEW v1 AS SELECT f2 FROM t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +ALTER VIEW v2 AS SELECT f2 FROM t1; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +SHOW CREATE VIEW v2; +View Create View character_set_client collation_connection +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci +ALTER VIEW v1 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f2` AS `f2` from `t1` latin1 latin1_swedish_ci +ALTER VIEW v2 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v2; +View Create View character_set_client collation_connection +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f2` AS `f2` from `t1` latin1 latin1_swedish_ci +ALTER VIEW v1 AS SELECT f1 FROM t1; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci +ALTER VIEW v2 AS SELECT f1 FROM t1; +SHOW CREATE VIEW v2; +View Create View character_set_client collation_connection +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci +DROP USER u29908_1@localhost; +DROP USER u29908_2@localhost; +DROP DATABASE mysqltest_29908; +####################################################################### +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +CREATE TABLE mysqltest1.t1(c1 INT); +CREATE TABLE mysqltest1.t2(c2 INT); +CREATE TABLE mysqltest1.t3(c3 INT); +CREATE TABLE mysqltest1.t4(c4 INT); +INSERT INTO mysqltest1.t1 VALUES (11), (12), (13), (14); +INSERT INTO mysqltest1.t2 VALUES (21), (22), (23), (24); +INSERT INTO mysqltest1.t3 VALUES (31), (32), (33), (34); +INSERT INTO mysqltest1.t4 VALUES (41), (42), (43), (44); +GRANT SELECT ON mysqltest1.t1 TO mysqltest_u1@localhost; +GRANT INSERT ON mysqltest1.t2 TO mysqltest_u1@localhost; +GRANT SELECT, UPDATE ON mysqltest1.t3 TO mysqltest_u1@localhost; +GRANT SELECT, DELETE ON mysqltest1.t4 TO mysqltest_u1@localhost; +GRANT ALL PRIVILEGES ON mysqltest2.* TO mysqltest_u1@localhost; + +---> connection: bug24040_con +SELECT * FROM mysqltest1.t1; +c1 +11 +12 +13 +14 +INSERT INTO mysqltest1.t2 VALUES(25); +UPDATE mysqltest1.t3 SET c3 = 331 WHERE c3 = 31; +DELETE FROM mysqltest1.t4 WHERE c4 = 44; +CREATE VIEW v1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v2 AS SELECT * FROM mysqltest1.t2; +CREATE VIEW v3 AS SELECT * FROM mysqltest1.t3; +CREATE VIEW v4 AS SELECT * FROM mysqltest1.t4; +SELECT * FROM v1; +c1 +11 +12 +13 +14 +INSERT INTO v2 VALUES(26); +UPDATE v3 SET c3 = 332 WHERE c3 = 32; +DELETE FROM v4 WHERE c4 = 43; +CREATE VIEW v12 AS SELECT c1, c2 FROM mysqltest1.t1, mysqltest1.t2; +ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v12' +CREATE VIEW v13 AS SELECT c1, c3 FROM mysqltest1.t1, mysqltest1.t3; +CREATE VIEW v14 AS SELECT c1, c4 FROM mysqltest1.t1, mysqltest1.t4; +CREATE VIEW v21 AS SELECT c2, c1 FROM mysqltest1.t2, mysqltest1.t1; +ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c1' in table 'v21' +CREATE VIEW v23 AS SELECT c2, c3 FROM mysqltest1.t2, mysqltest1.t3; +ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c3' in table 'v23' +CREATE VIEW v24 AS SELECT c2, c4 FROM mysqltest1.t2, mysqltest1.t4; +ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c4' in table 'v24' +CREATE VIEW v31 AS SELECT c3, c1 FROM mysqltest1.t3, mysqltest1.t1; +CREATE VIEW v32 AS SELECT c3, c2 FROM mysqltest1.t3, mysqltest1.t2; +ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v32' +CREATE VIEW v34 AS SELECT c3, c4 FROM mysqltest1.t3, mysqltest1.t4; +CREATE VIEW v41 AS SELECT c4, c1 FROM mysqltest1.t4, mysqltest1.t1; +CREATE VIEW v42 AS SELECT c4, c2 FROM mysqltest1.t4, mysqltest1.t2; +ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v42' +CREATE VIEW v43 AS SELECT c4, c3 FROM mysqltest1.t4, mysqltest1.t3; + +---> connection: default +SELECT * FROM mysqltest1.t1; +c1 +11 +12 +13 +14 +SELECT * FROM mysqltest1.t2; +c2 +21 +22 +23 +24 +25 +26 +SELECT * FROM mysqltest1.t3 order by c3; +c3 +33 +34 +331 +332 +SELECT * FROM mysqltest1.t4; +c4 +41 +42 +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +DROP USER mysqltest_u1@localhost; +End of 5.0 tests. +DROP VIEW IF EXISTS v1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i INT); +CREATE VIEW v1 AS SELECT * FROM t1; +ALTER VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci +ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1; +Warnings: +Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; +Warnings: +Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=MERGE DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1; +Warnings: +Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`no_such`@`user_2` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DROP VIEW v1; +DROP TABLE t1; +End of 5.1 tests. diff --git a/mysql-test/suite/pbxt/r/view_query_cache.result b/mysql-test/suite/pbxt/r/view_query_cache.result new file mode 100644 index 00000000000..03430bd504b --- /dev/null +++ b/mysql-test/suite/pbxt/r/view_query_cache.result @@ -0,0 +1,196 @@ +drop table if exists t1,t2,v1,v2,v3; +drop view if exists t1,t2,v1,v2,v3; +set GLOBAL query_cache_size=1355776; +flush status; +create table t1 (a int, b int); +create view v1 (c,d) as select sql_no_cache a,b from t1; +create view v2 (c,d) as select a+rand(),b from t1; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from v1; +c d +select * from v2; +c d +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from v1; +c d +select * from v2; +c d +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +drop view v1,v2; +set query_cache_type=demand; +flush status; +create view v1 (c,d) as select sql_cache a,b from t1; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from v1; +c d +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from t1; +a b +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from v1; +c d +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +select * from t1; +a b +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +drop view v1; +set query_cache_type=default; +drop table t1; +create table t1 (a int); +insert into t1 values (1), (2), (3); +create view v1 as select a from t1 where a > 1; +select * from v1; +a +2 +3 +alter view v1 as select a from t1 where a > 2; +select * from v1; +a +3 +drop view v1; +select * from v1; +ERROR 42S02: Table 'test.v1' doesn't exist +drop table t1; +create table t1 (a int, primary key (a), b int); +create table t2 (a int, primary key (a), b int); +insert into t2 values (1000, 2000); +create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2; +select * from v3; +a b +drop view v3; +drop table t1, t2; +create table t1(f1 int); +insert into t1 values(1),(2),(3); +create view v1 as select * from t1; +set query_cache_wlock_invalidate=1; +lock tables v1 read /*!32311 local */; +unlock tables; +set query_cache_wlock_invalidate=default; +drop view v1; +drop table t1; +flush status; +create table t1 (a int, b int); +create algorithm=temptable view v1 as select * from t1; +select * from v1; +a b +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from v1; +a b +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +insert into t1 values (1,1); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +select * from v1; +a b +1 1 +select * from v1; +a b +1 1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop view v1; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; +set GLOBAL query_cache_size=default; diff --git a/mysql-test/suite/pbxt/r/xml.result b/mysql-test/suite/pbxt/r/xml.result new file mode 100644 index 00000000000..26bd92d51aa --- /dev/null +++ b/mysql-test/suite/pbxt/r/xml.result @@ -0,0 +1,811 @@ +SET @xml='<a aa1="aa1" aa2="aa2">a1<b ba1="ba1">b1<c>c1</c>b2</b>a2</a>'; +SELECT extractValue(@xml,'/a'); +extractValue(@xml,'/a') +a1 a2 +SELECT extractValue(@xml,'/a/b'); +extractValue(@xml,'/a/b') +b1 b2 +SELECT extractValue(@xml,'/a/b/c'); +extractValue(@xml,'/a/b/c') +c1 +SELECT extractValue(@xml,'/a/@aa1'); +extractValue(@xml,'/a/@aa1') +aa1 +SELECT extractValue(@xml,'/a/@aa2'); +extractValue(@xml,'/a/@aa2') +aa2 +SELECT extractValue(@xml,'/a/@*'); +extractValue(@xml,'/a/@*') +aa1 aa2 +SELECT extractValue(@xml,'//@ba1'); +extractValue(@xml,'//@ba1') +ba1 +SELECT extractValue(@xml,'//a'); +extractValue(@xml,'//a') +a1 a2 +SELECT extractValue(@xml,'//b'); +extractValue(@xml,'//b') +b1 b2 +SELECT extractValue(@xml,'//c'); +extractValue(@xml,'//c') +c1 +SELECT extractValue(@xml,'/a//b'); +extractValue(@xml,'/a//b') +b1 b2 +SELECT extractValue(@xml,'/a//c'); +extractValue(@xml,'/a//c') +c1 +SELECT extractValue(@xml,'//*'); +extractValue(@xml,'//*') +a1 b1 c1 b2 a2 +SELECT extractValue(@xml,'/a//*'); +extractValue(@xml,'/a//*') +b1 c1 b2 +SELECT extractValue(@xml,'/./a'); +extractValue(@xml,'/./a') +a1 a2 +SELECT extractValue(@xml,'/a/b/.'); +extractValue(@xml,'/a/b/.') +b1 b2 +SELECT extractValue(@xml,'/a/b/..'); +extractValue(@xml,'/a/b/..') +a1 a2 +SELECT extractValue(@xml,'/a/b/../@aa1'); +extractValue(@xml,'/a/b/../@aa1') +aa1 +SELECT extractValue(@xml,'/*'); +extractValue(@xml,'/*') +a1 a2 +SELECT extractValue(@xml,'/*/*'); +extractValue(@xml,'/*/*') +b1 b2 +SELECT extractValue(@xml,'/*/*/*'); +extractValue(@xml,'/*/*/*') +c1 +SELECT extractValue(@xml,'/a/child::*'); +extractValue(@xml,'/a/child::*') +b1 b2 +SELECT extractValue(@xml,'/a/self::*'); +extractValue(@xml,'/a/self::*') +a1 a2 +SELECT extractValue(@xml,'/a/descendant::*'); +extractValue(@xml,'/a/descendant::*') +b1 c1 b2 +SELECT extractValue(@xml,'/a/descendant-or-self::*'); +extractValue(@xml,'/a/descendant-or-self::*') +a1 b1 c1 b2 a2 +SELECT extractValue(@xml,'/a/attribute::*'); +extractValue(@xml,'/a/attribute::*') +aa1 aa2 +SELECT extractValue(@xml,'/a/b/c/parent::*'); +extractValue(@xml,'/a/b/c/parent::*') +b1 b2 +SELECT extractValue(@xml,'/a/b/c/ancestor::*'); +extractValue(@xml,'/a/b/c/ancestor::*') +a1 b1 b2 a2 +SELECT extractValue(@xml,'/a/b/c/ancestor-or-self::*'); +extractValue(@xml,'/a/b/c/ancestor-or-self::*') +a1 b1 c1 b2 a2 +SELECT extractValue(@xml,'/descendant-or-self::*'); +extractValue(@xml,'/descendant-or-self::*') +a1 b1 c1 b2 a2 +SET @xml='<a>a11<b ba="ba11" ba="ba12">b11</b><b ba="ba21" ba="ba22">b21<c>c1</c>b22</b>a12</a>'; +SELECT extractValue(@xml,'/a/b/c/ancestor-or-self::*'); +extractValue(@xml,'/a/b/c/ancestor-or-self::*') +a11 b21 c1 b22 a12 +SELECT extractValue(@xml,'//@ba'); +extractValue(@xml,'//@ba') +ba11 ba12 ba21 ba22 +SET @xml='<a><b>b</b><c>c</c></a>'; +SELECT extractValue(@xml,'/a/b'); +extractValue(@xml,'/a/b') +b +SELECT extractValue(@xml,'/a/c'); +extractValue(@xml,'/a/c') +c +SELECT extractValue(@xml,'/a/child::b'); +extractValue(@xml,'/a/child::b') +b +SELECT extractValue(@xml,'/a/child::c'); +extractValue(@xml,'/a/child::c') +c +SET @xml='<a><b>b1</b><c>c1</c><b>b2</b><c>c2</c></a>'; +SELECT extractValue(@xml,'/a/b[1]'); +extractValue(@xml,'/a/b[1]') +b1 +SELECT extractValue(@xml,'/a/b[2]'); +extractValue(@xml,'/a/b[2]') +b2 +SELECT extractValue(@xml,'/a/c[1]'); +extractValue(@xml,'/a/c[1]') +c1 +SELECT extractValue(@xml,'/a/c[2]'); +extractValue(@xml,'/a/c[2]') +c2 +SET @xml='<a><b x="xb1" x="xb2"/><c x="xc1" x="xc2"/></a>'; +SELECT extractValue(@xml,'/a//@x'); +extractValue(@xml,'/a//@x') +xb1 xb2 xc1 xc2 +SELECT extractValue(@xml,'/a//@x[1]'); +extractValue(@xml,'/a//@x[1]') +xb1 xc1 +SELECT extractValue(@xml,'/a//@x[2]'); +extractValue(@xml,'/a//@x[2]') +xb2 xc2 +SET @xml='<a><b>b1</b><b>b2</b><c><b>c1b1</b><b>c1b2</b></c><c><b>c2b1</c></b></a>'; +SELECT extractValue(@xml,'//b[1]'); +extractValue(@xml,'//b[1]') +b1 c1b1 c2b1 +SELECT extractValue(@xml,'/descendant::b[1]'); +extractValue(@xml,'/descendant::b[1]') +b1 +SET @xml='<a><b>b1</b><b>b2</b></a>'; +SELECT extractValue(@xml,'/a/b[1+0]'); +extractValue(@xml,'/a/b[1+0]') +b1 +SELECT extractValue(@xml,'/a/b[1*1]'); +extractValue(@xml,'/a/b[1*1]') +b1 +SELECT extractValue(@xml,'/a/b[--1]'); +extractValue(@xml,'/a/b[--1]') +b1 +SELECT extractValue(@xml,'/a/b[2*1-1]'); +extractValue(@xml,'/a/b[2*1-1]') +b1 +SELECT extractValue(@xml,'/a/b[1+1]'); +extractValue(@xml,'/a/b[1+1]') +b2 +SELECT extractValue(@xml,'/a/b[1*2]'); +extractValue(@xml,'/a/b[1*2]') +b2 +SELECT extractValue(@xml,'/a/b[--2]'); +extractValue(@xml,'/a/b[--2]') +b2 +SELECT extractValue(@xml,'/a/b[1*(3-1)]'); +extractValue(@xml,'/a/b[1*(3-1)]') +b2 +SELECT extractValue(@xml,'//*[1=1]'); +extractValue(@xml,'//*[1=1]') +b1 b2 +SELECT extractValue(@xml,'//*[1!=1]'); +extractValue(@xml,'//*[1!=1]') + +SELECT extractValue(@xml,'//*[1>1]'); +extractValue(@xml,'//*[1>1]') + +SELECT extractValue(@xml,'//*[2>1]'); +extractValue(@xml,'//*[2>1]') +b1 b2 +SELECT extractValue(@xml,'//*[1>2]'); +extractValue(@xml,'//*[1>2]') + +SELECT extractValue(@xml,'//*[1>=1]'); +extractValue(@xml,'//*[1>=1]') +b1 b2 +SELECT extractValue(@xml,'//*[2>=1]'); +extractValue(@xml,'//*[2>=1]') +b1 b2 +SELECT extractValue(@xml,'//*[1>=2]'); +extractValue(@xml,'//*[1>=2]') + +SELECT extractValue(@xml,'//*[1<1]'); +extractValue(@xml,'//*[1<1]') + +SELECT extractValue(@xml,'//*[2<1]'); +extractValue(@xml,'//*[2<1]') + +SELECT extractValue(@xml,'//*[1<2]'); +extractValue(@xml,'//*[1<2]') +b1 b2 +SELECT extractValue(@xml,'//*[1<=1]'); +extractValue(@xml,'//*[1<=1]') +b1 b2 +SELECT extractValue(@xml,'//*[2<=1]'); +extractValue(@xml,'//*[2<=1]') + +SELECT extractValue(@xml,'//*[1<=2]'); +extractValue(@xml,'//*[1<=2]') +b1 b2 +SET @xml='<a><b>b11<c>c11</c></b><b>b21<c>c21</c></b></a>'; +SELECT extractValue(@xml,'/a/b[c="c11"]'); +extractValue(@xml,'/a/b[c="c11"]') +b11 +SELECT extractValue(@xml,'/a/b[c="c21"]'); +extractValue(@xml,'/a/b[c="c21"]') +b21 +SET @xml='<a><b c="c11">b11</b><b c="c21">b21</b></a>'; +SELECT extractValue(@xml,'/a/b[@c="c11"]'); +extractValue(@xml,'/a/b[@c="c11"]') +b11 +SELECT extractValue(@xml,'/a/b[@c="c21"]'); +extractValue(@xml,'/a/b[@c="c21"]') +b21 +SET @xml='<a>a1<b c="c11">b11<d>d11</d></b><b c="c21">b21<d>d21</d></b></a>'; +SELECT extractValue(@xml, '/a/b[@c="c11"]/d'); +extractValue(@xml, '/a/b[@c="c11"]/d') +d11 +SELECT extractValue(@xml, '/a/b[@c="c21"]/d'); +extractValue(@xml, '/a/b[@c="c21"]/d') +d21 +SELECT extractValue(@xml, '/a/b[d="d11"]/@c'); +extractValue(@xml, '/a/b[d="d11"]/@c') +c11 +SELECT extractValue(@xml, '/a/b[d="d21"]/@c'); +extractValue(@xml, '/a/b[d="d21"]/@c') +c21 +SELECT extractValue(@xml, '/a[b="b11"]'); +extractValue(@xml, '/a[b="b11"]') +a1 +SELECT extractValue(@xml, '/a[b/@c="c11"]'); +extractValue(@xml, '/a[b/@c="c11"]') +a1 +SELECT extractValue(@xml, '/a[b/d="d11"]'); +extractValue(@xml, '/a[b/d="d11"]') +a1 +SELECT extractValue(@xml, '/a[/a/b="b11"]'); +extractValue(@xml, '/a[/a/b="b11"]') +a1 +SELECT extractValue(@xml, '/a[/a/b/@c="c11"]'); +extractValue(@xml, '/a[/a/b/@c="c11"]') +a1 +SELECT extractValue(@xml, '/a[/a/b/d="d11"]'); +extractValue(@xml, '/a[/a/b/d="d11"]') +a1 +SELECT extractValue('<a>a</a>', '/a[false()]'); +extractValue('<a>a</a>', '/a[false()]') + +SELECT extractValue('<a>a</a>', '/a[true()]'); +extractValue('<a>a</a>', '/a[true()]') +a +SELECT extractValue('<a>a</a>', '/a[not(false())]'); +extractValue('<a>a</a>', '/a[not(false())]') +a +SELECT extractValue('<a>a</a>', '/a[not(true())]'); +extractValue('<a>a</a>', '/a[not(true())]') + +SELECT extractValue('<a>a</a>', '/a[true() and true()]'); +extractValue('<a>a</a>', '/a[true() and true()]') +a +SELECT extractValue('<a>a</a>', '/a[true() and false()]'); +extractValue('<a>a</a>', '/a[true() and false()]') + +SELECT extractValue('<a>a</a>', '/a[false()and false()]'); +extractValue('<a>a</a>', '/a[false()and false()]') + +SELECT extractValue('<a>a</a>', '/a[false()and true()]'); +extractValue('<a>a</a>', '/a[false()and true()]') + +SELECT extractValue('<a>a</a>', '/a[true() or true()]'); +extractValue('<a>a</a>', '/a[true() or true()]') +a +SELECT extractValue('<a>a</a>', '/a[true() or false()]'); +extractValue('<a>a</a>', '/a[true() or false()]') +a +SELECT extractValue('<a>a</a>', '/a[false()or false()]'); +extractValue('<a>a</a>', '/a[false()or false()]') + +SELECT extractValue('<a>a</a>', '/a[false()or true()]'); +extractValue('<a>a</a>', '/a[false()or true()]') +a +SET @xml='<a>ab<b c="c" c="e">b1</b><b c="d">b2</b><b c="f" c="e">b3</b></a>'; +select extractValue(@xml,'/a/b[@c="c"]'); +extractValue(@xml,'/a/b[@c="c"]') +b1 +select extractValue(@xml,'/a/b[@c="d"]'); +extractValue(@xml,'/a/b[@c="d"]') +b2 +select extractValue(@xml,'/a/b[@c="e"]'); +extractValue(@xml,'/a/b[@c="e"]') +b1 b3 +select extractValue(@xml,'/a/b[not(@c="e")]'); +extractValue(@xml,'/a/b[not(@c="e")]') +b2 +select extractValue(@xml,'/a/b[@c!="e"]'); +extractValue(@xml,'/a/b[@c!="e"]') +b1 b2 b3 +select extractValue(@xml,'/a/b[@c="c" or @c="d"]'); +extractValue(@xml,'/a/b[@c="c" or @c="d"]') +b1 b2 +select extractValue(@xml,'/a/b[@c="c" and @c="e"]'); +extractValue(@xml,'/a/b[@c="c" and @c="e"]') +b1 +SET @xml='<a><b c="c" d="d">b1</b><b d="d" e="e">b2</b></a>'; +select extractValue(@xml,'/a/b[@c]'); +extractValue(@xml,'/a/b[@c]') +b1 +select extractValue(@xml,'/a/b[@d]'); +extractValue(@xml,'/a/b[@d]') +b1 b2 +select extractValue(@xml,'/a/b[@e]'); +extractValue(@xml,'/a/b[@e]') +b2 +select extractValue(@xml,'/a/b[not(@c)]'); +extractValue(@xml,'/a/b[not(@c)]') +b2 +select extractValue(@xml,'/a/b[not(@d)]'); +extractValue(@xml,'/a/b[not(@d)]') + +select extractValue(@xml,'/a/b[not(@e)]'); +extractValue(@xml,'/a/b[not(@e)]') +b1 +select extractValue(@xml, '/a/b[boolean(@c) or boolean(@d)]'); +extractValue(@xml, '/a/b[boolean(@c) or boolean(@d)]') +b1 b2 +select extractValue(@xml, '/a/b[boolean(@c) or boolean(@e)]'); +extractValue(@xml, '/a/b[boolean(@c) or boolean(@e)]') +b1 b2 +select extractValue(@xml, '/a/b[boolean(@d) or boolean(@e)]'); +extractValue(@xml, '/a/b[boolean(@d) or boolean(@e)]') +b1 b2 +select extractValue(@xml, '/a/b[boolean(@c) and boolean(@d)]'); +extractValue(@xml, '/a/b[boolean(@c) and boolean(@d)]') +b1 +select extractValue(@xml, '/a/b[boolean(@c) and boolean(@e)]'); +extractValue(@xml, '/a/b[boolean(@c) and boolean(@e)]') + +select extractValue(@xml, '/a/b[boolean(@d) and boolean(@e)]'); +extractValue(@xml, '/a/b[boolean(@d) and boolean(@e)]') +b2 +select extractValue(@xml, '/a/b[@c or @d]'); +extractValue(@xml, '/a/b[@c or @d]') +b1 b2 +select extractValue(@xml, '/a/b[@c or @e]'); +extractValue(@xml, '/a/b[@c or @e]') +b1 b2 +select extractValue(@xml, '/a/b[@d or @e]'); +extractValue(@xml, '/a/b[@d or @e]') +b1 b2 +select extractValue(@xml, '/a/b[@c and @d]'); +extractValue(@xml, '/a/b[@c and @d]') +b1 +select extractValue(@xml, '/a/b[@c and @e]'); +extractValue(@xml, '/a/b[@c and @e]') + +select extractValue(@xml, '/a/b[@d and @e]'); +extractValue(@xml, '/a/b[@d and @e]') +b2 +SET @xml='<a><b c="c">b1</b><b>b2</b></a>'; +SELECT extractValue(@xml,'/a/b[@*]'); +extractValue(@xml,'/a/b[@*]') +b1 +SELECT extractValue(@xml,'/a/b[not(@*)]'); +extractValue(@xml,'/a/b[not(@*)]') +b2 +SELECT extractValue('<a>a</a>', '/a[ceiling(3.1)=4]'); +extractValue('<a>a</a>', '/a[ceiling(3.1)=4]') +a +SELECT extractValue('<a>a</a>', '/a[floor(3.1)=3]'); +extractValue('<a>a</a>', '/a[floor(3.1)=3]') +a +SELECT extractValue('<a>a</a>', '/a[round(3.1)=3]'); +extractValue('<a>a</a>', '/a[round(3.1)=3]') +a +SELECT extractValue('<a>a</a>', '/a[round(3.8)=4]'); +extractValue('<a>a</a>', '/a[round(3.8)=4]') +a +SELECT extractValue('<a><b>b</b><c>c</c></a>', '/a/b | /a/c'); +extractValue('<a><b>b</b><c>c</c></a>', '/a/b | /a/c') +b c +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=1]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=1]') +b1 +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=2]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=2]') +b2 +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3]') +b3 +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[1=position()]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[1=position()]') +b1 +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2=position()]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2=position()]') +b2 +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[3=position()]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[3=position()]') +b3 +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2>=position()]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2>=position()]') +b1 b2 +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2<=position()]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2<=position()]') +b2 b3 +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3 or position()=2]'); +extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3 or position()=2]') +b2 b3 +SELECT extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=0]'); +extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=0]') +a2 +SELECT extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=1]'); +extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=1]') +a1 +select extractValue('<a>a1<b ba="1" ba="2">b1</b><b>b2</b>4</a>','/a/b[sum(@ba)=3]'); +extractValue('<a>a1<b ba="1" ba="2">b1</b><b>b2</b>4</a>','/a/b[sum(@ba)=3]') +b1 +select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[1]'); +extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[1]') +b1 +select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[boolean(1)]'); +extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[boolean(1)]') +b1 b2 +select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[true()]'); +extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[true()]') +b1 b2 +select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[number(true())]'); +extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[number(true())]') +b1 +select extractValue('<a>ab</a>','/a[contains("abc","b")]'); +extractValue('<a>ab</a>','/a[contains("abc","b")]') +ab +select extractValue('<a>ab</a>','/a[contains(.,"a")]'); +extractValue('<a>ab</a>','/a[contains(.,"a")]') +ab +select extractValue('<a>ab</a>','/a[contains(.,"b")]'); +extractValue('<a>ab</a>','/a[contains(.,"b")]') +ab +select extractValue('<a>ab</a>','/a[contains(.,"c")]'); +extractValue('<a>ab</a>','/a[contains(.,"c")]') + +select extractValue('<a b="1">ab</a>','/a[concat(@b,"2")="12"]'); +extractValue('<a b="1">ab</a>','/a[concat(@b,"2")="12"]') +ab +SET @xml='<a b="11" b="12" b="21" b="22">ab</a>'; +select extractValue(@xml, '/a/@b[substring(.,2)="1"]'); +extractValue(@xml, '/a/@b[substring(.,2)="1"]') +11 21 +select extractValue(@xml, '/a/@b[substring(.,2)="2"]'); +extractValue(@xml, '/a/@b[substring(.,2)="2"]') +12 22 +select extractValue(@xml, '/a/@b[substring(.,1,1)="1"]'); +extractValue(@xml, '/a/@b[substring(.,1,1)="1"]') +11 12 +select extractValue(@xml, '/a/@b[substring(.,1,1)="2"]'); +extractValue(@xml, '/a/@b[substring(.,1,1)="2"]') +21 22 +select extractValue(@xml, '/a/@b[substring(.,2,1)="1"]'); +extractValue(@xml, '/a/@b[substring(.,2,1)="1"]') +11 21 +select extractValue(@xml, '/a/@b[substring(.,2,1)="2"]'); +extractValue(@xml, '/a/@b[substring(.,2,1)="2"]') +12 22 +SET @xml='<a><b>b1</b><b>b2</b></a>'; +SELECT extractValue(@xml, '/a/b[string-length("x")=1]'); +extractValue(@xml, '/a/b[string-length("x")=1]') +b1 b2 +SELECT extractValue(@xml, '/a/b[string-length("xx")=2]'); +extractValue(@xml, '/a/b[string-length("xx")=2]') +b1 b2 +SELECT extractValue(@xml, '/a/b[string-length("xxx")=2]'); +extractValue(@xml, '/a/b[string-length("xxx")=2]') + +SELECT extractValue(@xml, '/a/b[string-length("x")]'); +extractValue(@xml, '/a/b[string-length("x")]') +b1 +SELECT extractValue(@xml, '/a/b[string-length("xx")]'); +extractValue(@xml, '/a/b[string-length("xx")]') +b2 +SELECT extractValue(@xml, '/a/b[string-length()]'); +extractValue(@xml, '/a/b[string-length()]') +b2 +SELECT extractValue(@xml, 'string-length()'); +ERROR HY000: XPATH syntax error: '' +SELECT extractValue(@xml, 'string-length("x")'); +extractValue(@xml, 'string-length("x")') +1 +SET @xml='<a b="b11" b="b12" b="b21" b="22"/>'; +select extractValue(@xml,'/a/@b'); +extractValue(@xml,'/a/@b') +b11 b12 b21 22 +select extractValue(@xml,'/a/@b[contains(.,"1")]'); +extractValue(@xml,'/a/@b[contains(.,"1")]') +b11 b12 b21 +select extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")]'); +extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")]') +b12 b21 +select extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")][2]'); +extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")][2]') +b21 +SET @xml='<a>a1<b>b1<c>c1</c>b2</b>a2</a>'; +select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','+++++++++'); +UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','+++++++++') +<a>a1<b>b1+++++++++b2</b>a2</a> +select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1>+++++++++</c1>'); +UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1>+++++++++</c1>') +<a>a1<b>b1<c1>+++++++++</c1>b2</b>a2</a> +select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1/>'); +UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1/>') +<a>a1<b>b1<c1/>b2</b>a2</a> +SET @xml='<a><b>bb</b></a>'; +select UpdateXML(@xml, '/a/b', '<b>ccc</b>'); +UpdateXML(@xml, '/a/b', '<b>ccc</b>') +<a><b>ccc</b></a> +SET @xml='<a aa1="aa1" aa2="aa2"><b bb1="bb1" bb2="bb2">bb</b></a>'; +select UpdateXML(@xml, '/a/b', '<b>ccc</b>'); +UpdateXML(@xml, '/a/b', '<b>ccc</b>') +<a aa1="aa1" aa2="aa2"><b>ccc</b></a> +select UpdateXML(@xml, '/a/@aa1', ''); +UpdateXML(@xml, '/a/@aa1', '') +<a aa2="aa2"><b bb1="bb1" bb2="bb2">bb</b></a> +select UpdateXML(@xml, '/a/@aa1', 'aa3="aa3"'); +UpdateXML(@xml, '/a/@aa1', 'aa3="aa3"') +<a aa3="aa3" aa2="aa2"><b bb1="bb1" bb2="bb2">bb</b></a> +select UpdateXML(@xml, '/a/@aa2', ''); +UpdateXML(@xml, '/a/@aa2', '') +<a aa1="aa1" ><b bb1="bb1" bb2="bb2">bb</b></a> +select UpdateXML(@xml, '/a/@aa2', 'aa3="aa3"'); +UpdateXML(@xml, '/a/@aa2', 'aa3="aa3"') +<a aa1="aa1" aa3="aa3"><b bb1="bb1" bb2="bb2">bb</b></a> +select UpdateXML(@xml, '/a/b/@bb1', ''); +UpdateXML(@xml, '/a/b/@bb1', '') +<a aa1="aa1" aa2="aa2"><b bb2="bb2">bb</b></a> +select UpdateXML(@xml, '/a/b/@bb1', 'bb3="bb3"'); +UpdateXML(@xml, '/a/b/@bb1', 'bb3="bb3"') +<a aa1="aa1" aa2="aa2"><b bb3="bb3" bb2="bb2">bb</b></a> +select UpdateXML(@xml, '/a/b/@bb2', ''); +UpdateXML(@xml, '/a/b/@bb2', '') +<a aa1="aa1" aa2="aa2"><b bb1="bb1" >bb</b></a> +select UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"'); +UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"') +<a aa1="aa1" aa2="aa2"><b bb1="bb1" bb3="bb3">bb</b></a> +SET @xml= '<order><clerk>lesser wombat</clerk></order>'; +select extractvalue(@xml,'order/clerk'); +extractvalue(@xml,'order/clerk') +lesser wombat +select extractvalue(@xml,'/order/clerk'); +extractvalue(@xml,'/order/clerk') +lesser wombat +select extractvalue('<a><b>B</b></a>','/a|/b'); +extractvalue('<a><b>B</b></a>','/a|/b') + +select extractvalue('<a><b>B</b></a>','/a|b'); +extractvalue('<a><b>B</b></a>','/a|b') + +select extractvalue('<a>a<b>B</b></a>','/a|/b'); +extractvalue('<a>a<b>B</b></a>','/a|/b') +a +select extractvalue('<a>a<b>B</b></a>','/a|b'); +extractvalue('<a>a<b>B</b></a>','/a|b') +a +select extractvalue('<a>a<b>B</b></a>','a|/b'); +extractvalue('<a>a<b>B</b></a>','a|/b') +a +select extractvalue('<a>A</a>','/<a>'); +ERROR HY000: XPATH error: comparison of two nodesets is not supported: '<a>' +select extractvalue('<a><b>b</b><b!>b!</b!></a>','//b!'); +ERROR HY000: XPATH syntax error: '!' +select extractvalue('<a>A<b>B<c>C</c></b></a>','/a/descendant::*'); +extractvalue('<a>A<b>B<c>C</c></b></a>','/a/descendant::*') +B C +select extractvalue('<a>A<b>B<c>C</c></b></a>','/a/self::*'); +extractvalue('<a>A<b>B<c>C</c></b></a>','/a/self::*') +A +select extractvalue('<a>A<b>B<c>C</c></b></a>','/a/descendant-or-self::*'); +extractvalue('<a>A<b>B<c>C</c></b></a>','/a/descendant-or-self::*') +A B C +select extractvalue('<A_B>A</A_B>','/A_B'); +extractvalue('<A_B>A</A_B>','/A_B') +A +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[position()]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[position()]') +B1 B2 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=last()]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=last()]') +B1 B2 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()]') +B2 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()-1]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()-1]') +B1 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=1]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=1]') + +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=2]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=2]') +B1 B2 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=position()]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=position()]') +B2 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)]') +B2 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)-1]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)-1]') +B1 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=1]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=1]') + +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=2]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=2]') +B1 B2 +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=position()]'); +extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=position()]') +B2 +select extractvalue('<a>Jack</a>','/a[contains(../a,"J")]'); +extractvalue('<a>Jack</a>','/a[contains(../a,"J")]') +Jack +select extractvalue('<a>Jack</a>','/a[contains(../a,"j")]'); +extractvalue('<a>Jack</a>','/a[contains(../a,"j")]') +Jack +select extractvalue('<a>Jack</a>','/a[contains(../a,"j")]' collate latin1_bin); +extractvalue('<a>Jack</a>','/a[contains(../a,"j")]' collate latin1_bin) + +select extractvalue('<a>Jack</a>' collate latin1_bin,'/a[contains(../a,"j")]'); +extractvalue('<a>Jack</a>' collate latin1_bin,'/a[contains(../a,"j")]') + +select ExtractValue('<tag1><![CDATA[test]]></tag1>','/tag1'); +ExtractValue('<tag1><![CDATA[test]]></tag1>','/tag1') +test +select extractValue('<a>a','/a'); +extractValue('<a>a','/a') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 5: unexpected END-OF-INPUT' +select extractValue('<a>a<','/a'); +extractValue('<a>a<','/a') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 6: END-OF-INPUT unexpected (ident or '/' wanted)' +select extractValue('<a>a</','/a'); +extractValue('<a>a</','/a') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 7: END-OF-INPUT unexpected (ident wanted)' +select extractValue('<a>a</a','/a'); +extractValue('<a>a</a','/a') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 8: END-OF-INPUT unexpected ('>' wanted)' +select extractValue('<a>a</a></b>','/a'); +extractValue('<a>a</a></b>','/a') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 12: '</b>' unexpected (END-OF-INPUT wanted)' +select extractValue('<a b=>a</a>','/a'); +extractValue('<a b=>a</a>','/a') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 7: '>' unexpected (ident or string wanted)' +select extractValue('<e>1</e>','position()'); +ERROR HY000: XPATH syntax error: '' +select extractValue('<e>1</e>','last()'); +ERROR HY000: XPATH syntax error: '' +select extractValue('<e><a>1</a></e>','/e/'); +ERROR HY000: XPATH syntax error: '' +set names utf8; +select extractValue('<Ñ><r>r</r></Ñ>','/Ñ/r'); +extractValue('<Ñ><r>r</r></Ñ>','/Ñ/r') +r +select extractValue('<r><Ñ>Ñ</Ñ></r>','/r/Ñ'); +extractValue('<r><Ñ>Ñ</Ñ></r>','/r/Ñ') +Ñ +select extractValue('<Ñ r="r"/>','/Ñ/@r'); +extractValue('<Ñ r="r"/>','/Ñ/@r') +r +select extractValue('<r Ñ="Ñ"/>','/r/@Ñ'); +extractValue('<r Ñ="Ñ"/>','/r/@Ñ') +Ñ +DROP PROCEDURE IF EXISTS p2; +CREATE PROCEDURE p2 () +BEGIN +DECLARE p LONGTEXT CHARACTER SET UTF8 DEFAULT '<Ñ><r>A</r></Ñ>'; +SELECT EXTRACTVALUE(p,'/Ñ/r'); +END// +CALL p2(); +EXTRACTVALUE(p,'/Ñ/r') +A +DROP PROCEDURE p2; +select extractValue('<ns:element xmlns:ns="myns"/>','count(ns:element)'); +extractValue('<ns:element xmlns:ns="myns"/>','count(ns:element)') +1 +select extractValue('<ns:element xmlns:ns="myns">a</ns:element>','/ns:element'); +extractValue('<ns:element xmlns:ns="myns">a</ns:element>','/ns:element') +a +select extractValue('<ns:element xmlns:ns="myns">a</ns:element>','/ns:element/@xmlns:ns'); +extractValue('<ns:element xmlns:ns="myns">a</ns:element>','/ns:element/@xmlns:ns') +myns +select extractValue('<foo><foo.bar>Data</foo.bar><something>Otherdata</something></foo>','/foo/foo.bar'); +extractValue('<foo><foo.bar>Data</foo.bar><something>Otherdata</something></foo>','/foo/foo.bar') +Data +select extractValue('<foo><foo.bar>Data</foo.bar><something>Otherdata</something></foo>','/foo/something'); +extractValue('<foo><foo.bar>Data</foo.bar><something>Otherdata</something></foo>','/foo/something') +Otherdata +select extractValue('<zot><tim0><01>10:39:15</01><02>140</02></tim0></zot>','/zot/tim0/02'); +ERROR HY000: XPATH syntax error: '02' +select extractValue('<zot><tim0><01>10:39:15</01><02>140</02></tim0></zot>','//*'); +extractValue('<zot><tim0><01>10:39:15</01><02>140</02></tim0></zot>','//*') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 13: unknown token unexpected (ident or '/' wanted)' +select extractValue('<.>test</.>','//*'); +extractValue('<.>test</.>','//*') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)' +select extractValue('<->test</->','//*'); +extractValue('<->test</->','//*') +NULL +Warnings: +Warning 1525 Incorrect XML value: 'parse error at line 1 pos 2: unknown token unexpected (ident or '/' wanted)' +select extractValue('<:>test</:>','//*'); +extractValue('<:>test</:>','//*') +test +select extractValue('<_>test</_>','//*'); +extractValue('<_>test</_>','//*') +test +select extractValue('<x.-_:>test</x.-_:>','//*'); +extractValue('<x.-_:>test</x.-_:>','//*') +test +set @xml= "<entry><id>pt10</id><pt>10</pt></entry><entry><id>pt50</id><pt>50</pt></entry>"; +select ExtractValue(@xml, "/entry[(pt=10)]/id"); +ExtractValue(@xml, "/entry[(pt=10)]/id") +pt10 +select ExtractValue(@xml, "/entry[(pt!=10)]/id"); +ExtractValue(@xml, "/entry[(pt!=10)]/id") +pt50 +select ExtractValue(@xml, "/entry[(pt<10)]/id"); +ExtractValue(@xml, "/entry[(pt<10)]/id") + +select ExtractValue(@xml, "/entry[(pt<=10)]/id"); +ExtractValue(@xml, "/entry[(pt<=10)]/id") +pt10 +select ExtractValue(@xml, "/entry[(pt>10)]/id"); +ExtractValue(@xml, "/entry[(pt>10)]/id") +pt50 +select ExtractValue(@xml, "/entry[(pt>=10)]/id"); +ExtractValue(@xml, "/entry[(pt>=10)]/id") +pt10 pt50 +select ExtractValue(@xml, "/entry[(pt=50)]/id"); +ExtractValue(@xml, "/entry[(pt=50)]/id") +pt50 +select ExtractValue(@xml, "/entry[(pt!=50)]/id"); +ExtractValue(@xml, "/entry[(pt!=50)]/id") +pt10 +select ExtractValue(@xml, "/entry[(pt<50)]/id"); +ExtractValue(@xml, "/entry[(pt<50)]/id") +pt10 +select ExtractValue(@xml, "/entry[(pt<=50)]/id"); +ExtractValue(@xml, "/entry[(pt<=50)]/id") +pt10 pt50 +select ExtractValue(@xml, "/entry[(pt>50)]/id"); +ExtractValue(@xml, "/entry[(pt>50)]/id") + +select ExtractValue(@xml, "/entry[(pt>=50)]/id"); +ExtractValue(@xml, "/entry[(pt>=50)]/id") +pt50 +select ExtractValue(@xml, "/entry[(10=pt)]/id"); +ExtractValue(@xml, "/entry[(10=pt)]/id") +pt10 +select ExtractValue(@xml, "/entry[(10!=pt)]/id"); +ExtractValue(@xml, "/entry[(10!=pt)]/id") +pt50 +select ExtractValue(@xml, "/entry[(10>pt)]/id"); +ExtractValue(@xml, "/entry[(10>pt)]/id") + +select ExtractValue(@xml, "/entry[(10>=pt)]/id"); +ExtractValue(@xml, "/entry[(10>=pt)]/id") +pt10 +select ExtractValue(@xml, "/entry[(10<pt)]/id"); +ExtractValue(@xml, "/entry[(10<pt)]/id") +pt50 +select ExtractValue(@xml, "/entry[(10<=pt)]/id"); +ExtractValue(@xml, "/entry[(10<=pt)]/id") +pt10 pt50 +select ExtractValue(@xml, "/entry[(50=pt)]/id"); +ExtractValue(@xml, "/entry[(50=pt)]/id") +pt50 +select ExtractValue(@xml, "/entry[(50!=pt)]/id"); +ExtractValue(@xml, "/entry[(50!=pt)]/id") +pt10 +select ExtractValue(@xml, "/entry[(50>pt)]/id"); +ExtractValue(@xml, "/entry[(50>pt)]/id") +pt10 +select ExtractValue(@xml, "/entry[(50>=pt)]/id"); +ExtractValue(@xml, "/entry[(50>=pt)]/id") +pt10 pt50 +select ExtractValue(@xml, "/entry[(50<pt)]/id"); +ExtractValue(@xml, "/entry[(50<pt)]/id") + +select ExtractValue(@xml, "/entry[(50<=pt)]/id"); +ExtractValue(@xml, "/entry[(50<=pt)]/id") +pt50 diff --git a/mysql-test/suite/pbxt/t/alias.test b/mysql-test/suite/pbxt/t/alias.test new file mode 100644 index 00000000000..74894a3721a --- /dev/null +++ b/mysql-test/suite/pbxt/t/alias.test @@ -0,0 +1,91 @@ +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 ( + cont_nr int(11) NOT NULL auto_increment, + ver_nr int(11) NOT NULL default '0', + aufnr int(11) NOT NULL default '0', + username varchar(50) NOT NULL default '', + hdl_nr int(11) NOT NULL default '0', + eintrag date NOT NULL default '0000-00-00', + st_klasse varchar(40) NOT NULL default '', + st_wert varchar(40) NOT NULL default '', + st_zusatz varchar(40) NOT NULL default '', + st_bemerkung varchar(255) NOT NULL default '', + kunden_art varchar(40) NOT NULL default '', + mcbs_knr int(11) default NULL, + mcbs_aufnr int(11) NOT NULL default '0', + schufa_status char(1) default '?', + bemerkung text, + wirknetz text, + wf_igz int(11) NOT NULL default '0', + tarifcode varchar(80) default NULL, + recycle char(1) default NULL, + sim varchar(30) default NULL, + mcbs_tpl varchar(30) default NULL, + emp_nr int(11) NOT NULL default '0', + laufzeit int(11) default NULL, + hdl_name varchar(30) default NULL, + prov_hdl_nr int(11) NOT NULL default '0', + auto_wirknetz varchar(50) default NULL, + auto_billing varchar(50) default NULL, + touch timestamp NOT NULL, + kategorie varchar(50) default NULL, + kundentyp varchar(20) NOT NULL default '', + sammel_rech_msisdn varchar(30) NOT NULL default '', + p_nr varchar(9) NOT NULL default '', + suffix char(3) NOT NULL default '', + PRIMARY KEY (cont_nr), + KEY idx_aufnr(aufnr), + KEY idx_hdl_nr(hdl_nr), + KEY idx_st_klasse(st_klasse), + KEY ver_nr(ver_nr), + KEY eintrag_idx(eintrag), + KEY emp_nr_idx(emp_nr), + KEY wf_igz(wf_igz), + KEY touch(touch), + KEY hdl_tag(eintrag,hdl_nr), + KEY prov_hdl_nr(prov_hdl_nr), + KEY mcbs_aufnr(mcbs_aufnr), + KEY kundentyp(kundentyp), + KEY p_nr(p_nr,suffix) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (3359356,405,3359356,'Mustermann Musterfrau',52500,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1485525,2122316,'+','','N',1909160,'MobilComSuper92000D2',NULL,NULL,'MS9ND2',3,24,'MobilCom Shop Koeln',52500,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359357,468,3359357,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1503580,2139699,'+','','P',1909171,'MobilComSuper9D1T10SFreisprech(Akquise)',NULL,NULL,'MS9NS1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359358,407,3359358,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1501358,2137473,'N','','N',1909159,'MobilComSuper92000D2',NULL,NULL,'MS9ND2',325,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359359,468,3359359,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1507831,2143894,'+','','P',1909162,'MobilComSuper9D1T10SFreisprech(Akquise)',NULL,NULL,'MS9NS1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359360,0,0,'Mustermann Musterfrau',29674907,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1900169997,2414578,'+',NULL,'N',1909148,'',NULL,NULL,'RV99066_2',20,NULL,'POS',29674907,NULL,NULL,20010202105916,'Mobilfunk','','','97317481','007'); +INSERT INTO t1 VALUES (3359361,406,3359361,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag storniert','','(7001-84):Storno, Kd. möchte nicht mehr','privat',NULL,0,'+','','P',1909150,'MobilComSuper92000D1(Akquise)',NULL,NULL,'MS9ND1',325,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); +INSERT INTO t1 VALUES (3359362,406,3359362,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1509984,2145874,'+','','P',1909154,'MobilComSuper92000D1(Akquise)',NULL,NULL,'MS9ND1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); + +# This died because we used the field Kundentyp twice +SELECT ELT(FIELD(kundentyp,'PP','PPA','PG','PGA','FK','FKA','FP','FPA','K','KA','V','VA',''), 'Privat (Private Nutzung)','Privat (Private Nutzung) Sitz im Ausland','Privat (geschaeftliche Nutzung)','Privat (geschaeftliche Nutzung) Sitz im Ausland','Firma (Kapitalgesellschaft)','Firma (Kapitalgesellschaft) Sitz im Ausland','Firma (Personengesellschaft)','Firma (Personengesellschaft) Sitz im Ausland','oeff. rechtl. Koerperschaft','oeff. rechtl. Koerperschaft Sitz im Ausland','Eingetragener Verein','Eingetragener Verein Sitz im Ausland','Typ unbekannt') AS Kundentyp ,kategorie FROM t1 WHERE hdl_nr < 2000000 AND kategorie IN ('Prepaid','Mobilfunk') AND st_klasse = 'Workflow' GROUP BY kundentyp ORDER BY kategorie; + +drop table t1; + +# +# test case for #570 +# + +CREATE TABLE t1 ( + AUFNR varchar(12) NOT NULL default '', + PLNFL varchar(6) NOT NULL default '', + VORNR varchar(4) NOT NULL default '', + xstatus_vor smallint(5) unsigned NOT NULL default '0' +); + +INSERT INTO t1 VALUES ('40004712','000001','0010',9); +INSERT INTO t1 VALUES ('40004712','000001','0020',0); + +UPDATE t1 SET t1.xstatus_vor = Greatest(t1.xstatus_vor,1) WHERE t1.aufnr = +"40004712" AND t1.plnfl = "000001" AND t1.vornr > "0010" ORDER BY t1.vornr +ASC LIMIT 1; + +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/alter_table.test b/mysql-test/suite/pbxt/t/alter_table.test new file mode 100644 index 00000000000..4c328077961 --- /dev/null +++ b/mysql-test/suite/pbxt/t/alter_table.test @@ -0,0 +1,757 @@ +# +# Test of alter table +# +--disable_warnings +drop table if exists t1,t2; +drop database if exists mysqltest; +--enable_warnings + +create table t1 ( +col1 int not null auto_increment primary key, +col2 varchar(30) not null, +col3 varchar (20) not null, +col4 varchar(4) not null, +col5 enum('PENDING', 'ACTIVE', 'DISABLED') not null, +col6 int not null, to_be_deleted int); +insert into t1 values (2,4,3,5,"PENDING",1,7); +alter table t1 +add column col4_5 varchar(20) not null after col4, +add column col7 varchar(30) not null after col5, +add column col8 datetime not null, drop column to_be_deleted, +change column col2 fourth varchar(30) not null after col3, +modify column col6 int not null first; +select * from t1; +drop table t1; + +create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); +insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12); +alter table t1 add column new_col int, order by payoutid,bandid; +select * from t1; +alter table t1 order by bandid,payoutid; +select * from t1; +drop table t1; + +# Check that pack_keys and dynamic length rows are not forced. + +CREATE TABLE t1 ( +GROUP_ID int(10) unsigned DEFAULT '0' NOT NULL, +LANG_ID smallint(5) unsigned DEFAULT '0' NOT NULL, +NAME varchar(80) DEFAULT '' NOT NULL, +PRIMARY KEY (GROUP_ID,LANG_ID), +KEY NAME (NAME)); +#show table status like "t1"; +ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null; +--replace_column 8 # +SHOW FULL COLUMNS FROM t1; +DROP TABLE t1; + +# +# Test of ALTER TABLE ... ORDER BY +# + +create table t1 (n int); +insert into t1 values(9),(3),(12),(10); +alter table t1 order by n; +select * from t1; +drop table t1; + +CREATE TABLE t1 ( + id int(11) unsigned NOT NULL default '0', + category_id tinyint(4) unsigned NOT NULL default '0', + type_id tinyint(4) unsigned NOT NULL default '0', + body text NOT NULL, + user_id int(11) unsigned NOT NULL default '0', + status enum('new','old') NOT NULL default 'new', + PRIMARY KEY (id) +) ENGINE=MyISAM; + +ALTER TABLE t1 ORDER BY t1.id, t1.status, t1.type_id, t1.user_id, t1.body; +DROP TABLE t1; + +# +# The following combination found a hang-bug in MyISAM +# + +CREATE TABLE t1 (AnamneseId int(10) unsigned NOT NULL auto_increment,B BLOB,PRIMARY KEY (AnamneseId)) engine=myisam; +insert into t1 values (null,"hello"); +LOCK TABLES t1 WRITE; +ALTER TABLE t1 ADD Column new_col int not null; +UNLOCK TABLES; +OPTIMIZE TABLE t1; +DROP TABLE t1; + +# +# Drop and add an auto_increment column +# + +create table t1 (i int unsigned not null auto_increment primary key); +insert into t1 values (null),(null),(null),(null); +alter table t1 drop i,add i int unsigned not null auto_increment, drop primary key, add primary key (i); +select * from t1; +drop table t1; + +# +# Bug #2628: 'alter table t1 rename mysqltest.t1' silently drops mysqltest.t1 +# if it exists +# +create table t1 (name char(15)); +insert into t1 (name) values ("current"); +create database mysqltest; +create table mysqltest.t1 (name char(15)); +insert into mysqltest.t1 (name) values ("mysqltest"); +select * from t1; +select * from mysqltest.t1; +--error ER_TABLE_EXISTS_ERROR +alter table t1 rename mysqltest.t1; +select * from t1; +select * from mysqltest.t1; +drop table t1; +drop database mysqltest; + +# +# ALTER TABLE ... ENABLE/DISABLE KEYS + +create table t1 (n1 int not null, n2 int, n3 int, n4 float, + unique(n1), + key (n1, n2, n3, n4), + key (n2, n3, n4, n1), + key (n3, n4, n1, n2), + key (n4, n1, n2, n3) ); +--disable_warnings # PBXT: disable keys not supported +alter table t1 disable keys; +--enable_warnings # PBXT: disable keys not supported +show keys from t1; +#let $1=10000; +let $1=10; +while ($1) +{ + eval insert into t1 values($1,RAND()*1000,RAND()*1000,RAND()); + dec $1; +} +--disable_warnings # PBXT: disable keys not supported +alter table t1 enable keys; +--enable_warnings # PBXT: disable keys not supported +show keys from t1; +drop table t1; + +# +# Alter table and rename +# + +create table t1 (i int unsigned not null auto_increment primary key); +alter table t1 rename t2; +alter table t2 rename t1, add c char(10) comment "no comment"; +show columns from t1; +drop table t1; + +# implicit analyze + +create table t1 (a int, b int); +let $1=100; +while ($1) +{ + eval insert into t1 values(1,$1), (2,$1), (3, $1); + dec $1; +} +alter table t1 add unique (a,b), add key (b); +show keys from t1; +analyze table t1; +show keys from t1; +drop table t1; + +# +# Test of ALTER TABLE DELAYED +# + +CREATE TABLE t1 (i int(10), index(i) ); +--disable_warnings # PBXT: disable keys not supported +ALTER TABLE t1 DISABLE KEYS; +--enable_warnings # PBXT: disable keys not supported +# PBXT: DELAYED not supported +#INSERT DELAYED INTO t1 VALUES(1),(2),(3); +INSERT INTO t1 VALUES(1),(2),(3); +--disable_warnings # PBXT: disable keys not supported +ALTER TABLE t1 ENABLE KEYS; +--enable_warnings # PBXT: disable keys not supported +drop table t1; + +# +# Test ALTER TABLE ENABLE/DISABLE keys when things are locked +# + +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User) +) ENGINE=MyISAM; + +--disable_warnings # PBXT: disable keys not supported +ALTER TABLE t1 DISABLE KEYS; +--enable_warnings # PBXT: disable keys not supported +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty'); +SHOW INDEX FROM t1; +--disable_warnings # PBXT: disable keys not supported +ALTER TABLE t1 ENABLE KEYS; +--enable_warnings # PBXT: disable keys not supported +UNLOCK TABLES; +CHECK TABLES t1; +DROP TABLE t1; + +# +# Test with two keys +# + +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User), + KEY (Host) +) ENGINE=MyISAM; + +--disable_warnings # PBXT: disable keys not supported +ALTER TABLE t1 DISABLE KEYS; +--enable_warnings # PBXT: disable keys not supported +SHOW INDEX FROM t1; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''); +SHOW INDEX FROM t1; +--disable_warnings # PBXT: disable keys not supported +ALTER TABLE t1 ENABLE KEYS; +--enable_warnings # PBXT: disable keys not supported +SHOW INDEX FROM t1; +UNLOCK TABLES; +CHECK TABLES t1; + +# Test RENAME with LOCK TABLES +LOCK TABLES t1 WRITE; +ALTER TABLE t1 RENAME t2; +UNLOCK TABLES; +select * from t2; +DROP TABLE t2; + +# +# Test disable keys with locking +# +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User), + KEY (Host) +) ENGINE=MyISAM; + +LOCK TABLES t1 WRITE; +--disable_warnings # PBXT: disable keys not supported +ALTER TABLE t1 DISABLE KEYS; +--enable_warnings # PBXT: disable keys not supported +SHOW INDEX FROM t1; +DROP TABLE t1; + +# +# BUG#4717 - check for valid table names +# +create table t1 (a int); +--error ER_WRONG_TABLE_NAME +alter table t1 rename to ``; +--error ER_WRONG_TABLE_NAME +rename table t1 to ``; +drop table t1; + +# +# BUG#6236 - ALTER TABLE MODIFY should set implicit NOT NULL on PK columns +# +drop table if exists t1, t2; +create table t1 ( a varchar(10) not null primary key ) engine=myisam; +create table t2 ( a varchar(10) not null primary key ) engine=merge union=(t1); +flush tables; +alter table t1 modify a varchar(10); +show create table t2; +flush tables; +alter table t1 modify a varchar(10) not null; +show create table t2; +drop table if exists t1, t2; + +# The following is also part of bug #6236 (CREATE TABLE didn't properly count +# not null columns for primary keys) + +create table t1 (a int, b int, c int, d int, e int, f int, g int, h int,i int, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM; +insert into t1 (a) values(1); +--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X +show table status like 't1'; +alter table t1 modify a int; +--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X +show table status like 't1'; +drop table t1; +create table t1 (a int not null, b int not null, c int not null, d int not null, e int not null, f int not null, g int not null, h int not null,i int not null, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM; +insert into t1 (a) values(1); +--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X +show table status like 't1'; +drop table t1; + +# +# Test that data get converted when character set is changed +# Test that data doesn't get converted when src or dst is BINARY/BLOB +# +set names koi8r; +create table t1 (a char(10) character set koi8r); +insert into t1 values ('ÔÅÓÔ'); +select a,hex(a) from t1; +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a binary(4); +select a,hex(a) from t1; +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +alter table t1 change a a varchar(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +alter table t1 change a a text character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +delete from t1; + +# +# Test ALTER TABLE .. CHARACTER SET .. +# +show create table t1; +alter table t1 DEFAULT CHARACTER SET latin1; +show create table t1; +alter table t1 CONVERT TO CHARACTER SET latin1; +show create table t1; +alter table t1 DEFAULT CHARACTER SET cp1251; +show create table t1; + +drop table t1; + +# +# Bug#2821 +# Test that table CHARACTER SET does not affect blobs +# +create table t1 (myblob longblob,mytext longtext) +default charset latin1 collate latin1_general_cs; +show create table t1; +alter table t1 character set latin2; +show create table t1; +drop table t1; + +# +# Bug 2361 (Don't drop UNIQUE with DROP PRIMARY KEY) +# + +CREATE TABLE t1 (a int PRIMARY KEY, b INT UNIQUE); +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW CREATE TABLE t1; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t1 DROP PRIMARY KEY; +DROP TABLE t1; + +# BUG#3899 +create table t1 (a int, b int, key(a)); +insert into t1 values (1,1), (2,2); +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t1 drop key no_such_key; +alter table t1 drop key a; +drop table t1; + +# +# BUG 12207 alter table ... discard table space on MyISAM table causes ERROR 2013 (HY000) +# +# Some platforms (Mac OS X, Windows) will send the error message using small letters. +CREATE TABLE T12207(a int) ENGINE=MYISAM; +--replace_result t12207 T12207 +--error ER_ILLEGAL_HA +ALTER TABLE T12207 DISCARD TABLESPACE; +DROP TABLE T12207; + +# +# Bug #6479 ALTER TABLE ... changing charset fails for TEXT columns +# +# The column's character set was changed but the actual data was not +# modified. In other words, the values were reinterpreted +# as UTF8 instead of being converted. +create table t1 (a text) character set koi8r; +insert into t1 values (_koi8r'ÔÅÓÔ'); +select hex(a) from t1; +alter table t1 convert to character set cp1251; +select hex(a) from t1; +drop table t1; + +# +# Test for bug #7884 "Able to add invalid unique index on TIMESTAMP prefix" +# MySQL should not think that packed field with non-zero decimals is +# geometry field and allow to create prefix index which is +# shorter than packed field length. +# +create table t1 ( a timestamp ); +--error ER_WRONG_SUB_KEY +alter table t1 add unique ( a(1) ); +drop table t1; + +# +# Bug #24395: ALTER TABLE DISABLE KEYS doesn't work when modifying the table +# +# This problem happens if the data change is compatible. +# Changing to the same type is compatible for example. +# +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int, key(a)); +show indexes from t1; +--echo "this used not to disable the index" +--disable_warnings # PBXT: disable keys not supported +alter table t1 modify a int, disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--disable_warnings # PBXT: disable keys not supported +alter table t1 enable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--disable_warnings # PBXT: disable keys not supported +alter table t1 modify a bigint, disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--disable_warnings # PBXT: disable keys not supported +alter table t1 enable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--disable_warnings # PBXT: disable keys not supported +alter table t1 add b char(10), disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--disable_warnings # PBXT: disable keys not supported +alter table t1 add c decimal(10,2), enable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--echo "this however did" +--disable_warnings # PBXT: disable keys not supported +alter table t1 disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +desc t1; + +alter table t1 add d decimal(15,5); +--echo "The key should still be disabled" +show indexes from t1; + +drop table t1; + +--echo "Now will test with one unique index" +create table t1(a int, b char(10), unique(a)); +show indexes from t1; +--disable_warnings # PBXT: disable keys not supported +alter table t1 disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; +--disable_warnings # PBXT: disable keys not supported +alter table t1 enable keys; +--enable_warnings # PBXT: disable keys not supported + +--echo "If no copy on noop change, this won't touch the data file" +--echo "Unique index, no change" +--disable_warnings # PBXT: disable keys not supported +alter table t1 modify a int, disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--echo "Change the type implying data copy" +--echo "Unique index, no change" +--disable_warnings # PBXT: disable keys not supported +alter table t1 modify a bigint, disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +alter table t1 modify a bigint; +show indexes from t1; + +alter table t1 modify a int; +show indexes from t1; + +drop table t1; + +--echo "Now will test with one unique and one non-unique index" +create table t1(a int, b char(10), unique(a), key(b)); +show indexes from t1; +--disable_warnings # PBXT: disable keys not supported +alter table t1 disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; +--disable_warnings # PBXT: disable keys not supported +alter table t1 enable keys; +--enable_warnings # PBXT: disable keys not supported + + +--echo "If no copy on noop change, this won't touch the data file" +--echo "The non-unique index will be disabled" +--disable_warnings # PBXT: disable keys not supported +alter table t1 modify a int, disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; +--disable_warnings # PBXT: disable keys not supported +alter table t1 enable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--echo "Change the type implying data copy" +--echo "The non-unique index will be disabled" +--disable_warnings # PBXT: disable keys not supported +alter table t1 modify a bigint, disable keys; +--enable_warnings # PBXT: disable keys not supported +show indexes from t1; + +--echo "Change again the type, but leave the indexes as_is" +alter table t1 modify a int; +show indexes from t1; +--echo "Try the same. When data is no copied on similar tables, this is noop" +alter table t1 modify a int; +show indexes from t1; + +drop table t1; + + +# +# Bug#11493 - Alter table rename to default database does not work without +# db name qualifying +# +create database mysqltest; +create table t1 (c1 int); +# Move table to other database. +alter table t1 rename mysqltest.t1; +# Assure that it has moved. +--error ER_BAD_TABLE_ERROR +drop table t1; +# Move table back. +alter table mysqltest.t1 rename t1; +# Assure that it is back. +drop table t1; +# Now test for correct message if no database is selected. +# Create t1 in 'test'. +create table t1 (c1 int); +# Change to other db. +use mysqltest; +# Drop the current db. This de-selects any db. +drop database mysqltest; +# Now test for correct message. +--error ER_NO_DB_ERROR +alter table test.t1 rename t1; +# Check that explicit qualifying works even with no selected db. +alter table test.t1 rename test.t1; +# Go back to standard 'test' db. +use test; +drop table t1; + +# +# BUG#23404 - ROW_FORMAT=FIXED option is lost is an index is added to the +# table +# +CREATE TABLE t1(a INT) ROW_FORMAT=FIXED; +CREATE INDEX i1 ON t1(a); +SHOW CREATE TABLE t1; +DROP INDEX i1 ON t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# +# Bug#24219 - ALTER TABLE ... RENAME TO ... , DISABLE KEYS leads to crash +# +--disable_warnings +DROP TABLE IF EXISTS bug24219; +DROP TABLE IF EXISTS bug24219_2; +--enable_warnings + +CREATE TABLE bug24219 (a INT, INDEX(a)); + +SHOW INDEX FROM bug24219; + +--disable_warnings # PBXT: disable keys not supported +ALTER TABLE bug24219 RENAME TO bug24219_2, DISABLE KEYS; +--enable_warnings # PBXT: disable keys not supported + +SHOW INDEX FROM bug24219_2; + +DROP TABLE bug24219_2; + +# End of 4.1 tests + +# +# Bug #14693 (ALTER SET DEFAULT doesn't work) +# + +create table t1 (mycol int(10) not null); +alter table t1 alter column mycol set default 0; +desc t1; +drop table t1; + +# +# Some additional tests for new, faster alter table. Note that most of the +# whole alter table code is being tested all around the test suite already. +# + +create table t1 (v varchar(32)); +insert into t1 values ('def'),('abc'),('hij'),('3r4f'); +select * from t1; +# Fast alter, no copy performed +alter table t1 change v v2 varchar(32); +select * from t1; +# Fast alter, no copy performed +alter table t1 change v2 v varchar(64); +select * from t1; +update t1 set v = 'lmn' where v = 'hij'; +select * from t1; +# Regular alter table +alter table t1 add i int auto_increment not null primary key first; +select * from t1; +update t1 set i=5 where i=3; +select * from t1; +alter table t1 change i i bigint; +select * from t1; +alter table t1 add unique key (i, v); +select * from t1 where i between 2 and 4 and v in ('def','3r4f','lmn'); +drop table t1; + +# +# Bug#6073 "ALTER table minor glich": ALTER TABLE complains that an index +# without # prefix is not allowed for TEXT columns, while index +# is defined with prefix. +# +create table t1 (t varchar(255) default null, key t (t(80))) +engine=myisam default charset=latin1; +alter table t1 change t t text; +drop table t1; + +# +# Bug#18038 MySQL server corrupts binary columns data +# + +CREATE TABLE t1 (s CHAR(8) BINARY); +INSERT INTO t1 VALUES ('test'); +SELECT LENGTH(s) FROM t1; +ALTER TABLE t1 MODIFY s CHAR(10) BINARY; +SELECT LENGTH(s) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (s BINARY(8)); +INSERT INTO t1 VALUES ('test'); +SELECT LENGTH(s) FROM t1; +SELECT HEX(s) FROM t1; +ALTER TABLE t1 MODIFY s BINARY(10); +SELECT HEX(s) FROM t1; +SELECT LENGTH(s) FROM t1; +DROP TABLE t1; + +# +# Bug#19386: Multiple alter causes crashed table +# The trailing column would get corrupted data, or server could not even read +# it. +# + +CREATE TABLE t1 (v VARCHAR(3), b INT); +INSERT INTO t1 VALUES ('abc', 5); +SELECT * FROM t1; +ALTER TABLE t1 MODIFY COLUMN v VARCHAR(4); +SELECT * FROM t1; +DROP TABLE t1; + +# End of 5.0 tests + +# +# Bug#18775 - Temporary table from alter table visible to other threads +# +# Check if special characters work and duplicates are detected. +--disable_warnings +DROP TABLE IF EXISTS `t+1`, `t+2`; +--enable_warnings +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +CREATE TABLE `t+1` (c1 INT); +--error ER_TABLE_EXISTS_ERROR +ALTER TABLE `t+1` RENAME `t+2`; +DROP TABLE `t+1`, `t+2`; +# +# Same for temporary tables though these names do not become file names. +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +--error ER_TABLE_EXISTS_ERROR +ALTER TABLE `tt+1` RENAME `tt+2`; +SHOW CREATE TABLE `tt+1`; +SHOW CREATE TABLE `tt+2`; +DROP TABLE `tt+1`, `tt+2`; +# +# Check if special characters as in tmp_file_prefix work. +CREATE TABLE `#sql1` (c1 INT); +CREATE TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +RENAME TABLE `#sql1` TO `@0023sql1`; +RENAME TABLE `@0023sql2` TO `#sql2`; +SHOW TABLES; +ALTER TABLE `@0023sql1` RENAME `#sql-1`; +ALTER TABLE `#sql2` RENAME `@0023sql-2`; +SHOW TABLES; +INSERT INTO `#sql-1` VALUES (1); +INSERT INTO `@0023sql-2` VALUES (2); +DROP TABLE `#sql-1`, `@0023sql-2`; +# +# Same for temporary tables though these names do not become file names. +CREATE TEMPORARY TABLE `#sql1` (c1 INT); +CREATE TEMPORARY TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +ALTER TABLE `#sql1` RENAME `@0023sql1`; +ALTER TABLE `@0023sql2` RENAME `#sql2`; +SHOW TABLES; +INSERT INTO `#sql2` VALUES (1); +INSERT INTO `@0023sql1` VALUES (2); +SHOW CREATE TABLE `#sql2`; +SHOW CREATE TABLE `@0023sql1`; +DROP TABLE `#sql2`, `@0023sql1`; + +# +# Bug #22369: Alter table rename combined with other alterations causes lost tables +# +# This problem happens if the data change is compatible. +# Changing to the same type is compatible for example. +# +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings +CREATE TABLE t1 ( + int_field INTEGER UNSIGNED NOT NULL, + char_field CHAR(10), + INDEX(`int_field`) +); + +DESCRIBE t1; + +SHOW INDEXES FROM t1; + +INSERT INTO t1 VALUES (1, "edno"), (1, "edno"), (2, "dve"), (3, "tri"), (5, "pet"); +--echo "Non-copy data change - new frm, but old data and index files" +ALTER TABLE t1 + CHANGE int_field unsigned_int_field INTEGER UNSIGNED NOT NULL, + RENAME t2; + +--error ER_NO_SUCH_TABLE +SELECT * FROM t1 ORDER BY int_field; +SELECT * FROM t2 ORDER BY unsigned_int_field; +DESCRIBE t2; +DESCRIBE t2; +ALTER TABLE t2 MODIFY unsigned_int_field BIGINT UNSIGNED NOT NULL; +DESCRIBE t2; + +DROP TABLE t2; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/analyze.test b/mysql-test/suite/pbxt/t/analyze.test new file mode 100644 index 00000000000..1f3ba82dfd1 --- /dev/null +++ b/mysql-test/suite/pbxt/t/analyze.test @@ -0,0 +1,78 @@ +# +# Bug #10901 Analyze Table on new table destroys table +# This is minimal test case to get error +# The problem was that analyze table wrote the shared state to the +# file and this didn't include the inserts while locked. A check was +# needed to ensure that state information was not updated when +# executing analyze table for a locked table. The analyze table had +# to be within locks and check table had to be after unlocking since +# then it brings the wrong state from disk rather than from the +# currently correct internal state. The insert is needed since it +# changes the file state, number of records. The fix is to +# synchronise the state of the shared state and the current state +# before calling mi_state_info_write +# + +create table t1 (a bigint); +lock tables t1 write; +insert into t1 values(0); +analyze table t1; +unlock tables; +check table t1; + +drop table t1; + +create table t1 (a bigint); +insert into t1 values(0); +lock tables t1 write; +delete from t1; +analyze table t1; +unlock tables; +check table t1; + +drop table t1; + +create table t1 (a bigint); +insert into t1 values(0); +analyze table t1; +check table t1; + +drop table t1; + +# Bug #14902 ANALYZE TABLE fails to recognize up-to-date tables +# minimal test case to get an error. +# The problem is happening when analysing table with FT index that +# contains stopwords only. The first execution of analyze table should +# mark index statistics as up to date so that next execution of this +# statement will end up with Table is up to date status. +create table t1 (a mediumtext, fulltext key key1(a)) charset utf8 collate utf8_general_ci engine myisam; +insert into t1 values ('hello'); + +analyze table t1; +analyze table t1; + +drop table t1; + +# +# procedure in PS BUG#13673 +# +CREATE TABLE t1 (a int); +prepare stmt1 from "SELECT * FROM t1 PROCEDURE ANALYSE()"; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; +drop table t1; + +# +# bug#15225 (ANALYZE temporary has no effect) +# +create temporary table t1(a int, index(a)); +insert into t1 values('1'),('2'),('3'),('4'),('5'); +analyze table t1; +show index from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/ansi.test b/mysql-test/suite/pbxt/t/ansi.test new file mode 100644 index 00000000000..b4ecfeae722 --- /dev/null +++ b/mysql-test/suite/pbxt/t/ansi.test @@ -0,0 +1,44 @@ +# +# Test of ansi mode +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +set sql_mode="MySQL40"; +select @@sql_mode; +set @@sql_mode="ANSI"; +select @@sql_mode; + +# Test some functions that works different in ansi mode + +SELECT 'A' || 'B'; + +# Test GROUP BY behaviour + +CREATE TABLE t1 (id INT, id2 int); +SELECT id,NULL,1,1.1,'a' FROM t1 GROUP BY id; +#No --error 1055 error due to temporary fix for BUG#8510: +#ONLY_FULL_GROUP_BY is overly restrictive, so remove it from ANSI mode. +SELECT id FROM t1 GROUP BY id2; +drop table t1; + +SET @@SQL_MODE=""; + +# Bug#14515 + +CREATE TABLE t1 (i int auto_increment NOT NULL, PRIMARY KEY (i)); +SHOW CREATE TABLE t1; +SET @@SQL_MODE="MYSQL323"; +SHOW CREATE TABLE t1; +SET @@SQL_MODE="MYSQL40"; +SHOW CREATE TABLE t1; +SET @@SQL_MODE="NO_FIELD_OPTIONS"; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/auto_increment.test b/mysql-test/suite/pbxt/t/auto_increment.test new file mode 100644 index 00000000000..1819e0cba1f --- /dev/null +++ b/mysql-test/suite/pbxt/t/auto_increment.test @@ -0,0 +1,323 @@ +# +# Test of auto_increment; The test for BDB tables is in bdb.test +# +--disable_warnings +drop table if exists t1; +drop table if exists t2; +--enable_warnings +SET SQL_WARNINGS=1; + +create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam auto_increment=3; +insert into t1 values (1,1),(NULL,3),(NULL,4); +delete from t1 where a=4; +insert into t1 values (NULL,5),(NULL,6); +select * from t1; +delete from t1 where a=6; +#show table status like "t1"; +replace t1 values (3,1); +ALTER TABLE t1 add c int; +replace t1 values (3,3,3); +insert into t1 values (NULL,7,7); +update t1 set a=8,b=b+1,c=c+1 where a=7; +insert into t1 values (NULL,9,9); +select * from t1; +drop table t1; + +create table t1 ( + skey tinyint unsigned NOT NULL auto_increment PRIMARY KEY, + sval char(20) +); +insert into t1 values (NULL, "hello"); +insert into t1 values (NULL, "hey"); +select * from t1; +select _rowid,t1._rowid,skey,sval from t1; +drop table t1; + +# +# Test auto_increment on sub key +# +create table t1 (a char(10) not null, b int not null auto_increment, primary key(a,b)); +insert into t1 values ("a",1),("b",2),("a",2),("c",1); +insert into t1 values ("a",NULL),("b",NULL),("c",NULL),("e",NULL); +insert into t1 (a) values ("a"),("b"),("c"),("d"); +insert into t1 (a) values ('k'),('d'); +insert into t1 (a) values ("a"); +insert into t1 values ("d",last_insert_id()); +select * from t1; +drop table t1; + +create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ordid), index(ord,ordid)); +insert into t1 (ordid,ord) values (NULL,'sdj'),(NULL,'sdj'); +select * from t1; +drop table t1; + +create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)); +insert into t1 values (NULL,'sdj'),(NULL,'sdj'),(NULL,"abc"),(NULL,'abc'),(NULL,'zzz'),(NULL,'sdj'),(NULL,'abc'); +select * from t1; +drop table t1; + +create table t1 (sid char(5), id int(2) NOT NULL auto_increment, key(sid, id)); +create table t2 (sid char(20), id int(2)); +insert into t2 values ('skr',NULL),('skr',NULL),('test',NULL); +insert into t1 select * from t2; +select * from t1; +drop table t1,t2; + +# +# Test of auto_increment columns when they are set to 0 +# + +create table t1 (a int not null primary key auto_increment); +insert into t1 values (0); +update t1 set a=0; +select * from t1; +check table t1; +drop table t1; + +# +# Test negative values (Bug #1366) +# + +create table t1 (a int not null auto_increment primary key); +insert into t1 values (NULL); +insert into t1 values (-1); +select last_insert_id(); +insert into t1 values (NULL); +select * from t1; +drop table t1; + +create table t1 (a int not null auto_increment primary key) /*!40102 engine=heap */; +insert into t1 values (NULL); +insert into t1 values (-1); +select last_insert_id(); +insert into t1 values (NULL); +select * from t1; +drop table t1; +# +# last_insert_id() madness +# +create table t1 (i tinyint unsigned not null auto_increment primary key); +insert into t1 set i = 254; +insert into t1 set i = null; +select last_insert_id(); +explain extended select last_insert_id(); +--error ER_DUP_ENTRY +insert into t1 set i = 254; +select last_insert_id(); +--error 1467 +insert into t1 set i = null; +select last_insert_id(); +drop table t1; + +create table t1 (i tinyint unsigned not null auto_increment, key (i)); +insert into t1 set i = 254; +insert into t1 set i = null; +select last_insert_id(); +--error 1467 +insert into t1 set i = null; +select last_insert_id(); +drop table t1; + +create table t1 (i tinyint unsigned not null auto_increment primary key, b int, unique (b)); +insert into t1 values (NULL, 10); +select last_insert_id(); +insert into t1 values (NULL, 15); +select last_insert_id(); +--error ER_DUP_ENTRY +insert into t1 values (NULL, 10); +select last_insert_id(); + +drop table t1; + +create table t1(a int auto_increment,b int null,primary key(a)); +SET SQL_MODE=NO_AUTO_VALUE_ON_ZERO; +insert into t1(a,b)values(NULL,1); +insert into t1(a,b)values(200,2); +insert into t1(a,b)values(0,3); +insert into t1(b)values(4); +insert into t1(b)values(5); +insert into t1(b)values(6); +insert into t1(b)values(7); +select * from t1 order by b; +alter table t1 modify b mediumint; +select * from t1 order by b; +create table t2 (a int); +insert t2 values (1),(2); +alter table t2 add b int auto_increment primary key; +select * from t2; +drop table t2; +delete from t1 where a=0; +update t1 set a=0 where b=5; +select * from t1 order by b; +delete from t1 where a=0; +--error 1048 +update t1 set a=NULL where b=6; +update t1 set a=300 where b=7; +SET SQL_MODE=''; +insert into t1(a,b)values(NULL,8); +insert into t1(a,b)values(400,9); +insert into t1(a,b)values(0,10); +insert into t1(b)values(11); +insert into t1(b)values(12); +insert into t1(b)values(13); +insert into t1(b)values(14); +select * from t1 order by b; +delete from t1 where a=0; +update t1 set a=0 where b=12; +select * from t1 order by b; +delete from t1 where a=0; +--error 1048 +update t1 set a=NULL where b=13; +update t1 set a=500 where b=14; +select * from t1 order by b; +drop table t1; + +# +# Test of behavior of ALTER TABLE when coulmn containing NULL or zeroes is +# converted to AUTO_INCREMENT column +# +create table t1 (a bigint); +insert into t1 values (1), (2), (3), (NULL), (NULL); +alter table t1 modify a bigint not null auto_increment primary key; +select * from t1; +drop table t1; + +create table t1 (a bigint); +insert into t1 values (1), (2), (3), (0), (0); +alter table t1 modify a bigint not null auto_increment primary key; +select * from t1; +drop table t1; + +# We still should be able to preserve zero in NO_AUTO_VALUE_ON_ZERO mode +create table t1 (a bigint); +insert into t1 values (0), (1), (2), (3); +set sql_mode=NO_AUTO_VALUE_ON_ZERO; +alter table t1 modify a bigint not null auto_increment primary key; +set sql_mode= ''; +select * from t1; +drop table t1; + +# It also sensible to preserve zeroes if we are converting auto_increment +# column to auto_increment column (or not touching it at all, which is more +# common case probably) +create table t1 (a int auto_increment primary key , b int null); +set sql_mode=NO_AUTO_VALUE_ON_ZERO; +insert into t1 values (0,1),(1,2),(2,3); +select * from t1; +set sql_mode= ''; +alter table t1 modify b varchar(255); +insert into t1 values (0,4); +select * from t1; +drop table t1; + +# +# BUG #10045: Problem with composite AUTO_INCREMENT + BLOB key + +CREATE TABLE t1 ( a INT AUTO_INCREMENT, b BLOB, PRIMARY KEY (a,b(10))); +INSERT INTO t1 (b) VALUES ('aaaa'); +CHECK TABLE t1; +INSERT INTO t1 (b) VALUES (''); +CHECK TABLE t1; +INSERT INTO t1 (b) VALUES ('bbbb'); +CHECK TABLE t1; +DROP TABLE IF EXISTS t1; + +# BUG #19025: + +CREATE TABLE `t1` ( + t1_name VARCHAR(255) DEFAULT NULL, + t1_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + KEY (t1_name), + PRIMARY KEY (t1_id) +) AUTO_INCREMENT = 1000; + +INSERT INTO t1 (t1_name) VALUES('MySQL'); +INSERT INTO t1 (t1_name) VALUES('MySQL'); +INSERT INTO t1 (t1_name) VALUES('MySQL'); + +SELECT * from t1; + +SHOW CREATE TABLE `t1`; + +DROP TABLE `t1`; + +# +# Bug #6880: LAST_INSERT_ID() within a statement +# + +create table t1(a int not null auto_increment primary key); +create table t2(a int not null auto_increment primary key, t1a int); +insert into t1 values(NULL); +insert into t2 values (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()); +insert into t1 values (NULL); +insert into t2 values (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()), +(NULL, LAST_INSERT_ID()); +insert into t1 values (NULL); +insert into t2 values (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()), +(NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()); +select * from t2; +drop table t1, t2; + +--echo End of 4.1 tests + +# +# Bug #11080 & #11005 Multi-row REPLACE fails on a duplicate key error +# + +CREATE TABLE t1 ( `a` int(11) NOT NULL auto_increment, `b` int(11) default NULL,PRIMARY KEY (`a`),UNIQUE KEY `b` (`b`)); +insert into t1 (b) values (1); +replace into t1 (b) values (2), (1), (3); +select * from t1; +truncate table t1; +insert into t1 (b) values (1); +replace into t1 (b) values (2); +replace into t1 (b) values (1); +replace into t1 (b) values (3); +select * from t1 order by a; # PBXT: Required for consistent result +drop table t1; + +create table t1 (rowid int not null auto_increment, val int not null,primary +key (rowid), unique(val)); +replace into t1 (val) values ('1'),('2'); +replace into t1 (val) values ('1'),('2'); +--error ER_DUP_ENTRY +insert into t1 (val) values ('1'),('2'); +select * from t1; +drop table t1; + +# +# Test that update changes internal auto-increment value +# + +create table t1 (a int not null auto_increment primary key, val int); +insert into t1 (val) values (1); +update t1 set a=2 where a=1; +insert into t1 (val) values (1); +select * from t1 order by a; # PBXT: Required for consistent result +drop table t1; + +# +# Test key duplications with auto-increment in ALTER TABLE +# bug #14573 +# +CREATE TABLE t1 (t1 INT(10) PRIMARY KEY, t2 INT(10)); +INSERT INTO t1 VALUES(0, 0); +INSERT INTO t1 VALUES(1, 1); +--error ER_DUP_ENTRY +ALTER TABLE t1 CHANGE t1 t1 INT(10) auto_increment; +DROP TABLE t1; + +# Test of REPLACE when it does INSERT+DELETE and not UPDATE: +# see if it sets LAST_INSERT_ID() ok +create table t1 (a int primary key auto_increment, b int, c int, d timestamp default current_timestamp, unique(b),unique(c)); +insert into t1 values(null,1,1,now()); +insert into t1 values(null,0,0,null); +# this will delete two rows +replace into t1 values(null,1,0,null); +select last_insert_id(); + +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/bench_count_distinct.test b/mysql-test/suite/pbxt/t/bench_count_distinct.test new file mode 100644 index 00000000000..a40846c1dec --- /dev/null +++ b/mysql-test/suite/pbxt/t/bench_count_distinct.test @@ -0,0 +1,25 @@ +# +# Test of count(distinct ..) +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1(n int not null, key(n)) delay_key_write = 1; +let $1=100; +disable_query_log; +while ($1) +{ + eval insert into t1 values($1); + eval insert into t1 values($1); + dec $1; +} +enable_query_log; +select count(distinct n) from t1; +explain extended select count(distinct n) from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/bigint.test b/mysql-test/suite/pbxt/t/bigint.test new file mode 100644 index 00000000000..093dd5f38c9 --- /dev/null +++ b/mysql-test/suite/pbxt/t/bigint.test @@ -0,0 +1,293 @@ +# +# Initialize + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + +# +# Test of reading of bigint values +# +select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296; +select 9223372036854775807,-009223372036854775808; +select +9999999999999999999,-9999999999999999999; +select cast(9223372036854775808 as unsigned)+1; +select 9223372036854775808+1; +select -(0-3),round(-(0-3)), round(9999999999999999999); +select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001; +select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001; +select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16); + +# +# In 3.23 we have to disable the test of column to bigint as +# this fails on AIX powerpc (the resolution for double is not good enough) +# This will work on 4.0 as we then have internal handling of bigint variables. +# + +create table t1 (a bigint unsigned not null, primary key(a)); +insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612); +select * from t1; +select * from t1 where a=18446744073709551615; +# select * from t1 where a='18446744073709551615'; +delete from t1 where a=18446744073709551615; +select * from t1; +drop table t1; + +create table t1 ( a int not null default 1, big bigint ); +insert into t1 (big) values (-1),(12345678901234567),(9223372036854775807),(18446744073709551615); +select * from t1; +select min(big),max(big),max(big)-1 from t1; +select min(big),max(big),max(big)-1 from t1 group by a; +alter table t1 modify big bigint unsigned not null; +select min(big),max(big),max(big)-1 from t1; +select min(big),max(big),max(big)-1 from t1 group by a; +insert into t1 (big) values (18446744073709551615); +select * from t1; +select min(big),max(big),max(big)-1 from t1; +select min(big),max(big),max(big)-1 from t1 group by a; +alter table t1 add key (big); +select min(big),max(big),max(big)-1 from t1; +select min(big),max(big),max(big)-1 from t1 group by a; +alter table t1 modify big bigint not null; +select * from t1; +select min(big),max(big),max(big)-1 from t1; +select min(big),max(big),max(big)-1 from t1 group by a; +drop table t1; + +# +# Test problem with big values for auto_increment +# + +create table t1 (id bigint auto_increment primary key, a int) auto_increment=9999999999; +insert into t1 values (null,1); +select * from t1; +select * from t1 limit 9999999999; +drop table t1; + +# +# Item_uint::save_to_field() +# BUG#1845 +# This can't be fixed in MySQL 4.0 without loosing precisions for bigints +# + +CREATE TABLE t1 ( quantity decimal(60,0)); +insert into t1 values (10000000000000000000); +insert into t1 values (10000000000000000000.0); +insert into t1 values ('10000000000000000000'); +select * from t1; +drop table t1; + +# atof() behaviour is different of different systems. to be fixed in 4.1 +SELECT '0x8000000000000001'+0; + +# Test for BUG#8562: joins over BIGINT UNSIGNED value + constant propagation +create table t1 ( + value64 bigint unsigned not null, + value32 integer not null, + primary key(value64, value32) +); + +create table t2 ( + value64 bigint unsigned not null, + value32 integer not null, + primary key(value64, value32) +); + +insert into t1 values(17156792991891826145, 1); +insert into t1 values( 9223372036854775807, 2); +insert into t2 values(17156792991891826145, 3); +insert into t2 values( 9223372036854775807, 4); + +select * from t1; +select * from t2; + +select * from t1, t2 where t1.value64=17156792991891826145 and +t2.value64=17156792991891826145; +select * from t1, t2 where t1.value64=17156792991891826145 and +t2.value64=t1.value64; + +select * from t1, t2 where t1.value64= 9223372036854775807 and +t2.value64=9223372036854775807; +select * from t1, t2 where t1.value64= 9223372036854775807 and +t2.value64=t1.value64; + +drop table t1, t2; + +# End of 4.1 tests + +# +# Test of CREATE ... SELECT and unsigned integers +# + +create table t1 select 1 as 'a'; +show create table t1; +drop table t1; +create table t1 select 9223372036854775809 as 'a'; +show create table t1; +select * from t1; +drop table t1; +DROP DATABASE IF EXISTS `scott`; + + +# +# Check various conversions from/to unsigned bigint. +# + +create table t1 (a char(100), b varchar(100), c text, d blob); +insert into t1 values( + 18446744073709551615,18446744073709551615, + 18446744073709551615, 18446744073709551615 +); + +insert into t1 values (-1 | 0,-1 | 0,-1 | 0 ,-1 | 0); +select * from t1; +drop table t1; + +create table t1 ( quantity decimal(2) unsigned); +insert into t1 values (500), (-500), (~0), (-1); +select * from t1; +drop table t1; + +# +# Test of storing decimal values in BIGINT range +# (Bug #12750: Incorrect storage of 9999999999999999999 in DECIMAL(19, 0)) +# + +CREATE TABLE t1 ( + `col1` INT(1) NULL, + `col2` INT(2) NULL, + `col3` INT(3) NULL, + `col4` INT(4) NULL, + `col5` INT(5) NULL, + `col6` INT(6) NULL, + `col7` INT(7) NULL, + `col8` INT(8) NULL, + `col9` INT(9) NULL, + `col10` BIGINT(10) NULL, + `col11` BIGINT(11) NULL, + `col12` BIGINT(12) NULL, + `col13` BIGINT(13) NULL, + `col14` BIGINT(14) NULL, + `col15` BIGINT(15) NULL, + `col16` BIGINT(16) NULL, + `col17` BIGINT(17) NULL, + `col18` BIGINT(18) NULL, + `col19` DECIMAL(19, 0) NULL, + `col20` DECIMAL(20, 0) NULL, + `col21` DECIMAL(21, 0) NULL, + `col22` DECIMAL(22, 0) NULL, + `col23` DECIMAL(23, 0) NULL, + `col24` DECIMAL(24, 0) NULL, + `col25` DECIMAL(25, 0) NULL, + `col26` DECIMAL(26, 0) NULL, + `col27` DECIMAL(27, 0) NULL, + `col28` DECIMAL(28, 0) NULL, + `col29` DECIMAL(29, 0) NULL, + `col30` DECIMAL(30, 0) NULL, + `col31` DECIMAL(31, 0) NULL, + `col32` DECIMAL(32, 0) NULL, + `col33` DECIMAL(33, 0) NULL, + `col34` DECIMAL(34, 0) NULL, + `col35` DECIMAL(35, 0) NULL, + `col36` DECIMAL(36, 0) NULL, + `col37` DECIMAL(37, 0) NULL, + `col38` DECIMAL(38, 0) NULL, + `fix1` DECIMAL(38, 1) NULL, + `fix2` DECIMAL(38, 2) NULL, + `fix3` DECIMAL(38, 3) NULL, + `fix4` DECIMAL(38, 4) NULL, + `fix5` DECIMAL(38, 5) NULL, + `fix6` DECIMAL(38, 6) NULL, + `fix7` DECIMAL(38, 7) NULL, + `fix8` DECIMAL(38, 8) NULL, + `fix9` DECIMAL(38, 9) NULL, + `fix10` DECIMAL(38, 10) NULL, + `fix11` DECIMAL(38, 11) NULL, + `fix12` DECIMAL(38, 12) NULL, + `fix13` DECIMAL(38, 13) NULL, + `fix14` DECIMAL(38, 14) NULL, + `fix15` DECIMAL(38, 15) NULL, + `fix16` DECIMAL(38, 16) NULL, + `fix17` DECIMAL(38, 17) NULL, + `fix18` DECIMAL(38, 18) NULL, + `fix19` DECIMAL(38, 19) NULL, + `fix20` DECIMAL(38, 20) NULL, + `fix21` DECIMAL(38, 21) NULL, + `fix22` DECIMAL(38, 22) NULL, + `fix23` DECIMAL(38, 23) NULL, + `fix24` DECIMAL(38, 24) NULL, + `fix25` DECIMAL(38, 25) NULL, + `fix26` DECIMAL(38, 26) NULL, + `fix27` DECIMAL(38, 27) NULL, + `fix28` DECIMAL(38, 28) NULL, + `fix29` DECIMAL(38, 29) NULL, + `fix30` DECIMAL(38, 30) NULL +); + +INSERT INTO t1(`col1`, `col2`, `col3`, `col4`, `col5`, `col6`, `col7`, `col8`, `col9`, `col10`, `col11`, `col12`, `col13`, `col14`, `col15`, `col16`, `col17`, `col18`, `col19`, `col20`, `col21`, `col22`, `col23`, `col24`, `col25`, `col26`, `col27`, `col28`, `col29`, `col30`, `col31`, `col32`, `col33`, `col34`, `col35`, `col36`, `col37`, `col38`, `fix1`, `fix2`, `fix3`, `fix4`, `fix5`, `fix6`, `fix7`, `fix8`, `fix9`, `fix10`, `fix11`, `fix12`, `fix13`, `fix14`, `fix15`, `fix16`, `fix17`, `fix18`, `fix19`, `fix20`, `fix21`, `fix22`, `fix23`, `fix24`, `fix25`, `fix26`, `fix27`, `fix28`, `fix29`, `fix30`) +VALUES (9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, +9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, +999999999999999, 9999999999999999, 99999999999999999, 999999999999999999, +9999999999999999999, 99999999999999999999, 999999999999999999999, +9999999999999999999999, 99999999999999999999999, 999999999999999999999999, +9999999999999999999999999, 99999999999999999999999999, +999999999999999999999999999, 9999999999999999999999999999, +99999999999999999999999999999, 999999999999999999999999999999, +9999999999999999999999999999999, 99999999999999999999999999999999, +999999999999999999999999999999999, 9999999999999999999999999999999999, +99999999999999999999999999999999999, 999999999999999999999999999999999999, +9999999999999999999999999999999999999, 99999999999999999999999999999999999999, +9999999999999999999999999999999999999.9, +999999999999999999999999999999999999.99, +99999999999999999999999999999999999.999, +9999999999999999999999999999999999.9999, +999999999999999999999999999999999.99999, +99999999999999999999999999999999.999999, +9999999999999999999999999999999.9999999, +999999999999999999999999999999.99999999, +99999999999999999999999999999.999999999, +9999999999999999999999999999.9999999999, +999999999999999999999999999.99999999999, +99999999999999999999999999.999999999999, +9999999999999999999999999.9999999999999, +999999999999999999999999.99999999999999, +99999999999999999999999.999999999999999, +9999999999999999999999.9999999999999999, +999999999999999999999.99999999999999999, +99999999999999999999.999999999999999999, +9999999999999999999.9999999999999999999, +999999999999999999.99999999999999999999, +99999999999999999.999999999999999999999, +9999999999999999.9999999999999999999999, +999999999999999.99999999999999999999999, +99999999999999.999999999999999999999999, +9999999999999.9999999999999999999999999, +999999999999.99999999999999999999999999, +99999999999.999999999999999999999999999, +9999999999.9999999999999999999999999999, +999999999.99999999999999999999999999999, +99999999.999999999999999999999999999999); + +SELECT * FROM t1; +DROP TABLE t1; + +#bug #9088 BIGINT WHERE CLAUSE +create table t1 (bigint_col bigint unsigned); +insert into t1 values (17666000000000000000); +select * from t1 where bigint_col=17666000000000000000; +select * from t1 where bigint_col='17666000000000000000'; +drop table t1; + +--echo +--echo bug 19955 -- mod is signed with bigint + +select cast(10000002383263201056 as unsigned) mod 50 as result; + +create table t1 (c1 bigint unsigned); +insert into t1 values (10000002383263201056); +select c1 mod 50 as result from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/binary.test b/mysql-test/suite/pbxt/t/binary.test new file mode 100644 index 00000000000..d7879f28294 --- /dev/null +++ b/mysql-test/suite/pbxt/t/binary.test @@ -0,0 +1,107 @@ +# +# test sort,min and max on binary fields +# +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1 (name char(20) not null, primary key (name)); +create table t2 (name char(20) binary not null, primary key (name)); +insert into t1 values ("å"); +insert into t1 values ("ä"); +insert into t1 values ("ö"); +insert into t2 select * from t1; + +select * from t1 order by name; +select concat("*",name,"*") from t1 order by 1; +select min(name),min(concat("*",name,"*")),max(name),max(concat("*",name,"*")) from t1; +select * from t2 order by name; +select concat("*",name,"*") from t2 order by 1; +select min(name),min(concat("*",name,"*")),max(name),max(concat("*",name,"*")) from t2; +select name from t1 where name between 'Ä' and 'Ö'; +select name from t2 where name between 'ä' and 'ö'; +select name from t2 where name between 'Ä' and 'Ö'; + +drop table t1,t2; + +# +# Test of binary and normal strings +# + +create table t1 (a char(10) not null, b char(10) binary not null,key (a), key(b)); +insert into t1 values ("hello ","hello "),("hello2 ","hello2 "); +select concat("-",a,"-",b,"-") from t1 where a="hello"; +select concat("-",a,"-",b,"-") from t1 where a="hello "; +select concat("-",a,"-",b,"-") from t1 ignore index (a) where a="hello "; +select concat("-",a,"-",b,"-") from t1 where b="hello"; +select concat("-",a,"-",b,"-") from t1 where b="hello "; +select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; +# blob test +alter table t1 modify b tinytext not null, drop key b, add key (b(100)); +select concat("-",a,"-",b,"-") from t1; +select concat("-",a,"-",b,"-") from t1 where b="hello "; +select concat("-",a,"-",b,"-") from t1 ignore index (b) where b="hello "; +drop table t1; + +# +# Test of binary and NULL +# +create table t1 (b char(8)); +insert into t1 values(NULL); +select b from t1 where binary b like ''; +select b from t1 group by binary b like ''; +select b from t1 having binary b like ''; +drop table t1; + +# +# Test of binary and upper/lower +# +create table t1 (a char(3) binary, b binary(3)); +insert into t1 values ('aaa','bbb'),('AAA','BBB'); +select upper(a),upper(b) from t1; +select lower(a),lower(b) from t1; +select * from t1 where upper(a)='AAA'; +select * from t1 where lower(a)='aaa'; +select * from t1 where upper(b)='BBB'; +select * from t1 where lower(b)='bbb'; +select charset(a), charset(b), charset(binary 'ccc') from t1 limit 1; +select collation(a), collation(b), collation(binary 'ccc') from t1 limit 1; +drop table t1; + +# +# Bug5134: WHERE x = 'bar' AND x LIKE BINARY 'bar' returns wrong results +# + +create table t1( firstname char(20), lastname char(20)); +insert into t1 values ("john","doe"),("John","Doe"); +select * from t1 where firstname='john' and firstname like binary 'john'; +select * from t1 where firstname='john' and binary 'john' = firstname; +select * from t1 where firstname='john' and firstname = binary 'john'; +select * from t1 where firstname='John' and firstname like binary 'john'; +select * from t1 where firstname='john' and firstname like binary 'John'; +drop table t1; + +# +# Bug #6552 CHAR column w/o length is legal, BINARY w/o length is not +# +create table t1 (a binary); +show create table t1; +drop table t1; + +# End of 4.1 tests + +# +# Bug#16857 +# +create table t1 (col1 binary(4)); +insert into t1 values ('a'),('a '); +select hex(col1) from t1; +alter table t1 modify col1 binary(10); +select hex(col1) from t1; +insert into t1 values ('b'),('b '); +select hex(col1) from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/bool.test b/mysql-test/suite/pbxt/t/bool.test new file mode 100644 index 00000000000..768c29454f2 --- /dev/null +++ b/mysql-test/suite/pbxt/t/bool.test @@ -0,0 +1,65 @@ +# +# Test of boolean operations with NULL +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +SELECT IF(NULL AND 1, 1, 2), IF(1 AND NULL, 1, 2); +SELECT NULL AND 1, 1 AND NULL, 0 AND NULL, NULL and 0; + +create table t1 (a int); +insert into t1 values (0),(1),(NULL); +SELECT * FROM t1 WHERE IF(a AND 1, 0, 1); +SELECT * FROM t1 WHERE IF(1 AND a, 0, 1); +SELECT * FROM t1 where NOT(a AND 1); +SELECT * FROM t1 where NOT(1 AND a); +SELECT * FROM t1 where (a AND 1)=0; +SELECT * FROM t1 where (1 AND a)=0; +SELECT * FROM t1 where (1 AND a)=1; +SELECT * FROM t1 where (1 AND a) IS NULL; + +# WL#638 - Behaviour of NOT does not follow SQL specification +set sql_mode='high_not_precedence'; +select * from t1 where not a between 2 and 3; +set sql_mode=default; +select * from t1 where not a between 2 and 3; + +# SQL boolean tests +select a, a is false, a is true, a is unknown from t1; +select a, a is not false, a is not true, a is not unknown from t1; + +# Verify that NULL optimisation works in AND clause: +SET @a=0, @b=0; +SELECT * FROM t1 WHERE NULL AND (@a:=@a+1); +SELECT * FROM t1 WHERE NOT(a>=0 AND NULL AND (@b:=@b+1)); +SELECT * FROM t1 WHERE a=2 OR (NULL AND (@a:=@a+1)); +SELECT * FROM t1 WHERE NOT(a=2 OR (NULL AND (@b:=@b+1))); +DROP TABLE t1; + + +# Test boolean operators in select part +# NULLs are represented as N for readability +# Read nA as !A, AB as A && B, AoB as A || B +# Result table makes ANSI happy + +create table t1 (a int, b int); +insert into t1 values(null, null), (0, null), (1, null), (null, 0), (null, 1), (0, 0), (0, 1), (1, 0), (1, 1); + +# Below test is valid untill we have True/False implemented as 1/0 +# To comply to all rules it must show that: n(AB) = nAonB, n(AoB) = nAnB + +select ifnull(A, 'N') as A, ifnull(B, 'N') as B, ifnull(not A, 'N') as nA, ifnull(not B, 'N') as nB, ifnull(A and B, 'N') as AB, ifnull(not (A and B), 'N') as `n(AB)`, ifnull((not A or not B), 'N') as nAonB, ifnull(A or B, 'N') as AoB, ifnull(not(A or B), 'N') as `n(AoB)`, ifnull(not A and not B, 'N') as nAnB from t1; + +# This should work with any internal representation of True/False +# Result must be same as above + +select ifnull(A=1, 'N') as A, ifnull(B=1, 'N') as B, ifnull(not (A=1), 'N') as nA, ifnull(not (B=1), 'N') as nB, ifnull((A=1) and (B=1), 'N') as AB, ifnull(not ((A=1) and (B=1)), 'N') as `n(AB)`, ifnull((not (A=1) or not (B=1)), 'N') as nAonB, ifnull((A=1) or (B=1), 'N') as AoB, ifnull(not((A=1) or (B=1)), 'N') as `n(AoB)`, ifnull(not (A=1) and not (B=1), 'N') as nAnB from t1; + +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/bulk_replace.test b/mysql-test/suite/pbxt/t/bulk_replace.test new file mode 100644 index 00000000000..8470331266c --- /dev/null +++ b/mysql-test/suite/pbxt/t/bulk_replace.test @@ -0,0 +1,17 @@ +# +# this is a test of bulk-insert code +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +CREATE TABLE t1 (a int, unique (a), b int not null, unique(b), c int not null, index(c)); +replace into t1 values (1,1,1),(2,2,2),(3,1,3); +select * from t1 order by a; # PBXT requires an order by +check table t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/case.test b/mysql-test/suite/pbxt/t/case.test new file mode 100644 index 00000000000..5c20ebc3d0f --- /dev/null +++ b/mysql-test/suite/pbxt/t/case.test @@ -0,0 +1,159 @@ +# +# Testing of CASE +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +select CASE "b" when "a" then 1 when "b" then 2 END; +select CASE "c" when "a" then 1 when "b" then 2 END; +select CASE "c" when "a" then 1 when "b" then 2 ELSE 3 END; +select CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END; +select CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END; +select CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end; +select CASE when 1=0 then "true" else "false" END; +select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END; +explain extended select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END; +select CASE 2.0 when 1 then "one" WHEN 2.0 then "two" ELSE "more" END; +select (CASE "two" when "one" then "1" WHEN "two" then "2" END) | 0; +select (CASE "two" when "one" then 1.00 WHEN "two" then 2.00 END) +0.0; +select case 1/0 when "a" then "true" else "false" END; +select case 1/0 when "a" then "true" END; +select (case 1/0 when "a" then "true" END) | 0; +select (case 1/0 when "a" then "true" END) + 0.0; +select case when 1>0 then "TRUE" else "FALSE" END; +select case when 1<0 then "TRUE" else "FALSE" END; + +# +# Test bug when using GROUP BY on CASE +# +create table t1 (a int); +insert into t1 values(1),(2),(3),(4); +select case a when 1 then 2 when 2 then 3 else 0 end as fcase, count(*) from t1 group by fcase; +explain extended select case a when 1 then 2 when 2 then 3 else 0 end as fcase, count(*) from t1 group by fcase; +select case a when 1 then "one" when 2 then "two" else "nothing" end as fcase, count(*) from t1 group by fcase; +drop table t1; + +# +# Test MAX(CASE ... ) that can return null +# + +create table t1 (row int not null, col int not null, val varchar(255) not null); +insert into t1 values (1,1,'orange'),(1,2,'large'),(2,1,'yellow'),(2,2,'medium'),(3,1,'green'),(3,2,'small'); +select max(case col when 1 then val else null end) as color from t1 group by row; +drop table t1; + +SET NAMES latin1; + +# +# CASE and argument types/collations aggregation into result +# +CREATE TABLE t1 SELECT + CASE WHEN 1 THEN _latin1'a' COLLATE latin1_danish_ci ELSE _latin1'a' END AS c1, + CASE WHEN 1 THEN _latin1'a' ELSE _latin1'a' COLLATE latin1_danish_ci END AS c2, + CASE WHEN 1 THEN 'a' ELSE 1 END AS c3, + CASE WHEN 1 THEN 1 ELSE 'a' END AS c4, + CASE WHEN 1 THEN 'a' ELSE 1.0 END AS c5, + CASE WHEN 1 THEN 1.0 ELSE 'a' END AS c6, + CASE WHEN 1 THEN 1 ELSE 1.0 END AS c7, + CASE WHEN 1 THEN 1.0 ELSE 1 END AS c8, + CASE WHEN 1 THEN 1.0 END AS c9, + CASE WHEN 1 THEN 0.1e1 else 0.1 END AS c10, + CASE WHEN 1 THEN 0.1e1 else 1 END AS c11, + CASE WHEN 1 THEN 0.1e1 else '1' END AS c12 +; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--error 1267 +SELECT CASE + WHEN 1 + THEN _latin1'a' COLLATE latin1_danish_ci + ELSE _latin1'a' COLLATE latin1_swedish_ci + END; + +--error 1270 +SELECT CASE _latin1'a' COLLATE latin1_general_ci + WHEN _latin1'a' COLLATE latin1_danish_ci THEN 1 + WHEN _latin1'a' COLLATE latin1_swedish_ci THEN 2 + END; + +SELECT +CASE _latin1'a' COLLATE latin1_general_ci WHEN _latin1'A' THEN '1' ELSE 2 END, +CASE _latin1'a' COLLATE latin1_bin WHEN _latin1'A' THEN '1' ELSE 2 END, +CASE _latin1'a' WHEN _latin1'A' COLLATE latin1_swedish_ci THEN '1' ELSE 2 END, +CASE _latin1'a' WHEN _latin1'A' COLLATE latin1_bin THEN '1' ELSE 2 END +; + +# +# COALESCE is a CASE abbrevation: +# +# COALESCE(v1,v2) == CASE WHEN v1 IS NOT NULL THEN v1 ELSE v2 END +# +# COALESCE(V1, V2, . . . ,Vn ) = +# CASE WHEN V1 IS NOT NULL THEN V1 ELSE COALESCE (V2, . . . ,Vn) END +# +# Check COALESCE argument types aggregation + +--error 1267 +CREATE TABLE t1 SELECT COALESCE(_latin1'a',_latin2'a'); +--error 1267 +CREATE TABLE t1 SELECT COALESCE('a' COLLATE latin1_swedish_ci,'b' COLLATE latin1_bin); +CREATE TABLE t1 SELECT + COALESCE(1), COALESCE(1.0),COALESCE('a'), + COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), + COALESCE('a' COLLATE latin1_bin,'b'); +explain extended SELECT + COALESCE(1), COALESCE(1.0),COALESCE('a'), + COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), + COALESCE('a' COLLATE latin1_bin,'b'); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# Test for BUG#10151 +SELECT 'case+union+test' +UNION +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; + +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; + +SELECT 'case+union+test' +UNION +SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; + +# +# Bug #17896: problem with MIN(CASE...) +# + +create table t1(a float, b int default 3); +insert into t1 (a) values (2), (11), (8); +select min(a), min(case when 1=1 then a else NULL end), + min(case when 1!=1 then NULL else a end) +from t1 where b=3 group by b; +drop table t1; + + +# +# Tests for bug #9939: conversion of the arguments for COALESCE and IFNULL +# + +CREATE TABLE t1 (EMPNUM INT); +INSERT INTO t1 VALUES (0), (2); +CREATE TABLE t2 (EMPNUM DECIMAL (4, 2)); +INSERT INTO t2 VALUES (0.0), (9.0); + +SELECT COALESCE(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, + t1.EMPNUM AS EMPMUM1, t2.EMPNUM AS EMPNUM2 + FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; + +SELECT IFNULL(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, + t1.EMPNUM AS EMPMUM1, t2.EMPNUM AS EMPNUM2 + FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; + +DROP TABLE t1,t2; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/cast.test b/mysql-test/suite/pbxt/t/cast.test new file mode 100644 index 00000000000..e8f7bcfeeb4 --- /dev/null +++ b/mysql-test/suite/pbxt/t/cast.test @@ -0,0 +1,225 @@ +# +# Test of cast function +# + +select CAST(1-2 AS UNSIGNED); +select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER); +select CAST('10 ' as unsigned integer); +select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; +select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1; +select ~5, cast(~5 as signed); +explain extended select ~5, cast(~5 as signed); +select cast(5 as unsigned) -6.0; +select cast(NULL as signed), cast(1/0 as signed); +select cast(NULL as unsigned), cast(1/0 as unsigned); +select cast("A" as binary) = "a", cast(BINARY "a" as CHAR) = "A"; +select cast("2001-1-1" as DATE), cast("2001-1-1" as DATETIME); +select cast("1:2:3" as TIME); +select CONVERT("2004-01-22 21:45:33",DATE); +select 10+'10'; +select 10.0+'10'; +select 10E+0+'10'; + +# The following cast creates warnings + +select CONVERT(DATE "2004-01-22 21:45:33" USING latin1); +select CONVERT(DATE "2004-01-22 21:45:33",CHAR); +select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4)); +select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)); +select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); +select CAST(0xb3 as signed); +select CAST(0x8fffffffffffffff as signed); +select CAST(0xffffffffffffffff as unsigned); +select CAST(0xfffffffffffffffe as signed); +select cast('-10a' as signed integer); +select cast('a10' as unsigned integer); +select 10+'a'; +select 10.0+cast('a' as decimal); +select 10E+0+'a'; + +# out-of-range cases +select cast('18446744073709551616' as unsigned); +select cast('18446744073709551616' as signed); +select cast('9223372036854775809' as signed); +select cast('-1' as unsigned); +select cast('abc' as signed); +select cast('1a' as signed); +select cast('' as signed); + +# +# Character set conversion +# +set names binary; +select cast(_latin1'test' as char character set latin2); +select cast(_koi8r'ÔÅÓÔ' as char character set cp1251); +create table t1 select cast(_koi8r'ÔÅÓÔ' as char character set cp1251) as t; +show create table t1; +drop table t1; + +# +# CAST to CHAR with/without length +# +select + cast(_latin1'ab' AS char) as c1, + cast(_latin1'a ' AS char) as c2, + cast(_latin1'abc' AS char(2)) as c3, + cast(_latin1'a ' AS char(2)) as c4, + hex(cast(_latin1'a' AS char(2))) as c5; +select cast(1000 as CHAR(3)); + +create table t1 select + cast(_latin1'ab' AS char) as c1, + cast(_latin1'a ' AS char) as c2, + cast(_latin1'abc' AS char(2)) as c3, + cast(_latin1'a ' AS char(2)) as c4, + cast(_latin1'a' AS char(2)) as c5; +select c1,c2,c3,c4,hex(c5) from t1; +show create table t1; +drop table t1; + +# +# CAST to NCHAR with/without length +# +select + cast(_koi8r'ÆÇ' AS nchar) as c1, + cast(_koi8r'Æ ' AS nchar) as c2, + cast(_koi8r'ÆÇÈ' AS nchar(2)) as c3, + cast(_koi8r'Æ ' AS nchar(2)) as c4, + cast(_koi8r'Æ' AS nchar(2)) as c5; + +create table t1 select + cast(_koi8r'ÆÇ' AS nchar) as c1, + cast(_koi8r'Æ ' AS nchar) as c2, + cast(_koi8r'ÆÇÈ' AS nchar(2)) as c3, + cast(_koi8r'Æ ' AS nchar(2)) as c4, + cast(_koi8r'Æ' AS nchar(2)) as c5; +select * from t1; +show create table t1; +drop table t1; + +# +# Bug 2202 +# CAST from BINARY to non-BINARY and from non-BINARY to BINARY +# +create table t1 (a binary(4), b char(4) character set koi8r); +insert into t1 values (_binary'ÔÅÓÔ',_binary'ÔÅÓÔ'); +select a,b,cast(a as char character set cp1251),cast(b as binary) from t1; +set names koi8r; +select a,b,cast(a as char character set cp1251),cast(b as binary) from t1; +set names cp1251; +select a,b,cast(a as char character set cp1251),cast(b as binary) from t1; +drop table t1; +set names binary; + +# +# The following should be fixed in 4.1 +# + +select cast("2001-1-1" as date) = "2001-01-01"; +select cast("2001-1-1" as datetime) = "2001-01-01 00:00:00"; +select cast("1:2:3" as TIME) = "1:02:03"; +select cast(NULL as DATE); +select cast(NULL as BINARY); + +# +# Bug #5228 ORDER BY CAST(enumcol) sorts incorrectly under certain conditions +# +CREATE TABLE t1 (a enum ('aac','aab','aaa') not null); +INSERT INTO t1 VALUES ('aaa'),('aab'),('aac'); +# these two should be in enum order +SELECT a, CAST(a AS CHAR) FROM t1 ORDER BY CAST(a AS UNSIGNED) ; +SELECT a, CAST(a AS CHAR(3)) FROM t1 ORDER BY CAST(a AS CHAR(2)), a; +# these two should be in alphabetic order +SELECT a, CAST(a AS UNSIGNED) FROM t1 ORDER BY CAST(a AS CHAR) ; +SELECT a, CAST(a AS CHAR(2)) FROM t1 ORDER BY CAST(a AS CHAR(3)), a; +DROP TABLE t1; + +# +# Test for bug #6914 "Problems using time()/date() output in expressions". +# When we are casting datetime value to DATE/TIME we should throw away +# time/date parts (correspondingly). +# +select date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour); +select timediff(cast('2004-12-30 12:00:00' as time), '12:00:00'); +# Still we should not throw away "days" part of time value +select timediff(cast('1 12:00:00' as time), '12:00:00'); + +# +# Bug #7036: Casting from string to unsigned would cap value of result at +# maximum signed value instead of maximum unsigned value +# +select cast(18446744073709551615 as unsigned); +select cast(18446744073709551615 as signed); +select cast('18446744073709551615' as unsigned); +select cast('18446744073709551615' as signed); +select cast('9223372036854775807' as signed); + +select cast(concat('184467440','73709551615') as unsigned); +select cast(concat('184467440','73709551615') as signed); + +select cast(repeat('1',20) as unsigned); +select cast(repeat('1',20) as signed); + +# +# Bug #13344: cast of large decimal to signed int not handled correctly +# +select cast(1.0e+300 as signed int); + +# +# Bugs: #15098: CAST(column double TO signed int), wrong result +# +CREATE TABLE t1 (f1 double); +INSERT INTO t1 SET f1 = -1.0e+30 ; +INSERT INTO t1 SET f1 = +1.0e+30 ; +# Expected result is +-1e+30, but Windows returns +-1e+030. +--replace_result 1e+030 1e+30 +SELECT f1 AS double_val, CAST(f1 AS SIGNED INT) AS cast_val FROM t1; +DROP TABLE t1; + +# End of 4.1 tests + + +#decimal-related additions +select cast('1.2' as decimal(3,2)); +select 1e18 * cast('1.2' as decimal(3,2)); +select cast(cast('1.2' as decimal(3,2)) as signed); +set @v1=1e18; +select cast(@v1 as decimal(22, 2)); +select cast(-1e18 as decimal(22,2)); + +create table t1(s1 time); +insert into t1 values ('11:11:11'); +select cast(s1 as decimal(7,2)) from t1; +drop table t1; + +# +# Test for bug #11283: field conversion from varchar, and text types to decimal +# + +CREATE TABLE t1 (v varchar(10), tt tinytext, t text, + mt mediumtext, lt longtext); +INSERT INTO t1 VALUES ('1.01', '2.02', '3.03', '4.04', '5.05'); + +SELECT CAST(v AS DECIMAL), CAST(tt AS DECIMAL), CAST(t AS DECIMAL), + CAST(mt AS DECIMAL), CAST(lt AS DECIMAL) from t1; + +DROP TABLE t1; + +# +# Bug #10237 (CAST(NULL DECIMAL) crashes server) +# +select cast(NULL as decimal(6)) as t1; + + +# +# Bug #17903: cast to char results in binary +# +set names latin1; +select hex(cast('a' as char(2) binary)); +select hex(cast('a' as binary(2))); +select hex(cast('a' as char(2) binary)); + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/check.test b/mysql-test/suite/pbxt/t/check.test new file mode 100644 index 00000000000..e8f355fe266 --- /dev/null +++ b/mysql-test/suite/pbxt/t/check.test @@ -0,0 +1,42 @@ +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection con1; +--disable_warnings +drop table if exists t1; +--enable_warnings + +# Add a lot of keys to slow down check +create table t1(n int not null, key(n), key(n), key(n), key(n)); +let $1=10000; +disable_query_log; +while ($1) +{ + eval insert into t1 values ($1); + dec $1; +} +enable_query_log; +send check table t1 extended; +connection con2; +insert into t1 values (200000); +connection con1; +reap; +drop table t1; + +# End of 4.1 tests + +# +# Bug #9897 Views: 'Check Table' crashes MySQL, with a view and a table +# in the statement +# + +connection default; +Create table t1(f1 int); +Create table t2(f1 int); +Create view v1 as Select * from t1; +Check Table v1,t2; +drop view v1; +drop table t1, t2; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/client_xml.test b/mysql-test/suite/pbxt/t/client_xml.test new file mode 100644 index 00000000000..447903ebf18 --- /dev/null +++ b/mysql-test/suite/pbxt/t/client_xml.test @@ -0,0 +1,25 @@ +# Can't run with embedded server +-- source include/not_embedded.inc + +# Test of the xml output of the 'mysql' and 'mysqldump' clients -- makes +# sure that basic encoding issues are handled properly +create table t1 ( + `a&b` int, + `a<b` int, + `a>b` text +); +insert into t1 values (1, 2, 'a&b a<b a>b'); +--exec $MYSQL --xml test -e "select * from t1" +--exec $MYSQL_DUMP --xml --skip-create test + +--exec $MYSQL --xml test -e "select count(*) from t1" +--exec $MYSQL --xml test -e "select 1 < 2 from dual" +--exec $MYSQL --xml test -e "select 1 > 2 from dual" +--exec $MYSQL --xml test -e "select 1 & 3 from dual" +--exec $MYSQL --xml test -e "select null from dual" + +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/comments.test b/mysql-test/suite/pbxt/t/comments.test new file mode 100644 index 00000000000..52273ec9523 --- /dev/null +++ b/mysql-test/suite/pbxt/t/comments.test @@ -0,0 +1,21 @@ +# +# Testing of comments +# + +select 1+2/*hello*/+3; +select 1 /* long +multi line comment */; +--error 1065 + ; +select 1 /*!32301 +1 */; +select 1 /*!52301 +1 */; +select 1--1; +# Note that the following returns 4 while it should return 2 +# This is because the mysqld server doesn't parse -- comments +select 1 --2 ++1; +select 1 # The rest of the row will be ignored +; +/* line with only comment */; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/compare.test b/mysql-test/suite/pbxt/t/compare.test new file mode 100644 index 00000000000..ec70dd5e587 --- /dev/null +++ b/mysql-test/suite/pbxt/t/compare.test @@ -0,0 +1,52 @@ +# +# Bug when using comparions of strings and integers. +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE t1 (id CHAR(12) not null, PRIMARY KEY (id)); +insert into t1 values ('000000000001'),('000000000002'); +explain select * from t1 where id=000000000001; +select * from t1 where id=000000000001; +delete from t1 where id=000000000002; +select * from t1; +drop table t1; + +# +# Check the following: +# "a" == "a " +# "a\0" < "a" +# "a\0" < "a " + +SELECT 'a' = 'a '; +SELECT 'a\0' < 'a'; +SELECT 'a\0' < 'a '; +SELECT 'a\t' < 'a'; +SELECT 'a\t' < 'a '; + +CREATE TABLE t1 (a char(10) not null); +INSERT INTO t1 VALUES ('a'),('a\0'),('a\t'),('a '); +SELECT hex(a),STRCMP(a,'a'), STRCMP(a,'a ') FROM t1; +DROP TABLE t1; + +# Bug #8134: Comparison against CHAR(31) at end of string +SELECT CHAR(31) = '', '' = CHAR(31); +# Extra test +SELECT CHAR(30) = '', '' = CHAR(30); + +# End of 4.1 tests + +# +#Bug #21159: Optimizer: wrong result after AND with different data types +# +create table t1 (a tinyint(1),b binary(1)); +insert into t1 values (0x01,0x01); +select * from t1 where a=b; +select * from t1 where a=b and b=0x01; +drop table if exists t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/connect.test b/mysql-test/suite/pbxt/t/connect.test new file mode 100644 index 00000000000..aa1c34068f5 --- /dev/null +++ b/mysql-test/suite/pbxt/t/connect.test @@ -0,0 +1,108 @@ +# This test is to check various cases of connections +# with right and wrong password, with and without database +# Unfortunately the check is incomplete as we can't connect without database + +# This test makes no sense with the embedded server +--source include/not_embedded.inc + +# check that CSV engine was compiled in, as the test relies on the presence +# of the log tables (which are CSV-based). By connect mysql; show tables; +--source include/have_csv.inc + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + + +#connect (con1,localhost,root,,""); +#show tables; +connect (con1,localhost,root,,mysql); +show tables; +connect (con2,localhost,root,,test); +show tables; + +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,root,z,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,root,z,); + +grant ALL on *.* to test@localhost identified by "gambling"; +grant ALL on *.* to test@127.0.0.1 identified by "gambling"; + +# Now check this user with different databases +#connect (con1,localhost,test,gambling,""); +#show tables; +connect (con3,localhost,test,gambling,mysql); +show tables; +connect (con4,localhost,test,gambling,test); +show tables; + +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,,""); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,zorro,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,zorro,); + + +# check if old password version also works +update mysql.user set password=old_password("gambling2") where user=_binary"test"; +flush privileges; + +connect (con10,localhost,test,gambling2,); +connect (con5,localhost,test,gambling2,mysql); +connection con5; +set password=""; +--error 1372 +set password='gambling3'; +set password=old_password('gambling3'); +show tables; +connect (con6,localhost,test,gambling3,test); +show tables; + +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,,); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,zorro,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,zorro,); + + +# remove user 'test' so that other tests which may use 'test' +# do not depend on this test. + +delete from mysql.user where user=_binary"test"; +flush privileges; + +# +# Bug#12517: Clear user variables and replication events before +# closing temp tables in thread cleanup. +connect (con7,localhost,root,,test); +connection con7; +create table t1 (id integer not null auto_increment primary key); +create temporary table t2(id integer not null auto_increment primary key); +set @id := 1; +delete from t1 where id like @id; +disconnect con7; +--sleep 5 +connection default; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/consistent_snapshot.test b/mysql-test/suite/pbxt/t/consistent_snapshot.test new file mode 100644 index 00000000000..8da8e9ce660 --- /dev/null +++ b/mysql-test/suite/pbxt/t/consistent_snapshot.test @@ -0,0 +1,43 @@ +-- source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +### Test 1: +### - While a consistent snapshot transaction is executed, +### no external inserts should be visible to the transaction. + +connection con1; +create table t1 (a int) engine=innodb; +start transaction with consistent snapshot; + +connection con2; +insert into t1 values(1); + +connection con1; +select * from t1; # if consistent snapshot was set as expected, we +# should see nothing. +commit; + +### Test 2: +### - For any non-consistent snapshot transaction, external +### committed inserts should be visible to the transaction. + +delete from t1; +start transaction; # Now we omit WITH CONSISTENT SNAPSHOT + +connection con2; +insert into t1 values(1); + +connection con1; +select * from t1; # if consistent snapshot was not set, as expected, we +# should see 1. +commit; + +drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/constraints.test b/mysql-test/suite/pbxt/t/constraints.test new file mode 100644 index 00000000000..565c8890f69 --- /dev/null +++ b/mysql-test/suite/pbxt/t/constraints.test @@ -0,0 +1,34 @@ +# +# Testing of constraints +# Currently MySQL only ignores the syntax. +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int check (a>0)); +insert into t1 values (1); +insert into t1 values (0); +drop table t1; +create table t1 (a int ,b int, check a>b); +insert into t1 values (1,0); +insert into t1 values (0,1); +drop table t1; +create table t1 (a int ,b int, constraint abc check (a>b)); +insert into t1 values (1,0); +insert into t1 values (0,1); +drop table t1; +create table t1 (a int null); +insert into t1 values (1),(NULL); +drop table t1; +create table t1 (a int null); +alter table t1 add constraint constraint_1 unique (a); +alter table t1 add constraint unique key_1(a); +alter table t1 add constraint constraint_2 unique key_2(a); +show create table t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/contributors.test b/mysql-test/suite/pbxt/t/contributors.test new file mode 100644 index 00000000000..e463c4a888b --- /dev/null +++ b/mysql-test/suite/pbxt/t/contributors.test @@ -0,0 +1 @@ +SHOW CONTRIBUTORS; diff --git a/mysql-test/suite/pbxt/t/count_distinct.test b/mysql-test/suite/pbxt/t/count_distinct.test new file mode 100644 index 00000000000..1d4f4f22603 --- /dev/null +++ b/mysql-test/suite/pbxt/t/count_distinct.test @@ -0,0 +1,82 @@ +# +# Problem with count(distinct) +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +create table t1 (libname varchar(21) not null, city text, primary key (libname)); +create table t2 (isbn varchar(21) not null, author text, title text, primary key (isbn)); +create table t3 (isbn varchar(21) not null, libname varchar(21) not null, quantity int ,primary key (isbn,libname)); +insert into t2 values ('001','Daffy','A duck''s life'); +insert into t2 values ('002','Bugs','A rabbit\'s life'); +insert into t2 values ('003','Cowboy','Life on the range'); +insert into t2 values ('000','Anonymous','Wanna buy this book?'); +insert into t2 values ('004','Best Seller','One Heckuva book'); +insert into t2 values ('005','EveryoneBuys','This very book'); +insert into t2 values ('006','San Fran','It is a san fran lifestyle'); +insert into t2 values ('007','BerkAuthor','Cool.Berkley.the.book'); +insert into t3 values('000','New York Public Libra','1'); +insert into t3 values('001','New York Public Libra','2'); +insert into t3 values('002','New York Public Libra','3'); +insert into t3 values('003','New York Public Libra','4'); +insert into t3 values('004','New York Public Libra','5'); +insert into t3 values('005','New York Public Libra','6'); +insert into t3 values('006','San Fransisco Public','5'); +insert into t3 values('007','Berkeley Public1','3'); +insert into t3 values('007','Berkeley Public2','3'); +insert into t3 values('001','NYC Lib','8'); +insert into t1 values ('New York Public Libra','New York'); +insert into t1 values ('San Fransisco Public','San Fran'); +insert into t1 values ('Berkeley Public1','Berkeley'); +insert into t1 values ('Berkeley Public2','Berkeley'); +insert into t1 values ('NYC Lib','New York'); +select t2.isbn,city,t1.libname,count(t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city,t1.libname; +select t2.isbn,city,t1.libname,count(distinct t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city having count(distinct t1.libname) > 1; +select t2.isbn,city,t1.libname,count(distinct t1.libname) as a from t3 left join t1 on t3.libname=t1.libname left join t2 on t3.isbn=t2.isbn group by city having count(distinct concat(t1.libname,'a')) > 1; +drop table t1, t2, t3; + +# +# Problem with LEFT JOIN +# + +create table t1 (f1 int); +insert into t1 values (1); +create table t2 (f1 int,f2 int); +select t1.f1,count(distinct t2.f2),count(distinct 1,NULL) from t1 left join t2 on t1.f1=t2.f1 group by t1.f1; +drop table t1,t2; + + +# +# Empty tables +# +create table t1 (f int); +select count(distinct f) from t1; +drop table t1; + +# End of 4.1 tests + +# +# Bug #6515 +# + +create table t1 (a char(3), b char(20), primary key (a, b)); +insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English'); +select count(distinct a) from t1 group by b; +drop table t1; + +# +# Bug #9593 "The combination of COUNT, DISTINCT and CONCAT +# seems to lock the server" +# Bug appears only on Windows system +# + +create table t1 (f1 int, f2 int); +insert into t1 values (0,1),(1,2); +select count(distinct if(f1,3,f2)) from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/count_distinct2.test b/mysql-test/suite/pbxt/t/count_distinct2.test new file mode 100644 index 00000000000..2f95e000f6c --- /dev/null +++ b/mysql-test/suite/pbxt/t/count_distinct2.test @@ -0,0 +1,85 @@ +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1(n1 int, n2 int, s char(20), vs varchar(20), t text); +insert into t1 values (1,11, 'one','eleven', 'eleven'), + (1,11, 'one','eleven', 'eleven'), + (2,11, 'two','eleven', 'eleven'), + (2,12, 'two','twevle', 'twelve'), + (2,13, 'two','thirteen', 'foo'), + (2,13, 'two','thirteen', 'foo'), + (2,13, 'two','thirteen', 'bar'), + (NULL,13, 'two','thirteen', 'bar'), + (2,NULL, 'two','thirteen', 'bar'), + (2,13, NULL,'thirteen', 'bar'), + (2,13, 'two',NULL, 'bar'), + (2,13, 'two','thirteen', NULL); + +select distinct n1 from t1; +select count(distinct n1) from t1; + +select distinct n2 from t1; +select count(distinct n2) from t1; + +select distinct s from t1; +select count(distinct s) from t1; + +select distinct vs from t1; +select count(distinct vs) from t1; + +select distinct t from t1; +select count(distinct t) from t1; + +select distinct n1,n2 from t1; +select count(distinct n1,n2) from t1; + +select distinct n1,s from t1; +select count(distinct n1,s) from t1; + +select distinct s,n1,vs from t1; +select count(distinct s,n1,vs) from t1; + +select distinct s,t from t1; +select count(distinct s,t) from t1; + +select count(distinct n1), count(distinct n2) from t1; + +select count(distinct n2), n1 from t1 group by n1; +drop table t1; + +# test the conversion from tree to MyISAM +create table t1 (n int default NULL); +let $1=5000; +disable_query_log; +while ($1) +{ + eval insert into t1 values($1); + dec $1; +} +enable_query_log; + +flush status; +select count(distinct n) from t1; +show status like 'Created_tmp_disk_tables'; +drop table t1; + +# Test use of MyISAM tmp tables +create table t1 (s text); +let $1=5000; +disable_query_log; +while ($1) +{ + eval insert into t1 values('$1'); + dec $1; +} +enable_query_log; +flush status; +select count(distinct s) from t1; +show status like 'Created_tmp_disk_tables'; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/count_distinct3.test b/mysql-test/suite/pbxt/t/count_distinct3.test new file mode 100644 index 00000000000..734a6a808d9 --- /dev/null +++ b/mysql-test/suite/pbxt/t/count_distinct3.test @@ -0,0 +1,63 @@ +# +# this is a test for error 1032 in count(distinct) + group by, introduced in +# mysql-4.1 +# + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +CREATE TABLE t1 (id INTEGER, grp TINYINT, id_rev INTEGER); + +--disable_query_log +SET @rnd_max= 2147483647; +let $1 = 1000; +while ($1) +{ + SET @rnd= RAND(); + SET @id = CAST(@rnd * @rnd_max AS UNSIGNED); + SET @id_rev= @rnd_max - @id; + SET @grp= CAST(127.0 * @rnd AS UNSIGNED); + INSERT INTO t1 (id, grp, id_rev) VALUES (@id, @grp, @id_rev); + dec $1; +} +set @@read_buffer_size=2*1024*1024; +CREATE TABLE t2 SELECT * FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +INSERT INTO t1 (id, grp, id_rev) SELECT id, grp, id_rev FROM t2; +INSERT INTO t2 (id, grp, id_rev) SELECT id, grp, id_rev FROM t1; +DROP TABLE t2; +--enable_query_log + +SELECT COUNT(*) FROM t1; + +# As t1 contains random numbers, results are different from test to test. +# That's okay, because we test only that select doesn't yield an +# error. Note, that --disable_result_log doesn't suppress error output. + +--disable_result_log +SELECT COUNT(DISTINCT id) FROM t1 GROUP BY grp; +--enable_result_log +DROP TABLE t1; + +set @@read_buffer_size=default; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/create.test b/mysql-test/suite/pbxt/t/create.test new file mode 100644 index 00000000000..07ad03d4bfb --- /dev/null +++ b/mysql-test/suite/pbxt/t/create.test @@ -0,0 +1,741 @@ +# +# Check some special create statements. +# + +--disable_warnings +drop table if exists t1,t2,t3,t4,t5; +drop database if exists mysqltest; +--enable_warnings + +create table t1 (b char(0)); +insert into t1 values (""),(null); +select * from t1; +drop table if exists t1; + +create table t1 (b char(0) not null); +create table if not exists t1 (b char(0) not null); +insert into t1 values (""),(null); +select * from t1; +drop table t1; + +create table t1 (a int not null auto_increment,primary key (a)) engine=heap; +drop table t1; + +# +# Test of some CREATE TABLE'S that should fail +# + +--error 1146 +create table t2 engine=heap select * from t1; +--error 1146 +create table t2 select auto+1 from t1; +drop table if exists t1,t2; +--error 1167 +create table t1 (b char(0) not null, index(b)); +--error 1163 +create table t1 (a int not null,b text) engine=heap; +drop table if exists t1; + +--error 1075 +create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) engine=heap; + +-- error 1049 +create table not_existing_database.test (a int); +create table `a/a` (a int); +show create table `a/a`; +create table t1 like `a/a`; +drop table `a/a`; +drop table `t1`; +--error 1103 +create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int); +--error 1059 +create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int); + +# +# Some wrong defaults, so these creates should fail too (Bug #5902) +# +--error 1067 +create table t1 (a datetime default now()); +--error 1294 +create table t1 (a datetime on update now()); +--error 1067 +create table t1 (a int default 100 auto_increment); +--error 1067 +create table t1 (a tinyint default 1000); +--error 1067 +create table t1 (a varchar(5) default 'abcdef'); + +create table t1 (a varchar(5) default 'abcde'); +insert into t1 values(); +select * from t1; +--error 1067 +alter table t1 alter column a set default 'abcdef'; +drop table t1; + +# +# test of dummy table names +# + +create table 1ea10 (1a20 int,1e int); +insert into 1ea10 values(1,1); +select 1ea10.1a20,1e+ 1e+10 from 1ea10; +drop table 1ea10; +create table t1 (t1.index int); +drop table t1; +# Test that we get warning for this +drop database if exists mysqltest; +create database mysqltest; +create table mysqltest.$test1 (a$1 int, $b int, c$ int); +insert into mysqltest.$test1 values (1,2,3); +select a$1, $b, c$ from mysqltest.$test1; +create table mysqltest.test2$ (a int); +drop table mysqltest.test2$; +drop database mysqltest; + +--error 1103 +create table `` (a int); +--error 1103 +drop table if exists ``; +--error 1166 +create table t1 (`` int); +--error 1280 +create table t1 (i int, index `` (i)); + +# +# Test of CREATE ... SELECT with indexes +# + +create table t1 (a int auto_increment not null primary key, B CHAR(20)); +insert into t1 (b) values ("hello"),("my"),("world"); +create table t2 (key (b)) select * from t1; +explain select * from t2 where b="world"; +select * from t2 where b="world"; +drop table t1,t2; + +# +# Test types after CREATE ... SELECT +# + +create table t1(x varchar(50) ); +create table t2 select x from t1 where 1=2; +describe t1; +describe t2; +drop table t2; +create table t2 select now() as a , curtime() as b, curdate() as c , 1+1 as d , 1.0 + 1 as e , 33333333333333333 + 3 as f; +describe t2; +drop table t2; +create table t2 select CAST("2001-12-29" AS DATE) as d, CAST("20:45:11" AS TIME) as t, CAST("2001-12-29 20:45:11" AS DATETIME) as dt; +describe t2; +drop table t1,t2; + +# +# Test of CREATE ... SELECT with duplicate fields +# + +create table t1 (a tinyint); +create table t2 (a int) select * from t1; +describe t1; +describe t2; +drop table if exists t2; +--error 1060 +create table t2 (a int, a float) select * from t1; +drop table if exists t2; +--error 1060 +create table t2 (a int) select a as b, a+1 as b from t1; +drop table if exists t2; +--error 1060 +create table t2 (b int) select a as b, a+1 as b from t1; +drop table if exists t1,t2; + +# +# Test CREATE ... SELECT when insert fails +# + +CREATE TABLE t1 (a int not null); +INSERT INTO t1 values (1),(2),(1); +--error ER_DUP_ENTRY +CREATE TABLE t2 (primary key(a)) SELECT * FROM t1; +--error 1146 +SELECT * from t2; +DROP TABLE t1; +DROP TABLE IF EXISTS t2; + +# +# Test of primary key with 32 index +# + +create table t1 (a int not null, b int, primary key(a), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b)); +show create table t1; +drop table t1; +create table t1 select if(1,'1','0'), month("2002-08-02"); +drop table t1; +create table t1 select if('2002'='2002','Y','N'); +select * from t1; +drop table if exists t1; + +# +# Test default table type +# +SET SESSION storage_engine="heap"; +SELECT @@storage_engine; +CREATE TABLE t1 (a int not null); +show create table t1; +drop table t1; +--error 1286 +SET SESSION storage_engine="gemini"; +SELECT @@storage_engine; +CREATE TABLE t1 (a int not null); +show create table t1; +SET SESSION storage_engine=default; +drop table t1; + + +# +# ISO requires that primary keys are implicitly NOT NULL +# +create table t1 ( k1 varchar(2), k2 int, primary key(k1,k2)); +insert into t1 values ("a", 1), ("b", 2); +--error 1048 +insert into t1 values ("c", NULL); +--error 1048 +insert into t1 values (NULL, 3); +--error 1048 +insert into t1 values (NULL, NULL); +drop table t1; + +# +# Bug # 801 +# + +create table t1 select x'4132'; +drop table t1; + +# +# bug #1434 +# + +create table t1 select 1,2,3; +create table if not exists t1 select 1,2; +--error 1136 +create table if not exists t1 select 1,2,3,4; +create table if not exists t1 select 1; +select * from t1; +drop table t1; + +# +# Test create table if not exists with duplicate key error +# + +flush status; +create table t1 (a int not null, b int, primary key (a)); +insert into t1 values (1,1); +create table if not exists t1 select 2; +select * from t1; +create table if not exists t1 select 3 as 'a',4 as 'b'; +--error ER_DUP_ENTRY +create table if not exists t1 select 3 as 'a',3 as 'b'; +show warnings; +show status like "Opened_tables"; +select * from t1; +drop table t1; + +# +# Test for Bug #2985 +# "Table truncated when creating another table name with Spaces" +# + +--error 1103 +create table `t1 `(a int); +--error 1102 +create database `db1 `; +--error 1166 +create table t1(`a ` int); + +# +# Test for Bug #3481 +# "Parser permits multiple commas without syntax error" +# + +--error 1064 +create table t1 (a int,); +--error 1064 +create table t1 (a int,,b int); +--error 1064 +create table t1 (,b int); + +# +# Test create with foreign keys +# + +create table t1 (a int, key(a)); +create table t2 (b int, foreign key(b) references t1(a), key(b)); +drop table if exists t2,t1; + +# +# Test for CREATE TABLE .. LIKE .. +# + +create table t1(id int not null, name char(20)); +insert into t1 values(10,'mysql'),(20,'monty- the creator'); +create table t2(id int not null); +insert into t2 values(10),(20); +create table t3 like t1; +show create table t3; +select * from t3; +# Disable PS becasue of @@warning_count +create table if not exists t3 like t1; +--disable_ps_protocol +select @@warning_count; +--enable_ps_protocol +create temporary table t3 like t2; +show create table t3; +select * from t3; +drop table t3; +show create table t3; +select * from t3; +drop table t2, t3; +create database mysqltest; +alter table t1; +create table mysqltest.t3 like t1; +create temporary table t3 like mysqltest.t3; +show create table t3; +create table t2 like t3; +show create table t2; +select * from t2; +create table t3 like t1; +--error 1050 +create table t3 like mysqltest.t3; +--error 1049 +create table non_existing_database.t1 like t1; +--error ER_NO_SUCH_TABLE +create table t3 like non_existing_table; +--error 1050 +create temporary table t3 like t1; +drop table t1, t2, t3; +drop table t3; +drop database mysqltest; + +# +# Test default table type +# +SET SESSION storage_engine="heap"; +SELECT @@storage_engine; +CREATE TABLE t1 (a int not null); +show create table t1; +drop table t1; +--error 1286 +SET SESSION storage_engine="gemini"; +SELECT @@storage_engine; +CREATE TABLE t1 (a int not null); +show create table t1; +SET SESSION storage_engine=default; +drop table t1; + +# +# Test types of data for create select with functions +# + +create table t1(a int,b int,c int unsigned,d date,e char,f datetime,g time,h blob); +insert into t1(a)values(1); +insert into t1(a,b,c,d,e,f,g,h) +values(2,-2,2,'1825-12-14','a','2003-1-1 3:2:1','4:3:2','binary data'); +select * from t1; +select a, + ifnull(b,cast(-7 as signed)) as b, + ifnull(c,cast(7 as unsigned)) as c, + ifnull(d,cast('2000-01-01' as date)) as d, + ifnull(e,cast('b' as char)) as e, + ifnull(f,cast('2000-01-01' as datetime)) as f, + ifnull(g,cast('5:4:3' as time)) as g, + ifnull(h,cast('yet another binary data' as binary)) as h, + addtime(cast('1:0:0' as time),cast('1:0:0' as time)) as dd +from t1; + +create table t2 +select + a, + ifnull(b,cast(-7 as signed)) as b, + ifnull(c,cast(7 as unsigned)) as c, + ifnull(d,cast('2000-01-01' as date)) as d, + ifnull(e,cast('b' as char)) as e, + ifnull(f,cast('2000-01-01' as datetime)) as f, + ifnull(g,cast('5:4:3' as time)) as g, + ifnull(h,cast('yet another binary data' as binary)) as h, + addtime(cast('1:0:0' as time),cast('1:0:0' as time)) as dd +from t1; +explain t2; +select * from t2; +drop table t1, t2; + +create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp, l datetime, m enum('a','b'), n set('a','b'), o char(10)); +create table t2 select ifnull(a,a), ifnull(b,b), ifnull(c,c), ifnull(d,d), ifnull(e,e), ifnull(f,f), ifnull(g,g), ifnull(h,h), ifnull(i,i), ifnull(j,j), ifnull(k,k), ifnull(l,l), ifnull(m,m), ifnull(n,n), ifnull(o,o) from t1; +show create table t2; +drop table t1,t2; + +# +# Test of default() +# +create table t1(str varchar(10) default 'def',strnull varchar(10),intg int default '10',rel double default '3.14'); +insert into t1 values ('','',0,0.0); +describe t1; +create table t2 select default(str) as str, default(strnull) as strnull, default(intg) as intg, default(rel) as rel from t1; +describe t2; +drop table t1, t2; + +# +# Bug #2075 +# + +create table t1(name varchar(10), age smallint default -1); +describe t1; +create table t2(name varchar(10), age smallint default - 1); +describe t2; +drop table t1, t2; + +# +# test for bug #1427 "enum allows duplicate values in the list" +# + +create table t1(cenum enum('a'), cset set('b')); +create table t2(cenum enum('a','a'), cset set('b','b')); +create table t3(cenum enum('a','A','a','c','c'), cset set('b','B','b','d','d')); +drop table t1, t2, t3; + +# +# Bug #1209 +# + +create database mysqltest; +use mysqltest; +select database(); +drop database mysqltest; +select database(); + +# Connect without a database as user mysqltest_1 +create user mysqltest_1; +connect (user1,localhost,mysqltest_1,,*NO-ONE*); +connection user1; +select database(), user(); +connection default; +disconnect user1; +drop user mysqltest_1; +use test; + +# +# Test for Bug 856 'Naming a key "Primary" causes trouble' +# + +--error 1280 +create table t1 (a int, index `primary` (a)); +--error 1280 +create table t1 (a int, index `PRIMARY` (a)); + +create table t1 (`primary` int, index(`primary`)); +show create table t1; +create table t2 (`PRIMARY` int, index(`PRIMARY`)); +show create table t2; + +create table t3 (a int); +--error 1280 +alter table t3 add index `primary` (a); +--error 1280 +alter table t3 add index `PRIMARY` (a); + +create table t4 (`primary` int); +alter table t4 add index(`primary`); +show create table t4; +create table t5 (`PRIMARY` int); +alter table t5 add index(`PRIMARY`); +show create table t5; + +drop table t1, t2, t3, t4, t5; + +# +# bug #3266 TEXT in CREATE TABLE SELECT +# + +CREATE TABLE t1(id varchar(10) NOT NULL PRIMARY KEY, dsc longtext); +INSERT INTO t1 VALUES ('5000000001', NULL),('5000000003', 'Test'),('5000000004', NULL); +CREATE TABLE t2(id varchar(15) NOT NULL, proc varchar(100) NOT NULL, runID varchar(16) NOT NULL, start datetime NOT NULL, PRIMARY KEY (id,proc,runID,start)); + +INSERT INTO t2 VALUES ('5000000001', 'proc01', '20031029090650', '2003-10-29 13:38:40'),('5000000001', 'proc02', '20031029090650', '2003-10-29 13:38:51'),('5000000001', 'proc03', '20031029090650', '2003-10-29 13:38:11'),('5000000002', 'proc09', '20031024013310', '2003-10-24 01:33:11'),('5000000002', 'proc09', '20031024153537', '2003-10-24 15:36:04'),('5000000004', 'proc01', '20031024013641', '2003-10-24 01:37:29'),('5000000004', 'proc02', '20031024013641', '2003-10-24 01:37:39'); + +CREATE TABLE t3 SELECT t1.dsc,COUNT(DISTINCT t2.id) AS countOfRuns FROM t1 LEFT JOIN t2 ON (t1.id=t2.id) GROUP BY t1.id; +SELECT * FROM t3; +drop table t1, t2, t3; + +# +# Bug#9666: Can't use 'DEFAULT FALSE' for column of type bool +# +create table t1 (b bool not null default false); +create table t2 (b bool not null default true); +insert into t1 values (); +insert into t2 values (); +select * from t1; +select * from t2; +drop table t1,t2; + +# +# Bug#10224 - ANALYZE TABLE crashing with simultaneous +# CREATE ... SELECT statement. +# This tests two additional possible errors and a hang if +# an improper fix is present. +# +create table t1 (a int); +--error 1093 +create table t1 select * from t1; +--error 1347 +create table t2 union = (t1) select * from t1; +flush tables with read lock; +unlock tables; +drop table t1; + +# +# Bug#10413: Invalid column name is not rejected +# +--error 1103 +create table t1(column.name int); +--error 1103 +create table t1(test.column.name int); +--error 1102 +create table t1(xyz.t1.name int); +create table t1(t1.name int); +create table t2(test.t2.name int); +drop table t1,t2; + +# +# Bug #12537: UNION produces longtext instead of varchar +# +CREATE TABLE t1 (f1 VARCHAR(255) CHARACTER SET utf8); +CREATE TABLE t2 AS SELECT LEFT(f1,171) AS f2 FROM t1 UNION SELECT LEFT(f1,171) AS f2 FROM t1; +DESC t2; +DROP TABLE t1,t2; + +# +# Bug#12913 Simple SQL can crash server or connection +# +CREATE TABLE t12913 (f1 ENUM ('a','b')) AS SELECT 'a' AS f1; +SELECT * FROM t12913; +DROP TABLE t12913; + +# +# Bug#11028: Crash on create table like +# +create database mysqltest; +use mysqltest; +drop database mysqltest; +--error ER_NO_DB_ERROR +create table test.t1 like x; +--disable_warnings +drop table if exists test.t1; +--enable_warnings + +# +# Bug #6859: Bogus error message on attempt to CREATE TABLE t LIKE view +# +create database mysqltest; +use mysqltest; +create view v1 as select 'foo' from dual; +--error 1347 +create table t1 like v1; +drop view v1; +drop database mysqltest; +# Bug #6008 MySQL does not create warnings when +# creating database and using IF NOT EXISTS +# +create database mysqltest; +create database if not exists mysqltest character set latin2; +show create database mysqltest; +drop database mysqltest; +use test; +create table t1 (a int); +create table if not exists t1 (a int); +drop table t1; + +# BUG#14139 +create table t1 ( + a varchar(112) charset utf8 collate utf8_bin not null, + primary key (a) +) select 'test' as a ; +#--warning 1364 +show create table t1; +drop table t1; + +# +# BUG#14480: assert failure in CREATE ... SELECT because of wrong +# calculation of number of NULLs. +# +CREATE TABLE t2 ( + a int(11) default NULL +); +insert into t2 values(111); + +#--warning 1364 +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin not null, + b int not null, primary key (a) +) select a, 1 as b from t2 ; +show create table t1; +drop table t1; + +#--warning 1364 +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin not null, + b int not null, primary key (a) +) select a, 1 as c from t2 ; +show create table t1; +drop table t1; + +#--warning 1364 +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin not null, + b int null, primary key (a) +) select a, 1 as c from t2 ; +show create table t1; +drop table t1; + +#--warning 1364 +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin not null, + b int not null, primary key (a) +) select 'a' as a , 1 as b from t2 ; +show create table t1; +drop table t1; + +#--warning 1364 +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin, + b int not null, primary key (a) +) select 'a' as a , 1 as b from t2 ; +show create table t1; +drop table t1, t2; + +create table t1 ( + a1 int not null, + a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +); +insert into t1 values (1,1,1, 1,1,1, 1,1,1); + +#--warning 1364 +create table t2 ( + a1 varchar(12) charset utf8 collate utf8_bin not null, + a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, + primary key (a1) +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; +drop table t2; + +#--warning 1364 +create table t2 ( + a1 varchar(12) charset utf8 collate utf8_bin, + a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1; + +drop table t1, t2; +#--warning 1364 +create table t1 ( + a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int +); +insert into t1 values (1,1,1, 1,1,1, 1,1,1); + +#--warning 1364 +create table t2 ( + a1 varchar(12) charset utf8 collate utf8_bin not null, + a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, + primary key (a1) +) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; + +# Test the default value +drop table t2; + +create table t2 ( a int default 3, b int default 3) + select a1,a2 from t1; +show create table t2; + +drop table t1, t2; + +# +# Bug #15316 SET value having comma not correctly handled +# +--error 1367 +create table t1(a set("a,b","c,d") not null); + +# End of 4.1 tests + +# +# Bug #14155: Maximum value of MAX_ROWS handled incorrectly on 64-bit +# platforms +# +create table t1 (i int) engine=myisam max_rows=100000000000; +show create table t1; +alter table t1 max_rows=100; +show create table t1; +alter table t1 max_rows=100000000000; +show create table t1; +drop table t1; + +# +# Bug#21772: can not name a column 'upgrade' when create a table +# +create table t1 (upgrade int); +drop table t1; + +# End of 5.0 tests + +# +# Test of behaviour with CREATE ... SELECT +# + +CREATE TABLE t1 (a int, b int); +insert into t1 values (1,1),(1,2); +--error ER_DUP_ENTRY +CREATE TABLE t2 (primary key (a)) select * from t1; +# This should give warning +drop table if exists t2; +--error ER_DUP_ENTRY +CREATE TEMPORARY TABLE t2 (primary key (a)) select * from t1; +# This should give warning +drop table if exists t2; +CREATE TABLE t2 (a int, b int, primary key (a)); +--error ER_DUP_ENTRY +CREATE TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1; +SELECT * from t2; +TRUNCATE table t2; +--error ER_DUP_ENTRY +INSERT INTO t2 select * from t1; +SELECT * from t2; +drop table t2; + +CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a)); +--error ER_DUP_ENTRY +CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) select * from t1; +SELECT * from t2; +TRUNCATE table t2; +--error ER_DUP_ENTRY +INSERT INTO t2 select * from t1; +SELECT * from t2; +drop table t1,t2; + +# +# Test incorrect database names +# + +--error 1102 +CREATE DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +--error 1102 +DROP DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +--error 1064 +RENAME DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa TO a; +--error 1064 +RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +create database mysqltest; +--error 1064 +RENAME DATABASE mysqltest TO aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +drop database mysqltest; +--error 1102 +USE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; +--error 1102 +SHOW CREATE DATABASE aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/date_formats.test b/mysql-test/suite/pbxt/t/date_formats.test new file mode 100644 index 00000000000..6bfd6843d65 --- /dev/null +++ b/mysql-test/suite/pbxt/t/date_formats.test @@ -0,0 +1,343 @@ +# +# Test of date format functions +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +--replace_result ROW <format> STATEMENT <format> MIXED <format> +SHOW GLOBAL VARIABLES LIKE "%_format%"; +--replace_result ROW <format> STATEMENT <format> MIXED <format> +SHOW SESSION VARIABLES LIKE "%_format%"; + +# +# Test setting a lot of different formats to see which formats are accepted and +# which aren't +# + +SET time_format='%H%i%s'; +SET time_format='%H:%i:%s.%f'; +SET time_format='%h-%i-%s.%f%p'; +SET time_format='%h:%i:%s.%f %p'; +SET time_format='%h:%i:%s%p'; + +SET date_format='%Y%m%d'; +SET date_format='%Y.%m.%d'; +SET date_format='%d.%m.%Y'; +SET date_format='%m-%d-%Y'; + +set datetime_format= '%Y%m%d%H%i%s'; +set datetime_format= '%Y-%m-%d %H:%i:%s'; +set datetime_format= '%m-%d-%y %H:%i:%s.%f'; +set datetime_format= '%d-%m-%Y %h:%i:%s%p'; +set datetime_format= '%H:%i:%s %Y-%m-%d'; +set datetime_format= '%H:%i:%s.%f %m-%d-%Y'; +set datetime_format= '%h:%i:%s %p %Y-%m-%d'; +set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d'; + +--replace_result ROW <format> STATEMENT <format> MIXED <format> +SHOW SESSION VARIABLES LIKE "%format"; + +--error 1231 +SET time_format='%h:%i:%s'; +--error 1231 +SET time_format='%H %i:%s'; +--error 1231 +SET time_format='%H::%i:%s'; +--error 1231 +SET time_format='%H:%i:%s%f'; +--error 1231 +SET time_format='%H:%i.%f:%s'; +--error 1231 +SET time_format='%H:%i:%s%p'; +--error 1231 +SET time_format='%h:%i:%s.%f %p %Y-%m-%d'; +--error 1231 +SET time_format='%H%i%s.%f'; +--error 1231 +SET time_format='%H:%i-%s.%f'; +--error 1231 +SET date_format='%d.%m.%d'; +--error 1231 +SET datetime_format='%h.%m.%y %d.%i.%s'; +--error 1231 +set datetime_format= '%H:%i:%s.%f %p %Y-%m-%d'; + +# +# Test GLOBAL values + +set GLOBAL datetime_format= '%H:%i:%s %Y-%m-%d'; +SET SESSION datetime_format=default; +select @@global.datetime_format, @@session.datetime_format; +SET GLOBAL datetime_format=default; +SET SESSION datetime_format=default; +select @@global.datetime_format, @@session.datetime_format; + +SET GLOBAL date_format=default; +SET GLOBAL time_format=default; +SET GLOBAL datetime_format=default; +SET time_format=default; +SET date_format=default; +SET datetime_format=default; + +# +# The following tests will work only when we at some point will enable +# dynamic changing of formats +# + +# SET date_format='%d.%m.%Y'; +# select CAST('01.01.2001' as DATE) as a; +# SET datetime_format='%d.%m.%Y %H.%i.%s'; +# select CAST('01.01.2001 05.12.06' as DATETIME) as a; +# SET time_format='%H.%i.%s'; +# select CAST('05.12.06' as TIME) as a; +# +# SET datetime_format='%d.%m.%Y %h:%i:%s %p'; +# select CAST('01.01.2001 05:12:06AM' as DATETIME) as a; +# select CAST('01.01.2001 05:12:06 PM' as DATETIME) as a; +# +# SET time_format='%h:%i:%s %p'; +# select CAST('05:12:06 AM' as TIME) as a; +# select CAST('05:12:06.1234PM' as TIME) as a; +# +# SET time_format='%h.%i.%s %p'; +# SET date_format='%d.%m.%y'; +# SET datetime_format='%d.%m.%y %h.%i.%s %p'; +# select CAST('12-12-06' as DATE) as a; +# +# select adddate('01.01.97 11.59.59.000001 PM', 10); +# select datediff('31.12.97 11.59:59.000001 PM','01.01.98'); +# select weekofyear('31.11.97 11:59:59.000001 PM'); +# select makedate(1997,1); +# select addtime('31.12.97 11.59.59.999999 PM', '1 1.1.1.000002'); +# select maketime(23,11,12); +# select timediff('01.01.97 11:59:59.000001 PM','31.12.95 11:59:59.000002 PM'); +# +# SET time_format='%i:%s:%H'; +# select cast(str_to_date('15-01-2001 12:59:59', '%d-%m-%Y %H:%i:%S') as TIME); + +# +# Test of str_to_date +# + +# PS doesn't support fraction of a seconds +--disable_ps_protocol +select str_to_date(concat('15-01-2001',' 2:59:58.999'), + concat('%d-%m-%Y',' ','%H:%i:%s.%f')); +select STR_TO_DATE('2004.12.12 22.30.61','%Y.%m.%d %T'); +--enable_ps_protocol + +create table t1 (date char(30), format char(30) not null); +insert into t1 values +('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'), +('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S.%#'), +('2003-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'), +('2003-01-02 01:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f%p'), +('2003-01-02 02:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f %p'), +('2003-01-02 12:11:12.12345 am', '%Y-%m-%d %h:%i:%S.%f%p'), +('2003-01-02 11:11:12Pm', '%Y-%m-%d %h:%i:%S%p'), +('10:20:10', '%H:%i:%s'), +('10:20:10', '%h:%i:%s.%f'), +('10:20:10', '%T'), +('10:20:10AM', '%h:%i:%s%p'), +('10:20:10AM', '%r'), +('10:20:10.44AM', '%h:%i:%s.%f%p'), +('15-01-2001 12:59:58', '%d-%m-%Y %H:%i:%S'), +('15 September 2001', '%d %M %Y'), +('15 SEPTEMB 2001', '%d %M %Y'), +('15 MAY 2001', '%d %b %Y'), +('15th May 2001', '%D %b %Y'), +('Sunday 15 MAY 2001', '%W %d %b %Y'), +('Sund 15 MAY 2001', '%W %d %b %Y'), +('Tuesday 00 2002', '%W %U %Y'), +('Thursday 53 1998', '%W %u %Y'), +('Sunday 01 2001', '%W %v %x'), +('Tuesday 52 2001', '%W %V %X'), +('060 2004', '%j %Y'), +('4 53 1998', '%w %u %Y'), +('15-01-2001', '%d-%m-%Y %H:%i:%S'), +('15-01-20', '%d-%m-%y'), +('15-2001-1', '%d-%Y-%c'); + +# PS doesn't support fractional seconds +--disable_ps_protocol +select date,format,str_to_date(date, format) as str_to_date from t1; +# Use as a string +select date,format,concat('',str_to_date(date, format)) as con from t1; +# Use as datetime +select date,format,cast(str_to_date(date, format) as datetime) as datetime from t1; +select date,format,DATE(str_to_date(date, format)) as date2 from t1; +select date,format,TIME(str_to_date(date, format)) as time from t1; +select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1; +# Test small bug in %f handling +select concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d')); + +# Test wrong dates or converion specifiers + +truncate table t1; +insert into t1 values +('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'), +('2003-01-02 10:11:12.123456', '%Y-%m-%d %h:%i:%S %p'), +('2003-01-02 10:11:12AM', '%Y-%m-%d %h:%i:%S.%f %p'), +('2003-01-02 10:11:12AN', '%Y-%m-%d %h:%i:%S%p'), +('2003-01-02 10:11:12 PM', '%y-%m-%d %H:%i:%S %p'), +('10:20:10AM', '%H:%i:%s%p'), +('15 Septembei 2001', '%d %M %Y'), +('15 Ju 2001', '%d %M %Y'), +('Sund 15 MA', '%W %d %b %Y'), +('Thursdai 12 1998', '%W %u %Y'), +('Sunday 01 2001', '%W %v %X'), +('Tuesday 52 2001', '%W %V %x'), +('Tuesday 52 2001', '%W %V %Y'), +('Tuesday 52 2001', '%W %u %x'), +('7 53 1998', '%w %u %Y'), +(NULL, get_format(DATE,'USA')); +select date,format,str_to_date(date, format) as str_to_date from t1; +select date,format,concat(str_to_date(date, format),'') as con from t1; + +# Test 'maybe' date formats and 'strange but correct' results + +truncate table t1; +insert into t1 values +('10:20:10AM', '%h:%i:%s'), +('2003-01-02 10:11:12', '%Y-%m-%d %h:%i:%S'), +('03-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'); + +select date,format,str_to_date(date, format) as str_to_date from t1; +select date,format,concat(str_to_date(date, format),'') as con from t1; + +drop table t1; +--enable_ps_protocol + +# +# Test of get_format +# + +select get_format(DATE, 'USA') as a; +select get_format(TIME, 'internal') as a; +select get_format(DATETIME, 'eur') as a; +select get_format(TIMESTAMP, 'eur') as a; +select get_format(DATE, 'TEST') as a; +select str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA')); + +explain extended select makedate(1997,1), addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM"),cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME), maketime(23,11,12),microsecond("1997-12-31 23:59:59.000001"); + +# +# Test of date_format() +# + +create table t1 (d date); +insert into t1 values ('2004-07-14'),('2005-07-14'); +select date_format(d,"%d") from t1 order by 1; +drop table t1; + +# PS doesn't support fractional seconds +--disable_ps_protocol +select str_to_date("2003-....01ABCD-02 10:11:12.0012", "%Y-%.%m%@-%d %H:%i:%S.%f") as a; + + +create table t1 select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1, + str_to_date("10:11:12.0012", "%H:%i:%S.%f") as f2, + str_to_date("2003-01-02", "%Y-%m-%d") as f3, + str_to_date("02", "%d") as f4, str_to_date("02 10", "%d %H") as f5; +describe t1; +select * from t1; +drop table t1; + +create table t1 select "02 10" as a, "%d %H" as b; +select str_to_date(a,b) from t1; +create table t2 select str_to_date(a,b) from t1; +describe t2; +select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f") as f1, + str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S") as f2, + str_to_date("2003-01-02", "%Y-%m-%d") as f3, + str_to_date("02 10:11:12", "%d %H:%i:%S.%f") as f4, + str_to_date("02 10:11:12", "%d %H:%i:%S") as f5, + str_to_date("02 10", "%d %f") as f6; +drop table t1, t2; +select str_to_date("2003-01-02 10:11:12.0012ABCD", "%Y-%m-%d %H:%i:%S.%f") as f1, + addtime("-01:01:01.01 GGG", "-23:59:59.1") as f2, + microsecond("1997-12-31 23:59:59.01XXXX") as f3; + +select str_to_date("2003-04-05 g", "%Y-%m-%d") as f1, + str_to_date("2003-04-05 10:11:12.101010234567", "%Y-%m-%d %H:%i:%S.%f") as f2; +--enable_ps_protocol + +# +# Test of locale dependent date format (WL#2928 Date Translation NRE) +# +set names latin1; +select date_format('2004-01-01','%W (%a), %e %M (%b) %Y'); +set lc_time_names=ru_RU; +set names koi8r; +select date_format('2004-01-01','%W (%a), %e %M (%b) %Y'); +set lc_time_names=de_DE; +set names latin1; +select date_format('2004-01-01','%W (%a), %e %M (%b) %Y'); +set names latin1; +set lc_time_names=en_US; + +# +# Bug #14016 +# +create table t1 (f1 datetime); +insert into t1 (f1) values ("2005-01-01"); +insert into t1 (f1) values ("2005-02-01"); +select date_format(f1, "%m") as d1, date_format(f1, "%M") as d2 from t1 order by date_format(f1, "%M"); +drop table t1; + +# +# Bug #15828 +# +select str_to_date( 1, NULL ); +select str_to_date( NULL, 1 ); +select str_to_date( 1, IF(1=1,NULL,NULL) ); + +# +# Bug#11326 +# TIME_FORMAT using "%r" returns wrong hour using 24:00:00 in TIME column +# +# This tests that 24:00:00 does not return PM, when it should be AM. +# Some other values are being tested same time. +# + +SELECT TIME_FORMAT("24:00:00", '%r'); +SELECT TIME_FORMAT("00:00:00", '%r'); +SELECT TIME_FORMAT("12:00:00", '%r'); +SELECT TIME_FORMAT("15:00:00", '%r'); +SELECT TIME_FORMAT("01:00:00", '%r'); +SELECT TIME_FORMAT("25:00:00", '%r'); + +# +# Bug#11324 +# TIME_FORMAT using "%l:%i" returns 36:00 with 24:00:00 in TIME column +# +# This tests that 24:00:00 does not change to "36:00 AM". Testing +# some other values same time. +# + +SELECT TIME_FORMAT("00:00:00", '%l %p'); +SELECT TIME_FORMAT("01:00:00", '%l %p'); +SELECT TIME_FORMAT("12:00:00", '%l %p'); +SELECT TIME_FORMAT("23:00:00", '%l %p'); +SELECT TIME_FORMAT("24:00:00", '%l %p'); +SELECT TIME_FORMAT("25:00:00", '%l %p'); + +# +# Bug#20729: Bad date_format() call makes mysql server crash +# +SELECT DATE_FORMAT('%Y-%m-%d %H:%i:%s', 1151414896); + +# +# Bug #22029: str_to_date returning NULL +# + +select str_to_date('04 /30/2004', '%m /%d/%Y'); +select str_to_date('04/30 /2004', '%m /%d /%Y'); +select str_to_date('04/30/2004 ', '%m/%d/%Y '); + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo "End of 4.1 tests" diff --git a/mysql-test/suite/pbxt/t/default.test b/mysql-test/suite/pbxt/t/default.test new file mode 100644 index 00000000000..ea3786c7d3b --- /dev/null +++ b/mysql-test/suite/pbxt/t/default.test @@ -0,0 +1,145 @@ +# +# test of already fixed bugs +# +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6; +drop database if exists mysqltest; + +# +# Bug 10838 +# Insert causes warnings for no default values and corrupts tables +# +CREATE TABLE t1 (a varchar(30) binary NOT NULL DEFAULT ' ', + b varchar(1) binary NOT NULL DEFAULT ' ', + c varchar(4) binary NOT NULL DEFAULT '0000', + d tinyblob NULL, + e tinyblob NULL, + f tinyblob NULL, + g tinyblob NULL, + h tinyblob NULL, + i tinyblob NULL, + j tinyblob NULL, + k tinyblob NULL, + l tinyblob NULL, + m tinyblob NULL, + n tinyblob NULL, + o tinyblob NULL, + p tinyblob NULL, + q varchar(30) binary NOT NULL DEFAULT ' ', + r varchar(30) binary NOT NULL DEFAULT ' ', + s tinyblob NULL, + t varchar(4) binary NOT NULL DEFAULT ' ', + u varchar(1) binary NOT NULL DEFAULT ' ', + v varchar(30) binary NOT NULL DEFAULT ' ', + w varchar(30) binary NOT NULL DEFAULT ' ', + x tinyblob NULL, + y varchar(5) binary NOT NULL DEFAULT ' ', + z varchar(20) binary NOT NULL DEFAULT ' ', + a1 varchar(30) binary NOT NULL DEFAULT ' ', + b1 tinyblob NULL) +ENGINE=InnoDB DEFAULT CHARACTER SET = latin1 COLLATE latin1_bin; +--enable_warnings + +INSERT into t1 (b) values ('1'); +SHOW WARNINGS; +SELECT * from t1; + +CREATE TABLE t2 (a varchar(30) binary NOT NULL DEFAULT ' ', + b varchar(1) binary NOT NULL DEFAULT ' ', + c varchar(4) binary NOT NULL DEFAULT '0000', + d tinyblob NULL, + e tinyblob NULL, + f tinyblob NULL, + g tinyblob NULL, + h tinyblob NULL, + i tinyblob NULL, + j tinyblob NULL, + k tinyblob NULL, + l tinyblob NULL, + m tinyblob NULL, + n tinyblob NULL, + o tinyblob NULL, + p tinyblob NULL, + q varchar(30) binary NOT NULL DEFAULT ' ', + r varchar(30) binary NOT NULL DEFAULT ' ', + s tinyblob NULL, + t varchar(4) binary NOT NULL DEFAULT ' ', + u varchar(1) binary NOT NULL DEFAULT ' ', + v varchar(30) binary NOT NULL DEFAULT ' ', + w varchar(30) binary NOT NULL DEFAULT ' ', + x tinyblob NULL, + y varchar(5) binary NOT NULL DEFAULT ' ', + z varchar(20) binary NOT NULL DEFAULT ' ', + a1 varchar(30) binary NOT NULL DEFAULT ' ', + b1 tinyblob NULL) +ENGINE=MyISAM DEFAULT CHARACTER SET = latin1 COLLATE latin1_bin; + +SHOW CREATE TABLE t2; +INSERT into t2 (b) values ('1'); +SHOW WARNINGS; +SELECT * from t2; + +drop table t1; +drop table t2; + + +# +# Bug#20691: DATETIME col (NOT NULL, NO DEFAULT) may insert garbage when specifying DEFAULT +# +# From the docs: +# If the column can take NULL as a value, the column is defined with an +# explicit DEFAULT NULL clause. This is the same as before 5.0.2. +# +# If the column cannot take NULL as the value, MySQL defines the column with +# no explicit DEFAULT clause. For data entry, if an INSERT or REPLACE +# statement includes no value for the column, MySQL handles the column +# according to the SQL mode in effect at the time: +# +# * If strict SQL mode is not enabled, MySQL sets the column to the +# implicit default value for the column data type. +# +# * If strict mode is enabled, an error occurs for transactional tables and +# the statement is rolled back. For non-transactional tables, an error +# occurs, but if this happens for the second or subsequent row of a +# multiple-row statement, the preceding rows will have been inserted. +# +create table bug20691 (i int, d datetime NOT NULL, dn datetime not null default '0000-00-00 00:00:00'); +insert into bug20691 values (1, DEFAULT, DEFAULT), (1, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (1, DEFAULT, DEFAULT); +insert into bug20691 (i) values (2); +desc bug20691; +insert into bug20691 values (3, DEFAULT, DEFAULT), (3, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (3, DEFAULT, DEFAULT); +insert into bug20691 (i) values (4); +insert into bug20691 values (5, DEFAULT, DEFAULT), (5, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (5, DEFAULT, DEFAULT); +SET sql_mode = 'ALLOW_INVALID_DATES'; +insert into bug20691 values (6, DEFAULT, DEFAULT), (6, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (6, DEFAULT, DEFAULT); +SET sql_mode = 'STRICT_ALL_TABLES'; +--error 1364 +insert into bug20691 values (7, DEFAULT, DEFAULT), (7, '1975-07-10 07:10:03', '1978-01-13 14:08:51'), (7, DEFAULT, DEFAULT); +select * from bug20691 order by i asc; +drop table bug20691; + +SET sql_mode = ''; +create table bug20691 ( + a set('one', 'two', 'three') not null, + b enum('small', 'medium', 'large', 'enormous', 'ellisonego') not null, + c time not null, + d date not null, + e int not null, + f long not null, + g blob not null, + h datetime not null, + i decimal not null, + x int); +insert into bug20691 values (2, 3, 5, '0007-01-01', 11, 13, 17, '0019-01-01 00:00:00', 23, 1); +insert into bug20691 (x) values (2); +insert into bug20691 values (2, 3, 5, '0007-01-01', 11, 13, 17, '0019-01-01 00:00:00', 23, 3); +insert into bug20691 values (DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, 4); +select * from bug20691 order by x asc; +drop table bug20691; + +### +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests. + diff --git a/mysql-test/suite/pbxt/t/delete.test b/mysql-test/suite/pbxt/t/delete.test new file mode 100644 index 00000000000..d774ed50cd1 --- /dev/null +++ b/mysql-test/suite/pbxt/t/delete.test @@ -0,0 +1,198 @@ +# +# Check for problems with delete +# + +--disable_warnings +drop table if exists t1,t2,t3,t11,t12; +--enable_warnings +CREATE TABLE t1 (a tinyint(3), b tinyint(5)); +INSERT INTO t1 VALUES (1,1); +INSERT LOW_PRIORITY INTO t1 VALUES (1,2); +INSERT INTO t1 VALUES (1,3); +DELETE from t1 where a=1 limit 1; +DELETE LOW_PRIORITY from t1 where a=1; + +INSERT INTO t1 VALUES (1,1); +DELETE from t1; +LOCK TABLE t1 write; +INSERT INTO t1 VALUES (1,2); +DELETE from t1; +UNLOCK TABLES; +INSERT INTO t1 VALUES (1,2); +SET AUTOCOMMIT=0; +DELETE from t1; +SET AUTOCOMMIT=1; +drop table t1; + +# +# Test of delete when the delete will cause a node to disappear and reappear +# (This assumes a block size of 1024) +# + +create table t1 ( + a bigint not null, + b bigint not null default 0, + c bigint not null default 0, + d bigint not null default 0, + e bigint not null default 0, + f bigint not null default 0, + g bigint not null default 0, + h bigint not null default 0, + i bigint not null default 0, + j bigint not null default 0, + primary key (a,b,c,d,e,f,g,h,i,j)); +insert into t1 (a) values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23); +delete from t1 where a=26; +drop table t1; +create table t1 ( + a bigint not null, + b bigint not null default 0, + c bigint not null default 0, + d bigint not null default 0, + e bigint not null default 0, + f bigint not null default 0, + g bigint not null default 0, + h bigint not null default 0, + i bigint not null default 0, + j bigint not null default 0, + primary key (a,b,c,d,e,f,g,h,i,j)); +insert into t1 (a) values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23),(27); +delete from t1 where a=27; +drop table t1; + +CREATE TABLE `t1` ( + `i` int(10) NOT NULL default '0', + `i2` int(10) NOT NULL default '0', + PRIMARY KEY (`i`) +); +-- error 1054 +DELETE FROM t1 USING t1 WHERE post='1'; +drop table t1; + +# +# CHAR(0) bug - not actually DELETE bug, but anyway... +# + +CREATE TABLE t1 ( + bool char(0) default NULL, + not_null varchar(20) binary NOT NULL default '', + misc integer not null, + PRIMARY KEY (not_null) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (NULL,'a',4), (NULL,'b',5), (NULL,'c',6), (NULL,'d',7); + +select * from t1 where misc > 5 and bool is null; +delete from t1 where misc > 5 and bool is null; +select * from t1 where misc > 5 and bool is null; + +select count(*) from t1; +delete from t1 where 1 > 2; +select count(*) from t1; +delete from t1 where 3 > 2; +select count(*) from t1; + +drop table t1; +# +# Bug #5733: Table handler error with self-join multi-table DELETE +# + +create table t1 (a int not null auto_increment primary key, b char(32)); +insert into t1 (b) values ('apple'), ('apple'); +select * from t1; +delete t1 from t1, t1 as t2 where t1.b = t2.b and t1.a > t2.a; +select * from t1; +drop table t1; + +# +# IGNORE option +# +create table t11 (a int NOT NULL, b int, primary key (a)); +create table t12 (a int NOT NULL, b int, primary key (a)); +create table t2 (a int NOT NULL, b int, primary key (a)); +insert into t11 values (0, 10),(1, 11),(2, 12); +insert into t12 values (33, 10),(0, 11),(2, 12); +insert into t2 values (1, 21),(2, 12),(3, 23); +select * from t11; +select * from t12; +select * from t2; +-- error 1242 +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b <> (select b from t2 where t11.a < t2.a); +select * from t11; +select * from t12; +delete ignore t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b <> (select b from t2 where t11.a < t2.a); +select * from t11; +select * from t12; +insert into t11 values (2, 12); +-- error 1242 +delete from t11 where t11.b <> (select b from t2 where t11.a < t2.a); +select * from t11; +delete ignore from t11 where t11.b <> (select b from t2 where t11.a < t2.a); +select * from t11; +drop table t11, t12, t2; + +# +# Bug #4198: deletion and KEYREAD +# + +create table t1 (a int, b int, unique key (a), key (b)); +insert into t1 values (3, 3), (7, 7); +delete t1 from t1 where a = 3; +check table t1; +select * from t1; +drop table t1; + +# +# Bug #8392: delete with ORDER BY containing a direct reference to the table +# + +CREATE TABLE t1 ( a int PRIMARY KEY ); +DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a; +INSERT INTO t1 VALUES (0),(1),(2); +DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a LIMIT 1; +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #21392: multi-table delete with alias table name fails with +# 1003: Incorrect table name +# + +create table t1 (a int); +delete `4.t1` from t1 as `4.t1` where `4.t1`.a = 5; +delete FROM `4.t1` USING t1 as `4.t1` where `4.t1`.a = 5; +drop table t1; + +# End of 4.1 tests + +# +# Test of multi-delete where we are not scanning the first table +# + +CREATE TABLE t1 (a int not null,b int not null); +CREATE TABLE t2 (a int not null, b int not null, primary key (a,b)); +CREATE TABLE t3 (a int not null, b int not null, primary key (a,b)); +insert into t1 values (1,1),(2,1),(1,3); +insert into t2 values (1,1),(2,2),(3,3); +insert into t3 values (1,1),(2,1),(1,3); +select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b; +explain select * from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b; +delete t2.*,t3.* from t1,t2,t3 where t1.a=t2.a AND t2.b=t3.a and t1.b=t3.b; +# This should be empty +select * from t3; +drop table t1,t2,t3; + +# +# Bug #8143: deleting '0000-00-00' values using IS NULL +# + +create table t1(a date not null); +insert into t1 values (0); +select * from t1 where a is null; +delete from t1 where a is null; +select count(*) from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/derived.test b/mysql-test/suite/pbxt/t/derived.test new file mode 100644 index 00000000000..33ad994278c --- /dev/null +++ b/mysql-test/suite/pbxt/t/derived.test @@ -0,0 +1,283 @@ +# Initialize +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +select * from (select 2 from DUAL) b; +-- error 1054 +SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; +-- error 1054 +SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); +select t1.a,t3.y from t1,(select a as y from t2 where b='c') as t3 where t1.a = t3.y; +select t1.a,t3.a from t1,(select * from t2 where b='c') as t3 where t1.a = t3.a; +CREATE TABLE t3 (a int not null, b char (10) not null); +insert into t3 values (3,'f'),(4,'y'),(5,'z'),(6,'c'); +select t1.a,t4.y from t1,(select t2.a as y from t2,(select t3.b from t3 where t3.a>3) as t5 where t2.b=t5.b) as t4 where t1.a = t4.y; +--error 1054 +SELECT a FROM (SELECT 1 FROM (SELECT 1) a HAVING a=1) b; +--error 1052 +SELECT a,b as a FROM (SELECT '1' as a,'2' as b) b HAVING a=1; +SELECT a,2 as a FROM (SELECT '1' as a) b HAVING a=2; +SELECT a,2 as a FROM (SELECT '1' as a) b HAVING a=1; +--error 1054 +SELECT 1 FROM (SELECT 1) a WHERE a=2; +--error 1054 +SELECT (SELECT 1) as a FROM (SELECT 1 FROM t1 HAVING a=1) as a; +select * from t1 as x1, (select * from t1) as x2; +explain select * from t1 as x1, (select * from t1) as x2; +drop table if exists t2,t3; +select * from (select 1) as a; +select a from (select 1 as a) as b; +select 1 from (select 1) as a; +select * from (select * from t1 union select * from t1) a; +select * from (select * from t1 union all select * from t1) a; +select * from (select * from t1 union all select * from t1 limit 2) a; +explain select * from (select * from t1 union select * from t1) a; +explain select * from (select * from t1 union all select * from t1) a; +CREATE TABLE t2 (a int not null); +insert into t2 values(1); +select * from (select * from t1 where t1.a=(select a from t2 where t2.a=t1.a)) a; +select * from (select * from t1 where t1.a=(select t2.a from t2 where t2.a=t1.a) union select t1.a, t1.b from t1) a; +explain select * from (select t1.*, t2.a as t2a from t1,t2 where t1.a=t2.a) t1; +drop table t1, t2; +create table t1(a int not null, t char(8), index(a)); +disable_query_log; +let $1 = 10000; +while ($1) + { + eval insert into t1 values ($1,'$1'); + dec $1; + } +enable_query_log; +SELECT * FROM (SELECT * FROM t1) as b ORDER BY a ASC LIMIT 0,20; +explain select count(*) from t1 as tt1, (select * from t1) as tt2; +drop table t1; +SELECT * FROM (SELECT (SELECT * FROM (SELECT 1 as a) as a )) as b; +select * from (select 1 as a) b left join (select 2 as a) c using(a); +--error 1054 +SELECT * FROM (SELECT 1 UNION SELECT a) b; +--error 1054 +SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; +--error 1054 +SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; +--error 1054 +select 1 from (select 2) a order by 0; + +# +# Test of explain (bug #251) +# + +create table t1 (id int); +insert into t1 values (1),(2),(3); +describe select * from (select * from t1 group by id) bar; +drop table t1; + +# +# test->used_keys test for derived tables +# +create table t1 (mat_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, matintnum CHAR(6) NOT NULL, test MEDIUMINT UNSIGNED NULL); +create table t2 (mat_id MEDIUMINT UNSIGNED NOT NULL, pla_id MEDIUMINT UNSIGNED NOT NULL); +insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd', 4), (NULL, 'e', 5), (NULL, 'f', 6), (NULL, 'g', 7), (NULL, 'h', 8), (NULL, 'i', 9); +insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105); + +SELECT STRAIGHT_JOIN d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +SELECT STRAIGHT_JOIN d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; + +explain SELECT STRAIGHT_JOIN d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +explain SELECT STRAIGHT_JOIN d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +drop table t1,t2; + +# +# derived table reference +# +SELECT a.x FROM (SELECT 1 AS x) AS a HAVING a.x = 1; + +# +# Test for select if database is not selected. +# +# Connect without a database +create user mysqltest_1; +create table t1 select 1 as a; +analyze table t1; # PBXT: Required to get a consitent result +connect (con1,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK); +connection con1; +--error 1046 +select 2 as a from (select * from t1) b; +use test; +select 2 as a from (select * from t1) b; +drop table t1; +--error 1064 +select mail_id, if(folder.f_description!='', folder.f_description, folder.f_name) as folder_name, date, address_id, phrase, address, subject from folder, (select mail.mail_id as mail_id, date_format(mail.h_date, '%b %e, %Y %h:%i') as date, mail.folder_id, sender.address_id as address_id, sender.phrase as phrase, sender.address as address, mail.h_subject as subject from mail left join mxa as mxa_sender on mail.mail_id=mxa_sender.mail_id and mxa_sender.type='from' left join address as sender on mxa_sender.address_id=sender.address_id mxa as mxa_recipient, address as recipient, where 1 and mail.mail_id=mxa_recipient.mail_id and mxa_recipient.address_id=recipient.address_id and mxa_recipient.type='to' and match(sender.phrase, sender.address, sender.comment) against ('jeremy' in boolean mode) and match(recipient.phrase, recipient.address, recipient.comment) against ('monty' in boolean mode) order by mail.h_date desc limit 0, 25 ) as query where query.folder_id=folder.folder_id; + +# +# UPDATE/DELETE/INSERT of derived tables +# +create table t1 (a int); +insert into t1 values (1),(2),(3); +-- error 1288 +update (select * from t1) as t1 set a = 5; +-- error 1064 +delete from (select * from t1); +-- error 1064 +insert into (select * from t1) values (5); +drop table t1; + +# +# deived tables with subquery inside all by one table +# +create table t1 (E1 INTEGER UNSIGNED NOT NULL, E2 INTEGER UNSIGNED NOT NULL, E3 INTEGER UNSIGNED NOT NULL, PRIMARY KEY(E1) +); +insert into t1 VALUES(1,1,1), (2,2,1); +select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2; +explain select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2; +drop table t1; + +create table t1 (a int); +insert into t1 values (1),(2); +select * from ( select * from t1 union select * from t1) a,(select * from t1 union select * from t1) b; +explain select * from ( select * from t1 union select * from t1) a,(select * from t1 union select * from t1) b; +drop table t1; + +# +# multi-update & multi-delete with derived tables +# +CREATE TABLE `t1` ( + `N` int(11) unsigned NOT NULL default '0', + `M` tinyint(1) default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO `t1` (N, M) VALUES (1, 0),(1, 0),(1, 0),(2, 0),(2, 0),(3, 0); +UPDATE `t1` AS P1 INNER JOIN (SELECT N FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N SET P1.M = 2; +select * from t1; +-- error 1288 +UPDATE `t1` AS P1 INNER JOIN (SELECT N FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N SET P1.M = 2, P2.N = 2; +-- error 1054 +UPDATE `t1` AS P1 INNER JOIN (SELECT aaaa FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N SET P1.M = 2; +delete P1.* from `t1` AS P1 INNER JOIN (SELECT N FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N; +select * from t1; +--replace_result P2 p2 +--error ER_UNKNOWN_TABLE +delete P1.*,P2.* from `t1` AS P1 INNER JOIN (SELECT N FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N; +-- error 1054 +delete P1.* from `t1` AS P1 INNER JOIN (SELECT aaa FROM `t1` GROUP BY N HAVING Count(M) > 1) AS P2 ON P1.N = P2.N; +drop table t1; + +# +# correct lex->current_select +# +CREATE TABLE t1 ( + OBJECTID int(11) NOT NULL default '0', + SORTORDER int(11) NOT NULL auto_increment, + KEY t1_SortIndex (SORTORDER), + KEY t1_IdIndex (OBJECTID) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +CREATE TABLE t2 ( + ID int(11) default NULL, + PARID int(11) default NULL, + UNIQUE KEY t2_ID_IDX (ID), + KEY t2_PARID_IDX (PARID) +) engine=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO t2 VALUES (1000,0),(1001,0),(1002,0),(1003,0),(1008,1),(1009,1),(1010,1),(1011,1),(1016,2); +CREATE TABLE t3 ( + ID int(11) default NULL, + DATA decimal(10,2) default NULL, + UNIQUE KEY t3_ID_IDX (ID) +) engine=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO t3 VALUES (1000,0.00),(1001,0.25),(1002,0.50),(1003,0.75),(1008,1.00),(1009,1.25),(1010,1.50),(1011,1.75); +select 497, TMP.ID, NULL from (select 497 as ID, MAX(t3.DATA) as DATA from t1 join t2 on (t1.ObjectID = t2.ID) join t3 on (t1.ObjectID = t3.ID) group by t2.ParID order by DATA DESC) as TMP; +drop table t1, t2, t3; + +# +# explain derived +# +CREATE TABLE t1 (name char(1) default NULL, val int(5) default NULL); +INSERT INTO t1 VALUES ('a',1), ('a',2), ('a',2), ('a',2), ('a',3), ('a',6), ('a',7), ('a',11), ('a',11), ('a',12), ('a',13), ('a',13), ('a',20), ('b',2), ('b',3), ('b',4), ('b',5); +SELECT s.name, AVG(s.val) AS median FROM (SELECT x.name, x.val FROM t1 x, t1 y WHERE x.name=y.name GROUP BY x.name, x.val HAVING SUM(y.val <= x.val) >= COUNT(*)/2 AND SUM(y.val >= x.val) >= COUNT(*)/2) AS s GROUP BY s.name; +explain SELECT s.name, AVG(s.val) AS median FROM (SELECT x.name, x.val FROM t1 x, t1 y WHERE x.name=y.name GROUP BY x.name, x.val HAVING SUM(y.val <= x.val) >= COUNT(*)/2 AND SUM(y.val >= x.val) >= COUNT(*)/2) AS s GROUP BY s.name; +drop table t1; + +# +# "Using index" in explain +# +create table t2 (a int, b int, primary key (a)); +insert into t2 values (1,7),(2,7); +explain select a from t2 where a>1; +explain select a from (select a from t2 where a>1) tt; +drop table t2; + +# +# select list counter +# +CREATE TABLE `t1` ( `itemid` int(11) NOT NULL default '0', `grpid` varchar(15) NOT NULL default '', `vendor` int(11) NOT NULL default '0', `date_` date NOT NULL default '0000-00-00', `price` decimal(12,2) NOT NULL default '0.00', PRIMARY KEY (`itemid`,`grpid`,`vendor`,`date_`), KEY `itemid` (`itemid`,`vendor`), KEY `itemid_2` (`itemid`,`date_`)); +insert into t1 values (128, 'rozn', 2, now(), 10),(128, 'rozn', 1, now(), 10); +SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MAX(concat(date_,";",price)), 12) price FROM t1 WHERE itemid=128 AND grpid='rozn' GROUP BY itemid, grpid, vendor) lastprices; +DROP TABLE t1; + +# +# DISTINCT over grouped select on subquery in the FROM clause +# +create table t1 (a integer, b integer); +insert into t1 values (1,4), (2,2),(2,2), (4,1),(4,1),(4,1),(4,1); +select distinct sum(b) from t1 group by a; +select distinct sum(b) from (select a,b from t1) y group by a; +drop table t1; + + +# +# Test for bug #7413 "Subquery with non-scalar results participating in +# select list of derived table crashes server" aka "VIEW with sub query can +# cause the MySQL server to crash". If we have encountered problem during +# filling of derived table we should report error and perform cleanup +# properly. +# +CREATE TABLE t1 (a char(10), b char(10)); +INSERT INTO t1 VALUES ('root','localhost'), ('root','%'); +--error 1242 +SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c; +DROP TABLE t1; +# +# test of union subquery in the FROM clause with complex distinct/all (BUG#6565) +# +create table t1(a int); +create table t2(a int); +create table t3(a int); +insert into t1 values(1),(1); +insert into t2 values(2),(2); +insert into t3 values(3),(3); +select * from t1 union distinct select * from t2 union all select * from t3; +select * from (select * from t1 union distinct select * from t2 union all select * from t3) X; +drop table t1, t2, t3; + +# +# Bug #11864 non unique names are allowed in subquery +# +create table t1 (a int); +create table t2 (a int); +--error 1060 +select * from (select * from t1,t2) foo; +drop table t1,t2; + +# +# Bug#10586 - query works with 4.1.8, but not with 4.1.11 +# +create table t1 (ID int unsigned not null auto_increment, + DATA varchar(5) not null, primary key (ID)); +create table t2 (ID int unsigned not null auto_increment, + DATA varchar(5) not null, FID int unsigned not null, + primary key (ID)); +select A.* from (t1 inner join (select * from t2) as A on t1.ID = A.FID); +select t2.* from ((select * from t1) as A inner join t2 on A.ID = t2.FID); +select t2.* from (select * from t1) as A inner join t2 on A.ID = t2.FID; +drop table t1, t2; + +disconnect con1; +connection default; +drop user mysqltest_1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/dirty_close.test b/mysql-test/suite/pbxt/t/dirty_close.test new file mode 100644 index 00000000000..d2c2d60af23 --- /dev/null +++ b/mysql-test/suite/pbxt/t/dirty_close.test @@ -0,0 +1,19 @@ +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection con1; +dirty_close con1; +connection con2; + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (n int); +insert into t1 values (1),(2),(3); +select * from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/distinct.test b/mysql-test/suite/pbxt/t/distinct.test new file mode 100644 index 00000000000..5d02b38aed8 --- /dev/null +++ b/mysql-test/suite/pbxt/t/distinct.test @@ -0,0 +1,531 @@ +# +# Bug with distinct and INSERT INTO +# Bug with group by and not used fields +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +CREATE TABLE t1 (id int,facility char(20)); +CREATE TABLE t2 (facility char(20)); +INSERT INTO t1 VALUES (NULL,NULL); +INSERT INTO t1 VALUES (-1,''); +INSERT INTO t1 VALUES (0,''); +INSERT INTO t1 VALUES (1,'/L'); +INSERT INTO t1 VALUES (2,'A01'); +INSERT INTO t1 VALUES (3,'ANC'); +INSERT INTO t1 VALUES (4,'F01'); +INSERT INTO t1 VALUES (5,'FBX'); +INSERT INTO t1 VALUES (6,'MT'); +INSERT INTO t1 VALUES (7,'P'); +INSERT INTO t1 VALUES (8,'RV'); +INSERT INTO t1 VALUES (9,'SRV'); +INSERT INTO t1 VALUES (10,'VMT'); +INSERT INTO t2 SELECT DISTINCT FACILITY FROM t1; + +select id from t1 group by id; +select * from t1 order by id; +select id-5,facility from t1 order by "id-5"; +select id,concat(facility) from t1 group by id ; +select id+0 as a,max(id),concat(facility) as b from t1 group by a order by b desc,a; +select id >= 0 and id <= 5 as grp,count(*) from t1 group by grp; + +SELECT DISTINCT FACILITY FROM t1; +SELECT FACILITY FROM t2; +SELECT count(*) from t1,t2 where t1.facility=t2.facility; +select count(facility) from t1; +select count(*) from t1; +select count(*) from t1 where facility IS NULL; +select count(*) from t1 where facility = NULL; +select count(*) from t1 where facility IS NOT NULL; +select count(*) from t1 where id IS NULL; +select count(*) from t1 where id IS NOT NULL; + +drop table t1,t2; + +# +# Problem with distinct without results +# +CREATE TABLE t1 (UserId int(11) DEFAULT '0' NOT NULL); +INSERT INTO t1 VALUES (20); +INSERT INTO t1 VALUES (27); + +SELECT UserId FROM t1 WHERE Userid=22; +SELECT UserId FROM t1 WHERE UserId=22 group by Userid; +SELECT DISTINCT UserId FROM t1 WHERE UserId=22 group by Userid; +SELECT DISTINCT UserId FROM t1 WHERE UserId=22; +drop table t1; + +# +# Test of distinct +# + +CREATE TABLE t1 (a int(10) unsigned not null primary key,b int(10) unsigned); +INSERT INTO t1 VALUES (1,1),(2,1),(3,1),(4,1); +CREATE TABLE t2 (a int(10) unsigned not null, key (A)); +INSERT INTO t2 VALUES (1),(2); +CREATE TABLE t3 (a int(10) unsigned, key(A), b text); +INSERT INTO t3 VALUES (1,'1'),(2,'2'); +SELECT DISTINCT t3.b FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; +INSERT INTO t2 values (1),(2),(3); +INSERT INTO t3 VALUES (1,'1'),(2,'2'),(1,'1'),(2,'2'); +explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; +SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; + +# Create a lot of data into t3; +create temporary table t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; +insert into t4 select * from t3; +insert into t3 select * from t4; + +explain select distinct t1.a from t1,t3 where t1.a=t3.a; +#flush status; +select distinct t1.a from t1,t3 where t1.a=t3.a; +#show status like 'Handler%'; +#flush status; +select distinct 1 from t1,t3 where t1.a=t3.a; +#show status like 'Handler%'; + +explain SELECT distinct t1.a from t1; +explain SELECT distinct t1.a from t1 order by a desc; +explain SELECT t1.a from t1 group by a order by a desc; +explain SELECT distinct t1.a from t1 order by a desc limit 1; +explain SELECT distinct a from t3 order by a desc limit 2; +explain SELECT distinct a,b from t3 order by a+1; +explain SELECT distinct a,b from t3 order by a limit 10; +explain SELECT a,b from t3 group by a,b order by a+1; + +drop table t1,t2,t3,t4; + +CREATE TABLE t1 (name varchar(255)); +INSERT INTO t1 VALUES ('aa'),('ab'),('ac'),('ad'),('ae'); +SELECT DISTINCT * FROM t1 LIMIT 2; +SELECT DISTINCT name FROM t1 LIMIT 2; +SELECT DISTINCT 1 FROM t1 LIMIT 2; +drop table t1; + +CREATE TABLE t1 ( + ID int(11) NOT NULL auto_increment, + NAME varchar(75) DEFAULT '' NOT NULL, + LINK_ID int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (ID), + KEY NAME (NAME), + KEY LINK_ID (LINK_ID) +); + +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0),(2,'Jack',0),(3,'Bill',0); + +CREATE TABLE t2 ( + ID int(11) NOT NULL auto_increment, + NAME varchar(150) DEFAULT '' NOT NULL, + PRIMARY KEY (ID), + KEY NAME (NAME) +); + +SELECT DISTINCT + t2.id AS key_link_id, + t2.name AS link +FROM t1 +LEFT JOIN t2 ON t1.link_id=t2.id +GROUP BY t1.id +ORDER BY link; +drop table t1,t2; + +# +# Problem with table dependencies +# + +create table t1 ( + id int not null, + name tinytext not null, + unique (id) +); +create table t2 ( + id int not null, + idx int not null, + unique (id, idx) +); +create table t3 ( + id int not null, + idx int not null, + unique (id, idx) +); +insert into t1 values (1,'yes'), (2,'no'); +insert into t2 values (1,1); +insert into t3 values (1,1); +EXPLAIN +SELECT DISTINCT + t1.id +from + t1 + straight_join + t2 + straight_join + t3 + straight_join + t1 as j_lj_t2 left join t2 as t2_lj + on j_lj_t2.id=t2_lj.id + straight_join + t1 as j_lj_t3 left join t3 as t3_lj + on j_lj_t3.id=t3_lj.id +WHERE + ((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2)) + AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); +SELECT DISTINCT + t1.id +from + t1 + straight_join + t2 + straight_join + t3 + straight_join + t1 as j_lj_t2 left join t2 as t2_lj + on j_lj_t2.id=t2_lj.id + straight_join + t1 as j_lj_t3 left join t3 as t3_lj + on j_lj_t3.id=t3_lj.id +WHERE + ((t1.id=j_lj_t2.id AND t2_lj.id IS NULL) OR (t1.id=t2.id AND t2.idx=2)) + AND ((t1.id=j_lj_t3.id AND t3_lj.id IS NULL) OR (t1.id=t3.id AND t3.idx=2)); +drop table t1,t2,t3; + +# +# Test using DISTINCT on a function that contains a group function +# This also test the case when one doesn't use all fields in GROUP BY. +# + +create table t1 (a int not null, b int not null, t time); +insert into t1 values (1,1,"00:06:15"),(1,2,"00:06:15"),(1,2,"00:30:15"),(1,3,"00:06:15"),(1,3,"00:30:15"); +select a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b; +select distinct a,sec_to_time(sum(time_to_sec(t))) from t1 group by a,b; +create table t2 (a int not null primary key, b int); +insert into t2 values (1,1),(2,2),(3,3); +select t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b; +select distinct t1.a,sec_to_time(sum(time_to_sec(t))) from t1 left join t2 on (t1.b=t2.a) group by t1.a,t2.b; +drop table t1,t2; + +# +# Test problem with DISTINCT and HAVING +# +create table t1 (a int not null,b char(5), c text); +insert into t1 (a) values (1),(2),(3),(4),(1),(2),(3),(4); +select distinct a from t1 group by b,a having a > 2 order by a desc; +select distinct a,c from t1 group by b,c,a having a > 2 order by a desc; +drop table t1; + +# +# Test problem with DISTINCT and ORDER BY DESC +# + +create table t1 (a char(1), key(a)) engine=myisam; +insert into t1 values('1'),('1'); +select * from t1 where a >= '1'; +select distinct a from t1 order by a desc; +select distinct a from t1 where a >= '1' order by a desc; +drop table t1; + +# +# Test when using a not previously used column in ORDER BY +# + +CREATE TABLE t1 (email varchar(50), infoID BIGINT, dateentered DATETIME); +CREATE TABLE t2 (infoID BIGINT, shipcode varchar(10)); + +INSERT INTO t1 (email, infoID, dateentered) VALUES + ('test1@testdomain.com', 1, '2002-07-30 22:56:38'), + ('test1@testdomain.com', 1, '2002-07-27 22:58:16'), + ('test2@testdomain.com', 1, '2002-06-19 15:22:19'), + ('test2@testdomain.com', 2, '2002-06-18 14:23:47'), + ('test3@testdomain.com', 1, '2002-05-19 22:17:32'); + +INSERT INTO t2(infoID, shipcode) VALUES + (1, 'Z001'), + (2, 'R002'); + +SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID; +SELECT DISTINCTROW email FROM t1 ORDER BY dateentered DESC; +SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID ORDER BY dateentered DESC; +drop table t1,t2; + +# +# test with table.* in DISTINCT +# + +CREATE TABLE t1 (privatemessageid int(10) unsigned NOT NULL auto_increment, folderid smallint(6) NOT NULL default '0', userid int(10) unsigned NOT NULL default '0', touserid int(10) unsigned NOT NULL default '0', fromuserid int(10) unsigned NOT NULL default '0', title varchar(250) NOT NULL default '', message mediumtext NOT NULL, dateline int(10) unsigned NOT NULL default '0', showsignature smallint(6) NOT NULL default '0', iconid smallint(5) unsigned NOT NULL default '0', messageread smallint(6) NOT NULL default '0', readtime int(10) unsigned NOT NULL default '0', receipt smallint(6) unsigned NOT NULL default '0', deleteprompt smallint(6) unsigned NOT NULL default '0', multiplerecipients smallint(6) unsigned NOT NULL default '0', PRIMARY KEY (privatemessageid), KEY userid (userid)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (128,0,33,33,8,':D','',996121863,1,0,2,996122850,2,0,0); +CREATE TABLE t2 (userid int(10) unsigned NOT NULL auto_increment, usergroupid smallint(5) unsigned NOT NULL default '0', username varchar(50) NOT NULL default '', password varchar(50) NOT NULL default '', email varchar(50) NOT NULL default '', styleid smallint(5) unsigned NOT NULL default '0', parentemail varchar(50) NOT NULL default '', coppauser smallint(6) NOT NULL default '0', homepage varchar(100) NOT NULL default '', icq varchar(20) NOT NULL default '', aim varchar(20) NOT NULL default '', yahoo varchar(20) NOT NULL default '', signature mediumtext NOT NULL, adminemail smallint(6) NOT NULL default '0', showemail smallint(6) NOT NULL default '0', invisible smallint(6) NOT NULL default '0', usertitle varchar(250) NOT NULL default '', customtitle smallint(6) NOT NULL default '0', joindate int(10) unsigned NOT NULL default '0', cookieuser smallint(6) NOT NULL default '0', daysprune smallint(6) NOT NULL default '0', lastvisit int(10) unsigned NOT NULL default '0', lastactivity int(10) unsigned NOT NULL default '0', lastpost int(10) unsigned NOT NULL default '0', posts smallint(5) unsigned NOT NULL default '0', timezoneoffset varchar(4) NOT NULL default '', emailnotification smallint(6) NOT NULL default '0', buddylist mediumtext NOT NULL, ignorelist mediumtext NOT NULL, pmfolders mediumtext NOT NULL, receivepm smallint(6) NOT NULL default '0', emailonpm smallint(6) NOT NULL default '0', pmpopup smallint(6) NOT NULL default '0', avatarid smallint(6) NOT NULL default '0', avatarrevision int(6) unsigned NOT NULL default '0', options smallint(6) NOT NULL default '15', birthday date NOT NULL default '0000-00-00', maxposts smallint(6) NOT NULL default '-1', startofweek smallint(6) NOT NULL default '1', ipaddress varchar(20) NOT NULL default '', referrerid int(10) unsigned NOT NULL default '0', nosessionhash smallint(6) NOT NULL default '0', autorefresh smallint(6) NOT NULL default '-1', messagepopup tinyint(2) NOT NULL default '0', inforum smallint(5) unsigned NOT NULL default '0', ratenum smallint(5) unsigned NOT NULL default '0', ratetotal smallint(5) unsigned NOT NULL default '0', allowrate smallint(5) unsigned NOT NULL default '1', PRIMARY KEY (userid), KEY usergroupid (usergroupid), KEY username (username), KEY inforum (inforum)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (33,6,'Kevin','0','kevin@stileproject.com',1,'',0,'http://www.stileproject.com','','','','',1,1,0,'Administrator',0,996120694,1,-1,1030996168,1031027028,1030599436,36,'-6',0,'','','',1,0,1,0,0,15,'0000-00-00',-1,1,'64.0.0.0',0,1,-1,0,0,4,19,1); +SELECT DISTINCT t1.*, t2.* FROM t1 LEFT JOIN t2 ON (t2.userid = t1.touserid); +DROP TABLE t1,t2; + +# +# test with const_item in ORDER BY +# + +CREATE TABLE t1 (a int primary key, b int, c int); +INSERT t1 VALUES (1,2,3); +CREATE TABLE t2 (a int primary key, b int, c int); +INSERT t2 VALUES (3,4,5); +SELECT DISTINCT t1.a, t2.b FROM t1, t2 WHERE t1.a=1 ORDER BY t2.c; +DROP TABLE t1,t2; + +# +# Test of LEFT() with distinct +# + +CREATE table t1 ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL default '', PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=3 ; +INSERT INTO t1 VALUES (1, 'aaaaa'); +INSERT INTO t1 VALUES (3, 'aaaaa'); +INSERT INTO t1 VALUES (2, 'eeeeeee'); +select distinct left(name,1) as name from t1; +drop table t1; + +# +# Test case from sel000100 +# + +CREATE TABLE t1 ( + ID int(11) NOT NULL auto_increment, + NAME varchar(75) DEFAULT '' NOT NULL, + LINK_ID int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (ID), + KEY NAME (NAME), + KEY LINK_ID (LINK_ID) +); + +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (1,'Mike',0); +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (2,'Jack',0); +INSERT INTO t1 (ID, NAME, LINK_ID) VALUES (3,'Bill',0); + +CREATE TABLE t2 ( + ID int(11) NOT NULL auto_increment, + NAME varchar(150) DEFAULT '' NOT NULL, + PRIMARY KEY (ID), + KEY NAME (NAME) +); + +SELECT DISTINCT + t2.id AS key_link_id, + t2.name AS link +FROM t1 +LEFT JOIN t2 ON t1.link_id=t2.id +GROUP BY t1.id +ORDER BY link; +drop table t1,t2; + +# +# test case for #674 +# + +CREATE TABLE t1 ( + html varchar(5) default NULL, + rin int(11) default '0', + rout int(11) default '0' +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES ('1',1,0); +SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; +drop table t1; + +# +# Test cases for #12625: DISTINCT for a list with constants +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1),(2),(3),(4),(5); +SELECT DISTINCT a, 1 FROM t1; +SELECT DISTINCT 1, a FROM t1; + +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES (1,1),(2,2),(2,3),(2,4),(3,5); +SELECT DISTINCT a, b, 2 FROM t2; +SELECT DISTINCT 2, a, b FROM t2; +SELECT DISTINCT a, 2, b FROM t2; + +DROP TABLE t1,t2; +# +# Bug#16458: Simple SELECT FOR UPDATE causes "Result Set not updatable" +# error. +# +CREATE TABLE t1(a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,1), (3,1); +EXPLAIN SELECT DISTINCT a FROM t1; +EXPLAIN SELECT DISTINCT a,b FROM t1; +EXPLAIN SELECT DISTINCT t1_1.a, t1_1.b FROM t1 t1_1, t1 t1_2; +EXPLAIN SELECT DISTINCT t1_1.a, t1_1.b FROM t1 t1_1, t1 t1_2 + WHERE t1_1.a = t1_2.a; +EXPLAIN SELECT a FROM t1 GROUP BY a; +EXPLAIN SELECT a,b FROM t1 GROUP BY a,b; +EXPLAIN SELECT DISTINCT a,b FROM t1 GROUP BY a,b; + +CREATE TABLE t2(a INT, b INT, c INT, d INT, PRIMARY KEY (a,b)); +INSERT INTO t2 VALUES (1,1,1,50), (1,2,3,40), (2,1,3,4); +EXPLAIN SELECT DISTINCT a FROM t2; +EXPLAIN SELECT DISTINCT a,a FROM t2; +EXPLAIN SELECT DISTINCT b,a FROM t2; +EXPLAIN SELECT DISTINCT a,c FROM t2; +EXPLAIN SELECT DISTINCT c,a,b FROM t2; + +EXPLAIN SELECT DISTINCT a,b,d FROM t2 GROUP BY c,b,d; +CREATE UNIQUE INDEX c_b_unq ON t2 (c,b); +EXPLAIN SELECT DISTINCT a,b,d FROM t2 GROUP BY c,b,d; + +DROP TABLE t1,t2; + +# Bug 9784 DISTINCT IFNULL truncates data +# +create table t1 (id int, dsc varchar(50)); +insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three"); +select distinct id, IFNULL(dsc, '-') from t1; +drop table t1; + +# +# Bug 21456: SELECT DISTINCT(x) produces incorrect results when using order by +# +CREATE TABLE t1 (a int primary key, b int); + +INSERT INTO t1 (a,b) values (1,1), (2,3), (3,2); + +explain SELECT DISTINCT a, b FROM t1 ORDER BY b; +SELECT DISTINCT a, b FROM t1 ORDER BY b; +DROP TABLE t1; + +# End of 4.1 tests + + +# +# Bug #15745 ( COUNT(DISTINCT CONCAT(x,y)) returns wrong result) +# +CREATE TABLE t1 ( + ID int(11) NOT NULL auto_increment, + x varchar(20) default NULL, + y decimal(10,0) default NULL, + PRIMARY KEY (ID), + KEY (y) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +INSERT INTO t1 VALUES +(1,'ba','-1'), +(2,'ba','1150'), +(306,'ba','-1'), +(307,'ba','1150'), +(611,'ba','-1'), +(612,'ba','1150'); + +select count(distinct x,y) from t1; +select count(distinct concat(x,y)) from t1; +drop table t1; + +# +# Bug #18068: SELECT DISTINCT +# +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a,b)); + +INSERT INTO t1 VALUES (1, 101); +INSERT INTO t1 SELECT a + 1, a + 101 FROM t1; +INSERT INTO t1 SELECT a + 2, a + 102 FROM t1; +INSERT INTO t1 SELECT a + 4, a + 104 FROM t1; +INSERT INTO t1 SELECT a + 8, a + 108 FROM t1; + +EXPLAIN SELECT DISTINCT a,a FROM t1 WHERE b < 12 ORDER BY a; +SELECT DISTINCT a,a FROM t1 WHERE b < 12 ORDER BY a; + +DROP TABLE t1; +# The test case for bug#20836 should be re-enabled when bug#16861 is resolved +# The results for the test should be the same as in 4.1. +# +#Bug #20836: Selecting into variables results in wrong results being returned +# +#--disable_warnings +#DROP TABLE IF EXISTS t1; +#--enable_warnings +# +#CREATE TABLE t1 (id INT NOT NULL, fruit_id INT NOT NULL, fruit_name varchar(20) +#default NULL); +# +#INSERT INTO t1 VALUES (1,1,'ORANGE'); +#INSERT INTO t1 VALUES (2,2,'APPLE'); +#INSERT INTO t1 VALUES (3,2,'APPLE'); +#INSERT INTO t1 VALUES (4,3,'PEAR'); +# +#SELECT DISTINCT fruit_id, fruit_name INTO @v1, @v2 FROM t1 WHERE fruit_name = +#'APPLE'; +#SELECT @v1, @v2; +# +#SELECT DISTINCT fruit_id, fruit_name INTO @v3, @v4 FROM t1 GROUP BY fruit_id, +#fruit_name HAVING fruit_name = 'APPLE'; +#SELECT @v3, @v4; +# +#SELECT DISTINCT @v5:= fruit_id, @v6:= fruit_name INTO @v7, @v8 FROM t1 WHERE +#fruit_name = 'APPLE'; +#SELECT @v5, @v6, @v7, @v8; +# +#SELECT DISTINCT @v5 + fruit_id, CONCAT(@v6, fruit_name) INTO @v9, @v10 FROM t1 +#WHERE fruit_name = 'APPLE'; +#SELECT @v5, @v6, @v7, @v8, @v9, @v10; +# +#SELECT DISTINCT @v11:= @v5 + fruit_id, @v12:= CONCAT(@v6, fruit_name) INTO +#@v13, @v14 FROM t1 WHERE fruit_name = 'APPLE'; +#SELECT @v11, @v12, @v13, @v14; +# +#SELECT DISTINCT @v13, @v14 INTO @v15, @v16 FROM t1 WHERE fruit_name = 'APPLE'; +#SELECT @v15, @v16; +# +#SELECT DISTINCT 2 + 2, 'Bob' INTO @v17, @v18 FROM t1 WHERE fruit_name = +#'APPLE'; +#SELECT @v17, @v18; +# +#--disable_warnings +#DROP TABLE IF EXISTS t2; +#--enable_warnings +# +#CREATE TABLE t2 (fruit_id INT NOT NULL, fruit_name varchar(20) +#default NULL); +# +#SELECT DISTINCT fruit_id, fruit_name INTO OUTFILE +#'../tmp/data1.tmp' FROM t1 WHERE fruit_name = 'APPLE'; +#LOAD DATA INFILE '../tmp/data1.tmp' INTO TABLE t2; +#--exec rm $MYSQL_TEST_DIR/var/tmp/data1.tmp +# +#SELECT DISTINCT @v19:= fruit_id, @v20:= fruit_name INTO OUTFILE +#'../tmp/data2.tmp' FROM t1 WHERE fruit_name = 'APPLE'; +#LOAD DATA INFILE '../tmp/data2.tmp' INTO TABLE t2; +#--exec rm $MYSQL_TEST_DIR/var/tmp/data2.tmp +# +#SELECT @v19, @v20; +#SELECT * FROM t2; +# +#DROP TABLE t1; +#DROP TABLE t2; + +# +# Bug #15881: cast problems +# +CREATE TABLE t1 (a CHAR(1)); INSERT INTO t1 VALUES('A'), (0); +SELECT a FROM t1 WHERE a=0; +SELECT DISTINCT a FROM t1 WHERE a=0; +DROP TABLE t1; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('1972-07-29'), ('1972-02-06'); +EXPLAIN SELECT (SELECT DISTINCT a FROM t1 WHERE a = '2002-08-03'); +EXPLAIN SELECT (SELECT DISTINCT ADDDATE(a,1) FROM t1 + WHERE ADDDATE(a,1) = '2002-08-03'); +CREATE TABLE t2 (a CHAR(5) CHARACTER SET latin1 COLLATE latin1_general_ci); +INSERT INTO t2 VALUES (0xf6); +INSERT INTO t2 VALUES ('oe'); + +SELECT COUNT(*) FROM (SELECT DISTINCT a FROM t2) dt; +SELECT COUNT(*) FROM + (SELECT DISTINCT a FROM t2 WHERE a='oe' COLLATE latin1_german2_ci) dt; + +DROP TABLE t1, t2; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/drop.test b/mysql-test/suite/pbxt/t/drop.test new file mode 100644 index 00000000000..0e2f62f9812 --- /dev/null +++ b/mysql-test/suite/pbxt/t/drop.test @@ -0,0 +1,127 @@ +# Initialise +--disable_warnings +drop table if exists t1; +drop database if exists mysqltest; +# If earlier test failed +drop database if exists client_test_db; +--enable_warnings + +--error 1051 +drop table t1; +create table t1(n int); +insert into t1 values(1); +create temporary table t1( n int); +insert into t1 values(2); +--error 1050 +create table t1(n int); +drop table t1; +select * from t1; + +# now test for a bug in drop database - it is important that the name +# of the table is the same as the name of the database - in the original +# code this triggered a bug +create database mysqltest; +drop database if exists mysqltest; +create database mysqltest; +create table mysqltest.mysqltest (n int); +insert into mysqltest.mysqltest values (4); +select * from mysqltest.mysqltest; +--enable_info +drop database if exists mysqltest; +--disable_info +create database mysqltest; + +# +# drop many tables - bug#3891 +# we'll do it in mysqltest db, to be able to use longer table names +# (tableN instead on tN) +# +use mysqltest; +--error 1051 +drop table table1, table2, table3, table4, table5, table6, +table7, table8, table9, table10, table11, table12, table13, +table14, table15, table16, table17, table18, table19, table20, +table21, table22, table23, table24, table25, table26, table27, +table28; + +--error 1051 +drop table table1, table2, table3, table4, table5, table6, +table7, table8, table9, table10, table11, table12, table13, +table14, table15, table16, table17, table18, table19, table20, +table21, table22, table23, table24, table25, table26, table27, +table28, table29, table30; + +use test; +drop database mysqltest; + +# test drop/create database and FLUSH TABLES WITH READ LOCK +flush tables with read lock; +--error 1209,1223 +create database mysqltest; +unlock tables; +create database mysqltest; +show databases; +flush tables with read lock; +--error 1208,1223 +drop database mysqltest; +unlock tables; +drop database mysqltest; +show databases; +--error 1008 +drop database mysqltest; + +# test create table and FLUSH TABLES WITH READ LOCK +drop table t1; +flush tables with read lock; +--error 1223 +create table t1(n int); +unlock tables; +create table t1(n int); +show tables; +drop table t1; + +# End of 4.1 tests + + +# +# Test for bug#21216 "Simultaneous DROP TABLE and SHOW OPEN TABLES causes +# server to crash". Crash (caused by failed assertion in 5.0 or by null +# pointer dereference in 5.1) happened when one ran SHOW OPEN TABLES +# while concurrently doing DROP TABLE (or RENAME TABLE, CREATE TABLE LIKE +# or any other command that takes name-lock) in other connection. +# +# Also includes test for similar bug#12212 "Crash that happens during +# removing of database name from cache" reappeared in 5.1 as bug#19403 +# In its case crash happened when one concurrently executed DROP DATABASE +# and one of name-locking command. +# +--disable_warnings +drop database if exists mysqltest; +drop table if exists t1; +--enable_warnings +create table t1 (i int); +lock tables t1 read; +create database mysqltest; +connect (addconroot1, localhost, root,,); +--send drop table t1 +connect (addconroot2, localhost, root,,); +# Server should not crash in any of the following statements +--disable_result_log +show open tables; +--enable_result_log +--send drop database mysqltest +connection default; +select 1; +unlock tables; +connection addconroot1; +--reap +connection addconroot2; +--reap +disconnect addconroot1; +disconnect addconroot2; +connection default; + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/empty_table.test b/mysql-test/suite/pbxt/t/empty_table.test new file mode 100644 index 00000000000..5f8a0c527ca --- /dev/null +++ b/mysql-test/suite/pbxt/t/empty_table.test @@ -0,0 +1,18 @@ +# +# Some special cases with empty tables +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (nr int(5) not null auto_increment,b blob,str char(10), primary key (nr)); +select count(*) from t1; +select * from t1; +select * from t1 limit 0; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/endspace.test b/mysql-test/suite/pbxt/t/endspace.test new file mode 100644 index 00000000000..f2dcc1225a4 --- /dev/null +++ b/mysql-test/suite/pbxt/t/endspace.test @@ -0,0 +1,102 @@ +# +# Test problem with characters < ' ' at end of strings (Bug #3152) +# + +-- source include/have_innodb.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + +-- source include/endspace.inc + +# +# Test MyISAM tables. +# + +create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)); +insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); +check table t1; +select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 where text1='teststring' or text1 like 'teststring_%'; +select * from t1 where text1='teststring' or text1 > 'teststring\t'; +select * from t1 order by text1; +explain select * from t1 order by text1; + +alter table t1 modify text1 char(32) binary not null; +check table t1; +select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; +select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t'; +select text1, length(text1) from t1 order by text1; +select text1, length(text1) from t1 order by binary text1; + +alter table t1 modify text1 blob not null, drop key key1, add key key1 (text1(20)); +insert into t1 values ('teststring '); +select concat('|', text1, '|') from t1 order by text1; +select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t'; +select concat('|', text1, '|') from t1 where text1='teststring'; +select concat('|', text1, '|') from t1 where text1='teststring '; + +alter table t1 modify text1 text not null, pack_keys=1; +select concat('|', text1, '|') from t1 where text1='teststring'; +select concat('|', text1, '|') from t1 where text1='teststring '; +explain select concat('|', text1, '|') from t1 where text1='teststring '; +select concat('|', text1, '|') from t1 where text1 like 'teststring_%'; +select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; +select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t'; +select concat('|', text1, '|') from t1 order by text1; +drop table t1; + +create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)) pack_keys=0; +insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); +select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; +select concat('|', text1, '|') from t1 where text1='teststring' or text1 >= 'teststring\t'; +drop table t1; + +# Test HEAP tables (with BTREE keys) + +create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap; +insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); +select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 where text1='teststring' or text1 like 'teststring_%'; +select * from t1 where text1='teststring' or text1 >= 'teststring\t'; +select * from t1 order by text1; +explain select * from t1 order by text1; + +alter table t1 modify text1 char(32) binary not null; +select * from t1 order by text1; +drop table t1; + +# +# Test InnoDB tables +# + +create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)) engine=innodb; +insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); +check table t1; +select * from t1 where text1='teststring' or text1 like 'teststring_%'; +select * from t1 where text1='teststring' or text1 > 'teststring\t'; +select * from t1 order by text1; +explain select * from t1 order by text1; + +alter table t1 modify text1 char(32) binary not null; +select * from t1 order by text1; + +alter table t1 modify text1 blob not null, drop key key1, add key key1 (text1(20)); +insert into t1 values ('teststring '); +select concat('|', text1, '|') from t1 order by text1; + +alter table t1 modify text1 text not null, pack_keys=1; +select * from t1 where text1 like 'teststring_%'; + +# The following gives wrong result in InnoDB +select text1, length(text1) from t1 where text1='teststring' or text1 like 'teststring_%'; +select text1, length(text1) from t1 where text1='teststring' or text1 >= 'teststring\t'; +select concat('|', text1, '|') from t1 order by text1; +drop table t1; + + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/errors.test b/mysql-test/suite/pbxt/t/errors.test new file mode 100644 index 00000000000..d19e0799c50 --- /dev/null +++ b/mysql-test/suite/pbxt/t/errors.test @@ -0,0 +1,47 @@ +# +# Test some error conditions +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +--error 1146 +insert into t1 values(1); +--error 1146 +delete from t1; +--error 1146 +update t1 set a=1; +create table t1 (a int); +--error 1054 +select count(test.t1.b) from t1; +--error 1054 +select count(not_existing_database.t1) from t1; +--error 1054 +select count(not_existing_database.t1.a) from t1; +--error 1044,1146 +select count(not_existing_database.t1.a) from not_existing_database.t1; +--error 1054 +select 1 from t1 order by 2; +--error 1054 +select 1 from t1 group by 2; +--error 1054 +select 1 from t1 order by t1.b; +--error 1054 +select count(*),b from t1; +drop table t1; + +# End of 4.1 tests + +# +# Bug #6080: Error message for a field with a display width that is too long +# +--error 1439 +create table t1 (a int(256)); +set sql_mode='traditional'; +--error 1074 +create table t1 (a varchar(66000)); + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/explain.test b/mysql-test/suite/pbxt/t/explain.test new file mode 100644 index 00000000000..fb9f3507d01 --- /dev/null +++ b/mysql-test/suite/pbxt/t/explain.test @@ -0,0 +1,57 @@ +# +# Test of different EXPLAIN's + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (id int not null, str char(10), unique(str)); +explain select * from t1; +insert into t1 values (1, null),(2, null),(3, "foo"),(4, "bar"); +select * from t1 where str is null; +select * from t1 where str="foo"; +explain select * from t1 where str is null; +explain select * from t1 where str="foo"; +explain select * from t1 ignore key (str) where str="foo"; +explain select * from t1 use key (str,str) where str="foo"; + +#The following should give errors +--error 1176 +explain select * from t1 use key (str,str,foo) where str="foo"; +--error 1176 +explain select * from t1 ignore key (str,str,foo) where str="foo"; +drop table t1; + +explain select 1; + +create table t1 (a int not null); +explain select count(*) from t1; +insert into t1 values(1); +explain select count(*) from t1; +insert into t1 values(1); +explain select count(*) from t1; +drop table t1; + +# +# Bug #3403 Wrong encoding in EXPLAIN SELECT output +# +set names koi8r; +create table ÔÁ (ËÏÌ0 int, ËÏÌ1 int, key ÉÎÄ0 (ËÏÌ0), key ÉÎÄ01 (ËÏÌ0,ËÏÌ1)); +insert into ÔÁ (ËÏÌ0) values (1); +insert into ÔÁ (ËÏÌ0) values (2); +explain select ËÏÌ0 from ÔÁ where ËÏÌ0=1; +drop table ÔÁÂ; +set names latin1; + +# End of 4.1 tests + + +# +# Bug#15463: EXPLAIN SELECT..INTO hangs the client (QB, command line) +# +select 3 into @v1; +explain select 3 into @v1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/t/flush.test b/mysql-test/suite/pbxt/t/flush.test new file mode 100644 index 00000000000..f9329f08adf --- /dev/null +++ b/mysql-test/suite/pbxt/t/flush.test @@ -0,0 +1,139 @@ +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection con1; + +--disable_warnings +drop table if exists t1,t2; +drop database if exists mysqltest; +--enable_warnings + +create temporary table t1(n int not null primary key); +create table t2(n int); +insert into t2 values(3); +let $1=100; +disable_query_log; +while ($1) +{ + connection con1; + send replace into t1 select n from t2; + connection con2; + send flush tables; + connection con1; + reap; + connection con2; + reap; + dec $1; +} +enable_query_log; +connection con1; +select * from t1; +connection con2; +flush tables with read lock; +--error 1223 +drop table t2; +connection con1; +send drop table t2; +connection con2; +unlock tables; +connection con1; +reap; + +#test if drop database will wait until we release the global read lock +connection con1; +create database mysqltest; +create table mysqltest.t1(n int); +insert into mysqltest.t1 values (23); +flush tables with read lock; +connection con2; +send drop database mysqltest; +connection con1; +select * from mysqltest.t1; +unlock tables; +connection con2; +reap; + +# test if dirty close releases global read lock +connection con1; +create table t1 (n int); +flush tables with read lock; +dirty_close con1; +connection con2; +insert into t1 values (345); +select * from t1; +drop table t1; + +# +# Bug#9459 - deadlock with flush with lock, and lock table write +# +create table t1 (c1 int); +lock table t1 write; +# Cannot get the global read lock with write locked tables. +--error 1192 +flush tables with read lock; +lock table t1 read; +# Can get the global read lock with read locked tables. +flush tables with read lock; +--error 1223 +lock table t1 write; +lock table t1 read; +--error 1223 +lock table t1 write; +# Release all table locks and the global read lock. +unlock tables; +create table t2 (c1 int); +create table t3 (c1 int); +lock table t1 read, t2 read, t3 write; +# Cannot get the global read lock with write locked tables. +--error 1192 +flush tables with read lock; +lock table t1 read, t2 read, t3 read; +# Can get the global read lock with read locked tables. +flush tables with read lock; +# Release all table locks and the global read lock. +unlock tables; +drop table t1, t2, t3; + +# End of 4.1 tests + +# +# Test of deadlock problem when doing FLUSH TABLE with read lock +# (Bug was in NTPL threads in Linux when using different mutex while +# waiting for a condtion variable) + +create table t1 (c1 int); +create table t2 (c1 int); + +connect (con1,localhost,root,,); +connect (con3,localhost,root,,); + +connection con1; +lock table t1 write; + +connection con2; +send flush tables with read lock; +--sleep 1 + +connection con3; +send insert into t2 values(1); +--sleep 1 + +connection con1; +unlock tables; +disconnect con1; + +connection con2; +reap; +disconnect con2; + +connection con3; +# It hangs here (insert into t2 does not end). +reap; +disconnect con3; + +connection default; +drop table t1, t2; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/flush_read_lock_kill.test b/mysql-test/suite/pbxt/t/flush_read_lock_kill.test new file mode 100644 index 00000000000..6fd9e888984 --- /dev/null +++ b/mysql-test/suite/pbxt/t/flush_read_lock_kill.test @@ -0,0 +1,54 @@ +# Let's see if FLUSH TABLES WITH READ LOCK can be killed when waiting +# for running commits to finish (in the past it could not) +# This will not be a meaningful test on non-debug servers so will be +# skipped. +# If running mysql-test-run --debug, the --debug added by +# mysql-test-run to the mysqld command line will override the one of +# -master.opt. But this test is designed to still pass then (though it +# won't test anything interesting). + +# This also won't work with the embedded server test +-- source include/not_embedded.inc + +-- source include/have_debug.inc + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection con1; + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (kill_id int); +insert into t1 values(connection_id()); +select kill_id-kill_id from t1; + +# Thanks to the parameter we passed to --debug, this FLUSH will +# block on a debug build running with our --debug=make_global... It +# will block until killed. In other cases (non-debug build or other +# --debug) it will succeed immediately + +connection con1; +send flush tables with read lock; + +# kill con1 +connection con2; +select ((@id := kill_id) - kill_id) from t1; + +--sleep 2 # leave time for FLUSH to block +kill connection @id; + +connection con1; +# On debug builds it will be error 1053 (killed); on non-debug, or +# debug build running without our --debug=make_global..., will be +# error 0 (no error). The only important thing to test is that on +# debug builds with our --debug=make_global... we don't hang forever. +--error 0,1053,2013 +reap; + +connection con2; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/flush_table.test b/mysql-test/suite/pbxt/t/flush_table.test new file mode 100644 index 00000000000..fa7ef83e076 --- /dev/null +++ b/mysql-test/suite/pbxt/t/flush_table.test @@ -0,0 +1,141 @@ +# TODO: Only run this if we have privilege to do flush table + +# +# Test of flush table +# + +# Should work in embedded server after mysqltest is fixed +-- source include/not_embedded.inc +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +create table t1 (a int not null auto_increment primary key); +insert into t1 values(0); + +# Test for with read lock + flush + +lock table t1 read; +flush table t1; +check table t1; +unlock tables; + +# Test for with 2 read lock in different thread + flush + +lock table t1 read; +connect (locker,localhost,root,,test); +connection locker; +lock table t1 read; +connection default; +send flush table t1; +connection locker; +--sleep 2 +select * from t1; +unlock tables; +connection default; +reap; +select * from t1; +unlock tables; + +# Test for with a write lock and a waiting read lock + flush + +lock table t1 write; +connection locker; +send lock table t1 read; +connection default; +sleep 2; +flush table t1; +select * from t1; +unlock tables; +connection locker; +reap; +unlock tables; +connection default; + +# Test for with a read lock and a waiting write lock + flush + +lock table t1 read; +connection locker; +send lock table t1 write; +connection default; +sleep 2; +flush table t1; +select * from t1; +unlock tables; +connection locker; +reap; +unlock tables; +select * from t1; +connection default; +drop table t1; +disconnect locker; + +# +# In the following test FLUSH TABLES produces a deadlock +# (hang forever) if the fix for BUG #3565 is missing. +# And it shows that handler tables are re-opened after flush (BUG #4286). +# +create table t1(table_id char(20) primary key); +create table t2(table_id char(20) primary key); +insert into t1 values ('test.t1'); +insert into t1 values (''); +insert into t2 values ('test.t2'); +insert into t2 values (''); +handler t1 open as a1; +handler t1 open as a2; +handler t2 open; +handler a1 read first limit 9; +handler a2 read first limit 9; +handler t2 read first limit 9; +flush tables; +handler a1 read first limit 9; +handler a2 read first limit 9; +handler t2 read first limit 9; +# +--error 1066 +handler t1 open as a1; +--error 1066 +handler t1 open as a2; +--error 1066 +handler t2 open; +handler a1 read first limit 9; +handler a2 read first limit 9; +handler t2 read first limit 9; +flush table t1; +handler a1 read first limit 9; +handler a2 read first limit 9; +handler t2 read first limit 9; +flush table t2; +handler t2 close; +drop table t1; +drop table t2; + +# +# The fix for BUG #4286 cannot restore the position after a flush. +# +create table t1(table_id char(20) primary key); +insert into t1 values ('Record-01'); +insert into t1 values ('Record-02'); +insert into t1 values ('Record-03'); +insert into t1 values ('Record-04'); +insert into t1 values ('Record-05'); +handler t1 open; +handler t1 read first limit 1; +handler t1 read next limit 1; +handler t1 read next limit 1; +flush table t1; +handler t1 read next limit 1; +handler t1 read next limit 1; +handler t1 close; +drop table t1; + +# +# Bug #11934 Two sequential FLUSH TABLES WITH READ LOCK hangs client +# +FLUSH TABLES WITH READ LOCK ; +FLUSH TABLES WITH READ LOCK ; +UNLOCK TABLES; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/foreign_key.test b/mysql-test/suite/pbxt/t/foreign_key.test new file mode 100644 index 00000000000..e9940e60d15 --- /dev/null +++ b/mysql-test/suite/pbxt/t/foreign_key.test @@ -0,0 +1,33 @@ +# +# Test syntax of foreign keys +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +set foreign_key_checks = 0; +# PBXT: added row c so I can test set null (not allowed on primary key) +create table t1 ( + a int not null references t2, + b int not null references t2 (c), + c int, + primary key (a,b), + foreign key (a) references t3 match full, + foreign key (a) references t3 match partial, + foreign key (a,b) references t3 (c,d) on delete no action + on update no action, + foreign key (a,b) references t3 (c,d) on update cascade, + foreign key (a,b) references t3 (c,d) on delete set default, + foreign key (c) references t3 (e) on update set null); + +create index a on t1 (a); +create unique index b on t1 (a,b); +drop table t1; + +set foreign_key_checks = 1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_concat.test b/mysql-test/suite/pbxt/t/func_concat.test new file mode 100644 index 00000000000..390d3337c1f --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_concat.test @@ -0,0 +1,74 @@ +# +# Test of problem with CONCAT_WS() and long separators. +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 ( number INT NOT NULL, alpha CHAR(6) NOT NULL ); +INSERT INTO t1 VALUES (1413006,'idlfmv'), +(1413065,'smpsfz'),(1413127,'sljrhx'),(1413304,'qerfnd'); + +SELECT number, alpha, CONCAT_WS('<---->',number,alpha) AS new +FROM t1 GROUP BY number; + +SELECT CONCAT_WS('<---->',number,alpha) AS new +FROM t1 GROUP BY new LIMIT 1; + +SELECT number, alpha, CONCAT_WS('<->',number,alpha) AS new +FROM t1 GROUP BY new LIMIT 1; + +SELECT number, alpha, CONCAT_WS('-',number,alpha,alpha,alpha,alpha,alpha,alpha,alpha) AS new +FROM t1 GROUP BY new LIMIT 1; + +SELECT number, alpha, CONCAT_WS('<------------------>',number,alpha) AS new +FROM t1 GROUP BY new LIMIT 1; +drop table t1; + +# +# Bug #5540: a problem with double type +# + +create table t1 (a char(4), b double, c date, d tinyint(4)); +insert into t1 values ('AAAA', 105, '2003-03-01', 1); +select * from t1 where concat(A,C,B,D) = 'AAAA2003-03-011051'; +drop table t1; + +# BUG#6825 +select 'a' union select concat('a', -4); +select 'a' union select concat('a', -4.5); + +select 'a' union select concat('a', -(4 + 1)); +select 'a' union select concat('a', 4 - 5); + +select 'a' union select concat('a', -'3'); +select 'a' union select concat('a', -concat('3',4)); + +select 'a' union select concat('a', -0); +--replace_result a-0.0 a0.0 +select 'a' union select concat('a', -0.0); + +--replace_result a-0.0000 a0.0000 +select 'a' union select concat('a', -0.0000); + +# +# Bug#16716: subselect in concat() may lead to a wrong result +# +select concat((select x from (select 'a' as x) as t1 ), + (select y from (select 'b' as y) as t2 )) from (select 1 union select 2 ) + as t3; + +# End of 4.1 tests + +# +# Bug#15962: CONCAT() in UNION may lead to a data trucation. +# +create table t1(f1 varchar(6)) charset=utf8; +insert into t1 values ("123456"); +select concat(f1, 2) a from t1 union select 'x' a from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/func_crypt.test b/mysql-test/suite/pbxt/t/func_crypt.test new file mode 100644 index 00000000000..657f93ef083 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_crypt.test @@ -0,0 +1,61 @@ +-- source include/have_crypt.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +select length(encrypt('foo', 'ff')) <> 0; +--replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l. + +create table t1 (name varchar(50), pw varchar(64)); +insert into t1 values ('tom', password('my_pass')); +set @pass='my_pass'; +select name from t1 where name='tom' and pw=password(@pass); +select name from t1 where name='tom' and pw=password(@undefined); +drop table t1; + +# Test new and old password handling functions + +select password('abc'); +select password(''); +select old_password('abc'); +select old_password(''); +select password('gabbagabbahey'); +select old_password('idkfa'); +select length(password('1')); +select length(encrypt('test')); +select encrypt('test','aa'); +select old_password(NULL); +select password(NULL); +set global old_passwords=on; +select password(''); +select old_password(''); +select password('idkfa'); +select old_password('idkfa'); +set old_passwords=on; +select password('idkfa'); +select old_password('idkfa'); +set global old_passwords=off; +select password('idkfa'); +select old_password('idkfa'); + +# this test shows that new scrambles honor spaces in passwords: +set old_passwords=off; +select password('idkfa '); +select password('idkfa'); +select password(' idkfa'); +select old_password('idkfa'); +select old_password(' i d k f a '); + +explain extended select password('idkfa '), old_password('idkfa'); + +# +# Bug #13619: Crash on FreeBSD with salt like '_.' +# +--replace_column 1 # +select encrypt('1234','_.'); + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_date_add.test b/mysql-test/suite/pbxt/t/func_date_add.test new file mode 100644 index 00000000000..0d94b1d6a80 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_date_add.test @@ -0,0 +1,83 @@ +# +# Test of DATE_ADD +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE t1 ( + visitor_id int(10) unsigned DEFAULT '0' NOT NULL, + group_id int(10) unsigned DEFAULT '0' NOT NULL, + hits int(10) unsigned DEFAULT '0' NOT NULL, + sessions int(10) unsigned DEFAULT '0' NOT NULL, + ts timestamp, + PRIMARY KEY (visitor_id,group_id) +)/*! engine=MyISAM */; +INSERT INTO t1 VALUES (465931136,7,2,2,20000318160952); +INSERT INTO t1 VALUES (173865424,2,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,8,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,39,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,7,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,3,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,6,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,60,2,2,20000318233615); +INSERT INTO t1 VALUES (173865424,1502,2,2,20000318233615); +INSERT INTO t1 VALUES (48985536,2,2,2,20000319013932); +INSERT INTO t1 VALUES (48985536,8,2,2,20000319013932); +INSERT INTO t1 VALUES (48985536,39,2,2,20000319013932); +INSERT INTO t1 VALUES (48985536,7,2,2,20000319013932); +INSERT INTO t1 VALUES (465931136,3,2,2,20000318160951); +INSERT INTO t1 VALUES (465931136,119,1,1,20000318160953); +INSERT INTO t1 VALUES (465931136,2,1,1,20000318160950); +INSERT INTO t1 VALUES (465931136,8,1,1,20000318160950); +INSERT INTO t1 VALUES (465931136,39,1,1,20000318160950); +INSERT INTO t1 VALUES (1092858576,14,1,1,20000319013445); +INSERT INTO t1 VALUES (357917728,3,2,2,20000319145026); +INSERT INTO t1 VALUES (357917728,7,2,2,20000319145027); +select visitor_id,max(ts) as mts from t1 group by visitor_id +having mts < DATE_SUB(NOW(),INTERVAL 3 MONTH); +select visitor_id,max(ts) as mts from t1 group by visitor_id +having DATE_ADD(mts,INTERVAL 3 MONTH) < NOW(); +drop table t1; + +# +# Bug #10627: Invalid date turned to NULL from date_sub/date_add in +# traditional mode +# +set sql_mode='traditional'; +create table t1 (d date); +--error S22008 +insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); +--error S22008 +insert into t1 (d) select date_add('2000-01-01',interval 8000 year); +# No warnings/errors from the next two +insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); +insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); +set sql_mode=''; +# These will all work now, and we'll end up with some NULL entries in the +# table and some warnings. +insert into t1 (d) select date_sub('2000-01-01', INTERVAL 2001 YEAR); +insert into t1 (d) select date_add('2000-01-01',interval 8000 year); +insert into t1 values (date_add(NULL, INTERVAL 1 DAY)); +insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); +select * from t1; +drop table t1; + +--echo End of 4.1 tests + +# +# Bug#21811 +# +# Make sure we end up with an appropriate +# date format (DATE) after addition operation +# +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 DAY; +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 MONTH; +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 YEAR; +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 WEEK; + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/func_default.test b/mysql-test/suite/pbxt/t/func_default.test new file mode 100644 index 00000000000..b4bd4520b42 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_default.test @@ -0,0 +1,34 @@ +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + + +create table t1(str varchar(10) default 'def',strnull varchar(10),intg int default '10',rel double default '3.14'); + +insert into t1 values ('','',0,0.0); +select default(str), default(strnull), default(intg), default(rel) from t1; +explain extended select default(str), default(strnull), default(intg), default(rel) from t1; +select * from t1 where str <> default(str); +explain select * from t1 where str <> default(str); + +#TODO: uncomment when bug will be fixed +#create table t2 select default(str), default(strnull), default(intg), default(rel) from t1; +#show create table from t1; +#insert into t2 select select default(str), default(strnull), default(intg), default(rel) from t1; + +drop table t1; + +# End of 4.1 tests + +# +# Bug #11314 (HAVING DEFAULT() hangs) +# +CREATE TABLE t1 (id int(11), s varchar(20)); +INSERT INTO t1 VALUES (1, 'one'), (2, 'two'), (3, 'three'); +--error 1364 +SELECT s, 32 AS mi FROM t1 GROUP BY s HAVING DEFAULT(mi) IS NULL; +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/func_equal.test b/mysql-test/suite/pbxt/t/func_equal.test new file mode 100644 index 00000000000..ed7073d55ff --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_equal.test @@ -0,0 +1,49 @@ +# Initialise +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +# +# Testing of the <=> operator +# + +# +# First some simple tests +# + +select 0<=>0,0.0<=>0.0,0E0=0E0,"A"<=>"A",NULL<=>NULL; +select 1<=>0,0<=>NULL,NULL<=>0; +select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0; +select "A"<=>"B","A"<=>NULL,NULL<=>"A"; +select 0<=>0.0, 0.0<=>0E0, 0E0<=>"0", 10.0<=>1E1, 10<=>10.0, 10<=>1E1; +select 1.0<=>0E1,10<=>NULL,NULL<=>0.0, NULL<=>0E0; + +# +# Test with tables +# + +create table t1 (id int, value int); +create table t2 (id int, value int); + +insert into t1 values (1,null); +insert into t2 values (1,null); + +select t1.*, t2.*, t1.value<=>t2.value from t1, t2 where t1.id=t2.id and t1.id=1; +select * from t1 where id <=>id; +select * from t1 where value <=> value; +select * from t1 where id <=> value or value<=>id; +drop table t1,t2; + +# +# Bug #12612: quoted bigint unsigned value and the use of "in" in where clause +# +create table t1 (a bigint unsigned); +insert into t1 values (4828532208463511553); +select * from t1 where a = '4828532208463511553'; +select * from t1 where a in ('4828532208463511553'); +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_gconcat.test b/mysql-test/suite/pbxt/t/func_gconcat.test new file mode 100644 index 00000000000..fc2aff42520 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_gconcat.test @@ -0,0 +1,506 @@ +# +# simple test of group_concat function +# +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + +create table t1 (grp int, a bigint unsigned, c char(10) not null, d char(10) not null); +insert into t1 values (1,1,"a","a"); +insert into t1 values (2,2,"b","a"); +insert into t1 values (2,3,"c","b"); +insert into t1 values (3,4,"E","a"); +insert into t1 values (3,5,"C","b"); +insert into t1 values (3,6,"D","b"); +insert into t1 values (3,7,"d","d"); +insert into t1 values (3,8,"d","d"); +insert into t1 values (3,9,"D","c"); + +# Test of MySQL simple request +select grp,group_concat(c) from t1 group by grp; +explain extended select grp,group_concat(c) from t1 group by grp; +select grp,group_concat(a,c) from t1 group by grp; +select grp,group_concat("(",a,":",c,")") from t1 group by grp; + +# Test of MySQL with options +select grp,group_concat(c separator ",") from t1 group by grp; +select grp,group_concat(c separator "---->") from t1 group by grp; +select grp,group_concat(c order by c) from t1 group by grp; +select grp,group_concat(c order by c desc) from t1 group by grp; +select grp,group_concat(d order by a) from t1 group by grp; +select grp,group_concat(d order by a desc) from t1 group by grp; +--disable_warnings +select grp,group_concat(a order by a,d+c-ascii(c)-a) from t1 group by grp; +select grp,group_concat(a order by d+c-ascii(c),a) from t1 group by grp; +--enable_warnings +select grp,group_concat(c order by 1) from t1 group by grp; +select grp,group_concat(distinct c order by c) from t1 group by grp; +select grp,group_concat(distinct c order by c desc) from t1 group by grp; +explain extended select grp,group_concat(distinct c order by c desc) from t1 group by grp; +select grp,group_concat(c order by c separator ",") from t1 group by grp; +select grp,group_concat(c order by c desc separator ",") from t1 group by grp; +select grp,group_concat(distinct c order by c separator ",") from t1 group by grp; +explain extended select grp,group_concat(distinct c order by c separator ",") from t1 group by grp; +select grp,group_concat(distinct c order by c desc separator ",") from t1 group by grp; + +# Test of SQL_LIST objects +select grp,group_concat(c order by grp desc) from t1 group by grp order by grp; + + +# Test transfer to real values + +select grp, group_concat(a separator "")+0 from t1 group by grp; + +select grp, group_concat(a separator "")+0.0 from t1 group by grp; + +select grp, ROUND(group_concat(a separator "")) from t1 group by grp; + +drop table t1; + +# Test NULL values + +create table t1 (grp int, c char(10)); +insert into t1 values (1,NULL),(2,"b"),(2,NULL),(3,"E"),(3,NULL),(3,"D"),(3,NULL),(3,NULL),(3,"D"),(4,""),(5,NULL); +select grp,group_concat(c order by c) from t1 group by grp; + +# Test warnings + +set group_concat_max_len = 4; +select grp,group_concat(c) from t1 group by grp; +show warnings; +set group_concat_max_len = 1024; + +# Test errors + +--error 1111 +select group_concat(sum(c)) from t1 group by grp; +--error 1054 +select grp,group_concat(c order by 2) from t1 group by grp; + +drop table t1; + +# Test variable length + +create table t1 ( URL_ID int(11), URL varchar(80)); +create table t2 ( REQ_ID int(11), URL_ID int(11)); +insert into t1 values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); +insert into t2 values (1,4), (5,4), (5,5); +# Make this order independent +--replace_result www.help.com X www.host.com X www.google.com X +select REQ_ID, Group_Concat(URL) as URL from t1, t2 where +t2.URL_ID = t1.URL_ID group by REQ_ID; +# check min/max function +--replace_result www.help.com X www.host.com X www.google.com X +select REQ_ID, Group_Concat(URL) as URL, Min(t1.URL_ID) urll, +Max(t1.URL_ID) urlg from t1, t2 where t2.URL_ID = t1.URL_ID group by REQ_ID; + +drop table t1; +drop table t2; + +create table t1 (id int, name varchar(16)); +insert into t1 values (1,'longername'),(1,'evenlongername'); +select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; +select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1; +drop table t1; + +# check zero rows (bug#836) +create table t1(id int); +create table t2(id int); +insert into t1 values(0),(1); +select group_concat(t1.id) FROM t1,t2; +drop table t1; +drop table t2; + +# check having +create table t1 (bar varchar(32)); +insert into t1 values('test1'),('test2'); +select group_concat(bar order by concat(bar,bar)) from t1; +select group_concat(bar order by concat(bar,bar) desc) from t1; +select bar from t1 having group_concat(bar)=''; +select bar from t1 having instr(group_concat(bar), "test") > 0; +select bar from t1 having instr(group_concat(bar order by concat(bar,bar) desc), "test2,test1") > 0; +drop table t1; + +# ORDER BY fix_fields() +create table t1 (a int, a1 varchar(10)); +create table t2 (a0 int); +insert into t1 values (0,"a"),(0,"b"),(1,"c"); +insert into t2 values (1),(2),(3); +select group_concat(a1 order by (t1.a IN (select a0 from t2))) from t1; +select group_concat(a1 order by (t1.a)) from t1; +drop table t1, t2; + +# +# Problem with GROUP BY (Bug #2695) +# + +CREATE TABLE t1 (id1 tinyint(4) NOT NULL, id2 tinyint(4) NOT NULL); +INSERT INTO t1 VALUES (1, 1),(1, 2),(1, 3),(1, 4),(1, 5),(2, 1),(2, 2),(2, 3); +CREATE TABLE t2 (id1 tinyint(4) NOT NULL); +INSERT INTO t2 VALUES (1),(2),(3),(4),(5); +SELECT t1.id1, GROUP_CONCAT(t1.id2 ORDER BY t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 AND t1.id1=1 GROUP BY t1.id1; +SELECT t1.id1, GROUP_CONCAT(t1.id2 ORDER BY t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +SELECT t1.id1, GROUP_CONCAT(t1.id2 ORDER BY t1.id2 DESC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +SELECT t1.id1, GROUP_CONCAT(t1.id2 ORDER BY 6-t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; + +# The following failed when it was run twice: +SELECT t1.id1, GROUP_CONCAT(t1.id2,6-t1.id2 ORDER BY 6-t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +SELECT t1.id1, GROUP_CONCAT(t1.id2,6-t1.id2 ORDER BY 6-t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; + +SELECT t1.id1, GROUP_CONCAT(t1.id2,"/",6-t1.id2 ORDER BY 1+0,6-t1.id2,t1.id2 ASC) AS concat_id FROM t1, t2 WHERE t1.id1 = t2.id1 GROUP BY t1.id1; +drop table t1,t2; + +# +# Problem with distinct (Bug #3381) +# + +create table t1 (s1 char(10), s2 int not null); +insert into t1 values ('a',2),('b',2),('c',1),('a',3),('b',4),('c',4); +select distinct s1 from t1 order by s2,s1; +select group_concat(distinct s1) from t1; +select group_concat(distinct s1 order by s2) from t1 where s2 < 4; +# The following is wrong and needs to be fixed ASAP +select group_concat(distinct s1 order by s2) from t1; +drop table t1; + +# +# Test with subqueries (Bug #3319) +# + +create table t1 (a int, c int); +insert into t1 values (1, 2), (2, 3), (2, 4), (3, 5); +create table t2 (a int, c int); +insert into t2 values (1, 5), (2, 4), (3, 3), (3,3); +select group_concat(c) from t1; +select group_concat(c order by (select c from t2 where t2.a=t1.a limit 1)) as grp from t1; +select group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a)) as grp from t1; +select group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1; +select t1.a, group_concat(c order by (select c from t2 where t2.a=t1.a limit 1)) as grp from t1 group by 1; +select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a)) as grp from t1 group by 1; +select t1.a, group_concat(c order by (select mid(group_concat(c order by a),1,5) from t2 where t2.a=t1.a) desc) as grp from t1 group by 1; + +# The following returns random results as we are sorting on blob addresses +select group_concat(c order by (select concat(5-t1.c,group_concat(c order by a)) from t2 where t2.a=t1.a)) as grp from t1; +select group_concat(c order by (select concat(t1.c,group_concat(c)) from t2 where a=t1.a)) as grp from t1; + +select a,c,(select group_concat(c order by a) from t2 where a=t1.a) as grp from t1 order by grp; +drop table t1,t2; + +# +# group_concat of expression with GROUP BY and external GROUP BY +# +CREATE TABLE t1 ( a int ); +CREATE TABLE t2 ( a int ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +SELECT GROUP_CONCAT(t1.a*t2.a ORDER BY t2.a) FROM t1, t2 GROUP BY t1.a; +DROP TABLE t1, t2; + +# +# Bug #4035: group_concat() and HAVING +# + +CREATE TABLE t1 (a char(4)); +INSERT INTO t1 VALUES ('John'), ('Anna'), ('Bill'); +SELECT GROUP_CONCAT(a SEPARATOR '||') AS names FROM t1 + HAVING names LIKE '%An%'; +SELECT GROUP_CONCAT(a SEPARATOR '###') AS names FROM t1 + HAVING LEFT(names, 1) ='J'; +DROP TABLE t1; + +# +# check blobs +# + +CREATE TABLE t1 ( a int, b TEXT ); +INSERT INTO t1 VALUES (1,'First Row'), (2,'Second Row'); +SELECT GROUP_CONCAT(b ORDER BY b) FROM t1 GROUP BY a; +DROP TABLE t1; + +# +# check null values #2 +# + +CREATE TABLE t1 (A_ID INT NOT NULL,A_DESC CHAR(3) NOT NULL,PRIMARY KEY (A_ID)); +INSERT INTO t1 VALUES (1,'ABC'), (2,'EFG'), (3,'HIJ'); +CREATE TABLE t2 (A_ID INT NOT NULL,B_DESC CHAR(3) NOT NULL,PRIMARY KEY (A_ID,B_DESC)); +INSERT INTO t2 VALUES (1,'A'),(1,'B'),(3,'F'); +SELECT t1.A_ID, GROUP_CONCAT(t2.B_DESC) AS B_DESC FROM t1 LEFT JOIN t2 ON t1.A_ID=t2.A_ID GROUP BY t1.A_ID ORDER BY t1.A_DESC; +DROP TABLE t1; +DROP TABLE t2; + +# +# blobs +# + +create table t1 (a int, b text); +insert into t1 values (1, 'bb'), (1, 'ccc'), (1, 'a'), (1, 'bb'), (1, 'ccc'); +insert into t1 values (2, 'BB'), (2, 'CCC'), (2, 'A'), (2, 'BB'), (2, 'CCC'); +select group_concat(b) from t1 group by a; +select group_concat(distinct b) from t1 group by a; +select group_concat(b order by b) from t1 group by a; +select group_concat(distinct b order by b) from t1 group by a; +set local group_concat_max_len=4; +select group_concat(b) from t1 group by a; +select group_concat(distinct b) from t1 group by a; +select group_concat(b order by b) from t1 group by a; +select group_concat(distinct b order by b) from t1 group by a; + +# +# long blobs +# + +insert into t1 values (1, concat(repeat('1', 300), '2')), +(1, concat(repeat('1', 300), '2')), (1, concat(repeat('0', 300), '1')), +(2, concat(repeat('1', 300), '2')), (2, concat(repeat('1', 300), '2')), +(2, concat(repeat('0', 300), '1')); +set local group_concat_max_len=1024; +select group_concat(b) from t1 group by a; +select group_concat(distinct b) from t1 group by a; +select group_concat(b order by b) from t1 group by a; +select group_concat(distinct b order by b) from t1 group by a; +set local group_concat_max_len=400; +select group_concat(b) from t1 group by a; +select group_concat(distinct b) from t1 group by a; +select group_concat(b order by b) from t1 group by a; +select group_concat(distinct b order by b) from t1 group by a; + +drop table t1; + +# +# Bug#10201 +# +create table t1 (a varchar(255) character set cp1250 collate cp1250_general_ci, + b varchar(255) character set koi8r); +insert into t1 values ('xxx','yyy'); +select collation(a) from t1; +select collation(group_concat(a)) from t1; +create table t2 select group_concat(a) as a from t1; +show create table t2; +select collation(group_concat(a,_koi8r'test')) from t1; +--error 1267 +select collation(group_concat(a,_koi8r 0xC1C2)) from t1; +--error 1267 +select collation(group_concat(a,b)) from t1; +drop table t1; +drop table t2; + +# +# Bug #12829 +# Cannot convert the charset of a GROUP_CONCAT result +# +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +SELECT GROUP_CONCAT(a) FROM t1; +DROP TABLE t1; + +# +# bug #7769: group_concat returning null is checked in having +# +CREATE TABLE t1 (id int); +SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; +DROP TABLE t1; + +# +# Bug #8656: Crash with group_concat on alias in outer table +# +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2); +select b x, (select group_concat(x) from t2) from t2; +drop table t2; + +# +# Bug #7405: problems with rollup +# + +create table t1 (d int not null auto_increment,primary key(d), a int, b int, c int); +insert into t1(a,b) values (1,3), (1,4), (1,2), (2,7), (1,1), (1,2), (2,3), (2,3); +select d,a,b from t1 order by a; +explain select a, group_concat(b) from t1 group by a with rollup; +select a, group_concat(b) from t1 group by a with rollup; +select a, group_concat(distinct b) from t1 group by a with rollup; +select a, group_concat(b order by b) from t1 group by a with rollup; +select a, group_concat(distinct b order by b) from t1 group by a with rollup; +drop table t1; + +# +# Bug #6475 +# +create table t1 (a char(3), b char(20), primary key (a, b)); +insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English'); +select group_concat(a) from t1 group by b; +drop table t1; +# +# Bug #12095: GROUP_CONCAT for one row table +# + +CREATE TABLE t1 ( + aID smallint(5) unsigned NOT NULL auto_increment, + sometitle varchar(255) NOT NULL default '', + bID smallint(5) unsigned NOT NULL, + PRIMARY KEY (aID), + UNIQUE KEY sometitle (sometitle) +); +INSERT INTO t1 SET sometitle = 'title1', bID = 1; +INSERT INTO t1 SET sometitle = 'title2', bID = 1; + +CREATE TABLE t2 ( + bID smallint(5) unsigned NOT NULL auto_increment, + somename varchar(255) NOT NULL default '', + PRIMARY KEY (bID), + UNIQUE KEY somename (somename) +); +INSERT INTO t2 SET somename = 'test'; + +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') + FROM t1 JOIN t2 ON t1.bID = t2.bID; +INSERT INTO t2 SET somename = 'test2'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') + FROM t1 JOIN t2 ON t1.bID = t2.bID; +DELETE FROM t2 WHERE somename = 'test2'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') + FROM t1 JOIN t2 ON t1.bID = t2.bID; + +DROP TABLE t1,t2; + +# +# Bug #12861 hang with group_concat insubquery FROM DUAL +# +select * from (select group_concat('c') from DUAL) t; + +# +# Bug #12859 group_concat in subquery cause incorrect not null +# +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +select group_concat('x') UNION ALL select 1; +drop table t1; + +# +# Bug #12863 : missing separators after first empty cancatanated elements +# + +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES + (2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); + +SELECT GROUP_CONCAT(a) FROM t1; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; + +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; + +DROP TABLE t1; + +# +# Bug #15560: GROUP_CONCAT wasn't ready for WITH ROLLUP queries +# +create table t1(f1 int); +insert into t1 values(1),(2),(3); +select f1, group_concat(f1+1) from t1 group by f1 with rollup; +select count(distinct (f1+1)) from t1 group by f1 with rollup; +drop table t1; + +# +# Bug#14169 type of group_concat() result changed to blob if tmp_table was used +# +create table t1 (f1 int unsigned, f2 varchar(255)); +insert into t1 values (1,repeat('a',255)),(2,repeat('b',255)); +--enable_metadata +select f2,group_concat(f1) from t1 group by f2; +--disable_metadata +drop table t1; + +# End of 4.1 tests + +# +# Bug#8568 "GROUP_CONCAT returns string, unless in a UNION in which case +# returns BLOB": add a test case, the bug can not be repeated any more. +# + +set names latin1; +create table t1 (a char, b char); +insert into t1 values ('a', 'a'), ('a', 'b'), ('b', 'a'), ('b', 'b'); +create table t2 select group_concat(b) as a from t1 where a = 'a'; +create table t3 (select group_concat(a) as a from t1 where a = 'a') union + (select group_concat(b) as a from t1 where a = 'b'); +select charset(a) from t2; +select charset(a) from t3; +drop table t1, t2, t3; +set names default; + +# +# Bug#18281 group_concat changes charset to binary +# +create table t1 (c1 varchar(10), c2 int); +select charset(group_concat(c1 order by c2)) from t1; +drop table t1; + +# +# Bug #16712: group_concat returns odd string instead of intended result +# +CREATE TABLE t1 (a INT(10), b LONGTEXT, PRIMARY KEY (a)); + +SET GROUP_CONCAT_MAX_LEN = 20000000; + +INSERT INTO t1 VALUES (1,REPEAT(CONCAT('A',CAST(CHAR(0) AS BINARY),'B'), 40000)); +INSERT INTO t1 SELECT a + 1, b FROM t1; + +SELECT a, CHAR_LENGTH(b) FROM t1; +SELECT CHAR_LENGTH( GROUP_CONCAT(b) ) FROM t1; +SET GROUP_CONCAT_MAX_LEN = 1024; +DROP TABLE t1; + +# +# Bug #22015: crash with GROUP_CONCAT over a derived table that +# returns the results of aggregation by GROUP_CONCAT +# + +CREATE TABLE t1 (a int, b int); + +INSERT INTO t1 VALUES (2,1), (1,2), (2,2), (1,3); + +SELECT GROUP_CONCAT(a), x + FROM (SELECT a, GROUP_CONCAT(b) x FROM t1 GROUP BY a) AS s + GROUP BY x; + +DROP TABLE t1; +# +# Bug#23451 GROUP_CONCAT truncates a multibyte utf8 character +# +set names utf8; +create table t1 +( + x text character set utf8 not null, + y integer not null +); +insert into t1 values (repeat('a', 1022), 0), (repeat(_utf8 0xc3b7, 4), 0); +let $1= 10; +while ($1) +{ + eval set group_concat_max_len= 1022 + $1; + --disable_result_log + select @x:=group_concat(x) from t1 group by y; + --enable_result_log + select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12); + dec $1; +} +drop table t1; +set group_concat_max_len=1024; +set names latin1; + +# +# Bug#14169 type of group_concat() result changed to blob if tmp_table was used +# +create table t1 (f1 int unsigned, f2 varchar(255)); +insert into t1 values (1,repeat('a',255)),(2,repeat('b',255)); +--enable_metadata +select f2,group_concat(f1) from t1 group by f2; +--disable_metadata +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_group.test b/mysql-test/suite/pbxt/t/func_group.test new file mode 100644 index 00000000000..ca303030749 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_group.test @@ -0,0 +1,831 @@ +# +# simple test of all group functions +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +set @sav_dpi= @@div_precision_increment; +set div_precision_increment= 5; +show variables like 'div_precision_increment'; +create table t1 (grp int, a bigint unsigned, c char(10) not null); +insert into t1 values (1,1,"a"); +insert into t1 values (2,2,"b"); +insert into t1 values (2,3,"c"); +insert into t1 values (3,4,"E"); +insert into t1 values (3,5,"C"); +insert into t1 values (3,6,"D"); + +# Test of MySQL field extension with and without matching records. +select a,c,sum(a) from t1 group by a; +select a,c,sum(a) from t1 where a > 10 group by a; +select sum(a) from t1 where a > 10; +select a from t1 order by rand(10); +select distinct a from t1 order by rand(10); +select count(distinct a),count(distinct grp) from t1; +insert into t1 values (null,null,''); +select count(distinct a),count(distinct grp) from t1; + +select sum(all a),count(all a),avg(all a),std(all a),variance(all a),bit_or(all a),bit_and(all a),min(all a),max(all a),min(all c),max(all c) from t1; +select grp, sum(a),count(a),avg(a),std(a),variance(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp; +--disable_warnings +select grp, sum(a)+count(a)+avg(a)+std(a)+variance(a)+bit_or(a)+bit_and(a)+min(a)+max(a)+min(c)+max(c) as sum from t1 group by grp; +--enable_warnings + +create table t2 (grp int, a bigint unsigned, c char(10)); +insert into t2 select grp,max(a)+max(grp),max(c) from t1 group by grp; + +# REPLACE ... SELECT doesn't yet work with PS +replace into t2 select grp, a, c from t1 limit 2,1; +select * from t2; + +drop table t1,t2; + +# +# Problem with std() +# + +CREATE TABLE t1 (id int(11),value1 float(10,2)); +INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00); +CREATE TABLE t2 (id int(11),name char(20)); +INSERT INTO t2 VALUES (1,'Set One'),(2,'Set Two'); +select id, avg(value1), std(value1), variance(value1) from t1 group by id; +select name, avg(value1), std(value1), variance(value1) from t1, t2 where t1.id = t2.id group by t1.id; +drop table t1,t2; + +# +# Test of bug in left join & avg +# + +create table t1 (id int not null); +create table t2 (id int not null,rating int null); +insert into t1 values(1),(2),(3); +insert into t2 values(1, 3),(2, NULL),(2, NULL),(3, 2),(3, NULL); +select t1.id, avg(rating) from t1 left join t2 on ( t1.id = t2.id ) group by t1.id; +# Test different types with avg() +select sql_small_result t2.id, avg(rating) from t2 group by t2.id; +select sql_big_result t2.id, avg(rating) from t2 group by t2.id; +select sql_small_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +select sql_big_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +drop table t1,t2; + +# +# test of count +# +create table t1 (a smallint(6) primary key, c char(10), b text); +INSERT INTO t1 VALUES (1,'1','1'); +INSERT INTO t1 VALUES (2,'2','2'); +INSERT INTO t1 VALUES (4,'4','4'); + +select count(*) from t1; +select count(*) from t1 where a = 1; +select count(*) from t1 where a = 100; +select count(*) from t1 where a >= 10; +select count(a) from t1 where a = 1; +select count(a) from t1 where a = 100; +select count(a) from t1 where a >= 10; +select count(b) from t1 where b >= 2; +select count(b) from t1 where b >= 10; +select count(c) from t1 where c = 10; +drop table t1; + +# +# Test of bug in COUNT(i)*(i+0) +# + +CREATE TABLE t1 (d DATETIME, i INT); +INSERT INTO t1 VALUES (NOW(), 1); +SELECT COUNT(i), i, COUNT(i)*i FROM t1 GROUP BY i; +SELECT COUNT(i), (i+0), COUNT(i)*(i+0) FROM t1 GROUP BY i; +DROP TABLE t1; + +# +# Another SUM() problem with 3.23.2 +# + +create table t1 ( + num float(5,2), + user char(20) +); +insert into t1 values (10.3,'nem'),(20.53,'monty'),(30.23,'sinisa'); +insert into t1 values (30.13,'nem'),(20.98,'monty'),(10.45,'sinisa'); +insert into t1 values (5.2,'nem'),(8.64,'monty'),(11.12,'sinisa'); +select sum(num) from t1; +select sum(num) from t1 group by user; +drop table t1; + +# +# Test problem with MIN() optimization in case of null values +# + +create table t1 (a1 int, a2 char(3), key k1(a1), key k2(a2)); +insert into t1 values(10,'aaa'), (10,null), (10,'bbb'), (20,'zzz'); +create table t2(a1 char(3), a2 int, a3 real, key k1(a1), key k2(a2, a1)); +select * from t1; +# The following returned NULL in 4.0.10 +select min(a2) from t1; +select max(t1.a1), max(t2.a2) from t1, t2; +select max(t1.a1) from t1, t2; +select max(t2.a2), max(t1.a1) from t1, t2; + +explain select min(a2) from t1; +explain select max(t1.a1), max(t2.a2) from t1, t2; + +insert into t2 values('AAA', 10, 0.5); +insert into t2 values('BBB', 20, 1.0); +select t1.a1, t1.a2, t2.a1, t2.a2 from t1,t2; + +select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9; +select max(t2.a1), max(t1.a1) from t1, t2 where t2.a2=9; +select t1.a1, t1.a2, t2.a1, t2.a2 from t1 left outer join t2 on t1.a1=10; +select max(t1.a2) from t1 left outer join t2 on t1.a1=10; +select max(t2.a1) from t2 left outer join t1 on t2.a2=10 where t2.a2=20; +select max(t2.a1) from t2 left outer join t1 on t2.a2=10 where t2.a2=10; +select max(t2.a1) from t1 left outer join t2 on t1.a2=t2.a1 and 1=0 where t2.a1='AAA'; +select max(t1.a2),max(t2.a1) from t1 left outer join t2 on t1.a1=10; +drop table t1,t2; + +# +# Test of group function and NULL values +# + +CREATE TABLE t1 (a int, b int); +select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (1,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (1,null); +insert into t1 values (2,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (2,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (3,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +drop table t1; + +# +# Bug #1972: test for bit_and(), bit_or() and negative values +# +create table t1 (col int); +insert into t1 values (-1), (-2), (-3); +select bit_and(col), bit_or(col) from t1; +select SQL_BIG_RESULT bit_and(col), bit_or(col) from t1 group by col; +drop table t1; + +# +# Bug #3376: avg() and an empty table +# + +create table t1 (a int); +select avg(2) from t1; +drop table t1; + +# +# Tests to check MIN/MAX query optimization +# + +# Create database schema +create table t1( + a1 char(3) primary key, + a2 smallint, + a3 char(3), + a4 real, + a5 date, + key k1(a2,a3), + key k2(a4 desc,a1), + key k3(a5,a1) +); +create table t2( + a1 char(3) primary key, + a2 char(17), + a3 char(2), + a4 char(3), + key k1(a3, a2), + key k2(a4) +); + +# Populate table t1 +insert into t1 values('AME',0,'SEA',0.100,date'1942-02-19'); +insert into t1 values('HBR',1,'SEA',0.085,date'1948-03-05'); +insert into t1 values('BOT',2,'SEA',0.085,date'1951-11-29'); +insert into t1 values('BMC',3,'SEA',0.085,date'1958-09-08'); +insert into t1 values('TWU',0,'LAX',0.080,date'1969-10-05'); +insert into t1 values('BDL',0,'DEN',0.080,date'1960-11-27'); +insert into t1 values('DTX',1,'NYC',0.080,date'1961-05-04'); +insert into t1 values('PLS',1,'WDC',0.075,date'1949-01-02'); +insert into t1 values('ZAJ',2,'CHI',0.075,date'1960-06-15'); +insert into t1 values('VVV',2,'MIN',0.075,date'1959-06-28'); +insert into t1 values('GTM',3,'DAL',0.070,date'1977-09-23'); +insert into t1 values('SSJ',null,'CHI',null,date'1974-03-19'); +insert into t1 values('KKK',3,'ATL',null,null); +insert into t1 values('XXX',null,'MIN',null,null); +insert into t1 values('WWW',1,'LED',null,null); + +# Populate table t2 +insert into t2 values('TKF','Seattle','WA','AME'); +insert into t2 values('LCC','Los Angeles','CA','TWU'); +insert into t2 values('DEN','Denver','CO','BDL'); +insert into t2 values('SDC','San Diego','CA','TWU'); +insert into t2 values('NOL','New Orleans','LA','GTM'); +insert into t2 values('LAK','Los Angeles','CA','TWU'); +insert into t2 values('AAA','AAA','AA','AME'); + +# Show the table contents +select * from t1; +select * from t2; + +# Queries with min/max functions +# which regular min/max optimization are applied to + +explain +select min(a1) from t1; +select min(a1) from t1; +explain +select max(a4) from t1; +select max(a4) from t1; +explain +select min(a5), max(a5) from t1; +select min(a5), max(a5) from t1; +explain +select min(a3) from t1 where a2 = 2; +select min(a3) from t1 where a2 = 2; +explain +select min(a1), max(a1) from t1 where a4 = 0.080; +select min(a1), max(a1) from t1 where a4 = 0.080; + +explain +select min(t1.a5), max(t2.a3) from t1, t2; +select min(t1.a5), max(t2.a3) from t1, t2; +explain +select min(t1.a3), max(t2.a2) from t1, t2 where t1.a2 = 0 and t2.a3 = 'CA'; +select min(t1.a3), max(t2.a2) from t1, t2 where t1.a2 = 0 and t2.a3 = 'CA'; + +# Queries with min/max functions +# which extended min/max optimization are applied to + +explain +select min(a1) from t1 where a1 > 'KKK'; +select min(a1) from t1 where a1 > 'KKK'; +explain +select min(a1) from t1 where a1 >= 'KKK'; +select min(a1) from t1 where a1 >= 'KKK'; +explain +select max(a3) from t1 where a2 = 2 and a3 < 'SEA'; +select max(a3) from t1 where a2 = 2 and a3 < 'SEA'; +explain +select max(a5) from t1 where a5 < date'1970-01-01'; +select max(a5) from t1 where a5 < date'1970-01-01'; +explain +select max(a3) from t1 where a2 is null; +select max(a3) from t1 where a2 is null; +explain +select max(a3) from t1 where a2 = 0 and a3 between 'K' and 'Q'; +select max(a3) from t1 where a2 = 0 and a3 between 'K' and 'Q'; +explain +select min(a1), max(a1) from t1 where a1 between 'A' and 'P'; +select min(a1), max(a1) from t1 where a1 between 'A' and 'P'; +explain +select max(a3) from t1 where a3 < 'SEA' and a2 = 2 and a3 <= 'MIN'; +select max(a3) from t1 where a3 < 'SEA' and a2 = 2 and a3 <= 'MIN'; +explain +select max(a3) from t1 where a3 = 'MIN' and a2 = 2; +select max(a3) from t1 where a3 = 'MIN' and a2 = 2; +explain +select max(a3) from t1 where a3 = 'DEN' and a2 = 2; +select max(a3) from t1 where a3 = 'DEN' and a2 = 2; + +explain +select max(t1.a3), min(t2.a2) from t1, t2 where t1.a2 = 2 and t1.a3 < 'MIN' and t2.a3 = 'CA'; +select max(t1.a3), min(t2.a2) from t1, t2 where t1.a2 = 2 and t1.a3 < 'MIN' and t2.a3 = 'CA'; + +explain +select max(a3) from t1 where a2 is null and a2 = 2; +select max(a3) from t1 where a2 is null and a2 = 2; + +explain +select max(a2) from t1 where a2 >= 1; +select max(a2) from t1 where a2 >= 1; +explain +select min(a3) from t1 where a2 = 2 and a3 < 'SEA'; +select min(a3) from t1 where a2 = 2 and a3 < 'SEA'; + +explain +select min(a3) from t1 where a2 = 4; +select min(a3) from t1 where a2 = 4; +explain +select min(a3) from t1 where a2 = 2 and a3 > 'SEA'; +select min(a3) from t1 where a2 = 2 and a3 > 'SEA'; +explain +select (min(a4)+max(a4))/2 from t1; +select (min(a4)+max(a4))/2 from t1; +explain +select min(a3) from t1 where 2 = a2; +select min(a3) from t1 where 2 = a2; +explain +select max(a3) from t1 where a2 = 2 and 'SEA' > a3; +select max(a3) from t1 where a2 = 2 and 'SEA' > a3; +explain +select max(a3) from t1 where a2 = 2 and 'SEA' < a3; +select max(a3) from t1 where a2 = 2 and 'SEA' < a3; +explain +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI'; +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI'; +explain +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI' and a3 < 'SEA'; +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI' and a3 < 'SEA'; +explain +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI' and a3 = 'MIN'; +select min(a3) from t1 where a2 = 2 and a3 >= 'CHI' and a3 = 'MIN'; +explain +select min(a3) from t1 where a2 = 2 and a3 >= 'SEA' and a3 = 'MIN'; +select min(a3) from t1 where a2 = 2 and a3 >= 'SEA' and a3 = 'MIN'; + +explain +select min(t1.a1), min(t2.a4) from t1,t2 where t1.a1 < 'KKK' and t2.a4 < 'KKK'; +select min(t1.a1), min(t2.a4) from t1,t2 where t1.a1 < 'KKK' and t2.a4 < 'KKK'; + +# Queries to which max/min optimization is not applied + +explain +select min(a1) from t1 where a1 > 'KKK' or a1 < 'XXX'; +explain +select min(a1) from t1 where a1 != 'KKK'; +explain +select max(a3) from t1 where a2 < 2 and a3 < 'SEA'; +explain +select max(t1.a3), min(t2.a2) from t1, t2 where t1.a2 = 2 and t1.a3 < 'MIN' and t2.a3 > 'CA'; + +explain +select min(a4 - 0.01) from t1; +explain +select max(a4 + 0.01) from t1; +explain +select min(a3) from t1 where (a2 +1 ) is null; +explain +select min(a3) from t1 where (a2 + 1) = 2; +explain +select min(a3) from t1 where 2 = (a2 + 1); +explain +select min(a2) from t1 where a2 < 2 * a2 - 8; +explain +select min(a1) from t1 where a1 between a3 and 'KKK'; +explain +select min(a4) from t1 where (a4 + 0.01) between 0.07 and 0.08; +explain +select concat(min(t1.a1),min(t2.a4)) from t1, t2 where t2.a4 <> 'AME'; +drop table t1, t2; + +# Moved to func_group_innodb +#--disable_warnings +#create table t1 (USR_ID integer not null, MAX_REQ integer not null, constraint PK_SEA_USER primary key (USR_ID)) engine=InnoDB; +#--enable_warnings +#insert into t1 values (1, 3); +#select count(*) + MAX_REQ - MAX_REQ + MAX_REQ - MAX_REQ + MAX_REQ - MAX_REQ + MAX_REQ - MAX_REQ + MAX_REQ - MAX_REQ from t1 group by MAX_REQ; +#select Case When Count(*) < MAX_REQ Then 1 Else 0 End from t1 where t1.USR_ID = 1 group by MAX_REQ; +#drop table t1; + + +create table t1 (a char(10)); +insert into t1 values ('a'),('b'),('c'); +select coercibility(max(a)) from t1; +drop table t1; + +# +# Bug #6658 MAX(column) returns incorrect coercibility +# +create table t1 (a char character set latin2); +insert into t1 values ('a'),('b'); +select charset(max(a)), coercibility(max(a)), + charset(min(a)), coercibility(min(a)) from t1; +show create table t1; +create table t2 select max(a),min(a) from t1; +show create table t2; +drop table t2; +create table t2 select concat(a) from t1; +show create table t2; +drop table t2,t1; + +# +# aggregate functions on static tables +# +create table t1 (a int); +insert into t1 values (1); +select max(a) as b from t1 having b=1; +select a from t1 having a=1; +drop table t1; + +# +# Bug #3435: variance(const), stddev(const) and an empty table +# + +create table t1 (a int); +select variance(2) from t1; +select stddev(2) from t1; +drop table t1; + + +# +# cleunup() of optimized away count(*) and max/min +# +create table t1 (a int); +insert into t1 values (1),(2); +prepare stmt1 from 'SELECT COUNT(*) FROM t1'; +execute stmt1; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; +drop table t1; + +create table t1 (a int, primary key(a)); +insert into t1 values (1),(2); +prepare stmt1 from 'SELECT max(a) FROM t1'; +execute stmt1; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; +drop table t1; + +# +# Bug #5406 min/max optimization for empty set +# + +CREATE TABLE t1 (a int primary key); +INSERT INTO t1 VALUES (1),(2),(3),(4); + +SELECT MAX(a) FROM t1 WHERE a > 5; +SELECT MIN(a) FROM t1 WHERE a < 0; + +DROP TABLE t1; + +# +# Bug #5555 GROUP BY enum_field" returns incorrect results +# + +CREATE TABLE t1 ( + id int(10) unsigned NOT NULL auto_increment, + val enum('one','two','three') NOT NULL default 'one', + PRIMARY KEY (id) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +INSERT INTO t1 VALUES +(1,'one'),(2,'two'),(3,'three'),(4,'one'),(5,'two'); + +select val, count(*) from t1 group by val; +drop table t1; + +CREATE TABLE t1 ( + id int(10) unsigned NOT NULL auto_increment, + val set('one','two','three') NOT NULL default 'one', + PRIMARY KEY (id) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +INSERT INTO t1 VALUES +(1,'one'),(2,'two'),(3,'three'),(4,'one'),(5,'two'); + +select val, count(*) from t1 group by val; +drop table t1; + +# +# Bug #5615: type of aggregate function column wrong when using group by +# + +create table t1(a int, b datetime); +insert into t1 values (1, NOW()), (2, NOW()); +create table t2 select MAX(b) from t1 group by a; +show create table t2; +drop table t1, t2; + +# +# Bug 7833: Wrong datatype of aggregate column is returned +# + +create table t1(f1 datetime); +insert into t1 values (now()); +create table t2 select f2 from (select max(now()) f2 from t1) a; +show columns from t2; +drop table t2; +create table t2 select f2 from (select now() f2 from t1) a; +show columns from t2; +drop table t2, t1; + +# +# Bug 8893: wrong result for min/max optimization with 2 indexes +# + +CREATE TABLE t1( + id int PRIMARY KEY, + a int, + b int, + INDEX i_b_id(a,b,id), + INDEX i_id(a,id) +); +INSERT INTO t1 VALUES + (1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); +SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; +DROP TABLE t1; + +# change the order of the last two index definitions + +CREATE TABLE t1( + id int PRIMARY KEY, + a int, + b int, + INDEX i_id(a,id), + INDEX i_b_id(a,b,id) +); +INSERT INTO t1 VALUES + (1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); +SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; +DROP TABLE t1; + + +# +# Bug #12882 min/max inconsistent on empty table +# +# Test case moved to func_group_innodb +# +# Bug #18206: min/max optimization cannot be applied to partial index +# + +CREATE TABLE t1 (id int PRIMARY KEY, b char(3), INDEX(b)); +INSERT INTO t1 VALUES (1,'xx'), (2,'aa'); +SELECT * FROM t1; + +SELECT MAX(b) FROM t1 WHERE b < 'ppppp'; +SHOW WARNINGS; +SELECT MAX(b) FROM t1 WHERE b < 'pp'; +DROP TABLE t1; + +CREATE TABLE t1 (id int PRIMARY KEY, b char(16), INDEX(b(4))); +INSERT INTO t1 VALUES (1, 'xxxxbbbb'), (2, 'xxxxaaaa'); +SELECT MAX(b) FROM t1; +EXPLAIN SELECT MAX(b) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (id int , b varchar(512), INDEX(b(250))) COLLATE latin1_bin; +INSERT INTO t1 VALUES + (1,CONCAT(REPEAT('_', 250), "qq")), (1,CONCAT(REPEAT('_', 250), "zz")), + (1,CONCAT(REPEAT('_', 250), "aa")), (1,CONCAT(REPEAT('_', 250), "ff")); + +SELECT MAX(b) FROM t1; +EXPLAIN SELECT MAX(b) FROM t1; +DROP TABLE t1; +# +# Bug #16792 query with subselect, join, and group not returning proper values +# +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,1),(1,2),(2,3); + +SELECT (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a; +SELECT (SELECT COUNT(DISTINCT 12)) FROM t1 GROUP BY t1.a; +# an attempt to test all aggregate function with no table. +SELECT AVG(2), BIT_AND(2), BIT_OR(2), BIT_XOR(2), COUNT(*), COUNT(12), + COUNT(DISTINCT 12), MIN(2),MAX(2),STD(2), VARIANCE(2),SUM(2), + GROUP_CONCAT(2),GROUP_CONCAT(DISTINCT 2); +DROP TABLE t1; + +# End of 4.1 tests + +# +# decimal-related tests +# +create table t2 (ff double); +insert into t2 values (2.2); +select cast(sum(distinct ff) as decimal(5,2)) from t2; +select cast(sum(distinct ff) as signed) from t2; +select cast(variance(ff) as decimal(10,3)) from t2; +select cast(min(ff) as decimal(5,2)) from t2; + +create table t1 (df decimal(5,1)); +insert into t1 values(1.1); +insert into t1 values(2.2); +select cast(sum(distinct df) as signed) from t1; +select cast(min(df) as signed) from t1; +select 1e8 * sum(distinct df) from t1; +select 1e8 * min(df) from t1; + +create table t3 (ifl int); +insert into t3 values(1), (2); +select cast(min(ifl) as decimal(5,2)) from t3; + +drop table t1, t2, t3; + + +# +# BUG#3190, WL#1639: Standard Deviation STDDEV - 2 different calculations +# + +CREATE TABLE t1 (id int(11),value1 float(10,2)); +INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00), (2,13.00); +select id, stddev_pop(value1), var_pop(value1), stddev_samp(value1), var_samp(value1) from t1 group by id; +DROP TABLE t1; + +# +# BUG#8464 decimal AVG returns incorrect result +# + +CREATE TABLE t1 (col1 decimal(16,12)); +INSERT INTO t1 VALUES (-5.00000000001),(-5.00000000002),(-5.00000000003),(-5.00000000000),(-5.00000000001),(-5.00000000002); +insert into t1 select * from t1; +select col1,count(col1),sum(col1),avg(col1) from t1 group by col1; +DROP TABLE t1; + +# +# BUG#8465 decimal MIN and MAX return incorrect result +# + +create table t1 (col1 decimal(16,12)); +insert into t1 values (-5.00000000001); +insert into t1 values (-5.00000000001); +select col1,sum(col1),max(col1),min(col1) from t1 group by col1; +delete from t1; +insert into t1 values (5.00000000001); +insert into t1 values (5.00000000001); +select col1,sum(col1),max(col1),min(col1) from t1 group by col1; +DROP TABLE t1; + +# +# Test that new VARCHAR correctly works with COUNT(DISTINCT) +# + +CREATE TABLE t1 (a VARCHAR(400)); +INSERT INTO t1 (a) VALUES ("A"), ("a"), ("a "), ("a "), + ("B"), ("b"), ("b "), ("b "); +SELECT COUNT(DISTINCT a) FROM t1; +DROP TABLE t1; + +# +# Test for buf #9210: GROUP BY with expression if a decimal type +# + +CREATE TABLE t1 (a int, b int, c int); +INSERT INTO t1 (a, b, c) VALUES + (1,1,1), (1,1,2), (1,1,3), + (1,2,1), (1,2,2), (1,2,3), + (1,3,1), (1,3,2), (1,3,3), + (2,1,1), (2,1,2), (2,1,3), + (2,2,1), (2,2,2), (2,2,3), + (2,3,1), (2,3,2), (2,3,3), + (3,1,1), (3,1,2), (3,1,3), + (3,2,1), (3,2,2), (3,2,3), + (3,3,1), (3,3,2), (3,3,3); + +SELECT b/c as v, a FROM t1 ORDER BY v, a; # PBXT: Need a consistant order +SELECT b/c as v, SUM(a) FROM t1 GROUP BY v; +SELECT SUM(a) FROM t1 GROUP BY b/c; + +DROP TABLE t1; +set div_precision_increment= @sav_dpi; + +# +# Bug #20868: Client connection is broken on SQL query error +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); + +CREATE TABLE t2 (a INT PRIMARY KEY, b INT); +INSERT INTO t2 VALUES (1,1), (3,3); + +SELECT SQL_NO_CACHE + (SELECT SUM(c.a) FROM t1 ttt, t2 ccc + WHERE ttt.a = ccc.b AND ttt.a = t.a GROUP BY ttt.a) AS minid +FROM t1 t, t2 c WHERE t.a = c.b; + +DROP TABLE t1,t2; + +# +# Bug #10966: Variance functions return wrong data type +# + +create table t1 select variance(0); +show create table t1; +drop table t1; +create table t1 select stddev(0); +show create table t1; +drop table t1; + + +# +# Bug#22555: STDDEV yields positive result for groups with only one row +# + +create table bug22555 (i smallint primary key auto_increment, s1 smallint, s2 smallint, e decimal(30,10), o double); +insert into bug22555 (s1, s2, e, o) values (53, 78, 11.4276528, 6.828112), (17, 78, 5.916793, 1.8502951), (18, 76, 2.679231, 9.17975591), (31, 62, 6.07831, 0.1), (19, 41, 5.37463, 15.1), (83, 73, 14.567426, 7.959222), (92, 53, 6.10151, 13.1856852), (7, 12, 13.92272, 3.442007), (92, 35, 11.95358909, 6.01376678), (38, 84, 2.572, 7.904571); +select std(s1/s2) from bug22555 group by i; +select std(e) from bug22555 group by i; +select std(o) from bug22555 group by i; +drop table bug22555; + +create table bug22555 (i smallint, s1 smallint, s2 smallint, o1 double, o2 double, e1 decimal, e2 decimal); +insert into bug22555 values (1,53,78,53,78,53,78),(2,17,78,17,78,17,78),(3,18,76,18,76,18,76); +select i, count(*) from bug22555 group by i; +select std(s1/s2) from bug22555 where i=1; +select std(s1/s2) from bug22555 where i=2; +select std(s1/s2) from bug22555 where i=3; +select std(s1/s2) from bug22555 where i=1 group by i; +select std(s1/s2) from bug22555 where i=2 group by i; +select std(s1/s2) from bug22555 where i=3 group by i; +select std(s1/s2) from bug22555 group by i order by i; +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +set @saved_div_precision_increment=@@div_precision_increment; +set div_precision_increment=19; +select i, count(*), variance(s1/s2) from bug22555 group by i order by i; +select i, count(*), variance(o1/o2) from bug22555 group by i order by i; +select i, count(*), variance(e1/e2) from bug22555 group by i order by i; +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +set div_precision_increment=20; +select i, count(*), variance(s1/s2) from bug22555 group by i order by i; +select i, count(*), variance(o1/o2) from bug22555 group by i order by i; +select i, count(*), variance(e1/e2) from bug22555 group by i order by i; +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +set @@div_precision_increment=@saved_div_precision_increment; +insert into bug22555 values (1,53,78,53,78,53,78),(2,17,78,17,78,17,78),(3,18,76,18,76,18,76); +insert into bug22555 values (1,53,78,53,78,53,78),(2,17,78,17,78,17,78),(3,18,76,18,76,18,76); +insert into bug22555 values (1,53,78,53,78,53,78),(2,17,78,17,78,17,78),(3,18,76,18,76,18,76); + +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +select std(s1/s2) from bug22555; +select std(o1/o2) from bug22555; +select std(e1/e2) from bug22555; +set @saved_div_precision_increment=@@div_precision_increment; +set div_precision_increment=19; +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +select round(std(s1/s2), 17) from bug22555; +select std(o1/o2) from bug22555; +select round(std(e1/e2), 17) from bug22555; +set div_precision_increment=20; +select i, count(*), std(s1/s2) from bug22555 group by i order by i; +select i, count(*), std(o1/o2) from bug22555 group by i order by i; +select i, count(*), std(e1/e2) from bug22555 group by i order by i; +select round(std(s1/s2), 17) from bug22555; +select std(o1/o2) from bug22555; +select round(std(e1/e2), 17) from bug22555; +set @@div_precision_increment=@saved_div_precision_increment; +drop table bug22555; + +create table bug22555 (s smallint, o double, e decimal); +insert into bug22555 values (1,1,1),(2,2,2),(3,3,3),(6,6,6),(7,7,7); +select var_samp(s), var_pop(s) from bug22555; +select var_samp(o), var_pop(o) from bug22555; +select var_samp(e), var_pop(e) from bug22555; +drop table bug22555; + +create table bug22555 (s smallint, o double, e decimal); +insert into bug22555 values (null,null,null),(null,null,null); +select var_samp(s) as 'null', var_pop(s) as 'null' from bug22555; +select var_samp(o) as 'null', var_pop(o) as 'null' from bug22555; +select var_samp(e) as 'null', var_pop(e) as 'null' from bug22555; +insert into bug22555 values (1,1,1); +select var_samp(s) as 'null', var_pop(s) as '0' from bug22555; +select var_samp(o) as 'null', var_pop(o) as '0' from bug22555; +select var_samp(e) as 'null', var_pop(e) as '0' from bug22555; +insert into bug22555 values (2,2,2); +select var_samp(s) as '0.5', var_pop(s) as '0.25' from bug22555; +select var_samp(o) as '0.5', var_pop(o) as '0.25' from bug22555; +select var_samp(e) as '0.5', var_pop(e) as '0.25' from bug22555; +drop table bug22555; + + +# +# Bug #23184: SELECT causes server crash +# +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8); +INSERT INTO t1 SELECT a, b+8 FROM t1; +INSERT INTO t1 SELECT a, b+16 FROM t1; +INSERT INTO t1 SELECT a, b+32 FROM t1; +INSERT INTO t1 SELECT a, b+64 FROM t1; +INSERT INTO t1 SELECT a, b+128 FROM t1; +INSERT INTO t1 SELECT a, b+256 FROM t1; +INSERT INTO t1 SELECT a, b+512 FROM t1; +INSERT INTO t1 SELECT a, b+1024 FROM t1; +INSERT INTO t1 SELECT a, b+2048 FROM t1; +INSERT INTO t1 SELECT a, b+4096 FROM t1; +INSERT INTO t1 SELECT a, b+8192 FROM t1; +INSERT INTO t1 SELECT a, b+16384 FROM t1; +INSERT INTO t1 SELECT a, b+32768 FROM t1; +SELECT a,COUNT(DISTINCT b) AS cnt FROM t1 GROUP BY a HAVING cnt > 50; +SELECT a,SUM(DISTINCT b) AS sumation FROM t1 GROUP BY a HAVING sumation > 50; +SELECT a,AVG(DISTINCT b) AS average FROM t1 GROUP BY a HAVING average > 50; + +DROP TABLE t1; + +### +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/func_if.test b/mysql-test/suite/pbxt/t/func_if.test new file mode 100644 index 00000000000..dc83ceb771e --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_if.test @@ -0,0 +1,103 @@ +# +# Init section +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Simple IF tests +# + +select IF(0,"ERROR","this"),IF(1,"is","ERROR"),IF(NULL,"ERROR","a"),IF(1,2,3)|0,IF(1,2.0,3.0)+0 ; + +# +# Test of IF and case-sensitiveness +# +CREATE TABLE t1 (st varchar(255) NOT NULL, u int(11) NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('a',1),('A',1),('aa',1),('AA',1),('a',1),('aaa',0),('BBB',0); +select if(1,st,st) s from t1 order by s; +select if(u=1,st,st) s from t1 order by s; +select if(u=1,binary st,st) s from t1 order by s; +select if(u=1,st,binary st) s from t1 where st like "%a%" order by s; +explain extended select if(u=1,st,binary st) s from t1 where st like "%a%" order by s; + +# +# NULLIF test +# +select nullif(u, 1) from t1; +explain extended select nullif(u, 1) from t1; +drop table t1; +select nullif(1,'test'); + +# +# Bug 2629 +# +select NULLIF(NULL,NULL), NULLIF(NULL,1), NULLIF(NULL,1.0), NULLIF(NULL,"test"); +select NULLIF(1,NULL), NULLIF(1.0, NULL), NULLIF("test", NULL); + +# +# Problem with IF() +# + +create table t1 (num double(12,2)); +insert into t1 values (144.54); +select sum(if(num is null,0.00,num)) from t1; +drop table t1; +create table t1 (x int, y int); +insert into t1 values (0,6),(10,16),(20,26),(30,10),(40,46),(50,56); +select min(if(y -x > 5,y,NULL)), max(if(y - x > 5,y,NULL)) from t1; +drop table t1; + +# +# BUG#3987 +# +create table t1 (a int); +insert t1 values (1),(2); +select if(1>2,a,avg(a)) from t1; +drop table t1; + +# +# Bug #5595 NULLIF() IS NULL returns false if NULLIF() returns NULL +# +SELECT NULLIF(5,5) IS NULL, NULLIF(5,5) IS NOT NULL; + +# +# Bug #9669 Ordering on IF function with FROM_UNIXTIME function fails +# +CREATE TABLE `t1` ( + `id` int(11) NOT NULL , + `date` int(10) default NULL, + `text` varchar(32) NOT NULL +); +INSERT INTO t1 VALUES (1,1110000000,'Day 1'),(2,1111000000,'Day 2'),(3,1112000000,'Day 3'); +SELECT id, IF(date IS NULL, '-', FROM_UNIXTIME(date, '%d-%m-%Y')) AS date_ord, text FROM t1 ORDER BY date_ord ASC; +SELECT id, IF(date IS NULL, '-', FROM_UNIXTIME(date, '%d-%m-%Y')) AS date_ord, text FROM t1 ORDER BY date_ord DESC; +DROP TABLE t1; + + +# +# Test for bug #11142: evaluation of NULLIF when the first argument is NULL +# + +CREATE TABLE t1 (a CHAR(10)); +INSERT INTO t1 VALUES ('aaa'), (NULL), (''), ('bbb'); + +SELECT a, NULLIF(a,'') FROM t1; +SELECT a, NULLIF(a,'') FROM t1 WHERE NULLIF(a,'') IS NULL; + +DROP TABLE t1; + +# End of 4.1 tests + +# +# Bug #16272 IF function with decimal args can produce wrong result +# +create table t1 (f1 int, f2 int); +insert into t1 values(1,1),(0,0); +select f1, f2, if(f1, 40.0, 5.00) from t1 group by f1 order by f2; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/func_in.test b/mysql-test/suite/pbxt/t/func_in.test new file mode 100644 index 00000000000..47529647030 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_in.test @@ -0,0 +1,307 @@ +# Initialise +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +# +# test of IN (NULL) +# + +select 1 in (1,2,3); +select 10 in (1,2,3); +select NULL in (1,2,3); +select 1 in (1,NULL,3); +select 3 in (1,NULL,3); +select 10 in (1,NULL,3); +select 1.5 in (1.5,2.5,3.5); +select 10.5 in (1.5,2.5,3.5); +select NULL in (1.5,2.5,3.5); +select 1.5 in (1.5,NULL,3.5); +select 3.5 in (1.5,NULL,3.5); +select 10.5 in (1.5,NULL,3.5); + +CREATE TABLE t1 (a int, b int, c int); +insert into t1 values (1,2,3), (1,NULL,3); +select 1 in (a,b,c) from t1; +select 3 in (a,b,c) from t1; +select 10 in (a,b,c) from t1; +select NULL in (a,b,c) from t1; +drop table t1; +CREATE TABLE t1 (a float, b float, c float); +insert into t1 values (1.5,2.5,3.5), (1.5,NULL,3.5); +select 1.5 in (a,b,c) from t1; +select 3.5 in (a,b,c) from t1; +select 10.5 in (a,b,c) from t1; +drop table t1; +CREATE TABLE t1 (a varchar(10), b varchar(10), c varchar(10)); +insert into t1 values ('A','BC','EFD'), ('A',NULL,'EFD'); +select 'A' in (a,b,c) from t1; +select 'EFD' in (a,b,c) from t1; +select 'XSFGGHF' in (a,b,c) from t1; +drop table t1; + +CREATE TABLE t1 (field char(1)); +INSERT INTO t1 VALUES ('A'),(NULL); +SELECT * from t1 WHERE field IN (NULL); +SELECT * from t1 WHERE field NOT IN (NULL); +SELECT * from t1 where field = field; +SELECT * from t1 where field <=> field; +DELETE FROM t1 WHERE field NOT IN (NULL); +SELECT * FROM t1; +drop table t1; + +create table t1 (id int(10) primary key); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9); +select * from t1 where id in (2,5,9); +drop table t1; + +create table t1 ( +a char(1) character set latin1 collate latin1_general_ci, +b char(1) character set latin1 collate latin1_swedish_ci, +c char(1) character set latin1 collate latin1_danish_ci +); +insert into t1 values ('A','B','C'); +insert into t1 values ('a','c','c'); +--error 1267 +select * from t1 where a in (b); +--error 1270 +select * from t1 where a in (b,c); +--error 1271 +select * from t1 where 'a' in (a,b,c); +select * from t1 where 'a' in (a); +select * from t1 where a in ('a'); +select * from t1 where 'a' collate latin1_general_ci in (a,b,c); +select * from t1 where 'a' collate latin1_bin in (a,b,c); +select * from t1 where 'a' in (a,b,c collate latin1_bin); +explain extended select * from t1 where 'a' in (a,b,c collate latin1_bin); +drop table t1; + +set names utf8; +create table t1 (a char(10) character set utf8 not null); +insert into t1 values ('bbbb'),(_koi8r'ÃÃÃÃ'),(_latin1'ÄÄÄÄ'); +select a from t1 where a in ('bbbb',_koi8r'ÃÃÃÃ',_latin1'ÄÄÄÄ') order by a; +drop table t1; +# Bug#7834 Illegal mix of collations in IN operator +create table t1 (a char(10) character set latin1 not null); +insert into t1 values ('a'),('b'),('c'); +select a from t1 where a IN ('a','b','c') order by a; +drop table t1; +set names latin1; + +select '1.0' in (1,2); +select 1 in ('1.0',2); +select 1 in (1,'2.0'); +select 1 in ('1.0',2.0); +select 1 in (1.0,'2.0'); +select 1 in ('1.1',2); +select 1 in ('1.1',2.0); + +# Test case for bug #6365 + +create table t1 (a char(2) character set binary); +insert into t1 values ('aa'), ('bb'); +select * from t1 where a in (NULL, 'aa'); +drop table t1; + +# BUG#13419 +create table t1 (id int, key(id)); +insert into t1 values (1),(2),(3); +select count(*) from t1 where id not in (1); +select count(*) from t1 where id not in (1,2); +drop table t1; + + +# +# BUG#17047: CHAR() and IN() can return NULL without signaling NULL +# result +# +# The problem was in the IN() function that ignored maybe_null flags +# of all arguments except the first (the one _before_ the IN +# keyword, '1' in the test case below). +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 SELECT 1 IN (2, NULL); +--echo SELECT should return NULL. +SELECT * FROM t1; + +DROP TABLE t1; + + +--echo End of 4.1 tests + + +# +# Bug #11885: WHERE condition with NOT IN (one element) +# + +CREATE TABLE t1 (a int PRIMARY KEY); +INSERT INTO t1 VALUES (44), (45), (46); + +SELECT * FROM t1 WHERE a IN (45); +SELECT * FROM t1 WHERE a NOT IN (0, 45); +SELECT * FROM t1 WHERE a NOT IN (45); + +CREATE VIEW v1 AS SELECT * FROM t1 WHERE a NOT IN (45); +SHOW CREATE VIEW v1; +SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; + +# BUG#15872: Excessive memory consumption of range analysis of NOT IN +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, filler char(200), key(a)); + +insert into t2 select C.a*2, 'no' from t1 A, t1 B, t1 C; +insert into t2 select C.a*2+1, 'yes' from t1 C; + +explain +select * from t2 where a NOT IN (0, 2,4,6,8,10,12,14,16,18); +select * from t2 where a NOT IN (0, 2,4,6,8,10,12,14,16,18); + +# PBXT: Number rows in non-determined. (TODO: Why?) +--replace_column 9 # +explain select * from t2 force index(a) where a NOT IN (2,2,2,2,2,2); +# PBXT: Number rows in non-determined. (TODO: Why?) +--replace_column 9 # +explain select * from t2 force index(a) where a <> 2; + +drop table t2; + +# +# Repeat the test for DATETIME +# +create table t2 (a datetime, filler char(200), key(a)); + +insert into t2 select '2006-04-25 10:00:00' + interval C.a minute, + 'no' from t1 A, t1 B, t1 C where C.a % 2 = 0; + +insert into t2 select '2006-04-25 10:00:00' + interval C.a*2+1 minute, + 'yes' from t1 C; + +explain +select * from t2 where a NOT IN ( + '2006-04-25 10:00:00','2006-04-25 10:02:00','2006-04-25 10:04:00', + '2006-04-25 10:06:00', '2006-04-25 10:08:00'); +select * from t2 where a NOT IN ( + '2006-04-25 10:00:00','2006-04-25 10:02:00','2006-04-25 10:04:00', + '2006-04-25 10:06:00', '2006-04-25 10:08:00'); +drop table t2; + +# +# Repeat the test for CHAR(N) +# +create table t2 (a varchar(10), filler char(200), key(a)); + +insert into t2 select 'foo', 'no' from t1 A, t1 B; +insert into t2 select 'barbar', 'no' from t1 A, t1 B; +insert into t2 select 'bazbazbaz', 'no' from t1 A, t1 B; + +insert into t2 values ('fon', '1'), ('fop','1'), ('barbaq','1'), + ('barbas','1'), ('bazbazbay', '1'),('zz','1'); + + +# PBXT: wait for sweeper +analyze table t2; + +explain select * from t2 where a not in('foo','barbar', 'bazbazbaz'); + +drop table t2; + +# +# Repeat for DECIMAL +# +create table t2 (a decimal(10,5), filler char(200), key(a)); + +insert into t2 select 345.67890, 'no' from t1 A, t1 B; +insert into t2 select 43245.34, 'no' from t1 A, t1 B; +insert into t2 select 64224.56344, 'no' from t1 A, t1 B; + +insert into t2 values (0, '1'), (22334.123,'1'), (33333,'1'), + (55555,'1'), (77777, '1'); + +# PBXT: wait for sweeper +analyze table t2; + +explain +select * from t2 where a not in (345.67890, 43245.34, 64224.56344); +select * from t2 where a not in (345.67890, 43245.34, 64224.56344); + +drop table t2; + +# Try a very big IN-list +create table t2 (a int, key(a), b int); +insert into t2 values (1,1),(2,2); + +set @cnt= 1; +set @str="update t2 set b=1 where a not in ("; +select count(*) from ( + select @str:=concat(@str, @cnt:=@cnt+1, ",") + from t1 A, t1 B, t1 C, t1 D) Z; + +set @str:=concat(@str, "10000)"); +select substr(@str, 1, 50); +prepare s from @str; +execute s; +deallocate prepare s; +set @str=NULL; + +drop table t2; +drop table t1; + +# BUG#19618: Crash in range optimizer for +# "unsigned_keypart NOT IN(negative_number,...)" +# (introduced in fix BUG#15872) +create table t1 ( + some_id smallint(5) unsigned, + key (some_id) +); +insert into t1 values (1),(2); +select some_id from t1 where some_id not in(2,-1); +select some_id from t1 where some_id not in(-4,-1,-4); +select some_id from t1 where some_id not in(-4,-1,3423534,2342342); + +# +# BUG#24261: crash when WHERE contains NOT IN ('<negative value>') for unsigned column type +# + +select some_id from t1 where some_id not in('-1', '0'); + +drop table t1; + + +--echo End of 5.0 tests + + +# +# Bug#18360: Type aggregation for IN and CASE may lead to a wrong result +# +create table t1(f1 char(1)); +insert into t1 values ('a'),('b'),('1'); +select f1 from t1 where f1 in ('a',1); +select f1, case f1 when 'a' then '+' when 1 then '-' end from t1; +create index t1f1_idx on t1(f1); +select f1 from t1 where f1 in ('a',1); +explain select f1 from t1 where f1 in ('a',1); +select f1 from t1 where f1 in ('a','b'); +explain select f1 from t1 where f1 in ('a','b'); +select f1 from t1 where f1 in (2,1); +explain select f1 from t1 where f1 in (2,1); +create table t2(f2 int, index t2f2(f2)); +insert into t2 values(0),(1),(2); +select f2 from t2 where f2 in ('a',2); +explain select f2 from t2 where f2 in ('a',2); +select f2 from t2 where f2 in ('a','b'); +explain select f2 from t2 where f2 in ('a','b'); +select f2 from t2 where f2 in (1,'b'); +explain select f2 from t2 where f2 in (1,'b'); +drop table t1, t2; + + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.1 tests diff --git a/mysql-test/suite/pbxt/t/func_isnull.test b/mysql-test/suite/pbxt/t/func_isnull.test new file mode 100644 index 00000000000..68077a4b0f2 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_isnull.test @@ -0,0 +1,18 @@ +# +# test of ISNULL() +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (id int auto_increment primary key not null, mydate date not null); +insert into t1 values (0,"2002-05-01"),(0,"2002-05-01"),(0,"2002-05-01"); +flush tables; +select * from t1 where isnull(to_days(mydate)); +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_like.test b/mysql-test/suite/pbxt/t/func_like.test new file mode 100644 index 00000000000..fbddb202a2b --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_like.test @@ -0,0 +1,119 @@ +# +# Test of like +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a varchar(10), key(a)); +insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test"); +explain extended select * from t1 where a like 'abc%'; +explain extended select * from t1 where a like concat('abc','%'); +select * from t1 where a like "abc%"; +select * from t1 where a like concat("abc","%"); +select * from t1 where a like "ABC%"; +select * from t1 where a like "test%"; +select * from t1 where a like "te_t"; + +# +# The following will test the Turbo Boyer-Moore code +# +select * from t1 where a like "%a%"; +select * from t1 where a like "%abcd%"; +select * from t1 where a like "%abc\d%"; + +drop table t1; + +create table t1 (a varchar(10), key(a)); + +# +# Bug #2231 +# +insert into t1 values ('a'), ('a\\b'); +select * from t1 where a like 'a\\%' escape '#'; +select * from t1 where a like 'a\\%' escape '#' and a like 'a\\\\b'; + +# +# Bug #4200: Prepared statement parameter as argument to ESCAPE +# +prepare stmt1 from 'select * from t1 where a like \'a\\%\' escape ?'; +set @esc='#'; +execute stmt1 using @esc; +deallocate prepare stmt1; + +drop table t1; + +# +# Bug #2885: like and datetime +# + +create table t1 (a datetime); +insert into t1 values ('2004-03-11 12:00:21'); +select * from t1 where a like '2004-03-11 12:00:21'; +drop table t1; + +# +# Test like with non-default character set +# + +SET NAMES koi8r; + +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET koi8r); + +INSERT INTO t1 VALUES ('ÆÙ×Á'),('æÙ×Á'),('Æù×Á'),('ÆÙ÷Á'),('ÆÙ×á'),('æù÷á'); +INSERT INTO t1 VALUES ('ÆÙ×ÁÐÒÏÌÄÖ'),('æÙ×ÁÐÒÏÌÄÖ'),('Æù×ÁÐÒÏÌÄÖ'),('ÆÙ÷ÁÐÒÏÌÄÖ'); +INSERT INTO t1 VALUES ('ÆÙ×áÐÒÏÌÄÖ'),('ÆÙ×ÁðÒÏÌÄÖ'),('ÆÙ×ÁÐòÏÌÄÖ'),('ÆÙ×ÁÐÒïÌÄÖ'); +INSERT INTO t1 VALUES ('ÆÙ×ÁÐÒÏìÄÖ'),('ÆÙ×ÁÐÒÏÌäÖ'),('ÆÙ×ÁÐÒÏÌÄö'),('æù÷áðòïìäö'); + +SELECT * FROM t1 WHERE a LIKE '%Æù×Á%'; +SELECT * FROM t1 WHERE a LIKE '%Æù×%'; +SELECT * FROM t1 WHERE a LIKE 'Æù×Á%'; + +DROP TABLE t1; + +# Bug #2547 Strange "like" behaviour in tables with default charset=cp1250 +# Test like with non-default character set using TurboBM +# +SET NAMES cp1250; +CREATE TABLE t1 (a varchar(250) NOT NULL) DEFAULT CHARACTER SET=cp1250; +INSERT INTO t1 VALUES +('Techni Tapes Sp. z o.o.'), +('Pojazdy Szynowe PESA Bydgoszcz SA Holding'), +('AKAPESTER 1 P.P.H.U.'), +('Pojazdy Szynowe PESA Bydgoszcz S A Holding'), +('PPUH PESKA-I Maria Struniarska'); + +select * from t1 where a like '%PESA%'; +select * from t1 where a like '%PESA %'; +select * from t1 where a like '%PES%'; +select * from t1 where a like '%PESKA%'; +select * from t1 where a like '%ESKA%'; +DROP TABLE t1; + +# +# LIKE crashed for binary collations in some cases +# +select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; + +# +# Check 8bit escape character +# +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; + +# Check 8bit escape character with charset conversion: +# For "a LIKE b ESCAPE c" expressions, +# escape character is converted into the operation character set, +# which is result of aggregation of character sets of "a" and "b". +# "c" itself doesn't take part in aggregation, because its collation +# doesn't matter, escape character is always compared binary. +# In the example below, escape character is converted from koi8r into cp1251: +# +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; + +--disable_query_log +drop database pbxt; +--enable_query_log +# +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_math.test b/mysql-test/suite/pbxt/t/func_math.test new file mode 100644 index 00000000000..54d6e185409 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_math.test @@ -0,0 +1,202 @@ +# +# Test of math functions +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +select floor(5.5),floor(-5.5); +explain extended select floor(5.5),floor(-5.5); +select ceiling(5.5),ceiling(-5.5); +explain extended select ceiling(5.5),ceiling(-5.5); +select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2), truncate(-52.64,1),truncate(-52.64,-1); +explain extended select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2), truncate(-52.64,1),truncate(-52.64,-1); +select round(5.5),round(-5.5); +explain extended select round(5.5),round(-5.5); +select round(5.64,1),round(5.64,2),round(5.64,-1),round(5.64,-2); +select abs(-10), sign(-5), sign(5), sign(0); +explain extended select abs(-10), sign(-5), sign(5), sign(0); +select log(exp(10)),exp(log(sqrt(10))*2),log(-1),log(NULL),log(1,1),log(3,9),log(-1,2),log(NULL,2); +explain extended select log(exp(10)),exp(log(sqrt(10))*2),log(-1),log(NULL),log(1,1),log(3,9),log(-1,2),log(NULL,2); +select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL); +explain extended select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL); +select log2(8),log2(15),log2(-2),log2(0),log2(NULL); +explain extended select log2(8),log2(15),log2(-2),log2(0),log2(NULL); +select log10(100),log10(18),log10(-4),log10(0),log10(NULL); +explain extended select log10(100),log10(18),log10(-4),log10(0),log10(NULL); +select pow(10,log10(10)),power(2,4); +explain extended select pow(10,log10(10)),power(2,4); +set @@rand_seed1=10000000,@@rand_seed2=1000000; +select rand(999999),rand(); +explain extended select rand(999999),rand(); +select pi(),format(sin(pi()/2),6),format(cos(pi()/2),6),format(abs(tan(pi())),6),format(cot(1),6),format(asin(1),6),format(acos(0),6),format(atan(1),6); +explain extended select pi(),format(sin(pi()/2),6),format(cos(pi()/2),6),format(abs(tan(pi())),6),format(cot(1),6),format(asin(1),6),format(acos(0),6),format(atan(1),6); +select degrees(pi()),radians(360); + +select format(atan(-2, 2), 6); +select format(atan(pi(), 0), 6); +select format(atan2(-2, 2), 6); +select format(atan2(pi(), 0), 6); + +# +# Bug #2338 Trignometric arithmatic problems +# + +SELECT ACOS(1.0); +SELECT ASIN(1.0); +SELECT ACOS(0.2*5.0); +SELECT ACOS(0.5*2.0); +SELECT ASIN(0.8+0.2); +SELECT ASIN(1.2-0.2); + +# +# Bug #3051 FLOOR returns invalid +# + +# This can't be tested as it's not portable +#select floor(log(4)/log(2)); +#select floor(log(8)/log(2)); +#select floor(log(16)/log(2)); + +# +# Bug #9060 (format returns incorrect result) +# +select format(4.55, 1), format(4.551, 1); + +explain extended select degrees(pi()),radians(360); + +# +# Bug #7281: problem with rand() +# + +--error 1054 +select rand(rand); + +# End of 4.1 tests + +# +# Bug #8459 (FORMAT returns incorrect result) +# +create table t1 (col1 int, col2 decimal(60,30)); +insert into t1 values(1,1234567890.12345); +select format(col2,7) from t1; +select format(col2,8) from t1; +insert into t1 values(7,1234567890123456.12345); +select format(col2,6) from t1 where col1=7; +drop table t1; + + +# +# Bug #10083 (round doesn't increase decimals) +# +select round(150, 2); + +# +# Bug @10632 (Ceiling function returns wrong answer) +# +select ceil(0.09); +select ceil(0.000000000000000009); + +# +# Bug #9837: problem with round() +# + +create table t1 select round(1, 6); +show create table t1; +select * from t1; +drop table t1; + +# +# Bug #11402: abs() forces rest of calculation to unsigned +# +select abs(-2) * -2; + +# +# Bug #6172 RAND(a) should only accept constant values as arguments +# +CREATE TABLE t1 (a INT); + +INSERT INTO t1 VALUES (1),(1),(1),(2); +SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(a) * 1000 AS UNSIGNED) + FROM t1; +SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(a) * 1000 AS UNSIGNED) + FROM t1 WHERE a = 1; +INSERT INTO t1 VALUES (3); +SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(a) * 1000 AS UNSIGNED) + FROM t1; +SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(a) * 1000 AS UNSIGNED) + FROM t1 WHERE a = 1; +PREPARE stmt FROM + "SELECT CAST(RAND(2) * 1000 AS UNSIGNED), CAST(RAND(?) * 1000 AS UNSIGNED) + FROM t1 WHERE a = 1"; +set @var=2; +EXECUTE stmt USING @var; + +DROP TABLE t1; + +# +# Bug #14009: use of abs() on null value causes problems with filesort +# +# InnoDB is required to reproduce the fault, but it is okay if we default to +# MyISAM when testing. +--disable_warnings +create table t1 (a varchar(90), ts datetime not null, index (a)) engine=innodb default charset=utf8; +--enable_warnings +insert into t1 values ('http://www.foo.com/', now()); +select a from t1 where a='http://www.foo.com/' order by abs(timediff(ts, 0)); +drop table t1; + +# End of 4.1 tests + +# +# Bug #13820 (No warning on log(negative) +# +set sql_mode='traditional'; +select ln(-1); +select log10(-1); +select log2(-1); +select log(2,-1); +select log(-2,1); +set sql_mode=''; + +# +# Bug #8461 truncate() and round() return false results 2nd argument negative. +# +# round(a,-b) log_10(b) > a +select round(111,-10); +# round on bigint +select round(-5000111000111000155,-1); +# round on unsigned bigint +select round(15000111000111000155,-1); +# truncate on bigint +select truncate(-5000111000111000155,-1); +# truncate on unsigned bigint +select truncate(15000111000111000155,-1); + +# +# Bug#16678 FORMAT gives wrong result if client run with default-character-set=utf8 +# +set names utf8; +create table t1 +(f1 varchar(32) not null, + f2 smallint(5) unsigned not null, + f3 int(10) unsigned not null default '0') +engine=myisam default charset=utf8; +insert into t1 values ('zombie',0,0),('gold',1,10000),('silver',2,10000); + +create table t2 +(f1 int(10) unsigned not null, + f2 int(10) unsigned not null, + f3 smallint(5) unsigned not null) +engine=myisam default charset=utf8; +insert into t2 values (16777216,16787215,1),(33554432,33564431,2); + +select format(t2.f2-t2.f1+1,0) from t1,t2 +where t1.f2 = t2.f3 order by t1.f1; +drop table t1, t2; +set names default; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/func_misc.test b/mysql-test/suite/pbxt/t/func_misc.test new file mode 100644 index 00000000000..cafd272bd7f --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_misc.test @@ -0,0 +1,138 @@ +# +# Testing of misc functions +# + +select format(1.5555,0),format(123.5555,1),format(1234.5555,2),format(12345.55555,3),format(123456.5555,4),format(1234567.5555,5),format("12345.2399",2); + +select inet_ntoa(inet_aton("255.255.255.255.255.255.255.255")); +select inet_aton("255.255.255.255.255"),inet_aton("255.255.1.255"),inet_aton("0.1.255"); +select inet_ntoa(1099511627775),inet_ntoa(4294902271),inet_ntoa(511); + +select hex(inet_aton('127')); +select hex(inet_aton('127.1')); +select hex(inet_aton('127.1.1')); + +select length(uuid()), charset(uuid()), length(unhex(replace(uuid(),_utf8'-',_utf8''))); + +# +# Test for core dump with nan +# +select length(format('nan', 2)) > 0; + +# +# Test for bug #628 +# +select concat("$",format(2500,2)); + +# Test for BUG#7716 +create table t1 ( a timestamp ); +insert into t1 values ( '2004-01-06 12:34' ); +select a from t1 where left(a+0,6) in ( left(20040106,6) ); +select a from t1 where left(a+0,6) = ( left(20040106,6) ); + +select a from t1 where right(a+0,6) in ( right(20040106123400,6) ); +select a from t1 where right(a+0,6) = ( right(20040106123400,6) ); + +select a from t1 where mid(a+0,6,3) in ( mid(20040106123400,6,3) ); +select a from t1 where mid(a+0,6,3) = ( mid(20040106123400,6,3) ); + +drop table t1; + + +# +# Bug#16501: IS_USED_LOCK does not appear to work +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (conn CHAR(7), connection_id INT); +INSERT INTO t1 VALUES ('default', CONNECTION_ID()); + +SELECT GET_LOCK('bug16501',600); + +connect (con1,localhost,root,,); +INSERT INTO t1 VALUES ('con1', CONNECTION_ID()); +SELECT IS_USED_LOCK('bug16501') = connection_id +FROM t1 +WHERE conn = 'default'; +send SELECT GET_LOCK('bug16501',600); + +connection default; +SELECT IS_USED_LOCK('bug16501') = CONNECTION_ID(); +SELECT RELEASE_LOCK('bug16501'); +connection con1; +reap; +connection default; +SELECT IS_USED_LOCK('bug16501') = connection_id +FROM t1 +WHERE conn = 'con1'; + +connection con1; +SELECT IS_USED_LOCK('bug16501') = CONNECTION_ID(); +SELECT RELEASE_LOCK('bug16501'); +SELECT IS_USED_LOCK('bug16501'); + +disconnect con1; +connection default; + +DROP TABLE t1; + +# +# Bug #21531: EXPORT_SET() doesn't accept args with coercible character sets +# +select export_set(3, _latin1'foo', _utf8'bar', ',', 4); + +--echo End of 4.1 tests + + +# +# Test for BUG#9535 +# +create table t1 as select uuid(), length(uuid()); +show create table t1; +drop table t1; + +# +# Bug #6760: Add SLEEP() function +# +create table t1 (a timestamp default '2005-05-05 01:01:01', + b timestamp default '2005-05-05 01:01:01'); +insert into t1 set a = now(); +select sleep(3); +update t1 set b = now(); +select timediff(b, a) >= '00:00:03' from t1; +drop table t1; + +# +# Bug #12689: SLEEP() gets incorrectly cached/optimized-away +# +set global query_cache_size=1355776; +create table t1 (a int); +insert into t1 values (1),(1),(1); +create table t2 (a datetime default null, b datetime default null); +insert into t2 set a = now(); +select a from t1 where sleep(1); +update t2 set b = now() where b is null; +insert into t2 set a = now(); +select a from t1 where sleep(a); +update t2 set b = now() where b is null; +insert into t2 set a = now(); +select a from t1 where sleep(1); +update t2 set b = now() where b is null; +select timediff(b, a) >= '00:00:03' from t2; +drop table t2; +drop table t1; +set global query_cache_size=default; + +# +# Bug #21466: INET_ATON() returns signed, not unsigned +# + +create table t1 select INET_ATON('255.255.0.1') as `a`; +show create table t1; +drop table t1; +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/func_op.test b/mysql-test/suite/pbxt/t/func_op.test new file mode 100644 index 00000000000..5ac127ad25f --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_op.test @@ -0,0 +1,37 @@ +# Description +# ----------- +# Simple operands and arithmetic grouping + +select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; +explain extended select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; +select 1 | (1+1),5 & 3,bit_count(7) ; +explain extended select 1 | (1+1),5 & 3,bit_count(7) ; +select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60; +# +# bug #1993: bit functions must be unsigned +# +select -1 | 0, -1 ^ 0, -1 & 0; +select -1 | 1, -1 ^ 1, -1 & 1; +select 1 | -1, 1 ^ -1, 1 & -1; +select 0 | -1, 0 ^ -1, 0 & -1; +select -1 >> 0, -1 << 0; +select -1 >> 1, -1 << 1; + +# +# Bug 13044: wrong bit_count() results +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +create table t1(a int); +create table t2(a int, b int); +insert into t1 values (1), (2), (3); +insert into t2 values (1, 7), (3, 7); +select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; +drop table t1, t2; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_regexp.test b/mysql-test/suite/pbxt/t/func_regexp.test new file mode 100644 index 00000000000..02b13405ab5 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_regexp.test @@ -0,0 +1,80 @@ +# +# Some regexp tests +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (s1 char(64),s2 char(64)); + +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); + +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); + +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); + +select HIGH_PRIORITY s1 regexp s2 from t1; + +drop table t1; + +# +# This test a bug in regexp on Alpha +# + +create table t1 (xxx char(128)); +insert into t1 (xxx) values('this is a test of some long text to see what happens'); +select * from t1 where xxx regexp('is a test of some long text to'); +explain extended select * from t1 where xxx regexp('is a test of some long text to'); +select * from t1 where xxx regexp('is a test of some long text to '); +select * from t1 where xxx regexp('is a test of some long text to s'); +select * from t1 where xxx regexp('is a test of some long text to se'); +drop table t1; + +create table t1 (xxx char(128)); +insert into t1 (xxx) values('this is some text: to test - out.reg exp (22/45)'); +select * from t1 where xxx REGEXP '^this is some text: to test - out\\.reg exp [[(][0-9]+[/\\][0-9]+[])][ ]*$'; +drop table t1; + +# +# Check with different character sets and collations +# +select _latin1 0xFF regexp _latin1 '[[:lower:]]' COLLATE latin1_bin; +select _koi8r 0xFF regexp _koi8r '[[:lower:]]' COLLATE koi8r_bin; +select _latin1 0xFF regexp _latin1 '[[:upper:]]' COLLATE latin1_bin; +select _koi8r 0xFF regexp _koi8r '[[:upper:]]' COLLATE koi8r_bin; + +select _latin1 0xF7 regexp _latin1 '[[:alpha:]]'; +select _koi8r 0xF7 regexp _koi8r '[[:alpha:]]'; + +select _latin1'a' regexp _latin1'A' collate latin1_general_ci; +select _latin1'a' regexp _latin1'A' collate latin1_bin; + +# +# regexp cleanup() +# +create table t1 (a varchar(40)); +insert into t1 values ('C1'),('C2'),('R1'),('C3'),('R2'),('R3'); +prepare stmt1 from 'select a from t1 where a rlike ? order by a'; +set @a="^C.*"; +execute stmt1 using @a; +set @a="^R.*"; +execute stmt1 using @a; +deallocate prepare stmt1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_sapdb.test b/mysql-test/suite/pbxt/t/func_sapdb.test new file mode 100644 index 00000000000..d8ef28317ba --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_sapdb.test @@ -0,0 +1,137 @@ +--disable_warnings +drop table if exists t1, test; +--enable_warnings + + +# +# time functions +# +select extract(DAY_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select extract(HOUR_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select extract(MINUTE_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select extract(SECOND_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select extract(MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select date_format("1997-12-31 23:59:59.000002", "%f"); + +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000 99:99:99.999999" DAY_MICROSECOND); +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99:99.999999" HOUR_MICROSECOND); +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99.999999" MINUTE_MICROSECOND); +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000.999999" SECOND_MICROSECOND); +select date_add("1997-12-31 23:59:59.000002",INTERVAL "999999" MICROSECOND); + +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1 1:1:1.000002" DAY_MICROSECOND); +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1:1.000002" HOUR_MICROSECOND); +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1.000002" MINUTE_MICROSECOND); +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1.000002" SECOND_MICROSECOND); +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "000002" MICROSECOND); + +#Date functions +select adddate("1997-12-31 23:59:59.000001", 10); +select subdate("1997-12-31 23:59:59.000001", 10); + +select datediff("1997-12-31 23:59:59.000001","1997-12-30"); +select datediff("1997-11-30 23:59:59.000001","1997-12-31"); +SET @@SQL_MODE="ALLOW_INVALID_DATES"; +select datediff("1997-11-31 23:59:59.000001","1997-12-31"); +SET @@SQL_MODE=""; + +# This will give a warning +select datediff("1997-11-31 23:59:59.000001","1997-12-31"); +select datediff("1997-11-30 23:59:59.000001",null); + +select weekofyear("1997-11-30 23:59:59.000001"); + +select makedate(1997,1); +select makedate(1997,0); +select makedate(9999,365); +select makedate(9999,366); + +#Time functions + +select addtime("1997-12-31 23:59:59.999999", "1 1:1:1.000002"); +select subtime("1997-12-31 23:59:59.000001", "1 1:1:1.000002"); +select addtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); +select subtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); +select subtime("01:00:00.999999", "02:00:00.999998"); +select subtime("02:01:01.999999", "01:01:01.999999"); + +# PS doesn't support fractional seconds +--disable_ps_protocol +select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); +select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); +select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); +select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); +select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); +select timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50"); +--enable_ps_protocol + +select maketime(10,11,12); +select maketime(25,11,12); +select maketime(-25,11,12); + +# Extraction functions + +# PS doesn't support fractional seconds +--disable_ps_protocol +select timestamp("2001-12-01", "01:01:01.999999"); +select timestamp("2001-13-01", "01:01:01.000001"); +select timestamp("2001-12-01", "25:01:01"); +select timestamp("2001-12-01 01:01:01.000100"); +select timestamp("2001-12-01"); +select day("1997-12-31 23:59:59.000001"); +select date("1997-12-31 23:59:59.000001"); +select date("1997-13-31 23:59:59.000001"); +select time("1997-12-31 23:59:59.000001"); +select time("1997-12-31 25:59:59.000001"); +select microsecond("1997-12-31 23:59:59.000001"); +--enable_ps_protocol + +create table t1 +select makedate(1997,1) as f1, + addtime(cast("1997-12-31 23:59:59.000001" as datetime), "1 1:1:1.000002") as f2, + addtime(cast("23:59:59.999999" as time) , "1 1:1:1.000002") as f3, + timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") as f4, + timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") as f5, + maketime(10,11,12) as f6, + timestamp(cast("2001-12-01" as date), "01:01:01") as f7, + date("1997-12-31 23:59:59.000001") as f8, + time("1997-12-31 23:59:59.000001") as f9; +describe t1; +# PS doesn't support fractional seconds +--disable_ps_protocol +select * from t1; +--enable_ps_protocol + +create table test(t1 datetime, t2 time, t3 time, t4 datetime); +insert into test values +('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'), +('2001-01-01 01:01:01', '-01:01:01', '-23:59:59', "1997-12-31 23:59:59.000001"), +('1997-12-31 23:59:59.000001', '-23:59:59', '-01:01:01', '2001-01-01 01:01:01'), +('2001-01-01 01:01:01', '01:01:01', '-1 01:01:01', null), +('2001-01-01 01:01:01', '-01:01:01', '1 01:01:01', '2001-01-01 01:01:01'), +('2001-01-01 01:01:01', null, '-1 01:01:01', null), +(null, null, null, null), +('2001-01-01 01:01:01', '01:01:01', '1 01:01:01', '2001-01-01 01:01:01'); + +SELECT ADDTIME(t1,t2) As ttt, ADDTIME(t2, t3) As qqq from test; +# PS doesn't support fractional seconds +--disable_ps_protocol +SELECT TIMEDIFF(t1, t4) As ttt, TIMEDIFF(t2, t3) As qqq, + TIMEDIFF(t3, t2) As eee, TIMEDIFF(t2, t4) As rrr from test; +--enable_ps_protocol + +drop table t1, test; + +select addtime("-01:01:01.01", "-23:59:59.1") as a; +select microsecond("1997-12-31 23:59:59.01") as a; +select microsecond(19971231235959.01) as a; +select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a; +# PS doesn't support fractional seconds +--disable_ps_protocol +select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f"); +--enable_ps_protocol + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_set.test b/mysql-test/suite/pbxt/t/func_set.test new file mode 100644 index 00000000000..d89551a8a2f --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_set.test @@ -0,0 +1,60 @@ +# +# Testing if SET and similar functions +# + +select interval(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0; +explain extended select INTERVAL(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0; +# Test 8 and 9 values (Bug #1561) +SELECT INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56); +SELECT INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56, 77); + +select find_in_set("b","a,b,c"),find_in_set("c","a,b,c"),find_in_set("dd","a,bbb,dd"),find_in_set("bbb","a,bbb,dd"); +select find_in_set("d","a,b,c"),find_in_set("dd","a,bbb,d"),find_in_set("bb","a,bbb,dd"); +select make_set(0,'a','b','c'),make_set(-1,'a','b','c'),make_set(1,'a','b','c'),make_set(2,'a','b','c'),make_set(1+2,concat('a','b'),'c'); +select make_set(NULL,'a','b','c'),make_set(1|4,'a',NULL,'c'),make_set(1+2,'a',NULL,'c'); +select export_set(9,"Y","N","-",5),export_set(9,"Y","N"),export_set(9,"Y","N",""); + +# +# Wrong usage of functions +# +select elt(2,1),field(NULL,"a","b","c"); +select field("b","a",NULL),field(1,0,NULL)+0,field(1.0,0.0,NULL)+0.0,field(1.0e1,0.0e1,NULL)+0.0e1; +select field(NULL,"a",NULL),field(NULL,0,NULL)+0,field(NULL,0.0,NULL)+0.0,field(NULL,0.0e1,NULL)+0.0e1; +select find_in_set("","a,b,c"),find_in_set("","a,b,c,"),find_in_set("",",a,b,c"); +select find_in_set("abc","abc"),find_in_set("ab","abc"),find_in_set("abcd","abc"); +select interval(null, 1, 10, 100); + +# +# test for a bug with elt() +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1 (id int(10) not null unique); +create table t2 (id int(10) not null primary key, val int(10) not null); +insert into t1 values (1),(2),(4); +insert into t2 values (1,1),(2,1),(3,1),(4,2); + +select one.id, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id; +select one.id, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id order by one.id; +drop table t1,t2; + +# +# Bug4340: find_in_set is case insensitive even on binary operators +# + +select find_in_set(binary 'a',binary 'A,B,C'); +select find_in_set('a',binary 'A,B,C'); +select find_in_set(binary 'a', 'A,B,C'); + +# +# Bug5513:FIND_IN_SET fails if set ends with a comma +# +select find_in_set('1','3,1,'); + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_str.test b/mysql-test/suite/pbxt/t/func_str.test new file mode 100644 index 00000000000..8f516e6c4d9 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_str.test @@ -0,0 +1,1113 @@ +# Description +# ----------- +# Testing string functions + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +set names latin1; + +select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; +select 'hello' 'monty'; +select length('\n\t\r\b\0\_\%\\'); +select bit_length('\n\t\r\b\0\_\%\\'); +select char_length('\n\t\r\b\0\_\%\\'); +select length(_latin1'\n\t\n\b\0\\_\\%\\'); +select concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'); +select hex(char(256)); +select locate('he','hello'),locate('he','hello',2),locate('lo','hello',2) ; +select instr('hello','HE'), instr('hello',binary 'HE'), instr(binary 'hello','HE'); +select position(binary 'll' in 'hello'),position('a' in binary 'hello'); +# +# Bug#11728 string function LEFT, +# strange undocumented behaviour, strict mode +# +select left('hello',null), right('hello',null); +select left('hello',2),right('hello',2),substring('hello',2,2),mid('hello',1,5) ; +select concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',substring('monty',5,1)) ; +select substring_index('www.tcx.se','.',-2),substring_index('www.tcx.se','.',1); +select substring_index('www.tcx.se','tcx',1),substring_index('www.tcx.se','tcx',-1); +select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1); +select substring_index('aaaaaaaaa1','a',1); +select substring_index('aaaaaaaaa1','aa',1); +select substring_index('aaaaaaaaa1','aa',2); +select substring_index('aaaaaaaaa1','aa',3); +select substring_index('aaaaaaaaa1','aa',4); +select substring_index('aaaaaaaaa1','aa',5); +select substring_index('aaaaaaaaa1','aaa',1); +select substring_index('aaaaaaaaa1','aaa',2); +select substring_index('aaaaaaaaa1','aaa',3); +select substring_index('aaaaaaaaa1','aaa',4); +select substring_index('aaaaaaaaa1','aaaa',1); +select substring_index('aaaaaaaaa1','aaaa',2); +select substring_index('aaaaaaaaa1','1',1); +select substring_index('aaaaaaaaa1','a',-1); +select substring_index('aaaaaaaaa1','aa',-1); +select substring_index('aaaaaaaaa1','aa',-2); +select substring_index('aaaaaaaaa1','aa',-3); +select substring_index('aaaaaaaaa1','aa',-4); +select substring_index('aaaaaaaaa1','aa',-5); +select substring_index('aaaaaaaaa1','aaa',-1); +select substring_index('aaaaaaaaa1','aaa',-2); +select substring_index('aaaaaaaaa1','aaa',-3); +select substring_index('aaaaaaaaa1','aaa',-4); +select substring_index('the king of thethe hill','the',-2); +select substring_index('the king of the the hill','the',-2); +select substring_index('the king of the the hill','the',-2); +select substring_index('the king of the the hill',' the ',-1); +select substring_index('the king of the the hill',' the ',-2); +select substring_index('the king of the the hill',' ',-1); +select substring_index('the king of the the hill',' ',-2); +select substring_index('the king of the the hill',' ',-3); +select substring_index('the king of the the hill',' ',-4); +select substring_index('the king of the the hill',' ',-5); +select substring_index('the king of the.the hill','the',-2); +select substring_index('the king of thethethe.the hill','the',-3); +select substring_index('the king of thethethe.the hill','the',-1); +select substring_index('the king of the the hill','the',1); +select substring_index('the king of the the hill','the',2); +select substring_index('the king of the the hill','the',3); + +select concat(':',ltrim(' left '),':',rtrim(' right '),':'); +select concat(':',trim(leading from ' left '),':',trim(trailing from ' right '),':'); +select concat(':',trim(LEADING FROM ' left'),':',trim(TRAILING FROM ' right '),':'); +select concat(':',trim(' m '),':',trim(BOTH FROM ' y '),':',trim('*' FROM '*s*'),':'); +select concat(':',trim(BOTH 'ab' FROM 'ababmyabab'),':',trim(BOTH '*' FROM '***sql'),':'); +select concat(':',trim(LEADING '.*' FROM '.*my'),':',trim(TRAILING '.*' FROM 'sql.*.*'),':'); +select TRIM("foo" FROM "foo"), TRIM("foo" FROM "foook"), TRIM("foo" FROM "okfoo"); + +select concat_ws(', ','monty','was here','again'); +select concat_ws(NULL,'a'),concat_ws(',',NULL,''); +select concat_ws(',','',NULL,'a'); +SELECT CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"'); + +select insert('txs',2,1,'hi'),insert('is ',4,0,'a'),insert('txxxxt',2,4,'es'); +select replace('aaaa','a','b'),replace('aaaa','aa','b'),replace('aaaa','a','bb'),replace('aaaa','','b'),replace('bbbb','a','c'); +select replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL') ; +select soundex(''),soundex('he'),soundex('hello all folks'),soundex('#3556 in bugdb'); +select 'mood' sounds like 'mud'; +select 'Glazgo' sounds like 'Liverpool'; +select null sounds like 'null'; +select 'null' sounds like null; +select null sounds like null; +select md5('hello'); +select crc32("123"); +select sha('abc'); +select sha1('abc'); +select aes_decrypt(aes_encrypt('abc','1'),'1'); +select aes_decrypt(aes_encrypt('abc','1'),1); +select aes_encrypt(NULL,"a"); +select aes_encrypt("a",NULL); +select aes_decrypt(NULL,"a"); +select aes_decrypt("a",NULL); +select aes_decrypt("a","a"); +select aes_decrypt(aes_encrypt("","a"),"a"); +select repeat('monty',5),concat('*',space(5),'*'); +select reverse('abc'),reverse('abcd'); +select rpad('a',4,'1'),rpad('a',4,'12'),rpad('abcd',3,'12'), rpad(11, 10 , 22), rpad("ab", 10, 22); +select lpad('a',4,'1'),lpad('a',4,'12'),lpad('abcd',3,'12'), lpad(11, 10 , 22); +select rpad(741653838,17,'0'),lpad(741653838,17,'0'); +select rpad('abcd',7,'ab'),lpad('abcd',7,'ab'); +select rpad('abcd',1,'ab'),lpad('abcd',1,'ab'); +select rpad('STRING', 20, CONCAT('p','a','d') ); +select lpad('STRING', 20, CONCAT('p','a','d') ); + +select LEAST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'),GREATEST(NULL,'HARRY','HARRIOT',NULL,'HAROLD'); +select least(1,2,3) | greatest(16,32,8), least(5,4)*1,greatest(-1.0,1.0)*1,least(3,2,1)*1.0,greatest(1,1.1,1.0),least("10",9),greatest("A","B","0"); + +select decode(encode(repeat("a",100000),"monty"),"monty")=repeat("a",100000); +select decode(encode("abcdef","monty"),"monty")="abcdef"; + +select quote('\'\"\\test'); +select quote(concat('abc\'', '\\cba')); +select quote(1/0), quote('\0\Z'); +select length(quote(concat(char(0),"test"))); +select hex(quote(concat(char(224),char(227),char(230),char(231),char(232),char(234),char(235)))); +select unhex(hex("foobar")), hex(unhex("1234567890ABCDEF")), unhex("345678"), unhex(NULL); +select hex(unhex("1")), hex(unhex("12")), hex(unhex("123")), hex(unhex("1234")), hex(unhex("12345")), hex(unhex("123456")); +select length(unhex(md5("abrakadabra"))); + +# +# Bug #6564: QUOTE(NULL +# + +select concat('a', quote(NULL)); + +# +# Wrong usage of functions +# + +select reverse(""); +select insert("aa",100,1,"b"),insert("aa",1,3,"b"),left("aa",-1),substring("a",1,2); +select elt(2,1),field(NULL,"a","b","c"),reverse(""); +select locate("a","b",2),locate("","a",1); +select ltrim("a"),rtrim("a"),trim(BOTH "" from "a"),trim(BOTH " " from "a"); +select concat("1","2")|0,concat("1",".5")+0.0; +select substring_index("www.tcx.se","",3); +select length(repeat("a",100000000)),length(repeat("a",1000*64)); +select position("0" in "baaa" in (1)),position("0" in "1" in (1,2,3)),position("sql" in ("mysql")); +select position(("1" in (1,2,3)) in "01"); +select length(repeat("a",65500)),length(concat(repeat("a",32000),repeat("a",32000))),length(replace("aaaaa","a",concat(repeat("a",10000)))),length(insert(repeat("a",40000),1,30000,repeat("b",50000))); +select length(repeat("a",1000000)),length(concat(repeat("a",32000),repeat("a",32000),repeat("a",32000))),length(replace("aaaaa","a",concat(repeat("a",32000)))),length(insert(repeat("a",48000),1,1000,repeat("a",48000))); + +# +# Problem med concat +# + +create table t1 ( domain char(50) ); +insert into t1 VALUES ("hello.de" ), ("test.de" ); +select domain from t1 where concat('@', trim(leading '.' from concat('.', domain))) = '@hello.de'; +select domain from t1 where concat('@', trim(leading '.' from concat('.', domain))) = '@test.de'; +drop table t1; + +# +# Test bug in concat_ws +# + +CREATE TABLE t1 ( + id int(10) unsigned NOT NULL, + title varchar(255) default NULL, + prio int(10) unsigned default NULL, + category int(10) unsigned default NULL, + program int(10) unsigned default NULL, + bugdesc text, + created datetime default NULL, + modified timestamp NOT NULL, + bugstatus int(10) unsigned default NULL, + submitter int(10) unsigned default NULL +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (1,'Link',1,1,1,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','2001-02-28 08:40:16',20010228084016,0,4); +SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter), '"') FROM t1; +SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugstatus,submitter), '"') FROM t1; +SELECT CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter) FROM t1; +SELECT bugdesc, REPLACE(bugdesc, 'xxxxxxxxxxxxxxxxxxxx', 'bbbbbbbbbbbbbbbbbbbb') from t1 group by bugdesc; +drop table t1; + +# +# Test bug in AES_DECRYPT() when called with wrong argument +# + +CREATE TABLE t1 (id int(11) NOT NULL auto_increment, tmp text NOT NULL, KEY id (id)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 'a545f661efdd1fb66fdee3aab79945bf'); +SELECT 1 FROM t1 WHERE tmp=AES_DECRYPT(tmp,"password"); +DROP TABLE t1; + +CREATE TABLE t1 ( + wid int(10) unsigned NOT NULL auto_increment, + data_podp date default NULL, + status_wnio enum('nowy','podp','real','arch') NOT NULL default 'nowy', + PRIMARY KEY(wid) +); + +INSERT INTO t1 VALUES (8,NULL,'real'); +INSERT INTO t1 VALUES (9,NULL,'nowy'); +SELECT elt(status_wnio,data_podp) FROM t1 GROUP BY wid; +DROP TABLE t1; + +# +# test for #739 + +CREATE TABLE t1 (title text) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('Congress reconvenes in September to debate welfare and adult education'); +INSERT INTO t1 VALUES ('House passes the CAREERS bill'); +SELECT CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) from t1; +DROP TABLE t1; + +# +# test for Bug #2290 "output truncated with ELT when using DISTINCT" +# + +CREATE TABLE t1 (i int, j int); +INSERT INTO t1 VALUES (1,1),(2,2); +SELECT DISTINCT i, ELT(j, '345', '34') FROM t1; +DROP TABLE t1; + +# +# bug #3756: quote and NULL +# + +create table t1(a char(4)); +insert into t1 values ('one'),(NULL),('two'),('four'); +select a, quote(a), isnull(quote(a)), quote(a) is null, ifnull(quote(a), 'n') from t1; +drop table t1; + +# +# Bug #5498: TRIM fails with LEADING or TRAILING if remstr = str +# + +select trim(trailing 'foo' from 'foo'); +select trim(leading 'foo' from 'foo'); + +# +# crashing bug with QUOTE() and LTRIM() or TRIM() fixed +# Bug #7495 +# + +select quote(ltrim(concat(' ', 'a'))); +select quote(trim(concat(' ', 'a'))); + +# Bad results from QUOTE(). Bug #8248 +CREATE TABLE t1 SELECT 1 UNION SELECT 2 UNION SELECT 3; +SELECT QUOTE('A') FROM t1; +DROP TABLE t1; + +# Test collation and coercibility +# + +select 1=_latin1'1'; +select _latin1'1'=1; +select _latin2'1'=1; +select 1=_latin2'1'; +--error 1267 +select _latin1'1'=_latin2'1'; +select row('a','b','c') = row('a','b','c'); +select row('A','b','c') = row('a','b','c'); +select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c'); +select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); +--error 1267 +select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); + +--error 1267 +select concat(_latin1'a',_latin2'a'); +--error 1270 +select concat(_latin1'a',_latin2'a',_latin5'a'); +--error 1271 +select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a'); +--error 1267 +select concat_ws(_latin1'a',_latin2'a'); + +# +# Test FIELD() and collations +# +select FIELD('b','A','B'); +select FIELD('B','A','B'); +select FIELD('b' COLLATE latin1_bin,'A','B'); +select FIELD('b','A' COLLATE latin1_bin,'B'); +--error 1270 +select FIELD(_latin2'b','A','B'); +--error 1270 +select FIELD('b',_latin2'A','B'); +select FIELD('1',_latin2'3','2',1); + +select POSITION(_latin1'B' IN _latin1'abcd'); +select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); +select POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd'); +--error 1267 +select POSITION(_latin1'B' COLLATE latin1_general_ci IN _latin1'abcd' COLLATE latin1_bin); +--error 1267 +select POSITION(_latin1'B' IN _latin2'abcd'); + +select FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'); + +# fix this: +--disable_parsing +select FIND_IN_SET(_latin1'B',_latin1'a,b,c,d' COLLATE latin1_bin); +select FIND_IN_SET(_latin1'B' COLLATE latin1_bin,_latin1'a,b,c,d'); +--enable_parsing + +--error 1267 +select FIND_IN_SET(_latin1'B' COLLATE latin1_general_ci,_latin1'a,b,c,d' COLLATE latin1_bin); +--error 1267 +select FIND_IN_SET(_latin1'B',_latin2'a,b,c,d'); + +select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin1'd',2); + +# fix this: +--disable_parsing +select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_bin,_latin1'd',2); +select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin1'd' COLLATE latin1_bin,2); +--enable_parsing + +--error 1267 +select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin2'd',2); +--error 1267 +select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_general_ci,_latin1'd' COLLATE latin1_bin,2); + +select _latin1'B' between _latin1'a' and _latin1'c'; +select _latin1'B' collate latin1_bin between _latin1'a' and _latin1'c'; +select _latin1'B' between _latin1'a' collate latin1_bin and _latin1'c'; +select _latin1'B' between _latin1'a' and _latin1'c' collate latin1_bin; +--error 1270 +select _latin2'B' between _latin1'a' and _latin1'b'; +--error 1270 +select _latin1'B' between _latin2'a' and _latin1'b'; +--error 1270 +select _latin1'B' between _latin1'a' and _latin2'b'; +--error 1270 +select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b'; + +select _latin1'B' in (_latin1'a',_latin1'b'); +select _latin1'B' collate latin1_bin in (_latin1'a',_latin1'b'); +select _latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b'); +select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin); +--error 1270 +select _latin2'B' in (_latin1'a',_latin1'b'); +--error 1270 +select _latin1'B' in (_latin2'a',_latin1'b'); +--error 1270 +select _latin1'B' in (_latin1'a',_latin2'b'); +--error 1270 +select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b'); +--error 1270 +select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin); + +select collation(bin(130)), coercibility(bin(130)); +select collation(oct(130)), coercibility(oct(130)); +select collation(conv(130,16,10)), coercibility(conv(130,16,10)); +select collation(hex(130)), coercibility(hex(130)); +select collation(char(130)), coercibility(hex(130)); +select collation(format(130,10)), coercibility(format(130,10)); +select collation(lcase(_latin2'a')), coercibility(lcase(_latin2'a')); +select collation(ucase(_latin2'a')), coercibility(ucase(_latin2'a')); +select collation(left(_latin2'a',1)), coercibility(left(_latin2'a',1)); +select collation(right(_latin2'a',1)), coercibility(right(_latin2'a',1)); +select collation(substring(_latin2'a',1,1)), coercibility(substring(_latin2'a',1,1)); +select collation(concat(_latin2'a',_latin2'b')), coercibility(concat(_latin2'a',_latin2'b')); +select collation(lpad(_latin2'a',4,_latin2'b')), coercibility(lpad(_latin2'a',4,_latin2'b')); +select collation(rpad(_latin2'a',4,_latin2'b')), coercibility(rpad(_latin2'a',4,_latin2'b')); +select collation(concat_ws(_latin2'a',_latin2'b')), coercibility(concat_ws(_latin2'a',_latin2'b')); +select collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')), coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c')); +select collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')), coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' ')); +select collation(trim(_latin2' a ')), coercibility(trim(_latin2' a ')); +select collation(ltrim(_latin2' a ')), coercibility(ltrim(_latin2' a ')); +select collation(rtrim(_latin2' a ')), coercibility(rtrim(_latin2' a ')); +select collation(trim(LEADING _latin2' ' FROM _latin2'a')), coercibility(trim(LEADING _latin2'a' FROM _latin2'a')); +select collation(trim(TRAILING _latin2' ' FROM _latin2'a')), coercibility(trim(TRAILING _latin2'a' FROM _latin2'a')); +select collation(trim(BOTH _latin2' ' FROM _latin2'a')), coercibility(trim(BOTH _latin2'a' FROM _latin2'a')); +select collation(repeat(_latin2'a',10)), coercibility(repeat(_latin2'a',10)); +select collation(reverse(_latin2'ab')), coercibility(reverse(_latin2'ab')); +select collation(quote(_latin2'ab')), coercibility(quote(_latin2'ab')); +select collation(soundex(_latin2'ab')), coercibility(soundex(_latin2'ab')); +select collation(substring(_latin2'ab',1)), coercibility(substring(_latin2'ab',1)); +select collation(insert(_latin2'abcd',2,3,_latin2'ef')), coercibility(insert(_latin2'abcd',2,3,_latin2'ef')); +select collation(replace(_latin2'abcd',_latin2'b',_latin2'B')), coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B')); +select collation(encode('abcd','ab')), coercibility(encode('abcd','ab')); + +create table t1 +select + bin(130), + oct(130), + conv(130,16,10), + hex(130), + char(130), + format(130,10), + left(_latin2'a',1), + right(_latin2'a',1), + lcase(_latin2'a'), + ucase(_latin2'a'), + substring(_latin2'a',1,1), + concat(_latin2'a',_latin2'b'), + lpad(_latin2'a',4,_latin2'b'), + rpad(_latin2'a',4,_latin2'b'), + concat_ws(_latin2'a',_latin2'b'), + make_set(255,_latin2'a',_latin2'b',_latin2'c'), + export_set(255,_latin2'y',_latin2'n',_latin2' '), + trim(_latin2' a '), + ltrim(_latin2' a '), + rtrim(_latin2' a '), + trim(LEADING _latin2' ' FROM _latin2' a '), + trim(TRAILING _latin2' ' FROM _latin2' a '), + trim(BOTH _latin2' ' FROM _latin2' a '), + repeat(_latin2'a',10), + reverse(_latin2'ab'), + quote(_latin2'ab'), + soundex(_latin2'ab'), + substring(_latin2'ab',1), + insert(_latin2'abcd',2,3,_latin2'ef'), + replace(_latin2'abcd',_latin2'b',_latin2'B'), + encode('abcd','ab') +; +show create table t1; +drop table t1; + +# +# Bug#9129 +# +create table t1 (a char character set latin2); +insert into t1 values (null); +select charset(a), collation(a), coercibility(a) from t1; +drop table t1; +select charset(null), collation(null), coercibility(null); +# +# Make sure OUTER JOIN is not replaced with a regular joun +# +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (a int, b int); +INSERT INTO t1 VALUES (1,1),(2,2); +INSERT INTO t2 VALUES (2,2),(3,3); +select t1.*,t2.* from t1 left join t2 on (t1.b=t2.b) +where collation(t2.a) = _utf8'binary' order by t1.a,t2.a; +select t1.*,t2.* from t1 left join t2 on (t1.b=t2.b) +where charset(t2.a) = _utf8'binary' order by t1.a,t2.a; +select t1.*,t2.* from t1 left join t2 on (t1.b=t2.b) +where coercibility(t2.a) = 2 order by t1.a,t2.a; +DROP TABLE t1, t2; + +# +# test for SUBSTR +# +select SUBSTR('abcdefg',3,2); +select SUBSTRING('abcdefg',3,2); +select SUBSTR('abcdefg',-3,2) FROM DUAL; +select SUBSTR('abcdefg',-1,5) FROM DUAL; +select SUBSTR('abcdefg',0,0) FROM DUAL; +select SUBSTR('abcdefg',-1,-1) FROM DUAL; +select SUBSTR('abcdefg',1,-1) FROM DUAL; + +# +# Test that fix_fields doesn't follow to upper level (to comparison) +# when an error on a lower level (in concat) has accured: +# +create table t7 (s1 char); +--error 1267 +select * from t7 +where concat(s1 collate latin1_general_ci,s1 collate latin1_swedish_ci) = 'AA'; +drop table t7; + +select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2); + +explain extended select md5('hello'); +explain extended select sha('abc'); +explain extended select sha1('abc'); +explain extended select soundex(''); +explain extended select 'mood' sounds like 'mud'; +explain extended select aes_decrypt(aes_encrypt('abc','1'),'1'); +explain extended select concat('*',space(5),'*'); +explain extended select reverse('abc'); +explain extended select rpad('a',4,'1'); +explain extended select lpad('a',4,'1'); +explain extended select concat_ws(',','',NULL,'a'); +explain extended select make_set(255,_latin2'a', _latin2'b', _latin2'c'); +explain extended select elt(2,1); +explain extended select locate("a","b",2); +explain extended select format(130,10); +explain extended select char(0); +explain extended select conv(130,16,10); +explain extended select hex(130); +explain extended select binary 'HE'; +explain extended select export_set(255,_latin2'y', _latin2'n', _latin2' '); +explain extended select FIELD('b' COLLATE latin1_bin,'A','B'); +explain extended select FIND_IN_SET(_latin1'B', _latin1'a,b,c,d'); +explain extended select collation(conv(130,16,10)); +explain extended select coercibility(conv(130,16,10)); +explain extended select length('\n\t\r\b\0\_\%\\'); +explain extended select bit_length('\n\t\r\b\0\_\%\\'); +explain extended select bit_length('\n\t\r\b\0\_\%\\'); +explain extended select concat('monty',' was here ','again'); +explain extended select length('hello'); +explain extended select char(ascii('h')); +explain extended select ord('h'); +explain extended select quote(1/0); +explain extended select crc32("123"); +explain extended select replace('aaaa','a','b'); +explain extended select insert('txs',2,1,'hi'); +explain extended select left(_latin2'a',1); +explain extended select right(_latin2'a',1); +explain extended select lcase(_latin2'a'); +explain extended select ucase(_latin2'a'); +explain extended select SUBSTR('abcdefg',3,2); +explain extended select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2); +explain extended select trim(_latin2' a '); +explain extended select ltrim(_latin2' a '); +explain extended select rtrim(_latin2' a '); +explain extended select decode(encode(repeat("a",100000),"monty"),"monty"); + +# +# lpad returns incorrect result (Bug #2182) +# + +SELECT lpad(12345, 5, "#"); + +# +# Problem the the CONV() function (Bug #2972) +# + +SELECT conv(71, 10, 36), conv('1Z', 36, 10); +SELECT conv(71, 10, 37), conv('1Z', 37, 10), conv(0,1,10),conv(0,0,10), conv(0,-1,10); + +# +# Bug in SUBSTRING when mixed with CONCAT and ORDER BY (Bug #3089) +# + +create table t1 (id int(1), str varchar(10)) DEFAULT CHARSET=utf8; +insert into t1 values (1,'aaaaaaaaaa'), (2,'bbbbbbbbbb'); +create table t2 (id int(1), str varchar(10)) DEFAULT CHARSET=utf8; +insert into t2 values (1,'cccccccccc'), (2,'dddddddddd'); +select substring(concat(t1.str, t2.str), 1, 15) "name" from t1, t2 +where t2.id=t1.id order by name; +drop table t1, t2; + +# +# Test case for conversion of long string value to integer (Bug #3472) +# + +create table t1 (c1 INT, c2 INT UNSIGNED); +insert into t1 values ('21474836461','21474836461'); +insert into t1 values ('-21474836461','-21474836461'); +show warnings; +select * from t1; +drop table t1; + +# +# Bug #4878: LEFT() in integer/float context +# + +select left(1234, 3) + 0; + +# +# Bug #7101: bug with LEFT() when used as a field in GROUP BY aggregation +# +create table t1 (a int not null primary key, b varchar(40), c datetime); +insert into t1 (a,b,c) values (1,'Tom','2004-12-10 12:13:14'),(2,'ball games','2004-12-10 12:13:14'), (3,'Basil','2004-12-10 12:13:14'), (4,'Dean','2004-12-10 12:13:14'),(5,'Ellis','2004-12-10 12:13:14'), (6,'Serg','2004-12-10 12:13:14'), (7,'Sergei','2004-12-10 12:13:14'),(8,'Georg','2004-12-10 12:13:14'),(9,'Salle','2004-12-10 12:13:14'),(10,'Sinisa','2004-12-10 12:13:14'); +select count(*) as total, left(c,10) as reg from t1 group by reg order by reg desc limit 0,12; +drop table t1; + +# +# Bug#7455 unexpected result: TRIM(<NULL> FROM <whatever>) gives NOT NULL +# According to ANSI if one of the TRIM arguments is NULL, then the result +# must be NULL too. +# +select trim(null from 'kate') as "must_be_null"; +select trim('xyz' from null) as "must_be_null"; +select trim(leading NULL from 'kate') as "must_be_null"; +select trim(trailing NULL from 'xyz') as "must_be_null"; + +# +# Bug #7751 - conversion for a bigint unsigned constant +# + +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + a bigint(20) unsigned default NULL, + PRIMARY KEY (id) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES +('0','16307858876001849059'); + +SELECT CONV('e251273eb74a8ee3', 16, 10); + +EXPLAIN +SELECT id + FROM t1 + WHERE a = 16307858876001849059; + +EXPLAIN + SELECT id + FROM t1 + WHERE a = CONV('e251273eb74a8ee3', 16, 10); + +DROP TABLE t1; + +# +# Bug #6317: string function CHAR, parameter is NULL, wrong result +# +SELECT CHAR(NULL,121,83,81,'76') as my_column; +SELECT CHAR_LENGTH(CHAR(NULL,121,83,81,'76')) as my_column; +# +# Test case for bug #8669: null aes_decrypt result in order by query +# + +CREATE TABLE t1 (id int PRIMARY KEY, str char(255) NOT NULL); +CREATE TABLE t2 (id int NOT NULL UNIQUE); +INSERT INTO t2 VALUES (1),(2); +INSERT INTO t1 VALUES (1, aes_encrypt('foo', 'bar')); +INSERT INTO t1 VALUES (2, 'not valid'); + +SELECT t1.id, aes_decrypt(str, 'bar') FROM t1, t2 WHERE t1.id = t2.id; +SELECT t1.id, aes_decrypt(str, 'bar') FROM t1, t2 WHERE t1.id = t2.id + ORDER BY t1.id; + +DROP TABLE t1, t2; + +# +# Bug #10944: Mishandling of NULL arguments in FIELD() +# +select field(0,NULL,1,0), field("",NULL,"bar",""), field(0.0,NULL,1.0,0.0); +select field(NULL,1,2,NULL), field(NULL,1,2,0); + +# +# Bug #10124: access by integer index with a string key that is not a number +# + +CREATE TABLE t1 (str varchar(20) PRIMARY KEY); +CREATE TABLE t2 (num int primary key); +INSERT INTO t1 VALUES ('notnumber'); +INSERT INTO t2 VALUES (0), (1); + +SELECT * FROM t1, t2 WHERE num=str; +SELECT * FROM t1, t2 WHERE num=substring(str from 1 for 6); + +DROP TABLE t1,t2; + +# +# Bug #11469: NOT NULL optimization wrongly used for arguments of CONCAT_WS +# + +CREATE TABLE t1( + id int(11) NOT NULL auto_increment, + pc int(11) NOT NULL default '0', + title varchar(20) default NULL, + PRIMARY KEY (id) +); + +INSERT INTO t1 VALUES + (1, 0, 'Main'), + (2, 1, 'Toys'), + (3, 1, 'Games'); + +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 + FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id + LEFT JOIN t1 AS t3 ON t2.pc=t3.id; +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 + FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id + LEFT JOIN t1 AS t3 ON t2.pc=t3.id + WHERE CONCAT_WS('->', t3.title, t2.title, t1.title) LIKE '%Toys%'; + +DROP TABLE t1; + + +CREATE TABLE t1( + trackid int(10) unsigned NOT NULL auto_increment, + trackname varchar(100) NOT NULL default '', + PRIMARY KEY (trackid) +); + +CREATE TABLE t2( + artistid int(10) unsigned NOT NULL auto_increment, + artistname varchar(100) NOT NULL default '', + PRIMARY KEY (artistid) +); + +CREATE TABLE t3( + trackid int(10) unsigned NOT NULL, + artistid int(10) unsigned NOT NULL, + PRIMARY KEY (trackid,artistid) +); + +INSERT INTO t1 VALUES (1, 'April In Paris'), (2, 'Autumn In New York'); +INSERT INTO t2 VALUES (1, 'Vernon Duke'); +INSERT INTO t3 VALUES (1,1); + +SELECT CONCAT_WS(' ', trackname, artistname) trackname, artistname + FROM t1 LEFT JOIN t3 ON t1.trackid=t3.trackid + LEFT JOIN t2 ON t2.artistid=t3.artistid + WHERE CONCAT_WS(' ', trackname, artistname) LIKE '%In%'; + +DROP TABLE t1,t2,t3; + +# +# Correct length reporting from substring() (BUG#10269) +# +create table t1 (b varchar(5)); +insert t1 values ('ab'), ('abc'), ('abcd'), ('abcde'); +select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1; +select * from (select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1) t; +drop table t1; + +# +# Bug #9854 hex() and out of range handling +# +select hex(29223372036854775809), hex(-29223372036854775809); + +# +# Bug #11311: Incorrect length returned from LPAD() and RPAD() +# +create table t1 (i int); +insert into t1 values (1000000000),(1); +--enable_metadata +select lpad(i, 7, ' ') as t from t1; +select rpad(i, 7, ' ') as t from t1; +--disable_metadata +drop table t1; + +# +# Bug #10418: LOAD_FILE does not behave like in manual if file does not exist +# + +select load_file("lkjlkj"); +select ifnull(load_file("lkjlkj"),"it's null"); + +# +# Bug#15351: Wrong collation used for comparison of md5() and sha() +# parameter can lead to a wrong result. +# +create table t1 (f1 varchar(4), f2 varchar(64), unique key k1 (f1,f2)); +insert into t1 values ( 'test',md5('test')), ('test', sha('test')); +select * from t1 where f1='test' and (f2= md5("test") or f2= md5("TEST")); +select * from t1 where f1='test' and (f2= md5("TEST") or f2= md5("test")); +select * from t1 where f1='test' and (f2= sha("test") or f2= sha("TEST")); +select * from t1 where f1='test' and (f2= sha("TEST") or f2= sha("test")); +drop table t1; + +# +# Bug#18243: REVERSE changes its argument +# + +CREATE TABLE t1 (a varchar(10)); +INSERT INTO t1 VALUES ('abc'), ('xyz'); + +SELECT a, CONCAT(a,' ',a) AS c FROM t1 + HAVING LEFT(c,LENGTH(c)-INSTR(REVERSE(c)," ")) = a; + +SELECT a, CONCAT(a,' ',a) AS c FROM t1 + HAVING LEFT(CONCAT(a,' ',a), + LENGTH(CONCAT(a,' ',a))- + INSTR(REVERSE(CONCAT(a,' ',a))," ")) = a; + +DROP TABLE t1; + +# +# Bug#17526: WRONG PRINT for TRIM FUNCTION with two arguments +# + +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yaddy'); + +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM('y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(LEADING 'y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(TRAILING 'y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(BOTH 'y' FROM s) > 'ab'; + +DROP TABLE t1; + +--echo End of 4.1 tests + +# +# Bug #13361: SELECT FORMAT(<decimal field with null>, 2) crashes +# +create table t1 (d decimal default null); +insert into t1 values (null); +select format(d, 2) from t1; +drop table t1; + +# +# Bug #14676: substring_index() returns incorrect results +# +create table t1 (c varchar(40)); +insert into t1 values ('y,abc'),('y,abc'); +select c, substring_index(lcase(c), @q:=',', -1) as res from t1; +drop table t1; + +# +# Bug #17043: Casting trimmed string to decimal loses precision +# +select cast(rtrim(' 20.06 ') as decimal(19,2)); +select cast(ltrim(' 20.06 ') as decimal(19,2)); +select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)); + +# +# Bug #13975: "same string" + 0 has 2 different results +# +select conv("18383815659218730760",10,10) + 0; +select "18383815659218730760" + 0; + +# +# Bug #21698: substitution of a string field for a constant under a function +# + +CREATE TABLE t1 (code varchar(10)); +INSERT INTO t1 VALUES ('a12'), ('A12'), ('a13'); + +SELECT ASCII(code), code FROM t1 WHERE code='A12'; +SELECT ASCII(code), code FROM t1 WHERE code='A12' AND ASCII(code)=65; + +INSERT INTO t1 VALUES ('a12 '), ('A12 '); + +SELECT LENGTH(code), code FROM t1 WHERE code='A12'; +SELECT LENGTH(code), code FROM t1 WHERE code='A12' AND LENGTH(code)=5; + +ALTER TABLE t1 ADD INDEX (code); +CREATE TABLE t2 (id varchar(10) PRIMARY KEY); +INSERT INTO t2 VALUES ('a11'), ('a12'), ('a13'), ('a14'); + +SELECT * FROM t1 INNER JOIN t2 ON t1.code=t2.id + WHERE t2.id='a12' AND (LENGTH(code)=5 OR code < 'a00'); +EXPLAIN EXTENDED +SELECT * FROM t1 INNER JOIN t2 ON code=id + WHERE id='a12' AND (LENGTH(code)=5 OR code < 'a00'); + +DROP TABLE t1,t2; + +# +# Bug#22684: The Functions ENCODE, DECODE and FORMAT are not real functions +# + +select encode(NULL, NULL); +select encode("data", NULL); +select encode(NULL, "password"); + +select decode(NULL, NULL); +select decode("data", NULL); +select decode(NULL, "password"); + +select format(NULL, NULL); +select format(pi(), NULL); +select format(NULL, 2); + +select benchmark(NULL, NULL); +select benchmark(0, NULL); +select benchmark(100, NULL); +select benchmark(NULL, 1+1); + +# +# Please note: +# 1) The collation of the password is irrelevant, the encryption uses +# the binary representation of the string without charset/collation. +# 2) These tests can not print the encoded text directly, because it's binary, +# and doing this would cause problems with source control. +# Instead, an md5() checksum is used, to verify the result indirectly. +# 3) Each md5() result must be identical. +# 4) The md5() result must never change, and must be stable across releases. +# +set @password="password"; +set @my_data="clear text to encode"; +select md5(encode(@my_data, "password")); +select md5(encode(@my_data, _utf8 "password")); +select md5(encode(@my_data, binary "password")); +select md5(encode(@my_data, _latin1 "password")); +select md5(encode(@my_data, _koi8r "password")); +select md5(encode(@my_data, (select "password" from dual))); +select md5(encode(@my_data, concat("pass", "word"))); +select md5(encode(@my_data, @password)); + +set @my_data="binary encoded data"; +select md5(decode(@my_data, "password")); +select md5(decode(@my_data, _utf8 "password")); +select md5(decode(@my_data, binary "password")); +select md5(decode(@my_data, _latin1 "password")); +select md5(decode(@my_data, _koi8r "password")); +select md5(decode(@my_data, (select "password" from dual))); +select md5(decode(@my_data, concat("pass", "word"))); +select md5(decode(@my_data, @password)); + +set @dec=5; +select format(pi(), (1+1)); +select format(pi(), (select 3 from dual)); +select format(pi(), @dec); + +set @bench_count=10; +select benchmark(10, pi()); +select benchmark(5+5, pi()); +select benchmark((select 10 from dual), pi()); +select benchmark(@bench_count, pi()); + + +# +# Bug #10963 +# 4294967296 18446744073709551616 + +select locate('he','hello',-2); +select locate('lo','hello',-4294967295); +select locate('lo','hello',4294967295); +select locate('lo','hello',-4294967296); +select locate('lo','hello',4294967296); +select locate('lo','hello',-4294967297); +select locate('lo','hello',4294967297); +select locate('lo','hello',-18446744073709551615); +select locate('lo','hello',18446744073709551615); +select locate('lo','hello',-18446744073709551616); +select locate('lo','hello',18446744073709551616); +select locate('lo','hello',-18446744073709551617); +select locate('lo','hello',18446744073709551617); + +select left('hello', 10); +select left('hello', 0); +select left('hello', -1); +select left('hello', -4294967295); +select left('hello', 4294967295); +select left('hello', -4294967296); +select left('hello', 4294967296); +select left('hello', -4294967297); +select left('hello', 4294967297); +select left('hello', -18446744073709551615); +select left('hello', 18446744073709551615); +select left('hello', -18446744073709551616); +select left('hello', 18446744073709551616); +select left('hello', -18446744073709551617); +select left('hello', 18446744073709551617); + +select right('hello', 10); +select right('hello', 0); +select right('hello', -1); +select right('hello', -4294967295); +select right('hello', 4294967295); +select right('hello', -4294967296); +select right('hello', 4294967296); +select right('hello', -4294967297); +select right('hello', 4294967297); +select right('hello', -18446744073709551615); +select right('hello', 18446744073709551615); +select right('hello', -18446744073709551616); +select right('hello', 18446744073709551616); +select right('hello', -18446744073709551617); +select right('hello', 18446744073709551617); + +select substring('hello', 2, -1); + +select substring('hello', -1, 1); +select substring('hello', -2, 1); +select substring('hello', -4294967295, 1); +select substring('hello', 4294967295, 1); +select substring('hello', -4294967296, 1); +select substring('hello', 4294967296, 1); +select substring('hello', -4294967297, 1); +select substring('hello', 4294967297, 1); +select substring('hello', -18446744073709551615, 1); +select substring('hello', 18446744073709551615, 1); +select substring('hello', -18446744073709551616, 1); +select substring('hello', 18446744073709551616, 1); +select substring('hello', -18446744073709551617, 1); +select substring('hello', 18446744073709551617, 1); +select substring('hello', 1, -1); +select substring('hello', 1, -4294967295); +select substring('hello', 1, 4294967295); +select substring('hello', 1, -4294967296); +select substring('hello', 1, 4294967296); +select substring('hello', 1, -4294967297); +select substring('hello', 1, 4294967297); +select substring('hello', 1, -18446744073709551615); +select substring('hello', 1, 18446744073709551615); +select substring('hello', 1, -18446744073709551616); +select substring('hello', 1, 18446744073709551616); +select substring('hello', 1, -18446744073709551617); +select substring('hello', 1, 18446744073709551617); +select substring('hello', -1, -1); +select substring('hello', -4294967295, -4294967295); +select substring('hello', 4294967295, 4294967295); +select substring('hello', -4294967296, -4294967296); +select substring('hello', 4294967296, 4294967296); +select substring('hello', -4294967297, -4294967297); +select substring('hello', 4294967297, 4294967297); +select substring('hello', -18446744073709551615, -18446744073709551615); +select substring('hello', 18446744073709551615, 18446744073709551615); +select substring('hello', -18446744073709551616, -18446744073709551616); +select substring('hello', 18446744073709551616, 18446744073709551616); +select substring('hello', -18446744073709551617, -18446744073709551617); +select substring('hello', 18446744073709551617, 18446744073709551617); + +select insert('hello', -1, 1, 'hi'); +select insert('hello', -4294967295, 1, 'hi'); +select insert('hello', 4294967295, 1, 'hi'); +select insert('hello', -4294967296, 1, 'hi'); +select insert('hello', 4294967296, 1, 'hi'); +select insert('hello', -4294967297, 1, 'hi'); +select insert('hello', 4294967297, 1, 'hi'); +select insert('hello', -18446744073709551615, 1, 'hi'); +select insert('hello', 18446744073709551615, 1, 'hi'); +select insert('hello', -18446744073709551616, 1, 'hi'); +select insert('hello', 18446744073709551616, 1, 'hi'); +select insert('hello', -18446744073709551617, 1, 'hi'); +select insert('hello', 18446744073709551617, 1, 'hi'); +select insert('hello', 1, -1, 'hi'); +select insert('hello', 1, -4294967295, 'hi'); +select insert('hello', 1, 4294967295, 'hi'); +select insert('hello', 1, -4294967296, 'hi'); +select insert('hello', 1, 4294967296, 'hi'); +select insert('hello', 1, -4294967297, 'hi'); +select insert('hello', 1, 4294967297, 'hi'); +select insert('hello', 1, -18446744073709551615, 'hi'); +select insert('hello', 1, 18446744073709551615, 'hi'); +select insert('hello', 1, -18446744073709551616, 'hi'); +select insert('hello', 1, 18446744073709551616, 'hi'); +select insert('hello', 1, -18446744073709551617, 'hi'); +select insert('hello', 1, 18446744073709551617, 'hi'); +select insert('hello', -1, -1, 'hi'); +select insert('hello', -4294967295, -4294967295, 'hi'); +select insert('hello', 4294967295, 4294967295, 'hi'); +select insert('hello', -4294967296, -4294967296, 'hi'); +select insert('hello', 4294967296, 4294967296, 'hi'); +select insert('hello', -4294967297, -4294967297, 'hi'); +select insert('hello', 4294967297, 4294967297, 'hi'); +select insert('hello', -18446744073709551615, -18446744073709551615, 'hi'); +select insert('hello', 18446744073709551615, 18446744073709551615, 'hi'); +select insert('hello', -18446744073709551616, -18446744073709551616, 'hi'); +select insert('hello', 18446744073709551616, 18446744073709551616, 'hi'); +select insert('hello', -18446744073709551617, -18446744073709551617, 'hi'); +select insert('hello', 18446744073709551617, 18446744073709551617, 'hi'); + +select repeat('hello', -1); +select repeat('hello', -4294967295); +select repeat('hello', 4294967295); +select repeat('hello', -4294967296); +select repeat('hello', 4294967296); +select repeat('hello', -4294967297); +select repeat('hello', 4294967297); +select repeat('hello', -18446744073709551615); +select repeat('hello', 18446744073709551615); +select repeat('hello', -18446744073709551616); +select repeat('hello', 18446744073709551616); +select repeat('hello', -18446744073709551617); +select repeat('hello', 18446744073709551617); + +select space(-1); +select space(-4294967295); +select space(4294967295); +select space(-4294967296); +select space(4294967296); +select space(-4294967297); +select space(4294967297); +select space(-18446744073709551615); +select space(18446744073709551615); +select space(-18446744073709551616); +select space(18446744073709551616); +select space(-18446744073709551617); +select space(18446744073709551617); + +select rpad('hello', -1, '1'); +select rpad('hello', -4294967295, '1'); +select rpad('hello', 4294967295, '1'); +select rpad('hello', -4294967296, '1'); +select rpad('hello', 4294967296, '1'); +select rpad('hello', -4294967297, '1'); +select rpad('hello', 4294967297, '1'); +select rpad('hello', -18446744073709551615, '1'); +select rpad('hello', 18446744073709551615, '1'); +select rpad('hello', -18446744073709551616, '1'); +select rpad('hello', 18446744073709551616, '1'); +select rpad('hello', -18446744073709551617, '1'); +select rpad('hello', 18446744073709551617, '1'); + +select lpad('hello', -1, '1'); +select lpad('hello', -4294967295, '1'); +select lpad('hello', 4294967295, '1'); +select lpad('hello', -4294967296, '1'); +select lpad('hello', 4294967296, '1'); +select lpad('hello', -4294967297, '1'); +select lpad('hello', 4294967297, '1'); +select lpad('hello', -18446744073709551615, '1'); +select lpad('hello', 18446744073709551615, '1'); +select lpad('hello', -18446744073709551616, '1'); +select lpad('hello', 18446744073709551616, '1'); +select lpad('hello', -18446744073709551617, '1'); +select lpad('hello', 18446744073709551617, '1'); + + +# +# BUG#17047: CHAR() and IN() can return NULL without signaling NULL +# result +# +SET @orig_sql_mode = @@SQL_MODE; +SET SQL_MODE=traditional; + +SELECT CHAR(0xff,0x8f USING utf8); +SELECT CHAR(0xff,0x8f USING utf8) IS NULL; + +SET SQL_MODE=@orig_sql_mode; + +# +# Bug #24947: problem with some string function with unsigned int parameters +# + +select substring('abc', cast(2 as unsigned int)); +select repeat('a', cast(2 as unsigned int)); +select rpad('abc', cast(5 as unsigned integer), 'x'); +select lpad('abc', cast(5 as unsigned integer), 'x'); + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/func_system.test b/mysql-test/suite/pbxt/t/func_system.test new file mode 100644 index 00000000000..2bfe1e5a09a --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_system.test @@ -0,0 +1,60 @@ +# +# system functions +# + +select database(); +select charset(database()); +select database() = "test"; +select database() = _utf8"test"; +select database() = _latin1"test"; + +select user() like "%@%"; +select user() like _utf8"%@%"; +select user() like _latin1"%@%"; +select charset(user()); + +select version()>="3.23.29"; +select version()>=_utf8"3.23.29"; +select version()>=_latin1"3.23.29"; +select charset(version()); +explain extended select database(), user(); + +create table t1 (version char(60)) select database(), user(), version() as 'version'; +show create table t1; +drop table t1; + +select charset(charset(_utf8'a')), charset(collation(_utf8'a')); +select collation(charset(_utf8'a')), collation(collation(_utf8'a')); +create table t1 select charset(_utf8'a'), collation(_utf8'a'); +show create table t1; +drop table t1; + +select TRUE,FALSE,NULL; + +# +# Bug#12351: CONCAT with USER()/DATEBASE() and +# a constant and a column gets strange results +# +create table t1 (c1 char(5)) character set=latin1; +insert into t1 values('row 1'); +insert into t1 values('row 2'); +insert into t1 values('row 3'); +select concat(user(), '--', c1) from t1; +select concat(database(), '--', c1) from t1; +drop table t1; + +# +# Bug#8291 Illegal collation mix with USER() function +# +create table t1 (a char(10)) character set latin1; +select * from t1 where a=version(); +select * from t1 where a=database(); +select * from t1 where a=user(); +insert into t1 values ('a'); +select left(concat(a,version()),1) from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/func_timestamp.test b/mysql-test/suite/pbxt/t/func_timestamp.test new file mode 100644 index 00000000000..80afcc246b1 --- /dev/null +++ b/mysql-test/suite/pbxt/t/func_timestamp.test @@ -0,0 +1,27 @@ +# +# Tests that depend on the timestamp and the TZ variable +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# Set timezone to GMT-3, to make it possible to use "interval 3 hour" +set time_zone="+03:00"; + +create table t1 (Zeit time, Tag tinyint not null, Monat tinyint not null, +Jahr smallint not null, index(Tag), index(Monat), index(Jahr) ); +insert into t1 values ("09:26:00",16,9,1998),("09:26:00",16,9,1998); +SELECT CONCAT(Jahr,'-',Monat,'-',Tag,' ',Zeit) AS Date, + UNIX_TIMESTAMP(CONCAT(Jahr,'-',Monat,'-',Tag,' ',Zeit)) AS Unix +FROM t1; +drop table t1; + +# End of 4.1 tests + +# Restore timezone to default +set time_zone= @@global.time_zone; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/gcc296.test b/mysql-test/suite/pbxt/t/gcc296.test new file mode 100644 index 00000000000..3e66e866e37 --- /dev/null +++ b/mysql-test/suite/pbxt/t/gcc296.test @@ -0,0 +1,22 @@ +#try to crash gcc 2.96 +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE t1 ( + kodoboru varchar(10) default NULL, + obor tinytext, + aobor tinytext, + UNIQUE INDEX kodoboru (kodoboru), + FULLTEXT KEY obor (obor), + FULLTEXT KEY aobor (aobor) +) engine=myisam; # PBXT: Only MyISAM has full-text index +INSERT INTO t1 VALUES ('0101000000','aaa','AAA'); +INSERT INTO t1 VALUES ('0102000000','bbb','BBB'); +INSERT INTO t1 VALUES ('0103000000','ccc','CCC'); +INSERT INTO t1 VALUES ('0104000000','xxx','XXX'); + +select * from t1; +drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/grant.test b/mysql-test/suite/pbxt/t/grant.test new file mode 100644 index 00000000000..24b4eb926ce --- /dev/null +++ b/mysql-test/suite/pbxt/t/grant.test @@ -0,0 +1,945 @@ +# Test of GRANT commands + +# Grant tests not performed with embedded server +-- source include/not_embedded.inc + +# Cleanup +--disable_warnings +drop table if exists t1; +drop database if exists mysqltest; +--enable_warnings + +connect (master,localhost,root,,); +connection master; +SET NAMES binary; + +# +# Test that SSL options works properly +# + +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +flush privileges; +grant select on mysqltest.* to mysqltest_1@localhost require cipher "EDH-RSA-DES-CBC3-SHA"; +show grants for mysqltest_1@localhost; +grant delete on mysqltest.* to mysqltest_1@localhost; +select * from mysql.user where user="mysqltest_1"; +show grants for mysqltest_1@localhost; +revoke delete on mysqltest.* from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +grant select on mysqltest.* to mysqltest_1@localhost require NONE; +show grants for mysqltest_1@localhost; +grant USAGE on mysqltest.* to mysqltest_1@localhost require cipher "EDH-RSA-DES-CBC3-SHA" AND SUBJECT "testsubject" ISSUER "MySQL AB"; +show grants for mysqltest_1@localhost; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +flush privileges; + +# +# Test of GRANTS specifying user limits +# +delete from mysql.user where user='mysqltest_1'; +flush privileges; +grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10; +select * from mysql.user where user="mysqltest_1"; +show grants for mysqltest_1@localhost; +grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30; +select * from mysql.user where user="mysqltest_1"; +show grants for mysqltest_1@localhost; +# This is just to double check that one won't ignore results of selects +flush privileges; +show grants for mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +flush privileges; + +# +# Test that the new db privileges are stored/retrieved correctly +# + +grant CREATE TEMPORARY TABLES, LOCK TABLES on mysqltest.* to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +flush privileges; +show grants for mysqltest_1@localhost; +revoke CREATE TEMPORARY TABLES on mysqltest.* from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +grant ALL PRIVILEGES on mysqltest.* to mysqltest_1@localhost with GRANT OPTION; +flush privileges; +show grants for mysqltest_1@localhost; +revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +flush privileges; +grant usage on test.* to mysqltest_1@localhost with grant option; +show grants for mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +delete from mysql.tables_priv where user='mysqltest_1'; +delete from mysql.columns_priv where user='mysqltest_1'; +flush privileges; +--error 1141 +show grants for mysqltest_1@localhost; + +# +# Test what happens when you have same table and colum level grants +# + +create table t1 (a int); +GRANT select,update,insert on t1 to mysqltest_1@localhost; +GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +REVOKE select (a), update on t1 from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +REVOKE select,update,insert,insert (a) on t1 from mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +GRANT select,references on t1 to mysqltest_1@localhost; +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +grant all on test.* to mysqltest_3@localhost with grant option; +revoke all on test.* from mysqltest_3@localhost; +show grants for mysqltest_3@localhost; +revoke grant option on test.* from mysqltest_3@localhost; +show grants for mysqltest_3@localhost; +grant all on test.t1 to mysqltest_2@localhost with grant option; +revoke all on test.t1 from mysqltest_2@localhost; +show grants for mysqltest_2@localhost; +revoke grant option on test.t1 from mysqltest_2@localhost; +show grants for mysqltest_2@localhost; +delete from mysql.user where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.db where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.tables_priv where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.columns_priv where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +flush privileges; +drop table t1; + +# +# Test some error conditions +# +--error 1221 +GRANT FILE on mysqltest.* to mysqltest_1@localhost; +select 1; # To test that the previous command didn't cause problems + +# +# Bug #4898: User privileges depending on ORDER BY Settings of table db +# +insert into mysql.user (host, user) values ('localhost', 'test11'); +insert into mysql.db (host, db, user, select_priv) values +('localhost', 'a%', 'test11', 'Y'), ('localhost', 'ab%', 'test11', 'Y'); +alter table mysql.db order by db asc; +flush privileges; +show grants for test11@localhost; +alter table mysql.db order by db desc; +flush privileges; +show grants for test11@localhost; +delete from mysql.user where user='test11'; +delete from mysql.db where user='test11'; + +# +# Bug#6123: GRANT USAGE inserts useless Db row +# +create database mysqltest1; +grant usage on mysqltest1.* to test6123 identified by 'magic123'; +select host,db,user,select_priv,insert_priv from mysql.db where db="mysqltest1"; +delete from mysql.user where user='test6123'; +drop database mysqltest1; + +# +# Test for 'drop user', 'revoke privileges, grant' +# + +create table t1 (a int); +grant ALL PRIVILEGES on *.* to drop_user2@localhost with GRANT OPTION; +show grants for drop_user2@localhost; +revoke all privileges, grant option from drop_user2@localhost; +drop user drop_user2@localhost; + +grant ALL PRIVILEGES on *.* to drop_user@localhost with GRANT OPTION; +grant ALL PRIVILEGES on test.* to drop_user@localhost with GRANT OPTION; +grant select(a) on test.t1 to drop_user@localhost; +show grants for drop_user@localhost; + +# +# Bug3086 +# +set sql_mode=ansi_quotes; +show grants for drop_user@localhost; +set sql_mode=default; + +set sql_quote_show_create=0; +show grants for drop_user@localhost; +set sql_mode="ansi_quotes"; +show grants for drop_user@localhost; +set sql_quote_show_create=1; +show grants for drop_user@localhost; +set sql_mode=""; +show grants for drop_user@localhost; + +revoke all privileges, grant option from drop_user@localhost; +show grants for drop_user@localhost; +drop user drop_user@localhost; +--error 1269 +revoke all privileges, grant option from drop_user@localhost; + +grant select(a) on test.t1 to drop_user1@localhost; +grant select on test.t1 to drop_user2@localhost; +grant select on test.* to drop_user3@localhost; +grant select on *.* to drop_user4@localhost; +# Drop user now implicitly revokes all privileges. +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +--error 1269 +revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost, +drop_user3@localhost, drop_user4@localhost; +--error 1396 +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +drop table t1; +grant usage on *.* to mysqltest_1@localhost identified by "password"; +grant select, update, insert on test.* to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; +drop user mysqltest_1@localhost; + +# +# Bug #3403 Wrong encodin in SHOW GRANTS output +# +SET NAMES koi8r; +CREATE DATABASE ÂÄ; +USE ÂÄ; +CREATE TABLE ÔÁ (ËÏÌ int); + +GRANT SELECT ON ÂÄ.* TO ÀÚÅÒ@localhost; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +REVOKE SELECT ON ÂÄ.* FROM ÀÚÅÒ@localhost; + +GRANT SELECT ON ÂÄ.ÔÁ TO ÀÚÅÒ@localhost; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +REVOKE SELECT ON ÂÄ.ÔÁ FROM ÀÚÅÒ@localhost; + +GRANT SELECT (ËÏÌ) ON ÂÄ.ÔÁ TO ÀÚÅÒ@localhost; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +REVOKE SELECT (ËÏÌ) ON ÂÄ.ÔÁ FROM ÀÚÅÒ@localhost; + +# Revoke does not drop user. Leave a clean user table for the next tests. +DROP USER ÀÚÅÒ@localhost; + +DROP DATABASE ÂÄ; +SET NAMES latin1; + +# +# Bug #5831: REVOKE ALL PRIVILEGES, GRANT OPTION does not revoke everything +# +USE test; +CREATE TABLE t1 (a int ); +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 LIKE t1; +CREATE TABLE t4 LIKE t1; +CREATE TABLE t5 LIKE t1; +CREATE TABLE t6 LIKE t1; +CREATE TABLE t7 LIKE t1; +CREATE TABLE t8 LIKE t1; +CREATE TABLE t9 LIKE t1; +CREATE TABLE t10 LIKE t1; +CREATE DATABASE testdb1; +CREATE DATABASE testdb2; +CREATE DATABASE testdb3; +CREATE DATABASE testdb4; +CREATE DATABASE testdb5; +CREATE DATABASE testdb6; +CREATE DATABASE testdb7; +CREATE DATABASE testdb8; +CREATE DATABASE testdb9; +CREATE DATABASE testdb10; +GRANT ALL ON testdb1.* TO testuser@localhost; +GRANT ALL ON testdb2.* TO testuser@localhost; +GRANT ALL ON testdb3.* TO testuser@localhost; +GRANT ALL ON testdb4.* TO testuser@localhost; +GRANT ALL ON testdb5.* TO testuser@localhost; +GRANT ALL ON testdb6.* TO testuser@localhost; +GRANT ALL ON testdb7.* TO testuser@localhost; +GRANT ALL ON testdb8.* TO testuser@localhost; +GRANT ALL ON testdb9.* TO testuser@localhost; +GRANT ALL ON testdb10.* TO testuser@localhost; +GRANT SELECT ON test.t1 TO testuser@localhost; +GRANT SELECT ON test.t2 TO testuser@localhost; +GRANT SELECT ON test.t3 TO testuser@localhost; +GRANT SELECT ON test.t4 TO testuser@localhost; +GRANT SELECT ON test.t5 TO testuser@localhost; +GRANT SELECT ON test.t6 TO testuser@localhost; +GRANT SELECT ON test.t7 TO testuser@localhost; +GRANT SELECT ON test.t8 TO testuser@localhost; +GRANT SELECT ON test.t9 TO testuser@localhost; +GRANT SELECT ON test.t10 TO testuser@localhost; +GRANT SELECT (a) ON test.t1 TO testuser@localhost; +GRANT SELECT (a) ON test.t2 TO testuser@localhost; +GRANT SELECT (a) ON test.t3 TO testuser@localhost; +GRANT SELECT (a) ON test.t4 TO testuser@localhost; +GRANT SELECT (a) ON test.t5 TO testuser@localhost; +GRANT SELECT (a) ON test.t6 TO testuser@localhost; +GRANT SELECT (a) ON test.t7 TO testuser@localhost; +GRANT SELECT (a) ON test.t8 TO testuser@localhost; +GRANT SELECT (a) ON test.t9 TO testuser@localhost; +GRANT SELECT (a) ON test.t10 TO testuser@localhost; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM testuser@localhost; +SHOW GRANTS FOR testuser@localhost; +DROP USER testuser@localhost; +DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8,t9,t10; +DROP DATABASE testdb1; +DROP DATABASE testdb2; +DROP DATABASE testdb3; +DROP DATABASE testdb4; +DROP DATABASE testdb5; +DROP DATABASE testdb6; +DROP DATABASE testdb7; +DROP DATABASE testdb8; +DROP DATABASE testdb9; +DROP DATABASE testdb10; + +# +# Bug #6932: a problem with 'revoke ALL PRIVILEGES' +# + +create table t1(a int, b int, c int, d int); +grant insert(b), insert(c), insert(d), insert(a) on t1 to grant_user@localhost; +show grants for grant_user@localhost; +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name; +revoke ALL PRIVILEGES on t1 from grant_user@localhost; +show grants for grant_user@localhost; +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; +drop user grant_user@localhost; +drop table t1; + +# +# Bug#7391: Cross-database multi-table UPDATE security problem +# +create database mysqltest_1; +create database mysqltest_2; +create table mysqltest_1.t1 select 1 a, 2 q; +create table mysqltest_1.t2 select 1 b, 2 r; +create table mysqltest_2.t1 select 1 c, 2 s; +create table mysqltest_2.t2 select 1 d, 2 t; + +#test the column privileges +grant update (a) on mysqltest_1.t1 to mysqltest_3@localhost; +grant select (b) on mysqltest_1.t2 to mysqltest_3@localhost; +grant select (c) on mysqltest_2.t1 to mysqltest_3@localhost; +grant update (d) on mysqltest_2.t2 to mysqltest_3@localhost; +connect (conn1,localhost,mysqltest_3,,); +connection conn1; +SELECT * FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES + WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_NAME,COLUMN_NAME,PRIVILEGE_TYPE; +SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES + WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_NAME,PRIVILEGE_TYPE; +SELECT * from INFORMATION_SCHEMA.SCHEMA_PRIVILEGES + WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_SCHEMA,PRIVILEGE_TYPE; +SELECT * from INFORMATION_SCHEMA.USER_PRIVILEGES + WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_CATALOG,PRIVILEGE_TYPE; +--error 1143 +update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1; +--error 1143 +update mysqltest_1.t2, mysqltest_2.t2 set d=20 where d=1; +--error 1142 +update mysqltest_1.t1, mysqltest_2.t2 set d=20 where d=1; +--error 1142 +update mysqltest_2.t1, mysqltest_1.t2 set c=20 where b=1; +--error 1143 +update mysqltest_2.t1, mysqltest_2.t2 set d=10 where s=2; +#the following two should work +update mysqltest_1.t1, mysqltest_2.t2 set a=10,d=10; +update mysqltest_1.t1, mysqltest_2.t1 set a=20 where c=20; +connection master; +select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2; +select t1.*,t2.* from mysqltest_2.t1,mysqltest_2.t2; +revoke all on mysqltest_1.t1 from mysqltest_3@localhost; +revoke all on mysqltest_1.t2 from mysqltest_3@localhost; +revoke all on mysqltest_2.t1 from mysqltest_3@localhost; +revoke all on mysqltest_2.t2 from mysqltest_3@localhost; + +#test the db/table level privileges +grant all on mysqltest_2.* to mysqltest_3@localhost; +grant select on *.* to mysqltest_3@localhost; +# Next grant is needed to trigger bug#7391. Do not optimize! +grant select on mysqltest_2.t1 to mysqltest_3@localhost; +flush privileges; +disconnect conn1; +connect (conn2,localhost,mysqltest_3,,); +connection conn2; +use mysqltest_1; +update mysqltest_2.t1, mysqltest_2.t2 set c=500,d=600; +# the following failed before, should fail now. +--error 1142 +update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200; +use mysqltest_2; +#the following used to succeed, it must fail now. +--error 1142 +update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200; +--error 1142 +update mysqltest_2.t1, mysqltest_1.t2 set c=100,b=200; +--error 1142 +update mysqltest_1.t1, mysqltest_2.t2 set a=100,d=200; +#lets see the result +connection master; +select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2; +select t1.*,t2.* from mysqltest_2.t1,mysqltest_2.t2; + +delete from mysql.user where user='mysqltest_3'; +delete from mysql.db where user="mysqltest_3"; +delete from mysql.tables_priv where user="mysqltest_3"; +delete from mysql.columns_priv where user="mysqltest_3"; +flush privileges; +drop database mysqltest_1; +drop database mysqltest_2; + +# +# just SHOW PRIVILEGES test +# +SHOW PRIVILEGES; + +# +# Rights for renaming test (Bug #3270) +# +connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings +create table mysqltest.t1 (a int,b int,c int); +grant all on mysqltest.t1 to mysqltest_1@localhost; +connect (user1,localhost,mysqltest_1,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK); +connection user1; +-- error 1142 +alter table t1 rename t2; +connection root; +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +delete from mysql.user where user=_binary'mysqltest_1'; +drop database mysqltest; + +# +# check all new table priveleges +# +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT ALL PRIVILEGES ON mysqltest.dummytable TO dummy@localhost; +GRANT ALL PRIVILEGES ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +SHOW FIELDS FROM mysql.tables_priv; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +# check view only privileges +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT CREATE VIEW ON mysqltest.dummytable TO dummy@localhost; +GRANT CREATE VIEW ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT SHOW VIEW ON mysqltest.dummytable TO dummy@localhost; +GRANT SHOW VIEW ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +# +# Bug #11330: Entry in tables_priv with host = '' causes crash +# +connection default; +use mysql; +insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_grantor',CURRENT_TIMESTAMP,'Select','Select'); +flush privileges; +delete from tables_priv where host = '' and user = 'mysqltest_1'; +flush privileges; +use test; + +# +# Bug #10892 user variables not auto cast for comparisons +# Check that we don't get illegal mix of collations +# +set @user123="non-existent"; +select * from mysql.db where user=@user123; + +set names koi8r; +create database ÂÄ; +grant select on ÂÄ.* to root@localhost; +select hex(Db) from mysql.db where Db='ÂÄ'; +show grants for root@localhost; +flush privileges; +show grants for root@localhost; +drop database ÂÄ; +revoke all privileges on ÂÄ.* from root@localhost; +show grants for root@localhost; +set names latin1; + +# +# Bug #15598 Server crashes in specific case during setting new password +# - Caused by a user with host '' +# +create user mysqltest_7@; +set password for mysqltest_7@ = password('systpass'); +show grants for mysqltest_7@; +drop user mysqltest_7@; +--error 1141 +show grants for mysqltest_7@; + +# +# Bug#14385: GRANT and mapping to correct user account problems +# +create database mysqltest; +use mysqltest; +create table t1(f1 int); +GRANT DELETE ON mysqltest.t1 TO mysqltest1@'%'; +GRANT SELECT ON mysqltest.t1 TO mysqltest1@'192.%'; +show grants for mysqltest1@'192.%'; +show grants for mysqltest1@'%'; +delete from mysql.user where user='mysqltest1'; +delete from mysql.db where user='mysqltest1'; +delete from mysql.tables_priv where user='mysqltest1'; +flush privileges; +drop database mysqltest; + +# End of 4.1 tests + +# +# Bug #16297 In memory grant tables not flushed when users's hostname is "" +# +use test; +create table t1 (a int); + +# Backup anonymous users and remove them. (They get in the way of +# the one we test with here otherwise.) +create table t2 as select * from mysql.user where user=''; +delete from mysql.user where user=''; +flush privileges; + +# Create some users with different hostnames +create user mysqltest_8@''; +create user mysqltest_8; +create user mysqltest_8@host8; + +# Try to create them again +--error 1396 +create user mysqltest_8@''; +--error 1396 +create user mysqltest_8; +--error 1396 +create user mysqltest_8@host8; + +select user, QUOTE(host) from mysql.user where user="mysqltest_8"; + +--echo Schema privileges +grant select on mysqltest.* to mysqltest_8@''; +show grants for mysqltest_8@''; +grant select on mysqltest.* to mysqltest_8@; +show grants for mysqltest_8@; +grant select on mysqltest.* to mysqltest_8; +show grants for mysqltest_8; +select * from information_schema.schema_privileges +where grantee like "'mysqltest_8'%"; +connect (conn3,localhost,mysqltest_8,,); +select * from t1; +disconnect conn3; +connection master; +revoke select on mysqltest.* from mysqltest_8@''; +revoke select on mysqltest.* from mysqltest_8; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +select * from information_schema.schema_privileges +where grantee like "'mysqltest_8'%"; +flush privileges; +show grants for mysqltest_8@''; +show grants for mysqltest_8@; +grant select on mysqltest.* to mysqltest_8@''; +flush privileges; +show grants for mysqltest_8@; +revoke select on mysqltest.* from mysqltest_8@''; +flush privileges; + +--echo Column privileges +grant update (a) on t1 to mysqltest_8@''; +grant update (a) on t1 to mysqltest_8; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +flush privileges; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +select * from information_schema.column_privileges; +connect (conn4,localhost,mysqltest_8,,); +select * from t1; +disconnect conn4; +connection master; +revoke update (a) on t1 from mysqltest_8@''; +revoke update (a) on t1 from mysqltest_8; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +select * from information_schema.column_privileges; +flush privileges; +show grants for mysqltest_8@''; +show grants for mysqltest_8; + +--echo Table privileges +grant update on t1 to mysqltest_8@''; +grant update on t1 to mysqltest_8; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +flush privileges; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +select * from information_schema.table_privileges; +connect (conn5,localhost,mysqltest_8,,); +select * from t1; +disconnect conn5; +connection master; +revoke update on t1 from mysqltest_8@''; +revoke update on t1 from mysqltest_8; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +select * from information_schema.table_privileges; +flush privileges; +show grants for mysqltest_8@''; +show grants for mysqltest_8; + +--echo "DROP USER" should clear privileges +grant all privileges on mysqltest.* to mysqltest_8@''; +grant select on mysqltest.* to mysqltest_8@''; +grant update on t1 to mysqltest_8@''; +grant update (a) on t1 to mysqltest_8@''; +grant all privileges on mysqltest.* to mysqltest_8; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +select * from information_schema.user_privileges +where grantee like "'mysqltest_8'%"; +connect (conn5,localhost,mysqltest_8,,); +select * from t1; +disconnect conn5; +connection master; +flush privileges; +show grants for mysqltest_8@''; +show grants for mysqltest_8; +drop user mysqltest_8@''; +--error 1141 +show grants for mysqltest_8@''; +show grants for mysqltest_8; +select * from information_schema.user_privileges +where grantee like "'mysqltest_8'%"; +drop user mysqltest_8; +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (conn6,localhost,mysqltest_8,,); +connection master; +--error 1141 +show grants for mysqltest_8; +drop user mysqltest_8@host8; +--error 1141 +show grants for mysqltest_8@host8; + +# Restore the anonymous users. +insert into mysql.user select * from t2; +flush privileges; +drop table t2; + +drop table t1; + +# +# Bug#20214: Incorrect error when user calls SHOW CREATE VIEW on non +# privileged view +# + +connection master; + +CREATE DATABASE mysqltest3; +use mysqltest3; + +CREATE TABLE t_nn (c1 INT); +CREATE VIEW v_nn AS SELECT * FROM t_nn; + +CREATE DATABASE mysqltest2; +use mysqltest2; + +CREATE TABLE t_nn (c1 INT); +CREATE VIEW v_nn AS SELECT * FROM t_nn; +CREATE VIEW v_yn AS SELECT * FROM t_nn; +CREATE VIEW v_gy AS SELECT * FROM t_nn; +CREATE VIEW v_ny AS SELECT * FROM t_nn; +CREATE VIEW v_yy AS SELECT * FROM t_nn WHERE c1=55; + +GRANT SHOW VIEW ON mysqltest2.v_ny TO 'mysqltest_1'@'localhost' IDENTIFIED BY 'mysqltest_1'; +GRANT SELECT ON mysqltest2.v_yn TO 'mysqltest_1'@'localhost' IDENTIFIED BY 'mysqltest_1'; +GRANT SELECT ON mysqltest2.* TO 'mysqltest_1'@'localhost' IDENTIFIED BY 'mysqltest_1'; +GRANT SHOW VIEW,SELECT ON mysqltest2.v_yy TO 'mysqltest_1'@'localhost' IDENTIFIED BY 'mysqltest_1'; + +connect (mysqltest_1, localhost, mysqltest_1, mysqltest_1,); + +# fail because of missing SHOW VIEW (have generic SELECT) +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest2.v_nn; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE TABLE mysqltest2.v_nn; + + + +# fail because of missing SHOW VIEW +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest2.v_yn; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE TABLE mysqltest2.v_yn; + + + +# succeed (despite of missing SELECT, having SHOW VIEW bails us out) +SHOW CREATE TABLE mysqltest2.v_ny; + +# succeed (despite of missing SELECT, having SHOW VIEW bails us out) +SHOW CREATE VIEW mysqltest2.v_ny; + + + +# fail because of missing (specific or generic) SELECT +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE TABLE mysqltest3.t_nn; + +# fail because of missing (specific or generic) SELECT (not because it's not a view!) +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest3.t_nn; + + + +# fail because of missing missing (specific or generic) SELECT (and SHOW VIEW) +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest3.v_nn; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE TABLE mysqltest3.v_nn; + + + +# succeed thanks to generic SELECT +SHOW CREATE TABLE mysqltest2.t_nn; + +# fail because it's not a view! (have generic SELECT though) +--error ER_WRONG_OBJECT +SHOW CREATE VIEW mysqltest2.t_nn; + + + +# succeed, have SELECT and SHOW VIEW +SHOW CREATE VIEW mysqltest2.v_yy; + +# succeed, have SELECT and SHOW VIEW +SHOW CREATE TABLE mysqltest2.v_yy; + + + +#clean-up +connection master; + +# succeed, we're root +SHOW CREATE TABLE mysqltest2.v_nn; +SHOW CREATE VIEW mysqltest2.v_nn; + +SHOW CREATE TABLE mysqltest2.t_nn; + +# fail because it's not a view! +--error ER_WRONG_OBJECT +SHOW CREATE VIEW mysqltest2.t_nn; + + + +DROP VIEW mysqltest2.v_nn; +DROP VIEW mysqltest2.v_yn; +DROP VIEW mysqltest2.v_ny; +DROP VIEW mysqltest2.v_yy; + +DROP TABLE mysqltest2.t_nn; + +DROP DATABASE mysqltest2; + + + +DROP VIEW mysqltest3.v_nn; +DROP TABLE mysqltest3.t_nn; + +DROP DATABASE mysqltest3; + +REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'mysqltest_1'@'localhost'; +DROP USER 'mysqltest_1'@'localhost'; + +# restore the original database +use test; + +# +# Bug #10668: CREATE USER does not enforce username length limit +# +--error ER_WRONG_STRING_LENGTH +create user mysqltest1_thisisreallytoolong; + +# +# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause. +# +# These checks are intended to ensure that appropriate errors are risen when +# illegal user name or hostname is specified in user-clause of GRANT/REVOKE +# statements. +# + +# +# Bug #22369: Alter table rename combined with other alterations causes lost tables +# +CREATE DATABASE mysqltest1; +CREATE TABLE mysqltest1.t1 ( + int_field INTEGER UNSIGNED NOT NULL, + char_field CHAR(10), + INDEX(`int_field`) +); +CREATE TABLE mysqltest1.t2 (int_field INT); + +--echo "Now check that we require equivalent grants for " +--echo "RENAME TABLE and ALTER TABLE" +CREATE USER mysqltest_1@localhost; +GRANT SELECT ON mysqltest1.t1 TO mysqltest_1@localhost; + +connect (conn42,localhost,mysqltest_1,,mysqltest1); +SELECT USER(); +SHOW GRANTS; +--error ER_TABLEACCESS_DENIED_ERROR +RENAME TABLE t1 TO t2; +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 RENAME TO t2; +--disconnect conn42 +--connection default +GRANT DROP ON mysqltest1.t1 TO mysqltest_1@localhost; + +connect (conn42,localhost,mysqltest_1,,mysqltest1); +--error ER_TABLEACCESS_DENIED_ERROR +RENAME TABLE t1 TO t2; +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 RENAME TO t2; +--disconnect conn42 +--connection default +GRANT ALTER ON mysqltest1.t1 TO mysqltest_1@localhost; + +connect (conn42,localhost,mysqltest_1,,mysqltest1); +SHOW GRANTS; +--error ER_TABLEACCESS_DENIED_ERROR +RENAME TABLE t1 TO t2; +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 RENAME TO t2; +--disconnect conn42 +--connection default +GRANT INSERT, CREATE ON mysqltest1.t1 TO mysqltest_1@localhost; +connect (conn42,localhost,mysqltest_1,,mysqltest1); +SHOW GRANTS; +--error ER_TABLEACCESS_DENIED_ERROR +--disconnect conn42 +--connection default +GRANT INSERT, SELECT, CREATE, ALTER, DROP ON mysqltest1.t2 TO mysqltest_1@localhost; +DROP TABLE mysqltest1.t2; + +connect (conn42,localhost,mysqltest_1,,mysqltest1); +SHOW GRANTS; +RENAME TABLE t1 TO t2; +RENAME TABLE t2 TO t1; +ALTER TABLE t1 RENAME TO t2; +ALTER TABLE t2 RENAME TO t1; +--disconnect conn42 +--connection default +REVOKE DROP, INSERT ON mysqltest1.t1 FROM mysqltest_1@localhost; +REVOKE DROP, INSERT ON mysqltest1.t2 FROM mysqltest_1@localhost; + +connect (conn42,localhost,mysqltest_1,,mysqltest1); +SHOW GRANTS; +--error ER_TABLEACCESS_DENIED_ERROR +RENAME TABLE t1 TO t2; +--error ER_TABLEACCESS_DENIED_ERROR +ALTER TABLE t1 RENAME TO t2; +--disconnect conn42 +--connection default + +DROP USER mysqltest_1@localhost; +DROP DATABASE mysqltest1; + +# Working with database-level privileges. + +--error ER_WRONG_STRING_LENGTH +GRANT CREATE ON mysqltest.* TO 1234567890abcdefGHIKL@localhost; + +--error ER_WRONG_STRING_LENGTH +GRANT CREATE ON mysqltest.* TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; + +--error ER_WRONG_STRING_LENGTH +REVOKE CREATE ON mysqltest.* FROM 1234567890abcdefGHIKL@localhost; + +--error ER_WRONG_STRING_LENGTH +REVOKE CREATE ON mysqltest.* FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; + +# Working with table-level privileges. + +--error ER_WRONG_STRING_LENGTH +GRANT CREATE ON t1 TO 1234567890abcdefGHIKL@localhost; + +--error ER_WRONG_STRING_LENGTH +GRANT CREATE ON t1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; + +--error ER_WRONG_STRING_LENGTH +REVOKE CREATE ON t1 FROM 1234567890abcdefGHIKL@localhost; + +--error ER_WRONG_STRING_LENGTH +REVOKE CREATE ON t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; + +# Working with routine-level privileges. + +--error ER_WRONG_STRING_LENGTH +GRANT EXECUTE ON PROCEDURE p1 TO 1234567890abcdefGHIKL@localhost; + +--error ER_WRONG_STRING_LENGTH +GRANT EXECUTE ON PROCEDURE p1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; + +--error ER_WRONG_STRING_LENGTH +REVOKE EXECUTE ON PROCEDURE p1 FROM 1234567890abcdefGHIKL@localhost; + +--error ER_WRONG_STRING_LENGTH +REVOKE EXECUTE ON PROCEDURE t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY; +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/grant_cache.test b/mysql-test/suite/pbxt/t/grant_cache.test new file mode 100644 index 00000000000..f3faa579035 --- /dev/null +++ b/mysql-test/suite/pbxt/t/grant_cache.test @@ -0,0 +1,160 @@ +# Grant tests not performed with embedded server +-- source include/not_embedded.inc +-- source include/have_query_cache.inc + +--source include/add_anonymous_users.inc + +# +# Test grants with query cache +# +--disable_warnings +drop table if exists test.t1,mysqltest.t1,mysqltest.t2; +drop database if exists mysqltest; +--enable_warnings + +set GLOBAL query_cache_size=1355776; + +reset query cache; +flush status; +connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connection root; +show grants for current_user; +show grants; +--disable_warnings +create database if not exists mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int,b int,c int); +create table mysqltest.t2 (a int,b int,c int); +insert into mysqltest.t1 values (1,1,1),(2,2,2); +insert into mysqltest.t2 values (3,3,3); +create table test.t1 (a char (10)) engine=myisam; +insert into test.t1 values ("test.t1"); +select * from t1; +connect (root2,localhost,root,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK); +connection root2; +# put queries in cache +select * from t1; +select a from t1; +select c from t1; +select * from t2; +select * from mysqltest.t1,test.t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits%"; + +# Create the test users +grant SELECT on mysqltest.* to mysqltest_1@localhost; +grant SELECT on mysqltest.t1 to mysqltest_2@localhost; +grant SELECT on test.t1 to mysqltest_2@localhost; +grant SELECT(a) on mysqltest.t1 to mysqltest_3@localhost; + +# The following queries should be fetched from cache +connect (user1,localhost,mysqltest_1,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK); +connection user1; +show grants for current_user(); +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +show status like "Qcache_not_cached"; +select "user1"; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +show status like "Qcache_not_cached"; +select * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +show status like "Qcache_not_cached"; +# The pre and end space are intentional + select a from t1 ; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +show status like "Qcache_not_cached"; +select c from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +show status like "Qcache_not_cached"; + +# Don't use '' as user because it will pick Unix login +connect (unkuser,localhost,unkuser,,,$MASTER_MYPORT,$MASTER_MYSOCK); +connection unkuser; +show grants for current_user(); + +# The following queries should be fetched from cache +connect (user2,localhost,mysqltest_2,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK); +connection user2; +select "user2"; +select * from t1; +select a from t1; +select c from t1; +select * from mysqltest.t1,test.t1; +--replace_result 127.0.0.1 localhost +--error 1142 +select * from t2; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +show status like "Qcache_not_cached"; + +# The following queries should not be fetched from cache +connect (user3,localhost,mysqltest_3,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK); +connection user3; +select "user3"; +--replace_result 127.0.0.1 localhost +--error 1142 +select * from t1; +select a from t1; +--replace_result 127.0.0.1 localhost +--error 1143 +select c from t1; +--replace_result 127.0.0.1 localhost +--error 1142 +select * from t2; +--replace_result 127.0.0.1 localhost +--error 1143 +select mysqltest.t1.c from test.t1,mysqltest.t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +show status like "Qcache_not_cached"; + +# Connect without a database +connect (user4,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK); +connection user4; +select "user4"; +show grants; +--error 1046 +select a from t1; +# The following query is not cached before (different database) +select * from mysqltest.t1,test.t1; +# Cache a query with 'no database' +select a from mysqltest.t1; +select a from mysqltest.t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_hits"; +show status like "Qcache_not_cached"; + +# Cleanup + +connection root; +# +# A temporary 4.1 workaround to make this test pass if +# mysql was compiled with other than latin1 --with-charset=XXX. +# Without "set names binary" the below queries fail with +# "Illegal mix of collations" error. +# In 5.0 we will change grant tables to use NCHAR(N) instead +# of "CHAR(N) BINARY", and use cast-to-nchar: N'mysqltest_1'. +# +set names binary; +delete from mysql.user where user in ("mysqltest_1","mysqltest_2","mysqltest_3"); +delete from mysql.db where user in ("mysqltest_1","mysqltest_2","mysqltest_3"); +delete from mysql.tables_priv where user in ("mysqltest_1","mysqltest_2","mysqltest_3"); +delete from mysql.columns_priv where user in ("mysqltest_1","mysqltest_2","mysqltest_3"); +flush privileges; +drop table test.t1,mysqltest.t1,mysqltest.t2; +drop database mysqltest; + +set GLOBAL query_cache_size=default; + +--source include/delete_anonymous_users.inc + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/greedy_optimizer.test b/mysql-test/suite/pbxt/t/greedy_optimizer.test new file mode 100644 index 00000000000..fd0be172e83 --- /dev/null +++ b/mysql-test/suite/pbxt/t/greedy_optimizer.test @@ -0,0 +1,317 @@ +# +# A simple test of the greedy query optimization algorithm and the switches that +# control the optimizationprocess. +# + +# +# Schema +# +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6,t7; +--enable_warnings + +create table t1 ( + c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer, + primary key (c11) +); +create table t2 ( + c21 integer,c22 integer,c23 integer,c24 integer,c25 integer,c26 integer +); +create table t3 ( + c31 integer,c32 integer,c33 integer,c34 integer,c35 integer,c36 integer, + primary key (c31) +); +create table t4 ( + c41 integer,c42 integer,c43 integer,c44 integer,c45 integer,c46 integer +); +create table t5 ( + c51 integer,c52 integer,c53 integer,c54 integer,c55 integer,c56 integer, + primary key (c51) +); +create table t6 ( + c61 integer,c62 integer,c63 integer,c64 integer,c65 integer,c66 integer +); +create table t7 ( + c71 integer,c72 integer,c73 integer,c74 integer,c75 integer,c76 integer, + primary key (c71) +); + +# +# Data +# cardinality(Ti) = cardinality(T(i-1)) + 3 +# +insert into t1 values (1,2,3,4,5,6); +insert into t1 values (2,2,3,4,5,6); +insert into t1 values (3,2,3,4,5,6); + +insert into t2 values (1,2,3,4,5,6); +insert into t2 values (2,2,3,4,5,6); +insert into t2 values (3,2,3,4,5,6); +insert into t2 values (4,2,3,4,5,6); +insert into t2 values (5,2,3,4,5,6); +insert into t2 values (6,2,3,4,5,6); + +insert into t3 values (1,2,3,4,5,6); +insert into t3 values (2,2,3,4,5,6); +insert into t3 values (3,2,3,4,5,6); +insert into t3 values (4,2,3,4,5,6); +insert into t3 values (5,2,3,4,5,6); +insert into t3 values (6,2,3,4,5,6); +insert into t3 values (7,2,3,4,5,6); +insert into t3 values (8,2,3,4,5,6); +insert into t3 values (9,2,3,4,5,6); + +insert into t4 values (1,2,3,4,5,6); +insert into t4 values (2,2,3,4,5,6); +insert into t4 values (3,2,3,4,5,6); +insert into t4 values (4,2,3,4,5,6); +insert into t4 values (5,2,3,4,5,6); +insert into t4 values (6,2,3,4,5,6); +insert into t4 values (7,2,3,4,5,6); +insert into t4 values (8,2,3,4,5,6); +insert into t4 values (9,2,3,4,5,6); +insert into t4 values (10,2,3,4,5,6); +insert into t4 values (11,2,3,4,5,6); +insert into t4 values (12,2,3,4,5,6); + +insert into t5 values (1,2,3,4,5,6); +insert into t5 values (2,2,3,4,5,6); +insert into t5 values (3,2,3,4,5,6); +insert into t5 values (4,2,3,4,5,6); +insert into t5 values (5,2,3,4,5,6); +insert into t5 values (6,2,3,4,5,6); +insert into t5 values (7,2,3,4,5,6); +insert into t5 values (8,2,3,4,5,6); +insert into t5 values (9,2,3,4,5,6); +insert into t5 values (10,2,3,4,5,6); +insert into t5 values (11,2,3,4,5,6); +insert into t5 values (12,2,3,4,5,6); +insert into t5 values (13,2,3,4,5,6); +insert into t5 values (14,2,3,4,5,6); +insert into t5 values (15,2,3,4,5,6); + +insert into t6 values (1,2,3,4,5,6); +insert into t6 values (2,2,3,4,5,6); +insert into t6 values (3,2,3,4,5,6); +insert into t6 values (4,2,3,4,5,6); +insert into t6 values (5,2,3,4,5,6); +insert into t6 values (6,2,3,4,5,6); +insert into t6 values (7,2,3,4,5,6); +insert into t6 values (8,2,3,4,5,6); +insert into t6 values (9,2,3,4,5,6); +insert into t6 values (10,2,3,4,5,6); +insert into t6 values (11,2,3,4,5,6); +insert into t6 values (12,2,3,4,5,6); +insert into t6 values (13,2,3,4,5,6); +insert into t6 values (14,2,3,4,5,6); +insert into t6 values (15,2,3,4,5,6); +insert into t6 values (16,2,3,4,5,6); +insert into t6 values (17,2,3,4,5,6); +insert into t6 values (18,2,3,4,5,6); + +insert into t7 values (1,2,3,4,5,6); +insert into t7 values (2,2,3,4,5,6); +insert into t7 values (3,2,3,4,5,6); +insert into t7 values (4,2,3,4,5,6); +insert into t7 values (5,2,3,4,5,6); +insert into t7 values (6,2,3,4,5,6); +insert into t7 values (7,2,3,4,5,6); +insert into t7 values (8,2,3,4,5,6); +insert into t7 values (9,2,3,4,5,6); +insert into t7 values (10,2,3,4,5,6); +insert into t7 values (11,2,3,4,5,6); +insert into t7 values (12,2,3,4,5,6); +insert into t7 values (13,2,3,4,5,6); +insert into t7 values (14,2,3,4,5,6); +insert into t7 values (15,2,3,4,5,6); +insert into t7 values (16,2,3,4,5,6); +insert into t7 values (17,2,3,4,5,6); +insert into t7 values (18,2,3,4,5,6); +insert into t7 values (19,2,3,4,5,6); +insert into t7 values (20,2,3,4,5,6); +insert into t7 values (21,2,3,4,5,6); + +# +# The actual test begins here +# + +# Check the default values for the optimizer paramters + +select @@optimizer_search_depth; +select @@optimizer_prune_level; + +# This value swithes back to the old implementation of 'find_best()' +# set optimizer_search_depth=63; - old (independent of the optimizer_prune_level) +# +# These are the values for the parameters that control the greedy optimizer +# (total 6 combinations - 3 for optimizer_search_depth, 2 for optimizer_prune_level): +# +# set optimizer_search_depth=0; - automatic +# set optimizer_search_depth=1; - min +# set optimizer_search_depth=62; - max (default) +# +# set optimizer_prune_level=0 - exhaustive; +# set optimizer_prune_level=1 - heuristic; # default + + +# +# Compile several queries with all combinations of the query +# optimizer parameters. Each test query has two variants, where +# in the second variant the tables in the FROM clause are in +# inverse order to the tables in the first variant. +# Due to pre-sorting of tables before compilation, there should +# be no difference in the plans for each two such query variants. +# + +# First, for reference compile the test queries with the 'old' optimization +# procedure 'find_best'. Notice that 'find_best' does not depend on the +# choice of heuristic. + +set optimizer_search_depth=63; +select @@optimizer_search_depth; + +# 6-table join, chain +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, star +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, clique +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; + + +# Test the new optimization procedures + +set optimizer_prune_level=0; +select @@optimizer_prune_level; + +set optimizer_search_depth=0; +select @@optimizer_search_depth; + +# 6-table join, chain +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, star +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, clique +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; + +set optimizer_search_depth=1; +select @@optimizer_search_depth; + +# 6-table join, chain +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, star +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, clique +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; + +set optimizer_search_depth=62; +select @@optimizer_search_depth; + +# 6-table join, chain +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, star +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, clique +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; + + +set optimizer_prune_level=1; +select @@optimizer_prune_level; + +set optimizer_search_depth=0; +select @@optimizer_search_depth; + +# 6-table join, chain +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, star +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, clique +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; + +set optimizer_search_depth=1; +select @@optimizer_search_depth; + +# 6-table join, chain +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, star +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, clique +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; + +set optimizer_search_depth=62; +select @@optimizer_search_depth; + +# 6-table join, chain +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, star +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71; +show status like 'Last_query_cost'; +# 6-table join, clique +explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; +explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76; +show status like 'Last_query_cost'; + +drop table t1,t2,t3,t4,t5,t6,t7; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/group_by.test b/mysql-test/suite/pbxt/t/group_by.test new file mode 100644 index 00000000000..c1909668b55 --- /dev/null +++ b/mysql-test/suite/pbxt/t/group_by.test @@ -0,0 +1,720 @@ + +# Initialise +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +# +# Simple test without tables + +-- error 1111 +SELECT 1 FROM (SELECT 1) as a GROUP BY SUM(1); + +# +# Test of group (Failed for Lars Hoss <lh@pbm.de>) +# + +CREATE TABLE t1 ( + spID int(10) unsigned, + userID int(10) unsigned, + score smallint(5) unsigned, + lsg char(40), + date date +); + +INSERT INTO t1 VALUES (1,1,1,'','0000-00-00'); +INSERT INTO t1 VALUES (2,2,2,'','0000-00-00'); +INSERT INTO t1 VALUES (2,1,1,'','0000-00-00'); +INSERT INTO t1 VALUES (3,3,3,'','0000-00-00'); + +CREATE TABLE t2 ( + userID int(10) unsigned NOT NULL auto_increment, + niName char(15), + passwd char(8), + mail char(50), + isAukt enum('N','Y') DEFAULT 'N', + vName char(30), + nName char(40), + adr char(60), + plz char(5), + ort char(35), + land char(20), + PRIMARY KEY (userID) +); + +INSERT INTO t2 VALUES (1,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (2,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (3,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (4,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (5,'name','pass','mail','Y','v','n','adr','1','1','1'); + +SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID GROUP BY t2.userid; +SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID GROUP BY t2.userid ORDER BY NULL; +SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid; +SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid; +SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; +EXPLAIN SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; +drop table t1,t2; + +# +# Bug in GROUP BY, by Nikki Chumakov <nikki@saddam.cityline.ru> +# + +CREATE TABLE t1 ( + PID int(10) unsigned NOT NULL auto_increment, + payDate date DEFAULT '0000-00-00' NOT NULL, + recDate datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, + URID int(10) unsigned DEFAULT '0' NOT NULL, + CRID int(10) unsigned DEFAULT '0' NOT NULL, + amount int(10) unsigned DEFAULT '0' NOT NULL, + operator int(10) unsigned, + method enum('unknown','cash','dealer','check','card','lazy','delayed','test') DEFAULT 'unknown' NOT NULL, + DIID int(10) unsigned, + reason char(1) binary DEFAULT '' NOT NULL, + code_id int(10) unsigned, + qty mediumint(8) unsigned DEFAULT '0' NOT NULL, + PRIMARY KEY (PID), + KEY URID (URID), + KEY reason (reason), + KEY method (method), + KEY payDate (payDate) +); + +INSERT INTO t1 VALUES (1,'1970-01-01','1997-10-17 00:00:00',2529,1,21000,11886,'check',0,'F',16200,6); + +--error 1056 +SELECT COUNT(P.URID),SUM(P.amount),P.method, MIN(PP.recdate+0) > 19980501000000 AS IsNew FROM t1 AS P JOIN t1 as PP WHERE P.URID = PP.URID GROUP BY method,IsNew; + +drop table t1; + +# +# Problem with GROUP BY + ORDER BY when no match +# Tested with locking +# + +CREATE TABLE t1 ( + cid mediumint(9) NOT NULL auto_increment, + firstname varchar(32) DEFAULT '' NOT NULL, + surname varchar(32) DEFAULT '' NOT NULL, + PRIMARY KEY (cid) +); +INSERT INTO t1 VALUES (1,'That','Guy'); +INSERT INTO t1 VALUES (2,'Another','Gent'); + +CREATE TABLE t2 ( + call_id mediumint(8) NOT NULL auto_increment, + contact_id mediumint(8) DEFAULT '0' NOT NULL, + PRIMARY KEY (call_id), + KEY contact_id (contact_id) +); + +lock tables t1 read,t2 write; + +INSERT INTO t2 VALUES (10,2); +INSERT INTO t2 VALUES (18,2); +INSERT INTO t2 VALUES (62,2); +INSERT INTO t2 VALUES (91,2); +INSERT INTO t2 VALUES (92,2); + +SELECT cid, CONCAT(firstname, ' ', surname), COUNT(call_id) FROM t1 LEFT JOIN t2 ON cid=contact_id WHERE firstname like '%foo%' GROUP BY cid; +SELECT cid, CONCAT(firstname, ' ', surname), COUNT(call_id) FROM t1 LEFT JOIN t2 ON cid=contact_id WHERE firstname like '%foo%' GROUP BY cid ORDER BY NULL; +SELECT HIGH_PRIORITY cid, CONCAT(firstname, ' ', surname), COUNT(call_id) FROM t1 LEFT JOIN t2 ON cid=contact_id WHERE firstname like '%foo%' GROUP BY cid ORDER BY surname, firstname; + +drop table t1,t2; +unlock tables; + +# +# Test of group by bug in bugzilla +# + +CREATE TABLE t1 ( + bug_id mediumint(9) NOT NULL auto_increment, + groupset bigint(20) DEFAULT '0' NOT NULL, + assigned_to mediumint(9) DEFAULT '0' NOT NULL, + bug_file_loc text, + bug_severity enum('blocker','critical','major','normal','minor','trivial','enhancement') DEFAULT 'blocker' NOT NULL, + bug_status enum('','NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED') DEFAULT 'NEW' NOT NULL, + creation_ts datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, + delta_ts timestamp, + short_desc mediumtext, + long_desc mediumtext, + op_sys enum('All','Windows 3.1','Windows 95','Windows 98','Windows NT','Windows 2000','Linux','other') DEFAULT 'All' NOT NULL, + priority enum('P1','P2','P3','P4','P5') DEFAULT 'P1' NOT NULL, + product varchar(64) DEFAULT '' NOT NULL, + rep_platform enum('All','PC','VTD-8','Other'), + reporter mediumint(9) DEFAULT '0' NOT NULL, + version varchar(16) DEFAULT '' NOT NULL, + component varchar(50) DEFAULT '' NOT NULL, + resolution enum('','FIXED','INVALID','WONTFIX','LATER','REMIND','DUPLICATE','WORKSFORME') DEFAULT '' NOT NULL, + target_milestone varchar(20) DEFAULT '' NOT NULL, + qa_contact mediumint(9) DEFAULT '0' NOT NULL, + status_whiteboard mediumtext NOT NULL, + votes mediumint(9) DEFAULT '0' NOT NULL, + PRIMARY KEY (bug_id), + KEY assigned_to (assigned_to), + KEY creation_ts (creation_ts), + KEY delta_ts (delta_ts), + KEY bug_severity (bug_severity), + KEY bug_status (bug_status), + KEY op_sys (op_sys), + KEY priority (priority), + KEY product (product), + KEY reporter (reporter), + KEY version (version), + KEY component (component), + KEY resolution (resolution), + KEY target_milestone (target_milestone), + KEY qa_contact (qa_contact), + KEY votes (votes) +); + +INSERT INTO t1 VALUES (1,0,0,'','normal','','2000-02-10 09:25:12',20000321114747,'','','Linux','P1','TestProduct','PC',3,'other','TestComponent','','M1',0,'',0); +INSERT INTO t1 VALUES (9,0,0,'','enhancement','','2000-03-10 11:49:36',20000321114747,'','','All','P5','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - conversion','','',0,'',0); +INSERT INTO t1 VALUES (10,0,0,'','enhancement','','2000-03-10 18:10:16',20000321114747,'','','All','P4','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - conversion','','',0,'',0); +INSERT INTO t1 VALUES (7,0,0,'','critical','','2000-03-09 10:50:21',20000321114747,'','','All','P1','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - generic','','',0,'',0); +INSERT INTO t1 VALUES (6,0,0,'','normal','','2000-03-09 10:42:44',20000321114747,'','','All','P2','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0); +INSERT INTO t1 VALUES (8,0,0,'','major','','2000-03-09 11:32:14',20000321114747,'','','All','P3','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0); +INSERT INTO t1 VALUES (5,0,0,'','enhancement','','2000-03-09 10:38:59',20000321114747,'','','All','P5','CCC/CCCCCC','PC',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (4,0,0,'','normal','','2000-03-08 18:32:14',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent2','','',0,'',0); +INSERT INTO t1 VALUES (3,0,0,'','normal','','2000-03-08 18:30:52',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent','','',0,'',0); +INSERT INTO t1 VALUES (2,0,0,'','enhancement','','2000-03-08 18:24:51',20000321114747,'','','All','P2','TestProduct','Other',4,'other','TestComponent2','','',0,'',0); +INSERT INTO t1 VALUES (11,0,0,'','blocker','','2000-03-13 09:43:41',20000321114747,'','','All','P2','CCC/CCCCCC','PC',5,'7.00','DDDDDDDDD','','',0,'',0); +INSERT INTO t1 VALUES (12,0,0,'','normal','','2000-03-13 16:14:31',20000321114747,'','','All','P2','AAAAA','PC',3,'2.00 CD - Pre','kkkkkkkkkkk lllllllllll','','',0,'',0); +INSERT INTO t1 VALUES (13,0,0,'','normal','','2000-03-15 16:20:44',20000321114747,'','','other','P2','TestProduct','Other',3,'other','TestComponent','','',0,'',0); +INSERT INTO t1 VALUES (14,0,0,'','blocker','','2000-03-15 18:13:47',20000321114747,'','','All','P1','AAAAA','PC',3,'2.00 CD - Pre','BBBBBBBBBBBBB - generic','','',0,'',0); +INSERT INTO t1 VALUES (15,0,0,'','minor','','2000-03-16 18:03:28',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','DDDDDDDDD','','',0,'',0); +INSERT INTO t1 VALUES (16,0,0,'','normal','','2000-03-16 18:33:41',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (17,0,0,'','normal','','2000-03-16 18:34:18',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (18,0,0,'','normal','','2000-03-16 18:34:56',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (19,0,0,'','enhancement','','2000-03-16 18:35:34',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (20,0,0,'','enhancement','','2000-03-16 18:36:23',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (21,0,0,'','enhancement','','2000-03-16 18:37:23',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (22,0,0,'','enhancement','','2000-03-16 18:38:16',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','Administration','','',0,'',0); +INSERT INTO t1 VALUES (23,0,0,'','normal','','2000-03-16 18:58:12',20000321114747,'','','All','P2','CCC/CCCCCC','Other',5,'7.00','DDDDDDDDD','','',0,'',0); +INSERT INTO t1 VALUES (24,0,0,'','normal','','2000-03-17 11:08:10',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0); +INSERT INTO t1 VALUES (25,0,0,'','normal','','2000-03-17 11:10:45',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0); +INSERT INTO t1 VALUES (26,0,0,'','normal','','2000-03-17 11:15:47',20000321114747,'','','All','P2','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0); +INSERT INTO t1 VALUES (27,0,0,'','normal','','2000-03-17 17:45:41',20000321114747,'','','All','P2','CCC/CCCCCC','PC',5,'7.00','DDDDDDDDD','','',0,'',0); +INSERT INTO t1 VALUES (28,0,0,'','normal','','2000-03-20 09:51:45',20000321114747,'','','Windows NT','P2','TestProduct','PC',8,'other','TestComponent','','',0,'',0); +INSERT INTO t1 VALUES (29,0,0,'','normal','','2000-03-20 11:15:09',20000321114747,'','','All','P5','AAAAAAAA-AAA','PC',3,'2.8','Web Interface','','',0,'',0); +CREATE TABLE t2 ( + value tinytext, + program varchar(64), + initialowner tinytext NOT NULL, + initialqacontact tinytext NOT NULL, + description mediumtext NOT NULL +); + +INSERT INTO t2 VALUES ('TestComponent','TestProduct','id0001','',''); +INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - conversion','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - generic','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('TestComponent2','TestProduct','id0001','',''); +INSERT INTO t2 VALUES ('BBBBBBBBBBBBB - eeeeeeeee','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('kkkkkkkkkkk lllllllllll','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('Test Procedures','AAAAA','id0001','',''); +INSERT INTO t2 VALUES ('Documentation','AAAAA','id0003','',''); +INSERT INTO t2 VALUES ('DDDDDDDDD','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Eeeeeeee Lite','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Eeeeeeee Full','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Administration','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Distribution','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Setup','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Unspecified','CCC/CCCCCC','id0002','',''); +INSERT INTO t2 VALUES ('Web Interface','AAAAAAAA-AAA','id0001','',''); +INSERT INTO t2 VALUES ('Host communication','AAAAA','id0001','',''); +select value,description,bug_id from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA"; +select value,description,COUNT(bug_id) from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA" group by value; +select value,description,COUNT(bug_id) from t2 left join t1 on t2.program=t1.product and t2.value=t1.component where program="AAAAA" group by value having COUNT(bug_id) IN (0,2); + +drop table t1,t2; + +# +# Problem with functions and group functions when no matching rows +# + +create table t1 (foo int); +insert into t1 values (1); +select 1+1, "a",count(*) from t1 where foo in (2); +insert into t1 values (1); +select 1+1,"a",count(*) from t1 where foo in (2); +drop table t1; + +# +# Test GROUP BY DESC + +CREATE TABLE t1 ( + spID int(10) unsigned, + userID int(10) unsigned, + score smallint(5) unsigned, + key (spid), + key (score) +); + +INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3),(6,3,3),(7,3,3); +explain select userid,count(*) from t1 group by userid desc; +explain select userid,count(*) from t1 group by userid desc order by null; +select userid,count(*) from t1 group by userid desc; +select userid,count(*) from t1 group by userid desc having (count(*)+1) IN (4,3); +select userid,count(*) from t1 group by userid desc having 3 IN (1,COUNT(*)); +explain select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; +explain select spid,count(*) from t1 where spid between 1 and 2 group by spid; +explain select spid,count(*) from t1 where spid between 1 and 2 group by spid order by null; +select spid,count(*) from t1 where spid between 1 and 2 group by spid; +select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; +explain extended select sql_big_result spid,sum(userid) from t1 group by spid desc; +explain select sql_big_result spid,sum(userid) from t1 group by spid desc order by null; +select sql_big_result spid,sum(userid) from t1 group by spid desc; +explain select sql_big_result score,count(*) from t1 group by score desc; +explain select sql_big_result score,count(*) from t1 group by score desc order by null; +select sql_big_result score,count(*) from t1 group by score desc; +drop table t1; + +# not purely group_by bug, but group_by is involved... + +create table t1 (a date default null, b date default null); +insert t1 values ('1999-10-01','2000-01-10'), ('1997-01-01','1998-10-01'); +select a,min(b) c,count(distinct rand()) from t1 group by a having c<a + interval 1 day; +drop table t1; + +# Compare with hash keys + +CREATE TABLE t1 (a char(1)); +INSERT INTO t1 VALUES ('A'),('B'),('A'),('B'),('A'),('B'),(NULL),('a'),('b'),(NULL),('A'),('B'),(NULL); +SELECT a FROM t1 GROUP BY a; +SELECT a,count(*) FROM t1 GROUP BY a; +SELECT a FROM t1 GROUP BY binary a; +SELECT a,count(*) FROM t1 GROUP BY binary a; +SELECT binary a FROM t1 GROUP BY 1; +SELECT binary a,count(*) FROM t1 GROUP BY 1; +# Do the same tests with MyISAM temporary tables +SET SQL_BIG_TABLES=1; +SELECT a FROM t1 GROUP BY a; +SELECT a,count(*) FROM t1 GROUP BY a; +SELECT a FROM t1 GROUP BY binary a; +SELECT a,count(*) FROM t1 GROUP BY binary a; +SELECT binary a FROM t1 GROUP BY 1; +SELECT binary a,count(*) FROM t1 GROUP BY 1; +SET SQL_BIG_TABLES=0; +drop table t1; + +# +# Test of key >= 256 bytes +# + +CREATE TABLE t1 ( + `a` char(193) default NULL, + `b` char(63) default NULL +); +INSERT INTO t1 VALUES ('abc','def'),('hij','klm'); +SELECT CONCAT(a, b) FROM t1 GROUP BY 1; +SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1; +SELECT CONCAT(a, b),count(distinct a) FROM t1 GROUP BY 1; +SELECT 1 FROM t1 GROUP BY CONCAT(a, b); +INSERT INTO t1 values ('hij','klm'); +SELECT CONCAT(a, b),count(*) FROM t1 GROUP BY 1; +DROP TABLE t1; + +# +# Test problem with ORDER BY on a SUM() column +# + +create table t1 (One int unsigned, Two int unsigned, Three int unsigned, Four int unsigned); +insert into t1 values (1,2,1,4),(1,2,2,4),(1,2,3,4),(1,2,4,4),(1,1,1,4),(1,1,2,4),(1,1,3,4),(1,1,4,4),(1,3,1,4),(1,3,2,4),(1,3,3,4),(1,3,4,4); +select One, Two, sum(Four) from t1 group by One,Two; +drop table t1; + +create table t1 (id integer primary key not null auto_increment, gender char(1)); +insert into t1 values (NULL, 'M'), (NULL, 'F'),(NULL, 'F'),(NULL, 'F'),(NULL, 'M'); +create table t2 (user_id integer not null, date date); +insert into t2 values (1, '2002-06-09'),(2, '2002-06-09'),(1, '2002-06-09'),(3, '2002-06-09'),(4, '2002-06-09'),(4, '2002-06-09'); +select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender; +select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender order by percentage; +drop table t1,t2; + +# +# The GROUP BY returned rows in wrong order in 3.23.51 +# + +CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID +)); +insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); +select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; +select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1; +drop table t1; + +# +# Problem with MAX and LEFT JOIN +# + +CREATE TABLE t1 ( + pid int(11) unsigned NOT NULL default '0', + c1id int(11) unsigned default NULL, + c2id int(11) unsigned default NULL, + value int(11) unsigned NOT NULL default '0', + UNIQUE KEY pid2 (pid,c1id,c2id), + UNIQUE KEY pid (pid,value) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (1, 1, NULL, 1),(1, 2, NULL, 2),(1, NULL, 3, 3),(1, 4, NULL, 4),(1, 5, NULL, 5); + +CREATE TABLE t2 ( + id int(11) unsigned NOT NULL default '0', + active enum('Yes','No') NOT NULL default 'Yes', + PRIMARY KEY (id) +) ENGINE=MyISAM; + +INSERT INTO t2 VALUES (1, 'Yes'),(2, 'No'),(4, 'Yes'),(5, 'No'); + +CREATE TABLE t3 ( + id int(11) unsigned NOT NULL default '0', + active enum('Yes','No') NOT NULL default 'Yes', + PRIMARY KEY (id) +); +INSERT INTO t3 VALUES (3, 'Yes'); + +select * from t1 AS m LEFT JOIN t2 AS c1 ON m.c1id = +c1.id AND c1.active = 'Yes' LEFT JOIN t3 AS c2 ON m.c2id = c2.id AND +c2.active = 'Yes' WHERE m.pid=1 AND (c1.id IS NOT NULL OR c2.id IS NOT NULL); +select max(value) from t1 AS m LEFT JOIN t2 AS c1 ON +m.c1id = c1.id AND c1.active = 'Yes' LEFT JOIN t3 AS c2 ON m.c2id = +c2.id AND c2.active = 'Yes' WHERE m.pid=1 AND (c1.id IS NOT NULL OR c2.id IS +NOT NULL); +drop table t1,t2,t3; + +# +# Test bug in GROUP BY on BLOB that is NULL or empty +# + +create table t1 (a blob null); +insert into t1 values (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(""),(""),(""),("b"); +select a,count(*) from t1 group by a; +set option sql_big_tables=1; +select a,count(*) from t1 group by a; +drop table t1; + +# +# Test of GROUP BY ... ORDER BY NULL optimization +# + +create table t1 (a int not null, b int not null); +insert into t1 values (1,1),(1,2),(3,1),(3,2),(2,2),(2,1); +create table t2 (a int not null, b int not null, key(a)); +insert into t2 values (1,3),(3,1),(2,2),(1,1); +select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b; +select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b ORDER BY NULL; +explain select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b; +explain select t1.a,t2.b from t1,t2 where t1.a=t2.a group by t1.a,t2.b ORDER BY NULL; +drop table t1,t2; + +# +# group function arguments in some functions +# + +create table t1 (a int, b int); +insert into t1 values (1, 4),(10, 40),(1, 4),(10, 43),(1, 4),(10, 41),(1, 4),(10, 43),(1, 4); +select a, MAX(b), INTERVAL (MAX(b), 1,3,10,30,39,40,50,60,100,1000) from t1 group by a; +select a, MAX(b), CASE MAX(b) when 4 then 4 when 43 then 43 else 0 end from t1 group by a; +select a, MAX(b), FIELD(MAX(b), '43', '4', '5') from t1 group by a; +select a, MAX(b), CONCAT_WS(MAX(b), '43', '4', '5') from t1 group by a; +select a, MAX(b), ELT(MAX(b), 'a', 'b', 'c', 'd', 'e', 'f') from t1 group by a; +select a, MAX(b), MAKE_SET(MAX(b), 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h') from t1 group by a; +drop table t1; + +# +# Problem with group by and alias +# + +create table t1 (id int not null, qty int not null); +insert into t1 values (1,2),(1,3),(2,4),(2,5); +select id, sum(qty) as sqty, count(qty) as cqty from t1 group by id having sum(qty)>2 and cqty>1; +select id, sum(qty) as sqty from t1 group by id having sqty>2 and count(qty)>1; +select id, sum(qty) as sqty, count(qty) as cqty from t1 group by id having sqty>2 and cqty>1; +select id, sum(qty) as sqty, count(qty) as cqty from t1 group by id having sum(qty)>2 and count(qty)>1; +select count(*), case interval(qty,2,3,4,5,6,7,8) when -1 then NULL when 0 then "zero" when 1 then "one" when 2 then "two" end as category from t1 group by category; +select count(*), interval(qty,2,3,4,5,6,7,8) as category from t1 group by category; +drop table t1; +# +# Tests for bug #1355: 'Using filesort' is missing in EXPLAIN when ORDER BY +# NULL is used. +# +CREATE TABLE t1 ( + userid int(10) unsigned, + score smallint(5) unsigned, + key (score) +); +INSERT INTO t1 VALUES (1,1),(2,2),(1,1),(3,3),(3,3),(3,3),(3,3),(3,3); +# Here we select unordered GROUP BY into a temporary talbe, +# and then sort it with filesort (GROUP BY in MySQL +# implies sorted order of results) +SELECT userid,count(*) FROM t1 GROUP BY userid DESC; +EXPLAIN SELECT userid,count(*) FROM t1 GROUP BY userid DESC; +DROP TABLE t1; +CREATE TABLE t1 ( + i int(11) default NULL, + j int(11) default NULL +); +INSERT INTO t1 VALUES (1,2),(2,3),(4,5),(3,5),(1,5),(23,5); +SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; +explain SELECT i, COUNT(DISTINCT(i)) FROM t1 GROUP BY j ORDER BY NULL; +DROP TABLE t1; + +#Test for BUG#6976: Aggregate functions have incorrect NULL-ness +create table t1 (a int); +insert into t1 values(null); +select min(a) is null from t1; +select min(a) is null or null from t1; +select 1 and min(a) is null from t1; +drop table t1; + +# Test for BUG#5400: GROUP_CONCAT returns everything twice. +create table t1 ( col1 int, col2 int ); +insert into t1 values (1,1),(1,2),(1,3),(2,1),(2,2); +select group_concat( distinct col1 ) as alias from t1 + group by col2 having alias like '%'; + +drop table t1; + +# +# Test BUG#8216 when referring in HAVING to n alias which is rand() function +# + +create table t1 (a integer, b integer, c integer); +insert into t1 (a,b) values (1,2),(1,3),(2,5); +select a, 0.1*0+1 r2, sum(1) r1 from t1 where a = 1 group by a having r1>1 and r2=1; +# rand(100)*10 will be < 2 only for the first row (of 6) +select a, round(rand(100)*10) r2, sum(1) r1 from t1 where a = 1 group by a having r1>1 and r2<=2; +select a,sum(b) from t1 where a=1 group by c; +select a*sum(b) from t1 where a=1 group by c; +select sum(a)*sum(b) from t1 where a=1 group by c; +select a,sum(b) from t1 where a=1 group by c having a=1; +select a as d,sum(b) from t1 where a=1 group by c having d=1; +select sum(a)*sum(b) as d from t1 where a=1 group by c having d > 0; +drop table t1; + +# Test for BUG#9213 GROUP BY query on utf-8 key returns wrong results +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(8),(9); +create table t2 ( + a int, + b varchar(200) NOT NULL, + c varchar(50) NOT NULL, + d varchar(100) NOT NULL, + primary key (a,b(132),c,d), + key a (a,b) +) charset=utf8; + +insert into t2 select + x3.a, -- 3 + concat('val-', x3.a + 3*x4.a), -- 12 + concat('val-', @a:=x3.a + 3*x4.a + 12*C.a), -- 120 + concat('val-', @a + 120*D.a) +from t1 x3, t1 x4, t1 C, t1 D where x3.a < 3 and x4.a < 4 and D.a < 4; + +delete from t2 where a = 2 and b = 'val-2' order by a,b,c,d limit 30; +# PBXT: row count may vary +--replace_column 9 # +explain select c from t2 where a = 2 and b = 'val-2' group by c; +select c from t2 where a = 2 and b = 'val-2' group by c; +drop table t1,t2; + +# Test for BUG#9298 "Wrong handling of int4 unsigned columns in GROUP functions" +# (the actual problem was with protocol code, not GROUP BY) +create table t1 (b int4 unsigned not null); +insert into t1 values(3000000000); +select * from t1; +select min(b) from t1; +drop table t1; + +# +# Test for bug #11088: GROUP BY a BLOB column with COUNT(DISTINCT column1) +# + +CREATE TABLE t1 (id int PRIMARY KEY, user_id int, hostname longtext); + +INSERT INTO t1 VALUES + (1, 7, 'cache-dtc-af05.proxy.aol.com'), + (2, 3, 'what.ever.com'), + (3, 7, 'cache-dtc-af05.proxy.aol.com'), + (4, 7, 'cache-dtc-af05.proxy.aol.com'); + +SELECT hostname, COUNT(DISTINCT user_id) as no FROM t1 + WHERE hostname LIKE '%aol%' + GROUP BY hostname; + +DROP TABLE t1; + +# +# Test for bug #8614: GROUP BY 'const' with DISTINCT +# + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,2), (1,3); +SELECT a, b FROM t1 GROUP BY 'const'; +SELECT DISTINCT a, b FROM t1 GROUP BY 'const'; + +DROP TABLE t1; + +# +# Test for bug #11385: GROUP BY for datetime converted to decimals +# + +CREATE TABLE t1 (id INT, dt DATETIME); +INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); +INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); +INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); +INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); +SELECT dt DIV 1 AS f, id FROM t1 GROUP BY f; + +DROP TABLE t1; + +# +# Test for bug #11295: GROUP BY a BLOB column with COUNT(DISTINCT column1) +# when the BLOB column takes NULL values +# + +CREATE TABLE t1 (id varchar(20) NOT NULL); +INSERT INTO t1 VALUES ('trans1'), ('trans2'); +CREATE TABLE t2 (id varchar(20) NOT NULL, err_comment blob NOT NULL); +INSERT INTO t2 VALUES ('trans1', 'a problem'); +SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment + FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; + +DROP TABLE t1, t2; + +# +# Bug #12266 GROUP BY expression on DATE column produces result with +# reduced length +# +create table t1 (f1 date); +insert into t1 values('2005-06-06'); +insert into t1 values('2005-06-06'); +select date(left(f1+0,8)) from t1 group by 1; +drop table t1; + +# +# Test for bug #11414: crash on Windows for a simple GROUP BY query +# + +CREATE TABLE t1 (n int); +INSERT INTO t1 VALUES (1); +SELECT n+1 AS n FROM t1 GROUP BY n; +DROP TABLE t1; + +# +# BUG#12695: Item_func_isnull::update_used_tables +# did not update const_item_cache +# +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +select sql_buffer_result max(f1)+1 from t1; +drop table t1; + +# +# BUG#14019-4.1-opt +# +CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1),(2); + +SELECT a FROM t1 GROUP BY 'a'; +SELECT a FROM t1 GROUP BY "a"; +SELECT a FROM t1 GROUP BY `a`; + +set sql_mode=ANSI_QUOTES; +SELECT a FROM t1 GROUP BY "a"; +SELECT a FROM t1 GROUP BY 'a'; +SELECT a FROM t1 GROUP BY `a`; +set sql_mode=''; + +SELECT a FROM t1 HAVING 'a' > 1; +SELECT a FROM t1 HAVING "a" > 1; +SELECT a FROM t1 HAVING `a` > 1; + +SELECT a FROM t1 ORDER BY 'a' DESC; +SELECT a FROM t1 ORDER BY "a" DESC; +SELECT a FROM t1 ORDER BY `a` DESC; +DROP TABLE t1; + +# End of 4.1 tests + +# +# Bug#11211: Ambiguous column reference in GROUP BY. +# + +create table t1 (c1 char(3), c2 char(3)); +create table t2 (c3 char(3), c4 char(3)); +insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); +insert into t2 values ('aaa', 'bb1'), ('aaa', 'bb2'); + +# query with ambiguous column reference 'c2' +select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 +group by c2; +show warnings; + +# this query has no ambiguity +select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 +group by t1.c1; + +show warnings; +drop table t1, t2; + +# +# Bug #20466: a view is mixing data when there's a trigger on the table +# +CREATE TABLE t1 (a tinyint(3), b varchar(255), PRIMARY KEY (a)); + +INSERT INTO t1 VALUES (1,'-----'), (6,'Allemagne'), (17,'Autriche'), + (25,'Belgique'), (54,'Danemark'), (62,'Espagne'), (68,'France'); + +CREATE TABLE t2 (a tinyint(3), b tinyint(3), PRIMARY KEY (a), KEY b (b)); + +INSERT INTO t2 VALUES (1,1), (2,1), (6,6), (18,17), (15,25), (16,25), + (17,25), (10,54), (5,62),(3,68); + +CREATE VIEW v1 AS select t1.a, concat(t1.b,'') AS b, t1.b as real_b from t1; + +explain +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; + +DROP VIEW v1; +DROP TABLE t1,t2; + +# +# Bug#22781: SQL_BIG_RESULT fails to influence sort plan +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT, key (b)); + +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 SELECT a + 1 , MOD(a + 1 , 20) FROM t1; +INSERT INTO t1 SELECT a + 2 , MOD(a + 2 , 20) FROM t1; +INSERT INTO t1 SELECT a + 4 , MOD(a + 4 , 20) FROM t1; +INSERT INTO t1 SELECT a + 8 , MOD(a + 8 , 20) FROM t1; +INSERT INTO t1 SELECT a + 16, MOD(a + 16, 20) FROM t1; +INSERT INTO t1 SELECT a + 32, MOD(a + 32, 20) FROM t1; +INSERT INTO t1 SELECT a + 64, MOD(a + 64, 20) FROM t1; + +SELECT MIN(b), MAX(b) from t1; + +EXPLAIN SELECT b, sum(1) FROM t1 GROUP BY b; +EXPLAIN SELECT SQL_BIG_RESULT b, sum(1) FROM t1 GROUP BY b; +SELECT b, sum(1) FROM t1 GROUP BY b; +SELECT SQL_BIG_RESULT b, sum(1) FROM t1 GROUP BY b; +DROP TABLE t1; + +# +# Bug #21174: Index degrades sort performance and +# optimizer does not honor IGNORE INDEX +# +CREATE TABLE t1 (a INT, b INT, KEY(a)); +INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4); + +EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2; +EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2; + +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/group_min_max.test b/mysql-test/suite/pbxt/t/group_min_max.test new file mode 100644 index 00000000000..3241e23a903 --- /dev/null +++ b/mysql-test/suite/pbxt/t/group_min_max.test @@ -0,0 +1,948 @@ +# +# Test file for WL#1724 (Min/Max Optimization for Queries with Group By Clause). +# The queries in this file test query execution via QUICK_GROUP_MIN_MAX_SELECT. +# + +# +# TODO: +# Add queries with: +# - C != const +# - C IS NOT NULL +# - HAVING clause + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 ( + a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +); + +insert into t1 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'), +('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'), +('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'), +('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'), +('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'), +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'), +('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'), +('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'), +('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'), +('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'); + +create index idx_t1_0 on t1 (a1); +create index idx_t1_1 on t1 (a1,a2,b,c); +create index idx_t1_2 on t1 (a1,a2,b); +analyze table t1; + +# t2 is the same as t1, but with some NULLs in the MIN/MAX column, and +# one more nullable attribute + +--disable_warnings +drop table if exists t2; +--enable_warnings + +create table t2 ( + a1 char(64), a2 char(64) not null, b char(16), c char(16), d char(16), dummy char(64) default ' ' +); +insert into t2 select * from t1; +# add few rows with NULL's in the MIN/MAX column +insert into t2 (a1, a2, b, c, d) values +('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'), +('a','a','a',NULL,'xyz'), +('a','a','b',NULL,'xyz'), +('a','b','a',NULL,'xyz'), +('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'), +('d','b','b',NULL,'xyz'), +('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'), +('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'), +('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'), +('a','a','a',NULL,'xyz'), +('a','a','b',NULL,'xyz'), +('a','b','a',NULL,'xyz'), +('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'), +('d','b','b',NULL,'xyz'), +('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'), +('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'); + +create index idx_t2_0 on t2 (a1); +create index idx_t2_1 on t2 (a1,a2,b,c); +create index idx_t2_2 on t2 (a1,a2,b); +analyze table t2; + +# Table t3 is the same as t1, but with smaller column lenghts. +# This allows to test different branches of the cost computation procedure +# when the number of keys per block are less than the number of keys in the +# sub-groups formed by predicates over non-group attributes. + +--disable_warnings +drop table if exists t3; +--enable_warnings + +create table t3 ( + a1 char(1), a2 char(1), b char(1), c char(4) not null, d char(3), dummy char(1) default ' ' +); + +insert into t3 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'); +insert into t3 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'); +insert into t3 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'); +insert into t3 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'); + +create index idx_t3_0 on t3 (a1); +create index idx_t3_1 on t3 (a1,a2,b,c); +create index idx_t3_2 on t3 (a1,a2,b); +analyze table t3; + + +# +# Queries without a WHERE clause. These queries do not use ranges. +# + +# plans +explain select a1, min(a2) from t1 group by a1; +explain select a1, max(a2) from t1 group by a1; +explain select a1, min(a2), max(a2) from t1 group by a1; +explain select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b; +explain select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b; +--replace_column 7 # 9 # +explain select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b; +# Select fields in different order +explain select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1; +explain select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b; +explain select min(a2) from t1 group by a1; +explain select a2, min(c), max(c) from t1 group by a1,a2,b; + +# queries +select a1, min(a2) from t1 group by a1; +select a1, max(a2) from t1 group by a1; +select a1, min(a2), max(a2) from t1 group by a1; +select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b; +select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b; +select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b; +# Select fields in different order +select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1; +select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b; +select min(a2) from t1 group by a1; +select a2, min(c), max(c) from t1 group by a1,a2,b; + +# +# Queries with a where clause +# + +# A) Preds only over the group 'A' attributes +# plans +explain select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; +explain select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +explain select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; +explain select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +explain select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +explain select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; +explain select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b; + +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +--replace_column 9 # +explain select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +--replace_column 9 # +explain select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; +--replace_column 9 # +explain select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b; + +# queries +select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; +select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; +select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; +select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b; + +select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; +select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; +select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b; +select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b; +select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; +select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b; + +# B) Equalities only over the non-group 'B' attributes +# plans +explain select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1; +explain select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1; +explain select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2; +explain select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2; +explain select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2; + +explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1; +explain select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1; +explain select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2; +explain select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2; +explain select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2; + +# these queries test case 2) in TRP_GROUP_MIN_MAX::update_cost() +explain select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1; +explain select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1; + +# queries +select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1; +select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1; +select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2; +select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2; +select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2; + +select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1; +select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1; +select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2; +select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2; +select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2; + +# these queries test case 2) in TRP_GROUP_MIN_MAX::update_cost() +select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1; +select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1; + + +# IS NULL (makes sense for t2 only) +# plans +explain select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1; +explain select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1; +explain select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2; +explain select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2; +explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2; +explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2; +# queries +select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1; +select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1; +select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2; +select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2; +select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2; +select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2; + +# C) Range predicates for the MIN/MAX attribute +# plans +--replace_column 9 # +explain select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b; +explain select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b; +explain select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b; +explain select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b; +explain select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +explain select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b; + +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b; + +# queries +select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b; +select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b; +select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b; +select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b; +select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b; + +select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b; +select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b; +select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b; +select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b; +select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b; +select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b; + +# analyze the sub-select +explain select a1,a2,b,min(c),max(c) from t1 +where exists ( select * from t2 where t2.c = t1.c ) +group by a1,a2,b; + +# the sub-select is unrelated to MIN/MAX +explain select a1,a2,b,min(c),max(c) from t1 +where exists ( select * from t2 where t2.c > 'b1' ) +group by a1,a2,b; + + +# A,B,C) Predicates referencing mixed classes of attributes +# plans +explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b; +explain select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b; +explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; +explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; +explain select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +explain select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b; + +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; + +# queries +select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b; +select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; +select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; +select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b; + +select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b; +select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b; +select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; +select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; +select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; + + +# +# GROUP BY queries without MIN/MAX +# + +# plans +explain select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +explain select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +explain select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +explain select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; + +--replace_column 9 # +explain select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +--replace_column 9 # +explain select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; + +# queries +select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; + +select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b; +select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; + +# +# DISTINCT queries +# + +# plans +explain select distinct a1,a2,b from t1; +explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a'); +explain extended select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +explain select distinct b from t1 where (a2 >= 'b') and (b = 'a'); + +--replace_column 9 # +explain select distinct a1,a2,b from t2; +--replace_column 9 # +explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a'); +explain extended select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +--replace_column 9 # +explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +explain select distinct b from t2 where (a2 >= 'b') and (b = 'a'); + +# queries +select distinct a1,a2,b from t1; +select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a'); +select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +select distinct b from t1 where (a2 >= 'b') and (b = 'a'); + +select distinct a1,a2,b from t2; +select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a'); +select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +select distinct b from t2 where (a2 >= 'b') and (b = 'a'); + +# BUG #6303 +select distinct t_00.a1 +from t1 t_00 +where exists ( select * from t2 where a1 = t_00.a1 ); + +# BUG #8532 - SELECT DISTINCT a, a causes server to crash +select distinct a1,a1 from t1; +select distinct a2,a1,a2,a1 from t1; +select distinct t1.a1,t2.a1 from t1,t2; + + +# +# DISTINCT queries with GROUP-BY +# + +# plans +explain select distinct a1,a2,b from t1; +explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +explain select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +explain select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; + +--replace_column 9 # +explain select distinct a1,a2,b from t2; +--replace_column 9 # +explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +--replace_column 9 # +explain select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +--replace_column 9 # +explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +--replace_column 9 # +explain select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; + +# queries +select distinct a1,a2,b from t1; +select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; + +select distinct a1,a2,b from t2; +select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; +select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b; +select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; +select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; + + +# +# COUNT (DISTINCT cols) queries +# + +explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); +explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a'); +explain extended select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); + +select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); +select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); +select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); +select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a'); +select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); + +# +# Queries with expressions in the select clause +# + +explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b; +explain select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b; +explain select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b; +explain select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; +explain select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2; + +select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b; +select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b; +select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b; +select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; +select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2; + + +# +# Negative examples: queries that should NOT be treated as optimizable by +# QUICK_GROUP_MIN_MAX_SELECT +# + +# select a non-indexed attribute +explain select a1,a2,b,d,min(c),max(c) from t1 group by a1,a2,b; + +explain select a1,a2,b,d from t1 group by a1,a2,b; + +# predicate that references an attribute that is after the MIN/MAX argument +# in the index +explain extended select a1,a2,min(b),max(b) from t1 +where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2; + +# predicate that references a non-indexed attribute +explain extended select a1,a2,b,min(c),max(c) from t1 +where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b; + +explain extended select a1,a2,b,c from t1 +where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b,c; + +# non-equality predicate for a non-group select attribute +explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b < 'b') group by a1; +explain extended select a1,a2,b from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2,b; + +# non-group field with an equality predicate that references a keypart after the +# MIN/MAX argument +explain select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1; +select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1; + +# disjunction for a non-group select attribute +explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b = 'a') group by a1; + +# non-range predicate for the MIN/MAX attribute +explain select a1,a2,b,min(c),max(c) from t2 +where (c > 'a000') and (c <= 'd999') and (c like '_8__') group by a1,a2,b; + +# not all attributes are indexed by one index +explain select a1, a2, b, c, min(d), max(d) from t1 group by a1,a2,b,c; + +# other aggregate functions than MIN/MAX +explain select a1,a2,count(a2) from t1 group by a1,a2,b; +explain extended select a1,a2,count(a2) from t1 where (a1 > 'a') group by a1,a2,b; +explain extended select sum(ord(a1)) from t1 where (a1 > 'a') group by a1,a2,b; + + +# +# Bug #16710: select distinct doesn't return all it should +# + +explain select distinct(a1) from t1 where ord(a2) = 98; +select distinct(a1) from t1 where ord(a2) = 98; + +# +# BUG#11044: DISTINCT or GROUP BY queries with equality predicates instead of MIN/MAX. +# + +explain select a1 from t1 where a2 = 'b' group by a1; +select a1 from t1 where a2 = 'b' group by a1; + +explain select distinct a1 from t1 where a2 = 'b'; +select distinct a1 from t1 where a2 = 'b'; + +# +# Bug #12672: primary key implcitly included in every innodb index +# +# Test case moved to group_min_max_innodb + + +# +# Bug #6142: a problem with the empty innodb table +# +# Test case moved to group_min_max_innodb + + +# +# Bug #9798: group by with rollup +# +# Test case moved to group_min_max_innodb + + +# +# Bug #13293 Wrongly used index results in endless loop. +# +# Test case moved to group_min_max_innodb + + +drop table t1,t2,t3; + +# +# Bug #14920 Ordering aggregated result sets with composite primary keys +# corrupts resultset +# +create table t1 (c1 int not null,c2 int not null, primary key(c1,c2)); +insert into t1 (c1,c2) values +(10,1),(10,2),(10,3),(20,4),(20,5),(20,6),(30,7),(30,8),(30,9); +select distinct c1, c2 from t1 order by c2; +select c1,min(c2) as c2 from t1 group by c1 order by c2; +select c1,c2 from t1 group by c1,c2 order by c2; +drop table t1; + +# +# Bug #16203: Analysis for possible min/max optimization erroneously +# returns impossible range +# + +CREATE TABLE t1 (a varchar(5), b int(11), PRIMARY KEY (a,b)); +INSERT INTO t1 VALUES ('AA',1), ('AA',2), ('AA',3), ('BB',1), ('AA',4); +OPTIMIZE TABLE t1; + +SELECT a FROM t1 WHERE a='AA' GROUP BY a; +SELECT a FROM t1 WHERE a='BB' GROUP BY a; + +EXPLAIN SELECT a FROM t1 WHERE a='AA' GROUP BY a; +EXPLAIN SELECT a FROM t1 WHERE a='BB' GROUP BY a; + +SELECT DISTINCT a FROM t1 WHERE a='BB'; +SELECT DISTINCT a FROM t1 WHERE a LIKE 'B%'; +SELECT a FROM t1 WHERE a LIKE 'B%' GROUP BY a; + +DROP TABLE t1; + + +# +# Bug #15102: select distinct returns empty result, select count +# distinct > 0 (correct) +# + +CREATE TABLE t1 ( + a int(11) NOT NULL DEFAULT '0', + b varchar(16) COLLATE latin1_general_ci NOT NULL DEFAULT '', + PRIMARY KEY (a,b) + ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; + +delimiter |; + +CREATE PROCEDURE a(x INT) +BEGIN + DECLARE rnd INT; + DECLARE cnt INT; + + WHILE x > 0 DO + SET rnd= x % 100; + SET cnt = (SELECT COUNT(*) FROM t1 WHERE a = rnd); + INSERT INTO t1(a,b) VALUES (rnd, CAST(cnt AS CHAR)); + SET x= x - 1; + END WHILE; +END| + +DELIMITER ;| + +CALL a(1000); + +SELECT a FROM t1 WHERE a=0; +SELECT DISTINCT a FROM t1 WHERE a=0; +SELECT COUNT(DISTINCT a) FROM t1 WHERE a=0; + +DROP TABLE t1; +DROP PROCEDURE a; + +# +# Bug #18068: SELECT DISTINCT +# + +CREATE TABLE t1 (a varchar(64) NOT NULL default '', PRIMARY KEY(a)); + +INSERT INTO t1 (a) VALUES + (''), ('CENTRAL'), ('EASTERN'), ('GREATER LONDON'), + ('NORTH CENTRAL'), ('NORTH EAST'), ('NORTH WEST'), ('SCOTLAND'), + ('SOUTH EAST'), ('SOUTH WEST'), ('WESTERN'); + +EXPLAIN SELECT DISTINCT a,a FROM t1 ORDER BY a; +SELECT DISTINCT a,a FROM t1 ORDER BY a; + +DROP TABLE t1; + +# +# Bug #21007: NATURAL JOIN (any JOIN (2 x NATURAL JOIN)) crashes the server +# + +CREATE TABLE t1 (id1 INT, id2 INT); +CREATE TABLE t2 (id2 INT, id3 INT, id5 INT); +CREATE TABLE t3 (id3 INT, id4 INT); +CREATE TABLE t4 (id4 INT); +CREATE TABLE t5 (id5 INT, id6 INT); +CREATE TABLE t6 (id6 INT); + +INSERT INTO t1 VALUES(1,1); +INSERT INTO t2 VALUES(1,1,1); +INSERT INTO t3 VALUES(1,1); +INSERT INTO t4 VALUES(1); +INSERT INTO t5 VALUES(1,1); +INSERT INTO t6 VALUES(1); + +# original bug query +SELECT * FROM +t1 + NATURAL JOIN +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); + +# inner join swapped +SELECT * FROM +t1 + NATURAL JOIN +(((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6) on t3.id4 = t5.id5) JOIN t2 + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); + +# one join less, no ON cond +SELECT * FROM t1 NATURAL JOIN ((t3 join (t5 NATURAL JOIN t6)) JOIN t2); + +# wrong error message: 'id2' - ambiguous column +SELECT * FROM +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)) + NATURAL JOIN +t1; +SELECT * FROM +(t2 JOIN ((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6))) + NATURAL JOIN +t1; + +DROP TABLE t1,t2,t3,t4,t5,t6; + +# +# Bug#22342: No results returned for query using max and group by +# +CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b), KEY b (b)); +INSERT INTO t1 VALUES (1,1),(1,2),(1,0),(1,3); + +explain SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a; +SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a; +SELECT MIN(b), a FROM t1 WHERE b > 1 AND a = 1 GROUP BY a; +CREATE TABLE t2 (a int, b int, c int, PRIMARY KEY (a,b,c)); +INSERT INTO t2 SELECT a,b,b FROM t1; +explain SELECT MIN(c) FROM t2 WHERE b = 2 and a = 1 and c > 1 GROUP BY a; +SELECT MIN(c) FROM t2 WHERE b = 2 and a = 1 and c > 1 GROUP BY a; + +DROP TABLE t1,t2; + +# +# Bug#24156: Loose index scan not used with CREATE TABLE ...SELECT and similar statements +# + +CREATE TABLE t1 (a INT, b INT, INDEX (a,b)); +INSERT INTO t1 (a, b) VALUES (1,1), (1,2), (1,3), (1,4), (1,5), + (2,2), (2,3), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4), (4,5), (4,6); +EXPLAIN SELECT max(b), a FROM t1 GROUP BY a; +FLUSH STATUS; +SELECT max(b), a FROM t1 GROUP BY a; +SHOW STATUS LIKE 'handler_read__e%'; +EXPLAIN SELECT max(b), a FROM t1 GROUP BY a; +FLUSH STATUS; +CREATE TABLE t2 SELECT max(b), a FROM t1 GROUP BY a; +SHOW STATUS LIKE 'handler_read__e%'; +FLUSH STATUS; +SELECT * FROM (SELECT max(b), a FROM t1 GROUP BY a) b; +SHOW STATUS LIKE 'handler_read__e%'; +FLUSH STATUS; +(SELECT max(b), a FROM t1 GROUP BY a) UNION + (SELECT max(b), a FROM t1 GROUP BY a); +SHOW STATUS LIKE 'handler_read__e%'; +EXPLAIN (SELECT max(b), a FROM t1 GROUP BY a) UNION + (SELECT max(b), a FROM t1 GROUP BY a); + +EXPLAIN SELECT (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) x + FROM t1 AS t1_outer; +EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE EXISTS + (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); +EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE + (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12; +EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE + a IN (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); +EXPLAIN SELECT 1 FROM t1 AS t1_outer GROUP BY a HAVING + a > (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2); +EXPLAIN SELECT 1 FROM t1 AS t1_outer1 JOIN t1 AS t1_outer2 + ON t1_outer1.a = (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) + AND t1_outer1.b = t1_outer2.b; +EXPLAIN SELECT (SELECT (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) x + FROM t1 AS t1_outer) x2 FROM t1 AS t1_outer2; + +CREATE TABLE t3 LIKE t1; +FLUSH STATUS; +INSERT INTO t3 SELECT a,MAX(b) FROM t1 GROUP BY a; +SHOW STATUS LIKE 'handler_read__e%'; +DELETE FROM t3; +FLUSH STATUS; +INSERT INTO t3 SELECT 1, (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) + FROM t1 LIMIT 1; +SHOW STATUS LIKE 'handler_read__e%'; +FLUSH STATUS; +DELETE FROM t3 WHERE (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) > 10000; +SHOW STATUS LIKE 'handler_read__e%'; +FLUSH STATUS; +--error ER_SUBQUERY_NO_1_ROW +DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x + FROM t1) > 10000; +SHOW STATUS LIKE 'handler_read__e%'; + +DROP TABLE t1,t2,t3; + +# +# Bug#25602: queries with DISTINCT and SQL_BIG_RESULT hint +# for which loose scan optimization is applied +# + +CREATE TABLE t1 (a int, INDEX idx(a)); +INSERT INTO t1 VALUES + (4), (2), (1), (2), (4), (2), (1), (4), + (4), (2), (1), (2), (2), (4), (1), (4); + +EXPLAIN SELECT DISTINCT(a) FROM t1; +SELECT DISTINCT(a) FROM t1; +EXPLAIN SELECT SQL_BIG_RESULT DISTINCT(a) FROM t1; +SELECT SQL_BIG_RESULT DISTINCT(a) FROM t1; + +DROP TABLE t1; + +# +# Bug #32268: Indexed queries give bogus MIN and MAX results +# + +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 (a, b) VALUES (1,1), (1,2), (1,3); +INSERT INTO t1 SELECT a + 1, b FROM t1; +INSERT INTO t1 SELECT a + 2, b FROM t1; + +EXPLAIN +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a DESC; +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a DESC; + +CREATE INDEX break_it ON t1 (a, b); + +EXPLAIN +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a; +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a; + +EXPLAIN +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a DESC; +SELECT a, MIN(b), MAX(b) FROM t1 GROUP BY a ORDER BY a DESC; + +EXPLAIN +SELECT a, MIN(b), MAX(b), AVG(b) FROM t1 GROUP BY a ORDER BY a DESC; +SELECT a, MIN(b), MAX(b), AVG(b) FROM t1 GROUP BY a ORDER BY a DESC; + +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/having.test b/mysql-test/suite/pbxt/t/having.test new file mode 100644 index 00000000000..5ee6ddb8a60 --- /dev/null +++ b/mysql-test/suite/pbxt/t/having.test @@ -0,0 +1,412 @@ +# test of problems with having (Reported by Mark Rogers) +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +create table t1 (a int); +select count(a) as b from t1 where a=0 having b > 0; +insert into t1 values (null); +select count(a) as b from t1 where a=0 having b > 0; +select count(a) as b from t1 where a=0 having b >=0; +explain extended select count(a) as b from t1 where a=0 having b >=0; +drop table t1; + +# +# Test of problem with HAVING and AVG() +# + +CREATE TABLE t1 ( + raw_id int(10) NOT NULL default '0', + chr_start int(10) NOT NULL default '0', + chr_end int(10) NOT NULL default '0', + raw_start int(10) NOT NULL default '0', + raw_end int(10) NOT NULL default '0', + raw_ori int(2) NOT NULL default '0' +); + +INSERT INTO t1 VALUES (469713,1,164123,1,164123,1),(317330,164124,317193,101,153170,1),(469434,317194,375620,101,58527,1),(591816,375621,484273,1,108653,1),(591807,484274,534671,91,50488,1),(318885,534672,649362,101,114791,1),(318728,649363,775520,102,126259,1),(336829,775521,813997,101,38577,1),(317740,813998,953227,101,139330,1),(1,813998,953227,101,139330,1); + +CREATE TABLE t2 ( + id int(10) unsigned NOT NULL default '0', + contig_id int(10) unsigned NOT NULL default '0', + seq_start int(10) NOT NULL default '0', + seq_end int(10) NOT NULL default '0', + strand tinyint(2) NOT NULL default '0', + KEY id (id) +); +INSERT INTO t2 VALUES (133195,469713,61327,61384,1),(133196,469713,64113,64387,1),(133197,1,1,1,0),(133197,1,1,1,-2); +SELECT e.id, + MIN( IF(sgp.raw_ori=1, + (e.seq_start+sgp.chr_start-sgp.raw_start), + (sgp.chr_start+sgp.raw_end-e.seq_end))) as start, + MAX( IF(sgp.raw_ori=1, + (e.seq_end+sgp.chr_start-sgp.raw_start), + (sgp.chr_start+sgp.raw_end-e.seq_start))) as end, + AVG(IF (sgp.raw_ori=1,e.strand,(-e.strand))) as chr_strand +FROM t1 sgp, + t2 e +WHERE sgp.raw_id=e.contig_id +GROUP BY e.id +HAVING chr_strand= -1 and end >= 0 + AND start <= 999660; +drop table t1,t2; + +# +# Test problem with having and MAX() IS NOT NULL +# + +CREATE TABLE t1 (Fld1 int(11) default NULL,Fld2 int(11) default NULL); +INSERT INTO t1 VALUES (1,10),(1,20),(2,NULL),(2,NULL),(3,50); +select Fld1, max(Fld2) as q from t1 group by Fld1 having q is not null; +select Fld1, max(Fld2) from t1 group by Fld1 having max(Fld2) is not null; +select Fld1, max(Fld2) from t1 group by Fld1 having avg(Fld2) is not null; +select Fld1, max(Fld2) from t1 group by Fld1 having std(Fld2) is not null; +select Fld1, max(Fld2) from t1 group by Fld1 having variance(Fld2) is not null; +drop table t1; + +# +# Test problem with count(distinct) in having +# +create table t1 (id int not null, qty int not null); +insert into t1 values (1,2),(1,3),(2,4),(2,5); +select id, sum(qty) as sqty from t1 group by id having sqty>2; +select sum(qty) as sqty from t1 group by id having count(id) > 0; +select sum(qty) as sqty from t1 group by id having count(distinct id) > 0; +drop table t1; + +# +# Test case for Bug #4358 Problem with HAVING clause that uses alias from the +# select list and TEXT field +# + +CREATE TABLE t1 ( + `id` bigint(20) NOT NULL default '0', + `description` text +) ENGINE=MyISAM; + +CREATE TABLE t2 ( + `id` bigint(20) NOT NULL default '0', + `description` varchar(20) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (1, 'test'); +INSERT INTO t2 VALUES (1, 'test'); + +CREATE TABLE t3 ( + `id` bigint(20) NOT NULL default '0', + `order_id` bigint(20) NOT NULL default '0' +) ENGINE=MyISAM; + +select + a.id, a.description, + count(b.id) as c +from t1 a left join t3 b on a.id=b.order_id +group by a.id, a.description +having (a.description is not null) and (c=0); + +select + a.*, + count(b.id) as c +from t2 a left join t3 b on a.id=b.order_id +group by a.id, a.description +having (a.description is not null) and (c=0); + +INSERT INTO t1 VALUES (2, 'test2'); + +select + a.id, a.description, + count(b.id) as c +from t1 a left join t3 b on a.id=b.order_id +group by a.id, a.description +having (a.description is not null) and (c=0); +drop table t1,t2,t3; + +# +# Bug #14274: HAVING clause containing only set function +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3), (4), (1), (3), (1); + +SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a)>0; +SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a); + +DROP TABLE t1; + +# +# Bug #14927: HAVING clause containing constant false conjunct +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2), (1), (3), (2), (1); + +SELECT a FROM t1 GROUP BY a HAVING a > 1; +SELECT a FROM t1 GROUP BY a HAVING 1 != 1 AND a > 1; +SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1; + +EXPLAIN SELECT a FROM t1 GROUP BY a HAVING 1 != 1 AND a > 1; +EXPLAIN SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1; + +DROP table t1; + +# End of 4.1 tests + +# +# Tests for WL#1972 CORRECT EVALUATION OF COLUMN REFERENCES IN THE HAVING CLAUSE +# Per the SAP VERI tests and WL#1972, MySQL must ensure that HAVING can +# correctly evaluate column references from the GROUP BY clause, even if the +# same references are not also found in the select list. +# + +# set global sql_mode='ansi'; +# set session sql_mode='ansi'; + +create table t1 (col1 int, col2 varchar(5), col_t1 int); +create table t2 (col1 int, col2 varchar(5), col_t2 int); +create table t3 (col1 int, col2 varchar(5), col_t3 int); + +insert into t1 values(10,'hello',10); +insert into t1 values(20,'hello',20); +insert into t1 values(30,'hello',30); +insert into t1 values(10,'bye',10); +insert into t1 values(10,'sam',10); +insert into t1 values(10,'bob',10); + +insert into t2 select * from t1; +insert into t3 select * from t1; + +select count(*) from t1 group by col1 having col1 = 10; +select count(*) as count_col1 from t1 group by col1 having col1 = 10; +select count(*) as count_col1 from t1 as tmp1 group by col1 having col1 = 10; +select count(*) from t1 group by col2 having col2 = 'hello'; +--error 1054 +select count(*) from t1 group by col2 having col1 = 10; +select col1 as count_col1 from t1 as tmp1 group by col1 having col1 = 10; +select col1 as count_col1 from t1 as tmp1 group by col1 having count_col1 = 10; +select col1 as count_col1 from t1 as tmp1 group by count_col1 having col1 = 10; +# ANSI: should return SQLSTATE 42000 Syntax error or access violation +# MySQL: returns 10 - because of GROUP BY name resolution +select col1 as count_col1 from t1 as tmp1 group by count_col1 having count_col1 = 10; +# ANSI: should return SQLSTATE 42000 Syntax error or access violation +# MySQL: returns 10 - because of GROUP BY name resolution +select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having col1 = 10; +select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having count_col1 = 10; +select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having col2 = 'hello'; +select col1 as count_col1,col2 as group_col2 from t1 as tmp1 group by col1,col2 having group_col2 = 'hello'; +--error 1064 +select sum(col1) as co12 from t1 group by col2 having col2 10; +select sum(col1) as co2, count(col2) as cc from t1 group by col1 having col1 =10; +--error 1054 +select t2.col2 from t2 group by t2.col1, t2.col2 having t1.col1 <= 10; + + +# +# queries with nested sub-queries +# + +# the having column is resolved in the same query +select t1.col1 from t1 +where t1.col2 in + (select t2.col2 from t2 + group by t2.col1, t2.col2 having t2.col1 <= 10); + +select t1.col1 from t1 +where t1.col2 in + (select t2.col2 from t2 + group by t2.col1, t2.col2 + having t2.col1 <= + (select min(t3.col1) from t3)); + +# the having column is resolved in the SELECT clause of the outer query - +# works in ANSI +select t1.col1 from t1 +where t1.col2 in + (select t2.col2 from t2 + group by t2.col1, t2.col2 having t1.col1 <= 10); + +# the having column is resolved in the SELECT clause of the outer query - +# error in ANSI, works with MySQL extension +select t1.col1 as tmp_col from t1 +where t1.col2 in + (select t2.col2 from t2 + group by t2.col1, t2.col2 having tmp_col <= 10); + +# the having column is resolved in the FROM clause of the outer query - +# works in ANSI +select t1.col1 from t1 +where t1.col2 in + (select t2.col2 from t2 + group by t2.col1, t2.col2 having col_t1 <= 10); + +# Item_field must be resolved in the same way as Item_ref +select sum(col1) from t1 +group by col_t1 +having (select col_t1 from t2 where col_t1 = col_t2 order by col_t2 limit 1); + +# nested queries with HAVING, inner having column resolved in outer FROM clause +# the outer having column is not referenced in GROUP BY which results in an error +--error 1054 +select t1.col1 from t1 +where t1.col2 in + (select t2.col2 from t2 + group by t2.col1, t2.col2 having col_t1 <= 10) +having col_t1 <= 20; + +# both having columns are resolved in the GROUP clause of the outer query +select t1.col1 from t1 +where t1.col2 in + (select t2.col2 from t2 + group by t2.col1, t2.col2 having col_t1 <= 10) +group by col_t1 +having col_t1 <= 20; + +# +# nested HAVING clauses +# + +# non-correlated subqueries +select col_t1, sum(col1) from t1 +group by col_t1 +having col_t1 > 10 and + exists (select sum(t2.col1) from t2 + group by t2.col2 having t2.col2 > 'b'); + +# correlated subqueries - inner having column 't1.col2' resolves to +# the outer FROM clause, which cannot be used because the outer query +# is grouped +--error 1054 +select sum(col1) from t1 +group by col_t1 +having col_t1 in (select sum(t2.col1) from t2 + group by t2.col2, t2.col1 having t2.col1 = t1.col1); + +# correlated subqueries - inner having column 'col_t1' resolves to +# the outer GROUP clause +select sum(col1) from t1 +group by col_t1 +having col_t1 in (select sum(t2.col1) from t2 + group by t2.col2, t2.col1 having t2.col1 = col_t1); + +# +# queries with joins and ambiguous column names +# +--error 1052 +select t1.col1, t2.col1 from t1, t2 where t1.col1 = t2.col1 +group by t1.col1, t2.col1 having col1 = 2; + +--error 1052 +select t1.col1*10+t2.col1 from t1,t2 where t1.col1=t2.col1 +group by t1.col1, t2.col1 having col1 = 2; + +drop table t1, t2, t3; + +# More queries to test ANSI compatibility +create table t1 (s1 int); +insert into t1 values (1),(2),(3); + +select count(*) from t1 group by s1 having s1 is null; + +# prepared statements prints warnings too early +--disable_ps_protocol +select s1*0 as s1 from t1 group by s1 having s1 <> 0; +--enable_ps_protocol + +# ANSI requires: 3 rows +# MySQL returns: 0 rows - because of GROUP BY name resolution + +select s1*0 from t1 group by s1 having s1 = 0; + +select s1 from t1 group by 1 having 1 = 0; + +select count(s1) from t1 group by s1 having count(1+1)=2; +# ANSI requires: 3 rows +# MySQL returns: 0 rows - because of GROUP BY name resolution + +select count(s1) from t1 group by s1 having s1*0=0; + +-- error 1052 +select * from t1 a, t1 b group by a.s1 having s1 is null; +# ANSI requires: 0 rows +# MySQL returns: +# "ERROR 1052 (23000): Column 's1' in having clause is ambiguous" +# I think the column is ambiguous in ANSI too. +# It is the same as: +# select a.s1, b.s1 from t1 a, t1 b group by a.s1 having s1 is null; +# currently we first check SELECT, thus s1 is ambiguous. + +drop table t1; + +create table t1 (s1 char character set latin1 collate latin1_german1_ci); +insert into t1 values ('ü'),('y'); + +select s1,count(s1) from t1 +group by s1 collate latin1_swedish_ci having s1 = 'y'; +# ANSI requires: 1 row, with count(s1) = 2 +# MySQL returns: 1 row, with count(s1) = 1 + +drop table t1; + + +# +# Bug #15917: unexpected complain for a name in having clause +# when the server is run on Windows or with --lower-case-table-names=1 +# + +--disable_warnings +DROP SCHEMA IF EXISTS HU; +--enable_warnings +CREATE SCHEMA HU ; +USE HU ; + +CREATE TABLE STAFF + (EMPNUM CHAR(3) NOT NULL UNIQUE, + EMPNAME CHAR(20), + GRADE DECIMAL(4), + CITY CHAR(15)); + +CREATE TABLE PROJ + (PNUM CHAR(3) NOT NULL UNIQUE, + PNAME CHAR(20), + PTYPE CHAR(6), + BUDGET DECIMAL(9), + CITY CHAR(15)); + +INSERT INTO STAFF VALUES ('E1','Alice',12,'Deale'); +INSERT INTO STAFF VALUES ('E2','Betty',10,'Vienna'); +INSERT INTO STAFF VALUES ('E3','Carmen',13,'Vienna'); +INSERT INTO STAFF VALUES ('E4','Don',12,'Deale'); +INSERT INTO STAFF VALUES ('E5','Ed',13,'Akron'); + +INSERT INTO PROJ VALUES ('P1','MXSS','Design',10000,'Deale'); +INSERT INTO PROJ VALUES ('P2','CALM','Code',30000,'Vienna'); +INSERT INTO PROJ VALUES ('P3','SDP','Test',30000,'Tampa'); +INSERT INTO PROJ VALUES ('P4','SDP','Design',20000,'Deale'); +INSERT INTO PROJ VALUES ('P5','IRM','Test',10000,'Vienna'); +INSERT INTO PROJ VALUES ('P6','PAYR','Design',50000,'Deale'); + +SELECT EMPNUM, GRADE*1000 + FROM HU.STAFF WHERE GRADE * 1000 > + ANY (SELECT SUM(BUDGET) FROM HU.PROJ + GROUP BY CITY, PTYPE + HAVING HU.PROJ.CITY = HU.STAFF.CITY); + +DROP SCHEMA HU; +USE test; +# +# Bug#18739: non-standard HAVING extension was allowed in strict ANSI sql mode. +# +create table t1(f1 int); +select f1 from t1 having max(f1)=f1; +select f1 from t1 group by f1 having max(f1)=f1; +set session sql_mode='ONLY_FULL_GROUP_BY'; +--error ER_NON_GROUPING_FIELD_USED +select f1 from t1 having max(f1)=f1; +select f1 from t1 group by f1 having max(f1)=f1; +set session sql_mode=''; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/heap.test b/mysql-test/suite/pbxt/t/heap.test new file mode 100644 index 00000000000..2d863827b2b --- /dev/null +++ b/mysql-test/suite/pbxt/t/heap.test @@ -0,0 +1,476 @@ +# +# Test of heap tables. +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a=1 or a=0; +#show table status like "t1"; +show keys from t1; +select * from t1; +select * from t1 where a=4; +update t1 set b=5 where a=4; +update t1 set b=b+1 where a>=3; +replace t1 values (3,3); +select * from t1; +alter table t1 add c int not null, add key (c,a); +drop table t1; + +create table t1 (a int not null,b int not null, primary key (a)) engine=memory comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a > 0; +select * from t1; +drop table t1; + +create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +alter table t1 modify a int not null auto_increment, engine=myisam, comment="new myisam table"; +#show table status like "t1"; +select * from t1; +drop table t1; + +create table t1 (a int not null) engine=heap; +insert into t1 values (869751),(736494),(226312),(802616),(728912); +select * from t1 where a > 736494; +alter table t1 add unique uniq_id(a); +select * from t1 where a > 736494; +select * from t1 where a = 736494; +select * from t1 where a=869751 or a=736494; +select * from t1 where a in (869751,736494,226312,802616); +alter table t1 engine=myisam; +explain select * from t1 where a in (869751,736494,226312,802616); +drop table t1; + +create table t1 (x int not null, y int not null, key x (x), unique y (y)) +engine=heap; +insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6); +select * from t1 where x=1; +select * from t1,t1 as t2 where t1.x=t2.y; +explain select * from t1,t1 as t2 where t1.x=t2.y; +drop table t1; + +create table t1 (a int) engine=heap; +insert into t1 values(1); +select max(a) from t1; +drop table t1; + +CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key(a), key(b) ) ENGINE=HEAP; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +drop table t1; + +create table t1 (id int unsigned not null, primary key (id)) engine=HEAP; +insert into t1 values(1); +select max(id) from t1; +insert into t1 values(2); +select max(id) from t1; +replace into t1 values(1); +drop table t1; + +create table t1 (n int) engine=heap; +drop table t1; + +create table t1 (n int) engine=heap; +drop table if exists t1; + +# Test of non unique index + +CREATE table t1(f1 int not null,f2 char(20) not +null,index(f2)) engine=heap; +INSERT into t1 set f1=12,f2="bill"; +INSERT into t1 set f1=13,f2="bill"; +INSERT into t1 set f1=14,f2="bill"; +INSERT into t1 set f1=15,f2="bill"; +INSERT into t1 set f1=16,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +delete from t1 where f2="bill"; +select * from t1; +drop table t1; + +# +# Test when using part key searches +# + +create table t1 (btn char(10) not null, key(btn)) engine=heap; +insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i"); +explain select * from t1 where btn like "q%"; +select * from t1 where btn like "q%"; +alter table t1 add column new_col char(1) not null, add key (btn,new_col), drop key btn; +update t1 set new_col=left(btn,1); +explain select * from t1 where btn="a"; +explain select * from t1 where btn="a" and new_col="a"; +drop table t1; + +# +# Test of NULL keys +# + +CREATE TABLE t1 ( + a int default NULL, + b int default NULL, + KEY a (a), + UNIQUE b (b) +) engine=heap; +INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3); +SELECT * FROM t1 WHERE a=NULL; +explain SELECT * FROM t1 WHERE a IS NULL; +SELECT * FROM t1 WHERE a<=>NULL; +SELECT * FROM t1 WHERE b=NULL; +explain SELECT * FROM t1 WHERE b IS NULL; +SELECT * FROM t1 WHERE b<=>NULL; + +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES (1,3); +DROP TABLE t1; + +CREATE TABLE t1 ( + a int default NULL, + key a (a) +) ENGINE=HEAP; +INSERT INTO t1 VALUES (10), (10), (10); +EXPLAIN SELECT * FROM t1 WHERE a=10; +SELECT * FROM t1 WHERE a=10; +DROP TABLE t1; + +# +# Test when deleting all rows +# + +CREATE TABLE t1 (a int not null, primary key(a)) engine=heap; +INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); +DELETE from t1 where a < 100; +SELECT * from t1; +DROP TABLE t1; + +# +# Bug#4411 Server hangs when trying to SELECT MAX(id) from an empty HEAP table +# +CREATE TABLE `job_titles` ( + `job_title_id` int(6) unsigned NOT NULL default '0', + `job_title` char(18) NOT NULL default '', + PRIMARY KEY (`job_title_id`), + UNIQUE KEY `job_title_id` (`job_title_id`,`job_title`) +) ENGINE=HEAP; + +SELECT MAX(job_title_id) FROM job_titles; + +DROP TABLE job_titles; + +# +# Test of delete with NOT NULL +# (Bug #6082) +# + +CREATE TABLE t1 (a INT NOT NULL, B INT, KEY(B)) ENGINE=HEAP; +INSERT INTO t1 VALUES(1,1), (1,NULL); +SELECT * FROM t1 WHERE B is not null; +DROP TABLE t1; + +# +# Bug #6748 +# heap_rfirst() doesn't work (and never did!) +# +CREATE TABLE t1 (pseudo char(35) PRIMARY KEY, date int(10) unsigned NOT NULL) ENGINE=HEAP; +INSERT INTO t1 VALUES ('massecot',1101106491),('altec',1101106492),('stitch+',1101106304),('Seb Corgan',1101106305),('beerfilou',1101106263),('flaker',1101106529),('joce8',5),('M4vrick',1101106418),('gabay008',1101106525),('Vamp irX',1101106291),('ZoomZip',1101106546),('rip666',1101106502),('CBP ',1101106397),('guezpard',1101106496); +DELETE FROM t1 WHERE date<1101106546; +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #6878: a problem with small length records +# + +create table t1(a char(2)) engine=memory; +insert into t1 values (NULL), (NULL); +delete from t1 where a is null; +insert into t1 values ('2'), ('3'); +select * from t1; +drop table t1; + +# +# Test varchar +# We can't use varchar.inc becasue heap doesn't support blob's +# + +let $default=`select @@storage_engine`; +set storage_engine=HEAP; + +# +# Simple basic test that endspace is saved +# + +create table t1 (v varchar(10), c char(10), t varchar(50)); +insert into t1 values('+ ', '+ ', '+ '); +set @a=repeat(' ',20); +insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a)); +select concat('*',v,'*',c,'*',t,'*') from t1; + +# Check how columns are copied +show create table t1; +create table t2 like t1; +show create table t2; +create table t3 select * from t1; +show create table t3; +alter table t1 modify c varchar(10); +show create table t1; +alter table t1 modify v char(10); +show create table t1; +alter table t1 modify t varchar(10); +show create table t1; +select concat('*',v,'*',c,'*',t,'*') from t1; +drop table t1,t2,t3; + +# +# Testing of keys +# +create table t1 (v varchar(10), c char(10), t varchar(50), key(v), key(c), key(t(10))); +show create table t1; +disable_query_log; +let $1=10; +while ($1) +{ + let $2=27; + eval set @space=repeat(' ',10-$1); + while ($2) + { + eval set @char=char(ascii('a')+$2-1); + insert into t1 values(concat(@char,@space),concat(@char,@space),concat(@char,@space)); + dec $2; + } + dec $1; +} +enable_query_log; +select count(*) from t1; +insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); +select count(*) from t1 where v='a'; +select count(*) from t1 where c='a'; +select count(*) from t1 where t='a'; +select count(*) from t1 where v='a '; +select count(*) from t1 where c='a '; +select count(*) from t1 where t='a '; +select count(*) from t1 where v between 'a' and 'a '; +select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; +select count(*) from t1 where v like 'a%'; +select count(*) from t1 where c like 'a%'; +select count(*) from t1 where t like 'a%'; +select count(*) from t1 where v like 'a %'; +explain select count(*) from t1 where v='a '; +explain select count(*) from t1 where c='a '; +explain select count(*) from t1 where t='a '; +explain select count(*) from t1 where v like 'a%'; +explain select count(*) from t1 where v between 'a' and 'a '; +explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; + +--error ER_DUP_ENTRY +alter table t1 add unique(v); +select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); +explain select * from t1 where v='a'; + +# GROUP BY + +select v,count(*) from t1 group by v limit 10; +select v,count(t) from t1 group by v limit 10; +select v,count(c) from t1 group by v limit 10; +select sql_big_result trim(v),count(t) from t1 group by v limit 10; +select sql_big_result trim(v),count(c) from t1 group by v limit 10; +select c,count(*) from t1 group by c limit 10; +select c,count(t) from t1 group by c limit 10; +select sql_big_result c,count(t) from t1 group by c limit 10; +select t,count(*) from t1 group by t limit 10; +select t,count(t) from t1 group by t limit 10; +select sql_big_result trim(t),count(t) from t1 group by t limit 10; +drop table t1; + +# +# Test unique keys +# + +create table t1 (a char(10), unique (a)); +insert into t1 values ('a'); +--error ER_DUP_ENTRY +insert into t1 values ('a '); + +alter table t1 modify a varchar(10); +--error ER_DUP_ENTRY +insert into t1 values ('a '),('a '),('a '),('a '); +--error ER_DUP_ENTRY +insert into t1 values ('a '); +--error ER_DUP_ENTRY +insert into t1 values ('a '); +--error ER_DUP_ENTRY +insert into t1 values ('a '); +update t1 set a='a ' where a like 'a '; +update t1 set a='a ' where a like 'a '; +drop table t1; + +# +# Testing of btree keys +# + +create table t1 (v varchar(10), c char(10), t varchar(50), key using btree (v), key using btree (c), key using btree (t(10))); +show create table t1; +disable_query_log; +let $1=10; +while ($1) +{ + let $2=27; + eval set @space=repeat(' ',10-$1); + while ($2) + { + eval set @char=char(ascii('a')+$2-1); + insert into t1 values(concat(@char,@space),concat(@char,@space),concat(@char,@space)); + dec $2; + } + dec $1; +} +enable_query_log; +select count(*) from t1; +insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); +select count(*) from t1 where v='a'; +select count(*) from t1 where c='a'; +select count(*) from t1 where t='a'; +select count(*) from t1 where v='a '; +select count(*) from t1 where c='a '; +select count(*) from t1 where t='a '; +select count(*) from t1 where v between 'a' and 'a '; +--replace_column 9 # +select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; +--replace_column 9 # +explain select count(*) from t1 where v='a '; +--replace_column 9 # +explain select count(*) from t1 where c='a '; +--replace_column 9 # +explain select count(*) from t1 where t='a '; +--replace_column 9 # +explain select count(*) from t1 where v like 'a%'; +--replace_column 9 # +explain select count(*) from t1 where v between 'a' and 'a '; +--replace_column 9 # +explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; + +--error ER_DUP_ENTRY +alter table t1 add unique(v); +select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*')); +# Number of rows is not constant for b-trees keys +--replace_column 9 # +explain select * from t1 where v='a'; + +drop table t1; + +# +# Test unique btree keys +# + +create table t1 (a char(10), unique using btree (a)) engine=heap; +insert into t1 values ('a'); +--error ER_DUP_ENTRY +insert into t1 values ('a '); + +alter table t1 modify a varchar(10); +--error ER_DUP_ENTRY +insert into t1 values ('a '),('a '),('a '),('a '); +--error ER_DUP_ENTRY +insert into t1 values ('a '); +--error ER_DUP_ENTRY +insert into t1 values ('a '); +--error ER_DUP_ENTRY +insert into t1 values ('a '); +update t1 set a='a ' where a like 'a '; +update t1 set a='a ' where a like 'a '; +drop table t1; + +# +# test show create table +# + +create table t1 (v varchar(10), c char(10), t varchar(50), key(v(5)), key(c(5)), key(t(5))); +show create table t1; +drop table t1; + +create table t1 (v varchar(65530), key(v(10))); +show create table t1; +insert into t1 values(repeat('a',65530)); +select length(v) from t1 where v=repeat('a',65530); +drop table t1; + +# +# Reset varchar test +# +eval set storage_engine=$default; + +# +# Bug #8489: Strange auto_increment behaviour +# + +create table t1 (a bigint unsigned auto_increment primary key, b int, + key (b, a)) engine=heap; +insert t1 (b) values (1),(1),(1),(1),(1),(1),(1),(1); +select * from t1; +drop table t1; + +create table t1 (a int not null, b int not null auto_increment, + primary key(a, b), key(b)) engine=heap; +insert t1 (a) values (1),(1),(1),(1),(1),(1),(1),(1); +select * from t1; +drop table t1; + +--error 1075 +create table t1 (a int not null, b int not null auto_increment, + primary key(a, b)) engine=heap; + +# +# Bug #10566: Verify that we can create a prefixed key with length > 255 +# +create table t1 (c char(255), primary key(c(90))); +insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); +--error ER_DUP_ENTRY +insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); +drop table t1; + +# +# Bug 12796: Record doesn't show when selecting through index +# +CREATE TABLE t1 (a int, key(a)) engine=heap; +insert into t1 values (0); +delete from t1; +select * from t1; +insert into t1 values (0), (1); +select * from t1 where a = 0; +drop table t1; + +# End of 4.1 tests + +# +# Bug #3094: Row format of memory tables should always be reported as Fixed +# +create table t1 (c char(10)) engine=memory; +create table t2 (c varchar(10)) engine=memory; +--replace_column 8 # +show table status like 't_'; +drop table t1, t2; + +# +# BUG#18233 - Memory tables INDEX USING HASH (a,b) returns 1 row on +# SELECT WHERE a= AND b= +# +CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256), + KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY; +INSERT INTO t1 VALUES('a','aa',REPEAT('a', 256)),('a','aa',REPEAT('a',256)); +SELECT COUNT(*) FROM t1 WHERE a='a'; +SELECT COUNT(*) FROM t1 WHERE b='aa'; +SELECT COUNT(*) FROM t1 WHERE c=REPEAT('a',256); +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/heap_auto_increment.test b/mysql-test/suite/pbxt/t/heap_auto_increment.test new file mode 100644 index 00000000000..016bc946209 --- /dev/null +++ b/mysql-test/suite/pbxt/t/heap_auto_increment.test @@ -0,0 +1,35 @@ +# +# Test of auto_increment; The test for BDB tables is in bdb.test +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int not null auto_increment,b int, primary key (a)) engine=heap auto_increment=3; +insert into t1 values (1,1),(NULL,3),(NULL,4); +delete from t1 where a=4; +insert into t1 values (NULL,5),(NULL,6); +select * from t1; +delete from t1 where a=6; +#show table status like "t1"; +replace t1 values (3,1); +ALTER TABLE t1 add c int; +replace t1 values (3,3,3); +insert into t1 values (NULL,7,7); +update t1 set a=8,b=b+1,c=c+1 where a=7; +insert into t1 values (NULL,9,9); +select * from t1; +drop table t1; + +create table t1 ( + skey tinyint unsigned NOT NULL auto_increment PRIMARY KEY, + sval char(20) +) engine=heap; +insert into t1 values (NULL, "hello"); +insert into t1 values (NULL, "hey"); +select * from t1; +select _rowid,t1._rowid,skey,sval from t1; +drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/heap_btree.test b/mysql-test/suite/pbxt/t/heap_btree.test new file mode 100644 index 00000000000..fa30bb80e21 --- /dev/null +++ b/mysql-test/suite/pbxt/t/heap_btree.test @@ -0,0 +1,207 @@ +# +# Test of heap tables. +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int not null,b int not null, primary key using BTREE (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a=1 or a=0; +#show table status like "t1"; +show keys from t1; +select * from t1; +select * from t1 where a=4; +update t1 set b=5 where a=4; +update t1 set b=b+1 where a>=3; +replace t1 values (3,3); +select * from t1; +alter table t1 add c int not null, add key using BTREE (c,a); +drop table t1; + +create table t1 (a int not null,b int not null, primary key using BTREE (a)) engine=heap comment="testing heaps"; +insert into t1 values(-2,-2),(-1,-1),(0,0),(1,1),(2,2),(3,3),(4,4); +delete from t1 where a > -3; +select * from t1; +drop table t1; + +create table t1 (a int not null,b int not null, primary key using BTREE (a)) engine=heap comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +alter table t1 modify a int not null auto_increment, engine=myisam, comment="new myisam table"; +#show table status like "t1"; +select * from t1; +drop table t1; + +create table t1 (a int not null) engine=heap; +insert into t1 values (869751),(736494),(226312),(802616),(728912); +select * from t1 where a > 736494; +alter table t1 add unique uniq_id using BTREE (a); +select * from t1 where a > 736494; +select * from t1 where a = 736494; +select * from t1 where a=869751 or a=736494; +select * from t1 where a in (869751,736494,226312,802616); +alter table t1 engine=myisam; +explain select * from t1 where a in (869751,736494,226312,802616); +drop table t1; + +create table t1 (x int not null, y int not null, key x using BTREE (x,y), unique y using BTREE (y)) +engine=heap; +insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6); +explain select * from t1 where x=1; +select * from t1 where x=1; +select * from t1,t1 as t2 where t1.x=t2.y; +explain select * from t1,t1 as t2 where t1.x=t2.y; +drop table t1; + +create table t1 (a int) engine=heap; +insert into t1 values(1); +select max(a) from t1; +drop table t1; + +CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key using BTREE (a,b), key using BTREE (b) ) ENGINE=HEAP; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +--replace_result 0 x 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x 11 x 12 x 13 x 14 x +explain select * from t1 where a=1 order by a,b; +--replace_result 0 x 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x 11 x 12 x 13 x 14 x +explain select * from t1 where a=1 order by b; +select * from t1 where b=1; +--replace_result 0 x 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x 11 x 12 x 13 x 14 x +explain select * from t1 where b=1; +drop table t1; + +create table t1 (id int unsigned not null, primary key using BTREE (id)) engine=HEAP; +insert into t1 values(1); +select max(id) from t1; +insert into t1 values(2); +select max(id) from t1; +replace into t1 values(1); +drop table t1; + +create table t1 (n int) engine=heap; +drop table t1; + +create table t1 (n int) engine=heap; +drop table if exists t1; + +# Test of non unique index + +CREATE table t1(f1 int not null,f2 char(20) not +null,index(f2)) engine=heap; +INSERT into t1 set f1=12,f2="bill"; +INSERT into t1 set f1=13,f2="bill"; +INSERT into t1 set f1=14,f2="bill"; +INSERT into t1 set f1=15,f2="bill"; +INSERT into t1 set f1=16,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +delete from t1 where f2="bill"; +select * from t1; +drop table t1; + +# +# Test when using part key searches +# + +create table t1 (btn char(10) not null, key using BTREE (btn)) engine=heap; +insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i"); +explain select * from t1 where btn like "i%"; +--replace_column 9 # +explain select * from t1 where btn like "h%"; +explain select * from t1 where btn like "a%"; +explain select * from t1 where btn like "b%"; +# For the following the BTREE MAY notice that there is no possible matches +select * from t1 where btn like "ff%"; +select * from t1 where btn like " %"; +select * from t1 where btn like "q%"; +alter table t1 add column new_col char(1) not null, add key using BTREE (btn,new_col), drop key btn; +update t1 set new_col=left(btn,1); +explain select * from t1 where btn="a"; +explain select * from t1 where btn="a" and new_col="a"; +drop table t1; + +# +# Test of NULL keys +# + +CREATE TABLE t1 ( + a int default NULL, + b int default NULL, + KEY a using BTREE (a), + UNIQUE b using BTREE (b) +) engine=heap; +INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3); +SELECT * FROM t1 WHERE a=NULL; +explain SELECT * FROM t1 WHERE a IS NULL; +SELECT * FROM t1 WHERE a<=>NULL; +SELECT * FROM t1 WHERE b=NULL; +explain SELECT * FROM t1 WHERE b IS NULL; +SELECT * FROM t1 WHERE b<=>NULL; + +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES (1,3); +DROP TABLE t1; + +CREATE TABLE t1 (a int, b int, c int, key using BTREE (a, b, c)) engine=heap; +INSERT INTO t1 VALUES (1, NULL, NULL), (1, 1, NULL), (1, NULL, 1); +SELECT * FROM t1 WHERE a=1 and b IS NULL; +SELECT * FROM t1 WHERE a=1 and c IS NULL; +SELECT * FROM t1 WHERE a=1 and b IS NULL and c IS NULL; +DROP TABLE t1; + +# +# Test when deleting all rows +# + +CREATE TABLE t1 (a int not null, primary key using BTREE (a)) engine=heap; +INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); +DELETE from t1 where a < 100; +SELECT * from t1; +DROP TABLE t1; + +# +# Bug #9719: problem with delete +# + +create table t1(a int not null, key using btree(a)) engine=heap; +insert into t1 values (2), (2), (2), (1), (1), (3), (3), (3), (3); +select a from t1 where a > 2 order by a; +delete from t1 where a < 4; +select a from t1 order by a; +insert into t1 values (2), (2), (2), (1), (1), (3), (3), (3), (3); +select a from t1 where a > 4 order by a; +delete from t1 where a > 4; +select a from t1 order by a; +select a from t1 where a > 3 order by a; +delete from t1 where a >= 2; +select a from t1 order by a; +drop table t1; + +--echo End of 4.1 tests + +# +# BUG#18160 - Memory-/HEAP Table endless growing indexes +# +CREATE TABLE t1(val INT, KEY USING BTREE(val)) ENGINE=memory; +INSERT INTO t1 VALUES(0); +--replace_result 37 21 +SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='t1'; +UPDATE t1 SET val=1; +--replace_result 37 21 +SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='t1'; +DROP TABLE t1; + +# +# BUG#12873 - BTREE index on MEMORY table with multiple NULL values doesn't +# work properly +# +CREATE TABLE t1 (a INT, UNIQUE USING BTREE(a)) ENGINE=MEMORY; +INSERT INTO t1 VALUES(NULL),(NULL); +DROP TABLE t1; + +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/heap_hash.test b/mysql-test/suite/pbxt/t/heap_hash.test new file mode 100644 index 00000000000..33a589cc52b --- /dev/null +++ b/mysql-test/suite/pbxt/t/heap_hash.test @@ -0,0 +1,266 @@ +# +# Test of heap tables. +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a=1 or a=0; +#show table status like "t1"; +show keys from t1; +select * from t1; +select * from t1 where a=4; +update t1 set b=5 where a=4; +update t1 set b=b+1 where a>=3; +replace t1 values (3,3); +select * from t1; +alter table t1 add c int not null, add key using HASH (c,a); +drop table t1; + +create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +delete from t1 where a > 0; +select * from t1; +drop table t1; + +create table t1 (a int not null,b int not null, primary key using HASH (a)) engine=heap comment="testing heaps"; +insert into t1 values(1,1),(2,2),(3,3),(4,4); +alter table t1 modify a int not null auto_increment, engine=myisam, comment="new myisam table"; +#show table status like "t1"; +select * from t1; +drop table t1; + +create table t1 (a int not null) engine=heap; +insert into t1 values (869751),(736494),(226312),(802616),(728912); +select * from t1 where a > 736494; +alter table t1 add unique uniq_id using HASH (a); +select * from t1 where a > 736494; +select * from t1 where a = 736494; +select * from t1 where a=869751 or a=736494; +select * from t1 where a in (869751,736494,226312,802616); +alter table t1 engine=myisam; +explain select * from t1 where a in (869751,736494,226312,802616); +drop table t1; + +create table t1 (x int not null, y int not null, key x using HASH (x), unique y using HASH (y)) +engine=heap; +insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6); +select * from t1 where x=1; +select * from t1,t1 as t2 where t1.x=t2.y; +explain select * from t1,t1 as t2 where t1.x=t2.y; +drop table t1; + +create table t1 (a int) engine=heap; +insert into t1 values(1); +select max(a) from t1; +drop table t1; + +CREATE TABLE t1 ( a int not null default 0, b int not null default 0, key using HASH (a), key using HASH (b) ) ENGINE=HEAP; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +insert into t1 values(1,1),(1,2),(2,3),(1,3),(1,4),(1,5),(1,6); +select * from t1 where a=1; +drop table t1; + +create table t1 (id int unsigned not null, primary key using HASH (id)) engine=HEAP; +insert into t1 values(1); +select max(id) from t1; +insert into t1 values(2); +select max(id) from t1; +replace into t1 values(1); +drop table t1; + +create table t1 (n int) engine=heap; +drop table t1; + +create table t1 (n int) engine=heap; +drop table if exists t1; + +# Test of non unique index + +CREATE table t1(f1 int not null,f2 char(20) not +null,index(f2)) engine=heap; +INSERT into t1 set f1=12,f2="bill"; +INSERT into t1 set f1=13,f2="bill"; +INSERT into t1 set f1=14,f2="bill"; +INSERT into t1 set f1=15,f2="bill"; +INSERT into t1 set f1=16,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +INSERT into t1 set f1=12,f2="ted"; +delete from t1 where f2="bill"; +select * from t1; +drop table t1; + +# +# Test when using part key searches +# + +create table t1 (btn char(10) not null, key using HASH (btn)) engine=heap; +insert into t1 values ("hello"),("hello"),("hello"),("hello"),("hello"),("a"),("b"),("c"),("d"),("e"),("f"),("g"),("h"),("i"); +explain select * from t1 where btn like "q%"; +select * from t1 where btn like "q%"; +alter table t1 add column new_col char(1) not null, add key using HASH (btn,new_col), drop key btn; +update t1 set new_col=left(btn,1); +explain select * from t1 where btn="a"; +explain select * from t1 where btn="a" and new_col="a"; +drop table t1; + +# +# Test of NULL keys +# + +CREATE TABLE t1 ( + a int default NULL, + b int default NULL, + KEY a using HASH (a), + UNIQUE b using HASH (b) +) engine=heap; +INSERT INTO t1 VALUES (NULL,99),(99,NULL),(1,1),(2,2),(1,3); +SELECT * FROM t1 WHERE a=NULL; +explain SELECT * FROM t1 WHERE a IS NULL; +SELECT * FROM t1 WHERE a<=>NULL; +SELECT * FROM t1 WHERE b=NULL; +explain SELECT * FROM t1 WHERE b IS NULL; +SELECT * FROM t1 WHERE b<=>NULL; + +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES (1,3); +DROP TABLE t1; + +# +# Test when deleting all rows +# + +CREATE TABLE t1 (a int not null, primary key using HASH (a)) engine=heap; +INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); +DELETE from t1 where a < 100; +SELECT * from t1; +DROP TABLE t1; + + +# +# Hash index # records estimate test +# +create table t1 +( + a char(8) not null, + b char(20) not null, + c int not null, + key (a) +) engine=heap; + +insert into t1 values ('aaaa', 'prefill-hash=5',0); +insert into t1 values ('aaab', 'prefill-hash=0',0); +insert into t1 values ('aaac', 'prefill-hash=7',0); +insert into t1 values ('aaad', 'prefill-hash=2',0); +insert into t1 values ('aaae', 'prefill-hash=1',0); +insert into t1 values ('aaaf', 'prefill-hash=4',0); +insert into t1 values ('aaag', 'prefill-hash=3',0); +insert into t1 values ('aaah', 'prefill-hash=6',0); + +explain select * from t1 where a='aaaa'; +explain select * from t1 where a='aaab'; +explain select * from t1 where a='aaac'; +explain select * from t1 where a='aaad'; +insert into t1 select * from t1; + +# avoid statistics differences between normal and ps-protocol tests +flush tables; +explain select * from t1 where a='aaaa'; +explain select * from t1 where a='aaab'; +explain select * from t1 where a='aaac'; +explain select * from t1 where a='aaad'; + +# a known effect: table reload causes statistics to be updated: +flush tables; +explain select * from t1 where a='aaaa'; +explain select * from t1 where a='aaab'; +explain select * from t1 where a='aaac'; +explain select * from t1 where a='aaad'; + +# Check if delete_all_rows() updates #hash_buckets +create table t2 as select * from t1; +delete from t1; +insert into t1 select * from t2; +explain select * from t1 where a='aaaa'; +explain select * from t1 where a='aaab'; +explain select * from t1 where a='aaac'; +explain select * from t1 where a='aaad'; +drop table t1, t2; + + +# Btree and hash index use costs. +create table t1 ( + id int unsigned not null primary key auto_increment, + name varchar(20) not null, + index heap_idx(name), + index btree_idx using btree(name) +) engine=heap; + +create table t2 ( + id int unsigned not null primary key auto_increment, + name varchar(20) not null, + index btree_idx using btree(name), + index heap_idx(name) +) engine=heap; + +insert into t1 (name) values ('Matt'), ('Lilu'), ('Corbin'), ('Carly'), + ('Suzy'), ('Hoppy'), ('Burrito'), ('Mimi'), ('Sherry'), ('Ben'), ('Phil'), + ('Emily'), ('Mike'); +insert into t2 select * from t1; +explain select * from t1 where name='matt'; +explain select * from t2 where name='matt'; + +explain select * from t1 where name='Lilu'; +explain select * from t2 where name='Lilu'; + +explain select * from t1 where name='Phil'; +explain select * from t2 where name='Phil'; + +explain select * from t1 where name='Lilu'; +explain select * from t2 where name='Lilu'; + +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +insert into t1 (name) select name from t2; +flush tables; +select count(*) from t1 where name='Matt'; +explain select * from t1 ignore index (btree_idx) where name='matt'; +show index from t1; + +show index from t1; + +create table t3 +( + a varchar(20) not null, + b varchar(20) not null, + key (a,b) +) engine=heap; +insert into t3 select name, name from t1; +show index from t3; +show index from t3; + +# test rec_per_key use for joins. +explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name; + +drop table t1, t2, t3; + +# Fix for BUG#8371: wrong rec_per_key value for hash index on temporary table +create temporary table t1 ( a int, index (a) ) engine=memory; +insert into t1 values (1),(2),(3),(4),(5); +select a from t1 where a in (1,3); +explain select a from t1 where a in (1,3); +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/help.test b/mysql-test/suite/pbxt/t/help.test new file mode 100644 index 00000000000..766c3da5b07 --- /dev/null +++ b/mysql-test/suite/pbxt/t/help.test @@ -0,0 +1,141 @@ +# category: topic: keyword: +# +# impossible_category_1 +# impossible_function_1 +# impossible_function_5 +# impossible_function_2 +# impossible_function_1 +# impossible_category_2 +# impossible_function_3 +# impossible_function_6 +# impossible_function_4 +# impossible_function_6 +# impossible_category_3 +# impossible_function_7 + +insert into mysql.help_category(help_category_id,name)values(10001,'impossible_category_1'); +select @category1_id:= 10001; +insert into mysql.help_category(help_category_id,name)values(10002,'impossible_category_2'); +select @category2_id:= 10002; +insert into mysql.help_category(help_category_id,name,parent_category_id)values(10003,'impossible_category_3',@category2_id); +select @category3_id:= 10003; + +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10101,'impossible_function_1',@category1_id,'description of \n impossible_function1\n','example of \n impossible_function1'); +select @topic1_id:= 10101; +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10102,'impossible_function_2',@category1_id,'description of \n impossible_function2\n','example of \n impossible_function2'); +select @topic2_id:= 10102; +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10103,'impossible_function_3',@category2_id,'description of \n impossible_function3\n','example of \n impossible_function3'); +select @topic3_id:= 10103; +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10104,'impossible_function_4',@category2_id,'description of \n impossible_function4\n','example of \n impossible_function4'); +select @topic4_id:= 10104; +insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(10105,'impossible_function_7',@category3_id,'description of \n impossible_function5\n','example of \n impossible_function7'); +select @topic5_id:= 10105; + +insert into mysql.help_keyword(help_keyword_id,name)values(10201,'impossible_function_1'); +select @keyword1_id:= 10201; +insert into mysql.help_keyword(help_keyword_id,name)values(10202,'impossible_function_5'); +select @keyword2_id:= 10202; +insert into mysql.help_keyword(help_keyword_id,name)values(10203,'impossible_function_6'); +select @keyword3_id:= 10203; + +insert into mysql.help_relation(help_keyword_id,help_topic_id)values(@keyword1_id,@topic2_id); +insert into mysql.help_relation(help_keyword_id,help_topic_id)values(@keyword2_id,@topic1_id); +insert into mysql.help_relation(help_keyword_id,help_topic_id)values(@keyword3_id,@topic3_id); +insert into mysql.help_relation(help_keyword_id,help_topic_id)values(@keyword3_id,@topic4_id); + +############## +help 'function_of_my_dream'; +help '%possible_f%'; +help 'impossible_func%'; +help 'impossible_category%'; +help 'impossible_%'; + +help '%function_1'; +help '%function_2'; +help '%function_3'; +help '%function_4'; +help '%function_5'; +help '%function_6'; +help '%function_7'; + +help '%category_2'; +help 'impossible_function_1'; +help 'impossible_category_1'; +############## + +--disable_warnings +alter table mysql.help_relation engine=innodb; +alter table mysql.help_keyword engine=innodb; +alter table mysql.help_topic engine=innodb; +alter table mysql.help_category engine=innodb; +--enable_warnings + +############## +help 'function_of_my_dream'; +help '%possible_f%'; +help 'impossible_func%'; +help 'impossible_category%'; +help 'impossible_%'; + +help '%function_1'; +help '%function_2'; +help '%function_3'; +help '%function_4'; +help '%function_5'; +help '%function_6'; +help '%function_7'; + +help '%category_2'; +help 'impossible_function_1'; +help 'impossible_category_1'; +############## + +alter table mysql.help_relation engine=myisam; +alter table mysql.help_keyword engine=myisam; +alter table mysql.help_topic engine=myisam; +alter table mysql.help_category engine=myisam; + +delete from mysql.help_topic where help_topic_id=@topic1_id; +delete from mysql.help_topic where help_topic_id=@topic2_id; +delete from mysql.help_topic where help_topic_id=@topic3_id; +delete from mysql.help_topic where help_topic_id=@topic4_id; +delete from mysql.help_topic where help_topic_id=@topic5_id; + +delete from mysql.help_category where help_category_id=@category3_id; +delete from mysql.help_category where help_category_id=@category2_id; +delete from mysql.help_category where help_category_id=@category1_id; + +delete from mysql.help_keyword where help_keyword_id=@keyword1_id; +delete from mysql.help_keyword where help_keyword_id=@keyword2_id; +delete from mysql.help_keyword where help_keyword_id=@keyword3_id; + +delete from mysql.help_relation where help_keyword_id=@keyword1_id and help_topic_id=@topic2_id; +delete from mysql.help_relation where help_keyword_id=@keyword2_id and help_topic_id=@topic1_id; +delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic3_id; +delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic4_id; + +--echo End of 4.1 tests. + +# +# Test that we can use HELP even under LOCK TABLES. See bug#9953: +# CONVERT_TZ requires mysql.time_zone_name to be locked. +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (i INT); + +LOCK TABLES t1 WRITE; + +HELP no_such_topic; + +UNLOCK TABLES; + +DROP TABLE t1; + + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.1 tests. diff --git a/mysql-test/suite/pbxt/t/insert.test b/mysql-test/suite/pbxt/t/insert.test new file mode 100644 index 00000000000..2ba41e12f71 --- /dev/null +++ b/mysql-test/suite/pbxt/t/insert.test @@ -0,0 +1,241 @@ +# +# Test of refering to old values +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +create table t1 (a int not null); +insert into t1 values (1); +insert into t1 values (a+2); +insert into t1 values (a+3),(a+4); +insert into t1 values (5),(a+6); +select * from t1; +drop table t1; + +# +# Test of duplicate key values with packed keys +# + +create table t1 (id int not null auto_increment primary key, username varchar(32) not null, unique (username)); +insert into t1 values (0,"mysql"); +insert into t1 values (0,"mysql ab"); +insert into t1 values (0,"mysql a"); +insert into t1 values (0,"r1manic"); +insert into t1 values (0,"r1man"); +drop table t1; + +# +# Test insert syntax +# + +create table t1 (a int not null auto_increment, primary key (a), t timestamp, c char(10) default "hello", i int); +insert into t1 values (default,default,default,default), (default,default,default,default), (4,0,"a",5),(default,default,default,default); +select a,t>0,c,i from t1; +truncate table t1; +insert into t1 set a=default,t=default,c=default; +insert into t1 set a=default,t=default,c=default,i=default; +insert into t1 set a=4,t=0,c="a",i=5; +insert into t1 set a=5,t=0,c="a",i=null; +insert into t1 set a=default,t=default,c=default,i=default; +select a,t>0,c,i from t1; +drop table t1; + +# +# Test problem with bulk insert and auto_increment on second part keys +# + +create table t1 (sid char(20), id int(2) NOT NULL auto_increment, key(sid, id)); +insert into t1 values ('skr',NULL),('skr',NULL),('test',NULL); +select * from t1; +insert into t1 values ('rts',NULL),('rts',NULL),('test',NULL); +select * from t1; +drop table t1; + +# +#Test of behaviour with INSERT VALUES (NULL) +# + +create table t1 (id int NOT NULL DEFAULT 8); +-- error 1048 +insert into t1 values(NULL); +insert into t1 values (1), (NULL), (2); +select * from t1; +drop table t1; + +# +# Test if insert ... select distinct +# + +create table t1 (email varchar(50)); +insert into t1 values ('sasha@mysql.com'),('monty@mysql.com'),('foo@hotmail.com'),('foo@aol.com'),('bar@aol.com'); +create table t2(id int not null auto_increment primary key, t2 varchar(50), unique(t2)); +# PBXT: DELAYED not supported +#insert delayed into t2 (t2) select distinct substring(email, locate('@', email)+1) from t1; +insert into t2 (t2) select distinct substring(email, locate('@', email)+1) from t1; +select * from t2; +drop table t1,t2; + +# +# Test of mysqld crash with fully qualified column names +# + +--disable_warnings +drop database if exists mysqltest; +--enable_warnings +create database mysqltest; +use mysqltest; +create table t1 (c int); +insert into mysqltest.t1 set mysqltest.t1.c = '1'; +drop database mysqltest; +use test; + +# +# Test of wrong values for float data (bug #2082) +# + +# PS gives sligthly different numbers for max-float/max-double +--disable_ps_protocol +create table t1(number int auto_increment primary key, original_value varchar(50), f_double double, f_float float, f_double_7_2 double(7,2), f_float_4_3 float (4,3), f_double_u double unsigned, f_float_u float unsigned, f_double_15_1_u double(15,1) unsigned, f_float_3_1_u float (3,1) unsigned); + +set @value= "aa"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +set @value= "1aa"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +set @value= "aa1"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +set @value= "1e+1111111111a"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +set @value= "-1e+1111111111a"; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +--error 1367 +set @value= 1e+1111111111; +--error 1367 +set @value= -1e+1111111111; + + +set @value= 1e+111; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +set @value= -1e+111; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +set @value= 1; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +set @value= -1; +insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value); +--query_vertical select * from t1 where number =last_insert_id() + +drop table t1; +--enable_ps_protocol + +# End of 4.1 tests + +# +# Test automatic result buffering with INSERT INTO t1 ... SELECT ... FROM t1 +# + +create table t1(id1 int not null auto_increment primary key, t char(12)); +create table t2(id2 int not null, t char(12)); +create table t3(id3 int not null, t char(12), index(id3)); +disable_query_log; +let $1 = 100; +while ($1) + { + let $2 = 5; + eval insert into t1(t) values ('$1'); + while ($2) + { + eval insert into t2(id2,t) values ($1,'$2'); + let $3 = 10; + while ($3) + { + eval insert into t3(id3,t) values ($1,'$2'); + dec $3; + } + dec $2; + } + dec $1; + } +enable_query_log; +select count(*) from t2; +insert into t2 select t1.* from t1, t2 t, t3 where t1.id1 = t.id2 and t.id2 = t3.id3; +select count(*) from t2; +drop table t1,t2,t3; + +# +# Test different cases of duplicate fields +# + +create table t1 (a int, b int); +insert into t1 (a,b) values (a,b); +insert into t1 SET a=1, b=a+1; +insert into t1 (a,b) select 1,2; +INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a); +prepare stmt1 from ' replace into t1 (a,a) select 100, ''hundred'' '; +--error 1110 +execute stmt1; +--error 1110 +insert into t1 (a,b,b) values (1,1,1); +--error 1136 +insert into t1 (a,a) values (1,1,1); +--error 1110 +insert into t1 (a,a) values (1,1); +--error 1110 +insert into t1 SET a=1,b=2,a=1; +--error 1110 +insert into t1 (b,b) select 1,2; +--error 1110 +INSERT INTO t1 (b,b) SELECT 0,0 ON DUPLICATE KEY UPDATE a = a + VALUES (a); +drop table t1; + +# +# Test for values returned by ROW_COUNT() function +# (and thus for values returned by mysql_affected_rows()) +# for various forms of INSERT +# +create table t1 (id int primary key, data int); +insert into t1 values (1, 1), (2, 2), (3, 3); +select row_count(); +insert ignore into t1 values (1, 1); +select row_count(); +# Reports that 2 rows are affected (1 deleted + 1 inserted) +replace into t1 values (1, 11); +select row_count(); +replace into t1 values (4, 4); +select row_count(); +# Reports that 2 rows are affected. This conforms to documentation. +# (Useful for differentiating inserts from updates). +insert into t1 values (2, 2) on duplicate key update data= data + 10; +select row_count(); +insert into t1 values (5, 5) on duplicate key update data= data + 10; +select row_count(); +drop table t1; + +# Test of INSERT IGNORE and re-using auto_increment values +create table t1 (id int primary key auto_increment, data int, unique(data)); +insert ignore into t1 values(NULL,100),(NULL,110),(NULL,120); +insert ignore into t1 values(NULL,10),(NULL,20),(NULL,110),(NULL,120),(NULL,100),(NULL,90); +insert ignore into t1 values(NULL,130),(NULL,140),(500,110),(550,120),(450,100),(NULL,150); +select * from t1 order by id; + + +--disable_query_log +drop table if exists t1; +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/insert_select.test b/mysql-test/suite/pbxt/t/insert_select.test new file mode 100644 index 00000000000..7adb6290c10 --- /dev/null +++ b/mysql-test/suite/pbxt/t/insert_select.test @@ -0,0 +1,272 @@ +# +# Problem with INSERT ... SELECT +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); +insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12); +create table t2 (payoutID SMALLINT UNSIGNED NOT NULL PRIMARY KEY); +insert into t2 (payoutID) SELECT DISTINCT payoutID FROM t1; +--error ER_DUP_ENTRY +insert into t2 (payoutID) SELECT payoutID+10 FROM t1; +insert ignore into t2 (payoutID) SELECT payoutID+10 FROM t1; +select * from t2; +drop table t1,t2; + +# +# bug in bulk insert optimization +# test case by Fournier Jocelyn <joc@presence-pc.com> +# + +CREATE TABLE `t1` ( + `numeropost` bigint(20) unsigned NOT NULL default '0', + `icone` tinyint(4) unsigned NOT NULL default '0', + `numreponse` bigint(20) unsigned NOT NULL auto_increment, + `contenu` text NOT NULL, + `pseudo` varchar(50) NOT NULL default '', + `date` datetime NOT NULL default '0000-00-00 00:00:00', + `ip` bigint(11) NOT NULL default '0', + `signature` tinyint(1) unsigned NOT NULL default '0', + PRIMARY KEY (`numeropost`,`numreponse`) + ,KEY `ip` (`ip`), + KEY `date` (`date`), + KEY `pseudo` (`pseudo`), + KEY `numreponse` (`numreponse`) +) ENGINE=MyISAM; + +CREATE TABLE `t2` ( + `numeropost` bigint(20) unsigned NOT NULL default '0', + `icone` tinyint(4) unsigned NOT NULL default '0', + `numreponse` bigint(20) unsigned NOT NULL auto_increment, + `contenu` text NOT NULL, + `pseudo` varchar(50) NOT NULL default '', + `date` datetime NOT NULL default '0000-00-00 00:00:00', + `ip` bigint(11) NOT NULL default '0', + `signature` tinyint(1) unsigned NOT NULL default '0', + PRIMARY KEY (`numeropost`,`numreponse`), + KEY `ip` (`ip`), + KEY `date` (`date`), + KEY `pseudo` (`pseudo`), + KEY `numreponse` (`numreponse`) +) ENGINE=MyISAM; + +INSERT INTO t2 +(numeropost,icone,numreponse,contenu,pseudo,date,ip,signature) VALUES +(9,1,56,'test','joce','2001-07-25 13:50:53' +,3649052399,0); + + +INSERT INTO t1 (numeropost,icone,contenu,pseudo,date,signature,ip) +SELECT 1618,icone,contenu,pseudo,date,signature,ip FROM t2 +WHERE numeropost=9 ORDER BY numreponse ASC; + +show variables like '%bulk%'; + +INSERT INTO t1 (numeropost,icone,contenu,pseudo,date,signature,ip) +SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM t2 +WHERE numeropost=9 ORDER BY numreponse ASC; + +DROP TABLE t1,t2; + +# +# Test of insert ... select from same table +# + +create table t1 (a int not null); +create table t2 (a int not null); +insert into t1 values (1); +insert into t1 values (a+2); +insert into t1 values (a+3); +insert into t1 values (4),(a+5); +insert into t1 select * from t1; +select * from t1; +insert into t1 select * from t1 as t2; +select * from t1; +insert into t2 select * from t1 as t2; +select * from t1; +insert into t1 select t2.a from t1,t2; +select * from t1; +--error 1066 +insert into t1 select * from t1,t1; +drop table t1,t2; + +# +# test replace ... select +# + +create table t1 (a int not null primary key, b char(10)); +create table t2 (a int not null, b char(10)); +insert into t1 values (1,"t1:1"),(3,"t1:3"); +insert into t2 values (2,"t2:2"), (3,"t2:3"); +--error ER_DUP_ENTRY +insert into t1 select * from t2; +select * from t1; +# REPLACE .. SELECT is not yet supported by PS +replace into t1 select * from t2; +--sorted_result +select * from t1; +drop table t1,t2; + +# +# Test that caused uninitialized memory access in auto_increment_key update +# + +CREATE TABLE t1 ( USID INTEGER UNSIGNED, ServerID TINYINT UNSIGNED, State ENUM ('unknown', 'Access-Granted', 'Session-Active', 'Session-Closed' ) NOT NULL DEFAULT 'unknown', SessionID CHAR(32), User CHAR(32) NOT NULL DEFAULT '<UNKNOWN>', NASAddr INTEGER UNSIGNED, NASPort INTEGER UNSIGNED, NASPortType INTEGER UNSIGNED, ConnectSpeed INTEGER UNSIGNED, CarrierType CHAR(32), CallingStationID CHAR(32), CalledStationID CHAR(32), AssignedAddr INTEGER UNSIGNED, SessionTime INTEGER UNSIGNED, PacketsIn INTEGER UNSIGNED, OctetsIn INTEGER UNSIGNED, PacketsOut INTEGER UNSIGNED, OctetsOut INTEGER UNSIGNED, TerminateCause INTEGER UNSIGNED, UnauthTime TINYINT UNSIGNED, AccessRequestTime DATETIME, AcctStartTime DATETIME, AcctLastTime DATETIME, LastModification TIMESTAMP NOT NULL); +CREATE TABLE t2 ( USID INTEGER UNSIGNED AUTO_INCREMENT, ServerID TINYINT UNSIGNED, State ENUM ('unknown', 'Access-Granted', 'Session-Active', 'Session-Closed' ) NOT NULL DEFAULT 'unknown', SessionID CHAR(32), User TEXT NOT NULL, NASAddr INTEGER UNSIGNED, NASPort INTEGER UNSIGNED, NASPortType INTEGER UNSIGNED, ConnectSpeed INTEGER UNSIGNED, CarrierType CHAR(32), CallingStationID CHAR(32), CalledStationID CHAR(32), AssignedAddr INTEGER UNSIGNED, SessionTime INTEGER UNSIGNED, PacketsIn INTEGER UNSIGNED, OctetsIn INTEGER UNSIGNED, PacketsOut INTEGER UNSIGNED, OctetsOut INTEGER UNSIGNED, TerminateCause INTEGER UNSIGNED, UnauthTime TINYINT UNSIGNED, AccessRequestTime DATETIME, AcctStartTime DATETIME, AcctLastTime DATETIME, LastModification TIMESTAMP NOT NULL, INDEX(USID,ServerID,NASAddr,SessionID), INDEX(AssignedAddr)); +INSERT INTO t1 VALUES (39,42,'Access-Granted','46','491721000045',2130706433,17690,NULL,NULL,'Localnet','491721000045','49172200000',754974766,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2003-07-18 00:11:21',NULL,NULL,20030718001121); +INSERT INTO t2 SELECT USID, ServerID, State, SessionID, User, NASAddr, NASPort, NASPortType, ConnectSpeed, CarrierType, CallingStationID, CalledStationID, AssignedAddr, SessionTime, PacketsIn, OctetsIn, PacketsOut, OctetsOut, TerminateCause, UnauthTime, AccessRequestTime, AcctStartTime, AcctLastTime, LastModification from t1 LIMIT 1; +drop table t1,t2; + +# +# Another problem from Bug #2012 +# + +CREATE TABLE t1( + Month date NOT NULL, + Type tinyint(3) unsigned NOT NULL auto_increment, + Field int(10) unsigned NOT NULL, + Count int(10) unsigned NOT NULL, + UNIQUE KEY Month (Month,Type,Field) +); + +insert into t1 Values +(20030901, 1, 1, 100), +(20030901, 1, 2, 100), +(20030901, 2, 1, 100), +(20030901, 2, 2, 100), +(20030901, 3, 1, 100); + +select * from t1; + +Select null, Field, Count From t1 Where Month=20030901 and Type=2; + +create table t2(No int not null, Field int not null, Count int not null); + +insert into t2 Select null, Field, Count From t1 Where Month=20030901 and Type=2; + +select * from t2; + +drop table t1, t2; + +# +# BUG#6034 - Error code 124: Wrong medium type +# +CREATE TABLE t1 ( + ID int(11) NOT NULL auto_increment, + NO int(11) NOT NULL default '0', + SEQ int(11) NOT NULL default '0', + PRIMARY KEY (ID), + KEY t1$NO (SEQ,NO) +) ENGINE=MyISAM; +INSERT INTO t1 (SEQ, NO) SELECT "1" AS SEQ, IF(MAX(NO) IS NULL, 0, MAX(NO)) + 1 AS NO FROM t1 WHERE (SEQ = 1); +select SQL_BUFFER_RESULT * from t1 WHERE (SEQ = 1); +drop table t1; + +# +# Bug#10886 - Have to restore default values after update ON DUPLICATE KEY +# +create table t1 (f1 int); +create table t2 (ff1 int unique, ff2 int default 1); +insert into t1 values (1),(1),(2); +insert into t2(ff1) select f1 from t1 on duplicate key update ff2=ff2+1; +select * from t2; +drop table t1, t2; +# +# BUGS #9728 - 'Decreased functionality in "on duplicate key update"' +# #8147 - 'a column proclaimed ambigous in INSERT ... SELECT .. ON +# DUPLICATE' +# +create table t1 (a int unique); +create table t2 (a int, b int); +create table t3 (c int, d int); +insert into t1 values (1),(2); +insert into t2 values (1,2); +insert into t3 values (1,6),(3,7); +select * from t1; +insert into t1 select a from t2 on duplicate key update a= t1.a + t2.b; +select * from t1; +insert into t1 select a+1 from t2 on duplicate key update t1.a= t1.a + t2.b+1; +select * from t1; +insert into t1 select t3.c from t3 on duplicate key update a= a + t3.d; +select * from t1; +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + 10; + +#Some error cases +--error 1052 +insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +--error 1054 +insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; +--error 1054 +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; +drop table t1,t2,t3; + +# +# Bug #12695 Item_func_isnull::update_used_tables() did not update +# const_item_cache +create table t1(f1 varchar(5) key); +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +select * from t1; +drop table t1; + +# +# Bug #13392 values() fails with 'ambiguous' or returns NULL +# with ON DUPLICATE and SELECT +create table t1(x int, y int); +create table t2(x int, z int); +insert into t1(x,y) select x,z from t2 on duplicate key update x=values(x); +--error 1054 +insert into t1(x,y) select x,z from t2 on duplicate key update x=values(z); +--error 1054 +insert into t1(x,y) select x,z from t2 on duplicate key update x=values(t2.x); +drop table t1,t2; + +# +# Bug #9676: INSERT INTO x SELECT .. FROM x LIMIT 1; slows down with big +# tables +# + +#Note: not an exsaustive test : just a check of the code path. +CREATE TABLE t1 (a int PRIMARY KEY); +INSERT INTO t1 values (1), (2); + +INSERT INTO t1 SELECT a + 2 FROM t1 LIMIT 1; + +DROP TABLE t1; + +# End of 4.1 tests + +# +# Bug #18080: INSERT ... SELECT ... JOIN results in ambiguous field list error +# +CREATE TABLE t1 (x int, y int); +CREATE TABLE t2 (z int, y int); +CREATE TABLE t3 (a int, b int); +INSERT INTO t3 (SELECT x, y FROM t1 JOIN t2 USING (y) WHERE z = 1); +DROP TABLE IF EXISTS t1,t2,t3; + +# +# Bug #21774: Column count doesn't match value count at row x +# +CREATE DATABASE bug21774_1; +CREATE DATABASE bug21774_2; + +CREATE TABLE bug21774_1.t1(id VARCHAR(10) NOT NULL,label VARCHAR(255)); +CREATE TABLE bug21774_2.t1(id VARCHAR(10) NOT NULL,label VARCHAR(255)); +CREATE TABLE bug21774_1.t2(id VARCHAR(10) NOT NULL,label VARCHAR(255)); + +INSERT INTO bug21774_2.t1 SELECT t1.* FROM bug21774_1.t1; + +use bug21774_1; +INSERT INTO bug21774_2.t1 SELECT t1.* FROM t1; + +DROP DATABASE bug21774_1; +DROP DATABASE bug21774_2; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/insert_update.test b/mysql-test/suite/pbxt/t/insert_update.test new file mode 100644 index 00000000000..1a6fb5f2d90 --- /dev/null +++ b/mysql-test/suite/pbxt/t/insert_update.test @@ -0,0 +1,147 @@ +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B)); +INSERT t1 VALUES (1,2,10), (3,4,20); +INSERT t1 VALUES (5,6,30) ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1; +INSERT t1 VALUES (5,7,40) ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1; +INSERT t1 VALUES (8,4,50) ON DUPLICATE KEY UPDATE c=c+1000; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +INSERT t1 VALUES (1,4,60) ON DUPLICATE KEY UPDATE c=c+10000; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +-- error ER_DUP_ENTRY +INSERT t1 VALUES (1,9,70) ON DUPLICATE KEY UPDATE c=c+100000, b=4; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +TRUNCATE TABLE t1; +INSERT t1 VALUES (1,2,10), (3,4,20); +INSERT t1 VALUES (5,6,30), (7,4,40), (8,9,60) ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1; +INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +INSERT t1 VALUES (2,1,11), (7,4,40) ON DUPLICATE KEY UPDATE c=c+VALUES(a); +SELECT *, VALUES(a) FROM t1 order by a; # PBXT required ORDER for consistant result +--replace_column 9 ROWS +explain extended SELECT *, VALUES(a) FROM t1; +--replace_column 9 ROWS +explain extended select * from t1 where values(a); +DROP TABLE t1; + +# +# test for Bug #2709 "Affected Rows for ON DUPL.KEY undocumented, +# perhaps illogical" +# +create table t1(a int primary key, b int); +insert into t1 values(1,1),(2,2),(3,3),(4,4),(5,5); +select * from t1; + +--enable_info +insert into t1 values(4,14),(5,15),(6,16),(7,17),(8,18) + on duplicate key update b=b+10; +--disable_info + +select * from t1; + +enable_info; +replace into t1 values(5,25),(6,26),(7,27),(8,28),(9,29); +disable_info; + +select * from t1 order by a; # PBXT required for consistent order +drop table t1; + +# WorkLog #2274 - enable INSERT .. SELECT .. UPDATE syntax +# Same tests as beginning of this test except that insert source +# is a result from a select statement +# +CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B)); +INSERT t1 VALUES (1,2,10), (3,4,20); +INSERT t1 SELECT 5,6,30 FROM DUAL ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +INSERT t1 SELECT 5,7,40 FROM DUAL ON DUPLICATE KEY UPDATE c=c+100; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +INSERT t1 SELECT 8,4,50 FROM DUAL ON DUPLICATE KEY UPDATE c=c+1000; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +INSERT t1 SELECT 1,4,60 FROM DUAL ON DUPLICATE KEY UPDATE c=c+10000; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +-- error ER_DUP_ENTRY +INSERT t1 SELECT 1,9,70 FROM DUAL ON DUPLICATE KEY UPDATE c=c+100000, b=4; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +TRUNCATE TABLE t1; +INSERT t1 VALUES (1,2,10), (3,4,20); +CREATE TABLE t2 (a INT, b INT, c INT, d INT); +# column names deliberately clash with columns in t1 (Bug#8147) +INSERT t2 VALUES (5,6,30,1), (7,4,40,1), (8,9,60,1); +INSERT t2 VALUES (2,1,11,2), (7,4,40,2); +INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100; +SELECT * FROM t1; +INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0; +SELECT * FROM t1 order by a; # PBXT required ORDER for consistant result +--error 1052 +INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a); +INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a); +SELECT *, VALUES(a) FROM t1 order by a; # PBXT required ORDER for consistant result +DROP TABLE t1; +DROP TABLE t2; + +# +# Bug#9725 - "disapearing query/hang" and "unknown error" with "on duplicate key update" +# INSERT INGORE...UPDATE gives bad error or breaks protocol. +# +create table t1 (a int not null unique) engine=myisam; +insert into t1 values (1),(2); +insert ignore into t1 select 1 on duplicate key update a=2; +select * from t1; +insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ; +select * from t1; +insert into t1 select 1 on duplicate key update a=2; +select * from t1; +--error 1052 +insert into t1 select a from t1 on duplicate key update a=a+1 ; +--error 1052 +insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; +drop table t1; + +# +# Bug#10109 - INSERT .. SELECT ... ON DUPLICATE KEY UPDATE fails +# Bogus "Duplicate columns" error message +# + +CREATE TABLE t1 ( + a BIGINT(20) NOT NULL DEFAULT 0, + PRIMARY KEY (a) +) ENGINE=MyISAM; + +INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a) ; + +DROP TABLE t1; + +# +# Bug#21555: incorrect behavior with INSERT ... ON DUPL KEY UPDATE and VALUES +# + + +# End of 4.1 tests +CREATE TABLE t1 +( + a BIGINT UNSIGNED, + b BIGINT UNSIGNED, + PRIMARY KEY (a) +); + +INSERT INTO t1 VALUES (45, 1) ON DUPLICATE KEY UPDATE b = + IF(VALUES(b) > t1.b, VALUES(b), t1.b); +SELECT * FROM t1; +INSERT INTO t1 VALUES (45, 2) ON DUPLICATE KEY UPDATE b = + IF(VALUES(b) > t1.b, VALUES(b), t1.b); +SELECT * FROM t1; +INSERT INTO t1 VALUES (45, 1) ON DUPLICATE KEY UPDATE b = + IF(VALUES(b) > t1.b, VALUES(b), t1.b); +SELECT * FROM t1; + +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/join.test b/mysql-test/suite/pbxt/t/join.test new file mode 100644 index 00000000000..7e7e1c10f06 --- /dev/null +++ b/mysql-test/suite/pbxt/t/join.test @@ -0,0 +1,654 @@ +# +# Initialization +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +# +# Test different join syntaxes +# + +CREATE TABLE t1 (S1 INT); +CREATE TABLE t2 (S1 INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t1 JOIN t2; +SELECT * FROM t1 INNER JOIN t2; +SELECT * from t1 JOIN t2 USING (S1); +SELECT * FROM t1 INNER JOIN t2 USING (S1); +SELECT * from t1 CROSS JOIN t2; +SELECT * from t1 LEFT JOIN t2 USING(S1); +SELECT * from t1 LEFT JOIN t2 ON(t2.S1=2); +SELECT * from t1 RIGHT JOIN t2 USING(S1); +SELECT * from t1 RIGHT JOIN t2 ON(t1.S1=1); +drop table t1,t2; + +# +# This failed for lia Perminov +# + +create table t1 (id int primary key); +create table t2 (id int); +insert into t1 values (75); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +replace into t1 values (76); +replace into t1 values (76); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (105); +insert into t1 values (106); +insert into t1 values (107); + +insert into t2 values (107),(75),(1000); + +select t1.id, t2.id from t1, t2 where t2.id = t1.id; +select t1.id, count(t2.id) from t1,t2 where t2.id = t1.id group by t1.id; +select t1.id, count(t2.id) from t1,t2 where t2.id = t1.id group by t2.id; + +# +# Test problems with impossible ON or WHERE +# +select t1.id,t2.id from t2 left join t1 on t1.id>=74 and t1.id<=0 where t2.id=75 and t1.id is null; +explain select t1.id,t2.id from t2 left join t1 on t1.id>=74 and t1.id<=0 where t2.id=75 and t1.id is null; +explain select t1.id, t2.id from t1, t2 where t2.id = t1.id and t1.id <0 and t1.id > 0; +drop table t1,t2; + +# +# problem with join +# + +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + token varchar(100) DEFAULT '' NOT NULL, + count int(11) DEFAULT '0' NOT NULL, + qty int(11), + phone char(1) DEFAULT '' NOT NULL, + timestamp datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, + PRIMARY KEY (id), + KEY token (token(15)), + KEY timestamp (timestamp), + UNIQUE token_2 (token(75),count,phone) +); + +INSERT INTO t1 VALUES (21,'e45703b64de71482360de8fec94c3ade',3,7800,'n','1999-12-23 17:22:21'); +INSERT INTO t1 VALUES (22,'e45703b64de71482360de8fec94c3ade',4,5000,'y','1999-12-23 17:22:21'); +INSERT INTO t1 VALUES (18,'346d1cb63c89285b2351f0ca4de40eda',3,13200,'b','1999-12-23 11:58:04'); +INSERT INTO t1 VALUES (17,'ca6ddeb689e1b48a04146b1b5b6f936a',4,15000,'b','1999-12-23 11:36:53'); +INSERT INTO t1 VALUES (16,'ca6ddeb689e1b48a04146b1b5b6f936a',3,13200,'b','1999-12-23 11:36:53'); +INSERT INTO t1 VALUES (26,'a71250b7ed780f6ef3185bfffe027983',5,1500,'b','1999-12-27 09:44:24'); +INSERT INTO t1 VALUES (24,'4d75906f3c37ecff478a1eb56637aa09',3,5400,'y','1999-12-23 17:29:12'); +INSERT INTO t1 VALUES (25,'4d75906f3c37ecff478a1eb56637aa09',4,6500,'y','1999-12-23 17:29:12'); +INSERT INTO t1 VALUES (27,'a71250b7ed780f6ef3185bfffe027983',3,6200,'b','1999-12-27 09:44:24'); +INSERT INTO t1 VALUES (28,'a71250b7ed780f6ef3185bfffe027983',3,5400,'y','1999-12-27 09:44:36'); +INSERT INTO t1 VALUES (29,'a71250b7ed780f6ef3185bfffe027983',4,17700,'b','1999-12-27 09:45:05'); + +CREATE TABLE t2 ( + id int(11) NOT NULL auto_increment, + category int(11) DEFAULT '0' NOT NULL, + county int(11) DEFAULT '0' NOT NULL, + state int(11) DEFAULT '0' NOT NULL, + phones int(11) DEFAULT '0' NOT NULL, + nophones int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (id), + KEY category (category,county,state) +); +INSERT INTO t2 VALUES (3,2,11,12,5400,7800); +INSERT INTO t2 VALUES (4,2,25,12,6500,11200); +INSERT INTO t2 VALUES (5,1,37,6,10000,12000); +select a.id, b.category as catid, b.state as stateid, b.county as countyid from t1 a, t2 b ignore index (primary) where (a.token ='a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id); +select a.id, b.category as catid, b.state as stateid, b.county as +countyid from t1 a, t2 b where (a.token = +'a71250b7ed780f6ef3185bfffe027983') and (a.count = b.id) order by a.id; + +drop table t1, t2; + +# +# Test of join of many tables. + +create table t1 (a int primary key); +insert into t1 values(1),(2); +select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +--replace_result "31 tables" "XX tables" "61 tables" "XX tables" +--error 1116 +select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a); +--replace_result "31 tables" "XX tables" "61 tables" "XX tables" +--error 1116 +select a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); +drop table t1; + +# +# Simple join test. This failed in 3.23.42, there should have been +# no matches, still three matches were found. +# + +CREATE TABLE t1 ( + a int(11) NOT NULL, + b int(11) NOT NULL, + PRIMARY KEY (a,b) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(2,3); + +CREATE TABLE t2 ( + a int(11) default NULL +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (2),(3); +SELECT t1.a,t2.a,b FROM t1,t2 WHERE t1.a=t2.a AND (t1.a=1 OR t1.a=2) AND b>=1 AND b<=3; +DROP TABLE t1, t2; + +# +# TEST LEFT JOIN with DATE columns +# + +CREATE TABLE t1 (d DATE NOT NULL); +CREATE TABLE t2 (d DATE NOT NULL); +INSERT INTO t1 (d) VALUES ('2001-08-01'),('0000-00-00'); +SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE t2.d IS NULL; +SELECT * FROM t1 LEFT JOIN t2 USING (d) WHERE d IS NULL; +SELECT * from t1 WHERE t1.d IS NULL; +SELECT * FROM t1 WHERE 1/0 IS NULL; +DROP TABLE t1,t2; + +# +# Problem with reference from const tables +# +CREATE TABLE t1 ( + Document_ID varchar(50) NOT NULL default '', + Contractor_ID varchar(6) NOT NULL default '', + Language_ID char(3) NOT NULL default '', + Expiration_Date datetime default NULL, + Publishing_Date datetime default NULL, + Title text, + Column_ID varchar(50) NOT NULL default '', + PRIMARY KEY (Language_ID,Document_ID,Contractor_ID) +); + +INSERT INTO t1 VALUES ('xep80','1','ger','2001-12-31 20:00:00','2001-11-12 10:58:00','Kartenbestellung - jetzt auch online','anle'),('','999998','',NULL,NULL,NULL,''); + +CREATE TABLE t2 ( + Contractor_ID char(6) NOT NULL default '', + Language_ID char(3) NOT NULL default '', + Document_ID char(50) NOT NULL default '', + CanRead char(1) default NULL, + Customer_ID int(11) NOT NULL default '0', + PRIMARY KEY (Contractor_ID,Language_ID,Document_ID,Customer_ID) +); + +INSERT INTO t2 VALUES ('5','ger','xep80','1',999999),('1','ger','xep80','1',999999); +CREATE TABLE t3 ( + Language_ID char(3) NOT NULL default '', + Column_ID char(50) NOT NULL default '', + Contractor_ID char(6) NOT NULL default '', + CanRead char(1) default NULL, + Active char(1) default NULL, + PRIMARY KEY (Language_ID,Column_ID,Contractor_ID) +); +INSERT INTO t3 VALUES ('ger','home','1','1','1'),('ger','Test','1','0','0'),('ger','derclu','1','0','0'),('ger','clubne','1','0','0'),('ger','philos','1','0','0'),('ger','clubko','1','0','0'),('ger','clubim','1','1','1'),('ger','progra','1','0','0'),('ger','progvo','1','0','0'),('ger','progsp','1','0','0'),('ger','progau','1','0','0'),('ger','progku','1','0','0'),('ger','progss','1','0','0'),('ger','nachl','1','0','0'),('ger','mitgli','1','0','0'),('ger','mitsu','1','0','0'),('ger','mitbus','1','0','0'),('ger','ergmar','1','1','1'),('ger','home','4','1','1'),('ger','derclu','4','1','1'),('ger','clubne','4','0','0'),('ger','philos','4','1','1'),('ger','clubko','4','1','1'),('ger','clubim','4','1','1'),('ger','progra','4','1','1'),('ger','progvo','4','1','1'),('ger','progsp','4','1','1'),('ger','progau','4','0','0'),('ger','progku','4','1','1'),('ger','progss','4','1','1'),('ger','nachl','4','1','1'),('ger','mitgli','4','0','0'),('ger','mitsu','4','0','0'),('ger','mitbus','4','0','0'),('ger','ergmar','4','1','1'),('ger','progra2','1','0','0'),('ger','archiv','4','1','1'),('ger','anmeld','4','1','1'),('ger','thema','4','1','1'),('ger','edito','4','1','1'),('ger','madis','4','1','1'),('ger','enma','4','1','1'),('ger','madis','1','1','1'),('ger','enma','1','1','1'),('ger','vorsch','4','0','0'),('ger','veranst','4','0','0'),('ger','anle','4','1','1'),('ger','redak','4','1','1'),('ger','nele','4','1','1'),('ger','aukt','4','1','1'),('ger','callcenter','4','1','1'),('ger','anle','1','0','0'); +delete from t1 where Contractor_ID='999998'; +insert into t1 (Contractor_ID) Values ('999998'); +SELECT DISTINCT COUNT(t1.Title) FROM t1, +t2, t3 WHERE +t1.Document_ID='xep80' AND t1.Contractor_ID='1' AND +t1.Language_ID='ger' AND '2001-12-21 23:14:24' >= +Publishing_Date AND '2001-12-21 23:14:24' <= Expiration_Date AND +t1.Document_ID = t2.Document_ID AND +t1.Language_ID = t2.Language_ID AND +t1.Contractor_ID = t2.Contractor_ID AND ( +t2.Customer_ID = '4' OR +t2.Customer_ID = '999999' OR +t2.Customer_ID = '1' )AND t2.CanRead += '1' AND t1.Column_ID=t3.Column_ID AND +t1.Language_ID=t3.Language_ID AND ( +t3.Contractor_ID = '4' OR +t3.Contractor_ID = '999999' OR +t3.Contractor_ID = '1') AND +t3.CanRead='1' AND t3.Active='1'; +SELECT DISTINCT COUNT(t1.Title) FROM t1, +t2, t3 WHERE +t1.Document_ID='xep80' AND t1.Contractor_ID='1' AND +t1.Language_ID='ger' AND '2001-12-21 23:14:24' >= +Publishing_Date AND '2001-12-21 23:14:24' <= Expiration_Date AND +t1.Document_ID = t2.Document_ID AND +t1.Language_ID = t2.Language_ID AND +t1.Contractor_ID = t2.Contractor_ID AND ( +t2.Customer_ID = '4' OR +t2.Customer_ID = '999999' OR +t2.Customer_ID = '1' )AND t2.CanRead += '1' AND t1.Column_ID=t3.Column_ID AND +t1.Language_ID=t3.Language_ID AND ( +t3.Contractor_ID = '4' OR +t3.Contractor_ID = '999999' OR +t3.Contractor_ID = '1') AND +t3.CanRead='1' AND t3.Active='1'; +drop table t1,t2,t3; + +# +# Bug when doing full join and NULL fields. +# + +CREATE TABLE t1 ( + t1_id int(11) default NULL, + t2_id int(11) default NULL, + type enum('Cost','Percent') default NULL, + cost_unit enum('Cost','Unit') default NULL, + min_value double default NULL, + max_value double default NULL, + t3_id int(11) default NULL, + item_id int(11) default NULL +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (12,5,'Percent','Cost',-1,0,-1,-1),(14,4,'Percent','Cost',-1,0,-1,-1),(18,5,'Percent','Cost',-1,0,-1,-1),(19,4,'Percent','Cost',-1,0,-1,-1),(20,5,'Percent','Cost',100,-1,22,291),(21,5,'Percent','Cost',100,-1,18,291),(22,1,'Percent','Cost',100,-1,6,291),(23,1,'Percent','Cost',100,-1,21,291),(24,1,'Percent','Cost',100,-1,9,291),(25,1,'Percent','Cost',100,-1,4,291),(26,1,'Percent','Cost',100,-1,20,291),(27,4,'Percent','Cost',100,-1,7,202),(28,1,'Percent','Cost',50,-1,-1,137),(29,2,'Percent','Cost',100,-1,4,354),(30,2,'Percent','Cost',100,-1,9,137),(93,2,'Cost','Cost',-1,10000000,-1,-1); +CREATE TABLE t2 ( + id int(10) unsigned NOT NULL auto_increment, + name varchar(255) default NULL, + PRIMARY KEY (id) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,'s1'),(2,'s2'),(3,'s3'),(4,'s4'),(5,'s5'); +select t1.*, t2.* from t1, t2 where t2.id=t1.t2_id limit 2; +drop table t1,t2; + +# +# Bug in range optimiser with MAYBE_KEY +# + +CREATE TABLE t1 ( + siteid varchar(25) NOT NULL default '', + emp_id varchar(30) NOT NULL default '', + rate_code varchar(10) default NULL, + UNIQUE KEY site_emp (siteid,emp_id), + KEY siteid (siteid) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('rivercats','psmith','cust'), ('rivercats','KWalker','cust'); +CREATE TABLE t2 ( + siteid varchar(25) NOT NULL default '', + rate_code varchar(10) NOT NULL default '', + base_rate float NOT NULL default '0', + PRIMARY KEY (siteid,rate_code), + FULLTEXT KEY rate_code (rate_code) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES ('rivercats','cust',20); +SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND lr.siteid = 'rivercats'; +SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith'; +SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND siteid = 'rivercats'; +SELECT rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE siteid = 'rivercats' AND emp.emp_id = 'psmith'; +drop table t1,t2; + +# +# Problem with internal list handling when reducing WHERE +# + +CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, Value1 VARCHAR(255)); +CREATE TABLE t2 (ID INTEGER NOT NULL PRIMARY KEY, Value2 VARCHAR(255)); +INSERT INTO t1 VALUES (1, 'A'); +INSERT INTO t2 VALUES (1, 'B'); + +SELECT * FROM t1 NATURAL JOIN t2 WHERE 1 AND (Value1 = 'A' AND Value2 <> 'B'); +SELECT * FROM t1 NATURAL JOIN t2 WHERE 1 AND Value1 = 'A' AND Value2 <> 'B'; +SELECT * FROM t1 NATURAL JOIN t2 WHERE (Value1 = 'A' AND Value2 <> 'B') AND 1; +drop table t1,t2; + +# +# dummy natural join (no common columns) Bug #4807 +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +CREATE TABLE t3 (c int); +SELECT * FROM t1 NATURAL JOIN t2 NATURAL JOIN t3; +DROP TABLE t1, t2, t3; + +# +# Test combination of join methods +# + +create table t1 (i int); +create table t2 (i int); +create table t3 (i int); +insert into t1 values(1),(2); +insert into t2 values(2),(3); +insert into t3 values (2),(4); + +select * from t1 natural left join t2; +select * from t1 left join t2 on (t1.i=t2.i); +select * from t1 natural left join t2 natural left join t3; +select * from t1 left join t2 on (t1.i=t2.i) left join t3 on (t2.i=t3.i); + +select * from t3 natural right join t2; +select * from t3 right join t2 on (t3.i=t2.i); +select * from t3 natural right join t2 natural right join t1; +select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i); + +select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i; +select * from t1,t2 left join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; +select t1.i,t2.i,t3.i from t2 natural left join t3,t1 order by t1.i,t2.i,t3.i; +select t1.i,t2.i,t3.i from t2 left join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; + +select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i; +select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; +select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; +select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; +drop table t1,t2,t3; + +# End of 4.1 tests + +# +# Tests for WL#2486 Natural/using join according to SQL:2003. +# +# NOTICE: +# - The tests are designed so that all statements, except MySQL +# extensions run on any SQL server. Please do no change. +# - Tests marked with TODO will be submitted as bugs. +# + +create table t1 (c int, b int); +create table t2 (a int, b int); +create table t3 (b int, c int); +create table t4 (y int, c int); +create table t5 (y int, z int); +create table t6 (a int, c int); + +insert into t1 values (10,1); +insert into t1 values (3 ,1); +insert into t1 values (3 ,2); +insert into t2 values (2, 1); +insert into t3 values (1, 3); +insert into t3 values (1,10); +insert into t4 values (11,3); +insert into t4 values (2, 3); +insert into t5 values (11,4); +insert into t6 values (2, 3); + +# Views with simple natural join. +create algorithm=merge view v1a as +select * from t1 natural join t2; +# as above, but column names are cross-renamed: a->c, c->b, b->a +create algorithm=merge view v1b(a,b,c) as +select * from t1 natural join t2; +# as above, but column names are aliased: a->c, c->b, b->a +create algorithm=merge view v1c as +select b as a, c as b, a as c from t1 natural join t2; +# as above, but column names are cross-renamed, and aliased +# a->c->b, c->b->a, b->a->c +create algorithm=merge view v1d(b, a, c) as +select a as c, c as b, b as a from t1 natural join t2; + +# Views with JOIN ... ON +create algorithm=merge view v2a as +select t1.c, t1.b, t2.a from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c; +create algorithm=merge view v2b as +select t1.c as b, t1.b as a, t2.a as c +from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c; + +# Views with bigger natural join +create algorithm=merge view v3a as +select * from t1 natural join t2 natural join t3; +create algorithm=merge view v3b as +select * from t1 natural join (t2 natural join t3); + +# View over views with mixed natural join and join ... on +create algorithm=merge view v4 as +select * from v2a natural join v3a; + +# Nested natural/using joins. +select * from (t1 natural join t2) natural join (t3 natural join t4); +select * from (t1 natural join t2) natural left join (t3 natural join t4); +select * from (t3 natural join t4) natural right join (t1 natural join t2); +select * from (t1 natural left join t2) natural left join (t3 natural left join t4); +select * from (t4 natural right join t3) natural right join (t2 natural right join t1); +select * from t1 natural join t2 natural join t3 natural join t4; +select * from ((t1 natural join t2) natural join t3) natural join t4; +select * from t1 natural join (t2 natural join (t3 natural join t4)); +# BUG#15355: this query fails in 'prepared statements' mode +# select * from ((t3 natural join (t1 natural join t2)) natural join t4) natural join t5; +# select * from ((t3 natural left join (t1 natural left join t2)) natural left join t4) natural left join t5; +select * from t5 natural right join (t4 natural right join ((t2 natural right join t1) natural right join t3)); +select * from (t1 natural join t2), (t3 natural join t4); +# MySQL extension - nested comma ',' operator instead of cross join. +select * from t5 natural join ((t1 natural join t2), (t3 natural join t4)); +select * from ((t1 natural join t2), (t3 natural join t4)) natural join t5; +select * from t5 natural join ((t1 natural join t2) cross join (t3 natural join t4)); +select * from ((t1 natural join t2) cross join (t3 natural join t4)) natural join t5; + +select * from (t1 join t2 using (b)) join (t3 join t4 using (c)) using (c); +select * from (t1 join t2 using (b)) natural join (t3 join t4 using (c)); + + +# Other clauses refer to NJ columns. +select a,b,c from (t1 natural join t2) natural join (t3 natural join t4) +where b + 1 = y or b + 10 = y group by b,c,a having min(b) < max(y) order by a; +select * from (t1 natural join t2) natural left join (t3 natural join t4) +where b + 1 = y or b + 10 = y group by b,c,a,y having min(b) < max(y) order by a, y; +select * from (t3 natural join t4) natural right join (t1 natural join t2) +where b + 1 = y or b + 10 = y group by b,c,a,y having min(b) < max(y) order by a, y; + +# Qualified column references to NJ columns. +select * from t1 natural join t2 where t1.c > t2.a; +select * from t1 natural join t2 where t1.b > t2.b; +select * from t1 natural left join (t4 natural join t5) where t5.z is not NULL; + +# Nested 'join ... on' - name resolution of ON conditions +select * from t1 join (t2 join t4 on b + 1 = y) on t1.c = t4.c; +select * from (t2 join t4 on b + 1 = y) join t1 on t1.c = t4.c; +select * from t1 natural join (t2 join t4 on b + 1 = y); +select * from (t1 cross join t2) join (t3 cross join t4) on (a < y and t2.b < t3.c); + +# MySQL extension - 'join ... on' over nested comma operator +select * from (t1, t2) join (t3, t4) on (a < y and t2.b < t3.c); +select * from (t1 natural join t2) join (t3 natural join t4) on a = y; +select * from ((t3 join (t1 join t2 on c > a) on t3.b < t2.a) join t4 on y > t1.c) join t5 on z = t1.b + 3; + +# MySQL extension - refererence qualified coalesced columns +select * from t1 natural join t2 where t1.b > 0; +select * from t1 natural join (t4 natural join t5) where t4.y > 7; +select * from (t4 natural join t5) natural join t1 where t4.y > 7; +select * from t1 natural left join (t4 natural join t5) where t4.y > 7; +select * from (t4 natural join t5) natural right join t1 where t4.y > 7; +select * from (t1 natural join t2) join (t3 natural join t4) on t1.b = t3.b; + +# MySQL extension - select qualified columns of NJ columns +select t1.*, t2.* from t1 natural join t2; +select t1.*, t2.*, t3.*, t4.* from (t1 natural join t2) natural join (t3 natural join t4); + +# Queries over subselects in the FROM clause +select * from (select * from t1 natural join t2) as t12 + natural join + (select * from t3 natural join t4) as t34; +select * from (select * from t1 natural join t2) as t12 + natural left join + (select * from t3 natural join t4) as t34; +select * from (select * from t3 natural join t4) as t34 + natural right join + (select * from t1 natural join t2) as t12; + +# Queries over views +select * from v1a; +select * from v1b; +select * from v1c; +select * from v1d; +select * from v2a; +select * from v2b; +select * from v3a; +select * from v3b; +select * from v4; +select * from v1a natural join v2a; +select v2a.* from v1a natural join v2a; +select * from v1b join v2a on v1b.b = v2a.c; +select * from v1c join v2a on v1c.b = v2a.c; +select * from v1d join v2a on v1d.a = v2a.c; +select * from v1a join (t3 natural join t4) on a = y; + +# TODO: add tests with correlated subqueries for natural join/join on. +# related to BUG#15269 + + +#-------------------------------------------------------------------- +# Negative tests (tests for errors) +#-------------------------------------------------------------------- +-- error 1052 +select * from t1 natural join (t3 cross join t4); # works in Oracle - bug +-- error 1052 +select * from (t3 cross join t4) natural join t1; # works in Oracle - bug +-- error 1052 +select * from t1 join (t2, t3) using (b); +-- error 1052 +select * from ((t1 natural join t2), (t3 natural join t4)) natural join t6; +-- error 1052 +select * from ((t1 natural join t2), (t3 natural join t4)) natural join t6; +-- error 1052 +select * from t6 natural join ((t1 natural join t2), (t3 natural join t4)); +-- error 1052 +select * from (t1 join t2 on t1.b=t2.b) natural join (t3 natural join t4); +-- error 1052 +select * from (t3 natural join t4) natural join (t1 join t2 on t1.b=t2.b); +# this one is OK, the next equivalent one is incorrect (bug in Oracle) +-- error 1052 +select * from (t3 join (t4 natural join t5) on (b < z)) + natural join + (t1 natural join t2); +-- error 1052 +select * from (t1 natural join t2) natural join (t3 join (t4 natural join t5) on (b < z)); + +-- error 1054 +select t1.b from v1a; +-- error 1054 +select * from v1a join v1b on t1.b = t2.b; + +# +# Bug #17523 natural join and information_schema +# +# We mask out the Privileges column because it differs with embedded server +--replace_column 31 # +select * from information_schema.statistics join information_schema.columns + using(table_name,column_name) where table_name='user'; + +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; +drop table t6; + +drop view v1a; +drop view v1b; +drop view v1c; +drop view v1d; +drop view v2a; +drop view v2b; +drop view v3a; +drop view v3b; +drop view v4; + +# +# BUG#15229 - columns of nested joins that are not natural joins incorrectly +# materialized +# +create table t1 (a1 int, a2 int); +create table t2 (a1 int, b int); +create table t3 (c1 int, c2 int); +create table t4 (c2 int); + +insert into t1 values (1,1); +insert into t2 values (1,1); +insert into t3 values (1,1); +insert into t4 values (1); + +select * from t1 join t2 using (a1) join t3 on b=c1 join t4 using (c2); +select * from t3 join (t1 join t2 using (a1)) on b=c1 join t4 using (c2); +select a2 from t1 join t2 using (a1) join t3 on b=c1 join t4 using (c2); +select a2 from t3 join (t1 join t2 using (a1)) on b=c1 join t4 using (c2); +select a2 from ((t1 join t2 using (a1)) join t3 on b=c1) join t4 using (c2); +select a2 from ((t1 natural join t2) join t3 on b=c1) natural join t4; + +drop table t1,t2,t3,t4; + +# +# BUG#15355: Common natural join column not resolved in prepared statement nested query +# +create table t1 (c int, b int); +create table t2 (a int, b int); +create table t3 (b int, c int); +create table t4 (y int, c int); +create table t5 (y int, z int); + +insert into t1 values (3,2); +insert into t2 values (1,2); +insert into t3 values (2,3); +insert into t4 values (1,3); +insert into t5 values (1,4); + +# this fails +prepare stmt1 from "select * from ((t3 natural join (t1 natural join t2)) +natural join t4) natural join t5"; +execute stmt1; + +# this works +select * from ((t3 natural join (t1 natural join t2)) natural join t4) + natural join t5; +drop table t1, t2, t3, t4, t5; + +# End of tests for WL#2486 - natural/using join + +# +# BUG#14940: Make E(#rows) from "range" access be re-used by range optimizer +# +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t2 (a int, b int, filler char(100), key(a), key(b)); +create table t3 (a int, b int, filler char(100), key(a), key(b)); + +insert into t2 + select @a:= A.a + 10*(B.a + 10*C.a), @a, 'filler' from t1 A, t1 B, t1 C; +insert into t3 select * from t2 where a < 800; + +# The order of tables must be t2,t3: +explain select * from t2,t3 where t2.a < 200 and t2.b=t3.b; + +drop table t1, t2, t3; + +# BUG#14940 {Wrong query plan is chosen because of odd results of +# prev_record_reads() function } +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t2 (a int, b int, primary key(a)); +insert into t2 select @v:=A.a+10*B.a, @v from t1 A, t1 B; + +explain select * from t1; +show status like '%cost%'; +select 'The cost of accessing t1 (dont care if it changes' '^'; + +select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z; + +explain select * from t1, t2 A, t2 B where A.a = t1.a and B.a=A.b; +show status like '%cost%'; +select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z; + + + +drop table t1, t2; +# BUG#25106: A USING clause in combination with a VIEW results in column +# aliases ignored +# +CREATE TABLE t1 (ID INTEGER, Name VARCHAR(50)); +CREATE TABLE t2 (Test_ID INTEGER); +CREATE VIEW v1 (Test_ID, Description) AS SELECT ID, Name FROM t1; + +CREATE TABLE tv1 SELECT Description AS Name FROM v1 JOIN t2 + USING (Test_ID); +DESCRIBE tv1; +CREATE TABLE tv2 SELECT Description AS Name FROM v1 JOIN t2 + ON v1.Test_ID = t2.Test_ID; +DESCRIBE tv2; + +DROP VIEW v1; +DROP TABLE t1,t2,tv1,tv2; + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/t/join_crash.test b/mysql-test/suite/pbxt/t/join_crash.test new file mode 100644 index 00000000000..2ec96dc2c28 --- /dev/null +++ b/mysql-test/suite/pbxt/t/join_crash.test @@ -0,0 +1,121 @@ +# +# This test gave a core dump +# + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3,t4; +--enable_warnings + +CREATE TABLE t1 ( + project_id int(11) NOT NULL auto_increment, + project_row_lock int(11) NOT NULL default '0', + project_name varchar(80) NOT NULL default '', + client_ptr int(11) NOT NULL default '0', + project_contact_ptr int(11) default NULL, + client_contact_ptr int(11) default NULL, + billing_contact_ptr int(11) default NULL, + comments mediumtext, + PRIMARY KEY (project_id), + UNIQUE KEY project (client_ptr,project_name) +) ENGINE=MyISAM PACK_KEYS=1; + +INSERT INTO t1 VALUES (1,0,'Rejected Time',1,NULL,NULL,NULL,NULL); +INSERT INTO t1 VALUES (209,0,'MDGRAD Proposal/Investigation',97,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (208,0,'Font 9 Design',84,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (207,0,'Web Based Order Processing',95,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (205,0,'Mac Screen Saver',95,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (206,0,'Web Site',96,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (204,0,'Magnafire Glue',94,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (203,0,'Print Bid',93,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (202,0,'EPOC Port',92,NULL,NULL,NULL,''); +INSERT INTO t1 VALUES (201,0,'TravelMate',88,NULL,NULL,NULL,''); + +CREATE TABLE t2 ( + period_id int(11) NOT NULL auto_increment, + period_type enum('user_table','client_table','role_table','member_table','project_table') default NULL, + period_key int(11) default NULL, + start_date datetime default NULL, + end_date datetime default NULL, + work_load int(11) default NULL, + PRIMARY KEY (period_id), + KEY period_index (period_type,period_key), + KEY date_index (start_date,end_date) +) ENGINE=MyISAM PACK_KEYS=1; + +INSERT INTO t2 VALUES (1,'user_table',98,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (2,'user_table',99,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (3,'user_table',100,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (49,'project_table',148,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (50,'client_table',68,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (51,'project_table',149,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (52,'project_table',150,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (53,'client_table',69,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (54,'project_table',151,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (55,'client_table',70,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (155,'role_table',1,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (156,'role_table',2,'2000-01-01 00:00:00',NULL,NULL); +INSERT INTO t2 VALUES (160,'member_table',1,'2000-01-01 00:00:00',NULL,1); +INSERT INTO t2 VALUES (161,'member_table',2,'2000-01-01 00:00:00',NULL,1); +INSERT INTO t2 VALUES (162,'member_table',3,'2000-01-01 00:00:00',NULL,1); + +CREATE TABLE t3 ( + budget_id int(11) NOT NULL auto_increment, + project_ptr int(11) NOT NULL default '0', + po_number varchar(20) NOT NULL default '', + status enum('open','closed') default NULL, + date_received datetime default NULL, + amount_received float(10,2) default NULL, + adjustment float(10,2) default NULL, + PRIMARY KEY (budget_id), + UNIQUE KEY po (project_ptr,po_number) +) ENGINE=MyISAM PACK_KEYS=1; + +CREATE TABLE t4 ( + client_id int(11) NOT NULL auto_increment, + client_row_lock int(11) NOT NULL default '0', + client_name varchar(80) NOT NULL default '', + contact_ptr int(11) default NULL, + comments mediumtext, + PRIMARY KEY (client_id), + UNIQUE KEY client_name (client_name) +) ENGINE=MyISAM PACK_KEYS=1; + +INSERT INTO t4 VALUES (1,0,'CPS',NULL,NULL); + +# +# The query that fails... +# +select distinct + t1.project_id as project_id, + t1.project_name as project_name, + t1.client_ptr as client_ptr, + t1.comments as comments, + sum( t3.amount_received ) + sum( t3.adjustment ) as total_budget +from + t2 as client_period , + t2 as project_period, + t3 left join t1 on (t3.project_ptr = t1.project_id and + t3.date_received <= '2001-03-22 14:15:09') + left join t4 on t4.client_id = t1.client_ptr + where + 1 + and ( client_period.period_type = 'client_table' + and client_period.period_key = t4.client_id + and ( client_period.start_date <= '2001-03-22 14:15:09' or isnull( client_period.start_date )) + and ( client_period.end_date > '2001-03-21 14:15:09' or isnull( client_period.end_date )) + ) + and ( project_period.period_type = 'project_table' + and project_period.period_key = t1.project_id + and ( project_period.start_date <= '2001-03-22 14:15:09' or isnull( project_period.start_date )) + and ( project_period.end_date > '2001-03-21 14:15:09' or isnull( project_period.end_date )) ) + group by + client_id, + project_id , + client_period.period_id , + project_period.period_id + order by + client_name asc, + project_name asc; +DROP TABLE t1,t2,t3,t4; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/join_nested.test b/mysql-test/suite/pbxt/t/join_nested.test new file mode 100644 index 00000000000..9a678b5c0f6 --- /dev/null +++ b/mysql-test/suite/pbxt/t/join_nested.test @@ -0,0 +1,1056 @@ + +--disable_warnings +DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; +--enable_warnings + +CREATE TABLE t0 (a int, b int, c int); +CREATE TABLE t1 (a int, b int, c int); +CREATE TABLE t2 (a int, b int, c int); +CREATE TABLE t3 (a int, b int, c int); +CREATE TABLE t4 (a int, b int, c int); +CREATE TABLE t5 (a int, b int, c int); +CREATE TABLE t6 (a int, b int, c int); +CREATE TABLE t7 (a int, b int, c int); +CREATE TABLE t8 (a int, b int, c int); +CREATE TABLE t9 (a int, b int, c int); + +INSERT INTO t0 VALUES (1,1,0), (1,2,0), (2,2,0); +INSERT INTO t1 VALUES (1,3,0), (2,2,0), (3,2,0); +INSERT INTO t2 VALUES (3,3,0), (4,2,0), (5,3,0); +INSERT INTO t3 VALUES (1,2,0), (2,2,0); +INSERT INTO t4 VALUES (3,2,0), (4,2,0); +INSERT INTO t5 VALUES (3,1,0), (2,2,0), (3,3,0); +INSERT INTO t6 VALUES (3,2,0), (6,2,0), (6,1,0); +INSERT INTO t7 VALUES (1,1,0), (2,2,0); +INSERT INTO t8 VALUES (0,2,0), (1,2,0); +INSERT INTO t9 VALUES (1,1,0), (1,2,0), (3,3,0); + + +SELECT t2.a,t2.b + FROM t2; + +SELECT t3.a,t3.b + FROM t3; + +SELECT t4.a,t4.b + FROM t4; + +SELECT t3.a,t3.b,t4.a,t4.b + FROM t3,t4; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t2.b=t4.b; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b; + +EXPLAIN EXTENDED +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t2.b=t4.b + WHERE t3.a=1 OR t3.c IS NULL; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t2.b=t4.b + WHERE t3.a=1 OR t3.c IS NULL; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t2.b=t4.b + WHERE t3.a>1 OR t3.c IS NULL; + +SELECT t5.a,t5.b + FROM t5; + +SELECT t3.a,t3.b,t4.a,t4.b,t5.a,t5.b + FROM t3,t4,t5; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b + FROM t2 + LEFT JOIN + (t3, t4, t5) + ON t2.b=t4.b; + +EXPLAIN EXTENDED +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b + FROM t2 + LEFT JOIN + (t3, t4, t5) + ON t2.b=t4.b + WHERE t3.a>1 OR t3.c IS NULL; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b + FROM t2 + LEFT JOIN + (t3, t4, t5) + ON t2.b=t4.b + WHERE t3.a>1 OR t3.c IS NULL; + +EXPLAIN EXTENDED +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b + FROM t2 + LEFT JOIN + (t3, t4, t5) + ON t2.b=t4.b + WHERE (t3.a>1 OR t3.c IS NULL) AND + (t5.a<3 OR t5.c IS NULL); + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b + FROM t2 + LEFT JOIN + (t3, t4, t5) + ON t2.b=t4.b + WHERE (t3.a>1 OR t3.c IS NULL) AND + (t5.a<3 OR t5.c IS NULL); + +SELECT t6.a,t6.b + FROM t6; + +SELECT t7.a,t7.b + FROM t7; + +SELECT t6.a,t6.b,t7.a,t7.b + FROM t6,t7; + +SELECT t8.a,t8.b + FROM t8; + +EXPLAIN EXTENDED +SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10; + +SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10; + +SELECT t5.a,t5.b + FROM t5; + +SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b; + +SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b AND + (t8.a < 1 OR t8.c IS NULL); + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + WHERE t2.a > 3 AND + (t6.a < 6 OR t6.c IS NULL); + +SELECT t1.a,t1.b + FROM t1; + +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2); + +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2) + WHERE (t2.a >= 4 OR t2.c IS NULL); + +SELECT t0.a,t0.b + FROM t0; + +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2) + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL); + +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2) + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL); + +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2), + t9 + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL) AND + (t3.a < 5 OR t3.c IS NULL) AND + (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND + (t5.a >=2 OR t5.c IS NULL) AND + (t6.a >=4 OR t6.c IS NULL) AND + (t7.a <= 2 OR t7.c IS NULL) AND + (t8.a < 1 OR t8.c IS NULL) AND + (t8.b=t9.b OR t8.c IS NULL) AND + (t9.a=1); + +SELECT t9.a,t9.b + FROM t9; + +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2), + t9 + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL) AND + (t3.a < 5 OR t3.c IS NULL) AND + (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND + (t5.a >=2 OR t5.c IS NULL) AND + (t6.a >=4 OR t6.c IS NULL) AND + (t7.a <= 2 OR t7.c IS NULL) AND + (t8.a < 1 OR t8.c IS NULL) AND + (t8.b=t9.b OR t8.c IS NULL) AND + (t9.a=1); + +SELECT t1.a,t1.b + FROM t1; + +SELECT t2.a,t2.b + FROM t2; + +SELECT t3.a,t3.b + FROM t3; + +SELECT t2.a,t2.b,t3.a,t3.b + FROM t2 + LEFT JOIN + t3 + ON t2.b=t3.b; + +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b + FROM t1, t2 + LEFT JOIN + t3 + ON t2.b=t3.b + WHERE t1.a <= 2; + +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b + FROM t1, t3 + RIGHT JOIN + t2 + ON t2.b=t3.b + WHERE t1.a <= 2; + +SELECT t3.a,t3.b,t4.a,t4.b + FROM t3,t4; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b; + +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t1, t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b + WHERE t1.a <= 2; + +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t1, (t3, t4) + RIGHT JOIN + t2 + ON t3.a=1 AND t2.b=t4.b + WHERE t1.a <= 2; + +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t1, (t3, t4) + RIGHT JOIN + t2 + ON t3.a=1 AND t2.b=t4.b + WHERE t1.a <= 2; + +EXPLAIN EXTENDED +SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM t1, (t3, t4) + RIGHT JOIN + t2 + ON t3.a=1 AND t2.b=t4.b + WHERE t1.a <= 2; + +CREATE INDEX idx_b ON t2(b); + +EXPLAIN EXTENDED +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM (t3,t4) + LEFT JOIN + (t1,t2) + ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b; + +SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b + FROM (t3,t4) + LEFT JOIN + (t1,t2) + ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b; + +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2), + t9 + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL) AND + (t3.a < 5 OR t3.c IS NULL) AND + (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND + (t5.a >=2 OR t5.c IS NULL) AND + (t6.a >=4 OR t6.c IS NULL) AND + (t7.a <= 2 OR t7.c IS NULL) AND + (t8.a < 1 OR t8.c IS NULL) AND + (t8.b=t9.b OR t8.c IS NULL) AND + (t9.a=1); + +CREATE INDEX idx_b ON t4(b); +CREATE INDEX idx_b ON t5(b); + +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2), + t9 + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL) AND + (t3.a < 5 OR t3.c IS NULL) AND + (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND + (t5.a >=2 OR t5.c IS NULL) AND + (t6.a >=4 OR t6.c IS NULL) AND + (t7.a <= 2 OR t7.c IS NULL) AND + (t8.a < 1 OR t8.c IS NULL) AND + (t8.b=t9.b OR t8.c IS NULL) AND + (t9.a=1); + +CREATE INDEX idx_b ON t8(b); + +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2), + t9 + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL) AND + (t3.a < 5 OR t3.c IS NULL) AND + (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND + (t5.a >=2 OR t5.c IS NULL) AND + (t6.a >=4 OR t6.c IS NULL) AND + (t7.a <= 2 OR t7.c IS NULL) AND + (t8.a < 1 OR t8.c IS NULL) AND + (t8.b=t9.b OR t8.c IS NULL) AND + (t9.a=1); + +CREATE INDEX idx_b ON t1(b); +CREATE INDEX idx_a ON t0(a); + +EXPLAIN EXTENDED +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2), + t9 + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL) AND + (t3.a < 5 OR t3.c IS NULL) AND + (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND + (t5.a >=2 OR t5.c IS NULL) AND + (t6.a >=4 OR t6.c IS NULL) AND + (t7.a <= 2 OR t7.c IS NULL) AND + (t8.a < 1 OR t8.c IS NULL) AND + (t8.b=t9.b OR t8.c IS NULL) AND + (t9.a=1); + +SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b, + t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b + FROM t0,t1 + LEFT JOIN + ( + t2 + LEFT JOIN + (t3, t4) + ON t3.a=1 AND t2.b=t4.b, + t5 + LEFT JOIN + ( + (t6, t7) + LEFT JOIN + t8 + ON t7.b=t8.b AND t6.b < 10 + ) + ON t6.b >= 2 AND t5.b=t7.b + ) + ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND + (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND + (t1.a != 2), + t9 + WHERE t0.a=1 AND + t0.b=t1.b AND + (t2.a >= 4 OR t2.c IS NULL) AND + (t3.a < 5 OR t3.c IS NULL) AND + (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND + (t5.a >=2 OR t5.c IS NULL) AND + (t6.a >=4 OR t6.c IS NULL) AND + (t7.a <= 2 OR t7.c IS NULL) AND + (t8.a < 1 OR t8.c IS NULL) AND + (t8.b=t9.b OR t8.c IS NULL) AND + (t9.a=1); + +SELECT t2.a,t2.b + FROM t2; + +SELECT t3.a,t3.b + FROM t3; + +SELECT t2.a,t2.b,t3.a,t3.b + FROM t2 LEFT JOIN t3 ON t2.b=t3.b + WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL); + +SELECT t2.a,t2.b,t3.a,t3.b + FROM t2 LEFT JOIN (t3) ON t2.b=t3.b + WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL); + +ALTER TABLE t3 + CHANGE COLUMN a a1 int, + CHANGE COLUMN c c1 int; + +SELECT t2.a,t2.b,t3.a1,t3.b + FROM t2 LEFT JOIN t3 ON t2.b=t3.b + WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); + +SELECT t2.a,t2.b,t3.a1,t3.b + FROM t2 NATURAL LEFT JOIN t3 + WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL); + +DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +CREATE TABLE t3 (a int); + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (2); +INSERT INTO t1 VALUES (2); + +#check proper syntax for nested outer joins + +SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.a=t3.a; + +#must be equivalent to: + +SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a; + +#check that everything is al right when all tables contain not more than 1 row +#(bug #4922) + +DELETE FROM t1 WHERE a=2; +SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a; +DELETE FROM t2; +SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a; + +DROP TABLE t1,t2,t3; + +#on expression for a nested outer join does not depend on the outer table +#bug #4976 + +CREATE TABLE t1(a int, key (a)); +CREATE TABLE t2(b int, key (b)); +CREATE TABLE t3(c int, key (c)); + +INSERT INTO t1 VALUES (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(10), (11), (12), (13), (14), (15), (16), (17), (18), (19); + +INSERT INTO t2 VALUES (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(10), (11), (12), (13), (14), (15), (16), (17), (18), (19); + +INSERT INTO t3 VALUES (0), (1), (2), (3), (4), (5); + +analyze table t2; # PBXT required for stable count +analyze table t3; # PBXT required for stable count + +EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON c < 3 and b = c; +--replace_column 9 # +EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c; +SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c; + +DELETE FROM t3; +--replace_column 9 # +EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c; +SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c; + +DROP TABLE t1,t2,t3; + +# +# Test for bug #11284: empty table in a nested left join +# + +CREATE TABLE t1 (c11 int); +CREATE TABLE t2 (c21 int); +CREATE TABLE t3 (c31 int); + +INSERT INTO t1 VALUES (4), (5); + +SELECT * FROM t1 LEFT JOIN t2 ON c11=c21; +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON c11=c21; + +SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON c21=c31) ON c11=c21; +EXPLAIN SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON c21=c31) ON c11=c21; + +DROP TABLE t1,t2,t3; + +# +# Bug #12154: creation of temp table for a query with nested outer join +# + +CREATE TABLE t1 (goods int(12) NOT NULL, price varchar(128) NOT NULL); +INSERT INTO t1 VALUES (23, 2340), (26, 9900); + +CREATE TABLE t2 (goods int(12), name varchar(50), shop char(2)); +INSERT INTO t2 VALUES (23, 'as300', 'fr'), (26, 'as600', 'fr'); + +create table t3 (groupid int(12) NOT NULL, goodsid int(12) NOT NULL); +INSERT INTO t3 VALUES (3,23), (6,26); + +CREATE TABLE t4 (groupid int(12)); +INSERT INTO t4 VALUES (1), (2), (3), (4), (5), (6); + +SELECT * FROM +(SELECT DISTINCT gl.groupid, gp.price + FROM t4 gl + LEFT JOIN + (t3 g INNER JOIN t2 p ON g.goodsid = p.goods + INNER JOIN t1 gp ON p.goods = gp.goods) + ON gl.groupid = g.groupid and p.shop = 'fr') t; + +CREATE VIEW v1 AS +SELECT g.groupid groupid, p.goods goods, + p.name name, p.shop shop, + gp.price price + FROM t3 g INNER JOIN t2 p ON g.goodsid = p.goods + INNER JOIN t1 gp on p.goods = gp.goods; + +CREATE VIEW v2 AS +SELECT DISTINCT g.groupid, fr.price + FROM t4 g + LEFT JOIN + v1 fr on g.groupid = fr.groupid and fr.shop = 'fr'; + +SELECT * FROM v2; + +SELECT * FROM +(SELECT DISTINCT g.groupid, fr.price + FROM t4 g + LEFT JOIN + v1 fr on g.groupid = fr.groupid and fr.shop = 'fr') t; + +DROP VIEW v1,v2; +DROP TABLE t1,t2,t3,t4; + +# +# Bug #13545: problem with NATURAL/USING joins. +# + +CREATE TABLE t1(a int); +CREATE TABLE t2(b int); +CREATE TABLE t3(c int, d int); +CREATE TABLE t4(d int); +CREATE TABLE t5(e int, f int); +CREATE TABLE t6(f int); +CREATE VIEW v1 AS + SELECT e FROM t5 JOIN t6 ON t5.e=t6.f; +CREATE VIEW v2 AS + SELECT e FROM t5 NATURAL JOIN t6; + +SELECT t1.a FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c JOIN t4 USING(d); +--error 1054 +SELECT t1.x FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c JOIN t4 USING(d); +SELECT t1.a FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c NATURAL JOIN t4; +--error 1054 +SELECT t1.x FROM t1 JOIN t2 ON a=b JOIN t3 ON a=c NATURAL JOIN t4; +SELECT v1.e FROM v1 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +--error 1054 +SELECT v1.x FROM v1 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +SELECT v2.e FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); +--error 1054 +SELECT v2.x FROM v2 JOIN t2 ON e=b JOIN t3 ON e=c JOIN t4 USING(d); + +DROP VIEW v1, v2; +DROP TABLE t1, t2, t3, t4, t5, t6; + +# +# BUG#13126 -test case from bug report +# +create table t1 (id1 int(11) not null); +insert into t1 values (1),(2); + +create table t2 (id2 int(11) not null); +insert into t2 values (1),(2),(3),(4); + +create table t3 (id3 char(16) not null); +insert into t3 values ('100'); + +create table t4 (id2 int(11) not null, id3 char(16)); + +create table t5 (id1 int(11) not null, key (id1)); +insert into t5 values (1),(2),(1); + +create view v1 as + select t4.id3 from t4 join t2 on t4.id2 = t2.id2; + +select t1.id1 from t1 inner join (t3 left join v1 on t3.id3 = v1.id3); + +drop view v1; +drop table t1, t2, t3, t4, t5; + +create table t0 (a int); +insert into t0 values (0),(1),(2),(3); +create table t1(a int); +insert into t1 select A.a + 10*(B.a) from t0 A, t0 B; + +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2), (3,3); + +create table t3(a int, b int, filler char(200), key(a)); +insert into t3 select a,a,'filler' from t1; +insert into t3 select a,a,'filler' from t1; + +create table t4 like t3; +insert into t4 select * from t3; +insert into t4 select * from t3; + +create table t5 like t4; +insert into t5 select * from t4; +insert into t5 select * from t4; + +create table t6 like t5; +insert into t6 select * from t5; +insert into t6 select * from t5; + +create table t7 like t6; +insert into t7 select * from t6; +insert into t7 select * from t6; + +--replace_column 9 X +explain select * from t4 join + t2 left join (t3 join t5 on t5.a=t3.b) on t3.a=t2.b where t4.a<=>t3.b; + +--replace_column 9 X +explain select * from (t4 join t6 on t6.a=t4.b) right join t3 on t4.a=t3.b + join t2 left join (t5 join t7 on t7.a=t5.b) on t5.a=t2.b where t3.a<=>t2.b; + +--replace_column 9 X +explain select * from t2 left join + (t3 left join (t4 join t6 on t6.a=t4.b) on t4.a=t3.b + join t5 on t5.a=t3.b) on t3.a=t2.b; + +drop table t0, t1, t2, t3, t4, t5, t6, t7; + +# BUG#16393 +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, filler char(100), key(a)); +insert into t2 select A.a + 10*B.a, '' from t1 A, t1 B; +create table t3 like t2; +insert into t3 select * from t2; + +explain select * from t1 left join + (t2 left join t3 on (t2.a = t3.a)) + on (t1.a = t2.a); +drop table t1, t2, t3; + +# +# Bug #16260: single row table in the inner nest of an outer join +# + +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, type varchar(10)); +CREATE TABLE t2 (pid int NOT NULL PRIMARY KEY, type varchar(10)); +CREATE TABLE t3 (cid int NOT NULL PRIMARY KEY, + id int NOT NULL, + pid int NOT NULL); + +INSERT INTO t1 VALUES (1, 'A'), (3, 'C'); +INSERT INTO t2 VALUES (1, 'A'), (3, 'C'); +INSERT INTO t3 VALUES (1, 1, 1), (3, 3, 3); + +SELECT * FROM t1 p LEFT JOIN (t3 JOIN t1) + ON (t1.id=t3.id AND t1.type='B' AND p.id=t3.id) + LEFT JOIN t2 ON (t3.pid=t2.pid) + WHERE p.id=1; + +CREATE VIEW v1 AS + SELECT t3.* FROM t3 JOIN t1 ON t1.id=t3.id AND t1.type='B'; + +SELECT * FROM t1 p LEFT JOIN v1 ON p.id=v1.id + LEFT JOIN t2 ON v1.pid=t2.pid + WHERE p.id=1; + +DROP VIEW v1; +DROP TABLE t1,t2,t3; + + +# +# Test for bug #18279: crash when on conditions are moved out of a nested join +# to the on conditions for the nest + +CREATE TABLE t1 (id1 int PRIMARY KEY, id2 int); +CREATE TABLE t2 (id1 int PRIMARY KEY, id2 int); +CREATE TABLE t3 (id1 int PRIMARY KEY, id2 int); +CREATE TABLE t4 (id1 int PRIMARY KEY, id2 int); +CREATE TABLE t5 (id1 int PRIMARY KEY, id2 int); + +SELECT t1.id1 AS id, t5.id1 AS ngroupbynsa + FROM t1 INNER JOIN t2 ON t2.id2 = t1.id1 + LEFT OUTER JOIN + (t3 INNER JOIN t4 ON t4.id1 = t3.id2 INNER JOIN t5 ON t4.id2 = t5.id1) + ON t3.id2 IS NOT NULL + WHERE t1.id1=2; + +PREPARE stmt FROM +"SELECT t1.id1 AS id, t5.id1 AS ngroupbynsa + FROM t1 INNER JOIN t2 ON t2.id2 = t1.id1 + LEFT OUTER JOIN + (t3 INNER JOIN t4 ON t4.id1 = t3.id2 INNER JOIN t5 ON t4.id2 = t5.id1) + ON t3.id2 IS NOT NULL + WHERE t1.id1=2"; + +EXECUTE stmt; +EXECUTE stmt; +EXECUTE stmt; +EXECUTE stmt; + +INSERT INTO t1 VALUES (1,1), (2,1), (3,2); +INSERT INTO t2 VALUES (2,1), (3,2), (4,3); +INSERT INTO t3 VALUES (1,1), (3,2), (2,NULL); +INSERT INTO t4 VALUES (1,1), (2,1), (3,3); +INSERT INTO t5 VALUES (1,1), (2,2), (3,3), (4,3); + +EXECUTE stmt; +EXECUTE stmt; +EXECUTE stmt; +EXECUTE stmt; + +SELECT t1.id1 AS id, t5.id1 AS ngroupbynsa + FROM t1 INNER JOIN t2 ON t2.id2 = t1.id1 + LEFT OUTER JOIN + (t3 INNER JOIN t4 ON t4.id1 = t3.id2 INNER JOIN t5 ON t4.id2 = t5.id1) + ON t3.id2 IS NOT NULL + WHERE t1.id1=2; + +DROP TABLE t1,t2,t3,t4,t5; + +# +# Test for bug #24345: crash with nested left outer join when outer table is substituted +# for a row that happens to have a null value for the join attribute. +# + +CREATE TABLE t1 ( + id int NOT NULL PRIMARY KEY, + ct int DEFAULT NULL, + pc int DEFAULT NULL, + INDEX idx_ct (ct), + INDEX idx_pc (pc) +); +INSERT INTO t1 VALUES + (1,NULL,NULL),(2,NULL,NULL),(3,NULL,NULL),(4,NULL,NULL),(5,NULL,NULL); + +CREATE TABLE t2 ( + id int NOT NULL PRIMARY KEY, + sr int NOT NULL, + nm varchar(255) NOT NULL, + INDEX idx_sr (sr) +); +INSERT INTO t2 VALUES + (2441905,4308,'LesAbymes'),(2441906,4308,'Anse-Bertrand'); + +CREATE TABLE t3 ( + id int NOT NULL PRIMARY KEY, + ct int NOT NULL, + ln int NOT NULL, + INDEX idx_ct (ct), + INDEX idx_ln (ln) +); + +CREATE TABLE t4 ( + id int NOT NULL PRIMARY KEY, + nm varchar(255) NOT NULL +); + +INSERT INTO t4 VALUES (4308,'Guadeloupe'),(4309,'Martinique'); + +SELECT t1.* + FROM t1 LEFT JOIN + (t2 LEFT JOIN t3 ON t3.ct=t2.id AND t3.ln='5') ON t1.ct=t2.id + WHERE t1.id='5'; + +SELECT t1.*, t4.nm + FROM t1 LEFT JOIN + (t2 LEFT JOIN t3 ON t3.ct=t2.id AND t3.ln='5') ON t1.ct=t2.id + LEFT JOIN t4 ON t2.sr=t4.id + WHERE t1.id='5'; + +DROP TABLE t1,t2,t3,t4; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/join_outer.test b/mysql-test/suite/pbxt/t/join_outer.test new file mode 100644 index 00000000000..a9635de7081 --- /dev/null +++ b/mysql-test/suite/pbxt/t/join_outer.test @@ -0,0 +1,814 @@ +# +# test of left outer join +# + +--disable_warnings +drop table if exists t0,t1,t2,t3,t4,t5; +--enable_warnings + +CREATE TABLE t1 ( + grp int(11) default NULL, + a bigint(20) unsigned default NULL, + c char(10) NOT NULL default '' +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,1,'a'),(2,2,'b'),(2,3,'c'),(3,4,'E'),(3,5,'C'),(3,6,'D'),(NULL,NULL,''); +create table t2 (id int, a bigint unsigned not null, c char(10), d int, primary key (a)); +insert into t2 values (1,1,"a",1),(3,4,"A",4),(3,5,"B",5),(3,6,"C",6),(4,7,"D",7); + +select t1.*,t2.* from t1 JOIN t2 where t1.a=t2.a; +select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) order by t1.grp,t1.a,t2.c; +select t1.*,t2.* from { oj t2 left outer join t1 on (t1.a=t2.a) }; +select t1.*,t2.* from t1 as t0,{ oj t2 left outer join t1 on (t1.a=t2.a) } WHERE t0.a=2; +select t1.*,t2.* from t1 left join t2 using (a); +select t1.*,t2.* from t1 left join t2 using (a) where t1.a=t2.a; +select t1.*,t2.* from t1 left join t2 using (a,c); +select t1.*,t2.* from t1 left join t2 using (c); +select t1.*,t2.* from t1 natural left outer join t2; + +select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id=3; +select t1.*,t2.* from t1 left join t2 on (t1.a=t2.a) where t2.id is null; + +explain select t1.*,t2.* from t1,t2 where t1.a=t2.a and isnull(t2.a)=1; +explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1; + +select t1.*,t2.*,t3.a from t1 left join t2 on (t1.a=t2.a) left join t1 as t3 on (t2.a=t3.a); + +# The next query should rearange the left joins to get this to work +--error 1054 +explain select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); +--error 1054 +select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); + +# The next query should give an error in MySQL +--error 1054 +select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a); + +# Test of inner join +select t1.*,t2.* from t1 inner join t2 using (a); +select t1.*,t2.* from t1 inner join t2 on (t1.a=t2.a); +select t1.*,t2.* from t1 natural join t2; + +drop table t1,t2; + +# +# Test of left join bug +# + +CREATE TABLE t1 ( + usr_id INT unsigned NOT NULL, + uniq_id INT unsigned NOT NULL AUTO_INCREMENT, + start_num INT unsigned NOT NULL DEFAULT 1, + increment INT unsigned NOT NULL DEFAULT 1, + PRIMARY KEY (uniq_id), + INDEX usr_uniq_idx (usr_id, uniq_id), + INDEX uniq_usr_idx (uniq_id, usr_id) +); +CREATE TABLE t2 ( + id INT unsigned NOT NULL DEFAULT 0, + usr2_id INT unsigned NOT NULL DEFAULT 0, + max INT unsigned NOT NULL DEFAULT 0, + c_amount INT unsigned NOT NULL DEFAULT 0, + d_max INT unsigned NOT NULL DEFAULT 0, + d_num INT unsigned NOT NULL DEFAULT 0, + orig_time INT unsigned NOT NULL DEFAULT 0, + c_time INT unsigned NOT NULL DEFAULT 0, + active ENUM ("no","yes") NOT NULL, + PRIMARY KEY (id,usr2_id), + INDEX id_idx (id), + INDEX usr2_idx (usr2_id) +); +INSERT INTO t1 VALUES (3,NULL,0,50),(3,NULL,0,200),(3,NULL,0,25),(3,NULL,0,84676),(3,NULL,0,235),(3,NULL,0,10),(3,NULL,0,3098),(3,NULL,0,2947),(3,NULL,0,8987),(3,NULL,0,8347654),(3,NULL,0,20398),(3,NULL,0,8976),(3,NULL,0,500),(3,NULL,0,198); + +#1st select shows that one record is returned with null entries for the right +#table, when selecting on an id that does not exist in the right table t2 +SELECT t1.usr_id,t1.uniq_id,t1.increment, +t2.usr2_id,t2.c_amount,t2.max +FROM t1 +LEFT JOIN t2 ON t2.id = t1.uniq_id +WHERE t1.uniq_id = 4 +ORDER BY t2.c_amount; + +# The same with RIGHT JOIN +SELECT t1.usr_id,t1.uniq_id,t1.increment, +t2.usr2_id,t2.c_amount,t2.max +FROM t2 +RIGHT JOIN t1 ON t2.id = t1.uniq_id +WHERE t1.uniq_id = 4 +ORDER BY t2.c_amount; + +INSERT INTO t2 VALUES (2,3,3000,6000,0,0,746584,837484,'yes'); +--error ER_DUP_ENTRY +INSERT INTO t2 VALUES (2,3,3000,6000,0,0,746584,837484,'yes'); +INSERT INTO t2 VALUES (7,3,1000,2000,0,0,746294,937484,'yes'); + +#3rd select should show that one record is returned with null entries for the +# right table, when selecting on an id that does not exist in the right table +# t2 but this select returns an empty set!!!! +SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4 ORDER BY t2.c_amount; +SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4 GROUP BY t2.c_amount; +# Removing the ORDER BY works: +SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4; + +drop table t1,t2; + +# +# Test of LEFT JOIN with const tables (failed for frankie@etsetb.upc.es) +# + +CREATE TABLE t1 ( + cod_asig int(11) DEFAULT '0' NOT NULL, + desc_larga_cat varchar(80) DEFAULT '' NOT NULL, + desc_larga_cas varchar(80) DEFAULT '' NOT NULL, + desc_corta_cat varchar(40) DEFAULT '' NOT NULL, + desc_corta_cas varchar(40) DEFAULT '' NOT NULL, + cred_total double(3,1) DEFAULT '0.0' NOT NULL, + pre_requisit int(11), + co_requisit int(11), + preco_requisit int(11), + PRIMARY KEY (cod_asig) +); + +INSERT INTO t1 VALUES (10360,'asdfggfg','Introduccion a los Ordenadores I','asdfggfg','Introduccio Ordinadors I',6.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (10361,'Components i Circuits Electronics I','Componentes y Circuitos Electronicos I','Components i Circuits Electronics I','Comp. i Circ. Electr. I',6.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (10362,'Laboratori d`Ordinadors','Laboratorio de Ordenadores','Laboratori d`Ordinadors','Laboratori Ordinadors',4.5,NULL,NULL,NULL); +INSERT INTO t1 VALUES (10363,'Tecniques de Comunicacio Oral i Escrita','Tecnicas de Comunicacion Oral y Escrita','Tecniques de Comunicacio Oral i Escrita','Tec. Com. Oral i Escrita',4.5,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11403,'Projecte Fi de Carrera','Proyecto Fin de Carrera','Projecte Fi de Carrera','PFC',9.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11404,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',15.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11405,'+lgebra lineal','Algebra lineal','+lgebra lineal','+lgebra lineal',18.0,NULL,NULL,NULL); +INSERT INTO t1 VALUES (11406,'Calcul Infinitesimal','Cßlculo Infinitesimal','Calcul Infinitesimal','Calcul Infinitesimal',15.0,NULL,NULL,NULL); + +CREATE TABLE t2 ( + idAssignatura int(11) DEFAULT '0' NOT NULL, + Grup int(11) DEFAULT '0' NOT NULL, + Places smallint(6) DEFAULT '0' NOT NULL, + PlacesOcupades int(11) DEFAULT '0', + PRIMARY KEY (idAssignatura,Grup) +); + + +INSERT INTO t2 VALUES (10360,12,333,0); +INSERT INTO t2 VALUES (10361,30,2,0); +INSERT INTO t2 VALUES (10361,40,3,0); +INSERT INTO t2 VALUES (10360,45,10,0); +INSERT INTO t2 VALUES (10362,10,12,0); +INSERT INTO t2 VALUES (10360,55,2,0); +INSERT INTO t2 VALUES (10360,70,0,0); +INSERT INTO t2 VALUES (10360,565656,0,0); +INSERT INTO t2 VALUES (10360,32767,7,0); +INSERT INTO t2 VALUES (10360,33,8,0); +INSERT INTO t2 VALUES (10360,7887,85,0); +INSERT INTO t2 VALUES (11405,88,8,0); +INSERT INTO t2 VALUES (10360,0,55,0); +INSERT INTO t2 VALUES (10360,99,0,0); +INSERT INTO t2 VALUES (11411,30,10,0); +INSERT INTO t2 VALUES (11404,0,0,0); +INSERT INTO t2 VALUES (10362,11,111,0); +INSERT INTO t2 VALUES (10363,33,333,0); +INSERT INTO t2 VALUES (11412,55,0,0); +INSERT INTO t2 VALUES (50003,66,6,0); +INSERT INTO t2 VALUES (11403,5,0,0); +INSERT INTO t2 VALUES (11406,11,11,0); +INSERT INTO t2 VALUES (11410,11410,131,0); +INSERT INTO t2 VALUES (11416,11416,32767,0); +INSERT INTO t2 VALUES (11409,0,0,0); + +CREATE TABLE t3 ( + id int(11) NOT NULL auto_increment, + dni_pasaporte char(16) DEFAULT '' NOT NULL, + idPla int(11) DEFAULT '0' NOT NULL, + cod_asig int(11) DEFAULT '0' NOT NULL, + any smallint(6) DEFAULT '0' NOT NULL, + quatrimestre smallint(6) DEFAULT '0' NOT NULL, + estat char(1) DEFAULT 'M' NOT NULL, + PRIMARY KEY (id), + UNIQUE dni_pasaporte (dni_pasaporte,idPla), + UNIQUE dni_pasaporte_2 (dni_pasaporte,idPla,cod_asig,any,quatrimestre) +); + +INSERT INTO t3 VALUES (1,'11111111',1,10362,98,1,'M'); + +CREATE TABLE t4 ( + id int(11) NOT NULL auto_increment, + papa int(11) DEFAULT '0' NOT NULL, + fill int(11) DEFAULT '0' NOT NULL, + idPla int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (id), + KEY papa (idPla,papa), + UNIQUE papa_2 (idPla,papa,fill) +); + +INSERT INTO t4 VALUES (1,-1,10360,1); +INSERT INTO t4 VALUES (2,-1,10361,1); +INSERT INTO t4 VALUES (3,-1,10362,1); + +SELECT DISTINCT fill,desc_larga_cat,cred_total,Grup,Places,PlacesOcupades FROM t4 LEFT JOIN t3 ON t3.cod_asig=fill AND estat='S' AND dni_pasaporte='11111111' AND t3.idPla=1 , t2,t1 WHERE fill=t1.cod_asig AND Places>PlacesOcupades AND fill=idAssignatura AND t4.idPla=1 AND papa=-1; + +SELECT DISTINCT fill,t3.idPla FROM t4 LEFT JOIN t3 ON t3.cod_asig=t4.fill AND t3.estat='S' AND t3.dni_pasaporte='1234' AND t3.idPla=1 ; + +INSERT INTO t3 VALUES (3,'1234',1,10360,98,1,'S'); +SELECT DISTINCT fill,t3.idPla FROM t4 LEFT JOIN t3 ON t3.cod_asig=t4.fill AND t3.estat='S' AND t3.dni_pasaporte='1234' AND t3.idPla=1 ; + +drop table t1,t2,t3,test.t4; + +# +# Test of IS NULL on AUTO_INCREMENT with LEFT JOIN +# + +CREATE TABLE t1 ( + id smallint(5) unsigned NOT NULL auto_increment, + name char(60) DEFAULT '' NOT NULL, + PRIMARY KEY (id) +); +INSERT INTO t1 VALUES (1,'Antonio Paz'); +INSERT INTO t1 VALUES (2,'Lilliana Angelovska'); +INSERT INTO t1 VALUES (3,'Thimble Smith'); + +CREATE TABLE t2 ( + id smallint(5) unsigned NOT NULL auto_increment, + owner smallint(5) unsigned DEFAULT '0' NOT NULL, + name char(60), + PRIMARY KEY (id) +); +INSERT INTO t2 VALUES (1,1,'El Gato'); +INSERT INTO t2 VALUES (2,1,'Perrito'); +INSERT INTO t2 VALUES (3,3,'Happy'); + +select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner); +select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.id is null; +explain select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.id is null; +explain select t1.name, t2.name, t2.id from t1 left join t2 on (t1.id = t2.owner) where t2.name is null; +select count(*) from t1 left join t2 on (t1.id = t2.owner); + +select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner); +select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.id is null; +explain select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.id is null; +explain select t1.name, t2.name, t2.id from t2 right join t1 on (t1.id = t2.owner) where t2.name is null; +select count(*) from t2 right join t1 on (t1.id = t2.owner); + +select t1.name, t2.name, t2.id,t3.id from t2 right join t1 on (t1.id = t2.owner) left join t1 as t3 on t3.id=t2.owner; +select t1.name, t2.name, t2.id,t3.id from t1 right join t2 on (t1.id = t2.owner) right join t1 as t3 on t3.id=t2.owner; +select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id = t2.owner) right join t1 as t3 on t3.id=t2.owner; + +drop table t1,t2; + +create table t1 (id int not null, str char(10), index(str)); +insert into t1 values (1, null), (2, null), (3, "foo"), (4, "bar"); +select * from t1 where str is not null order by id; +select * from t1 where str is null; +drop table t1; + +# +# Test wrong LEFT JOIN query +# + +CREATE TABLE t1 ( + t1_id bigint(21) NOT NULL auto_increment, + PRIMARY KEY (t1_id) +); +CREATE TABLE t2 ( + t2_id bigint(21) NOT NULL auto_increment, + PRIMARY KEY (t2_id) +); +CREATE TABLE t3 ( + t3_id bigint(21) NOT NULL auto_increment, + PRIMARY KEY (t3_id) +); +CREATE TABLE t4 ( + seq_0_id bigint(21) DEFAULT '0' NOT NULL, + seq_1_id bigint(21) DEFAULT '0' NOT NULL, + KEY seq_0_id (seq_0_id), + KEY seq_1_id (seq_1_id) +); +CREATE TABLE t5 ( + seq_0_id bigint(21) DEFAULT '0' NOT NULL, + seq_1_id bigint(21) DEFAULT '0' NOT NULL, + KEY seq_1_id (seq_1_id), + KEY seq_0_id (seq_0_id) +); + +insert into t1 values (1); +insert into t2 values (1); +insert into t3 values (1); +insert into t4 values (1,1); +insert into t5 values (1,1); + +--error 1054 +explain select * from t3 left join t4 on t4.seq_1_id = t2.t2_id left join t1 on t1.t1_id = t4.seq_0_id left join t5 on t5.seq_0_id = t1.t1_id left join t2 on t2.t2_id = t5.seq_1_id where t3.t3_id = 23; + +drop table t1,t2,t3,t4,t5; + +# +# Another LEFT JOIN problem +# (The problem was that the result changed when we added ORDER BY) +# + +create table t1 (n int, m int, o int, key(n)); +create table t2 (n int not null, m int, o int, primary key(n)); +insert into t1 values (1, 2, 11), (1, 2, 7), (2, 2, 8), (1,2,9),(1,3,9); +insert into t2 values (1, 2, 3),(2, 2, 8), (4,3,9),(3,2,10); +select t1.*, t2.* from t1 left join t2 on t1.n = t2.n and +t1.m = t2.m where t1.n = 1; +select t1.*, t2.* from t1 left join t2 on t1.n = t2.n and +t1.m = t2.m where t1.n = 1 order by t1.o; +drop table t1,t2; + +# Test bug with NATURAL join: + +CREATE TABLE t1 (id1 INT NOT NULL PRIMARY KEY, dat1 CHAR(1), id2 INT); +INSERT INTO t1 VALUES (1,'a',1); +INSERT INTO t1 VALUES (2,'b',1); +INSERT INTO t1 VALUES (3,'c',2); + +CREATE TABLE t2 (id2 INT NOT NULL PRIMARY KEY, dat2 CHAR(1)); +INSERT INTO t2 VALUES (1,'x'); +INSERT INTO t2 VALUES (2,'y'); +INSERT INTO t2 VALUES (3,'z'); + +SELECT t2.id2 FROM t2 LEFT OUTER JOIN t1 ON t1.id2 = t2.id2 WHERE id1 IS NULL; +SELECT t2.id2 FROM t2 NATURAL LEFT OUTER JOIN t1 WHERE id1 IS NULL; + +drop table t1,t2; + +create table t1 ( color varchar(20), name varchar(20) ); +insert into t1 values ( 'red', 'apple' ); +insert into t1 values ( 'yellow', 'banana' ); +insert into t1 values ( 'green', 'lime' ); +insert into t1 values ( 'black', 'grape' ); +insert into t1 values ( 'blue', 'blueberry' ); +create table t2 ( count int, color varchar(20) ); +insert into t2 values (10, 'green'); +insert into t2 values (5, 'black'); +insert into t2 values (15, 'white'); +insert into t2 values (7, 'green'); +select * from t1; +select * from t2; +select * from t2 natural join t1; +select t2.count, t1.name from t2 natural join t1; +select t2.count, t1.name from t2 inner join t1 using (color); +drop table t1; +drop table t2; + +# +# Test of LEFT JOIN + GROUP FUNCTIONS within functions: +# + +CREATE TABLE t1 ( + pcode varchar(8) DEFAULT '' NOT NULL +); +INSERT INTO t1 VALUES ('kvw2000'),('kvw2001'),('kvw3000'),('kvw3001'),('kvw3002'),('kvw3500'),('kvw3501'),('kvw3502'),('kvw3800'),('kvw3801'),('kvw3802'),('kvw3900'),('kvw3901'),('kvw3902'),('kvw4000'),('kvw4001'),('kvw4002'),('kvw4200'),('kvw4500'),('kvw5000'),('kvw5001'),('kvw5500'),('kvw5510'),('kvw5600'),('kvw5601'),('kvw6000'),('klw1000'),('klw1020'),('klw1500'),('klw2000'),('klw2001'),('klw2002'),('kld2000'),('klw2500'),('kmw1000'),('kmw1500'),('kmw2000'),('kmw2001'),('kmw2100'),('kmw3000'),('kmw3200'); +CREATE TABLE t2 ( + pcode varchar(8) DEFAULT '' NOT NULL, + KEY pcode (pcode) +); +INSERT INTO t2 VALUES ('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw2000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3000'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw3500'),('kvw6000'),('kvw6000'),('kld2000'); + +SELECT t1.pcode, IF(ISNULL(t2.pcode), 0, COUNT(*)) AS count FROM t1 +LEFT JOIN t2 ON t1.pcode = t2.pcode GROUP BY t1.pcode; +SELECT SQL_BIG_RESULT t1.pcode, IF(ISNULL(t2.pcode), 0, COUNT(*)) AS count FROM t1 LEFT JOIN t2 ON t1.pcode = t2.pcode GROUP BY t1.pcode; +drop table t1,t2; + +# +# Another left join problem +# + +CREATE TABLE t1 ( + id int(11), + pid int(11), + rep_del tinyint(4), + KEY id (id), + KEY pid (pid) +); +INSERT INTO t1 VALUES (1,NULL,NULL); +INSERT INTO t1 VALUES (2,1,NULL); +select * from t1 LEFT JOIN t1 t2 ON (t1.id=t2.pid) AND t2.rep_del IS NULL; +create index rep_del ON t1(rep_del); +select * from t1 LEFT JOIN t1 t2 ON (t1.id=t2.pid) AND t2.rep_del IS NULL; +drop table t1; + +CREATE TABLE t1 ( + id int(11) DEFAULT '0' NOT NULL, + name tinytext DEFAULT '' NOT NULL, + UNIQUE id (id) +); +INSERT INTO t1 VALUES (1,'yes'),(2,'no'); +CREATE TABLE t2 ( + id int(11) DEFAULT '0' NOT NULL, + idx int(11) DEFAULT '0' NOT NULL, + UNIQUE id (id,idx) +); +INSERT INTO t2 VALUES (1,1); +explain SELECT * from t1 left join t2 on t1.id=t2.id where t2.id IS NULL; +SELECT * from t1 left join t2 on t1.id=t2.id where t2.id IS NULL; +drop table t1,t2; + +# +# Test problem with using key_column= constant in ON and WHERE +# +create table t1 (bug_id mediumint, reporter mediumint); +create table t2 (bug_id mediumint, who mediumint, index(who)); +insert into t2 values (1,1),(1,2); +insert into t1 values (1,1),(2,1); +SELECT * FROM t1 LEFT JOIN t2 ON (t1.bug_id = t2.bug_id AND t2.who = 2) WHERE (t1.reporter = 2 OR t2.who = 2); +drop table t1,t2; + +# +# Test problem with LEFT JOIN + +create table t1 (fooID smallint unsigned auto_increment, primary key (fooID)); +create table t2 (fooID smallint unsigned not null, barID smallint unsigned not null, primary key (fooID,barID)); +insert into t1 (fooID) values (10),(20),(30); +insert into t2 values (10,1),(20,2),(30,3); +explain select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30; +select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30; +select * from t2 left join t1 ignore index(primary) on t1.fooID = t2.fooID and t1.fooID = 30; +drop table t1,t2; + +create table t1 (i int); +create table t2 (i int); +create table t3 (i int); +insert into t1 values(1),(2); +insert into t2 values(2),(3); +insert into t3 values(2),(4); +select * from t1 natural left join t2 natural left join t3; +select * from t1 natural left join t2 where (t2.i is not null)=0; +select * from t1 natural left join t2 where (t2.i is not null) is not null; +select * from t1 natural left join t2 where (i is not null)=0; +select * from t1 natural left join t2 where (i is not null) is not null; +drop table t1,t2,t3; + +# +# Test of USING +# +create table t1 (f1 integer,f2 integer,f3 integer); +create table t2 (f2 integer,f4 integer); +create table t3 (f3 integer,f5 integer); +select * from t1 + left outer join t2 using (f2) + left outer join t3 using (f3); +drop table t1,t2,t3; + +create table t1 (a1 int, a2 int); +create table t2 (b1 int not null, b2 int); +create table t3 (c1 int, c2 int); + +insert into t1 values (1,2), (2,2), (3,2); +insert into t2 values (1,3), (2,3); +insert into t3 values (2,4), (3,4); + +select * from t1 left join t2 on b1 = a1 left join t3 on c1 = a1 and b1 is null; +explain select * from t1 left join t2 on b1 = a1 left join t3 on c1 = a1 and b1 is null; + +drop table t1, t2, t3; + +# Test for BUG#8711 '<=>' was considered to be a NULL-rejecting predicate. +create table t1 ( + a int(11), + b char(10), + key (a) +); +insert into t1 (a) values (1),(2),(3),(4); +create table t2 (a int); + +select * from t1 left join t2 on t1.a=t2.a where not (t2.a <=> t1.a); +select * from t1 left join t2 on t1.a=t2.a having not (t2.a <=> t1.a); +drop table t1,t2; + +# Test for BUG#5088 + +create table t1 ( + match_id tinyint(3) unsigned not null auto_increment, + home tinyint(3) unsigned default '0', + unique key match_id (match_id), + key match_id_2 (match_id) +); + +insert into t1 values("1", "2"); + +create table t2 ( + player_id tinyint(3) unsigned default '0', + match_1_h tinyint(3) unsigned default '0', + key player_id (player_id) +); + +insert into t2 values("1", "5"); +insert into t2 values("2", "9"); +insert into t2 values("3", "3"); +insert into t2 values("4", "7"); +insert into t2 values("5", "6"); +insert into t2 values("6", "8"); +insert into t2 values("7", "4"); +insert into t2 values("8", "12"); +insert into t2 values("9", "11"); +insert into t2 values("10", "10"); + +explain select s.*, '*', m.*, (s.match_1_h - m.home) UUX from + (t2 s left join t1 m on m.match_id = 1) + order by m.match_id desc; + +explain select s.*, '*', m.*, (s.match_1_h - m.home) UUX from + (t2 s left join t1 m on m.match_id = 1) + order by UUX desc; + +select s.*, '*', m.*, (s.match_1_h - m.home) UUX from + (t2 s left join t1 m on m.match_id = 1) + order by UUX desc; + +explain select s.*, '*', m.*, (s.match_1_h - m.home) UUX from + t2 s straight_join t1 m where m.match_id = 1 + order by UUX desc; + +select s.*, '*', m.*, (s.match_1_h - m.home) UUX from + t2 s straight_join t1 m where m.match_id = 1 + order by UUX desc; + +drop table t1, t2; + +# Tests for bugs #6307 and 6460 + +create table t1 (a int, b int, unique index idx (a, b)); +create table t2 (a int, b int, c int, unique index idx (a, b)); + +insert into t1 values (1, 10), (1,11), (2,10), (2,11); +insert into t2 values (1,10,3); + +select t1.a, t1.b, t2.c from t1 left join t2 + on t1.a=t2.a and t1.b=t2.b and t2.c=3 + where t1.a=1 and t2.c is null; + +drop table t1, t2; + +CREATE TABLE t1 ( + ts_id bigint(20) default NULL, + inst_id tinyint(4) default NULL, + flag_name varchar(64) default NULL, + flag_value text, + UNIQUE KEY ts_id (ts_id,inst_id,flag_name) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE t2 ( + ts_id bigint(20) default NULL, + inst_id tinyint(4) default NULL, + flag_name varchar(64) default NULL, + flag_value text, + UNIQUE KEY ts_id (ts_id,inst_id,flag_name) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +INSERT INTO t1 VALUES + (111056548820001, 0, 'flag1', NULL), + (111056548820001, 0, 'flag2', NULL), + (2, 0, 'other_flag', NULL); + +INSERT INTO t2 VALUES + (111056548820001, 3, 'flag1', 'sss'); + +SELECT t1.flag_name,t2.flag_value + FROM t1 LEFT JOIN t2 + ON (t1.ts_id = t2.ts_id AND t1.flag_name = t2.flag_name AND + t2.inst_id = 3) + WHERE t1.inst_id = 0 AND t1.ts_id=111056548820001 AND + t2.flag_value IS NULL; + +DROP TABLE t1,t2; + +CREATE TABLE t1 ( + id int(11) unsigned NOT NULL auto_increment, + text_id int(10) unsigned default NULL, + PRIMARY KEY (id) +); + +INSERT INTO t1 VALUES("1", "0"); +INSERT INTO t1 VALUES("2", "10"); + +CREATE TABLE t2 ( + text_id char(3) NOT NULL default '', + language_id char(3) NOT NULL default '', + text_data text, + PRIMARY KEY (text_id,language_id) +); + +INSERT INTO t2 VALUES("0", "EN", "0-EN"); +INSERT INTO t2 VALUES("0", "SV", "0-SV"); +INSERT INTO t2 VALUES("10", "EN", "10-EN"); +INSERT INTO t2 VALUES("10", "SV", "10-SV"); +SELECT t1.id, t1.text_id, t2.text_data + FROM t1 LEFT JOIN t2 + ON t1.text_id = t2.text_id + AND t2.language_id = 'SV' + WHERE (t1.id LIKE '%' OR t2.text_data LIKE '%'); + +DROP TABLE t1, t2; + +# Test for bug #5896 + +CREATE TABLE t0 (a0 int PRIMARY KEY); +CREATE TABLE t1 (a1 int PRIMARY KEY); +CREATE TABLE t2 (a2 int); +CREATE TABLE t3 (a3 int); +INSERT INTO t0 VALUES (1); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); + +SELECT * FROM t1 LEFT JOIN t2 ON a1=0; +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON a1=0; +SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0; +EXPLAIN SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0; +SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1; +EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1; + +INSERT INTO t0 VALUES (0); +INSERT INTO t1 VALUES (0); +SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1; +EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1; + +# Test for BUG#4480 +drop table t1,t2; +create table t1 (a int, b int); +insert into t1 values (1,1),(2,2),(3,3); +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2); + +select * from t2 right join t1 on t2.a=t1.a; +select straight_join * from t2 right join t1 on t2.a=t1.a; + +DROP TABLE t0,t1,t2,t3; + +# +# Test for bug #9017: left join mistakingly converted to inner join +# + +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); + +INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (4,2); +INSERT INTO t2 VALUES (1,2), (2,2); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE t1.b=1; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a + WHERE t1.b=1 XOR (NOT ISNULL(t2.a) AND t2.b=1); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE not(0+(t1.a=30 and t2.b=1)); + +DROP TABLE t1,t2; + +# Bug #8681: Bad warning message when group_concat() exceeds max length +set group_concat_max_len=5; +create table t1 (a int, b varchar(20)); +create table t2 (a int, c varchar(20)); +insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); +insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); +select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; +select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; +select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; +select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a; +drop table t1, t2; +set group_concat_max_len=default; + +# End of 4.1 tests + +# +# BUG#10162 - ON is merged with WHERE, left join is convered to a regular join +# +create table t1 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, art int(11) not null, primary key (gid,x,y)); +insert t1 values (1, -5, -8, 2), (1, 2, 2, 1), (1, 1, 1, 1); +create table t2 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, id int(11) not null, primary key (gid,id,x,y), key id (id)); +insert t2 values (1, -5, -8, 1), (1, 1, 1, 1), (1, 2, 2, 1); +create table t3 ( set_id smallint(5) unsigned not null, id tinyint(4) unsigned not null, name char(12) not null, primary key (id,set_id)); +insert t3 values (0, 1, 'a'), (1, 1, 'b'), (0, 2, 'c'), (1, 2, 'd'), (1, 3, 'e'), (1, 4, 'f'), (1, 5, 'g'), (1, 6, 'h'); +explain select name from t1 left join t2 on t1.x = t2.x and t1.y = t2.y +left join t3 on t1.art = t3.id where t2.id =1 and t2.x = -5 and t2.y =-8 +and t1.gid =1 and t2.gid =1 and t3.set_id =1; +drop tables t1,t2,t3; + +# +# Test for bug #9938: invalid conversion from outer join to inner join +# for queries containing indirect reference in WHERE clause +# + +CREATE TABLE t1 (EMPNUM INT, GRP INT); +INSERT INTO t1 VALUES (0, 10); +INSERT INTO t1 VALUES (2, 30); + +CREATE TABLE t2 (EMPNUM INT, NAME CHAR(5)); +INSERT INTO t2 VALUES (0, 'KERI'); +INSERT INTO t2 VALUES (9, 'BARRY'); + +CREATE VIEW v1 AS +SELECT COALESCE(t2.EMPNUM,t1.EMPNUM) AS EMPNUM, NAME, GRP + FROM t2 LEFT OUTER JOIN t1 ON t2.EMPNUM=t1.EMPNUM; + +SELECT * FROM v1; +SELECT * FROM v1 WHERE EMPNUM < 10; + +DROP VIEW v1; +DROP TABLE t1,t2; + +# +# Test for bug #11285: false Item_equal on expression in outer join +# + +CREATE TABLE t1 (c11 int); +CREATE TABLE t2 (c21 int); +INSERT INTO t1 VALUES (30), (40), (50); +INSERT INTO t2 VALUES (300), (400), (500); +SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40; +DROP TABLE t1, t2; +# +# Test for bugs +# #12101: erroneously applied outer join elimination in case of WHERE NOT BETWEEN +# #12102: erroneously missing outer join elimination in case of WHERE IN/IF +# + +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); + +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); + +DROP TABLE t1,t2; + +# +# Test for bug #17164: ORed FALSE blocked conversion of outer join into join +# + +# Test case moved to join_outer_innodb + +# +# Bug 19396: LEFT OUTER JOIN over views in curly braces +# +--disable_warnings +DROP VIEW IF EXISTS v1,v2; +DROP TABLE IF EXISTS t1,t2; +--enable_warnings + +CREATE TABLE t1 (a int); +CREATE table t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (1), (1), (3); +INSERT INTO t2 VALUES (2), (3); + +CREATE VIEW v1 AS SELECT a FROM t1 JOIN t2 ON t1.a=t2.b; +CREATE VIEW v2 AS SELECT b FROM t2 JOIN t1 ON t2.b=t1.a; + +SELECT v1.a, v2. b + FROM v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) + GROUP BY v1.a; +SELECT v1.a, v2. b + FROM { OJ v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) } + GROUP BY v1.a; + +DROP VIEW v1,v2; +DROP TABLE t1,t2; + +# +# Bug 19816: LEFT OUTER JOIN with constant ORed predicates in WHERE clause +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (2), (3); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1 OR 1); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (0 OR 1); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 2=2); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b WHERE (1=1 OR 1=0); + +DROP TABLE t1,t2; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/key.test b/mysql-test/suite/pbxt/t/key.test new file mode 100644 index 00000000000..8d3dcbd174d --- /dev/null +++ b/mysql-test/suite/pbxt/t/key.test @@ -0,0 +1,447 @@ +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings +SET SQL_WARNINGS=1; + +# +# This failed for Elizabeth Mattijsen +# + +CREATE TABLE t1 ( + ID CHAR(32) NOT NULL, + name CHAR(32) NOT NULL, + value CHAR(255), + INDEX indexIDname (ID(8),name(8)) +) ; + +INSERT INTO t1 VALUES +('keyword','indexdir','/export/home/local/www/database/indexes/keyword'); +INSERT INTO t1 VALUES ('keyword','urlprefix','text/ /text'); +INSERT INTO t1 VALUES ('keyword','urlmap','/text/ /'); +INSERT INTO t1 VALUES ('keyword','attr','personal employee company'); +INSERT INTO t1 VALUES +('emailgids','indexdir','/export/home/local/www/database/indexes/emailgids'); +INSERT INTO t1 VALUES ('emailgids','urlprefix','text/ /text'); +INSERT INTO t1 VALUES ('emailgids','urlmap','/text/ /'); +INSERT INTO t1 VALUES ('emailgids','attr','personal employee company'); + +SELECT value FROM t1 WHERE ID='emailgids' AND name='attr'; + +drop table t1; + +# +# Problem with many key parts and many or +# + +CREATE TABLE t1 ( + price int(5) DEFAULT '0' NOT NULL, + area varchar(40) DEFAULT '' NOT NULL, + type varchar(40) DEFAULT '' NOT NULL, + transityes enum('Y','N') DEFAULT 'Y' NOT NULL, + shopsyes enum('Y','N') DEFAULT 'Y' NOT NULL, + schoolsyes enum('Y','N') DEFAULT 'Y' NOT NULL, + petsyes enum('Y','N') DEFAULT 'Y' NOT NULL, + KEY price (price,area,type,transityes,shopsyes,schoolsyes,petsyes) +); + +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','N','N','N','N'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','N','N','N','N'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','','','',''); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); +INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); + + SELECT * FROM t1 WHERE area='Vancouver' and transityes='y' and schoolsyes='y' and ( ((type='1 Bedroom' or type='Studio/Bach') and (price<=500)) or ((type='2 Bedroom') and (price<=550)) or ((type='Shared/Roomate') and (price<=300)) or ((type='Room and Board') and (price<=500)) ) and price <= 400; + +drop table t1; + +# +# No longer a problem with primary key +# + +CREATE TABLE t1 (program enum('signup','unique','sliding') not null, type enum('basic','sliding','signup'), sites set('mt'), PRIMARY KEY (program)); +# This no longer give an error for wrong primary key +ALTER TABLE t1 modify program enum('signup','unique','sliding'); +drop table t1; + +# +# Test of compressed decimal index. +# + +CREATE TABLE t1 ( + name varchar(50) DEFAULT '' NOT NULL, + author varchar(50) DEFAULT '' NOT NULL, + category decimal(10,0) DEFAULT '0' NOT NULL, + email varchar(50), + password varchar(50), + proxy varchar(50), + bitmap varchar(20), + msg varchar(255), + urlscol varchar(127), + urlhttp varchar(127), + timeout decimal(10,0), + nbcnx decimal(10,0), + creation decimal(10,0), + livinguntil decimal(10,0), + lang decimal(10,0), + type decimal(10,0), + subcat decimal(10,0), + subtype decimal(10,0), + reg char(1), + scs varchar(255), + capacity decimal(10,0), + userISP varchar(50), + CCident varchar(50) DEFAULT '' NOT NULL, + PRIMARY KEY (name,author,category) +); +INSERT INTO t1 VALUES +('patnom','patauteur',0,'p.favre@cryo-networks.fr',NULL,NULL,'#p2sndnq6ae5g1u6t','essai salut','scol://195.242.78.119:patauteur.patnom',NULL,NULL,NULL,950036174,-882087474,NULL,3,0,3,'1','Pub/patnom/futur_divers.scs',NULL,'pat','CC1'); +INSERT INTO t1 VALUES +('LeNomDeMonSite','Marc',0,'m.barilley@cryo-networks.fr',NULL,NULL,NULL,NULL,'scol://195.242.78.119:Marc.LeNomDeMonSite',NULL,NULL,NULL,950560434,-881563214,NULL,3,0,3,'1','Pub/LeNomDeMonSite/domus_hibere.scs',NULL,'Marq','CC1'); +select * from t1 where name='patnom' and author='patauteur' and category=0; +drop table t1; + +# +# Problem with search on partial index +# + +create table t1 +( + name_id int not null auto_increment, + name blob, + INDEX name_idx (name(5)), + primary key (name_id) +); + +INSERT t1 VALUES(NULL,'/'); +INSERT t1 VALUES(NULL,'[T,U]_axpby'); +SELECT * FROM t1 WHERE name='[T,U]_axpy'; +SELECT * FROM t1 WHERE name='[T,U]_axpby'; +create table t2 +( + name_id int not null auto_increment, + name char(255) binary, + INDEX name_idx (name(5)), + primary key (name_id) +); +INSERT t2 select * from t1; +SELECT * FROM t2 WHERE name='[T,U]_axpy'; +SELECT * FROM t2 WHERE name='[T,U]_axpby'; +# Test possible problems with warnings in CREATE ... SELECT +CREATE TABLE t3 SELECT * FROM t2 WHERE name='[T,U]_axpby'; +SELECT * FROM t2 WHERE name='[T,U]_axpby'; + +drop table t1,t2,t3; + +# +# Test bug with long primary key +# + +create table t1 +( + SEQNO numeric(12 ) not null, + MOTYPEID numeric(12 ) not null, + MOINSTANCEID numeric(12 ) not null, + ATTRID numeric(12 ) not null, + VALUE varchar(120) not null, + primary key (SEQNO, MOTYPEID, MOINSTANCEID, ATTRID, VALUE ) +); +INSERT INTO t1 VALUES (1, 1, 1, 1, 'a'); +INSERT INTO t1 VALUES (1, 1, 1, 1, 'b'); +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES (1, 1, 1, 1, 'a'); +drop table t1; + +# +# Test with blob + tinyint key +# (Failed for Greg Valure) +# + +CREATE TABLE t1 ( + a tinytext NOT NULL, + b tinyint(3) unsigned NOT NULL default '0', + PRIMARY KEY (a(32),b) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('a',1),('a',2); +SELECT * FROM t1 WHERE a='a' AND b=2; +SELECT * FROM t1 WHERE a='a' AND b in (2); +SELECT * FROM t1 WHERE a='a' AND b in (1,2); +drop table t1; + +# +# Test of create key order +# + +create table t1 (a int not null unique, b int unique, c int, d int not null primary key, key(c), e int not null unique); +show keys from t1; +drop table t1; + +# +# Problem with UNIQUE() with NULL parts and auto increment +# + +CREATE TABLE t1 (c CHAR(10) NOT NULL,i INT NOT NULL AUTO_INCREMENT, +UNIQUE (c,i)); +INSERT INTO t1 (c) VALUES (NULL),(NULL); +SELECT * FROM t1; +INSERT INTO t1 (c) VALUES ('a'),('a'); +SELECT * FROM t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c CHAR(10) NULL, i INT NOT NULL AUTO_INCREMENT, +UNIQUE (c,i)); +INSERT INTO t1 (c) VALUES (NULL),(NULL); +SELECT * FROM t1; +INSERT INTO t1 (c) VALUES ('a'),('a'); +SELECT * FROM t1; +drop table t1; + +# +# longer keys +# +create table t1 (i int, a char(200), b text, unique (a), unique (b(300))) charset utf8; +insert t1 values (1, repeat('a',210), repeat('b', 310)); +insert t1 values (2, repeat(0xD0B1,215), repeat(0xD0B1, 310)); +select i, length(a), length(b), char_length(a), char_length(b) from t1; +select i from t1 where a=repeat(_utf8 'a',200); +select i from t1 where a=repeat(_utf8 0xD0B1,200); +select i from t1 where b=repeat(_utf8 'b',310); +drop table t1; + +# +# Test of key read with primary key (Bug #3497) +# + +CREATE TABLE t1 (id int unsigned auto_increment, name char(50), primary key (id)) engine=myisam; +insert into t1 (name) values ('a'), ('b'),('c'),('d'),('e'),('f'),('g'); +explain select 1 from t1 where id =2; +explain select 1 from t1 where id =2 or id=3; +explain select name from t1 where id =2; +ALTER TABLE t1 DROP PRIMARY KEY, ADD INDEX (id); +explain select 1 from t1 where id =2; +drop table t1; + +# +# Test of problem with key read (Bug #3666) +# + +CREATE TABLE t1 (numeropost mediumint(8) unsigned NOT NULL default '0', numreponse int(10) unsigned NOT NULL auto_increment, PRIMARY KEY (numeropost,numreponse), UNIQUE KEY numreponse (numreponse)); +INSERT INTO t1 (numeropost,numreponse) VALUES ('1','1'),('1','2'),('2','3'),('2','4'); +SELECT numeropost FROM t1 WHERE numreponse='1'; +EXPLAIN SELECT numeropost FROM t1 WHERE numreponse='1'; +FLUSH TABLES; +SELECT numeropost FROM t1 WHERE numreponse='1'; +drop table t1; + +# +# UNIQUE prefix keys and multi-byte charsets +# + +create table t1 (c varchar(30) character set utf8, t text character set utf8, unique (c(2)), unique (t(3))) engine=myisam; +show create table t1; +insert t1 values ('cccc', 'tttt'), + (0xD0B1212223D0B1D0B1D0B1D0B1D0B1, 0xD0B1D0B1212223D0B1D0B1D0B1D0B1), + (0xD0B1222123D0B1D0B1D0B1D0B1D0B1, 0xD0B1D0B1222123D0B1D0B1D0B1D0B1); +--error ER_DUP_ENTRY +insert t1 (c) values ('cc22'); +--error ER_DUP_ENTRY +insert t1 (t) values ('ttt22'); +--error ER_DUP_ENTRY +insert t1 (c) values (0xD0B1212322D0B1D0B1D0B1D0B1D0B1); +--error ER_DUP_ENTRY +insert t1 (t) values (0xD0B1D0B1212322D0B1D0B1D0B1D0B1); +select c from t1 where c='cccc'; +select t from t1 where t='tttt'; +select c from t1 where c=0xD0B1212223D0B1D0B1D0B1D0B1D0B1; +select t from t1 where t=0xD0B1D0B1212223D0B1D0B1D0B1D0B1; +drop table t1; + +# +# BUG#6151 - myisam index corruption +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( + c1 int, + c2 varbinary(240), + UNIQUE KEY (c1), + KEY (c2) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,'\Z\Z\Z\Z'); +INSERT INTO t1 VALUES (2,'\Z\Z\Z\Z\Z\Z'); +INSERT INTO t1 VALUES (3,'\Z\Z\Z\Z'); +select c1 from t1 where c2='\Z\Z\Z\Z'; +DELETE FROM t1 WHERE (c1 = 1); +check table t1; +select c1 from t1 where c2='\Z\Z\Z\Z'; +DELETE FROM t1 WHERE (c1 = 3); +check table t1; +select c1 from t1 where c2='\Z\Z\Z\Z'; + +# +# test delete of keys in a different order +# +truncate table t1; +insert into t1 values(1,"aaaa"),(2,"aaab"),(3,"aaac"),(4,"aaccc"); +delete from t1 where c1=3; +delete from t1 where c1=1; +delete from t1 where c1=4; +check table t1; + +drop table t1; + +# +# Bug 6166: index prefix length of 0 not rejected +# +# this test should fail in 5.0 +# to fix it, remove #ifdef in +# file sql_yacc.yy(key_part) +# create dedicated error code for this and +# and change my_printf_error() to my_error + +--error 1391 +create table t1 (c char(10), index (c(0))); + +# +# Bug #6126: Duplicate columns in keys should fail +# Bug #6252: (dup) +# +--error 1060 +create table t1 (c char(10), index (c,c)); +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)); +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c1,c1,c2)); +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c2,c1,c1)); +create table t1 (c1 char(10), c2 char(10)); +--error 1060 +alter table t1 add key (c1,c1); +--error 1060 +alter table t1 add key (c2,c1,c1); +--error 1060 +alter table t1 add key (c1,c2,c1); +--error 1060 +alter table t1 add key (c1,c1,c2); +drop table t1; + +# +# Bug#11228: DESC shows arbitrary column as "PRI" +# +create table t1 ( + i1 INT NOT NULL, + i2 INT NOT NULL, + UNIQUE i1idx (i1), + UNIQUE i2idx (i2)); +desc t1; +show create table t1; +drop table t1; + +# +# Bug#12565 - ERROR 1034 when running simple UPDATE or DELETE +# on large MyISAM table +# +create table t1 ( + c1 int, + c2 varchar(20) not null, + primary key (c1), + key (c2(10)) +) engine=myisam; +insert into t1 values (1,''); +insert into t1 values (2,' \t\tTest String'); +insert into t1 values (3,' \n\tTest String'); +update t1 set c2 = 'New Test String' where c1 = 1; +select * from t1; +drop table t1; + +# +# If we use a partial field for a key that is actually the length of the +# field, and we extend the field, we end up with a key that includes the +# whole new length of the field. +# +create table t1 (a varchar(10), b varchar(10), key(a(10),b(10))); +show create table t1; +alter table t1 modify b varchar(20); +show create table t1; +alter table t1 modify a varchar(20); +show create table t1; +drop table t1; + +# +# Bug #11227: Incorrectly reporting 'MUL' vs. 'UNI' on varchar +# +create table t1 (a int not null primary key, b varchar(20) not null unique); +desc t1; +drop table t1; +create table t1 (a int not null primary key, b int not null unique); +desc t1; +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null, unique (b(10))); +desc t1; +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null, c varchar(20) not null, unique(b(10),c(10))); +desc t1; +drop table t1; + +# End of 4.1 tests + +# +# WL#1563 - Modify MySQL to support on-line CREATE/DROP INDEX +# To test if this really works, you need to run with --debug +# and check the trace file. +# +# Create a table with named and unnamed indexes. +create table t1 ( + c1 int, + c2 char(12), + c3 varchar(123), + c4 timestamp, + index (c1), + index i1 (c1), + index i2 (c2), + index i3 (c3), + unique i4 (c4), + index i5 (c1, c2, c3, c4), + primary key (c2, c3), + index (c2, c4)); +show create table t1; +# Some simple tests. +alter table t1 drop index c1; +alter table t1 add index (c1); +# This creates index 'c1_2'. +alter table t1 add index (c1); +alter table t1 drop index i3; +alter table t1 add index i3 (c3); +# Two indexes at the same time. +alter table t1 drop index i2, drop index i4; +alter table t1 add index i2 (c2), add index i4 (c4); +# Three indexes, one of them reversely. +alter table t1 drop index i2, drop index i4, add index i6 (c2, c4); +alter table t1 add index i2 (c2), add index i4 (c4), drop index i6; +# include an unique index. +alter table t1 drop index i2, drop index i4, add unique i4 (c4); +alter table t1 add index i2 (c2), drop index i4, add index i4 (c4); +# Modify an index by changing its definition. +alter table t1 drop index c2, add index (c2(4),c3(7)); +# Change nothing. The new key definition is the same as the old one. +alter table t1 drop index c2, add index (c2(4),c3(7)); +# Test primary key handling. +alter table t1 add primary key (c1, c2), drop primary key; +alter table t1 drop primary key; +# Drop is checked first. Primary key must exist. +--error 1091 +alter table t1 add primary key (c1, c2), drop primary key; +show create table t1; +# Insert non-unique values. +insert into t1 values(1, 'a', 'a', NULL); +insert into t1 values(1, 'b', 'b', NULL); +# Drop some indexes for new adds. +alter table t1 drop index i3, drop index i2, drop index i1; +# Add indexes, one is unique on non-unique values. +--error ER_DUP_ENTRY +alter table t1 add index i3 (c3), add index i2 (c2), add unique index i1 (c1); +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/key_cache.test b/mysql-test/suite/pbxt/t/key_cache.test new file mode 100644 index 00000000000..10dbdda6068 --- /dev/null +++ b/mysql-test/suite/pbxt/t/key_cache.test @@ -0,0 +1,229 @@ +# +# Test of multiple key caches +# +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings + +SET @save_key_buffer=@@key_buffer_size; + +SELECT @@key_buffer_size, @@small.key_buffer_size; + +# Change default key cache size +SET @@global.key_buffer_size=16*1024*1024; +SET @@global.default.key_buffer_size=16*1024*1024; +SET @@global.default.key_buffer_size=16*1024*1024; + +SET @@global.small.key_buffer_size=1*1024*1024; +SET @@global.medium.key_buffer_size=4*1024*1024; +# Drop buffer +SET @@global.medium.key_buffer_size=0; +# Test double drop +SET @@global.medium.key_buffer_size=0; + +# Print key buffer with different syntaxes +SHOW VARIABLES like "key_buffer_size"; +SELECT @@key_buffer_size; +SELECT @@global.key_buffer_size; +SELECT @@global.default.key_buffer_size; +SELECT @@global.default.`key_buffer_size`; +SELECT @@global.`default`.`key_buffer_size`; +SELECT @@`default`.key_buffer_size; + +SELECT @@small.key_buffer_size; +SELECT @@medium.key_buffer_size; + +SET @@global.key_buffer_size=@save_key_buffer; + +# +# Errors +# + +--error 1064 +SELECT @@default.key_buffer_size; +--error 1272 +SELECT @@skr.storage_engine="test"; + +select @@keycache1.key_cache_block_size; +select @@keycache1.key_buffer_size; +set global keycache1.key_cache_block_size=2048; +select @@keycache1.key_buffer_size; +select @@keycache1.key_cache_block_size; +set global keycache1.key_buffer_size=1*1024*1024; +select @@keycache1.key_buffer_size; +select @@keycache1.key_cache_block_size; +set global keycache2.key_buffer_size=4*1024*1024; +select @@keycache2.key_buffer_size; +select @@keycache2.key_cache_block_size; +set global keycache1.key_buffer_size=0; +select @@keycache1.key_buffer_size; +select @@keycache1.key_cache_block_size; +select @@key_buffer_size; +select @@key_cache_block_size; + +set global keycache1.key_buffer_size=1024*1024; + +create table t1 (p int primary key, a char(10)) delay_key_write=1; +create table t2 (p int primary key, i int, a char(10), key k1(i), key k2(a)); + +# PBXT: this is irrelevant for PBXT and gives different results on different systems +#show status like 'key_blocks_used'; + +# Following results differs on 64 and 32 bit systems because of different +# pointer sizes, which takes up different amount of space in key cache + +# PBXT: this is irrelevant for PBXT and gives different results on different systems +#--replace_result 1812 KEY_BLOCKS_UNUSED 1793 KEY_BLOCKS_UNUSED 1674 KEY_BLOCKS_UNUSED 1818 KEY_BLOCKS_UNUSED 1824 KEY_BLOCKS_UNUSED +#show status like 'key_blocks_unused'; + +insert into t1 values (1, 'qqqq'), (11, 'yyyy'); +insert into t2 values (1, 1, 'qqqq'), (2, 1, 'pppp'), + (3, 1, 'yyyy'), (4, 3, 'zzzz'); +select * from t1; +select * from t2; + +update t1 set p=2 where p=1; +update t2 set i=2 where i=1; + +# PBXT: this is irrelevant for PBXT and gives different results on different systems +#show status like 'key_blocks_used'; +#--replace_result 1808 KEY_BLOCKS_UNUSED 1789 KEY_BLOCKS_UNUSED 1670 KEY_BLOCKS_UNUSED 1814 KEY_BLOCKS_UNUSED 1820 KEY_BLOCKS_UNUSED +#show status like 'key_blocks_unused'; + +cache index t1 key (`primary`) in keycache1; + +explain select p from t1; +select p from t1; +explain select i from t2; +select i from t2; +explain select count(*) from t1, t2 where t1.p = t2.i; +select count(*) from t1, t2 where t1.p = t2.i; + +cache index t2 in keycache1; +update t2 set p=p+1000, i=2 where a='qqqq'; +cache index t2 in keycache2; +insert into t2 values (2000, 3, 'yyyy'); +cache index t2 in keycache1; +update t2 set p=3000 where a='zzzz'; +select * from t2 order by p; # PBXT required ORDER for consistant result +explain select p from t2; +select p from t2; +explain select i from t2; +select i from t2; +explain select a from t2; +select a from t2; + +# Test some error conditions +--error 1284 +cache index t1 in unknown_key_cache; +cache index t1 key (unknown_key) in keycache1; + +select @@keycache2.key_buffer_size; +select @@keycache2.key_cache_block_size; +set global keycache2.key_buffer_size=0; +select @@keycache2.key_buffer_size; +select @@keycache2.key_cache_block_size; +set global keycache2.key_buffer_size=1024*1024; +select @@keycache2.key_buffer_size; + +update t2 set p=4000 where a='zzzz'; +update t1 set p=p+1; + +set global keycache1.key_buffer_size=0; +select * from t2 order by p; # PBXT required ORDER for consistant result +select p from t2 order by p; # PBXT required ORDER for consistant result +explain select i from t2; +select i from t2; +explain select a from t2; +select a from t2; + +select * from t1; +select p from t1; + +# Use the 'small' key cache +create table t3 (like t1); +cache index t3 in small; +insert into t3 select * from t1; +cache index t3 in keycache2; +cache index t1,t2 in default; +drop table t1,t2,t3; + +# PBXT: this is irrelevant for PBXT and gives different results on different systems +#show status like 'key_blocks_used'; +#--replace_result 1812 KEY_BLOCKS_UNUSED 1793 KEY_BLOCKS_UNUSED 1674 KEY_BLOCKS_UNUSED 1818 KEY_BLOCKS_UNUSED 1824 KEY_BLOCKS_UNUSED +#show status like 'key_blocks_unused'; + + +# Cleanup +# We don't reset keycache2 as we want to ensure that mysqld will reset it +set global keycache2.key_buffer_size=0; + +# Test to set up a too small size for a key cache (bug #2064) +set global keycache3.key_buffer_size=100; +set global keycache3.key_buffer_size=0; + +# Test case for bug 6447 + +create table t1 (mytext text, FULLTEXT (mytext)) engine=myisam; # PBXT: Only MyISAM can do FULLTEXT +insert t1 values ('aaabbb'); + +check table t1; +set @my_key_cache_block_size= @@global.key_cache_block_size; +set GLOBAL key_cache_block_size=2048; +check table t1; +drop table t1; +# Restore the changed variable value +set global key_cache_block_size= @my_key_cache_block_size; + +# +# Bug #19079: corrupted index when key_cache_block_size is not multiple of +# myisam_block_size + +CREATE TABLE t1(a int NOT NULL AUTO_INCREMENT PRIMARY KEY); +SET @my_key_cache_block_size= @@global.key_cache_block_size; +SET GLOBAL key_cache_block_size=1536; +INSERT INTO t1 VALUES (1); +SELECT @@key_cache_block_size; +CHECK TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1(a int NOT NULL AUTO_INCREMENT PRIMARY KEY, b int); +CREATE TABLE t2(a int NOT NULL AUTO_INCREMENT PRIMARY KEY, b int); +SET GLOBAL key_cache_block_size=1536; +INSERT INTO t1 VALUES (1,0); +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +INSERT INTO t2(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t2; +SELECT COUNT(*) FROM t1; +SELECT @@key_cache_block_size; +CHECK TABLE t1; +DROP TABLE t1,t2; +# Restore changed variables +set global key_cache_block_size= @my_key_cache_block_size; + +# +# Bug#10473 - Can't set 'key_buffer_size' system variable to ZERO +# (One cannot drop the default key cache.) +# +set @@global.key_buffer_size=0; +select @@global.key_buffer_size; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/key_diff.test b/mysql-test/suite/pbxt/t/key_diff.test new file mode 100644 index 00000000000..5e9d7bac9cc --- /dev/null +++ b/mysql-test/suite/pbxt/t/key_diff.test @@ -0,0 +1,27 @@ +# +# Check on condition on different length keys. + +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE t1 ( + a char(5) NOT NULL, + b char(4) NOT NULL, + KEY (a), + KEY (b) +); + +INSERT INTO t1 VALUES ('A','B'),('b','A'),('C','c'),('D','E'),('a','a'); + +select * from t1,t1 as t2; +explain select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B; +#select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B; +select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B order by binary t1.a,t2.a; +select * from t1 where a='a'; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/key_primary.test b/mysql-test/suite/pbxt/t/key_primary.test new file mode 100644 index 00000000000..185170bddd9 --- /dev/null +++ b/mysql-test/suite/pbxt/t/key_primary.test @@ -0,0 +1,23 @@ +# +# test of primary key conversions +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (t1 char(3) primary key); +insert into t1 values("ABC"); +insert into t1 values("ABA"); +insert into t1 values("AB%"); +select * from t1 where t1="ABC"; +select * from t1 where t1="ABCD"; +select * from t1 where t1 like "a_\%"; +describe select * from t1 where t1="ABC"; +describe select * from t1 where t1="ABCD"; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/keywords.test b/mysql-test/suite/pbxt/t/keywords.test new file mode 100644 index 00000000000..22b5b955942 --- /dev/null +++ b/mysql-test/suite/pbxt/t/keywords.test @@ -0,0 +1,48 @@ +# +# Test keywords as fields +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (time time, date date, timestamp timestamp, +quarter int, week int, year int, timestampadd int, timestampdiff int); +insert into t1 values ("12:22:22","97:02:03","1997-01-02",1,2,3,4,5); +select * from t1; +select t1.time+0,t1.date+0,t1.timestamp+0,concat(date," ",time), + t1.quarter+t1.week, t1.year+timestampadd, timestampdiff from t1; +drop table t1; +create table events(binlog int); +insert into events values(1); +select events.binlog from events; +drop table events; + +# End of 4.1 tests + +# +# Bug#19939 "AUTHORS is not a keyword" +# +delimiter |; +create procedure p1() +begin + declare n int default 2; + authors: while n > 0 do + set n = n -1; + end while authors; +end| +create procedure p2() +begin + declare n int default 2; + contributors: while n > 0 do + set n = n -1; + end while contributors; +end| +delimiter ;| +drop procedure p1; +drop procedure p2; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 5.1 tests diff --git a/mysql-test/suite/pbxt/t/limit.test b/mysql-test/suite/pbxt/t/limit.test new file mode 100644 index 00000000000..0844af8705d --- /dev/null +++ b/mysql-test/suite/pbxt/t/limit.test @@ -0,0 +1,76 @@ +# +# Test of update and delete with limit +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int not null default 0 primary key, b int not null default 0); +insert into t1 () values (); # Testing default values +insert into t1 values (1,1),(2,1),(3,1); +update t1 set a=4 where b=1 limit 1; +select * from t1 order by a; # PBXT: required for consistent result +update t1 set b=2 where b=1 limit 2; +select * from t1 order by a; # PBXT: required for consistent result +update t1 set b=4 where b=1; +select * from t1 order by a; # PBXT: required for consistent result +delete from t1 where b=2 limit 1; +select * from t1 order by a; # PBXT: required for consistent result +delete from t1 limit 1; +select * from t1 order by a; # PBXT: required for consistent result +drop table t1; + +create table t1 (i int); +insert into t1 (i) values(1),(1),(1); +delete from t1 limit 1; +update t1 set i=2 limit 1; +delete from t1 limit 0; +update t1 set i=3 limit 0; +select * from t1; +drop table t1; + +# LIMIT 0 + +select 0 limit 0; + +# +# Test with DELETE, ORDER BY and limit (bug #1024) +# + +CREATE TABLE t1(id int auto_increment primary key, id2 int, index(id2)); +INSERT INTO t1 (id2) values (0),(0),(0); +DELETE FROM t1 WHERE id=1; +INSERT INTO t1 SET id2=0; +SELECT * FROM t1; +DELETE FROM t1 WHERE id2 = 0 ORDER BY id LIMIT 1; +# should have deleted WHERE id=2 +SELECT * FROM t1; +DELETE FROM t1 WHERE id2 = 0 ORDER BY id desc LIMIT 1; +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug#8023 - limit on UNION with from DUAL, causes syntax error +# +create table t1 (a integer); +insert into t1 values (1); +# both queries must return one row +select 1 as a from t1 union all select 1 from dual limit 1; +(select 1 as a from t1) union all (select 1 from dual) limit 1; +drop table t1; + +# +# Bug #21787: COUNT(*) + ORDER BY + LIMIT returns wrong result +# +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6),(7); +explain select count(*) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3; +select count(*) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3; +explain select sum(a) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3; +select sum(a) c FROM t1 WHERE a > 0 ORDER BY c LIMIT 3; +drop table t1; +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/load_unique_error1.inc b/mysql-test/suite/pbxt/t/load_unique_error1.inc new file mode 100644 index 00000000000..998daad4144 --- /dev/null +++ b/mysql-test/suite/pbxt/t/load_unique_error1.inc @@ -0,0 +1,5 @@ +1,abc +2,def +3,ghi +3,jkl +4,opq diff --git a/mysql-test/suite/pbxt/t/lock.test b/mysql-test/suite/pbxt/t/lock.test new file mode 100644 index 00000000000..266fc7397c2 --- /dev/null +++ b/mysql-test/suite/pbxt/t/lock.test @@ -0,0 +1,113 @@ +# +# Testing of table locking +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +CREATE TABLE t1 ( `id` int(11) NOT NULL default '0', `id2` int(11) NOT NULL default '0', `id3` int(11) NOT NULL default '0', `dummy1` char(30) default NULL, PRIMARY KEY (`id`,`id2`), KEY `index_id3` (`id3`)) ENGINE=MyISAM; +insert into t1 (id,id2) values (1,1),(1,2),(1,3); +LOCK TABLE t1 WRITE; +select dummy1,count(distinct id) from t1 group by dummy1; +update t1 set id=-1 where id=1; +LOCK TABLE t1 READ; +--error 1099 +update t1 set id=1 where id=1; +--error 1100 +create table t2 SELECT * from t1; +create temporary table t2 SELECT * from t1; +drop table if exists t2; +unlock tables; +create table t2 SELECT * from t1; +LOCK TABLE t1 WRITE,t2 write; +insert into t2 SELECT * from t1; +update t1 set id=1 where id=-1; +drop table t1,t2; + + +# +# Check bug with INSERT ... SELECT with lock tables +# + +CREATE TABLE t1 ( + index1 smallint(6) default NULL, + nr smallint(6) default NULL, + KEY index1(index1) +) ENGINE=MyISAM; + +CREATE TABLE t2 ( + nr smallint(6) default NULL, + name varchar(20) default NULL +) ENGINE=MyISAM; + +INSERT INTO t2 VALUES (1,'item1'); +INSERT INTO t2 VALUES (2,'item2'); + +# problem begins here! +lock tables t1 write, t2 read; +insert into t1 select 1,nr from t2 where name='item1'; +insert into t1 select 2,nr from t2 where name='item2'; +unlock tables; +check table t1; + +# Check error message +lock tables t1 write; +check table t2; +--error 1100 +insert into t1 select index1,nr from t1; +unlock tables; +lock tables t1 write, t1 as t1_alias read; +insert into t1 select index1,nr from t1 as t1_alias; +drop table t1,t2; + +# +# BUG#5390 - problems with merge tables +# Supplement test for the after-fix optimization +# Check that a dropped table is correctly removed from a lock. +create table t1 (c1 int); +create table t2 (c1 int); +create table t3 (c1 int); +lock tables t1 write, t2 write, t3 write; +# This removes one table after the other from the lock. +drop table t2, t3, t1; +# +# Check that a lock merge works. +create table t1 (c1 int); +create table t2 (c1 int); +create table t3 (c1 int); +lock tables t1 write, t2 write, t3 write, t1 as t4 read; +alter table t2 add column c2 int; +drop table t1, t2, t3; + +# Bug7241 - Invalid response when DELETE .. USING and LOCK TABLES used. +# +create table t1 ( a int(11) not null auto_increment, primary key(a)); +create table t2 ( a int(11) not null auto_increment, primary key(a)); +lock tables t1 write, t2 read; +delete from t1 using t1,t2 where t1.a=t2.a; +delete t1 from t1,t2 where t1.a=t2.a; +--error 1099 +delete from t2 using t1,t2 where t1.a=t2.a; +--error 1099 +delete t2 from t1,t2 where t1.a=t2.a; +drop table t1,t2; + +# End of 4.1 tests + +# +# Bug#18884 "lock table + global read lock = crash" +# The bug is not repeatable, just add the test case. +# +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +lock table t1 write; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables with read lock; +unlock tables; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/lock_multi.test b/mysql-test/suite/pbxt/t/lock_multi.test new file mode 100644 index 00000000000..57d4729657b --- /dev/null +++ b/mysql-test/suite/pbxt/t/lock_multi.test @@ -0,0 +1,269 @@ +-- source include/not_embedded.inc +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +# Test to see if select will get the lock ahead of low priority update + +connect (locker,localhost,root,,); +connect (reader,localhost,root,,); +connect (writer,localhost,root,,); + +connection locker; +create table t1(n int); +insert into t1 values (1); +lock tables t1 write; +connection writer; +send update low_priority t1 set n = 4; +connection reader; +--sleep 2 +send select n from t1; +connection locker; +--sleep 2 +unlock tables; +connection writer; +reap; +connection reader; +reap; +drop table t1; + +connection locker; +create table t1(n int); +insert into t1 values (1); +lock tables t1 read; +connection writer; +send update low_priority t1 set n = 4; +connection reader; +--sleep 2 +send select n from t1; +connection locker; +--sleep 2 +unlock tables; +connection writer; +reap; +connection reader; +reap; +drop table t1; + +# +# Test problem when using locks with multi-updates +# It should not block when multi-update is reading on a read-locked table +# + +connection locker; +create table t1 (a int, b int); +create table t2 (c int, d int); +insert into t1 values(1,1); +insert into t1 values(2,2); +insert into t2 values(1,2); +lock table t1 read; +connection writer; +--sleep 2 +send update t1,t2 set c=a where b=d; +connection reader; +--sleep 2 +select c from t2; +connection writer; +reap; +connection locker; +drop table t1; +drop table t2; + +# +# Test problem when using locks on many tables and droping a table that +# is to-be-locked by another thread +# + +connection locker; +create table t1 (a int); +create table t2 (a int); +lock table t1 write, t2 write; +connection reader; +send insert t1 select * from t2; +connection locker; +drop table t2; +connection reader; +--error 1146 +reap; +connection locker; +drop table t1; + +# +# Same test as above, but with the dropped table locked twice +# + +connection locker; +create table t1 (a int); +create table t2 (a int); +lock table t1 write, t2 write, t1 as t1_2 write, t2 as t2_2 write; +connection reader; +send insert t1 select * from t2; +connection locker; +drop table t2; +connection reader; +--error 1146 +reap; +connection locker; +drop table t1; + + +# End of 4.1 tests + +# +# BUG#9998 - MySQL client hangs on USE "database" +# +create table t1(a int); +lock tables t1 write; +connection reader; +show columns from t1; +connection locker; +unlock tables; +drop table t1; + +# +# Bug#16986 - Deadlock condition with MyISAM tables +# +connection locker; +use mysql; +LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; +FLUSH TABLES; +--sleep 1 +# +connection reader; +use mysql; +#NOTE: This must be a multi-table select, otherwise the deadlock will not occur +send SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; +--sleep 1 +# +connection locker; +# Make test case independent from earlier grants. +--replace_result "Table is already up to date" "OK" +OPTIMIZE TABLES columns_priv, db, host, user; +UNLOCK TABLES; +# +connection reader; +reap; +use test; +# +connection locker; +use test; +# +connection default; +# +# Test if CREATE TABLE with LOCK TABLE deadlocks. +# +connection writer; +CREATE TABLE t1 (c1 int); +LOCK TABLE t1 WRITE; +# +# This waits until t1 is unlocked. +connection locker; +send FLUSH TABLES WITH READ LOCK; +--sleep 1 +# +# This must not block. +connection writer; +CREATE TABLE t2 (c1 int); +UNLOCK TABLES; +# +# This awakes now. +connection locker; +reap; +UNLOCK TABLES; +# +connection default; +DROP TABLE t1, t2; +# +# Test if CREATE TABLE SELECT with LOCK TABLE deadlocks. +# +connection writer; +CREATE TABLE t1 (c1 int); +LOCK TABLE t1 WRITE; +# +# This waits until t1 is unlocked. +connection locker; +send FLUSH TABLES WITH READ LOCK; +--sleep 1 +# +# This must not block. +connection writer; +--error 1100 +CREATE TABLE t2 AS SELECT * FROM t1; +UNLOCK TABLES; +# +# This awakes now. +connection locker; +reap; +UNLOCK TABLES; +# +connection default; +DROP TABLE t1; + +# +# Bug#19815 - CREATE/RENAME/DROP DATABASE can deadlock on a global read lock +# +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +# +connection con1; +CREATE DATABASE mysqltest_1; +FLUSH TABLES WITH READ LOCK; +# +# With bug in place: acquire LOCK_mysql_create_table and +# wait in wait_if_global_read_lock(). +connection con2; +send DROP DATABASE mysqltest_1; +--sleep 1 +# +# With bug in place: try to acquire LOCK_mysql_create_table... +# When fixed: Reject dropping db because of the read lock. +connection con1; +--error ER_CANT_UPDATE_WITH_READLOCK +DROP DATABASE mysqltest_1; +UNLOCK TABLES; +# +connection con2; +reap; +# +connection default; +disconnect con1; +disconnect con2; +# This must have been dropped by connection 2 already, +# which waited until the global read lock was released. +--error ER_DB_DROP_EXISTS +DROP DATABASE mysqltest_1; + +# +# Bug #17264: MySQL Server freeze +# +connection locker; +# Disable warnings to allow test to run also without InnoDB +--disable_warnings +create table t1 (f1 int(12) unsigned not null auto_increment, primary key(f1)) engine=innodb; +--enable_warnings +lock tables t1 write; +connection writer; +--sleep 2 +delimiter //; +send alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // +delimiter ;// +connection reader; +--sleep 2 +delimiter //; +send alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // +delimiter ;// +connection locker; +--sleep 2 +unlock tables; +connection writer; +reap; +connection reader; +reap; +connection locker; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 5.0 tests + diff --git a/mysql-test/suite/pbxt/t/lock_tables_lost_commit.test b/mysql-test/suite/pbxt/t/lock_tables_lost_commit.test new file mode 100644 index 00000000000..d31b4b7dfb5 --- /dev/null +++ b/mysql-test/suite/pbxt/t/lock_tables_lost_commit.test @@ -0,0 +1,24 @@ +# This is a test for bug 578 + +-- source include/have_innodb.inc + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +connection con1; +--disable_warnings +drop table if exists t1; +create table t1(a int) engine=innodb; +--enable_warnings +lock tables t1 write; +insert into t1 values(10); +disconnect con1; + +connection con2; +# The bug was that, because of the LOCK TABLES, the handler "forgot" to commit, +# and the other commit when we write to the binlog was not done because of +# binlog-ignore-db +select * from t1; +drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/lowercase_table2.test b/mysql-test/suite/pbxt/t/lowercase_table2.test new file mode 100644 index 00000000000..f4e97842871 --- /dev/null +++ b/mysql-test/suite/pbxt/t/lowercase_table2.test @@ -0,0 +1,156 @@ +# +# Test of --lower-case-table-names=2 +# (User has case insensitive file system and wants to preserve case of +# table names) +# +--source include/have_innodb.inc +--require r/lowercase2.require +disable_query_log; +show variables like "lower_case_table_names"; +enable_query_log; + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3,t2aA,t1Aa; +DROP DATABASE IF EXISTS `TEST_$1`; +DROP DATABASE IF EXISTS `test_$1`; +DROP DATABASE IF EXISTS mysqltest_LC2; +--enable_warnings + +CREATE TABLE T1 (a int); +INSERT INTO T1 VALUES (1); +SHOW TABLES LIKE "T1"; +SHOW TABLES LIKE "t1"; +SHOW CREATE TABLE T1; +RENAME TABLE T1 TO T2; +SHOW TABLES LIKE "T2"; +SELECT * FROM t2; +RENAME TABLE T2 TO t3; +SHOW TABLES LIKE "T3"; +RENAME TABLE T3 TO T1; +SHOW TABLES LIKE "T1"; +ALTER TABLE T1 add b int; +SHOW TABLES LIKE "T1"; +ALTER TABLE T1 RENAME T2; +SHOW TABLES LIKE "T2"; + +LOCK TABLE T2 WRITE; +ALTER TABLE T2 drop b; +SHOW TABLES LIKE "T2"; +UNLOCK TABLES; +RENAME TABLE T2 TO T1; +SHOW TABLES LIKE "T1"; +SELECT * from T1; +DROP TABLE T1; + +# +# Test database level +# + +CREATE DATABASE `TEST_$1`; +SHOW DATABASES LIKE "TEST%"; +DROP DATABASE `test_$1`; + +# +# Test of innodb tables with lower_case_table_names=2 +# + +CREATE TABLE T1 (a int) engine=innodb; +INSERT INTO T1 VALUES (1); +SHOW TABLES LIKE "T1"; +SHOW TABLES LIKE "t1"; +SHOW CREATE TABLE T1; +RENAME TABLE T1 TO T2; +SHOW TABLES LIKE "T2"; +SELECT * FROM t2; +RENAME TABLE T2 TO t3; +SHOW TABLES LIKE "T3"; +RENAME TABLE T3 TO T1; +SHOW TABLES LIKE "T1"; +ALTER TABLE T1 add b int; +SHOW TABLES LIKE "T1"; +ALTER TABLE T1 RENAME T2; +SHOW TABLES LIKE "T2"; + +LOCK TABLE T2 WRITE; +ALTER TABLE T2 drop b; +SHOW TABLES LIKE "T2"; +UNLOCK TABLES; +RENAME TABLE T2 TO T1; +SHOW TABLES LIKE "T1"; +SELECT * from T1; +DROP TABLE T1; + +# +# Test problem with temporary tables (Bug #2858) +# + +create table T1 (EVENT_ID int auto_increment primary key, LOCATION char(20)); +insert into T1 values (NULL,"Mic-4"),(NULL,"Mic-5"),(NULL,"Mic-6"); +SELECT LOCATION FROM T1 WHERE EVENT_ID=2 UNION ALL SELECT LOCATION FROM T1 WHERE EVENT_ID=3; +SELECT LOCATION FROM T1 WHERE EVENT_ID=2 UNION ALL SELECT LOCATION FROM T1 WHERE EVENT_ID=3; +SELECT LOCATION FROM T1 WHERE EVENT_ID=2 UNION ALL SELECT LOCATION FROM T1 WHERE EVENT_ID=3; +drop table T1; + +# +# Test name conversion with ALTER TABLE / CREATE INDEX (Bug #3109) +# + +create table T1 (A int); +alter table T1 add index (A); +show tables like 'T1%'; +alter table t1 add index (A); +show tables like 't1%'; +drop table t1; + +# +# Bug #7261: Alter table loses temp table +# + +create temporary table T1(a int(11), b varchar(8)); +insert into T1 values (1, 'abc'); +select * from T1; +alter table T1 add index (a); +select * from T1; +drop table T1; + +# +# Bug #8355: Tables not dropped from table cache on drop db +# +create database mysqltest_LC2; +use mysqltest_LC2; +create table myUC (i int); +insert into myUC values (1),(2),(3); +select * from myUC; +use test; +drop database mysqltest_LC2; +create database mysqltest_LC2; +use mysqltest_LC2; +create table myUC (i int); +select * from myUC; +use test; +drop database mysqltest_LC2; + +# +# Bug #9500: Problem with WHERE clause +# +create table t2aA (col1 int); +create table t1Aa (col1 int); +select t1Aa.col1 from t1aA,t2Aa where t1Aa.col1 = t2aA.col1; +drop table t2aA, t1Aa; + +# End of 4.1 tests + +# +# Bug#17661 information_schema.SCHEMATA returns uppercase with lower_case_table_names = 1 +# +create database mysqltest_LC2; +use mysqltest_LC2; +create table myUC (i int); +select TABLE_SCHEMA,TABLE_NAME FROM information_schema.TABLES +where TABLE_SCHEMA ='mysqltest_LC2'; +use test; +drop database mysqltest_LC2; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/lowercase_table_grant.test b/mysql-test/suite/pbxt/t/lowercase_table_grant.test new file mode 100644 index 00000000000..7449231fca5 --- /dev/null +++ b/mysql-test/suite/pbxt/t/lowercase_table_grant.test @@ -0,0 +1,30 @@ +# Don't test with embedded server +-- source include/not_embedded.inc + +# Test of grants when lower_case_table_names is on +use mysql; + +# mixed-case database name for testing +create database MYSQLtest; + +# check that database name gets forced to lowercase +grant all on MySQLtest.* to mysqltest_1@localhost; +show grants for mysqltest_1@localhost; + +# now force it to mixed case, but see that it is lowercased in the acl cache +select * from db where user = 'mysqltest_1'; +update db set db = 'MYSQLtest' where db = 'mysqltest' and user = 'mysqltest_1' and host = 'localhost'; +flush privileges; +show grants for mysqltest_1@localhost; +select * from db where user = 'mysqltest_1'; + +# clear out the user we created +# +# can't use REVOKE because of the mixed-case database name +delete from db where db = 'MYSQLtest' and user = 'mysqltest_1' and host = 'localhost'; +flush privileges; +drop user mysqltest_1@localhost; + +drop database MYSQLtest; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/lowercase_table_qcache.test b/mysql-test/suite/pbxt/t/lowercase_table_qcache.test new file mode 100644 index 00000000000..b397133255d --- /dev/null +++ b/mysql-test/suite/pbxt/t/lowercase_table_qcache.test @@ -0,0 +1,34 @@ +-- source include/have_query_cache.inc +# +# Test of query cache with --lower-case-table-names +# +set GLOBAL query_cache_size=1355776; + +--disable_warnings +drop database if exists MySQLtesT; +--enable_warnings + +create database MySQLtesT; +create table MySQLtesT.t1 (a int); +select * from MySQLtesT.t1; +show status like "Qcache_queries_in_cache"; +drop database mysqltest; +show status like "Qcache_queries_in_cache"; + +use MySQL; +disable_result_log; +select * from db; +enable_result_log; +show status like "Qcache_queries_in_cache"; +use test; +disable_result_log; +select * from MySQL.db; +enable_result_log; +show status like "Qcache_queries_in_cache"; + +set GLOBAL query_cache_size=0; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/lowercase_view.test b/mysql-test/suite/pbxt/t/lowercase_view.test new file mode 100644 index 00000000000..4be8d90d590 --- /dev/null +++ b/mysql-test/suite/pbxt/t/lowercase_view.test @@ -0,0 +1,166 @@ +--disable_warnings +drop table if exists t1Aa,t2Aa,v1Aa,v2Aa; +drop view if exists t1Aa,t2Aa,v1Aa,v2Aa; +drop database if exists MySQLTest; +--enable_warnings + +# +# different cases in VIEW +# +create database MySQLTest; +use MySQLTest; +create table TaB (Field int); +create view ViE as select * from TAb; +show create table VIe; +drop database MySQLTest; +use test; + +# +# test of updating and fetching from the same table check +# +create table t1Aa (col1 int); +create table t2aA (col1 int); +create view v1Aa as select * from t1aA; +create view v2aA as select * from v1aA; +create view v3Aa as select v2Aa.col1 from v2aA,t2Aa where v2Aa.col1 = t2aA.col1; +-- error 1443 +update v2aA set col1 = (select max(col1) from v1Aa); +-- error 1443 +update v2Aa set col1 = (select max(col1) from t1Aa); +-- error 1093 +update v2aA set col1 = (select max(col1) from v2Aa); +-- error 1443 +update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1; +-- error 1443 +update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v1Aa) where t1aA.col1 = t2aA.col1; +-- error 1093 +update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; +-- error 1443 +update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from v1aA) where v2Aa.col1 = t2aA.col1; +-- error 1443 +update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v1Aa) where t1Aa.col1 = t2aA.col1; +-- error 1443 +update t2Aa,v1aA set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; +-- error 1443 +update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from t1aA) where v2aA.col1 = t2aA.col1; +-- error 1093 +update t1Aa,t2Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; +-- error 1443 +update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from t1Aa) where v1aA.col1 = t2aA.col1; +-- error 1093 +update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from t1aA) where v2Aa.col1 = t2aA.col1; +-- error 1093 +update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; +-- error 1093 +update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from t1Aa) where v1Aa.col1 = t2aA.col1; +-- error 1093 +update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; +-- error 1443 +update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v2aA) where t1aA.col1 = t2aA.col1; +-- error 1443 +update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v2Aa) where v1aA.col1 = t2aA.col1; +-- error 1443 +update t2Aa,v2aA set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; +-- error 1443 +update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v2aA) where t1Aa.col1 = t2aA.col1; +-- error 1443 +update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from v2Aa) where v1Aa.col1 = t2aA.col1; +-- error 1443 +update v3aA set v3Aa.col1 = (select max(col1) from v1aA); +-- error 1443 +update v3aA set v3Aa.col1 = (select max(col1) from t1aA); +-- error 1443 +update v3aA set v3Aa.col1 = (select max(col1) from v2aA); +-- error 1093 +update v3aA set v3Aa.col1 = (select max(col1) from v3aA); +-- error 1443 +delete from v2Aa where col1 = (select max(col1) from v1Aa); +-- error 1443 +delete from v2aA where col1 = (select max(col1) from t1Aa); +-- error 1093 +delete from v2Aa where col1 = (select max(col1) from v2aA); +-- error 1443 +delete v2Aa from v2aA,t2Aa where (select max(col1) from v1aA) > 0 and v2Aa.col1 = t2aA.col1; +-- error 1443 +delete t1aA from t1Aa,t2Aa where (select max(col1) from v1Aa) > 0 and t1aA.col1 = t2aA.col1; +-- error 1093 +delete v1aA from v1Aa,t2Aa where (select max(col1) from v1aA) > 0 and v1Aa.col1 = t2aA.col1; +-- error 1443 +delete v2aA from v2Aa,t2Aa where (select max(col1) from t1Aa) > 0 and v2aA.col1 = t2aA.col1; +-- error 1093 +delete t1aA from t1Aa,t2Aa where (select max(col1) from t1aA) > 0 and t1Aa.col1 = t2aA.col1; +-- error 1443 +delete v1aA from v1Aa,t2Aa where (select max(col1) from t1aA) > 0 and v1aA.col1 = t2aA.col1; +-- error 1093 +delete v2Aa from v2aA,t2Aa where (select max(col1) from v2Aa) > 0 and v2aA.col1 = t2aA.col1; +-- error 1443 +delete t1Aa from t1aA,t2Aa where (select max(col1) from v2Aa) > 0 and t1Aa.col1 = t2aA.col1; +-- error 1443 +delete v1Aa from v1aA,t2Aa where (select max(col1) from v2aA) > 0 and v1Aa.col1 = t2aA.col1; +-- error 1443 +insert into v2Aa values ((select max(col1) from v1aA)); +-- error 1443 +insert into t1aA values ((select max(col1) from v1Aa)); +-- error 1443 +insert into v2aA values ((select max(col1) from v1aA)); +-- error 1443 +insert into v2Aa values ((select max(col1) from t1Aa)); +-- error 1093 +insert into t1aA values ((select max(col1) from t1Aa)); +-- error 1443 +insert into v2aA values ((select max(col1) from t1aA)); +-- error 1093 +insert into v2Aa values ((select max(col1) from v2aA)); +-- error 1443 +insert into t1Aa values ((select max(col1) from v2Aa)); +-- error 1093 +insert into v2aA values ((select max(col1) from v2Aa)); +-- error 1443 +insert into v3Aa (col1) values ((select max(col1) from v1Aa)); +-- error 1443 +insert into v3aA (col1) values ((select max(col1) from t1aA)); +-- error 1443 +insert into v3Aa (col1) values ((select max(col1) from v2aA)); +drop view v3aA,v2Aa,v1aA; +drop table t1Aa,t2Aa; + +# +# aliases in VIEWs +# +create table t1Aa (col1 int); +create view v1Aa as select col1 from t1Aa as AaA; +show create view v1AA; +drop view v1AA; +select Aaa.col1 from t1Aa as AaA; +create view v1Aa as select Aaa.col1 from t1Aa as AaA; +drop view v1AA; +create view v1Aa as select AaA.col1 from t1Aa as AaA; +show create view v1AA; +drop view v1AA; +drop table t1Aa; + + +# +# Bug #31562: HAVING and lower case +# + +CREATE TABLE t1 (a int, b int); + +select X.a from t1 AS X group by X.b having (X.a = 1); +select X.a from t1 AS X group by X.b having (x.a = 1); +select X.a from t1 AS X group by X.b having (x.b = 1); + +CREATE OR REPLACE VIEW v1 AS +select X.a from t1 AS X group by X.b having (X.a = 1); + +SHOW CREATE VIEW v1; + +SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/t/metadata.test b/mysql-test/suite/pbxt/t/metadata.test new file mode 100644 index 00000000000..dac38e74371 --- /dev/null +++ b/mysql-test/suite/pbxt/t/metadata.test @@ -0,0 +1,86 @@ +# +# Test metadata +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +--enable_metadata +# PS protocol gives slightly different metadata +--disable_ps_protocol + +# +# First some simple tests +# + +select 1, 1.0, -1, "hello", NULL; + +create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp, l datetime, m enum('a','b'), n set('a','b'), o char(10)); +select * from t1; +select a b, b c from t1 as t2; +drop table t1; + +# +# Test metadata from ORDER BY (Bug #2654) +# + +CREATE TABLE t1 (id tinyint(3) default NULL, data varchar(255) default NULL); +INSERT INTO t1 VALUES (1,'male'),(2,'female'); +CREATE TABLE t2 (id tinyint(3) unsigned default NULL, data char(3) default '0'); +INSERT INTO t2 VALUES (1,'yes'),(2,'no'); + +select t1.id, t1.data, t2.data from t1, t2 where t1.id = t2.id; +select t1.id, t1.data, t2.data from t1, t2 where t1.id = t2.id order by t1.id; +select t1.id from t1 union select t2.id from t2; +drop table t1,t2; + +# +# variables union and derived tables metadata test +# +create table t1 ( a int, b varchar(30), primary key(a)); +insert into t1 values (1,'one'); +insert into t1 values (2,'two'); +set @arg00=1 ; +select @arg00 FROM t1 where a=1 union distinct select 1 FROM t1 where a=1; +select * from (select @arg00) aaa; +select 1 union select 1; +select * from (select 1 union select 1) aaa; +drop table t1; + +--disable_metadata + +# +# Bug #11688: Bad mysql_info() results in multi-results +# +--enable_info +delimiter //; +create table t1 (i int); +insert into t1 values (1),(2),(3); +select * from t1 where i = 2; +drop table t1;// +delimiter ;// +--disable_info + +# +# Bug #20191: getTableName gives wrong or inconsistent result when using VIEWs +# +--enable_metadata +create table t1 (id int(10)); +insert into t1 values (1); +CREATE VIEW v1 AS select t1.id as id from t1; +CREATE VIEW v2 AS select t1.id as renamed from t1; +CREATE VIEW v3 AS select t1.id + 12 as renamed from t1; +select * from v1 group by id limit 1; +select * from v1 group by id limit 0; +select * from v1 where id=1000 group by id; +select * from v1 where id=1 group by id; +select * from v2 where renamed=1 group by renamed; +select * from v3 where renamed=1 group by renamed; +drop table t1; +drop view v1,v2,v3; +--disable_metadata + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/multi_statement.test b/mysql-test/suite/pbxt/t/multi_statement.test new file mode 100644 index 00000000000..e024fa12c0f --- /dev/null +++ b/mysql-test/suite/pbxt/t/multi_statement.test @@ -0,0 +1,40 @@ +# PS doesn't support multi-statements +--disable_ps_protocol + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +select 1; +delimiter ||||; +select 2; +select 3; +select 4|||| +delimiter 'abcd'|||| +select 5; +select 6; +select 50, 'abc';'abcd' +select "abcd'";'abcd'select "'abcd";'abcd' +select 5'abcd' +delimiter ;'abcd' +select 'finish'; + +# Bug #8475: Make sure every statement that is a slow query in +# a multi-statement query gets logged as a slow query. +flush status; +delimiter ||||; +create table t1 (i int); +insert into t1 values (1); +select * from t1 where i = 1; +insert into t1 values (2),(3),(4); +select * from t1 where i = 2; +select * from t1 where i = 3|||| +show status like 'Slow_queries'|||| +drop table t1|||| + +delimiter ;|||| + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/multi_update.test b/mysql-test/suite/pbxt/t/multi_update.test new file mode 100644 index 00000000000..12e91c79f22 --- /dev/null +++ b/mysql-test/suite/pbxt/t/multi_update.test @@ -0,0 +1,579 @@ +# +# Test of update statement that uses many tables. +# + +# Requires grants, so won't work with embedded server test +-- source include/not_embedded.inc + +--disable_warnings +drop table if exists t1,t2,t3; +drop database if exists mysqltest; +drop view if exists v1; +--error 0,1141,1147 +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +--error 0,1141,1147 +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +delete from mysql.user where user=_binary'mysqltest_1'; +--enable_warnings + +create table t1(id1 int not null auto_increment primary key, t char(12)); +create table t2(id2 int not null, t char(12)); +create table t3(id3 int not null, t char(12), index(id3)); +disable_query_log; +let $1 = 100; +while ($1) + { + let $2 = 5; + eval insert into t1(t) values ('$1'); + while ($2) + { + eval insert into t2(id2,t) values ($1,'$2'); + let $3 = 10; + while ($3) + { + eval insert into t3(id3,t) values ($1,'$2'); + dec $3; + } + dec $2; + } + dec $1; + } +enable_query_log; + +select count(*) from t1 where id1 > 95; +select count(*) from t2 where id2 > 95; +select count(*) from t3 where id3 > 95; + +update t1,t2,t3 set t1.t="aaa", t2.t="bbb", t3.t="cc" where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 90; +select count(*) from t1 where t = "aaa"; +select count(*) from t1 where id1 > 90; +select count(*) from t2 where t = "bbb"; +select count(*) from t2 where id2 > 90; +select count(*) from t3 where t = "cc"; +select count(*) from t3 where id3 > 90; +delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 95; + +check table t1, t2, t3; + +select count(*) from t1 where id1 > 95; +select count(*) from t2 where id2 > 95; +select count(*) from t3 where id3 > 95; + +delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 5; +select count(*) from t1 where id1 > 5; +select count(*) from t2 where id2 > 5; +select count(*) from t3 where id3 > 5; + +delete from t1, t2, t3 using t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0; + +# These queries will force a scan of the table +select count(*) from t1 where id1; +select count(*) from t2 where id2; +select count(*) from t3 where id3; +drop table t1,t2,t3; + +create table t1(id1 int not null primary key, t varchar(100)) pack_keys = 1; +create table t2(id2 int not null, t varchar(100), index(id2)) pack_keys = 1; +disable_query_log; +let $1 = 1000; +while ($1) + { + let $2 = 5; + eval insert into t1 values ($1,'aaaaaaaaaaaaaaaaaaaa'); + while ($2) + { + eval insert into t2(id2,t) values ($1,'bbbbbbbbbbbbbbbbb'); + dec $2; + } + dec $1; + } +enable_query_log; +delete t1 from t1,t2 where t1.id1 = t2.id2 and t1.id1 > 500; +drop table t1,t2; + +CREATE TABLE t1 ( + id int(11) NOT NULL default '0', + name varchar(10) default NULL, + PRIMARY KEY (id) +) ENGINE=PBXT; # PBXT : Instead of MyISAM +INSERT INTO t1 VALUES (1,'aaa'),(2,'aaa'),(3,'aaa'); +CREATE TABLE t2 ( + id int(11) NOT NULL default '0', + name varchar(10) default NULL, + PRIMARY KEY (id) +) ENGINE=PBXT; # PBXT : Instead of MyISAM +INSERT INTO t2 VALUES (2,'bbb'),(3,'bbb'),(4,'bbb'); +CREATE TABLE t3 ( + id int(11) NOT NULL default '0', + mydate datetime default NULL, + PRIMARY KEY (id) +) ENGINE=PBXT; # PBXT : Instead of MyISAM +INSERT INTO t3 VALUES (1,'2002-02-04 00:00:00'),(3,'2002-05-12 00:00:00'),(5,'2002-05-12 00:00:00'),(6,'2002-06-22 +00:00:00'),(7,'2002-07-22 00:00:00'); +delete t1,t2,t3 from t1,t2,t3 where to_days(now())-to_days(t3.mydate)>=30 and t3.id=t1.id and t3.id=t2.id; +select * from t3; +DROP TABLE t1,t2,t3; + +CREATE TABLE IF NOT EXISTS `t1` ( + `id` int(11) NOT NULL auto_increment, + `tst` text, + `tst1` text, + PRIMARY KEY (`id`) +) ENGINE=PBXT; # PBXT : Instead of MyISAM + +CREATE TABLE IF NOT EXISTS `t2` ( + `ID` int(11) NOT NULL auto_increment, + `ParId` int(11) default NULL, + `tst` text, + `tst1` text, + PRIMARY KEY (`ID`), + KEY `IX_ParId_t2` (`ParId`), + FOREIGN KEY (`ParId`) REFERENCES `t1` (`id`) +) ENGINE=PBXT; # PBXT : Instead of MyISAM + +INSERT INTO t1(tst,tst1) VALUES("MySQL","MySQL AB"), ("MSSQL","Microsoft"), ("ORACLE","ORACLE"); + +INSERT INTO t2(ParId) VALUES(1), (2), (3); + +select * from t2; + +UPDATE t2, t1 SET t2.tst = t1.tst, t2.tst1 = t1.tst1 WHERE t2.ParId = t1.Id; + +select * from t2; +drop table t2, t1 ; + +create table t1 (n numeric(10)); +create table t2 (n numeric(10)); +insert into t2 values (1),(2),(4),(8),(16),(32); +select * from t2 left outer join t1 using (n); +delete t1,t2 from t2 left outer join t1 using (n); +select * from t2 left outer join t1 using (n); +drop table t1,t2 ; + +# +# Test with locking +# + +create table t1 (n int(10) not null primary key, d int(10)); +create table t2 (n int(10) not null primary key, d int(10)); +insert into t1 values(1,1); +insert into t2 values(1,10),(2,20); +LOCK TABLES t1 write, t2 read; +--error 1099 +DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n; +--error 1099 +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +unlock tables; +LOCK TABLES t1 write, t2 write; +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +select * from t1; +DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n; +select * from t1; +select * from t2; +unlock tables; +drop table t1,t2; + +# +# Test safe updates and timestamps +# +set sql_safe_updates=1; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1); +insert into t2 values(1,10),(2,20); +--error 1175 +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +set sql_safe_updates=0; +drop table t1,t2; +set timestamp=1038401397; +create table t1 (n int(10) not null primary key, d int(10), t timestamp); +create table t2 (n int(10) not null primary key, d int(10), t timestamp); +insert into t1 values(1,1,NULL); +insert into t2 values(1,10,NULL),(2,20,NULL); +set timestamp=1038000000; +UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; +select n,d,unix_timestamp(t) from t1; +select n,d,unix_timestamp(t) from t2; +--error 1064 +UPDATE t1,t2 SET 1=2 WHERE t1.n=t2.n; +drop table t1,t2; +set timestamp=0; +set sql_safe_updates=0; +create table t1 (n int(10) not null primary key, d int(10)); +create table t2 (n int(10) not null primary key, d int(10)); +insert into t1 values(1,1), (3,3); +insert into t2 values(1,10),(2,20); +UPDATE t2 left outer join t1 on t1.n=t2.n SET t1.d=t2.d; +select * from t1 order by n; # PBXT required ORDER for consistant result +select * from t2 order by n; # PBXT required ORDER for consistant result +drop table t1,t2; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1),(1,2); +insert into t2 values(1,10),(2,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1 order by n; # PBXT required ORDER for consistant result +select * from t2 order by n; # PBXT required ORDER for consistant result +drop table t1,t2; +create table t1 (n int(10), d int(10)); +create table t2 (n int(10), d int(10)); +insert into t1 values(1,1),(3,2); +insert into t2 values(1,10),(1,20); +UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; +select * from t1 order by n; # PBXT required ORDER for consistant result +select * from t2 order by n; # PBXT required ORDER for consistant result +UPDATE t1 a ,t2 b SET a.d=b.d,b.d=30 WHERE a.n=b.n; +select * from t1 order by n; # PBXT required ORDER for consistant result +select * from t2 order by n; # PBXT required ORDER for consistant result +DELETE a, b FROM t1 a,t2 b where a.n=b.n; +select * from t1 order by n; # PBXT required ORDER for consistant result +select * from t2 order by n; # PBXT required ORDER for consistant result +drop table t1,t2; + +CREATE TABLE t1 ( broj int(4) unsigned NOT NULL default '0', naziv char(25) NOT NULL default 'NEPOZNAT', PRIMARY KEY (broj)) ENGINE=PBXT; # PBXT : Instead of MyISAM +INSERT INTO t1 VALUES (1,'jedan'),(2,'dva'),(3,'tri'),(4,'xxxxxxxxxx'),(5,'a'),(10,''),(11,''),(12,''),(13,''); +CREATE TABLE t2 ( broj int(4) unsigned NOT NULL default '0', naziv char(25) NOT NULL default 'NEPOZNAT', PRIMARY KEY (broj)) ENGINE=PBXT; # PBXT : Instead of MyISAM +INSERT INTO t2 VALUES (1,'jedan'),(2,'dva'),(3,'tri'),(4,'xxxxxxxxxx'),(5,'a'); +CREATE TABLE t3 ( broj int(4) unsigned NOT NULL default '0', naziv char(25) NOT NULL default 'NEPOZNAT', PRIMARY KEY (broj)) ENGINE=PBXT; # PBXT : Instead of MyISAM +INSERT INTO t3 VALUES (1,'jedan'),(2,'dva'); +update t1,t2 set t1.naziv="aaaa" where t1.broj=t2.broj; +update t1,t2,t3 set t1.naziv="bbbb", t2.naziv="aaaa" where t1.broj=t2.broj and t2.broj=t3.broj; +drop table t1,t2,t3; + +# +# Test multi update with different join methods +# + +CREATE TABLE t1 (a int not null primary key, b int not null, key (b)); +CREATE TABLE t2 (a int not null primary key, b int not null, key (b)); +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); +INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); + +# Full join, without key +update t1,t2 set t1.a=t1.a+100; +select * from t1 order by a; # PBXT required ORDER for consistant result + +# unique key +update t1,t2 set t1.a=t1.a+100 where t1.a=101; +select * from t1 order by a; # PBXT required ORDER for consistant result + +# ref key +update t1,t2 set t1.b=t1.b+10 where t1.b=2; +select * from t1 order by a; # PBXT required ORDER for consistant result + +# Range key (in t1) +update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t2.a=t1.a-100; +select * from t1 order by a; # PBXT required ORDER for consistant result +select * from t2 order by a; # PBXT required ORDER for consistant result + +# test for non-updating table which is also used in sub-select + +update t1,t2 set t1.b=t2.b, t1.a=t2.a where t1.a=t2.a and not exists (select * from t2 where t2.a > 10); + +drop table t1,t2; +CREATE TABLE t3 ( KEY1 varchar(50) NOT NULL default '', PARAM_CORR_DISTANCE_RUSH double default NULL, PARAM_CORR_DISTANCE_GEM double default NULL, PARAM_AVG_TARE double default NULL, PARAM_AVG_NB_DAYS double default NULL, PARAM_DEFAULT_PROP_GEM_SRVC varchar(50) default NULL, PARAM_DEFAULT_PROP_GEM_NO_ETIK varchar(50) default NULL, PARAM_SCENARIO_COSTS varchar(50) default NULL, PARAM_DEFAULT_WAGON_COST double default NULL, tmp int(11) default NULL, PRIMARY KEY (KEY1)) ENGINE=PBXT; # PBXT : Instead of MyISAM +INSERT INTO t3 VALUES ('A',1,1,22,3.2,'R','R','BASE2',0.24,NULL); +create table t1 (A varchar(1)); +insert into t1 values ("A") ,("B"),("C"),("D"); +create table t2(Z varchar(15)); +insert into t2(Z) select concat(a.a,b.a,c.a,d.a) from t1 as a, t1 as b, t1 as c, t1 as d; +update t2,t3 set Z =param_scenario_costs; +drop table t1,t2,t3; +create table t1 (a int, b int); +create table t2 (a int, b int); +insert into t1 values (1,1),(2,1),(3,1); +insert into t2 values (1,1), (3,1); +update t1 left join t2 on t1.a=t2.a set t1.b=2, t2.b=2 where t1.b=1 and t2.b=1 or t2.a is NULL; +select t1.a, t1.b,t2.a, t2.b from t1 left join t2 on t1.a=t2.a where t1.b=1 and t2.b=1 or t2.a is NULL; +drop table t1,t2; + +# +# Test reuse of same table +# + +create table t1 (a int not null auto_increment primary key, b int not null); +insert into t1 (b) values (1),(2),(3),(4); +update t1, t1 as t2 set t1.b=t2.b+1 where t1.a=t2.a; +select * from t1; +drop table t1; + +# Test multi-update and multi-delete with impossible where + +create table t1(id1 smallint(5), field char(5)); +create table t2(id2 smallint(5), field char(5)); + +insert into t1 values (1, 'a'), (2, 'aa'); +insert into t2 values (1, 'b'), (2, 'bb'); + +select * from t1; +select * from t2; + +update t2 inner join t1 on t1.id1=t2.id2 + set t2.field=t1.field + where 0=1; +update t2, t1 set t2.field=t1.field + where t1.id1=t2.id2 and 0=1; + +delete t1, t2 from t2 inner join t1 on t1.id1=t2.id2 + where 0=1; +delete t1, t2 from t2,t1 + where t1.id1=t2.id2 and 0=1; + +drop table t1,t2; + +# +# Test for bug #1820. +# + +create table t1 ( a int not null, b int not null) ; +--disable_query_log +insert into t1 values (1,1),(2,2),(3,3),(4,4); +let $1=19; +set @d=4; +while ($1) +{ + eval insert into t1 select a+@d,b+@d from t1; + eval set @d=@d*2; + dec $1; +} + +--enable_query_log +alter table t1 add index i1(a); +delete from t1 where a > 2000000; +create table t2 like t1; +insert into t2 select * from t1; + +analyze table t2; # PBXT: This statements waits so that count(*) is accurate! +select 't2 rows before small delete', count(*) from t1; +delete t1,t2 from t1,t2 where t1.b=t2.a and t1.a < 2; +analyze table t2; # PBXT: This statements waits so that count(*) is accurate! +select 't2 rows after small delete', count(*) from t2; +select 't1 rows after small delete', count(*) from t1; + +## Try deleting many rows + +delete t1,t2 from t1,t2 where t1.b=t2.a and t1.a < 100*1000; +analyze table t2; # PBXT: This statements waits so that count(*) is accurate! +select 't2 rows after big delete', count(*) from t2; +select 't1 rows after big delete', count(*) from t1; + +drop table t1,t2; + +# +# Test alias (this is not correct in 4.0) +# + +CREATE TABLE t1 ( a int ); +CREATE TABLE t2 ( a int ); +DELETE t1 FROM t1, t2 AS t3; +DELETE t4 FROM t1, t1 AS t4; +DELETE t3 FROM t1 AS t3, t1 AS t4; +--error 1109 +DELETE t1 FROM t1 AS t3, t2 AS t4; +INSERT INTO t1 values (1),(2); +INSERT INTO t2 values (1),(2); +DELETE t1 FROM t1 AS t2, t2 AS t1 where t1.a=t2.a and t1.a=1; +SELECT * from t1; +SELECT * from t2; +DELETE t2 FROM t1 AS t2, t2 AS t1 where t1.a=t2.a and t1.a=2; +SELECT * from t1; +SELECT * from t2; +DROP TABLE t1,t2; + +# +# Test update with const tables +# +create table `t1` (`p_id` int(10) unsigned NOT NULL auto_increment, `p_code` varchar(20) NOT NULL default '', `p_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`p_id`) ); +create table `t2` (`c2_id` int(10) unsigned NULL auto_increment, `c2_p_id` int(10) unsigned NOT NULL default '0', `c2_note` text NOT NULL, `c2_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`c2_id`), KEY `c2_p_id` (`c2_p_id`) ); +insert into t1 values (0,'A01-Comp',1); +insert into t1 values (0,'B01-Comp',1); +insert into t2 values (0,1,'A Note',1); +update t1 left join t2 on p_id = c2_p_id set c2_note = 'asdf-1' where p_id = 2; +select * from t1; +select * from t2; +drop table t1, t2; + +# +# privilege check for multiupdate with other tables +# + +connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings +create table mysqltest.t1 (a int, b int, primary key (a)); +create table mysqltest.t2 (a int, b int, primary key (a)); +create table mysqltest.t3 (a int, b int, primary key (a)); +grant select on mysqltest.* to mysqltest_1@localhost; +grant update on mysqltest.t1 to mysqltest_1@localhost; +connect (user1,localhost,mysqltest_1,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK); +connection user1; +update t1, t2 set t1.b=1 where t1.a=t2.a; +update t1, t2 set t1.b=(select t3.b from t3 where t1.a=t3.a) where t1.a=t2.a; +connection root; +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +delete from mysql.user where user=_binary'mysqltest_1'; +drop database mysqltest; + +# +# multi delete wrong table check +# +create table t1 (a int, primary key (a)); +create table t2 (a int, primary key (a)); +create table t3 (a int, primary key (a)); +-- error 1109 +delete t1,t3 from t1,t2 where t1.a=t2.a and t2.a=(select t3.a from t3 where t1.a=t3.a); +drop table t1, t2, t3; + +# +# multi* unique updating table check +# +create table t1 (col1 int); +create table t2 (col1 int); +-- error 1093 +update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; +-- error 1093 +delete t1 from t1,t2 where t1.col1 < (select max(col1) from t1) and t1.col1 = t2.col1; +drop table t1,t2; + +# Test for BUG#5837 - delete with outer join and const tables +--disable_warnings +create table t1 ( + aclid bigint not null primary key, + status tinyint(1) not null +); + +create table t2 ( + refid bigint not null primary key, + aclid bigint, index idx_acl(aclid) +); +--enable_warnings +insert into t2 values(1,null); +delete t2, t1 from t2 left join t1 on (t2.aclid=t1.aclid) where t2.refid='1'; +drop table t1, t2; + +# +# Bug#19225: unchecked error leads to server crash +# +create table t1(a int); +create table t2(a int); +--error 1093 +delete from t1,t2 using t1,t2 where t1.a=(select a from t1); +drop table t1, t2; +# End of 4.1 tests + +# +# Test for bug #1980. +# +--disable_warnings +create table t1 ( c char(8) not null ) engine=pbxt; # PBXT: Instead of InnoDB +--enable_warnings + +insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); +insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); + +alter table t1 add b char(8) not null; +alter table t1 add a char(8) not null; +alter table t1 add primary key (a,b,c); +update t1 set a=c, b=c; + +create table t2 like t1; +insert into t2 select * from t1; + +delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; + +drop table t1,t2; + +--disable_warnings +create table t1 ( c char(8) not null ) engine=pbxt; # PBXT: Instead of InnoDB +--enable_warnings + +insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); +insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); + +alter table t1 add b char(8) not null; +alter table t1 add a char(8) not null; +alter table t1 add primary key (a,b,c); +update t1 set a=c, b=c; + +create table t2 like t1; +insert into t2 select * from t1; + +delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; + +drop table t1,t2; + +# +# Test alter table and a concurrent multi update +# (This will force update to reopen tables) +# + +create table t1 (a int, b int); +insert into t1 values (1, 2), (2, 3), (3, 4); +create table t2 (a int); +insert into t2 values (10), (20), (30); +create view v1 as select a as b, a/10 as a from t2; + +connect (locker,localhost,root,,test); +connection locker; +lock table t1 write; + +connect (changer,localhost,root,,test); +connection changer; +send alter table t1 add column c int default 100 after a; + +connect (updater,localhost,root,,test); +connection updater; +sleep 2; +send update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a; + +connection locker; +sleep 2; +unlock tables; + +connection changer; +reap; + +connection updater; +reap; +select * from t1; +select * from t2; +drop view v1; +drop table t1, t2; + +# +# Test multi updates and deletes using primary key and without. +# +create table t1 (i1 int, i2 int, i3 int); +create table t2 (id int, c1 varchar(20), c2 varchar(20)); +insert into t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2); +insert into t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test"); +select * from t1 order by i1; +select * from t2; +update t1,t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id; +select * from t1 order by i1; +select * from t2 order by id; +delete t1.*,t2.* from t1,t2 where t1.i2=t2.id; +select * from t1 order by i1; +select * from t2 order by id; +drop table t1, t2; +create table t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)); +create table t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)); +insert into t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2); +insert into t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test"); +select * from t1 order by i1; +select * from t2 order by id; +update t1,t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id; +select * from t1 order by i1; +select * from t2 order by id; +delete t1.*,t2.* from t1,t2 where t1.i2=t2.id; +select * from t1 order by i1; +select * from t2 order by id; +drop table t1, t2; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/mysql_protocols.test b/mysql-test/suite/pbxt/t/mysql_protocols.test new file mode 100644 index 00000000000..5eba780420c --- /dev/null +++ b/mysql-test/suite/pbxt/t/mysql_protocols.test @@ -0,0 +1,15 @@ +# Embedded server doesn't support external clients +--source include/not_embedded.inc +# Windows does not have SOCKET, but will try to create a PIPE as well as MEMORY +--source include/not_windows.inc + +# test for Bug #4998 "--protocol doesn't reject bad values" + +--exec echo "select ' ok' as '<default>'" | $MYSQL +--exec echo "select ' ok' as 'TCP'" | $MYSQL --protocol=TCP +--exec echo "select ' ok' as 'SOCKET'" | $MYSQL --protocol=SOCKET +--exec echo "select ' ok' as 'PIPE'" | $MYSQL --protocol=PIPE 2>&1 || true +--exec echo "select ' ok' as 'MEMORY'" | $MYSQL --protocol=MEMORY 2>&1 || true +--exec echo "select ' ok' as 'NullS'" | $MYSQL --protocol=NullS 2>&1 || true + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/mysqlshow.test b/mysql-test/suite/pbxt/t/mysqlshow.test new file mode 100644 index 00000000000..d8f5c20afcd --- /dev/null +++ b/mysql-test/suite/pbxt/t/mysqlshow.test @@ -0,0 +1,39 @@ +# Can't run test of external client with embedded server +-- source include/not_embedded.inc + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,test1,test2; +--enable_warnings + +# +## Bug #5036 mysqlshow is missing a column +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1),(2),(3); +CREATE TABLE t2 (a int, b int); +show tables; +select "--------------------" as ""; +--exec $MYSQL_SHOW test +select "---- -v ------------" as ""; +--exec $MYSQL_SHOW test -v +select "---- -v -v ---------" as ""; +--exec $MYSQL_SHOW test -v -v +select "----- -t -----------" as ""; +--exec $MYSQL_SHOW test -t +select "---- -v -t ---------" as ""; +--exec $MYSQL_SHOW test -v -t +select "---- -v -v -t ------" as ""; +--exec $MYSQL_SHOW test -v -v -t +DROP TABLE t1, t2; + +# +# Bug #19147: mysqlshow INFORMATION_SCHEMA does not work +# +--exec $MYSQL_SHOW information_schema +--exec $MYSQL_SHOW INFORMATION_SCHEMA +--exec $MYSQL_SHOW inf_rmation_schema + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/mysqlslap.test b/mysql-test/suite/pbxt/t/mysqlslap.test new file mode 100644 index 00000000000..55dca40e190 --- /dev/null +++ b/mysql-test/suite/pbxt/t/mysqlslap.test @@ -0,0 +1,44 @@ +# Can't run test of external client with embedded server +--source include/not_embedded.inc +--source include/not_windows.inc + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql + +--exec $MYSQL_SLAP --only-print --iterations=20 --query="select * from t1" --create="CREATE TABLE t1 (id int, name varchar(64)); INSERT INTO t1 VALUES (1, 'This is a test')" --delimiter=";" +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --query="select * from t1" --create="CREATE TABLE t1 (id int, name varchar(64)); INSERT INTO t1 VALUES (1, 'This is a test')" --delimiter=";" + +--exec $MYSQL_SLAP --only-print --delimiter=";" --query="select * from t1;select * from t2" --create="CREATE TABLE t1 (id int, name varchar(64)); create table t2(foo1 varchar(32), foo2 varchar(32)); INSERT INTO t1 VALUES (1, 'This is a test'); insert into t2 values ('test', 'test2')" --engine="heap,myisam" + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --delimiter=";" --query="select * from t1;select * from t2" --create="CREATE TABLE t1 (id int, name varchar(64)); create table t2(foo1 varchar(32), foo2 varchar(32)); INSERT INTO t1 VALUES (1, 'This is a test'); insert into t2 values ('test', 'test2')" + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --create-schema=test_env + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --create-schema=test_env --auto-generate-sql-add-autoincrement + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=update + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=read + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=write + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=mixed + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=update + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=update --auto-generate-sql-execute-number=5 + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=key --auto-generate-sql-execute-number=5 + +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=key --auto-generate-sql-execute-number=5 --auto-generate-sql-secondary-indexes=3 + +--exec $MYSQL_SLAP --only-print --delimiter=";" --query="select * from t1;select * from t2" --create="CREATE TABLE t1 (id int, name varchar(64)); create table t2(foo1 varchar(32), foo2 varchar(32)); INSERT INTO t1 VALUES (1, 'This is a test'); insert into t2 values ('test', 'test2')" --engine="heap,myisam" --post-query="SHOW TABLES" --pre-query="SHOW TABLES"; + + --exec $MYSQL_SLAP --only-print --delimiter=";" --query="select * from t1;select * from t2" --create="CREATE TABLE t1 (id int, name varchar(64)); create table t2(foo1 varchar(32), foo2 varchar(32)); INSERT INTO t1 VALUES (1, 'This is a test'); insert into t2 values ('test', 'test2')" --engine="heap,myisam" --post-query="SHOW TABLES" --pre-query="SHOW TABLES" --number-of-queries=6 --commit=1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/negation_elimination.test b/mysql-test/suite/pbxt/t/negation_elimination.test new file mode 100644 index 00000000000..9bc2cef75a9 --- /dev/null +++ b/mysql-test/suite/pbxt/t/negation_elimination.test @@ -0,0 +1,78 @@ +# +# Test negation elimination +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int, key (a)); +insert into t1 values (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(10), (11), (12), (13), (14), (15), (16), (17), (18), (19); + +explain select * from t1 where not(not(a)); +select * from t1 where not(not(a)); +explain select * from t1 where not(not(not(a > 10))); +select * from t1 where not(not(not(a > 10))); +explain select * from t1 where not(not(not(a < 5) and not(a > 10))); +select * from t1 where not(not(not(a < 5) and not(a > 10))); +explain select * from t1 where not(a = 10); +select * from t1 where not(a = 10); +explain select * from t1 where not(a != 10); +select * from t1 where not(a != 1); +explain select * from t1 where not(a < 10); +select * from t1 where not(a < 10); +explain select * from t1 where not(a >= 10); +select * from t1 where not(a >= 10); +explain select * from t1 where not(a > 10); +select * from t1 where not(a > 10); +explain select * from t1 where not(a <= 10); +select * from t1 where not(a <= 10); +explain select * from t1 where not(a is null); +select * from t1 where not(a is null); +explain select * from t1 where not(a is not null); +select * from t1 where not(a is not null); +explain select * from t1 where not(a < 5 or a > 15); +select * from t1 where not(a < 5 or a > 15); +explain select * from t1 where not(a < 15 and a > 5); +select * from t1 where not(a < 15 and a > 5); + +explain select * from t1 where a = 2 or not(a < 10); +select * from t1 where a = 2 or not(a < 10); +explain select * from t1 where a > 5 and not(a > 10); +select * from t1 where a > 5 and not(a > 10); +explain select * from t1 where a > 5 xor a < 10; +select * from t1 where a > 5 xor a < 10; + +explain select * from t1 where a = 2 or not(a < 5 or a > 15); +select * from t1 where a = 2 or not(a < 5 or a > 15); +explain select * from t1 where a = 7 or not(a < 15 and a > 5); +select * from t1 where a = 7 or not(a < 15 and a > 5); + +explain select * from t1 where NULL or not(a < 15 and a > 5); +select * from t1 where NULL or not(a < 15 and a > 5); +explain select * from t1 where not(NULL and a > 5); +select * from t1 where not(NULL and a > 5); +explain select * from t1 where not(NULL or a); +select * from t1 where not(NULL or a); +explain select * from t1 where not(NULL and a); +select * from t1 where not(NULL and a); + +explain select * from t1 where not((a < 5 or a < 10) and (not(a > 16) or a > 17)); +select * from t1 where not((a < 5 or a < 10) and (not(a > 16) or a > 17)); +explain select * from t1 where not((a < 5 and a < 10) and (not(a > 16) or a > 17)); +select * from t1 where not((a < 5 and a < 10) and (not(a > 16) or a > 17)); +explain select * from t1 where ((a between 5 and 15) and (not(a like 10))); +select * from t1 where ((a between 5 and 15) and (not(a like 10))); + +delete from t1 where a > 3; +select a, not(not(a)) from t1; +analyze table t1; # PBXT: Required for consistent explain result +explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "1"), not (a not in (1,2)), not(a != 2) from t1 where not(not(a)) having not(not(a)); + +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/null.test b/mysql-test/suite/pbxt/t/null.test new file mode 100644 index 00000000000..a52e9d85b6c --- /dev/null +++ b/mysql-test/suite/pbxt/t/null.test @@ -0,0 +1,241 @@ +# Initialise +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + +# +# Testing of NULL in a lot of different places +# + +select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null; +explain extended select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null; +select 1 | NULL,1 & NULL,1+NULL,1-NULL; +select NULL=NULL,NULL<>NULL,IFNULL(NULL,1.1)+0,IFNULL(NULL,1) | 0; +select strcmp("a",NULL),(1<NULL)+0.0,NULL regexp "a",null like "a%","a%" like null; +select concat("a",NULL),replace(NULL,"a","b"),replace("string","i",NULL),replace("string",NULL,"i"),insert("abc",1,1,NULL),left(NULL,1); +select repeat("a",0),repeat("ab",5+5),repeat("ab",-1),reverse(NULL); +select field(NULL,"a","b","c"); +select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null; +explain extended select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null; +SELECT NULL AND NULL, 1 AND NULL, NULL AND 1, NULL OR NULL, 0 OR NULL, NULL OR 0; +SELECT (NULL OR NULL) IS NULL; +select NULL AND 0, 0 and NULL; +select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton(""); +explain extended select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton(""); + +create table t1 (x int); +insert into t1 values (null); +select * from t1 where x != 0; +drop table t1; + +# +# Test problem med index on NULL columns and testing with =NULL; +# + +CREATE TABLE t1 ( + indexed_field int default NULL, + KEY indexed_field (indexed_field) +); +INSERT INTO t1 VALUES (NULL),(NULL); +SELECT * FROM t1 WHERE indexed_field=NULL; +SELECT * FROM t1 WHERE indexed_field IS NULL; +SELECT * FROM t1 WHERE indexed_field<=>NULL; +DROP TABLE t1; + +# +# Testing of IFNULL +# +create table t1 (a int, b int) engine=myisam; +insert into t1 values(20,null); +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a; +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a order by 1; +insert into t1 values(10,null); +select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on +t2.b=t3.a order by 1; +drop table t1; + +# +# Test inserting and updating with NULL +# +CREATE TABLE t1 (a varchar(16) NOT NULL default '', b smallint(6) NOT NULL default 0, c datetime NOT NULL default '0000-00-00 00:00:00', d smallint(6) NOT NULL default 0); +INSERT INTO t1 SET a = "", d= "2003-01-14 03:54:55"; +--error 1048 +UPDATE t1 SET d=1/NULL; +--error 1048 +UPDATE t1 SET d=NULL; +--error 1048 +INSERT INTO t1 (a) values (null); +--error 1048 +INSERT INTO t1 (a) values (1/null); +INSERT INTO t1 (a) values (null),(null); +--error 1048 +INSERT INTO t1 (b) values (null); +--error 1048 +INSERT INTO t1 (b) values (1/null); +INSERT INTO t1 (b) values (null),(null); +--error 1048 +INSERT INTO t1 (c) values (null); +--error 1048 +INSERT INTO t1 (c) values (1/null); +INSERT INTO t1 (c) values (null),(null); +--error 1048 +INSERT INTO t1 (d) values (null); +--error 1048 +INSERT INTO t1 (d) values (1/null); +INSERT INTO t1 (d) values (null),(null); +select * from t1; +drop table t1; + +# +# Test to check elimination of IS NULL predicate for a non-nullable attribute +# (bug #1990) +# +create table t1 (a int not null, b int not null, index idx(a)); +insert into t1 values + (1,1), (2,2), (3,3), (4,4), (5,5), (6,6), + (7,7), (8,8), (9,9), (10,10), (11,11), (12,12); +explain select * from t1 where a between 2 and 3; +explain select * from t1 where a between 2 and 3 or b is null; +drop table t1; +select cast(NULL as signed); + +# +# IS NULL is unable to use index in range if column is declared not null +# (Bug #4256) +# +create table t1(i int, key(i)); +insert into t1 values(1); +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 select i*2 from t1; +insert into t1 values(null); +# PBXT: Row estimate non-determonistic (TODO: Why?) +--replace_column 9 # +explain select * from t1 where i=2 or i is null; +select count(*) from t1 where i=2 or i is null; +alter table t1 change i i int not null; +explain select * from t1 where i=2 or i is null; +select count(*) from t1 where i=2 or i is null; +drop table t1; + +# +# NULL has its own type BINARY(0) by default. +# But NULL should be weaker than a constant +# when mixing charsets/collations +# +set names latin2; +# Check that result type is taken from a non-null string +create table t1 select + null as c00, + if(1, null, 'string') as c01, + if(0, null, 'string') as c02, + ifnull(null, 'string') as c03, + ifnull('string', null) as c04, + case when 0 then null else 'string' end as c05, + case when 1 then null else 'string' end as c06, + coalesce(null, 'string') as c07, + coalesce('string', null) as c08, + least('string',null) as c09, + least(null, 'string') as c10, + greatest('string',null) as c11, + greatest(null, 'string') as c12, + nullif('string', null) as c13, + nullif(null, 'string') as c14, + trim('string' from null) as c15, + trim(null from 'string') as c16, + substring_index('string', null, 1) as c17, + substring_index(null, 'string', 1) as c18, + elt(1, null, 'string') as c19, + elt(1, 'string', null) as c20, + concat('string', null) as c21, + concat(null, 'string') as c22, + concat_ws('sep', 'string', null) as c23, + concat_ws('sep', null, 'string') as c24, + concat_ws(null, 'string', 'string') as c25, + make_set(3, 'string', null) as c26, + make_set(3, null, 'string') as c27, + export_set(3, null, 'off', 'sep') as c29, + export_set(3, 'on', null, 'sep') as c30, + export_set(3, 'on', 'off', null) as c31, + replace(null, 'from', 'to') as c32, + replace('str', null, 'to') as c33, + replace('str', 'from', null) as c34, + insert('str', 1, 2, null) as c35, + insert(null, 1, 2, 'str') as c36, + lpad('str', 10, null) as c37, + rpad(null, 10, 'str') as c38; + +show create table t1; +drop table t1; + +# +# Check that comparison is done according to +# non-null string collation, i.e. case insensitively, +# rather than according to NULL's collation, i.e. case sensitively +# +# in field +select + case 'str' when 'STR' then 'str' when null then 'null' end as c01, + case 'str' when null then 'null' when 'STR' then 'str' end as c02, + field(null, 'str1', 'str2') as c03, + field('str1','STR1', null) as c04, + field('str1', null, 'STR1') as c05, + 'string' in ('STRING', null) as c08, + 'string' in (null, 'STRING') as c09; + +# Restore charset to the default value. +set names latin1; + +# +# Bug#19145: mysqld crashes if you set the default value of an enum field to NULL +# +create table bug19145a (e enum('a','b','c') default 'b' , s set('x', 'y', 'z') default 'y' ) engine=MyISAM; +create table bug19145b (e enum('a','b','c') default null, s set('x', 'y', 'z') default null) engine=MyISAM; + +create table bug19145c (e enum('a','b','c') not null default 'b' , s set('x', 'y', 'z') not null default 'y' ) engine=MyISAM; + +# Invalid default value for 's' +--error 1067 +create table bug19145setnotnulldefaultnull (e enum('a','b','c') default null, s set('x', 'y', 'z') not null default null) engine=MyISAM; + +# Invalid default value for 'e' +--error 1067 +create table bug19145enumnotnulldefaultnull (e enum('a','b','c') not null default null, s set('x', 'y', 'z') default null) engine=MyISAM; + +alter table bug19145a alter column e set default null; +alter table bug19145a alter column s set default null; +alter table bug19145a add column (i int); + +alter table bug19145b alter column e set default null; +alter table bug19145b alter column s set default null; +alter table bug19145b add column (i int); + +# Invalid default value for 'e' +--error 1067 +alter table bug19145c alter column e set default null; + +# Invalid default value for 's' +--error 1067 +alter table bug19145c alter column s set default null; +alter table bug19145c add column (i int); + +show create table bug19145a; +show create table bug19145b; +show create table bug19145c; + +drop table bug19145a; +drop table bug19145b; +drop table bug19145c; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/null_key.test b/mysql-test/suite/pbxt/t/null_key.test new file mode 100644 index 00000000000..1fbe21b3b5b --- /dev/null +++ b/mysql-test/suite/pbxt/t/null_key.test @@ -0,0 +1,245 @@ +# +# Check null keys + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1 (a int, b int not null,unique key (a,b),index(b)) engine=myisam; +insert ignore into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(null,7),(9,9),(8,8),(7,7),(null,9),(null,9),(6,6); +explain select * from t1 where a is null; +explain select * from t1 where a is null and b = 2; +explain select * from t1 where a is null and b = 7; +explain select * from t1 where a=2 and b = 2; +explain select * from t1 where a<=>b limit 2; +explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3; +explain select * from t1 where (a is null or a = 7) and b=7; +explain select * from t1 where (a is null or a = 7) and b=7 order by a; +explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2; +explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +explain select * from t1 where a > 1 and a < 3 limit 1; +explain select * from t1 where a > 8 and a < 9; +select * from t1 where a is null; +select * from t1 where a is null and b = 7; +select * from t1 where a<=>b limit 2; +select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3; +select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3; +select * from t1 where (a is null or a = 7) and b=7; +select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +select * from t1 where a > 1 and a < 3 limit 1; +select * from t1 where a > 8 and a < 9; +create table t2 like t1; +insert into t2 select * from t1; +alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10)); +explain select * from t1 where a is null and b = 2; +explain select * from t1 where a is null and b = 2 and c=0; +explain select * from t1 where a is null and b = 7 and c=0; +explain select * from t1 where a=2 and b = 2; +explain select * from t1 where a<=>b limit 2; +explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 and c=0 limit 3; +explain select * from t1 where (a is null or a = 7) and b=7 and c=0; +explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2; +explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +explain select * from t1 where a > 1 and a < 3 limit 1; +explain select * from t1 where a is null and b=7 or a > 1 and a < 3 limit 1; +explain select * from t1 where a > 8 and a < 9; +explain select * from t1 where b like "6%"; +select * from t1 where a is null; +select * from t1 where a is null and b = 7 and c=0; +select * from t1 where a<=>b limit 2; +select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3; +select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3; +select * from t1 where (a is null or a = 7) and b=7 and c=0; +select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +select * from t1 where b like "6%"; + +# +# Test ref_or_null optimization +# +drop table t1; +rename table t2 to t1; +alter table t1 modify b int null; +insert into t1 values (7,null), (8,null), (8,7); +explain select * from t1 where a = 7 and (b=7 or b is null); +select * from t1 where a = 7 and (b=7 or b is null); +explain select * from t1 where (a = 7 or a is null) and (b=7 or b is null); +select * from t1 where (a = 7 or a is null) and (b=7 or b is null); +explain select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); +select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); +create table t2 (a int); +insert into t2 values (7),(8); +explain select * from t2 straight_join t1 where t1.a=t2.a and b is null; +drop index b on t1; +explain select * from t2,t1 where t1.a=t2.a and b is null; +select * from t2,t1 where t1.a=t2.a and b is null; +explain select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null); +select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null); +explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7; +select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7; +explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null); +select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null); +insert into t2 values (null),(6); +delete from t1 where a=8; +explain select * from t2,t1 where t1.a=t2.a or t1.a is null; +explain select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9); +select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9); +drop table t1,t2; + +# +# The following failed for Matt Loschert +# + +CREATE TABLE t1 ( + id int(10) unsigned NOT NULL auto_increment, + uniq_id int(10) unsigned default NULL, + PRIMARY KEY (id), + UNIQUE KEY idx1 (uniq_id) +) ENGINE=MyISAM; + +CREATE TABLE t2 ( + id int(10) unsigned NOT NULL auto_increment, + uniq_id int(10) unsigned default NULL, + PRIMARY KEY (id) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (1,NULL),(2,NULL),(3,1),(4,2),(5,NULL),(6,NULL),(7,3),(8,4),(9,NULL),(10,NULL); +INSERT INTO t2 VALUES (1,NULL),(2,NULL),(3,1),(4,2),(5,NULL),(6,NULL),(7,3),(8,4),(9,NULL),(10,NULL); + +# +# Check IS NULL optimization +# +explain select id from t1 where uniq_id is null; +explain select id from t1 where uniq_id =1; +# +# Check updates +# +UPDATE t1 SET id=id+100 where uniq_id is null; +UPDATE t2 SET id=id+100 where uniq_id is null; +select id from t1 where uniq_id is null; +select id from t2 where uniq_id is null; +# +# Delete all records from each table where the uniq_id field is null +# +DELETE FROM t1 WHERE uniq_id IS NULL; +DELETE FROM t2 WHERE uniq_id IS NULL; +# +# Select what is left -- notice the difference +# +SELECT * FROM t1 ORDER BY uniq_id, id; +SELECT * FROM t2 ORDER BY uniq_id, id; +DROP table t1,t2; + +# +# This crashed MySQL 3.23.47 +# + +CREATE TABLE `t1` ( + `order_id` char(32) NOT NULL default '', + `product_id` char(32) NOT NULL default '', + `product_type` int(11) NOT NULL default '0', + PRIMARY KEY (`order_id`,`product_id`,`product_type`) +) ENGINE=MyISAM; +CREATE TABLE `t2` ( + `order_id` char(32) NOT NULL default '', + `product_id` char(32) NOT NULL default '', + `product_type` int(11) NOT NULL default '0', + PRIMARY KEY (`order_id`,`product_id`,`product_type`) +) ENGINE=MyISAM; +INSERT INTO t1 (order_id, product_id, product_type) VALUES +('3d7ce39b5d4b3e3d22aaafe9b633de51',1206029, 3), +('3d7ce39b5d4b3e3d22aaafe9b633de51',5880836, 3), +('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); +INSERT INTO t2 (order_id, product_id, product_type) VALUES +('9d9aad7764b5b2c53004348ef8d34500',2315652, 3); + +select t1.* from t1 +left join t2 using(order_id, product_id, product_type) +where t2.order_id=NULL; +select t1.* from t1 +left join t2 using(order_id, product_id, product_type) +where t2.order_id is NULL; +drop table t1,t2; + +# +# The last select returned wrong results in 3.23.52 +# + +create table t1 (id int); +insert into t1 values (null), (0); +create table t2 (id int); +insert into t2 values (null); +select * from t1, t2 where t1.id = t2.id; +alter table t1 add key id (id); +select * from t1, t2 where t1.id = t2.id; +drop table t1,t2; + +# +# Check bug when doing <=> NULL on an indexed null field +# + +create table t1 ( + id integer, + id2 integer not null, + index (id), + index (id2) +); +insert into t1 values(null,null),(1,1); +select * from t1; +select * from t1 where id <=> null; +select * from t1 where id <=> null or id > 0; +select * from t1 where id is null or id > 0; +select * from t1 where id2 <=> null or id2 > 0; +select * from t1 where id2 is null or id2 > 0; +delete from t1 where id <=> NULL; +select * from t1; +drop table t1; + +# +# Test for bug #12144: optimizations for key access with null keys +# used for outer joins +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int, b int, INDEX idx(a)); +CREATE TABLE t3 (b int, INDEX idx(b)); +CREATE TABLE t4 (b int, INDEX idx(b)); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (1, 1), (3, 1); +INSERT INTO t3 VALUES + (NULL), (NULL), (NULL), (NULL), (NULL), + (NULL), (NULL), (NULL), (NULL), (NULL); +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t3 VALUES (2), (3); + +ANALYZE table t1, t2, t3; + +SELECT COUNT(*) FROM t3; + +EXPLAIN SELECT SQL_CALC_FOUND_ROWS * FROM t1 LEFT JOIN t2 ON t1.a=t2.a + LEFT JOIN t3 ON t2.b=t3.b; +FLUSH STATUS ; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LEFT JOIN t2 ON t1.a=t2.a + LEFT JOIN t3 ON t2.b=t3.b; +SELECT FOUND_ROWS(); +SHOW STATUS LIKE "handler_read%"; + +DROP TABLE t1,t2,t3,t4; +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/odbc.test b/mysql-test/suite/pbxt/t/odbc.test new file mode 100644 index 00000000000..51738029577 --- /dev/null +++ b/mysql-test/suite/pbxt/t/odbc.test @@ -0,0 +1,37 @@ +# Initialise +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Test some ODBC compatibility +# + +select {fn length("hello")}, { date "1997-10-20" }; + +# +# Test retreiving row with last insert_id value. +# + +create table t1 (a int not null auto_increment,b int not null,primary key (a,b)); +insert into t1 SET A=NULL,B=1; +insert into t1 SET a=null,b=2; +select * from t1 where a is null and b=2; +select * from t1 where a is null; +explain select * from t1 where b is null; +drop table t1; + +# +# Bug #14553: NULL in WHERE resets LAST_INSERT_ID +# +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (NULL); +SELECT sql_no_cache a, last_insert_id() FROM t1 WHERE a IS NULL; +SELECT sql_no_cache a, last_insert_id() FROM t1 WHERE a IS NULL; +SELECT sql_no_cache a, last_insert_id() FROM t1; +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/olap.test b/mysql-test/suite/pbxt/t/olap.test new file mode 100644 index 00000000000..0b000eea077 --- /dev/null +++ b/mysql-test/suite/pbxt/t/olap.test @@ -0,0 +1,333 @@ +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +set @sav_dpi= @@div_precision_increment; +set div_precision_increment= 5; +show variables like 'div_precision_increment'; + +create table t1 (product varchar(32), country_id int not null, year int, profit int); +insert into t1 values ( 'Computer', 2,2000, 1200), +( 'TV', 1, 1999, 150), +( 'Calculator', 1, 1999,50), +( 'Computer', 1, 1999,1500), +( 'Computer', 1, 2000,1500), +( 'TV', 1, 2000, 150), +( 'TV', 2, 2000, 100), +( 'TV', 2, 2000, 100), +( 'Calculator', 1, 2000,75), +( 'Calculator', 2, 2000,75), +( 'TV', 1, 1999, 100), +( 'Computer', 1, 1999,1200), +( 'Computer', 2, 2000,1500), +( 'Calculator', 2, 2000,75), +( 'Phone', 3, 2003,10) +; + +create table t2 (country_id int primary key, country char(20) not null); +insert into t2 values (1, 'USA'),(2,'India'), (3,'Finland'); + +# First simple rollups, with just grand total +select product, sum(profit) from t1 group by product; +select product, sum(profit) from t1 group by product with rollup; +select product, sum(profit) from t1 group by 1 with rollup; +select product, sum(profit),avg(profit) from t1 group by product with rollup; + +# Sub totals +select product, country_id , year, sum(profit) from t1 group by product, country_id, year; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +explain extended select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +select product, country_id , sum(profit) from t1 group by product desc, country_id with rollup; + +# limit +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup limit 5; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup limit 3,3; + +select product, country_id, count(*), count(distinct year) from t1 group by product, country_id; +select product, country_id, count(*), count(distinct year) from t1 group by product, country_id with rollup; + +# Test of having +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having country_id = 1; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having sum(profit) > 200; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having sum(profit) > 7000; + +# Functions +select concat(product,':',country_id) as 'prod', concat(":",year,":") as 'year',1+1, sum(profit)/count(*) from t1 group by 1,2 with rollup; +select product, sum(profit)/count(*) from t1 group by product with rollup; +select left(product,4) as prod, sum(profit)/count(*) from t1 group by prod with rollup; +select concat(product,':',country_id), 1+1, sum(profit)/count(*) from t1 group by concat(product,':',country_id) with rollup; + +# Joins +select product, country , year, sum(profit) from t1,t2 where t1.country_id=t2.country_id group by product, country, year with rollup; + +# Derived tables and sub selects +select product, `sum` from (select product, sum(profit) as 'sum' from t1 group by product with rollup) as tmp where product is null; +select product from t1 where exists (select product, country_id , sum(profit) from t1 as t2 where t1.product=t2.product group by product, country_id with rollup having sum(profit) > 6000); + +# The following doesn't return the expected answer, but this is a limitation +# in the implementation so we should just document it +select product, country_id , year, sum(profit) from t1 group by product, country_id, year having country_id is NULL; +select concat(':',product,':'), sum(profit),avg(profit) from t1 group by product with rollup; + +# Error handling + +# Cube is not yet implemented +--error 1235 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; +--error 1235 +explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; +--error 1235 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube union all select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; + +drop table t1,t2; + +# +# Test bug with const tables +# + +CREATE TABLE t1 (i int); +INSERT INTO t1 VALUES(100); +CREATE TABLE t2 (i int); +INSERT INTO t2 VALUES (100),(200); +SELECT i, COUNT(*) FROM t1 GROUP BY i WITH ROLLUP; +SELECT t1.i, t2.i, COUNT(*) FROM t1,t2 GROUP BY t1.i,t2.i WITH ROLLUP; +drop table t1,t2; + +#bug #4767: ROLLUP with LEFT JOIN + +CREATE TABLE user_day( + user_id INT NOT NULL, + date DATE NOT NULL, + UNIQUE INDEX user_date (user_id, date) +); + +INSERT INTO user_day VALUES + (1, '2004-06-06' ), + (1, '2004-06-07' ), + (2, '2004-06-06' ); + +SELECT + d.date AS day, + COUNT(d.user_id) as sample, + COUNT(next_day.user_id) AS not_cancelled + FROM user_day d + LEFT JOIN user_day next_day + ON next_day.user_id=d.user_id AND + next_day.date= DATE_ADD( d.date, interval 1 day ) + GROUP BY day; + +SELECT + d.date AS day, + COUNT(d.user_id) as sample, + COUNT(next_day.user_id) AS not_cancelled + FROM user_day d + LEFT JOIN user_day next_day + ON next_day.user_id=d.user_id AND + next_day.date= DATE_ADD( d.date, interval 1 day ) + GROUP BY day + WITH ROLLUP; + +DROP TABLE user_day; + +# +# Tests for bugs #8616, #8615: distinct sum with rollup +# + +CREATE TABLE t1 (a int, b int); + +INSERT INTO t1 VALUES + (1,4), + (2,2), (2,2), + (4,1), (4,1), (4,1), (4,1), + (2,1), (2,1); + +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 + GROUP BY a WITH ROLLUP; + +SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; + +SELECT b, a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT b,a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; + +ALTER TABLE t1 ADD COLUMN c INT; +SELECT a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP; +SELECT distinct a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP; + +DROP TABLE t1; + +# +# Tests for bugs #8617: SQL_CACL_FOUND_ROWS with rollup and limit +# + +CREATE TABLE t1 (a int, b int); + +INSERT INTO t1 VALUES + (1,4), + (2,2), (2,2), + (4,1), (4,1), (4,1), (4,1), + (2,1), (2,1); + +SELECT a, SUM(b) FROM t1 GROUP BY a WITH ROLLUP LIMIT 1; +SELECT SQL_CALC_FOUND_ROWS a, SUM(b) FROM t1 GROUP BY a WITH ROLLUP LIMIT 1; + +DROP TABLE t1; + +# +# Tests for bug #9681: ROLLUP in subquery for derived table wiht +# a group by field declared as NOT NULL +# + +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); + +SELECT a, SUM(a) m FROM t1 GROUP BY a WITH ROLLUP; +SELECT * FROM ( SELECT a, SUM(a) m FROM t1 GROUP BY a WITH ROLLUP ) t2; + +DROP TABLE t1; +set div_precision_increment= @sav_dpi; + +# +# Tests for bug #7914: ROLLUP over expressions on temporary table +# + +CREATE TABLE t1 (a int(11)); +INSERT INTO t1 VALUES (1),(2); + +SELECT a, SUM(a), SUM(a)+1 FROM (SELECT a FROM t1 UNION select 2) d + GROUP BY a; +SELECT a, SUM(a), SUM(a)+1 FROM (SELECT a FROM t1 UNION select 2) d + GROUP BY a WITH ROLLUP; + +SELECT a, SUM(a), SUM(a)+1 FROM (SELECT 1 a UNION select 2) d + GROUP BY a; +SELECT a, SUM(a), SUM(a)+1 FROM (SELECT 1 a UNION select 2) d + GROUP BY a WITH ROLLUP; + +SELECT a, SUM(a), SUM(a)+1, CONCAT(SUM(a),'x'), SUM(a)+SUM(a), SUM(a) + FROM (SELECT 1 a, 2 b UNION SELECT 2,3 UNION SELECT 5,6 ) d + GROUP BY a WITH ROLLUP; + +DROP TABLE t1; + +# +# Tests for bug #7894: ROLLUP over expressions on group by attributes +# + +CREATE TABLE t1 (a int(11)); +INSERT INTO t1 VALUES (1),(2); + +SELECT a, a+1, SUM(a) FROM t1 GROUP BY a WITH ROLLUP; +SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP; +SELECT a+SUM(a) FROM t1 GROUP BY a WITH ROLLUP; +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b > 2; +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING a IS NULL; +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b IS NULL; +SELECT IFNULL(a, 'TEST') FROM t1 GROUP BY a WITH ROLLUP; + +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES + (1,4), + (2,2), (2,2), + (4,1), (4,1), (4,1), (4,1), + (2,1), (2,1); + +SELECT a,b,SUM(b) FROM t2 GROUP BY a,b WITH ROLLUP; +SELECT a,b,SUM(b), a+b as c FROM t2 + GROUP BY a,b WITH ROLLUP HAVING c IS NULL; +SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 + GROUP BY a, b WITH ROLLUP; + +DROP TABLE t1,t2; + +# +# Test for bug #11543: ROLLUP query with a repeated column in GROUP BY +# + +CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (1, 2); + +SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; + +DROP TABLE t1; + +# Bug #12885(1): derived table specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes +# + +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); + +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; + +DROP TABLE t1; + +# +# Bug #12887 Distinct is not always applied after rollup +# +create table t1 ( a varchar(9), b int ); +insert into t1 values('a',1),(null,2); +select a, max(b) from t1 group by a with rollup; +select distinct a, max(b) from t1 group by a with rollup; +drop table t1; + +# +# Bug #20825: rollup puts non-equal values together +# +create table t1 (a varchar(22) not null , b int); +insert into t1 values ("2006-07-01 21:30", 1), ("2006-07-01 23:30", 10); +select left(a,10), a, sum(b) from t1 group by 1,2 with rollup; +select left(a,10) x, a, sum(b) from t1 group by x,a with rollup; +drop table t1; + +# End of 4.1 tests + +# +# Tests for bug #11639: ROLLUP over view executed through filesort +# + +CREATE TABLE t1(id int, type char(1)); +INSERT INTO t1 VALUES + (1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), + (6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C"); +CREATE VIEW v1 AS SELECT * FROM t1; + +SELECT type FROM t1 GROUP BY type WITH ROLLUP; +SELECT type FROM v1 GROUP BY type WITH ROLLUP; +EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; + +DROP VIEW v1; +DROP TABLE t1; + +# +# Bug #12885(2): view specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes +# + +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); + +CREATE VIEW v1 AS + SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; + +DESC v1; +SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/order_by.test b/mysql-test/suite/pbxt/t/order_by.test new file mode 100644 index 00000000000..04d08b41262 --- /dev/null +++ b/mysql-test/suite/pbxt/t/order_by.test @@ -0,0 +1,646 @@ +# +# Bug with order by +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +CREATE TABLE t1 ( + id int(6) DEFAULT '0' NOT NULL, + idservice int(5), + clee char(20) NOT NULL, + flag char(1), + KEY id (id), + PRIMARY KEY (clee) +); + + +INSERT INTO t1 VALUES (2,4,'6067169d','Y'); +INSERT INTO t1 VALUES (2,5,'606716d1','Y'); +INSERT INTO t1 VALUES (2,1,'606717c1','Y'); +INSERT INTO t1 VALUES (3,1,'6067178d','Y'); +INSERT INTO t1 VALUES (2,6,'60671515','Y'); +INSERT INTO t1 VALUES (2,7,'60671569','Y'); +INSERT INTO t1 VALUES (2,3,'dd','Y'); + +CREATE TABLE t2 ( + id int(6) NOT NULL auto_increment, + description varchar(40) NOT NULL, + idform varchar(40), + ordre int(6) unsigned DEFAULT '0' NOT NULL, + image varchar(60), + PRIMARY KEY (id), + KEY id (id,ordre) +); + +# +# Dumping data for table 't2' +# + +INSERT INTO t2 VALUES (1,'Emettre un appel d''offres','en_construction.html',10,'emettre.gif'); +INSERT INTO t2 VALUES (2,'Emettre des soumissions','en_construction.html',20,'emettre.gif'); +INSERT INTO t2 VALUES (7,'Liste des t2','t2_liste_form.phtml',51060,'link.gif'); +INSERT INTO t2 VALUES (8,'Consulter les soumissions','consulter_soumissions.phtml',200,'link.gif'); +INSERT INTO t2 VALUES (9,'Ajouter un type de materiel','typeMateriel_ajoute_form.phtml',51000,'link.gif'); +INSERT INTO t2 VALUES (10,'Lister/modifier un type de materiel','typeMateriel_liste_form.phtml',51010,'link.gif'); +INSERT INTO t2 VALUES (3,'Créer une fiche de client','clients_ajoute_form.phtml',40000,'link.gif'); +INSERT INTO t2 VALUES (4,'Modifier des clients','en_construction.html',40010,'link.gif'); +INSERT INTO t2 VALUES (5,'Effacer des clients','en_construction.html',40020,'link.gif'); +INSERT INTO t2 VALUES (6,'Ajouter un service','t2_ajoute_form.phtml',51050,'link.gif'); + + +select t1.id,t1.idservice,t2.ordre,t2.description from t1, t2 where t1.id = 2 and t1.idservice = t2.id order by t2.ordre; + +drop table t1,t2; + +# +# Test of ORDER BY on concat() result +# + +create table t1 (first char(10),last char(10)); +insert into t1 values ("Michael","Widenius"); +insert into t1 values ("Allan","Larsson"); +insert into t1 values ("David","Axmark"); +select concat(first," ",last) as name from t1 order by name; +select concat(last," ",first) as name from t1 order by name; +drop table t1; + +# +# bug in distinct + order by +# + +create table t1 (i int); +insert into t1 values(1),(2),(1),(2),(1),(2),(3); +select distinct i from t1; +select distinct i from t1 order by rand(5); +select distinct i from t1 order by i desc; +select distinct i from t1 order by 1-i; +select distinct i from t1 order by mod(i,2),i; +drop table t1; + +# +# bug#3681 +# + +create table t1 ( pk int primary key, name varchar(255) not null, number varchar(255) not null); +insert into t1 values (1, 'Gamma', '123'), (2, 'Gamma Ext', '123a'), (3, 'Alpha', '001'), (4, 'Beta', '200c'); +select distinct t1.name as 'Building Name',t1.number as 'Building Number' from t1 order by t1.name asc; +drop table t1; + + +# +# Order by on first index part +# + +create table t1 (id int not null,col1 int not null,col2 int not null,index(col1)); +insert into t1 values(1,2,2),(2,2,1),(3,1,2),(4,1,1),(5,1,4),(6,2,3),(7,3,1),(8,2,4); +select * from t1 order by col1,col2; +select col1 from t1 order by id; +select col1 as id from t1 order by id; +select concat(col1) as id from t1 order by id; +drop table t1; + +# +# Test of order by on field() +# + +CREATE TABLE t1 (id int auto_increment primary key,aika varchar(40),aikakentta timestamp); +insert into t1 (aika) values ('Keskiviikko'); +insert into t1 (aika) values ('Tiistai'); +insert into t1 (aika) values ('Maanantai'); +insert into t1 (aika) values ('Sunnuntai'); + +SELECT FIELD(SUBSTRING(t1.aika,1,2),'Ma','Ti','Ke','To','Pe','La','Su') AS test FROM t1 ORDER by test; +drop table t1; + +# +# Test of ORDER BY on IF +# + +CREATE TABLE t1 +( + a int unsigned NOT NULL, + b int unsigned NOT NULL, + c int unsigned NOT NULL, + UNIQUE(a), + INDEX(b), + INDEX(c) +); + +CREATE TABLE t2 +( + c int unsigned NOT NULL, + i int unsigned NOT NULL, + INDEX(c) +); + +CREATE TABLE t3 +( + c int unsigned NOT NULL, + v varchar(64), + INDEX(c) +); + +INSERT INTO t1 VALUES (1,1,1); +INSERT INTO t1 VALUES (2,1,2); +INSERT INTO t1 VALUES (3,2,1); +INSERT INTO t1 VALUES (4,2,2); +INSERT INTO t2 VALUES (1,50); +INSERT INTO t2 VALUES (2,25); +INSERT INTO t3 VALUES (1,'123 Park Place'); +INSERT INTO t3 VALUES (2,'453 Boardwalk'); + +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 USING(c) +LEFT JOIN t3 ON t3.c = t1.c; + +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 ON t1.c = t2.c +LEFT JOIN t3 ON t3.c = t1.c; + +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 USING(c) +LEFT JOIN t3 ON t3.c = t1.c +ORDER BY a; + +SELECT a,b,if(b = 1,i,if(b = 2,v,'')) +FROM t1 +LEFT JOIN t2 ON t1.c = t2.c +LEFT JOIN t3 ON t3.c = t1.c +ORDER BY a; + +drop table t1,t2,t3; + +# +# Test of ORDER BY (Bug found by Dean Edmonds) +# + +create table t1 (ID int not null primary key, TransactionID int not null); +insert into t1 (ID, TransactionID) values (1, 87), (2, 89), (3, 92), (4, 94), (5, 486), (6, 490), (7, 753), (9, 828), (10, 832), (11, 834), (12, 840); +create table t2 (ID int not null primary key, GroupID int not null); + insert into t2 (ID, GroupID) values (87, 87), (89, 89), (92, 92), (94, 94), (486, 486), (490, 490),(753, 753), (828, 828), (832, 832), (834, 834), (840, 840); +create table t3 (ID int not null primary key, DateOfAction date not null); +insert into t3 (ID, DateOfAction) values (87, '1999-07-19'), (89, '1999-07-19'), (92, '1999-07-19'), (94, '1999-07-19'), (486, '1999-07-18'), (490, '2000-03-27'), (753, '2000-03-28'), (828, '1999-07-27'), (832, '1999-07-27'),(834, '1999-07-27'), (840, '1999-07-27'); +select t3.DateOfAction, t1.TransactionID from t1 join t2 join t3 where t2.ID = t1.TransactionID and t3.ID = t2.GroupID order by t3.DateOfAction, t1.TransactionID; +select t3.DateOfAction, t1.TransactionID from t1 join t2 join t3 where t2.ID = t1.TransactionID and t3.ID = t2.GroupID order by t1.TransactionID,t3.DateOfAction; +drop table t1,t2,t3; + +#bug reported by Wouter de Jong + +CREATE TABLE t1 ( + member_id int(11) NOT NULL auto_increment, + inschrijf_datum varchar(20) NOT NULL default '', + lastchange_datum varchar(20) NOT NULL default '', + nickname varchar(20) NOT NULL default '', + password varchar(8) NOT NULL default '', + voornaam varchar(30) NOT NULL default '', + tussenvoegsels varchar(10) NOT NULL default '', + achternaam varchar(50) NOT NULL default '', + straat varchar(100) NOT NULL default '', + postcode varchar(10) NOT NULL default '', + wijk varchar(40) NOT NULL default '', + plaats varchar(50) NOT NULL default '', + telefoon varchar(10) NOT NULL default '', + geboortedatum date NOT NULL default '0000-00-00', + geslacht varchar(5) NOT NULL default '', + email varchar(80) NOT NULL default '', + uin varchar(15) NOT NULL default '', + homepage varchar(100) NOT NULL default '', + internet varchar(15) NOT NULL default '', + scherk varchar(30) NOT NULL default '', + favo_boek varchar(50) NOT NULL default '', + favo_tijdschrift varchar(50) NOT NULL default '', + favo_tv varchar(50) NOT NULL default '', + favo_eten varchar(50) NOT NULL default '', + favo_muziek varchar(30) NOT NULL default '', + info text NOT NULL default '', + ipnr varchar(30) NOT NULL default '', + PRIMARY KEY (member_id) +) ENGINE=MyISAM PACK_KEYS=1; + +insert into t1 (member_id) values (1),(2),(3); +select member_id, nickname, voornaam FROM t1 +ORDER by lastchange_datum DESC LIMIT 2; +drop table t1; + +# +# Test optimization of ORDER BY DESC +# + +create table t1 (a int not null, b int, c varchar(10), key (a, b, c)); +insert into t1 values (1, NULL, NULL), (1, NULL, 'b'), (1, 1, NULL), (1, 1, 'b'), (1, 1, 'b'), (2, 1, 'a'), (2, 1, 'b'), (2, 2, 'a'), (2, 2, 'b'), (2, 3, 'c'),(1,3,'b'); + +explain select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc; +select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc; +explain select * from t1 where a >= 1 and a < 3 order by a desc; +select * from t1 where a >= 1 and a < 3 order by a desc; +explain select * from t1 where a = 1 order by a desc, b desc; +select * from t1 where a = 1 order by a desc, b desc; +explain select * from t1 where a = 1 and b is null order by a desc, b desc; +select * from t1 where a = 1 and b is null order by a desc, b desc; +explain select * from t1 where a >= 1 and a < 3 and b >0 order by a desc,b desc; +explain select * from t1 where a = 2 and b >0 order by a desc,b desc; +explain select * from t1 where a = 2 and b is null order by a desc,b desc; +explain select * from t1 where a = 2 and (b is null or b > 0) order by a +desc,b desc; +explain select * from t1 where a = 2 and b > 0 order by a desc,b desc; +explain select * from t1 where a = 2 and b < 2 order by a desc,b desc; +explain select * from t1 where a = 1 order by b desc; +select * from t1 where a = 1 order by b desc; +# +# Test things when we don't have NULL keys +# + +alter table t1 modify b int not null, modify c varchar(10) not null; +explain select * from t1 order by a, b, c; +select * from t1 order by a, b, c; +explain select * from t1 order by a desc, b desc, c desc; +select * from t1 order by a desc, b desc, c desc; +# test multiple ranges, NO_MAX_RANGE and EQ_RANGE +explain select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc; +select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc; +# test NEAR_MAX, NO_MIN_RANGE +explain select * from t1 where a < 2 and b <= 1 order by a desc, b desc; +select * from t1 where a < 2 and b <= 1 order by a desc, b desc; +select count(*) from t1 where a < 5 and b > 0; +select * from t1 where a < 5 and b > 0 order by a desc,b desc; +# test HA_READ_AFTER_KEY (at the end of the file), NEAR_MIN +explain select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc; +select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc; +# test HA_READ_AFTER_KEY (in the middle of the file) +explain select * from t1 where a between 0 and 1 order by a desc, b desc; +select * from t1 where a between 0 and 1 order by a desc, b desc; +drop table t1; + + +CREATE TABLE t1 ( + gid int(10) unsigned NOT NULL auto_increment, + cid smallint(5) unsigned NOT NULL default '0', + PRIMARY KEY (gid), + KEY component_id (cid) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES (103853,108),(103867,108),(103962,108),(104505,108),(104619,108),(104620,108); +ALTER TABLE t1 add skr int(10) not null; + +CREATE TABLE t2 ( + gid int(10) unsigned NOT NULL default '0', + uid smallint(5) unsigned NOT NULL default '1', + sid tinyint(3) unsigned NOT NULL default '1', + PRIMARY KEY (gid), + KEY uid (uid), + KEY status_id (sid) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (103853,250,5),(103867,27,5),(103962,27,5),(104505,117,5),(104619,75,5),(104620,15,5); + +CREATE TABLE t3 ( + uid smallint(6) NOT NULL auto_increment, + PRIMARY KEY (uid) +) ENGINE=MyISAM; +INSERT INTO t3 VALUES (1),(15),(27),(75),(117),(250); +ALTER TABLE t3 add skr int(10) not null; + +select t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid; +select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid; + +# The following ORDER BY can be optimimized +EXPLAIN select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t1.gid, t3.uid; +EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t1.gid,t3.skr; + +# The following ORDER BY can't be optimimized +EXPLAIN SELECT t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid; +EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t3.skr,t1.gid; +EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.skr = t3.uid order by t1.gid,t3.skr; +drop table t1,t2,t3; + +# +# Test of bug when doing an ORDER BY with const items +# + +CREATE TABLE t1 ( + `titre` char(80) NOT NULL default '', + `numeropost` mediumint(8) unsigned NOT NULL auto_increment, + `date` datetime NOT NULL default '0000-00-00 00:00:00', + `auteur` char(35) NOT NULL default '', + `icone` tinyint(2) unsigned NOT NULL default '0', + `lastauteur` char(35) NOT NULL default '', + `nbrep` smallint(6) unsigned NOT NULL default '0', + `dest` char(35) NOT NULL default '', + `lu` tinyint(1) unsigned NOT NULL default '0', + `vue` mediumint(8) unsigned NOT NULL default '0', + `ludest` tinyint(1) unsigned NOT NULL default '0', + `ouvert` tinyint(1) unsigned NOT NULL default '1', + PRIMARY KEY (`numeropost`), + KEY `date` (`date`), + KEY `dest` (`dest`,`ludest`), + KEY `auteur` (`auteur`,`lu`), + KEY `auteur_2` (`auteur`,`date`), + KEY `dest_2` (`dest`,`date`) +) CHECKSUM=1; + +CREATE TABLE t2 ( + `numeropost` mediumint(8) unsigned NOT NULL default '0', + `pseudo` char(35) NOT NULL default '', + PRIMARY KEY (`numeropost`,`pseudo`), + KEY `pseudo` (`pseudo`) +); + +INSERT INTO t1 (titre,auteur,dest) VALUES ('test','joce','bug'); +INSERT INTO t2 (numeropost,pseudo) VALUES (1,'joce'),(1,'bug'); +SELECT titre,t1.numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +SELECT titre,numeropost,auteur,icone,nbrep,0,date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +SELECT titre,numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,dest FROM t2 LEFT JOIN t1 USING(numeropost) WHERE t2.pseudo='joce' ORDER BY date DESC LIMIT 0,30; +drop table t1,t2; + +# +# Test order by with NULL values +# +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1, 2); +INSERT INTO t1 VALUES (3, 4); +INSERT INTO t1 VALUES (5, NULL); +SELECT * FROM t1 ORDER BY b; +SELECT * FROM t1 ORDER BY b DESC; +SELECT * FROM t1 ORDER BY (a + b); +SELECT * FROM t1 ORDER BY (a + b) DESC; +DROP TABLE t1; + +# +# Test of FORCE INDEX ... ORDER BY +# + +create table t1(id int not null auto_increment primary key, t char(12)); +disable_query_log; +let $1 = 1000; +while ($1) + { + eval insert into t1(t) values ('$1'); + dec $1; + } +enable_query_log; +explain select id,t from t1 order by id; +explain select id,t from t1 force index (primary) order by id; +drop table t1; + +# +# Test of test_if_subkey() function +# +CREATE TABLE t1 ( + FieldKey varchar(36) NOT NULL default '', + LongVal bigint(20) default NULL, + StringVal mediumtext, + KEY FieldKey (FieldKey), + KEY LongField (FieldKey,LongVal), + KEY StringField (FieldKey,StringVal(32)) +); +INSERT INTO t1 VALUES ('0',3,'0'),('0',2,'1'),('0',1,'2'),('1',2,'1'),('1',1,'3'), ('1',0,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('3',2,'1'),('3',1,'2'),('3','3','3'); +EXPLAIN SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal; +SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal; +EXPLAIN SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal; +SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal; +EXPLAIN SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY FieldKey, LongVal; +SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY FieldKey, LongVal; +DROP TABLE t1; +# +# Bug #1945 - Crashing bug with bad User Variables in UPDATE ... ORDER BY ... +# +CREATE TABLE t1 (a INT, b INT); +SET @id=0; +UPDATE t1 SET a=0 ORDER BY (a=@id), b; +DROP TABLE t1; + +# +# Bug when doing an order by on a 1 byte string (Bug #2147) +# + +CREATE TABLE t1 ( id smallint(6) unsigned NOT NULL default '0', menu tinyint(4) NOT NULL default '0', KEY id (id), KEY menu (menu)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (11384, 2),(11392, 2); +SELECT id FROM t1 WHERE id <11984 AND menu =2 ORDER BY id DESC LIMIT 1 ; +drop table t1; + +# +# REF_OR_NULL optimization + filesort (bug #2419) +# + +create table t1(a int, b int, index(b)); +insert into t1 values (2, 1), (1, 1), (4, NULL), (3, NULL), (6, 2), (5, 2); +explain select * from t1 where b=1 or b is null order by a; +select * from t1 where b=1 or b is null order by a; +explain select * from t1 where b=2 or b is null order by a; +select * from t1 where b=2 or b is null order by a; +drop table t1; + +# +# Bug #3155 - Strange results with index (x, y) ... WHERE ... ORDER BY pk +# + +create table t1 (a int not null auto_increment, b int not null, c int not null, d int not null, +key(a,b,d), key(c,b,a)); +create table t2 like t1; +insert into t1 values (NULL, 1, 2, 0), (NULL, 2, 1, 1), (NULL, 3, 4, 2), (NULL, 4, 3, 3); +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +insert into t2 select null, b, c, d from t1; +insert into t1 select null, b, c, d from t2; +optimize table t1; +set @row=10; +insert into t1 select 1, b, c + (@row:=@row - 1) * 10, d - @row from t2 limit 10; +select * from t1 where a=1 and b in (1) order by c, b, a; +select * from t1 where a=1 and b in (1); +drop table t1, t2; + +# +# Bug #4302 +# Ambiguos order by when renamed column is identical to another in result. +# Should not fail and prefer column from t1 for sorting. +# +create table t1 (col1 int, col int); +create table t2 (col2 int, col int); +insert into t1 values (1,1),(2,2),(3,3); +insert into t2 values (1,3),(2,2),(3,1); +select t1.* , t2.col as t2_col from t1 left join t2 on (t1.col1=t2.col2) + order by col; + +# +# Let us also test various ambiguos and potentially ambiguos cases +# related to aliases +# +--error 1052 +select col1 as col, col from t1 order by col; +--error 1052 +select t1.col as c1, t2.col as c2 from t1, t2 where t1.col1=t2.col2 + order by col; +--error 1052 +select t1.col as c1, t2.col as c2 from t1, t2 where t1.col1=t2.col2 + order by col; +--error 1052 +select col1 from t1, t2 where t1.col1=t2.col2 order by col; +--error 1052 +select t1.col as t1_col, t2.col2 from t1, t2 where t1.col1=t2.col2 + order by col; + +select t1.col as t1_col, t2.col from t1, t2 where t1.col1=t2.col2 + order by col; +select col2 as c, col as c from t2 order by col; +select col2 as col, col as col2 from t2 order by col; +select t2.col2, t2.col, t2.col from t2 order by col; + +select t2.col2 as col from t2 order by t2.col; +select t2.col2 as col, t2.col from t2 order by t2.col; +select t2.col2, t2.col, t2.col from t2 order by t2.col; + +drop table t1, t2; + +# +# Bug #5428: a problem with small max_sort_length value +# + +create table t1 (a char(25)); +insert into t1 set a = repeat('x', 20); +insert into t1 set a = concat(repeat('x', 19), 'z'); +insert into t1 set a = concat(repeat('x', 19), 'ab'); +insert into t1 set a = concat(repeat('x', 19), 'aa'); +set max_sort_length=20; +select a from t1 order by a; +drop table t1; + +# +# Bug #7331 +# + +create table t1 ( + `sid` decimal(8,0) default null, + `wnid` varchar(11) not null default '', + key `wnid14` (`wnid`(4)), + key `wnid` (`wnid`) +) engine=myisam default charset=latin1; + +insert into t1 (`sid`, `wnid`) values +('10100','01019000000'),('37986','01019000000'),('37987','01019010000'), +('39560','01019090000'),('37989','01019000000'),('37990','01019011000'), +('37991','01019011000'),('37992','01019019000'),('37993','01019030000'), +('37994','01019090000'),('475','02070000000'),('25253','02071100000'), +('25255','02071100000'),('25256','02071110000'),('25258','02071130000'), +('25259','02071190000'),('25260','02071200000'),('25261','02071210000'), +('25262','02071290000'),('25263','02071300000'),('25264','02071310000'), +('25265','02071310000'),('25266','02071320000'),('25267','02071320000'), +('25269','02071330000'),('25270','02071340000'),('25271','02071350000'), +('25272','02071360000'),('25273','02071370000'),('25281','02071391000'), +('25282','02071391000'),('25283','02071399000'),('25284','02071400000'), +('25285','02071410000'),('25286','02071410000'),('25287','02071420000'), +('25288','02071420000'),('25291','02071430000'),('25290','02071440000'), +('25292','02071450000'),('25293','02071460000'),('25294','02071470000'), +('25295','02071491000'),('25296','02071491000'),('25297','02071499000'); + +explain select * from t1 where wnid like '0101%' order by wnid; + +select * from t1 where wnid like '0101%' order by wnid; + +drop table t1; + +# +# Bug #7672 - a wrong result for a select query in braces followed by order by +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (2), (1), (1), (2), (1); +SELECT a FROM t1 ORDER BY a; +(SELECT a FROM t1) ORDER BY a; +DROP TABLE t1; + +# +# Bug #18767: global ORDER BY applied to a SELECT with ORDER BY either was +# ignored or 'concatened' to the latter. + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,30), (2,20), (1,10), (2,30), (1,20), (2,10); + +(SELECT b,a FROM t1 ORDER BY a,b) ORDER BY b,a; +(SELECT b FROM t1 ORDER BY b DESC) ORDER BY b ASC; +(SELECT b,a FROM t1 ORDER BY b,a) ORDER BY a,b; +(SELECT b,a FROM t1 ORDER by b,a LIMIT 3) ORDER by a,b; + +DROP TABLE t1; + +# +# Bug #22457: Column alias in ORDER BY works, but not if in an expression +# + +CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2); +SELECT a + 1 AS num FROM t1 ORDER BY 30 - num; +SELECT CONCAT('test', a) AS str FROM t1 ORDER BY UPPER(str); +SELECT a + 1 AS num FROM t1 GROUP BY 30 - num; +SELECT a + 1 AS num FROM t1 HAVING 30 - num; +--error 1054 +SELECT a + 1 AS num, num + 1 FROM t1; +SELECT a + 1 AS num, (select num + 2 FROM t1 LIMIT 1) FROM t1; +--error 1054 +SELECT a.a + 1 AS num FROM t1 a JOIN t1 b ON num = b.a; +DROP TABLE t1; + +# +# Bug #25427: crash when order by expression contains a name +# that cannot be resolved unambiguously +# + +CREATE TABLE t1 (a int); + +SELECT p.a AS val, q.a AS val1 FROM t1 p, t1 q ORDER BY val > 1; +--error 1052 +SELECT p.a AS val, q.a AS val FROM t1 p, t1 q ORDER BY val; +--error 1052 +SELECT p.a AS val, q.a AS val FROM t1 p, t1 q ORDER BY val > 1; + +DROP TABLE t1; + +# End of 4.1 tests +create table t1 (a int not null, b int not null, c int not null); +insert t1 values (1,1,1),(1,1,2),(1,2,1); +select a, b from t1 group by a, b order by sum(c); +drop table t1; + +# +# Bug#21302: Result not properly sorted when using an ORDER BY on a second +# table in a join +# +CREATE TABLE t1 (a int, b int, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3); + +explain SELECT t1.b as a, t2.b as c FROM + t1 LEFT JOIN t1 t2 ON (t1.a = t2.a AND t2.a = 2) +ORDER BY c; +SELECT t2.b as c FROM + t1 LEFT JOIN t1 t2 ON (t1.a = t2.a AND t2.a = 2) +ORDER BY c; + +# check that it still removes sort of const table +explain SELECT t1.b as a, t2.b as c FROM + t1 JOIN t1 t2 ON (t1.a = t2.a AND t2.a = 2) +ORDER BY c; + +CREATE TABLE t2 LIKE t1; +INSERT INTO t2 SELECT * from t1; +CREATE TABLE t3 LIKE t1; +INSERT INTO t3 SELECT * from t1; +CREATE TABLE t4 LIKE t1; +INSERT INTO t4 SELECT * from t1; +INSERT INTO t1 values (0,0),(4,4); + +SELECT t2.b FROM t1 LEFT JOIN (t2, t3 LEFT JOIN t4 ON t3.a=t4.a) +ON (t1.a=t2.a AND t1.b=t3.b) order by t2.b; + +DROP TABLE t1,t2,t3,t4; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/order_fill_sortbuf.test b/mysql-test/suite/pbxt/t/order_fill_sortbuf.test new file mode 100644 index 00000000000..3ddcdb4bff1 --- /dev/null +++ b/mysql-test/suite/pbxt/t/order_fill_sortbuf.test @@ -0,0 +1,29 @@ +# +# This test does a create-select with ORDER BY, where there is so many +# rows MySQL needs to use a merge during the sort phase. +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +CREATE TABLE `t1` ( + `id` int(11) NOT NULL default '0', + `id2` int(11) NOT NULL default '0', + `id3` int(11) NOT NULL default '0'); +let $1=4000; +disable_query_log; +while ($1) + { + eval insert into t1 (id,id2,id3) values ($1,$1,$1); + dec $1; + } +enable_query_log; +create table t2 select id2 from t1 order by id3; +select count(*) from t2; +drop table t1,t2; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/overflow.test b/mysql-test/suite/pbxt/t/overflow.test new file mode 100644 index 00000000000..a62ef9c4cd2 --- /dev/null +++ b/mysql-test/suite/pbxt/t/overflow.test @@ -0,0 +1,6 @@ +connect (con1,localhost,root,,); +connection con1; +-- error 1064,1102,1280 +drop database AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/partition_charset.test b/mysql-test/suite/pbxt/t/partition_charset.test new file mode 100644 index 00000000000..6dabadfe756 --- /dev/null +++ b/mysql-test/suite/pbxt/t/partition_charset.test @@ -0,0 +1,25 @@ +# +# Test for character set related things in combination +# with the partition storage engine +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +set names utf8; +create table t1 (s1 int) + partition by list (s1) + (partition c values in (1), + partition Ç values in (3)); +insert into t1 values (1),(3); +select * from t1; +flush tables; +set names latin1; +select * from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/partition_error.test b/mysql-test/suite/pbxt/t/partition_error.test new file mode 100644 index 00000000000..622b4f483b4 --- /dev/null +++ b/mysql-test/suite/pbxt/t/partition_error.test @@ -0,0 +1,801 @@ +# +# Simple test for the erroneos create statements using the +# partition storage engine +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Partition by key stand-alone error +# +--error 1064 +partition by list (a) +partitions 3 +(partition x1 values in (1,2,9,4) tablespace ts1, + partition x2 values in (3, 11, 5, 7) tablespace ts2, + partition x3 values in (16, 8, 5+19, 70-43) tablespace ts3); + +# +# Partition by key list, number of partitions defined, no partition defined +# +--error ER_PARTITIONS_MUST_BE_DEFINED_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2; + +# +# Partition by key list, wrong result type +# +--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (sin(a)) +partitions 3 +(partition x1 values in (1,2,9,4) tablespace ts1, + partition x2 values in (3, 11, 5, 7) tablespace ts2, + partition x3 values in (16, 8, 5+19, 70-43) tablespace ts3); + +# +# Partition by key, partition function not allowed +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a+2) +partitions 3 +(partition x1 tablespace ts1, + partition x2 tablespace ts2, + partition x3 tablespace ts3); + +# +# Partition by key, no partition name +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a) +partitions 3 +(partition tablespace ts1, + partition x2 tablespace ts2, + partition x3 tablespace ts3); + +# +# Partition by key, invalid field in field list +# +--error ER_FIELD_NOT_FOUND_PART_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a,d) +partitions 3 +(partition x1 tablespace ts1, + partition x2 tablespace ts2, + partition x3 tablespace ts3); + +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); +# +# Partition by hash, invalid field in function +# +--error 1054 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a + d) +partitions 3 +(partition x1 tablespace ts1, + partition x2 tablespace ts2, + partition x3 tablespace ts3); + +# +# Partition by hash, invalid result type +# +--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (sin(a)) +partitions 3 +(partition x1 tablespace ts1, + partition x2 tablespace ts2, + partition x3 tablespace ts3); + +# +# Partition by key specified 3 partitions but only defined 2 => error +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a) +partitions 3 +(partition x1, partition x2); + +# +# Partition by key specified 3 partitions but only defined 2 => error +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (rand(a)) +partitions 2 +(partition x1, partition x2); + +# +# Partition by key specified 3 partitions but only defined 2 => error +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (rand(a)) +partitions 2 +(partition x1 values less than (0), partition x2 values less than (2)); + +# +# Partition by key specified 3 partitions but only defined 2 => error +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (rand(a)) +partitions 2 +(partition x1 values in (1), partition x2 values in (2)); + +# +# Partition by hash, values less than error +# +--error ER_PARTITION_WRONG_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a) +partitions 2 +(partition x1 values less than (4), + partition x2 values less than (5)); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Partition by hash, values in error +# +--error ER_PARTITION_WRONG_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a) +partitions 2 +(partition x1 values in (4), + partition x2 values in (5)); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Partition by hash, values in error +# +--error ER_PARTITION_WRONG_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a) +partitions 2 +(partition x1 values in (4,6), + partition x2 values in (5,7)); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by key, no partitions defined, single field +# +--error ER_SUBPARTITION_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by key (b); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by key, no partitions defined, list of fields +# +--error ER_SUBPARTITION_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by key (a, b); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by hash, no partitions defined +# +--error ER_SUBPARTITION_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (a+b); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by key, no partitions defined, single field +# +--error ER_SUBPARTITION_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by key (b); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by key, no partitions defined, list of fields +# +--error ER_SUBPARTITION_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by key (a, b); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by hash, no partitions defined +# +--error ER_SUBPARTITION_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (a+b); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by hash, no partitions defined, wrong subpartition function +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (rand(a+b)); + +# +# Subpartition by hash, wrong subpartition function +# +--error ER_SUBPARTITION_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (sin(a+b)) +(partition x1 (subpartition x11, subpartition x12), + partition x2 (subpartition x21, subpartition x22)); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by hash, no partitions defined, wrong subpartition function +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by key (a+b) +(partition x1 values less than (1) (subpartition x11, subpartition x12), + partition x2 values less than (2) (subpartition x21, subpartition x22)); + +# +# Subpartition by hash, no partitions defined, wrong subpartition function +# +--error ER_FIELD_NOT_FOUND_PART_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by key (a,d) +(partition x1 values less than (1) (subpartition x11, subpartition x12), + partition x2 values less than (2) (subpartition x21, subpartition x22)); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Subpartition by hash, no partitions defined, wrong subpartition function +# +--error ER_SUBPARTITION_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by hash (3+4); + +# +# Subpartition by hash, no partitions defined, wrong subpartition function +# +--error 1054 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+d) +(partition x1 values less than (1) (subpartition x11, subpartition x12), + partition x2 values less than (2) (subpartition x21, subpartition x22)); + +# +# Partition by range, no partition => error +# +--error ER_PARTITIONS_MUST_BE_DEFINED_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a); +select load_file('$MYSQLTEST_VARDIR/master-data/test/t1.par'); + +# +# Partition by range, invalid field in function +# +--error 1054 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a+d) +partitions 2 +(partition x1 values less than (4) tablespace ts1, + partition x2 values less than (8) tablespace ts2); + +# +# Partition by range, inconsistent partition function and constants +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than (4.0) tablespace ts1, + partition x2 values less than (8) tablespace ts2); + +# +# Partition by range, constant partition function not allowed +# +--error ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (3+4) +partitions 2 +(partition x1 values less than (4) tablespace ts1, + partition x2 values less than (8) tablespace ts2); + +# +# Partition by range, no values less than definition +# +--error ER_PARTITION_REQUIRES_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than (4), + partition x2); + +# +# Partition by range, no values in definition allowed +# +--error ER_PARTITION_WRONG_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values in (4), + partition x2); + +# +# Partition by range, values in error +# +--error ER_PARTITION_WRONG_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values in (4), + partition x2 values less than (5)); + +# +# Partition by range, missing parenthesis +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values less than 4, + partition x2 values less than (5)); + +# +# Partition by range, maxvalue in wrong place +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than maxvalue, + partition x2 values less than (5)); + +# +# Partition by range, maxvalue in several places +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than maxvalue, + partition x2 values less than maxvalue); + +# +# Partition by range, not increasing ranges +# +--error ER_RANGE_NOT_INCREASING_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 2 +(partition x1 values less than (4), + partition x2 values less than (3)); + +# +# Partition by range, wrong result type of partition function +# +--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (sin(a)) +partitions 2 +(partition x1 values less than (4), + partition x2 values less than (5)); + +# +# Subpartition by hash, wrong number of subpartitions +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by list (a) +subpartition by hash (a+b) +subpartitions 3 +( partition x1 values in (1,2,4) + ( subpartition x11 nodegroup 0, + subpartition x12 nodegroup 1), + partition x2 values in (3,5,6) + ( subpartition x21 nodegroup 0, + subpartition x22 nodegroup 1) +); + +# +# Subpartition by hash, wrong number of subpartitions +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by list (a) +subpartition by hash (a+b) +( partition x1 values in (1) + ( subpartition x11 nodegroup 0, + subpartition xextra, + subpartition x12 nodegroup 1), + partition x2 values in (2) + ( subpartition x21 nodegroup 0, + subpartition x22 nodegroup 1) +); + +# +# Subpartition by list => error +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by list (a+b) +( partition x1 + ( subpartition x11 engine myisam, + subpartition x12 engine myisam), + partition x2 + ( subpartition x21 engine myisam, + subpartition x22 engine myisam) +); + +# +# Subpartition by list => error +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by key (a) +subpartition by list (a+b) +( partition x1 + ( subpartition x11 engine myisam values in (0), + subpartition x12 engine myisam values in (1)), + partition x2 + ( subpartition x21 engine myisam values in (0), + subpartition x22 engine myisam values in (1)) +); + +# +# Partition by list, no partition => error +# +--error ER_PARTITIONS_MUST_BE_DEFINED_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a); + +# +# Partition by list, constant partition function not allowed +# +--error ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (3+4) +partitions 2 +(partition x1 values in (4) tablespace ts1, + partition x2 values in (8) tablespace ts2); + +# +# Partition by list, invalid field in function +# +--error 1054 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a+d) +partitions 2 +(partition x1 values in (4) tablespace ts1, + partition x2 values in (8) tablespace ts2); + +# +# Partition by list, no values in definition +# +--error ER_PARTITION_REQUIRES_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4), + partition x2); + +# +# Partition by list, values less than error +# +--error ER_PARTITION_WRONG_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4), + partition x2 values less than (5)); + +# +# Partition by list, no values in definition +# +--error ER_PARTITION_REQUIRES_VALUES_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4,6), + partition x2); + +# +# Partition by list, duplicate values +# +--error ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4, 12+9), + partition x2 values in (3, 21)); + +# +# Partition by list, wrong constant result type (not INT) +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in (4.0, 12+8), + partition x2 values in (3, 21)); + +# +# Partition by list, missing parenthesis +# +--error 1064 +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +partitions 2 +(partition x1 values in 4, + partition x2 values in (5)); + +# +# Bug #13439: Crash when LESS THAN (non-literal) +# +--error 1054 +CREATE TABLE t1 (a int) +PARTITION BY RANGE (a) +(PARTITION p0 VALUES LESS THAN (x1)); + +# +# No partition for the given value +# +CREATE TABLE t1(a int) + PARTITION BY RANGE (a) (PARTITION p1 VALUES LESS THAN(5)); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values (10); +drop table t1; + +--error ER_PARTITION_CONST_DOMAIN_ERROR +create table t1 (a bigint unsigned) +partition by range (a) +(partition p0 values less than (-1)); +# +# Bug 18198 Partitions: Verify that erroneus partition functions doesn't work +# +-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +create table t1 (v varchar(12)) +partition by range (ascii(v)) +(partition p0 values less than (10)); +#drop table t1; + +-- error 1064 +create table t1 (a int) +partition by hash (rand(a)); +-- error 1064 +create table t1 (a int) +partition by hash(CURTIME() + a); +-- error 1064 +create table t1 (a int) +partition by hash (NOW()+a); +-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +create table t1 (a int) +partition by hash (extract(hour from convert_tz(a, '+00:00', '+00:00'))); +-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +create table t1 (a int) +partition by range (a + (select count(*) from t1)) +(partition p1 values less than (1)); +-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +create table t1 (a char(10)) +partition by hash (extractvalue(a,'a')); + +--disable_query_log +drop database pbxt; +--enable_query_log + diff --git a/mysql-test/suite/pbxt/t/partition_grant.test b/mysql-test/suite/pbxt/t/partition_grant.test new file mode 100644 index 00000000000..8997efa7e5c --- /dev/null +++ b/mysql-test/suite/pbxt/t/partition_grant.test @@ -0,0 +1,62 @@ +-- source include/have_partition.inc +# Grant tests not performed with embedded server +-- source include/not_embedded.inc + +--disable_warnings +drop schema if exists mysqltest_1; +--enable_warnings + + +# +# Bug #17139: ALTER TABLE ... DROP PARTITION should require DROP privilege +# + +create schema mysqltest_1; +use mysqltest_1; + +create table t1 (a int) partition by list (a) (partition p1 values in (1), partition p2 values in (2), partition p3 values in (3)); +insert into t1 values (1),(2); + +# We don't have DROP USER IF EXISTS. Use this workaround to +# cleanup possible grants for mysqltest_1 left by previous tests +# and ensure consistent results of SHOW GRANTS command below. +--disable_warnings +grant usage on *.* to mysqltest_1@localhost; +revoke all privileges on *.* from mysqltest_1@localhost; +--enable_warnings + +grant select,alter on mysqltest_1.* to mysqltest_1@localhost; + +connect (conn1,localhost,mysqltest_1,,mysqltest_1); +show grants for current_user; +alter table t1 add b int; +--error ER_TABLEACCESS_DENIED_ERROR +alter table t1 drop partition p2; +disconnect conn1; + +connection default; +grant drop on mysqltest_1.* to mysqltest_1@localhost; + +connect (conn2,localhost,mysqltest_1,,mysqltest_1); +alter table t1 drop partition p2; +disconnect conn2; + +connection default; +revoke alter on mysqltest_1.* from mysqltest_1@localhost; + +connect (conn3,localhost,mysqltest_1,,mysqltest_1); +--error ER_TABLEACCESS_DENIED_ERROR +alter table t1 drop partition p3; +disconnect conn3; + +connection default; + +revoke select,alter,drop on mysqltest_1.* from mysqltest_1@localhost; +drop user mysqltest_1@localhost; +drop table t1; +drop schema mysqltest_1; + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.1 tests diff --git a/mysql-test/suite/pbxt/t/partition_hash.test b/mysql-test/suite/pbxt/t/partition_hash.test new file mode 100644 index 00000000000..087443fda59 --- /dev/null +++ b/mysql-test/suite/pbxt/t/partition_hash.test @@ -0,0 +1,149 @@ +#--disable_abort_on_error +# +# Simple test for the partition storage engine +# Taken fromm the select test +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# More partition pruning tests, especially on interval walking +# +create table t1 (a int unsigned) +partition by hash(a div 2) +partitions 4; +insert into t1 values (null),(0),(1),(2),(3),(4),(5),(6),(7); +select * from t1 where a < 0; +select * from t1 where a is null or (a >= 5 and a <= 7); +select * from t1 where a is null; +select * from t1 where a is not null; +select * from t1 where a >= 1 and a < 3; +select * from t1 where a >= 3 and a <= 5; +select * from t1 where a > 2 and a < 4; +select * from t1 where a > 3 and a <= 6; +select * from t1 where a > 5; +select * from t1 where a >= 1 and a <= 5; +explain partitions select * from t1 where a < 0; +explain partitions select * from t1 where a is null or (a >= 5 and a <= 7); +explain partitions select * from t1 where a is null; +explain partitions select * from t1 where a is not null; +explain partitions select * from t1 where a >= 1 and a < 3; +explain partitions select * from t1 where a >= 3 and a <= 5; +explain partitions select * from t1 where a > 2 and a < 4; +explain partitions select * from t1 where a > 3 and a <= 6; +explain partitions select * from t1 where a > 5; +explain partitions select * from t1 where a >= 1 and a <= 5; + +drop table t1; + +# +# Partition by hash, basic +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a + 2) +partitions 3 +(partition x1 tablespace ts1, + partition x2 tablespace ts2, + partition x3 tablespace ts3); + +insert into t1 values (1,1,1); +insert into t1 values (2,1,1); +insert into t1 values (3,1,1); +insert into t1 values (4,1,1); +insert into t1 values (5,1,1); + +select * from t1; + +update t1 set c=3 where b=1; +select * from t1; + +select b from t1 where a=3; +select b,c from t1 where a=1 AND b=1; + +delete from t1 where a=1; +delete from t1 where c=3; + +select * from t1; + +ALTER TABLE t1 +partition by hash (a + 3) +partitions 3 +(partition x1 tablespace ts1, + partition x2 tablespace ts2, + partition x3 tablespace ts3); +select * from t1; +drop table t1; + +# +# Partition by hash, only one partition +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by hash (a) +(partition x1); + +drop table t1; +# +# Partition by key, only one partition +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by key (a) +(partition x1); + +drop table t1; + +# +# Bug# 15968 - crash when INSERT with f1 = -1 into partition by hash(f1) +# +CREATE TABLE t1 (f1 INTEGER, f2 char(20)) ENGINE = 'MYISAM' PARTITION BY HASH(f1) PARTITIONS 2; +INSERT INTO t1 SET f1 = 0 - 1, f2 = '#######'; +select * from t1; +drop table t1; + +# +# BUG# 14524 Partitions: crash if blackhole +# +# Disable warnings to allow this test case to run without +# the Blackhole storage engine. +--disable_warnings +CREATE TABLE t1 (s1 int) ENGINE=BLACKHOLE PARTITION BY HASH (s1); +--enable_warnings +--error 0,ER_BINLOG_LOGGING_IMPOSSIBLE +INSERT INTO t1 VALUES (0); +DROP TABLE t1; + +# +# BUG 18423 Hash partitioning can lose rows in some queries +# +create table t1 (c1 int DEFAULT NULL, + c2 varchar (30) DEFAULT NULL, + c3 date DEFAULT NULL) +engine = myisam +partition by hash (to_days(c3)) +partitions 12; + +insert into t1 values +(136,'abc','2002-01-05'),(142,'abc','2002-02-14'),(162,'abc','2002-06-28'), +(182,'abc','2002-11-09'),(158,'abc','2002-06-01'),(184,'abc','2002-11-22'); +select * from t1; +select * from t1 where c3 between '2002-01-01' and '2002-12-31'; + +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/partition_list.test b/mysql-test/suite/pbxt/t/partition_list.test new file mode 100644 index 00000000000..7059a7c1931 --- /dev/null +++ b/mysql-test/suite/pbxt/t/partition_list.test @@ -0,0 +1,185 @@ +#--disable_abort_on_error +# +# Simple test for the partition storage engine +# testing list partitioning +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Bug 20733: Zerofill columns gives wrong result with partitioned tables +# +create table t1 (a int unsigned) +partition by list (a) +(partition p0 values in (0), + partition p1 values in (1), + partition pnull values in (null), + partition p2 values in (2)); + +insert into t1 values (null),(0),(1),(2); +select * from t1 where a < 2; +select * from t1 where a <= 0; +select * from t1 where a < 1; +select * from t1 where a > 0; +select * from t1 where a > 1; +select * from t1 where a >= 0; +select * from t1 where a >= 1; +select * from t1 where a is null; +select * from t1 where a is not null; +select * from t1 where a is null or a > 0; +drop table t1; + +create table t1 (a int unsigned, b int) +partition by list (a) +subpartition by hash (b) +subpartitions 2 +(partition p0 values in (0), + partition p1 values in (1), + partition pnull values in (null, 2), + partition p3 values in (3)); +insert into t1 values (0,0),(0,1),(1,0),(1,1),(null,0),(null,1); +insert into t1 values (2,0),(2,1),(3,0),(3,1); + +explain partitions select * from t1 where a is null; +select * from t1 where a is null; +explain partitions select * from t1 where a = 2; +select * from t1 where a = 2; +select * from t1 where a <= 0; +select * from t1 where a < 3; +select * from t1 where a >= 1 or a is null; +drop table t1; + +# +# Test ordinary list partitioning that it works ok +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null) +partition by list(a) +partitions 2 +(partition x123 values in (1,5,6), + partition x234 values in (4,7,8)); + +INSERT into t1 VALUES (1,1,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (2,1,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (3,1,1); +INSERT into t1 VALUES (4,1,1); +INSERT into t1 VALUES (5,1,1); +INSERT into t1 VALUES (6,1,1); +INSERT into t1 VALUES (7,1,1); +INSERT into t1 VALUES (8,1,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (9,1,1); +INSERT into t1 VALUES (1,2,1); +INSERT into t1 VALUES (1,3,1); +INSERT into t1 VALUES (1,4,1); +INSERT into t1 VALUES (7,2,1); +INSERT into t1 VALUES (7,3,1); +INSERT into t1 VALUES (7,4,1); + +SELECT * from t1; +SELECT * from t1 WHERE a=1; +SELECT * from t1 WHERE a=7; +SELECT * from t1 WHERE b=2; + +UPDATE t1 SET a=8 WHERE a=7 AND b=3; +SELECT * from t1 order by a, b; # PBXT: required for consistent result +UPDATE t1 SET a=8 WHERE a=5 AND b=1; +SELECT * from t1 order by a, b; # PBXT: required for consistent result + +DELETE from t1 WHERE a=8; +SELECT * from t1 order by a, b; # PBXT: required for consistent result +DELETE from t1 WHERE a=2; +SELECT * from t1 order by a, b; # PBXT: required for consistent result +DELETE from t1 WHERE a=5 OR a=6; +SELECT * from t1 order by a, b; # PBXT: required for consistent result + +ALTER TABLE t1 +partition by list(a) +partitions 2 +(partition x123 values in (1,5,6), + partition x234 values in (4,7,8)); +SELECT * from t1; +INSERT into t1 VALUES (6,2,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (2,2,1); + +drop table t1; +# +# Subpartition by hash, two partitions and two subpartitions +# Defined node group +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by list (a) +subpartition by hash (a+b) +( partition x1 values in (1,2,3) + ( subpartition x11 nodegroup 0, + subpartition x12 nodegroup 1), + partition x2 values in (4,5,6) + ( subpartition x21 nodegroup 0, + subpartition x22 nodegroup 1) +); + +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (7,1,1); +UPDATE t1 SET a=5 WHERE a=1; +SELECT * from t1; +UPDATE t1 SET a=6 WHERE a=4; +SELECT * from t1; +DELETE from t1 WHERE a=6; +SELECT * from t1; + +drop table t1; + +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by list (a) +(partition x1 values in (1,2,9,4) tablespace ts1); + +drop table t1; + +# +#Bug #17173 Partitions: less-than search fails +# +CREATE TABLE t1 (s1 int) PARTITION BY LIST (s1) +(PARTITION p1 VALUES IN (1), +PARTITION p2 VALUES IN (2), +PARTITION p3 VALUES IN (3), +PARTITION p4 VALUES IN (4), +PARTITION p5 VALUES IN (5)); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +SELECT COUNT(*) FROM t1 WHERE s1 < 3; +DROP TABLE t1; + +# +# Bug 19281 Partitions: Auto-increment value lost +# +create table t1 (a int auto_increment primary key) +auto_increment=100 +partition by list (a) +(partition p0 values in (1, 100)); +create index inx on t1 (a); +insert into t1 values (null); +select * from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log + diff --git a/mysql-test/suite/pbxt/t/partition_order.test b/mysql-test/suite/pbxt/t/partition_order.test new file mode 100644 index 00000000000..857b1fe33e7 --- /dev/null +++ b/mysql-test/suite/pbxt/t/partition_order.test @@ -0,0 +1,848 @@ +#--disable_abort_on_error +# +# Simple test for the partition storage engine +# Focuses on tests of ordered index read +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Ordered index read, int type +# +CREATE TABLE t1 ( +a int not null, +b int not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 order by b; + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, unsigned int type +# +CREATE TABLE t1 ( +a int not null, +b int unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, tiny int type +# +CREATE TABLE t1 ( +a int not null, +b tinyint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, unsigned tinyint type +# +CREATE TABLE t1 ( +a int not null, +b tinyint unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, smallint type +# +CREATE TABLE t1 ( +a int not null, +b smallint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, unsigned smallint type +# +CREATE TABLE t1 ( +a int not null, +b smallint unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; +# +# Ordered index read, mediumint type +# +CREATE TABLE t1 ( +a int not null, +b mediumint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, unsigned int type +# +CREATE TABLE t1 ( +a int not null, +b mediumint unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, unsigned bigint type +# +CREATE TABLE t1 ( +a int not null, +b bigint unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, bigint type +# +CREATE TABLE t1 ( +a int not null, +b bigint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; +# +# Ordered index read, bigint type +# +CREATE TABLE t1 ( +a int not null, +b bigint not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, float type +# +CREATE TABLE t1 ( +a int not null, +b float not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, double type +# +CREATE TABLE t1 ( +a int not null, +b double not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, unsigned double type +# +CREATE TABLE t1 ( +a int not null, +b double unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, unsigned float type +# +CREATE TABLE t1 ( +a int not null, +b float unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, double precision type +# +CREATE TABLE t1 ( +a int not null, +b double precision not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; +# +# Ordered index read, unsigned double precision type +# +CREATE TABLE t1 ( +a int not null, +b double precision unsigned not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, decimal type +# +CREATE TABLE t1 ( +a int not null, +b decimal not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (2, 5); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; +# +# Ordered index read, char type +# +CREATE TABLE t1 ( +a int not null, +b char(10) not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b > 0 order by b; + +drop table t1; + +# +# Ordered index read, varchar type +# +CREATE TABLE t1 ( +a int not null, +b varchar(10) not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b > '0' order by b; + +drop table t1; +# +# Ordered index read, varchar type limited index size +# +CREATE TABLE t1 ( +a int not null, +b varchar(10) not null, +primary key(a), +index (b(5))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b > '0' order by b; + +drop table t1; + +# +# Ordered index read, varchar binary type +# +CREATE TABLE t1 ( +a int not null, +b varchar(10) binary not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b > '0' order by b; + +drop table t1; + +# +# Ordered index read, tinytext type +# +CREATE TABLE t1 ( +a int not null, +b tinytext not null, +primary key(a), +index (b(10))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b > '0' order by b; + +drop table t1; +# +# Ordered index read, text type +# +CREATE TABLE t1 ( +a int not null, +b text not null, +primary key(a), +index (b(10))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b > '0' order by b; + +drop table t1; + +# +# Ordered index read, mediumtext type +# +CREATE TABLE t1 ( +a int not null, +b mediumtext not null, +primary key(a), +index (b(10))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b > '0' order by b; + +drop table t1; +# +# Ordered index read, longtext type +# +CREATE TABLE t1 ( +a int not null, +b longtext not null, +primary key(a), +index (b(10))) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b > '0' order by b; + +drop table t1; +# +# Ordered index read, enum type +# +CREATE TABLE t1 ( +a int not null, +b enum('1','2', '4', '5') not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b >= '1' order by b; + +drop table t1; +# +# Ordered index read, set type +# +CREATE TABLE t1 ( +a int not null, +b set('1','2', '4', '5') not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '1'); +INSERT into t1 values (2, '5'); +INSERT into t1 values (30, '4'); +INSERT into t1 values (35, '2'); + +select * from t1 force index (b) where b >= '1' order by b; + +drop table t1; +# +# Ordered index read, date type +# +CREATE TABLE t1 ( +a int not null, +b date not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '2001-01-01'); +INSERT into t1 values (2, '2005-01-01'); +INSERT into t1 values (30, '2004-01-01'); +INSERT into t1 values (35, '2002-01-01'); + +select * from t1 force index (b) where b > '2000-01-01' order by b; + +drop table t1; +# +# Ordered index read, datetime type +# +CREATE TABLE t1 ( +a int not null, +b datetime not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '2001-01-01 00:00:00'); +INSERT into t1 values (2, '2005-01-01 00:00:00'); +INSERT into t1 values (30, '2004-01-01 00:00:00'); +INSERT into t1 values (35, '2002-01-01 00:00:00'); + +select * from t1 force index (b) where b > '2000-01-01 00:00:00' order by b; + +drop table t1; +# +# Ordered index read, timestamp type +# +CREATE TABLE t1 ( +a int not null, +b timestamp not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '2001-01-01 00:00:00'); +INSERT into t1 values (2, '2005-01-01 00:00:00'); +INSERT into t1 values (30, '2004-01-01 00:00:00'); +INSERT into t1 values (35, '2002-01-01 00:00:00'); + +select * from t1 force index (b) where b > '2000-01-01 00:00:00' order by b; + +drop table t1; +# +# Ordered index read, time type +# +CREATE TABLE t1 ( +a int not null, +b time not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, '01:00:00'); +INSERT into t1 values (2, '05:00:00'); +INSERT into t1 values (30, '04:00:00'); +INSERT into t1 values (35, '02:00:00'); + +select * from t1 force index (b) where b > '00:00:00' order by b; + +drop table t1; +# +# Ordered index read, year type +# +CREATE TABLE t1 ( +a int not null, +b year not null, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 2001); +INSERT into t1 values (2, 2005); +INSERT into t1 values (30, 2004); +INSERT into t1 values (35, 2002); + +select * from t1 force index (b) where b > 2000 order by b; + +drop table t1; +# +# Ordered index read, bit(5) type +# +CREATE TABLE t1 ( +a int not null, +b bit(5) not null, +c int, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, b'00001', NULL); +INSERT into t1 values (2, b'00101', 2); +INSERT into t1 values (30, b'00100', 2); +INSERT into t1 values (35, b'00010', NULL); + +select a from t1 force index (b) where b > b'00000' order by b; + +drop table t1; +# +# Ordered index read, bit(15) type +# +CREATE TABLE t1 ( +a int not null, +b bit(15) not null, +c int, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, b'000000000000001', NULL); +INSERT into t1 values (2, b'001010000000101', 2); +INSERT into t1 values (30, b'001000000000100', 2); +INSERT into t1 values (35, b'000100000000010', NULL); + +select a from t1 force index (b) where b > b'000000000000000' order by b; + +drop table t1; + +# +# Ordered index read, NULL values +# +CREATE TABLE t1 ( +a int not null, +b int, +primary key(a), +index (b)) +partition by range (a) +partitions 2 +(partition x1 values less than (25), + partition x2 values less than (100)); + +# Insert a couple of tuples +INSERT into t1 values (1, 1); +INSERT into t1 values (5, NULL); +INSERT into t1 values (2, 4); +INSERT into t1 values (3, 3); +INSERT into t1 values (4, 5); +INSERT into t1 values (7, 1); +INSERT into t1 values (6, 6); +INSERT into t1 values (30, 4); +INSERT into t1 values (35, 2); +INSERT into t1 values (40, NULL); + +select * from t1 force index (b) where b < 10 OR b IS NULL order by b; +select * from t1 force index (b) where b < 10 ORDER BY b; +select * from t1 force index (b) where b < 10 ORDER BY b DESC; +drop table t1; + +create table t1 (a int not null, b int, c varchar(20), key (a,b,c)) +partition by range (b) +(partition p0 values less than (5), + partition p1 values less than (10)); +INSERT into t1 values (1,1,'1'),(2,2,'2'),(1,3,'3'),(2,4,'4'),(1,5,'5'); +INSERT into t1 values (2,6,'6'),(1,7,'7'),(2,8,'8'),(1,9,'9'); +INSERT into t1 values (1, NULL, NULL), (2, NULL, '10'); +select * from t1 where a = 1 order by a desc, b desc; +select * from t1 where a = 1 order by b desc; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/partition_pruning.test b/mysql-test/suite/pbxt/t/partition_pruning.test new file mode 100644 index 00000000000..234eb67535e --- /dev/null +++ b/mysql-test/suite/pbxt/t/partition_pruning.test @@ -0,0 +1,760 @@ +# +# Partition pruning tests. Currently we only detect which partitions to +# prune, so the test is EXPLAINs. +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +--enable_warnings + + +# Check if we can infer from condition on partition fields that +# no records will match. +create table t1 ( a int not null) partition by hash(a) partitions 2; +insert into t1 values (1),(2),(3); +explain select * from t1 where a=5 and a=6; +drop table t1; + +# Simple HASH partitioning +create table t1 ( + a int(11) not null +) partition by hash (a) partitions 2; +insert into t1 values (1),(2),(3); + +explain partitions select * from t1 where a=1; +explain partitions select * from t1 where a=2; +explain partitions select * from t1 where a=1 or a=2; + +# Partitioning over several fields +create table t2 ( + a int not null, + b int not null +) partition by key(a,b) partitions 2; +insert into t2 values (1,1),(2,2),(3,3); + +explain partitions select * from t2 where a=1; +explain partitions select * from t2 where b=1; + +explain partitions select * from t2 where a=1 and b=1; + +# RANGE(expr) partitioning +create table t3 ( + a int +) +partition by range (a*1) ( + partition p0 values less than (10), + partition p1 values less than (20) +); +insert into t3 values (5),(15); + +explain partitions select * from t3 where a=11; +explain partitions select * from t3 where a=10; +explain partitions select * from t3 where a=20; + +explain partitions select * from t3 where a=30; + +# LIST(expr) partitioning +create table t4 (a int not null, b int not null) partition by LIST (a+b) ( + partition p0 values in (12), + partition p1 values in (14) +); +insert into t4 values (10,2), (10,4); + +# empty OR one +explain partitions select * from t4 where (a=10 and b=1) or (a=10 and b=2); + +# empty OR one OR empty +explain partitions select * from t4 + where (a=10 and b=1) or (a=10 and b=2) or (a=10 and b = 3); + +# one OR empty OR one +explain partitions select * from t4 where (a=10 and b=2) or (a=10 and b=3) + or (a=10 and b = 4); + +# empty OR full +explain partitions select * from t4 where (a=10 and b=1) or a=11; + +# one OR full +explain partitions select * from t4 where (a=10 and b=2) or a=11; + +drop table t1, t2, t3, t4; + +# LIST(expr)/HASH subpartitioning. +create table t5 (a int not null, b int not null, + c int not null, d int not null) +partition by LIST(a+b) subpartition by HASH (c+d) subpartitions 2 +( + partition p0 values in (12), + partition p1 values in (14) +); + +insert into t5 values (10,2,0,0), (10,4,0,0), (10,2,0,1), (10,4,0,1); +explain partitions select * from t5; + +# empty OR one OR empty +explain partitions select * from t5 + where (a=10 and b=1) or (a=10 and b=2) or (a=10 and b = 3); + +# one OR empty OR one +explain partitions select * from t5 where (a=10 and b=2) or (a=10 and b=3) + or (a=10 and b = 4); + +# conditions on subpartitions only +explain partitions select * from t5 where (c=1 and d=1); +explain partitions select * from t5 where (c=2 and d=1); + +# mixed partition/subpartitions. +explain partitions select * from t5 where (a=10 and b=2 and c=1 and d=1) or +(c=2 and d=1); + +# same as above +explain partitions select * from t5 where (a=10 and b=2 and c=1 and d=1) or +(b=2 and c=2 and d=1); + +# LIST(field) partitioning, interval analysis. +create table t6 (a int not null) partition by LIST(a) ( + partition p1 values in (1), + partition p3 values in (3), + partition p5 values in (5), + partition p7 values in (7), + partition p9 values in (9) +); +insert into t6 values (1),(3),(5); + +explain partitions select * from t6 where a < 1; +explain partitions select * from t6 where a <= 1; +explain partitions select * from t6 where a > 9; +explain partitions select * from t6 where a >= 9; + +explain partitions select * from t6 where a > 0 and a < 5; +explain partitions select * from t6 where a > 5 and a < 12; +explain partitions select * from t6 where a > 3 and a < 8 ; + +explain partitions select * from t6 where a >= 0 and a <= 5; +explain partitions select * from t6 where a >= 5 and a <= 12; +explain partitions select * from t6 where a >= 3 and a <= 8; + +explain partitions select * from t6 where a > 3 and a < 5; + +drop table t6; + +create table t6 (a int unsigned not null) partition by LIST(a) ( + partition p1 values in (1), + partition p3 values in (3), + partition p5 values in (5), + partition p7 values in (7), + partition p9 values in (9) +); +insert into t6 values (1),(3),(5); + +explain partitions select * from t6 where a < 1; +explain partitions select * from t6 where a <= 1; +explain partitions select * from t6 where a > 9; +explain partitions select * from t6 where a >= 9; + +explain partitions select * from t6 where a > 0 and a < 5; +explain partitions select * from t6 where a > 5 and a < 12; +explain partitions select * from t6 where a > 3 and a < 8 ; + +explain partitions select * from t6 where a >= 0 and a <= 5; +explain partitions select * from t6 where a >= 5 and a <= 12; +explain partitions select * from t6 where a >= 3 and a <= 8; + +explain partitions select * from t6 where a > 3 and a < 5; + +# RANGE(field) partitioning, interval analysis. +create table t7 (a int not null) partition by RANGE(a) ( + partition p10 values less than (10), + partition p30 values less than (30), + partition p50 values less than (50), + partition p70 values less than (70), + partition p90 values less than (90) +); +insert into t7 values (10),(30),(50); + +# leftmost intervals +explain partitions select * from t7 where a < 5; +explain partitions select * from t7 where a < 10; +explain partitions select * from t7 where a <= 10; +explain partitions select * from t7 where a = 10; + +#rightmost intervals +explain partitions select * from t7 where a < 90; +explain partitions select * from t7 where a = 90; +explain partitions select * from t7 where a > 90; +explain partitions select * from t7 where a >= 90; + +# misc intervals +explain partitions select * from t7 where a > 11 and a < 29; + +drop table t7; + +create table t7 (a int unsigned not null) partition by RANGE(a) ( + partition p10 values less than (10), + partition p30 values less than (30), + partition p50 values less than (50), + partition p70 values less than (70), + partition p90 values less than (90) +); +insert into t7 values (10),(30),(50); + +# leftmost intervals +explain partitions select * from t7 where a < 5; +explain partitions select * from t7 where a < 10; +explain partitions select * from t7 where a <= 10; +explain partitions select * from t7 where a = 10; + +#rightmost intervals +explain partitions select * from t7 where a < 90; +explain partitions select * from t7 where a = 90; +explain partitions select * from t7 where a > 90; +explain partitions select * from t7 where a >= 90; + +# misc intervals +explain partitions select * from t7 where a > 11 and a < 29; + +# LIST(monontonic_func) partitioning +create table t8 (a date not null) partition by RANGE(YEAR(a)) ( + partition p0 values less than (1980), + partition p1 values less than (1990), + partition p2 values less than (2000) +); +insert into t8 values ('1985-05-05'),('1995-05-05'); + +explain partitions select * from t8 where a < '1980-02-02'; + +# LIST(strict_monotonic_func) partitioning +create table t9 (a date not null) partition by RANGE(TO_DAYS(a)) ( + partition p0 values less than (732299), -- 2004-12-19 + partition p1 values less than (732468), -- 2005-06-06 + partition p2 values less than (732664) -- 2005-12-19 +); +insert into t9 values ('2005-05-05'), ('2005-04-04'); + +explain partitions select * from t9 where a < '2004-12-19'; +explain partitions select * from t9 where a <= '2004-12-19'; + +drop table t5,t6,t7,t8,t9; + +# Test the case where we can't create partitioning 'index' +# +# Not supported after bug#18198 is fixed +# +#create table t1 (a enum('a','b','c','d') default 'a') +# partition by hash (ascii(a)) partitions 2; +#insert into t1 values ('a'),('b'),('c'); +#explain partitions select * from t1 where a='b'; +#drop table t1; + +# +# Test cases for bugs found in code review: +# +create table t1 ( + a1 int not null +) +partition by range (a1) ( + partition p0 values less than (3), + partition p1 values less than (6), + partition p2 values less than (9) +); +insert into t1 values (1),(2),(3); +explain partitions select * from t1 where a1 > 3; +explain partitions select * from t1 where a1 >= 3; + +explain partitions select * from t1 where a1 < 3 and a1 > 3; +drop table t1; + +# +create table t3 (a int, b int) + partition by list(a) subpartition by hash(b) subpartitions 4 ( + partition p0 values in (1), + partition p1 values in (2), + partition p2 values in (3), + partition p3 values in (4) + ); +insert into t3 values (1,1),(2,2),(3,3); + +explain partitions select * from t3 where a=2 or b=1; +explain partitions select * from t3 where a=4 or b=2; +explain partitions select * from t3 where (a=2 or b=1) and (a=4 or b=2) ; +drop table t3; + +# Test for NULLs +create table t1 (a int) partition by hash(a) partitions 2; +insert into t1 values (1),(2); +explain partitions select * from t1 where a is null; + +# this uses both partitions +explain partitions select * from t1 where a is not null; +drop table t1; + +# Join tests +create table t1 (a int not null, b int not null, key(a), key(b)) + partition by hash(a) partitions 4; +insert into t1 values (1,1),(2,2),(3,3),(4,4); + +explain partitions +select * from t1 X, t1 Y +where X.b = Y.b and (X.a=1 or X.a=2) and (Y.a=2 or Y.a=3); + +explain partitions +select * from t1 X, t1 Y where X.a = Y.a and (X.a=1 or X.a=2); + +drop table t1; + +# Tests for "short ranges" +create table t1 (a int) partition by hash(a) partitions 20; +insert into t1 values (1),(2),(3); +explain partitions select * from t1 where a > 1 and a < 3; +explain partitions select * from t1 where a >= 1 and a < 3; +explain partitions select * from t1 where a > 1 and a <= 3; +explain partitions select * from t1 where a >= 1 and a <= 3; +drop table t1; + +create table t1 (a int, b int) + partition by list(a) subpartition by hash(b) subpartitions 20 +( + partition p0 values in (0), + partition p1 values in (1), + partition p2 values in (2), + partition p3 values in (3) +); +insert into t1 values (1,1),(2,2),(3,3); + +explain partitions select * from t1 where b > 1 and b < 3; +explain partitions select * from t1 where b > 1 and b < 3 and (a =1 or a =2); +drop table t1; + +# Test partition pruning for single-table UPDATE/DELETE. +# TODO: Currently we test only "all partitions pruned away" case. Add more +# tests when the patch that makes use of partition pruning results at +# execution phase is pushed. + +create table t1 (a int) partition by list(a) ( + partition p0 values in (1,2), + partition p1 values in (3,4) +); +insert into t1 values (1),(1),(2),(2),(3),(4),(3),(4); + +# This won't do any table access +flush status; +update t1 set a=100 where a=5; +show status like 'Handler_read_rnd_next'; + +# ... as compared to this, which will scan both partitions +flush status; +update t1 set a=100 where a+1=5+1; +show status like 'Handler_read_rnd_next'; + +# Same as above for DELETE: +flush status; +delete from t1 where a=5; +show status like 'Handler_read_rnd_next'; + +flush status; +delete from t1 where a+1=5+1; +show status like 'Handler_read_rnd_next'; + +# Same as above multi-table UPDATE/DELETE +create table t2 like t1; +insert into t2 select * from t2; + +flush status; +update t1,t2 set t1.a=1000, t2.a=1000 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +# ^ This shows 3 accesses, these are caused by const table reads. +# They should vanish when partition pruning results are used. + +flush status; +delete t1,t2 from t1, t2 where t1.a=5 and t2.a=5; +show status like 'Handler_read_rnd_next'; +drop table t1,t2; + +# +# WL#2986 Tests (Checking if partition pruning results are used at query +# execution phase) +# +CREATE TABLE `t1` ( + `a` int(11) default NULL +); +INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +CREATE TABLE `t2` ( + `a` int(11) default NULL, + KEY `a` (`a`) +) ; + +insert into t2 select A.a + 10*(B.a + 10* C.a) from t1 A, t1 B, t1 C ; +insert into t1 select a from t2; + +drop table t2; +CREATE TABLE `t2` ( + `a` int(11) default NULL, + `b` int(11) default NULL +) +PARTITION BY RANGE (a) ( +PARTITION p0 VALUES LESS THAN (200), +PARTITION p1 VALUES LESS THAN (400), +PARTITION p2 VALUES LESS THAN (600), +PARTITION p3 VALUES LESS THAN (800), +PARTITION p4 VALUES LESS THAN (1001)); + +insert into t2 select a,1 from t1 where a < 200; +insert into t2 select a,2 from t1 where a >= 200 and a < 400; +insert into t2 select a,3 from t1 where a >= 400 and a < 600; +insert into t2 select a,4 from t1 where a >= 600 and a < 800; +insert into t2 select a,5 from t1 where a >= 800 and a < 1001; + +explain partitions select * from t2; +explain partitions select * from t2 where a < 801 and a > 200; +explain partitions select * from t2 where a < 801 and a > 800; +explain partitions select * from t2 where a > 600; +explain partitions select * from t2 where a > 600 and b = 1; +explain partitions select * from t2 where a > 600 and b = 4; +explain partitions select * from t2 where a > 600 and b = 5; +explain partitions select * from t2 where b = 5; + +flush status; +update t2 set b = 100 where b = 6; +show status like 'Handler_read_rnd_next'; +flush status; +update t2 set a = 1002 where a = 1001; +show status like 'Handler_read_rnd_next'; +flush status; +update t2 set b = 6 where a = 600; +show status like 'Handler_read_rnd_next'; +flush status; +update t2 set b = 6 where a > 600 and a < 800; +show status like 'Handler_read_rnd_next'; +flush status; +delete from t2 where a > 600; +show status like 'Handler_read_rnd_next'; + +drop table t2; +CREATE TABLE `t2` ( + `a` int(11) default NULL, + `b` int(11) default NULL, + index (b) +) +PARTITION BY RANGE (a) ( +PARTITION p0 VALUES LESS THAN (200), +PARTITION p1 VALUES LESS THAN (400), +PARTITION p2 VALUES LESS THAN (600), +PARTITION p3 VALUES LESS THAN (800), +PARTITION p4 VALUES LESS THAN (1001)); + +insert into t2 select a,1 from t1 where a < 100; +insert into t2 select a,2 from t1 where a >= 200 and a < 300; +insert into t2 select a,3 from t1 where a >= 300 and a < 400; +insert into t2 select a,4 from t1 where a >= 400 and a < 500; +insert into t2 select a,5 from t1 where a >= 500 and a < 600; +insert into t2 select a,6 from t1 where a >= 600 and a < 700; +insert into t2 select a,7 from t1 where a >= 700 and a < 800; +insert into t2 select a,8 from t1 where a >= 800 and a < 900; +insert into t2 select a,9 from t1 where a >= 900 and a < 1001; + +explain partitions select * from t2; +# not using indexes +explain partitions select * from t2 where a = 101; +explain partitions select * from t2 where a = 550; +explain partitions select * from t2 where a = 833; +explain partitions select * from t2 where (a = 100 OR a = 900); +explain partitions select * from t2 where (a > 100 AND a < 600); +# PBXT: wait for sweeper +analyze table t2; +explain partitions select * from t2 where b = 4; +explain extended select * from t2 where b = 6; +explain partitions select * from t2 where b = 6; +explain extended select * from t2 where b in (1,3,5); +explain partitions select * from t2 where b in (1,3,5); +explain extended select * from t2 where b in (2,4,6); +explain partitions select * from t2 where b in (2,4,6); +explain extended select * from t2 where b in (7,8,9); +explain partitions select * from t2 where b in (7,8,9); +explain extended select * from t2 where b > 5; +explain partitions select * from t2 where b > 5; +explain extended select * from t2 where b > 5 and b < 8; +explain partitions select * from t2 where b > 5 and b < 8; +explain extended select * from t2 where b > 5 and b < 7; +explain partitions select * from t2 where b > 5 and b < 7; +explain extended select * from t2 where b > 0 and b < 5; +explain partitions select * from t2 where b > 0 and b < 5; + +flush status; +update t2 set a = 111 where b = 10; +show status like 'Handler_read_rnd_next'; +show status like 'Handler_read_key'; +flush status; +update t2 set a = 111 where b in (5,6); +show status like 'Handler_read_rnd_next'; +show status like 'Handler_read_key'; +flush status; +update t2 set a = 222 where b = 7; +show status like 'Handler_read_rnd_next'; +show status like 'Handler_read_key'; +flush status; +delete from t2 where b = 7; +show status like 'Handler_read_rnd_next'; +show status like 'Handler_read_key'; +flush status; +delete from t2 where b > 5; +show status like 'Handler_read_rnd_next'; +show status like 'Handler_read_key'; +show status like 'Handler_read_prev'; +show status like 'Handler_read_next'; +flush status; +delete from t2 where b < 5 or b > 3; +show status like 'Handler_read_rnd_next'; +show status like 'Handler_read_key'; +show status like 'Handler_read_prev'; +show status like 'Handler_read_next'; + +drop table t1, t2; + +# BUG#18025 +# part1: mediumint columns +create table t1 ( f_int1 mediumint, f_int2 integer) +partition by list(mod(f_int1,4)) ( + partition p_3 values in (-3), + partition p_2 values in (-2), + partition p_1 values in (-1), + partition p0 values in (0), + partition p1 values in (1), + partition p2 values in (2), + partition p3 values in (3) +); + +insert into t1 values (9, 9), (8, 8), (7, 7), (6, 6), (5, 5), + (4, 4), (3, 3), (2, 2), (1, 1); +select * from t1 where f_int1 between 5 and 15 order by f_int1; + +drop table t1; + +# part2: bug in pruning code +#create table t1 (a char(10) binary) +#partition by list(ascii(a)) +# (partition p1 values in (ascii('a')), +# partition p2 values in (ascii('b')), +# partition p3 values in (ascii('c')), +# partition p4 values in (ascii('d')), +# partition p5 values in (ascii('e'))); +#insert into t1 values ('a'),('bb'),('ccc'),('dddd'),('eeEee'); +#select * from t1 where a>='a' and a <= 'dddd'; +#explain partitions select * from t1 where a>='a' and a <= 'dddd'; +#drop table t1; + +# BUG#18659: Assertion failure when subpartitioning is used and partition is +# "IS NULL" +create table t1 (f_int1 integer) partition by list(abs(mod(f_int1,2))) + subpartition by hash(f_int1) subpartitions 2 +( + partition part1 values in (0), + partition part2 values in (1), + partition part4 values in (null) +); +insert into t1 set f_int1 = null; + +select * from t1 where f_int1 is null; +explain partitions select * from t1 where f_int1 is null; +drop table t1; + +# +# BUG#18558 +# +create table t1 (a int not null, b int not null) +partition by list(a) + subpartition by hash(b) subpartitions 4 +( + partition p0 values in (1), + partition p1 values in (2), + partition p2 values in (3) +); +insert into t1 values (1,1),(1,2),(1,3),(1,4), + (2,1),(2,2),(2,3),(2,4); +explain partitions select * from t1 where a=1 AND (b=1 OR b=2); +drop table t1; + +create table t1 (a int, b int not null) +partition by list(a) + subpartition by hash(b) subpartitions 2 +( + partition p0 values in (1), + partition p1 values in (2), + partition p2 values in (3), + partition pn values in (NULL) +); +insert into t1 values (1,1),(1,2),(1,3),(1,4), + (2,1),(2,2),(2,3),(2,4), (NULL,1); + +explain partitions select * from t1 where a IS NULL AND (b=1 OR b=2); + +explain partitions select * from t1 where (a IS NULL or a < 1) AND (b=1 OR b=2); +explain partitions select * from t1 where (a IS NULL or a < 2) AND (b=1 OR b=2); +explain partitions select * from t1 where (a IS NULL or a <= 1) AND (b=1 OR b=2); + +drop table t1; + +create table t1 ( a int) partition by list (MOD(a, 10)) +( partition p0 values in (0), partition p1 values in (1), + partition p2 values in (2), partition p3 values in (3), + partition p4 values in (4), partition p5 values in (5), + partition p6 values in (6), partition pn values in (NULL) +); +insert into t1 values (NULL), (0),(1),(2),(3),(4),(5),(6); +explain partitions select * from t1 where a is null or a < 2; +drop table t1; + +# Testcase from BUG#18751 +create table t1 (s1 int) partition by list (s1) + (partition p1 values in (0), + partition p2 values in (1), + partition p3 values in (null)); + +insert into t1 values (0),(1),(null); + +select count(*) from t1 where s1 < 0 or s1 is null; +explain partitions select count(*) from t1 where s1 < 0 or s1 is null; +drop table t1; + +# No tests for NULLs in RANGE(monotonic_expr()) - they depend on BUG#15447 +# being fixed. + +# +# BUG#17946 Like searches fail with partitioning +# +create table t1 (a char(32) primary key) +partition by key() +partitions 100; +insert into t1 values ('na'); +select * from t1; +select * from t1 where a like 'n%'; +drop table t1; + + +# BUG#19055 Crashes for varchar_col=NUMBER or varchar_col IS NULL +create table t1 (s1 varchar(15)) partition by key (s1); +select * from t1 where s1 = 0 or s1 is null; +insert into t1 values ('aa'),('bb'),('0'); +explain partitions select * from t1 where s1 = 0 or s1 is null; +drop table t1; + +# +# BUG#19684: EXPLAIN PARTITIONS produces garbage in 'partitions' column when +# the length of string to be displayed exceeds some limit. +create table t2 (a int, b int) + partition by LIST(a) + subpartition by HASH(b) subpartitions 40 +( partition p_0_long_partition_name values in(1), + partition p_1_long_partition_name values in(2)); + +insert into t2 values (1,1),(2,2); + +--vertical_results +explain partitions select * from t2; +--horizontal_results +drop table t2; + + +# BUG#20484 "Partitions: crash with explain and union" +create table t1 (s1 int); +explain partitions select 1 from t1 union all select 2; +drop table t1; + + +# BUG#20257: partition pruning test coverage for BIGINT UNSIGNED +create table t1 (a bigint unsigned not null) partition by range(a) ( + partition p0 values less than (10), + partition p1 values less than (100), + partition p2 values less than (1000), + partition p3 values less than (18446744073709551000), + partition p4 values less than (18446744073709551614) +); +insert into t1 values (5),(15),(105),(1005); +insert into t1 values (18446744073709551000+1); +insert into t1 values (18446744073709551614-1); + +explain partitions select * from t1 where a < 10; +explain partitions select * from t1 + where a >= 18446744073709551000-1 and a <= 18446744073709551000+1; + +explain partitions select * from t1 + where a between 18446744073709551001 and 18446744073709551002; + +explain partitions select * from t1 where a = 18446744073709551000; +explain partitions select * from t1 where a = 18446744073709551613; +explain partitions select * from t1 where a = 18446744073709551614; +drop table t1; +# +# Test all variants of usage for interval_via_mapping +# and interval_via_walking +# +# t1 will use interval_via_mapping since it uses a +# monotonic function, whereas t2 will use +# interval_via_walking since the intervals are short +# and the function isn't monotonic (it is, but it isn't +# discovered in this version). +# + create table t1 (a int) + partition by range(a) ( + partition p0 values less than (64), + partition p1 values less than (128), + partition p2 values less than (255) +); + +create table t2 (a int) + partition by range(a+0) ( + partition p0 values less than (64), + partition p1 values less than (128), + partition p2 values less than (255) +); + +insert into t1 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE); +insert into t2 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE); +explain partitions select * from t1 where a=0; +explain partitions select * from t2 where a=0; +explain partitions select * from t1 where a=0xFE; +explain partitions select * from t2 where a=0xFE; +explain partitions select * from t1 where a > 0xFE AND a <= 0xFF; +explain partitions select * from t2 where a > 0xFE AND a <= 0xFF; +explain partitions select * from t1 where a >= 0xFE AND a <= 0xFF; +explain partitions select * from t2 where a >= 0xFE AND a <= 0xFF; +explain partitions select * from t1 where a < 64 AND a >= 63; +explain partitions select * from t2 where a < 64 AND a >= 63; +explain partitions select * from t1 where a <= 64 AND a >= 63; +explain partitions select * from t2 where a <= 64 AND a >= 63; +drop table t1; +drop table t2; + +create table t1(a bigint unsigned not null) partition by range(a+0) ( + partition p1 values less than (10), + partition p2 values less than (20), + partition p3 values less than (2305561538531885056), + partition p4 values less than (2305561538531950591) +); + +insert into t1 values (9),(19),(0xFFFF0000FFFF000-1), (0xFFFF0000FFFFFFF-1); +insert into t1 values (9),(19),(0xFFFF0000FFFF000-1), (0xFFFF0000FFFFFFF-1); + +explain partitions select * from t1 where + a >= 2305561538531885056-10 and a <= 2305561538531885056-8; + +explain partitions select * from t1 where + a > 0xFFFFFFFFFFFFFFEC and a < 0xFFFFFFFFFFFFFFEE; + +explain partitions select * from t1 where a>=0 and a <= 0xFFFFFFFFFFFFFFFF; +drop table t1; + +create table t1 (a bigint) partition by range(a+0) ( + partition p1 values less than (-1000), + partition p2 values less than (-10), + partition p3 values less than (10), + partition p4 values less than (1000) +); +insert into t1 values (-15),(-5),(5),(15),(-15),(-5),(5),(15); +explain partitions select * from t1 where a>-2 and a <=0; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/partition_range.test b/mysql-test/suite/pbxt/t/partition_range.test new file mode 100644 index 00000000000..ec9e78670d4 --- /dev/null +++ b/mysql-test/suite/pbxt/t/partition_range.test @@ -0,0 +1,763 @@ +#--disable_abort_on_error +# +# Simple test for the partition storage engine +# Focuses on range partitioning tests +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# BUG 18198: Various tests for partition functions +# +#create table t1 (a varchar(10) charset latin1 collate latin1_bin, b int) +#partition by range (ascii(a) * b) +#(partition p0 values less than (2), partition p1 values less than (4000)); +#insert into t1 values ('a ', 2),('a',3); +#drop table t1; + +#create table t1 (a varchar(10) charset latin1 collate latin1_bin, b int) +#partition by range (b* ascii(a) * b) +#(partition p0 values less than (2), partition p1 values less than (4000)); +#insert into t1 values ('a ', 2),('a',3); +#drop table t1; + +#create table t1 (a varchar(10) charset latin1 collate latin1_bin, +# b varchar(10) charset latin1 collate latin1_bin) +#partition by range (ascii(b) * ascii(a)) +#(partition p0 values less than (2), partition p1 values less than (40000)); +#insert into t1 values ('a ', 'b '),('a','b'); +#drop table t1; + +#create table t1 (a varchar(10) charset latin1 collate latin1_bin, +# b varchar(10) charset latin1 collate latin1_bin) +#partition by range (ascii(a) * ascii(b)) +#(partition p0 values less than (2), partition p1 values less than (40000)); +#insert into t1 values ('a ', 'b '),('a','b'); +#drop table t1; + +#create table t1 (a varchar(10) charset latin1 collate latin1_bin, +# b varchar(10) charset latin1 collate latin1_bin, c int) +#partition by range (ascii(a) * c) +#(partition p0 values less than (2), partition p1 values less than (4000)); +#insert into t1 values ('a ', 'b ', 2),('a','b', 3); +#drop table t1; + +#create table t1 (a varchar(10) charset latin1 collate latin1_bin, +# b varchar(10) charset latin1 collate latin1_bin, c int) +#partition by range (c * ascii(a)) +#(partition p0 values less than (2), partition p1 values less than (4000)); +#insert into t1 values ('a ', 'b ', 2),('a','b', 3); +#drop table t1; + +# +# More checks for partition pruning +# +create table t1 (a int unsigned) +partition by range (a) +(partition pnull values less than (0), + partition p0 values less than (1), + partition p1 values less than(2)); +insert into t1 values (null),(0),(1); + +select * from t1 where a is null; +select * from t1 where a >= 0; +select * from t1 where a < 0; +select * from t1 where a <= 0; +select * from t1 where a > 1; +explain partitions select * from t1 where a is null; +explain partitions select * from t1 where a >= 0; +explain partitions select * from t1 where a < 0; +explain partitions select * from t1 where a <= 0; +explain partitions select * from t1 where a > 1; +drop table t1; + +create table t1 (a int unsigned, b int unsigned) +partition by range (a) +subpartition by hash (b) +subpartitions 2 +(partition pnull values less than (0), + partition p0 values less than (1), + partition p1 values less than(2)); +insert into t1 values (null,0),(null,1),(0,0),(0,1),(1,0),(1,1); + +select * from t1 where a is null; +select * from t1 where a >= 0; +select * from t1 where a < 0; +select * from t1 where a <= 0; +select * from t1 where a > 1; +explain partitions select * from t1 where a is null; +explain partitions select * from t1 where a >= 0; +explain partitions select * from t1 where a < 0; +explain partitions select * from t1 where a <= 0; +explain partitions select * from t1 where a > 1; + +drop table t1; + +# +# Partition by range, basic +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, + partition x2 values less than (10) tablespace ts2, + partition x3 values less than maxvalue tablespace ts3); + +# Simple insert and verify test +INSERT into t1 values (1, 1, 1); +INSERT into t1 values (6, 1, 1); +INSERT into t1 values (10, 1, 1); +INSERT into t1 values (15, 1, 1); + +select * from t1; +show create table t1; + +ALTER TABLE t1 +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, + partition x2 values less than (10) tablespace ts2, + partition x3 values less than maxvalue tablespace ts3); + +select * from t1; +show create table t1; + +drop table if exists t1; + +# +# Partition by range, basic +# No primary key +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null) +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, + partition x2 values less than (10) tablespace ts2, + partition x3 values less than maxvalue tablespace ts3); + +# Simple insert and verify test +INSERT into t1 values (1, 1, 1); +INSERT into t1 values (6, 1, 1); +INSERT into t1 values (10, 1, 1); +INSERT into t1 values (15, 1, 1); + +select * from t1; + +ALTER TABLE t1 +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, + partition x2 values less than (10) tablespace ts2, + partition x3 values less than maxvalue tablespace ts3); + +select * from t1; + +drop table if exists t1; + +# +# Partition by range, basic +# No max value used +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, + partition x2 values less than (10) tablespace ts2, + partition x3 values less than (15) tablespace ts3); + + +# Simple insert and verify test +INSERT into t1 values (1, 1, 1); +INSERT into t1 values (6, 1, 1); +INSERT into t1 values (10, 1, 1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 values (15, 1, 1); + +select * from t1; + +ALTER TABLE t1 +partition by range (a) +partitions 3 +(partition x1 values less than (5) tablespace ts1, + partition x2 values less than (10) tablespace ts2, + partition x3 values less than (15) tablespace ts3); + +select * from t1; + +drop table t1; + +# +# Partition by range, only one partition +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key(a,b)) +partition by range (a) +(partition x1 values less than (1)); + +drop table t1; + +# +# Subpartition by hash, two partitions and two subpartitions +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11, + subpartition x12), + partition x2 values less than (5) + ( subpartition x21, + subpartition x22) +); + +SELECT * from t1; +show create table t1; + +ALTER TABLE t1 ADD COLUMN d int; +show create table t1; + +drop table t1; + +# +# Subpartition by hash, two partitions and two subpartitions +# Defined tablespace, engine and node group +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11 tablespace t1 nodegroup 0, + subpartition x12 tablespace t2 nodegroup 1), + partition x2 values less than (5) + ( subpartition x21 tablespace t1 nodegroup 0, + subpartition x22 tablespace t2 nodegroup 1) +); + +SELECT * from t1; + +drop table t1; + +# +# Subpartition by hash, two partitions and two subpartitions +# Defined tablespace, node group +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11 tablespace t1 nodegroup 0, + subpartition x12 tablespace t2 nodegroup 1), + partition x2 values less than (5) + ( subpartition x21 tablespace t1 nodegroup 0, + subpartition x22 tablespace t2 nodegroup 1) +); + +SELECT * from t1; + +drop table t1; + +# +# Subpartition by hash, two partitions and two subpartitions +# Defined engine and node group +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11 nodegroup 0, + subpartition x12 nodegroup 1), + partition x2 values less than (5) + ( subpartition x21 nodegroup 0, + subpartition x22 nodegroup 1) +); + +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (5,1,1); + +SELECT * from t1; + +ALTER TABLE t1 +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11 nodegroup 0, + subpartition x12 nodegroup 1), + partition x2 values less than (5) + ( subpartition x21 nodegroup 0, + subpartition x22 nodegroup 1) +); + +SELECT * from t1; + +drop table t1; + +# +# Subpartition by hash, two partitions and two subpartitions +# Defined tablespace, engine +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11 tablespace t1, + subpartition x12 tablespace t2), + partition x2 values less than (5) + ( subpartition x21 tablespace t1, + subpartition x22 tablespace t2) +); + +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (5,1,1); + +SELECT * from t1; + +ALTER TABLE t1 +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11 tablespace t1, + subpartition x12 tablespace t2), + partition x2 values less than (5) + ( subpartition x21 tablespace t1, + subpartition x22 tablespace t2) +); + +SELECT * from t1; + +drop table t1; + +# +# Subpartition by hash, two partitions and two subpartitions +# Defined tablespace +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11 tablespace t1, + subpartition x12 tablespace t2), + partition x2 values less than (5) + ( subpartition x21 tablespace t1, + subpartition x22 tablespace t2) +); + +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (5,1,1); + +SELECT * from t1; + +ALTER TABLE t1 +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11 tablespace t1, + subpartition x12 tablespace t2), + partition x2 values less than (5) + ( subpartition x21 tablespace t1, + subpartition x22 tablespace t2) +); + +SELECT * from t1; + +drop table t1; + +# +# Subpartition by hash, two partitions and two subpartitions +# Defined engine +# +CREATE TABLE t1 ( +a int not null, +b int not null, +c int not null, +primary key (a,b)) +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11, + subpartition x12), + partition x2 values less than (5) + ( subpartition x21, + subpartition x22) +); + +INSERT into t1 VALUES (1,1,1); +INSERT into t1 VALUES (4,1,1); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT into t1 VALUES (5,1,1); + +SELECT * from t1; + +ALTER TABLE t1 +partition by range (a) +subpartition by hash (a+b) +( partition x1 values less than (1) + ( subpartition x11, + subpartition x12), + partition x2 values less than (5) + ( subpartition x21, + subpartition x22) +); + +SELECT * from t1; + +drop table t1; + +# +# Bug #17894 Comparison with "less than" operator fails with Range partition +# +CREATE TABLE t1 (c1 int default NULL, c2 varchar(30) default NULL, +c3 date default NULL) engine=myisam +PARTITION BY RANGE (year(c3)) (PARTITION p0 VALUES LESS THAN (1995), +PARTITION p1 VALUES LESS THAN (1996) , PARTITION p2 VALUES LESS THAN (1997) , +PARTITION p3 VALUES LESS THAN (1998) , PARTITION p4 VALUES LESS THAN (1999) , +PARTITION p5 VALUES LESS THAN (2000) , PARTITION p6 VALUES LESS THAN (2001) , +PARTITION p7 VALUES LESS THAN (2002) , PARTITION p8 VALUES LESS THAN (2003) , +PARTITION p9 VALUES LESS THAN (2004) , PARTITION p10 VALUES LESS THAN (2010), +PARTITION p11 VALUES LESS THAN MAXVALUE ); +INSERT INTO t1 VALUES (1, 'testing partitions', '1995-07-17'), +(3, 'testing partitions','1995-07-31'), +(5, 'testing partitions','1995-08-13'), +(7, 'testing partitions','1995-08-26'), +(9, 'testing partitions','1995-09-09'), +(0, 'testing partitions','2000-07-10'), +(2, 'testing partitions','2000-07-23'), +(4, 'testing partitions','2000-08-05'), +(6, 'testing partitions','2000-08-19'), +(8, 'testing partitions','2000-09-01'); +SELECT COUNT(*) FROM t1 WHERE c3 BETWEEN '1996-12-31' AND '2000-12-31'; +SELECT COUNT(*) FROM t1 WHERE c3 < '2000-12-31'; +DROP TABLE t1; + +# +# BUG 16002: Unsigned partition functions not handled correctly +# +--error ER_RANGE_NOT_INCREASING_ERROR +create table t1 (a bigint unsigned) +partition by range (a) +(partition p0 values less than (10), + partition p1 values less than (0)); + +create table t1 (a bigint unsigned) +partition by range (a) +(partition p0 values less than (0), + partition p1 values less than (10)); +show create table t1; +drop table t1; + +create table t1 (a bigint unsigned) +partition by range (a) +(partition p0 values less than (2), + partition p1 values less than (10)); +show create table t1; +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values (0xFFFFFFFFFFFFFFFF); +drop table t1; + +# +# BUG 18962 Errors in DROP PARTITION +# +create table t1 (a int) +partition by range (MOD(a,3)) +subpartition by hash(a) +subpartitions 2 +(partition p0 values less than (1), + partition p1 values less than (2), + partition p2 values less than (3), + partition p3 values less than (4)); +ALTER TABLE t1 DROP PARTITION p3; +ALTER TABLE t1 DROP PARTITION p1; +ALTER TABLE t1 DROP PARTITION p2; +drop table t1; + +create table t1 (a int) +partition by range (MOD(a,3)) +subpartition by hash(a) +subpartitions 2 +(partition p0 values less than (1), + partition p1 values less than (2), + partition p2 values less than (3), + partition p3 values less than (4)); +ALTER TABLE t1 DROP PARTITION p0; +ALTER TABLE t1 DROP PARTITION p1; +ALTER TABLE t1 DROP PARTITION p2; +drop table t1; + +# +# Bug 19830: ALTER TABLE t1 REORGANIZE PARTITION crashes +# +create table t1 (a int DEFAULT NULL, + b varchar(30) DEFAULT NULL, + c date DEFAULT NULL) +ENGINE=MYISAM DEFAULT CHARSET=latin1; + +insert into t1 values (1, 'abc', '1995-01-01'); +insert into t1 values (1, 'abc', '1995-01-02'); +insert into t1 values (1, 'abc', '1995-01-03'); +insert into t1 values (1, 'abc', '1995-01-04'); +insert into t1 values (1, 'abc', '1995-01-05'); +insert into t1 values (1, 'abc', '1995-01-06'); +insert into t1 values (1, 'abc', '1995-01-07'); +insert into t1 values (1, 'abc', '1995-01-08'); +insert into t1 values (1, 'abc', '1995-01-09'); +insert into t1 values (1, 'abc', '1995-01-10'); +insert into t1 values (1, 'abc', '1995-01-11'); +insert into t1 values (1, 'abc', '1995-01-12'); +insert into t1 values (1, 'abc', '1995-01-13'); +insert into t1 values (1, 'abc', '1995-01-14'); +insert into t1 values (1, 'abc', '1995-01-15'); +insert into t1 values (1, 'abc', '1997-01-01'); +insert into t1 values (1, 'abc', '1997-01-02'); +insert into t1 values (1, 'abc', '1997-01-03'); +insert into t1 values (1, 'abc', '1997-01-04'); +insert into t1 values (1, 'abc', '1997-01-05'); +insert into t1 values (1, 'abc', '1997-01-06'); +insert into t1 values (1, 'abc', '1997-01-07'); +insert into t1 values (1, 'abc', '1997-01-08'); +insert into t1 values (1, 'abc', '1997-01-09'); +insert into t1 values (1, 'abc', '1997-01-10'); +insert into t1 values (1, 'abc', '1997-01-11'); +insert into t1 values (1, 'abc', '1997-01-12'); +insert into t1 values (1, 'abc', '1997-01-13'); +insert into t1 values (1, 'abc', '1997-01-14'); +insert into t1 values (1, 'abc', '1997-01-15'); +insert into t1 values (1, 'abc', '1998-01-01'); +insert into t1 values (1, 'abc', '1998-01-02'); +insert into t1 values (1, 'abc', '1998-01-03'); +insert into t1 values (1, 'abc', '1998-01-04'); +insert into t1 values (1, 'abc', '1998-01-05'); +insert into t1 values (1, 'abc', '1998-01-06'); +insert into t1 values (1, 'abc', '1998-01-07'); +insert into t1 values (1, 'abc', '1998-01-08'); +insert into t1 values (1, 'abc', '1998-01-09'); +insert into t1 values (1, 'abc', '1998-01-10'); +insert into t1 values (1, 'abc', '1998-01-11'); +insert into t1 values (1, 'abc', '1998-01-12'); +insert into t1 values (1, 'abc', '1998-01-13'); +insert into t1 values (1, 'abc', '1998-01-14'); +insert into t1 values (1, 'abc', '1998-01-15'); +insert into t1 values (1, 'abc', '1999-01-01'); +insert into t1 values (1, 'abc', '1999-01-02'); +insert into t1 values (1, 'abc', '1999-01-03'); +insert into t1 values (1, 'abc', '1999-01-04'); +insert into t1 values (1, 'abc', '1999-01-05'); +insert into t1 values (1, 'abc', '1999-01-06'); +insert into t1 values (1, 'abc', '1999-01-07'); +insert into t1 values (1, 'abc', '1999-01-08'); +insert into t1 values (1, 'abc', '1999-01-09'); +insert into t1 values (1, 'abc', '1999-01-10'); +insert into t1 values (1, 'abc', '1999-01-11'); +insert into t1 values (1, 'abc', '1999-01-12'); +insert into t1 values (1, 'abc', '1999-01-13'); +insert into t1 values (1, 'abc', '1999-01-14'); +insert into t1 values (1, 'abc', '1999-01-15'); +insert into t1 values (1, 'abc', '2000-01-01'); +insert into t1 values (1, 'abc', '2000-01-02'); +insert into t1 values (1, 'abc', '2000-01-03'); +insert into t1 values (1, 'abc', '2000-01-04'); +insert into t1 values (1, 'abc', '2000-01-05'); +insert into t1 values (1, 'abc', '2000-01-06'); +insert into t1 values (1, 'abc', '2000-01-07'); +insert into t1 values (1, 'abc', '2000-01-08'); +insert into t1 values (1, 'abc', '2000-01-09'); +insert into t1 values (1, 'abc', '2000-01-15'); +insert into t1 values (1, 'abc', '2000-01-11'); +insert into t1 values (1, 'abc', '2000-01-12'); +insert into t1 values (1, 'abc', '2000-01-13'); +insert into t1 values (1, 'abc', '2000-01-14'); +insert into t1 values (1, 'abc', '2000-01-15'); +insert into t1 values (1, 'abc', '2001-01-01'); +insert into t1 values (1, 'abc', '2001-01-02'); +insert into t1 values (1, 'abc', '2001-01-03'); +insert into t1 values (1, 'abc', '2001-01-04'); +insert into t1 values (1, 'abc', '2001-01-05'); +insert into t1 values (1, 'abc', '2001-01-06'); +insert into t1 values (1, 'abc', '2001-01-07'); +insert into t1 values (1, 'abc', '2001-01-08'); +insert into t1 values (1, 'abc', '2001-01-09'); +insert into t1 values (1, 'abc', '2001-01-15'); +insert into t1 values (1, 'abc', '2001-01-11'); +insert into t1 values (1, 'abc', '2001-01-12'); +insert into t1 values (1, 'abc', '2001-01-13'); +insert into t1 values (1, 'abc', '2001-01-14'); +insert into t1 values (1, 'abc', '2001-01-15'); + +alter table t1 +partition by range (year(c)) +(partition p5 values less than (2000), partition p10 values less than (2010)); + +alter table t1 +reorganize partition p5 into +(partition p1 values less than (1996), + partition p2 values less than (1997), + partition p3 values less than (1998), + partition p4 values less than (1999), + partition p5 values less than (2000)); + +drop table t1; + +# +# New test cases for date based partitioning +# +CREATE TABLE t1 (a date) +PARTITION BY RANGE (TO_DAYS(a)) +(PARTITION p3xx VALUES LESS THAN (TO_DAYS('2004-01-01')), + PARTITION p401 VALUES LESS THAN (TO_DAYS('2004-02-01')), + PARTITION p402 VALUES LESS THAN (TO_DAYS('2004-03-01')), + PARTITION p403 VALUES LESS THAN (TO_DAYS('2004-04-01')), + PARTITION p404 VALUES LESS THAN (TO_DAYS('2004-05-01')), + PARTITION p405 VALUES LESS THAN (TO_DAYS('2004-06-01')), + PARTITION p406 VALUES LESS THAN (TO_DAYS('2004-07-01')), + PARTITION p407 VALUES LESS THAN (TO_DAYS('2004-08-01')), + PARTITION p408 VALUES LESS THAN (TO_DAYS('2004-09-01')), + PARTITION p409 VALUES LESS THAN (TO_DAYS('2004-10-01')), + PARTITION p410 VALUES LESS THAN (TO_DAYS('2004-11-01')), + PARTITION p411 VALUES LESS THAN (TO_DAYS('2004-12-01')), + PARTITION p412 VALUES LESS THAN (TO_DAYS('2005-01-01')), + PARTITION p501 VALUES LESS THAN (TO_DAYS('2005-02-01')), + PARTITION p502 VALUES LESS THAN (TO_DAYS('2005-03-01')), + PARTITION p503 VALUES LESS THAN (TO_DAYS('2005-04-01')), + PARTITION p504 VALUES LESS THAN (TO_DAYS('2005-05-01')), + PARTITION p505 VALUES LESS THAN (TO_DAYS('2005-06-01')), + PARTITION p506 VALUES LESS THAN (TO_DAYS('2005-07-01')), + PARTITION p507 VALUES LESS THAN (TO_DAYS('2005-08-01')), + PARTITION p508 VALUES LESS THAN (TO_DAYS('2005-09-01')), + PARTITION p509 VALUES LESS THAN (TO_DAYS('2005-10-01')), + PARTITION p510 VALUES LESS THAN (TO_DAYS('2005-11-01')), + PARTITION p511 VALUES LESS THAN (TO_DAYS('2005-12-01')), + PARTITION p512 VALUES LESS THAN (TO_DAYS('2006-01-01')), + PARTITION p601 VALUES LESS THAN (TO_DAYS('2006-02-01')), + PARTITION p602 VALUES LESS THAN (TO_DAYS('2006-03-01')), + PARTITION p603 VALUES LESS THAN (TO_DAYS('2006-04-01')), + PARTITION p604 VALUES LESS THAN (TO_DAYS('2006-05-01')), + PARTITION p605 VALUES LESS THAN (TO_DAYS('2006-06-01')), + PARTITION p606 VALUES LESS THAN (TO_DAYS('2006-07-01')), + PARTITION p607 VALUES LESS THAN (TO_DAYS('2006-08-01'))); + +INSERT INTO t1 VALUES ('2003-01-13'),('2003-06-20'),('2003-08-30'); +INSERT INTO t1 VALUES ('2003-04-13'),('2003-07-20'),('2003-10-30'); +INSERT INTO t1 VALUES ('2003-05-13'),('2003-11-20'),('2003-12-30'); + +INSERT INTO t1 VALUES ('2004-01-13'),('2004-01-20'),('2004-01-30'); +INSERT INTO t1 VALUES ('2004-02-13'),('2004-02-20'),('2004-02-28'); +INSERT INTO t1 VALUES ('2004-03-13'),('2004-03-20'),('2004-03-30'); +INSERT INTO t1 VALUES ('2004-04-13'),('2004-04-20'),('2004-04-30'); +INSERT INTO t1 VALUES ('2004-05-13'),('2004-05-20'),('2004-05-30'); +INSERT INTO t1 VALUES ('2004-06-13'),('2004-06-20'),('2004-06-30'); +INSERT INTO t1 VALUES ('2004-07-13'),('2004-07-20'),('2004-07-30'); +INSERT INTO t1 VALUES ('2004-08-13'),('2004-08-20'),('2004-08-30'); +INSERT INTO t1 VALUES ('2004-09-13'),('2004-09-20'),('2004-09-30'); +INSERT INTO t1 VALUES ('2004-10-13'),('2004-10-20'),('2004-10-30'); +INSERT INTO t1 VALUES ('2004-11-13'),('2004-11-20'),('2004-11-30'); +INSERT INTO t1 VALUES ('2004-12-13'),('2004-12-20'),('2004-12-30'); + +INSERT INTO t1 VALUES ('2005-01-13'),('2005-01-20'),('2005-01-30'); +INSERT INTO t1 VALUES ('2005-02-13'),('2005-02-20'),('2005-02-28'); +INSERT INTO t1 VALUES ('2005-03-13'),('2005-03-20'),('2005-03-30'); +INSERT INTO t1 VALUES ('2005-04-13'),('2005-04-20'),('2005-04-30'); +INSERT INTO t1 VALUES ('2005-05-13'),('2005-05-20'),('2005-05-30'); +INSERT INTO t1 VALUES ('2005-06-13'),('2005-06-20'),('2005-06-30'); +INSERT INTO t1 VALUES ('2005-07-13'),('2005-07-20'),('2005-07-30'); +INSERT INTO t1 VALUES ('2005-08-13'),('2005-08-20'),('2005-08-30'); +INSERT INTO t1 VALUES ('2005-09-13'),('2005-09-20'),('2005-09-30'); +INSERT INTO t1 VALUES ('2005-10-13'),('2005-10-20'),('2005-10-30'); +INSERT INTO t1 VALUES ('2005-11-13'),('2005-11-20'),('2005-11-30'); +INSERT INTO t1 VALUES ('2005-12-13'),('2005-12-20'),('2005-12-30'); + +INSERT INTO t1 VALUES ('2006-01-13'),('2006-01-20'),('2006-01-30'); +INSERT INTO t1 VALUES ('2006-02-13'),('2006-02-20'),('2006-02-28'); +INSERT INTO t1 VALUES ('2006-03-13'),('2006-03-20'),('2006-03-30'); +INSERT INTO t1 VALUES ('2006-04-13'),('2006-04-20'),('2006-04-30'); +INSERT INTO t1 VALUES ('2006-05-13'),('2006-05-20'),('2006-05-30'); +INSERT INTO t1 VALUES ('2006-06-13'),('2006-06-20'),('2006-06-30'); +INSERT INTO t1 VALUES ('2006-07-13'),('2006-07-20'),('2006-07-30'); + +SELECT * FROM t1 +WHERE a >= '2004-07-01' AND a <= '2004-09-30'; +EXPLAIN PARTITIONS SELECT * FROM t1 +WHERE a >= '2004-07-01' AND a <= '2004-09-30'; +SELECT * from t1 +WHERE (a >= '2004-07-01' AND a <= '2004-09-30') OR + (a >= '2005-07-01' AND a <= '2005-09-30'); +EXPLAIN PARTITIONS SELECT * from t1 +WHERE (a >= '2004-07-01' AND a <= '2004-09-30') OR + (a >= '2005-07-01' AND a <= '2005-09-30'); +DROP TABLE t1; + +# +# Bug 18198: Try with a couple of cases using VARCHAR fields in +# partition function. +#create table t1 (a varchar(20)) +#partition by range (ascii(a)) +#(partition p0 values less than (100), +# partition p1 values less than maxvalue); + +#insert into t1 values ("12345678901234567890"); +#insert into t1 values ("A2345678901234567890"); +#insert into t1 values ("B2345678901234567890"); +#insert into t1 values ("1234567890123456789"); +#insert into t1 values ("1234567890123456"); +#select * from t1; +#explain partitions select * from t1 where a = "12345678901234567890"; +#explain partitions select * from t1 where a = "12345678901234567890" OR +# a = "A2345678901234567890" OR +# a = "B2345678901234567890" OR +# a = "C2345678901234567890"; +#explain partitions select * from t1 where a = "01234567890123456"; +#select * from t1 where a = "01234567890123456"; +#select * from t1 where a = "12345678901234567890" OR +# a = "A2345678901234567890" OR +# a = "B2345678901234567890" OR +# a = "C2345678901234567890"; +#select * from t1 where a = "12345678901234567890"; +#drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/pbxt_assertions.test b/mysql-test/suite/pbxt/t/pbxt_assertions.test new file mode 100644 index 00000000000..3699ab04568 --- /dev/null +++ b/mysql-test/suite/pbxt/t/pbxt_assertions.test @@ -0,0 +1,31 @@ +
+#
+# BUG: doing a SELECT COUNT(*) on a table with extended records and without indexes
+# caused assertion violation in debug version
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+CREATE TABLE t1 (c1 VARCHAR(255), c2 VARCHAR(255), c3 INT);
+INSERT INTO t1 VALUES (REPEAT('x', 255), REPEAT('y', 255), 1);
+INSERT INTO t1 VALUES (REPEAT('x', 255), REPEAT('y', 255), 2);
+INSERT INTO t1 VALUES (REPEAT('x', 255), REPEAT('y', 255), 3);
+SELECT COUNT(*) FROM t1;
+
+#
+# BUG: the following SELECT query caused assertion violation. The engine
+# code expected that index_int/index_end will be called nested in relation to
+# handler locking functions, which was not true for the case below
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a int, unique index indexa (a));
+insert into t1 values (-1), (-4), (-2), (NULL);
+select -10 IN (select a from t1 FORCE INDEX (indexa));
+
+--disable_query_log
+drop table t1;
+drop database pbxt;
+--enable_query_log
diff --git a/mysql-test/suite/pbxt/t/pbxt_bugs.test b/mysql-test/suite/pbxt/t/pbxt_bugs.test new file mode 100644 index 00000000000..3976f44267c --- /dev/null +++ b/mysql-test/suite/pbxt/t/pbxt_bugs.test @@ -0,0 +1,932 @@ +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + +#---------------------------------------- +# Bug with auto_increment settings + +create table t1 (id int auto_increment key) engine=pbxt auto_increment=200; +show create table t1; + +alter table t1 add column text char(40); +show create table t1; + +alter table t1 auto_increment = 100; +show create table t1; + +#---------------------------------------- +# Short fields +drop table if exists t1; +create table t1 ( + id int, + c_char char(3), + c_varchar varchar(3), + c_char_bin char(3) binary, + c_varchar_bin varchar(3) binary, + c_char_uni char(3) unicode, + c_varchar_uni varchar(3) unicode, + c_dec decimal(3), + index(c_char), + index(c_varchar), + index(c_char_bin), + index(c_varchar_bin), + index(c_char_uni), + index(c_varchar_uni), + index(c_dec) +) engine=pbxt; + +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", 12); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", 123); +select c_char from t1 where c_char = "ab"; +select c_varchar from t1 where c_varchar = "ab"; +select c_char_bin from t1 where c_char_bin = "ab"; +select c_varchar_bin from t1 where c_varchar_bin = "ab"; +select c_char_uni from t1 where c_char_uni = "ab"; +select c_varchar_uni from t1 where c_varchar_uni = "ab"; +select c_dec from t1 where c_dec = 12; +select * from t1 where c_char = "ab "; +select * from t1 where c_varchar = "ab "; +select * from t1 where c_char_bin = "ab "; +select * from t1 where c_varchar_bin = "ab "; +select * from t1 where c_char_uni = "ab "; +select * from t1 where c_varchar_uni = "ab "; +select * from t1 where c_dec = 123; + + +#---------------------------------------- +# Medium fields +drop table if exists t1; +create table t1 ( + id int, + c_char char(100), + c_varchar varchar(100), + c_char_bin char(100) binary, + c_varchar_bin varchar(100) binary, + c_char_uni char(100) unicode, + c_varchar_uni varchar(100) unicode, + c_dec decimal(65), + index(c_char), + index(c_varchar), + index(c_char_bin), + index(c_varchar_bin), + index(c_char_uni), + index(c_varchar_uni), + index(c_dec) +) engine=pbxt; + +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", 12); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", 123); +select * from t1 where c_char = "ab"; +select * from t1 where c_varchar = "ab"; +select * from t1 where c_char_bin = "ab"; +select * from t1 where c_varchar_bin = "ab"; +select * from t1 where c_char_uni = "ab"; +select * from t1 where c_varchar_uni = "ab"; +select * from t1 where c_dec = 12; +select c_char from t1 where c_char = "ab "; +select c_varchar from t1 where c_varchar = "ab "; +select c_char_bin from t1 where c_char_bin = "ab "; +select c_varchar_bin from t1 where c_varchar_bin = "ab "; +select c_char_uni from t1 where c_char_uni = "ab "; +select c_varchar_uni from t1 where c_varchar_uni = "ab "; +select c_dec from t1 where c_dec = 123; + + +#---------------------------------------- +# Large fields +drop table if exists t1; +create table t1 ( + id int, + c_varchar varchar(300), + c_varchar_bin varchar(300) binary, + c_varchar_uni varchar(300) unicode, + c_ttext TINYTEXT, + c_text TEXT, + c_mtext MEDIUMTEXT, + c_ltext LONGTEXT, + index(c_varchar), + index(c_varchar_bin), + index(c_varchar_uni), + index(c_ttext(100)), + index(c_text(100)), + index(c_mtext(100)), + index(c_ltext(100)) +) engine=pbxt; + +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", "ab"); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", "ab "); +select c_varchar from t1 where c_varchar = "ab"; +select c_varchar_bin from t1 where c_varchar_bin = "ab"; +select c_varchar_uni from t1 where c_varchar_uni = "ab"; +select c_ttext from t1 where c_ttext = "ab"; +select c_text from t1 where c_text = "ab"; +select c_mtext from t1 where c_mtext = "ab"; +select c_ltext from t1 where c_ltext = "ab"; + +select * from t1 where c_varchar = "ab "; +select * from t1 where c_varchar_bin = "ab "; +select * from t1 where c_varchar_uni = "ab "; +select * from t1 where c_ttext = "ab "; +select * from t1 where c_text = "ab "; +select * from t1 where c_mtext = "ab "; +select * from t1 where c_ltext = "ab "; + +#---------------------------------------- +# Short fields NOT NULL +drop table if exists t1; +create table t1 ( + id int not null, + c_char char(3) not null, + c_varchar varchar(3) not null, + c_char_bin char(3) binary not null, + c_varchar_bin varchar(3) binary not null, + c_char_uni char(3) unicode not null, + c_varchar_uni varchar(3) unicode not null, + c_dec decimal(3) not null, + index(c_char), + index(c_varchar), + index(c_char_bin), + index(c_varchar_bin), + index(c_char_uni), + index(c_varchar_uni), + index(c_dec) +) engine=pbxt; + +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", 12); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", 123); +select * from t1 where c_char = "ab"; +select * from t1 where c_varchar = "ab"; +select * from t1 where c_char_bin = "ab"; +select * from t1 where c_varchar_bin = "ab"; +select * from t1 where c_char_uni = "ab"; +select * from t1 where c_varchar_uni = "ab"; +select * from t1 where c_dec = 12; +select c_char from t1 where c_char = "ab "; +select c_varchar from t1 where c_varchar = "ab "; +select c_char_bin from t1 where c_char_bin = "ab "; +select c_varchar_bin from t1 where c_varchar_bin = "ab "; +select c_char_uni from t1 where c_char_uni = "ab "; +select c_varchar_uni from t1 where c_varchar_uni = "ab "; +select c_dec from t1 where c_dec = 123; + + +#---------------------------------------- +# Medium fields NOT NULL +drop table if exists t1; +create table t1 ( + id int not null, + c_char char(100) not null, + c_varchar varchar(100) not null, + c_char_bin char(100) binary not null, + c_varchar_bin varchar(100) binary not null, + c_char_uni char(100) unicode not null, + c_varchar_uni varchar(100) unicode not null, + c_dec decimal(65), + index(c_char), + index(c_varchar), + index(c_char_bin), + index(c_varchar_bin), + index(c_char_uni), + index(c_varchar_uni), + index(c_dec) +) engine=pbxt; + +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", 12); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", 123); +select c_char from t1 where c_char = "ab"; +select c_varchar from t1 where c_varchar = "ab"; +select c_char_bin from t1 where c_char_bin = "ab"; +select c_varchar_bin from t1 where c_varchar_bin = "ab"; +select c_char_uni from t1 where c_char_uni = "ab"; +select c_varchar_uni from t1 where c_varchar_uni = "ab"; +select c_dec from t1 where c_dec = 12; +select * from t1 where c_char = "ab "; +select * from t1 where c_varchar = "ab "; +select * from t1 where c_char_bin = "ab "; +select * from t1 where c_varchar_bin = "ab "; +select * from t1 where c_char_uni = "ab "; +select * from t1 where c_varchar_uni = "ab "; +select * from t1 where c_dec = 123; + + +#---------------------------------------- +# Large fields NOT NULL +drop table if exists t1; +create table t1 ( + id int, + c_varchar varchar(300) not null, + c_varchar_bin varchar(300) binary not null, + c_varchar_uni varchar(300) unicode not null, + c_ttext TINYTEXT not null, + c_text TEXT not null, + c_mtext MEDIUMTEXT not null, + c_ltext LONGTEXT not null, + index(c_varchar), + index(c_varchar_bin), + index(c_varchar_uni), + index(c_ttext(100)), + index(c_text(100)), + index(c_mtext(100)), + index(c_ltext(100)) +) engine=pbxt; + +insert t1 values (1, "ab", "ab", "ab", "ab", "ab", "ab", "ab"); +insert t1 values (2, "ab ", "ab ", "ab ", "ab ", "ab ", "ab ", "ab "); +select * from t1 where c_varchar = "ab"; +select * from t1 where c_varchar_bin = "ab"; +select * from t1 where c_varchar_uni = "ab"; +select * from t1 where c_ttext = "ab"; +select * from t1 where c_text = "ab"; +select * from t1 where c_mtext = "ab"; +select * from t1 where c_ltext = "ab"; + +select c_varchar from t1 where c_varchar = "ab "; +select c_varchar_bin from t1 where c_varchar_bin = "ab "; +select c_varchar_uni from t1 where c_varchar_uni = "ab "; +select c_ttext from t1 where c_ttext = "ab "; +select c_text from t1 where c_text = "ab "; +select c_mtext from t1 where c_mtext = "ab "; +select c_ltext from t1 where c_ltext = "ab "; + +#---------------------------------------- +# UNICODE Tests + +drop table if exists t1; +create table t1 ( + id int, + c_char_suni char(4) unicode, + c_varchar_suni varchar(4) unicode, + c_char_uni char(255) unicode, + c_varchar_uni varchar(300) unicode, + index(c_char_suni), + index(c_varchar_suni), + index(c_char_uni), + index(c_varchar_uni) +) engine=pbxt; + +insert t1 values (1, "ab", "ab", "ab", "ab"); +insert t1 values (1, "abcd", "abcd", "abcd", "abcd"); +insert t1 values (1, "ab ", "ab ", "abcd123123123123123123123123123123123123", "abcd123123123123123123123123123123123123"); +select * from t1 where c_char_suni = "ab"; +select * from t1 where c_varchar_suni = "ab"; +select * from t1 where c_char_uni = "ab"; +select * from t1 where c_varchar_uni = "ab"; + + +#---------------------------------------- +# Duplicate key tests + +drop table if exists t1; +create table t1 (id int, name char(10) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +-- error 1062 +insert t1 values (2, "ab "); + +drop table if exists t1; +create table t1 (id int, name char(100) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +-- error 1062 +insert t1 values (2, "ab "); + +drop table if exists t1; +create table t1 (id int, name varchar(10) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +-- error 1062 +insert t1 values (2, "ab "); + +drop table if exists t1; +create table t1 (id int, name varchar(100) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +-- error 1062 +insert t1 values (2, "ab "); + +drop table if exists t1; +create table t1 (id int, name varchar(400) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +-- error 1062 +insert t1 values (2, "ab "); + +drop table if exists t1; +create table t1 (id int, name char(10) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +-- error 1062 +insert t1 values (2, "ab "); + +drop table if exists t1; +create table t1 (id int, name char(100) key) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +-- error 1062 +insert t1 values (2, "ab "); + + +drop table if exists t1; +create table t1 (id int, name varchar(10), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +insert t1 values (4, "ab "); + +drop table if exists t1; +create table t1 (id int, name varchar(100), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +insert t1 values (4, "ab "); + +drop table if exists t1; +create table t1 (id int, name varchar(400), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +insert t1 values (4, "ab "); + +drop table if exists t1; +create table t1 (id int, name char(10), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +insert t1 values (4, "ab "); + +drop table if exists t1; +create table t1 (id int, name char(100), index(name)) engine=pbxt; +insert t1 values (1, "ab"); +select * from t1 where name = "ab"; +insert t1 values (2, "ab "); +insert t1 values (3, "ab "); +select * from t1 where name = "ab"; +insert t1 values (4, "ab "); + + +# BUG: "-49: Record format unknown, either corrupted or upgrade required" + +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( id int, name varchar(300)) engine=pbxt; +begin; +insert t1(id, name) values(1, "aaa"); +update t1 set name=REPEAT('A', 300) where id = 1; +commit; +flush tables; +select * from t1; + +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( id int, name varchar(300)) engine=pbxt; +begin; +insert t1(id, name) values(1, REPEAT('A', 300)); +update t1 set name="aaa" where id = 1; +commit; +flush tables; +select * from t1; + + +# BUG: failing TRUNCATE TABLE puts handler into an invalid state with later crash + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +create table t1 (s1 int primary key) engine = pbxt; +insert into t1 values (1); +create table t2 (s1 int, foreign key (s1) references t1 (s1)) engine = pbxt; +insert into t2 values (1); +# this should fail because of FK constraint +--error 1451 +truncate table t1; +# this caused a crash +alter table t1 engine myisam; +show create table t1; + +# BUG: Foreign Keys: missing row in table_constraints + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + +create table t1 (s1 int primary key, s2 int unique not null) engine = pbxt; +create table t2 (s1 int, foreign key (s1) references t1 (s1)) engine = pbxt; + +select * from information_schema.table_constraints + where constraint_type = 'FOREIGN KEY' and table_name = 't2'; + +select * from information_schema.referential_constraints where table_name = 't2'; + +drop table t2, t1; + +create table t1 (s1 int, s2 int, unique key ix1 (s1, s2)) engine = pbxt; +create table t2 (s1 int, s2 int, foreign key (s1, s2) references t1 (s1, s2)) engine = pbxt; + +select * from information_schema.table_constraints + where constraint_type = 'FOREIGN KEY' and table_name = 't2'; + +select * from information_schema.referential_constraints where table_name = 't2'; + +drop table t2, t1; + +create table t1 (s1 int, s2 int, unique key ix1 (s1, s2), unique key ix2 (s1, s2)) engine = pbxt; +create table t2 (s1 int, s2 int, foreign key (s1, s2) references t1 (s1, s2)) engine = pbxt; + +select * from information_schema.table_constraints + where constraint_type = 'FOREIGN KEY' and table_name = 't2'; + +select * from information_schema.referential_constraints where table_name = 't2'; + +drop table t2, t1; + +create table t1 (s1 int, s2 int, unique key ix1 (s1, s2)) engine = pbxt; +create table t2 (s1 int, s2 int, + foreign key (s1, s2) references t1 (s1, s2) on delete cascade on update set null) engine = pbxt; + +select * from information_schema.table_constraints + where constraint_type = 'FOREIGN KEY' and table_name = 't2'; + +select * from information_schema.referential_constraints where table_name = 't2'; + +drop table t2, t1; + +create table t2 (s1 int, s2 int, s3 int, s4 int, unique key ix34 (s3, s4), + foreign key (s1, s2) references t2 (s3, s4)) engine = pbxt; + +select * from information_schema.table_constraints + where constraint_type = 'FOREIGN KEY' and table_name = 't2'; + +select * from information_schema.referential_constraints where table_name = 't2'; + +drop table t2; + +create table t1 (s1 int, s2 int, unique key ix1 (s1, s2)) engine = pbxt; +create table t2 (s1 int, s2 int, + foreign key (s1, s2) references t1 (s1, s2)) engine = pbxt; +alter table t1 add constraint s2 foreign key (s1, s2) references t2 (s1, s2); + +select * from information_schema.table_constraints + where constraint_type = 'FOREIGN KEY' and (table_name = 't1' or table_name = 't2'); + +select * from information_schema.referential_constraints where (table_name = 't1' or table_name = 't2'); + +set foreign_key_checks = 0; +drop table t2, t1; +set foreign_key_checks = 1; + +create table t1 (id int primary key, s1 int, foreign key (s1) references t1 (id)) engine = pbxt; + +select * from information_schema.table_constraints + where constraint_type = 'FOREIGN KEY' and table_name = 't1'; + +select * from information_schema.referential_constraints where table_name = 't1'; + +drop table t1; + +# BUGS: +# 1. Foreign keys: crash if update cascade and autocommit=0, +# 2. Foreign keys: crash if update cascade and multi-level recursion + +# original test-case + +--disable_warnings +drop table if exists t2,t1; +--enable_warnings + +create table t1 (s1 int primary key) engine = pbxt; +create table t2 (s1 int primary key, foreign key (s1) references t1 (s1) on update cascade) engine = pbxt; + +set @@autocommit = 0; +insert into t1 values (1); +insert into t2 values (1); +update t1 set s1 = 2; +set @@autocommit = 1; + +select * from t1, t2; + +# test-case with multiple columns/indexes + +drop table t2, t1; + +create table t1 (s1 int primary key, s2 int, key (s1, s2)) engine = pbxt; +create table t2 (s1 int primary key, s2 int, key (s1, s2), foreign key (s1) references t1 (s1) on update cascade) engine = pbxt; + +set @@autocommit = 0; +insert into t1 values (1, 5); +insert into t2 values (1, 6); +update t1 set s1 = 2; +set @@autocommit = 1; + +select * from t1, t2; + +drop table t2, t1; + +# test case for the second bug + +set @@autocommit = 1; + +SET foreign_key_checks = 0; +--disable_warnings +DROP TABLE IF EXISTS t15,t14,t13,t12,t11,t10,t9,t8,t7,t6,t5,t4,t3,t2,t1; +--enable_warnings +SET foreign_key_checks = 1; + +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 INT) engine = pbxt; +CREATE TABLE t2 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t3 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t2 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t4 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t3 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t5 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t4 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t6 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t5 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t7 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t6 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t8 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t7 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t9 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t8 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t10(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t9 (s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t11(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t10(s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t12(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t11(s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t13(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t12(s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t14(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t13(s1) ON UPDATE CASCADE) engine = pbxt; +CREATE TABLE t15(s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t14(s1) ON UPDATE CASCADE) engine = pbxt; + +ALTER TABLE t1 ADD FOREIGN KEY (s2) REFERENCES t15(s1) ON UPDATE CASCADE; + +SET foreign_key_checks = 0; + +INSERT INTO t1 VALUES (1,NULL); +INSERT INTO t2 VALUES (1); +INSERT INTO t3 VALUES (1); +INSERT INTO t4 VALUES (1); +INSERT INTO t5 VALUES (1); +INSERT INTO t6 VALUES (1); +INSERT INTO t7 VALUES (1); +INSERT INTO t8 VALUES (1); +INSERT INTO t9 VALUES (1); +INSERT INTO t10 VALUES (1); +INSERT INTO t11 VALUES (1); +INSERT INTO t12 VALUES (1); +INSERT INTO t13 VALUES (1); +INSERT INTO t14 VALUES (1); +INSERT INTO t15 VALUES (1); + +SET foreign_key_checks = 1; + +UPDATE t1 SET s1 = 2; +select * from t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15; + +UPDATE t1 SET s2 = 2; +select * from t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15; + +# this query works with pbxt, fails with innodb, falcon 6.0.5 ignores constraint actions +UPDATE t1 SET s1 = 3; +select * from t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15; + +SET foreign_key_checks = 0; +DROP TABLE IF EXISTS t15,t14,t13,t12,t11,t10,t9,t8,t7,t6,t5,t4,t3,t2,t1; +SET foreign_key_checks = 1; + +# BUG: Foreign keys: can't reference with enum +# correct behavior: references between ENUMs and SETs are allowed as long as they have equal number of members + +--disable_warnings +DROP TABLE IF EXISTS t2,t1; +--enable_warnings + +CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 ENUM('A','B'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +DROP TABLE t2,t1; + +CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY) engine = pbxt; +-- error 1005 +CREATE TABLE t2 (s1 ENUM('A','B', 'C'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +DROP TABLE t1; + +CREATE TABLE t1 (s1 ENUM('a','b','c') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 ENUM('d','e','f'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +DROP TABLE t2,t1; + +CREATE TABLE t1 (s1 SET('a','b') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 SET('A','B'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +DROP TABLE t2,t1; + +CREATE TABLE t1 (s1 SET('a','b') PRIMARY KEY) engine = pbxt; +-- error 1005 +CREATE TABLE t2 (s1 SET('A','B', 'C'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +DROP TABLE t1; + +CREATE TABLE t1 (s1 SET('a','b','c') PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 SET('d','e','f'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +DROP TABLE t2,t1; + +CREATE TABLE t1 (s1 SET('a','b') PRIMARY KEY) engine = pbxt; +-- error 1005 +CREATE TABLE t2 (s1 ENUM('a','b'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +DROP TABLE t1; + +CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY) engine = pbxt; +-- error 1005 +CREATE TABLE t2 (s1 SET('a','b'), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +DROP TABLE t1; + +# RN155: Errors during cascade update of VARCHAR values with trailing spaces + +DROP TABLE IF EXISTS t2, t1; +CREATE TABLE t1 (s1 VARCHAR(50) PRIMARY KEY) engine = pbxt; +CREATE TABLE t2 (s1 VARCHAR(50), FOREIGN KEY (s1) REFERENCES t1 (s1)) engine = pbxt; + +INSERT INTO t1 VALUES ('A'); +INSERT INTO t2 VALUES ('A '); + +UPDATE t1 SET s1 = 'A '; + +DELETE FROM t2; +DELETE FROM t1; + +INSERT INTO t1 VALUES ('A'); +INSERT INTO t2 VALUES ('A'); + +UPDATE t1 SET s1 = 'A '; +UPDATE t2 SET s1 = 'A '; +UPDATE t1 SET s1 = 'a'; +UPDATE t2 SET s1 = 'a'; + +DROP TABLE t2, t1; + +# SET DEFAULT produces error + +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 INT PRIMARY KEY); +CREATE TABLE t2 (s1 INT DEFAULT 2, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +SELECT * FROM t2; + +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 DATE NOT NULL UNIQUE); +CREATE TABLE t2 (s1 DATE DEFAULT '2000-01-01', FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE SET DEFAULT); + +INSERT INTO t1 VALUES ('2001-01-01'); +INSERT INTO t2 VALUES ('2001-01-01'); +UPDATE t1 SET s1 = '2001-01-02'; +SELECT * FROM t2; + +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 INT PRIMARY KEY); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +SELECT * FROM t2; + +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 VARCHAR(45) primary key); +CREATE TABLE t2 (s1 VARCHAR(45) DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +SELECT * FROM t2; + +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 VARCHAR(45), INDEX (s1(10))); +CREATE TABLE t2 (s1 VARCHAR(45) DEFAULT "12345678901", FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +DELETE FROM t1 WHERE s1 = 1; +SELECT * FROM t2; + +# A crash if inserting into a table that has an FK that references a column that has no index on it + +DROP TABLE IF EXISTS t2,t1; +CREATE TABLE t1 (s1 INT); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1); +--error 1297 +INSERT INTO t2 VALUES (1); # this used to crash + +# A crash if cascade operation on child table triggers a subsequent cascade operation and that operation fails +# (e.g. because of contraint violation) + +--disable_warnings +DROP TABLE IF EXISTS t3,t2,t1; +--enable_warnings +CREATE TABLE t1 (s1 INT primary key); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET NULL); +CREATE TABLE t3 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t2 (s1) ON DELETE SET NULL); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +INSERT INTO t3 VALUES (1); + +# we don't have on-update action for t3 which means NO ACTION which is basically the same as RESTICT, and the constraints check fails +--error 1451 +DELETE FROM t1 WHERE s1 = 1; + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +# Same as previous test but action is SET DEFAULT + +--disable_warnings +DROP TABLE IF EXISTS t3,t2,t1; +--enable_warnings +CREATE TABLE t1 (s1 INT primary key); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE SET DEFAULT); +CREATE TABLE t3 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t2 (s1) ON DELETE SET DEFAULT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1); +INSERT INTO t3 VALUES (1); + +# we don't have on-update action for t3 which means NO ACTION which is basically the same as RESTICT, and the constraints check fails +--error 1451 +DELETE FROM t1 WHERE s1 = 1; + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +DROP TABLE IF EXISTS t3,t2,t1; + +# RN203: Fixed foreign key bug: REPLACE fails with 'on delete cascade' + +--disable_warnings +DROP TABLE IF EXISTS t2,t1; +--enable_warnings +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 char(1)); +CREATE TABLE t2 (s1 INT, s2 INT PRIMARY KEY, + FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE CASCADE); +INSERT INTO t1 VALUES (1,'a'); +INSERT INTO t2 VALUES (1,1); +REPLACE INTO t1 VALUES (1,'b'); +SELECT COUNT(*) FROM t2; + +set foreign_key_checks = 0; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 char(1)); +set foreign_key_checks = 1; +INSERT INTO t1 VALUES (1,'a'); +REPLACE INTO t1 VALUES (1,'b'); + +# RN204: Foreign key references are now checked on CREATE TABLE. + +--disable_warnings +DROP TABLE IF EXISTS t3,t2,t1; +--enable_warnings +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 INT); +CREATE TABLE t2 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE CASCADE); +CREATE TABLE t3 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t2 (s1) ON UPDATE CASCADE); + +DROP TABLE IF EXISTS t3,t2,t1; +CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY); +--error 1005 +CREATE TABLE t2 (s1 ENUM('A','B','C'), FOREIGN KEY (s1) REFERENCES t1 (s1)); + +DROP TABLE IF EXISTS t2,t1; + +CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 INT); +CREATE TABLE t2 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE CASCADE); + +DROP TABLE IF EXISTS t2,t1; + +# Relax restrictions on data types + +create table t1 (s1 varchar(40) primary key); +create table t2 (s1 VARCHAR(30), foreign key (s1) references t1 (s1)); +insert into t1 values ("1"); +insert into t2 values ("1"); + +DROP TABLE IF EXISTS t2,t1; + +# bug 340316: Issue with bigint unsigned auto-increment field + +--disable_warnings +DROP TABLE IF EXISTS t5; +--enable_warnings +CREATE TABLE t5 ( + c1 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + c2 BIGINT SIGNED NULL, + c3 BIGINT SIGNED NOT NULL, + c4 TINYINT, c5 SMALLINT, + c6 MEDIUMINT, + c7 INT, + c8 INTEGER, + PRIMARY KEY(c1,c2), UNIQUE INDEX(c3)); + +INSERT INTO t5 VALUES + (0,-9223372036854775808,1,2,3,4,5,5), + (255,-2147483648,6,7,8,9,10,10), + (65535,-8388608,11,12,13,14,15,15), + (16777215,-32768,16,17,18,19,20,20), + (4294967295,-128,21,22,23,24,25,25), + (18446744073709551615,9223372036854775807,26,27,28,29,30,30); + +--error 1467 +INSERT INTO t5(c2,c3) VALUES(33,34) /* tries to increment out of range */; +--error 1467 +INSERT INTO t5(c2,c3) VALUES(33,34); + +SELECT * FROM t5; + +DROP TABLE t5; + +/* same test as above with signed bigint */ +CREATE TABLE t5 ( + c1 BIGINT SIGNED NOT NULL AUTO_INCREMENT, + c2 BIGINT SIGNED NULL, + c3 BIGINT SIGNED NOT NULL, + c4 TINYINT, c5 SMALLINT, + c6 MEDIUMINT, + c7 INT, + c8 INTEGER, + PRIMARY KEY(c1,c2), UNIQUE INDEX(c3)); + +INSERT INTO t5 VALUES + (0,-9223372036854775808,1,2,3,4,5,5), + (255,-2147483648,6,7,8,9,10,10), + (65535,-8388608,11,12,13,14,15,15), + (16777215,-32768,16,17,18,19,20,20), + (4294967295,-128,21,22,23,24,25,25), + (9223372036854775807,9223372036854775807,26,27,28,29,30,30); + +--error 1467 +INSERT INTO t5(c2,c3) VALUES(33,34) /* tries to increment out of range */; +--error 1467 +INSERT INTO t5(c2,c3) VALUES(33,34); + +SELECT * FROM t5; + +# bug 341115: wrong key comparison algorithm led to endless resultset + +CREATE TABLE t2(c1 INT SIGNED NOT NULL, c2 INT UNSIGNED NULL, c3 INT, KEY(c1), KEY(c2)); +INSERT INTO t2 VALUES(-1,1,1),(-2,2,2),(-3,3,3),(-4,4,4),(-5,5,5),(-6,6,6),(-7,7,7),(-8,8,8),(-9,9,9),(10,10,10),(-11,NULL,11),(-12,12,12); +INSERT INTO t2 VALUES(-2147483648,0,13),(2147483647,4294967295,14),(0,2147483648,15),(2147483647,2147483647,16); +--sorted_result +SELECT * FROM t2; + +# make sure it uses index scan +EXPLAIN SELECT c1 FROM t2; +--sorted_result +SELECT c1 FROM t2; + +UPDATE t2 SET c1=-2147483648 WHERE c2 <> 0 ORDER BY c2 LIMIT 2; +--sorted_result +SELECT * FROM t2 WHERE c2 <> 0 ORDER BY c2; +UPDATE t2 SET c1=-2147483648 WHERE c2 >= 0 ORDER BY c2 DESC LIMIT 2; +--sorted_result +SELECT * FROM t2 WHERE c2 >= 0 ORDER BY c2 DESC; +UPDATE t2 SET c1=-2147483648 WHERE c2 <= 3 ORDER BY c2 LIMIT 2; +--sorted_result +SELECT * FROM t2 WHERE c2 <= 3 ORDER BY c2; +UPDATE t2 SET c1=-2147483648 WHERE c2 <=> 4 ORDER BY c2 DESC LIMIT 2; +--sorted_result +SELECT * FROM t2 WHERE c2 <=> 4 ORDER BY c2; +UPDATE t2 SET c1=-2147483648 WHERE c2 BETWEEN 4 AND 7 ORDER BY c2 LIMIT 2; +--sorted_result +SELECT * FROM t2 WHERE c2 BETWEEN 4 AND 7 ORDER BY c2; +UPDATE t2 SET c1=-2147483648 WHERE c2 IN(8,9) ORDER BY c2 DESC LIMIT 2; +--sorted_result +SELECT * FROM t2 WHERE c2 IN(8,9) ORDER BY c2 DESC; +UPDATE t2 SET c1=-2147483648 WHERE c2 IS NULL ORDER BY c2 LIMIT 2; +--sorted_result +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c2; +UPDATE t2 SET c1=-2147483648 WHERE c2>= 6 AND c2 < 9 ORDER BY c2 LIMIT 2; +--sorted_result +SELECT * FROM t2 WHERE c2>= 6 AND c2 < 9 ORDER BY c2; +UPDATE t2 SET c1=-2147483648 WHERE c1=-12 OR c2=1; +--sorted_result +SELECT * FROM t2 WHERE c1=-2147483648; +--sorted_result +SELECT * FROM t2; + +# make sure it uses index scan +EXPLAIN SELECT c1 FROM t2; +--sorted_result +SELECT c1 FROM t2; + +# bug 313391: LOAD DATA..REPLACE broken + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (c1 INTEGER NOT NULL PRIMARY KEY, c2 VARCHAR(255)); +LOAD DATA LOCAL INFILE 'suite/pbxt/t/load_unique_error1.inc' REPLACE INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (@c1,c2) SET c1 = @c1 % 2; +--sorted_result +SELECT * FROM t1 ORDER BY c1; +DROP TABLE t1; + +--disable_query_log +DROP TABLE t2, t5; +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/pbxt_locking.test b/mysql-test/suite/pbxt/t/pbxt_locking.test new file mode 100644 index 00000000000..975015b22e2 --- /dev/null +++ b/mysql-test/suite/pbxt/t/pbxt_locking.test @@ -0,0 +1,125 @@ +# This test covers various aspects of PBXT locking mechanism, including
+# internal permanent/temporary row locking and MySQL locking
+
+# TEST: select for update test
+
+drop table if exists t1;
+create table t1 (id int, index (id)) engine = pbxt;
+insert into t1 values (1), (2), (3), (4), (5);
+begin;
+select * from t1 where id < 5 for update;
+
+connect (con1,localhost,root,,);
+
+connection con1;
+
+# this shouldn't lock
+# note this implies usage of the index, table scan will block
+update t1 set id = 8 where id = 5;
+
+# this should block
+send update t1 set id = 8 where id = 4;
+
+connection default;
+sleep 1;
+replace_column 1 x 3 x 6 x;
+show processlist;
+commit;
+
+connection con1;
+reap;
+select * from t1;
+
+# TEST: make sure no unneeded temporary locks are set
+
+connection default;
+
+drop table if exists t1;
+# notice absence of index
+create table t1 (id int) engine = pbxt;
+insert into t1 values (1), (2), (3), (4), (5);
+
+begin;
+# after this statement all rows should be unlocked
+select * from t1 where id > 10 for update;
+
+connection con1;
+# this shouldn't block
+update t1 set id = 8;
+
+connection default;
+commit;
+select * from t1;
+
+# TEST: last row temp->perm locking
+
+connection default;
+
+drop table if exists t1;
+create table t1 (id int, index (id)) engine = pbxt;
+insert into t1 values (1), (2), (3), (4), (5);
+
+begin;
+select * from t1 where id = 5 for update;
+
+connection con1;
+
+update t1 set id = 8 where id < 4;
+# this should block
+send update t1 set id = 8 where id = 5;
+
+connection default;
+sleep 1;
+replace_column 1 x 3 x 6 x;
+show processlist;
+commit;
+
+connection con1;
+reap;
+
+connection default;
+select * from t1;
+
+# TEST: select for update in auto-commit mode
+# although this is not a widely used case in practice, make sure it operates correctly
+
+connection default;
+
+drop table if exists t1;
+create table t1 (id int, index (id)) engine = pbxt;
+insert into t1 values (1), (2), (3), (4), (5);
+
+# auto-commit mode - should unlock immediately
+select * from t1 for update;
+
+connection con1;
+# this shouldn't block
+update t1 set id = 8;
+
+# TEST: same as before but from a stored routine
+
+connection default;
+
+drop table if exists t1;
+create table t1 (id int, index (id)) engine = pbxt;
+insert into t1 values (1), (2), (3), (4), (5);
+
+delimiter |;
+create procedure p1 ()
+begin
+ select * from t1 for update;
+end|
+
+delimiter ;|
+call p1 ();
+
+connection con1;
+
+# this shouldn't block
+update t1 set id = 8;
+
+--disable_query_log
+drop procedure p1;
+drop table t1;
+drop database pbxt;
+--enable_query_log
diff --git a/mysql-test/suite/pbxt/t/pbxt_my_fail2.test b/mysql-test/suite/pbxt/t/pbxt_my_fail2.test new file mode 100644 index 00000000000..a8baf637dad --- /dev/null +++ b/mysql-test/suite/pbxt/t/pbxt_my_fail2.test @@ -0,0 +1,74 @@ +# This test demonstrates how the flag OPTION_STATUS_NO_TRANS_UPDATE is +# not correctly reset, and leads to an incorrect warning + +delimiter |; + +--disable_warnings +drop table if exists t4| +--enable_warnings +create table t4 ( + a mediumint(8) unsigned not null auto_increment, + b smallint(5) unsigned not null, + c char(32) not null, + primary key (a) +) engine=myisam default charset=latin1| +insert into t4 values (1, 2, 'oneword')| +insert into t4 values (2, 2, 'anotherword')| + +--disable_warnings +drop table if exists t3| +--enable_warnings + +create table t3 ( x int unique ) engine=pbxt| + +create procedure bug7049_1() +begin + insert into t3 values (42); + insert into t3 values (42); +end| + +create procedure bug7049_2() +begin + declare exit handler for sqlexception + select 'Caught it' as 'Result'; + + call bug7049_1(); + select 'Missed it' as 'Result'; +end| + +create function bug7049_1() + returns int +begin + insert into t3 values (42); + insert into t3 values (42); + return 42; +end| + +create function bug7049_2() + returns int +begin + declare x int default 0; + declare continue handler for sqlexception + set x = 1; + + set x = bug7049_1(); + return x; +end| + +# This cause the following warning: +# Warning 1196: Some non-transactional changed tables couldn't be rolled back +# which is not correct +# PMC - This bug was fixed in 5.1.12 (confirmed 2006-9-15). +call bug7049_2()| + +drop procedure bug7049_1| +drop function bug7049_1| +drop procedure bug7049_2| +drop function bug7049_2| + +delimiter ;| + +--disable_query_log +drop table t3, t4; +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/pbxt_ref_int.test b/mysql-test/suite/pbxt/t/pbxt_ref_int.test new file mode 100644 index 00000000000..483e461cb67 --- /dev/null +++ b/mysql-test/suite/pbxt/t/pbxt_ref_int.test @@ -0,0 +1,391 @@ +# Test PBXT referential integrity + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + +CREATE TABLE t1 +( + id INT PRIMARY KEY +) ENGINE=pbxt; # PBXT: Instead of InnoDB + +CREATE TABLE t2 +( + v INT, + CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) +) ENGINE=pbxt; # PBXT: Instead of InnoDB + +--error 1452 +INSERT INTO t2 VALUES(2); + +set foreign_key_checks = 0; +drop table t1; +set foreign_key_checks = 1; + +--error 1452 +INSERT INTO t2 VALUES(2); + +--disable_warnings +drop table if exists parent, child, child_child; +--enable_warnings +CREATE TABLE parent ( + id INT NOT NULL, + PRIMARY KEY (id) +) ENGINE=PBXT; + +CREATE TABLE child ( + id INT PRIMARY KEY, + parent_id INT, + INDEX par_ind (parent_id), + FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE SET NULL ON UPDATE SET NULL +) ENGINE=PBXT; + +insert parent values(1); +insert parent values(2); +insert child values(100, 1); +insert child values(200, 1); +insert child values(300, 2); +insert child values(400, 2); + +update parent set id = 3 where id = 1; + +select * from parent; +select * from child order by id; + +delete from parent where id = 2; + +select * from parent; +select * from child order by id; + +set foreign_key_checks = 0; +--disable_warnings +drop table if exists parent, child, child_child; +--enable_warnings +set foreign_key_checks = 1; + +CREATE TABLE parent ( + id INT NOT NULL, + PRIMARY KEY (id) +) ENGINE=PBXT; + +CREATE TABLE child ( + id INT PRIMARY KEY, + parent_id INT, + INDEX par_ind (parent_id), + FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=PBXT; + +CREATE TABLE child_child ( + id INT PRIMARY KEY, + child_id INT, + INDEX (child_id), + FOREIGN KEY (child_id) REFERENCES child(id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=PBXT; + +delete from parent; +delete from child; +delete from child_child; +insert parent values(1); +insert parent values(2); +insert child values(100, 1); +insert child values(200, 1); +insert child values(300, 2); +insert child values(400, 2); +insert child_child values(1000, 100); +insert child_child values(2000, 200); +insert child_child values(3000, 300); +insert child_child values(4000, 300); +insert child_child values(5000, 400); + +select * from parent; +select * from child order by id; +select * from child_child; + +update parent set id = 3 where id = 1; + +select * from parent; +select * from child order by id; + +delete from parent where id = 2; + +select * from parent; +select * from child order by id; +select * from child_child; + +set foreign_key_checks = 0; +--disable_warnings +drop table if exists parent, child, child_child; +--enable_warnings +set foreign_key_checks = 1; + +CREATE TABLE parent ( + id INT NOT NULL, + PRIMARY KEY (id) +) ENGINE=PBXT; + +CREATE TABLE child ( + id INT, + parent_id INT, + INDEX par_ind (parent_id), + FOREIGN KEY (parent_id) REFERENCES parent(id) +) ENGINE=PBXT; + +insert parent values(2); +insert parent values(1); +insert child values(100, 1); +insert child values(200, 1); + +--error 1451 +update parent set id = 3 where id = 1; + +--error 1451 +delete from parent where id = 1; + +select * from parent; +select * from child order by id; + +delete from child; + +insert child values(100, 1); +insert child values(200, 1); + +create index child_ind on child(id); +show create table child; +drop index child_ind on child; +show create table child; + +alter table parent add column c1 varchar(40); + +insert child values(2000, 2); + +select * from parent; +select * from child order by id; + +show create table parent; + +alter table parent drop column c1; + +select * from parent; +show create table parent; + +alter table parent add column c1 int; + +alter table parent drop column id; + +--error 1215 +insert child values(300, 1); + +alter table parent add column id int, add index (id); + +select * from parent; + +--error 1452 +insert child values(300, 1); + +update parent set id = 1 where id is null limit 1; +update parent set id = 2 where id is null limit 1; + +insert child values(300, 1); + +select * from parent order by id; +select * from child order by id; + +show create table parent; +show create table child; + +alter table child add column c1 varchar(40); + +insert child values(400, 1, "asd"); + +select * from parent order by id; +select * from child order by id; + +alter table child drop key par_ind, drop column parent_id, add column parent_id int, add key par_ind (parent_id); + +insert child (id, parent_id, c1) values(500, 1, "asd"); + +--disable_warnings +drop table if exists child, parent; +--enable_warnings +CREATE TABLE parent ( + id INT NOT NULL, + PRIMARY KEY (id) +) ENGINE=PBXT; + +CREATE TABLE child ( + id INT, + parent_id INT, + INDEX par_ind (parent_id), + FOREIGN KEY (parent_id) + REFERENCES parent(id) ON DELETE CASCADE +) ENGINE=PBXT; + +show create table parent; +show create table child; + +insert parent values(1); +insert child values(100, 1); +--error 1452 +insert child values(102, 2); + +set foreign_key_checks = 0; +--disable_warnings +drop table if exists parent, child; +--enable_warnings +set foreign_key_checks = 1; + +CREATE TABLE parent ( + id INT NOT NULL, + PRIMARY KEY (id) +) ENGINE=PBXT; + +CREATE TABLE child ( + id INT, + parent_id INT, + INDEX par_ind (parent_id), + FOREIGN KEY (parent_id) + REFERENCES parent(glump) ON DELETE CASCADE +) ENGINE=PBXT; + +insert parent values(1); +--error 1215 +insert child values(100, 1); + +--disable_warnings +drop table if exists test1; +--enable_warnings +CREATE TABLE test1 ( + id INT NOT NULL, + c1 varchar(30), + PRIMARY KEY (id) +) ENGINE=pbxt; + +insert test1 values(1, "asd"); +insert test1 values(2, "qwer"); + +alter table test1 drop column id, drop primary key, add column id int; + +show create table test1; +select * from test1; + +# Test some extended table and column names. +--disable_warnings +drop table if exists `ÔÁÂÌÉÃÁ`, t2; +--enable_warnings + +create table `ÔÁÂÌÉÃÁ` ( + id int primary key +) engine=pbxt; + +CREATE TABLE t2 +( + ÐÏÌÅ int NOT NULL, + cc varchar(20), + foreign key (ÐÏÌÅ) references `ÔÁÂÌÉÃÁ` (id), + index (ÐÏÌÅ) +) engine=pbxt; + +insert `ÔÁÂÌÉÃÁ` values (1); +insert t2 values (1, "asd"); + +select * from `ÔÁÂÌÉÃÁ`; + +set foreign_key_checks = 0; +--disable_warnings +drop table if exists test1, parent, child, child_child, `ÔÁÂÌÉÃÁ`, t2; +--enable_warnings +set foreign_key_checks = 1; + +SET CHARACTER SET koi8r; +SET NAMES binary; + +create table `теÑÑ‚` ( + id int primary key +) engine=pbxt; + + +CREATE TABLE `2теÑÑ‚` ( + `теÑÑ‚` int, + foreign key (`теÑÑ‚`) references `теÑÑ‚`(id), + index (`теÑÑ‚`) +) engine=pbxt; + +select * from `теÑÑ‚`; +select * from `2теÑÑ‚`; + +set foreign_key_checks = 0; +--disable_warnings +drop table if exists `теÑÑ‚`, `2теÑÑ‚`; +--enable_warnings +set foreign_key_checks = 1; + +# Test processing of foreign_key_checks flag + +--disable_warnings +drop table if exists t2, t1; +--enable_warnings + +set foreign_key_checks = 1; +--error 1005 +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1)); + +set foreign_key_checks = 0; +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1)); + +set foreign_key_checks = 1; +--error 1452 +insert into t2 values (1); + +set foreign_key_checks = 0; +insert into t2 values (1); + +CREATE TABLE t1 (s1 INT PRIMARY KEY); +set foreign_key_checks = 1; +--error 1217 +DROP TABLE t1; +set foreign_key_checks = 0; +DROP TABLE t1; +DROP TABLE t2; + +# check that table with self-refs can be dropped +set foreign_key_checks = 1; +CREATE TABLE t1 (s1 INT DEFAULT NULL, s2 INT DEFAULT NULL, s3 INT DEFAULT NULL, s4 INT DEFAULT NULL, + INDEX (s1), INDEX (s2), INDEX (s3), INDEX (s4), + FOREIGN KEY (s1) REFERENCES t1 (s2), + FOREIGN KEY (s2) REFERENCES t1 (s3), + FOREIGN KEY (s3) REFERENCES t1 (s4)); +DROP TABLE t1; + +# .. but only if there are no other refs +CREATE TABLE t1 (s1 INT DEFAULT NULL, s2 INT DEFAULT NULL, s3 INT DEFAULT NULL, s4 INT DEFAULT NULL, + INDEX (s1), INDEX (s2), INDEX (s3), INDEX (s4), + FOREIGN KEY (s1) REFERENCES t1 (s2), + FOREIGN KEY (s2) REFERENCES t1 (s3), + FOREIGN KEY (s3) REFERENCES t1 (s4)); +CREATE TABLE t2 (s1 INT DEFAULT NULL, FOREIGN KEY (s1) REFERENCES t1 (s1)); +--error 1217 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE t2 (s1 INT, INDEX (s1)); + +# this test is temporary disabled because the server error message includes temporary file name +# and thus differs every time, so it's impossible to get fixed text output + +#set foreign_key_checks = 1; +#--error 1005 +#ALTER TABLE t2 ADD FOREIGN KEY (s1) REFERENCES t1 (s1); + +set foreign_key_checks = 0; +ALTER TABLE t2 ADD FOREIGN KEY (s1) REFERENCES t1 (s1); + +--disable_warnings +DROP TABLE IF EXISTS t2, t1; +--enable_warnings + +--disable_query_log +drop database pbxt; +--enable_query_log +set foreign_key_checks = 1; + diff --git a/mysql-test/suite/pbxt/t/pbxt_transactions.test b/mysql-test/suite/pbxt/t/pbxt_transactions.test new file mode 100644 index 00000000000..815d2258d0e --- /dev/null +++ b/mysql-test/suite/pbxt/t/pbxt_transactions.test @@ -0,0 +1,537 @@ +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings + +create table `t1` (`id` int( 11 ) not null ,primary key ( `id` )) engine = pbxt; +insert into `t1`values ( 1 ) ; +create table `t2` (`id` int( 11 ) not null default '0',unique key `id` ( `id` ) ,constraint `t1_id_fk` foreign key ( `id` ) references `t1` (`id` )) engine = pbxt; +insert into `t2`values ( 1 ) ; +create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = pbxt; +insert into `t3`values ( 1 ) ; + +select * from t1; +select * from t2; +select * from t3; + +--error 1451 +update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; + +select * from t1; +select * from t2; +select * from t3; + +--error 1451 +delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; + +select * from t1; +select * from t2; +select * from t3; + +--disable_warnings +drop table if exists t3, t2, t1; +--enable_warnings + +create table t1 (id int primary key) engine = pbxt; +create table t2 (id int) engine = pbxt; + +insert into t1 values ( 1 ) ; +insert into t1 values ( 2 ) ; +insert into t2 values ( 1 ) ; +insert into t2 values ( 2 ) ; + +select * from t1; +select * from t2; + +# This statement is returns an error calls ha_autocommit_or_rollback(): +--error ER_DUP_ENTRY +update t1 set t1.id=1 where t1.id=2; + +select * from t1; +select * from t2; + +# This statement is returns no error and calls ha_autocommit_or_rollback(): +update t1,t2 set t1.id=3, t2.id=3 where t1.id=2 and t2.id = t1.id; + +select * from t1; +select * from t2; + +# But this statement returns an error and does not call ha_autocommit_or_rollback(): +--error ER_DUP_ENTRY +update t1,t2 set t1.id=1, t2.id=1 where t1.id=3 and t2.id = t1.id; + +select * from t1; +select * from t2; + +--error ER_DUP_ENTRY +update t1 set t1.id=1 where t1.id=3; + +select * from t1; +select * from t2; + +# rename will generate an error if MySQL thinks a transaction is +# still running. + +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings + +create table t1 (c1 int); +insert t1 values (1); +select * from t1; +rename table t1 to t2; + +# The select below will not include the data if the INSERT statement +# is not committed on time. By doing a SELECT FOR UPDATE, we +# make sure the SELECT transaction waits (I think)! + +create table t1 (a text character set utf8, b text character set latin1); +insert t1 values (0x4F736E616272C3BC636B, 0x4BF66C6E); +select * from t1; +--exec $MYSQL_DUMP --tab=$MYSQLTEST_VARDIR/tmp/ test +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/t1.sql +--exec $MYSQL_IMPORT test $MYSQLTEST_VARDIR/tmp/t1.txt +select * from t1 for update; + +# Test nested start_stmt() calls + +--disable_warnings +drop table if exists t1,t3; +--enable_warnings +create table t1 ( + id char(16) not null default '', + data int not null +); + +delimiter |; + +insert into t1 values ("foo", 3), ("bar", 2), ("zip", 5), ("zap", 1)| + +create table t3 ( + v char(16) not null primary key, + c int unsigned not null +)| + +create function getcount(s char(16)) returns int +begin + declare x int; + + select count(*) into x from t3 where v = s; + if x = 0 then + insert into t3 values (s, 1); + else + update t3 set c = c+1 where v = s; + end if; + return x; +end| + +select * from t1| +select * from t3| + +select * from t1 where data = getcount("bar")| + +select * from t1| +select * from t3| + +drop table t1,t3| + +delimiter ;| + +drop function getcount; + +# This test forces a begin transaction in start_stmt() + +drop tables if exists t1; +create table t1 (id int); +lock tables t1 write; +insert t1 values (1); +insert t1 values (2); +select id from t1; +unlock tables; +select id from t1; + +# This demonstratrates the behavior of locked tables + +DROP TABLE if exists t1; +create table t1 (id int primary key); +insert t1 values (100); +LOCK TABLES t1 WRITE; +insert t1 values (98); +--error ER_DUP_ENTRY +insert into t1 values (99),(100); +select id from t1; +UNLOCK TABLES; +select id from t1; + +# And this is how it goes with a transaction: + +DROP TABLE if exists t1; +create table t1 (id int primary key); +insert t1 values (100); +begin; +insert t1 values (98); +--error ER_DUP_ENTRY +insert into t1 values (99),(100); +select id from t1; +rollback; +select id from t1; + + +# And this without lock or transaction: + +DROP TABLE if exists t1; +create table t1 (id int primary key); +insert t1 values (100); +insert t1 values (98); +--error ER_DUP_ENTRY +insert into t1 values (99),(100); +select id from t1; + +# And with multiple tables + +DROP TABLE if exists t1, t2; +create table t1 (id int primary key); +insert t1 values (100); +create table t2 (id int primary key); +insert t2 values (100); + + +LOCK TABLES t1 WRITE, t2 READ; +insert t1 values (98); +select * from t1, t2 where t1.id = t2.id; +insert t1 values (97); +--error ER_DUP_ENTRY +insert into t1 values (99),(100); +select id from t1; +UNLOCK TABLES; +select id from t1; + +DROP TABLE t1; + +# Test ALTER TABLE and UPDATE together + +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +create table t1 (a int, b int); +insert into t1 values (1, 2), (2, 3), (3, 4); +create table t2 (a int); +insert into t2 values (10), (20), (30); +create view v1 as select a as b, a/10 as a from t2; + +connect (locker,localhost,root,,test); +connection locker; +lock table t1 write; + +connect (changer,localhost,root,,test); +connection changer; +send alter table t1 add column c int default 100 after a; + +connect (updater,localhost,root,,test); +connection updater; +sleep 2; +send update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a; + +connection locker; +sleep 2; +unlock tables; + +connection changer; +reap; + +connection updater; +reap; +select * from t1; +select * from t2; +drop view v1; +drop table t1, t2; + +# It is possible that the sweeper gets stuck because +#it has no dictionary information! +# As in the example below. + +--disable_warnings +drop table if exists t1, t4; +--enable_warnings + +create table t1 ( + a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +) engine=pbxt; + +insert t1 values ("a1", "a2", "b", "c", "d", "dummy"); + +create table t4 ( + pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +) engine=pbxt; + +insert into t4 (a1, a2, b, c, d, dummy) select * from t1; + +create index idx12672_0 on t4 (a1); +create index idx12672_1 on t4 (a1,a2,b,c); +create index idx12672_2 on t4 (a1,a2,b); +analyze table t1; + +# Rename between different databases if triggers exist should fail +use test; +--disable_warnings +drop table if exists t1; +drop database if exists mysqltest; +--enable_warnings + +create database mysqltest; +use mysqltest; +create table t1 (id int); +create trigger t1_bi before insert on t1 for each row set @a:=new.id; +insert into t1 values (101); +--error ER_TRG_IN_WRONG_SCHEMA, 1005 +alter table t1 rename to test.t1, add column val int default 0; + +drop database mysqltest; +use test; + +# Various update/statement boundary tests + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +drop table t9; + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +lock tables t9 write; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9 order by id; +unlock tables; +SELECT * from t9 order by id; +drop table t9; + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; + +delimiter |; + +create procedure auto_test() +begin +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +end| + +delimiter ;| + +call auto_test(); +SELECT * from t9; + +drop procedure auto_test; +drop table t9; + +SET AUTOCOMMIT=0; + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +drop table t9; + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +lock tables t9 write; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +unlock tables; +SELECT * from t9; +drop table t9; + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; + +delimiter |; + +create procedure auto_test() +begin +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +end| + +delimiter ;| + +call auto_test(); +SELECT * from t9; + +drop procedure auto_test; +drop table t9; + +SET AUTOCOMMIT=1; + +SET AUTOCOMMIT=0; + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +commit; +SELECT * from t9; +drop table t9; + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; +lock tables t9 write; +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +unlock tables; +SELECT * from t9; +commit; +SELECT * from t9; +drop table t9; + +create table t9 (id int primary key auto_increment, fk int, index (fk)) engine=pbxt; + +delimiter |; + +create procedure auto_test() +begin +insert into t9 (id) values (null),(null),(null),(null),(null); +update t9 set fk=69 where fk is null order by id limit 1; +SELECT * from t9; +end| + +delimiter ;| + +call auto_test(); +SELECT * from t9; +commit; +SELECT * from t9; + +drop procedure auto_test; +drop table t9; + +SET AUTOCOMMIT=1; + +# Create table involving a procedure +# This tests the handling of transactions an statements + +delimiter |; + +--disable_warnings +drop table if exists t1,t3| +--enable_warnings + +create table t1 ( + id char(16) not null default '', + data int not null +)| +insert t1 value ("one", 1), ("two", 2)| + +--disable_warnings +drop function if exists bug12472| +--enable_warnings +create function bug12472() returns int +begin +declare a int; +declare b int; +set a = (select count(*) from t1); +set b = (select count(*) from t1); +return (a + b); +end| +# Check case when function is used directly +create table t3 as select bug12472() as i| +show create table t3| +select * from t3| +drop table t3| +# Check case when function is used indirectly through view +create view v1 as select bug12472() as j| +create table t3 as select * from v1| +show create table t3| +select * from t3| +drop table t3| +drop view v1| +drop function bug12472| + +drop table t1| + +# Test procedures and transactions + +--disable_warnings +drop table if exists t1, t3| +drop procedure if exists t3_update| +drop function if exists t3_update| +--enable_warnings + +create table t3 (a smallint primary key) engine=pbxt| + +insert into t3 (a) values (1)| + +create procedure t3_update() + deterministic +begin + declare continue handler for 1062 -- ER_DUP_ENTRY + select 'Outer (bad)' as 't3_update'; + + begin + declare continue handler for 1062 -- ER_DUP_ENTRY + select 'Inner (good)' as 't3_update'; + + insert into t3 values (1); + end; +end| + +call t3_update()| + +begin| +call t3_update()| +commit| + +--disable_warnings +drop table if exists t3| +drop procedure if exists t3_update| +drop function if exists t3_update| +--enable_warnings + +create table t3 (a smallint primary key) engine=pbxt| +insert into t3 (a) values (40)| +insert into t3 (a) values (50)| + +create function t3_update() returns int +begin + insert into t3 values (10); + insert into t3 values (40); + insert into t3 values (500); + return 100; +end| + +select * from t3| + +connect (conn1,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK)| +connect (conn2,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK)| + +connection conn1| + +begin| +insert into t3 values (10)| + +connection conn2| +# This will hang (so use send - reap later) +send select t3_update()| + +connection conn1| +# This should stop the hanger: +rollback| + +connection conn2| +-- error 1062 +reap| +select * from t3| + +--disable_warnings +drop function t3_update| +drop table if exists t1, t2, t3, t4| +--enable_warnings + +--disable_query_log +drop database pbxt| +--enable_query_log + +disconnect conn1| +disconnect conn2| + +delimiter ;| + diff --git a/mysql-test/suite/pbxt/t/pbxt_updates.test b/mysql-test/suite/pbxt/t/pbxt_updates.test new file mode 100644 index 00000000000..4183d148fcc --- /dev/null +++ b/mysql-test/suite/pbxt/t/pbxt_updates.test @@ -0,0 +1,111 @@ +# Test in-place updates + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + +CREATE TABLE t1 +( + id INT PRIMARY KEY, + number INT, + string VARCHAR(20), + UNIQUE INDEX (number) +) ENGINE=pbxt; + +truncate table t1; +insert t1 values (1, 1, 'abc'); + +begin; +update t1 set string = 'def' where id = 1; +update t1 set string = 'HIJ' where id = 1; +select * from t1 where id = 1; +select * from t1 where number = 1; +update t1 set string = '123', number=2 where id = 1; +select * from t1 where id = 1; +select * from t1 where number = 2; +commit; + +-- error 1062 +insert t1 values (2, 2, 'abc'); +insert t1 values (2, 3, 'abc'); +select * from t1 order by id; + +begin; +update t1 set number = 1 where id = 1; +select * from t1 order by id; + +-- error 1062 +update t1 set number = 3 where id = 1; + +select * from t1 where id = 1; +select * from t1 where id = 2; +select * from t1 where number = 1; +select * from t1 where number = 3; +select * from t1 order by id; + +commit; +select * from t1 order by id; + +drop table t1; + +CREATE TABLE t1 +( + id INT PRIMARY KEY, + number INT, + string VARCHAR(300), + UNIQUE INDEX (number) +) ENGINE=pbxt; + +truncate table t1; +insert t1 values (1, 1, 'abc01234567890123456789012345678901234567890123456789$$$'); + +begin; +update t1 set string = 'def01234567890123456789012345678901234567890123456789---' where id = 1; +update t1 set string = 'HIJ01234567890123456789012345678901234567890123456789***' where id = 1; +select * from t1 where id = 1; +select * from t1 where number = 1; +update t1 set string = '12301234567890123456789012345678901234567890123456789+++', number=2 where id = 1; +select * from t1 where id = 1; +select * from t1 where number = 2; +commit; + +-- error 1062 +insert t1 values (2, 2, 'abc01234567890123456789012345678901234567890123456789==='); +insert t1 values (2, 3, 'abc01234567890123456789012345678901234567890123456789+++'); +select * from t1 order by id; + +begin; +update t1 set number = 1 where id = 1; +select * from t1 order by id; + +-- error 1062 +update t1 set number = 3 where id = 1; + +select * from t1 where id = 1; +select * from t1 where id = 2; +select * from t1 where number = 1; +select * from t1 where number = 3; +select * from t1 order by id; + +rollback; +select * from t1 order by id; + +drop table t1; + +# insert + update in the same trx that changed record type caused a problem + +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( id int, name varchar(300)) engine=pbxt; + +begin; +insert t1(id, name) values(1, "aaa"); +update t1 set name=REPEAT('A', 300) where id = 1; +commit; +select * from t1; + +drop table t1; + + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/perror.test b/mysql-test/suite/pbxt/t/perror.test new file mode 100644 index 00000000000..a4b99d8aa22 --- /dev/null +++ b/mysql-test/suite/pbxt/t/perror.test @@ -0,0 +1,19 @@ +# +# Check if the variable MY_PERROR is set +# +--require r/have_perror.require +disable_query_log; +eval select LENGTH("$MY_PERROR") > 0 as "have_perror"; +enable_query_log; + +--exec $MY_PERROR 150 > /dev/null +--exec $MY_PERROR --silent 120 > /dev/null + +# +# Bug#16561 Unknown ERROR msg "ERROR 1186 (HY000): Binlog closed" by perror +# + +# Test with error code 10000 as it's a common "unknown error" +# As there is no error code defined for 10000, expect error +--error 1 +--exec $MY_PERROR 10000 2>&1 diff --git a/mysql-test/suite/pbxt/t/preload.test b/mysql-test/suite/pbxt/t/preload.test new file mode 100644 index 00000000000..8404346cc7a --- /dev/null +++ b/mysql-test/suite/pbxt/t/preload.test @@ -0,0 +1,105 @@ +# +# Testing of PRELOAD +# + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + + +create table t1 ( + a int not null auto_increment, + b char(16) not null, + primary key (a), + key (b) +); + +create table t2( + a int not null auto_increment, + b char(16) not null, + primary key (a), + key (b) +); + +insert into t1(b) values + ('test0'), + ('test1'), + ('test2'), + ('test3'), + ('test4'), + ('test5'), + ('test6'), + ('test7'); + +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; +insert into t2(b) select b from t1; +insert into t1(b) select b from t2; + +select count(*) from t1; +select count(*) from t2; + +flush tables; flush status; +show status like "key_read%"; + +select count(*) from t1 where b = 'test1'; +show status like "key_read%"; +select count(*) from t1 where b = 'test1'; +show status like "key_read%"; + +flush tables; flush status; +select @@preload_buffer_size; +load index into cache t1; +show status like "key_read%"; +select count(*) from t1 where b = 'test1'; +show status like "key_read%"; + +flush tables; flush status; +show status like "key_read%"; +set session preload_buffer_size=256*1024; +select @@preload_buffer_size; +load index into cache t1 ignore leaves; +show status like "key_read%"; +select count(*) from t1 where b = 'test1'; +show status like "key_read%"; + +flush tables; flush status; +show status like "key_read%"; +set session preload_buffer_size=1*1024; +select @@preload_buffer_size; +load index into cache t1, t2 key (primary,b) ignore leaves; +show status like "key_read%"; +select count(*) from t1 where b = 'test1'; +select count(*) from t2 where b = 'test1'; +show status like "key_read%"; + +flush tables; flush status; +show status like "key_read%"; +load index into cache t3, t2 key (primary,b) ; +show status like "key_read%"; + +flush tables; flush status; +show status like "key_read%"; +load index into cache t3 key (b), t2 key (c) ; +show status like "key_read%"; + +drop table t1, t2; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/ps_10nestset.test b/mysql-test/suite/pbxt/t/ps_10nestset.test new file mode 100644 index 00000000000..67be17d448c --- /dev/null +++ b/mysql-test/suite/pbxt/t/ps_10nestset.test @@ -0,0 +1,76 @@ +############################################### +# # +# Prepared Statements test on # +# "nested sets" representing hierarchies # +# # +############################################### + +# Source: http://kris.koehntopp.de/artikel/sql-self-references (dated 1999) +# Source: http://dbmsmag.com/9603d06.html (dated 1996) + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# "Nested Set": This table represents an employee list with a hierarchy tree. +# The tree is not modeled by "parent" links but rather by showing the "left" +# and "right" border of any person's "region". By convention, "l" < "r". +# As it is a tree, these "regions" of two persons A and B are either disjoint, +# or A's region is completely contained in B's (B.l < A.l < A.r < B.r: +# B is A's boss), or vice versa. +# Any other overlaps violate the model. See the references for more info. + +create table t1 ( + id INTEGER AUTO_INCREMENT PRIMARY KEY, + emp CHAR(10) NOT NULL, + salary DECIMAL(6,2) NOT NULL, + l INTEGER NOT NULL, + r INTEGER NOT NULL); + +prepare st_ins from 'insert into t1 set emp = ?, salary = ?, l = ?, r = ?'; + +# Initial employee list: +# Jerry ( Bert () Chuck ( Donna () Eddie () Fred () ) ) +set @arg_nam= 'Jerry'; set @arg_sal= 1000; set @arg_l= 1; set @arg_r= 12; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Bert'; set @arg_sal= 900; set @arg_l= 2; set @arg_r= 3; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Chuck'; set @arg_sal= 900; set @arg_l= 4; set @arg_r= 11; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Donna'; set @arg_sal= 800; set @arg_l= 5; set @arg_r= 6; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Eddie'; set @arg_sal= 700; set @arg_l= 7; set @arg_r= 8; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; +set @arg_nam= 'Fred'; set @arg_sal= 600; set @arg_l= 9; set @arg_r= 10; +execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; + +select * from t1; + +# Three successive raises, each one is 100 units for managers, 10 percent for others. +prepare st_raise_base from 'update t1 set salary = salary * ( 1 + ? ) where r - l = 1'; +prepare st_raise_mgr from 'update t1 set salary = salary + ? where r - l > 1'; +let $1= 3; +set @arg_percent= .10; +set @arg_amount= 100; +while ($1) +{ + execute st_raise_base using @arg_percent; + execute st_raise_mgr using @arg_amount; + dec $1; +} + +select * from t1 order by id; # PBXT: Require for consistent result + +# Now, increase salary to a multiple of 50 (checks for bug#6138) +prepare st_round from 'update t1 set salary = salary + ? - ( salary MOD ? )'; +set @arg_round= 50; +execute st_round using @arg_round, @arg_round; + +select * from t1 order by id; # PBXT: Require for consistent result + +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/ps_11bugs.test b/mysql-test/suite/pbxt/t/ps_11bugs.test new file mode 100644 index 00000000000..1f27d24b8cd --- /dev/null +++ b/mysql-test/suite/pbxt/t/ps_11bugs.test @@ -0,0 +1,183 @@ +############################################### +# # +# Prepared Statements # +# re-testing bug DB entries # +# # +# The bugs are reported as "closed". # +# Command sequences taken from bug report. # +# No other test contains the bug# as comment. # +# # +# Tests drop/create tables 't1', 't2', ... # +# # +############################################### + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + +# bug#1180: optimized away part of WHERE clause cause incorect prepared satatement results + +CREATE TABLE t1(session_id char(9) NOT NULL); +INSERT INTO t1 VALUES ("abc"); +SELECT * FROM t1; + +prepare st_1180 from 'SELECT * FROM t1 WHERE ?="1111" and session_id = "abc"'; + +# Must not find a row +set @arg1= 'abc'; +execute st_1180 using @arg1; + +# Now, it should find one row +set @arg1= '1111'; +execute st_1180 using @arg1; + +# Back to non-matching +set @arg1= 'abc'; +execute st_1180 using @arg1; + +drop table t1; + +# end of bug#1180 + + +# bug#1644: Insertion of more than 3 NULL columns with parameter binding fails + +# Using prepared statements, insertion of more than three columns with NULL +# values fails to insert additional NULLS. After the third column NULLS will +# be inserted into the database as zeros. +# First insert four columns of a value (i.e. 22) to verify binding is working +# correctly. Then Bind to each columns bind parameter an is_null value of 1. +# Then insert four more columns of integers, just for sanity. +# A subsequent select on the server will result in this: +# mysql> select * from foo_dfr; +# +------+------+------+------+ +# | col1 | col2 | col3 | col4 | +# +------+------+------+------+ +# | 22 | 22 | 22 | 22 | +# | NULL | NULL | NULL | 0 | +# | 88 | 88 | 88 | 88 | +# +------+------+------+------+ + +# Test is extended to more columns - code stores bit vector in bytes. + +create table t1 ( + c_01 char(6), c_02 integer, c_03 real, c_04 int(3), c_05 varchar(20), + c_06 date, c_07 char(1), c_08 real, c_09 int(11), c_10 time, + c_11 char(6), c_12 integer, c_13 real, c_14 int(3), c_15 varchar(20), + c_16 date, c_17 char(1), c_18 real, c_19 int(11), c_20 text); +# Do not use "timestamp" type, because it has a non-NULL default as of 4.1.2 + +prepare st_1644 from 'insert into t1 values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; + +set @arg01= 'row_1'; set @arg02= 1; set @arg03= 1.1; set @arg04= 111; set @arg05= 'row_one'; +set @arg06= '2004-10-12'; set @arg07= '1'; set @arg08= 1.1; set @arg09= '100100100'; set @arg10= '12:34:56'; +set @arg11= 'row_1'; set @arg12= 1; set @arg13= 1.1; set @arg14= 111; set @arg15= 'row_one'; +set @arg16= '2004-10-12'; set @arg17= '1'; set @arg18= 1.1; set @arg19= '100100100'; set @arg20= '12:34:56'; +execute st_1644 using @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08, @arg09, @arg10, + @arg11, @arg12, @arg13, @arg14, @arg15, @arg16, @arg17, @arg18, @arg19, @arg20; + +set @arg01= NULL; set @arg02= NULL; set @arg03= NULL; set @arg04= NULL; set @arg05= NULL; +set @arg06= NULL; set @arg07= NULL; set @arg08= NULL; set @arg09= NULL; set @arg10= NULL; +set @arg11= NULL; set @arg12= NULL; set @arg13= NULL; set @arg14= NULL; set @arg15= NULL; +set @arg16= NULL; set @arg17= NULL; set @arg18= NULL; set @arg19= NULL; set @arg20= NULL; +execute st_1644 using @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08, @arg09, @arg10, + @arg11, @arg12, @arg13, @arg14, @arg15, @arg16, @arg17, @arg18, @arg19, @arg20; + +set @arg01= 'row_3'; set @arg02= 3; set @arg03= 3.3; set @arg04= 333; set @arg05= 'row_three'; +set @arg06= '2004-10-12'; set @arg07= '3'; set @arg08= 3.3; set @arg09= '300300300'; set @arg10= '12:34:56'; +set @arg11= 'row_3'; set @arg12= 3; set @arg13= 3.3; set @arg14= 333; set @arg15= 'row_three'; +set @arg16= '2004-10-12'; set @arg17= '3'; set @arg18= 3.3; set @arg19= '300300300'; set @arg20= '12:34:56'; +execute st_1644 using @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08, @arg09, @arg10, + @arg11, @arg12, @arg13, @arg14, @arg15, @arg16, @arg17, @arg18, @arg19, @arg20; + +select * from t1; + +drop table t1; + +# end of bug#1644 + + +# bug#1676: Prepared statement two-table join returns no rows when one is expected + +create table t1( + cola varchar(50) not null, + colb varchar(8) not null, + colc varchar(12) not null, + cold varchar(2) not null, + primary key (cola, colb, cold)); + +create table t2( + cola varchar(50) not null, + colb varchar(8) not null, + colc varchar(2) not null, + cold float, + primary key (cold)); + +insert into t1 values ('aaaa', 'yyyy', 'yyyy-dd-mm', 'R'); + +insert into t2 values ('aaaa', 'yyyy', 'R', 203), ('bbbb', 'zzzz', 'C', 201); + +prepare st_1676 from 'select a.cola, a.colb, a.cold from t1 a, t2 b where a.cola = ? and a.colb = ? and a.cold = ? and b.cola = a.cola and b.colb = a.colb and b.colc = a.cold'; + +set @arg0= "aaaa"; +set @arg1= "yyyy"; +set @arg2= "R"; + +execute st_1676 using @arg0, @arg1, @arg2; + +drop table t1, t2; + +# end of bug#1676 + +# End of 4.1 tests + +# bug#18492: mysqld reports ER_ILLEGAL_REFERENCE in --ps-protocol + +create table t1 (a int primary key); +insert into t1 values (1); + +explain select * from t1 where 3 in (select (1+1) union select 1); + +select * from t1 where 3 in (select (1+1) union select 1); + +prepare st_18492 from 'select * from t1 where 3 in (select (1+1) union select 1)'; +execute st_18492; + +drop table t1; + +# +# Bug#19356: Assertion failure with undefined @uservar in prepared statement execution +# +create table t1 (a int, b varchar(4)); +create table t2 (a int, b varchar(4), primary key(a)); + +prepare stmt1 from 'insert into t1 (a, b) values (?, ?)'; +prepare stmt2 from 'insert into t2 (a, b) values (?, ?)'; + +set @intarg= 11; +set @varchararg= '2222'; +execute stmt1 using @intarg, @varchararg; +execute stmt2 using @intarg, @varchararg; +set @intarg= 12; +execute stmt1 using @intarg, @UNDEFINED; +execute stmt2 using @intarg, @UNDEFINED; +set @intarg= 13; +execute stmt1 using @UNDEFINED, @varchararg; +--error 1048 +execute stmt2 using @UNDEFINED, @varchararg; +set @intarg= 14; +set @nullarg= Null; +execute stmt1 using @UNDEFINED, @nullarg; +--error 1048 +execute stmt2 using @nullarg, @varchararg; + +select * from t1; +select * from t2; + +drop table t1; +drop table t2; + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/t/ps_1general.test b/mysql-test/suite/pbxt/t/ps_1general.test new file mode 100644 index 00000000000..96cc04dbb75 --- /dev/null +++ b/mysql-test/suite/pbxt/t/ps_1general.test @@ -0,0 +1,929 @@ +###################### ps_general.test ####################### +# # +# basic and miscellaneous tests for prepared statements # +# # +############################################################## + +# +# NOTE: PLEASE SEE THE DETAILED DESCRIPTION AT THE BOTTOM OF THIS FILE +# BEFORE ADDING NEW TEST CASES HERE !!! + +--disable_warnings +drop table if exists t5, t6, t7, t8; +drop database if exists mysqltest ; + +# Cleanup from other tests +drop database if exists client_test_db; +drop database if exists testtets; +drop table if exists t1Aa,t2Aa,v1Aa,v2Aa; +drop view if exists t1Aa,t2Aa,v1Aa,v2Aa; +--enable_warnings + +--disable_query_log +select '------ basic tests ------' as test_sequence ; +--enable_query_log + +let $type= 'MYISAM' ; +# create the tables (t1 and t9) used in many tests +--source include/ps_create.inc +# insert data into these tables +--source include/ps_renew.inc + + +################ The basic functions ################ + +# 1. PREPARE stmt_name FROM <preparable statement>; +# <preparable statement> ::= +# 'literal_stmt' | +# @variable_ref_stmt. +# The statement may contain question marks as placeholders for parameters. +# +# Bind a statement name to a string containing a SQL statement and +# send it to the server. The server will parse the statement and +# reply with "Query Ok" or an error message. +# +PREPARE stmt FROM ' select * from t1 where a = ? ' ; + +# 2. EXECUTE stmt_name [USING @var [, @var ]]; +# Current values of supplied variables are used as parameters. +# +# Send the server the order to execute the statement and supply values +# for the input parameters needed. +# If no error occurs the server reply will be identical to the reply for +# the query used in PREPARE with question marks replaced with values of +# the input variables. +# +SET @var= 2 ; +EXECUTE stmt USING @var ; +# The non prepared statement with the same server reply would be: +select * from t1 where a = @var ; + +# 3. DEALLOCATE PREPARE stmt_name; +# +# Send the server the order to drop the parse informations. +# The server will reply with "Query Ok" or an error message. +DEALLOCATE PREPARE stmt ; + +################ PREPARE ################ +# prepare without parameter +prepare stmt1 from ' select 1 as my_col ' ; +# prepare with parameter +prepare stmt1 from ' select ? as my_col ' ; +# prepare must fail (incomplete statements/wrong syntax) +--error 1064 +prepare ; +--error 1064 +prepare stmt1 ; +--error 1064 +prepare stmt1 from ; +--error 1064 +prepare_garbage stmt1 from ' select 1 ' ; +--error 1064 +prepare stmt1 from_garbage ' select 1 ' ; +--error 1064 +prepare stmt1 from ' select_garbage 1 ' ; +--error 1064 +prepare from ' select 1 ' ; +--error 1064 +prepare stmt1 ' select 1 ' ; +--error 1064 +prepare ? from ' select ? as my_col ' ; +# statement in variable +set @arg00='select 1 as my_col'; +prepare stmt1 from @arg00; +# prepare must fail (query variable is empty) +set @arg00=''; +--error 1065 +prepare stmt1 from @arg00; +set @arg00=NULL; +# prepare must fail (query variable is NULL) +--error 1064 +prepare stmt1 from @arg01; + +prepare stmt1 from ' select * from t1 where a <= 2 ' ; +# prepare must fail (column x does not exist) +--error 1054 +prepare stmt1 from ' select * from t1 where x <= 2 ' ; +# cases derived from client_test.c: test_null() +# prepare must fail (column x does not exist) +--error 1054 +prepare stmt1 from ' insert into t1(a,x) values(?,?) ' ; +--error 1054 +prepare stmt1 from ' insert into t1(x,a) values(?,?) ' ; +--disable_warnings +drop table if exists not_exist ; +--enable_warnings +# prepare must fail (table does not exist) +--error 1146 +prepare stmt1 from ' select * from not_exist where a <= 2 ' ; + +# case derived from client_test.c: test_prepare_syntax() +# prepare must fail (incomplete statement) +--error 1064 +prepare stmt1 from ' insert into t1 values(? ' ; +--error 1064 +prepare stmt1 from ' select a, b from t1 + where a=? and where ' ; + +################ EXECUTE ################ +# execute must fail (statement never_prepared never prepared) +--error 1243 +execute never_prepared ; +# execute must fail (prepare stmt1 just failed, +# but there was a successful prepare of stmt1 before) +prepare stmt1 from ' select * from t1 where a <= 2 ' ; +--error 1146 +prepare stmt1 from ' select * from not_exist where a <= 2 ' ; +--error 1243 +execute stmt1 ; + +# drop the table between prepare and execute +create table t5 +( + a int primary key, + b char(30), + c int +); +insert into t5( a, b, c) values( 1, 'original table', 1); +prepare stmt2 from ' select * from t5 ' ; +execute stmt2 ; +drop table t5 ; +# execute must fail (table was dropped after prepare) +--error 1146 +execute stmt2 ; +# cases derived from client_test.c: test_select_prepare() +# 1. drop + create table (same column names/types/order) +# between prepare and execute +create table t5 +( + a int primary key, + b char(30), + c int +); +insert into t5( a, b, c) values( 9, 'recreated table', 9); +execute stmt2 ; +drop table t5 ; +# 2. drop + create table (same column names/types but different order) +# between prepare and execute +create table t5 +( + a int primary key, + c int, + b char(30) +); +insert into t5( a, b, c) values( 9, 'recreated table', 9); +execute stmt2 ; +drop table t5 ; +# 3. drop + create table (same column names/types/order+extra column) +# between prepare and execute +create table t5 +( + a int primary key, + b char(30), + c int, + d timestamp default '2008-02-23 09:23:45' +); +insert into t5( a, b, c) values( 9, 'recreated table', 9); +execute stmt2 ; +drop table t5 ; +# 4. drop + create table (same column names/types, different order + +# additional column) between prepare and execute +create table t5 +( + a int primary key, + d timestamp default '2008-02-23 09:23:45', + b char(30), + c int +); +insert into t5( a, b, c) values( 9, 'recreated table', 9); +execute stmt2 ; +drop table t5 ; +# 5. drop + create table (same column names/order, different types) +# between prepare and execute +create table t5 +( + a timestamp default '2004-02-29 18:01:59', + b char(30), + c int +); +insert into t5( b, c) values( 'recreated table', 9); +execute stmt2 ; +drop table t5 ; +# 6. drop + create table (same column types/order, different names) +# between prepare and execute +create table t5 +( + f1 int primary key, + f2 char(30), + f3 int +); +insert into t5( f1, f2, f3) values( 9, 'recreated table', 9); +execute stmt2 ; +drop table t5 ; + +# execute without parameter +prepare stmt1 from ' select * from t1 where a <= 2 ' ; +execute stmt1 ; +# execute with parameter +set @arg00=1 ; +set @arg01='two' ; +prepare stmt1 from ' select * from t1 where a <= ? ' ; +execute stmt1 using @arg00; +# execute must fail (too small number of parameters) +--error 1210 +execute stmt1 ; +# execute must fail (too big number of parameters) +--error 1210 +execute stmt1 using @arg00, @arg01; +# execute must fail (parameter is not set) +execute stmt1 using @not_set; + +################ DEALLOCATE ################ +# deallocate must fail (the statement 'never_prepared' was never prepared) +--error 1243 +deallocate prepare never_prepared ; +# deallocate must fail (prepare stmt1 just failed, +# but there was a successful prepare before) +prepare stmt1 from ' select * from t1 where a <= 2 ' ; +--error 1146 +prepare stmt1 from ' select * from not_exist where a <= 2 ' ; +--error 1243 +deallocate prepare stmt1; +create table t5 +( + a int primary key, + b char(10) +); +prepare stmt2 from ' select a,b from t5 where a <= 2 ' ; +drop table t5 ; +# deallocate prepared statement where the table was dropped after prepare +deallocate prepare stmt2; + +## parallel use of more than one prepared statement handlers +# switch between different queries +prepare stmt1 from ' select a from t1 where a <= 2 ' ; +prepare stmt2 from ' select b from t1 where a <= 2 ' ; +execute stmt2 ; +execute stmt1 ; +# switch between statement handlers of the same query +prepare stmt1 from ' select a from t1 where a <= 2 ' ; +prepare stmt2 from ' select a from t1 where a <= 2 ' ; +execute stmt2 ; +execute stmt1 ; +deallocate prepare stmt1 ; +# Will the deallocate of stmt1 with the same query affect stmt2 ? +execute stmt2 ; + +--disable_query_log +select '------ show and misc tests ------' as test_sequence ; +--enable_query_log + +--disable_warnings +drop table if exists t2; +--enable_warnings +create table t2 +( + a int primary key, b char(10) +); + +################ SHOW COMMANDS ################ +prepare stmt4 from ' show databases '; +execute stmt4; +prepare stmt4 from ' show tables from test like ''t2%'' '; +execute stmt4; +prepare stmt4 from ' show columns from t2 where field in (select ?) '; +SET @arg00="a"; +execute stmt4 using @arg00; +SET @arg00="b"; +execute stmt4 using @arg00; +SET @arg00=1; +execute stmt4 using @arg00; + +prepare stmt4 from ' show columns from t2 from test like ''a%'' '; +execute stmt4; +create index t2_idx on t2(b); +prepare stmt4 from ' show index from t2 from test '; +execute stmt4; +prepare stmt4 from ' show table status from test like ''t2%'' '; +# egalize date and time values +--replace_column 8 # 12 # 13 # 14 # +# Bug#4288 : prepared statement 'show table status ..', wrong output on execute +execute stmt4; +# try the same with the big table +prepare stmt4 from ' show table status from test like ''t9%'' '; +# egalize date and time values +--replace_column 8 # 12 # 13 # 14 # +# Bug#4288 +execute stmt4; +prepare stmt4 from ' show status like ''Threads_running'' '; +--replace_column 2 # +execute stmt4; +prepare stmt4 from ' show variables like ''sql_mode'' '; +execute stmt4; +# The output depends on the bdb being enabled and on the history +# history (actions of the bdb engine). +# That is the reason why, we switch the output here off. +# (The real output will be tested in ps_6bdb.test) +--disable_result_log +prepare stmt4 from ' show engine pbxt logs '; # PBXT: changed from bdb to pbxt +execute stmt4; +--enable_result_log +prepare stmt4 from ' show grants for user '; +prepare stmt4 from ' show create table t2 '; +prepare stmt4 from ' show master status '; +prepare stmt4 from ' show master logs '; +prepare stmt4 from ' show slave status '; +prepare stmt4 from ' show warnings limit 20 '; +prepare stmt4 from ' show errors limit 20 '; +prepare stmt4 from ' show storage engines '; +# The output depends upon the precise order in which +# storage engines are registered, so we switch off the output. +--disable_result_log +execute stmt4; +--enable_result_log + +################ MISC STUFF ################ +## get a warning and an error +# cases derived from client_test.c: test_warnings(), test_errors() +--disable_warnings +drop table if exists t5; +--enable_warnings +prepare stmt1 from ' drop table if exists t5 ' ; +execute stmt1 ; +prepare stmt1 from ' drop table t5 ' ; +--error 1051 +execute stmt1 ; + +## SELECT @@version +# cases derived from client_test.c: test_select_version() +# +# TODO: Metadata check is temporary disabled here, because metadata of +# this statement also depends on @@version contents and you can't apply +# replace_column and replace_result to it. It will be enabled again when +# support of replace_column and replace_result on metadata will be +# implemented. +# +#--enable_metadata +prepare stmt1 from ' SELECT @@version ' ; +# egalize the version +--replace_column 1 <version> +execute stmt1 ; +#--disable_metadata + +## do @var:= and set @var= +# cases derived from client_test.c: test_do_set() +prepare stmt_do from ' do @var:= (1 in (select a from t1)) ' ; +prepare stmt_set from ' set @var= (1 in (select a from t1)) ' ; +let $1= 3 ; +while ($1) +{ + execute stmt_do ; + --disable_query_log + select @var as 'content of @var is:' ; + --enable_query_log + execute stmt_set ; + --disable_query_log + select @var as 'content of @var is:' ; + --enable_query_log + dec $1 ; +} +# the same test with a table containing one column and 'select *' +--disable_warnings +drop table if exists t5 ; +--enable_warnings +create table t5 (a int) ; +prepare stmt_do from ' do @var:= (1 in (select a from t5)) ' ; +prepare stmt_set from ' set @var= (1 in (select a from t5)) ' ; +let $1= 3 ; +while ($1) +{ + execute stmt_do ; + --disable_query_log + select @var as 'content of @var is:' ; + --enable_query_log + execute stmt_set ; + --disable_query_log + select @var as 'content of @var is:' ; + --enable_query_log + dec $1 ; +} +drop table t5 ; +deallocate prepare stmt_do ; +deallocate prepare stmt_set ; + +## nonsense like prepare of prepare,execute or deallocate +--error ER_UNSUPPORTED_PS +prepare stmt1 from ' prepare stmt2 from '' select 1 '' ' ; +--error ER_UNSUPPORTED_PS +prepare stmt1 from ' execute stmt2 ' ; +--error ER_UNSUPPORTED_PS +prepare stmt1 from ' deallocate prepare never_prepared ' ; + +## We don't support alter view as prepared statements +--error ER_UNSUPPORTED_PS +prepare stmt1 from 'alter view v1 as select 2'; + +## switch the database connection +--error ER_UNSUPPORTED_PS +prepare stmt4 from ' use test ' ; + +## create/drop database +prepare stmt3 from ' create database mysqltest '; +create database mysqltest ; +prepare stmt3 from ' drop database mysqltest '; +drop database mysqltest ; + +#### table related commands +## describe +prepare stmt3 from ' describe t2 '; +execute stmt3; +drop table t2 ; +--error 1146 +execute stmt3; +## lock/unlock +--error ER_UNSUPPORTED_PS +prepare stmt3 from ' lock tables t1 read ' ; +--error ER_UNSUPPORTED_PS +prepare stmt3 from ' unlock tables ' ; +## Load/Unload table contents +--error ER_UNSUPPORTED_PS +prepare stmt1 from ' load data infile ''data.txt'' +into table t1 fields terminated by ''\t'' '; +prepare stmt1 from ' select * into outfile ''data.txt'' from t1 '; +execute stmt1 ; +## +prepare stmt1 from ' optimize table t1 ' ; +prepare stmt1 from ' analyze table t1 ' ; +prepare stmt1 from ' checksum table t1 ' ; +prepare stmt1 from ' repair table t1 ' ; +--error ER_UNSUPPORTED_PS +prepare stmt1 from ' restore table t1 from ''data.txt'' ' ; +## handler +--error ER_UNSUPPORTED_PS +prepare stmt1 from ' handler t1 open '; + + +## commit/rollback +prepare stmt3 from ' commit ' ; +prepare stmt3 from ' rollback ' ; + + +## switch the sql_mode +prepare stmt4 from ' SET sql_mode=ansi '; +execute stmt4; +# check if the sql_mode is now ansi +select 'a' || 'b' ; +prepare stmt4 from ' SET sql_mode="" '; +execute stmt4; +# check if the sql_mode is not ansi +select '2' || '3' ; +# Will a switch of the sqlmode affect the execution of already prepared +# statements ? +prepare stmt5 from ' select ''2'' || ''3'' ' ; +execute stmt5; +SET sql_mode=ansi; +execute stmt5; +SET sql_mode=""; + +prepare stmt1 from ' flush local privileges ' ; +prepare stmt1 from ' reset query cache ' ; +prepare stmt1 from ' KILL 0 '; + +## simple explain +# cases derived from client_test.c: test_explain_bug() +prepare stmt1 from ' explain select a from t1 order by b '; +# PS protocol gives slightly different metadata +--disable_ps_protocol +--enable_metadata +execute stmt1; +--disable_metadata +SET @arg00=1 ; +prepare stmt1 from ' explain select a from t1 where a > ? order by b '; +--enable_metadata +execute stmt1 using @arg00; +--disable_metadata +--enable_ps_protocol + +## parameters with probably problematic characters (quote, double quote) +# cases derived from client_test.c: test_logs() +# try if +--disable_warnings +drop table if exists t2; +--enable_warnings +create table t2 (id smallint, name varchar(20)) ; +prepare stmt1 from ' insert into t2 values(?, ?) ' ; +set @id= 9876 ; +set @arg00= 'MySQL - Open Source Database' ; +set @arg01= "'" ; +set @arg02= '"' ; +set @arg03= "my'sql'" ; +set @arg04= 'my"sql"' ; +insert into t2 values ( @id , @arg00 ); +insert into t2 values ( @id , @arg01 ); +insert into t2 values ( @id , @arg02 ); +insert into t2 values ( @id , @arg03 ); +insert into t2 values ( @id , @arg04 ); +prepare stmt1 from ' select * from t2 where id= ? and name= ? '; +execute stmt1 using @id, @arg00 ; +execute stmt1 using @id, @arg01 ; +execute stmt1 using @id, @arg02 ; +execute stmt1 using @id, @arg03 ; +execute stmt1 using @id, @arg04 ; +drop table t2; + +################ CREATE/DROP/ALTER/RENAME TESTS ################ +--disable_query_log +select '------ create/drop/alter/rename tests ------' as test_sequence ; +--enable_query_log + +--disable_warnings +drop table if exists t2, t3; +--enable_warnings + +## DROP TABLE +prepare stmt_drop from ' drop table if exists t2 ' ; +--disable_warnings +execute stmt_drop; +--enable_warnings + +## CREATE TABLE +prepare stmt_create from ' create table t2 ( + a int primary key, b char(10)) '; +execute stmt_create; +prepare stmt3 from ' create table t3 like t2 '; +execute stmt3; +drop table t3; + +## CREATE TABLE .. SELECT +set @arg00=1; +prepare stmt3 from ' create table t3 (m int) select ? as m ' ; +# Bug#4280 server hangs, prepared "create table .. as select ? .." +execute stmt3 using @arg00; +select m from t3; +drop table t3; + +prepare stmt3 from ' create index t2_idx on t2(b) '; +prepare stmt3 from ' drop index t2_idx on t2 ' ; +prepare stmt3 from ' alter table t2 drop primary key '; + +## RENAME TABLE +--disable_warnings +drop table if exists new_t2; +--enable_warnings +prepare stmt3 from ' rename table t2 to new_t2 '; +execute stmt3; +--error 1050 +execute stmt3; +rename table new_t2 to t2; +drop table t2; +## RENAME more than on TABLE within one statement +# cases derived from client_test.c: test_rename() +prepare stmt1 from ' rename table t5 to t6, t7 to t8 ' ; +create table t5 (a int) ; +# rename must fail, t7 does not exist +# Clean up the filename here because embedded server reports whole path +--replace_result $MYSQLTEST_VARDIR . master-data/ '' t7.frm t7 +--error 1017 +execute stmt1 ; +create table t7 (a int) ; +# rename, t5 -> t6 and t7 -> t8 +execute stmt1 ; +# rename must fail, t5 and t7 does not exist t6 and t8 already exist +--error 1050 +execute stmt1 ; +rename table t6 to t5, t8 to t7 ; +# rename, t5 -> t6 and t7 -> t8 +execute stmt1 ; +drop table t6, t8 ; + + +################ BIG STATEMENT TESTS ################ +--disable_query_log +select '------ big statement tests ------' as test_sequence ; +--enable_query_log +# The following tests use huge numbers of lines, characters or parameters +# per prepared statement. +# I assume the server and also the client (mysqltest) are stressed. +# +# Attention: The limits used are NOT derived from the manual +# or other sources. + +## many lines ( 50 ) +let $my_stmt= select 'ABC' as my_const_col from t1 where +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 AND +1 = 1 ; +eval ($my_stmt) ; +eval prepare stmt1 from "$my_stmt" ; +execute stmt1 ; +execute stmt1 ; + +## many characters ( about 1400 ) + +let $my_stmt= select 'ABC' as my_const_col FROM t1 WHERE +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' AND +'1234567890123456789012345678901234567890123456789012345678901234567890' += '1234567890123456789012345678901234567890123456789012345678901234567890' ; +eval ($my_stmt) ; +eval prepare stmt1 from "$my_stmt" ; +execute stmt1 ; +execute stmt1 ; + + +## many parameters ( 50 ) +--disable_query_log +set @arg00= 1; +set @arg01= 1; +set @arg02= 1; +set @arg03= 1; +set @arg04= 1; +set @arg05= 1; +set @arg06= 1; +set @arg07= 1; +set @arg10= 1; +set @arg11= 1; +set @arg12= 1; +set @arg13= 1; +set @arg14= 1; +set @arg15= 1; +set @arg16= 1; +set @arg17= 1; +set @arg20= 1; +set @arg21= 1; +set @arg22= 1; +set @arg23= 1; +set @arg24= 1; +set @arg25= 1; +set @arg26= 1; +set @arg27= 1; +set @arg30= 1; +set @arg31= 1; +set @arg32= 1; +set @arg33= 1; +set @arg34= 1; +set @arg35= 1; +set @arg36= 1; +set @arg37= 1; +set @arg40= 1; +set @arg41= 1; +set @arg42= 1; +set @arg43= 1; +set @arg44= 1; +set @arg45= 1; +set @arg46= 1; +set @arg47= 1; +set @arg50= 1; +set @arg51= 1; +set @arg52= 1; +set @arg53= 1; +set @arg54= 1; +set @arg55= 1; +set @arg56= 1; +set @arg57= 1; +set @arg60= 1; +set @arg61= 1; +--enable_query_log + +select 'ABC' as my_const_col FROM t1 WHERE +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and @arg00=@arg00 and +@arg00=@arg00 ; +prepare stmt1 from ' select ''ABC'' as my_const_col FROM t1 WHERE + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? and ? = ? and ? = ? and ? = ? and + ? = ? ' ; +execute stmt1 using +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, +@arg00, @arg00; +execute stmt1 using +@arg00, @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, +@arg10, @arg11, @arg12, @arg13, @arg14, @arg15, @arg16, @arg17, +@arg20, @arg21, @arg22, @arg23, @arg24, @arg25, @arg26, @arg27, +@arg30, @arg31, @arg32, @arg33, @arg34, @arg35, @arg36, @arg37, +@arg40, @arg41, @arg42, @arg43, @arg44, @arg45, @arg46, @arg47, +@arg50, @arg51, @arg52, @arg53, @arg54, @arg55, @arg56, @arg57, +@arg60, @arg61 ; + +# cases derived from client_test.c: test_mem_overun() +--disable_warnings +drop table if exists t5 ; +--enable_warnings + +set @col_num= 1000 ; + +--disable_query_log +set @string= 'create table t5( ' ; +let $1=`select @col_num - 1` ; +while ($1) +{ + eval set @string= concat(@string, 'c$1 int,') ; + dec $1 ; +} +set @string= concat(@string, 'c0 int)' ); +--enable_query_log +select @string as "" ; +prepare stmt1 from @string ; +execute stmt1 ; + +--disable_query_log +set @string= 'insert into t5 values(' ; +let $1=`select @col_num - 1` ; +while ($1) +{ + eval set @string= concat(@string, '1 ,') ; + dec $1 ; +} +eval set @string= concat(@string, '1 )') ; +--enable_query_log +select @string as "" ; +prepare stmt1 from @string ; +execute stmt1 ; + +prepare stmt1 from ' select * from t5 ' ; +--enable_metadata +# prevent too long lines +--vertical_results +--disable_result_log +execute stmt1 ; +--enable_result_log +--disable_metadata +--horizontal_results + +drop table t1, t5, t9; + +##### RULES OF THUMB TO PRESERVE THE SYSTEMATICS OF THE PS TEST CASES ##### +# +# 0. You don't have the time to +# - read and pay attention to these rules of thumb +# - accept that QA may move your test case to a different place +# (I will not change your code!!) . +# Please append your test case to +# t/ps.test +# +# 1. You have more time and want to get as much value from you test case as +# possible. Please try to make the following decisions: +# +# Will the execution or result of the sub test case depend on the +# properties of a storage engine ? +# +# NO --> alter t/ps_1general.test (Example: Command with syntax error) +# If you need a table, please try to use +# t1 - very simple table +# t9 - table with nearly all available column types +# whenever possible. +# +# The structure and the content of these tables can be found in +# include/ps_create.inc CREATE TABLE ... +# include/ps_renew.inc DELETE all rows and INSERT some rows +# +# Both tables are managed by the same storage engine. +# The type of the storage engine is stored in the variable +# '$type' . In ps_1general.test $type is set to 'MYISAM'. +# +# Please feel free to source ps_create.inc or ps_renew.inc +# whenever you think it helps. But please restore the original +# state of these tables after your tests, because the following +# statements may depend on it. +# +# YES +# | +# | +# Is it possible to apply the sub test case to all table types ? +# YES --> alter include/ps_query.inc (for SELECTs) +# include/ps_modify.inc (for INSERT/UPDATE/DELETE) +# include/ps_modify1.inc (also for INSERT/UPDATE/DELETE, +# but t/ps_5merge.test will not source that file) +# Please try to find an appropriate place within the file. +# It would be nice if we have some systematics in the +# order of the sub test cases (if possible). +# +# Please be aware, that +# include: ps_query.inc, ps_modify.inc, ps_modify1.inc +# will be sourced by several test case files stored within the +# subdirectory 't'. So every change here will affect several test +# cases. +# +# NO +# | +# | +# Append the sub test case to the appropriate +# ps_<number><table type>.test . +# +# 2. The current structure of the PS tests +# +# t/ps_1general.test Check of basic PS features, SHOW commands and DDL +# The tests should not depend on the table type. +# +# t/ps_2myisam Check of PS on tables of type MYISAM . +# t/ps_3innodb Check of PS on tables of type InnoDB . +# ... +# t/ps_6bdb Check of PS on tables of type BDB . +# All storage engine related tests use the variable $type to hold the +# name of the storage engine. +# +# include/ps_query.inc test cases with SELECT/... +# These test cases should not modify the content or +# the structure (DROP/ALTER..) of the tables +# 't1' and 't9'. +# include/ps_modify.inc test cases with INSERT/UPDATE/... +# These test cases should not modify the structure +# (DROP/ALTER..) of the tables +# 't1' and 't9'. +# These two test sequences will be applied to all table types . +# +# include/ps_modify1.inc test cases with INSERT/UPDATE/... +# This test sequences will be applied to all table types +# except MERGE tables. +# +# include/ps_create.inc DROP and CREATE of the tables +# 't1' and 't9' . +# include/ps_renew.inc DELETE all rows and INSERT some rows, that means +# recreate the original content of these tables. +# Please do not alter the commands concerning these two tables. +# +# Please feel free and encouraged to exploit the current code sharing +# mechanism of the 'ps_<number><table type>' test cases. It is an convenient +# way to check all storage engines. +# +# Thank you for reading these rules of thumb. +# +# Matthias + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/ps_grant.test b/mysql-test/suite/pbxt/t/ps_grant.test new file mode 100644 index 00000000000..b25facdb418 --- /dev/null +++ b/mysql-test/suite/pbxt/t/ps_grant.test @@ -0,0 +1,128 @@ +# Can't test grants with embedded server +-- source include/not_embedded.inc + +let $type= 'MYISAM' ; + +################ GRANT/REVOKE/DROP affecting a parallel session ################ +--disable_query_log +select '------ grant/revoke/drop affects a parallel session test ------' + as test_sequence ; +--enable_query_log + +#---------------------------------------------------------------------# +# Here we test that: +# 1. A new GRANT will be visible within another sessions. # +# # +# Let's assume there is a parallel session with an already prepared # +# statement for a table. # +# A DROP TABLE will affect the EXECUTE properties. # +# A REVOKE will affect the EXECUTE properties. # +#---------------------------------------------------------------------# + +# Who am I ? +# this is different across different systems: +# select current_user(), user() ; + +#### create a new user account #### +## There should be no grants for that non existing user +--error 1141 +show grants for second_user@localhost ; +## create a new user account by using GRANT statements on t9 +create database mysqltest; +# create the tables (t1 and t9) used in many tests +use mysqltest; +--disable_query_log +--source include/ps_create.inc +--source include/ps_renew.inc +--enable_query_log +use test; +grant usage on mysqltest.* to second_user@localhost +identified by 'looser' ; +grant select on mysqltest.t9 to second_user@localhost +identified by 'looser' ; +show grants for second_user@localhost ; + + +#### establish a second session to the new user account +connect (con3,localhost,second_user,looser,mysqltest); +## switch to the second session +connection con3; +# Who am I ? +select current_user(); +## check the access rights +show grants for current_user(); +prepare s_t9 from 'select c1 as my_col + from t9 where c1= 1' ; +execute s_t9 ; +# check that we cannot do a SELECT on the table t1; +--error 1142 +select a as my_col from t1; + + +#### give access rights to t1 and drop table t9 +## switch back to the first session +connection default; +grant select on mysqltest.t1 to second_user@localhost +identified by 'looser' ; +show grants for second_user@localhost ; +drop table mysqltest.t9 ; +show grants for second_user@localhost ; + + +#### check the access as new user +## switch to the second session +connection con3; +######## Question 1: The table t1 should be now accessible. ######## +show grants for second_user@localhost ; +prepare s_t1 from 'select a as my_col from t1' ; +execute s_t1 ; +######## Question 2: The table t9 does not exist. ######## +--error 1146 +execute s_t9 ; +deallocate prepare s_t9; + + +#### revoke the access rights to t1 +## switch back to the first session +connection default; +revoke all privileges on mysqltest.t1 from second_user@localhost +identified by 'looser' ; +show grants for second_user@localhost ; + +#### check the access as new user +## switch to the second session +connection con3; +show grants for second_user@localhost ; +######## Question 2: The table t1 should be now not accessible. ######## +--error 1142 +execute s_t1 ; + +## cleanup +## switch back to the first session +connection default; +## disconnect the second session +disconnect con3 ; +## remove all rights of second_user@localhost +revoke all privileges, grant option from second_user@localhost ; +show grants for second_user@localhost ; +drop user second_user@localhost ; +commit ; +--error 1141 +show grants for second_user@localhost ; + +drop database mysqltest; + +# End of 4.1 tests + +# +# grant/revoke + drop user +# +prepare stmt3 from ' grant all on test.t1 to drop_user@localhost +identified by ''looser'' '; +grant all on test.t1 to drop_user@localhost +identified by 'looser' ; +prepare stmt3 from ' revoke all privileges on test.t1 from +drop_user@localhost '; +revoke all privileges on test.t1 from drop_user@localhost ; +prepare stmt3 from ' drop user drop_user@localhost '; +drop user drop_user@localhost; diff --git a/mysql-test/suite/pbxt/t/range.test b/mysql-test/suite/pbxt/t/range.test new file mode 100644 index 00000000000..8615c76888d --- /dev/null +++ b/mysql-test/suite/pbxt/t/range.test @@ -0,0 +1,782 @@ +# +# Problem with range optimizer +# + +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings + +CREATE TABLE t1 ( + event_date date DEFAULT '0000-00-00' NOT NULL, + type int(11) DEFAULT '0' NOT NULL, + event_id int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (event_date,type,event_id) +); + +INSERT INTO t1 VALUES ('1999-07-10',100100,24), ('1999-07-11',100100,25), +('1999-07-13',100600,0), ('1999-07-13',100600,4), ('1999-07-13',100600,26), +('1999-07-14',100600,10), ('1999-07-15',100600,16), ('1999-07-15',100800,45), +('1999-07-15',101000,47), ('1999-07-16',100800,46), ('1999-07-20',100600,5), +('1999-07-20',100600,27), ('1999-07-21',100600,11), ('1999-07-22',100600,17), +('1999-07-23',100100,39), ('1999-07-24',100100,39), ('1999-07-24',100500,40), +('1999-07-25',100100,39), ('1999-07-27',100600,1), ('1999-07-27',100600,6), +('1999-07-27',100600,28), ('1999-07-28',100600,12), ('1999-07-29',100500,41), +('1999-07-29',100600,18), ('1999-07-30',100500,41), ('1999-07-31',100500,41), +('1999-08-01',100700,34), ('1999-08-03',100600,7), ('1999-08-03',100600,29), +('1999-08-04',100600,13), ('1999-08-05',100500,42), ('1999-08-05',100600,19), +('1999-08-06',100500,42), ('1999-08-07',100500,42), ('1999-08-08',100500,42), +('1999-08-10',100600,2), ('1999-08-10',100600,9), ('1999-08-10',100600,30), +('1999-08-11',100600,14), ('1999-08-12',100600,20), ('1999-08-17',100500,8), +('1999-08-17',100600,31), ('1999-08-18',100600,15), ('1999-08-19',100600,22), +('1999-08-24',100600,3), ('1999-08-24',100600,32), ('1999-08-27',100500,43), +('1999-08-31',100600,33), ('1999-09-17',100100,37), ('1999-09-18',100100,37), +('1999-09-19',100100,37), ('2000-12-18',100700,38); + +select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date; +explain select event_date,type,event_id from t1 WHERE type = 100601 and event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date; +select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date <= "1999-07-15" AND (type=100600 OR type=100100) or event_date >= "1999-07-01" AND event_date <= "1999-07-15" AND type=100099; +drop table t1; + +CREATE TABLE t1 ( + PAPER_ID smallint(6) DEFAULT '0' NOT NULL, + YEAR smallint(6) DEFAULT '0' NOT NULL, + ISSUE smallint(6) DEFAULT '0' NOT NULL, + CLOSED tinyint(4) DEFAULT '0' NOT NULL, + ISS_DATE date DEFAULT '0000-00-00' NOT NULL, + PRIMARY KEY (PAPER_ID,YEAR,ISSUE) +); +INSERT INTO t1 VALUES (3,1999,34,0,'1999-07-12'), (1,1999,111,0,'1999-03-23'), + (1,1999,222,0,'1999-03-23'), (3,1999,33,0,'1999-07-12'), + (3,1999,32,0,'1999-07-12'), (3,1999,31,0,'1999-07-12'), + (3,1999,30,0,'1999-07-12'), (3,1999,29,0,'1999-07-12'), + (3,1999,28,0,'1999-07-12'), (1,1999,40,1,'1999-05-01'), + (1,1999,41,1,'1999-05-01'), (1,1999,42,1,'1999-05-01'), + (1,1999,46,1,'1999-05-01'), (1,1999,47,1,'1999-05-01'), + (1,1999,48,1,'1999-05-01'), (1,1999,49,1,'1999-05-01'), + (1,1999,50,0,'1999-05-01'), (1,1999,51,0,'1999-05-01'), + (1,1999,200,0,'1999-06-28'), (1,1999,52,0,'1999-06-28'), + (1,1999,53,0,'1999-06-28'), (1,1999,54,0,'1999-06-28'), + (1,1999,55,0,'1999-06-28'), (1,1999,56,0,'1999-07-01'), + (1,1999,57,0,'1999-07-01'), (1,1999,58,0,'1999-07-01'), + (1,1999,59,0,'1999-07-01'), (1,1999,60,0,'1999-07-01'), + (3,1999,35,0,'1999-07-12'); +select YEAR,ISSUE from t1 where PAPER_ID=3 and (YEAR>1999 or (YEAR=1999 and ISSUE>28)) order by YEAR,ISSUE; +check table t1; +repair table t1; +drop table t1; + +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + parent_id int(11) DEFAULT '0' NOT NULL, + level tinyint(4) DEFAULT '0' NOT NULL, + PRIMARY KEY (id), + KEY parent_id (parent_id), + KEY level (level) +); +INSERT INTO t1 VALUES (1,0,0), (3,1,1), (4,1,1), (8,2,2), (9,2,2), (17,3,2), +(22,4,2), (24,4,2), (28,5,2), (29,5,2), (30,5,2), (31,6,2), (32,6,2), (33,6,2), +(203,7,2), (202,7,2), (20,3,2), (157,0,0), (193,5,2), (40,7,2), (2,1,1), +(15,2,2), (6,1,1), (34,6,2), (35,6,2), (16,3,2), (7,1,1), (36,7,2), (18,3,2), +(26,5,2), (27,5,2), (183,4,2), (38,7,2), (25,5,2), (37,7,2), (21,4,2), +(19,3,2), (5,1,1), (179,5,2); +SELECT * FROM t1 WHERE level = 1 AND parent_id = 1; +# The following select returned 0 rows in 3.23.8 +SELECT * FROM t1 WHERE level = 1 AND parent_id = 1 order by id; +drop table t1; + +# +# Testing of bug in range optimizer with many key parts and > and < +# + +create table t1( + Satellite varchar(25) not null, + SensorMode varchar(25) not null, + FullImageCornersUpperLeftLongitude double not null, + FullImageCornersUpperRightLongitude double not null, + FullImageCornersUpperRightLatitude double not null, + FullImageCornersLowerRightLatitude double not null, + index two (Satellite, SensorMode, FullImageCornersUpperLeftLongitude, FullImageCornersUpperRightLongitude, FullImageCornersUpperRightLatitude, FullImageCornersLowerRightLatitude)); + +insert into t1 values("OV-3","PAN1",91,-92,40,50); +insert into t1 values("OV-4","PAN1",91,-92,40,50); + +select * from t1 where t1.Satellite = "OV-3" and t1.SensorMode = "PAN1" and t1.FullImageCornersUpperLeftLongitude > -90.000000 and t1.FullImageCornersUpperRightLongitude < -82.000000; +drop table t1; + +create table t1 ( aString char(100) not null default "", key aString (aString(10)) ); +insert t1 (aString) values ( "believe in myself" ), ( "believe" ), ("baaa" ), ( "believe in love"); +select * from t1 where aString < "believe in myself" order by aString; +select * from t1 where aString > "believe in love" order by aString; +alter table t1 drop key aString; +select * from t1 where aString < "believe in myself" order by aString; +select * from t1 where aString > "believe in love" order by aString; +drop table t1; + +# +# Problem with binary strings +# + +CREATE TABLE t1 ( + t1ID int(10) unsigned NOT NULL auto_increment, + art binary(1) NOT NULL default '', + KNR char(5) NOT NULL default '', + RECHNR char(6) NOT NULL default '', + POSNR char(2) NOT NULL default '', + ARTNR char(10) NOT NULL default '', + TEX char(70) NOT NULL default '', + PRIMARY KEY (t1ID), + KEY IdxArt (art), + KEY IdxKnr (KNR), + KEY IdxArtnr (ARTNR) +) ENGINE=MyISAM; + +INSERT INTO t1 (art) VALUES ('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'), +('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'),('j'); +select count(*) from t1 where upper(art) = 'J'; +select count(*) from t1 where art = 'J' or art = 'j'; +select count(*) from t1 where art = 'j' or art = 'J'; +select count(*) from t1 where art = 'j'; +select count(*) from t1 where art = 'J'; +drop table t1; +# +# BETWEEN problems +# +create table t1 (x int, y int, index(x), index(y)); +insert into t1 (x) values (1),(2),(3),(4),(5),(6),(7),(8),(9); +update t1 set y=x; +# between with only one end fixed +explain select * from t1, t1 t2 where t1.y = 8 and t2.x between 7 and t1.y+0; +explain select * from t1, t1 t2 where t1.y = 8 and t2.x >= 7 and t2.x <= t1.y+0; +# between with both expressions on both ends +explain select * from t1, t1 t2 where t1.y = 2 and t2.x between t1.y-1 and t1.y+1; +explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= t1.y-1 and t2.x <= t1.y+1; +# equation propagation +explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 0 and t1.y; +explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 0 and t2.x <= t1.y; +# testing IN +explain select count(*) from t1 where x in (1); +explain select count(*) from t1 where x in (1,2); +drop table t1; + +# +# bug #1172: "Force index" option caused server crash +# +CREATE TABLE t1 (key1 int(11) NOT NULL default '0', KEY i1 (key1)); +INSERT INTO t1 VALUES (0),(0),(0),(0),(0),(1),(1); +CREATE TABLE t2 (keya int(11) NOT NULL default '0', KEY j1 (keya)); +INSERT INTO t2 VALUES (0),(0),(1),(1),(2),(2); +explain select * from t1, t2 where (t1.key1 <t2.keya + 1) and t2.keya=3; +explain select * from t1 force index(i1), t2 force index(j1) where + (t1.key1 <t2.keya + 1) and t2.keya=3; +DROP TABLE t1,t2; + +# +# bug #1724: use RANGE on more selective column instead of REF on less +# selective + +CREATE TABLE t1 ( + a int(11) default NULL, + b int(11) default NULL, + KEY a (a), + KEY b (b) +) ENGINE=MyISAM; + + +INSERT INTO t1 VALUES +(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(10,2), +(13,2),(14,2),(15,2),(16,2),(17,3),(17,3),(16,3),(17,3),(19,3),(20,3), +(21,4),(22,5),(23,5),(24,5),(25,5),(26,5),(30,5),(31,5),(32,5),(33,5), +(33,5),(33,5),(33,5),(33,5),(34,5),(35,5); + +# we expect that optimizer will choose index on A +EXPLAIN SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +DROP TABLE t1; + +# +# Test problem with range optimzer and sub ranges +# + +CREATE TABLE t1 (a int, b int, c int, INDEX (c,a,b)); +INSERT INTO t1 VALUES (1,0,0),(1,0,0),(1,0,0); +INSERT INTO t1 VALUES (0,1,0),(0,1,0),(0,1,0); +# -- First reports 3; second reports 6 +SELECT COUNT(*) FROM t1 WHERE (c=0 and a=1) or (c=0 and b=1); +SELECT COUNT(*) FROM t1 WHERE (c=0 and b=1) or (c=0 and a=1); +DROP TABLE t1; + +# +# Test problem with range optimization over overlapping ranges (#2448) +# + +CREATE TABLE t1 ( a int not null, b int not null, INDEX ab(a,b) ); +INSERT INTO t1 VALUES (47,1), (70,1), (15,1), (15, 4); +SELECT * FROM t1 +WHERE +( + ( b =1 AND a BETWEEN 14 AND 21 ) OR + ( b =2 AND a BETWEEN 16 AND 18 ) OR + ( b =3 AND a BETWEEN 15 AND 19 ) OR + (a BETWEEN 19 AND 47) +); +DROP TABLE t1; + +# +# Test of problem with IN on many different keyparts. (Bug #4157) +# + +CREATE TABLE t1 ( +id int( 11 ) unsigned NOT NULL AUTO_INCREMENT , +line int( 5 ) unsigned NOT NULL default '0', +columnid int( 3 ) unsigned NOT NULL default '0', +owner int( 3 ) unsigned NOT NULL default '0', +ordinal int( 3 ) unsigned NOT NULL default '0', +showid smallint( 6 ) unsigned NOT NULL default '1', +tableid int( 1 ) unsigned NOT NULL default '1', +content int( 5 ) unsigned NOT NULL default '188', +PRIMARY KEY ( owner, id ) , +KEY menu( owner, showid, columnid ) , +KEY `COLUMN` ( owner, columnid, line ) , +KEY `LINES` ( owner, tableid, content, id ) , +KEY recount( owner, line ) +) ENGINE = MYISAM; + +INSERT into t1 (owner,id,columnid,line) values (11,15,15,1),(11,13,13,5); + +SELECT id, columnid, tableid, content, showid, line, ordinal FROM t1 WHERE owner=11 AND ((columnid IN ( 15, 13, 14 ) AND line IN ( 1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 31 )) OR (columnid IN ( 13, 14 ) AND line IN ( 15 ))) LIMIT 0 , 30; +drop table t1; + +# +# test for a bug with in() and unique key +# + +create table t1 (id int(10) primary key); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9); + +select id from t1 where id in (2,5,9) ; +select id from t1 where id=2 or id=5 or id=9 ; +drop table t1; +create table t1 ( id1 int not null, id2 int not null, idnull int null, c char(20), primary key (id1,id2)); +insert into t1 values (0,1,NULL,"aaa"), (1,1,NULL,"aaa"), (2,1,NULL,"aaa"), + (3,1,NULL,"aaa"), (4,1,NULL,"aaa"), (5,1,NULL,"aaa"), + (6,1,NULL,"aaa"), (7,1,NULL,"aaa"), (8,1,NULL,"aaa"), + (9,1,NULL,"aaa"), (10,1,NULL,"aaa"), (11,1,NULL,"aaa"), + (12,1,NULL,"aaa"), (13,1,NULL,"aaa"), (14,1,NULL,"aaa"), + (15,1,NULL,"aaa"), (16,1,NULL,"aaa"), (17,1,NULL,"aaa"), + (18,1,NULL,"aaa"), (19,1,NULL,"aaa"), (20,1,NULL,"aaa"); +select a.id1, b.idnull from t1 as a, t1 as b where a.id2=1 and a.id1=1 and b.id1=a.idnull order by b.id2 desc limit 1; +drop table t1; + + +# +# Problem with optimizing != +# + +create table t1 ( + id int not null auto_increment, + name char(1) not null, + uid int not null, + primary key (id), + index uid_index (uid)); + +create table t2 ( + id int not null auto_increment, + name char(1) not null, + uid int not null, + primary key (id), + index uid_index (uid)); + +insert into t1(id, uid, name) values(1, 0, ' '); +insert into t1(uid, name) values(0, ' '); + +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; +insert into t2(uid, name) select uid, name from t1; +insert into t2(uid, name) select uid, name from t1; +insert into t2(uid, name) select uid, name from t1; +insert into t2(uid, name) select uid, name from t1; +insert into t1(uid, name) select uid, name from t2; + +delete from t2; +insert into t2(uid, name) values + (1, CHAR(64+1)), + (2, CHAR(64+2)), + (3, CHAR(64+3)), + (4, CHAR(64+4)), + (5, CHAR(64+5)), + (6, CHAR(64+6)), + (7, CHAR(64+7)), + (8, CHAR(64+8)), + (9, CHAR(64+9)), + (10, CHAR(64+10)), + (11, CHAR(64+11)), + (12, CHAR(64+12)), + (13, CHAR(64+13)), + (14, CHAR(64+14)), + (15, CHAR(64+15)), + (16, CHAR(64+16)), + (17, CHAR(64+17)), + (18, CHAR(64+18)), + (19, CHAR(64+19)), + (20, CHAR(64+20)), + (21, CHAR(64+21)), + (22, CHAR(64+22)), + (23, CHAR(64+23)), + (24, CHAR(64+24)), + (25, CHAR(64+25)), + (26, CHAR(64+26)); + +insert into t1(uid, name) select uid, name from t2 order by uid; + +delete from t2; +insert into t2(id, uid, name) select id, uid, name from t1; + +select count(*) from t1; +select count(*) from t2; + +analyze table t1,t2; + +explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0; +explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid > 0; +explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0; +explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid != 0; + +select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0; +select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0; + +drop table t1,t2; + +# Fix for bug#4488 +# +create table t1 (x bigint unsigned not null); +insert into t1(x) values (0xfffffffffffffff0); +insert into t1(x) values (0xfffffffffffffff1); +select * from t1; +select count(*) from t1 where x>0; +select count(*) from t1 where x=0; +select count(*) from t1 where x<0; +select count(*) from t1 where x < -16; +select count(*) from t1 where x = -16; +select count(*) from t1 where x > -16; +select count(*) from t1 where x = 18446744073709551601; + + +create table t2 (x bigint not null); +insert into t2(x) values (-16); +insert into t2(x) values (-15); +select * from t2; +select count(*) from t2 where x>0; +select count(*) from t2 where x=0; +select count(*) from t2 where x<0; +select count(*) from t2 where x < -16; +select count(*) from t2 where x = -16; +select count(*) from t2 where x > -16; +select count(*) from t2 where x = 18446744073709551601; +drop table t1,t2; + +--disable_warnings +create table t1 (x bigint unsigned not null primary key) engine=innodb; +--enable_warnings +insert into t1(x) values (0xfffffffffffffff0); +insert into t1(x) values (0xfffffffffffffff1); +select * from t1; +select count(*) from t1 where x>0; +select count(*) from t1 where x=0; +select count(*) from t1 where x<0; +select count(*) from t1 where x < -16; +select count(*) from t1 where x = -16; +select count(*) from t1 where x > -16; +select count(*) from t1 where x = 18446744073709551601; + +drop table t1; + +# +# Bug #11185 incorrect comparison of unsigned int to signed constant +# +create table t1 (a bigint unsigned); +create index t1i on t1(a); +insert into t1 select 18446744073709551615; +insert into t1 select 18446744073709551614; + +explain select * from t1 where a <> -1; +select * from t1 where a <> -1; +explain select * from t1 where a > -1 or a < -1; +select * from t1 where a > -1 or a < -1; +explain select * from t1 where a > -1; +select * from t1 where a > -1; +explain select * from t1 where a < -1; +select * from t1 where a < -1; + +drop table t1; + +# +# Bug #6045: Binary Comparison regression in MySQL 4.1 +# Binary searches didn't use a case insensitive index. +# +set names latin1; +create table t1 (a char(10), b text, key (a)) character set latin1; +INSERT INTO t1 (a) VALUES +('111'),('222'),('222'),('222'),('222'),('444'),('aaa'),('AAA'),('bbb'); +# all these three can be optimized +explain select * from t1 where a='aaa'; +explain select * from t1 where a=binary 'aaa'; +explain select * from t1 where a='aaa' collate latin1_bin; +# this one cannot: +explain select * from t1 where a='aaa' collate latin1_german1_ci; +drop table t1; + +# Test for BUG#9348 "result for WHERE A AND (B OR C) differs from WHERE a AND (C OR B)" +--disable_warnings +CREATE TABLE t1 ( + `CLIENT` char(3) character set latin1 collate latin1_bin NOT NULL default '000', + `ARG1` char(3) character set latin1 collate latin1_bin NOT NULL default '', + `ARG2` char(3) character set latin1 collate latin1_bin NOT NULL default '', + `FUNCTION` varchar(10) character set latin1 collate latin1_bin NOT NULL default '', + `FUNCTINT` int(11) NOT NULL default '0', + KEY `VERI_CLNT~2` (`ARG1`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +--enable_warnings + +INSERT INTO t1 VALUES ('000',' 0',' 0','Text 001',0), ('000',' 0',' 1','Text 002',0), + ('000',' 1',' 2','Text 003',0), ('000',' 2',' 3','Text 004',0), + ('001',' 3',' 0','Text 017',0); + +SELECT count(*) FROM t1 WHERE CLIENT='000' AND (ARG1 != ' 1' OR ARG1 != ' 2'); + +SELECT count(*) FROM t1 WHERE CLIENT='000' AND (ARG1 != ' 2' OR ARG1 != ' 1'); +drop table t1; + +# BUG#16168: Wrong range optimizer results, "Use_count: Wrong count ..." +# warnings in server stderr. +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +CREATE TABLE t2 ( + pk1 int(11) NOT NULL, + pk2 int(11) NOT NULL, + pk3 int(11) NOT NULL, + pk4 int(11) NOT NULL, + filler char(82), + PRIMARY KEY (pk1,pk2,pk3,pk4) +) DEFAULT CHARSET=latin1; + +insert into t2 select 1, A.a+10*B.a, 432, 44, 'fillerZ' from t1 A, t1 B; +INSERT INTO t2 VALUES (2621, 2635, 0, 0,'filler'), (2621, 2635, 1, 0,'filler'), + (2621, 2635, 10, 0,'filler'), (2621, 2635, 11, 0,'filler'), + (2621, 2635, 14, 0,'filler'), (2621, 2635, 1000015, 0,'filler'); + +SELECT * FROM t2 +WHERE ((((pk4 =0) AND (pk1 =2621) AND (pk2 =2635))) +OR ((pk4 =1) AND (((pk1 IN ( 7, 2, 1 ))) OR (pk1 =522)) AND ((pk2 IN ( 0, 2635)))) +) AND (pk3 >=1000000); +drop table t1, t2; + +# +# Bug #20732: Partial index and long sjis search with '>' fails sometimes +# + +create table t1(a char(2), key(a(1))); +insert into t1 values ('x'), ('xx'); +explain select a from t1 where a > 'x'; +select a from t1 where a > 'x'; +drop table t1; + +--echo End of 4.1 tests + +# +# Test for optimization request #10561: to use keys for +# NOT IN (c1,...,cn) and NOT BETWEEN c1 AND c2 +# + +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + status varchar(20), + PRIMARY KEY (id), + KEY (status) +); + +INSERT INTO t1 VALUES +(1,'B'), (2,'B'), (3,'B'), (4,'B'), (5,'B'), (6,'B'), +(7,'B'), (8,'B'), (9,'B'), (10,'B'), (11,'B'), (12,'B'), +(13,'B'), (14,'B'), (15,'B'), (16,'B'), (17,'B'), (18,'B'), +(19,'B'), (20,'B'), (21,'B'), (22,'B'), (23,'B'), (24,'B'), +(25,'A'), (26,'A'), (27,'A'), (28,'A'), (29,'A'), (30,'A'), +(31,'A'), (32,'A'), (33,'A'), (34,'A'), (35,'A'), (36,'A'), +(37,'A'), (38,'A'), (39,'A'), (40,'A'), (41,'A'), (42,'A'), +(43,'A'), (44,'A'), (45,'A'), (46,'A'), (47,'A'), (48,'A'), +(49,'A'), (50,'A'), (51,'A'), (52,'A'), (53,'C'), (54,'C'), +(55,'C'), (56,'C'), (57,'C'), (58,'C'), (59,'C'), (60,'C'); + +EXPLAIN SELECT * FROM t1 WHERE status <> 'A' AND status <> 'B'; +EXPLAIN SELECT * FROM t1 WHERE status NOT IN ('A','B'); + +SELECT * FROM t1 WHERE status <> 'A' AND status <> 'B'; +SELECT * FROM t1 WHERE status NOT IN ('A','B'); + +EXPLAIN SELECT status FROM t1 WHERE status <> 'A' AND status <> 'B'; +EXPLAIN SELECT status FROM t1 WHERE status NOT IN ('A','B'); + +EXPLAIN SELECT * FROM t1 WHERE status NOT BETWEEN 'A' AND 'B'; +EXPLAIN SELECT * FROM t1 WHERE status < 'A' OR status > 'B'; + +SELECT * FROM t1 WHERE status NOT BETWEEN 'A' AND 'B'; +SELECT * FROM t1 WHERE status < 'A' OR status > 'B'; + +DROP TABLE t1; + +# +# Test for bug #10031: range to be used over a view +# + +CREATE TABLE t1 (a int, b int, primary key(a,b)); + +INSERT INTO t1 VALUES + (1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3); + +CREATE VIEW v1 as SELECT a,b FROM t1 WHERE b=3; + +EXPLAIN SELECT a,b FROM t1 WHERE a < 2 and b=3; +EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3; + +EXPLAIN SELECT a,b FROM t1 WHERE a < 2; +EXPLAIN SELECT a,b FROM v1 WHERE a < 2; + +SELECT a,b FROM t1 WHERE a < 2 and b=3; +SELECT a,b FROM v1 WHERE a < 2 and b=3; + +DROP VIEW v1; +DROP TABLE t1; + +# +# Bug #11853: DELETE statement with a NOT (LIKE/<=>) where condition +# for an indexed attribute +# + +CREATE TABLE t1 (name varchar(15) NOT NULL, KEY idx(name)); +INSERT INTO t1 VALUES ('Betty'), ('Anna'); + +SELECT * FROM t1; +DELETE FROM t1 WHERE name NOT LIKE 'A%a'; +SELECT * FROM t1; + +DROP TABLE t1; + +CREATE TABLE t1 (a int, KEY idx(a)); +INSERT INTO t1 VALUES (NULL), (1), (2), (3); + +SELECT * FROM t1; +DELETE FROM t1 WHERE NOT(a <=> 2); +SELECT * FROM t1; + +DROP TABLE t1; + +# +# BUG#13317: range optimization doesn't work for IN over VIEW. +# +create table t1 (a int, b int, primary key(a,b)); +create view v1 as select a, b from t1; + +INSERT INTO `t1` VALUES +(0,0),(1,0),(2,0),(3,0),(4,0),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(11,2),(12,2) +,(13,2),(14,2),(15,3),(16,3),(17,3),(18,3),(19,3); + +--replace_column 9 # +explain select * from t1 where a in (3,4) and b in (1,2,3); +--replace_column 9 # +explain select * from v1 where a in (3,4) and b in (1,2,3); +--replace_column 9 # +explain select * from t1 where a between 3 and 4 and b between 1 and 2; +--replace_column 9 # +explain select * from v1 where a between 3 and 4 and b between 1 and 2; + +drop view v1; +drop table t1; + +# BUG#13455: +create table t3 (a int); +insert into t3 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t1 (a varchar(10), filler char(200), key(a)) charset=binary; +insert into t1 values ('a',''); +insert into t1 values ('a ',''); +insert into t1 values ('a ', ''); +insert into t1 select concat('a', 1000 + A.a + 10 * (B.a + 10 * C.a)), '' + from t3 A, t3 B, t3 C; + +create table t2 (a varchar(10), filler char(200), key(a)); +insert into t2 select * from t1; + +--replace_column 9 # +explain select * from t1 where a between 'a' and 'a '; +--replace_column 9 # +explain select * from t1 where a = 'a' or a='a '; + +--replace_column 9 # +explain select * from t2 where a between 'a' and 'a '; +--replace_column 9 # +explain select * from t2 where a = 'a' or a='a '; + +update t1 set a='b' where a<>'a'; +--replace_column 9 # +explain select * from t1 where a not between 'b' and 'b'; +select a, hex(filler) from t1 where a not between 'b' and 'b'; + +drop table t1,t2,t3; + +# +# BUG#21282 +# +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, key(a)); +insert into t2 select 2*(A.a + 10*(B.a + 10*C.a)) from t1 A, t1 B, t1 C; + +set @a="select * from t2 force index (a) where a NOT IN(0"; +select count(*) from (select @a:=concat(@a, ',', a) from t2 ) Z; +set @a=concat(@a, ')'); + +insert into t2 values (11),(13),(15); + +set @b= concat("explain ", @a); + +prepare stmt1 from @b; +execute stmt1; + +prepare stmt1 from @a; +execute stmt1; + +drop table t1, t2; + +# +# Bug #18165: range access for BETWEEN with a constant for the first argument +# + +CREATE TABLE t1 ( + id int NOT NULL DEFAULT '0', + b int NOT NULL DEFAULT '0', + c int NOT NULL DEFAULT '0', + INDEX idx1(b,c), INDEX idx2(c)); + +INSERT INTO t1(id) VALUES (1), (2), (3), (4), (5), (6), (7), (8); + +INSERT INTO t1(b,c) VALUES (3,4), (3,4); + +SELECT * FROM t1 WHERE b<=3 AND 3<=c; +SELECT * FROM t1 WHERE 3 BETWEEN b AND c; + +EXPLAIN SELECT * FROM t1 WHERE b<=3 AND 3<=c; +EXPLAIN SELECT * FROM t1 WHERE 3 BETWEEN b AND c; + +SELECT * FROM t1 WHERE 0 < b OR 0 > c; +SELECT * FROM t1 WHERE 0 NOT BETWEEN b AND c; + +EXPLAIN SELECT * FROM t1 WHERE 0 < b OR 0 > c; +EXPLAIN SELECT * FROM t1 WHERE 0 NOT BETWEEN b AND c; + +DROP TABLE t1; + +# +# Bug #16249: different results for a range with an without index +# when a range condition use an invalid datetime constant +# + +CREATE TABLE t1 ( + item char(20) NOT NULL default '', + started datetime NOT NULL default '0000-00-00 00:00:00', + price decimal(16,3) NOT NULL default '0.000', + PRIMARY KEY (item,started) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES +('A1','2005-11-01 08:00:00',1000), +('A1','2005-11-15 00:00:00',2000), +('A1','2005-12-12 08:00:00',3000), +('A2','2005-12-01 08:00:00',1000); + +EXPLAIN SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-01 24:00:00'; +SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-01 24:00:00'; +SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-02 00:00:00'; + +DROP INDEX `PRIMARY` ON t1; + +EXPLAIN SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-01 24:00:00'; +SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-01 24:00:00'; +SELECT * FROM t1 WHERE item='A1' AND started<='2005-12-02 00:00:00'; + +DROP TABLE t1; + +# End of 5.0 tests + +# BUG#22393 fix: Adjust 'ref' estimate if we have 'range' estimate for +# a smaller scan interval +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t2 (a int, b int, filler char(100)); +insert into t2 select A.a + 10 * (B.a + 10 * C.a), 10, 'filler' from t1 A, +t1 B, t1 C where A.a < 5; + +insert into t2 select 1000, b, 'filler' from t2; +alter table t2 add index (a,b); +# t2 values +# ( 1 , 10, 'filler') +# ( 2 , 10, 'filler') +# ( 3 , 10, 'filler') +# (... , 10, 'filler') +# ... +# (1000, 10, 'filler') - 500 times + +# 500 rows, 1 row + +select 'In following EXPLAIN the access method should be ref, #rows~=500 (and not 2)' Z; +explain select * from t2 where a=1000 and b<11; + +drop table t1, t2; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/read_only.test b/mysql-test/suite/pbxt/t/read_only.test new file mode 100644 index 00000000000..92d9b295cd6 --- /dev/null +++ b/mysql-test/suite/pbxt/t/read_only.test @@ -0,0 +1,231 @@ +# Test of the READ_ONLY global variable: +# check that it blocks updates unless they are only on temporary tables. + +# should work with embedded server after mysqltest is fixed +-- source include/not_embedded.inc + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3; +--enable_warnings + +# READ_ONLY does nothing to SUPER users +# so we use a non-SUPER one: + +grant CREATE, SELECT, DROP on *.* to test@localhost; + +connect (con1,localhost,test,,test); + +connection default; + +set global read_only=0; + +connection con1; + +create table t1 (a int); + +insert into t1 values(1); + +create table t2 select * from t1; + +connection default; + +set global read_only=1; + +# We check that SUPER can: + +create table t3 (a int); +drop table t3; + +connection con1; + +select @@global.read_only; + +--error 1290 +create table t3 (a int); + +--error 1290 +insert into t1 values(1); + +# if a statement, after parse stage, looks like it will update a +# non-temp table, it will be rejected, even if at execution it would +# have turned out that 0 rows would be updated +--error 1290 +update t1 set a=1 where 1=0; + +# multi-update is special (see sql_parse.cc) so we test it +--error 1290 +update t1,t2 set t1.a=t2.a+1 where t1.a=t2.a; + +# check multi-delete to be sure +--error 1290 +delete t1,t2 from t1,t2 where t1.a=t2.a; + +# With temp tables updates should be accepted: + +create temporary table t3 (a int) engine=myisam; # PBXT: Used in multi-table update + +create temporary table t4 (a int) engine=myisam select * from t3; # PBXT: Server complains about read-only + +insert into t3 values(1); + +insert into t4 select * from t3; + +# a non-temp table updated: +--error 1290 +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; + +# no non-temp table updated (just swapped): +update t1,t3 set t3.a=t1.a+1 where t1.a=t3.a; + +update t4,t3 set t4.a=t3.a+1 where t4.a=t3.a; + +--error 1290 +delete t1 from t1,t3 where t1.a=t3.a; + +delete t3 from t1,t3 where t1.a=t3.a; + +delete t4 from t3,t4 where t4.a=t3.a; + +# and even homonymous ones + +create temporary table t1 (a int) engine=myisam; # PBXT: Server complains about read-only + +insert into t1 values(1); + +update t1,t3 set t1.a=t3.a+1 where t1.a=t3.a; + +delete t1 from t1,t3 where t1.a=t3.a; + +drop table t1; + +--error 1290 +insert into t1 values(1); + +# +# BUG#11733: COMMITs should not happen if read-only is set +# + +# LOCK TABLE ... WRITE / READ_ONLY +# - is an error in the same connection +# - is ok in a different connection + +connection default; +set global read_only=0; +lock table t1 write; + +connection con1; +lock table t2 write; + +connection default; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +set global read_only=1; +unlock tables ; +# The following call blocks until con1 releases the write lock. +# Blocking is expected. +send set global read_only=1; + +connection con1; +--sleep 1 +select @@global.read_only; +unlock tables ; +--sleep 1 +select @@global.read_only; + +connection default; +reap; + +# LOCK TABLE ... READ / READ_ONLY +# - is an error in the same connection +# - is ok in a different connection + +connection default; +set global read_only=0; +lock table t1 read; + +connection con1; +lock table t2 read; + +connection default; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +set global read_only=1; +unlock tables ; +# The following call blocks until con1 releases the read lock. +# Blocking is a limitation, and could be improved. +send set global read_only=1; + +connection con1; +--sleep 1 +select @@global.read_only; +unlock tables ; +--sleep 1 +select @@global.read_only; + +connection default; +reap; + +# pending transaction / READ_ONLY +# - is an error in the same connection +# - is ok in a different connection + +connection default; +set global read_only=0; +BEGIN; + +connection con1; +BEGIN; + +connection default; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +set global read_only=1; +ROLLBACK; +set global read_only=1; + +connection con1; +select @@global.read_only; +ROLLBACK; + +# Verify that FLUSH TABLES WITH READ LOCK do not block READ_ONLY +# - in the same SUPER connection +# - in another SUPER connection + +connection default; +set global read_only=0; +flush tables with read lock; +set global read_only=1; +unlock tables; + +connect (root2,localhost,root,,test); + +connection default; +set global read_only=0; +flush tables with read lock; + +connection root2; +set global read_only=1; + +connection default; +select @@global.read_only; +unlock tables; + +# BUG #22077 "DROP TEMPORARY TABLE fails with wrong error if read_only is set" +# +# check if DROP TEMPORARY on a non-existing temporary table returns the right +# error + +--error ER_BAD_TABLE_ERROR +drop temporary table ttt; + +# check if DROP TEMPORARY TABLE IF EXISTS produces a warning with read_only set +drop temporary table if exists ttt; + +# +# Cleanup +# +connection default; +set global read_only=0; +drop table t1,t2; +drop user test@localhost; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/rename.test b/mysql-test/suite/pbxt/t/rename.test new file mode 100644 index 00000000000..1cd02ef8a65 --- /dev/null +++ b/mysql-test/suite/pbxt/t/rename.test @@ -0,0 +1,98 @@ +# +# Test of rename table +# + +--disable_warnings +drop table if exists t0,t1,t2,t3,t4; +# Clear up from other tests (to ensure that SHOW TABLES below is right) +drop table if exists t0,t5,t6,t7,t8,t9,t1_1,t1_2,t9_1,t9_2; +--enable_warnings + +create table t0 SELECT 1,"table 1"; +create table t2 SELECT 2,"table 2"; +create table t3 SELECT 3,"table 3"; +rename table t0 to t1; +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +select * from t1; +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +select * from t1; + +# The following should give errors +--error 1050,1050 +rename table t1 to t2; +--error 1050,1050 +rename table t1 to t1; +--error 1050,1050 +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t2; +show tables like "t_"; +--error 1050,1050 +rename table t3 to t1, t2 to t3, t1 to t2, t4 to t1; +--error 1017,1017 +rename table t3 to t4, t5 to t3, t1 to t2, t4 to t1; + +select * from t1; +select * from t2; +select * from t3; + +# This should give a warning for t4 +drop table if exists t1,t2,t3,t4; + +# +# Bug #2397 RENAME TABLES is not blocked by +# FLUSH TABLES WITH READ LOCK +# + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +connection con1; +CREATE TABLE t1 (a int); +CREATE TABLE t3 (a int); +connection con2; +FLUSH TABLES WITH READ LOCK; +connection con1; +send RENAME TABLE t1 TO t2, t3 to t4; +connection con2; +show tables; +UNLOCK TABLES; +connection con1; +reap; +connection con2; + +# Wait for the the tables to be renamed +# i.e the query below succeds +let $query= select * from t2, t4; +source include/wait_for_query_to_suceed.inc; + +show tables; + +drop table t2, t4; + +disconnect con2; +disconnect con1; +connection default; + + +--echo End of 4.1 tests + + +# +# Bug#14959: ALTER TABLE isn't able to rename a view +# +create table t1(f1 int); +create view v1 as select * from t1; +alter table v1 rename to v2; +--error 1146 +alter table v1 rename to v2; +rename table v2 to v1; +--error 1050 +rename table v2 to v1; +drop view v1; +drop table t1; + + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/renamedb.test b/mysql-test/suite/pbxt/t/renamedb.test new file mode 100644 index 00000000000..84315090b7a --- /dev/null +++ b/mysql-test/suite/pbxt/t/renamedb.test @@ -0,0 +1,53 @@ + +# TODO: enable these tests when RENAME DATABASE is implemented. +# +# --disable_warnings +# drop database if exists testdb1; +# --enable_warnings +# +# create database testdb1 default character set latin2; +# use testdb1; +# create table t1 (a int); +# insert into t1 values (1),(2),(3); +# show create database testdb1; +# show tables; +# rename database testdb1 to testdb2; +# --error 1049 +# show create database testdb1; +# show create database testdb2; +# select database(); +# show tables; +# select a from t1 order by a; +# drop database testdb2; +# +# +# Bug#19392 Rename Database: Crash if case change +# +# create database testdb1; +# --error 1007 +# rename database testdb1 to testdb1; +# drop database testdb1; + +# +# WL#4030 (Deprecate RENAME DATABASE: replace with ALTER DATABASE <name> UPGRADE) +# + +--error ER_PARSE_ERROR +rename database testdb1 to testdb2; + +--error ER_WRONG_USAGE +ALTER DATABASE wrong UPGRADE DATA DIRECTORY NAME; + +--error ER_WRONG_USAGE +ALTER DATABASE `#mysql41#not-supported` UPGRADE DATA DIRECTORY NAME; + +--error ER_WRONG_USAGE +ALTER DATABASE `#mysql51#not-yet` UPGRADE DATA DIRECTORY NAME; + +--error ER_WRONG_USAGE +ALTER DATABASE `#mysql50#` UPGRADE DATA DIRECTORY NAME; + +--error ER_BAD_DB_ERROR +ALTER DATABASE `#mysql50#upgrade-me` UPGRADE DATA DIRECTORY NAME; + + diff --git a/mysql-test/suite/pbxt/t/replace.test b/mysql-test/suite/pbxt/t/replace.test new file mode 100644 index 00000000000..7b2a409b16f --- /dev/null +++ b/mysql-test/suite/pbxt/t/replace.test @@ -0,0 +1,51 @@ +# +# Test of REPLACE with MyISAM and HEAP +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE t1 ( + gesuchnr int(11) DEFAULT '0' NOT NULL, + benutzer_id int(11) DEFAULT '0' NOT NULL, + PRIMARY KEY (gesuchnr,benutzer_id) +); + +replace into t1 (gesuchnr,benutzer_id) values (2,1); +replace into t1 (gesuchnr,benutzer_id) values (1,1); +replace into t1 (gesuchnr,benutzer_id) values (1,1); +alter table t1 engine=heap; +replace into t1 (gesuchnr,benutzer_id) values (1,1); +drop table t1; + +# +# Test when using replace on a key that has used up it's whole range +# + +create table t1 (a tinyint not null auto_increment primary key, b char(20) default "default_value"); +insert into t1 values (126,"first"),(63, "middle"),(0,"last"); +--error 1467 +insert into t1 values (0,"error"); +--error 1467 +replace into t1 values (0,"error"); +replace into t1 values (126,"first updated"); +replace into t1 values (63,default); +select * from t1 order by a; # PBXT requires order +drop table t1; + +# End of 4.1 tests + +# +# Bug#19789: REPLACE was allowed for a VIEW with CHECK OPTION enabled. +# +CREATE TABLE t1 (f1 INT); +CREATE VIEW v1 AS SELECT f1 FROM t1 WHERE f1 = 0 WITH CHECK OPTION; +--error 1369 +REPLACE INTO v1 (f1) VALUES (1); +DROP TABLE t1; +DROP VIEW v1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/rollback.test b/mysql-test/suite/pbxt/t/rollback.test new file mode 100644 index 00000000000..3b8ad901907 --- /dev/null +++ b/mysql-test/suite/pbxt/t/rollback.test @@ -0,0 +1,25 @@ +# +# This test should fail as MyISAM doesn't have rollback +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +# PS doesn't work with BEGIN ... ROLLBACK +--disable_ps_protocol + +create table t1 (n int not null primary key) engine=myisam; +begin work; +insert into t1 values (4); +insert into t1 values (5); +rollback; +select @@warning_count; +select @@error_count; +show warnings; +show errors; +select * from t1; +select @@warning_count; +show warnings; +drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/schema.test b/mysql-test/suite/pbxt/t/schema.test new file mode 100644 index 00000000000..a08d9b38935 --- /dev/null +++ b/mysql-test/suite/pbxt/t/schema.test @@ -0,0 +1,14 @@ +# +# Just a couple of tests to make sure that schema works. +# +# Drop mysqltest1 database, as it can left from the previous tests. +# + +--disable_warnings +drop database if exists mysqltest1; +--enable_warnings + +create schema foo; +show create schema foo; +show schemas; +drop schema foo; diff --git a/mysql-test/suite/pbxt/t/select.test b/mysql-test/suite/pbxt/t/select.test new file mode 100644 index 00000000000..6b2781e6a5b --- /dev/null +++ b/mysql-test/suite/pbxt/t/select.test @@ -0,0 +1,3133 @@ +# +# Find string "NOTE NOTE NOTE" in order to find some 'unsure' tests +# + +# +# Simple select test +# + +--disable_warnings +drop table if exists t1,t2,t3,t4,t11; +# The following may be left from older tests +drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa; +drop view if exists v1; +--enable_warnings + +CREATE TABLE t1 ( + Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, + Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL +); + +INSERT INTO t1 VALUES (9410,9412); + +select period from t1; +select * from t1; +select t1.* from t1; + +# +# Create test table +# + +CREATE TABLE t2 ( + auto int not null auto_increment, + fld1 int(6) unsigned zerofill DEFAULT '000000' NOT NULL, + companynr tinyint(2) unsigned zerofill DEFAULT '00' NOT NULL, + fld3 char(30) DEFAULT '' NOT NULL, + fld4 char(35) DEFAULT '' NOT NULL, + fld5 char(35) DEFAULT '' NOT NULL, + fld6 char(4) DEFAULT '' NOT NULL, + UNIQUE fld1 (fld1), + KEY fld3 (fld3), + PRIMARY KEY (auto) +); + +# +# Populate table +# + +--disable_query_log +INSERT INTO t2 VALUES (1,000001,00,'Omaha','teethe','neat',''); +INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); +INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); +INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); +INSERT INTO t2 VALUES (5,011501,37,'bewilderingly','wallet','balled',''); +INSERT INTO t2 VALUES (6,011701,37,'astound','parters','persist','W'); +INSERT INTO t2 VALUES (7,011702,37,'admonishing','eschew','attainments',''); +INSERT INTO t2 VALUES (8,011703,37,'sumac','quitter','fanatic',''); +INSERT INTO t2 VALUES (9,012001,37,'flanking','neat','measures','FAS'); +INSERT INTO t2 VALUES (10,012003,37,'combed','Steinberg','rightfulness',''); +INSERT INTO t2 VALUES (11,012004,37,'subjective','jarring','capably',''); +INSERT INTO t2 VALUES (12,012005,37,'scatterbrain','tinily','impulsive',''); +INSERT INTO t2 VALUES (13,012301,37,'Eulerian','balled','starlet',''); +INSERT INTO t2 VALUES (14,012302,36,'dubbed','persist','terminators',''); +INSERT INTO t2 VALUES (15,012303,37,'Kane','attainments','untying',''); +INSERT INTO t2 VALUES (16,012304,37,'overlay','fanatic','announces','FAS'); +INSERT INTO t2 VALUES (17,012305,37,'perturb','measures','featherweight','FAS'); +INSERT INTO t2 VALUES (18,012306,37,'goblins','rightfulness','pessimist','FAS'); +INSERT INTO t2 VALUES (19,012501,37,'annihilates','capably','daughter',''); +INSERT INTO t2 VALUES (20,012602,37,'Wotan','impulsive','decliner','FAS'); +INSERT INTO t2 VALUES (21,012603,37,'snatching','starlet','lawgiver',''); +INSERT INTO t2 VALUES (22,012604,37,'concludes','terminators','stated',''); +INSERT INTO t2 VALUES (23,012605,37,'laterally','untying','readable',''); +INSERT INTO t2 VALUES (24,012606,37,'yelped','announces','attrition',''); +INSERT INTO t2 VALUES (25,012701,37,'grazing','featherweight','cascade','FAS'); +INSERT INTO t2 VALUES (26,012702,37,'Baird','pessimist','motors','FAS'); +INSERT INTO t2 VALUES (27,012703,37,'celery','daughter','interrogate',''); +INSERT INTO t2 VALUES (28,012704,37,'misunderstander','decliner','pests','W'); +INSERT INTO t2 VALUES (29,013601,37,'handgun','lawgiver','stairway',''); +INSERT INTO t2 VALUES (30,013602,37,'foldout','stated','dopers','FAS'); +INSERT INTO t2 VALUES (31,013603,37,'mystic','readable','testicle','W'); +INSERT INTO t2 VALUES (32,013604,37,'succumbed','attrition','Parsifal','W'); +INSERT INTO t2 VALUES (33,013605,37,'Nabisco','cascade','leavings',''); +INSERT INTO t2 VALUES (34,013606,37,'fingerings','motors','postulation','W'); +INSERT INTO t2 VALUES (35,013607,37,'aging','interrogate','squeaking',''); +INSERT INTO t2 VALUES (36,013608,37,'afield','pests','contrasted',''); +INSERT INTO t2 VALUES (37,013609,37,'ammonium','stairway','leftover',''); +INSERT INTO t2 VALUES (38,013610,37,'boat','dopers','whiteners',''); +INSERT INTO t2 VALUES (39,013801,37,'intelligibility','testicle','erases','W'); +INSERT INTO t2 VALUES (40,013802,37,'Augustine','Parsifal','Punjab','W'); +INSERT INTO t2 VALUES (41,013803,37,'teethe','leavings','Merritt',''); +INSERT INTO t2 VALUES (42,013804,37,'dreaded','postulation','Quixotism',''); +INSERT INTO t2 VALUES (43,013901,37,'scholastics','squeaking','sweetish','FAS'); +INSERT INTO t2 VALUES (44,016001,37,'audiology','contrasted','dogging','FAS'); +INSERT INTO t2 VALUES (45,016201,37,'wallet','leftover','scornfully','FAS'); +INSERT INTO t2 VALUES (46,016202,37,'parters','whiteners','bellow',''); +INSERT INTO t2 VALUES (47,016301,37,'eschew','erases','bills',''); +INSERT INTO t2 VALUES (48,016302,37,'quitter','Punjab','cupboard','FAS'); +INSERT INTO t2 VALUES (49,016303,37,'neat','Merritt','sureties','FAS'); +INSERT INTO t2 VALUES (50,016304,37,'Steinberg','Quixotism','puddings',''); +INSERT INTO t2 VALUES (51,018001,37,'jarring','sweetish','tapestry',''); +INSERT INTO t2 VALUES (52,018002,37,'tinily','dogging','fetters',''); +INSERT INTO t2 VALUES (53,018003,37,'balled','scornfully','bivalves',''); +INSERT INTO t2 VALUES (54,018004,37,'persist','bellow','incurring',''); +INSERT INTO t2 VALUES (55,018005,37,'attainments','bills','Adolph',''); +INSERT INTO t2 VALUES (56,018007,37,'fanatic','cupboard','pithed',''); +INSERT INTO t2 VALUES (57,018008,37,'measures','sureties','emergency',''); +INSERT INTO t2 VALUES (58,018009,37,'rightfulness','puddings','Miles',''); +INSERT INTO t2 VALUES (59,018010,37,'capably','tapestry','trimmings',''); +INSERT INTO t2 VALUES (60,018012,37,'impulsive','fetters','tragedies','W'); +INSERT INTO t2 VALUES (61,018013,37,'starlet','bivalves','skulking','W'); +INSERT INTO t2 VALUES (62,018014,37,'terminators','incurring','flint',''); +INSERT INTO t2 VALUES (63,018015,37,'untying','Adolph','flopping','W'); +INSERT INTO t2 VALUES (64,018016,37,'announces','pithed','relaxing','FAS'); +INSERT INTO t2 VALUES (65,018017,37,'featherweight','emergency','offload','FAS'); +INSERT INTO t2 VALUES (66,018018,37,'pessimist','Miles','suites','W'); +INSERT INTO t2 VALUES (67,018019,37,'daughter','trimmings','lists','FAS'); +INSERT INTO t2 VALUES (68,018020,37,'decliner','tragedies','animized','FAS'); +INSERT INTO t2 VALUES (69,018021,37,'lawgiver','skulking','multilayer','W'); +INSERT INTO t2 VALUES (70,018022,37,'stated','flint','standardizes','FAS'); +INSERT INTO t2 VALUES (71,018023,37,'readable','flopping','Judas',''); +INSERT INTO t2 VALUES (72,018024,37,'attrition','relaxing','vacuuming','W'); +INSERT INTO t2 VALUES (73,018025,37,'cascade','offload','dentally','W'); +INSERT INTO t2 VALUES (74,018026,37,'motors','suites','humanness','W'); +INSERT INTO t2 VALUES (75,018027,37,'interrogate','lists','inch','W'); +INSERT INTO t2 VALUES (76,018028,37,'pests','animized','Weissmuller','W'); +INSERT INTO t2 VALUES (77,018029,37,'stairway','multilayer','irresponsibly','W'); +INSERT INTO t2 VALUES (78,018030,37,'dopers','standardizes','luckily','FAS'); +INSERT INTO t2 VALUES (79,018032,37,'testicle','Judas','culled','W'); +INSERT INTO t2 VALUES (80,018033,37,'Parsifal','vacuuming','medical','FAS'); +INSERT INTO t2 VALUES (81,018034,37,'leavings','dentally','bloodbath','FAS'); +INSERT INTO t2 VALUES (82,018035,37,'postulation','humanness','subschema','W'); +INSERT INTO t2 VALUES (83,018036,37,'squeaking','inch','animals','W'); +INSERT INTO t2 VALUES (84,018037,37,'contrasted','Weissmuller','Micronesia',''); +INSERT INTO t2 VALUES (85,018038,37,'leftover','irresponsibly','repetitions',''); +INSERT INTO t2 VALUES (86,018039,37,'whiteners','luckily','Antares',''); +INSERT INTO t2 VALUES (87,018040,37,'erases','culled','ventilate','W'); +INSERT INTO t2 VALUES (88,018041,37,'Punjab','medical','pityingly',''); +INSERT INTO t2 VALUES (89,018042,37,'Merritt','bloodbath','interdependent',''); +INSERT INTO t2 VALUES (90,018043,37,'Quixotism','subschema','Graves','FAS'); +INSERT INTO t2 VALUES (91,018044,37,'sweetish','animals','neonatal',''); +INSERT INTO t2 VALUES (92,018045,37,'dogging','Micronesia','scribbled','FAS'); +INSERT INTO t2 VALUES (93,018046,37,'scornfully','repetitions','chafe','W'); +INSERT INTO t2 VALUES (94,018048,37,'bellow','Antares','honoring',''); +INSERT INTO t2 VALUES (95,018049,37,'bills','ventilate','realtor',''); +INSERT INTO t2 VALUES (96,018050,37,'cupboard','pityingly','elite',''); +INSERT INTO t2 VALUES (97,018051,37,'sureties','interdependent','funereal',''); +INSERT INTO t2 VALUES (98,018052,37,'puddings','Graves','abrogating',''); +INSERT INTO t2 VALUES (99,018053,50,'tapestry','neonatal','sorters',''); +INSERT INTO t2 VALUES (100,018054,37,'fetters','scribbled','Conley',''); +INSERT INTO t2 VALUES (101,018055,37,'bivalves','chafe','lectured',''); +INSERT INTO t2 VALUES (102,018056,37,'incurring','honoring','Abraham',''); +INSERT INTO t2 VALUES (103,018057,37,'Adolph','realtor','Hawaii','W'); +INSERT INTO t2 VALUES (104,018058,37,'pithed','elite','cage',''); +INSERT INTO t2 VALUES (105,018059,36,'emergency','funereal','hushes',''); +INSERT INTO t2 VALUES (106,018060,37,'Miles','abrogating','Simla',''); +INSERT INTO t2 VALUES (107,018061,37,'trimmings','sorters','reporters',''); +INSERT INTO t2 VALUES (108,018101,37,'tragedies','Conley','Dutchman','FAS'); +INSERT INTO t2 VALUES (109,018102,37,'skulking','lectured','descendants','FAS'); +INSERT INTO t2 VALUES (110,018103,37,'flint','Abraham','groupings','FAS'); +INSERT INTO t2 VALUES (111,018104,37,'flopping','Hawaii','dissociate',''); +INSERT INTO t2 VALUES (112,018201,37,'relaxing','cage','coexist','W'); +INSERT INTO t2 VALUES (113,018202,37,'offload','hushes','Beebe',''); +INSERT INTO t2 VALUES (114,018402,37,'suites','Simla','Taoism',''); +INSERT INTO t2 VALUES (115,018403,37,'lists','reporters','Connally',''); +INSERT INTO t2 VALUES (116,018404,37,'animized','Dutchman','fetched','FAS'); +INSERT INTO t2 VALUES (117,018405,37,'multilayer','descendants','checkpoints','FAS'); +INSERT INTO t2 VALUES (118,018406,37,'standardizes','groupings','rusting',''); +INSERT INTO t2 VALUES (119,018409,37,'Judas','dissociate','galling',''); +INSERT INTO t2 VALUES (120,018601,37,'vacuuming','coexist','obliterates',''); +INSERT INTO t2 VALUES (121,018602,37,'dentally','Beebe','traitor',''); +INSERT INTO t2 VALUES (122,018603,37,'humanness','Taoism','resumes','FAS'); +INSERT INTO t2 VALUES (123,018801,37,'inch','Connally','analyzable','FAS'); +INSERT INTO t2 VALUES (124,018802,37,'Weissmuller','fetched','terminator','FAS'); +INSERT INTO t2 VALUES (125,018803,37,'irresponsibly','checkpoints','gritty','FAS'); +INSERT INTO t2 VALUES (126,018804,37,'luckily','rusting','firearm','W'); +INSERT INTO t2 VALUES (127,018805,37,'culled','galling','minima',''); +INSERT INTO t2 VALUES (128,018806,37,'medical','obliterates','Selfridge',''); +INSERT INTO t2 VALUES (129,018807,37,'bloodbath','traitor','disable',''); +INSERT INTO t2 VALUES (130,018808,37,'subschema','resumes','witchcraft','W'); +INSERT INTO t2 VALUES (131,018809,37,'animals','analyzable','betroth','W'); +INSERT INTO t2 VALUES (132,018810,37,'Micronesia','terminator','Manhattanize',''); +INSERT INTO t2 VALUES (133,018811,37,'repetitions','gritty','imprint',''); +INSERT INTO t2 VALUES (134,018812,37,'Antares','firearm','peeked',''); +INSERT INTO t2 VALUES (135,019101,37,'ventilate','minima','swelling',''); +INSERT INTO t2 VALUES (136,019102,37,'pityingly','Selfridge','interrelationships','W'); +INSERT INTO t2 VALUES (137,019103,37,'interdependent','disable','riser',''); +INSERT INTO t2 VALUES (138,019201,37,'Graves','witchcraft','Gandhian','W'); +INSERT INTO t2 VALUES (139,030501,37,'neonatal','betroth','peacock','A'); +INSERT INTO t2 VALUES (140,030502,50,'scribbled','Manhattanize','bee','A'); +INSERT INTO t2 VALUES (141,030503,37,'chafe','imprint','kanji',''); +INSERT INTO t2 VALUES (142,030504,37,'honoring','peeked','dental',''); +INSERT INTO t2 VALUES (143,031901,37,'realtor','swelling','scarf','FAS'); +INSERT INTO t2 VALUES (144,036001,37,'elite','interrelationships','chasm','A'); +INSERT INTO t2 VALUES (145,036002,37,'funereal','riser','insolence','A'); +INSERT INTO t2 VALUES (146,036004,37,'abrogating','Gandhian','syndicate',''); +INSERT INTO t2 VALUES (147,036005,37,'sorters','peacock','alike',''); +INSERT INTO t2 VALUES (148,038001,37,'Conley','bee','imperial','A'); +INSERT INTO t2 VALUES (149,038002,37,'lectured','kanji','convulsion','A'); +INSERT INTO t2 VALUES (150,038003,37,'Abraham','dental','railway','A'); +INSERT INTO t2 VALUES (151,038004,37,'Hawaii','scarf','validate','A'); +INSERT INTO t2 VALUES (152,038005,37,'cage','chasm','normalizes','A'); +INSERT INTO t2 VALUES (153,038006,37,'hushes','insolence','comprehensive',''); +INSERT INTO t2 VALUES (154,038007,37,'Simla','syndicate','chewing',''); +INSERT INTO t2 VALUES (155,038008,37,'reporters','alike','denizen',''); +INSERT INTO t2 VALUES (156,038009,37,'Dutchman','imperial','schemer',''); +INSERT INTO t2 VALUES (157,038010,37,'descendants','convulsion','chronicle',''); +INSERT INTO t2 VALUES (158,038011,37,'groupings','railway','Kline',''); +INSERT INTO t2 VALUES (159,038012,37,'dissociate','validate','Anatole',''); +INSERT INTO t2 VALUES (160,038013,37,'coexist','normalizes','partridges',''); +INSERT INTO t2 VALUES (161,038014,37,'Beebe','comprehensive','brunch',''); +INSERT INTO t2 VALUES (162,038015,37,'Taoism','chewing','recruited',''); +INSERT INTO t2 VALUES (163,038016,37,'Connally','denizen','dimensions','W'); +INSERT INTO t2 VALUES (164,038017,37,'fetched','schemer','Chicana','W'); +INSERT INTO t2 VALUES (165,038018,37,'checkpoints','chronicle','announced',''); +INSERT INTO t2 VALUES (166,038101,37,'rusting','Kline','praised','FAS'); +INSERT INTO t2 VALUES (167,038102,37,'galling','Anatole','employing',''); +INSERT INTO t2 VALUES (168,038103,37,'obliterates','partridges','linear',''); +INSERT INTO t2 VALUES (169,038104,37,'traitor','brunch','quagmire',''); +INSERT INTO t2 VALUES (170,038201,37,'resumes','recruited','western','A'); +INSERT INTO t2 VALUES (171,038202,37,'analyzable','dimensions','relishing',''); +INSERT INTO t2 VALUES (172,038203,37,'terminator','Chicana','serving','A'); +INSERT INTO t2 VALUES (173,038204,37,'gritty','announced','scheduling',''); +INSERT INTO t2 VALUES (174,038205,37,'firearm','praised','lore',''); +INSERT INTO t2 VALUES (175,038206,37,'minima','employing','eventful',''); +INSERT INTO t2 VALUES (176,038208,37,'Selfridge','linear','arteriole','A'); +INSERT INTO t2 VALUES (177,042801,37,'disable','quagmire','disentangle',''); +INSERT INTO t2 VALUES (178,042802,37,'witchcraft','western','cured','A'); +INSERT INTO t2 VALUES (179,046101,37,'betroth','relishing','Fenton','W'); +INSERT INTO t2 VALUES (180,048001,37,'Manhattanize','serving','avoidable','A'); +INSERT INTO t2 VALUES (181,048002,37,'imprint','scheduling','drains','A'); +INSERT INTO t2 VALUES (182,048003,37,'peeked','lore','detectably','FAS'); +INSERT INTO t2 VALUES (183,048004,37,'swelling','eventful','husky',''); +INSERT INTO t2 VALUES (184,048005,37,'interrelationships','arteriole','impelling',''); +INSERT INTO t2 VALUES (185,048006,37,'riser','disentangle','undoes',''); +INSERT INTO t2 VALUES (186,048007,37,'Gandhian','cured','evened',''); +INSERT INTO t2 VALUES (187,048008,37,'peacock','Fenton','squeezes',''); +INSERT INTO t2 VALUES (188,048101,37,'bee','avoidable','destroyer','FAS'); +INSERT INTO t2 VALUES (189,048102,37,'kanji','drains','rudeness',''); +INSERT INTO t2 VALUES (190,048201,37,'dental','detectably','beaner','FAS'); +INSERT INTO t2 VALUES (191,048202,37,'scarf','husky','boorish',''); +INSERT INTO t2 VALUES (192,048203,37,'chasm','impelling','Everhart',''); +INSERT INTO t2 VALUES (193,048204,37,'insolence','undoes','encompass','A'); +INSERT INTO t2 VALUES (194,048205,37,'syndicate','evened','mushrooms',''); +INSERT INTO t2 VALUES (195,048301,37,'alike','squeezes','Alison','A'); +INSERT INTO t2 VALUES (196,048302,37,'imperial','destroyer','externally','FAS'); +INSERT INTO t2 VALUES (197,048303,37,'convulsion','rudeness','pellagra',''); +INSERT INTO t2 VALUES (198,048304,37,'railway','beaner','cult',''); +INSERT INTO t2 VALUES (199,048305,37,'validate','boorish','creek','A'); +INSERT INTO t2 VALUES (200,048401,37,'normalizes','Everhart','Huffman',''); +INSERT INTO t2 VALUES (201,048402,37,'comprehensive','encompass','Majorca','FAS'); +INSERT INTO t2 VALUES (202,048403,37,'chewing','mushrooms','governing','A'); +INSERT INTO t2 VALUES (203,048404,37,'denizen','Alison','gadfly','FAS'); +INSERT INTO t2 VALUES (204,048405,37,'schemer','externally','reassigned','FAS'); +INSERT INTO t2 VALUES (205,048406,37,'chronicle','pellagra','intentness','W'); +INSERT INTO t2 VALUES (206,048407,37,'Kline','cult','craziness',''); +INSERT INTO t2 VALUES (207,048408,37,'Anatole','creek','psychic',''); +INSERT INTO t2 VALUES (208,048409,37,'partridges','Huffman','squabbled',''); +INSERT INTO t2 VALUES (209,048410,37,'brunch','Majorca','burlesque',''); +INSERT INTO t2 VALUES (210,048411,37,'recruited','governing','capped',''); +INSERT INTO t2 VALUES (211,048412,37,'dimensions','gadfly','extracted','A'); +INSERT INTO t2 VALUES (212,048413,37,'Chicana','reassigned','DiMaggio',''); +INSERT INTO t2 VALUES (213,048601,37,'announced','intentness','exclamation','FAS'); +INSERT INTO t2 VALUES (214,048602,37,'praised','craziness','subdirectory',''); +INSERT INTO t2 VALUES (215,048603,37,'employing','psychic','fangs',''); +INSERT INTO t2 VALUES (216,048604,37,'linear','squabbled','buyer','A'); +INSERT INTO t2 VALUES (217,048801,37,'quagmire','burlesque','pithing','A'); +INSERT INTO t2 VALUES (218,050901,37,'western','capped','transistorizing','A'); +INSERT INTO t2 VALUES (219,051201,37,'relishing','extracted','nonbiodegradable',''); +INSERT INTO t2 VALUES (220,056002,37,'serving','DiMaggio','dislocate',''); +INSERT INTO t2 VALUES (221,056003,37,'scheduling','exclamation','monochromatic','FAS'); +INSERT INTO t2 VALUES (222,056004,37,'lore','subdirectory','batting',''); +INSERT INTO t2 VALUES (223,056102,37,'eventful','fangs','postcondition','A'); +INSERT INTO t2 VALUES (224,056203,37,'arteriole','buyer','catalog','FAS'); +INSERT INTO t2 VALUES (225,056204,37,'disentangle','pithing','Remus',''); +INSERT INTO t2 VALUES (226,058003,37,'cured','transistorizing','devices','A'); +INSERT INTO t2 VALUES (227,058004,37,'Fenton','nonbiodegradable','bike','A'); +INSERT INTO t2 VALUES (228,058005,37,'avoidable','dislocate','qualify',''); +INSERT INTO t2 VALUES (229,058006,37,'drains','monochromatic','detained',''); +INSERT INTO t2 VALUES (230,058007,37,'detectably','batting','commended',''); +INSERT INTO t2 VALUES (231,058101,37,'husky','postcondition','civilize',''); +INSERT INTO t2 VALUES (232,058102,37,'impelling','catalog','Elmhurst',''); +INSERT INTO t2 VALUES (233,058103,37,'undoes','Remus','anesthetizing',''); +INSERT INTO t2 VALUES (234,058105,37,'evened','devices','deaf',''); +INSERT INTO t2 VALUES (235,058111,37,'squeezes','bike','Brigham',''); +INSERT INTO t2 VALUES (236,058112,37,'destroyer','qualify','title',''); +INSERT INTO t2 VALUES (237,058113,37,'rudeness','detained','coarse',''); +INSERT INTO t2 VALUES (238,058114,37,'beaner','commended','combinations',''); +INSERT INTO t2 VALUES (239,058115,37,'boorish','civilize','grayness',''); +INSERT INTO t2 VALUES (240,058116,37,'Everhart','Elmhurst','innumerable','FAS'); +INSERT INTO t2 VALUES (241,058117,37,'encompass','anesthetizing','Caroline','A'); +INSERT INTO t2 VALUES (242,058118,37,'mushrooms','deaf','fatty','FAS'); +INSERT INTO t2 VALUES (243,058119,37,'Alison','Brigham','eastbound',''); +INSERT INTO t2 VALUES (244,058120,37,'externally','title','inexperienced',''); +INSERT INTO t2 VALUES (245,058121,37,'pellagra','coarse','hoarder','A'); +INSERT INTO t2 VALUES (246,058122,37,'cult','combinations','scotch','W'); +INSERT INTO t2 VALUES (247,058123,37,'creek','grayness','passport','A'); +INSERT INTO t2 VALUES (248,058124,37,'Huffman','innumerable','strategic','FAS'); +INSERT INTO t2 VALUES (249,058125,37,'Majorca','Caroline','gated',''); +INSERT INTO t2 VALUES (250,058126,37,'governing','fatty','flog',''); +INSERT INTO t2 VALUES (251,058127,37,'gadfly','eastbound','Pipestone',''); +INSERT INTO t2 VALUES (252,058128,37,'reassigned','inexperienced','Dar',''); +INSERT INTO t2 VALUES (253,058201,37,'intentness','hoarder','Corcoran',''); +INSERT INTO t2 VALUES (254,058202,37,'craziness','scotch','flyers','A'); +INSERT INTO t2 VALUES (255,058303,37,'psychic','passport','competitions','W'); +INSERT INTO t2 VALUES (256,058304,37,'squabbled','strategic','suppliers','FAS'); +INSERT INTO t2 VALUES (257,058602,37,'burlesque','gated','skips',''); +INSERT INTO t2 VALUES (258,058603,37,'capped','flog','institutes',''); +INSERT INTO t2 VALUES (259,058604,37,'extracted','Pipestone','troop','A'); +INSERT INTO t2 VALUES (260,058605,37,'DiMaggio','Dar','connective','W'); +INSERT INTO t2 VALUES (261,058606,37,'exclamation','Corcoran','denies',''); +INSERT INTO t2 VALUES (262,058607,37,'subdirectory','flyers','polka',''); +INSERT INTO t2 VALUES (263,060401,36,'fangs','competitions','observations','FAS'); +INSERT INTO t2 VALUES (264,061701,36,'buyer','suppliers','askers',''); +INSERT INTO t2 VALUES (265,066201,36,'pithing','skips','homeless','FAS'); +INSERT INTO t2 VALUES (266,066501,36,'transistorizing','institutes','Anna',''); +INSERT INTO t2 VALUES (267,068001,36,'nonbiodegradable','troop','subdirectories','W'); +INSERT INTO t2 VALUES (268,068002,36,'dislocate','connective','decaying','FAS'); +INSERT INTO t2 VALUES (269,068005,36,'monochromatic','denies','outwitting','W'); +INSERT INTO t2 VALUES (270,068006,36,'batting','polka','Harpy','W'); +INSERT INTO t2 VALUES (271,068007,36,'postcondition','observations','crazed',''); +INSERT INTO t2 VALUES (272,068008,36,'catalog','askers','suffocate',''); +INSERT INTO t2 VALUES (273,068009,36,'Remus','homeless','provers','FAS'); +INSERT INTO t2 VALUES (274,068010,36,'devices','Anna','technically',''); +INSERT INTO t2 VALUES (275,068011,36,'bike','subdirectories','Franklinizations',''); +INSERT INTO t2 VALUES (276,068202,36,'qualify','decaying','considered',''); +INSERT INTO t2 VALUES (277,068302,36,'detained','outwitting','tinnily',''); +INSERT INTO t2 VALUES (278,068303,36,'commended','Harpy','uninterruptedly',''); +INSERT INTO t2 VALUES (279,068401,36,'civilize','crazed','whistled','A'); +INSERT INTO t2 VALUES (280,068501,36,'Elmhurst','suffocate','automate',''); +INSERT INTO t2 VALUES (281,068502,36,'anesthetizing','provers','gutting','W'); +INSERT INTO t2 VALUES (282,068503,36,'deaf','technically','surreptitious',''); +INSERT INTO t2 VALUES (283,068602,36,'Brigham','Franklinizations','Choctaw',''); +INSERT INTO t2 VALUES (284,068603,36,'title','considered','cooks',''); +INSERT INTO t2 VALUES (285,068701,36,'coarse','tinnily','millivolt','FAS'); +INSERT INTO t2 VALUES (286,068702,36,'combinations','uninterruptedly','counterpoise',''); +INSERT INTO t2 VALUES (287,068703,36,'grayness','whistled','Gothicism',''); +INSERT INTO t2 VALUES (288,076001,36,'innumerable','automate','feminine',''); +INSERT INTO t2 VALUES (289,076002,36,'Caroline','gutting','metaphysically','W'); +INSERT INTO t2 VALUES (290,076101,36,'fatty','surreptitious','sanding','A'); +INSERT INTO t2 VALUES (291,076102,36,'eastbound','Choctaw','contributorily',''); +INSERT INTO t2 VALUES (292,076103,36,'inexperienced','cooks','receivers','FAS'); +INSERT INTO t2 VALUES (293,076302,36,'hoarder','millivolt','adjourn',''); +INSERT INTO t2 VALUES (294,076303,36,'scotch','counterpoise','straggled','A'); +INSERT INTO t2 VALUES (295,076304,36,'passport','Gothicism','druggists',''); +INSERT INTO t2 VALUES (296,076305,36,'strategic','feminine','thanking','FAS'); +INSERT INTO t2 VALUES (297,076306,36,'gated','metaphysically','ostrich',''); +INSERT INTO t2 VALUES (298,076307,36,'flog','sanding','hopelessness','FAS'); +INSERT INTO t2 VALUES (299,076402,36,'Pipestone','contributorily','Eurydice',''); +INSERT INTO t2 VALUES (300,076501,36,'Dar','receivers','excitation','W'); +INSERT INTO t2 VALUES (301,076502,36,'Corcoran','adjourn','presumes','FAS'); +INSERT INTO t2 VALUES (302,076701,36,'flyers','straggled','imaginable','FAS'); +INSERT INTO t2 VALUES (303,078001,36,'competitions','druggists','concoct','W'); +INSERT INTO t2 VALUES (304,078002,36,'suppliers','thanking','peering','W'); +INSERT INTO t2 VALUES (305,078003,36,'skips','ostrich','Phelps','FAS'); +INSERT INTO t2 VALUES (306,078004,36,'institutes','hopelessness','ferociousness','FAS'); +INSERT INTO t2 VALUES (307,078005,36,'troop','Eurydice','sentences',''); +INSERT INTO t2 VALUES (308,078006,36,'connective','excitation','unlocks',''); +INSERT INTO t2 VALUES (309,078007,36,'denies','presumes','engrossing','W'); +INSERT INTO t2 VALUES (310,078008,36,'polka','imaginable','Ruth',''); +INSERT INTO t2 VALUES (311,078101,36,'observations','concoct','tying',''); +INSERT INTO t2 VALUES (312,078103,36,'askers','peering','exclaimers',''); +INSERT INTO t2 VALUES (313,078104,36,'homeless','Phelps','synergy',''); +INSERT INTO t2 VALUES (314,078105,36,'Anna','ferociousness','Huey','W'); +INSERT INTO t2 VALUES (315,082101,36,'subdirectories','sentences','merging',''); +INSERT INTO t2 VALUES (316,083401,36,'decaying','unlocks','judges','A'); +INSERT INTO t2 VALUES (317,084001,36,'outwitting','engrossing','Shylock','W'); +INSERT INTO t2 VALUES (318,084002,36,'Harpy','Ruth','Miltonism',''); +INSERT INTO t2 VALUES (319,086001,36,'crazed','tying','hen','W'); +INSERT INTO t2 VALUES (320,086102,36,'suffocate','exclaimers','honeybee','FAS'); +INSERT INTO t2 VALUES (321,086201,36,'provers','synergy','towers',''); +INSERT INTO t2 VALUES (322,088001,36,'technically','Huey','dilutes','W'); +INSERT INTO t2 VALUES (323,088002,36,'Franklinizations','merging','numerals','FAS'); +INSERT INTO t2 VALUES (324,088003,36,'considered','judges','democracy','FAS'); +INSERT INTO t2 VALUES (325,088004,36,'tinnily','Shylock','Ibero-',''); +INSERT INTO t2 VALUES (326,088101,36,'uninterruptedly','Miltonism','invalids',''); +INSERT INTO t2 VALUES (327,088102,36,'whistled','hen','behavior',''); +INSERT INTO t2 VALUES (328,088103,36,'automate','honeybee','accruing',''); +INSERT INTO t2 VALUES (329,088104,36,'gutting','towers','relics','A'); +INSERT INTO t2 VALUES (330,088105,36,'surreptitious','dilutes','rackets',''); +INSERT INTO t2 VALUES (331,088106,36,'Choctaw','numerals','Fischbein','W'); +INSERT INTO t2 VALUES (332,088201,36,'cooks','democracy','phony','W'); +INSERT INTO t2 VALUES (333,088203,36,'millivolt','Ibero-','cross','FAS'); +INSERT INTO t2 VALUES (334,088204,36,'counterpoise','invalids','cleanup',''); +INSERT INTO t2 VALUES (335,088302,37,'Gothicism','behavior','conspirator',''); +INSERT INTO t2 VALUES (336,088303,37,'feminine','accruing','label','FAS'); +INSERT INTO t2 VALUES (337,088305,37,'metaphysically','relics','university',''); +INSERT INTO t2 VALUES (338,088402,37,'sanding','rackets','cleansed','FAS'); +INSERT INTO t2 VALUES (339,088501,36,'contributorily','Fischbein','ballgown',''); +INSERT INTO t2 VALUES (340,088502,36,'receivers','phony','starlet',''); +INSERT INTO t2 VALUES (341,088503,36,'adjourn','cross','aqueous',''); +INSERT INTO t2 VALUES (342,098001,58,'straggled','cleanup','portrayal','A'); +INSERT INTO t2 VALUES (343,098002,58,'druggists','conspirator','despising','W'); +INSERT INTO t2 VALUES (344,098003,58,'thanking','label','distort','W'); +INSERT INTO t2 VALUES (345,098004,58,'ostrich','university','palmed',''); +INSERT INTO t2 VALUES (346,098005,58,'hopelessness','cleansed','faced',''); +INSERT INTO t2 VALUES (347,098006,58,'Eurydice','ballgown','silverware',''); +INSERT INTO t2 VALUES (348,141903,29,'excitation','starlet','assessor',''); +INSERT INTO t2 VALUES (349,098008,58,'presumes','aqueous','spiders',''); +INSERT INTO t2 VALUES (350,098009,58,'imaginable','portrayal','artificially',''); +INSERT INTO t2 VALUES (351,098010,58,'concoct','despising','reminiscence',''); +INSERT INTO t2 VALUES (352,098011,58,'peering','distort','Mexican',''); +INSERT INTO t2 VALUES (353,098012,58,'Phelps','palmed','obnoxious',''); +INSERT INTO t2 VALUES (354,098013,58,'ferociousness','faced','fragile',''); +INSERT INTO t2 VALUES (355,098014,58,'sentences','silverware','apprehensible',''); +INSERT INTO t2 VALUES (356,098015,58,'unlocks','assessor','births',''); +INSERT INTO t2 VALUES (357,098016,58,'engrossing','spiders','garages',''); +INSERT INTO t2 VALUES (358,098017,58,'Ruth','artificially','panty',''); +INSERT INTO t2 VALUES (359,098018,58,'tying','reminiscence','anteater',''); +INSERT INTO t2 VALUES (360,098019,58,'exclaimers','Mexican','displacement','A'); +INSERT INTO t2 VALUES (361,098020,58,'synergy','obnoxious','drovers','A'); +INSERT INTO t2 VALUES (362,098021,58,'Huey','fragile','patenting','A'); +INSERT INTO t2 VALUES (363,098022,58,'merging','apprehensible','far','A'); +INSERT INTO t2 VALUES (364,098023,58,'judges','births','shrieks',''); +INSERT INTO t2 VALUES (365,098024,58,'Shylock','garages','aligning','W'); +INSERT INTO t2 VALUES (366,098025,37,'Miltonism','panty','pragmatism',''); +INSERT INTO t2 VALUES (367,106001,36,'hen','anteater','fevers','W'); +INSERT INTO t2 VALUES (368,108001,36,'honeybee','displacement','reexamines','A'); +INSERT INTO t2 VALUES (369,108002,36,'towers','drovers','occupancies',''); +INSERT INTO t2 VALUES (370,108003,36,'dilutes','patenting','sweats','FAS'); +INSERT INTO t2 VALUES (371,108004,36,'numerals','far','modulators',''); +INSERT INTO t2 VALUES (372,108005,36,'democracy','shrieks','demand','W'); +INSERT INTO t2 VALUES (373,108007,36,'Ibero-','aligning','Madeira',''); +INSERT INTO t2 VALUES (374,108008,36,'invalids','pragmatism','Viennese','W'); +INSERT INTO t2 VALUES (375,108009,36,'behavior','fevers','chillier','W'); +INSERT INTO t2 VALUES (376,108010,36,'accruing','reexamines','wildcats','FAS'); +INSERT INTO t2 VALUES (377,108011,36,'relics','occupancies','gentle',''); +INSERT INTO t2 VALUES (378,108012,36,'rackets','sweats','Angles','W'); +INSERT INTO t2 VALUES (379,108101,36,'Fischbein','modulators','accuracies',''); +INSERT INTO t2 VALUES (380,108102,36,'phony','demand','toggle',''); +INSERT INTO t2 VALUES (381,108103,36,'cross','Madeira','Mendelssohn','W'); +INSERT INTO t2 VALUES (382,108111,50,'cleanup','Viennese','behaviorally',''); +INSERT INTO t2 VALUES (383,108105,36,'conspirator','chillier','Rochford',''); +INSERT INTO t2 VALUES (384,108106,36,'label','wildcats','mirror','W'); +INSERT INTO t2 VALUES (385,108107,36,'university','gentle','Modula',''); +INSERT INTO t2 VALUES (386,108108,50,'cleansed','Angles','clobbering',''); +INSERT INTO t2 VALUES (387,108109,36,'ballgown','accuracies','chronography',''); +INSERT INTO t2 VALUES (388,108110,36,'starlet','toggle','Eskimoizeds',''); +INSERT INTO t2 VALUES (389,108201,36,'aqueous','Mendelssohn','British','W'); +INSERT INTO t2 VALUES (390,108202,36,'portrayal','behaviorally','pitfalls',''); +INSERT INTO t2 VALUES (391,108203,36,'despising','Rochford','verify','W'); +INSERT INTO t2 VALUES (392,108204,36,'distort','mirror','scatter','FAS'); +INSERT INTO t2 VALUES (393,108205,36,'palmed','Modula','Aztecan',''); +INSERT INTO t2 VALUES (394,108301,36,'faced','clobbering','acuity','W'); +INSERT INTO t2 VALUES (395,108302,36,'silverware','chronography','sinking','W'); +INSERT INTO t2 VALUES (396,112101,36,'assessor','Eskimoizeds','beasts','FAS'); +INSERT INTO t2 VALUES (397,112102,36,'spiders','British','Witt','W'); +INSERT INTO t2 VALUES (398,113701,36,'artificially','pitfalls','physicists','FAS'); +INSERT INTO t2 VALUES (399,116001,36,'reminiscence','verify','folksong','A'); +INSERT INTO t2 VALUES (400,116201,36,'Mexican','scatter','strokes','FAS'); +INSERT INTO t2 VALUES (401,116301,36,'obnoxious','Aztecan','crowder',''); +INSERT INTO t2 VALUES (402,116302,36,'fragile','acuity','merry',''); +INSERT INTO t2 VALUES (403,116601,36,'apprehensible','sinking','cadenced',''); +INSERT INTO t2 VALUES (404,116602,36,'births','beasts','alimony','A'); +INSERT INTO t2 VALUES (405,116603,36,'garages','Witt','principled','A'); +INSERT INTO t2 VALUES (406,116701,36,'panty','physicists','golfing',''); +INSERT INTO t2 VALUES (407,116702,36,'anteater','folksong','undiscovered',''); +INSERT INTO t2 VALUES (408,118001,36,'displacement','strokes','irritates',''); +INSERT INTO t2 VALUES (409,118002,36,'drovers','crowder','patriots','A'); +INSERT INTO t2 VALUES (410,118003,36,'patenting','merry','rooms','FAS'); +INSERT INTO t2 VALUES (411,118004,36,'far','cadenced','towering','W'); +INSERT INTO t2 VALUES (412,118005,36,'shrieks','alimony','displease',''); +INSERT INTO t2 VALUES (413,118006,36,'aligning','principled','photosensitive',''); +INSERT INTO t2 VALUES (414,118007,36,'pragmatism','golfing','inking',''); +INSERT INTO t2 VALUES (415,118008,36,'fevers','undiscovered','gainers',''); +INSERT INTO t2 VALUES (416,118101,36,'reexamines','irritates','leaning','A'); +INSERT INTO t2 VALUES (417,118102,36,'occupancies','patriots','hydrant','A'); +INSERT INTO t2 VALUES (418,118103,36,'sweats','rooms','preserve',''); +INSERT INTO t2 VALUES (419,118202,36,'modulators','towering','blinded','A'); +INSERT INTO t2 VALUES (420,118203,36,'demand','displease','interactions','A'); +INSERT INTO t2 VALUES (421,118204,36,'Madeira','photosensitive','Barry',''); +INSERT INTO t2 VALUES (422,118302,36,'Viennese','inking','whiteness','A'); +INSERT INTO t2 VALUES (423,118304,36,'chillier','gainers','pastimes','W'); +INSERT INTO t2 VALUES (424,118305,36,'wildcats','leaning','Edenization',''); +INSERT INTO t2 VALUES (425,118306,36,'gentle','hydrant','Muscat',''); +INSERT INTO t2 VALUES (426,118307,36,'Angles','preserve','assassinated',''); +INSERT INTO t2 VALUES (427,123101,36,'accuracies','blinded','labeled',''); +INSERT INTO t2 VALUES (428,123102,36,'toggle','interactions','glacial','A'); +INSERT INTO t2 VALUES (429,123301,36,'Mendelssohn','Barry','implied','W'); +INSERT INTO t2 VALUES (430,126001,36,'behaviorally','whiteness','bibliographies','W'); +INSERT INTO t2 VALUES (431,126002,36,'Rochford','pastimes','Buchanan',''); +INSERT INTO t2 VALUES (432,126003,36,'mirror','Edenization','forgivably','FAS'); +INSERT INTO t2 VALUES (433,126101,36,'Modula','Muscat','innuendo','A'); +INSERT INTO t2 VALUES (434,126301,36,'clobbering','assassinated','den','FAS'); +INSERT INTO t2 VALUES (435,126302,36,'chronography','labeled','submarines','W'); +INSERT INTO t2 VALUES (436,126402,36,'Eskimoizeds','glacial','mouthful','A'); +INSERT INTO t2 VALUES (437,126601,36,'British','implied','expiring',''); +INSERT INTO t2 VALUES (438,126602,36,'pitfalls','bibliographies','unfulfilled','FAS'); +INSERT INTO t2 VALUES (439,126702,36,'verify','Buchanan','precession',''); +INSERT INTO t2 VALUES (440,128001,36,'scatter','forgivably','nullified',''); +INSERT INTO t2 VALUES (441,128002,36,'Aztecan','innuendo','affects',''); +INSERT INTO t2 VALUES (442,128003,36,'acuity','den','Cynthia',''); +INSERT INTO t2 VALUES (443,128004,36,'sinking','submarines','Chablis','A'); +INSERT INTO t2 VALUES (444,128005,36,'beasts','mouthful','betterments','FAS'); +INSERT INTO t2 VALUES (445,128007,36,'Witt','expiring','advertising',''); +INSERT INTO t2 VALUES (446,128008,36,'physicists','unfulfilled','rubies','A'); +INSERT INTO t2 VALUES (447,128009,36,'folksong','precession','southwest','FAS'); +INSERT INTO t2 VALUES (448,128010,36,'strokes','nullified','superstitious','A'); +INSERT INTO t2 VALUES (449,128011,36,'crowder','affects','tabernacle','W'); +INSERT INTO t2 VALUES (450,128012,36,'merry','Cynthia','silk','A'); +INSERT INTO t2 VALUES (451,128013,36,'cadenced','Chablis','handsomest','A'); +INSERT INTO t2 VALUES (452,128014,36,'alimony','betterments','Persian','A'); +INSERT INTO t2 VALUES (453,128015,36,'principled','advertising','analog','W'); +INSERT INTO t2 VALUES (454,128016,36,'golfing','rubies','complex','W'); +INSERT INTO t2 VALUES (455,128017,36,'undiscovered','southwest','Taoist',''); +INSERT INTO t2 VALUES (456,128018,36,'irritates','superstitious','suspend',''); +INSERT INTO t2 VALUES (457,128019,36,'patriots','tabernacle','relegated',''); +INSERT INTO t2 VALUES (458,128020,36,'rooms','silk','awesome','W'); +INSERT INTO t2 VALUES (459,128021,36,'towering','handsomest','Bruxelles',''); +INSERT INTO t2 VALUES (460,128022,36,'displease','Persian','imprecisely','A'); +INSERT INTO t2 VALUES (461,128023,36,'photosensitive','analog','televise',''); +INSERT INTO t2 VALUES (462,128101,36,'inking','complex','braking',''); +INSERT INTO t2 VALUES (463,128102,36,'gainers','Taoist','true','FAS'); +INSERT INTO t2 VALUES (464,128103,36,'leaning','suspend','disappointing','FAS'); +INSERT INTO t2 VALUES (465,128104,36,'hydrant','relegated','navally','W'); +INSERT INTO t2 VALUES (466,128106,36,'preserve','awesome','circus',''); +INSERT INTO t2 VALUES (467,128107,36,'blinded','Bruxelles','beetles',''); +INSERT INTO t2 VALUES (468,128108,36,'interactions','imprecisely','trumps',''); +INSERT INTO t2 VALUES (469,128202,36,'Barry','televise','fourscore','W'); +INSERT INTO t2 VALUES (470,128203,36,'whiteness','braking','Blackfoots',''); +INSERT INTO t2 VALUES (471,128301,36,'pastimes','true','Grady',''); +INSERT INTO t2 VALUES (472,128302,36,'Edenization','disappointing','quiets','FAS'); +INSERT INTO t2 VALUES (473,128303,36,'Muscat','navally','floundered','FAS'); +INSERT INTO t2 VALUES (474,128304,36,'assassinated','circus','profundity','W'); +INSERT INTO t2 VALUES (475,128305,36,'labeled','beetles','Garrisonian','W'); +INSERT INTO t2 VALUES (476,128307,36,'glacial','trumps','Strauss',''); +INSERT INTO t2 VALUES (477,128401,36,'implied','fourscore','cemented','FAS'); +INSERT INTO t2 VALUES (478,128502,36,'bibliographies','Blackfoots','contrition','A'); +INSERT INTO t2 VALUES (479,128503,36,'Buchanan','Grady','mutations',''); +INSERT INTO t2 VALUES (480,128504,36,'forgivably','quiets','exhibits','W'); +INSERT INTO t2 VALUES (481,128505,36,'innuendo','floundered','tits',''); +INSERT INTO t2 VALUES (482,128601,36,'den','profundity','mate','A'); +INSERT INTO t2 VALUES (483,128603,36,'submarines','Garrisonian','arches',''); +INSERT INTO t2 VALUES (484,128604,36,'mouthful','Strauss','Moll',''); +INSERT INTO t2 VALUES (485,128702,36,'expiring','cemented','ropers',''); +INSERT INTO t2 VALUES (486,128703,36,'unfulfilled','contrition','bombast',''); +INSERT INTO t2 VALUES (487,128704,36,'precession','mutations','difficultly','A'); +INSERT INTO t2 VALUES (488,138001,36,'nullified','exhibits','adsorption',''); +INSERT INTO t2 VALUES (489,138002,36,'affects','tits','definiteness','FAS'); +INSERT INTO t2 VALUES (490,138003,36,'Cynthia','mate','cultivation','A'); +INSERT INTO t2 VALUES (491,138004,36,'Chablis','arches','heals','A'); +INSERT INTO t2 VALUES (492,138005,36,'betterments','Moll','Heusen','W'); +INSERT INTO t2 VALUES (493,138006,36,'advertising','ropers','target','FAS'); +INSERT INTO t2 VALUES (494,138007,36,'rubies','bombast','cited','A'); +INSERT INTO t2 VALUES (495,138008,36,'southwest','difficultly','congresswoman','W'); +INSERT INTO t2 VALUES (496,138009,36,'superstitious','adsorption','Katherine',''); +INSERT INTO t2 VALUES (497,138102,36,'tabernacle','definiteness','titter','A'); +INSERT INTO t2 VALUES (498,138103,36,'silk','cultivation','aspire','A'); +INSERT INTO t2 VALUES (499,138104,36,'handsomest','heals','Mardis',''); +INSERT INTO t2 VALUES (500,138105,36,'Persian','Heusen','Nadia','W'); +INSERT INTO t2 VALUES (501,138201,36,'analog','target','estimating','FAS'); +INSERT INTO t2 VALUES (502,138302,36,'complex','cited','stuck','A'); +INSERT INTO t2 VALUES (503,138303,36,'Taoist','congresswoman','fifteenth','A'); +INSERT INTO t2 VALUES (504,138304,36,'suspend','Katherine','Colombo',''); +INSERT INTO t2 VALUES (505,138401,29,'relegated','titter','survey','A'); +INSERT INTO t2 VALUES (506,140102,29,'awesome','aspire','staffing',''); +INSERT INTO t2 VALUES (507,140103,29,'Bruxelles','Mardis','obtain',''); +INSERT INTO t2 VALUES (508,140104,29,'imprecisely','Nadia','loaded',''); +INSERT INTO t2 VALUES (509,140105,29,'televise','estimating','slaughtered',''); +INSERT INTO t2 VALUES (510,140201,29,'braking','stuck','lights','A'); +INSERT INTO t2 VALUES (511,140701,29,'true','fifteenth','circumference',''); +INSERT INTO t2 VALUES (512,141501,29,'disappointing','Colombo','dull','A'); +INSERT INTO t2 VALUES (513,141502,29,'navally','survey','weekly','A'); +INSERT INTO t2 VALUES (514,141901,29,'circus','staffing','wetness',''); +INSERT INTO t2 VALUES (515,141902,29,'beetles','obtain','visualized',''); +INSERT INTO t2 VALUES (516,142101,29,'trumps','loaded','Tannenbaum',''); +INSERT INTO t2 VALUES (517,142102,29,'fourscore','slaughtered','moribund',''); +INSERT INTO t2 VALUES (518,142103,29,'Blackfoots','lights','demultiplex',''); +INSERT INTO t2 VALUES (519,142701,29,'Grady','circumference','lockings',''); +INSERT INTO t2 VALUES (520,143001,29,'quiets','dull','thugs','FAS'); +INSERT INTO t2 VALUES (521,143501,29,'floundered','weekly','unnerves',''); +INSERT INTO t2 VALUES (522,143502,29,'profundity','wetness','abut',''); +INSERT INTO t2 VALUES (523,148001,29,'Garrisonian','visualized','Chippewa','A'); +INSERT INTO t2 VALUES (524,148002,29,'Strauss','Tannenbaum','stratifications','A'); +INSERT INTO t2 VALUES (525,148003,29,'cemented','moribund','signaled',''); +INSERT INTO t2 VALUES (526,148004,29,'contrition','demultiplex','Italianizes','A'); +INSERT INTO t2 VALUES (527,148005,29,'mutations','lockings','algorithmic','A'); +INSERT INTO t2 VALUES (528,148006,29,'exhibits','thugs','paranoid','FAS'); +INSERT INTO t2 VALUES (529,148007,29,'tits','unnerves','camping','A'); +INSERT INTO t2 VALUES (530,148009,29,'mate','abut','signifying','A'); +INSERT INTO t2 VALUES (531,148010,29,'arches','Chippewa','Patrice','W'); +INSERT INTO t2 VALUES (532,148011,29,'Moll','stratifications','search','A'); +INSERT INTO t2 VALUES (533,148012,29,'ropers','signaled','Angeles','A'); +INSERT INTO t2 VALUES (534,148013,29,'bombast','Italianizes','semblance',''); +INSERT INTO t2 VALUES (535,148023,36,'difficultly','algorithmic','taxed',''); +INSERT INTO t2 VALUES (536,148015,29,'adsorption','paranoid','Beatrice',''); +INSERT INTO t2 VALUES (537,148016,29,'definiteness','camping','retrace',''); +INSERT INTO t2 VALUES (538,148017,29,'cultivation','signifying','lockout',''); +INSERT INTO t2 VALUES (539,148018,29,'heals','Patrice','grammatic',''); +INSERT INTO t2 VALUES (540,148019,29,'Heusen','search','helmsman',''); +INSERT INTO t2 VALUES (541,148020,29,'target','Angeles','uniform','W'); +INSERT INTO t2 VALUES (542,148021,29,'cited','semblance','hamming',''); +INSERT INTO t2 VALUES (543,148022,29,'congresswoman','taxed','disobedience',''); +INSERT INTO t2 VALUES (544,148101,29,'Katherine','Beatrice','captivated','A'); +INSERT INTO t2 VALUES (545,148102,29,'titter','retrace','transferals','A'); +INSERT INTO t2 VALUES (546,148201,29,'aspire','lockout','cartographer','A'); +INSERT INTO t2 VALUES (547,148401,29,'Mardis','grammatic','aims','FAS'); +INSERT INTO t2 VALUES (548,148402,29,'Nadia','helmsman','Pakistani',''); +INSERT INTO t2 VALUES (549,148501,29,'estimating','uniform','burglarized','FAS'); +INSERT INTO t2 VALUES (550,148502,29,'stuck','hamming','saucepans','A'); +INSERT INTO t2 VALUES (551,148503,29,'fifteenth','disobedience','lacerating','A'); +INSERT INTO t2 VALUES (552,148504,29,'Colombo','captivated','corny',''); +INSERT INTO t2 VALUES (553,148601,29,'survey','transferals','megabytes','FAS'); +INSERT INTO t2 VALUES (554,148602,29,'staffing','cartographer','chancellor',''); +INSERT INTO t2 VALUES (555,150701,29,'obtain','aims','bulk','A'); +INSERT INTO t2 VALUES (556,152101,29,'loaded','Pakistani','commits','A'); +INSERT INTO t2 VALUES (557,152102,29,'slaughtered','burglarized','meson','W'); +INSERT INTO t2 VALUES (558,155202,36,'lights','saucepans','deputies',''); +INSERT INTO t2 VALUES (559,155203,29,'circumference','lacerating','northeaster','A'); +INSERT INTO t2 VALUES (560,155204,29,'dull','corny','dipole',''); +INSERT INTO t2 VALUES (561,155205,29,'weekly','megabytes','machining','0'); +INSERT INTO t2 VALUES (562,156001,29,'wetness','chancellor','therefore',''); +INSERT INTO t2 VALUES (563,156002,29,'visualized','bulk','Telefunken',''); +INSERT INTO t2 VALUES (564,156102,29,'Tannenbaum','commits','salvaging',''); +INSERT INTO t2 VALUES (565,156301,29,'moribund','meson','Corinthianizes','A'); +INSERT INTO t2 VALUES (566,156302,29,'demultiplex','deputies','restlessly','A'); +INSERT INTO t2 VALUES (567,156303,29,'lockings','northeaster','bromides',''); +INSERT INTO t2 VALUES (568,156304,29,'thugs','dipole','generalized','A'); +INSERT INTO t2 VALUES (569,156305,29,'unnerves','machining','mishaps',''); +INSERT INTO t2 VALUES (570,156306,29,'abut','therefore','quelling',''); +INSERT INTO t2 VALUES (571,156501,29,'Chippewa','Telefunken','spiritual','A'); +INSERT INTO t2 VALUES (572,158001,29,'stratifications','salvaging','beguiles','FAS'); +INSERT INTO t2 VALUES (573,158002,29,'signaled','Corinthianizes','Trobriand','FAS'); +INSERT INTO t2 VALUES (574,158101,29,'Italianizes','restlessly','fleeing','A'); +INSERT INTO t2 VALUES (575,158102,29,'algorithmic','bromides','Armour','A'); +INSERT INTO t2 VALUES (576,158103,29,'paranoid','generalized','chin','A'); +INSERT INTO t2 VALUES (577,158201,29,'camping','mishaps','provers','A'); +INSERT INTO t2 VALUES (578,158202,29,'signifying','quelling','aeronautic','A'); +INSERT INTO t2 VALUES (579,158203,29,'Patrice','spiritual','voltage','W'); +INSERT INTO t2 VALUES (580,158204,29,'search','beguiles','sash',''); +INSERT INTO t2 VALUES (581,158301,29,'Angeles','Trobriand','anaerobic','A'); +INSERT INTO t2 VALUES (582,158302,29,'semblance','fleeing','simultaneous','A'); +INSERT INTO t2 VALUES (583,158303,29,'taxed','Armour','accumulating','A'); +INSERT INTO t2 VALUES (584,158304,29,'Beatrice','chin','Medusan','A'); +INSERT INTO t2 VALUES (585,158305,29,'retrace','provers','shouted','A'); +INSERT INTO t2 VALUES (586,158306,29,'lockout','aeronautic','freakish',''); +INSERT INTO t2 VALUES (587,158501,29,'grammatic','voltage','index','FAS'); +INSERT INTO t2 VALUES (588,160301,29,'helmsman','sash','commercially',''); +INSERT INTO t2 VALUES (589,166101,50,'uniform','anaerobic','mistiness','A'); +INSERT INTO t2 VALUES (590,166102,50,'hamming','simultaneous','endpoint',''); +INSERT INTO t2 VALUES (591,168001,29,'disobedience','accumulating','straight','A'); +INSERT INTO t2 VALUES (592,168002,29,'captivated','Medusan','flurried',''); +INSERT INTO t2 VALUES (593,168003,29,'transferals','shouted','denotative','A'); +INSERT INTO t2 VALUES (594,168101,29,'cartographer','freakish','coming','FAS'); +INSERT INTO t2 VALUES (595,168102,29,'aims','index','commencements','FAS'); +INSERT INTO t2 VALUES (596,168103,29,'Pakistani','commercially','gentleman',''); +INSERT INTO t2 VALUES (597,168104,29,'burglarized','mistiness','gifted',''); +INSERT INTO t2 VALUES (598,168202,29,'saucepans','endpoint','Shanghais',''); +INSERT INTO t2 VALUES (599,168301,29,'lacerating','straight','sportswriting','A'); +INSERT INTO t2 VALUES (600,168502,29,'corny','flurried','sloping','A'); +INSERT INTO t2 VALUES (601,168503,29,'megabytes','denotative','navies',''); +INSERT INTO t2 VALUES (602,168601,29,'chancellor','coming','leaflet','A'); +INSERT INTO t2 VALUES (603,173001,40,'bulk','commencements','shooter',''); +INSERT INTO t2 VALUES (604,173701,40,'commits','gentleman','Joplin','FAS'); +INSERT INTO t2 VALUES (605,173702,40,'meson','gifted','babies',''); +INSERT INTO t2 VALUES (606,176001,40,'deputies','Shanghais','subdivision','FAS'); +INSERT INTO t2 VALUES (607,176101,40,'northeaster','sportswriting','burstiness','W'); +INSERT INTO t2 VALUES (608,176201,40,'dipole','sloping','belted','FAS'); +INSERT INTO t2 VALUES (609,176401,40,'machining','navies','assails','FAS'); +INSERT INTO t2 VALUES (610,176501,40,'therefore','leaflet','admiring','W'); +INSERT INTO t2 VALUES (611,176601,40,'Telefunken','shooter','swaying','0'); +INSERT INTO t2 VALUES (612,176602,40,'salvaging','Joplin','Goldstine','FAS'); +INSERT INTO t2 VALUES (613,176603,40,'Corinthianizes','babies','fitting',''); +INSERT INTO t2 VALUES (614,178001,40,'restlessly','subdivision','Norwalk','W'); +INSERT INTO t2 VALUES (615,178002,40,'bromides','burstiness','weakening','W'); +INSERT INTO t2 VALUES (616,178003,40,'generalized','belted','analogy','FAS'); +INSERT INTO t2 VALUES (617,178004,40,'mishaps','assails','deludes',''); +INSERT INTO t2 VALUES (618,178005,40,'quelling','admiring','cokes',''); +INSERT INTO t2 VALUES (619,178006,40,'spiritual','swaying','Clayton',''); +INSERT INTO t2 VALUES (620,178007,40,'beguiles','Goldstine','exhausts',''); +INSERT INTO t2 VALUES (621,178008,40,'Trobriand','fitting','causality',''); +INSERT INTO t2 VALUES (622,178101,40,'fleeing','Norwalk','sating','FAS'); +INSERT INTO t2 VALUES (623,178102,40,'Armour','weakening','icon',''); +INSERT INTO t2 VALUES (624,178103,40,'chin','analogy','throttles',''); +INSERT INTO t2 VALUES (625,178201,40,'provers','deludes','communicants','FAS'); +INSERT INTO t2 VALUES (626,178202,40,'aeronautic','cokes','dehydrate','FAS'); +INSERT INTO t2 VALUES (627,178301,40,'voltage','Clayton','priceless','FAS'); +INSERT INTO t2 VALUES (628,178302,40,'sash','exhausts','publicly',''); +INSERT INTO t2 VALUES (629,178401,40,'anaerobic','causality','incidentals','FAS'); +INSERT INTO t2 VALUES (630,178402,40,'simultaneous','sating','commonplace',''); +INSERT INTO t2 VALUES (631,178403,40,'accumulating','icon','mumbles',''); +INSERT INTO t2 VALUES (632,178404,40,'Medusan','throttles','furthermore','W'); +INSERT INTO t2 VALUES (633,178501,40,'shouted','communicants','cautioned','W'); +INSERT INTO t2 VALUES (634,186002,37,'freakish','dehydrate','parametrized','A'); +INSERT INTO t2 VALUES (635,186102,37,'index','priceless','registration','A'); +INSERT INTO t2 VALUES (636,186201,40,'commercially','publicly','sadly','FAS'); +INSERT INTO t2 VALUES (637,186202,40,'mistiness','incidentals','positioning',''); +INSERT INTO t2 VALUES (638,186203,40,'endpoint','commonplace','babysitting',''); +INSERT INTO t2 VALUES (639,186302,37,'straight','mumbles','eternal','A'); +INSERT INTO t2 VALUES (640,188007,37,'flurried','furthermore','hoarder',''); +INSERT INTO t2 VALUES (641,188008,37,'denotative','cautioned','congregates',''); +INSERT INTO t2 VALUES (642,188009,37,'coming','parametrized','rains',''); +INSERT INTO t2 VALUES (643,188010,37,'commencements','registration','workers','W'); +INSERT INTO t2 VALUES (644,188011,37,'gentleman','sadly','sags','A'); +INSERT INTO t2 VALUES (645,188012,37,'gifted','positioning','unplug','W'); +INSERT INTO t2 VALUES (646,188013,37,'Shanghais','babysitting','garage','A'); +INSERT INTO t2 VALUES (647,188014,37,'sportswriting','eternal','boulder','A'); +INSERT INTO t2 VALUES (648,188015,37,'sloping','hoarder','hollowly','A'); +INSERT INTO t2 VALUES (649,188016,37,'navies','congregates','specifics',''); +INSERT INTO t2 VALUES (650,188017,37,'leaflet','rains','Teresa',''); +INSERT INTO t2 VALUES (651,188102,37,'shooter','workers','Winsett',''); +INSERT INTO t2 VALUES (652,188103,37,'Joplin','sags','convenient','A'); +INSERT INTO t2 VALUES (653,188202,37,'babies','unplug','buckboards','FAS'); +INSERT INTO t2 VALUES (654,188301,40,'subdivision','garage','amenities',''); +INSERT INTO t2 VALUES (655,188302,40,'burstiness','boulder','resplendent','FAS'); +INSERT INTO t2 VALUES (656,188303,40,'belted','hollowly','priding','FAS'); +INSERT INTO t2 VALUES (657,188401,37,'assails','specifics','configurations',''); +INSERT INTO t2 VALUES (658,188402,37,'admiring','Teresa','untidiness','A'); +INSERT INTO t2 VALUES (659,188503,37,'swaying','Winsett','Brice','W'); +INSERT INTO t2 VALUES (660,188504,37,'Goldstine','convenient','sews','FAS'); +INSERT INTO t2 VALUES (661,188505,37,'fitting','buckboards','participated',''); +INSERT INTO t2 VALUES (662,190701,37,'Norwalk','amenities','Simon','FAS'); +INSERT INTO t2 VALUES (663,190703,50,'weakening','resplendent','certificates',''); +INSERT INTO t2 VALUES (664,191701,37,'analogy','priding','Fitzpatrick',''); +INSERT INTO t2 VALUES (665,191702,37,'deludes','configurations','Evanston','A'); +INSERT INTO t2 VALUES (666,191703,37,'cokes','untidiness','misted',''); +INSERT INTO t2 VALUES (667,196001,37,'Clayton','Brice','textures','A'); +INSERT INTO t2 VALUES (668,196002,37,'exhausts','sews','save',''); +INSERT INTO t2 VALUES (669,196003,37,'causality','participated','count',''); +INSERT INTO t2 VALUES (670,196101,37,'sating','Simon','rightful','A'); +INSERT INTO t2 VALUES (671,196103,37,'icon','certificates','chaperone',''); +INSERT INTO t2 VALUES (672,196104,37,'throttles','Fitzpatrick','Lizzy','A'); +INSERT INTO t2 VALUES (673,196201,37,'communicants','Evanston','clenched','A'); +INSERT INTO t2 VALUES (674,196202,37,'dehydrate','misted','effortlessly',''); +INSERT INTO t2 VALUES (675,196203,37,'priceless','textures','accessed',''); +INSERT INTO t2 VALUES (676,198001,37,'publicly','save','beaters','A'); +INSERT INTO t2 VALUES (677,198003,37,'incidentals','count','Hornblower','FAS'); +INSERT INTO t2 VALUES (678,198004,37,'commonplace','rightful','vests','A'); +INSERT INTO t2 VALUES (679,198005,37,'mumbles','chaperone','indulgences','FAS'); +INSERT INTO t2 VALUES (680,198006,37,'furthermore','Lizzy','infallibly','A'); +INSERT INTO t2 VALUES (681,198007,37,'cautioned','clenched','unwilling','FAS'); +INSERT INTO t2 VALUES (682,198008,37,'parametrized','effortlessly','excrete','FAS'); +INSERT INTO t2 VALUES (683,198009,37,'registration','accessed','spools','A'); +INSERT INTO t2 VALUES (684,198010,37,'sadly','beaters','crunches','FAS'); +INSERT INTO t2 VALUES (685,198011,37,'positioning','Hornblower','overestimating','FAS'); +INSERT INTO t2 VALUES (686,198012,37,'babysitting','vests','ineffective',''); +INSERT INTO t2 VALUES (687,198013,37,'eternal','indulgences','humiliation','A'); +INSERT INTO t2 VALUES (688,198014,37,'hoarder','infallibly','sophomore',''); +INSERT INTO t2 VALUES (689,198015,37,'congregates','unwilling','star',''); +INSERT INTO t2 VALUES (690,198017,37,'rains','excrete','rifles',''); +INSERT INTO t2 VALUES (691,198018,37,'workers','spools','dialysis',''); +INSERT INTO t2 VALUES (692,198019,37,'sags','crunches','arriving',''); +INSERT INTO t2 VALUES (693,198020,37,'unplug','overestimating','indulge',''); +INSERT INTO t2 VALUES (694,198021,37,'garage','ineffective','clockers',''); +INSERT INTO t2 VALUES (695,198022,37,'boulder','humiliation','languages',''); +INSERT INTO t2 VALUES (696,198023,50,'hollowly','sophomore','Antarctica','A'); +INSERT INTO t2 VALUES (697,198024,37,'specifics','star','percentage',''); +INSERT INTO t2 VALUES (698,198101,37,'Teresa','rifles','ceiling','A'); +INSERT INTO t2 VALUES (699,198103,37,'Winsett','dialysis','specification',''); +INSERT INTO t2 VALUES (700,198105,37,'convenient','arriving','regimented','A'); +INSERT INTO t2 VALUES (701,198106,37,'buckboards','indulge','ciphers',''); +INSERT INTO t2 VALUES (702,198201,37,'amenities','clockers','pictures','A'); +INSERT INTO t2 VALUES (703,198204,37,'resplendent','languages','serpents','A'); +INSERT INTO t2 VALUES (704,198301,53,'priding','Antarctica','allot','A'); +INSERT INTO t2 VALUES (705,198302,53,'configurations','percentage','realized','A'); +INSERT INTO t2 VALUES (706,198303,53,'untidiness','ceiling','mayoral','A'); +INSERT INTO t2 VALUES (707,198304,53,'Brice','specification','opaquely','A'); +INSERT INTO t2 VALUES (708,198401,37,'sews','regimented','hostess','FAS'); +INSERT INTO t2 VALUES (709,198402,37,'participated','ciphers','fiftieth',''); +INSERT INTO t2 VALUES (710,198403,37,'Simon','pictures','incorrectly',''); +INSERT INTO t2 VALUES (711,202101,37,'certificates','serpents','decomposition','FAS'); +INSERT INTO t2 VALUES (712,202301,37,'Fitzpatrick','allot','stranglings',''); +INSERT INTO t2 VALUES (713,202302,37,'Evanston','realized','mixture','FAS'); +INSERT INTO t2 VALUES (714,202303,37,'misted','mayoral','electroencephalography','FAS'); +INSERT INTO t2 VALUES (715,202304,37,'textures','opaquely','similarities','FAS'); +INSERT INTO t2 VALUES (716,202305,37,'save','hostess','charges','W'); +INSERT INTO t2 VALUES (717,202601,37,'count','fiftieth','freest','FAS'); +INSERT INTO t2 VALUES (718,202602,37,'rightful','incorrectly','Greenberg','FAS'); +INSERT INTO t2 VALUES (719,202605,37,'chaperone','decomposition','tinting',''); +INSERT INTO t2 VALUES (720,202606,37,'Lizzy','stranglings','expelled','W'); +INSERT INTO t2 VALUES (721,202607,37,'clenched','mixture','warm',''); +INSERT INTO t2 VALUES (722,202901,37,'effortlessly','electroencephalography','smoothed',''); +INSERT INTO t2 VALUES (723,202902,37,'accessed','similarities','deductions','FAS'); +INSERT INTO t2 VALUES (724,202903,37,'beaters','charges','Romano','W'); +INSERT INTO t2 VALUES (725,202904,37,'Hornblower','freest','bitterroot',''); +INSERT INTO t2 VALUES (726,202907,37,'vests','Greenberg','corset',''); +INSERT INTO t2 VALUES (727,202908,37,'indulgences','tinting','securing',''); +INSERT INTO t2 VALUES (728,203101,37,'infallibly','expelled','environing','FAS'); +INSERT INTO t2 VALUES (729,203103,37,'unwilling','warm','cute',''); +INSERT INTO t2 VALUES (730,203104,37,'excrete','smoothed','Crays',''); +INSERT INTO t2 VALUES (731,203105,37,'spools','deductions','heiress','FAS'); +INSERT INTO t2 VALUES (732,203401,37,'crunches','Romano','inform','FAS'); +INSERT INTO t2 VALUES (733,203402,37,'overestimating','bitterroot','avenge',''); +INSERT INTO t2 VALUES (734,203404,37,'ineffective','corset','universals',''); +INSERT INTO t2 VALUES (735,203901,37,'humiliation','securing','Kinsey','W'); +INSERT INTO t2 VALUES (736,203902,37,'sophomore','environing','ravines','FAS'); +INSERT INTO t2 VALUES (737,203903,37,'star','cute','bestseller',''); +INSERT INTO t2 VALUES (738,203906,37,'rifles','Crays','equilibrium',''); +INSERT INTO t2 VALUES (739,203907,37,'dialysis','heiress','extents','0'); +INSERT INTO t2 VALUES (740,203908,37,'arriving','inform','relatively',''); +INSERT INTO t2 VALUES (741,203909,37,'indulge','avenge','pressure','FAS'); +INSERT INTO t2 VALUES (742,206101,37,'clockers','universals','critiques','FAS'); +INSERT INTO t2 VALUES (743,206201,37,'languages','Kinsey','befouled',''); +INSERT INTO t2 VALUES (744,206202,37,'Antarctica','ravines','rightfully','FAS'); +INSERT INTO t2 VALUES (745,206203,37,'percentage','bestseller','mechanizing','FAS'); +INSERT INTO t2 VALUES (746,206206,37,'ceiling','equilibrium','Latinizes',''); +INSERT INTO t2 VALUES (747,206207,37,'specification','extents','timesharing',''); +INSERT INTO t2 VALUES (748,206208,37,'regimented','relatively','Aden',''); +INSERT INTO t2 VALUES (749,208001,37,'ciphers','pressure','embassies',''); +INSERT INTO t2 VALUES (750,208002,37,'pictures','critiques','males','FAS'); +INSERT INTO t2 VALUES (751,208003,37,'serpents','befouled','shapelessly','FAS'); +INSERT INTO t2 VALUES (752,208004,37,'allot','rightfully','genres','FAS'); +INSERT INTO t2 VALUES (753,208008,37,'realized','mechanizing','mastering',''); +INSERT INTO t2 VALUES (754,208009,37,'mayoral','Latinizes','Newtonian',''); +INSERT INTO t2 VALUES (755,208010,37,'opaquely','timesharing','finishers','FAS'); +INSERT INTO t2 VALUES (756,208011,37,'hostess','Aden','abates',''); +INSERT INTO t2 VALUES (757,208101,37,'fiftieth','embassies','teem',''); +INSERT INTO t2 VALUES (758,208102,37,'incorrectly','males','kiting','FAS'); +INSERT INTO t2 VALUES (759,208103,37,'decomposition','shapelessly','stodgy','FAS'); +INSERT INTO t2 VALUES (760,208104,37,'stranglings','genres','scalps','FAS'); +INSERT INTO t2 VALUES (761,208105,37,'mixture','mastering','feed','FAS'); +INSERT INTO t2 VALUES (762,208110,37,'electroencephalography','Newtonian','guitars',''); +INSERT INTO t2 VALUES (763,208111,37,'similarities','finishers','airships',''); +INSERT INTO t2 VALUES (764,208112,37,'charges','abates','store',''); +INSERT INTO t2 VALUES (765,208113,37,'freest','teem','denounces',''); +INSERT INTO t2 VALUES (766,208201,37,'Greenberg','kiting','Pyle','FAS'); +INSERT INTO t2 VALUES (767,208203,37,'tinting','stodgy','Saxony',''); +INSERT INTO t2 VALUES (768,208301,37,'expelled','scalps','serializations','FAS'); +INSERT INTO t2 VALUES (769,208302,37,'warm','feed','Peruvian','FAS'); +INSERT INTO t2 VALUES (770,208305,37,'smoothed','guitars','taxonomically','FAS'); +INSERT INTO t2 VALUES (771,208401,37,'deductions','airships','kingdom','A'); +INSERT INTO t2 VALUES (772,208402,37,'Romano','store','stint','A'); +INSERT INTO t2 VALUES (773,208403,37,'bitterroot','denounces','Sault','A'); +INSERT INTO t2 VALUES (774,208404,37,'corset','Pyle','faithful',''); +INSERT INTO t2 VALUES (775,208501,37,'securing','Saxony','Ganymede','FAS'); +INSERT INTO t2 VALUES (776,208502,37,'environing','serializations','tidiness','FAS'); +INSERT INTO t2 VALUES (777,208503,37,'cute','Peruvian','gainful','FAS'); +INSERT INTO t2 VALUES (778,208504,37,'Crays','taxonomically','contrary','FAS'); +INSERT INTO t2 VALUES (779,208505,37,'heiress','kingdom','Tipperary','FAS'); +INSERT INTO t2 VALUES (780,210101,37,'inform','stint','tropics','W'); +INSERT INTO t2 VALUES (781,210102,37,'avenge','Sault','theorizers',''); +INSERT INTO t2 VALUES (782,210103,37,'universals','faithful','renew','0'); +INSERT INTO t2 VALUES (783,210104,37,'Kinsey','Ganymede','already',''); +INSERT INTO t2 VALUES (784,210105,37,'ravines','tidiness','terminal',''); +INSERT INTO t2 VALUES (785,210106,37,'bestseller','gainful','Hegelian',''); +INSERT INTO t2 VALUES (786,210107,37,'equilibrium','contrary','hypothesizer',''); +INSERT INTO t2 VALUES (787,210401,37,'extents','Tipperary','warningly','FAS'); +INSERT INTO t2 VALUES (788,213201,37,'relatively','tropics','journalizing','FAS'); +INSERT INTO t2 VALUES (789,213203,37,'pressure','theorizers','nested',''); +INSERT INTO t2 VALUES (790,213204,37,'critiques','renew','Lars',''); +INSERT INTO t2 VALUES (791,213205,37,'befouled','already','saplings',''); +INSERT INTO t2 VALUES (792,213206,37,'rightfully','terminal','foothill',''); +INSERT INTO t2 VALUES (793,213207,37,'mechanizing','Hegelian','labeled',''); +INSERT INTO t2 VALUES (794,216101,37,'Latinizes','hypothesizer','imperiously','FAS'); +INSERT INTO t2 VALUES (795,216103,37,'timesharing','warningly','reporters','FAS'); +INSERT INTO t2 VALUES (796,218001,37,'Aden','journalizing','furnishings','FAS'); +INSERT INTO t2 VALUES (797,218002,37,'embassies','nested','precipitable','FAS'); +INSERT INTO t2 VALUES (798,218003,37,'males','Lars','discounts','FAS'); +INSERT INTO t2 VALUES (799,218004,37,'shapelessly','saplings','excises','FAS'); +INSERT INTO t2 VALUES (800,143503,50,'genres','foothill','Stalin',''); +INSERT INTO t2 VALUES (801,218006,37,'mastering','labeled','despot','FAS'); +INSERT INTO t2 VALUES (802,218007,37,'Newtonian','imperiously','ripeness','FAS'); +INSERT INTO t2 VALUES (803,218008,37,'finishers','reporters','Arabia',''); +INSERT INTO t2 VALUES (804,218009,37,'abates','furnishings','unruly',''); +INSERT INTO t2 VALUES (805,218010,37,'teem','precipitable','mournfulness',''); +INSERT INTO t2 VALUES (806,218011,37,'kiting','discounts','boom','FAS'); +INSERT INTO t2 VALUES (807,218020,37,'stodgy','excises','slaughter','A'); +INSERT INTO t2 VALUES (808,218021,50,'scalps','Stalin','Sabine',''); +INSERT INTO t2 VALUES (809,218022,37,'feed','despot','handy','FAS'); +INSERT INTO t2 VALUES (810,218023,37,'guitars','ripeness','rural',''); +INSERT INTO t2 VALUES (811,218024,37,'airships','Arabia','organizer',''); +INSERT INTO t2 VALUES (812,218101,37,'store','unruly','shipyard','FAS'); +INSERT INTO t2 VALUES (813,218102,37,'denounces','mournfulness','civics','FAS'); +INSERT INTO t2 VALUES (814,218103,37,'Pyle','boom','inaccuracy','FAS'); +INSERT INTO t2 VALUES (815,218201,37,'Saxony','slaughter','rules','FAS'); +INSERT INTO t2 VALUES (816,218202,37,'serializations','Sabine','juveniles','FAS'); +INSERT INTO t2 VALUES (817,218203,37,'Peruvian','handy','comprised','W'); +INSERT INTO t2 VALUES (818,218204,37,'taxonomically','rural','investigations',''); +INSERT INTO t2 VALUES (819,218205,37,'kingdom','organizer','stabilizes','A'); +INSERT INTO t2 VALUES (820,218301,37,'stint','shipyard','seminaries','FAS'); +INSERT INTO t2 VALUES (821,218302,37,'Sault','civics','Hunter','A'); +INSERT INTO t2 VALUES (822,218401,37,'faithful','inaccuracy','sporty','FAS'); +INSERT INTO t2 VALUES (823,218402,37,'Ganymede','rules','test','FAS'); +INSERT INTO t2 VALUES (824,218403,37,'tidiness','juveniles','weasels',''); +INSERT INTO t2 VALUES (825,218404,37,'gainful','comprised','CERN',''); +INSERT INTO t2 VALUES (826,218407,37,'contrary','investigations','tempering',''); +INSERT INTO t2 VALUES (827,218408,37,'Tipperary','stabilizes','afore','FAS'); +INSERT INTO t2 VALUES (828,218409,37,'tropics','seminaries','Galatean',''); +INSERT INTO t2 VALUES (829,218410,37,'theorizers','Hunter','techniques','W'); +INSERT INTO t2 VALUES (830,226001,37,'renew','sporty','error',''); +INSERT INTO t2 VALUES (831,226002,37,'already','test','veranda',''); +INSERT INTO t2 VALUES (832,226003,37,'terminal','weasels','severely',''); +INSERT INTO t2 VALUES (833,226004,37,'Hegelian','CERN','Cassites','FAS'); +INSERT INTO t2 VALUES (834,226005,37,'hypothesizer','tempering','forthcoming',''); +INSERT INTO t2 VALUES (835,226006,37,'warningly','afore','guides',''); +INSERT INTO t2 VALUES (836,226007,37,'journalizing','Galatean','vanish','FAS'); +INSERT INTO t2 VALUES (837,226008,37,'nested','techniques','lied','A'); +INSERT INTO t2 VALUES (838,226203,37,'Lars','error','sawtooth','FAS'); +INSERT INTO t2 VALUES (839,226204,37,'saplings','veranda','fated','FAS'); +INSERT INTO t2 VALUES (840,226205,37,'foothill','severely','gradually',''); +INSERT INTO t2 VALUES (841,226206,37,'labeled','Cassites','widens',''); +INSERT INTO t2 VALUES (842,226207,37,'imperiously','forthcoming','preclude',''); +INSERT INTO t2 VALUES (843,226208,37,'reporters','guides','Jobrel',''); +INSERT INTO t2 VALUES (844,226209,37,'furnishings','vanish','hooker',''); +INSERT INTO t2 VALUES (845,226210,37,'precipitable','lied','rainstorm',''); +INSERT INTO t2 VALUES (846,226211,37,'discounts','sawtooth','disconnects',''); +INSERT INTO t2 VALUES (847,228001,37,'excises','fated','cruelty',''); +INSERT INTO t2 VALUES (848,228004,37,'Stalin','gradually','exponentials','A'); +INSERT INTO t2 VALUES (849,228005,37,'despot','widens','affective','A'); +INSERT INTO t2 VALUES (850,228006,37,'ripeness','preclude','arteries',''); +INSERT INTO t2 VALUES (851,228007,37,'Arabia','Jobrel','Crosby','FAS'); +INSERT INTO t2 VALUES (852,228008,37,'unruly','hooker','acquaint',''); +INSERT INTO t2 VALUES (853,228009,37,'mournfulness','rainstorm','evenhandedly',''); +INSERT INTO t2 VALUES (854,228101,37,'boom','disconnects','percentage',''); +INSERT INTO t2 VALUES (855,228108,37,'slaughter','cruelty','disobedience',''); +INSERT INTO t2 VALUES (856,228109,37,'Sabine','exponentials','humility',''); +INSERT INTO t2 VALUES (857,228110,37,'handy','affective','gleaning','A'); +INSERT INTO t2 VALUES (858,228111,37,'rural','arteries','petted','A'); +INSERT INTO t2 VALUES (859,228112,37,'organizer','Crosby','bloater','A'); +INSERT INTO t2 VALUES (860,228113,37,'shipyard','acquaint','minion','A'); +INSERT INTO t2 VALUES (861,228114,37,'civics','evenhandedly','marginal','A'); +INSERT INTO t2 VALUES (862,228115,37,'inaccuracy','percentage','apiary','A'); +INSERT INTO t2 VALUES (863,228116,37,'rules','disobedience','measures',''); +INSERT INTO t2 VALUES (864,228117,37,'juveniles','humility','precaution',''); +INSERT INTO t2 VALUES (865,228118,37,'comprised','gleaning','repelled',''); +INSERT INTO t2 VALUES (866,228119,37,'investigations','petted','primary','FAS'); +INSERT INTO t2 VALUES (867,228120,37,'stabilizes','bloater','coverings',''); +INSERT INTO t2 VALUES (868,228121,37,'seminaries','minion','Artemia','A'); +INSERT INTO t2 VALUES (869,228122,37,'Hunter','marginal','navigate',''); +INSERT INTO t2 VALUES (870,228201,37,'sporty','apiary','spatial',''); +INSERT INTO t2 VALUES (871,228206,37,'test','measures','Gurkha',''); +INSERT INTO t2 VALUES (872,228207,37,'weasels','precaution','meanwhile','A'); +INSERT INTO t2 VALUES (873,228208,37,'CERN','repelled','Melinda','A'); +INSERT INTO t2 VALUES (874,228209,37,'tempering','primary','Butterfield',''); +INSERT INTO t2 VALUES (875,228210,37,'afore','coverings','Aldrich','A'); +INSERT INTO t2 VALUES (876,228211,37,'Galatean','Artemia','previewing','A'); +INSERT INTO t2 VALUES (877,228212,37,'techniques','navigate','glut','A'); +INSERT INTO t2 VALUES (878,228213,37,'error','spatial','unaffected',''); +INSERT INTO t2 VALUES (879,228214,37,'veranda','Gurkha','inmate',''); +INSERT INTO t2 VALUES (880,228301,37,'severely','meanwhile','mineral',''); +INSERT INTO t2 VALUES (881,228305,37,'Cassites','Melinda','impending','A'); +INSERT INTO t2 VALUES (882,228306,37,'forthcoming','Butterfield','meditation','A'); +INSERT INTO t2 VALUES (883,228307,37,'guides','Aldrich','ideas',''); +INSERT INTO t2 VALUES (884,228308,37,'vanish','previewing','miniaturizes','W'); +INSERT INTO t2 VALUES (885,228309,37,'lied','glut','lewdly',''); +INSERT INTO t2 VALUES (886,228310,37,'sawtooth','unaffected','title',''); +INSERT INTO t2 VALUES (887,228311,37,'fated','inmate','youthfulness',''); +INSERT INTO t2 VALUES (888,228312,37,'gradually','mineral','creak','FAS'); +INSERT INTO t2 VALUES (889,228313,37,'widens','impending','Chippewa',''); +INSERT INTO t2 VALUES (890,228314,37,'preclude','meditation','clamored',''); +INSERT INTO t2 VALUES (891,228401,65,'Jobrel','ideas','freezes',''); +INSERT INTO t2 VALUES (892,228402,65,'hooker','miniaturizes','forgivably','FAS'); +INSERT INTO t2 VALUES (893,228403,65,'rainstorm','lewdly','reduce','FAS'); +INSERT INTO t2 VALUES (894,228404,65,'disconnects','title','McGovern','W'); +INSERT INTO t2 VALUES (895,228405,65,'cruelty','youthfulness','Nazis','W'); +INSERT INTO t2 VALUES (896,228406,65,'exponentials','creak','epistle','W'); +INSERT INTO t2 VALUES (897,228407,65,'affective','Chippewa','socializes','W'); +INSERT INTO t2 VALUES (898,228408,65,'arteries','clamored','conceptions',''); +INSERT INTO t2 VALUES (899,228409,65,'Crosby','freezes','Kevin',''); +INSERT INTO t2 VALUES (900,228410,65,'acquaint','forgivably','uncovering',''); +INSERT INTO t2 VALUES (901,230301,37,'evenhandedly','reduce','chews','FAS'); +INSERT INTO t2 VALUES (902,230302,37,'percentage','McGovern','appendixes','FAS'); +INSERT INTO t2 VALUES (903,230303,37,'disobedience','Nazis','raining',''); +INSERT INTO t2 VALUES (904,018062,37,'humility','epistle','infest',''); +INSERT INTO t2 VALUES (905,230501,37,'gleaning','socializes','compartment',''); +INSERT INTO t2 VALUES (906,230502,37,'petted','conceptions','minting',''); +INSERT INTO t2 VALUES (907,230503,37,'bloater','Kevin','ducks',''); +INSERT INTO t2 VALUES (908,230504,37,'minion','uncovering','roped','A'); +INSERT INTO t2 VALUES (909,230505,37,'marginal','chews','waltz',''); +INSERT INTO t2 VALUES (910,230506,37,'apiary','appendixes','Lillian',''); +INSERT INTO t2 VALUES (911,230507,37,'measures','raining','repressions','A'); +INSERT INTO t2 VALUES (912,230508,37,'precaution','infest','chillingly',''); +INSERT INTO t2 VALUES (913,230509,37,'repelled','compartment','noncritical',''); +INSERT INTO t2 VALUES (914,230901,37,'primary','minting','lithograph',''); +INSERT INTO t2 VALUES (915,230902,37,'coverings','ducks','spongers',''); +INSERT INTO t2 VALUES (916,230903,37,'Artemia','roped','parenthood',''); +INSERT INTO t2 VALUES (917,230904,37,'navigate','waltz','posed',''); +INSERT INTO t2 VALUES (918,230905,37,'spatial','Lillian','instruments',''); +INSERT INTO t2 VALUES (919,230906,37,'Gurkha','repressions','filial',''); +INSERT INTO t2 VALUES (920,230907,37,'meanwhile','chillingly','fixedly',''); +INSERT INTO t2 VALUES (921,230908,37,'Melinda','noncritical','relives',''); +INSERT INTO t2 VALUES (922,230909,37,'Butterfield','lithograph','Pandora',''); +INSERT INTO t2 VALUES (923,230910,37,'Aldrich','spongers','watering','A'); +INSERT INTO t2 VALUES (924,230911,37,'previewing','parenthood','ungrateful',''); +INSERT INTO t2 VALUES (925,230912,37,'glut','posed','secures',''); +INSERT INTO t2 VALUES (926,230913,37,'unaffected','instruments','chastisers',''); +INSERT INTO t2 VALUES (927,230914,37,'inmate','filial','icon',''); +INSERT INTO t2 VALUES (928,231304,37,'mineral','fixedly','reuniting','A'); +INSERT INTO t2 VALUES (929,231305,37,'impending','relives','imagining','A'); +INSERT INTO t2 VALUES (930,231306,37,'meditation','Pandora','abiding','A'); +INSERT INTO t2 VALUES (931,231307,37,'ideas','watering','omnisciently',''); +INSERT INTO t2 VALUES (932,231308,37,'miniaturizes','ungrateful','Britannic',''); +INSERT INTO t2 VALUES (933,231309,37,'lewdly','secures','scholastics','A'); +INSERT INTO t2 VALUES (934,231310,37,'title','chastisers','mechanics','A'); +INSERT INTO t2 VALUES (935,231311,37,'youthfulness','icon','humidly','A'); +INSERT INTO t2 VALUES (936,231312,37,'creak','reuniting','masterpiece',''); +INSERT INTO t2 VALUES (937,231313,37,'Chippewa','imagining','however',''); +INSERT INTO t2 VALUES (938,231314,37,'clamored','abiding','Mendelian',''); +INSERT INTO t2 VALUES (939,231315,37,'freezes','omnisciently','jarred',''); +INSERT INTO t2 VALUES (940,232102,37,'forgivably','Britannic','scolds',''); +INSERT INTO t2 VALUES (941,232103,37,'reduce','scholastics','infatuate',''); +INSERT INTO t2 VALUES (942,232104,37,'McGovern','mechanics','willed','A'); +INSERT INTO t2 VALUES (943,232105,37,'Nazis','humidly','joyfully',''); +INSERT INTO t2 VALUES (944,232106,37,'epistle','masterpiece','Microsoft',''); +INSERT INTO t2 VALUES (945,232107,37,'socializes','however','fibrosities',''); +INSERT INTO t2 VALUES (946,232108,37,'conceptions','Mendelian','Baltimorean',''); +INSERT INTO t2 VALUES (947,232601,37,'Kevin','jarred','equestrian',''); +INSERT INTO t2 VALUES (948,232602,37,'uncovering','scolds','Goodrich',''); +INSERT INTO t2 VALUES (949,232603,37,'chews','infatuate','apish','A'); +INSERT INTO t2 VALUES (950,232605,37,'appendixes','willed','Adlerian',''); +INSERT INTO t2 VALUES (5950,1232605,37,'appendixes','willed','Adlerian',''); +INSERT INTO t2 VALUES (5951,1232606,37,'appendixes','willed','Adlerian',''); +INSERT INTO t2 VALUES (5952,1232607,37,'appendixes','willed','Adlerian',''); +INSERT INTO t2 VALUES (5953,1232608,37,'appendixes','willed','Adlerian',''); +INSERT INTO t2 VALUES (5954,1232609,37,'appendixes','willed','Adlerian',''); +INSERT INTO t2 VALUES (951,232606,37,'raining','joyfully','Tropez',''); +INSERT INTO t2 VALUES (952,232607,37,'infest','Microsoft','nouns',''); +INSERT INTO t2 VALUES (953,232608,37,'compartment','fibrosities','distracting',''); +INSERT INTO t2 VALUES (954,232609,37,'minting','Baltimorean','mutton',''); +INSERT INTO t2 VALUES (955,236104,37,'ducks','equestrian','bridgeable','A'); +INSERT INTO t2 VALUES (956,236105,37,'roped','Goodrich','stickers','A'); +INSERT INTO t2 VALUES (957,236106,37,'waltz','apish','transcontinental','A'); +INSERT INTO t2 VALUES (958,236107,37,'Lillian','Adlerian','amateurish',''); +INSERT INTO t2 VALUES (959,236108,37,'repressions','Tropez','Gandhian',''); +INSERT INTO t2 VALUES (960,236109,37,'chillingly','nouns','stratified',''); +INSERT INTO t2 VALUES (961,236110,37,'noncritical','distracting','chamberlains',''); +INSERT INTO t2 VALUES (962,236111,37,'lithograph','mutton','creditably',''); +INSERT INTO t2 VALUES (963,236112,37,'spongers','bridgeable','philosophic',''); +INSERT INTO t2 VALUES (964,236113,37,'parenthood','stickers','ores',''); +INSERT INTO t2 VALUES (965,238005,37,'posed','transcontinental','Carleton',''); +INSERT INTO t2 VALUES (966,238006,37,'instruments','amateurish','tape','A'); +INSERT INTO t2 VALUES (967,238007,37,'filial','Gandhian','afloat','A'); +INSERT INTO t2 VALUES (968,238008,37,'fixedly','stratified','goodness','A'); +INSERT INTO t2 VALUES (969,238009,37,'relives','chamberlains','welcoming',''); +INSERT INTO t2 VALUES (970,238010,37,'Pandora','creditably','Pinsky','FAS'); +INSERT INTO t2 VALUES (971,238011,37,'watering','philosophic','halting',''); +INSERT INTO t2 VALUES (972,238012,37,'ungrateful','ores','bibliography',''); +INSERT INTO t2 VALUES (973,238013,37,'secures','Carleton','decoding',''); +INSERT INTO t2 VALUES (974,240401,41,'chastisers','tape','variance','A'); +INSERT INTO t2 VALUES (975,240402,41,'icon','afloat','allowed','A'); +INSERT INTO t2 VALUES (976,240901,41,'reuniting','goodness','dire','A'); +INSERT INTO t2 VALUES (977,240902,41,'imagining','welcoming','dub','A'); +INSERT INTO t2 VALUES (978,241801,41,'abiding','Pinsky','poisoning',''); +INSERT INTO t2 VALUES (979,242101,41,'omnisciently','halting','Iraqis','A'); +INSERT INTO t2 VALUES (980,242102,41,'Britannic','bibliography','heaving',''); +INSERT INTO t2 VALUES (981,242201,41,'scholastics','decoding','population','A'); +INSERT INTO t2 VALUES (982,242202,41,'mechanics','variance','bomb','A'); +INSERT INTO t2 VALUES (983,242501,41,'humidly','allowed','Majorca','A'); +INSERT INTO t2 VALUES (984,242502,41,'masterpiece','dire','Gershwins',''); +INSERT INTO t2 VALUES (985,246201,41,'however','dub','explorers',''); +INSERT INTO t2 VALUES (986,246202,41,'Mendelian','poisoning','libretto','A'); +INSERT INTO t2 VALUES (987,246203,41,'jarred','Iraqis','occurred',''); +INSERT INTO t2 VALUES (988,246204,41,'scolds','heaving','Lagos',''); +INSERT INTO t2 VALUES (989,246205,41,'infatuate','population','rats',''); +INSERT INTO t2 VALUES (990,246301,41,'willed','bomb','bankruptcies','A'); +INSERT INTO t2 VALUES (991,246302,41,'joyfully','Majorca','crying',''); +INSERT INTO t2 VALUES (992,248001,41,'Microsoft','Gershwins','unexpected',''); +INSERT INTO t2 VALUES (993,248002,41,'fibrosities','explorers','accessed','A'); +INSERT INTO t2 VALUES (994,248003,41,'Baltimorean','libretto','colorful','A'); +INSERT INTO t2 VALUES (995,248004,41,'equestrian','occurred','versatility','A'); +INSERT INTO t2 VALUES (996,248005,41,'Goodrich','Lagos','cosy',''); +INSERT INTO t2 VALUES (997,248006,41,'apish','rats','Darius','A'); +INSERT INTO t2 VALUES (998,248007,41,'Adlerian','bankruptcies','mastering','A'); +INSERT INTO t2 VALUES (999,248008,41,'Tropez','crying','Asiaticizations','A'); +INSERT INTO t2 VALUES (1000,248009,41,'nouns','unexpected','offerers','A'); +INSERT INTO t2 VALUES (1001,248010,41,'distracting','accessed','uncles','A'); +INSERT INTO t2 VALUES (1002,248011,41,'mutton','colorful','sleepwalk',''); +INSERT INTO t2 VALUES (1003,248012,41,'bridgeable','versatility','Ernestine',''); +INSERT INTO t2 VALUES (1004,248013,41,'stickers','cosy','checksumming',''); +INSERT INTO t2 VALUES (1005,248014,41,'transcontinental','Darius','stopped',''); +INSERT INTO t2 VALUES (1006,248015,41,'amateurish','mastering','sicker',''); +INSERT INTO t2 VALUES (1007,248016,41,'Gandhian','Asiaticizations','Italianization',''); +INSERT INTO t2 VALUES (1008,248017,41,'stratified','offerers','alphabetic',''); +INSERT INTO t2 VALUES (1009,248018,41,'chamberlains','uncles','pharmaceutic',''); +INSERT INTO t2 VALUES (1010,248019,41,'creditably','sleepwalk','creator',''); +INSERT INTO t2 VALUES (1011,248020,41,'philosophic','Ernestine','chess',''); +INSERT INTO t2 VALUES (1012,248021,41,'ores','checksumming','charcoal',''); +INSERT INTO t2 VALUES (1013,248101,41,'Carleton','stopped','Epiphany','A'); +INSERT INTO t2 VALUES (1014,248102,41,'tape','sicker','bulldozes','A'); +INSERT INTO t2 VALUES (1015,248201,41,'afloat','Italianization','Pygmalion','A'); +INSERT INTO t2 VALUES (1016,248202,41,'goodness','alphabetic','caressing','A'); +INSERT INTO t2 VALUES (1017,248203,41,'welcoming','pharmaceutic','Palestine','A'); +INSERT INTO t2 VALUES (1018,248204,41,'Pinsky','creator','regimented','A'); +INSERT INTO t2 VALUES (1019,248205,41,'halting','chess','scars','A'); +INSERT INTO t2 VALUES (1020,248206,41,'bibliography','charcoal','realest','A'); +INSERT INTO t2 VALUES (1021,248207,41,'decoding','Epiphany','diffusing','A'); +INSERT INTO t2 VALUES (1022,248208,41,'variance','bulldozes','clubroom','A'); +INSERT INTO t2 VALUES (1023,248209,41,'allowed','Pygmalion','Blythe','A'); +INSERT INTO t2 VALUES (1024,248210,41,'dire','caressing','ahead',''); +INSERT INTO t2 VALUES (1025,248211,50,'dub','Palestine','reviver',''); +INSERT INTO t2 VALUES (1026,250501,34,'poisoning','regimented','retransmitting','A'); +INSERT INTO t2 VALUES (1027,250502,34,'Iraqis','scars','landslide',''); +INSERT INTO t2 VALUES (1028,250503,34,'heaving','realest','Eiffel',''); +INSERT INTO t2 VALUES (1029,250504,34,'population','diffusing','absentee',''); +INSERT INTO t2 VALUES (1030,250505,34,'bomb','clubroom','aye',''); +INSERT INTO t2 VALUES (1031,250601,34,'Majorca','Blythe','forked','A'); +INSERT INTO t2 VALUES (1032,250602,34,'Gershwins','ahead','Peruvianizes',''); +INSERT INTO t2 VALUES (1033,250603,34,'explorers','reviver','clerked',''); +INSERT INTO t2 VALUES (1034,250604,34,'libretto','retransmitting','tutor',''); +INSERT INTO t2 VALUES (1035,250605,34,'occurred','landslide','boulevard',''); +INSERT INTO t2 VALUES (1036,251001,34,'Lagos','Eiffel','shuttered',''); +INSERT INTO t2 VALUES (1037,251002,34,'rats','absentee','quotes','A'); +INSERT INTO t2 VALUES (1038,251003,34,'bankruptcies','aye','Caltech',''); +INSERT INTO t2 VALUES (1039,251004,34,'crying','forked','Mossberg',''); +INSERT INTO t2 VALUES (1040,251005,34,'unexpected','Peruvianizes','kept',''); +INSERT INTO t2 VALUES (1041,251301,34,'accessed','clerked','roundly',''); +INSERT INTO t2 VALUES (1042,251302,34,'colorful','tutor','features','A'); +INSERT INTO t2 VALUES (1043,251303,34,'versatility','boulevard','imaginable','A'); +INSERT INTO t2 VALUES (1044,251304,34,'cosy','shuttered','controller',''); +INSERT INTO t2 VALUES (1045,251305,34,'Darius','quotes','racial',''); +INSERT INTO t2 VALUES (1046,251401,34,'mastering','Caltech','uprisings','A'); +INSERT INTO t2 VALUES (1047,251402,34,'Asiaticizations','Mossberg','narrowed','A'); +INSERT INTO t2 VALUES (1048,251403,34,'offerers','kept','cannot','A'); +INSERT INTO t2 VALUES (1049,251404,34,'uncles','roundly','vest',''); +INSERT INTO t2 VALUES (1050,251405,34,'sleepwalk','features','famine',''); +INSERT INTO t2 VALUES (1051,251406,34,'Ernestine','imaginable','sugars',''); +INSERT INTO t2 VALUES (1052,251801,34,'checksumming','controller','exterminated','A'); +INSERT INTO t2 VALUES (1053,251802,34,'stopped','racial','belays',''); +INSERT INTO t2 VALUES (1054,252101,34,'sicker','uprisings','Hodges','A'); +INSERT INTO t2 VALUES (1055,252102,34,'Italianization','narrowed','translatable',''); +INSERT INTO t2 VALUES (1056,252301,34,'alphabetic','cannot','duality','A'); +INSERT INTO t2 VALUES (1057,252302,34,'pharmaceutic','vest','recording','A'); +INSERT INTO t2 VALUES (1058,252303,34,'creator','famine','rouses','A'); +INSERT INTO t2 VALUES (1059,252304,34,'chess','sugars','poison',''); +INSERT INTO t2 VALUES (1060,252305,34,'charcoal','exterminated','attitude',''); +INSERT INTO t2 VALUES (1061,252306,34,'Epiphany','belays','dusted',''); +INSERT INTO t2 VALUES (1062,252307,34,'bulldozes','Hodges','encompasses',''); +INSERT INTO t2 VALUES (1063,252308,34,'Pygmalion','translatable','presentation',''); +INSERT INTO t2 VALUES (1064,252309,34,'caressing','duality','Kantian',''); +INSERT INTO t2 VALUES (1065,256001,34,'Palestine','recording','imprecision','A'); +INSERT INTO t2 VALUES (1066,256002,34,'regimented','rouses','saving',''); +INSERT INTO t2 VALUES (1067,256003,34,'scars','poison','maternal',''); +INSERT INTO t2 VALUES (1068,256004,34,'realest','attitude','hewed',''); +INSERT INTO t2 VALUES (1069,256005,34,'diffusing','dusted','kerosene',''); +INSERT INTO t2 VALUES (1070,258001,34,'clubroom','encompasses','Cubans',''); +INSERT INTO t2 VALUES (1071,258002,34,'Blythe','presentation','photographers',''); +INSERT INTO t2 VALUES (1072,258003,34,'ahead','Kantian','nymph','A'); +INSERT INTO t2 VALUES (1073,258004,34,'reviver','imprecision','bedlam','A'); +INSERT INTO t2 VALUES (1074,258005,34,'retransmitting','saving','north','A'); +INSERT INTO t2 VALUES (1075,258006,34,'landslide','maternal','Schoenberg','A'); +INSERT INTO t2 VALUES (1076,258007,34,'Eiffel','hewed','botany','A'); +INSERT INTO t2 VALUES (1077,258008,34,'absentee','kerosene','curs',''); +INSERT INTO t2 VALUES (1078,258009,34,'aye','Cubans','solidification',''); +INSERT INTO t2 VALUES (1079,258010,34,'forked','photographers','inheritresses',''); +INSERT INTO t2 VALUES (1080,258011,34,'Peruvianizes','nymph','stiller',''); +INSERT INTO t2 VALUES (1081,258101,68,'clerked','bedlam','t1','A'); +INSERT INTO t2 VALUES (1082,258102,68,'tutor','north','suite','A'); +INSERT INTO t2 VALUES (1083,258103,34,'boulevard','Schoenberg','ransomer',''); +INSERT INTO t2 VALUES (1084,258104,68,'shuttered','botany','Willy',''); +INSERT INTO t2 VALUES (1085,258105,68,'quotes','curs','Rena','A'); +INSERT INTO t2 VALUES (1086,258106,68,'Caltech','solidification','Seattle','A'); +INSERT INTO t2 VALUES (1087,258107,68,'Mossberg','inheritresses','relaxes','A'); +INSERT INTO t2 VALUES (1088,258108,68,'kept','stiller','exclaim',''); +INSERT INTO t2 VALUES (1089,258109,68,'roundly','t1','implicated','A'); +INSERT INTO t2 VALUES (1090,258110,68,'features','suite','distinguish',''); +INSERT INTO t2 VALUES (1091,258111,68,'imaginable','ransomer','assayed',''); +INSERT INTO t2 VALUES (1092,258112,68,'controller','Willy','homeowner',''); +INSERT INTO t2 VALUES (1093,258113,68,'racial','Rena','and',''); +INSERT INTO t2 VALUES (1094,258201,34,'uprisings','Seattle','stealth',''); +INSERT INTO t2 VALUES (1095,258202,34,'narrowed','relaxes','coinciding','A'); +INSERT INTO t2 VALUES (1096,258203,34,'cannot','exclaim','founder','A'); +INSERT INTO t2 VALUES (1097,258204,34,'vest','implicated','environing',''); +INSERT INTO t2 VALUES (1098,258205,34,'famine','distinguish','jewelry',''); +INSERT INTO t2 VALUES (1099,258301,34,'sugars','assayed','lemons','A'); +INSERT INTO t2 VALUES (1100,258401,34,'exterminated','homeowner','brokenness','A'); +INSERT INTO t2 VALUES (1101,258402,34,'belays','and','bedpost','A'); +INSERT INTO t2 VALUES (1102,258403,34,'Hodges','stealth','assurers','A'); +INSERT INTO t2 VALUES (1103,258404,34,'translatable','coinciding','annoyers',''); +INSERT INTO t2 VALUES (1104,258405,34,'duality','founder','affixed',''); +INSERT INTO t2 VALUES (1105,258406,34,'recording','environing','warbling',''); +INSERT INTO t2 VALUES (1106,258407,34,'rouses','jewelry','seriously',''); +INSERT INTO t2 VALUES (1107,228123,37,'poison','lemons','boasted',''); +INSERT INTO t2 VALUES (1108,250606,34,'attitude','brokenness','Chantilly',''); +INSERT INTO t2 VALUES (1109,208405,37,'dusted','bedpost','Iranizes',''); +INSERT INTO t2 VALUES (1110,212101,37,'encompasses','assurers','violinist',''); +INSERT INTO t2 VALUES (1111,218206,37,'presentation','annoyers','extramarital',''); +INSERT INTO t2 VALUES (1112,150401,37,'Kantian','affixed','spates',''); +INSERT INTO t2 VALUES (1113,248212,41,'imprecision','warbling','cloakroom',''); +INSERT INTO t2 VALUES (1114,128026,00,'saving','seriously','gazer',''); +INSERT INTO t2 VALUES (1115,128024,00,'maternal','boasted','hand',''); +INSERT INTO t2 VALUES (1116,128027,00,'hewed','Chantilly','tucked',''); +INSERT INTO t2 VALUES (1117,128025,00,'kerosene','Iranizes','gems',''); +INSERT INTO t2 VALUES (1118,128109,00,'Cubans','violinist','clinker',''); +INSERT INTO t2 VALUES (1119,128705,00,'photographers','extramarital','refiner',''); +INSERT INTO t2 VALUES (1120,126303,00,'nymph','spates','callus',''); +INSERT INTO t2 VALUES (1121,128308,00,'bedlam','cloakroom','leopards',''); +INSERT INTO t2 VALUES (1122,128204,00,'north','gazer','comfortingly',''); +INSERT INTO t2 VALUES (1123,128205,00,'Schoenberg','hand','generically',''); +INSERT INTO t2 VALUES (1124,128206,00,'botany','tucked','getters',''); +INSERT INTO t2 VALUES (1125,128207,00,'curs','gems','sexually',''); +INSERT INTO t2 VALUES (1126,118205,00,'solidification','clinker','spear',''); +INSERT INTO t2 VALUES (1127,116801,00,'inheritresses','refiner','serums',''); +INSERT INTO t2 VALUES (1128,116803,00,'stiller','callus','Italianization',''); +INSERT INTO t2 VALUES (1129,116804,00,'t1','leopards','attendants',''); +INSERT INTO t2 VALUES (1130,116802,00,'suite','comfortingly','spies',''); +INSERT INTO t2 VALUES (1131,128605,00,'ransomer','generically','Anthony',''); +INSERT INTO t2 VALUES (1132,118308,00,'Willy','getters','planar',''); +INSERT INTO t2 VALUES (1133,113702,00,'Rena','sexually','cupped',''); +INSERT INTO t2 VALUES (1134,113703,00,'Seattle','spear','cleanser',''); +INSERT INTO t2 VALUES (1135,112103,00,'relaxes','serums','commuters',''); +INSERT INTO t2 VALUES (1136,118009,00,'exclaim','Italianization','honeysuckle',''); +INSERT INTO t2 VALUES (5136,1118009,00,'exclaim','Italianization','honeysuckle',''); +INSERT INTO t2 VALUES (1137,138011,00,'implicated','attendants','orphanage',''); +INSERT INTO t2 VALUES (1138,138010,00,'distinguish','spies','skies',''); +INSERT INTO t2 VALUES (1139,138012,00,'assayed','Anthony','crushers',''); +INSERT INTO t2 VALUES (1140,068304,00,'homeowner','planar','Puritan',''); +INSERT INTO t2 VALUES (1141,078009,00,'and','cupped','squeezer',''); +INSERT INTO t2 VALUES (1142,108013,00,'stealth','cleanser','bruises',''); +INSERT INTO t2 VALUES (1143,084004,00,'coinciding','commuters','bonfire',''); +INSERT INTO t2 VALUES (1144,083402,00,'founder','honeysuckle','Colombo',''); +INSERT INTO t2 VALUES (1145,084003,00,'environing','orphanage','nondecreasing',''); +INSERT INTO t2 VALUES (1146,088504,00,'jewelry','skies','innocents',''); +INSERT INTO t2 VALUES (1147,088005,00,'lemons','crushers','masked',''); +INSERT INTO t2 VALUES (1148,088007,00,'brokenness','Puritan','file',''); +INSERT INTO t2 VALUES (1149,088006,00,'bedpost','squeezer','brush',''); +INSERT INTO t2 VALUES (1150,148025,00,'assurers','bruises','mutilate',''); +INSERT INTO t2 VALUES (1151,148024,00,'annoyers','bonfire','mommy',''); +INSERT INTO t2 VALUES (1152,138305,00,'affixed','Colombo','bulkheads',''); +INSERT INTO t2 VALUES (1153,138306,00,'warbling','nondecreasing','undeclared',''); +INSERT INTO t2 VALUES (1154,152701,00,'seriously','innocents','displacements',''); +INSERT INTO t2 VALUES (1155,148505,00,'boasted','masked','nieces',''); +INSERT INTO t2 VALUES (1156,158003,00,'Chantilly','file','coeducation',''); +INSERT INTO t2 VALUES (1157,156201,00,'Iranizes','brush','brassy',''); +INSERT INTO t2 VALUES (1158,156202,00,'violinist','mutilate','authenticator',''); +INSERT INTO t2 VALUES (1159,158307,00,'extramarital','mommy','Washoe',''); +INSERT INTO t2 VALUES (1160,158402,00,'spates','bulkheads','penny',''); +INSERT INTO t2 VALUES (1161,158401,00,'cloakroom','undeclared','Flagler',''); +INSERT INTO t2 VALUES (1162,068013,00,'gazer','displacements','stoned',''); +INSERT INTO t2 VALUES (1163,068012,00,'hand','nieces','cranes',''); +INSERT INTO t2 VALUES (1164,068203,00,'tucked','coeducation','masterful',''); +INSERT INTO t2 VALUES (1165,088205,00,'gems','brassy','biracial',''); +INSERT INTO t2 VALUES (1166,068704,00,'clinker','authenticator','steamships',''); +INSERT INTO t2 VALUES (1167,068604,00,'refiner','Washoe','windmills',''); +INSERT INTO t2 VALUES (1168,158502,00,'callus','penny','exploit',''); +INSERT INTO t2 VALUES (1169,123103,00,'leopards','Flagler','riverfront',''); +INSERT INTO t2 VALUES (1170,148026,00,'comfortingly','stoned','sisterly',''); +INSERT INTO t2 VALUES (1171,123302,00,'generically','cranes','sharpshoot',''); +INSERT INTO t2 VALUES (1172,076503,00,'getters','masterful','mittens',''); +INSERT INTO t2 VALUES (1173,126304,00,'sexually','biracial','interdependency',''); +INSERT INTO t2 VALUES (1174,068306,00,'spear','steamships','policy',''); +INSERT INTO t2 VALUES (1175,143504,00,'serums','windmills','unleashing',''); +INSERT INTO t2 VALUES (1176,160201,00,'Italianization','exploit','pretenders',''); +INSERT INTO t2 VALUES (1177,148028,00,'attendants','riverfront','overstatements',''); +INSERT INTO t2 VALUES (1178,148027,00,'spies','sisterly','birthed',''); +INSERT INTO t2 VALUES (1179,143505,00,'Anthony','sharpshoot','opportunism',''); +INSERT INTO t2 VALUES (1180,108014,00,'planar','mittens','showroom',''); +INSERT INTO t2 VALUES (1181,076104,00,'cupped','interdependency','compromisingly',''); +INSERT INTO t2 VALUES (1182,078106,00,'cleanser','policy','Medicare',''); +INSERT INTO t2 VALUES (1183,126102,00,'commuters','unleashing','corresponds',''); +INSERT INTO t2 VALUES (1184,128029,00,'honeysuckle','pretenders','hardware',''); +INSERT INTO t2 VALUES (1185,128028,00,'orphanage','overstatements','implant',''); +INSERT INTO t2 VALUES (1186,018410,00,'skies','birthed','Alicia',''); +INSERT INTO t2 VALUES (1187,128110,00,'crushers','opportunism','requesting',''); +INSERT INTO t2 VALUES (1188,148506,00,'Puritan','showroom','produced',''); +INSERT INTO t2 VALUES (1189,123303,00,'squeezer','compromisingly','criticizes',''); +INSERT INTO t2 VALUES (1190,123304,00,'bruises','Medicare','backer',''); +INSERT INTO t2 VALUES (1191,068504,00,'bonfire','corresponds','positively',''); +INSERT INTO t2 VALUES (1192,068305,00,'Colombo','hardware','colicky',''); +INSERT INTO t2 VALUES (1193,000000,00,'nondecreasing','implant','thrillingly',''); +--enable_query_log + +# +# Search with a key +# + +select t2.fld3 from t2 where companynr = 58 and fld3 like "%imaginable%"; +select fld3 from t2 where fld3 like "%cultivation" ; + +# +# Search with a key using sorting and limit the same time +# + +select t2.fld3,companynr from t2 where companynr = 57+1 order by fld3; +select fld3,companynr from t2 where companynr = 58 order by fld3; + +select fld3 from t2 order by fld3 desc limit 10; +select fld3 from t2 order by fld3 desc limit 5; +select fld3 from t2 order by fld3 desc limit 5,5; + +# +# Search with a key having a constant with each unique key. +# The table is read directly with read-next on fld3 +# + +select t2.fld3 from t2 where fld3 = 'honeysuckle'; +select t2.fld3 from t2 where fld3 LIKE 'honeysuckl_'; +select t2.fld3 from t2 where fld3 LIKE 'hon_ysuckl_'; +select t2.fld3 from t2 where fld3 LIKE 'honeysuckle%'; +select t2.fld3 from t2 where fld3 LIKE 'h%le'; + +select t2.fld3 from t2 where fld3 LIKE 'honeysuckle_'; +select t2.fld3 from t2 where fld3 LIKE 'don_t_find_me_please%'; + +# +# Test using INDEX and IGNORE INDEX +# + +explain select t2.fld3 from t2 where fld3 = 'honeysuckle'; + +explain select fld3 from t2 ignore index (fld3) where fld3 = 'honeysuckle'; +explain select fld3 from t2 use index (fld1) where fld3 = 'honeysuckle'; + +explain select fld3 from t2 use index (fld3) where fld3 = 'honeysuckle'; +explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle'; + +# +# NOTE NOTE NOTE +# The next should give an error +# + +-- error 1176 +explain select fld3 from t2 ignore index (fld3,not_used); +-- error 1176 +explain select fld3 from t2 use index (not_used); + +# +# Test sorting with a used key (there is no need for sorting) +# + +select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3; +explain select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3; +select fld1,fld3 from t2 where fld3="Colombo" or fld3 = "nondecreasing" order by fld3; + +# +# Search with a key having a constant with many occurrences +# The table is read directly with read-next having fld3 to get the +# occurrences +# + +select fld1,fld3 from t2 where companynr = 37 and fld3 = 'appendixes'; + +# +# Search with bunched 'or's. +# If one can limit the key to a certain interval only the possible +# alternatives will be gone through +# + +select fld1 from t2 where fld1=250501 or fld1="250502"; +explain select fld1 from t2 where fld1=250501 or fld1="250502"; +select fld1 from t2 where fld1=250501 or fld1=250502 or fld1 >= 250505 and fld1 <= 250601 or fld1 between 250501 and 250502; +explain select fld1 from t2 where fld1=250501 or fld1=250502 or fld1 >= 250505 and fld1 <= 250601 or fld1 between 250501 and 250502; + +# +# Search with a key with LIKE constant +# If the like starts with a certain letter key will be used. +# + +select fld1,fld3 from t2 where companynr = 37 and fld3 like 'f%'; +select fld3 from t2 where fld3 like "L%" and fld3 = "ok"; +select fld3 from t2 where (fld3 like "C%" and fld3 = "Chantilly"); +select fld1,fld3 from t2 where fld1 like "25050%"; +select fld1,fld3 from t2 where fld1 like "25050_"; + +# +# Search using distinct. An automatic grouping will be done over all the fields, +# if only distinct is used. In any other case a temporary table will always +# be created. If only the field used for sorting is from the main register, +# it will be sorted first before the distinct table is created. +# + +select distinct companynr from t2; +select distinct companynr from t2 order by companynr; +select distinct companynr from t2 order by companynr desc; +select distinct t2.fld3,period from t2,t1 where companynr=37 and fld3 like "O%"; + +select distinct fld3 from t2 where companynr = 34 order by fld3; +select distinct fld3 from t2 limit 10; +select distinct fld3 from t2 having fld3 like "A%" limit 10; +select distinct substring(fld3,1,3) from t2 where fld3 like "A%"; +select distinct substring(fld3,1,3) as a from t2 having a like "A%" order by a limit 10; +select distinct substring(fld3,1,3) from t2 where fld3 like "A%" limit 10; +select distinct substring(fld3,1,3) as a from t2 having a like "A%" limit 10; + +# make a big table. + +create table t3 ( + period int not null, + name char(32) not null, + companynr int not null, + price double(11,0), + price2 double(11,0), + key (period), + key (name) +); + +--disable_query_log +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1001,"Iranizes",37,5987435,234724); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1002,"violinist",37,28357832,8723648); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1003,"extramarital",37,39654943,235872); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1004,"spates",78,726498,72987523); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1005,"cloakroom",78,98439034,823742); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1006,"gazer",101,834598,27348324); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1007,"hand",154,983543950,29837423); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1008,"tucked",311,234298,3275892); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1009,"gems",447,2374834,9872392); +INSERT INTO t3 (period,name,companynr,price,price2) VALUES (1010,"clinker",512,786542,76234234); +--enable_query_log + +create temporary table tmp engine = myisam select * from t3; + +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +insert into tmp select * from t3; +insert into t3 select * from tmp; +#insert into tmp select * from t3; +#insert into t3 select * from tmp; + +alter table t3 add t2nr int not null auto_increment primary key first; + +drop table tmp; + +# big table done + +SET SQL_BIG_TABLES=1; +select distinct concat(fld3," ",fld3) as namn from t2,t3 where t2.fld1=t3.t2nr order by namn limit 10; +SET SQL_BIG_TABLES=0; +select distinct concat(fld3," ",fld3) from t2,t3 where t2.fld1=t3.t2nr order by fld3 limit 10; +select distinct fld5 from t2 limit 10; + +# +# Force use of remove_dupp +# + +select distinct fld3,count(*) from t2 group by companynr,fld3 limit 10; +SET SQL_BIG_TABLES=1; # Force use of MyISAM +select distinct fld3,count(*) from t2 group by companynr,fld3 limit 10; +SET SQL_BIG_TABLES=0; +select distinct fld3,repeat("a",length(fld3)),count(*) from t2 group by companynr,fld3 limit 100,10; + +# +# A big order by that should trigger a merge in filesort +# + +select distinct companynr,rtrim(space(512+companynr)) from t3 order by 1,2; + +# +# Search with distinct and order by with many table. +# + +select distinct fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2nr order by fld3; + +# +# Here the last fld3 is optimized away from the order by +# + +explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2nr order by t3.t2nr,fld3; + +# +# Some test with ORDER BY and limit +# + +explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; +explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; +explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; + +# +# Search with a constant table. +# + +select period from t1; +select period from t1 where period=1900; +select fld3,period from t1,t2 where fld1 = 011401 order by period; + +# +# Search with a constant table and several keyparts. (Rows are read only once +# in the beginning of the search) +# + +select fld3,period from t2,t3 where t2.fld1 = 011401 and t2.fld1=t3.t2nr and t3.period=1001; + +explain select fld3,period from t2,t3 where t2.fld1 = 011401 and t3.t2nr=t2.fld1 and 1001 = t3.period; + +# +# Search with a constant table and several rows from another table +# + +select fld3,period from t2,t1 where companynr*10 = 37*10; + +# +# Search with a table reference and without a key. +# t3 will be the main table. +# + +select fld3,period,price,price2 from t2,t3 where t2.fld1=t3.t2nr and period >= 1001 and period <= 1002 and t2.companynr = 37 order by fld3,period, price; + +# +# Search with an interval on a table with full key on reference table. +# Here t2 will be the main table and only records matching the +# t2nr will be checked. +# + +select t2.fld1,fld3,period,price,price2 from t2,t3 where t2.fld1>= 18201 and t2.fld1 <= 18811 and t2.fld1=t3.t2nr and period = 1001 and t2.companynr = 37; + +# +# We need another table for join stuff.. +# + +create table t4 ( + companynr tinyint(2) unsigned zerofill NOT NULL default '00', + companyname char(30) NOT NULL default '', + PRIMARY KEY (companynr), + UNIQUE KEY companyname(companyname) +) ENGINE=MyISAM MAX_ROWS=50 PACK_KEYS=1 COMMENT='companynames'; + +--disable_query_log +INSERT INTO t4 (companynr, companyname) VALUES (29,'company 1'); +INSERT INTO t4 (companynr, companyname) VALUES (34,'company 2'); +INSERT INTO t4 (companynr, companyname) VALUES (36,'company 3'); +INSERT INTO t4 (companynr, companyname) VALUES (37,'company 4'); +INSERT INTO t4 (companynr, companyname) VALUES (40,'company 5'); +INSERT INTO t4 (companynr, companyname) VALUES (41,'company 6'); +INSERT INTO t4 (companynr, companyname) VALUES (53,'company 7'); +INSERT INTO t4 (companynr, companyname) VALUES (58,'company 8'); +INSERT INTO t4 (companynr, companyname) VALUES (65,'company 9'); +INSERT INTO t4 (companynr, companyname) VALUES (68,'company 10'); +INSERT INTO t4 (companynr, companyname) VALUES (50,'company 11'); +INSERT INTO t4 (companynr, companyname) VALUES (00,'Unknown'); +--enable_query_log + +# +# Test of stright join to force a full join. +# + +select STRAIGHT_JOIN t2.companynr,companyname from t4,t2 where t2.companynr=t4.companynr group by t2.companynr; + +select SQL_SMALL_RESULT t2.companynr,companyname from t4,t2 where t2.companynr=t4.companynr group by t2.companynr; + +# +# Full join (same alias) +# + +select * from t1,t1 t12; +select t2.fld1,t22.fld1 from t2,t2 t22 where t2.fld1 >= 250501 and t2.fld1 <= 250505 and t22.fld1 >= 250501 and t22.fld1 <= 250505; + +# +# Test of left join. +# +insert into t2 (fld1, companynr) values (999999,99); + +analyze table t2; # PBXT: Required for correct count(*) + +select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +select count(*) from t2 left join t4 using (companynr) where t4.companynr is not null; +explain select t2.companynr,companyname from t2 left join t4 using (companynr) where t4.companynr is null; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr is null; + +select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; +select count(*) from t2 left join t4 using (companynr) where companynr is not null; +explain select companynr,companyname from t2 left join t4 using (companynr) where companynr is null; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr is null; +delete from t2 where fld1=999999; + +analyze table t2; # PBXT: Required for correct count(*) + +# +# Test left join optimization + +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0; + +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 and companynr > 0; +# Following can't be optimized +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr < 0 or t4.companynr > 0; +explain select t2.companynr,companyname from t4 left join t2 using (companynr) where ifnull(t2.companynr,1)>0; + +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr is null; +explain select companynr,companyname from t4 left join t2 using (companynr) where companynr > 0 or companynr < 0 or companynr > 0; +explain select companynr,companyname from t4 left join t2 using (companynr) where ifnull(companynr,1)>0; + +# +# Joins with forms. +# + +select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; +explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1; + +# +# Search using 'or' with the same referens group. +# An interval search will be done first with the first table and after that +# the other table is referenced with a key with a 'test if key in use' for +# each record +# + +select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008; + +select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t2.fld1 = 38208 or t2.fld1 = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; + +select t2.fld1,t2.companynr,fld3,period from t3,t2 where (t3.t2nr = 38208 or t3.t2nr = 38008) and t2.fld1=t3.t2nr and period>=1008 and period<=1009; + +# +# Test of many parenthesis levels +# + +select period from t1 where (((period > 0) or period < 10000 or (period = 1900)) and (period=1900 and period <= 1901) or (period=1903 and (period=1903)) and period>=1902) or ((period=1904 or period=1905) or (period=1906 or period>1907)) or (period=1908 and period = 1909); +select period from t1 where ((period > 0 and period < 1) or (((period > 0 and period < 100) and (period > 10)) or (period > 10)) or (period > 0 and (period > 5 or period > 6))); + +select a.fld1 from t2 as a,t2 b where ((a.fld1 = 250501 and a.fld1=b.fld1) or a.fld1=250502 or a.fld1=250503 or (a.fld1=250505 and a.fld1<=b.fld1 and b.fld1>=a.fld1)) and a.fld1=b.fld1; + +select fld1 from t2 where fld1 in (250502,98005,98006,250503,250605,250606) and fld1 >=250502 and fld1 not in (250605,250606); + +select fld1 from t2 where fld1 between 250502 and 250504; + +select fld3 from t2 where (((fld3 like "_%L%" ) or (fld3 like "%ok%")) and ( fld3 like "L%" or fld3 like "G%")) and fld3 like "L%" ; + +# +# Group on one table. +# optimizer: sort table by group and send rows. +# + +select count(*) from t1; +select companynr,count(*),sum(fld1) from t2 group by companynr; +select companynr,count(*) from t2 group by companynr order by companynr desc limit 5; +select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; +explain extended select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; +select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3; +select companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; +select /*! SQL_SMALL_RESULT */ companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; +select companynr,count(price),sum(price),min(price),max(price),avg(price) from t3 group by companynr ; +select distinct mod(companynr,10) from t4 group by companynr; +select distinct 1 from t4 group by companynr; +select count(distinct fld1) from t2; +select companynr,count(distinct fld1) from t2 group by companynr; +select companynr,count(*) from t2 group by companynr; +select companynr,count(distinct concat(fld1,repeat(65,1000))) from t2 group by companynr; +select companynr,count(distinct concat(fld1,repeat(65,200))) from t2 group by companynr; +select companynr,count(distinct floor(fld1/100)) from t2 group by companynr; +select companynr,count(distinct concat(repeat(65,1000),floor(fld1/100))) from t2 group by companynr; + +# +# group with where on a key field +# + +select sum(fld1),fld3 from t2 where fld3="Romans" group by fld1 limit 10; +select name,count(*) from t3 where name='cloakroom' group by name; +select name,count(*) from t3 where name='cloakroom' and price>10 group by name; +select count(*) from t3 where name='cloakroom' and price2=823742; +select name,count(*) from t3 where name='cloakroom' and price2=823742 group by name; +select name,count(*) from t3 where name >= "extramarital" and price <= 39654943 group by name; +select t2.fld3,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; + +# +# Group with extra not group fields. +# + +select companynr|0,companyname from t4 group by 1; +select t2.companynr,companyname,count(*) from t2,t4 where t2.companynr=t4.companynr group by t2.companynr order by companyname; +select t2.fld1,count(*) from t2,t3 where t2.fld1=158402 and t3.name=t2.fld3 group by t3.name; + +# +# Calculation with group functions +# + +select sum(Period)/count(*) from t1; +select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; +select companynr,sum(price)/count(price) as avg from t3 group by companynr having avg > 70000000 order by avg; + +# +# Group with order on not first table +# optimizer: sort table by group and write group records to tmp table. +# sort tmp_table and send rows. +# + +select companynr,count(*) from t2 group by companynr order by 2 desc; +select companynr,count(*) from t2 where companynr > 40 group by companynr order by 2 desc; +select t2.fld4,t2.fld1,count(price),sum(price),min(price),max(price),avg(price) from t3,t2 where t3.companynr = 37 and t2.fld1 = t3.t2nr group by fld1,t2.fld4; + +# +# group by with many tables +# optimizer: create tmp table with group-by uniq index. +# write with update to tmp table. +# sort tmp table according to order (or group if no order) +# send rows +# + +select t3.companynr,fld3,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 group by companynr,fld3; +select t2.companynr,count(*),min(fld3),max(fld3),sum(price),avg(price) from t2,t3 where t3.companynr >= 30 and t3.companynr <= 58 and t3.t2nr = t2.fld1 and 1+1=2 group by t2.companynr; + +# +# group with many tables and long group on many tables. group on formula +# optimizer: create tmp table with neaded fields +# sort tmp table by group and calculate sums to new table +# if different order by than group, sort tmp table +# send rows +# + +select t3.companynr+0,t3.t2nr,fld3,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 37 group by 1,t3.t2nr,fld3,fld3,fld3,fld3,fld3 order by fld1; + +# +# WHERE const folding +# optimize: If there is a "field = const" part in the where, change all +# instances of field in the and level to const. +# All instances of const = const are checked once and removed. +# + +# +# Where -> t3.t2nr = 98005 and t2.fld1 = 98005 +# + +select sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 and t3.t2nr = 38008 and t2.fld1 = 38008 or t2.fld1= t3.t2nr and t3.t2nr = 38008 and t2.fld1 = 38008; + +select t2.fld1,sum(price) from t3,t2 where t2.fld1 = t3.t2nr and t3.companynr = 512 and t3.t2nr = 38008 and t2.fld1 = 38008 or t2.fld1 = t3.t2nr and t3.t2nr = 38008 and t2.fld1 = 38008 or t3.t2nr = t2.fld1 and t2.fld1 = 38008 group by t2.fld1; + +explain select fld3 from t2 where 1>2 or 2>3; +explain select fld3 from t2 where fld1=fld1; + +# +# HAVING +# + +select companynr,fld1 from t2 HAVING fld1=250501 or fld1=250502; +select companynr,fld1 from t2 WHERE fld1>=250501 HAVING fld1<=250502; +select companynr,count(*) as count,sum(fld1) as sum from t2 group by companynr having count > 40 and sum/count >= 120000; +select companynr from t2 group by companynr having count(*) > 40 and sum(fld1)/count(*) >= 120000 ; +select t2.companynr,companyname,count(*) from t2,t4 where t2.companynr=t4.companynr group by companyname having t2.companynr >= 40; + +# +# MIN(), MAX() and COUNT() optimizing +# + +select count(*) from t2; +select count(*) from t2 where fld1 < 098024; +# PS does correct pre-zero here. MySQL can't do it as it returns a number. +--disable_ps_protocol +select min(fld1) from t2 where fld1>= 098024; +--enable_ps_protocol +select max(fld1) from t2 where fld1>= 098024; +select count(*) from t3 where price2=76234234; +select count(*) from t3 where companynr=512 and price2=76234234; +explain select min(fld1),max(fld1),count(*) from t2; +# PS does correct pre-zero here. MySQL can't do it as it returns a number. +--disable_ps_protocol +select min(fld1),max(fld1),count(*) from t2; +--enable_ps_protocol +select min(t2nr),max(t2nr) from t3 where t2nr=2115 and price2=823742; +select count(*),min(t2nr),max(t2nr) from t3 where name='spates' and companynr=78; +select t2nr,count(*) from t3 where name='gems' group by t2nr limit 20; +select max(t2nr) from t3 where price=983543950; + +# +# Test of alias +# + +select t1.period from t3 = t1 limit 1; +select t1.period from t1 as t1 limit 1; +select t1.period as "Nuvarande period" from t1 as t1 limit 1; +select period as ok_period from t1 limit 1; +select period as ok_period from t1 group by ok_period limit 1; +select 1+1 as summa from t1 group by summa limit 1; +select period as "Nuvarande period" from t1 group by "Nuvarande period" limit 1; + +# +# Some simple show commands +# + +show tables; +show tables from test like "s%"; +show tables from test like "t?"; +# We mask out the Privileges column because it differs with embedded server +--replace_column 8 # +show full columns from t2; +--replace_column 8 # +show full columns from t2 from test like 'f%'; +--replace_column 8 # +show full columns from t2 from test like 's%'; +show keys from t2; + +drop table t4, t3, t2, t1; + +# +# Test of DO +# + +DO 1; +DO benchmark(100,1+1),1,1; + +# +# Bug #6449: do default; +# + +--error ER_PARSE_ERROR +do default; +--error ER_BAD_FIELD_ERROR +do foobar; + +# +# random in WHERE clause +# + +CREATE TABLE t1 ( + id mediumint(8) unsigned NOT NULL auto_increment, + pseudo varchar(35) NOT NULL default '', + PRIMARY KEY (id), + UNIQUE KEY pseudo (pseudo) +); +INSERT INTO t1 (pseudo) VALUES ('test'); +INSERT INTO t1 (pseudo) VALUES ('test1'); +SELECT 1 as rnd1 from t1 where rand() > 2; +DROP TABLE t1; + +# +# Test of bug with SUM(CASE...) +# + +CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (200001,2,1,1,100,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\E$',''),(200002,2,2,1,101,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\C$',''),(200003,1,3,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,0,1,20020425060427,'c:',NULL); +CREATE TABLE t2 ( hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, sampletid smallint(5) unsigned default NULL, sampletime datetime default NULL, samplevalue bigint(20) unsigned default NULL, KEY idx1 (hmid,volid,sampletid,sampletime)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,3,10,'2002-06-01 08:00:00',35),(1,3,1010,'2002-06-01 12:00:01',35); +# Disable PS becasue we get more warnings from PS than from normal execution +--disable_ps_protocol +SELECT a.gvid, (SUM(CASE b.sampletid WHEN 140 THEN b.samplevalue ELSE 0 END)) as the_success,(SUM(CASE b.sampletid WHEN 141 THEN b.samplevalue ELSE 0 END)) as the_fail,(SUM(CASE b.sampletid WHEN 142 THEN b.samplevalue ELSE 0 END)) as the_size,(SUM(CASE b.sampletid WHEN 143 THEN b.samplevalue ELSE 0 END)) as the_time FROM t1 a, t2 b WHERE a.hmid = b.hmid AND a.volid = b.volid AND b.sampletime >= 'wrong-date-value' AND b.sampletime < 'wrong-date-value' AND b.sampletid IN (140, 141, 142, 143) GROUP BY a.gvid; +--enable_ps_protocol +# Testing the same select with NULL's instead of invalid datetime values +SELECT a.gvid, (SUM(CASE b.sampletid WHEN 140 THEN b.samplevalue ELSE 0 END)) as the_success,(SUM(CASE b.sampletid WHEN 141 THEN b.samplevalue ELSE 0 END)) as the_fail,(SUM(CASE b.sampletid WHEN 142 THEN b.samplevalue ELSE 0 END)) as the_size,(SUM(CASE b.sampletid WHEN 143 THEN b.samplevalue ELSE 0 END)) as the_time FROM t1 a, t2 b WHERE a.hmid = b.hmid AND a.volid = b.volid AND b.sampletime >= NULL AND b.sampletime < NULL AND b.sampletid IN (140, 141, 142, 143) GROUP BY a.gvid; +DROP TABLE t1,t2; + +# +# Test of bigint comparision +# + +create table t1 ( A_Id bigint(20) NOT NULL default '0', A_UpdateBy char(10) NOT NULL default '', A_UpdateDate bigint(20) NOT NULL default '0', A_UpdateSerial int(11) NOT NULL default '0', other_types bigint(20) NOT NULL default '0', wss_type bigint(20) NOT NULL default '0'); +INSERT INTO t1 VALUES (102935998719055004,'brade',1029359987,2,102935229116544068,102935229216544093); +select wss_type from t1 where wss_type ='102935229216544106'; +select wss_type from t1 where wss_type ='102935229216544105'; +select wss_type from t1 where wss_type ='102935229216544104'; +select wss_type from t1 where wss_type ='102935229216544093'; +select wss_type from t1 where wss_type =102935229216544093; +drop table t1; +select 1+2,"aaaa",3.13*2.0 into @a,@b,@c; +select @a; +select @b; +select @c; + +# +# Test of removing redundant braces in the FROM part +# (We test each construct with the braced join to the left and right; +# the latter case used to cause a syntax errors.) +# + +create table t1 (a int not null auto_increment primary key); +insert into t1 values (); +insert into t1 values (); +insert into t1 values (); +# , +select * from (t1 as t2 left join t1 as t3 using (a)), t1; +select * from t1, (t1 as t2 left join t1 as t3 using (a)); +# stright_join +select * from (t1 as t2 left join t1 as t3 using (a)) straight_join t1; +select * from t1 straight_join (t1 as t2 left join t1 as t3 using (a)); +# inner join on +select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; +select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +# inner join using +select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a ); +select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) using ( a ); +# left [outer] join on +select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1; +select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +# left join using +select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a ); +select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a ); +# natural left join +select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1; +select * from t1 natural left join (t1 as t2 left join t1 as t3 using (a)); +# right join on +select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; +select * from t1 right join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +# right [outer] joing using +select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a ); +select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a ); +# natural right join +select * from (t1 as t2 left join t1 as t3 using (a)) natural right join t1; +select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a)); +# natural join +select * from t1 natural join (t1 as t2 left join t1 as t3 using (a)); +select * from (t1 as t2 left join t1 as t3 using (a)) natural join t1; +drop table t1; + +CREATE TABLE t1 ( aa char(2), id int(11) NOT NULL auto_increment, t2_id int(11) NOT NULL default '0', PRIMARY KEY (id), KEY replace_id (t2_id)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ("1",8264,2506),("2",8299,2517),("3",8301,2518),("4",8302,2519),("5",8303,2520),("6",8304,2521),("7",8305,2522); +CREATE TABLE t2 ( id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (2517), (2518), (2519), (2520), (2521), (2522); +select * from t1, t2 WHERE t1.t2_id = t2.id and t1.t2_id > 0 order by t1.id LIMIT 0, 5; +drop table t1,t2; + +# +# outer join, impossible on condition, where, and usable key for range +# +create table t1 (id1 int NOT NULL); +create table t2 (id2 int NOT NULL); +create table t3 (id3 int NOT NULL); +create table t4 (id4 int NOT NULL, id44 int NOT NULL, KEY (id4)); + +insert into t1 values (1); +insert into t1 values (2); +insert into t2 values (1); +insert into t4 values (1,1); + +explain select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3 +left join t4 on id3 = id4 where id2 = 1 or id4 = 1; +select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3 +left join t4 on id3 = id4 where id2 = 1 or id4 = 1; + +drop table t1,t2,t3,t4; +# +# Bug #2298 +# + +create table t1(s varchar(10) not null); +create table t2(s varchar(10) not null primary key); +create table t3(s varchar(10) not null primary key); +insert into t1 values ('one\t'), ('two\t'); +insert into t2 values ('one\r'), ('two\t'); +insert into t3 values ('one '), ('two\t'); +select * from t1 where s = 'one'; +select * from t2 where s = 'one'; +select * from t3 where s = 'one'; +select * from t1,t2 where t1.s = t2.s; +select * from t2,t3 where t2.s = t3.s; +drop table t1, t2, t3; + +# +# Bug #3759 +# Both queries should produce identical plans and results. +# +create table t1 (a integer, b integer, index(a), index(b)); +create table t2 (c integer, d integer, index(c), index(d)); +insert into t1 values (1,2), (2,2), (3,2), (4,2); +insert into t2 values (1,3), (2,3), (3,4), (4,4); +explain select * from t1 left join t2 on a=c where d in (4); +select * from t1 left join t2 on a=c where d in (4); +explain select * from t1 left join t2 on a=c where d = 4; +select * from t1 left join t2 on a=c where d = 4; +drop table t1, t2; + +# +# Covering index is mentioned in EXPLAIN output for const tables (bug #5333) +# + +CREATE TABLE t1 ( + i int(11) NOT NULL default '0', + c char(10) NOT NULL default '', + PRIMARY KEY (i), + UNIQUE KEY c (c) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (1,'a'); +INSERT INTO t1 VALUES (2,'b'); +INSERT INTO t1 VALUES (3,'c'); + +EXPLAIN SELECT i FROM t1 WHERE i=1; + +DROP TABLE t1; + +# +# Test case for bug 7520: a wrong cost of the index for a BLOB field +# + +CREATE TABLE t1 ( a BLOB, INDEX (a(20)) ); +CREATE TABLE t2 ( a BLOB, INDEX (a(20)) ); + +INSERT INTO t1 VALUES ('one'),('two'),('three'),('four'),('five'); +INSERT INTO t2 VALUES ('one'),('two'),('three'),('four'),('five'); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 USE INDEX (a) ON t1.a=t2.a; +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a; + +DROP TABLE t1, t2; + +# +# Test case for bug 7098: substitution of a constant for a string field +# + +CREATE TABLE t1 ( city char(30) ); +INSERT INTO t1 VALUES ('London'); +INSERT INTO t1 VALUES ('Paris'); + +SELECT * FROM t1 WHERE city='London'; +SELECT * FROM t1 WHERE city='london'; +EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; +SELECT * FROM t1 WHERE city='London' AND city='london'; +EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; + +DROP TABLE t1; + +# +# Bug#7425 inconsistent sort order on unsigned columns result of substraction +# + +create table t1 (a int(11) unsigned, b int(11) unsigned); +insert into t1 values (1,0), (1,1), (1,2); +select a-b from t1 order by 1; +select a-b , (a-b < 0) from t1 order by 1; +select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; +select cast((a - b) as unsigned) from t1 order by 1; +drop table t1; + + +# +# Bug#8733 server accepts malformed query (multiply mentioned distinct) +# +create table t1 (a int(11)); +select all all * from t1; +select distinct distinct * from t1; +--error 1221 +select all distinct * from t1; +--error 1221 +select distinct all * from t1; +drop table t1; + +# +# Test for BUG#10095 +# +CREATE TABLE t1 ( + kunde_intern_id int(10) unsigned NOT NULL default '0', + kunde_id int(10) unsigned NOT NULL default '0', + FK_firma_id int(10) unsigned NOT NULL default '0', + aktuell enum('Ja','Nein') NOT NULL default 'Ja', + vorname varchar(128) NOT NULL default '', + nachname varchar(128) NOT NULL default '', + geloescht enum('Ja','Nein') NOT NULL default 'Nein', + firma varchar(128) NOT NULL default '' +); + +INSERT INTO t1 VALUES + (3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), + (3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); + + +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 + WHERE + ( + ( + ( '' != '' AND firma LIKE CONCAT('%', '', '%')) + OR + (vorname LIKE CONCAT('%', 'Vorname1', '%') AND + nachname LIKE CONCAT('%', '1Nachname', '%') AND + 'Vorname1' != '' AND 'xxxx' != '') + ) + AND + ( + aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 + ) + ) + ; + +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, +geloescht FROM t1 + WHERE + ( + ( + aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 + ) + AND + ( + ( '' != '' AND firma LIKE CONCAT('%', '', '%') ) + OR + ( vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND +'xxxx' != '') + ) + ) + ; + +SELECT COUNT(*) FROM t1 WHERE +( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) +AND FK_firma_id = 2; + +drop table t1; + +# +# +# Test for Bug#8009, SELECT failed on bigint unsigned when using HEX +# + +CREATE TABLE t1 (b BIGINT(20) UNSIGNED NOT NULL, PRIMARY KEY (b)); +INSERT INTO t1 VALUES (0x8000000000000000); +SELECT b FROM t1 WHERE b=0x8000000000000000; +DROP TABLE t1; + +# +# IN with outer join condition (BUG#9393) +# +CREATE TABLE `t1` ( `gid` int(11) default NULL, `uid` int(11) default NULL); + +CREATE TABLE `t2` ( `ident` int(11) default NULL, `level` char(16) default NULL); +INSERT INTO `t2` VALUES (0,'READ'); + +CREATE TABLE `t3` ( `id` int(11) default NULL, `name` char(16) default NULL); +INSERT INTO `t3` VALUES (1,'fs'); + +select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid, t3.id, 0); + +drop table t1,t2,t3; + +# Test for BUG#11700 +CREATE TABLE t1 ( + acct_id int(11) NOT NULL default '0', + profile_id smallint(6) default NULL, + UNIQUE KEY t1$acct_id (acct_id), + KEY t1$profile_id (profile_id) +); +INSERT INTO t1 VALUES (132,17),(133,18); + +CREATE TABLE t2 ( + profile_id smallint(6) default NULL, + queue_id int(11) default NULL, + seq int(11) default NULL, + KEY t2$queue_id (queue_id) +); +INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1); + +CREATE TABLE t3 ( + id int(11) NOT NULL default '0', + qtype int(11) default NULL, + seq int(11) default NULL, + warn_lvl int(11) default NULL, + crit_lvl int(11) default NULL, + rr1 tinyint(4) NOT NULL default '0', + rr2 int(11) default NULL, + default_queue tinyint(4) NOT NULL default '0', + KEY t3$qtype (qtype), + KEY t3$id (id) +); + +INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0), + (36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0); + +SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q +WHERE + (pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND + (pq.queue_id = q.id) AND (q.rr1 <> 1); + +drop table t1,t2,t3; + +# +# Bug #11482 Wrongly applied optimization was erroneously rejecting valid +# rows +create table t1 (f1 int); +insert into t1 values (1),(NULL); +create table t2 (f2 int, f3 int, f4 int); +create index idx1 on t2 (f4); +insert into t2 values (1,2,3),(2,4,6); +select A.f2 from t1 left join t2 A on A.f2 = f1 where A.f3=(select min(f3) +from t2 C where A.f4 = C.f4) or A.f3 IS NULL; +drop table t1,t2; + +# +# Bug #11521 Negative integer keys incorrectly substituted for 0 during +# range analysis. + +create table t2 (a tinyint unsigned); +create index t2i on t2(a); +insert into t2 values (0), (254), (255); +explain select * from t2 where a > -1; +select * from t2 where a > -1; +drop table t2; + +# +# Bug #11745: SELECT ... FROM DUAL with WHERE condition +# + +CREATE TABLE t1 (a int, b int, c int); +INSERT INTO t1 + SELECT 50, 3, 3 FROM DUAL + WHERE NOT EXISTS + (SELECT * FROM t1 WHERE a = 50 AND b = 3); +SELECT * FROM t1; +INSERT INTO t1 + SELECT 50, 3, 3 FROM DUAL + WHERE NOT EXISTS + (SELECT * FROM t1 WHERE a = 50 AND b = 3); +select found_rows(); +SELECT * FROM t1; +select count(*) from t1; +select found_rows(); +select count(*) from t1 limit 2,3; +select found_rows(); # PBXT: returns 1 here (like InnoDB), MyISAM returns 0. Bug?! +select SQL_CALC_FOUND_ROWS count(*) from t1 limit 2,3; +select found_rows(); + +DROP TABLE t1; + +# +# Bug 7672 Unknown column error in order clause +# +CREATE TABLE t1 (a INT, b INT); +(SELECT a, b AS c FROM t1) ORDER BY c+1; +(SELECT a, b AS c FROM t1) ORDER BY b+1; +SELECT a, b AS c FROM t1 ORDER BY c+1; +SELECT a, b AS c FROM t1 ORDER BY b+1; +drop table t1; + +# +# Bug #13356 assertion failed in resolve_const_item() +# +create table t1(f1 int, f2 int); +create table t2(f3 int); +select f1 from t1,t2 where f1=f2 and (f1,f2) = ((1,1)); +select f1 from t1,t2 where f1=f2 and (f1,NULL) = ((1,1)); +select f1 from t1,t2 where f1=f2 and (f1,f2) = ((1,NULL)); +insert into t1 values(1,1),(2,null); +insert into t2 values(2); +select * from t1,t2 where f1=f3 and (f1,f2) = (2,null); +select * from t1,t2 where f1=f3 and (f1,f2) <=> (2,null); +drop table t1,t2; + +# +# Bug #13535 +# +create table t1 (f1 int not null auto_increment primary key, f2 varchar(10)); +create table t11 like t1; +insert into t1 values(1,""),(2,""); +--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X +show table status like 't1%'; +select 123 as a from t1 where f1 is null; +drop table t1,t11; + +# +# Bug #3874 (function in GROUP and LEFT JOIN) +# + +CREATE TABLE t1 ( a INT NOT NULL, b INT NOT NULL, UNIQUE idx (a,b) ); +INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4); +CREATE TABLE t2 ( a INT NOT NULL, b INT NOT NULL, e INT ); +INSERT INTO t2 VALUES ( 1,10,1), (1,10,2), (1,11,1), (1,11,2), (1,2,1), (1,2,2),(1,2,3); +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY a, b, c; +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY t1.a, t1.b, c; +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2 LEFT JOIN +t1 ON t2.a = t1.a AND t2.b = t1.b GROUP BY t2.a, t2.b, c; +SELECT t2.a, t2.b, IF(t1.b IS NULL,'',e) AS c, COUNT(*) AS d FROM t2,t1 +WHERE t2.a = t1.a AND t2.b = t1.b GROUP BY a, b, c; +DROP TABLE IF EXISTS t1, t2; + +# +# Bug #13855 select distinct with group by caused server crash +# +create table t1 (f1 int primary key, f2 int); +create table t2 (f3 int, f4 int, primary key(f3,f4)); +insert into t1 values (1,1); +insert into t2 values (1,1),(1,2); +select distinct count(f2) >0 from t1 left join t2 on f1=f3 group by f1; +drop table t1,t2; + +# +# Bug #14482 Server crash when subselecting from the same table +# +create table t1 (f1 int,f2 int); +insert into t1 values(1,1); +create table t2 (f3 int, f4 int, primary key(f3,f4)); +insert into t2 values(1,1); +select * from t1 where f1 in (select f3 from t2 where (f3,f4)= (select f3,f4 from t2)); +drop table t1,t2; + +# +# Bug #4981: 4.x and 5.x produce non-optimal execution path, 3.23 regression test failure +# +CREATE TABLE t1(a int, b int, c int, KEY b(b), KEY c(c)); +insert into t1 values (1,0,0),(2,0,0); +CREATE TABLE t2 (a int, b varchar(2), c varchar(2), PRIMARY KEY(a)); +insert into t2 values (1,'',''), (2,'',''); +CREATE TABLE t3 (a int, b int, PRIMARY KEY (a,b), KEY a (a), KEY b (b)); +insert into t3 values (1,1),(1,2); +# must have "range checked" for t2 +explain select straight_join DISTINCT t2.a,t2.b, t1.c from t1, t3, t2 + where (t1.c=t2.a or (t1.c=t3.a and t2.a=t3.b)) and t1.b=556476786 and + t2.b like '%%' order by t2.b limit 0,1; +DROP TABLE t1,t2,t3; + +# +# Bug #17873: confusing error message when IGNORE INDEX refers a column name +# + +CREATE TABLE t1 (a int, INDEX idx(a)); +INSERT INTO t1 VALUES (2), (3), (1); + +EXPLAIN SELECT * FROM t1 IGNORE INDEX (idx); +--error 1176 +EXPLAIN SELECT * FROM t1 IGNORE INDEX (a); +--error 1176 +EXPLAIN SELECT * FROM t1 FORCE INDEX (a); + +DROP TABLE t1; + +# +# Bug #21019: First result of SELECT COUNT(*) different than consecutive runs +# +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (4,10); + +CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); +INSERT INTO t2 VALUES (1,NULL), (2,10); +ALTER TABLE t1 ENABLE KEYS; + +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +DROP TABLE IF EXISTS t1,t2; + +# +# Bug #20954 "avg(keyval) retuns 0.38 but max(keyval) returns an empty set" +# +--disable_ps_protocol +CREATE TABLE t1 (key1 float default NULL, UNIQUE KEY key1 (key1)); +CREATE TABLE t2 (key2 float default NULL, UNIQUE KEY key2 (key2)); +INSERT INTO t1 VALUES (0.3762),(0.3845),(0.6158),(0.7941); +INSERT INTO t2 VALUES (1.3762),(1.3845),(1.6158),(1.7941); + +explain select max(key1) from t1 where key1 <= 0.6158; +explain select max(key2) from t2 where key2 <= 1.6158; +explain select min(key1) from t1 where key1 >= 0.3762; +explain select min(key2) from t2 where key2 >= 1.3762; +explain select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; + +select max(key1) from t1 where key1 <= 0.6158; +select max(key2) from t2 where key2 <= 1.6158; +select min(key1) from t1 where key1 >= 0.3762; +select min(key2) from t2 where key2 >= 1.3762; +select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; + +DROP TABLE t1,t2; +--enable_ps_protocol + +# +# Bug #18759 "Incorrect string to numeric conversion" +# +# This test is here so that the behavior will not be changed to 4.1 +# and not to 5.0 either. In 4.1 and 5.0 sending an integer as a string +# will be converted internally to real (double) value and it is not +# as accurate as bigint (longlong) for integers. Thus the results may +# vary. In 5.1 internally it is decimal, which is a string type and +# will be more accurate. Due to rather big changes needed to fix this +# in 4.1 or 5.0 it is not desired to do it in the stable versions. +# +# This test is here only to make sure that behavior is not changed in +# 4.1 and 5.0 +# +CREATE TABLE t1 (i BIGINT UNSIGNED NOT NULL); +INSERT INTO t1 VALUES (10); +SELECT i='1e+01',i=1e+01, i in (1e+01,1e+01), i in ('1e+01','1e+01') FROM t1; +DROP TABLE t1; + +# +# Bug #22533: storing large hex strings +# + +create table t1(a bigint unsigned, b bigint); +insert into t1 values (0xfffffffffffffffff, 0xfffffffffffffffff), + (0x10000000000000000, 0x10000000000000000), + (0x8fffffffffffffff, 0x8fffffffffffffff); +select hex(a), hex(b) from t1; +drop table t1; + +--echo End of 4.1 tests + +# +# Test for bug #6474 +# + +CREATE TABLE t1 ( +K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', +K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000', +F2I4 int(11) NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +INSERT INTO t1 VALUES +('W%RT', '0100', 1), +('W-RT', '0100', 1), +('WART', '0100', 1), +('WART', '0200', 1), +('WERT', '0100', 2), +('WORT','0200', 2), +('WT', '0100', 2), +('W_RT', '0100', 2), +('WaRT', '0100', 3), +('WART', '0300', 3), +('WRT' , '0400', 3), +('WURM', '0500', 3), +('W%T', '0600', 4), +('WA%T', '0700', 4), +('WA_T', '0800', 4); + +SELECT K2C4, K4N4, F2I4 FROM t1 + WHERE K2C4 = 'WART' AND + (F2I4 = 2 AND K2C4 = 'WART' OR (F2I4 = 2 OR K4N4 = '0200')); +SELECT K2C4, K4N4, F2I4 FROM t1 + WHERE K2C4 = 'WART' AND (K2C4 = 'WART' OR K4N4 = '0200'); +DROP TABLE t1; + +# +# Bug#8670 +# +create table t1 (a int, b int); +create table t2 like t1; +select t1.a from (t1 inner join t2 on t1.a=t2.a) where t2.a=1; +select t1.a from ((t1 inner join t2 on t1.a=t2.a)) where t2.a=1; +select x.a, y.a, z.a from ( (t1 x inner join t2 y on x.a=y.a) inner join t2 z on y.a=z.a) WHERE x.a=1; +drop table t1,t2; + +# +# Bug#9820 +# + +create table t1 (s1 varchar(5)); +insert into t1 values ('Wall'); +select min(s1) from t1 group by s1 with rollup; +drop table t1; + +# +# Bug#9799 +# + +create table t1 (s1 int) engine=myisam; +insert into t1 values (0); +select avg(distinct s1) from t1 group by s1 with rollup; +drop table t1; + +# +# Bug#9800 +# + +create table t1 (s1 int); +insert into t1 values (null),(1); +select distinct avg(s1) as x from t1 group by s1 with rollup; +drop table t1; + + +# +# Test for bug #10084: STRAIGHT_JOIN with ON expression +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +INSERT INTO t2 VALUES (2), (4), (6); + +SELECT t1.a FROM t1 STRAIGHT_JOIN t2 ON t1.a=t2.a; + +EXPLAIN SELECT t1.a FROM t1 STRAIGHT_JOIN t2 ON t1.a=t2.a; +EXPLAIN SELECT t1.a FROM t1 INNER JOIN t2 ON t1.a=t2.a; + +DROP TABLE t1,t2; + +# +# Bug #10650 +# + +select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; + +# +# Bug #11398 Bug in field_conv() results in wrong result of join with index +# +create table t1 (f1 varchar(6) default NULL, f2 int(6) primary key not null); +create table t2 (f3 varchar(5) not null, f4 varchar(5) not null, UNIQUE KEY UKEY (f3,f4)); +insert into t1 values (" 2", 2); +insert into t2 values (" 2", " one "),(" 2", " two "); +select * from t1 left join t2 on f1 = f3; +drop table t1,t2; + +# +# Bug #6558 Views: CREATE VIEW fails with JOIN ... USING +# + +create table t1 (empnum smallint, grp int); +create table t2 (empnum int, name char(5)); +insert into t1 values(1,1); +insert into t2 values(1,'bob'); +create view v1 as select * from t2 inner join t1 using (empnum); +select * from v1; +drop table t1,t2; +drop view v1; + +# +# Bug #10646 Columns included in the join between two tables are ambigious +# in the select +# + +create table t1 (pk int primary key, b int); +create table t2 (pk int primary key, c int); +select pk from t1 inner join t2 using (pk); +drop table t1,t2; + +# +# Bug #10972 Natural join of view and underlying table gives wrong result +# + +create table t1 (s1 int, s2 char(5), s3 decimal(10)); +create view v1 as select s1, s2, 'x' as s3 from t1; +select * from t1 natural join v1; +insert into t1 values (1,'x',5); +select * from t1 natural join v1; +drop table t1; +drop view v1; + +# +# Bug #6276 A SELECT that does a NATURAL OUTER JOIN without common +# columns crashes server because of empty ON condition +# + +create table t1(a1 int); +create table t2(a2 int); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +create view v2 (c) as select a1 from t1; + +select * from t1 natural left join t2; +select * from t1 natural right join t2; + +select * from v2 natural left join t2; +select * from v2 natural right join t2; + +drop table t1, t2; +drop view v2; + + +# +# Bug #4789 Incosistent results of more than 2-way natural joins due to +# incorrect transformation to join ... on. +# + +create table t1 (a int(10), t1_val int(10)); +create table t2 (b int(10), t2_val int(10)); +create table t3 (a int(10), b int(10)); +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(2,2),(3,3); +insert into t3 values (1,1),(2,1),(3,1),(4,1); +# the following two queries must return the same result +select * from t1 natural join t2 natural join t3; +select * from t1 natural join t3 natural join t2; +drop table t1, t2, t3; + + +# +# Bug #12841: Server crash on DO IFNULL(NULL,NULL) +# +# (testing returning of int, decimal, real, string) +DO IFNULL(NULL, NULL); +SELECT CAST(IFNULL(NULL, NULL) AS DECIMAL); +SELECT ABS(IFNULL(NULL, NULL)); +SELECT IFNULL(NULL, NULL); + +# +# BUG #12595 (ESCAPE must be exactly one) +# +SET @OLD_SQL_MODE12595=@@SQL_MODE, @@SQL_MODE=''; +SHOW LOCAL VARIABLES LIKE 'SQL_MODE'; + +CREATE TABLE BUG_12595(a varchar(100)); +INSERT INTO BUG_12595 VALUES ('hakan%'), ('hakank'), ("ha%an"); +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%'; +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +# this should work when sql_mode is not NO_BACKSLASH_ESCAPES +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan%' ESCAPE ''; +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%' ESCAPE ''; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE 0x5c; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha%%an' ESCAPE '%'; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE '\\'; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha|%an' ESCAPE '|'; + +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +SHOW LOCAL VARIABLES LIKE 'SQL_MODE'; +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%'; +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan*%' ESCAPE '*'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan**%' ESCAPE '**'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\%' ESCAPE '\\'; +#this gives an error when NO_BACKSLASH_ESCAPES is set +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan%' ESCAPE ''; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha\%an' ESCAPE 0x5c; +SELECT * FROM BUG_12595 WHERE a LIKE 'ha|%an' ESCAPE '|'; +-- error 1210 +SELECT * FROM BUG_12595 WHERE a LIKE 'hakan\n%' ESCAPE '\n'; + +SET @@SQL_MODE=@OLD_SQL_MODE12595; +DROP TABLE BUG_12595; + +# +# Bug #6495 Illogical requirement for column qualification in NATURAL join +# + +create table t1 (a char(1)); +create table t2 (a char(1)); +insert into t1 values ('a'),('b'),('c'); +insert into t2 values ('b'),('c'),('d'); +select a from t1 natural join t2; +select * from t1 natural join t2 where a = 'b'; +drop table t1, t2; + +# +# Bug #12977 Compare table names with qualifying field tables only +# for base tables, search all nested join operands of natural joins. +# + +CREATE TABLE t1 (`id` TINYINT); +CREATE TABLE t2 (`id` TINYINT); +CREATE TABLE t3 (`id` TINYINT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +-- error 1052 +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.notacolumn=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT id,t3.id FROM (t1 JOIN t2 ON (t2.id=t1.id)) LEFT JOIN t3 USING (id); + +drop table t1, t2, t3; + +# +# Bug #13067 JOIN xxx USING is case sensitive +# + +create table t1 (a int(10),b int(10)); +create table t2 (a int(10),b int(10)); +insert into t1 values (1,10),(2,20),(3,30); +insert into t2 values (1,10); +# both queries should produce the same result +select * from t1 inner join t2 using (A); +select * from t1 inner join t2 using (a); +drop table t1, t2; + +# +# Bug #12943 Incorrect nesting of [INNER| CROSS] JOIN due to unspecified +# associativity in the parser. +# + +create table t1 (a int, c int); +create table t2 (b int); +create table t3 (b int, a int); +create table t4 (c int); +insert into t1 values (1,1); +insert into t2 values (1); +insert into t3 values (1,1); +insert into t4 values (1); + +select * from t1 join t2 join t3 on (t2.b = t3.b and t1.a = t3.a); +# Notice that ',' has lower priority than 'join', thus we have that: +# t1, t2 join t3 <==> t1, (t2 join t3). +-- error 1054 +select * from t1, t2 join t3 on (t2.b = t3.b and t1.a = t3.a); +select * from t1 join t2 join t3 join t4 on (t1.a = t4.c and t2.b = t4.c); +select * from t1 join t2 join t4 using (c); +drop table t1, t2, t3, t4; + +# +# Bug #12291 Table wasn't reinited for index scan after sequential scan +# +create table t1(x int, y int); +create table t2(x int, y int); +create table t3(x int, primary key(x)); +insert into t1 values (1, 1), (2, 1), (3, 1), (4, 3), (5, 6), (6, 6); +insert into t2 values (1, 1), (2, 1), (3, 3), (4, 6), (5, 6); +insert into t3 values (1), (2), (3), (4), (5); +select t1.x, t3.x from t1, t2, t3 where t1.x = t2.x and t3.x >= t1.y and t3.x <= t2.y; +drop table t1,t2,t3; + +# +# Bug #13127 LEFT JOIN against a VIEW returns NULL instead of correct value +# + +create table t1 (id char(16) not null default '', primary key (id)); +insert into t1 values ('100'),('101'),('102'); +create table t2 (id char(16) default null); +insert into t2 values (1); +create view v1 as select t1.id from t1; +create view v2 as select t2.id from t2; +create view v3 as select (t1.id+2) as id from t1 natural left join t2; + +# all queries must return the same result +select t1.id from t1 left join v2 using (id); +select t1.id from v2 right join t1 using (id); +select t1.id from t1 left join v3 using (id); +select * from t1 left join v2 using (id); +select * from v2 right join t1 using (id); +select * from t1 left join v3 using (id); + +select v1.id from v1 left join v2 using (id); +select v1.id from v2 right join v1 using (id); +select v1.id from v1 left join v3 using (id); +select * from v1 left join v2 using (id); +select * from v2 right join v1 using (id); +select * from v1 left join v3 using (id); + +drop table t1, t2; +drop view v1, v2, v3; + +# +# Bug #13597 Column in ON condition not resolved if references a table in +# nested right join. +# + +create table t1 (id int(11) not null default '0'); +insert into t1 values (123),(191),(192); +create table t2 (id char(16) character set utf8 not null); +insert into t2 values ('58013'),('58014'),('58015'),('58016'); +create table t3 (a_id int(11) not null, b_id char(16) character set utf8); +insert into t3 values (123,null),(123,null),(123,null),(123,null),(123,null),(123,'58013'); + +# both queries are equivalent +select count(*) +from t1 inner join (t3 left join t2 on t2.id = t3.b_id) on t1.id = t3.a_id; + +select count(*) +from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; + +drop table t1,t2,t3; + +# +# Bug #13832 Incorrect parse order of join productions due to unspecified +# operator priorities results in incorrect join tree. +# + +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +select * from t1 join t2 join t3 on (t1.a=t3.c); +select * from t1 join t2 left join t3 on (t1.a=t3.c); +select * from t1 join t2 right join t3 on (t1.a=t3.c); +select * from t1 join t2 straight_join t3 on (t1.a=t3.c); +drop table t1, t2 ,t3; + +# +# Bug #14093 Query takes a lot of time when date format is not valid +# fix optimizes execution. so here we just check that returned set is +# correct. +create table t1(f1 int, f2 date); +insert into t1 values(1,'2005-01-01'),(2,'2005-09-01'),(3,'2005-09-30'), + (4,'2005-10-01'),(5,'2005-12-30'); +# should return all records +select * from t1 where f2 >= 0; +select * from t1 where f2 >= '0000-00-00'; +# should return 4,5 +select * from t1 where f2 >= '2005-09-31'; +select * from t1 where f2 >= '2005-09-3a'; +# should return 1,2,3 +select * from t1 where f2 <= '2005-09-31'; +select * from t1 where f2 <= '2005-09-3a'; +drop table t1; + +# +# Bug ##14662 ORDER BY on column of a view, with an alias of the same +# column causes ambiguous +# + +create table t1 (f1 int, f2 int); +insert into t1 values (1, 30), (2, 20), (3, 10); +create algorithm=merge view v1 as select f1, f2 from t1; +create algorithm=merge view v2 (f2, f1) as select f1, f2 from t1; +create algorithm=merge view v3 as select t1.f1 as f2, t1.f2 as f1 from t1; +select t1.f1 as x1, f1 from t1 order by t1.f1; +select v1.f1 as x1, f1 from v1 order by v1.f1; +select v2.f1 as x1, f1 from v2 order by v2.f1; +select v3.f1 as x1, f1 from v3 order by v3.f1; +select f1, f2, v1.f1 as x1 from v1 order by v1.f1; +select f1, f2, v2.f1 as x1 from v2 order by v2.f1; +select f1, f2, v3.f1 as x1 from v3 order by v3.f1; +drop table t1; +drop view v1, v2, v3; + +# +# Bug #15106: lost equality predicate of the form field=const in a join query +# + +CREATE TABLE t1(key_a int4 NOT NULL, optimus varchar(32), PRIMARY KEY(key_a)); +CREATE TABLE t2(key_a int4 NOT NULL, prime varchar(32), PRIMARY KEY(key_a)); +CREATE table t3(key_a int4 NOT NULL, key_b int4 NOT NULL, foo varchar(32), + PRIMARY KEY(key_a,key_b)); + +INSERT INTO t1 VALUES (0,''); +INSERT INTO t1 VALUES (1,'i'); +INSERT INTO t1 VALUES (2,'j'); +INSERT INTO t1 VALUES (3,'k'); + +INSERT INTO t2 VALUES (1,'r'); +INSERT INTO t2 VALUES (2,'s'); +INSERT INTO t2 VALUES (3,'t'); + +INSERT INTO t3 VALUES (1,5,'x'); +INSERT INTO t3 VALUES (1,6,'y'); +INSERT INTO t3 VALUES (2,5,'xx'); +INSERT INTO t3 VALUES (2,6,'yy'); +INSERT INTO t3 VALUES (2,7,'zz'); +INSERT INTO t3 VALUES (3,5,'xxx'); + +SELECT t2.key_a,foo + FROM t1 INNER JOIN t2 ON t1.key_a = t2.key_a + INNER JOIN t3 ON t1.key_a = t3.key_a + WHERE t2.key_a=2 and key_b=5; +EXPLAIN SELECT t2.key_a,foo + FROM t1 INNER JOIN t2 ON t1.key_a = t2.key_a + INNER JOIN t3 ON t1.key_a = t3.key_a + WHERE t2.key_a=2 and key_b=5; + +SELECT t2.key_a,foo + FROM t1 INNER JOIN t2 ON t2.key_a = t1.key_a + INNER JOIN t3 ON t1.key_a = t3.key_a + WHERE t2.key_a=2 and key_b=5; +EXPLAIN SELECT t2.key_a,foo + FROM t1 INNER JOIN t2 ON t2.key_a = t1.key_a + INNER JOIN t3 ON t1.key_a = t3.key_a + WHERE t2.key_a=2 and key_b=5; + +DROP TABLE t1,t2,t3; + +# +# Bug#15347 Wrong result of subselect when records cache and set functions +# are involved +# +create table t1 (f1 int); +insert into t1 values(1),(2); +create table t2 (f2 int, f3 int, key(f2)); +insert into t2 values(1,1),(2,2); +create table t3 (f4 int not null); +insert into t3 values (2),(2),(2); +select f1,(select count(*) from t2,t3 where f2=f1 and f3=f4) as count from t1; +drop table t1,t2,t3; + +# +# Bug #15633 Evaluation of Item_equal for non-const table caused wrong +# select result +# +create table t1 (f1 int unique); +create table t2 (f2 int unique); +create table t3 (f3 int unique); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +insert into t3 values(1),(NULL); +select * from t3 where f3 is null; +select t2.f2 from t1 left join t2 on f1=f2 join t3 on f1=f3 where f1=1; +drop table t1,t2,t3; + +# +# Bug#15268 Unchecked null value caused server crash +# +create table t1(f1 char, f2 char not null); +insert into t1 values(null,'a'); +create table t2 (f2 char not null); +insert into t2 values('b'); +select * from t1 left join t2 on f1=t2.f2 where t1.f2='a'; +drop table t1,t2; + +# +# Bug#15538 unchecked table absense caused server crash. +# +--error 1064 +select * from (select * left join t on f1=f2) tt; + +# +# Bug #16504: re-evaluation of Item_equal object after reading const table +# + +CREATE TABLE t1 (sku int PRIMARY KEY, pr int); +CREATE TABLE t2 (sku int PRIMARY KEY, sppr int, name varchar(255)); + +INSERT INTO t1 VALUES + (10, 10), (20, 10), (30, 20), (40, 30), (50, 10), (60, 10); + +INSERT INTO t2 VALUES + (10, 10, 'aaa'), (20, 10, 'bbb'), (30, 10, 'ccc'), (40, 20, 'ddd'), + (50, 10, 'eee'), (60, 20, 'fff'), (70, 20, 'ggg'), (80, 30, 'hhh'); + +SELECT t2.sku, t2.sppr, t2.name, t1.sku, t1.pr + FROM t2, t1 WHERE t2.sku=20 AND (t2.sku=t1.sku OR t2.sppr=t1.sku); +EXPLAIN +SELECT t2.sku, t2.sppr, t2.name, t1.sku, t1.pr + FROM t2, t1 WHERE t2.sku=20 AND (t2.sku=t1.sku OR t2.sppr=t1.sku); + + +DROP TABLE t1,t2; + +# +# Bug#18712: Truncation problem (needs just documenting and test +# cases to prevent fixing this accidently. It is intended behaviour) +# + +CREATE TABLE t1 (i TINYINT UNSIGNED NOT NULL); +INSERT t1 SET i = 0; +UPDATE t1 SET i = -1; +SELECT * FROM t1; +UPDATE t1 SET i = CAST(i - 1 AS SIGNED); +SELECT * FROM t1; +UPDATE t1 SET i = i - 1; +SELECT * FROM t1; +DROP TABLE t1; + +# BUG#17379 + +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, b int, c int, e int, primary key(a,b,c)); +insert into t2 select A.a, B.a, C.a, C.a from t1 A, t1 B, t1 C; +analyze table t2; +select 'In next EXPLAIN, B.rows must be exactly 10:' Z; + +explain select * from t2 A, t2 B where A.a=5 and A.b=5 and A.C<5 + and B.a=5 and B.b=A.e and (B.b =1 or B.b = 3 or B.b=5); +drop table t1, t2; + +# +#Bug #18940: selection of optimal execution plan caused by equality +# propagation (the bug was fixed by the patch for bug #17379) + +CREATE TABLE t1 (a int PRIMARY KEY, b int, INDEX(b)); +INSERT INTO t1 VALUES (1, 3), (9,4), (7,5), (4,5), (6,2), + (3,1), (5,1), (8,9), (2,2), (0,9); + +CREATE TABLE t2 (c int, d int, f int, INDEX(c,f)); +INSERT INTO t2 VALUES + (1,0,0), (1,0,1), (2,0,0), (2,0,1), (3,0,0), (4,0,1), + (5,0,0), (5,0,1), (6,0,0), (0,0,1), (7,0,0), (7,0,1), + (0,0,0), (0,0,1), (8,0,0), (8,0,1), (9,0,0), (9,0,1); + +EXPLAIN +SELECT a, c, d, f FROM t1,t2 WHERE a=c AND b BETWEEN 4 AND 6; +EXPLAIN +SELECT a, c, d, f FROM t1,t2 WHERE a=c AND b BETWEEN 4 AND 6 AND a > 0; + +DROP TABLE t1, t2; + +# +# Bug #18895: BIT values cause joins to fail +# +create table t1 ( + a int unsigned not null auto_increment primary key, + b bit not null, + c bit not null +); + +create table t2 ( + a int unsigned not null auto_increment primary key, + b bit not null, + c int unsigned not null, + d varchar(50) +); + +insert into t1 (b,c) values (0,1), (0,1); +insert into t2 (b,c) values (0,1); + +# Row 1 should succeed. Row 2 should fail. Both fail. +select t1.a, t1.b + 0, t1.c + 0, t2.a, t2.b + 0, t2.c, t2.d +from t1 left outer join t2 on t1.a = t2.c and t2.b <> 1 +where t1.b <> 1 order by t1.a; + +drop table t1,t2; + +# +# Bug #20569: Garbage in DECIMAL results from some mathematical functions +# +SELECT 0.9888889889 * 1.011111411911; + +# +# Bug #10977: No warning issued if a column name is truncated +# +prepare stmt from 'select 1 as " a "'; +execute stmt; + +# +# Bug #21390: wrong estimate of rows after elimination of const tables +# + +CREATE TABLE t1 (a int NOT NULL PRIMARY KEY, b int NOT NULL); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); + +CREATE TABLE t2 (c int NOT NULL, INDEX idx(c)); +INSERT INTO t2 VALUES + (1), (1), (1), (1), (1), (1), (1), (1), + (2), (2), (2), (2), + (3), (3), + (4); + +EXPLAIN SELECT b FROM t1, t2 WHERE b=c AND a=1; +EXPLAIN SELECT b FROM t1, t2 WHERE b=c AND a=4; + +DROP TABLE t1, t2; + +# +# No matches for a join after substitution of a const table +# + +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a int); +INSERT INTO t1 VALUES (1,2), (2,NULL), (3,2); + +CREATE TABLE t2 (b int, c INT, INDEX idx1(b)); +INSERT INTO t2 VALUES (2,1), (3,2); + +CREATE TABLE t3 (d int, e int, INDEX idx1(d)); +INSERT INTO t3 VALUES (2,10), (2,20), (1,30), (2,40), (2,50); + +EXPLAIN +SELECT * FROM t1 LEFT JOIN t2 ON t2.b=t1.a INNER JOIN t3 ON t3.d=t1.id + WHERE t1.id=2; +SELECT * FROM t1 LEFT JOIN t2 ON t2.b=t1.a INNER JOIN t3 ON t3.d=t1.id + WHERE t1.id=2; + +DROP TABLE t1,t2,t3; + +# +# Bug#20503: Server crash due to the ORDER clause isn't taken into account +# while space allocation +# +create table t1 (c1 varchar(1), c2 int, c3 int, c4 int, c5 int, c6 int, +c7 int, c8 int, c9 int, fulltext key (`c1`)) engine=myisam; # PBXT: Fulltext requires MyISAM +select distinct match (`c1`) against ('z') , c2, c3, c4,c5, c6,c7, c8 + from t1 where c9=1 order by c2, c2; +drop table t1; + +# +# Bug #22735: no equality propagation for BETWEEN and IN with STRING arguments +# + +CREATE TABLE t1 (pk varchar(10) PRIMARY KEY, fk varchar(16)); +CREATE TABLE t2 (pk varchar(16) PRIMARY KEY, fk varchar(10)); + +INSERT INTO t1 VALUES + ('d','dddd'), ('i','iii'), ('a','aa'), ('b','bb'), ('g','gg'), + ('e','eee'), ('c','cccc'), ('h','hhh'), ('j','jjj'), ('f','fff'); +INSERT INTO t2 VALUES + ('jjj', 'j'), ('cc','c'), ('ccc','c'), ('aaa', 'a'), ('jjjj','j'), + ('hhh','h'), ('gg','g'), ('fff','f'), ('ee','e'), ('ffff','f'), + ('bbb','b'), ('ff','f'), ('cccc','c'), ('dddd','d'), ('jj','j'), + ('aaaa','a'), ('bb','b'), ('eeee','e'), ('aa','a'), ('hh','h'); + +EXPLAIN SELECT t2.* + FROM t1 JOIN t2 ON t2.fk=t1.pk + WHERE t2.fk < 'c' AND t2.pk=t1.fk; +EXPLAIN SELECT t2.* + FROM t1 JOIN t2 ON t2.fk=t1.pk + WHERE t2.fk BETWEEN 'a' AND 'b' AND t2.pk=t1.fk; +EXPLAIN SELECT t2.* + FROM t1 JOIN t2 ON t2.fk=t1.pk + WHERE t2.fk IN ('a','b') AND t2.pk=t1.fk; + +DROP TABLE t1,t2; + +# +# Bug #22367: Optimizer uses ref join type instead of eq_ref for simple +# join on strings +# +CREATE TABLE t1 (a int, b varchar(20) NOT NULL, PRIMARY KEY(a)); +CREATE TABLE t2 (a int, b varchar(20) NOT NULL, + PRIMARY KEY (a), UNIQUE KEY (b)); +INSERT INTO t1 VALUES (1,'a'),(2,'b'),(3,'c'); +INSERT INTO t2 VALUES (1,'a'),(2,'b'),(3,'c'); + +EXPLAIN SELECT t1.a FROM t1 LEFT JOIN t2 ON t2.b=t1.b WHERE t1.a=3; + +DROP TABLE t1,t2; + +# +# Bug #19579: predicates that become sargable after reading const tables +# are not taken into account by optimizer +# + +CREATE TABLE t1(id int PRIMARY KEY, b int, e int); +CREATE TABLE t2(i int, a int, INDEX si(i), INDEX ai(a)); +CREATE TABLE t3(a int PRIMARY KEY, c char(4), INDEX ci(c)); + +INSERT INTO t1 VALUES + (1,10,19), (2,20,22), (4,41,42), (9,93,95), (7, 77,79), + (6,63,67), (5,55,58), (3,38,39), (8,81,89); +INSERT INTO t2 VALUES + (21,210), (41,410), (82,820), (83,830), (84,840), + (65,650), (51,510), (37,370), (94,940), (76,760), + (22,220), (33,330), (40,400), (95,950), (38,380), + (67,670), (88,880), (57,570), (96,960), (97,970); +INSERT INTO t3 VALUES + (210,'bb'), (950,'ii'), (400,'ab'), (500,'ee'), (220,'gg'), + (440,'gg'), (310,'eg'), (380,'ee'), (840,'bb'), (830,'ff'), + (230,'aa'), (960,'ii'), (410,'aa'), (510,'ee'), (290,'bb'), + (450,'gg'), (320,'dd'), (390,'hh'), (850,'jj'), (860,'ff'); + +EXPLAIN +SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3 + WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND + t3.a=t2.a AND t3.c IN ('bb','ee'); +EXPLAIN +SELECT t3.a FROM t1,t2,t3 + WHERE t1.id = 8 AND t2.i BETWEEN t1.b AND t1.e AND + t3.a=t2.a AND t3.c IN ('bb','ee') ; + +EXPLAIN +SELECT t3.a FROM t1,t2 FORCE INDEX (si),t3 + WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND + t3.c IN ('bb','ee'); +EXPLAIN +SELECT t3.a FROM t1,t2,t3 + WHERE t1.id = 8 AND (t2.i=t1.b OR t2.i=t1.e) AND t3.a=t2.a AND + t3.c IN ('bb','ee'); + +DROP TABLE t1,t2,t3; + +# +# Bug#6298: LIMIT #, -1 no longer works to set start with no end limit +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1(a int); +INSERT into t1 values (1), (2), (3); + +# LIMIT N, -1 was accepted by accident in 4.0, but was not intended. +# This test verifies that this illegal construct is now properly detected. + +--error ER_PARSE_ERROR +SELECT * FROM t1 LIMIT 2, -1; + +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/select_found.test b/mysql-test/suite/pbxt/t/select_found.test new file mode 100644 index 00000000000..23813f6d883 --- /dev/null +++ b/mysql-test/suite/pbxt/t/select_found.test @@ -0,0 +1,198 @@ +# +# Testing of found_rows() +# +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1 (a int not null auto_increment, b int not null, primary key(a)); +insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9); +select SQL_CALC_FOUND_ROWS * from t1; +select found_rows(); +select SQL_CALC_FOUND_ROWS * from t1 limit 1; +select found_rows(); +select SQL_BUFFER_RESULT SQL_CALC_FOUND_ROWS * from t1 limit 1; +select found_rows(); +select SQL_CALC_FOUND_ROWS * from t1 order by b desc limit 1; +select found_rows(); +select SQL_CALC_FOUND_ROWS distinct b from t1 limit 1; +select found_rows(); +select SQL_CALC_FOUND_ROWS b,count(*) as c from t1 group by b order by c desc limit 1; +select found_rows(); +select SQL_CALC_FOUND_ROWS * from t1 left join t1 as t2 on (t1.b=t2.a) limit 2,1; +select found_rows(); +drop table t1; + +# +# Test SQL_CALC_FOUND_ROWS optimization when used with one table and filesort +# + +create table t1 (a int not null primary key); +insert into t1 values (1),(2),(3),(4),(5); +select sql_calc_found_rows a from t1 where a in (1,2,3) order by a desc limit 0,2; +select FOUND_ROWS(); +select sql_calc_found_rows a from t1 where a in (1,2,3) order by a+2 desc limit 0,2; +select FOUND_ROWS(); +drop table t1; + +# +# Test of SQL_CALC_FOUND_ROWS with DISTINCT +# + +CREATE TABLE t1 ( +`id` smallint(5) unsigned NOT NULL auto_increment, +`kid` smallint(5) unsigned NOT NULL default '0', +PRIMARY KEY (`id`), +KEY `kid` (`kid`) +); + +CREATE TABLE t2 ( + id smallint(5) unsigned NOT NULL auto_increment, + name varchar(50) NOT NULL default '', + email varchar(50) NOT NULL default '', + PRIMARY KEY (id), + UNIQUE KEY e_n (email,name) +); + +disable_query_log; +let $1=200; +let $2=0; +while ($1) +{ + inc $2; + eval INSERT INTO t2 VALUES ($2,'name$2','email$2'); + dec $1; +} +enable_query_log; + +EXPLAIN SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; +SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; +SELECT FOUND_ROWS(); + +SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL order by email LIMIT 10; +SELECT FOUND_ROWS(); + +SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; +SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL ORDER BY email LIMIT 10; +INSERT INTO `t1` (`id`, `kid`) VALUES ('0', '150'); + +SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; +SELECT FOUND_ROWS(); + +drop table t1,t2; + +# +# Test bug when using range optimization +# + +CREATE TABLE `t1` ( + `titre` char(80) NOT NULL default '', + `numeropost` mediumint(8) unsigned NOT NULL auto_increment, + `maxnumrep` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`numeropost`), + KEY `maxnumrep` (`maxnumrep`) +) ENGINE=MyISAM ROW_FORMAT=FIXED; +INSERT INTO t1 (titre,maxnumrep) VALUES +('test1','1'),('test2','2'),('test3','3'); +SELECT SQL_CALC_FOUND_ROWS titre,numeropost,maxnumrep FROM t1 WHERE numeropost IN (1,2) ORDER BY maxnumrep DESC LIMIT 0, 1; +SELECT FOUND_ROWS(); +SELECT SQL_CALC_FOUND_ROWS 1 FROM (SELECT 1) as a LIMIT 0; +SELECT FOUND_ROWS(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE numeropost > 1 LIMIT 0; +SELECT FOUND_ROWS(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 0; +SELECT FOUND_ROWS(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 ORDER BY numeropost LIMIT 0; +SELECT FOUND_ROWS(); +drop table t1; + +# +# Test problem with impossible WHERE (Bug #1468) +# + +create table t1 (id int, primary key (id)); +insert into t1 values (1), (2), (3), (4), (5); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 limit 0, 1; +select FOUND_ROWS(); +select SQL_CALC_FOUND_ROWS * from t1 where id > 3 AND 1=2 limit 0, 1; +select FOUND_ROWS(); +select SQL_CALC_FOUND_ROWS * from t1 where id > 6 limit 0, 1; +select FOUND_ROWS(); +drop table t1; + +# +# Other bugs with range optimization +# + +# bug #2448 + +CREATE TABLE t1 ( a int not null, b int not null, KEY ab(a,b) ); +INSERT INTO t1 VALUES ( 47, 1 ); +INSERT INTO t1 VALUES ( 70, 1 ); +SELECT * FROM t1 +WHERE +( + ( b =1 AND a BETWEEN 14 AND 21 ) OR + ( b =2 AND a BETWEEN 16 AND 18 ) OR + ( b =3 AND a BETWEEN 15 AND 19 ) +); +DROP TABLE t1; + +# bug #2698 + +CREATE TABLE t1 ( a integer, u varchar(15), r integer, key uao_idx( r, a, u)); +DELETE FROM t1 +WHERE ( r = 1 AND a IN ( 1, 2 ) AND ( u = 'w' OR u LIKE 'w/%' ) ) + OR ( r = 1 AND a IN ( 3 ) AND ( u = 'w/U' OR u LIKE 'w/U/%' ) ) + OR ( r = 1 AND a IN ( 1, 2, 3 ) AND ( u = 'w' ) ); +drop table t1; + +# +# Bug #3738: we have a ref key +# + +CREATE TABLE t1 (a VARCHAR(16), UNIQUE(a)); +INSERT INTO t1 VALUES ('1'), ('2'), ('3'); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a = '2' LIMIT 0, 1; +SELECT FOUND_ROWS(); +DROP TABLE t1; + +# +# Bug #3845: group by, having and empty result +# + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (0), (0), (1), (2); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a = 0 GROUP BY a HAVING a > 10; +SELECT FOUND_ROWS(); +DROP TABLE t1; + +# +# Bug #6089: queries which don't use any tables +# + +SELECT 'foo'; +SELECT FOUND_ROWS(); +SELECT SQL_CALC_FOUND_ROWS 'foo'; +SELECT FOUND_ROWS(); +SELECT SQL_CALC_FOUND_ROWS 'foo' limit 0; +SELECT FOUND_ROWS(); +SELECT FOUND_ROWS(); + +SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0; +SELECT FOUND_ROWS(); + +# +# Bug #7945: group by + distinct with constant expression + limit +# + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,2), (1,3), (1,4), (1,5); +SELECT SQL_CALC_FOUND_ROWS DISTINCT 'a' FROM t1 GROUP BY b LIMIT 2; +SELECT FOUND_ROWS(); +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/select_safe.test b/mysql-test/suite/pbxt/t/select_safe.test new file mode 100644 index 00000000000..309dbf21791 --- /dev/null +++ b/mysql-test/suite/pbxt/t/select_safe.test @@ -0,0 +1,94 @@ +# +# test of safe selects +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=4, SQL_MAX_JOIN_SIZE=9; +create table t1 (a int auto_increment primary key, b char(20)); +insert into t1 values(1,"test"); +SELECT SQL_BUFFER_RESULT * from t1; +update t1 set b="a" where a=1; +delete from t1 where a=1; +insert into t1 values(1,"test"),(2,"test2"); +SELECT SQL_BUFFER_RESULT * from t1 order by a; # PBXT required for consistent result +update t1 set b="a" where a=1; +analyze table t1; # PBXT: required to get the correct COUNT(*) +select 1 from t1,t1 as t2,t1 as t3; + +# The following should give errors: +--error 1175 +update t1 set b="a"; +--error 1175 +update t1 set b="a" where b="test"; +--error 1175 +delete from t1; +--error 1175 +delete from t1 where b="test"; +--error 1175 +delete from t1 where a+0=1; +--error 1104 +select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; + +# The following should be ok: +update t1 set b="a" order by a limit 1; # PBXT required for consistent result +update t1 set b="a" where b="b" order by a limit 2; # PBXT required for consistent result +delete from t1 where b="test" order by a limit 1; # PBXT required for consistent result +delete from t1 where a+0=1 order by a limit 2; # PBXT required for consistent result + +# Test SQL_BIG_SELECTS + +alter table t1 add key b (b); +SET MAX_JOIN_SIZE=2; +SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; +insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); +--error 1104 +SELECT * from t1 order by a; +SET SQL_BIG_SELECTS=1; +SELECT * from t1 order by a; +SET MAX_JOIN_SIZE=2; +--error 1104 +SELECT * from t1; +SET MAX_JOIN_SIZE=DEFAULT; +SELECT * from t1; + +# +# Test MAX_SEEKS_FOR_KEY +# +analyze table t1; +insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); +explain select STRAIGHT_JOIN * from t1,t1 as t2 where t1.b=t2.b; +set MAX_SEEKS_FOR_KEY=1; +explain select STRAIGHT_JOIN * from t1,t1 as t2 where t1.b=t2.b; +SET MAX_SEEKS_FOR_KEY=DEFAULT; + +drop table t1; + +# BUG#8726 +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5); +insert into t1 select * from t1; +insert into t1 select * from t1; +insert into t1 select * from t1; + +set local max_join_size=8; +--error 1104 +select * from (select * from t1) x; + +set local max_join_size=1; +--error 1104 +select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x; + +set local max_join_size=1; +--error 1104 +select * from (select 1 union select 2 union select 3) x; +drop table t1; + +SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/skip_grants.test b/mysql-test/suite/pbxt/t/skip_grants.test new file mode 100644 index 00000000000..87a8fa88491 --- /dev/null +++ b/mysql-test/suite/pbxt/t/skip_grants.test @@ -0,0 +1,114 @@ +# This tests not performed with embedded server +-- source include/not_embedded.inc + +use test; + +# +# BUG#16777: Can not create trigger nor view w/o definer if --skip-grant-tables +# specified +# +# Also, the following test cases have been moved here: +# - test that we can create VIEW if privileges check switched off has been +# moved here; +# - test that we can create and drop procedure without warnings (BUG#9993); +# - BUG#17595: "DROP FUNCTION IF EXISTS" crashes server; +# - BUG#13504: creation view with DEFINER clause if --skip-grant-tables +# + +# Prepare. + +--disable_warnings + +DROP VIEW IF EXISTS v1; +DROP VIEW IF EXISTS v2; +DROP VIEW IF EXISTS v3; + +DROP TABLE IF EXISTS t1; + +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; + +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; + +--enable_warnings + +# Test case. + +CREATE TABLE t1(c INT); + +# - try to create with implicit definer (definer would be ''@''); + +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 + FOR EACH ROW + SET @a = 1; + +CREATE VIEW v1 AS SELECT * FROM t1; + +CREATE PROCEDURE p1() + SELECT 1; + +CREATE FUNCTION f1() RETURNS INT + RETURN 1; + +# - try to create with explicit definer; + +CREATE DEFINER=a@b TRIGGER ti_ai AFTER INSERT ON t1 + FOR EACH ROW + SET @b = 1; + +CREATE DEFINER=a@b VIEW v2 AS SELECT * FROM t1; + +CREATE DEFINER=a@b PROCEDURE p2() + SELECT 2; + +CREATE DEFINER=a@b FUNCTION f2() RETURNS INT + RETURN 2; + +# - try to create with explicit definer with empty host; + +CREATE DEFINER=a@'' TRIGGER ti_bu BEFORE UPDATE ON t1 + FOR EACH ROW + SET @c = 1; + +CREATE DEFINER=a@'' VIEW v3 AS SELECT * FROM t1; + +CREATE DEFINER=a@'' PROCEDURE p3() + SELECT 3; + +CREATE DEFINER=a@'' FUNCTION f3() RETURNS INT + RETURN 3; + +# - check that empty host name is treated correctly; + +SHOW CREATE VIEW v3; + +SHOW CREATE PROCEDURE p3; + +SHOW CREATE FUNCTION f3; + +# Cleanup. + +DROP TRIGGER t1_bi; +DROP TRIGGER ti_ai; +DROP TRIGGER ti_bu; + +DROP VIEW v1; +DROP VIEW v2; +DROP VIEW v3; + +DROP TABLE t1; + +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP PROCEDURE p3; + +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP FUNCTION f3; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/skip_name_resolve.test b/mysql-test/suite/pbxt/t/skip_name_resolve.test new file mode 100644 index 00000000000..3f732c8912b --- /dev/null +++ b/mysql-test/suite/pbxt/t/skip_name_resolve.test @@ -0,0 +1,20 @@ +# Can't be tested with embedded server +-- source include/not_embedded.inc + +# Bug #8471: IP address with mask fail when skip-name-resolve is on +GRANT ALL ON test.* TO mysqltest_1@'127.0.0.1/255.255.255.255'; +SHOW GRANTS FOR mysqltest_1@'127.0.0.1/255.255.255.255'; +REVOKE ALL ON test.* FROM mysqltest_1@'127.0.0.1/255.255.255.255'; +DROP USER mysqltest_1@'127.0.0.1/255.255.255.255'; + +# End of 4.1 tests + +# Bug #13407 "Remote connecting crashes server". +# Server crashed when one used USER() function in connection for which +# was impossible to obtain peer hostname. +connect (con1, 127.0.0.1, root, , test, $MASTER_MYPORT, ); +--replace_column 1 # +select user(); +--replace_column 1 <id> 3 <host> 5 <command> 6 <time> 7 <state> 8 <info> +show processlist; +connection default; diff --git a/mysql-test/suite/pbxt/t/sql_mode.test b/mysql-test/suite/pbxt/t/sql_mode.test new file mode 100644 index 00000000000..9f5183ce3cb --- /dev/null +++ b/mysql-test/suite/pbxt/t/sql_mode.test @@ -0,0 +1,273 @@ +--disable_warnings +drop table if exists t1,t2,v1,v2; +drop view if exists t1,t2,v1,v2; +--enable_warnings + +CREATE TABLE `t1` ( + a int not null auto_increment, + `pseudo` varchar(35) character set latin2 NOT NULL default '', + `email` varchar(60) character set latin2 NOT NULL default '', + PRIMARY KEY (a), + UNIQUE KEY `email` USING BTREE (`email`) +) ENGINE=HEAP CHARSET=latin1 ROW_FORMAT DYNAMIC; +set @@sql_mode=""; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="ansi_quotes"; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="no_table_options"; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="no_key_options"; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="no_field_options,mysql323,mysql40"; +show variables like 'sql_mode'; +show create table t1; +set sql_mode="postgresql,oracle,mssql,db2,maxdb"; +select @@sql_mode; +show create table t1; +drop table t1; + +# +# Check that a binary collation adds 'binary' +# suffix into a char() column definition in +# mysql40 and mysql2323 modes. This allows +# not to lose the column's case sensitivity +# when loading the dump in pre-4.1 servers. +# +# Thus, in 4.0 and 3.23 modes we dump: +# +# 'char(10) collate xxx_bin' as 'char(10) binary' +# 'binary(10)' as 'binary(10)' +# +# In mysql-4.1 these types are different, and they will +# be recreated differently. +# +# In mysqld-4.0 the the above two types were the same, +# so it will create a 'char(10) binary' column for both definitions. +# +CREATE TABLE t1 ( + a char(10), + b char(10) collate latin1_bin, + c binary(10) +) character set latin1; +set @@sql_mode=""; +show create table t1; +set @@sql_mode="mysql323"; +show create table t1; +set @@sql_mode="mysql40"; +show create table t1; +drop table t1; + +# +# BUG#5318 - failure: 'IGNORE_SPACE' affects numeric values after DEFAULT +# +# Force the usage of the default +set session sql_mode = ''; +# statement for comparison, value starts with '.' +create table t1 ( min_num dec(6,6) default .000001); +show create table t1; +drop table t1 ; +# +set session sql_mode = 'IGNORE_SPACE'; +# statement for comparison, value starts with '0' +create table t1 ( min_num dec(6,6) default 0.000001); +show create table t1; +drop table t1 ; +# This statement fails, value starts with '.' +create table t1 ( min_num dec(6,6) default .000001); +show create table t1; +drop table t1 ; + +# +# Bug #10732: Set SQL_MODE to NULL gives garbled error message +# +--error 1231 +set @@SQL_MODE=NULL; + +# +# Bug #797: in sql_mode=ANSI, show create table ignores auto_increment +# +set session sql_mode=ansi; +create table t1 +(f1 integer auto_increment primary key, + f2 timestamp default current_timestamp on update current_timestamp); +show create table t1; +set session sql_mode=no_field_options; +show create table t1; +drop table t1; + +# End of 4.1 tests + +# +# test for +# WL 1941 "NO_C_ESCAPES sql_mode" +# +# an sql_mode to disable \n, \r, \b, etc escapes in string literals. actually, to +# disable special meaning of backslash completely. It's not in the SQL standard +# and it causes some R/3 tests to fail. +# + +SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=''; +show local variables like 'SQL_MODE'; + +CREATE TABLE t1 (p int not null auto_increment, a varchar(20), primary key(p)); +INSERT t1 (a) VALUES +('\\'), +('\n'), +('\b'), +('\r'), +('\t'), +('\x'), +('\a'), +('\aa'), +('\\a'), +('\\aa'), +('_'), +('\_'), +('\\_'), +('\\\_'), +('\\\\_'), +('%'), +('\%'), +('\\%'), +('\\\%'), +('\\\\%') +; + +SELECT p, hex(a) FROM t1; + +delete from t1 where a in ('\n','\r','\t', '\b'); + +select + masks.p, + masks.a as mask, + examples.a as example +from + t1 as masks + left join t1 as examples on examples.a LIKE masks.a +order by masks.p, example; + +DROP TABLE t1; + +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +show local variables like 'SQL_MODE'; + +CREATE TABLE t1 (p int not null auto_increment, a varchar(20), primary key(p)); +INSERT t1 (a) VALUES +('\\'), +('\n'), +('\b'), +('\r'), +('\t'), +('\x'), +('\a'), +('\aa'), +('\\a'), +('\\aa'), +('_'), +('\_'), +('\\_'), +('\\\_'), +('\\\\_'), +('%'), +('\%'), +('\\%'), +('\\\%'), +('\\\\%') +; + +SELECT p, hex(a) FROM t1; + +delete from t1 where a in ('\n','\r','\t', '\b'); + +select + masks.p, + masks.a as mask, + examples.a as example +from + t1 as masks + left join t1 as examples on examples.a LIKE masks.a +order by masks.p, example; + +DROP TABLE t1; + +# Bug #6368: Make sure backslashes mixed with doubled quotes are handled +# correctly in NO_BACKSLASH_ESCAPES mode +SET @@SQL_MODE='NO_BACKSLASH_ESCAPES'; +SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; +SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; + +SET @@SQL_MODE=''; +SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; +SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; + +# +# Bug#6877: MySQL should give an error if the requested table type +# is not available +# + +#set session sql_mode = 'NO_ENGINE_SUBSTITUTION'; +#--error 1289 +#create table t1 (a int) engine=isam; +#--error 1146 +#show create table t1; +#drop table if exists t1; +# +## for comparison, lets see the warnings... +#set session sql_mode = ''; +#create table t1 (a int) engine=isam; +#show create table t1; +#drop table t1; + +# +# Bug #6903: ANSI_QUOTES does not come into play with SHOW CREATE FUNCTION +# or PROCEDURE because it displays the SQL_MODE used to create the routine. +# +SET @@SQL_MODE=''; +create function `foo` () returns int return 5; +show create function `foo`; +SET @@SQL_MODE='ANSI_QUOTES'; +show create function `foo`; +drop function `foo`; + +create function `foo` () returns int return 5; +show create function `foo`; +SET @@SQL_MODE=''; +show create function `foo`; +drop function `foo`; + +# +# Bug #6903: ANSI_QUOTES should have effect for SHOW CREATE VIEW (Bug #6903) +# +SET @@SQL_MODE=''; +create table t1 (a int); +create table t2 (a int); +create view v1 as select a from t1; +show create view v1; +SET @@SQL_MODE='ANSI_QUOTES'; +show create view v1; +# Test a view with a subselect, which will get shown incorrectly without +# thd->lex->view_prepare_mode set properly. +create view v2 as select a from t2 where a in (select a from v1); +drop view v2, v1; +drop table t1, t2; + +select @@sql_mode; +set sql_mode=2097152; +select @@sql_mode; +# BUG#14675 +set sql_mode=4194304; +select @@sql_mode; +set sql_mode=16384+(65536*4); +select @@sql_mode; +set sql_mode=2147483648; # that mode does not exist +select @@sql_mode; + +SET @@SQL_MODE=@OLD_SQL_MODE; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/status.test b/mysql-test/suite/pbxt/t/status.test new file mode 100644 index 00000000000..8a3d43ea475 --- /dev/null +++ b/mysql-test/suite/pbxt/t/status.test @@ -0,0 +1,190 @@ +# embedded server causes different stat +-- source include/not_embedded.inc + +# PS causes different statistics +--disable_ps_protocol + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +flush status; +show status like 'Table_lock%'; +select * from information_schema.session_status where variable_name like 'Table_lock%'; +connection con1; +SET SQL_LOG_BIN=0; +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1(n int) engine=myisam; +insert into t1 values(1); + +# PBXT: fix for late commit on unlock, see comment in ps.test +# +select * from t1; +connection con2; +lock tables t1 read; +unlock tables; +lock tables t1 read; +connection con1; +--send +update t1 set n = 3; +connection con2; +sleep 0.5; +unlock tables; +connection con1; +reap; +show status like 'Table_lock%'; +select * from information_schema.session_status where variable_name like 'Table_lock%'; +drop table t1; + +disconnect con2; +disconnect con1; +connection default; + +# End of 4.1 tests + +# +# last_query_cost +# + +select 1; +show status like 'last_query_cost'; +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +select * from t1 where a=6; +show status like 'last_query_cost'; +# Ensure value dosn't change by second status call +show status like 'last_query_cost'; +select 1; +show status like 'last_query_cost'; +drop table t1; + +# +# Test for Bug #15933 max_used_connections is wrong after FLUSH STATUS +# if connections are cached +# +# +# The first suggested fix from the bug report was chosen +# (see http://bugs.mysql.com/bug.php?id=15933): +# +# a) On flushing the status, set max_used_connections to +# threads_connected, not to 0. +# +# b) Check if it is necessary to increment max_used_connections when +# taking a thread from the cache as well as when creating new threads +# + +# Wait for at most $disconnect_timeout seconds for disconnects to finish. +let $disconnect_timeout = 10; + +# Wait for any previous disconnects to finish. +FLUSH STATUS; +--disable_query_log +--disable_result_log +eval SET @wait_left = $disconnect_timeout; +let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; +eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; +let $wait_more = `SELECT @max_used_connections != 1 && @wait_left > 0`; +while ($wait_more) +{ + sleep 1; + FLUSH STATUS; + SET @wait_left = @wait_left - 1; + let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; + eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; + let $wait_more = `SELECT @max_used_connections != 1 && @wait_left > 0`; +} +--enable_query_log +--enable_result_log + +# Prerequisite. +SHOW STATUS LIKE 'max_used_connections'; +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; + +# Save original setting. +SET @save_thread_cache_size=@@thread_cache_size; +SET GLOBAL thread_cache_size=3; + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +connection con1; +disconnect con2; + +# Check that max_used_connections still reflects maximum value. +SHOW STATUS LIKE 'max_used_connections'; +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; + +# Check that after flush max_used_connections equals to current number +# of connections. First wait for previous disconnect to finish. +FLUSH STATUS; +--disable_query_log +--disable_result_log +eval SET @wait_left = $disconnect_timeout; +let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; +eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; +let $wait_more = `SELECT @max_used_connections != 2 && @wait_left > 0`; +while ($wait_more) +{ + sleep 1; + FLUSH STATUS; + SET @wait_left = @wait_left - 1; + let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; + eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; + let $wait_more = `SELECT @max_used_connections != 2 && @wait_left > 0`; +} +--enable_query_log +--enable_result_log +# Check that we don't count disconnected thread any longer. +SHOW STATUS LIKE 'max_used_connections'; +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; + +# Check that max_used_connections is updated when cached thread is +# reused... +connect (con2,localhost,root,,); +SHOW STATUS LIKE 'max_used_connections'; +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; + +# ...and when new thread is created. +connect (con3,localhost,root,,); +SHOW STATUS LIKE 'max_used_connections'; +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'max_used_connections'; + +# Restore original setting. +connection default; +SET GLOBAL thread_cache_size=@save_thread_cache_size; + +disconnect con3; +disconnect con2; +disconnect con1; + +# End of 5.0 tests + +# +# Ensure that SHOW STATUS only changes global status variables +# + +connect (con1,localhost,root,,); +let $rnd_next = `show global status like 'handler_read_rnd_next'`; +let $tmp_table = `show global status like 'Created_tmp_tables'`; +show status like 'com_show_status'; +show status like 'hand%write%'; +show status like '%tmp%'; +show status like 'hand%write%'; +show status like '%tmp%'; +show status like 'com_show_status'; +let $rnd_next2 = `show global status like 'handler_read_rnd_next'`; +let $tmp_table2 = `show global status like 'Created_tmp_tables'`; +--disable_query_log +eval select substring_index('$rnd_next2',0x9,-1)-substring_index('$rnd_next',0x9,-1) as rnd_diff, substring_index('$tmp_table2',0x9,-1)-substring_index('$tmp_table',0x9,-1) as tmp_table_diff; +--enable_query_log + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 5.1 tests diff --git a/mysql-test/suite/pbxt/t/subselect.test b/mysql-test/suite/pbxt/t/subselect.test new file mode 100644 index 00000000000..708d3214cf7 --- /dev/null +++ b/mysql-test/suite/pbxt/t/subselect.test @@ -0,0 +1,3210 @@ +# Initialise +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12; +--enable_warnings + +select (select 2); +explain extended select (select 2); +SELECT (SELECT 1) UNION SELECT (SELECT 2); +explain extended SELECT (SELECT 1) UNION SELECT (SELECT 2); +SELECT (SELECT (SELECT 0 UNION SELECT 0)); +explain extended SELECT (SELECT (SELECT 0 UNION SELECT 0)); +-- error 1247 +SELECT (SELECT 1 FROM (SELECT 1) as b HAVING a=1) as a; +-- error 1247 +SELECT (SELECT 1 FROM (SELECT 1) as b HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) as c HAVING a=1) as b; +SELECT (SELECT 1),MAX(1) FROM (SELECT 1) as a; +-- error 1247 +SELECT (SELECT a) as a; +EXPLAIN EXTENDED SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; +SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; +-- error 1054 +SELECT (SELECT 1), a; +SELECT 1 as a FROM (SELECT 1) as b HAVING (SELECT a)=1; +-- error 1054 +SELECT 1 FROM (SELECT (SELECT a) b) c; +SELECT * FROM (SELECT 1 as id) b WHERE id IN (SELECT * FROM (SELECT 1 as id) c ORDER BY id); +-- error 1241 +SELECT * FROM (SELECT 1) a WHERE 1 IN (SELECT 1,1); +SELECT 1 IN (SELECT 1); +SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); +-- error 1221 +select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); +-- error 1108 +SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); +-- error ER_BAD_FIELD_ERROR +SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; +-- error ER_BAD_FIELD_ERROR +SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; +SELECT (SELECT 1,2,3) = ROW(1,2,3); +SELECT (SELECT 1,2,3) = ROW(1,2,1); +SELECT (SELECT 1,2,3) < ROW(1,2,1); +SELECT (SELECT 1,2,3) > ROW(1,2,1); +SELECT (SELECT 1,2,3) = ROW(1,2,NULL); +SELECT ROW(1,2,3) = (SELECT 1,2,3); +SELECT ROW(1,2,3) = (SELECT 1,2,1); +SELECT ROW(1,2,3) < (SELECT 1,2,1); +SELECT ROW(1,2,3) > (SELECT 1,2,1); +SELECT ROW(1,2,3) = (SELECT 1,2,NULL); +SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'a'); +SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'b'); +SELECT (SELECT 1.5,2,'a') = ROW('1.5b',2,'b'); +SELECT (SELECT 'b',2,'a') = ROW(1.5,2,'a'); +SELECT (SELECT 1.5,2,'a') = ROW(1.5,'2','a'); +SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a'); + +-- error 1241 +SELECT (SELECT * FROM (SELECT 'test' a,'test' b) a); + +SELECT 1 as a,(SELECT a+a) b,(SELECT b); + +create table t1 (a int); +create table t2 (a int, b int); +create table t3 (a int); +create table t4 (a int not null, b int not null); +insert into t1 values (2); +insert into t2 values (1,7),(2,7); +insert into t4 values (4,8),(3,8),(5,9); +-- error 1247 +select (select a from t1 where t1.a = a1) as a2, (select b from t2 where t2.b=a2) as a1; +select (select a from t1 where t1.a=t2.a), a from t2; +select (select a from t1 where t1.a=t2.b), a from t2; +select (select a from t1), a, (select 1 union select 2 limit 1) from t2; +select (select a from t3), a from t2; +select * from t2 where t2.a=(select a from t1); +insert into t3 values (6),(7),(3); +select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1); +(select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 order by a limit 2) limit 3; +(select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +explain extended (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2; +select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from +(select * from t2 where a>1) as tt; +explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from +(select * from t2 where a>1) as tt; +select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); +select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a > t1.a) order by 1 desc limit 1); +select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a < t1.a) order by 1 desc limit 1); +select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; +explain extended select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; +select * from t3 where exists (select * from t2 where t2.b=t3.a); +select * from t3 where not exists (select * from t2 where t2.b=t3.a); +select * from t3 where a in (select b from t2); +select * from t3 where a not in (select b from t2); +select * from t3 where a = some (select b from t2); +select * from t3 where a <> any (select b from t2); + +# Rewrite: select * from t3 where not exists (select b from t2 where a <> b); +select * from t3 where a = all (select b from t2); + +select * from t3 where a <> all (select b from t2); +insert into t2 values (100, 5); +select * from t3 where a < any (select b from t2); +select * from t3 where a < all (select b from t2); +select * from t3 where a >= any (select b from t2); +explain extended select * from t3 where a >= any (select b from t2); +select * from t3 where a >= all (select b from t2); +delete from t2 where a=100; +-- error 1241 +select * from t3 where a in (select a,b from t2); +-- error 1241 +select * from t3 where a in (select * from t2); +insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9),(1,10); +# empty set +select b,max(a) as ma from t4 group by b having b < (select max(t2.a) from t2 where t2.b=t4.b); +insert into t2 values (2,10); +select b,max(a) as ma from t4 group by b having ma < (select max(t2.a) from t2 where t2.b=t4.b); +delete from t2 where a=2 and b=10; +select b,max(a) as ma from t4 group by b having b >= (select max(t2.a) from t2 where t2.b=t4.b); +create table t5 (a int); +select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +insert into t5 values (5); +select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +insert into t5 values (2); +select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +--replace_column 9 # +explain extended select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +-- error 1242 +select (select a from t1 where t1.a=t2.a union all select a from t5 where t5.a=t2.a), a from t2; +create table t6 (patient_uq int, clinic_uq int, index i1 (clinic_uq)); +create table t7( uq int primary key, name char(25)); +insert into t7 values(1,"Oblastnaia bolnitsa"),(2,"Bolnitsa Krasnogo Kresta"); +insert into t6 values (1,1),(1,2),(2,2),(1,3); +select * from t6 where exists (select * from t7 where uq = clinic_uq); +explain extended select * from t6 where exists (select * from t7 where uq = clinic_uq); + +# not unique fields +-- error 1052 +select * from t1 where a= (select a from t2,t4 where t2.b=t4.b); + +# different tipes & group functions +drop table t1,t2,t3; + +CREATE TABLE t3 (a varchar(20),b char(1) NOT NULL default '0'); +INSERT INTO t3 VALUES ('W','a'),('A','c'),('J','b'); +CREATE TABLE t2 (a varchar(20),b int NOT NULL default '0'); +INSERT INTO t2 VALUES ('W','1'),('A','3'),('J','2'); +CREATE TABLE t1 (a varchar(20),b date NOT NULL default '0000-00-00'); +INSERT INTO t1 VALUES ('W','1732-02-22'),('A','1735-10-30'),('J','1743-04-13'); +SELECT * FROM t1 WHERE b = (SELECT MIN(b) FROM t1); +SELECT * FROM t2 WHERE b = (SELECT MIN(b) FROM t2); +SELECT * FROM t3 WHERE b = (SELECT MIN(b) FROM t3); + +CREATE TABLE `t8` ( + `pseudo` varchar(35) character set latin1 NOT NULL default '', + `email` varchar(60) character set latin1 NOT NULL default '', + PRIMARY KEY (`pseudo`), + UNIQUE KEY `email` (`email`) +) ENGINE=MyISAM CHARSET=latin1 ROW_FORMAT=DYNAMIC; + +INSERT INTO t8 (pseudo,email) VALUES ('joce','test'); +INSERT INTO t8 (pseudo,email) VALUES ('joce1','test1'); +INSERT INTO t8 (pseudo,email) VALUES ('2joce1','2test1'); +EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); +-- error 1241 +SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM +t8 WHERE pseudo='joce'); +-- error 1241 +SELECT pseudo FROM t8 WHERE pseudo=(SELECT * FROM t8 WHERE +pseudo='joce'); +SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); +-- error 1242 +SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo LIKE '%joce%'); + +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8; + +#searchconthardwarefr3 forumconthardwarefr7 +CREATE TABLE `t1` ( + `topic` mediumint(8) unsigned NOT NULL default '0', + `date` date NOT NULL default '0000-00-00', + `pseudo` varchar(35) character set latin1 NOT NULL default '', + PRIMARY KEY (`pseudo`,`date`,`topic`), + KEY `topic` (`topic`) +) ENGINE=MyISAM ROW_FORMAT=DYNAMIC; +INSERT INTO t1 (topic,date,pseudo) VALUES +('43506','2002-10-02','joce'),('40143','2002-08-03','joce'); +EXPLAIN EXTENDED SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; +EXPLAIN EXTENDED SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); +SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; +SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); +SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1) UNION ALL SELECT 1; +-- error 1242 +SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1) UNION SELECT 1; +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1); +drop table t1; + +#forumconthardwarefr7 searchconthardwarefr7 +CREATE TABLE `t1` ( + `numeropost` mediumint(8) unsigned NOT NULL auto_increment, + `maxnumrep` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`numeropost`), + UNIQUE KEY `maxnumrep` (`maxnumrep`) +) ENGINE=MyISAM ROW_FORMAT=FIXED; + +INSERT INTO t1 (numeropost,maxnumrep) VALUES (40143,1),(43506,2); + +CREATE TABLE `t2` ( + `mot` varchar(30) NOT NULL default '', + `topic` mediumint(8) unsigned NOT NULL default '0', + `date` date NOT NULL default '0000-00-00', + `pseudo` varchar(35) NOT NULL default '', + PRIMARY KEY (`mot`,`pseudo`,`date`,`topic`) + ) ENGINE=MyISAM ROW_FORMAT=DYNAMIC; + +INSERT INTO t2 (mot,topic,date,pseudo) VALUES ('joce','40143','2002-10-22','joce'), ('joce','43506','2002-10-22','joce'); +select numeropost as a FROM t1 GROUP BY (SELECT 1 FROM t1 HAVING a=1); +SELECT numeropost,maxnumrep FROM t1 WHERE exists (SELECT 1 FROM t2 WHERE (mot='joce') AND date >= '2002-10-21' AND t1.numeropost = t2.topic) ORDER BY maxnumrep DESC LIMIT 0, 20; +-- error 1054 +SELECT (SELECT 1) as a FROM (SELECT 1 FROM t1 HAVING a=1) b; +-- error 1054 +SELECT 1 IN (SELECT 1 FROM t2 HAVING a); + +SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY topic); +SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100); +SELECT * from t2 where topic IN (SELECT SUM(topic) FROM t1); +SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY topic); +SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100); +SELECT * from t2 where topic = any (SELECT SUM(topic) FROM t1); +SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY topic); +SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100); +SELECT *, topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 4100) from t2; +SELECT * from t2 where topic = all (SELECT SUM(topic) FROM t2); +SELECT * from t2 where topic <> any (SELECT SUM(topic) FROM t2); +SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000); +SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000); +SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000); +SELECT *, topic = all (SELECT topic FROM t2 GROUP BY topic HAVING topic < 41000) from t2; +drop table t1,t2; + +#forumconthardwarefr7 +CREATE TABLE `t1` ( + `numeropost` mediumint(8) unsigned NOT NULL auto_increment, + `maxnumrep` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`numeropost`), + UNIQUE KEY `maxnumrep` (`maxnumrep`) +) ENGINE=MyISAM ROW_FORMAT=FIXED; + +INSERT INTO t1 (numeropost,maxnumrep) VALUES (1,0),(2,1); +-- error 1242 +select numeropost as a FROM t1 GROUP BY (SELECT 1 FROM t1 HAVING a=1); +-- error 1242 +select numeropost as a FROM t1 ORDER BY (SELECT 1 FROM t1 HAVING a=1); +drop table t1; + +create table t1 (a int); +insert into t1 values (1),(2),(3); +(select * from t1) union (select * from t1) order by (select a from t1 limit 1); +drop table t1; + +#iftest +CREATE TABLE t1 (field char(1) NOT NULL DEFAULT 'b'); +INSERT INTO t1 VALUES (); +-- error 1242 +SELECT field FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1 FROM (SELECT 1) a HAVING field='b'); +drop table t1; + +# threadhardwarefr7 +CREATE TABLE `t1` ( + `numeropost` mediumint(8) unsigned NOT NULL default '0', + `numreponse` int(10) unsigned NOT NULL auto_increment, + `pseudo` varchar(35) NOT NULL default '', + PRIMARY KEY (`numeropost`,`numreponse`), + UNIQUE KEY `numreponse` (`numreponse`), + KEY `pseudo` (`pseudo`,`numeropost`) +) ENGINE=MyISAM; +-- error 1247 +SELECT (SELECT numeropost FROM t1 HAVING numreponse=a),numreponse FROM (SELECT * FROM t1) as a; +-- error 1054 +SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=a) FROM (SELECT * FROM t1) as a; +SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=1) FROM (SELECT * FROM t1) as a; +INSERT INTO t1 (numeropost,numreponse,pseudo) VALUES (1,1,'joce'),(1,2,'joce'),(1,3,'test'); +-- error 1242 +EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM t1 WHERE numeropost='1'); +EXPLAIN EXTENDED SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; +EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); +drop table t1; + +CREATE TABLE t1 (a int(1)); +INSERT INTO t1 VALUES (1); +SELECT 1 FROM (SELECT a FROM t1) b HAVING (SELECT b.a)=1; +drop table t1; + +#update with subselects +create table t1 (a int NOT NULL, b int, primary key (a)); +create table t2 (a int NOT NULL, b int, primary key (a)); +insert into t1 values (0, 10),(1, 11),(2, 12); +insert into t2 values (1, 21),(2, 22),(3, 23); +select * from t1; +-- error 1093 +update t1 set b= (select b from t1); +-- error 1242 +update t1 set b= (select b from t2); +update t1 set b= (select b from t2 where t1.a = t2.a); +select * from t1; +drop table t1, t2; + +#delete with subselects +create table t1 (a int NOT NULL, b int, primary key (a)); +create table t2 (a int NOT NULL, b int, primary key (a)); +insert into t1 values (0, 10),(1, 11),(2, 12); +insert into t2 values (1, 21),(2, 12),(3, 23); +select * from t1; +select * from t1 where b = (select b from t2 where t1.a = t2.a); +-- error 1093 +delete from t1 where b = (select b from t1); +-- error 1242 +delete from t1 where b = (select b from t2); +delete from t1 where b = (select b from t2 where t1.a = t2.a); +select * from t1; +drop table t1, t2; + +#multi-delete with subselects + +create table t11 (a int NOT NULL, b int, primary key (a)); +create table t12 (a int NOT NULL, b int, primary key (a)); +create table t2 (a int NOT NULL, b int, primary key (a)); +insert into t11 values (0, 10),(1, 11),(2, 12); +insert into t12 values (33, 10),(22, 11),(2, 12); +insert into t2 values (1, 21),(2, 12),(3, 23); +select * from t11; +select * from t12; +-- error 1093 +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); +-- error 1242 +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); +delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); +select * from t11; +select * from t12; +drop table t11, t12, t2; + +#insert with subselects +CREATE TABLE t1 (x int); +create table t2 (a int); +create table t3 (b int); +insert into t2 values (1); +insert into t3 values (1),(2); +-- error 1093 +INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); +-- error 1242 +INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); +INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); +select * from t1; +insert into t2 values (1); +# PBXT: DELAYED not supported +#INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); +INSERT INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); +-- sleep 1 +select * from t1; +INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2; +select * from t1; +# After this, only data based on old t1 records should have been added. +INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2; +select * from t1; +-- error 1054 +# PBXT: DELAYED not supported +#INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2)); +INSERT INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2)); +#INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); +INSERT INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); +-- sleep 1 +select * from t1; +# +#TODO: should be uncommented after bug 380 fix pushed +#INSERT INTO t1 (x) SELECT (SELECT SUM(a)+b FROM t2) from t3; +#select * from t1; +drop table t1, t2, t3; + +#replace with subselects +CREATE TABLE t1 (x int not null, y int, primary key (x)); +create table t2 (a int); +create table t3 (a int); +insert into t2 values (1); +insert into t3 values (1),(2); +select * from t1; +-- error 1093 +replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); +-- error 1242 +replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); +replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); +select * from t1; +replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+2 FROM t2)); +select * from t1; +# PBXT: DELAYED not supported +#replace DELAYED into t1 (x, y) VALUES ((SELECT a+3 FROM t2), (SELECT a FROM t2)); +replace into t1 (x, y) VALUES ((SELECT a+3 FROM t2), (SELECT a FROM t2)); +-- sleep 1 +select * from t1 order by x; # PBXT required for consistent order +# PBXT: DELAYED not supported +#replace DELAYED into t1 (x, y) VALUES ((SELECT a+3 FROM t2), (SELECT a+1 FROM t2)); +replace into t1 (x, y) VALUES ((SELECT a+3 FROM t2), (SELECT a+1 FROM t2)); +-- sleep 1 +select * from t1 order by x; # PBXT required for consistent order +replace LOW_PRIORITY into t1 (x, y) VALUES ((SELECT a+1 FROM t2), (SELECT a FROM t2)); +select * from t1 order by x; # PBXT required for consistent order +drop table t1, t2, t3; + +-- error 1096 +SELECT * FROM (SELECT 1) b WHERE 1 IN (SELECT *); + +CREATE TABLE t2 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t2 VALUES (1),(2); +SELECT * FROM t2 WHERE id IN (SELECT 1); +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1); +SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); +SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); +SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 3); +SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); +-- error 1093 +INSERT INTO t2 VALUES ((SELECT * FROM t2)); +-- error 1093 +INSERT INTO t2 VALUES ((SELECT id FROM t2)); +SELECT * FROM t2; +CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 values (1),(1); +-- error 1242 +UPDATE t2 SET id=(SELECT * FROM t1); +drop table t2, t1; + +#NULL test +create table t1 (a int); +insert into t1 values (1),(2),(3); +select 1 IN (SELECT * from t1); +select 10 IN (SELECT * from t1); +select NULL IN (SELECT * from t1); +update t1 set a=NULL where a=2; +select 1 IN (SELECT * from t1); +select 3 IN (SELECT * from t1); +select 10 IN (SELECT * from t1); +select 1 > ALL (SELECT * from t1); +select 10 > ALL (SELECT * from t1); +select 1 > ANY (SELECT * from t1); +select 10 > ANY (SELECT * from t1); +drop table t1; +create table t1 (a varchar(20)); +insert into t1 values ('A'),('BC'),('DEF'); +select 'A' IN (SELECT * from t1); +select 'XYZS' IN (SELECT * from t1); +select NULL IN (SELECT * from t1); +update t1 set a=NULL where a='BC'; +select 'A' IN (SELECT * from t1); +select 'DEF' IN (SELECT * from t1); +select 'XYZS' IN (SELECT * from t1); +select 'A' > ALL (SELECT * from t1); +select 'XYZS' > ALL (SELECT * from t1); +select 'A' > ANY (SELECT * from t1); +select 'XYZS' > ANY (SELECT * from t1); +drop table t1; +create table t1 (a float); +insert into t1 values (1.5),(2.5),(3.5); +select 1.5 IN (SELECT * from t1); +select 10.5 IN (SELECT * from t1); +select NULL IN (SELECT * from t1); +update t1 set a=NULL where a=2.5; +select 1.5 IN (SELECT * from t1); +select 3.5 IN (SELECT * from t1); +select 10.5 IN (SELECT * from t1); +select 1.5 > ALL (SELECT * from t1); +select 10.5 > ALL (SELECT * from t1); +select 1.5 > ANY (SELECT * from t1); +select 10.5 > ANY (SELECT * from t1); +explain extended select (select a+1) from t1; +select (select a+1) from t1; +drop table t1; + +# +# Null with keys +# + +CREATE TABLE t1 (a int(11) NOT NULL default '0', PRIMARY KEY (a)); +CREATE TABLE t2 (a int(11) default '0', INDEX (a)); +INSERT INTO t1 VALUES (1),(2),(3),(4); +INSERT INTO t2 VALUES (1),(2),(3); +SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; +explain extended SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; +CREATE TABLE t3 (a int(11) default '0'); +INSERT INTO t3 VALUES (1),(2),(3); +SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; +explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; +drop table t1,t2,t3; + +#LIMIT is not supported now +create table t1 (a float); +-- error 1235 +select 10.5 IN (SELECT * from t1 LIMIT 1); +-- error 1235 +select 10.5 IN (SELECT * from t1 LIMIT 1 UNION SELECT 1.5); +drop table t1; + +create table t1 (a int, b int, c varchar(10)); +create table t2 (a int); +insert into t1 values (1,2,'a'),(2,3,'b'),(3,4,'c'); +insert into t2 values (1),(2),(NULL); +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t1 where a=t2.a) from t2; +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2; +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t1 where a=t2.a) from t2; +drop table t1,t2; + +create table t1 (a int, b real, c varchar(10)); +insert into t1 values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b'); +select ROW(1, 1, 'a') IN (select a,b,c from t1); +select ROW(1, 2, 'a') IN (select a,b,c from t1); +select ROW(1, 1, 'a') IN (select b,a,c from t1); +select ROW(1, 1, 'a') IN (select a,b,c from t1 where a is not null); +select ROW(1, 2, 'a') IN (select a,b,c from t1 where a is not null); +select ROW(1, 1, 'a') IN (select b,a,c from t1 where a is not null); +select ROW(1, 1, 'a') IN (select a,b,c from t1 where c='b' or c='a'); +select ROW(1, 2, 'a') IN (select a,b,c from t1 where c='b' or c='a'); +select ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a'); +-- error 1235 +select ROW(1, 1, 'a') IN (select b,a,c from t1 limit 2); +drop table t1; + +# +# DO & SET +# +create table t1 (a int); +insert into t1 values (1); +do @a:=(SELECT a from t1); +select @a; +set @a:=2; +set @a:=(SELECT a from t1); +select @a; +drop table t1; +-- error 1146 +do (SELECT a from t1); +-- error 1146 +set @a:=(SELECT a from t1); + +CREATE TABLE t1 (a int, KEY(a)); +HANDLER t1 OPEN; +-- error 1064 +HANDLER t1 READ a=((SELECT 1)); +HANDLER t1 CLOSE; +drop table t1; + +create table t1 (a int); +create table t2 (b int); +insert into t1 values (1),(2); +insert into t2 values (1); +select a from t1 where a in (select a from t1 where a in (select b from t2)); +drop table t1, t2; + +create table t1 (a int, b int); +create table t2 like t1; +insert into t1 values (1,2),(1,3),(1,4),(1,5); +insert into t2 values (1,2),(1,3); +select * from t1 where row(a,b) in (select a,b from t2); +drop table t1, t2; + +CREATE TABLE `t1` (`i` int(11) NOT NULL default '0',PRIMARY KEY (`i`)) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES (1); +UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); +select * from t1; +drop table t1; + +#test of uncacheable subqueries +CREATE TABLE t1 (a int(1)); +EXPLAIN EXTENDED SELECT (SELECT RAND() FROM t1) FROM t1; +EXPLAIN EXTENDED SELECT (SELECT ENCRYPT('test') FROM t1) FROM t1; +EXPLAIN EXTENDED SELECT (SELECT BENCHMARK(1,1) FROM t1) FROM t1; +drop table t1; + + +CREATE TABLE `t1` ( + `mot` varchar(30) character set latin1 NOT NULL default '', + `topic` mediumint(8) unsigned NOT NULL default '0', + `date` date NOT NULL default '0000-00-00', + `pseudo` varchar(35) character set latin1 NOT NULL default '', + PRIMARY KEY (`mot`,`pseudo`,`date`,`topic`), + KEY `pseudo` (`pseudo`,`date`,`topic`), + KEY `topic` (`topic`) +) ENGINE=MyISAM CHARSET=latin1 ROW_FORMAT=DYNAMIC; + +CREATE TABLE `t2` ( + `mot` varchar(30) character set latin1 NOT NULL default '', + `topic` mediumint(8) unsigned NOT NULL default '0', + `date` date NOT NULL default '0000-00-00', + `pseudo` varchar(35) character set latin1 NOT NULL default '', + PRIMARY KEY (`mot`,`pseudo`,`date`,`topic`), + KEY `pseudo` (`pseudo`,`date`,`topic`), + KEY `topic` (`topic`) +) ENGINE=MyISAM CHARSET=latin1 ROW_FORMAT=DYNAMIC; + +CREATE TABLE `t3` ( + `numeropost` mediumint(8) unsigned NOT NULL auto_increment, + `maxnumrep` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`numeropost`), + UNIQUE KEY `maxnumrep` (`maxnumrep`) +) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES ('joce','1','','joce'),('test','2','','test'); + +INSERT INTO t2 VALUES ('joce','1','','joce'),('test','2','','test'); + +INSERT INTO t3 VALUES (1,1); + +SELECT DISTINCT topic FROM t2 WHERE NOT EXISTS(SELECT * FROM t3 WHERE +numeropost=topic); +select * from t1; +DELETE FROM t1 WHERE topic IN (SELECT DISTINCT topic FROM t2 WHERE NOT +EXISTS(SELECT * FROM t3 WHERE numeropost=topic)); +select * from t1; + +drop table t1, t2, t3; + +SELECT * FROM (SELECT 1 as a,(SELECT a)) a; +CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT 1)) a; +SHOW CREATE TABLE t1; +drop table t1; +CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a)) a; +SHOW CREATE TABLE t1; +drop table t1; +CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a+0)) a; +SHOW CREATE TABLE t1; +drop table t1; +CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a; +select * from t1; +SHOW CREATE TABLE t1; +drop table t1; + +create table t1 (a int); +insert into t1 values (1), (2), (3); +explain extended select a,(select (select rand() from t1 limit 1) from t1 limit 1) +from t1; +drop table t1; + +# +# error in IN +# +-- error 1146 +select t1.Continent, t2.Name, t2.Population from t1 LEFT JOIN t2 ON t1.Code = t2.Country where t2.Population IN (select max(t2.Population) AS Population from t2, t1 where t2.Country = t1.Code group by Continent); + +# +# complex subquery +# + +CREATE TABLE t1 ( + ID int(11) NOT NULL auto_increment, + name char(35) NOT NULL default '', + t2 char(3) NOT NULL default '', + District char(20) NOT NULL default '', + Population int(11) NOT NULL default '0', + PRIMARY KEY (ID) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (130,'Sydney','AUS','New South Wales',3276207); +INSERT INTO t1 VALUES (131,'Melbourne','AUS','Victoria',2865329); +INSERT INTO t1 VALUES (132,'Brisbane','AUS','Queensland',1291117); + +CREATE TABLE t2 ( + Code char(3) NOT NULL default '', + Name char(52) NOT NULL default '', + Continent enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') NOT NULL default 'Asia', + Region char(26) NOT NULL default '', + SurfaceArea float(10,2) NOT NULL default '0.00', + IndepYear smallint(6) default NULL, + Population int(11) NOT NULL default '0', + LifeExpectancy float(3,1) default NULL, + GNP float(10,2) default NULL, + GNPOld float(10,2) default NULL, + LocalName char(45) NOT NULL default '', + GovernmentForm char(45) NOT NULL default '', + HeadOfState char(60) default NULL, + Capital int(11) default NULL, + Code2 char(2) NOT NULL default '', + PRIMARY KEY (Code) +) ENGINE=MyISAM; + +INSERT INTO t2 VALUES ('AUS','Australia','Oceania','Australia and New Zealand',7741220.00,1901,18886000,79.8,351182.00,392911.00,'Australia','Constitutional Monarchy, Federation','Elisabeth II',135,'AU'); +INSERT INTO t2 VALUES ('AZE','Azerbaijan','Asia','Middle East',86600.00,1991,7734000,62.9,4127.00,4100.00,'Azärbaycan','Federal Republic','Heydär Äliyev',144,'AZ'); + +select t2.Continent, t1.Name, t1.Population from t2 LEFT JOIN t1 ON t2.Code = t1.t2 where t1.Population IN (select max(t1.Population) AS Population from t1, t2 where t1.t2 = t2.Code group by Continent); + +drop table t1, t2; + +# +# constants in IN +# +CREATE TABLE `t1` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `pseudo` varchar(35) character set latin1 NOT NULL default '', + PRIMARY KEY (`id`), + UNIQUE KEY `pseudo` (`pseudo`) +) ENGINE=MyISAM PACK_KEYS=1 ROW_FORMAT=DYNAMIC; +INSERT INTO t1 (pseudo) VALUES ('test'); +SELECT 0 IN (SELECT 1 FROM t1 a); +EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); +INSERT INTO t1 (pseudo) VALUES ('test1'); +SELECT 0 IN (SELECT 1 FROM t1 a); +EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); +drop table t1; + +CREATE TABLE `t1` ( + `i` int(11) NOT NULL default '0', + PRIMARY KEY (`i`) +) ENGINE=MyISAM CHARSET=latin1; + +INSERT INTO t1 VALUES (1); +UPDATE t1 SET i=i+(SELECT MAX(i) FROM (SELECT 1) t) WHERE i=(SELECT MAX(i)); +UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); +-- error 1054 +UPDATE t1 SET t.i=i+(SELECT MAX(i) FROM (SELECT 1) t); +select * from t1; +drop table t1; + +# +# Multi update test +# +CREATE TABLE t1 ( + id int(11) default NULL +) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES (1),(1),(2),(2),(1),(3); +CREATE TABLE t2 ( + id int(11) default NULL, + name varchar(15) default NULL +) ENGINE=MyISAM CHARSET=latin1; + +INSERT INTO t2 VALUES (4,'vita'), (1,'vita'), (2,'vita'), (1,'vita'); +update t1, t2 set t2.name='lenka' where t2.id in (select id from t1); +select * from t2; +drop table t1,t2; + +# +# correct NULL in <CONSTANT> IN (SELECT ...) +# +create table t1 (a int, unique index indexa (a)); +insert into t1 values (-1), (-4), (-2), (NULL); +select -10 IN (select a from t1 FORCE INDEX (indexa)); +drop table t1; + +# +# Test optimization for sub selects +# +create table t1 (id int not null auto_increment primary key, salary int, key(salary)); +insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); +explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); +drop table t1; + +CREATE TABLE t1 ( + ID int(10) unsigned NOT NULL auto_increment, + SUB_ID int(3) unsigned NOT NULL default '0', + REF_ID int(10) unsigned default NULL, + REF_SUB int(3) unsigned default '0', + PRIMARY KEY (ID,SUB_ID), + UNIQUE KEY t1_PK (ID,SUB_ID), + KEY t1_FK (REF_ID,REF_SUB), + KEY t1_REFID (REF_ID) +) ENGINE=MyISAM CHARSET=cp1251; +INSERT INTO t1 VALUES (1,0,NULL,NULL),(2,0,NULL,NULL); +SELECT DISTINCT REF_ID FROM t1 WHERE ID= (SELECT DISTINCT REF_ID FROM t1 WHERE ID=2); +DROP TABLE t1; + +# +# uninterruptable update +# +create table t1 (a int, b int); +create table t2 (a int, b int); + +insert into t1 values (1,0), (2,0), (3,0); +insert into t2 values (1,1), (2,1), (3,1), (2,2); + +update ignore t1 set b=(select b from t2 where t1.a=t2.a); +select * from t1; + +drop table t1, t2; + +# +# reduced subselect in ORDER BY & GROUP BY clauses +# + +CREATE TABLE `t1` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `pseudo` varchar(35) NOT NULL default '', + `email` varchar(60) NOT NULL default '', + PRIMARY KEY (`id`), + UNIQUE KEY `email` (`email`), + UNIQUE KEY `pseudo` (`pseudo`) +) ENGINE=MyISAM CHARSET=latin1 PACK_KEYS=1 ROW_FORMAT=DYNAMIC; +INSERT INTO t1 (id,pseudo,email) VALUES (1,'test','test'),(2,'test1','test1'); +SELECT pseudo as a, pseudo as b FROM t1 GROUP BY (SELECT a) ORDER BY (SELECT id*1); +drop table if exists t1; + +(SELECT 1 as a) UNION (SELECT 1) ORDER BY (SELECT a+0); + +# +# IN subselect optimization test +# +create table t1 (a int not null, b int, primary key (a)); +create table t2 (a int not null, primary key (a)); +create table t3 (a int not null, b int, primary key (a)); +insert into t1 values (1,10), (2,20), (3,30), (4,40); +insert into t2 values (2), (3), (4), (5); +insert into t3 values (10,3), (20,4), (30,5); +select * from t2 where t2.a in (select a from t1); +explain extended select * from t2 where t2.a in (select a from t1); +select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +drop table t1, t2, t3; +create table t1 (a int, b int, index a (a,b)); +create table t2 (a int, index a (a)); +create table t3 (a int, b int, index a (a)); +insert into t1 values (1,10), (2,20), (3,30), (4,40); +disable_query_log; +# making table large enough +let $1 = 10000; +while ($1) + { + eval insert into t1 values (rand()*100000+200,rand()*100000); + dec $1; + } +enable_query_log; +insert into t2 values (2), (3), (4), (5); +insert into t3 values (10,3), (20,4), (30,5); +select * from t2 where t2.a in (select a from t1); +explain extended select * from t2 where t2.a in (select a from t1); +select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +insert into t1 values (3,31); +select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +select * from t2 where t2.a in (select a from t1 where t1.b <> 30 and t1.b <> 31); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +drop table t1, t2, t3; + +# +# alloc_group_fields() working +# +create table t1 (a int, b int); +create table t2 (a int, b int); +create table t3 (a int, b int); +insert into t1 values (0,100),(1,2), (1,3), (2,2), (2,7), (2,-1), (3,10); +insert into t2 values (0,0), (1,1), (2,1), (3,1), (4,1); +insert into t3 values (3,3), (2,2), (1,1); +select a,(select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3; +drop table t1,t2,t3; + +# +# aggregate functions in HAVING test +# +create table t1 (s1 int); +create table t2 (s1 int); +insert into t1 values (1); +insert into t2 values (1); +select * from t1 where exists (select s1 from t2 having max(t2.s1)=t1.s1); +drop table t1,t2; + +# +# update subquery with wrong field (to force name resolving +# in UPDATE name space) +# +create table t1 (s1 int); +create table t2 (s1 int); +insert into t1 values (1); +insert into t2 values (1); +-- error 1054 +update t1 set s1 = s1 + 1 where 1 = (select x.s1 as A from t2 WHERE t2.s1 > t1.s1 order by A); +DROP TABLE t1, t2; + +# +# collation test +# +CREATE TABLE t1 (s1 CHAR(5) COLLATE latin1_german1_ci, + s2 CHAR(5) COLLATE latin1_swedish_ci); +INSERT INTO t1 VALUES ('z','?'); +-- error 1267 +select * from t1 where s1 > (select max(s2) from t1); +-- error 1267 +select * from t1 where s1 > any (select max(s2) from t1); +drop table t1; + +# +# aggregate functions reinitialization +# +create table t1(toid int,rd int); +create table t2(userid int,pmnew int,pmtotal int); +insert into t2 values(1,0,0),(2,0,0); +insert into t1 values(1,0),(1,0),(1,0),(1,12),(1,15),(1,123),(1,12312),(1,12312),(1,123),(2,0),(2,0),(2,1),(2,2); +select userid,pmtotal,pmnew, (select count(rd) from t1 where toid=t2.userid) calc_total, (select count(rd) from t1 where rd=0 and toid=t2.userid) calc_new from t2 where userid in (select distinct toid from t1); +drop table t1, t2; + +# +# row union +# +create table t1 (s1 char(5)); +-- error 1241 +select (select 'a','b' from t1 union select 'a','b' from t1) from t1; +insert into t1 values ('tttt'); +select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); +explain extended (select * from t1); +(select * from t1); +drop table t1; + +# +# IN optimisation test results +# +create table t1 (s1 char(5), index s1(s1)); +create table t2 (s1 char(5), index s1(s1)); +insert into t1 values ('a1'),('a2'),('a3'); +insert into t2 values ('a1'),('a2'); +select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; +select s1, s1 = ANY (SELECT s1 FROM t2) from t1; +select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; +select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; +explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; +explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1; +explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; +explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; +drop table t1,t2; + +# +# correct ALL optimisation +# +create table t2 (a int, b int); +create table t3 (a int); +insert into t3 values (6),(7),(3); +select * from t3 where a >= all (select b from t2); +explain extended select * from t3 where a >= all (select b from t2); +select * from t3 where a >= some (select b from t2); +explain extended select * from t3 where a >= some (select b from t2); +select * from t3 where a >= all (select b from t2 group by 1); +explain extended select * from t3 where a >= all (select b from t2 group by 1); +select * from t3 where a >= some (select b from t2 group by 1); +explain extended select * from t3 where a >= some (select b from t2 group by 1); +select * from t3 where NULL >= any (select b from t2); +explain extended select * from t3 where NULL >= any (select b from t2); +select * from t3 where NULL >= any (select b from t2 group by 1); +explain extended select * from t3 where NULL >= any (select b from t2 group by 1); +select * from t3 where NULL >= some (select b from t2); +explain extended select * from t3 where NULL >= some (select b from t2); +select * from t3 where NULL >= some (select b from t2 group by 1); +explain extended select * from t3 where NULL >= some (select b from t2 group by 1); +# +# optimized static ALL/ANY with grouping +# +insert into t2 values (2,2), (2,1), (3,3), (3,1); +select * from t3 where a > all (select max(b) from t2 group by a); +explain extended select * from t3 where a > all (select max(b) from t2 group by a); +drop table t2, t3; + +# +# correct used_tables() +# + +CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ; +INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now()); +CREATE TABLE `t2` (`db_id` int(11) NOT NULL auto_increment,`name` varchar(200) NOT NULL default '',`primary_uid` smallint(6) NOT NULL default '0',`secondary_uid` smallint(6) NOT NULL default '0',PRIMARY KEY (`db_id`),UNIQUE KEY `name_2` (`name`),FULLTEXT KEY `name` (`name`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=2147483647; +INSERT INTO `t2` (`db_id`, `name`, `primary_uid`, `secondary_uid`) VALUES (18, 'Not Set 1', 0, 0),(19, 'Valid', 1, 2),(20, 'Valid 2', 1, 2),(21, 'Should Not Return', 1, 2),(26, 'Not Set 2', 0, 0),(-1, 'ALL DB\'S', 0, 0); +CREATE TABLE `t3` (`taskgenid` mediumint(9) NOT NULL auto_increment,`dbid` int(11) NOT NULL default '0',`taskid` int(11) NOT NULL default '0',`mon` tinyint(4) NOT NULL default '1',`tues` tinyint(4) NOT NULL default '1',`wed` tinyint(4) NOT NULL default '1',`thur` tinyint(4) NOT NULL default '1',`fri` tinyint(4) NOT NULL default '1',`sat` tinyint(4) NOT NULL default '0',`sun` tinyint(4) NOT NULL default '0',`how_often` smallint(6) NOT NULL default '1',`userid` smallint(6) NOT NULL default '0',`active` tinyint(4) NOT NULL default '1',PRIMARY KEY (`taskgenid`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=2 ; +INSERT INTO `t3` (`taskgenid`, `dbid`, `taskid`, `mon`, `tues`,`wed`, `thur`, `fri`, `sat`, `sun`, `how_often`, `userid`, `active`) VALUES (1,-1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1); +CREATE TABLE `t4` (`task_id` smallint(6) NOT NULL default '0',`description` varchar(200) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; +INSERT INTO `t4` (`task_id`, `description`) VALUES (1, 'Daily Check List'),(2, 'Weekly Status'); +select dbid, name, (date_format(now() , '%Y-%m-%d') - INTERVAL how_often DAY) >= ifnull((SELECT date_format(max(create_date),'%Y-%m-%d') FROM t1 WHERE dbid = b.db_id AND taskid = a.taskgenid), '1950-01-01') from t3 a, t2 b, t4 WHERE dbid = - 1 AND primary_uid = '1' AND t4.task_id = taskid; +SELECT dbid, name FROM t3 a, t2 b, t4 WHERE dbid = - 1 AND primary_uid = '1' AND ((date_format(now() , '%Y-%m-%d') - INTERVAL how_often DAY) >= ifnull((SELECT date_format(max(create_date),'%Y-%m-%d') FROM t1 WHERE dbid = b.db_id AND taskid = a.taskgenid), '1950-01-01')) AND t4.task_id = taskid; +drop table t1,t2,t3,t4; + +# +# cardinality check +# +CREATE TABLE t1 (id int(11) default NULL) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES (1),(5); +CREATE TABLE t2 (id int(11) default NULL) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t2 VALUES (2),(6); +-- error 1241 +select * from t1 where (1,2,6) in (select * from t2); +DROP TABLE t1,t2; + +# +# DO and SET with errors +# +create table t1 (s1 int); +insert into t1 values (1); +insert into t1 values (2); +-- error 1242 +set sort_buffer_size = (select s1 from t1); +do (select * from t1); +drop table t1; + +# +# optimized ALL/ANY with union +# +create table t1 (s1 char); +insert into t1 values ('e'); +select * from t1 where 'f' > any (select s1 from t1); +select * from t1 where 'f' > any (select s1 from t1 union select s1 from t1); +explain extended select * from t1 where 'f' > any (select s1 from t1 union select s1 from t1); +drop table t1; + +# +# filesort in subquery (restoring join_tab) +# +CREATE TABLE t1 (number char(11) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t1 VALUES ('69294728265'),('18621828126'),('89356874041'),('95895001874'); +CREATE TABLE t2 (code char(5) NOT NULL default '',UNIQUE KEY code (code)) ENGINE=MyISAM CHARSET=latin1; +INSERT INTO t2 VALUES ('1'),('1226'),('1245'),('1862'),('18623'),('1874'),('1967'),('6'); +select c.number as phone,(select p.code from t2 p where c.number like concat(p.code, '%') order by length(p.code) desc limit 1) as code from t1 c; +drop table t1, t2; + +# +# unresolved field error +# +create table t1 (s1 int); +create table t2 (s1 int); +-- error 1054 +select * from t1 where (select count(*) from t2 where t1.s2) = 1; +-- error 1054 +select * from t1 where (select count(*) from t2 group by t1.s2) = 1; +-- error 1054 +select count(*) from t2 group by t1.s2; +drop table t1, t2; + +# +# fix_fields() in add_ref_to_table_cond() +# +CREATE TABLE t1(COLA FLOAT NOT NULL,COLB FLOAT NOT NULL,COLC VARCHAR(20) DEFAULT NULL,PRIMARY KEY (COLA, COLB)); +CREATE TABLE t2(COLA FLOAT NOT NULL,COLB FLOAT NOT NULL,COLC CHAR(1) NOT NULL,PRIMARY KEY (COLA)); +INSERT INTO t1 VALUES (1,1,'1A3240'), (1,2,'4W2365'); +INSERT INTO t2 VALUES (100, 200, 'C'); +SELECT DISTINCT COLC FROM t1 WHERE COLA = (SELECT COLA FROM t2 WHERE COLB = 200 AND COLC ='C' LIMIT 1); +DROP TABLE t1, t2; + +CREATE TABLE t1 (a int(1)); +INSERT INTO t1 VALUES (1),(1),(1),(1),(1),(2),(3),(4),(5); +SELECT DISTINCT (SELECT a) FROM t1 LIMIT 100; +DROP TABLE t1; + +# +# Bug 2198 +# + +create table t1 (a int, b decimal(13, 3)); +insert into t1 values (1, 0.123); +select a, (select max(b) from t1) into outfile "subselect.out.file.1" from t1; +delete from t1; +load data infile "subselect.out.file.1" into table t1; +select * from t1; +drop table t1; + +# +# Bug 2479 +# + +CREATE TABLE `t1` ( + `id` int(11) NOT NULL auto_increment, + `id_cns` tinyint(3) unsigned NOT NULL default '0', + `tipo` enum('','UNO','DUE') NOT NULL default '', + `anno_dep` smallint(4) unsigned zerofill NOT NULL default '0000', + `particolare` mediumint(8) unsigned NOT NULL default '0', + `generale` mediumint(8) unsigned NOT NULL default '0', + `bis` tinyint(3) unsigned NOT NULL default '0', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_cns_gen_anno` (`anno_dep`,`id_cns`,`generale`,`particolare`), + UNIQUE KEY `idx_cns_par_anno` (`id_cns`,`anno_dep`,`tipo`,`particolare`,`bis`) +); +INSERT INTO `t1` VALUES (1,16,'UNO',1987,2048,9681,0),(2,50,'UNO',1987,1536,13987,0),(3,16,'UNO',1987,2432,14594,0),(4,16,'UNO',1987,1792,13422,0),(5,16,'UNO',1987,1025,10240,0),(6,16,'UNO',1987,1026,7089,0); +CREATE TABLE `t2` ( + `id` tinyint(3) unsigned NOT NULL auto_increment, + `max_anno_dep` smallint(6) unsigned NOT NULL default '0', + PRIMARY KEY (`id`) +); +INSERT INTO `t2` VALUES (16,1987),(50,1990),(51,1990); + +SELECT cns.id, cns.max_anno_dep, cns.max_anno_dep = (SELECT s.anno_dep FROM t1 AS s WHERE s.id_cns = cns.id ORDER BY s.anno_dep DESC LIMIT 1) AS PIPPO FROM t2 AS cns; + +DROP TABLE t1, t2; + +# +# GLOBAL LIMIT +# +create table t1 (a int); +insert into t1 values (1), (2), (3); +SET SQL_SELECT_LIMIT=1; +select sum(a) from (select * from t1) as a; +select 2 in (select * from t1); +SET SQL_SELECT_LIMIT=default; +drop table t1; + +# +# Bug #3118: subselect + order by +# + +CREATE TABLE t1 (a int, b int, INDEX (a)); +INSERT INTO t1 VALUES (1, 1), (1, 2), (1, 3); +SELECT * FROM t1 WHERE a = (SELECT MAX(a) FROM t1 WHERE a = 1) ORDER BY b; +DROP TABLE t1; + +# Item_cond fix field +# +create table t1(val varchar(10)); +insert into t1 values ('aaa'), ('bbb'),('eee'),('mmm'),('ppp'); +select count(*) from t1 as w1 where w1.val in (select w2.val from t1 as w2 where w2.val like 'm%') and w1.val in (select w3.val from t1 as w3 where w3.val like 'e%'); +drop table t1; + +# +# ref_or_null replacing with ref +# +create table t1 (id int not null, text varchar(20) not null default '', primary key (id)); +insert into t1 (id, text) values (1, 'text1'), (2, 'text2'), (3, 'text3'), (4, 'text4'), (5, 'text5'), (6, 'text6'), (7, 'text7'), (8, 'text8'), (9, 'text9'), (10, 'text10'), (11, 'text11'), (12, 'text12'); +select * from t1 where id not in (select id from t1 where id < 8); +select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null); +explain extended select * from t1 where id not in (select id from t1 where id < 8); +explain extended select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null); +insert into t1 (id, text) values (1000, 'text1000'), (1001, 'text1001'); +create table t2 (id int not null, text varchar(20) not null default '', primary key (id)); +insert into t2 (id, text) values (1, 'text1'), (2, 'text2'), (3, 'text3'), (4, 'text4'), (5, 'text5'), (6, 'text6'), (7, 'text7'), (8, 'text8'), (9, 'text9'), (10, 'text10'), (11, 'text1'), (12, 'text2'), (13, 'text3'), (14, 'text4'), (15, 'text5'), (16, 'text6'), (17, 'text7'), (18, 'text8'), (19, 'text9'), (20, 'text10'),(21, 'text1'), (22, 'text2'), (23, 'text3'), (24, 'text4'), (25, 'text5'), (26, 'text6'), (27, 'text7'), (28, 'text8'), (29, 'text9'), (30, 'text10'), (31, 'text1'), (32, 'text2'), (33, 'text3'), (34, 'text4'), (35, 'text5'), (36, 'text6'), (37, 'text7'), (38, 'text8'), (39, 'text9'), (40, 'text10'), (41, 'text1'), (42, 'text2'), (43, 'text3'), (44, 'text4'), (45, 'text5'), (46, 'text6'), (47, 'text7'), (48, 'text8'), (49, 'text9'), (50, 'text10'); +select * from t1 a left join t2 b on (a.id=b.id or b.id is null) join t1 c on (if(isnull(b.id), 1000, b.id)=c.id); +explain extended select * from t1 a left join t2 b on (a.id=b.id or b.id is null) join t1 c on (if(isnull(b.id), 1000, b.id)=c.id); +drop table t1,t2; + +# +# Static tables & rund() in subqueries +# +create table t1 (a int); +insert into t1 values (1); +explain select benchmark(1000, (select a from t1 where a=sha(rand()))); +drop table t1; + +# +# bug 3188 +# +create table t1(id int); +create table t2(id int); +create table t3(flag int); +-- error 1064 +select (select * from t3 where id not null) from t1, t2; +drop table t1,t2,t3; + +# +# aggregate functions (Bug #3505) +# +CREATE TABLE t1 (id INT); +CREATE TABLE t2 (id INT); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1); +SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); +SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id); +SELECT t1.id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY t1.id; +SELECT id, ( SELECT COUNT(t.id) FROM t2 AS t WHERE t.id = t1.id ) AS c FROM t1 LEFT JOIN t2 USING (id) ORDER BY id; +DROP TABLE t1,t2; + +# +# ALL/ANY test +# +CREATE TABLE t1 ( a int, b int ); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +SELECT a FROM t1 WHERE a > ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a < ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a = ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a >= ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a <= ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a <> ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a > ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a < ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a = ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a >= ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a <= ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a <> ALL ( SELECT a FROM t1 WHERE b = 2 ); +# with index +ALTER TABLE t1 ADD INDEX (a); +SELECT a FROM t1 WHERE a > ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a < ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a = ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a >= ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a <= ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a <> ANY ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a > ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a < ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a = ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a >= ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a <= ALL ( SELECT a FROM t1 WHERE b = 2 ); +SELECT a FROM t1 WHERE a <> ALL ( SELECT a FROM t1 WHERE b = 2 ); +# having clause test +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 HAVING a = 2); +# union test +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 WHERE b = 2 UNION SELECT a FROM t1 WHERE b = 2); +# union + having test +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 HAVING a = 2 UNION SELECT a FROM t1 HAVING a = 2); +# row tests +# < > >= <= and = ALL/ <> ANY do not support row operation +-- error 1241 +SELECT a FROM t1 WHERE (1,2) > ANY (SELECT a FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE a > ANY (SELECT a,2 FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE (1,2) > ANY (SELECT a,2 FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE (1,2) > ALL (SELECT a FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE a > ALL (SELECT a,2 FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE (1,2) > ALL (SELECT a,2 FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE (1,2) = ALL (SELECT a,2 FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE (1,2) <> ANY (SELECT a,2 FROM t1 WHERE b = 2); +# following should be converted to IN +-- error 1241 +SELECT a FROM t1 WHERE (1,2) = ANY (SELECT a FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE a = ANY (SELECT a,2 FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE (1,2) = ANY (SELECT a,2 FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE (1,2) <> ALL (SELECT a FROM t1 WHERE b = 2); +-- error 1241 +SELECT a FROM t1 WHERE a <> ALL (SELECT a,2 FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE (1,2) <> ALL (SELECT a,2 FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE (a,1) = ANY (SELECT a,1 FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE (a,1) <> ALL (SELECT a,1 FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE (a,1) = ANY (SELECT a,1 FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE (a,1) <> ALL (SELECT a,1 FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE (a,1) = ANY (SELECT a,1 FROM t1 WHERE b = 2 UNION SELECT a,1 FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE (a,1) <> ALL (SELECT a,1 FROM t1 WHERE b = 2 UNION SELECT a,1 FROM t1 WHERE b = 2); +SELECT a FROM t1 WHERE (a,1) = ANY (SELECT a,1 FROM t1 HAVING a = 2 UNION SELECT a,1 FROM t1 HAVING a = 2); +SELECT a FROM t1 WHERE (a,1) <> ALL (SELECT a,1 FROM t1 HAVING a = 2 UNION SELECT a,1 FROM t1 HAVING a = 2); +# without optimisation +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 WHERE b = 2 group by a); +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 WHERE b = 2 group by a); +# without optimisation + having +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 group by a HAVING a = 2); +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 group by a HAVING a = 2); +# EXISTS in string contence +SELECT concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a > t1.a), '-') from t1 a; +SELECT concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a < t1.a), '-') from t1 a; +SELECT concat(EXISTS(SELECT a FROM t1 WHERE b = 2 and a.a = t1.a), '-') from t1 a; +DROP TABLE t1; +CREATE TABLE t1 ( a double, b double ); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 WHERE b = 2e0); +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 WHERE b = 2e0); +DROP TABLE t1; +CREATE TABLE t1 ( a char(1), b char(1)); +INSERT INTO t1 VALUES ('1','1'),('2','2'),('3','3'); +SELECT a FROM t1 WHERE a > ANY (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a < ANY (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a = ANY (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a >= ANY (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a <= ANY (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a <> ANY (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a > ALL (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a < ALL (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a = ALL (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a >= ALL (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a <= ALL (SELECT a FROM t1 WHERE b = '2'); +SELECT a FROM t1 WHERE a <> ALL (SELECT a FROM t1 WHERE b = '2'); +DROP TABLE t1; + + +# +# SELECT(EXISTS * ...)optimisation +# +create table t1 (a int, b int); +insert into t1 values (1,2),(3,4); +select * from t1 up where exists (select * from t1 where t1.a=up.a); +explain extended select * from t1 up where exists (select * from t1 where t1.a=up.a); +drop table t1; + +# +# Bug #4102: subselect in HAVING +# + +CREATE TABLE t1 (t1_a int); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (t2_a int, t2_b int, PRIMARY KEY (t2_a, t2_b)); +INSERT INTO t2 VALUES (1, 1), (1, 2); +SELECT * FROM t1, t2 table2 WHERE t1_a = 1 AND table2.t2_a = 1 + HAVING table2.t2_b = (SELECT MAX(t2_b) FROM t2 WHERE t2_a = table2.t2_a); +DROP TABLE t1, t2; + +# +# Test problem with NULL and derived tables (Bug #4097) +# + +CREATE TABLE t1 (id int(11) default NULL,name varchar(10) default NULL); +INSERT INTO t1 VALUES (1,'Tim'),(2,'Rebecca'),(3,NULL); +CREATE TABLE t2 (id int(11) default NULL, pet varchar(10) default NULL); +INSERT INTO t2 VALUES (1,'Fido'),(2,'Spot'),(3,'Felix'); +SELECT a.*, b.* FROM (SELECT * FROM t1) AS a JOIN t2 as b on a.id=b.id; +drop table t1,t2; + +# +# outer fields resolving in INSERT/REPLACE and CRETE with SELECT +# +CREATE TABLE t1 ( a int, b int ); +CREATE TABLE t2 ( c int, d int ); +INSERT INTO t1 VALUES (1,2), (2,3), (3,4); +SELECT a AS abc, b FROM t1 outr WHERE b = + (SELECT MIN(b) FROM t1 WHERE a=outr.a); +INSERT INTO t2 SELECT a AS abc, b FROM t1 outr WHERE b = + (SELECT MIN(b) FROM t1 WHERE a=outr.a); +select * from t2; +CREATE TABLE t3 SELECT a AS abc, b FROM t1 outr WHERE b = + (SELECT MIN(b) FROM t1 WHERE a=outr.a); +select * from t3; +prepare stmt1 from "INSERT INTO t2 SELECT a AS abc, b FROM t1 outr WHERE b = (SELECT MIN(b) FROM t1 WHERE a=outr.a);"; +execute stmt1; +deallocate prepare stmt1; +select * from t2; +drop table t3; +prepare stmt1 from "CREATE TABLE t3 SELECT a AS abc, b FROM t1 outr WHERE b = (SELECT MIN(b) FROM t1 WHERE a=outr.a);"; +execute stmt1; +select * from t3; +deallocate prepare stmt1; +DROP TABLE t1, t2, t3; + +# +# Aggregate function comparation with ALL/ANY/SOME subselect +# +CREATE TABLE `t1` ( `a` int(11) default NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1; +insert into t1 values (1); +CREATE TABLE `t2` ( `b` int(11) default NULL, `a` int(11) default NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1; +insert into t2 values (1,2); +select t000.a, count(*) `C` FROM t1 t000 GROUP BY t000.a HAVING count(*) > ALL (SELECT count(*) FROM t2 t001 WHERE t001.a=1); +drop table t1,t2; + +# +# BUG#4769 - fulltext in subselect +# +create table t1 (a int not null auto_increment primary key, b varchar(40), fulltext(b)) engine=myisam; # PBXT: Full-text engine required +insert into t1 (b) values ('ball'),('ball games'), ('games'), ('foo'), ('foobar'), ('Serg'), ('Sergei'),('Georg'), ('Patrik'),('Hakan'); +create table t2 (a int); +insert into t2 values (1),(3),(2),(7); +select a,b from t1 where match(b) against ('Ball') > 0; +select a from t2 where a in (select a from t1 where match(b) against ('Ball') > 0); +drop table t1,t2; + +# +# BUG#5003 - like in subselect +# +CREATE TABLE t1(`IZAVORGANG_ID` VARCHAR(11) CHARACTER SET latin1 COLLATE latin1_bin,`KUERZEL` VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_bin,`IZAANALYSEART_ID` VARCHAR(11) CHARACTER SET latin1 COLLATE latin1_bin,`IZAPMKZ_ID` VARCHAR(11) CHARACTER SET latin1 COLLATE latin1_bin); +CREATE INDEX AK01IZAVORGANG ON t1(izaAnalyseart_id,Kuerzel); +INSERT INTO t1(`IZAVORGANG_ID`,`KUERZEL`,`IZAANALYSEART_ID`,`IZAPMKZ_ID`)VALUES('D0000000001','601','D0000000001','I0000000001'); +INSERT INTO t1(`IZAVORGANG_ID`,`KUERZEL`,`IZAANALYSEART_ID`,`IZAPMKZ_ID`)VALUES('D0000000002','602','D0000000001','I0000000001'); +INSERT INTO t1(`IZAVORGANG_ID`,`KUERZEL`,`IZAANALYSEART_ID`,`IZAPMKZ_ID`)VALUES('D0000000003','603','D0000000001','I0000000001'); +INSERT INTO t1(`IZAVORGANG_ID`,`KUERZEL`,`IZAANALYSEART_ID`,`IZAPMKZ_ID`)VALUES('D0000000004','101','D0000000001','I0000000001'); +SELECT `IZAVORGANG_ID` FROM t1 WHERE `KUERZEL` IN(SELECT MIN(`KUERZEL`)`Feld1` FROM t1 WHERE `KUERZEL` LIKE'601%'And`IZAANALYSEART_ID`='D0000000001'); +drop table t1; + +# +# Optimized IN with compound index +# +CREATE TABLE `t1` ( `aid` int(11) NOT NULL default '0', `bid` int(11) NOT NULL default '0', PRIMARY KEY (`aid`,`bid`)); +CREATE TABLE `t2` ( `aid` int(11) NOT NULL default '0', `bid` int(11) NOT NULL default '0', PRIMARY KEY (`aid`,`bid`)); +insert into t1 values (1,1),(1,2),(2,1),(2,2); +insert into t2 values (1,2),(2,2); +select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid); +alter table t2 drop primary key; +alter table t2 add key KEY1 (aid, bid); +select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid); +alter table t2 drop key KEY1; +alter table t2 add primary key (bid, aid); +select * from t1 where t1.aid not in (select aid from t2 where bid=t1.bid); +drop table t1,t2; + +# +# resolving fields of grouped outer SELECT +# +CREATE TABLE t1 (howmanyvalues bigint, avalue int); +INSERT INTO t1 VALUES (1, 1),(2, 1),(2, 2),(3, 1),(3, 2),(3, 3),(4, 1),(4, 2),(4, 3),(4, 4); +SELECT howmanyvalues, count(*) from t1 group by howmanyvalues; +SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues = a.howmanyvalues) as mycount from t1 a group by a.howmanyvalues; +CREATE INDEX t1_howmanyvalues_idx ON t1 (howmanyvalues); +SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues+1 = a.howmanyvalues+1) as mycount from t1 a group by a.howmanyvalues; +SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues = a.howmanyvalues) as mycount from t1 a group by a.howmanyvalues; +SELECT a.howmanyvalues, (SELECT count(*) from t1 b where b.howmanyvalues = a.avalue) as mycount from t1 a group by a.howmanyvalues; +drop table t1; + +create table t1 (x int); +select (select b.x from t1 as b where b.x=a.x) from t1 as a where a.x=2 group by a.x; +drop table t1; + +# +# Test of correct maybe_null flag returning by subquwery for temporary table +# creation +# +CREATE TABLE `t1` ( `master` int(10) unsigned NOT NULL default '0', `map` smallint(6) unsigned NOT NULL default '0', `slave` int(10) unsigned NOT NULL default '0', `access` int(10) unsigned NOT NULL default '0', UNIQUE KEY `access_u` (`master`,`map`,`slave`)); +INSERT INTO `t1` VALUES (1,0,0,700),(1,1,1,400),(1,5,5,400),(1,12,12,400),(1,12,32,400),(4,12,32,400); +CREATE TABLE `t2` ( `id` int(10) unsigned NOT NULL default '0', `pid` int(10) unsigned NOT NULL default '0', `map` smallint(6) unsigned NOT NULL default '0', `level` tinyint(4) unsigned NOT NULL default '0', `title` varchar(255) default NULL, PRIMARY KEY (`id`,`pid`,`map`), KEY `level` (`level`), KEY `id` (`id`,`map`)) ; +INSERT INTO `t2` VALUES (6,5,12,7,'a'),(12,0,0,7,'a'),(12,1,0,7,'a'),(12,5,5,7,'a'),(12,5,12,7,'a'); +-- error 1054 +SELECT b.sc FROM (SELECT (SELECT a.access FROM t1 a WHERE a.map = op.map AND a.slave = op.pid AND a.master = 1) ac FROM t2 op WHERE op.id = 12 AND op.map = 0) b; +SELECT b.ac FROM (SELECT (SELECT a.access FROM t1 a WHERE a.map = op.map AND a.slave = op.pid AND a.master = 1) ac FROM t2 op WHERE op.id = 12 AND op.map = 0) b; +drop tables t1,t2; + +# +# Test for bug #6462. "Same request on same data returns different +# results." a.k.a. "Proper cleanup of subqueries is missing for +# SET and DO statements". +# +create table t1 (a int not null, b int not null, c int, primary key (a,b)); +insert into t1 values (1,1,1), (2,2,2), (3,3,3); +set @b:= 0; +# Let us check that subquery will use covering index +explain select sum(a) from t1 where b > @b; +# This should not crash -debug server due to failing assertion +set @a:= (select sum(a) from t1 where b > @b); +# And this should not falsely report index usage +explain select a from t1 where c=2; +# Same for DO statement +do @a:= (select sum(a) from t1 where b > @b); +explain select a from t1 where c=2; +drop table t1; + +# +# Subselect in non-select command just after connection +# +connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connection root; +set @got_val= (SELECT 1 FROM (SELECT 'A' as my_col) as T1 ) ; + +# +# primary query with temporary table and subquery with groupping +# +create table t1 (a int, b int); +create table t2 (a int, b int); +insert into t1 values (1,1),(1,2),(1,3),(2,4),(2,5); +insert into t2 values (1,3),(2,1); +select distinct a,b, (select max(b) from t2 where t1.b=t2.a) from t1 order by t1.b; +drop table t1, t2; + +# +# subqueries with full text search +# +create table t1 (id int); +create table t2 (id int, body text, fulltext (body)) engine=myisam; # PBXT: Full-text engine required +insert into t1 values(1),(2),(3); +insert into t2 values (1,'test'), (2,'mysql'), (3,'test'), (4,'test'); +select count(distinct id) from t1 where id in (select id from t2 where match(body) against ('mysql' in boolean mode)); +drop table t2,t1; + +# +# Equal operation under row and empty subquery +# +create table t1 (s1 int,s2 int); +insert into t1 values (20,15); +select * from t1 where (('a',null) <=> (select 'a',s2 from t1 where s1 = 0)); +drop table t1; + +# +# ALL/ANY with NULL +# +create table t1 (s1 int); +insert into t1 values (1),(null); +select * from t1 where s1 < all (select s1 from t1); +select s1, s1 < all (select s1 from t1) from t1; +drop table t1; + +# +# reference on changable fields from subquery +# +CREATE TABLE t1 ( + Code char(3) NOT NULL default '', + Name char(52) NOT NULL default '', + Continent enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') NOT NULL default 'Asia', + Region char(26) NOT NULL default '', + SurfaceArea float(10,2) NOT NULL default '0.00', + IndepYear smallint(6) default NULL, + Population int(11) NOT NULL default '0', + LifeExpectancy float(3,1) default NULL, + GNP float(10,2) default NULL, + GNPOld float(10,2) default NULL, + LocalName char(45) NOT NULL default '', + GovernmentForm char(45) NOT NULL default '', + HeadOfState char(60) default NULL, + Capital int(11) default NULL, + Code2 char(2) NOT NULL default '' +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('XXX','Xxxxx','Oceania','Xxxxxx',26.00,0,0,0,0,0,'Xxxxx','Xxxxx','Xxxxx',NULL,'XX'); +INSERT INTO t1 VALUES ('ASM','American Samoa','Oceania','Polynesia',199.00,0,68000,75.1,334.00,NULL,'Amerika Samoa','US Territory','George W. Bush',54,'AS'); +INSERT INTO t1 VALUES ('ATF','French Southern territories','Antarctica','Antarctica',7780.00,0,0,NULL,0.00,NULL,'Terres australes françaises','Nonmetropolitan Territory of France','Jacques Chirac',NULL,'TF'); +INSERT INTO t1 VALUES ('UMI','United States Minor Outlying Islands','Oceania','Micronesia/Caribbean',16.00,0,0,NULL,0.00,NULL,'United States Minor Outlying Islands','Dependent Territory of the US','George W. Bush',NULL,'UM'); +/*!40000 ALTER TABLE t1 ENABLE KEYS */; +SELECT DISTINCT Continent AS c FROM t1 outr WHERE + Code <> SOME ( SELECT Code FROM t1 WHERE Continent = outr.Continent AND + Population < 200); +drop table t1; + +# +# Test for BUG#7885: Server crash when 'any' subselect compared to +# non-existant field. +# +create table t1 (a1 int); +create table t2 (b1 int); +--error 1054 +select * from t1 where a2 > any(select b1 from t2); +select * from t1 where a1 > any(select b1 from t2); +drop table t1,t2; + + +# +# Comparison subquery with * and row +# +create table t1 (a integer, b integer); +select (select * from t1) = (select 1,2); +select (select 1,2) = (select * from t1); +# queries whih can be converted to IN +select row(1,2) = ANY (select * from t1); +select row(1,2) != ALL (select * from t1); +drop table t1; + +# +# Comparison subquery and row with nested rows +# +create table t1 (a integer, b integer); +-- error 1241 +select row(1,(2,2)) in (select * from t1 ); +-- error 1241 +select row(1,(2,2)) = (select * from t1 ); +-- error 1241 +select (select * from t1) = row(1,(2,2)); +drop table t1; + +# +# Forward reference detection +# +create table t1 (a integer); +insert into t1 values (1); +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx ; +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +select 1 as xx, 1 = ALL ( select 1 from t1 where 1 = xx ); +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx; +-- error 1247 +select 1 = ALL (select 1 from t1 where 1 = xx ), 1 as xx from DUAL; +drop table t1; + +# +# Test for BUG#8218 +# +CREATE TABLE t1 ( + categoryId int(11) NOT NULL, + courseId int(11) NOT NULL, + startDate datetime NOT NULL, + endDate datetime NOT NULL, + createDate datetime NOT NULL, + modifyDate timestamp NOT NULL, + attributes text NOT NULL +); +INSERT INTO t1 VALUES (1,41,'2004-02-09','2010-01-01','2004-02-09','2004-02-09',''), +(1,86,'2004-08-16','2004-08-16','2004-08-16','2004-08-16',''), +(1,87,'2004-08-16','2004-08-16','2004-08-16','2004-08-16',''), +(2,52,'2004-03-15','2004-10-01','2004-03-15','2004-09-17',''), +(2,53,'2004-03-16','2004-10-01','2004-03-16','2004-09-17',''), +(2,88,'2004-08-16','2004-08-16','2004-08-16','2004-08-16',''), +(2,89,'2004-08-16','2004-08-16','2004-08-16','2004-08-16',''), +(3,51,'2004-02-09','2010-01-01','2004-02-09','2004-02-09',''), +(5,12,'2004-02-18','2010-01-01','2004-02-18','2004-02-18',''); + +CREATE TABLE t2 ( + userId int(11) NOT NULL, + courseId int(11) NOT NULL, + date datetime NOT NULL +); +INSERT INTO t2 VALUES (5141,71,'2003-11-18'), +(5141,72,'2003-11-25'),(5141,41,'2004-08-06'), +(5141,52,'2004-08-06'),(5141,53,'2004-08-06'), +(5141,12,'2004-08-06'),(5141,86,'2004-10-21'), +(5141,87,'2004-10-21'),(5141,88,'2004-10-21'), +(5141,89,'2004-10-22'),(5141,51,'2004-10-26'); + + +CREATE TABLE t3 ( + groupId int(11) NOT NULL, + parentId int(11) NOT NULL, + startDate datetime NOT NULL, + endDate datetime NOT NULL, + createDate datetime NOT NULL, + modifyDate timestamp NOT NULL, + ordering int(11) +); +INSERT INTO t3 VALUES (12,9,'1000-01-01','3999-12-31','2004-01-29','2004-01-29',NULL); + +CREATE TABLE t4 ( + id int(11) NOT NULL, + groupTypeId int(11) NOT NULL, + groupKey varchar(50) NOT NULL, + name text, + ordering int(11), + description text, + createDate datetime NOT NULL, + modifyDate timestamp NOT NULL +); +INSERT INTO t4 VALUES (9,5,'stationer','stationer',0,'Stationer','2004-01-29','2004-01-29'), +(12,5,'group2','group2',0,'group2','2004-01-29','2004-01-29'); + +CREATE TABLE t5 ( + userId int(11) NOT NULL, + groupId int(11) NOT NULL, + createDate datetime NOT NULL, + modifyDate timestamp NOT NULL +); +INSERT INTO t5 VALUES (5141,12,'2004-08-06','2004-08-06'); + +select + count(distinct t2.userid) pass, + groupstuff.*, + count(t2.courseid) crse, + t1.categoryid, + t2.courseid, + date_format(date, '%b%y') as colhead +from t2 +join t1 on t2.courseid=t1.courseid +join +( + select + t5.userid, + parentid, + parentgroup, + childid, + groupname, + grouptypeid + from t5 + join + ( + select t4.id as parentid, + t4.name as parentgroup, + t4.id as childid, + t4.name as groupname, + t4.grouptypeid + from t4 + ) as gin on t5.groupid=gin.childid +) as groupstuff on t2.userid = groupstuff.userid +group by + groupstuff.groupname, colhead , t2.courseid; + +drop table t1, t2, t3, t4, t5; + +# +# Transformation in left expression of subquery (BUG#8888) +# +create table t1 (a int); +insert into t1 values (1), (2), (3); +SELECT 1 FROM t1 WHERE (SELECT 1) in (SELECT 1); +drop table t1; + +# +# subselect into HAVING clause (code covarage improvement) +# +create table t1 (a int); +create table t2 (a int); +insert into t1 values (1),(2); +insert into t2 values (0),(1),(2),(3); +select a from t2 where a in (select a from t1); +select a from t2 having a in (select a from t1); +prepare stmt1 from "select a from t2 where a in (select a from t1)"; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; +prepare stmt1 from "select a from t2 having a in (select a from t1)"; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; +drop table t1, t2; + +# +# single row subqueries and row operations (code covarage improvement) +# +create table t1 (a int, b int); +insert into t1 values (1,2); +-- error 1241 +select 1 = (select * from t1); +-- error 1241 +select (select * from t1) = 1; +-- error 1241 +select (1,2) = (select a from t1); +-- error 1241 +select (select a from t1) = (1,2); +-- error 1241 +select (1,2,3) = (select * from t1); +-- error 1241 +select (select * from t1) = (1,2,3); +drop table t1; + +# +# Item_int_with_ref check (BUG#10020) +# +CREATE TABLE `t1` ( + `itemid` bigint(20) unsigned NOT NULL auto_increment, + `sessionid` bigint(20) unsigned default NULL, + `time` int(10) unsigned NOT NULL default '0', + `type` set('A','D','E','F','G','I','L','N','U') collate latin1_general_ci NOT +NULL default '', + `data` text collate latin1_general_ci NOT NULL, + PRIMARY KEY (`itemid`) +) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +INSERT INTO `t1` VALUES (1, 1, 1, 'D', ''); +CREATE TABLE `t2` ( + `sessionid` bigint(20) unsigned NOT NULL auto_increment, + `pid` int(10) unsigned NOT NULL default '0', + `date` int(10) unsigned NOT NULL default '0', + `ip` varchar(15) collate latin1_general_ci NOT NULL default '', + PRIMARY KEY (`sessionid`) +) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +INSERT INTO `t2` VALUES (1, 1, 1, '10.10.10.1'); +SELECT s.ip, count( e.itemid ) FROM `t1` e JOIN t2 s ON s.sessionid = e.sessionid WHERE e.sessionid = ( SELECT sessionid FROM t2 ORDER BY sessionid DESC LIMIT 1 ) GROUP BY s.ip HAVING count( e.itemid ) >0 LIMIT 0 , 30; +drop tables t1,t2; + +# BUG#11821 : Select from subselect using aggregate function on an enum +# segfaults: +create table t1 (fld enum('0','1')); +insert into t1 values ('1'); +select * from (select max(fld) from t1) as foo; +drop table t1; + +# +# Bug #11867: queries with ROW(,elems>) IN (SELECT DISTINCT <cols> FROM ...) +# + +CREATE TABLE t1 (one int, two int, flag char(1)); +CREATE TABLE t2 (one int, two int, flag char(1)); +INSERT INTO t1 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); +INSERT INTO t2 VALUES(1,2,'Y'),(2,3,'Y'),(3,4,'Y'),(5,6,'N'),(7,8,'N'); + +SELECT * FROM t1 + WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t2 WHERE flag = 'N'); +SELECT * FROM t1 + WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); + +insert into t2 values (null,null,'N'); +insert into t2 values (null,3,'0'); +insert into t2 values (null,5,'0'); +insert into t2 values (10,null,'0'); +insert into t1 values (10,3,'0'); +insert into t1 values (10,5,'0'); +insert into t1 values (10,10,'0'); +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1; +SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1; +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; +explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0') as 'test' from t1; +explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N'); +explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1; +DROP TABLE t1,t2; + +# +# Bug #12392: where cond with IN predicate for rows and NULL values in table +# + +CREATE TABLE t1 (a char(5), b char(5)); +INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa'); + +SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb')); + +DROP TABLE t1; + +# +# Bug #11479: subquery over left join with an empty inner table +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int, b int); +CREATE TABLE t3 (b int NOT NULL); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (1,10), (3,30); + +SELECT * FROM t2 LEFT JOIN t3 ON t2.b=t3.b + WHERE t3.b IS NOT NULL OR t2.a > 10; +SELECT * FROM t1 + WHERE t1.a NOT IN (SELECT a FROM t2 LEFT JOIN t3 ON t2.b=t3.b + WHERE t3.b IS NOT NULL OR t2.a > 10); + +DROP TABLE t1,t2,t3; + +# +# Bug#18503: Queries with a quantified subquery returning empty set may +# return a wrong result. +# +CREATE TABLE t1 (f1 INT); +CREATE TABLE t2 (f2 INT); +INSERT INTO t1 VALUES (1); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2 WHERE 1=0); +INSERT INTO t2 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2 WHERE f2=0); +DROP TABLE t1, t2; + +# +# Bug#16302: Quantified subquery without any tables gives wrong results +# +select 1 from dual where 1 < any (select 2); +select 1 from dual where 1 < all (select 2); +select 1 from dual where 2 > any (select 1); +select 1 from dual where 2 > all (select 1); +select 1 from dual where 1 < any (select 2 from dual); +select 1 from dual where 1 < all (select 2 from dual where 1!=1); + +# BUG#20975 Wrong query results for subqueries within NOT +create table t1 (s1 char); +insert into t1 values (1),(2); + +select * from t1 where (s1 < any (select s1 from t1)); +select * from t1 where not (s1 < any (select s1 from t1)); + +select * from t1 where (s1 < ALL (select s1+1 from t1)); +select * from t1 where not(s1 < ALL (select s1+1 from t1)); + +select * from t1 where (s1+1 = ANY (select s1 from t1)); +select * from t1 where NOT(s1+1 = ANY (select s1 from t1)); + +select * from t1 where (s1 = ALL (select s1/s1 from t1)); +select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); +drop table t1; + +# +# Bug #16255: Subquery in where +# +create table t1 ( + retailerID varchar(8) NOT NULL, + statusID int(10) unsigned NOT NULL, + changed datetime NOT NULL, + UNIQUE KEY retailerID (retailerID, statusID, changed) +); + +INSERT INTO t1 VALUES("0026", "1", "2005-12-06 12:18:56"); +INSERT INTO t1 VALUES("0026", "2", "2006-01-06 12:25:53"); +INSERT INTO t1 VALUES("0037", "1", "2005-12-06 12:18:56"); +INSERT INTO t1 VALUES("0037", "2", "2006-01-06 12:25:53"); +INSERT INTO t1 VALUES("0048", "1", "2006-01-06 12:37:50"); +INSERT INTO t1 VALUES("0059", "1", "2006-01-06 12:37:50"); + +select * from t1 r1 + where (r1.retailerID,(r1.changed)) in + (SELECT r2.retailerId,(max(changed)) from t1 r2 + group by r2.retailerId); +drop table t1; + +# +# Bug #21180: Subselect with index for both WHERE and ORDER BY +# produces empty result +# +create table t1(a int, primary key (a)); +insert into t1 values (10); + +create table t2 (a int primary key, b varchar(32), c int, unique key b(c, b)); +insert into t2(a, c, b) values (1,10,'359'), (2,10,'35988'), (3,10,'35989'); + +explain SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r + ON r.a = (SELECT t2.a FROM t2 WHERE t2.c = t1.a AND t2.b <= '359899' + ORDER BY t2.c DESC, t2.b DESC LIMIT 1) WHERE t1.a = 10; +SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r + ON r.a = (SELECT t2.a FROM t2 WHERE t2.c = t1.a AND t2.b <= '359899' + ORDER BY t2.c DESC, t2.b DESC LIMIT 1) WHERE t1.a = 10; + +explain SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r + ON r.a = (SELECT t2.a FROM t2 WHERE t2.c = t1.a AND t2.b <= '359899' + ORDER BY t2.c, t2.b LIMIT 1) WHERE t1.a = 10; +SELECT sql_no_cache t1.a, r.a, r.b FROM t1 LEFT JOIN t2 r + ON r.a = (SELECT t2.a FROM t2 WHERE t2.c = t1.a AND t2.b <= '359899' + ORDER BY t2.c, t2.b LIMIT 1) WHERE t1.a = 10; + +drop table t1,t2; + +# +# Bug #21853: assert failure for a grouping query with +# an ALL/ANY quantified subquery in HAVING +# + +CREATE TABLE t1 ( + field1 int NOT NULL, + field2 int NOT NULL, + field3 int NOT NULL, + PRIMARY KEY (field1,field2,field3) +); +CREATE TABLE t2 ( + fieldA int NOT NULL, + fieldB int NOT NULL, + PRIMARY KEY (fieldA,fieldB) +); + +INSERT INTO t1 VALUES + (1,1,1), (1,1,2), (1,2,1), (1,2,2), (1,2,3), (1,3,1); +INSERT INTO t2 VALUES (1,1), (1,2), (1,3); + +SELECT field1, field2, COUNT(*) + FROM t1 GROUP BY field1, field2; + +SELECT field1, field2 + FROM t1 + GROUP BY field1, field2 + HAVING COUNT(*) >= ALL (SELECT fieldB + FROM t2 WHERE fieldA = field1); +SELECT field1, field2 + FROM t1 + GROUP BY field1, field2 + HAVING COUNT(*) < ANY (SELECT fieldB + FROM t2 WHERE fieldA = field1); + +DROP TABLE t1, t2; + +# +# Bug #23478: not top-level IN subquery returning a non-empty result set +# with possible NULL values by index access from the outer query +# + +CREATE TABLE t1(a int, INDEX (a)); +INSERT INTO t1 VALUES (1), (3), (5), (7); +INSERT INTO t1 VALUES (NULL); + +CREATE TABLE t2(a int); +INSERT INTO t2 VALUES (1),(2),(3); + +EXPLAIN SELECT a, a IN (SELECT a FROM t1) FROM t2; +SELECT a, a IN (SELECT a FROM t1) FROM t2; + +DROP TABLE t1,t2; + +# +# Bug #11302: getObject() returns a String for a sub-query of type datetime +# +CREATE TABLE t1 (a DATETIME); +INSERT INTO t1 VALUES ('1998-09-23'), ('2003-03-25'); + +CREATE TABLE t2 AS SELECT + (SELECT a FROM t1 WHERE a < '2000-01-01') AS sub_a + FROM t1 WHERE a > '2000-01-01'; +SHOW CREATE TABLE t2; + +CREATE TABLE t3 AS (SELECT a FROM t1 WHERE a < '2000-01-01') UNION (SELECT a FROM t1 WHERE a > '2000-01-01'); +SHOW CREATE TABLE t3; + +DROP TABLE t1,t2,t3; + +# +# Bug 24670: subquery witout tables but with a WHERE clause +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); + +SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) > 0; +SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL; +EXPLAIN SELECT a FROM t1 WHERE (SELECT 1 FROM DUAL WHERE 1=0) IS NULL; + +DROP TABLE t1; + +# +# Bug 24653: sorting by expressions containing subselects +# that return more than one row +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (2), (4), (1), (3); + +CREATE TABLE t2 (b int, c int); +INSERT INTO t2 VALUES + (2,1), (1,3), (2,1), (4,4), (2,2), (1,4); + +SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2 ); +--error 1242 +SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1); +SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 2), a; +--error 1242 +SELECT a FROM t1 ORDER BY (SELECT c FROM t2 WHERE b > 1), a; + +SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 2); +--error 1242 +SELECT b, MAX(c) FROM t2 GROUP BY b, (SELECT c FROM t2 WHERE b > 1); + + +SELECT a FROM t1 GROUP BY a + HAVING IFNULL((SELECT b FROM t2 WHERE b > 2), + (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3; +--error 1242 +SELECT a FROM t1 GROUP BY a + HAVING IFNULL((SELECT b FROM t2 WHERE b > 1), + (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3; + +SELECT a FROM t1 GROUP BY a + HAVING IFNULL((SELECT b FROM t2 WHERE b > 4), + (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)) > 3; +--error 1242 +SELECT a FROM t1 GROUP BY a + HAVING IFNULL((SELECT b FROM t2 WHERE b > 4), + (SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)) > 3; + +SELECT a FROM t1 + ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 2), + (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)); +--error 1242 +SELECT a FROM t1 + ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 1), + (SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)); + +SELECT a FROM t1 + ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4), + (SELECT c FROM t2 WHERE c=a AND b > 2 ORDER BY b)); +--error 1242 +SELECT a FROM t1 + ORDER BY IFNULL((SELECT b FROM t2 WHERE b > 4), + (SELECT c FROM t2 WHERE c=a AND b > 1 ORDER BY b)); + +DROP TABLE t1,t2; + +# End of 4.1 tests + +# +#decimal-related tests +# +create table t1 (df decimal(5,1)); +insert into t1 values(1.1); +insert into t1 values(2.2); + +select * from t1 where df <= all (select avg(df) from t1 group by df); +select * from t1 where df >= all (select avg(df) from t1 group by df); +drop table t1; + +create table t1 (df decimal(5,1)); +insert into t1 values(1.1); +select 1.1 * exists(select * from t1); +drop table t1; + +CREATE TABLE t1 ( + grp int(11) default NULL, + a decimal(10,2) default NULL); + +insert into t1 values (1, 1), (2, 2), (2, 3), (3, 4), (3, 5), (3, 6), (NULL, NULL); +select * from t1; +select min(a) from t1 group by grp; +drop table t1; + +# +# Test for bug #9338: lame substitution of c1 instead of c2 +# + +CREATE table t1 ( c1 integer ); +INSERT INTO t1 VALUES ( 1 ); +INSERT INTO t1 VALUES ( 2 ); +INSERT INTO t1 VALUES ( 3 ); + +CREATE TABLE t2 ( c2 integer ); +INSERT INTO t2 VALUES ( 1 ); +INSERT INTO t2 VALUES ( 4 ); +INSERT INTO t2 VALUES ( 5 ); + +SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2 WHERE c2 IN (1); + +SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2 + WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2 IN ( 1 ) ); + +DROP TABLE t1,t2; + +# +# Test for bug #9516: wrong evaluation of not_null_tables attribute in SQ +# +CREATE TABLE t1 ( c1 integer ); +INSERT INTO t1 VALUES ( 1 ); +INSERT INTO t1 VALUES ( 2 ); +INSERT INTO t1 VALUES ( 3 ); +INSERT INTO t1 VALUES ( 6 ); + +CREATE TABLE t2 ( c2 integer ); +INSERT INTO t2 VALUES ( 1 ); +INSERT INTO t2 VALUES ( 4 ); +INSERT INTO t2 VALUES ( 5 ); +INSERT INTO t2 VALUES ( 6 ); + +CREATE TABLE t3 ( c3 integer ); +INSERT INTO t3 VALUES ( 7 ); +INSERT INTO t3 VALUES ( 8 ); + +SELECT c1,c2 FROM t1 LEFT JOIN t2 ON c1 = c2 + WHERE EXISTS (SELECT c3 FROM t3 WHERE c2 IS NULL ); + +DROP TABLE t1,t2,t3; + +# +# Item_int_with_ref check (BUG#10020) +# +CREATE TABLE `t1` ( + `itemid` bigint(20) unsigned NOT NULL auto_increment, + `sessionid` bigint(20) unsigned default NULL, + `time` int(10) unsigned NOT NULL default '0', + `type` set('A','D','E','F','G','I','L','N','U') collate latin1_general_ci NOT +NULL default '', + `data` text collate latin1_general_ci NOT NULL, + PRIMARY KEY (`itemid`) +) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +INSERT INTO `t1` VALUES (1, 1, 1, 'D', ''); +CREATE TABLE `t2` ( + `sessionid` bigint(20) unsigned NOT NULL auto_increment, + `pid` int(10) unsigned NOT NULL default '0', + `date` int(10) unsigned NOT NULL default '0', + `ip` varchar(15) collate latin1_general_ci NOT NULL default '', + PRIMARY KEY (`sessionid`) +) DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +INSERT INTO `t2` VALUES (1, 1, 1, '10.10.10.1'); +SELECT s.ip, count( e.itemid ) FROM `t1` e JOIN t2 s ON s.sessionid = e.sessionid WHERE e.sessionid = ( SELECT sessionid FROM t2 ORDER BY sessionid DESC LIMIT 1 ) GROUP BY s.ip HAVING count( e.itemid ) >0 LIMIT 0 , 30; +drop tables t1,t2; + +# +# Correct building of equal fields list (do not include outer +# fields) (BUG#6384) +# +CREATE TABLE t1 (EMPNUM CHAR(3)); +CREATE TABLE t2 (EMPNUM CHAR(3) ); +INSERT INTO t1 VALUES ('E1'),('E2'); +INSERT INTO t2 VALUES ('E1'); +DELETE FROM t1 +WHERE t1.EMPNUM NOT IN + (SELECT t2.EMPNUM + FROM t2 + WHERE t1.EMPNUM = t2.EMPNUM); +select * from t1; +DROP TABLE t1,t2; + +# +# Test for bug #11487: range access in a subquery +# + +CREATE TABLE t1(select_id BIGINT, values_id BIGINT); +INSERT INTO t1 VALUES (1, 1); +CREATE TABLE t2 (select_id BIGINT, values_id BIGINT, + PRIMARY KEY(select_id,values_id)); +INSERT INTO t2 VALUES (0, 1), (0, 2), (0, 3), (1, 5); + +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 + WHERE select_id IN (1, 0)); +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 + WHERE select_id BETWEEN 0 AND 1); +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 + WHERE select_id = 0 OR select_id = 1); + +DROP TABLE t1, t2; + +# BUG#11821 : Select from subselect using aggregate function on an enum +# segfaults: +create table t1 (fld enum('0','1')); +insert into t1 values ('1'); +select * from (select max(fld) from t1) as foo; +drop table t1; + +# +# Test for bug #11762: subquery with an aggregate function in HAVING +# + +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (c int, d int); +CREATE TABLE t3 (e int); + +INSERT INTO t1 VALUES + (1,10), (2,10), (1,20), (2,20), (3,20), (2,30), (4,40); +INSERT INTO t2 VALUES + (2,10), (2,20), (4,10), (5,10), (3,20), (2,40); +INSERT INTO t3 VALUES (10), (30), (10), (20) ; + +SELECT a, MAX(b), MIN(b) FROM t1 GROUP BY a; +SELECT * FROM t2; +SELECT * FROM t3; + +SELECT a FROM t1 GROUP BY a + HAVING a IN (SELECT c FROM t2 WHERE MAX(b)>20); +SELECT a FROM t1 GROUP BY a + HAVING a IN (SELECT c FROM t2 WHERE MAX(b)<d); +SELECT a FROM t1 GROUP BY a + HAVING a IN (SELECT c FROM t2 WHERE MAX(b)>d); +SELECT a FROM t1 GROUP BY a + HAVING a IN (SELECT c FROM t2 + WHERE d >= SOME(SELECT e FROM t3 WHERE MAX(b)=e)); +SELECT a FROM t1 GROUP BY a + HAVING a IN (SELECT c FROM t2 + WHERE EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e <= d)); +SELECT a FROM t1 GROUP BY a + HAVING a IN (SELECT c FROM t2 + WHERE d > SOME(SELECT e FROM t3 WHERE MAX(b)=e)); +SELECT a FROM t1 GROUP BY a + HAVING a IN (SELECT c FROM t2 + WHERE EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e < d)); +SELECT a FROM t1 GROUP BY a + HAVING a IN (SELECT c FROM t2 + WHERE MIN(b) < d AND + EXISTS(SELECT e FROM t3 WHERE MAX(b)=e AND e <= d)); + +SELECT a, SUM(a) FROM t1 GROUP BY a; + +SELECT a FROM t1 + WHERE EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) = c) GROUP BY a; +SELECT a FROM t1 GROUP BY a + HAVING EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) = c); + +SELECT a FROM t1 + WHERE a < 3 AND + EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) != c) GROUP BY a; +SELECT a FROM t1 + WHERE a < 3 AND + EXISTS(SELECT c FROM t2 GROUP BY c HAVING SUM(a) != c); + +SELECT t1.a FROM t1 GROUP BY t1.a + HAVING t1.a < ALL(SELECT t2.c FROM t2 GROUP BY t2.c + HAVING EXISTS(SELECT t3.e FROM t3 GROUP BY t3.e + HAVING SUM(t1.a+t2.c) < t3.e/4)); +SELECT t1.a FROM t1 GROUP BY t1.a + HAVING t1.a > ALL(SELECT t2.c FROM t2 + WHERE EXISTS(SELECT t3.e FROM t3 GROUP BY t3.e + HAVING SUM(t1.a+t2.c) < t3.e/4)); +-- error 1111 +SELECT t1.a FROM t1 GROUP BY t1.a + HAVING t1.a > ALL(SELECT t2.c FROM t2 + WHERE EXISTS(SELECT t3.e FROM t3 + WHERE SUM(t1.a+t2.c) < t3.e/4)); +-- error 1111 +SELECT t1.a from t1 GROUP BY t1.a HAVING AVG(SUM(t1.b)) > 20; + +SELECT t1.a FROM t1 GROUP BY t1.a + HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c + HAVING AVG(t2.c+SUM(t1.b)) > 20); +SELECT t1.a FROM t1 GROUP BY t1.a + HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c + HAVING AVG(SUM(t1.b)) > 20); + +SELECT t1.a, SUM(b) AS sum FROM t1 GROUP BY t1.a + HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c + HAVING t2.c+sum > 20); + +DROP TABLE t1,t2,t3; + +# +# Test for bug #16603: GROUP BY in a row subquery with a quantifier +# when an index is defined on the grouping field + +CREATE TABLE t1 (a varchar(5), b varchar(10)); +INSERT INTO t1 VALUES + ('AAA', 5), ('BBB', 4), ('BBB', 1), ('CCC', 2), + ('CCC', 7), ('AAA', 2), ('AAA', 4), ('BBB', 3), ('AAA', 8); + +SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); +EXPLAIN +SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); + +ALTER TABLE t1 ADD INDEX(a); + +SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); +EXPLAIN +SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a); + +DROP TABLE t1; + +# +# Bug#17366: Unchecked Item_int results in server crash +# +create table t1( f1 int,f2 int); +insert into t1 values (1,1),(2,2); +select tt.t from (select 'crash1' as t, f2 from t1) as tt left join t1 on tt.t = 'crash2' and tt.f2 = t1.f2 where tt.t = 'crash1'; +drop table t1; + +# +# Bug #18306: server crash on delete using subquery. +# + +create table t1 (c int, key(c)); +insert into t1 values (1142477582), (1142455969); +create table t2 (a int, b int); +insert into t2 values (2, 1), (1, 0); +delete from t1 where c <= 1140006215 and (select b from t2 where a = 2) = 1; +drop table t1, t2; + +# +# Bug #7549: Missing error message for invalid view selection with subquery +# + +CREATE TABLE t1 (a INT); + +--error 1054 +CREATE VIEW v1 AS SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +--error 1054 +CREATE VIEW v2 AS SELECT * FROM t1 WHERE no_such_column = (SELECT 1); +--error 1054 +SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); + +DROP TABLE t1; + +# +# Bug#19077: A nested materialized derived table is used before being populated. +# +create table t1 (i int, j bigint); +insert into t1 values (1, 2), (2, 2), (3, 2); +select * from (select min(i) from t1 where j=(select * from (select min(j) from t1) t2)) t3; +drop table t1; + +# +# Bug#19700: subselect returning BIGINT always returned it as SIGNED +# +CREATE TABLE t1 (i BIGINT UNSIGNED); +INSERT INTO t1 VALUES (10000000000000000000); # > MAX SIGNED BIGINT 9323372036854775807 +INSERT INTO t1 VALUES (1); + +CREATE TABLE t2 (i BIGINT UNSIGNED); +INSERT INTO t2 VALUES (10000000000000000000); # same as first table +INSERT INTO t2 VALUES (1); + +/* simple test */ +SELECT t1.i FROM t1 JOIN t2 ON t1.i = t2.i; + +/* subquery test */ +SELECT t1.i FROM t1 WHERE t1.i = (SELECT MAX(i) FROM t2); + +/* subquery test with cast*/ +SELECT t1.i FROM t1 WHERE t1.i = CAST((SELECT MAX(i) FROM t2) AS UNSIGNED); + +DROP TABLE t1; +DROP TABLE t2; + +# +# Bug#20519: subselect with LIMIT M, N +# + +CREATE TABLE t1 ( + id bigint(20) unsigned NOT NULL auto_increment, + name varchar(255) NOT NULL, + PRIMARY KEY (id) +); +INSERT INTO t1 VALUES + (1, 'Balazs'), (2, 'Joe'), (3, 'Frank'); + +CREATE TABLE t2 ( + id bigint(20) unsigned NOT NULL auto_increment, + mid bigint(20) unsigned NOT NULL, + date date NOT NULL, + PRIMARY KEY (id) +); +INSERT INTO t2 VALUES + (1, 1, '2006-03-30'), (2, 2, '2006-04-06'), (3, 3, '2006-04-13'), + (4, 2, '2006-04-20'), (5, 1, '2006-05-01'); + +SELECT *, + (SELECT date FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 0, 1) AS date_last, + (SELECT date FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 3, 1) AS date_next_to_last + FROM t1; +SELECT *, + (SELECT COUNT(*) FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 1, 1) AS date_count + FROM t1; +SELECT *, + (SELECT date FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 0, 1) AS date_last, + (SELECT date FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 1, 1) AS date_next_to_last + FROM t1; +DROP TABLE t1,t2; + +# +# Bug#20869: subselect with range access by DESC +# + +CREATE TABLE t1 ( + i1 int(11) NOT NULL default '0', + i2 int(11) NOT NULL default '0', + t datetime NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY (i1,i2,t) +); +INSERT INTO t1 VALUES +(24,1,'2005-03-03 16:31:31'),(24,1,'2005-05-27 12:40:07'), +(24,1,'2005-05-27 12:40:08'),(24,1,'2005-05-27 12:40:10'), +(24,1,'2005-05-27 12:40:25'),(24,1,'2005-05-27 12:40:30'), +(24,2,'2005-03-03 13:43:05'),(24,2,'2005-03-03 16:23:31'), +(24,2,'2005-03-03 16:31:30'),(24,2,'2005-05-27 12:37:02'), +(24,2,'2005-05-27 12:40:06'); + +CREATE TABLE t2 ( + i1 int(11) NOT NULL default '0', + i2 int(11) NOT NULL default '0', + t datetime default NULL, + PRIMARY KEY (i1) +); +INSERT INTO t2 VALUES (24,1,'2006-06-20 12:29:40'); + +EXPLAIN +SELECT * FROM t1,t2 + WHERE t1.t = (SELECT t1.t FROM t1 + WHERE t1.t < t2.t AND t1.i2=1 AND t2.i1=t1.i1 + ORDER BY t1.t DESC LIMIT 1); +SELECT * FROM t1,t2 + WHERE t1.t = (SELECT t1.t FROM t1 + WHERE t1.t < t2.t AND t1.i2=1 AND t2.i1=t1.i1 + ORDER BY t1.t DESC LIMIT 1); + +DROP TABLE t1, t2; + +# +# Bug#14654 : Cannot select from the same table twice within a UNION +# statement +# +CREATE TABLE t1 (i INT); + +(SELECT i FROM t1) UNION (SELECT i FROM t1); +#TODO:not supported +--error ER_PARSE_ERROR +SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS + ( + (SELECT i FROM t1) UNION + (SELECT i FROM t1) + ); + +#TODO:not supported +--error ER_PARSE_ERROR +SELECT * FROM t1 +WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1))); + +#TODO:not supported +--error 1064 +explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) + from t1; + +#TODO:not supported +--error ER_PARSE_ERROR +explain select * from t1 where not exists + ((select t11.i from t1 t11) union (select t12.i from t1 t12)); + +DROP TABLE t1; + +# +# Bug#21798: memory leak during query execution with subquery in column +# list using a function +# +CREATE TABLE t1 (a VARCHAR(250), b INT auto_increment, PRIMARY KEY (b)); +insert into t1 (a) values (FLOOR(rand() * 100)); +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; +insert into t1 (a) select FLOOR(rand() * 100) from t1; + +SELECT a, + (SELECT REPEAT(' ',250) FROM t1 i1 + WHERE i1.b=t1.a ORDER BY RAND() LIMIT 1) AS a +FROM t1 ORDER BY a LIMIT 5; +DROP TABLE t1; + +# +# Bug #21540: Subqueries with no from and aggregate functions return +# wrong results +CREATE TABLE t1 (a INT, b INT); +CREATE TABLE t2 (a INT); +INSERT INTO t2 values (1); +INSERT INTO t1 VALUES (1,1),(1,2),(2,3),(3,4); +SELECT (SELECT COUNT(DISTINCT t1.b) from t2) FROM t1 GROUP BY t1.a; +SELECT (SELECT COUNT(DISTINCT t1.b) from t2 union select 1 from t2 where 12 < 3) + FROM t1 GROUP BY t1.a; +SELECT COUNT(DISTINCT t1.b), (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a; +SELECT COUNT(DISTINCT t1.b), + (SELECT COUNT(DISTINCT t1.b) union select 1 from DUAL where 12 < 3) + FROM t1 GROUP BY t1.a; +SELECT ( + SELECT ( + SELECT COUNT(DISTINCT t1.b) + ) +) +FROM t1 GROUP BY t1.a; +SELECT ( + SELECT ( + SELECT ( + SELECT COUNT(DISTINCT t1.b) + ) + ) + FROM t1 GROUP BY t1.a LIMIT 1) +FROM t1 t2 +GROUP BY t2.a; +DROP TABLE t1,t2; + +# +# Bug #21727: Correlated subquery that requires filesort: +# slow with big sort_buffer_size +# + +CREATE TABLE t1 (a int, b int auto_increment, PRIMARY KEY (b)); +CREATE TABLE t2 (x int auto_increment, y int, z int, + PRIMARY KEY (x), FOREIGN KEY (y) REFERENCES t1 (b)); + +disable_query_log; +let $1=3000; +while ($1) +{ + eval INSERT INTO t1(a) VALUES(RAND()*1000); + eval SELECT MAX(b) FROM t1 INTO @id; + let $2=10; + while ($2) + { + eval INSERT INTO t2(y,z) VALUES(@id,RAND()*1000); + dec $2; + } + dec $1; +} +enable_query_log; + +SET SESSION sort_buffer_size = 32 * 1024; +SELECT SQL_NO_CACHE COUNT(*) + FROM (SELECT a, b, (SELECT x FROM t2 WHERE y=b ORDER BY z DESC LIMIT 1) c + FROM t1) t; + +SET SESSION sort_buffer_size = 8 * 1024 * 1024; +SELECT SQL_NO_CACHE COUNT(*) + FROM (SELECT a, b, (SELECT x FROM t2 WHERE y=b ORDER BY z DESC LIMIT 1) c + FROM t1) t; + +DROP TABLE t2,t1; + +# +# Bug #25219: EXIST subquery with UNION over a mix of +# correlated and uncorrelated selects +# + +CREATE TABLE t1 (id char(4) PRIMARY KEY, c int); +CREATE TABLE t2 (c int); + +INSERT INTO t1 VALUES ('aa', 1); +INSERT INTO t2 VALUES (1); + +SELECT * FROM t1 + WHERE EXISTS (SELECT c FROM t2 WHERE c=1 + UNION + SELECT c from t2 WHERE c=t1.c); + +INSERT INTO t1 VALUES ('bb', 2), ('cc', 3), ('dd',1); + +SELECT * FROM t1 + WHERE EXISTS (SELECT c FROM t2 WHERE c=1 + UNION + SELECT c from t2 WHERE c=t1.c); + +INSERT INTO t2 VALUES (2); +CREATE TABLE t3 (c int); +INSERT INTO t3 VALUES (1); + +SELECT * FROM t1 + WHERE EXISTS (SELECT t2.c FROM t2 JOIN t3 ON t2.c=t3.c WHERE t2.c=1 + UNION + SELECT c from t2 WHERE c=t1.c); + +DROP TABLE t1,t2,t3; + +# +# Bug#23800: Outer fields in correlated subqueries is used in a temporary +# table created for sorting. +# +CREATE TABLE t1(f1 int); +CREATE TABLE t2(f2 int, f21 int, f3 timestamp); +INSERT INTO t1 VALUES (1),(1),(2),(2); +INSERT INTO t2 VALUES (1,1,"2004-02-29 11:11:11"), (2,2,"2004-02-29 11:11:11"); +SELECT ((SELECT f2 FROM t2 WHERE f21=f1 LIMIT 1) * COUNT(f1)) AS sq FROM t1 GROUP BY f1; +SELECT (SELECT SUM(1) FROM t2 ttt GROUP BY t2.f3 LIMIT 1) AS tt FROM t2; +PREPARE stmt1 FROM 'SELECT ((SELECT f2 FROM t2 WHERE f21=f1 LIMIT 1) * COUNT(f1)) AS sq FROM t1 GROUP BY f1'; +EXECUTE stmt1; +EXECUTE stmt1; +DEALLOCATE PREPARE stmt1; +SELECT f2, AVG(f21), + (SELECT t.f3 FROM t2 AS t WHERE t2.f2=t.f2 AND t.f3=MAX(t2.f3)) AS test + FROM t2 GROUP BY f2; +DROP TABLE t1,t2; +CREATE TABLE t1 (a int, b INT, c CHAR(10) NOT NULL); +INSERT INTO t1 VALUES + (1,1,'a'), (1,2,'b'), (1,3,'c'), (1,4,'d'), (1,5,'e'), + (2,1,'f'), (2,2,'g'), (2,3,'h'), (3,4,'i'), (3,3,'j'), + (3,2,'k'), (3,1,'l'), (1,9,'m'); +SELECT a, MAX(b), + (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b)) AS test + FROM t1 GROUP BY a; +DROP TABLE t1; + +# +# Bug#21904 (parser problem when using IN with a double "(())") +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t1xt2; +--enable_warnings + +CREATE TABLE t1 ( + id_1 int(5) NOT NULL, + t varchar(4) DEFAULT NULL +); + +CREATE TABLE t2 ( + id_2 int(5) NOT NULL, + t varchar(4) DEFAULT NULL +); + +CREATE TABLE t1xt2 ( + id_1 int(5) NOT NULL, + id_2 int(5) NOT NULL +); + +INSERT INTO t1 VALUES (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'); + +INSERT INTO t2 VALUES (2, 'bb'), (3, 'cc'), (4, 'dd'), (12, 'aa'); + +INSERT INTO t1xt2 VALUES (2, 2), (3, 3), (4, 4); + +# subselect returns 0 rows + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 where t1.id_1 = t1xt2.id_1))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 where t1.id_1 = t1xt2.id_1)))); + +insert INTO t1xt2 VALUES (1, 12); + +# subselect returns 1 row + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); + +insert INTO t1xt2 VALUES (2, 12); + +# subselect returns more than 1 row + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN ((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1))); + +SELECT DISTINCT t1.id_1 FROM t1 WHERE +(12 NOT IN (((SELECT t1xt2.id_2 FROM t1xt2 WHERE t1.id_1 = t1xt2.id_1)))); + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t1xt2; + +# +# Bug #26728: derived table with concatanation of literals in select list +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3), (1), (2); + +SELECT 'this is ' 'a test.' AS col1, a AS col2 FROM t1; +SELECT * FROM (SELECT 'this is ' 'a test.' AS col1, a AS t2 FROM t1) t; + +DROP table t1; + +# +# Bug #27257: COUNT(*) aggregated in outer query +# + +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (m int, n int); +INSERT INTO t1 VALUES (2,2), (2,2), (3,3), (3,3), (3,3), (4,4); +INSERT INTO t2 VALUES (1,11), (2,22), (3,32), (4,44), (4,44); + +SELECT COUNT(*), a, + (SELECT m FROM t2 WHERE m = count(*) LIMIT 1) + FROM t1 GROUP BY a; + +SELECT COUNT(*), a, + (SELECT MIN(m) FROM t2 WHERE m = count(*)) + FROM t1 GROUP BY a; + +SELECT COUNT(*), a + FROM t1 GROUP BY a + HAVING (SELECT MIN(m) FROM t2 WHERE m = count(*)) > 1; + +DROP TABLE t1,t2; + +# +# Bug #27229: GROUP_CONCAT in subselect with COUNT() as an argument +# + +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (m int, n int); +INSERT INTO t1 VALUES (2,2), (2,2), (3,3), (3,3), (3,3), (4,4); +INSERT INTO t2 VALUES (1,11), (2,22), (3,32), (4,44), (4,44); + +SELECT COUNT(*) c, a, + (SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a) + FROM t1 GROUP BY a; + +SELECT COUNT(*) c, a, + (SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a) + FROM t1 GROUP BY a; + +DROP table t1,t2; + +# +# Bug#27321: Wrong subquery result in a grouping select +# +CREATE TABLE t1 (a int, b INT, d INT, c CHAR(10) NOT NULL, PRIMARY KEY (a, b)); +INSERT INTO t1 VALUES (1,1,0,'a'), (1,2,0,'b'), (1,3,0,'c'), (1,4,0,'d'), +(1,5,0,'e'), (2,1,0,'f'), (2,2,0,'g'), (2,3,0,'h'), (3,4,0,'i'), (3,3,0,'j'), +(3,2,0,'k'), (3,1,0,'l'), (1,9,0,'m'), (1,0,10,'n'), (2,0,5,'o'), (3,0,7,'p'); + +SELECT a, MAX(b), + (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b + 0)) as test + FROM t1 GROUP BY a; +SELECT a x, MAX(b), + (SELECT t.c FROM t1 AS t WHERE x=t.a AND t.b=MAX(t1.b + 0)) as test + FROM t1 GROUP BY a; +SELECT a, AVG(b), + (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=AVG(t1.b)) AS test + FROM t1 WHERE t1.d=0 GROUP BY a; + +SELECT tt.a, + (SELECT (SELECT c FROM t1 as t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a) + LIMIT 1) FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1) as test + FROM t1 as tt; + +SELECT tt.a, + (SELECT (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a) + LIMIT 1) + FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1) as test + FROM t1 as tt GROUP BY tt.a; + +SELECT tt.a, MAX( + (SELECT (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a) + LIMIT 1) + FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1)) as test + FROM t1 as tt GROUP BY tt.a; + +DROP TABLE t1; +# +# Bug #27348: SET FUNCTION used in a subquery from WHERE condition +# + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (2,22),(1,11),(2,22); + +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; + +SELECT a FROM t1 t0 + WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; + +SET @@sql_mode='ansi'; +--error 1111 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +--error 1111 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; + +--error 1111 +SELECT a FROM t1 t0 + WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; + +SET @@sql_mode=default; + +DROP TABLE t1; + +# +# Bug #27363: nested aggregates in outer, subquery / sum(select +# count(outer)) +# +CREATE TABLE t1 (a INT); INSERT INTO t1 values (1),(1),(1),(1); +CREATE TABLE t2 (x INT); INSERT INTO t1 values (1000),(1001),(1002); + +--error ER_INVALID_GROUP_FUNC_USE +SELECT SUM( (SELECT COUNT(a) FROM t2) ) FROM t1; +--error ER_INVALID_GROUP_FUNC_USE +SELECT SUM( (SELECT SUM(COUNT(a)) FROM t2) ) FROM t1; +SELECT COUNT(1) FROM DUAL; + +--error ER_INVALID_GROUP_FUNC_USE +SELECT SUM( (SELECT AVG( (SELECT t1.a FROM t2) ) FROM DUAL) ) FROM t1; + +--error ER_INVALID_GROUP_FUNC_USE +SELECT + SUM( (SELECT AVG( (SELECT COUNT(*) FROM t1 t HAVING t1.a < 12) ) FROM t2) ) +FROM t1; + +--error ER_INVALID_GROUP_FUNC_USE +SELECT t1.a as XXA, + SUM( (SELECT AVG( (SELECT COUNT(*) FROM t1 t HAVING XXA < 12) ) FROM t2) ) +FROM t1; + +DROP TABLE t1,t2; + +# +# Bug #27807: Server crash when executing subquery with EXPLAIN +# +CREATE TABLE t1 (a int, b int, KEY (a)); +INSERT INTO t1 VALUES (1,1),(2,1); +EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b); +DROP TABLE t1; + +# +# Bug #28377: grouping query with a correlated subquery in WHERE condition +# + +CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id)); +INSERT INTO t1 VALUES + (3,'FL'), (2,'GA'), (4,'FL'), (1,'GA'), (5,'NY'), (7,'FL'), (6,'NY'); +CREATE TABLE t2 (id int NOT NULL, INDEX idx(id)); +INSERT INTO t2 VALUES (7), (5), (1), (3); + +SELECT id, st FROM t1 + WHERE st IN ('GA','FL') AND EXISTS(SELECT 1 FROM t2 WHERE t2.id=t1.id); +SELECT id, st FROM t1 + WHERE st IN ('GA','FL') AND EXISTS(SELECT 1 FROM t2 WHERE t2.id=t1.id) + GROUP BY id; + +SELECT id, st FROM t1 + WHERE st IN ('GA','FL') AND NOT EXISTS(SELECT 1 FROM t2 WHERE t2.id=t1.id); +SELECT id, st FROM t1 + WHERE st IN ('GA','FL') AND NOT EXISTS(SELECT 1 FROM t2 WHERE t2.id=t1.id) + GROUP BY id; + +DROP TABLE t1,t2; + +# +# Bug #28728: crash with EXPLAIN EXTENDED for a query with a derived table +# over a grouping subselect +# + +CREATE TABLE t1 (a int); + +INSERT INTO t1 VALUES (1), (2); + +EXPLAIN EXTENDED +SELECT * FROM (SELECT count(*) FROM t1 GROUP BY a) as res; + +DROP TABLE t1; + +# +# Bug #28811: crash for query containing subquery with ORDER BY and LIMIT 1 +# + +CREATE TABLE t1 ( + a varchar(255) default NULL, + b timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + INDEX idx(a,b) +); +CREATE TABLE t2 ( + a varchar(255) default NULL +); + +INSERT INTO t1 VALUES ('abcdefghijk','2007-05-07 06:00:24'); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO `t1` VALUES ('asdf','2007-02-08 01:11:26'); +INSERT INTO `t2` VALUES ('abcdefghijk'); +INSERT INTO `t2` VALUES ('asdf'); + +SET session sort_buffer_size=8192; + +SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.a ORDER BY t1.b LIMIT 1) AS d1 FROM t2; + +DROP TABLE t1,t2; + + +# +# Bug #27333: subquery grouped for aggregate of outer query / no aggregate +# of subquery +# +CREATE TABLE t1 (a INTEGER, b INTEGER); +CREATE TABLE t2 (x INTEGER); +INSERT INTO t1 VALUES (1,11), (2,22), (2,22); +INSERT INTO t2 VALUES (1), (2); + +# wasn't failing, but should +--error ER_SUBQUERY_NO_1_ROW +SELECT a, COUNT(b), (SELECT COUNT(b) FROM t2) FROM t1 GROUP BY a; + +# fails as it should +--error ER_SUBQUERY_NO_1_ROW +SELECT a, COUNT(b), (SELECT COUNT(b)+0 FROM t2) FROM t1 GROUP BY a; + +SELECT (SELECT SUM(t1.a)/AVG(t2.x) FROM t2) FROM t1; +DROP TABLE t1,t2; + +# second test case from 27333 +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1, 2), (1,3), (1,4), (2,1), (2,2); + +# returns no rows, when it should +SELECT a1.a, COUNT(*) FROM t1 a1 WHERE a1.a = 1 +AND EXISTS( SELECT a2.a FROM t1 a2 WHERE a2.a = a1.a) +GROUP BY a1.a; +DROP TABLE t1; + +#test cases from 29297 +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=0) FROM t1; +--error ER_SUBQUERY_NO_1_ROW +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a!=0) FROM t1; +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=1) FROM t1; +DROP TABLE t1,t2; + +# +# Bug #31884: Assertion + crash in subquery in the SELECT clause. +# + +CREATE TABLE t1 (a1 INT, a2 INT); +CREATE TABLE t2 (b1 INT, b2 INT); + +INSERT INTO t1 VALUES (100, 200); +INSERT INTO t1 VALUES (101, 201); +INSERT INTO t2 VALUES (101, 201); +INSERT INTO t2 VALUES (103, 203); + +SELECT ((a1,a2) IN (SELECT * FROM t2 WHERE b2 > 0)) IS NULL FROM t1; +DROP TABLE t1, t2; + +# +# Bug #28076: inconsistent binary/varbinary comparison +# + +CREATE TABLE t1 (s1 BINARY(5), s2 VARBINARY(5)); +INSERT INTO t1 VALUES (0x41,0x41), (0x42,0x42), (0x43,0x43); + +SELECT s1, s2 FROM t1 WHERE s2 IN (SELECT s1 FROM t1); +SELECT s1, s2 FROM t1 WHERE (s2, 10) IN (SELECT s1, 10 FROM t1); + +CREATE INDEX I1 ON t1 (s1); +CREATE INDEX I2 ON t1 (s2); + +SELECT s1, s2 FROM t1 WHERE s2 IN (SELECT s1 FROM t1); +SELECT s1, s2 FROM t1 WHERE (s2, 10) IN (SELECT s1, 10 FROM t1); + +TRUNCATE t1; +INSERT INTO t1 VALUES (0x41,0x41); +SELECT * FROM t1 WHERE s1 = (SELECT s2 FROM t1); + +DROP TABLE t1; + +CREATE TABLE t1 (a1 VARBINARY(2) NOT NULL DEFAULT '0', PRIMARY KEY (a1)); +CREATE TABLE t2 (a2 BINARY(2) default '0', INDEX (a2)); +CREATE TABLE t3 (a3 BINARY(2) default '0'); +INSERT INTO t1 VALUES (1),(2),(3),(4); +INSERT INTO t2 VALUES (1),(2),(3); +INSERT INTO t3 VALUES (1),(2),(3); +SELECT LEFT(t2.a2, 1) FROM t2,t3 WHERE t3.a3=t2.a2; +SELECT t1.a1, t1.a1 in (SELECT t2.a2 FROM t2,t3 WHERE t3.a3=t2.a2) FROM t1; +DROP TABLE t1,t2,t3; + +CREATE TABLE t1 (a1 BINARY(3) PRIMARY KEY, b1 VARBINARY(3)); +CREATE TABLE t2 (a2 VARBINARY(3) PRIMARY KEY); +CREATE TABLE t3 (a3 VARBINARY(3) PRIMARY KEY); +INSERT INTO t1 VALUES (1,10), (2,20), (3,30), (4,40); +INSERT INTO t2 VALUES (2), (3), (4), (5); +INSERT INTO t3 VALUES (10), (20), (30); +SELECT LEFT(t1.a1,1) FROM t1,t3 WHERE t1.b1=t3.a3; +SELECT a2 FROM t2 WHERE t2.a2 IN (SELECT t1.a1 FROM t1,t3 WHERE t1.b1=t3.a3); +DROP TABLE t1, t2, t3; + +# +# Bug #30788: Inconsistent retrieval of char/varchar +# + +CREATE TABLE t1 (a CHAR(1), b VARCHAR(10)); +INSERT INTO t1 VALUES ('a', 'aa'); +INSERT INTO t1 VALUES ('a', 'aaa'); +SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); +CREATE INDEX I1 ON t1 (a); +CREATE INDEX I2 ON t1 (b); +EXPLAIN SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); +SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1); + +CREATE TABLE t2 (a VARCHAR(1), b VARCHAR(10)); +INSERT INTO t2 SELECT * FROM t1; +CREATE INDEX I1 ON t2 (a); +CREATE INDEX I2 ON t2 (b); +EXPLAIN SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2); +SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2); +EXPLAIN +SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); +SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500); + +DROP TABLE t1,t2; + +# +# Bug #32400: Complex SELECT query returns correct result only on some +# occasions +# + +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 VALUES (1,1), (1,2), (2,3), (2,4); + +--error ER_BAD_FIELD_ERROR +EXPLAIN +SELECT a AS out_a, MIN(b) FROM t1 +WHERE b > (SELECT MIN(b) FROM t1 WHERE a = out_a) +GROUP BY a; + +--error ER_BAD_FIELD_ERROR +SELECT a AS out_a, MIN(b) FROM t1 +WHERE b > (SELECT MIN(b) FROM t1 WHERE a = out_a) +GROUP BY a; + +EXPLAIN +SELECT a AS out_a, MIN(b) FROM t1 t1_outer +WHERE b > (SELECT MIN(b) FROM t1 WHERE a = t1_outer.a) +GROUP BY a; + +SELECT a AS out_a, MIN(b) FROM t1 t1_outer +WHERE b > (SELECT MIN(b) FROM t1 WHERE a = t1_outer.a) +GROUP BY a; + +DROP TABLE t1; + + +# +# Bug #32036: EXISTS within a WHERE clause with a UNION crashes MySQL 5.122 +# + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); + +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); + +SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a)); +EXPLAIN EXTENDED +SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a)); + + +#TODO:not supported +--error ER_PARSE_ERROR +EXPLAIN EXTENDED +SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a) UNION + (SELECT 1 FROM t2 WHERE t1.a = t2.a)); + +DROP TABLE t1,t2; + +# +# Bug#33675: Usage of an uninitialized memory by filesort in a subquery +# caused server crash. +# +create table t1(f11 int, f12 int); +create table t2(f21 int unsigned not null, f22 int, f23 varchar(10)); +insert into t1 values(1,1),(2,2), (3, 3); +let $i=10000; +--disable_query_log +--disable_warnings +while ($i) +{ + eval insert into t2 values (-1 , $i/5000 + 1, '$i'); + dec $i; +} +--enable_warnings +--enable_query_log +set session sort_buffer_size= 33*1024; +select count(*) from t1 where f12 = +(select f22 from t2 where f22 = f12 order by f21 desc, f22, f23 limit 1); + +drop table t1,t2; + +--echo End of 5.0 tests. + +# +# Bug #27348: SET FUNCTION used in a subquery from WHERE condition +# + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (2,22),(1,11),(2,22); + +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; + +SELECT a FROM t1 t0 + WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; + +SET @@sql_mode='ansi'; +--error 1111 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +--error 1111 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; + +--error 1111 +SELECT a FROM t1 t0 + WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; + +SET @@sql_mode=default; +DROP TABLE t1; + +# +# Bug#20835 (literal string with =any values) +# +CREATE TABLE t1 (s1 char(1)); +INSERT INTO t1 VALUES ('a'); +SELECT * FROM t1 WHERE _utf8'a' = ANY (SELECT s1 FROM t1); +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/sum_distinct.test b/mysql-test/suite/pbxt/t/sum_distinct.test new file mode 100644 index 00000000000..ce470dbe68d --- /dev/null +++ b/mysql-test/suite/pbxt/t/sum_distinct.test @@ -0,0 +1,99 @@ +# +# Various tests for SUM(DISTINCT ...) +# +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +CREATE TABLE t1 ( + id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, + gender CHAR(1), + name VARCHAR(20) +); + +# According to ANSI SQL, SUM(DISTINCT ...) should return NULL for empty +# record set + +SELECT SUM(DISTINCT LENGTH(name)) s1 FROM t1; + +# According to ANSI SQL, SUM(DISTINCT ...) should return NULL for records sets +# entirely consisting of NULLs + +INSERT INTO t1 (gender, name) VALUES (NULL, NULL); +INSERT INTO t1 (gender, name) VALUES (NULL, NULL); +INSERT INTO t1 (gender, name) VALUES (NULL, NULL); + +SELECT SUM(DISTINCT LENGTH(name)) s1 FROM t1; + + +# Filling table with t1 + +INSERT INTO t1 (gender, name) VALUES ('F', 'Helen'), ('F', 'Anastasia'), +('F', 'Katherine'), ('F', 'Margo'), ('F', 'Magdalene'), ('F', 'Mary'); + +CREATE TABLE t2 SELECT name FROM t1; + +SELECT (SELECT SUM(DISTINCT LENGTH(name)) FROM t1) FROM t2; + +DROP TABLE t2; + +INSERT INTO t1 (gender, name) VALUES ('F', 'Eva'), ('F', 'Sofia'), +('F', 'Sara'), ('F', 'Golda'), ('F', 'Toba'), ('F', 'Victory'), +('F', 'Faina'), ('F', 'Miriam'), ('F', 'Beki'), ('F', 'America'), +('F', 'Susan'), ('F', 'Glory'), ('F', 'Priscilla'), ('F', 'Rosmary'), +('F', 'Rose'), ('F', 'Margareth'), ('F', 'Elizabeth'), ('F', 'Meredith'), +('F', 'Julie'), ('F', 'Xenia'), ('F', 'Zena'), ('F', 'Olga'), +('F', 'Brunhilda'), ('F', 'Nataly'), ('F', 'Lara'), ('F', 'Svetlana'), +('F', 'Grethem'), ('F', 'Irene'); + +SELECT + SUM(DISTINCT LENGTH(name)) s1, + SUM(DISTINCT SUBSTRING(NAME, 1, 3)) s2, + SUM(DISTINCT LENGTH(SUBSTRING(name, 1, 4))) s3 +FROM t1; + +SELECT + SUM(DISTINCT LENGTH(g1.name)) s1, + SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2, + SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3 +FROM t1 g1, t1 g2, t1 g3; + +SELECT + SUM(DISTINCT LENGTH(g1.name)) s1, + SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2, + SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3 +FROM t1 g1, t1 g2, t1 g3 GROUP BY LENGTH(SUBSTRING(g3.name, 5, 10)); + +# here we explicitly request summing through temporary table (so +# Item_sum_sum_distinct::copy_or_same() is called) + +SELECT SQL_BUFFER_RESULT + SUM(DISTINCT LENGTH(name)) s1, + SUM(DISTINCT SUBSTRING(NAME, 1, 3)) s2, + SUM(DISTINCT LENGTH(SUBSTRING(name, 1, 4))) s3 +FROM t1; + +SELECT SQL_BUFFER_RESULT + SUM(DISTINCT LENGTH(g1.name)) s1, + SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2, + SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3 +FROM t1 g1, t1 g2, t1 g3 GROUP BY LENGTH(SUBSTRING(g3.name, 5, 10)); + +# this test demonstrates that strings are automatically converted to numbers +# before summing + +SET @l=1; +UPDATE t1 SET name=CONCAT(name, @l:=@l+1); + +SELECT SUM(DISTINCT RIGHT(name, 1)) FROM t1; + +# this is a test case for ordinary t1 + +SELECT SUM(DISTINCT id) FROM t1; +SELECT SUM(DISTINCT id % 11) FROM t1; + +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/temp_table.test b/mysql-test/suite/pbxt/t/temp_table.test new file mode 100644 index 00000000000..71ff086f60a --- /dev/null +++ b/mysql-test/suite/pbxt/t/temp_table.test @@ -0,0 +1,183 @@ +# mysqltest should be fixed +-- source include/not_embedded.inc +# +# Test of temporary tables +# + +--disable_warnings +drop table if exists t1,t2; +drop view if exists v1; +--enable_warnings + +CREATE TABLE t1 (c int not null, d char (10) not null); +insert into t1 values(1,""),(2,"a"),(3,"b"); +CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(4,"e"),(5,"f"),(6,"g"); +alter table t1 rename t2; +select * from t1; +select * from t2; +CREATE TABLE t2 (x int not null, y int not null); +alter table t2 rename t1; +select * from t1; +create TEMPORARY TABLE t2 engine=heap select * from t1; +create TEMPORARY TABLE IF NOT EXISTS t2 (a int) engine=heap; + +# This should give errors +--error 1050 +CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null); +--error 1050 +ALTER TABLE t1 RENAME t2; + +select * from t2; +alter table t2 add primary key (a,b); +drop table t1,t2; +select * from t1; +drop table t2; +create temporary table t1 engine=myisam select *,2 as "e" from t1; # PBXT cannot handle INSERT/SELECT with temp +select * from t1; +drop table t1; +drop table t1; + +# +# Test CONCAT_WS with temporary tables +# + +CREATE TABLE t1 (pkCrash INTEGER PRIMARY KEY,strCrash VARCHAR(255)); +INSERT INTO t1 ( pkCrash, strCrash ) VALUES ( 1, '1'); +SELECT CONCAT_WS(pkCrash, strCrash) FROM t1; +drop table t1; +create temporary table t1 select 1 as 'x'; +drop table t1; +CREATE TABLE t1 (x INT); +INSERT INTO t1 VALUES (1), (2), (3); +CREATE TEMPORARY TABLE tmp engine=myisam SELECT *, NULL FROM t1; # PBXT cannot handle INSERT/SELECT with temp +drop table t1; + +# +# Problem with ELT +# +create temporary table t1 (id int(10) not null unique); +create temporary table t2 (id int(10) not null primary key, +val int(10) not null); + +# put in some initial values +insert into t1 values (1),(2),(4); +insert into t2 values (1,1),(2,1),(3,1),(4,2); + +# do a query using ELT, a join and an ORDER BY. +select one.id, two.val, elt(two.val,'one','two') from t1 one, t2 two where two.id=one.id order by one.id; +drop table t1,t2; + +# +# Test of failed ALTER TABLE on temporary table +# +create temporary table t1 (a int not null); +insert into t1 values (1),(1); +-- error 1062 +alter table t1 add primary key (a); +drop table t1; + +# +# In MySQL 4.0.4 doing a GROUP BY on a NULL column created a disk based +# temporary table when a memory based one would be good enough. + +CREATE TABLE t1 ( + d datetime default NULL +) ENGINE=MyISAM; + + +INSERT INTO t1 VALUES ('2002-10-24 14:50:32'),('2002-10-24 14:50:33'),('2002-10-24 14:50:34'),('2002-10-24 14:50:34'),('2002-10-24 14:50:34'),('2002-10-24 14:50:35'),('2002-10-24 14:50:35'),('2002-10-24 14:50:35'),('2002-10-24 14:50:35'),('2002-10-24 14:50:36'),('2002-10-24 14:50:36'),('2002-10-24 14:50:36'),('2002-10-24 14:50:36'),('2002-10-24 14:50:37'),('2002-10-24 14:50:37'),('2002-10-24 14:50:37'),('2002-10-24 14:50:37'),('2002-10-24 14:50:38'),('2002-10-24 14:50:38'),('2002-10-24 14:50:38'),('2002-10-24 14:50:39'),('2002-10-24 14:50:39'),('2002-10-24 14:50:39'),('2002-10-24 14:50:39'),('2002-10-24 14:50:40'),('2002-10-24 14:50:40'),('2002-10-24 14:50:40'); + +flush status; +select * from t1 group by d; +show status like "created_tmp%tables"; +drop table t1; + +# Fix for BUG#8921: Check that temporary table is ingored by view commands. +create temporary table v1 as select 'This is temp. table' A; +create view v1 as select 'This is view' A; +select * from v1; +show create table v1; +show create view v1; +drop view v1; +select * from v1; +create view v1 as select 'This is view again' A; +select * from v1; +drop table v1; +select * from v1; +drop view v1; + +# Bug #8497: tmpdir with extra slashes would cause failures +# +create table t1 (a int, b int, index(a), index(b)); +create table t2 (c int auto_increment, d varchar(255), primary key (c)); +insert into t1 values (3,1),(3,2); +insert into t2 values (NULL, 'foo'), (NULL, 'bar'); +select d, c from t1 left join t2 on b = c where a = 3 order by d; +drop table t1, t2; + + +# +# BUG#21096: locking issue ; temporary table conflicts. +# +# The problem was that on DROP TEMPORARY table name lock was acquired, +# which should not be done. +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (i INT); + +LOCK TABLE t1 WRITE; + +connect (conn1, localhost, root,,); + +CREATE TEMPORARY TABLE t1 (i INT); + +--echo The following command should not block +DROP TEMPORARY TABLE t1; + +disconnect conn1; +connection default; + +DROP TABLE t1; + +# +# Check that it's not possible to drop a base table with +# DROP TEMPORARY statement. +# +CREATE TABLE t1 (i INT); +CREATE TEMPORARY TABLE t2 (i INT); + +--error 1051 +DROP TEMPORARY TABLE t2, t1; + +# Table t2 should have been dropped. +--error 1146 +SELECT * FROM t2; +# But table t1 should still be there. +SELECT * FROM t1; + +DROP TABLE t1; + + +--echo End of 4.1 tests. + + +# +# Test truncate with temporary tables +# + +create temporary table t1 (a int); +insert into t1 values (4711); +select * from t1; +truncate t1; +insert into t1 values (42); +select * from t1; +drop table t1; + + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/truncate.test b/mysql-test/suite/pbxt/t/truncate.test new file mode 100644 index 00000000000..e28115f1164 --- /dev/null +++ b/mysql-test/suite/pbxt/t/truncate.test @@ -0,0 +1,57 @@ +# +# Test of truncate +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a integer, b integer,c1 CHAR(10)); +insert into t1 (a) values (1),(2); +truncate table t1; +select count(*) from t1; +insert into t1 values(1,2,"test"); +select count(*) from t1; +delete from t1; +select * from t1; +drop table t1; +# The following should fail +--error 1146 +select count(*) from t1; +create temporary table t1 (n int); +insert into t1 values (1),(2),(3); +truncate table t1; +select * from t1; +drop table t1; +--error 1146 +truncate non_existing_table; + +# +# test autoincrement with TRUNCATE; verifying difference with DELETE +# + +create table t1 (a integer auto_increment primary key); +insert into t1 (a) values (NULL),(NULL); +truncate table t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +delete from t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +drop table t1; + +# Verifying that temp tables are handled the same way + +create temporary table t1 (a integer auto_increment primary key); +insert into t1 (a) values (NULL),(NULL); +truncate table t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +delete from t1; +insert into t1 (a) values (NULL),(NULL); +SELECT * from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/type_binary.test b/mysql-test/suite/pbxt/t/type_binary.test new file mode 100644 index 00000000000..097d05beed6 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_binary.test @@ -0,0 +1,105 @@ +# check 0x00 padding +create table t1 (s1 binary(3)); +insert into t1 values (0x61), (0x6120), (0x612020); +select hex(s1) from t1; +drop table t1; + +# check that 0x00 is not stripped in val_str +create table t1 (s1 binary(2), s2 varbinary(2)); +insert into t1 values (0x4100,0x4100); +select length(concat('*',s1,'*',s2,'*')) from t1; +delete from t1; +insert into t1 values (0x4120,0x4120); +select length(concat('*',s1,'*',s2,'*')) from t1; +drop table t1; + +# check that trailing 0x00 and 0x20 do matter on comparison +create table t1 (s1 varbinary(20), s2 varbinary(20)); +show create table t1; +insert into t1 values (0x41,0x4100),(0x41,0x4120),(0x4100,0x4120); +select hex(s1), hex(s2) from t1; +select count(*) from t1 where s1 < s2; +drop table t1; + +# check that trailing 0x00 do matter on filesort +create table t1 (s1 varbinary(2), s2 varchar(1)); +insert into t1 values (0x41,'a'), (0x4100,'b'), (0x41,'c'), (0x4100,'d'); +select hex(s1),s2 from t1 order by s1,s2; +drop table t1; + +# check that 0x01 is padded to 0x0100 and thus we get a duplicate value +create table t1 (s1 binary(2) primary key); +insert into t1 values (0x01); +insert into t1 values (0x0120); +--error ER_DUP_ENTRY +insert into t1 values (0x0100); +select hex(s1) from t1 order by s1; +# check index search +select hex(s1) from t1 where s1=0x01; +select hex(s1) from t1 where s1=0x0120; +select hex(s1) from t1 where s1=0x0100; +select count(distinct s1) from t1; +alter table t1 drop primary key; +# check non-indexed search +select hex(s1) from t1 where s1=0x01; +select hex(s1) from t1 where s1=0x0120; +select hex(s1) from t1 where s1=0x0100; +select count(distinct s1) from t1; +drop table t1; + +# check that 0x01 is not padded, and all three values are unique +create table t1 (s1 varbinary(2) primary key); +insert into t1 values (0x01); +insert into t1 values (0x0120); +insert into t1 values (0x0100); +select hex(s1) from t1 order by s1; +# check index search +select hex(s1) from t1 where s1=0x01; +select hex(s1) from t1 where s1=0x0120; +select hex(s1) from t1 where s1=0x0100; +select count(distinct s1) from t1; +alter table t1 drop primary key; +# check non-indexed search +select hex(s1) from t1 where s1=0x01; +select hex(s1) from t1 where s1=0x0120; +select hex(s1) from t1 where s1=0x0100; +select count(distinct s1) from t1; +drop table t1; + +# check that cast appends trailing zeros +select hex(cast(0x10 as binary(2))); + +# +# Bug #14299: BINARY space truncation should cause warning or error +# +create table t1 (b binary(2), vb varbinary(2)); +insert into t1 values(0x4120, 0x4120); +insert into t1 values(0x412020, 0x412020); +drop table t1; +create table t1 (c char(2), vc varchar(2)); +insert into t1 values(0x4120, 0x4120); +insert into t1 values(0x412020, 0x412020); +drop table t1; + +set @old_sql_mode= @@sql_mode, sql_mode= 'traditional'; +create table t1 (b binary(2), vb varbinary(2)); +insert into t1 values(0x4120, 0x4120); +--error ER_DATA_TOO_LONG +insert into t1 values(0x412020, NULL); +--error ER_DATA_TOO_LONG +insert into t1 values(NULL, 0x412020); +drop table t1; +set @@sql_mode= @old_sql_mode; + +# +# Bug#14171: Wrong default value for a BINARY field +# +create table t1(f1 int, f2 binary(2) not null, f3 char(2) not null); +insert into t1 set f1=1; +select hex(f2), hex(f3) from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/type_bit.test b/mysql-test/suite/pbxt/t/type_bit.test new file mode 100644 index 00000000000..aaae858f4dc --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_bit.test @@ -0,0 +1,278 @@ +# +# testing of the BIT column type +# + +select 0 + b'1'; +select 0 + b'0'; +select 0 + b'000001'; +select 0 + b'000011'; +select 0 + b'000101'; +select 0 + b'000000'; +select 0 + b'10000000'; +select 0 + b'11111111'; +select 0 + b'10000001'; +select 0 + b'1000000000000000'; +select 0 + b'1111111111111111'; +select 0 + b'1000000000000001'; + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +--error 1439 +create table t1 (a bit(65)); + +create table t1 (a bit(0)); +show create table t1; +drop table t1; + +create table t1 (a bit(64)); +insert into t1 values +(b'1111111111111111111111111111111111111111111111111111111111111111'), +(b'1000000000000000000000000000000000000000000000000000000000000000'), +(b'0000000000000000000000000000000000000000000000000000000000000001'), +(b'1010101010101010101010101010101010101010101010101010101010101010'), +(b'0101010101010101010101010101010101010101010101010101010101010101'); +select hex(a) from t1; +drop table t1; + +create table t1 (a bit); +insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001'); +select hex(a) from t1; +--error ER_DUP_ENTRY +alter table t1 add unique (a); +drop table t1; + +create table t1 (a bit(2)); +insert into t1 values (b'00'), (b'01'), (b'10'), (b'100'); +select a+0 from t1; +alter table t1 add key (a); +explain select a+0 from t1; +select a+0 from t1; +drop table t1; + +create table t1 (a bit(7), b bit(9), key(a, b)); +insert into t1 values +(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177), +(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380), +(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36), +(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499), +(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403), +(44, 307), (68, 454), (57, 135); +explain select a+0 from t1; +select a+0 from t1; +explain select b+0 from t1; +select b+0 from t1; +explain select a+0, b+0 from t1; +select a+0, b+0 from t1; +explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1; +select a+0, b+0 from t1 where a > 40 and b > 200 order by 1; +explain select a+0, b+0 from t1 where a > 40 and a < 70 order by 2; +select a+0, b+0 from t1 where a > 40 and a < 70 order by 2; +set @@max_length_for_sort_data=0; +select a+0, b+0 from t1 where a > 40 and a < 70 order by 2; +select hex(min(a)) from t1; +select hex(min(b)) from t1; +select hex(min(a)), hex(max(a)), hex(min(b)), hex(max(b)) from t1; +drop table t1; + +create table t1 (a int not null, b bit, c bit(9), key(a, b, c)); +insert into t1 values +(4, NULL, 1), (4, 0, 3), (2, 1, 4), (1, 1, 100), (4, 0, 23), (4, 0, 54), +(56, 0, 22), (4, 1, 100), (23, 0, 1), (4, 0, 34); +select a+0, b+0, c+0 from t1; +select hex(min(b)) from t1 where a = 4; +select hex(min(c)) from t1 where a = 4 and b = 0; +select hex(max(b)) from t1; +select a+0, b+0, c+0 from t1 where a = 4 and b = 0 limit 2; +select a+0, b+0, c+0 from t1 where a = 4 and b = 1; +select a+0, b+0, c+0 from t1 where a = 4 and b = 1 and c=100; +select a+0, b+0, c+0 from t1 order by b desc; +select a+0, b+0, c+0 from t1 order by c; +drop table t1; + +create table t1(a bit(2), b bit(2)); +insert into t1 (a) values (0x01), (0x03), (0x02); +update t1 set b= concat(a); +select a+0, b+0 from t1; +drop table t1; + +# Some magic numbers + +create table t1 (a bit(7), key(a)); +insert into t1 values (44), (57); +select a+0 from t1; +drop table t1; + +# +# Test conversion to and from strings +# +create table t1 (a bit(3), b bit(12)); +insert into t1 values (7,(1<<12)-2), (0x01,0x01ff); +select hex(a),hex(b) from t1; +select hex(concat(a)),hex(concat(b)) from t1; +drop table t1; + +# +# Bug #9571: problem with primary key creation +# + +create table t1(a int, b bit not null); +alter table t1 add primary key (a); +drop table t1; + +# +# myisam <-> heap +# + +create table t1 (a bit(19), b bit(5)); +insert into t1 values (1000, 10), (3, 8), (200, 6), (2303, 2), (12345, 4), (1, 0); +select a+0, b+0 from t1; +alter table t1 engine=heap; +select a+0, b+0 from t1; +alter table t1 add key(a, b); +select a+0, b+0 from t1; +alter table t1 engine=myisam; +select a+0, b+0 from t1; +create table t2 engine=heap select * from t1; +select a+0, b+0 from t2; +drop table t1; +create table t1 select * from t2; +select a+0, b+0 from t1; +drop table t1, t2; + +# +# Bug #10179: problem with NULLs and default values +# + +create table t1 (a int, b time, c tinyint, d bool, e char(10), f bit(1), + g bit(1) NOT NULL default 1, h char(1) default 'a'); +insert into t1 set a=1; +select hex(g), h from t1; +drop table t1; + +create table t1 (a int, b time, c tinyint, d bool, e char(10), f bit(1), + g bit(1) NOT NULL default 1); +insert into t1 set a=1; +select hex(g) from t1; +drop table t1; + +create table t1 (a int, b time, c tinyint, d bool, e char(10), f bit(1), + h char(1) default 'a') engine=myisam; +insert into t1 set a=1; +select h from t1; +drop table t1; + +# +# Bug #10539 +# + +create table t1 (a bit(8)) engine=heap; +insert into t1 values ('1111100000'); +select a+0 from t1; +drop table t1; + +# +# Bug #11091: union +# + +create table t1 (a bit(7)); +insert into t1 values (120), (0), (111); +select a+0 from t1 union select a+0 from t1; +select a+0 from t1 union select NULL; +select NULL union select a+0 from t1; +create table t2 select a from t1 union select a from t1; +select a+0 from t2; +show create table t2; +drop table t1, t2; + +# +# Bug #11572: view +# + +create table t1 (id1 int(11), b1 bit(1)); +create table t2 (id2 int(11), b2 bit(1)); +insert into t1 values (1, 1), (2, 0), (3, 1); +insert into t2 values (2, 1), (3, 0), (4, 0); +create algorithm=undefined view v1 as + select b1+0, b2+0 from t1, t2 where id1 = id2 and b1 = 0 + union + select b1+0, b2+0 from t1, t2 where id1 = id2 and b2 = 1; +select * from v1; +drop table t1, t2; +drop view v1; + +# +# Bug #10617: bulk-insert +# + +create table t1(a bit(4)); +insert into t1(a) values (1), (2), (5), (4), (3); +insert into t1 select * from t1; +select a+0 from t1; +drop table t1; + +# +# join +# + +create table t1 (a1 int(11), b1 bit(2)); +create table t2 (a2 int(11), b2 bit(2)); +insert into t1 values (1, 1), (2, 0), (3, 1), (4, 2); +insert into t2 values (2, 1), (3, 0), (4, 1), (5, 2); +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2; +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1; +select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2; +select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1; +select 1 from t1 join t2 on b1 = b2 group by b1 order by 1; +select b1+0,sum(b1), sum(b2) from t1 join t2 on b1 = b2 group by b1 order by 1; +drop table t1, t2; + +# +# Bug #13601: Wrong field length reported for BIT fields +# +create table t1 (a bit(7)); +insert into t1 values (0x60); +--enable_metadata +select * from t1; +--disable_metadata +drop table t1; + +# +# Bug#15583: BIN()/OCT()/CONV() do not work with BIT values +# +create table bug15583(b BIT(8), n INT); +insert into bug15583 values(128, 128); +insert into bug15583 values(null, null); +insert into bug15583 values(0, 0); +insert into bug15583 values(255, 255); +select hex(b), bin(b), oct(b), hex(n), bin(n), oct(n) from bug15583; +select hex(b)=hex(n) as should_be_onetrue, bin(b)=bin(n) as should_be_onetrue, oct(b)=oct(n) as should_be_onetrue from bug15583; +select hex(b + 0), bin(b + 0), oct(b + 0), hex(n), bin(n), oct(n) from bug15583; +select conv(b, 10, 2), conv(b + 0, 10, 2) from bug15583; +drop table bug15583; + +# +# Bug #22271: data casting may affect data stored in the next column(s?) +# + +create table t1(a bit(1), b smallint unsigned); +insert into t1 (b, a) values ('2', '1'); +select hex(a), b from t1; +drop table t1; + +# +# type was not properly initalized, which caused key_copy to fail +# + +create table t1(bit_field bit(2), int_field int, key a(bit_field)); +insert into t1 values (1,2); +handler t1 open as t1; +handler t1 read a=(1); +handler t1 close; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/type_date.test b/mysql-test/suite/pbxt/t/type_date.test new file mode 100644 index 00000000000..6a034c89ab5 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_date.test @@ -0,0 +1,128 @@ +# +# test of problem with date fields +# +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1 (a char(16), b date, c datetime); +insert into t1 SET a='test 2000-01-01', b='2000-01-01', c='2000-01-01'; +select * from t1 where c = '2000-01-01'; +select * from t1 where b = '2000-01-01'; +drop table t1; + +# +# problem with date conversions +# + +CREATE TABLE t1 (name char(6),cdate date); +INSERT INTO t1 VALUES ('name1','1998-01-01'); +INSERT INTO t1 VALUES ('name2','1998-01-01'); +INSERT INTO t1 VALUES ('name1','1998-01-02'); +INSERT INTO t1 VALUES ('name2','1998-01-02'); +CREATE TABLE t2 (cdate date, note char(6)); +INSERT INTO t2 VALUES ('1998-01-01','note01'); +INSERT INTO t2 VALUES ('1998-01-02','note02'); +select name,t1.cdate,note from t1,t2 where t1.cdate=t2.cdate and t1.cdate='1998-01-01'; +drop table t1,t2; + +# +# Date and BETWEEN +# + +CREATE TABLE t1 ( datum DATE ); +INSERT INTO t1 VALUES ( "2000-1-1" ); +INSERT INTO t1 VALUES ( "2000-1-2" ); +INSERT INTO t1 VALUES ( "2000-1-3" ); +INSERT INTO t1 VALUES ( "2000-1-4" ); +INSERT INTO t1 VALUES ( "2000-1-5" ); +SELECT * FROM t1 WHERE datum BETWEEN cast("2000-1-2" as date) AND cast("2000-1-4" as date); +SELECT * FROM t1 WHERE datum BETWEEN cast("2000-1-2" as date) AND datum - INTERVAL 100 DAY; +DROP TABLE t1; + +# +# test of max(date) and having +# + +CREATE TABLE t1 ( + user_id char(10), + summa int(11), + rdate date +); +INSERT INTO t1 VALUES ('aaa',100,'1998-01-01'); +INSERT INTO t1 VALUES ('aaa',200,'1998-01-03'); +INSERT INTO t1 VALUES ('bbb',50,'1998-01-02'); +INSERT INTO t1 VALUES ('bbb',200,'1998-01-04'); +select max(rdate) as s from t1 where rdate < '1998-01-03' having s> "1998-01-01"; +select max(rdate) as s from t1 having s="1998-01-04"; +select max(rdate+0) as s from t1 having s="19980104"; +drop table t1; + +# +# Test of date and not null +# + +create table t1 (date date); +insert into t1 values ("2000-08-10"),("2000-08-11"); +select date_add(date,INTERVAL 1 DAY),date_add(date,INTERVAL 1 SECOND) from t1; +drop table t1; + +# +# Test problem with DATE_FORMAT +# + +CREATE TABLE t1(AFIELD INT); +INSERT INTO t1 VALUES(1); +CREATE TABLE t2(GMT VARCHAR(32)); +INSERT INTO t2 VALUES('GMT-0800'); +SELECT DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) FROM t1, t2 GROUP BY t1.AFIELD; +INSERT INTO t1 VALUES(1); +SELECT DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)), DATE_FORMAT("2002-03-06 10:11:12", CONCAT('%a, %d %M %Y %H:%i:%s ' , t2.GMT)) FROM t1,t2 GROUP BY t1.AFIELD; +drop table t1,t2; + +# +# Multiple SELECT DATE_FORMAT gave incorrect results (Bug #4036) +# + +CREATE TABLE t1 (f1 time default NULL, f2 time default NULL); +INSERT INTO t1 (f1, f2) VALUES ('09:00', '12:00'); +SELECT DATE_FORMAT(f1, "%l.%i %p") , DATE_FORMAT(f2, "%l.%i %p") FROM t1; +DROP TABLE t1; + +# +# Bug 4937: different date -> string conversion when using SELECT ... UNION +# and INSERT ... SELECT ... UNION +# + +CREATE TABLE t1 (f1 DATE); +CREATE TABLE t2 (f2 VARCHAR(8)); +CREATE TABLE t3 (f2 CHAR(8)); + +INSERT INTO t1 VALUES ('1978-11-26'); +INSERT INTO t2 SELECT f1+0 FROM t1; +INSERT INTO t2 SELECT f1+0 FROM t1 UNION SELECT f1+0 FROM t1; +INSERT INTO t3 SELECT f1+0 FROM t1; +INSERT INTO t3 SELECT f1+0 FROM t1 UNION SELECT f1+0 FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +DROP TABLE t1, t2, t3; + +# Test that setting YEAR to invalid string results in default value, not +# 2000. (Bug #6067) +CREATE TABLE t1 (y YEAR); +INSERT INTO t1 VALUES ('abc'); +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug#21677: Wrong result when comparing a DATE and a DATETIME in BETWEEN +# +create table t1(start_date date, end_date date); +insert into t1 values ('2000-01-01','2000-01-02'); +select 1 from t1 where cast('2000-01-01 12:01:01' as datetime) between start_date and end_date; +drop table t1; +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/type_datetime.test b/mysql-test/suite/pbxt/t/type_datetime.test new file mode 100644 index 00000000000..4dd95d7535e --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_datetime.test @@ -0,0 +1,140 @@ +# +# testing different DATETIME ranges +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (t datetime); +insert into t1 values (101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030100000000),(20030000000000); +select * from t1; +delete from t1 where t > 0; +optimize table t1; +check table t1; +delete from t1; +insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030100000000"),("20030000000000"); + +# Strange dates +insert into t1 values ("2003-003-03"); + +# Bug #7308: ISO-8601 date format not handled correctly +insert into t1 values ("20030102T131415"),("2001-01-01T01:01:01"), ("2001-1-1T1:01:01"); +select * from t1; + +# Test some wrong dates +truncate table t1; +insert into t1 values("2003-0303 12:13:14"); +select * from t1; +drop table t1; + +# +# Test insert of now() and curtime() +# + +CREATE TABLE t1 (a timestamp, b date, c time, d datetime); +insert into t1 (b,c,d) values(now(),curtime(),now()); +select date_format(a,"%Y-%m-%d")=b,right(a+0,6)=c+0,a=d+0 from t1; +drop table t1; + +# +# Test of datetime and not null +# + +CREATE TABLE t1 (a datetime not null); +insert into t1 values (0); +select * from t1 where a is null; +drop table t1; + +# +# Test with bug when propagating DATETIME to integer and WHERE optimization +# + +create table t1 (id int, dt datetime); +insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00"),(4,"2003-09-15 01:20:30"); +select * from t1 where dt='2001-08-14 00:00:00' and dt = if(id=1,'2001-08-14 00:00:00','1999-08-15'); +create index dt on t1 (dt); +select * from t1 where dt > 20021020; +select * from t1 ignore index (dt) where dt > 20021020; +drop table t1; + +# +# Test of datetime optimization +# + +CREATE TABLE `t1` ( + `date` datetime NOT NULL default '0000-00-00 00:00:00', + `numfacture` int(6) unsigned NOT NULL default '0', + `expedition` datetime NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY (`numfacture`), + KEY `date` (`date`), + KEY `expedition` (`expedition`) +) ENGINE=MyISAM; + +INSERT INTO t1 (expedition) VALUES ('0001-00-00 00:00:00'); +SELECT * FROM t1 WHERE expedition='0001-00-00 00:00:00'; +INSERT INTO t1 (numfacture,expedition) VALUES ('1212','0001-00-00 00:00:00'); +SELECT * FROM t1 WHERE expedition='0001-00-00 00:00:00'; +EXPLAIN SELECT * FROM t1 WHERE expedition='0001-00-00 00:00:00'; +drop table t1; +create table t1 (a datetime not null, b datetime not null); +insert into t1 values (now(), now()); +insert into t1 values (now(), now()); +select * from t1 where a is null or b is null; +drop table t1; + +# +# Let us check if we properly treat wrong datetimes and produce proper +# warnings (for both strings and numbers) +# +create table t1 (t datetime); +insert into t1 values (20030102030460),(20030102036301),(20030102240401), + (20030132030401),(20031302030401),(100001202030401); +select * from t1; +delete from t1; +insert into t1 values + ("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"), + ("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00"); +select * from t1; +delete from t1; +insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer"); +select * from t1 order by t; +drop table t1; + +# +# Test for bug #7297 "Two digit year should be interpreted correctly even +# with zero month and day" +# +create table t1 (dt datetime); +# These dates should be treated as dates in 21st century +insert into t1 values ("12-00-00"), ("00-00-00 01:00:00"); +# Zero dates are still special :/ +insert into t1 values ("00-00-00"), ("00-00-00 00:00:00"); +select * from t1; +drop table t1; + +# End of 4.1 tests + +# +# Bug#21475: Wrongly applied constant propagation leads to a false comparison. +# +CREATE TABLE t1(a DATETIME NOT NULL); +INSERT INTO t1 VALUES ('20060606155555'); +SELECT a FROM t1 WHERE a=(SELECT MAX(a) FROM t1) AND (a="20060606155555"); +PREPARE s FROM 'SELECT a FROM t1 WHERE a=(SELECT MAX(a) FROM t1) AND (a="20060606155555")'; +EXECUTE s; +DROP PREPARE s; +DROP TABLE t1; + + +# +# Bug 19491 (CAST DATE AS DECIMAL returns incorrect result +# +SELECT CAST(CAST('2006-08-10' AS DATE) AS DECIMAL(20,6)); +SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) AS DECIMAL(20,6)); +SELECT CAST(CAST('2006-08-10 10:11:12' AS DATETIME) + INTERVAL 14 MICROSECOND AS DECIMAL(20,6)); +SELECT CAST(CAST('10:11:12.098700' AS TIME) AS DECIMAL(20,6)); + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/type_decimal.test b/mysql-test/suite/pbxt/t/type_decimal.test new file mode 100644 index 00000000000..8f973f4ae55 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_decimal.test @@ -0,0 +1,400 @@ +# bug in decimal() with negative numbers by kaido@tradenet.ee + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings +SET SQL_WARNINGS=1; + +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + datatype_id int(11) DEFAULT '0' NOT NULL, + minvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL, + maxvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL, + valuename varchar(20), + forecolor int(11), + backcolor int(11), + PRIMARY KEY (id), + UNIQUE datatype_id (datatype_id, minvalue, maxvalue) +); +INSERT INTO t1 VALUES ( '1', '4', '0.0000000000', '0.0000000000', 'Ei saja', '0', '16776960'); +INSERT INTO t1 VALUES ( '2', '4', '1.0000000000', '1.0000000000', 'Sajab', '16777215', '255'); +INSERT INTO t1 VALUES ( '3', '1', '2.0000000000', '49.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '60', '11', '0.0000000000', '0.0000000000', 'Rikkis', '16777215', '16711680'); +INSERT INTO t1 VALUES ( '4', '12', '1.0000000000', '1.0000000000', 'nork sadu', '65280', '14474460'); +INSERT INTO t1 VALUES ( '5', '12', '2.0000000000', '2.0000000000', 'keskmine sadu', '255', '14474460'); +INSERT INTO t1 VALUES ( '6', '12', '3.0000000000', '3.0000000000', 'tugev sadu', '127', '14474460'); +INSERT INTO t1 VALUES ( '43', '39', '6.0000000000', '6.0000000000', 'lobjakas', '13107327', '16763080'); +INSERT INTO t1 VALUES ( '40', '39', '2.0000000000', '2.0000000000', 'vihm', '8355839', '16777215'); +INSERT INTO t1 VALUES ( '53', '1', '-35.0000000000', '-5.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '41', '39', '3.0000000000', '3.0000000000', 'külm vihm', '120', '16763080'); +INSERT INTO t1 VALUES ( '12', '21', '21.0000000000', '21.0000000000', 'Kuiv', '13158600', '16777215'); +INSERT INTO t1 VALUES ( '13', '21', '13.0000000000', '13.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '14', '21', '22.0000000000', '22.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '19', '21', '33.0000000000', '33.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '15', '21', '23.0000000000', '23.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '16', '21', '31.0000000000', '31.0000000000', 'Kuiv', '13158600', '16777215'); +INSERT INTO t1 VALUES ( '17', '21', '12.0000000000', '12.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '18', '21', '32.0000000000', '32.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '20', '21', '331.0000000000', '331.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '21', '21', '11.0000000000', '11.0000000000', 'Kuiv', '13158600', '16777215'); +INSERT INTO t1 VALUES ( '22', '33', '21.0000000000', '21.0000000000', 'Pilves, kuiv', '8355711', '12632256'); +INSERT INTO t1 VALUES ( '23', '33', '13.0000000000', '13.0000000000', 'Sajab, märg', '0', '8355839'); +INSERT INTO t1 VALUES ( '24', '33', '22.0000000000', '22.0000000000', 'Pilves, niiske', '8355711', '12632319'); +INSERT INTO t1 VALUES ( '29', '33', '33.0000000000', '33.0000000000', 'Selge, märg', '16777215', '8355839'); +INSERT INTO t1 VALUES ( '25', '33', '23.0000000000', '23.0000000000', 'Pilves, märg', '8355711', '8355839'); +INSERT INTO t1 VALUES ( '26', '33', '31.0000000000', '31.0000000000', 'Selge, kuiv', '16777215', '12632256'); +INSERT INTO t1 VALUES ( '27', '33', '12.0000000000', '12.0000000000', 'Sajab, niiske', '0', '12632319'); +INSERT INTO t1 VALUES ( '28', '33', '32.0000000000', '32.0000000000', 'Selge, niiske', '16777215', '12632319'); +INSERT INTO t1 VALUES ( '30', '33', '331.0000000000', '331.0000000000', 'Härmatis! selge,kuiv', '16711680', '12632256'); +INSERT INTO t1 VALUES ( '31', '33', '11.0000000000', '11.0000000000', 'Sajab, kuiv', '0', '12632256'); +INSERT INTO t1 VALUES ( '32', '11', '1.0000000000', '1.0000000000', 'Korras', '16777215', '49152'); +INSERT INTO t1 VALUES ( '33', '21', '335.0000000000', '335.0000000000', 'Härmatis!', '14448840', '11842740'); +INSERT INTO t1 VALUES ( '34', '21', '134.0000000000', '134.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '35', '21', '133.0000000000', '133.0000000000', 'Hoiatus, märg!', '5263615', '13158600'); +INSERT INTO t1 VALUES ( '36', '21', '135.0000000000', '135.0000000000', 'Härmatis!', '14448840', '11842740'); +INSERT INTO t1 VALUES ( '37', '21', '334.0000000000', '334.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '38', '21', '132.0000000000', '132.0000000000', 'Hoiatus, niiske!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '39', '39', '1.0000000000', '1.0000000000', 'ei saja', '11206570', '16777215'); +INSERT INTO t1 VALUES ( '44', '39', '4.0000000000', '5.0000000000', 'lumi', '16711680', '16763080'); +INSERT INTO t1 VALUES ( '45', '12', '0.0000000000', '0.0000000000', '', '16777215', '14474460'); +INSERT INTO t1 VALUES ( '46', '39', '8.0000000000', '8.0000000000', 'rahe', '9830400', '16763080'); +INSERT INTO t1 VALUES ( '47', '39', '9.0000000000', '9.0000000000', 'tüüp ebaselge', '12582912', '16777215'); +INSERT INTO t1 VALUES ( '48', '39', '7.0000000000', '7.0000000000', 'lumetuisk', '7209070', '16763080'); +INSERT INTO t1 VALUES ( '142', '15', '2.0000000000', '49.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '52', '1', '-4.9000000000', '-0.1000000000', '', '0', '15774720'); +INSERT INTO t1 VALUES ( '141', '15', '-4.9000000000', '-0.1000000000', '', '0', '15774720'); +INSERT INTO t1 VALUES ( '55', '8', '0.0000000000', '0.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '56', '8', '0.0100000000', '0.1000000000', '', '0', '16770560'); +INSERT INTO t1 VALUES ( '57', '8', '0.1100000000', '25.0000000000', '', '0', '15774720'); +INSERT INTO t1 VALUES ( '58', '2', '90.0000000000', '94.9000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '59', '6', '0.0000000000', '360.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '61', '21', '38.0000000000', '38.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '62', '38', '500.0000000000', '999.0000000000', '', '0', '16770560'); +INSERT INTO t1 VALUES ( '63', '38', '1000.0000000000', '2000.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '64', '17', '0.0000000000', '0.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '65', '17', '0.1000000000', '10.0000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '67', '21', '412.0000000000', '412.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '68', '21', '413.0000000000', '413.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '69', '21', '113.0000000000', '113.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '70', '21', '416.0000000000', '416.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '71', '38', '0.0000000000', '499.0000000000', '', NULL, '16711680'); +INSERT INTO t1 VALUES ( '72', '22', '-49.0000000000', '49.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '73', '13', '0.0000000000', '9.9000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '74', '13', '10.0000000000', '14.9000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '75', '7', '0.0000000000', '50.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '76', '18', '0.0000000000', '0.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '77', '18', '0.1000000000', '10.0000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '78', '19', '300.0000000000', '400.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '79', '19', '0.0000000000', '299.0000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '80', '23', '0.0000000000', '100.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '81', '24', '0.0000000000', '200.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '82', '26', '0.0000000000', '0.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '83', '26', '0.1000000000', '5.0000000000', '', NULL, '16776960'); +INSERT INTO t1 VALUES ( '84', '21', '422.0000000000', '422.0000000000', 'Niiske', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '85', '21', '411.0000000000', '411.0000000000', 'Saju hoiat.,kuiv!', '16777215', '13158600'); +INSERT INTO t1 VALUES ( '86', '21', '423.0000000000', '423.0000000000', 'Märg', '5263615', '16777215'); +INSERT INTO t1 VALUES ( '144', '16', '-49.0000000000', '-5.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '88', '16', '2.0000000000', '49.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '89', '21', '338.0000000000', '338.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '90', '21', '332.0000000000', '332.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '91', '21', '114.0000000000', '114.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '92', '21', '117.0000000000', '117.0000000000', 'Hoiatus, JÄÄ!', '14448840', '16711680'); +INSERT INTO t1 VALUES ( '93', '21', '116.0000000000', '116.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '94', '21', '414.0000000000', '414.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '95', '21', '325.0000000000', '325.0000000000', 'Härmatis!', '14448840', '11842740'); +INSERT INTO t1 VALUES ( '96', '21', '321.0000000000', '321.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '97', '21', '328.0000000000', '328.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '98', '21', '28.0000000000', '28.0000000000', 'Niiske ja sool', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '99', '21', '118.0000000000', '118.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '100', '21', '418.0000000000', '418.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '101', '21', '322.0000000000', '322.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '102', '21', '428.0000000000', '428.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '103', '21', '432.0000000000', '432.0000000000', 'Hoiatus, niiske!', '7895240', '13158600'); +INSERT INTO t1 VALUES ( '104', '21', '421.0000000000', '421.0000000000', 'Saju hoiat.,kuiv!', '16777215', '13158600'); +INSERT INTO t1 VALUES ( '105', '21', '24.0000000000', '24.0000000000', 'Märg ja sool', '255', '16777215'); +INSERT INTO t1 VALUES ( '106', '21', '438.0000000000', '438.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '107', '21', '112.0000000000', '112.0000000000', 'Hoiatus, niiske!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '108', '21', '34.0000000000', '34.0000000000', 'Märg ja sool', '255', '16777215'); +INSERT INTO t1 VALUES ( '109', '21', '434.0000000000', '434.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '110', '21', '124.0000000000', '124.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '111', '21', '424.0000000000', '424.0000000000', 'Hoiatus, M+S!', '255', '13158600'); +INSERT INTO t1 VALUES ( '112', '21', '123.0000000000', '123.0000000000', 'Hoiatus, märg!', '5263615', '13158600'); +INSERT INTO t1 VALUES ( '140', '15', '-49.0000000000', '-5.0000000000', '', '0', '16777215'); +INSERT INTO t1 VALUES ( '114', '21', '18.0000000000', '18.0000000000', 'Niiske ja sool', '9869055', '16777215'); +INSERT INTO t1 VALUES ( '115', '21', '122.0000000000', '122.0000000000', 'Hoiatus, niiske!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '116', '21', '14.0000000000', '14.0000000000', 'Märg ja sool', '255', '16777215'); +INSERT INTO t1 VALUES ( '117', '21', '311.0000000000', '311.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '121', '2', '95.0000000000', '100.0000000000', '', NULL, '15774720'); +INSERT INTO t1 VALUES ( '118', '2', '0.0000000000', '89.9000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '119', '21', '16.0000000000', '16.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '120', '21', '26.0000000000', '26.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '122', '13', '15.0000000000', '50.0000000000', '', NULL, '15774720'); +INSERT INTO t1 VALUES ( '123', '5', '0.0000000000', '9.9000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '124', '5', '10.0000000000', '14.9000000000', '', NULL, '16770560'); +INSERT INTO t1 VALUES ( '125', '5', '15.0000000000', '50.0000000000', '', NULL, '15774720'); +INSERT INTO t1 VALUES ( '126', '21', '128.0000000000', '128.0000000000', 'Hoiatus, N+S!', '9869055', '13158600'); +INSERT INTO t1 VALUES ( '127', '21', '318.0000000000', '318.0000000000', 'Härm.hoiatus, N+S!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '128', '21', '312.0000000000', '312.0000000000', 'Härm.hoiat., niiske!', '16744319', '13158600'); +INSERT INTO t1 VALUES ( '129', '21', '126.0000000000', '126.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '130', '21', '324.0000000000', '324.0000000000', 'Härmatise hoiatus!', '14448840', '13158600'); +INSERT INTO t1 VALUES ( '131', '21', '316.0000000000', '316.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '132', '1', '0.0000000000', '1.9000000000', '', NULL, '16769024'); +INSERT INTO t1 VALUES ( '134', '3', '-50.0000000000', '50.0000000000', '', NULL, '16777215'); +INSERT INTO t1 VALUES ( '135', '8', '26.0000000000', '2000.0000000000', '', '9868950', '15774720'); +INSERT INTO t1 VALUES ( '136', '21', '426.0000000000', '426.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '137', '21', '127.0000000000', '127.0000000000', 'Hoiatus, JÄÄ!', '14448840', '16711680'); +INSERT INTO t1 VALUES ( '138', '21', '121.0000000000', '121.0000000000', 'Kuiv', '13158600', '16777215'); +INSERT INTO t1 VALUES ( '139', '21', '326.0000000000', '326.0000000000', 'Lumine!', '16711680', '11842740'); +INSERT INTO t1 VALUES ( '143', '16', '-4.9000000000', '-0.1000000000', '', NULL, '15774720'); +INSERT INTO t1 VALUES ( '145', '15', '0.0000000000', '1.9000000000', '', '0', '16769024'); +INSERT INTO t1 VALUES ( '146', '16', '0.0000000000', '1.9000000000', '', '0', '16769024'); +select * from t1 where minvalue<=1 and maxvalue>=-1 and datatype_id=16; +select * from t1 where minvalue<=-1 and maxvalue>=-1 and datatype_id=16; +drop table t1; + +# +# Test of correct handling leading zero and +/- signs +# then values are passed as strings +# Also test overflow handling in this case +# + +create table t1 (a decimal(10,2)); +insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0"); +insert into t1 values ("-.1"),("+.1"),(".1"); +insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); +insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); +insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); +insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); +insert into t1 values ("1e+4294967296"),("1e-4294967296"); +insert into t1 values ("1e+18446744073709551615"),("1e+18446744073709551616"),("1e-9223372036854775807"),("1e-9223372036854775809"); +insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); +select * from t1; +drop table t1; + +create table t1 (a decimal(10,2) unsigned); +insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0"); +insert into t1 values ("-.1"),("+.1"),(".1"); +insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); +insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); +insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); +insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); +insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); +select * from t1; +drop table t1; + +create table t1 (a decimal(10,2) zerofill); +insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0"); +insert into t1 values ("-.1"),("+.1"),(".1"); +insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); +insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); +insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); +insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); +insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); +select * from t1; +drop table t1; + + +create table t1 (a decimal(10,2)); +# The -0.0 needs to be quoted as not all platforms supports this +insert into t1 values (0.0),("-0.0"),(+0.0),(01.0),(+01.0),(-01.0); +insert into t1 values (-.1),(+.1),(.1); +insert into t1 values (00000000000001),(+0000000000001),(-0000000000001); +insert into t1 values (+111111111.11),(111111111.11),(-11111111.11); +insert into t1 values (-111111111.11),(+1111111111.11),(1111111111.11); +insert into t1 values (1e+100),(1e-100),(-1e+100); +insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0); +insert into t1 values (MID("987",1,2)),("987 "),("987.6e+2 "); +select * from t1; +drop table t1; + +# +# Test correct handling of overflowed decimal values +# + +create table t1 (a decimal); +insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999); +select * from t1; +drop table t1; +create table t1 (a decimal unsigned); +insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999); +select * from t1; +drop table t1; +create table t1 (a decimal zerofill); +insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999); +select * from t1; +drop table t1; +create table t1 (a decimal unsigned zerofill); +insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999); +select * from t1; +drop table t1; + +# Exponent overflow bug +create table t1(a decimal(10,0)); +insert into t1 values ("1e4294967295"); +select * from t1; +delete from t1; +insert into t1 values("1e4294967297"); +select * from t1; +drop table t1; + +# +# Test of wrong decimal type +# + +--error 1064 +CREATE TABLE t1 (a_dec DECIMAL(-1,0)); +--error 1064 +CREATE TABLE t1 (a_dec DECIMAL(-2,1)); +--error 1064 +CREATE TABLE t1 (a_dec DECIMAL(-1,1)); +--error 1427 +CREATE TABLE t1 (a_dec DECIMAL(0,11)); + +# +# Zero prepend overflow bug +# +--disable_warnings +create table t1(a decimal(7,3)); +insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000'); +select * from t1; +drop table t1; +create table t1(a decimal(7,3) unsigned); +insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000'); +select * from t1; +drop table t1; +create table t1(a decimal(7,3) zerofill); +insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000'); +--enable_warnings +select * from t1; +drop table t1; + +# +# Bug #7589: a problem with update from column +# + +create table t1(a decimal(10,5), b decimal(10,1)); +insert into t1 values(123.12345, 123.12345); +update t1 set b=a; +select * from t1; +drop table t1; + +# End of 4.1 tests + +# +# Test for BUG#8397: decimal type in subselects (Item_cache_decimal) +# +CREATE TABLE t1 +(EMPNUM CHAR(3) NOT NULL, +HOURS DECIMAL(5)); +CREATE TABLE t2 +(EMPNUM CHAR(3) NOT NULL, +HOURS BIGINT); + +INSERT INTO t1 VALUES ('E1',40); +INSERT INTO t1 VALUES ('E8',NULL); +INSERT INTO t2 VALUES ('E1',40); + +SELECT EMPNUM FROM t1 WHERE HOURS IN (SELECT HOURS FROM t2); +SELECT EMPNUM FROM t1 WHERE HOURS IN (SELECT HOURS FROM t1); + +DROP TABLE t1,t2; + +# +# Test limits of decimal +# +create table t1 (d decimal(64,0)); +insert into t1 values (1); +select * from t1; +drop table t1; +create table t1 (d decimal(5)); +show create table t1; +drop table t1; +create table t1 (d decimal); +show create table t1; +drop table t1; +--error 1426 +create table t1 (d decimal(66,0)); + +# +# Test example from manual +# + +CREATE TABLE t1 (i INT, d1 DECIMAL(9,2), d2 DECIMAL(9,2)); +INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00), +(2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40), +(2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00), +(4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00), +(5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20), +(6, 0.00, 0.00), (6, -51.40, 0.00); + +SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1 GROUP BY i HAVING a <> b; +SELECT i, ROUND(SUM(d1), 2) AS a, ROUND(SUM(d2), 2) AS b FROM t1 GROUP BY i +HAVING a <> b; +drop table t1; + +# +# A test case for Bug#4956 "strange result, insert into longtext, parameter +# with numeric value": ensure that conversion is done identically no matter +# where the input data comes from. +# +create table t1 (c1 varchar(100), c2 longtext); +insert into t1 set c1= 'non PS, 1.0 as constant', c2=1.0; +prepare stmt from "insert into t1 set c1='PS, 1.0 as constant ', c2=1.0"; +execute stmt; +set @a=1.0; +insert into t1 set c1='non PS, 1.0 in parameter', c2=@a; +prepare stmt from "insert into t1 set c1='PS, 1.0 in parameter ', c2=?"; +execute stmt using @a; +select * from t1; +deallocate prepare stmt; +drop table t1; + +# +# A test case for Bug#5673 "Rounding problem in 4.0.21 inserting decimal +# value into a char field": this is a regression bug in 4.0 tree caused by +# a fix for some other decimal conversion issue. The patch never was +# approved to get into 4.0 (maybe because it was considered too intrusive) +# + +create table t1 ( + strippedproductid char(15) not null default '', + zlevelprice decimal(10,2) default null, + primary key (strippedproductid) +); + +create table t2 ( + productid char(15) not null default '', + zlevelprice char(21) default null, + primary key (productid) +); + +insert into t1 values ('002trans','49.99'); +insert into t1 values ('003trans','39.98'); +insert into t1 values ('004trans','31.18'); + +insert INTO t2 SELECT * FROM t1; + +select * from t2; +drop table t1, t2; + +# +# Bug #17826 'type_decimal' fails with ps-protocol +# +create table t1 (f1 decimal(5)); +insert into t1 values (40); +flush tables; +select f1 from t1 where f1 in (select f1 from t1); +drop table t1; + +# +# Bug#22183: Unhandled NULL caused server crash +# +create table t1 as + select from_days(s) as date,t + from (select 1 as s,'t' as t union select null, null ) as sub1; +select group_concat(t) from t1 group by week(date)/10; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/type_enum.test b/mysql-test/suite/pbxt/t/type_enum.test new file mode 100644 index 00000000000..10beff8fdc3 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_enum.test @@ -0,0 +1,165 @@ +# +# Problem with many enums +# + +--disable_warnings +DROP TABLE if exists t1; +--enable_warnings + +CREATE TABLE t1 ( + field enum('001001','001004','001010','001018','001019','001020','001021','001027','001028','001029','001030','001031','001100','002003','002004','002005','002007','002008','002009','002012','002013','002014','003002','003003','003004','003005','003006','003007','003008','003009','003010','003011','003012','003013','003014','003015','003016','003017','003018','003019','004002','004003','004005','004006','004007','004008','004010','004012','004014','004016','004017','004020','004021','004022','004023','004024','004025','004026','006002','006004','006006','006010','006011','006012','006013','006014','007001','007002','007003','007004','007005','007006','007007','007008','007009','007010','007011','007012','007013','007014','007015','007016','007017','007018','007019','007020','007021','007022','007023','007024','007025','007026','007027','007028','007029','007030','007031','007032','007033','007034','007035','007036','007037','007038','007039','007040','007043','007044','009001','009002','009004','009005','009006','009007','009008','009009','009010','009011','009012','009013','010002','010003','010004','010005','010006','010007','010008','010009','010010','010011','010012','010013','010015','010016','010017','010018','010019','010020','010021','010022','010023','010024','010025','010026','010027','010028','011001','011002','011003','011004','011006','011012','011013','011014','011015','011016','012017','012018','012019','012023','012027','012028','012029','012030','012031','012032','012033','012034','012035','012036','012037','012038','012039','014001','016002','016003','016004','016007','016010','016011','016016','016019','016020','016021','016022','016023','016024','016026','016027','016028','016029','016030','016031','016032','016033','016034','017002','018001','019002','019004','020001','020003','020004','020005','020006','020007','020008','020009','022001','022002','022003','023001','023002','023003','023004','023005','023006','023007','023008','023010','023011','023012','023017','023019','023020','023021','023025','023026','023027','023028','023029','023030','023031','023032','023033','023034','023035','025001','025003','025004','025005','025006','025007','025008','025009','025010','025011','025012','025013','025014','025015','025016','025017','025018','025019','025020','025021','025022','025023','025024','025025','025026','025027','025028','025029','025030','025031','025032','025033','025034','025035','025036','025037','025038','025039','025040','025041','025042','025043','025044','025045','025046','025047','025048','025049','025050','025051','025052','025053','025054','025055','025056','025057','025058','025059','025060','025061','025062','025063','027001','027002','027011','035008','035012','036001','037001','037003','037004','037005','037006','037007','037008','037009','038004','038005','038006','038007','038009','039001','039002','039003','039004','039005','039006','046001','046002','046003','046004','046005','046007','046008','046009','046010','046011','046012','046013','046014','047001','047002','048001','051001','051002','051003','051004','052001','052002','052005','053015','053016','053019','053020','053023','053024','053026','053028','053029','053033','053034','053036','053037','053038','053039','053041','053042','053043','053045','053046','053047','053048','053051','053052','053054','053055','053056','053057','053068','053069','053070','053073','053074','053075','053086','053094','053095','053096','053097','053098','053099','053100','053101','053102','053103','053104','053105','053107','053122','053123','053124','053125','053127','053128','054001','054002','054003','054004','054005','054006','054007','054009','054010','056001','056002','056003','056004','056005','056006','056009','056010','056011','056016','056017','056018','056019','056020','056021','056022','057001','057002','057003','057004','058002','058003','058004','058005','060001','060003','060004','060005','060006','060007','061002','061003','061004','061005','061006','069006','069007','069010','069011','069012','069013','069014','069015','069016','069017','069018','069020','069021','069022','069023','069024','071002','071003','071004','071005','071006','071008','071011','071013','071020','071021','071022','072001','073001','073002','073003','073004','074001','074002','074003','074004','074005','074006','074007','074008','074009','074010','074011','074012','075001','075007','076101','076102','076103','077001','077002','077003','077004','077006','077007','077008','077009','078005','079002','079003','079004','079005','079006','079007','081001','082006','082007','082011','082013','082014','082015','082016','082017','082021','082022','082023','082024','082025','082026','082027','082028','082029','082030','082031','082032','082033','082034','082035','082036','082037','082038','082039','082040','082041','082042','082043','082044','084001','084002','084003','084004','084005','084007','084008','084009','084011','084013','084014','084016','084017','084027','084031','084032','084033','084035','084036','084037','084038','084039','084040','084041','084042','084043','084044','084045','084046','084047','084048','084049','084050','084051','085001','085002','085003','085004','085005','085006','085007','085009','085011','085012','085013','085014','085015','085016','085017','085018','085019','085020','085021','085022','085023','085028','085029','085030','085031','085033','085034','085035','085036','085037','085038','085040','085041','085042','085043','085044','085045','085046','085047','085048','085063','085064','085065','085068','085070','085071','085073','085082','085083','085086','085088','085089','085090','085091','085092','085093','085094','085095','085096','085097','085098','085099','085100','085101','085102','085103','085104','085105','085106','085107','085108','085109','085110','085111','085112','085113','085115','085119','085120','085121','085122','085123','085124','085125','085126','085127','085128','085129','085130','085132','085133','085134','085135','085136','085137','086001','086002','086003','086004','086005','088001','088003','088005','088006','088007','088008','088009','089001','090001','090002','090003','090004','090005','090006','090007','090008','090009','090010','090013','090015','090016','090017','090018','090019','090022','090027','090028','091001','091002','091005','091008','091009','091010','091011','091012','091013','091014','091015','091016','091017','091018','093001','093003','093098','093100','093102','093104','093141','093142','093146','093151','093153','093167','093168','093176','094001','094002','094004','094005','095004','099001','099002','100001','101001','102002','102003','105001','105002','106001','113001','113002','113003','113004','113005','113006','113007','113008','113009','113010','113011','113012','113013','113014','113015','113016','113017','113018','113019','113020','113021','113022','113023','113024','113025','113026','113027','113028','114001','115001','115002','115003','115004','115005','115006','115007','115008','115009','115010','115011','115012','115013','115014','115015','115016','115017','115018','115020','115021','115022','115023','115025','115026','115027','115028','115029','115030','115031','115032','115033','115034','115035','115036','115039','115040','115041','115042','115043','115044','115045','115046','115047','115048','115049','115050','115051','115052','115053','115054','115055','115056','115057','115059','115060','115061','115062','115063','115064','115065','115066','115067','115068','115069','115070','115071','115072','115073','115075','115076','115081','115082','115085','115086','115087','115088','115095','115096','115097','115098','115099','115101','115102','115103','115104','115105','115106','115108','115109','115110','115111','115112','115113','115114','115115','115116','115117','115118','115119','115120','115121','115122','116001','116002','116003','116004','116005','116006','116007','116008','116009','116010','116011','116012','117001','117002','117003','123001','124010','124014','124015','124019','124024','124025','124026','124027','124028','124029','124030','124031','124032','124033','124035','124036','124037','124038','124039','124040','124041','124042','124043','124044','124045','124046','124047','124048','124049','124050','124051','124052','124053','124054','124055','124056','124057','124058','124059','124060','124061','124062','124063','124064','124065','126001','126002','126003','126004','126005','126006','126007','126008','126009','126010','126011','126012','130001','132001','132002','132003','133001','133008','133009','133010','133011','133012','133013','133014','133015','133016','133017','133018','133019','133020','133021','133022','133023','133024','133025','133027','133028','133029','133030','133031','134001','135001','135002','135003','135004','135005','135006','135007','135008','135009','135010','136001','137009','137010','137011','137012','137013','137014','137015','137016','137017','137018','137019','138001','138002','138003','138004','139001','139003','140001','141001','141002','141003','141006','141007','141008','141009','141011','141012','141014','141015','141016','141017','141018','141019','141020','141021','141022','141023','141024','141025','141026','141027','141028','142001','142002','142003','142004','142005','142006','142007','142008','142010','142011','142012','144001','145001','145002','145003','145004','145005','145006','145007','145008','145009','145010','145011','145012','145013','145014','145015','145016','147001','150003','150005','150009','150013','150014','150015','150016','150017','150020','150021','152001','152002','152003','152004','152005','152006','152007','154001','154002','154003','155001','155002','155003','155004','155005','155006','159001','159002','159003','159004','160001','160002','160003','161001','162001','162002','162003','162004','162007','162010','162011','162012','163001','163002','163003','163005','163010','163011','163014','163015','163016','165001','165002','165003','165004','165005','165006','165007','165008','165009','165010','165011','165012','165013','165014','165015','165016','165017','165018','165019','165020','165021','165022','165023','165024','165025','165026','165027','165028','165029','165030','165031','165032','165033','165034','165035','165036','167001','168001','168002','168003','168004','168005','168007','168008','168009','168010','168011','168012','168013','168014','169001','169002','169003','169007','169008','169009','169010','170001','171001','171002','171003','171004','171005','171006','171007','171008','171009','172001','174001','174002','174003','176001','176002','176003','177001','177002','179001','179002','179003','179004','179005','179006','179007','179008','179009','179010','179011','179012','179013','179014','179015','179016','179017','179018','179019','179020','179021','179022','179023','179024','179025','179026','179027','179028','179029','179030','179031','179032','179033','179034','179035','179036','179037','179038','179039','179040','179041','179042','179043','179044','179045','179046','179047','180001','180010','180012','180013','180014','180015','180016','180017','180018','180019','180020','180021','180022','180023','180024','180025','180026','180027','180028','180030','180031','180032','180033','180034','180035','180036','180037','180038','180039','180041','180042','180043','180044','180045','180046','180047','180048','180049','180050','180051','180052','180053','180054','180055','180056','180057','180058','180059','180060','180061','180062','180063','180064','180065','180066','180067','180068','180069','180070','180071','182001','184001','184002','184005','184006','184007','184008','184009','184010','184011','185001','185003','187001','188001','188002','188003','188004','188005','188006','188007','188008','188009','188010','188011','191001','191002','192002','194001','194002','194003','194004','194005','194006','194007','195001','195002','195003','195004','195005','195006','195007','196001','196002','197001','197002','197003','197004','197005','197006','198001','198003','198004','198005','198006','198007','198008','198009','198010','198011','198012','198013','198014','198015','198016','198017','201001','201002','201005','202001','203001','203002','203003','203017','203018','203019','204001','204002','204003','205001','208001','208002','208003','208004','208005','209001','209002','209003','210001','210002','210003','210004','210005','210006','210007','210008','210009','210010','210011','210012','210013','211017','212001','212002','212003','212004','212005','212006','212007','212008','212009','212010','212011','212012','212013','218001','218003','218004','218006','218007','218008','218009','218011','218015','218016','218017','218018','218019','218020','218021','218022','218023','218024','218025','218026','218027','218028','218029','218030','218031','218032','218033','218034','218035','218036','221001','221002','221003','221004','221005','221006','221007','221008','221009','221010','221011','221012','221013','223001','223002','223003','224001','224002','224003','224006','224007','224008','225001','225002','225003','225004','225005','225006','225007','225008','225009','225010','225011','225012','225013','226001','226002','226003','226004','226005','226006','226007','226008','226009','227001','227002','227003','227004','227005','227006','227007','227008','227009','227010','227011','227012','227013','227014','227015','227016','227017','227018','227019','227020','227021','227022','227023','227024','227025','227026','227027','227028','227029','227030','227031','227032','227033','227034','227035','227036','227037','227038','227039','227040','227041','227042','227043','227044','227045','227046','227047','227048','227049','227050','227051','227052','227053','227054','227055','227056','227057','227058','227059','227060','227061','227062','227063','227064','227065','227066','227067','227068','227069','227070','227071','227072','227073','227074','227075','227076','227077','227078','227079','227080','227081','227082','227083','227084','227085','227086','227087','227088','227089','227090','227091','227092','227093','227094','227095','227096','227097','227098','227099','227100','227101','227102','227103','227104','227105','227106','227107','227108','227109','227110','227111','227112','227113','227114','227115','227116','227117','227118','227119','227120','227122','227123','227124','227125','227126','227127','227128','227129','227130','227131','227132','227133','227134','227135','227136','227137','227138','227139','227140','227141','227142','227143','227144','227145','227146','227147','227148','227149','227150','227151','227152','228001','229001','229002','229003','229004','229005','230001','230002','232001','233001','233002','233003','233004','233005','233006','233007','233008','234001','234002','234003','234004','234005','234006','234007','234008','234009','234010','234011','234012','234013','234014','234015','234016','234017','234018','234019','234020','234021','234022','234023','234024','234025','234026','234027','234028','234029','234030','235001','235002','235003','235004','235005','236001','236002','236003','237001','238002','238003','238004','238005','238006','238007','238008','333013','333014','333015','333016','333017','333018','333019','333020','333021','333022','333023','333024','333025','333030','333031','333032','333033','333034','333035','334001','334002','334003','334004','334005','334006','334007','336004','337001','337002','337003','337004','339001','339002','343001','344001','344002','344003','344004','344005','345001','345002','345003','347001','347002','348001','348002','348003','348004','348005','349001','349002','349003','350001','353001','353002','353003','353004','355001','355002','355003','355004','355005','355006','356001','358001','359001','359002','360001','360002','360003','360004','360005','366001','366002','366003','366004','369001','373001','373002','373003','373004','373005','373006','373007','373008','373009','373010','373011','373012','373013','373014','373015','373016','373017','373018','373019','373020','373021','374001','374002','374003','374004','374005','374006','374007','374008','374009','374010','374011','374012','374013','374014','374015','374016','376001','376002','376003','376004','376005','376006','376007','376008','376009','376010','376011','376012','376013','376016','376017','376018','376019','376020','376021','379003','382001','382002','383001','384001','384002','385001','385002','386001','386002','386003','386004','386005','386006','386007','386008','386009','386010','386011','386012','386013','386014','387001','389001','389002','389003','389004','392001','393001','393002','393003','393004','395001','396001','397001','397002','399001','399002','399003','400001','400002','401001','401002','401003','402001','402002','402003','402004','402005','403001','403002','403003','504001','504002','504004','504005','504006','504007','504008','504009','504010','504011','504012','504013','504014','504017','504018','504019','504021','504022','504023','504024','504025','506001','506002','508001','508002','511001','511002','511003','511004','511005','511006','511007','511008','511009','511010','511011','511012','511013','511014','511017','511018','511020','511021','511022','511024','511028','511029','513001','513002','513003','513004','514001','515001','515002','515003','515007','515008','515009','515010','515011','515012','515013','515014','515015','518001','518002','518003','520001','520002','521001','521002','521003','521004','521005','521006','521007','521008','521009','521010','521011','521012','521013','521014','521015','521016','523001','523002','523003','523004','523005','523006','523007','524001','700001','701001','701002','701003','702001','702002','702003','702004','702005','702006','702007','702008','703001','703002','703003','704001','704002','704003','704004','705001','706001','706002','707001','707002','707003','708001','709001','709002','710001','710002','711001','711002','712001','713001','713002','714001','714002','715001','716001','718001','718002','719001','719002','991001','991002','991003','991004','991005','991006','991007','991008','992001','995001','996001','996002','996003','998001','998002','998003','998004','998005','998006','998007','999001','999002','011017','011018','034001','034002','071010','208006','239001','519001','519003','126013','184012','053071','374017','374018','374019','374020','374021','404001','405002','405001','405003','405007','405006','405005','405004','240011','240010','240009','240008','240007','240006','240005','240004','240003','240002','240001','240012','240013','240014','240015','240016','240017','357001','235006','235007','712002','355008','355007','056023','999999','046015','019005','126014','241003','241002','241001','240018','240020','240019','242001','242002','242003','242004','242005','242006','089002','406001','406002','406003','406004','406005','406006','243001','243002','243003','243004','243005','243006','243007','243008','010030','010029','407001','407006','407005','407004','407003','407002','408001','366005','133032','016035','077010','996004','025064','011019','407007','407008','407009','409001','115123','504026','039007','039009','039008','039010','039011','039012','180072','240021','240023','408002','405008','235008','525001','525002','525003','525004','410001','410002','410003','410004','410005','410006','410007','410008','410009','410010','410011','410012','410013','410014','410015','410016','344006','240031','240030','240029','240028','240027','240026','240025','240024','240034','240033','240032','410017','410018','411001','411002','411003','411004','411005','411006','411007','411008','203020','203021','203022','412001','412002','412003','412004','069025','244001','244002','244009','244008','244007','244006','244005','244004','244003','244015','244014','244013','244012','244011','244010','244016','244017','240042','240041','240040','240039','240038','240037','240036','240035','405009','405010','240043','504034','504033','504032','504031','504030','504029','504028','504027','504042','504041','504040','504039','504038','504037','504036','504035','800001','410019','410020','410021','244018','244019','244020','399004','413001','504043','198018','198019','344007','082045','010031','010032','010033','010034','010035','504044','515016','801002','801003','801004','801005','802001','801001','414001','414002','414003','141029','141030','803001','803002','803003','803004','803005','803006','803007','803008','803009','803010','803011','803012','803013','803014','803015','803016','803017','410022','410023','803018','803019','803020','415002','415001','244021','011020','011023','011022','011021','025065','165037','165038','165039','416001','416002','416003','417001','418001','504045','803022','803021','240022','419001','420001','804010','804009','804008','804007','804006','804005','804004','804003','804002','804001','804020','804019','804018','804017','804016','804015','804014','804013','804012','804011','804024','804021','804023','804022','511019','511016','511015','511032','511031','511030','511027','511026','511025','511033','511023','133034','133033','169011','344008','344009','244022','244026','244025','244030','244023','244024','244027','244028','244029','244031','082046','082047','082048','126015','126016','416004','416005','421001','421002','016037','016036','115124','115125','115126','240049','240048','240047','240046','240045','240044','244032','244033','422001','422002','422003','422004','422005','184013','239002','805001','805002','805003','805004','805005','056024','423001','344010','235009','212014','056025','056026','802002','244034','244035','244036','244037','244038','244039','515017','504046','203015','245002','245001','071023','056027','056028','056029','056030','056031','056032','424001','056034','056033','805006','805007','805008','805009','805010','422008','422007','422006','422010','422009','422011','209004','150022','150023','100002','056035','023036','185004','185005','246001','247001','247002','425001','416006','165042','165041','165040','165043','010040','010039','010038','010037','010036','422012','422013','422014','422015','426000','248001','248002','248003','248004','248005','249001','249002','249003','249004','249005','249006','250007','250001','250002','250003','250004','250005','250006','250008','250009','250010','250011','250012','250013','251001','251002','422016','422017','422018','806001','806002','116013','235010','235011','091026','091027','091028','091029','091019','091020','091021','091022','091023','091024','091025','252001','243009','249007','249008','249009','011024','011025','427001','428002','428001','169012','429001','429002','429003') DEFAULT '001001' NOT NULL, + KEY field (field) +); +INSERT INTO t1 VALUES ('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001001'),('001010'),('001010'),('001010'),('001010'),('001010'),('001018'),('001018'),('001018'),('001018'),('001018'),('001018'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001020'),('001021'),('001021'),('001021'),('001021'),('001021'),('001021'),('001027'),('001027'),('001028'),('001030'),('001030'),('001030'),('001030'),('001031'),('001031'),('001031'),('001031'),('001031'),('001100'),('001100'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002003'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002004'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002005'),('002007'),('002007'),('002007'),('002007'),('002007'),('002007'),('002007'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002008'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002009'),('002012'),('002012'),('002012'),('002012'),('002012'),('002012'),('002012'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002013'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('002014'),('003002'),('003002'),('003002'),('003002'),('003002'),('003002'),('003003'),('003003'),('003003'),('003003'),('003003'),('003003'),('003004'),('003004'),('003004'),('003004'),('003004'),('003004'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003005'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003006'),('003007'),('003007'),('003007'),('003007'),('003007'),('003008'),('003008'),('003008'),('003008'),('003008'),('003008'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003009'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003010'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003011'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003012'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003013'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003014'),('003015'),('003015'),('003015'),('003015'),('003015'),('003015'),('003016'),('003016'),('003016'),('003016'),('003016'),('003016'),('003017'),('003017'),('003017'),('003017'),('003017'),('003018'),('003018'),('003018'),('003018'),('003018'),('003019'),('003019'),('004003'),('004005'),('004005'),('004005'),('004005'),('004005'),('004005'),('004006'),('004008'),('004010'),('004012'),('004012'),('004014'),('004014'),('004014'),('004014'),('004014'),('004016'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004017'),('004020'),('004020'),('004020'),('004020'),('004020'),('004020'),('004021'),('004021'),('004021'),('004021'),('004021'),('004021'),('004021'),('004022'),('004023'),('004023'),('004023'),('004023'),('004023'),('004023'),('004023'),('004025'),('004026'),('004026'),('004026'),('004026'),('004026'),('006004'),('006006'),('006010'),('006010'),('006010'),('006010'),('006010'),('006010'),('006010'),('006011'),('006011'),('006011'),('006011'),('006011'),('006011'),('006012'),('006012'),('006012'),('006012'),('006012'),('006012'),('006014'),('006014'),('006014'),('007001'),('007001'),('007002'),('007003'),('007005'),('007007'),('007008'),('007009'),('007011'),('007012'),('007013'),('007015'),('007016'),('007017'),('007018'),('007019'),('007019'),('007020'),('007021'),('007021'),('007022'),('007023'),('007023'),('007025'),('007025'),('007025'),('007027'),('007029'),('007031'),('007031'),('007032'),('007034'),('007034'),('007036'),('007036'),('007036'),('007037'),('007037'),('007038'),('007040'),('007040'),('007040'),('007043'),('009001'),('009001'),('009001'),('009001'),('009001'),('009001'),('009001'),('009002'),('009002'),('009002'),('009002'),('009002'),('009004'),('009004'),('009004'),('009004'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009005'),('009006'),('009006'),('009006'),('009006'),('009007'),('009007'),('009007'),('009007'),('009007'),('009007'),('009008'),('009010'),('009010'),('009010'),('009010'),('009010'),('009010'),('009011'),('009011'),('009011'),('009011'),('009011'),('009012'),('009013'),('009013'),('009013'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010002'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010003'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010004'),('010005'),('010005'),('010005'),('010005'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010006'),('010007'),('010007'),('010007'),('010007'),('010007'),('010007'),('010008'),('010008'),('010008'),('010008'),('010008'),('010008'),('010008'),('010009'),('010009'),('010009'),('010009'),('010009'),('010009'),('010010'),('010010'),('010010'),('010010'),('010010'),('010010'),('010010'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010011'),('010012'),('010012'),('010012'),('010012'),('010012'),('010012'),('010012'),('010013'),('010013'),('010013'),('010013'),('010013'),('010013'),('010015'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010016'),('010017'),('010017'),('010017'),('010017'),('010017'),('010017'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010018'),('010019'),('010019'),('010019'),('010019'),('010019'),('010019'),('010020'),('010020'),('010020'),('010021'),('010021'),('010021'),('010021'),('010021'),('010021'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010022'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010023'),('010026'),('010027'),('010028'),('010028'),('011001'),('011001'),('011001'),('011001'),('011001'),('011001'),('011001'),('011002'),('011002'),('011002'),('011002'),('011002'),('011002'),('011002'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011003'),('011004'),('011004'),('011004'),('011004'),('011004'),('011004'),('011004'),('011006'),('011006'),('011006'),('011006'),('011006'),('011006'),('011006'),('011012'),('011012'),('011012'),('011013'),('011013'),('011013'),('011013'),('011013'),('011013'),('011014'),('011014'),('011014'),('011014'),('011015'),('011015'),('011015'),('011015'),('011015'),('011016'),('011016'),('011016'),('011016'),('011016'),('012017'),('012017'),('012027'),('012027'),('012032'),('012034'),('012036'),('012036'),('012037'),('012037'),('012038'),('012039'),('014001'),('014001'),('016016'),('016016'),('016016'),('016019'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016020'),('016021'),('016021'),('016021'),('016021'),('016021'),('016021'),('016021'),('016022'),('016022'),('016022'),('016023'),('016023'),('016023'),('016024'),('016024'),('016024'),('016024'),('016024'),('016024'),('016024'),('016026'),('016026'),('016026'),('016026'),('016026'),('016026'),('016028'),('016028'),('016028'),('016028'),('016028'),('016028'),('016028'),('016029'),('016029'),('016030'),('016031'),('016032'),('016032'),('016032'),('016032'),('016032'),('016032'),('016032'),('016033'),('016033'),('016033'),('016033'),('016033'),('016034'),('016034'),('016034'),('016034'),('016034'),('017002'),('017002'),('017002'),('017002'),('017002'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('018001'),('019002'),('019002'),('019002'),('019002'),('019002'),('019002'),('019004'),('019004'),('019004'),('019004'),('019004'),('019004'),('020001'),('020001'),('020001'),('020001'),('020004'),('020006'),('020006'),('020006'),('020006'),('020006'),('020006'),('020008'),('020009'),('020009'),('020009'),('020009'),('020009'),('022001'),('022001'),('022001'),('022001'),('022002'),('022002'),('022002'),('022002'),('022003'),('022003'),('022003'),('022003'),('023001'),('023002'),('023002'),('023002'),('023002'),('023002'),('023002'),('023003'),('023003'),('023003'),('023003'),('023004'),('023004'),('023005'),('023005'),('023006'),('023006'),('023006'),('023006'),('023006'),('023006'),('023007'),('023007'),('023010'),('023010'),('023011'),('023011'),('023017'),('023019'),('023019'),('023019'),('023020'),('023020'),('023025'),('023025'),('023025'),('023026'),('023026'),('023026'),('023027'),('023027'),('023027'),('023028'),('023028'),('023029'),('023029'),('023030'),('023030'),('023032'),('023033'),('023033'),('023033'),('023033'),('023033'),('023033'),('023034'),('023035'),('023035'),('025001'),('025001'),('025001'),('025001'),('025001'),('025001'),('025001'),('025003'),('025003'),('025004'),('025004'),('025005'),('025005'),('025007'),('025007'),('025008'),('025008'),('025009'),('025010'),('025010'),('025010'),('025011'),('025011'),('025012'),('025012'),('025013'),('025013'),('025013'),('025014'),('025015'),('025016'),('025018'),('025018'),('025019'),('025019'),('025020'),('025020'),('025021'),('025022'),('025022'),('025023'),('025023'),('025024'),('025025'),('025025'),('025026'),('025026'),('025027'),('025027'),('025027'),('025028'),('025030'),('025031'),('025033'),('025034'),('025035'),('025037'),('025041'),('025042'),('025043'),('025046'),('025048'),('025048'),('025048'),('025049'),('025049'),('025049'),('025050'),('025050'),('025050'),('025051'),('025051'),('025052'),('025052'),('025052'),('025053'),('025053'),('025054'),('025054'),('025054'),('025054'),('025055'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025056'),('025057'),('025057'),('025058'),('025058'),('025060'),('025060'),('025061'),('025062'),('025063'),('027001'),('027002'),('027011'),('036001'),('036001'),('036001'),('036001'),('036001'),('037003'),('037006'),('037007'),('037008'),('037008'),('038009'),('039001'),('039001'),('039001'),('039001'),('039001'),('039001'),('039002'),('039002'),('039002'),('039002'),('039002'),('039003'),('039003'),('039003'),('039003'),('039003'),('039003'),('039004'),('039004'),('039004'),('039004'),('039004'),('039005'),('039005'),('039005'),('039005'),('039005'),('039006'),('039006'),('039006'),('039006'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046001'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046002'),('046003'),('046003'),('046003'),('046003'),('046003'),('046003'),('046003'),('046005'),('046005'),('046005'),('046005'),('046005'),('046005'),('046005'),('046007'),('046007'),('046007'),('046007'),('046007'),('046007'),('046008'),('046008'),('046008'),('046008'),('046008'),('046009'),('046009'),('046009'),('046010'),('046012'),('046012'),('046012'),('046013'),('046014'),('046014'),('046014'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047001'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('047002'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('048001'),('051003'),('051003'),('051003'),('051003'),('051003'),('051004'),('051004'),('051004'),('051004'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052001'),('052002'),('052002'),('052005'),('052005'),('052005'),('052005'),('052005'),('052005'),('053016'),('053019'),('053019'),('053023'),('053023'),('053023'),('053023'),('053024'),('053024'),('053024'),('053026'),('053026'),('053026'),('053026'),('053028'),('053028'),('053029'),('053029'),('053029'),('053029'),('053033'),('053033'),('053033'),('053045'),('053046'),('053051'),('053051'),('053051'),('053054'),('053054'),('053054'),('053054'),('053057'),('053069'),('053069'),('053097'),('053107'),('053125'),('053125'),('053127'),('054001'),('054001'),('054001'),('054001'),('054001'),('054001'),('054001'),('054002'),('054002'),('054002'),('054002'),('054002'),('054002'),('054003'),('054003'),('054003'),('054003'),('054003'),('054003'),('054003'),('054004'),('054004'),('054004'),('054004'),('054004'),('054004'),('054004'),('054006'),('054006'),('054006'),('054007'),('054007'),('054007'),('054007'),('054007'),('054009'),('054009'),('054009'),('054009'),('054010'),('054010'),('054010'),('054010'),('054010'),('054010'),('054010'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056001'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056002'),('056003'),('056003'),('056003'),('056003'),('056003'),('056003'),('056004'),('056004'),('056004'),('056004'),('056004'),('056004'),('056004'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056005'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056006'),('056009'),('056009'),('056009'),('056011'),('056016'),('056016'),('056016'),('056016'),('056016'),('056016'),('056016'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056017'),('056018'),('056018'),('056018'),('056018'),('056018'),('056018'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056019'),('056020'),('056020'),('056020'),('056020'),('056022'),('056022'),('056022'),('056022'),('056022'),('057003'),('057003'),('057004'),('058002'),('058002'),('058002'),('058002'),('058003'),('058003'),('058003'),('058003'),('058004'),('058004'),('058004'),('058005'),('058005'),('058005'),('060001'),('060001'),('060001'),('060001'),('060001'),('060004'),('060004'),('060004'),('060004'),('060004'),('060004'),('060005'),('060005'),('060005'),('060005'),('060005'),('060005'),('060007'),('060007'),('060007'),('060007'),('060007'),('060007'),('060007'),('061004'),('061004'),('061004'),('061004'),('061004'),('061004'),('061006'),('061006'),('061006'),('061006'),('061006'),('061006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069006'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069007'),('069010'),('069010'),('069010'),('069010'),('069010'),('069010'),('069011'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069012'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069013'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069014'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069015'),('069016'),('069016'),('069016'),('069016'),('069016'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069018'),('069020'),('069020'),('069020'),('069020'),('069021'),('069023'),('071002'),('071002'),('071002'),('071002'),('071002'),('071003'),('071003'),('071003'),('071003'),('071003'),('071004'),('071004'),('071004'),('071004'),('071004'),('071005'),('071005'),('071005'),('071005'),('071005'),('071005'),('071006'),('071006'),('071006'),('071006'),('071008'),('071008'),('071008'),('071008'),('071008'),('071008'),('071011'),('071011'),('071011'),('071011'),('071011'),('071020'),('071020'),('071020'),('071020'),('071020'),('071021'),('071022'),('071022'),('071022'),('072001'),('072001'),('074001'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074002'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074003'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074004'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074005'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074006'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074007'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074008'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074009'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074010'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074011'),('074012'),('074012'),('074012'),('074012'),('074012'),('074012'),('074012'),('075001'),('075001'),('075001'),('075007'),('075007'),('075007'),('075007'),('076101'),('076101'),('076101'),('076101'),('076102'),('076102'),('076102'),('076103'),('076103'),('076103'),('076103'),('076103'),('077001'),('077001'),('077001'),('077002'),('077002'),('077002'),('077002'),('077002'),('077002'),('077002'),('077003'),('077003'),('077003'),('077003'),('077003'),('077003'),('077003'),('077004'),('077004'),('077004'),('077004'),('077004'),('077004'),('077006'),('077006'),('077008'),('077008'),('077008'),('077008'),('077008'),('077008'),('077008'),('077009'),('077009'),('077009'),('077009'),('077009'),('077009'),('077009'),('078005'),('078005'),('078005'),('079002'),('079002'),('079002'),('079002'),('079002'),('079002'),('079002'),('079003'),('079003'),('079004'),('079004'),('079005'),('079005'),('079005'),('079005'),('079005'),('079005'),('079006'),('079006'),('079006'),('079006'),('079007'),('079007'),('079007'),('079007'),('079007'),('081001'),('081001'),('081001'),('081001'),('081001'),('082011'),('082011'),('082011'),('082011'),('082011'),('082013'),('082013'),('082013'),('082013'),('082013'),('082013'),('082014'),('082014'),('082014'),('082014'),('082014'),('082014'),('082014'),('082015'),('082015'),('082015'),('082015'),('082015'),('082016'),('082016'),('082016'),('082016'),('082016'),('082016'),('082017'),('082017'),('082017'),('082017'),('082017'),('082017'),('082017'),('082021'),('082021'),('082022'),('082022'),('082022'),('082022'),('082022'),('082023'),('082023'),('082023'),('082023'),('082023'),('082024'),('082024'),('082024'),('082024'),('082024'),('082025'),('082025'),('082025'),('082025'),('082025'),('082026'),('082026'),('082026'),('082026'),('082026'),('082027'),('082027'),('082027'),('082027'),('082027'),('082028'),('082028'),('082028'),('082028'),('082029'),('082029'),('082029'),('082029'),('082029'),('082030'),('082030'),('082030'),('082030'),('082031'),('082031'),('082031'),('082031'),('082031'),('082032'),('082032'),('082032'),('082033'),('082033'),('082034'),('082034'),('082034'),('082034'),('082034'),('082034'),('082034'),('082035'),('082035'),('082035'),('082036'),('082036'),('082036'),('082036'),('082037'),('082037'),('082037'),('082038'),('082038'),('082038'),('082038'),('082039'),('082039'),('082039'),('082039'),('082040'),('082040'),('082040'),('082040'),('082040'),('082041'),('082041'),('082041'),('082041'),('082042'),('082042'),('082043'),('082043'),('082043'),('082043'),('082043'),('082044'),('082044'),('082044'),('082044'),('084001'),('084002'),('084002'),('084002'),('084002'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084003'),('084004'),('084004'),('084004'),('084004'),('084004'),('084005'),('084005'),('084005'),('084005'),('084005'),('084007'),('084007'),('084007'),('084007'),('084007'),('084007'),('084008'),('084008'),('084008'),('084008'),('084008'),('084008'),('084009'),('084009'),('084009'),('084009'),('084009'),('084009'),('084011'),('084013'),('084013'),('084013'),('084013'),('084013'),('084014'),('084014'),('084014'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084016'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084017'),('084027'),('084027'),('084027'),('084027'),('084027'),('084027'),('084032'),('084032'),('084033'),('084033'),('084033'),('084035'),('084035'),('084035'),('084036'),('084036'),('084036'),('084036'),('084036'),('084036'),('084037'),('084037'),('084038'),('084038'),('084038'),('084038'),('084038'),('084038'),('084039'),('084039'),('084039'),('084039'),('084040'),('084040'),('084040'),('084040'),('084040'),('084041'),('084041'),('084041'),('084041'),('084042'),('084042'),('084043'),('084043'),('084043'),('084043'),('084044'),('084044'),('084044'),('084044'),('084044'),('084045'),('084046'),('084046'),('084046'),('084047'),('084048'),('084048'),('084049'),('084049'),('084050'),('084051'),('084051'),('085001'),('085001'),('085001'),('085001'),('085001'),('085001'),('085002'),('085002'),('085002'),('085002'),('085003'),('085003'),('085003'),('085003'),('085003'),('085003'),('085003'),('085004'),('085004'),('085004'),('085004'),('085004'),('085004'),('085004'),('085005'),('085005'),('085005'),('085005'),('085005'),('085005'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085006'),('085007'),('085007'),('085007'),('085007'),('085007'),('085007'),('085007'),('085009'),('085009'),('085009'),('085009'),('085009'),('085009'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085011'),('085012'),('085012'),('085012'),('085012'),('085012'),('085012'),('085012'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085014'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085015'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085016'),('085017'),('085017'),('085017'),('085017'),('085017'),('085018'),('085018'),('085018'),('085018'),('085018'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085019'),('085020'),('085020'),('085020'),('085020'),('085020'),('085020'),('085022'),('085022'),('085022'),('085022'),('085022'),('085022'),('085023'),('085023'),('085023'),('085023'),('085023'),('085028'),('085028'),('085028'),('085028'),('085028'),('085028'),('085028'),('085029'),('085029'),('085029'),('085029'),('085029'),('085029'),('085029'),('085030'),('085030'),('085030'),('085030'),('085030'),('085030'),('085030'),('085031'),('085031'),('085031'),('085031'),('085031'),('085031'),('085031'),('085033'),('085034'),('085034'),('085034'),('085034'),('085034'),('085034'),('085034'),('085035'),('085035'),('085035'),('085035'),('085035'),('085035'),('085036'),('085036'),('085036'),('085036'),('085036'),('085036'),('085037'),('085037'),('085037'),('085037'),('085037'),('085037'),('085038'),('085038'),('085038'),('085038'),('085038'),('085038'),('085038'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085040'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085041'),('085042'),('085042'),('085042'),('085042'),('085042'),('085042'),('085042'),('085043'),('085043'),('085043'),('085043'),('085043'),('085043'),('085044'),('085044'),('085044'),('085044'),('085044'),('085044'),('085044'),('085045'),('085045'),('085045'),('085045'),('085045'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085046'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085047'),('085048'),('085048'),('085048'),('085048'),('085048'),('085048'),('085048'),('085063'),('085063'),('085063'),('085063'),('085063'),('085064'),('085064'),('085064'),('085064'),('085064'),('085065'),('085065'),('085068'),('085068'),('085068'),('085068'),('085068'),('085068'),('085071'),('085071'),('085071'),('085071'),('085071'),('085071'),('085073'),('085073'),('085082'),('085082'),('085082'),('085082'),('085082'),('085086'),('085086'),('085086'),('085088'),('085088'),('085088'),('085088'),('085088'),('085088'),('085088'),('085089'),('085089'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085090'),('085091'),('085091'),('085091'),('085091'),('085091'),('085092'),('085092'),('085092'),('085093'),('085093'),('085095'),('085095'),('085095'),('085095'),('085095'),('085096'),('085096'),('085096'),('085096'),('085096'),('085096'),('085097'),('085097'),('085097'),('085097'),('085097'),('085098'),('085098'),('085098'),('085098'),('085098'),('085098'),('085098'),('085099'),('085099'),('085099'),('085099'),('085099'),('085099'),('085099'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085100'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085101'),('085102'),('085102'),('085103'),('085103'),('085103'),('085104'),('085104'),('085104'),('085104'),('085104'),('085105'),('085105'),('085106'),('085106'),('085106'),('085106'),('085106'),('085106'),('085108'),('085108'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085109'),('085110'),('085110'),('085110'),('085110'),('085110'),('085111'),('085111'),('085111'),('085112'),('085112'),('085112'),('085112'),('085113'),('085113'),('085113'),('085113'),('085113'),('085115'),('085120'),('085121'),('085121'),('085121'),('085121'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085122'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085123'),('085125'),('085125'),('085125'),('085125'),('085125'),('085126'),('085126'),('085126'),('085126'),('085126'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085127'),('085128'),('085128'),('085128'),('085128'),('085128'),('085129'),('085129'),('085129'),('085129'),('085129'),('085130'),('085130'),('085130'),('085130'),('085130'),('085132'),('085132'),('085132'),('085132'),('085132'),('085132'),('085133'),('085133'),('085133'),('085133'),('085133'),('085134'),('085134'),('085134'),('085135'),('085135'),('085135'),('085136'),('085136'),('085136'),('085136'),('085137'),('085137'),('085137'),('085137'),('085137'),('085137'),('085137'),('086002'),('086002'),('086002'),('086002'),('086003'),('086003'),('086003'),('086003'),('086005'),('088001'),('088001'),('088001'),('088001'),('088001'),('088003'),('088003'),('088003'),('088003'),('088003'),('088003'),('088005'),('088005'),('088005'),('088005'),('088005'),('088006'),('088006'),('088006'),('088006'),('088006'),('088007'),('088007'),('088007'),('088008'),('088008'),('088008'),('088008'),('088009'),('088009'),('088009'),('088009'),('088009'),('089001'),('089001'),('089001'),('089001'),('089001'),('089001'),('089001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090001'),('090002'),('090002'),('090002'),('090002'),('090002'),('090002'),('090003'),('090003'),('090003'),('090003'),('090003'),('090003'),('090003'),('090004'),('090004'),('090004'),('090004'),('090004'),('090004'),('090004'),('090006'),('090006'),('090006'),('090006'),('090006'),('090006'),('090006'),('090008'),('090008'),('090008'),('090008'),('090008'),('090009'),('090009'),('090009'),('090009'),('090009'),('090010'),('090010'),('090013'),('090013'),('090013'),('090016'),('090016'),('090017'),('090018'),('090022'),('090027'),('091001'),('091001'),('091001'),('091001'),('091001'),('091001'),('091002'),('091002'),('091002'),('091002'),('091002'),('091002'),('091009'),('091009'),('091009'),('091009'),('091009'),('091011'),('091011'),('091011'),('091011'),('091011'),('091011'),('091011'),('091012'),('091012'),('091013'),('091013'),('091013'),('091013'),('091013'),('091013'),('091015'),('091015'),('091015'),('091015'),('091015'),('091015'),('091016'),('091016'),('091016'),('091016'),('091016'),('091017'),('091017'),('091018'),('091018'),('091018'),('091018'),('093003'),('093003'),('093003'),('093003'),('093003'),('093003'),('099001'),('099001'),('099001'),('099001'),('099001'),('099001'),('099001'),('100001'),('100001'),('100001'),('100001'),('106001'),('113005'),('113005'),('113005'),('113006'),('113006'),('113018'),('113019'),('113020'),('115001'),('115001'),('115001'),('115002'),('115002'),('115003'),('115004'),('115004'),('115004'),('115004'),('115005'),('115005'),('115005'),('115006'),('115006'),('115006'),('115007'),('115007'),('115007'),('115007'),('115007'),('115008'),('115008'),('115008'),('115009'),('115010'),('115010'),('115010'),('115010'),('115010'),('115011'),('115011'),('115011'),('115011'),('115012'),('115012'),('115013'),('115013'),('115013'),('115014'),('115014'),('115014'),('115014'),('115015'),('115015'),('115015'),('115016'),('115016'),('115016'),('115016'),('115017'),('115017'),('115017'),('115017'),('115017'),('115018'),('115018'),('115020'),('115020'),('115021'),('115021'),('115022'),('115022'),('115022'),('115023'),('115023'),('115023'),('115023'),('115023'),('115025'),('115025'),('115025'),('115026'),('115026'),('115027'),('115027'),('115027'),('115028'),('115028'),('115028'),('115028'),('115029'),('115029'),('115029'),('115030'),('115030'),('115030'),('115031'),('115031'),('115032'),('115032'),('115032'),('115033'),('115033'),('115033'),('115033'),('115034'),('115034'),('115034'),('115035'),('115035'),('115036'),('115036'),('115036'),('115036'),('115036'),('115039'),('115040'),('115040'),('115040'),('115041'),('115041'),('115041'),('115041'),('115041'),('115042'),('115042'),('115042'),('115042'),('115042'),('115043'),('115043'),('115043'),('115044'),('115044'),('115044'),('115044'),('115046'),('115046'),('115046'),('115047'),('115048'),('115050'),('115050'),('115050'),('115050'),('115050'),('115051'),('115051'),('115051'),('115052'),('115053'),('115053'),('115054'),('115054'),('115054'),('115055'),('115055'),('115055'),('115057'),('115059'),('115059'),('115059'),('115059'),('115060'),('115060'),('115060'),('115060'),('115060'),('115060'),('115061'),('115061'),('115061'),('115062'),('115062'),('115062'),('115062'),('115064'),('115064'),('115064'),('115065'),('115065'),('115065'),('115065'),('115066'),('115066'),('115066'),('115067'),('115067'),('115067'),('115068'),('115068'),('115068'),('115069'),('115069'),('115069'),('115069'),('115069'),('115070'),('115070'),('115070'),('115071'),('115071'),('115071'),('115072'),('115072'),('115072'),('115073'),('115073'),('115075'),('115075'),('115075'),('115076'),('115076'),('115076'),('115076'),('115076'),('115076'),('115081'),('115081'),('115081'),('115082'),('115082'),('115082'),('115085'),('115085'),('115085'),('115085'),('115085'),('115086'),('115086'),('115086'),('115087'),('115087'),('115088'),('115088'),('115088'),('115088'),('115088'),('115095'),('115095'),('115095'),('115096'),('115096'),('115097'),('115097'),('115098'),('115098'),('115099'),('115101'),('115102'),('115102'),('115102'),('115103'),('115103'),('115104'),('115104'),('115104'),('115104'),('115105'),('115105'),('115106'),('115106'),('115106'),('115106'),('115106'),('115108'),('115109'),('115111'),('115111'),('115111'),('115111'),('115112'),('115112'),('115112'),('115112'),('115112'),('115113'),('115113'),('115113'),('115114'),('115114'),('115114'),('115114'),('115114'),('115115'),('115115'),('115115'),('115115'),('115116'),('115117'),('115117'),('115117'),('115118'),('115118'),('115119'),('115119'),('115119'),('115119'),('115120'),('115121'),('115121'),('115122'),('115122'),('116001'),('116003'),('116003'),('116003'),('116003'),('116004'),('116004'),('116005'),('116005'),('116006'),('116006'),('116006'),('116007'),('116007'),('116008'),('116008'),('116009'),('116009'),('116009'),('116010'),('116010'),('116010'),('116010'),('116011'),('116011'),('116011'),('116011'),('116012'),('116012'),('123001'),('123001'),('123001'),('123001'),('123001'),('124065'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126001'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126002'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126003'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126004'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126005'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126006'),('126007'),('126007'),('126007'),('126007'),('126007'),('126007'),('126007'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126008'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126009'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126010'),('126011'),('126011'),('126011'),('126011'),('126011'),('126011'),('126011'),('126012'),('126012'),('126012'),('126012'),('130001'),('130001'),('130001'),('130001'),('132001'),('132001'),('132001'),('132001'),('132001'),('132002'),('132002'),('132002'),('132002'),('132002'),('132002'),('132002'),('133001'),('133001'),('133008'),('133009'),('133010'),('133011'),('133011'),('133011'),('133011'),('133011'),('133011'),('133012'),('133015'),('133015'),('133015'),('133015'),('133016'),('133018'),('133018'),('133018'),('133018'),('133018'),('133019'),('133021'),('133021'),('133022'),('133022'),('133023'),('133023'),('133024'),('133024'),('133024'),('133024'),('133024'),('133024'),('133025'),('133027'),('133027'),('133027'),('133027'),('133027'),('133028'),('133028'),('133028'),('133029'),('133029'),('133029'),('133029'),('133029'),('133029'),('133030'),('133030'),('133031'),('133031'),('133031'),('134001'),('134001'),('134001'),('135001'),('135001'),('135001'),('135001'),('135001'),('135002'),('135002'),('135002'),('135004'),('135010'),('135010'),('135010'),('135010'),('135010'),('135010'),('137010'),('137011'),('137012'),('137014'),('137015'),('137015'),('137016'),('137019'),('139001'),('140001'),('140001'),('140001'),('140001'),('140001'),('140001'),('141001'),('141001'),('141001'),('141001'),('141001'),('141002'),('141002'),('141002'),('141002'),('141002'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141003'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141006'),('141007'),('141007'),('141007'),('141007'),('141007'),('141009'),('141009'),('141009'),('141009'),('141009'),('141011'),('141011'),('141011'),('141011'),('141011'),('141011'),('141012'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141014'),('141015'),('141015'),('141015'),('141015'),('141015'),('141016'),('141016'),('141016'),('141016'),('141016'),('141016'),('141017'),('141017'),('141017'),('141017'),('141017'),('141017'),('141018'),('141018'),('141018'),('141018'),('141019'),('141019'),('141019'),('141019'),('141020'),('141020'),('141020'),('141020'),('141020'),('141020'),('141020'),('141021'),('141021'),('141021'),('141021'),('141021'),('141021'),('141022'),('141022'),('141022'),('141022'),('141022'),('141022'),('141023'),('141023'),('141023'),('141023'),('141023'),('141023'),('141023'),('141024'),('141025'),('141025'),('141025'),('141026'),('141026'),('141026'),('141026'),('141026'),('141026'),('141027'),('141027'),('141027'),('141027'),('141027'),('141028'),('141028'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145001'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145002'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145003'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145004'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145005'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145006'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145008'),('145009'),('145009'),('145009'),('145009'),('145009'),('145009'),('145009'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145011'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145012'),('145013'),('145013'),('145013'),('145013'),('145013'),('145013'),('145013'),('150009'),('150013'),('150014'),('150015'),('150015'),('150015'),('150016'),('150016'),('150017'),('150017'),('150017'),('150017'),('150020'),('152001'),('152001'),('152001'),('152002'),('152003'),('152003'),('152003'),('152003'),('152004'),('152005'),('152006'),('152006'),('152006'),('152006'),('152007'),('154001'),('154002'),('154002'),('155001'),('155001'),('155002'),('155003'),('155004'),('155004'),('155006'),('159001'),('159003'),('160001'),('160001'),('160001'),('160001'),('160002'),('160002'),('161001'),('162002'),('162002'),('162003'),('162003'),('162003'),('162003'),('162003'),('162007'),('162012'),('162012'),('162012'),('163001'),('163001'),('163001'),('163011'),('163015'),('163016'),('163016'),('165001'),('165001'),('165001'),('165001'),('165002'),('165002'),('165002'),('165002'),('165003'),('165003'),('165003'),('165004'),('165004'),('165004'),('165005'),('165005'),('165005'),('165006'),('165006'),('165006'),('165006'),('165007'),('165007'),('165007'),('165007'),('165008'),('165008'),('165008'),('165008'),('165009'),('165009'),('165009'),('165009'),('165010'),('165010'),('165010'),('165011'),('165011'),('165012'),('165012'),('165012'),('165013'),('165013'),('165013'),('165014'),('165014'),('165014'),('165015'),('165015'),('165015'),('165015'),('165016'),('165016'),('165016'),('165017'),('165017'),('165017'),('165017'),('165018'),('165018'),('165018'),('165018'),('165019'),('165019'),('165019'),('165019'),('165020'),('165020'),('165020'),('165020'),('165021'),('165021'),('165021'),('165021'),('165022'),('165022'),('165022'),('165023'),('165024'),('165024'),('165024'),('165025'),('165025'),('165025'),('165026'),('165026'),('165026'),('165028'),('165029'),('165030'),('165030'),('165030'),('165031'),('165031'),('165033'),('165033'),('165034'),('165034'),('165034'),('165035'),('165035'),('165035'),('165036'),('165036'),('165036'),('168003'),('168003'),('168004'),('168005'),('168014'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169001'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169002'),('169003'),('169003'),('169003'),('169003'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169007'),('169008'),('169008'),('169008'),('169008'),('169008'),('169008'),('169008'),('169009'),('169009'),('169009'),('169009'),('169010'),('171006'),('171006'),('171007'),('171007'),('171008'),('171008'),('171008'),('171009'),('171009'),('171009'),('172001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176001'),('176002'),('176002'),('176002'),('176002'),('176002'),('176003'),('176003'),('176003'),('176003'),('176003'),('176003'),('177001'),('177001'),('177001'),('177001'),('177001'),('177001'),('179007'),('179007'),('179012'),('179012'),('179012'),('179012'),('179012'),('179012'),('179013'),('179013'),('179013'),('179013'),('179013'),('179013'),('179042'),('179044'),('179045'),('180001'),('180013'),('180014'),('180014'),('180015'),('180017'),('180018'),('180020'),('180020'),('180021'),('180021'),('180027'),('180030'),('180033'),('180035'),('180036'),('180037'),('180038'),('180041'),('180042'),('180045'),('180045'),('180047'),('180048'),('180049'),('180050'),('180054'),('180060'),('180066'),('180067'),('180068'),('180070'),('182001'),('184001'),('184002'),('184005'),('184005'),('184005'),('184005'),('184006'),('184006'),('184006'),('184006'),('184008'),('184008'),('184008'),('184008'),('184009'),('184009'),('184009'),('184009'),('184010'),('184010'),('184010'),('184010'),('184011'),('184011'),('184011'),('184011'),('185001'),('185001'),('185001'),('185001'),('185001'),('185001'),('185001'),('185003'),('185003'),('185003'),('185003'),('185003'),('185003'),('185003'),('187001'),('191002'),('191002'),('192002'),('194003'),('197001'),('197001'),('197001'),('197001'),('197001'),('197001'),('197001'),('197002'),('197002'),('197002'),('197002'),('197002'),('197002'),('197002'),('197003'),('197003'),('197003'),('197003'),('197003'),('197003'),('197003'),('197004'),('197004'),('197004'),('197004'),('197004'),('197004'),('197004'),('197005'),('197005'),('197005'),('197005'),('197005'),('197005'),('197006'),('197006'),('197006'),('197006'),('197006'),('198001'),('198001'),('198001'),('198001'),('198001'),('198001'),('198003'),('198003'),('198003'),('198004'),('198004'),('198004'),('198004'),('198004'),('198004'),('198005'),('198005'),('198005'),('198005'),('198005'),('198005'),('198005'),('198006'),('198006'),('198006'),('198006'),('198006'),('198006'),('198007'),('198007'),('198007'),('198007'),('198007'),('198007'),('198007'),('198008'),('198008'),('198008'),('198008'),('198008'),('198008'),('198009'),('198009'),('198009'),('198009'),('198009'),('198009'),('198009'),('198010'),('198010'),('198010'),('198010'),('198010'),('198010'),('198011'),('198012'),('198012'),('198012'),('198012'),('198015'),('198015'),('198016'),('198016'),('198016'),('198016'),('198016'),('198016'),('198017'),('198017'),('198017'),('198017'),('198017'),('198017'),('201001'),('201001'),('201001'),('201001'),('201001'),('201002'),('202001'),('202001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203001'),('203002'),('203002'),('203002'),('203002'),('203003'),('203003'),('203003'),('203003'),('203003'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203017'),('203018'),('203018'),('203018'),('203018'),('203018'),('203019'),('203019'),('203019'),('203019'),('203019'),('204001'),('204002'),('205001'),('205001'),('205001'),('205001'),('205001'),('205001'),('205001'),('208001'),('208001'),('208002'),('208002'),('208002'),('208003'),('208003'),('208003'),('208004'),('208004'),('208004'),('208004'),('208004'),('208004'),('208004'),('208005'),('208005'),('208005'),('208005'),('208005'),('209001'),('209001'),('209001'),('209001'),('209001'),('209002'),('209002'),('209002'),('209002'),('209002'),('209003'),('209003'),('209003'),('209003'),('209003'),('210001'),('210001'),('210001'),('210001'),('210001'),('210004'),('210004'),('210004'),('210004'),('210004'),('210004'),('210009'),('210010'),('212001'),('212001'),('212002'),('212002'),('212002'),('212002'),('212003'),('212003'),('212003'),('212004'),('212004'),('212004'),('212005'),('212005'),('212005'),('212005'),('212005'),('212006'),('212006'),('212006'),('212007'),('212007'),('212008'),('212008'),('212008'),('212008'),('212009'),('212009'),('212009'),('212009'),('212010'),('212010'),('212010'),('212010'),('212011'),('212011'),('212012'),('212012'),('212013'),('212013'),('212013'),('218001'),('218004'),('218009'),('218011'),('218011'),('218015'),('218020'),('218021'),('218021'),('218022'),('218022'),('218022'),('218023'),('218024'),('218025'),('218026'),('218026'),('218027'),('218028'),('218029'),('218029'),('218029'),('218030'),('218031'),('221001'),('221001'),('221001'),('221001'),('221001'),('221001'),('221002'),('221002'),('221002'),('221002'),('221002'),('221002'),('221003'),('221003'),('221003'),('221003'),('221003'),('221003'),('221004'),('221004'),('221004'),('221004'),('221004'),('221004'),('221005'),('221005'),('221005'),('221005'),('221005'),('221006'),('221006'),('221006'),('221006'),('221006'),('221007'),('221007'),('221007'),('221007'),('221007'),('221007'),('221008'),('221008'),('221008'),('221008'),('221008'),('221008'),('221009'),('221009'),('221009'),('221009'),('221009'),('221009'),('221010'),('221010'),('221010'),('221010'),('221011'),('221011'),('221011'),('221011'),('221012'),('221012'),('221012'),('221012'),('221012'),('221012'),('221013'),('221013'),('221013'),('221013'),('221013'),('221013'),('223003'),('223003'),('224001'),('224001'),('224002'),('224002'),('224003'),('224007'),('224008'),('225001'),('225002'),('225002'),('225002'),('225003'),('225003'),('225003'),('225003'),('225004'),('225004'),('225004'),('225005'),('225005'),('225005'),('225005'),('225005'),('225005'),('225006'),('225006'),('225006'),('225007'),('225007'),('225007'),('225008'),('225008'),('225008'),('225008'),('225008'),('225009'),('225009'),('225009'),('225010'),('225010'),('225010'),('225011'),('225011'),('225011'),('225011'),('225011'),('225012'),('225012'),('225012'),('225012'),('225012'),('225012'),('225013'),('225013'),('226001'),('226002'),('226003'),('226003'),('226005'),('226005'),('226006'),('226007'),('226007'),('226007'),('226007'),('227011'),('227015'),('227015'),('227041'),('227045'),('227052'),('227056'),('227063'),('227064'),('227066'),('227067'),('227069'),('227071'),('227073'),('227085'),('227116'),('227119'),('227131'),('227133'),('227147'),('229005'),('229005'),('229005'),('233003'),('233004'),('235001'),('235001'),('235002'),('235003'),('235003'),('235003'),('235004'),('235005'),('235005'),('235005'),('235005'),('235005'),('235005'),('235005'),('236001'),('236001'),('236001'),('236001'),('236002'),('236003'),('236003'),('236003'),('236003'),('236003'),('236003'),('238002'),('238002'),('238002'),('238002'),('238002'),('238002'),('238003'),('238003'),('238003'),('238003'),('238003'),('238003'),('238004'),('238004'),('238004'),('238004'),('238004'),('238005'),('238005'),('238005'),('238007'),('238007'),('238007'),('238007'),('238007'),('238007'),('238007'),('238008'),('238008'),('238008'),('238008'),('238008'),('238008'),('238008'),('334005'),('334006'),('337001'),('337001'),('337001'),('337002'),('337002'),('337003'),('337003'),('337003'),('337004'),('343001'),('343001'),('344001'),('344002'),('344003'),('344004'),('344005'),('344005'),('345001'),('345001'),('348001'),('348004'),('348005'),('348005'),('349001'),('349001'),('349002'),('349002'),('349002'),('350001'),('353002'),('353002'),('353002'),('353003'),('355001'),('355002'),('355005'),('355006'),('355006'),('356001'),('358001'),('358001'),('358001'),('359001'),('359001'),('359002'),('359002'),('359002'),('359002'),('360001'),('360001'),('360002'),('360002'),('360003'),('360003'),('360004'),('360004'),('360005'),('360005'),('360005'),('366001'),('366002'),('366002'),('366003'),('366004'),('369001'),('369001'),('373001'),('373002'),('373002'),('373003'),('373003'),('373005'),('373007'),('373008'),('373009'),('373009'),('373010'),('373010'),('373010'),('373011'),('373011'),('373011'),('373011'),('373012'),('373012'),('373012'),('373013'),('373013'),('373014'),('373014'),('373015'),('373015'),('373015'),('373015'),('373017'),('373017'),('373017'),('373017'),('373018'),('373021'),('374002'),('374004'),('374006'),('374007'),('374008'),('374009'),('374010'),('374011'),('374012'),('374015'),('374016'),('382001'),('382002'),('382002'),('384001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386001'),('386002'),('386002'),('386002'),('386002'),('386002'),('386002'),('386002'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386003'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386004'),('386005'),('386005'),('386005'),('386005'),('386005'),('386005'),('386005'),('386006'),('386006'),('386006'),('386006'),('386006'),('386006'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386007'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386008'),('386009'),('386009'),('386009'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386010'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386011'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386012'),('386013'),('386013'),('386013'),('386013'),('386013'),('386013'),('386013'),('386014'),('386014'),('386014'),('386014'),('389001'),('389002'),('389002'),('389003'),('389003'),('389003'),('389003'),('389004'),('389004'),('389004'),('389004'),('392001'),('393001'),('393002'),('393002'),('393003'),('393004'),('395001'),('395001'),('397001'),('397001'),('397001'),('397002'),('399001'),('399001'),('399001'),('399001'),('399001'),('399001'),('399001'),('399002'),('399002'),('399002'),('399002'),('399002'),('399002'),('399002'),('399003'),('400001'),('400001'),('400001'),('400001'),('400002'),('403002'),('504001'),('504001'),('504002'),('504002'),('504002'),('504004'),('504004'),('504005'),('504006'),('504007'),('504007'),('504007'),('504008'),('504008'),('504009'),('504009'),('504009'),('504009'),('504009'),('504010'),('504011'),('504011'),('504012'),('504012'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504014'),('504017'),('504017'),('504021'),('504021'),('504021'),('504021'),('504021'),('504021'),('504021'),('504022'),('504023'),('504023'),('504024'),('504024'),('504025'),('504025'),('506001'),('506001'),('506001'),('506001'),('506001'),('506001'),('506002'),('506002'),('506002'),('506002'),('506002'),('511001'),('511001'),('511001'),('511001'),('511001'),('511001'),('511001'),('511002'),('511002'),('511002'),('511002'),('511002'),('511002'),('511002'),('511003'),('511003'),('511003'),('511003'),('511003'),('511003'),('511004'),('511004'),('511004'),('511004'),('511004'),('511004'),('511004'),('511005'),('511005'),('511005'),('511005'),('511005'),('511005'),('511005'),('511006'),('511006'),('511006'),('511006'),('511006'),('511006'),('511006'),('511007'),('511007'),('511007'),('511007'),('511007'),('511008'),('511008'),('511008'),('511008'),('511008'),('511008'),('511009'),('511009'),('511009'),('511009'),('511009'),('511009'),('511010'),('511010'),('511010'),('511010'),('511010'),('511010'),('511011'),('511011'),('511011'),('511011'),('511011'),('511011'),('511012'),('511012'),('511012'),('511012'),('511012'),('511012'),('511012'),('511013'),('511013'),('511013'),('511013'),('511013'),('511013'),('511013'),('511014'),('511014'),('511014'),('511014'),('511014'),('511017'),('511018'),('511020'),('511021'),('511022'),('511024'),('511028'),('511029'),('511029'),('511029'),('511029'),('511029'),('511029'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513001'),('513002'),('513002'),('513002'),('513002'),('513002'),('513002'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513003'),('513004'),('513004'),('513004'),('515001'),('515001'),('515001'),('515001'),('515001'),('515002'),('515002'),('515003'),('515003'),('515007'),('515007'),('515008'),('515011'),('515011'),('515011'),('515011'),('515011'),('515011'),('515012'),('515012'),('515012'),('515012'),('515013'),('515013'),('515013'),('515013'),('515013'),('515014'),('515014'),('515014'),('515014'),('515014'),('515015'),('515015'),('515015'),('515015'),('515015'),('518001'),('518002'),('521001'),('521002'),('521002'),('521002'),('521003'),('521003'),('521003'),('521003'),('521004'),('521004'),('521004'),('521004'),('521005'),('521005'),('521005'),('521005'),('521006'),('521006'),('521006'),('521009'),('521010'),('521010'),('521010'),('521010'),('521011'),('521011'),('521011'),('521011'),('521012'),('521013'),('521013'),('521015'),('521016'),('521016'),('523001'),('523001'),('523001'),('523001'),('523001'),('523001'),('523001'),('523002'),('523002'),('523002'),('523002'),('523002'),('523002'),('523003'),('523003'),('523003'),('523003'),('523003'),('523003'),('523003'),('523004'),('523004'),('523004'),('523004'),('523004'),('523004'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523005'),('523006'),('523006'),('523006'),('523006'),('523006'),('523006'),('523006'),('523007'),('523007'),('523007'),('523007'),('523007'),('523007'),('523007'),('524001'),('700001'),('701001'),('701002'),('701003'),('702001'),('702002'),('702004'),('702005'),('704001'),('704004'),('705001'),('706001'),('706002'),('707001'),('707002'),('707003'),('708001'),('710001'),('710002'),('711001'),('711002'),('712001'),('714001'),('714002'),('715001'),('719001'),('719002'),('991002'),('991002'),('991002'),('991003'),('991003'),('991003'),('991003'),('991003'),('991003'),('991003'),('991004'),('991004'),('991004'),('991005'),('991005'),('991005'),('991006'),('991007'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('995001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996001'),('996002'),('996002'),('996003'),('996003'),('996003'),('996003'),('996003'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998001'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998002'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998003'),('998004'),('998004'),('998005'),('998005'),('998006'),('998007'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999001'),('999002'),('999002'),('011017'),('011017'),('011017'),('011017'),('011017'),('011017'),('011017'),('011018'),('011018'),('011018'),('011018'),('034001'),('034001'),('034002'),('034002'),('071010'),('071010'),('071010'),('519001'),('126013'),('126013'),('126013'),('126013'),('126013'),('184012'),('184012'),('184012'),('404001'),('405002'),('405002'),('405001'),('405003'),('405006'),('240011'),('240011'),('240011'),('240011'),('240011'),('240011'),('240010'),('240010'),('240010'),('240009'),('240009'),('240009'),('240009'),('240008'),('240008'),('240008'),('240007'),('240007'),('240007'),('240007'),('240007'),('240007'),('240005'),('240005'),('240005'),('240005'),('240005'),('240004'),('240004'),('240004'),('240004'),('240004'),('240003'),('240003'),('240003'),('240003'),('240002'),('240002'),('240002'),('240002'),('240002'),('240002'),('240002'),('240001'),('240001'),('240001'),('240001'),('240001'),('240012'),('240012'),('240012'),('240012'),('240012'),('240013'),('240014'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240015'),('240016'),('240016'),('240016'),('240016'),('240016'),('240016'),('240017'),('240017'),('240017'),('357001'),('357001'),('235006'),('235006'),('235007'),('235007'),('235007'),('235007'),('235007'),('056023'),('056023'),('056023'),('056023'),('056023'),('046015'),('019005'),('019005'),('126014'),('126014'),('126014'),('126014'),('126014'),('126014'),('241003'),('241003'),('241003'),('241003'),('241003'),('241003'),('241002'),('241002'),('241002'),('241002'),('241002'),('241002'),('241001'),('241001'),('241001'),('241001'),('241001'),('240020'),('240020'),('240020'),('240020'),('240020'),('240020'),('240019'),('240019'),('240019'),('242001'),('242002'),('242004'),('242005'),('242006'),('089002'),('089002'),('089002'),('089002'),('089002'),('089002'),('406001'),('406002'),('406003'),('406004'),('406004'),('243001'),('243005'),('243006'),('243007'),('243008'),('408001'),('408001'),('408001'),('408001'),('408001'),('366005'),('366005'),('016035'),('016035'),('016035'),('016035'),('077010'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('996004'),('025064'),('025064'),('025064'),('025064'),('011019'),('011019'),('011019'),('011019'),('011019'),('115123'),('115123'),('504026'),('039007'),('039009'),('039008'),('039008'),('039010'),('039010'),('039011'),('039012'),('180072'),('240021'),('240021'),('240021'),('240021'),('240021'),('240021'),('240021'),('240023'),('240023'),('240023'),('240023'),('405008'),('405008'),('525002'),('410002'),('410002'),('410004'),('410005'),('410005'),('410006'),('410007'),('410007'),('410008'),('410009'),('410010'),('410011'),('410011'),('410012'),('410012'),('410013'),('410013'),('410014'),('410014'),('410016'),('410016'),('344006'),('240031'),('240031'),('240031'),('240031'),('240030'),('240030'),('240030'),('240030'),('240029'),('240029'),('240029'),('240029'),('240028'),('240028'),('240028'),('240028'),('240027'),('240027'),('240026'),('240026'),('240026'),('240025'),('240025'),('240025'),('240025'),('240024'),('240024'),('240034'),('240034'),('240034'),('240033'),('240033'),('240033'),('240032'),('240032'),('240032'),('240032'),('411001'),('411002'),('203020'),('069025'),('069025'),('069025'),('069025'),('069025'),('069025'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244001'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244002'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244009'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244008'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244007'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244006'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244004'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244003'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244014'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244013'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244012'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244011'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244016'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('244017'),('240040'),('240037'),('405009'),('405009'),('405009'),('405010'),('405010'),('240043'),('240043'),('504028'),('504040'),('800001'),('410019'),('410019'),('410020'),('410020'),('410020'),('410021'),('410021'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244018'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244019'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('244020'),('413001'),('344007'),('082045'),('082045'),('082045'),('082045'),('082045'),('010031'),('010031'),('010031'),('010031'),('010032'),('010032'),('010032'),('010032'),('010033'),('010033'),('010033'),('010033'),('010033'),('010034'),('010034'),('010034'),('010034'),('010035'),('010035'),('010035'),('010035'),('504044'),('515016'),('515016'),('515016'),('515016'),('801002'),('801003'),('801004'),('801005'),('802001'),('801001'),('414001'),('141029'),('803001'),('803002'),('803004'),('803005'),('803006'),('803007'),('803008'),('803009'),('803013'),('803014'),('803015'),('803016'),('803017'),('410022'),('410023'),('410023'),('803019'),('415002'),('415001'),('244021'),('244021'),('244021'),('244021'),('244021'),('244021'),('244021'),('011020'),('011020'),('011020'),('011020'),('011023'),('011023'),('011023'),('011023'),('011022'),('011022'),('011022'),('011022'),('011022'),('011022'),('011021'),('011021'),('011021'),('011021'),('025065'),('025065'),('025065'),('025065'),('165037'),('165037'),('165038'),('165038'),('165038'),('165039'),('416001'),('416001'),('416001'),('416001'),('416001'),('416002'),('416003'),('417001'),('418001'),('504045'),('504045'),('504045'),('803022'),('240022'),('240022'),('240022'),('240022'),('420001'),('420001'),('420001'),('420001'),('804010'),('804005'),('804002'),('804018'),('804013'),('511019'),('511016'),('511015'),('511032'),('511031'),('511030'),('511027'),('511026'),('511025'),('511033'),('511023'),('133034'),('133034'),('133034'),('133033'),('169011'),('169011'),('169011'),('169011'),('169011'),('344008'),('244022'),('244022'),('244022'),('244022'),('244022'),('244022'),('244022'),('244026'),('244026'),('244026'),('244026'),('244026'),('244026'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244025'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244030'),('244023'),('244023'),('244023'),('244023'),('244023'),('244023'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244024'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244027'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244028'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244029'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('244031'),('082046'),('082046'),('082046'),('082046'),('082047'),('082047'),('082048'),('082048'),('126015'),('126015'),('126016'),('126016'),('126016'),('126016'),('126016'),('416005'),('421001'),('421001'),('421002'),('016037'),('016037'),('016037'),('016037'),('016036'),('016036'),('016036'),('016036'),('115124'),('115124'),('115126'),('240049'),('240049'),('240048'),('240048'),('240047'),('240047'),('240046'),('240046'),('240045'),('240044'),('244032'),('244033'),('422002'),('422004'),('422004'),('422004'),('422005'),('422005'),('184013'),('184013'),('184013'),('805001'),('805002'),('805003'),('805004'),('805005'),('056024'),('056024'),('056024'),('423001'),('344010'),('235009'),('235009'),('235009'),('235009'),('212014'),('212014'),('056025'),('056025'),('056025'),('056026'),('056026'),('056026'),('056026'),('056026'),('056026'),('244034'),('244034'),('244034'),('244034'),('244034'),('244034'),('244035'),('244035'),('244035'),('244035'),('244035'),('244035'),('244035'),('244036'),('244036'),('244036'),('244036'),('244036'),('244036'),('244036'),('244037'),('244037'),('244037'),('244037'),('244037'),('244037'),('244037'),('244038'),('244038'),('244038'),('244038'),('244038'),('244038'),('244038'),('244039'),('244039'),('244039'),('244039'),('244039'),('244039'),('244039'),('203015'),('245002'),('245002'),('245001'),('245001'),('056029'),('056030'),('056032'),('424001'),('056034'),('056034'),('056034'),('056034'),('056033'),('056033'),('056033'),('805006'),('805007'),('805008'),('805009'),('805010'),('422008'),('422008'),('422007'),('422007'),('422006'),('422006'),('422010'),('422009'),('422009'),('422011'),('422011'),('209004'),('209004'),('150022'),('100002'),('056035'),('056035'),('056035'),('023036'),('023036'),('185005'),('246001'),('246001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247001'),('247002'),('247002'),('425001'),('416006'),('416006'),('165042'),('165041'),('165040'),('165043'),('010040'),('010039'),('010038'),('010036'),('248001'),('248002'),('248003'),('248004'),('248005'),('249001'),('249003'),('249004'),('249005'),('250007'),('250001'),('250002'),('250003'),('250004'),('250005'),('250006'),('250008'),('250009'),('250010'),('250011'),('250012'),('250013'),('251001'),('251002'),('806001'),('806002'),('235010'),('243009'),('249007'),('249008'),('249009'),('011024'),('011025'),('429001'),('429001'),('429002'),('429002'),('429003'),('429003'); +select field from t1 group by field; +drop table t1; + +# +# Test of enum with space +# + +create table t1 (a enum (' ','a','b') not null); +show create table t1; +drop table t1; +create table t1 (a enum (' ','a','b ') not null default 'b '); +show create table t1; +drop table t1; + +# +# Tests of wrong enum values (bug #2023) +# + +create table t1 (a enum ('0','1')); +insert into t1 set a='foobar'; +select * from t1; +update t1 set a = replace(a,'x','y'); +select * from t1; +drop table t1; + +# +# Bug #2077 +# + +set names latin1; +create table t1 (a enum(0xE4, '1', '2') not null default 0xE4); +show columns from t1; +show create table t1; +drop table t1; + + +# +# Bug #5628 German characters in field-defs will be '?' +# with some table definitions +# +set names latin1; +CREATE TABLE t1 ( + a INT default 1, + b ENUM('value','öäü_value','ÊÃÕ') character set latin1 NOT NULL +); +show create table t1; +show columns from t1; +drop table t1; + +# +# Bugs #6154, 6206: ENUMs are not case sensitive even if declared BINARY +# +CREATE TABLE t1 (c enum('a', 'A') BINARY); +INSERT INTO t1 VALUES ('a'),('A'); +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c enum('ae','oe','ue','ss') collate latin1_german2_ci); +INSERT INTO t1 VALUES ('ä'),('ö'),('ü'),('ß'); +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #6379: ENUM values are incorrectly converted +# +# Check latin1 -> utf8 conversion +# +CREATE TABLE t1 ( + a ENUM('ä','ö','ü') character set utf8 default 'ü' +); +show create table t1; +insert into t1 values ('ä'), ('ö'), ('ü'); +select a from t1 order by a; +drop table t1; + +# +# Now check utf8 -> latin1 conversion +# This test emulates loading a script generated with mysqldump +# +set names utf8; +CREATE TABLE t1 ( + a ENUM('ä','ö','ü') character set latin1 default 'ü' +); +insert into t1 values ('ä'),('ö'),('ü'); +# Now check what has been loaded +set names latin1; +show create table t1; +select a from t1 order by a; +drop table t1; + +# +# Test bug where enum fields where extended for each ALTER TABLE +# + +create table t1 (a enum ('Y','N') CHARACTER SET utf8 COLLATE utf8_bin); +insert into t1 values ('Y'); +alter table t1 add b set ('Y','N') CHARACTER SET utf8 COLLATE utf8_bin; +alter table t1 add c enum ('Y','N') CHARACTER SET utf8 COLLATE utf8_bin; +--enable_metadata +select * from t1; +--disable_metadata +drop table t1; + +# +# Bug #6840 Default value is not checked in ALTER column SET DEFAULT 'x' +# +create table t1 (a enum('x','y') default 'x'); +--error 1067 +alter table t1 alter a set default 'z'; +drop table t1; + +create table t1 (a set('x','y') default 'x'); +--error 1067 +alter table t1 alter a set default 'z'; +drop table t1; + + +# +# Bug#20922 mysql removes a name of first column in a table +# +create table t1 (f1 int); +alter table t1 add f2 enum(0xFFFF); +show create table t1; +drop table t1; + +--echo End of 4.1 tests + +# +# Bug#24660 "enum" field type definition problem +# +create table t1(russian enum('E','F','EÿF','FÿE') NOT NULL DEFAULT'E'); +show create table t1; +drop table t1; + +create table t1(denormal enum('E','F','E,F','F,E') NOT NULL DEFAULT'E'); +show create table t1; +drop table t1; + +create table t1(russian_deviant enum('E','F','EÿF','F,E') NOT NULL DEFAULT'E'); +show create table t1; +drop table t1; + +# ER_WRONG_FIELD_TERMINATORS +--error 1005 +create table t1(exhausting_charset enum('ABCDEFGHIJKLMNOPQRSTUVWXYZ',' + + !"','#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~','xx\','yy\€','zz‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ')); + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.1 tests diff --git a/mysql-test/suite/pbxt/t/type_float.test b/mysql-test/suite/pbxt/t/type_float.test new file mode 100644 index 00000000000..2b3184eb830 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_float.test @@ -0,0 +1,203 @@ +# Description +# ----------- +# Numeric floating point. + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +SELECT 10,10.0,10.,.1e+2,100.0e-1; +SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000; +SELECT 1e1,1.e1,1.0e1,1e+1,1.e+1,1.0e+1,1e-1,1.e-1,1.0e-1; +SELECT 0.001e+1,0.001e-1, -0.001e+01,-0.001e-01; +SELECT 123.23E+02,-123.23E-02,"123.23E+02"+0.0,"-123.23E-02"+0.0; +SELECT 2147483647E+02,21474836.47E+06; + +create table t1 (f1 float(24),f2 float(52)); +# We mask out Privileges column because it differs for embedded server +--replace_column 8 # +show full columns from t1; +insert into t1 values(10,10),(1e+5,1e+5),(1234567890,1234567890),(1e+10,1e+10),(1e+15,1e+15),(1e+20,1e+20),(1e+50,1e+50),(1e+150,1e+150); +insert into t1 values(-10,-10),(1e-5,1e-5),(1e-10,1e-10),(1e-15,1e-15),(1e-20,1e-20),(1e-50,1e-50),(1e-150,1e-150); +select * from t1; +drop table t1; + +create table t1 (datum double); +insert into t1 values (0.5),(1.0),(1.5),(2.0),(2.5); +select * from t1; +select * from t1 where datum < 1.5; +select * from t1 where datum > 1.5; +select * from t1 where datum = 1.5; +drop table t1; + +create table t1 (a decimal(7,3) not null, key (a)); +insert into t1 values ("0"),("-0.00"),("-0.01"),("-0.002"),("1"); +select a from t1 order by a; +select min(a) from t1; +drop table t1; + +# +# BUG#3612, BUG#4393, BUG#4356, BUG#4394 +# + +create table t1 (c1 double, c2 varchar(20)); +insert t1 values (121,"16"); +select c1 + c1 * (c2 / 100) as col from t1; +create table t2 select c1 + c1 * (c2 / 100) as col1, round(c1, 5) as col2, round(c1, 35) as col3, sqrt(c1*1e-15) col4 from t1; +# Floats are a bit different in PS +--disable_ps_protocol +select * from t2; +--enable_ps_protocol +show create table t2; +drop table t1,t2; + +# Bug #1022: When a table contains a 'float' field, +# and one of the functions MAX, MIN, or AVG is used on that field, +# the system crashes. + +create table t1 (a float); +insert into t1 values (1); +select max(a),min(a),avg(a) from t1; +drop table t1; + +# +# FLOAT/DOUBLE/DECIMAL handling +# + +create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(7,6)); +# We mask out Privileges column because it differs for embedded server +--replace_column 8 # +show full columns from t1; +drop table t1; + +create table t1 (a decimal(7,3) not null, key (a)); +insert into t1 values ("0"),("-0.00"),("-0.01"),("-0.002"),("1"); +select a from t1 order by a; +select min(a) from t1; +drop table t1; + +--error 1425 +create table t1 (a float(200,100), b double(200,100)); + +# +# float in a char(1) field +# +create table t1 (c20 char); +insert into t1 values (5000.0); +insert into t1 values (0.5e4); +drop table t1; + +# Errors + +--error 1063 +create table t1 (f float(54)); # Should give an error +--disable_warnings +drop table if exists t1; +--enable_warnings + +# Don't allow 'double unsigned' to be set to a negative value (Bug #7700) +create table t1 (d1 double, d2 double unsigned); +insert into t1 set d1 = -1.0; +update t1 set d2 = d1; +select * from t1; +drop table t1; + +# Ensure that maximum values as the result of number of decimals +# being specified in table schema are enforced (Bug #7361) +create table t1 (f float(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +select * from t1; +drop table if exists t1; +create table t1 (f double(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +select * from t1; +drop table if exists t1; + +# Check conversion of floats to character field (Bug #7774) +create table t1 (c char(20)); +insert into t1 values (5e-28); +# Expected result is "5e-28", but windows returns "5e-028" +--replace_result 5e-028 5e-28 +select * from t1; +drop table t1; +create table t1 (c char(6)); +insert into t1 values (2e5),(2e6),(2e-4),(2e-5); +# Expected result is "2e+06", but windows returns "2e+006" +# Expected result is "2e-05", but windows returns "2e-005" +--replace_result 2e+006 2e+06 2e-005 2e-05 +select * from t1; +drop table t1; + +# +# Test of comparison of integer with float-in-range (Bug #7840) +# This is needed because some ODBC applications (like Foxpro) uses +# floats for everything. +# + +CREATE TABLE t1 ( + reckey int unsigned NOT NULL, + recdesc varchar(50) NOT NULL, + PRIMARY KEY (reckey) +) ENGINE=PBXT DEFAULT CHARSET=latin1; # PBXT tested instead of MyISAM + +INSERT INTO t1 VALUES (108, 'Has 108 as key'); +INSERT INTO t1 VALUES (109, 'Has 109 as key'); +select * from t1 where reckey=108; +select * from t1 where reckey=1.08E2; +select * from t1 where reckey=109; +select * from t1 where reckey=1.09E2; +drop table t1; + +# +# Bug #13372 (decimal union) +# +create table t1 (d double(10,1)); +create table t2 (d double(10,9)); +insert into t1 values ("100000000.0"); +insert into t2 values ("1.23456780"); +create table t3 select * from t2 union select * from t1; +select * from t3; +show create table t3; +drop table t1, t2, t3; + + +# +# Bug #9855 (inconsistent column type for create select +# +create table t1 select 105213674794682365.00 + 0.0 x; +show warnings; +desc t1; +drop table t1; + +create table t1 select 0.0 x; +desc t1; +create table t2 select 105213674794682365.00 y; +desc t2; +create table t3 select x+y a from t1,t2; +show warnings; +desc t3; +drop table t1,t2,t3; + +# +# Bug #22129: A small double precision number becomes zero +# +# check if underflows are detected correctly +select 1e-308, 1.00000001e-300, 100000000e-300; + +# check if overflows are detected correctly +select 10e307; + +--echo End of 4.1 tests + +# +# bug #12694 (float(m,d) specifications) +# + +--error 1427 +create table t1 (s1 float(0,2)); +--error 1427 +create table t1 (s1 float(1,2)); + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/type_nchar.test b/mysql-test/suite/pbxt/t/type_nchar.test new file mode 100644 index 00000000000..731f0d1c041 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_nchar.test @@ -0,0 +1,39 @@ +# +# Test nchar/nvarchar +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (c nchar(10)); +show create table t1; +drop table t1; + +create table t1 (c national char(10)); +show create table t1; +drop table t1; + +create table t1 (c national varchar(10)); +show create table t1; +drop table t1; + +create table t1 (c nvarchar(10)); +show create table t1; +drop table t1; + +create table t1 (c nchar varchar(10)); +show create table t1; +drop table t1; + +create table t1 (c national character varying(10)); +show create table t1; +drop table t1; + +create table t1 (c nchar varying(10)); +show create table t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/type_newdecimal.test b/mysql-test/suite/pbxt/t/type_newdecimal.test new file mode 100644 index 00000000000..fa2417675dd --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_newdecimal.test @@ -0,0 +1,1148 @@ +--disable_warnings +drop table if exists t1; +--enable_warnings +# +# constant IN function test +# +select 1.1 IN (1.0, 1.2); +select 1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5); +select 1.1 IN (1.0, 1.2, NULL, 1.4, 0.5); +select 0.5 IN (1.0, 1.2, NULL, 1.4, 0.5); +select 1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5); +select 1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5); + +# +# case function test +# +select case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 1 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 1.0 when 0.1 then "a" when 1 then "b" else "c" END; +select case 1.001 when 0.1 then "a" when 1 then "b" else "c" END; + +# +# non constant IN test +# +create table t1 (a decimal(6,3)); +insert into t1 values (1.0), (NULL), (0.1); +select * from t1; +select 0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) from t1; +drop table t1; + +# +# if function test +# +create table t1 select if(1, 1.1, 1.2), if(0, 1.1, 1.2), if(0.1, 1.1, 1.2), if(0, 1, 1.1), if(0, NULL, 1.2), if(1, 0.22e1, 1.1), if(1E0, 1.1, 1.2); +select * from t1; +show create table t1; +drop table t1; + +# +# NULLIF +# +create table t1 select nullif(1.1, 1.1), nullif(1.1, 1.2), nullif(1.1, 0.11e1), nullif(1.0, 1), nullif(1, 1.0), nullif(1, 1.1); +select * from t1; +show create table t1; +drop table t1; + +# +# saving in decimal field with overflow +# + +create table t1 (a decimal(4,2)); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +select a from t1; +drop table t1; +create table t1 (a decimal(4,2) unsigned); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +select a from t1; +drop table t1; + + +# +# saving in field with overflow from decimal +# +create table t1 (a bigint); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (-18446744073709551615.0); +select * from t1; +drop table t1; +create table t1 (a bigint unsigned); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (9999999999999999999999999.000); +insert into t1 values (-1.0); +select * from t1; +drop table t1; +create table t1 (a tinyint); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +select * from t1; +drop table t1; + +# +# test that functions create decimal fields +# +create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(-1.1); +show create table t1; +drop table t1; + +# +# Trydy's tests +# +set session sql_mode='traditional'; +select 1e10/0e0; +create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10)); +insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890); +select * from wl1612; +insert into wl1612 values(2,01234567890123456789.0123456789,01234567890123456789.0123456789); +select * from wl1612 where col1=2; +insert into wl1612 values(3,1234567890123456789012345678.0123456789,1234567890123456789012345678.0123456789); +select * from wl1612 where col1=3; + +select col1/0 from wl1612; +select col2/0 from wl1612; +select col3/0 from wl1612; + +insert into wl1612 values(5,5000.0005,5000.0005); +insert into wl1612 values(6,5000.0005,5000.0005); +select sum(col2),sum(col3) from wl1612; +#select avg(col2),avg(col3) from wl1612; + +insert into wl1612 values(7,500000.000005,500000.000005); +insert into wl1612 values(8,500000.000005,500000.000005); +select sum(col2),sum(col3) from wl1612 where col1>4; +#select avg(col2),avg(col3) from wl1612 where col1>4; + +#insert into wl1612 (col1,col2) values(9,123456789012345678901234567890); +#insert into wl1612 (col1,col3) values(9,123456789012345678901234567890); + +insert into wl1612 (col1, col2) values(9,1.01234567891); +insert into wl1612 (col1, col2) values(10,1.01234567894); +insert into wl1612 (col1, col2) values(11,1.01234567895); +insert into wl1612 (col1, col2) values(12,1.01234567896); +select col1,col2 from wl1612 where col1>8; + +insert into wl1612 (col1, col3) values(13,1.01234567891); +insert into wl1612 (col1, col3) values(14,1.01234567894); +insert into wl1612 (col1, col3) values(15,1.01234567895); +insert into wl1612 (col1, col3) values(16,1.01234567896); +select col1,col3 from wl1612 where col1>12; + +select col1 from wl1612 where col1>4 and col2=1.01234567891; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col2=1.0123456789; +#-- should return col1 values 9 & 10 +# +select col1 from wl1612 where col1>4 and col2<>1.0123456789; +#-- should return col1 values 5,6,7,8,11,12 +# +select col1 from wl1612 where col1>4 and col2<1.0123456789; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col2<=1.0123456789; +#-- should return col1 values 9 & 10 +# +select col1 from wl1612 where col1>4 and col2>1.0123456789; +#-- should return col1 values 5,6,7,8,11,12 +# +select col1 from wl1612 where col1>4 and col2>=1.0123456789; +#-- should return col1 values 5,6,7,8,910,11,12 +# +#select col1, col2 from wl1612 where col1=11 or col1=12; +select col1 from wl1612 where col1>4 and col2=1.012345679; +#-- should return col1 values 11,12 +# +select col1 from wl1612 where col1>4 and col2<>1.012345679; +#-- should return col1 values 5,6,7,8,9,10 +# +select col1 from wl1612 where col1>4 and col3=1.01234567891; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col3=1.0123456789; +#-- should return col1 values 13,14 +# +select col1 from wl1612 where col1>4 and col3<>1.0123456789; +#-- should return col1 values 5,6,7,8,15,16 +# +select col1 from wl1612 where col1>4 and col3<1.0123456789; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col3<=1.0123456789; +#-- should return col1 values 13,14 +# +select col1 from wl1612 where col1>4 and col3>1.0123456789; +#-- should return col1 values 5,6,7,8,15,16 +# +select col1 from wl1612 where col1>4 and col3>=1.0123456789; +#-- should return col1 values 5,6,7,8,13,14,15,16 +# +select col1 from wl1612 where col1>4 and col3=1.012345679; +#-- should return col1 values 15,16 +# +select col1 from wl1612 where col1>4 and col3<>1.012345679; +#-- should return col1 values 5,6,7,8,13,14 +# +drop table wl1612; +# +select 1/3; +# +select 0.8=0.7+0.1; +#-- should return 1 (true) +# +select 0.7+0.1; +# +create table wl1612_1 (col1 int); +insert into wl1612_1 values(10); +# +select * from wl1612_1 where 0.8=0.7+0.1; +#--should return 1 row (col1=10) +# +select 0.07+0.07 from wl1612_1; +# +select 0.07-0.07 from wl1612_1; +# +select 0.07*0.07 from wl1612_1; +# +select 0.07/0.07 from wl1612_1; +# +drop table wl1612_1; +# +create table wl1612_2 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_2 values(1,1); +insert into wl1612_2 values(+1,+1); +insert into wl1612_2 values(+01,+01); +insert into wl1612_2 values(+001,+001); +# +select col1,count(*) from wl1612_2 group by col1; +# +select col2,count(*) from wl1612_2 group by col2; +# +drop table wl1612_2; +# +create table wl1612_3 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_3 values('1','1'); +insert into wl1612_3 values('+1','+1'); +# +insert into wl1612_3 values('+01','+01'); +insert into wl1612_3 values('+001','+001'); +# +select col1,count(*) from wl1612_3 group by col1; +# +select col2,count(*) from wl1612_3 group by col2; +# +drop table wl1612_3; +# +select mod(234,10) ; +#-- should return 4 +# +select mod(234.567,10.555); +#-- should return 2.357 +# +select mod(-234.567,10.555); +#-- should return -2.357 +# +select mod(234.567,-10.555); +#-- should return 2.357 +# +select round(15.1); +#-- should return 15 +# +select round(15.4); +#-- should return 15 +# +select round(15.5); +#-- should return 16 +# +select round(15.6); +#-- should return 16 +# +select round(15.9); +#-- should return 16 +# +select round(-15.1); +#-- should return -15 +# +select round(-15.4); +#-- should return -15 +# +select round(-15.5); +#-- should return -16 +# +select round(-15.6); +#-- should return -16 +# +select round(-15.9); +#-- should return -16 +# +select round(15.1,1); +#-- should return 15.1 +# +select round(15.4,1); +#-- should return 15.4 +# +select round(15.5,1); +#-- should return 15.5 +# +select round(15.6,1); +#-- should return 15.6 +# +select round(15.9,1); +#-- should return 15.9 +# +select round(-15.1,1); +#-- should return -15.1 +# +select round(-15.4,1); +#-- should return -15.4 +# +select round(-15.5,1); +#-- should return -15.5 +# +select round(-15.6,1); +#-- should return -15.6 +# +select round(-15.9,1); +#-- should return -15.9 +# +select round(15.1,0); +#-- should return 15 +# +select round(15.4,0); +#-- should return 15 +# +select round(15.5,0); +#-- should return 16 +# +select round(15.6,0); +#-- should return 16 +# +select round(15.9,0); +#-- should return 16 +# +select round(-15.1,0); +#-- should return -15 +# +select round(-15.4,0); +#-- should return -15 +# +select round(-15.5,0); +#-- should return -16 +# +select round(-15.6,0); +#-- should return -16 +# +select round(-15.9,0); +#-- should return -16 +# +select round(15.1,-1); +#-- should return 20 +# +select round(15.4,-1); +#-- should return 20 +# +select round(15.5,-1); +#-- should return 20 +# +select round(15.6,-1); +#-- should return 20 +# +select round(15.9,-1); +#-- should return 20 +# +select round(-15.1,-1); +#-- should return -20 +# +select round(-15.4,-1); +#-- should return -20 +# +select round(-15.5,-1); +#-- should return -20 +# +select round(-15.6,-1); +#-- should return -20 +# +select round(-15.91,-1); +#-- should return -20 +# +select truncate(5678.123451,0); +#-- should return 5678 +# +select truncate(5678.123451,1); +#-- should return 5678.1 +# +select truncate(5678.123451,2); +#-- should return 5678.12 +# +select truncate(5678.123451,3); +#-- should return 5678.123 +# +select truncate(5678.123451,4); +#-- should return 5678.1234 +# +select truncate(5678.123451,5); +#-- should return 5678.12345 +# +select truncate(5678.123451,6); +#-- should return 5678.123451 +# +select truncate(5678.123451,-1); +#-- should return 5670 +# +select truncate(5678.123451,-2); +#-- should return 5600 +# +select truncate(5678.123451,-3); +#-- should return 5000 +# +select truncate(5678.123451,-4); +#-- should return 0 +# +select truncate(-5678.123451,0); +#-- should return -5678 +# +select truncate(-5678.123451,1); +#-- should return -5678.1 +# +select truncate(-5678.123451,2); +#-- should return -5678.12 +# +select truncate(-5678.123451,3); +#-- should return -5678.123 +# +select truncate(-5678.123451,4); +#-- should return -5678.1234 +# +select truncate(-5678.123451,5); +#-- should return -5678.12345 +# +select truncate(-5678.123451,6); +#-- should return -5678.123451 +# +select truncate(-5678.123451,-1); +#-- should return -5670 +# +select truncate(-5678.123451,-2); +#-- should return -5600 +# +select truncate(-5678.123451,-3); +#-- should return -5000 +# +select truncate(-5678.123451,-4); +#-- should return 0 +# +#drop table if exists wl1612_4; +create table wl1612_4 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); +# +insert into wl1612_4 values(1,0.0123456789012345678912345,0.0123456789012345678912345); +# +select col2/9999999999 from wl1612_4 where col1=1; +# +select col3/9999999999 from wl1612_4 where col1=1; +# +select 9999999999/col2 from wl1612_4 where col1=1; +# +select 9999999999/col3 from wl1612_4 where col1=1; +# +select col2*9999999999 from wl1612_4 where col1=1; +# +select col3*9999999999 from wl1612_4 where col1=1; +# +insert into wl1612_4 values(2,55555.0123456789012345678912345,55555.0123456789012345678912345); +# +select col2/9999999999 from wl1612_4 where col1=2; +# +select col3/9999999999 from wl1612_4 where col1=2; +# +select 9999999999/col2 from wl1612_4 where col1=2; +# +select 9999999999/col3 from wl1612_4 where col1=2; +# +select col2*9999999999 from wl1612_4 where col1=2; +# +select col3*9999999999 from wl1612_4 where col1=2; +# +drop table wl1612_4; +# +# +# +# +#-- Additional tests for WL#1612 Precision math +# +#-- Comparisons should show that a number is +#-- exactly equal to its value as displayed. +# +set sql_mode=''; +# +select 23.4 + (-41.7), 23.4 - (41.7) = -18.3; +# +select -18.3=-18.3; +# +select 18.3=18.3; +# +select -18.3=18.3; +# +select 0.8 = 0.7 + 0.1; + +# +#-- It should be possible to define a column +#-- with up to 38 digits precision either before +#-- or after the decimal point. Any number which +#-- is inserted, if it's within the range, should +#-- be exactly the same as the number that gets +#-- selected. +# +drop table if exists t1; +# +create table t1 (col1 decimal(38)); +# +insert into t1 values (12345678901234567890123456789012345678); +# +select * from t1; +#-- should return: +#+----------------------------------------+ +#| col1 | +#+----------------------------------------+ +#| 12345678901234567890123456789012345678 | +#+----------------------------------------+ +# +#drop table t1; +# +#create table t1 (col1 decimal(38,38)); +# +#insert into t1 values (.12345678901234567890123456789012345678); +# +#select * from t1; +#-- should return: +#+------------------------------------------+ +#| col1 | +#+------------------------------------------+ +#| 0.12345678901234567890123456789012345678 | +#+------------------------------------------+ +# +drop table t1; +# +create table t1 (col1 decimal(31,30)); +# +insert into t1 values (0.00000000001); +# +select * from t1; +#-- should return: +#+---------------+ +#|col1 | +#+---------------+ +#| 0.00000000001 | +#+---------------+ +# +drop table t1; +# +#-- The usual arithmetic operators / * + - should work. +# +#select 77777777777777777777777777777777777777 / 7777777777777777777777777777777777777 = 10; +#-- should return 0 (false). +# +select 7777777777777777777777777777777777777 * 10; +#-- should return 77777777777777777777777777777777777770 +# +select .7777777777777777777777777777777777777 * + 1000000000000000000; +#-- should return 777777777777777777.7777777777777777777 +# +select .7777777777777777777777777777777777777 - 0.1; +#-- should return .6777777777777777777777777777777777777 +# +select .343434343434343434 + .343434343434343434; +#-- should return .686868686868686868 +# +#-- 5. All arithmetic functions mentioned in the +#MySQL Reference Manual should work. +# +select abs(9999999999999999999999); +#-- should return 9999999999999999999999 +# +select abs(-9999999999999999999999); +#-- should return 9999999999999999999999 +# +select ceiling(999999999999999999); +select ceiling(99999999999999999999); +#-- should return 99999999999999999999 +# +select ceiling(9.9999999999999999999); +#-- should return 10 +# +select ceiling(-9.9999999999999999999); +#-- should return 9 +# +select floor(999999999999999999); +select floor(9999999999999999999999); +#-- should return 9999999999999999999999 +# +select floor(9.999999999999999999999); +#-- should return 9 +# +select floor(-9.999999999999999999999); +#-- should return -10 +# +select floor(-999999999999999999999.999); +select ceiling(999999999999999999999.999); +# +# +select 99999999999999999999999999999999999999 mod 3; +#-- should return 0 +# +select round(99999999999999999.999); +#-- should return 100000000000000000 +# +select round(-99999999999999999.999); +#-- should return -100000000000000000 +# +select round(99999999999999999.999,3); +#-- should return 100000000000000000.000 +# +select round(-99999999999999999.999,3); +#-- should return -100000000000000000.000 +# +select truncate(99999999999999999999999999999999999999,31); +#-- should return 99999999999999999999999999999999999999.000 +# +select truncate(99.999999999999999999999999999999999999,31); +#-- should return 99.9999999999999999999999999999999 +# +select truncate(99999999999999999999999999999999999999,-31); +# should return 90000000000000000000000000000000 +# +#-- 6. Set functions (AVG, SUM, COUNT) should work. +# +#drop table if exists t1; +# +#delimiter // +# +#create procedure p1 () begin +# declare v1 int default 1; declare v2 decimal(0,38) default 0; +# create table t1 (col1 decimal(0,38)); +# while v1 <= 10000 do +# insert into t1 values (-v2); +# set v2 = v2 + 0.00000000000000000000000000000000000001; +# set v1 = v1 + 1; +# end while; +# select avg(col1),sum(col1),count(col1) from t1; end;// +# +#call p1()// +#-- should return +# -- avg(col1)=0.00000000000000000000000000000000000001 added 10,000 times, then divided by 10,000 +# -- sum(col1)=0.00000000000000000000000000000000000001 added 10,000 times +# +# -- count(col1)=10000 +# +#delimiter ;// +# +#drop procedure p1; +#drop table t1; +# +#-- When I say DECIMAL(x) I should be able to store x digits. +#-- If I can't, there should be an error at CREATE time. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(254)); +#-- should return SQLSTATE 22003 numeric value out of range +# +#-- When I say DECIMAL(x,y) there should be no silent change of precision or +#-- scale. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(0,38)); +# +#show create table t1; +#-- should return: +#+-------+--------------------------------+ +#| Table | Create Table | +#+-------+--------------------------------+ +#| t9 | CREATE TABLE `t1` ( | +#|`s1` decimal(0,38) default NULL | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+--------------------------------+ +# +#drop table t1; +# +#-- From WL#1612 "The future" point 2.: +#-- The standard requires that we treat numbers like "0.5" as +#-- DECIMAL or NUMERIC, not as floating-point. +# +#drop table if exists t1; +# +# +create table t1 as select 0.5; +# +show create table t1; +#-- should return: +#+-------+-----------------------------------+ +#| Table | Create Table | +#+-------+-----------------------------------+ +#| t7 | CREATE TABLE `t1` ( | +#| `0.5` decimal(3,1) NOT NULL default '0.0' | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+-----------------------------------+ +# +drop table t1; +# +#-- From WL#1612, "The future", point 3.: We have to start rounding correctly. +# +select round(1.5),round(2.5); +#-- should return: +#+------------+------------+ +#| round(1.5) | round(2.5) | +#+------------+------------+ +#| 2 | 3 | +#+------------+------------+ +# +#-- From WL#1612, "The future", point 4.: "select 0.07 * 0.07;" should return 0.0049, not 0.00. +#-- If operand#1 has scale X and operand#2 has scale Y, then result should have scale (X+Y). +# +select 0.07 * 0.07; +#-- should return 0.0049 +# +#-- From WL#1612, "The future", point 5.: Division by zero is an error. +# +set sql_mode='traditional'; +# +select 1E-500 = 0; +#-- should return 1 (true). +# +select 1 / 1E-500; +# +#-- should return SQLSTATE 22012 division by zero. +# +select 1 / 0; +#-- should return SQLSTATE 22012 division by zero. +# +#+-------+ +#| 1 / 0 | +#+-------+ +#| NULL | +#+-------+ +#1 row in set, 1 warning (0.00 sec) +# +#-- From WL#1612 "The future" point 6.: Overflow is an error. +# +#set sql_mode=''; +# +#select 1E300 * 1E300; +#-- should return SQLSTATE 22003 numeric value out of range +# +#select 18446744073709551615 + 1; +#-- should return SQLSTATE 22003 numeric value out of range +# +#-- 14. From WL#1612 "The future" point 7.: +#-- If s1 is INTEGER and s2 is DECIMAL, then +#-- "create table tk7 as select avg(s1),avg(s2) from tk;" +#-- should not create a table with "double(17,4)" data types. +#-- The result of AVG must still be exact numeric, with a +#-- scale the same or greater than the operand's scale. +#-- The result of SUM must still be exact numeric, with +#-- a scale the same as the operand's scale. +# +#drop table if exists t1; +#drop table if exists t2; +# +#create table t1 (col1 int, col2 decimal(5)); +# +#create table t2 as select avg(col1),avg(col2) from t1; +# +# +#show create table t2; +#-- should return: +#+-------+---------------------------------+ +#| Table | Create Table | +#+-------+---------------------------------+ +#| t2 | CREATE TABLE `t2` ( | +#| `avg(col1)` decimal(17,4) default NULL, | +#| `avg(col2)` decimal(17,5) default NULL | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+---------------------------------+ +# +#drop table t2; +#drop table t1; +# +#-- From WL#1612 "The future" point 8.: Stop storing leading "+" signs and +# leading "0"s. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(5,2),col2 decimal(5) zerofill, col3 decimal(3,1)); +# +#insert into t1 values (1,1,1); +# +#select col1 from t1 union select col2 from t1 union select col3 from t1; +# +#drop table t1; +# +#-- From WL#1612, The future" point 9.: +#-- Accept the data type and precision and scale as the user +#-- asks, or return an error, but don't change to something else. +# +#drop table if exists t1; +# +#create table t1 (col1 numeric(4,2)); +# +#show create table t1; +# +#drop table t1; +# +#-- The scripts in the following bugs should work: +# + +#BUG#559 Maximum precision for DECIMAL column ... +#BUG#1499 INSERT/UPDATE into decimal field rounding problem +#BUG#1845 Not correctly recognising value for decimal field +#BUG#2493 Round function doesn't work correctly +#BUG#2649 round(0.5) gives 0 (should be 1) +#BUG#3612 impicite rounding of VARCHARS during aritchmetic operations... +#BUG#3722 SELECT fails for certain values in Double(255,10) column. +#BUG#4485 Floating point conversions are inconsistent +#BUG#4891 MATH +#BUG#5931 Out-of-range values are accepted +#BUG#6048 Stored procedure causes operating system reboot +#BUG#6053 DOUBLE PRECISION literal + +# Tests from 'traditional' mode tests +# +set sql_mode='ansi,traditional'; +# +CREATE TABLE Sow6_2f (col1 NUMERIC(4,2)); +#-- should return OK +INSERT INTO Sow6_2f VALUES (10.55); +#-- should return OK +INSERT INTO Sow6_2f VALUES (10.5555); +#-- should return OK +INSERT INTO Sow6_2f VALUES (-10.55); +#-- should return OK +INSERT INTO Sow6_2f VALUES (-10.5555); +#-- should return OK +INSERT INTO Sow6_2f VALUES (11); +#-- should return OK +-- error 1264 +INSERT INTO Sow6_2f VALUES (101.55); +#-- should return SQLSTATE 22003 numeric value out of range +-- error 1264 +UPDATE Sow6_2f SET col1 = col1 * 50 WHERE col1 = 11; +#-- should return SQLSTATE 22003 numeric value out of range +-- error 1365 +UPDATE Sow6_2f SET col1 = col1 / 0 WHERE col1 > 0; +#-- should return SQLSTATE 22012 division by zero +SELECT MOD(col1,0) FROM Sow6_2f; +#-- should return SQLSTATE 22012 division by zero +-- error 1366 +INSERT INTO Sow6_2f VALUES ('a59b'); +#-- should return SQLSTATE 22018 invalid character value for cast +drop table Sow6_2f; + +# +# bug#9501 +# +select 10.3330000000000/12.34500000; + +# +# Bug #10404 +# + +set sql_mode=''; +select 0/0; + +# +# bug #9546 +# +--disable_ps_protocol +select 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 as x; +select 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + 1 as x; +--enable_ps_protocol +# +# Bug #10004 +# +select 0.190287977636363637 + 0.040372670 * 0 - 0; +# +# Bug #9527 +# +select -0.123 * 0; + +# +# Bug #10232 +# + +CREATE TABLE t1 (f1 DECIMAL (12,9), f2 DECIMAL(2,2)); +INSERT INTO t1 VALUES (10.5, 0); +UPDATE t1 SET f1 = 4.5; +SELECT * FROM t1; +DROP TABLE t1; +CREATE TABLE t1 (f1 DECIMAL (64,20), f2 DECIMAL(2,2)); +INSERT INTO t1 VALUES (9999999999999999999999999999999999, 0); +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #10599: problem with NULL +# + +select abs(10/0); +select abs(NULL); + +# +# Bug #9894 (negative to unsigned column) +# +set @@sql_mode='traditional'; +create table t1( d1 decimal(18) unsigned, d2 decimal(20) unsigned, d3 decimal (22) unsigned); +--error 1264 +insert into t1 values(1,-1,-1); +drop table t1; +create table t1 (col1 decimal(5,2), col2 numeric(5,2)); +--error 1264 +insert into t1 values (999.999,999.999); +--error 1264 +insert into t1 values (-999.999,-999.999); +select * from t1; +drop table t1; +set sql_mode=''; + +# +# Bug #8425 (insufficient precision of the division) +# +set @sav_dpi= @@div_precision_increment; +set @@div_precision_increment=15; +create table t1 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); +insert into t1 values (1,0.0123456789012345678912345,0.0123456789012345678912345); +select col2/9999999999 from t1 where col1=1; +select 9999999999/col2 from t1 where col1=1; +select 77777777/7777777; +drop table t1; +set div_precision_increment= @sav_dpi; + +# +# Bug #10896 (0.00 > -0.00) +# +create table t1 (a decimal(4,2)); +insert into t1 values (0.00); +select * from t1 where a > -0.00; +select * from t1 where a = -0.00; +drop table t1; + +# +# Bug #11215: a problem with LONGLONG_MIN +# + +create table t1 (col1 bigint default -9223372036854775808); +insert into t1 values (default); +select * from t1; +drop table t1; + +# +# Bug #10891 (converting to decimal crashes server) +# +select cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15)); + +# +# Bug #11708 (conversion to decimal fails in decimal part) +# +select ln(14000) c1, convert(ln(14000),decimal(5,3)) c2, cast(ln(14000) as decimal(5,3)) c3; +--error 1427 +select convert(ln(14000),decimal(2,3)) c1; +--error 1427 +select cast(ln(14000) as decimal(2,3)) c1; + +# +# Bug #8449 (Silent column changes) +# +--error 1426 +create table t1 (sl decimal(70,30)); +--error 1425 +create table t1 (sl decimal(32,31)); +--error 1425 +create table t1 (sl decimal(0,38)); +--error 1427 +create table t1 (sl decimal(0,30)); +create table t1 (sl decimal(5, 5)); +show create table t1; +drop table t1; +# Test limits +create table t1 (sl decimal(65, 30)); +show create table t1; +drop table t1; + +# +# Bug 11557 (DEFAULT values rounded improperly +# +create table t1 ( + f1 decimal unsigned not null default 17.49, + f2 decimal unsigned not null default 17.68, + f3 decimal unsigned not null default 99.2, + f4 decimal unsigned not null default 99.7, + f5 decimal unsigned not null default 104.49, + f6 decimal unsigned not null default 199.91, + f7 decimal unsigned not null default 999.9, + f8 decimal unsigned not null default 9999.99); +insert into t1 (f1) values (1); +select * from t1; +drop table t1; + +# +# Bug 12173 (show create table fails) +# +create table t1 ( + f0 decimal (30,30) zerofill not null DEFAULT 0, + f1 decimal (0,0) zerofill not null default 0); +show create table t1; +drop table t1; + +# +# Bug 12938 (arithmetic loop's zero) +# +--disable_warnings +drop procedure if exists wg2; +--enable_warnings +delimiter //; +create procedure wg2() +begin + declare v int default 1; + declare tdec decimal(5) default 0; + while v <= 9 do set tdec =tdec * 10; + select v, tdec; + set v = v + 1; + end while; +end// + +call wg2()// + +delimiter ;// +drop procedure wg2; + +# +# Bug #12979 Stored procedures: crash if inout decimal parameter +# (not a SP bug in fact) +# + +select cast(@non_existing_user_var/2 as DECIMAL); + +# +# Bug #13667 (Inconsistency for decimal(m,d) specification +# +--error 1427 +create table t (d decimal(0,10)); + +# +# Bug #14268 (bad FLOAT->DECIMAL conversion) +# + +CREATE TABLE t1 ( + my_float FLOAT, + my_double DOUBLE, + my_varchar VARCHAR(50), + my_decimal DECIMAL(65,30) +); +SHOW CREATE TABLE t1; + +let $max_power= 32; +while ($max_power) +{ + eval INSERT INTO t1 SET my_float = 1.175494345e-$max_power, + my_double = 1.175494345e-$max_power, + my_varchar = '1.175494345e-$max_power'; + dec $max_power; +} +SELECT my_float, my_double, my_varchar FROM t1; + +# Expected result 0.000000000011754943372854760000 +# On windows we get 0.000000000011754943372854770000 +# use replace_result to correct it +--replace_result 0.000000000011754943372854770000 0.000000000011754943372854760000 +SELECT CAST(my_float AS DECIMAL(65,30)), my_float FROM t1; +SELECT CAST(my_double AS DECIMAL(65,30)), my_double FROM t1; +SELECT CAST(my_varchar AS DECIMAL(65,30)), my_varchar FROM t1; + +# We have to disable warnings here as the test in +# Field_new_decimal::store(double): +# if (nr2 != nr) +# fails randomly depending on compiler options + +--disable_warnings +UPDATE t1 SET my_decimal = my_float; + +# Expected result 0.000000000011754943372854760000 +# On windows we get 0.000000000011754943372854770000 +# use replace_result to correct it +--replace_result 0.000000000011754943372854770000 0.000000000011754943372854760000 +SELECT my_decimal, my_float FROM t1; + +UPDATE t1 SET my_decimal = my_double; +SELECT my_decimal, my_double FROM t1 order by my_decimal; # PBXT required for consistent result +--enable_warnings +--disable_warnings # PBXT The rows updated keeps changing +UPDATE t1 SET my_decimal = my_varchar; +--enable_warnings # PBXT The rows updated keeps changing +SELECT my_decimal, my_varchar FROM t1 order by my_decimal, my_varchar; + +DROP TABLE t1; + +# +# Bug #13573 (Wrong data inserted for too big values) +# + +create table t1 (c1 decimal(64)); +--disable_ps_protocol +insert into t1 values( +89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000); +insert into t1 values( +99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * +99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999); +--enable_ps_protocol +insert into t1 values(1e100); +select * from t1; +drop table t1; + +# +# Bug #18014: problem with 'alter table' +# + +create table t1(a decimal(7,2)); +insert into t1 values(123.12); +select * from t1; +alter table t1 modify a decimal(10,2); +select * from t1; +drop table t1; + +# +# Bug#19667 group by a decimal expression yields wrong result +# +create table t1 (i int, j int); +insert into t1 values (1,1), (1,2), (2,3), (2,4); +select i, count(distinct j) from t1 group by i; +select i+0.0 as i2, count(distinct j) from t1 group by i2; +drop table t1; + +create table t1(f1 decimal(20,6)); +insert into t1 values (CAST('10:11:12' AS date) + interval 14 microsecond); +insert into t1 values (CAST('10:11:12' AS time)); +select * from t1; +drop table t1; + +# +# Bug#16172 DECIMAL data type processed incorrectly +# +select cast(143.481 as decimal(4,1)); +select cast(143.481 as decimal(4,0)); +select cast(143.481 as decimal(2,1)); +select cast(-3.4 as decimal(2,1)); +select cast(99.6 as decimal(2,0)); +select cast(-13.4 as decimal(2,1)); +select cast(98.6 as decimal(2,0)); + +# Bug #8663 (cant use bigint as input to CAST) +# +select cast(19999999999999999999 as unsigned); + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/type_ranges.test b/mysql-test/suite/pbxt/t/type_ranges.test new file mode 100644 index 00000000000..e1a06bb047e --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_ranges.test @@ -0,0 +1,179 @@ +# +# Test ranges for all types and some other basic tests +# + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings +SET SQL_WARNINGS=1; + +CREATE TABLE t1 ( + auto int(5) unsigned NOT NULL auto_increment, + string char(10) default "hello", + tiny tinyint(4) DEFAULT '0' NOT NULL , + short smallint(6) DEFAULT '1' NOT NULL , + medium mediumint(8) DEFAULT '0' NOT NULL, + long_int int(11) DEFAULT '0' NOT NULL, + longlong bigint(13) DEFAULT '0' NOT NULL, + real_float float(13,1) DEFAULT 0.0 NOT NULL, + real_double double(16,4), + utiny tinyint(3) unsigned DEFAULT '0' NOT NULL, + ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL, + umedium mediumint(8) unsigned DEFAULT '0' NOT NULL, + ulong int(11) unsigned DEFAULT '0' NOT NULL, + ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL, + time_stamp timestamp, + date_field date, + time_field time, + date_time datetime, + blob_col blob, + tinyblob_col tinyblob, + mediumblob_col mediumblob not null default '', + longblob_col longblob not null default '', + options enum('one','two','tree') not null , + flags set('one','two','tree') not null default '', + PRIMARY KEY (auto), + KEY (utiny), + KEY (tiny), + KEY (short), + KEY any_name (medium), + KEY (longlong), + KEY (real_float), + KEY (ushort), + KEY (umedium), + KEY (ulong), + KEY (ulonglong,ulong), + KEY (options,flags) +); + +# We mask out the Privileges column because it differs with embedded server +--replace_column 8 # +show full fields from t1; +show keys from t1; + +CREATE UNIQUE INDEX test on t1 ( auto ) ; +CREATE INDEX test2 on t1 ( ulonglong,ulong) ; +CREATE INDEX test3 on t1 ( medium ) ; +DROP INDEX test ON t1; + +insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one'); +insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one'); +insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); +insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); +insert into t1 values (0,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,NULL,0,0,0,-4294967295,-4294967295,-4294967295,'-4294967295',0,"one,two,tree"); +insert into t1 values (0,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,NULL,0,0,0,4294967295,4294967295,4294967295,'4294967295',0,0); +insert into t1 (tiny) values (1); + +select auto,string,tiny,short,medium,long_int,longlong,real_float,real_double,utiny,ushort,umedium,ulong,ulonglong,mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000),date_field,time_field,date_time,blob_col,tinyblob_col,mediumblob_col,longblob_col from t1; + + +ALTER TABLE t1 +add new_field char(10) default "new" not null, +change blob_col new_blob_col varchar(20), +change date_field date_field char(10), +alter column string set default "newdefault", +alter short drop default, +DROP INDEX utiny, +DROP INDEX ushort, +DROP PRIMARY KEY, +DROP FOREIGN KEY any_name, +ADD INDEX (auto); + +LOCK TABLES t1 WRITE; +ALTER TABLE t1 +RENAME as t2, +DROP longblob_col; +UNLOCK TABLES; + +ALTER TABLE t2 rename as t3; +LOCK TABLES t3 WRITE ; +ALTER TABLE t3 rename as t1; +UNLOCK TABLES; + +select auto,new_field,new_blob_col,date_field from t1 ; + +# +# check with old syntax +# +CREATE TABLE t2 ( + auto int(5) unsigned NOT NULL auto_increment, + string char(20), + mediumblob_col mediumblob not null, + new_field char(2), + PRIMARY KEY (auto) +); + +INSERT INTO t2 (string,mediumblob_col,new_field) SELECT string,mediumblob_col,new_field from t1 where auto > 10; + +select * from t2; + +# test enums +select distinct flags from t1; +select flags from t1 where find_in_set("two",flags)>0; +select flags from t1 where find_in_set("unknown",flags)>0; +select options,flags from t1 where options="ONE" and flags="ONE"; +select options,flags from t1 where options="one" and flags="one"; + +drop table t2; + +# +# Check CREATE ... SELECT +# + +create table t2 select * from t1; +update t2 set string="changed" where auto=16; +# We mask out the Privileges column because it differs with embedded server +--replace_column 8 # +show full columns from t1; +--replace_column 8 # +show full columns from t2; +select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and ((t1.string<>t2.string and (t1.string is not null or t2.string is not null)) or (t1.tiny<>t2.tiny and (t1.tiny is not null or t2.tiny is not null)) or (t1.short<>t2.short and (t1.short is not null or t2.short is not null)) or (t1.medium<>t2.medium and (t1.medium is not null or t2.medium is not null)) or (t1.long_int<>t2.long_int and (t1.long_int is not null or t2.long_int is not null)) or (t1.longlong<>t2.longlong and (t1.longlong is not null or t2.longlong is not null)) or (t1.real_float<>t2.real_float and (t1.real_float is not null or t2.real_float is not null)) or (t1.real_double<>t2.real_double and (t1.real_double is not null or t2.real_double is not null)) or (t1.utiny<>t2.utiny and (t1.utiny is not null or t2.utiny is not null)) or (t1.ushort<>t2.ushort and (t1.ushort is not null or t2.ushort is not null)) or (t1.umedium<>t2.umedium and (t1.umedium is not null or t2.umedium is not null)) or (t1.ulong<>t2.ulong and (t1.ulong is not null or t2.ulong is not null)) or (t1.ulonglong<>t2.ulonglong and (t1.ulonglong is not null or t2.ulonglong is not null)) or (t1.time_stamp<>t2.time_stamp and (t1.time_stamp is not null or t2.time_stamp is not null)) or (t1.date_field<>t2.date_field and (t1.date_field is not null or t2.date_field is not null)) or (t1.time_field<>t2.time_field and (t1.time_field is not null or t2.time_field is not null)) or (t1.date_time<>t2.date_time and (t1.date_time is not null or t2.date_time is not null)) or (t1.new_blob_col<>t2.new_blob_col and (t1.new_blob_col is not null or t2.new_blob_col is not null)) or (t1.tinyblob_col<>t2.tinyblob_col and (t1.tinyblob_col is not null or t2.tinyblob_col is not null)) or (t1.mediumblob_col<>t2.mediumblob_col and (t1.mediumblob_col is not null or t2.mediumblob_col is not null)) or (t1.options<>t2.options and (t1.options is not null or t2.options is not null)) or (t1.flags<>t2.flags and (t1.flags is not null or t2.flags is not null)) or (t1.new_field<>t2.new_field and (t1.new_field is not null or t2.new_field is not null))); +select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and not (t1.string<=>t2.string and t1.tiny<=>t2.tiny and t1.short<=>t2.short and t1.medium<=>t2.medium and t1.long_int<=>t2.long_int and t1.longlong<=>t2.longlong and t1.real_float<=>t2.real_float and t1.real_double<=>t2.real_double and t1.utiny<=>t2.utiny and t1.ushort<=>t2.ushort and t1.umedium<=>t2.umedium and t1.ulong<=>t2.ulong and t1.ulonglong<=>t2.ulonglong and t1.time_stamp<=>t2.time_stamp and t1.date_field<=>t2.date_field and t1.time_field<=>t2.time_field and t1.date_time<=>t2.date_time and t1.new_blob_col<=>t2.new_blob_col and t1.tinyblob_col<=>t2.tinyblob_col and t1.mediumblob_col<=>t2.mediumblob_col and t1.options<=>t2.options and t1.flags<=>t2.flags and t1.new_field<=>t2.new_field); + +drop table t2; + +create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1; +# We mask out the Privileges column because it differs with embedded server +--replace_column 8 # +show full columns from t2; +select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2; +drop table t1,t2; + +create table t1 (c int); +insert into t1 values(1),(2); +create table t2 select * from t1; +--error 1060 +create table t3 select * from t1, t2; # Should give an error +create table t3 select t1.c AS c1, t2.c AS c2,1 as "const" from t1, t2; +# We mask out the Privileges column because it differs with embedded server +--replace_column 8 # +show full columns from t3; +drop table t1,t2,t3; + +create table t1 ( myfield INT NOT NULL, UNIQUE INDEX (myfield), unique (myfield), index(myfield)); +drop table t1; + +create table t1 ( id integer unsigned not null primary key ); +create table t2 ( id integer unsigned not null primary key ); +insert into t1 values (1), (2); +insert into t2 values (1); +select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); +create table t3 (id_A integer unsigned not null, id_B integer unsigned null ); +insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select * from t3; +truncate table t3; +insert into t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); +select * from t3; +drop table t3; +create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); +select * from t3; +drop table t3; +create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 on (t1.id = t2.id); +select * from t3; +drop table t1,t2,t3; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/type_set.test b/mysql-test/suite/pbxt/t/type_set.test new file mode 100644 index 00000000000..b77ef42c5a2 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_set.test @@ -0,0 +1,44 @@ +# +# Test of SET with space +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a set (' ','a','b') not null); +show create table t1; +drop table t1; +create table t1 (a set (' ','a','b ') not null default 'b '); +show create table t1; +drop table t1; +CREATE TABLE t1 ( user varchar(64) NOT NULL default '', path varchar(255) NOT NULL default '', privilege set('select','RESERVED30','RESERVED29','RESERVED28','RESERVED27','RESERVED26', 'RESERVED25','RESERVED24','data.delete','RESERVED22','RESERVED21', 'RESERVED20','data.insert.none','data.insert.approve', 'data.insert.delete','data.insert.move','data.insert.propose', 'data.insert.reject','RESERVED13','RESERVED12','RESERVED11','RESERVED10', 'RESERVED09','data.update','RESERVED07','RESERVED06','RESERVED05', 'RESERVED04','metadata.delete','metadata.put','RESERVED01','RESERVED00') NOT NULL default '', KEY user (user) ) ENGINE=MyISAM CHARSET=utf8; +DROP TABLE t1; + +# +# Check that SET is case sensitive with a binary collation +# +set names latin1; +create table t1 (s set ('a','A') character set latin1 collate latin1_bin); +show create table t1; +insert into t1 values ('a'),('a,A'),('A,a'),('A'); +select s from t1 order by s; +select s from t1 order by concat(s); +drop table t1; + +# +# Check that SET honors a more complex collation correctly +# +CREATE TABLE t1 (c set('ae','oe','ue','ss') collate latin1_german2_ci); +INSERT INTO t1 VALUES ('ä'),('ö'),('ü'),('ß'); +INSERT INTO t1 VALUES ('ae'),('oe'),('ue'),('ss'); +INSERT INTO t1 VALUES ('ä,ö,ü,ß'); +INSERT INTO t1 VALUES ('ae,oe,ue,ss'); +SELECT c FROM t1 ORDER BY c; +SELECT c FROM t1 ORDER BY concat(c); +DROP TABLE t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/type_time.test b/mysql-test/suite/pbxt/t/type_time.test new file mode 100644 index 00000000000..7b11a754845 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_time.test @@ -0,0 +1,45 @@ +# +# testing of the TIME column type +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (t time); +insert into t1 values("10:22:33"),("12:34:56.78"),(10),(1234),(123456.78),(1234559.99),("1"),("1:23"),("1:23:45"), ("10.22"), ("-10 1:22:33.45"),("20 10:22:33"),("1999-02-03 20:33:34"); +insert t1 values (30),(1230),("1230"),("12:30"),("12:30:35"),("1 12:30:31.32"); +select * from t1; +# Test wrong values +insert into t1 values("10.22.22"),(1234567),(123456789),(123456789.10),("10 22:22"),("12.45a"); +select * from t1; +drop table t1; + +create table t1 (t time); +insert into t1 values ('09:00:00'),('13:00:00'),('19:38:34'), ('13:00:00'),('09:00:00'),('09:00:00'),('13:00:00'),('13:00:00'),('13:00:00'),('09:00:00'); +select t, time_to_sec(t),sec_to_time(time_to_sec(t)) from t1; +select sec_to_time(time_to_sec(t)) from t1; +drop table t1; + +# +# BUG #12440: Incorrect processing of time values containing +# long fraction part and/or large exponent part. +# +# These must return normal result: +# ########################################################## +# To be uncommented after fix BUG #15805 +# ########################################################## +# SELECT CAST(235959.123456 AS TIME); +# SELECT CAST(0.235959123456e+6 AS TIME); +# SELECT CAST(235959123456e-6 AS TIME); +# These must cut fraction part and produce warning: +# SELECT CAST(235959.1234567 AS TIME); +# SELECT CAST(0.2359591234567e6 AS TIME); +# This must return NULL and produce warning: +# SELECT CAST(0.2359591234567e+30 AS TIME); +# ########################################################## + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/type_timestamp.test b/mysql-test/suite/pbxt/t/type_timestamp.test new file mode 100644 index 00000000000..88b4c4e2587 --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_timestamp.test @@ -0,0 +1,345 @@ +# +# Test timestamp +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +# Set timezone to GMT-3, to make it possible to use "interval 3 hour" +set time_zone="+03:00"; + +CREATE TABLE t1 (a int, t timestamp); +CREATE TABLE t2 (a int, t datetime); +SET TIMESTAMP=1234; +insert into t1 values(1,NULL); +insert into t1 values(2,"2002-03-03"); +SET TIMESTAMP=1235; +insert into t1 values(3,NULL); +SET TIMESTAMP=1236; +insert into t1 (a) values(4); +insert into t2 values(5,"2002-03-04"),(6,NULL),(7,"2002-03-05"),(8,"00-00-00"); +SET TIMESTAMP=1237; +insert into t1 select * from t2; +SET TIMESTAMP=1238; +insert into t1 (a) select a+1 from t2 where a=8; +select * from t1; +drop table t1,t2; + +SET TIMESTAMP=1234; +CREATE TABLE t1 (value TEXT NOT NULL, id VARCHAR(32) NOT NULL, stamp timestamp, PRIMARY KEY (id)); +INSERT INTO t1 VALUES ("my value", "myKey","1999-04-02 00:00:00"); +SELECT stamp FROM t1 WHERE id="myKey"; +UPDATE t1 SET value="my value" WHERE id="myKey"; +SELECT stamp FROM t1 WHERE id="myKey"; +UPDATE t1 SET id="myKey" WHERE value="my value"; +SELECT stamp FROM t1 WHERE id="myKey"; +drop table t1; + +create table t1 (a timestamp); +insert into t1 values (now()); +select date_format(a,"%Y %y"),year(a),year(now()) from t1; +drop table t1; + +create table t1 (ix timestamp); +insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000); +select ix+0 from t1; +truncate table t1; +insert into t1 values ("19991101000000"),("19990102030405"),("19990630232922"),("19990601000000"); +select ix+0 from t1; +drop table t1; + +CREATE TABLE t1 (date date, date_time datetime, time_stamp timestamp); +INSERT INTO t1 VALUES ("1998-12-31","1998-12-31 23:59:59",19981231235959); +INSERT INTO t1 VALUES ("1999-01-01","1999-01-01 00:00:00",19990101000000); +INSERT INTO t1 VALUES ("1999-09-09","1999-09-09 23:59:59",19990909235959); +INSERT INTO t1 VALUES ("2000-01-01","2000-01-01 00:00:00",20000101000000); +INSERT INTO t1 VALUES ("2000-02-28","2000-02-28 00:00:00",20000228000000); +INSERT INTO t1 VALUES ("2000-02-29","2000-02-29 00:00:00",20000229000000); +INSERT INTO t1 VALUES ("2000-03-01","2000-03-01 00:00:00",20000301000000); +INSERT INTO t1 VALUES ("2000-12-31","2000-12-31 23:59:59",20001231235959); +INSERT INTO t1 VALUES ("2001-01-01","2001-01-01 00:00:00",20010101000000); +INSERT INTO t1 VALUES ("2004-12-31","2004-12-31 23:59:59",20041231235959); +INSERT INTO t1 VALUES ("2005-01-01","2005-01-01 00:00:00",20050101000000); +INSERT INTO t1 VALUES ("2030-01-01","2030-01-01 00:00:00",20300101000000); +# The following will get you an different answer on 64 bit machines +#INSERT INTO t1 VALUES ("2050-01-01","2050-01-01 00:00:00",20500101000000); +SELECT * FROM t1; +drop table t1; + +create table t1 (t2 timestamp(2), t4 timestamp(4), t6 timestamp(6), + t8 timestamp(8), t10 timestamp(10), t12 timestamp(12), + t14 timestamp(14)); +insert t1 values (0,0,0,0,0,0,0), +("1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", +"1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", +"1997-12-31 23:47:59"); +select * from t1; +select * from t1; +drop table t1; + +# +# Let us check if we properly treat wrong datetimes and produce proper warnings +# (for both strings and numbers) +# +create table t1 (ix timestamp); +insert into t1 values (0),(20030101010160),(20030101016001),(20030101240101),(20030132010101),(20031301010101),(20031200000000),(20030000000000); +select ix+0 from t1; +truncate table t1; +insert into t1 values ("00000000000000"),("20030101010160"),("20030101016001"),("20030101240101"),("20030132010101"),("20031301010101"),("20031200000000"),("20030000000000"); +select ix+0 from t1; +truncate table t1; +insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer"); +select ix+0 from t1; +drop table t1; + +# +# Test for TIMESTAMP column with default now() and on update now() clauses +# + +# These statements should fail. +--error 1293 +create table t1 (t1 timestamp, t2 timestamp default now()); +--error 1293 +create table t1 (t1 timestamp, t2 timestamp on update now()); +--error 1293 +create table t1 (t1 timestamp, t2 timestamp default now() on update now()); +--error 1293 +create table t1 (t1 timestamp default now(), t2 timestamp on update now()); +--error 1293 +create table t1 (t1 timestamp on update now(), t2 timestamp default now() on update now()); + +# Let us test TIMESTAMP auto-update behaviour +# Also we will test behaviour of TIMESTAMP field in SHOW CREATE TABLE and +# behaviour of DEFAULT literal for such fields +create table t1 (t1 timestamp default '2003-01-01 00:00:00', t2 datetime, t3 timestamp); +SET TIMESTAMP=1000000000; +insert into t1 values (); +SET TIMESTAMP=1000000001; +update t1 set t2=now(); +SET TIMESTAMP=1000000002; +insert into t1 (t1,t3) values (default, default); +select * from t1 order by t2; # PBXT: Order for consistent result +show create table t1; +show columns from t1; +drop table t1; + +create table t1 (t1 timestamp default now(), t2 datetime, t3 timestamp); +SET TIMESTAMP=1000000002; +insert into t1 values (); +SET TIMESTAMP=1000000003; +update t1 set t2=now(); +SET TIMESTAMP=1000000003; +insert into t1 (t1,t3) values (default, default); +select * from t1 order by t1; # PBXT: Order for consistent result +show create table t1; +show columns from t1; +drop table t1; + +create table t1 (t1 timestamp default '2003-01-01 00:00:00' on update now(), t2 datetime); +SET TIMESTAMP=1000000004; +insert into t1 values (); +select * from t1; +SET TIMESTAMP=1000000005; +update t1 set t2=now(); +SET TIMESTAMP=1000000005; +insert into t1 (t1) values (default); +select * from t1 order by t1; # PBXT: Order for consistent result +show create table t1; +show columns from t1; +drop table t1; + +create table t1 (t1 timestamp default now() on update now(), t2 datetime); +SET TIMESTAMP=1000000006; +insert into t1 values (); +select * from t1; +SET TIMESTAMP=1000000007; +update t1 set t2=now(); +SET TIMESTAMP=1000000007; +insert into t1 (t1) values (default); +select * from t1 order by t2; # PBXT: Order for consistent result +show create table t1; +show columns from t1; +drop table t1; + +create table t1 (t1 timestamp, t2 datetime, t3 timestamp); +SET TIMESTAMP=1000000007; +insert into t1 values (); +select * from t1; +SET TIMESTAMP=1000000008; +update t1 set t2=now(); +SET TIMESTAMP=1000000008; +insert into t1 (t1,t3) values (default, default); +select * from t1 order by t2; # PBXT: Order for consistent result +show create table t1; +show columns from t1; +drop table t1; + +# Let us test if CURRENT_TIMESTAMP also works well as default value +# (Of course NOW and CURRENT_TIMESTAMP are same for parser but still just +# for demonstartion.) +create table t1 (t1 timestamp default current_timestamp on update current_timestamp, t2 datetime); +SET TIMESTAMP=1000000009; +insert into t1 values (); +select * from t1; +SET TIMESTAMP=1000000010; +update t1 set t2=now(); +SET TIMESTAMP=1000000011; +insert into t1 (t1) values (default); +select * from t1 order by t1; # PBXT: Order for consistent result +show create table t1; +show columns from t1; +truncate table t1; + +# +# Let us test some cases when auto-set should be disabled or influence +# on server behavior in some other way. +# + +# Update statement that explicitly sets field should not auto-set it. +insert into t1 values ('2004-04-01 00:00:00', '2004-04-01 00:00:00'); +SET TIMESTAMP=1000000012; +update t1 set t1= '2004-04-02 00:00:00'; +select * from t1; +# The same for multi updates +update t1 as ta, t1 as tb set tb.t1= '2004-04-03 00:00:00'; +select * from t1; +drop table t1; + +# Now let us test replace it should behave exactly like delete+insert +# Case where optimization is possible DEFAULT = ON UPDATE +create table t1 (pk int primary key, t1 timestamp default current_timestamp on update current_timestamp, bulk int); +insert into t1 values (1, '2004-04-01 00:00:00', 10); +SET TIMESTAMP=1000000013; +replace into t1 set pk = 1, bulk= 20; +select * from t1; +drop table t1; +# Case in which there should not be optimisation +create table t1 (pk int primary key, t1 timestamp default '2003-01-01 00:00:00' on update current_timestamp, bulk int); +insert into t1 values (1, '2004-04-01 00:00:00', 10); +SET TIMESTAMP=1000000014; +replace into t1 set pk = 1, bulk= 20; +select * from t1; +drop table t1; +# Other similar case +create table t1 (pk int primary key, t1 timestamp default current_timestamp, bulk int); +insert into t1 values (1, '2004-04-01 00:00:00', 10); +SET TIMESTAMP=1000000015; +replace into t1 set pk = 1, bulk= 20; +select * from t1; +drop table t1; + +# Let us test alter now +create table t1 (t1 timestamp default current_timestamp on update current_timestamp); +insert into t1 values ('2004-04-01 00:00:00'); +SET TIMESTAMP=1000000016; +alter table t1 add i int default 10; +select * from t1; +drop table t1; + +# +# Test for TIMESTAMP columns which are able to store NULLs +# + +# Unlike for default TIMESTAMP fields we don't interpret first field +# in this table as TIMESTAMP with DEFAULT NOW() ON UPDATE NOW() properties. +create table t1 (a timestamp null, b timestamp null); +show create table t1; +insert into t1 values (NULL, NULL); +SET TIMESTAMP=1000000017; +insert into t1 values (); +select * from t1; +drop table t1; + +# But explicit auto-set properties still should be OK. +create table t1 (a timestamp null default current_timestamp on update current_timestamp, b timestamp null); +show create table t1; +insert into t1 values (NULL, NULL); +SET TIMESTAMP=1000000018; +insert into t1 values (); +select * from t1; +drop table t1; + +# It is also OK to specify NULL as default explicitly for such fields. +# This is also a test for bug #2464, DEFAULT keyword in INSERT statement +# should return default value for column. + +create table t1 (a timestamp null default null, b timestamp null default '2003-01-01 00:00:00'); +show create table t1; +insert into t1 values (NULL, NULL); +insert into t1 values (DEFAULT, DEFAULT); +select * from t1; +drop table t1; + +# +# Let us test behavior of ALTER TABLE when it converts columns +# containing NULL to TIMESTAMP columns. +# +create table t1 (a bigint, b bigint); +insert into t1 values (NULL, NULL), (20030101000000, 20030102000000); +set timestamp=1000000019; +alter table t1 modify a timestamp, modify b timestamp; +select * from t1; +drop table t1; + +# +# Test for bug #4131, TIMESTAMP columns missing minutes and seconds when +# using GROUP BY in @@new=1 mode. +# +create table t1 (a char(2), t timestamp); +insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00'), + ('b', '2004-02-01 00:00:00'); +select max(t) from t1 group by a; +drop table t1; + +# +# Test for bug #7418 "TIMESTAMP not always converted to DATETIME in MAXDB +# mode". TIMESTAMP columns should be converted DATETIME columns in MAXDB +# mode regardless of whether a display width is given. +# +set sql_mode='maxdb'; +create table t1 (a timestamp, b timestamp(19)); +show create table t1; +# restore default mode +set sql_mode=''; +drop table t1; + +# +# Bug#7806 - insert on duplicate key and auto-update of timestamp +# +create table t1 (a int auto_increment primary key, b int, c timestamp); +insert into t1 (a, b, c) values (1, 0, '2001-01-01 01:01:01'), + (2, 0, '2002-02-02 02:02:02'), (3, 0, '2003-03-03 03:03:03'); +select * from t1; +update t1 set b = 2, c = c where a = 2; +select * from t1; +insert into t1 (a) values (4); +select * from t1 order by a; # PBXT: Order for consistent result +update t1 set c = '2004-04-04 04:04:04' where a = 4; +select * from t1 order by a; # PBXT required order for consistent result +insert into t1 (a) values (3), (5) on duplicate key update b = 3, c = c; +select * from t1 order by a; # PBXT: Order for consistent result +insert into t1 (a, c) values (4, '2004-04-04 00:00:00'), + (6, '2006-06-06 06:06:06') on duplicate key update b = 4; +select * from t1 order by a; # PBXT: Order for consistent result +drop table t1; + +# End of 4.1 tests + +# Restore timezone to default +set time_zone= @@global.time_zone; + +CREATE TABLE t1 ( +`id` int(11) NOT NULL auto_increment, +`username` varchar(80) NOT NULL default '', +`posted_on` timestamp NOT NULL default '0000-00-00 00:00:00', +PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; + +show fields from t1; +select is_nullable from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='t1' and COLUMN_NAME='posted_on'; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/type_uint.test b/mysql-test/suite/pbxt/t/type_uint.test new file mode 100644 index 00000000000..a9ee2a94a1a --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_uint.test @@ -0,0 +1,20 @@ +# +# test of unsigned int +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +SET SQL_WARNINGS=1; + +create table t1 (this int unsigned); +insert into t1 values (1); +insert into t1 values (-1); +insert into t1 values ('5000000000'); +select * from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/type_year.test b/mysql-test/suite/pbxt/t/type_year.test new file mode 100644 index 00000000000..1a5fb9f082b --- /dev/null +++ b/mysql-test/suite/pbxt/t/type_year.test @@ -0,0 +1,27 @@ +# +# Test year +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (y year,y2 year(2)); +insert into t1 values (0,0),(1999,1999),(2000,2000),(2001,2001),(70,70),(69,69); +select * from t1; +select * from t1 order by y; +select * from t1 order by y2; +drop table t1; + +# +# Bug 2335 +# + +create table t1 (y year); +insert into t1 values (now()); +select if(y = now(), 1, 0) from t1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/udf.test b/mysql-test/suite/pbxt/t/udf.test new file mode 100644 index 00000000000..ab430cc2416 --- /dev/null +++ b/mysql-test/suite/pbxt/t/udf.test @@ -0,0 +1,443 @@ +--source include/have_udf.inc +# +# To run this tests the "sql/udf_example.c" need to be compiled into +# udf_example.so and LD_LIBRARY_PATH should be setup to point out where +# the library are. +# + + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Create the example functions from udf_example +# + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION myfunc_double RETURNS REAL SONAME "$UDF_EXAMPLE_LIB"; + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +--error ER_CANT_FIND_DL_ENTRY +eval CREATE FUNCTION myfunc_nonexist RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB"; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB"; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION sequence RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB"; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION lookup RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION reverse_lookup + RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE AGGREGATE FUNCTION avgcost + RETURNS REAL SONAME "$UDF_EXAMPLE_LIB"; + +--error ER_CANT_INITIALIZE_UDF +select myfunc_double(); +select myfunc_double(1); +select myfunc_double(78654); +--error 1305 +select myfunc_nonexist(); +select myfunc_int(); +--error ER_CANT_INITIALIZE_UDF +select lookup(); +select lookup("127.0.0.1"); +--error ER_CANT_INITIALIZE_UDF +select lookup(127,0,0,1); +select lookup("localhost"); +--error ER_CANT_INITIALIZE_UDF +select reverse_lookup(); + +# These two functions should return "localhost", but it's +# depending on configuration, so just call them and don't log the result +--disable_result_log +select reverse_lookup("127.0.0.1"); +select reverse_lookup(127,0,0,1); +--enable_result_log + +select reverse_lookup("localhost"); +--error ER_CANT_INITIALIZE_UDF +select avgcost(); +--error ER_CANT_INITIALIZE_UDF +select avgcost(100,23.76); +create table t1(sum int, price float(24)); +insert into t1 values(100, 50.00), (100, 100.00); +select avgcost(sum, price) from t1; +delete from t1; +insert into t1 values(100, 54.33), (200, 199.99); +select avgcost(sum, price) from t1; +drop table t1; + +#------------------------------------------------------------------------ +# BUG#17261 Passing a variable from a stored procedure to UDF crashes mysqld +#------------------------------------------------------------------------ + +select metaphon('hello'); + +delimiter //; +CREATE PROCEDURE `XXX1`(in testval varchar(10)) +begin +select metaphon(testval); +end// +delimiter ;// + +call XXX1('hello'); +drop procedure xxx1; + +delimiter //; +CREATE PROCEDURE `XXX2`() +begin +declare testval varchar(10); +set testval = 'hello'; +select metaphon(testval); +end// +delimiter ;// + +call XXX2(); +drop procedure xxx2; + +# +# Bug#19904: UDF: not initialized *is_null per row +# + +CREATE TABLE bug19904(n INT, v varchar(10)); +INSERT INTO bug19904 VALUES (1,'one'),(2,'two'),(NULL,NULL),(3,'three'),(4,'four'); +SELECT myfunc_double(n) AS f FROM bug19904; +SELECT metaphon(v) AS f FROM bug19904; +DROP TABLE bug19904; + +# +# Bug#21269: DEFINER-clause is allowed for UDF-functions +# + +--error ER_PARSE_ERROR +CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse +RETURNS STRING SONAME "should_not_parse.so"; + +--error ER_PARSE_ERROR +CREATE DEFINER=someone@somewhere FUNCTION should_not_parse +RETURNS STRING SONAME "should_not_parse.so"; +# +# Bug#19862: Sort with filesort by function evaluates function twice +# +create table t1(f1 int); +insert into t1 values(1),(2); +explain select myfunc_int(f1) from t1 order by 1; +drop table t1; + +# +# Bug #21809: Error 1356 while selecting from view with grouping though +# underlying select OK. +# +CREATE TABLE t1(a INT, b INT); INSERT INTO t1 values (1,1),(2,2); + +DELIMITER ||; +CREATE FUNCTION fn(a int) RETURNS int DETERMINISTIC +BEGIN + RETURN a; +END +|| +DELIMITER ;|| + +CREATE VIEW v1 AS SELECT a, fn(MIN(b)) as c FROM t1 GROUP BY a; + +SELECT myfunc_int(a AS attr_name) FROM t1; +EXPLAIN EXTENDED SELECT myfunc_int(a AS attr_name) FROM t1; +EXPLAIN EXTENDED SELECT myfunc_int(a) FROM t1; +SELECT a,c FROM v1; + +--error ER_WRONG_PARAMETERS_TO_STORED_FCT +SELECT a, fn(MIN(b) xx) as c FROM t1 GROUP BY a; +--error ER_WRONG_PARAMETERS_TO_STORED_FCT +SELECT myfunc_int(fn(MIN(b) xx)) as c FROM t1 GROUP BY a; +--error ER_PARSE_ERROR +SELECT myfunc_int(test.fn(MIN(b) xx)) as c FROM t1 GROUP BY a; + +SELECT myfunc_int(fn(MIN(b)) xx) as c FROM t1 GROUP BY a; +SELECT myfunc_int(test.fn(MIN(b)) xx) as c FROM t1 GROUP BY a; + +EXPLAIN EXTENDED SELECT myfunc_int(MIN(b) xx) as c FROM t1 GROUP BY a; +EXPLAIN EXTENDED SELECT test.fn(MIN(b)) as c FROM t1 GROUP BY a; +EXPLAIN EXTENDED SELECT myfunc_int(fn(MIN(b))) as c FROM t1 GROUP BY a; +EXPLAIN EXTENDED SELECT myfunc_int(test.fn(MIN(b))) as c FROM t1 GROUP BY a; +SELECT myfunc_int(MIN(b) xx) as c FROM t1 GROUP BY a; +SELECT test.fn(MIN(b)) as c FROM t1 GROUP BY a; +SELECT myfunc_int(fn(MIN(b))) as c FROM t1 GROUP BY a; +SELECT myfunc_int(test.fn(MIN(b))) as c FROM t1 GROUP BY a; +DROP VIEW v1; +DROP TABLE t1; +DROP FUNCTION fn; + +--echo End of 5.0 tests. + +# +# Bug#24736: UDF functions parsed as Stored Functions +# + +select myfunc_double(3); +select myfunc_double(3 AS three); +select myfunc_double(abs(3)); +select myfunc_double(abs(3) AS named_param); +select abs(myfunc_double(3)); +select abs(myfunc_double(3 AS three)); + +-- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT +select myfunc_double(abs(3 AS wrong)); +-- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT +select abs(myfunc_double(3) AS wrong); + +# +# BUG#18239: Possible to overload internal functions with stored functions +# + +--disable_warnings +drop function if exists pi; +--enable_warnings + +--error ER_NATIVE_FCT_NAME_COLLISION +CREATE FUNCTION pi RETURNS STRING SONAME "should_not_parse.so"; + +# Verify that Stored Functions and UDF are mutually exclusive +DROP FUNCTION IF EXISTS metaphon; + +CREATE FUNCTION metaphon(a int) RETURNS int +return 0; + +# this currently passes, and eclipse the stored function +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; + +DROP FUNCTION metaphon; +DROP FUNCTION metaphon; + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; + +--error ER_UDF_EXISTS +CREATE FUNCTION metaphon(a int) RETURNS int +return 0; + +--error ER_UDF_EXISTS +CREATE FUNCTION test.metaphon(a int) RETURNS int +return 0; + +# End of Bug#18239 + +# +# Drop the example functions from udf_example +# + +DROP FUNCTION metaphon; +DROP FUNCTION myfunc_double; +--error ER_SP_DOES_NOT_EXIST +DROP FUNCTION myfunc_nonexist; +DROP FUNCTION myfunc_int; +DROP FUNCTION sequence; +DROP FUNCTION lookup; +DROP FUNCTION reverse_lookup; +DROP FUNCTION avgcost; + +# +# Bug #15439: UDF name case handling forces DELETE FROM mysql.func to remove +# the UDF +# +select * from mysql.func; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION is_const RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; + +select IS_const(3); + +drop function IS_const; + +select * from mysql.func; + +--error 1305 +select is_const(3); + +# +# Bug#18761: constant expression as UDF parameters not passed in as constant +# +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION is_const RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; + +select + is_const(3) as const, + is_const(3.14) as const, + is_const('fnord') as const, + is_const(2+3) as const, + is_const(rand()) as 'nc rand()', + is_const(sin(3.14)) as const, + is_const(upper('test')) as const; + +create table bug18761 (n int); +insert into bug18761 values (null),(2); +select + is_const(3) as const, + is_const(3.14) as const, + is_const('fnord') as const, + is_const(2+3) as const, + is_const(2+n) as 'nc 2+n ', + is_const(sin(n)) as 'nc sin(n)', + is_const(sin(3.14)) as const, + is_const(upper('test')) as const, + is_const(rand()) as 'nc rand()', + is_const(n) as 'nc n ', + is_const(is_const(n)) as 'nc ic?(n)', + is_const(is_const('c')) as const +from + bug18761; +drop table bug18761; + +--error 1241 +select is_const((1,2,3)); + +drop function if exists is_const; + +# +# Bug #25382: Passing NULL to an UDF called from stored procedures +# crashes server +# +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION myfunc_double RETURNS REAL SONAME "$UDF_EXAMPLE_LIB"; + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB"; + +delimiter //; +create function f1(p1 varchar(255)) +returns varchar(255) +begin + return metaphon(p1); +end// + +create function f2(p1 varchar(255)) +returns double +begin + return myfunc_double(p1); +end// + +create function f3(p1 varchar(255)) +returns double +begin + return myfunc_int(p1); +end// + +delimiter ;// + +select f3(NULL); +select f2(NULL); +select f1(NULL); + +drop function f1; +drop function f2; +drop function f3; +drop function metaphon; +drop function myfunc_double; +drop function myfunc_int; + +# +# Bug #28921: Queries containing UDF functions are cached +# + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; +create table t1 (a char); + +set GLOBAL query_cache_size=1355776; +reset query cache; + +select metaphon('MySQL') from t1; +show status like "Qcache_hits"; +show status like "Qcache_queries_in_cache"; + +select metaphon('MySQL') from t1; +show status like "Qcache_hits"; +show status like "Qcache_queries_in_cache"; + +drop table t1; +drop function metaphon; +set GLOBAL query_cache_size=default; + +# +# Bug#28318 CREATE FUNCTION (UDF) requires a schema +# + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest; +--enable_warnings +CREATE DATABASE mysqltest; +USE mysqltest; +DROP DATABASE mysqltest; +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB"; +DROP FUNCTION metaphon; +USE test; + +# +# Bug #29804 UDF parameters don't contain correct string length +# + +CREATE TABLE const_len_bug ( + str_const varchar(4000), + result1 varchar(4000), + result2 varchar(4000) +); + +DELIMITER |; +CREATE TRIGGER check_const_len_trigger BEFORE INSERT ON const_len_bug FOR EACH ROW BEGIN + set NEW.str_const = 'bar'; + set NEW.result2 = check_const_len(NEW.str_const); +END | + +CREATE PROCEDURE check_const_len_sp (IN str_const VARCHAR(4000)) +BEGIN +DECLARE result VARCHAR(4000); +SET result = check_const_len(str_const); +insert into const_len_bug values(str_const, result, ""); +END | +DELIMITER ;| + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION check_const_len RETURNS string SONAME "$UDF_EXAMPLE_LIB"; + +CALL check_const_len_sp("foo"); + +SELECT * from const_len_bug; + +DROP FUNCTION check_const_len; +DROP PROCEDURE check_const_len_sp; +DROP TRIGGER check_const_len_trigger; +DROP TABLE const_len_bug; + + +# +# Bug #30355: Incorrect ordering of UDF results +# + +--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB +eval CREATE FUNCTION sequence RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB"; +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (4),(3),(2),(1); +INSERT INTO t2 SELECT * FROM t1; + +SELECT sequence() AS seq, a FROM t1 ORDER BY seq ASC; +SELECT sequence() AS seq, a FROM t1 ORDER BY seq DESC; + +SELECT * FROM t1 WHERE a = sequence(); +SELECT * FROM t2 WHERE a = sequence(); + +DROP FUNCTION sequence; +DROP TABLE t1,t2; + + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests. diff --git a/mysql-test/suite/pbxt/t/union.test b/mysql-test/suite/pbxt/t/union.test new file mode 100644 index 00000000000..07add11fe5f --- /dev/null +++ b/mysql-test/suite/pbxt/t/union.test @@ -0,0 +1,904 @@ +# +# Test of unions +# + +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6; +--enable_warnings + +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); + +select a,b from t1 union distinct select a,b from t2; +select a,b from t1 union all select a,b from t2; +select a,b from t1 union all select a,b from t2 order by b; +select a,b from t1 union all select a,b from t2 union select 7,'g'; +select 0,'#' union select a,b from t1 union all select a,b from t2 union select 7,'gg'; +select a,b from t1 union select a,b from t1; +select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 group by b; + +# Test alternate syntax for unions +(select a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 4; +(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1); +(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; +--error 1250 +(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; +explain extended (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; +(select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; +select found_rows(); +select sql_calc_found_rows a,b from t1 union all select a,b from t2 limit 2; +select found_rows(); + +# +# Test some error conditions with UNION +# + +explain select a,b from t1 union all select a,b from t2; + +--error 1054 +explain select xx from t1 union select 1; +--error 1222 +explain select a,b from t1 union select 1; +--error 1222 +explain select 1 union select a,b from t1 union select 1; +--error 1222 +explain select a,b from t1 union select 1 limit 0; + +--error 1221 +select a,b from t1 into outfile 'skr' union select a,b from t2; + +--error 1221 +select a,b from t1 order by a union select a,b from t2; + +--error 1221 +insert into t3 select a from t1 order by a union select a from t2; + +--error 1222 +create table t3 select a,b from t1 union select a from t2; + +--error 1222 +select a,b from t1 union select a from t2; + +--error 1222 +select * from t1 union select a from t2; + +--error 1222 +select a from t1 union select * from t2; + +--error 1234 +select * from t1 union select SQL_BUFFER_RESULT * from t2; + +# Test CREATE, INSERT and REPLACE +create table t3 select a,b from t1 union all select a,b from t2; +insert into t3 select a,b from t1 union all select a,b from t2; +# PS can't handle REPLACE ... SELECT +replace into t3 select a,b as c from t1 union all select a,b from t2; + +drop table t1,t2,t3; + +# +# Test some unions without tables +# +--error 1096 +select * union select 1; +select 1 as a,(select a union select a); +--error 1054 +(select 1) union (select 2) order by 0; +SELECT @a:=1 UNION SELECT @a:=@a+1; +--error 1054 +(SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a); +(SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2); + +# +# Test bug reported by joc@presence-pc.com +# + +CREATE TABLE t1 ( + `pseudo` char(35) NOT NULL default '', + `pseudo1` char(35) NOT NULL default '', + `same` tinyint(1) unsigned NOT NULL default '1', + PRIMARY KEY (`pseudo1`), + KEY `pseudo` (`pseudo`) +) ENGINE=MyISAM; +INSERT INTO t1 (pseudo,pseudo1,same) VALUES ('joce', 'testtt', 1),('joce', 'tsestset', 1),('dekad', 'joce', 1); +SELECT pseudo FROM t1 WHERE pseudo1='joce' UNION SELECT pseudo FROM t1 WHERE pseudo='joce'; +SELECT pseudo1 FROM t1 WHERE pseudo1='joce' UNION SELECT pseudo1 FROM t1 WHERE pseudo='joce'; +SELECT * FROM t1 WHERE pseudo1='joce' UNION SELECT * FROM t1 WHERE pseudo='joce' order by pseudo desc,pseudo1 desc; +SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION SELECT pseudo FROM t1 WHERE pseudo1='joce'; +SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION ALL SELECT pseudo FROM t1 WHERE pseudo1='joce'; +SELECT pseudo1 FROM t1 WHERE pseudo='joce' UNION SELECT 1; +drop table t1; + +create table t1 (a int); +create table t2 (a int); +insert into t1 values (1),(2),(3),(4),(5); +insert into t2 values (11),(12),(13),(14),(15); +(select * from t1 limit 2) union (select * from t2 limit 3) limit 4; +(select * from t1 limit 2) union (select * from t2 limit 3); +(select * from t1 limit 2) union (select * from t2 limit 20,3); +set SQL_SELECT_LIMIT=2; +(select * from t1 limit 1) union (select * from t2 limit 3); +set SQL_SELECT_LIMIT=DEFAULT; +drop table t1,t2; + +# +# Test error with left join +# + +CREATE TABLE t1 ( + cid smallint(5) unsigned NOT NULL default '0', + cv varchar(250) NOT NULL default '', + PRIMARY KEY (cid), + UNIQUE KEY cv (cv) +) ; +INSERT INTO t1 VALUES (8,'dummy'); +CREATE TABLE t2 ( + cid bigint(20) unsigned NOT NULL auto_increment, + cap varchar(255) NOT NULL default '', + PRIMARY KEY (cid), + KEY cap (cap) +) ; +CREATE TABLE t3 ( + gid bigint(20) unsigned NOT NULL auto_increment, + gn varchar(255) NOT NULL default '', + must tinyint(4) default NULL, + PRIMARY KEY (gid), + KEY gn (gn) +) ; +INSERT INTO t3 VALUES (1,'V1',NULL); +CREATE TABLE t4 ( + uid bigint(20) unsigned NOT NULL default '0', + gid bigint(20) unsigned default NULL, + rid bigint(20) unsigned default NULL, + cid bigint(20) unsigned default NULL, + UNIQUE KEY m (uid,gid,rid,cid), + KEY uid (uid), + KEY rid (rid), + KEY cid (cid), + KEY container (gid,rid,cid) +) ; +INSERT INTO t4 VALUES (1,1,NULL,NULL); +CREATE TABLE t5 ( + rid bigint(20) unsigned NOT NULL auto_increment, + rl varchar(255) NOT NULL default '', + PRIMARY KEY (rid), + KEY rl (rl) +) ; +CREATE TABLE t6 ( + uid bigint(20) unsigned NOT NULL auto_increment, + un varchar(250) NOT NULL default '', + uc smallint(5) unsigned NOT NULL default '0', + PRIMARY KEY (uid), + UNIQUE KEY nc (un,uc), + KEY un (un) +) ; +INSERT INTO t6 VALUES (1,'test',8); + +SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"; +SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t3.must IS NOT NULL AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"; +(SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t3.must IS NOT NULL AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test") UNION (SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"); +drop table t1,t2,t3,t4,t5,t6; + +# +# Test insert ... SELECT with UNION +# + +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); +create table t3 select a,b from t1 union select a,b from t2; +create table t4 (select a,b from t1) union (select a,b from t2) limit 2; +insert into t4 select a,b from t1 union select a,b from t2; +insert into t3 (select a,b from t1) union (select a,b from t2) limit 2; +select * from t3; +select * from t4; +drop table t1,t2,t3,t4; + +# +# Test of SQL_CALC_FOUND_ROW handling +# +create table t1 (a int); +insert into t1 values (1),(2),(3); +create table t2 (a int); +insert into t2 values (3),(4),(5); + +# Test global limits +(SELECT SQL_CALC_FOUND_ROWS * FROM t1) UNION all (SELECT * FROM t2) LIMIT 1; +select found_rows(); +(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION all (SELECT * FROM t2) LIMIT 2; +select found_rows(); + +# Test cases where found_rows() should return number of returned rows +(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION all (SELECT * FROM t2); +select found_rows(); +(SELECT SQL_CALC_FOUND_ROWS * FROM t1) UNION all (SELECT * FROM t2 LIMIT 1); +select found_rows(); +# This used to work in 4.0 but not anymore in 4.1 +--error 1064 +(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION SELECT * FROM t2 LIMIT 1; +#select found_rows(); + +# In these case found_rows() should work +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION all SELECT * FROM t2 LIMIT 2; +select found_rows(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION all SELECT * FROM t2 LIMIT 2; +select found_rows(); + +# The following examples will not be exact +SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2; +select found_rows(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 100; +select found_rows(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 100 UNION SELECT * FROM t2; +select found_rows(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION SELECT * FROM t2; +select found_rows(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION SELECT * FROM t2 LIMIT 2; +select found_rows(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2,2; +select found_rows(); +SELECT SQL_CALC_FOUND_ROWS * FROM t1 limit 2,2 UNION SELECT * FROM t2; +select found_rows(); + +# Test some limits with ORDER BY +SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a desc LIMIT 1; +(SELECT * FROM t1 ORDER by a) UNION ALL (SELECT * FROM t2 ORDER BY a) ORDER BY A desc LIMIT 4; + +# Wrong usage +--error 1234 +(SELECT * FROM t1) UNION all (SELECT SQL_CALC_FOUND_ROWS * FROM t2) LIMIT 1; + +create temporary table t1 engine=myisam select a from t1 union select a from t2; # PBXT cannot handle INSERT/SELECT on temp table +drop temporary table t1; +--error 1093 +create table t1 select a from t1 union select a from t2; +--error 1054 +select a from t1 union select a from t2 order by t2.a; +drop table t1,t2; + +# +# Problem with alias '*' (BUG #1249) +# + +select length(version()) > 1 as `*` UNION select 2; + +# +# Bug #4980: problem with explain +# + +create table t1 (a int); +insert into t1 values (0), (3), (1), (2); +explain (select * from t1) union (select * from t1) order by a; +drop table t1; +# +# Test for another bug with UNION and LEFT JOIN +# +CREATE TABLE t1 ( id int(3) unsigned default '0') ENGINE=MyISAM; +INSERT INTO t1 (id) VALUES("1"); +CREATE TABLE t2 ( id int(3) unsigned default '0', id_master int(5) default '0', text1 varchar(5) default NULL, text2 varchar(5) default NULL) ENGINE=MyISAM; +INSERT INTO t2 (id, id_master, text1, text2) VALUES("1", "1", +"foo1", "bar1"); +INSERT INTO t2 (id, id_master, text1, text2) VALUES("2", "1", +"foo2", "bar2"); +INSERT INTO t2 (id, id_master, text1, text2) VALUES("3", "1", NULL, +"bar3"); +INSERT INTO t2 (id, id_master, text1, text2) VALUES("4", "1", +"foo4", "bar4"); +SELECT 1 AS id_master, 1 AS id, NULL AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; +SELECT 1 AS id_master, 1 AS id, 'ABCDE' AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; +drop table if exists t1,t2; + +# +# Test of bug when using the same table multiple times +# +create table t1 (a int not null primary key auto_increment, b int, key(b)); +create table t2 (a int not null primary key auto_increment, b int); +insert into t1 (b) values (1),(2),(2),(3); +insert into t2 (b) values (10),(11),(12),(13); + +explain extended (select * from t1 where a=1) union (select * from t2 where a=1); +(select * from t1 where a=5) union (select * from t2 where a=1); +(select * from t1 where a=5 and a=6) union (select * from t2 where a=1); +(select t1.a,t1.b from t1,t2 where t1.a=5) union (select * from t2 where a=1); +(select * from t1 where a=1) union (select t1.a,t2.a from t1,t2 where t1.a=t2.a); +explain (select * from t1 where a=1 and b=10) union (select straight_join t1.a,t2.a from t1,t2 where t1.a=t2.a); +explain (select * from t1 where a=1) union (select * from t1 where b=1); +drop table t1,t2; +create table t1 ( id int not null auto_increment, primary key (id) ,user_name text ); +create table t2 ( id int not null auto_increment, primary key (id) ,group_name text ); +create table t3 ( id int not null auto_increment, primary key (id) ,user_id int ,index user_idx (user_id) ,foreign key (user_id) references t1(id) ,group_id int ,index group_idx (group_id) ,foreign key (group_id) references t2(id) ); # PBXT: Correct table references! +insert into t1 (user_name) values ('Tester'); +insert into t2 (group_name) values ('Group A'); +insert into t2 (group_name) values ('Group B'); +insert into t3 (user_id, group_id) values (1,1); +select 1 'is_in_group', a.user_name, c.group_name, b.id from t1 a, t3 b, t2 c where a.id = b.user_id and b.group_id = c.id UNION select 0 'is_in_group', a.user_name, c.group_name, null from t1 a, t2 c; +drop table t3, t2, t1; + +# +# fix_fields problem +# +create table t1 (mat_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, matintnum CHAR(6) NOT NULL, test MEDIUMINT UNSIGNED NULL); +create table t2 (mat_id MEDIUMINT UNSIGNED NOT NULL, pla_id MEDIUMINT UNSIGNED NOT NULL); +insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd', 4), (NULL, 'e', 5), (NULL, 'f', 6), (NULL, 'g', 7), (NULL, 'h', 8), (NULL, 'i', 9); +insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105); +SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id union SELECT 0, 0; +drop table t1, t2; + +# +# types conversions +# +create table t1 SELECT "a" as a UNION select "aa" as a; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT 12 as a UNION select "aa" as a; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT 12 as a UNION select 12.2 as a; +select * from t1; +show create table t1; +drop table t1; + +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob, tx text); +insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'testc', 'testv', 'tetetetetest', 'teeeeeeeeeeeest'); + +create table t1 SELECT it2 from t2 UNION select it1 from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT it2 from t2 UNION select i from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT i from t2 UNION select f from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT f from t2 UNION select d from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT ib from t2 UNION select f from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT ib from t2 UNION select d from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT f from t2 UNION select y from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT f from t2 UNION select da from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT y from t2 UNION select da from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT y from t2 UNION select dt from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT da from t2 UNION select dt from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT dt from t2 UNION select trim(sc) from t2; +select trim(dt) from t1; +show create table t1; +drop table t1; +create table t1 SELECT dt from t2 UNION select sv from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT sc from t2 UNION select sv from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT dt from t2 UNION select b from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT sv from t2 UNION select b from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT i from t2 UNION select d from t2 UNION select b from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT sv from t2 UNION select tx from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT b from t2 UNION select tx from t2; +select * from t1; +show create table t1; +drop table t1,t2; +create table t1 select 1 union select -1; +select * from t1; +show create table t1; +drop table t1; +-- error 1267 +create table t1 select _latin1"test" union select _latin2"testt" ; +create table t1 select _latin2"test" union select _latin2"testt" ; +show create table t1; +drop table t1; + +# +# conversion memory->disk table +# +create table t1 (s char(200)); +insert into t1 values (repeat("1",200)); +create table t2 select * from t1; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +set local tmp_table_size=1024; +select count(*) from (select * from t1 union all select * from t2 order by 1) b; +select count(*) from t1; +select count(*) from t2; +drop table t1,t2; +set local tmp_table_size=default; + +# +# slow logging +# +create table t1 (a int, index (a), b int); +insert t1 values (1,1),(2,2),(3,3),(4,4),(5,5); +insert t1 select a+1, a+b from t1; +insert t1 select a+1, a+b from t1; +insert t1 select a+1, a+b from t1; +insert t1 select a+1, a+b from t1; +insert t1 select a+1, a+b from t1; +FLUSH STATUS; +show status like 'Slow_queries'; +select count(*) from t1 where a=7; +show status like 'Slow_queries'; +select count(*) from t1 where b=13; +show status like 'Slow_queries'; +select count(*) from t1 where b=13 union select count(*) from t1 where a=7; +show status like 'Slow_queries'; +select count(*) from t1 where a=7 union select count(*) from t1 where b=13; +show status like 'Slow_queries'; +# additional test for examined rows +flush status; +select a from t1 where b not in (1,2,3) union select a from t1 where b not in (4,5,6); +show status like 'Slow_queries'; +drop table t1; + +# +# Column 'name' cannot be null (error with union and left join) (bug #2508) +# +create table t1 ( RID int(11) not null default '0', IID int(11) not null default '0', nada varchar(50) not null,NAME varchar(50) not null,PHONE varchar(50) not null) engine=MyISAM; +insert into t1 ( RID,IID,nada,NAME,PHONE) values (1, 1, 'main', 'a', '111'), (2, 1, 'main', 'b', '222'), (3, 1, 'main', 'c', '333'), (4, 1, 'main', 'd', '444'), (5, 1, 'main', 'e', '555'), (6, 2, 'main', 'c', '333'), (7, 2, 'main', 'd', '454'), (8, 2, 'main', 'e', '555'), (9, 2, 'main', 'f', '666'), (10, 2, 'main', 'g', '777'); +select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 A left join t1 B on A.NAME = B.NAME and B.IID = 2 where A.IID = 1 and (A.PHONE <> B.PHONE or B.NAME is null) union select A.NAME, A.PHONE, B.NAME, B.PHONE from t1 B left join t1 A on B.NAME = A.NAME and A.IID = 1 where B.IID = 2 and (A.PHONE <> B.PHONE or A.NAME is null); +drop table t1; + +# +# Bug #2809 (UNION fails on MyIsam tables when index on second column from +# same table) +# +create table t1 (col1 tinyint unsigned, col2 tinyint unsigned); +insert into t1 values (1,2),(3,4),(5,6),(7,8),(9,10); +select col1 n from t1 union select col2 n from t1 order by n; +alter table t1 add index myindex (col2); +select col1 n from t1 union select col2 n from t1 order by n; +drop table t1; + +# +# Incorrect handling of UNION ALL (Bug #1428) +# +create table t1 (i int); +insert into t1 values (1); +select * from t1 UNION select * from t1; +select * from t1 UNION ALL select * from t1; +select * from t1 UNION select * from t1 UNION ALL select * from t1; +drop table t1; +select 1 as a union all select 1 union all select 2 union select 1 union all select 2; +set sql_select_limit=1; +select 1 union select 2; +(select 1) union (select 2); +(select 1) union (select 2) union (select 3) limit 2; +set sql_select_limit=default; + +# +# ORDER with LIMIT +# +create table t1 (a int); +insert into t1 values (100), (1); +create table t2 (a int); +insert into t2 values (100); +select a from t1 union select a from t2 order by a; +SET SQL_SELECT_LIMIT=1; +select a from t1 union select a from t2 order by a; +drop table t1, t2; +set sql_select_limit=default; + +# +# nonexisting column in global ORDER BY +# +CREATE TABLE t1 (i int(11) default NULL,c char(1) default NULL,KEY i (i)); +CREATE TABLE t2 (i int(11) default NULL,c char(1) default NULL,KEY i (i)); +--error 1054 +explain (select * from t1) union (select * from t2) order by not_existing_column; +drop table t1, t2; + +# +# length detecting +# +CREATE TABLE t1 (uid int(1)); +INSERT INTO t1 SELECT 150; +SELECT 'a' UNION SELECT uid FROM t1; +drop table t1; + +# +# parser stack overflow +# +CREATE TABLE t1 ( ID1 int(10) unsigned NOT NULL DEFAULT '0' , ID2 datetime NOT NULL DEFAULT '0000-00-00 00:00:00' , DATA1 varchar(10) , DATA2 double(5,4) , DATA3 datetime , PRIMARY KEY (ID1,ID2)); + +CREATE TABLE t2 ( ID int(3) unsigned NOT NULL DEFAULT '0' , DATA1 timestamp DEFAULT '0000-00-00 00:00:00' , PRIMARY KEY (ID)); +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1) UNION +(SELECT * FROM t1 AS PARTITIONED, t2 AS +PARTITIONED_B WHERE PARTITIONED_B.ID=PARTITIONED.ID1); +drop table t1,t2; + +# +# merging ENUM and SET fields in one UNION +# +create table t1 (a ENUM('Yes', 'No') NOT NULL); +create table t2 (a ENUM('aaa', 'bbb') NOT NULL); +insert into t1 values ('No'); +insert into t2 values ('bbb'); +create table t3 (a SET('Yes', 'No') NOT NULL); +create table t4 (a SET('aaa', 'bbb') NOT NULL); +insert into t3 values (1); +insert into t4 values (3); +select "1" as a union select a from t1; +select a as a from t1 union select "1"; +select a as a from t2 union select a from t1; +select "1" as a union select a from t3; +select a as a from t3 union select "1"; +select a as a from t4 union select a from t3; +select a as a from t1 union select a from t4; +drop table t1,t2,t3,t4; + +# +# Bug #6139 UNION doesn't understand collate in the column of second select +# +create table t1 as +(select _latin1'test') union +(select _latin1'TEST') union +(select _latin1'TeST'); +show create table t1; +select count(*) from t1; +drop table t1; + +create table t1 as +(select _latin1'test' collate latin1_bin) union +(select _latin1'TEST') union +(select _latin1'TeST'); +show create table t1; +select count(*) from t1; +drop table t1; + +create table t1 as +(select _latin1'test') union +(select _latin1'TEST' collate latin1_bin) union +(select _latin1'TeST'); +show create table t1; +select count(*) from t1; +drop table t1; + +create table t1 as +(select _latin1'test') union +(select _latin1'TEST') union +(select _latin1'TeST' collate latin1_bin); +show create table t1; +select count(*) from t1; +drop table t1; + +create table t2 ( +a char character set latin1 collate latin1_swedish_ci, +b char character set latin1 collate latin1_german1_ci); +--error 1271 +create table t1 as +(select a from t2) union +(select b from t2); +create table t1 as +(select a collate latin1_german1_ci from t2) union +(select b from t2); +show create table t1; +drop table t1; +create table t1 as +(select a from t2) union +(select b collate latin1_german1_ci from t2); +show create table t1; +drop table t1; +create table t1 as +(select a from t2) union +(select b from t2) union +(select 'c' collate latin1_german1_ci from t2); +show create table t1; +drop table t1; +drop table t2; + +# +# Bug 6931: Date Type column problem when using UNION-Table. +# +create table t1(a1 int, f1 char(10)); +create table t2 +select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a +union +select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a +order by f2, a1; +show columns from t2; +drop table t1, t2; + +create table t1 (f1 int); +create table t2 (f1 int, f2 int ,f3 date); +create table t3 (f1 int, f2 char(10)); +create table t4 +( + select t2.f3 as sdate + from t1 + left outer join t2 on (t1.f1 = t2.f1) + inner join t3 on (t2.f2 = t3.f1) + order by t1.f1, t3.f1, t2.f3 +) +union +( + select cast('2004-12-31' as date) as sdate + from t1 + left outer join t2 on (t1.f1 = t2.f1) + inner join t3 on (t2.f2 = t3.f1) + group by t1.f1 + order by t1.f1, t3.f1, t2.f3 +) +order by sdate; +show columns from t4; +drop table t1, t2, t3, t4; + +# +# Bug #2435 UNION with parentheses not supported +# +create table t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +select * from ((select * from t1 limit 1)) a; +select * from ((select * from t1 limit 1) union (select * from t1 limit 1)) a; +select * from ((select * from t1 limit 1) union (select * from t1 limit 1) union (select * from t1 limit 1)) a; +select * from ((((select * from t1))) union (select * from t1) union (select * from t1)) a; +select * from ((select * from t1) union (((select * from t1))) union (select * from t1)) a; +drop table t1; + +# +# Bugs#6519 UNION with collation binary and latin1_swedish_ci fails +# +set @val:=6; +select concat('value is: ', @val) union select 'some text'; + +# +# Bug#15949 union + illegal mix of collations (IMPLICIT + COERCIBLE) +# +select concat(_latin1'a', _ascii'b' collate ascii_bin); +create table t1 (foo varchar(100)) collate ascii_bin; +insert into t1 (foo) values ("foo"); +select foo from t1 union select 'bar' as foo from dual; +drop table t1; + +# +# Enum merging test +# +CREATE TABLE t1 ( + a ENUM('ä','ö','ü') character set utf8 not null default 'ü', + b ENUM("one", "two") character set utf8, + c ENUM("one", "two") +); +show create table t1; +insert into t1 values ('ä', 'one', 'one'), ('ö', 'two', 'one'), ('ü', NULL, NULL); +create table t2 select NULL union select a from t1; +show columns from t2; +drop table t2; +create table t2 select a from t1 union select NULL; +show columns from t2; +drop table t2; +create table t2 select a from t1 union select a from t1; +show columns from t2; +drop table t2; +create table t2 select a from t1 union select c from t1; +drop table t2; +create table t2 select a from t1 union select b from t1; +show columns from t2; +drop table t2, t1; + +# +# Bug #14216: UNION + DECIMAL wrong values in result +# +create table t1 (f1 decimal(60,25), f2 decimal(60,25)); +insert into t1 values (0.0,0.0); +select f1 from t1 union all select f2 from t1; +select 'XXXXXXXXXXXXXXXXXXXX' as description, f1 from t1 +union all +select 'YYYYYYYYYYYYYYYYYYYY' as description, f2 from t1; +drop table t1; +create table t1 (f1 decimal(60,24), f2 decimal(60,24)); +insert into t1 values (0.0,0.0); +select f1 from t1 union all select f2 from t1; +select 'XXXXXXXXXXXXXXXXXXXX' as description, f1 from t1 +union all +select 'YYYYYYYYYYYYYYYYYYYY' as description, f2 from t1; +drop table t1; + +# +# Test that union with VARCHAR produces dynamic row tables +# + +create table t1 (a varchar(5)); +create table t2 select * from t1 union select 'abcdefghijkl'; +show create table t2; +select row_format from information_schema.TABLES where table_schema="test" and table_name="t2"; +alter table t2 ROW_FORMAT=fixed; +show create table t2; +drop table t1,t2; + +# +# correct conversion long string to TEXT (BUG#10025) +# + +CREATE TABLE t1 (a mediumtext); +CREATE TABLE t2 (b varchar(20)); +INSERT INTO t1 VALUES ('a'),('b'); +SELECT left(a,100000000) FROM t1 UNION SELECT b FROM t2; +create table t3 SELECT left(a,100000000) FROM t1 UNION SELECT b FROM t2; +show create table t3; +drop tables t1,t2,t3; + +# +# Extended fix to Bug#10025 - the test above should result to mediumtext +# and the one below to longtext. Earlier above test resulted to longtext +# type also. +# + +CREATE TABLE t1 (a longtext); +CREATE TABLE t2 (b varchar(20)); +INSERT INTO t1 VALUES ('a'),('b'); +SELECT left(a,100000000) FROM t1 UNION SELECT b FROM t2; +create table t3 SELECT left(a,100000000) FROM t1 UNION SELECT b FROM t2; +show create table t3; +drop tables t1,t2,t3; + +# +# Testing here that mediumtext converts into longtext if the result +# exceeds mediumtext maximum length +# + +CREATE TABLE t1 (a mediumtext); +CREATE TABLE t2 (b varchar(20)); +INSERT INTO t1 VALUES ('a'); +CREATE TABLE t3 SELECT REPEAT(a,20000000) AS a FROM t1 UNION SELECT b FROM t2; +SHOW CREATE TABLE t3; +DROP TABLES t1,t3; +CREATE TABLE t1 (a tinytext); +INSERT INTO t1 VALUES ('a'); +CREATE TABLE t3 SELECT REPEAT(a,2) AS a FROM t1 UNION SELECT b FROM t2; +SHOW CREATE TABLE t3; +DROP TABLES t1,t3; +CREATE TABLE t1 (a mediumtext); +INSERT INTO t1 VALUES ('a'); +CREATE TABLE t3 SELECT REPEAT(a,2) AS a FROM t1 UNION SELECT b FROM t2; +SHOW CREATE TABLE t3; +DROP TABLES t1,t3; +CREATE TABLE t1 (a tinyblob); +INSERT INTO t1 VALUES ('a'); +CREATE TABLE t3 SELECT REPEAT(a,2) AS a FROM t1 UNION SELECT b FROM t2; +SHOW CREATE TABLE t3; +DROP TABLES t1,t2,t3; + +# +# Bug #10032 Bug in parsing UNION with ORDER BY when one node does not use FROM +# + +create table t1 ( id int not null auto_increment, primary key (id), col1 int); +insert into t1 (col1) values (2),(3),(4),(5),(6); +select 99 union all select id from t1 order by 1; +select id from t1 union all select 99 order by 1; +drop table t1; + +# End of 4.1 tests + +# +# Bug#12185: Data type aggregation may produce wrong result +# +create table t1(f1 char(1), f2 char(5), f3 binary(1), f4 binary(5), f5 timestamp, f6 varchar(1) character set utf8 collate utf8_general_ci, f7 text); +create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1; +show create table t2; +drop table t1, t2; + +# +# Bug#18175: Union select over 129 tables with a sum function fails. +# +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)) union +(select avg(1)) union (select avg(1)) union (select avg(1)); + +# +# Bug #16881: password() and union select +# (The issue was poor handling of character set aggregation.) +# +select _utf8'12' union select _latin1'12345'; + + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.0 tests diff --git a/mysql-test/suite/pbxt/t/update.test b/mysql-test/suite/pbxt/t/update.test new file mode 100644 index 00000000000..edc99e304a7 --- /dev/null +++ b/mysql-test/suite/pbxt/t/update.test @@ -0,0 +1,314 @@ +# +# test of updating of keys +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1 (a int auto_increment , primary key (a)); +insert into t1 values (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +update t1 set a=a+10 where a > 34; +update t1 set a=a+100 where a > 0; + +# Some strange updates to test some otherwise unused code +update t1 set a=a+100 where a=1 and a=2; +--error 1054 +update t1 set a=b+100 where a=1 and a=2; +--error 1054 +update t1 set a=b+100 where c=1 and a=2; +--error 1054 +update t1 set d=a+100 where a=1; +select * from t1; +drop table t1; + +CREATE TABLE t1 + ( + place_id int (10) unsigned NOT NULL, + shows int(10) unsigned DEFAULT '0' NOT NULL, + ishows int(10) unsigned DEFAULT '0' NOT NULL, + ushows int(10) unsigned DEFAULT '0' NOT NULL, + clicks int(10) unsigned DEFAULT '0' NOT NULL, + iclicks int(10) unsigned DEFAULT '0' NOT NULL, + uclicks int(10) unsigned DEFAULT '0' NOT NULL, + ts timestamp, + PRIMARY KEY (place_id,ts) + ); + +INSERT INTO t1 (place_id,shows,ishows,ushows,clicks,iclicks,uclicks,ts) +VALUES (1,0,0,0,0,0,0,20000928174434); +UPDATE t1 SET shows=shows+1,ishows=ishows+1,ushows=ushows+1,clicks=clicks+1,iclicks=iclicks+1,uclicks=uclicks+1 WHERE place_id=1 AND ts>="2000-09-28 00:00:00"; +select place_id,shows from t1; +drop table t1; + +# +# Test bug with update reported by Jan Legenhausen +# + +CREATE TABLE t1 ( + lfdnr int(10) unsigned NOT NULL default '0', + ticket int(10) unsigned NOT NULL default '0', + client varchar(255) NOT NULL default '', + replyto varchar(255) NOT NULL default '', + subject varchar(100) NOT NULL default '', + timestamp int(10) unsigned NOT NULL default '0', + tstamp timestamp NOT NULL, + status int(3) NOT NULL default '0', + type varchar(15) NOT NULL default '', + assignment int(10) unsigned NOT NULL default '0', + fupcount int(4) unsigned NOT NULL default '0', + parent int(10) unsigned NOT NULL default '0', + activity int(10) unsigned NOT NULL default '0', + priority tinyint(1) unsigned NOT NULL default '1', + cc varchar(255) NOT NULL default '', + bcc varchar(255) NOT NULL default '', + body text NOT NULL, + comment text, + header text, + PRIMARY KEY (lfdnr), + KEY k1 (timestamp), + KEY k2 (type), + KEY k3 (parent), + KEY k4 (assignment), + KEY ticket (ticket) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES (773,773,'','','',980257344,20010318180652,0,'Open',10,0,0,0,1,'','','','',''); + +alter table t1 change lfdnr lfdnr int(10) unsigned not null auto_increment; +update t1 set status=1 where type='Open'; +select status from t1; +drop table t1; + +# +# Test of ORDER BY +# + +create table t1 (a int not null, b int not null, key (a)); +insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); +SET @tmp=0; +update t1 set b=(@tmp:=@tmp+1) order by a; +update t1 set b=99 where a=1 order by b asc limit 1; +select * from t1 order by a,b; +update t1 set b=100 where a=1 order by b desc limit 2; +update t1 set a=a+10+b where a=1 order by b; +select * from t1 order by a,b; +create table t2 (a int not null, b int not null); +insert into t2 values (1,1),(1,2),(1,3); +update t1 set b=(select distinct 1 from (select * from t2) a); +drop table t1,t2; + +# +# Test with limit (Bug #393) +# + +CREATE TABLE t1 ( + `id_param` smallint(3) unsigned NOT NULL default '0', + `nom_option` char(40) NOT NULL default '', + `valid` tinyint(1) NOT NULL default '0', + KEY `id_param` (`id_param`,`nom_option`) + ) ENGINE=MyISAM; + +INSERT INTO t1 (id_param,nom_option,valid) VALUES (185,'600x1200',1); + +UPDATE t1 SET nom_option='test' WHERE id_param=185 AND nom_option='600x1200' AND valid=1 LIMIT 1; +select * from t1; +drop table t1; + +# +# Multi table update test from bugs +# + +create table t1 (F1 VARCHAR(30), F2 VARCHAR(30), F3 VARCHAR(30), cnt int, groupid int, KEY groupid_index (groupid)); + +insert into t1 (F1,F2,F3,cnt,groupid) values ('0','0','0',1,6), +('0','1','2',1,5), ('0','2','0',1,3), ('1','0','1',1,2), +('1','2','1',1,1), ('1','2','2',1,1), ('2','0','1',2,4), +('2','2','0',1,7); +delete from m1 using t1 m1,t1 m2 where m1.groupid=m2.groupid and (m1.cnt < m2.cnt or m1.cnt=m2.cnt and m1.F3>m2.F3); +select * from t1; +drop table t1; + +# +# Bug#5553 - Multi table UPDATE IGNORE fails on duplicate keys +# + +CREATE TABLE t1 ( + `colA` int(10) unsigned NOT NULL auto_increment, + `colB` int(11) NOT NULL default '0', + PRIMARY KEY (`colA`) +); +INSERT INTO t1 VALUES (4433,5424); +CREATE TABLE t2 ( + `colC` int(10) unsigned NOT NULL default '0', + `colA` int(10) unsigned NOT NULL default '0', + `colD` int(10) unsigned NOT NULL default '0', + `colE` int(10) unsigned NOT NULL default '0', + `colF` int(10) unsigned NOT NULL default '0', + PRIMARY KEY (`colC`,`colA`,`colD`,`colE`) +); +INSERT INTO t2 VALUES (3,4433,10005,495,500); +INSERT INTO t2 VALUES (3,4433,10005,496,500); +INSERT INTO t2 VALUES (3,4433,10009,494,500); +INSERT INTO t2 VALUES (3,4433,10011,494,500); +INSERT INTO t2 VALUES (3,4433,10005,497,500); +INSERT INTO t2 VALUES (3,4433,10013,489,500); +INSERT INTO t2 VALUES (3,4433,10005,494,500); +INSERT INTO t2 VALUES (3,4433,10005,493,500); +INSERT INTO t2 VALUES (3,4433,10005,492,500); +UPDATE IGNORE t2,t1 set t2.colE = t2.colE + 1,colF=0 WHERE t1.colA = t2.colA AND (t1.colB & 4096) > 0 AND (colE + 1) < colF; +SELECT * FROM t2; +DROP TABLE t1; +DROP TABLE t2; + +# +# Bug #6054 +# +create table t1 (c1 int, c2 char(6), c3 int); +create table t2 (c1 int, c2 char(6)); +insert into t1 values (1, "t1c2-1", 10), (2, "t1c2-2", 20); +update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1"; +update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1" where t1.c3 = 10; +drop table t1, t2; + +# +# Bug #8057 +# +create table t1 (id int not null auto_increment primary key, id_str varchar(32)); +insert into t1 (id_str) values ("test"); +update t1 set id_str = concat(id_str, id) where id = last_insert_id(); +select * from t1; +drop table t1; + +# +# Bug #8942: a problem with update and partial key part +# + +create table t1 (a int, b char(255), key(a, b(20))); +insert into t1 values (0, '1'); +update t1 set b = b + 1 where a = 0; +select * from t1; +drop table t1; + +# BUG#9103 "Erroneous data truncation warnings on multi-table updates" +create table t1 (a int, b varchar(10), key b(b(5))) engine=myisam; +create table t2 (a int, b varchar(10)) engine=myisam; +insert into t1 values ( 1, 'abcd1e'); +insert into t1 values ( 2, 'abcd2e'); +insert into t2 values ( 1, 'abcd1e'); +insert into t2 values ( 2, 'abcd2e'); +analyze table t1,t2; +update t1, t2 set t1.a = t2.a where t2.b = t1.b; +show warnings; +drop table t1, t2; + +# +# Bug #11868 Update with subquery with ref built with a key from the updated +# table crashes server +# +create table t1(f1 int, f2 int); +create table t2(f3 int, f4 int); +create index idx on t2(f3); +insert into t1 values(1,0),(2,0); +insert into t2 values(1,1),(2,2); +UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); +select * from t1; +drop table t1,t2; + +# +# Bug #13180 sometimes server accepts sum func in update/delete where condition +# +create table t1(f1 int); +select DATABASE(); +--error 1111 +update t1 set f1=1 where count(*)=1; +select DATABASE(); +--error 1111 +delete from t1 where count(*)=1; +drop table t1; + +# BUG#12915: Optimize "DELETE|UPDATE ... ORDER BY ... LIMIT n" to use an index +create table t1 ( a int, b int default 0, index (a) ); +insert into t1 (a) values (0),(0),(0),(0),(0),(0),(0),(0); + +flush status; +select a from t1 order by a limit 1; +show status like 'handler_read%'; + +flush status; +update t1 set a=9999 order by a limit 1; +analyze table t1; # PBXT required to get a consistent order in the update below +update t1 set b=9999 order by a desc limit 1; # PBXT Update last updated field +show status like 'handler_read%'; + +flush status; +delete from t1 order by a limit 1; +show status like 'handler_read%'; + +flush status; +delete from t1 order by a desc limit 1; +show status like 'handler_read%'; + +alter table t1 disable keys; + +flush status; +delete from t1 order by a limit 1; +show status like 'handler_read%'; + +select * from t1; +update t1 set a=a+10,b=1 order by a limit 3; +update t1 set a=a+11,b=2 order by a limit 3; +update t1 set a=a+12,b=3 order by a limit 3; +select * from t1 order by a; + +drop table t1; + +# +# Bug#14186 select datefield is null not updated +# +create table t1 (f1 date not null); +insert into t1 values('2000-01-01'),('0000-00-00'); +update t1 set f1='2002-02-02' where f1 is null; +select * from t1; +drop table t1; + +# +# Bug#15028 Multitable update returns different numbers of matched rows +# depending on table order +create table t1 (f1 int); +create table t2 (f2 int); +insert into t1 values(1),(2); +insert into t2 values(1),(1); +--enable_info +update t1,t2 set f1=3,f2=3 where f1=f2 and f1=1; +--disable_info +update t2 set f2=1; +update t1 set f1=1 where f1=3; +--enable_info +update t2,t1 set f1=3,f2=3 where f1=f2 and f1=1; +--disable_info +drop table t1,t2; + + +# BUG#15935 +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, filler1 char(200), filler2 char(200), key(a)); +insert into t2 select A.a + 10*B.a, 'filler','filler' from t1 A, t1 B; +flush status; +update t2 set a=3 where a=2; +show status like 'handler_read%'; +drop table t1, t2; + +# +# Bug #16510 Updating field named like '*name' caused server crash +# +create table t1(f1 int, `*f2` int); +insert into t1 values (1,1); +update t1 set `*f2`=1; +drop table t1; + +--disable_query_log +drop database pbxt; +--enable_query_log +# End of 4.1 tests diff --git a/mysql-test/suite/pbxt/t/user_var.test b/mysql-test/suite/pbxt/t/user_var.test new file mode 100644 index 00000000000..f965913ef67 --- /dev/null +++ b/mysql-test/suite/pbxt/t/user_var.test @@ -0,0 +1,228 @@ +# Initialise +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +--error 1054 +set @a := foo; +set @a := connection_id() + 3; +select @a - connection_id(); + +set @b := 1; +select @b; + +# Check using and setting variables with SELECT DISTINCT + +CREATE TABLE t1 ( i int not null, v int not null,index (i)); +insert into t1 values (1,1),(1,3),(2,1); +create table t2 (i int not null, unique (i)); +insert into t2 select distinct i from t1; +select * from t2; +select distinct t2.i,@vv1:=if(sv1.i,1,0),@vv2:=if(sv2.i,1,0),@vv3:=if(sv3.i,1,0), @vv1+@vv2+@vv3 from t2 left join t1 as sv1 on sv1.i=t2.i and sv1.v=1 left join t1 as sv2 on sv2.i=t2.i and sv2.v=2 left join t1 as sv3 on sv3.i=t2.i and sv3.v=3; +explain select * from t1 where i=@vv1; +select @vv1,i,v from t1 where i=@vv1; +explain select * from t1 where @vv1:=@vv1+1 and i=@vv1; +explain select @vv1:=i from t1 where i=@vv1; +explain select * from t1 where i=@vv1; +drop table t1,t2; + +# Check types of variables +set @a=0,@b=0; +select @a:=10, @b:=1, @a > @b, @a < @b; +# Note that here a and b will be avaluated as number +select @a:="10", @b:="1", @a > @b, @a < @b; +# Note that here a and b will be avaluated as strings +select @a:=10, @b:=2, @a > @b, @a < @b; +select @a:="10", @b:="2", @a > @b, @a < @b; + +# Fixed bug #1194 +select @a:=1; +select @a, @a:=1; + +create table t1 (id int, d double, c char(10)); +insert into t1 values (1,2.0, "test"); +select @c:=0; +update t1 SET id=(@c:=@c+1); +select @c; +select @c:=0; +update t1 set id=(@c:=@c+1); +select @c; +select @c:=0; +select @c:=@c+1; +select @d,(@d:=id),@d from t1; +select @e,(@e:=d),@e from t1; +select @f,(@f:=c),@f from t1; +set @g=1; +select @g,(@g:=c),@g from t1; +select @c, @d, @e, @f; +select @d:=id, @e:=id, @f:=id, @g:=@id from t1; +select @c, @d, @e, @f, @g; +drop table t1; + +# just for fun :) +select @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b, @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b; + +# +# bug#1739 +# Item_func_set_user_var sets update_query_id, Item_func_get_user_var checks it +# +create table t1 (i int not null); +insert t1 values (1),(2),(2),(3),(3),(3); +select @a:=0; select @a, @a:=@a+count(*), count(*), @a from t1 group by i; +select @a:=0; select @a+0, @a:=@a+0+count(*), count(*), @a+0 from t1 group by i; + +set @a=0; +select @a,@a:="hello",@a,@a:=3,@a,@a:="hello again" from t1 group by i; +select @a,@a:="hello",@a,@a:=3,@a,@a:="hello again" from t1 group by i; +drop table t1; + +# +# Bug #2244: User variables didn't copy collation and derivation +# attributes from values they were initialized to. +# + +set @a=_latin2'test'; +select charset(@a),collation(@a),coercibility(@a); +select @a=_latin2'TEST'; +select @a=_latin2'TEST' collate latin2_bin; + +set @a=_latin2'test' collate latin2_general_ci; +select charset(@a),collation(@a),coercibility(@a); +select @a=_latin2'TEST'; +select @a=_latin2'TEST' collate latin2_bin; + +# +# Check the same invoking Item_set_user_var +# +select charset(@a:=_latin2'test'); +select collation(@a:=_latin2'test'); +select coercibility(@a:=_latin2'test'); +select collation(@a:=_latin2'test' collate latin2_bin); +select coercibility(@a:=_latin2'test' collate latin2_bin); +select (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST'; +select charset(@a),collation(@a),coercibility(@a); +select (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST' collate latin2_general_ci; + +# +# Bug #6321 strange error: +# string function FIELD(<uservariable content NULL>, ...) +# +set @var= NULL ; +select FIELD( @var,'1it','Hit') as my_column; + +# +# Bug#9425 A user variable doesn't always have implicit coercibility +# +select @v, coercibility(@v); +set @v1=null, @v2=1, @v3=1.1, @v4=now(); +select coercibility(@v1),coercibility(@v2),coercibility(@v3),coercibility(@v4); + +# +# Bug #9286 SESSION/GLOBAL should be disallowed for user variables +# +--error 1064 +set session @honk=99; +--error 1382 +set one_shot @honk=99; + +# +# Bug #10724 @@local not preserved in column name of select +# +# The value doesn't actually matter, we just care about the column name +--replace_column 1 # +select @@local.max_allowed_packet; +--replace_column 1 # +select @@session.max_allowed_packet; +--replace_column 1 # +select @@global.max_allowed_packet; +--replace_column 1 # +select @@max_allowed_packet; +--replace_column 1 # +select @@Max_Allowed_Packet; +--replace_column 1 # +select @@version; +--replace_column 1 # +select @@global.version; + +--echo End of 4.1 tests + +# Bug #6598: problem with cast(NULL as signed integer); +# + +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= cast(NULL as signed integer); +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= concat(NULL); +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var=1; +set @first_var= cast(NULL as CHAR); +create table t1 select @first_var; +show create table t1; +drop table t1; + +# +# Bug #7498 User variable SET saves SIGNED BIGINT as UNSIGNED BIGINT +# + +# First part, set user var to large number and select it +set @a=18446744071710965857; +select @a; + +# Second part, set user var from large number in table +# then select it +CREATE TABLE `bigfailure` ( + `afield` BIGINT UNSIGNED NOT NULL +); +INSERT INTO `bigfailure` VALUES (18446744071710965857); +SELECT * FROM bigfailure; +select * from (SELECT afield FROM bigfailure) as b; +select * from bigfailure where afield = (SELECT afield FROM bigfailure); +select * from bigfailure where afield = 18446744071710965857; +# This is fixed in 5.0, to be uncommented there +#select * from bigfailure where afield = '18446744071710965857'; +select * from bigfailure where afield = 18446744071710965856+1; + +SET @a := (SELECT afield FROM bigfailure); +SELECT @a; +SET @a := (select afield from (SELECT afield FROM bigfailure) as b); +SELECT @a; +SET @a := (select * from bigfailure where afield = (SELECT afield FROM bigfailure)); +SELECT @a; + +drop table bigfailure; + +# +# Bug#16861: User defined variable can have a wrong value if a tmp table was +# used. +# +create table t1(f1 int, f2 int); +insert into t1 values (1,2),(2,3),(3,1); +select @var:=f2 from t1 group by f1 order by f2 desc limit 1; +select @var; +create table t2 as select @var:=f2 from t1 group by f1 order by f2 desc limit 1; +select * from t2; +select @var; +drop table t1,t2; + +# +# Bug#19024 - SHOW COUNT(*) WARNINGS not return Errors +# +--error 1064 +insert into city 'blah'; +SHOW COUNT(*) WARNINGS; +SHOW COUNT(*) ERRORS; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/view_grant.test b/mysql-test/suite/pbxt/t/view_grant.test new file mode 100644 index 00000000000..6a105da61f8 --- /dev/null +++ b/mysql-test/suite/pbxt/t/view_grant.test @@ -0,0 +1,1224 @@ +# Can't test with embedded server +-- source include/not_embedded.inc + +--disable_warnings +drop database if exists mysqltest; +drop view if exists v1,v2,v3; +--enable_warnings + + +# simple test of grants +grant create view on test.* to test@localhost; +show grants for test@localhost; +revoke create view on test.* from test@localhost; +show grants for test@localhost; +# The grant above creates a new user test@localhost, delete it +drop user test@localhost; + +# grant create view test +# +connect (root,localhost,root,,test); +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int, b int); +create table mysqltest.t2 (a int, b int); + +grant select on mysqltest.t1 to mysqltest_1@localhost; +grant create view,select on test.* to mysqltest_1@localhost; + +connect (user1,localhost,mysqltest_1,,test); +connection user1; + +-- error ER_SPECIFIC_ACCESS_DENIED_ERROR +create definer=root@localhost view v1 as select * from mysqltest.t1; +create view v1 as select * from mysqltest.t1; +# try to modify view without DROP privilege on it +-- error 1142 +alter view v1 as select * from mysqltest.t1; +-- error 1142 +create or replace view v1 as select * from mysqltest.t1; +# no CRETE VIEW privilege +-- error 1142 +create view mysqltest.v2 as select * from mysqltest.t1; +# no SELECT privilege +-- error 1142 +create view v2 as select * from mysqltest.t2; + +connection root; +# check view definer information +show create view v1; + +grant create view,drop,select on test.* to mysqltest_1@localhost; + +connection user1; +# following 'use' command is workaround of bug #9582 and should be removed +# when that bug will be fixed +use test; +alter view v1 as select * from mysqltest.t1; +create or replace view v1 as select * from mysqltest.t1; + +connection root; +revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; +revoke all privileges on test.* from mysqltest_1@localhost; + +drop database mysqltest; +drop view test.v1; + +# +# grants per columns +# +# MERGE algorithm +--disable_warnings +create database mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int, b int); +create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; +grant select (c) on mysqltest.v1 to mysqltest_1@localhost; + +connection user1; +select c from mysqltest.v1; +# there are no privileges on column 'd' +-- error 1143 +select d from mysqltest.v1; + +connection root; +revoke all privileges on mysqltest.v1 from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +drop database mysqltest; + +# TEMPORARY TABLE algorithm +--disable_warnings +create database mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int, b int); +create algorithm=temptable view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; +grant select (c) on mysqltest.v1 to mysqltest_1@localhost; + +connection user1; +select c from mysqltest.v1; +# there are no privileges on column 'd' +-- error 1143 +select d from mysqltest.v1; + +connection root; +revoke all privileges on mysqltest.v1 from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +drop database mysqltest; + +# +# EXPLAIN rights +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings +#prepare views and tables +create table mysqltest.t1 (a int, b int); +create table mysqltest.t2 (a int, b int); +create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1; +create algorithm=temptable view mysqltest.v2 (c,d) as select a+1,b+1 from mysqltest.t1; +create view mysqltest.v3 (c,d) as select a+1,b+1 from mysqltest.t2; +create algorithm=temptable view mysqltest.v4 (c,d) as select a+1,b+1 from mysqltest.t2; +grant select on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.v2 to mysqltest_1@localhost; +grant select on mysqltest.v3 to mysqltest_1@localhost; +grant select on mysqltest.v4 to mysqltest_1@localhost; + +connection user1; +# all selects works +select c from mysqltest.v1; +select c from mysqltest.v2; +select c from mysqltest.v3; +select c from mysqltest.v4; +# test of show coluns +show columns from mysqltest.v1; +show columns from mysqltest.v2; +# but explain/show do not +-- error 1345 +explain select c from mysqltest.v1; +-- error 1142 +show create view mysqltest.v1; +-- error 1345 +explain select c from mysqltest.v2; +-- error 1142 +show create view mysqltest.v2; +-- error 1345 +explain select c from mysqltest.v3; +-- error 1142 +show create view mysqltest.v3; +-- error 1345 +explain select c from mysqltest.v4; +-- error 1142 +show create view mysqltest.v4; + +# allow to see one of underlying table +connection root; +grant select on mysqltest.t1 to mysqltest_1@localhost; +connection user1; +# EXPLAIN of view on above table works +explain select c from mysqltest.v1; +-- error 1142 +show create view mysqltest.v1; +explain select c from mysqltest.v2; +-- error 1142 +show create view mysqltest.v2; +# but other EXPLAINs do not +-- error 1345 +explain select c from mysqltest.v3; +-- error 1142 +show create view mysqltest.v3; +-- error 1345 +explain select c from mysqltest.v4; +-- error 1142 +show create view mysqltest.v4; + +# allow to see any view in mysqltest database +connection root; +grant show view on mysqltest.* to mysqltest_1@localhost; +connection user1; +explain select c from mysqltest.v1; +show create view mysqltest.v1; +explain select c from mysqltest.v2; +show create view mysqltest.v2; +explain select c from mysqltest.v3; +show create view mysqltest.v3; +explain select c from mysqltest.v4; +show create view mysqltest.v4; + +connection root; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +drop database mysqltest; + +# +# UPDATE privileges on VIEW columns and whole VIEW +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int, b int, primary key(a)); +insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10); +create table mysqltest.t2 (x int); +insert into mysqltest.t2 values (3), (4), (5), (6); +create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; +create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; +create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1; + +grant update (a) on mysqltest.v2 to mysqltest_1@localhost; +grant update on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.* to mysqltest_1@localhost; + +connection user1; +use mysqltest; +# update with rights on VIEW column +update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.c; +select * from t1 order by a; # PBXT : required for order +update v1 set a=a+c; +select * from t1 order by a; # PBXT : required for order +# update with rights on whole VIEW +update t2,v2 set v2.a=v2.a+v2.c where t2.x=v2.c; +select * from t1 order by a; # PBXT : required for order +update v2 set a=a+c; +select * from t1 order by a; # PBXT : required for order +# no rights on column +-- error 1143 +update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c; +-- error 1143 +update v2 set c=a+c; +# no rights for view +-- error 1142 +update t2,v3 set v3.a=v3.a+v3.c where t2.x=v3.c; +-- error 1142 +update v3 set a=a+c; + +use test; +connection root; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; + +# +# DELETE privileges on VIEW +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int, b int, primary key(a)); +insert into mysqltest.t1 values (1,2), (2,3), (3,4), (4,5), (5,10); +create table mysqltest.t2 (x int); +insert into mysqltest.t2 values (3), (4), (5), (6); +create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1; +create view mysqltest.v2 (a,c) as select a, b+1 from mysqltest.t1; + +grant delete on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.* to mysqltest_1@localhost; + +connection user1; +use mysqltest; +# update with rights on VIEW column +delete from v1 where c < 4; +select * from t1; +delete v1 from t2,v1 where t2.x=v1.c; +select * from t1; +# no rights for view +-- error 1142 +delete v2 from t2,v2 where t2.x=v2.c; +-- error 1142 +delete from v2 where c < 4; + +use test; +connection root; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; + +# +# insert privileges on VIEW +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int, b int, primary key(a)); +insert into mysqltest.t1 values (1,2), (2,3); +create table mysqltest.t2 (x int, y int); +insert into mysqltest.t2 values (3,4); +create view mysqltest.v1 (a,c) as select a, b from mysqltest.t1; +create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1; + +grant insert on mysqltest.v1 to mysqltest_1@localhost; +grant select on mysqltest.* to mysqltest_1@localhost; + +connection user1; +use mysqltest; +# update with rights on VIEW column +insert into v1 values (5,6); +select * from t1; +insert into v1 select x,y from t2; +select * from t1; +# no rights for view +-- error 1142 +insert into v2 values (5,6); +-- error 1142 +insert into v2 select x,y from t2; + +use test; +connection root; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; + +# +# test of CREATE VIEW privileges if we have limited privileges +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int, b int); +create table mysqltest.t2 (a int, b int); + +grant update on mysqltest.t1 to mysqltest_1@localhost; +grant update(b) on mysqltest.t2 to mysqltest_1@localhost; +grant create view,update on test.* to mysqltest_1@localhost; + +connection user1; + +create view v1 as select * from mysqltest.t1; +create view v2 as select b from mysqltest.t2; +# There are not rights on mysqltest.v1 +-- error 1142 +create view mysqltest.v1 as select * from mysqltest.t1; +# There are not any rights on mysqltest.t2.a +-- error 1143 +create view v3 as select a from mysqltest.t2; + +# give CREATE VIEW privileges (without any privileges for result column) +connection root; +create table mysqltest.v3 (b int); +grant create view on mysqltest.v3 to mysqltest_1@localhost; +drop table mysqltest.v3; +connection user1; +create view mysqltest.v3 as select b from mysqltest.t2; + +# give UPDATE privileges +connection root; +grant create view, update on mysqltest.v3 to mysqltest_1@localhost; +drop view mysqltest.v3; +connection user1; +create view mysqltest.v3 as select b from mysqltest.t2; + + +# Expression need select privileges +-- error 1143 +create view v4 as select b+1 from mysqltest.t2; + +connection root; +grant create view,update,select on test.* to mysqltest_1@localhost; +connection user1; +-- error 1143 +create view v4 as select b+1 from mysqltest.t2; + +connection root; +grant update,select(b) on mysqltest.t2 to mysqltest_1@localhost; +connection user1; +create view v4 as select b+1 from mysqltest.t2; + +connection root; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; +drop view v1,v2,v4; + +# +# user with global DB privileges +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings +create table mysqltest.t1 (a int); +grant all privileges on mysqltest.* to mysqltest_1@localhost; + +connection user1; +use mysqltest; +create view v1 as select * from t1; +use test; + +connection root; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +drop database mysqltest; + +# +# view definer grants revoking +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +create table mysqltest.t1 (a int, b int); + +grant select on mysqltest.t1 to mysqltest_1@localhost; +grant create view,select on test.* to mysqltest_1@localhost; + +connection user1; + +create view v1 as select * from mysqltest.t1; + +connection root; +# check view definer information +show create view v1; +revoke select on mysqltest.t1 from mysqltest_1@localhost; +-- error ER_VIEW_INVALID +select * from v1; +grant select on mysqltest.t1 to mysqltest_1@localhost; +select * from v1; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop view v1; +drop database mysqltest; + +# +# rights on execution of view underlying functiond (BUG#9505) +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +use mysqltest; +create table t1 (a int); +insert into t1 values (1); +create table t2 (s1 int); +--disable_warnings +drop function if exists f2; +--enable_warnings +delimiter //; +create function f2 () returns int begin declare v int; select s1 from t2 +into v; return v; end// +delimiter ;// +create algorithm=TEMPTABLE view v1 as select f2() from t1; +create algorithm=MERGE view v2 as select f2() from t1; +create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1; +create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1; +create SQL SECURITY INVOKER view v5 as select * from v4; +grant select on v1 to mysqltest_1@localhost; +grant select on v2 to mysqltest_1@localhost; +grant select on v3 to mysqltest_1@localhost; +grant select on v4 to mysqltest_1@localhost; +grant select on v5 to mysqltest_1@localhost; + +connection user1; +use mysqltest; +select * from v1; +select * from v2; +-- error ER_VIEW_INVALID +select * from v3; +-- error ER_VIEW_INVALID +select * from v4; +-- error ER_VIEW_INVALID +select * from v5; +use test; + +connection root; +drop view v1, v2, v3, v4, v5; +drop function f2; +drop table t1, t2; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; + +# +# revertion of previous test, definer of view lost his/her rights to execute +# function +# + +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +use mysqltest; +create table t1 (a int); +insert into t1 values (1); +create table t2 (s1 int); +--disable_warnings +drop function if exists f2; +--enable_warnings +delimiter //; +create function f2 () returns int begin declare v int; select s1 from t2 +into v; return v; end// +delimiter ;// +grant select on t1 to mysqltest_1@localhost; +grant execute on function f2 to mysqltest_1@localhost; +grant create view on mysqltest.* to mysqltest_1@localhost; + +connection user1; +use mysqltest; +create algorithm=TEMPTABLE view v1 as select f2() from t1; +create algorithm=MERGE view v2 as select f2() from t1; +create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select f2() from t1; +create algorithm=MERGE SQL SECURITY INVOKER view v4 as select f2() from t1; +use test; + +connection root; +create view v5 as select * from v1; +revoke execute on function f2 from mysqltest_1@localhost; +-- error ER_VIEW_INVALID +select * from v1; +-- error ER_VIEW_INVALID +select * from v2; +select * from v3; +select * from v4; +-- error ER_VIEW_INVALID +select * from v5; + +drop view v1, v2, v3, v4, v5; +drop function f2; +drop table t1, t2; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; + +# +# definer/invoker rights for columns +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +use mysqltest; +create table t1 (a int); +create table v1 (a int); +insert into t1 values (1); +grant select on t1 to mysqltest_1@localhost; +grant select on v1 to mysqltest_1@localhost; +grant create view on mysqltest.* to mysqltest_1@localhost; +drop table v1; + +connection user1; +use mysqltest; +create algorithm=TEMPTABLE view v1 as select *, a as b from t1; +create algorithm=MERGE view v2 as select *, a as b from t1; +create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1; +create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1; +create view v5 as select * from v1; +use test; + +connection root; +revoke select on t1 from mysqltest_1@localhost; +-- error ER_VIEW_INVALID +select * from v1; +-- error ER_VIEW_INVALID +select * from v2; +select * from v3; +select * from v4; +-- error ER_VIEW_INVALID +select * from v5; + +#drop view v1, v2, v3, v4, v5; +drop table t1; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; + + +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +use mysqltest; +create table t1 (a int); +insert into t1 values (1); +create algorithm=TEMPTABLE view v1 as select *, a as b from t1; +create algorithm=MERGE view v2 as select *, a as b from t1; +create algorithm=TEMPTABLE SQL SECURITY INVOKER view v3 as select *, a as b from t1; +create algorithm=MERGE SQL SECURITY INVOKER view v4 as select *, a as b from t1; +create SQL SECURITY INVOKER view v5 as select * from v4; +grant select on v1 to mysqltest_1@localhost; +grant select on v2 to mysqltest_1@localhost; +grant select on v3 to mysqltest_1@localhost; +grant select on v4 to mysqltest_1@localhost; +grant select on v5 to mysqltest_1@localhost; + +connection user1; +use mysqltest; +select * from v1; +select * from v2; +-- error ER_VIEW_INVALID +select * from v3; +-- error ER_VIEW_INVALID +select * from v4; +-- error ER_VIEW_INVALID +select * from v5; +use test; + +connection root; +drop view v1, v2, v3, v4, v5; +drop table t1; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; +drop database mysqltest; + +# +# BUG#14256: definer in view definition is not fully qualified +# +--disable_warnings +drop view if exists v1; +--enable_warnings + +# Backup anonymous users and remove them. (They get in the way of +# the one we test with here otherwise.) +create table t1 as select * from mysql.user where user=''; +delete from mysql.user where user=''; +flush privileges; + +# Create the test user +grant all on test.* to 'test14256'@'%'; + +connect (test14256,localhost,test14256,,test); +connection test14256; +use test; + +create view v1 as select 42; +show create view v1; + +select definer into @v1def1 from information_schema.views + where table_schema = 'test' and table_name='v1'; +drop view v1; + +create definer=`test14256`@`%` view v1 as select 42; +show create view v1; + +select definer into @v1def2 from information_schema.views + where table_schema = 'test' and table_name='v1'; +drop view v1; + +select @v1def1, @v1def2, @v1def1=@v1def2; + +connection root; +drop user test14256; + +# Restore the anonymous users. +insert into mysql.user select * from t1; +flush privileges; + +drop table t1; + +# +# BUG#14726: freeing stack variable in case of an error of opening +# a view when we have locked tables with LOCK TABLES statement. +# +connection root; +--disable_warnings +create database mysqltest; +--enable_warnings + +use mysqltest; +CREATE TABLE t1 (i INT); +CREATE VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +GRANT SELECT, LOCK TABLES ON mysqltest.* TO mysqltest_1@localhost; + +connection user1; + +use mysqltest; +LOCK TABLES v1 READ; +-- error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE TABLE v1; +UNLOCK TABLES; +use test; + +connection root; +use test; +drop user mysqltest_1@localhost; +drop database mysqltest; + +# +# switch to default connaction +# +disconnect user1; +disconnect root; +connection default; + +# +# DEFINER information check +# +create definer=some_user@`` sql security invoker view v1 as select 1; +create definer=some_user@localhost sql security invoker view v2 as select 1; +show create view v1; +show create view v2; +drop view v1; +drop view v2; + +# +# Bug#18681: View privileges are broken +# +CREATE DATABASE mysqltest1; +CREATE USER readonly@localhost; +CREATE TABLE mysqltest1.t1 (x INT); +INSERT INTO mysqltest1.t1 VALUES (1), (2); +CREATE SQL SECURITY INVOKER VIEW mysqltest1.v_t1 AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ts AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ti AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tu AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tus AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_td AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tds AS SELECT * FROM mysqltest1.t1; +GRANT SELECT, INSERT, UPDATE, DELETE ON mysqltest1.v_t1 TO readonly@localhost; +GRANT SELECT ON mysqltest1.v_ts TO readonly@localhost; +GRANT INSERT ON mysqltest1.v_ti TO readonly@localhost; +GRANT UPDATE ON mysqltest1.v_tu TO readonly@localhost; +GRANT UPDATE,SELECT ON mysqltest1.v_tus TO readonly@localhost; +GRANT DELETE ON mysqltest1.v_td TO readonly@localhost; +GRANT DELETE,SELECT ON mysqltest1.v_tds TO readonly@localhost; + +CONNECT (n1,localhost,readonly,,); +CONNECTION n1; + +--error 1356 +SELECT * FROM mysqltest1.v_t1; +--error 1356 +INSERT INTO mysqltest1.v_t1 VALUES(4); +--error 1356 +DELETE FROM mysqltest1.v_t1 WHERE x = 1; +--error 1356 +UPDATE mysqltest1.v_t1 SET x = 3 WHERE x = 2; +--error 1356 +UPDATE mysqltest1.v_t1 SET x = 3; +--error 1356 +DELETE FROM mysqltest1.v_t1; +--error 1356 +SELECT 1 FROM mysqltest1.v_t1; +--error 1142 +SELECT * FROM mysqltest1.t1; + +SELECT * FROM mysqltest1.v_ts; +--error 1142 +SELECT * FROM mysqltest1.v_ts, mysqltest1.t1 WHERE mysqltest1.t1.x = mysqltest1.v_ts.x; +--error 1142 +SELECT * FROM mysqltest1.v_ti; + +--error 1142 +INSERT INTO mysqltest1.v_ts VALUES (100); +INSERT INTO mysqltest1.v_ti VALUES (100); + +--error 1142 +UPDATE mysqltest1.v_ts SET x= 200 WHERE x = 100; +--error 1142 +UPDATE mysqltest1.v_ts SET x= 200; +UPDATE mysqltest1.v_tu SET x= 200 WHERE x = 100; +UPDATE mysqltest1.v_tus SET x= 200 WHERE x = 100; +UPDATE mysqltest1.v_tu SET x= 200; + +--error 1142 +DELETE FROM mysqltest1.v_ts WHERE x= 200; +--error 1142 +DELETE FROM mysqltest1.v_ts; +--error 1143 +DELETE FROM mysqltest1.v_td WHERE x= 200; +DELETE FROM mysqltest1.v_tds WHERE x= 200; +DELETE FROM mysqltest1.v_td; + +CONNECTION default; +DROP VIEW mysqltest1.v_tds; +DROP VIEW mysqltest1.v_td; +DROP VIEW mysqltest1.v_tus; +DROP VIEW mysqltest1.v_tu; +DROP VIEW mysqltest1.v_ti; +DROP VIEW mysqltest1.v_ts; +DROP VIEW mysqltest1.v_t1; +DROP TABLE mysqltest1.t1; +DROP USER readonly@localhost; +DROP DATABASE mysqltest1; + +# +# BUG#14875: Bad view DEFINER makes SHOW CREATE VIEW fail +# +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1), (2), (3); +CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1; +#--warning 1448 +SHOW CREATE VIEW v; +--error 1449 +SELECT * FROM v; +DROP VIEW v; +DROP TABLE t1; +USE test; + +# +# Bug#20363: Create view on just created view is now denied +# +eval CREATE USER mysqltest_db1@localhost identified by 'PWD'; +eval GRANT ALL ON mysqltest_db1.* TO mysqltest_db1@localhost WITH GRANT OPTION; + +# The session with the non root user is needed. +--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK +connect (session1,localhost,mysqltest_db1,PWD,test); + +CREATE SCHEMA mysqltest_db1 ; +USE mysqltest_db1 ; + +CREATE TABLE t1 (f1 INTEGER); + +CREATE VIEW view1 AS +SELECT * FROM t1; +SHOW CREATE VIEW view1; + +CREATE VIEW view2 AS +SELECT * FROM view1; +--echo # Here comes a suspicious warning +SHOW CREATE VIEW view2; +--echo # But the view view2 is usable +SELECT * FROM view2; + +CREATE VIEW view3 AS +SELECT * FROM view2; + +SELECT * from view3; + +connection default; +DROP VIEW mysqltest_db1.view3; +DROP VIEW mysqltest_db1.view2; +DROP VIEW mysqltest_db1.view1; +DROP TABLE mysqltest_db1.t1; +DROP SCHEMA mysqltest_db1; +DROP USER mysqltest_db1@localhost; +# +# BUG#20482: failure on Create join view with sources views/tables +# in different schemas +# +--disable_warnings +CREATE DATABASE test1; +CREATE DATABASE test2; +--enable_warnings + +CREATE TABLE test1.t0 (a VARCHAR(20)) engine=myisam; # PBXT can't mix databases; +CREATE TABLE test2.t1 (a VARCHAR(20)); +CREATE VIEW test2.t3 AS SELECT * FROM test1.t0; +CREATE OR REPLACE VIEW test.v1 AS + SELECT ta.a AS col1, tb.a AS col2 FROM test2.t3 ta, test2.t1 tb; + +DROP VIEW test.v1; +DROP VIEW test2.t3; +DROP TABLE test2.t1, test1.t0; +DROP DATABASE test2; +DROP DATABASE test1; + + +# +# BUG#20570: CURRENT_USER() in a VIEW with SQL SECURITY DEFINER +# returns invoker name +# +--disable_warnings +DROP VIEW IF EXISTS v1; +DROP VIEW IF EXISTS v2; +DROP VIEW IF EXISTS v3; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP PROCEDURE IF EXISTS p1; +--enable_warnings + +CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT CURRENT_USER() AS cu; + +CREATE FUNCTION f1() RETURNS VARCHAR(77) SQL SECURITY INVOKER + RETURN CURRENT_USER(); +CREATE SQL SECURITY DEFINER VIEW v2 AS SELECT f1() AS cu; + +CREATE PROCEDURE p1(OUT cu VARCHAR(77)) SQL SECURITY INVOKER + SET cu= CURRENT_USER(); +delimiter |; +CREATE FUNCTION f2() RETURNS VARCHAR(77) SQL SECURITY INVOKER +BEGIN + DECLARE cu VARCHAR(77); + CALL p1(cu); + RETURN cu; +END| +delimiter ;| +CREATE SQL SECURITY DEFINER VIEW v3 AS SELECT f2() AS cu; + +CREATE USER mysqltest_u1@localhost; +GRANT ALL ON test.* TO mysqltest_u1@localhost; + +connect (conn1, localhost, mysqltest_u1,,); + +--echo +--echo The following tests should all return 1. +--echo +SELECT CURRENT_USER() = 'mysqltest_u1@localhost'; +SELECT f1() = 'mysqltest_u1@localhost'; +CALL p1(@cu); +SELECT @cu = 'mysqltest_u1@localhost'; +SELECT f2() = 'mysqltest_u1@localhost'; +SELECT cu = 'root@localhost' FROM v1; +SELECT cu = 'root@localhost' FROM v2; +SELECT cu = 'root@localhost' FROM v3; + +disconnect conn1; +connection default; + +DROP VIEW v3; +DROP FUNCTION f2; +DROP PROCEDURE p1; +DROP FUNCTION f1; +DROP VIEW v2; +DROP VIEW v1; +DROP USER mysqltest_u1@localhost; + + +# +# Bug#17254: Error for DEFINER security on VIEW provides too much info +# +connect (root,localhost,root,,); +connection root; +CREATE DATABASE db17254; +USE db17254; +CREATE TABLE t1 (f1 INT); +INSERT INTO t1 VALUES (10),(20); +CREATE USER def_17254@localhost; +GRANT SELECT ON db17254.* TO def_17254@localhost; +CREATE USER inv_17254@localhost; +GRANT SELECT ON db17254.t1 TO inv_17254@localhost; +GRANT CREATE VIEW ON db17254.* TO def_17254@localhost; + +connect (def,localhost,def_17254,,db17254); +connection def; +CREATE VIEW v1 AS SELECT * FROM t1; + +connection root; +DROP USER def_17254@localhost; + +connect (inv,localhost,inv_17254,,db17254); +connection inv; +--echo for a user +--error 1142 +SELECT * FROM v1; + +connection root; +--echo for a superuser +--error 1449 +SELECT * FROM v1; +DROP USER inv_17254@localhost; +DROP DATABASE db17254; +disconnect def; +disconnect inv; + + +# +# BUG#24404: strange bug with view+permission+prepared statement +# +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +DROP DATABASE IF EXISTS mysqltest_db2; +--enable_warnings +--error 0,ER_CANNOT_USER +DROP USER mysqltest_u1; +--error 0,ER_CANNOT_USER +DROP USER mysqltest_u2; + +CREATE USER mysqltest_u1@localhost; +CREATE USER mysqltest_u2@localhost; + +CREATE DATABASE mysqltest_db1; +CREATE DATABASE mysqltest_db2; + +GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost WITH GRANT OPTION; +GRANT ALL ON mysqltest_db2.* TO mysqltest_u2@localhost; + +connect (conn1, localhost, mysqltest_u1, , mysqltest_db1); + +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1); + +# Use view with subquery for better coverage. +CREATE VIEW v1 AS SELECT i FROM t1 WHERE 1 IN (SELECT * FROM t1); + +CREATE TABLE t2 (s CHAR(7)); +INSERT INTO t2 VALUES ('public'); + +GRANT SELECT ON v1 TO mysqltest_u2@localhost; +GRANT SELECT ON t2 TO mysqltest_u2@localhost; + +connect (conn2, localhost, mysqltest_u2, , mysqltest_db2); + +SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; +PREPARE stmt1 FROM "SELECT * FROM mysqltest_db1.t2"; +EXECUTE stmt1; +PREPARE stmt2 FROM "SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2"; +EXECUTE stmt2; + +connection conn1; +# Make table 't2' private. +REVOKE SELECT ON t2 FROM mysqltest_u2@localhost; +UPDATE t2 SET s = 'private' WHERE s = 'public'; + +connection conn2; +--error ER_TABLEACCESS_DENIED_ERROR +SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; +--error ER_TABLEACCESS_DENIED_ERROR +EXECUTE stmt1; +# Original bug was here: the statement didn't fail. +--error ER_TABLEACCESS_DENIED_ERROR +EXECUTE stmt2; + +# Cleanup. +disconnect conn2; +disconnect conn1; +connection default; +REVOKE ALL ON mysqltest_db1.* FROM mysqltest_u1@localhost; +REVOKE ALL ON mysqltest_db2.* FROM mysqltest_u2@localhost; +DROP DATABASE mysqltest_db1; +DROP DATABASE mysqltest_db2; +DROP USER mysqltest_u1@localhost; +DROP USER mysqltest_u2@localhost; + +# +# Bug#26813: The SUPER privilege is wrongly required to alter a view created +# by another user. +# +connection root; +CREATE DATABASE db26813; +USE db26813; +CREATE TABLE t1(f1 INT, f2 INT); +CREATE VIEW v1 AS SELECT f1 FROM t1; +CREATE VIEW v2 AS SELECT f1 FROM t1; +CREATE VIEW v3 AS SELECT f1 FROM t1; +CREATE USER u26813@localhost; +GRANT DROP ON db26813.v1 TO u26813@localhost; +GRANT CREATE VIEW ON db26813.v2 TO u26813@localhost; +GRANT DROP, CREATE VIEW ON db26813.v3 TO u26813@localhost; +GRANT SELECT ON db26813.t1 TO u26813@localhost; + +connect (u1,localhost,u26813,,db26813); +connection u1; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +ALTER VIEW v1 AS SELECT f2 FROM t1; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +ALTER VIEW v2 AS SELECT f2 FROM t1; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +ALTER VIEW v3 AS SELECT f2 FROM t1; + +connection root; +SHOW CREATE VIEW v3; + +DROP USER u26813@localhost; +DROP DATABASE db26813; +disconnect u1; + +--echo # +--echo # Bug#29908: A user can gain additional access through the ALTER VIEW. +--echo # +connection root; +CREATE DATABASE mysqltest_29908; +USE mysqltest_29908; +CREATE TABLE t1(f1 INT, f2 INT); +CREATE USER u29908_1@localhost; +CREATE DEFINER = u29908_1@localhost VIEW v1 AS SELECT f1 FROM t1; +CREATE DEFINER = u29908_1@localhost SQL SECURITY INVOKER VIEW v2 AS + SELECT f1 FROM t1; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v1 TO u29908_1@localhost; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_1@localhost; +GRANT SELECT ON mysqltest_29908.t1 TO u29908_1@localhost; +CREATE USER u29908_2@localhost; +GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; +GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; +GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; + +connect (u2,localhost,u29908_2,,mysqltest_29908); +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +ALTER VIEW v1 AS SELECT f2 FROM t1; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +ALTER VIEW v2 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v2; + +connect (u1,localhost,u29908_1,,mysqltest_29908); +ALTER VIEW v1 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v1; +ALTER VIEW v2 AS SELECT f2 FROM t1; +SHOW CREATE VIEW v2; + +connection root; +ALTER VIEW v1 AS SELECT f1 FROM t1; +SHOW CREATE VIEW v1; +ALTER VIEW v2 AS SELECT f1 FROM t1; +SHOW CREATE VIEW v2; + +DROP USER u29908_1@localhost; +DROP USER u29908_2@localhost; +DROP DATABASE mysqltest_29908; +disconnect u1; +disconnect u2; +--echo ####################################################################### + +# +# BUG#24040: Create View don't succed with "all privileges" on a database. +# + +# Prepare. + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +--enable_warnings + +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; + +# Test. + +CREATE TABLE mysqltest1.t1(c1 INT); +CREATE TABLE mysqltest1.t2(c2 INT); +CREATE TABLE mysqltest1.t3(c3 INT); +CREATE TABLE mysqltest1.t4(c4 INT); + +INSERT INTO mysqltest1.t1 VALUES (11), (12), (13), (14); +INSERT INTO mysqltest1.t2 VALUES (21), (22), (23), (24); +INSERT INTO mysqltest1.t3 VALUES (31), (32), (33), (34); +INSERT INTO mysqltest1.t4 VALUES (41), (42), (43), (44); + +GRANT SELECT ON mysqltest1.t1 TO mysqltest_u1@localhost; +GRANT INSERT ON mysqltest1.t2 TO mysqltest_u1@localhost; +GRANT SELECT, UPDATE ON mysqltest1.t3 TO mysqltest_u1@localhost; +GRANT SELECT, DELETE ON mysqltest1.t4 TO mysqltest_u1@localhost; + +GRANT ALL PRIVILEGES ON mysqltest2.* TO mysqltest_u1@localhost; + +--connect (bug24040_con,localhost,mysqltest_u1,,mysqltest2) +--echo +--echo ---> connection: bug24040_con + +SELECT * FROM mysqltest1.t1; +INSERT INTO mysqltest1.t2 VALUES(25); +UPDATE mysqltest1.t3 SET c3 = 331 WHERE c3 = 31; +DELETE FROM mysqltest1.t4 WHERE c4 = 44; + +CREATE VIEW v1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v2 AS SELECT * FROM mysqltest1.t2; +CREATE VIEW v3 AS SELECT * FROM mysqltest1.t3; +CREATE VIEW v4 AS SELECT * FROM mysqltest1.t4; + +SELECT * FROM v1; +INSERT INTO v2 VALUES(26); +UPDATE v3 SET c3 = 332 WHERE c3 = 32; +DELETE FROM v4 WHERE c4 = 43; + +--error ER_COLUMNACCESS_DENIED_ERROR +CREATE VIEW v12 AS SELECT c1, c2 FROM mysqltest1.t1, mysqltest1.t2; +CREATE VIEW v13 AS SELECT c1, c3 FROM mysqltest1.t1, mysqltest1.t3; +CREATE VIEW v14 AS SELECT c1, c4 FROM mysqltest1.t1, mysqltest1.t4; + +--error ER_COLUMNACCESS_DENIED_ERROR +CREATE VIEW v21 AS SELECT c2, c1 FROM mysqltest1.t2, mysqltest1.t1; +--error ER_COLUMNACCESS_DENIED_ERROR +CREATE VIEW v23 AS SELECT c2, c3 FROM mysqltest1.t2, mysqltest1.t3; +--error ER_COLUMNACCESS_DENIED_ERROR +CREATE VIEW v24 AS SELECT c2, c4 FROM mysqltest1.t2, mysqltest1.t4; + +CREATE VIEW v31 AS SELECT c3, c1 FROM mysqltest1.t3, mysqltest1.t1; +--error ER_COLUMNACCESS_DENIED_ERROR +CREATE VIEW v32 AS SELECT c3, c2 FROM mysqltest1.t3, mysqltest1.t2; +CREATE VIEW v34 AS SELECT c3, c4 FROM mysqltest1.t3, mysqltest1.t4; + +CREATE VIEW v41 AS SELECT c4, c1 FROM mysqltest1.t4, mysqltest1.t1; +--error ER_COLUMNACCESS_DENIED_ERROR +CREATE VIEW v42 AS SELECT c4, c2 FROM mysqltest1.t4, mysqltest1.t2; +CREATE VIEW v43 AS SELECT c4, c3 FROM mysqltest1.t4, mysqltest1.t3; + +--connection default +--echo +--echo ---> connection: default + +SELECT * FROM mysqltest1.t1; +SELECT * FROM mysqltest1.t2; +SELECT * FROM mysqltest1.t3 order by c3; # PBXT: order required +SELECT * FROM mysqltest1.t4; + +# Cleanup. + +-- disconnect bug24040_con + +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +DROP USER mysqltest_u1@localhost; + +--echo End of 5.0 tests. + + +# +# Test that ALTER VIEW accepts DEFINER and ALGORITHM, see bug#16425. +# +connection default; +--disable_warnings +DROP VIEW IF EXISTS v1; +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (i INT); +CREATE VIEW v1 AS SELECT * FROM t1; + +ALTER VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; + +DROP VIEW v1; +DROP TABLE t1; + + +--disable_query_log +drop database pbxt; +--enable_query_log +--echo End of 5.1 tests. diff --git a/mysql-test/suite/pbxt/t/view_query_cache.test b/mysql-test/suite/pbxt/t/view_query_cache.test new file mode 100644 index 00000000000..ab276bb0aa9 --- /dev/null +++ b/mysql-test/suite/pbxt/t/view_query_cache.test @@ -0,0 +1,134 @@ +-- source include/have_query_cache.inc +# +# QUERY CACHE options for VIEWs +# +--disable_warnings +drop table if exists t1,t2,v1,v2,v3; +drop view if exists t1,t2,v1,v2,v3; +--enable_warnings + +set GLOBAL query_cache_size=1355776; +flush status; +create table t1 (a int, b int); + +# queries with following views should not be in query cache +create view v1 (c,d) as select sql_no_cache a,b from t1; +create view v2 (c,d) as select a+rand(),b from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from v1; +select * from v2; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from v1; +select * from v2; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; + +drop view v1,v2; + +# SQL_CACHE option +set query_cache_type=demand; +flush status; +# query with view will be cached, but direct acess to table will not +create view v1 (c,d) as select sql_cache a,b from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +drop view v1; +set query_cache_type=default; + +drop table t1; + +# +# invalidation of view +# +create table t1 (a int); +insert into t1 values (1), (2), (3); +create view v1 as select a from t1 where a > 1; +select * from v1; +alter view v1 as select a from t1 where a > 2; +select * from v1; +drop view v1; +-- error 1146 +select * from v1; +drop table t1; + +# +# join view with QC +# +create table t1 (a int, primary key (a), b int); +create table t2 (a int, primary key (a), b int); +insert into t2 values (1000, 2000); +create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2; +select * from v3; +drop view v3; +drop table t1, t2; + +# +# Bug #13424 locking view with query cache enabled crashes server +# +create table t1(f1 int); +insert into t1 values(1),(2),(3); +create view v1 as select * from t1; +set query_cache_wlock_invalidate=1; +lock tables v1 read /*!32311 local */; +unlock tables; +set query_cache_wlock_invalidate=default; +drop view v1; +drop table t1; + +# +# BUG#15119: returning temptable view from the query cache. +# +flush status; +create table t1 (a int, b int); +create algorithm=temptable view v1 as select * from t1; +select * from v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +insert into t1 values (1,1); +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from v1; +select * from v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +drop view v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +drop table t1; + +# Reset default environment. +set GLOBAL query_cache_size=default; + +--disable_query_log +drop database pbxt; +--enable_query_log diff --git a/mysql-test/suite/pbxt/t/xml.test b/mysql-test/suite/pbxt/t/xml.test new file mode 100644 index 00000000000..ef94c7508c4 --- /dev/null +++ b/mysql-test/suite/pbxt/t/xml.test @@ -0,0 +1,408 @@ +SET @xml='<a aa1="aa1" aa2="aa2">a1<b ba1="ba1">b1<c>c1</c>b2</b>a2</a>'; +SELECT extractValue(@xml,'/a'); +SELECT extractValue(@xml,'/a/b'); +SELECT extractValue(@xml,'/a/b/c'); +SELECT extractValue(@xml,'/a/@aa1'); +SELECT extractValue(@xml,'/a/@aa2'); +SELECT extractValue(@xml,'/a/@*'); +SELECT extractValue(@xml,'//@ba1'); + +SELECT extractValue(@xml,'//a'); +SELECT extractValue(@xml,'//b'); +SELECT extractValue(@xml,'//c'); +SELECT extractValue(@xml,'/a//b'); +SELECT extractValue(@xml,'/a//c'); +SELECT extractValue(@xml,'//*'); +SELECT extractValue(@xml,'/a//*'); +SELECT extractValue(@xml,'/./a'); +SELECT extractValue(@xml,'/a/b/.'); +SELECT extractValue(@xml,'/a/b/..'); +SELECT extractValue(@xml,'/a/b/../@aa1'); +SELECT extractValue(@xml,'/*'); +SELECT extractValue(@xml,'/*/*'); +SELECT extractValue(@xml,'/*/*/*'); + +SELECT extractValue(@xml,'/a/child::*'); +SELECT extractValue(@xml,'/a/self::*'); +SELECT extractValue(@xml,'/a/descendant::*'); +SELECT extractValue(@xml,'/a/descendant-or-self::*'); +SELECT extractValue(@xml,'/a/attribute::*'); +SELECT extractValue(@xml,'/a/b/c/parent::*'); +SELECT extractValue(@xml,'/a/b/c/ancestor::*'); +SELECT extractValue(@xml,'/a/b/c/ancestor-or-self::*'); +SELECT extractValue(@xml,'/descendant-or-self::*'); + +SET @xml='<a>a11<b ba="ba11" ba="ba12">b11</b><b ba="ba21" ba="ba22">b21<c>c1</c>b22</b>a12</a>'; +SELECT extractValue(@xml,'/a/b/c/ancestor-or-self::*'); +SELECT extractValue(@xml,'//@ba'); + +SET @xml='<a><b>b</b><c>c</c></a>'; +SELECT extractValue(@xml,'/a/b'); +SELECT extractValue(@xml,'/a/c'); +SELECT extractValue(@xml,'/a/child::b'); +SELECT extractValue(@xml,'/a/child::c'); + +SET @xml='<a><b>b1</b><c>c1</c><b>b2</b><c>c2</c></a>'; +SELECT extractValue(@xml,'/a/b[1]'); +SELECT extractValue(@xml,'/a/b[2]'); +SELECT extractValue(@xml,'/a/c[1]'); +SELECT extractValue(@xml,'/a/c[2]'); + +SET @xml='<a><b x="xb1" x="xb2"/><c x="xc1" x="xc2"/></a>'; +SELECT extractValue(@xml,'/a//@x'); +SELECT extractValue(@xml,'/a//@x[1]'); +SELECT extractValue(@xml,'/a//@x[2]'); + +SET @xml='<a><b>b1</b><b>b2</b><c><b>c1b1</b><b>c1b2</b></c><c><b>c2b1</c></b></a>'; +SELECT extractValue(@xml,'//b[1]'); +SELECT extractValue(@xml,'/descendant::b[1]'); + +SET @xml='<a><b>b1</b><b>b2</b></a>'; +SELECT extractValue(@xml,'/a/b[1+0]'); +SELECT extractValue(@xml,'/a/b[1*1]'); +SELECT extractValue(@xml,'/a/b[--1]'); +SELECT extractValue(@xml,'/a/b[2*1-1]'); + +SELECT extractValue(@xml,'/a/b[1+1]'); +SELECT extractValue(@xml,'/a/b[1*2]'); +SELECT extractValue(@xml,'/a/b[--2]'); +SELECT extractValue(@xml,'/a/b[1*(3-1)]'); + +SELECT extractValue(@xml,'//*[1=1]'); +SELECT extractValue(@xml,'//*[1!=1]'); +SELECT extractValue(@xml,'//*[1>1]'); +SELECT extractValue(@xml,'//*[2>1]'); +SELECT extractValue(@xml,'//*[1>2]'); +SELECT extractValue(@xml,'//*[1>=1]'); +SELECT extractValue(@xml,'//*[2>=1]'); +SELECT extractValue(@xml,'//*[1>=2]'); +SELECT extractValue(@xml,'//*[1<1]'); +SELECT extractValue(@xml,'//*[2<1]'); +SELECT extractValue(@xml,'//*[1<2]'); +SELECT extractValue(@xml,'//*[1<=1]'); +SELECT extractValue(@xml,'//*[2<=1]'); +SELECT extractValue(@xml,'//*[1<=2]'); + +SET @xml='<a><b>b11<c>c11</c></b><b>b21<c>c21</c></b></a>'; +SELECT extractValue(@xml,'/a/b[c="c11"]'); +SELECT extractValue(@xml,'/a/b[c="c21"]'); + +SET @xml='<a><b c="c11">b11</b><b c="c21">b21</b></a>'; +SELECT extractValue(@xml,'/a/b[@c="c11"]'); +SELECT extractValue(@xml,'/a/b[@c="c21"]'); + +SET @xml='<a>a1<b c="c11">b11<d>d11</d></b><b c="c21">b21<d>d21</d></b></a>'; +SELECT extractValue(@xml, '/a/b[@c="c11"]/d'); +SELECT extractValue(@xml, '/a/b[@c="c21"]/d'); +SELECT extractValue(@xml, '/a/b[d="d11"]/@c'); +SELECT extractValue(@xml, '/a/b[d="d21"]/@c'); +SELECT extractValue(@xml, '/a[b="b11"]'); +SELECT extractValue(@xml, '/a[b/@c="c11"]'); +SELECT extractValue(@xml, '/a[b/d="d11"]'); +SELECT extractValue(@xml, '/a[/a/b="b11"]'); +SELECT extractValue(@xml, '/a[/a/b/@c="c11"]'); +SELECT extractValue(@xml, '/a[/a/b/d="d11"]'); + +SELECT extractValue('<a>a</a>', '/a[false()]'); +SELECT extractValue('<a>a</a>', '/a[true()]'); +SELECT extractValue('<a>a</a>', '/a[not(false())]'); +SELECT extractValue('<a>a</a>', '/a[not(true())]'); +SELECT extractValue('<a>a</a>', '/a[true() and true()]'); +SELECT extractValue('<a>a</a>', '/a[true() and false()]'); +SELECT extractValue('<a>a</a>', '/a[false()and false()]'); +SELECT extractValue('<a>a</a>', '/a[false()and true()]'); +SELECT extractValue('<a>a</a>', '/a[true() or true()]'); +SELECT extractValue('<a>a</a>', '/a[true() or false()]'); +SELECT extractValue('<a>a</a>', '/a[false()or false()]'); +SELECT extractValue('<a>a</a>', '/a[false()or true()]'); + +SET @xml='<a>ab<b c="c" c="e">b1</b><b c="d">b2</b><b c="f" c="e">b3</b></a>'; +select extractValue(@xml,'/a/b[@c="c"]'); +select extractValue(@xml,'/a/b[@c="d"]'); +select extractValue(@xml,'/a/b[@c="e"]'); +select extractValue(@xml,'/a/b[not(@c="e")]'); +select extractValue(@xml,'/a/b[@c!="e"]'); +select extractValue(@xml,'/a/b[@c="c" or @c="d"]'); +select extractValue(@xml,'/a/b[@c="c" and @c="e"]'); + +SET @xml='<a><b c="c" d="d">b1</b><b d="d" e="e">b2</b></a>'; +select extractValue(@xml,'/a/b[@c]'); +select extractValue(@xml,'/a/b[@d]'); +select extractValue(@xml,'/a/b[@e]'); +select extractValue(@xml,'/a/b[not(@c)]'); +select extractValue(@xml,'/a/b[not(@d)]'); +select extractValue(@xml,'/a/b[not(@e)]'); + +select extractValue(@xml, '/a/b[boolean(@c) or boolean(@d)]'); +select extractValue(@xml, '/a/b[boolean(@c) or boolean(@e)]'); +select extractValue(@xml, '/a/b[boolean(@d) or boolean(@e)]'); +select extractValue(@xml, '/a/b[boolean(@c) and boolean(@d)]'); +select extractValue(@xml, '/a/b[boolean(@c) and boolean(@e)]'); +select extractValue(@xml, '/a/b[boolean(@d) and boolean(@e)]'); + +select extractValue(@xml, '/a/b[@c or @d]'); +select extractValue(@xml, '/a/b[@c or @e]'); +select extractValue(@xml, '/a/b[@d or @e]'); +select extractValue(@xml, '/a/b[@c and @d]'); +select extractValue(@xml, '/a/b[@c and @e]'); +select extractValue(@xml, '/a/b[@d and @e]'); + +SET @xml='<a><b c="c">b1</b><b>b2</b></a>'; +SELECT extractValue(@xml,'/a/b[@*]'); +SELECT extractValue(@xml,'/a/b[not(@*)]'); + +SELECT extractValue('<a>a</a>', '/a[ceiling(3.1)=4]'); +SELECT extractValue('<a>a</a>', '/a[floor(3.1)=3]'); +SELECT extractValue('<a>a</a>', '/a[round(3.1)=3]'); +SELECT extractValue('<a>a</a>', '/a[round(3.8)=4]'); + +SELECT extractValue('<a><b>b</b><c>c</c></a>', '/a/b | /a/c'); + +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=1]'); +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=2]'); +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3]'); +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[1=position()]'); +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2=position()]'); +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[3=position()]'); +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2>=position()]'); +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2<=position()]'); +select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3 or position()=2]'); + +SELECT extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=0]'); +SELECT extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=1]'); +select extractValue('<a>a1<b ba="1" ba="2">b1</b><b>b2</b>4</a>','/a/b[sum(@ba)=3]'); + +select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[1]'); +select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[boolean(1)]'); +select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[true()]'); +select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[number(true())]'); + +select extractValue('<a>ab</a>','/a[contains("abc","b")]'); +select extractValue('<a>ab</a>','/a[contains(.,"a")]'); +select extractValue('<a>ab</a>','/a[contains(.,"b")]'); +select extractValue('<a>ab</a>','/a[contains(.,"c")]'); + +select extractValue('<a b="1">ab</a>','/a[concat(@b,"2")="12"]'); + +SET @xml='<a b="11" b="12" b="21" b="22">ab</a>'; +select extractValue(@xml, '/a/@b[substring(.,2)="1"]'); +select extractValue(@xml, '/a/@b[substring(.,2)="2"]'); +select extractValue(@xml, '/a/@b[substring(.,1,1)="1"]'); +select extractValue(@xml, '/a/@b[substring(.,1,1)="2"]'); +select extractValue(@xml, '/a/@b[substring(.,2,1)="1"]'); +select extractValue(@xml, '/a/@b[substring(.,2,1)="2"]'); + +# +# Bug#16319: XML: extractvalue() returns syntax errors for some functions +# +SET @xml='<a><b>b1</b><b>b2</b></a>'; +SELECT extractValue(@xml, '/a/b[string-length("x")=1]'); +SELECT extractValue(@xml, '/a/b[string-length("xx")=2]'); +SELECT extractValue(@xml, '/a/b[string-length("xxx")=2]'); +SELECT extractValue(@xml, '/a/b[string-length("x")]'); +SELECT extractValue(@xml, '/a/b[string-length("xx")]'); +SELECT extractValue(@xml, '/a/b[string-length()]'); +--error 1105 +SELECT extractValue(@xml, 'string-length()'); +SELECT extractValue(@xml, 'string-length("x")'); + +SET @xml='<a b="b11" b="b12" b="b21" b="22"/>'; +select extractValue(@xml,'/a/@b'); +select extractValue(@xml,'/a/@b[contains(.,"1")]'); +select extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")]'); +select extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")][2]'); + +SET @xml='<a>a1<b>b1<c>c1</c>b2</b>a2</a>'; +select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','+++++++++'); +select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1>+++++++++</c1>'); +select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1/>'); + +SET @xml='<a><b>bb</b></a>'; +select UpdateXML(@xml, '/a/b', '<b>ccc</b>'); + +SET @xml='<a aa1="aa1" aa2="aa2"><b bb1="bb1" bb2="bb2">bb</b></a>'; +select UpdateXML(@xml, '/a/b', '<b>ccc</b>'); +select UpdateXML(@xml, '/a/@aa1', ''); +select UpdateXML(@xml, '/a/@aa1', 'aa3="aa3"'); +select UpdateXML(@xml, '/a/@aa2', ''); +select UpdateXML(@xml, '/a/@aa2', 'aa3="aa3"'); +select UpdateXML(@xml, '/a/b/@bb1', ''); +select UpdateXML(@xml, '/a/b/@bb1', 'bb3="bb3"'); +select UpdateXML(@xml, '/a/b/@bb2', ''); +select UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"'); + +# +# Bug#16234 XML: Crash if ExtractValue() +# +SET @xml= '<order><clerk>lesser wombat</clerk></order>'; +select extractvalue(@xml,'order/clerk'); +select extractvalue(@xml,'/order/clerk'); + +# +# Bug#16314 XML: extractvalue() crash if vertical bar +# +select extractvalue('<a><b>B</b></a>','/a|/b'); +select extractvalue('<a><b>B</b></a>','/a|b'); +select extractvalue('<a>a<b>B</b></a>','/a|/b'); +select extractvalue('<a>a<b>B</b></a>','/a|b'); +select extractvalue('<a>a<b>B</b></a>','a|/b'); + +# +# Bug#16312 XML: extractvalue() crash if angle brackets +# +--error 1105 +select extractvalue('<a>A</a>','/<a>'); + +# +# Bug#16313 XML: extractvalue() ignores '!' in names +# +--error 1105 +select extractvalue('<a><b>b</b><b!>b!</b!></a>','//b!'); + +# +# Bug #16315 XML: extractvalue() handles self badly +# +select extractvalue('<a>A<b>B<c>C</c></b></a>','/a/descendant::*'); +select extractvalue('<a>A<b>B<c>C</c></b></a>','/a/self::*'); +select extractvalue('<a>A<b>B<c>C</c></b></a>','/a/descendant-or-self::*'); +# Bug #16320 XML: extractvalue() won't accept names containing underscores +# +select extractvalue('<A_B>A</A_B>','/A_B'); + +# +# Bug#16318: XML: extractvalue() incorrectly returns last() = 1 +# +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[position()]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=last()]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()-1]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=1]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=2]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=position()]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)-1]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=1]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=2]'); +select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=position()]'); +# +# Bug#16316: XML: extractvalue() is case-sensitive with contains() +# +select extractvalue('<a>Jack</a>','/a[contains(../a,"J")]'); +select extractvalue('<a>Jack</a>','/a[contains(../a,"j")]'); +select extractvalue('<a>Jack</a>','/a[contains(../a,"j")]' collate latin1_bin); +select extractvalue('<a>Jack</a>' collate latin1_bin,'/a[contains(../a,"j")]'); + +# +# Bug#18285: ExtractValue not returning character +# data within <![CDATA[]]> as expected +# +select ExtractValue('<tag1><![CDATA[test]]></tag1>','/tag1'); + +# +# Bug#18201: XML: ExtractValue works even if the xml fragment +# is not well-formed xml +# +select extractValue('<a>a','/a'); +select extractValue('<a>a<','/a'); +select extractValue('<a>a</','/a'); +select extractValue('<a>a</a','/a'); +select extractValue('<a>a</a></b>','/a'); +select extractValue('<a b=>a</a>','/a'); + +# +# Bug #18171 XML: ExtractValue: the XPath position() +# function crashes the server! +# +--error 1105 +select extractValue('<e>1</e>','position()'); +--error 1105 +select extractValue('<e>1</e>','last()'); + + +# +# Bug #18172 XML: Extractvalue() accepts mallformed +# XPath without a XPath syntax error +# +--error 1105 +select extractValue('<e><a>1</a></e>','/e/'); + +# +# Bug#16233: XML: ExtractValue() fails with special characters +# +set names utf8; +select extractValue('<Ñ><r>r</r></Ñ>','/Ñ/r'); +select extractValue('<r><Ñ>Ñ</Ñ></r>','/r/Ñ'); +select extractValue('<Ñ r="r"/>','/Ñ/@r'); +select extractValue('<r Ñ="Ñ"/>','/r/@Ñ'); +--disable_warnings +DROP PROCEDURE IF EXISTS p2; +--enable_warnings +DELIMITER //; +CREATE PROCEDURE p2 () +BEGIN + DECLARE p LONGTEXT CHARACTER SET UTF8 DEFAULT '<Ñ><r>A</r></Ñ>'; + SELECT EXTRACTVALUE(p,'/Ñ/r'); +END// +DELIMITER ;// +CALL p2(); +DROP PROCEDURE p2; + +# +# Bug#18170: XML: ExtractValue(): +# XPath expression can't use QNames (colon in names) +# +select extractValue('<ns:element xmlns:ns="myns"/>','count(ns:element)'); +select extractValue('<ns:element xmlns:ns="myns">a</ns:element>','/ns:element'); +select extractValue('<ns:element xmlns:ns="myns">a</ns:element>','/ns:element/@xmlns:ns'); + +# +# Bug#20795 extractvalue() won't accept names containing a dot (.) +# +select extractValue('<foo><foo.bar>Data</foo.bar><something>Otherdata</something></foo>','/foo/foo.bar'); +select extractValue('<foo><foo.bar>Data</foo.bar><something>Otherdata</something></foo>','/foo/something'); + +# +# Bug#20854 XML functions: wrong result in ExtractValue +# +--error 1105 +select extractValue('<zot><tim0><01>10:39:15</01><02>140</02></tim0></zot>','/zot/tim0/02'); +select extractValue('<zot><tim0><01>10:39:15</01><02>140</02></tim0></zot>','//*'); +# dot and dash are bad identtifier start character +select extractValue('<.>test</.>','//*'); +select extractValue('<->test</->','//*'); +# semicolon is good identifier start character +select extractValue('<:>test</:>','//*'); +# underscore is good identifier start character +select extractValue('<_>test</_>','//*'); +# dot, dash, underscore and semicolon are good identifier middle characters +select extractValue('<x.-_:>test</x.-_:>','//*'); + +# +# Bug#22823 gt and lt operators appear to be +# reversed in ExtractValue() command +# +set @xml= "<entry><id>pt10</id><pt>10</pt></entry><entry><id>pt50</id><pt>50</pt></entry>"; +select ExtractValue(@xml, "/entry[(pt=10)]/id"); +select ExtractValue(@xml, "/entry[(pt!=10)]/id"); +select ExtractValue(@xml, "/entry[(pt<10)]/id"); +select ExtractValue(@xml, "/entry[(pt<=10)]/id"); +select ExtractValue(@xml, "/entry[(pt>10)]/id"); +select ExtractValue(@xml, "/entry[(pt>=10)]/id"); +select ExtractValue(@xml, "/entry[(pt=50)]/id"); +select ExtractValue(@xml, "/entry[(pt!=50)]/id"); +select ExtractValue(@xml, "/entry[(pt<50)]/id"); +select ExtractValue(@xml, "/entry[(pt<=50)]/id"); +select ExtractValue(@xml, "/entry[(pt>50)]/id"); +select ExtractValue(@xml, "/entry[(pt>=50)]/id"); +select ExtractValue(@xml, "/entry[(10=pt)]/id"); +select ExtractValue(@xml, "/entry[(10!=pt)]/id"); +select ExtractValue(@xml, "/entry[(10>pt)]/id"); +select ExtractValue(@xml, "/entry[(10>=pt)]/id"); +select ExtractValue(@xml, "/entry[(10<pt)]/id"); +select ExtractValue(@xml, "/entry[(10<=pt)]/id"); +select ExtractValue(@xml, "/entry[(50=pt)]/id"); +select ExtractValue(@xml, "/entry[(50!=pt)]/id"); +select ExtractValue(@xml, "/entry[(50>pt)]/id"); +select ExtractValue(@xml, "/entry[(50>=pt)]/id"); +select ExtractValue(@xml, "/entry[(50<pt)]/id"); +select ExtractValue(@xml, "/entry[(50<=pt)]/id"); diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment.result b/mysql-test/suite/rpl/r/rpl_auto_increment.result index 2a4c3a09361..17aa592654f 100644 --- a/mysql-test/suite/rpl/r/rpl_auto_increment.result +++ b/mysql-test/suite/rpl/r/rpl_auto_increment.result @@ -37,7 +37,7 @@ a b 32 6 drop table t1; set @@session.auto_increment_increment=100, @@session.auto_increment_offset=10; -show variables like "%auto_inc%"; +show variables like "auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 7105d7e04f0..16fc5437dc7 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -41,7 +41,8 @@ create view v1 (c) as SELECT table_name FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND - table_name<>'ndb_apply_status'; + table_name<>'ndb_apply_status' AND + NOT (table_schema = 'INFORMATION_SCHEMA' AND table_name LIKE 'PBXT_%'); select * from v1; select c,table_name from v1 @@ -529,13 +530,6 @@ delete from mysql.db where user='mysqltest_4'; flush privileges; # -# Bug #9404 information_schema: Weird error messages -# with SELECT SUM() ... GROUP BY queries -# -SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; - - -# # TRIGGERS table test # create table t1 (i int, j int); @@ -898,39 +892,6 @@ DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; # -# Bug#18925: subqueries with MIN/MAX functions on INFORMARTION_SCHEMA -# - -SELECT t.table_name, c1.column_name - FROM information_schema.tables t - INNER JOIN - information_schema.columns c1 - ON t.table_schema = c1.table_schema AND - t.table_name = c1.table_name - WHERE t.table_schema = 'information_schema' AND - c1.ordinal_position = - ( SELECT COALESCE(MIN(c2.ordinal_position),1) - FROM information_schema.columns c2 - WHERE c2.table_schema = t.table_schema AND - c2.table_name = t.table_name AND - c2.column_name LIKE '%SCHEMA%' - ); -SELECT t.table_name, c1.column_name - FROM information_schema.tables t - INNER JOIN - information_schema.columns c1 - ON t.table_schema = c1.table_schema AND - t.table_name = c1.table_name - WHERE t.table_schema = 'information_schema' AND - c1.ordinal_position = - ( SELECT COALESCE(MIN(c2.ordinal_position),1) - FROM information_schema.columns c2 - WHERE c2.table_schema = 'information_schema' AND - c2.table_name = t.table_name AND - c2.column_name LIKE '%SCHEMA%' - ); - -# # Bug#21231: query with a simple non-correlated subquery over # INFORMARTION_SCHEMA.TABLES # @@ -1007,29 +968,6 @@ drop table t1,t2; # -# Bug#24630 Subselect query crashes mysqld -# -select 1 as f1 from information_schema.tables where "CHARACTER_SETS"= -(select cast(table_name as char) from information_schema.tables - order by table_name limit 1) limit 1; - -select t.table_name, group_concat(t.table_schema, '.', t.table_name), - count(*) as num1 -from information_schema.tables t -inner join information_schema.columns c1 -on t.table_schema = c1.table_schema AND t.table_name = c1.table_name -where t.table_schema = 'information_schema' and - c1.ordinal_position = - (select isnull(c2.column_type) - - isnull(group_concat(c2.table_schema, '.', c2.table_name)) + - count(*) as num - from information_schema.columns c2 where - c2.table_schema='information_schema' and - (c2.column_type = 'varchar(7)' or c2.column_type = 'varchar(20)') - group by c2.column_type order by num limit 1) -group by t.table_name order by num1, t.table_name; - -# # Bug#28266 IS_UPDATABLE field on VIEWS table in I_S database is wrong # create table t1(f1 int); diff --git a/mysql-test/t/information_schema_all_engines.test b/mysql-test/t/information_schema_all_engines.test new file mode 100644 index 00000000000..4fb145b1406 --- /dev/null +++ b/mysql-test/t/information_schema_all_engines.test @@ -0,0 +1,79 @@ +# This file contains tests moved from information_schema.test and +# information_schema_db.test whose results depends on which engines are +# available (since these engines inject tables into INFORMATION_SCHEMA). + +--source include/not_embedded.inc +--source include/have_pbxt.inc + +use INFORMATION_SCHEMA; +--replace_result Tables_in_INFORMATION_SCHEMA Tables_in_information_schema +show tables; + +# +# Bug#18925: subqueries with MIN/MAX functions on INFORMARTION_SCHEMA +# + +SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN + information_schema.columns c1 + ON t.table_schema = c1.table_schema AND + t.table_name = c1.table_name + WHERE t.table_schema = 'information_schema' AND + c1.ordinal_position = + ( SELECT COALESCE(MIN(c2.ordinal_position),1) + FROM information_schema.columns c2 + WHERE c2.table_schema = t.table_schema AND + c2.table_name = t.table_name AND + c2.column_name LIKE '%SCHEMA%' + ); +SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN + information_schema.columns c1 + ON t.table_schema = c1.table_schema AND + t.table_name = c1.table_name + WHERE t.table_schema = 'information_schema' AND + c1.ordinal_position = + ( SELECT COALESCE(MIN(c2.ordinal_position),1) + FROM information_schema.columns c2 + WHERE c2.table_schema = 'information_schema' AND + c2.table_name = t.table_name AND + c2.column_name LIKE '%SCHEMA%' + ); + +# +# Bug#24630 Subselect query crashes mysqld +# +select 1 as f1 from information_schema.tables where "CHARACTER_SETS"= +(select cast(table_name as char) from information_schema.tables + order by table_name limit 1) limit 1; + +select t.table_name, group_concat(t.table_schema, '.', t.table_name), + count(*) as num1 +from information_schema.tables t +inner join information_schema.columns c1 +on t.table_schema = c1.table_schema AND t.table_name = c1.table_name +where t.table_schema = 'information_schema' and + c1.ordinal_position = + (select isnull(c2.column_type) - + isnull(group_concat(c2.table_schema, '.', c2.table_name)) + + count(*) as num + from information_schema.columns c2 where + c2.table_schema='information_schema' and + (c2.column_type = 'varchar(7)' or c2.column_type = 'varchar(20)') + group by c2.column_type order by num limit 1) +group by t.table_name order by num1, t.table_name; + +# +# Bug #19147: mysqlshow INFORMATION_SCHEMA does not work +# +--exec $MYSQL_SHOW information_schema +--exec $MYSQL_SHOW INFORMATION_SCHEMA +--exec $MYSQL_SHOW inf_rmation_schema + +# +# Bug #9404 information_schema: Weird error messages +# with SELECT SUM() ... GROUP BY queries +# +SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test index 6353e94fd51..2850c794393 100644 --- a/mysql-test/t/information_schema_db.test +++ b/mysql-test/t/information_schema_db.test @@ -11,9 +11,6 @@ drop function if exists f1; drop function if exists f2; --enable_warnings -use INFORMATION_SCHEMA; ---replace_result Tables_in_INFORMATION_SCHEMA Tables_in_information_schema -show tables; --replace_result 'Tables_in_INFORMATION_SCHEMA (T%)' 'Tables_in_information_schema (T%)' show tables from INFORMATION_SCHEMA like 'T%'; create database `inf%`; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index e6b804c4fff..4d2afa28e9d 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -156,7 +156,7 @@ DROP TABLE t1; # # Test changes to AUTOINC next value calculation SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES (NULL),(5),(NULL); @@ -173,7 +173,7 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(0); @@ -193,13 +193,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL); INSERT INTO t1 VALUES (250),(NULL); SELECT * FROM t1; @@ -214,13 +214,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2); INSERT INTO t1 VALUES (NULL); INSERT INTO t1 VALUES (2); @@ -240,13 +240,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL); INSERT INTO t1 VALUES (250),(NULL); SELECT * FROM t1; @@ -262,7 +262,7 @@ DROP TABLE t1; # Check for overflow handling when increment is > 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -271,7 +271,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (9223372036854775794); #-- 2^63 - 14 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # This should just fit INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); SELECT * FROM t1; @@ -281,7 +281,7 @@ DROP TABLE t1; # Check for overflow handling when increment and offser are > 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -290,7 +290,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # This should fail because of overflow but it doesn't, it seems to be # a MySQL server bug. It wraps around to 0 for the last value. # See MySQL Bug# 39828 @@ -313,7 +313,7 @@ DROP TABLE t1; # Check for overflow handling when increment and offset are odd numbers SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -322,7 +322,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # This should fail because of overflow but it doesn't. It fails with # a duplicate entry message because of a MySQL server bug, it wraps # around. See MySQL Bug# 39828, once MySQL fix the bug we can replace @@ -344,7 +344,7 @@ DROP TABLE t1; # and check for large -ve numbers SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -355,7 +355,7 @@ INSERT INTO t1 VALUES(-9223372036854775807); #-- -2^63 + 1 INSERT INTO t1 VALUES(-9223372036854775808); #-- -2^63 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; INSERT INTO t1 VALUES (NULL),(NULL), (NULL); SELECT * FROM t1; DROP TABLE t1; @@ -364,7 +364,7 @@ DROP TABLE t1; # large numbers 2^60 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -373,7 +373,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; -SHOW VARIABLES LIKE "%auto_inc%"; +SHOW VARIABLES LIKE "auto_inc%"; # This should fail because of overflow but it doesn't. It wraps around # and the autoinc values look bogus too. # See MySQL Bug# 39828, once MySQL fix the bug we can enable the error diff --git a/mysql-test/t/mysqlshow.test b/mysql-test/t/mysqlshow.test index 9ed93079f57..b545a430481 100644 --- a/mysql-test/t/mysqlshow.test +++ b/mysql-test/t/mysqlshow.test @@ -26,11 +26,4 @@ select "---- -v -v -t ------" as ""; --exec $MYSQL_SHOW test -v -v -t DROP TABLE t1, t2; -# -# Bug #19147: mysqlshow INFORMATION_SCHEMA does not work -# ---exec $MYSQL_SHOW information_schema ---exec $MYSQL_SHOW INFORMATION_SCHEMA ---exec $MYSQL_SHOW inf_rmation_schema - --echo End of 5.0 tests diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 8d578cd22cb..f30f5d2e3c5 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -379,7 +379,7 @@ } { - dlclose memory loss from plugin + dlclose memory loss from plugin variant 1 Memcheck:Leak fun:calloc fun:_dlerror_run @@ -388,6 +388,19 @@ } { + dlclose memory loss from plugin variant 2 + Memcheck:Leak + fun:malloc + fun:_dl_close_worker + fun:_dl_close + fun:_dl_catch_error + fun:_dlerror_run + fun:dlclose + fun:_Z15free_plugin_memP12st_plugin_dl + fun:_Z13plugin_dl_delPK19st_mysql_lex_string +} + +{ dlopen / ptread_cancel_init memory loss on Suse Linux 10.3 32/64 bit Memcheck:Leak fun:*alloc @@ -588,3 +601,19 @@ fun:dlopen* } +# +# In glibc (checked version 2.7), inet_ntoa allocates an 18-byte +# per-thread static buffer for the return value. That memory is freed +# at thread exit, however if called from the main thread, Valgrind +# does not see the free (test main.no-threads). +# +# Since inet_ntoa() does not allocate memory dynamically per-call, this +# suppression is safe. +# + +{ + inet_ntoa thread local storage + Memcheck:Leak + fun:malloc + fun:inet_ntoa +} diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4a75c8452e9..7a988f1cbad 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4815,10 +4815,10 @@ static bool read_init_file(char *file_name) DBUG_ENTER("read_init_file"); DBUG_PRINT("enter",("name: %s",file_name)); if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME)))) - return(1); + DBUG_RETURN(1); bootstrap(file); (void) my_fclose(file,MYF(MY_WME)); - return 0; + DBUG_RETURN(0); } @@ -4839,6 +4839,7 @@ void handle_connection_in_main_thread(THD *thd) safe_mutex_assert_owner(&LOCK_thread_count); thread_cache_size=0; // Safety threads.append(thd); + thd->connect_utime= my_micro_time(); (void) pthread_mutex_unlock(&LOCK_thread_count); handle_one_connection((void*) thd); } @@ -4974,7 +4975,7 @@ inline void kill_broken_server() #if !defined(__NETWARE__) unix_sock == INVALID_SOCKET || #endif - (!opt_disable_networking && ip_sock == INVALID_SOCKET)) + (!opt_disable_networking && base_ip_sock == INVALID_SOCKET)) { select_thread_in_use = 0; /* The following call will never return */ diff --git a/sql/set_var.cc b/sql/set_var.cc index 7ca6fe4d979..c6650702cf9 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1740,7 +1740,7 @@ bool sys_var::check_enum(THD *thd, set_var *var, const TYPELIB *enum_names) { char buff[STRING_BUFFER_USUAL_SIZE]; const char *value; - String str(buff, sizeof(buff), system_charset_info), *res; + String str(buff, sizeof(buff) - 1, system_charset_info), *res; if (var->value->result_type() == STRING_RESULT) { @@ -1777,7 +1777,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) bool not_used; char buff[STRING_BUFFER_USUAL_SIZE], *error= 0; uint error_len= 0; - String str(buff, sizeof(buff), system_charset_info), *res; + String str(buff, sizeof(buff) - 1, system_charset_info), *res; if (var->value->result_type() == STRING_RESULT) { @@ -1795,7 +1795,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) } var->save_result.ulong_value= ((ulong) - find_set(enum_names, res->c_ptr(), + find_set(enum_names, res->ptr(), res->length(), NULL, &error, &error_len, @@ -1942,7 +1942,7 @@ bool sys_var_thd_date_time_format::update(THD *thd, set_var *var) bool sys_var_thd_date_time_format::check(THD *thd, set_var *var) { char buff[STRING_BUFFER_USUAL_SIZE]; - String str(buff,sizeof(buff), system_charset_info), *res; + String str(buff,sizeof(buff) - 1, system_charset_info), *res; DATE_TIME_FORMAT *format; if (!(res=var->value->val_str(&str))) @@ -2047,7 +2047,7 @@ bool sys_var_collation::check(THD *thd, set_var *var) if (var->value->result_type() == STRING_RESULT) { char buff[STRING_BUFFER_USUAL_SIZE]; - String str(buff,sizeof(buff), system_charset_info), *res; + String str(buff,sizeof(buff) - 1, system_charset_info), *res; if (!(res=var->value->val_str(&str))) { my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, "NULL"); @@ -2082,7 +2082,7 @@ bool sys_var_character_set::check(THD *thd, set_var *var) if (var->value->result_type() == STRING_RESULT) { char buff[STRING_BUFFER_USUAL_SIZE]; - String str(buff,sizeof(buff), system_charset_info), *res; + String str(buff,sizeof(buff) - 1, system_charset_info), *res; if (!(res=var->value->val_str(&str))) { if (!nullable) @@ -3620,7 +3620,7 @@ bool sys_var_thd_storage_engine::check(THD *thd, set_var *var) { char buff[STRING_BUFFER_USUAL_SIZE]; const char *value; - String str(buff, sizeof(buff), &my_charset_latin1), *res; + String str(buff, sizeof(buff) - 1, &my_charset_latin1), *res; var->save_result.plugin= NULL; if (var->value->result_type() == STRING_RESULT) @@ -3737,7 +3737,7 @@ sys_var_thd_sql_mode:: symbolic_mode_representation(THD *thd, ulonglong val, LEX_STRING *rep) { char buff[STRING_BUFFER_USUAL_SIZE*8]; - String tmp(buff, sizeof(buff), &my_charset_latin1); + String tmp(buff, sizeof(buff) - 1, &my_charset_latin1); tmp.length(0); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 723c483a7a8..7bf44183f2d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1994,8 +1994,17 @@ JOIN::exec() tmp_fields_list2, tmp_all_fields2, fields_list.elements, tmp_all_fields1)) DBUG_VOID_RETURN; - curr_join->tmp_fields_list2= tmp_fields_list2; - curr_join->tmp_all_fields2= tmp_all_fields2; +#ifdef HAVE_purify + /* + Some GCCs use memcpy() for struct assignment, even for x=x. + GCC bug 19410: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19410 + */ + if (curr_join != this) +#endif + { + curr_join->tmp_fields_list2= tmp_fields_list2; + curr_join->tmp_all_fields2= tmp_all_fields2; + } } curr_fields_list= &curr_join->tmp_fields_list2; curr_all_fields= &curr_join->tmp_all_fields2; diff --git a/sql/sql_string.h b/sql/sql_string.h index be11fea70dc..9088863ac4d 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -63,6 +63,11 @@ public: Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0; str_charset=cs; } + /* + NOTE: If one intend to use the c_ptr() method, the following two + contructors need the size of memory for STR to be at least LEN+1 (to make + room for zero termination). + */ String(const char *str,uint32 len, CHARSET_INFO *cs) { Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0; diff --git a/storage/archive/azio.c b/storage/archive/azio.c index 59fbe2182ee..6d088f279ac 100644 --- a/storage/archive/azio.c +++ b/storage/archive/azio.c @@ -37,6 +37,40 @@ void putLong(File file, uLong x); uLong getLong(azio_stream *s); void read_header(azio_stream *s, unsigned char *buffer); +/* + Valgrind normally gives false alarms for zlib operations, in the form of + "conditional jump depends on uninitialised values" etc. The reason is + explained in the zlib FAQ (http://www.zlib.net/zlib_faq.html#faq36): + + "That is intentional for performance reasons, and the output of deflate + is not affected." + + Also discussed on a blog + (http://www.sirena.org.uk/log/2006/02/19/zlib-generating-valgrind-warnings/): + + "...loop unrolling in the zlib library causes the mentioned + “Conditional jump or move depends on uninitialised value(s)†+ warnings. These are safe since the results of the comparison are + subsequently ignored..." + + "the results of the calculations are discarded by bounds checking done + after the loop exits" + + Fix by initializing the memory allocated by zlib when running under Valgrind. + + This fix is safe, since such memory is only used internally by zlib, so we + will not hide any bugs in mysql this way. +*/ +static void *az_allocator(void *dummy, uInt items, uInt size) +{ + return my_malloc((size_t)items*(size_t)size, IF_PURIFY(MY_ZEROFILL, MYF(0))); +} + +static void az_free(void *dummy, void *address) +{ + my_free(address, MYF(MY_ALLOW_ZERO_PTR)); +} + /* =========================================================================== Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb"). The file is given either by file descriptor @@ -52,8 +86,8 @@ int az_open (azio_stream *s, const char *path, int Flags, File fd) int level = Z_DEFAULT_COMPRESSION; /* compression level */ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; + s->stream.zalloc = az_allocator; + s->stream.zfree = az_free; s->stream.opaque = (voidpf)0; memset(s->inbuf, 0, AZ_BUFSIZE_READ); memset(s->outbuf, 0, AZ_BUFSIZE_WRITE); diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index f868609bbfe..b675b0e8a3f 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -2874,7 +2874,7 @@ static my_bool write_block_record(MARIA_HA *info, if (cur_block->used & BLOCKUSED_TAIL) { DBUG_ASSERT(data_length < MAX_TAIL_SIZE(block_size)); - /* tail written to full tail page */ + /* tail written to tail page */ cur_block->used|= BLOCKUSED_USED; head_tail_block= cur_block; } diff --git a/storage/pbxt/AUTHORS b/storage/pbxt/AUTHORS new file mode 100644 index 00000000000..3c5c3db6db8 --- /dev/null +++ b/storage/pbxt/AUTHORS @@ -0,0 +1,4 @@ +Paul McCullagh +paul.mccullagh@primebase.org +http://www.primebase.org +http://pbxt.blogspot.com diff --git a/storage/pbxt/ChangeLog b/storage/pbxt/ChangeLog new file mode 100644 index 00000000000..958bcd81cd1 --- /dev/null +++ b/storage/pbxt/ChangeLog @@ -0,0 +1,689 @@ +PBXT Release Notes +================== + +------- 1.0.08 RC - Not yet released + +RN233: Fixed bugs which occur when PBXT is used together with PBMS (BLOB Streaming engine). + +RN232: Merged Drizzle-specific changes into the main tree. + +RN231: Fixed a bug that caused bad performance as the number of threads increased. This occurred when the number of open table handles exceeded 'table_open_cache', and MySQL started closing open table handlers. PBXT was flushing a table when all table handlers were closed. PBXT will now only do this when the FLUSH TABLES statement is used. + +RN230: Improved efficiency of conflict resolution: Implemented a queue for threads waiting for a lock. Threads no longer poll to take a lock. If a temp lock is granted because of an update, then the thread granted the temp lock will also wait for the transaction that did the update to quit. + +RN229: Fixed bug #313391: LOAD DATA ... REPLACE broken. + +RN228: Fixed bug #341115: 'Out of memory' error (a bug in key comparison algorithm). + +RN227: Changed conflict handling to use spin locks and improve efficiency. + +RN226: Fixed bug #340316: Issue with bigint unsigned auto-increment field. + +RN225: Fixed bug #308557: UPDATE fails to match all rows in a transactional scenario. + +RN224: Fixed a deadlock which could occur during table scans. + +RN223: Index scans now use handles to cache buffers instead of making a copy of the index page. The handles are "copy-on-write". + +RN222: Fixed a bug that caused the server to hang on startup if PBXT ran out of record cache while waiting for the sweeper to complete. + +RN221: Fixed an index recovery bug. This occurred if the server crashed after operating in low index cache sitations. + +RN220: Improved index selectivity estimation: added scanning from the end of index backwards. + +RN219: Fixed a problem: during intersected range scan not all fields were returned by engine to MySQL. + +RN218: Changed the way row locking (used by SELECT FOR UPDATE) works. Previously we locked a group of rows at once (although there were many groups). However, this caused conflicts even when the same rows were not locked. We now locks individual rows. + +RN217: Fixed bug #315564: Rollbacked inserts remain permanently in table. + +RN216: Added lock tracing. In DEBUG mode, each thread has a list of locks (semaphores, mutexes, r/w locks that it holds). + +RN215: Fixed a bug that caused a crash during restart if an index file was flushed during recovery. + +RN214: Fixed bug #310184: Deadlock when trying to wake up transactions + +RN213: Fixed an index corruption bug on SPARC Solaris. Note this error will occur on any machine that does not use the x86 (little endian) byte order. + +------- 1.0.07 RC - 2008-12-15 + +RN212: Fixed build problems on NetBSD. + +RN211: Fixed build problems on FreeBSD. + +RN210: Fixed build problems on OpenSolaris. + +RN209: Added handling of the foreign_key_checks system flag. + +RN208: xtstat will now automatically reconnect if the connection to server is lost. + +RN207: Foreign key references are now checked on CREATE TABLE. + +RN206: Fixed a crash if inserting into a table that has an FK that references a column that has no index on it. + +RN205: Added processing of foreign key action SET DEFAULT. + +RN204: Fixed an index recovery problem: unswept index entries were not recovered correctly + +RN203: Fixed foreign key bug: REPLACE fails with 'on delete cascade' + +RN202: Fixes and updates to tests, now all tests pass on windows and linux. + +RN201: Fixed ref-counting for mmapped files. + +RN200: Fixed an index recovery problem: unswept index entries were not recovered correctly . + +RN199: Recovery now takes place on plug-in startup. Previously recovery occurred when the first PBXT table was accessed. + +RN198: Fixed a recovery bug that caused index entries to get out of sync with the data file. + +RN197: Improved the efficiency of group commit. + +RN196: Changed checkpointing so that it now works during idle time. Every record, row or index file fllush now also contributes to the checkpoint (fuzzy checkpointing). Checkpointing is forced to complete after about 50% of the checkpoint threshold in order to ensure the correct maximum for log reading on recovery. + +RN195: Fixed scheduling bug that caused sweeper to get behind with the cleanup, which caused performance problems in high conflict situations. Foreground threads will now wait if the sweeper gets too far behind. + +RN194: Created the xtstat program which monitors the internal performance of PBXT. Run xtstat --help for more details information of the output. + +RN193: Implemented the pbxt.statistics virtual table. The statistics table returns information about the internal activity of the engine. This includes I/O byte counts, cache hit counts and usage, commit count, etc. + +RN192: Due to timing issues in the engine API it could happen that the client received an OK for a committed transaction before the transaction was actually committed. This problem has been fixed. + +RN191: Fixed a bug that caused a hang when conflicts occured while reading a covering index. + +RN190: Previously the sweeper delayed deletion of transaction structures until all transactions that were running during sweeping have quit. This is now handled by the same code that fixed the bug in RN189. + +RN189: Fixed a bug that could cause a row to go missing due to a visibility issue. + +RN188: Fixed a bug which ocurred when using CREATE TABLE ... AVG_ROW_LENGTH=x, and the table contained BLOBs. In this case, alter table corrupted the table. + +RN187: Windows now stores paths in the location file in UNIX format by converting all '\' characters to '/'. Note that the location file is only cross-platform if the paths are relative (which is the default). + +RN186: Set version number to 1.0.07. + +------- 1.0.06 Beta 2 - 2008-11-06 + +RN185: Disabled support for INSERT DELAYED because of MySQL bug #40505 + +RN184: Implemented info(flag == HA_STATUS_AUTO) engine API call. This call returns the next value that will be assigned as auto-increment value on the table. + +RN183: Turned off streaming on Windows (see XT_STREAMING macro in sources) + +RN182: Switch code base to the latest version of BLOB streaming engine (PBMS): www.blobstreaming.org. + +RN181: Updated pbxt-test-run default parameters (--force is on, --default-storage-engine is pbxt, --base-dir is set according to config) + +RN180: PBXT can now cope with a missing .xti file (the file that contains the table indexes). This file can be regenerated using REPAIR TABLE. + +RN179: On recovery PBXT now creates a filed called 'recovery-progress' in the pbxt database. The recovery percentage complete is written to this file as recovery progresses. Note that this file will not be created if no recoery is necessary or if PBXT estimates that it will read less then 10MB to do recovery. + +RN178: Fixed a problem in CHECK TABLE that caused memory corruption for fixed-size records + +RN177: Added "crash debugging". When enabled, crash debugging does the following: + - Create a core dump on Windows if the server crashes. + - Make a backup copy of the datadir directory before recovery if the server crashes. + - Keep at least 5 of the previous transaction logs. +Currently crash debugging is disabled by default. To disable, create a file called 'no-debug' in the pbxt database folder, and restart the server. When crash debugging is disabled by default, it can be enabled by creating a file called 'crash-debug; in the pbxt database folder. + +RN176: Fixed a bug: a lock was not released appropriately + +RN175: Fixed some debug assertions + +RN174: Fixed some of test/mysql-test tests + +RN173: Fixed a RENAME TABLE bug, that prevented index files from being properly recreated + +RN172: Added the file ./pbxt/lock-pid. This file is locked while the server is running, and contains the process of the server. PBXT will return an error on startup if the file is locked or the process is still running in order to prevent a second server from being started. + +RN171: Implemented the AVG_ROW_LENGTH table attribute. When set, this value determines the size of the fixed length data component of a record. Normally this size is estimated depending on the column definitions. The command CHECK TABLE dumps the current average row length to the log. This can be used to find a suitable value for AVG_ROW_LENGTH. + +RN170: Changed configure so that debug/optimize flags set for building the engine override the flags set for MySQL. If --with-debug is not specified, then the engine will use the flags set when building MySQL. If MySQL was built with --with-debug=full, the DEBUG will be defined for the engine. When building the engine, the following flags can be set: + yes - Debug symbols enabled, no optimization, DEBUG not defined. + full - Debug symbols enabled, no optimization, DEBUG defined. + only - Debug symbols enabled, MySQL flags used, DEBUG not defined. + prof - Profile code enabled, optimization on, DEBUG not defined. + no - No debug symbols, optimization on, DEBUG not defined. + +RN169: Used MySQL root Makefile instead of config.status in order to extract settings (such as CFLAGS and CXXFLAGS) for the PBXT build. + +RN168: Fixed Windows build after merging changes for Drizzle. + +RN167: Fixed "This table requires primary key" error in sql-bench. + +RN166: Fixed threading problems that caused crashes in sql-bench. + +RN165: Added sql-bench to pbxt source tree. + +RN164: Ported PBXT to Drizzle. To compile for Drizzle DRIZZLED must be defined on the command line. The -drz.am and -drz.in files are must be used when PBXT is embedded in Drizzle. + +RN163: Added "make test" build step. Running "make test" from the root of pbxt source tree will launch test/mysql-test/pbxt-test-run.pl with appropriate options to execute the pbxt functional test suite. On Windows where +pbxt is statically linked into mysql server binary pbxt testing works by going to test/mysql-test directory and running ./pbxt-test-run.pl with --base-dir argument pointing to a mysql source tree (mysql binaries are taken +from there) and passing the rest of usual arguments (--force --mysqld=--default-storage-engine=pbxt) + +RN162: The 'pbxt' database must now be dropped explicitly. It is automatically created when the first PBXT table is created. After that, the pbxt database can be dropped once all PBXT tables have been dropped. Dropping the pbxt database will also cause all transaction (pbxt/system directory) and data logs (pbxt/data directory) to also be deleted. + +RN161: Added pbxt.location system table. This table can only be dropped when all PBXT tables have been deleted. Dropping the system table will cause all transaction (pbxt/system directory) and data logs (pbxt/data directory) to also be deleted. + +RN160: Made changes to run with MySQL 6.0.6. + +RN159: Changes to configure: added --with-plugindir=<path>, which should be used to specify the plugin directory. This means that --libdir should no longer be used. For backwards compatibility configure will still recognize this options if the path ends with 'plugin'. + +Also updated --help, to include all options, and better desciptions of the options. + +The configure options are now as follows: + +--with-mysql=<path> - (Required) It specifies the path to the MySQL source tree. The source should already be built. All other options will be taken from the MySQL build by default. +--with-debug=yes/no - (Optional) Specify if then engine should be built with different debug options to the MySQL source tree. +--with-plugindur=<path> - (Optional) Specify an alternative installation directory for the plugin. By default it will be installed in the plugin directory of the MySQL installation. + + +RN158: Added support for core dumps on Windows. This can be enabled by defining XT_COREDUMP. On by default at the moment. If the server crashes a file called PBXTCore00000001.dmp will be created in the data directory. This file can be openned using MS VS. + +RN157: Fixed a compile problem with tv_nsec which is not supported on all platforms. + +RN156: Updated tests to run with MySQL 5.1.28. + +RN155: Errors during cascade update of VARCHAR values with trailing spaces + +RN154: Fixed a bug: impossible to create a foreign key that referenced an ENUM or SET column + +RN153: Fixed a bug that caused the following problems: #1. Foreign keys: crash if update cascade and autocommit=0 #2. Foreign keys: crash if update cascade and multi-level recursion + +RN152: Fixed missing information about foreign keys in I_S.table_constraints and I_S.referential_constraints + +------- 1.0.05 Beta - 2008-08-30 + +RN151: "Quick config": It is now possible to configure the engine by just specifying the mysql source code tree (the --with-mysql option). The --libdir and --with-debug setting will be deduced automatically. + +RN150: Added system variable pbxt_sweeper_priority, 0 = low (default), 1 = normal (same as user threads), 2 = high. The sweeper cleans up deleted records (deleted records also result from an update). If allowed to accumulate, these records can slow searches. Higher priority for the sweeper is recommended on systems with 4 or more cores. + +RN149: Record cleanup is now initiated if a deleted record is found, and the transaction that deleted the record has ended. Since waking up the sweeper is an expensive operation, normally the sweeper will run every 1/10th of a second. + +RN148: Fixed a bug which caused transaction starvation (one transaction was constantly locked out) during high conflict updates. This lead to cleanup of records not being done, which lead to a general slow down. + +RN147: Fixed a problem with TRUNCATE TABLE: a failed TRUNCATE TABLE could put the engine into an invalid state that later caused a crash + +RN146: Fixed a bug that caused the error: "-49: Record format unknown, either corrupted or upgrade required". + +RN145: Added pbxt_db_offline_log_function system variable, 0 = recycle logs (default), 1 = delete logs (default on Mac OS X), 2 = keep logs. + +------- 1.0.04 Alpha - 2008-08-02 + +RN144: Completed port and testing of Windows version. + +RN143: Fixed a bug which caused the free-er thread to hang. This was a result of an invalid operation ID, which was the result of the checkpointer flushing the table at the same time as a foreground thread. + +RN142: The fast RW/mutex lock can now handle nested calls. This is possible during a sequential scan. + +RN141: The normal behavior in MySQL is that an auto-increment values will be re-issued if you delete the row containing the current maximum auto-increment value and then restart the server. To prevent this you can use ALTER TABLE my_table AUTO_INCREMENT = <current-max-auto-increment> + 1, before deleting the current maximum auto-increment value. + +A new system variable, pbxt_auto_increment_mode, has been added so that this work around is not necessary. When set to 0 (the default), auto-increment works as described above. When set to 1, the AUTO_INCREMENT value of the table is automatically to prevent previously issued auto-increment values being returned. + +However, if the server crashes, a gap of up to 100 unique values can result, because the table AUTO_INCREMENT value is incremented in steps of 100. + +RN140: Index statistics are now automatically recalculated when the table row count exceeds 200. + +RN139: Fixed a bug that caused index corruption, error: "int idx_push(index_xt.cc:172) -2: Core B-tree too deep". + +RN138: Handle startup and recovery when an index is corrupted. + +RN137: Fixed a bug in the zero wait R/W lock that caused the lock to fail (the state is extremely volatile, and must be written to memory after increment). + +RN136: Fixed a bug that cause the error "int xt_pwrite_file(filesys_xt.cc:789) errno (14): Bad address". + +RN135: Fixed TRUNCATE TABLE that did not work correctly when the table contained BLOBs stored in the BLOB streaming engine (www.blobstreaming.org). + +RN134: Fixed a bug that caused duplicate rows to be returned from an index scan (using a SELECT FOR UPDATE) if a concurrent update was done. + +RN133: Optimised PBXT for multi-processor scale-up. This mostly involved using different types of locks instead of the standard pthread mutex and reader/writer locks [TODO: 0038]. + +------- 1.0.03 Alpha - 2008-05-30 + +RN132: Fixed bug when using PBXT in conjunction with the BLOB streaming engine (www.blobstreaming.org). Uploaded BLOBs could not be inserted into a table. + +RN131: Fixed wait for background processes on shutdown. Shutdown will wait a maximum of 16 seconds for each process. + +RN130: Fixed calculation of bytes to be read for recovery. + +RN129: Fixed bug in cleanup of unterminated transactions. + +RN128: The writer will now start working when one of the following is true: +- it is time for a checkpoint, +- the log cache is almost full, +- the free'er is waiting for the writer, +- there is no other activity. + +RN127: Fixed checkpoint frequency. Checkpointing is now done correctly after 'pbxt_checkpoint_frequency' bytes. + +RN126: Implemented index consistent write [TODO: 0050]. + +RN125: Implemented memory mapping for row pointer (.xtr) and handle data files (.xtd). + +RN124: Index files now use direct I/O. + +------- 1.0.02 Alpha - 2008-04-25 + +RN123: Fixed compile errors with MySQL 5.1.24. + +------- 1.0.01 Alpha - 2008-03-28 + +RN122: ++++ NOTE: This version is not compatible with older versions of PBXT ++++. + +RN121: Transaction logs are now global so that multi-database statements are now possible. This makes it also possible to work PBXT temporary tables. + +RN120: Transaction logs pre-allocated and recycled. + +RN119: Transaction log writes on 512 byte boundaries only. + +------- 1.0.00 Alpha - 2008-03-10 + +This version has alpha status because of the large number of changes done for full durability. + +RN118: ++++ NOTE: This version is incompatible to older versions of PBXT ++++. + +RN117: Documentation now avaliable at http://www.primebase.org/documentation. + +RN116: Corrected the plug.in file so that PBXT compiles when dropped into the storage directory in the MySQL source tree. + +RN115: Compiled and tested with MySQL 5.1.23. + +RN114: Increased index block size. Minimum is now 4K. Default is 16K. + +RN113: Calculate index selectivity to return a more accurate value from records_in_range(). NOTE: FLUSH TABLESl will update the index statistics, after data has been inserted or updated. + +RN112: Optimized table storage, saving 8 bytes per row. + +RN111: Optimized search on keys containing 2 or 3 not null integer values. + +RN110: Optimization: store the row ID in the index so that an index entry can be verified as current without loading the record. This is necessary to optimize an access with index coverage. + +RN109: Optimization: only load the record extended data if required. + +RN108: Implemented SHOW ENGINE PBXT STATUS; + +RN107: Added the following system variables: + +pbxt_index_cache_size - The amount of memory allocated to the index cache, used only to cache index data +pbxt_record_cache_size - The amount of memory allocated to the record cache used to cache table data +pbxt_log_cache_size - The amount of memory allocated to the transaction log cache used to cache on transaction log data +pbxt_log_file_threshold - The size of a transaction log before rollover, and a new log is created +pbxt_transaction_buffer_size - The size of the global transaction log buffer (the engine allocates 2 buffers of this size) +pbxt_log_buffer_size - The size of the buffer used to cache data from transaction and data logs during sequential scans, or when writing a data log +pbxt_checkpoint_frequency - The amount of data written to the transaction log before a checkpoint is performed +pbxt_data_log_threshold - The maximum size of a data log file +pbxt_garbage_threshold - The percentage of garbage in a data log file before it is compacted + +RN106: PBXT now compiles for MySQL 6.0.3. + +RN104: Updates now locks a record temporarily. This prevents most "record changed" errors, however, it makes UPDATE statements a type of "committed read". This means that you may update a different value to that which you selected in repeatable read mode. To avoid this, use SELECT FOR UPDATE if you plan to UPDATE records after reading. + +RN103: Implemented SELECT FOR UPDATE. This is implemented by turning SELECT FOR UPDATE into a type of "committed read". This means that, if you do a SELECT followed by a SELECT FOR UPDATE you can get different results, even in repeatable read mode. + +RN102: Implemented recovery of index entries. Note: indexes are not yet fully consistent. This means that index can become currupted due to a crash. Data, however, cannot be lost. The indices can be rebuild using REPAIR TABLE. + +RN101: Writing and flushing of a single transaction write-ahead log. + +RN100: Automatic rollover of transaction logs as they become full. + +RN99: Implementation of the transaction log cache. + +RN98: Group commit. + +RN97: Implementation of the writer thread that applies changes in the transaction log to the database. + +RN96: Implementation of the checkpointer thread that periodically flushes the database and writes a checkpoint which determines the recovery start point. + +RN95: Implementation of the free'er thread that is responsible for keeping the record cache at a preset level. + +RN94: Modifications to the record cache so that rows are stored in pages, in order to speed up sequence access. + +RN93: Implemented the recovery process which applies changes written to the log that are not in the database, on startup. + +RN92: Modification of the sweeper thread which cleans up rolled-back transactions and deleted data, to use the new transaction log format. + +RN91: Modifications to the data logs so that they use the same record structure as the transaction logs. + +RN90: The data logs are now managed "per database" in order to minimize the work done to flush and commit a transaction. + +RN89: Implementation of a file handle pool for the data logs. + +------- 0.9.91 Beta - 2007-10-30 + +RN88: The format of the URL genearated by MyBS has been changed. The format of the BLOB URLs is now as follows: + +'~*' <db-name> '/' <type-char> <table-id> '-' <blob-id> '-' <access-code> '-' <server-id> + +Where <type-char> is '_' or '~'. + +Examples: ~*test/_11-128-fbd590b-0, ~*test/~1-524-3dc45b09-0 + +In other words, the characters '>' has been replace by '*', '^' has been replace by '_' and ':' has been replace by '~'. The reason for this is that the characters '>' and '^' are not allowed in URLs, and must be URL-encoded. The character ':' is reserved, but allowed. + +NOTE: This change makes this version incompatible with previous versions of MyBS. If you have a table with BLOB URLs, you can upgrade the URLs as follows: + +UPDATE blob_table SET blob_col = REPLACE(REPLACE(blob_col, '~>', '~*'), '/:', '/~'); + +Replacing '^' is not necessary because BLOB URLs with '^' should not appear in tables. + +------- 0.9.90 Beta - 2007-10-17 + +RN87: Corrected stack trace of errors passed through the BLOB streaming API. + +RN86: Added new engine API accessor functions that appeared in 5.1.21 (thanks Stewart). + +RN85: Added plug.in file. PBXT now compiles when dropped into the storage directory of the MySQL build tree. However, you have rebuild configure. For example: + +rm -rf autom4te.cache/ +aclocal +autoconf +autoheader +automake -a +./configure --help +./configure --with-plugins=max --without-innodb --prefix=/usr/local/mysql --with-debug=full + +NOTE: ./configure --help should show that the PBXT has been included. + +RN84: Fixed several problems with shutdown of PBXT in combiniation with MyBS. + +------- 0.9.89 Beta - 2007-08-17 + +RN83 (2007-08-21): Fixed a crash due to a compile bug that does not like the contruct *((xtWordPS *) &(v)) = (xtWordPS) (x) (macro allocr_() and alloczr_()). + +RN82: It is now possible to insert non-URL values into a LONGBLOB field, in the previous version the generated an "Invalid URL" error. Such values can be retrieved as a stream using a field reference. + +RN81: Fixed a bug that caused PBXT to crash during certina operations when MyBS was not installed. + +RN80: Set engine as capable of row-level replication, but not as statement replication. Statement replication does not work because MVCC is not serializable. + +------- 0.9.88 Beta - 2007-07-25 + +RN79: Made some corrections in order to compile with MySQL 5.1.20. + +RN78: Support for the features of the MyBS BLOB Streaming engine, version 0.5 Alpha. + +RN77: Bugfix: The server crashes during BLOB data handling. The reason is the table field structure is shared, and may not be changed. + +------- 0.9.87 Beta - 2007-06-19 + +RN76: The major feature of this release is support for the BLOB Streaming Engine. The current version enables the download of specific BLOB columns via the Streaming Engine. For example: + +use test; +CREATE TABLE notes_tab ( + n_id INTEGER PRIMARY KEY, + n_text BLOB +) ENGINE=pbxt; +INSERT notes_tab VALUES (1, "This is a BLOB streaming test!"); + +The URL: + +http://localhost:8080/test/notes_tab/n_text/n_id=1 + +will return the value "This is a BLOB streaming test!" + +RN75: Bugfix: MySQL prints error: "Plugin 'PBXT' will be forced to shutdown". This error was caused by the plug-in having a reference to itself. + +RN74: Added system variable pbxt_index_cache_size and pbxt_record_cache_size. These variable can now be set on the mysqld command line (for example: --pbxt_record_cache_size=50MB). The values are also displayed by SHOW VARIABLES. + +------- 0.9.86 Beta - 2007-04-07 + +RN74: ++++ NOTE: This version is incompatible to older versions of PBXT ++++. + +In order to upgrade, install the older version of PBXT. Convert all tables to MyISAM using ALTER TABLE t1 ENGINE=MyISAM. Then install the new version of PBXT and convert back using ALTER TABLE t1 ENGINE=PBXT. + +RN73: Each table will now use a maximum of 4 data log files. This means a maximum of 7 files per table. The minimum is 3 for tables that do not have a variable field that exceeds about 40 bytes in size. This means that under Linux PBXT requires a maximum of 7 file handles per table used. Windows lock of pread/pwrite (atomic seek and read/write) functions means it requires a file handler per file per open table handler. [TODO: 0044] + +RN72: All threads now write to the same data log file. Recovery and compaction take this fact into account. Each thread still writes its own transaction log. + +RN71: Removed all directory scans when creating and dropping table. Increased the table limit to 10000. + +RN70: Changed locking to avoid a deadlock when TRUNCATE TABLE is used together with other DML. + +RN69: procedures and functions are now considered atomic, and execute in a single transaction. + +RN68: Bug fixed: all files are now correctly flushed before commit. + +------- 0.9.85 Beta - 2007-03-15 + +RN67: Changed the implementation of the pushsr_ and allocr_ macros because "*((void **) &(v) = " caused a crash due to a compiler error on some platforms (thanks Luciano for your help on this one and RN66). + +RN66: Fixed a bug that caused PBXT to corrupt the index file when the size exceeded 4GB. [TODO: 0031] + +RN65: PBXT now runs under Windows. This source tree must be placed in the MySQL source storage directory in order to compile. Further details of how to build are in the windows-readme.txt file. [TODO: 0027] + +RN64: Improved speed of table lookup by ID after a table has been deleted. The sweeper needs to ignore these records. Scanning the directory each time was too slow. + +RN63: Added checking for repeat update of a record in a statement. + +RN62: Committed read no longer blocks due to a change made by another transaction (the XT_REPEATABLE_READ_BLOCKS define, turns blocking on). + +RN61: Avoid checking for duplicates if an index is not modified by an update. + +RN60: Records updated repeatedly by a transaction are now updated in place. [TODO: 0040] + +------- 0.9.8 Beta - 2007-01-30 + +RN59: Reduced the number of file handles used to a maximum of one per file. This assumes that pread() and pwrite() allows multiple threads to use the same file handle (according to my tests, this is the case). + +RN58: Added the configure flag --with-debug=only which compiles a version of the plug-in with debug symbols that will link to an non-debug MySQL server. + +RN57: Changed error number returned on lock from 1205 (lock timeout) to 1020 (optimistic lock failure). + +RN56: Added UNIX environment variable for PBXT system parameters. These must be set before starting mysqld, for example: + +setenv pbxt_index_cache_size 400MB +setenv pbxt_record_cache_size "1 GB" + +Values are in bytes unless one of the following units is specified: GB, MB, Kb + +RN55: Fixed a bug which prevented VARCHAR values from being compressed correctly when stored in variable length rows. + +RN54: Fixed a bug which caused a crash when PBXT was used with MySQL 5.1.14. This bug also caused data to be corrupted on insert. + +RN53: Set query caching mode to transactional. [TODO: 0027] + +RN52: Added conditions so that the engine compiles with MySQL 5.1.14 and 5.1.13. + +------- 0.9.74 Beta - 2006-12-14 + +RN51: DELETE FROM <table>; is no longer implemented by re-creating the table. This statement now works by deleting all rows. TRUNCATE is implemented as before, by re-creating the table. + +RN50: The test scripts innodb.test and innodb-mysql.test have been modified to run with PBXT. + +RN49: [TODO: 0020] Implemented foreign keys. Functionality is identical to InnoDB with 2 exceptions: + +* Data types of referenced columns must be an exact match (e.g. you cannot mix VARCHAR and CHAR values). +* Currently an exact matching index is required on referenced columns (i.e. the index may not have more columns that the columns used in the foreign key definition). + +Also note the following: + +* It is possible to create foreign keys that reference non-existent tables or columns. An error will occur when updating a table with an incorrect foreign key declaration. +* If you alter the data-type of a column referenced by a foreign key set you need to set foreign_key_checks=0; or an error will occur. + +RN48: Fixed a bug in the implementation of indexes on ENUM and SET types. + +RN47: Fixed a bug that caused a crash when an index was place on a BLOB column, and data was retrieved from the index directly. + +------- 0.9.73 Beta - 2006-10-31 + +RN46: Updated test scripts to run with MySQL 5.1.13. + +------- 0.9.72 Beta - 2006-10-19 + +RN45: Corrected compilation errors that occurred due to a change to struct st_mysql_plugin. + +------- 0.9.71 Beta - 2006-10-04 + +RN44: Corrected compilation errors that occurred due to changes in the storage engine API. + +------- 0.9.7 Beta - 2006-09-20 + +RN43: This is the first Beta release of PrimeBase XT. It has been integrated into MySQL 4.1.21 and is available as a plug-in for MySQL 5.1.12, or later. This version has been extensively tested using mysql-test-run, on various Linux and Mac OS X platforms. + +RN42: ++++ NOTE: This version is incompatible to older versions of PBXT ++++. Files created by older versions cannot be opened by version 0.9.7. + +RN41: Renaming or deleting a table while using a name with different case to the original created name did not work. + +RN40: Fixed a bug when grouping and searching on indexed columns that contain a null. + +RN39: Fixed bugs related to trailing spaces on VARCHAR values. Values that only vary by the number of trailing spaces (for example "aa" and "aa "), are now correctly handled as identical. + +RN38: The default AUTO_INCREMENT value was not correctly preserved during ALTER TABLE. + +RN37: Created a MySQL 5.1 Plugin version of PBXT. [TODO: 0017] + +RN36: Fixed a race condition in the row cache which had the affect that inserted rows dissappeared after cleanup because the cache was out of date. I was only able to reproduce this error on multi-processor machines. + +------- 0.9.6 - 2006-08-05 + +RN35: ++++ NOTE: This version is incompatible to older versions of PBXT ++++. + +The disk format of tables and log files has changed slightly in this version. As a result, files created by older versions cannot be opened by version 0.9.6. An error will be generated. If you have data wish to preserve, first start the older version of XT and convert all tables to MyISAM. The stop the server and removed all transaction log file (files of the form xtlog-*.xt). Then start the new version and convert tables back to XT. + +RN34: Implemented READ COMMITTED transaction mode. XT now supports READ COMMITTED and SERIALIZABLE transaction modes. NOTE: if the mode is set to REPEATABLE READ, SERIALIZABLE is used. If the mode is set to READ UNCOMMITTED READ COMMITTED is used. + +RN33: The implementation of AUTO_INCREMENT on a paritial index is non-standard. A unique value is generated without regard to the value of the index prefix. For example, assume we have the following table: CREATE TABLE t1 (c1 CHAR(10) not null, c2 INT not null AUTO_INCREMENT, PRIMARY KEY(c1, c2)); + +With the following contents: c1 c2 + A 8 + B 1 + +After executing the following statement: insert into t1 (c1) values ('B'); + +This is the result using PBXT: c1 c2 + A 8 + B 1 + B 9 + +The standard result would be: c1 c2 + A 8 + B 1 + B 2 + +RN32: PBXT does not permit access to multiple databases within a single transaction. For example: + +begin; +update database_1.t1 set a=10; +update database_2.t2 set d=10; +commit; + +In this case the following error is returned: 1015: Can't lock file (errno: -1) + +RN31: The implementation of COUNT(*) has changed. For effectiency, rows are not counted. The information is taken from the header of the record (.xtr) files. This information is only 100% accurate after transaction cleanup has completed. Which basically means, only when PBXT is idle. ANALYZE TABLE waits for all background activity to stop, so the statement may be executed before a COUNT(*) to ensure an accurate result. NOTE: Other then waiting for background processes, ANALYSE TABLE is not implemented. + +RN30: Two concurrency bugs have been fixed: a shared lock was used instead of an exclusive lock when deleting from a transaction list, the transaction segment semaphore was not initialized. XT now runs correctly in a multi-processor environment. The test used was sysbench on a dual-process, dual-core, AMD 64-bit machine running SUSE Linux 10.0. + +RN29: PBXT compiles and runs on under 64-bit Lunix. [TODO: 0009] + +RN28: ./mysql-test-run --force --mysqld=--default-storage-engine=pbxt will now execute most tests successfully. Changes to the tests and the result have been documented in http://www.primebase.com/xt/download/pbxt-test-run-changes.txt. [TODO: 0004, 0019] + +RN27: Fixed a bug that caused the server to crash if when using tables locks and transactions. For example: LOCK TABLES, BEGIN, COMMIT, SELECT. This sequence now returns an error. The correct sequence is: + +LOCK TABLES, BEGIN, COMMIT, UNLOCK TABLES, SELECT +or +LOCK TABLES, BEGIN, COMMIT, BEGIN, SELECT COMMIT, UNLOCK TABLES + +RN26: Fixed a concurrency problem which caused a number of threads to hang during the sysbench test - see RN30 above (bug reported by Vadim). + +RN25: Fixed a bug that caused the server to hang when ha_pbxt::create() and ha_pbxt::ha_open() where given different, but equivalent paths for a particular table. + +RN24: Fixed bug in the indexing of blob columns, for example: create table t1(name_id int, name blob, INDEX name_idx (name(5))); + +RN23: When a duplicate key error occurs in auto-commit mode, the transaction is now rolled back. + +RN22: Fixed incorrect duplicate key error. In the case of a unique key which allows NULLs, duplicates are allowed if the inserted key contains a NULL. For example: + +create table t1 (id int not null, str char(10), unique(str)); +insert into t1 values (1, null),(2, null),(3, "foo"),(4, "bar"); + +RN21: PBXT now returns the correct error code on duplicate key: 1062 instead of 1022. + +RN19: Implemented AUTO_INCREMENT on partial keys. However, the XT implementation is non-standard. Increment of partial index works, but the ID generated is incremented like a non-partial index. For example: + +create table t1 (c1 char(10) not null, c2 int not null auto_increment, primary key(c1, c2)); +select * from t1; +c1 c2 +A 8 +B 1 + +insert into t1 (c1) values ('B'); +select * from t1; +c1 c2 +A 8 +B 1 +B 9 + +The standard result would be: +c1 c2 +A 8 +B 1 +B 2 + +RN18: Implemented TRUNCATE TABLE and DELETE FROM <table>; (i.e. a DELETE without WHERE clause). Previously DELETE FROM <table>; did not cause an error, but no rows where deleted (TRUNCATE TABLE returned an error). [TODO: 0012, 0022] + +RN17: Implemented CREATE TABLE (...) auto_increment=<value>; + +------- 0.9.51 - 2006-07-06 + +RN16: Fixed crash which could occur when creating the first table in a database (bug reported by Hakan). + +------- 0.9.5 - 2006-07-03 + +RN15: This version concludes the re-structuring of the PBXT implementation. I have made a number of major changes, including: + +- All files except the transaction logs are now associated with a particular table. All table related files begin with the name of the table. The extension indicates the function. + +- I have merged the handle and the fixed length row data for performance reasons. + +- Only the variable size component of a row is stored in the data log files. As a result the data logs can now be considered as a type of "overflow" area. + +- Memory mapped files are no longer used because it is not possible to flush changes to the disk. + +RN14: File names have the following forms: + +[table-name]-[table-id].xtr - These files contains the table row pointers. Each row pointer occupies 8 bytes and refers to a list of records. The file name also contains the table ID. This is a unique number which is used internally by XT to identify the table. + +[table-name].xtd - This file contains the fixed length data of a table. Each data item includes a handle and a record. The handle references a record in the data log file if the table contains variable length records. + +[table-name].xti - This file contains the index data of the table. + +[table-name]-[log-id].xtl - This is a data log file. It contains the variable length data of the table. A table may have any number of data log files, each with a unique ID. + +xtlog-[log-id].xt - These files are the transaction logs. Log entries that specify updates reference a data file record. Each active thread has its own transaction log in order to avoid contension. + +RN13: Fixed the bug "Hang on DROP DATABASE". [TODO: 0016] + +RN12: PBXT currently only supports the "Serializable" transaction isolation level. This is the highest isolation level possible and includes the "repeatable-read" functionality [TODO: 0015]. This is implemented by giving every transaction a snapshot of the database at the point when the transaction is started. + +If the transaction tries to update a record that was updated by some other transaction after the snapshot was taken, a locked error is returned. A deadlock can occur if 2 transactions update the same record in a different order. PBXT can detect all deadlocks. + +RN11: I have implemented write buffering on the table data files. [TODO: 0013] + +RN10: The unique constraint (UNIQUE INDEX/PRIMARY KEY) is now checked correctly. [TODO: 0008] + +RN9: I have implemented a conventional B-tree algorithm for the indices (instead of the Lehman and Yoa B*-link tree). Although this reduces concurrency it improves the performance of queries significantly because of the simplicity of the algorithm. Deletion is also implemented in a very simple manner. [TODO: 0007] + +RN8: PBXT now has only 2 caches [TODO: 0006]: + +The Index Cache (pbxt_index_cache_size): This is the amount of memory the PBXT storage engine uses to cache index data and row pointers. This is all the data in the files with the extensions '.xti' and '.xtr'. This cache is managed in blocks of 2K. + +The Record Cache (pbxt_record_cache_size): This is the amount of memory the PBXT storage engine uses to cache table row data (handles and records). This is all the data in the files with the extension '.xtd'. + +The size of the caches are determined by the values of the system variables pbxt_index_cache_size and pbxt_row_cache_size. By default these values are set to 32MB. + +RN7: Auto-increment is now implemented in memory. This is done by doing a MAX() select when a table is first opened to get the high value. After that, then high value is incremented in memory on INSERT. On UPDATE (or INSERT) the value in memory is adjusted if necessary. This method also makes it possible for rows to be inserted simultaneously on the same table. [TODO: 0005, 0014] + +RN6: ./run-all-tests --create-options=TYPE=PBXT succeeds. [TODO: 0004] + +RN5: Using sql-bench and my own Java based test I have confirmed that PBXT behaves correctly during multi-threaded access. [PARTIALY TODO: 0002] + +RN4: Load/Stability test. Using sql-bench I have tested PBXT under load over a long period of time. [PARTIALY TODO: 0001] + +------- 0.9.2 - 2006-04-01 + +RN3: Fixed a bug that cause the error "-6: Handle is out of range: [0:0]". + +RN2: Implemented SET, ENUM and YEAR data types. + +RN1: Fixed a bug in the error reporting when a table is created with a datatype that is not supported. [TODO: 0011] + + diff --git a/storage/pbxt/INSTALL b/storage/pbxt/INSTALL new file mode 100644 index 00000000000..23e5f25d0e5 --- /dev/null +++ b/storage/pbxt/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/storage/pbxt/Makefile.am b/storage/pbxt/Makefile.am new file mode 100644 index 00000000000..a8bfde74ee3 --- /dev/null +++ b/storage/pbxt/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +EXTRA_DIST = plug.in diff --git a/storage/pbxt/NEWS b/storage/pbxt/NEWS new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/storage/pbxt/NEWS diff --git a/storage/pbxt/README b/storage/pbxt/README new file mode 100644 index 00000000000..52d7cf6c44e --- /dev/null +++ b/storage/pbxt/README @@ -0,0 +1,19 @@ +PrimeBase XT for MySQL 5.1 +========================== + +This is the PrimeBase XT (PBXT) transactional storage engine for MySQL. PBXT is "pluggable", which means that it can be loaded dynamically by MySQL at runtime. It uses a unique "write-once" update strategy and MVCC (multi-version concurrency control) to provide optimal performance over a wide range of tasks. + +This package includes the complete source code for the engine. Although this is a standalone project it must be built against a compiled version of the MySQL 5.1 source tree, because it references headers files used internally by the server. + +Details about how to build PBXT both under UNIX or Windows, as a standalone plug-in, or as part of the MySQL source code, is distribed in the documentation which is avaliable online at: + +http://www.primebase.org/documentation + +Bug reports, questions and comments can be sent directly to me. + +Thanks for your support! + +Paul McCullagh +SNAP Innovation GmbH +paul.mccullagh@primebase.org + diff --git a/storage/pbxt/TODO b/storage/pbxt/TODO new file mode 100644 index 00000000000..b5782defb61 --- /dev/null +++ b/storage/pbxt/TODO @@ -0,0 +1,195 @@ +PBXT To-Do List +=============== + +My thanks to all who have downloaded and tested PBXT. If an issue you reported before the date below is not on this list, please e-mail me again. + +------- 2008-12-09 + +0063: The option for not using memory mapped files must be fixed. + +0062: Dynamic option for using memory mapping on a table (Dimitri). + +------- 2008-09-12 + +0061: Add records per key result to ha_pbxt:info() call (Mark). + +------- 2008-08-31 + +0060: Add table option to determine if a table should be memory mapped or not (also requested by Dimitri). + +0059: Add table options: + AVG_ROW_LENGTH [=] value + DATA DIRECTORY [=] 'absolute path to directory' + INDEX DIRECTORY [=] 'absolute path to directory' + MAX_ROWS [=] value + +------- 2008-03-28 + +0058: Consolidate writes when changes in the log are applied to the database. + +------- 2008-03-07 + +0057: Cluster updates onto a single page. + +0056: Add checksum to index and data pages. + +0055: When no index cache is available, the complete index must be flushed (not just single pages). + +0054: Optimize indexes by not creating indexes that are a complete sub-set of some other index. In this case we must be able to identify part of an index as unique. For example: primary key (a, b), index (a, b, c). Here we would just create index (a, b, c), and specify that the part (a, b) must be unique. Operations on (a, b) will be directed to index (a, b, c). + +0053: Check and test lock tables. + +0052: Cache data log data in the handle data cache. Must be purged when a handle data record is written. + +0051: Write data log data alternatively to the transaction log. The compactor must then compact transaction logs. + +0050: [RESOLVED: RN126] Implement consistent write for indexes. + +0049: [RESOLVED: RN114] Set the index block size to 4K, or 16K as used by InnoDB. + +0048: [RESOLVED: RN110] Add row ID to indexes. This should only be set once the row is cleaned by the sweeper. Then the row ID can be used to make a quite check if the row is the most recent version. + +------- 2007-06-19 + +0047: Test build with ./configure --with-innodb under Linux (Vadim). + +0046: [RESOLVED: RN85] Add plug.in file to enable drop in compile under Linux. + +0045: Provide libstdc++.so.6 binaries (Vadim). + +0044: [RESOLVED: RN73] Limit number of file handles used per table (Brian). + +0043: XA (two-phase commit) support (Peter). + +------- 2007-03-13 + +0042: [RESOLVED: RN108] Implemement STATUS commands. + +0041: Implement index prefix compression. + +------- 2007-03-07 + +0040: [RESOLVED: RN60] Update in-place when a transaction updates the same record more than once. + +0039: Set the number and size of the segments dynamically according to the amount of memory in the cache (and the number of CPUs?) (as discussed with: Peter & Vadim). + +0038: [RESOLVED: RN133] Improve the efficiency of the locks by using atomic compare and swap (Peter & Vadim). + +0037: [RESOLVED: RN133] Instead of a global LRU list, use a LRU list for segment of the cache (Peter & Vadim). [ Note: a global list using a TAS lock and change time (so that LRU is not always updated) is most efficient]. + +0036: Add support for deferred foreign key checking (requested by: Mark). + +0035: [RESOLVED: RN71] Remove the 2000 table limit (reported by: Hakan). + +------- 2007-02-28 + +0035: [RESOLVED: RN74, RN107] Build in the PBXT system parameters (currently they must be set using environment variables. + +0034: [RESOLVED: RN117] Initial documentation (yes, it must be done!) + +0033: Make the error code returned on lock error configurable. + +0032: [RESOLVED: RN65] Create a source code pluggable version for Windows. + +0031: [RESOLVED: RN66] PBXT corrupts the index file when the size exceeds 4 GB (reported by: Luciano) + +0030: [RESOLVED: RN102] Implement pbxt_index_flush_delay. Postpones index writing in order to speed up imports. [Resolution uses that fact hat index entries that are missing are added during recovery. As a result, index flushing can be delayed.] + +0029: [RESOLVED: RN103] Implement SELECT ... FOR UPDATE (recommended by: Robin). + +------- 2007-02-14 + +0028: Implement CREATE TABLE ... DATA/INDEX DIRECTORY (suggested by: Robin). + +------- 2006-12-06 + +0027: [RESOLVED: RN53] Bug in pbxt with query caching (reported by: Giuseppe) caused violation of transaction isolation. + +------- 2006-08-05 + +0026: Implement BACKUP and RESTORE table (planned for the first post release version). + +0025: Implement DISABLE/ENABLE KEYS. Works for FOREIGN KEYs, currently no plans to implement for disabling indexes. + +0024: Implement ANALYZE TABLE (planned for the first post release version). + +0023: Implement CHECK TABLE (planned for the first release candidate). + +0022: [RESOLVED: RN18] Implement TRUNCATE TABLE and DELETE FROM <table>; (i.e. a DELETE without WHERE clause). Currently this function does not cause an error, but no rows are deleted. + +------- 2006-07-06 + +0021: [RESOLVED: RN28] .../mysql-test/mysql-test-run --force --mysqld=--default-storage-engine=pbxt produces a number of errors (reported by: Hakan): As far as I can tell some failures are unnessary but others are bugs. All need to be checked. + +------- 2006-07-03 + +0020: [RESOLVED: RN49] Implement referential integrity (planned for the first release candidate). + +------- 2006-04-01 + +0019: [RESOLVED: RN28] mysql-test-run hangs on alter table (reported by: Hakan): Running a test like ./mysql-test-run.pl --mysqld=--default-storage-engine=pbxt, hangs on ALTER TABLE. + +0018: Implement GEOMETRY date type. Note: There are currently no plans to implement this feature. + +------- 2006-03-31 + +0017: [RESOLVED: RN37] MySQL 5.x Version (reported by: Ronald, Giuseppe). + +0016: [RESOLVED: RN13] Hang on "DROP DATABASE" (reported by: Giuseppe). Load the world database (http://downloads.mysql.com/docs/world.sql) and convert all tables into PBXT. Then, the drop database command hangs. + +0015: [RESOLVED: RN12] Implement isolation level "repeatable read" (reported by: Giuseppe). Current PBXT only supports isolation level "committed read". This means committed data can be seen no matter when it was committed. Use SELECT ... FOR UPDATE to guarantee repeatable read, on data already read. + +0014: [RESOLVED: RN7] Two transactions cannot insert simaltaneously if they use auto_increment (reported by: Giuseppe). See also 0005. + +0013: [RESOLVED: RN11] Implement buffered write (reported by: Giuseppe): Lack of buffered write leads to bad performance in operations such as ALTER TABLE ENGINE = PBXT and INSERT ... SELECT. + +0012: [RESOLVED: RN18] TRUNCATE does not work (reported by: Giuseppe) + +0011: [RESOLVED: RN2] Load Sakila Sample Database (reported by: Ronald): ALTER TABLE film ENGINE=PBXT; fails + +0010: [RESOLVED: RN6] sql-bench (reported by: Dmitry): ./run-all-tests --create-options=TYPE=PBXT fails. + +0009: [RESOLVED: RN29] 64-bit Linux (reported by: Hakan): PBXT current does not compile under 64-bit Linux. + +------- 2006-03-16 + +0008: [RESOLVED: RN10] Enforcing the unique index constraint: + +An index declared as "unique" must return a "duplicate unique key" error when inserting a duplicate value. The difficulty part of implementing this in PBXT is that we may encounter a duplicate value that has not yet been committed. The index reading thread must then wait for the transaction to commit or abort. + +0007: [RESOLVED: RN9] Cleaning up empty index nodes: + +The Lehman and Yoa algorithm used for indexing does not describe a way of cleaning up empty index nodes on-the-fly. A search of the relevant literature for an algorithm also turns up empty handed (periodic "reorg" is mostly suggested). I have subsequently devised an algorithm that will do the job. This needs to be implemented. + +0006: [RESOLVED: RN8] Cache Balancing: + +PBXT uses a number of small caches in order to improve concurrency (rather than one large cache). A process is required to manage the amount of cache memory used as a whole. The process must distribute the overall amount of memory available for caching over the small caches, according to demand. + +0005: [RESOLVED: RN7] Implement a faster auto-increment method + +Currently the auto-increment is handled by the default method used in MySQL. This is done by performing a "fetch-last" on the index for each insert to find the highest key value. This works well unless there are large number empty index nodes due to the problem described in (2) above. + +PBXT Testing To-Do List + +This is my first take on what still must be tested. My thanks to Ronald Bradford who is working on a generic testing framework that can be used to test PBXT. + +0004: [RESOLVED: RN6, RN28] MySQL Tests: + +Several tests (for mysql-test-run) written for other engines can be adapted and used to test PBXT. + +0003: [RESOLVED: RN30] Multi-processor Test: + +There is a difference between preemptive multitasking and true multitasking, which you have on a multi-processor (or dual core) machine. I don't expect any fundamental problems here, but it must be tested. + +0002: [RESOLVED: RN5, RN30, RN43] Multi-user/locking Test: + +How does the engine perform with a number of concurrent users running various transactions on a number of different tables? +This is a difficult test to write because it need to simulate a production situation. To test at least 2 or 3 machines is required. The idea is not to use too much data so that a lot of conflicts may occur. + +0001: [RESOLVED: RN4, RN43] Load/Stability Test: + +How does the engine perform under heavy load over a long period of time? How stable is the engine on power outage, etc? + +The test could use a variation of the test program written for test (3) above. At least 3 test machines would be required. The test must be modified to cause as much activity as possible. The test should monitor the performance under load. + + diff --git a/storage/pbxt/plug.in b/storage/pbxt/plug.in new file mode 100644 index 00000000000..f79df759f87 --- /dev/null +++ b/storage/pbxt/plug.in @@ -0,0 +1,7 @@ +MYSQL_STORAGE_ENGINE(pbxt,no, [PBXT Storage Engine], + [MVCC-based transactional engine], [max,max-no-ndb]) +MYSQL_PLUGIN_DIRECTORY(pbxt, [storage/pbxt]) +MYSQL_PLUGIN_STATIC(pbxt, [src/libpbxt.a]) +MYSQL_PLUGIN_ACTIONS(pbxt, [ + AC_CONFIG_FILES(storage/pbxt/src/Makefile) + ]) diff --git a/storage/pbxt/src/CMakeLists.txt b/storage/pbxt/src/CMakeLists.txt new file mode 100755 index 00000000000..4533752045c --- /dev/null +++ b/storage/pbxt/src/CMakeLists.txt @@ -0,0 +1,53 @@ +# Copyright (c) 2008 PrimeBase Technologies GmbH +# +# PrimeBase XT +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# 2006-03-22 Paul McCullagh +# +# H&G2JCtL +# +# This file is used to make the Windows version + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMYSQL_SERVER") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMYSQL_SERVER") + +SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DMYSQL_SERVER -DSAFEMALLOC -DSAFE_MUTEX -DDEBUG") +SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DMYSQL_SERVER -DSAFEMALLOC -DSAFE_MUTEX -DDEBUG") + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql + ${CMAKE_SOURCE_DIR}/regex + ${CMAKE_SOURCE_DIR}/extra/yassl/include) + +SET(PBXT_SOURCES ha_pbxt.cc bsearch_xt.cc index_xt.cc strutil_xt.cc cache_xt.cc linklist_xt.cc + ccutils_xt.cc lock_xt.cc table_xt.cc database_xt.cc thread_xt.cc + datadic_xt.cc memory_xt.cc trace_xt.cc datalog_xt.cc myxt_xt.cc util_xt.cc + filesys_xt.cc pthread_xt.cc xaction_xt.cc restart_xt.cc xactlog_xt.cc + hashtab_xt.cc sortedlist_xt.cc heap_xt.cc streaming_xt.cc tabcache_xt.cc + systab_xt.cc ha_xtsys.cc discover_xt.cc + bsearch_xt.h linklist_xt.h tabcache_xt.h cache_xt.h lock_xt.h table_xt.h + ccutils_xt.h thread_xt.h database_xt.h memory_xt.h trace_xt.h + datadic_xt.h pbms.h util_xt.h datalog_xt.h myxt_xt.h xaction_xt.h + filesys_xt.h pthread_xt.h xactlog_xt.h ha_pbxt.h restart_xt.h xt_config.h + hashtab_xt.h sortedlist_xt.h xt_defs.h heap_xt.h streaming_xt.h xt_errno.h + systab_xt.h ha_xtsys.h discover_xt.h + index_xt.h strutil_xt.h) + +IF(NOT SOURCE_SUBLIBS) + ADD_LIBRARY(pbxt ${PBXT_SOURCES}) + ADD_DEPENDENCIES(pbxt GenError) +ENDIF(NOT SOURCE_SUBLIBS) + diff --git a/storage/pbxt/src/Makefile.am b/storage/pbxt/src/Makefile.am new file mode 100644 index 00000000000..2d7cdc8d2e8 --- /dev/null +++ b/storage/pbxt/src/Makefile.am @@ -0,0 +1,52 @@ +# Used to build Makefile.in + +MYSQLDATAdir = $(localstatedir) +MYSQLSHAREdir = $(pkgdatadir) +MYSQLBASEdir= $(prefix) +MYSQLLIBdir= $(pkglibdir) +pkgplugindir = $(pkglibdir)/plugin +INCLUDES= -I$(top_srcdir)/include -I$(top_builddir)/include \ + -I$(top_srcdir)/regex \ + -I$(top_srcdir)/storage/innobase/include \ + -I$(top_srcdir)/sql \ + -I$(srcdir) + +LIBS = + +LDADD = + +noinst_HEADERS = bsearch_xt.h cache_xt.h ccutils_xt.h database_xt.h \ + datadic_xt.h datalog_xt.h filesys_xt.h hashtab_xt.h \ + ha_pbxt.h heap_xt.h index_xt.h linklist_xt.h \ + memory_xt.h myxt_xt.h pthread_xt.h restart_xt.h \ + streaming_xt.h sortedlist_xt.h strutil_xt.h \ + tabcache_xt.h table_xt.h trace_xt.h thread_xt.h \ + util_xt.h xaction_xt.h xactlog_xt.h lock_xt.h \ + systab_xt.h ha_xtsys.h discover_xt.h \ + pbms.h xt_config.h xt_defs.h xt_errno.h locklist_xt.h +EXTRA_LTLIBRARIES = libpbxt.la + +libpbxt_la_SOURCES = bsearch_xt.cc cache_xt.cc ccutils_xt.cc database_xt.cc \ + datadic_xt.cc datalog_xt.cc filesys_xt.cc hashtab_xt.cc \ + ha_pbxt.cc heap_xt.cc index_xt.cc linklist_xt.cc \ + memory_xt.cc myxt_xt.cc pthread_xt.cc restart_xt.cc \ + streaming_xt.cc sortedlist_xt.cc strutil_xt.cc \ + tabcache_xt.cc table_xt.cc trace_xt.cc thread_xt.cc \ + systab_xt.cc ha_xtsys.cc discover_xt.cc \ + util_xt.cc xaction_xt.cc xactlog_xt.cc lock_xt.cc locklist_xt.cc + +libpbxt_la_LDFLAGS = -module + +# These are the warning Drizzle uses: +# DRIZZLE_WARNINGS = -W -Wall -Wextra -pedantic -Wundef -Wredundant-decls -Wno-strict-aliasing -Wno-long-long -Wno-unused-parameter + +libpbxt_la_CXXFLAGS = $(AM_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN +libpbxt_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN -std=c99 + +EXTRA_LIBRARIES = libpbxt.a +noinst_LIBRARIES = libpbxt.a +libpbxt_a_SOURCES = $(libpbxt_la_SOURCES) +libpbxt_a_CXXFLAGS = $(AM_CXXFLAGS) -Wno-long-long +libpbxt_a_CFLAGS = $(AM_CFLAGS) -std=c99 + +EXTRA_DIST = CMakeLists.txt diff --git a/storage/pbxt/src/bsearch_xt.cc b/storage/pbxt/src/bsearch_xt.cc new file mode 100644 index 00000000000..539de1ae74d --- /dev/null +++ b/storage/pbxt/src/bsearch_xt.cc @@ -0,0 +1,66 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2004-01-03 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <stdio.h> + +#include "bsearch_xt.h" +#include "pthread_xt.h" +#include "thread_xt.h" + +/** + * Binary search a array of 'count' items, with byte size 'size'. This + * function returns a pointer to the element and the 'index' + * of the element if found. + * + * If not found the index of the insert point of the item + * is returned (0 <= index <= count). + * + * The comparison routine 'compar' may throw an exception. + * In this case the error details will be stored in 'thread'. + */ +void *xt_bsearch(XTThreadPtr thread, const void *key, register const void *base, size_t count, size_t size, size_t *idx, const void *thunk, XTCompareFunc compar) +{ + register size_t i; + register size_t guess; + register int r; + + i = 0; + while (i < count) { + guess = (i + count - 1) >> 1; + r = (compar)(thread, thunk, key, ((char *) base) + guess * size); + if (r == 0) { + *idx = guess; + return ((char *) base) + guess * size; + } + if (r < 0) + count = guess; + else + i = guess + 1; + } + + *idx = i; + return NULL; +} + diff --git a/storage/pbxt/src/bsearch_xt.h b/storage/pbxt/src/bsearch_xt.h new file mode 100644 index 00000000000..f15e28009fb --- /dev/null +++ b/storage/pbxt/src/bsearch_xt.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2004-01-03 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_bsearch_h__ +#define __xt_bsearch_h__ + +#include "xt_defs.h" + +struct XTThread; + +void *xt_bsearch(struct XTThread *self, const void *key, register const void *base, size_t count, size_t size, size_t *idx, const void *thunk, XTCompareFunc compar); + +#endif diff --git a/storage/pbxt/src/cache_xt.cc b/storage/pbxt/src/cache_xt.cc new file mode 100644 index 00000000000..0e15475f185 --- /dev/null +++ b/storage/pbxt/src/cache_xt.cc @@ -0,0 +1,1507 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH, Germany + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-05-24 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#ifndef XT_WIN +#include <unistd.h> +#endif + +#include <stdio.h> +#include <time.h> + +#include "pthread_xt.h" +#include "thread_xt.h" +#include "filesys_xt.h" +#include "cache_xt.h" +#include "table_xt.h" +#include "trace_xt.h" +#include "util_xt.h" + +#define XT_TIME_DIFF(start, now) (\ + ((xtWord4) (now) < (xtWord4) (start)) ? \ + ((xtWord4) 0XFFFFFFFF - ((xtWord4) (start) - (xtWord4) (now))) : \ + ((xtWord4) (now) - (xtWord4) (start))) + +/* + * ----------------------------------------------------------------------- + * D I S K C A C H E + */ + +#define IDX_CAC_SEGMENT_COUNT ((off_t) 1 << XT_INDEX_CACHE_SEGMENT_SHIFTS) +#define IDX_CAC_SEGMENT_MASK (IDX_CAC_SEGMENT_COUNT - 1) + +//#define IDX_USE_SPINRWLOCK +#define IDX_USE_RWMUTEX +//#define IDX_CAC_USE_PTHREAD_RW + +#ifdef IDX_CAC_USE_FASTWRLOCK +#define IDX_CAC_LOCK_TYPE XTFastRWLockRec +#define IDX_CAC_INIT_LOCK(s, i) xt_fastrwlock_init(s, &(i)->cs_lock) +#define IDX_CAC_FREE_LOCK(s, i) xt_fastrwlock_free(s, &(i)->cs_lock) +#define IDX_CAC_READ_LOCK(i, o) xt_fastrwlock_slock(&(i)->cs_lock, (o)) +#define IDX_CAC_WRITE_LOCK(i, o) xt_fastrwlock_xlock(&(i)->cs_lock, (o)) +#define IDX_CAC_UNLOCK(i, o) xt_fastrwlock_unlock(&(i)->cs_lock, (o)) +#elif defined(IDX_CAC_USE_PTHREAD_RW) +#define IDX_CAC_LOCK_TYPE xt_rwlock_type +#define IDX_CAC_INIT_LOCK(s, i) xt_init_rwlock(s, &(i)->cs_lock) +#define IDX_CAC_FREE_LOCK(s, i) xt_free_rwlock(&(i)->cs_lock) +#define IDX_CAC_READ_LOCK(i, o) xt_slock_rwlock_ns(&(i)->cs_lock) +#define IDX_CAC_WRITE_LOCK(i, o) xt_xlock_rwlock_ns(&(i)->cs_lock) +#define IDX_CAC_UNLOCK(i, o) xt_unlock_rwlock_ns(&(i)->cs_lock) +#elif defined(IDX_USE_RWMUTEX) +#define IDX_CAC_LOCK_TYPE XTRWMutexRec +#define IDX_CAC_INIT_LOCK(s, i) xt_rwmutex_init_with_autoname(s, &(i)->cs_lock) +#define IDX_CAC_FREE_LOCK(s, i) xt_rwmutex_free(s, &(i)->cs_lock) +#define IDX_CAC_READ_LOCK(i, o) xt_rwmutex_slock(&(i)->cs_lock, (o)->t_id) +#define IDX_CAC_WRITE_LOCK(i, o) xt_rwmutex_xlock(&(i)->cs_lock, (o)->t_id) +#define IDX_CAC_UNLOCK(i, o) xt_rwmutex_unlock(&(i)->cs_lock, (o)->t_id) +#endif + +#define ID_HANDLE_USE_SPINLOCK +//#define ID_HANDLE_USE_PTHREAD_RW + +#if defined(ID_HANDLE_USE_PTHREAD_RW) +#define ID_HANDLE_LOCK_TYPE xt_mutex_type +#define ID_HANDLE_INIT_LOCK(s, i) xt_init_mutex_with_autoname(s, i) +#define ID_HANDLE_FREE_LOCK(s, i) xt_free_mutex(i) +#define ID_HANDLE_LOCK(i) xt_lock_mutex_ns(i) +#define ID_HANDLE_UNLOCK(i) xt_unlock_mutex_ns(i) +#elif defined(ID_HANDLE_USE_SPINLOCK) +#define ID_HANDLE_LOCK_TYPE XTSpinLockRec +#define ID_HANDLE_INIT_LOCK(s, i) xt_spinlock_init_with_autoname(s, i) +#define ID_HANDLE_FREE_LOCK(s, i) xt_spinlock_free(s, i) +#define ID_HANDLE_LOCK(i) xt_spinlock_lock(i) +#define ID_HANDLE_UNLOCK(i) xt_spinlock_unlock(i) +#endif + +#define XT_HANDLE_SLOTS 37 + +/* +#ifdef DEBUG +#define XT_INIT_HANDLE_COUNT 0 +#define XT_INIT_HANDLE_BLOCKS 0 +#else +#define XT_INIT_HANDLE_COUNT 40 +#define XT_INIT_HANDLE_BLOCKS 10 +#endif +*/ + +/* A disk cache segment. The cache is divided into a number of segments + * to improve concurrency. + */ +typedef struct DcSegment { + IDX_CAC_LOCK_TYPE cs_lock; /* The cache segment lock. */ + XTIndBlockPtr *cs_hash_table; +} DcSegmentRec, *DcSegmentPtr; + +typedef struct DcHandleSlot { + ID_HANDLE_LOCK_TYPE hs_handles_lock; + XTIndHandleBlockPtr hs_free_blocks; + XTIndHandlePtr hs_free_handles; + XTIndHandlePtr hs_used_handles; +} DcHandleSlotRec, *DcHandleSlotPtr; + +typedef struct DcGlobals { + xt_mutex_type cg_lock; /* The public cache lock. */ + DcSegmentRec cg_segment[IDX_CAC_SEGMENT_COUNT]; + XTIndBlockPtr cg_blocks; +#ifdef XT_USE_DIRECT_IO_ON_INDEX + xtWord1 *cg_buffer; +#endif + XTIndBlockPtr cg_free_list; + xtWord4 cg_free_count; + xtWord4 cg_ru_now; /* A counter as described by Jim Starkey (my thanks) */ + XTIndBlockPtr cg_lru_block; + XTIndBlockPtr cg_mru_block; + xtWord4 cg_hash_size; + xtWord4 cg_block_count; + xtWord4 cg_max_free; +#ifdef DEBUG_CHECK_IND_CACHE + u_int cg_reserved_by_ots; /* Number of blocks reserved by open tables. */ + u_int cg_read_count; /* Number of blocks being read. */ +#endif + + /* Index cache handles: */ + DcHandleSlotRec cg_handle_slot[XT_HANDLE_SLOTS]; +} DcGlobalsRec; + +static DcGlobalsRec ind_cac_globals; + +#ifdef XT_USE_MYSYS +#ifdef xtPublic +#undef xtPublic +#endif +#include "my_global.h" +#include "my_sys.h" +#include "keycache.h" +KEY_CACHE my_cache; +#undef pthread_rwlock_rdlock +#undef pthread_rwlock_wrlock +#undef pthread_rwlock_unlock +#undef pthread_mutex_lock +#undef pthread_mutex_unlock +#undef pthread_cond_wait +#undef pthread_cond_broadcast +#undef xt_mutex_type +#define xtPublic +#endif + +/* + * ----------------------------------------------------------------------- + * INDEX CACHE HANDLES + */ + +static XTIndHandlePtr ind_alloc_handle() +{ + XTIndHandlePtr handle; + + if (!(handle = (XTIndHandlePtr) xt_calloc_ns(sizeof(XTIndHandleRec)))) + return NULL; + xt_spinlock_init_with_autoname(NULL, &handle->ih_lock); + return handle; +} + +static void ind_free_handle(XTIndHandlePtr handle) +{ + xt_spinlock_free(NULL, &handle->ih_lock); + xt_free_ns(handle); +} + +static void ind_handle_exit(XTThreadPtr self) +{ + DcHandleSlotPtr hs; + XTIndHandlePtr handle; + XTIndHandleBlockPtr hptr; + + for (int i=0; i<XT_HANDLE_SLOTS; i++) { + hs = &ind_cac_globals.cg_handle_slot[i]; + + while (hs->hs_used_handles) { + handle = hs->hs_used_handles; + xt_ind_release_handle(handle, FALSE, self); + } + + while (hs->hs_free_blocks) { + hptr = hs->hs_free_blocks; + hs->hs_free_blocks = hptr->hb_next; + xt_free(self, hptr); + } + + while (hs->hs_free_handles) { + handle = hs->hs_free_handles; + hs->hs_free_handles = handle->ih_next; + ind_free_handle(handle); + } + + ID_HANDLE_FREE_LOCK(self, &hs->hs_handles_lock); + } +} + +static void ind_handle_init(XTThreadPtr self) +{ + DcHandleSlotPtr hs; + + for (int i=0; i<XT_HANDLE_SLOTS; i++) { + hs = &ind_cac_globals.cg_handle_slot[i]; + memset(hs, 0, sizeof(DcHandleSlotRec)); + ID_HANDLE_INIT_LOCK(self, &hs->hs_handles_lock); + } +} + +//#define CHECK_HANDLE_STRUCTS + +#ifdef CHECK_HANDLE_STRUCTS +static int gdummy = 0; + +static void ic_stop_here() +{ + gdummy = gdummy + 1; + printf("Nooo %d!\n", gdummy); +} + +static void ic_check_handle_structs() +{ + XTIndHandlePtr handle, phandle; + XTIndHandleBlockPtr hptr, phptr; + int count = 0; + int ctest; + + phandle = NULL; + handle = ind_cac_globals.cg_used_handles; + while (handle) { + if (handle == phandle) + ic_stop_here(); + if (handle->ih_prev != phandle) + ic_stop_here(); + if (handle->ih_cache_reference) { + ctest = handle->x.ih_cache_block->cb_handle_count; + if (ctest == 0 || ctest > 100) + ic_stop_here(); + } + else { + ctest = handle->x.ih_handle_block->hb_ref_count; + if (ctest == 0 || ctest > 100) + ic_stop_here(); + } + phandle = handle; + handle = handle->ih_next; + count++; + if (count > 1000) + ic_stop_here(); + } + + count = 0; + hptr = ind_cac_globals.cg_free_blocks; + while (hptr) { + if (hptr == phptr) + ic_stop_here(); + phptr = hptr; + hptr = hptr->hb_next; + count++; + if (count > 1000) + ic_stop_here(); + } + + count = 0; + handle = ind_cac_globals.cg_free_handles; + while (handle) { + if (handle == phandle) + ic_stop_here(); + phandle = handle; + handle = handle->ih_next; + count++; + if (count > 1000) + ic_stop_here(); + } +} +#endif + +/* + * Get a handle to the index block. + * This function is called by index scanners (readers). + */ +xtPublic XTIndHandlePtr xt_ind_get_handle(XTOpenTablePtr ot, XTIndexPtr ind, XTIndReferencePtr iref) +{ + DcHandleSlotPtr hs; + XTIndHandlePtr handle; + + hs = &ind_cac_globals.cg_handle_slot[iref->ir_block->cb_address % XT_HANDLE_SLOTS]; + + ASSERT_NS(iref->ir_ulock == XT_UNLOCK_READ); + ID_HANDLE_LOCK(&hs->hs_handles_lock); +#ifdef CHECK_HANDLE_STRUCTS + ic_check_handle_structs(); +#endif + if ((handle = hs->hs_free_handles)) + hs->hs_free_handles = handle->ih_next; + else { + if (!(handle = ind_alloc_handle())) { + ID_HANDLE_UNLOCK(&hs->hs_handles_lock); + xt_ind_release(ot, ind, XT_UNLOCK_READ, iref); + return NULL; + } + } + if (hs->hs_used_handles) + hs->hs_used_handles->ih_prev = handle; + handle->ih_next = hs->hs_used_handles; + handle->ih_prev = NULL; + handle->ih_address = iref->ir_block->cb_address; + handle->ih_cache_reference = TRUE; + handle->x.ih_cache_block = iref->ir_block; + handle->ih_branch = iref->ir_branch; + /* {HANDLE-COUNT-USAGE} + * This is safe because: + * + * I have an Slock on the cache block, and I have + * at least an Slock on the index. + * So this excludes anyone who is reading + * cb_handle_count in the index. + * (all cache block writers, and a freeer). + * + * The increment is safe because I have the list + * lock, which is required by anyone else + * who increments or decrements this value. + */ + iref->ir_block->cb_handle_count++; + hs->hs_used_handles = handle; +#ifdef CHECK_HANDLE_STRUCTS + ic_check_handle_structs(); +#endif + ID_HANDLE_UNLOCK(&hs->hs_handles_lock); + xt_ind_release(ot, ind, XT_UNLOCK_READ, iref); + return handle; +} + +xtPublic void xt_ind_release_handle(XTIndHandlePtr handle, xtBool have_lock, XTThreadPtr thread) +{ + DcHandleSlotPtr hs; + XTIndBlockPtr block = NULL; + u_int hash_idx = NULL; + DcSegmentPtr seg = NULL; + XTIndBlockPtr xblock; + + /* The lock order is: + * 1. Cache segment (cs_lock) - This is only by ind_free_block()! + * 1. S/Slock cache block (cb_lock) + * 2. List lock (cg_handles_lock). + * 3. Handle lock (ih_lock) + */ + if (!have_lock) + xt_spinlock_lock(&handle->ih_lock); + + /* Get the lock on the cache page if required: */ + if (handle->ih_cache_reference) { + u_int file_id; + xtIndexNodeID address; + + block = handle->x.ih_cache_block; + + file_id = block->cb_file_id; + address = block->cb_address; + hash_idx = XT_NODE_ID(address) + (file_id * 223); + seg = &ind_cac_globals.cg_segment[hash_idx & IDX_CAC_SEGMENT_MASK]; + hash_idx = (hash_idx >> XT_INDEX_CACHE_SEGMENT_SHIFTS) % ind_cac_globals.cg_hash_size; + } + + xt_spinlock_unlock(&handle->ih_lock); + + /* Because of the lock order, I have to release the + * handle before I get a lock on the cache block. + * + * But, by doing this, thie cache block may be gone! + */ + if (block) { + IDX_CAC_READ_LOCK(seg, thread); + xblock = seg->cs_hash_table[hash_idx]; + while (xblock) { + if (block == xblock) { + /* Found the block... */ + xt_atomicrwlock_xlock(&block->cb_lock, thread->t_id); + goto block_found; + } + xblock = xblock->cb_next; + } + block = NULL; + block_found: + IDX_CAC_UNLOCK(seg, thread); + } + + hs = &ind_cac_globals.cg_handle_slot[handle->ih_address % XT_HANDLE_SLOTS]; + + ID_HANDLE_LOCK(&hs->hs_handles_lock); +#ifdef CHECK_HANDLE_STRUCTS + ic_check_handle_structs(); +#endif + + /* I don't need to lock the handle because I have locked + * the list, and no other thread can change the + * handle without first getting a lock on the list. + * + * In addition, the caller is the only owner of the + * handle, and the only thread with an independent + * reference to the handle. + * All other access occur over the list. + */ + + /* Remove the reference to the cache or a handle block: */ + if (handle->ih_cache_reference) { + ASSERT_NS(block == handle->x.ih_cache_block); + ASSERT_NS(block && block->cb_handle_count > 0); + /* {HANDLE-COUNT-USAGE} + * This is safe here because I have excluded + * all readers by taking an Xlock on the + * cache block. + */ + block->cb_handle_count--; + } + else { + XTIndHandleBlockPtr hptr = handle->x.ih_handle_block; + + ASSERT_NS(!handle->ih_cache_reference); + ASSERT_NS(hptr->hb_ref_count > 0); + hptr->hb_ref_count--; + if (!hptr->hb_ref_count) { + /* Put it back on the free list: */ + hptr->hb_next = hs->hs_free_blocks; + hs->hs_free_blocks = hptr; + } + } + + /* Unlink the handle: */ + if (handle->ih_next) + handle->ih_next->ih_prev = handle->ih_prev; + if (handle->ih_prev) + handle->ih_prev->ih_next = handle->ih_next; + if (hs->hs_used_handles == handle) + hs->hs_used_handles = handle->ih_next; + + /* Put it on the free list: */ + handle->ih_next = hs->hs_free_handles; + hs->hs_free_handles = handle; + +#ifdef CHECK_HANDLE_STRUCTS + ic_check_handle_structs(); +#endif + ID_HANDLE_UNLOCK(&hs->hs_handles_lock); + + if (block) + xt_atomicrwlock_unlock(&block->cb_lock, TRUE); +} + +/* Call this function before a referenced cache block is modified! + * This function is called by index updaters. + */ +xtPublic xtBool xt_ind_copy_on_write(XTIndReferencePtr iref) +{ + DcHandleSlotPtr hs; + XTIndHandleBlockPtr hptr; + u_int branch_size; + XTIndHandlePtr handle; + u_int i = 0; + + hs = &ind_cac_globals.cg_handle_slot[iref->ir_block->cb_address % XT_HANDLE_SLOTS]; + + /* {HANDLE-COUNT-USAGE} + * This is only called by updaters of this index block, or + * the free which holds an Xlock on the index block. + * + * These are all mutually exclusive for the index block. + */ + ASSERT_NS(iref->ir_block->cb_handle_count); + if (!iref->ir_block->cb_handle_count) + return OK; + + ID_HANDLE_LOCK(&hs->hs_handles_lock); +#ifdef CHECK_HANDLE_STRUCTS + ic_check_handle_structs(); +#endif + if ((hptr = hs->hs_free_blocks)) + hs->hs_free_blocks = hptr->hb_next; + else { + if (!(hptr = (XTIndHandleBlockPtr) xt_malloc_ns(sizeof(XTIndHandleBlockRec)))) { + ID_HANDLE_UNLOCK(&hs->hs_handles_lock); + return FAILED; + } + } + + branch_size = XT_GET_INDEX_BLOCK_LEN(XT_GET_DISK_2(iref->ir_branch->tb_size_2)); + memcpy(&hptr->hb_branch, iref->ir_branch, branch_size); + hptr->hb_ref_count = iref->ir_block->cb_handle_count; + + handle = hs->hs_used_handles; + while (handle) { + if (handle->ih_branch == iref->ir_branch) { + i++; + xt_spinlock_lock(&handle->ih_lock); + ASSERT_NS(handle->ih_cache_reference); + handle->ih_cache_reference = FALSE; + handle->x.ih_handle_block = hptr; + handle->ih_branch = &hptr->hb_branch; + xt_spinlock_unlock(&handle->ih_lock); +#ifndef DEBUG + if (i == hptr->hb_ref_count) + break; +#endif + } + handle = handle->ih_next; + } +#ifdef DEBUG + ASSERT_NS(hptr->hb_ref_count == i); +#endif + /* {HANDLE-COUNT-USAGE} + * It is safe to modify cb_handle_count when I have the + * list lock, and I have excluded all readers! + */ + iref->ir_block->cb_handle_count = 0; +#ifdef CHECK_HANDLE_STRUCTS + ic_check_handle_structs(); +#endif + ID_HANDLE_UNLOCK(&hs->hs_handles_lock); + + return OK; +} + +xtPublic void xt_ind_lock_handle(XTIndHandlePtr handle) +{ + xt_spinlock_lock(&handle->ih_lock); +} + +xtPublic void xt_ind_unlock_handle(XTIndHandlePtr handle) +{ + xt_spinlock_unlock(&handle->ih_lock); +} + +/* + * ----------------------------------------------------------------------- + * INIT/EXIT + */ + +/* + * Initialize the disk cache. + */ +xtPublic void xt_ind_init(XTThreadPtr self, size_t cache_size) +{ + XTIndBlockPtr block; + +#ifdef XT_USE_MYSYS + init_key_cache(&my_cache, 1024, cache_size, 100, 300); +#endif + /* Memory is devoted to the page data alone, I no longer count the size of the directory, + * or the page overhead: */ + ind_cac_globals.cg_block_count = cache_size / XT_INDEX_PAGE_SIZE; + ind_cac_globals.cg_hash_size = ind_cac_globals.cg_block_count / (IDX_CAC_SEGMENT_COUNT >> 1); + ind_cac_globals.cg_max_free = ind_cac_globals.cg_block_count / 10; + if (ind_cac_globals.cg_max_free < 8) + ind_cac_globals.cg_max_free = 8; + if (ind_cac_globals.cg_max_free > 128) + ind_cac_globals.cg_max_free = 128; + + try_(a) { + for (u_int i=0; i<IDX_CAC_SEGMENT_COUNT; i++) { + ind_cac_globals.cg_segment[i].cs_hash_table = (XTIndBlockPtr *) xt_calloc(self, ind_cac_globals.cg_hash_size * sizeof(XTIndBlockPtr)); + IDX_CAC_INIT_LOCK(self, &ind_cac_globals.cg_segment[i]); + } + + block = (XTIndBlockPtr) xt_malloc(self, ind_cac_globals.cg_block_count * sizeof(XTIndBlockRec)); + ind_cac_globals.cg_blocks = block; + xt_init_mutex_with_autoname(self, &ind_cac_globals.cg_lock); +#ifdef XT_USE_DIRECT_IO_ON_INDEX + xtWord1 *buffer; +#ifdef XT_WIN + size_t psize = 512; +#else + size_t psize = getpagesize(); +#endif + size_t diff; + + buffer = (xtWord1 *) xt_malloc(self, (ind_cac_globals.cg_block_count * XT_INDEX_PAGE_SIZE)); + diff = (size_t) buffer % psize; + if (diff != 0) { + xt_free(self, buffer); + buffer = (xtWord1 *) xt_malloc(self, (ind_cac_globals.cg_block_count * XT_INDEX_PAGE_SIZE) + psize); + diff = (size_t) buffer % psize; + if (diff != 0) + diff = psize - diff; + } + ind_cac_globals.cg_buffer = buffer; + buffer += diff; +#endif + + for (u_int i=0; i<ind_cac_globals.cg_block_count; i++) { + xt_atomicrwlock_init_with_autoname(self, &block->cb_lock); + block->cb_state = IDX_CAC_BLOCK_FREE; + block->cb_next = ind_cac_globals.cg_free_list; +#ifdef XT_USE_DIRECT_IO_ON_INDEX + block->cb_data = buffer; + buffer += XT_INDEX_PAGE_SIZE; +#endif + ind_cac_globals.cg_free_list = block; + block++; + } + ind_cac_globals.cg_free_count = ind_cac_globals.cg_block_count; +#ifdef DEBUG_CHECK_IND_CACHE + ind_cac_globals.cg_reserved_by_ots = 0; +#endif + ind_handle_init(self); + } + catch_(a) { + xt_ind_exit(self); + throw_(); + } + cont_(a); +} + +xtPublic void xt_ind_exit(XTThreadPtr self) +{ +#ifdef XT_USE_MYSYS + end_key_cache(&my_cache, 1); +#endif + for (u_int i=0; i<IDX_CAC_SEGMENT_COUNT; i++) { + if (ind_cac_globals.cg_segment[i].cs_hash_table) { + xt_free(self, ind_cac_globals.cg_segment[i].cs_hash_table); + ind_cac_globals.cg_segment[i].cs_hash_table = NULL; + IDX_CAC_FREE_LOCK(self, &ind_cac_globals.cg_segment[i]); + } + } + + if (ind_cac_globals.cg_blocks) { + xt_free(self, ind_cac_globals.cg_blocks); + ind_cac_globals.cg_blocks = NULL; + xt_free_mutex(&ind_cac_globals.cg_lock); + } +#ifdef XT_USE_DIRECT_IO_ON_INDEX + if (ind_cac_globals.cg_buffer) { + xt_free(self, ind_cac_globals.cg_buffer); + ind_cac_globals.cg_buffer = NULL; + } +#endif + ind_handle_exit(self); + + memset(&ind_cac_globals, 0, sizeof(ind_cac_globals)); +} + +xtPublic xtInt8 xt_ind_get_usage() +{ + xtInt8 size = 0; + + size = (xtInt8) (ind_cac_globals.cg_block_count - ind_cac_globals.cg_free_count) * (xtInt8) XT_INDEX_PAGE_SIZE; + return size; +} + +xtPublic xtInt8 xt_ind_get_size() +{ + xtInt8 size = 0; + + size = (xtInt8) ind_cac_globals.cg_block_count * (xtInt8) XT_INDEX_PAGE_SIZE; + return size; +} + +/* + * ----------------------------------------------------------------------- + * INDEX CHECKING + */ + +xtPublic void xt_ind_check_cache(XTIndexPtr ind) +{ + XTIndBlockPtr block; + u_int free_count, inuse_count, clean_count; + xtBool check_count = FALSE; + + if (ind == (XTIndex *) 1) { + ind = NULL; + check_count = TRUE; + } + + // Check the dirty list: + if (ind) { + u_int cnt = 0; + + block = ind->mi_dirty_list; + while (block) { + cnt++; + ASSERT_NS(block->cb_state == IDX_CAC_BLOCK_DIRTY); + block = block->cb_dirty_next; + } + ASSERT_NS(ind->mi_dirty_blocks == cnt); + } + + xt_lock_mutex_ns(&ind_cac_globals.cg_lock); + + // Check the free list: + free_count = 0; + block = ind_cac_globals.cg_free_list; + while (block) { + free_count++; + ASSERT_NS(block->cb_state == IDX_CAC_BLOCK_FREE); + block = block->cb_next; + } + ASSERT_NS(ind_cac_globals.cg_free_count == free_count); + + /* Check the LRU list: */ + XTIndBlockPtr list_block, plist_block; + + plist_block = NULL; + list_block = ind_cac_globals.cg_lru_block; + if (list_block) { + ASSERT_NS(ind_cac_globals.cg_mru_block != NULL); + ASSERT_NS(ind_cac_globals.cg_mru_block->cb_mr_used == NULL); + ASSERT_NS(list_block->cb_lr_used == NULL); + inuse_count = 0; + clean_count = 0; + while (list_block) { + inuse_count++; + ASSERT_NS(list_block->cb_state == IDX_CAC_BLOCK_DIRTY || list_block->cb_state == IDX_CAC_BLOCK_CLEAN); + if (list_block->cb_state == IDX_CAC_BLOCK_CLEAN) + clean_count++; + ASSERT_NS(block != list_block); + ASSERT_NS(list_block->cb_lr_used == plist_block); + plist_block = list_block; + list_block = list_block->cb_mr_used; + } + ASSERT_NS(ind_cac_globals.cg_mru_block == plist_block); + } + else { + inuse_count = 0; + clean_count = 0; + ASSERT_NS(ind_cac_globals.cg_mru_block == NULL); + } + +#ifdef DEBUG_CHECK_IND_CACHE + ASSERT_NS(free_count + inuse_count + ind_cac_globals.cg_reserved_by_ots + ind_cac_globals.cg_read_count == ind_cac_globals.cg_block_count); +#endif + xt_unlock_mutex_ns(&ind_cac_globals.cg_lock); + if (check_count) { + /* We have just flushed, check how much is now free/clean. */ + if (free_count + clean_count < 10) { + /* This could be a problem: */ + printf("Cache very low!\n"); + } + } +} + +#ifdef XXXXDEBUG +static void ind_cac_check_on_dirty_list(DcSegmentPtr seg, XTIndBlockPtr block) +{ + XTIndBlockPtr list_block, plist_block; + xtBool found = FALSE; + + plist_block = NULL; + list_block = seg->cs_dirty_list[block->cb_file_id % XT_INDEX_CACHE_FILE_SLOTS]; + while (list_block) { + ASSERT_NS(list_block->cb_state == IDX_CAC_BLOCK_DIRTY); + ASSERT_NS(list_block->cb_dirty_prev == plist_block); + if (list_block == block) + found = TRUE; + plist_block = list_block; + list_block = list_block->cb_dirty_next; + } + ASSERT_NS(found); +} + +static void ind_cac_check_dirty_list(DcSegmentPtr seg, XTIndBlockPtr block) +{ + XTIndBlockPtr list_block, plist_block; + + for (u_int j=0; j<XT_INDEX_CACHE_FILE_SLOTS; j++) { + plist_block = NULL; + list_block = seg->cs_dirty_list[j]; + while (list_block) { + ASSERT_NS(list_block->cb_state == IDX_CAC_BLOCK_DIRTY); + ASSERT_NS(block != list_block); + ASSERT_NS(list_block->cb_dirty_prev == plist_block); + plist_block = list_block; + list_block = list_block->cb_dirty_next; + } + } +} + +#endif + +/* + * ----------------------------------------------------------------------- + * FREEING INDEX CACHE + */ + +/* + * This function return TRUE if the block is freed. + * This function returns FALSE if the block cannot be found, or the + * block is not clean. + * + * We also return FALSE if we cannot copy the block to the handle + * (if this is required). This will be due to out-of-memory! + */ +static xtBool ind_free_block(XTOpenTablePtr ot, XTIndBlockPtr block) +{ + XTIndBlockPtr xblock, pxblock; + u_int hash_idx; + u_int file_id; + xtIndexNodeID address; + DcSegmentPtr seg; + +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + file_id = block->cb_file_id; + address = block->cb_address; + + hash_idx = XT_NODE_ID(address) + (file_id * 223); + seg = &ind_cac_globals.cg_segment[hash_idx & IDX_CAC_SEGMENT_MASK]; + hash_idx = (hash_idx >> XT_INDEX_CACHE_SEGMENT_SHIFTS) % ind_cac_globals.cg_hash_size; + + IDX_CAC_WRITE_LOCK(seg, ot->ot_thread); + + pxblock = NULL; + xblock = seg->cs_hash_table[hash_idx]; + while (xblock) { + if (block == xblock) { + /* Found the block... */ + xt_atomicrwlock_xlock(&block->cb_lock, ot->ot_thread->t_id); + if (block->cb_state != IDX_CAC_BLOCK_CLEAN) { + /* This block cannot be freeed: */ + xt_atomicrwlock_unlock(&block->cb_lock, TRUE); + IDX_CAC_UNLOCK(seg, ot->ot_thread); +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return FALSE; + } + + goto free_the_block; + } + pxblock = xblock; + xblock = xblock->cb_next; + } + + IDX_CAC_UNLOCK(seg, ot->ot_thread); + + /* Not found (this can happen, if block was freed by another thread) */ +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return FALSE; + + free_the_block: + + /* If the block is reference by a handle, then we + * have to copy the data to the handle before we + * free the page: + */ + /* {HANDLE-COUNT-USAGE} + * This access is safe because: + * + * We have an Xlock on the cache block, which excludes + * all other writers that want to change the cache block + * and also all readers of the cache block, because + * they all have at least an Slock on the cache block. + */ + if (block->cb_handle_count) { + XTIndReferenceRec iref; + + iref.ir_ulock = XT_UNLOCK_WRITE; + iref.ir_block = block; + iref.ir_branch = (XTIdxBranchDPtr) block->cb_data; + if (!xt_ind_copy_on_write(&iref)) { + xt_atomicrwlock_unlock(&block->cb_lock, TRUE); + return FALSE; + } + } + + /* Block is clean, remove from the hash table: */ + if (pxblock) + pxblock->cb_next = block->cb_next; + else + seg->cs_hash_table[hash_idx] = block->cb_next; + + xt_lock_mutex_ns(&ind_cac_globals.cg_lock); + + /* Remove from the MRU list: */ + if (ind_cac_globals.cg_lru_block == block) + ind_cac_globals.cg_lru_block = block->cb_mr_used; + if (ind_cac_globals.cg_mru_block == block) + ind_cac_globals.cg_mru_block = block->cb_lr_used; + + /* Note, I am updating blocks for which I have no lock + * here. But I think this is OK because I have a lock + * for the MRU list. + */ + if (block->cb_lr_used) + block->cb_lr_used->cb_mr_used = block->cb_mr_used; + if (block->cb_mr_used) + block->cb_mr_used->cb_lr_used = block->cb_lr_used; + + /* The block is now free: */ + block->cb_next = ind_cac_globals.cg_free_list; + ind_cac_globals.cg_free_list = block; + ind_cac_globals.cg_free_count++; + block->cb_state = IDX_CAC_BLOCK_FREE; + IDX_TRACE("%d- f%x\n", (int) XT_NODE_ID(address), (int) XT_GET_DISK_2(block->cb_data)); + + /* Unlock BEFORE the block is reused! */ + xt_atomicrwlock_unlock(&block->cb_lock, TRUE); + + xt_unlock_mutex_ns(&ind_cac_globals.cg_lock); + + IDX_CAC_UNLOCK(seg, ot->ot_thread); + +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return TRUE; +} + +#define IND_CACHE_MAX_BLOCKS_TO_FREE 100 + +/* + * Return the number of blocks freed. + * + * The idea is to grab a list of blocks to free. + * The list consists of the LRU blocks that are + * clean. + * + * Free as many as possible (up to max of blocks_required) + * from the list, even if LRU position has changed + * (or we have a race if there are too few blocks). + * However, if the block cannot be found, or is dirty + * we must skip it. + * + * Repeat until we find no blocks for the list, or + * we have freed 'blocks_required'. + * + * 'not_this' is a block that must not be freed because + * it is locked by the calling thread! + */ +static u_int ind_cac_free_lru_blocks(XTOpenTablePtr ot, u_int blocks_required, XTIdxBranchDPtr not_this) +{ + register DcGlobalsRec *dcg = &ind_cac_globals; + XTIndBlockPtr to_free[IND_CACHE_MAX_BLOCKS_TO_FREE]; + int count; + XTIndBlockPtr block; + u_int blocks_freed = 0; + XTIndBlockPtr locked_block; + +#ifdef XT_USE_DIRECT_IO_ON_INDEX +#error This will not work! +#endif + locked_block = (XTIndBlockPtr) ((xtWord1 *) not_this - offsetof(XTIndBlockRec, cb_data)); + + retry: + xt_lock_mutex_ns(&ind_cac_globals.cg_lock); + block = dcg->cg_lru_block; + count = 0; + while (block && count < IND_CACHE_MAX_BLOCKS_TO_FREE) { + if (block != locked_block && block->cb_state == IDX_CAC_BLOCK_CLEAN) { + to_free[count] = block; + count++; + } + block = block->cb_mr_used; + } + xt_unlock_mutex_ns(&ind_cac_globals.cg_lock); + + if (!count) + return blocks_freed; + + for (int i=0; i<count; i++) { + if (ind_free_block(ot, to_free[i])) + blocks_freed++; + if (blocks_freed >= blocks_required && + ind_cac_globals.cg_free_count >= ind_cac_globals.cg_max_free + blocks_required) + return blocks_freed; + } + + goto retry; +} + +/* + * ----------------------------------------------------------------------- + * MAIN CACHE FUNCTIONS + */ + +/* + * Fetch the block. Note, if we are about to write the block + * then there is no need to read it from disk! + */ +static XTIndBlockPtr ind_cac_fetch(XTOpenTablePtr ot, xtIndexNodeID address, DcSegmentPtr *ret_seg, xtBool read_data) +{ + register XTOpenFilePtr file = ot->ot_ind_file; + register XTIndBlockPtr block, new_block; + register DcSegmentPtr seg; + register u_int hash_idx; + register DcGlobalsRec *dcg = &ind_cac_globals; + size_t red_size; + +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + /* Address, plus file ID multiplied by my favorite prime number! */ + hash_idx = XT_NODE_ID(address) + (file->fr_id * 223); + seg = &dcg->cg_segment[hash_idx & IDX_CAC_SEGMENT_MASK]; + hash_idx = (hash_idx >> XT_INDEX_CACHE_SEGMENT_SHIFTS) % dcg->cg_hash_size; + + IDX_CAC_READ_LOCK(seg, ot->ot_thread); + block = seg->cs_hash_table[hash_idx]; + while (block) { + if (XT_NODE_ID(block->cb_address) == XT_NODE_ID(address) && block->cb_file_id == file->fr_id) { + ASSERT_NS(block->cb_state != IDX_CAC_BLOCK_FREE); + + /* Check how recently this page has been used: */ + if (XT_TIME_DIFF(block->cb_ru_time, dcg->cg_ru_now) > (dcg->cg_block_count >> 1)) { + xt_lock_mutex_ns(&dcg->cg_lock); + + /* Move to the front of the MRU list: */ + block->cb_ru_time = ++dcg->cg_ru_now; + if (dcg->cg_mru_block != block) { + /* Remove from the MRU list: */ + if (dcg->cg_lru_block == block) + dcg->cg_lru_block = block->cb_mr_used; + if (block->cb_lr_used) + block->cb_lr_used->cb_mr_used = block->cb_mr_used; + if (block->cb_mr_used) + block->cb_mr_used->cb_lr_used = block->cb_lr_used; + + /* Make the block the most recently used: */ + if ((block->cb_lr_used = dcg->cg_mru_block)) + dcg->cg_mru_block->cb_mr_used = block; + block->cb_mr_used = NULL; + dcg->cg_mru_block = block; + if (!dcg->cg_lru_block) + dcg->cg_lru_block = block; + } + + xt_unlock_mutex_ns(&dcg->cg_lock); + } + + *ret_seg = seg; +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + ot->ot_thread->st_statistics.st_ind_cache_hit++; + return block; + } + block = block->cb_next; + } + + /* Block not found... */ + IDX_CAC_UNLOCK(seg, ot->ot_thread); + + /* Check the open table reserve list first: */ + if ((new_block = ot->ot_ind_res_bufs)) { + ot->ot_ind_res_bufs = new_block->cb_next; + ot->ot_ind_res_count--; +#ifdef DEBUG_CHECK_IND_CACHE + xt_lock_mutex_ns(&dcg->cg_lock); + dcg->cg_reserved_by_ots--; + dcg->cg_read_count++; + xt_unlock_mutex_ns(&dcg->cg_lock); +#endif + goto use_free_block; + } + + free_some_blocks: + if (!dcg->cg_free_list) { + if (!ind_cac_free_lru_blocks(ot, 1, NULL)) { + if (!dcg->cg_free_list) { + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_NO_INDEX_CACHE); +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return NULL; + } + } + } + + /* Get a free block: */ + xt_lock_mutex_ns(&dcg->cg_lock); + if (!(new_block = dcg->cg_free_list)) { + xt_unlock_mutex_ns(&dcg->cg_lock); + goto free_some_blocks; + } + ASSERT_NS(new_block->cb_state == IDX_CAC_BLOCK_FREE); + dcg->cg_free_list = new_block->cb_next; + dcg->cg_free_count--; +#ifdef DEBUG_CHECK_IND_CACHE + dcg->cg_read_count++; +#endif + xt_unlock_mutex_ns(&dcg->cg_lock); + + use_free_block: + new_block->cb_address = address; + new_block->cb_file_id = file->fr_id; + new_block->cb_state = IDX_CAC_BLOCK_CLEAN; + new_block->cb_handle_count = 0; + new_block->cp_flush_seq = 0; + new_block->cb_dirty_next = NULL; + new_block->cb_dirty_prev = NULL; + + if (read_data) { + if (!xt_pread_file(file, xt_ind_node_to_offset(ot->ot_table, address), XT_INDEX_PAGE_SIZE, 0, new_block->cb_data, &red_size, &ot->ot_thread->st_statistics.st_ind, ot->ot_thread)) { + xt_lock_mutex_ns(&dcg->cg_lock); + new_block->cb_next = dcg->cg_free_list; + dcg->cg_free_list = new_block; + dcg->cg_free_count++; +#ifdef DEBUG_CHECK_IND_CACHE + dcg->cg_read_count--; +#endif + new_block->cb_state = IDX_CAC_BLOCK_FREE; + IDX_TRACE("%d- F%x\n", (int) XT_NODE_ID(address), (int) XT_GET_DISK_2(new_block->cb_data)); + xt_unlock_mutex_ns(&dcg->cg_lock); +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return NULL; + } + IDX_TRACE("%d- R%x\n", (int) XT_NODE_ID(address), (int) XT_GET_DISK_2(new_block->cb_data)); + ot->ot_thread->st_statistics.st_ind_cache_miss++; + } + else + red_size = 0; + // PMC - I don't think this is required! memset(new_block->cb_data + red_size, 0, XT_INDEX_PAGE_SIZE - red_size); + + IDX_CAC_WRITE_LOCK(seg, ot->ot_thread); + block = seg->cs_hash_table[hash_idx]; + while (block) { + if (XT_NODE_ID(block->cb_address) == XT_NODE_ID(address) && block->cb_file_id == file->fr_id) { + /* Oops, someone else was faster! */ + xt_lock_mutex_ns(&dcg->cg_lock); + new_block->cb_next = dcg->cg_free_list; + dcg->cg_free_list = new_block; + dcg->cg_free_count++; +#ifdef DEBUG_CHECK_IND_CACHE + dcg->cg_read_count--; +#endif + new_block->cb_state = IDX_CAC_BLOCK_FREE; + IDX_TRACE("%d- F%x\n", (int) XT_NODE_ID(address), (int) XT_GET_DISK_2(new_block->cb_data)); + xt_unlock_mutex_ns(&dcg->cg_lock); + goto done_ok; + } + block = block->cb_next; + } + block = new_block; + + /* Make the block the most recently used: */ + xt_lock_mutex_ns(&dcg->cg_lock); + block->cb_ru_time = ++dcg->cg_ru_now; + if ((block->cb_lr_used = dcg->cg_mru_block)) + dcg->cg_mru_block->cb_mr_used = block; + block->cb_mr_used = NULL; + dcg->cg_mru_block = block; + if (!dcg->cg_lru_block) + dcg->cg_lru_block = block; +#ifdef DEBUG_CHECK_IND_CACHE + dcg->cg_read_count--; +#endif + xt_unlock_mutex_ns(&dcg->cg_lock); + + /* Add to the hash table: */ + block->cb_next = seg->cs_hash_table[hash_idx]; + seg->cs_hash_table[hash_idx] = block; + + done_ok: + *ret_seg = seg; +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return block; +} + +static xtBool ind_cac_get(XTOpenTablePtr ot, xtIndexNodeID address, DcSegmentPtr *ret_seg, XTIndBlockPtr *ret_block) +{ + register XTOpenFilePtr file = ot->ot_ind_file; + register XTIndBlockPtr block; + register DcSegmentPtr seg; + register u_int hash_idx; + register DcGlobalsRec *dcg = &ind_cac_globals; + + hash_idx = XT_NODE_ID(address) + (file->fr_id * 223); + seg = &dcg->cg_segment[hash_idx & IDX_CAC_SEGMENT_MASK]; + hash_idx = (hash_idx >> XT_INDEX_CACHE_SEGMENT_SHIFTS) % dcg->cg_hash_size; + + IDX_CAC_READ_LOCK(seg, ot->ot_thread); + block = seg->cs_hash_table[hash_idx]; + while (block) { + if (XT_NODE_ID(block->cb_address) == XT_NODE_ID(address) && block->cb_file_id == file->fr_id) { + ASSERT_NS(block->cb_state != IDX_CAC_BLOCK_FREE); + + *ret_seg = seg; + *ret_block = block; + return OK; + } + block = block->cb_next; + } + IDX_CAC_UNLOCK(seg, ot->ot_thread); + + /* Block not found: */ + *ret_seg = NULL; + *ret_block = NULL; + return OK; +} + +xtPublic xtBool xt_ind_write(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID address, size_t size, xtWord1 *data) +{ + XTIndBlockPtr block; + DcSegmentPtr seg; + + if (!(block = ind_cac_fetch(ot, address, &seg, FALSE))) + return FAILED; + + xt_atomicrwlock_xlock(&block->cb_lock, ot->ot_thread->t_id); + ASSERT_NS(block->cb_state == IDX_CAC_BLOCK_CLEAN || block->cb_state == IDX_CAC_BLOCK_DIRTY); + memcpy(block->cb_data, data, size); + block->cp_flush_seq = ot->ot_table->tab_ind_flush_seq; + if (block->cb_state != IDX_CAC_BLOCK_DIRTY) { + TRACK_BLOCK_WRITE(offset); + xt_spinlock_lock(&ind->mi_dirty_lock); + if ((block->cb_dirty_next = ind->mi_dirty_list)) + ind->mi_dirty_list->cb_dirty_prev = block; + block->cb_dirty_prev = NULL; + ind->mi_dirty_list = block; + ind->mi_dirty_blocks++; + xt_spinlock_unlock(&ind->mi_dirty_lock); + block->cb_state = IDX_CAC_BLOCK_DIRTY; + } + xt_atomicrwlock_unlock(&block->cb_lock, TRUE); + IDX_CAC_UNLOCK(seg, ot->ot_thread); +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_changed++; +#endif + return OK; +} + +/* + * Update the cache, if in RAM. + */ +xtPublic xtBool xt_ind_write_cache(XTOpenTablePtr ot, xtIndexNodeID address, size_t size, xtWord1 *data) +{ + XTIndBlockPtr block; + DcSegmentPtr seg; + + if (!ind_cac_get(ot, address, &seg, &block)) + return FAILED; + + if (block) { + xt_atomicrwlock_xlock(&block->cb_lock, ot->ot_thread->t_id); + ASSERT_NS(block->cb_state == IDX_CAC_BLOCK_CLEAN || block->cb_state == IDX_CAC_BLOCK_DIRTY); + memcpy(block->cb_data, data, size); + xt_atomicrwlock_unlock(&block->cb_lock, TRUE); + IDX_CAC_UNLOCK(seg, ot->ot_thread); + } + + return OK; +} + +xtPublic xtBool xt_ind_clean(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID address) +{ + XTIndBlockPtr block; + DcSegmentPtr seg; + + if (!ind_cac_get(ot, address, &seg, &block)) + return FAILED; + if (block) { + xt_atomicrwlock_xlock(&block->cb_lock, ot->ot_thread->t_id); + ASSERT_NS(block->cb_state == IDX_CAC_BLOCK_CLEAN || block->cb_state == IDX_CAC_BLOCK_DIRTY); + + if (block->cb_state == IDX_CAC_BLOCK_DIRTY) { + /* Take the block off the dirty list: */ + xt_spinlock_lock(&ind->mi_dirty_lock); + if (block->cb_dirty_next) + block->cb_dirty_next->cb_dirty_prev = block->cb_dirty_prev; + if (block->cb_dirty_prev) + block->cb_dirty_prev->cb_dirty_next = block->cb_dirty_next; + if (ind->mi_dirty_list == block) + ind->mi_dirty_list = block->cb_dirty_next; + ind->mi_dirty_blocks--; + xt_spinlock_unlock(&ind->mi_dirty_lock); + block->cb_state = IDX_CAC_BLOCK_CLEAN; + } + xt_atomicrwlock_unlock(&block->cb_lock, TRUE); + + IDX_CAC_UNLOCK(seg, ot->ot_thread); + } + + return OK; +} + +xtPublic xtBool xt_ind_read_bytes(XTOpenTablePtr ot, xtIndexNodeID address, size_t size, xtWord1 *data) +{ + XTIndBlockPtr block; + DcSegmentPtr seg; + + if (!(block = ind_cac_fetch(ot, address, &seg, TRUE))) + return FAILED; + + xt_atomicrwlock_slock(&block->cb_lock); + memcpy(data, block->cb_data, size); + xt_atomicrwlock_unlock(&block->cb_lock, FALSE); + IDX_CAC_UNLOCK(seg, ot->ot_thread); + return OK; +} + +xtPublic xtBool xt_ind_fetch(XTOpenTablePtr ot, xtIndexNodeID address, XTPageLockType ltype, XTIndReferencePtr iref) +{ + register XTIndBlockPtr block; + DcSegmentPtr seg; + xtWord2 branch_size; + + ASSERT_NS(iref->ir_ulock == XT_UNLOCK_NONE); + if (!(block = ind_cac_fetch(ot, address, &seg, TRUE))) + return NULL; + + branch_size = XT_GET_DISK_2(((XTIdxBranchDPtr) block->cb_data)->tb_size_2); + if (XT_GET_INDEX_BLOCK_LEN(branch_size) < 2 || XT_GET_INDEX_BLOCK_LEN(branch_size) > XT_INDEX_PAGE_SIZE) { + IDX_CAC_UNLOCK(seg, ot->ot_thread); + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, ot->ot_table->tab_name); + return FAILED; + } + + if (ltype == XT_XLOCK_LEAF) { + if (XT_IS_NODE(branch_size)) + ltype = XT_LOCK_READ; + else + ltype = XT_LOCK_WRITE; + } + + if (ltype == XT_LOCK_WRITE) { + xt_atomicrwlock_xlock(&block->cb_lock, ot->ot_thread->t_id); + iref->ir_ulock = XT_UNLOCK_WRITE; + } + else { + xt_atomicrwlock_slock(&block->cb_lock); + iref->ir_ulock = XT_UNLOCK_READ; + } + + IDX_CAC_UNLOCK(seg, ot->ot_thread); + + /* {DIRECT-IO} + * Direct I/O requires that the buffer is 512 byte aligned. + * To do this, cb_data is turned into a pointer, instead + * of an array. + * As a result, we need to pass a pointer to both the + * cache block and the cache block data: + */ + iref->ir_block = block; + iref->ir_branch = (XTIdxBranchDPtr) block->cb_data; + return OK; +} + +xtPublic xtBool xt_ind_release(XTOpenTablePtr ot, XTIndexPtr ind, XTPageUnlockType XT_UNUSED(utype), XTIndReferencePtr iref) +{ + register XTIndBlockPtr block; + + block = iref->ir_block; + + if (utype == XT_UNLOCK_R_UPDATE || utype == XT_UNLOCK_W_UPDATE) { + /* The page was update: */ + ASSERT_NS(block->cb_state == IDX_CAC_BLOCK_CLEAN || block->cb_state == IDX_CAC_BLOCK_DIRTY); + block->cp_flush_seq = ot->ot_table->tab_ind_flush_seq; + if (block->cb_state != IDX_CAC_BLOCK_DIRTY) { + TRACK_BLOCK_WRITE(offset); + xt_spinlock_lock(&ind->mi_dirty_lock); + if ((block->cb_dirty_next = ind->mi_dirty_list)) + ind->mi_dirty_list->cb_dirty_prev = block; + block->cb_dirty_prev = NULL; + ind->mi_dirty_list = block; + ind->mi_dirty_blocks++; + xt_spinlock_unlock(&ind->mi_dirty_lock); + block->cb_state = IDX_CAC_BLOCK_DIRTY; + } + } + +#ifdef DEBUG + if (utype == XT_UNLOCK_W_UPDATE) + utype = XT_UNLOCK_WRITE; + else if (utype == XT_UNLOCK_R_UPDATE) + utype = XT_UNLOCK_READ; + ASSERT_NS(iref->ir_ulock == utype); +#endif + xt_atomicrwlock_unlock(&block->cb_lock, iref->ir_ulock == XT_UNLOCK_WRITE ? TRUE : FALSE); +#ifdef DEBUG + iref->ir_ulock = XT_UNLOCK_NONE; +#endif + return OK; +} + +xtPublic xtBool xt_ind_reserve(XTOpenTablePtr ot, u_int count, XTIdxBranchDPtr not_this) +{ + register XTIndBlockPtr block; + register DcGlobalsRec *dcg = &ind_cac_globals; + +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_reserved = count; + ot->ot_ind_reads = 0; +#endif +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + while (ot->ot_ind_res_count < count) { + if (!dcg->cg_free_list) { + if (!ind_cac_free_lru_blocks(ot, count - ot->ot_ind_res_count, not_this)) { + if (!dcg->cg_free_list) { + xt_ind_free_reserved(ot); + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_NO_INDEX_CACHE); +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return FAILED; + } + } + } + + /* Get a free block: */ + xt_lock_mutex_ns(&dcg->cg_lock); + while (ot->ot_ind_res_count < count && (block = dcg->cg_free_list)) { + ASSERT_NS(block->cb_state == IDX_CAC_BLOCK_FREE); + dcg->cg_free_list = block->cb_next; + dcg->cg_free_count--; + block->cb_next = ot->ot_ind_res_bufs; + ot->ot_ind_res_bufs = block; + ot->ot_ind_res_count++; +#ifdef DEBUG_CHECK_IND_CACHE + dcg->cg_reserved_by_ots++; +#endif + } + xt_unlock_mutex_ns(&dcg->cg_lock); + } +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return OK; +} + +xtPublic void xt_ind_free_reserved(XTOpenTablePtr ot) +{ +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + if (ot->ot_ind_res_bufs) { + register XTIndBlockPtr block, fblock; + register DcGlobalsRec *dcg = &ind_cac_globals; + + xt_lock_mutex_ns(&dcg->cg_lock); + block = ot->ot_ind_res_bufs; + while (block) { + fblock = block; + block = block->cb_next; + + fblock->cb_next = dcg->cg_free_list; + dcg->cg_free_list = fblock; +#ifdef DEBUG_CHECK_IND_CACHE + dcg->cg_reserved_by_ots--; +#endif + dcg->cg_free_count++; + } + xt_unlock_mutex_ns(&dcg->cg_lock); + ot->ot_ind_res_bufs = NULL; + ot->ot_ind_res_count = 0; + } +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif +} + +xtPublic void xt_ind_unreserve(XTOpenTablePtr ot) +{ + if (!ind_cac_globals.cg_free_list) + xt_ind_free_reserved(ot); +} + +xtPublic void xt_load_indices(XTThreadPtr self, XTOpenTablePtr ot) +{ + register XTTableHPtr tab = ot->ot_table; + register XTIndBlockPtr block; + DcSegmentPtr seg; + xtIndexNodeID id; + + xt_lock_mutex_ns(&tab->tab_ind_flush_lock); + + for (id=1; id < XT_NODE_ID(tab->tab_ind_eof); id++) { + if (!(block = ind_cac_fetch(ot, id, &seg, TRUE))) { + xt_unlock_mutex_ns(&tab->tab_ind_flush_lock); + xt_throw(self); + } + IDX_CAC_UNLOCK(seg, ot->ot_thread); + } + + xt_unlock_mutex_ns(&tab->tab_ind_flush_lock); +} + + diff --git a/storage/pbxt/src/cache_xt.h b/storage/pbxt/src/cache_xt.h new file mode 100644 index 00000000000..d113bb2f907 --- /dev/null +++ b/storage/pbxt/src/cache_xt.h @@ -0,0 +1,148 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-05-24 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_cache_h__ +#define __xt_cache_h__ + +//#define XT_USE_MYSYS + +#include "filesys_xt.h" +#include "index_xt.h" + +struct XTOpenTable; +struct XTIdxReadBuffer; + +#ifdef DEBUG +//#define XT_USE_CACHE_DEBUG_SIZES +#endif + +#ifdef XT_USE_CACHE_DEBUG_SIZES +#define XT_INDEX_CACHE_SEGMENT_SHIFTS 1 +#else +#define XT_INDEX_CACHE_SEGMENT_SHIFTS 3 +#endif + +#define IDX_CAC_BLOCK_FREE 0 +#define IDX_CAC_BLOCK_CLEAN 1 +#define IDX_CAC_BLOCK_DIRTY 2 + +typedef enum XTPageLockType { XT_LOCK_READ, XT_LOCK_WRITE, XT_XLOCK_LEAF }; +typedef enum XTPageUnlockType { XT_UNLOCK_NONE, XT_UNLOCK_READ, XT_UNLOCK_WRITE, XT_UNLOCK_R_UPDATE, XT_UNLOCK_W_UPDATE }; + +/* A block is X locked if it is being changed or freed. + * A block is S locked if it is being read. + */ +typedef struct XTIndBlock { + xtIndexNodeID cb_address; /* The block address. */ + u_int cb_file_id; /* The file id of the block. */ + /* This is protected by cs_lock */ + struct XTIndBlock *cb_next; /* Pointer to next block on hash list, or next free block on free list. */ + /* This is protected by mi_dirty_lock */ + struct XTIndBlock *cb_dirty_next; /* Double link for dirty blocks, next pointer. */ + struct XTIndBlock *cb_dirty_prev; /* Double link for dirty blocks, previous pointer. */ + /* This is protected by cg_lock */ + xtWord4 cb_ru_time; /* If this is in the top 1/4 don't change position in MRU list. */ + struct XTIndBlock *cb_mr_used; /* More recently used blocks. */ + struct XTIndBlock *cb_lr_used; /* Less recently used blocks. */ + /* Protected by cb_lock: */ + XTAtomicRWLockRec cb_lock; + xtWord1 cb_state; /* Block status. */ + xtWord2 cb_handle_count; /* TRUE if this page is referenced by a handle. */ + xtWord2 cp_flush_seq; +#ifdef XT_USE_DIRECT_IO_ON_INDEX + xtWord1 *cb_data; +#else + xtWord1 cb_data[XT_INDEX_PAGE_SIZE]; +#endif +} XTIndBlockRec, *XTIndBlockPtr; + +typedef struct XTIndReference { + XTPageUnlockType ir_ulock; + XTIndBlockPtr ir_block; + XTIdxBranchDPtr ir_branch; +} XTIndReferenceRec, *XTIndReferencePtr; + +typedef struct XTIndFreeBlock { + XTDiskValue1 if_status_1; + XTDiskValue1 if_unused1_1; + XTDiskValue2 if_unused2_2; + XTDiskValue4 if_unused3_4; + XTDiskValue8 if_next_block_8; +} XTIndFreeBlockRec, *XTIndFreeBlockPtr; + +typedef struct XTIndHandleBlock { + xtWord4 hb_ref_count; + struct XTIndHandleBlock *hb_next; + XTIdxBranchDRec hb_branch; +} XTIndHandleBlockRec, *XTIndHandleBlockPtr; + +typedef struct XTIndHandle { + struct XTIndHandle *ih_next; + struct XTIndHandle *ih_prev; + XTSpinLockRec ih_lock; + xtIndexNodeID ih_address; + xtBool ih_cache_reference; /* True if this handle references the cache. */ + union { + XTIndBlockPtr ih_cache_block; + XTIndHandleBlockPtr ih_handle_block; + } x; + XTIdxBranchDPtr ih_branch; +} XTIndHandleRec, *XTIndHandlePtr; + +void xt_ind_init(XTThreadPtr self, size_t cache_size); +void xt_ind_exit(XTThreadPtr self); + +xtInt8 xt_ind_get_usage(); +xtInt8 xt_ind_get_size(); +xtBool xt_ind_write(struct XTOpenTable *ot, XTIndexPtr ind, xtIndexNodeID offset, size_t size, xtWord1 *data); +xtBool xt_ind_write_cache(struct XTOpenTable *ot, xtIndexNodeID offset, size_t size, xtWord1 *data); +xtBool xt_ind_clean(struct XTOpenTable *ot, XTIndexPtr ind, xtIndexNodeID offset); +xtBool xt_ind_read_bytes(struct XTOpenTable *ot, xtIndexNodeID offset, size_t size, xtWord1 *data); +void xt_ind_check_cache(XTIndexPtr ind); +xtBool xt_ind_reserve(struct XTOpenTable *ot, u_int count, XTIdxBranchDPtr not_this); +void xt_ind_free_reserved(struct XTOpenTable *ot); +void xt_ind_unreserve(struct XTOpenTable *ot); +void xt_load_indices(XTThreadPtr self, struct XTOpenTable *ot); + +xtBool xt_ind_fetch(struct XTOpenTable *ot, xtIndexNodeID node, XTPageLockType ltype, XTIndReferencePtr iref); +xtBool xt_ind_release(struct XTOpenTable *ot, XTIndexPtr ind, XTPageUnlockType utype, XTIndReferencePtr iref); + +void xt_ind_lock_handle(XTIndHandlePtr handle); +void xt_ind_unlock_handle(XTIndHandlePtr handle); +xtBool xt_ind_copy_on_write(XTIndReferencePtr iref); + +XTIndHandlePtr xt_ind_get_handle(struct XTOpenTable *ot, XTIndexPtr ind, XTIndReferencePtr iref); +void xt_ind_release_handle(XTIndHandlePtr handle, xtBool have_lock, XTThreadPtr thread); + +#ifdef DEBUG +//#define DEBUG_CHECK_IND_CACHE +#endif + +//#define XT_TRACE_INDEX + +#ifdef XT_TRACE_INDEX +#define IDX_TRACE(x, y, z) xt_trace(x, y, z) +#else +#define IDX_TRACE(x, y, z) +#endif + +#endif diff --git a/storage/pbxt/src/ccutils_xt.cc b/storage/pbxt/src/ccutils_xt.cc new file mode 100644 index 00000000000..1d93e4c34b3 --- /dev/null +++ b/storage/pbxt/src/ccutils_xt.cc @@ -0,0 +1,69 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-05-16 Paul McCullagh + * + * H&G2JCtL + * + * C++ Utilities + */ + +#include "xt_config.h" + +#include "pthread_xt.h" +#include "ccutils_xt.h" +#include "bsearch_xt.h" + +static int ccu_compare_object(XTThreadPtr XT_UNUSED(self), register const void XT_UNUSED(*thunk), register const void *a, register const void *b) +{ + XTObject *obj_ptr = (XTObject *) b; + + return obj_ptr->compare(a); +} + +void XTListImp::append(XTThreadPtr self, XTObject *info, void *key) { + size_t idx; + + if (li_item_count == 0) + idx = 0; + else if (li_item_count == 1) { + int r; + + if ((r = li_items[0]->compare(key)) == 0) + idx = 0; + else if (r < 0) + idx = 0; + else + idx = 1; + } + else { + xt_bsearch(self, key, li_items, li_item_count, sizeof(void *), &idx, NULL, ccu_compare_object); + } + + if (!xt_realloc(NULL, (void **) &li_items, (li_item_count + 1) * sizeof(void *))) { + if (li_referenced) + info->release(self); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return; + } + memmove(&li_items[idx+1], &li_items[idx], (li_item_count-idx) * sizeof(void *)); + li_items[idx] = info; + li_item_count++; +} + + diff --git a/storage/pbxt/src/ccutils_xt.h b/storage/pbxt/src/ccutils_xt.h new file mode 100644 index 00000000000..a800073869d --- /dev/null +++ b/storage/pbxt/src/ccutils_xt.h @@ -0,0 +1,220 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-05-16 Paul McCullagh + * + * H&G2JCtL + * + * C++ Utilities + */ + +#ifndef __ccutils_xt_h__ +#define __ccutils_xt_h__ + +#include <errno.h> + +#include "xt_defs.h" +#include "thread_xt.h" + +class XTObject +{ + private: + u_int o_refcnt; + + public: + inline XTObject() { o_refcnt = 1; } + + virtual ~XTObject() { } + + inline void reference() { + o_refcnt++; + } + + inline void release(XTThreadPtr self) { + ASSERT(o_refcnt > 0); + o_refcnt--; + if (o_refcnt == 0) { + finalize(self); + delete this; + } + } + + virtual XTObject *factory(XTThreadPtr self) { + XTObject *new_obj; + + if (!(new_obj = new XTObject())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return new_obj; + } + + virtual XTObject *clone(XTThreadPtr self) { + XTObject *new_obj; + + new_obj = factory(self); + new_obj->init(self, this); + return new_obj; + } + + virtual void init(XTThreadPtr self) { (void) self; } + virtual void init(XTThreadPtr self, XTObject *obj) { (void) obj; init(self); } + virtual void finalize(XTThreadPtr self) { (void) self; } + virtual int compare(const void *key) { (void) key; return -1; } +}; + +class XTListImp +{ + protected: + bool li_referenced; + u_int li_item_count; + XTObject **li_items; + + public: + inline XTListImp() : li_referenced(true), li_item_count(0), li_items(NULL) { } + + inline void setNonReferenced() { li_referenced = false; } + + void append(XTThreadPtr self, XTObject *info) { + if (!xt_realloc(NULL, (void **) &li_items, (li_item_count + 1) * sizeof(void *))) { + if (li_referenced) + info->release(self); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return; + } + li_items[li_item_count] = info; + li_item_count++; + } + + void insert(XTThreadPtr self, XTObject *info, u_int i) { + if (!xt_realloc(NULL, (void **) &li_items, (li_item_count + 1) * sizeof(void *))) { + if (li_referenced) + info->release(self); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return; + } + memmove(&li_items[i+1], &li_items[i], (li_item_count-i) * sizeof(XTObject *)); + li_items[i] = info; + li_item_count++; + } + + void addToFront(XTThreadPtr self, XTObject *info) { + insert(self, info, 0); + } + + /* Will sort! */ + void append(XTThreadPtr self, XTObject *info, void *key); + + inline bool remove(XTObject *info) { + for (u_int i=0; i<li_item_count; i++) { + if (li_items[i] == info) { + li_item_count--; + memmove(&li_items[i], &li_items[i+1], (li_item_count - i) * sizeof(XTObject *)); + return true; + } + } + return false; + } + + inline bool remove(XTThreadPtr self, u_int i) { + XTObject *item; + + if (i >= li_item_count) + return false; + item = li_items[i]; + li_item_count--; + memmove(&li_items[i], &li_items[i+1], (li_item_count - i) * sizeof(void *)); + if (li_referenced) + item->release(self); + return true; + } + + inline XTObject *take(u_int i) { + XTObject *item; + + if (i >= li_item_count) + return NULL; + item = li_items[i]; + li_item_count--; + memmove(&li_items[i], &li_items[i+1], (li_item_count - i) * sizeof(void *)); + return item; + } + + inline u_int size() const { return li_item_count; } + + inline void setEmpty(XTThreadPtr self) { + if (li_items) + xt_free(self, li_items); + li_item_count = 0; + li_items = NULL; + } + + inline bool isEmpty() { return li_item_count == 0; } + + inline XTObject *itemAt(u_int i) const { + if (i >= li_item_count) + return NULL; + return li_items[i]; + } +}; + + +template <class T> class XTList : public XTListImp +{ + public: + inline XTList() : XTListImp() { } + + inline void append(XTThreadPtr self, T *a) { XTListImp::append(self, a); } + inline void insert(XTThreadPtr self, T *a, u_int i) { XTListImp::insert(self, a, i); } + inline void addToFront(XTThreadPtr self, T *a) { XTListImp::addToFront(self, a); } + + inline bool remove(T *a) { return XTListImp::remove(a); } + + inline bool remove(XTThreadPtr self, u_int i) { return XTListImp::remove(self, i); } + + inline T *take(u_int i) { return (T *) XTListImp::take(i); } + + inline T *itemAt(u_int i) const { return (T *) XTListImp::itemAt(i); } + + inline u_int indexOf(T *a) { + u_int i; + + for (i=0; i<size(); i++) { + if (itemAt(i) == a) + break; + } + return i; + } + + void deleteAll(XTThreadPtr self) + { + for (u_int i=0; i<size(); i++) { + if (li_referenced) + itemAt(i)->release(self); + } + setEmpty(self); + } + + void clone(XTThreadPtr self, XTListImp *list) + { + deleteAll(self); + for (u_int i=0; i<list->size(); i++) { + XTListImp::append(self, list->itemAt(i)->clone(self)); + } + } +}; + +#endif diff --git a/storage/pbxt/src/database_xt.cc b/storage/pbxt/src/database_xt.cc new file mode 100644 index 00000000000..d15ffc6d06e --- /dev/null +++ b/storage/pbxt/src/database_xt.cc @@ -0,0 +1,1280 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-15 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <string.h> +#include <stdio.h> + +#include "pthread_xt.h" +#include "hashtab_xt.h" +#include "filesys_xt.h" +#include "database_xt.h" +#include "memory_xt.h" +#include "heap_xt.h" +#include "datalog_xt.h" +#include "strutil_xt.h" +#include "util_xt.h" +#include "trace_xt.h" + +#ifdef DEBUG +//#define XT_TEST_XACT_OVERFLOW +#endif + +#ifndef NAME_MAX +#define NAME_MAX 128 +#endif + +/* + * ----------------------------------------------------------------------- + * GLOBALS + */ + +xtPublic xtLogOffset xt_db_log_file_threshold; +xtPublic size_t xt_db_log_buffer_size; +xtPublic size_t xt_db_transaction_buffer_size; +xtPublic size_t xt_db_checkpoint_frequency; +xtPublic off_t xt_db_data_log_threshold; +xtPublic size_t xt_db_data_file_grow_size; +xtPublic size_t xt_db_row_file_grow_size; +xtPublic int xt_db_garbage_threshold; +xtPublic int xt_db_log_file_count; +xtPublic int xt_db_auto_increment_mode; /* 0 = MySQL compatible, 1 = PrimeBase Compatible. */ +xtPublic int xt_db_offline_log_function; /* 0 = recycle logs, 1 = delete logs, 2 = keep logs */ +xtPublic int xt_db_sweeper_priority; /* 0 = low (default), 1 = normal, 2 = high */ + +xtPublic XTSortedListPtr xt_db_open_db_by_id = NULL; +xtPublic XTHashTabPtr xt_db_open_databases = NULL; +xtPublic time_t xt_db_approximate_time = 0; /* A "fast" alternative timer (not too accurate). */ + +static xtDatabaseID db_next_id = 1; +static volatile XTOpenFilePtr db_lock_file = NULL; + +/* + * ----------------------------------------------------------------------- + * LOCK/UNLOCK INSTALLATION + */ + +xtPublic void xt_lock_installation(XTThreadPtr self, char *installation_path) +{ + char file_path[PATH_MAX]; + char buffer[101]; + size_t red_size; + llong pid; + xtBool cd = pbxt_crash_debug; + + xt_strcpy(PATH_MAX, file_path, installation_path); + xt_add_pbxt_file(PATH_MAX, file_path, "no-debug"); + if (xt_fs_exists(file_path)) + pbxt_crash_debug = FALSE; + xt_strcpy(PATH_MAX, file_path, installation_path); + xt_add_pbxt_file(PATH_MAX, file_path, "crash-debug"); + if (xt_fs_exists(file_path)) + pbxt_crash_debug = TRUE; + + if (pbxt_crash_debug != cd) { + if (pbxt_crash_debug) + xt_logf(XT_NT_WARNING, "Crash debugging has been turned on ('crash-debug' file exists)\n"); + else + xt_logf(XT_NT_WARNING, "Crash debugging has been turned off ('no-debug' file exists)\n"); + } + else if (pbxt_crash_debug) + xt_logf(XT_NT_WARNING, "Crash debugging is enabled\n"); + + /* Moved the lock file out of the pbxt directory so that + * it is possible to drop the pbxt database! + */ + xt_strcpy(PATH_MAX, file_path, installation_path); + xt_add_dir_char(PATH_MAX, file_path); + xt_strcat(PATH_MAX, file_path, "pbxt-lock"); + db_lock_file = xt_open_file(self, file_path, XT_FS_CREATE | XT_FS_MAKE_PATH); + + try_(a) { + if (!xt_lock_file(self, db_lock_file)) { + xt_logf(XT_NT_ERROR, "A server appears to already be running\n"); + xt_logf(XT_NT_ERROR, "The file: %s, is locked\n", file_path); + xt_throw_xterr(XT_CONTEXT, XT_ERR_SERVER_RUNNING); + } + if (!xt_pread_file(db_lock_file, 0, 100, 0, buffer, &red_size, &self->st_statistics.st_rec, self)) + xt_throw(self); + if (red_size > 0) { + buffer[red_size] = 0; +#ifdef XT_WIN + pid = (llong) _atoi64(buffer); +#else + pid = atoll(buffer); +#endif + /* Problem with this code is, after a restart + * the process ID's are reused. + * If some system process grabs the proc id that + * the server had on the last run, then + * the database will not start. + if (xt_process_exists((xtProcID) pid)) { + xt_logf(XT_NT_ERROR, "A server appears to already be running, process ID: %lld\n", pid); + xt_logf(XT_NT_ERROR, "Remove the file: %s, if this is not the case\n", file_path); + xt_throw_xterr(XT_CONTEXT, XT_ERR_SERVER_RUNNING); + } + */ + xt_logf(XT_NT_INFO, "The server was not shutdown correctly, recovery required\n"); +#ifdef XT_BACKUP_BEFORE_RECOVERY + if (pbxt_crash_debug) { + /* The server was not shut down correctly. Make a backup before + * we start recovery. + */ + char extension[100]; + + for (int i=1;;i++) { + xt_strcpy(PATH_MAX, file_path, installation_path); + xt_remove_dir_char(file_path); + sprintf(extension, "-recovery-%d", i); + xt_strcat(PATH_MAX, file_path, extension); + if (!xt_fs_exists(file_path)) + break; + } + xt_logf(XT_NT_INFO, "In order to reproduce recovery errors a backup of the installation\n"); + xt_logf(XT_NT_INFO, "will be made to:\n"); + xt_logf(XT_NT_INFO, "%s\n", file_path); + xt_logf(XT_NT_INFO, "Copy in progress...\n"); + xt_fs_copy_dir(self, installation_path, file_path); + xt_logf(XT_NT_INFO, "Copy OK\n"); + } +#endif + } + + sprintf(buffer, "%lld", (llong) xt_getpid()); + xt_set_eof_file(self, db_lock_file, 0); + if (!xt_pwrite_file(db_lock_file, 0, strlen(buffer), buffer, &self->st_statistics.st_rec, self)) + xt_throw(self); + } + catch_(a) { + xt_close_file(self, db_lock_file); + db_lock_file = NULL; + xt_throw(self); + } + cont_(a); +} + +xtPublic void xt_unlock_installation(XTThreadPtr self, char *installation_path) +{ + if (db_lock_file) { + char lock_file[PATH_MAX]; + + xt_unlock_file(NULL, db_lock_file); + xt_close_file_ns(db_lock_file); + db_lock_file = NULL; + + xt_strcpy(PATH_MAX, lock_file, installation_path); + xt_add_dir_char(PATH_MAX, lock_file); + xt_strcat(PATH_MAX, lock_file, "pbxt-lock"); + xt_fs_delete(self, lock_file); + } +} + +int *xt_bad_pointer = 0; + +void xt_crash_me(void) +{ + if (pbxt_crash_debug) + *xt_bad_pointer = 123; +} + +/* + * ----------------------------------------------------------------------- + * INIT/EXIT DATABASE + */ + +static xtBool db_hash_comp(void *key, void *data) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) data; + + return strcmp((char *) key, db->db_name) == 0; +} + +static xtHashValue db_hash(xtBool is_key, void *key_data) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) key_data; + + if (is_key) + return xt_ht_hash((char *) key_data); + return xt_ht_hash(db->db_name); +} + +static xtBool db_hash_comp_ci(void *key, void *data) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) data; + + return strcasecmp((char *) key, db->db_name) == 0; +} + +static xtHashValue db_hash_ci(xtBool is_key, void *key_data) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) key_data; + + if (is_key) + return xt_ht_casehash((char *) key_data); + return xt_ht_casehash(db->db_name); +} + +static void db_hash_free(XTThreadPtr self, void *data) +{ + xt_heap_release(self, (XTDatabaseHPtr) data); +} + +static int db_cmp_db_id(struct XTThread XT_UNUSED(*self), register const void XT_UNUSED(*thunk), register const void *a, register const void *b) +{ + xtDatabaseID db_id = *((xtDatabaseID *) a); + XTDatabaseHPtr *db_ptr = (XTDatabaseHPtr *) b; + + if (db_id == (*db_ptr)->db_id) + return 0; + if (db_id < (*db_ptr)->db_id) + return -1; + return 1; +} + +xtPublic void xt_init_databases(XTThreadPtr self) +{ + if (pbxt_ignore_case) + xt_db_open_databases = xt_new_hashtable(self, db_hash_comp_ci, db_hash_ci, db_hash_free, TRUE, TRUE); + else + xt_db_open_databases = xt_new_hashtable(self, db_hash_comp, db_hash, db_hash_free, TRUE, TRUE); + xt_db_open_db_by_id = xt_new_sortedlist(self, sizeof(XTDatabaseHPtr), 20, 10, db_cmp_db_id, NULL, NULL, FALSE, FALSE); +} + +xtPublic void xt_stop_database_threads(XTThreadPtr self, xtBool sync) +{ + u_int len = 0; + XTDatabaseHPtr *dbptr; + XTDatabaseHPtr db = NULL; + + if (xt_db_open_db_by_id) + len = xt_sl_get_size(xt_db_open_db_by_id); + for (u_int i=0; i<len; i++) { + if ((dbptr = (XTDatabaseHPtr *) xt_sl_item_at(xt_db_open_db_by_id, i))) { + db = *dbptr; + if (sync) { + /* Wait for the sweeper: */ + xt_wait_for_sweeper(self, db, 16); + + /* Wait for the writer: */ + xt_wait_for_writer(self, db); + + /* Wait for the checkpointer: */ + xt_wait_for_checkpointer(self, db); + } + xt_stop_checkpointer(self, db); + xt_stop_writer(self, db); + xt_stop_sweeper(self, db); + xt_stop_compactor(self, db); + } + } +} + +xtPublic void xt_exit_databases(XTThreadPtr self) +{ + if (xt_db_open_databases) { + xt_free_hashtable(self, xt_db_open_databases); + xt_db_open_databases = NULL; + } + if (xt_db_open_db_by_id) { + xt_free_sortedlist(self, xt_db_open_db_by_id); + xt_db_open_db_by_id = NULL; + } +} + +xtPublic void xt_create_database(XTThreadPtr self, char *path) +{ + xt_fs_mkdir(self, path); +} + +static void db_finalize(XTThreadPtr self, void *x) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) x; + + xt_stop_checkpointer(self, db); + xt_stop_compactor(self, db); + xt_stop_sweeper(self, db); + xt_stop_writer(self, db); + + xt_sl_delete(self, xt_db_open_db_by_id, &db->db_id); + /* + * Important is that xt_db_pool_exit() is called + * before xt_xn_exit_db() because xt_xn_exit_db() + * frees the checkpoint information which + * may be required to shutdown the tables, which + * flushes tables, and therefore does a checkpoint. + */ + /* This was the previous order of shutdown: + xt_xn_exit_db(self, db); + xt_dl_exit_db(self, db); + xt_db_pool_exit(self, db); + db->db_indlogs.ilp_exit(self); + */ + + xt_db_pool_exit(self, db); + db->db_indlogs.ilp_exit(self); + xt_dl_exit_db(self, db); + xt_xn_exit_db(self, db); + xt_tab_exit_db(self, db); + if (db->db_name) { + xt_free(self, db->db_name); + db->db_name = NULL; + } + if (db->db_main_path) { + xt_free(self, db->db_main_path); + db->db_main_path = NULL; + } +} + +static void db_onrelease(XTThreadPtr self, void XT_UNUSED(*x)) +{ + /* Signal threads waiting for exclusive use of the database: */ + if (xt_db_open_databases) // The database may already be closed. + xt_ht_signal(self, xt_db_open_databases); +} + +xtPublic void xt_add_pbxt_file(size_t size, char *path, const char *file) +{ + xt_add_dir_char(size, path); + xt_strcat(size, path, "pbxt"); + xt_add_dir_char(size, path); + xt_strcat(size, path, file); +} + +xtPublic void xt_add_location_file(size_t size, char *path) +{ + xt_add_dir_char(size, path); + xt_strcat(size, path, "pbxt"); + xt_add_dir_char(size, path); + xt_strcat(size, path, "location"); +} + +xtPublic void xt_add_pbxt_dir(size_t size, char *path) +{ + xt_add_dir_char(size, path); + xt_strcat(size, path, "pbxt"); +} + +xtPublic void xt_add_system_dir(size_t size, char *path) +{ + xt_add_dir_char(size, path); + xt_strcat(size, path, "pbxt"); + xt_add_dir_char(size, path); + xt_strcat(size, path, "system"); +} + +xtPublic void xt_add_data_dir(size_t size, char *path) +{ + xt_add_dir_char(size, path); + xt_strcat(size, path, "pbxt"); + xt_add_dir_char(size, path); + xt_strcat(size, path, "data"); +} + +/* + * I have a problem here. I cannot rely on the path given to xt_get_database() to be + * consistant. When called from ha_create_table() the path is not modified. + * However when called from ha_open() the path is first transformed by a call to + * fn_format(). I have given an example from a stack trace below. + * + * In this case the odd path comes from the option: + * --tmpdir=/Users/build/Development/mysql/debug-mysql/mysql-test/var//tmp + * + * #3 0x001a3818 in ha_pbxt::create(char const*, st_table*, st_ha_create_information*) + * (this=0x2036898, table_path=0xf0060bd0 "/users/build/development/mysql/debug-my + * sql/mysql-test/var//tmp/#sql5718_1_0.frm", table_arg=0xf00601c0, + * create_info=0x2017410) at ha_pbxt.cc:2323 + * #4 0x00140d74 in ha_create_table(char const*, st_ha_create_information*, bool) + * (name=0xf0060bd0 "/users/build/development/mysql/debug-mysql/mysql-te + * st/var//tmp/#sql5718_1_0.frm", create_info=0x2017410, + * update_create_info=false) at handler.cc:1387 + * + * #4 0x0013f7a4 in handler::ha_open(char const*, int, int) (this=0x203ba98, + * name=0xf005eb70 "/users/build/development/mysql/debug-mysql/mysql-te + * st/var/tmp/#sql5718_1_1", mode=2, test_if_locked=2) at handler.cc:993 + * #5 0x000cd900 in openfrm(char const*, char const*, unsigned, unsigned, + * unsigned, st_table*) (name=0xf005f260 "/users/build/development/mys + * ql/debug-mysql/mysql-test/var//tmp/#sql5718_1_1.frm", + * alias=0xf005fb90 "#sql-5718_1", db_stat=7, prgflag=44, + * ha_open_flags=0, outparam=0x2039e18) at table.cc:771 + * + * As a result, I no longer use the entire path as the key to find a database. + * Just the last component of the path (i.e. the database name) should be + * sufficient!? + */ +xtPublic XTDatabaseHPtr xt_get_database(XTThreadPtr self, char *path, xtBool multi_path) +{ + XTDatabaseHPtr db = NULL; + char db_path[PATH_MAX]; + char db_name[NAME_MAX]; + xtBool multi_path_db = FALSE; + + /* A database may not be in use when this is called. */ + ASSERT(!self->st_database); + xt_ht_lock(self, xt_db_open_databases); + pushr_(xt_ht_unlock, xt_db_open_databases); + + xt_strcpy(PATH_MAX, db_path, path); + xt_add_location_file(PATH_MAX, db_path); + if (multi_path || xt_fs_exists(db_path)) + multi_path_db = TRUE; + + xt_strcpy(PATH_MAX, db_path, path); + xt_remove_dir_char(db_path); + xt_strcpy(NAME_MAX, db_name, xt_last_directory_of_path(db_path)); + + db = (XTDatabaseHPtr) xt_ht_get(self, xt_db_open_databases, db_name); + if (!db) { + pushsr_(db, xt_heap_release, (XTDatabaseHPtr) xt_heap_new(self, sizeof(XTDatabaseRec), db_finalize)); + xt_heap_set_release_callback(self, db, db_onrelease); + db->db_id = db_next_id++; + db->db_name = xt_dup_string(self, db_name); + db->db_main_path = xt_dup_string(self, db_path); + db->db_multi_path = multi_path_db; +#ifdef XT_TEST_XACT_OVERFLOW + /* Test transaction ID overflow: */ + db->db_xn_curr_id = 0xFFFFFFFF - 30; +#endif + xt_db_pool_init(self, db); + xt_tab_init_db(self, db); + xt_dl_init_db(self, db); + + /* Initialize the index logs: */ + db->db_indlogs.ilp_init(self, db, XT_INDEX_WRITE_BUFFER_SIZE); + + xt_xn_init_db(self, db); + xt_sl_insert(self, xt_db_open_db_by_id, &db->db_id, &db); + + xt_start_sweeper(self, db); + xt_start_compactor(self, db); + xt_start_writer(self, db); + xt_start_checkpointer(self, db); + + popr_(); + xt_ht_put(self, xt_db_open_databases, db); + + /* The recovery process could attach parts of the open + * database to the thread! + */ + xt_unuse_database(self, self); + + } + xt_heap_reference(self, db); + freer_(); + + /* {INDEX-RECOV_ROWID} + * Wait for sweeper to finish processing possibly + * unswept transactions after recovery. + * This is required because during recovery for + * all index entries written the row_id is set. + * + * When the row ID is set, this means that the row + * is "clean". i.e. visible to all transactions. + * + * Obviously this is not necessary the case for all + * index entries recovered. For example, + * transactions that still need to be swept may be + * rolled back. + * + * As a result, we have to wait the the sweeper + * to complete. Only then can we be sure that + * all index entries that are not visible have + * been removed. + * + * {OPEN-DB-SWEEPER-WAIT} + * This has been moved to after the release of the open + * database lock because: + * + * - We are waiting for the sweeper which may run out of + * record cache. + * - If it runs out of cache it well wait + * for the freeer thread. + * - For the freeer thread to be able to work it needs + * to open the database. + * - To open the database it needs the open database + * lock. + */ + pushr_(xt_heap_release, db); + xt_wait_for_sweeper(self, db, 0); + popr_(); + + return db; +} + +xtPublic XTDatabaseHPtr xt_get_database_by_id(XTThreadPtr self, xtDatabaseID db_id) +{ + XTDatabaseHPtr *dbptr; + XTDatabaseHPtr db = NULL; + + xt_ht_lock(self, xt_db_open_databases); + pushr_(xt_ht_unlock, xt_db_open_databases); + if ((dbptr = (XTDatabaseHPtr *) xt_sl_find(self, xt_db_open_db_by_id, &db_id))) { + db = *dbptr; + xt_heap_reference(self, db); + } + freer_(); // xt_ht_unlock(xt_db_open_databases) + return db; +} + +xtPublic void xt_check_database(XTThreadPtr self) +{ + xt_check_tables(self); + /* + xt_check_handlefiles(self, db); + */ +} + +xtPublic void xt_drop_database(XTThreadPtr self, XTDatabaseHPtr db) +{ + char path[PATH_MAX]; + char db_name[NAME_MAX]; + XTOpenDirPtr od; + char *file; + XTTablePathPtr *tp_ptr; + + xt_ht_lock(self, xt_db_open_databases); + pushr_(xt_ht_unlock, xt_db_open_databases); + + /* Shutdown the database daemons: */ + xt_stop_checkpointer(self, db); + xt_stop_sweeper(self, db); + xt_stop_compactor(self, db); + xt_stop_writer(self, db); + + /* Remove the database from the directory: */ + xt_strcpy(NAME_MAX, db_name, db->db_name); + xt_ht_del(self, xt_db_open_databases, db_name); + + /* Release the lock on the database directory: */ + freer_(); // xt_ht_unlock(xt_db_open_databases) + + /* Delete the transaction logs: */ + xt_xlog_delete_logs(self, db); + + /* Delete the data logs: */ + xt_dl_delete_logs(self, db); + + for (u_int i=0; i<xt_sl_get_size(db->db_table_paths); i++) { + + tp_ptr = (XTTablePathPtr *) xt_sl_item_at(db->db_table_paths, i); + + xt_strcpy(PATH_MAX, path, (*tp_ptr)->tp_path); + + /* Delete all files in the database: */ + pushsr_(od, xt_dir_close, xt_dir_open(self, path, NULL)); + while (xt_dir_next(self, od)) { + file = xt_dir_name(self, od); + if (xt_ends_with(file, ".xtr") || + xt_ends_with(file, ".xtd") || + xt_ends_with(file, ".xti") || + xt_ends_with(file, ".xt")) + { + xt_add_dir_char(PATH_MAX, path); + xt_strcat(PATH_MAX, path, file); + xt_fs_delete(self, path); + xt_remove_last_name_of_path(path); + } + } + freer_(); // xt_dir_close(od) + + } + if (!db->db_multi_path) { + xt_strcpy(PATH_MAX, path, db->db_main_path); + xt_add_pbxt_dir(PATH_MAX, path); + if (!xt_fs_rmdir(NULL, path)) + xt_log_and_clear_exception(self); + } +} + +/* + * Open/use a database. + */ +xtPublic void xt_open_database(XTThreadPtr self, char *path, xtBool multi_path) +{ + XTDatabaseHPtr db; + + /* We cannot get a database, without unusing the current + * first. The reason is that the restart process will + * partially set the current database! + */ + xt_unuse_database(self, self); + db = xt_get_database(self, path, multi_path); + pushr_(xt_heap_release, db); + xt_use_database(self, db, XT_FOR_USER); + freer_(); // xt_heap_release(self, db); +} + +/* This function can only be called if you do not already have a database in + * use. This is because to get a database pointer you are not allowed + * to have a database in use! + */ +xtPublic void xt_use_database(XTThreadPtr self, XTDatabaseHPtr db, int what_for) +{ + /* Check if a transaction is in progress. If so, + * we cannot change the database! + */ + if (self->st_xact_data || self->st_database) + xt_throw_xterr(XT_CONTEXT, XT_ERR_CANNOT_CHANGE_DB); + + xt_heap_reference(self, db); + self->st_database = db; + xt_xn_init_thread(self, what_for); +} + +xtPublic void xt_unuse_database(XTThreadPtr self, XTThreadPtr other_thr) +{ + /* Abort the transacion if it belongs exclusively to this thread. */ + xt_lock_mutex(self, &other_thr->t_lock); + pushr_(xt_unlock_mutex, &other_thr->t_lock); + + xt_xn_exit_thread(other_thr); + if (other_thr->st_database) { + xt_heap_release(self, other_thr->st_database); + other_thr->st_database = NULL; + } + + freer_(); +} + +xtPublic void xt_db_init_thread(XTThreadPtr XT_UNUSED(self), XTThreadPtr XT_UNUSED(new_thread)) +{ +#ifdef XT_IMPLEMENT_NO_ACTION + memset(&new_thread->st_restrict_list, 0, sizeof(XTBasicListRec)); + new_thread->st_restrict_list.bl_item_size = sizeof(XTRestrictItemRec); +#endif +} + +xtPublic void xt_db_exit_thread(XTThreadPtr self) +{ +#ifdef XT_IMPLEMENT_NO_ACTION + xt_bl_free(NULL, &self->st_restrict_list); +#endif + xt_unuse_database(self, self); +} + +/* + * ----------------------------------------------------------------------- + * OPEN TABLE POOL + */ + +#ifdef UNUSED_CODE +static void check_free_list(XTDatabaseHPtr db) +{ + XTOpenTablePtr ot; + u_int cnt = 0; + + ot = db->db_ot_pool.otp_mr_used; + if (ot) + ASSERT_NS(!ot->ot_otp_mr_used); + ot = db->db_ot_pool.otp_lr_used; + if (ot) + ASSERT_NS(!ot->ot_otp_lr_used); + while (ot) { + cnt++; + ot = ot->ot_otp_mr_used; + } + ASSERT_NS(cnt == db->db_ot_pool.otp_total_free); +} +#endif + +xtPublic void xt_db_pool_init(XTThreadPtr self, XTDatabaseHPtr db) +{ + memset(&db->db_ot_pool, 0, sizeof(XTAllTablePoolsRec)); + xt_init_mutex_with_autoname(self, &db->db_ot_pool.opt_lock); + xt_init_cond(self, &db->db_ot_pool.opt_cond); +} + +xtPublic void xt_db_pool_exit(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTOpenTablePoolPtr table_pool, tmp; + XTOpenTablePtr ot, tmp_ot; + + xt_free_mutex(&db->db_ot_pool.opt_lock); + xt_free_cond(&db->db_ot_pool.opt_cond); + + for (u_int i=0; i<XT_OPEN_TABLE_POOL_HASH_SIZE; i++) { + table_pool = db->db_ot_pool.otp_hash[i]; + while (table_pool) { + tmp = table_pool->opt_next_hash; + ot = table_pool->opt_free_list; + while (ot) { + tmp_ot = ot->ot_otp_next_free; + ot->ot_thread = self; + xt_close_table(ot, TRUE, FALSE); + ot = tmp_ot; + } + xt_free(self, table_pool); + table_pool = tmp; + } + } +} + +static XTOpenTablePoolPtr db_get_open_table_pool(XTDatabaseHPtr db, xtTableID tab_id) +{ + XTOpenTablePoolPtr table_pool; + u_int hash; + + hash = tab_id % XT_OPEN_TABLE_POOL_HASH_SIZE; + table_pool = db->db_ot_pool.otp_hash[hash]; + while (table_pool) { + if (table_pool->opt_tab_id == tab_id) + return table_pool; + table_pool = table_pool->opt_next_hash; + } + + if (!(table_pool = (XTOpenTablePoolPtr) xt_malloc_ns(sizeof(XTOpenTablePoolRec)))) + return NULL; + + table_pool->opt_db = db; + table_pool->opt_tab_id = tab_id; + table_pool->opt_total_open = 0; + table_pool->opt_locked = FALSE; + table_pool->opt_flushing = 0; + table_pool->opt_free_list = NULL; + table_pool->opt_next_hash = db->db_ot_pool.otp_hash[hash]; + db->db_ot_pool.otp_hash[hash] = table_pool; + + return table_pool; +} + +static void db_free_open_table_pool(XTThreadPtr self, XTOpenTablePoolPtr table_pool) +{ + if (!table_pool->opt_locked && !table_pool->opt_flushing && !table_pool->opt_total_open) { + XTOpenTablePoolPtr ptr, pptr = NULL; + u_int hash; + + hash = table_pool->opt_tab_id % XT_OPEN_TABLE_POOL_HASH_SIZE; + ptr = table_pool->opt_db->db_ot_pool.otp_hash[hash]; + while (ptr) { + if (ptr == table_pool) + break; + pptr = ptr; + ptr = ptr->opt_next_hash; + } + + if (ptr == table_pool) { + if (pptr) + pptr->opt_next_hash = table_pool->opt_next_hash; + else + table_pool->opt_db->db_ot_pool.otp_hash[hash] = table_pool->opt_next_hash; + } + + xt_free(self, table_pool); + } +} + +static XTOpenTablePoolPtr db_lock_table_pool(XTThreadPtr self, XTDatabaseHPtr db, xtTableID tab_id, xtBool flush_table, xtBool wait_for_open) +{ + XTOpenTablePoolPtr table_pool; + XTOpenTablePtr ot, tmp_ot; + + xt_lock_mutex(self, &db->db_ot_pool.opt_lock); + pushr_(xt_unlock_mutex, &db->db_ot_pool.opt_lock); + + if (!(table_pool = db_get_open_table_pool(db, tab_id))) + xt_throw(self); + + /* Wait for the lock: */ + while (table_pool->opt_locked) { + xt_timed_wait_cond(self, &db->db_ot_pool.opt_cond, &db->db_ot_pool.opt_lock, 2000); + if (!(table_pool = db_get_open_table_pool(db, tab_id))) + xt_throw(self); + } + + /* Lock it: */ + table_pool->opt_locked = TRUE; + + if (flush_table) { + table_pool->opt_flushing++; + freer_(); // xt_unlock_mutex(db_ot_pool.opt_lock) + + pushr_(xt_db_unlock_table_pool, table_pool); + /* During this time, background processes can use the + * pool! + * + * May also do a flush, but this is now taken care + * of here [*10*] + */ + if ((ot = xt_db_open_pool_table(self, db, tab_id, NULL, TRUE))) { + pushr_(xt_db_return_table_to_pool, ot); + xt_sync_flush_table(self, ot); + freer_(); //xt_db_return_table_to_pool_foreground(ot); + } + + popr_(); // Discard xt_db_unlock_table_pool_no_lock(table_pool) + + xt_lock_mutex(self, &db->db_ot_pool.opt_lock); + pushr_(xt_unlock_mutex, &db->db_ot_pool.opt_lock); + table_pool->opt_flushing--; + } + + /* Free all open tables not in use: */ + ot = table_pool->opt_free_list; + table_pool->opt_free_list = NULL; + while (ot) { + tmp_ot = ot->ot_otp_next_free; + + /* Remove from MRU list: */ + if (db->db_ot_pool.otp_lr_used == ot) + db->db_ot_pool.otp_lr_used = ot->ot_otp_mr_used; + if (db->db_ot_pool.otp_mr_used == ot) + db->db_ot_pool.otp_mr_used = ot->ot_otp_lr_used; + if (ot->ot_otp_lr_used) + ot->ot_otp_lr_used->ot_otp_mr_used = ot->ot_otp_mr_used; + if (ot->ot_otp_mr_used) + ot->ot_otp_mr_used->ot_otp_lr_used = ot->ot_otp_lr_used; + + if (db->db_ot_pool.otp_lr_used) + db->db_ot_pool.otp_free_time = db->db_ot_pool.otp_lr_used->ot_otp_free_time; + + ASSERT_NS(db->db_ot_pool.otp_total_free > 0); + db->db_ot_pool.otp_total_free--; + + /* Close the table: */ + ASSERT(table_pool->opt_total_open > 0); + table_pool->opt_total_open--; + + ot->ot_thread = self; + xt_close_table(ot, table_pool->opt_total_open == 0, FALSE); + + /* Go to the next: */ + ot = tmp_ot; + } + + /* Wait for other to close: */ + if (wait_for_open) { + while (table_pool->opt_total_open > 0) { + xt_timed_wait_cond_ns(&db->db_ot_pool.opt_cond, &db->db_ot_pool.opt_lock, 2000); + } + } + + freer_(); // xt_unlock_mutex(db_ot_pool.opt_lock) + return table_pool; +} + +xtPublic XTOpenTablePoolPtr xt_db_lock_table_pool_by_name(XTThreadPtr self, XTDatabaseHPtr db, XTPathStrPtr tab_name, xtBool no_load, xtBool flush_table, xtBool missing_ok, xtBool wait_for_open, XTTableHPtr *ret_tab) +{ + XTOpenTablePoolPtr table_pool; + XTTableHPtr tab; + xtTableID tab_id; + + pushsr_(tab, xt_heap_release, xt_use_table(self, tab_name, no_load, missing_ok, NULL)); + if (!tab) { + freer_(); // xt_heap_release(tab) + return NULL; + } + + tab_id = tab->tab_id; + + if (ret_tab) { + *ret_tab = tab; + table_pool = db_lock_table_pool(self, db, tab_id, flush_table, wait_for_open); + popr_(); // Discard xt_heap_release(tab) + return table_pool; + } + + freer_(); // xt_heap_release(tab) + return db_lock_table_pool(self, db, tab_id, flush_table, wait_for_open); +} + +xtPublic void xt_db_wait_for_open_tables(XTThreadPtr self, XTOpenTablePoolPtr table_pool) +{ + XTDatabaseHPtr db = table_pool->opt_db; + + xt_lock_mutex(self, &db->db_ot_pool.opt_lock); + pushr_(xt_unlock_mutex, &db->db_ot_pool.opt_lock); + + /* Wait for other to close: */ + while (table_pool->opt_total_open > 0) { + xt_timed_wait_cond(self, &db->db_ot_pool.opt_cond, &db->db_ot_pool.opt_lock, 2000); + } + + freer_(); // xt_unlock_mutex(db_ot_pool.opt_lock) +} + +xtPublic void xt_db_unlock_table_pool(XTThreadPtr self, XTOpenTablePoolPtr table_pool) +{ + XTDatabaseHPtr db; + + if (!table_pool) + return; + + db = table_pool->opt_db; + xt_lock_mutex(self, &db->db_ot_pool.opt_lock); + pushr_(xt_unlock_mutex, &db->db_ot_pool.opt_lock); + + table_pool->opt_locked = FALSE; + xt_broadcast_cond(self, &db->db_ot_pool.opt_cond); + db_free_open_table_pool(NULL, table_pool); + + freer_(); // xt_unlock_mutex(db_ot_pool.opt_lock) +} + +xtPublic XTOpenTablePtr xt_db_open_table_using_tab(XTTableHPtr tab, XTThreadPtr thread) +{ + XTDatabaseHPtr db = tab->tab_db; + XTOpenTablePoolPtr table_pool; + XTOpenTablePtr ot; + + xt_lock_mutex_ns(&db->db_ot_pool.opt_lock); + + if (!(table_pool = db_get_open_table_pool(db, tab->tab_id))) + goto failed; + + while (table_pool->opt_locked) { + if (!xt_timed_wait_cond_ns(&db->db_ot_pool.opt_cond, &db->db_ot_pool.opt_lock, 2000)) + goto failed_1; + if (!(table_pool = db_get_open_table_pool(db, tab->tab_id))) + goto failed; + } + + if ((ot = table_pool->opt_free_list)) { + /* Remove from the free list: */ + table_pool->opt_free_list = ot->ot_otp_next_free; + + /* Remove from MRU list: */ + if (db->db_ot_pool.otp_lr_used == ot) + db->db_ot_pool.otp_lr_used = ot->ot_otp_mr_used; + if (db->db_ot_pool.otp_mr_used == ot) + db->db_ot_pool.otp_mr_used = ot->ot_otp_lr_used; + if (ot->ot_otp_lr_used) + ot->ot_otp_lr_used->ot_otp_mr_used = ot->ot_otp_mr_used; + if (ot->ot_otp_mr_used) + ot->ot_otp_mr_used->ot_otp_lr_used = ot->ot_otp_lr_used; + + if (db->db_ot_pool.otp_lr_used) + db->db_ot_pool.otp_free_time = db->db_ot_pool.otp_lr_used->ot_otp_free_time; + + ASSERT_NS(db->db_ot_pool.otp_total_free > 0); + db->db_ot_pool.otp_total_free--; + + ot->ot_thread = thread; + goto done_ok; + } + + if ((ot = xt_open_table(tab))) { + ot->ot_thread = thread; + table_pool->opt_total_open++; + } + + done_ok: + db_free_open_table_pool(NULL, table_pool); + xt_unlock_mutex_ns(&db->db_ot_pool.opt_lock); + return ot; + + failed_1: + db_free_open_table_pool(NULL, table_pool); + + failed: + xt_unlock_mutex_ns(&db->db_ot_pool.opt_lock); + return NULL; +} + +xtPublic xtBool xt_db_open_pool_table_ns(XTOpenTablePtr *ret_ot, XTDatabaseHPtr db, xtTableID tab_id) +{ + XTThreadPtr self = xt_get_self(); + xtBool ok = TRUE; + + try_(a) { + *ret_ot = xt_db_open_pool_table(self, db, tab_id, NULL, FALSE); + } + catch_(a) { + ok = FALSE; + } + cont_(a); + return ok; +} + +xtPublic XTOpenTablePtr xt_db_open_pool_table(XTThreadPtr self, XTDatabaseHPtr db, xtTableID tab_id, int *result, xtBool i_am_background) +{ + XTOpenTablePtr ot; + XTOpenTablePoolPtr table_pool; + int r; + XTTableHPtr tab; + + xt_lock_mutex(self, &db->db_ot_pool.opt_lock); + pushr_(xt_unlock_mutex, &db->db_ot_pool.opt_lock); + + if (!(table_pool = db_get_open_table_pool(db, tab_id))) + xt_throw(self); + + /* Background processes do not have to wait while flushing! + * + * I think I did this so that the background process would + * not hang during flushing. Exact reason currently + * unknown. + * + * This led to the situation that the checkpointer + * could flush at the same time as a user process + * which was flushing due to a rename. + * + * This led to the situation described here: [*10*], + * which is now fixed. + */ + while (table_pool->opt_locked && !(i_am_background && table_pool->opt_flushing)) { + xt_timed_wait_cond(self, &db->db_ot_pool.opt_cond, &db->db_ot_pool.opt_lock, 2000); + if (!(table_pool = db_get_open_table_pool(db, tab_id))) + xt_throw(self); + } + + /* Moved from above, because db_get_open_table_pool() may return a different + * pool on each call! + */ + pushr_(db_free_open_table_pool, table_pool); + + if ((ot = table_pool->opt_free_list)) { + /* Remove from the free list: */ + table_pool->opt_free_list = ot->ot_otp_next_free; + + /* Remove from MRU list: */ + if (db->db_ot_pool.otp_lr_used == ot) + db->db_ot_pool.otp_lr_used = ot->ot_otp_mr_used; + if (db->db_ot_pool.otp_mr_used == ot) + db->db_ot_pool.otp_mr_used = ot->ot_otp_lr_used; + if (ot->ot_otp_lr_used) + ot->ot_otp_lr_used->ot_otp_mr_used = ot->ot_otp_mr_used; + if (ot->ot_otp_mr_used) + ot->ot_otp_mr_used->ot_otp_lr_used = ot->ot_otp_lr_used; + + if (db->db_ot_pool.otp_lr_used) + db->db_ot_pool.otp_free_time = db->db_ot_pool.otp_lr_used->ot_otp_free_time; + + ASSERT(db->db_ot_pool.otp_total_free > 0); + db->db_ot_pool.otp_total_free--; + + freer_(); // db_free_open_table_pool(table_pool) + freer_(); // xt_unlock_mutex(&db->db_ot_pool.opt_lock) + ot->ot_thread = self; + return ot; + } + + r = xt_use_table_by_id(self, &tab, db, tab_id); + if (result) { + if (r != XT_TAB_OK) { + *result = r; + freer_(); // db_free_open_table_pool(table_pool) + freer_(); // xt_unlock_mutex(&db->db_ot_pool.opt_lock) + return NULL; + } + } + else { + switch (r) { + case XT_TAB_NOT_FOUND: + /* The table no longer exists, ignore the change: */ + freer_(); // db_free_open_table_pool(table_pool) + freer_(); // xt_unlock_mutex(&db->db_ot_pool.opt_lock) + return NULL; + case XT_TAB_NO_DICTIONARY: + xt_throw_ulxterr(XT_CONTEXT, XT_ERR_NO_DICTIONARY, (u_long) tab_id); + case XT_TAB_POOL_CLOSED: + xt_throw_ulxterr(XT_CONTEXT, XT_ERR_TABLE_LOCKED, (u_long) tab_id); + default: + break; + } + } + + /* xt_use_table_by_id returns a referenced tab! */ + pushr_(xt_heap_release, tab); + if ((ot = xt_open_table(tab))) { + ot->ot_thread = self; + table_pool->opt_total_open++; + } + freer_(); // xt_release_heap(tab) + + freer_(); // db_free_open_table_pool(table_pool) + freer_(); // xt_unlock_mutex(&db->db_ot_pool.opt_lock) + return ot; +} + +xtPublic void xt_db_return_table_to_pool(XTThreadPtr XT_UNUSED(self), XTOpenTablePtr ot) +{ + xt_db_return_table_to_pool_ns(ot); +} + +xtPublic void xt_db_return_table_to_pool_ns(XTOpenTablePtr ot) +{ + XTOpenTablePoolPtr table_pool; + XTDatabaseHPtr db = ot->ot_table->tab_db; + xtBool flush_table = TRUE; + + xt_lock_mutex_ns(&db->db_ot_pool.opt_lock); + + if (!(table_pool = db_get_open_table_pool(db, ot->ot_table->tab_id))) + goto failed; + + if (table_pool->opt_locked && !table_pool->opt_flushing) { + table_pool->opt_total_open--; + /* Table will be closed below: */ + if (table_pool->opt_total_open > 0) + flush_table = FALSE; + } + else { + /* Put it on the free list: */ + db->db_ot_pool.otp_total_free++; + + ot->ot_otp_next_free = table_pool->opt_free_list; + table_pool->opt_free_list = ot; + + /* This is the time the table was freed: */ + ot->ot_otp_free_time = xt_db_approximate_time; + + /* Add to most recently used: */ + if ((ot->ot_otp_lr_used = db->db_ot_pool.otp_mr_used)) + db->db_ot_pool.otp_mr_used->ot_otp_mr_used = ot; + ot->ot_otp_mr_used = NULL; + db->db_ot_pool.otp_mr_used = ot; + if (!db->db_ot_pool.otp_lr_used) { + db->db_ot_pool.otp_lr_used = ot; + db->db_ot_pool.otp_free_time = ot->ot_otp_free_time; + } + + ot = NULL; + } + + db_free_open_table_pool(NULL, table_pool); + + if (!xt_broadcast_cond_ns(&db->db_ot_pool.opt_cond)) + goto failed; + xt_unlock_mutex_ns(&db->db_ot_pool.opt_lock); + if (ot) + xt_close_table(ot, flush_table, FALSE); + + return; + + failed: + xt_unlock_mutex_ns(&db->db_ot_pool.opt_lock); + if (ot) + xt_close_table(ot, TRUE, FALSE); + xt_log_and_clear_exception_ns(); +} + +//#define TEST_FREE_OPEN_TABLES + +#ifdef DEBUG +#undef XT_OPEN_TABLE_FREE_TIME +#define XT_OPEN_TABLE_FREE_TIME 5 +#endif + +xtPublic void xt_db_free_unused_open_tables(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTOpenTablePoolPtr table_pool; + size_t count; + XTOpenTablePtr ot; + xtBool flush_table = TRUE; + u_int table_count; + + /* A quick check of the oldest free table: */ + if (xt_db_approximate_time < db->db_ot_pool.otp_free_time + XT_OPEN_TABLE_FREE_TIME) + return; + + table_count = db->db_table_by_id ? xt_sl_get_size(db->db_table_by_id) : 0; + count = table_count * 3; + if (count < 20) + count = 20; +#ifdef TEST_FREE_OPEN_TABLES + count = 10; +#endif + if (db->db_ot_pool.otp_total_free > count) { + XTOpenTablePtr ptr, pptr; + + count = table_count * 2; + if (count < 10) + count = 10; +#ifdef TEST_FREE_OPEN_TABLES + count = 5; +#endif + xt_lock_mutex(self, &db->db_ot_pool.opt_lock); + pushr_(xt_unlock_mutex, &db->db_ot_pool.opt_lock); + + while (db->db_ot_pool.otp_total_free > count) { + ASSERT_NS(db->db_ot_pool.otp_lr_used); + if (!(ot = db->db_ot_pool.otp_lr_used)) + break; + + /* Check how long the open table has been free: */ + if (xt_db_approximate_time < ot->ot_otp_free_time + XT_OPEN_TABLE_FREE_TIME) + break; + + ot->ot_thread = self; + + /* Remove from MRU list: */ + db->db_ot_pool.otp_lr_used = ot->ot_otp_mr_used; + if (db->db_ot_pool.otp_mr_used == ot) + db->db_ot_pool.otp_mr_used = ot->ot_otp_lr_used; + if (ot->ot_otp_lr_used) + ot->ot_otp_lr_used->ot_otp_mr_used = ot->ot_otp_mr_used; + if (ot->ot_otp_mr_used) + ot->ot_otp_mr_used->ot_otp_lr_used = ot->ot_otp_lr_used; + + if (db->db_ot_pool.otp_lr_used) + db->db_ot_pool.otp_free_time = db->db_ot_pool.otp_lr_used->ot_otp_free_time; + + ASSERT(db->db_ot_pool.otp_total_free > 0); + db->db_ot_pool.otp_total_free--; + + if (!(table_pool = db_get_open_table_pool(db, ot->ot_table->tab_id))) + xt_throw(self); + + /* Find the open table in the table pool, + * and remove it from the list: + */ + pptr = NULL; + ptr = table_pool->opt_free_list; + while (ptr) { + if (ptr == ot) + break; + pptr = ptr; + ptr = ptr->ot_otp_next_free; + } + + ASSERT_NS(ptr == ot); + if (ptr == ot) { + if (pptr) + pptr->ot_otp_next_free = ot->ot_otp_next_free; + else + table_pool->opt_free_list = ot->ot_otp_next_free; + } + + ASSERT_NS(table_pool->opt_total_open > 0); + table_pool->opt_total_open--; + if (table_pool->opt_total_open > 0) + flush_table = FALSE; + else + flush_table = TRUE; + + db_free_open_table_pool(self, table_pool); + + freer_(); + + /* Close the table, but not + * while holding the lock. + */ + xt_close_table(ot, flush_table, FALSE); + + xt_lock_mutex(self, &db->db_ot_pool.opt_lock); + pushr_(xt_unlock_mutex, &db->db_ot_pool.opt_lock); + } + + freer_(); + } +} diff --git a/storage/pbxt/src/database_xt.h b/storage/pbxt/src/database_xt.h new file mode 100644 index 00000000000..469bfa4adb6 --- /dev/null +++ b/storage/pbxt/src/database_xt.h @@ -0,0 +1,247 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-15 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_database_h__ +#define __xt_database_h__ + +#include <time.h> + +#include "thread_xt.h" +#include "hashtab_xt.h" +#include "table_xt.h" +#include "sortedlist_xt.h" +#include "xaction_xt.h" +#include "heap_xt.h" +#include "xactlog_xt.h" +#include "restart_xt.h" +#include "index_xt.h" + +#ifdef DEBUG +//#define XT_USE_XACTION_DEBUG_SIZES +#endif + +#ifdef XT_USE_XACTION_DEBUG_SIZES +#define XT_DB_TABLE_POOL_SIZE 2 +#else +#define XT_DB_TABLE_POOL_SIZE 10 // The number of open tables maintained by the sweeper +#endif + +/* Turn this switch on to enable spin lock based wait-for logic: */ +#define XT_USE_SPINLOCK_WAIT_FOR + +extern xtLogOffset xt_db_log_file_threshold; +extern size_t xt_db_log_buffer_size; +extern size_t xt_db_transaction_buffer_size; +extern size_t xt_db_checkpoint_frequency; +extern off_t xt_db_data_log_threshold; +extern size_t xt_db_data_file_grow_size; +extern size_t xt_db_row_file_grow_size; +extern int xt_db_garbage_threshold; +extern int xt_db_log_file_count; +extern int xt_db_auto_increment_mode; +extern int xt_db_offline_log_function; +extern int xt_db_sweeper_priority; + +extern XTSortedListPtr xt_db_open_db_by_id; +extern XTHashTabPtr xt_db_open_databases; +extern time_t xt_db_approximate_time; + +#define XT_OPEN_TABLE_POOL_HASH_SIZE 223 + +#define XT_SW_WORK_NORMAL 0 +#define XT_SW_NO_MORE_XACT_SLOTS 1 +#define XT_SW_DIRTY_RECORD_FOUND 2 +#define XT_SW_TOO_FAR_BEHIND 3 /* The sweeper is getting too far behind, although it is working! */ + +typedef struct XTOpenTablePool { + struct XTDatabase *opt_db; + xtTableID opt_tab_id; /* The table ID. */ + u_int opt_total_open; /* Total number of open tables. */ + xtBool opt_locked; /* This table is locked open tables are freed on return to pool. */ + u_int opt_flushing; + XTOpenTablePtr opt_free_list; /* A list of free, unused open tables. */ + struct XTOpenTablePool *opt_next_hash; +} XTOpenTablePoolRec, *XTOpenTablePoolPtr; + +typedef struct XTAllTablePools { + xt_mutex_type opt_lock; /* This lock protects the open table pool. */ + xt_cond_type opt_cond; /* Used to wait for an exclusive lock on a table. */ + + u_int otp_total_free; /* This is the total number of free open tables (not in use): */ + + /* All free (unused tables) are on this list: */ + XTOpenTablePtr otp_mr_used; + XTOpenTablePtr otp_lr_used; + time_t otp_free_time; /* The free time of the LRU open table. */ + + XTOpenTablePoolPtr otp_hash[XT_OPEN_TABLE_POOL_HASH_SIZE]; +} XTAllTablePoolsRec, *XTAllTablePoolsPtr; + +typedef struct XTTablePath { + u_int tp_tab_count; /* The number of tables using this path. */ + char tp_path[XT_VAR_LENGTH]; /* The table path. */ +} XTTablePathRec, *XTTablePathPtr; + +#define XT_THREAD_BUSY 0 +#define XT_THREAD_IDLE 1 +#define XT_THREAD_INERR 2 + +typedef struct XTDatabase : public XTHeap { + char *db_name; /* The name of the database, last component of the path! */ + char *db_main_path; + xtDatabaseID db_id; + xtTableID db_curr_tab_id; /* The ID of the last table created. */ + XTHashTabPtr db_tables; + XTSortedListPtr db_table_by_id; + XTSortedListPtr db_table_paths; /* A list of table paths used by this database. */ + xtBool db_multi_path; + + /* The open table pool: */ + XTAllTablePoolsRec db_ot_pool; + + /* Transaction related stuff: */ + XTSpinLockRec db_xn_id_lock; /* Lock for next transaction ID. */ + xtXactID db_xn_curr_id; /* The ID of the last transaction started. */ + xtXactID db_xn_min_ram_id; /* The lowest ID of the transactions in memory (RAM). */ + xtXactID db_xn_to_clean_id; /* The next transaction to be cleaned (>= db_xn_min_ram_id). */ + xtXactID db_xn_min_run_id; /* The lowest ID of all running transactions (not up-to-date! >= db_xn_to_clean_id) */ + xtWord4 db_xn_end_time; /* The time of the transaction end. */ + XTXactSegRec db_xn_idx[XT_XN_NO_OF_SEGMENTS]; /* Index of transactions in RAM. */ + xtWord1 *db_xn_data; /* Start of the block allocated to contain transaction data. */ + xtWord1 *db_xn_data_end; /* End of the transaction data block. */ + u_int db_stat_sweep_waits; /* STATISTICS: count the sweeper waits. */ + XTDatabaseLogRec db_xlog; /* The transaction log for this database. */ + XTXactRestartRec db_restart; /* Database recovery stuff. */ + + XTSortedListPtr db_xn_wait_for; /* The "wait-for" list, of transactions waiting for other transactions. */ + u_int db_xn_call_start; /* Start of the post wait calls. */ + XTSpinLockRec db_xn_wait_spinlock; + //xt_mutex_type db_xn_wait_lock; /* The lock associated with the wait for list. */ + //xt_cond_type db_xn_wait_cond; /* This condition is signalled when a transaction quits. */ + //u_int db_xn_wait_on_cond; /* Number of threads waiting on the condition. */ + int db_xn_wait_count; /* Number of waiting transactions. */ + u_int db_xn_total_writer_count; /* The total number of writers. */ + int db_xn_writer_count; /* The number of writer threads. */ + int db_xn_writer_wait_count; /* The number of writer threads waiting. */ + int db_xn_long_running_count; /* The number of long running writer threads. */ + + /* Sweeper stuff: */ + struct XTThread *db_sw_thread; /* The sweeper thread (cleans up transactions). */ + xt_mutex_type db_sw_lock; /* The lock associated with the sweeper. */ + xt_cond_type db_sw_cond; /* The sweeper wakeup condition. */ + u_int db_sw_check_count; + int db_sw_idle; /* BUSY/IDLE/INERR depending on the state of the sweeper. */ + int db_sw_faster; /* non-zero if the sweeper should work faster. */ + xtBool db_sw_fast; /* TRUE if the sweeper is working faster. */ + + /* Writer stuff: */ + struct XTThread *db_wr_thread; /* The writer thread (write log data to the database). */ + int db_wr_idle; /* BUSY/IDLE/INERR depending on the state of the writer. */ + xtBool db_wr_faster; /* Set to TRUE if the writer should work faster. */ + xtBool db_wr_fast; /* TRUE if the writer is working faster. */ + u_int db_wr_thread_waiting; /* Count the number of threads waiting for the writer. */ + xtBool db_wr_freeer_waiting; /* TRUE if the freeer is wating for the writer. */ + xt_mutex_type db_wr_lock; + xt_cond_type db_wr_cond; /* Writer condition when idle (must bw woken by log flush! */ + xtLogID db_wr_log_id; /* Current write log ID. */ + xtLogOffset db_wr_log_offset; /* Current write log offset. */ + xtLogID db_wr_flush_point_log_id; /* This is the point to which the writer will write (log ID). */ + xtLogOffset db_wr_flush_point_log_offset; /* This is the point to which the writer will write (log offset). */ + + /* Data log stuff: */ + XTDataLogCacheRec db_datalogs; /* The database data log stuff. */ + XTIndexLogPoolRec db_indlogs; /* Index logs used for consistent write. */ + + /* Compactor stuff: */ + struct XTThread *db_co_thread; /* The compator thread (compacts data logs). */ + xt_mutex_type db_co_ext_lock; /* Required when extended data is moved, or removed. */ + xtBool db_co_busy; /* True of the compactor is busy compacting a data log. */ + xt_mutex_type db_co_dlog_lock; /* This is the lock required to flusht the compactors data log. */ + + /* Checkpointer stuff: */ + struct XTThread *db_cp_thread; /* The checkpoint thread (flushes the database data). */ + xt_mutex_type db_cp_lock; + xt_cond_type db_cp_cond; /* Writer condition when idle (must bw woken by log flush! */ + XTCheckPointStateRec db_cp_state; /* The checkpoint state. */ +} XTDatabaseRec, *XTDatabaseHPtr; /* Heap pointer */ + +#define XT_FOR_USER 0 +#define XT_FOR_COMPACTOR 1 +#define XT_FOR_SWEEPER 2 +#define XT_FOR_WRITER 3 +#define XT_FOR_CHECKPOINTER 4 + +void xt_create_database(XTThreadPtr th, char *path); +XTDatabaseHPtr xt_get_database(XTThreadPtr self, char *path, xtBool multi_path); +XTDatabaseHPtr xt_get_database_by_id(XTThreadPtr self, xtDatabaseID db_id); +void xt_drop_database(XTThreadPtr self, XTDatabaseHPtr db); +void xt_check_database(XTThreadPtr self); + +void xt_add_pbxt_file(size_t size, char *path, const char *file); +void xt_add_location_file(size_t size, char *path); +void xt_add_system_dir(size_t size, char *path); +void xt_add_data_dir(size_t size, char *path); + +void xt_use_database(XTThreadPtr self, XTDatabaseHPtr db, int what_for); +void xt_unuse_database(XTThreadPtr self, XTThreadPtr other_thr); +void xt_open_database(XTThreadPtr self, char *path, xtBool multi_path); + +void xt_lock_installation(XTThreadPtr self, char *installation_path); +void xt_unlock_installation(XTThreadPtr self, char *installation_path); +void xt_crash_me(void); + +void xt_init_databases(XTThreadPtr self); +void xt_stop_database_threads(XTThreadPtr self, xtBool sync); +void xt_exit_databases(XTThreadPtr self); + +void xt_dump_database(XTThreadPtr self, XTDatabaseHPtr db); + +void xt_db_init_thread(XTThreadPtr self, XTThreadPtr new_thread); +void xt_db_exit_thread(XTThreadPtr self); + +void xt_db_pool_init(XTThreadPtr self, struct XTDatabase *db); +void xt_db_pool_exit(XTThreadPtr self, struct XTDatabase *db); +XTOpenTablePoolPtr xt_db_lock_table_pool_by_name(XTThreadPtr self, XTDatabaseHPtr db, XTPathStrPtr name, xtBool no_load, xtBool flush_table, xtBool missing_ok, xtBool wait_for_open, XTTableHPtr *ret_tab); +void xt_db_wait_for_open_tables(XTThreadPtr self, XTOpenTablePoolPtr table_pool); +void xt_db_unlock_table_pool(struct XTThread *self, XTOpenTablePoolPtr table_pool); +XTOpenTablePtr xt_db_open_pool_table(XTThreadPtr self, XTDatabaseHPtr db, xtTableID tab_id, int *result, xtBool i_am_background); +XTOpenTablePtr xt_db_open_table_using_tab(XTTableHPtr tab, XTThreadPtr thread); +xtBool xt_db_open_pool_table_ns(XTOpenTablePtr *ret_ot, XTDatabaseHPtr db, xtTableID tab_id); +void xt_db_return_table_to_pool(XTThreadPtr self, XTOpenTablePtr ot); +void xt_db_return_table_to_pool_ns(XTOpenTablePtr ot); +void xt_db_free_unused_open_tables(XTThreadPtr self, XTDatabaseHPtr db); + +#define XT_LONG_RUNNING_TIME 2 + +inline void xt_xlog_check_long_writer(XTThreadPtr thread) +{ + if (thread->st_xact_writer) { + if (xt_db_approximate_time - thread->st_xact_write_time > XT_LONG_RUNNING_TIME) { + if (!thread->st_xact_long_running) { + thread->st_xact_long_running = TRUE; + thread->st_database->db_xn_long_running_count++; + } + } + } +} + +#endif diff --git a/storage/pbxt/src/datadic_xt.cc b/storage/pbxt/src/datadic_xt.cc new file mode 100644 index 00000000000..c2ac186cf6f --- /dev/null +++ b/storage/pbxt/src/datadic_xt.cc @@ -0,0 +1,2875 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-05-16 Paul McCullagh + * + * H&G2JCtL + * + * Implementation of the PBXT internal data dictionary. + */ + + +#include "xt_config.h" + +#include <ctype.h> +#include <errno.h> + +#ifdef DEBUG +#ifdef DRIZZLED +#include <drizzled/common_includes.h> +#else +#include "mysql_priv.h" +#endif +#endif + +#include "pthread_xt.h" +#include "datadic_xt.h" +#include "util_xt.h" +#include "database_xt.h" +#include "table_xt.h" +#include "heap_xt.h" +#include "strutil_xt.h" +#include "myxt_xt.h" +#include "hashtab_xt.h" + +/* + * ----------------------------------------------------------------------- + * Lexical analyser + */ + +#define XT_TK_EOF 0 +#define XT_TK_IDENTIFIER 1 +#define XT_TK_NUMBER 2 +#define XT_TK_STRING 3 +#define XT_TK_PUNCTUATION 4 + +#define XT_TK_RESERVER_WORDS 5 +#define XT_TK_PRIMARY 5 +#define XT_TK_UNIQUE 6 +#define XT_TK_FULLTEXT 7 +#define XT_TK_SPATIAL 8 +#define XT_TK_INDEX 9 +#define XT_TK_KEY 10 +#define XT_TK_CHECK 11 +#define XT_TK_FOREIGN 12 +#define XT_TK_COLUMN 13 +#define XT_TK_REFERENCES 14 +#define XT_TK_NOT 15 +#define XT_TK_NULL 16 +#define XT_TK_AUTO_INCREMENT 17 +#define XT_TK_COMMENT 18 +#define XT_TK_DEFAULT 19 +#define XT_TK_COLLATE 20 + +class XTToken { + public: + u_int tk_type; + char *tk_text; + size_t tk_length; + + void initCString(u_int type, char *start, char *end); + inline char charAt(u_int i) { + if (i >= tk_length) + return 0; + return toupper(tk_text[i]); + } + void expectKeyWord(XTThreadPtr self, c_char *keyword); + void expectIdentifier(XTThreadPtr self); + void expectNumber(XTThreadPtr self); + bool isKeyWord(c_char *keyword); + bool isReservedWord(); + bool isReservedWord(u_int word); + void identifyReservedWord(); + bool isEOF(); + bool isIdentifier(); + bool isNumber(); + size_t getString(char *string, size_t len); + void getTokenText(char *string, size_t len); + XTToken *clone(XTThreadPtr self); +}; + +void XTToken::initCString(u_int type, char *start, char *end) +{ + tk_type = type; + tk_text = start; + tk_length = (size_t) end - (size_t) start; +} + +bool XTToken::isKeyWord(c_char *keyword) +{ + char *str = tk_text; + size_t len = tk_length; + + while (len && *keyword) { + if (toupper(*keyword) != toupper(*str)) + return false; + keyword++; + str++; + len--; + } + return !len && !*keyword; +} + +bool XTToken::isReservedWord() +{ + return tk_type >= XT_TK_RESERVER_WORDS; +} + +bool XTToken::isReservedWord(u_int word) +{ + return tk_type == word; +} + +void XTToken::identifyReservedWord() +{ + if (tk_type == XT_TK_IDENTIFIER) { + switch (charAt(0)) { + case 'A': + if (isKeyWord("AUTO_INCREMENT")) + tk_type = XT_TK_AUTO_INCREMENT; + break; + case 'C': + switch (charAt(2)) { + case 'E': + if (isKeyWord("CHECK")) + tk_type = XT_TK_CHECK; + break; + case 'L': + if (isKeyWord("COLUMN")) + tk_type = XT_TK_COLUMN; + else if (isKeyWord("COLLATE")) + tk_type = XT_TK_COLLATE; + break; + case 'M': + if (isKeyWord("COMMENT")) + tk_type = XT_TK_COMMENT; + break; + } + break; + case 'D': + if (isKeyWord("DEFAULT")) + tk_type = XT_TK_DEFAULT; + break; + case 'F': + switch (charAt(1)) { + case 'O': + if (isKeyWord("FOREIGN")) + tk_type = XT_TK_FOREIGN; + break; + case 'U': + if (isKeyWord("FULLTEXT")) + tk_type = XT_TK_FULLTEXT; + break; + } + break; + case 'I': + if (isKeyWord("INDEX")) + tk_type = XT_TK_INDEX; + break; + case 'K': + if (isKeyWord("KEY")) + tk_type = XT_TK_KEY; + break; + case 'N': + switch (charAt(1)) { + case 'O': + if (isKeyWord("NOT")) + tk_type = XT_TK_NOT; + break; + case 'U': + if (isKeyWord("NULL")) + tk_type = XT_TK_NULL; + break; + } + break; + case 'P': + if (isKeyWord("PRIMARY")) + tk_type = XT_TK_PRIMARY; + break; + case 'R': + if (isKeyWord("REFERENCES")) + tk_type = XT_TK_REFERENCES; + break; + case 'S': + if (isKeyWord("SPATIAL")) + tk_type = XT_TK_SPATIAL; + break; + case 'U': + if (isKeyWord("UNIQUE")) + tk_type = XT_TK_UNIQUE; + break; + } + } +} + +bool XTToken::isEOF() +{ + return tk_type == XT_TK_EOF; +} + +bool XTToken::isIdentifier() +{ + return tk_type == XT_TK_IDENTIFIER; +} + +bool XTToken::isNumber() +{ + return tk_type == XT_TK_NUMBER; +} + +/* Return actual, or required string length. */ +size_t XTToken::getString(char *dtext, size_t dsize) +{ + char *buffer = dtext; + int slen; + size_t dlen; + char *stext; + char quote; + + if ((slen = (int) tk_length) == 0) { + *dtext = 0; + return 0; + } + switch (*tk_text) { + case '\'': + case '"': + case '`': + quote = *tk_text; + stext = tk_text+1; + slen -= 2; + dlen = 0; + while (slen > 0) { + if (*stext == '\\') { + stext++; + slen--; + if (slen > 0) { + switch (*stext) { + case '\0': + *dtext = 0; + break; + case '\'': + *dtext = '\''; + break; + case '"': + *dtext = '"'; + break; + case 'b': + *dtext = '\b'; + break; + case 'n': + *dtext = '\n'; + break; + case 'r': + *dtext = '\r'; + break; + case 't': + *dtext = '\t'; + break; + case 'z': + *dtext = (char) 26; + break; + case '\\': + *dtext = '\\'; + break; + default: + *dtext = *stext; + break; + } + } + } + else if (*stext == quote) { + if (dlen < dsize) + *dtext = quote; + stext++; + slen--; + } + else { + if (dlen < dsize) + *dtext = *stext; + } + dtext++; + dlen++; + stext++; + slen--; + } + if (dlen < dsize) + buffer[dlen] = 0; + else if (dsize > 0) + buffer[dsize-1] = 0; + break; + default: + if (dsize > 0) { + dlen = dsize-1; + if ((int) dlen > slen) + dlen = slen; + memcpy(dtext, tk_text, dlen); + dtext[dlen] = 0; + } + dlen = tk_length; + break; + } + return dlen; +} + +/* Return the token as a string with ... in it if it is too long + */ +void XTToken::getTokenText(char *string, size_t size) +{ + if (tk_length == 0 || !tk_text) { + xt_strcpy(size, string, "EOF"); + return; + } + + size--; + if (tk_length <= size) { + memcpy(string, tk_text, tk_length); + string[tk_length] = 0; + return; + } + + size = (size - 3) / 2; + memcpy(string, tk_text, size); + memcpy(string+size, "...", 3); + memcpy(string+size+3, tk_text + tk_length - size, size); + string[size+3+size] = 0; +} + +XTToken *XTToken::clone(XTThreadPtr self) +{ + XTToken *tk; + + if (!(tk = new XTToken())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + tk->initCString(tk_type, tk_text, tk_text + tk_length); + return tk; +} + +void XTToken::expectKeyWord(XTThreadPtr self, c_char *keyword) +{ + char buffer[100]; + + if (isKeyWord(keyword)) + return; + getTokenText(buffer, 100); + xt_throw_i2xterr(XT_CONTEXT, XT_ERR_A_EXPECTED_NOT_B, keyword, buffer); +} + +void XTToken::expectIdentifier(XTThreadPtr self) +{ + char buffer[100]; + + if (isIdentifier()) + return; + getTokenText(buffer, 100); + xt_throw_i2xterr(XT_CONTEXT, XT_ERR_A_EXPECTED_NOT_B, "Identifier", buffer); +} + +void XTToken::expectNumber(XTThreadPtr self) +{ + char buffer[100]; + + if (isNumber()) + return; + getTokenText(buffer, 100); + xt_throw_i2xterr(XT_CONTEXT, XT_ERR_A_EXPECTED_NOT_B, "Value", buffer); +} + +struct charset_info_st; + +class XTTokenizer { + struct charset_info_st *tkn_charset; + char *tkn_cstring; + char *tkn_curr_pos; + XTToken *tkn_current; + bool tkn_in_comment; + + public: + + XTTokenizer(bool convert, char *cstring) { + tkn_charset = myxt_getcharset(convert); + tkn_cstring = cstring; + tkn_curr_pos = cstring; + tkn_current = NULL; + tkn_in_comment = FALSE; + } + + virtual ~XTTokenizer(void) { + if (tkn_current) + delete tkn_current; + } + + inline bool isSingleChar(int ch) + { + return ch != '$' && ch != '_' && myxt_ispunct(tkn_charset, ch); + } + + inline bool isIdentifierChar(int ch) + { + return ch && !isSingleChar(ch) && !myxt_isspace(tkn_charset, ch); + } + + inline bool isNumberChar(int ch, int next_ch) + { + return myxt_isdigit(tkn_charset, ch) || ((ch == '-' || ch == '+') && myxt_isdigit(tkn_charset, next_ch)); + } + + XTToken *newToken(XTThreadPtr self, u_int type, char *start, char *end); + XTToken *nextToken(XTThreadPtr self); + XTToken *nextToken(XTThreadPtr self, c_char *keyword, XTToken *tk); +}; + +void ri_free_token(XTThreadPtr self __attribute__((unused)), XTToken *tk) +{ + delete tk; +} + +XTToken *XTTokenizer::newToken(XTThreadPtr self, u_int type, char *start, char *end) +{ + if (!tkn_current) { + if (!(tkn_current = new XTToken())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + } + tkn_current->initCString(type, start, end); + if (type == XT_TK_IDENTIFIER) + tkn_current->identifyReservedWord(); + return tkn_current; +} + +XTToken *XTTokenizer::nextToken(XTThreadPtr self) +{ + char *token_start; + u_int token_type = XT_TK_PUNCTUATION; + char quote; + bool must_be_num; + + restart: + + /* Ignore space: */ + while (*tkn_curr_pos && myxt_isspace(tkn_charset, *tkn_curr_pos)) tkn_curr_pos++; + + token_start = tkn_curr_pos; + switch (*tkn_curr_pos) { + case '\0': + return newToken(self, XT_TK_EOF, NULL, NULL); + // Comment: # ... EOL + case '#': + tkn_curr_pos++; + while (*tkn_curr_pos && *tkn_curr_pos != '\n' && *tkn_curr_pos != '\r') tkn_curr_pos++; + goto restart; + case '-': + if (tkn_curr_pos[1] == '-') { + // Comment: -- ... EOL + while (*tkn_curr_pos && *tkn_curr_pos != '\n' && *tkn_curr_pos != '\r') tkn_curr_pos++; + goto restart; + } + if (myxt_isdigit(tkn_charset, tkn_curr_pos[1])) + goto is_number; + tkn_curr_pos++; + break; + case '+': + if (myxt_isdigit(tkn_charset, tkn_curr_pos[1])) + goto is_number; + tkn_curr_pos++; + break; + case '/': + tkn_curr_pos++; + if (*tkn_curr_pos == '*') { + // Comment: /* ... */ + // Look for: /*!99999 ... */ version conditional statements + tkn_curr_pos++; + if (*tkn_curr_pos == '!') { + tkn_curr_pos++; + if (isdigit(*tkn_curr_pos)) { + while (isdigit(*tkn_curr_pos)) + tkn_curr_pos++; + tkn_in_comment = true; + goto restart; + } + } + + while (*tkn_curr_pos && !(*tkn_curr_pos == '*' && *(tkn_curr_pos+1) == '/')) tkn_curr_pos++; + if (*tkn_curr_pos == '*' && *(tkn_curr_pos+1) == '/') + tkn_curr_pos += 2; + goto restart; + } + break; + case '\'': + token_type = XT_TK_STRING; + goto is_string; + case '"': + case '`': + token_type = XT_TK_IDENTIFIER; + is_string: + quote = *tkn_curr_pos; + tkn_curr_pos++; + while (*tkn_curr_pos) { + if (*tkn_curr_pos == quote) { + // Doubling the quote means stay in string... + if (*(tkn_curr_pos + 1) != quote) + break; + tkn_curr_pos++; + } + tkn_curr_pos++; + } + + if (*tkn_curr_pos == quote) + tkn_curr_pos++; + break; + case '$': + goto is_identifier; + case '*': + if (tkn_in_comment) { + if (tkn_curr_pos[1] == '/') { + tkn_in_comment = false; + tkn_curr_pos += 2; + goto restart; + } + } + /* No break required! */ + default: + if (isNumberChar(tkn_curr_pos[0], tkn_curr_pos[1])) + goto is_number; + + if (isSingleChar(*tkn_curr_pos)) { + token_type = XT_TK_PUNCTUATION; + // The rest are singles... + tkn_curr_pos++; + break; + } + + is_identifier: + // Identifier (any string of characters that is not punctuation or a space: + token_type = XT_TK_IDENTIFIER; + while (isIdentifierChar(*tkn_curr_pos)) + tkn_curr_pos++; + break; + + is_number: + must_be_num = false; + token_type = XT_TK_NUMBER; + + if (*tkn_curr_pos == '-' || *tkn_curr_pos == '+') { + must_be_num = true; + tkn_curr_pos++; + } + + // Number: 9999 [ . 9999 ] [ e/E [+/-] 9999 ] + // However, 9999e or 9999E is an identifier! + while (*tkn_curr_pos && myxt_isdigit(tkn_charset, *tkn_curr_pos)) tkn_curr_pos++; + + if (*tkn_curr_pos == '.') { + must_be_num = true; + tkn_curr_pos++; + while (*tkn_curr_pos && myxt_isdigit(tkn_charset, *tkn_curr_pos)) tkn_curr_pos++; + } + + if (*tkn_curr_pos == 'e' || *tkn_curr_pos == 'E') { + tkn_curr_pos++; + + if (isNumberChar(tkn_curr_pos[0], tkn_curr_pos[1])) { + must_be_num = true; + + if (*tkn_curr_pos == '-' || *tkn_curr_pos == '+') + tkn_curr_pos++; + while (*tkn_curr_pos && myxt_isdigit(tkn_charset, *tkn_curr_pos)) + tkn_curr_pos++; + } + else if (!must_be_num) + token_type = XT_TK_IDENTIFIER; + } + + if (must_be_num || !isIdentifierChar(*tkn_curr_pos)) + break; + + /* Crazy, but true. An identifier can start by looking like a number! */ + goto is_identifier; + } + + return newToken(self, token_type, token_start, tkn_curr_pos); +} + +XTToken *XTTokenizer::nextToken(XTThreadPtr self, c_char *keyword, XTToken *tk) +{ + tk->expectKeyWord(self, keyword); + return nextToken(self); +} + +/* + * ----------------------------------------------------------------------- + * Parser + */ + +/* + We must parse the following syntax. Note that the constraints + may be embedded in a CREATE TABLE/ALTER TABLE statement. + + [CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...) + REFERENCES tbl_name (index_col_name, ...) + [ON DELETE {RESTRICT | CASCADE | SET NULL | SET DEFAULT | NO ACTION}] + [ON UPDATE {RESTRICT | CASCADE | SET NULL | SET DEFAULT | NO ACTION}] +*/ + +class XTParseTable : public XTObject { + public: + void raiseError(XTThreadPtr self, XTToken *tk, int err); + + private: + XTTokenizer *pt_tokenizer; + XTToken *pt_current; + XTStringBufferRec pt_sbuffer; + + void syntaxError(XTThreadPtr self, XTToken *tk); + + void parseIdentifier(XTThreadPtr self, char *name); + int parseKeyAction(XTThreadPtr self); + void parseCreateTable(XTThreadPtr self); + void parseAddTableItem(XTThreadPtr self); + void parseQualifiedName(XTThreadPtr self, char *name); + void parseTableName(XTThreadPtr self, bool alterTable); + void parseExpression(XTThreadPtr self, bool allow_reserved); + void parseBrackets(XTThreadPtr self); + void parseMoveColumn(XTThreadPtr self); + + /* If old_col_name is NULL, then this column is to be added, + * if old_col_name is empty (strlen() = 0) then the column + * exists, and should be modified, otherwize the column + * given is to be modified. + */ + void parseColumnDefinition(XTThreadPtr self, char *old_col_name); + void parseDataType(XTThreadPtr self); + void parseReferenceDefinition(XTThreadPtr self, u_int req_cols); + void optionalIndexName(XTThreadPtr self); + void optionalIndexType(XTThreadPtr self); + u_int columnList(XTThreadPtr self, bool index_cols); + void parseAlterTable(XTThreadPtr self); + void parseCreateIndex(XTThreadPtr self); + void parseDropIndex(XTThreadPtr self); + + public: + XTParseTable() { + pt_tokenizer = NULL; + pt_current = NULL; + memset(&pt_sbuffer, 0, sizeof(XTStringBufferRec)); + } + + virtual void finalize(XTThreadPtr self __attribute__((unused))) { + if (pt_tokenizer) + delete pt_tokenizer; + xt_sb_set_size(NULL, &pt_sbuffer, 0); + } + + // Hooks to receive output from the parser: + virtual void setTableName(XTThreadPtr self __attribute__((unused)), char *name __attribute__((unused)), bool alterTable __attribute__((unused))) { + } + virtual void addColumn(XTThreadPtr self __attribute__((unused)), char *col_name __attribute__((unused)), char *old_col_name __attribute__((unused))) { + } + virtual void setDataType(XTThreadPtr self, char *cstring) { + if (cstring) + xt_free(self, cstring); + } + virtual void setNull(XTThreadPtr self __attribute__((unused)), bool nullOK __attribute__((unused))) { + } + virtual void setAutoInc(XTThreadPtr self __attribute__((unused)), bool autoInc __attribute__((unused))) { + } + + /* Add a contraint. If lastColumn is TRUE then add the contraint + * to the last column. If not, expect addListedColumn() to be called. + */ + virtual void addConstraint(XTThreadPtr self __attribute__((unused)), char *name __attribute__((unused)), u_int type __attribute__((unused)), bool lastColumn __attribute__((unused))) { + } + + /* Move the last column created. If symbol is NULL then move the column to the + * first position, else move it to the position just after the given column. + */ + virtual void moveColumn(XTThreadPtr self __attribute__((unused)), char *col_name __attribute__((unused))) { + } + + virtual void dropColumn(XTThreadPtr self __attribute__((unused)), char *col_name __attribute__((unused))) { + } + + virtual void dropConstraint(XTThreadPtr self __attribute__((unused)), char *name __attribute__((unused)), u_int type __attribute__((unused))) { + } + + virtual void setIndexName(XTThreadPtr self __attribute__((unused)), char *name __attribute__((unused))) { + } + virtual void addListedColumn(XTThreadPtr self __attribute__((unused)), char *index_col_name __attribute__((unused))) { + } + virtual void setReferencedTable(XTThreadPtr self __attribute__((unused)), char *ref_table __attribute__((unused))) { + } + virtual void addReferencedColumn(XTThreadPtr self __attribute__((unused)), char *index_col_name __attribute__((unused))) { + } + virtual void setActions(XTThreadPtr self __attribute__((unused)), int on_delete __attribute__((unused)), int on_update __attribute__((unused))) { + } + + virtual void parseTable(XTThreadPtr self, bool convert, char *sql); +}; + +void XTParseTable::raiseError(XTThreadPtr self, XTToken *tk, int err) +{ + char buffer[100]; + + tk->getTokenText(buffer, 100); + xt_throw_ixterr(XT_CONTEXT, err, buffer); +} + +void XTParseTable::syntaxError(XTThreadPtr self, XTToken *tk) +{ + raiseError(self, tk, XT_ERR_SYNTAX); +} + +void XTParseTable::parseIdentifier(XTThreadPtr self, char *name) +{ + pt_current->expectIdentifier(self); + if (name) { + if (pt_current->getString(name, XT_IDENTIFIER_NAME_SIZE) >= XT_IDENTIFIER_NAME_SIZE) + raiseError(self, pt_current, XT_ERR_ID_TOO_LONG); + } + pt_current = pt_tokenizer->nextToken(self); +} + +int XTParseTable::parseKeyAction(XTThreadPtr self) +{ + XTToken *tk; + + tk = pt_tokenizer->nextToken(self); + + if (tk->isKeyWord("RESTRICT")) + return XT_KEY_ACTION_RESTRICT; + + if (tk->isKeyWord("CASCADE")) + return XT_KEY_ACTION_CASCADE; + + if (tk->isKeyWord("SET")) { + tk = pt_tokenizer->nextToken(self); + if (tk->isKeyWord("DEFAULT")) + return XT_KEY_ACTION_SET_DEFAULT; + tk->expectKeyWord(self, "NULL"); + return XT_KEY_ACTION_SET_NULL; + } + + if (tk->isKeyWord("NO")) { + tk = pt_tokenizer->nextToken(self); + tk->expectKeyWord(self, "ACTION"); + return XT_KEY_ACTION_NO_ACTION; + } + + syntaxError(self, tk); + return 0; +} + +void XTParseTable::parseTable(XTThreadPtr self, bool convert, char *sql) +{ + if (pt_tokenizer) + delete pt_tokenizer; + pt_tokenizer = new XTTokenizer(convert, sql); + if (!pt_tokenizer) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + pt_current = pt_tokenizer->nextToken(self); + + if (pt_current->isKeyWord("CREATE")) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isKeyWord("TEMPORARY") || pt_current->isKeyWord("TABLE")) + parseCreateTable(self); + else + parseCreateIndex(self); + } + else if (pt_current->isKeyWord("ALTER")) + parseAlterTable(self); + else if (pt_current->isKeyWord("DROP")) + parseDropIndex(self); + else if (pt_current->isKeyWord("TRUNCATE")) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isKeyWord("TABLE")) + pt_current = pt_tokenizer->nextToken(self); + parseTableName(self, true); + } + else if (pt_current->isKeyWord("OPTIMIZE") || pt_current->isKeyWord("REPAIR")) { + /* OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... + * + * GOTCHA: This cannot work if more than one table is specified, + * because then I cannot find the source table?! + */ + pt_current = pt_tokenizer->nextToken(self); + while (!pt_current->isEOF() && !pt_current->isKeyWord("TABLE")) + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self); + parseTableName(self, true); + } + else + syntaxError(self, pt_current); +} + +void XTParseTable::parseCreateTable(XTThreadPtr self) +{ + if (pt_current->isKeyWord("TEMPORARY")) + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "TABLE", pt_current); + if (pt_current->isKeyWord("IF")) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "NOT", pt_current); + pt_current = pt_tokenizer->nextToken(self, "EXISTS", pt_current); + } + + /* Table name is optional (when loading from dictionary)! */ + if (!pt_current->isKeyWord("(")) + parseTableName(self, false); + else + setTableName(self, NULL, false); + + /* We do not support CREATE ... SELECT! */ + if (pt_current->isKeyWord("(")) { + pt_current = pt_tokenizer->nextToken(self); + // Avoid this: + // create table t3 (select group_concat(a) as a from t1 where a = 'a') union + // (select group_concat(b) as a from t1 where a = 'b'); + if (pt_current->isKeyWord("SELECT")) + return; + + /* Allow empty table definition for temporary table. */ + while (!pt_current->isEOF() && !pt_current->isKeyWord(")")) { + parseAddTableItem(self); + if (!pt_current->isKeyWord(",")) + break; + pt_current = pt_tokenizer->nextToken(self); + } + pt_current = pt_tokenizer->nextToken(self, ")", pt_current); + } +} + +void XTParseTable::parseAddTableItem(XTThreadPtr self) +{ + char name[XT_IDENTIFIER_NAME_SIZE]; + + *name = 0; + if (pt_current->isKeyWord("CONSTRAINT")) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isIdentifier()) + parseQualifiedName(self, name); + } + + if (pt_current->isReservedWord(XT_TK_PRIMARY)) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "KEY", pt_current); + + addConstraint(self, name, XT_DD_KEY_PRIMARY, false); + optionalIndexType(self); + + /* GATCHA: Wierd?! This syntax is used in a test: + * alter table t1 add primary key aaa(tt); + */ + if (!pt_current->isKeyWord("(")) + pt_current = pt_tokenizer->nextToken(self); + columnList(self, true); + } + else if (pt_current->isReservedWord(XT_TK_UNIQUE) || + pt_current->isReservedWord(XT_TK_FULLTEXT) || + pt_current->isReservedWord(XT_TK_SPATIAL) || + pt_current->isReservedWord(XT_TK_INDEX) || + pt_current->isReservedWord(XT_TK_KEY)) { + bool is_unique = false; + + if (pt_current->isReservedWord(XT_TK_FULLTEXT) || pt_current->isReservedWord(XT_TK_SPATIAL)) + pt_current = pt_tokenizer->nextToken(self); + else if (pt_current->isReservedWord(XT_TK_UNIQUE)) { + pt_current = pt_tokenizer->nextToken(self); + is_unique = true; + } + if (pt_current->isReservedWord(XT_TK_INDEX) || pt_current->isReservedWord(XT_TK_KEY)) + pt_current = pt_tokenizer->nextToken(self); + + addConstraint(self, name, is_unique ? XT_DD_INDEX_UNIQUE : XT_DD_INDEX, false); + optionalIndexName(self); + optionalIndexType(self); + columnList(self, true); + } + else if (pt_current->isReservedWord(XT_TK_CHECK)) { + pt_current = pt_tokenizer->nextToken(self); + parseExpression(self, false); + } + else if (pt_current->isReservedWord(XT_TK_FOREIGN)) { + u_int req_cols; + + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "KEY", pt_current); + + addConstraint(self, name, XT_DD_KEY_FOREIGN, false); + optionalIndexName(self); + req_cols = columnList(self, false); + /* GOTCHA: According the MySQL manual this is optional, but without domains, + * it is required! + */ + parseReferenceDefinition(self, req_cols); + } + else if (pt_current->isKeyWord("(")) { + pt_current = pt_tokenizer->nextToken(self); + for (;;) { + parseColumnDefinition(self, NULL); + if (!pt_current->isKeyWord(",")) + break; + pt_current = pt_tokenizer->nextToken(self); + } + pt_current = pt_tokenizer->nextToken(self, ")", pt_current); + } + else { + if (pt_current->isReservedWord(XT_TK_COLUMN)) + pt_current = pt_tokenizer->nextToken(self); + parseColumnDefinition(self, NULL); + parseMoveColumn(self); + } + /* GOTCHA: Support: create table t1 (a int not null, key `a` (a) key_block_size=1024) + * and any other undocumented syntax?! + */ + parseExpression(self, true); +} + +void XTParseTable::parseExpression(XTThreadPtr self, bool allow_reserved) +{ + while (!pt_current->isEOF() && !pt_current->isKeyWord(",") && + !pt_current->isKeyWord(")") && (allow_reserved || !pt_current->isReservedWord())) { + if (pt_current->isKeyWord("(")) + parseBrackets(self); + else + pt_current = pt_tokenizer->nextToken(self); + } +} + +void XTParseTable::parseBrackets(XTThreadPtr self) +{ + u_int cnt = 1; + pt_current = pt_tokenizer->nextToken(self, "(", pt_current); + while (cnt) { + if (pt_current->isEOF()) + break; + if (pt_current->isKeyWord("(")) + cnt++; + if (pt_current->isKeyWord(")")) + cnt--; + pt_current = pt_tokenizer->nextToken(self); + } +} + +void XTParseTable::parseMoveColumn(XTThreadPtr self) +{ + if (pt_current->isKeyWord("FIRST")) { + pt_current = pt_tokenizer->nextToken(self); + /* If name is NULL it means move to the front. */ + moveColumn(self, NULL); + } + else if (pt_current->isKeyWord("AFTER")) { + char name[XT_IDENTIFIER_NAME_SIZE]; + + pt_current = pt_tokenizer->nextToken(self); + parseQualifiedName(self, name); + moveColumn(self, name); + } +} + +void XTParseTable::parseQualifiedName(XTThreadPtr self, char *name) +{ + /* Should be an identifier by I have this example: + * CREATE TABLE t1 ( comment CHAR(32) ASCII NOT NULL, koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL default '' ) CHARSET=latin5; + * + * COMMENT is elsewhere used as reserved word?! + */ + if (pt_current->getString(name, XT_IDENTIFIER_NAME_SIZE) >= XT_IDENTIFIER_NAME_SIZE) + raiseError(self, pt_current, XT_ERR_ID_TOO_LONG); + pt_current = pt_tokenizer->nextToken(self); + while (pt_current->isKeyWord(".")) { + pt_current = pt_tokenizer->nextToken(self); + /* Accept anything after the DOT! */ + if (pt_current->getString(name, XT_IDENTIFIER_NAME_SIZE) >= XT_IDENTIFIER_NAME_SIZE) + raiseError(self, pt_current, XT_ERR_ID_TOO_LONG); + pt_current = pt_tokenizer->nextToken(self); + } +} + +void XTParseTable::parseTableName(XTThreadPtr self, bool alterTable) +{ + char name[XT_IDENTIFIER_NAME_SIZE]; + + parseQualifiedName(self, name); + setTableName(self, name, alterTable); +} + +void XTParseTable::parseColumnDefinition(XTThreadPtr self, char *old_col_name) +{ + char col_name[XT_IDENTIFIER_NAME_SIZE]; + + // column_definition + parseQualifiedName(self, col_name); + addColumn(self, col_name, old_col_name); + parseDataType(self); + + for (;;) { + if (pt_current->isReservedWord(XT_TK_NOT)) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "NULL", pt_current); + setNull(self, false); + } + else if (pt_current->isReservedWord(XT_TK_NULL)) { + pt_current = pt_tokenizer->nextToken(self); + setNull(self, true); + } + else if (pt_current->isReservedWord(XT_TK_DEFAULT)) { + pt_current = pt_tokenizer->nextToken(self); + /* Possible here [ + | - ] <value> or [ <charset> ] <string> */ + parseExpression(self, false); + } + else if (pt_current->isReservedWord(XT_TK_AUTO_INCREMENT)) { + pt_current = pt_tokenizer->nextToken(self); + setAutoInc(self, true); + } + else if (pt_current->isReservedWord(XT_TK_UNIQUE)) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isReservedWord(XT_TK_KEY)) + pt_current = pt_tokenizer->nextToken(self); + addConstraint(self, NULL, XT_DD_INDEX_UNIQUE, true); + } + else if (pt_current->isReservedWord(XT_TK_KEY)) { + pt_current = pt_tokenizer->nextToken(self); + addConstraint(self, NULL, XT_DD_INDEX, true); + } + else if (pt_current->isReservedWord(XT_TK_PRIMARY)) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "KEY", pt_current); + addConstraint(self, NULL, XT_DD_KEY_PRIMARY, true); + } + else if (pt_current->isReservedWord(XT_TK_COMMENT)) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self); + } + else if (pt_current->isReservedWord(XT_TK_REFERENCES)) { + addConstraint(self, NULL, XT_DD_KEY_FOREIGN, true); + parseReferenceDefinition(self, 1); + } + else if (pt_current->isReservedWord(XT_TK_CHECK)) { + pt_current = pt_tokenizer->nextToken(self); + parseExpression(self, false); + } + /* GOTCHA: Not in the documentation: + * CREATE TABLE t1 (c varchar(255) NOT NULL COLLATE utf8_general_ci, INDEX (c)) + */ + else if (pt_current->isReservedWord(XT_TK_COLLATE)) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self); + } + else + break; + } +} + +void XTParseTable::parseDataType(XTThreadPtr self) +{ + /* Not actually implemented because MySQL allows undocumented + * syntax like this: + * create table t1 (c national character varying(10)) + */ + parseExpression(self, false); + setDataType(self, NULL); +} + +void XTParseTable::optionalIndexName(XTThreadPtr self) +{ + // [index_name] + if (!pt_current->isKeyWord("USING") && !pt_current->isKeyWord("(")) { + char name[XT_IDENTIFIER_NAME_SIZE]; + + parseIdentifier(self, name); + setIndexName(self, name); + } +} + +void XTParseTable::optionalIndexType(XTThreadPtr self) +{ + // USING {BTREE | HASH} + if (pt_current->isKeyWord("USING")) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self); + } +} + +u_int XTParseTable::columnList(XTThreadPtr self, bool index_cols) +{ + char name[XT_IDENTIFIER_NAME_SIZE]; + u_int cols = 0; + + pt_current->expectKeyWord(self, "("); + do { + pt_current = pt_tokenizer->nextToken(self); + parseQualifiedName(self, name); + addListedColumn(self, name); + cols++; + if (index_cols) { + if (pt_current->isKeyWord("(")) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, ")", pt_current); + } + if (pt_current->isKeyWord("ASC")) + pt_current = pt_tokenizer->nextToken(self); + else if (pt_current->isKeyWord("DESC")) + pt_current = pt_tokenizer->nextToken(self); + } + } while (pt_current->isKeyWord(",")); + pt_current = pt_tokenizer->nextToken(self, ")", pt_current); + return cols; +} + +void XTParseTable::parseReferenceDefinition(XTThreadPtr self, u_int req_cols) +{ + int on_delete = XT_KEY_ACTION_DEFAULT; + int on_update = XT_KEY_ACTION_DEFAULT; + char name[XT_IDENTIFIER_NAME_SIZE]; + u_int cols = 0; + + // REFERENCES tbl_name + pt_current = pt_tokenizer->nextToken(self, "REFERENCES", pt_current); + parseQualifiedName(self, name); + setReferencedTable(self, name); + + // [ (index_col_name,...) ] + if (pt_current->isKeyWord("(")) { + pt_current->expectKeyWord(self, "("); + do { + pt_current = pt_tokenizer->nextToken(self); + parseQualifiedName(self, name); + addReferencedColumn(self, name); + cols++; + if (cols > req_cols) + raiseError(self, pt_current, XT_ERR_INCORRECT_NO_OF_COLS); + } while (pt_current->isKeyWord(",")); + if (cols != req_cols) + raiseError(self, pt_current, XT_ERR_INCORRECT_NO_OF_COLS); + pt_current = pt_tokenizer->nextToken(self, ")", pt_current); + } + else + addReferencedColumn(self, NULL); + + // [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] + if (pt_current->isKeyWord("MATCH")) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self); + } + + // [ON DELETE {RESTRICT | CASCADE | SET NULL | SET DEFAULT | NO ACTION}] + // [ON UPDATE {RESTRICT | CASCADE | SET NULL | SET DEFAULT | NO ACTION}] + while (pt_current->isKeyWord("ON")) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isKeyWord("DELETE")) + on_delete = parseKeyAction(self); + else if (pt_current->isKeyWord("UPDATE")) + on_update = parseKeyAction(self); + else + syntaxError(self, pt_current); + pt_current = pt_tokenizer->nextToken(self); + } + + setActions(self, on_delete, on_update); +} + +void XTParseTable::parseAlterTable(XTThreadPtr self) +{ + char name[XT_IDENTIFIER_NAME_SIZE]; + + pt_current = pt_tokenizer->nextToken(self, "ALTER", pt_current); + if (pt_current->isKeyWord("IGNORE")) + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "TABLE", pt_current); + parseTableName(self, true); + for (;;) { + if (pt_current->isKeyWord("ADD")) { + pt_current = pt_tokenizer->nextToken(self); + parseAddTableItem(self); + } + else if (pt_current->isKeyWord("ALTER")) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isReservedWord(XT_TK_COLUMN)) + pt_current = pt_tokenizer->nextToken(self); + pt_current->expectIdentifier(self); + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isKeyWord("SET")) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "DEFAULT", pt_current); + pt_current = pt_tokenizer->nextToken(self); + } + else if (pt_current->isKeyWord("DROP")) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "DEFAULT", pt_current); + } + } + else if (pt_current->isKeyWord("CHANGE")) { + char old_col_name[XT_IDENTIFIER_NAME_SIZE]; + + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isReservedWord(XT_TK_COLUMN)) + pt_current = pt_tokenizer->nextToken(self); + + parseQualifiedName(self, old_col_name); + parseColumnDefinition(self, old_col_name); + parseMoveColumn(self); + } + else if (pt_current->isKeyWord("MODIFY")) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isReservedWord(XT_TK_COLUMN)) + pt_current = pt_tokenizer->nextToken(self); + parseColumnDefinition(self, NULL); + parseMoveColumn(self); + } + else if (pt_current->isKeyWord("DROP")) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isReservedWord(XT_TK_PRIMARY)) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "KEY", pt_current); + dropConstraint(self, NULL, XT_DD_KEY_PRIMARY); + } + else if (pt_current->isReservedWord(XT_TK_INDEX) || pt_current->isReservedWord(XT_TK_KEY)) { + pt_current = pt_tokenizer->nextToken(self); + parseIdentifier(self, name); + dropConstraint(self, name, XT_DD_INDEX); + } + else if (pt_current->isReservedWord(XT_TK_FOREIGN)) { + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "KEY", pt_current); + parseIdentifier(self, name); + dropConstraint(self, name, XT_DD_KEY_FOREIGN); + } + else { + if (pt_current->isReservedWord(XT_TK_COLUMN)) + pt_current = pt_tokenizer->nextToken(self); + parseQualifiedName(self, name); + dropColumn(self, name); + } + } + else if (pt_current->isKeyWord("RENAME")) { + pt_current = pt_tokenizer->nextToken(self); + if (pt_current->isKeyWord("TO")) + pt_current = pt_tokenizer->nextToken(self); + parseQualifiedName(self, name); + } + else + /* Just ignore the syntax until the next , */ + parseExpression(self, true); + if (!pt_current->isKeyWord(",")) + break; + pt_current = pt_tokenizer->nextToken(self); + } +} + +void XTParseTable::parseCreateIndex(XTThreadPtr self) +{ + char name[XT_IDENTIFIER_NAME_SIZE]; + bool is_unique = false; + + if (pt_current->isReservedWord(XT_TK_UNIQUE)) { + pt_current = pt_tokenizer->nextToken(self); + is_unique = true; + } + else if (pt_current->isReservedWord(XT_TK_FULLTEXT)) + pt_current = pt_tokenizer->nextToken(self); + else if (pt_current->isKeyWord("SPACIAL")) + pt_current = pt_tokenizer->nextToken(self); + pt_current = pt_tokenizer->nextToken(self, "INDEX", pt_current); + parseQualifiedName(self, name); + optionalIndexType(self); + pt_current = pt_tokenizer->nextToken(self, "ON", pt_current); + parseTableName(self, true); + addConstraint(self, NULL, is_unique ? XT_DD_INDEX_UNIQUE : XT_DD_INDEX, false); + setIndexName(self, name); + columnList(self, true); +} + +void XTParseTable::parseDropIndex(XTThreadPtr self) +{ + char name[XT_IDENTIFIER_NAME_SIZE]; + + pt_current = pt_tokenizer->nextToken(self, "DROP", pt_current); + pt_current = pt_tokenizer->nextToken(self, "INDEX", pt_current); + parseQualifiedName(self, name); + pt_current = pt_tokenizer->nextToken(self, "ON", pt_current); + parseTableName(self, true); + dropConstraint(self, name, XT_DD_INDEX); +} + +/* + * ----------------------------------------------------------------------- + * Create/Alter table table + */ + +class XTCreateTable : public XTParseTable { + public: + bool ct_convert; + struct charset_info_st *ct_charset; + XTPathStrPtr ct_tab_path; + u_int ct_contraint_no; + XTDDTable *ct_curr_table; + XTDDColumn *ct_curr_column; + XTDDConstraint *ct_curr_constraint; + + XTCreateTable(bool convert, XTPathStrPtr tab_path) : XTParseTable() { + ct_convert = convert; + ct_charset = myxt_getcharset(convert); + ct_tab_path = tab_path; + ct_curr_table = NULL; + ct_curr_column = NULL; + ct_curr_constraint = NULL; + } + + virtual void finalize(XTThreadPtr self) { + if (ct_curr_table) + ct_curr_table->release(self); + XTParseTable::finalize(self); + } + + virtual void setTableName(XTThreadPtr self, char *name, bool alterTable); + virtual void addColumn(XTThreadPtr self, char *col_name, char *old_col_name); + virtual void addConstraint(XTThreadPtr self, char *name, u_int type, bool lastColumn); + virtual void dropConstraint(XTThreadPtr self, char *name, u_int type); + virtual void addListedColumn(XTThreadPtr self, char *index_col_name); + virtual void setReferencedTable(XTThreadPtr self, char *ref_table); + virtual void addReferencedColumn(XTThreadPtr self, char *index_col_name); + virtual void setActions(XTThreadPtr self, int on_delete, int on_update); + + virtual void parseTable(XTThreadPtr self, bool convert, char *sql); +}; + +static void ri_free_create_table(XTThreadPtr self, XTCreateTable *ct) +{ + if (ct) + ct->release(self); +} + +XTDDTable *xt_ri_create_table(XTThreadPtr self, bool convert, XTPathStrPtr tab_path, char *sql, XTDDTable *start_tab) +{ + XTCreateTable *ct; + XTDDTable *dd_tab; + + if (!(ct = new XTCreateTable(convert, tab_path))) { + if (start_tab) + start_tab->release(self); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + } + + ct->ct_curr_table = start_tab; + + pushr_(ri_free_create_table, ct); + + ct->parseTable(self, convert, sql); + + /* Return the table ... */ + dd_tab = ct->ct_curr_table; + ct->ct_curr_table = NULL; + + freer_(); + return dd_tab; +} + +void XTCreateTable::parseTable(XTThreadPtr self, bool convert, char *sql) +{ + u_int i; + + ct_contraint_no = 0; + XTParseTable::parseTable(self, convert, sql); + + /* Remove contraints that do not have matching columns. */ + for (i=0; i<ct_curr_table->dt_indexes.size();) { + if (!ct_curr_table->dt_indexes.itemAt(i)->attachColumns()) + ct_curr_table->dt_indexes.remove(self, i); + else + i++; + } + + for (i=0; i<ct_curr_table->dt_fkeys.size(); ) { + if (!ct_curr_table->dt_fkeys.itemAt(i)->attachColumns()) + ct_curr_table->dt_fkeys.remove(self, i); + else + i++; + } +} + +void XTCreateTable::setTableName(XTThreadPtr self, char *name, bool alterTable) +{ + char path[PATH_MAX]; + + if (!name) + return; + + xt_strcpy(PATH_MAX, path, ct_tab_path->ps_path); + xt_remove_last_name_of_path(path); + + if (ct_convert) { + char buffer[XT_IDENTIFIER_NAME_SIZE]; + size_t len; + + myxt_static_convert_identifier(self, ct_charset, name, buffer, XT_IDENTIFIER_NAME_SIZE); + len = strlen(path); + myxt_static_convert_table_name(self, buffer, &path[len], PATH_MAX - len); + } + else + xt_strcat(PATH_MAX, path, name); + + if (alterTable) { + XTTableHPtr tab; + + /* Find the table... */ + pushsr_(tab, xt_heap_release, xt_use_table(self, (XTPathStrPtr) path, FALSE, TRUE, NULL)); + + /* Clone the foreign key definitions: */ + if (tab && tab->tab_dic.dic_table) { + ct_curr_table->dt_fkeys.deleteAll(self); + ct_curr_table->dt_fkeys.clone(self, &tab->tab_dic.dic_table->dt_fkeys); + for (u_int i=0; i<ct_curr_table->dt_fkeys.size(); i++) + ct_curr_table->dt_fkeys.itemAt(i)->co_table = ct_curr_table; + } + + freer_(); // xt_heap_release(tab) + } +} + +/* + * old_name is given if the column name was changed. + * NOTE that we built the table desciption from the current MySQL table + * description. This means that all changes to columns and + * indexes have already been applied. + * + * Our job is to now add the foreign key changes. + * This means we have to note the current column here. It is + * possible to add a FOREIGN KEY contraint directly to a column! + */ +void XTCreateTable::addColumn(XTThreadPtr self, char *new_name, char *old_name) +{ + char new_col_name[XT_IDENTIFIER_NAME_SIZE]; + + myxt_static_convert_identifier(self, ct_charset, new_name, new_col_name, XT_IDENTIFIER_NAME_SIZE); + ct_curr_column = ct_curr_table->findColumn(new_col_name); + if (old_name) { + char old_col_name[XT_IDENTIFIER_NAME_SIZE]; + + myxt_static_convert_identifier(self, ct_charset, old_name, old_col_name, XT_IDENTIFIER_NAME_SIZE); + ct_curr_table->alterColumnName(self, old_col_name, new_col_name); + } +} + +void XTCreateTable::addConstraint(XTThreadPtr self, char *name, u_int type, bool lastColumn) +{ + /* We are only interested in foreign keys! */ + if (type == XT_DD_KEY_FOREIGN) { + char buffer[50]; + + if (!(ct_curr_constraint = new XTDDForeignKey())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + ct_curr_table->dt_fkeys.append(self, (XTDDForeignKey *) ct_curr_constraint); + ct_curr_constraint->co_table = ct_curr_table; + + if (name && *name) + ct_curr_constraint->co_name = myxt_convert_identifier(self, ct_charset, name); + else { + // Generate a default constraint name: + ct_contraint_no++; + sprintf(buffer, "FOREIGN_%d", ct_contraint_no); + ct_curr_constraint->co_name = xt_dup_string(self, buffer); + } + + if (lastColumn && ct_curr_column) { + /* This constraint has one column, the current column. */ + XTDDColumnRef *cref; + char *col_name = xt_dup_string(self, ct_curr_column->dc_name); + + if (!(cref = new XTDDColumnRef())) { + xt_free(self, col_name); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + } + cref->cr_col_name = col_name; + ct_curr_constraint->co_cols.append(self, cref); + } + } + else + /* Other constraints/indexes do not interest us: */ + ct_curr_constraint = NULL; +} + +void XTCreateTable::dropConstraint(XTThreadPtr self, char *name, u_int type) +{ + if (type == XT_DD_KEY_FOREIGN && name) { + u_int i; + XTDDForeignKey *fkey; + char con_name[XT_IDENTIFIER_NAME_SIZE]; + + myxt_static_convert_identifier(self, ct_charset, name, con_name, XT_IDENTIFIER_NAME_SIZE); + for (i=0; i<ct_curr_table->dt_fkeys.size(); i++) { + fkey = ct_curr_table->dt_fkeys.itemAt(i); + if (fkey->co_name && myxt_strcasecmp(con_name, fkey->co_name) == 0) { + ct_curr_table->dt_fkeys.remove(fkey); + fkey->release(self); + } + } + } +} + +void XTCreateTable::addListedColumn(XTThreadPtr self, char *index_col_name) +{ + if (ct_curr_constraint && ct_curr_constraint->co_type == XT_DD_KEY_FOREIGN) { + XTDDColumnRef *cref; + char *name = myxt_convert_identifier(self, ct_charset, index_col_name); + + if (!(cref = new XTDDColumnRef())) { + xt_free(self, name); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + } + cref->cr_col_name = name; + ct_curr_constraint->co_cols.append(self, cref); + } +} + +void XTCreateTable::setReferencedTable(XTThreadPtr self, char *ref_table) +{ + XTDDForeignKey *fk = (XTDDForeignKey *) ct_curr_constraint; + char path[PATH_MAX]; + + xt_strcpy(PATH_MAX, path, ct_tab_path->ps_path); + xt_remove_last_name_of_path(path); + if (ct_convert) { + char buffer[XT_IDENTIFIER_NAME_SIZE]; + size_t len; + + myxt_static_convert_identifier(self, ct_charset, ref_table, buffer, XT_IDENTIFIER_NAME_SIZE); + len = strlen(path); + myxt_static_convert_table_name(self, buffer, &path[len], PATH_MAX - len); + } + else + xt_strcat(PATH_MAX, path, ref_table); + + fk->fk_ref_tab_name = (XTPathStrPtr) xt_dup_string(self, path); +} + +/* If the referenced column is NULL, this means + * duplicate the local column list! + */ +void XTCreateTable::addReferencedColumn(XTThreadPtr self, char *index_col_name) +{ + XTDDForeignKey *fk = (XTDDForeignKey *) ct_curr_constraint; + XTDDColumnRef *cref; + char *name; + + if (index_col_name) { + name = myxt_convert_identifier(self, ct_charset, index_col_name); + if (!(cref = new XTDDColumnRef())) { + xt_free(self, name); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + } + cref->cr_col_name = name; + fk->fk_ref_cols.append(self, cref); + } + else + fk->fk_ref_cols.clone(self, &fk->co_cols); +} + +void XTCreateTable::setActions(XTThreadPtr self __attribute__((unused)), int on_delete, int on_update) +{ + XTDDForeignKey *fk = (XTDDForeignKey *) ct_curr_constraint; + + fk->fk_on_delete = on_delete; + fk->fk_on_update = on_update; +} + +/* + * ----------------------------------------------------------------------- + * Dictionary methods + */ + +void XTDDColumn::init(XTThreadPtr self, XTObject *obj) { + XTDDColumn *col = (XTDDColumn *) obj; + + XTObject::init(self, obj); + if (col->dc_name) + dc_name = xt_dup_string(self, col->dc_name); + if (col->dc_data_type) + dc_data_type = xt_dup_string(self, col->dc_data_type); + dc_null_ok = col->dc_null_ok; + dc_auto_inc = col->dc_auto_inc; +} + +void XTDDColumn::finalize(XTThreadPtr self) +{ + if (dc_name) + xt_free(self, dc_name); + if (dc_data_type) + xt_free(self, dc_data_type); +} + +void XTDDColumn::loadString(XTThreadPtr self, XTStringBufferPtr sb) +{ + xt_sb_concat(self, sb, "`"); + xt_sb_concat(self, sb, dc_name); + xt_sb_concat(self, sb, "` "); + if (dc_data_type) { + xt_sb_concat(self, sb, dc_data_type); + if (dc_null_ok) + xt_sb_concat(self, sb, " NULL"); + else + xt_sb_concat(self, sb, " NOT NULL"); + if (dc_auto_inc) + xt_sb_concat(self, sb, " AUTO_INCREMENT"); + } +} + +void XTDDColumnRef::init(XTThreadPtr self, XTObject *obj) +{ + XTDDColumnRef *cr = (XTDDColumnRef *) obj; + + XTObject::init(self, obj); + cr_col_name = xt_dup_string(self, cr->cr_col_name); +} + +void XTDDColumnRef::finalize(XTThreadPtr self) +{ + XTObject::finalize(self); + if (cr_col_name) { + xt_free(self, cr_col_name); + cr_col_name = NULL; + } +} + +void XTDDConstraint::init(XTThreadPtr self, XTObject *obj) +{ + XTDDConstraint *co = (XTDDConstraint *) obj; + + XTObject::init(self, obj); + co_type = co->co_type; + if (co->co_name) + co_name = xt_dup_string(self, co->co_name); + if (co->co_ind_name) + co_ind_name = xt_dup_string(self, co->co_ind_name); + co_cols.clone(self, &co->co_cols); +} + +void XTDDConstraint::loadString(XTThreadPtr self, XTStringBufferPtr sb) +{ + if (co_name) { + xt_sb_concat(self, sb, "CONSTRAINT `"); + xt_sb_concat(self, sb, co_name); + xt_sb_concat(self, sb, "` "); + } + switch (co_type) { + case XT_DD_INDEX: + xt_sb_concat(self, sb, "INDEX "); + break; + case XT_DD_INDEX_UNIQUE: + xt_sb_concat(self, sb, "UNIQUE INDEX "); + break; + case XT_DD_KEY_PRIMARY: + xt_sb_concat(self, sb, "PRIMARY KEY "); + break; + case XT_DD_KEY_FOREIGN: + xt_sb_concat(self, sb, "FOREIGN KEY "); + break; + } + if (co_ind_name) { + xt_sb_concat(self, sb, "`"); + xt_sb_concat(self, sb, co_ind_name); + xt_sb_concat(self, sb, "` "); + } + xt_sb_concat(self, sb, "(`"); + xt_sb_concat(self, sb, co_cols.itemAt(0)->cr_col_name); + for (u_int i=1; i<co_cols.size(); i++) { + xt_sb_concat(self, sb, "`, `"); + xt_sb_concat(self, sb, co_cols.itemAt(i)->cr_col_name); + } + xt_sb_concat(self, sb, "`)"); +} + +void XTDDConstraint::alterColumnName(XTThreadPtr self, char *from_name, char *to_name) +{ + XTDDColumnRef *col; + + for (u_int i=0; i<co_cols.size(); i++) { + col = co_cols.itemAt(i); + if (myxt_strcasecmp(col->cr_col_name, from_name) == 0) { + char *name = xt_dup_string(self, to_name); + + xt_free(self, col->cr_col_name); + col->cr_col_name = name; + break; + } + } +} + +void XTDDConstraint::getColumnList(char *buffer, size_t size) +{ + if (co_table->dt_table) { + xt_strcat(size, buffer, "`"); + xt_strcpy(size, buffer, co_table->dt_table->tab_name->ps_path); + xt_strcat(size, buffer, "` (`"); + } + else + xt_strcpy(size, buffer, "(`"); + xt_strcat(size, buffer, co_cols.itemAt(0)->cr_col_name); + for (u_int i=1; i<co_cols.size(); i++) { + xt_strcat(size, buffer, "`, `"); + xt_strcat(size, buffer, co_cols.itemAt(i)->cr_col_name); + } + xt_strcat(size, buffer, "`)"); +} + +bool XTDDConstraint::sameColumns(XTDDConstraint *co) +{ + u_int i = 0; + + if (co_cols.size() != co->co_cols.size()) + return false; + while (i<co_cols.size()) { + if (myxt_strcasecmp(co_cols.itemAt(i)->cr_col_name, co->co_cols.itemAt(i)->cr_col_name) != 0) + return false; + i++; + } + return OK; +} + +bool XTDDConstraint::attachColumns() +{ + XTDDColumn *col; + + for (u_int i=0; i<co_cols.size(); i++) { + if (!(col = co_table->findColumn(co_cols.itemAt(i)->cr_col_name))) + return false; + /* If this is a primary key, then the column becomes not-null! */ + if (co_type == XT_DD_KEY_PRIMARY) + col->dc_null_ok = false; + } + return true; +} + +void XTDDTableRef::finalize(XTThreadPtr self) +{ + XTDDForeignKey *fk; + + if ((fk = tr_fkey)) { + tr_fkey = NULL; + fk->removeReference(self); + xt_heap_release(self, fk->co_table->dt_table); /* We referenced the database table, not the foreign key */ + } + XTObject::finalize(self); +} + +bool XTDDTableRef::checkReference(xtWord1 *before_buf, XTThreadPtr thread) +{ + XTIndexPtr loc_ind, ind; + xtBool no_null = TRUE; + XTOpenTablePtr ot; + XTIdxSearchKeyRec search_key; + xtXactID xn_id; + XTXactWaitRec xw; + + if (!(loc_ind = tr_fkey->getReferenceIndexPtr())) + return false; + + if (!(ind = tr_fkey->getIndexPtr())) + return false; + + search_key.sk_key_value.sv_flags = 0; + search_key.sk_key_value.sv_rec_id = 0; + search_key.sk_key_value.sv_row_id = 0; + search_key.sk_key_value.sv_key = search_key.sk_key_buf; + search_key.sk_key_value.sv_length = myxt_create_foreign_key_from_row(loc_ind, search_key.sk_key_buf, before_buf, ind, &no_null); + search_key.sk_on_key = FALSE; + + if (!no_null) + return true; + + /* Search for the key in the child (referencing) table: */ + if (!(ot = xt_db_open_table_using_tab(tr_fkey->co_table->dt_table, thread))) + goto failed; + + retry: + if (!xt_idx_search(ot, ind, &search_key)) + goto failed; + + while (ot->ot_curr_rec_id && search_key.sk_on_key) { + switch (xt_tab_maybe_committed(ot, ot->ot_curr_rec_id, &xn_id, &ot->ot_curr_row_id, &ot->ot_curr_updated)) { + case XT_MAYBE: + xw.xw_xn_id = xn_id; + if (!xt_xn_wait_for_xact(thread, &xw, NULL)) + goto failed; + goto retry; + case XT_ERR: + goto failed; + case TRUE: + /* We found a matching child: */ + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_ROW_IS_REFERENCED, tr_fkey->co_name); + goto failed; + break; + case FALSE: + if (!xt_idx_next(ot, ind, &search_key)) + goto failed; + break; + } + } + + /* No matching children, all OK: */ + xt_db_return_table_to_pool_ns(ot); + return true; + + failed: + xt_db_return_table_to_pool_ns(ot); + return false; +} + +/* + * A row has been deleted or updated (after_buf non-NULL), check if it is referenced by the foreign key table. + * If it is referenced, then we need to follow the specified action. + */ +bool XTDDTableRef::modifyRow(XTOpenTablePtr XT_UNUSED(ref_ot), xtWord1 *before_buf, xtWord1 *after_buf, XTThreadPtr thread) +{ + XTIndexPtr loc_ind, ind; + xtBool no_null = TRUE; + XTOpenTablePtr ot; + XTIdxSearchKeyRec search_key; + xtXactID xn_id; + int action = after_buf ? tr_fkey->fk_on_update : tr_fkey->fk_on_delete; + u_int after_key_len = 0; + xtWord1 *after_key = NULL; + XTInfoBufferRec after_info; + XTXactWaitRec xw; + + after_info.ib_free = FALSE; + + if (!(loc_ind = tr_fkey->getReferenceIndexPtr())) + return false; + + if (!(ind = tr_fkey->getIndexPtr())) + return false; + + search_key.sk_key_value.sv_flags = 0; + search_key.sk_key_value.sv_rec_id = 0; + search_key.sk_key_value.sv_row_id = 0; + search_key.sk_key_value.sv_key = search_key.sk_key_buf; + search_key.sk_key_value.sv_length = myxt_create_foreign_key_from_row(loc_ind, search_key.sk_key_buf, before_buf, ind, &no_null); + search_key.sk_on_key = FALSE; + + if (!no_null) + return true; + + if (after_buf) { + if (!(after_key = (xtWord1 *) xt_malloc_ns(XT_INDEX_MAX_KEY_SIZE))) + return false; + after_key_len = myxt_create_foreign_key_from_row(loc_ind, after_key, after_buf, ind, NULL); + + /* Check whether the key value has changed, if not, we have nothing + * to do here! + */ + if (myxt_compare_key(ind, 0, search_key.sk_key_value.sv_length, + search_key.sk_key_value.sv_key, after_key) == 0) + goto success; + + } + + /* Search for the key in the child (referencing) table: */ + if (!(ot = xt_db_open_table_using_tab(tr_fkey->co_table->dt_table, thread))) + goto failed; + + retry: + if (!xt_idx_search(ot, ind, &search_key)) + goto failed_2; + + while (ot->ot_curr_rec_id && search_key.sk_on_key) { + switch (xt_tab_maybe_committed(ot, ot->ot_curr_rec_id, &xn_id, &ot->ot_curr_row_id, &ot->ot_curr_updated)) { + case XT_MAYBE: + xw.xw_xn_id = xn_id; + if (!xt_xn_wait_for_xact(thread, &xw, NULL)) + goto failed_2; + goto retry; + case XT_ERR: + goto failed_2; + case TRUE: + /* We found a matching child: */ + switch (action) { + case XT_KEY_ACTION_CASCADE: + if (after_buf) { + /* Do a cascaded update: */ + if (!xt_tab_load_record(ot, ot->ot_curr_rec_id, &after_info)) + goto failed_2; + + if (!myxt_create_row_from_key(ot, ind, after_key, after_key_len, after_info.ib_db.db_data)) + goto failed_2; + + if (!xt_tab_update_record(ot, NULL, after_info.ib_db.db_data)) { + // Change to duplicate foreign key + if (ot->ot_thread->t_exception.e_xt_err == XT_ERR_DUPLICATE_KEY) + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_DUPLICATE_FKEY, tr_fkey->co_name); + goto failed_2; + } + } + else { + /* Do a cascaded delete: */ + if (!xt_tab_delete_record(ot, NULL)) + goto failed_2; + } + break; + case XT_KEY_ACTION_SET_NULL: + if (!xt_tab_load_record(ot, ot->ot_curr_rec_id, &after_info)) + goto failed_2; + + myxt_set_null_row_from_key(ot, ind, after_info.ib_db.db_data); + + if (!xt_tab_update_record(ot, NULL, after_info.ib_db.db_data)) + goto failed_2; + break; + case XT_KEY_ACTION_SET_DEFAULT: + + if (!xt_tab_load_record(ot, ot->ot_curr_rec_id, &after_info)) + goto failed_2; + + myxt_set_default_row_from_key(ot, ind, after_info.ib_db.db_data); + + if (!xt_tab_update_record(ot, NULL, after_info.ib_db.db_data)) + goto failed_2; + + break; + case XT_KEY_ACTION_NO_ACTION: +#ifdef XT_IMPLEMENT_NO_ACTION + XTRestrictItemRec r; + + r.ri_tab_id = ref_ot->ot_table->tab_id; + r.ri_rec_id = ref_ot->ot_curr_rec_id; + if (!xt_bl_append(NULL, &thread->st_restrict_list, (void *) &r)) + goto failed_2; + break; +#endif + default: + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_ROW_IS_REFERENCED, tr_fkey->co_name); + goto failed_2; + } + /* Fall throught to next: */ + case FALSE: + if (!xt_idx_next(ot, ind, &search_key)) + goto failed_2; + break; + } + } + + /* No matching children, all OK: */ + xt_db_return_table_to_pool_ns(ot); + + success: + xt_ib_free(NULL, &after_info); + if (after_key) + xt_free_ns(after_key); + return true; + + failed_2: + xt_db_return_table_to_pool_ns(ot); + + failed: + xt_ib_free(NULL, &after_info); + if (after_key) + xt_free_ns(after_key); + return false; +} + +void XTDDTableRef::deleteAllRows(XTThreadPtr self) +{ + XTOpenTablePtr ot; + xtInt8 row_count; + + if (!tr_fkey->getReferenceIndexPtr()) + throw_(); + + if (!tr_fkey->getIndexPtr()) + throw_(); + + if (!(ot = xt_db_open_table_using_tab(tr_fkey->co_table->dt_table, self))) + throw_(); + + row_count = ((xtInt8) ot->ot_table->tab_row_eof_id) - 1; + row_count -= (xtInt8) ot->ot_table->tab_row_fnum; + + xt_db_return_table_to_pool_ns(ot); + + if (row_count > 0) + xt_throw_ixterr(XT_CONTEXT, XT_ERR_ROW_IS_REFERENCED, tr_fkey->co_name); +} + +void XTDDIndex::init(XTThreadPtr self, XTObject *obj) +{ + XTDDConstraint::init(self, obj); +} + +XTIndexPtr XTDDIndex::getIndexPtr() +{ + if (in_index >= co_table->dt_table->tab_dic.dic_key_count) { + XTDDIndex *in; + + if (!(in = co_table->findIndex(this))) + return NULL; + in_index = in->in_index; + } + return co_table->dt_table->tab_dic.dic_keys[in_index]; +} + +void XTDDForeignKey::init(XTThreadPtr self, XTObject *obj) +{ + XTDDForeignKey *fk = (XTDDForeignKey *) obj; + + XTDDIndex::init(self, obj); + if (fk->fk_ref_tab_name) + fk_ref_tab_name = (XTPathStrPtr) xt_dup_string(self, fk->fk_ref_tab_name->ps_path); + fk_ref_cols.clone(self, &fk->fk_ref_cols); + fk_on_delete = fk->fk_on_delete; + fk_on_update = fk->fk_on_update; +} + +void XTDDForeignKey::finalize(XTThreadPtr self) +{ + XTDDTable *ref_tab; + + if (fk_ref_tab_name) { + xt_free(self, fk_ref_tab_name); + fk_ref_tab_name = NULL; + } + + if ((ref_tab = fk_ref_table)) { + fk_ref_table = NULL; + ref_tab->removeReference(self, this); + xt_heap_release(self, ref_tab->dt_table); /* We referenced the table, not the index! */ + } + + fk_ref_index = UINT_MAX; + + fk_ref_cols.deleteAll(self); + XTDDConstraint::finalize(self); +} + +void XTDDForeignKey::loadString(XTThreadPtr self, XTStringBufferPtr sb) +{ + XTDDConstraint::loadString(self, sb); + xt_sb_concat(self, sb, " REFERENCES `"); + xt_sb_concat(self, sb, xt_last_name_of_path(fk_ref_tab_name->ps_path)); + xt_sb_concat(self, sb, "` "); + + xt_sb_concat(self, sb, "(`"); + xt_sb_concat(self, sb, fk_ref_cols.itemAt(0)->cr_col_name); + for (u_int i=1; i<fk_ref_cols.size(); i++) { + xt_sb_concat(self, sb, "`, `"); + xt_sb_concat(self, sb, fk_ref_cols.itemAt(i)->cr_col_name); + } + xt_sb_concat(self, sb, "`)"); + + if (fk_on_delete != XT_KEY_ACTION_DEFAULT && fk_on_delete != XT_KEY_ACTION_RESTRICT) { + xt_sb_concat(self, sb, " ON DELETE "); + switch (fk_on_delete) { + case XT_KEY_ACTION_CASCADE: xt_sb_concat(self, sb, "CASCADE"); break; + case XT_KEY_ACTION_SET_NULL: xt_sb_concat(self, sb, "SET NULL"); break; + case XT_KEY_ACTION_SET_DEFAULT: xt_sb_concat(self, sb, "SET DEFAULT"); break; + case XT_KEY_ACTION_NO_ACTION: xt_sb_concat(self, sb, "NO ACTION"); break; + } + } + if (fk_on_update != XT_KEY_ACTION_DEFAULT && fk_on_update != XT_KEY_ACTION_RESTRICT) { + xt_sb_concat(self, sb, " ON UPDATE "); + switch (fk_on_update) { + case XT_KEY_ACTION_DEFAULT: xt_sb_concat(self, sb, "RESTRICT"); break; + case XT_KEY_ACTION_RESTRICT: xt_sb_concat(self, sb, "RESTRICT"); break; + case XT_KEY_ACTION_CASCADE: xt_sb_concat(self, sb, "CASCADE"); break; + case XT_KEY_ACTION_SET_NULL: xt_sb_concat(self, sb, "SET NULL"); break; + case XT_KEY_ACTION_SET_DEFAULT: xt_sb_concat(self, sb, "SET DEFAULT"); break; + case XT_KEY_ACTION_NO_ACTION: xt_sb_concat(self, sb, "NO ACTION"); break; + } + } +} + +void XTDDForeignKey::getReferenceList(char *buffer, size_t size) +{ + buffer[0] = '`'; + xt_strcpy(size, buffer + 1, xt_last_name_of_path(fk_ref_tab_name->ps_path)); + xt_strcat(size, buffer, "` ("); + xt_strcat(size, buffer, fk_ref_cols.itemAt(0)->cr_col_name); + for (u_int i=1; i<fk_ref_cols.size(); i++) { + xt_strcat(size, buffer, ", "); + xt_strcat(size, buffer, fk_ref_cols.itemAt(i)->cr_col_name); + } + xt_strcat(size, buffer, ")"); +} + +struct XTIndex *XTDDForeignKey::getReferenceIndexPtr() +{ + if (!fk_ref_table) { + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_REF_TABLE_NOT_FOUND, fk_ref_tab_name); + return NULL; + } + if (fk_ref_index >= fk_ref_table->dt_table->tab_dic.dic_key_count) { + XTDDIndex *in; + + if (!(in = fk_ref_table->findReferenceIndex(this))) + return NULL; + if (!checkReferencedTypes(fk_ref_table)) + return NULL; + fk_ref_index = in->in_index; + } + + return fk_ref_table->dt_table->tab_dic.dic_keys[fk_ref_index]; +} + +bool XTDDForeignKey::sameReferenceColumns(XTDDConstraint *co) +{ + u_int i = 0; + + if (fk_ref_cols.size() != co->co_cols.size()) + return false; + while (i<fk_ref_cols.size()) { + if (myxt_strcasecmp(fk_ref_cols.itemAt(i)->cr_col_name, co->co_cols.itemAt(i)->cr_col_name) != 0) + return false; + i++; + } + return OK; +} + +bool XTDDForeignKey::checkReferencedTypes(XTDDTable *dt) +{ + XTDDColumn *col, *ref_col; + XTDDEnumerableColumn *enum_col, *enum_ref_col; + + if (dt->dt_table->tab_dic.dic_tab_flags & XT_TAB_FLAGS_TEMP_TAB) { + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_FK_REF_TEMP_TABLE); + return false; + } + + for (u_int i=0; i<co_cols.size() && i<fk_ref_cols.size(); i++) { + col = co_table->findColumn(co_cols.itemAt(i)->cr_col_name); + ref_col = dt->findColumn(fk_ref_cols.itemAt(i)->cr_col_name); + if (!col || !ref_col) + continue; + + enum_col = col->castToEnumerable(); + enum_ref_col = ref_col->castToEnumerable(); + + if (!enum_col && !enum_ref_col && (strcmp(col->dc_data_type, ref_col->dc_data_type) == 0)) + continue; + + /* Allow match varchar(30) == varchar(40): */ + if (strncmp(col->dc_data_type, "varchar", 7) == 0 && strncmp(ref_col->dc_data_type, "varchar", 7) == 0) { + char *t1, *t2; + + t1 = col->dc_data_type + 7; + while (*t1 && (isdigit(*t1) || *t1 == '(' || *t1 == ')')) t1++; + t2 = col->dc_data_type + 7; + while (*t2 && (isdigit(*t2) || *t2 == '(' || *t2 == ')')) t2++; + + if (strcmp(t1, t2) == 0) + continue; + } + + /* + * MySQL stores ENUMs an integer indexes for string values. That's why + * it is ok to have refrences between columns that are different ENUMs as long + * as they contain equal number of members, so that for example a cascase update + * will not cause an invaid value to be stored in the child table. + * + * The above is also true for SETs. + * + */ + + if (enum_col && enum_ref_col && + (enum_col->enum_size == enum_ref_col->enum_size) && + (enum_col->is_enum == enum_ref_col->is_enum)) + continue; + + xt_register_tabcolerr(XT_REG_CONTEXT, XT_ERR_REF_TYPE_WRONG, fk_ref_tab_name, ref_col->dc_name); + return false; + } + return true; +} + +void XTDDForeignKey::removeReference(XTThreadPtr self) +{ + XTDDTable *ref_tab; + + xt_xlock_rwlock(self, &co_table->dt_ref_lock); + pushr_(xt_unlock_rwlock, &co_table->dt_ref_lock); + + if ((ref_tab = fk_ref_table)) { + fk_ref_table = NULL; + ref_tab->removeReference(self, this); + xt_heap_release(self, ref_tab->dt_table); /* We referenced the table, not the index! */ + } + + fk_ref_index = UINT_MAX; + + freer_(); // xt_unlock_rwlock(&co_table->dt_ref_lock); +} + +/* + * A row was inserted, check that a key exists in the referenced + * table. + */ +bool XTDDForeignKey::insertRow(xtWord1 *before_buf, xtWord1 *rec_buf, XTThreadPtr thread) +{ + XTIndexPtr loc_ind, ind; + xtBool no_null = TRUE; + XTOpenTablePtr ot; + XTIdxSearchKeyRec search_key; + xtXactID xn_id; + XTXactWaitRec xw; + + /* This lock ensures that the foreign key references are not + * changed. + */ + xt_slock_rwlock_ns(&co_table->dt_ref_lock); + + if (!(loc_ind = getIndexPtr())) + goto failed; + + if (!(ind = getReferenceIndexPtr())) + goto failed; + + search_key.sk_key_value.sv_flags = 0; + search_key.sk_key_value.sv_rec_id = 0; + search_key.sk_key_value.sv_row_id = 0; + search_key.sk_key_value.sv_key = search_key.sk_key_buf; + search_key.sk_key_value.sv_length = myxt_create_foreign_key_from_row(loc_ind, search_key.sk_key_buf, rec_buf, ind, &no_null); + search_key.sk_on_key = FALSE; + + if (!no_null) + goto success; + + if (before_buf) { + u_int before_key_len; + xtWord1 before_key[XT_INDEX_MAX_KEY_SIZE]; + + /* If there is a before buffer, this insert was an update, so check + * if the key value has changed. If not, we need not do anything. + */ + before_key_len = myxt_create_foreign_key_from_row(loc_ind, before_key, before_buf, ind, NULL); + + /* Check whether the key value has changed, if not, we have nothing + * to do here! + */ + if (search_key.sk_key_value.sv_length == before_key_len && + memcmp(search_key.sk_key_buf, before_key, before_key_len) == 0) + goto success; + } + + /* Search for the key in the parent (referenced) table: */ + if (!(ot = xt_db_open_table_using_tab(fk_ref_table->dt_table, thread))) + goto failed; + + retry: + if (!xt_idx_search(ot, ind, &search_key)) + goto failed_2; + + while (ot->ot_curr_rec_id) { + if (!search_key.sk_on_key) + break; + + switch (xt_tab_maybe_committed(ot, ot->ot_curr_rec_id, &xn_id, &ot->ot_curr_row_id, &ot->ot_curr_updated)) { + case XT_MAYBE: + /* We should not get a deadlock here because the thread + * that we are waiting for, should not doing + * data definition (i.e. should not be trying to + * get an exclusive lock on dt_ref_lock. + */ + xw.xw_xn_id = xn_id; + if (!xt_xn_wait_for_xact(thread, &xw, NULL)) + goto failed_2; + goto retry; + case XT_ERR: + goto failed_2; + case TRUE: + /* We found a matching parent: */ + xt_db_return_table_to_pool_ns(ot); + goto success; + case FALSE: + if (!xt_idx_next(ot, ind, &search_key)) + goto failed_2; + break; + } + } + + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_NO_REFERENCED_ROW, co_name); + + failed_2: + xt_db_return_table_to_pool_ns(ot); + + failed: + xt_unlock_rwlock_ns(&co_table->dt_ref_lock); + return false; + + success: + xt_unlock_rwlock_ns(&co_table->dt_ref_lock); + return true; +} + +/* + * Convert XT_KEY_ACTION_* constants to strings + */ +const char *XTDDForeignKey::actionTypeToString(int action) +{ + switch (action) + { + case XT_KEY_ACTION_DEFAULT: + case XT_KEY_ACTION_RESTRICT: + return "RESTRICT"; + case XT_KEY_ACTION_CASCADE: + return "CASCADE"; + case XT_KEY_ACTION_SET_NULL: + return "SET NULL"; + case XT_KEY_ACTION_SET_DEFAULT: + return ""; + case XT_KEY_ACTION_NO_ACTION: + return "NO ACTION"; + } + + return ""; +} + +void XTDDTable::init(XTThreadPtr self) +{ + xt_init_rwlock_with_autoname(self, &dt_ref_lock); + dt_trefs = NULL; +} + +void XTDDTable::init(XTThreadPtr self, XTObject *obj) +{ + XTDDTable *tab = (XTDDTable *) obj; + u_int i; + + init(self); + XTObject::init(self, obj); + dt_cols.clone(self, &tab->dt_cols); + dt_indexes.clone(self, &tab->dt_indexes); + dt_fkeys.clone(self, &tab->dt_fkeys); + + for (i=0; i<dt_indexes.size(); i++) + dt_indexes.itemAt(i)->co_table = this; + for (i=0; i<dt_fkeys.size(); i++) + dt_fkeys.itemAt(i)->co_table = this; +} + +void XTDDTable::finalize(XTThreadPtr self) +{ + XTDDTableRef *ptr; + + removeReferences(self); + + dt_cols.deleteAll(self); + dt_indexes.deleteAll(self); + dt_fkeys.deleteAll(self); + + while (dt_trefs) { + ptr = dt_trefs; + dt_trefs = dt_trefs->tr_next; + ptr->release(self); + } + + xt_free_rwlock(&dt_ref_lock); +} + +XTDDColumn *XTDDTable::findColumn(char *name) +{ + XTDDColumn *col; + + for (u_int i=0; i<dt_cols.size(); i++) { + col = dt_cols.itemAt(i); + if (myxt_strcasecmp(name, col->dc_name) == 0) + return col; + } + return NULL; +} + +void XTDDTable::loadString(XTThreadPtr self, XTStringBufferPtr sb) +{ + u_int i; + + /* I do not specify a table name because that is known */ + xt_sb_concat(self, sb, "CREATE TABLE (\n "); + + /* We only need to save the foreign key definitions!! + for (i=0; i<dt_cols.size(); i++) { + if (i != 0) + xt_sb_concat(self, sb, ",\n "); + dt_cols.itemAt(i)->loadString(self, sb); + } + + for (i=0; i<dt_indexes.size(); i++) { + xt_sb_concat(self, sb, ",\n "); + dt_indexes.itemAt(i)->loadString(self, sb); + } + */ + + for (i=0; i<dt_fkeys.size(); i++) { + if (i != 0) + xt_sb_concat(self, sb, ",\n "); + dt_fkeys.itemAt(i)->loadString(self, sb); + } + + xt_sb_concat(self, sb, "\n)\n"); +} + +void XTDDTable::loadForeignKeyString(XTThreadPtr self, XTStringBufferPtr sb) +{ + for (u_int i=0; i<dt_fkeys.size(); i++) { + xt_sb_concat(self, sb, ",\n "); + dt_fkeys.itemAt(i)->loadString(self, sb); + } +} + +/* Change all references to the given column name to new name. */ +void XTDDTable::alterColumnName(XTThreadPtr self, char *from_name, char *to_name) +{ + u_int i; + + /* We only alter references in the foreign keys (we copied the + * other changes from MySQL). + */ + for (i=0; i<dt_fkeys.size(); i++) + dt_fkeys.itemAt(i)->alterColumnName(self, from_name, to_name); +} + +void XTDDTable::attachReference(XTThreadPtr self, XTDDForeignKey *fk) +{ + XTDDTableRef *tr; + + /* Remove the reference to this FK if one exists: */ + removeReference(self, fk); + + if (!fk->checkReferencedTypes(this)) { + if (!self->st_ignore_fkeys) + throw_(); + } + + xt_xlock_rwlock(self, &dt_ref_lock); + pushr_(xt_unlock_rwlock, &dt_ref_lock); + + if (!(tr = new XTDDTableRef())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + tr->tr_fkey = fk; + tr->tr_next = dt_trefs; + dt_trefs = tr; + + /* Reference the database table of the foreign key, not the FK itself. + * Just referencing the key will not guarantee that the + * table remains valid because the FK does not reference the + * table. + */ + xt_heap_reference(self, fk->co_table->dt_table); + + freer_(); // xt_unlock_rwlock(&dt_ref_lock); +} + +/* + * Remove the reference to the given foreign key. + */ +void XTDDTable::removeReference(XTThreadPtr self, XTDDForeignKey *fk) +{ + XTDDTableRef *tr, *prev_tr = NULL; + + xt_xlock_rwlock(self, &dt_ref_lock); + pushr_(xt_unlock_rwlock, &dt_ref_lock); + + tr = dt_trefs; + while (tr) { + if (tr->tr_fkey == fk) { + if (prev_tr) + prev_tr->tr_next = tr->tr_next; + else + dt_trefs = tr->tr_next; + break; + } + prev_tr = tr; + tr = tr->tr_next; + } + freer_(); // xt_unlock_rwlock(&dt_ref_lock); + if (tr) + tr->release(self); +} + +void XTDDTable::checkForeignKeyReference(XTThreadPtr self, XTDDForeignKey *fk) +{ + XTDDColumnRef *cr; + + for (u_int i=0; i<fk->fk_ref_cols.size(); i++) { + cr = fk->fk_ref_cols.itemAt(i); + if (!findColumn(cr->cr_col_name)) + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_COLUMN_NOT_FOUND, fk->fk_ref_tab_name, cr->cr_col_name); + } +} + +void XTDDTable::attachReference(XTThreadPtr self, XTDDTable *dt) +{ + XTDDForeignKey *fk; + + for (u_int i=0; i<dt_fkeys.size(); i++) { + fk = dt_fkeys.itemAt(i); + if (xt_tab_compare_names(fk->fk_ref_tab_name->ps_path, dt->dt_table->tab_name->ps_path) == 0) { + fk->removeReference(self); + + dt->attachReference(self, fk); + + xt_xlock_rwlock(self, &dt_ref_lock); + pushr_(xt_unlock_rwlock, &dt_ref_lock); + /* Referenced the table, not the index! + * We do this because we know that if the table is referenced, the + * index will remain valid! + * This is because the table references the index, and only + * releases it when the table is released. The index does not + * reference the table though! + */ + xt_heap_reference(self, dt->dt_table); + fk->fk_ref_table = dt; + freer_(); // xt_unlock_rwlock(&dt_ref_lock); + } + } +} + +/* + * This function assumes the database table list is locked! + */ +void XTDDTable::attachReferences(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTDDForeignKey *fk; + XTTableHPtr tab; + XTDDTable *dt; + XTHashEnumRec tables; + + /* Search for table referenced by this table. */ + for (u_int i=0; i<dt_fkeys.size(); i++) { + fk = dt_fkeys.itemAt(i); + fk->removeReference(self); + + // if self-reference + if (xt_tab_compare_names(fk->fk_ref_tab_name->ps_path, this->dt_table->tab_name->ps_path) == 0) + fk->fk_ref_table = this; + else { + /* get pointer to the referenced table, load it if needed + * cyclic references are being handled, absent table is ignored + */ + tab = xt_use_table_no_lock(self, db, fk->fk_ref_tab_name, /*TRUE*/FALSE, /*FALSE*/TRUE, NULL, NULL); + + if (tab) { + pushr_(xt_heap_release, tab); + if ((dt = tab->tab_dic.dic_table)) { + // Add a reverse reference: + dt->attachReference(self, fk); + xt_heap_reference(self, dt->dt_table); /* Referenced the table, not the index! */ + fk->fk_ref_table = dt; + } + freer_(); // xt_heap_release(tab) + } + else if (!self->st_ignore_fkeys) { + xt_throw_taberr(XT_CONTEXT, XT_ERR_REF_TABLE_NOT_FOUND, fk->fk_ref_tab_name); + } + } + } + + /* Search for tables that reference this table. */ + xt_ht_enum(self, dt_table->tab_db->db_tables, &tables); + while ((tab = (XTTableHPtr) xt_ht_next(self, &tables))) { + if (tab == this->dt_table) /* no need to re-reference itself, also this fails with "native" pthreads */ + continue; + xt_heap_reference(self, tab); + pushr_(xt_heap_release, tab); + if ((dt = tab->tab_dic.dic_table)) + dt->attachReference(self, this); + freer_(); // xt_heap_release(tab) + } +} + +void XTDDTable::removeReferences(XTThreadPtr self) +{ + XTDDForeignKey *fk; + XTDDTableRef *tr; + XTDDTable *tab; + + xt_xlock_rwlock(self, &dt_ref_lock); + pushr_(xt_unlock_rwlock, &dt_ref_lock); + + for (u_int i=0; i<dt_fkeys.size(); i++) { + fk = dt_fkeys.itemAt(i); + if ((tab = fk->fk_ref_table)) { + fk->fk_ref_table = NULL; + fk->fk_ref_index = UINT_MAX; + if (tab != this) { + /* To avoid deadlock we do not hold more than + * one lock at a time! + */ + freer_(); // xt_unlock_rwlock(&dt_ref_lock); + + tab->removeReference(self, fk); + xt_heap_release(self, tab->dt_table); /* We referenced the table, not the index! */ + + xt_xlock_rwlock(self, &dt_ref_lock); + pushr_(xt_unlock_rwlock, &dt_ref_lock); + } + } + } + + while (dt_trefs) { + tr = dt_trefs; + dt_trefs = tr->tr_next; + freer_(); // xt_unlock_rwlock(&dt_ref_lock); + tr->release(self); + xt_xlock_rwlock(self, &dt_ref_lock); + pushr_(xt_unlock_rwlock, &dt_ref_lock); + } + + freer_(); // xt_unlock_rwlock(&dt_ref_lock); +} + +void XTDDTable::checkForeignKeys(XTThreadPtr self, bool temp_table) +{ + XTDDForeignKey *fk; + + if (temp_table && dt_fkeys.size()) { + /* Temporary tables cannot have foreign keys: */ + xt_throw_xterr(XT_CONTEXT, XT_ERR_FK_ON_TEMP_TABLE); + + } + + /* Search for table referenced by this table. */ + for (u_int i=0; i<dt_fkeys.size(); i++) { + fk = dt_fkeys.itemAt(i); + + if (fk->fk_on_delete == XT_KEY_ACTION_SET_NULL || fk->fk_on_update == XT_KEY_ACTION_SET_NULL) { + /* Check that all the columns can be set to NULL! */ + XTDDColumn *col; + + for (u_int j=0; j<fk->co_cols.size(); j++) { + if ((col = findColumn(fk->co_cols.itemAt(j)->cr_col_name))) { + if (!col->dc_null_ok) + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_COLUMN_IS_NOT_NULL, fk->fk_ref_tab_name, col->dc_name); + } + } + } + + // TODO: dont close table immediately so it can be possibly reused in this loop + XTTable *ref_tab; + + pushsr_(ref_tab, xt_heap_release, xt_use_table(self, fk->fk_ref_tab_name, FALSE, TRUE, NULL)); + if (ref_tab && !fk->checkReferencedTypes(ref_tab->tab_dic.dic_table)) + throw_(); + freer_(); + + /* Currently I allow foreign keys to be created on tables that do not yet exist! + pushsr_(tab, xt_heap_release, xt_use_table(self, fk->fk_ref_tab_name, FALSE FALSE)); + if ((dt = tab->tab_dic.dic_table)) + dt->checkForeignKeyReference(self, fk); + freer_(); // xt_heap_release(tab) + */ + } +} + +XTDDIndex *XTDDTable::findIndex(XTDDConstraint *co) +{ + XTDDIndex *ind; + + for (u_int i=0; i<dt_indexes.size(); i++) { + ind = dt_indexes.itemAt(i); + if (co->sameColumns(ind)) + return ind; + } + { + char buffer[XT_ERR_MSG_SIZE - 200]; + + co->getColumnList(buffer, XT_ERR_MSG_SIZE - 200); + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_NO_MATCHING_INDEX, buffer); + } + return NULL; +} + +XTDDIndex *XTDDTable::findReferenceIndex(XTDDForeignKey *fk) +{ + XTDDIndex *ind; + XTDDColumnRef *cr; + u_int i; + + for (i=0; i<dt_indexes.size(); i++) { + ind = dt_indexes.itemAt(i); + if (fk->sameReferenceColumns(ind)) + return ind; + } + + /* If the index does not exist, maybe the columns do not exist?! */ + for (i=0; i<fk->fk_ref_cols.size(); i++) { + cr = fk->fk_ref_cols.itemAt(i); + if (!findColumn(cr->cr_col_name)) { + xt_register_tabcolerr(XT_REG_CONTEXT, XT_ERR_COLUMN_NOT_FOUND, fk->fk_ref_tab_name, cr->cr_col_name); + return NULL; + } + } + + { + char buffer[XT_ERR_MSG_SIZE - 200]; + + fk->getReferenceList(buffer, XT_ERR_MSG_SIZE - 200); + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_NO_MATCHING_INDEX, buffer); + } + return NULL; +} + +bool XTDDTable::insertRow(XTOpenTablePtr ot, xtWord1 *rec_ptr) +{ + bool ok = true; + XTInfoBufferRec rec_buf; + + if (ot->ot_thread->st_ignore_fkeys) + return true; + + rec_buf.ib_free = FALSE; + if (!rec_ptr) { + if (!xt_tab_load_record(ot, ot->ot_curr_rec_id, &rec_buf)) + return false; + rec_ptr = rec_buf.ib_db.db_data; + + } + for (u_int i=0; i<dt_fkeys.size(); i++) { + if (!dt_fkeys.itemAt(i)->insertRow(NULL, rec_ptr, ot->ot_thread)) { + ok = false; + break; + } + } + xt_ib_free(NULL, &rec_buf); + return ok; +} + +bool XTDDTable::checkNoAction(XTOpenTablePtr ot, xtRecordID rec_id) +{ + XTDDTableRef *tr; + bool ok = true; + XTInfoBufferRec rec_buf; + xtWord1 *rec_ptr; + + if (ot->ot_thread->st_ignore_fkeys) + return true; + + rec_buf.ib_free = FALSE; + if (!xt_tab_load_record(ot, rec_id, &rec_buf)) + return false; + rec_ptr = rec_buf.ib_db.db_data; + + xt_slock_rwlock_ns(&dt_ref_lock); + tr = dt_trefs; + while (tr) { + if (!tr->checkReference(rec_ptr, ot->ot_thread)) { + ok = false; + break; + } + tr = tr->tr_next; + } + xt_unlock_rwlock_ns(&dt_ref_lock); + xt_ib_free(NULL, &rec_buf); + return ok; +} + +bool XTDDTable::deleteRow(XTOpenTablePtr ot, xtWord1 *rec_ptr) +{ + XTDDTableRef *tr; + bool ok = true; + XTInfoBufferRec rec_buf; + + if (ot->ot_thread->st_ignore_fkeys) + return true; + + rec_buf.ib_free = FALSE; + if (!rec_ptr) { + if (!xt_tab_load_record(ot, ot->ot_curr_rec_id, &rec_buf)) + return false; + rec_ptr = rec_buf.ib_db.db_data; + + } + xt_slock_rwlock_ns(&dt_ref_lock); + tr = dt_trefs; + while (tr) { + if (!tr->modifyRow(ot, rec_ptr, NULL, ot->ot_thread)) { + ok = false; + break; + } + tr = tr->tr_next; + } + xt_unlock_rwlock_ns(&dt_ref_lock); + xt_ib_free(NULL, &rec_buf); + return ok; +} + +void XTDDTable::deleteAllRows(XTThreadPtr self) +{ + XTDDTableRef *tr; + + xt_slock_rwlock(self, &dt_ref_lock); + pushr_(xt_unlock_rwlock, &dt_ref_lock); + + tr = dt_trefs; + while (tr) { + tr->deleteAllRows(self); + tr = tr->tr_next; + } + + freer_(); // xt_unlock_rwlock(&dt_ref_lock); +} + +bool XTDDTable::updateRow(XTOpenTablePtr ot, xtWord1 *before, xtWord1 *after) +{ + XTDDTableRef *tr; + bool ok; + XTInfoBufferRec before_buf; + + ASSERT_NS(after); + + if (ot->ot_thread->st_ignore_fkeys) + return true; + + /* If before is NULL then this is a cascaded + * update. In this case there is no need to check + * if the column has a parent!! + */ + if (before) { + if (dt_fkeys.size() > 0) { + for (u_int i=0; i<dt_fkeys.size(); i++) { + if (!dt_fkeys.itemAt(i)->insertRow(before, after, ot->ot_thread)) + return false; + } + } + } + + ok = true; + before_buf.ib_free = FALSE; + + xt_slock_rwlock_ns(&dt_ref_lock); + if ((tr = dt_trefs)) { + if (!before) { + if (!xt_tab_load_record(ot, ot->ot_curr_rec_id, &before_buf)) + return false; + before = before_buf.ib_db.db_data; + } + + while (tr) { + if (!tr->modifyRow(ot, before, after, ot->ot_thread)) { + ok = false; + break; + } + tr = tr->tr_next; + } + } + xt_unlock_rwlock_ns(&dt_ref_lock); + + xt_ib_free(NULL, &before_buf); + return ok; +} + +xtBool XTDDTable::checkCanDrop() +{ + /* no refs or references only itself */ + return (dt_trefs == NULL) || + (dt_trefs->tr_next == NULL) && (dt_trefs->tr_fkey->co_table == this); +} diff --git a/storage/pbxt/src/datadic_xt.h b/storage/pbxt/src/datadic_xt.h new file mode 100644 index 00000000000..825914b60f3 --- /dev/null +++ b/storage/pbxt/src/datadic_xt.h @@ -0,0 +1,295 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2004-01-03 Paul McCullagh + * + * H&G2JCtL + * + * Implementation of the PBXT internal data dictionary. + */ + +#ifndef __datadic_xt_h__ +#define __datadic_xt_h__ + +#include <stddef.h> +#include <limits.h> + +#include "ccutils_xt.h" +#include "util_xt.h" + +struct XTDatabase; +struct XTTable; +struct XTIndex; +struct XTOpenTable; +struct XTIndex; + +/* Constraint types: */ +#define XT_DD_UNKNOWN ((u_int) -1) +#define XT_DD_INDEX 0 +#define XT_DD_INDEX_UNIQUE 1 +#define XT_DD_KEY_PRIMARY 2 +#define XT_DD_KEY_FOREIGN 3 + +#define XT_KEY_ACTION_DEFAULT 0 +#define XT_KEY_ACTION_RESTRICT 1 +#define XT_KEY_ACTION_CASCADE 2 +#define XT_KEY_ACTION_SET_NULL 3 +#define XT_KEY_ACTION_SET_DEFAULT 4 +#define XT_KEY_ACTION_NO_ACTION 5 /* Like RESTRICT, but check at end of statement. */ + +class XTDDEnumerableColumn; +class XTDDColumnFactory; + +class XTDDColumn : public XTObject { + +protected: + + XTDDColumn() : XTObject(), + dc_name(NULL), + dc_data_type(NULL), + dc_null_ok(true), + dc_auto_inc(false) { + } + +public: + char *dc_name; + char *dc_data_type; + bool dc_null_ok; + bool dc_auto_inc; + + virtual XTObject *factory(XTThreadPtr self) { + XTObject *new_obj; + + if (!(new_obj = new XTDDColumn())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return new_obj; + } + + virtual void init(XTThreadPtr self) { + XTObject::init(self); + } + virtual void init(XTThreadPtr self, XTObject *obj); + virtual void finalize(XTThreadPtr self); + virtual void loadString(XTThreadPtr self, XTStringBufferPtr sb); + + virtual XTDDEnumerableColumn *castToEnumerable() { + return NULL; + } + + friend class XTDDColumnFactory; +}; + +/* + * subclass for ENUMs and SETs + */ +class XTDDEnumerableColumn : public XTDDColumn { + +protected: + XTDDEnumerableColumn() : XTDDColumn(), + enum_size(0), is_enum(0) { + } + +public: + int enum_size; /* number of elements in the ENUM or SET */ + xtBool is_enum; /* TRUE if this is ENUM, FALSE if SET */ + + virtual XTObject *factory(XTThreadPtr self) { + XTObject *new_obj; + + if (!(new_obj = new XTDDEnumerableColumn())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return new_obj; + } + + virtual XTDDEnumerableColumn *castToEnumerable() { + return this; + } + + friend class XTDDColumnFactory; +}; + +class XTDDColumnRef : public XTObject { + public: + char *cr_col_name; + + XTDDColumnRef() : XTObject(), cr_col_name(NULL) { } + + virtual XTObject *factory(XTThreadPtr self) { + XTObject *new_obj; + + if (!(new_obj = new XTDDColumnRef())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return new_obj; + } + + virtual void init(XTThreadPtr self, XTObject *obj); + virtual void finalize(XTThreadPtr self); +}; + +class XTDDConstraint : public XTObject { + public: + class XTDDTable *co_table; /* The table of this constraint (non-referenced). */ + u_int co_type; + char *co_name; + char *co_ind_name; + XTList<XTDDColumnRef> co_cols; + + XTDDConstraint(u_int t) : XTObject(), + co_table(NULL), + co_type(t), + co_name(NULL), + co_ind_name(NULL) { + } + + virtual void init(XTThreadPtr self, XTObject *obj); + virtual void finalize(XTThreadPtr self) { + if (co_name) + xt_free(self, co_name); + if (co_ind_name) + xt_free(self, co_ind_name); + co_cols.deleteAll(self); + XTObject::finalize(self); + } + virtual void loadString(XTThreadPtr self, XTStringBufferPtr sb); + virtual void alterColumnName(XTThreadPtr self, char *from_name, char *to_name); + void getColumnList(char *buffer, size_t size); + bool sameColumns(XTDDConstraint *co); + bool attachColumns(); +}; + +class XTDDTableRef : public XTObject { + public: + class XTDDTableRef *tr_next; /* The next reference in the list. */ + class XTDDForeignKey *tr_fkey; /* The foreign key that references this table (if not-NULL). */ + + XTDDTableRef() : XTObject(), tr_next(NULL), tr_fkey(NULL) { } + virtual void finalize(XTThreadPtr self); + bool modifyRow(struct XTOpenTable *tab, xtWord1 *before, xtWord1 *after, XTThreadPtr thread); + bool checkReference(xtWord1 *before, XTThreadPtr thread); + void deleteAllRows(XTThreadPtr self); +}; + +class XTDDIndex : public XTDDConstraint { + public: + u_int in_index; + + XTDDIndex(u_int type) : XTDDConstraint(type), in_index((u_int) -1) { } + + virtual XTObject *factory(XTThreadPtr self) { + XTObject *new_obj; + + if (!(new_obj = new XTDDIndex(XT_DD_UNKNOWN))) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return new_obj; + } + + virtual void init(XTThreadPtr self, XTObject *obj); + struct XTIndex *getIndexPtr(); +}; + +/* + * A foreign key is based on a local index. + */ +class XTDDForeignKey : public XTDDIndex { + public: + XTPathStrPtr fk_ref_tab_name; + XTDDTable *fk_ref_table; + u_int fk_ref_index; /* The index on which this foreign key references. */ + XTList<XTDDColumnRef> fk_ref_cols; + int fk_on_delete; + int fk_on_update; + + XTDDForeignKey() : XTDDIndex(XT_DD_KEY_FOREIGN), + fk_ref_tab_name(NULL), + fk_ref_table(NULL), + fk_ref_index(UINT_MAX), + fk_on_delete(0), + fk_on_update(0) { + } + + virtual XTObject *factory(XTThreadPtr self) { + XTObject *new_obj; + + if (!(new_obj = new XTDDForeignKey())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return new_obj; + } + + virtual void init(XTThreadPtr self, XTObject *obj); + virtual void finalize(XTThreadPtr self); + virtual void loadString(XTThreadPtr self, XTStringBufferPtr sb); + void getReferenceList(char *buffer, size_t size); + struct XTIndex *getReferenceIndexPtr(); + bool sameReferenceColumns(XTDDConstraint *co); + bool checkReferencedTypes(XTDDTable *dt); + void removeReference(XTThreadPtr self); + bool insertRow(xtWord1 *before, xtWord1 *after, XTThreadPtr thread); + bool updateRow(xtWord1 *before, xtWord1 *after, XTThreadPtr thread); + + static const char *actionTypeToString(int action); +}; + +class XTDDTable : public XTObject { + private: + + public: + struct XTTable *dt_table; + + XTList<XTDDColumn> dt_cols; + XTList<XTDDIndex> dt_indexes; + + xt_rwlock_type dt_ref_lock; /* The lock for adding and using references. */ + XTList<XTDDForeignKey> dt_fkeys; /* The foreign keys on this table. */ + XTDDTableRef *dt_trefs; /* A list of tables that reference this table. */ + + virtual XTObject *factory(XTThreadPtr self) { + XTObject *new_obj; + + if (!(new_obj = new XTDDTable())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return new_obj; + } + + virtual void init(XTThreadPtr self); + virtual void init(XTThreadPtr self, XTObject *obj); + virtual void finalize(XTThreadPtr self); + + XTDDColumn *findColumn(char *name); + void loadString(XTThreadPtr self, XTStringBufferPtr sb); + void loadForeignKeyString(XTThreadPtr self, XTStringBufferPtr sb); + void checkForeignKeyReference(XTThreadPtr self, XTDDForeignKey *fk); + void attachReferences(XTThreadPtr self, struct XTDatabase *db); + void attachReference(XTThreadPtr self, XTDDForeignKey *fk); + void alterColumnName(XTThreadPtr self, char *from_name, char *to_name); + void attachReference(XTThreadPtr self, XTDDTable *dt); + void removeReferences(XTThreadPtr self); + void removeReference(XTThreadPtr self, XTDDForeignKey *fk); + void checkForeignKeys(XTThreadPtr self, bool temp_table); + XTDDIndex *findIndex(XTDDConstraint *co); + XTDDIndex *findReferenceIndex(XTDDForeignKey *fk); + bool insertRow(struct XTOpenTable *rec_ot, xtWord1 *buffer); + bool checkNoAction(struct XTOpenTable *ot, xtRecordID rec_id); + xtBool checkCanDrop(); + bool deleteRow(struct XTOpenTable *rec_ot, xtWord1 *buffer); + void deleteAllRows(XTThreadPtr self); + bool updateRow(struct XTOpenTable *rec_ot, xtWord1 *before, xtWord1 *after); +}; + +XTDDTable *xt_ri_create_table(XTThreadPtr self, bool convert, XTPathStrPtr tab_path, char *sql, XTDDTable *my_tab); + +#endif diff --git a/storage/pbxt/src/datalog_xt.cc b/storage/pbxt/src/datalog_xt.cc new file mode 100644 index 00000000000..dc9423e7eac --- /dev/null +++ b/storage/pbxt/src/datalog_xt.cc @@ -0,0 +1,2052 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-24 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <stdio.h> +#ifndef XT_WIN +#include <unistd.h> +#include <signal.h> +#endif +#include <stdlib.h> + +#ifndef DRIZZLED +#include "mysql_priv.h" +#endif + +#include "ha_pbxt.h" + +#include "filesys_xt.h" +#include "database_xt.h" +#include "memory_xt.h" +#include "strutil_xt.h" +#include "sortedlist_xt.h" +#include "util_xt.h" +#include "heap_xt.h" +#include "table_xt.h" +#include "trace_xt.h" +#include "myxt_xt.h" + +static void dl_wake_co_thread(XTDatabaseHPtr db); + +/* + * -------------------------------------------------------------------------------- + * SEQUENTIAL READING + */ + +xtBool XTDataSeqRead::sl_seq_init(struct XTDatabase *db, size_t buffer_size) +{ + sl_db = db; + sl_buffer_size = buffer_size; + + sl_log_file = NULL; + sl_log_eof = 0; + + sl_buf_log_offset = 0; + sl_buffer_len = 0; + sl_buffer = (xtWord1 *) xt_malloc_ns(buffer_size); + + sl_rec_log_id = 0; + sl_rec_log_offset = 0; + sl_record_len = 0; + + return sl_buffer != NULL; +} + +void XTDataSeqRead::sl_seq_exit() +{ + if (sl_log_file) { + xt_close_file_ns(sl_log_file); + sl_log_file = NULL; + } + if (sl_buffer) { + xt_free_ns(sl_buffer); + sl_buffer = NULL; + } +} + +XTOpenFilePtr XTDataSeqRead::sl_seq_open_file() +{ + return sl_log_file; +} + +void XTDataSeqRead::sl_seq_pos(xtLogID *log_id, xtLogOffset *log_offset) +{ + *log_id = sl_rec_log_id; + *log_offset = sl_rec_log_offset; +} + +xtBool XTDataSeqRead::sl_seq_start(xtLogID log_id, xtLogOffset log_offset, xtBool missing_ok) +{ + if (sl_rec_log_id != log_id) { + if (sl_log_file) { + xt_close_file_ns(sl_log_file); + sl_log_file = NULL; + } + + sl_rec_log_id = log_id; + sl_buf_log_offset = sl_rec_log_offset; + sl_buffer_len = 0; + + if (!sl_db->db_datalogs.dlc_open_log(&sl_log_file, log_id, missing_ok ? XT_FS_MISSING_OK : XT_FS_DEFAULT)) + return FAILED; + if (sl_log_file) + sl_log_eof = xt_seek_eof_file(NULL, sl_log_file); + } + sl_rec_log_offset = log_offset; + sl_record_len = 0; + return OK; +} + +xtBool XTDataSeqRead::sl_rnd_read(xtLogOffset log_offset, size_t size, xtWord1 *buffer, size_t *data_read, struct XTThread *thread) +{ + if (!sl_log_file) { + *data_read = 0; + return OK; + } + return xt_pread_file(sl_log_file, log_offset, size, 0, buffer, data_read, &thread->st_statistics.st_data, thread); +} + +/* + * Unlike the transaction log sequential reader, this function only returns + * the header of a record. + */ +xtBool XTDataSeqRead::sl_seq_next(XTXactLogBufferDPtr *ret_entry, xtBool verify, struct XTThread *thread) +{ + XTXactLogBufferDPtr record; + size_t tfer; + size_t len = 0; + size_t rec_offset; + size_t max_rec_len; + xtBool reread_from_buffer; + xtWord4 size; + + /* Go to the next record (xseq_record_len must be initialized + * to 0 for this to work. + */ + sl_rec_log_offset += sl_record_len; + sl_record_len = 0; + + if (sl_rec_log_offset < sl_buf_log_offset || + sl_rec_log_offset >= sl_buf_log_offset + (xtLogOffset) sl_buffer_len) { + /* The current position is nowhere near the buffer, read data into the + * buffer: + */ + tfer = sl_buffer_size; + if (!sl_rnd_read(sl_rec_log_offset, tfer, sl_buffer, &tfer, thread)) + return FAILED; + sl_buf_log_offset = sl_rec_log_offset; + sl_buffer_len = tfer; + + /* Should we go to the next log? */ + if (!tfer) + goto return_empty; + } + + /* The start of the record is in the buffer: */ + read_from_buffer: + rec_offset = (size_t) (sl_rec_log_offset - sl_buf_log_offset); + max_rec_len = sl_buffer_len - rec_offset; + reread_from_buffer = FALSE; + size = 0; + + /* Check the type of record: */ + record = (XTXactLogBufferDPtr) (sl_buffer + rec_offset); + switch (record->xl.xl_status_1) { + case XT_LOG_ENT_HEADER: + if (offsetof(XTXactLogHeaderDRec, xh_size_4) + 4 > max_rec_len) { + reread_from_buffer = TRUE; + goto read_more; + } + len = XT_GET_DISK_4(record->xh.xh_size_4); + if (len > max_rec_len) { + reread_from_buffer = TRUE; + goto read_more; + } + if (verify) { + if (record->xh.xh_checksum_1 != XT_CHECKSUM_1(sl_rec_log_id)) + goto return_empty; + if (XT_LOG_HEAD_MAGIC(record, len) != XT_LOG_FILE_MAGIC) + goto return_empty; + if (len > offsetof(XTXactLogHeaderDRec, xh_log_id_4) + 4) { + if (XT_GET_DISK_4(record->xh.xh_log_id_4) != sl_rec_log_id) + goto return_empty; + } + } + break; + case XT_LOG_ENT_EXT_REC_OK: + case XT_LOG_ENT_EXT_REC_DEL: + len = offsetof(XTactExtRecEntryDRec, er_data); + if (len > max_rec_len) { + reread_from_buffer = TRUE; + goto read_more; + } + size = XT_GET_DISK_4(record->er.er_data_size_4); + if (verify) { + if (sl_rec_log_offset + (xtLogOffset) offsetof(XTactExtRecEntryDRec, er_data) + size > sl_log_eof) + goto return_empty; + } + break; + default: + ASSERT_NS(FALSE); + goto return_empty; + } + + if (len <= max_rec_len) { + /* The record is completely in the buffer: */ + sl_record_len = len+size; + *ret_entry = record; + return OK; + } + + read_more: + /* The record is partially in the buffer. */ + memmove(sl_buffer, sl_buffer + rec_offset, max_rec_len); + sl_buf_log_offset += rec_offset; + sl_buffer_len = max_rec_len; + + /* Read the rest, as far as possible: */ + tfer = sl_buffer_size - max_rec_len; + if (!sl_rnd_read(sl_buf_log_offset + max_rec_len, tfer, sl_buffer + max_rec_len, &tfer, thread)) + return FAILED; + sl_buffer_len += tfer; + + if (sl_buffer_len < len) + /* A partial record is in the log, must be the end of the log: */ + goto return_empty; + + if (reread_from_buffer) + goto read_from_buffer; + + /* The record is not completely in the buffer: */ + sl_record_len = len; + *ret_entry = (XTXactLogBufferDPtr) sl_buffer; + return OK; + + return_empty: + *ret_entry = NULL; + return OK; +} + +void XTDataSeqRead::sl_seq_skip(size_t size) +{ + sl_record_len += size; +} + +void XTDataSeqRead::sl_seq_skip_to(off_t log_offset) +{ + if (log_offset >= sl_rec_log_offset) + sl_record_len = (size_t) (log_offset - sl_rec_log_offset); +} + +/* + * -------------------------------------------------------------------------------- + * STATIC UTILITIES + */ + +static xtBool dl_create_log_header(XTDataLogFilePtr data_log, XTOpenFilePtr of, XTThreadPtr thread) +{ + XTXactLogHeaderDRec header; + + /* The header was not completely written, so write a new one: */ + memset(&header, 0, sizeof(XTXactLogHeaderDRec)); + header.xh_status_1 = XT_LOG_ENT_HEADER; + header.xh_checksum_1 = XT_CHECKSUM_1(data_log->dlf_log_id); + XT_SET_DISK_4(header.xh_size_4, sizeof(XTXactLogHeaderDRec)); + XT_SET_DISK_8(header.xh_free_space_8, 0); + XT_SET_DISK_8(header.xh_file_len_8, sizeof(XTXactLogHeaderDRec)); + XT_SET_DISK_4(header.xh_log_id_4, data_log->dlf_log_id); + XT_SET_DISK_2(header.xh_version_2, XT_LOG_VERSION_NO); + XT_SET_DISK_4(header.xh_magic_4, XT_LOG_FILE_MAGIC); + if (!xt_pwrite_file(of, 0, sizeof(XTXactLogHeaderDRec), &header, &thread->st_statistics.st_data, thread)) + return FAILED; + if (!xt_flush_file(of, &thread->st_statistics.st_data, thread)) + return FAILED; + return OK; +} + +static xtBool dl_write_log_header(XTDataLogFilePtr data_log, XTOpenFilePtr of, xtBool flush, XTThreadPtr thread) +{ + XTXactLogHeaderDRec header; + + /* The header was not completely written, so write a new one: */ + XT_SET_DISK_8(header.xh_free_space_8, data_log->dlf_garbage_count); + XT_SET_DISK_8(header.xh_file_len_8, data_log->dlf_log_eof); + XT_SET_DISK_8(header.xh_comp_pos_8, data_log->dlf_start_offset); + + if (!xt_pwrite_file(of, offsetof(XTXactLogHeaderDRec, xh_free_space_8), 24, (xtWord1 *) &header.xh_free_space_8, &thread->st_statistics.st_data, thread)) + return FAILED; + if (flush && !xt_flush_file(of, &thread->st_statistics.st_data, thread)) + return FAILED; + return OK; +} + +static void dl_free_seq_read(XTThreadPtr self __attribute__((unused)), XTDataSeqReadPtr seq_read) +{ + seq_read->sl_seq_exit(); +} + +static void dl_recover_log(XTThreadPtr self, XTDatabaseHPtr db, XTDataLogFilePtr data_log) +{ + XTDataSeqReadRec seq_read; + XTXactLogBufferDPtr record; + + if (!seq_read.sl_seq_init(db, xt_db_log_buffer_size)) + xt_throw(self); + pushr_(dl_free_seq_read, &seq_read); + + seq_read.sl_seq_start(data_log->dlf_log_id, 0, FALSE); + + for (;;) { + if (!seq_read.sl_seq_next(&record, TRUE, self)) + xt_throw(self); + if (!record) + break; + switch (record->xh.xh_status_1) { + case XT_LOG_ENT_HEADER: + data_log->dlf_garbage_count = XT_GET_DISK_8(record->xh.xh_free_space_8); + data_log->dlf_start_offset = XT_GET_DISK_8(record->xh.xh_comp_pos_8); + seq_read.sl_seq_skip_to((off_t) XT_GET_DISK_8(record->xh.xh_file_len_8)); + break; + } + } + + if (!(data_log->dlf_log_eof = seq_read.sl_rec_log_offset)) { + data_log->dlf_log_eof = sizeof(XTXactLogHeaderDRec); + if (!dl_create_log_header(data_log, seq_read.sl_log_file, self)) + xt_throw(self); + } + if (!dl_write_log_header(data_log, seq_read.sl_log_file, TRUE, self)) + xt_throw(self); + + freer_(); // dl_free_seq_read(&seq_read) +} + +/* + * -------------------------------------------------------------------------------- + * D A T A L O G C AC H E + */ + +void XTDataLogCache::dls_remove_log(XTDataLogFilePtr data_log) +{ + xtLogID log_id = data_log->dlf_log_id; + + switch (data_log->dlf_state) { + case XT_DL_HAS_SPACE: + xt_sl_delete(NULL, dlc_has_space, &log_id); + break; + case XT_DL_TO_COMPACT: + xt_sl_delete(NULL, dlc_to_compact, &log_id); + break; + case XT_DL_TO_DELETE: + xt_sl_delete(NULL, dlc_to_delete, &log_id); + break; + case XT_DL_DELETED: + xt_sl_delete(NULL, dlc_deleted, &log_id); + break; + } +} + +int XTDataLogCache::dls_get_log_state(XTDataLogFilePtr data_log) +{ + if (data_log->dlf_to_much_garbage()) + return XT_DL_TO_COMPACT; + if (data_log->dlf_space_avaliable() > 0) + return XT_DL_HAS_SPACE; + return XT_DL_READ_ONLY; +} + +xtBool XTDataLogCache::dls_set_log_state(XTDataLogFilePtr data_log, int state) +{ + xtLogID log_id = data_log->dlf_log_id; + + xt_lock_mutex_ns(&dlc_lock); + if (state == XT_DL_MAY_COMPACT) { + if (data_log->dlf_state != XT_DL_UNKNOWN && + data_log->dlf_state != XT_DL_HAS_SPACE && + data_log->dlf_state != XT_DL_READ_ONLY) + goto ok; + state = XT_DL_TO_COMPACT; + } + if (state == XT_DL_UNKNOWN) + state = dls_get_log_state(data_log); + switch (state) { + case XT_DL_HAS_SPACE: + if (data_log->dlf_state != XT_DL_HAS_SPACE) { + dls_remove_log(data_log); + if (!xt_sl_insert(NULL, dlc_has_space, &log_id, &log_id)) + goto failed; + } + break; + case XT_DL_TO_COMPACT: +#ifdef DEBUG_LOG_DELETE + printf("-- set to compact: %d\n", (int) log_id); +#endif + if (data_log->dlf_state != XT_DL_TO_COMPACT) { + dls_remove_log(data_log); + if (!xt_sl_insert(NULL, dlc_to_compact, &log_id, &log_id)) + goto failed; + } + dl_wake_co_thread(dlc_db); + break; + case XT_DL_COMPACTED: +#ifdef DEBUG_LOG_DELETE + printf("-- set compacted: %d\n", (int) log_id); +#endif + if (data_log->dlf_state != state) + dls_remove_log(data_log); + break; + case XT_DL_TO_DELETE: +#ifdef DEBUG_LOG_DELETE + printf("-- set to delete log: %d\n", (int) log_id); +#endif + if (data_log->dlf_state != XT_DL_TO_DELETE) { + dls_remove_log(data_log); + if (!xt_sl_insert(NULL, dlc_to_delete, &log_id, &log_id)) + goto failed; + } + break; + case XT_DL_DELETED: +#ifdef DEBUG_LOG_DELETE + printf("-- set DELETED log: %d\n", (int) log_id); +#endif + if (data_log->dlf_state != XT_DL_DELETED) { + dls_remove_log(data_log); + if (!xt_sl_insert(NULL, dlc_deleted, &log_id, &log_id)) + goto failed; + } + break; + default: + if (data_log->dlf_state != state) + dls_remove_log(data_log); + break; + } + data_log->dlf_state = state; + + ok: + xt_unlock_mutex_ns(&dlc_lock); + return OK; + + failed: + xt_unlock_mutex_ns(&dlc_lock); + return FAILED; +} + +static int dl_cmp_log_id(XTThreadPtr XT_UNUSED(self), register const void XT_UNUSED(*thunk), register const void *a, register const void *b) +{ + xtLogID log_id_a = *((xtLogID *) a); + xtLogID log_id_b = *((xtLogID *) b); + + if (log_id_a == log_id_b) + return 0; + if (log_id_a < log_id_b) + return -1; + return 1; +} + +void XTDataLogCache::dlc_init(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTOpenDirPtr od; + char log_dir[PATH_MAX]; + char *file; + xtLogID log_id; + XTDataLogFilePtr data_log= NULL; + + memset(this, 0, sizeof(XTDataLogCacheRec)); + dlc_db = db; + try_(a) { + xt_init_mutex_with_autoname(self, &dlc_lock); + xt_init_cond(self, &dlc_cond); + for (u_int i=0; i<XT_DL_NO_OF_SEGMENTS; i++) { + xt_init_mutex_with_autoname(self, &dlc_segment[i].dls_lock); + xt_init_cond(self, &dlc_segment[i].dls_cond); + } + dlc_has_space = xt_new_sortedlist(self, sizeof(xtLogID), 20, 10, dl_cmp_log_id, NULL, NULL, FALSE, FALSE); + dlc_to_compact = xt_new_sortedlist(self, sizeof(xtLogID), 20, 10, dl_cmp_log_id, NULL, NULL, FALSE, FALSE); + dlc_to_delete = xt_new_sortedlist(self, sizeof(xtLogID), 20, 10, dl_cmp_log_id, NULL, NULL, FALSE, FALSE); + dlc_deleted = xt_new_sortedlist(self, sizeof(xtLogID), 20, 10, dl_cmp_log_id, NULL, NULL, FALSE, FALSE); + xt_init_mutex_with_autoname(self, &dlc_mru_lock); + xt_init_mutex_with_autoname(self, &dlc_head_lock); + + xt_strcpy(PATH_MAX, log_dir, dlc_db->db_main_path); + xt_add_data_dir(PATH_MAX, log_dir); + if (xt_fs_exists(log_dir)) { + pushsr_(od, xt_dir_close, xt_dir_open(self, log_dir, NULL)); + while (xt_dir_next(self, od)) { + file = xt_dir_name(self, od); + if (xt_ends_with(file, ".xt")) { + if ((log_id = (xtLogID) xt_file_name_to_id(file))) { + if (!dlc_get_data_log(&data_log, log_id, TRUE, NULL)) + xt_throw(self); + dl_recover_log(self, db, data_log); + if (!dls_set_log_state(data_log, XT_DL_UNKNOWN)) + xt_throw(self); + } + } + } + freer_(); + } + } + catch_(a) { + dlc_exit(self); + xt_throw(self); + } + cont_(a); +} + +void XTDataLogCache::dlc_exit(XTThreadPtr self) +{ + XTDataLogFilePtr data_log, tmp_data_log; + XTOpenLogFilePtr open_log, tmp_open_log; + + if (dlc_has_space) { + xt_free_sortedlist(self, dlc_has_space); + dlc_has_space = NULL; + } + if (dlc_to_compact) { + xt_free_sortedlist(self, dlc_to_compact); + dlc_to_compact = NULL; + } + if (dlc_to_delete) { + xt_free_sortedlist(self, dlc_to_delete); + dlc_to_delete = NULL; + } + if (dlc_deleted) { + xt_free_sortedlist(self, dlc_deleted); + dlc_deleted = NULL; + } + for (u_int i=0; i<XT_DL_NO_OF_SEGMENTS; i++) { + for (u_int j=0; j<XT_DL_SEG_HASH_TABLE_SIZE; j++) { + data_log = dlc_segment[i].dls_hash_table[j]; + while (data_log) { + if (data_log->dlf_log_file) { + xt_close_file_ns(data_log->dlf_log_file); + data_log->dlf_log_file = NULL; + } + + open_log = data_log->dlf_free_list; + while (open_log) { + if (open_log->odl_log_file) + xt_close_file(self, open_log->odl_log_file); + tmp_open_log = open_log; + open_log = open_log->odl_next_free; + xt_free(self, tmp_open_log); + } + tmp_data_log = data_log; + data_log = data_log->dlf_next_hash; + + xt_free(self, tmp_data_log); + } + } + xt_free_mutex(&dlc_segment[i].dls_lock); + xt_free_cond(&dlc_segment[i].dls_cond); + } + xt_free_mutex(&dlc_head_lock); + xt_free_mutex(&dlc_mru_lock); + xt_free_mutex(&dlc_lock); + xt_free_cond(&dlc_cond); +} + +void XTDataLogCache::dlc_name(size_t size, char *path, xtLogID log_id) +{ + char name[50]; + + sprintf(name, "dlog-%lu.xt", (u_long) log_id); + xt_strcpy(size, path, dlc_db->db_main_path); + xt_add_data_dir(size, path); + xt_add_dir_char(size, path); + xt_strcat(size, path, name); +} + +xtBool XTDataLogCache::dlc_open_log(XTOpenFilePtr *fh, xtLogID log_id, int mode) +{ + char log_path[PATH_MAX]; + + dlc_name(PATH_MAX, log_path, log_id); + return xt_open_file_ns(fh, log_path, mode); +} + +xtBool XTDataLogCache::dlc_unlock_log(XTDataLogFilePtr data_log) +{ + if (data_log->dlf_log_file) { + xt_close_file_ns(data_log->dlf_log_file); + data_log->dlf_log_file = NULL; + } + + return dls_set_log_state(data_log, XT_DL_UNKNOWN); +} + +XTDataLogFilePtr XTDataLogCache::dlc_get_log_for_writing(off_t space_required, struct XTThread *thread) +{ + xtLogID log_id, *log_id_ptr = NULL; + size_t size; + size_t idx; + XTDataLogFilePtr data_log = NULL; + + xt_lock_mutex_ns(&dlc_lock); + + /* Look for an existing log with enough space: */ + size = xt_sl_get_size(dlc_has_space); + for (idx=0; idx<size; idx++) { + log_id_ptr = (xtLogID *) xt_sl_item_at(dlc_has_space, idx); + if (!dlc_get_data_log(&data_log, *log_id_ptr, FALSE, NULL)) + goto failed; + if (data_log) { + if (data_log->dlf_space_avaliable() >= space_required) + break; + data_log = NULL; + } + else { + ASSERT_NS(FALSE); + xt_sl_delete_item_at(NULL, dlc_has_space, idx); + idx--; + size--; + } + } + + if (data_log) { + /* Found a log: */ + if (!dlc_open_log(&data_log->dlf_log_file, *log_id_ptr, XT_FS_DEFAULT)) + goto failed; + xt_sl_delete_item_at(NULL, dlc_has_space, idx); + } + else { + /* Create a new log: */ + log_id = dlc_next_log_id; + for (u_int i=0; i<XT_DL_MAX_LOG_ID; i++) { + log_id++; + if (log_id > XT_DL_MAX_LOG_ID) + log_id = 1; + if (!dlc_get_data_log(&data_log, log_id, FALSE, NULL)) + goto failed; + if (!data_log) + break; + } + dlc_next_log_id = log_id; + if (data_log) { + xt_register_ulxterr(XT_REG_CONTEXT, XT_ERR_LOG_MAX_EXCEEDED, (u_long) XT_DL_MAX_LOG_ID); + goto failed; + } + if (!dlc_get_data_log(&data_log, log_id, TRUE, NULL)) + goto failed; + if (!dlc_open_log(&data_log->dlf_log_file, log_id, XT_FS_CREATE | XT_FS_MAKE_PATH)) + goto failed; + data_log->dlf_log_eof = sizeof(XTXactLogHeaderDRec); + if (!dl_create_log_header(data_log, data_log->dlf_log_file, thread)) { + xt_close_file_ns(data_log->dlf_log_file); + goto failed; + } + /* By setting this late we ensure that the error + * will be repeated. + */ + dlc_next_log_id = log_id; + } + data_log->dlf_state = XT_DL_EXCLUSIVE; + + xt_unlock_mutex_ns(&dlc_lock); + return data_log; + + failed: + xt_unlock_mutex_ns(&dlc_lock); + return NULL; +} + +xtBool XTDataLogCache::dlc_get_data_log(XTDataLogFilePtr *lf, xtLogID log_id, xtBool create, XTDataLogSegPtr *ret_seg) +{ + register XTDataLogSegPtr seg; + register u_int hash_idx; + register XTDataLogFilePtr data_log; + + /* Which segment, and hash index: */ + seg = &dlc_segment[log_id & XT_DL_SEGMENT_MASK]; + hash_idx = (log_id >> XT_DL_SEGMENT_SHIFTS) % XT_DL_SEG_HASH_TABLE_SIZE; + + /* Lock the segment: */ + xt_lock_mutex_ns(&seg->dls_lock); + + /* Find the log file on the hash list: */ + data_log = seg->dls_hash_table[hash_idx]; + while (data_log) { + if (data_log->dlf_log_id == log_id) + break; + data_log = data_log->dlf_next_hash; + } + + if (!data_log && create) { + /* Create a new log file structure: */ + if (!(data_log = (XTDataLogFilePtr) xt_calloc_ns(sizeof(XTDataLogFileRec)))) + goto failed; + data_log->dlf_log_id = log_id; + data_log->dlf_next_hash = seg->dls_hash_table[hash_idx]; + seg->dls_hash_table[hash_idx] = data_log; + } + + if (ret_seg) { + /* This gives the caller the lock: */ + *ret_seg = seg; + *lf = data_log; + return OK; + } + + xt_unlock_mutex_ns(&seg->dls_lock); + *lf = data_log; + return OK; + + failed: + xt_unlock_mutex_ns(&seg->dls_lock); + return FAILED; +} + +/* + * If just_close is FALSE, then a log is being deleted. + * This means that that the log may still be in exclusive use by + * some thread. So we just close the log! + */ +xtBool XTDataLogCache::dlc_remove_data_log(xtLogID log_id, xtBool just_close) +{ + register XTDataLogSegPtr seg; + register u_int hash_idx; + register XTDataLogFilePtr data_log; + XTOpenLogFilePtr open_log, tmp_open_log; + + /* Which segment, and hash index: */ + seg = &dlc_segment[log_id & XT_DL_SEGMENT_MASK]; + hash_idx = (log_id >> XT_DL_SEGMENT_SHIFTS) % XT_DL_SEG_HASH_TABLE_SIZE; + + /* Lock the segment: */ + retry: + xt_lock_mutex_ns(&seg->dls_lock); + + /* Find the log file on the hash list: */ + data_log = seg->dls_hash_table[hash_idx]; + while (data_log) { + if (data_log->dlf_log_id == log_id) + break; + data_log = data_log->dlf_next_hash; + } + + if (data_log) { + xt_lock_mutex_ns(&dlc_mru_lock); + + open_log = data_log->dlf_free_list; + while (open_log) { + if (open_log->odl_log_file) + xt_close_file_ns(open_log->odl_log_file); + + /* Remove from MRU list: */ + if (dlc_lru_open_log == open_log) { + dlc_lru_open_log = open_log->odl_mr_used; + ASSERT_NS(!open_log->odl_lr_used); + } + else if (open_log->odl_lr_used) + open_log->odl_lr_used->odl_mr_used = open_log->odl_mr_used; + if (dlc_mru_open_log == open_log) { + dlc_mru_open_log = open_log->odl_lr_used; + ASSERT_NS(!open_log->odl_mr_used); + } + else if (open_log->odl_mr_used) + open_log->odl_mr_used->odl_lr_used = open_log->odl_lr_used; + + data_log->dlf_open_count--; + tmp_open_log = open_log; + open_log = open_log->odl_next_free; + xt_free_ns(tmp_open_log); + } + data_log->dlf_free_list = NULL; + + xt_unlock_mutex_ns(&dlc_mru_lock); + + if (data_log->dlf_open_count) { + if (!xt_timed_wait_cond_ns(&seg->dls_cond, &seg->dls_lock, 2000)) + goto failed; + xt_unlock_mutex_ns(&seg->dls_lock); + goto retry; + } + + /* Close the exclusive file if required: */ + if (data_log->dlf_log_file) { + xt_close_file_ns(data_log->dlf_log_file); + data_log->dlf_log_file = NULL; + } + + if (!just_close) { + /* Remove the log from the hash list: */ + XTDataLogFilePtr ptr, pptr = NULL; + + ptr = seg->dls_hash_table[hash_idx]; + while (ptr) { + if (ptr == data_log) + break; + pptr = ptr; + ptr = ptr->dlf_next_hash; + } + + if (ptr == data_log) { + if (pptr) + pptr->dlf_next_hash = ptr->dlf_next_hash; + else + seg->dls_hash_table[hash_idx] = ptr->dlf_next_hash; + } + + xt_free_ns(data_log); + } + } + + xt_unlock_mutex_ns(&seg->dls_lock); + return OK; + + failed: + xt_unlock_mutex_ns(&seg->dls_lock); + return FAILED; +} + +xtBool XTDataLogCache::dlc_get_open_log(XTOpenLogFilePtr *ol, xtLogID log_id) +{ + register XTDataLogSegPtr seg; + register u_int hash_idx; + register XTDataLogFilePtr data_log; + register XTOpenLogFilePtr open_log; + char path[PATH_MAX]; + + /* Which segment, and hash index: */ + seg = &dlc_segment[log_id & XT_DL_SEGMENT_MASK]; + hash_idx = (log_id >> XT_DL_SEGMENT_SHIFTS) % XT_DL_SEG_HASH_TABLE_SIZE; + + /* Lock the segment: */ + xt_lock_mutex_ns(&seg->dls_lock); + + /* Find the log file on the hash list: */ + data_log = seg->dls_hash_table[hash_idx]; + while (data_log) { + if (data_log->dlf_log_id == log_id) + break; + data_log = data_log->dlf_next_hash; + } + + if (!data_log) { + /* Create a new log file structure: */ + dlc_name(PATH_MAX, path, log_id); + if (!xt_fs_exists(path)) { + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_DATA_LOG_NOT_FOUND, path); + goto failed; + } + if (!(data_log = (XTDataLogFilePtr) xt_calloc_ns(sizeof(XTDataLogFileRec)))) + goto failed; + data_log->dlf_log_id = log_id; + data_log->dlf_next_hash = seg->dls_hash_table[hash_idx]; + seg->dls_hash_table[hash_idx] = data_log; + } + + if ((open_log = data_log->dlf_free_list)) { + /* Remove from the free list: */ + if ((data_log->dlf_free_list = open_log->odl_next_free)) + data_log->dlf_free_list->odl_prev_free = NULL; + + /* This file has been most recently used: */ + if (XT_TIME_DIFF(open_log->odl_ru_time, dlc_ru_now) > (XT_DL_LOG_POOL_SIZE >> 1)) { + /* Move to the front of the MRU list: */ + xt_lock_mutex_ns(&dlc_mru_lock); + + open_log->odl_ru_time = ++dlc_ru_now; + if (dlc_mru_open_log != open_log) { + /* Remove from the MRU list: */ + if (dlc_lru_open_log == open_log) { + dlc_lru_open_log = open_log->odl_mr_used; + ASSERT_NS(!open_log->odl_lr_used); + } + else if (open_log->odl_lr_used) + open_log->odl_lr_used->odl_mr_used = open_log->odl_mr_used; + if (open_log->odl_mr_used) + open_log->odl_mr_used->odl_lr_used = open_log->odl_lr_used; + + /* Make the file the most recently used: */ + if ((open_log->odl_lr_used = dlc_mru_open_log)) + dlc_mru_open_log->odl_mr_used = open_log; + open_log->odl_mr_used = NULL; + dlc_mru_open_log = open_log; + if (!dlc_lru_open_log) + dlc_lru_open_log = open_log; + } + xt_unlock_mutex_ns(&dlc_mru_lock); + } + } + else { + /* Create a new open file: */ + if (!(open_log = (XTOpenLogFilePtr) xt_calloc_ns(sizeof(XTOpenLogFileRec)))) + goto failed; + dlc_name(PATH_MAX, path, log_id); + if (!xt_open_file_ns(&open_log->odl_log_file, path, XT_FS_DEFAULT)) { + xt_free_ns(open_log); + goto failed; + } + open_log->olf_log_id = log_id; + open_log->odl_data_log = data_log; + data_log->dlf_open_count++; + + /* Make the new open file the most recently used: */ + xt_lock_mutex_ns(&dlc_mru_lock); + open_log->odl_ru_time = ++dlc_ru_now; + if ((open_log->odl_lr_used = dlc_mru_open_log)) + dlc_mru_open_log->odl_mr_used = open_log; + open_log->odl_mr_used = NULL; + dlc_mru_open_log = open_log; + if (!dlc_lru_open_log) + dlc_lru_open_log = open_log; + dlc_open_count++; + xt_unlock_mutex_ns(&dlc_mru_lock); + } + + open_log->odl_in_use = TRUE; + xt_unlock_mutex_ns(&seg->dls_lock); + *ol = open_log; + + if (dlc_open_count > XT_DL_LOG_POOL_SIZE) { + u_int target = XT_DL_LOG_POOL_SIZE / 4 * 3; + xtLogID free_log_id; + + /* Remove some open files: */ + while (dlc_open_count > target) { + XTOpenLogFilePtr to_free = dlc_lru_open_log; + + if (!to_free || to_free->odl_in_use) + break; + + /* Dirty read the file ID: */ + free_log_id = to_free->olf_log_id; + + seg = &dlc_segment[free_log_id & XT_DL_SEGMENT_MASK]; + + /* Lock the segment: */ + xt_lock_mutex_ns(&seg->dls_lock); + + /* Lock the MRU list: */ + xt_lock_mutex_ns(&dlc_mru_lock); + + /* Check if we have the same open file: */ + if (dlc_lru_open_log == to_free && !to_free->odl_in_use) { + data_log = to_free->odl_data_log; + + /* Remove from the MRU list: */ + dlc_lru_open_log = to_free->odl_mr_used; + ASSERT_NS(!to_free->odl_lr_used); + + if (dlc_mru_open_log == to_free) { + dlc_mru_open_log = to_free->odl_lr_used; + ASSERT_NS(!to_free->odl_mr_used); + } + else if (to_free->odl_mr_used) + to_free->odl_mr_used->odl_lr_used = to_free->odl_lr_used; + + /* Remove from the free list of the file: */ + if (data_log->dlf_free_list == to_free) { + data_log->dlf_free_list = to_free->odl_next_free; + ASSERT_NS(!to_free->odl_prev_free); + } + else if (to_free->odl_prev_free) + to_free->odl_prev_free->odl_next_free = to_free->odl_next_free; + if (to_free->odl_next_free) + to_free->odl_next_free->odl_prev_free = to_free->odl_prev_free; + ASSERT_NS(data_log->dlf_open_count > 0); + data_log->dlf_open_count--; + dlc_open_count--; + } + else + to_free = NULL; + + xt_unlock_mutex_ns(&dlc_mru_lock); + xt_unlock_mutex_ns(&seg->dls_lock); + + if (to_free) { + xt_close_file_ns(to_free->odl_log_file); + xt_free_ns(to_free); + } + } + } + + return OK; + + failed: + xt_unlock_mutex_ns(&seg->dls_lock); + return FAILED; +} + +void XTDataLogCache::dlc_release_open_log(XTOpenLogFilePtr open_log) +{ + register XTDataLogSegPtr seg; + register XTDataLogFilePtr data_log = open_log->odl_data_log; + + /* Which segment, and hash index: */ + seg = &dlc_segment[open_log->olf_log_id & XT_DL_SEGMENT_MASK]; + + xt_lock_mutex_ns(&seg->dls_lock); + open_log->odl_next_free = data_log->dlf_free_list; + open_log->odl_prev_free = NULL; + if (data_log->dlf_free_list) + data_log->dlf_free_list->odl_prev_free = open_log; + data_log->dlf_free_list = open_log; + open_log->odl_in_use = FALSE; + + /* Wakeup any exclusive lockers: */ + if (!xt_broadcast_cond_ns(&seg->dls_cond)) + xt_log_and_clear_exception_ns(); + + xt_unlock_mutex_ns(&seg->dls_lock); +} + +/* + * -------------------------------------------------------------------------------- + * D A T A L O G F I L E + */ + +off_t XTDataLogFile::dlf_space_avaliable() +{ + if (dlf_log_eof < xt_db_data_log_threshold) + return xt_db_data_log_threshold - dlf_log_eof; + return 0; +} + +xtBool XTDataLogFile::dlf_to_much_garbage() +{ + if (!dlf_log_eof) + return FALSE; + return dlf_garbage_count * 100 / dlf_log_eof >= xt_db_garbage_threshold; +} + +/* + * -------------------------------------------------------------------------------- + * D A T A L O G B U F F E R + */ + +void XTDataLogBuffer::dlb_init(XTDatabaseHPtr db, size_t buffer_size) +{ + ASSERT_NS(!dlb_db); + ASSERT_NS(!dlb_buffer_size); + ASSERT_NS(!dlb_data_log); + ASSERT_NS(!dlb_log_buffer); + dlb_db = db; + dlb_buffer_size = buffer_size; +} + +void XTDataLogBuffer::dlb_exit(XTThreadPtr self) +{ + dlb_close_log(self); + if (dlb_log_buffer) { + xt_free(self, dlb_log_buffer); + dlb_log_buffer = NULL; + } + dlb_db = NULL; + dlb_buffer_offset = 0; + dlb_buffer_size = 0; + dlb_buffer_len = 0; + dlb_flush_required = FALSE; +#ifdef DEBUG + dlb_max_write_offset = 0; +#endif +} + +xtBool XTDataLogBuffer::dlb_close_log(XTThreadPtr thread) +{ + if (dlb_data_log) { + /* Flush and commit the data in the old log: */ + if (!dlb_flush_log(TRUE, thread)) + return FAILED; + + if (!dlb_db->db_datalogs.dlc_unlock_log(dlb_data_log)) + return FAILED; + dlb_data_log = NULL; + } + return OK; +} + +/* When I use 'thread' instead of 'self', this means + * that I will not throw an error. + */ +xtBool XTDataLogBuffer::dlb_get_log_offset(xtLogID *log_id, xtLogOffset *out_offset, size_t req_size, struct XTThread *thread) +{ + /* Note, I am allowing a log to grow beyond the threshold. + * The amount depends on the maximum extended record size. + * If I don't some logs will never fill up, because of only having + * a few more bytes available. + */ + if (!dlb_data_log || dlb_data_log->dlf_space_avaliable() == 0) { + /* Release the old log: */ + if (!dlb_close_log(thread)) + return FAILED; + + if (!dlb_log_buffer) { + if (!(dlb_log_buffer = (xtWord1 *) xt_malloc_ns(dlb_buffer_size))) + return FAILED; + } + + /* I could use req_size instead of 1, but this would mean some logs + * are never filled up. + */ + if (!(dlb_data_log = dlb_db->db_datalogs.dlc_get_log_for_writing(1, thread))) + return FAILED; +#ifdef DEBUG + dlb_max_write_offset = dlb_data_log->dlf_log_eof; +#endif + } + + *log_id = dlb_data_log->dlf_log_id; + *out_offset = dlb_data_log->dlf_log_eof; + dlb_data_log->dlf_log_eof += req_size; + return OK; +} + +xtBool XTDataLogBuffer::dlb_flush_log(xtBool commit, XTThreadPtr thread) +{ + if (!dlb_data_log || !dlb_data_log->dlf_log_file) + return OK; + + if (dlb_buffer_len) { + if (!xt_pwrite_file(dlb_data_log->dlf_log_file, dlb_buffer_offset, dlb_buffer_len, dlb_log_buffer, &thread->st_statistics.st_data, thread)) + return FAILED; +#ifdef DEBUG + if (dlb_buffer_offset + (xtLogOffset) dlb_buffer_len > dlb_max_write_offset) + dlb_max_write_offset = dlb_buffer_offset + (xtLogOffset) dlb_buffer_len; +#endif + dlb_buffer_len = 0; + dlb_flush_required = TRUE; + } + + if (commit && dlb_flush_required) { +#ifdef DEBUG + /* This would normally be equal, however, in the case + * where some other thread flushes the compactors + * data log, the eof, can be greater than the + * write offset. + * + * This occurs because the flush can come between the + * dlb_get_log_offset() and dlb_write_thru_log() calls. + */ + ASSERT_NS(dlb_data_log->dlf_log_eof >= dlb_max_write_offset); +#endif + if (!xt_flush_file(dlb_data_log->dlf_log_file, &thread->st_statistics.st_data, thread)) + return FAILED; + dlb_flush_required = FALSE; + } + return OK; +} + +xtBool XTDataLogBuffer::dlb_write_thru_log(xtLogID log_id __attribute__((unused)), xtLogOffset log_offset, size_t size, xtWord1 *data, XTThreadPtr thread) +{ + ASSERT_NS(log_id == dlb_data_log->dlf_log_id); + + if (dlb_buffer_len) + dlb_flush_log(FALSE, thread); + + if (!xt_pwrite_file(dlb_data_log->dlf_log_file, log_offset, size, data, &thread->st_statistics.st_data, thread)) + return FAILED; +#ifdef DEBUG + if (log_offset + size > dlb_max_write_offset) + dlb_max_write_offset = log_offset + size; +#endif + dlb_flush_required = TRUE; + return OK; +} + +xtBool XTDataLogBuffer::dlb_append_log(xtLogID log_id __attribute__((unused)), xtLogOffset log_offset, size_t size, xtWord1 *data, XTThreadPtr thread) +{ + ASSERT_NS(log_id == dlb_data_log->dlf_log_id); + + if (dlb_buffer_len) { + /* Should be the case, we only write by appending: */ + ASSERT_NS(dlb_buffer_offset + (xtLogOffset) dlb_buffer_len == log_offset); + /* Check if we are appending to the existing value in the buffer: */ + if (dlb_buffer_offset + (xtLogOffset) dlb_buffer_len == log_offset) { + /* Can we just append: */ + if (dlb_buffer_size >= dlb_buffer_len + size) { + memcpy(dlb_log_buffer + dlb_buffer_len, data, size); + dlb_buffer_len += size; + return OK; + } + } + dlb_flush_log(FALSE, thread); + } + + ASSERT_NS(dlb_buffer_len == 0); + + if (dlb_buffer_size >= size) { + dlb_buffer_offset = log_offset; + dlb_buffer_len = size; + memcpy(dlb_log_buffer, data, size); + return OK; + } + + /* Write directly: */ + if (!xt_pwrite_file(dlb_data_log->dlf_log_file, log_offset, size, data, &thread->st_statistics.st_data, thread)) + return FAILED; +#ifdef DEBUG + if (log_offset + size > dlb_max_write_offset) + dlb_max_write_offset = log_offset + size; +#endif + dlb_flush_required = TRUE; + return OK; +} + +xtBool XTDataLogBuffer::dlb_read_log(xtLogID log_id, xtLogOffset log_offset, size_t size, xtWord1 *data, XTThreadPtr thread) +{ + size_t red_size; + XTOpenLogFilePtr open_log; + + if (dlb_data_log && log_id == dlb_data_log->dlf_log_id) { + /* Reading from the write log, I can do this quicker: */ + if (dlb_buffer_len) { + /* If it is in the buffer, then it is completely in the buffer. */ + if (log_offset >= dlb_buffer_offset) { + if (log_offset + (xtLogOffset) size <= dlb_buffer_offset + (xtLogOffset) dlb_buffer_len) { + memcpy(data, dlb_log_buffer + (log_offset - dlb_buffer_offset), size); + return OK; + } + /* Should not happen, reading past EOF: */ + ASSERT_NS(FALSE); + memset(data, 0, size); + return OK; + } + /* In the write log, but not in the buffer, + * must be completely not in the log, + * because only whole records are written to the + * log: + */ + ASSERT_NS(log_offset + (xtLogOffset) size <= dlb_buffer_offset); + } + return xt_pread_file(dlb_data_log->dlf_log_file, log_offset, size, size, data, NULL, &thread->st_statistics.st_data, thread); + } + + /* Read from some other log: */ + if (!dlb_db->db_datalogs.dlc_get_open_log(&open_log, log_id)) + return FAILED; + + if (!xt_pread_file(open_log->odl_log_file, log_offset, size, 0, data, &red_size, &thread->st_statistics.st_data, thread)) { + dlb_db->db_datalogs.dlc_release_open_log(open_log); + return FAILED; + } + + dlb_db->db_datalogs.dlc_release_open_log(open_log); + + if (red_size < size) + memset(data + red_size, 0, size - red_size); + + return OK; +} + +/* + * We assume that the given reference may not be valid. + * Only valid references actually cause a delete. + * Invalid references are logged, and ignored. + * + * Note this routine does not lock the compactor. + * This can lead to the some incorrect calculation is the + * amount of garbage. But nothing serious I think. + */ +xtBool XTDataLogBuffer::dlb_delete_log(xtLogID log_id, xtLogOffset log_offset, size_t size, xtTableID tab_id, xtRecordID rec_id, XTThreadPtr thread) +{ + XTactExtRecEntryDRec record; + xtWord1 status = XT_LOG_ENT_EXT_REC_DEL; + XTOpenLogFilePtr open_log; + xtBool to_much_garbage; + XTDataLogFilePtr data_log; + + if (!dlb_read_log(log_id, log_offset, offsetof(XTactExtRecEntryDRec, er_data), (xtWord1 *) &record, thread)) + return FAILED; + + /* Already deleted: */ + if (record.er_status_1 == XT_LOG_ENT_EXT_REC_DEL) + return OK; + + if (record.er_status_1 != XT_LOG_ENT_EXT_REC_OK || + size != XT_GET_DISK_4(record.er_data_size_4) || + tab_id != XT_GET_DISK_4(record.er_tab_id_4) || + rec_id != XT_GET_DISK_4(record.er_rec_id_4)) { + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_BAD_EXT_RECORD); + return FAILED; + } + + if (dlb_data_log && log_id == dlb_data_log->dlf_log_id) { + /* Writing to the write log, I can do this quicker: */ + if (dlb_buffer_len) { + /* If it is in the buffer, then it is completely in the buffer. */ + if (log_offset >= dlb_buffer_offset) { + if (log_offset + 1 <= dlb_buffer_offset + (xtLogOffset) dlb_buffer_len) { + *(dlb_log_buffer + (log_offset - dlb_buffer_offset)) = XT_LOG_ENT_EXT_REC_DEL; + goto inc_garbage_count; + } + /* Should not happen, writing past EOF: */ + ASSERT_NS(FALSE); + return OK; + } + ASSERT_NS(log_offset + (xtLogOffset) size <= dlb_buffer_offset); + } + + if (!xt_pwrite_file(dlb_data_log->dlf_log_file, log_offset, 1, &status, &thread->st_statistics.st_data, thread)) + return FAILED; + + inc_garbage_count: + xt_lock_mutex_ns(&dlb_db->db_datalogs.dlc_head_lock); + dlb_data_log->dlf_garbage_count += offsetof(XTactExtRecEntryDRec, er_data) + size; + ASSERT_NS(dlb_data_log->dlf_garbage_count < dlb_data_log->dlf_log_eof); + if (!dl_write_log_header(dlb_data_log, dlb_data_log->dlf_log_file, FALSE, thread)) { + xt_unlock_mutex_ns(&dlb_db->db_datalogs.dlc_head_lock); + return FAILED; + } + dlb_flush_required = TRUE; + xt_unlock_mutex_ns(&dlb_db->db_datalogs.dlc_head_lock); + return OK; + } + + /* Write to some other log, open the log: */ + if (!dlb_db->db_datalogs.dlc_get_open_log(&open_log, log_id)) + return FAILED; + + /* Write the status byte: */ + if (!xt_pwrite_file(open_log->odl_log_file, log_offset, 1, &status, &thread->st_statistics.st_data, thread)) + goto failed; + + data_log = open_log->odl_data_log; + + /* Adjust the garbage level in the header. */ + xt_lock_mutex_ns(&dlb_db->db_datalogs.dlc_head_lock); + data_log->dlf_garbage_count += offsetof(XTactExtRecEntryDRec, er_data) + size; + ASSERT_NS(data_log->dlf_garbage_count < data_log->dlf_log_eof); + if (!dl_write_log_header(data_log, open_log->odl_log_file, FALSE, thread)) { + xt_unlock_mutex_ns(&dlb_db->db_datalogs.dlc_head_lock); + goto failed; + } + to_much_garbage = data_log->dlf_to_much_garbage(); + xt_unlock_mutex_ns(&dlb_db->db_datalogs.dlc_head_lock); + + if (to_much_garbage && + (data_log->dlf_state == XT_DL_HAS_SPACE || data_log->dlf_state == XT_DL_READ_ONLY)) { + /* There is too much garbage, it may be compacted. */ + if (!dlb_db->db_datalogs.dls_set_log_state(data_log, XT_DL_MAY_COMPACT)) + goto failed; + } + + /* Release the open log: */ + dlb_db->db_datalogs.dlc_release_open_log(open_log); + + return OK; + + failed: + dlb_db->db_datalogs.dlc_release_open_log(open_log); + return FAILED; +} + +/* + * Delete all the extended data belonging to a particular + * table. + */ +xtPublic void xt_dl_delete_ext_data(XTThreadPtr self, XTTableHPtr tab, xtBool missing_ok __attribute__((unused)), xtBool have_table_lock) +{ + XTOpenTablePtr ot; + xtRecordID page_rec_id, offs_rec_id; + XTTabRecExtDPtr rec_buf; + xtWord4 log_over_size; + xtLogID log_id; + xtLogOffset log_offset; + xtWord1 *page_data; + + page_data = (xtWord1 *) xt_malloc(self, tab->tab_recs.tci_page_size); + pushr_(xt_free, page_data); + + /* Scan the table, and remove all exended data... */ + if (!(ot = xt_open_table(tab))) { + if (self->t_exception.e_xt_err == XT_SYSTEM_ERROR && + XT_FILE_NOT_FOUND(self->t_exception.e_sys_err)) + return; + xt_throw(self); + } + ot->ot_thread = self; + + /* {LOCK-EXT-REC} This lock is to stop the compactor changing records + * while we are doing the delete. + */ + xt_lock_mutex_ns(&tab->tab_db->db_co_ext_lock); + + page_rec_id = 1; + while (page_rec_id < tab->tab_rec_eof_id) { + /* NOTE: There is a good reason for using xt_tc_read_page(). + * A deadlock can occur if using read, which can run out of + * memory, which waits for the freeer, which may need to + * open a table, which requires the db->db_tables lock, + * which is owned by the this thread, when the function + * is called from drop table. + * + * xt_tc_read_page() should work because no more changes + * should happen to the table while we are dropping it. + */ + if (!tab->tab_recs.xt_tc_read_page(ot->ot_rec_file, page_rec_id, page_data, self)) + goto failed; + + for (offs_rec_id=0; offs_rec_id<tab->tab_recs.tci_rows_per_page && page_rec_id+offs_rec_id < tab->tab_rec_eof_id; offs_rec_id++) { + rec_buf = (XTTabRecExtDPtr) (page_data + (offs_rec_id * tab->tab_recs.tci_rec_size)); + if (XT_REC_IS_EXT_DLOG(rec_buf->tr_rec_type_1)) { + log_over_size = XT_GET_DISK_4(rec_buf->re_log_dat_siz_4); + XT_GET_LOG_REF(log_id, log_offset, rec_buf); + + if (!self->st_dlog_buf.dlb_delete_log(log_id, log_offset, log_over_size, tab->tab_id, page_rec_id+offs_rec_id, self)) { + if (self->t_exception.e_xt_err != XT_ERR_BAD_EXT_RECORD && + self->t_exception.e_xt_err != XT_ERR_DATA_LOG_NOT_FOUND) + xt_log_and_clear_exception(self); + } + } + } + + page_rec_id += tab->tab_recs.tci_rows_per_page; + } + + xt_unlock_mutex_ns(&tab->tab_db->db_co_ext_lock); + + xt_close_table(ot, TRUE, have_table_lock); + + freer_(); // xt_free(page_data) + return; + + failed: + xt_unlock_mutex_ns(&tab->tab_db->db_co_ext_lock); + + xt_close_table(ot, TRUE, have_table_lock); + xt_throw(self); +} + +/* + * -------------------------------------------------------------------------------- + * GARBAGE COLLECTOR THREAD + */ + +xtPublic void xt_dl_init_db(XTThreadPtr self, XTDatabaseHPtr db) +{ + xt_init_mutex_with_autoname(self, &db->db_co_ext_lock); + xt_init_mutex_with_autoname(self, &db->db_co_dlog_lock); +} + +xtPublic void xt_dl_exit_db(XTThreadPtr self, XTDatabaseHPtr db) +{ + xt_stop_compactor(self, db); // Already done! + db->db_co_thread = NULL; + xt_free_mutex(&db->db_co_ext_lock); + xt_free_mutex(&db->db_co_dlog_lock); +} + +xtPublic void xt_dl_set_to_delete(XTThreadPtr self, XTDatabaseHPtr db, xtLogID log_id) +{ + XTDataLogFilePtr data_log; + + if (!db->db_datalogs.dlc_get_data_log(&data_log, log_id, FALSE, NULL)) + xt_throw(self); + if (data_log) { + if (!db->db_datalogs.dls_set_log_state(data_log, XT_DL_TO_DELETE)) + xt_throw(self); + } +} + +xtPublic void xt_dl_log_status(XTThreadPtr self, XTDatabaseHPtr db, XTStringBufferPtr strbuf) +{ + XTSortedListPtr list; + XTDataLogFilePtr data_log; + XTDataLogSegPtr seg; + u_int no_of_logs; + xtLogID *log_id_ptr; + + list = xt_new_sortedlist(self, sizeof(xtLogID), 20, 10, dl_cmp_log_id, NULL, NULL, FALSE, FALSE); + pushr_(xt_free_sortedlist, list); + + for (u_int i=0; i<XT_DL_NO_OF_SEGMENTS; i++) { + for (u_int j=0; j<XT_DL_SEG_HASH_TABLE_SIZE; j++) { + seg = &db->db_datalogs.dlc_segment[i]; + data_log = seg->dls_hash_table[j]; + while (data_log) { + xt_sl_insert(self, list, &data_log->dlf_log_id, &data_log->dlf_log_id); + data_log = data_log->dlf_next_hash; + } + } + } + + no_of_logs = xt_sl_get_size(list); + for (u_int i=0; i<no_of_logs; i++) { + log_id_ptr = (xtLogID *) xt_sl_item_at(list, i); + if (!db->db_datalogs.dlc_get_data_log(&data_log, *log_id_ptr, FALSE, &seg)) + xt_throw(self); + if (data_log) { + xt_sb_concat(self, strbuf, "d-log: "); + xt_sb_concat_int8(self, strbuf, data_log->dlf_log_id); + xt_sb_concat(self, strbuf, " status="); + switch (data_log->dlf_state) { + case XT_DL_UNKNOWN: + xt_sb_concat(self, strbuf, "?"); + break; + case XT_DL_HAS_SPACE: + xt_sb_concat(self, strbuf, "has-space "); + break; + case XT_DL_READ_ONLY: + xt_sb_concat(self, strbuf, "read-only "); + break; + case XT_DL_TO_COMPACT: + xt_sb_concat(self, strbuf, "to-compact"); + break; + case XT_DL_COMPACTED: + xt_sb_concat(self, strbuf, "compacted "); + break; + case XT_DL_TO_DELETE: + xt_sb_concat(self, strbuf, "to-delete "); + break; + case XT_DL_DELETED: + xt_sb_concat(self, strbuf, "deleted "); + break; + case XT_DL_EXCLUSIVE: + xt_sb_concat(self, strbuf, "x-locked "); + break; + } + xt_sb_concat(self, strbuf, " eof="); + xt_sb_concat_int8(self, strbuf, data_log->dlf_log_eof); + xt_sb_concat(self, strbuf, " garbage="); + xt_sb_concat_int8(self, strbuf, data_log->dlf_garbage_count); + xt_sb_concat(self, strbuf, " g%="); + if (data_log->dlf_log_eof) + xt_sb_concat_int8(self, strbuf, data_log->dlf_garbage_count * 100 / data_log->dlf_log_eof); + else + xt_sb_concat(self, strbuf, "100"); + xt_sb_concat(self, strbuf, " open="); + xt_sb_concat_int8(self, strbuf, data_log->dlf_open_count); + xt_sb_concat(self, strbuf, "\n"); + } + xt_unlock_mutex_ns(&seg->dls_lock); + } + + freer_(); // xt_free_sortedlist(list) +} + +xtPublic void xt_dl_delete_logs(XTThreadPtr self, XTDatabaseHPtr db) +{ + char path[PATH_MAX]; + XTOpenDirPtr od; + char *file; + xtLogID log_id; + + xt_strcpy(PATH_MAX, path, db->db_main_path); + xt_add_data_dir(PATH_MAX, path); + if (!xt_fs_exists(path)) + return; + pushsr_(od, xt_dir_close, xt_dir_open(self, path, NULL)); + while (xt_dir_next(self, od)) { + file = xt_dir_name(self, od); + if ((log_id = (xtLogID) xt_file_name_to_id(file))) { + if (!db->db_datalogs.dlc_remove_data_log(log_id, TRUE)) + xt_log_and_clear_exception(self); + } + if (xt_ends_with(file, ".xt")) { + xt_add_dir_char(PATH_MAX, path); + xt_strcat(PATH_MAX, path, file); + xt_fs_delete(self, path); + xt_remove_last_name_of_path(path); + } + } + freer_(); // xt_dir_close(od) + + /* I no longer attach the condition: !db->db_multi_path + * to removing this directory. This is because + * the pbxt directory must now be removed explicitly + * by drop database, or by delete all the PBXT + * system tables. + */ + if (!xt_fs_rmdir(NULL, path)) + xt_log_and_clear_exception(self); +} + +typedef struct XTCompactorState { + XTSeqLogReadPtr cs_seqread; + XTOpenTablePtr cs_ot; + XTDataBufferRec cs_databuf; +} XTCompactorStateRec, *XTCompactorStatePtr; + +static void dl_free_compactor_state(XTThreadPtr self, XTCompactorStatePtr cs) +{ + if (cs->cs_seqread) { + cs->cs_seqread->sl_seq_exit(); + delete cs->cs_seqread; + cs->cs_seqread = NULL; + } + if (cs->cs_ot) { + xt_db_return_table_to_pool(self, cs->cs_ot); + cs->cs_ot = NULL; + } + xt_db_set_size(self, &cs->cs_databuf, 0); +} + +static XTOpenTablePtr dl_cs_get_open_table(XTThreadPtr self, XTCompactorStatePtr cs, xtTableID tab_id) +{ + if (cs->cs_ot) { + if (cs->cs_ot->ot_table->tab_id == tab_id) + return cs->cs_ot; + + xt_db_return_table_to_pool(self, cs->cs_ot); + cs->cs_ot = NULL; + } + + if (!cs->cs_ot) { + if (!(cs->cs_ot = xt_db_open_pool_table(self, self->st_database, tab_id, NULL, TRUE))) + return NULL; + } + + return cs->cs_ot; +} + +static void dl_co_wait(XTThreadPtr self, XTDatabaseHPtr db, u_int secs) +{ + xt_lock_mutex(self, &db->db_datalogs.dlc_lock); + pushr_(xt_unlock_mutex, &db->db_datalogs.dlc_lock); + if (!self->t_quit) + xt_timed_wait_cond(self, &db->db_datalogs.dlc_cond, &db->db_datalogs.dlc_lock, secs * 1000); + freer_(); // xt_unlock_mutex(&db->db_datalogs.dlc_lock) +} + +/* + * Collect all the garbage in a file by moving all valid records + * into some other data log and updating the handles. + */ +static xtBool dl_collect_garbage(XTThreadPtr self, XTDatabaseHPtr db, XTDataLogFilePtr data_log) +{ + XTXactLogBufferDPtr record; + size_t size; + xtTableID tab_id; + xtRecordID rec_id; + XTCompactorStateRec cs; + XTOpenTablePtr ot; + XTTableHPtr tab; + XTTabRecExtDRec rec_buffer; + size_t src_size; + xtLogID src_log_id; + xtLogOffset src_log_offset; + xtLogID curr_log_id; + xtLogOffset curr_log_offset; + xtLogID dest_log_id; + xtLogOffset dest_log_offset; + off_t garbage_count = 0; + + memset(&cs, 0, sizeof(XTCompactorStateRec)); + + if (!(cs.cs_seqread = new XTDataSeqRead())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + + if (!cs.cs_seqread->sl_seq_init(db, xt_db_log_buffer_size)) { + delete cs.cs_seqread; + xt_throw(self); + } + pushr_(dl_free_compactor_state, &cs); + + if (!cs.cs_seqread->sl_seq_start(data_log->dlf_log_id, data_log->dlf_start_offset, FALSE)) + xt_throw(self); + + for (;;) { + if (self->t_quit) { + /* Flush the destination log: */ + xt_lock_mutex(self, &db->db_co_dlog_lock); + pushr_(xt_unlock_mutex, &db->db_co_dlog_lock); + if (!self->st_dlog_buf.dlb_flush_log(TRUE, self)) + xt_throw(self); + freer_(); // xt_unlock_mutex(&db->db_co_dlog_lock) + + /* Flush the transaction log. */ + if (!xt_xlog_flush_log(self)) + xt_throw(self); + + xt_lock_mutex_ns(&db->db_datalogs.dlc_head_lock); + data_log->dlf_garbage_count += garbage_count; + ASSERT(data_log->dlf_garbage_count < data_log->dlf_log_eof); + if (!dl_write_log_header(data_log, cs.cs_seqread->sl_seq_open_file(), TRUE, self)) { + xt_unlock_mutex_ns(&db->db_datalogs.dlc_head_lock); + xt_throw(self); + } + xt_unlock_mutex_ns(&db->db_datalogs.dlc_head_lock); + + freer_(); // dl_free_compactor_state(&cs) + return FAILED; + } + if (!cs.cs_seqread->sl_seq_next(&record, TRUE, self)) + xt_throw(self); + cs.cs_seqread->sl_seq_pos(&curr_log_id, &curr_log_offset); + if (!record) { + data_log->dlf_start_offset = curr_log_offset; + break; + } + switch (record->xh.xh_status_1) { + case XT_LOG_ENT_EXT_REC_OK: + size = XT_GET_DISK_4(record->er.er_data_size_4); + tab_id = XT_GET_DISK_4(record->er.er_tab_id_4); + rec_id = XT_GET_DISK_4(record->er.er_rec_id_4); + + if (!(ot = dl_cs_get_open_table(self, &cs, tab_id))) + break; + tab = ot->ot_table; + + /* All this is required for a valid record address: */ + if (!rec_id || rec_id >= tab->tab_rec_eof_id) + break; + + /* {LOCK-EXT-REC} It is important to prevent the compactor from modifying + * a record that has been freed (and maybe allocated again). + * + * Consider the following sequence: + * + * 1. Compactor reads the record. + * 2. The record is freed and reallocated. + * 3. The compactor updates the record. + * + * To prevent this, the compactor locks out the + * sweeper using the db_co_ext_lock lock. The db_co_ext_lock lock + * prevents a extended record from being moved and removed at the + * same time. + * + * The compactor also checks the status of the record before + * moving a record. + */ + xt_lock_mutex(self, &db->db_co_ext_lock); + pushr_(xt_unlock_mutex, &db->db_co_ext_lock); + + /* Read the record: */ + if (!xt_tab_get_rec_data(ot, rec_id, offsetof(XTTabRecExtDRec, re_data), (xtWord1 *) &rec_buffer)) { + xt_log_and_clear_warning(self); + freer_(); // xt_unlock_mutex(&db->db_co_ext_lockk) + break; + } + + /* [(7)] REMOVE is followed by FREE: + if (XT_REC_IS_REMOVED(rec_buffer.tr_rec_type_1) || !XT_REC_IS_EXT_DLOG(rec_buffer.tr_rec_type_1)) { + */ + if (!XT_REC_IS_EXT_DLOG(rec_buffer.tr_rec_type_1)) { + freer_(); // xt_unlock_mutex(&db->db_co_ext_lock) + break; + } + + XT_GET_LOG_REF(src_log_id, src_log_offset, &rec_buffer); + src_size = (size_t) XT_GET_DISK_4(rec_buffer.re_log_dat_siz_4); + + /* Does the record agree with the current position: */ + if (curr_log_id != src_log_id || + curr_log_offset != src_log_offset || + size != src_size) { + freer_(); // xt_unlock_mutex(&db->db_co_ext_lock) + break; + } + + size = offsetof(XTactExtRecEntryDRec, er_data) + size; + + /* Allocate space in a destination log: */ + xt_lock_mutex(self, &db->db_co_dlog_lock); + pushr_(xt_unlock_mutex, &db->db_co_dlog_lock); + if (!self->st_dlog_buf.dlb_get_log_offset(&dest_log_id, &dest_log_offset, size, self)) + xt_throw(self); + freer_(); // xt_unlock_mutex(&db->db_co_dlog_lock) + + /* This record is referenced by the data: */ + xt_db_set_size(self, &cs.cs_databuf, size); + if (!cs.cs_seqread->sl_rnd_read(src_log_offset, size, cs.cs_databuf.db_data, NULL, self)) + xt_throw(self); + + /* The problem with writing to the buffer here, is that other + * threads want to read the data! */ + xt_lock_mutex(self, &db->db_co_dlog_lock); + pushr_(xt_unlock_mutex, &db->db_co_dlog_lock); + if (!self->st_dlog_buf.dlb_write_thru_log(dest_log_id, dest_log_offset, size, cs.cs_databuf.db_data, self)) + xt_throw(self); + freer_(); // xt_unlock_mutex(&db->db_co_dlog_lock) + + /* Make sure we flush the compactor target log, before we + * flush the transaction log!! + * This is done here [(8)] + */ + + XT_SET_LOG_REF(&rec_buffer, dest_log_id, dest_log_offset); + xtOpSeqNo op_seq; + if (!xt_tab_put_log_rec_data(ot, XT_LOG_ENT_REC_MOVED, 0, rec_id, 8, (xtWord1 *) &rec_buffer.re_log_id_2, &op_seq)) + xt_throw(self); + tab->tab_co_op_seq = op_seq; + + /* Only records that were actually moved, count as garbage now! + * This means, lost records, remain "lost" as far as the garbage + * count is concerned! + */ + garbage_count += size; + freer_(); // xt_unlock_mutex(&db->db_co_ext_lock) + break; + } + data_log->dlf_start_offset = curr_log_offset; + } + + /* Flush the distination log. */ + xt_lock_mutex(self, &db->db_co_dlog_lock); + pushr_(xt_unlock_mutex, &db->db_co_dlog_lock); + if (!self->st_dlog_buf.dlb_flush_log(TRUE, self)) + xt_throw(self); + freer_(); // xt_unlock_mutex(&db->db_co_dlog_lock) + + /* Flush the transaction log. */ + if (!xt_xlog_flush_log(self)) + xt_throw(self); + + /* Save state in source log header. */ + xt_lock_mutex_ns(&db->db_datalogs.dlc_head_lock); + data_log->dlf_garbage_count += garbage_count; + ASSERT(data_log->dlf_garbage_count < data_log->dlf_log_eof); + if (!dl_write_log_header(data_log, cs.cs_seqread->sl_seq_open_file(), TRUE, self)) { + xt_unlock_mutex_ns(&db->db_datalogs.dlc_head_lock); + xt_throw(self); + } + xt_unlock_mutex_ns(&db->db_datalogs.dlc_head_lock); + + /* Wait for the writer to write all the changes. + * Then we can start the delete process for the log: + * + * Note, if we do not wait, then it could be some operations are held up, + * by being out of sequence. This could cause the log to be deleted + * before all the operations have been performed (which are on a table + * basis). + * + */ + for (;;) { + u_int edx; + XTTableEntryPtr tab_ptr; + xtBool wait; + + if (self->t_quit) { + freer_(); // dl_free_compactor_state(&cs) + return FAILED; + } + wait = FALSE; + xt_ht_lock(self, db->db_tables); + pushr_(xt_ht_unlock, db->db_tables); + xt_enum_tables_init(&edx); + while ((tab_ptr = xt_enum_tables_next(self, db, &edx))) { + if (tab_ptr->te_table && tab_ptr->te_table->tab_co_op_seq > tab_ptr->te_table->tab_head_op_seq) { + wait = TRUE; + break; + } + } + freer_(); // xt_ht_unlock(db->db_tables) + + if (!wait) + break; + + /* Nobody will wake me, so check again shortly! */ + dl_co_wait(self, db, 1); + } + + db->db_datalogs.dls_set_log_state(data_log, XT_DL_COMPACTED); + +#ifdef DEBUG_LOG_DELETE + printf("-- MARK FOR DELETE IN LOG: %d\n", (int) data_log->dlf_log_id); +#endif + /* Log that this log should be deleted on the next checkpoint: */ + // transaction log... + XTXactNewLogEntryDRec log_rec; + log_rec.xl_status_1 = XT_LOG_ENT_DEL_LOG; + log_rec.xl_checksum_1 = XT_CHECKSUM_1(data_log->dlf_log_id); + XT_SET_DISK_4(log_rec.xl_log_id_4, data_log->dlf_log_id); + if (!xt_xlog_log_data(self, sizeof(XTXactNewLogEntryDRec), (XTXactLogBufferDPtr) &log_rec, TRUE)) { + db->db_datalogs.dls_set_log_state(data_log, XT_DL_TO_COMPACT); + xt_throw(self); + } + + freer_(); // dl_free_compactor_state(&cs) + return OK; +} + +static void dl_co_not_busy(XTThreadPtr XT_UNUSED(self), XTDatabaseHPtr db) +{ + db->db_co_busy = FALSE; +} + +static void dl_co_main(XTThreadPtr self, xtBool once_off) +{ + XTDatabaseHPtr db = self->st_database; + xtLogID *log_id_ptr, log_id; + XTDataLogFilePtr data_log = NULL; + + xt_set_low_priority(self); + + while (!self->t_quit) { + while (!self->t_quit) { + xt_lock_mutex_ns(&db->db_datalogs.dlc_lock); + if ((log_id_ptr = (xtLogID *) xt_sl_first_item(db->db_datalogs.dlc_to_compact))) { + log_id = *log_id_ptr; + } + else + log_id = 0; + xt_unlock_mutex_ns(&db->db_datalogs.dlc_lock); + if (!log_id) + break; + if (!db->db_datalogs.dlc_get_data_log(&data_log, log_id, FALSE, NULL)) + xt_throw(self); + ASSERT(data_log); + if (data_log) { + db->db_co_busy = TRUE; + pushr_(dl_co_not_busy, db); + dl_collect_garbage(self, db, data_log); + freer_(); // dl_co_not_busy(db) + } + else { + xt_lock_mutex_ns(&db->db_datalogs.dlc_lock); + xt_sl_delete(self, db->db_datalogs.dlc_to_compact, &log_id); + xt_unlock_mutex_ns(&db->db_datalogs.dlc_lock); + } + } + + if (once_off) + break; + + /* Wait for a signal that a data log can be collected: */ + dl_co_wait(self, db, 120); + } +} + +static void *dl_run_co_thread(XTThreadPtr self) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) self->t_data; + int count; + void *mysql_thread; + + mysql_thread = myxt_create_thread(); + + while (!self->t_quit) { + try_(a) { + /* + * The garbage collector requires that the database + * is in use because. + */ + xt_use_database(self, db, XT_FOR_COMPACTOR); + + /* This action is both safe and required: + * + * safe: releasing the database is safe because as + * long as this thread is running the database + * reference is valid, and this reference cannot + * be the only one to the database because + * otherwize this thread would not be running. + * + * required: releasing the database is necessary + * otherwise we cannot close the database + * correctly because we only shutdown this + * thread when the database is closed and we + * only close the database when all references + * are removed. + */ + xt_heap_release(self, self->st_database); + + dl_co_main(self, FALSE); + } + catch_(a) { + if (!(self->t_exception.e_xt_err == XT_SIGNAL_CAUGHT && + self->t_exception.e_sys_err == SIGTERM)) + xt_log_and_clear_exception(self); + } + cont_(a); + + /* Avoid releasing the database (done above) */ + self->st_database = NULL; + xt_unuse_database(self, self); + + /* After an exception, pause before trying again... */ + /* Number of seconds */ +#ifdef DEBUG + count = 10; +#else + count = 2*60; +#endif + while (!self->t_quit && count > 0) { + sleep(1); + count--; + } + } + + myxt_destroy_thread(mysql_thread, TRUE); + return NULL; +} + +static void dl_free_co_thread(XTThreadPtr self, void *data) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) data; + + if (db->db_co_thread) { + xt_lock_mutex(self, &db->db_datalogs.dlc_lock); + pushr_(xt_unlock_mutex, &db->db_datalogs.dlc_lock); + db->db_co_thread = NULL; + freer_(); // xt_unlock_mutex(&db->db_datalogs.dlc_lock) + } +} + +xtPublic void xt_start_compactor(XTThreadPtr self, XTDatabaseHPtr db) +{ + char name[PATH_MAX]; + + sprintf(name, "GC-%s", xt_last_directory_of_path(db->db_main_path)); + xt_remove_dir_char(name); + db->db_co_thread = xt_create_daemon(self, name); + xt_set_thread_data(db->db_co_thread, db, dl_free_co_thread); + xt_run_thread(self, db->db_co_thread, dl_run_co_thread); +} + +static void dl_wake_co_thread(XTDatabaseHPtr db) +{ + if (!xt_signal_cond(NULL, &db->db_datalogs.dlc_cond)) + xt_log_and_clear_exception_ns(); +} + +xtPublic void xt_stop_compactor(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTThreadPtr thr_co; + + if (db->db_co_thread) { + xt_lock_mutex(self, &db->db_datalogs.dlc_lock); + pushr_(xt_unlock_mutex, &db->db_datalogs.dlc_lock); + + /* This pointer is safe as long as you have the transaction lock. */ + if ((thr_co = db->db_co_thread)) { + xtThreadID tid = thr_co->t_id; + + /* Make sure the thread quits when woken up. */ + xt_terminate_thread(self, thr_co); + + dl_wake_co_thread(db); + + freer_(); // xt_unlock_mutex(&db->db_datalogs.dlc_lock) + + /* + * This seems to kill the whole server sometimes!! + * SIGTERM is going to a different thread??! + xt_kill_thread(thread); + */ + xt_wait_for_thread(tid, FALSE); + + /* PMC - This should not be necessary to set the signal here, but in the + * debugger the handler is not called!!? + thr_co->t_delayed_signal = SIGTERM; + xt_kill_thread(thread); + */ + db->db_co_thread = NULL; + } + else + freer_(); // xt_unlock_mutex(&db->db_datalogs.dlc_lock) + } +} + diff --git a/storage/pbxt/src/datalog_xt.h b/storage/pbxt/src/datalog_xt.h new file mode 100644 index 00000000000..245ebcbaeda --- /dev/null +++ b/storage/pbxt/src/datalog_xt.h @@ -0,0 +1,228 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-24 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_datalog_h__ +#define __xt_datalog_h__ + +#include "pthread_xt.h" +#include "filesys_xt.h" +#include "sortedlist_xt.h" +#include "xactlog_xt.h" +#include "util_xt.h" + +struct XTThread; +struct XTDatabase; +struct xXTDataLog; +struct XTTable; +struct XTOpenTable; + +#define XT_SET_LOG_REF(d, l, o) do { XT_SET_DISK_2((d)->re_log_id_2, l); \ + XT_SET_DISK_6((d)->re_log_offs_6, o); \ + } while (0) +#define XT_GET_LOG_REF(l, o, s) do { l = XT_GET_DISK_2((s)->re_log_id_2); \ + o = XT_GET_DISK_6((s)->re_log_offs_6); \ + } while (0) + +#ifdef DEBUG +//#define USE_DEBUG_SIZES +#endif + +#ifdef USE_DEBUG_SIZES +#define XT_DL_MAX_LOG_ID 500 +#define XT_DL_LOG_POOL_SIZE 10 +#define XT_DL_HASH_TABLE_SIZE 5 +#define XT_DL_SEGMENT_SHIFTS 1 +#else +#define XT_DL_MAX_LOG_ID 0x7FFF +#define XT_DL_LOG_POOL_SIZE 1000 +#define XT_DL_HASH_TABLE_SIZE 10000 +#define XT_DL_SEGMENT_SHIFTS 3 +#endif + +#define XT_DL_SEG_HASH_TABLE_SIZE (XT_DL_HASH_TABLE_SIZE / XT_DL_NO_OF_SEGMENTS) +#define XT_DL_NO_OF_SEGMENTS (1 << XT_DL_SEGMENT_SHIFTS) +#define XT_DL_SEGMENT_MASK (XT_DL_NO_OF_SEGMENTS - 1) + +typedef struct XTOpenLogFile { + xtLogID olf_log_id; + XTOpenFilePtr odl_log_file; /* The open file handle. */ + struct XTDataLogFile *odl_data_log; + + xtBool odl_in_use; + struct XTOpenLogFile *odl_next_free; /* Pointer to the next on the free list. */ + struct XTOpenLogFile *odl_prev_free; /* Pointer to the previous on the free list. */ + + xtWord4 odl_ru_time; /* If this is in the top 1/4 don't change position in MRU list. */ + struct XTOpenLogFile *odl_mr_used; /* More recently used pages. */ + struct XTOpenLogFile *odl_lr_used; /* Less recently used pages. */ +} XTOpenLogFileRec, *XTOpenLogFilePtr; + +#define XT_DL_MAY_COMPACT -1 /* This is an indication to set the state to XT_DL_TO_COMPACT. */ +#define XT_DL_UNKNOWN 0 +#define XT_DL_HAS_SPACE 1 /* The log is not yet full, and can be used for writing. */ +#define XT_DL_READ_ONLY 2 /* The log is full, and can only be read now. */ +#define XT_DL_TO_COMPACT 3 /* The log has too much garbage, and must be compacted. */ +#define XT_DL_COMPACTED 4 /* The state after compaction. */ +#define XT_DL_TO_DELETE 5 /* All references to this log have been removed, and it is to be deleted. */ +#define XT_DL_DELETED 6 /* After deletion, logs are locked until the next checkpoint. */ +#define XT_DL_EXCLUSIVE 7 /* The log is locked and being written by a thread. */ + +typedef struct XTDataLogFile { + xtLogID dlf_log_id; /* The ID of the data log. */ + int dlf_state; + struct XTDataLogFile *dlf_next_hash; /* Pointer to the next on the hash list. */ + u_int dlf_open_count; /* Number of open log files. */ + XTOpenLogFilePtr dlf_free_list; /* The open file free list. */ + off_t dlf_log_eof; + off_t dlf_start_offset; /* Start offset for garbage collection. */ + off_t dlf_garbage_count; /* The amount of garbage in the log file. */ + XTOpenFilePtr dlf_log_file; /* The open file handle (if the log is in exclusive use!!). */ + + off_t dlf_space_avaliable(); + xtBool dlf_to_much_garbage(); +} XTDataLogFileRec, *XTDataLogFilePtr; + +typedef struct XTDataLogSeg { + xt_mutex_type dls_lock; /* The cache segment lock. */ + xt_cond_type dls_cond; + XTDataLogFilePtr dls_hash_table[XT_DL_SEG_HASH_TABLE_SIZE]; +} XTDataLogSegRec, *XTDataLogSegPtr; + +typedef struct XTDataLogCache { + struct XTDatabase *dlc_db; + + xt_mutex_type dlc_lock; /* The public cache lock. */ + xt_cond_type dlc_cond; /* The public cache wait condition. */ + XTSortedListPtr dlc_has_space; /* List of logs with space for more data. */ + XTSortedListPtr dlc_to_compact; /* List of logs to be compacted. */ + XTSortedListPtr dlc_to_delete; /* List of logs to be deleted at next checkpoint. */ + XTSortedListPtr dlc_deleted; /* List of logs deleted at the previous checkpoint. */ + XTDataLogSegRec dlc_segment[XT_DL_NO_OF_SEGMENTS]; + xtLogID dlc_next_log_id; /* The next log ID to be used to create a new log. */ + + xt_mutex_type dlc_mru_lock; /* The lock for the LRU list. */ + xtWord4 dlc_ru_now; + XTOpenLogFilePtr dlc_lru_open_log; + XTOpenLogFilePtr dlc_mru_open_log; + u_int dlc_open_count; /* The total open file count. */ + + xt_mutex_type dlc_head_lock; /* The lock for changing the header of shared logs. */ + + void dls_remove_log(XTDataLogFilePtr data_log); + int dls_get_log_state(XTDataLogFilePtr data_log); + xtBool dls_set_log_state(XTDataLogFilePtr data_log, int state); + void dlc_init(struct XTThread *self, struct XTDatabase *db); + void dlc_exit(struct XTThread *self); + void dlc_name(size_t size, char *path, xtLogID log_id); + xtBool dlc_open_log(XTOpenFilePtr *fh, xtLogID log_id, int mode); + xtBool dlc_unlock_log(XTDataLogFilePtr data_log); + XTDataLogFilePtr dlc_get_log_for_writing(off_t space_required, struct XTThread *thread); + xtBool dlc_get_data_log(XTDataLogFilePtr *data_log, xtLogID log_id, xtBool create, XTDataLogSegPtr *ret_seg); + xtBool dlc_remove_data_log(xtLogID log_id, xtBool just_close); + xtBool dlc_get_open_log(XTOpenLogFilePtr *open_log, xtLogID log_id); + void dlc_release_open_log(XTOpenLogFilePtr open_log); +} XTDataLogCacheRec, *XTDataLogCachePtr; + +/* The data log buffer, used by a thread to write a + * data log file. + */ +typedef struct XTDataLogBuffer { + struct XTDatabase *dlb_db; + XTDataLogFilePtr dlb_data_log; /* The data log file. */ + + xtLogOffset dlb_buffer_offset; /* The offset into the log file. */ + size_t dlb_buffer_size; /* The size of the buffer. */ + size_t dlb_buffer_len; /* The amount of data in the buffer. */ + xtWord1 *dlb_log_buffer; + xtBool dlb_flush_required; +#ifdef DEBUG + off_t dlb_max_write_offset; +#endif + + void dlb_init(struct XTDatabase *db, size_t buffer_size); + void dlb_exit(struct XTThread *self); + xtBool dlb_close_log(struct XTThread *thread); + xtBool dlb_get_log_offset(xtLogID *log_id, off_t *out_offset, size_t req_size, struct XTThread *thread); + xtBool dlb_flush_log(xtBool commit, struct XTThread *thread); + xtBool dlb_write_thru_log(xtLogID log_id, xtLogOffset log_offset, size_t size, xtWord1 *data, struct XTThread *thread); + xtBool dlb_append_log(xtLogID log_id, off_t out_offset, size_t size, xtWord1 *data, struct XTThread *thread); + xtBool dlb_read_log(xtLogID log_id, off_t offset, size_t size, xtWord1 *data, struct XTThread *thread); + xtBool dlb_delete_log(xtLogID log_id, off_t offset, size_t size, xtTableID tab_id, xtRecordID tab_offset, struct XTThread *thread); +} XTDataLogBufferRec, *XTDataLogBufferPtr; + +typedef struct XTSeqLogRead { + struct XTDatabase *sl_db; + + virtual ~XTSeqLogRead() { } + virtual xtBool sl_seq_init(struct XTDatabase *db, size_t buffer_size) { (void) buffer_size; sl_db = db; return OK; }; + virtual void sl_seq_exit() { }; + virtual XTOpenFilePtr sl_seq_open_file() { return NULL; }; + virtual void sl_seq_pos(xtLogID *log_id, xtLogOffset *log_offset) { (void) log_id; (void) log_offset; }; + virtual xtBool sl_seq_start(xtLogID log_id, xtLogOffset log_offset, xtBool missing_ok) { + (void) log_id; (void) log_offset; (void) missing_ok; return OK; + }; + virtual xtBool sl_rnd_read(xtLogOffset log_offset, size_t size, xtWord1 *data, size_t *read, struct XTThread *thread) { + (void) log_offset; (void) size; (void) data; (void) read; (void) thread; return OK; + }; + virtual xtBool sl_seq_next(XTXactLogBufferDPtr *entry, xtBool verify, struct XTThread *thread) { + (void) entry; (void) verify; (void) thread; return OK; + }; + virtual void sl_seq_skip(size_t size) { (void) size; } +} XTSeqLogReadRec, *XTSeqLogReadPtr; + +typedef struct XTDataSeqRead : public XTSeqLogRead { + XTOpenFilePtr sl_log_file; + xtLogID sl_rec_log_id; /* The current record log ID. */ + xtLogOffset sl_rec_log_offset; /* The current log read position. */ + size_t sl_record_len; /* The length of the current record. */ + xtLogOffset sl_log_eof; + + size_t sl_buffer_size; /* Size of the buffer. */ + xtLogOffset sl_buf_log_offset; /* File offset of the buffer. */ + size_t sl_buffer_len; /* Amount of data in the buffer. */ + xtWord1 *sl_buffer; + + virtual ~XTDataSeqRead() { } + virtual xtBool sl_seq_init(struct XTDatabase *db, size_t buffer_size); + virtual void sl_seq_exit(); + virtual XTOpenFilePtr sl_seq_open_file(); + virtual void sl_seq_pos(xtLogID *log_id, xtLogOffset *log_offset); + virtual xtBool sl_seq_start(xtLogID log_id, xtLogOffset log_offset, xtBool missing_ok); + virtual xtBool sl_rnd_read(xtLogOffset log_offset, size_t size, xtWord1 *data, size_t *read, struct XTThread *thread); + virtual xtBool sl_seq_next(XTXactLogBufferDPtr *entry, xtBool verify, struct XTThread *thread); + virtual void sl_seq_skip(size_t size); + virtual void sl_seq_skip_to(off_t offset); +} XTDataSeqReadRec, *XTDataSeqReadPtr; + +void xt_dl_delete_ext_data(struct XTThread *self, struct XTTable *tab, xtBool missing_ok, xtBool have_table_lock); + +void xt_start_compactor(struct XTThread *self, struct XTDatabase *db); +void xt_stop_compactor(struct XTThread *self, struct XTDatabase *db); + +void xt_dl_init_db(struct XTThread *self, struct XTDatabase *db); +void xt_dl_exit_db(struct XTThread *self, struct XTDatabase *db); +void xt_dl_set_to_delete(struct XTThread *self, struct XTDatabase *db, xtLogID log_id); +void xt_dl_log_status(struct XTThread *self, struct XTDatabase *db, XTStringBufferPtr strbuf); +void xt_dl_delete_logs(struct XTThread *self, struct XTDatabase *db); + +#endif + diff --git a/storage/pbxt/src/discover_xt.cc b/storage/pbxt/src/discover_xt.cc new file mode 100644 index 00000000000..074132d47cb --- /dev/null +++ b/storage/pbxt/src/discover_xt.cc @@ -0,0 +1,1383 @@ +/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany + * Derived from code Copyright (C) 2000-2004 MySQL AB + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Created by Leslie on 8/27/08. + * + */ + +#include "xt_config.h" + +#ifndef DRIZZLED +#include "mysql_priv.h" +#include "item_create.h" +#include <m_ctype.h> +#else +#include <drizzled/session.h> +#include <drizzled/server_includes.h> +#include <drizzled/sql_base.h> +#endif + +#include "strutil_xt.h" +#include "ha_pbxt.h" +#include "discover_xt.h" +#include "ha_xtsys.h" + +#ifndef DRIZZLED +#if MYSQL_VERSION_ID > 60005 +#define DOT_STR(x) x.str +#else +#define DOT_STR(x) x +#endif +#endif + +#ifndef DRIZZLED +#define LOCK_OPEN_HACK_REQUIRED +#endif // DRIZZLED + +#ifdef LOCK_OPEN_HACK_REQUIRED +/////////////////////////////// +/* + * Unfortunately I cannot use the standard mysql_create_table_no_lock() because it will lock "LOCK_open" + * which has already been locked while the server is performing table discovery. So I have added this hack + * in here to create my own version. The following macros will make the changes I need to get it to work. + * The actual function code has been copied here without changes. + * + * Its almost enough to make you want to cry. :( +*/ +//----------------------------- + +#ifdef pthread_mutex_lock +#undef pthread_mutex_lock +#endif + +#ifdef pthread_mutex_unlock +#undef pthread_mutex_unlock +#endif + +#define mysql_create_table_no_lock hacked_mysql_create_table_no_lock +#define pthread_mutex_lock(l) +#define pthread_mutex_unlock(l) + +#define check_engine(t, n, c) (0) +#define set_table_default_charset(t, c, d) + +void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval, + uint32 *max_length, uint32 *tot_length); + +uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen); +uint build_table_filename(char *buff, size_t bufflen, const char *db, + const char *table_name, const char *ext, uint flags); + +////////////////////////////////////////////////////////// +////// START OF CUT AND PASTES FROM sql_table.cc //////// +////////////////////////////////////////////////////////// + +// sort_keys() cut and pasted directly from sql_table.cc. +static int sort_keys(KEY *a, KEY *b) +{ + ulong a_flags= a->flags, b_flags= b->flags; + + if (a_flags & HA_NOSAME) + { + if (!(b_flags & HA_NOSAME)) + return -1; + if ((a_flags ^ b_flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) + { + /* Sort NOT NULL keys before other keys */ + return (a_flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; + } + if (a->name == primary_key_name) + return -1; + if (b->name == primary_key_name) + return 1; + /* Sort keys don't containing partial segments before others */ + if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG) + return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1; + } + else if (b_flags & HA_NOSAME) + return 1; // Prefer b + + if ((a_flags ^ b_flags) & HA_FULLTEXT) + { + return (a_flags & HA_FULLTEXT) ? 1 : -1; + } + /* + Prefer original key order. usable_key_parts contains here + the original key position. + */ + return ((a->usable_key_parts < b->usable_key_parts) ? -1 : + (a->usable_key_parts > b->usable_key_parts) ? 1 : + 0); +} + +// check_if_keyname_exists() cut and pasted directly from sql_table.cc. +static bool +check_if_keyname_exists(const char *name, KEY *start, KEY *end) +{ + for (KEY *key=start ; key != end ; key++) + if (!my_strcasecmp(system_charset_info,name,key->name)) + return 1; + return 0; +} + +// make_unique_key_name() cut and pasted directly from sql_table.cc. +static char * +make_unique_key_name(const char *field_name,KEY *start,KEY *end) +{ + char buff[MAX_FIELD_NAME],*buff_end; + + if (!check_if_keyname_exists(field_name,start,end) && + my_strcasecmp(system_charset_info,field_name,primary_key_name)) + return (char*) field_name; // Use fieldname + buff_end=strmake(buff,field_name, sizeof(buff)-4); + + /* + Only 3 chars + '\0' left, so need to limit to 2 digit + This is ok as we can't have more than 100 keys anyway + */ + for (uint i=2 ; i< 100; i++) + { + *buff_end= '_'; + int10_to_str(i, buff_end+1, 10); + if (!check_if_keyname_exists(buff,start,end)) + return sql_strdup(buff); + } + return (char*) "not_specified"; // Should never happen +} + + +// prepare_blob_field() cut and pasted directly from sql_table.cc. +static bool prepare_blob_field(THD *thd, Create_field *sql_field) +{ + DBUG_ENTER("prepare_blob_field"); + + if (sql_field->length > MAX_FIELD_VARCHARLENGTH && + !(sql_field->flags & BLOB_FLAG)) + { + /* Convert long VARCHAR columns to TEXT or BLOB */ + char warn_buff[MYSQL_ERRMSG_SIZE]; + + if (sql_field->def || (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES))) + { + my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name, + MAX_FIELD_VARCHARLENGTH / sql_field->charset->mbmaxlen); + DBUG_RETURN(1); + } + sql_field->sql_type= MYSQL_TYPE_BLOB; + sql_field->flags|= BLOB_FLAG; + sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name, + (sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR", + (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT"); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT, + warn_buff); + } + + if ((sql_field->flags & BLOB_FLAG) && sql_field->length) + { + if (sql_field->sql_type == MYSQL_TYPE_BLOB) + { + /* The user has given a length to the blob column */ + sql_field->sql_type= get_blob_type_from_length(sql_field->length); + sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0); + } + sql_field->length= 0; + } + DBUG_RETURN(0); +} + +////////////////////////////// +// mysql_prepare_create_table() cut and pasted directly from sql_table.cc. +static int +mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, + Alter_info *alter_info, + bool tmp_table, + uint *db_options, + handler *file, KEY **key_info_buffer, + uint *key_count, int select_field_count) +{ + const char *key_name; + Create_field *sql_field,*dup_field; + uint field,null_fields,blob_columns,max_key_length; + ulong record_offset= 0; + KEY *key_info; + KEY_PART_INFO *key_part_info; + int timestamps= 0, timestamps_with_niladic= 0; + int field_no,dup_no; + int select_field_pos,auto_increment=0; + List_iterator<Create_field> it(alter_info->create_list); + List_iterator<Create_field> it2(alter_info->create_list); + uint total_uneven_bit_length= 0; + DBUG_ENTER("mysql_prepare_create_table"); + + select_field_pos= alter_info->create_list.elements - select_field_count; + null_fields=blob_columns=0; + create_info->varchar= 0; + max_key_length= file->max_key_length(); + + for (field_no=0; (sql_field=it++) ; field_no++) + { + CHARSET_INFO *save_cs; + + /* + Initialize length from its original value (number of characters), + which was set in the parser. This is necessary if we're + executing a prepared statement for the second time. + */ + sql_field->length= sql_field->char_length; + if (!sql_field->charset) + sql_field->charset= create_info->default_table_charset; + /* + table_charset is set in ALTER TABLE if we want change character set + for all varchar/char columns. + But the table charset must not affect the BLOB fields, so don't + allow to change my_charset_bin to somethig else. + */ + if (create_info->table_charset && sql_field->charset != &my_charset_bin) + sql_field->charset= create_info->table_charset; + + save_cs= sql_field->charset; + if ((sql_field->flags & BINCMP_FLAG) && + !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname, + MY_CS_BINSORT,MYF(0)))) + { + char tmp[64]; + strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4), + STRING_WITH_LEN("_bin")); + my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp); + DBUG_RETURN(TRUE); + } + + /* + Convert the default value from client character + set into the column character set if necessary. + */ + if (sql_field->def && + save_cs != sql_field->def->collation.collation && + (sql_field->sql_type == MYSQL_TYPE_VAR_STRING || + sql_field->sql_type == MYSQL_TYPE_STRING || + sql_field->sql_type == MYSQL_TYPE_SET || + sql_field->sql_type == MYSQL_TYPE_ENUM)) + { + /* + Starting from 5.1 we work here with a copy of Create_field + created by the caller, not with the instance that was + originally created during parsing. It's OK to create + a temporary item and initialize with it a member of the + copy -- this item will be thrown away along with the copy + at the end of execution, and thus not introduce a dangling + pointer in the parsed tree of a prepared statement or a + stored procedure statement. + */ + sql_field->def= sql_field->def->safe_charset_converter(save_cs); + + if (sql_field->def == NULL) + { + /* Could not convert */ + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + } + + if (sql_field->sql_type == MYSQL_TYPE_SET || + sql_field->sql_type == MYSQL_TYPE_ENUM) + { + uint32 dummy; + CHARSET_INFO *cs= sql_field->charset; + TYPELIB *interval= sql_field->interval; + + /* + Create typelib from interval_list, and if necessary + convert strings from client character set to the + column character set. + */ + if (!interval) + { + /* + Create the typelib in runtime memory - we will free the + occupied memory at the same time when we free this + sql_field -- at the end of execution. + */ + interval= sql_field->interval= typelib(thd->mem_root, + sql_field->interval_list); + List_iterator<String> int_it(sql_field->interval_list); + String conv, *tmp; + char comma_buf[2]; + int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf, + (uchar*) comma_buf + + sizeof(comma_buf)); + DBUG_ASSERT(comma_length > 0); + for (uint i= 0; (tmp= int_it++); i++) + { + uint lengthsp; + if (String::needs_conversion(tmp->length(), tmp->charset(), + cs, &dummy)) + { + uint cnv_errs; + conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs); + interval->type_names[i]= strmake_root(thd->mem_root, conv.ptr(), + conv.length()); + interval->type_lengths[i]= conv.length(); + } + + // Strip trailing spaces. + lengthsp= cs->cset->lengthsp(cs, interval->type_names[i], + interval->type_lengths[i]); + interval->type_lengths[i]= lengthsp; + ((uchar *)interval->type_names[i])[lengthsp]= '\0'; + if (sql_field->sql_type == MYSQL_TYPE_SET) + { + if (cs->coll->instr(cs, interval->type_names[i], + interval->type_lengths[i], + comma_buf, comma_length, NULL, 0)) + { + my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", tmp->ptr()); + DBUG_RETURN(TRUE); + } + } + } + sql_field->interval_list.empty(); // Don't need interval_list anymore + } + + if (sql_field->sql_type == MYSQL_TYPE_SET) + { + uint32 field_length; + if (sql_field->def != NULL) + { + char *not_used; + uint not_used2; + bool not_found= 0; + String str, *def= sql_field->def->val_str(&str); + if (def == NULL) /* SQL "NULL" maps to NULL */ + { + if ((sql_field->flags & NOT_NULL_FLAG) != 0) + { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + + /* else, NULL is an allowed value */ + (void) find_set(interval, NULL, 0, + cs, ¬_used, ¬_used2, ¬_found); + } + else /* not NULL */ + { + (void) find_set(interval, def->ptr(), def->length(), + cs, ¬_used, ¬_used2, ¬_found); + } + + if (not_found) + { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + } + calculate_interval_lengths(cs, interval, &dummy, &field_length); + sql_field->length= field_length + (interval->count - 1); + } + else /* MYSQL_TYPE_ENUM */ + { + uint32 field_length; + DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM); + if (sql_field->def != NULL) + { + String str, *def= sql_field->def->val_str(&str); + if (def == NULL) /* SQL "NULL" maps to NULL */ + { + if ((sql_field->flags & NOT_NULL_FLAG) != 0) + { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + + /* else, the defaults yield the correct length for NULLs. */ + } + else /* not NULL */ + { + def->length(cs->cset->lengthsp(cs, def->ptr(), def->length())); + if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */ + { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + } + } + calculate_interval_lengths(cs, interval, &field_length, &dummy); + sql_field->length= field_length; + } + set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1); + } + + if (sql_field->sql_type == MYSQL_TYPE_BIT) + { + sql_field->pack_flag= FIELDFLAG_NUMBER; + if (file->ha_table_flags() & HA_CAN_BIT_FIELD) + total_uneven_bit_length+= sql_field->length & 7; + else + sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR; + } + + sql_field->create_length_to_internal_length(); + if (prepare_blob_field(thd, sql_field)) + DBUG_RETURN(TRUE); + + if (!(sql_field->flags & NOT_NULL_FLAG)) + null_fields++; + + if (check_column_name(sql_field->field_name)) + { + my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + + /* Check if we have used the same field name before */ + for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++) + { + if (my_strcasecmp(system_charset_info, + sql_field->field_name, + dup_field->field_name) == 0) + { + /* + If this was a CREATE ... SELECT statement, accept a field + redefinition if we are changing a field in the SELECT part + */ + if (field_no < select_field_pos || dup_no >= select_field_pos) + { + my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + else + { + /* Field redefined */ + sql_field->def= dup_field->def; + sql_field->sql_type= dup_field->sql_type; + sql_field->charset= (dup_field->charset ? + dup_field->charset : + create_info->default_table_charset); + sql_field->length= dup_field->char_length; + sql_field->pack_length= dup_field->pack_length; + sql_field->key_length= dup_field->key_length; + sql_field->decimals= dup_field->decimals; + sql_field->create_length_to_internal_length(); + sql_field->unireg_check= dup_field->unireg_check; + /* + We're making one field from two, the result field will have + dup_field->flags as flags. If we've incremented null_fields + because of sql_field->flags, decrement it back. + */ + if (!(sql_field->flags & NOT_NULL_FLAG)) + null_fields--; + sql_field->flags= dup_field->flags; + sql_field->interval= dup_field->interval; + it2.remove(); // Remove first (create) definition + select_field_pos--; + break; + } + } + } + /* Don't pack rows in old tables if the user has requested this */ + if ((sql_field->flags & BLOB_FLAG) || + sql_field->sql_type == MYSQL_TYPE_VARCHAR && + create_info->row_type != ROW_TYPE_FIXED) + (*db_options)|= HA_OPTION_PACK_RECORD; + it2.rewind(); + } + + /* record_offset will be increased with 'length-of-null-bits' later */ + record_offset= 0; + null_fields+= total_uneven_bit_length; + + it.rewind(); + while ((sql_field=it++)) + { + DBUG_ASSERT(sql_field->charset != 0); + + if (prepare_create_field(sql_field, &blob_columns, + ×tamps, ×tamps_with_niladic, + file->ha_table_flags())) + DBUG_RETURN(TRUE); + if (sql_field->sql_type == MYSQL_TYPE_VARCHAR) + create_info->varchar= TRUE; + sql_field->offset= record_offset; + if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) + auto_increment++; + record_offset+= sql_field->pack_length; + } + if (timestamps_with_niladic > 1) + { + my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS, + ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0)); + DBUG_RETURN(TRUE); + } + if (auto_increment > 1) + { + my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0)); + DBUG_RETURN(TRUE); + } + if (auto_increment && + (file->ha_table_flags() & HA_NO_AUTO_INCREMENT)) + { + my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, + ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0)); + DBUG_RETURN(TRUE); + } + + if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS)) + { + my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB), + MYF(0)); + DBUG_RETURN(TRUE); + } + + /* Create keys */ + + List_iterator<Key> key_iterator(alter_info->key_list); + List_iterator<Key> key_iterator2(alter_info->key_list); + uint key_parts=0, fk_key_count=0; + bool primary_key=0,unique_key=0; + Key *key, *key2; + uint tmp, key_number; + /* special marker for keys to be ignored */ + static char ignore_key[1]; + + /* Calculate number of key segements */ + *key_count= 0; + + while ((key=key_iterator++)) + { + DBUG_PRINT("info", ("key name: '%s' type: %d", key->DOT_STR(name) ? key->DOT_STR(name) : + "(none)" , key->type)); + LEX_STRING key_name_str; + if (key->type == Key::FOREIGN_KEY) + { + fk_key_count++; + Foreign_key *fk_key= (Foreign_key*) key; + if (fk_key->ref_columns.elements && + fk_key->ref_columns.elements != fk_key->columns.elements) + { + my_error(ER_WRONG_FK_DEF, MYF(0), + (fk_key->DOT_STR(name) ? fk_key->DOT_STR(name) : "foreign key without name"), + ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF)); + DBUG_RETURN(TRUE); + } + continue; + } + (*key_count)++; + tmp=file->max_key_parts(); + if (key->columns.elements > tmp) + { + my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp); + DBUG_RETURN(TRUE); + } + key_name_str.str= (char*) key->DOT_STR(name); + key_name_str.length= key->DOT_STR(name) ? strlen(key->DOT_STR(name)) : 0; + if (check_string_char_length(&key_name_str, "", NAME_CHAR_LEN, + system_charset_info, 1)) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), key->DOT_STR(name)); + DBUG_RETURN(TRUE); + } + key_iterator2.rewind (); + if (key->type != Key::FOREIGN_KEY) + { + while ((key2 = key_iterator2++) != key) + { + /* + foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is + 'generated', and a generated key is a prefix of the other key. + Then we do not need the generated shorter key. + */ + if ((key2->type != Key::FOREIGN_KEY && + key2->DOT_STR(name) != ignore_key && + !foreign_key_prefix(key, key2))) + { + /* TODO: issue warning message */ + /* mark that the generated key should be ignored */ + if (!key2->generated || + (key->generated && key->columns.elements < + key2->columns.elements)) + key->DOT_STR(name)= ignore_key; + else + { + key2->DOT_STR(name)= ignore_key; + key_parts-= key2->columns.elements; + (*key_count)--; + } + break; + } + } + } + if (key->DOT_STR(name) != ignore_key) + key_parts+=key->columns.elements; + else + (*key_count)--; + if (key->DOT_STR(name) && !tmp_table && (key->type != Key::PRIMARY) && + !my_strcasecmp(system_charset_info,key->DOT_STR(name),primary_key_name)) + { + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->DOT_STR(name)); + DBUG_RETURN(TRUE); + } + } + tmp=file->max_keys(); + if (*key_count > tmp) + { + my_error(ER_TOO_MANY_KEYS,MYF(0),tmp); + DBUG_RETURN(TRUE); + } + + (*key_info_buffer)= key_info= (KEY*) sql_calloc(sizeof(KEY) * (*key_count)); + key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts); + if (!*key_info_buffer || ! key_part_info) + DBUG_RETURN(TRUE); // Out of memory + + key_iterator.rewind(); + key_number=0; + for (; (key=key_iterator++) ; key_number++) + { + uint key_length=0; + Key_part_spec *column; + + if (key->DOT_STR(name) == ignore_key) + { + /* ignore redundant keys */ + do + key=key_iterator++; + while (key && key->DOT_STR(name) == ignore_key); + if (!key) + break; + } + + switch (key->type) { + case Key::MULTIPLE: + key_info->flags= 0; + break; + case Key::FULLTEXT: + key_info->flags= HA_FULLTEXT; + if ((key_info->parser_name= &key->key_create_info.parser_name)->str) + key_info->flags|= HA_USES_PARSER; + else + key_info->parser_name= 0; + break; + case Key::SPATIAL: +#ifdef HAVE_SPATIAL + key_info->flags= HA_SPATIAL; + break; +#else + my_error(ER_FEATURE_DISABLED, MYF(0), + sym_group_geom.name, sym_group_geom.needed_define); + DBUG_RETURN(TRUE); +#endif + case Key::FOREIGN_KEY: + key_number--; // Skip this key + continue; + default: + key_info->flags = HA_NOSAME; + break; + } + if (key->generated) + key_info->flags|= HA_GENERATED_KEY; + + key_info->key_parts=(uint8) key->columns.elements; + key_info->key_part=key_part_info; + key_info->usable_key_parts= key_number; + key_info->algorithm= key->key_create_info.algorithm; + + if (key->type == Key::FULLTEXT) + { + if (!(file->ha_table_flags() & HA_CAN_FULLTEXT)) + { + my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT), + MYF(0)); + DBUG_RETURN(TRUE); + } + } + /* + Make SPATIAL to be RTREE by default + SPATIAL only on BLOB or at least BINARY, this + actually should be replaced by special GEOM type + in near future when new frm file is ready + checking for proper key parts number: + */ + + /* TODO: Add proper checks if handler supports key_type and algorithm */ + if (key_info->flags & HA_SPATIAL) + { + if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS)) + { + my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS), + MYF(0)); + DBUG_RETURN(TRUE); + } + if (key_info->key_parts != 1) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX"); + DBUG_RETURN(TRUE); + } + } + else if (key_info->algorithm == HA_KEY_ALG_RTREE) + { +#ifdef HAVE_RTREE_KEYS + if ((key_info->key_parts & 1) == 1) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX"); + DBUG_RETURN(TRUE); + } + /* TODO: To be deleted */ + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX"); + DBUG_RETURN(TRUE); +#else + my_error(ER_FEATURE_DISABLED, MYF(0), + sym_group_rtree.name, sym_group_rtree.needed_define); + DBUG_RETURN(TRUE); +#endif + } + + /* Take block size from key part or table part */ + /* + TODO: Add warning if block size changes. We can't do it here, as + this may depend on the size of the key + */ + key_info->block_size= (key->key_create_info.block_size ? + key->key_create_info.block_size : + create_info->key_block_size); + + if (key_info->block_size) + key_info->flags|= HA_USES_BLOCK_SIZE; + + List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns); + CHARSET_INFO *ft_key_charset=0; // for FULLTEXT + for (uint column_nr=0 ; (column=cols++) ; column_nr++) + { + uint length; + Key_part_spec *dup_column; + + it.rewind(); + field=0; + while ((sql_field=it++) && + my_strcasecmp(system_charset_info, + column->DOT_STR(field_name), + sql_field->field_name)) + field++; + if (!sql_field) + { + my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name); + DBUG_RETURN(TRUE); + } + while ((dup_column= cols2++) != column) + { + if (!my_strcasecmp(system_charset_info, + column->DOT_STR(field_name), dup_column->DOT_STR(field_name))) + { + my_printf_error(ER_DUP_FIELDNAME, + ER(ER_DUP_FIELDNAME),MYF(0), + column->field_name); + DBUG_RETURN(TRUE); + } + } + cols2.rewind(); + if (key->type == Key::FULLTEXT) + { + if ((sql_field->sql_type != MYSQL_TYPE_STRING && + sql_field->sql_type != MYSQL_TYPE_VARCHAR && + !f_is_blob(sql_field->pack_flag)) || + sql_field->charset == &my_charset_bin || + sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet + (ft_key_charset && sql_field->charset != ft_key_charset)) + { + my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name); + DBUG_RETURN(-1); + } + ft_key_charset=sql_field->charset; + /* + for fulltext keys keyseg length is 1 for blobs (it's ignored in ft + code anyway, and 0 (set to column width later) for char's. it has + to be correct col width for char's, as char data are not prefixed + with length (unlike blobs, where ft code takes data length from a + data prefix, ignoring column->length). + */ + column->length=test(f_is_blob(sql_field->pack_flag)); + } + else + { + column->length*= sql_field->charset->mbmaxlen; + + if (key->type == Key::SPATIAL && column->length) + { + my_error(ER_WRONG_SUB_KEY, MYF(0)); + DBUG_RETURN(TRUE); + } + + if (f_is_blob(sql_field->pack_flag) || + (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL)) + { + if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS)) + { + my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name); + DBUG_RETURN(TRUE); + } + if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type == + Field::GEOM_POINT) + column->length= 25; + if (!column->length) + { + my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name); + DBUG_RETURN(TRUE); + } + } +#ifdef HAVE_SPATIAL + if (key->type == Key::SPATIAL) + { + if (!column->length) + { + /* + 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case + Lately we'll extend this code to support more dimensions + */ + column->length= 4*sizeof(double); + } + } +#endif + if (!(sql_field->flags & NOT_NULL_FLAG)) + { + if (key->type == Key::PRIMARY) + { + /* Implicitly set primary key fields to NOT NULL for ISO conf. */ + sql_field->flags|= NOT_NULL_FLAG; + sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL; + null_fields--; + } + else + { + key_info->flags|= HA_NULL_PART_KEY; + if (!(file->ha_table_flags() & HA_NULL_IN_KEY)) + { + my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name); + DBUG_RETURN(TRUE); + } + if (key->type == Key::SPATIAL) + { + my_message(ER_SPATIAL_CANT_HAVE_NULL, + ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0)); + DBUG_RETURN(TRUE); + } + } + } + if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) + { + if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY)) + auto_increment--; // Field is used + } + } + + key_part_info->fieldnr= field; + key_part_info->offset= (uint16) sql_field->offset; + key_part_info->key_type=sql_field->pack_flag; + length= sql_field->key_length; + + if (column->length) + { + if (f_is_blob(sql_field->pack_flag)) + { + if ((length=column->length) > max_key_length || + length > file->max_key_part_length()) + { + length=min(max_key_length, file->max_key_part_length()); + if (key->type == Key::MULTIPLE) + { + /* not a critical problem */ + char warn_buff[MYSQL_ERRMSG_SIZE]; + my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY), + length); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TOO_LONG_KEY, warn_buff); + /* Align key length to multibyte char boundary */ + length-= length % sql_field->charset->mbmaxlen; + } + else + { + my_error(ER_TOO_LONG_KEY,MYF(0),length); + DBUG_RETURN(TRUE); + } + } + } + else if (!f_is_geom(sql_field->pack_flag) && + (column->length > length || + !Field::type_can_have_key_part (sql_field->sql_type) || + ((f_is_packed(sql_field->pack_flag) || + ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) && + (key_info->flags & HA_NOSAME))) && + column->length != length))) + { + my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0)); + DBUG_RETURN(TRUE); + } + else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS)) + length=column->length; + } + else if (length == 0) + { + my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name); + DBUG_RETURN(TRUE); + } + if (length > file->max_key_part_length() && key->type != Key::FULLTEXT) + { + length= file->max_key_part_length(); + if (key->type == Key::MULTIPLE) + { + /* not a critical problem */ + char warn_buff[MYSQL_ERRMSG_SIZE]; + my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY), + length); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TOO_LONG_KEY, warn_buff); + /* Align key length to multibyte char boundary */ + length-= length % sql_field->charset->mbmaxlen; + } + else + { + my_error(ER_TOO_LONG_KEY,MYF(0),length); + DBUG_RETURN(TRUE); + } + } + key_part_info->length=(uint16) length; + /* Use packed keys for long strings on the first column */ + if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) && + (length >= KEY_DEFAULT_PACK_LENGTH && + (sql_field->sql_type == MYSQL_TYPE_STRING || + sql_field->sql_type == MYSQL_TYPE_VARCHAR || + sql_field->pack_flag & FIELDFLAG_BLOB))) + { + if (column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB) || + sql_field->sql_type == MYSQL_TYPE_VARCHAR) + key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY; + else + key_info->flags|= HA_PACK_KEY; + } + /* Check if the key segment is partial, set the key flag accordingly */ + if (length != sql_field->key_length) + key_info->flags|= HA_KEY_HAS_PART_KEY_SEG; + + key_length+=length; + key_part_info++; + + /* Create the key name based on the first column (if not given) */ + if (column_nr == 0) + { + if (key->type == Key::PRIMARY) + { + if (primary_key) + { + my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY), + MYF(0)); + DBUG_RETURN(TRUE); + } + key_name=primary_key_name; + primary_key=1; + } + else if (!(key_name = key->DOT_STR(name))) + key_name=make_unique_key_name(sql_field->field_name, + *key_info_buffer, key_info); + if (check_if_keyname_exists(key_name, *key_info_buffer, key_info)) + { + my_error(ER_DUP_KEYNAME, MYF(0), key_name); + DBUG_RETURN(TRUE); + } + key_info->name=(char*) key_name; + } + } + if (!key_info->name || check_column_name(key_info->name)) + { + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name); + DBUG_RETURN(TRUE); + } + if (!(key_info->flags & HA_NULL_PART_KEY)) + unique_key=1; + key_info->key_length=(uint16) key_length; + if (key_length > max_key_length && key->type != Key::FULLTEXT) + { + my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length); + DBUG_RETURN(TRUE); + } + key_info++; + } + if (!unique_key && !primary_key && + (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY)) + { + my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0)); + DBUG_RETURN(TRUE); + } + if (auto_increment > 0) + { + my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0)); + DBUG_RETURN(TRUE); + } + /* Sort keys in optimized order */ + my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY), + (qsort_cmp) sort_keys); + create_info->null_bits= null_fields; + + /* Check fields. */ + it.rewind(); + while ((sql_field=it++)) + { + Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check); + + if (thd->variables.sql_mode & MODE_NO_ZERO_DATE && + !sql_field->def && + sql_field->sql_type == MYSQL_TYPE_TIMESTAMP && + (sql_field->flags & NOT_NULL_FLAG) && + (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD)) + { + /* + An error should be reported if: + - NO_ZERO_DATE SQL mode is active; + - there is no explicit DEFAULT clause (default column value); + - this is a TIMESTAMP column; + - the column is not NULL; + - this is not the DEFAULT CURRENT_TIMESTAMP column. + + In other words, an error should be reported if + - NO_ZERO_DATE SQL mode is active; + - the column definition is equivalent to + 'column_name TIMESTAMP DEFAULT 0'. + */ + + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + } + + DBUG_RETURN(FALSE); +} + +////////////////////////////// +// mysql_create_table_no_lock() cut and pasted directly from sql_table.cc. (I did make is static after copying it.) + +static bool mysql_create_table_no_lock(THD *thd, + const char *db, const char *table_name, + HA_CREATE_INFO *create_info, + Alter_info *alter_info, + bool internal_tmp_table, + uint select_field_count) +{ + char path[FN_REFLEN]; + uint path_length; + const char *alias; + uint db_options, key_count; + KEY *key_info_buffer; + handler *file; + bool error= TRUE; + DBUG_ENTER("mysql_create_table_no_lock"); + DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d", + db, table_name, internal_tmp_table)); + + + /* Check for duplicate fields and check type of table to create */ + if (!alter_info->create_list.elements) + { + my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS), + MYF(0)); + DBUG_RETURN(TRUE); + } + if (check_engine(thd, table_name, create_info)) + DBUG_RETURN(TRUE); + db_options= create_info->table_options; + if (create_info->row_type == ROW_TYPE_DYNAMIC) + db_options|=HA_OPTION_PACK_RECORD; + alias= table_case_name(create_info, table_name); + + /* PMC - Done to avoid getting the partition handler by mistake! */ + if (!(file= new (thd->mem_root) ha_xtsys(pbxt_hton, NULL))) + { + mem_alloc_error(sizeof(handler)); + DBUG_RETURN(TRUE); + } + + set_table_default_charset(thd, create_info, (char*) db); + + if (mysql_prepare_create_table(thd, create_info, alter_info, + internal_tmp_table, + &db_options, file, + &key_info_buffer, &key_count, + select_field_count)) + goto err; + + /* Check if table exists */ + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + path_length= build_tmptable_filename(thd, path, sizeof(path)); + create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE; + } + else + { + #ifdef FN_DEVCHAR + /* check if the table name contains FN_DEVCHAR when defined */ + if (strchr(alias, FN_DEVCHAR)) + { + my_error(ER_WRONG_TABLE_NAME, MYF(0), alias); + DBUG_RETURN(TRUE); + } +#endif + path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext, + internal_tmp_table ? FN_IS_TMP : 0); + } + + /* Check if table already exists */ + if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) && + find_temporary_table(thd, db, table_name)) + { + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + create_info->table_existed= 1; // Mark that table existed + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + alias); + error= 0; + goto err; + } + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); + goto err; + } + + pthread_mutex_lock(&LOCK_open); + if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) + { + if (!access(path,F_OK)) + { + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + goto warn; + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + goto unlock_and_end; + } + /* + We don't assert here, but check the result, because the table could be + in the table definition cache and in the same time the .frm could be + missing from the disk, in case of manual intervention which deletes + the .frm file. The user has to use FLUSH TABLES; to clear the cache. + Then she could create the table. This case is pretty obscure and + therefore we don't introduce a new error message only for it. + */ + if (get_cached_table_share(db, alias)) + { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); + goto unlock_and_end; + } + } + + /* + Check that table with given name does not already + exist in any storage engine. In such a case it should + be discovered and the error ER_TABLE_EXISTS_ERROR be returned + unless user specified CREATE TABLE IF EXISTS + The LOCK_open mutex has been locked to make sure no + one else is attempting to discover the table. Since + it's not on disk as a frm file, no one could be using it! + */ + if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) + { + bool create_if_not_exists = + create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS; + int retcode = ha_table_exists_in_engine(thd, db, table_name); + DBUG_PRINT("info", ("exists_in_engine: %u",retcode)); + switch (retcode) + { + case HA_ERR_NO_SUCH_TABLE: + /* Normal case, no table exists. we can go and create it */ + break; + case HA_ERR_TABLE_EXIST: + DBUG_PRINT("info", ("Table existed in handler")); + + if (create_if_not_exists) + goto warn; + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + goto unlock_and_end; + break; + default: + DBUG_PRINT("info", ("error: %u from storage engine", retcode)); + my_error(retcode, MYF(0),table_name); + goto unlock_and_end; + } + } + + thd_proc_info(thd, "creating table"); + create_info->table_existed= 0; // Mark that table is created + + create_info->table_options=db_options; + + path[path_length - reg_ext_length]= '\0'; // Remove .frm extension + if (rea_create_table(thd, path, db, table_name, + create_info, alter_info->create_list, + key_count, key_info_buffer, file)) + goto unlock_and_end; + + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + /* Open table and put in temporary table list */ +#if MYSQL_VERSION_ID > 60005 + if (!(open_temporary_table(thd, path, db, table_name, 1, OTM_OPEN))) +#else + if (!(open_temporary_table(thd, path, db, table_name, 1))) +#endif + { +#if MYSQL_VERSION_ID > 60005 + (void) rm_temporary_table(create_info->db_type, path, false); +#else + (void) rm_temporary_table(create_info->db_type, path); +#endif + goto unlock_and_end; + } + thd->thread_specific_used= TRUE; + } + + /* + Don't write statement if: + - It is an internal temporary table, + - Row-based logging is used and it we are creating a temporary table, or + - The binary log is not open. + Otherwise, the statement shall be binlogged. + */ + if (!internal_tmp_table && + (!thd->current_stmt_binlog_row_based || + (thd->current_stmt_binlog_row_based && + !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) + write_bin_log(thd, TRUE, thd->query, thd->query_length); + error= FALSE; +unlock_and_end: + pthread_mutex_unlock(&LOCK_open); + +err: + thd_proc_info(thd, "After create"); + delete file; + DBUG_RETURN(error); + +warn: + error= FALSE; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + alias); + create_info->table_existed= 1; // Mark that table existed + goto unlock_and_end; +} + +//////////////////////////////////////////////////////// +////// END OF CUT AND PASTES FROM sql_table.cc //////// +//////////////////////////////////////////////////////// + +#endif // LOCK_OPEN_HACK_REQUIRED + +//------------------------------ +int xt_create_table_frm(handlerton *hton, THD* thd, const char *db, const char *name, DT_FIELD_INFO *info, DT_KEY_INFO *keys __attribute__((unused)), xtBool skip_existing) +{ +#ifdef DRIZZLED + static const char *ext = ".dfe"; + static const int ext_len = 4; +#else + static const char *ext = ".frm"; + static const int ext_len = 4; +#endif + int err = 1; + //HA_CREATE_INFO create_info = {0}; + //Alter_info alter_info; + char field_length_buffer[12], *field_length_ptr; + LEX *save_lex= thd->lex, mylex; + + memset(&mylex.create_info, 0, sizeof(HA_CREATE_INFO)); + + thd->lex = &mylex; + lex_start(thd); + + /* setup the create info */ + mylex.create_info.db_type = hton; +#ifndef DRIZZLED + mylex.create_info.frm_only = 1; +#endif + mylex.create_info.default_table_charset = system_charset_info; + + /* setup the column info. */ + while (info->field_name) { + LEX_STRING field_name, comment; + field_name.str = (char*)(info->field_name); + field_name.length = strlen(info->field_name); + + comment.str = (char*)(info->comment); + comment.length = strlen(info->comment); + + if (info->field_length) { + sprintf(field_length_buffer, "%d", info->field_length); + field_length_ptr = field_length_buffer; + } else + field_length_ptr = NULL; + +#ifdef DRIZZLED + if (add_field_to_list(thd, &field_name, info->field_type, field_length_ptr, info->field_decimal_length, + info->field_flags, + COLUMN_FORMAT_TYPE_FIXED, + NULL /*default_value*/, NULL /*on_update_value*/, &comment, NULL /*change*/, + NULL /*interval_list*/, info->field_charset, + NULL /*vcol_info*/)) +#else + if (add_field_to_list(thd, &field_name, info->field_type, field_length_ptr, info->field_decimal_length, + info->field_flags, +#if MYSQL_VERSION_ID > 60005 + HA_SM_DISK, + COLUMN_FORMAT_TYPE_FIXED, +#endif + NULL /*default_value*/, NULL /*on_update_value*/, &comment, NULL /*change*/, + NULL /*interval_list*/, info->field_charset, 0 /*uint_geom_type*/)) +#endif + goto error; + + + info++; + } + + if (skip_existing) { + size_t db_len = strlen(db); + size_t name_len = strlen(name); + size_t len = db_len + 1 + name_len + ext_len + 1; + char *path = (char *)xt_malloc_ns(len); + memcpy(path, db, db_len); + memcpy(path + db_len + 1, name, name_len); + memcpy(path + db_len + 1 + name_len, ext, ext_len); + path[db_len] = XT_DIR_CHAR; + path[len - 1] = '\0'; + xtBool exists = xt_fs_exists(path); + xt_free_ns(path); + if (exists) + goto noerror; + } + + /* Create an internal temp table */ +#ifdef DRIZZLED + if (mysql_create_table_no_lock(thd, db, name, &mylex.create_info, &mylex.alter_info, 1, 0, false)) + goto error; +#else + if (mysql_create_table_no_lock(thd, db, name, &mylex.create_info, &mylex.alter_info, 1, 0)) + goto error; +#endif + + noerror: + err = 0; + + error: + lex_end(&mylex); + thd->lex = save_lex; + return err; +} + diff --git a/storage/pbxt/src/discover_xt.h b/storage/pbxt/src/discover_xt.h new file mode 100644 index 00000000000..733974ad59f --- /dev/null +++ b/storage/pbxt/src/discover_xt.h @@ -0,0 +1,79 @@ +/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Created by Leslie on 8/27/08. + * + */ + +#ifndef __DISCOVER_XT_H__ +#define __DISCOVER_XT_H__ + +#ifdef DRIZZLED +#include <drizzled/common.h> +#else +#include "mysql_priv.h" +#endif + +/* + * --------------------------------------------------------------- + * TABLE DISCOVERY HANDLER + */ + +typedef struct dt_field_info { + /** + This is used as column name. + */ + const char* field_name; + /** + For string-type columns, this is the maximum number of + characters. For numeric data this can be NULL. + */ + uint field_length; + + /** + For decimal columns, this is the maximum number of + digits after the decimal. For other data this can be NULL. + */ + char* field_decimal_length; + /** + This denotes data type for the column. For the most part, there seems to + be one entry in the enum for each SQL data type, although there seem to + be a number of additional entries in the enum. + */ + enum enum_field_types field_type; + + /** + This is the charater set for non numeric data types including blob data. + */ + CHARSET_INFO *field_charset; + + uint field_flags; // Field atributes(maybe_null, signed, unsigned etc.) + const char* comment; +} DT_FIELD_INFO; + +typedef struct dt_key_info +{ + const char* key_name; + uint key_type; /* PRI_KEY_FLAG, UNIQUE_KEY_FLAG, MULTIPLE_KEY_FLAG */ + const char* key_columns[8]; // The size of this can be set to what ever you need. +} DT_KEY_INFO; + +int xt_create_table_frm(handlerton *hton, THD* thd, const char *db, const char *name, DT_FIELD_INFO *info, DT_KEY_INFO *keys, xtBool skip_existing); + +#endif + diff --git a/storage/pbxt/src/filesys_xt.cc b/storage/pbxt/src/filesys_xt.cc new file mode 100644 index 00000000000..5ca36cd9244 --- /dev/null +++ b/storage/pbxt/src/filesys_xt.cc @@ -0,0 +1,1697 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-12 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#ifndef XT_WIN +#include <unistd.h> +#include <dirent.h> +#include <sys/mman.h> +#endif +#include <stdio.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/types.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> + +#include "strutil_xt.h" +#include "pthread_xt.h" +#include "thread_xt.h" +#include "filesys_xt.h" +#include "memory_xt.h" +#include "cache_xt.h" +#include "sortedlist_xt.h" +#include "trace_xt.h" + +#ifdef DEBUG +//#define DEBUG_PRINT_IO +//#define DEBUG_TRACE_IO +//#define DEBUG_TRACE_MAP_IO +//#define DEBUG_TRACE_FILES +#endif + +#ifdef DEBUG_TRACE_FILES +//#define PRINTF xt_ftracef +#define PRINTF xt_trace +#endif + +/* ---------------------------------------------------------------------- + * Globals + */ + +typedef struct FsGlobals { + xt_mutex_type *fsg_lock; /* The xtPublic cache lock. */ + u_int fsg_current_id; + XTSortedListPtr fsg_open_files; +} FsGlobalsRec; + +static FsGlobalsRec fs_globals; + +#ifdef XT_WIN +static int fs_get_win_error() +{ + return (int) GetLastError(); +} + +xtPublic void xt_get_win_message(char *buffer, size_t size, int err) +{ + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buffer, + size, NULL); +} +#endif + +/* ---------------------------------------------------------------------- + * Open file list + */ + +static XTFilePtr fs_new_file(XTThreadPtr self, char *file) +{ + XTFilePtr file_ptr; + + pushsr_(file_ptr, xt_free, (XTFilePtr) xt_calloc(self, sizeof(XTFileRec))); + + file_ptr->fil_path = xt_dup_string(self, file); + file_ptr->fil_id = fs_globals.fsg_current_id++; +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: allocated file: (%d) %s\n", self->t_name, (int) file_ptr->fil_id, xt_last_2_names_of_path(file_ptr->fil_path)); +#endif + if (!fs_globals.fsg_current_id) + fs_globals.fsg_current_id++; + file_ptr->fil_filedes = XT_NULL_FD; + file_ptr->fil_handle_count = 0; + + popr_(); // Discard xt_free(file_ptr) + return file_ptr; +} + +static void fs_close_fmap(XTThreadPtr self, XTFileMemMapPtr mm) +{ +#ifdef XT_WIN + if (mm->mm_start) { + FlushViewOfFile(mm->mm_start, 0); + UnmapViewOfFile(mm->mm_start); + mm->mm_start = NULL; + } + if (mm->mm_mapdes != NULL) { + CloseHandle(mm->mm_mapdes); + mm->mm_mapdes = NULL; + } +#else + if (mm->mm_start) { + msync( (char *)mm->mm_start, (size_t) mm->mm_length, MS_SYNC); + munmap((caddr_t) mm->mm_start, (size_t) mm->mm_length); + mm->mm_start = NULL; + } +#endif + xt_rwmutex_free(self, &mm->mm_lock); + xt_free(self, mm); +} + +static void fs_free_file(XTThreadPtr self, void *thunk __attribute__((unused)), void *item) +{ + XTFilePtr file_ptr = *((XTFilePtr *) item); + + if (file_ptr->fil_filedes != XT_NULL_FD) { +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: close file: (%d) %s\n", self->t_name, (int) file_ptr->fil_id, xt_last_2_names_of_path(file_ptr->fil_path)); +#endif +#ifdef XT_WIN + CloseHandle(file_ptr->fil_filedes); +#else + close(file_ptr->fil_filedes); +#endif + //PRINTF("close (FILE) %d %s\n", file_ptr->fil_filedes, file_ptr->fil_path); + file_ptr->fil_filedes = XT_NULL_FD; + } + + if (file_ptr->fil_memmap) { + fs_close_fmap(self, file_ptr->fil_memmap); + file_ptr->fil_memmap = NULL; + } + +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: free file: (%d) %s\n", self->t_name, (int) file_ptr->fil_id, + file_ptr->fil_path ? xt_last_2_names_of_path(file_ptr->fil_path) : "?"); +#endif + + if (!file_ptr->fil_ref_count) { + /* Flush any cache before this file is invalid: */ + if (file_ptr->fil_path) { + xt_free(self, file_ptr->fil_path); + file_ptr->fil_path = NULL; + } + + xt_free(self, file_ptr); + } +} + +static int fs_comp_file(XTThreadPtr self __attribute__((unused)), register const void *thunk __attribute__((unused)), register const void *a, register const void *b) +{ + char *file_name = (char *) a; + XTFilePtr file_ptr = *((XTFilePtr *) b); + + return strcmp(file_name, file_ptr->fil_path); +} + +static int fs_comp_file_ci(XTThreadPtr self __attribute__((unused)), register const void *thunk __attribute__((unused)), register const void *a, register const void *b) +{ + char *file_name = (char *) a; + XTFilePtr file_ptr = *((XTFilePtr *) b); + + return strcasecmp(file_name, file_ptr->fil_path); +} + +/* ---------------------------------------------------------------------- + * init & exit + */ + +xtPublic void xt_fs_init(XTThreadPtr self) +{ + fs_globals.fsg_open_files = xt_new_sortedlist(self, + sizeof(XTFilePtr), 20, 20, + pbxt_ignore_case ? fs_comp_file_ci : fs_comp_file, + NULL, fs_free_file, TRUE, FALSE); + fs_globals.fsg_lock = fs_globals.fsg_open_files->sl_lock; + fs_globals.fsg_current_id = 1; +} + +xtPublic void xt_fs_exit(XTThreadPtr self) +{ + if (fs_globals.fsg_open_files) { + xt_free_sortedlist(self, fs_globals.fsg_open_files); + fs_globals.fsg_open_files = NULL; + } + fs_globals.fsg_lock = NULL; + fs_globals.fsg_current_id = 0; +} + +/* ---------------------------------------------------------------------- + * File operations + */ + +static void fs_set_stats(XTThreadPtr self, char *path) +{ + char super_path[PATH_MAX]; + struct stat stats; + char *ptr; + + ptr = xt_last_name_of_path(path); + if (ptr == path) + strcpy(super_path, "."); + else { + xt_strcpy(PATH_MAX, super_path, path); + + if ((ptr = xt_last_name_of_path(super_path))) + *ptr = 0; + } + if (stat(super_path, &stats) == -1) + xt_throw_ferrno(XT_CONTEXT, errno, super_path); + + if (chmod(path, stats.st_mode) == -1) + xt_throw_ferrno(XT_CONTEXT, errno, path); + + /*chown(path, stats.st_uid, stats.st_gid);*/ +} + +xtPublic char *xt_file_path(struct XTFileRef *of) +{ + return of->fr_file->fil_path; +} + +xtBool xt_fs_exists(char *path) +{ + int err; + + err = access(path, F_OK); + if (err == -1) + return FALSE; + return TRUE; +} + +/* + * No error is generated if the file dose not exist. + */ +xtPublic xtBool xt_fs_delete(XTThreadPtr self, char *name) +{ +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: DELETE FILE: %s\n", xt_get_self()->t_name, xt_last_2_names_of_path(name)); +#endif +#ifdef XT_WIN + //PRINTF("delete %s\n", name); + if (!DeleteFile(name)) { + int err = fs_get_win_error(); + + if (!XT_FILE_NOT_FOUND(err)) { + xt_throw_ferrno(XT_CONTEXT, err, name); + return FAILED; + } + } +#else + if (unlink(name) == -1) { + int err = errno; + + if (err != ENOENT) { + xt_throw_ferrno(XT_CONTEXT, err, name); + return FAILED; + } + } +#endif + return OK; +} + +xtPublic xtBool xt_fs_file_not_found(int err) +{ +#ifdef XT_WIN + return XT_FILE_NOT_FOUND(err); +#else + return err == ENOENT; +#endif +} + +xtPublic void xt_fs_move(struct XTThread *self, char *from_path, char *to_path) +{ +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: MOVE FILE: %s --> %s\n", xt_get_self()->t_name, xt_last_2_names_of_path(from_path), xt_last_2_names_of_path(to_path)); +#endif +#ifdef XT_WIN + if (!MoveFile(from_path, to_path)) + xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), from_path); +#else + int err; + + if (link(from_path, to_path) == -1) { + err = errno; + xt_throw_ferrno(XT_CONTEXT, err, from_path); + } + + if (unlink(from_path) == -1) { + err = errno; + unlink(to_path); + xt_throw_ferrno(XT_CONTEXT, err, from_path); + } +#endif +} + +xtPublic xtBool xt_fs_rename(struct XTThread *self, char *from_path, char *to_path) +{ + int err; + +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: RENAME FILE: %s --> %s\n", xt_get_self()->t_name, xt_last_2_names_of_path(from_path), xt_last_2_names_of_path(to_path)); +#endif + if (rename(from_path, to_path) == -1) { + err = errno; + xt_throw_ferrno(XT_CONTEXT, err, from_path); + return FAILED; + } + return OK; +} + +xtPublic xtBool xt_fs_stat(XTThreadPtr self, char *path, off_t *size, struct timespec *mod_time) +{ +#ifdef XT_WIN + HANDLE fh; + BY_HANDLE_FILE_INFORMATION info; + SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 }; + + fh = CreateFile( + path, + GENERIC_READ, + FILE_SHARE_READ, + &sa, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (fh == INVALID_HANDLE_VALUE) { + xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path); + return FAILED; + } + + if (!GetFileInformationByHandle(fh, &info)) { + CloseHandle(fh); + xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path); + return FAILED; + } + + CloseHandle(fh); + if (size) + *size = (off_t) info.nFileSizeLow | (((off_t) info.nFileSizeHigh) << 32); + if (mod_time) + mod_time->tv.ft = info.ftLastWriteTime; +#else + struct stat sb; + + if (stat(path, &sb) == -1) { + xt_throw_ferrno(XT_CONTEXT, errno, path); + return FAILED; + } + if (size) + *size = sb.st_size; + if (mod_time) { + mod_time->tv_sec = sb.st_mtime; +#ifdef XT_MAC + /* This is the Mac OS X version: */ + mod_time->tv_nsec = sb.st_mtimespec.tv_nsec; +#else +#ifdef __USE_MISC + /* This is the Linux version: */ + mod_time->tv_nsec = sb.st_mtim.tv_nsec; +#else + /* Not supported? */ + mod_time->tv_nsec = 0; +#endif +#endif + } +#endif + return OK; +} + +void xt_fs_mkdir(XTThreadPtr self, char *name) +{ + char path[PATH_MAX]; + + xt_strcpy(PATH_MAX, path, name); + xt_remove_dir_char(path); + +#ifdef XT_WIN + { + SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 }; + + if (!CreateDirectory(path, &sa)) + xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), path); + } +#else + if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == -1) + xt_throw_ferrno(XT_CONTEXT, errno, path); + + try_(a) { + fs_set_stats(self, path); + } + catch_(a) { + xt_fs_rmdir(NULL, name); + throw_(); + } + cont_(a); +#endif +} + +void xt_fs_mkpath(XTThreadPtr self, char *path) +{ + char *ptr; + + if (xt_fs_exists(path)) + return; + + if (!(ptr = (char *) xt_last_directory_of_path((c_char *) path))) + return; + if (ptr == path) + return; + ptr--; + if (XT_IS_DIR_CHAR(*ptr)) { + *ptr = 0; + xt_fs_mkpath(self, path); + *ptr = XT_DIR_CHAR; + xt_fs_mkdir(self, path); + } +} + +xtBool xt_fs_rmdir(XTThreadPtr self, char *name) +{ + char path[PATH_MAX]; + + xt_strcpy(PATH_MAX, path, name); + xt_remove_dir_char(path); + +#ifdef XT_WIN + if (!RemoveDirectory(path)) { + int err = fs_get_win_error(); + + if (!XT_FILE_NOT_FOUND(err)) { + xt_throw_ferrno(XT_CONTEXT, err, path); + return FAILED; + } + } +#else + if (rmdir(path) == -1) { + int err = errno; + + if (err != ENOENT) { + xt_throw_ferrno(XT_CONTEXT, err, path); + return FAILED; + } + } +#endif + return OK; +} + +/* ---------------------------------------------------------------------- + * Open & Close operations + */ + +xtPublic XTFilePtr xt_fs_get_file(XTThreadPtr self, char *file_name) +{ + XTFilePtr file_ptr, *file_pptr; + + xt_sl_lock(self, fs_globals.fsg_open_files); + pushr_(xt_sl_unlock, fs_globals.fsg_open_files); + + if ((file_pptr = (XTFilePtr *) xt_sl_find(self, fs_globals.fsg_open_files, file_name))) + file_ptr = *file_pptr; + else { + file_ptr = fs_new_file(self, file_name); + xt_sl_insert(self, fs_globals.fsg_open_files, file_name, &file_ptr); + } + file_ptr->fil_ref_count++; + freer_(); // xt_sl_unlock(fs_globals.fsg_open_files) + return file_ptr; +} + +xtPublic void xt_fs_release_file(XTThreadPtr self, XTFilePtr file_ptr) +{ + xt_sl_lock(self, fs_globals.fsg_open_files); + pushr_(xt_sl_unlock, fs_globals.fsg_open_files); + + file_ptr->fil_ref_count--; + if (!file_ptr->fil_ref_count) { + xt_sl_delete(self, fs_globals.fsg_open_files, file_ptr->fil_path); + } + + freer_(); // xt_ht_unlock(fs_globals.fsg_open_files) +} + +static xtBool fs_open_file(XTThreadPtr self, XT_FD *fd, XTFilePtr file, int mode) +{ + int retried = FALSE; + +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: OPEN FILE: (%d) %s\n", self->t_name, (int) file->fil_id, xt_last_2_names_of_path(file->fil_path)); +#endif + retry: +#ifdef XT_WIN + SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 }; + DWORD flags; + + if (mode & XT_FS_EXCLUSIVE) + flags = CREATE_NEW; + else if (mode & XT_FS_CREATE) + flags = OPEN_ALWAYS; + else + flags = OPEN_EXISTING; + + *fd = CreateFile( + file->fil_path, + mode & XT_FS_READONLY ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE), + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + flags, + FILE_FLAG_RANDOM_ACCESS, + NULL); + if (*fd == INVALID_HANDLE_VALUE) { + int err = fs_get_win_error(); + + if (!(mode & XT_FS_MISSING_OK) || !XT_FILE_NOT_FOUND(err)) { + if (!retried && (mode & XT_FS_MAKE_PATH) && XT_FILE_NOT_FOUND(err)) { + char path[PATH_MAX]; + + xt_strcpy(PATH_MAX, path, file->fil_path); + xt_remove_last_name_of_path(path); + xt_fs_mkpath(self, path); + retried = TRUE; + goto retry; + } + + xt_throw_ferrno(XT_CONTEXT, err, file->fil_path); + } + + /* File is missing, but don't throw an error. */ + return FAILED; + } + //PRINTF("open %d %s\n", *fd, file->fil_path); + return OK; +#else + int flags = 0; + + if (mode & XT_FS_READONLY) + flags = O_RDONLY; + else + flags = O_RDWR; + if (mode & XT_FS_CREATE) + flags |= O_CREAT; + if (mode & XT_FS_EXCLUSIVE) + flags |= O_EXCL; +#ifdef O_DIRECT + if (mode & XT_FS_DIRECT_IO) + flags |= O_DIRECT; +#endif + + *fd = open(file->fil_path, flags, XT_MASK); + if (*fd == -1) { + int err = errno; + + if (!(mode & XT_FS_MISSING_OK) || err != ENOENT) { + if (!retried && (mode & XT_FS_MAKE_PATH) && err == ENOENT) { + char path[PATH_MAX]; + + xt_strcpy(PATH_MAX, path, file->fil_path); + xt_remove_last_name_of_path(path); + xt_fs_mkpath(self, path); + retried = TRUE; + goto retry; + } + + xt_throw_ferrno(XT_CONTEXT, err, file->fil_path); + } + + /* File is missing, but don't throw an error. */ + return FAILED; + } + ///PRINTF("open %d %s\n", *fd, file->fil_path); + return OK; +#endif +} + +xtPublic XTOpenFilePtr xt_open_file(XTThreadPtr self, char *file, int mode) +{ + XTOpenFilePtr of; + + pushsr_(of, xt_close_file, (XTOpenFilePtr) xt_calloc(self, sizeof(XTOpenFileRec))); + of->fr_file = xt_fs_get_file(self, file); + of->fr_id = of->fr_file->fil_id; + of->of_filedes = XT_NULL_FD; + +#ifdef XT_WIN + if (!fs_open_file(self, &of->of_filedes, of->fr_file, mode)) { + xt_close_file(self, of); + of = NULL; + } +#else + xtBool failed = FALSE; + + if (of->fr_file->fil_filedes == -1) { + xt_sl_lock(self, fs_globals.fsg_open_files); + pushr_(xt_sl_unlock, fs_globals.fsg_open_files); + if (of->fr_file->fil_filedes == -1) { + if (!fs_open_file(self, &of->fr_file->fil_filedes, of->fr_file, mode)) + failed = TRUE; + } + freer_(); // xt_ht_unlock(fs_globals.fsg_open_files) + } + + if (failed) { + /* Close, but after we have release the fsg_open_files lock! */ + xt_close_file(self, of); + of = NULL; + } + else + of->of_filedes = of->fr_file->fil_filedes; +#endif + + popr_(); // Discard xt_close_file(of) + return of; +} + +xtPublic XTOpenFilePtr xt_open_file_ns(char *file, int mode) +{ + XTThreadPtr self = xt_get_self(); + XTOpenFilePtr of; + + try_(a) { + of = xt_open_file(self, file, mode); + } + catch_(a) { + of = NULL; + } + cont_(a); + return of; +} + +xtPublic xtBool xt_open_file_ns(XTOpenFilePtr *fh, char *file, int mode) +{ + XTThreadPtr self = xt_get_self(); + xtBool ok = TRUE; + + try_(a) { + *fh = xt_open_file(self, file, mode); + } + catch_(a) { + ok = FALSE; + } + cont_(a); + return ok; +} + +xtPublic void xt_close_file(XTThreadPtr self, XTOpenFilePtr of) +{ + if (of->of_filedes != XT_NULL_FD) { +#ifdef XT_WIN + CloseHandle(of->of_filedes); +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: close file: (%d) %s\n", self->t_name, (int) of->fr_file->fil_id, xt_last_2_names_of_path(of->fr_file->fil_path)); +#endif +#else + if (!of->fr_file || of->of_filedes != of->fr_file->fil_filedes) { + close(of->of_filedes); +#ifdef DEBUG_TRACE_FILES + PRINTF("%s: close file: (%d) %s\n", self->t_name, (int) of->fr_file->fil_id, xt_last_2_names_of_path(of->fr_file->fil_path)); +#endif + } +#endif + + of->of_filedes = XT_NULL_FD; + } + + if (of->fr_file) { + xt_fs_release_file(self, of->fr_file); + of->fr_file = NULL; + } + xt_free(self, of); +} + +xtPublic xtBool xt_close_file_ns(XTOpenFilePtr of) +{ + XTThreadPtr self = xt_get_self(); + xtBool failed = FALSE; + + try_(a) { + xt_close_file(self, of); + } + catch_(a) { + failed = TRUE; + } + cont_(a); + return failed; +} + +/* ---------------------------------------------------------------------- + * I/O operations + */ + +xtPublic xtBool xt_lock_file(struct XTThread *self, XTOpenFilePtr of) +{ +#ifdef XT_WIN + if (!LockFile(of->of_filedes, 0, 0, 512, 0)) { + int err = fs_get_win_error(); + + if (err == ERROR_LOCK_VIOLATION || + err == ERROR_LOCK_FAILED) + return FAILED; + + xt_throw_ferrno(XT_CONTEXT, err, xt_file_path(of)); + return FAILED; + } + return OK; +#else + if (lockf(of->of_filedes, F_TLOCK, 0) == 0) + return OK; + if (errno == EAGAIN) + return FAILED; + xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of)); + return FAILED; +#endif +} + +xtPublic void xt_unlock_file(struct XTThread *self, XTOpenFilePtr of) +{ +#ifdef XT_WIN + if (!UnlockFile(of->of_filedes, 0, 0, 512, 0)) { + int err = fs_get_win_error(); + + if (err != ERROR_NOT_LOCKED) + xt_throw_ferrno(XT_CONTEXT, err, xt_file_path(of)); + } +#else + if (lockf(of->of_filedes, F_ULOCK, 0) == -1) + xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of)); +#endif +} + +static off_t fs_seek_eof(XTThreadPtr self, XT_FD fd, XTFilePtr file) +{ +#ifdef XT_WIN + DWORD result; + LARGE_INTEGER lpFileSize; + + result = SetFilePointer(fd, 0, NULL, FILE_END); + if (result == 0xFFFFFFFF) { + xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), file->fil_path); + return (off_t) -1; + } + + if (!GetFileSizeEx(fd, &lpFileSize)) { + xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), file->fil_path); + return (off_t) -1; + } + + return lpFileSize.QuadPart; +#else + off_t off; + + off = lseek(fd, 0, SEEK_END); + if (off == -1) { + xt_throw_ferrno(XT_CONTEXT, errno, file->fil_path); + return -1; + } + + return off; +#endif +} + +xtPublic off_t xt_seek_eof_file(XTThreadPtr self, XTOpenFilePtr of) +{ + return fs_seek_eof(self, of->of_filedes, of->fr_file); +} + +xtPublic xtBool xt_set_eof_file(XTThreadPtr self, XTOpenFilePtr of, off_t offset) +{ +#ifdef XT_WIN + LARGE_INTEGER liDistanceToMove; + + liDistanceToMove.QuadPart = offset; + if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) { + xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), xt_file_path(of)); + return FAILED; + } + + if (!SetEndOfFile(of->of_filedes)) { + xt_throw_ferrno(XT_CONTEXT, fs_get_win_error(), xt_file_path(of)); + return FAILED; + } +#else + if (ftruncate(of->of_filedes, offset) == -1) { + xt_throw_ferrno(XT_CONTEXT, errno, xt_file_path(of)); + return FAILED; + } +#endif + return OK; +} + +xtPublic xtBool xt_pwrite_file(XTOpenFilePtr of, off_t offset, size_t size, void *data, XTIOStatsPtr stat, XTThreadPtr XT_UNUSED(thread)) +{ +#ifdef DEBUG_PRINT_IO + PRINTF("PBXT WRITE %s offs=%d size=%d\n", of->fr_file->fil_path, (int) offset, (int) size); +#endif +#ifdef DEBUG_TRACE_IO + char timef[50]; + xtWord8 start = xt_trace_clock(); +#endif +#ifdef XT_WIN + LARGE_INTEGER liDistanceToMove; + DWORD result; + + liDistanceToMove.QuadPart = offset; + if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) + return xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of)); + + if (!WriteFile(of->of_filedes, data, size, &result, NULL)) + return xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of)); + + if (result != size) + return xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of)); +#else + ssize_t write_size; + + write_size = pwrite(of->of_filedes, data, size, offset); + if (write_size == -1) + return xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of)); + + if ((size_t) write_size != size) + return xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of)); + +#endif + stat->ts_write += (u_int) size; + +#ifdef DEBUG_TRACE_IO + xt_trace("/* %s */ pbxt_file_writ(\"%s\", %lu, %lu);\n", xt_trace_clock_diff(timef, start), of->fr_file->fil_path, (u_long) offset, (u_long) size); +#endif + return OK; +} + +xtPublic xtBool xt_flush_file(XTOpenFilePtr of, XTIOStatsPtr stat, XTThreadPtr XT_UNUSED(thread)) +{ + xtWord8 s; + +#ifdef DEBUG_PRINT_IO + PRINTF("PBXT FLUSH %s\n", of->fr_file->fil_path); +#endif +#ifdef DEBUG_TRACE_IO + char timef[50]; + xtWord8 start = xt_trace_clock(); +#endif + stat->ts_flush_start = xt_trace_clock(); +#ifdef XT_WIN + if (!FlushFileBuffers(of->of_filedes)) { + xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of)); + goto failed; + } +#else + if (fsync(of->of_filedes) == -1) { + xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of)); + goto failed; + } +#endif +#ifdef DEBUG_TRACE_IO + xt_trace("/* %s */ pbxt_file_sync(\"%s\");\n", xt_trace_clock_diff(timef, start), of->fr_file->fil_path); +#endif + s = stat->ts_flush_start; + stat->ts_flush_start = 0; + stat->ts_flush_time += xt_trace_clock() - s; + stat->ts_flush++; + return OK; + + failed: + s = stat->ts_flush_start; + stat->ts_flush_start = 0; + stat->ts_flush_time += xt_trace_clock() - s; + return FAILED; +} + +xtBool xt_pread_file(XTOpenFilePtr of, off_t offset, size_t size, size_t min_size, void *data, size_t *red_size, XTIOStatsPtr stat, XTThreadPtr XT_UNUSED(thread)) +{ +#ifdef DEBUG_PRINT_IO + PRINTF("PBXT READ %s offset=%d size=%d\n", of->fr_file->fil_path, (int) offset, (int) size); +#endif +#ifdef DEBUG_TRACE_IO + char timef[50]; + xtWord8 start = xt_trace_clock(); +#endif +#ifdef XT_WIN + LARGE_INTEGER liDistanceToMove; + DWORD result; + + liDistanceToMove.QuadPart = offset; + if (!SetFilePointerEx(of->of_filedes, liDistanceToMove, NULL, FILE_BEGIN)) + return xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of)); + + if (!ReadFile(of->of_filedes, data, size, &result, NULL)) + return xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(of)); + + if ((size_t) result < min_size) + return xt_register_ferrno(XT_REG_CONTEXT, ERROR_HANDLE_EOF, xt_file_path(of)); + + if (red_size) + *red_size = (size_t) result; + stat->ts_read += (u_int) result; +#else + ssize_t read_size; + + read_size = pread(of->of_filedes, data, size, offset); + if (read_size == -1) + return xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(of)); + + /* Throw an error if read less than the minimum: */ + if ((size_t) read_size < min_size) { +//PRINTF("PMC PBXT <-- offset:%llu, count:%lu \n", (u_llong) offset, (u_long) size); + return xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(of)); + } + + if (red_size) + *red_size = (size_t) read_size; + stat->ts_read += (u_int) read_size; +#endif +#ifdef DEBUG_TRACE_IO + xt_trace("/* %s */ pbxt_file_read(\"%s\", %lu, %lu);\n", xt_trace_clock_diff(timef, start), of->fr_file->fil_path, (u_long) offset, (u_long) size); +#endif + return OK; +} + +/* ---------------------------------------------------------------------- + * Directory operations + */ + +/* + * The filter may contain one '*' as wildcard. + */ +XTOpenDirPtr xt_dir_open(XTThreadPtr self, c_char *path, c_char *filter) +{ + XTOpenDirPtr od; + + pushsr_(od, xt_dir_close, (XTOpenDirPtr) xt_calloc(self, sizeof(XTOpenDirRec))); + +#ifdef XT_WIN + size_t len; + + od->od_handle = XT_NULL_FD; + + // path = path\(filter | *) + len = strlen(path) + 1 + (filter ? strlen(filter) : 1) + 1; + od->od_path = (char *) xt_malloc(self, len); + + strcpy(od->od_path, path); + xt_add_dir_char(len, od->od_path); + if (filter) + strcat(od->od_path, filter); + else + strcat(od->od_path, "*"); +#else + od->od_path = xt_dup_string(self, path); + + if (filter) + od->od_filter = xt_dup_string(self, filter); + + od->od_dir = opendir(path); + if (!od->od_dir) + xt_throw_ferrno(XT_CONTEXT, errno, path); +#endif + + popr_(); // Discard xt_dir_close(od) + return od; +} + +void xt_dir_close(XTThreadPtr self, XTOpenDirPtr od) +{ + if (od) { +#ifdef XT_WIN + if (od->od_handle != XT_NULL_FD) { + FindClose(od->od_handle); + od->od_handle = XT_NULL_FD; + } +#else + if (od->od_dir) { + closedir(od->od_dir); + od->od_dir = NULL; + } + if (od->od_filter) { + xt_free(self, od->od_filter); + od->od_filter = NULL; + } +#endif + if (od->od_path) { + xt_free(self, od->od_path); + od->od_path = NULL; + } + xt_free(self, od); + } +} + +#ifdef XT_WIN +xtBool xt_dir_next(XTThreadPtr self, XTOpenDirPtr od) +{ + int err = 0; + + if (od->od_handle == INVALID_HANDLE_VALUE) { + od->od_handle = FindFirstFile(od->od_path, &od->od_data); + if (od->od_handle == INVALID_HANDLE_VALUE) + err = fs_get_win_error(); + } + else { + if (!FindNextFile(od->od_handle, &od->od_data)) + err = fs_get_win_error(); + } + + if (err) { + if (err != ERROR_NO_MORE_FILES) { + if (err == ERROR_FILE_NOT_FOUND) { + char path[PATH_MAX]; + + xt_strcpy(PATH_MAX, path, od->od_path); + xt_remove_last_name_of_path(path); + if (!xt_fs_exists(path)) + xt_throw_ferrno(XT_CONTEXT, err, path); + } + else + xt_throw_ferrno(XT_CONTEXT, err, od->od_path); + } + return FAILED; + } + + return OK; +} +#else +static xtBool fs_match_filter(c_char *name, c_char *filter) +{ + while (*name && *filter) { + if (*filter == '*') { + if (filter[1] == *name) + filter++; + else + name++; + } + else { + if (*name != *filter) + return FALSE; + name++; + filter++; + } + } + if (!*name) { + if (!*filter || (*filter == '*' && !filter[1])) + return TRUE; + } + return FALSE; +} + +xtBool xt_dir_next(XTThreadPtr self, XTOpenDirPtr od) +{ + int err; + struct dirent *result; + + for (;;) { + err = readdir_r(od->od_dir, &od->od_entry, &result); + if (err) { + xt_throw_ferrno(XT_CONTEXT, err, od->od_path); + return FAILED; + } + if (!result) + break; + /* Filter out '.' and '..': */ + if (od->od_entry.d_name[0] == '.') { + if (od->od_entry.d_name[1] == '.') { + if (od->od_entry.d_name[2] == '\0') + continue; + } + else { + if (od->od_entry.d_name[1] == '\0') + continue; + } + } + if (!od->od_filter) + break; + if (fs_match_filter(od->od_entry.d_name, od->od_filter)) + break; + } + return result ? TRUE : FALSE; +} +#endif + +char *xt_dir_name(XTThreadPtr self __attribute__((unused)), XTOpenDirPtr od) +{ +#ifdef XT_WIN + return od->od_data.cFileName; +#else + return od->od_entry.d_name; +#endif +} + +xtBool xt_dir_is_file(XTThreadPtr self __attribute__((unused)), XTOpenDirPtr od) +{ +#ifdef XT_WIN + if (od->od_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return FALSE; +#elif defined(XT_SOLARIS) + char path[PATH_MAX]; + struct stat sb; + + xt_strcpy(PATH_MAX, path, od->od_path); + xt_add_dir_char(PATH_MAX, path); + xt_strcat(PATH_MAX, path, od->od_entry.d_name); + + if (stat(path, &sb) == -1) { + xt_throw_ferrno(XT_CONTEXT, errno, path); + return FAILED; + } + + if ( sb.st_mode & S_IFDIR ) + return FALSE; +#else + if (od->od_entry.d_type & DT_DIR) + return FALSE; +#endif + return TRUE; +} + +off_t xt_dir_file_size(XTThreadPtr self, XTOpenDirPtr od) +{ +#ifdef XT_WIN + return (off_t) od->od_data.nFileSizeLow | (((off_t) od->od_data.nFileSizeHigh) << 32); +#else + char path[PATH_MAX]; + off_t size; + + xt_strcpy(PATH_MAX, path, od->od_path); + xt_add_dir_char(PATH_MAX, path); + xt_strcat(PATH_MAX, path, od->od_entry.d_name); + if (!xt_fs_stat(self, path, &size, NULL)) + return -1; + return size; +#endif +} + +/* ---------------------------------------------------------------------- + * File mapping operations + */ + +static xtBool fs_map_file(XTFileMemMapPtr mm, XTFilePtr file, xtBool grow) +{ + ASSERT_NS(!mm->mm_start); +#ifdef XT_WIN + /* This will grow the file to the given size: */ + mm->mm_mapdes = CreateFileMapping(file->fil_filedes, NULL, PAGE_READWRITE, (DWORD) (mm->mm_length >> 32), (DWORD) mm->mm_length, NULL); + if (mm->mm_mapdes == NULL) { + xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), file->fil_path); + return FAILED; + } + + mm->mm_start = (xtWord1 *) MapViewOfFile(mm->mm_mapdes, FILE_MAP_WRITE, 0, 0, 0); + if (!mm->mm_start) { + CloseHandle(mm->mm_mapdes); + mm->mm_mapdes = NULL; + xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), file->fil_path); + return FAILED; + } +#else + if (grow) { + char data[2]; + + if (pwrite(file->fil_filedes, data, 1, mm->mm_length - 1) == -1) { + xt_register_ferrno(XT_REG_CONTEXT, errno, file->fil_path); + return FAILED; + } + } + + /* Remap: */ + mm->mm_start = (xtWord1 *) mmap(0, (size_t) mm->mm_length, PROT_READ | PROT_WRITE, MAP_SHARED, file->fil_filedes, 0); + if (mm->mm_start == MAP_FAILED) { + mm->mm_start = NULL; + xt_register_ferrno(XT_REG_CONTEXT, errno, file->fil_path); + return FAILED; + } +#endif + return OK; +} + +xtPublic XTMapFilePtr xt_open_fmap(XTThreadPtr self, char *file, size_t grow_size) +{ + XTMapFilePtr map; + + pushsr_(map, xt_close_fmap, (XTMapFilePtr) xt_calloc(self, sizeof(XTMapFileRec))); + map->fr_file = xt_fs_get_file(self, file); + map->fr_id = map->fr_file->fil_id; + + xt_sl_lock(self, fs_globals.fsg_open_files); + pushr_(xt_sl_unlock, fs_globals.fsg_open_files); + + if (map->fr_file->fil_filedes == XT_NULL_FD) { + if (!fs_open_file(self, &map->fr_file->fil_filedes, map->fr_file, XT_FS_DEFAULT)) { + xt_close_fmap(self, map); + map = NULL; + } + } + + map->fr_file->fil_handle_count++; + + freer_(); // xt_ht_unlock(fs_globals.fsg_open_files) + + if (!map->fr_file->fil_memmap) { + xt_sl_lock(self, fs_globals.fsg_open_files); + pushr_(xt_sl_unlock, fs_globals.fsg_open_files); + if (!map->fr_file->fil_memmap) { + XTFileMemMapPtr mm; + + mm = (XTFileMemMapPtr) xt_calloc(self, sizeof(XTFileMemMapRec)); + pushr_(fs_close_fmap, mm); + +#ifdef XT_WIN + /* NULL is the value returned on error! */ + mm->mm_mapdes = NULL; +#endif + xt_rwmutex_init_with_autoname(self, &mm->mm_lock); + mm->mm_length = fs_seek_eof(self, map->fr_file->fil_filedes, map->fr_file); + if (sizeof(size_t) == 4 && mm->mm_length >= (off_t) 0xFFFFFFFF) + xt_throw_ixterr(XT_CONTEXT, XT_ERR_FILE_TOO_LONG, map->fr_file->fil_path); + mm->mm_grow_size = grow_size; + + if (mm->mm_length < (off_t) grow_size) { + mm->mm_length = (off_t) grow_size; + if (!fs_map_file(mm, map->fr_file, TRUE)) + xt_throw(self); + } + else { + if (!fs_map_file(mm, map->fr_file, FALSE)) + xt_throw(self); + } + + popr_(); // Discard fs_close_fmap(mm) + map->fr_file->fil_memmap = mm; + } + freer_(); // xt_ht_unlock(fs_globals.fsg_open_files) + } + map->mf_memmap = map->fr_file->fil_memmap; + + popr_(); // Discard xt_close_fmap(map) + return map; +} + +xtPublic void xt_close_fmap(XTThreadPtr self, XTMapFilePtr map) +{ + if (map->fr_file) { + xt_fs_release_file(self, map->fr_file); + + xt_sl_lock(self, fs_globals.fsg_open_files); + pushr_(xt_sl_unlock, fs_globals.fsg_open_files); + + map->fr_file->fil_handle_count--; + if (!map->fr_file->fil_handle_count) + fs_free_file(self, NULL, &map->fr_file); + + freer_(); + + map->fr_file = NULL; + + + } + map->mf_memmap = NULL; + xt_free(self, map); +} + +xtPublic xtBool xt_close_fmap_ns(XTMapFilePtr map) +{ + XTThreadPtr self = xt_get_self(); + xtBool failed = FALSE; + + try_(a) { + xt_close_fmap(self, map); + } + catch_(a) { + failed = TRUE; + } + cont_(a); + return failed; +} + +static xtBool fs_remap_file(XTMapFilePtr map, off_t offset, size_t size, XTIOStatsPtr stat) +{ + off_t new_size = 0; + XTFileMemMapPtr mm = map->mf_memmap; + xtWord8 s; + + if (offset + (off_t) size > mm->mm_length) { + /* Expand the file: */ + new_size = (mm->mm_length + (off_t) mm->mm_grow_size) / (off_t) mm->mm_grow_size; + new_size *= mm->mm_grow_size; + while (new_size < offset + (off_t) size) + new_size += mm->mm_grow_size; + + if (sizeof(size_t) == 4 && new_size >= (off_t) 0xFFFFFFFF) { + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_FILE_TOO_LONG, xt_file_path(map)); + return FAILED; + } + } + else if (!mm->mm_start) + new_size = mm->mm_length; + + if (new_size) { + if (mm->mm_start) { + /* Flush & unmap: */ + stat->ts_flush_start = xt_trace_clock(); +#ifdef XT_WIN + if (!FlushViewOfFile(mm->mm_start, 0)) { + xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map)); + goto failed; + } + + if (!UnmapViewOfFile(mm->mm_start)) { + xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map)); + goto failed; + } +#else + if (msync( (char *)mm->mm_start, (size_t) mm->mm_length, MS_SYNC) == -1) { + xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(map)); + goto failed; + } + + /* Unmap: */ + if (munmap((caddr_t) mm->mm_start, (size_t) mm->mm_length) == -1) { + xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(map)); + goto failed; + } +#endif + s = stat->ts_flush_start; + stat->ts_flush_start = 0; + stat->ts_flush_time += xt_trace_clock() - s; + stat->ts_flush++; + } + mm->mm_start = NULL; +#ifdef XT_WIN + if (!CloseHandle(mm->mm_mapdes)) + return xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map)); + mm->mm_mapdes = NULL; +#endif + mm->mm_length = new_size; + + if (!fs_map_file(mm, map->fr_file, TRUE)) + return FAILED; + } + return OK; + + failed: + s = stat->ts_flush_start; + stat->ts_flush_start = 0; + stat->ts_flush_time += xt_trace_clock() - s; + return FAILED; +} + +xtPublic xtBool xt_pwrite_fmap(XTMapFilePtr map, off_t offset, size_t size, void *data, XTIOStatsPtr stat, XTThreadPtr thread) +{ + XTFileMemMapPtr mm = map->mf_memmap; + xtThreadID thd_id = thread->t_id; + +#ifdef DEBUG_TRACE_MAP_IO + xt_trace("/* %s */ pbxt_fmap_writ(\"%s\", %lu, %lu);\n", xt_trace_clock_diff(NULL), map->fr_file->fil_path, (u_long) offset, (u_long) size); +#endif + xt_rwmutex_slock(&mm->mm_lock, thd_id); + if (!mm->mm_start || offset + (off_t) size > mm->mm_length) { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + + xt_rwmutex_xlock(&mm->mm_lock, thd_id); + if (!fs_remap_file(map, offset, size, stat)) + goto failed; + } + +#ifdef XT_WIN + __try + { + memcpy(mm->mm_start + offset, data, size); + } + // GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH + __except(EXCEPTION_EXECUTE_HANDLER) + { + xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(map)); + goto failed; + } +#else + memcpy(mm->mm_start + offset, data, size); +#endif + + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + stat->ts_write += size; + return OK; + + failed: + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + return FAILED; +} + +xtPublic xtBool xt_pread_fmap_4(XTMapFilePtr map, off_t offset, xtWord4 *value, XTIOStatsPtr stat, XTThreadPtr thread) +{ + XTFileMemMapPtr mm = map->mf_memmap; + xtThreadID thd_id = thread->t_id; + +#ifdef DEBUG_TRACE_MAP_IO + xt_trace("/* %s */ pbxt_fmap_read_4(\"%s\", %lu, 4);\n", xt_trace_clock_diff(NULL), map->fr_file->fil_path, (u_long) offset); +#endif + xt_rwmutex_slock(&mm->mm_lock, thd_id); + if (!mm->mm_start) { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + xt_rwmutex_xlock(&mm->mm_lock, thd_id); + if (!fs_remap_file(map, 0, 0, stat)) { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + return FAILED; + } + } + if (offset >= mm->mm_length) + *value = 0; + else { + xtWord1 *data; + + data = mm->mm_start + offset; +#ifdef XT_WIN + __try + { + *value = XT_GET_DISK_4(data); + // GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + return xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(map)); + } +#else + *value = XT_GET_DISK_4(data); +#endif + } + + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + stat->ts_read += 4; + return OK; +} + +xtPublic xtBool xt_pread_fmap(XTMapFilePtr map, off_t offset, size_t size, size_t min_size, void *data, size_t *red_size, XTIOStatsPtr stat, XTThreadPtr thread) +{ + XTFileMemMapPtr mm = map->mf_memmap; + xtThreadID thd_id = thread->t_id; + size_t tfer; + +#ifdef DEBUG_TRACE_MAP_IO + xt_trace("/* %s */ pbxt_fmap_read(\"%s\", %lu, %lu);\n", xt_trace_clock_diff(NULL), map->fr_file->fil_path, (u_long) offset, (u_long) size); +#endif + /* NOTE!! The file map may already be locked, + * by a call to xt_lock_fmap_ptr()! + * + * This can occur during a sequential scan: + * xt_pread_fmap() Line 1330 + * XTTabCache::tc_read_direct() Line 361 + * XTTabCache::xt_tc_read() Line 220 + * xt_tab_get_rec_data() + * tab_visible() Line 2412 + * xt_tab_seq_next() Line 4068 + * + * And occurs during the following test: + * create table t1 ( a int not null, b int not null) ; + * --disable_query_log + * insert into t1 values (1,1),(2,2),(3,3),(4,4); + * let $1=19; + * set @d=4; + * while ($1) + * { + * eval insert into t1 select a+@d,b+@d from t1; + * eval set @d=@d*2; + * dec $1; + * } + * + * --enable_query_log + * alter table t1 add index i1(a); + * delete from t1 where a > 2000000; + * create table t2 like t1; + * insert into t2 select * from t1; + * + * As a result, the slock must be able to handle + * nested calls to lock/unlock. + */ + xt_rwmutex_slock(&mm->mm_lock, thd_id); + tfer = size; + if (!mm->mm_start) { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + xt_rwmutex_xlock(&mm->mm_lock, thd_id); + if (!fs_remap_file(map, 0, 0, stat)) { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + return FAILED; + } + } + if (offset >= mm->mm_length) + tfer = 0; + else { + if (mm->mm_length - offset < (off_t) tfer) + tfer = (size_t) (mm->mm_length - offset); +#ifdef XT_WIN + __try + { + memcpy(data, mm->mm_start + offset, tfer); + // GetExceptionCode()== EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + return xt_register_ferrno(XT_REG_CONTEXT, GetExceptionCode(), xt_file_path(map)); + } +#else + memcpy(data, mm->mm_start + offset, tfer); +#endif + } + + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + if (tfer < min_size) + return xt_register_ferrno(XT_REG_CONTEXT, ESPIPE, xt_file_path(map)); + + if (red_size) + *red_size = tfer; + stat->ts_read += tfer; + return OK; +} + +xtPublic xtBool xt_flush_fmap(XTMapFilePtr map, XTIOStatsPtr stat, XTThreadPtr thread) +{ + XTFileMemMapPtr mm = map->mf_memmap; + xtThreadID thd_id = thread->t_id; + xtWord8 s; + +#ifdef DEBUG_TRACE_MAP_IO + xt_trace("/* %s */ pbxt_fmap_sync(\"%s\");\n", xt_trace_clock_diff(NULL), map->fr_file->fil_path); +#endif + xt_rwmutex_slock(&mm->mm_lock, thd_id); + if (!mm->mm_start) { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + xt_rwmutex_xlock(&mm->mm_lock, thd_id); + if (!fs_remap_file(map, 0, 0, stat)) { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + return FAILED; + } + } + stat->ts_flush_start = xt_trace_clock(); +#ifdef XT_WIN + if (!FlushViewOfFile(mm->mm_start, 0)) { + xt_register_ferrno(XT_REG_CONTEXT, fs_get_win_error(), xt_file_path(map)); + goto failed; + } +#else + if (msync( (char *)mm->mm_start, (size_t) mm->mm_length, MS_SYNC) == -1) { + xt_register_ferrno(XT_REG_CONTEXT, errno, xt_file_path(map)); + goto failed; + } +#endif + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + s = stat->ts_flush_start; + stat->ts_flush_start = 0; + stat->ts_flush_time += xt_trace_clock() - s; + stat->ts_flush++; + return OK; + + failed: + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + s = stat->ts_flush_start; + stat->ts_flush_start = 0; + stat->ts_flush_time += xt_trace_clock() - s; + return FAILED; +} + +xtPublic xtWord1 *xt_lock_fmap_ptr(XTMapFilePtr map, off_t offset, size_t size, XTIOStatsPtr stat, XTThreadPtr XT_UNUSED(thread)) +{ + XTFileMemMapPtr mm = map->mf_memmap; + xtThreadID thd_id = thread->t_id; + + xt_rwmutex_slock(&mm->mm_lock, thd_id); + if (!mm->mm_start) { + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + xt_rwmutex_xlock(&mm->mm_lock, thd_id); + if (!fs_remap_file(map, 0, 0, stat)) + goto failed; + } + if (offset >= mm->mm_length) + goto failed; + + if (offset + (off_t) size > mm->mm_length) + stat->ts_read += (u_int) (offset + (off_t) size - mm->mm_length); + else + stat->ts_read += size; + return mm->mm_start + offset; + + failed: + xt_rwmutex_unlock(&mm->mm_lock, thd_id); + return NULL; +} + +xtPublic void xt_unlock_fmap_ptr(XTMapFilePtr map, XTThreadPtr thread) +{ + xt_rwmutex_unlock(&map->mf_memmap->mm_lock, thread->t_id); +} + +/* ---------------------------------------------------------------------- + * Copy files/directories + */ + +static void fs_copy_file(XTThreadPtr self, char *from_path, char *to_path, void *copy_buf) +{ + XTOpenFilePtr from; + XTOpenFilePtr to; + off_t offset = 0; + size_t read_size= 0; + + from = xt_open_file(self, from_path, XT_FS_READONLY); + pushr_(xt_close_file, from); + to = xt_open_file(self, to_path, XT_FS_CREATE | XT_FS_MAKE_PATH); + pushr_(xt_close_file, to); + + for (;;) { + if (!xt_pread_file(from, offset, 16*1024, 0, copy_buf, &read_size, &self->st_statistics.st_x, self)) + xt_throw(self); + if (!read_size) + break; + if (!xt_pwrite_file(to, offset, read_size, copy_buf, &self->st_statistics.st_x, self)) + xt_throw(self); + offset += (off_t) read_size; + } + + freer_(); + freer_(); +} + +xtPublic void xt_fs_copy_file(XTThreadPtr self, char *from_path, char *to_path) +{ + void *buffer; + + buffer = xt_malloc(self, 16*1024); + pushr_(xt_free, buffer); + fs_copy_file(self, from_path, to_path, buffer); + freer_(); +} + +static void fs_copy_dir(XTThreadPtr self, char *from_path, char *to_path, void *copy_buf) +{ + XTOpenDirPtr od; + char *file; + + xt_add_dir_char(PATH_MAX, from_path); + xt_add_dir_char(PATH_MAX, to_path); + + pushsr_(od, xt_dir_close, xt_dir_open(self, from_path, NULL)); + while (xt_dir_next(self, od)) { + file = xt_dir_name(self, od); + if (*file == '.') + continue; +#ifdef XT_WIN + if (strcmp(file, "pbxt-lock") == 0) + continue; +#endif + xt_strcat(PATH_MAX, from_path, file); + xt_strcat(PATH_MAX, to_path, file); + if (xt_dir_is_file(self, od)) + fs_copy_file(self, from_path, to_path, copy_buf); + else + fs_copy_dir(self, from_path, to_path, copy_buf); + xt_remove_last_name_of_path(from_path); + xt_remove_last_name_of_path(to_path); + } + freer_(); + + xt_remove_dir_char(from_path); + xt_remove_dir_char(to_path); +} + +xtPublic void xt_fs_copy_dir(XTThreadPtr self, const char *from, const char *to) +{ + void *buffer; + char from_path[PATH_MAX]; + char to_path[PATH_MAX]; + + xt_strcpy(PATH_MAX, from_path, from); + xt_strcpy(PATH_MAX, to_path, to); + + buffer = xt_malloc(self, 16*1024); + pushr_(xt_free, buffer); + fs_copy_dir(self, from_path, to_path, buffer); + freer_(); +} + diff --git a/storage/pbxt/src/filesys_xt.h b/storage/pbxt/src/filesys_xt.h new file mode 100644 index 00000000000..ebc4f474fc9 --- /dev/null +++ b/storage/pbxt/src/filesys_xt.h @@ -0,0 +1,167 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-12 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_filesys_h__ +#define __xt_filesys_h__ + +#ifdef XT_WIN +#include <time.h> +#else +#include <sys/time.h> +#include <dirent.h> +#endif +#include <sys/stat.h> + +#include "xt_defs.h" +#include "lock_xt.h" + +#ifdef XT_WIN +#define XT_FILE_IN_USE(x) ((x) == ERROR_SHARING_VIOLATION) +#define XT_FILE_ACCESS_DENIED(x) ((x) == ERROR_ACCESS_DENIED || (x) == ERROR_NETWORK_ACCESS_DENIED) +#define XT_FILE_TOO_MANY_OPEN(x) ((x) == ERROR_TOO_MANY_OPEN_FILES) +#define XT_FILE_NOT_FOUND(x) ((x) == ERROR_FILE_NOT_FOUND || (x) == ERROR_PATH_NOT_FOUND) +#else +#define XT_FILE_IN_USE(x) ((x) == ETXTBSY) +#define XT_FILE_ACCESS_DENIED(x) ((x) == EACCES) +#define XT_FILE_TOO_MANY_OPEN(x) ((x) == EMFILE) +#define XT_FILE_NOT_FOUND(x) ((x) == ENOENT) +#endif + +struct XTOpenFile; + +#define XT_MASK ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH)) + +#define XT_FS_DEFAULT 0 /* Open for read/write, error if does not exist. */ +#define XT_FS_READONLY 1 /* Open for read only (otherwize read/write). */ +#define XT_FS_CREATE 2 /* Create if the file does not exist. */ +#define XT_FS_EXCLUSIVE 4 /* Create, and generate an error if it already exists. */ +#define XT_FS_MISSING_OK 8 /* Set this flag if you don't want to throw an error if the file does not exist! */ +#define XT_FS_MAKE_PATH 16 /* Create the path if it does not exist. */ +#define XT_FS_DIRECT_IO 32 /* Use direct I/O on this file if possible (O_DIRECT). */ + +xtBool xt_fs_exists(char *path); +xtBool xt_fs_delete(struct XTThread *self, char *path); +xtBool xt_fs_file_not_found(int err); +void xt_fs_mkdir(struct XTThread *self, char *path); +void xt_fs_mkpath(struct XTThread *self, char *path); +xtBool xt_fs_rmdir(struct XTThread *self, char *path); +xtBool xt_fs_stat(struct XTThread *self, char *path, off_t *size, struct timespec *mod_time); +void xt_fs_move(struct XTThread *self, char *from_path, char *to_path); +xtBool xt_fs_rename(struct XTThread *self, char *from_path, char *to_path); + +#ifdef XT_WIN +#define XT_FD HANDLE +#define XT_NULL_FD INVALID_HANDLE_VALUE +#else +#define XT_FD int +#define XT_NULL_FD (-1) +#endif + +typedef struct XTFileMemMap { + xtWord1 *mm_start; /* The in-memory start of the map. */ +#ifdef XT_WIN + HANDLE mm_mapdes; +#endif + off_t mm_length; /* The length of the file map. */ + XTRWMutexRec mm_lock; /* The file map R/W lock. */ + size_t mm_grow_size; /* The amount by which the map file is increased. */ +} XTFileMemMapRec, *XTFileMemMapPtr; + +typedef struct XTFile { + u_int fil_ref_count; /* The number of open file structure referencing this file. */ + char *fil_path; + u_int fil_id; /* This is used by the disk cache to identify a file in the hash index. */ + XT_FD fil_filedes; /* The shared file descriptor (pread and pwrite allow this), on Windows this is used only for mmapped files */ + u_int fil_handle_count; /* Number of references in the case of mmapped fil_filedes, both Windows and Unix */ + XTFileMemMapPtr fil_memmap; /* Non-null if this file is memory mapped. */ +} XTFileRec, *XTFilePtr; + +typedef struct XTFileRef { + XTFilePtr fr_file; + u_int fr_id; /* Copied from above (small optimisation). */ +} XTFileRefRec, *XTFileRefPtr; + +typedef struct XTOpenFile : public XTFileRef { + XT_FD of_filedes; +} XTOpenFileRec, *XTOpenFilePtr; + +void xt_fs_init(struct XTThread *self); +void xt_fs_exit(struct XTThread *self); + +XTFilePtr xt_fs_get_file(struct XTThread *self, char *file_name); +void xt_fs_release_file(struct XTThread *self, XTFilePtr file_ptr); + +XTOpenFilePtr xt_open_file(struct XTThread *self, char *file, int mode); +XTOpenFilePtr xt_open_file_ns(char *file, int mode); +xtBool xt_open_file_ns(XTOpenFilePtr *fh, char *file, int mode); +void xt_close_file(struct XTThread *self, XTOpenFilePtr f); +xtBool xt_close_file_ns(XTOpenFilePtr f); +char *xt_file_path(struct XTFileRef *of); + +xtBool xt_lock_file(struct XTThread *self, XTOpenFilePtr of); +void xt_unlock_file(struct XTThread *self, XTOpenFilePtr of); + +off_t xt_seek_eof_file(struct XTThread *self, XTOpenFilePtr of); +xtBool xt_set_eof_file(struct XTThread *self, XTOpenFilePtr of, off_t offset); + +xtBool xt_pwrite_file(XTOpenFilePtr of, off_t offset, size_t size, void *data, struct XTIOStats *timer, struct XTThread *thread); +xtBool xt_pread_file(XTOpenFilePtr of, off_t offset, size_t size, size_t min_size, void *data, size_t *red_size, struct XTIOStats *timer, struct XTThread *thread); +xtBool xt_flush_file(XTOpenFilePtr of, struct XTIOStats *timer, struct XTThread *thread); + +typedef struct XTOpenDir { + char *od_path; +#ifdef XT_WIN + HANDLE od_handle; + WIN32_FIND_DATA od_data; +#else + char *od_filter; + struct dirent od_entry; + DIR *od_dir; +#endif +} XTOpenDirRec, *XTOpenDirPtr; + +XTOpenDirPtr xt_dir_open(struct XTThread *self, c_char *path, c_char *filter); +void xt_dir_close(struct XTThread *self, XTOpenDirPtr od); +xtBool xt_dir_next(struct XTThread *self, XTOpenDirPtr od); +char *xt_dir_name(struct XTThread *self, XTOpenDirPtr od); +xtBool xt_dir_is_file(struct XTThread *self, XTOpenDirPtr od); +off_t xt_dir_file_size(struct XTThread *self, XTOpenDirPtr od); + +typedef struct XTMapFile : public XTFileRef { + XTFileMemMapPtr mf_memmap; +} XTMapFileRec, *XTMapFilePtr; + +XTMapFilePtr xt_open_fmap(struct XTThread *self, char *file, size_t grow_size); +void xt_close_fmap(struct XTThread *self, XTMapFilePtr map); +xtBool xt_close_fmap_ns(XTMapFilePtr map); +xtBool xt_pwrite_fmap(XTMapFilePtr map, off_t offset, size_t size, void *data, struct XTIOStats *timer, struct XTThread *thread); +xtBool xt_pread_fmap(XTMapFilePtr map, off_t offset, size_t size, size_t min_size, void *data, size_t *red_size, struct XTIOStats *timer, struct XTThread *thread); +xtBool xt_pread_fmap_4(XTMapFilePtr map, off_t offset, xtWord4 *value, struct XTIOStats *timer, struct XTThread *thread); +xtBool xt_flush_fmap(XTMapFilePtr map, struct XTIOStats *stat, struct XTThread *thread); +xtWord1 *xt_lock_fmap_ptr(XTMapFilePtr map, off_t offset, size_t size, struct XTIOStats *timer, struct XTThread *thread); +void xt_unlock_fmap_ptr(XTMapFilePtr map, struct XTThread *thread); + +void xt_fs_copy_file(struct XTThread *self, char *from_path, char *to_path); +void xt_fs_copy_dir(struct XTThread *self, const char *from, const char *to); + +#endif + diff --git a/storage/pbxt/src/ha_pbxt.cc b/storage/pbxt/src/ha_pbxt.cc new file mode 100644 index 00000000000..86cea271e0d --- /dev/null +++ b/storage/pbxt/src/ha_pbxt.cc @@ -0,0 +1,5417 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * Derived from ha_example.h + * Copyright (C) 2003 MySQL AB + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-11-10 Paul McCullagh + * + */ + +#ifdef USE_PRAGMA_IMPLEMENTATION +#pragma implementation // gcc: Class implementation +#endif + +#include "xt_config.h" + +#if defined(XT_WIN) +#include <windows.h> +#endif + +#include <stdlib.h> +#include <time.h> + +#ifdef DRIZZLED +#include <drizzled/common.h> +#include <drizzled/plugin.h> +#include <mysys/my_alloc.h> +#include <mysys/hash.h> +#include <drizzled/field.h> +#include <drizzled/current_session.h> +#include <drizzled/data_home.h> +#include <drizzled/error.h> +#include <drizzled/table.h> +#include <drizzled/field/timestamp.h> +#include <drizzled/server_includes.h> +extern "C" char **session_query(Session *session); +#define my_strdup(a,b) strdup(a) +#else +#include "mysql_priv.h" +#include <mysql/plugin.h> +#endif + +#include "ha_pbxt.h" +#include "ha_xtsys.h" + +#include "strutil_xt.h" +#include "database_xt.h" +#include "cache_xt.h" +#include "trace_xt.h" +#include "heap_xt.h" +#include "myxt_xt.h" +#include "datadic_xt.h" +#ifdef XT_STREAMING +#include "streaming_xt.h" +#endif +#include "tabcache_xt.h" +#include "systab_xt.h" +#include "xaction_xt.h" + +#ifdef DEBUG +//#define XT_USE_SYS_PAR_DEBUG_SIZES +//#define PBXT_HANDLER_TRACE +//#define PBXT_TRACE_RETURN +//#define XT_PRINT_INDEX_OPT +//#define XT_SHOW_DUMPS_TRACE +//#define XT_UNIT_TEST +//#define LOAD_TABLE_ON_OPEN +//#define CHECK_TABLE_LOADS + +/* Enable to trace the statements executed by the engine: */ +//#define TRACE_STATEMENTS + +/* Enable to print the trace to the stdout, instead of + * to the trace log. + */ +//#define PRINT_STATEMENTS +#endif + +static handler *pbxt_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +static int pbxt_init(void *p); +static int pbxt_end(void *p); +#ifndef DRIZZLED +static int pbxt_panic(handlerton *hton, enum ha_panic_function flag); +#endif +static void pbxt_drop_database(handlerton *hton, char *path); +static int pbxt_close_connection(handlerton *hton, THD* thd); +static int pbxt_commit(handlerton *hton, THD *thd, bool all); +static int pbxt_rollback(handlerton *hton, THD *thd, bool all); +static void ha_aquire_exclusive_use(XTThreadPtr self, XTSharePtr share, ha_pbxt *mine); +static void ha_release_exclusive_use(XTThreadPtr self, XTSharePtr share); +static void ha_close_open_tables(XTThreadPtr self, XTSharePtr share, ha_pbxt *mine); + +#ifdef TRACE_STATEMENTS + +#ifdef PRINT_STATEMENTS +#define STAT_TRACE(y, x) printf("%s: %s\n", y ? y->t_name : "-unknown-", x) +#else +#define STAT_TRACE(y, x) xt_ttraceq(y, x) +#endif + +#else + +#define STAT_TRACE(y, x) + +#endif + +#ifdef PBXT_HANDLER_TRACE +#define PBXT_ALLOW_PRINTING + +#define XT_TRACE_CALL() do { XTThreadPtr s = xt_get_self(); printf("%s %s\n", s ? s->t_name : "-unknown-", __FUNC__); } while (0) +#ifdef PBXT_TRACE_RETURN +#define XT_RETURN(x) do { printf("%d\n", (int) (x)); return (x); } while (0) +#define XT_RETURN_VOID do { printf("out\n"); return; } while (0) +#else +#define XT_RETURN(x) return (x) +#define XT_RETURN_VOID return +#endif + +#else + +#define XT_TRACE_CALL() +#define XT_RETURN(x) return (x) +#define XT_RETURN_VOID return + +#endif + +#ifdef PBXT_ALLOW_PRINTING +#define XT_PRINT0(y, x) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-"); } while (0) +#define XT_PRINT1(y, x, a) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-", a); } while (0) +#define XT_PRINT2(y, x, a, b) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-", a, b); } while (0) +#define XT_PRINT3(y, x, a, b, c) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-", a, b, c); } while (0) +#else +#define XT_PRINT0(y, x) +#define XT_PRINT1(y, x, a) +#define XT_PRINT2(y, x, a, b) +#define XT_PRINT3(y, x, a, b, c) +#endif + + +#define TS(x) (x)->s + +handlerton *pbxt_hton; +bool pbxt_inited = false; // Variable for checking the init state of hash +xtBool pbxt_ignore_case = true; +const char *pbxt_extensions[]= { ".xtr", ".xtd", ".xtl", ".xti", ".xt", "", NULL }; +#ifdef XT_CRASH_DEBUG +xtBool pbxt_crash_debug = TRUE; +#else +xtBool pbxt_crash_debug = FALSE; +#endif + +/* Variables for pbxt share methods */ +static xt_mutex_type pbxt_database_mutex; // Prevent a database from being opened while it is being dropped +static XTHashTabPtr pbxt_share_tables; // Hash used to track open tables +static XTDatabaseHPtr pbxt_database = NULL; // The global open database +static char *pbxt_index_cache_size; +static char *pbxt_record_cache_size; +static char *pbxt_log_cache_size; +static char *pbxt_log_file_threshold; +static char *pbxt_transaction_buffer_size; +static char *pbxt_log_buffer_size; +static char *pbxt_checkpoint_frequency; +static char *pbxt_data_log_threshold; +static char *pbxt_data_file_grow_size; +static char *pbxt_row_file_grow_size; + +#ifdef DEBUG +#define XT_SHARE_LOCK_WAIT 5000 +#else +#define XT_SHARE_LOCK_WAIT 500 +#endif + +/* + * Lock timeout in 1/1000ths of a second + */ +#define XT_SHARE_LOCK_TIMEOUT 30000 + +/* + * ----------------------------------------------------------------------- + * SYSTEM VARIABLES + * + */ + +//#define XT_FOR_TEAMDRIVE + +typedef struct HAVarParams { + const char *vp_var; /* Variable name. */ + const char *vp_def; /* Default value. */ + const char *vp_min; /* Minimum allowed value. */ + const char *vp_max4; /* Maximum allowed value on 32-bit processors. */ + const char *vp_max8; /* Maximum allowed value on 64-bit processors. */ +} HAVarParamsRec, *HAVarParamsPtr; + +#ifdef XT_USE_SYS_PAR_DEBUG_SIZES +static HAVarParamsRec vp_index_cache_size = { "pbxt_index_cache_size", "32MB", "8MB", "2GB", "2000GB" }; +static HAVarParamsRec vp_record_cache_size = { "pbxt_record_cache_size", "32MB", "8MB", "2GB", "2000GB" }; +static HAVarParamsRec vp_log_cache_size = { "pbxt_log_cache_size", "16MB", "4MB", "2GB", "2000GB" }; +static HAVarParamsRec vp_checkpoint_frequency = { "pbxt_checkpoint_frequency", "28MB", "512K", "1GB", "24GB" }; +static HAVarParamsRec vp_log_file_threshold = { "pbxt_log_file_threshold", "32MB", "1MB", "2GB", "256TB" }; +static HAVarParamsRec vp_transaction_buffer_size = { "pbxt_transaction_buffer_size", "1MB", "128K", "1GB", "24GB" }; +static HAVarParamsRec vp_log_buffer_size = { "pbxt_log_buffer_size", "256K", "128K", "1GB", "24GB" }; +static HAVarParamsRec vp_data_log_threshold = { "pbxt_data_log_threshold", "400K", "400K", "2GB", "256TB" }; +static HAVarParamsRec vp_data_file_grow_size = { "pbxt_data_file_grow_size", "2MB", "128K", "1GB", "2GB" }; +static HAVarParamsRec vp_row_file_grow_size = { "pbxt_row_file_grow_size", "256K", "32K", "1GB", "2GB" }; +#define XT_DL_DEFAULT_XLOG_COUNT 3 +#define XT_DL_DEFAULT_GARBAGE_LEVEL 10 +#else +static HAVarParamsRec vp_index_cache_size = { "pbxt_index_cache_size", "32MB", "8MB", "2GB", "2000GB" }; +static HAVarParamsRec vp_record_cache_size = { "pbxt_record_cache_size", "32MB", "8MB", "2GB", "2000GB" }; +static HAVarParamsRec vp_log_cache_size = { "pbxt_log_cache_size", "16MB", "4MB", "2GB", "2000GB" }; +static HAVarParamsRec vp_checkpoint_frequency = { "pbxt_checkpoint_frequency", "28MB", "512K", "1GB", "24GB" }; +static HAVarParamsRec vp_log_file_threshold = { "pbxt_log_file_threshold", "32MB", "1MB", "2GB", "256TB" }; +static HAVarParamsRec vp_transaction_buffer_size = { "pbxt_transaction_buffer_size", "1MB", "128K", "1GB", "24GB" }; +static HAVarParamsRec vp_log_buffer_size = { "pbxt_log_buffer_size", "256K", "128K", "1GB", "24GB" }; +static HAVarParamsRec vp_data_log_threshold = { "pbxt_data_log_threshold", "64MB", "1MB", "2GB", "256TB" }; +static HAVarParamsRec vp_data_file_grow_size = { "pbxt_data_file_grow_size", "2MB", "128K", "1GB", "2GB" }; +static HAVarParamsRec vp_row_file_grow_size = { "pbxt_row_file_grow_size", "256K", "32K", "1GB", "2GB" }; +#define XT_DL_DEFAULT_XLOG_COUNT 3 +#define XT_DL_DEFAULT_GARBAGE_LEVEL 50 +#endif + +#define XT_AUTO_INCREMENT_DEF 0 + +#ifdef XT_MAC +#ifdef DEBUG +/* For debugging on the Mac, we check the re-use logs: */ +#define XT_OFFLINE_LOG_FUNCTION_DEF XT_RECYCLE_LOGS +#else +#define XT_OFFLINE_LOG_FUNCTION_DEF XT_DELETE_LOGS +#endif +#else +#define XT_OFFLINE_LOG_FUNCTION_DEF XT_RECYCLE_LOGS +#endif + +/* TeamDrive, uses special auto-increment, and + * we keep the logs for the moment: + */ +#ifdef XT_FOR_TEAMDRIVE +#undef XT_OFFLINE_LOG_FUNCTION_DEF +#define XT_OFFLINE_LOG_FUNCTION_DEF XT_KEEP_LOGS +//#undef XT_AUTO_INCREMENT_DEF +//#define XT_AUTO_INCREMENT_DEF 1 +#endif + +/* + * ----------------------------------------------------------------------- + * SHARED TABLE DATA + * + */ + +static xtBool ha_hash_comp(void *key, void *data) +{ + XTSharePtr share = (XTSharePtr) data; + + return strcmp((char *) key, share->sh_table_path->ps_path) == 0; +} + +static xtHashValue ha_hash(xtBool is_key, void *key_data) +{ + XTSharePtr share = (XTSharePtr) key_data; + + if (is_key) + return xt_ht_hash((char *) key_data); + return xt_ht_hash(share->sh_table_path->ps_path); +} + +static xtBool ha_hash_comp_ci(void *key, void *data) +{ + XTSharePtr share = (XTSharePtr) data; + + return strcasecmp((char *) key, share->sh_table_path->ps_path) == 0; +} + +static xtHashValue ha_hash_ci(xtBool is_key, void *key_data) +{ + XTSharePtr share = (XTSharePtr) key_data; + + if (is_key) + return xt_ht_casehash((char *) key_data); + return xt_ht_casehash(share->sh_table_path->ps_path); +} + +static void ha_open_share(XTThreadPtr self, XTShareRec *share, xtBool *tabled_opened) +{ + xt_lock_mutex(self, (xt_mutex_type *) share->sh_ex_mutex); + pushr_(xt_unlock_mutex, share->sh_ex_mutex); + + if (!share->sh_table) { + share->sh_table = xt_use_table(self, share->sh_table_path, FALSE, FALSE, tabled_opened); + share->sh_dic_key_count = share->sh_table->tab_dic.dic_key_count; + share->sh_dic_keys = share->sh_table->tab_dic.dic_keys; + share->sh_recalc_selectivity = FALSE; + } + + freer_(); // xt_ht_unlock(pbxt_share_tables) +} + +static void ha_close_share(XTThreadPtr self, XTShareRec *share) +{ + XTTableHPtr tab; + + if ((tab = share->sh_table)) { + /* Save this, in case the share is re-opened. */ + share->sh_min_auto_inc = tab->tab_auto_inc; + + xt_heap_release(self, tab); + share->sh_table = NULL; + } + + /* This are only references: */ + share->sh_dic_key_count = 0; + share->sh_dic_keys = NULL; +} + +static void ha_cleanup_share(XTThreadPtr self, XTSharePtr share) +{ + ha_close_share(self, share); + + if (share->sh_table_path) { + xt_free(self, share->sh_table_path); + share->sh_table_path = NULL; + } + + if (share->sh_ex_cond) { + thr_lock_delete(&share->sh_lock); + xt_delete_cond(self, (xt_cond_type *) share->sh_ex_cond); + share->sh_ex_cond = NULL; + } + + if (share->sh_ex_mutex) { + xt_delete_mutex(self, (xt_mutex_type *) share->sh_ex_mutex); + share->sh_ex_mutex = NULL; + } + + xt_free(self, share); +} + +static void ha_hash_free(XTThreadPtr self, void *data) +{ + XTSharePtr share = (XTSharePtr) data; + + ha_cleanup_share(self, share); +} + +/* + * This structure contains information that is common to all handles. + * (i.e. it is table specific). + */ +static XTSharePtr ha_get_share(XTThreadPtr self, const char *table_path, bool open_table, xtBool *tabled_opened) +{ + XTShareRec *share; + + enter_(); + xt_ht_lock(self, pbxt_share_tables); + pushr_(xt_ht_unlock, pbxt_share_tables); + + // Check if the table exists... + if (!(share = (XTSharePtr) xt_ht_get(self, pbxt_share_tables, (void *) table_path))) { + share = (XTSharePtr) xt_calloc(self, sizeof(XTShareRec)); + pushr_(ha_cleanup_share, share); + + share->sh_ex_mutex = (xt_mutex_type *) xt_new_mutex(self); + share->sh_ex_cond = (xt_cond_type *) xt_new_cond(self); + + thr_lock_init(&share->sh_lock); + + share->sh_use_count = 0; + share->sh_table_path = (XTPathStrPtr) xt_dup_string(self, table_path); + + if (open_table) + ha_open_share(self, share, tabled_opened); + + popr_(); // Discard ha_cleanup_share(share); + + xt_ht_put(self, pbxt_share_tables, share); + } + + share->sh_use_count++; + freer_(); // xt_ht_unlock(pbxt_share_tables) + + return_(share); +} + +/* + * Free shared information. + */ +static void ha_unget_share(XTThreadPtr self, XTSharePtr share) +{ + xt_ht_lock(self, pbxt_share_tables); + pushr_(xt_ht_unlock, pbxt_share_tables); + + if (!--share->sh_use_count) + xt_ht_del(self, pbxt_share_tables, share->sh_table_path); + + freer_(); // xt_ht_unlock(pbxt_share_tables) +} + +static xtBool ha_unget_share_removed(XTThreadPtr self, XTSharePtr share) +{ + xtBool removed = FALSE; + + xt_ht_lock(self, pbxt_share_tables); + pushr_(xt_ht_unlock, pbxt_share_tables); + + if (!--share->sh_use_count) { + removed = TRUE; + xt_ht_del(self, pbxt_share_tables, share->sh_table_path); + } + + freer_(); // xt_ht_unlock(pbxt_share_tables) + return removed; +} + +/* + * ----------------------------------------------------------------------- + * PUBLIC FUNCTIONS + * + */ + +xtPublic void xt_ha_unlock_table(XTThreadPtr self, void *share) +{ + ha_release_exclusive_use(self, (XTSharePtr) share); + ha_unget_share(self, (XTSharePtr) share); +} + +xtPublic void xt_ha_close_global_database(XTThreadPtr self) +{ + if (pbxt_database) { + xt_heap_release(self, pbxt_database); + pbxt_database = NULL; + } +} + +/* + * Open a PBXT database given the path of a table. + * This function also returns the name of the table. + * + * We use the pbxt_database_mutex to lock this + * operation to make sure it does not occur while + * some other thread is doing a "closeall". + */ +xtPublic void xt_ha_open_database_of_table(XTThreadPtr self, XTPathStrPtr table_path __attribute__((unused))) +{ +#ifdef XT_USE_GLOBAL_DB + if (!self->st_database) { + if (!pbxt_database) { + xt_open_database(self, mysql_real_data_home, TRUE); + pbxt_database = self->st_database; + xt_heap_reference(self, pbxt_database); + } + else + xt_use_database(self, pbxt_database, XT_FOR_USER); + } +#else + char db_path[PATH_MAX]; + + xt_strcpy(PATH_MAX, db_path, (char *) table_path); + xt_remove_last_name_of_path(db_path); + xt_remove_dir_char(db_path); + + if (self->st_database && xt_tab_compare_paths(self->st_database->db_name, xt_last_name_of_path(db_path)) == 0) + /* This thread already has this database open! */ + return; + + /* Auto commit before changing the database: */ + if (self->st_xact_data) { + /* PMC - This probably indicates something strange is happening: + * + * This sequence generates this error: + * + * delimiter | + * + * create temporary table t3 (id int)| + * + * create function f10() returns int + * begin + * drop temporary table if exists t3; + * create temporary table t3 (id int) engine=myisam; + * insert into t3 select id from t4; + * return (select count(*) from t3); + * end| + * + * select f10()| + * + * An error is generated because the same thread is used + * to open table t4 (at the start of the functions), and + * then to drop table t3. To drop t3 we need to + * switch the database, so we land up here! + */ + xt_throw_xterr(XT_CONTEXT, XT_ERR_CANNOT_CHANGE_DB); + /* + if (!xt_xn_commit(self)) + throw_(); + */ + } + + xt_lock_mutex(self, &pbxt_database_mutex); + pushr_(xt_unlock_mutex, &pbxt_database_mutex); + xt_open_database(self, db_path, FALSE); + freer_(); // xt_unlock_mutex(&pbxt_database_mutex); +#endif +} + +xtPublic XTThreadPtr xt_ha_set_current_thread(THD *thd, XTExceptionPtr e) +{ + XTThreadPtr self; + static int ha_thread_count = 0, ha_id; + + if (!(self = (XTThreadPtr) *thd_ha_data(thd, pbxt_hton))) { +// const Security_context *sctx; + char name[120]; + char ha_id_str[50]; + + ha_id = ++ha_thread_count; + sprintf(ha_id_str, "_%d", ha_id); + xt_strcpy(120,name,"user"); // TODO: Fix this hack +/* + sctx = &thd->main_security_ctx; + + if (sctx->user) { + xt_strcpy(120, name, sctx->user); + xt_strcat(120, name, "@"); + } + else + *name = 0; + if (sctx->host) + xt_strcat(120, name, sctx->host); + else if (sctx->ip) + xt_strcat(120, name, sctx->ip); + else if (thd->proc_info) + xt_strcat(120, name, (char *) thd->proc_info); + else + xt_strcat(120, name, "system"); +*/ + xt_strcat(120, name, ha_id_str); + if (!(self = xt_create_thread(name, FALSE, TRUE, e))) + return NULL; + + self->st_xact_mode = XT_XACT_REPEATABLE_READ; + + *thd_ha_data(thd, pbxt_hton) = (void *) self; + } + return self; +} + +xtPublic void xt_ha_close_connection(THD* thd) +{ + XTThreadPtr self; + + if ((self = (XTThreadPtr) *thd_ha_data(thd, pbxt_hton))) { + *thd_ha_data(thd, pbxt_hton) = NULL; + xt_free_thread(self); + } +} + +xtPublic XTThreadPtr xt_ha_thd_to_self(THD *thd) +{ + return (XTThreadPtr) *thd_ha_data(thd, pbxt_hton); +} + +/* The first bit is 1. */ +static u_int ha_get_max_bit(MY_BITMAP *map) +{ + my_bitmap_map *data_ptr = map->bitmap; + my_bitmap_map *end_ptr = map->last_word_ptr; + my_bitmap_map b; + u_int cnt = map->n_bits; + + for (; end_ptr >= data_ptr; end_ptr--) { + if ((b = *end_ptr)) { + my_bitmap_map mask; + + if (end_ptr == map->last_word_ptr && map->last_word_mask) + mask = map->last_word_mask >> 1; + else + mask = 0x80000000; + while (!(b & mask)) { + b = b << 1; + /* Should not happen, but if it does, we hang! */ + if (!b) + return map->n_bits; + cnt--; + } + return cnt; + } + if (end_ptr == map->last_word_ptr) + cnt = ((cnt-1) / 32) * 32; + else + cnt -= 32; + } + return 0; +} + +/* + * ----------------------------------------------------------------------- + * SUPPORT FUNCTIONS + * + */ + +/* + * In PBXT, as in MySQL: thread == connection. + * + * So we simply attach a PBXT thread to a MySQL thread. + */ +static XTThreadPtr ha_set_current_thread(THD *thd, int *err) +{ + XTThreadPtr self; + XTExceptionRec e; + + if (!(self = xt_ha_set_current_thread(thd, &e))) { + xt_log_exception(NULL, &e, XT_LOG_DEFAULT); + *err = e.e_xt_err; + return NULL; + } + return self; +} + +xtPublic int xt_ha_pbxt_to_mysql_error(int xt_err) +{ + switch (xt_err) { + case XT_NO_ERR: + return(0); + case XT_ERR_DUPLICATE_KEY: + return HA_ERR_FOUND_DUPP_KEY; + case XT_ERR_DEADLOCK: + return HA_ERR_LOCK_DEADLOCK; + case XT_ERR_RECORD_CHANGED: + /* If we generate HA_ERR_RECORD_CHANGED instead of HA_ERR_LOCK_WAIT_TIMEOUT + * then sysbench does not work because it does not handle this error. + */ + //return HA_ERR_LOCK_WAIT_TIMEOUT; // but HA_ERR_RECORD_CHANGED is the correct error for a optimistic lock failure. + return HA_ERR_RECORD_CHANGED; + case XT_ERR_LOCK_TIMEOUT: + return HA_ERR_LOCK_WAIT_TIMEOUT; + case XT_ERR_TABLE_IN_USE: + return HA_ERR_WRONG_COMMAND; + case XT_ERR_TABLE_NOT_FOUND: + return HA_ERR_NO_SUCH_TABLE; + case XT_ERR_TABLE_EXISTS: + return HA_ERR_TABLE_EXIST; + case XT_ERR_CANNOT_CHANGE_DB: + return ER_TRG_IN_WRONG_SCHEMA; + case XT_ERR_COLUMN_NOT_FOUND: + return HA_ERR_CANNOT_ADD_FOREIGN; + case XT_ERR_NO_REFERENCED_ROW: + case XT_ERR_REF_TABLE_NOT_FOUND: + case XT_ERR_REF_TYPE_WRONG: + return HA_ERR_NO_REFERENCED_ROW; + case XT_ERR_ROW_IS_REFERENCED: + return HA_ERR_ROW_IS_REFERENCED; + case XT_ERR_COLUMN_IS_NOT_NULL: + case XT_ERR_INCORRECT_NO_OF_COLS: + case XT_ERR_FK_ON_TEMP_TABLE: + case XT_ERR_FK_REF_TEMP_TABLE: + return HA_ERR_CANNOT_ADD_FOREIGN; + case XT_ERR_DUPLICATE_FKEY: + return HA_ERR_FOREIGN_DUPLICATE_KEY; + case XT_ERR_RECORD_DELETED: + return HA_ERR_RECORD_DELETED; + } + return(-1); // Unknown error +} + +xtPublic int xt_ha_pbxt_thread_error_for_mysql(THD *thd __attribute__((unused)), const XTThreadPtr self, int ignore_dup_key) +{ + int xt_err = self->t_exception.e_xt_err; + + XT_PRINT2(self, "xt_ha_pbxt_thread_error_for_mysql xt_err=%d auto commit=%d\n", (int) xt_err, (int) self->st_auto_commit); + switch (xt_err) { + case XT_NO_ERR: + break; + case XT_ERR_DUPLICATE_KEY: + case XT_ERR_DUPLICATE_FKEY: + /* Let MySQL call rollback as and when it wants to for duplicate + * key. + * + * In addition, we are not allowed to do an auto-rollback + * inside a sub-statement (function() or procedure()) + * For example: + * + * delimiter | + * + * create table t3 (c1 char(1) primary key not null)| + * + * create function bug12379() + * returns integer + * begin + * insert into t3 values('X'); + * insert into t3 values('X'); + * return 0; + * end| + * + * --error 1062 + * select bug12379()| + * + * + * Not doing an auto-rollback should solve this problem in the + * case of duplicate key (but not in others - like deadlock)! + * I don't think this situation is handled correctly by MySQL. + */ + + /* If we are in auto-commit mode (and we are not ignoring + * duplicate keys) then rollback the transaction automatically. + */ + if (!ignore_dup_key && self->st_auto_commit) + goto abort_transaction; + break; + case XT_ERR_DEADLOCK: + case XT_ERR_NO_REFERENCED_ROW: + case XT_ERR_ROW_IS_REFERENCED: + goto abort_transaction; + case XT_ERR_RECORD_CHANGED: + /* MySQL also handles the locked error. NOTE: There is no automatic + * rollback! + */ + break; + default: + xt_log_exception(self, &self->t_exception, XT_LOG_DEFAULT); + abort_transaction: + /* PMC 2006-08-30: It should be that this is not necessary! + * + * It is only necessary to call ha_rollback() if the engine + * aborts the transaction. + * + * On the other hand, I shouldn't need to rollback the + * transaction because, if I return an error, MySQL + * should do it for me. + * + * Unfortunately, when auto-commit is off, MySQL does not + * rollback automatically (for example when a deadlock + * is provoked). + * + * And when we have a multi update we cannot rely on this + * either (see comment above). + */ + if (self->st_xact_data) { + /* + * GOTCHA: + * A result of the "st_abort_trans = TRUE" below is that + * the following code results in an empty set. + * The reason is "ignore_dup_key" is not set so + * the duplicate key leads to an error which causes + * the transaction to be aborted. + * The delayed inserts are all execute in one transaction. + * + * CREATE TABLE t1 ( + * c1 INT(11) NOT NULL AUTO_INCREMENT, + * c2 INT(11) DEFAULT NULL, + * PRIMARY KEY (c1) + * ); + * SET insert_id= 14; + * INSERT DELAYED INTO t1 VALUES(NULL, 11), (NULL, 12); + * INSERT DELAYED INTO t1 VALUES(14, 91); + * INSERT DELAYED INTO t1 VALUES (NULL, 92), (NULL, 93); + * FLUSH TABLE t1; + * SELECT * FROM t1; + */ + if (self->st_lock_count == 0) { + /* No table locks, must rollback immediately + * (there will be no possibility later! + */ + XT_PRINT1(self, "xt_xn_rollback xt_err=%d\n", xt_err); + if (!xt_xn_rollback(self)) + xt_log_exception(self, &self->t_exception, XT_LOG_DEFAULT); + } + else { + /* Locks are held on tables. + * Only rollback after locks are released. + */ + self->st_auto_commit = TRUE; + self->st_abort_trans = TRUE; + } +#ifdef xxxx +/* DBUG_ASSERT(thd->transaction.stmt.ha_list == NULL || + trans == &thd->transaction.stmt); in handler.cc now + * fails, and I don't know if this function can be called anymore! */ + /* Cause any other DBs to do a rollback as well... */ + if (thd) { + /* + * GOTCHA: + * This is a BUG in MySQL. I cannot rollback a transaction if + * pb_mysql_thd->in_sub_stmt! But I must....?! + */ +#ifdef MYSQL_SERVER + if (!thd->in_sub_stmt) + ha_rollback(thd); +#endif + } +#endif + } + break; + } + return xt_ha_pbxt_to_mysql_error(xt_err); +} + +static void ha_conditional_close_database(XTThreadPtr self, XTThreadPtr other_thr, void *db) +{ + if (other_thr->st_database == (XTDatabaseHPtr) db) + xt_unuse_database(self, other_thr); +} + +/* + * This is only called from drop database, so we know that + * no thread is actually using the database. This means that it + * must be safe to close the database. + */ +xtPublic void xt_ha_all_threads_close_database(XTThreadPtr self, XTDatabaseHPtr db) +{ + xt_lock_mutex(self, &pbxt_database_mutex); + pushr_(xt_unlock_mutex, &pbxt_database_mutex); + xt_do_to_all_threads(self, ha_conditional_close_database, db); + freer_(); // xt_unlock_mutex(&pbxt_database_mutex); +} + +static int ha_log_pbxt_thread_error_for_mysql(int ignore_dup_key) +{ + return xt_ha_pbxt_thread_error_for_mysql(current_thd, myxt_get_self(), ignore_dup_key); +} + +/* + * ----------------------------------------------------------------------- + * STATIC HOOKS + * + */ +static xtWord8 ha_set_variable(char **value, HAVarParamsPtr vp) +{ + xtWord8 result; + xtWord8 mi, ma; + char *mm; + + if (!*value) + *value = getenv(vp->vp_var); + if (!*value) + *value = (char *) vp->vp_def; + result = xt_byte_size_to_int8(*value); + mi = (xtWord8) xt_byte_size_to_int8(vp->vp_min); + if (result < mi) { + result = mi; + *value = (char *) vp->vp_min; + } + if (sizeof(size_t) == 8) + mm = (char *) vp->vp_max8; + else + mm = (char *) vp->vp_max4; + ma = (xtWord8) xt_byte_size_to_int8(mm); + if (result > ma) { + result = ma; + *value = mm; + } + return result; +} + +static void pbxt_call_init(XTThreadPtr self) +{ + xtInt8 index_cache_size; + xtInt8 record_cache_size; + xtInt8 log_cache_size; + xtInt8 log_file_threshold; + xtInt8 transaction_buffer_size; + xtInt8 log_buffer_size; + xtInt8 checkpoint_frequency; + xtInt8 data_log_threshold; + xtInt8 data_file_grow_size; + xtInt8 row_file_grow_size; + + xt_logf(XT_NT_INFO, "PrimeBase XT (PBXT) Engine %s loaded...\n", xt_get_version()); + xt_logf(XT_NT_INFO, "Paul McCullagh, PrimeBase Technologies GmbH, http://www.primebase.org\n"); + + index_cache_size = ha_set_variable(&pbxt_index_cache_size, &vp_index_cache_size); + record_cache_size = ha_set_variable(&pbxt_record_cache_size, &vp_record_cache_size); + log_cache_size = ha_set_variable(&pbxt_log_cache_size, &vp_log_cache_size); + log_file_threshold = ha_set_variable(&pbxt_log_file_threshold, &vp_log_file_threshold); + transaction_buffer_size = ha_set_variable(&pbxt_transaction_buffer_size, &vp_transaction_buffer_size); + log_buffer_size = ha_set_variable(&pbxt_log_buffer_size, &vp_log_buffer_size); + checkpoint_frequency = ha_set_variable(&pbxt_checkpoint_frequency, &vp_checkpoint_frequency); + data_log_threshold = ha_set_variable(&pbxt_data_log_threshold, &vp_data_log_threshold); + data_file_grow_size = ha_set_variable(&pbxt_data_file_grow_size, &vp_data_file_grow_size); + row_file_grow_size = ha_set_variable(&pbxt_row_file_grow_size, &vp_row_file_grow_size); + + xt_db_log_file_threshold = (xtLogOffset) log_file_threshold; + xt_db_log_buffer_size = (size_t) xt_align_offset(log_buffer_size, 512); + xt_db_transaction_buffer_size = (size_t) xt_align_offset(transaction_buffer_size, 512); + xt_db_checkpoint_frequency = (size_t) checkpoint_frequency; + xt_db_data_log_threshold = (off_t) data_log_threshold; + xt_db_data_file_grow_size = (size_t) data_file_grow_size; + xt_db_row_file_grow_size = (size_t) row_file_grow_size; + + pbxt_ignore_case = lower_case_table_names != 0; + if (pbxt_ignore_case) + pbxt_share_tables = xt_new_hashtable(self, ha_hash_comp_ci, ha_hash_ci, ha_hash_free, TRUE, FALSE); + else + pbxt_share_tables = xt_new_hashtable(self, ha_hash_comp, ha_hash, ha_hash_free, TRUE, FALSE); + + xt_thread_wait_init(self); + xt_fs_init(self); + xt_lock_installation(self, mysql_real_data_home); + XTSystemTableShare::startUp(self); + xt_init_databases(self); + xt_ind_init(self, (size_t) index_cache_size); + xt_tc_init(self, (size_t) record_cache_size); + xt_xlog_init(self, (size_t) log_cache_size); +} + +static void pbxt_call_exit(XTThreadPtr self) +{ + xt_logf(XT_NT_INFO, "PrimeBase XT Engine shutdown...\n"); + +#ifdef TRACE_STATEMENTS + xt_dump_trace(); +#endif +#ifdef XT_USE_GLOBAL_DB + xt_ha_close_global_database(self); +#endif +#ifdef DEBUG + //xt_stop_database_threads(self, FALSE); + xt_stop_database_threads(self, TRUE); +#else + xt_stop_database_threads(self, TRUE); +#endif + /* This will tell the freeer to quit ASAP: */ + xt_quit_freeer(self); + /* We conditional stop the freeer here, because if we are + * in startup, then the free will be hanging. + * {FREEER-HANG} + * + * This problem has been solved by MySQL! + */ + xt_stop_freeer(self); + xt_exit_databases(self); + XTSystemTableShare::shutDown(self); + xt_xlog_exit(self); + xt_tc_exit(self); + xt_ind_exit(self); + xt_unlock_installation(self, mysql_real_data_home); + xt_fs_exit(self); + xt_thread_wait_exit(self); + if (pbxt_share_tables) { + xt_free_hashtable(self, pbxt_share_tables); + pbxt_share_tables = NULL; + } +} + +/* + * Shutdown the PBXT sub-system. + */ +static void ha_exit(XTThreadPtr self) +{ + /* Wrap things up... */ + xt_unuse_database(self, self); /* Just in case the main thread has a database in use (for testing)? */ + /* This may cause the streaming engine to cleanup connections and + * tables belonging to this engine. This in turn may require some of + * the stuff below (like xt_create_thread() called from pbxt_close_table()! */ +#ifdef XT_STREAMING + xt_exit_streaming(); +#endif + pbxt_call_exit(self); + xt_exit_threading(self); + xt_exit_memory(); + xt_exit_logging(); + xt_p_mutex_destroy(&pbxt_database_mutex); + pbxt_inited = false; +} + +/* + * Outout the PBXT status. Return FALSE on error. + */ +static bool pbxt_show_status(handlerton *hton __attribute__((unused)), THD* thd, + stat_print_fn* stat_print, + enum ha_stat_type stat_type __attribute__((unused))) +{ + XTThreadPtr self; + int err = 0; + XTStringBufferRec strbuf = { 0, 0, 0 }; + bool not_ok = FALSE; + + if (!(self = ha_set_current_thread(thd, &err))) + return FALSE; + +#ifdef XT_SHOW_DUMPS_TRACE + //if (pbxt_database) + // xt_dump_xlogs(pbxt_database, 0); + xt_trace("// %s - dump\n", xt_trace_clock_diff(NULL)); + xt_dump_trace(); +#endif + + try_(a) { + myxt_get_status(self, &strbuf); + } + catch_(a) { + not_ok = TRUE; + } + cont_(a); + + if (!not_ok) { + if (stat_print(thd, "PBXT", 4, "", 0, strbuf.sb_cstring, strbuf.sb_len)) + not_ok = TRUE; + } + xt_sb_set_size(self, &strbuf, 0); + + return not_ok; +} + +/* + * Initialize the PBXT sub-system. + * + * return 1 on error, else 0. + */ +static int pbxt_init(void *p) +{ + int init_err = 0; + + XT_TRACE_CALL(); + + if (sizeof(xtWordPS) != sizeof(void *)) { + printf("PBXT: This won't work, I require that sizeof(xtWordPS) != sizeof(void *)!\n"); + XT_RETURN(1); + } + + /* GOTCHA: This will "detect" if are loading the plug-in + * with different --with-debug option to MySQL. + * + * In this case, you will get an error when loading the + * library that some symbol was not found. + */ + void *dummy = my_malloc(100, MYF(0)); + my_free((byte *) dummy, MYF(0)); + + if (!pbxt_inited) { + XTThreadPtr self = NULL; + + xt_p_mutex_init_with_autoname(&pbxt_database_mutex, NULL); + + pbxt_hton = (handlerton *) p; + pbxt_hton->state = SHOW_OPTION_YES; +#ifndef DRIZZLED + pbxt_hton->db_type = DB_TYPE_PBXT; // Wow! I have my own! +#endif + pbxt_hton->close_connection = pbxt_close_connection; /* close_connection, cleanup thread related data. */ + pbxt_hton->commit = pbxt_commit; /* commit */ + pbxt_hton->rollback = pbxt_rollback; /* rollback */ + pbxt_hton->create = pbxt_create_handler; /* Create a new handler */ + pbxt_hton->drop_database = pbxt_drop_database; /* Drop a database */ +#ifndef DRIZZLED + pbxt_hton->panic = pbxt_panic; /* Panic call */ +#endif + pbxt_hton->show_status = pbxt_show_status; + pbxt_hton->flags = HTON_NO_FLAGS; /* HTON_CAN_RECREATE - Without this flags TRUNCATE uses delete_all_rows() */ + + if (!xt_init_logging()) /* Initialize logging */ + goto error_1; + +#ifdef XT_STREAMING + if (!xt_init_streaming()) + goto error_2; +#endif + + if (!xt_init_memory()) /* Initialize memory */ + goto error_3; + + /* +7 assumes: + * We are not using multiple database, and: + * +1 Main thread. + * +1 Compactor thread + * +1 Writer thread + * +1 Checkpointer thread + * +1 Sweeper thread + * +1 Free'er thread + * +1 Temporary thread (e.g. TempForClose, TempForEnd) + */ + self = xt_init_threading(max_connections + 7); /* Create the main self: */ + if (!self) + goto error_4; + + pbxt_inited = true; + + try_(a) { + /* Initialize all systems */ + pbxt_call_init(self); + + /* Conditional unit test: */ +#ifdef XT_UNIT_TEST + //xt_unit_test_create_threads(self); + xt_unit_test_read_write_locks(self); + //xt_unit_test_mutex_locks(self); +#endif + + /* {OPEN-DB-SWEEPER-WAIT} + * I have to start the freeer before I open and recover the database + * because it we run out of cache while waiting for the sweeper + * we will hang! + */ + xt_start_freeer(self); + +#ifdef XT_USE_GLOBAL_DB + /* Open the global database. */ + ASSERT(!pbxt_database); + { + THD *curr_thd = current_thd; + THD *thd = curr_thd; + +#ifndef DRIZZLED + extern myxt_mutex_t LOCK_plugin; + + /* {MYSQL QUIRK} + * I have to release this lock for PBXT recovery to + * work, because it needs to open .frm files. + * So, I unlock, but during INSTALL PLUGIN this is + * risky, because we are in multi-threaded + * mode! + * + * Although, as far as I can tell from the MySQL code, + * INSTALL PLUGIN should still work ok, during + * concurrent access, because we are not + * relying on pointer/memory that may be changed by + * other users. + * + * Only real problem, 2 threads try to load the same + * plugin at the same time. + */ + myxt_mutex_unlock(&LOCK_plugin); +#endif + + /* Can't do this here yet, because I need a THD! */ + try_(b) { + /* {MYSQL QUIRK} + * Sometime we have a THD, + * sometimes we don't. + * So far, I have noticed that during INSTALL PLUGIN, + * we have one, otherwize not. + */ + if (!curr_thd) { + if (!(thd = (THD *) myxt_create_thread())) + xt_throw(self); + } + + xt_open_database(self, mysql_real_data_home, TRUE); + pbxt_database = self->st_database; + xt_heap_reference(self, pbxt_database); + } + catch_(b) { + if (!curr_thd && thd) + myxt_destroy_thread(thd, FALSE); +#ifndef DRIZZLED + myxt_mutex_lock(&LOCK_plugin); +#endif + xt_throw(self); + } + cont_(b); + + if (!curr_thd) + myxt_destroy_thread(thd, FALSE); +#ifndef DRIZZLED + myxt_mutex_lock(&LOCK_plugin); +#endif + } +#endif + } + catch_(a) { + xt_log_exception(self, &self->t_exception, XT_LOG_DEFAULT); + init_err = 1; + } + cont_(a); + + if (init_err) { + /* {FREEER-HANG} The free-er will be hung in: + #0 0x91fc6a2e in semaphore_wait_signal_trap + #1 0x91fce505 in pthread_mutex_lock + #2 0x00489633 in safe_mutex_lock at thr_mutex.c:149 + #3 0x002dfca9 in plugin_thdvar_init at sql_plugin.cc:2398 + #4 0x000d6a12 in THD::init at sql_class.cc:715 + #5 0x000de9d3 in THD::THD at sql_class.cc:597 + #6 0x000debe1 in THD::THD at sql_class.cc:631 + #7 0x00e207a4 in myxt_create_thread at myxt_xt.cc:2666 + #8 0x00e3134b in tabc_fr_run_thread at tabcache_xt.cc:982 + #9 0x00e422ca in thr_main at thread_xt.cc:1006 + #10 0x91ff7c55 in _pthread_start + #11 0x91ff7b12 in thread_start + * + * so it is not good trying to stop it here! + * + * With regard to this problem, see {OPEN-DB-SWEEPER-WAIT} + * Due to this problem, I will probably have to hack + * the mutex so that the freeer can get started... + * + * NOPE! problem has gone in 6.0.9. Also not a problem in + * 5.1.29. + */ + + /* {OPEN-DB-SWEEPER-WAIT} + * I have to stop the freeer here because it was + * started before opening the database. + */ + pbxt_call_exit(self); + pbxt_inited = FALSE; + xt_exit_threading(self); + goto error_4; + } + xt_free_thread(self); + } + XT_RETURN(init_err); + + error_4: + xt_exit_memory(); + + error_3: +#ifdef XT_STREAMING + xt_exit_streaming(); + + error_2: +#endif + xt_exit_logging(); + + error_1: + xt_p_mutex_destroy(&pbxt_database_mutex); + XT_RETURN(1); +} + +static int pbxt_end(void *p __attribute__((unused))) +{ + XTThreadPtr self; + int err = 0; + + XT_TRACE_CALL(); + + if (pbxt_inited) { + XTExceptionRec e; + + /* This flag also means "shutting down". */ + pbxt_inited = FALSE; + self = xt_create_thread("TempForEnd", FALSE, TRUE, &e); + if (self) { + self->t_main = TRUE; + ha_exit(self); + } + } + + XT_RETURN(err); +} + +#ifndef DRIZZLED +static int pbxt_panic(handlerton *hton, enum ha_panic_function flag) +{ + return pbxt_end(hton); +} +#endif + +/* + * Kill the PBXT thread associated with the MySQL thread. + */ +static int pbxt_close_connection(handlerton *hton, THD* thd) +{ + XTThreadPtr self; +#ifdef XT_STREAMING + XTExceptionRec e; +#endif + + XT_TRACE_CALL(); + if ((self = (XTThreadPtr) *thd_ha_data(thd, hton))) { + *thd_ha_data(thd, hton) = NULL; + /* Required because freeing the thread could cause + * free of database which could call xt_close_file_ns()! + */ + xt_set_self(self); + xt_free_thread(self); + } +#ifdef XT_STREAMING + if (!xt_pbms_close_connection((void *) thd, &e)) + xt_log_exception(NULL, &e, XT_LOG_DEFAULT); +#endif + return 0; +} + +/* + * Currently does nothing because it was all done + * when the last PBXT table was removed from the + * database. + */ +static void pbxt_drop_database(handlerton *hton __attribute__((unused)), char *path __attribute__((unused))) +{ + XT_TRACE_CALL(); +} + +/* + * NOTES ON TRANSACTIONS: + * + * 1. If self->st_lock_count == 0 and transaction can be ended immediately. + * If not, we must wait until the last lock is released on the last handler + * to ensure that the tables are flushed before the transaction is + * committed or aborted. + * + * 2. all (below) indicates, within a BEGIN/END (i.e. auto_commit off) whether + * the statement or the entire transation is being terminated. + * We currently ignore statement termination. + * + * 3. If in BEGIN/END we must call ha_rollback() if we abort the transaction + * internally. + */ + +/* + * Commit the PBXT transaction of the given thread. + * thd is the MySQL thread structure. + * pbxt_thr is a pointer the the PBXT thread structure. + * + */ +static int pbxt_commit(handlerton *hton, THD *thd, bool all) +{ + int err = 0; + XTThreadPtr self; + + if ((self = (XTThreadPtr) *thd_ha_data(thd, hton))) { + XT_PRINT1(self, "pbxt_commit all=%d\n", all); + + if (self->st_xact_data) { + /* There are no table locks, commit immediately in all cases + * except when this is a statement commit with an explicit + * transaction (!all && !self->st_auto_commit). + */ + if (all || self->st_auto_commit) { + XT_PRINT0(self, "xt_xn_commit\n"); + + if (!xt_xn_commit(self)) + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE); + } + } + if (!all) + self->st_stat_trans = FALSE; + } + return err; +} + +static int pbxt_rollback(handlerton *hton, THD *thd, bool all) +{ + int err = 0; + XTThreadPtr self; + + if ((self = (XTThreadPtr) *thd_ha_data(thd, hton))) { + XT_PRINT1(self, "pbxt_rollback all=%d\n", all); + + if (self->st_xact_data) { + /* There are no table locks, rollback immediately in all cases + * except when this is a statement commit with an explicit + * transaction (!all && !self->st_auto_commit). + * + * Note, the only reason for a rollback of a operation is + * due to an error. In this case PBXT has already + * undone the effects of the operation. + * + * However, this is not the same as statement rollback + * which can involve a number of operations. + * + * TODO: Implement statement rollback. + */ + if (all || self->st_auto_commit) { + XT_PRINT0(self, "xt_xn_rollback\n"); + if (!xt_xn_rollback(self)) + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE); + } + } + if (!all) + self->st_stat_trans = FALSE; + } + return 0; +} + +static handler *pbxt_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root) +{ + if (table && XTSystemTableShare::isSystemTable(table->path.str)) + return new (mem_root) ha_xtsys(hton, table); + else + return new (mem_root) ha_pbxt(hton, table); +} + +/* + * ----------------------------------------------------------------------- + * HANDLER LOCKING FUNCTIONS + * + * These functions are used get a lock on all handles of a particular table. + * + */ + +static void ha_add_to_handler_list(XTThreadPtr self, XTSharePtr share, ha_pbxt *handler) +{ + xt_lock_mutex(self, (xt_mutex_type *) share->sh_ex_mutex); + pushr_(xt_unlock_mutex, share->sh_ex_mutex); + + handler->pb_ex_next = share->sh_handlers; + handler->pb_ex_prev = NULL; + if (share->sh_handlers) + share->sh_handlers->pb_ex_prev = handler; + share->sh_handlers = handler; + + freer_(); // xt_unlock_mutex(share->sh_ex_mutex) +} + +static void ha_remove_from_handler_list(XTThreadPtr self, XTSharePtr share, ha_pbxt *handler) +{ + xt_lock_mutex(self, (xt_mutex_type *) share->sh_ex_mutex); + pushr_(xt_unlock_mutex, share->sh_ex_mutex); + + /* Move front pointer: */ + if (share->sh_handlers == handler) + share->sh_handlers = handler->pb_ex_next; + + /* Remove from list: */ + if (handler->pb_ex_prev) + handler->pb_ex_prev->pb_ex_next = handler->pb_ex_next; + if (handler->pb_ex_next) + handler->pb_ex_next->pb_ex_prev = handler->pb_ex_prev; + + freer_(); // xt_unlock_mutex(share->sh_ex_mutex) +} + +/* + * Aquire exclusive use of a table, by waiting for all + * threads to complete use of all handlers of the table. + * At the same time we hold up all threads + * that want to use handlers belonging to the table. + * + * But we do not hold up threads that close the handlers. + */ +static void ha_aquire_exclusive_use(XTThreadPtr self, XTSharePtr share, ha_pbxt *mine) +{ + ha_pbxt *handler; + time_t end_time = time(NULL) + XT_SHARE_LOCK_TIMEOUT / 1000; + + XT_PRINT1(self, "ha_aquire_exclusive_use %s PBXT X lock\n", share->sh_table_path->ps_path); + /* GOTCHA: It is possible to hang here, if you hold + * onto the sh_ex_mutex lock, before we really + * have the exclusive lock (i.e. before all + * handlers are no longer in use. + * The reason is, because reopen() is not possible + * when some other thread holds sh_ex_mutex. + * So this can prevent a thread from completing its + * use of a handler, when prevents exclusive use + * here. + */ + xt_lock_mutex(self, (xt_mutex_type *) share->sh_ex_mutex); + pushr_(xt_unlock_mutex, share->sh_ex_mutex); + + /* Wait until we can get an exclusive lock: */ + while (share->sh_table_lock) { + xt_timed_wait_cond(self, (xt_cond_type *) share->sh_ex_cond, (xt_mutex_type *) share->sh_ex_mutex, XT_SHARE_LOCK_WAIT); + if (time(NULL) > end_time) { + freer_(); // xt_unlock_mutex(share->sh_ex_mutex) + xt_throw_taberr(XT_CONTEXT, XT_ERR_LOCK_TIMEOUT, share->sh_table_path); + } + } + + /* This tells readers (and other exclusive lockers) that someone has an exclusive lock. */ + share->sh_table_lock = TRUE; + + /* Wait for all open handlers use count to go to 0 */ + retry: + handler = share->sh_handlers; + while (handler) { + if (handler == mine || !handler->pb_ex_in_use) + handler = handler->pb_ex_next; + else { + /* Wait a bit, and try again: */ + xt_timed_wait_cond(self, (xt_cond_type *) share->sh_ex_cond, (xt_mutex_type *) share->sh_ex_mutex, XT_SHARE_LOCK_WAIT); + if (time(NULL) > end_time) { + freer_(); // xt_unlock_mutex(share->sh_ex_mutex) + xt_throw_taberr(XT_CONTEXT, XT_ERR_LOCK_TIMEOUT, share->sh_table_path); + } + /* Handler may have been freed, check from the begining again: */ + goto retry; + } + } + + freer_(); // xt_unlock_mutex(share->sh_ex_mutex) +} + +/* + * If you have exclusively locked the table, you can close all handler + * open tables. + * + * Call ha_close_open_tables() to get an exclusive lock. + */ +static void ha_close_open_tables(XTThreadPtr self, XTSharePtr share, ha_pbxt *mine) +{ + ha_pbxt *handler; + + xt_lock_mutex(self, (xt_mutex_type *) share->sh_ex_mutex); + pushr_(xt_unlock_mutex, share->sh_ex_mutex); + + /* Now that we know no handler is in use, we can close all the + * open tables... + */ + handler = share->sh_handlers; + while (handler) { + if (handler != mine && handler->pb_open_tab) { + xt_db_return_table_to_pool_ns(handler->pb_open_tab); + handler->pb_open_tab = NULL; + } + handler = handler->pb_ex_next; + } + + freer_(); // xt_unlock_mutex(share->sh_ex_mutex) +} + +static void ha_release_exclusive_use(XTThreadPtr self __attribute__((unused)), XTSharePtr share) +{ + XT_PRINT1(self, "ha_release_exclusive_use %s PBXT X UNLOCK\n", share->sh_table_path->ps_path); + xt_lock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex); + share->sh_table_lock = FALSE; + xt_broadcast_cond_ns((xt_cond_type *) share->sh_ex_cond); + xt_unlock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex); +} + +static xtBool ha_wait_for_shared_use(ha_pbxt *mine, XTSharePtr share) +{ + time_t end_time = time(NULL) + XT_SHARE_LOCK_TIMEOUT / 1000; + + XT_PRINT1(xt_get_self(), "ha_wait_for_shared_use %s share lock wait...\n", share->sh_table_path->ps_path); + mine->pb_ex_in_use = 0; + xt_lock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex); + while (share->sh_table_lock) { + /* Wake up the exclusive locker (may be waiting). He can try to continue: */ + xt_broadcast_cond_ns((xt_cond_type *) share->sh_ex_cond); + + if (!xt_timed_wait_cond(NULL, (xt_cond_type *) share->sh_ex_cond, (xt_mutex_type *) share->sh_ex_mutex, XT_SHARE_LOCK_WAIT)) { + xt_unlock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex); + return FAILED; + } + + if (time(NULL) > end_time) { + xt_unlock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex); + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_LOCK_TIMEOUT, share->sh_table_path); + return FAILED; + } + } + mine->pb_ex_in_use = 1; + xt_unlock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex); + return OK; +} + +xtPublic int ha_pbxt::reopen() +{ + THD *thd = current_thd; + int err = 0; + XTThreadPtr self; + xtBool tabled_opened = FALSE; + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + try_(a) { + xt_ha_open_database_of_table(self, pb_share->sh_table_path); + + ha_open_share(self, pb_share, &tabled_opened); + + if (!(pb_open_tab = xt_db_open_table_using_tab(pb_share->sh_table, self))) + xt_throw(self); + pb_open_tab->ot_thread = self; + + if (tabled_opened) { +#ifdef LOAD_TABLE_ON_OPEN + xt_tab_load_table(self, pb_open_tab); +#else + xt_tab_load_row_pointers(self, pb_open_tab); +#endif + xt_ind_set_index_selectivity(self, pb_open_tab); + /* If the number of rows is less than 150 we will recalculate the + * selectity of the indices, as soon as the number of rows + * exceeds 200 (see [**]) + */ + pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 - pb_share->sh_table->tab_row_fnum) < 150; + } + + /* I am not doing this anymore because it was only required + * for DELETE FROM table;, which is now implemented + * by deleting each row. + * TRUNCATE TABLE does not preserve the counter value. + */ + //init_auto_increment(pb_share->sh_min_auto_inc); + init_auto_increment(0); + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + cont_(a); + + return err; +} + +/* + * ----------------------------------------------------------------------- + * INFORMATION SCHEMA FUNCTIONS + * + */ + +int pbxt_statistics_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) +{ + XTThreadPtr self; + int err = 0; + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + try_(a) { + err = myxt_statistics_fill_table(self, thd, tables, cond, system_charset_info); + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE); + } + cont_(a); + return err; +} + +ST_FIELD_INFO pbxt_statistics_fields_info[]= +{ + { "ID", 4, MYSQL_TYPE_LONG, 0, 0, "The ID of the statistic", SKIP_OPEN_TABLE}, + { "Name", 40, MYSQL_TYPE_STRING, 0, 0, "The name of the statistic", SKIP_OPEN_TABLE}, + { "Value", 8, MYSQL_TYPE_LONGLONG, 0, 0, "The accumulated value", SKIP_OPEN_TABLE}, + { 0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} +}; + +int pbxt_init_statitics(void *p) +{ + ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p; + schema->fields_info = pbxt_statistics_fields_info; + schema->fill_table = pbxt_statistics_fill_table; + +#if defined(XT_WIN) && defined(XT_COREDUMP) + void register_crash_filter(); + + if (pbxt_crash_debug) + register_crash_filter(); +#endif + + return 0; +} + +int pbxt_exit_statitics(void *p __attribute__((unused))) +{ + return(0); +} + +/* + * ----------------------------------------------------------------------- + * DYNAMIC HOOKS + * + */ + +ha_pbxt::ha_pbxt(handlerton *hton, TABLE_SHARE *table_arg) : handler(hton, table_arg) +{ + pb_share = NULL; + pb_open_tab = NULL; + pb_key_read = FALSE; + pb_ignore_dup_key = 0; + pb_lock_table = FALSE; + pb_table_locked = 0; + pb_ex_next = NULL; + pb_ex_prev = NULL; + pb_ex_in_use = 0; + pb_in_stat = FALSE; +} + +/* + * If frm_error() is called then we will use this to to find out what file extentions + * exist for the storage engine. This is also used by the default rename_table and + * delete_table method in handler.cc. + */ +const char **ha_pbxt::bas_ext() const +{ + return pbxt_extensions; +} + +/* + * Specify the caching type: HA_CACHE_TBL_NONTRANSACT, HA_CACHE_TBL_NOCACHE + * HA_CACHE_TBL_ASKTRANSACT, HA_CACHE_TBL_TRANSACT + */ +MX_UINT8_T ha_pbxt::table_cache_type() +{ + return HA_CACHE_TBL_TRANSACT; /* Use transactional query cache */ +} + +MX_TABLE_TYPES_T ha_pbxt::table_flags() const +{ + return ( + /* We need this flag because records are not packed + * into a table which means #ROWID != offset + */ + HA_REC_NOT_IN_SEQ | + /* Since PBXT caches read records itself, I believe + * this to be the case. + */ + HA_FAST_KEY_READ | + /* + * I am assuming a "key" means a unique index. + * Of course a primary key does not allow nulls. + */ + HA_NULL_IN_KEY | + /* + * This is necessary because a MySQL blob can be + * fairly small. + */ + HA_CAN_INDEX_BLOBS | + /* + * Due to transactional influences, this will be + * the case. + * Although the count is good enough for practical + * purposes! + HA_NOT_EXACT_COUNT | + */ + /* + * This basically means we have a file with the name of + * database table (which we do). + */ + HA_FILE_BASED | + /* + * Not sure what this does (but MyISAM and InnoDB have it)?! + * Could it mean that we support the handler functions. + */ + HA_CAN_SQL_HANDLER | + /* + * This is not true, we cannot insert delayed, but a + * really cannot see what's wrong with inserting normally + * when asked to insert delayed! + * And the functionallity is required to pass the alter_table + * test. + * + * Disabled because of MySQL bug #40505 + */ + /*HA_CAN_INSERT_DELAYED |*/ +#if MYSQL_VERSION_ID > 50119 + /* We can do row logging, but not statement, because + * MVCC is not serializable! + */ + HA_BINLOG_ROW_CAPABLE | +#endif + /* + * Auto-increment is allowed on a partial key. + */ + HA_AUTO_PART_KEY); +} + +/* + * The following query from the DBT1 test is VERY slow + * if we do not set HA_READ_ORDER. + * The reason is that it must scan all duplicates, then + * sort. + * + * SELECT o_id, o_carrier_id, o_entry_d, o_ol_cnt + * FROM orders FORCE INDEX (o_w_id) + * WHERE o_w_id = 2 + * AND o_d_id = 1 + * AND o_c_id = 500 + * ORDER BY o_id DESC limit 1; + * + */ +#define FLAGS_ARE_READ_DYNAMICALLY + +MX_ULONG_T ha_pbxt::index_flags(uint inx __attribute__((unused)), uint part __attribute__((unused)), bool all_parts __attribute__((unused))) const +{ + /* It would be nice if the dynamic version of this function works, + * but it does not. MySQL loads this information when the table is openned, + * and then it is fixed. + * + * The problem is, I have had to remove the HA_READ_ORDER option although + * it applies to PBXT. PBXT returns entries in index order during an index + * scan in _almost_ all cases. + * + * A number of cases are demostrated here: [(11)] + * + * If involves the following conditions: + * - a SELECT FOR UPDATE, UPDATE or DELETE statement + * - an ORDER BY, or join that requires the sort order + * - another transaction which updates the index while it is being + * scanned. + * + * In this "obscure" case, the index scan may return index + * entries in the wrong order. + */ +#ifdef FLAGS_ARE_READ_DYNAMICALLY + /* If were are in an update (SELECT FOR UPDATE, UPDATE or DELETE), then + * it may be that we return the rows from an index in the wrong + * order! This is due to the fact that update reads wait for transactions + * to commit and this means that index entries may change position during + * the scan! + */ + if (pb_open_tab && pb_open_tab->ot_for_update) + return (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | HA_KEYREAD_ONLY); + /* If I understand HA_KEYREAD_ONLY then this means I do not + * need to fetch the record associated with an index + * key. + */ + return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE | HA_KEYREAD_ONLY); +#else + return (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | HA_KEYREAD_ONLY); +#endif +} + +void ha_pbxt::internal_close(THD *thd, struct XTThread *self) +{ + if (pb_share) { + xtBool removed; + XTOpenTablePtr ot; + + try_(a) { + /* This lock must be held when we remove the handler's + * open table because ha_close_open_tables() can run + * concurrently. + */ + xt_lock_mutex_ns(pb_share->sh_ex_mutex); + if ((ot = pb_open_tab)) { + pb_open_tab->ot_thread = self; + if (self->st_database != pb_open_tab->ot_table->tab_db) + xt_ha_open_database_of_table(self, pb_share->sh_table_path); + pb_open_tab = NULL; + pushr_(xt_db_return_table_to_pool, ot); + } + xt_unlock_mutex_ns(pb_share->sh_ex_mutex); + + ha_remove_from_handler_list(self, pb_share, this); + + /* Someone may be waiting for me to complete: */ + xt_broadcast_cond_ns((xt_cond_type *) pb_share->sh_ex_cond); + + removed = ha_unget_share_removed(self, pb_share); + + if (ot) { + /* Flush the table if this was the last handler: */ + /* This is not necessary but has the affect that + * FLUSH TABLES; does a checkpoint! + */ + if (removed) { + /* GOTCHA: + * This was killing performance as the number of threads increased! + * + * When MySQL runs out of table handlers because the table + * handler cache is too small, it starts to close handlers. + * (open_cache.records > table_cache_size) + * + * Which can lead to closing all handlers for a particular table. + * + * It does this while holding lock_OPEN! + * So this code below leads to a sync operation while lock_OPEN + * is held. The result is that the whole server comes to a stop. + */ + if (!thd || thd_sql_command(thd) == SQLCOM_FLUSH) // FLUSH TABLES + xt_sync_flush_table(self, ot); + } + freer_(); // xt_db_return_table_to_pool(ot); + } + } + catch_(a) { + xt_log_and_clear_exception(self); + } + cont_(a); + + pb_share = NULL; + } +} + +/* + * Used for opening tables. The name will be the name of the file. + * A table is opened when it needs to be opened. For instance + * when a request comes in for a select on the table (tables are not + * open and closed for each request, they are cached). + + * Called from handler.cc by handler::ha_open(). The server opens all tables by + * calling ha_open() which then calls the handler specific open(). + */ +int ha_pbxt::open(const char *table_path, int mode __attribute__((unused)), uint test_if_locked __attribute__((unused))) +{ + THD *thd = current_thd; + int err = 0; + XTThreadPtr self; + xtBool tabled_opened = FALSE; + + ref_length = XT_RECORD_OFFS_SIZE; + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + XT_PRINT1(self, "ha_pbxt::open %s\n", table_path); + + pb_ex_in_use = 1; + try_(a) { + xt_ha_open_database_of_table(self, (XTPathStrPtr) table_path); + + pb_share = ha_get_share(self, table_path, true, &tabled_opened); + ha_add_to_handler_list(self, pb_share, this); + if (pb_share->sh_table_lock) { + if (!ha_wait_for_shared_use(this, pb_share)) + xt_throw(self); + } + + ha_open_share(self, pb_share, &tabled_opened); + + thr_lock_data_init(&pb_share->sh_lock, &pb_lock, NULL); + if (!(pb_open_tab = xt_db_open_table_using_tab(pb_share->sh_table, self))) + xt_throw(self); + pb_open_tab->ot_thread = self; + + if (tabled_opened) { +#ifdef LOAD_TABLE_ON_OPEN + xt_tab_load_table(self, pb_open_tab); +#else + xt_tab_load_row_pointers(self, pb_open_tab); +#endif + xt_ind_set_index_selectivity(self, pb_open_tab); + pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 - pb_share->sh_table->tab_row_fnum) < 150; + } + + init_auto_increment(0); + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + internal_close(thd, self); + } + cont_(a); + + if (!err) + info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); + + pb_ex_in_use = 0; + if (pb_share) { + /* Someone may be waiting for me to complete: */ + if (pb_share->sh_table_lock) + xt_broadcast_cond_ns((xt_cond_type *) pb_share->sh_ex_cond); + } + return err; +} + + +/* + Closes a table. We call the free_share() function to free any resources + that we have allocated in the "shared" structure. + + Called from sql_base.cc, sql_select.cc, and table.cc. + In sql_select.cc it is only used to close up temporary tables or during + the process where a temporary table is converted over to being a + myisam table. + For sql_base.cc look at close_data_tables(). +*/ +int ha_pbxt::close(void) +{ + THD *thd = current_thd; + volatile int err = 0; + volatile XTThreadPtr self; + + if (thd) + self = ha_set_current_thread(thd, (int *) &err); + else { + XTExceptionRec e; + + if (!(self = xt_create_thread("TempForClose", FALSE, TRUE, &e))) { + xt_log_exception(NULL, &e, XT_LOG_DEFAULT); + return 0; + } + } + + XT_PRINT1(self, "ha_pbxt::close %s\n", pb_share && pb_share->sh_table_path->ps_path ? pb_share->sh_table_path->ps_path : "unknown"); + + if (self) { + try_(a) { + internal_close(thd, self); + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + cont_(a); + + if (!thd) + xt_free_thread(self); + } + else + xt_log(XT_NS_CONTEXT, XT_LOG_WARNING, "Unable to release table reference\n"); + + return err; +} + +void ha_pbxt::init_auto_increment(xtWord8 min_auto_inc) +{ + XTTableHPtr tab; + xtWord8 nr = 0; + int err; + + /* Get the value of the auto-increment value by + * loading the highest value from the index... + */ + tab = pb_open_tab->ot_table; + + /* Cannot do this if the index version is bad! */ + if (tab->tab_dic.dic_disable_index) + return; + + xt_spinlock_lock(&tab->tab_ainc_lock); + if (table->found_next_number_field && !tab->tab_auto_inc) { + Field *tmp_fie = table->next_number_field; + THD *tmp_thd = table->in_use; + xtBool xn_started = FALSE; + XTThreadPtr self = pb_open_tab->ot_thread; + + /* + * A table may be opened by a thread with a running + * transaction! + * Since get_auto_increment() does not do an update, + * it should be OK to use the transaction we already + * have to get the next auto-increment value. + */ + if (!self->st_xact_data) { + self->st_xact_mode = XT_XACT_REPEATABLE_READ; + self->st_ignore_fkeys = FALSE; + self->st_auto_commit = TRUE; + self->st_table_trans = FALSE; + self->st_abort_trans = FALSE; + self->st_stat_ended = FALSE; + self->st_stat_trans = FALSE; + self->st_is_update = FALSE; + if (!xt_xn_begin(self)) { + xt_spinlock_unlock(&tab->tab_ainc_lock); + xt_throw(self); + } + xn_started = TRUE; + } + + /* Setup the conditions for the next call! */ + table->in_use = current_thd; + table->next_number_field = table->found_next_number_field; + + extra(HA_EXTRA_KEYREAD); + table->mark_columns_used_by_index_no_reset(TS(table)->next_number_index, table->read_set); + column_bitmaps_signal(); + index_init(TS(table)->next_number_index, 0); + if (!TS(table)->next_number_key_offset) { + // Autoincrement at key-start + err = index_last(table->record[1]); + if (!err) + /* {PRE-INC} */ + nr = (xtWord8) table->next_number_field->val_int_offset(TS(table)->rec_buff_length); + } + else { + /* Do an index scan to find the largest value! */ + /* The standard method will not work because it forces + * us to lock that table! + */ + xtWord8 val; + + err = index_first(table->record[1]); + while (!err) { + /* {PRE-INC} */ + val = (xtWord8) table->next_number_field->val_int_offset(TS(table)->rec_buff_length); + if (val > nr) + nr = val; + err = index_next(table->record[1]); + } + } + + index_end(); + extra(HA_EXTRA_NO_KEYREAD); + + /* {PRE-INC} + * I have changed this from post increment to pre-increment! + * The reason is: + * When using post increment we are not able to return + * the last valid value in the range. + * + * Here the test example: + * + * drop table if exists t1; + * create table t1 (i tinyint unsigned not null auto_increment primary key) engine=pbxt; + * insert into t1 set i = 254; + * insert into t1 set i = null; + * + * With post-increment, this last insert fails because on post increment + * the value overflows! + * + * Pre-increment means we store the current max, and increment + * before returning the next value. + * + * This will work in this situation. + */ + tab->tab_auto_inc = nr; + if (tab->tab_auto_inc < tab->tab_dic.dic_min_auto_inc) + tab->tab_auto_inc = tab->tab_dic.dic_min_auto_inc-1; + if (tab->tab_auto_inc < min_auto_inc) + tab->tab_auto_inc = min_auto_inc-1; + + /* Restore the changed values: */ + table->next_number_field = tmp_fie; + table->in_use = tmp_thd; + + if (xn_started) + xt_xn_commit(self); + } + xt_spinlock_unlock(&tab->tab_ainc_lock); +} + +void ha_pbxt::get_auto_increment(MX_ULONGLONG_T offset, MX_ULONGLONG_T increment, + MX_ULONGLONG_T nb_desired_values __attribute__((unused)), + MX_ULONGLONG_T *first_value, + MX_ULONGLONG_T *nb_reserved_values __attribute__((unused))) +{ + register XTTableHPtr tab; + MX_ULONGLONG_T nr, nr_less_inc; + + ASSERT_NS(pb_ex_in_use); + + tab = pb_open_tab->ot_table; + + /* {PRE-INC} + * Assume that nr contains the last value returned! + * We will increment and then return the value. + */ + xt_spinlock_lock(&tab->tab_ainc_lock); + nr = (MX_ULONGLONG_T) tab->tab_auto_inc; + nr_less_inc = nr; + if (nr < offset) + nr = offset; + else if (increment > 1 && ((nr - offset) % increment) != 0) + nr += increment - ((nr - offset) % increment); + else + nr += increment; + if (table->next_number_field->cmp((const unsigned char *)&nr_less_inc, (const unsigned char *)&nr) < 0) + tab->tab_auto_inc = (xtWord8) (nr); + else + nr = ~0; /* indicate error to the caller */ + xt_spinlock_unlock(&tab->tab_ainc_lock); + + *first_value = nr; + *nb_reserved_values = 1; +} + +/* GOTCHA: We need to use signed value here because of the test + * (from auto_increment.test): + * create table t1 (a int not null auto_increment primary key); + * insert into t1 values (NULL); + * insert into t1 values (-1); + * insert into t1 values (NULL); + */ +void ha_pbxt::set_auto_increment(Field *nr) +{ + register XTTableHPtr tab; + MX_ULONGLONG_T nr_int_val; + + nr_int_val = nr->val_int(); + tab = pb_open_tab->ot_table; + + if (nr->cmp((const unsigned char *)&tab->tab_auto_inc) > 0) { + xt_spinlock_lock(&tab->tab_ainc_lock); + + if (nr->cmp((const unsigned char *)&tab->tab_auto_inc) > 0) { + /* {PRE-INC} + * We increment later, so just set the value! + MX_ULONGLONG_T nr_int_val_plus_one = nr_int_val + 1; + if (nr->cmp((const unsigned char *)&nr_int_val_plus_one) < 0) + tab->tab_auto_inc = nr_int_val_plus_one; + else + */ + tab->tab_auto_inc = nr_int_val; + } + xt_spinlock_unlock(&tab->tab_ainc_lock); + } + + if (xt_db_auto_increment_mode == 1) { + if (nr_int_val > (MX_ULONGLONG_T) tab->tab_dic.dic_min_auto_inc) { + /* Do this every 100 calls: */ +#ifdef DEBUG + tab->tab_dic.dic_min_auto_inc = nr_int_val + 5; +#else + tab->tab_dic.dic_min_auto_inc = nr_int_val + 100; +#endif + pb_open_tab->ot_thread = xt_get_self(); + if (!xt_tab_write_min_auto_inc(pb_open_tab)) + xt_log_and_clear_exception(pb_open_tab->ot_thread); + } + } +} + +/* +static void dump_buf(unsigned char *buf, int len) +{ + int i; + + for (i=0; i<len; i++) printf("%2c", buf[i] <= 127 ? buf[i] : '.'); + printf("\n"); + for (i=0; i<len; i++) printf("%02x", buf[i]); + printf("\n"); +} +*/ + +/* + * write_row() inserts a row. No extra() hint is given currently if a bulk load + * is happeneding. buf() is a byte array of data. You can use the field + * information to extract the data from the native byte array type. + * Example of this would be: + * for (Field **field=table->field ; *field ; field++) + * { + * ... + * } + + * See ha_tina.cc for an example of extracting all of the data as strings. + * ha_berekly.cc has an example of how to store it intact by "packing" it + * for ha_berkeley's own native storage type. + + * See the note for update_row() on auto_increments and timestamps. This + * case also applied to write_row(). + + * Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc, + * sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc. + */ +int ha_pbxt::write_row(byte *buf) +{ + int err = 0; + + ASSERT_NS(pb_ex_in_use); + + XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::write_row %s\n", pb_share->sh_table_path->ps_path); + XT_DISABLED_TRACE(("INSERT tx=%d val=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(&buf[1]))); + //statistic_increment(ha_write_count,&LOCK_status); + + /* GOTCHA: I have a huge problem with the transaction statement. + * It is not ALWAYS committed (I mean ha_commit_trans() is + * not always called - for example in SELECT). + * + * If I call trans_register_ha() but ha_commit_trans() is not called + * then MySQL thinks a transaction is still running (while + * I have committed the auto-transaction in ha_pbxt::external_lock()). + * + * This causes all kinds of problems, like transactions + * are killed when they should not be. + * + * To prevent this, I only inform MySQL that a transaction + * has beens started when an update is performed. I have determined that + * ha_commit_trans() is only guarenteed to be called if an update is done. + */ + if (!pb_open_tab->ot_thread->st_stat_trans) { + trans_register_ha(pb_mysql_thd, FALSE, pbxt_hton); + XT_PRINT0(pb_open_tab->ot_thread, "ha_pbxt::write_row trans_register_ha all=FALSE\n"); + pb_open_tab->ot_thread->st_stat_trans = TRUE; + } + + xt_xlog_check_long_writer(pb_open_tab->ot_thread); + + if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) + table->timestamp_field->set_time(); + + if (table->next_number_field && buf == table->record[0]) { + int update_err = update_auto_increment(); + if (update_err) { + ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + return update_err; + } + set_auto_increment(table->next_number_field); + } + + if (!xt_tab_new_record(pb_open_tab, (xtWord1 *) buf)) { + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + + /* + * This is needed to allow the same row to be updated multiple times in case of bulk REPLACE. + * This happens during execution of LOAD DATA...REPLACE MySQL first tries to INSERT the row + * and if it gets dup-key error it tries UPDATE, so the same row can be overwriten multiple + * times within the same statement + */ + if (err == HA_ERR_FOUND_DUPP_KEY && pb_open_tab->ot_thread->st_is_update) + pb_open_tab->ot_thread->st_update_id++; + } + + return err; +} + +#ifdef UNUSED_CODE +static int equ_bin(const byte *a, const char *b) +{ + while (*a && *b) { + if (*a != *b) + return 0; + a++; + b++; + } + return 1; +} +static void dump_bin(const byte *a_in, int offset, int len_in) +{ + const byte *a = a_in; + int len = len_in; + + a += offset; + while (len > 0) { + xt_trace("%02X", (int) *a); + a++; + len--; + } + xt_trace("=="); + a = a_in; + len = len_in; + a += offset; + while (len > 0) { + xt_trace("%c", (*a > 8 && *a < 127) ? *a : '.'); + a++; + len--; + } + xt_trace("\n"); +} +#endif + +/* + * Yes, update_row() does what you expect, it updates a row. old_data will have + * the previous row record in it, while new_data will have the newest data in + * it. Keep in mind that the server can do updates based on ordering if an ORDER BY + * clause was used. Consecutive ordering is not guarenteed. + * + * Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc. + */ +int ha_pbxt::update_row(const byte * old_data, byte * new_data) +{ + int err = 0; + register XTThreadPtr self = pb_open_tab->ot_thread; + + ASSERT_NS(pb_ex_in_use); + + XT_PRINT1(self, "ha_pbxt::update_row %s\n", pb_share->sh_table_path->ps_path); + XT_DISABLED_TRACE(("UPDATE tx=%d val=%d\n", (int) self->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(&new_data[1]))); + //statistic_increment(ha_update_count,&LOCK_status); + + if (!self->st_stat_trans) { + trans_register_ha(pb_mysql_thd, FALSE, pbxt_hton); + XT_PRINT0(self, "ha_pbxt::update_row trans_register_ha all=FALSE\n"); + self->st_stat_trans = TRUE; + } + + xt_xlog_check_long_writer(self); + + if (!self->st_is_update) { + self->st_is_update = TRUE; + self->st_update_id++; + } + + if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) + table->timestamp_field->set_time(); + + /* GOTCHA: We need to check the auto-increment value on update + * because of the following test (which fails for InnoDB) - + * auto_increment.test: + * create table t1 (a int not null auto_increment primary key, val int); + * insert into t1 (val) values (1); + * update t1 set a=2 where a=1; + * insert into t1 (val) values (1); + */ + if (table->found_next_number_field && new_data == table->record[0]) { + MX_LONGLONG_T nr; + my_bitmap_map *old_map; + + old_map = mx_tmp_use_all_columns(table, table->read_set); + nr = table->found_next_number_field->val_int(); + set_auto_increment(table->found_next_number_field); + mx_tmp_restore_column_map(table, old_map); + } + + if (!xt_tab_update_record(pb_open_tab, (xtWord1 *) old_data, (xtWord1 *) new_data)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + + pb_open_tab->ot_table->tab_locks.xt_remove_temp_lock(pb_open_tab, TRUE); + + return err; +} + +/* + * This will delete a row. buf will contain a copy of the row to be deleted. + * The server will call this right after the current row has been called (from + * either a previous rnd_next() or index call). + * + * Called in sql_acl.cc and sql_udf.cc to manage internal table information. + * Called in sql_delete.cc, sql_insert.cc, and sql_select.cc. In sql_select it is + * used for removing duplicates while in insert it is used for REPLACE calls. +*/ +int ha_pbxt::delete_row(const byte * buf) +{ + int err = 0; + + ASSERT_NS(pb_ex_in_use); + + XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::delete_row %s\n", pb_share->sh_table_path->ps_path); + XT_DISABLED_TRACE(("DELETE tx=%d val=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(&buf[1]))); + //statistic_increment(ha_delete_count,&LOCK_status); + + if (!pb_open_tab->ot_thread->st_stat_trans) { + trans_register_ha(pb_mysql_thd, FALSE, pbxt_hton); + XT_PRINT0(pb_open_tab->ot_thread, "ha_pbxt::delete_row trans_register_ha all=FALSE\n"); + pb_open_tab->ot_thread->st_stat_trans = TRUE; + } + + xt_xlog_check_long_writer(pb_open_tab->ot_thread); + + if (!xt_tab_delete_record(pb_open_tab, (xtWord1 *) buf)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + + pb_open_tab->ot_table->tab_locks.xt_remove_temp_lock(pb_open_tab, TRUE); + + return err; +} + +/* + * ----------------------------------------------------------------------- + * INDEX METHODS + */ + +/* + * This looks like a hack, but actually, it is OK. + * It depends on the setup done by the super-class. It involves an extra + * range check that we need to do if a "new" record is returned during + * an index scan. + * + * A new record is returned if a row is updated (by another transaction) + * during the index scan. If an update is detected, then the scan stops + * and waits for the transaction to end. + * + * If the transaction commits, then the updated row is returned instead + * of the row it would have returned when doing a consistant read + * (repeatable read). + * + * These new records can appear out of index order, and may not even + * belong to the index range that we are concerned with. + * + * Notice that there is not check for the start of the range. It appears + * that this is not necessary, MySQL seems to have no problem ignoring + * such values. + * + * A number of test have been given below which demonstrate the use + * of the function. + * + * They also demonstrate the ORDER BY problem described here: [(11)]. + * + * DROP TABLE IF EXISTS test_tab, test_tab_1, test_tab_2; + * CREATE TABLE test_tab (ID int primary key, Value int, Name varchar(20), index(Value, Name)) ENGINE=pbxt; + * INSERT test_tab values(1, 1, 'A'); + * INSERT test_tab values(2, 1, 'B'); + * INSERT test_tab values(3, 1, 'C'); + * INSERT test_tab values(4, 2, 'D'); + * INSERT test_tab values(5, 2, 'E'); + * INSERT test_tab values(6, 2, 'F'); + * INSERT test_tab values(7, 2, 'G'); + * + * select * from test_tab where value = 1 order by value, name for update; + * + * -- Test: 1 + * -- C1 + * begin; + * select * from test_tab where id = 5 for update; + * + * -- C2 + * begin; + * select * from test_tab where value = 2 order by value, name for update; + * + * -- C1 + * update test_tab set value = 3 where id = 6; + * commit; + * + * -- Test: 2 + * -- C1 + * begin; + * select * from test_tab where id = 5 for update; + * + * -- C2 + * begin; + * select * from test_tab where value >= 2 order by value, name for update; + * + * -- C1 + * update test_tab set value = 3 where id = 6; + * commit; + * + * -- Test: 3 + * -- C1 + * begin; + * select * from test_tab where id = 5 for update; + * + * -- C2 + * begin; + * select * from test_tab where value = 2 order by value, name for update; + * + * -- C1 + * update test_tab set value = 1 where id = 6; + * commit; + */ + +int ha_pbxt::xt_index_in_range(register XTOpenTablePtr ot __attribute__((unused)), register XTIndexPtr ind, + register XTIdxSearchKeyPtr search_key, xtWord1 *buf) +{ + /* If search key is given, this means we want an exact match. */ + if (search_key) { + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE]; + + myxt_create_key_from_row(ind, key_buf, buf, NULL); + search_key->sk_on_key = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length, + search_key->sk_key_value.sv_key, key_buf) == 0; + return search_key->sk_on_key; + } + + /* Otherwise, check the end of the range. */ + if (end_range) + return compare_key(end_range) <= 0; + return 1; +} + +int ha_pbxt::xt_index_next_read(register XTOpenTablePtr ot, register XTIndexPtr ind, xtBool key_only, + register XTIdxSearchKeyPtr search_key, byte *buf) +{ + xt_xlog_check_long_writer(ot->ot_thread); + + if (key_only) { + /* We only need to read the data from the key: */ + while (ot->ot_curr_rec_id) { + if (search_key && !search_key->sk_on_key) + break; + + switch (xt_tab_visible(ot)) { + case FALSE: + if (xt_idx_next(ot, ind, search_key)) + break; + case XT_ERR: + goto failed; + case XT_NEW: + if (!xt_idx_read(ot, ind, (xtWord1 *) buf)) + goto failed; + if (xt_index_in_range(ot, ind, search_key, buf)) { + return 0; + } + if (!xt_idx_next(ot, ind, search_key)) + goto failed; + break; + case XT_RETRY: + /* We cannot start from the beginning again, if we have + * already output rows! + * And we need the orginal search key. + * + * The case in which this occurs is: + * + * T1: UPDATE tbl_file SET GlobalID = 'DBCD5C4514210200825501089884844_6M' WHERE ID = 39 + * Locks a particular row. + * + * T2: SELECT ID,Flags FROM tbl_file WHERE SpaceID = 1 AND Path = '/zi/America/' AND + * Name = 'Cuiaba' AND Flags IN ( 0,1,4,5 ) FOR UPDATE + * scans the index and stops on the lock (of the before image) above. + * + * T1 quits, the sweeper deletes the record updated by T1?! + * BUG: Cleanup should wait until T2 is complete! + * + * T2 continues, and returns XT_RETRY. + * + * At this stage T2 has already returned some rows, so it may not retry from the + * start. Instead it tries to locate the last record it tried to lock. + * This record is gone (or not visible), so it finds the next one. + * + * POTENTIAL BUG: If cleanup does not wait until T2 is complete, then + * I may miss the update record, if it is moved before the index scan + * position. + */ + if (!pb_ind_row_count && search_key) { + if (!xt_idx_search(pb_open_tab, ind, search_key)) + return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + } + else { + if (!xt_idx_research(pb_open_tab, ind)) + goto failed; + } + break; + default: + if (!xt_idx_read(ot, ind, (xtWord1 *) buf)) + goto failed; + return 0; + } + } + } + else { + while (ot->ot_curr_rec_id) { + if (search_key && !search_key->sk_on_key) + break; + + switch (xt_tab_read_record(ot, (xtWord1 *) buf)) { + case FALSE: + XT_DISABLED_TRACE(("not visi tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_xn_id, (int) ot->ot_curr_rec_id)); + if (xt_idx_next(ot, ind, search_key)) + break; + case XT_ERR: + goto failed; + case XT_NEW: + if (xt_index_in_range(ot, ind, search_key, buf)) + return 0; + if (!xt_idx_next(ot, ind, search_key)) + goto failed; + break; + case XT_RETRY: + if (!pb_ind_row_count && search_key) { + if (!xt_idx_search(pb_open_tab, ind, search_key)) + return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + } + else { + if (!xt_idx_research(pb_open_tab, ind)) + goto failed; + } + break; + default: + XT_DISABLED_TRACE(("visible tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_xn_id, (int) ot->ot_curr_rec_id)); + return 0; + } + } + } + return HA_ERR_END_OF_FILE; + + failed: + return ha_log_pbxt_thread_error_for_mysql(FALSE); +} + +int ha_pbxt::xt_index_prev_read(XTOpenTablePtr ot, XTIndexPtr ind, xtBool key_only, + register XTIdxSearchKeyPtr search_key, byte *buf) +{ + if (key_only) { + /* We only need to read the data from the key: */ + while (ot->ot_curr_rec_id) { + if (search_key && !search_key->sk_on_key) + break; + + switch (xt_tab_visible(ot)) { + case FALSE: + if (xt_idx_prev(ot, ind, search_key)) + break; + case XT_ERR: + goto failed; + case XT_NEW: + if (!xt_idx_read(ot, ind, (xtWord1 *) buf)) + goto failed; + if (xt_index_in_range(ot, ind, search_key, buf)) + return 0; + if (!xt_idx_next(ot, ind, search_key)) + goto failed; + break; + case XT_RETRY: + if (!pb_ind_row_count && search_key) { + if (!xt_idx_search_prev(pb_open_tab, ind, search_key)) + return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + } + else { + if (!xt_idx_research(pb_open_tab, ind)) + goto failed; + } + break; + default: + if (!xt_idx_read(ot, ind, (xtWord1 *) buf)) + goto failed; + return 0; + } + } + } + else { + /* We need to read the entire record: */ + while (ot->ot_curr_rec_id) { + if (search_key && !search_key->sk_on_key) + break; + + switch (xt_tab_read_record(ot, (xtWord1 *) buf)) { + case FALSE: + if (xt_idx_prev(ot, ind, search_key)) + break; + case XT_ERR: + goto failed; + case XT_NEW: + if (xt_index_in_range(ot, ind, search_key, buf)) + return 0; + if (!xt_idx_next(ot, ind, search_key)) + goto failed; + break; + case XT_RETRY: + if (!pb_ind_row_count && search_key) { + if (!xt_idx_search_prev(pb_open_tab, ind, search_key)) + return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + } + else { + if (!xt_idx_research(pb_open_tab, ind)) + goto failed; + } + break; + default: + return 0; + } + } + } + return HA_ERR_END_OF_FILE; + + failed: + return ha_log_pbxt_thread_error_for_mysql(FALSE); +} + +int ha_pbxt::index_init(uint idx, bool sorted __attribute__((unused))) +{ + XTIndexPtr ind; + + /* select count(*) from smalltab_PBXT; + * ignores the error below, and continues to + * call index_first! + */ + active_index = idx; + + if (pb_open_tab->ot_table->tab_dic.dic_disable_index) { + xt_tab_set_index_error(pb_open_tab->ot_table); + return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + } + + /* The number of columns required: */ + if (pb_open_tab->ot_is_modify) { + pb_open_tab->ot_cols_req = table->read_set->n_bits; +#ifdef XT_PRINT_INDEX_OPT + ind = (XTIndexPtr) pb_share->sh_dic_keys[idx]; + + printf("index_init %s index %d cols req=%d/%d read_bits=%X write_bits=%X index_bits=%X\n", pb_open_tab->ot_table->tab_name->ps_path, (int) idx, pb_open_tab->ot_cols_req, pb_open_tab->ot_cols_req, (int) *table->read_set->bitmap, (int) *table->write_set->bitmap, (int) *ind->mi_col_map.bitmap); +#endif + } + else { + pb_open_tab->ot_cols_req = ha_get_max_bit(table->read_set); + + /* Check for index coverage! + * + * Given the following table: + * + * CREATE TABLE `customer` ( + * `c_id` int(11) NOT NULL DEFAULT '0', + * `c_d_id` int(11) NOT NULL DEFAULT '0', + * `c_w_id` int(11) NOT NULL DEFAULT '0', + * `c_first` varchar(16) DEFAULT NULL, + * `c_middle` char(2) DEFAULT NULL, + * `c_last` varchar(16) DEFAULT NULL, + * `c_street_1` varchar(20) DEFAULT NULL, + * `c_street_2` varchar(20) DEFAULT NULL, + * `c_city` varchar(20) DEFAULT NULL, + * `c_state` char(2) DEFAULT NULL, + * `c_zip` varchar(9) DEFAULT NULL, + * `c_phone` varchar(16) DEFAULT NULL, + * `c_since` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + * `c_credit` char(2) DEFAULT NULL, + * `c_credit_lim` decimal(24,12) DEFAULT NULL, + * `c_discount` double DEFAULT NULL, + * `c_balance` decimal(24,12) DEFAULT NULL, + * `c_ytd_payment` decimal(24,12) DEFAULT NULL, + * `c_payment_cnt` double DEFAULT NULL, + * `c_delivery_cnt` double DEFAULT NULL, + * `c_data` text, + * PRIMARY KEY (`c_w_id`,`c_d_id`,`c_id`), + * KEY `c_w_id` (`c_w_id`,`c_d_id`,`c_last`,`c_first`,`c_id`) + * ) ENGINE=PBXT; + * + * MySQL does not recognize index coverage on the followin select: + * + * SELECT c_id FROM customer WHERE c_w_id = 3 AND c_d_id = 8 AND + * c_last = 'EINGATIONANTI' ORDER BY c_first ASC LIMIT 1; + * + * TODO: Find out why this is necessary, MyISAM does not + * seem to have this problem! + */ + ind = (XTIndexPtr) pb_share->sh_dic_keys[idx]; + if (bitmap_is_subset(table->read_set, &ind->mi_col_map)) + pb_key_read = TRUE; +#ifdef XT_PRINT_INDEX_OPT + printf("index_init %s index %d cols req=%d/%d read_bits=%X write_bits=%X index_bits=%X converage=%d\n", pb_open_tab->ot_table->tab_name->ps_path, (int) idx, pb_open_tab->ot_cols_req, table->read_set->n_bits, (int) *table->read_set->bitmap, (int) *table->write_set->bitmap, (int) *ind->mi_col_map.bitmap, (int) (bitmap_is_subset(table->read_set, &ind->mi_col_map) != 0)); +#endif + } + + xt_xlog_check_long_writer(pb_open_tab->ot_thread); + + pb_open_tab->ot_thread->st_statistics.st_scan_index++; + return 0; +} + +int ha_pbxt::index_end() +{ + int err = 0; + + XT_TRACE_CALL(); + + XTThreadPtr thread = pb_open_tab->ot_thread; + + /* + * the assertion below is not always held, because the sometimes handler is unlocked + * before this function is called + */ + /*ASSERT_NS(pb_ex_in_use);*/ + + if (pb_open_tab->ot_ind_rhandle) { + xt_ind_release_handle(pb_open_tab->ot_ind_rhandle, FALSE, thread); + pb_open_tab->ot_ind_rhandle = NULL; + } + + /* + * make permanent the lock for the last scanned row + */ + if (pb_open_tab) + pb_open_tab->ot_table->tab_locks.xt_make_lock_permanent(pb_open_tab, &thread->st_lock_list); + + xt_xlog_check_long_writer(thread); + + active_index = MAX_KEY; + XT_RETURN(err); +} + +#ifdef XT_TRACK_RETURNED_ROWS +void ha_start_scan(XTOpenTablePtr ot, u_int index) +{ + xt_ttracef(ot->ot_thread, "SCAN %d:%d\n", (int) ot->ot_table->tab_id, (int) index); + ot->ot_rows_ret_curr = 0; + for (u_int i=0; i<ot->ot_rows_ret_max; i++) + ot->ot_rows_returned[i] = 0; +} + +void ha_return_row(XTOpenTablePtr ot, u_int index) +{ + xt_ttracef(ot->ot_thread, "%d:%d ROW=%d:%d\n", + (int) ot->ot_table->tab_id, (int) index, (int) ot->ot_curr_row_id, (int) ot->ot_curr_rec_id); + ot->ot_rows_ret_curr++; + if (ot->ot_curr_row_id >= ot->ot_rows_ret_max) { + if (!xt_realloc_ns((void **) &ot->ot_rows_returned, (ot->ot_curr_row_id+1) * sizeof(xtRecordID))) + ASSERT_NS(FALSE); + memset(&ot->ot_rows_returned[ot->ot_rows_ret_max], 0, (ot->ot_curr_row_id+1 - ot->ot_rows_ret_max) * sizeof(xtRecordID)); + ot->ot_rows_ret_max = ot->ot_curr_row_id+1; + } + if (!ot->ot_curr_row_id || !ot->ot_curr_rec_id || ot->ot_rows_returned[ot->ot_curr_row_id]) { + char *sql = *thd_query(current_thd); + + xt_ttracef(ot->ot_thread, "DUP %d:%d %s\n", + (int) ot->ot_table->tab_id, (int) index, *thd_query(current_thd)); + xt_dump_trace(); + printf("ERROR: row=%d rec=%d newr=%d, already returned!\n", (int) ot->ot_curr_row_id, (int) ot->ot_rows_returned[ot->ot_curr_row_id], (int) ot->ot_curr_rec_id); + printf("ERROR: %s\n", sql); +#ifdef XT_WIN + FatalAppExit(0, "Debug Me!"); +#endif + } + else + ot->ot_rows_returned[ot->ot_curr_row_id] = ot->ot_curr_rec_id; +} +#endif + +int ha_pbxt::index_read_xt(byte * buf, uint idx, const byte *key, uint key_len __attribute__((unused)), enum ha_rkey_function find_flag __attribute__((unused))) +{ + int err = 0; + XTIndexPtr ind; + int prefix = 0; + XTIdxSearchKeyRec search_key; + +#ifdef XT_TRACK_RETURNED_ROWS + ha_start_scan(pb_open_tab, idx); +#endif + + /* This call starts a search on this handler! */ + pb_ind_row_count = 0; + + ASSERT_NS(pb_ex_in_use); + + XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::index_read_xt %s\n", pb_share->sh_table_path->ps_path); + XT_DISABLED_TRACE(("search tx=%d val=%d update=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(key), pb_modified)); + ind = (XTIndexPtr) pb_share->sh_dic_keys[idx]; + + switch (find_flag) { + case HA_READ_PREFIX_LAST: + case HA_READ_PREFIX_LAST_OR_PREV: + prefix = SEARCH_PREFIX; + case HA_READ_BEFORE_KEY: + case HA_READ_KEY_OR_PREV: // I assume you want to be positioned on the last entry in the key duplicate list!! + xt_idx_prep_key(ind, &search_key, ((find_flag == HA_READ_BEFORE_KEY) ? 0 : XT_SEARCH_AFTER_KEY) | prefix, (xtWord1 *) key, (size_t) key_len); + if (!xt_idx_search_prev(pb_open_tab, ind, &search_key)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + else + err = xt_index_prev_read(pb_open_tab, ind, pb_key_read, + (find_flag == HA_READ_PREFIX_LAST) ? &search_key : NULL, buf); + break; + case HA_READ_PREFIX: + prefix = SEARCH_PREFIX; + case HA_READ_KEY_EXACT: + case HA_READ_KEY_OR_NEXT: + case HA_READ_AFTER_KEY: + default: + xt_idx_prep_key(ind, &search_key, ((find_flag == HA_READ_AFTER_KEY) ? XT_SEARCH_AFTER_KEY : 0) | prefix, (xtWord1 *) key, key_len); + if (!xt_idx_search(pb_open_tab, ind, &search_key)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + else + err = xt_index_next_read(pb_open_tab, ind, pb_key_read, + (find_flag == HA_READ_KEY_EXACT || find_flag == HA_READ_PREFIX) ? &search_key : NULL, buf); + break; + } + + pb_ind_row_count++; +#ifdef XT_TRACK_RETURNED_ROWS + if (!err) + ha_return_row(pb_open_tab, idx); +#endif + XT_DISABLED_TRACE(("search tx=%d val=%d err=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(key), err)); + if (err) + table->status = STATUS_NOT_FOUND; + else { + pb_open_tab->ot_thread->st_statistics.st_row_select++; + table->status = 0; + } + return err; +} + +/* + * Positions an index cursor to the index specified in the handle. Fetches the + * row if available. If the key value is null, begin at the first key of the + * index. + */ +int ha_pbxt::index_read(byte * buf, const byte * key, uint key_len __attribute__((unused)), enum ha_rkey_function find_flag __attribute__((unused))) +{ + //statistic_increment(ha_read_key_count,&LOCK_status); + return index_read_xt(buf, active_index, key, key_len, find_flag); +} + +int ha_pbxt::index_read_idx(byte * buf, uint idx, const byte *key, uint key_len __attribute__((unused)), enum ha_rkey_function find_flag __attribute__((unused))) +{ + //statistic_increment(ha_read_key_count,&LOCK_status); + return index_read_xt(buf, idx, key, key_len, find_flag); +} + +int ha_pbxt::index_read_last(byte * buf, const byte * key, uint key_len) +{ + //statistic_increment(ha_read_key_count,&LOCK_status); + return index_read_xt(buf, active_index, key, key_len, HA_READ_PREFIX_LAST); +} + +/* + * Used to read forward through the index. + */ +int ha_pbxt::index_next(byte * buf) +{ + int err = 0; + XTIndexPtr ind; + + XT_TRACE_CALL(); + //statistic_increment(ha_read_next_count,&LOCK_status); + ASSERT_NS(pb_ex_in_use); + + ind = (XTIndexPtr) pb_share->sh_dic_keys[active_index]; + + if (!xt_idx_next(pb_open_tab, ind, NULL)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + else + err = xt_index_next_read(pb_open_tab, ind, pb_key_read, NULL, buf); + + pb_ind_row_count++; +#ifdef XT_TRACK_RETURNED_ROWS + if (!err) + ha_return_row(pb_open_tab, active_index); +#endif + if (err) + table->status = STATUS_NOT_FOUND; + else { + pb_open_tab->ot_thread->st_statistics.st_row_select++; + table->status = 0; + } + XT_RETURN(err); +} + +/* + * I have implemented this because there is currently a + * bug in handler::index_next_same(). + * + * drop table if exists t1; + * CREATE TABLE t1 (a int, b int, primary key(a,b)) + * PARTITION BY KEY(b,a) PARTITIONS 2; + * insert into t1 values (0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6); + * select * from t1 where a = 4; + * + */ +int ha_pbxt::index_next_same(byte * buf, const byte *key, uint length) +{ + int err = 0; + XTIndexPtr ind; + XTIdxSearchKeyRec search_key; + + XT_TRACE_CALL(); + //statistic_increment(ha_read_next_count,&LOCK_status); + ASSERT_NS(pb_ex_in_use); + + ind = (XTIndexPtr) pb_share->sh_dic_keys[active_index]; + + search_key.sk_key_value.sv_flags = HA_READ_KEY_EXACT; + search_key.sk_key_value.sv_rec_id = 0; + search_key.sk_key_value.sv_row_id = 0; + search_key.sk_key_value.sv_key = search_key.sk_key_buf; + search_key.sk_key_value.sv_length = myxt_create_key_from_key(ind, search_key.sk_key_buf, (xtWord1 *) key, (u_int) length); + search_key.sk_on_key = TRUE; + + if (!xt_idx_next(pb_open_tab, ind, &search_key)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + else + err = xt_index_next_read(pb_open_tab, ind, pb_key_read, &search_key, buf); + + pb_ind_row_count++; +#ifdef XT_TRACK_RETURNED_ROWS + if (!err) + ha_return_row(pb_open_tab, active_index); +#endif + if (err) + table->status = STATUS_NOT_FOUND; + else { + pb_open_tab->ot_thread->st_statistics.st_row_select++; + table->status = 0; + } + XT_RETURN(err); +} + +/* + * Used to read backwards through the index. + */ +int ha_pbxt::index_prev(byte * buf) +{ + int err = 0; + XTIndexPtr ind; + + XT_TRACE_CALL(); + //statistic_increment(ha_read_prev_count,&LOCK_status); + ASSERT_NS(pb_ex_in_use); + + ind = (XTIndexPtr) pb_share->sh_dic_keys[active_index]; + + if (!xt_idx_prev(pb_open_tab, ind, NULL)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + else + err = xt_index_prev_read(pb_open_tab, ind, pb_key_read, NULL, buf); + + pb_ind_row_count++; +#ifdef XT_TRACK_RETURNED_ROWS + if (!err) + ha_return_row(pb_open_tab, active_index); +#endif + if (err) + table->status = STATUS_NOT_FOUND; + else { + pb_open_tab->ot_thread->st_statistics.st_row_select++; + table->status = 0; + } + XT_RETURN(err); +} + +/* + * index_first() asks for the first key in the index. + */ +int ha_pbxt::index_first(byte * buf) +{ + int err = 0; + XTIndexPtr ind; + XTIdxSearchKeyRec search_key; + + XT_TRACE_CALL(); + //statistic_increment(ha_read_first_count,&LOCK_status); + ASSERT_NS(pb_ex_in_use); + +#ifdef XT_TRACK_RETURNED_ROWS + ha_start_scan(pb_open_tab, active_index); +#endif + pb_ind_row_count = 0; + + ind = (XTIndexPtr) pb_share->sh_dic_keys[active_index]; + + xt_idx_prep_key(ind, &search_key, XT_SEARCH_FIRST_FLAG, NULL, 0); + if (!xt_idx_search(pb_open_tab, ind, &search_key)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + else + err = xt_index_next_read(pb_open_tab, ind, pb_key_read, NULL, buf); + + pb_ind_row_count++; +#ifdef XT_TRACK_RETURNED_ROWS + if (!err) + ha_return_row(pb_open_tab, active_index); +#endif + if (err) + table->status = STATUS_NOT_FOUND; + else { + pb_open_tab->ot_thread->st_statistics.st_row_select++; + table->status = 0; + } + XT_RETURN(err); +} + +/* + * index_last() asks for the last key in the index. + */ +int ha_pbxt::index_last(byte * buf) +{ + int err = 0; + XTIndexPtr ind; + XTIdxSearchKeyRec search_key; + + XT_TRACE_CALL(); + //statistic_increment(ha_read_last_count,&LOCK_status); + ASSERT_NS(pb_ex_in_use); + +#ifdef XT_TRACK_RETURNED_ROWS + ha_start_scan(pb_open_tab, active_index); +#endif + pb_ind_row_count = 0; + + ind = (XTIndexPtr) pb_share->sh_dic_keys[active_index]; + + xt_idx_prep_key(ind, &search_key, XT_SEARCH_AFTER_LAST_FLAG, NULL, 0); + if (!xt_idx_search_prev(pb_open_tab, ind, &search_key)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + else + err = xt_index_prev_read(pb_open_tab, ind, pb_key_read, NULL, buf); + + pb_ind_row_count++; +#ifdef XT_TRACK_RETURNED_ROWS + if (!err) + ha_return_row(pb_open_tab, active_index); +#endif + if (err) + table->status = STATUS_NOT_FOUND; + else { + pb_open_tab->ot_thread->st_statistics.st_row_select++; + table->status = 0; + } + XT_RETURN(err); +} + +/* + * ----------------------------------------------------------------------- + * RAMDOM/SEQUENTIAL READ METHODS + */ + +/* + * rnd_init() is called when the system wants the storage engine to do a table + * scan. + * See the example in the introduction at the top of this file to see when + * rnd_init() is called. + * + * Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc, + * and sql_update.cc. + */ +int ha_pbxt::rnd_init(bool scan) +{ + int err = 0; + + XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::rnd_init %s\n", pb_share->sh_table_path->ps_path); + XT_DISABLED_TRACE(("seq scan tx=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id)); + + /* The number of columns required: */ + if (pb_open_tab->ot_is_modify) + pb_open_tab->ot_cols_req = table->read_set->n_bits; + else { + pb_open_tab->ot_cols_req = ha_get_max_bit(table->read_set); + + /* + * in case of queries like SELECT COUNT(*) FROM t + * table->read_set is empty. Otoh, ot_cols_req == 0 can be treated + * as "all columns" by some internal code (see e.g. myxt_load_row), + * which makes such queries very ineffective for the records with + * extended part. Setting column count to 1 makes sure that the + * extended part will not be acessed in most cases. + */ + + if (pb_open_tab->ot_cols_req == 0) + pb_open_tab->ot_cols_req = 1; + } + + ASSERT_NS(pb_ex_in_use); + if (scan) { + if (!xt_tab_seq_init(pb_open_tab)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + } + else + xt_tab_seq_reset(pb_open_tab); + + xt_xlog_check_long_writer(pb_open_tab->ot_thread); + + return err; +} + +int ha_pbxt::rnd_end() +{ + XT_TRACE_CALL(); + + /* + * make permanent the lock for the last scanned row + */ + XTThreadPtr thread = pb_open_tab->ot_thread; + if (pb_open_tab) + pb_open_tab->ot_table->tab_locks.xt_make_lock_permanent(pb_open_tab, &thread->st_lock_list); + + xt_xlog_check_long_writer(thread); + + xt_tab_seq_exit(pb_open_tab); + XT_RETURN(0); +} + +/* + * This is called for each row of the table scan. When you run out of records + * you should return HA_ERR_END_OF_FILE. Fill buff up with the row information. + * The Field structure for the table is the key to getting data into buf + * in a manner that will allow the server to understand it. + * + * Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc, + * and sql_update.cc. + */ +int ha_pbxt::rnd_next(byte *buf) +{ + int err = 0; + xtBool eof; + + XT_TRACE_CALL(); + ASSERT_NS(pb_ex_in_use); + //statistic_increment(ha_read_rnd_next_count, &LOCK_status); + xt_xlog_check_long_writer(pb_open_tab->ot_thread); + + if (!xt_tab_seq_next(pb_open_tab, (xtWord1 *) buf, &eof)) + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + else if (eof) + err = HA_ERR_END_OF_FILE; + + if (err) + table->status = STATUS_NOT_FOUND; + else { + pb_open_tab->ot_thread->st_statistics.st_row_select++; + table->status = 0; + } + XT_RETURN(err); +} + +/* + * position() is called after each call to rnd_next() if the data needs + * to be ordered. You can do something like the following to store + * the position: + * ha_store_ptr(ref, ref_length, current_position); + * + * The server uses ref to store data. ref_length in the above case is + * the size needed to store current_position. ref is just a byte array + * that the server will maintain. If you are using offsets to mark rows, then + * current_position should be the offset. If it is a primary key like in + * BDB, then it needs to be a primary key. + * + * Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc. + */ +void ha_pbxt::position(const byte *record __attribute__((unused))) +{ + XT_TRACE_CALL(); + ASSERT_NS(pb_ex_in_use); + /* + * I changed this from using little endian to big endian. + * + * The reason is because sometime the pointer are sorted. + * When they are are sorted a binary compare is used. + * A binary compare sorts big endian values correctly! + * + * Take the followin example: + * + * create table t1 (a int, b text); + * insert into t1 values (1, 'aa'), (1, 'bb'), (1, 'cc'); + * select group_concat(b) from t1 group by a; + * + * With little endian pointers the result is: + * aa,bb,cc + * + * With big-endian pointer the result is: + * aa,cc,bb + * + */ + (void) ASSERT_NS(XT_RECORD_OFFS_SIZE == 4); + mi_int4store((xtWord1 *) ref, pb_open_tab->ot_curr_rec_id); + XT_RETURN_VOID; +} + +/* + * Given the #ROWID retrieve the record. + * + * Called from filesort.cc records.cc sql_insert.cc sql_select.cc sql_update.cc. + */ +int ha_pbxt::rnd_pos(byte * buf, byte *pos) +{ + int err = 0; + + XT_TRACE_CALL(); + ASSERT_NS(pb_ex_in_use); + //statistic_increment(ha_read_rnd_count, &LOCK_status); + XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::rnd_pos %s\n", pb_share->sh_table_path->ps_path); + + pb_open_tab->ot_curr_rec_id = mi_uint4korr((xtWord1 *) pos); + switch (xt_tab_dirty_read_record(pb_open_tab, (xtWord1 *) buf)) { + case FALSE: + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + break; + default: + break; + } + + if (err) + table->status = STATUS_NOT_FOUND; + else { + pb_open_tab->ot_thread->st_statistics.st_row_select++; + table->status = 0; + } + XT_RETURN(err); +} + +/* + * ----------------------------------------------------------------------- + * INFO METHODS + */ + +/* + ::info() is used to return information to the optimizer. + Currently this table handler doesn't implement most of the fields + really needed. SHOW also makes use of this data + Another note, you will probably want to have the following in your + code: + if (records < 2) + records = 2; + The reason is that the server will optimize for cases of only a single + record. If in a table scan you don't know the number of records + it will probably be better to set records to two so you can return + as many records as you need. + Along with records a few more variables you may wish to set are: + records + deleted + data_file_length + index_file_length + delete_length + check_time + Take a look at the public variables in handler.h for more information. + + Called in: + filesort.cc + ha_heap.cc + item_sum.cc + opt_sum.cc + sql_delete.cc + sql_delete.cc + sql_derived.cc + sql_select.cc + sql_select.cc + sql_select.cc + sql_select.cc + sql_select.cc + sql_show.cc + sql_show.cc + sql_show.cc + sql_show.cc + sql_table.cc + sql_union.cc + sql_update.cc + +*/ +#if MYSQL_VERSION_ID < 50114 +void ha_pbxt::info(uint flag) +#else +int ha_pbxt::info(uint flag) +#endif +{ + XTOpenTablePtr ot; + int in_use; + + XT_TRACE_CALL(); + + if (!(in_use = pb_ex_in_use)) { + pb_ex_in_use = 1; + if (pb_share && pb_share->sh_table_lock) { + /* If some thread has an exclusive lock, then + * we wait for the lock to be removed: + */ +#if MYSQL_VERSION_ID < 50114 + ha_wait_for_shared_use(this, pb_share); + pb_ex_in_use = 1; +#else + if (!ha_wait_for_shared_use(this, pb_share)) + return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); +#endif + } + } + + if ((ot = pb_open_tab)) { + if (flag & HA_STATUS_VARIABLE) { + stats.deleted = ot->ot_table->tab_row_fnum; + stats.records = (ha_rows) (ot->ot_table->tab_row_eof_id - 1 - stats.deleted); + stats.data_file_length = ot->ot_table->tab_rec_eof_id; + stats.index_file_length = xt_ind_node_to_offset(ot->ot_table, ot->ot_table->tab_ind_eof); + stats.delete_length = ot->ot_table->tab_rec_fnum * ot->ot_rec_size; + //check_time = info.check_time; + stats.mean_rec_length = ot->ot_rec_size; + } + + if (flag & HA_STATUS_CONST) { + ha_rows rec_per_key; + XTIndexPtr ind; + TABLE_SHARE *share= TS(table); + + stats.max_data_file_length = 0x00FFFFFF; + stats.max_index_file_length = 0x00FFFFFF; + //stats.create_time = info.create_time; + ref_length = XT_RECORD_OFFS_SIZE; + //share->db_options_in_use = info.options; + stats.block_size = XT_INDEX_PAGE_SIZE; + + if (share->tmp_table == NO_TMP_TABLE) +#if MYSQL_VERSION_ID > 60005 +#define WHICH_MUTEX LOCK_ha_data +#else +#define WHICH_MUTEX mutex +#endif + +#ifdef SAFE_MUTEX + +#if MYSQL_VERSION_ID < 60000 +#if MYSQL_VERSION_ID < 50123 + safe_mutex_lock(&share->mutex,__FILE__,__LINE__); +#else + safe_mutex_lock(&share->mutex,0,__FILE__,__LINE__); +#endif +#else +#if MYSQL_VERSION_ID < 60004 + safe_mutex_lock(&share->mutex,__FILE__,__LINE__); +#else + safe_mutex_lock(&share->WHICH_MUTEX,0,__FILE__,__LINE__); +#endif +#endif + +#else // SAFE_MUTEX + +#ifdef MY_PTHREAD_FASTMUTEX + my_pthread_fastmutex_lock(&share->WHICH_MUTEX); +#else + pthread_mutex_lock(&share->WHICH_MUTEX); +#endif + +#endif // SAFE_MUTEX + share->keys_in_use.set_prefix(share->keys); + //share->keys_in_use.intersect_extended(info.key_map); + share->keys_for_keyread.intersect(share->keys_in_use); + //share->db_record_offset = info.record_offset; + for (u_int i = 0; i < share->keys; i++) { + ind = pb_share->sh_dic_keys[i]; + + rec_per_key = 0; + if (ind->mi_seg_count == 1 && (ind->mi_flags & HA_NOSAME)) + rec_per_key = 1; + else { + + } + for (u_int j = 0; j < table->key_info[i].key_parts; j++) + table->key_info[i].rec_per_key[j] = (ulong) rec_per_key; + } + if (share->tmp_table == NO_TMP_TABLE) +#ifdef SAFE_MUTEX + safe_mutex_unlock(&share->WHICH_MUTEX,__FILE__,__LINE__); +#else +#ifdef MY_PTHREAD_FASTMUTEX + pthread_mutex_unlock(&share->WHICH_MUTEX.mutex); +#else + pthread_mutex_unlock(&share->WHICH_MUTEX); +#endif +#endif + /* + Set data_file_name and index_file_name to point at the symlink value + if table is symlinked (Ie; Real name is not same as generated name) + */ + /* + data_file_name = index_file_name = 0; + fn_format(name_buff, file->filename, "", MI_NAME_DEXT, 2); + if (strcmp(name_buff, info.data_file_name)) + data_file_name = info.data_file_name; + strmov(fn_ext(name_buff), MI_NAME_IEXT); + if (strcmp(name_buff, info.index_file_name)) + index_file_name = info.index_file_name; + */ + } + + if (flag & HA_STATUS_ERRKEY) + errkey = ot->ot_err_index_no; + + /* {PRE-INC} + * We assume they want the next value to be returned! + * + * At least, this is what works for the following code: + * + * create table t1 (a int auto_increment primary key) + * auto_increment=100 + * engine=pbxt + * partition by list (a) + * (partition p0 values in (1, 98,99, 100, 101)); + * create index inx on t1 (a); + * insert into t1 values (null); + * select * from t1; + */ + if (flag & HA_STATUS_AUTO) + stats.auto_increment_value = (ulonglong) ot->ot_table->tab_auto_inc+1; + } + else + errkey = (uint) -1; + + if (!in_use) { + pb_ex_in_use = 0; + if (pb_share) { + /* Someone may be waiting for me to complete: */ + if (pb_share->sh_table_lock) + xt_broadcast_cond_ns((xt_cond_type *) pb_share->sh_ex_cond); + } + } +#if MYSQL_VERSION_ID < 50114 + XT_RETURN_VOID; +#else + XT_RETURN(0); +#endif +} + +/* + * extra() is called whenever the server wishes to send a hint to + * the storage engine. The myisam engine implements the most hints. + * ha_innodb.cc has the most exhaustive list of these hints. + */ +int ha_pbxt::extra(enum ha_extra_function operation) +{ + int err = 0; + + XT_PRINT2(xt_get_self(), "ha_pbxt::extra %s operation=%d\n", pb_share->sh_table_path->ps_path, operation); + + switch (operation) { + case HA_EXTRA_RESET_STATE: + pb_key_read = FALSE; + pb_ignore_dup_key = 0; + /* As far as I can tell, this function is called for + * every table at the end of a statement. + * + * So, during a LOCK TABLES ... UNLOCK TABLES, I use + * this to find the end of a statement. + * start_stmt() indicates the start of a statement, + * and is also called once for each table in the + * statement. + * + * So the statement boundary is indicated by + * self->st_stat_count == 0 + * + * GOTCHA: I cannot end the transaction here! + * I must end it in start_stmt(). + * The reason is because there are situations + * where this would end a transaction that + * was begin by external_lock(). + * + * An example of this is when a function + * is called when doing CREATE TABLE SELECT. + */ + if (pb_in_stat) { + /* NOTE: pb_in_stat is just used to avoid getting + * self, if it is not necessary!! + */ + XTThreadPtr self; + + pb_in_stat = FALSE; + + if (!(self = ha_set_current_thread(pb_mysql_thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + if (self->st_stat_count > 0) { + self->st_stat_count--; + if (self->st_stat_count == 0) + self->st_stat_ended = TRUE; + } + + /* This is the end of a statement, I can turn any locks into perminant locks now: */ + if (pb_open_tab) + pb_open_tab->ot_table->tab_locks.xt_make_lock_permanent(pb_open_tab, &self->st_lock_list); + } + break; + case HA_EXTRA_KEYREAD: + /* This means we so not need to read the entire record. */ + pb_key_read = TRUE; + break; + case HA_EXTRA_NO_KEYREAD: + pb_key_read = FALSE; + break; + case HA_EXTRA_IGNORE_DUP_KEY: + /* NOTE!!! Calls to extra(HA_EXTRA_IGNORE_DUP_KEY) can be nested! + * In fact, the calls are from different threads, so + * strictly speaking I should protect this variable!! + * Here is the sequence that produces the duplicate call: + * + * drop table if exists t1; + * CREATE TABLE t1 (x int not null, y int, primary key (x)) engine=pbxt; + * insert into t1 values (1, 3), (4, 1); + * replace DELAYED into t1 (x, y) VALUES (4, 2); + * select * from t1 order by x; + * + */ + pb_ignore_dup_key++; + break; + case HA_EXTRA_NO_IGNORE_DUP_KEY: + pb_ignore_dup_key--; + break; + case HA_EXTRA_KEYREAD_PRESERVE_FIELDS: + /* MySQL needs all fields */ + pb_key_read = FALSE; + break; + default: + break; + } + + return err; +} + + +/* + * Deprecated and likely to be removed in the future. Storage engines normally + * just make a call like: + * ha_pbxt::extra(HA_EXTRA_RESET); + * to handle it. + */ +int ha_pbxt::reset(void) +{ + XT_TRACE_CALL(); + extra(HA_EXTRA_RESET_STATE); + XT_RETURN(0); +} + +void ha_pbxt::unlock_row() +{ + XT_TRACE_CALL(); + if (pb_open_tab) + pb_open_tab->ot_table->tab_locks.xt_remove_temp_lock(pb_open_tab, FALSE); +} + +/* + * Used to delete all rows in a table. Both for cases of truncate and + * for cases where the optimizer realizes that all rows will be + * removed as a result of a SQL statement. + * + * Called from item_sum.cc by Item_func_group_concat::clear(), + * Item_sum_count_distinct::clear(), and Item_func_group_concat::clear(). + * Called from sql_delete.cc by mysql_delete(). + * Called from sql_select.cc by JOIN::reinit(). + * Called from sql_union.cc by st_select_lex_unit::exec(). + */ +int ha_pbxt::delete_all_rows() +{ + THD *thd = current_thd; + int err = 0; + XTThreadPtr self; + XTDDTable *tab_def = NULL; + char path[PATH_MAX]; + + XT_TRACE_CALL(); + + if (thd_sql_command(thd) != SQLCOM_TRUNCATE) { + /* Just like InnoDB we only handle TRUNCATE TABLE + * by recreating the table. + * DELETE FROM t must be handled by deleting + * each row because it may be part of a transaction, + * and there may be foreign key actions. + */ + XT_RETURN (my_errno = HA_ERR_WRONG_COMMAND); + } + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + try_(a) { + XTDictionaryRec dic; + + memset(&dic, 0, sizeof(dic)); + + dic = pb_share->sh_table->tab_dic; + xt_strcpy(PATH_MAX, path, pb_share->sh_table->tab_name->ps_path); + + if ((tab_def = dic.dic_table)) + tab_def->reference(); + + if (!(thd_test_options(thd,OPTION_NO_FOREIGN_KEY_CHECKS))) + tab_def->deleteAllRows(self); + + /* We should have a table lock! */ + //ASSERT(pb_lock_table); + if (!pb_table_locked) { + ha_aquire_exclusive_use(self, pb_share, this); + pushr_(ha_release_exclusive_use, pb_share); + } + ha_close_open_tables(self, pb_share, NULL); + + /* This is required in the case of delete_all_rows, because we must + * ensure that the handlers no longer reference the old + * table, so that it will not be used again. The table + * must be re-openned, because the ID has changed! + * + * 0.9.86+ Must check if this is still necessary. + * + * the ha_close_share(self, pb_share) call was moved from above + * (before tab_def = dic.dic_table), because of a crash. + * Test case: + * + * set storage_engine = pbxt; + * create table t1 (s1 int primary key); + * insert into t1 values (1); + * create table t2 (s1 int, foreign key (s1) references t1 (s1)); + * insert into t2 values (1); + * truncate table t1; -- this should fail because of FK constraint + * alter table t1 engine = myisam; -- this caused crash + * + */ + ha_close_share(self, pb_share); + + xt_create_table(self, (XTPathStrPtr) path, &dic); + if (!pb_table_locked) + freer_(); // ha_release_exclusive_use(pb_share) + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + cont_(a); + + if (tab_def) + tab_def->release(self); + + XT_RETURN(err); +} + +/* + * TODO: Implement! + * Assuming a key (a,b,c) + * + * rec_per_key[0] = SELECT COUNT(*)/COUNT(DISTINCT a) FROM t; + * rec_per_key[1] = SELECT COUNT(*)/COUNT(DISTINCT a,b) FROM t; + * rec_per_key[2] = SELECT COUNT(*)/COUNT(DISTINCT a,b,c) FROM t; + * + * After this is implemented, the selectivity can serve as + * a quick estimate of records_in_range(). + * + * After you have done this, you need to redo the index_merge* + * tests. Restore the standard result to check if we + * now agree with the MyISAM strategy. + * + */ +int ha_pbxt::analyze(THD *thd __attribute__((unused)), HA_CHECK_OPT *check_opt __attribute__((unused))) +{ + int err = 0; + XTDatabaseHPtr db; + xtXactID my_xn_id; + xtXactID clean_xn_id = 0; + uint cnt = 10; + + XT_TRACE_CALL(); + + if (!pb_open_tab) { + if ((err = reopen())) + XT_RETURN(err); + } + + /* Wait until the sweeper is no longer busy! + * If you want an accurate count(*) value, then call + * ANALYZE TABLE first. This function waits until the + * sweeper has completed. + */ + db = pb_open_tab->ot_table->tab_db; + + /* + * Wait until everything is cleaned up before this transaction. + * But this will only work if the we quit out transaction! + * + * GOTCHA: When a PBXT table is partitioned, then analyze() is + * called for each component. The first calls xt_xn_commit(). + * All following calls have no transaction!: + * + * CREATE TABLE t1 (a int) + * PARTITION BY LIST (a) + * (PARTITION x1 VALUES IN (10), PARTITION x2 VALUES IN (20)); + * + * analyze table t1; + * + */ + if (pb_open_tab->ot_thread && pb_open_tab->ot_thread->st_xact_data) { + my_xn_id = pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id; + XT_PRINT0(xt_get_self(), "xt_xn_commit\n"); + xt_xn_commit(pb_open_tab->ot_thread); + } + else + my_xn_id = db->db_xn_to_clean_id; + + while ((!db->db_sw_idle || xt_xn_is_before(db->db_xn_to_clean_id, my_xn_id)) && !thd_killed(thd)) { + xt_busy_wait(); + + /* + * It is possible that the sweeper gets stuck because + * it has no dictionary information! + * As in the example below. + * + * create table t4 ( + * pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' + * ) engine=pbxt; + * + * insert into t4 (a1, a2, b, c, d, dummy) select * from t1; + * + * create index idx12672_0 on t4 (a1); + * create index idx12672_1 on t4 (a1,a2,b,c); + * create index idx12672_2 on t4 (a1,a2,b); + * analyze table t1; + */ + if (db->db_sw_idle) { + /* This will make sure we don't wait forever: */ + if (clean_xn_id != db->db_xn_to_clean_id) { + clean_xn_id = db->db_xn_to_clean_id; + cnt = 10; + } + else { + cnt--; + if (!cnt) + break; + } + xt_wakeup_sweeper(db); + } + } + + XT_RETURN(err); +} + +int ha_pbxt::repair(THD *thd __attribute__((unused)), HA_CHECK_OPT *check_opt __attribute__((unused))) +{ + return(HA_ADMIN_TRY_ALTER); +} + +/* + * This is mapped to "ALTER TABLE tablename TYPE=PBXT", which rebuilds + * the table in MySQL. + */ +int ha_pbxt::optimize(THD *thd __attribute__((unused)), HA_CHECK_OPT *check_opt __attribute__((unused))) +{ + return(HA_ADMIN_TRY_ALTER); +} + +#ifdef DEBUG +extern int pbxt_mysql_trace_on; +#endif + +int ha_pbxt::check(THD* thd, HA_CHECK_OPT* check_opt __attribute__((unused))) +{ + int err = 0; + XTThreadPtr self; + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + if (self->st_lock_count) + ASSERT(self->st_xact_data); + + if (!pb_table_locked) { + ha_aquire_exclusive_use(self, pb_share, this); + pushr_(ha_release_exclusive_use, pb_share); + } + +#ifdef CHECK_TABLE_LOADS + xt_tab_load_table(self, pb_open_tab); +#endif + xt_check_table(self, pb_open_tab); + + if (!pb_table_locked) + freer_(); // ha_release_exclusive_use(pb_share) + + //pbxt_mysql_trace_on = TRUE; + return 0; +} + +/* + * This function is called: + * For each table in LOCK TABLES, + * OR + * For each table in a statement. + * + * It is called with F_UNLCK: + * in UNLOCK TABLES + * OR + * at the end of a statement. + * + */ +xtPublic int ha_pbxt::external_lock(THD *thd, int lock_type) +{ + int err = 0; + XTThreadPtr self; + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + /* F_UNLCK is set when this function is called at end + * of statement or UNLOCK TABLES + */ + if (lock_type == F_UNLCK) { + /* This is not TRUE if external_lock() FAILED! + * Can we rely on external_unlock being called when + * external_lock() fails? Currently yes, but it does + * not make sense! + ASSERT_NS(pb_ex_in_use); + */ + + XT_PRINT1(self, "ha_pbxt::EXTERNAL_LOCK %s lock_type=UNLOCK\n", pb_share->sh_table_path->ps_path); + + /* Make any temporary locks on this table permanent. + * + * This is required here because of the following example: + * create table t1 (a int NOT NULL, b int, primary key (a)); + * create table t2 (a int NOT NULL, b int, primary key (a)); + * insert into t1 values (0, 10),(1, 11),(2, 12); + * insert into t2 values (1, 21),(2, 22),(3, 23); + * update t1 set b= (select b from t2 where t1.a = t2.a); + * update t1 set b= (select b from t2 where t1.a = t2.a); + * select * from t1; + * drop table t1, t2; + * + */ + + /* GOTCHA! It's weird, but, if this function returns an error + * on lock, then UNLOCK is called?! + * This should not be done, because if lock fails, it should be + * assumed that no UNLOCK is required. + * Basically, I have to assume that some code will presume this, + * although the function lock_external() calls unlock, even + * when lock fails. + * The result is, that my lock count can go wrong. So I could + * change the lock method, and increment the lock count, even + * if it fails. However, the consequences are more serious, + * if some code decides not to call UNLOCK after lock fails. + * The result is that I would have a permanent too high lock, + * count and nothing will work. + * So instead, I handle the fact that I might too many unlocks + * here. + */ + if (self->st_lock_count > 0) + self->st_lock_count--; + if (!self->st_lock_count) { + /* This section handles "auto-commit"... */ + +#ifdef XT_IMPLEMENT_NO_ACTION + /* {NO-ACTION-BUG} + * This is required here because it marks the end of a statement. + * If we are in a non-auto-commit mode, then we cannot + * wait for st_is_update to be set by the begining of a new transaction. + */ + if (self->st_restrict_list.bl_count) { + if (!xt_tab_restrict_rows(&self->st_restrict_list, self)) + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } +#endif + + if (self->st_xact_data) { + if (self->st_auto_commit) { + /* + * Normally I could assume that if the transaction + * has not been aborted by now, then it should be committed. + * + * Unfortunately, this is not the case! + * + * create table t1 (id int primary key) engine = pbxt; + * create table t2 (id int) engine = pbxt; + * + * insert into t1 values ( 1 ) ; + * insert into t1 values ( 2 ) ; + * insert into t2 values ( 1 ) ; + * insert into t2 values ( 2 ) ; + * + * --This statement is returns an error calls ha_autocommit_or_rollback(): + * update t1 set t1.id=1 where t1.id=2; + * + * --This statement is returns no error and calls ha_autocommit_or_rollback(): + * update t1,t2 set t1.id=3, t2.id=3 where t1.id=2 and t2.id = t1.id; + * + * --But this statement returns an error and does not call ha_autocommit_or_rollback(): + * update t1,t2 set t1.id=1, t2.id=1 where t1.id=3 and t2.id = t1.id; + * + * The result is, I cannot rely on ha_autocommit_or_rollback() being called :( + * So I have to abort myself here... + */ + if (pb_open_tab) + pb_open_tab->ot_table->tab_locks.xt_make_lock_permanent(pb_open_tab, &self->st_lock_list); + + if (self->st_abort_trans) { + XT_PRINT0(self, "xt_xn_rollback in unlock\n"); + if (!xt_xn_rollback(self)) + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + else { + XT_PRINT0(self, "xt_xn_commit in unlock\n"); + if (!xt_xn_commit(self)) + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + } + } + + /* If the previous statement was "for update", then set the visibilty + * so that non- for update SELECTs will see what the for update select + * (or update statement) just saw. + */ + if (pb_open_tab) { + if (pb_open_tab->ot_for_update) + self->st_visible_time = self->st_database->db_xn_end_time; + + if (pb_share->sh_recalc_selectivity) { + if ((pb_share->sh_table->tab_row_eof_id - 1 - pb_share->sh_table->tab_row_fnum) >= 200) { + /* [**] */ + pb_share->sh_recalc_selectivity = FALSE; + xt_ind_set_index_selectivity(self, pb_open_tab); + pb_share->sh_recalc_selectivity = (pb_share->sh_table->tab_row_eof_id - 1 - pb_share->sh_table->tab_row_fnum) < 150; + } + } + } + + if (self->st_stat_modify) + self->st_statistics.st_stat_write++; + else + self->st_statistics.st_stat_read++; + self->st_stat_modify = FALSE; + } + + if (pb_table_locked) { + pb_table_locked--; + if (!pb_table_locked) + ha_release_exclusive_use(self, pb_share); + } + + /* No longer in use: */ + pb_ex_in_use = 0; + /* Someone may be waiting for me to complete: */ + if (pb_share->sh_table_lock) + xt_broadcast_cond_ns((xt_cond_type *) pb_share->sh_ex_cond); + } + else { + XT_PRINT2(self, "ha_pbxt::EXTERNAL_LOCK %s lock_type=%d\n", pb_share->sh_table_path->ps_path, lock_type); + + if (pb_lock_table) { + + pb_ex_in_use = 1; + try_(a) { + if (!pb_table_locked) + ha_aquire_exclusive_use(self, pb_share, this); + pb_table_locked++; + + ha_close_open_tables(self, pb_share, this); + + if (!pb_share->sh_table) { + xt_ha_open_database_of_table(self, pb_share->sh_table_path); + + ha_open_share(self, pb_share, NULL); + } + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + pb_ex_in_use = 0; + goto complete; + } + cont_(a); + } + else { + pb_ex_in_use = 1; + if (pb_share->sh_table_lock && !pb_table_locked) { + /* If some thread has an exclusive lock, then + * we wait for the lock to be removed: + */ + if (!ha_wait_for_shared_use(this, pb_share)) { + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + goto complete; + } + } + + if (!pb_open_tab) { + if ((err = reopen())) { + pb_ex_in_use = 0; + goto complete; + } + } + + /* Set the current thread for this open table: */ + pb_open_tab->ot_thread = self; + + /* If this is a set, then it is in UPDATE/DELETE TABLE ... + * or SELECT ... FOR UPDATE + */ + pb_open_tab->ot_is_modify = FALSE; + if ((pb_open_tab->ot_for_update = (lock_type == F_WRLCK))) { + switch ((int) thd_sql_command(thd)) { + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: + case SQLCOM_REPLACE: + case SQLCOM_REPLACE_SELECT: + case SQLCOM_INSERT: + case SQLCOM_INSERT_SELECT: + pb_open_tab->ot_is_modify = TRUE; + self->st_stat_modify = TRUE; + break; + case SQLCOM_CREATE_TABLE: + case SQLCOM_CREATE_INDEX: + case SQLCOM_ALTER_TABLE: + case SQLCOM_TRUNCATE: + case SQLCOM_DROP_TABLE: + case SQLCOM_DROP_INDEX: + case SQLCOM_LOAD: + case SQLCOM_REPAIR: + case SQLCOM_OPTIMIZE: + self->st_stat_modify = TRUE; + break; + } + } + + if (pb_open_tab->ot_is_modify && pb_open_tab->ot_table->tab_dic.dic_disable_index) { + xt_tab_set_index_error(pb_open_tab->ot_table); + err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key); + goto complete; + } + } + + /* Record the associated MySQL thread: */ + pb_mysql_thd = thd; + + if (self->st_database != pb_share->sh_table->tab_db) { + try_(b) { + /* PBXT does not permit multiple databases us one statement, + * or in a single transaction! + * + * Example query: + * + * update mysqltest_1.t1, mysqltest_2.t2 set a=10,d=10; + */ + if (self->st_lock_count > 0) + xt_throw_xterr(XT_CONTEXT, XT_ERR_MULTIPLE_DATABASES); + + xt_ha_open_database_of_table(self, pb_share->sh_table_path); + } + catch_(b) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + pb_ex_in_use = 0; + goto complete; + } + cont_(b); + } + + /* See (***) */ + self->st_is_update = FALSE; + + /* Auto begin a transaction (if one is not already running): */ + if (!self->st_xact_data) { + /* Transaction mode numbers must be identical! */ + (void) ASSERT_NS(ISO_READ_UNCOMMITTED == XT_XACT_UNCOMMITTED_READ); + (void) ASSERT_NS(ISO_SERIALIZABLE == XT_XACT_SERIALIZABLE); + + self->st_xact_mode = thd_tx_isolation(thd) <= ISO_READ_COMMITTED ? XT_XACT_COMMITTED_READ : XT_XACT_REPEATABLE_READ; + self->st_ignore_fkeys = (thd_test_options(thd,OPTION_NO_FOREIGN_KEY_CHECKS)) != 0; + self->st_auto_commit = (thd_test_options(thd, (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) == 0; + self->st_table_trans = thd_sql_command(thd) == SQLCOM_LOCK_TABLES; + self->st_abort_trans = FALSE; + self->st_stat_ended = FALSE; + self->st_stat_trans = FALSE; + XT_PRINT0(self, "xt_xn_begin\n"); + if (!xt_xn_begin(self)) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + pb_ex_in_use = 0; + goto complete; + } + + /* + * (**) GOTCHA: trans_register_ha() is not mentioned in the documentation. + * It must be called to inform MySQL that we have a transaction (see start_stmt). + * + * Here are some tests that confirm whether things are done correctly: + * + * drop table if exists t1, t2; + * create table t1 (c1 int); + * insert t1 values (1); + * select * from t1; + * rename table t1 to t2; + * + * rename will generate an error if MySQL thinks a transaction is + * still running. + * + * create table t1 (a text character set utf8, b text character set latin1); + * insert t1 values (0x4F736E616272C3BC636B, 0x4BF66C6E); + * select * from t1; + * --exec $MYSQL_DUMP --tab=$MYSQLTEST_VARDIR/tmp/ test + * --exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/t1.sql + * --exec $MYSQL_IMPORT test $MYSQLTEST_VARDIR/tmp/t1.txt + * select * from t1; + * + * This test forces a begin transaction in start_stmt() + * + * drop tables if exists t1; + * create table t1 (c1 int); + * lock tables t1 write; + * insert t1 values (1); + * insert t1 values (2); + * unlock tables; + * + * The second select will return an empty result of the + * MySQL is not informed that a transaction is running (auto-commit + * in external_lock comes too late)! + * + */ + if (!self->st_auto_commit) { + trans_register_ha(thd, TRUE, pbxt_hton); + XT_PRINT0(self, "ha_pbxt::external_lock trans_register_ha all=TRUE\n"); + } + } + + if (lock_type == F_WRLCK || self->st_xact_mode < XT_XACT_REPEATABLE_READ) + self->st_visible_time = self->st_database->db_xn_end_time; + +#ifdef TRACE_STATEMENTS + if (self->st_lock_count == 0) + STAT_TRACE(self, *thd_query(thd)); +#endif + self->st_lock_count++; + } + + complete: + return err; +} + +/* + * This function is called for each table in a statement + * after LOCK TABLES has been used. + * + * Currently I only use this function to set the + * current thread of the table handle. + * + * GOTCHA: The prototype of start_stmt() has changed + * from version 4.1 to 5.1! + */ +int ha_pbxt::start_stmt(THD *thd, thr_lock_type lock_type) +{ + int err = 0; + XTThreadPtr self; + + ASSERT_NS(pb_ex_in_use); + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + XT_PRINT2(self, "ha_pbxt::start_stmt %s lock_type=%d\n", pb_share->sh_table_path->ps_path, (int) lock_type); + + if (!pb_open_tab) { + if ((err = reopen())) + goto complete; + } + + ASSERT_NS(pb_open_tab->ot_thread == self); + ASSERT_NS(thd == pb_mysql_thd); + ASSERT_NS(self->st_database == pb_open_tab->ot_table->tab_db); + + if (self->st_stat_ended) { + self->st_stat_ended = FALSE; + self->st_stat_trans = FALSE; + +#ifdef XT_IMPLEMENT_NO_ACTION + if (self->st_restrict_list.bl_count) { + if (!xt_tab_restrict_rows(&self->st_restrict_list, self)) { + err = xt_ha_pbxt_thread_error_for_mysql(pb_mysql_thd, self, pb_ignore_dup_key); + } + } +#endif + + /* This section handles "auto-commit"... */ + if (self->st_xact_data && self->st_auto_commit && self->st_table_trans) { + if (self->st_abort_trans) { + XT_PRINT0(self, "xt_xn_rollback\n"); + if (!xt_xn_rollback(self)) + err = xt_ha_pbxt_thread_error_for_mysql(pb_mysql_thd, self, pb_ignore_dup_key); + } + else { + XT_PRINT0(self, "xt_xn_commit\n"); + if (!xt_xn_commit(self)) + err = xt_ha_pbxt_thread_error_for_mysql(pb_mysql_thd, self, pb_ignore_dup_key); + } + } + + if (self->st_stat_modify) + self->st_statistics.st_stat_write++; + else + self->st_statistics.st_stat_read++; + self->st_stat_modify = FALSE; + + /* If the previous statement was "for update", then set the visibilty + * so that non- for update SELECTs will see what the for update select + * (or update statement) just saw. + */ + if (pb_open_tab->ot_for_update) + self->st_visible_time = self->st_database->db_xn_end_time; + } + + pb_open_tab->ot_for_update = + (lock_type != TL_READ && + lock_type != TL_READ_WITH_SHARED_LOCKS && + lock_type != TL_READ_HIGH_PRIORITY && + lock_type != TL_READ_NO_INSERT); + pb_open_tab->ot_is_modify = FALSE; + if (pb_open_tab->ot_for_update) { + switch ((int) thd_sql_command(thd)) { + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: + case SQLCOM_REPLACE: + case SQLCOM_REPLACE_SELECT: + case SQLCOM_INSERT: + case SQLCOM_INSERT_SELECT: + pb_open_tab->ot_is_modify = TRUE; + self->st_stat_modify = TRUE; + break; + case SQLCOM_CREATE_TABLE: + case SQLCOM_CREATE_INDEX: + case SQLCOM_ALTER_TABLE: + case SQLCOM_TRUNCATE: + case SQLCOM_DROP_TABLE: + case SQLCOM_DROP_INDEX: + case SQLCOM_LOAD: + case SQLCOM_REPAIR: + case SQLCOM_OPTIMIZE: + self->st_stat_modify = TRUE; + break; + } + } + + + /* (***) This is required at this level! + * No matter how often it is called, it is still the start of a + * statement. We need to make sure statements that are NOT mistaken + * for different type of statement. + * + * Here is an example: + * select * from t1 where data = getcount("bar") + * + * If the procedure getcount() addresses another table. + * then open and close of the statements in getcount() + * are nested within an open close of the select t1 + * statement. + */ + self->st_is_update = FALSE; + + /* See comment (**) */ + if (!self->st_xact_data) { + self->st_xact_mode = thd_tx_isolation(thd) <= ISO_READ_COMMITTED ? XT_XACT_COMMITTED_READ : XT_XACT_REPEATABLE_READ; + self->st_ignore_fkeys = (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) != 0; + self->st_auto_commit = (thd_test_options(thd,(OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) == 0; + /* self->st_table_trans = not set here! */ + self->st_abort_trans = FALSE; + self->st_stat_ended = FALSE; + self->st_stat_trans = FALSE; + XT_PRINT0(self, "xt_xn_begin\n"); + if (!xt_xn_begin(self)) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + goto complete; + } + if (!self->st_auto_commit) { + trans_register_ha(thd, TRUE, pbxt_hton); + XT_PRINT0(self, "ha_pbxt::start_stmt trans_register_ha all=TRUE\n"); + } + } + + if (pb_open_tab->ot_for_update || self->st_xact_mode < XT_XACT_REPEATABLE_READ) + self->st_visible_time = self->st_database->db_xn_end_time; + + pb_in_stat = TRUE; + + self->st_stat_count++; + + complete: + return err; +} + +/* + * The idea with handler::store_lock() is the following: + * + * The statement decided which locks we should need for the table + * for updates/deletes/inserts we get WRITE locks, for SELECT... we get + * read locks. + * + * Before adding the lock into the table lock handler (see thr_lock.c) + * mysqld calls store lock with the requested locks. Store lock can now + * modify a write lock to a read lock (or some other lock), ignore the + * lock (if we don't want to use MySQL table locks at all) or add locks + * for many tables (like we do when we are using a MERGE handler). + * + * When releasing locks, store_lock() are also called. In this case one + * usually doesn't have to do anything. + * + * In some exceptional cases MySQL may send a request for a TL_IGNORE; + * This means that we are requesting the same lock as last time and this + * should also be ignored. (This may happen when someone does a flush + * table when we have opened a part of the tables, in which case mysqld + * closes and reopens the tables and tries to get the same locks at last + * time). In the future we will probably try to remove this. + * + * Called from lock.cc by get_lock_data(). + */ +THR_LOCK_DATA **ha_pbxt::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) +{ + if (lock_type != TL_IGNORE && pb_lock.type == TL_UNLOCK) { + /* Set to TRUE for operations that require a table lock: */ + switch (thd_sql_command(thd)) { + case SQLCOM_TRUNCATE: + /* GOTCHA: + * The problem is, if I do not do this, then + * TRUNCATE TABLE deadlocks with a normal update of the table! + * The reason is: + * + * external_lock() is called before MySQL actually locks the + * table. In external_lock(), the table is shared locked, + * by indicating that the handler is in use. + * + * Then later, in delete_all_rows(), a exclusive lock must be + * obtained. If an UPDATE or INSERT has also gained a shared + * lock in the meantime, then TRUNCATE TABLE hangs. + * + * By setting pb_lock_table we indicate that an exclusive lock + * should be gained in external_lock(). + * + * This is the locking behaviour: + * + * TRUNCATE TABLE: + * XT SHARE LOCK (mysql_lock_tables calls external_lock) + * MySQL WRITE LOCK (mysql_lock_tables) + * ... + * XT EXCLUSIVE LOCK (delete_all_rows) + * + * INSERT: + * XT SHARED LOCK (mysql_lock_tables calls external_lock) + * MySQL WRITE_ALLOW_WRITE LOCK (mysql_lock_tables) + * + * If the locking for INSERT is done in the ... phase + * above, then we have a deadlock because + * WRITE_ALLOW_WRITE conflicts with WRITE. + * + * Making TRUNCATE TABLE take a WRITE_ALLOW_WRITE LOCK, will + * not solve the problem because then 2 TRUNCATE TABLES + * can deadlock due to lock escalation. + * + * What may work is if MySQL were to lock BEFORE calling + * external_lock()! + * + * However, using this method, TRUNCATE TABLE does deadlock + * with other operations such as ALTER TABLE! + * + * This is handled with a lock timeout. Assuming + * TRUNCATE TABLE will be mixed with DML this is the + * best solution! + */ + pb_lock_table = TRUE; + break; + default: + pb_lock_table = FALSE; + break; + } + +#ifdef PBXT_HANDLER_TRACE + pb_lock.type = lock_type; +#endif + /* GOTCHA: Before it was OK to weaken the lock after just checking + * that !thd->in_lock_tables. However, when starting a procedure, MySQL + * simulates a LOCK TABLES statement. + * + * So we need to be more specific here, and check what the actual statement + * type. Before doing this I got a deadlock (undetected) on the following test. + * However, now we get a failed assertion in ha_rollback_trans(): + * TODO: Check this with InnoDB! + * + * DBUG_ASSERT(0); + * my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); + * + * drop table if exists t3; + * create table t3 (a smallint primary key) engine=pbxt; + * insert into t3 (a) values (40); + * insert into t3 (a) values (50); + * + * delimiter | + * + * drop function if exists t3_update| + * + * create function t3_update() returns int + * begin + * insert into t3 values (10); + * return 100; + * end| + * + * delimiter ; + * + * CONN 1: + * + * begin; + * update t3 set a = 5 where a = 50; + * + * CONN 2: + * + * begin; + * update t3 set a = 4 where a = 40; + * + * CONN 1: + * + * update t3 set a = 4 where a = 40; // Hangs waiting CONN 2. + * + * CONN 2: + * + * select t3_update(); // Hangs waiting for table lock. + * + */ + if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && lock_type <= TL_WRITE) && + !(thd_in_lock_tables(thd) && thd_sql_command(thd) == SQLCOM_LOCK_TABLES) && + !thd_tablespace_op(thd) && + thd_sql_command(thd) != SQLCOM_TRUNCATE && + thd_sql_command(thd) != SQLCOM_OPTIMIZE && + thd_sql_command(thd) != SQLCOM_CREATE_TABLE) { + lock_type = TL_WRITE_ALLOW_WRITE; + } + + /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ... + * MySQL would use the lock TL_READ_NO_INSERT on t2, and that + * would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts + * to t2. Convert the lock to a normal read lock to allow + * concurrent inserts to t2. + * + * (This one from InnoDB) + + * Stewart: removed SQLCOM_CALL, not sure of implications. + */ + if (lock_type == TL_READ_NO_INSERT && + (!thd_in_lock_tables(thd) +#ifndef DRIZZLED + || thd_sql_command(thd) == SQLCOM_CALL +#endif + )) + { + lock_type = TL_READ; + } + + XT_PRINT3(xt_get_self(), "ha_pbxt::store_lock %s %d->%d\n", pb_share->sh_table_path->ps_path, pb_lock.type, lock_type); + pb_lock.type = lock_type; + } +#ifdef PBXT_HANDLER_TRACE + else { + XT_PRINT3(xt_get_self(), "ha_pbxt::store_lock %s %d->%d (ignore/unlock)\n", pb_share->sh_table_path->ps_path, lock_type, lock_type); + } +#endif + *to++= &pb_lock; + return to; +} + +/* + * Used to delete a table. By the time delete_table() has been called all + * opened references to this table will have been closed (and your globally + * shared references released. The variable name will just be the name of + * the table. You will need to remove any files you have created at this point. + * + * Called from handler.cc by delete_table and ha_create_table(). Only used + * during create if the table_flag HA_DROP_BEFORE_CREATE was specified for + * the storage engine. +*/ +int ha_pbxt::delete_table(const char *table_path) +{ + THD *thd = current_thd; + int err = 0; + XTThreadPtr self; + XTSharePtr share; + + if (XTSystemTableShare::isSystemTable(table_path)) + return delete_system_table(table_path); + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + self->st_ignore_fkeys = (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) != 0; + + STAT_TRACE(self, *thd_query(thd)); + XT_PRINT1(self, "ha_pbxt::delete_table %s\n", table_path); + + try_(a) { + xt_ha_open_database_of_table(self, (XTPathStrPtr) table_path); + + ASSERT(xt_get_self() == self); + try_(b) { + /* NOTE: MySQL does not drop a table by first locking it! + * We also cannot use pb_share because the handler used + * to delete a table is not openned correctly. + */ + share = ha_get_share(self, table_path, false, NULL); + pushr_(ha_unget_share, share); + ha_aquire_exclusive_use(self, share, NULL); + pushr_(ha_release_exclusive_use, share); + ha_close_open_tables(self, share, NULL); + + xt_drop_table(self, (XTPathStrPtr) table_path); + + freer_(); // ha_release_exclusive_use(share) + freer_(); // ha_unget_share(share) + } + catch_(b) { + /* If the table does not exist, just log the error and continue... */ + if (self->t_exception.e_xt_err == XT_ERR_TABLE_NOT_FOUND) + xt_log_and_clear_exception(self); + else + throw_(); + } + cont_(b); + + /* + * If there are no more PBXT tables in the database, we + * "drop the database", which deletes all PBXT resources + * in the database. + */ + /* We now only drop the pbxt system data, + * when the PBXT database is dropped. + */ +#ifndef XT_USE_GLOBAL_DB + if (!xt_table_exists(self->st_database)) { + xt_ha_all_threads_close_database(self, self->st_database); + xt_drop_database(self, self->st_database); + xt_unuse_database(self, self); + xt_ha_close_global_database(self); + } +#endif + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + cont_(a); + + return err; +} + +int ha_pbxt::delete_system_table(const char *table_path) +{ + THD *thd = current_thd; + XTExceptionRec e; + int err = 0; + XTThreadPtr self; + + if (!(self = xt_ha_set_current_thread(thd, &e))) + return xt_ha_pbxt_to_mysql_error(e.e_xt_err); + + try_(a) { + xt_ha_open_database_of_table(self, (XTPathStrPtr) table_path); + + if (xt_table_exists(self->st_database)) + xt_throw_xterr(XT_CONTEXT, XT_ERR_PBXT_TABLE_EXISTS); + + XTSystemTableShare::setSystemTableDeleted(table_path); + + if (!XTSystemTableShare::doesSystemTableExist()) { + xt_ha_all_threads_close_database(self, self->st_database); + xt_drop_database(self, self->st_database); + xt_unuse_database(self, self); + xt_ha_close_global_database(self); + } + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE); + } + cont_(a); + + return err; +} + +/* + * Renames a table from one name to another from alter table call. + * This function can be used to move a table from one database to + * another. + */ +int ha_pbxt::rename_table(const char *from, const char *to) +{ + THD *thd = current_thd; + int err = 0; + XTThreadPtr self; + XTSharePtr share; + XTDatabaseHPtr to_db; + + XT_TRACE_CALL(); + + if (XTSystemTableShare::isSystemTable(from)) + return rename_system_table(from, to); + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + XT_PRINT2(self, "ha_pbxt::rename_table %s -> %s\n", from, to); + + try_(a) { + xt_ha_open_database_of_table(self, (XTPathStrPtr) to); + to_db = self->st_database; + + xt_ha_open_database_of_table(self, (XTPathStrPtr) from); + + if (self->st_database != to_db) + xt_throw_xterr(XT_CONTEXT, XT_ERR_CANNOT_CHANGE_DB); + + /* + * NOTE: MySQL does not lock before calling rename table! + * + * We cannot use pb_share because rename_table() is + * called without correctly initializing + * the handler! + */ + share = ha_get_share(self, from, true, NULL); + pushr_(ha_unget_share, share); + ha_aquire_exclusive_use(self, share, NULL); + pushr_(ha_release_exclusive_use, share); + ha_close_open_tables(self, share, NULL); + + self->st_ignore_fkeys = (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) != 0; + xt_rename_table(self, (XTPathStrPtr) from, (XTPathStrPtr) to); + + freer_(); // ha_release_exclusive_use(share) + freer_(); // ha_unget_share(share) + +#ifdef XT_STREAMING + /* PBMS remove the table? */ + xt_pbms_rename_table(from, to); +#endif + /* + * If there are no more PBXT tables in the database, we + * "drop the database", which deletes all PBXT resources + * in the database. + */ +#ifdef XT_USE_GLOBAL_DB + /* We now only drop the pbxt system data, + * when the PBXT database is dropped. + */ + if (!xt_table_exists(self->st_database)) { + xt_ha_all_threads_close_database(self, self->st_database); + xt_drop_database(self, self->st_database); + } +#endif + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + cont_(a); + + XT_RETURN(err); +} + +int ha_pbxt::rename_system_table(const char *from __attribute__((unused)), const char *to __attribute__((unused))) +{ + return ER_NOT_SUPPORTED_YET; +} + +uint ha_pbxt::max_supported_key_length() const +{ + return XT_INDEX_MAX_KEY_SIZE; +} + +uint ha_pbxt::max_supported_key_part_length() const +{ + /* There is a little overhead in order to fit! */ + return XT_INDEX_MAX_KEY_SIZE-4; +} + +/* + * Called in test_quick_select to determine if indexes should be used. + * + * As far as I can tell, time is measured in "disk reads". So the + * calculation below means the system reads about 20 rows per read. + * + * For example a sequence scan uses a read buffer which reads a + * number of rows at once, or a sequential scan can make use + * of the cache (so it need to read less). + */ +double ha_pbxt::scan_time() +{ + double result = (double) (stats.records + stats.deleted) / 38.0 + 2; + return result; +} + +/* + * The next method will never be called if you do not implement indexes. + */ +double ha_pbxt::read_time(uint index __attribute__((unused)), uint ranges, ha_rows rows) +{ + double result = rows2double(ranges+rows); + return result; +} + +/* + * Given a starting key, and an ending key estimate the number of rows that + * will exist between the two. end_key may be empty which in case determine + * if start_key matches any rows. + * + * Called from opt_range.cc by check_quick_keys(). + * + */ +ha_rows ha_pbxt::records_in_range(uint inx, key_range *min_key, key_range *max_key) +{ + XTIndexPtr ind; + key_part_map keypart_map; + u_int segement = 0; + ha_rows result; + + if (min_key) + keypart_map = min_key->keypart_map; + else if (max_key) + keypart_map = max_key->keypart_map; + else + return 1; + ind = (XTIndexPtr) pb_share->sh_dic_keys[inx]; + + while (keypart_map & 1) { + segement++; + keypart_map = keypart_map >> 1; + } + + if (segement < 1 || segement > ind->mi_seg_count) + result = 1; + else + result = ind->mi_seg[segement-1].is_recs_in_range; +#ifdef XT_PRINT_INDEX_OPT + printf("records_in_range %s index %d cols req=%d/%d read_bits=%X write_bits=%X index_bits=%X --> %d\n", pb_open_tab->ot_table->tab_name->ps_path, (int) inx, segement, ind->mi_seg_count, (int) *table->read_set->bitmap, (int) *table->write_set->bitmap, (int) *ind->mi_col_map.bitmap, (int) result); +#endif + return result; +} + +/* + * create() is called to create a table/database. The variable name will have the name + * of the table. When create() is called you do not need to worry about opening + * the table. Also, the FRM file will have already been created so adjusting + * create_info will not do you any good. You can overwrite the frm file at this + * point if you wish to change the table definition, but there are no methods + * currently provided for doing that. + + * Called from handle.cc by ha_create_table(). +*/ +int ha_pbxt::create(const char *table_path, TABLE *table_arg, HA_CREATE_INFO *create_info) +{ + THD *thd = current_thd; + int err = 0; + XTThreadPtr self; + XTDDTable *tab_def = NULL; + XTDictionaryRec dic; + + memset(&dic, 0, sizeof(dic)); + + XT_TRACE_CALL(); + + if (!(self = ha_set_current_thread(thd, &err))) + return xt_ha_pbxt_to_mysql_error(err); + + STAT_TRACE(self, *thd_query(thd)); + XT_PRINT1(self, "ha_pbxt::create %s\n", table_path); + + try_(a) { + xt_ha_open_database_of_table(self, (XTPathStrPtr) table_path); + + for (uint i=0; i<TS(table_arg)->keys; i++) { + if (table_arg->key_info[i].key_length > XT_INDEX_MAX_KEY_SIZE) + xt_throw_sulxterr(XT_CONTEXT, XT_ERR_KEY_TOO_LARGE, table_arg->key_info[i].name, (u_long) XT_INDEX_MAX_KEY_SIZE); + } + + /* ($) auto_increment_value will be zero if + * AUTO_INCREMENT is not used. Otherwise + * Query was ALTER TABLE ... AUTO_INCREMENT = x; or + * CREATE TABLE ... AUTO_INCREMENT = x; + */ + tab_def = xt_ri_create_table(self, true, (XTPathStrPtr) table_path, *thd_query(thd), myxt_create_table_from_table(self, table_arg)); + tab_def->checkForeignKeys(self, create_info->options & HA_LEX_CREATE_TMP_TABLE); + + dic.dic_table = tab_def; + dic.dic_my_table = table_arg; + dic.dic_tab_flags = (create_info->options & HA_LEX_CREATE_TMP_TABLE) ? XT_TAB_FLAGS_TEMP_TAB : 0; + dic.dic_min_auto_inc = (xtWord8) create_info->auto_increment_value; /* ($) */ + dic.dic_def_ave_row_size = (xtWord8) table_arg->s->avg_row_length; + myxt_setup_dictionary(self, &dic); + + /* + * We used to ignore the value of foreign_key_checks flag and allowed creation + * of tables with "hanging" references. Now we validate FKs if foreign_key_checks != 0 + */ + self->st_ignore_fkeys = (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) != 0; + + /* + * Previously I set delete_if_exists=TRUE because + * CREATE TABLE was being used to TRUNCATE. + * This was due to the flag HTON_CAN_RECREATE. + * Now I could set delete_if_exists=FALSE, but + * leaving it TRUE should not cause any problems. + */ + xt_create_table(self, (XTPathStrPtr) table_path, &dic); + } + catch_(a) { + if (tab_def) + tab_def->finalize(self); + dic.dic_table = NULL; + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + cont_(a); + + /* Free the dictionary, but not 'table_arg'! */ + dic.dic_my_table = NULL; + myxt_free_dictionary(self, &dic); + + XT_RETURN(err); +} + +void ha_pbxt::update_create_info(HA_CREATE_INFO *create_info) +{ + XTOpenTablePtr ot; + + if ((ot = pb_open_tab)) { + if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) { + /* Fill in the minimum auto-increment value! */ + create_info->auto_increment_value = ot->ot_table->tab_dic.dic_min_auto_inc; + } + } +} + +char *ha_pbxt::get_foreign_key_create_info() +{ + THD *thd = current_thd; + int err = 0; + XTThreadPtr self; + XTStringBufferRec tab_def = { 0, 0, 0 }; + + if (!(self = ha_set_current_thread(thd, &err))) { + xt_ha_pbxt_to_mysql_error(err); + return NULL; + } + + if (!pb_open_tab) { + if ((err = reopen())) + return NULL; + } + + if (!pb_open_tab->ot_table->tab_dic.dic_table) + return NULL; + + try_(a) { + pb_open_tab->ot_table->tab_dic.dic_table->loadForeignKeyString(self, &tab_def); + } + catch_(a) { + xt_sb_set_size(self, &tab_def, 0); + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + cont_(a); + + return tab_def.sb_cstring; +} + +void ha_pbxt::free_foreign_key_create_info(char* str) +{ + xt_free(NULL, str); +} + +bool ha_pbxt::get_error_message(int error __attribute__((unused)), String *buf) +{ + THD *thd = current_thd; + int err = 0; + XTThreadPtr self; + + if (!(self = ha_set_current_thread(thd, &err))) + return FALSE; + + if (!self->t_exception.e_xt_err) + return FALSE; + + buf->copy(self->t_exception.e_err_msg, strlen(self->t_exception.e_err_msg), system_charset_info); + return TRUE; +} + +/* + * get info about FKs of the currently open table + * used in + * 1. REPLACE; is > 0 if table is referred by a FOREIGN KEY + * 2. INFORMATION_SCHEMA tables: TABLE_CONSTRAINTS, REFERENTIAL_CONSTRAINTS + * Return value: as of 5.1.24 it's ignored + */ + +int ha_pbxt::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list) +{ + int err = 0; + XTThreadPtr self; + const char *action; + + if (!(self = ha_set_current_thread(thd, &err))) { + return xt_ha_pbxt_to_mysql_error(err); + } + + try_(a) { + XTDDTable *table_dic = pb_open_tab->ot_table->tab_dic.dic_table; + + if (table_dic == NULL) + xt_throw_errno(XT_CONTEXT, XT_ERR_NO_DICTIONARY); + + for (int i = 0, sz = table_dic->dt_fkeys.size(); i < sz; i++) { + FOREIGN_KEY_INFO *fk_info= new // assumed that C++ exceptions are disabled + (thd_alloc(thd, sizeof(FOREIGN_KEY_INFO))) FOREIGN_KEY_INFO; + + if (fk_info == NULL) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + + XTDDForeignKey *fk = table_dic->dt_fkeys.itemAt(i); + + const char *path = fk->fk_ref_tab_name->ps_path; + const char *ref_tbl_name = path + strlen(path); + + while (ref_tbl_name != path && !XT_IS_DIR_CHAR(*ref_tbl_name)) + ref_tbl_name--; + + const char * ref_db_name = ref_tbl_name - 1; + + while (ref_db_name != path && !XT_IS_DIR_CHAR(*ref_db_name)) + ref_db_name--; + + ref_tbl_name++; + ref_db_name++; + + fk_info->forein_id = thd_make_lex_string(thd, 0, + fk->co_name, (uint) strlen(fk->co_name), 1); + + fk_info->referenced_db = thd_make_lex_string(thd, 0, + ref_db_name, (uint) (ref_tbl_name - ref_db_name - 1), 1); + + fk_info->referenced_table = thd_make_lex_string(thd, 0, + ref_tbl_name, (uint) strlen(ref_tbl_name), 1); + + fk_info->referenced_key_name = NULL; + + XTIndex *ix = fk->getReferenceIndexPtr(); + if (ix == NULL) /* can be NULL if another thread changes referenced table at the moment */ + continue; + + XTDDTable *ref_table = fk->fk_ref_table; + + // might be a self-reference + if ((ref_table == NULL) + && (xt_tab_compare_names(path, table_dic->dt_table->tab_name->ps_path) == 0)) { + ref_table = table_dic; + } + + if (ref_table != NULL) { + const XTList<XTDDIndex>& ix_list = ref_table->dt_indexes; + for (int j = 0, sz2 = ix_list.size(); j < sz2; j++) { + XTDDIndex *ddix = ix_list.itemAt(j); + if (ddix->in_index == ix->mi_index_no) { + const char *ix_name = + ddix->co_name ? ddix->co_name : ddix->co_ind_name; + fk_info->referenced_key_name = thd_make_lex_string(thd, 0, + ix_name, (uint) strlen(ix_name), 1); + break; + } + } + } + + action = XTDDForeignKey::actionTypeToString(fk->fk_on_delete); + fk_info->delete_method = thd_make_lex_string(thd, 0, + action, (uint) strlen(action), 1); + action = XTDDForeignKey::actionTypeToString(fk->fk_on_update); + fk_info->update_method = thd_make_lex_string(thd, 0, + action, (uint) strlen(action), 1); + + const XTList<XTDDColumnRef>& cols = fk->co_cols; + for (int j = 0, sz2 = cols.size(); j < sz2; j++) { + XTDDColumnRef *col_ref= cols.itemAt(j); + fk_info->foreign_fields.push_back(thd_make_lex_string(thd, 0, + col_ref->cr_col_name, (uint) strlen(col_ref->cr_col_name), 1)); + } + + const XTList<XTDDColumnRef>& ref_cols = fk->fk_ref_cols; + for (int j = 0, sz2 = ref_cols.size(); j < sz2; j++) { + XTDDColumnRef *col_ref= ref_cols.itemAt(j); + fk_info->referenced_fields.push_back(thd_make_lex_string(thd, 0, + col_ref->cr_col_name, (uint) strlen(col_ref->cr_col_name), 1)); + } + + f_key_list->push_back(fk_info); + } + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key); + } + cont_(a); + + return err; +} + +uint ha_pbxt::referenced_by_foreign_key() +{ + XTDDTable *table_dic = pb_open_tab->ot_table->tab_dic.dic_table; + + if (!table_dic) + return 0; + /* Check the list of referencing tables: */ + return table_dic->dt_trefs ? 1 : 0; +} + + +struct st_mysql_sys_var +{ + MYSQL_PLUGIN_VAR_HEADER; +}; + +#if MYSQL_VERSION_ID < 60000 +#if MYSQL_VERSION_ID >= 50124 +#define USE_CONST_SAVE +#endif +#else +#if MYSQL_VERSION_ID >= 60005 +#define USE_CONST_SAVE +#endif +#endif + +#ifdef USE_CONST_SAVE +static void pbxt_record_cache_size_func(THD *thd __attribute__((unused)), struct st_mysql_sys_var *var, void *tgt, const void *save) +#else +static void pbxt_record_cache_size_func(THD *thd __attribute__((unused)), struct st_mysql_sys_var *var, void *tgt, void *save) +#endif +{ + xtInt8 record_cache_size; + + char *old= *(char **) tgt; + *(char **)tgt= *(char **) save; + if (var->flags & PLUGIN_VAR_MEMALLOC) + { + *(char **)tgt= my_strdup(*(char **) save, MYF(0)); + my_free(old, MYF(0)); + } + record_cache_size = ha_set_variable(&pbxt_record_cache_size, &vp_record_cache_size); + xt_tc_set_cache_size((size_t) record_cache_size); +#ifdef DEBUG + char buffer[200]; + + sprintf(buffer, "pbxt_record_cache_size=%llu\n", (u_llong) record_cache_size); + xt_logf(XT_NT_INFO, buffer); +#endif +} + +#ifndef DRIZZLED +struct st_mysql_storage_engine pbxt_storage_engine = { + MYSQL_HANDLERTON_INTERFACE_VERSION +}; +static st_mysql_information_schema pbxt_statitics = { + MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION +}; +#endif + +#if MYSQL_VERSION_ID >= 50118 +static MYSQL_SYSVAR_STR(index_cache_size, pbxt_index_cache_size, + PLUGIN_VAR_READONLY, + "The amount of memory allocated to the index cache, used only to cache index data.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(record_cache_size, pbxt_record_cache_size, + PLUGIN_VAR_READONLY, // PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "The amount of memory allocated to the record cache used to cache table data.", + NULL, pbxt_record_cache_size_func, NULL); + +static MYSQL_SYSVAR_STR(log_cache_size, pbxt_log_cache_size, + PLUGIN_VAR_READONLY, + "The amount of memory allocated to the transaction log cache used to cache transaction log data.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(log_file_threshold, pbxt_log_file_threshold, + PLUGIN_VAR_READONLY, + "The size of a transaction log before rollover, and a new log is created.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(transaction_buffer_size, pbxt_transaction_buffer_size, + PLUGIN_VAR_READONLY, + "The size of the global transaction log buffer (the engine allocates 2 buffers of this size).", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(log_buffer_size, pbxt_log_buffer_size, + PLUGIN_VAR_READONLY, + "The size of the buffer used to cache data from transaction and data logs during sequential scans, or when writing a data log.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(checkpoint_frequency, pbxt_checkpoint_frequency, + PLUGIN_VAR_READONLY, + "The size of the transaction data buffer which is allocate by each thread.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(data_log_threshold, pbxt_data_log_threshold, + PLUGIN_VAR_READONLY, + "The maximum size of a data log file.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(data_file_grow_size, pbxt_data_file_grow_size, + PLUGIN_VAR_READONLY, + "The amount by which the handle data files (.xtd) grow.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(row_file_grow_size, pbxt_row_file_grow_size, + PLUGIN_VAR_READONLY, + "The amount by which the row pointer files (.xtr) grow.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_INT(garbage_threshold, xt_db_garbage_threshold, + PLUGIN_VAR_OPCMDARG, + "The percentage of garbage in a repository file before it is compacted.", + NULL, NULL, XT_DL_DEFAULT_GARBAGE_LEVEL, 0, 100, 1); + +static MYSQL_SYSVAR_INT(log_file_count, xt_db_log_file_count, + PLUGIN_VAR_OPCMDARG, + "The minimum number of transaction logs used.", + NULL, NULL, XT_DL_DEFAULT_XLOG_COUNT, 1, 20000, 1); + +static MYSQL_SYSVAR_INT(auto_increment_mode, xt_db_auto_increment_mode, + PLUGIN_VAR_OPCMDARG, + "The auto-increment mode, 0 = MySQL standard (default), 1 = previous ID's never reused.", + NULL, NULL, XT_AUTO_INCREMENT_DEF, 0, 1, 1); + +/* {RN145} */ +static MYSQL_SYSVAR_INT(offline_log_function, xt_db_offline_log_function, + PLUGIN_VAR_OPCMDARG, + "Determines what happens to transaction logs when the are moved offline, 0 = recycle logs (default), 1 = delete logs (default on Mac OS X), 2 = keep logs.", + NULL, NULL, XT_OFFLINE_LOG_FUNCTION_DEF, 0, 2, 1); + +/* {RN150} */ +static MYSQL_SYSVAR_INT(sweeper_priority, xt_db_sweeper_priority, + PLUGIN_VAR_OPCMDARG, + "Determines the priority of the background sweeper process, 0 = low (default), 1 = normal (same as user threads), 2 = high.", + NULL, NULL, XT_PRIORITY_LOW, XT_PRIORITY_LOW, XT_PRIORITY_HIGH, 1); + +static struct st_mysql_sys_var* pbxt_system_variables[] = { + MYSQL_SYSVAR(index_cache_size), + MYSQL_SYSVAR(record_cache_size), + MYSQL_SYSVAR(log_cache_size), + MYSQL_SYSVAR(log_file_threshold), + MYSQL_SYSVAR(transaction_buffer_size), + MYSQL_SYSVAR(log_buffer_size), + MYSQL_SYSVAR(checkpoint_frequency), + MYSQL_SYSVAR(data_log_threshold), + MYSQL_SYSVAR(data_file_grow_size), + MYSQL_SYSVAR(row_file_grow_size), + MYSQL_SYSVAR(garbage_threshold), + MYSQL_SYSVAR(log_file_count), + MYSQL_SYSVAR(auto_increment_mode), + MYSQL_SYSVAR(offline_log_function), + MYSQL_SYSVAR(sweeper_priority), + NULL +}; +#endif + +#ifdef DRIZZLED +drizzle_declare_plugin(pbxt) +#else +mysql_declare_plugin(pbxt) +#endif +{ + MYSQL_STORAGE_ENGINE_PLUGIN, +#ifndef DRIZZLED + &pbxt_storage_engine, +#endif + "PBXT", +#ifdef DRIZZLED + "1.0", +#endif + "Paul McCullagh, PrimeBase Technologies GmbH", + "High performance, multi-versioning transactional engine", + PLUGIN_LICENSE_GPL, + pbxt_init, /* Plugin Init */ + pbxt_end, /* Plugin Deinit */ +#ifndef DRIZZLED + 0x0001 /* 0.1 */, +#endif + NULL, /* status variables */ +#if MYSQL_VERSION_ID >= 50118 + pbxt_system_variables, /* system variables */ +#else + NULL, +#endif + NULL /* config options */ +}, +{ + MYSQL_INFORMATION_SCHEMA_PLUGIN, +#ifndef DRIZZLED + &pbxt_statitics, +#endif + "PBXT_STATISTICS", +#ifdef DRIZZLED + "1.0", +#endif + "Paul McCullagh, PrimeBase Technologies GmbH", + "PBXT internal system statitics", + PLUGIN_LICENSE_GPL, + pbxt_init_statitics, /* plugin init */ + pbxt_exit_statitics, /* plugin deinit */ +#ifndef DRIZZLED + 0x0005, +#endif + NULL, /* status variables */ + NULL, /* system variables */ + NULL /* config options */ +} +#ifdef DRIZZLED +drizzle_declare_plugin_end; +#else +mysql_declare_plugin_end; +#endif + +#if defined(XT_WIN) && defined(XT_COREDUMP) + +/* + * WINDOWS CORE DUMP SUPPORT + * + * MySQL supports core dumping on Windows with --core-file command line option. + * However it creates dumps with the MiniDumpNormal option which saves only stack traces. + * + * We instead (or in addition) create dumps with MiniDumpWithoutOptionalData option + * which saves all available information. To enable core dumping enable XT_COREDUMP + * at compile time. + * In addition, pbxt_crash_debug must be set to TRUE which is the case if XT_CRASH_DEBUG + * is defined. + * This switch is also controlled by creating a file called "no-debug" or "crash-debug" + * in the pbxt database directory. + */ + +typedef enum _MINIDUMP_TYPE { + MiniDumpNormal = 0x0000, + MiniDumpWithDataSegs = 0x0001, + MiniDumpWithFullMemory = 0x0002, + MiniDumpWithHandleData = 0x0004, + MiniDumpFilterMemory = 0x0008, + MiniDumpScanMemory = 0x0010, + MiniDumpWithUnloadedModules = 0x0020, + MiniDumpWithIndirectlyReferencedMemory = 0x0040, + MiniDumpFilterModulePaths = 0x0080, + MiniDumpWithProcessThreadData = 0x0100, + MiniDumpWithPrivateReadWriteMemory = 0x0200, +} MINIDUMP_TYPE; + +typedef struct _MINIDUMP_EXCEPTION_INFORMATION { + DWORD ThreadId; + PEXCEPTION_POINTERS ExceptionPointers; + BOOL ClientPointers; +} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION; + +typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)( + HANDLE hProcess, + DWORD dwPid, + HANDLE hFile, + MINIDUMP_TYPE DumpType, + void *ExceptionParam, + void *UserStreamParam, + void *CallbackParam + ); + +char base_path[_MAX_PATH] = {0}; +char dump_path[_MAX_PATH] = {0}; + +void core_dump(struct _EXCEPTION_POINTERS *pExceptionInfo) +{ + SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, 0 }; + int i; + HMODULE hDll = NULL; + HANDLE hFile; + MINIDUMPWRITEDUMP pDump; + char *end_ptr = base_path; + + MINIDUMP_EXCEPTION_INFORMATION ExInfo, *ExInfoPtr = NULL; + + if (pExceptionInfo) { + ExInfo.ThreadId = GetCurrentThreadId(); + ExInfo.ExceptionPointers = pExceptionInfo; + ExInfo.ClientPointers = NULL; + ExInfoPtr = &ExInfo; + } + + end_ptr = base_path + strlen(base_path); + + strcat(base_path, "DBGHELP.DLL" ); + hDll = LoadLibrary(base_path); + *end_ptr = 0; + if (hDll==NULL) { + int err; + err = HRESULT_CODE(GetLastError()); + hDll = LoadLibrary( "DBGHELP.DLL" ); + if (hDll==NULL) { + err = HRESULT_CODE(GetLastError()); + return; + } + } + + pDump = (MINIDUMPWRITEDUMP)GetProcAddress( hDll, "MiniDumpWriteDump" ); + if (!pDump) { + int err; + err = HRESULT_CODE(GetLastError()); + return; + } + + for (i = 1; i < INT_MAX; i++) { + sprintf(dump_path, "%sPBXTCore%08d.dmp", base_path, i); + hFile = CreateFile( dump_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL ); + + if ( hFile != INVALID_HANDLE_VALUE ) + break; + + if (HRESULT_CODE(GetLastError()) == ERROR_FILE_EXISTS ) + continue; + + return; + } + + // write the dump + BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, + MiniDumpWithPrivateReadWriteMemory, ExInfoPtr, NULL, NULL ); + + CloseHandle(hFile); +} + +LONG crash_filter( struct _EXCEPTION_POINTERS *pExceptionInfo ) +{ + core_dump(pExceptionInfo); + return EXCEPTION_EXECUTE_HANDLER; +} + +void register_crash_filter() +{ + SetUnhandledExceptionFilter( (LPTOP_LEVEL_EXCEPTION_FILTER) crash_filter ); +} + +#endif // XT_WIN && XT_COREDUMP diff --git a/storage/pbxt/src/ha_pbxt.h b/storage/pbxt/src/ha_pbxt.h new file mode 100644 index 00000000000..6f6a194de12 --- /dev/null +++ b/storage/pbxt/src/ha_pbxt.h @@ -0,0 +1,318 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * Derived from ha_example.h + * Copyright (C) 2003 MySQL AB + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-11-10 Paul McCullagh + * + */ +#ifndef __ha_pbxt_h__ +#define __ha_pbxt_h__ + +#ifdef DRIZZLED +#include <drizzled/common.h> +#include <drizzled/handler.h> +#include <drizzled/handlerton.h> +#include <mysys/thr_lock.h> +#else +#include "mysql_priv.h" +#endif + +#include "xt_defs.h" +#include "table_xt.h" + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#if MYSQL_VERSION_ID <= 50120 +#define thd_killed(t) (t)->killed +#endif + +#if MYSQL_VERSION_ID >= 50120 +#define byte uchar +#endif + +class ha_pbxt; + +extern handlerton *pbxt_hton; + +/* + * XTShareRec is a structure that will be shared amoung all open handlers. + */ +typedef struct XTShare { + XTPathStrPtr sh_table_path; + uint sh_use_count; + + XTTableHPtr sh_table; /* This is a XTTableHPtr, a reference to the XT internal table handle. */ + + uint sh_dic_key_count; + XTIndexPtr *sh_dic_keys; /* A reference to the XT internal index list. */ + xtBool sh_recalc_selectivity; /* This is set to TRUE if when have < 100 rows when the table is openned. */ + + /* We use a trick here to get an exclusive lock + * on a table. The trick avoids having to use a + * semaphore if a thread does not want + * exclusive use. + */ + xt_mutex_type *sh_ex_mutex; + xt_cond_type *sh_ex_cond; + xtBool sh_table_lock; /* Set to TRUE if a lock on the table is held. */ + ha_pbxt *sh_handlers; /* Double linked list of handlers for a particular table. */ + xtWord8 sh_min_auto_inc; /* Used to proporgate the current auto-inc over a DELETE FROM + * (does not work if the server shuts down in between!). + */ + + THR_LOCK sh_lock; /* MySQL lock */ +} XTShareRec, *XTSharePtr; + +/* + * Class definition for the storage engine + */ +class ha_pbxt: public handler +{ + public: + XTSharePtr pb_share; /* Shared table info */ + + XTOpenTablePtr pb_open_tab; /* This is a XTOpenTablePtr (a reference to the XT internal table handle)! */ + + xtBool pb_key_read; /* No Need to retrieve the entire row, index values are sufficient. */ + int pb_ignore_dup_key; + u_int pb_ind_row_count; + + THR_LOCK_DATA pb_lock; /* MySQL lock */ + + ha_pbxt *pb_ex_next; /* Double linked list of handlers for a particular table. */ + ha_pbxt *pb_ex_prev; + + xtBool pb_lock_table; /* The operation requires a table lock. */ + int pb_table_locked; /* TRUE of this handler holds the table lock. */ + int pb_ex_in_use; /* Set to 1 while when the handler is in use. */ + + THD *pb_mysql_thd; /* A pointer to the MySQL thread. */ + xtBool pb_in_stat; /* TRUE of start_stmt() was issued */ + + ha_pbxt(handlerton *hton, TABLE_SHARE *table_arg); + + virtual ~ha_pbxt() { } + + /* The name that will be used for display purposes */ + const char *table_type() const { return "PBXT"; } + + /* + * The name of the index type that will be used for display + * don't implement this method unless you really have indexes. + */ + const char *index_type(uint inx) { (void) inx; return "BTREE"; } + + const char **bas_ext() const; + + MX_UINT8_T table_cache_type(); + + /* + * This is a list of flags that says what the storage engine + * implements. The current table flags are documented in + * handler.h + */ + MX_TABLE_TYPES_T table_flags() const; + + /* + * part is the key part to check. First key part is 0 + * If all_parts it's set, MySQL want to know the flags for the combined + * index up to and including 'part'. + */ + MX_ULONG_T index_flags(uint inx, uint part, bool all_parts) const; + + /* + * unireg.cc will call the following to make sure that the storage engine can + * handle the data it is about to send. + * + * Return *real* limits of your storage engine here. MySQL will do + * min(your_limits, MySQL_limits) automatically + * + * Theoretically PBXT supports any number of key parts, etc. + * Practically this is not true of course. + */ + uint max_supported_record_length() const { return UINT_MAX; } + uint max_supported_keys() const { return 512; } + uint max_supported_key_parts() const { return 128; } + uint max_supported_key_length() const; + uint max_supported_key_part_length() const; + + double scan_time(); + + double read_time(uint index, uint ranges, ha_rows rows); + + bool has_transactions() { return 1; } + + /* + * Everything below are methods that we implement in ha_pbxt.cc. + */ + void internal_close(THD *thd, struct XTThread *self); + int open(const char *name, int mode, uint test_if_locked); // required + int reopen(void); + int close(void); // required + + void init_auto_increment(xtWord8 min_auto_inc); + void get_auto_increment(MX_ULONGLONG_T offset, MX_ULONGLONG_T increment, + MX_ULONGLONG_T nb_desired_values, + MX_ULONGLONG_T *first_value, + MX_ULONGLONG_T *nb_reserved_values); + void set_auto_increment(Field *nr); + + int write_row(byte * buf); + int update_row(const byte * old_data, byte * new_data); + int delete_row(const byte * buf); + + /* Index access functions: */ + int xt_index_in_range(register XTOpenTablePtr ot, register XTIndexPtr ind, register XTIdxSearchKeyPtr search_key, byte *buf); + int xt_index_next_read(register XTOpenTablePtr ot, register XTIndexPtr ind, xtBool key_only, register XTIdxSearchKeyPtr search_key, byte *buf); + int xt_index_prev_read(XTOpenTablePtr ot, XTIndexPtr ind, xtBool key_only, register XTIdxSearchKeyPtr search_key, byte *buf); + int index_init(uint idx, bool sorted); + int index_end(); + int index_read(byte * buf, const byte * key, + uint key_len, enum ha_rkey_function find_flag); + int index_read_idx(byte * buf, uint idx, const byte * key, + uint key_len, enum ha_rkey_function find_flag); + int index_read_xt(byte * buf, uint idx, const byte * key, + uint key_len, enum ha_rkey_function find_flag); + int index_next(byte * buf); + int index_next_same(byte * buf, const byte *key, uint length); + int index_prev(byte * buf); + int index_first(byte * buf); + int index_last(byte * buf); + int index_read_last(byte * buf, const byte * key, uint key_len); + + /* Sequential scan functions: */ + int rnd_init(bool scan); //required + int rnd_end(); + int rnd_next(byte *buf); //required + int rnd_pos(byte * buf, byte *pos); //required + void position(const byte *record); //required +#if MYSQL_VERSION_ID < 50114 + void info(uint); +#else + int info(uint); +#endif + + int extra(enum ha_extra_function operation); + int reset(void); + int external_lock(THD *thd, int lock_type); //required + int start_stmt(THD *thd, thr_lock_type lock_type); + void unlock_row(); + int delete_all_rows(void); + int repair(THD* thd, HA_CHECK_OPT* check_opt); + int analyze(THD* thd, HA_CHECK_OPT* check_opt); + int optimize(THD* thd, HA_CHECK_OPT* check_opt); + int check(THD* thd, HA_CHECK_OPT* check_opt); + ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key); + int delete_table(const char *from); + int delete_system_table(const char *table_path); + int rename_table(const char * from, const char * to); + int rename_system_table(const char * from, const char * to); + int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); //required + void update_create_info(HA_CREATE_INFO *create_info); + + THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); //required + + /* Foreign key support: */ + //bool is_fk_defined_on_table_or_index(uint index); + char* get_foreign_key_create_info(); + int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list); + //bool can_switch_engines(); + uint referenced_by_foreign_key(); + void free_foreign_key_create_info(char* str); + + virtual bool get_error_message(int error, String *buf); +}; + +/* From ha_pbxt.cc: */ +#define XT_TAB_NAME_WITH_EXT_SIZE XT_TABLE_NAME_SIZE+4 + +class THD; +struct XTThread; +struct XTDatabase; + +void xt_ha_unlock_table(struct XTThread *self, void *share); +void xt_ha_close_global_database(XTThreadPtr self); +void xt_ha_open_database_of_table(struct XTThread *self, XTPathStrPtr table_path); +struct XTThread *xt_ha_set_current_thread(THD *thd, XTExceptionPtr e); +void xt_ha_close_connection(THD* thd); +struct XTThread *xt_ha_thd_to_self(THD* thd); +int xt_ha_pbxt_to_mysql_error(int xt_err); +int xt_ha_pbxt_thread_error_for_mysql(THD *thd, const XTThreadPtr self, int ignore_dup_key); +void xt_ha_all_threads_close_database(XTThreadPtr self, XTDatabase *db); + +/* + * These hooks are suppossed to only be used by InnoDB: + */ +#ifndef DRIZZLED +#ifdef INNODB_COMPATIBILITY_HOOKS +extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd); +extern "C" char **thd_query(MYSQL_THD thd); +extern "C" int thd_slave_thread(const MYSQL_THD thd); +extern "C" int thd_non_transactional_update(const MYSQL_THD thd); +extern "C" int thd_binlog_format(const MYSQL_THD thd); +extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); +#else +#define thd_charset(t) (t)->charset() +#define thd_query(t) &(t)->query +#define thd_slave_thread(t) (t)->slave_thread +#define thd_non_transactional_update(t) (t)->transaction.all.modified_non_trans_table +#define thd_binlog_format(t) (t)->variables.binlog_format +#define thd_mark_transaction_to_rollback(t) mark_transaction_to_rollback(t, all) +#endif // INNODB_COMPATIBILITY_HOOKS */ +#endif /* !DRIZZLED */ + +/* How to lock MySQL mutexes! */ +#ifdef SAFE_MUTEX + +#if MYSQL_VERSION_ID < 60000 +#if MYSQL_VERSION_ID < 50123 +#define myxt_mutex_lock(x) safe_mutex_lock(x,__FILE__,__LINE__) +#else +#define myxt_mutex_lock(x) safe_mutex_lock(x,0,__FILE__,__LINE__) +#endif +#else +#if MYSQL_VERSION_ID < 60004 +#define myxt_mutex_lock(x) safe_mutex_lock(x,__FILE__,__LINE__) +#else +#define myxt_mutex_lock(x) safe_mutex_lock(x,0,__FILE__,__LINE__) +#endif +#endif + +#define myxt_mutex_t safe_mutex_t +#define myxt_mutex_unlock(x) safe_mutex_unlock(x,__FILE__,__LINE__) + +#else // SAFE_MUTEX + +#ifdef MY_PTHREAD_FASTMUTEX +#define myxt_mutex_lock(x) my_pthread_fastmutex_lock(x) +#define myxt_mutex_t my_pthread_fastmutex_t +#define myxt_mutex_unlock(x) pthread_mutex_unlock(&(x)->mutex) +#else +#define myxt_mutex_lock(x) pthread_mutex_lock(x) +#define myxt_mutex_t pthread_mutex_t +#define myxt_mutex_unlock(x) pthread_mutex_unlock(x) +#endif + +#endif // SAFE_MUTEX + +#endif + diff --git a/storage/pbxt/src/ha_xtsys.cc b/storage/pbxt/src/ha_xtsys.cc new file mode 100644 index 00000000000..1c76d13379a --- /dev/null +++ b/storage/pbxt/src/ha_xtsys.cc @@ -0,0 +1,252 @@ +/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany + * + * PrimeBase Media Stream for MySQL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Paul McCullagh + * + * 2007-05-20 + * + * H&G2JCtL + * + * Table handler. + * + */ + +#ifdef USE_PRAGMA_IMPLEMENTATION +#pragma implementation // gcc: Class implementation +#endif + +#include "xt_config.h" + +#include <stdlib.h> +#include <time.h> + +#ifdef DRIZZLED +#include <drizzled/server_includes.h> +#endif + +#include "ha_xtsys.h" +#include "ha_pbxt.h" + +#include "strutil_xt.h" +#include "database_xt.h" +#include "discover_xt.h" +#include "systab_xt.h" +#include "xt_defs.h" + +/* Note: mysql_priv.h messes with new, which caused a crash. */ +#ifdef new +#undef new +#endif + +/* + * --------------------------------------------------------------- + * HANDLER INTERFACE + */ + +ha_xtsys::ha_xtsys(handlerton *hton, TABLE_SHARE *table_arg): +handler(hton, table_arg), +ha_open_tab(NULL) +{ + init(); +} + +static const char *ha_pbms_exts[] = { + "", + NullS +}; + +const char **ha_xtsys::bas_ext() const +{ + return ha_pbms_exts; +} + +int ha_xtsys::open(const char *table_path, int mode __attribute__((unused)), uint test_if_locked __attribute__((unused))) +{ + THD *thd = current_thd; + XTExceptionRec e; + XTThreadPtr self; + int err = 0; + + if (!(self = xt_ha_set_current_thread(thd, &e))) + return xt_ha_pbxt_to_mysql_error(e.e_xt_err); + + try_(a) { + xt_ha_open_database_of_table(self, (XTPathStrPtr) table_path); + + ha_open_tab = XTSystemTableShare::openSystemTable(self, table_path, table); + thr_lock_data_init(ha_open_tab->ost_share->sts_my_lock, &ha_lock, NULL); + ref_length = ha_open_tab->getRefLen(); + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE); + if (ha_open_tab) { + ha_open_tab->release(self); + ha_open_tab = NULL; + } + } + cont_(a); + + return err; +} + +int ha_xtsys::close(void) +{ + THD *thd = current_thd; + XTExceptionRec e; + volatile XTThreadPtr self = NULL; + int err = 0; + + if (thd) + self = xt_ha_set_current_thread(thd, &e); + else { + if (!(self = xt_create_thread("TempForClose", FALSE, TRUE, &e))) { + xt_log_exception(NULL, &e, XT_LOG_DEFAULT); + return 0; + } + } + + if (self) { + try_(a) { + if (ha_open_tab) { + ha_open_tab->release(self); + ha_open_tab = NULL; + } + } + catch_(a) { + err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE); + } + cont_(a); + + if (!thd) + xt_free_thread(self); + } + else + xt_log(XT_NS_CONTEXT, XT_LOG_WARNING, "Unable to release table reference\n"); + + return err; +} + +int ha_xtsys::rnd_init(bool scan __attribute__((unused))) +{ + int err = 0; + + if (!ha_open_tab->seqScanInit()) + err = xt_ha_pbxt_thread_error_for_mysql(current_thd, xt_get_self(), FALSE); + + return err; +} + +int ha_xtsys::rnd_next(byte *buf) +{ + bool eof; + int err = 0; + + if (!ha_open_tab->seqScanNext((char *) buf, &eof)) { + if (eof) + err = HA_ERR_END_OF_FILE; + else + err = xt_ha_pbxt_thread_error_for_mysql(current_thd, xt_get_self(), FALSE); + } + + return err; +} + +void ha_xtsys::position(const byte *record) +{ + xtWord4 rec_id; + rec_id = ha_open_tab->seqScanPos((xtWord1 *) record); + mi_int4store((xtWord1 *) ref, rec_id); +} + +int ha_xtsys::rnd_pos(byte * buf, byte *pos) +{ + int err = 0; + xtWord4 rec_id; + + rec_id = mi_uint4korr((xtWord1 *) pos); + if (!ha_open_tab->seqScanRead(rec_id, (char *) buf)) + err = xt_ha_pbxt_thread_error_for_mysql(current_thd, xt_get_self(), FALSE); + + return err; +} + +int ha_xtsys::info(uint flag __attribute__((unused))) +{ + return 0; +} + +int ha_xtsys::external_lock(THD *thd, int lock_type) +{ + XTExceptionRec e; + XTThreadPtr self; + int err = 0; + bool ok; + + if (!(self = xt_ha_set_current_thread(thd, &e))) + return xt_ha_pbxt_to_mysql_error(e.e_xt_err); + + if (lock_type == F_UNLCK) + ok = ha_open_tab->unuse(); + else + ok = ha_open_tab->use(); + + if (!ok) + err = xt_ha_pbxt_thread_error_for_mysql(current_thd, xt_get_self(), FALSE); + + return err; +} + +THR_LOCK_DATA **ha_xtsys::store_lock(THD *thd __attribute__((unused)), THR_LOCK_DATA **to, enum thr_lock_type lock_type) +{ + if (lock_type != TL_IGNORE && ha_lock.type == TL_UNLOCK) + ha_lock.type = lock_type; + *to++ = &ha_lock; + return to; +} + +/* Note: ha_pbxt::delete_system_table is called instead. */ +int ha_xtsys::delete_table(const char *table_path __attribute__((unused))) +{ + /* Should never be called */ + return 0; +} + +int ha_xtsys::create(const char *name __attribute__((unused)), TABLE *table_arg __attribute__((unused)), HA_CREATE_INFO *create_info __attribute__((unused))) +{ + /* Allow the table to be created. + * This is required after a dump is restored. + */ + return 0; +} + +bool ha_xtsys::get_error_message(int error __attribute__((unused)), String *buf) +{ + THD *thd = current_thd; + XTExceptionRec e; + XTThreadPtr self; + + if (!(self = xt_ha_set_current_thread(thd, &e))) + return FALSE; + + if (!self->t_exception.e_xt_err) + return FALSE; + + buf->copy(self->t_exception.e_err_msg, strlen(self->t_exception.e_err_msg), system_charset_info); + return TRUE; +} + diff --git a/storage/pbxt/src/ha_xtsys.h b/storage/pbxt/src/ha_xtsys.h new file mode 100644 index 00000000000..66a4b5a5dfa --- /dev/null +++ b/storage/pbxt/src/ha_xtsys.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Paul McCullagh + * + * 2007-05-20 + * + * H&G2JCtL + * + * PBXT System Table handler. + * + */ +#ifndef __HA_XTSYS_H__ +#define __HA_XTSYS_H__ + +#ifdef DRIZZLED +#include <drizzled/common.h> +#include <drizzled/handler.h> +#include <drizzled/current_session.h> +#else +#include "mysql_priv.h" +#endif + +#include "xt_defs.h" + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#if MYSQL_VERSION_ID >= 50120 +#define byte uchar +#endif + +class XTOpenSystemTable; + +class ha_xtsys: public handler +{ + THR_LOCK_DATA ha_lock; ///< MySQL lock + XTOpenSystemTable *ha_open_tab; + +public: + ha_xtsys(handlerton *hton, TABLE_SHARE *table_arg); + ~ha_xtsys() { } + + const char *table_type() const { return "PBXT"; } + + const char *index_type(uint inx __attribute__((unused))) { + return "NONE"; + } + + const char **bas_ext() const; + + MX_TABLE_TYPES_T table_flags() const { + return HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE; + } + + MX_ULONG_T index_flags(uint inx __attribute__((unused)), uint part __attribute__((unused)), bool all_parts __attribute__((unused))) const { + return (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | HA_KEYREAD_ONLY); + } + uint max_supported_keys() const { return 512; } + uint max_supported_key_part_length() const { return 1024; } + + int open(const char *name, int mode, uint test_if_locked); + int close(void); + int rnd_init(bool scan); + int rnd_next(byte *buf); + int rnd_pos(byte * buf, byte *pos); + void position(const byte *record); + int info(uint); + + int external_lock(THD *thd, int lock_type); + int delete_table(const char *from); + int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); + + THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); + bool get_error_message(int error, String *buf); +}; + +#endif + diff --git a/storage/pbxt/src/hashtab_xt.cc b/storage/pbxt/src/hashtab_xt.cc new file mode 100644 index 00000000000..3708f071ac5 --- /dev/null +++ b/storage/pbxt/src/hashtab_xt.cc @@ -0,0 +1,264 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-15 Paul McCullagh + * + */ + +#include "xt_config.h" + +#include <ctype.h> + +#include "pthread_xt.h" +#include "heap_xt.h" +#include "thread_xt.h" +#include "hashtab_xt.h" + +XTHashTabPtr xt_new_hashtable(XTThreadPtr self, XTHTCompareFunc comp_func, XTHTHashFunc hash_func, XTHTFreeFunc free_func, xtBool with_lock, xtBool with_cond) +{ + XTHashTabPtr ht; + xtHashValue tab_size = 223; + + ht = (XTHashTabPtr) xt_calloc(self, offsetof(XTHashTabRec, ht_items) + (sizeof(XTHashItemPtr) * tab_size)); + ht->ht_comp_func = comp_func; + ht->ht_hash_func = hash_func; + ht->ht_free_func = free_func; + ht->ht_tab_size = tab_size; + + if (with_lock || with_cond) { + ht->ht_lock = (xt_mutex_type *) xt_calloc(self, sizeof(xt_mutex_type)); + try_(a) { + xt_init_mutex_with_autoname(self, ht->ht_lock); + } + catch_(a) { + xt_free(self, ht->ht_lock); + xt_free(self, ht); + throw_(); + } + cont_(a); + } + + if (with_cond) { + ht->ht_cond = (xt_cond_type *) xt_calloc(self, sizeof(xt_cond_type)); + try_(b) { + xt_init_cond(self, ht->ht_cond); + } + catch_(b) { + xt_free(self, ht->ht_cond); + ht->ht_cond = NULL; + xt_free_hashtable(self, ht); + throw_(); + } + cont_(b); + } + + return ht; +} + +void xt_free_hashtable(XTThreadPtr self, XTHashTabPtr ht) +{ + xtHashValue i; + XTHashItemPtr item, tmp_item; + + if (ht->ht_lock) + xt_lock_mutex(self, ht->ht_lock); + for (i=0; i<ht->ht_tab_size; i++) { + item = ht->ht_items[i]; + while (item) { + if (ht->ht_free_func) + (*ht->ht_free_func)(self, item->hi_data); + tmp_item = item; + item = item->hi_next; + xt_free(self, tmp_item); + } + } + if (ht->ht_lock) + xt_unlock_mutex(self, ht->ht_lock); + if (ht->ht_lock) { + xt_free_mutex(ht->ht_lock); + xt_free(self, ht->ht_lock); + } + if (ht->ht_cond) { + xt_free_cond(ht->ht_cond); + xt_free(self, ht->ht_cond); + } + xt_free(self, ht); +} + +xtPublic void xt_ht_put(XTThreadPtr self, XTHashTabPtr ht, void *data) +{ + XTHashItemPtr item = NULL; + xtHashValue h; + + pushr_(ht->ht_free_func, data); + h = (*ht->ht_hash_func)(FALSE, data); + item = (XTHashItemPtr) xt_malloc(self, sizeof(XTHashItemRec)); + item->hi_data = data; + item->hi_hash = h; + item->hi_next = ht->ht_items[h % ht->ht_tab_size]; + ht->ht_items[h % ht->ht_tab_size] = item; + popr_(); +} + +xtPublic void *xt_ht_get(XTThreadPtr self __attribute__((unused)), XTHashTabPtr ht, void *key) +{ + XTHashItemPtr item; + xtHashValue h; + void *data = NULL; + + h = (*ht->ht_hash_func)(TRUE, key); + + item = ht->ht_items[h % ht->ht_tab_size]; + while (item) { + if (item->hi_hash == h && (*ht->ht_comp_func)(key, item->hi_data)) { + data = item->hi_data; + break; + } + item = item->hi_next; + } + + return data; +} + +xtPublic xtBool xt_ht_del(XTThreadPtr self, XTHashTabPtr ht, void *key) +{ + XTHashItemPtr item, pitem = NULL; + xtHashValue h; + xtBool found = FALSE; + + h = (*ht->ht_hash_func)(TRUE, key); + + item = ht->ht_items[h % ht->ht_tab_size]; + while (item) { + if (item->hi_hash == h && (*ht->ht_comp_func)(key, item->hi_data)) { + void *data; + + found = TRUE; + data = item->hi_data; + + /* Unlink the item: */ + if (pitem) + pitem->hi_next = item->hi_next; + else + ht->ht_items[h % ht->ht_tab_size] = item->hi_next; + + /* Free the item: */ + xt_free(self, item); + + /* Free the data */ + if (ht->ht_free_func) + (*ht->ht_free_func)(self, data); + break; + } + pitem = item; + item = item->hi_next; + } + + return found; +} + +xtPublic xtHashValue xt_ht_hash(char *s) +{ + register char *p; + register xtHashValue h = 0, g; + + p = s; + while (*p) { + h = (h << 4) + *p; + /* Assignment intended here! */ + if ((g = h & 0xF0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + p++; + } + return h; +} + +/* + * The case-insensitive version of the hash... + */ +xtPublic xtHashValue xt_ht_casehash(char *s) +{ + register char *p; + register xtHashValue h = 0, g; + + p = s; + while (*p) { + h = (h << 4) + tolower(*p); + /* Assignment intended here! */ + if ((g = h & 0xF0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + p++; + } + return h; +} + +xtPublic xtBool xt_ht_lock(XTThreadPtr self, XTHashTabPtr ht) +{ + if (ht->ht_lock) + return xt_lock_mutex(self, ht->ht_lock); + return TRUE; +} + +xtPublic void xt_ht_unlock(XTThreadPtr self, XTHashTabPtr ht) +{ + if (ht->ht_lock) + xt_unlock_mutex(self, ht->ht_lock); +} + +xtPublic void xt_ht_wait(XTThreadPtr self, XTHashTabPtr ht) +{ + xt_wait_cond(self, ht->ht_cond, ht->ht_lock); +} + +xtPublic void xt_ht_timed_wait(XTThreadPtr self, XTHashTabPtr ht, u_long milli_sec) +{ + xt_timed_wait_cond(self, ht->ht_cond, ht->ht_lock, milli_sec); +} + +xtPublic void xt_ht_signal(XTThreadPtr self, XTHashTabPtr ht) +{ + xt_signal_cond(self, ht->ht_cond); +} + +xtPublic void xt_ht_enum(struct XTThread *self __attribute__((unused)), XTHashTabPtr ht, XTHashEnumPtr en) +{ + en->he_i = 0; + en->he_item = NULL; + en->he_ht = ht; +} + +xtPublic void *xt_ht_next(struct XTThread *self __attribute__((unused)), XTHashEnumPtr en) +{ + if (en->he_item) { + en->he_item = en->he_item->hi_next; + if (en->he_item) + return en->he_item->hi_data; + en->he_i++; + } + while (en->he_i < en->he_ht->ht_tab_size) { + if ((en->he_item = en->he_ht->ht_items[en->he_i])) + return en->he_item->hi_data; + en->he_i++; + } + return NULL; +} + diff --git a/storage/pbxt/src/hashtab_xt.h b/storage/pbxt/src/hashtab_xt.h new file mode 100644 index 00000000000..d6085c4288d --- /dev/null +++ b/storage/pbxt/src/hashtab_xt.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-15 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_hashtab_h__ +#define __xt_hashtab_h__ + +#include "xt_defs.h" + +struct XTThread; + +#define xtHashValue u_int + +typedef xtBool (*XTHTCompareFunc)(void *key, void *data); +typedef xtHashValue (*XTHTHashFunc)(xtBool is_key, void *key_data); +typedef void (*XTHTFreeFunc)(struct XTThread *self, void *item); + +typedef struct XTHashItem { + struct XTHashItem *hi_next; + xtHashValue hi_hash; + void *hi_data; +} XTHashItemRec, *XTHashItemPtr; + +typedef struct XTHashTab { + XTHTCompareFunc ht_comp_func; + XTHTHashFunc ht_hash_func; + XTHTFreeFunc ht_free_func; + xt_mutex_type *ht_lock; + xt_cond_type *ht_cond; + + xtHashValue ht_tab_size; + XTHashItemPtr ht_items[XT_VAR_LENGTH]; +} XTHashTabRec, *XTHashTabPtr; + +typedef struct XTHashEnum { + u_int he_i; + XTHashItemPtr he_item; + XTHashTabPtr he_ht; +} XTHashEnumRec, *XTHashEnumPtr; + +XTHashTabPtr xt_new_hashtable(struct XTThread *self, XTHTCompareFunc comp_func, XTHTHashFunc hash_func, XTHTFreeFunc free_func, xtBool with_lock, xtBool with_cond); +void xt_free_hashtable(struct XTThread *self, XTHashTabPtr ht); + +void xt_ht_put(struct XTThread *self, XTHashTabPtr ht, void *data); +void *xt_ht_get(struct XTThread *self, XTHashTabPtr ht, void *key); +xtBool xt_ht_del(struct XTThread *self, XTHashTabPtr ht, void *key); + +xtHashValue xt_ht_hash(char *s); +xtHashValue xt_ht_casehash(char *s); + +xtBool xt_ht_lock(struct XTThread *self, XTHashTabPtr ht); +void xt_ht_unlock(struct XTThread *self, XTHashTabPtr ht); +void xt_ht_wait(struct XTThread *self, XTHashTabPtr ht); +void xt_ht_timed_wait(struct XTThread *self, XTHashTabPtr ht, u_long milli_sec); +void xt_ht_signal(struct XTThread *self, XTHashTabPtr ht); + +void xt_ht_enum(struct XTThread *self, XTHashTabPtr ht, XTHashEnumPtr en); +void *xt_ht_next(struct XTThread *self, XTHashEnumPtr en); + +#endif diff --git a/storage/pbxt/src/heap_xt.cc b/storage/pbxt/src/heap_xt.cc new file mode 100644 index 00000000000..a88df833a4a --- /dev/null +++ b/storage/pbxt/src/heap_xt.cc @@ -0,0 +1,129 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-10 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include "pthread_xt.h" +#include "heap_xt.h" +#include "thread_xt.h" + +#ifdef xt_heap_new +#undef xt_heap_new +#endif + +#ifdef DEBUG +xtPublic XTHeapPtr xt_mm_heap_new(XTThreadPtr self, size_t size, XTFinalizeFunc finalize, u_int line, c_char *file, xtBool track) +#else +xtPublic XTHeapPtr xt_heap_new(XTThreadPtr self, size_t size, XTFinalizeFunc finalize) +#endif +{ + volatile XTHeapPtr hp; + +#ifdef DEBUG + hp = (XTHeapPtr) xt_mm_calloc(self, size, line, file); + hp->h_track = track; + if (track) + printf("HEAP: +1 1 %s:%d\n", file, (int) line); +#else + hp = (XTHeapPtr) xt_calloc(self, size); +#endif + if (!hp) + return NULL; + + try_(a) { + xt_spinlock_init_with_autoname(self, &hp->h_lock); + } + catch_(a) { + xt_free(self, hp); + throw_(); + } + cont_(a); + + hp->h_ref_count = 1; + hp->h_finalize = finalize; + hp->h_onrelease = NULL; + return hp; +} + +xtPublic void xt_check_heap(XTThreadPtr self __attribute__((unused)), XTHeapPtr hp __attribute__((unused))) +{ +#ifdef DEBUG + xt_mm_malloc_size(self, hp); +#endif +} + +#ifdef DEBUG +xtPublic void xt_mm_heap_reference(XTThreadPtr self, XTHeapPtr hp, u_int line, c_char *file) +#else +xtPublic void xt_heap_reference(XTThreadPtr, XTHeapPtr hp) +#endif +{ + xt_spinlock_lock(&hp->h_lock); +#ifdef DEBUG + if (hp->h_track) + printf("HEAP: +1 %d->%d %s:%d\n", (int) hp->h_ref_count, (int) hp->h_ref_count+1, file, (int) line); +#endif + hp->h_ref_count++; + xt_spinlock_unlock(&hp->h_lock); +} + +xtPublic void xt_heap_release(XTThreadPtr self, XTHeapPtr hp) +{ + if (!hp) + return; +#ifdef DEBUG + xt_spinlock_lock(&hp->h_lock); + ASSERT(hp->h_ref_count != 0); + xt_spinlock_unlock(&hp->h_lock); +#endif + xt_spinlock_lock(&hp->h_lock); + if (hp->h_onrelease) + (*hp->h_onrelease)(self, hp); + if (hp->h_ref_count > 0) { +#ifdef DEBUG + if (hp->h_track) + printf("HEAP: -1 %d->%d\n", (int) hp->h_ref_count, (int) hp->h_ref_count-1); +#endif + hp->h_ref_count--; + if (hp->h_ref_count == 0) { + if (hp->h_finalize) + (*hp->h_finalize)(self, hp); + xt_spinlock_unlock(&hp->h_lock); + xt_free(self, hp); + return; + } + } + xt_spinlock_unlock(&hp->h_lock); +} + +xtPublic void xt_heap_set_release_callback(XTThreadPtr self __attribute__((unused)), XTHeapPtr hp, XTFinalizeFunc onrelease) +{ + hp->h_onrelease = onrelease; +} + +xtPublic u_int xt_heap_get_ref_count(struct XTThread *self __attribute__((unused)), XTHeapPtr hp) +{ + return hp->h_ref_count; +} + + diff --git a/storage/pbxt/src/heap_xt.h b/storage/pbxt/src/heap_xt.h new file mode 100644 index 00000000000..afad132e1e3 --- /dev/null +++ b/storage/pbxt/src/heap_xt.h @@ -0,0 +1,68 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-10 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_heap_h__ +#define __xt_heap_h__ + +#include "xt_defs.h" +#include "lock_xt.h" + +struct XTThread; + +/* + * Heap memory has a reference count, and a lock for shared access. + * It also has a finalize routine which is called before the memory is + * freed. + */ +typedef void (*XTFinalizeFunc)(struct XTThread *self, void *heap_ptr); + +typedef struct XTHeap { + XTSpinLockRec h_lock; /* Prevent concurrent access to the heap memory: */ + u_int h_ref_count; /* So we know when to free (EVERY pointer reference MUST be counted). */ + XTFinalizeFunc h_finalize; /* If non-NULL, call before freeing. */ + XTFinalizeFunc h_onrelease; /* If non-NULL, call on release. */ +#ifdef DEBUG + xtBool h_track; +#endif +} XTHeapRec, *XTHeapPtr; + +/* Returns with reference count = 1 */ +XTHeapPtr xt_heap_new(struct XTThread *self, size_t size, XTFinalizeFunc finalize); +XTHeapPtr xt_mm_heap_new(struct XTThread *self, size_t size, XTFinalizeFunc finalize, u_int line, c_char *file, xtBool track); + +void xt_heap_set_release_callback(struct XTThread *self, XTHeapPtr mem, XTFinalizeFunc onrelease); + +void xt_heap_reference(struct XTThread *self, XTHeapPtr mem); +void xt_mm_heap_reference(struct XTThread *self, XTHeapPtr hp, u_int line, c_char *file); + +void xt_heap_release(struct XTThread *self, XTHeapPtr mem); +u_int xt_heap_get_ref_count(struct XTThread *self, XTHeapPtr mem); + +void xt_check_heap(struct XTThread *self, XTHeapPtr mem); + +#ifdef DEBUG +#define xt_heap_new(t, s, f) xt_mm_heap_new(t, s, f, __LINE__, __FILE__, FALSE) +#define xt_heap_new_track(t, s, f) xt_mm_heap_new(t, s, f, __LINE__, __FILE__, TRUE) +#define xt_heap_reference(t, s) xt_mm_heap_reference(t, s, __LINE__, __FILE__) +#endif + +#endif diff --git a/storage/pbxt/src/index_xt.cc b/storage/pbxt/src/index_xt.cc new file mode 100644 index 00000000000..9cd9a966f74 --- /dev/null +++ b/storage/pbxt/src/index_xt.cc @@ -0,0 +1,3854 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-09-30 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <string.h> +#include <stdio.h> +#include <stddef.h> +#ifndef XT_WIN +#include <strings.h> +#endif + +#ifdef DRIZZLED +#include <drizzled/base.h> +#else +#include "mysql_priv.h" +#endif + +#include "pthread_xt.h" +#include "memory_xt.h" +#include "index_xt.h" +#include "heap_xt.h" +#include "database_xt.h" +#include "strutil_xt.h" +#include "cache_xt.h" +#include "myxt_xt.h" +#include "trace_xt.h" +#include "table_xt.h" + +#ifdef DEBUG +#define MAX_SEARCH_DEPTH 32 +//#define CHECK_AND_PRINT +//#define CHECK_NODE_REFERENCE +//#define TRACE_FLUSH +//#define CHECK_PRINTS_RECORD_REFERENCES +#else +#define MAX_SEARCH_DEPTH 100 +#endif + +#define IND_FLUSH_BUFFER_SIZE 200 + +typedef struct IdxStackItem { + XTIdxItemRec i_pos; + xtIndexNodeID i_branch; +} IdxStackItemRec, *IdxStackItemPtr; + +typedef struct IdxBranchStack { + int s_top; + IdxStackItemRec s_elements[MAX_SEARCH_DEPTH]; +} IdxBranchStackRec, *IdxBranchStackPtr; + +#ifdef DEBUG +#ifdef TEST_CODE +static void idx_check_on_key(XTOpenTablePtr ot); +#endif +static u_int idx_check_index(XTOpenTablePtr ot, XTIndexPtr ind, xtBool with_lock); +#endif + +static xtBool idx_insert_node(XTOpenTablePtr ot, XTIndexPtr ind, IdxBranchStackPtr stack, XTIdxKeyValuePtr key_value, xtIndexNodeID branch); + +#ifdef XT_TRACK_INDEX_UPDATES + +static xtBool ind_track_write(struct XTOpenTable *ot, struct XTIndex *ind, xtIndexNodeID offset, size_t size, xtWord1 *data) +{ + ot->ot_ind_reads++; + return xt_ind_write(ot, ind, offset, size, data); +} + +#define XT_IND_WRITE ind_track_write + +#else + +#define XT_IND_WRITE xt_ind_write + +#endif + + +#ifdef CHECK_NODE_REFERENCE +#define IDX_GET_NODE_REF(t, x, o) idx_get_node_ref(t, x, o) +#else +#define IDX_GET_NODE_REF(t, x, o) XT_GET_NODE_REF(t, (x) - (o)) +#endif + +/* + * ----------------------------------------------------------------------- + * DEBUG ACTIVITY + */ + +//#define TRACK_ACTIVITY + +#ifdef TRACK_ACTIVITY +#define TRACK_MAX_BLOCKS 2000 + +typedef struct TrackBlock { + xtWord1 exists; + char *activity; +} TrackBlockRec, *TrackBlockPtr; + +TrackBlockRec blocks[TRACK_MAX_BLOCKS]; + +xtPublic void track_work(u_int block, char *what) +{ + int len = 0, len2; + + ASSERT_NS(block > 0 && block <= TRACK_MAX_BLOCKS); + block--; + if (blocks[block].activity) + len = strlen(blocks[block].activity); + len2 = strlen(what); + xt_realloc_ns((void **) &blocks[block].activity, len + len2 + 1); + memcpy(blocks[block].activity + len, what, len2 + 1); +} + +static void track_block_exists(xtIndexNodeID block) +{ + if (XT_NODE_ID(block) > 0 && XT_NODE_ID(block) <= TRACK_MAX_BLOCKS) + blocks[XT_NODE_ID(block)-1].exists = TRUE; +} + +static void track_reset_missing() +{ + for (u_int i=0; i<TRACK_MAX_BLOCKS; i++) + blocks[i].exists = FALSE; +} + +static void track_dump_missing(xtIndexNodeID eof_block) +{ + for (u_int i=0; i<XT_NODE_ID(eof_block)-1; i++) { + if (!blocks[i].exists) + printf("block missing = %04d %s\n", i+1, blocks[i].activity); + } +} + +static void track_dump_all(u_int max_block) +{ + for (u_int i=0; i<max_block; i++) { + if (blocks[i].exists) + printf(" %04d %s\n", i+1, blocks[i].activity); + else + printf("-%04d %s\n", i+1, blocks[i].activity); + } +} + +#endif + +xtPublic void xt_ind_track_dump_block(XTTableHPtr tab __attribute__((unused)), xtIndexNodeID address __attribute__((unused))) +{ +#ifdef TRACK_ACTIVITY + u_int i = XT_NODE_ID(address)-1; + + printf("BLOCK %04d %s\n", i+1, blocks[i].activity); +#endif +} + +#ifdef CHECK_NODE_REFERENCE +static xtIndexNodeID idx_get_node_ref(XTTableHPtr tab, xtWord1 *ref, u_int node_ref_size) +{ + xtIndexNodeID node; + + /* Node is invalid by default: */ + XT_NODE_ID(node) = 0xFFFFEEEE; + if (node_ref_size) { + ref -= node_ref_size; + node = XT_RET_NODE_ID(XT_GET_DISK_4(ref)); + if (node >= tab->tab_ind_eof) { + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, tab->tab_name); + } + } + return node; +} +#endif + +/* + * ----------------------------------------------------------------------- + * Stack functions + */ + +static void idx_newstack(IdxBranchStackPtr stack) +{ + stack->s_top = 0; +} + +static xtBool idx_push(IdxBranchStackPtr stack, xtIndexNodeID n, XTIdxItemPtr pos) +{ + if (stack->s_top == MAX_SEARCH_DEPTH) { + xt_register_error(XT_REG_CONTEXT, XT_ERR_STACK_OVERFLOW, 0, "Index node stack overflow"); + return FAILED; + } + stack->s_elements[stack->s_top].i_branch = n; + if (pos) + stack->s_elements[stack->s_top].i_pos = *pos; + stack->s_top++; + return OK; +} + +static IdxStackItemPtr idx_pop(IdxBranchStackPtr stack) +{ + if (stack->s_top == 0) + return NULL; + stack->s_top--; + return &stack->s_elements[stack->s_top]; +} + +static IdxStackItemPtr idx_top(IdxBranchStackPtr stack) +{ + if (stack->s_top == 0) + return NULL; + return &stack->s_elements[stack->s_top-1]; +} + +/* + * ----------------------------------------------------------------------- + * Allocation of nodes + */ + +static xtBool idx_new_branch(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID *address) +{ + register XTTableHPtr tab; + xtIndexNodeID wrote_pos; + XTIndFreeBlockRec free_block; + XTIndFreeListPtr list_ptr; + + tab = ot->ot_table; + + //ASSERT_NS(XT_INDEX_HAVE_XLOCK(ind, ot)); + if (ind->mi_free_list && ind->mi_free_list->fl_free_count) { + ind->mi_free_list->fl_free_count--; + *address = ind->mi_free_list->fl_page_id[ind->mi_free_list->fl_free_count]; + TRACK_BLOCK_ALLOC(*address); + return OK; + } + + xt_lock_mutex_ns(&tab->tab_ind_lock); + + /* Check the cached free list: */ + while ((list_ptr = tab->tab_ind_free_list)) { + if (list_ptr->fl_start < list_ptr->fl_free_count) { + wrote_pos = list_ptr->fl_page_id[list_ptr->fl_start]; + list_ptr->fl_start++; + xt_unlock_mutex_ns(&tab->tab_ind_lock); + *address = wrote_pos; + TRACK_BLOCK_ALLOC(wrote_pos); + return OK; + } + tab->tab_ind_free_list = list_ptr->fl_next_list; + xt_free_ns(list_ptr); + } + + if ((XT_NODE_ID(wrote_pos) = XT_NODE_ID(tab->tab_ind_free))) { + /* Use the block on the free list: */ + if (!xt_ind_read_bytes(ot, wrote_pos, sizeof(XTIndFreeBlockRec), (xtWord1 *) &free_block)) + goto failed; + XT_NODE_ID(tab->tab_ind_free) = (xtIndexNodeID) XT_GET_DISK_8(free_block.if_next_block_8); + xt_unlock_mutex_ns(&tab->tab_ind_lock); + *address = wrote_pos; + TRACK_BLOCK_ALLOC(wrote_pos); + return OK; + } + + /* PMC - Dont allow overflow! */ + if (XT_NODE_ID(tab->tab_ind_eof) >= 0xFFFFFFF) { + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_FILE_TO_LARGE, xt_file_path(ot->ot_ind_file)); + goto failed; + } + *address = tab->tab_ind_eof; + XT_NODE_ID(tab->tab_ind_eof)++; + xt_unlock_mutex_ns(&tab->tab_ind_lock); + TRACK_BLOCK_ALLOC(*address); + return OK; + + failed: + xt_unlock_mutex_ns(&tab->tab_ind_lock); + return FAILED; +} + +/* Add the block to the private free list of the index. + * On flush, this list will be transfered to the global list. + */ +static xtBool idx_free_branch(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID node_id) +{ + register u_int count; + register u_int i; + register u_int guess; + + TRACK_BLOCK_FREE(node_id); + //ASSERT_NS(XT_INDEX_HAVE_XLOCK(ind, ot)); + if (!ind->mi_free_list) { + count = 0; + if (!(ind->mi_free_list = (XTIndFreeListPtr) xt_calloc_ns(offsetof(XTIndFreeListRec, fl_page_id) + 10 * sizeof(xtIndexNodeID)))) + return FAILED; + } + else { + count = ind->mi_free_list->fl_free_count; + if (!xt_realloc_ns((void **) &ind->mi_free_list, offsetof(XTIndFreeListRec, fl_page_id) + (count + 1) * sizeof(xtIndexNodeID))) + return FAILED; + } + + i = 0; + while (i < count) { + guess = (i + count - 1) >> 1; + if (XT_NODE_ID(node_id) == XT_NODE_ID(ind->mi_free_list->fl_page_id[guess])) { + // Should not happen... + ASSERT_NS(FALSE); + return OK; + } + if (XT_NODE_ID(node_id) < XT_NODE_ID(ind->mi_free_list->fl_page_id[guess])) + count = guess; + else + i = guess + 1; + } + + /* Insert at position i */ + memmove(ind->mi_free_list->fl_page_id + i + 1, ind->mi_free_list->fl_page_id + i, (ind->mi_free_list->fl_free_count - i) * sizeof(xtIndexNodeID)); + ind->mi_free_list->fl_page_id[i] = node_id; + ind->mi_free_list->fl_free_count++; + + /* Set the cache page to clean: */ + return xt_ind_clean(ot, ind, node_id); +} + +/* + * ----------------------------------------------------------------------- + * Simple compare functions + */ + +xtPublic int xt_compare_2_int4(XTIndexPtr ind __attribute__((unused)), uint key_length, xtWord1 *key_value, xtWord1 *b_value) +{ + int r; + + ASSERT_NS(key_length == 4 || key_length == 8); + r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value); + if (r == 0 && key_length > 4) { + key_value += 4; + b_value += 4; + r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value); + } + return r; +} + +xtPublic int xt_compare_3_int4(XTIndexPtr ind __attribute__((unused)), uint key_length, xtWord1 *key_value, xtWord1 *b_value) +{ + int r; + + ASSERT_NS(key_length == 4 || key_length == 8 || key_length == 12); + r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value); + if (r == 0 && key_length > 4) { + key_value += 4; + b_value += 4; + r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value); + if (r == 0 && key_length > 8) { + key_value += 4; + b_value += 4; + r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value); + } + } + return r; +} + +/* + * ----------------------------------------------------------------------- + * Tree branch sanning (searching nodes and leaves) + */ + +xtPublic void xt_scan_branch_single(struct XTTable *tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result) +{ + XT_NODE_TEMP; + u_int branch_size; + u_int node_ref_size; + u_int full_item_size; + int search_flags; + register xtWord1 *base; + register u_int i; + register xtWord1 *bitem; + + branch_size = XT_GET_DISK_2(branch->tb_size_2); + node_ref_size = XT_IS_NODE(branch_size) ? XT_NODE_REF_SIZE : 0; + + result->sr_found = FALSE; + result->sr_duplicate = FALSE; + result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size); + ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2); + + result->sr_item.i_item_size = ind->mi_key_size + XT_RECORD_REF_SIZE; + full_item_size = result->sr_item.i_item_size + node_ref_size; + result->sr_item.i_node_ref_size = node_ref_size; + + search_flags = value->sv_flags; + base = branch->tb_data + node_ref_size; + if (search_flags & XT_SEARCH_FIRST_FLAG) + i = 0; + else if (search_flags & XT_SEARCH_AFTER_LAST_FLAG) + i = (result->sr_item.i_total_size - node_ref_size) / full_item_size; + else { + register u_int guess; + register u_int count; + register xtInt4 r; + xtRecordID key_record; + + key_record = value->sv_rec_id; + count = (result->sr_item.i_total_size - node_ref_size) / full_item_size; + + ASSERT_NS(ind); + i = 0; + while (i < count) { + guess = (i + count - 1) >> 1; + + bitem = base + guess * full_item_size; + + switch (ind->mi_single_type) { + case HA_KEYTYPE_LONG_INT: { + register xtInt4 a, b; + + a = XT_GET_DISK_4(value->sv_key); + b = XT_GET_DISK_4(bitem); + r = (a < b) ? -1 : (a == b ? 0 : 1); + break; + } + case HA_KEYTYPE_ULONG_INT: { + register xtWord4 a, b; + + a = XT_GET_DISK_4(value->sv_key); + b = XT_GET_DISK_4(bitem); + r = (a < b) ? -1 : (a == b ? 0 : 1); + break; + } + default: + /* Should not happen: */ + r = 1; + break; + } + if (r == 0) { + if (search_flags & XT_SEARCH_WHOLE_KEY) { + xtRecordID item_record; + xtRowID row_id; + + xt_get_record_ref(bitem + ind->mi_key_size, &item_record, &row_id); + + /* This should not happen because we should never + * try to insert the same record twice into the + * index! + */ + result->sr_duplicate = TRUE; + if (key_record == item_record) { + result->sr_found = TRUE; + result->sr_rec_id = item_record; + result->sr_row_id = row_id; + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, node_ref_size); + result->sr_item.i_item_offset = node_ref_size + guess * full_item_size; + return; + } + if (key_record < item_record) + r = -1; + else + r = 1; + } + else { + result->sr_found = TRUE; + /* -1 causes a search to the beginning of the duplicate list of keys. + * 1 causes a search to just after the key. + */ + if (search_flags & XT_SEARCH_AFTER_KEY) + r = 1; + else + r = -1; + } + } + + if (r < 0) + count = guess; + else + i = guess + 1; + } + } + + bitem = base + i * full_item_size; + xt_get_res_record_ref(bitem + ind->mi_key_size, result); + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, node_ref_size); /* Only valid if this is a node. */ + result->sr_item.i_item_offset = node_ref_size + i * full_item_size; +} + +/* + * We use a special binary search here. It basically assumes that the values + * in the index are not unique. + * + * Even if they are unique, when we search for part of a key, then it is + * effectively the case. + * + * So in the situation where we find duplicates in the index we usually + * want to position ourselves at the beginning of the duplicate list. + * + * Alternatively a search can find the position just after a given key. + * + * To achieve this we make the following modifications: + * - The result of the comparison is always returns 1 or -1. We only stop + * the search early in the case an exact match when inserting (but this + * should not happen anyway). + * - The search never actually fails, but sets 'found' to TRUE if it + * sees the search key in the index. + * + * If the search value exists in the index we know that + * this method will take us to the first occurrence of the key in the + * index (in the case of -1) or to the first value after the + * the search key in the case of 1. + */ +xtPublic void xt_scan_branch_fix(struct XTTable *tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result) +{ + XT_NODE_TEMP; + u_int branch_size; + u_int node_ref_size; + u_int full_item_size; + int search_flags; + xtWord1 *base; + register u_int i; + xtWord1 *bitem; + + branch_size = XT_GET_DISK_2(branch->tb_size_2); + node_ref_size = XT_IS_NODE(branch_size) ? XT_NODE_REF_SIZE : 0; + + result->sr_found = FALSE; + result->sr_duplicate = FALSE; + result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size); + ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2); + + result->sr_item.i_item_size = ind->mi_key_size + XT_RECORD_REF_SIZE; + full_item_size = result->sr_item.i_item_size + node_ref_size; + result->sr_item.i_node_ref_size = node_ref_size; + + search_flags = value->sv_flags; + base = branch->tb_data + node_ref_size; + if (search_flags & XT_SEARCH_FIRST_FLAG) + i = 0; + else if (search_flags & XT_SEARCH_AFTER_LAST_FLAG) + i = (result->sr_item.i_total_size - node_ref_size) / full_item_size; + else { + register u_int guess; + register u_int count; + xtRecordID key_record; + int r; + + key_record = value->sv_rec_id; + count = (result->sr_item.i_total_size - node_ref_size) / full_item_size; + + ASSERT_NS(ind); + i = 0; + while (i < count) { + guess = (i + count - 1) >> 1; + + bitem = base + guess * full_item_size; + + r = myxt_compare_key(ind, search_flags, value->sv_length, value->sv_key, bitem); + + if (r == 0) { + if (search_flags & XT_SEARCH_WHOLE_KEY) { + xtRecordID item_record; + xtRowID row_id; + + xt_get_record_ref(bitem + ind->mi_key_size, &item_record, &row_id); + + /* This should not happen because we should never + * try to insert the same record twice into the + * index! + */ + result->sr_duplicate = TRUE; + if (key_record == item_record) { + result->sr_found = TRUE; + result->sr_rec_id = item_record; + result->sr_row_id = row_id; + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, node_ref_size); + result->sr_item.i_item_offset = node_ref_size + guess * full_item_size; + return; + } + if (key_record < item_record) + r = -1; + else + r = 1; + } + else { + result->sr_found = TRUE; + /* -1 causes a search to the beginning of the duplicate list of keys. + * 1 causes a search to just after the key. + */ + if (search_flags & XT_SEARCH_AFTER_KEY) + r = 1; + else + r = -1; + } + } + + if (r < 0) + count = guess; + else + i = guess + 1; + } + } + + bitem = base + i * full_item_size; + xt_get_res_record_ref(bitem + ind->mi_key_size, result); + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, node_ref_size); /* Only valid if this is a node. */ + result->sr_item.i_item_offset = node_ref_size + i * full_item_size; +} + +xtPublic void xt_scan_branch_fix_simple(struct XTTable *tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result) +{ + XT_NODE_TEMP; + u_int branch_size; + u_int node_ref_size; + u_int full_item_size; + int search_flags; + xtWord1 *base; + register u_int i; + xtWord1 *bitem; + + branch_size = XT_GET_DISK_2(branch->tb_size_2); + node_ref_size = XT_IS_NODE(branch_size) ? XT_NODE_REF_SIZE : 0; + + result->sr_found = FALSE; + result->sr_duplicate = FALSE; + result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size); + ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2); + + result->sr_item.i_item_size = ind->mi_key_size + XT_RECORD_REF_SIZE; + full_item_size = result->sr_item.i_item_size + node_ref_size; + result->sr_item.i_node_ref_size = node_ref_size; + + search_flags = value->sv_flags; + base = branch->tb_data + node_ref_size; + if (search_flags & XT_SEARCH_FIRST_FLAG) + i = 0; + else if (search_flags & XT_SEARCH_AFTER_LAST_FLAG) + i = (result->sr_item.i_total_size - node_ref_size) / full_item_size; + else { + register u_int guess; + register u_int count; + xtRecordID key_record; + int r; + + key_record = value->sv_rec_id; + count = (result->sr_item.i_total_size - node_ref_size) / full_item_size; + + ASSERT_NS(ind); + i = 0; + while (i < count) { + guess = (i + count - 1) >> 1; + + bitem = base + guess * full_item_size; + + r = ind->mi_simple_comp_key(ind, value->sv_length, value->sv_key, bitem); + + if (r == 0) { + if (search_flags & XT_SEARCH_WHOLE_KEY) { + xtRecordID item_record; + xtRowID row_id; + + xt_get_record_ref(bitem + ind->mi_key_size, &item_record, &row_id); + + /* This should not happen because we should never + * try to insert the same record twice into the + * index! + */ + result->sr_duplicate = TRUE; + if (key_record == item_record) { + result->sr_found = TRUE; + result->sr_rec_id = item_record; + result->sr_row_id = row_id; + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, node_ref_size); + result->sr_item.i_item_offset = node_ref_size + guess * full_item_size; + return; + } + if (key_record < item_record) + r = -1; + else + r = 1; + } + else { + result->sr_found = TRUE; + /* -1 causes a search to the beginning of the duplicate list of keys. + * 1 causes a search to just after the key. + */ + if (search_flags & XT_SEARCH_AFTER_KEY) + r = 1; + else + r = -1; + } + } + + if (r < 0) + count = guess; + else + i = guess + 1; + } + } + + bitem = base + i * full_item_size; + xt_get_res_record_ref(bitem + ind->mi_key_size, result); + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, node_ref_size); /* Only valid if this is a node. */ + result->sr_item.i_item_offset = node_ref_size + i * full_item_size; +} + +/* + * Variable length key values are stored as a sorted list. Since each list item has a variable length, we + * must scan the list sequentially in order to find a key. + */ +xtPublic void xt_scan_branch_var(struct XTTable *tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result) +{ + XT_NODE_TEMP; + u_int branch_size; + u_int node_ref_size; + int search_flags; + xtWord1 *base; + xtWord1 *bitem; + u_int ilen; + xtWord1 *bend; + + branch_size = XT_GET_DISK_2(branch->tb_size_2); + node_ref_size = XT_IS_NODE(branch_size) ? XT_NODE_REF_SIZE : 0; + + result->sr_found = FALSE; + result->sr_duplicate = FALSE; + result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size); + ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2); + + result->sr_item.i_node_ref_size = node_ref_size; + + search_flags = value->sv_flags; + base = branch->tb_data + node_ref_size; + bitem = base; + bend = &branch->tb_data[result->sr_item.i_total_size]; + ilen = 0; + if (bitem >= bend) + goto done_ok; + + if (search_flags & XT_SEARCH_FIRST_FLAG) + ilen = myxt_get_key_length(ind, bitem); + else if (search_flags & XT_SEARCH_AFTER_LAST_FLAG) { + bitem = bend; + ilen = 0; + } + else { + xtRecordID key_record; + int r; + + key_record = value->sv_rec_id; + + ASSERT_NS(ind); + while (bitem < bend) { + ilen = myxt_get_key_length(ind, bitem); + r = myxt_compare_key(ind, search_flags, value->sv_length, value->sv_key, bitem); + if (r == 0) { + if (search_flags & XT_SEARCH_WHOLE_KEY) { + xtRecordID item_record; + xtRowID row_id; + + xt_get_record_ref(bitem + ilen, &item_record, &row_id); + + /* This should not happen because we should never + * try to insert the same record twice into the + * index! + */ + result->sr_duplicate = TRUE; + if (key_record == item_record) { + result->sr_found = TRUE; + result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE; + result->sr_rec_id = item_record; + result->sr_row_id = row_id; + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, node_ref_size); + result->sr_item.i_item_offset = bitem - branch->tb_data; + return; + } + if (key_record < item_record) + r = -1; + else + r = 1; + } + else { + result->sr_found = TRUE; + /* -1 causes a search to the beginning of the duplicate list of keys. + * 1 causes a search to just after the key. + */ + if (search_flags & XT_SEARCH_AFTER_KEY) + r = 1; + else + r = -1; + } + } + if (r <= 0) + break; + bitem += ilen + XT_RECORD_REF_SIZE + node_ref_size; + } + } + + done_ok: + result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE; + xt_get_res_record_ref(bitem + ilen, result); + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, node_ref_size); /* Only valid if this is a node. */ + result->sr_item.i_item_offset = bitem - branch->tb_data; +} + +/* Go to the next item in the node. */ +static void idx_next_branch_item(XTTableHPtr tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result) +{ + XT_NODE_TEMP; + xtWord1 *bitem; + u_int ilen; + + result->sr_item.i_item_offset += result->sr_item.i_item_size + result->sr_item.i_node_ref_size; + bitem = branch->tb_data + result->sr_item.i_item_offset; + if (ind->mi_fix_key) + ilen = result->sr_item.i_item_size; + else { + ilen = myxt_get_key_length(ind, bitem) + XT_RECORD_REF_SIZE; + result->sr_item.i_item_size = ilen; + } + xt_get_res_record_ref(bitem + ilen - XT_RECORD_REF_SIZE, result); /* (Only valid if i_item_offset < i_total_size) */ + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, result->sr_item.i_node_ref_size); +} + +xtPublic void xt_prev_branch_item_fix(XTTableHPtr tab __attribute__((unused)), XTIndexPtr ind __attribute__((unused)), XTIdxBranchDPtr branch, register XTIdxResultRec *result) +{ + XT_NODE_TEMP; + ASSERT_NS(result->sr_item.i_item_offset >= result->sr_item.i_item_size + result->sr_item.i_node_ref_size + result->sr_item.i_node_ref_size); + result->sr_item.i_item_offset -= (result->sr_item.i_item_size + result->sr_item.i_node_ref_size); + xt_get_res_record_ref(branch->tb_data + result->sr_item.i_item_offset + result->sr_item.i_item_size - XT_RECORD_REF_SIZE, result); /* (Only valid if i_item_offset < i_total_size) */ + result->sr_branch = IDX_GET_NODE_REF(tab, branch->tb_data + result->sr_item.i_item_offset, result->sr_item.i_node_ref_size); +} + +xtPublic void xt_prev_branch_item_var(XTTableHPtr tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result) +{ + XT_NODE_TEMP; + xtWord1 *bitem; + xtWord1 *bend; + u_int ilen; + + bitem = branch->tb_data + result->sr_item.i_node_ref_size; + bend = &branch->tb_data[result->sr_item.i_item_offset]; + for (;;) { + ilen = myxt_get_key_length(ind, bitem); + if (bitem + ilen + XT_RECORD_REF_SIZE + result->sr_item.i_node_ref_size >= bend) + break; + bitem += ilen + XT_RECORD_REF_SIZE + result->sr_item.i_node_ref_size; + } + + result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE; + xt_get_res_record_ref(bitem + ilen, result); /* (Only valid if i_item_offset < i_total_size) */ + result->sr_branch = IDX_GET_NODE_REF(tab, bitem, result->sr_item.i_node_ref_size); + result->sr_item.i_item_offset = bitem - branch->tb_data; +} + +static void idx_first_branch_item(XTTableHPtr tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultPtr result) +{ + XT_NODE_TEMP; + u_int branch_size; + u_int node_ref_size; + u_int key_data_size; + + branch_size = XT_GET_DISK_2(branch->tb_size_2); + node_ref_size = XT_IS_NODE(branch_size) ? XT_NODE_REF_SIZE : 0; + + result->sr_found = FALSE; + result->sr_duplicate = FALSE; + result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size); + ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2); + + if (ind->mi_fix_key) + key_data_size = ind->mi_key_size; + else { + xtWord1 *bitem; + + bitem = branch->tb_data + node_ref_size; + if (bitem < &branch->tb_data[result->sr_item.i_total_size]) + key_data_size = myxt_get_key_length(ind, bitem); + else + key_data_size = 0; + } + + result->sr_item.i_item_size = key_data_size + XT_RECORD_REF_SIZE; + result->sr_item.i_node_ref_size = node_ref_size; + + xt_get_res_record_ref(branch->tb_data + node_ref_size + key_data_size, result); + result->sr_branch = IDX_GET_NODE_REF(tab, branch->tb_data + node_ref_size, node_ref_size); /* Only valid if this is a node. */ + result->sr_item.i_item_offset = node_ref_size; +} + +/* + * Last means different things for leaf or node! + */ +xtPublic void xt_last_branch_item_fix(XTTableHPtr tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultPtr result) +{ + XT_NODE_TEMP; + u_int branch_size; + u_int node_ref_size; + + branch_size = XT_GET_DISK_2(branch->tb_size_2); + node_ref_size = XT_IS_NODE(branch_size) ? XT_NODE_REF_SIZE : 0; + + result->sr_found = FALSE; + result->sr_duplicate = FALSE; + result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size); + ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2); + + result->sr_item.i_item_size = ind->mi_key_size + XT_RECORD_REF_SIZE; + result->sr_item.i_node_ref_size = node_ref_size; + + if (node_ref_size) { + result->sr_item.i_item_offset = result->sr_item.i_total_size; + result->sr_branch = IDX_GET_NODE_REF(tab, branch->tb_data + result->sr_item.i_item_offset, node_ref_size); + } + else { + if (result->sr_item.i_total_size) { + result->sr_item.i_item_offset = result->sr_item.i_total_size - result->sr_item.i_item_size; + xt_get_res_record_ref(branch->tb_data + result->sr_item.i_item_offset + ind->mi_key_size, result); + } + else + /* Leaf is empty: */ + result->sr_item.i_item_offset = 0; + } +} + +xtPublic void xt_last_branch_item_var(XTTableHPtr tab __attribute__((unused)), XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultPtr result) +{ + XT_NODE_TEMP; + u_int branch_size; + u_int node_ref_size; + + branch_size = XT_GET_DISK_2(branch->tb_size_2); + node_ref_size = XT_IS_NODE(branch_size) ? XT_NODE_REF_SIZE : 0; + + result->sr_found = FALSE; + result->sr_duplicate = FALSE; + result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size); + ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2); + + result->sr_item.i_node_ref_size = node_ref_size; + + if (node_ref_size) { + result->sr_item.i_item_offset = result->sr_item.i_total_size; + result->sr_branch = IDX_GET_NODE_REF(tab, branch->tb_data + result->sr_item.i_item_offset, node_ref_size); + result->sr_item.i_item_size = 0; + } + else { + if (result->sr_item.i_total_size) { + xtWord1 *bitem; + u_int ilen; + xtWord1 *bend; + + bitem = branch->tb_data + node_ref_size;; + bend = &branch->tb_data[result->sr_item.i_total_size]; + ilen = 0; + if (bitem < bend) { + for (;;) { + ilen = myxt_get_key_length(ind, bitem); + if (bitem + ilen + XT_RECORD_REF_SIZE + node_ref_size >= bend) + break; + bitem += ilen + XT_RECORD_REF_SIZE + node_ref_size; + } + } + + result->sr_item.i_item_offset = bitem - branch->tb_data; + xt_get_res_record_ref(bitem + ilen, result); + result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE; + } + else { + /* Leaf is empty: */ + result->sr_item.i_item_offset = 0; + result->sr_item.i_item_size = 0; + } + } +} + +/* + * Remove an item and save to disk. + */ +static xtBool idx_remove_branch_item_right(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID, XTIndReferencePtr iref, register XTIdxItemPtr item) +{ + register XTIdxBranchDPtr branch = iref->ir_branch; + u_int size = item->i_item_size + item->i_node_ref_size; + + /* {HANDLE-COUNT-USAGE} + * This access is safe because we have the right to update + * the page, so no other thread can modify the page. + * + * This means: + * We either have an Xlock on the index, or we have + * an Xlock on the cache block. + */ + if (iref->ir_block->cb_handle_count) { + if (!xt_ind_copy_on_write(iref)) + return FAILED; + } + /* Remove the node reference to the left of the item: */ + memmove(&branch->tb_data[item->i_item_offset], + &branch->tb_data[item->i_item_offset + size], + item->i_total_size - item->i_item_offset - size); + item->i_total_size -= size; + XT_SET_DISK_2(branch->tb_size_2, XT_MAKE_BRANCH_SIZE(item->i_total_size, item->i_node_ref_size)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(address), (int) XT_GET_DISK_2(branch->tb_size_2)); + xt_ind_release(ot, ind, item->i_node_ref_size ? XT_UNLOCK_R_UPDATE : XT_UNLOCK_W_UPDATE, iref); + return OK; +} + +static xtBool idx_remove_branch_item_left(XTOpenTablePtr ot, XTIndexPtr ind, xtIndexNodeID, XTIndReferencePtr iref, register XTIdxItemPtr item) +{ + register XTIdxBranchDPtr branch = iref->ir_branch; + u_int size = item->i_item_size + item->i_node_ref_size; + + if (iref->ir_block->cb_handle_count) { + if (!xt_ind_copy_on_write(iref)) + return FAILED; + } + /* Remove the node reference to the left of the item: */ + memmove(&branch->tb_data[item->i_item_offset - item->i_node_ref_size], + &branch->tb_data[item->i_item_offset + item->i_item_size], + item->i_total_size - item->i_item_offset - item->i_item_size); + item->i_total_size -= size; + XT_SET_DISK_2(branch->tb_size_2, XT_MAKE_BRANCH_SIZE(item->i_total_size, item->i_node_ref_size)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(address), (int) XT_GET_DISK_2(branch->tb_size_2)); + xt_ind_release(ot, ind, item->i_node_ref_size ? XT_UNLOCK_R_UPDATE : XT_UNLOCK_W_UPDATE, iref); + return OK; +} + +static void idx_insert_leaf_item(XTIndexPtr ind __attribute__((unused)), XTIdxBranchDPtr leaf, XTIdxKeyValuePtr value, XTIdxResultPtr result) +{ + xtWord1 *item; + + /* This will ensure we do not overwrite the end of the buffer: */ + ASSERT_NS(value->sv_length <= XT_INDEX_MAX_KEY_SIZE); + memmove(&leaf->tb_data[result->sr_item.i_item_offset + value->sv_length + XT_RECORD_REF_SIZE], + &leaf->tb_data[result->sr_item.i_item_offset], + result->sr_item.i_total_size - result->sr_item.i_item_offset); + item = &leaf->tb_data[result->sr_item.i_item_offset]; + memcpy(item, value->sv_key, value->sv_length); + xt_set_val_record_ref(item + value->sv_length, value); + result->sr_item.i_total_size += value->sv_length + XT_RECORD_REF_SIZE; + XT_SET_DISK_2(leaf->tb_size_2, XT_MAKE_LEAF_SIZE(result->sr_item.i_total_size)); +} + +static void idx_insert_node_item(XTTableHPtr tab __attribute__((unused)), XTIndexPtr ind __attribute__((unused)), XTIdxBranchDPtr leaf, XTIdxKeyValuePtr value, XTIdxResultPtr result, xtIndexNodeID branch) +{ + xtWord1 *item; + + /* This will ensure we do not overwrite the end of the buffer: */ + ASSERT_NS(value->sv_length <= XT_INDEX_MAX_KEY_SIZE); + memmove(&leaf->tb_data[result->sr_item.i_item_offset + value->sv_length + XT_RECORD_REF_SIZE + result->sr_item.i_node_ref_size], + &leaf->tb_data[result->sr_item.i_item_offset], + result->sr_item.i_total_size - result->sr_item.i_item_offset); + item = &leaf->tb_data[result->sr_item.i_item_offset]; + memcpy(item, value->sv_key, value->sv_length); + xt_set_val_record_ref(item + value->sv_length, value); + XT_SET_NODE_REF(tab, item + value->sv_length + XT_RECORD_REF_SIZE, branch); + result->sr_item.i_total_size += value->sv_length + XT_RECORD_REF_SIZE + result->sr_item.i_node_ref_size; + XT_SET_DISK_2(leaf->tb_size_2, XT_MAKE_NODE_SIZE(result->sr_item.i_total_size)); +} + +static void idx_get_middle_branch_item(XTIndexPtr ind, XTIdxBranchDPtr branch, XTIdxKeyValuePtr value, XTIdxResultPtr result) +{ + xtWord1 *bitem; + + if (ind->mi_fix_key) { + u_int full_item_size = result->sr_item.i_item_size + result->sr_item.i_node_ref_size; + + result->sr_item.i_item_offset = ((result->sr_item.i_total_size - result->sr_item.i_node_ref_size) + / full_item_size / 2 * full_item_size) + result->sr_item.i_node_ref_size; + + bitem = &branch->tb_data[result->sr_item.i_item_offset]; + value->sv_flags = XT_SEARCH_WHOLE_KEY; + value->sv_length = result->sr_item.i_item_size - XT_RECORD_REF_SIZE; + xt_get_record_ref(bitem + value->sv_length, &value->sv_rec_id, &value->sv_row_id); + memcpy(value->sv_key, bitem, value->sv_length); + } + else { + u_int node_ref_size; + u_int ilen; + xtWord1 *bend; + + node_ref_size = result->sr_item.i_node_ref_size; + bitem = branch->tb_data + node_ref_size;; + bend = &branch->tb_data[(result->sr_item.i_total_size - node_ref_size) / 2 + node_ref_size]; + ilen = 0; + if (bitem < bend) { + for (;;) { + ilen = myxt_get_key_length(ind, bitem); + if (bitem + ilen + XT_RECORD_REF_SIZE + node_ref_size >= bend) + break; + bitem += ilen + XT_RECORD_REF_SIZE + node_ref_size; + } + } + + result->sr_item.i_item_offset = bitem - branch->tb_data; + result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE; + + value->sv_flags = XT_SEARCH_WHOLE_KEY; + value->sv_length = ilen; + xt_get_record_ref(bitem + ilen, &value->sv_rec_id, &value->sv_row_id); + memcpy(value->sv_key, bitem, value->sv_length); + } +} + +static size_t idx_write_branch_item(XTIndexPtr ind __attribute__((unused)), xtWord1 *item, XTIdxKeyValuePtr value) +{ + memcpy(item, value->sv_key, value->sv_length); + xt_set_val_record_ref(item + value->sv_length, value); + return value->sv_length + XT_RECORD_REF_SIZE; +} + +static xtBool idx_replace_node_key(XTOpenTablePtr ot, XTIndexPtr ind, IdxStackItemPtr item, IdxBranchStackPtr stack, u_int item_size, xtWord1 *item_buf) +{ + XTIndReferenceRec iref; + xtIndexNodeID new_branch; + XTIdxResultRec result; + xtIndexNodeID current = item->i_branch; + u_int new_size; + XTIdxBranchDPtr new_branch_ptr; + XTIdxKeyValueRec key_value; + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE]; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + if (!xt_ind_fetch(ot, current, XT_LOCK_WRITE, &iref)) + return FAILED; + if (iref.ir_block->cb_handle_count) { + if (!xt_ind_copy_on_write(&iref)) + goto failed_1; + } + memmove(&iref.ir_branch->tb_data[item->i_pos.i_item_offset + item_size], + &iref.ir_branch->tb_data[item->i_pos.i_item_offset + item->i_pos.i_item_size], + item->i_pos.i_total_size - item->i_pos.i_item_offset - item->i_pos.i_item_size); + memcpy(&iref.ir_branch->tb_data[item->i_pos.i_item_offset], + item_buf, item_size); + item->i_pos.i_total_size = item->i_pos.i_total_size + item_size - item->i_pos.i_item_size; + XT_SET_DISK_2(iref.ir_branch->tb_size_2, XT_MAKE_NODE_SIZE(item->i_pos.i_total_size)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(iref.ir_branch->tb_size_2)); + + if (item->i_pos.i_total_size <= XT_INDEX_PAGE_DATA_SIZE) + return xt_ind_release(ot, ind, XT_UNLOCK_W_UPDATE, &iref); + + /* The node has overflowed!! */ + result.sr_item = item->i_pos; + + /* Adjust the stack (we want the parents of the delete node): */ + for (;;) { + if (idx_pop(stack) == item) + break; + } + + /* We assume that value can be overwritten (which is the case) */ + key_value.sv_flags = XT_SEARCH_WHOLE_KEY; + key_value.sv_key = key_buf; + idx_get_middle_branch_item(ind, iref.ir_branch, &key_value, &result); + + if (!idx_new_branch(ot, ind, &new_branch)) + goto failed_1; + + /* Split the node: */ + new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size; + // TODO: Are 2 buffers now required? + new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE]; + memmove(new_branch_ptr->tb_data, &iref.ir_branch->tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size], new_size); + + XT_SET_DISK_2(new_branch_ptr->tb_size_2, XT_MAKE_NODE_SIZE(new_size)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(new_branch), (int) XT_GET_DISK_2(new_branch_ptr->tb_size_2)); + if (!xt_ind_write(ot, ind, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr)) + goto failed_2; + + /* Change the size of the old branch: */ + XT_SET_DISK_2(iref.ir_branch->tb_size_2, XT_MAKE_NODE_SIZE(result.sr_item.i_item_offset)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(iref.ir_branch->tb_size_2)); + + xt_ind_release(ot, ind, XT_UNLOCK_W_UPDATE, &iref); + + /* Insert the new branch into the parent node, using the new middle key value: */ + if (!idx_insert_node(ot, ind, stack, &key_value, new_branch)) { + /* + * TODO: Mark the index as corrupt. + * This should not fail because everything has been + * preallocated. + * However, if it does fail the index + * will be corrupt. + * I could modify and release the branch above, + * after this point. + * But that would mean holding the lock longer, + * and also may not help because idx_insert_node() + * is recursive. + */ + idx_free_branch(ot, ind, new_branch); + return FAILED; + } + + return OK; + + failed_2: + idx_free_branch(ot, ind, new_branch); + + failed_1: + xt_ind_release(ot, ind, XT_UNLOCK_WRITE, &iref); + + return FAILED; +} + +/*ot_ind_wbuf + * ----------------------------------------------------------------------- + * Standard b-tree insert + */ + +/* + * Insert the given branch into the node on the top of the stack. If the stack + * is empty we need to add a new root. + */ +static xtBool idx_insert_node(XTOpenTablePtr ot, XTIndexPtr ind, IdxBranchStackPtr stack, XTIdxKeyValuePtr key_value, xtIndexNodeID branch) +{ + IdxStackItemPtr stack_item; + xtIndexNodeID new_branch; + size_t size; + xtIndexNodeID current; + XTIndReferenceRec iref; + XTIdxResultRec result; + u_int new_size; + XTIdxBranchDPtr new_branch_ptr; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + /* Insert a new branch (key, data)... */ + if (!(stack_item = idx_pop(stack))) { + xtWord1 *ditem; + + /* New root */ + if (!idx_new_branch(ot, ind, &new_branch)) + goto failed; + + ditem = ot->ot_ind_wbuf.tb_data; + XT_SET_NODE_REF(ot->ot_table, ditem, ind->mi_root); + ditem += XT_NODE_REF_SIZE; + ditem += idx_write_branch_item(ind, ditem, key_value); + XT_SET_NODE_REF(ot->ot_table, ditem, branch); + ditem += XT_NODE_REF_SIZE; + size = ditem - ot->ot_ind_wbuf.tb_data; + XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_NODE_SIZE(size)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(new_branch), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)); + if (!xt_ind_write(ot, ind, new_branch, offsetof(XTIdxBranchDRec, tb_data) + size, (xtWord1 *) &ot->ot_ind_wbuf)) + goto failed_2; + ind->mi_root = new_branch; + goto done_ok; + } + + current = stack_item->i_branch; + /* This read does not count (towards ot_ind_reads), because we are only + * counting each loaded page once. We assume that the page is in + * cache, and will remain in cache when we read again below for the + * purpose of update. + */ + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + goto failed; + ASSERT_NS(XT_IS_NODE(XT_GET_DISK_2(iref.ir_branch->tb_size_2))); + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, key_value, &result); + + if (result.sr_item.i_total_size + key_value->sv_length + XT_RECORD_REF_SIZE + result.sr_item.i_node_ref_size <= XT_INDEX_PAGE_DATA_SIZE) { + if (iref.ir_block->cb_handle_count) { + if (!xt_ind_copy_on_write(&iref)) + goto failed_1; + } + idx_insert_node_item(ot->ot_table, ind, iref.ir_branch, key_value, &result, branch); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)); + ASSERT_NS(result.sr_item.i_total_size <= XT_INDEX_PAGE_DATA_SIZE); + xt_ind_release(ot, ind, XT_UNLOCK_R_UPDATE, &iref); + goto done_ok; + } + + memcpy(&ot->ot_ind_wbuf, iref.ir_branch, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_total_size); + idx_insert_node_item(ot->ot_table, ind, &ot->ot_ind_wbuf, key_value, &result, branch); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)); + ASSERT_NS(result.sr_item.i_total_size > XT_INDEX_PAGE_DATA_SIZE); + + /* We assume that value can be overwritten (which is the case) */ + idx_get_middle_branch_item(ind, &ot->ot_ind_wbuf, key_value, &result); + + if (!idx_new_branch(ot, ind, &new_branch)) + goto failed_1; + + /* Split the node: */ + new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size; + new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE]; + memmove(new_branch_ptr->tb_data, &ot->ot_ind_wbuf.tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size], new_size); + + XT_SET_DISK_2(new_branch_ptr->tb_size_2, XT_MAKE_NODE_SIZE(new_size)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(new_branch), (int) XT_GET_DISK_2(new_branch_ptr->tb_size_2)); + if (!xt_ind_write(ot, ind, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr)) + goto failed_2; + + /* Change the size of the old branch: */ + XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_NODE_SIZE(result.sr_item.i_item_offset)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)); + if (iref.ir_block->cb_handle_count) { + if (!xt_ind_copy_on_write(&iref)) + goto failed_2; + } + memcpy(iref.ir_branch, &ot->ot_ind_wbuf, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset); + xt_ind_release(ot, ind, XT_UNLOCK_R_UPDATE, &iref); + + /* Insert the new branch into the parent node, using the new middle key value: */ + if (!idx_insert_node(ot, ind, stack, key_value, new_branch)) { + // Index may be inconsistant now... + idx_free_branch(ot, ind, new_branch); + goto failed; + } + + done_ok: + return OK; + + failed_2: + idx_free_branch(ot, ind, new_branch); + + failed_1: + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + + failed: + return FAILED; +} + +static xtBool idx_out_of_memory_failure(XTOpenTablePtr ot) +{ +#ifdef XT_TRACK_INDEX_UPDATES + /* If the index has been changed when we run out of memory, we + * will corrupt the index! + */ + ASSERT_NS(ot->ot_ind_changed == 0); +#endif + if (ot->ot_thread->t_exception.e_xt_err == XT_ERR_NO_INDEX_CACHE) { + /* Flush index and retry! */ + xt_clear_exception(ot->ot_thread); + if (!xt_flush_indices(ot, NULL, FALSE)) + return FAILED; + return TRUE; + } + return FALSE; +} + +/* + * Check all the duplicate variation in an index. + * If one of them is visible, then we have a duplicate key + * error. + * + * GOTCHA: This routine must use the write index buffer! + */ +static xtBool idx_check_duplicates(XTOpenTablePtr ot, XTIndexPtr ind, XTIdxKeyValuePtr key_value) +{ + IdxBranchStackRec stack; + xtIndexNodeID current; + XTIndReferenceRec iref; + XTIdxResultRec result; + xtBool on_key = FALSE; + xtXactID xn_id; + int save_flags; + XTXactWaitRec xw; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + retry: + idx_newstack(&stack); + + if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) + return OK; + + save_flags = key_value->sv_flags; + key_value->sv_flags = 0; + + while (XT_NODE_ID(current)) { + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) { + key_value->sv_flags = save_flags; + return FAILED; + } + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, key_value, &result); + if (result.sr_found) + /* If we have found the key in a node: */ + on_key = TRUE; + if (!result.sr_item.i_node_ref_size) + break; + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) { + key_value->sv_flags = save_flags; + return FAILED; + } + current = result.sr_branch; + } + + key_value->sv_flags = save_flags; + + if (!on_key) { + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + return OK; + } + + for (;;) { + if (result.sr_item.i_item_offset == result.sr_item.i_total_size) { + IdxStackItemPtr node; + + /* We are at the end of a leaf node. + * Go up the stack to find the start position of the next key. + * If we find none, then we are the end of the index. + */ + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + while ((node = idx_pop(&stack))) { + if (node->i_pos.i_item_offset < node->i_pos.i_total_size) { + current = node->i_branch; + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + return FAILED; + xt_get_res_record_ref(&iref.ir_branch->tb_data[node->i_pos.i_item_offset + node->i_pos.i_item_size - XT_RECORD_REF_SIZE], &result); + result.sr_item = node->i_pos; + goto check_value; + } + } + break; + } + + check_value: + /* Quit the loop if the key is no longer matched! */ + if (myxt_compare_key(ind, 0, key_value->sv_length, key_value->sv_key, &iref.ir_branch->tb_data[result.sr_item.i_item_offset]) != 0) { + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + break; + } + + switch (xt_tab_maybe_committed(ot, result.sr_rec_id, &xn_id, NULL, NULL)) { + case XT_MAYBE: + /* Record is not committed, wait for the transaction. */ + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + XT_INDEX_UNLOCK(ind, ot); + xw.xw_xn_id = xn_id; + if (!xt_xn_wait_for_xact(ot->ot_thread, &xw, NULL)) { + XT_INDEX_WRITE_LOCK(ind, ot); + return FAILED; + } + XT_INDEX_WRITE_LOCK(ind, ot); + goto retry; + case XT_ERR: + /* Error while reading... */ + goto failed; + case TRUE: + /* Record is committed or belongs to me, duplicate key: */ + XT_DEBUG_TRACE(("DUPLICATE KEY tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_xn_id, (int) result.sr_rec_id)); + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_DUPLICATE_KEY); + goto failed; + case FALSE: + /* Record is deleted or rolled-back: */ + break; + } + + idx_next_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + + if (result.sr_item.i_node_ref_size) { + /* Go down to the bottom: */ + while (XT_NODE_ID(current)) { + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) + return FAILED; + current = result.sr_branch; + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + return FAILED; + idx_first_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + if (!result.sr_item.i_node_ref_size) + break; + } + } + } + + return OK; + + failed: + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + return FAILED; +} + +/* + * Insert a value into the given index. Return FALSE if an error occurs. + */ +xtPublic xtBool xt_idx_insert(XTOpenTablePtr ot, XTIndexPtr ind, xtRowID row_id, xtRecordID rec_id, xtWord1 *rec_buf, xtWord1 *bef_buf, xtBool allow_dups) +{ + XTIdxKeyValueRec key_value; + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE]; + IdxBranchStackRec stack; + xtIndexNodeID current; + XTIndReferenceRec iref; + xtIndexNodeID new_branch; + XTIdxBranchDPtr new_branch_ptr; + size_t size; + XTIdxResultRec result; + size_t new_size; + xtBool check_for_dups = ind->mi_flags & (HA_UNIQUE_CHECK | HA_NOSAME) && !allow_dups; + xtBool lock_structure = FALSE; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif +#ifdef CHECK_AND_PRINT + //idx_check_index(ot, ind, TRUE); +#endif + + retry_after_oom: +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_changed = 0; +#endif + key_value.sv_flags = XT_SEARCH_WHOLE_KEY; + key_value.sv_rec_id = rec_id; + key_value.sv_row_id = row_id; /* Should always be zero on insert (will be update by sweeper later). + * Non-zero only during recovery, assuming that sweeper will process such records right after recovery. + */ + key_value.sv_key = key_buf; + key_value.sv_length = myxt_create_key_from_row(ind, key_buf, rec_buf, &check_for_dups); + + if (bef_buf && check_for_dups) { + /* If we have a before image, and we are required to check for duplicates. + * then compare the before image key with the after image key. + */ + xtWord1 bef_key_buf[XT_INDEX_MAX_KEY_SIZE]; + u_int len; + xtBool has_no_null = TRUE; + + len = myxt_create_key_from_row(ind, bef_key_buf, bef_buf, &has_no_null); + if (has_no_null) { + /* If the before key has no null values, then compare with the after key value. + * We only have to check for duplicates if the key has changed! + */ + check_for_dups = myxt_compare_key(ind, 0, len, bef_key_buf, key_buf) != 0; + } + } + + /* The index appears to have no root: */ + if (!XT_NODE_ID(ind->mi_root)) + lock_structure = TRUE; + + lock_and_retry: + idx_newstack(&stack); + + /* A write lock is only required if we are going to change the + * strcuture of the index! + */ + if (lock_structure) + XT_INDEX_WRITE_LOCK(ind, ot); + else + XT_INDEX_READ_LOCK(ind, ot); + + retry: + if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) { + /* Index is empty, create a new one: */ + ASSERT_NS(lock_structure); + if (!xt_ind_reserve(ot, 1, NULL)) + goto failed; + if (!idx_new_branch(ot, ind, &new_branch)) + goto failed; + size = idx_write_branch_item(ind, ot->ot_ind_wbuf.tb_data, &key_value); + XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_LEAF_SIZE(size)); + IDX_TRACE("%d-> %x\n", (int) new_branch, (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)); + if (!xt_ind_write(ot, ind, new_branch, offsetof(XTIdxBranchDRec, tb_data) + size, (xtWord1 *) &ot->ot_ind_wbuf)) + goto failed_2; + ind->mi_root = new_branch; + goto done_ok; + } + + while (XT_NODE_ID(current)) { + if (!xt_ind_fetch(ot, current, XT_XLOCK_LEAF, &iref)) + goto failed; + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, &key_value, &result); + if (result.sr_duplicate) { + if (check_for_dups) { + /* Duplicates are not allowed, at least one has been + * found... + */ + + /* Leaf nodes (i_node_ref_size == 0) are write locked, + * non-leaf nodes are read locked. + */ + xt_ind_release(ot, ind, result.sr_item.i_node_ref_size ? XT_UNLOCK_READ : XT_UNLOCK_WRITE, &iref); + + if (!idx_check_duplicates(ot, ind, &key_value)) + goto failed; + /* We have checked all the "duplicate" variations. None of them are + * relevant. So this will cause a correct insert. + */ + check_for_dups = FALSE; + idx_newstack(&stack); + goto retry; + } + } + if (result.sr_found) { + /* Node found, can happen during recovery of indexes! */ + XTPageUnlockType utype; + + if (!result.sr_row_id && row_id) { + /* {INDEX-RECOV_ROWID} Set the row-id + * during recovery, even if the index entry + * is not committed. + * It will be removed later by the sweeper. + */ + size_t offset; + xtWord1 *data; + + offset = + /* This is the offset of the reference in the item we found: */ + result.sr_item.i_item_offset + result.sr_item.i_item_size - XT_RECORD_REF_SIZE + + /* This is the offset of the row id in the reference: */ + 4; + data = &iref.ir_branch->tb_data[offset]; + + /* This update does not change the structure of page, so we do it without + * copying the page before we write. + */ + XT_SET_DISK_4(data, row_id); + utype = result.sr_item.i_node_ref_size ? XT_UNLOCK_R_UPDATE : XT_UNLOCK_W_UPDATE; + } + else + utype = result.sr_item.i_node_ref_size ? XT_UNLOCK_READ : XT_UNLOCK_WRITE; + xt_ind_release(ot, ind, utype, &iref); + goto done_ok; + } + /* Stop when we get to a leaf: */ + if (!result.sr_item.i_node_ref_size) + break; + xt_ind_release(ot, ind, result.sr_item.i_node_ref_size ? XT_UNLOCK_READ : XT_UNLOCK_WRITE, &iref); + if (!idx_push(&stack, current, NULL)) + goto failed; + current = result.sr_branch; + } + ASSERT_NS(XT_NODE_ID(current)); + + /* Must be a leaf!: */ + ASSERT_NS(!result.sr_item.i_node_ref_size); + + if (result.sr_item.i_total_size + key_value.sv_length + XT_RECORD_REF_SIZE <= XT_INDEX_PAGE_DATA_SIZE) { + if (iref.ir_block->cb_handle_count) { + if (!xt_ind_copy_on_write(&iref)) + goto failed_1; + } + idx_insert_leaf_item(ind, iref.ir_branch, &key_value, &result); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)); + ASSERT_NS(result.sr_item.i_total_size <= XT_INDEX_PAGE_DATA_SIZE); + xt_ind_release(ot, ind, XT_UNLOCK_W_UPDATE, &iref); + goto done_ok; + } + + /* Key does not fit. Must split the node. + * Make sure we have a structural lock: + */ + if (!lock_structure) { + xt_ind_release(ot, ind, XT_UNLOCK_WRITE, &iref); + XT_INDEX_UNLOCK(ind, ot); + lock_structure = TRUE; + goto lock_and_retry; + } + + memcpy(&ot->ot_ind_wbuf, iref.ir_branch, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_total_size); + idx_insert_leaf_item(ind, &ot->ot_ind_wbuf, &key_value, &result); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)); + ASSERT_NS(result.sr_item.i_total_size > XT_INDEX_PAGE_DATA_SIZE); + + /* This is the number of potential writes. In other words, the total number + * of blocks that may be accessed. + * + * Note that this assume if a block is read and written soon after that the block + * will not be freed in-between (a safe assumption?) + */ + if (!xt_ind_reserve(ot, stack.s_top * 2 + 3, iref.ir_branch)) + goto failed_1; + + /* Key does not fit, must split... */ + idx_get_middle_branch_item(ind, &ot->ot_ind_wbuf, &key_value, &result); + + if (!idx_new_branch(ot, ind, &new_branch)) + goto failed_1; + + /* Copy and write the rest of the data to the new node: */ + new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size; + new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE]; + memmove(new_branch_ptr->tb_data, &ot->ot_ind_wbuf.tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size], new_size); + + XT_SET_DISK_2(new_branch_ptr->tb_size_2, XT_MAKE_LEAF_SIZE(new_size)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(new_branch), (int) XT_GET_DISK_2(new_branch_ptr->tb_size_2)); + if (!xt_ind_write(ot, ind, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr)) + goto failed_2; + + /* Modify the first node: */ + XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_LEAF_SIZE(result.sr_item.i_item_offset)); + IDX_TRACE("%d-> %x\n", (int) XT_NODE_ID(current), (int) XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)); + + if (iref.ir_block->cb_handle_count) { + if (!xt_ind_copy_on_write(&iref)) + goto failed_2; + } + memcpy(iref.ir_branch, &ot->ot_ind_wbuf, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset); + xt_ind_release(ot, ind, XT_UNLOCK_W_UPDATE, &iref); + + /* Insert the new branch into the parent node, using the new middle key value: */ + if (!idx_insert_node(ot, ind, &stack, &key_value, new_branch)) { + // Index may be inconsistant now... + idx_free_branch(ot, ind, new_branch); + goto failed; + } + +#ifdef XT_TRACK_INDEX_UPDATES + ASSERT_NS(ot->ot_ind_reserved >= ot->ot_ind_reads); +#endif + + done_ok: + XT_INDEX_UNLOCK(ind, ot); + +#ifdef DEBUG + //printf("INSERT OK\n"); + //idx_check_index(ot, ind, TRUE); +#endif + xt_ind_unreserve(ot); + return OK; + + failed_2: + idx_free_branch(ot, ind, new_branch); + + failed_1: + xt_ind_release(ot, ind, XT_UNLOCK_WRITE, &iref); + + failed: + XT_INDEX_UNLOCK(ind, ot); + if (idx_out_of_memory_failure(ot)) + goto retry_after_oom; + +#ifdef DEBUG + //printf("INSERT FAILED\n"); + //idx_check_index(ot, ind, TRUE); +#endif + xt_ind_unreserve(ot); + return FAILED; +} + +static xtBool idx_delete(XTOpenTablePtr ot, XTIndexPtr ind, XTIdxKeyValuePtr key_value) +{ + IdxBranchStackRec stack; + xtIndexNodeID current; + XTIndReferenceRec iref; + XTIdxResultRec result; + IdxStackItemPtr delete_node = NULL; + IdxStackItemPtr current_top = NULL; + xtBool lock_structure = FALSE; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + /* The index appears to have no root: */ + if (!XT_NODE_ID(ind->mi_root)) + lock_structure = TRUE; + + lock_and_retry: + idx_newstack(&stack); + + if (lock_structure) + XT_INDEX_WRITE_LOCK(ind, ot); + else + XT_INDEX_READ_LOCK(ind, ot); + + if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) + goto done_ok; + + while (XT_NODE_ID(current)) { + if (!xt_ind_fetch(ot, current, XT_XLOCK_LEAF, &iref)) + goto failed; + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, key_value, &result); + if (!result.sr_item.i_node_ref_size) { + /* A leaf... */ + if (result.sr_found) { + if (!idx_remove_branch_item_right(ot, ind, current, &iref, &result.sr_item)) + goto failed; + } + else + xt_ind_release(ot, ind, XT_UNLOCK_WRITE, &iref); + goto done_ok; + } + if (!idx_push(&stack, current, &result.sr_item)) { + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + goto failed; + } + if (result.sr_found) + /* If we have found the key in a node: */ + break; + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + current = result.sr_branch; + } + + /* Must be a non-leaf!: */ + ASSERT_NS(result.sr_item.i_node_ref_size); + + /* We will have to remove the key from a non-leaf node, + * which means we are changing the structure of the index. + * Make sure we have a structural lock: + */ + if (!lock_structure) { + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + XT_INDEX_UNLOCK(ind, ot); + lock_structure = TRUE; + goto lock_and_retry; + } + + /* This is the item we will have to replace: */ + delete_node = idx_top(&stack); + + /* Follow the branch after this item: */ + idx_next_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + ASSERT_NS(XT_NODE_ID(current)); + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + + /* Go down the left-hand side until we reach a leaf: */ + while (XT_NODE_ID(current)) { + current = result.sr_branch; + if (!xt_ind_fetch(ot, current, XT_XLOCK_LEAF, &iref)) + goto failed; + idx_first_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + if (!result.sr_item.i_node_ref_size) + break; + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) + goto failed; + } + + ASSERT_NS(XT_NODE_ID(current)); + ASSERT_NS(!result.sr_item.i_node_ref_size); + + if (!xt_ind_reserve(ot, stack.s_top + 2, iref.ir_branch)) { + xt_ind_release(ot, ind, XT_UNLOCK_WRITE, &iref); + goto failed; + } + + /* Crawl back up the stack trace, looking for a key + * that can be used to replace the deleted key. + * + * Any empty nodes on the way up can be removed! + */ + if (result.sr_item.i_total_size > 0) { + /* There is a key in the leaf, extract it, and put it in the node: */ + memcpy(key_value->sv_key, &iref.ir_branch->tb_data[result.sr_item.i_item_offset], result.sr_item.i_item_size); + /* This call also frees the iref.ir_branch page! */ + if (!idx_remove_branch_item_right(ot, ind, current, &iref, &result.sr_item)) + goto failed; + if (!idx_replace_node_key(ot, ind, delete_node, &stack, result.sr_item.i_item_size, key_value->sv_key)) + goto failed; + goto done_ok_2; + } + + xt_ind_release(ot, ind, XT_UNLOCK_WRITE, &iref); + + for (;;) { + /* The current node/leaf is empty, remove it: */ + idx_free_branch(ot, ind, current); + + current_top = idx_pop(&stack); + current = current_top->i_branch; + if (!xt_ind_fetch(ot, current, XT_XLOCK_LEAF, &iref)) + goto failed; + + if (current_top == delete_node) { + /* All children have been removed. Delete the key and done: */ + if (!idx_remove_branch_item_right(ot, ind, current, &iref, ¤t_top->i_pos)) + goto failed; + goto done_ok_2; + } + + if (current_top->i_pos.i_total_size > current_top->i_pos.i_node_ref_size) { + /* Save the key: */ + memcpy(key_value->sv_key, &iref.ir_branch->tb_data[current_top->i_pos.i_item_offset], current_top->i_pos.i_item_size); + /* This function also frees the cache page: */ + if (!idx_remove_branch_item_left(ot, ind, current, &iref, ¤t_top->i_pos)) + goto failed; + if (!idx_replace_node_key(ot, ind, delete_node, &stack, current_top->i_pos.i_item_size, key_value->sv_key)) + goto failed; + goto done_ok_2; + } + xt_ind_release(ot, ind, current_top->i_pos.i_node_ref_size ? XT_UNLOCK_READ : XT_UNLOCK_WRITE, &iref); + } + + + done_ok_2: +#ifdef XT_TRACK_INDEX_UPDATES + ASSERT_NS(ot->ot_ind_reserved >= ot->ot_ind_reads); +#endif + + done_ok: + XT_INDEX_UNLOCK(ind, ot); + +#ifdef DEBUG + //printf("DELETE OK\n"); + //idx_check_index(ot, ind, TRUE); +#endif + xt_ind_unreserve(ot); + return OK; + + failed: + XT_INDEX_UNLOCK(ind, ot); + xt_ind_unreserve(ot); + return FAILED; +} + +xtPublic xtBool xt_idx_delete(XTOpenTablePtr ot, XTIndexPtr ind, xtRecordID rec_id, xtWord1 *rec_buf) +{ + XTIdxKeyValueRec key_value; + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE + XT_MAX_RECORD_REF_SIZE]; + + retry_after_oom: +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_changed = 0; +#endif + + key_value.sv_flags = XT_SEARCH_WHOLE_KEY; + key_value.sv_rec_id = rec_id; + key_value.sv_row_id = 0; + key_value.sv_key = key_buf; + key_value.sv_length = myxt_create_key_from_row(ind, key_buf, rec_buf, NULL); + + if (!idx_delete(ot, ind, &key_value)) { + if (idx_out_of_memory_failure(ot)) + goto retry_after_oom; + return FAILED; + } + return OK; +} + +xtPublic xtBool xt_idx_update_row_id(XTOpenTablePtr ot, XTIndexPtr ind, xtRecordID rec_id, xtRowID row_id, xtWord1 *rec_buf) +{ + xtIndexNodeID current; + XTIndReferenceRec iref; + XTIdxResultRec result; + XTIdxKeyValueRec key_value; + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE + XT_MAX_RECORD_REF_SIZE]; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif +#ifdef CHECK_AND_PRINT + idx_check_index(ot, ind, TRUE); +#endif + retry_after_oom: +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_changed = 0; +#endif + key_value.sv_flags = XT_SEARCH_WHOLE_KEY; + key_value.sv_rec_id = rec_id; + key_value.sv_row_id = 0; + key_value.sv_key = key_buf; + key_value.sv_length = myxt_create_key_from_row(ind, key_buf, rec_buf, NULL); + + /* NOTE: Only a read lock is required for this!! + * + * 09.05.2008 - This has changed because the dirty list now + * hangs on the index. And the dirty list may be updated + * by any change of the index. + * However, the advantage is that I should be able to read + * lock in the first phase of the flush. + * + * 18.02.2009 - This has changed again. + * I am now using a read lock, because this update does not + * require a structural change. In fact, it does not even + * need a WRITE LOCK on the page affected, because there + * is only ONE thread that can do this (the sweeper). + * + * This has the advantage that the sweeper (which uses this + * function, causes less conflicts. + * + * However, it does mean that the dirty list must be otherwise + * protected (which it now is be a spin lock - mi_dirty_lock). + * + * It also has the dissadvantage that I am going to have to + * take an xlock in the first phase of the flush. + */ + XT_INDEX_READ_LOCK(ind, ot); + + if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) + goto done_ok; + + while (XT_NODE_ID(current)) { + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + goto failed; + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, &key_value, &result); + if (result.sr_found || !result.sr_item.i_node_ref_size) + break; + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + current = result.sr_branch; + } + + if (result.sr_found) { + size_t offset; + xtWord1 *data; + + offset = + /* This is the offset of the reference in the item we found: */ + result.sr_item.i_item_offset + result.sr_item.i_item_size - XT_RECORD_REF_SIZE + + /* This is the offset of the row id in the reference: */ + 4; + data = &iref.ir_branch->tb_data[offset]; + + /* This update does not change the structure of page, so we do it without + * copying the page before we write. + * + * TODO: Check that concurrent reads can handle this! + * assuming the write is not atomic. + */ + XT_SET_DISK_4(data, row_id); + xt_ind_release(ot, ind, XT_UNLOCK_R_UPDATE, &iref); + } + else + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + + done_ok: + XT_INDEX_UNLOCK(ind, ot); + +#ifdef DEBUG + //idx_check_index(ot, ind, TRUE); + //idx_check_on_key(ot); +#endif + return OK; + + failed: + XT_INDEX_UNLOCK(ind, ot); + if (idx_out_of_memory_failure(ot)) + goto retry_after_oom; + return FAILED; +} + +xtPublic void xt_idx_prep_key(XTIndexPtr ind, register XTIdxSearchKeyPtr search_key, int flags, xtWord1 *in_key_buf, size_t in_key_length) +{ + search_key->sk_key_value.sv_flags = flags; + search_key->sk_key_value.sv_rec_id = 0; + search_key->sk_key_value.sv_row_id = 0; + search_key->sk_key_value.sv_key = search_key->sk_key_buf; + search_key->sk_key_value.sv_length = myxt_create_key_from_key(ind, search_key->sk_key_buf, in_key_buf, in_key_length); + search_key->sk_on_key = FALSE; +} + +xtPublic xtBool xt_idx_research(XTOpenTablePtr ot, XTIndexPtr ind) +{ + XTIdxSearchKeyRec search_key; + + xt_ind_lock_handle(ot->ot_ind_rhandle); + search_key.sk_key_value.sv_flags = XT_SEARCH_WHOLE_KEY; + xt_get_record_ref(&ot->ot_ind_rhandle->ih_branch->tb_data[ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE], + &search_key.sk_key_value.sv_rec_id, &search_key.sk_key_value.sv_row_id); + search_key.sk_key_value.sv_key = search_key.sk_key_buf; + search_key.sk_key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE; + search_key.sk_on_key = FALSE; + memcpy(search_key.sk_key_buf, &ot->ot_ind_rhandle->ih_branch->tb_data[ot->ot_ind_state.i_item_offset], search_key.sk_key_value.sv_length); + xt_ind_unlock_handle(ot->ot_ind_rhandle); + return xt_idx_search(ot, ind, &search_key); +} + +/* + * Search for a given key and position the current pointer on the first + * key in the list of duplicates. If the key is not found the current + * pointer is placed at the first position after the key. + */ +xtPublic xtBool xt_idx_search(XTOpenTablePtr ot, XTIndexPtr ind, register XTIdxSearchKeyPtr search_key) +{ + IdxBranchStackRec stack; + xtIndexNodeID current; + XTIndReferenceRec iref; + XTIdxResultRec result; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + if (ot->ot_ind_rhandle) { + xt_ind_release_handle(ot->ot_ind_rhandle, FALSE, ot->ot_thread); + ot->ot_ind_rhandle = NULL; + } +#ifdef DEBUG + //idx_check_index(ot, ind, TRUE); +#endif + + /* Calling from recovery, this is not the case. + * But the index read does not require a transaction! + * Only insert requires this to check for duplicates. + if (!ot->ot_thread->st_xact_data) { + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_NO_TRANSACTION); + return FAILED; + } + */ + + retry_after_oom: +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_changed = 0; +#endif + idx_newstack(&stack); + + ot->ot_curr_rec_id = 0; + ot->ot_curr_row_id = 0; + + XT_INDEX_READ_LOCK(ind, ot); + + if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) + goto done_ok; + + while (XT_NODE_ID(current)) { + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + goto failed; + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, &search_key->sk_key_value, &result); + if (result.sr_found) + /* If we have found the key in a node: */ + search_key->sk_on_key = TRUE; + if (!result.sr_item.i_node_ref_size) + break; + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) + goto failed; + current = result.sr_branch; + } + + if (result.sr_item.i_item_offset == result.sr_item.i_total_size) { + IdxStackItemPtr node; + + /* We are at the end of a leaf node. + * Go up the stack to find the start position of the next key. + * If we find none, then we are the end of the index. + */ + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + while ((node = idx_pop(&stack))) { + if (node->i_pos.i_item_offset < node->i_pos.i_total_size) { + xtRecordID rec_id; + + if (!xt_ind_fetch(ot, node->i_branch, XT_LOCK_READ, &iref)) + goto failed; + xt_get_record_ref(&iref.ir_branch->tb_data[node->i_pos.i_item_offset + node->i_pos.i_item_size - XT_RECORD_REF_SIZE], &rec_id, &ot->ot_curr_row_id); + ot->ot_curr_rec_id = rec_id; + ot->ot_ind_state = node->i_pos; + + /* Convert the pointer to a handle which can be used in later operations: */ + ASSERT_NS(!ot->ot_ind_rhandle); + if (!(ot->ot_ind_rhandle = xt_ind_get_handle(ot, ind, &iref))) + goto failed; + /* Keep the node for next operations: */ + /* + branch_size = XT_GET_INDEX_BLOCK_LEN(XT_GET_DISK_2(iref.ir_branch->tb_size_2)); + memcpy(&ot->ot_ind_rbuf, iref.ir_branch, branch_size); + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + */ + break; + } + } + } + else { + ot->ot_curr_rec_id = result.sr_rec_id; + ot->ot_curr_row_id = result.sr_row_id; + ot->ot_ind_state = result.sr_item; + + /* Convert the pointer to a handle which can be used in later operations: */ + ASSERT_NS(!ot->ot_ind_rhandle); + if (!(ot->ot_ind_rhandle = xt_ind_get_handle(ot, ind, &iref))) + goto failed; + /* Keep the node for next operations: */ + /* + branch_size = XT_GET_INDEX_BLOCK_LEN(XT_GET_DISK_2(iref.ir_branch->tb_size_2)); + memcpy(&ot->ot_ind_rbuf, iref.ir_branch, branch_size); + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + */ + } + + done_ok: + XT_INDEX_UNLOCK(ind, ot); + +#ifdef DEBUG + //idx_check_index(ot, ind, TRUE); + //idx_check_on_key(ot); +#endif + ASSERT_NS(iref.ir_ulock == XT_UNLOCK_NONE); + return OK; + + failed: + XT_INDEX_UNLOCK(ind, ot); + if (idx_out_of_memory_failure(ot)) + goto retry_after_oom; + ASSERT_NS(iref.ir_ulock == XT_UNLOCK_NONE); + return FAILED; +} + +xtPublic xtBool xt_idx_search_prev(XTOpenTablePtr ot, XTIndexPtr ind, register XTIdxSearchKeyPtr search_key) +{ + IdxBranchStackRec stack; + xtIndexNodeID current; + XTIndReferenceRec iref; + XTIdxResultRec result; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + if (ot->ot_ind_rhandle) { + xt_ind_release_handle(ot->ot_ind_rhandle, FALSE, ot->ot_thread); + ot->ot_ind_rhandle = NULL; + } +#ifdef DEBUG + //idx_check_index(ot, ind, TRUE); +#endif + + /* see the comment above in xt_idx_search */ + /* + if (!ot->ot_thread->st_xact_data) { + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_NO_TRANSACTION); + return FAILED; + } + */ + + retry_after_oom: +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_changed = 0; +#endif + idx_newstack(&stack); + + ot->ot_curr_rec_id = 0; + ot->ot_curr_row_id = 0; + + XT_INDEX_READ_LOCK(ind, ot); + + if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) + goto done_ok; + + while (XT_NODE_ID(current)) { + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + goto failed; + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, &search_key->sk_key_value, &result); + if (result.sr_found) + /* If we have found the key in a node: */ + search_key->sk_on_key = TRUE; + if (!result.sr_item.i_node_ref_size) + break; + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) + goto failed; + current = result.sr_branch; + } + + if (result.sr_item.i_item_offset == 0) { + IdxStackItemPtr node; + + /* We are at the end of a leaf node. + * Go up the stack to find the start poition of the next key. + * If we find none, then we are the end of the index. + */ + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + while ((node = idx_pop(&stack))) { + if (node->i_pos.i_item_offset > node->i_pos.i_node_ref_size) { + if (!xt_ind_fetch(ot, node->i_branch, XT_LOCK_READ, &iref)) + goto failed; + result.sr_item = node->i_pos; + ind->mi_prev_item(ot->ot_table, ind, iref.ir_branch, &result); + goto record_found; + } + } + goto done_ok; + } + + /* We must just step once to the left in this leaf node... */ + ind->mi_prev_item(ot->ot_table, ind, iref.ir_branch, &result); + + record_found: + ot->ot_curr_rec_id = result.sr_rec_id; + ot->ot_curr_row_id = result.sr_row_id; + ot->ot_ind_state = result.sr_item; + + /* Convert to handle for later operations: */ + ASSERT_NS(!ot->ot_ind_rhandle); + if (!(ot->ot_ind_rhandle = xt_ind_get_handle(ot, ind, &iref))) + goto failed; + /* Keep a copy of the node for previous operations... */ + /* + u_int branch_size; + + branch_size = XT_GET_INDEX_BLOCK_LEN(XT_GET_DISK_2(iref.ir_branch->tb_size_2)); + memcpy(&ot->ot_ind_rbuf, iref.ir_branch, branch_size); + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + */ + + done_ok: + XT_INDEX_UNLOCK(ind, ot); + +#ifdef DEBUG + //idx_check_index(ot, ind, TRUE); + //idx_check_on_key(ot); +#endif + return OK; + + failed: + XT_INDEX_UNLOCK(ind, ot); + if (idx_out_of_memory_failure(ot)) + goto retry_after_oom; + return FAILED; +} + +/* + * Copy the current index value to the record. + */ +xtPublic xtBool xt_idx_read(XTOpenTablePtr ot, XTIndexPtr ind, xtWord1 *rec_buf) +{ + xtWord1 *bitem; + +#ifdef DEBUG + //idx_check_on_key(ot); +#endif + xt_ind_lock_handle(ot->ot_ind_rhandle); + bitem = ot->ot_ind_rhandle->ih_branch->tb_data + ot->ot_ind_state.i_item_offset; + myxt_create_row_from_key(ot, ind, bitem, ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE, rec_buf); + xt_ind_unlock_handle(ot->ot_ind_rhandle); + return OK; +} + +xtPublic xtBool xt_idx_next(register XTOpenTablePtr ot, register XTIndexPtr ind, register XTIdxSearchKeyPtr search_key) +{ + XTIdxKeyValueRec key_value; + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE]; + XTIdxResultRec result; + IdxBranchStackRec stack; + xtIndexNodeID current; + XTIndReferenceRec iref; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + ASSERT_NS(ot->ot_ind_rhandle); + xt_ind_lock_handle(ot->ot_ind_rhandle); + if (!ot->ot_ind_state.i_node_ref_size && + ot->ot_ind_state.i_item_offset < ot->ot_ind_state.i_total_size && + ot->ot_ind_rhandle->ih_cache_reference) { + key_value.sv_key = &ot->ot_ind_rhandle->ih_branch->tb_data[ot->ot_ind_state.i_item_offset]; + key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE; + + result.sr_item = ot->ot_ind_state; + idx_next_branch_item(ot->ot_table, ind, ot->ot_ind_rhandle->ih_branch, &result); + if (result.sr_item.i_item_offset < result.sr_item.i_total_size) { + /* Still on key? */ + if (search_key && search_key->sk_on_key) { + search_key->sk_on_key = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length, + search_key->sk_key_value.sv_key, &ot->ot_ind_rhandle->ih_branch->tb_data[result.sr_item.i_item_offset]) == 0; + } + xt_ind_unlock_handle(ot->ot_ind_rhandle); + goto checked_on_key; + } + } + + key_value.sv_flags = XT_SEARCH_WHOLE_KEY; + xt_get_record_ref(&ot->ot_ind_rhandle->ih_branch->tb_data[ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE], &key_value.sv_rec_id, &key_value.sv_row_id); + key_value.sv_key = key_buf; + key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE; + memcpy(key_buf, &ot->ot_ind_rhandle->ih_branch->tb_data[ot->ot_ind_state.i_item_offset], key_value.sv_length); + xt_ind_release_handle(ot->ot_ind_rhandle, TRUE, ot->ot_thread); + ot->ot_ind_rhandle = NULL; + + retry_after_oom: +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_changed = 0; +#endif + idx_newstack(&stack); + + XT_INDEX_READ_LOCK(ind, ot); + + if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) { + XT_INDEX_UNLOCK(ind, ot); + return OK; + } + + while (XT_NODE_ID(current)) { + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + goto failed; + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, &key_value, &result); + if (result.sr_item.i_node_ref_size) { + if (result.sr_found) { + /* If we have found the key in a node: */ + idx_next_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + + /* Go down to the bottom: */ + while (XT_NODE_ID(current)) { + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) + goto failed; + current = result.sr_branch; + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + goto failed; + idx_first_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + if (!result.sr_item.i_node_ref_size) + break; + } + + /* Is the leaf not empty, then we are done... */ + break; + } + } + else { + /* We have reached the leaf. */ + if (result.sr_found) + /* If we have found the key in a leaf: */ + idx_next_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + /* If we did not find the key (although we should have). Our + * position is automatically the next one. + */ + break; + } + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) + goto failed; + current = result.sr_branch; + } + + /* Check the current position in a leaf: */ + if (result.sr_item.i_item_offset == result.sr_item.i_total_size) { + /* At the end: */ + IdxStackItemPtr node; + + /* We are at the end of a leaf node. + * Go up the stack to find the start poition of the next key. + * If we find none, then we are the end of the index. + */ + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + while ((node = idx_pop(&stack))) { + if (node->i_pos.i_item_offset < node->i_pos.i_total_size) { + if (!xt_ind_fetch(ot, node->i_branch, XT_LOCK_READ, &iref)) + goto failed; + result.sr_item = node->i_pos; + xt_get_res_record_ref(&iref.ir_branch->tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size - XT_RECORD_REF_SIZE], &result); + goto unlock_check_on_key; + } + } + + /* No more keys: */ + if (search_key) + search_key->sk_on_key = FALSE; + ot->ot_curr_rec_id = 0; + ot->ot_curr_row_id = 0; + XT_INDEX_UNLOCK(ind, ot); + return OK; + } + + unlock_check_on_key: + + ASSERT_NS(!ot->ot_ind_rhandle); + if (!(ot->ot_ind_rhandle = xt_ind_get_handle(ot, ind, &iref))) + goto failed; + /* + u_int branch_size; + + branch_size = XT_GET_INDEX_BLOCK_LEN(XT_GET_DISK_2(iref.ir_branch->tb_size_2)); + memcpy(&ot->ot_ind_rbuf, iref.ir_branch, branch_size); + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + */ + + XT_INDEX_UNLOCK(ind, ot); + + /* Still on key? */ + if (search_key && search_key->sk_on_key) { + /* GOTCHA: As a short-cut I was using a length compare + * and a memcmp() here to check whether we as still on + * the original search key. + * This does not work because it does not take into account + * trialing spaces (which are ignored in comparison). + * So lengths can be different, but values still equal. + * + * NOTE: We have to use the original search flags for + * this compare. + */ + xt_ind_lock_handle(ot->ot_ind_rhandle); + search_key->sk_on_key = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length, + search_key->sk_key_value.sv_key, &ot->ot_ind_rhandle->ih_branch->tb_data[result.sr_item.i_item_offset]) == 0; + xt_ind_unlock_handle(ot->ot_ind_rhandle); + } + + checked_on_key: + ot->ot_curr_rec_id = result.sr_rec_id; + ot->ot_curr_row_id = result.sr_row_id; + ot->ot_ind_state = result.sr_item; + + return OK; + + failed: + XT_INDEX_UNLOCK(ind, ot); + if (idx_out_of_memory_failure(ot)) + goto retry_after_oom; + return FAILED; +} + +xtPublic xtBool xt_idx_prev(register XTOpenTablePtr ot, register XTIndexPtr ind, register XTIdxSearchKeyPtr search_key) +{ + XTIdxKeyValueRec key_value; + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE]; + XTIdxResultRec result; + IdxBranchStackRec stack; + xtIndexNodeID current; + XTIndReferenceRec iref; + IdxStackItemPtr node; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + ASSERT_NS(ot->ot_ind_rhandle); + xt_ind_lock_handle(ot->ot_ind_rhandle); + if (!ot->ot_ind_state.i_node_ref_size && ot->ot_ind_state.i_item_offset > 0) { + key_value.sv_key = &ot->ot_ind_rhandle->ih_branch->tb_data[ot->ot_ind_state.i_item_offset]; + key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE; + + result.sr_item = ot->ot_ind_state; + ind->mi_prev_item(ot->ot_table, ind, ot->ot_ind_rhandle->ih_branch, &result); + + if (search_key && search_key->sk_on_key) { + search_key->sk_on_key = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length, + search_key->sk_key_value.sv_key, &ot->ot_ind_rhandle->ih_branch->tb_data[result.sr_item.i_item_offset]) == 0; + } + + xt_ind_unlock_handle(ot->ot_ind_rhandle); + goto checked_on_key; + } + + key_value.sv_flags = XT_SEARCH_WHOLE_KEY; + key_value.sv_rec_id = ot->ot_curr_rec_id; + key_value.sv_row_id = 0; + key_value.sv_key = key_buf; + key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE; + memcpy(key_buf, &ot->ot_ind_rhandle->ih_branch->tb_data[ot->ot_ind_state.i_item_offset], key_value.sv_length); + xt_ind_release_handle(ot->ot_ind_rhandle, TRUE, ot->ot_thread); + ot->ot_ind_rhandle = NULL; + + retry_after_oom: +#ifdef XT_TRACK_INDEX_UPDATES + ot->ot_ind_changed = 0; +#endif + idx_newstack(&stack); + + XT_INDEX_READ_LOCK(ind, ot); + + if (!(XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) { + XT_INDEX_UNLOCK(ind, ot); + return OK; + } + + while (XT_NODE_ID(current)) { + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + goto failed; + ind->mi_scan_branch(ot->ot_table, ind, iref.ir_branch, &key_value, &result); + if (result.sr_item.i_node_ref_size) { + if (result.sr_found) { + /* If we have found the key in a node: */ + + /* Go down to the bottom: */ + while (XT_NODE_ID(current)) { + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) + goto failed; + current = result.sr_branch; + if (!xt_ind_fetch(ot, current, XT_LOCK_READ, &iref)) + goto failed; + ind->mi_last_item(ot->ot_table, ind, iref.ir_branch, &result); + if (!result.sr_item.i_node_ref_size) + break; + } + + /* Is the leaf not empty, then we are done... */ + if (result.sr_item.i_total_size == 0) + break; + goto unlock_check_on_key; + } + } + else { + /* We have reached the leaf. + * Whether we found the key or not, we have + * to move one to the left. + */ + if (result.sr_item.i_item_offset == 0) + break; + ind->mi_prev_item(ot->ot_table, ind, iref.ir_branch, &result); + goto unlock_check_on_key; + } + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + if (!idx_push(&stack, current, &result.sr_item)) + goto failed; + current = result.sr_branch; + } + + /* We are at the start of a leaf node. + * Go up the stack to find the start poition of the next key. + * If we find none, then we are the end of the index. + */ + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + while ((node = idx_pop(&stack))) { + if (node->i_pos.i_item_offset > node->i_pos.i_node_ref_size) { + if (!xt_ind_fetch(ot, node->i_branch, XT_LOCK_READ, &iref)) + goto failed; + result.sr_item = node->i_pos; + ind->mi_prev_item(ot->ot_table, ind, iref.ir_branch, &result); + goto unlock_check_on_key; + } + } + + /* No more keys: */ + if (search_key) + search_key->sk_on_key = FALSE; + ot->ot_curr_rec_id = 0; + ot->ot_curr_row_id = 0; + + XT_INDEX_UNLOCK(ind, ot); + return OK; + + unlock_check_on_key: + ASSERT_NS(!ot->ot_ind_rhandle); + if (!(ot->ot_ind_rhandle = xt_ind_get_handle(ot, ind, &iref))) + goto failed; + /* + u_int branch_size; + + branch_size = XT_GET_INDEX_BLOCK_LEN(XT_GET_DISK_2(iref.ir_branch->tb_size_2)); + memcpy(&ot->ot_ind_rbuf, iref.ir_branch, branch_size); + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + */ + + XT_INDEX_UNLOCK(ind, ot); + + /* Still on key? */ + if (search_key && search_key->sk_on_key) { + xt_ind_lock_handle(ot->ot_ind_rhandle); + search_key->sk_on_key = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length, + search_key->sk_key_value.sv_key, &ot->ot_ind_rhandle->ih_branch->tb_data[result.sr_item.i_item_offset]) == 0; + xt_ind_unlock_handle(ot->ot_ind_rhandle); + } + + checked_on_key: + ot->ot_curr_rec_id = result.sr_rec_id; + ot->ot_curr_row_id = result.sr_row_id; + ot->ot_ind_state = result.sr_item; + return OK; + + failed: + XT_INDEX_UNLOCK(ind, ot); + if (idx_out_of_memory_failure(ot)) + goto retry_after_oom; + return FAILED; +} + +/* Return TRUE if the record matches the current index search! */ +xtPublic xtBool xt_idx_match_search(register XTOpenTablePtr ot __attribute__((unused)), register XTIndexPtr ind, register XTIdxSearchKeyPtr search_key, xtWord1 *buf, int mode) +{ + int r; + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE]; + + myxt_create_key_from_row(ind, key_buf, (xtWord1 *) buf, NULL); + r = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length, search_key->sk_key_value.sv_key, key_buf); + switch (mode) { + case XT_S_MODE_MATCH: + return r == 0; + case XT_S_MODE_NEXT: + return r <= 0; + case XT_S_MODE_PREV: + return r >= 0; + } + return FALSE; +} + +static void idx_set_index_selectivity(XTThreadPtr self __attribute__((unused)), XTOpenTablePtr ot, XTIndexPtr ind) +{ + static const xtRecordID MAX_RECORDS = 100; + + XTIdxSearchKeyRec search_key; + XTIndexSegPtr key_seg; + u_int select_count[2] = {0, 0}; + xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE]; + u_int key_len; + xtWord1 *next_key_buf; + u_int next_key_len; + u_int curr_len; + u_int diff; + u_int j, i; + /* these 2 vars are used to check the overlapping if we have < 200 records */ + xtRecordID last_rec = 0; /* last record accounted in this iteration */ + xtRecordID last_iter_rec = 0; /* last record accounted in the previous iteration */ + + xtBool (* xt_idx_iterator[2])( + register struct XTOpenTable *ot, register struct XTIndex *ind, register XTIdxSearchKeyPtr search_key) = { + + xt_idx_next, + xt_idx_prev + }; + + xtBool (* xt_idx_begin[2])( + struct XTOpenTable *ot, struct XTIndex *ind, register XTIdxSearchKeyPtr search_key) = { + + xt_idx_search, + xt_idx_search_prev + }; + + ind->mi_select_total = 0; + key_seg = ind->mi_seg; + for (i=0; i < ind->mi_seg_count; key_seg++, i++) { + key_seg->is_selectivity = 1; + key_seg->is_recs_in_range = 1; + } + + for (j=0; j < 2; j++) { + xt_idx_prep_key(ind, &search_key, j == 0 ? XT_SEARCH_FIRST_FLAG : XT_SEARCH_AFTER_LAST_FLAG, NULL, 0); + if (!(xt_idx_begin[j])(ot, ind, &search_key)) + goto failed; + + /* Initialize the buffer with the first index valid index entry: */ + while (!select_count[j] && ot->ot_curr_rec_id != last_iter_rec) { + if (ot->ot_curr_row_id) { + select_count[j]++; + last_rec = ot->ot_curr_rec_id; + + key_len = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE; + xt_ind_unlock_handle(ot->ot_ind_rhandle); + memcpy(key_buf, ot->ot_ind_rhandle->ih_branch->tb_data + ot->ot_ind_state.i_item_offset, key_len); + xt_ind_unlock_handle(ot->ot_ind_rhandle); + } + if (!(xt_idx_iterator[j])(ot, ind, &search_key)) + goto failed_1; + } + + while (select_count[j] < MAX_RECORDS && ot->ot_curr_rec_id != last_iter_rec) { + /* Check if the index entry is committed: */ + if (ot->ot_curr_row_id) { + xt_ind_lock_handle(ot->ot_ind_rhandle); + select_count[j]++; + last_rec = ot->ot_curr_rec_id; + + next_key_len = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE; + next_key_buf = ot->ot_ind_rhandle->ih_branch->tb_data + ot->ot_ind_state.i_item_offset; + + curr_len = 0; + diff = FALSE; + key_seg = ind->mi_seg; + for (i=0; i < ind->mi_seg_count; key_seg++, i++) { + curr_len += myxt_key_seg_length(key_seg, curr_len, key_buf); + if (!diff && myxt_compare_key(ind, 0, curr_len, key_buf, next_key_buf) != 0) + diff = i+1; + if (diff) + key_seg->is_selectivity++; + } + + /* Store the key for the next comparison: */ + key_len = next_key_len; + memcpy(key_buf, next_key_buf, key_len); + xt_ind_unlock_handle(ot->ot_ind_rhandle); + } + + if (!(xt_idx_iterator[j])(ot, ind, &search_key)) + goto failed_1; + } + + last_iter_rec = last_rec; + + if (ot->ot_ind_rhandle) { + xt_ind_release_handle(ot->ot_ind_rhandle, FALSE, self); + ot->ot_ind_rhandle = NULL; + } + } + + u_int select_total; + + select_total = select_count[0] + select_count[1]; + if (select_total) { + u_int recs; + + ind->mi_select_total = select_total; + key_seg = ind->mi_seg; + for (i=0; i < ind->mi_seg_count; key_seg++, i++) { + recs = (u_int) ((double) select_total / (double) key_seg->is_selectivity + (double) 0.5); + key_seg->is_recs_in_range = recs ? recs : 1; + } + } + return; + + failed_1: + xt_ind_release_handle(ot->ot_ind_rhandle, FALSE, self); + ot->ot_ind_rhandle = NULL; + + failed: + ot->ot_table->tab_dic.dic_disable_index = XT_INDEX_CORRUPTED; + xt_log_and_clear_exception_ns(); + return; +} + +xtPublic void xt_ind_set_index_selectivity(XTThreadPtr self, XTOpenTablePtr ot) +{ + XTTableHPtr tab = ot->ot_table; + XTIndexPtr *ind; + u_int i; + + if (!tab->tab_dic.dic_disable_index) { + for (i=0, ind=tab->tab_dic.dic_keys; i<tab->tab_dic.dic_key_count; i++, ind++) + idx_set_index_selectivity(self, ot, *ind); + } +} + +/* + * ----------------------------------------------------------------------- + * Print a b-tree + */ + +#ifdef TEST_CODE +static void idx_check_on_key(XTOpenTablePtr ot) +{ + u_int offs = ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE; + xtRecordID rec_id; + xtRowID row_id; + + if (ot->ot_curr_rec_id && ot->ot_ind_state.i_item_offset < ot->ot_ind_state.i_total_size) { + xt_get_record_ref(&ot->ot_ind_rbuf.tb_data[offs], &rec_id, &row_id); + + ASSERT_NS(rec_id == ot->ot_curr_rec_id); + } +} +#endif + +static void idx_check_space(int depth) +{ + for (int i=0; i<depth; i++) + printf(". "); +} + +static u_int idx_check_node(XTOpenTablePtr ot, XTIndexPtr ind, int depth, xtIndexNodeID node) +{ + XTIdxResultRec result; + u_int block_count = 1; + XTIndReferenceRec iref; + +#ifdef DEBUG + iref.ir_ulock = XT_UNLOCK_NONE; +#endif + ASSERT_NS(XT_NODE_ID(node) <= XT_NODE_ID(ot->ot_table->tab_ind_eof)); + if (!xt_ind_fetch(ot, node, XT_LOCK_READ, &iref)) + return 0; + + idx_first_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + ASSERT_NS(result.sr_item.i_total_size + offsetof(XTIdxBranchDRec, tb_data) <= XT_INDEX_PAGE_SIZE); + if (result.sr_item.i_node_ref_size) { + idx_check_space(depth); + printf("%04d -->\n", (int) XT_NODE_ID(result.sr_branch)); +#ifdef TRACK_ACTIVITY + track_block_exists(result.sr_branch); +#endif + block_count += idx_check_node(ot, ind, depth+1, result.sr_branch); + } + + while (result.sr_item.i_item_offset < result.sr_item.i_total_size) { +#ifdef CHECK_PRINTS_RECORD_REFERENCES + idx_check_space(depth); + if (result.sr_item.i_item_size == 12) { + /* Assume this is a NOT-NULL INT!: */ + xtWord4 val = XT_GET_DISK_4(&iref.ir_branch->tb_data[result.sr_item.i_item_offset]); + printf("(%6d) ", (int) val); + } + printf("rec=%d row=%d ", (int) result.sr_rec_id, (int) result.sr_row_id); + printf("\n"); +#endif + idx_next_branch_item(ot->ot_table, ind, iref.ir_branch, &result); + if (result.sr_item.i_node_ref_size) { + idx_check_space(depth); + printf("%04d -->\n", (int) XT_NODE_ID(result.sr_branch)); +#ifdef TRACK_ACTIVITY + track_block_exists(result.sr_branch); +#endif + block_count += idx_check_node(ot, ind, depth+1, result.sr_branch); + } + } + + xt_ind_release(ot, ind, XT_UNLOCK_READ, &iref); + return block_count; +} + +static u_int idx_check_index(XTOpenTablePtr ot, XTIndexPtr ind, xtBool with_lock) +{ + xtIndexNodeID current; + u_int block_count = 0; + u_int i; + + if (with_lock) + XT_INDEX_WRITE_LOCK(ind, ot); + + printf("INDEX (%d) %04d ---------------------------------------\n", (int) ind->mi_index_no, (int) XT_NODE_ID(ind->mi_root)); + if ((XT_NODE_ID(current) = XT_NODE_ID(ind->mi_root))) { +#ifdef TRACK_ACTIVITY + track_block_exists(ind->mi_root); +#endif + block_count = idx_check_node(ot, ind, 0, current); + } + + if (ind->mi_free_list && ind->mi_free_list->fl_free_count) { + printf("INDEX (%d) FREE ---------------------------------------", (int) ind->mi_index_no); + ASSERT_NS(ind->mi_free_list->fl_start == 0); + for (i=0; i<ind->mi_free_list->fl_free_count; i++) { + if ((i % 40) == 0) + printf("\n"); + block_count++; +#ifdef TRACK_ACTIVITY + track_block_exists(ind->mi_free_list->fl_page_id[i]); +#endif + printf("%2d ", (int) XT_NODE_ID(ind->mi_free_list->fl_page_id[i])); + } + if ((i % 40) != 0) + printf("\n"); + } + + if (with_lock) + XT_INDEX_UNLOCK(ind, ot); + return block_count; + +} + +xtPublic void xt_check_indices(XTOpenTablePtr ot) +{ + register XTTableHPtr tab = ot->ot_table; + XTIndexPtr *ind; + xtIndexNodeID current; + XTIndFreeBlockRec free_block; + u_int ind_count, block_count = 0; + u_int free_count = 0; + u_int i, j; + + xt_lock_mutex_ns(&tab->tab_ind_flush_lock); + printf("CHECK INDICES %s ==============================\n", tab->tab_name->ps_path); +#ifdef TRACK_ACTIVITY + track_reset_missing(); +#endif + + ind = tab->tab_dic.dic_keys; + for (u_int k=0; k<tab->tab_dic.dic_key_count; k++, ind++) { + ind_count = idx_check_index(ot, *ind, TRUE); + block_count += ind_count; + } + + xt_lock_mutex_ns(&tab->tab_ind_lock); + printf("\nFREE: ---------------------------------------\n"); + if (tab->tab_ind_free_list) { + XTIndFreeListPtr ptr; + + ptr = tab->tab_ind_free_list; + while (ptr) { + printf("Memory List:"); + i = 0; + for (j=ptr->fl_start; j<ptr->fl_free_count; j++, i++) { + if ((i % 40) == 0) + printf("\n"); + free_count++; +#ifdef TRACK_ACTIVITY + track_block_exists(ptr->fl_page_id[j]); +#endif + printf("%2d ", (int) XT_NODE_ID(ptr->fl_page_id[j])); + } + if ((i % 40) != 0) + printf("\n"); + ptr = ptr->fl_next_list; + } + } + + current = tab->tab_ind_free; + if (XT_NODE_ID(current)) { + u_int k = 0; + printf("Disk List:"); + while (XT_NODE_ID(current)) { + if ((k % 40) == 0) + printf("\n"); + free_count++; +#ifdef TRACK_ACTIVITY + track_block_exists(current); +#endif + printf("%d ", (int) XT_NODE_ID(current)); + if (!xt_ind_read_bytes(ot, current, sizeof(XTIndFreeBlockRec), (xtWord1 *) &free_block)) { + xt_log_and_clear_exception_ns(); + break; + } + XT_NODE_ID(current) = (xtIndexNodeID) XT_GET_DISK_8(free_block.if_next_block_8); + k++; + } + if ((k % 40) != 0) + printf("\n"); + } + printf("\n-----------------------------\n"); + printf("used blocks %d + free blocks %d = %d\n", block_count, free_count, block_count + free_count); + printf("EOF = %"PRIu64", total blocks = %d\n", (xtWord8) xt_ind_node_to_offset(tab, tab->tab_ind_eof), (int) (XT_NODE_ID(tab->tab_ind_eof) - 1)); + printf("-----------------------------\n"); + xt_unlock_mutex_ns(&tab->tab_ind_lock); +#ifdef TRACK_ACTIVITY + track_dump_missing(tab->tab_ind_eof); + printf("===================================================\n"); + track_dump_all((u_int) (XT_NODE_ID(tab->tab_ind_eof) - 1)); +#endif + printf("===================================================\n"); + xt_unlock_mutex_ns(&tab->tab_ind_flush_lock); +} + +/* + * ----------------------------------------------------------------------- + * Index consistant flush + */ + +static xtBool idx_flush_dirty_list(XTIndexLogPtr il, XTOpenTablePtr ot, u_int *flush_count, XTIndBlockPtr *flush_list) +{ + for (u_int i=0; i<*flush_count; i++) + il->il_write_block(ot, flush_list[i]); + *flush_count = 0; + return OK; +} + +static xtBool ind_add_to_dirty_list(XTIndexLogPtr il, XTOpenTablePtr ot, u_int *flush_count, XTIndBlockPtr *flush_list, XTIndBlockPtr block) +{ + register u_int count; + register u_int i; + register u_int guess; + + if (*flush_count == IND_FLUSH_BUFFER_SIZE) { + if (!idx_flush_dirty_list(il, ot, flush_count, flush_list)) + return FAILED; + } + + count = *flush_count; + i = 0; + while (i < count) { + guess = (i + count - 1) >> 1; + if (XT_NODE_ID(block->cb_address) == XT_NODE_ID(flush_list[guess]->cb_address)) { + // Should not happen... + ASSERT_NS(FALSE); + return OK; + } + if (XT_NODE_ID(block->cb_address) < XT_NODE_ID(flush_list[guess]->cb_address)) + count = guess; + else + i = guess + 1; + } + + /* Insert at position i */ + memmove(flush_list + i + 1, flush_list + i, (*flush_count - i) * sizeof(XTIndBlockPtr)); + flush_list[i] = block; + *flush_count = *flush_count + 1; + return OK; +} + +xtPublic xtBool xt_flush_indices(XTOpenTablePtr ot, off_t *bytes_flushed, xtBool have_table_lock) +{ + register XTTableHPtr tab = ot->ot_table; + XTIndexLogPtr il; + XTIndexPtr *indp; + XTIndexPtr ind; + u_int i, j; + xtBool wrote_something = FALSE; + u_int flush_count = 0; + XTIndBlockPtr flush_list[IND_FLUSH_BUFFER_SIZE]; + XTIndBlockPtr block, fblock; + xtWord1 *data; + xtIndexNodeID ind_free; + xtBool something_to_free = FALSE; + xtIndexNodeID last_address, next_address; + xtWord2 curr_flush_seq; + XTIndFreeListPtr list_ptr; + u_int dirty_blocks; + XTCheckPointTablePtr cp_tab; + XTCheckPointStatePtr cp = NULL; + + if (!xt_begin_checkpoint(tab->tab_db, have_table_lock, ot->ot_thread)) + return FAILED; + +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + xt_lock_mutex_ns(&tab->tab_ind_flush_lock); + + if (!tab->tab_db->db_indlogs.ilp_get_log(&il, ot->ot_thread)) + goto failed_3; + + il->il_reset(tab->tab_id); + if (!il->il_write_byte(ot, XT_DT_FREE_LIST)) + goto failed_2; + if (!il->il_write_word4(ot, tab->tab_id)) + goto failed_2; + if (!il->il_write_word4(ot, 0)) + goto failed_2; + + /* Lock all: */ + dirty_blocks = 0; + indp = tab->tab_dic.dic_keys; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp++) { + ind = *indp; + XT_INDEX_WRITE_LOCK(ind, ot); + if (ind->mi_free_list && ind->mi_free_list->fl_free_count) + something_to_free = TRUE; + dirty_blocks += ind->mi_dirty_blocks; + } + // 128 dirty blocks == 2MB +#ifdef TRACE_FLUSH + printf("FLUSH index %d %s\n", (int) dirty_blocks * XT_INDEX_PAGE_SIZE, tab->tab_name->ps_path); + fflush(stdout); +#endif + if (bytes_flushed) + *bytes_flushed += (dirty_blocks * XT_INDEX_PAGE_SIZE); + + curr_flush_seq = tab->tab_ind_flush_seq; + tab->tab_ind_flush_seq++; + + /* Write the dirty pages: */ + indp = tab->tab_dic.dic_keys; + data = tab->tab_index_head->tp_data; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp++) { + ind = *indp; + xt_spinlock_lock(&ind->mi_dirty_lock); + if ((block = ind->mi_dirty_list)) { + wrote_something = TRUE; + while (block) { + ASSERT_NS(block->cb_state == IDX_CAC_BLOCK_DIRTY); + ASSERT_NS(block->cp_flush_seq == curr_flush_seq); + if (!ind_add_to_dirty_list(il, ot, &flush_count, flush_list, block)) + goto failed; + block = block->cb_dirty_next; + } + } + xt_spinlock_unlock(&ind->mi_dirty_lock); + XT_SET_NODE_REF(tab, data, ind->mi_root); + data += XT_NODE_REF_SIZE; + } + + /* Flush the dirty blocks: */ + if (!idx_flush_dirty_list(il, ot, &flush_count, flush_list)) + goto failed; + + xt_lock_mutex_ns(&tab->tab_ind_lock); + + /* Write the free list: */ + if (something_to_free) { + union { + xtWord1 buffer[XT_BLOCK_SIZE_FOR_DIRECT_IO]; + XTIndFreeBlockRec free_block; + } x; + memset(x.buffer, 0, sizeof(XTIndFreeBlockRec)); + + /* The old start of the free list: */ + XT_NODE_ID(ind_free) = 0; + while ((list_ptr = tab->tab_ind_free_list)) { + if (list_ptr->fl_start < list_ptr->fl_free_count) { + ind_free = list_ptr->fl_page_id[list_ptr->fl_start]; + break; + } + tab->tab_ind_free_list = list_ptr->fl_next_list; + xt_free_ns(list_ptr); + } + if (!XT_NODE_ID(ind_free)) + ind_free = tab->tab_ind_free; + + if (!il->il_write_byte(ot, XT_DT_FREE_LIST)) + goto failed; + indp = tab->tab_dic.dic_keys; + XT_NODE_ID(last_address) = 0; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp++) { + ind = *indp; + //ASSERT_NS(XT_INDEX_HAVE_XLOCK(ind, ot)); + if (ind->mi_free_list && ind->mi_free_list->fl_free_count) { + for (j=0; j<ind->mi_free_list->fl_free_count; j++) { + next_address = ind->mi_free_list->fl_page_id[j]; + if (!il->il_write_word4(ot, XT_NODE_ID(ind->mi_free_list->fl_page_id[j]))) + goto failed; + if (XT_NODE_ID(last_address)) { + XT_SET_DISK_8(x.free_block.if_next_block_8, XT_NODE_ID(next_address)); + if (!xt_ind_write_cache(ot, last_address, 8, x.buffer)) + goto failed; + } + last_address = next_address; + } + } + } + if (!il->il_write_word4(ot, XT_NODE_ID(ind_free))) + goto failed; + if (XT_NODE_ID(last_address)) { + XT_SET_DISK_8(x.free_block.if_next_block_8, XT_NODE_ID(tab->tab_ind_free)); + if (!xt_ind_write_cache(ot, last_address, 8, x.buffer)) + goto failed; + } + if (!il->il_write_word4(ot, 0xFFFFFFFF)) + goto failed; + } + + /* + * Add the free list caches to the global free list cache. + * Added backwards to match the write order. + */ + indp = tab->tab_dic.dic_keys + tab->tab_dic.dic_key_count-1; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp--) { + ind = *indp; + //ASSERT_NS(XT_INDEX_HAVE_XLOCK(ind, ot)); + if (ind->mi_free_list) { + wrote_something = TRUE; + ind->mi_free_list->fl_next_list = tab->tab_ind_free_list; + tab->tab_ind_free_list = ind->mi_free_list; + } + ind->mi_free_list = NULL; + } + + /* + * The new start of the free list is the first + * item on the table free list: + */ + XT_NODE_ID(ind_free) = 0; + while ((list_ptr = tab->tab_ind_free_list)) { + if (list_ptr->fl_start < list_ptr->fl_free_count) { + ind_free = list_ptr->fl_page_id[list_ptr->fl_start]; + break; + } + tab->tab_ind_free_list = list_ptr->fl_next_list; + xt_free_ns(list_ptr); + } + if (!XT_NODE_ID(ind_free)) + ind_free = tab->tab_ind_free; + xt_unlock_mutex_ns(&tab->tab_ind_lock); + + XT_SET_DISK_6(tab->tab_index_head->tp_ind_eof_6, XT_NODE_ID(tab->tab_ind_eof)); + XT_SET_DISK_6(tab->tab_index_head->tp_ind_free_6, XT_NODE_ID(ind_free)); + + if (!il->il_write_header(ot, XT_INDEX_HEAD_SIZE, (xtWord1 *) tab->tab_index_head)) + goto failed; + + indp = tab->tab_dic.dic_keys; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp++) { + ind = *indp; + XT_INDEX_UNLOCK(ind, ot); + } + + if (wrote_something) { + /* Flush the log before we flush the index. + * + * The reason is, we must make sure that changes that + * will be in the index are already in the transaction + * log. + * + * Only then are we able to undo those changes on + * recovery. + * + * Simple example: + * CREATE TABLE t1 (s1 INT PRIMARY KEY); + * INSERT INTO t1 VALUES (1); + * + * BEGIN; + * INSERT INTO t1 VALUES (2); + * + * --- INDEX IS FLUSHED HERE --- + * + * --- SERVER CRASH HERE --- + * + * + * The INSERT VALUES (2) has been written + * to the log, but not flushed. + * But the index has been updated. + * If the index is flushed it will contain + * the entry for record with s1=2. + * + * This entry must be removed on recovery. + * + * To prevent this situation I flush the log + * here. + */ + if (!(tab->tab_dic.dic_tab_flags & XT_TAB_FLAGS_TEMP_TAB)) { + if (!xt_xlog_flush_log(ot->ot_thread)) + goto failed_2; + if (!il->il_flush(ot)) + goto failed_2; + } + + if (!il->il_apply_log(ot)) + goto failed_2; + + indp = tab->tab_dic.dic_keys; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp++) { + ind = *indp; + XT_INDEX_WRITE_LOCK(ind, ot); + } + + /* Free up flushed pages: */ + indp = tab->tab_dic.dic_keys; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp++) { + ind = *indp; + xt_spinlock_lock(&ind->mi_dirty_lock); + if ((block = ind->mi_dirty_list)) { + while (block) { + fblock = block; + block = block->cb_dirty_next; + ASSERT_NS(fblock->cb_state == IDX_CAC_BLOCK_DIRTY); + if (fblock->cp_flush_seq == curr_flush_seq) { + /* Take the block off the dirty list: */ + if (fblock->cb_dirty_next) + fblock->cb_dirty_next->cb_dirty_prev = fblock->cb_dirty_prev; + if (fblock->cb_dirty_prev) + fblock->cb_dirty_prev->cb_dirty_next = fblock->cb_dirty_next; + if (ind->mi_dirty_list == fblock) + ind->mi_dirty_list = fblock->cb_dirty_next; + ind->mi_dirty_blocks--; + fblock->cb_state = IDX_CAC_BLOCK_CLEAN; + } + } + } + xt_spinlock_unlock(&ind->mi_dirty_lock); + } + + indp = tab->tab_dic.dic_keys; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp++) { + ind = *indp; + XT_INDEX_UNLOCK(ind, ot); + } + } + + il->il_release(); + + /* Mark this table as index flushed: */ + cp = &tab->tab_db->db_cp_state; + xt_lock_mutex_ns(&cp->cp_state_lock); + if (cp->cp_running) { + cp_tab = (XTCheckPointTablePtr) xt_sl_find(NULL, cp->cp_table_ids, &tab->tab_id); + if (cp_tab && (cp_tab->cpt_flushed & XT_CPT_ALL_FLUSHED) != XT_CPT_ALL_FLUSHED) { + cp_tab->cpt_flushed |= XT_CPT_INDEX_FLUSHED; + if ((cp_tab->cpt_flushed & XT_CPT_ALL_FLUSHED) == XT_CPT_ALL_FLUSHED) { + ASSERT_NS(cp->cp_flush_count < xt_sl_get_size(cp->cp_table_ids)); + cp->cp_flush_count++; + } + } + } + xt_unlock_mutex_ns(&cp->cp_state_lock); + + xt_unlock_mutex_ns(&tab->tab_ind_flush_lock); +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache((XTIndex *) 1); +#endif +#ifdef TRACE_FLUSH + printf("FLUSH --end-- %s\n", tab->tab_name->ps_path); + fflush(stdout); +#endif + if (!xt_end_checkpoint(tab->tab_db, ot->ot_thread, NULL)) + return FAILED; + return OK; + + failed: + indp = tab->tab_dic.dic_keys; + for (i=0; i<tab->tab_dic.dic_key_count; i++, indp++) { + ind = *indp; + XT_INDEX_UNLOCK(ind, ot); + } + + failed_2: + il->il_release(); + + failed_3: + xt_unlock_mutex_ns(&tab->tab_ind_flush_lock); +#ifdef DEBUG_CHECK_IND_CACHE + xt_ind_check_cache(NULL); +#endif + return FAILED; +} + +void XTIndexLogPool::ilp_init(struct XTThread *self, struct XTDatabase *db, size_t log_buffer_size) +{ + char path[PATH_MAX]; + XTOpenDirPtr od; + xtLogID log_id; + char *file; + XTIndexLogPtr il = NULL; + XTOpenTablePtr ot = NULL; + + ilp_db = db; + ilp_log_buffer_size = log_buffer_size; + xt_init_mutex_with_autoname(self, &ilp_lock); + + xt_strcpy(PATH_MAX, path, db->db_main_path); + xt_add_system_dir(PATH_MAX, path); + if (xt_fs_exists(path)) { + pushsr_(od, xt_dir_close, xt_dir_open(self, path, NULL)); + while (xt_dir_next(self, od)) { + file = xt_dir_name(self, od); + if (xt_starts_with(file, "ilog")) { + if ((log_id = (xtLogID) xt_file_name_to_id(file))) { + if (!ilp_open_log(&il, log_id, FALSE, self)) + goto failed; + if (il->il_tab_id && il->il_log_eof) { + if (!il->il_open_table(&ot)) + goto failed; + if (ot) { + if (!il->il_apply_log(ot)) + goto failed; + ot->ot_thread = self; + il->il_close_table(ot); + } + } + il->il_close(TRUE); + } + } + } + freer_(); // xt_dir_close(od) + } + return; + + failed: + if (ot && il) + il->il_close_table(ot); + if (il) + il->il_close(FALSE); + xt_throw(self); +} + +void XTIndexLogPool::ilp_close(struct XTThread *self __attribute__((unused)), xtBool lock) +{ + XTIndexLogPtr il; + + if (lock) + xt_lock_mutex_ns(&ilp_lock); + while ((il = ilp_log_pool)) { + ilp_log_pool = il->il_next_in_pool; + il_pool_count--; + il->il_close(TRUE); + } + if (lock) + xt_unlock_mutex_ns(&ilp_lock); +} + +void XTIndexLogPool::ilp_exit(struct XTThread *self) +{ + ilp_close(self, FALSE); + ASSERT_NS(il_pool_count == 0); + xt_free_mutex(&ilp_lock); +} + +void XTIndexLogPool::ilp_name(size_t size, char *path, xtLogID log_id) +{ + char name[50]; + + sprintf(name, "ilog-%lu.xt", (u_long) log_id); + xt_strcpy(size, path, ilp_db->db_main_path); + xt_add_system_dir(size, path); + xt_add_dir_char(size, path); + xt_strcat(size, path, name); +} + +xtBool XTIndexLogPool::ilp_open_log(XTIndexLogPtr *ret_il, xtLogID log_id, xtBool excl, XTThreadPtr thread) +{ + char log_path[PATH_MAX]; + XTIndexLogPtr il; + XTIndLogHeadDRec log_head; + size_t read_size; + + ilp_name(PATH_MAX, log_path, log_id); + if (!(il = (XTIndexLogPtr) xt_calloc_ns(sizeof(XTIndexLogRec)))) + return FAILED; + il->il_log_id = log_id; + il->il_pool = this; + + /* Writes will be rounded up to the nearest direct write block size (see [+]), + * so make sure we have space in the buffer for that: + */ + if (!(il->il_buffer = (xtWord1 *) xt_malloc_ns(ilp_log_buffer_size + XT_BLOCK_SIZE_FOR_DIRECT_IO))) + goto failed; + il->il_buffer_size = ilp_log_buffer_size; + + if (!(il->il_of = xt_open_file_ns(log_path, (excl ? XT_FS_EXCLUSIVE : 0) | XT_FS_CREATE | XT_FS_MAKE_PATH))) + goto failed; + + if (!xt_pread_file(il->il_of, 0, sizeof(XTIndLogHeadDRec), 0, &log_head, &read_size, &thread->st_statistics.st_ilog, thread)) + goto failed; + + if (read_size == sizeof(XTIndLogHeadDRec)) { + il->il_tab_id = XT_GET_DISK_4(log_head.ilh_tab_id_4); + il->il_log_eof = XT_GET_DISK_4(log_head.ilh_log_eof_4); + } + else { + il->il_tab_id = 0; + il->il_log_eof = 0; + } + + *ret_il = il; + return OK; + + failed: + il->il_close(FALSE); + return FAILED; +} + +xtBool XTIndexLogPool::ilp_get_log(XTIndexLogPtr *ret_il, XTThreadPtr thread) +{ + XTIndexLogPtr il; + xtLogID log_id = 0; + + xt_lock_mutex_ns(&ilp_lock); + if ((il = ilp_log_pool)) { + ilp_log_pool = il->il_next_in_pool; + il_pool_count--; + } + else { + ilp_next_log_id++; + log_id = ilp_next_log_id; + } + xt_unlock_mutex_ns(&ilp_lock); + if (!il) { + if (!ilp_open_log(&il, log_id, TRUE, thread)) + return FAILED; + } + *ret_il= il; + return OK; +} + +void XTIndexLogPool::ilp_release_log(XTIndexLogPtr il) +{ + xt_lock_mutex_ns(&ilp_lock); + if (il_pool_count == 5) + il->il_close(TRUE); + else { + il_pool_count++; + il->il_next_in_pool = ilp_log_pool; + ilp_log_pool = il; + } + xt_unlock_mutex_ns(&ilp_lock); +} + +void XTIndexLog::il_reset(xtTableID tab_id) +{ + il_tab_id = tab_id; + il_log_eof = 0; + il_buffer_len = 0; + il_buffer_offset = 0; +} + +void XTIndexLog::il_close(xtBool delete_it) +{ + xtLogID log_id = il_log_id; + + if (il_of) { + xt_close_file_ns(il_of); + il_of = NULL; + } + + if (delete_it && log_id) { + char log_path[PATH_MAX]; + + il_pool->ilp_name(PATH_MAX, log_path, log_id); + xt_fs_delete(NULL, log_path); + } + + if (il_buffer) { + xt_free_ns(il_buffer); + il_buffer = NULL; + } + + xt_free_ns(this); +} + + +void XTIndexLog::il_release() +{ + il_pool->ilp_db->db_indlogs.ilp_release_log(this); +} + +xtBool XTIndexLog::il_require_space(size_t bytes, XTThreadPtr thread) +{ + if (il_buffer_len + bytes > il_buffer_size) { + if (!xt_pwrite_file(il_of, il_buffer_offset, il_buffer_len, il_buffer, &thread->st_statistics.st_ilog, thread)) + return FAILED; + il_buffer_offset += il_buffer_len; + il_buffer_len = 0; + } + + return OK; +} + +xtBool XTIndexLog::il_write_byte(struct XTOpenTable *ot __attribute__((unused)), xtWord1 byte) +{ + if (!il_require_space(1, ot->ot_thread)) + return FAILED; + *(il_buffer + il_buffer_len) = byte; + il_buffer_len++; + return OK; +} + +xtBool XTIndexLog::il_write_word4(struct XTOpenTable *ot __attribute__((unused)), xtWord4 value) +{ + xtWord1 *buffer; + + if (!il_require_space(4, ot->ot_thread)) + return FAILED; + buffer = il_buffer + il_buffer_len; + XT_SET_DISK_4(buffer, value); + il_buffer_len += 4; + return OK; +} + +xtBool XTIndexLog::il_write_block(struct XTOpenTable *ot __attribute__((unused)), XTIndBlockPtr block) +{ + XTIndPageDataDPtr page_data; + xtIndexNodeID node_id; + XTIdxBranchDPtr node; + u_int block_len; + + node_id = block->cb_address; + node = (XTIdxBranchDPtr) block->cb_data; + block_len = XT_GET_INDEX_BLOCK_LEN(XT_GET_DISK_2(node->tb_size_2)); + + if (!il_require_space(offsetof(XTIndPageDataDRec, ild_data) + block_len, ot->ot_thread)) + return FAILED; + + ASSERT_NS(offsetof(XTIndPageDataDRec, ild_data) + XT_INDEX_PAGE_SIZE <= il_buffer_size); + + page_data = (XTIndPageDataDPtr) (il_buffer + il_buffer_len); + TRACK_BLOCK_TO_FLUSH(node_id); + page_data->ild_data_type = XT_DT_INDEX_PAGE; + XT_SET_DISK_4(page_data->ild_page_id_4, XT_NODE_ID(node_id)); + memcpy(page_data->ild_data, block->cb_data, block_len); + + il_buffer_len += offsetof(XTIndPageDataDRec, ild_data) + block_len; + + return OK; +} + +xtBool XTIndexLog::il_write_header(struct XTOpenTable *ot __attribute__((unused)), size_t head_size, xtWord1 *head_buf) +{ + XTIndHeadDataDPtr head_data; + + if (!il_require_space(offsetof(XTIndHeadDataDRec, ilh_data) + head_size, ot->ot_thread)) + return FAILED; + + head_data = (XTIndHeadDataDPtr) (il_buffer + il_buffer_len); + head_data->ilh_data_type = XT_DT_HEADER; + XT_SET_DISK_2(head_data->ilh_head_size_2, head_size); + memcpy(head_data->ilh_data, head_buf, head_size); + + il_buffer_len += offsetof(XTIndHeadDataDRec, ilh_data) + head_size; + + return OK; +} + +xtBool XTIndexLog::il_flush(struct XTOpenTable *ot) +{ + XTIndLogHeadDRec log_head; + xtTableID tab_id = ot->ot_table->tab_id; + + if (il_buffer_len) { + if (!xt_pwrite_file(il_of, il_buffer_offset, il_buffer_len, il_buffer, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) + return FAILED; + il_buffer_offset += il_buffer_len; + il_buffer_len = 0; + } + + if (il_log_eof != il_buffer_offset) { + log_head.ilh_data_type = XT_DT_LOG_HEAD; + XT_SET_DISK_4(log_head.ilh_tab_id_4, tab_id); + XT_SET_DISK_4(log_head.ilh_log_eof_4, il_buffer_offset); + + if (!xt_flush_file(il_of, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) + return FAILED; + + if (!xt_pwrite_file(il_of, 0, sizeof(XTIndLogHeadDRec), (xtWord1 *) &log_head, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) + return FAILED; + + if (!xt_flush_file(il_of, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) + return FAILED; + + il_tab_id = tab_id; + il_log_eof = il_buffer_offset; + } + return OK; +} + +xtBool XTIndexLog::il_apply_log(struct XTOpenTable *ot) +{ + XT_NODE_TEMP; + register XTTableHPtr tab = ot->ot_table; + off_t offset; + size_t pos; + xtWord1 *buffer; + off_t address; + xtIndexNodeID node_id; + size_t req_size = 0; + XTIndLogHeadDRec log_head; + + offset = 0; + while (offset < il_log_eof) { + if (offset < il_buffer_offset || + offset >= il_buffer_offset + (off_t) il_buffer_len) { + il_buffer_len = il_buffer_size; + if (il_log_eof - offset < (off_t) il_buffer_len) + il_buffer_len = (size_t) (il_log_eof - offset); + + /* Corrupt log?! */ + if (il_buffer_len < req_size) { + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of)); + xt_log_and_clear_exception_ns(); + return OK; + } + if (!xt_pread_file(il_of, offset, il_buffer_len, il_buffer_len, il_buffer, NULL, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) + return FAILED; + il_buffer_offset = offset; + } + pos = (size_t) (offset - il_buffer_offset); + ASSERT_NS(pos < il_buffer_len); + buffer = il_buffer + pos; + switch (*buffer) { + case XT_DT_LOG_HEAD: + req_size = sizeof(XTIndLogHeadDRec); + if (il_buffer_len - pos < req_size) { + il_buffer_len = 0; + continue; + } + offset += req_size; + req_size = 0; + break; + case XT_DT_INDEX_PAGE: + XTIndPageDataDPtr page_data; + XTIdxBranchDPtr node; + u_int block_len; + size_t size; + + req_size = offsetof(XTIndPageDataDRec, ild_data) + 2; + if (il_buffer_len - pos < req_size) { + il_buffer_len = 0; + continue; + } + page_data = (XTIndPageDataDPtr) buffer; + node_id = XT_RET_NODE_ID(XT_GET_DISK_4(page_data->ild_page_id_4)); + node = (XTIdxBranchDPtr) page_data->ild_data; + block_len = XT_GET_INDEX_BLOCK_LEN(XT_GET_DISK_2(node->tb_size_2)); + if (block_len < 2 || block_len > XT_INDEX_PAGE_SIZE) { + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, tab->tab_name); + return FAILED; + } + + req_size = offsetof(XTIndPageDataDRec, ild_data) + block_len; + if (il_buffer_len - pos < req_size) { + il_buffer_len = 0; + continue; + } + + TRACK_BLOCK_FLUSH_N(node_id); + address = xt_ind_node_to_offset(tab, node_id); + /* [+] Round up the block size. Space has been provided. */ + size = (((block_len - 1) / XT_BLOCK_SIZE_FOR_DIRECT_IO) + 1) * XT_BLOCK_SIZE_FOR_DIRECT_IO; + IDX_TRACE("%d- W%x\n", (int) XT_NODE_ID(node_id), (int) XT_GET_DISK_2(page_data->ild_data)); + ASSERT_NS(size > 0 && size <= XT_INDEX_PAGE_SIZE); + if (!xt_pwrite_file(ot->ot_ind_file, address, size, page_data->ild_data, &ot->ot_thread->st_statistics.st_ind, ot->ot_thread)) + return FAILED; + + offset += req_size; + req_size = 0; + break; + case XT_DT_FREE_LIST: + xtWord4 block, nblock; + union { + xtWord1 buffer[XT_BLOCK_SIZE_FOR_DIRECT_IO]; + XTIndFreeBlockRec free_block; + } x; + off_t aoff; + + memset(x.buffer, 0, sizeof(XTIndFreeBlockRec)); + + pos++; + offset++; + + for (;;) { + req_size = 8; + if (il_buffer_len - pos < req_size) { + il_buffer_len = il_buffer_size; + if (il_log_eof - offset < (off_t) il_buffer_len) + il_buffer_len = (size_t) (il_log_eof - offset); + /* Corrupt log?! */ + if (il_buffer_len < req_size) { + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of)); + xt_log_and_clear_exception_ns(); + return OK; + } + if (!xt_pread_file(il_of, offset, il_buffer_len, il_buffer_len, il_buffer, NULL, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) + return FAILED; + pos = 0; + } + block = XT_GET_DISK_4(il_buffer + pos); + nblock = XT_GET_DISK_4(il_buffer + pos + 4); + if (nblock == 0xFFFFFFFF) + break; + aoff = xt_ind_node_to_offset(tab, XT_RET_NODE_ID(block)); + XT_SET_DISK_8(x.free_block.if_next_block_8, nblock); + IDX_TRACE("%d- *%x\n", (int) block, (int) XT_GET_DISK_2(x.buffer)); + if (!xt_pwrite_file(ot->ot_ind_file, aoff, XT_BLOCK_SIZE_FOR_DIRECT_IO, x.buffer, &ot->ot_thread->st_statistics.st_ind, ot->ot_thread)) + return FAILED; + pos += 4; + offset += 4; + } + + offset += 8; + req_size = 0; + break; + case XT_DT_HEADER: + XTIndHeadDataDPtr head_data; + size_t len; + + req_size = offsetof(XTIndHeadDataDRec, ilh_data); + if (il_buffer_len - pos < req_size) { + il_buffer_len = 0; + continue; + } + head_data = (XTIndHeadDataDPtr) buffer; + len = XT_GET_DISK_2(head_data->ilh_head_size_2); + + req_size = offsetof(XTIndHeadDataDRec, ilh_data) + len; + if (il_buffer_len - pos < req_size) { + il_buffer_len = 0; + continue; + } + + if (!xt_pwrite_file(ot->ot_ind_file, 0, len, head_data->ilh_data, &ot->ot_thread->st_statistics.st_ind, ot->ot_thread)) + return FAILED; + + offset += req_size; + req_size = 0; + break; + default: + xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_LOG_CORRUPT, xt_file_path(il_of)); + xt_log_and_clear_exception_ns(); + return OK; + } + } + + if (!xt_flush_file(ot->ot_ind_file, &ot->ot_thread->st_statistics.st_ind, ot->ot_thread)) + return FAILED; + + log_head.ilh_data_type = XT_DT_LOG_HEAD; + XT_SET_DISK_4(log_head.ilh_tab_id_4, il_tab_id); + XT_SET_DISK_4(log_head.ilh_log_eof_4, 0); + + if (!xt_pwrite_file(il_of, 0, sizeof(XTIndLogHeadDRec), (xtWord1 *) &log_head, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) + return FAILED; + + if (!(tab->tab_dic.dic_tab_flags & XT_TAB_FLAGS_TEMP_TAB)) { + if (!xt_flush_file(il_of, &ot->ot_thread->st_statistics.st_ilog, ot->ot_thread)) + return FAILED; + } + return OK; +} + +xtBool XTIndexLog::il_open_table(struct XTOpenTable **ot) +{ + return xt_db_open_pool_table_ns(ot, il_pool->ilp_db, il_tab_id); +} + +void XTIndexLog::il_close_table(struct XTOpenTable *ot) +{ + xt_db_return_table_to_pool_ns(ot); +} + + diff --git a/storage/pbxt/src/index_xt.h b/storage/pbxt/src/index_xt.h new file mode 100644 index 00000000000..b0b2813f5e1 --- /dev/null +++ b/storage/pbxt/src/index_xt.h @@ -0,0 +1,509 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-09-30 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_index_h__ +#define __xt_index_h__ + +#ifdef DRIZZLED +#include <mysys/my_bitmap.h> +#else +#include <mysql_version.h> +#include <my_bitmap.h> +#endif + +#include "thread_xt.h" +#include "linklist_xt.h" +#include "datalog_xt.h" +#include "datadic_xt.h" +//#include "cache_xt.h" + +#ifndef MYSQL_VERSION_ID +#error MYSQL_VERSION_ID must be defined! +#endif + +struct XTDictionary; +STRUCT_TABLE; +struct XTTable; +struct XTOpenTable; +struct XTIndex; +struct XTIndBlock; +struct XTTable; +class Field; + +/* + * INDEX ROLLBACK + * + * When a transaction is rolled back, the index entries are not + * garbage collected!! Instead, the index entries are deleted + * when the data record is garbage collected. + * + * When an index record is written, and this record replaces + * some other record (i.e. a node is updated). The new record + * references its predecessor. + * + * On cleanup (rollback or commit), the predecessor records + * are garbage collected. + * + * NOTE: It is possible to loose memory if a crash occurs during + * index modification. This can occur if a node is split and + * we crash between writing the 2 new records. + * + */ + +/* + * These flags influence the way the compare and search + * routines function. + * + * The low-order 16 bits are reserved for the caller + * (i.e. MySQL specific stuff). + */ +#define XT_SEARCH_WHOLE_KEY 0x10000000 /* This flag is used to search for an insertion point, or to find + * a particular slot that has already been inserted into the + * index. The compare includes the handle of the variation. + */ +#define XT_SEARCH_AFTER_KEY 0x20000000 /* This flags searches for the position just after the given key. + * Even if the key is not found, success is possible if there + * is a value in the index that would be after the search key. + * + * If this flag is not set then we search for the first + * occurrence of the key in the index. If not found we + * take the position just after the search key. + */ +#define XT_SEARCH_FIRST_FLAG 0x40000000 /* Use this flags to find the first position in the index. + * When set, the actual key value is ignored. + */ +#define XT_SEARCH_AFTER_LAST_FLAG 0x80000000 /* Search out the position after the last in the index. + * When set, the actual key value is ignored. + */ + +#define XT_INDEX_MAX_KEY_SIZE_MAX 2048 /* These are allocated on the stack, so this is the maximum! */ + +#define XT_INDEX_MAX_KEY_SIZE ((XT_INDEX_PAGE_SIZE >> 1) > XT_INDEX_MAX_KEY_SIZE_MAX ? XT_INDEX_MAX_KEY_SIZE_MAX : (XT_INDEX_PAGE_SIZE >> 1)) + +#define XT_IS_NODE_BIT 0x8000 + +#define XT_IS_NODE(x) ((x) & XT_IS_NODE_BIT) + +#define XT_NODE_REF_SIZE 4 +#define XT_GET_NODE_REF(t, x) XT_RET_NODE_ID(XT_GET_DISK_4(x)) +#define XT_SET_NODE_REF(t, x, y) XT_SET_DISK_4((x), XT_NODE_ID(y)) + +#define XT_MAX_RECORD_REF_SIZE 8 + +#define XT_INDEX_PAGE_DATA_SIZE XT_INDEX_PAGE_SIZE - 2 /* NOTE: 2 == offsetof(XTIdxBranchDRec, tb_data) */ + +#define XT_MAKE_LEAF_SIZE(x) ((x) + offsetof(XTIdxBranchDRec, tb_data)) + +#define XT_MAKE_NODE_SIZE(x) (((x) + offsetof(XTIdxBranchDRec, tb_data)) | XT_IS_NODE_BIT) + +#define XT_MAKE_BRANCH_SIZE(x, y) (((x) + offsetof(XTIdxBranchDRec, tb_data)) | ((y) ? XT_IS_NODE_BIT : 0)) + +#define XT_GET_INDEX_BLOCK_LEN(x) ((x) & 0x7FFF) + +#define XT_GET_BRANCH_DATA_SIZE(x) (XT_GET_INDEX_BLOCK_LEN(x) - offsetof(XTIdxBranchDRec, tb_data)) + +typedef struct XTIndexHead { + XTDiskValue4 tp_format_offset_4; /* The offset of the format part of the header. */ + + XTDiskValue4 tp_header_size_4; /* The size of the header. */ + XTDiskValue6 tp_not_used_6; + + XTDiskValue6 tp_ind_eof_6; + XTDiskValue6 tp_ind_free_6; + + /* The index roots follow. Each is if_node_ref_size_1 size. */ + xtWord1 tp_data[XT_VAR_LENGTH]; +} XTIndexHeadDRec, *XTIndexHeadDPtr; + +typedef struct XTIndexFormat { + XTDiskValue4 if_format_size_4; /* The size of this structure (index format). */ + XTDiskValue2 if_tab_version_2; /* The table version number. */ + XTDiskValue2 if_ind_version_2; /* The index version number. */ + XTDiskValue1 if_node_ref_size_1; /* This size of index node reference in indexes (default 4 bytes). */ + XTDiskValue1 if_rec_ref_size_1; /* The size of record references in the indexes (default 4 bytes). */ + XTDiskValue4 if_page_size_4; +} XTIndexFormatDRec, *XTIndexFormatDPtr; + +typedef struct XTIdxBranch { + XTDiskValue2 tb_size_2; /* No of bytes used below. */ + + /* We enough space for 2 buffers when splitting! */ + xtWord1 tb_data[XT_INDEX_PAGE_DATA_SIZE]; +} XTIdxBranchDRec, *XTIdxBranchDPtr; + +typedef struct XTIdxItem { + u_int i_total_size; /* Size of the data in the searched branch (excludes 2 byte header). */ + u_int i_item_size; /* Size of the item at this position. */ + u_int i_node_ref_size; + u_int i_item_offset; /* Item offset. */ +} XTIdxItemRec, *XTIdxItemPtr; + +typedef struct XTIdxResult { + xtBool sr_found; /* TRUE if the key was found. */ + xtBool sr_duplicate; /* TRUE if the duplicate was found. */ + xtRecordID sr_rec_id; /* Reference to the record of the found key. */ + xtRowID sr_row_id; + xtIndexNodeID sr_branch; /* Branch to follow when searching a node. */ + XTIdxItemRec sr_item; +} XTIdxResultRec, *XTIdxResultPtr; + +typedef struct XTIdxKeyValue { + int sv_flags; + xtRecordID sv_rec_id; + xtRowID sv_row_id; + u_int sv_length; + xtWord1 *sv_key; +} XTIdxKeyValueRec, *XTIdxKeyValuePtr; + +typedef struct XTIdxSearchKey { + xtBool sk_on_key; /* TRUE if we are positioned on the search key. */ + XTIdxKeyValueRec sk_key_value; /* The value of the search key. */ + xtWord1 sk_key_buf[XT_INDEX_MAX_KEY_SIZE]; +} XTIdxSearchKeyRec, *XTIdxSearchKeyPtr; + +typedef void (*XTScanBranchFunc)(struct XTTable *tab, struct XTIndex *ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result); +typedef void (*XTPrevItemFunc)(struct XTTable *tab, struct XTIndex *ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result); +typedef void (*XTLastItemFunc)(struct XTTable *tab, struct XTIndex *ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result); + +typedef int (*XTSimpleCompFunc)(struct XTIndex *ind, u_int key_length, xtWord1 *key_value, xtWord1 *b_value); + +struct charset_info_st; + +typedef struct XTIndexSeg /* Key-portion */ +{ + u_int col_idx; /* The table column index of this component. */ + u_int is_recs_in_range; /* Value returned by records_in_range(). */ + u_int is_selectivity; /* The number of unique values per mi_select_total. */ + xtWord1 type; /* Type of key (for sort) */ + xtWord1 language; + xtWord1 null_bit; /* bitmask to test for NULL */ + xtWord1 bit_start,bit_end; /* if bit field */ + xtWord1 bit_pos,bit_length; /* (not used in 4.1) */ + xtWord2 flag; + xtWord2 length; /* Keylength */ + xtWord4 start; /* Start of key in record */ + xtWord4 null_pos; /* position to NULL indicator */ + MX_CONST_CHARSET_INFO *charset; +} XTIndexSegRec, *XTIndexSegPtr; + +typedef struct XTIndFreeList { + struct XTIndFreeList *fl_next_list; /* List of free pages for this index. */ + u_int fl_start; /* Start for allocating from the front of the list. */ + u_int fl_free_count; /* Total items in the free list. */ + xtIndexNodeID fl_page_id[XT_VAR_LENGTH]; /* List of page ID's of the free pages. */ +} XTIndFreeListRec, *XTIndFreeListPtr; + +/* + * XT_INDEX_USE_PTHREAD_RW: + * The stardard pthread RW lock is currently the fastest for INSERTs + * in 32 threads on smalltab: runTest(SMALL_INSERT_TEST, 32, dbUrl) + */ +/* + * XT_INDEX_USE_RW_MUTEX: + * But the RW mutex is a close second, if not just as fast. + * If it is at least as fast, then it is better because read lock + * overhead is then zero. + * + * If definitely does get in the way of the + */ +/* XT_INDEX_USE_PTHREAD_RW: + * But this is clearly better on Linux. 216682 instead of 169259 + * payment transactions (DBT2 in non-conflict transactions, + * using only the customer table). + * + * 27.2.2009: + * The story continues. I have now fixed a bug in RW MUTEX that + * may have been slowing things down (see {RACE-WR_MUTEX}). + * + * So we will need to test "customer payment" again. + * + * 3.3.2009 + * Latest test show that RW mutex is slightly faster: + * 127460 to 123574 payment transactions. + */ +#define XT_INDEX_USE_RW_MUTEX +//#define XT_INDEX_USE_PTHREAD_RW + +#ifdef XT_INDEX_USE_FASTWRLOCK +#define XT_INDEX_LOCK_TYPE XTFastRWLockRec +#define XT_INDEX_INIT_LOCK(s, i) xt_fastrwlock_init(s, &(i)->mi_rwlock) +#define XT_INDEX_FREE_LOCK(s, i) xt_fastrwlock_free(s, &(i)->mi_rwlock) +#define XT_INDEX_READ_LOCK(i, o) xt_fastrwlock_slock(&(i)->mi_rwlock, (o)->ot_thread) +#define XT_INDEX_WRITE_LOCK(i, o) xt_fastrwlock_xlock(&(i)->mi_rwlock, (o)->ot_thread) +#define XT_INDEX_UNLOCK(i, o) xt_fastrwlock_unlock(&(i)->mi_rwlock, (o)->ot_thread) +#define XT_INDEX_HAVE_XLOCK(i, o) TRUE +#elif defined(XT_INDEX_USE_PTHREAD_RW) +#define XT_INDEX_LOCK_TYPE xt_rwlock_type +#define XT_INDEX_INIT_LOCK(s, i) xt_init_rwlock_with_autoname(s, &(i)->mi_rwlock) +#define XT_INDEX_FREE_LOCK(s, i) xt_free_rwlock(&(i)->mi_rwlock) +#define XT_INDEX_READ_LOCK(i, o) xt_slock_rwlock_ns(&(i)->mi_rwlock) +#define XT_INDEX_WRITE_LOCK(i, o) xt_xlock_rwlock_ns(&(i)->mi_rwlock) +#define XT_INDEX_UNLOCK(i, o) xt_unlock_rwlock_ns(&(i)->mi_rwlock) +#define XT_INDEX_HAVE_XLOCK(i, o) TRUE +#else // XT_INDEX_USE_RW_MUTEX +#define XT_INDEX_LOCK_TYPE XTRWMutexRec +#define XT_INDEX_INIT_LOCK(s, i) xt_rwmutex_init_with_autoname(s, &(i)->mi_rwlock) +#define XT_INDEX_FREE_LOCK(s, i) xt_rwmutex_free(s, &(i)->mi_rwlock) +#define XT_INDEX_READ_LOCK(i, o) xt_rwmutex_slock(&(i)->mi_rwlock, (o)->ot_thread->t_id) +#define XT_INDEX_WRITE_LOCK(i, o) xt_rwmutex_xlock(&(i)->mi_rwlock, (o)->ot_thread->t_id) +#define XT_INDEX_UNLOCK(i, o) xt_rwmutex_unlock(&(i)->mi_rwlock, (o)->ot_thread->t_id) +#define XT_INDEX_HAVE_XLOCK(i, o) ((i)->mi_rwlock.xs_xlocker == (o)->ot_thread->t_id) +#endif + +/* The R/W lock on the index is used as follows: + * Read Lock - used for operations on the index that are not of a structural nature. + * This includes any read operation and update operations that change an index + * node. + * Write lock - used to change the structure of the index. This includes adding + * and deleting pages. + */ +typedef struct XTIndex { + u_int mi_index_no; /* The index number (used by MySQL). */ + xt_mutex_type mi_flush_lock; /* Lock the index during flushing. */ + + /* Protected by the mi_rwlock lock: */ + XT_INDEX_LOCK_TYPE mi_rwlock; /* This lock protects the structure of the index. + * Read lock - structure may not change, but pages may change. + * Write lock - structure of index may be changed. + */ + xtIndexNodeID mi_root; /* The index root node. */ + XTIndFreeListPtr mi_free_list; /* List of free pages for this index. */ + + /* Protected by the mi_dirty_lock: */ + XTSpinLockRec mi_dirty_lock; /* Spin lock protecting the dirty & free lists. */ + struct XTIndBlock *mi_dirty_list; /* List of dirty pages for this index. */ + u_int mi_dirty_blocks; /* Count of the dirty blocks. */ + + /* Index contants: */ + u_int mi_flags; + u_int mi_key_size; + xtBool mi_low_byte_first; + xtBool mi_fix_key; + u_int mi_single_type; /* Used when the index contains a single field. */ + u_int mi_select_total; + XTScanBranchFunc mi_scan_branch; + XTPrevItemFunc mi_prev_item; + XTLastItemFunc mi_last_item; + XTSimpleCompFunc mi_simple_comp_key; + MY_BITMAP mi_col_map; /* Bit-map of columns in the index. */ + u_int mi_subset_of; /* Indicates if this index is a complete subset of someother index. */ + u_int mi_seg_count; + XTIndexSegRec mi_seg[200]; +} XTIndexRec, *XTIndexPtr; + +#define XT_INDEX_OK 0 +#define XT_INDEX_TOO_OLD 1 +#define XT_INDEX_TOO_NEW 2 +#define XT_INDEX_BAD_BLOCK 3 +#define XT_INDEX_CORRUPTED 4 +#define XT_INDEX_MISSING 5 + +typedef void (*XTFreeDicFunc)(struct XTThread *self, struct XTDictionary *dic); + +typedef struct XTDictionary { + XTDDTable *dic_table; /* XT table information. */ + + /* Table binary information. */ + u_int dic_mysql_buf_size; /* This is the size of the MySQL buffer (row size + null bytes). */ + u_int dic_mysql_rec_size; /* This is the size of the fixed length MySQL row. */ + u_int dic_rec_size; /* This is the size of the handle data file record. */ + xtBool dic_rec_fixed; /* TRUE if the record has a fixed length size. */ + u_int dic_tab_flags; /* Table flags XT_TAB_FLAGS_* */ + xtWord8 dic_min_auto_inc; /* The minimum auto-increment value. */ + xtWord8 dic_min_row_size; + xtWord8 dic_max_row_size; + xtWord8 dic_ave_row_size; + xtWord8 dic_def_ave_row_size; /* Defined row size set by the user. */ + u_int dic_no_of_cols; /* Number of columns. */ + u_int dic_fix_col_count; /* The number of columns always in the fixed part of a extended record. */ + u_int dic_ind_cols_req; /* The number of columns required to build all indexes. */ + xtWord8 dic_ind_rec_len; /* Length of the record part that is needed for all index columns! */ + + /* BLOB columns: */ + u_int dic_blob_cols_req; /* The number of the columns required to load all LONGBLOB columns. */ + u_int dic_blob_count; + Field **dic_blob_cols; + + /* MySQL related information. NULL when no tables are open from MySQL side! */ + u_int dic_disable_index; /* Non-zero if the index cannot be used. */ + u_int dic_index_ver; /* The version of the index. */ + u_int dic_key_count; + XTIndexPtr *dic_keys; /* MySQL/PBXT key description */ + STRUCT_TABLE *dic_my_table; /* MySQL table */ +} XTDictionaryRec, *XTDictionaryPtr; + +#define XT_DT_LOG_HEAD 0 +#define XT_DT_INDEX_PAGE 1 +#define XT_DT_FREE_LIST 2 +#define XT_DT_HEADER 3 + +typedef struct XTIndLogHead { + xtWord1 ilh_data_type; /* XT_DT_LOG_HEAD */ + XTDiskValue4 ilh_tab_id_4; + XTDiskValue4 ilh_log_eof_4; /* The entire size of the log (0 if invalid!) */ +} XTIndLogHeadDRec, *XTIndLogHeadDPtr; + +typedef struct XTIndPageData { + xtWord1 ild_data_type; + XTDiskValue4 ild_page_id_4; + xtWord1 ild_data[XT_VAR_LENGTH]; +} XTIndPageDataDRec, *XTIndPageDataDPtr; + +typedef struct XTIndHeadData { + xtWord1 ilh_data_type; + XTDiskValue2 ilh_head_size_2; + xtWord1 ilh_data[XT_VAR_LENGTH]; +} XTIndHeadDataDRec, *XTIndHeadDataDPtr; + +typedef struct XTIndexLog { + struct XTIndexLogPool *il_pool; + struct XTIndexLog *il_next_in_pool; + + xtLogID il_log_id; /* The ID of the data log. */ + XTOpenFilePtr il_of; + size_t il_buffer_size; + xtWord1 *il_buffer; + + xtTableID il_tab_id; + off_t il_log_eof; + size_t il_buffer_len; + off_t il_buffer_offset; + + + void il_reset(xtTableID tab_id); + void il_close(xtBool delete_it); + void il_release(); + + xtBool il_write_byte(struct XTOpenTable *ot, xtWord1 val); + xtBool il_write_word4(struct XTOpenTable *ot, xtWord4 value); + xtBool il_write_block(struct XTOpenTable *ot, struct XTIndBlock *block); + xtBool il_write_free_list(struct XTOpenTable *ot, u_int free_count, XTIndFreeListPtr free_list); + xtBool il_require_space(size_t bytes, XTThreadPtr thread); + xtBool il_write_header(struct XTOpenTable *ot, size_t head_size, xtWord1 *head_data); + xtBool il_flush(struct XTOpenTable *ot); + xtBool il_apply_log(struct XTOpenTable *ot); + + xtBool il_open_table(struct XTOpenTable **ot); + void il_close_table(struct XTOpenTable *ot); +} XTIndexLogRec, *XTIndexLogPtr; + +typedef struct XTIndexLogPool { + struct XTDatabase *ilp_db; + size_t ilp_log_buffer_size; + u_int il_pool_count; + XTIndexLogPtr ilp_log_pool; + xt_mutex_type ilp_lock; /* The public pool lock. */ + xtLogID ilp_next_log_id; + + void ilp_init(struct XTThread *self, struct XTDatabase *db, size_t log_buffer_size); + void ilp_close(struct XTThread *self, xtBool lock); + void ilp_exit(struct XTThread *self); + void ilp_name(size_t size, char *path, xtLogID log_id); + + xtBool ilp_open_log(XTIndexLogPtr *il, xtLogID log_id, xtBool excl, XTThreadPtr thread); + + xtBool ilp_get_log(XTIndexLogPtr *il, XTThreadPtr thread); + void ilp_release_log(XTIndexLogPtr il); +} XTIndexLogPoolRec, *XTIndexLogPoolPtr; + +/* A record reference consists of a record ID and a row ID: */ +inline void xt_get_record_ref(register xtWord1 *item, xtRecordID *rec_id, xtRowID *row_id) { + *rec_id = XT_GET_DISK_4(item); + item += 4; + *row_id = XT_GET_DISK_4(item); +} + +inline void xt_get_res_record_ref(register xtWord1 *item, register XTIdxResultRec *result) { + result->sr_rec_id = XT_GET_DISK_4(item); + item += 4; + result->sr_row_id = XT_GET_DISK_4(item); +} + +inline void xt_set_record_ref(register xtWord1 *item, xtRecordID rec_id, xtRowID row_id) { + XT_SET_DISK_4(item, rec_id); + item += 4; + XT_SET_DISK_4(item, row_id); +} + +inline void xt_set_val_record_ref(register xtWord1 *item, register XTIdxKeyValuePtr value) { + XT_SET_DISK_4(item, value->sv_rec_id); + item += 4; + XT_SET_DISK_4(item, value->sv_row_id); +} + +xtBool xt_idx_insert(struct XTOpenTable *ot, struct XTIndex *ind, xtRowID row_id, xtRecordID rec_id, xtWord1 *rec_buf, xtWord1 *bef_buf, xtBool allow_dups); +xtBool xt_idx_delete(struct XTOpenTable *ot, struct XTIndex *ind, xtRecordID rec_id, xtWord1 *rec_buf); +xtBool xt_idx_update_row_id(struct XTOpenTable *ot, struct XTIndex *ind, xtRecordID rec_id, xtRowID row_id, xtWord1 *rec_buf); +void xt_idx_prep_key(struct XTIndex *ind, register XTIdxSearchKeyPtr search_key, int flags, xtWord1 *in_key_buf, size_t in_key_length); +xtBool xt_idx_research(struct XTOpenTable *ot, struct XTIndex *ind); +xtBool xt_idx_search(struct XTOpenTable *ot, struct XTIndex *ind, register XTIdxSearchKeyPtr search_key); +xtBool xt_idx_search_prev(struct XTOpenTable *ot, struct XTIndex *ind, register XTIdxSearchKeyPtr search_key); +xtBool xt_idx_next(register struct XTOpenTable *ot, register struct XTIndex *ind, register XTIdxSearchKeyPtr search_key); +xtBool xt_idx_prev(register struct XTOpenTable *ot, register struct XTIndex *ind, register XTIdxSearchKeyPtr search_key); +xtBool xt_idx_read(struct XTOpenTable *ot, struct XTIndex *ind, xtWord1 *rec_buf); +void xt_ind_set_index_selectivity(XTThreadPtr self, struct XTOpenTable *ot); +void xt_check_indices(struct XTOpenTable *ot); +xtBool xt_flush_indices(struct XTOpenTable *ot, off_t *bytes_flushed, xtBool have_table_lock); +void xt_ind_track_dump_block(struct XTTable *tab, xtIndexNodeID address); + +#define XT_S_MODE_MATCH 0 +#define XT_S_MODE_NEXT 1 +#define XT_S_MODE_PREV 2 +xtBool xt_idx_match_search(struct XTOpenTable *ot, struct XTIndex *ind, register XTIdxSearchKeyPtr search_key, xtWord1 *buf, int mode); + +int xt_compare_2_int4(XTIndexPtr ind, uint key_length, xtWord1 *key_value, xtWord1 *b_value); +int xt_compare_3_int4(XTIndexPtr ind, uint key_length, xtWord1 *key_value, xtWord1 *b_value); +void xt_scan_branch_single(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result); +void xt_scan_branch_fix(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result); +void xt_scan_branch_fix_simple(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result); +void xt_scan_branch_var(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result); + +void xt_prev_branch_item_fix(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result); +void xt_prev_branch_item_var(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result); + +void xt_last_branch_item_fix(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultPtr result); +void xt_last_branch_item_var(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultPtr result); + +//#define TRACK_ACTIVITY +#ifdef TRACK_ACTIVITY + +#define TRACK_BLOCK_ALLOC(x) track_work(xt_ind_offset_to_node(tab, x), "A") +#define TRACK_BLOCK_FREE(x) track_work(xt_ind_offset_to_node(ot->ot_table, x), "-") +#define TRACK_BLOCK_SPLIT(x) track_work(xt_ind_offset_to_node(ot->ot_table, x), "/") +#define TRACK_BLOCK_WRITE(x) track_work(xt_ind_offset_to_node(ot->ot_table, x), "w") +#define TRACK_BLOCK_FLUSH_N(x) track_work(x, "F") +#define TRACK_BLOCK_TO_FLUSH(x) track_work(x, "f") + +xtPublic void track_work(u_int block, char *what); +#else + +#define TRACK_BLOCK_ALLOC(x) +#define TRACK_BLOCK_FREE(x) +#define TRACK_BLOCK_SPLIT(x) +#define TRACK_BLOCK_WRITE(x) +#define TRACK_BLOCK_FLUSH_N(x) +#define TRACK_BLOCK_TO_FLUSH(x) + +#endif + +#endif + diff --git a/storage/pbxt/src/linklist_xt.cc b/storage/pbxt/src/linklist_xt.cc new file mode 100644 index 00000000000..de5fc6170ce --- /dev/null +++ b/storage/pbxt/src/linklist_xt.cc @@ -0,0 +1,224 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-02-03 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include "pthread_xt.h" +#include "linklist_xt.h" +#include "thread_xt.h" +#include "memory_xt.h" + +xtPublic XTLinkedListPtr xt_new_linkedlist(struct XTThread *self, void *thunk, XTFreeFunc free_func, xtBool with_lock) +{ + XTLinkedListPtr ll; + + ll = (XTLinkedListPtr) xt_calloc(self, sizeof(XTLinkedListRec)); + try_(a) { + if (with_lock) { + ll->ll_lock = (xt_mutex_type *) xt_calloc(self, sizeof(xt_mutex_type)); + try_(b) { + xt_init_mutex_with_autoname(self, ll->ll_lock); + } + catch_(b) { + xt_free(self, ll->ll_lock); + ll->ll_lock = NULL; + throw_(); + } + cont_(b); + ll->ll_cond = (xt_cond_type *) xt_calloc(self, sizeof(xt_cond_type)); + try_(c) { + xt_init_cond(self, ll->ll_cond); + } + catch_(c) { + xt_free(self, ll->ll_cond); + ll->ll_cond = NULL; + throw_(); + } + cont_(c); + } + ll->ll_thunk = thunk; + ll->ll_free_func = free_func; + } + catch_(a) { + xt_free_linkedlist(self, ll); + throw_(); + } + cont_(a); + return ll; +} + +xtPublic void xt_free_linkedlist(XTThreadPtr self, XTLinkedListPtr ll) +{ + if (ll->ll_lock) + xt_lock_mutex(self, ll->ll_lock); + while (ll->ll_items) + xt_ll_remove(self, ll, ll->ll_items, FALSE); + if (ll->ll_lock) + xt_unlock_mutex(self, ll->ll_lock); + if (ll->ll_lock) { + xt_free_mutex(ll->ll_lock); + xt_free(self, ll->ll_lock); + } + if (ll->ll_cond) { + xt_free_cond(ll->ll_cond); + xt_free(self, ll->ll_cond); + } + xt_free(self, ll); +} + +xtPublic void xt_ll_add(XTThreadPtr self, XTLinkedListPtr ll, XTLinkedItemPtr li, xtBool lock) +{ + if (lock && ll->ll_lock) + xt_lock_mutex(self, ll->ll_lock); + li->li_next = ll->ll_items; + li->li_prev = NULL; + if (ll->ll_items) + ll->ll_items->li_prev = li; + ll->ll_items = li; + ll->ll_item_count++; + if (lock && ll->ll_lock) + xt_unlock_mutex(self, ll->ll_lock); +} + +xtPublic XTLinkedItemPtr xt_ll_first_item(XTThreadPtr XT_UNUSED(self), XTLinkedListPtr ll) +{ + return ll ? ll->ll_items : NULL; +} + +xtPublic XTLinkedItemPtr xt_ll_next_item(XTThreadPtr XT_UNUSED(self), XTLinkedItemPtr item) +{ + return item->li_next; +} + +xtPublic xtBool xt_ll_exists(XTThreadPtr self, XTLinkedListPtr ll, XTLinkedItemPtr li, xtBool lock) +{ + XTLinkedItemPtr ptr; + + if (lock && ll->ll_lock) + xt_lock_mutex(self, ll->ll_lock); + + ptr = ll->ll_items; + + for (ptr = ll->ll_items; ptr && (ptr != li); ptr = ptr->li_next){} + + if (lock && ll->ll_lock) + xt_unlock_mutex(self, ll->ll_lock); + + return (ptr == li); +} + +xtPublic void xt_ll_remove(XTThreadPtr self, XTLinkedListPtr ll, XTLinkedItemPtr li, xtBool lock) +{ + if (lock && ll->ll_lock) + xt_lock_mutex(self, ll->ll_lock); + + /* Move front pointer: */ + if (ll->ll_items == li) + ll->ll_items = li->li_next; + + /* Remove from list: */ + if (li->li_prev) + li->li_prev->li_next = li->li_next; + if (li->li_next) + li->li_next->li_prev = li->li_prev; + + ll->ll_item_count--; + if (ll->ll_free_func) + (*ll->ll_free_func)(self, ll->ll_thunk, li); + + /* Signal one less: */ + if (ll->ll_cond) + xt_signal_cond(self, ll->ll_cond); + + if (lock && ll->ll_lock) + xt_unlock_mutex(self, ll->ll_lock); +} + +xtPublic void xt_ll_lock(XTThreadPtr self, XTLinkedListPtr ll) +{ + if (ll->ll_lock) + xt_lock_mutex(self, ll->ll_lock); +} + +xtPublic void xt_ll_unlock(XTThreadPtr self, XTLinkedListPtr ll) +{ + if (ll->ll_lock) + xt_unlock_mutex(self, ll->ll_lock); +} + +xtPublic void xt_ll_wait_till_empty(XTThreadPtr self, XTLinkedListPtr ll) +{ + xt_lock_mutex(self, ll->ll_lock); + pushr_(xt_unlock_mutex, ll->ll_lock); + for (;;) { + if (ll->ll_item_count == 0) + break; + xt_wait_cond(self, ll->ll_cond, ll->ll_lock); + } + freer_(); // xt_unlock_mutex(ll->ll_lock) +} + +xtPublic u_int xt_ll_get_size(XTLinkedListPtr ll) +{ + return ll->ll_item_count; +} + +xtPublic void xt_init_linkedqueue(XTThreadPtr XT_UNUSED(self), XTLinkedQueuePtr lq) +{ + lq->lq_count = 0; + lq->lq_front = NULL; + lq->lq_back = NULL; +} + +xtPublic void xt_exit_linkedqueue(XTThreadPtr XT_UNUSED(self), XTLinkedQueuePtr lq) +{ + lq->lq_count = 0; + lq->lq_front = NULL; + lq->lq_back = NULL; +} + +xtPublic void xt_lq_add(XTThreadPtr XT_UNUSED(self), XTLinkedQueuePtr lq, XTLinkedQItemPtr qi) +{ + lq->lq_count++; + qi->qi_next = NULL; + if (!lq->lq_front) + lq->lq_front = qi; + if (lq->lq_back) + lq->lq_back->qi_next = qi; + lq->lq_back = qi; +} + +xtPublic XTLinkedQItemPtr xt_lq_remove(XTThreadPtr XT_UNUSED(self), XTLinkedQueuePtr lq) +{ + XTLinkedQItemPtr qi = NULL; + + if (!lq->lq_front) { + qi = lq->lq_front; + lq->lq_front = qi->qi_next; + if (!lq->lq_front) + lq->lq_back = NULL; + qi->qi_next = NULL; + } + return qi; +} + diff --git a/storage/pbxt/src/linklist_xt.h b/storage/pbxt/src/linklist_xt.h new file mode 100644 index 00000000000..1e33f71a421 --- /dev/null +++ b/storage/pbxt/src/linklist_xt.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-02-03 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_linklist_h__ +#define __xt_linklist_h__ + +#include "xt_defs.h" + +struct XTThread; + +typedef struct XTLinkedItem { + struct XTLinkedItem *li_prev; + struct XTLinkedItem *li_next; +} XTLinkedItemRec, *XTLinkedItemPtr; + +typedef struct XTLinkedList { + xt_mutex_type *ll_lock; + xt_cond_type *ll_cond; /* Condition for wait for empty. */ + void *ll_thunk; + XTFreeFunc ll_free_func; + u_int ll_item_count; + XTLinkedItemPtr ll_items; +} XTLinkedListRec, *XTLinkedListPtr; + +XTLinkedListPtr xt_new_linkedlist(struct XTThread *self, void *thunk, XTFreeFunc free_func, xtBool with_lock); +void xt_free_linkedlist(struct XTThread *self, XTLinkedListPtr ll); + +void xt_ll_add(struct XTThread *self, XTLinkedListPtr ll, XTLinkedItemPtr li, xtBool lock); +void xt_ll_remove(struct XTThread *self, XTLinkedListPtr ll, XTLinkedItemPtr li, xtBool lock); +xtBool xt_ll_exists(struct XTThread *self, XTLinkedListPtr ll, XTLinkedItemPtr li, xtBool lock); + +void xt_ll_lock(struct XTThread *self, XTLinkedListPtr ll); +void xt_ll_unlock(struct XTThread *self, XTLinkedListPtr ll); + +void xt_ll_wait_till_empty(struct XTThread *self, XTLinkedListPtr ll); + +XTLinkedItemPtr xt_ll_first_item(struct XTThread *self, XTLinkedListPtr ll); +XTLinkedItemPtr xt_ll_next_item(struct XTThread *self, XTLinkedItemPtr item); +u_int xt_ll_get_size(XTLinkedListPtr ll); + +typedef struct XTLinkedQItem { + struct XTLinkedQItem *qi_next; +} XTLinkedQItemRec, *XTLinkedQItemPtr; + +typedef struct XTLinkedQueue { + size_t lq_count; + XTLinkedQItemPtr lq_front; + XTLinkedQItemPtr lq_back; +} XTLinkedQueueRec, *XTLinkedQueuePtr; + +void xt_init_linkedqueue(struct XTThread *self, XTLinkedQueuePtr lq); +void xt_exit_linkedqueue(struct XTThread *self, XTLinkedQueuePtr lq); + +void xt_lq_add(struct XTThread *self, XTLinkedQueuePtr lq, XTLinkedQItemPtr qi); +XTLinkedQItemPtr xt_lq_remove(struct XTThread *self, XTLinkedQueuePtr lq); + +#endif + diff --git a/storage/pbxt/src/lock_xt.cc b/storage/pbxt/src/lock_xt.cc new file mode 100644 index 00000000000..ec698bb81b2 --- /dev/null +++ b/storage/pbxt/src/lock_xt.cc @@ -0,0 +1,2506 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2008-01-24 Paul McCullagh + * + * Row lock functions. + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <stdio.h> + +#include "lock_xt.h" +#include "thread_xt.h" +#include "table_xt.h" +#include "xaction_xt.h" +#include "database_xt.h" +#include "trace_xt.h" + +#ifdef DEBUG +//#define XT_TRACE_LOCKS +//#define CHECK_ROWLOCK_GROUP_CONSISTENCY +#endif + +/* + * ----------------------------------------------------------------------- + * ROW LOCKS, LIST BASED + */ +#ifdef XT_USE_LIST_BASED_ROW_LOCKS + +#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY +/* + * Requires a spin-lock on group->lg_lock! + */ +static void check_rowlock_group(XTLockGroupPtr group) +{ + XTThreadPtr self = xt_get_self(); + + char *crash = NULL; + + if (group->lg_lock.spl_locker != self) + *crash = 1; + + if (group->lg_list_in_use > group->lg_list_size) + *crash = 1; + + xtRowID prev_row = 0; + XTLockItemPtr item = group->lg_list; + + for (int i = 0; i < group->lg_list_in_use; i++, item++) { + + if (!item->li_thread_id) + *crash = 1; + + if(!xt_thr_array[item->li_thread_id]->st_xact_data) + *crash = 1; + + if(item->li_count > XT_TEMP_LOCK_BYTES) + *crash = 1; + + // rows per thread must obey the row_id > prev_row_id + prev_count*group_size rule + if (prev_row >= item->li_row_id) + *crash = 1; + + // calculate the new prev. row + if (item->li_count < XT_TEMP_LOCK_BYTES) + prev_row = item->li_row_id + (item->li_count - 1) * XT_ROW_LOCK_GROUP_COUNT; + else + prev_row = item->li_row_id; + } +} +#endif + +static int xlock_cmp_row_ids(XTThreadPtr XT_UNUSED(self), register const void *XT_UNUSED(thunk), register const void *a, register const void *b) +{ + xtRowID row_id = *((xtTableID *) a); + XTLockItemPtr item = (XTLockItemPtr) b; + + if (row_id < item->li_row_id) + return -1; + if (row_id > item->li_row_id) + return 1; + return 0; +} + +void XTRowLockList::xt_remove_all_locks(struct XTDatabase *, XTThreadPtr thread) +{ +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "remove all locks\n"); +#endif + if (!bl_count) + return; + + xtThreadID thd_id; + XTPermRowLockPtr plock; +#ifndef XT_USE_TABLE_REF + XTOpenTablePtr pot = NULL; +#endif + + thd_id = thread->t_id; + plock = (XTPermRowLockPtr) bl_data; + for (u_int i=0; i<bl_count; i++) { +#ifdef XT_USE_TABLE_REF + XTTableHPtr tab = plock->pr_table; +#else + if (!xt_db_open_pool_table_ns(&pot, db, plock->pr_tab_id)) { + /* Should not happen, but just in case, we just don't + * remove the lock. We will probably end up with a deadlock + * somewhere. + */ + xt_log_and_clear_exception_ns(); + } + else { +#endif + for (int j=0; j<XT_ROW_LOCK_GROUP_COUNT; j++) { + if (plock->pr_group[j]) { + /* Go through group j and compact. */ +#ifndef XT_USE_TABLE_REF + XTTableHPtr tab = pot->ot_table; +#endif + XTLockGroupPtr group; + XTLockItemPtr copy; + XTLockItemPtr item; + int new_count; + + group = &tab->tab_locks.rl_groups[j]; + xt_spinlock_lock(&group->lg_lock); + copy = group->lg_list; + item = group->lg_list; + new_count = 0; + for (size_t k=0; k<group->lg_list_in_use; k++) { + if (item->li_thread_id != thd_id) { + if (copy != item) { + copy->li_row_id = item->li_row_id; + copy->li_count = item->li_count; + copy->li_thread_id = item->li_thread_id; + } + new_count++; + copy++; + } +#ifdef XT_TRACE_LOCKS + else { + if (item->li_count == XT_TEMP_LOCK_BYTES) + xt_ttracef(xt_get_self(), "remove group %d lock row_id=%d TEMP\n", j, (int) item->li_row_id); + else + xt_ttracef(xt_get_self(), "remove group %d locks row_id=%d (%d)\n", j, (int) item->li_row_id, (int) item->li_count); + } +#endif + item++; + } + group->lg_list_in_use = new_count; +#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY + check_rowlock_group(group); +#endif + if (group->lg_wait_queue) + tab->tab_locks.rl_grant_locks(group, thread); + + xt_spinlock_unlock(&group->lg_lock); + + xt_xn_wakeup_thread_list(thread); + } + } +#ifdef XT_USE_TABLE_REF + xt_heap_release(NULL, plock->pr_table); +#else + xt_db_return_table_to_pool_ns(pot); + } +#endif + plock++; + } + bl_count = 0; +} + +#ifdef DEBUG_LOCK_QUEUE +int *dummy_ptr = 0; + +void XTRowLocks::rl_check(XTLockWaitPtr no_lw) +{ + XTLockGroupPtr group; + XTLockWaitPtr lw, lw_prev; + + for (int i=0; i<XT_ROW_LOCK_GROUP_COUNT; i++) { + group = &rl_groups[i]; + xt_spinlock_lock(&group->lg_lock); + + lw = group->lg_wait_queue; + lw_prev = NULL; + while (lw) { + if (lw == no_lw) + *dummy_ptr = 1; + if (lw->lw_prev != lw_prev) + *dummy_ptr = 2; + lw_prev = lw; + lw = lw->lw_next; + } + xt_spinlock_unlock(&group->lg_lock); + } +} +#endif + +xtBool XTRowLocks::rl_lock_row(XTLockGroupPtr group, XTLockWaitPtr lw, XTRowLockListPtr, int *result) +{ + XTLockItemPtr item; + size_t index; + xtRowID row_id = lw->lw_row_id; + +#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY + check_rowlock_group(group); +#endif + if (group->lg_list_size == group->lg_list_in_use) { + if (!xt_realloc_ns((void **) &group->lg_list, (group->lg_list_size + 2) * sizeof(XTLockItemRec))) + return FAILED; + group->lg_list_size += 2; + } + item = (XTLockItemPtr) xt_bsearch(NULL, &row_id, group->lg_list, group->lg_list_in_use, sizeof(XTLockItemRec), &index, NULL, xlock_cmp_row_ids); + + /* There's no item with this ID, but there could be an item with a range that covers this row */ + if (!item && group->lg_list_in_use) { + if (index > 0) { + int count; + + item = group->lg_list + index - 1; + + count = item->li_count; + if (item->li_count == XT_TEMP_LOCK_BYTES) + count = 1; + + if (row_id >= item->li_row_id + count * XT_ROW_LOCK_GROUP_COUNT) + item = NULL; + } + } + + if (item) { + /* Item already exists. */ + if (item->li_thread_id == lw->lw_thread->t_id) { + /* Already have a permanent lock: */ + *result = XT_NO_LOCK; + lw->lw_curr_lock = XT_NO_LOCK; + return OK; + } + /* {REMOVE-LOCKS} + * This must be valid because a thread must remove + * the locks before it frees its st_xact_data structure, + * xt_thr_array entry must also be valid, because + * transaction must be ended before the thread is + * killed. + */ + *result = item->li_count == XT_TEMP_LOCK_BYTES ? XT_TEMP_LOCK : XT_PERM_LOCK; + lw->lw_xn_id = xt_thr_array[item->li_thread_id]->st_xact_data->xd_start_xn_id; + lw->lw_curr_lock = *result; + return OK; + } + + /* Add the lock: */ + XT_MEMMOVE(group->lg_list, &group->lg_list[index+1], + &group->lg_list[index], (group->lg_list_in_use - index) * sizeof(XTLockItemRec)); + group->lg_list[index].li_row_id = row_id; + group->lg_list[index].li_count = XT_TEMP_LOCK_BYTES; + group->lg_list[index].li_thread_id = lw->lw_thread->t_id; + group->lg_list_in_use++; + +#ifdef XT_TRACE_LOCKS + xt_ttracef(ot->ot_thread, "set temp lock row=%d setby=%s\n", (int) row_id, xt_get_self()->t_name); +#endif +#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY + check_rowlock_group(group); +#endif + *result = XT_NO_LOCK; + lw->lw_ot->ot_temp_row_lock = row_id; + lw->lw_curr_lock = XT_NO_LOCK; + return OK; +} + +void XTRowLocks::rl_grant_locks(XTLockGroupPtr group, XTThreadPtr thread) +{ + XTLockWaitPtr lw, lw_next, lw_prev; + int result; + xtThreadID lw_thd_id; + + thread->st_thread_list_count = 0; + lw = group->lg_wait_queue; + while (lw) { + lw_next = lw->lw_next; + lw_prev = lw->lw_prev; + lw_thd_id = lw->lw_thread->t_id; + /* NOTE: after lw_curr_lock is changed, lw may no longer be referenced + * by this function!!! + */ + if (!rl_lock_row(group, lw, &lw->lw_thread->st_lock_list, &result)) { + /* We transfer the error to the other thread! */ + XTThreadPtr self = xt_get_self(); + + result = XT_LOCK_ERR; + memcpy(&lw->lw_thread->t_exception, &self->t_exception, sizeof(XTExceptionRec)); + lw->lw_curr_lock = XT_LOCK_ERR; + } + if (result == XT_NO_LOCK || result == XT_LOCK_ERR) { + /* Remove from the wait queue: */ + if (lw_next) + lw_next->lw_prev = lw_prev; + if (lw_prev) + lw_prev->lw_next = lw_next; + if (group->lg_wait_queue == lw) + group->lg_wait_queue = lw_next; + if (group->lg_wait_queue_end == lw) + group->lg_wait_queue_end = lw_prev; + if (result == XT_NO_LOCK) { + /* Add to the thread list: */ + if (thread->st_thread_list_count == thread->st_thread_list_size) { + if (!xt_realloc_ns((void **) &thread->st_thread_list, (thread->st_thread_list_size+1) * sizeof(xtThreadID))) { + xt_xn_wakeup_thread(lw_thd_id); + goto done; + } + thread->st_thread_list_size++; + } + thread->st_thread_list[thread->st_thread_list_count] = lw_thd_id; + thread->st_thread_list_count++; + done:; + } + } + lw = lw_next; + } +} + +void XTRowLocks::xt_cancel_temp_lock(XTLockWaitPtr lw) +{ + XTLockGroupPtr group; + + group = &rl_groups[lw->lw_row_id % XT_ROW_LOCK_GROUP_COUNT]; + xt_spinlock_lock(&group->lg_lock); + if (lw->lw_curr_lock == XT_TEMP_LOCK || lw->lw_curr_lock == XT_PERM_LOCK) { + /* In case of XT_LOCK_ERR or XT_NO_LOCK, the lw structure will + * no longer be on the wait queue. + */ + XTLockWaitPtr lw_next, lw_prev; + + lw_next = lw->lw_next; + lw_prev = lw->lw_prev; + + /* Remove from the wait queue: */ + if (lw_next) + lw_next->lw_prev = lw_prev; + if (lw_prev) + lw_prev->lw_next = lw_next; + if (group->lg_wait_queue == lw) + group->lg_wait_queue = lw_next; + if (group->lg_wait_queue_end == lw) + group->lg_wait_queue_end = lw_prev; + } + xt_spinlock_unlock(&group->lg_lock); +} + +//#define QUEUE_ORDER_FIFO + +/* Try to lock a row. + * This function returns: + * XT_NO_LOCK on success. + * XT_TEMP_LOCK if there is a temporary lock on the row. + * XT_PERM_LOCK if there is a permanent lock in the row. + * XT_FAILED an error occured. + * + * If there is a lock on this row, the transaction ID of the + * locker is also returned. + * + * The caller must wait if the row is locked. If the lock is + * permanent, then the caller must wait for the transaction to + * terminate. If the lock is temporary, then the caller must + * wait for the transaction to signal that the lock has been + * released. + */ +xtBool XTRowLocks::xt_set_temp_lock(XTOpenTablePtr ot, XTLockWaitPtr lw, XTRowLockListPtr lock_list) +{ + XTLockGroupPtr group; + int result; + + if (ot->ot_temp_row_lock) { + /* Check if we don't already have this temp lock: */ + if (ot->ot_temp_row_lock == lw->lw_row_id) { + lw->lw_curr_lock = XT_NO_LOCK; + return OK; + } + + xt_make_lock_permanent(ot, lock_list); + } + + /* Add a temporary lock. */ + group = &rl_groups[lw->lw_row_id % XT_ROW_LOCK_GROUP_COUNT]; + xt_spinlock_lock(&group->lg_lock); + + if (!rl_lock_row(group, lw, lock_list, &result)) { + xt_spinlock_unlock(&group->lg_lock); + return FAILED; + } + + if (result != XT_NO_LOCK) { + /* Add the thread to the end of the thread queue: */ +#ifdef QUEUE_ORDER_FIFO + if (group->lg_wait_queue_end) { + group->lg_wait_queue_end->lw_next = lw; + lw->lw_prev = group->lg_wait_queue_end; + } + else { + group->lg_wait_queue = lw; + lw->lw_prev = NULL; + } + lw->lw_next = NULL; + group->lg_wait_queue_end = lw; +#else + XTLockWaitPtr pos = group->lg_wait_queue_end; + xtXactID xn_id = ot->ot_thread->st_xact_data->xd_start_xn_id; + + while (pos) { + if (pos->lw_thread->st_xact_data->xd_start_xn_id < xn_id) + break; + pos = pos->lw_prev; + } + if (pos) { + lw->lw_prev = pos; + lw->lw_next = pos->lw_next; + if (pos->lw_next) + pos->lw_next->lw_prev = lw; + else + group->lg_wait_queue_end = lw; + pos->lw_next = lw; + } + else { + /* Front of the queue: */ + lw->lw_prev = NULL; + lw->lw_next = group->lg_wait_queue; + if (group->lg_wait_queue) + group->lg_wait_queue->lw_prev = lw; + else + group->lg_wait_queue_end = lw; + group->lg_wait_queue = lw; + } +#endif + } + + xt_spinlock_unlock(&group->lg_lock); + return OK; +} + +/* + * Remove a temporary lock. + * + * If updated is set to TRUE this means that the row was update. + * This means that any thread waiting on the temporary lock will + * also have to wait for the transaction to quit before + * continuing. + * + * If the thread were to continue it would just hang again because + * it will discover that the transaction has updated the row. + * + * So the 'updated' flag is an optimisation which prevents the + * thread from making an unncessary retry. + */ +void XTRowLocks::xt_remove_temp_lock(XTOpenTablePtr ot, xtBool updated) +{ + xtRowID row_id; + XTLockGroupPtr group; + XTLockItemPtr item; + size_t index; + xtBool lock_granted = FALSE; + xtThreadID locking_thread_id = 0; + + if (!(row_id = ot->ot_temp_row_lock)) + return; + + group = &rl_groups[row_id % XT_ROW_LOCK_GROUP_COUNT]; + xt_spinlock_lock(&group->lg_lock); +#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY + check_rowlock_group(group); +#endif + +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "remove temp lock %d\n", (int) row_id); +#endif + item = (XTLockItemPtr) xt_bsearch(NULL, &row_id, group->lg_list, group->lg_list_in_use, sizeof(XTLockItemRec), &index, NULL, xlock_cmp_row_ids); + if (item) { + /* Item exists. */ + if (item->li_thread_id == ot->ot_thread->t_id && + item->li_count == XT_TEMP_LOCK_BYTES) { + XTLockWaitPtr lw; + + /* First check if there is some thread waiting to take over this lock: */ + lw = group->lg_wait_queue; + while (lw) { + if (lw->lw_row_id == row_id) { + lock_granted = TRUE; + break; + } + lw = lw->lw_next; + } + + if (lock_granted) { + /* Grant the lock just released... */ + XTLockWaitPtr lw_next, lw_prev; + xtXactID locking_xact_id; + + /* Store this info, lw will soon be untouchable! */ + lw_next = lw->lw_next; + lw_prev = lw->lw_prev; + locking_xact_id = lw->lw_thread->st_xact_data->xd_start_xn_id; + locking_thread_id = lw->lw_thread->t_id; + + /* Lock has moved from one thread to the next. + * change the thread holding this lock: + */ + item->li_thread_id = locking_thread_id; + + /* Remove from the wait queue: */ + if (lw_next) + lw_next->lw_prev = lw_prev; + if (lw_prev) + lw_prev->lw_next = lw_next; + if (group->lg_wait_queue == lw) + group->lg_wait_queue = lw_next; + if (group->lg_wait_queue_end == lw) + group->lg_wait_queue_end = lw_prev; + + /* If the thread that release the lock updated the + * row then we will have to wait for the transaction + * to terminate: + */ + if (updated) { + lw->lw_row_updated = TRUE; + lw->lw_updating_xn_id = ot->ot_thread->st_xact_data->xd_start_xn_id; + } + + /* The thread has the lock now: */ + lw->lw_ot->ot_temp_row_lock = row_id; + lw->lw_curr_lock = XT_NO_LOCK; + + /* Everyone after this that is waiting for the same lock is + * now waiting for a different transaction: + */ + lw = lw_next; + while (lw) { + if (lw->lw_row_id == row_id) { + lw->lw_xn_id = locking_xact_id; + lw->lw_curr_lock = XT_TEMP_LOCK; + } + lw = lw->lw_next; + } + } + else { + /* Remove the lock: */ + XT_MEMMOVE(group->lg_list, &group->lg_list[index], + &group->lg_list[index+1], (group->lg_list_in_use - index - 1) * sizeof(XTLockItemRec)); + group->lg_list_in_use--; + } + } + } +#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY + check_rowlock_group(group); +#endif + xt_spinlock_unlock(&group->lg_lock); + + ot->ot_temp_row_lock = 0; + if (lock_granted) + xt_xn_wakeup_thread(locking_thread_id); +} + +xtBool XTRowLocks::xt_make_lock_permanent(XTOpenTablePtr ot, XTRowLockListPtr lock_list) +{ + xtRowID row_id; + XTLockGroupPtr group; + XTLockItemPtr item; + size_t index; + + if (!(row_id = ot->ot_temp_row_lock)) + return OK; + +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "make lock perm %d\n", (int) ot->ot_temp_row_lock); +#endif + + /* Add to the lock list: */ + XTPermRowLockPtr locks = (XTPermRowLockPtr) lock_list->bl_data; + for (unsigned i=0; i<lock_list->bl_count; i++) { +#ifdef XT_USE_TABLE_REF + if (locks->pr_table == ot->ot_table) { +#else + if (locks->pr_tab_id == ot->ot_table->tab_id) { +#endif + locks->pr_group[row_id % XT_ROW_LOCK_GROUP_COUNT] = 1; + goto done; + } + locks++; + } + + /* Add new to lock list: */ + { + XTPermRowLockRec perm_lock; + +#ifdef XT_USE_TABLE_REF + perm_lock.pr_table = ot->ot_table; + xt_heap_reference(NULL, perm_lock.pr_table); +#else + perm_lock.pr_tab_id = ot->ot_table->tab_id; +#endif + memset(perm_lock.pr_group, 0, XT_ROW_LOCK_GROUP_COUNT); + perm_lock.pr_group[row_id % XT_ROW_LOCK_GROUP_COUNT] = 1; + if (!xt_bl_append(NULL, lock_list, &perm_lock)) { + xt_remove_temp_lock(ot, FALSE); + return FAILED; + } + } + + done: + group = &rl_groups[row_id % XT_ROW_LOCK_GROUP_COUNT]; + xt_spinlock_lock(&group->lg_lock); + + item = (XTLockItemPtr) xt_bsearch(NULL, &row_id, group->lg_list, group->lg_list_in_use, sizeof(XTLockItemRec), &index, NULL, xlock_cmp_row_ids); + ASSERT_NS(item); +#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY + check_rowlock_group(group); +#endif + if (item) { + /* Lock exists (it should!). */ + if (item->li_thread_id == ot->ot_thread->t_id && + item->li_count == XT_TEMP_LOCK_BYTES) { + if (index > 0 && + group->lg_list[index-1].li_thread_id == ot->ot_thread->t_id && + group->lg_list[index-1].li_count < XT_TEMP_LOCK_BYTES-2 && + group->lg_list[index-1].li_row_id == row_id - (XT_ROW_LOCK_GROUP_COUNT * group->lg_list[index-1].li_count)) { + group->lg_list[index-1].li_count++; + /* Combine with the left: */ + if (index + 1 < group->lg_list_in_use && + group->lg_list[index+1].li_thread_id == ot->ot_thread->t_id && + group->lg_list[index+1].li_count != XT_TEMP_LOCK_BYTES && + group->lg_list[index+1].li_row_id == row_id + XT_ROW_LOCK_GROUP_COUNT) { + /* And combine with the right */ + u_int left = group->lg_list[index-1].li_count + group->lg_list[index+1].li_count; + u_int right; + + if (left > XT_TEMP_LOCK_BYTES-1) { + right = left - (XT_TEMP_LOCK_BYTES-1); + left = XT_TEMP_LOCK_BYTES-1; + } + else + right = 0; + + group->lg_list[index-1].li_count = left; + if (right) { + /* There is something left over on the right: */ + group->lg_list[index+1].li_count = right; + group->lg_list[index+1].li_row_id = group->lg_list[index-1].li_row_id + left * XT_ROW_LOCK_GROUP_COUNT; + XT_MEMMOVE(group->lg_list, &group->lg_list[index], + &group->lg_list[index+1], (group->lg_list_in_use - index - 1) * sizeof(XTLockItemRec)); + group->lg_list_in_use--; + } + else { + XT_MEMMOVE(group->lg_list, &group->lg_list[index], + &group->lg_list[index+2], (group->lg_list_in_use - index - 2) * sizeof(XTLockItemRec)); + group->lg_list_in_use -= 2; + } + } + else { + XT_MEMMOVE(group->lg_list, &group->lg_list[index], + &group->lg_list[index+1], (group->lg_list_in_use - index - 1) * sizeof(XTLockItemRec)); + group->lg_list_in_use--; + } + } + else if (index + 1 < group->lg_list_in_use && + group->lg_list[index+1].li_thread_id == ot->ot_thread->t_id && + group->lg_list[index+1].li_count < XT_TEMP_LOCK_BYTES-2 && + group->lg_list[index+1].li_row_id == row_id + XT_ROW_LOCK_GROUP_COUNT) { + /* Combine with the right: */ + group->lg_list[index+1].li_count++; + group->lg_list[index+1].li_row_id = row_id; + XT_MEMMOVE(group->lg_list, &group->lg_list[index], + &group->lg_list[index+1], (group->lg_list_in_use - index - 1) * sizeof(XTLockItemRec)); + group->lg_list_in_use--; + } + else + group->lg_list[index].li_count = 1; + } + } +#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY + check_rowlock_group(group); +#endif + xt_spinlock_unlock(&group->lg_lock); + + ot->ot_temp_row_lock = 0; + return OK; +} + +xtBool xt_init_row_locks(XTRowLocksPtr rl) +{ + for (int i=0; i<XT_ROW_LOCK_GROUP_COUNT; i++) { + xt_spinlock_init_with_autoname(NULL, &rl->rl_groups[i].lg_lock); + rl->rl_groups[i].lg_wait_queue = NULL; + rl->rl_groups[i].lg_list_size = 0; + rl->rl_groups[i].lg_list_in_use = 0; + rl->rl_groups[i].lg_list = NULL; + } + return OK; +} + +void xt_exit_row_locks(XTRowLocksPtr rl __attribute__((unused))) +{ + for (int i=0; i<XT_ROW_LOCK_GROUP_COUNT; i++) { + xt_spinlock_free(NULL, &rl->rl_groups[i].lg_lock); + rl->rl_groups[i].lg_wait_queue = NULL; + rl->rl_groups[i].lg_list_size = 0; + rl->rl_groups[i].lg_list_in_use = 0; + if (rl->rl_groups[i].lg_list) { + xt_free_ns(rl->rl_groups[i].lg_list); + rl->rl_groups[i].lg_list = NULL; + } + } +} + +/* + * ----------------------------------------------------------------------- + * ROW LOCKS, HASH BASED + */ +#else // XT_USE_LIST_BASED_ROW_LOCKS + +void XTRowLockList::old_xt_remove_all_locks(struct XTDatabase *db, xtThreadID thd_id) +{ +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "remove all locks\n"); +#endif + if (!bl_count) + return; + + int pgroup; + xtTableID ptab_id; + XTPermRowLockPtr plock; + XTOpenTablePtr pot = NULL; + + plock = (XTPermRowLockPtr) &bl_data[bl_count * bl_item_size]; + for (u_int i=0; i<bl_count; i++) { + plock--; + pgroup = plock->pr_group; + ptab_id = plock->pr_tab_id; + if (pot) { + if (pot->ot_table->tab_id == ptab_id) + goto remove_lock; + xt_db_return_table_to_pool_ns(pot); + pot = NULL; + } + + if (!xt_db_open_pool_table_ns(&pot, db, ptab_id)) { + /* Should not happen, but just in case, we just don't + * remove the lock. We will probably end up with a deadlock + * somewhere. + */ + xt_log_and_clear_exception_ns(); + goto skip_remove_lock; + } + if (!pot) + /* Can happen of the table has been dropped: */ + goto skip_remove_lock; + + remove_lock: +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "remove lock group=%d\n", pgroup); +#endif + pot->ot_table->tab_locks.tab_row_locks[pgroup] = NULL; + pot->ot_table->tab_locks.tab_lock_perm[pgroup] = 0; + skip_remove_lock:; + } + bl_count = 0; + + if (pot) + xt_db_return_table_to_pool_ns(pot); +} + +/* Try to lock a row. + * This function returns: + * XT_NO_LOCK on success. + * XT_TEMP_LOCK if there is a temporary lock on the row. + * XT_PERM_LOCK if there is a permanent lock in the row. + * + * If there is a lock on this row, the transaction ID of the + * locker is also returned. + * + * The caller must wait if the row is locked. If the lock is + * permanent, then the caller must wait for the transaction to + * terminate. If the lock is temporary, then the caller must + * wait for the transaction to signal that the lock has been + * released. + */ +int XTRowLocks::old_xt_set_temp_lock(XTOpenTablePtr ot, xtRowID row, xtXactID *xn_id, XTRowLockListPtr lock_list) +{ + int group; + XTXactDataPtr xact, my_xact; + + if (ot->ot_temp_row_lock) { + /* Check if we don't already have this temp lock: */ + if (ot->ot_temp_row_lock == row) { + gl->lw_curr_lock = XT_NO_LOCK; + return XT_NO_LOCK; + } + + xt_make_lock_permanent(ot, lock_list); + } + + my_xact = ot->ot_thread->st_xact_data; + group = row % XT_ROW_LOCK_COUNT; + if ((xact = tab_row_locks[group])) { + if (xact == my_xact) + return XT_NO_LOCK; + *xn_id = xact->xd_start_xn_id; + return tab_lock_perm[group] ? XT_PERM_LOCK : XT_TEMP_LOCK; + } + + tab_row_locks[row % XT_ROW_LOCK_COUNT] = my_xact; + +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "set temp lock %d group=%d for %s\n", (int) row, (int) row % XT_ROW_LOCK_COUNT, ot->ot_thread->t_name); +#endif + ot->ot_temp_row_lock = row; + return XT_NO_LOCK; +} + +/* Just check if there is a lock on the row. + * This function returns: + * XT_NO_LOCK if there is no lock. + * XT_TEMP_LOCK if there is a temporary lock on the row. + * XT_PERM_LOCK if a lock is a permanent lock in the row. + */ +int XTRowLocks::old_xt_is_locked(struct XTOpenTable *ot, xtRowID row, xtXactID *xn_id) +{ + int group; + XTXactDataPtr xact; + + group = row % XT_ROW_LOCK_COUNT; + if ((xact = tab_row_locks[group])) { + if (xact == ot->ot_thread->st_xact_data) + return XT_NO_LOCK; + *xn_id = xact->xd_start_xn_id; + if (tab_lock_perm[group]) + return XT_PERM_LOCK; + return XT_TEMP_LOCK; + } + return XT_NO_LOCK; +} + +void XTRowLocks::old_xt_remove_temp_lock(XTOpenTablePtr ot) +{ + int group; + XTXactDataPtr xact, my_xact; + + if (!ot->ot_temp_row_lock) + return; + + my_xact = ot->ot_thread->st_xact_data; + group = ot->ot_temp_row_lock % XT_ROW_LOCK_COUNT; +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "remove temp lock %d group=%d\n", (int) ot->ot_temp_row_lock, (int) ot->ot_temp_row_lock % XT_ROW_LOCK_COUNT); +#endif + ot->ot_temp_row_lock = 0; + if ((xact = tab_row_locks[group])) { + if (xact == my_xact) + tab_row_locks[group] = NULL; + } + + if (ot->ot_table->tab_db->db_xn_wait_count) + xt_xn_wakeup_transactions(ot->ot_table->tab_db, ot->ot_thread); +} + +xtBool XTRowLocks::old_xt_make_lock_permanent(XTOpenTablePtr ot, XTRowLockListPtr lock_list) +{ + int group; + + if (!ot->ot_temp_row_lock) + return OK; + +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "make lock perm %d group=%d\n", (int) ot->ot_temp_row_lock, (int) ot->ot_temp_row_lock % XT_ROW_LOCK_COUNT); +#endif + /* Check if the lock is already permanent: */ + group = ot->ot_temp_row_lock % XT_ROW_LOCK_COUNT; + if (!tab_lock_perm[group]) { + XTPermRowLockRec plock; + + plock.pr_tab_id = ot->ot_table->tab_id; + plock.pr_group = group; + if (!xt_bl_append(NULL, lock_list, &plock)) { + xt_remove_temp_lock(ot); + return FAILED; + } + tab_lock_perm[group] = 1; + } + + ot->ot_temp_row_lock = 0; + return OK; +} + +/* Release this lock, and all locks gained after this lock + * on this table. + * + * The locks are only released temporarily. The will be regained + * below using regain locks. + * + * Returns: + * XT_NO_LOCK if no lock is released. + * XT_PERM_LOCK if a lock is released. + * + * Note that only permanent locks can be released in this way. + * So if the thread has a temporary lock, it will first be made + * permanent. + * + * {RELEASING-LOCKS} + * The idea of the releasing locks comes from the fact that each + * lock, locks a group of records. + * So if T1 has a lock (e.g. when doing SELECT FOR UPDATE), + * and then encounters an updated record x + * from T2, and it must wait for T2, it firsts releases the + * lock, just in case T2 tries to gain a lock on another + * record y in the same group, which will cause it to + * wait on T1. + * + * However, there are several problems with releasing + * locks. + * - It can cause a "live-lock", where another transation + * keeps getting in before. + * - It may not solve the problem in all cases because + * the SELECT FOR UPDATE has locked other record groups + * before it encountered record x. + * - Further problems occur when locks are granted by + * callback: + * T1 waits for T2, because it has a lock on record x + * T2 releases the lock because it must wait for T3 + * T1 is granted the lock (but does not know about this yet) + * T2 tries to regain lock (after T3 quits) and + * must wait for T1 - DEADLOCK + * + * In general, it does not make sense to release locks + * when it can be granted again by a callback. + * + * TODO: 2 possible solutions: + * - Do not lock groups, lock rows. + * UPDATE INTENSION ROW LOCK + * - Use multiple lock types: + * UPDATE INTENSION LOCK (required first) + * SHARED UPDATE LOCK (used by INSERT or DELETE) + * EXCLUSIVE UPDATE LOCK (used by SELECT FOR UPDATE) + * + * Temporary solution. Do not release any locks. +int XTRowLocks::xt_release_locks(struct XTOpenTable *ot, xtRowID row, XTRowLockListPtr lock_list) + */ + +/* + * Regain a lock previously held. This function regains locks + * released by xt_release_locks(). + * + * It will return lock_type and xn_id if the row is locked, and therefore + * regain cannot continue. In this case, the caller must wait. + * It returns XT_NO_LOCK if there are no more locks to be regained. + * + * Locks are always regained in the order in which they were originally + * taken. +xtBool XTRowLocks::xt_regain_locks(struct XTOpenTable *ot, int *lock_type, xtXactID *xn_id, XTRowLockListPtr lock_list) + */ + +xtBool old_xt_init_row_locks(XTRowLocksPtr rl) +{ + memset(rl->tab_lock_perm, 0, XT_ROW_LOCK_COUNT); + memset(rl->tab_row_locks, 0, XT_ROW_LOCK_COUNT * sizeof(XTXactDataPtr)); + return OK; +} + +void old_xt_exit_row_locks(XTRowLocksPtr rl __attribute__((unused))) +{ +} + +#endif // XT_USE_LIST_BASED_ROW_LOCKS + +xtPublic xtBool xt_init_row_lock_list(XTRowLockListPtr lock_list) +{ + lock_list->bl_item_size = sizeof(XTPermRowLockRec); + lock_list->bl_size = 0; + lock_list->bl_count = 0; + lock_list->bl_data = NULL; + return OK; +} + +xtPublic void xt_exit_row_lock_list(XTRowLockListPtr lock_list) +{ + xt_bl_set_size(NULL, lock_list, 0); +} + +/* + * ----------------------------------------------------------------------- + * SPECIAL EXCLUSIVE/SHARED (XS) LOCK + */ + +#define XT_GET1(x) *(x) +#define XT_SET4(x, y) xt_atomic_set4(x, y) +#define XT_GET4(x) xt_atomic_get4(x) + +#ifdef XT_THREAD_LOCK_INFO +xtPublic void xt_rwmutex_init(struct XTThread *self, XTRWMutexPtr xsl, const char *n) +#else +xtPublic void xt_rwmutex_init(XTThreadPtr self, XTRWMutexPtr xsl) +#endif +{ +#ifdef DEBUG + xsl->xs_lock_thread = 0; + xsl->xs_inited = 12345; +#endif + xt_init_mutex_with_autoname(self, &xsl->xs_lock); + xt_init_cond(self, &xsl->xs_cond); + XT_SET4(&xsl->xs_state, 0); + xsl->xs_xlocker = 0; + /* Must be aligned! */ + ASSERT(xt_thr_maximum_threads == xt_align_size(xt_thr_maximum_threads, XT_XS_LOCK_ALIGN)); + xsl->x.xs_rlock = (xtWord1 *) xt_calloc(self, xt_thr_maximum_threads); +#ifdef XT_THREAD_LOCK_INFO + xsl->xs_name = n; + xt_thread_lock_info_init(&xsl->xs_lock_info, xsl); +#endif +} + +xtPublic void xt_rwmutex_free(XTThreadPtr self, XTRWMutexPtr xsl) +{ +#ifdef DEBUG + ASSERT(!xsl->xs_lock_thread); + ASSERT(xsl->xs_inited == 12345); + xsl->xs_inited = 0; +#endif + if (xsl->x.xs_rlock) + xt_free(self, (void *) xsl->x.xs_rlock); + xt_free_mutex(&xsl->xs_lock); + xt_free_cond(&xsl->xs_cond); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&xsl->xs_lock_info); +#endif +} + +xtPublic xtBool xt_rwmutex_xlock(XTRWMutexPtr xsl, xtThreadID thd_id) +{ +#ifdef DEBUG + ASSERT_NS(xsl->xs_inited == 12345); +#endif + ASSERT_NS(xt_get_self()->t_id == thd_id); + xt_lock_mutex_ns(&xsl->xs_lock); + ASSERT_NS(xsl->x.xs_rlock[thd_id] == XT_NO_LOCK); + + /* Wait for exclusive locker: */ + while (xsl->xs_xlocker) { + if (!xt_timed_wait_cond_ns(&xsl->xs_cond, &xsl->xs_lock, 10000)) { + xt_unlock_mutex_ns(&xsl->xs_lock); + return FAILED; + } + } + + /* I am the locker (set state before locker!): */ + XT_SET4(&xsl->xs_state, 0); + xsl->xs_xlocker = thd_id; + + /* Wait for all the read lockers: */ + while (xsl->xs_state < xt_thr_current_max_threads) { + while (xsl->x.xs_rlock[xsl->xs_state]) { + /* {RACE-WR_MUTEX} + * Just in case of this, we keep the wait time down! + */ + if (!xt_timed_wait_cond_ns(&xsl->xs_cond, &xsl->xs_lock, 10)) { + XT_SET4(&xsl->xs_state, 0); + xsl->xs_xlocker = 0; + xt_unlock_mutex_ns(&xsl->xs_lock); + return FAILED; + } + } + /* State can be incremented in parallel by a reader + * thread! + */ + XT_SET4(&xsl->xs_state, xsl->xs_state + 1); + } + + /* I have waited for all: */ + XT_SET4(&xsl->xs_state, xt_thr_maximum_threads); + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&xsl->xs_lock_info); +#endif + + return OK; +} + +xtPublic xtBool xt_rwmutex_slock(XTRWMutexPtr xsl, xtThreadID thd_id) +{ +#ifdef DEBUG + ASSERT_NS(xsl->xs_inited == 12345); +#endif + ASSERT_NS(xt_get_self()->t_id == thd_id); + + xt_flushed_inc1(&xsl->x.xs_rlock[thd_id]); + + if (xsl->x.xs_rlock[thd_id] > 1) + return OK; + + /* Check if there could be an X locker: */ + if (xsl->xs_xlocker) { + /* There is an X locker. + * If xs_state < thd_id then the X locker will wait for me. + * So I should not wait! + */ + if (xsl->xs_state >= thd_id) { + /* If xsl->xs_state >= thd_id, then the locker has already + * checked me, and I will have to wait. + * + * Otherwise, xs_state <= thd_id, which means the + * X locker has not checked me, and will still wait for me (or + * is already waiting for me). In this case, I will have to + * take the mutex to make sure exactly how far he + * is with the checking. + */ + xt_lock_mutex_ns(&xsl->xs_lock); + while (xsl->xs_state > thd_id && xsl->xs_xlocker) { + if (!xt_timed_wait_cond_ns(&xsl->xs_cond, &xsl->xs_lock, 10000)) { + xt_unlock_mutex_ns(&xsl->xs_lock); + xsl->x.xs_rlock[thd_id]--; + return FAILED; + } + } + xt_unlock_mutex_ns(&xsl->xs_lock); + } + } + + /* There is no exclusive locker, so we have the read lock: */ + ASSERT_NS(xsl->xs_state != xt_thr_maximum_threads); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&xsl->xs_lock_info); +#endif + return OK; +} + +xtPublic xtBool xt_rwmutex_unlock(XTRWMutexPtr xsl, xtThreadID thd_id) +{ +#ifdef DEBUG + ASSERT_NS(xsl->xs_inited == 12345); +#endif + ASSERT_NS(xt_get_self()->t_id == thd_id); + if (xsl->xs_xlocker == thd_id) { + /* I have an X lock. */ + ASSERT_NS(xsl->x.xs_rlock[thd_id] == XT_NO_LOCK); + ASSERT_NS(xsl->xs_state == xt_thr_maximum_threads); + XT_SET4(&xsl->xs_state, 0); + xsl->xs_xlocker = 0; + xt_unlock_mutex_ns(&xsl->xs_lock); + /* Wake up any other X or shared lockers: */ + if (!xt_broadcast_cond_ns(&xsl->xs_cond)) + return FAILED; + } + else { + /* I have a shared lock: */ + ASSERT_NS(xsl->x.xs_rlock[thd_id] > 0); + ASSERT_NS(xsl->xs_state != xt_thr_maximum_threads); /* TODO: PMC - HOW can this fail?! - but it does? */ + if (xsl->x.xs_rlock[thd_id] > 1) + xsl->x.xs_rlock[thd_id]--; + else { + /* {RACE-WR_MUTEX}. + * A BUG FIX: + * + * Previously I was checking "xsl->xs_xlocker" after, + * descrementing the READ lock. + * + * This resulted in a race condition that could cause the + * unlocking reader to hang in xt_lock_mutex_ns(). + * This was because the X locker, grabbed the mutex (xs_lock) + * but did not wait for the reader. + * + * The result was that the reader had to wait in UNLOCK + * until the X locker did an unlock! + * + * This only became obvious when it caused a deadlock (because + * the reader was waiting for the locker, which it should not + * have been, of course). + */ + if (xsl->xs_xlocker) { + xt_lock_mutex_ns(&xsl->xs_lock); + if (xsl->xs_xlocker && xsl->xs_state == thd_id) { + /* If the X locker is waiting for me, + * then allow him to continue. + */ + if (!xt_broadcast_cond_ns(&xsl->xs_cond)) { + xt_unlock_mutex_ns(&xsl->xs_lock); + return FAILED; + } + } + xt_flushed_dec1(&xsl->x.xs_rlock[thd_id]); + xt_unlock_mutex_ns(&xsl->xs_lock); + } + else + /* {RACE-WR_MUTEX} + * There is a race condition between the check above, and the + * the decrement here. + * + * However, if I check xsl->xs_xlocker afterwards, and then + * try to get the lock xs_lock, I could hand for the duration + * of the X lock. + */ + xt_flushed_dec1(&xsl->x.xs_rlock[thd_id]); + } + } +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&xsl->xs_lock_info); +#endif + return OK; +} + +/* + * ----------------------------------------------------------------------- + * SPIN LOCK + */ + +#ifdef XT_THREAD_LOCK_INFO +xtPublic void xt_spinlock_init(XTThreadPtr self __attribute__((unused)), XTSpinLockPtr spl, const char *n) +#else +xtPublic void xt_spinlock_init(XTThreadPtr self __attribute__((unused)), XTSpinLockPtr spl) +#endif +{ + spl->spl_lock = 0; +#ifdef XT_SPL_DEFAULT + xt_init_mutex(self, &spl->spl_mutex); +#endif +#ifdef DEBUG + spl->spl_locker = 0; +#endif +#ifdef XT_THREAD_LOCK_INFO + spl->spl_name = n; + xt_thread_lock_info_init(&spl->spl_lock_info, spl); +#endif +} + +xtPublic void xt_spinlock_free(XTThreadPtr self __attribute__((unused)), XTSpinLockPtr spl __attribute__((unused))) +{ +#ifdef XT_SPL_DEFAULT + xt_free_mutex(&spl->spl_mutex); +#endif +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&spl->spl_lock_info); +#endif +} + +xtPublic xtBool xt_spinlock_spin(XTSpinLockPtr spl) +{ + volatile xtWord4 *lck = &spl->spl_lock; + + for (;;) { + for (int i=0; i<10; i++) { + /* Check the lock variable: */ + if (!*lck) { + /* Try to get the lock: */ + if (!xt_spinlock_set(spl)) + return OK; + } + } + + /* Go to "sleep" */ + xt_critical_wait(); + } + + return OK; +} + +#ifdef DEBUG +xtPublic void xt_spinlock_set_thread(XTSpinLockPtr spl) +{ + spl->spl_locker = xt_get_self(); +} +#endif + +/* + * ----------------------------------------------------------------------- + * FAST LOCK + */ + +#ifdef XT_THREAD_LOCK_INFO +xtPublic void xt_fastlock_init(XTThreadPtr self, XTFastLockPtr fal, const char *n) +#else +xtPublic void xt_fastlock_init(XTThreadPtr self, XTFastLockPtr fal) +#endif +{ + xt_spinlock_init_with_autoname(self, &fal->fal_spinlock); + xt_spinlock_init_with_autoname(self, &fal->fal_wait_lock); + for (u_int i=0; i<XT_FAST_LOCK_MAX_WAIT; i++) + fal->fal_wait_list[i] = NULL; + fal->fal_wait_count = 0; + fal->fal_wait_wakeup = 0; + fal->fal_wait_alloc = 0; +#ifdef XT_THREAD_LOCK_INFO + fal->fal_name = n; + xt_thread_lock_info_init(&fal->fal_lock_info, fal); +#endif +} + +xtPublic void xt_fastlock_free(XTThreadPtr self, XTFastLockPtr fal) +{ + xt_spinlock_free(self, &fal->fal_spinlock); + xt_spinlock_free(self, &fal->fal_wait_lock); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&fal->fal_lock_info); +#endif +} + +xtPublic xtBool xt_fastlock_spin(XTFastLockPtr fal, XTThreadPtr thread) +{ + volatile xtWord4 *lck = &fal->fal_spinlock.spl_lock; + + do { + for (int i=0; i<10; i++) { + /* Check the lock variable: */ + if (!*lck) { + /* Try to get the lock: */ + if (!xt_spinlock_set(&fal->fal_spinlock)) { + fal->fal_locker = thread; + return OK; + } + } + } + + for (int i=0; i<10; i++) { + xt_critical_wait(); + if (!*lck) { + /* Try to get the lock: */ + if (!xt_spinlock_set(&fal->fal_spinlock)) { + fal->fal_locker = thread; + return OK; + } + } + } + + /* Wait for a wakeup */ + xt_spinlock_lock(&fal->fal_wait_lock); + if (fal->fal_wait_count == XT_FAST_LOCK_MAX_WAIT) { + xt_register_ulxterr(XT_REG_CONTEXT, XT_ERR_TOO_MANY_WAITERS, (u_long) XT_FAST_LOCK_MAX_WAIT+1); + xt_spinlock_unlock(&fal->fal_wait_lock); + return FAILED; + } + while (fal->fal_wait_list[fal->fal_wait_alloc]) + fal->fal_wait_alloc = (fal->fal_wait_alloc + 1) % XT_FAST_LOCK_MAX_WAIT; + fal->fal_wait_list[fal->fal_wait_alloc] = thread; + fal->fal_wait_alloc = (fal->fal_wait_alloc + 1) % XT_FAST_LOCK_MAX_WAIT; + fal->fal_wait_count++; + xt_lock_thread(thread); + xt_spinlock_unlock(&fal->fal_wait_lock); + if (!xt_wait_thread(thread)) { + xt_unlock_thread(thread); + if (fal->fal_locker == thread) + xt_fastlock_unlock(fal, thread); + return FAILED; + } + xt_unlock_thread(thread); + } while (fal->fal_locker != thread); + return OK; +} + +/* Wake up one of the waiters. */ +xtPublic void xt_fastlock_wakeup(XTFastLockPtr fal) +{ + xt_spinlock_lock(&fal->fal_wait_lock); + if (fal->fal_wait_count) { + XTThreadPtr thread; + + /* Find a waiting thread, and give it the exclusive lock: */ + while (!fal->fal_wait_list[fal->fal_wait_wakeup]) + fal->fal_wait_wakeup = (fal->fal_wait_wakeup + 1) % XT_FAST_LOCK_MAX_WAIT; + thread = fal->fal_wait_list[fal->fal_wait_wakeup]; + fal->fal_wait_list[fal->fal_wait_wakeup] = NULL; + fal->fal_wait_wakeup = (fal->fal_wait_wakeup + 1) % XT_FAST_LOCK_MAX_WAIT; + fal->fal_wait_count--; + fal->fal_locker = thread; + + xt_lock_thread(thread); + xt_spinlock_unlock(&fal->fal_wait_lock); + xt_signal_thread(thread); + xt_unlock_thread(thread); + } + else { + xt_spinlock_unlock(&fal->fal_wait_lock); + fal->fal_locker = NULL; + xt_spinlock_reset(&fal->fal_spinlock); + } +} + +/* + * ----------------------------------------------------------------------- + * READ/WRITE SPIN LOCK + */ + +#ifdef XT_THREAD_LOCK_INFO +xtPublic void xt_spinrwlock_init(struct XTThread *self, XTSpinRWLockPtr srw, const char *name) +#else +xtPublic void xt_spinrwlock_init(struct XTThread *self, XTSpinRWLockPtr srw) +#endif +{ + xt_spinlock_init_with_autoname(self, &srw->srw_lock); + xt_spinlock_init_with_autoname(self, &srw->srw_state_lock); + srw->srw_state = 0; + srw->srw_xlocker = 0; + /* Must be aligned! */ + ASSERT(xt_thr_maximum_threads == xt_align_size(xt_thr_maximum_threads, XT_XS_LOCK_ALIGN)); + srw->x.srw_rlock = (xtWord1 *) xt_calloc(self, xt_thr_maximum_threads); +#ifdef XT_THREAD_LOCK_INFO + srw->srw_name = name; + xt_thread_lock_info_init(&srw->srw_lock_info, srw); +#endif +} + +xtPublic void xt_spinrwlock_free(struct XTThread *self, XTSpinRWLockPtr srw) +{ + if (srw->x.srw_rlock) + xt_free(self, (void *) srw->x.srw_rlock); + xt_spinlock_free(self, &srw->srw_lock); + xt_spinlock_free(self, &srw->srw_state_lock); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&srw->srw_lock_info); +#endif +} + +xtPublic xtBool xt_spinrwlock_xlock(XTSpinRWLockPtr srw, xtThreadID thd_id) +{ + xt_spinlock_lock(&srw->srw_lock); + ASSERT_NS(srw->x.srw_rlock[thd_id] == XT_NO_LOCK); + + xt_spinlock_lock(&srw->srw_state_lock); + + /* Set the state before xlocker (dirty read!) */ + srw->srw_state = 0; + + /* I am the locker: */ + srw->srw_xlocker = thd_id; + + /* Wait for all the read lockers: */ + while (srw->srw_state < xt_thr_current_max_threads) { + while (srw->x.srw_rlock[srw->srw_state]) { + xt_spinlock_unlock(&srw->srw_state_lock); + /* Wait for this reader, during this time, the reader + * himself, may increment the state. */ + xt_critical_wait(); + xt_spinlock_lock(&srw->srw_state_lock); + } + /* State can be incremented in parallel by a reader + * thread! + */ + srw->srw_state++; + } + + /* I have waited for all: */ + srw->srw_state = xt_thr_maximum_threads; + + xt_spinlock_unlock(&srw->srw_state_lock); + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&srw->srw_lock_info); +#endif + + return OK; +} + +xtPublic xtBool xt_spinrwlock_slock(XTSpinRWLockPtr srw, xtThreadID thd_id) +{ + ASSERT_NS(srw->x.srw_rlock[thd_id] == XT_NO_LOCK); + srw->x.srw_rlock[thd_id] = XT_WANT_LOCK; + /* Check if there could be an X locker: */ + if (srw->srw_xlocker) { + /* There is an X locker. + * If srw_state < thd_id then the X locker will wait for me. + * So I should not wait! + */ + if (srw->srw_state >= thd_id) { + /* If srw->srw_state >= thd_id, then the locker may have, or + * has already checked me, and I will have to wait. + * + * Otherwise, srw_state <= thd_id, which means the + * X locker has not checked me, and will still wait for me (or + * is already waiting for me). In this case, I will have to + * take the mutex to make sure exactly how far he + * is with the checking. + */ + xt_spinlock_lock(&srw->srw_state_lock); + while (srw->srw_state > thd_id && srw->srw_xlocker) { + xt_spinlock_unlock(&srw->srw_state_lock); + xt_critical_wait(); + xt_spinlock_lock(&srw->srw_state_lock); + } + xt_spinlock_unlock(&srw->srw_state_lock); + } + } + /* There is no exclusive locker, so we have the read lock: */ + srw->x.srw_rlock[thd_id] = XT_HAVE_LOCK; + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&srw->srw_lock_info); +#endif + + return OK; +} + +xtPublic xtBool xt_spinrwlock_unlock(XTSpinRWLockPtr srw, xtThreadID thd_id) +{ + if (srw->srw_xlocker == thd_id) { + /* I have an X lock. */ + ASSERT_NS(srw->srw_state == xt_thr_maximum_threads); + srw->srw_state = 0; + srw->srw_xlocker = 0; + xt_spinlock_unlock(&srw->srw_lock); + } + else { + /* I have a shared lock: */ + ASSERT_NS(srw->x.srw_rlock[thd_id] == XT_HAVE_LOCK); + ASSERT_NS(srw->srw_state != xt_thr_maximum_threads); + srw->x.srw_rlock[thd_id] = XT_NO_LOCK; + if (srw->srw_xlocker && srw->srw_state == thd_id) { + xt_spinlock_lock(&srw->srw_state_lock); + if (srw->srw_xlocker && srw->srw_state == thd_id) { + /* If the X locker is waiting for me, + * then allow him to continue. + */ + srw->srw_state = thd_id+1; + } + xt_spinlock_unlock(&srw->srw_state_lock); + } + } + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&srw->srw_lock_info); +#endif + + return OK; +} + +/* + * ----------------------------------------------------------------------- + * FAST READ/WRITE LOCK (BASED ON FAST MUTEX) + */ + +#ifdef XT_THREAD_LOCK_INFO +xtPublic void xt_fastrwlock_init(struct XTThread *self, XTFastRWLockPtr frw, const char *n) +#else +xtPublic void xt_fastrwlock_init(struct XTThread *self, XTFastRWLockPtr frw) +#endif +{ + xt_fastlock_init_with_autoname(self, &frw->frw_lock); + frw->frw_xlocker = NULL; + xt_spinlock_init_with_autoname(self, &frw->frw_state_lock); + frw->frw_state = 0; + frw->frw_read_waiters = 0; + /* Must be aligned! */ + ASSERT(xt_thr_maximum_threads == xt_align_size(xt_thr_maximum_threads, XT_XS_LOCK_ALIGN)); + frw->x.frw_rlock = (xtWord1 *) xt_calloc(self, xt_thr_maximum_threads); +#ifdef XT_THREAD_LOCK_INFO + frw->frw_name = n; + xt_thread_lock_info_init(&frw->frw_lock_info, frw); +#endif +} + +xtPublic void xt_fastrwlock_free(struct XTThread *self, XTFastRWLockPtr frw) +{ + if (frw->x.frw_rlock) + xt_free(self, (void *) frw->x.frw_rlock); + xt_fastlock_free(self, &frw->frw_lock); + xt_spinlock_free(self, &frw->frw_state_lock); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&frw->frw_lock_info); +#endif +} + +xtPublic xtBool xt_fastrwlock_xlock(XTFastRWLockPtr frw, struct XTThread *thread) +{ + xt_fastlock_lock(&frw->frw_lock, thread); + ASSERT_NS(frw->x.frw_rlock[thread->t_id] == XT_NO_LOCK); + + xt_spinlock_lock(&frw->frw_state_lock); + + /* Set the state before xlocker (dirty read!) */ + frw->frw_state = 0; + + /* I am the locker: */ + frw->frw_xlocker = thread; + + /* Wait for all the read lockers: */ + while (frw->frw_state < xt_thr_current_max_threads) { + while (frw->x.frw_rlock[frw->frw_state]) { + xt_lock_thread(thread); + xt_spinlock_unlock(&frw->frw_state_lock); + /* Wait for this reader. We rely on the reader to free + * us from this wait! */ + if (!xt_wait_thread(thread)) { + xt_unlock_thread(thread); + frw->frw_state = 0; + frw->frw_xlocker = NULL; + xt_fastlock_unlock(&frw->frw_lock, thread); + return FAILED; + } + xt_unlock_thread(thread); + xt_spinlock_lock(&frw->frw_state_lock); + } + /* State can be incremented in parallel by a reader + * thread! + */ + frw->frw_state++; + } + + /* I have waited for all: */ + frw->frw_state = xt_thr_maximum_threads; + + xt_spinlock_unlock(&frw->frw_state_lock); + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&frw->frw_lock_info); +#endif + + return OK; +} + +xtPublic xtBool xt_fastrwlock_slock(XTFastRWLockPtr frw, struct XTThread *thread) +{ + xtThreadID thd_id = thread->t_id; + + ASSERT_NS(frw->x.frw_rlock[thd_id] == XT_NO_LOCK); + frw->x.frw_rlock[thd_id] = XT_WANT_LOCK; + /* Check if there could be an X locker: */ + if (frw->frw_xlocker) { + /* There is an X locker. + * If frw_state < thd_id then the X locker will wait for me. + * So I should not wait! + */ + if (frw->frw_state >= thd_id) { + /* If frw->frw_state >= thd_id, then the locker may have, or + * has already checked me, and I will have to wait. + * + * Otherwise, frw_state <= thd_id, which means the + * X locker has not checked me, and will still wait for me (or + * is already waiting for me). In this case, I will have to + * take the mutex to make sure exactly how far he + * is with the checking. + */ + xt_spinlock_lock(&frw->frw_state_lock); + frw->frw_read_waiters++; + frw->x.frw_rlock[thd_id] = XT_WAITING; + while (frw->frw_state > thd_id && frw->frw_xlocker) { + xt_lock_thread(thread); + xt_spinlock_unlock(&frw->frw_state_lock); + if (!xt_wait_thread(thread)) { + xt_unlock_thread(thread); + xt_spinlock_lock(&frw->frw_state_lock); + frw->frw_read_waiters--; + frw->x.frw_rlock[thd_id] = XT_NO_LOCK; + xt_spinlock_unlock(&frw->frw_state_lock); + return FAILED; + } + xt_unlock_thread(thread); + xt_spinlock_lock(&frw->frw_state_lock); + } + frw->x.frw_rlock[thd_id] = XT_HAVE_LOCK; + frw->frw_read_waiters--; + xt_spinlock_unlock(&frw->frw_state_lock); + return OK; + } + } + /* There is no exclusive locker, so we have the read lock: */ + frw->x.frw_rlock[thd_id] = XT_HAVE_LOCK; + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&frw->frw_lock_info); +#endif + + return OK; +} + +xtPublic xtBool xt_fastrwlock_unlock(XTFastRWLockPtr frw, struct XTThread *thread) +{ + xtThreadID thd_id = thread->t_id; + + if (frw->frw_xlocker == thread) { + /* I have an X lock. */ + ASSERT_NS(frw->frw_state == xt_thr_maximum_threads); + frw->frw_state = 0; + frw->frw_xlocker = NULL; + + /* Wake up all read waiters: */ + if (frw->frw_read_waiters) { + xt_spinlock_lock(&frw->frw_state_lock); + if (frw->frw_read_waiters) { + XTThreadPtr target; + + for (u_int i=0; i<xt_thr_current_max_threads; i++) { + if (frw->x.frw_rlock[i] == XT_WAITING) { + if ((target = xt_thr_array[i])) { + xt_lock_thread(target); + xt_signal_thread(target); + xt_unlock_thread(target); + } + } + } + } + xt_spinlock_unlock(&frw->frw_state_lock); + } + xt_fastlock_unlock(&frw->frw_lock, thread); + } + else { + /* I have a shared lock: */ + ASSERT_NS(frw->x.frw_rlock[thd_id] == XT_HAVE_LOCK); + ASSERT_NS(frw->frw_state != xt_thr_maximum_threads); + frw->x.frw_rlock[thd_id] = XT_NO_LOCK; + if (frw->frw_xlocker && frw->frw_state == thd_id) { + xt_spinlock_lock(&frw->frw_state_lock); + if (frw->frw_xlocker && frw->frw_state == thd_id) { + /* If the X locker is waiting for me, + * then allow him to continue. + */ + frw->frw_state = thd_id+1; + /* Wake him up: */ + xt_lock_thread(frw->frw_xlocker); + xt_signal_thread(frw->frw_xlocker); + xt_unlock_thread(frw->frw_xlocker); + } + xt_spinlock_unlock(&frw->frw_state_lock); + } + } + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&frw->frw_lock_info); +#endif + + return OK; +} + +/* + * ----------------------------------------------------------------------- + * ATOMIC READ/WRITE LOCK (BASED ON ATOMIC OPERATIONS) + */ + +#ifdef XT_THREAD_LOCK_INFO +xtPublic void xt_atomicrwlock_init(struct XTThread XT_UNUSED(*self), XTAtomicRWLockPtr arw, const char *n) +#else +xtPublic void xt_atomicrwlock_init(struct XTThread XT_UNUSED(*self), XTAtomicRWLockPtr arw) +#endif +{ + arw->arw_reader_count = 0; + arw->arw_xlock_set = 0; +#ifdef XT_THREAD_LOCK_INFO + arw->arw_name = n; + xt_thread_lock_info_init(&arw->arw_lock_info, arw); +#endif +} + +xtPublic void xt_atomicrwlock_free(struct XTThread *, XTAtomicRWLockPtr XT_UNUSED(arw)) +{ +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&arw->arw_lock_info); +#endif +} + +xtPublic xtBool xt_atomicrwlock_xlock(XTAtomicRWLockPtr arw, xtThreadID XT_UNUSED(thr_id)) +{ + register xtWord2 set; + + /* First get an exclusive lock: */ + for (;;) { + set = xt_atomic_tas2(&arw->arw_xlock_set, 1); + if (!set) + break; + xt_yield(); + } + + /* Wait for the remaining readers: */ + while (arw->arw_reader_count) + xt_yield(); + +#ifdef DEBUG + arw->arw_locker = thr_id; +#endif + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&arw->arw_lock_info); +#endif + return OK; +} + +xtPublic xtBool xt_atomicrwlock_slock(XTAtomicRWLockPtr arw) +{ + register xtWord2 set; + + /* First get an exclusive lock: */ + for (;;) { + set = xt_atomic_tas2(&arw->arw_xlock_set, 1); + if (!set) + break; + xt_yield(); + } + + /* Add a reader: */ + xt_atomic_inc2(&arw->arw_reader_count); + + /* Release the xlock: */ + arw->arw_xlock_set = 0; + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&arw->arw_lock_info); +#endif + return OK; +} + +xtPublic xtBool xt_atomicrwlock_unlock(XTAtomicRWLockPtr arw, xtBool xlocked) +{ + if (xlocked) + arw->arw_xlock_set = 0; + else + xt_atomic_dec2(&arw->arw_reader_count); + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&arw->arw_lock_info); +#endif +#ifdef DEBUG + arw->arw_locker = 0; +#endif + + return OK; +} + +/* + * ----------------------------------------------------------------------- + * UNIT TESTS + */ + +#define JOB_MEMCPY 1 +#define JOB_SLEEP 2 +#define JOB_PRINT 3 +#define JOB_INCREMENT 4 +#define JOB_SNOOZE 5 + +#define LOCK_PTHREAD_RW 1 +#define LOCK_PTHREAD_MUTEX 2 +#define LOCK_FASTRW 3 +#define LOCK_SPINLOCK 4 +#define LOCK_FASTLOCK 5 +#define LOCK_SPINRWLOCK 6 +#define LOCK_FASTRWLOCK 7 +#define LOCK_ATOMICRWLOCK 8 + +typedef struct XSLockTest { + u_int xs_interations; + xtBool xs_which_lock; + xtBool xs_which_job; + xtBool xs_debug_print; + XTRWMutexRec xs_lock; + xt_rwlock_type xs_plock; + XTSpinLockRec xs_spinlock; + xt_mutex_type xs_mutex; + XTFastLockRec xs_fastlock; + XTSpinRWLockRec xs_spinrwlock; + XTFastRWLockRec xs_fastrwlock; + XTAtomicRWLockRec xs_atomicrwlock; + int xs_progress; + xtWord4 xs_inc; +} XSLockTestRec, *XSLockTestPtr; + +static void lck_free_thread_data(XTThreadPtr self __attribute__((unused)), void *data __attribute__((unused))) +{ +} + +static void lck_do_job(XTThreadPtr self, int job, XSLockTestPtr data) +{ + char b1[2048], b2[2048]; + + switch (job) { + case JOB_MEMCPY: + memcpy(b1, b2, 2048); + data->xs_inc++; + break; + case JOB_SLEEP: + xt_sleep_milli_second(1); + data->xs_inc++; + break; + case JOB_PRINT: + printf("- %s got lock\n", self->t_name); + xt_sleep_milli_second(10); + data->xs_inc++; + break; + case JOB_INCREMENT: + data->xs_inc++; + break; + case JOB_SNOOZE: + xt_sleep_milli_second(10); + data->xs_inc++; + break; + } +} + +#if 0 +static void *lck_run_dumper(XTThreadPtr self) +{ + int state = 0; + + while (state != 1) { + sleep(1); + if (state == 2) { + xt_dump_trace(); + state = 0; + } + } +} +#endif + +static void *lck_run_reader(XTThreadPtr self) +{ + XSLockTestRec *data = (XSLockTestRec *) self->t_data; + + if (data->xs_debug_print) + printf("- %s start\n", self->t_name); + for (u_int i=0; i<data->xs_interations; i++) { + if (data->xs_progress && ((i+1) % data->xs_progress) == 0) + printf("- %s %d\n", self->t_name, i+1); + if (data->xs_which_lock == LOCK_PTHREAD_RW) { + xt_slock_rwlock_ns(&data->xs_plock); + lck_do_job(self, data->xs_which_job, data); + xt_unlock_rwlock_ns(&data->xs_plock); + } + else if (data->xs_which_lock == LOCK_FASTRW) { + xt_rwmutex_slock(&data->xs_lock, self->t_id); + lck_do_job(self, data->xs_which_job, data); + xt_rwmutex_unlock(&data->xs_lock, self->t_id); + } + else if (data->xs_which_lock == LOCK_SPINRWLOCK) { + xt_spinrwlock_slock(&data->xs_spinrwlock, self->t_id); + lck_do_job(self, data->xs_which_job, data); + xt_spinrwlock_unlock(&data->xs_spinrwlock, self->t_id); + } + else if (data->xs_which_lock == LOCK_FASTRWLOCK) { + xt_fastrwlock_slock(&data->xs_fastrwlock, self); + lck_do_job(self, data->xs_which_job, data); + xt_fastrwlock_unlock(&data->xs_fastrwlock, self); + } + else if (data->xs_which_lock == LOCK_ATOMICRWLOCK) { + xt_atomicrwlock_slock(&data->xs_atomicrwlock); + lck_do_job(self, data->xs_which_job, data); + xt_atomicrwlock_unlock(&data->xs_atomicrwlock, FALSE); + } + else + ASSERT(FALSE); + } + if (data->xs_debug_print) + printf("- %s stop\n", self->t_name); + return NULL; +} + +static void *lck_run_writer(XTThreadPtr self) +{ + XSLockTestRec *data = (XSLockTestRec *) self->t_data; + + if (data->xs_debug_print) + printf("- %s start\n", self->t_name); + for (u_int i=0; i<data->xs_interations; i++) { + if (data->xs_progress && ((i+1) % data->xs_progress) == 0) + printf("- %s %d\n", self->t_name, i+1); + if (data->xs_which_lock == LOCK_PTHREAD_RW) { + xt_xlock_rwlock_ns(&data->xs_plock); + lck_do_job(self, data->xs_which_job, data); + xt_unlock_rwlock_ns(&data->xs_plock); + } + else if (data->xs_which_lock == LOCK_FASTRW) { + xt_rwmutex_xlock(&data->xs_lock, self->t_id); + lck_do_job(self, data->xs_which_job, data); + xt_rwmutex_unlock(&data->xs_lock, self->t_id); + } + else if (data->xs_which_lock == LOCK_SPINRWLOCK) { + xt_spinrwlock_xlock(&data->xs_spinrwlock, self->t_id); + lck_do_job(self, data->xs_which_job, data); + xt_spinrwlock_unlock(&data->xs_spinrwlock, self->t_id); + } + else if (data->xs_which_lock == LOCK_FASTRWLOCK) { + xt_fastrwlock_xlock(&data->xs_fastrwlock, self); + lck_do_job(self, data->xs_which_job, data); + xt_fastrwlock_unlock(&data->xs_fastrwlock, self); + } + else if (data->xs_which_lock == LOCK_ATOMICRWLOCK) { + xt_atomicrwlock_xlock(&data->xs_atomicrwlock, self->t_id); + lck_do_job(self, data->xs_which_job, data); + xt_atomicrwlock_unlock(&data->xs_atomicrwlock, TRUE); + } + else + ASSERT(FALSE); + } + if (data->xs_debug_print) + printf("- %s stop\n", self->t_name); + return NULL; +} + +static void lck_print_test(XSLockTestRec *data) +{ + switch (data->xs_which_lock) { + case LOCK_PTHREAD_RW: + printf("pthread read/write"); + break; + case LOCK_PTHREAD_MUTEX: + printf("pthread mutex"); + break; + case LOCK_FASTRW: + printf("fast read/write mutex"); + break; + case LOCK_SPINLOCK: + printf("spin mutex"); + break; + case LOCK_FASTLOCK: + printf("fast mutex"); + break; + case LOCK_SPINRWLOCK: + printf("spin read/write lock"); + break; + case LOCK_FASTRWLOCK: + printf("fast read/write lock"); + break; + case LOCK_ATOMICRWLOCK: + printf("atomic read/write lock"); + break; + } + + switch (data->xs_which_job) { + case JOB_MEMCPY: + printf(" MEMCPY 2K"); + break; + case JOB_SLEEP: + printf(" SLEEP 1/1000s"); + break; + case JOB_PRINT: + printf(" PRINT DEBUG"); + break; + case JOB_INCREMENT: + printf(" INCREMENT"); + break; + case JOB_SNOOZE: + printf(" SLEEP 1/100s"); + break; + } + + printf(" %d interations", data->xs_interations); +} + +static void *lck_run_mutex_locker(XTThreadPtr self) +{ + XSLockTestRec *data = (XSLockTestRec *) self->t_data; + + if (data->xs_debug_print) + printf("- %s start\n", self->t_name); + for (u_int i=0; i<data->xs_interations; i++) { + if (data->xs_progress && ((i+1) % data->xs_progress) == 0) + printf("- %s %d\n", self->t_name, i+1); + if (data->xs_which_lock == LOCK_PTHREAD_MUTEX) { + xt_lock_mutex_ns(&data->xs_mutex); + lck_do_job(self, data->xs_which_job, data); + xt_unlock_mutex_ns(&data->xs_mutex); + } + else if (data->xs_which_lock == LOCK_SPINLOCK) { + xt_spinlock_lock(&data->xs_spinlock); + lck_do_job(self, data->xs_which_job, data); + xt_spinlock_unlock(&data->xs_spinlock); + } + else if (data->xs_which_lock == LOCK_FASTLOCK) { + xt_fastlock_lock(&data->xs_fastlock, self); + lck_do_job(self, data->xs_which_job, data); + xt_fastlock_unlock(&data->xs_fastlock, self); + } + else + ASSERT(FALSE); + } + if (data->xs_debug_print) + printf("- %s stop\n", self->t_name); + return NULL; +} + +typedef struct LockThread { + xtThreadID id; + XTThreadPtr ptr; +} LockThreadRec, *LockThreadPtr; + +static void lck_reader_writer_test(XTThreadPtr self, XSLockTestRec *data, int reader_cnt, int writer_cnt) +{ + xtWord8 start; + LockThreadPtr threads; + int thread_cnt = reader_cnt + writer_cnt; + char buffer[40]; + + //XTThreadPtr dumper = xt_create_daemon(self, "DUMPER"); + //xt_run_thread(self, dumper, lck_run_dumper); + + printf("READ/WRITE TEST: "); + lck_print_test(data); + printf(", %d readers, %d writers\n", reader_cnt, writer_cnt); + threads = (LockThreadPtr) xt_malloc(self, thread_cnt * sizeof(LockThreadRec)); + + for (int i=0; i<thread_cnt; i++) { + sprintf(buffer, "%s%d", i < reader_cnt ? "READER-" : "WRITER-", i+1); + threads[i].ptr = xt_create_daemon(self, buffer); + threads[i].id = threads[i].ptr->t_id; + xt_set_thread_data(threads[i].ptr, data, lck_free_thread_data); + } + + start = xt_trace_clock(); + for (int i=0; i<reader_cnt; i++) + xt_run_thread(self, threads[i].ptr, lck_run_reader); + for (int i=reader_cnt; i<thread_cnt; i++) + xt_run_thread(self, threads[i].ptr, lck_run_writer); + + for (int i=0; i<thread_cnt; i++) + xt_wait_for_thread(threads[i].id, TRUE); + printf("----- %d reader, %d writer time=%s\n", reader_cnt, writer_cnt, xt_trace_clock_diff(buffer, start)); + + xt_free(self, threads); + printf("TEST RESULT = %d\n", data->xs_inc); + + //xt_wait_for_thread(dumper, TRUE); +} + +static void lck_mutex_lock_test(XTThreadPtr self, XSLockTestRec *data, int thread_cnt) +{ + xtWord8 start; + LockThreadPtr threads; + char buffer[40]; + + printf("LOCK MUTEX TEST: "); + lck_print_test(data); + printf(", %d threads\n", thread_cnt); + threads = (LockThreadPtr) xt_malloc(self, thread_cnt * sizeof(LockThreadRec)); + + for (int i=0; i<thread_cnt; i++) { + sprintf(buffer, "THREAD%d", i+1); + threads[i].ptr = xt_create_daemon(self, buffer); + threads[i].id = threads[i].ptr->t_id; + xt_set_thread_data(threads[i].ptr, data, lck_free_thread_data); + } + + start = xt_trace_clock(); + for (int i=0; i<thread_cnt; i++) + xt_run_thread(self, threads[i].ptr, lck_run_mutex_locker); + + for (int i=0; i<thread_cnt; i++) + xt_wait_for_thread(threads[i].id, TRUE); + printf("----- %d threads time=%s\n", thread_cnt, xt_trace_clock_diff(buffer, start)); + + xt_free(self, threads); + printf("TEST RESULT = %d\n", data->xs_inc); +} + +xtPublic void xt_unit_test_read_write_locks(XTThreadPtr self) +{ + XSLockTestRec data; + + memset(&data, 0, sizeof(data)); + + printf("TEST: xt_unit_test_read_write_locks\n"); + xt_rwmutex_init_with_autoname(self, &data.xs_lock); + xt_init_rwlock_with_autoname(self, &data.xs_plock); + xt_spinrwlock_init_with_autoname(self, &data.xs_spinrwlock); + xt_fastrwlock_init_with_autoname(self, &data.xs_fastrwlock); + xt_atomicrwlock_init_with_autoname(self, &data.xs_atomicrwlock); + + /** + data.xs_interations = 10; + data.xs_which_lock = LOCK_FASTRW; // LOCK_PTHREAD_RW, LOCK_FASTRW, LOCK_SPINRWLOCK, LOCK_FASTRWLOCK + data.xs_which_job = JOB_PRINT; + data.xs_debug_print = TRUE; + data.xs_progress = 0; + lck_reader_writer_test(self, &data, 4, 0); + lck_reader_writer_test(self, &data, 0, 2); + lck_reader_writer_test(self, &data, 1, 1); + lck_reader_writer_test(self, &data, 4, 2); + **/ + + /** + data.xs_interations = 4000; + data.xs_which_lock = LOCK_FASTRW; // LOCK_PTHREAD_RW, LOCK_FASTRW, LOCK_SPINRWLOCK, LOCK_FASTRWLOCK + data.xs_which_job = JOB_SLEEP; + data.xs_debug_print = TRUE; + data.xs_progress = 200; + lck_reader_writer_test(self, &data, 4, 0); + lck_reader_writer_test(self, &data, 0, 2); + lck_reader_writer_test(self, &data, 1, 1); + lck_reader_writer_test(self, &data, 4, 2); + **/ + + /**/ + data.xs_interations = 1000000; + data.xs_which_lock = LOCK_FASTRW; // LOCK_PTHREAD_RW, LOCK_FASTRW, LOCK_SPINRWLOCK, LOCK_FASTRWLOCK, LOCK_ATOMICRWLOCK + data.xs_which_job = JOB_INCREMENT; + data.xs_debug_print = FALSE; + data.xs_progress = 0; + lck_reader_writer_test(self, &data, 10, 0); + /**/ + + /** + data.xs_interations = 10000; + data.xs_which_lock = LOCK_FASTRW; // LOCK_PTHREAD_RW, LOCK_FASTRW, LOCK_SPINRWLOCK, LOCK_FASTRWLOCK + data.xs_which_job = JOB_MEMCPY; + data.xs_debug_print = FALSE; + data.xs_progress = 0; + lck_reader_writer_test(self, &data, 10, 5); + **/ + + /** + data.xs_interations = 1000; + data.xs_which_lock = LOCK_FASTRW; // LOCK_PTHREAD_RW, LOCK_FASTRW, LOCK_SPINRWLOCK, LOCK_FASTRWLOCK + data.xs_which_job = JOB_SLEEP; + data.xs_debug_print = FALSE; + data.xs_progress = 0; + lck_reader_writer_test(self, &data, 10, 5); + **/ + + xt_rwmutex_free(self, &data.xs_lock); + xt_free_rwlock(&data.xs_plock); + xt_spinrwlock_free(self, &data.xs_spinrwlock); + xt_fastrwlock_free(self, &data.xs_fastrwlock); +} + +xtPublic void xt_unit_test_mutex_locks(XTThreadPtr self) +{ + XSLockTestRec data; + + memset(&data, 0, sizeof(data)); + + printf("TEST: xt_unit_test_mutex_locks\n"); + xt_spinlock_init_with_autoname(self, &data.xs_spinlock); + xt_fastlock_init_with_autoname(self, &data.xs_fastlock); + xt_init_mutex_with_autoname(self, &data.xs_mutex); + + /**/ + data.xs_interations = 10; + data.xs_which_lock = LOCK_SPINLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX, LOCK_FASTLOCK + data.xs_which_job = JOB_PRINT; + data.xs_debug_print = TRUE; + data.xs_progress = 0; + data.xs_inc = 0; + lck_mutex_lock_test(self, &data, 2); + /**/ + + /**/ + data.xs_interations = 100000; + data.xs_which_lock = LOCK_SPINLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX, LOCK_FASTLOCK + data.xs_which_job = JOB_INCREMENT; + data.xs_debug_print = FALSE; + data.xs_progress = 0; + data.xs_inc = 0; + lck_mutex_lock_test(self, &data, 10); + /**/ + + /**/ + data.xs_interations = 10000; + data.xs_which_lock = LOCK_SPINLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX, LOCK_FASTLOCK + data.xs_which_job = JOB_MEMCPY; + data.xs_debug_print = FALSE; + data.xs_progress = 0; + data.xs_inc = 0; + lck_mutex_lock_test(self, &data, 10); + /**/ + + /**/ + data.xs_interations = 1000; + data.xs_which_lock = LOCK_FASTLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX, LOCK_FASTLOCK + data.xs_which_job = JOB_SLEEP; + data.xs_debug_print = FALSE; + data.xs_progress = 0; + data.xs_inc = 0; + lck_mutex_lock_test(self, &data, 10); + /**/ + + /**/ + data.xs_interations = 100; + data.xs_which_lock = LOCK_FASTLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX, LOCK_FASTLOCK + data.xs_which_job = JOB_SNOOZE; + data.xs_debug_print = FALSE; + data.xs_progress = 0; + data.xs_inc = 0; + lck_mutex_lock_test(self, &data, 10); + /**/ + + xt_spinlock_free(self, &data.xs_spinlock); + xt_fastlock_free(self, &data.xs_fastlock); + xt_free_mutex(&data.xs_mutex); +} + +xtPublic void xt_unit_test_create_threads(XTThreadPtr self) +{ + XTThreadPtr threads[10]; + + printf("TEST: xt_unit_test_create_threads\n"); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); + + /* Create some threads: */ + threads[0] = xt_create_daemon(self, "test0"); + printf("thread = %d\n", threads[0]->t_id); + threads[1] = xt_create_daemon(self, "test1"); + printf("thread = %d\n", threads[1]->t_id); + threads[2] = xt_create_daemon(self, "test2"); + printf("thread = %d\n", threads[2]->t_id); + threads[3] = xt_create_daemon(self, "test3"); + printf("thread = %d\n", threads[3]->t_id); + threads[4] = xt_create_daemon(self, "test4"); + printf("thread = %d\n", threads[4]->t_id); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); + + /* Max stays the same: */ + xt_free_thread(threads[3]); + xt_free_thread(threads[2]); + xt_free_thread(threads[1]); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); + + /* Fill in the gaps: */ + threads[1] = xt_create_daemon(self, "test1"); + printf("thread = %d\n", threads[1]->t_id); + threads[2] = xt_create_daemon(self, "test2"); + printf("thread = %d\n", threads[2]->t_id); + threads[3] = xt_create_daemon(self, "test3"); + printf("thread = %d\n", threads[3]->t_id); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); + + /* And add one: */ + threads[5] = xt_create_daemon(self, "test5"); + printf("thread = %d\n", threads[5]->t_id); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); + + /* Max stays the same: */ + xt_free_thread(threads[3]); + xt_free_thread(threads[2]); + xt_free_thread(threads[1]); + xt_free_thread(threads[4]); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); + + /* Recalculate the max: */ + xt_free_thread(threads[5]); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); + + /* Fill in the gaps: */ + threads[1] = xt_create_daemon(self, "test1"); + printf("thread = %d\n", threads[1]->t_id); + threads[2] = xt_create_daemon(self, "test2"); + printf("thread = %d\n", threads[2]->t_id); + threads[3] = xt_create_daemon(self, "test3"); + printf("thread = %d\n", threads[3]->t_id); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); + + xt_free_thread(threads[3]); + xt_free_thread(threads[2]); + xt_free_thread(threads[1]); + xt_free_thread(threads[0]); + printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count); +} + +#ifdef UNUSED_CODE +int XTRowLocks::xt_release_locks(struct XTOpenTable *ot, xtRowID row, XTRowLockListPtr lock_list) +{ + if (ot->ot_temp_row_lock) + xt_make_lock_permanent(ot, lock_list); + + if (!lock_list->bl_count) + return XT_NO_LOCK; + + int group, pgroup; + XTXactDataPtr xact; + xtTableID tab_id, ptab_id; + XTPermRowLockPtr plock; + XTOpenTablePtr pot = NULL; + XTRowLocksPtr row_locks; + + /* Do I have the lock? */ + group = row % XT_ROW_LOCK_COUNT; + if (!(xact = tab_row_locks[group])) + /* There is no lock: */ + return XT_NO_LOCK; + + if (xact != ot->ot_thread->st_xact_data) + /* There is a lock but it does not belong to me! */ + return XT_NO_LOCK; + + tab_id = ot->ot_table->tab_id; + plock = (XTPermRowLockPtr) &lock_list->bl_data[lock_list->bl_count * lock_list->bl_item_size]; + lock_list->rll_release_point = lock_list->bl_count; + for (u_int i=0; i<lock_list->bl_count; i++) { + plock--; + + pgroup = plock->pr_group; + ptab_id = plock->pr_tab_id; + + if (ptab_id == tab_id) + row_locks = this; + else { + if (pot) { + if (pot->ot_table->tab_id == ptab_id) + goto remove_lock; + xt_db_return_table_to_pool_ns(pot); + pot = NULL; + } + + if (!xt_db_open_pool_table_ns(&pot, ot->ot_table->tab_db, tab_id)) { + /* Should not happen, but just in case, we just don't + * remove the lock. We will probably end up with a deadlock + * somewhere. + */ + xt_log_and_clear_exception_ns(); + goto skip_remove_lock; + } + if (!pot) + /* Can happen of the table has been dropped: */ + goto skip_remove_lock; + + remove_lock: + row_locks = &pot->ot_table->tab_locks; + } + +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "release lock group=%d\n", pgroup); +#endif + row_locks->tab_row_locks[pgroup] = NULL; + row_locks->tab_lock_perm[pgroup] = 0; + skip_remove_lock:; + + lock_list->rll_release_point--; + if (tab_id == ptab_id && group == pgroup) + break; + } + + if (pot) + xt_db_return_table_to_pool_ns(pot); + return XT_PERM_LOCK; +} + +xtBool XTRowLocks::xt_regain_locks(struct XTOpenTable *ot, int *lock_type, xtXactID *xn_id, XTRowLockListPtr lock_list) +{ + int group; + XTXactDataPtr xact, my_xact; + XTPermRowLockPtr plock; + xtTableID tab_id; + XTOpenTablePtr pot = NULL; + XTRowLocksPtr row_locks = NULL; + XTTableHPtr tab = NULL; + + for (u_int i=lock_list->rll_release_point; i<lock_list->bl_count; i++) { + plock = (XTPermRowLockPtr) &lock_list->bl_data[i * lock_list->bl_item_size]; + + my_xact = ot->ot_thread->st_xact_data; + group = plock->pr_group; + tab_id = plock->pr_tab_id; + + if (tab_id == ot->ot_table->tab_id) { + row_locks = this; + tab = ot->ot_table; + } + else { + if (pot) { + if (tab_id == pot->ot_table->tab_id) + goto gain_lock; + xt_db_return_table_to_pool_ns(pot); + pot = NULL; + } + + if (!xt_db_open_pool_table_ns(&pot, ot->ot_table->tab_db, tab_id)) + return FAILED; + if (!pot) + goto no_gain_lock; + + gain_lock: + tab = pot->ot_table; + row_locks = &tab->tab_locks; + no_gain_lock:; + } + +#ifdef XT_TRACE_LOCKS + xt_ttracef(xt_get_self(), "regain lock group=%d\n", group); +#endif + XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[group % XT_ROW_RWLOCKS], ot->ot_thread); + if ((xact = row_locks->tab_row_locks[group])) { + if (xact != my_xact) { + *xn_id = xact->xd_start_xn_id; + *lock_type = row_locks->tab_lock_perm[group] ? XT_PERM_LOCK : XT_TEMP_LOCK; + goto done; + } + } + else + row_locks->tab_row_locks[group] = my_xact; + row_locks->tab_lock_perm[group] = 1; + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[group % XT_ROW_RWLOCKS], ot->ot_thread); + lock_list->rll_release_point++; + } + *lock_type = XT_NO_LOCK; + return OK; + + done: + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[group % XT_ROW_RWLOCKS], ot->ot_thread); + return OK; +} + +#endif diff --git a/storage/pbxt/src/lock_xt.h b/storage/pbxt/src/lock_xt.h new file mode 100644 index 00000000000..1019421871d --- /dev/null +++ b/storage/pbxt/src/lock_xt.h @@ -0,0 +1,699 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2008-01-24 Paul McCullagh + * + * Row lock functions. + * + * H&G2JCtL + */ +#ifndef __xt_lock_h__ +#define __xt_lock_h__ + +#include "xt_defs.h" +#include "util_xt.h" +#include "locklist_xt.h" +#include "pthread_xt.h" + +struct XTThread; +struct XTDatabase; +struct XTOpenTable; +struct XTXactData; +struct XTTable; + +/* Possibilities are 2 = align 4 or 2 = align 8 */ +#define XT_XS_LOCK_SHIFT 2 +#define XT_XS_LOCK_ALIGN (1 << XT_XS_LOCK_SHIFT) + +/* This lock is fast for reads but slow for writes. + * Use this lock in situations where you have 99% reads, + * and then some potentially long writes. + */ +typedef struct XTRWMutex { +#ifdef DEBUG + struct XTThread *xs_lock_thread; + u_int xs_inited; +#endif +#ifdef XT_THREAD_LOCK_INFO + XTThreadLockInfoRec xs_lock_info; + const char *xs_name; +#endif + xt_mutex_type xs_lock; + xt_cond_type xs_cond; + volatile xtWord4 xs_state; + volatile xtThreadID xs_xlocker; + union { +#if XT_XS_LOCK_ALIGN == 4 + volatile xtWord4 *xs_rlock_align; +#else + volatile xtWord8 *xs_rlock_align; +#endif + volatile xtWord1 *xs_rlock; + } x; +} XTRWMutexRec, *XTRWMutexPtr; + +#ifdef XT_THREAD_LOCK_INFO +#define xt_rwmutex_init_with_autoname(a,b) xt_rwmutex_init(a,b,LOCKLIST_ARG_SUFFIX(b)) +void xt_rwmutex_init(struct XTThread *self, XTRWMutexPtr xsl, const char *name); +#else +#define xt_rwmutex_init_with_autoname(a,b) xt_rwmutex_init(a,b) +void xt_rwmutex_init(struct XTThread *self, XTRWMutexPtr xsl); +#endif +void xt_rwmutex_free(struct XTThread *self, XTRWMutexPtr xsl); +xtBool xt_rwmutex_xlock(XTRWMutexPtr xsl, xtThreadID thd_id); +xtBool xt_rwmutex_slock(XTRWMutexPtr xsl, xtThreadID thd_id); +xtBool xt_rwmutex_unlock(XTRWMutexPtr xsl, xtThreadID thd_id); + +#ifdef XT_WIN +#define XT_SPL_WIN32_ASM +#else +#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) +#define XT_SPL_GNUC_X86 +#else +#define XT_SPL_DEFAULT +#endif +#endif + +#ifdef XT_SOLARIS +/* Use Sun atomic operations library + * http://docs.sun.com/app/docs/doc/816-5168/atomic-ops-3c?a=view + */ +#define XT_SPL_SOLARIS_LIB +#endif + +#ifdef XT_SPL_SOLARIS_LIB +#include <atomic.h> +#endif + +typedef struct XTSpinLock { + volatile xtWord4 spl_lock; +#ifdef XT_SPL_DEFAULT + xt_mutex_type spl_mutex; +#endif +#ifdef DEBUG + struct XTThread *spl_locker; +#endif +#ifdef XT_THREAD_LOCK_INFO + XTThreadLockInfoRec spl_lock_info; + const char *spl_name; +#endif +} XTSpinLockRec, *XTSpinLockPtr; + +#ifdef XT_THREAD_LOCK_INFO +#define xt_spinlock_init_with_autoname(a,b) xt_spinlock_init(a,b,LOCKLIST_ARG_SUFFIX(b)) +void xt_spinlock_init(struct XTThread *self, XTSpinLockPtr sp, const char *name); +#else +#define xt_spinlock_init_with_autoname(a,b) xt_spinlock_init(a,b) +void xt_spinlock_init(struct XTThread *self, XTSpinLockPtr sp); +#endif +void xt_spinlock_free(struct XTThread *self, XTSpinLockPtr sp); +xtBool xt_spinlock_spin(XTSpinLockPtr spl); +#ifdef DEBUG +void xt_spinlock_set_thread(XTSpinLockPtr spl); +#endif + +/* + * This macro is to remind me where it was safe + * to use a read lock! + */ +#define xt_lck_slock xt_spinlock_lock + +/* I call these operations flushed because the result + * is written atomically. + * But the operations themselves are not atomic! + */ +inline void xt_flushed_inc1(volatile xtWord1 *mptr) +{ +#ifdef XT_SPL_WIN32_ASM + __asm MOV ECX, mptr + __asm MOV DL, BYTE PTR [ECX] + __asm INC DL + __asm XCHG DL, BYTE PTR [ECX] +#elif defined(XT_SPL_GNUC_X86) + xtWord1 val; + + asm volatile ("movb %1,%0" : "=r" (val) : "m" (*mptr) : "memory"); + val++; + asm volatile ("xchgb %1,%0" : "=r" (val) : "m" (*mptr), "0" (val) : "memory"); +#elif defined(XT_SPL_SOLARIS_LIB) + atomic_inc_8(mptr); +#else + *mptr++; +#endif +} + +inline xtWord1 xt_flushed_dec1(volatile xtWord1 *mptr) +{ + xtWord1 val; + +#ifdef XT_SPL_WIN32_ASM + __asm MOV ECX, mptr + __asm MOV DL, BYTE PTR [ECX] + __asm DEC DL + __asm MOV val, DL + __asm XCHG DL, BYTE PTR [ECX] +#elif defined(XT_SPL_GNUC_X86) + xtWord1 val2; + + asm volatile ("movb %1, %0" : "=r" (val) : "m" (*mptr) : "memory"); + val--; + asm volatile ("xchgb %1,%0" : "=r" (val2) : "m" (*mptr), "0" (val) : "memory"); + /* Should work, but compiler makes a mistake? + * asm volatile ("xchgb %1, %0" : : "r" (val), "m" (*mptr) : "memory"); + */ +#elif defined(XT_SPL_SOLARIS_LIB) + val = atomic_dec_8_nv(mptr); +#else + val = --(*mptr); +#endif + return val; +} + +inline void xt_atomic_inc2(volatile xtWord2 *mptr) +{ +#ifdef XT_SPL_WIN32_ASM + __asm LOCK INC WORD PTR mptr +#elif defined(XT_SPL_GNUC_X86) + asm volatile ("lock; incw %0" : : "m" (*mptr) : "memory"); +#elif defined(__GNUC__) + __sync_fetch_and_add(mptr, 1); +#elif defined(XT_SPL_SOLARIS_LIB) + atomic_inc_16_nv(mptr); +#else + (*mptr)++; +#endif +} + +inline void xt_atomic_dec2(volatile xtWord2 *mptr) +{ +#ifdef XT_SPL_WIN32_ASM + __asm LOCK DEC WORD PTR mptr +#elif defined(XT_SPL_GNUC_X86) + asm volatile ("lock; decw %0" : : "m" (*mptr) : "memory"); +#elif defined(__GNUC__) + __sync_fetch_and_sub(mptr, 1); +#elif defined(XT_SPL_SOLARIS_LIB) + val1 = atomic_dec_16_nv(mptr); +#else + val1 = --(*mptr); +#endif +} + +/* Atomic test and set 2 byte word! */ +inline xtWord2 xt_atomic_tas2(volatile xtWord2 *mptr, xtWord2 val) +{ +#ifdef XT_SPL_WIN32_ASM + __asm MOV ECX, mptr + __asm MOV DX, val + __asm XCHG DX, WORD PTR [ECX] + __asm MOV val, DX +#elif defined(XT_SPL_GNUC_X86) + asm volatile ("xchgw %1,%0" : "=r" (val) : "m" (*mptr), "0" (val) : "memory"); +#elif defined(XT_SPL_SOLARIS_LIB) + val = atomic_swap_16(mptr, val); +#else + /* Yikes! */ + xtWord2 nval = val; + + val = *mptr; + *mptr = nval; +#endif + return val; +} + +inline void xt_atomic_set4(volatile xtWord4 *mptr, xtWord4 val) +{ +#ifdef XT_SPL_WIN32_ASM + __asm MOV ECX, mptr + __asm MOV EDX, val + __asm XCHG EDX, DWORD PTR [ECX] + //__asm MOV DWORD PTR [ECX], EDX +#elif defined(XT_SPL_GNUC_X86) + asm volatile ("xchgl %1,%0" : "=r" (val) : "m" (*mptr), "0" (val) : "memory"); + //asm volatile ("movl %0,%1" : "=r" (val) : "m" (*mptr) : "memory"); +#elif defined(XT_SPL_SOLARIS_LIB) + atomic_swap_32(mptr, val); +#else + *mptr = val; +#endif +} + +inline xtWord4 xt_atomic_get4(volatile xtWord4 *mptr) +{ + xtWord4 val; + +#ifdef XT_SPL_WIN32_ASM + __asm MOV ECX, mptr + __asm MOV EDX, DWORD PTR [ECX] + __asm MOV val, EDX +#elif defined(XT_SPL_GNUC_X86) + asm volatile ("movl %1,%0" : "=r" (val) : "m" (*mptr) : "memory"); +#else + val = *mptr; +#endif + return val; +} + +/* Code for test and set is derived from code by Larry Zhou and + * Google: http://code.google.com/p/google-perftools + */ +inline xtWord4 xt_spinlock_set(XTSpinLockPtr spl) +{ + xtWord4 prv; + volatile xtWord4 *lck; + + lck = &spl->spl_lock; +#ifdef XT_SPL_WIN32_ASM + __asm MOV ECX, lck + __asm MOV EDX, 1 + __asm XCHG EDX, DWORD PTR [ECX] + __asm MOV prv, EDX +#elif defined(XT_SPL_GNUC_X86) + prv = 1; + asm volatile ("xchgl %1,%0" : "=r" (prv) : "m" (*lck), "0" (prv) : "memory"); +#elif defined(XT_SPL_SOLARIS_LIB) + prv = atomic_swap_32(lck, 1); +#else + /* The default implementation just uses a mutex, and + * does not spin! */ + xt_lock_mutex_ns(&spl->spl_mutex); + /* We have the lock */ + *lck = 1; + prv = 0; +#endif +#ifdef DEBUG + if (!prv) + xt_spinlock_set_thread(spl); +#endif + return prv; +} + +inline xtWord4 xt_spinlock_reset(XTSpinLockPtr spl) +{ + xtWord4 prv; + volatile xtWord4 *lck; + +#ifdef DEBUG + spl->spl_locker = NULL; +#endif + lck = &spl->spl_lock; +#ifdef XT_SPL_WIN32_ASM + __asm MOV ECX, lck + __asm MOV EDX, 0 + __asm XCHG EDX, DWORD PTR [ECX] + __asm MOV prv, EDX +#elif defined(XT_SPL_GNUC_X86) + prv = 0; + asm volatile ("xchgl %1,%0" : "=r" (prv) : "m" (*lck), "0" (prv) : "memory"); +#elif defined(XT_SPL_SOLARIS_LIB) + prv = atomic_swap_32(lck, 0); +#else + *lck = 0; + xt_unlock_mutex_ns(&spl->spl_mutex); + prv = 1; +#endif + return prv; +} + +/* + * Return FALSE, and register an error on failure. + */ +inline xtBool xt_spinlock_lock(XTSpinLockPtr spl) +{ + if (!xt_spinlock_set(spl)) { +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&spl->spl_lock_info); +#endif + return OK; + } +#ifdef XT_THREAD_LOCK_INFO + xtBool spin_result = xt_spinlock_spin(spl); + if (spin_result) + xt_thread_lock_info_add_owner(&spl->spl_lock_info); + return spin_result; +#else + return xt_spinlock_spin(spl); +#endif +} + +inline void xt_spinlock_unlock(XTSpinLockPtr spl) +{ + xt_spinlock_reset(spl); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&spl->spl_lock_info); +#endif +} + +void xt_unit_test_read_write_locks(struct XTThread *self); +void xt_unit_test_mutex_locks(struct XTThread *self); +void xt_unit_test_create_threads(struct XTThread *self); + +#define XT_FAST_LOCK_MAX_WAIT 100 + +typedef struct XTFastLock { + XTSpinLockRec fal_spinlock; + struct XTThread *fal_locker; + + XTSpinLockRec fal_wait_lock; + u_int fal_wait_count; + u_int fal_wait_wakeup; + u_int fal_wait_alloc; + struct XTThread *fal_wait_list[XT_FAST_LOCK_MAX_WAIT]; +#ifdef XT_THREAD_LOCK_INFO + XTThreadLockInfoRec fal_lock_info; + const char *fal_name; +#endif +} XTFastLockRec, *XTFastLockPtr; + +#ifdef XT_THREAD_LOCK_INFO +#define xt_fastlock_init_with_autoname(a,b) xt_fastlock_init(a,b,LOCKLIST_ARG_SUFFIX(b)) +void xt_fastlock_init(struct XTThread *self, XTFastLockPtr spl, const char *name); +#else +#define xt_fastlock_init_with_autoname(a,b) xt_fastlock_init(a,b) +void xt_fastlock_init(struct XTThread *self, XTFastLockPtr spl); +#endif +void xt_fastlock_free(struct XTThread *self, XTFastLockPtr spl); +void xt_fastlock_wakeup(XTFastLockPtr spl); +xtBool xt_fastlock_spin(XTFastLockPtr spl, struct XTThread *thread); + +inline xtBool xt_fastlock_lock(XTFastLockPtr fal, struct XTThread *thread) +{ + if (!xt_spinlock_set(&fal->fal_spinlock)) { + fal->fal_locker = thread; +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&fal->fal_lock_info); +#endif + return OK; + } +#ifdef XT_THREAD_LOCK_INFO + xtBool spin_result = xt_fastlock_spin(fal, thread); + if (spin_result) + xt_thread_lock_info_add_owner(&fal->fal_lock_info); + return spin_result; +#else + return xt_fastlock_spin(fal, thread); +#endif +} + +inline void xt_fastlock_unlock(XTFastLockPtr fal, struct XTThread *thread __attribute__((unused))) +{ + if (fal->fal_wait_count) + xt_fastlock_wakeup(fal); + else { + fal->fal_locker = NULL; + xt_spinlock_reset(&fal->fal_spinlock); + } +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&fal->fal_lock_info); +#endif +} + +typedef struct XTSpinRWLock { + XTSpinLockRec srw_lock; + volatile xtThreadID srw_xlocker; + XTSpinLockRec srw_state_lock; + volatile u_int srw_state; + union { +#if XT_XS_LOCK_ALIGN == 4 + volatile xtWord4 *srw_rlock_align; +#else + volatile xtWord8 *srw_rlock_align; +#endif + volatile xtWord1 *srw_rlock; + } x; + +#ifdef XT_THREAD_LOCK_INFO + XTThreadLockInfoRec srw_lock_info; + const char *srw_name; +#endif + +} XTSpinRWLockRec, *XTSpinRWLockPtr; + +#ifdef XT_THREAD_LOCK_INFO +#define xt_spinrwlock_init_with_autoname(a,b) xt_spinrwlock_init(a,b,LOCKLIST_ARG_SUFFIX(b)) +void xt_spinrwlock_init(struct XTThread *self, XTSpinRWLockPtr xsl, const char *name); +#else +#define xt_spinrwlock_init_with_autoname(a,b) xt_spinrwlock_init(a,b) +void xt_spinrwlock_init(struct XTThread *self, XTSpinRWLockPtr xsl); +#endif +void xt_spinrwlock_free(struct XTThread *self, XTSpinRWLockPtr xsl); +xtBool xt_spinrwlock_xlock(XTSpinRWLockPtr xsl, xtThreadID thd_id); +xtBool xt_spinrwlock_slock(XTSpinRWLockPtr xsl, xtThreadID thd_id); +xtBool xt_spinrwlock_unlock(XTSpinRWLockPtr xsl, xtThreadID thd_id); + +typedef struct XTFastRWLock { + XTFastLockRec frw_lock; + struct XTThread *frw_xlocker; + XTSpinLockRec frw_state_lock; + volatile u_int frw_state; + u_int frw_read_waiters; + union { +#if XT_XS_LOCK_ALIGN == 4 + volatile xtWord4 *frw_rlock_align; +#else + volatile xtWord8 *frw_rlock_align; +#endif + volatile xtWord1 *frw_rlock; + } x; + +#ifdef XT_THREAD_LOCK_INFO + XTThreadLockInfoRec frw_lock_info; + const char *frw_name; +#endif + +} XTFastRWLockRec, *XTFastRWLockPtr; + +#ifdef XT_THREAD_LOCK_INFO +#define xt_fastrwlock_init_with_autoname(a,b) xt_fastrwlock_init(a,b,LOCKLIST_ARG_SUFFIX(b)) +void xt_fastrwlock_init(struct XTThread *self, XTFastRWLockPtr frw, const char *name); +#else +#define xt_fastrwlock_init_with_autoname(a,b) xt_fastrwlock_init(a,b) +void xt_fastrwlock_init(struct XTThread *self, XTFastRWLockPtr frw); +#endif + +void xt_fastrwlock_free(struct XTThread *self, XTFastRWLockPtr frw); +xtBool xt_fastrwlock_xlock(XTFastRWLockPtr frw, struct XTThread *thread); +xtBool xt_fastrwlock_slock(XTFastRWLockPtr frw, struct XTThread *thread); +xtBool xt_fastrwlock_unlock(XTFastRWLockPtr frw, struct XTThread *thread); + +typedef struct XTAtomicRWLock { + volatile xtWord2 arw_reader_count; + volatile xtWord2 arw_xlock_set; + +#ifdef XT_THREAD_LOCK_INFO + XTThreadLockInfoRec arw_lock_info; + const char *arw_name; +#endif +#ifdef DEBUG + xtThreadID arw_locker; +#endif +} XTAtomicRWLockRec, *XTAtomicRWLockPtr; + +#ifdef XT_THREAD_LOCK_INFO +#define xt_atomicrwlock_init_with_autoname(a,b) xt_atomicrwlock_init(a,b,LOCKLIST_ARG_SUFFIX(b)) +void xt_atomicrwlock_init(struct XTThread *self, XTAtomicRWLockPtr xsl, const char *name); +#else +#define xt_atomicrwlock_init_with_autoname(a,b) xt_atomicrwlock_init(a,b) +void xt_atomicrwlock_init(struct XTThread *self, XTAtomicRWLockPtr xsl); +#endif +void xt_atomicrwlock_free(struct XTThread *self, XTAtomicRWLockPtr xsl); +xtBool xt_atomicrwlock_xlock(XTAtomicRWLockPtr xsl, xtThreadID thr_id); +xtBool xt_atomicrwlock_slock(XTAtomicRWLockPtr xsl); +xtBool xt_atomicrwlock_unlock(XTAtomicRWLockPtr xsl, xtBool xlocked); + +/* + * ----------------------------------------------------------------------- + * ROW LOCKS + */ + +/* + * [(9)] + * + * These are perminent row locks. They are set on rows for 2 reasons: + * + * 1. To lock a row that is being updated. The row is locked + * when it is read, until the point that it is updated. If the row + * is not updated, the lock is removed. + * This prevents an update coming between which will cause an error + * on the first thread. + * + * 2. The locks are used to implement SELECT FOR UPDATE. + */ + +/* + * A lock that is set in order to perform an update is a temporary lock. + * This lock will be removed once the update of the record is done. + * The objective is to prevent some other thread from changine the + * record between the time the record is read and updated. This is to + * prevent unncessary "Record was updated" errors. + * + * A permanent lock is set by a SELECT FOR UPDATE. These locks are + * held until the end of the transaction. + * + * However, a SELECT FOR UPDATE will pop its lock stack before + * waiting for a transaction that has updated a record. + * This is to prevent the deadlock that can occur because a + * SELECT FOR UPDATE locks groups of records (I mean in general the + * locks used are group locks). + * + * This means a SELECT FOR UPDATE can get ahead of an UPDATE as far as + * locking is concerned. Example: + * + * Record 1,2 and 3 are in group A. + * + * T1: UPDATES record 2. + * T2: SELECT FOR UPDATE record 1, which locks group A. + * T2: SELECT FOR UPDATE record 2, which must wait for T1. + * T1: UPDATES record 3, which musts wait because of group lock A. + * + * To avoid deadlock, T2 releases its group lock A before waiting for + * record 2. It then regains the lock after waiting for record 2. + * + * (NOTE: Locks are no longer released. Please check this comment: + * {RELEASING-LOCKS} in lock_xt.cc. ) + * + * However, release group A lock mean first releasing all locks gained + * after group a lock. + * + * For example: a thread locks groups: A, B and C. To release group B + * lock the thread must release C as well. Afterwards, it must gain + * B and C again, in that order. This is to ensure that the lock + * order is NOT changed! + * + */ +#define XT_LOCK_ERR -1 +#define XT_NO_LOCK 0 +#define XT_TEMP_LOCK 1 /* A temporary lock */ +#define XT_PERM_LOCK 2 /* A permanent lock */ + +typedef struct XTRowLockList : public XTBasicList { + void xt_remove_all_locks(struct XTDatabase *db, struct XTThread *thread); +} XTRowLockListRec, *XTRowLockListPtr; + +#define XT_USE_LIST_BASED_ROW_LOCKS + +#ifdef XT_USE_LIST_BASED_ROW_LOCKS +/* + * This method stores each lock, and avoids conflicts. + * But it is a bit more expensive in time. + */ + +#ifdef DEBUG +#define XT_TEMP_LOCK_BYTES 10 +#define XT_ROW_LOCK_GROUP_COUNT 5 +#else +#define XT_TEMP_LOCK_BYTES 0xFFFF +#define XT_ROW_LOCK_GROUP_COUNT 23 +#endif + +typedef struct XTLockWait { + /* Information about the lock to be aquired: */ + struct XTThread *lw_thread; + struct XTOpenTable *lw_ot; + xtRowID lw_row_id; + + /* This is the lock currently held, and the transaction ID: */ + int lw_curr_lock; + xtXactID lw_xn_id; + + /* This is information about the updating transaction: */ + xtBool lw_row_updated; + xtXactID lw_updating_xn_id; + + /* Pointers for the lock list: */ + struct XTLockWait *lw_next; + struct XTLockWait *lw_prev; +} XTLockWaitRec, *XTLockWaitPtr; + +typedef struct XTLockItem { + xtRowID li_row_id; /* The row list is sorted in this value. */ + xtWord2 li_count; /* The number of consecutive rows locked. FFFF means a temporary lock. */ + xtWord2 li_thread_id; /* The thread that holds this lock. */ +} XTLockItemRec, *XTLockItemPtr; + +typedef struct XTLockGroup { + XTSpinLockRec lg_lock; /* A lock for the list. */ + XTLockWaitPtr lg_wait_queue; /* A queue of threads waiting for a lock in this group. */ + XTLockWaitPtr lg_wait_queue_end; /* The end of the thread queue. */ + size_t lg_list_size; /* The size of the list. */ + size_t lg_list_in_use; /* Number of slots on the list in use. */ + XTLockItemPtr lg_list; /* List of locks. */ +} XTLockGroupRec, *XTLockGroupPtr; + +struct XTLockWait; + +typedef struct XTRowLocks { + XTLockGroupRec rl_groups[XT_ROW_LOCK_GROUP_COUNT]; + + void xt_cancel_temp_lock(XTLockWaitPtr lw); + xtBool xt_set_temp_lock(struct XTOpenTable *ot, XTLockWaitPtr lw, XTRowLockListPtr lock_list); + void xt_remove_temp_lock(struct XTOpenTable *ot, xtBool updated); + xtBool xt_make_lock_permanent(struct XTOpenTable *ot, XTRowLockListPtr lock_list); + + xtBool rl_lock_row(XTLockGroupPtr group, XTLockWaitPtr lw, XTRowLockListPtr lock_list, int *result); + void rl_grant_locks(XTLockGroupPtr group, struct XTThread *thread); +#ifdef DEBUG_LOCK_QUEUE + void rl_check(XTLockWaitPtr lw); +#endif +} XTRowLocksRec, *XTRowLocksPtr; + +#define XT_USE_TABLE_REF + +typedef struct XTPermRowLock { +#ifdef XT_USE_TABLE_REF + struct XTTable *pr_table; +#else + xtTableID pr_tab_id; +#endif + xtWord1 pr_group[XT_ROW_LOCK_GROUP_COUNT]; +} XTPermRowLockRec, *XTPermRowLockPtr; + +#else // XT_ROW_LOCK_GROUP_COUNT + +/* Hash based row locking. This method allows conflics, even + * when there is none. + */ +typedef struct XTRowLocks { + xtWord1 tab_lock_perm[XT_ROW_LOCK_COUNT]; /* Byte set to 1 for permanent locks. */ + struct XTXactData *tab_row_locks[XT_ROW_LOCK_COUNT]; /* The transactions that have locked the specific rows. */ + + int xt_set_temp_lock(struct XTOpenTable *ot, xtRowID row, xtXactID *xn_id, XTRowLockListPtr lock_list); + void xt_remove_temp_lock(struct XTOpenTable *ot); + xtBool xt_make_lock_permanent(struct XTOpenTable *ot, XTRowLockListPtr lock_list); + int xt_is_locked(struct XTOpenTable *ot, xtRowID row, xtXactID *xn_id); +} XTRowLocksRec, *XTRowLocksPtr; + +typedef struct XTPermRowLock { + xtTableID pr_tab_id; + xtWord4 pr_group; +} XTPermRowLockRec, *XTPermRowLockPtr; + +#endif // XT_ROW_LOCK_GROUP_COUNT + +xtBool xt_init_row_locks(XTRowLocksPtr rl); +void xt_exit_row_locks(XTRowLocksPtr rl); + +xtBool xt_init_row_lock_list(XTRowLockListPtr rl); +void xt_exit_row_lock_list(XTRowLockListPtr rl); + +#define XT_NO_LOCK 0 +#define XT_WANT_LOCK 1 +#define XT_HAVE_LOCK 2 +#define XT_WAITING 3 + +#endif diff --git a/storage/pbxt/src/locklist_xt.cc b/storage/pbxt/src/locklist_xt.cc new file mode 100644 index 00000000000..0a3df584ba6 --- /dev/null +++ b/storage/pbxt/src/locklist_xt.cc @@ -0,0 +1,184 @@ +/* Copyright (c) 2009 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2009-01-20 Vladimir Kolesnikov + * + * H&G2JCtL + */ + +#include "xt_config.h" +#include "locklist_xt.h" + +#ifdef XT_THREAD_LOCK_INFO +#include "pthread_xt.h" +#include "thread_xt.h" +#include "trace_xt.h" + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTSpinLock *lock) +{ + ptr->li_spin_lock = lock; + ptr->li_lock_type = XTThreadLockInfo::SPIN_LOCK; +} + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTRWMutex *lock) +{ + ptr->li_rw_mutex = lock; + ptr->li_lock_type = XTThreadLockInfo::RW_MUTEX; +} + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTFastLock *lock) +{ + ptr->li_fast_lock = lock; + ptr->li_lock_type = XTThreadLockInfo::FAST_LOCK; +} + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, xt_mutex_struct *lock) +{ + ptr->li_mutex = lock; + ptr->li_lock_type = XTThreadLockInfo::MUTEX; +} + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, xt_rwlock_struct *lock) +{ + ptr->li_rwlock = lock; + ptr->li_lock_type = XTThreadLockInfo::RW_LOCK; +} + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTFastRWLock *lock) +{ + ptr->li_fast_rwlock = lock; + ptr->li_lock_type = XTThreadLockInfo::FAST_RW_LOCK; +} + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTSpinRWLock *lock) +{ + ptr->li_spin_rwlock = lock; + ptr->li_lock_type = XTThreadLockInfo::SPIN_RW_LOCK; +} + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTAtomicRWLock *lock) +{ + ptr->li_atomic_rwlock = lock; + ptr->li_lock_type = XTThreadLockInfo::ATOMIC_RW_LOCK; +} + +void xt_thread_lock_info_free(XTThreadLockInfoPtr ptr) +{ + /* TODO: check to see if it's present in a thread's list */ +} + +void xt_thread_lock_info_add_owner (XTThreadLockInfoPtr ptr) +{ + XTThread *self = xt_get_self(); + + if (!self) + return; + + if (self->st_thread_lock_count < XT_THREAD_LOCK_INFO_MAX_COUNT) { + self->st_thread_lock_list[self->st_thread_lock_count] = ptr; + self->st_thread_lock_count++; + } +} + +void xt_thread_lock_info_release_owner (XTThreadLockInfoPtr ptr) +{ + XTThread *self = xt_get_self(); + + if (!self) + return; + + for (int i = self->st_thread_lock_count - 1; i >= 0; i--) { + if (self->st_thread_lock_list[i] == ptr) { + self->st_thread_lock_count--; + memcpy(self->st_thread_lock_list + i, + self->st_thread_lock_list + i + 1, + (self->st_thread_lock_count - i)*sizeof(XTThreadLockInfoPtr)); + self->st_thread_lock_list[self->st_thread_lock_count] = NULL; + break; + } + } +} + +void xt_trace_thread_locks(XTThread *self) +{ + if (!self) + return; + + xt_ttracef(self, "thread lock list (first in list added first): "); + + if (!self->st_thread_lock_count) { + xt_trace(" <empty>\n"); + return; + } + + xt_trace("\n"); + + int count = min(self->st_thread_lock_count, XT_THREAD_LOCK_INFO_MAX_COUNT); + + for(int i = 0; i < count; i++) { + + const char *lock_type = NULL; + const char *lock_name = NULL; + + XTThreadLockInfoPtr li = self->st_thread_lock_list[i]; + + switch(li->li_lock_type) { + case XTThreadLockInfo::SPIN_LOCK: + lock_type = "XTSpinLock"; + lock_name = li->li_spin_lock->spl_name; + break; + case XTThreadLockInfo::RW_MUTEX: + lock_type = "XTRWMutex"; + lock_name = li->li_rw_mutex->xs_name; + break; + case XTThreadLockInfo::MUTEX: + lock_type = "xt_mutex_struct"; +#ifdef XT_WIN + lock_name = li->li_mutex->mt_name; +#else + lock_name = li->li_mutex->mu_name; +#endif + break; + case XTThreadLockInfo::RW_LOCK: + lock_type = "xt_rwlock_struct"; + lock_name = li->li_rwlock->rw_name; + break; + case XTThreadLockInfo::FAST_LOCK: + lock_type = "XTFastLock"; + lock_name = li->li_fast_lock->fal_name; + break; + case XTThreadLockInfo::FAST_RW_LOCK: + lock_type = "XTFastRWLock"; + lock_name = li->li_fast_rwlock->frw_name; + break; + case XTThreadLockInfo::SPIN_RW_LOCK: + lock_type = "XTSpinRWLock"; + lock_name = li->li_spin_rwlock->srw_name; + break; + case XTThreadLockInfo::ATOMIC_RW_LOCK: + lock_type = "XTAtomicRWLock"; + lock_name = li->li_atomic_rwlock->arw_name; + break; + } + + xt_ttracef(self, " #lock#%d: type: %s name: %s \n", count, lock_type, lock_name); + } +} + +#endif + diff --git a/storage/pbxt/src/locklist_xt.h b/storage/pbxt/src/locklist_xt.h new file mode 100644 index 00000000000..f0f16009ca1 --- /dev/null +++ b/storage/pbxt/src/locklist_xt.h @@ -0,0 +1,97 @@ +/* Copyright (c) 2009 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2009-01-20 Vladimir Kolesnikov + * + * H&G2JCtL + */ + +#ifndef __xt_locklist_h__ +#define __xt_locklist_h__ + +#ifdef DEBUG +//#define XT_THREAD_LOCK_INFO +#ifndef XT_WIN +/* We need DEBUG_LOCKING in order to enable pthread function wrappers */ +#define DEBUG_LOCKING +#endif +#endif + +#include "xt_defs.h" + +struct XTThread; +struct XTSpinLock; +struct XTRWMutex; +struct xt_mutex_struct; +struct xt_rwlock_struct; +struct XTFastLock; +struct XTFastRWLock; +struct XTSpinRWLock; +struct XTAtomicRWLock; + +#ifdef XT_THREAD_LOCK_INFO + +#define XT_THREAD_LOCK_INFO_MAX_COUNT 50 + +#ifdef XT_WIN +#define LOCKLIST_ARG_SUFFIX(name) #name " in " __FUNCTION__ "() at " __FILE__ ":" QUOTE(__LINE__) +#else +#define LOCKLIST_ARG_SUFFIX(name) #name " in " QUOTE(__PRETTY_FUNCTION__) "() at " QUOTE(__FILE__) ":" QUOTE(__LINE__) +#endif + +/* + * An instance of XTThreadLockInfo class keeps information about a lock kept by a thread. + * There's a list of XTThreadLockInfo instances per thread. An instance can be included + * into several thread lists in case of shared locks. + */ +typedef struct XTThreadLockInfo { + + enum LockType { SPIN_LOCK, RW_MUTEX, MUTEX, RW_LOCK, FAST_LOCK, FAST_RW_LOCK, SPIN_RW_LOCK, ATOMIC_RW_LOCK }; + + LockType li_lock_type; + + union { + XTSpinLock *li_spin_lock; // SPIN_LOCK + XTRWMutex *li_rw_mutex; // RW_MUTEX + XTFastLock *li_fast_lock; // FAST_LOCK + XTFastRWLock *li_fast_rwlock; // FAST_RW_LOCK + XTSpinRWLock *li_spin_rwlock; // SPIN_RW_LOCK + XTAtomicRWLock *li_atomic_rwlock; // ATOMIC_RW_LOCK + xt_mutex_struct *li_mutex; // MUTEX + xt_rwlock_struct *li_rwlock; // RW_LOCK + }; +} +XTThreadLockInfoRec, *XTThreadLockInfoPtr; + +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTSpinLock *lock); +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTRWMutex *lock); +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTFastLock *lock); +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTFastRWLock *lock); +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTSpinRWLock *lock); +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, XTAtomicRWLock *lock); +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, xt_mutex_struct *lock); +void xt_thread_lock_info_init(XTThreadLockInfoPtr ptr, xt_rwlock_struct *lock); +void xt_thread_lock_info_free(XTThreadLockInfoPtr ptr); + +void xt_thread_lock_info_add_owner (XTThreadLockInfoPtr ptr); +void xt_thread_lock_info_release_owner (XTThreadLockInfoPtr ptr); + +void xt_trace_thread_locks(XTThread *self); + +#endif // XT_THREAD_LOCK_INFO +#endif // __xt_locklist_h__ diff --git a/storage/pbxt/src/memory_xt.cc b/storage/pbxt/src/memory_xt.cc new file mode 100644 index 00000000000..6da8673cfcc --- /dev/null +++ b/storage/pbxt/src/memory_xt.cc @@ -0,0 +1,1138 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-04 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "pthread_xt.h" +#include "thread_xt.h" +#include "strutil_xt.h" +#include "trace_xt.h" + +#ifdef DEBUG +#define RECORD_MM +#endif + +#ifdef DEBUG + +#undef xt_malloc +#undef xt_calloc +#undef xt_realloc +#undef xt_free +#undef xt_pfree + +#undef xt_malloc_ns +#undef xt_calloc_ns +#undef xt_realloc_ns +#undef xt_free_ns + +void *xt_malloc(XTThreadPtr self, size_t size); +void *xt_calloc(XTThreadPtr self, size_t size); +xtBool xt_realloc(XTThreadPtr self, void **ptr, size_t size); +void xt_free(XTThreadPtr self, void *ptr); +void xt_pfree(XTThreadPtr self, void **ptr); + +void *xt_malloc_ns(size_t size); +void *xt_calloc_ns(size_t size); +xtBool xt_realloc_ns(void **ptr, size_t size); +void xt_free_ns(void *ptr); + +#define ADD_TOTAL_ALLOCS 4000 + +#define SHIFT_RIGHT(ptr, n) memmove(((char *) (ptr)) + sizeof(MissingMemoryRec), (ptr), (long) (n) * sizeof(MissingMemoryRec)) +#define SHIFT_LEFT(ptr, n) memmove((ptr), ((char *) (ptr)) + sizeof(MissingMemoryRec), (long) (n) * sizeof(MissingMemoryRec)) + +#define STACK_TRACE_DEPTH 4 + +typedef struct MissingMemory { + void *mm_ptr; + xtWord4 id; + xtWord2 line_nr; + xtWord2 trace_count; + c_char *mm_file; + c_char *mm_func[STACK_TRACE_DEPTH]; +} MissingMemoryRec, *MissingMemoryPtr; + +static MissingMemoryRec *mm_addresses = NULL; +static long mm_nr_in_use = 0L; +static long mm_total_allocated = 0L; +static xtWord4 mm_alloc_count = 0; +static xt_mutex_type mm_mutex; + +#ifdef RECORD_MM +static long mm_find_pointer(void *ptr); +#endif + +#endif + +/* + * ----------------------------------------------------------------------- + * STANDARD SYSTEM BASED MEMORY ALLOCATION + */ + +xtPublic void *xt_malloc(XTThreadPtr self, size_t size) +{ + void *ptr; + + if (!(ptr = malloc(size))) { + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return NULL; + } + return ptr; +} + +xtPublic xtBool xt_realloc(XTThreadPtr self, void **ptr, size_t size) +{ + void *new_ptr; + + if (!(new_ptr = realloc(*ptr, size))) { + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return FAILED; + } + *ptr = new_ptr; + return OK; +} + +xtPublic void xt_free(XTThreadPtr self __attribute__((unused)), void *ptr) +{ + free(ptr); +} + +xtPublic void *xt_calloc(XTThreadPtr self, size_t size) +{ + void *ptr; + + if ((ptr = xt_malloc(self, size))) + memset(ptr, 0, size); + return ptr; +} + +#undef xt_pfree + +xtPublic void xt_pfree(XTThreadPtr self, void **ptr) +{ + if (*ptr) { + void *p = *ptr; + + *ptr = NULL; + xt_free(self, p); + } +} + +/* + * ----------------------------------------------------------------------- + * SYSTEM MEMORY ALLOCATION WITH A THREAD + */ + +xtPublic void *xt_malloc_ns(size_t size) +{ + void *ptr; + + if (!(ptr = malloc(size))) { + xt_register_errno(XT_REG_CONTEXT, XT_ENOMEM); + return NULL; + } + return ptr; +} + +xtPublic void *xt_calloc_ns(size_t size) +{ + void *ptr; + + if (!(ptr = malloc(size))) { + xt_register_errno(XT_REG_CONTEXT, XT_ENOMEM); + return NULL; + } + memset(ptr, 0, size); + return ptr; +} + +xtPublic xtBool xt_realloc_ns(void **ptr, size_t size) +{ + void *new_ptr; + + if (!(new_ptr = realloc(*ptr, size))) + return xt_register_errno(XT_REG_CONTEXT, XT_ENOMEM); + *ptr = new_ptr; + return OK; +} + +xtPublic void xt_free_ns(void *ptr) +{ + free(ptr); +} + +#ifdef DEBUG + +/* + * ----------------------------------------------------------------------- + * MEMORY SEARCHING CODE + */ + +#define MM_THROW_ASSERTION(str) mm_throw_assertion(self, __FUNC__, __FILE__, __LINE__, str) + +static void mm_throw_assertion(XTThreadPtr self, c_char *func, c_char *file, u_int line, c_char *str) +{ + printf("***** MM:FATAL %s\n", str); + xt_throw_assertion(self, func, file, line, str); +} + +/* + * ----------------------------------------------------------------------- + * MEMORY SEARCHING CODE + */ + +static int mm_debug_ik_inc; +static int mm_debug_ik_dec; +static int mm_debug_ik_no; + +/* + * Call this function where the missing memory + * is referenced. + */ +xtPublic void mm_trace_inc(XTThreadPtr self, XTMMTraceRefPtr tr) +{ + int i; + +#ifdef RECORD_MM + if (xt_lock_mutex(self, &mm_mutex)) { + long mm; + + mm = mm_find_pointer(tr); + if (mm >= 0) + mm_addresses[mm].trace_count = 1; + xt_unlock_mutex(self, &mm_mutex); + } +#endif + mm_debug_ik_inc++; + if (tr->mm_pos < XT_MM_STACK_TRACE-1) { + tr->mm_trace[tr->mm_pos++] = self->t_name[0] == 'S' ? XT_MM_TRACE_SW_INC : XT_MM_TRACE_INC; + for (i=1; i<=XT_MM_TRACE_DEPTH; i++) { + if (self->t_call_top-i < 0) + break; + if (tr->mm_pos < XT_MM_STACK_TRACE-1) { + tr->mm_line[tr->mm_pos] = self->t_call_stack[self->t_call_top-i].cs_line; + tr->mm_trace[tr->mm_pos++] = self->t_call_stack[self->t_call_top-i].cs_func; + } + else if (tr->mm_pos < XT_MM_STACK_TRACE) + tr->mm_trace[tr->mm_pos++] = XT_MM_TRACE_ERROR; + } + } + else if (tr->mm_pos < XT_MM_STACK_TRACE) + tr->mm_trace[tr->mm_pos++] = XT_MM_TRACE_ERROR; +} + +xtPublic void mm_trace_dec(XTThreadPtr self, XTMMTraceRefPtr tr) +{ + int i; + +#ifdef RECORD_MM + if (xt_lock_mutex(self, &mm_mutex)) { + long mm; + + mm = mm_find_pointer(tr); + if (mm >= 0) + mm_addresses[mm].trace_count = 1; + xt_unlock_mutex(self, &mm_mutex); + } +#endif + mm_debug_ik_dec++; + if (tr->mm_pos < XT_MM_STACK_TRACE-1) { + tr->mm_trace[tr->mm_pos++] = self->t_name[0] == 'S' ? XT_MM_TRACE_SW_DEC : XT_MM_TRACE_DEC; + for (i=1; i<=XT_MM_TRACE_DEPTH; i++) { + if (self->t_call_top-i < 0) + break; + if (tr->mm_pos < XT_MM_STACK_TRACE-1) { + tr->mm_line[tr->mm_pos] = self->t_call_stack[self->t_call_top-i].cs_line; + tr->mm_trace[tr->mm_pos++] = self->t_call_stack[self->t_call_top-i].cs_func; + } + else if (tr->mm_pos < XT_MM_STACK_TRACE) + tr->mm_trace[tr->mm_pos++] = XT_MM_TRACE_ERROR; + } + } + else if (tr->mm_pos < XT_MM_STACK_TRACE) + tr->mm_trace[tr->mm_pos++] = XT_MM_TRACE_ERROR; +} + +xtPublic void mm_trace_init(XTThreadPtr self, XTMMTraceRefPtr tr) +{ + mm_debug_ik_no++; + tr->mm_id = (u_int) mm_debug_ik_no; + tr->mm_pos = 0; + mm_trace_inc(self, tr); +} + +xtPublic void mm_trace_print(XTMMTraceRefPtr tr) +{ + int i, cnt = 0; + + for (i=0; i<tr->mm_pos; i++) { + if (tr->mm_trace[i] == XT_MM_TRACE_INC) { + if (i > 0) + printf("\n"); + cnt++; + printf("INC (%d) ", cnt); + } + else if (tr->mm_trace[i] == XT_MM_TRACE_SW_INC) { + if (i > 0) + printf("\n"); + printf("SW-DEC (%d) ", cnt); + cnt--; + } + else if (tr->mm_trace[i] == XT_MM_TRACE_DEC) { + if (i > 0) + printf("\n"); + printf("DEC (%d) ", cnt); + cnt--; + } + else if (tr->mm_trace[i] == XT_MM_TRACE_SW_DEC) { + if (i > 0) + printf("\n"); + printf("SW-DEC (%d) ", cnt); + cnt--; + } + else if (tr->mm_trace[i] == XT_MM_TRACE_ERROR) { + if (i > 0) + printf("\n"); + printf("ERROR: Space out"); + } + else + printf("%s(%d) ", tr->mm_trace[i], (int) tr->mm_line[i]); + } + printf("\n"); +} + +/* Call this function on exit, when you know the memory is missing. */ +static void mm_debug_trace_count(XTMMTraceRefPtr tr) +{ + printf("MM Trace ID: %d\n", tr->mm_id); + mm_trace_print(tr); +} + +/* The give the sum of allocations, etc. */ +static void mm_debug_trace_sum(void) +{ + if (mm_debug_ik_no) { + printf("MM Trace INC: %d\n", mm_debug_ik_inc); + printf("MM Trace DEC: %d\n", mm_debug_ik_dec); + printf("MM Trace ALL: %d\n", mm_debug_ik_no); + } +} + +/* + * ----------------------------------------------------------------------- + * DEBUG MEMORY ALLOCATION AND HEAP CHECKING + */ + +#ifdef RECORD_MM +static long mm_find_pointer(void *ptr) +{ + register long i, n, guess; + + i = 0; + n = mm_nr_in_use; + while (i < n) { + guess = (i + n - 1) >> 1; + if (ptr == mm_addresses[guess].mm_ptr) + return(guess); + if (ptr < mm_addresses[guess].mm_ptr) + n = guess; + else + i = guess + 1; + } + return(-1); +} + +static long mm_add_pointer(void *ptr, u_int id) +{ +#pragma unused(id) + register int i, n, guess; + + if (mm_nr_in_use == mm_total_allocated) { + /* Not enough space, add more: */ + MissingMemoryRec *new_addresses; + + new_addresses = (MissingMemoryRec *) xt_calloc_ns(sizeof(MissingMemoryRec) * (mm_total_allocated + ADD_TOTAL_ALLOCS)); + if (!new_addresses) + return(-1); + + if (mm_addresses) { + memcpy(new_addresses, mm_addresses, sizeof(MissingMemoryRec) * mm_total_allocated); + free(mm_addresses); + } + + mm_addresses = new_addresses; + mm_total_allocated += ADD_TOTAL_ALLOCS; + } + + i = 0; + n = mm_nr_in_use; + while (i < n) { + guess = (i + n - 1) >> 1; + if (ptr < mm_addresses[guess].mm_ptr) + n = guess; + else + i = guess + 1; + } + + SHIFT_RIGHT(&mm_addresses[i], mm_nr_in_use - i); + mm_nr_in_use++; + mm_addresses[i].mm_ptr = ptr; + return(i); +} + +xtPublic char *mm_watch_point = 0; + +static long mm_remove_pointer(void *ptr) +{ + register int i, n, guess; + + if (mm_watch_point == ptr) + printf("Hit watch point!\n"); + + i = 0; + n = mm_nr_in_use; + while (i < n) { + guess = (i + n - 1) >> 1; + if (ptr == mm_addresses[guess].mm_ptr) + goto remove; + if (ptr < mm_addresses[guess].mm_ptr) + n = guess; + else + i = guess + 1; + } + return(-1); + + remove: + /* Decrease the number of sets, and shift left: */ + mm_nr_in_use--; + SHIFT_LEFT(&mm_addresses[guess], mm_nr_in_use - guess); + return(guess); +} + +static void mm_add_core_ptr(XTThreadPtr self, void *ptr, u_int id, u_int line, c_char *file_name) +{ + long mm; + + mm = mm_add_pointer(ptr, id); + if (mm < 0) { + MM_THROW_ASSERTION("MM ERROR: Cannot allocate table big enough!"); + return; + } + + /* Record the pointer: */ + if (mm_alloc_count >= 4115 && mm_alloc_count <= 4130) { + if (id) + mm_addresses[mm].id = id; + else + mm_addresses[mm].id = mm_alloc_count++; + } + else { + if (id) + mm_addresses[mm].id = id; + else + mm_addresses[mm].id = mm_alloc_count++; + } + mm_addresses[mm].mm_ptr = ptr; + mm_addresses[mm].line_nr = (ushort) line; + if (file_name) + mm_addresses[mm].mm_file = file_name; + else + mm_addresses[mm].mm_file = "?"; + if (self) { + for (int i=1; i<=STACK_TRACE_DEPTH; i++) { + if (self->t_call_top-i >= 0) + mm_addresses[mm].mm_func[i-1] = self->t_call_stack[self->t_call_top-i].cs_func; + else + mm_addresses[mm].mm_func[i-1] = NULL; + } + } + else { + for (int i=0; i<STACK_TRACE_DEPTH; i++) + mm_addresses[mm].mm_func[i] = NULL; + } +} + +static void mm_remove_core_ptr(void *ptr) +{ + XTThreadPtr self = NULL; + long mm; + + mm = mm_remove_pointer(ptr); + if (mm < 0) { + MM_THROW_ASSERTION("Pointer not allocated"); + return; + } +} + +static void mm_throw_assertion(MissingMemoryPtr mm_ptr, void *p, c_char *message); + +static long mm_find_core_ptr(void *ptr) +{ + long mm; + + mm = mm_find_pointer(ptr); + if (mm < 0) + mm_throw_assertion(NULL, ptr, "Pointer not allocated"); + return(mm); +} + +static void mm_replace_core_ptr(long i, void *ptr) +{ + XTThreadPtr self = NULL; + MissingMemoryRec tmp = mm_addresses[i]; + long mm; + + mm_remove_pointer(mm_addresses[i].mm_ptr); + mm = mm_add_pointer(ptr, mm_addresses[i].id); + if (mm < 0) { + MM_THROW_ASSERTION("Cannot allocate table big enough!"); + return; + } + mm_addresses[mm] = tmp; + mm_addresses[mm].mm_ptr = ptr; +} +#endif + +static void mm_throw_assertion(MissingMemoryPtr mm_ptr, void *p, c_char *message) +{ + XTThreadPtr self = NULL; + char str[200]; + + if (mm_ptr) { + sprintf(str, "MM: %08lX (#%ld) %s:%d %s", + (unsigned long) mm_ptr->mm_ptr, + (long) mm_ptr->id, + xt_last_name_of_path(mm_ptr->mm_file), + (int) mm_ptr->line_nr, + message); + } + else + sprintf(str, "MM: %08lX %s", (unsigned long) p, message); + MM_THROW_ASSERTION(str); +} + +/* + * ----------------------------------------------------------------------- + * MISSING MEMORY PUBLIC ROUTINES + */ + +#define MEM_DEBUG_HDR_SIZE offsetof(MemoryDebugRec, data) +#define MEM_TRAILER_SIZE 2 +#define MEM_HEADER 0x01010101 +#define MEM_FREED 0x03030303 +#define MEM_TRAILER_BYTE 0x02 +#define MEM_FREED_BYTE 0x03 + +typedef struct MemoryDebug { + xtWord4 check; + xtWord4 size; + char data[200]; +} MemoryDebugRec, *MemoryDebugPtr; + +static size_t mm_checkmem(XTThreadPtr self, MissingMemoryPtr mm_ptr, void *p, xtBool freeme) +{ + unsigned char *ptr = (unsigned char *) p - MEM_DEBUG_HDR_SIZE; + MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ptr; + size_t size = debug_ptr->size; + long a_value; /* Added to simplfy debugging. */ + + if (!ASSERT(p)) + return(0); + if (!ASSERT(((long) p & 1L) == 0)) + return(0); + a_value = MEM_FREED; + if (debug_ptr->check == MEM_FREED) { + mm_throw_assertion(mm_ptr, p, "Pointer already freed 'debug_ptr->check != MEM_FREED'"); + return(0); + } + a_value = MEM_HEADER; + if (debug_ptr->check != MEM_HEADER) { + mm_throw_assertion(mm_ptr, p, "Header not valid 'debug_ptr->check != MEM_HEADER'"); + return(0); + } + a_value = MEM_TRAILER_BYTE; + if (!(*((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE) == MEM_TRAILER_BYTE && + *((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE + 1L) == MEM_TRAILER_BYTE)) { + mm_throw_assertion(mm_ptr, p, "Trailer overwritten"); + return(0); + } + + if (freeme) { + debug_ptr->check = MEM_FREED; + *((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE) = MEM_FREED_BYTE; + *((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_FREED_BYTE; + + memset(((unsigned char *) ptr) + MEM_DEBUG_HDR_SIZE, 0xF5, size); + xt_free(self, ptr); + } + + return size; +} + +xtBool xt_mm_scan_core(void) +{ + long mm; + + if (!mm_addresses) + return TRUE; + + if (!xt_lock_mutex(NULL, &mm_mutex)) + return TRUE; + + for (mm=0; mm<mm_nr_in_use; mm++) { + mm_checkmem(NULL, &mm_addresses[mm], mm_addresses[mm].mm_ptr, FALSE); + } + + xt_unlock_mutex(NULL, &mm_mutex); + return TRUE; +} + +void xt_mm_memmove(void *block, void *dest, void *source, size_t size) +{ + if (block) { + MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE); + +#ifdef RECORD_MM + if (xt_lock_mutex(NULL, &mm_mutex)) { + mm_find_core_ptr(block); + xt_unlock_mutex(NULL, &mm_mutex); + } +#endif + mm_checkmem(NULL, NULL, block, FALSE); + + if (dest < block || (char *) dest > (char *) block + debug_ptr->size) + mm_throw_assertion(NULL, block, "Destination not in block"); + if ((char *) dest + size > (char *) block + debug_ptr->size) + mm_throw_assertion(NULL, block, "Copy will overwrite memory"); + } + + memmove(dest, source, size); +} + +void xt_mm_memcpy(void *block, void *dest, void *source, size_t size) +{ + if (block) { + MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE); + +#ifdef RECORD_MM + if (xt_lock_mutex(NULL, &mm_mutex)) { + mm_find_core_ptr(block); + xt_unlock_mutex(NULL, &mm_mutex); + } +#endif + mm_checkmem(NULL, NULL, block, FALSE); + + if (dest < block || (char *) dest > (char *) block + debug_ptr->size) + mm_throw_assertion(NULL, block, "Destination not in block"); + if ((char *) dest + size > (char *) block + debug_ptr->size) + mm_throw_assertion(NULL, block, "Copy will overwrite memory"); + } + + memcpy(dest, source, size); +} + +void xt_mm_memset(void *block, void *dest, int value, size_t size) +{ + if (block) { + MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE); + +#ifdef RECORD_MM + if (xt_lock_mutex(NULL, &mm_mutex)) { + mm_find_core_ptr(block); + xt_unlock_mutex(NULL, &mm_mutex); + } +#endif + mm_checkmem(NULL, NULL, block, FALSE); + + if (dest < block || (char *) dest > (char *) block + debug_ptr->size) + mm_throw_assertion(NULL, block, "Destination not in block"); + if ((char *) dest + size > (char *) block + debug_ptr->size) + mm_throw_assertion(NULL, block, "Copy will overwrite memory"); + } + + memset(dest, value, size); +} + +void *xt_mm_malloc(XTThreadPtr self, size_t size, u_int line __attribute__((unused)), c_char *file __attribute__((unused))) +{ + unsigned char *p; + + if (size > (600*1024*1024)) + mm_throw_assertion(NULL, NULL, "Very large block allocated - meaybe error"); + p = (unsigned char *) xt_malloc(self, size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE); + if (!p) + return NULL; + + memset(p, 0x55, size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE); + + ((MemoryDebugPtr) p)->check = MEM_HEADER; + ((MemoryDebugPtr) p)->size = size; + *(p + size + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE; + *(p + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE; + +#ifdef RECORD_MM + xt_lock_mutex(self, &mm_mutex); + mm_add_core_ptr(self, p + MEM_DEBUG_HDR_SIZE, 0, line, file); + xt_unlock_mutex(self, &mm_mutex); +#endif + + return p + MEM_DEBUG_HDR_SIZE; +} + +void *xt_mm_calloc(XTThreadPtr self, size_t size, u_int line __attribute__((unused)), c_char *file __attribute__((unused))) +{ + unsigned char *p; + + if (size > (500*1024*1024)) + mm_throw_assertion(NULL, NULL, "Very large block allocated - meaybe error"); + p = (unsigned char *) xt_calloc(self, size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE); + if (!p) + return NULL; + + ((MemoryDebugPtr) p)->check = MEM_HEADER; + ((MemoryDebugPtr) p)->size = size; + *(p + size + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE; + *(p + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE; + +#ifdef RECORD_MM + xt_lock_mutex(self, &mm_mutex); + mm_add_core_ptr(self, p + MEM_DEBUG_HDR_SIZE, 0, line, file); + xt_unlock_mutex(self, &mm_mutex); +#endif + + return p + MEM_DEBUG_HDR_SIZE; +} + +xtBool xt_mm_sys_realloc(XTThreadPtr self, void **ptr, size_t newsize, u_int line, c_char *file) +{ + return xt_mm_realloc(self, ptr, newsize, line, file); +} + +xtBool xt_mm_realloc(XTThreadPtr self, void **ptr, size_t newsize, u_int line, c_char *file) +{ + unsigned char *oldptr = (unsigned char *) *ptr; + size_t size; +#ifdef RECORD_MM + long mm; +#endif + unsigned char *pnew; + + if (!oldptr) { + *ptr = xt_mm_malloc(self, newsize, line, file); + return *ptr ? TRUE : FALSE; + } + +#ifdef RECORD_MM + xt_lock_mutex(self, &mm_mutex); + if ((mm = mm_find_core_ptr(oldptr)) < 0) { + xt_unlock_mutex(self, &mm_mutex); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return FAILED; + } + xt_unlock_mutex(self, &mm_mutex); +#endif + + oldptr = oldptr - MEM_DEBUG_HDR_SIZE; + size = ((MemoryDebugPtr) oldptr)->size; + + ASSERT(((MemoryDebugPtr) oldptr)->check == MEM_HEADER); + ASSERT(*((unsigned char *) oldptr + size + MEM_DEBUG_HDR_SIZE) == MEM_TRAILER_BYTE && + *((unsigned char *) oldptr + size + MEM_DEBUG_HDR_SIZE + 1L) == MEM_TRAILER_BYTE); + + /* Realloc allways moves! */ + pnew = (unsigned char *) xt_malloc(self, newsize + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE); + if (!pnew) { + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return FAILED; + } + + if (newsize > size) { + memcpy(((MemoryDebugPtr) pnew)->data, ((MemoryDebugPtr) oldptr)->data, size); + memset(((MemoryDebugPtr) pnew)->data + size, 0x55, newsize - size); + } + else + memcpy(((MemoryDebugPtr) pnew)->data, ((MemoryDebugPtr) oldptr)->data, newsize); + + ((MemoryDebugPtr) pnew)->check = MEM_HEADER; + ((MemoryDebugPtr) pnew)->size = newsize; + *(pnew + newsize + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE; + *(pnew + newsize + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE; + +#ifdef RECORD_MM + xt_lock_mutex(self, &mm_mutex); + if ((mm = mm_find_core_ptr(oldptr + MEM_DEBUG_HDR_SIZE)) < 0) { + xt_unlock_mutex(self, &mm_mutex); + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return FAILED; + } + mm_replace_core_ptr(mm, pnew + MEM_DEBUG_HDR_SIZE); + xt_unlock_mutex(self, &mm_mutex); +#endif + + memset(oldptr, 0x55, size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE); + xt_free(self, oldptr); + + *ptr = pnew + MEM_DEBUG_HDR_SIZE; + return OK; +} + +void xt_mm_free(XTThreadPtr self, void *ptr) +{ +#ifdef RECORD_MM + if (xt_lock_mutex(self, &mm_mutex)) { + mm_remove_core_ptr(ptr); + xt_unlock_mutex(self, &mm_mutex); + } +#endif + mm_checkmem(self, NULL, ptr, TRUE); +} + +void xt_mm_pfree(XTThreadPtr self, void **ptr) +{ + if (*ptr) { + void *p = *ptr; + + *ptr = NULL; + xt_mm_free(self, p); + } +} + +size_t xt_mm_malloc_size(XTThreadPtr self, void *ptr) +{ + size_t size = 0; + +#ifdef RECORD_MM + if (xt_lock_mutex(self, &mm_mutex)) { + mm_find_core_ptr(ptr); + xt_unlock_mutex(self, &mm_mutex); + } +#endif + size = mm_checkmem(self, NULL, ptr, FALSE); + return size; +} + +void xt_mm_check_ptr(XTThreadPtr self, void *ptr) +{ + mm_checkmem(self, NULL, ptr, FALSE); +} +#endif + +/* + * ----------------------------------------------------------------------- + * INIT/EXIT MEMORY + */ + +xtPublic xtBool xt_init_memory(void) +{ +#ifdef DEBUG + XTThreadPtr self = NULL; + + if (!xt_init_mutex_with_autoname(NULL, &mm_mutex)) + return FALSE; + + mm_addresses = (MissingMemoryRec *) malloc(sizeof(MissingMemoryRec) * ADD_TOTAL_ALLOCS); + if (!mm_addresses) { + MM_THROW_ASSERTION("MM ERROR: Insuffient memory to allocate MM table"); + xt_free_mutex(&mm_mutex); + return FALSE; + } + + memset(mm_addresses, 0, sizeof(MissingMemoryRec) * ADD_TOTAL_ALLOCS); + mm_total_allocated = ADD_TOTAL_ALLOCS; + mm_nr_in_use = 0L; + mm_alloc_count = 0L; +#endif + return TRUE; +} + +xtPublic void debug_ik_count(void *value); +xtPublic void debug_ik_sum(void); + +xtPublic void xt_exit_memory(void) +{ +#ifdef DEBUG + long mm; + int i; + + if (!mm_addresses) + return; + + xt_lock_mutex(NULL, &mm_mutex); + for (mm=0; mm<mm_nr_in_use; mm++) { + MissingMemoryPtr mm_ptr = &mm_addresses[mm]; + + xt_logf(XT_NS_CONTEXT, XT_LOG_FATAL, "MM: %p (#%ld) %s:%d Not freed\n", + mm_ptr->mm_ptr, + (long) mm_ptr->id, + xt_last_name_of_path(mm_ptr->mm_file), + (int) mm_ptr->line_nr); + for (i=0; i<STACK_TRACE_DEPTH; i++) { + if (mm_ptr->mm_func[i]) + xt_logf(XT_NS_CONTEXT, XT_LOG_FATAL, "MM: %s\n", mm_ptr->mm_func[i]); + } + /* + * Assumes we place out tracing function in the first + * position!! + */ + if (mm_ptr->trace_count) + mm_debug_trace_count((XTMMTraceRefPtr) mm_ptr->mm_ptr); + } + mm_debug_trace_sum(); + free(mm_addresses); + mm_addresses = NULL; + mm_nr_in_use = 0L; + mm_total_allocated = 0L; + mm_alloc_count = 0L; + xt_unlock_mutex(NULL, &mm_mutex); + + xt_free_mutex(&mm_mutex); +#endif +} + +/* + * ----------------------------------------------------------------------- + * MEMORY ALLOCATION UTILITIES + */ + +#ifdef DEBUG +char *xt_mm_dup_string(XTThreadPtr self, c_char *str, u_int line, c_char *file) +#else +char *xt_dup_string(XTThreadPtr self, c_char *str) +#endif +{ + size_t len; + char *new_str; + + if (!str) + return NULL; + len = strlen(str); +#ifdef DEBUG + new_str = (char *) xt_mm_malloc(self, len + 1, line, file); +#else + new_str = (char *) xt_malloc(self, len + 1); +#endif + if (new_str) + strcpy(new_str, str); + return new_str; +} + +xtPublic char *xt_long_to_str(XTThreadPtr self, long v) +{ + char str[50]; + + sprintf(str, "%lu", v); + return xt_dup_string(self, str); +} + +char *xt_dup_nstr(XTThreadPtr self, c_char *str, int start, size_t len) +{ + char *new_str = (char *) xt_malloc(self, len + 1); + + if (new_str) { + memcpy(new_str, str + start, len); + new_str[len] = 0; + } + return new_str; +} + +/* + * ----------------------------------------------------------------------- + * LIGHT WEIGHT CHECK FUNCTIONS + * Timing related memory management problems my not like the memset + * or other heavy checking. Try this... + */ + +#ifdef LIGHT_WEIGHT_CHECKS +xtPublic void *xt_malloc(XTThreadPtr self, size_t size) +{ + char *ptr; + + if (!(ptr = (char *) malloc(size+8))) { + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return NULL; + } + *((xtWord4 *) ptr) = size; + *((xtWord4 *) (ptr + size + 4)) = 0x7E7EFEFE; + return ptr+4; +} + +xtPublic void xt_check_ptr(void *ptr) +{ + char *old_ptr; + xtWord4 size; + + old_ptr = (char *) ptr; + old_ptr -= 4; + size = *((xtWord4 *) old_ptr); + if (size == 0xDEADBEAF || *((xtWord4 *) (old_ptr + size + 4)) != 0x7E7EFEFE) { + char *dummy = NULL; + + xt_dump_trace(); + *dummy = 40; + } +} + +xtPublic xtBool xt_realloc(XTThreadPtr self, void **ptr, size_t size) +{ + char *old_ptr; + char *new_ptr; + + if ((old_ptr = (char *) *ptr)) { + void check_for_file(char *my_ptr, xtWord4 len); + + xt_check_ptr(old_ptr); + check_for_file((char *) old_ptr, *((xtWord4 *) (old_ptr - 4))); + if (!(new_ptr = (char *) realloc(old_ptr - 4, size+8))) { + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + return FAILED; + } + *((xtWord4 *) new_ptr) = size; + *((xtWord4 *) (new_ptr + size + 4)) = 0x7E7EFEFE; + *ptr = new_ptr+4; + return OK; + } + *ptr = xt_malloc(self, size); + return *ptr != NULL; +} + +xtPublic void xt_free(XTThreadPtr self __attribute__((unused)), void *ptr) +{ + char *old_ptr; + xtWord4 size; + void check_for_file(char *my_ptr, xtWord4 len); + + old_ptr = (char *) ptr; + old_ptr -= 4; + size = *((xtWord4 *) old_ptr); + if (size == 0xDEADBEAF || *((xtWord4 *) (old_ptr + size + 4)) != 0x7E7EFEFE) { + char *dummy = NULL; + + xt_dump_trace(); + *dummy = 41; + } + check_for_file((char *) ptr, size); + *((xtWord4 *) old_ptr) = 0xDEADBEAF; + *((xtWord4 *) (old_ptr + size)) = 0xEFEFDFDF; + *((xtWord4 *) (old_ptr + size + 4)) = 0x1F1F1F1F; + //memset(old_ptr, 0xEF, size+4); + free(old_ptr); +} + +xtPublic void *xt_calloc(XTThreadPtr self, size_t size) +{ + void *ptr; + + if ((ptr = xt_malloc(self, size))) + memset(ptr, 0, size); + return ptr; +} + +#undef xt_pfree + +xtPublic void xt_pfree(XTThreadPtr self, void **ptr) +{ + if (*ptr) { + void *p = *ptr; + + *ptr = NULL; + xt_free(self, p); + } +} + +xtPublic void *xt_malloc_ns(size_t size) +{ + char *ptr; + + if (!(ptr = (char *) malloc(size+8))) { + xt_register_errno(XT_REG_CONTEXT, XT_ENOMEM); + return NULL; + } + *((xtWord4 *) ptr) = size; + *((xtWord4 *) (ptr + size + 4)) = 0x7E7EFEFE; + return ptr+4; +} + +xtPublic void *xt_calloc_ns(size_t size) +{ + char *ptr; + + if (!(ptr = (char *) malloc(size+8))) { + xt_register_errno(XT_REG_CONTEXT, XT_ENOMEM); + return NULL; + } + *((xtWord4 *) ptr) = size; + *((xtWord4 *) (ptr + size + 4)) = 0x7E7EFEFE; + memset(ptr+4, 0, size); + return ptr+4; +} + +xtPublic xtBool xt_realloc_ns(void **ptr, size_t size) +{ + char *old_ptr; + char *new_ptr; + + if ((old_ptr = (char *) *ptr)) { + void check_for_file(char *my_ptr, xtWord4 len); + + xt_check_ptr(old_ptr); + check_for_file((char *) old_ptr, *((xtWord4 *) (old_ptr - 4))); + if (!(new_ptr = (char *) realloc(old_ptr - 4, size+8))) + return xt_register_errno(XT_REG_CONTEXT, XT_ENOMEM); + *((xtWord4 *) new_ptr) = size; + *((xtWord4 *) (new_ptr + size + 4)) = 0x7E7EFEFE; + *ptr = new_ptr+4; + return OK; + } + *ptr = xt_malloc_ns(size); + return *ptr != NULL; +} + +xtPublic void xt_free_ns(void *ptr) +{ + char *old_ptr; + xtWord4 size; + void check_for_file(char *my_ptr, xtWord4 len); + + old_ptr = (char *) ptr; + old_ptr -= 4; + size = *((xtWord4 *) old_ptr); + if (size == 0xDEADBEAF || *((xtWord4 *) (old_ptr + size + 4)) != 0x7E7EFEFE) { + char *dummy = NULL; + + xt_dump_trace(); + *dummy = 42; + } + check_for_file((char *) ptr, size); + *((xtWord4 *) old_ptr) = 0xDEADBEAF; + *((xtWord4 *) (old_ptr + size)) = 0xEFEFDFDF; + *((xtWord4 *) (old_ptr + size + 4)) = 0x1F1F1F1F; + //memset(old_ptr, 0xEE, size+4); + free(old_ptr); +} +#endif + diff --git a/storage/pbxt/src/memory_xt.h b/storage/pbxt/src/memory_xt.h new file mode 100644 index 00000000000..3b4150df185 --- /dev/null +++ b/storage/pbxt/src/memory_xt.h @@ -0,0 +1,126 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-04 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_memory_h__ +#define __xt_memory_h__ + +#include <string.h> + +#include "xt_defs.h" + +struct XTThread; + +#ifdef DEBUG + +#define XT_MM_STACK_TRACE 200 +#define XT_MM_TRACE_DEPTH 4 +#define XT_MM_TRACE_INC ((char *) 1) +#define XT_MM_TRACE_DEC ((char *) 2) +#define XT_MM_TRACE_SW_INC ((char *) 1) +#define XT_MM_TRACE_SW_DEC ((char *) 2) +#define XT_MM_TRACE_ERROR ((char *) 3) + +typedef struct XTMMTraceRef { + int mm_pos; + u_int mm_id; + u_int mm_line[XT_MM_STACK_TRACE]; + c_char *mm_trace[XT_MM_STACK_TRACE]; +} XTMMTraceRefRec, *XTMMTraceRefPtr; + +#define XT_MM_TRACE_INIT(x) (x)->mm_pos = 0 + +extern char *mm_watch_point; + +#define XT_MEMMOVE(b, d, s, l) xt_mm_memmove(b, d, s, l) +#define XT_MEMCPY(b, d, s, l) xt_mm_memcpy(b, d, s, l) +#define XT_MEMSET(b, d, v, l) xt_mm_memset(b, d, v, l) + +#define xt_malloc(t, s) xt_mm_malloc(t, s, __LINE__, __FILE__) +#define xt_calloc(t, s) xt_mm_calloc(t, s, __LINE__, __FILE__) +#define xt_realloc(t, p, s) xt_mm_realloc(t, p, s, __LINE__, __FILE__) +#define xt_free xt_mm_free +#define xt_pfree xt_mm_pfree + +#define xt_malloc_ns(s) xt_mm_malloc(NULL, s, __LINE__, __FILE__) +#define xt_calloc_ns(s) xt_mm_calloc(NULL, s, __LINE__, __FILE__) +#define xt_realloc_ns(p, s) xt_mm_sys_realloc(NULL, p, s, __LINE__, __FILE__) +#define xt_free_ns(p) xt_mm_free(NULL, p) + +void xt_mm_memmove(void *block, void *dest, void *source, size_t size); +void xt_mm_memcpy(void *block, void *dest, void *source, size_t size); +void xt_mm_memset(void *block, void *dest, int value, size_t size); + +void *xt_mm_malloc(struct XTThread *self, size_t size, u_int line, const char *file); +void *xt_mm_calloc(struct XTThread *self, size_t size, u_int line, const char *file); +xtBool xt_mm_realloc(struct XTThread *self, void **ptr, size_t size, u_int line, const char *file); +void xt_mm_free(struct XTThread *self, void *ptr); +void xt_mm_pfree(struct XTThread *self, void **ptr); +size_t xt_mm_malloc_size(struct XTThread *self, void *ptr); +void xt_mm_check_ptr(struct XTThread *self, void *ptr); +xtBool xt_mm_sys_realloc(struct XTThread *self, void **ptr, size_t newsize, u_int line, const char *file); + +#ifndef XT_SCAN_CORE_DEFINED +#define XT_SCAN_CORE_DEFINED +xtBool xt_mm_scan_core(void); +#endif + +void mm_trace_inc(struct XTThread *self, XTMMTraceRefPtr tr); +void mm_trace_dec(struct XTThread *self, XTMMTraceRefPtr tr); +void mm_trace_init(struct XTThread *self, XTMMTraceRefPtr tr); +void mm_trace_print(XTMMTraceRefPtr tr); + +#else + +#define XT_MEMMOVE(b, d, s, l) memmove(d, s, l) +#define XT_MEMCPY(b, d, s, l) memcpy(d, s, l) +#define XT_MEMSET(b, d, v, l) memset(d, v, l) + +void *xt_malloc(struct XTThread *self, size_t size); +void *xt_calloc(struct XTThread *self, size_t size); +xtBool xt_realloc(struct XTThread *self, void **ptr, size_t size); +void xt_free(struct XTThread *self, void *ptr); +void xt_pfree(struct XTThread *self, void **ptr); + +void *xt_malloc_ns(size_t size); +void *xt_calloc_ns(size_t size); +xtBool xt_realloc_ns(void **ptr, size_t size); +void xt_free_ns(void *ptr); + +#define xt_pfree(t, p) xt_pfree(t, (void **) p) + +#endif + +#ifdef DEBUG +#define xt_dup_string(t, s) xt_mm_dup_string(t, s, __LINE__, __FILE__) + +char *xt_mm_dup_string(struct XTThread *self, const char *path, u_int line, const char *file); +#else +char *xt_dup_string(struct XTThread *self, const char *path); +#endif + +char *xt_long_to_str(struct XTThread *self, long v); +char *xt_dup_nstr(struct XTThread *self, const char *str, int start, size_t len); + +xtBool xt_init_memory(void); +void xt_exit_memory(void); + +#endif diff --git a/storage/pbxt/src/myxt_xt.cc b/storage/pbxt/src/myxt_xt.cc new file mode 100644 index 00000000000..ba9a72c87a3 --- /dev/null +++ b/storage/pbxt/src/myxt_xt.cc @@ -0,0 +1,3245 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-05-16 Paul McCullagh + * + * H&G2JCtL + * + * These functions implement the parts of PBXT which must conform to the + * key and row format used by MySQL. + */ + +#include "xt_config.h" + +#ifdef DRIZZLED +#include <drizzled/server_includes.h> +#include <drizzled/plugin.h> +#include <drizzled/show.h> +#include <drizzled/field/blob.h> +#include <drizzled/field/enum.h> +#include <drizzled/field/varstring.h> +#include <drizzled/current_session.h> +#include <drizzled/sql_lex.h> +#include <drizzled/session.h> +extern "C" struct charset_info_st *session_charset(Session *session); +extern pthread_key_t THR_Session; +#else +#include "mysql_priv.h" +#include <mysql/plugin.h> +#endif + +#ifdef HAVE_ISNAN +#include <math.h> +#endif + +#include "ha_pbxt.h" + +#include "myxt_xt.h" +#include "strutil_xt.h" +#include "database_xt.h" +#ifdef XT_STREAMING +#include "streaming_xt.h" +#endif +#include "cache_xt.h" +#include "datalog_xt.h" + +#ifdef DRIZZLED +#define swap_variables(TYPE, a, b) \ + do { \ + TYPE dummy; \ + dummy= a; \ + a= b; \ + b= dummy; \ + } while (0) + + +#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1) +#else +#define get_rec_bits(bit_ptr, bit_ofs, bit_len) \ + (((((uint16) (bit_ptr)[1] << 8) | (uint16) (bit_ptr)[0]) >> (bit_ofs)) & \ + ((1 << (bit_len)) - 1)) +#endif + +#define FIX_LENGTH(cs, pos, length, char_length) \ + do { \ + if ((length) > char_length) \ + char_length= my_charpos(cs, pos, pos+length, char_length); \ + set_if_smaller(char_length,length); \ + } while(0) + +#ifdef store_key_length_inc +#undef store_key_length_inc +#endif +#define store_key_length_inc(key,length) \ +{ if ((length) < 255) \ + { *(key)++=(length); } \ + else \ + { *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \ +} + +#define set_rec_bits(bits, bit_ptr, bit_ofs, bit_len) \ +{ \ + (bit_ptr)[0]= ((bit_ptr)[0] & ~(((1 << (bit_len)) - 1) << (bit_ofs))) | \ + ((bits) << (bit_ofs)); \ + if ((bit_ofs) + (bit_len) > 8) \ + (bit_ptr)[1]= ((bit_ptr)[1] & ~((1 << ((bit_len) - 8 + (bit_ofs))) - 1)) | \ + ((bits) >> (8 - (bit_ofs))); \ +} + +#define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \ + set_rec_bits(0, bit_ptr, bit_ofs, bit_len) + +static ulong my_calc_blob_length(uint length, xtWord1 *pos) +{ + switch (length) { + case 1: + return (uint) (uchar) *pos; + case 2: + return (uint) uint2korr(pos); + case 3: + return uint3korr(pos); + case 4: + return uint4korr(pos); + default: + break; + } + return 0; /* Impossible */ +} + +static void my_store_blob_length(byte *pos,uint pack_length,uint length) +{ + switch (pack_length) { + case 1: + *pos= (uchar) length; + break; + case 2: + int2store(pos,length); + break; + case 3: + int3store(pos,length); + break; + case 4: + int4store(pos,length); + default: + break; + } + return; +} + +static int my_compare_text(MX_CONST_CHARSET_INFO *charset_info, uchar *a, uint a_length, + uchar *b, uint b_length, my_bool part_key, + my_bool skip_end_space __attribute__((unused))) +{ + if (!part_key) + /* The last parameter is diff_if_only_endspace_difference, which means + * that end spaces are not ignored. We actually always want + * to ignore end spaces! + */ + return charset_info->coll->strnncollsp(charset_info, a, a_length, + b, b_length, /*(my_bool)!skip_end_space*/0); + return charset_info->coll->strnncoll(charset_info, a, a_length, + b, b_length, part_key); +} + +/* + * ----------------------------------------------------------------------- + * Create a key + */ + +/* + * Derived from _mi_pack_key() + */ +xtPublic u_int myxt_create_key_from_key(XTIndexPtr ind, xtWord1 *key, xtWord1 *old, u_int k_length) +{ + xtWord1 *start_key = key; + XTIndexSegRec *keyseg = ind->mi_seg; + + for (u_int i=0; i<ind->mi_seg_count && (int) k_length > 0; i++, old += keyseg->length, keyseg++) + { + enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type; + u_int length = keyseg->length < k_length ? keyseg->length : k_length; + u_int char_length; + xtWord1 *pos; + MX_CONST_CHARSET_INFO *cs = keyseg->charset; + + if (keyseg->null_bit) { + k_length--; + if (!(*key++ = (xtWord1) 1 - *old++)) { /* Copy null marker */ + k_length -= length; + if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) { + k_length -= 2; /* Skip length */ + old += 2; + } + continue; /* Found NULL */ + } + } + char_length= (cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length; + pos = old; + if (keyseg->flag & HA_SPACE_PACK) { + uchar *end = pos + length; + if (type != HA_KEYTYPE_NUM) { + while (end > pos && end[-1] == ' ') + end--; + } + else { + while (pos < end && pos[0] == ' ') + pos++; + } + k_length -= length; + length = (u_int) (end-pos); + FIX_LENGTH(cs, pos, length, char_length); + store_key_length_inc(key, char_length); + memcpy((byte*) key,pos,(size_t) char_length); + key += char_length; + continue; + } + if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) { + /* Length of key-part used with mi_rkey() always 2 */ + u_int tmp_length = uint2korr(pos); + k_length -= 2 + length; + pos += 2; + set_if_smaller(length, tmp_length); /* Safety */ + FIX_LENGTH(cs, pos, length, char_length); + store_key_length_inc(key,char_length); + old +=2; /* Skip length */ + memcpy((char *) key, pos, (size_t) char_length); + key += char_length; + continue; + } + if (keyseg->flag & HA_SWAP_KEY) + { /* Numerical column */ + pos+=length; + k_length-=length; + while (length--) { + *key++ = *--pos; + } + continue; + } + FIX_LENGTH(cs, pos, length, char_length); + memcpy((byte*) key, pos, char_length); + if (length > char_length) + cs->cset->fill(cs, (char *) (key + char_length), length - char_length, ' '); + key += length; + k_length -= length; + } + + return (u_int) (key - start_key); +} + +/* Derived from _mi_make_key */ +xtPublic u_int myxt_create_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, xtBool *no_duplicate) +{ + register XTIndexSegRec *keyseg = ind->mi_seg; + xtWord1 *pos; + xtWord1 *end; + xtWord1 *start; + + start = key; + for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) + { + enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type; + u_int length = keyseg->length; + u_int char_length; + MX_CONST_CHARSET_INFO *cs = keyseg->charset; + + if (keyseg->null_bit) { + if (record[keyseg->null_pos] & keyseg->null_bit) { + *key++ = 0; /* NULL in key */ + + /* The point is, if a key contains a NULL value + * the duplicate checking must be disabled. + * This is because a NULL value is not considered + * equal to any other value. + */ + if (no_duplicate) + *no_duplicate = FALSE; + continue; + } + *key++ = 1; /* Not NULL */ + } + + char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length); + + pos = record + keyseg->start; + if (type == HA_KEYTYPE_BIT) + { + if (keyseg->bit_length) + { + uchar bits = get_rec_bits((uchar*) record + keyseg->bit_pos, + keyseg->bit_start, keyseg->bit_length); + *key++ = bits; + length--; + } + memcpy((byte*) key, pos, length); + key+= length; + continue; + } + if (keyseg->flag & HA_SPACE_PACK) + { + end = pos + length; + if (type != HA_KEYTYPE_NUM) { + while (end > pos && end[-1] == ' ') + end--; + } + else { + while (pos < end && pos[0] == ' ') + pos++; + } + length = (u_int) (end-pos); + FIX_LENGTH(cs, pos, length, char_length); + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key += char_length; + continue; + } + if (keyseg->flag & HA_VAR_LENGTH_PART) { + uint pack_length= (keyseg->bit_start == 1 ? 1 : 2); + uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos : + uint2korr(pos)); + pos += pack_length; /* Skip VARCHAR length */ + set_if_smaller(length,tmp_length); + FIX_LENGTH(cs, pos, length, char_length); + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key += char_length; + continue; + } + if (keyseg->flag & HA_BLOB_PART) + { + u_int tmp_length = my_calc_blob_length(keyseg->bit_start, pos); + memcpy((byte*) &pos,pos+keyseg->bit_start,sizeof(char*)); + set_if_smaller(length,tmp_length); + FIX_LENGTH(cs, pos, length, char_length); + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key+= char_length; + continue; + } + if (keyseg->flag & HA_SWAP_KEY) + { /* Numerical column */ +#ifdef HAVE_ISNAN + if (type == HA_KEYTYPE_FLOAT) + { + float nr; + float4get(nr,pos); + if (isnan(nr)) + { + /* Replace NAN with zero */ + bzero(key,length); + key+=length; + continue; + } + } + else if (type == HA_KEYTYPE_DOUBLE) { + double nr; + + float8get(nr,pos); + if (isnan(nr)) { + bzero(key,length); + key+=length; + continue; + } + } +#endif + pos+=length; + while (length--) { + *key++ = *--pos; + } + continue; + } + FIX_LENGTH(cs, pos, length, char_length); + memcpy((byte*) key, pos, char_length); + if (length > char_length) + cs->cset->fill(cs, (char *) key + char_length, length - char_length, ' '); + key += length; + } + + return ind->mi_fix_key ? ind->mi_key_size : (u_int) (key - start); /* Return keylength */ +} + +xtPublic u_int myxt_create_foreign_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, XTIndexPtr fkey_ind, xtBool *no_null) +{ + register XTIndexSegRec *keyseg = ind->mi_seg; + register XTIndexSegRec *fkey_keyseg = fkey_ind->mi_seg; + xtWord1 *pos; + xtWord1 *end; + xtWord1 *start; + + start = key; + for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++, fkey_keyseg++) + { + enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type; + u_int length = keyseg->length; + u_int char_length; + MX_CONST_CHARSET_INFO *cs = keyseg->charset; + xtBool is_null = FALSE; + + if (keyseg->null_bit) { + if (record[keyseg->null_pos] & keyseg->null_bit) { + is_null = TRUE; + if (no_null) + *no_null = FALSE; + } + } + + if (fkey_keyseg->null_bit) { + if (is_null) { + *key++ = 0; /* NULL in key */ + + /* The point is, if a key contains a NULL value + * the duplicate checking must be disabled. + * This is because a NULL value is not considered + * equal to any other value. + */ + continue; + } + *key++ = 1; /* Not NULL */ + } + + char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length); + + pos = record + keyseg->start; + if (type == HA_KEYTYPE_BIT) + { + if (keyseg->bit_length) + { + uchar bits = get_rec_bits((uchar*) record + keyseg->bit_pos, + keyseg->bit_start, keyseg->bit_length); + *key++ = bits; + length--; + } + memcpy((byte*) key, pos, length); + key+= length; + continue; + } + if (keyseg->flag & HA_SPACE_PACK) + { + end = pos + length; + if (type != HA_KEYTYPE_NUM) { + while (end > pos && end[-1] == ' ') + end--; + } + else { + while (pos < end && pos[0] == ' ') + pos++; + } + length = (u_int) (end-pos); + FIX_LENGTH(cs, pos, length, char_length); + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key += char_length; + continue; + } + if (keyseg->flag & HA_VAR_LENGTH_PART) { + uint pack_length= (keyseg->bit_start == 1 ? 1 : 2); + uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos : + uint2korr(pos)); + pos += pack_length; /* Skip VARCHAR length */ + set_if_smaller(length,tmp_length); + FIX_LENGTH(cs, pos, length, char_length); + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key += char_length; + continue; + } + if (keyseg->flag & HA_BLOB_PART) + { + u_int tmp_length = my_calc_blob_length(keyseg->bit_start, pos); + memcpy((byte*) &pos,pos+keyseg->bit_start,sizeof(char*)); + set_if_smaller(length,tmp_length); + FIX_LENGTH(cs, pos, length, char_length); + store_key_length_inc(key,char_length); + memcpy((byte*) key,(byte*) pos,(size_t) char_length); + key+= char_length; + continue; + } + if (keyseg->flag & HA_SWAP_KEY) + { /* Numerical column */ +#ifdef HAVE_ISNAN + if (type == HA_KEYTYPE_FLOAT) + { + float nr; + float4get(nr,pos); + if (isnan(nr)) + { + /* Replace NAN with zero */ + bzero(key,length); + key+=length; + continue; + } + } + else if (type == HA_KEYTYPE_DOUBLE) { + double nr; + + float8get(nr,pos); + if (isnan(nr)) { + bzero(key,length); + key+=length; + continue; + } + } +#endif + pos+=length; + while (length--) { + *key++ = *--pos; + } + continue; + } + FIX_LENGTH(cs, pos, length, char_length); + memcpy((byte*) key, pos, char_length); + if (length > char_length) + cs->cset->fill(cs, (char *) key + char_length, length - char_length, ' '); + key += length; + } + + return fkey_ind->mi_fix_key ? fkey_ind->mi_key_size : (u_int) (key - start); /* Return keylength */ +} + +/* I may be overcautious here, but can I assume that + * null_ptr refers to my buffer. If I cannot, then I + * cannot use the set_notnull() method. + */ +static void mx_set_notnull_in_record(Field *field, char *record) +{ + if (field->null_ptr) + record[(uint) (field->null_ptr - (uchar *) field->table->record[0])] &= (uchar) ~field->null_bit; +} + +static xtBool mx_is_null_in_record(Field *field, char *record) +{ + if (field->null_ptr) { + if (record[(uint) (field->null_ptr - (uchar *) field->table->record[0])] & (uchar) field->null_bit) + return TRUE; + } + return FALSE; +} + +/* + * PBXT uses a completely different disk format to MySQL so I need a + * method that just returns the byte length and + * pointer to the data in a row. + */ +static char *mx_get_length_and_data(Field *field, char *dest, xtWord4 *len) +{ + char *from; + +#if MYSQL_VERSION_ID < 50114 + from = dest + field->offset(); +#else + from = dest + field->offset(field->table->record[0]); +#endif + switch (field->real_type()) { +#ifndef DRIZZLED + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: +#endif + case MYSQL_TYPE_BLOB: { + /* TODO - Check: this was the original comment: I must set + * *data to non-NULL value, *data == 0, means SQL NULL value. + */ + char *data; + + /* GOTCHA: There is no way this can work! field is shared + * between threads. + char *save = field->ptr; + + field->ptr = (char *) from; + ((Field_blob *) field)->get_ptr(&data); + field->ptr = save; // Restore org row pointer + */ + + xtWord4 packlength = ((Field_blob *) field)->pack_length() - field->table->s->blob_ptr_size; + memcpy(&data, ((char *) from)+packlength, sizeof(char*)); + + *len = ((Field_blob *) field)->get_length((byte *) from); + return data; + } +#ifndef DRIZZLED + case MYSQL_TYPE_STRING: + /* To write this function you would think Field_string::pack + * would serve as a good example, but as far as I can tell + * it has a bug: the test from[length-1] == ' ' assumes + * 1-byte chars. + * + * But this is not relevant because I believe lengthsp + * will give me the correct answer! + */ + *len = field->charset()->cset->lengthsp(field->charset(), from, field->field_length); + return from; + case MYSQL_TYPE_VAR_STRING: { + uint length=uint2korr(from); + + *len = length; + return from+HA_KEY_BLOB_LENGTH; + } +#endif + case MYSQL_TYPE_VARCHAR: { + uint length; + + if (((Field_varstring *) field)->length_bytes == 1) + length = *((unsigned char *) from); + else + length = uint2korr(from); + + *len = length; + return from+((Field_varstring *) field)->length_bytes; + } +#ifndef DRIZZLED + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_GEOMETRY: +#else + case DRIZZLE_TYPE_TINY: + case DRIZZLE_TYPE_LONG: + case DRIZZLE_TYPE_DOUBLE: + case DRIZZLE_TYPE_NULL: + case DRIZZLE_TYPE_TIMESTAMP: + case DRIZZLE_TYPE_LONGLONG: + case DRIZZLE_TYPE_DATETIME: + case DRIZZLE_TYPE_DATE: + case DRIZZLE_TYPE_NEWDECIMAL: + case DRIZZLE_TYPE_ENUM: + case DRIZZLE_TYPE_VIRTUAL: +#endif + break; + } + + *len = field->pack_length(); + return from; +} + +/* + * Set the length and data value of a field. + * + * If input data is NULL this is a NULL value. In this case + * we assume the null bit has been set and prepared + * the field as follows: + * + * According to the InnoDB implementation, we need + * to zero out the field data... + * "MySQL seems to assume the field for an SQL NULL + * value is set to zero or space. Not taking this into + * account caused seg faults with NULL BLOB fields, and + * bug number 154 in the MySQL bug database: GROUP BY + * and DISTINCT could treat NULL values inequal". + */ +static void mx_set_length_and_data(Field *field, char *dest, xtWord4 len, char *data) +{ + char *from; + +#if MYSQL_VERSION_ID < 50114 + from = dest + field->offset(); +#else + from = dest + field->offset(field->table->record[0]); +#endif + switch (field->real_type()) { +#ifndef DRIZZLED + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: +#endif + case MYSQL_TYPE_BLOB: { + /* GOTCHA: There is no way that this can work. + * field is shared, because table is shared! + char *save = field->ptr; + + field->ptr = (char *) from; + ((Field_blob *) field)->set_ptr(len, data); + field->ptr = save; // Restore org row pointer + */ + xtWord4 packlength = ((Field_blob *) field)->pack_length() - field->table->s->blob_ptr_size; + + ((Field_blob *) field)->store_length((byte *) from, packlength, len); + memcpy_fixed(((char *) from)+packlength, &data, sizeof(char*)); + + if (data) + mx_set_notnull_in_record(field, dest); + return; + } +#ifndef DRIZZLED + case MYSQL_TYPE_STRING: + if (data) { + mx_set_notnull_in_record(field, dest); + memcpy(from, data, len); + } + else + len = 0; + + /* And I think that fill will do this for me... */ + field->charset()->cset->fill(field->charset(), from + len, field->field_length - len, ' '); + return; + case MYSQL_TYPE_VAR_STRING: + int2store(from, len); + if (data) { + mx_set_notnull_in_record(field, dest); + memcpy(from+HA_KEY_BLOB_LENGTH, data, len); + } + return; +#endif + case MYSQL_TYPE_VARCHAR: + if (((Field_varstring *) field)->length_bytes == 1) + *((unsigned char *) from) = (unsigned char) len; + else + int2store(from, len); + if (data) { + mx_set_notnull_in_record(field, dest); + memcpy(from+((Field_varstring *) field)->length_bytes, data, len); + } + return; +#ifndef DRIZZLED + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_GEOMETRY: +#else + case DRIZZLE_TYPE_TINY: + case DRIZZLE_TYPE_LONG: + case DRIZZLE_TYPE_DOUBLE: + case DRIZZLE_TYPE_NULL: + case DRIZZLE_TYPE_TIMESTAMP: + case DRIZZLE_TYPE_LONGLONG: + case DRIZZLE_TYPE_DATETIME: + case DRIZZLE_TYPE_DATE: + case DRIZZLE_TYPE_NEWDECIMAL: + case DRIZZLE_TYPE_ENUM: + case DRIZZLE_TYPE_VIRTUAL: +#endif + break; + } + + if (data) { + mx_set_notnull_in_record(field, dest); + memcpy(from, data, len); + } + else + bzero(from, field->pack_length()); +} + +xtPublic void myxt_set_null_row_from_key(XTOpenTablePtr ot __attribute__((unused)), XTIndexPtr ind, xtWord1 *record) +{ + register XTIndexSegRec *keyseg = ind->mi_seg; + + for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) { + ASSERT_NS(keyseg->null_bit); + record[keyseg->null_pos] |= keyseg->null_bit; + } +} + +xtPublic void myxt_set_default_row_from_key(XTOpenTablePtr ot, XTIndexPtr ind, xtWord1 *record) +{ + XTTableHPtr tab = ot->ot_table; + TABLE *table = tab->tab_dic.dic_my_table; + XTIndexSegRec *keyseg = ind->mi_seg; + + xt_lock_mutex_ns(&tab->tab_dic_field_lock); + + for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) { + + u_int col_idx = keyseg->col_idx; + Field *field = table->field[col_idx]; + byte *field_save = field->ptr; + + field->ptr = table->s->default_values + keyseg->start; + memcpy(record + keyseg->start, field->ptr, field->pack_length()); + record[keyseg->null_pos] &= ~keyseg->null_bit; + record[keyseg->null_pos] |= table->s->default_values[keyseg->null_pos] & keyseg->null_bit; + + field->ptr = field_save; + } + + xt_unlock_mutex_ns(&tab->tab_dic_field_lock); +} + +/* Derived from _mi_put_key_in_record */ +xtPublic xtBool myxt_create_row_from_key(XTOpenTablePtr ot __attribute__((unused)), XTIndexPtr ind, xtWord1 *b_value, u_int key_len, xtWord1 *dest_buff) +{ + byte *record = (byte *) dest_buff; + register byte *key; + byte *pos,*key_end; + register XTIndexSegRec *keyseg = ind->mi_seg; + + /* GOTCHA: When selecting from multiple + * indexes the key values are "merged" into the + * same buffer!! + * This means that this function must not affect + * the value of any other feilds. + * + * I was setting all to NULL: + memset(dest_buff, 0xFF, table->s->null_bytes); + */ + key = (byte *) b_value; + key_end = key + key_len; + for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) { + if (keyseg->null_bit) { + if (!*key++) + { + record[keyseg->null_pos] |= keyseg->null_bit; + continue; + } + record[keyseg->null_pos] &= ~keyseg->null_bit; + } + if (keyseg->type == HA_KEYTYPE_BIT) + { + uint length = keyseg->length; + + if (keyseg->bit_length) + { + uchar bits= *key++; + set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start, + keyseg->bit_length); + length--; + } + else + { + clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start, + keyseg->bit_length); + } + memcpy(record + keyseg->start, (byte*) key, length); + key+= length; + continue; + } + if (keyseg->flag & HA_SPACE_PACK) + { + uint length; + get_key_length(length,key); +#ifdef CHECK_KEYS + if (length > keyseg->length || key+length > key_end) + goto err; +#endif + pos = record+keyseg->start; + if (keyseg->type != (int) HA_KEYTYPE_NUM) + { + memcpy(pos,key,(size_t) length); + bfill(pos+length,keyseg->length-length,' '); + } + else + { + bfill(pos,keyseg->length-length,' '); + memcpy(pos+keyseg->length-length,key,(size_t) length); + } + key+=length; + continue; + } + + if (keyseg->flag & HA_VAR_LENGTH_PART) + { + uint length; + get_key_length(length,key); +#ifdef CHECK_KEYS + if (length > keyseg->length || key+length > key_end) + goto err; +#endif + /* Store key length */ + if (keyseg->bit_start == 1) + *(uchar*) (record+keyseg->start)= (uchar) length; + else + int2store(record+keyseg->start, length); + /* And key data */ + memcpy(record+keyseg->start + keyseg->bit_start, (byte*) key, length); + key+= length; + } + else if (keyseg->flag & HA_BLOB_PART) + { + uint length; + get_key_length(length,key); +#ifdef CHECK_KEYS + if (length > keyseg->length || key+length > key_end) + goto err; +#endif + /* key is a pointer into ot_ind_rbuf, which should be + * safe until we move to the next index item! + */ + byte *key_ptr = key; // Cannot take the address of a register variable! + memcpy(record+keyseg->start+keyseg->bit_start, + (char*) &key_ptr,sizeof(char*)); + + my_store_blob_length(record+keyseg->start, + (uint) keyseg->bit_start,length); + key+=length; + } + else if (keyseg->flag & HA_SWAP_KEY) + { + byte *to= record+keyseg->start+keyseg->length; + byte *end= key+keyseg->length; +#ifdef CHECK_KEYS + if (end > key_end) + goto err; +#endif + do { + *--to= *key++; + } while (key != end); + continue; + } + else + { +#ifdef CHECK_KEYS + if (key+keyseg->length > key_end) + goto err; +#endif + memcpy(record+keyseg->start,(byte*) key, + (size_t) keyseg->length); + key+= keyseg->length; + } + + } + return OK; + +#ifdef CHECK_KEYS + err: +#endif + return FAILED; /* Crashed row */ +} + +/* + * ----------------------------------------------------------------------- + * Compare keys + */ + +static int my_compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, + my_bool part_key, my_bool skip_end_space) +{ + uint length= min(a_length,b_length); + uchar *end= a+ length; + int flag; + + while (a < end) + if ((flag= (int) *a++ - (int) *b++)) + return flag; + if (part_key && b_length < a_length) + return 0; + if (skip_end_space && a_length != b_length) + { + int swap= 1; + /* + We are using space compression. We have to check if longer key + has next character < ' ', in which case it's less than the shorter + key that has an implicite space afterwards. + + This code is identical to the one in + strings/ctype-simple.c:my_strnncollsp_simple + */ + if (a_length < b_length) + { + /* put shorter key in a */ + a_length= b_length; + a= b; + swap= -1; /* swap sign of result */ + } + for (end= a + a_length-length; a < end ; a++) + { + if (*a != ' ') + return (*a < ' ') ? -swap : swap; + } + return 0; + } + return (int) (a_length-b_length); +} + +xtPublic u_int myxt_get_key_length(XTIndexPtr ind, xtWord1 *key_buf) +{ + register XTIndexSegRec *keyseg = ind->mi_seg; + register uchar *key_data = (uchar *) key_buf; + uint seg_len; + uint pack_len; + + for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) { + /* Handle NULL part */ + if (keyseg->null_bit) { + if (!*key_data++) + continue; + } + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ + if (keyseg->flag & HA_SPACE_PACK) { + get_key_pack_length(seg_len, pack_len, key_data); + } + else + seg_len = keyseg->length; + key_data += seg_len; + break; + case HA_KEYTYPE_BINARY: + if (keyseg->flag & HA_SPACE_PACK) { + get_key_pack_length(seg_len, pack_len, key_data); + } + else + seg_len = keyseg->length; + key_data += seg_len; + break; + case HA_KEYTYPE_VARTEXT1: + case HA_KEYTYPE_VARTEXT2: + get_key_pack_length(seg_len, pack_len, key_data); + key_data += seg_len; + break; + case HA_KEYTYPE_VARBINARY1: + case HA_KEYTYPE_VARBINARY2: + get_key_pack_length(seg_len, pack_len, key_data); + key_data += seg_len; + break; + case HA_KEYTYPE_NUM: { + /* Numeric key */ + if (keyseg->flag & HA_SPACE_PACK) + seg_len = *key_data++; + else + seg_len = keyseg->length; + key_data += seg_len; + break; + } + case HA_KEYTYPE_INT8: + case HA_KEYTYPE_SHORT_INT: + case HA_KEYTYPE_USHORT_INT: + case HA_KEYTYPE_LONG_INT: + case HA_KEYTYPE_ULONG_INT: + case HA_KEYTYPE_INT24: + case HA_KEYTYPE_UINT24: + case HA_KEYTYPE_FLOAT: + case HA_KEYTYPE_DOUBLE: + case HA_KEYTYPE_LONGLONG: + case HA_KEYTYPE_ULONGLONG: + case HA_KEYTYPE_BIT: + key_data += keyseg->length; + break; + case HA_KEYTYPE_END: + goto end; + } + } + + end: + return (xtWord1 *) key_data - key_buf; +} + +/* Derived from ha_key_cmp */ +xtPublic int myxt_compare_key(XTIndexPtr ind, int search_flags, uint key_length, xtWord1 *key_value, xtWord1 *b_value) +{ + register XTIndexSegRec *keyseg = ind->mi_seg; + int flag; + register uchar *a = (uchar *) key_value; + uint a_length; + register uchar *b = (uchar *) b_value; + uint b_length; + uint next_key_length; + uchar *end; + uint piks; + uint pack_len; + + for (uint i=0; i < ind->mi_seg_count && (int) key_length > 0; key_length = next_key_length, keyseg++, i++) { + piks = !(keyseg->flag & HA_NO_SORT); + + /* Handle NULL part */ + if (keyseg->null_bit) { + /* 1 is not null, 0 is null */ + int b_not_null = (int) *b++; + + key_length--; + if ((int) *a != b_not_null && piks) + { + flag = (int) *a - b_not_null; + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + } + if (!*a++) { + /* If key was NULL */ + if (search_flags == (SEARCH_FIND | SEARCH_UPDATE)) + search_flags = SEARCH_SAME; /* Allow duplicate keys */ + else if (search_flags & SEARCH_NULL_ARE_NOT_EQUAL) + { + /* + * This is only used from mi_check() to calculate cardinality. + * It can't be used when searching for a key as this would cause + * compare of (a,b) and (b,a) to return the same value. + */ + return -1; + } + /* PMC - I don't know why I had next_key_length = key_length - keyseg->length; + * This was my comment: even when null we have the complete length + * + * The truth is, a NULL only takes up one byte in the key, and this has already + * been subtracted. + */ + next_key_length = key_length; + continue; /* To next key part */ + } + } + + /* Both components are not null... */ + if (keyseg->length < key_length) { + end = a + keyseg->length; + next_key_length = key_length - keyseg->length; + } + else { + end = a + key_length; + next_key_length = 0; + } + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ + if (keyseg->flag & HA_SPACE_PACK) { + get_key_pack_length(a_length, pack_len, a); + next_key_length = key_length - a_length - pack_len; + get_key_pack_length(b_length, pack_len, b); + + if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length, + (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), + (my_bool)!(search_flags & SEARCH_PREFIX)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a += a_length; + } + else { + a_length = (uint) (end - a); + b_length = keyseg->length; + if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length, + (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), + (my_bool)!(search_flags & SEARCH_PREFIX)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + } + b += b_length; + break; + case HA_KEYTYPE_BINARY: + if (keyseg->flag & HA_SPACE_PACK) { + get_key_pack_length(a_length, pack_len, a); + next_key_length = key_length - a_length - pack_len; + get_key_pack_length(b_length, pack_len, b); + + if (piks && (flag = my_compare_bin(a, a_length, b, b_length, + (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 1))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + } + else { + a_length = keyseg->length; + b_length = keyseg->length; + if (piks && (flag = my_compare_bin(a, a_length, b, b_length, + (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 0))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + } + a += a_length; + b += b_length; + break; + case HA_KEYTYPE_VARTEXT1: + case HA_KEYTYPE_VARTEXT2: + { + get_key_pack_length(a_length, pack_len, a); + next_key_length = key_length - a_length - pack_len; + get_key_pack_length(b_length, pack_len, b); + + if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length, + (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), + (my_bool) ((search_flags & (SEARCH_FIND | SEARCH_UPDATE)) == SEARCH_FIND)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a += a_length; + b += b_length; + break; + } + case HA_KEYTYPE_VARBINARY1: + case HA_KEYTYPE_VARBINARY2: + { + get_key_pack_length(a_length, pack_len, a); + next_key_length = key_length - a_length - pack_len; + get_key_pack_length(b_length, pack_len, b); + + if (piks && (flag=my_compare_bin(a, a_length, b, b_length, + (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 0))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a += a_length; + b += b_length; + break; + } + case HA_KEYTYPE_INT8: + { + int i_1 = (int) *((signed char *) a); + int i_2 = (int) *((signed char *) b); + if (piks && (flag = CMP_NUM(i_1,i_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_SHORT_INT: { + int16 s_1 = sint2korr(a); + int16 s_2 = sint2korr(b); + if (piks && (flag = CMP_NUM(s_1, s_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_USHORT_INT: { + uint16 us_1= sint2korr(a); + uint16 us_2= sint2korr(b); + if (piks && (flag = CMP_NUM(us_1, us_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_LONG_INT: { + int32 l_1 = sint4korr(a); + int32 l_2 = sint4korr(b); + if (piks && (flag = CMP_NUM(l_1, l_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_ULONG_INT: { + uint32 u_1 = sint4korr(a); + uint32 u_2 = sint4korr(b); + if (piks && (flag = CMP_NUM(u_1, u_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_INT24: { + int32 l_1 = sint3korr(a); + int32 l_2 = sint3korr(b); + if (piks && (flag = CMP_NUM(l_1, l_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_UINT24: { + int32 l_1 = uint3korr(a); + int32 l_2 = uint3korr(b); + if (piks && (flag = CMP_NUM(l_1, l_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_FLOAT: { + float f_1, f_2; + + float4get(f_1, a); + float4get(f_2, b); + /* + * The following may give a compiler warning about floating point + * comparison not being safe, but this is ok in this context as + * we are bascily doing sorting + */ + if (piks && (flag = CMP_NUM(f_1, f_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_DOUBLE: { + double d_1, d_2; + + float8get(d_1, a); + float8get(d_2, b); + /* + * The following may give a compiler warning about floating point + * comparison not being safe, but this is ok in this context as + * we are bascily doing sorting + */ + if (piks && (flag = CMP_NUM(d_1, d_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_NUM: { + /* Numeric key */ + if (keyseg->flag & HA_SPACE_PACK) { + a_length = *a++; + end = a + a_length; + next_key_length = key_length - a_length - 1; + b_length = *b++; + } + else { + a_length = (int) (end - a); + b_length = keyseg->length; + } + + /* remove pre space from keys */ + for ( ; a_length && *a == ' ' ; a++, a_length--) ; + for ( ; b_length && *b == ' ' ; b++, b_length--) ; + + if (keyseg->flag & HA_REVERSE_SORT) { + swap_variables(uchar *, a, b); + swap_variables(uint, a_length, b_length); + } + + if (piks) { + if (*a == '-') { + if (*b != '-') + return -1; + a++; b++; + swap_variables(uchar *, a, b); + swap_variables(uint, a_length, b_length); + a_length--; b_length--; + } + else if (*b == '-') + return 1; + while (a_length && (*a == '+' || *a == '0')) { + a++; a_length--; + } + + while (b_length && (*b == '+' || *b == '0')) { + b++; b_length--; + } + + if (a_length != b_length) + return (a_length < b_length) ? -1 : 1; + while (b_length) { + if (*a++ != *b++) + return ((int) a[-1] - (int) b[-1]); + b_length--; + } + } + a = end; + b += b_length; + break; + } +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: { + longlong ll_a = sint8korr(a); + longlong ll_b = sint8korr(b); + if (piks && (flag = CMP_NUM(ll_a,ll_b))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } + case HA_KEYTYPE_ULONGLONG: { + ulonglong ll_a = uint8korr(a); + ulonglong ll_b = uint8korr(b); + if (piks && (flag = CMP_NUM(ll_a,ll_b))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a = end; + b += keyseg->length; + break; + } +#endif + case HA_KEYTYPE_BIT: + /* TODO: What here? */ + break; + case HA_KEYTYPE_END: /* Ready */ + goto end; + } + } + + end: + return 0; +} + +xtPublic u_int myxt_key_seg_length(XTIndexSegRec *keyseg, u_int key_offset, xtWord1 *key_value) +{ + register xtWord1 *a = (xtWord1 *) key_value + key_offset; + u_int a_length; + u_int has_null = 0; + u_int key_length = 0; + u_int pack_len; + + /* Handle NULL part */ + if (keyseg->null_bit) { + has_null++; + /* If the value is null, then it only requires one byte: */ + if (!*a++) + return has_null; + } + + key_length = has_null + keyseg->length; + + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ + if (keyseg->flag & HA_SPACE_PACK) { + get_key_pack_length(a_length, pack_len, a); + key_length = has_null + a_length + pack_len; + } + break; + case HA_KEYTYPE_BINARY: + if (keyseg->flag & HA_SPACE_PACK) { + get_key_pack_length(a_length, pack_len, a); + key_length = has_null + a_length + pack_len; + } + break; + case HA_KEYTYPE_VARTEXT1: + case HA_KEYTYPE_VARTEXT2: + case HA_KEYTYPE_VARBINARY1: + case HA_KEYTYPE_VARBINARY2: { + get_key_pack_length(a_length, pack_len, a); + key_length = has_null + a_length + pack_len; + break; + } + case HA_KEYTYPE_INT8: + case HA_KEYTYPE_SHORT_INT: + case HA_KEYTYPE_USHORT_INT: + case HA_KEYTYPE_LONG_INT: + case HA_KEYTYPE_ULONG_INT: + case HA_KEYTYPE_INT24: + case HA_KEYTYPE_UINT24: + case HA_KEYTYPE_FLOAT: + case HA_KEYTYPE_DOUBLE: + break; + case HA_KEYTYPE_NUM: { + /* Numeric key */ + if (keyseg->flag & HA_SPACE_PACK) { + a_length = *a++; + key_length = has_null + a_length + 1; + } + break; + } +#ifdef HAVE_LONG_LONG + case HA_KEYTYPE_LONGLONG: + case HA_KEYTYPE_ULONGLONG: + break; +#endif + case HA_KEYTYPE_BIT: + /* TODO: What here? */ + break; + case HA_KEYTYPE_END: /* Ready */ + break; + } + + return key_length; +} + +/* + * ----------------------------------------------------------------------- + * Load and store rows + */ + +xtPublic xtWord4 myxt_store_row_length(XTOpenTablePtr ot, char *rec_buff) +{ + TABLE *table = ot->ot_table->tab_dic.dic_my_table; + char *sdata; + xtWord4 dlen; + xtWord4 item_size; + xtWord4 row_size = 0; + + for (Field **field=table->field ; *field ; field++) { + if ((*field)->is_null_in_record((const uchar *) rec_buff)) { + sdata = NULL; + dlen = 0; + item_size = 1; + } + else { + sdata = mx_get_length_and_data(*field, rec_buff, &dlen); + if (!dlen) { + /* Empty, but not null (blobs may return NULL, when + * length is 0. + */ + sdata = rec_buff; // Any valid pointer will do + item_size = 1 + dlen; + } + else if (dlen <= 240) + item_size = 1 + dlen; + else if (dlen <= 0xFFFF) + item_size = 3 + dlen; + else if (dlen <= 0xFFFFFF) + item_size = 4 + dlen; + else + item_size = 5 + dlen; + } + + row_size += item_size; + } + return row_size; +} + +static xtWord4 mx_store_row(XTOpenTablePtr ot, xtWord4 row_size, char *rec_buff) +{ + TABLE *table = ot->ot_table->tab_dic.dic_my_table; + char *sdata; + xtWord4 dlen; + xtWord4 item_size; + + for (Field **field=table->field ; *field ; field++) { + if ((*field)->is_null_in_record((const uchar *) rec_buff)) { + sdata = NULL; + dlen = 0; + item_size = 1; + } + else { + sdata = mx_get_length_and_data(*field, rec_buff, &dlen); + if (!dlen) { + /* Empty, but not null (blobs may return NULL, when + * length is 0. + */ + sdata = rec_buff; // Any valid pointer will do + item_size = 1 + dlen; + } + else if (dlen <= 240) + item_size = 1 + dlen; + else if (dlen <= 0xFFFF) + item_size = 3 + dlen; + else if (dlen <= 0xFFFFFF) + item_size = 4 + dlen; + else + item_size = 5 + dlen; + } + + if (row_size + item_size > ot->ot_row_wbuf_size) { + if (!xt_realloc_ns((void **) &ot->ot_row_wbuffer, row_size + item_size)) + return 0; + ot->ot_row_wbuf_size = row_size + item_size; + } + + if (!sdata) + ot->ot_row_wbuffer[row_size] = 255; + else if (dlen <= 240) { + ot->ot_row_wbuffer[row_size] = (unsigned char) dlen; + memcpy(&ot->ot_row_wbuffer[row_size+1], sdata, dlen); + } + else if (dlen <= 0xFFFF) { + ot->ot_row_wbuffer[row_size] = 254; + XT_SET_DISK_2(&ot->ot_row_wbuffer[row_size+1], dlen); + memcpy(&ot->ot_row_wbuffer[row_size+3], sdata, dlen); + } + else if (dlen <= 0xFFFFFF) { + ot->ot_row_wbuffer[row_size] = 253; + XT_SET_DISK_3(&ot->ot_row_wbuffer[row_size+1], dlen); + memcpy(&ot->ot_row_wbuffer[row_size+4], sdata, dlen); + } + else { + ot->ot_row_wbuffer[row_size] = 252; + XT_SET_DISK_4(&ot->ot_row_wbuffer[row_size+1], dlen); + memcpy(&ot->ot_row_wbuffer[row_size+5], sdata, dlen); + } + + row_size += item_size; + } + return row_size; +} + +/* Count the number and size of whole columns in the given buffer. */ +xtPublic size_t myxt_load_row_length(XTOpenTablePtr ot, size_t buffer_size, xtWord1 *source_buf, u_int *ret_col_cnt) +{ + u_int col_cnt; + xtWord4 len; + size_t size = 0; + u_int i; + + col_cnt = ot->ot_table->tab_dic.dic_no_of_cols; + if (ret_col_cnt) + col_cnt = *ret_col_cnt; + for (i=0; i<col_cnt; i++) { + if (size + 1 > buffer_size) + goto done; + switch (*source_buf) { + case 255: // Indicate NULL value + size++; + source_buf++; + break; + case 254: // 2 bytes length + if (size + 3 > buffer_size) + goto done; + len = XT_GET_DISK_2(source_buf + 1); + if (size + 3 + len > buffer_size) + goto done; + size += 3 + len; + source_buf += 3 + len; + break; + case 253: // 3 bytes length + if (size + 4 > buffer_size) + goto done; + len = XT_GET_DISK_3(source_buf + 1); + if (size + 4 + len > buffer_size) + goto done; + size += 4 + len; + source_buf += 4 + len; + break; + case 252: // 4 bytes length + if (size + 5 > buffer_size) + goto done; + len = XT_GET_DISK_4(source_buf + 1); + if (size + 5 + len > buffer_size) + goto done; + size += 5 + len; + source_buf += 5 + len; + break; + default: // Length byte + len = *source_buf; + if (size + 1 + len > buffer_size) + goto done; + size += 1 + len; + source_buf += 1 + len; + break; + } + } + + done: + if (ret_col_cnt) + *ret_col_cnt = i; + return size; +} + +/* Unload from PBXT variable length format to the MySQL row format. */ +xtPublic xtBool myxt_load_row(XTOpenTablePtr ot, xtWord1 *source_buf, xtWord1 *dest_buff, u_int col_cnt) +{ + TABLE *table; + xtWord4 len; + Field *curr_field; + xtBool is_null; + u_int i = 0; + + if (!(table = ot->ot_table->tab_dic.dic_my_table)) { + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_NO_DICTIONARY, ot->ot_table->tab_name); + return FAILED; + } + + /* According to the InnoDB implementation: + * "MySQL assumes that all columns + * have the SQL NULL bit set unless it + * is a nullable column with a non-NULL value". + */ + memset(dest_buff, 0xFF, table->s->null_bytes); + for (Field **field=table->field ; *field && (!col_cnt || i<col_cnt); field++, i++) { + curr_field = *field; + is_null = FALSE; + switch (*source_buf) { + case 255: // Indicate NULL value + is_null = TRUE; + len = 0; + source_buf++; + break; + case 254: // 2 bytes length + len = XT_GET_DISK_2(source_buf + 1); + source_buf += 3; + break; + case 253: // 3 bytes length + len = XT_GET_DISK_3(source_buf + 1); + source_buf += 4; + break; + case 252: // 4 bytes length + len = XT_GET_DISK_4(source_buf + 1); + source_buf += 5; + break; + default: // Length byte + if (*source_buf > 240) { + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_BAD_RECORD_FORMAT); + return FAILED; + } + len = *source_buf; + source_buf++; + break; + } + + if (is_null) + mx_set_length_and_data(curr_field, (char *) dest_buff, 0, NULL); + else + mx_set_length_and_data(curr_field, (char *) dest_buff, len, (char *) source_buf); + + source_buf += len; + } + return OK; +} + +xtPublic xtBool myxt_find_column(XTOpenTablePtr ot, u_int *col_idx, const char *col_name) +{ + TABLE *table = ot->ot_table->tab_dic.dic_my_table; + u_int i=0; + + for (Field **field=table->field; *field; field++, i++) { + if (!my_strcasecmp(system_charset_info, (*field)->field_name, col_name)) { + *col_idx = i; + return OK; + } + } + return FALSE; +} + +xtPublic void myxt_get_column_name(XTOpenTablePtr ot, u_int col_idx, u_int len, char *col_name) +{ + TABLE *table = ot->ot_table->tab_dic.dic_my_table; + Field *field; + + field = table->field[col_idx]; + xt_strcpy(len, col_name, field->field_name); +} + +xtPublic void myxt_get_column_as_string(XTOpenTablePtr ot, char *buffer, u_int col_idx, u_int len, char *value) +{ + XTTableHPtr tab = ot->ot_table; + XTThreadPtr self = ot->ot_thread; + TABLE *table = tab->tab_dic.dic_my_table; + Field *field = table->field[col_idx]; + char buf_val[MAX_FIELD_WIDTH]; + String val(buf_val, sizeof(buf_val), &my_charset_bin); + + if (mx_is_null_in_record(field, buffer)) + xt_strcpy(len, value, "NULL"); + else { + byte *save; + + /* Required by store() - or an assertion will fail: */ + if (table->read_set) + bitmap_set_bit(table->read_set, col_idx); + + save = field->ptr; + xt_lock_mutex(self, &tab->tab_dic_field_lock); + pushr_(xt_unlock_mutex, &tab->tab_dic_field_lock); +#if MYSQL_VERSION_ID < 50114 + field->ptr = (byte *) buffer + field->offset(); +#else + field->ptr = (byte *) buffer + field->offset(field->table->record[0]); +#endif + field->val_str(&val); + field->ptr = save; // Restore org row pointer + freer_(); // xt_unlock_mutex(&tab->tab_dic_field_lock) + xt_strcpy(len, value, val.c_ptr()); + } +} + +xtPublic xtBool myxt_set_column(XTOpenTablePtr ot, char *buffer, u_int col_idx, const char *value, u_int len) +{ + XTTableHPtr tab = ot->ot_table; + XTThreadPtr self = ot->ot_thread; + TABLE *table = tab->tab_dic.dic_my_table; + Field *field = table->field[col_idx]; + byte *save; + int error; + + /* Required by store() - or an assertion will fail: */ + if (table->write_set) + bitmap_set_bit(table->write_set, col_idx); + + mx_set_notnull_in_record(field, buffer); + + save = field->ptr; + xt_lock_mutex(self, &tab->tab_dic_field_lock); + pushr_(xt_unlock_mutex, &tab->tab_dic_field_lock); +#if MYSQL_VERSION_ID < 50114 + field->ptr = (byte *) buffer + field->offset(); +#else + field->ptr = (byte *) buffer + field->offset(field->table->record[0]); +#endif + error = field->store(value, len, &my_charset_utf8_general_ci); + field->ptr = save; // Restore org row pointer + freer_(); // xt_unlock_mutex(&tab->tab_dic_field_lock) + return error ? FAILED : OK; +} + +xtPublic void myxt_get_column_data(XTOpenTablePtr ot, char *buffer, u_int col_idx, char **value, size_t *len) +{ + TABLE *table = ot->ot_table->tab_dic.dic_my_table; + Field *field = table->field[col_idx]; + char *sdata; + xtWord4 dlen; + + sdata = mx_get_length_and_data(field, buffer, &dlen); + *value = sdata; + *len = dlen; +} + +xtPublic xtBool myxt_store_row(XTOpenTablePtr ot, XTTabRecInfoPtr rec_info, char *rec_buff) +{ + if (ot->ot_rec_fixed) { + rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) ot->ot_row_wbuffer; + rec_info->ri_rec_buf_size = ot->ot_rec_size; + rec_info->ri_ext_rec = NULL; + + rec_info->ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_FIXED; + memcpy(rec_info->ri_fix_rec_buf->rf_data, rec_buff, ot->ot_rec_size - XT_REC_FIX_HEADER_SIZE); + } + else { + xtWord4 row_size; + + if (!(row_size = mx_store_row(ot, XT_REC_EXT_HEADER_SIZE, rec_buff))) + return FAILED; + if (row_size - XT_REC_FIX_EXT_HEADER_DIFF <= ot->ot_rec_size) { + rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) &ot->ot_row_wbuffer[XT_REC_FIX_EXT_HEADER_DIFF]; + rec_info->ri_rec_buf_size = row_size - XT_REC_FIX_EXT_HEADER_DIFF; + rec_info->ri_ext_rec = NULL; + + rec_info->ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_VARIABLE; + } + else { + rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) ot->ot_row_wbuffer; + rec_info->ri_rec_buf_size = ot->ot_rec_size; + rec_info->ri_ext_rec = (XTTabRecExtDPtr) ot->ot_row_wbuffer; + rec_info->ri_log_data_size = row_size - ot->ot_rec_size; + rec_info->ri_log_buf = (XTactExtRecEntryDPtr) &ot->ot_row_wbuffer[ot->ot_rec_size - offsetof(XTactExtRecEntryDRec, er_data)]; + + rec_info->ri_ext_rec->tr_rec_type_1 = XT_TAB_STATUS_EXT_DLOG; + XT_SET_DISK_4(rec_info->ri_ext_rec->re_log_dat_siz_4, rec_info->ri_log_data_size); + } + } + return OK; +} + +static void mx_print_string(uchar *s, uint count) +{ + while (count > 0) { + if (s[count - 1] != ' ') + break; + count--; + } + printf("\""); + for (u_int i=0; i<count; i++, s++) + printf("%c", *s); + printf("\""); +} + +xtPublic void myxt_print_key(XTIndexPtr ind, xtWord1 *key_value) +{ + register XTIndexSegRec *keyseg = ind->mi_seg; + register uchar *b = (uchar *) key_value; + uint b_length; + uint pack_len; + + for (u_int i = 0; i < ind->mi_seg_count; i++, keyseg++) { + if (i!=0) + printf(" "); + if (keyseg->null_bit) { + if (!*b++) { + printf("NULL"); + continue; + } + } + switch ((enum ha_base_keytype) keyseg->type) { + case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ + if (keyseg->flag & HA_SPACE_PACK) { + get_key_pack_length(b_length, pack_len, b); + } + else + b_length = keyseg->length; + mx_print_string(b, b_length); + b += b_length; + break; + case HA_KEYTYPE_LONG_INT: { + int32 l_2 = sint4korr(b); + b += keyseg->length; + printf("%ld", (long) l_2); + break; + } + case HA_KEYTYPE_ULONG_INT: { + xtWord4 u_2 = sint4korr(b); + b += keyseg->length; + printf("%lu", (u_long) u_2); + break; + } + default: + break; + } + } +} + +/* + * ----------------------------------------------------------------------- + * MySQL Data Dictionary + */ + +#define TS(x) (x)->s + +static void my_close_table(TABLE *table) +{ +#ifndef DRIZZLED + closefrm(table, 1); // TODO: Q, why did Stewart remove this? +#endif + xt_free_ns(table); +} + +/* + * This function returns NULL if the table cannot be opened + * because this is not a MySQL thread. + */ +static TABLE *my_open_table(XTThreadPtr self, XTDatabaseHPtr db __attribute__((unused)), XTPathStrPtr tab_path) +{ + THD *thd = current_thd; + char path_buffer[PATH_MAX]; + char *table_name; + char database_name[XT_IDENTIFIER_NAME_SIZE]; + char *ptr; + size_t size; + char *buffer, *path, *db_name, *name; + TABLE_SHARE *share; + int error; + TABLE *table; + + /* If we have no MySQL thread, then we cannot open this table! + * What this means is the thread is probably the sweeper or the + * compactor. + */ + if (!thd) + return NULL; + + /* GOTCHA: Check if the table name is a partitian, + * if so we need to remove the partition + * extension, in order for this to work! + * + * Reason: the parts of a partition table do not + * have .frm files!! + */ + xt_strcpy(PATH_MAX, path_buffer, tab_path->ps_path); + table_name = xt_last_name_of_path(path_buffer); + if ((ptr = strstr(table_name, "#P#"))) + *ptr = 0; + + xt_2nd_last_name_of_path(XT_IDENTIFIER_NAME_SIZE, database_name, path_buffer); + + size = sizeof(TABLE) + sizeof(TABLE_SHARE) + + strlen(path_buffer) + 1 + + strlen(database_name) + 1 + strlen(table_name) + 1; + if (!(buffer = (char *) xt_malloc(self, size))) + return NULL; + table = (TABLE *) buffer; + buffer += sizeof(TABLE); + share = (TABLE_SHARE *) buffer; + buffer += sizeof(TABLE_SHARE); + + path = buffer; + strcpy(path, path_buffer); + buffer += strlen(path_buffer) + 1; + db_name = buffer; + strcpy(db_name, database_name); + buffer += strlen(database_name) + 1; + name = buffer; + strcpy(name, table_name); + + /* Required to call 'open_table_from_share'! */ + LEX *old_lex, new_lex; + + old_lex = thd->lex; + thd->lex = &new_lex; + new_lex.current_select= NULL; + lex_start(thd); + +#if MYSQL_VERSION_ID < 60000 +#if MYSQL_VERSION_ID < 50123 + init_tmp_table_share(share, db_name, 0, name, path); +#else + init_tmp_table_share(thd, share, db_name, 0, name, path); +#endif +#else +#if MYSQL_VERSION_ID < 60004 + init_tmp_table_share(share, db_name, 0, name, path); +#else + init_tmp_table_share(thd, share, db_name, 0, name, path); +#endif +#endif + + if ((error = open_table_def(thd, share, 0))) { + xt_free(self, table); + lex_end(&new_lex); + thd->lex = old_lex; + xt_throw_ulxterr(XT_CONTEXT, XT_ERR_LOADING_MYSQL_DIC, (u_long) error); + return NULL; + } + +#if MYSQL_VERSION_ID >= 60003 + if ((error = open_table_from_share(thd, share, "", 0, (uint) READ_ALL, 0, table, OTM_OPEN))) +#else + if ((error = open_table_from_share(thd, share, "", 0, (uint) READ_ALL, 0, table, FALSE))) +#endif + { + xt_free(self, table); + lex_end(&new_lex); + thd->lex = old_lex; + xt_throw_ulxterr(XT_CONTEXT, XT_ERR_LOADING_MYSQL_DIC, (u_long) error); + return NULL; + } + + lex_end(&new_lex); + thd->lex = old_lex; + + /* GOTCHA: I am the plug-in!!! Therefore, I should not hold + * a reference to myself. By holding this reference I prevent + * plugin_shutdown() and reap_plugins() in sql_plugin.cc + * from doing their job on shutdown! + */ + plugin_unlock(NULL, table->s->db_plugin); + table->s->db_plugin = NULL; + return table; +} + +/* +static bool my_match_index(XTDDIndex *ind, KEY *index) +{ + KEY_PART_INFO *key_part; + KEY_PART_INFO *key_part_end; + u_int j; + XTDDColumnRef *cref; + + if (index->key_parts != ind->co_cols.size()) + return false; + + j=0; + key_part_end = index->key_part + index->key_parts; + for (key_part = index->key_part; key_part != key_part_end; key_part++, j++) { + if (!(cref = ind->co_cols.itemAt(j))) + return false; + if (myxt_strcasecmp(cref->cr_col_name, (char *) key_part->field->field_name) != 0) + return false; + } + + if (ind->co_type == XT_DD_KEY_PRIMARY) { + if (!(index->flags & HA_NOSAME)) + return false; + } + else { + if (ind->co_type == XT_DD_INDEX_UNIQUE) { + if (!(index->flags & HA_NOSAME)) + return false; + } + if (ind->co_ind_name) { + if (myxt_strcasecmp(ind->co_ind_name, index->name) != 0) + return false; + } + } + + return true; +} + +static XTDDIndex *my_find_index(XTDDTable *dd_tab, KEY *index) +{ + XTDDIndex *ind; + + for (u_int i=0; i<dd_tab->dt_indexes.size(); i++) + { + ind = dd_tab->dt_indexes.itemAt(i); + if (my_match_index(ind, index)) + return ind; + } + return NULL; +} +*/ + +static void my_deref_index_data(struct XTThread *self, XTIndexPtr mi) +{ + enter_(); + /* The dirty list of cache pages should be empty here! */ + ASSERT(!mi->mi_dirty_list); + ASSERT(!mi->mi_free_list); + + xt_free_mutex(&mi->mi_flush_lock); + xt_spinlock_free(self, &mi->mi_dirty_lock); + XT_INDEX_FREE_LOCK(self, mi); + myxt_bitmap_free(self, &mi->mi_col_map); + if (mi->mi_free_list) + xt_free(self, mi->mi_free_list); + + xt_free(self, mi); + exit_(); +} + +static xtBool my_is_not_null_int4(XTIndexSegPtr seg) +{ + return (seg->type == HA_KEYTYPE_LONG_INT && !(seg->flag & HA_NULL_PART)); +} + +/* Derived from ha_myisam::create and mi_create */ +static XTIndexPtr my_create_index(XTThreadPtr self, TABLE *table_arg, u_int idx, KEY *index) +{ + XTIndexPtr ind; + KEY_PART_INFO *key_part; + KEY_PART_INFO *key_part_end; + XTIndexSegRec *seg; + Field *field; + enum ha_base_keytype type; + uint options = 0; + u_int key_length = 0; + xtBool partial_field; + + enter_(); + + pushsr_(ind, my_deref_index_data, (XTIndexPtr) xt_calloc(self, offsetof(XTIndexRec, mi_seg) + sizeof(XTIndexSegRec) * index->key_parts)); + + XT_INDEX_INIT_LOCK(self, ind); + xt_init_mutex_with_autoname(self, &ind->mi_flush_lock); + xt_spinlock_init_with_autoname(self, &ind->mi_dirty_lock); + ind->mi_index_no = idx; + ind->mi_flags = (index->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL | HA_UNIQUE_CHECK)); + ind->mi_low_byte_first = TS(table_arg)->db_low_byte_first; + ind->mi_fix_key = TRUE; + ind->mi_select_total = 0; + ind->mi_subset_of = 0; + myxt_bitmap_init(self, &ind->mi_col_map, TS(table_arg)->fields); + + ind->mi_seg_count = (uint) index->key_parts; + key_part_end = index->key_part + index->key_parts; + seg = ind->mi_seg; + for (key_part = index->key_part; key_part != key_part_end; key_part++, seg++) { + partial_field = FALSE; + field = key_part->field; + + type = field->key_type(); + seg->flag = key_part->key_part_flag; + + if (options & HA_OPTION_PACK_KEYS || + (index->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | HA_SPACE_PACK_USED))) + { + if (key_part->length > 8 && (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_NUM || + (type == HA_KEYTYPE_BINARY && !field->zero_pack()))) + { + /* No blobs here */ + if (key_part == index->key_part) + ind->mi_flags |= HA_PACK_KEY; +#ifndef DRIZZLED + if (!(field->flags & ZEROFILL_FLAG) && + (field->type() == MYSQL_TYPE_STRING || + field->type() == MYSQL_TYPE_VAR_STRING || + ((int) (key_part->length - field->decimals())) >= 4)) + seg->flag |= HA_SPACE_PACK; +#endif + } + } + + seg->col_idx = field->field_index; + seg->is_recs_in_range = 1; + seg->is_selectivity = 1; + seg->type = (int) type; + seg->start = key_part->offset; + seg->length = key_part->length; + seg->bit_start = seg->bit_end = 0; + seg->bit_length = seg->bit_pos = 0; + seg->charset = field->charset(); + + if (field->null_ptr) { + key_length++; + seg->flag |= HA_NULL_PART; + seg->null_bit = field->null_bit; + seg->null_pos = (uint) (field->null_ptr - (uchar*) table_arg->record[0]); + } + else { + seg->null_bit = 0; + seg->null_pos = 0; + } + + if (field->real_type() == MYSQL_TYPE_ENUM +#ifndef DRIZZLED + || field->real_type() == MYSQL_TYPE_SET +#endif + ) { + /* This values are not indexed as string!! + * The index will not be built correctly if this value is non-NULL. + */ + seg->charset = NULL; + } + + if (field->type() == MYSQL_TYPE_BLOB +#ifndef DRIZZLED + || field->type() == MYSQL_TYPE_GEOMETRY +#endif + ) { + seg->flag |= HA_BLOB_PART; + /* save number of bytes used to pack length */ + seg->bit_start = (uint) (field->pack_length() - TS(table_arg)->blob_ptr_size); + } +#ifndef DRIZZLED + else if (field->type() == MYSQL_TYPE_BIT) { + seg->bit_length = ((Field_bit *) field)->bit_len; + seg->bit_start = ((Field_bit *) field)->bit_ofs; + seg->bit_pos = (uint) (((Field_bit *) field)->bit_ptr - (uchar*) table_arg->record[0]); + } +#else + /* Drizzle uses HA_KEYTYPE_ULONG_INT keys for enums > 1 byte, which is not consistent with MySQL, so we fix it here */ + else if (field->type() == MYSQL_TYPE_ENUM) { + switch (seg->length) { + case 2: + seg->type = HA_KEYTYPE_USHORT_INT; + break; + case 3: + seg->type = HA_KEYTYPE_UINT24; + break; + } + } +#endif + + switch (seg->type) { + case HA_KEYTYPE_VARTEXT1: + case HA_KEYTYPE_VARTEXT2: + case HA_KEYTYPE_VARBINARY1: + case HA_KEYTYPE_VARBINARY2: + if (!(seg->flag & HA_BLOB_PART)) { + /* Make a flag that this is a VARCHAR */ + seg->flag |= HA_VAR_LENGTH_PART; + /* Store in bit_start number of bytes used to pack the length */ + seg->bit_start = ((seg->type == HA_KEYTYPE_VARTEXT1 || seg->type == HA_KEYTYPE_VARBINARY1) ? 1 : 2); + } + break; + } + + /* All packed fields start with a length (1 or 3 bytes): */ + if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK)) { + key_length++; /* At least one length byte */ + if (seg->length >= 255) /* prefix may be 3 bytes */ + key_length +=2; + } + + key_length += seg->length; + if (seg->length > 40) + ind->mi_fix_key = FALSE; + + /* Determine if only part of the field is in the key: + * This is important for index coverage! + * Note, BLOB fields are never retrieved from + * an index! + */ + if (field->type() == MYSQL_TYPE_BLOB) + partial_field = TRUE; + else if (field->real_type() == MYSQL_TYPE_VARCHAR // For varbinary type +#ifndef DRIZZLED + || field->real_type() == MYSQL_TYPE_VAR_STRING // For varbinary type + || field->real_type() == MYSQL_TYPE_STRING // For binary type +#endif + ) + { + Field *tab_field = table_arg->field[key_part->fieldnr-1]; + u_int field_len = tab_field->key_length(); + + if (key_part->length != field_len) + partial_field = TRUE; + } + + /* NOTE: do not set if the field is only partially in the index!!! */ + if (!partial_field) + bitmap_fast_test_and_set(&ind->mi_col_map, field->field_index); + } + + if (key_length > XT_INDEX_MAX_KEY_SIZE) + xt_throw_sulxterr(XT_CONTEXT, XT_ERR_KEY_TOO_LARGE, index->name, (u_long) XT_INDEX_MAX_KEY_SIZE); + + /* This is the maximum size of the index on disk: */ + ind->mi_key_size = key_length; + + if (ind->mi_fix_key) { + /* Special case for not-NULL 4 byte int value: */ + switch (ind->mi_seg_count) { + case 1: + ind->mi_single_type = ind->mi_seg[0].type; + if (ind->mi_seg[0].type == HA_KEYTYPE_LONG_INT || + ind->mi_seg[0].type == HA_KEYTYPE_ULONG_INT) { + if (!(ind->mi_seg[0].flag & HA_NULL_PART)) + ind->mi_scan_branch = xt_scan_branch_single; + } + break; + case 2: + if (my_is_not_null_int4(&ind->mi_seg[0]) && + my_is_not_null_int4(&ind->mi_seg[1])) { + ind->mi_scan_branch = xt_scan_branch_fix_simple; + ind->mi_simple_comp_key = xt_compare_2_int4; + } + break; + case 3: + if (my_is_not_null_int4(&ind->mi_seg[0]) && + my_is_not_null_int4(&ind->mi_seg[1]) && + my_is_not_null_int4(&ind->mi_seg[2])) { + ind->mi_scan_branch = xt_scan_branch_fix_simple; + ind->mi_simple_comp_key = xt_compare_3_int4; + } + break; + } + if (!ind->mi_scan_branch) + ind->mi_scan_branch = xt_scan_branch_fix; + ind->mi_prev_item = xt_prev_branch_item_fix; + ind->mi_last_item = xt_last_branch_item_fix; + } + else { + ind->mi_scan_branch = xt_scan_branch_var; + ind->mi_prev_item = xt_prev_branch_item_var; + ind->mi_last_item = xt_last_branch_item_var; + } + + XT_NODE_ID(ind->mi_root) = 0; + + popr_(); // Discard my_deref_index_data(ind) + + return_(ind); +} + +/* We estimate the size of BLOBs depending on the number + * of BLOBs in the table. + */ +static u_int mx_blob_field_size_total[] = { + 500, // 1 + 400, // 2 + 350, // 3 + 320, // 4 + 300, // 5 + 280, // 6 + 260, // 7 + 240, // 8 + 220, // 9 + 210 // 10 +}; + +static u_int mxvarchar_field_min_ave[] = { + 120, // 1 + 105, // 2 + 90, // 3 + 65, // 4 + 50, // 5 + 40, // 6 + 40, // 7 + 40, // 8 + 40, // 9 + 40 // 10 +}; + +xtPublic void myxt_setup_dictionary(XTThreadPtr self, XTDictionaryPtr dic) +{ + TABLE *my_tab = dic->dic_my_table; + u_int field_count; + u_int var_field_count = 0; + u_int varchar_field_count = 0; + u_int blob_field_count = 0; + u_int large_blob_field_count = 0; + xtWord8 min_data_size = 0; + xtWord8 max_data_size = 0; + xtWord8 ave_data_size = 0; + xtWord8 min_row_size = 0; + xtWord8 max_row_size = 0; + xtWord8 ave_row_size = 0; + xtWord8 min_ave_row_size = 0; + xtWord8 max_ave_row_size = 0; + u_int dic_rec_size; + xtBool dic_rec_fixed; + Field *curr_field; + Field **field; + + /* How many columns are required for all indexes. */ + KEY *index; + KEY_PART_INFO *key_part; + KEY_PART_INFO *key_part_end; + + dic->dic_ind_cols_req = 0; + for (uint i=0; i<TS(my_tab)->keys; i++) { + index = &my_tab->key_info[i]; + + key_part_end = index->key_part + index->key_parts; + for (key_part = index->key_part; key_part != key_part_end; key_part++) { + curr_field = key_part->field; + + if ((u_int) curr_field->field_index+1 > dic->dic_ind_cols_req) + dic->dic_ind_cols_req = curr_field->field_index+1; + } + } + + /* We will work out how many columns are required for all blobs: */ + dic->dic_blob_cols_req = 0; + field_count = 0; + for (field=my_tab->field; (curr_field = *field); field++) { + field_count++; + min_data_size = curr_field->key_length(); + max_data_size = curr_field->key_length(); + enum_field_types tno = curr_field->type(); + + min_ave_row_size = 40; + max_ave_row_size = 128; + if (tno == MYSQL_TYPE_BLOB) { + blob_field_count++; + min_data_size = 0; + max_data_size = ((Field_blob *) curr_field)->max_data_length(); + /* Set the average length higher for BLOBs: */ + if (max_data_size == 0xFFFF || + max_data_size == 0xFFFFFF) { + if (large_blob_field_count < 10) + max_ave_row_size = mx_blob_field_size_total[large_blob_field_count]; + else + max_ave_row_size = 200; + large_blob_field_count++; + } + else if (max_data_size == 0xFFFFFFFF) { + /* Scale the estimated size of the blob depending on how many BLOBs + * are in the table! + */ + if (large_blob_field_count < 10) + max_ave_row_size = mx_blob_field_size_total[large_blob_field_count]; + else + max_ave_row_size = 200; + large_blob_field_count++; + if ((u_int) curr_field->field_index+1 > dic->dic_blob_cols_req) + dic->dic_blob_cols_req = curr_field->field_index+1; + dic->dic_blob_count++; + xt_realloc(self, (void **) &dic->dic_blob_cols, sizeof(Field *) * dic->dic_blob_count); + dic->dic_blob_cols[dic->dic_blob_count-1] = curr_field; + } + } + else if (tno == MYSQL_TYPE_VARCHAR +#ifndef DRIZZLED + || tno == MYSQL_TYPE_VAR_STRING +#endif + ) { + /* GOTCHA: MYSQL_TYPE_VAR_STRING does not exist as MYSQL_TYPE_VARCHAR define, but + * is used when creating a table with + * VARCHAR() + */ + min_data_size = 0; + if (varchar_field_count < 10) + min_ave_row_size = mxvarchar_field_min_ave[varchar_field_count]; + else + min_ave_row_size = 40; + varchar_field_count++; + } + + if (max_data_size == min_data_size) + ave_data_size = max_data_size; + else { + var_field_count++; + /* Take the average a 25% of the maximum: */ + ave_data_size = max_data_size / 4; + + /* Set the average based on min and max parameters: */ + if (ave_data_size < min_ave_row_size) + ave_data_size = min_ave_row_size; + else if (ave_data_size > max_ave_row_size) + ave_data_size = max_ave_row_size; + + if (ave_data_size > max_data_size) + ave_data_size = max_data_size; + } + + /* Add space for the length indicators: */ + if (min_data_size <= 240) + min_row_size += 1 + min_data_size; + else if (min_data_size <= 0xFFFF) + min_row_size += 3 + min_data_size; + else if (min_data_size <= 0xFFFFFF) + min_row_size += 4 + min_data_size; + else + min_row_size += 5 + min_data_size; + + if (max_data_size <= 240) + max_row_size += 1 + max_data_size; + else if (max_data_size <= 0xFFFF) + max_row_size += 3 + max_data_size; + else if (max_data_size <= 0xFFFFFF) + max_row_size += 4 + max_data_size; + else + max_row_size += 5 + max_data_size; + + if (ave_data_size <= 240) + ave_row_size += 1 + ave_data_size; + else /* Should not be more than this! */ + ave_row_size += 3 + ave_data_size; + + /* This is the length of the record required for all indexes: */ + if (field_count + 1 == dic->dic_ind_cols_req) + dic->dic_ind_rec_len = max_data_size; + } + + dic->dic_min_row_size = min_row_size; + dic->dic_max_row_size = max_row_size; + dic->dic_ave_row_size = ave_row_size; + dic->dic_no_of_cols = field_count; + + if (dic->dic_def_ave_row_size) { + /* The average row size has been set: */ + dic_rec_size = offsetof(XTTabRecFix, rf_data) + TS(my_tab)->reclength; + + /* The conditions for a fixed record are: */ + if (dic->dic_def_ave_row_size >= (xtWord8) TS(my_tab)->reclength && + dic_rec_size <= XT_TAB_MAX_FIX_REC_LENGTH && + !blob_field_count) { + dic_rec_fixed = TRUE; + } + else { + xtWord8 new_rec_size; + + dic_rec_fixed = FALSE; + if (dic->dic_def_ave_row_size > max_row_size) + new_rec_size = offsetof(XTTabRecFix, rf_data) + max_row_size; + else + new_rec_size = offsetof(XTTabRecFix, rf_data) + dic->dic_def_ave_row_size; + + /* The maximum record size 64K for explicit AVG_ROW_LENGTH! */ + if (new_rec_size > XT_TAB_MAX_FIX_REC_LENGTH_SPEC) + new_rec_size = XT_TAB_MAX_FIX_REC_LENGTH_SPEC; + + dic_rec_size = (u_int) new_rec_size; + } + } + else { + /* If the average size is within 10% if of the maximum size, then we + * we handle these rows as fixed size rows. + * Fixed size rows use the internal MySQL format. + */ + dic_rec_size = offsetof(XTTabRecFix, rf_data) + TS(my_tab)->reclength; + /* Fixed length records must be less than 16K in size, + * have an average size which is very close (20%) to the maximum size or + * be less than a minimum size, + * and not contain any BLOBs: + */ + if (dic_rec_size <= XT_TAB_MAX_FIX_REC_LENGTH && + (ave_row_size + ave_row_size / 4 >= max_row_size || + dic_rec_size < XT_TAB_MIN_VAR_REC_LENGTH) && + !blob_field_count) { + dic_rec_fixed = TRUE; + } + else { + dic_rec_fixed = FALSE; + /* Note I add offsetof(XTTabRecFix, rf_data) insteard of + * offsetof(XTTabRecExt, re_data) here! + * The reason is that, we want to include the average size + * record in the fixed data part. To do this we only need to + * calculate a fixed header size, because in the cases in which + * it fits, we will only be using a fixed header! + */ + dic_rec_size = (u_int) (offsetof(XTTabRecFix, rf_data) + ave_row_size); + /* The maximum record size (16K for autorow sizing)! */ + if (dic_rec_size > XT_TAB_MAX_FIX_REC_LENGTH) + dic_rec_size = XT_TAB_MAX_FIX_REC_LENGTH; + } + } + + if (!dic->dic_rec_size) { + dic->dic_rec_size = dic_rec_size; + dic->dic_rec_fixed = dic_rec_fixed; + } + else { + /* This just confirms that our original calculation on + * create table agrees with the current calculation. + * (i.e. if non-zero values were loaded from the table). + * + * It may be the criteria for calculating the data record size + * and whether to used a fixed or variable record has changed, + * but we need to stick to the current physical layout of the + * table. + * + * Note that this can occur in rename table when the + * method of calculation has changed. + * + * On rename, the format of the table does not change, so we + * will not take the calculated values. + */ + //ASSERT(dic->dic_rec_size == dic_rec_size); + //ASSERT(dic->dic_rec_fixed == dic_rec_fixed); + } + + if (dic_rec_fixed) { + /* Recalculate the length of the required required to address all + * index columns! + */ + if (field_count == dic->dic_ind_cols_req) + dic->dic_ind_rec_len = TS(my_tab)->reclength; + else { + field=my_tab->field; + + curr_field = field[dic->dic_ind_cols_req]; +#if MYSQL_VERSION_ID < 50114 + dic->dic_ind_rec_len = curr_field->offset(); +#else + dic->dic_ind_rec_len = curr_field->offset(curr_field->table->record[0]); +#endif + } + } + + /* We now calculate how many of the first columns in the row + * will definitely fit into the buffer, when the record is + * of type extended. + * + * In this way we can figure out if we need to load the extended + * record at all. + */ + dic->dic_fix_col_count = 0; + if (!dic_rec_fixed) { + xtWord8 max_rec_size = offsetof(XTTabRecExt, re_data); + + for (Field **f=my_tab->field; (curr_field = *f); f++) { + max_data_size = curr_field->key_length(); + enum_field_types tno = curr_field->type(); + if (tno == MYSQL_TYPE_BLOB) + max_data_size = ((Field_blob *) curr_field)->max_data_length(); + if (max_data_size <= 240) + max_rec_size += 1 + max_data_size; + else if (max_data_size <= 0xFFFF) + max_rec_size += 3 + max_data_size; + else if (max_data_size <= 0xFFFFFF) + max_rec_size += 4 + max_data_size; + else + max_rec_size += 5 + max_data_size; + if (max_rec_size > (xtWord8) dic_rec_size) + break; + dic->dic_fix_col_count++; + } + ASSERT(dic->dic_fix_col_count < dic->dic_no_of_cols); + } + + dic->dic_key_count = TS(my_tab)->keys; + dic->dic_mysql_buf_size = TS(my_tab)->rec_buff_length; + dic->dic_mysql_rec_size = TS(my_tab)->reclength; +} + +static u_int my_get_best_superset(XTThreadPtr self __attribute__((unused)), XTDictionaryPtr dic, XTIndexPtr ind) +{ + XTIndexPtr super_ind; + u_int super = 0; + u_int super_seg_count = ind->mi_seg_count; + + for (u_int i=0; i<dic->dic_key_count; i++) { + super_ind = dic->dic_keys[i]; + if (ind->mi_index_no != super_ind->mi_index_no && + super_seg_count < super_ind->mi_seg_count) { + for (u_int j=0; j<ind->mi_seg_count; j++) { + if (ind->mi_seg[j].col_idx != super_ind->mi_seg[j].col_idx) + goto next; + } + super_seg_count = super_ind->mi_seg_count; + super = i+1; + next:; + } + } + return super; +} + +/* + * Return FAILED if the MySQL dictionary is not available. + */ +xtPublic xtBool myxt_load_dictionary(XTThreadPtr self, XTDictionaryPtr dic, XTDatabaseHPtr db, XTPathStrPtr tab_path) +{ + TABLE *my_tab; + + if (!(my_tab = my_open_table(self, db, tab_path))) + return FAILED; + dic->dic_my_table = my_tab; + dic->dic_def_ave_row_size = (xtWord8) my_tab->s->avg_row_length; + myxt_setup_dictionary(self, dic); + dic->dic_keys = (XTIndexPtr *) xt_calloc(self, sizeof(XTIndexPtr) * TS(my_tab)->keys); + for (uint i=0; i<TS(my_tab)->keys; i++) + dic->dic_keys[i] = my_create_index(self, my_tab, i, &my_tab->key_info[i]); + + /* Check if any key is a subset of another: */ + for (u_int i=0; i<dic->dic_key_count; i++) + dic->dic_keys[i]->mi_subset_of = my_get_best_superset(self, dic, dic->dic_keys[i]); + + return OK; +} + +xtPublic void myxt_free_dictionary(XTThreadPtr self, XTDictionaryPtr dic) +{ + if (dic->dic_table) { + dic->dic_table->release(self); + dic->dic_table = NULL; + } + + if (dic->dic_my_table) { + my_close_table(dic->dic_my_table); + dic->dic_my_table = NULL; + } + + if (dic->dic_blob_cols) { + xt_free(self, dic->dic_blob_cols); + dic->dic_blob_cols = NULL; + } + dic->dic_blob_count = 0; + + /* If we have opened a table, then this data is freed with the dictionary: */ + if (dic->dic_keys) { + for (uint i=0; i<dic->dic_key_count; i++) { + if (dic->dic_keys[i]) + my_deref_index_data(self, (XTIndexPtr) dic->dic_keys[i]); + } + xt_free(self, dic->dic_keys); + dic->dic_key_count = 0; + dic->dic_keys = NULL; + } +} + +xtPublic void myxt_move_dictionary(XTDictionaryPtr dic, XTDictionaryPtr source_dic) +{ + dic->dic_my_table = source_dic->dic_my_table; + source_dic->dic_my_table = NULL; + + if (!dic->dic_rec_size) { + dic->dic_rec_size = source_dic->dic_rec_size; + dic->dic_rec_fixed = source_dic->dic_rec_fixed; + } + else { + /* This just confirms that our original calculation on + * create table agrees with the current calculation. + * (i.e. if non-zero values were loaded from the table). + * + * It may be the criteria for calculating the data record size + * and whether to used a fixed or variable record has changed, + * but we need to stick to the current physical layout of the + * table. + */ + ASSERT_NS(dic->dic_rec_size == source_dic->dic_rec_size); + ASSERT_NS(dic->dic_rec_fixed == source_dic->dic_rec_fixed); + } + + dic->dic_tab_flags = source_dic->dic_tab_flags; + dic->dic_blob_cols_req = source_dic->dic_blob_cols_req; + dic->dic_blob_count = source_dic->dic_blob_count; + dic->dic_blob_cols = source_dic->dic_blob_cols; + source_dic->dic_blob_cols = NULL; + + dic->dic_mysql_buf_size = source_dic->dic_mysql_buf_size; + dic->dic_mysql_rec_size = source_dic->dic_mysql_rec_size; + dic->dic_key_count = source_dic->dic_key_count; + dic->dic_keys = source_dic->dic_keys; + + /* Set this to zero, bcause later xt_flush_tables() may be called. + * This can occur when using the BLOB streaming engine, + * in command ALTER TABLE x ENGINE = PBXT; + */ + source_dic->dic_key_count = 0; + source_dic->dic_keys = NULL; + + dic->dic_min_row_size = source_dic->dic_min_row_size; + dic->dic_max_row_size = source_dic->dic_max_row_size; + dic->dic_ave_row_size = source_dic->dic_ave_row_size; + dic->dic_def_ave_row_size = source_dic->dic_def_ave_row_size; + + dic->dic_no_of_cols = source_dic->dic_no_of_cols; + dic->dic_fix_col_count = source_dic->dic_fix_col_count; + dic->dic_ind_cols_req = source_dic->dic_ind_cols_req; + dic->dic_ind_rec_len = source_dic->dic_ind_rec_len; +} + +static void my_free_dd_table(XTThreadPtr self, XTDDTable *dd_tab) +{ + if (dd_tab) + dd_tab->release(self); +} + +static void ha_create_dd_index(XTThreadPtr self, XTDDIndex *ind, KEY *key) +{ + KEY_PART_INFO *key_part; + KEY_PART_INFO *key_part_end; + XTDDColumnRef *cref; + + if (strcmp(key->name, "PRIMARY") == 0) + ind->co_type = XT_DD_KEY_PRIMARY; + else if (key->flags & HA_NOSAME) + ind->co_type = XT_DD_INDEX_UNIQUE; + else + ind->co_type = XT_DD_INDEX; + + if (ind->co_type == XT_DD_KEY_PRIMARY) + ind->co_name = xt_dup_string(self, key->name); + else + ind->co_ind_name = xt_dup_string(self, key->name); + + key_part_end = key->key_part + key->key_parts; + for (key_part = key->key_part; key_part != key_part_end; key_part++) { + if (!(cref = new XTDDColumnRef())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + ind->co_cols.append(self, cref); + cref->cr_col_name = xt_dup_string(self, (char *) key_part->field->field_name); + } +} + +static char *my_type_to_string(XTThreadPtr self, Field *field, TABLE *my_tab __attribute__((unused))) +{ + char buffer[MAX_FIELD_WIDTH + 400], *ptr; + String type((char *) buffer, sizeof(buffer), system_charset_info); + + /* GOTCHA: + * - Above sets the string length to the same as the buffer, + * so we must set the length to zero. + * - The result is not necessarilly zero terminated. + * - We cannot assume that the input buffer is the one + * we get back (for example text field). + */ + type.length(0); + field->sql_type(type); + ptr = type.c_ptr(); + if (ptr != buffer) + xt_strcpy(sizeof(buffer), buffer, ptr); + + if (field->has_charset()) { + /* Always include the charset so that we can compare types + * for FK/PK releations. + */ + xt_strcat(sizeof(buffer), buffer, " CHARACTER SET "); + xt_strcat(sizeof(buffer), buffer, (char *) field->charset()->csname); + + /* For string types dump collation name only if + * collation is not primary for the given charset + */ + if (!(field->charset()->state & MY_CS_PRIMARY)) { + xt_strcat(sizeof(buffer), buffer, " COLLATE "); + xt_strcat(sizeof(buffer), buffer, (char *) field->charset()->name); + } + } + + return xt_dup_string(self, buffer); // type.length() +} + +xtPublic XTDDTable *myxt_create_table_from_table(XTThreadPtr self, TABLE *my_tab) +{ + XTDDTable *dd_tab; + Field *curr_field; + XTDDColumn *col; + XTDDIndex *ind; + + if (!(dd_tab = new XTDDTable())) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + dd_tab->init(self); + pushr_(my_free_dd_table, dd_tab); + + for (Field **field=my_tab->field; (curr_field = *field); field++) { + col = XTDDColumnFactory::createFromMySQLField(self, my_tab, curr_field); + dd_tab->dt_cols.append(self, col); + } + + for (uint i=0; i<TS(my_tab)->keys; i++) { + if (!(ind = (XTDDIndex *) new XTDDIndex(XT_DD_UNKNOWN))) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + dd_tab->dt_indexes.append(self, ind); + ind->co_table = dd_tab; + ind->in_index = i; + ha_create_dd_index(self, ind, &my_tab->key_info[i]); + } + + popr_(); // my_free_dd_table(dd_tab) + return dd_tab; +} + +/* + * ----------------------------------------------------------------------- + * MySQL CHARACTER UTILITIES + */ + +xtPublic void myxt_static_convert_identifier(XTThreadPtr self __attribute__((unused)), MX_CHARSET_INFO *cs, char *from, char *to, size_t to_len) +{ + uint errors; + + /* + * Bug#4417 + * Check that identifiers and strings are not converted + * when the client character set is binary. + */ + if (cs == &my_charset_utf8_general_ci || cs == &my_charset_bin) + xt_strcpy(to_len, to, from); + else + strconvert(cs, from, &my_charset_utf8_general_ci, to, to_len, &errors); +} + +// cs == current_thd->charset() +xtPublic char *myxt_convert_identifier(XTThreadPtr self, MX_CHARSET_INFO *cs, char *from) +{ + uint errors; + u_int len; + char *to; + + if (cs == &my_charset_utf8_general_ci || cs == &my_charset_bin) + to = xt_dup_string(self, from); + else { + len = strlen(from) * 3 + 1; + to = (char *) xt_malloc(self, len); + strconvert(cs, from, &my_charset_utf8_general_ci, to, len, &errors); + } + return to; +} + +xtPublic char *myxt_convert_table_name(XTThreadPtr self, char *from) +{ + u_int len; + char *to; + + len = strlen(from) * 5 + 1; + to = (char *) xt_malloc(self, len); + tablename_to_filename(from, to, len); + return to; +} + +xtPublic void myxt_static_convert_table_name(XTThreadPtr self __attribute__((unused)), char *from, char *to, size_t to_len) +{ + tablename_to_filename(from, to, to_len); +} + +xtPublic int myxt_strcasecmp(char * a, char *b) +{ + return my_strcasecmp(&my_charset_utf8_general_ci, a, b); +} + +xtPublic int myxt_isspace(MX_CHARSET_INFO *cs, char a) +{ + return my_isspace(cs, a); +} + +xtPublic int myxt_ispunct(MX_CHARSET_INFO *cs, char a) +{ + return my_ispunct(cs, a); +} + +xtPublic int myxt_isdigit(MX_CHARSET_INFO *cs, char a) +{ + return my_isdigit(cs, a); +} + +xtPublic MX_CHARSET_INFO *myxt_getcharset(bool convert) +{ + if (convert) { + THD *thd = current_thd; + + if (thd) + return thd_charset(thd); + } + return &my_charset_utf8_general_ci; +} + +#ifdef XT_STREAMING +xtPublic xtBool myxt_use_blobs(XTOpenTablePtr ot, void **ret_pbms_table, xtWord1 *rec_buf) +{ + void *pbms_table; + XTTable *tab = ot->ot_table; + u_int idx = 0; + Field *field; + char *blob_ref; + xtWord4 len; + char in_url[PBMS_BLOB_URL_SIZE]; + char *out_url; + + if (!xt_pbms_open_table(&pbms_table, tab->tab_name->ps_path)) + return FAILED; + + for (idx=0; idx<tab->tab_dic.dic_blob_count; idx++) { + field = tab->tab_dic.dic_blob_cols[idx]; + if ((blob_ref = mx_get_length_and_data(field, (char *) rec_buf, &len)) && len) { + xt_strncpy(PBMS_BLOB_URL_SIZE, in_url, blob_ref, len); + + if (!xt_pbms_use_blob(pbms_table, &out_url, in_url, field->field_index)) { + xt_pbms_close_table(pbms_table); + return FAILED; + } + + if (out_url) { + len = strlen(out_url); + mx_set_length_and_data(field, (char *) rec_buf, len, out_url); + } + } + } + *ret_pbms_table = pbms_table; + return OK; +} + +xtPublic void myxt_unuse_blobs(XTOpenTablePtr ot __attribute__((unused)), void *pbms_table) +{ + xt_pbms_close_table(pbms_table); +} + +xtPublic xtBool myxt_retain_blobs(XTOpenTablePtr ot __attribute__((unused)), void *pbms_table, xtRecordID rec_id) +{ + xtBool ok; + PBMSEngineRefRec eng_ref; + + memset(&eng_ref, 0, sizeof(PBMSEngineRefRec)); + XT_SET_DISK_8(eng_ref.er_data, rec_id); + ok = xt_pbms_retain_blobs(pbms_table, &eng_ref); + xt_pbms_close_table(pbms_table); + return ok; +} + +xtPublic void myxt_release_blobs(XTOpenTablePtr ot, xtWord1 *rec_buf, xtRecordID rec_id) +{ + void *pbms_table; + XTTable *tab = ot->ot_table; + u_int idx = 0; + Field *field; + char *blob_ref; + xtWord4 len; + char in_url[PBMS_BLOB_URL_SIZE]; + PBMSEngineRefRec eng_ref; + + memset(&eng_ref, 0, sizeof(PBMSEngineRefRec)); + XT_SET_DISK_8(eng_ref.er_data, rec_id); + + if (!xt_pbms_open_table(&pbms_table, tab->tab_name->ps_path)) + return; + + for (idx=0; idx<tab->tab_dic.dic_blob_count; idx++) { + field = tab->tab_dic.dic_blob_cols[idx]; + if ((blob_ref = mx_get_length_and_data(field, (char *) rec_buf, &len)) && len) { + xt_strncpy(PBMS_BLOB_URL_SIZE, in_url, blob_ref, len); + + xt_pbms_release_blob(pbms_table, in_url, field->field_index, &eng_ref); + } + } + + xt_pbms_close_table(pbms_table); +} +#endif // XT_STREAMING + +xtPublic void *myxt_create_thread() +{ + THD *new_thd; + + if (my_thread_init()) { + xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to initialize MySQL threading"); + return NULL; + } + + if (!(new_thd = new THD())) { + my_thread_end(); + xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to create MySQL thread (THD)"); + return NULL; + } + + new_thd->thread_stack = (char *) &new_thd; + new_thd->store_globals(); + lex_start(new_thd); + + return (void *) new_thd; +} + +xtPublic void myxt_destroy_thread(void *thread, xtBool end_threads) +{ + THD *thd = (THD *) thread; + +#if MYSQL_VERSION_ID > 60005 + /* PMC - This is a HACK! It is required because + * MySQL shuts down MDL before shutting down the + * plug-ins. + */ + if (!pbxt_inited) + mdl_init(); + close_thread_tables(thd); + if (!pbxt_inited) + mdl_destroy(); +#else + close_thread_tables(thd); +#endif + + delete thd; + + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + + if (end_threads) + my_thread_end(); +} + +xtPublic XTThreadPtr myxt_get_self() +{ + THD *thd; + + if ((thd = current_thd)) + return xt_ha_thd_to_self(thd); + return NULL; +} + +/* + * ----------------------------------------------------------------------- + * INFORMATION SCHEMA FUNCTIONS + * + */ + +static int mx_put_record(THD *thd, TABLE *table) +{ + return schema_table_store_record(thd, table); +} + +#ifdef UNUSED_CODE +static void mx_put_int(TABLE *table, int column, int value) +{ + table->field[column]->store(value, false); +} + +static void mx_put_real8(TABLE *table, int column, xtReal8 value) +{ + table->field[column]->store(value); +} + +static void mx_put_string(TABLE *table, int column, const char *string, u_int len, charset_info_st *charset) +{ + table->field[column]->store(string, len, charset); +} +#endif + +static void mx_put_u_llong(TABLE *table, int column, u_llong value) +{ + table->field[column]->store(value, false); +} + +static void mx_put_string(TABLE *table, int column, const char *string, charset_info_st *charset) +{ + table->field[column]->store(string, strlen(string), charset); +} + +xtPublic int myxt_statistics_fill_table(XTThreadPtr self, void *th, void *ta, void *, MX_CONST void *ch) +{ + THD *thd = (THD *) th; + TABLE_LIST *tables = (TABLE_LIST *) ta; + charset_info_st *charset = (charset_info_st *) ch; + TABLE *table = (TABLE *) tables->table; + int err = 0; + int col; + const char *stat_name; + u_llong stat_value; + XTStatisticsRec statistics; + + xt_gather_statistics(&statistics); + for (u_int rec_id=0; !err && rec_id<XT_STAT_CURRENT_MAX; rec_id++) { + stat_name = xt_get_stat_meta_data(rec_id)->sm_name; + stat_value = xt_get_statistic(&statistics, self->st_database, rec_id); + + col=0; + mx_put_u_llong(table, col++, rec_id+1); + mx_put_string(table, col++, stat_name, charset); + mx_put_u_llong(table, col++, stat_value); + err = mx_put_record(thd, table); + } + + return err; +} + +xtPublic void myxt_get_status(XTThreadPtr self, XTStringBufferPtr strbuf) +{ + char string[200]; + + xt_sb_concat(self, strbuf, "\n"); + xt_get_now(string, 200); + xt_sb_concat(self, strbuf, string); + xt_sb_concat(self, strbuf, " PBXT "); + xt_sb_concat(self, strbuf, xt_get_version()); + xt_sb_concat(self, strbuf, " STATUS OUTPUT"); + xt_sb_concat(self, strbuf, "\n"); + + xt_sb_concat(self, strbuf, "Record cache usage: "); + xt_sb_concat_int8(self, strbuf, xt_tc_get_usage()); + xt_sb_concat(self, strbuf, "\n"); + xt_sb_concat(self, strbuf, "Record cache size: "); + xt_sb_concat_int8(self, strbuf, xt_tc_get_size()); + xt_sb_concat(self, strbuf, "\n"); + xt_sb_concat(self, strbuf, "Record cache high: "); + xt_sb_concat_int8(self, strbuf, xt_tc_get_high()); + xt_sb_concat(self, strbuf, "\n"); + xt_sb_concat(self, strbuf, "Index cache usage: "); + xt_sb_concat_int8(self, strbuf, xt_ind_get_usage()); + xt_sb_concat(self, strbuf, "\n"); + xt_sb_concat(self, strbuf, "Index cache size: "); + xt_sb_concat_int8(self, strbuf, xt_ind_get_size()); + xt_sb_concat(self, strbuf, "\n"); + xt_sb_concat(self, strbuf, "Log cache usage: "); + xt_sb_concat_int8(self, strbuf, xt_xlog_get_usage()); + xt_sb_concat(self, strbuf, "\n"); + xt_sb_concat(self, strbuf, "Log cache size: "); + xt_sb_concat_int8(self, strbuf, xt_xlog_get_size()); + xt_sb_concat(self, strbuf, "\n"); + + xt_ht_lock(self, xt_db_open_databases); + pushr_(xt_ht_unlock, xt_db_open_databases); + + XTDatabaseHPtr *dbptr; + size_t len = xt_sl_get_size(xt_db_open_db_by_id); + + if (len > 0) { + xt_sb_concat(self, strbuf, "Data log files:\n"); + for (u_int i=0; i<len; i++) { + dbptr = (XTDatabaseHPtr *) xt_sl_item_at(xt_db_open_db_by_id, i); + +#ifndef XT_USE_GLOBAL_DB + xt_sb_concat(self, strbuf, "Database: "); + xt_sb_concat(self, strbuf, (*dbptr)->db_name); + xt_sb_concat(self, strbuf, "\n"); +#endif + xt_dl_log_status(self, *dbptr, strbuf); + } + } + else + xt_sb_concat(self, strbuf, "No data logs in use\n"); + + freer_(); // xt_ht_unlock(xt_db_open_databases) +} + +/* + * ----------------------------------------------------------------------- + * MySQL Bit Maps + */ + +xtPublic void myxt_bitmap_init(XTThreadPtr self, MY_BITMAP *map, u_int n_bits) +{ + my_bitmap_map *buf; + uint size_in_bytes = (((n_bits) + 31) / 32) * 4; + + buf = (my_bitmap_map *) xt_malloc(self, size_in_bytes); + map->bitmap= buf; + map->n_bits= n_bits; + create_last_word_mask(map); + bitmap_clear_all(map); +} + +xtPublic void myxt_bitmap_free(XTThreadPtr self, MY_BITMAP *map) +{ + if (map->bitmap) { + xt_free(self, map->bitmap); + map->bitmap = NULL; + } +} + +/* + * ----------------------------------------------------------------------- + * XTDDColumnFactory methods + */ + +XTDDColumn *XTDDColumnFactory::createFromMySQLField(XTThread *self, TABLE *my_tab, Field *field) +{ + XTDDEnumerableColumn *en_col; + XTDDColumn *col; + xtBool is_enum = FALSE; + + switch(field->real_type()) { + case MYSQL_TYPE_ENUM: + is_enum = TRUE; + /* fallthrough */ + +#ifndef DRIZZLED + case MYSQL_TYPE_SET: +#endif + col = en_col = new XTDDEnumerableColumn(); + if (!col) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + col->init(self); + en_col->enum_size = ((Field_enum *)field)->typelib->count; + en_col->is_enum = is_enum; + break; + + default: + col = new XTDDColumn(); + if (!col) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + col->init(self); + } + + col->dc_name = xt_dup_string(self, (char *) field->field_name); + col->dc_data_type = my_type_to_string(self, field, my_tab); + col->dc_null_ok = field->null_ptr != NULL; + + return col; +} + diff --git a/storage/pbxt/src/myxt_xt.h b/storage/pbxt/src/myxt_xt.h new file mode 100644 index 00000000000..4d33431088e --- /dev/null +++ b/storage/pbxt/src/myxt_xt.h @@ -0,0 +1,104 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-05-16 Paul McCullagh + * + * H&G2JCtL + * + * These functions implement the parts of PBXT which must conform to the + * key and row format used by MySQL. + */ + +#ifndef __xt_myxt_h__ +#define __xt_myxt_h__ + +#include "xt_defs.h" +#include "table_xt.h" +#include "datadic_xt.h" + +#ifndef MYSQL_VERSION_ID +#error MYSQL_VERSION_ID must be defined! +#endif + +struct XTDictionary; +struct XTDatabase; +STRUCT_TABLE; +struct charset_info_st; + +u_int myxt_create_key_from_key(XTIndexPtr ind, xtWord1 *key, xtWord1 *old, u_int k_length); +u_int myxt_create_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, xtBool *no_duplicate); +u_int myxt_create_foreign_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, XTIndexPtr fkey_ind, xtBool *no_null); +u_int myxt_get_key_length(XTIndexPtr ind, xtWord1 *b_value); +int myxt_compare_key(XTIndexPtr ind, int search_flags, uint key_length, xtWord1 *key_value, xtWord1 *b_value); +u_int myxt_key_seg_length(XTIndexSegRec *keyseg, u_int key_offset, xtWord1 *key_value); +xtBool myxt_create_row_from_key(XTOpenTablePtr ot, XTIndexPtr ind, xtWord1 *key, u_int key_len, xtWord1 *record); +void myxt_set_null_row_from_key(XTOpenTablePtr ot, XTIndexPtr ind, xtWord1 *record); +void myxt_set_default_row_from_key(XTOpenTablePtr ot, XTIndexPtr ind, xtWord1 *record); +void myxt_print_key(XTIndexPtr ind, xtWord1 *key_value); + +xtWord4 myxt_store_row_length(XTOpenTablePtr ot, char *rec_buff); +xtBool myxt_store_row(XTOpenTablePtr ot, XTTabRecInfoPtr rec_info, char *rec_buff); +size_t myxt_load_row_length(XTOpenTablePtr ot, size_t buffer_size, xtWord1 *source_buf, u_int *ret_col_cnt); +xtBool myxt_load_row(XTOpenTablePtr ot, xtWord1 *source_buf, xtWord1 *dest_buff, u_int col_cnt); +xtBool myxt_find_column(XTOpenTablePtr ot, u_int *col_idx, const char *col_name); +void myxt_get_column_name(XTOpenTablePtr ot, u_int col_idx, u_int len, char *col_name); +void myxt_get_column_as_string(XTOpenTablePtr ot, char *buffer, u_int col_idx, u_int len, char *value); +xtBool myxt_set_column(XTOpenTablePtr ot, char *buffer, u_int col_idx, const char *value, u_int len); +void myxt_get_column_data(XTOpenTablePtr ot, char *buffer, u_int col_idx, char **value, size_t *len); + +void myxt_setup_dictionary(XTThreadPtr self, XTDictionary *dic); +xtBool myxt_load_dictionary(XTThreadPtr self, struct XTDictionary *dic, struct XTDatabase *db, XTPathStrPtr tab_path); +void myxt_free_dictionary(XTThreadPtr self, XTDictionary *dic); +void myxt_move_dictionary(XTDictionaryPtr dic, XTDictionaryPtr source_dic); +XTDDTable *myxt_create_table_from_table(XTThreadPtr self, STRUCT_TABLE *my_tab); + +void myxt_static_convert_identifier(XTThreadPtr self, struct charset_info_st *cs, char *from, char *to, size_t to_len); +char *myxt_convert_identifier(XTThreadPtr self, struct charset_info_st *cs, char *from); +void myxt_static_convert_table_name(XTThreadPtr self, char *from, char *to, size_t to_len); +char *myxt_convert_table_name(XTThreadPtr self, char *from); +int myxt_strcasecmp(char * a, char *b); +int myxt_isspace(struct charset_info_st *cs, char a); +int myxt_ispunct(struct charset_info_st *cs, char a); +int myxt_isdigit(struct charset_info_st *cs, char a); + +struct charset_info_st *myxt_getcharset(bool convert); + +#ifdef XT_STREAMING +xtBool myxt_use_blobs(XTOpenTablePtr ot, void **ret_pbms_table, xtWord1 *rec_buf); +void myxt_unuse_blobs(XTOpenTablePtr ot, void *pbms_table); +xtBool myxt_retain_blobs(XTOpenTablePtr ot, void *pbms_table, xtRecordID record); +void myxt_release_blobs(XTOpenTablePtr ot, xtWord1 *rec_buf, xtRecordID record); +#endif + +void *myxt_create_thread(); +void myxt_destroy_thread(void *thread, xtBool end_threads); +XTThreadPtr myxt_get_self(); + +int myxt_statistics_fill_table(XTThreadPtr self, void *th, void *ta, void *co, MX_CONST void *ch); +void myxt_get_status(XTThreadPtr self, XTStringBufferPtr strbuf); + +void myxt_bitmap_init(XTThreadPtr self, MY_BITMAP *map, u_int n_bits); +void myxt_bitmap_free(XTThreadPtr self, MY_BITMAP *map); + +class XTDDColumnFactory +{ +public: + static XTDDColumn *createFromMySQLField(XTThread *self, STRUCT_TABLE *, Field *); +}; + +#endif diff --git a/storage/pbxt/src/pbms.h b/storage/pbxt/src/pbms.h new file mode 100644 index 00000000000..1c1f4e71c04 --- /dev/null +++ b/storage/pbxt/src/pbms.h @@ -0,0 +1,866 @@ +/* Copyright (c) 2007 PrimeBase Technologies GmbH + * + * PrimeBase Media Stream for MySQL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Paul McCullagh + * H&G2JCtL + * + * 2007-06-01 + * + * This file contains the BLOB streaming interface engines that + * are streaming enabled. + * + */ +#ifndef __streaming_unx_h__ +#define __streaming_unx_h__ + +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <dirent.h> +#include <signal.h> +#include <ctype.h> + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#define MS_SHARED_MEMORY_MAGIC 0x7E9A120C +#define MS_ENGINE_VERSION 1 +#define MS_CALLBACK_VERSION 1 +#define MS_SHARED_MEMORY_VERSION 1 +#define MS_ENGINE_LIST_SIZE 80 +#define MS_TEMP_FILE_PREFIX "pbms_temp_" +#define MS_TEMP_FILE_PREFIX "pbms_temp_" + +#define MS_RESULT_MESSAGE_SIZE 300 +#define MS_RESULT_STACK_SIZE 200 + +#define MS_BLOB_HANDLE_SIZE 300 + +#define SH_MASK ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH)) + +#define MS_OK 0 +#define MS_ERR_ENGINE 1 /* Internal engine error. */ +#define MS_ERR_UNKNOWN_TABLE 2 /* Returned if the engine cannot open the given table. */ +#define MS_ERR_NOT_FOUND 3 /* The BLOB cannot be found. */ +#define MS_ERR_TABLE_LOCKED 4 /* Table is currently locked. */ +#define MS_ERR_INCORRECT_URL 5 +#define MS_ERR_AUTH_FAILED 6 +#define MS_ERR_NOT_IMPLEMENTED 7 +#define MS_ERR_UNKNOWN_DB 8 +#define MS_ERR_REMOVING_REPO 9 +#define MS_ERR_DATABASE_DELETED 10 + +#define MS_LOCK_NONE 0 +#define MS_LOCK_READONLY 1 +#define MS_LOCK_READ_WRITE 2 + +#define MS_XACT_NONE 0 +#define MS_XACT_BEGIN 1 +#define MS_XACT_COMMIT 2 +#define MS_XACT_ROLLBACK 3 + +#define PBMS_ENGINE_REF_LEN 8 +#define PBMS_BLOB_URL_SIZE 200 + +#define PBMS_FIELD_COL_SIZE 128 +#define PBMS_FIELD_COND_SIZE 300 + + +typedef struct PBMSBlobID { + u_int64_t bi_blob_size; + u_int64_t bi_blob_id; // or repo file offset if type = REPO + u_int32_t bi_tab_id; // or repo ID if type = REPO + u_int32_t bi_auth_code; + u_int32_t bi_blob_type; +} PBMSBlobIDRec, *PBMSBlobIDPtr; + +typedef struct PBMSResultRec { + int mr_code; /* Engine specific error code. */ + char mr_message[MS_RESULT_MESSAGE_SIZE]; /* Error message, required if non-zero return code. */ + char mr_stack[MS_RESULT_STACK_SIZE]; /* Trace information about where the error occurred. */ +} PBMSResultRec, *PBMSResultPtr; + +typedef struct PBMSEngineRefRec { + unsigned char er_data[PBMS_ENGINE_REF_LEN]; +} PBMSEngineRefRec, *PBMSEngineRefPtr; + +typedef struct PBMSBlobURL { + char bu_data[PBMS_BLOB_URL_SIZE]; +} PBMSBlobURLRec, *PBMSBlobURLPtr; + +typedef struct PBMSFieldRef { + char fr_column[PBMS_FIELD_COL_SIZE]; + char fr_cond[PBMS_FIELD_COND_SIZE]; +} PBMSFieldRefRec, *PBMSFieldRefPtr; +/* + * The engine must free its resources for the given thread. + */ +typedef void (*MSCloseConnFunc)(void *thd); + +/* Before access BLOBs of a table, the streaming engine will open the table. + * Open tables are managed as a pool by the streaming engine. + * When a request is received, the streaming engine will ask all + * registered engine to open the table. The engine must return a NULL + * open_table pointer if it does not handle the table. + * A callback allows an engine to request all open tables to be + * closed by the streaming engine. + */ +typedef int (*MSOpenTableFunc)(void *thd, const char *table_url, void **open_table, PBMSResultPtr result); +typedef void (*MSCloseTableFunc)(void *thd, void *open_table); + +/* + * When the streaming engine wants to use an open table handle from the + * pool, it calls the lock table function. + */ +typedef int (*MSLockTableFunc)(void *thd, int *xact, void *open_table, int lock_type, PBMSResultPtr result); +typedef int (*MSUnlockTableFunc)(void *thd, int xact, void *open_table, PBMSResultPtr result); + +/* This function is used to locate and send a BLOB on the given stream. + */ +typedef int (*MSSendBLOBFunc)(void *thd, void *open_table, const char *blob_column, const char *blob_url, void *stream, PBMSResultPtr result); + +/* + * Lookup and engine reference, and return readable text. + */ +typedef int (*MSLookupRefFunc)(void *thd, void *open_table, unsigned short col_index, PBMSEngineRefPtr eng_ref, PBMSFieldRefPtr feild_ref, PBMSResultPtr result); + +typedef struct PBMSEngineRec { + int ms_version; /* MS_ENGINE_VERSION */ + int ms_index; /* The index into the engine list. */ + int ms_removing; /* TRUE (1) if the engine is being removed. */ + const char *ms_engine_name; + void *ms_engine_info; + MSCloseConnFunc ms_close_conn; + MSOpenTableFunc ms_open_table; + MSCloseTableFunc ms_close_table; + MSLockTableFunc ms_lock_table; + MSUnlockTableFunc ms_unlock_table; + MSSendBLOBFunc ms_send_blob; + MSLookupRefFunc ms_lookup_ref; +} PBMSEngineRec, *PBMSEnginePtr; + +/* + * This function should never be called directly, it is called + * by deregisterEngine() below. + */ +typedef void (*ECDeregisterdFunc)(PBMSEnginePtr engine); + +typedef void (*ECTableCloseAllFunc)(const char *table_url); + +typedef int (*ECSetContentLenFunc)(void *stream, off_t len, PBMSResultPtr result); + +typedef int (*ECWriteHeadFunc)(void *stream, PBMSResultPtr result); + +typedef int (*ECWriteStreamFunc)(void *stream, void *buffer, size_t len, PBMSResultPtr result); + +/* + * The engine should call this function from + * its own close connection function! + */ +typedef int (*ECCloseConnFunc)(void *thd, PBMSResultPtr result); + +/* + * Call this function before retaining or releasing BLOBs in a row. + */ +typedef int (*ECOpenTableFunc)(void **open_table, char *table_path, PBMSResultPtr result); + +/* + * Call this function when the operation is complete. + */ +typedef void (*ECCloseTableFunc)(void *open_table); + +/* + * Call this function for each BLOB to be retained. When a BLOB is used, the + * URL may be changed. The returned URL is valid as long as the the + * table is open. + * + * The returned URL must be inserted into the row in place of the given + * URL. + */ +typedef int (*ECUseBlobFunc)(void *open_table, char **ret_blob_url, char *blob_url, unsigned short col_index, PBMSResultPtr result); + +/* + * Reference Blobs that has been uploaded to the streaming engine. + * + * All BLOBs specified by the use blob function are retained by + * this function. + * + * The engine reference is a (unaligned) 8 byte value which + * identifies the row that the BLOBs are in. + */ +typedef int (*ECRetainBlobsFunc)(void *open_table, PBMSEngineRefPtr eng_ref, PBMSResultPtr result); + +/* + * If a row containing a BLOB is deleted, then the BLOBs in the + * row must be released. + * + * Note: if a table is dropped, all the BLOBs referenced by the + * table are automatically released. + */ +typedef int (*ECReleaseBlobFunc)(void *open_table, char *blob_url, unsigned short col_index, PBMSEngineRefPtr eng_ref, PBMSResultPtr result); + +typedef int (*ECDropTable)(const char *table_path, PBMSResultPtr result); + +typedef int (*ECRenameTable)(const char *from_table, const char *to_table, PBMSResultPtr result); + +typedef struct PBMSCallbacksRec { + int cb_version; /* MS_CALLBACK_VERSION */ + ECDeregisterdFunc cb_deregister; + ECTableCloseAllFunc cb_table_close_all; + ECSetContentLenFunc cb_set_cont_len; + ECWriteHeadFunc cb_write_head; + ECWriteStreamFunc cb_write_stream; + ECCloseConnFunc cb_close_conn; + ECOpenTableFunc cb_open_table; + ECCloseTableFunc cb_close_table; + ECUseBlobFunc cb_use_blob; + ECRetainBlobsFunc cb_retain_blobs; + ECReleaseBlobFunc cb_release_blob; + ECDropTable cb_drop_table; + ECRenameTable cb_rename_table; +} PBMSCallbacksRec, *PBMSCallbacksPtr; + +typedef struct PBMSSharedMemoryRec { + int sm_magic; /* MS_SHARED_MEMORY_MAGIC */ + int sm_version; /* MS_SHARED_MEMORY_VERSION */ + volatile int sm_shutdown_lock; /* "Cheap" lock for shutdown! */ + PBMSCallbacksPtr sm_callbacks; + int sm_reserved1[20]; + void *sm_reserved2[20]; + int sm_list_size; + int sm_list_len; + PBMSEnginePtr sm_engine_list[MS_ENGINE_LIST_SIZE]; +} PBMSSharedMemoryRec, *PBMSSharedMemoryPtr; + +#ifndef PBMS_API +#ifndef PBMS_CLIENT_API +Please define he value of PBMS_API +#endif +#else + +class PBMS_API +{ +private: + const char *temp_prefix[3]; + +public: + PBMS_API(): sharedMemory(NULL) { + int i = 0; + temp_prefix[i++] = MS_TEMP_FILE_PREFIX; +#ifdef MS_TEMP_FILE_PREFIX + temp_prefix[i++] = MS_TEMP_FILE_PREFIX; +#endif + temp_prefix[i++] = NULL; + + } + + ~PBMS_API() { } + + /* + * Register the engine with the Stream Engine. + */ + int registerEngine(PBMSEnginePtr engine, PBMSResultPtr result) { + int err; + + deleteTempFiles(); + + if ((err = getSharedMemory(true, result))) + return err; + + for (int i=0; i<sharedMemory->sm_list_size; i++) { + if (!sharedMemory->sm_engine_list[i]) { + sharedMemory->sm_engine_list[i] = engine; + engine->ms_index = i; + if (i >= sharedMemory->sm_list_len) + sharedMemory->sm_list_len = i+1; + return MS_OK; + } + } + + result->mr_code = 15010; + strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "Too many BLOB streaming engines already registered"); + *result->mr_stack = 0; + return MS_ERR_ENGINE; + } + + void lock() { + while (sharedMemory->sm_shutdown_lock) + usleep(10000); + sharedMemory->sm_shutdown_lock++; + while (sharedMemory->sm_shutdown_lock != 1) { + usleep(random() % 10000); + sharedMemory->sm_shutdown_lock--; + usleep(10000); + sharedMemory->sm_shutdown_lock++; + } + } + + void unlock() { + sharedMemory->sm_shutdown_lock--; + } + + void deregisterEngine(PBMSEnginePtr engine) { + PBMSResultRec result; + int err; + + if ((err = getSharedMemory(true, &result))) + return; + + lock(); + + bool empty = true; + for (int i=0; i<sharedMemory->sm_list_len; i++) { + if (sharedMemory->sm_engine_list[i]) { + if (sharedMemory->sm_engine_list[i] == engine) { + if (sharedMemory->sm_callbacks) + sharedMemory->sm_callbacks->cb_deregister(engine); + sharedMemory->sm_engine_list[i] = NULL; + } + else + empty = false; + } + } + + unlock(); + + if (empty) { + char temp_file[100]; + + sharedMemory->sm_magic = 0; + free(sharedMemory); + sharedMemory = NULL; + const char **prefix = temp_prefix; + while (*prefix) { + getTempFileName(temp_file, *prefix, getpid()); + unlink(temp_file); + prefix++; + } + } + } + + void closeAllTables(const char *table_url) + { + PBMSResultRec result; + int err; + + if ((err = getSharedMemory(true, &result))) + return; + + if (sharedMemory->sm_callbacks) + sharedMemory->sm_callbacks->cb_table_close_all(table_url); + } + + int setContentLength(void *stream, off_t len, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + return sharedMemory->sm_callbacks->cb_set_cont_len(stream, len, result); + } + + int writeHead(void *stream, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + return sharedMemory->sm_callbacks->cb_write_head(stream, result); + } + + int writeStream(void *stream, void *buffer, size_t len, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + return sharedMemory->sm_callbacks->cb_write_stream(stream, buffer, len, result); + } + + int closeConn(void *thd, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + if (!sharedMemory->sm_callbacks) + return MS_OK; + + return sharedMemory->sm_callbacks->cb_close_conn(thd, result); + } + + int openTable(void **open_table, char *table_path, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + if (!sharedMemory->sm_callbacks) { + *open_table = NULL; + return MS_OK; + } + + return sharedMemory->sm_callbacks->cb_open_table(open_table, table_path, result); + } + + int closeTable(void *open_table, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + if (sharedMemory->sm_callbacks && open_table) + sharedMemory->sm_callbacks->cb_close_table(open_table); + return MS_OK; + } + + int couldBeURL(char *blob_url) + /* ~*test/~1-150-2b5e0a7-0[*<blob size>][.ext] */ + /* ~*test/_1-150-2b5e0a7-0[*<blob size>][.ext] */ + { + char *ptr; + size_t len; + bool have_blob_size = false; + + if (blob_url) { + if ((len = strlen(blob_url))) { + /* Too short: */ + if (len <= 10) + return 0; + + /* Required prefix: */ + /* NOTE: ~> is deprecated v0.5.4+, now use ~* */ + if (*blob_url != '~' || (*(blob_url + 1) != '>' && *(blob_url + 1) != '*')) + return 0; + + ptr = blob_url + len - 1; + + /* Allow for an optional extension: */ + if (!isdigit(*ptr)) { + while (ptr > blob_url && *ptr != '/' && *ptr != '.') + ptr--; + if (ptr == blob_url || *ptr != '.') + return 0; + if (ptr == blob_url || !isdigit(*ptr)) + return 0; + } + + // field 1: server id OR blob size + do_again: + while (ptr > blob_url && isdigit(*ptr)) + ptr--; + + if (ptr != blob_url && *ptr == '*' && !have_blob_size) { + ptr--; + have_blob_size = true; + goto do_again; + } + + if (ptr == blob_url || *ptr != '-') + return 0; + + + // field 2: Authoration code + ptr--; + if (!isxdigit(*ptr)) + return 0; + + while (ptr > blob_url && isxdigit(*ptr)) + ptr--; + + if (ptr == blob_url || *ptr != '-') + return 0; + + // field 3:offset + ptr--; + if (!isxdigit(*ptr)) + return 0; + + while (ptr > blob_url && isdigit(*ptr)) + ptr--; + + if (ptr == blob_url || *ptr != '-') + return 0; + + + // field 4:Table id + ptr--; + if (!isdigit(*ptr)) + return 0; + + while (ptr > blob_url && isdigit(*ptr)) + ptr--; + + /* NOTE: ^ and : are deprecated v0.5.4+, now use ! and ~ */ + if (ptr == blob_url || (*ptr != '^' && *ptr != ':' && *ptr != '_' && *ptr != '~')) + return 0; + ptr--; + + if (ptr == blob_url || *ptr != '/') + return 0; + ptr--; + if (ptr == blob_url) + return 0; + return 1; + } + } + return 0; + } + + int useBlob(void *open_table, char **ret_blob_url, char *blob_url, unsigned short col_index, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + if (!couldBeURL(blob_url)) { + *ret_blob_url = NULL; + return MS_OK; + } + + if (!sharedMemory->sm_callbacks) { + result->mr_code = MS_ERR_INCORRECT_URL; + strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "BLOB streaming engine (PBMS) not installed"); + *result->mr_stack = 0; + return MS_ERR_INCORRECT_URL; + } + + return sharedMemory->sm_callbacks->cb_use_blob(open_table, ret_blob_url, blob_url, col_index, result); + } + + int retainBlobs(void *open_table, PBMSEngineRefPtr eng_ref, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + if (!sharedMemory->sm_callbacks) + return MS_OK; + + return sharedMemory->sm_callbacks->cb_retain_blobs(open_table, eng_ref, result); + } + + int releaseBlob(void *open_table, char *blob_url, unsigned short col_index, PBMSEngineRefPtr eng_ref, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + if (!sharedMemory->sm_callbacks) + return MS_OK; + + if (!couldBeURL(blob_url)) + return MS_OK; + + return sharedMemory->sm_callbacks->cb_release_blob(open_table, blob_url, col_index, eng_ref, result); + } + + int dropTable(const char *table_path, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + if (!sharedMemory->sm_callbacks) + return MS_OK; + + return sharedMemory->sm_callbacks->cb_drop_table(table_path, result); + } + + int renameTable(const char *from_table, const char *to_table, PBMSResultPtr result) + { + int err; + + if ((err = getSharedMemory(true, result))) + return err; + + if (!sharedMemory->sm_callbacks) + return MS_OK; + + return sharedMemory->sm_callbacks->cb_rename_table(from_table, to_table, result); + } + + volatile PBMSSharedMemoryPtr sharedMemory; + +private: + int getSharedMemory(bool create, PBMSResultPtr result) + { + int tmp_f; + int r; + char temp_file[100]; + const char **prefix = temp_prefix; + void *tmp_p = NULL; + + if (sharedMemory) + return MS_OK; + + while (*prefix) { + getTempFileName(temp_file, *prefix, getpid()); + tmp_f = open(temp_file, O_RDWR | (create ? O_CREAT : 0), SH_MASK); + if (tmp_f == -1) + return setOSResult(errno, "open", temp_file, result); + + r = lseek(tmp_f, 0, SEEK_SET); + if (r == -1) { + close(tmp_f); + return setOSResult(errno, "lseek", temp_file, result); + } + ssize_t tfer; + char buffer[100]; + + tfer = read(tmp_f, buffer, 100); + if (tfer == -1) { + close(tmp_f); + return setOSResult(errno, "read", temp_file, result); + } + + buffer[tfer] = 0; + sscanf(buffer, "%p", &tmp_p); + sharedMemory = (PBMSSharedMemoryPtr) tmp_p; + if (!sharedMemory || sharedMemory->sm_magic != MS_SHARED_MEMORY_MAGIC) { + if (!create) + return MS_OK; + + sharedMemory = (PBMSSharedMemoryPtr) calloc(1, sizeof(PBMSSharedMemoryRec)); + sharedMemory->sm_magic = MS_SHARED_MEMORY_MAGIC; + sharedMemory->sm_version = MS_SHARED_MEMORY_VERSION; + sharedMemory->sm_list_size = MS_ENGINE_LIST_SIZE; + + r = lseek(tmp_f, 0, SEEK_SET); + if (r == -1) { + close(tmp_f); + return setOSResult(errno, "fseek", temp_file, result); + } + + sprintf(buffer, "%p", (void *) sharedMemory); + tfer = write(tmp_f, buffer, strlen(buffer)); + if (tfer != (ssize_t) strlen(buffer)) { + close(tmp_f); + return setOSResult(errno, "write", temp_file, result); + } + r = fsync(tmp_f); + if (r == -1) { + close(tmp_f); + return setOSResult(errno, "fsync", temp_file, result); + } + } + else if (sharedMemory->sm_version != MS_SHARED_MEMORY_VERSION) { + close(tmp_f); + result->mr_code = -1000; + *result->mr_stack = 0; + strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "Shared memory version: "); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, sharedMemory->sm_version); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, ", does not match engine shared memory version: "); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, MS_SHARED_MEMORY_VERSION); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, "."); + return MS_ERR_ENGINE; + } + close(tmp_f); + + // For backward compatability we need to create the old versions but we only need to read the current version. + if (create) + prefix++; + else + break; + } + return MS_OK; + } + + void strcpy(size_t size, char *to, const char *from) + { + if (size > 0) { + size--; + while (*from && size--) + *to++ = *from++; + *to = 0; + } + } + + void strcat(size_t size, char *to, const char *from) + { + while (*to && size--) to++; + strcpy(size, to, from); + } + + void strcat(size_t size, char *to, int val) + { + char buffer[100]; + + sprintf(buffer, "%d", val); + strcat(size, to, buffer); + } + + int setOSResult(int err, const char *func, char *file, PBMSResultPtr result) { + char *msg; + + result->mr_code = err; + *result->mr_stack = 0; + strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "System call "); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, func); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, "() failed on "); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, file); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, ": "); + +#ifdef XT_WIN + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, iMessage + strlen(iMessage), MS_RESULT_MESSAGE_SIZE - strlen(iMessage), NULL)) { + char *ptr; + + ptr = &iMessage[strlen(iMessage)]; + while (ptr-1 > err_msg) { + if (*(ptr-1) != '\n' && *(ptr-1) != '\r' && *(ptr-1) != '.') + break; + ptr--; + } + *ptr = 0; + + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, " ("); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, err); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, ")"); + return MS_ERR_ENGINE; + } +#endif + + msg = strerror(err); + if (msg) { + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, msg); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, " ("); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, err); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, ")"); + } + else { + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, "Unknown OS error code "); + strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, err); + } + + return MS_ERR_ENGINE; + } + + void getTempFileName(char *temp_file, const char * prefix, int pid) + { + sprintf(temp_file, "/tmp/%s%d", prefix, pid); + } + + bool startsWith(const char *cstr, const char *w_cstr) + { + while (*cstr && *w_cstr) { + if (*cstr != *w_cstr) + return false; + cstr++; + w_cstr++; + } + return *cstr || !*w_cstr; + } + + void deleteTempFiles() + { + struct dirent entry; + struct dirent *result; + DIR *odir; + int err; + char temp_file[100]; + + if (!(odir = opendir("/tmp/"))) + return; + err = readdir_r(odir, &entry, &result); + while (!err && result) { + const char **prefix = temp_prefix; + + while (*prefix) { + if (startsWith(entry.d_name, *prefix)) { + int pid = atoi(entry.d_name + strlen(*prefix)); + + /* If the process does not exist: */ + if (kill(pid, 0) == -1 && errno == ESRCH) { + getTempFileName(temp_file, *prefix, pid); + unlink(temp_file); + } + } + prefix++; + } + + err = readdir_r(odir, &entry, &result); + } + closedir(odir); + } +}; +#endif // PBMS_API + +/* + * The following is a low level API for accessing blobs directly. + */ + + +/* + * Any threads using the direct blob access API must first register them selves with the + * blob streaming engine before using the blob access functions. This is done by calling + * PBMSInitBlobStreamingThread(). Call PBMSDeinitBlobStreamingThread() after the thread is + * done using the direct blob access API + */ + +/* +* PBMSInitBlobStreamingThread(): Returns a pointer to a blob streaming thread. +*/ +extern void *PBMSInitBlobStreamingThread(char *thread_name, PBMSResultPtr result); +extern void PBMSDeinitBlobStreamingThread(void *v_bs_thread); + +/* +* PBMSGetError():Gets the last error reported by a blob streaming thread. +*/ +extern void PBMSGetError(void *v_bs_thread, PBMSResultPtr result); + +/* +* PBMSCreateBlob():Creates a new blob in the database of the given size. cont_type can be NULL. +*/ +extern bool PBMSCreateBlob(PBMSBlobIDPtr blob_id, char *database_name, char *cont_type, u_int64_t size); + +/* +* PBMSWriteBlob():Write the data to the blob in one or more chunks. The total size of all the chuncks of +* data written to the blob must match the size specified when the blob was created. +*/ +extern bool PBMSWriteBlob(PBMSBlobIDPtr blob_id, char *database_name, char *data, size_t size, size_t offset); + +/* +* PBMSReadBlob():Read the blob data out of the blob in one or more chunks. +*/ +extern bool PBMSReadBlob(PBMSBlobIDPtr blob_id, char *database_name, char *buffer, size_t *size, size_t offset); + +/* +* PBMSIDToURL():Convert a blob id to a blob URL. The 'url' buffer must be atleast PBMS_BLOB_URL_SIZE bytes in size. +*/ +extern bool PBMSIDToURL(PBMSBlobIDPtr blob_id, char *database_name, char *url); + +/* +* PBMSIDToURL():Convert a blob URL to a blob ID. +*/ +extern bool PBMSURLToID(char *url, PBMSBlobIDPtr blob_id); + +#endif diff --git a/storage/pbxt/src/pthread_xt.cc b/storage/pbxt/src/pthread_xt.cc new file mode 100755 index 00000000000..0a9f4da2074 --- /dev/null +++ b/storage/pbxt/src/pthread_xt.cc @@ -0,0 +1,712 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-03-22 Paul McCullagh + * + * H&G2JCtL + * + * This file contains windows specific code + */ + +#include "xt_config.h" + +#ifdef XT_WIN +#include <my_pthread.h> +#else +#include <sys/resource.h> +#endif +#include <errno.h> +#include <limits.h> +#include <string.h> + +#include "pthread_xt.h" +#include "thread_xt.h" + +#ifdef XT_WIN + +void xt_p_init_threading(void) +{ +} + +int xt_p_set_normal_priority(pthread_t thr) +{ + if (!SetThreadPriority (thr, THREAD_PRIORITY_NORMAL)) + return GetLastError(); + return 0; +} + +int xt_p_set_low_priority(pthread_t thr) +{ + if (!SetThreadPriority (thr, THREAD_PRIORITY_LOWEST)) + return GetLastError(); + return 0; +} + +int xt_p_set_high_priority(pthread_t thr) +{ + if (!SetThreadPriority (thr, THREAD_PRIORITY_HIGHEST)) + return GetLastError(); + return 0; +} + +#define XT_RWLOCK_MAGIC 0x78AC390E + +#ifdef XT_THREAD_LOCK_INFO +int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr, const char *n) +#else +int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr) +#endif +{ + InitializeCriticalSection(&mutex->mt_cs); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_init(&mutex->mt_lock_info, mutex); + mutex->mt_name = n; +#endif + return 0; +} + +int xt_p_mutex_destroy(xt_mutex_type *mutex) +{ + DeleteCriticalSection(&mutex->mt_cs); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&mutex->mt_lock_info); +#endif + return 0; +} + +int xt_p_mutex_lock(xt_mutex_type *mx) +{ + EnterCriticalSection(&mx->mt_cs); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&mx->mt_lock_info); +#endif + return 0; +} + +int xt_p_mutex_unlock(xt_mutex_type *mx) +{ + LeaveCriticalSection(&mx->mt_cs); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&mx->mt_lock_info); +#endif + return 0; +} + +int xt_p_mutex_trylock(xt_mutex_type *mutex) +{ +#if(_WIN32_WINNT >= 0x0400) + /* NOTE: MySQL bug! was using?! + * pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT) + */ + if (TryEnterCriticalSection(&mutex->mt_cs)) { +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&mutex->mt_lock_info); +#endif + return 0; + } + return WAIT_TIMEOUT; +#else + EnterCriticalSection(&mutex->mt_cs); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&mutex->mt_lock_info); +#endif + return 0; +#endif +} + +#ifdef XT_THREAD_LOCK_INFO +int xt_p_rwlock_init(xt_rwlock_type *rwl, const pthread_condattr_t *attr, const char *n) +#else +int xt_p_rwlock_init(xt_rwlock_type *rwl, const pthread_condattr_t *attr) +#endif +{ + int result; + + if (rwl == NULL) + return ERROR_BAD_ARGUMENTS; + + rwl->rw_sh_count = 0; + rwl->rw_ex_count = 0; + rwl->rw_sh_complete_count = 0; + + result = xt_p_mutex_init_with_autoname(&rwl->rw_ex_lock, NULL); + if (result != 0) + goto failed; + + result = xt_p_mutex_init_with_autoname(&rwl->rw_sh_lock, NULL); + if (result != 0) + goto failed_2; + + result = pthread_cond_init(&rwl->rw_sh_cond, NULL); + if (result != 0) + goto failed_3; + + rwl->rw_magic = XT_RWLOCK_MAGIC; +#ifdef XT_THREAD_LOCK_INFO + rwl->rw_name = n; + xt_thread_lock_info_init(&rwl->rw_lock_info, rwl); +#endif + return 0; + + failed_3: + (void) xt_p_mutex_destroy(&rwl->rw_sh_lock); + + failed_2: + (void) xt_p_mutex_destroy(&rwl->rw_ex_lock); + + failed: + return result; +} + +int xt_p_rwlock_destroy(xt_rwlock_type *rwl) +{ + int result = 0, result1 = 0, result2 = 0; + + if (rwl == NULL) + return ERROR_BAD_ARGUMENTS; + + if (rwl->rw_magic != XT_RWLOCK_MAGIC) + return ERROR_BAD_ARGUMENTS; + + if ((result = xt_p_mutex_lock(&rwl->rw_ex_lock)) != 0) + return result; + + if ((result = xt_p_mutex_lock(&rwl->rw_sh_lock)) != 0) { + (void) xt_p_mutex_unlock(&rwl->rw_ex_lock); + return result; + } + + /* + * Check whether any threads own/wait for the lock (wait for ex.access); + * report "BUSY" if so. + */ + if (rwl->rw_ex_count > 0 || rwl->rw_sh_count > rwl->rw_sh_complete_count) { + result = xt_p_mutex_unlock(&rwl->rw_sh_lock); + result1 = xt_p_mutex_unlock(&rwl->rw_ex_lock); + result2 = ERROR_BUSY; + } + else { + rwl->rw_magic = 0; + + if ((result = xt_p_mutex_unlock(&rwl->rw_sh_lock)) != 0) + { + xt_p_mutex_unlock(&rwl->rw_ex_lock); + return result; + } + + if ((result = xt_p_mutex_unlock(&rwl->rw_ex_lock)) != 0) + return result; + + result = pthread_cond_destroy(&rwl->rw_sh_cond); + result1 = xt_p_mutex_destroy(&rwl->rw_sh_lock); + result2 = xt_p_mutex_destroy(&rwl->rw_ex_lock); + } + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&rwl->rw_lock_info); +#endif + + return (result != 0) ? result : ((result1 != 0) ? result1 : result2); +} + + +int xt_p_rwlock_rdlock(xt_rwlock_type *rwl) +{ + int result; + + if (rwl == NULL) + return ERROR_BAD_ARGUMENTS; + + if (rwl->rw_magic != XT_RWLOCK_MAGIC) + return ERROR_BAD_ARGUMENTS; + + if ((result = xt_p_mutex_lock(&rwl->rw_ex_lock)) != 0) + return result; + + if (++rwl->rw_sh_count == INT_MAX) { + if ((result = xt_p_mutex_lock(&rwl->rw_sh_lock)) != 0) + { + (void) xt_p_mutex_unlock(&rwl->rw_ex_lock); + return result; + } + + rwl->rw_sh_count -= rwl->rw_sh_complete_count; + rwl->rw_sh_complete_count = 0; + + if ((result = xt_p_mutex_unlock(&rwl->rw_sh_lock)) != 0) + { + (void) xt_p_mutex_unlock(&rwl->rw_ex_lock); + return result; + } + } + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&rwl->rw_lock_info); +#endif + + return (xt_p_mutex_unlock (&(rwl->rw_ex_lock))); +} + +int xt_p_rwlock_wrlock(xt_rwlock_type *rwl) +{ + int result; + + if (rwl == NULL) + return ERROR_BAD_ARGUMENTS; + + if (rwl->rw_magic != XT_RWLOCK_MAGIC) + return ERROR_BAD_ARGUMENTS; + + if ((result = xt_p_mutex_lock (&rwl->rw_ex_lock)) != 0) + return result; + + if ((result = xt_p_mutex_lock (&rwl->rw_sh_lock)) != 0) { + (void) xt_p_mutex_unlock (&rwl->rw_ex_lock); + return result; + } + + if (rwl->rw_ex_count == 0) { + if (rwl->rw_sh_complete_count > 0) { + rwl->rw_sh_count -= rwl->rw_sh_complete_count; + rwl->rw_sh_complete_count = 0; + } + + if (rwl->rw_sh_count > 0) { + rwl->rw_sh_complete_count = -rwl->rw_sh_count; + + do { + result = pthread_cond_wait (&rwl->rw_sh_cond, &rwl->rw_sh_lock.mt_cs); + } + while (result == 0 && rwl->rw_sh_complete_count < 0); + + if (result == 0) + rwl->rw_sh_count = 0; + } + } + + if (result == 0) + rwl->rw_ex_count++; + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&rwl->rw_lock_info); +#endif + + return result; +} + +int xt_p_rwlock_unlock(xt_rwlock_type *rwl) +{ + int result, result1; + + if (rwl == NULL) + return (ERROR_BAD_ARGUMENTS); + + if (rwl->rw_magic != XT_RWLOCK_MAGIC) + return ERROR_BAD_ARGUMENTS; + + if (rwl->rw_ex_count == 0) { + if ((result = xt_p_mutex_lock(&rwl->rw_sh_lock)) != 0) + return result; + + if (++rwl->rw_sh_complete_count == 0) + result = pthread_cond_signal(&rwl->rw_sh_cond); + + result1 = xt_p_mutex_unlock(&rwl->rw_sh_lock); + } + else { + rwl->rw_ex_count--; + + result = xt_p_mutex_unlock(&rwl->rw_sh_lock); + result1 = xt_p_mutex_unlock(&rwl->rw_ex_lock); + } + +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&rwl->rw_lock_info); +#endif + + return ((result != 0) ? result : result1); +} + +int xt_p_cond_wait(xt_cond_type *cond, xt_mutex_type *mutex) +{ + return xt_p_cond_timedwait(cond, mutex, NULL); +} + +int xt_p_cond_timedwait(xt_cond_type *cond, xt_mutex_type *mt, struct timespec *abstime) +{ + pthread_mutex_t *mutex = &mt->mt_cs; + int result; + long timeout; + union ft64 now; + + if (abstime != NULL) { + GetSystemTimeAsFileTime(&now.ft); + + timeout = (long)((abstime->tv.i64 - now.i64) / 10000); + if (timeout < 0) + timeout = 0L; + if (timeout > abstime->max_timeout_msec) + timeout = abstime->max_timeout_msec; + } + else + timeout= INFINITE; + + WaitForSingleObject(cond->broadcast_block_event, INFINITE); + + EnterCriticalSection(&cond->lock_waiting); + cond->waiting++; + LeaveCriticalSection(&cond->lock_waiting); + + LeaveCriticalSection(mutex); + + result= WaitForMultipleObjects(2, cond->events, FALSE, timeout); + + EnterCriticalSection(&cond->lock_waiting); + cond->waiting--; + + if (cond->waiting == 0) { + /* The last waiter must reset the broadcast + * state (whther there was a broadcast or not)! + */ + ResetEvent(cond->events[xt_cond_type::BROADCAST]); + SetEvent(cond->broadcast_block_event); + } + LeaveCriticalSection(&cond->lock_waiting); + + EnterCriticalSection(mutex); + + return result == WAIT_TIMEOUT ? ETIMEDOUT : 0; +} + +int xt_p_join(pthread_t thread, void **value) +{ + switch (WaitForSingleObject(thread, INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_TIMEOUT: + /* Don't do this! According to the Win docs: + * _endthread automatically closes the thread handle + * (whereas _endthreadex does not). Therefore, when using + * _beginthread and _endthread, do not explicitly close the + * thread handle by calling the Win32 CloseHandle API. + CloseHandle(thread); + */ + break; + case WAIT_FAILED: + return GetLastError(); + } + return 0; +} + +#else // XT_WIN + +#ifdef __darwin__ +#define POLICY SCHED_RR +#else +#define POLICY pth_policy +#endif + +static int pth_policy; +static int pth_normal_priority; +static int pth_min_priority; +static int pth_max_priority; + +/* Return zero if the priority was set OK, + * else errno. + */ +static int pth_set_priority(pthread_t thread, int priority) +{ + struct sched_param sp; + + memset(&sp, 0, sizeof(struct sched_param)); + sp.sched_priority = priority; + return pthread_setschedparam(thread, POLICY, &sp); +} + +static void pth_get_priority_limits(void) +{ + XTThreadPtr self = NULL; + struct sched_param sp; + int err; + int start; + + /* Save original priority: */ + err = pthread_getschedparam(pthread_self(), &pth_policy, &sp); + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return; + } + pth_normal_priority = sp.sched_priority; + + start = sp.sched_priority; + +#ifdef XT_FREEBSD + pth_min_priority = sched_get_priority_min(sched_getscheduler(0)); + pth_max_priority = sched_get_priority_max(sched_getscheduler(0)); +#else + /* Search for the minimum priority: */ + pth_min_priority = start; + for (;;) { + /* 2007-03-01: Corrected, pth_set_priority returns the error code + * (thanks to Hakan for pointing out this bug!) + */ + if (pth_set_priority(pthread_self(), pth_min_priority-1) != 0) + break; + pth_min_priority--; + } + + /* Search for the maximum priority: */ + pth_max_priority = start; + for (;;) { + if (pth_set_priority(pthread_self(), pth_max_priority+1) != 0) + break; + pth_max_priority++; + } + + /* Restore original priority: */ + pthread_setschedparam(pthread_self(), pth_policy, &sp); +#endif +} + +xtPublic void xt_p_init_threading(void) +{ + pth_get_priority_limits(); +} + +xtPublic int xt_p_set_low_priority(pthread_t thr) +{ + if (pth_min_priority == pth_max_priority) { + /* Under Linux the priority of normal (non-runtime) + * threads are set using the standard methods + * for setting process priority. + */ + + /* We could set who == 0 because it should have the same affect + * as using the PID. + */ + + /* -20 = highest, 20 = lowest */ + if (setpriority(PRIO_PROCESS, getpid(), 20) == -1) + return errno; + return 0; + } + return pth_set_priority(thr, pth_min_priority); +} + +xtPublic int xt_p_set_normal_priority(pthread_t thr) +{ + if (pth_min_priority == pth_max_priority) { + if (setpriority(PRIO_PROCESS, getpid(), 0) == -1) + return errno; + return 0; + } + return pth_set_priority(thr, pth_normal_priority); +} + +xtPublic int xt_p_set_high_priority(pthread_t thr) +{ + if (pth_min_priority == pth_max_priority) { + if (setpriority(PRIO_PROCESS, getpid(), -20) == -1) + return errno; + return 0; + } + return pth_set_priority(thr, pth_max_priority); +} + +#ifdef DEBUG_LOCKING + +xtPublic int xt_p_mutex_lock(xt_mutex_type *mutex, u_int line, const char *file) +{ + XTThreadPtr self = xt_get_self(); + int r; + + ASSERT_NS(mutex->mu_init == 12345); + r = pthread_mutex_lock(&mutex->mu_plock); + if (r == 0) { + if (mutex->mu_trace) + printf("==LOCK mutex %d %s:%d\n", (int) mutex->mu_trace, file, (int) line); + ASSERT_NS(!mutex->mu_locker); + mutex->mu_locker = self; + mutex->mu_line = line; + mutex->mu_file = file; + } +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&mutex->mu_lock_info); +#endif + return r; +} + +xtPublic int xt_p_mutex_unlock(xt_mutex_type *mutex) +{ + XTThreadPtr self = xt_get_self(); + + ASSERT_NS(mutex->mu_init == 12345); + ASSERT_NS(mutex->mu_locker == self); + mutex->mu_locker = NULL; + if (mutex->mu_trace) + printf("UNLOCK mutex %d\n", (int) mutex->mu_trace); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&mutex->mu_lock_info); +#endif + return pthread_mutex_unlock(&mutex->mu_plock); +} + +xtPublic int xt_p_mutex_destroy(xt_mutex_type *mutex) +{ + ASSERT_NS(mutex->mu_init == 12345); + mutex->mu_init = 89898; +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&mutex->mu_lock_info); +#endif + return pthread_mutex_destroy(&mutex->mu_plock); +} + +xtPublic int xt_p_mutex_trylock(xt_mutex_type *mutex) +{ + XTThreadPtr self = xt_get_self(); + int r; + + ASSERT_NS(mutex->mu_init == 12345); + r = pthread_mutex_trylock(&mutex->mu_plock); + if (r == 0) { + ASSERT_NS(!mutex->mu_locker); + mutex->mu_locker = self; +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&mutex->mu_lock_info); +#endif + } + return r; +} + +#ifdef XT_THREAD_LOCK_INFO +xtPublic int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr, const char *n) +#else +xtPublic int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr) +#endif +{ + mutex->mu_init = 12345; + mutex->mu_trace = FALSE; + mutex->mu_locker = NULL; +#ifdef XT_THREAD_LOCK_INFO + mutex->mu_name = n; + xt_thread_lock_info_init(&mutex->mu_lock_info, mutex); +#endif + return pthread_mutex_init(&mutex->mu_plock, attr); +} + +xtPublic int xt_p_cond_wait(xt_cond_type *cond, xt_mutex_type *mutex) +{ + XTThreadPtr self = xt_get_self(); + int r; + + ASSERT_NS(mutex->mu_init == 12345); + ASSERT_NS(mutex->mu_locker == self); + mutex->mu_locker = NULL; + r = pthread_cond_wait(cond, &mutex->mu_plock); + ASSERT_NS(!mutex->mu_locker); + mutex->mu_locker = self; + return r; +} + +xtPublic int xt_p_cond_timedwait(xt_cond_type *cond, xt_mutex_type *mutex, const struct timespec *abstime) +{ + XTThreadPtr self = xt_get_self(); + int r; + + ASSERT_NS(mutex->mu_init == 12345); + ASSERT_NS(mutex->mu_locker == self); + mutex->mu_locker = NULL; + r = pthread_cond_timedwait(cond, &mutex->mu_plock, abstime); + ASSERT_NS(!mutex->mu_locker); + mutex->mu_locker = self; + return r; +} + +xtPublic int xt_p_rwlock_rdlock(xt_rwlock_type *rwlock) +{ + int r; + + ASSERT_NS(rwlock->rw_init == 67890); + r = pthread_rwlock_rdlock(&rwlock->rw_plock); +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&rwlock->rw_lock_info); +#endif + return r; +} + +xtPublic int xt_p_rwlock_wrlock(xt_rwlock_type *rwlock) +{ + XTThreadPtr self = xt_get_self(); + int r; + + ASSERT_NS(rwlock->rw_init == 67890); + r = pthread_rwlock_wrlock(&rwlock->rw_plock); + if (r == 0) { + ASSERT_NS(!rwlock->rw_locker); + rwlock->rw_locker = self; + } +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_add_owner(&rwlock->rw_lock_info); +#endif + return r; +} + +xtPublic int xt_p_rwlock_unlock(xt_rwlock_type *rwlock) +{ + XTThreadPtr self = xt_get_self(); + + ASSERT_NS(rwlock->rw_init == 67890); + if (rwlock->rw_locker) { + ASSERT_NS(rwlock->rw_locker == self); + rwlock->rw_locker = NULL; + } +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_release_owner(&rwlock->rw_lock_info); +#endif + return pthread_rwlock_unlock(&rwlock->rw_plock); +} + +xtPublic int xt_p_rwlock_destroy(xt_rwlock_type *rwlock) +{ + ASSERT_NS(rwlock->rw_init == 67890); + rwlock->rw_init = 0; +#ifdef XT_THREAD_LOCK_INFO + xt_thread_lock_info_free(&rwlock->rw_lock_info); +#endif + return pthread_rwlock_destroy(&rwlock->rw_plock); +} + +#ifdef XT_THREAD_LOCK_INFO +xtPublic int xt_p_rwlock_init(xt_rwlock_type *rwlock, const pthread_rwlockattr_t *attr, const char *n) +#else +xtPublic int xt_p_rwlock_init(xt_rwlock_type *rwlock, const pthread_rwlockattr_t *attr) +#endif +{ + rwlock->rw_init = 67890; + rwlock->rw_readers = 0; + rwlock->rw_locker = NULL; +#ifdef XT_THREAD_LOCK_INFO + rwlock->rw_name = n; + xt_thread_lock_info_init(&rwlock->rw_lock_info, rwlock); +#endif + return pthread_rwlock_init(&rwlock->rw_plock, attr); +} + +#endif // DEBUG_LOCKING + +#endif // XT_WIN + diff --git a/storage/pbxt/src/pthread_xt.h b/storage/pbxt/src/pthread_xt.h new file mode 100755 index 00000000000..d8ef1a85d41 --- /dev/null +++ b/storage/pbxt/src/pthread_xt.h @@ -0,0 +1,292 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-03-22 Paul McCullagh + * + * H&G2JCtL + * + * This file contains windows specific code. + */ + +#ifndef __win_xt_h__ +#define __win_xt_h__ + +#ifdef XT_WIN +#include <windef.h> +#include <my_pthread.h> +#else +#include <pthread.h> +#endif + +#include "locklist_xt.h" + +#ifdef DEBUG +//#define DEBUG_LOCKING +#endif + +#define xt_cond_struct _opaque_pthread_cond_t +#define xt_cond_type pthread_cond_t + +#define xt_cond_wait pthread_cond_wait +#define xt_cond_wakeall pthread_cond_broadcast + +#ifdef __cplusplus +extern "C" { +#endif +void xt_p_init_threading(void); +int xt_p_set_normal_priority(pthread_t thr); +int xt_p_set_low_priority(pthread_t thr); +int xt_p_set_high_priority(pthread_t thr); +#ifdef __cplusplus +} +#endif + +#ifdef XT_WIN + +#ifdef __cplusplus +extern "C" { +#endif + +typedef LPVOID pthread_key_t; + +typedef struct xt_mutex_struct { + CRITICAL_SECTION mt_cs; +#ifdef XT_THREAD_LOCK_INFO + const char *mt_name; + XTThreadLockInfoRec mt_lock_info; +#endif +} xt_mutex_type; + +typedef struct xt_rwlock_struct { + xt_mutex_type rw_ex_lock; + xt_mutex_type rw_sh_lock; + pthread_cond_t rw_sh_cond; + int rw_sh_count; + int rw_ex_count; + int rw_sh_complete_count; + int rw_magic; +#ifdef XT_THREAD_LOCK_INFO + const char *rw_name; + XTThreadLockInfoRec rw_lock_info; +#endif +} xt_rwlock_type; + +#ifdef XT_THREAD_LOCK_INFO +int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr, const char *name); +#else +int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr); +#endif +int xt_p_mutex_destroy(xt_mutex_type *mutex); +int xt_p_mutex_lock(xt_mutex_type *mx); +int xt_p_mutex_unlock(xt_mutex_type *mx); +int xt_p_mutex_trylock(xt_mutex_type *mutex); + +#ifdef XT_THREAD_LOCK_INFO +int xt_p_rwlock_init(xt_rwlock_type *rwlock, const pthread_condattr_t *attr, const char *name); +#else +int xt_p_rwlock_init(xt_rwlock_type *rwlock, const pthread_condattr_t *attr); +#endif +int xt_p_rwlock_destroy(xt_rwlock_type *rwlock); +int xt_p_rwlock_rdlock(xt_rwlock_type *mx); +int xt_p_rwlock_wrlock(xt_rwlock_type *mx); +int xt_p_rwlock_unlock(xt_rwlock_type *mx); + +int xt_p_cond_wait(xt_cond_type *cond, xt_mutex_type *mutex); +int xt_p_cond_timedwait(xt_cond_type *cond, xt_mutex_type *mutex, struct timespec *abstime); + +int xt_p_join(pthread_t thread, void **value); + +#ifdef __cplusplus +} +#endif + +#ifdef XT_THREAD_LOCK_INFO +#define xt_p_rwlock_init_with_name(a,b,c) xt_p_rwlock_init(a,b,c) +#define xt_p_rwlock_init_with_autoname(a,b) xt_p_rwlock_init_with_name(a,b,LOCKLIST_ARG_SUFFIX(a)) +#else +#define xt_p_rwlock_init_with_name(a,b,c) xt_p_rwlock_init(a,b,c) +#define xt_p_rwlock_init_with_autoname(a,b) xt_p_rwlock_init(a,b) +#endif + +#define xt_slock_rwlock_ns xt_p_rwlock_rdlock +#define xt_xlock_rwlock_ns xt_p_rwlock_wrlock +#define xt_unlock_rwlock_ns xt_p_rwlock_unlock + +#ifdef XT_THREAD_LOCK_INFO +#define xt_p_mutex_init_with_name(a,b,c) xt_p_mutex_init(a,b,c) +#define xt_p_mutex_init_with_autoname(a,b) xt_p_mutex_init_with_name(a,b,LOCKLIST_ARG_SUFFIX(a)) +#else +#define xt_p_mutex_init_with_name(a,b,c) xt_p_mutex_init(a,b) +#define xt_p_mutex_init_with_autoname(a,b) xt_p_mutex_init(a,b) +#endif +#define xt_lock_mutex_ns xt_p_mutex_lock +#define xt_unlock_mutex_ns xt_p_mutex_unlock +#define xt_mutex_trylock xt_p_mutex_trylock + +#else // XT_WIN + +/* Finger weg! */ +#ifdef pthread_mutex_t +#undef pthread_mutex_t +#endif +#ifdef pthread_rwlock_t +#undef pthread_rwlock_t +#endif +#ifdef pthread_mutex_init +#undef pthread_mutex_init +#endif +#ifdef pthread_mutex_destroy +#undef pthread_mutex_destroy +#endif +#ifdef pthread_mutex_lock +#undef pthread_mutex_lock +#endif +#ifdef pthread_mutex_unlock +#undef pthread_mutex_unlock +#endif +#ifdef pthread_cond_wait +#undef pthread_cond_wait +#endif +#ifdef pthread_cond_broadcast +#undef pthread_cond_broadcast +#endif +#ifdef pthread_mutex_trylock +#undef pthread_mutex_trylock +#endif + +/* + * ----------------------------------------------------------------------- + * Reedefinition of pthread locking, for debugging + */ + +struct XTThread; + + +#ifdef XT_THREAD_LOCK_INFO + +#define xt_p_mutex_init_with_name(a,b,c) xt_p_mutex_init(a,b,c) +#define xt_p_mutex_init_with_autoname(a,b) xt_p_mutex_init_with_name(a,b,LOCKLIST_ARG_SUFFIX(a)) + +#define xt_p_rwlock_init_with_name(a,b,c) xt_p_rwlock_init(a,b,c) +#define xt_p_rwlock_init_with_autoname(a,b) xt_p_rwlock_init_with_name(a,b,LOCKLIST_ARG_SUFFIX(a)) + +#else + +#define xt_p_mutex_init_with_name(a,b,c) xt_p_mutex_init(a,b) +#define xt_p_mutex_init_with_autoname(a,b) xt_p_mutex_init(a,b) + +#define xt_p_rwlock_init_with_name(a,b,c) xt_p_rwlock_init(a,b) +#define xt_p_rwlock_init_with_autoname(a,b) xt_p_rwlock_init_with_name(a,b) + +#endif + +#ifdef DEBUG_LOCKING + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct xt_mutex_struct { + unsigned short mu_init; + unsigned short mu_trace; + unsigned int mu_line; + const char *mu_file; + struct XTThread *mu_locker; + pthread_mutex_t mu_plock; +#ifdef XT_THREAD_LOCK_INFO + const char *mu_name; + XTThreadLockInfoRec mu_lock_info; +#endif +} xt_mutex_type; + +typedef struct xt_rwlock_struct { + u_int rw_init; + volatile u_int rw_readers; + struct XTThread *rw_locker; + pthread_rwlock_t rw_plock; +#ifdef XT_THREAD_LOCK_INFO + const char *rw_name; + XTThreadLockInfoRec rw_lock_info; +#endif +} xt_rwlock_type; + +int xt_p_rwlock_rdlock(xt_rwlock_type *mx); +int xt_p_rwlock_wrlock(xt_rwlock_type *mx); +int xt_p_rwlock_unlock(xt_rwlock_type *mx); + +int xt_p_mutex_lock(xt_mutex_type *mx, u_int line, const char *file); +int xt_p_mutex_unlock(xt_mutex_type *mx); +int xt_p_mutex_trylock(xt_mutex_type *mutex); +int xt_p_mutex_destroy(xt_mutex_type *mutex); +#ifdef XT_THREAD_LOCK_INFO +int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr, const char *name); +#else +int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr); +#endif +int xt_p_rwlock_destroy(xt_rwlock_type * rwlock); +#ifdef XT_THREAD_LOCK_INFO +int xt_p_rwlock_init(xt_rwlock_type *rwlock, const pthread_rwlockattr_t *attr, const char *name); +#else +int xt_p_rwlock_init(xt_rwlock_type *rwlock, const pthread_rwlockattr_t *attr); +#endif +int xt_p_cond_wait(xt_cond_type *cond, xt_mutex_type *mutex); +int xt_p_cond_timedwait(xt_cond_type *cond, xt_mutex_type *mutex, const struct timespec *abstime); + +#ifdef __cplusplus +} +#endif + +#define xt_slock_rwlock_ns xt_p_rwlock_rdlock +#define xt_xlock_rwlock_ns xt_p_rwlock_wrlock +#define xt_unlock_rwlock_ns xt_p_rwlock_unlock + +#define xt_lock_mutex_ns(x) xt_p_mutex_lock(x, __LINE__, __FILE__) +#define xt_unlock_mutex_ns xt_p_mutex_unlock +#define xt_mutex_trylock xt_p_mutex_trylock + +#else // DEBUG_LOCKING + +#define xt_rwlock_struct _opaque_pthread_rwlock_t +#define xt_mutex_struct _opaque_pthread_mutex_t + +#define xt_rwlock_type pthread_rwlock_t +#define xt_mutex_type pthread_mutex_t + +#define xt_slock_rwlock_ns pthread_rwlock_rdlock +#define xt_xlock_rwlock_ns pthread_rwlock_wrlock +#define xt_unlock_rwlock_ns pthread_rwlock_unlock + +#define xt_lock_mutex_ns pthread_mutex_lock +#define xt_unlock_mutex_ns pthread_mutex_unlock +#define xt_mutex_trylock pthread_mutex_trylock + +#define xt_p_mutex_trylock pthread_mutex_trylock +#define xt_p_mutex_destroy pthread_mutex_destroy +#define xt_p_mutex_init pthread_mutex_init +#define xt_p_rwlock_destroy pthread_rwlock_destroy +#define xt_p_rwlock_init pthread_rwlock_init +#define xt_p_cond_wait pthread_cond_wait +#define xt_p_cond_timedwait pthread_cond_timedwait + +#endif // DEBUG_LOCKING + +#define xt_p_join pthread_join + +#endif // XT_WIN + +#endif diff --git a/storage/pbxt/src/restart_xt.cc b/storage/pbxt/src/restart_xt.cc new file mode 100644 index 00000000000..50390bfb727 --- /dev/null +++ b/storage/pbxt/src/restart_xt.cc @@ -0,0 +1,3203 @@ +/* Copyright (c) 2007 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2007-11-12 Paul McCullagh + * + * H&G2JCtL + * + * Restart and write data to the database. + */ + +#include "xt_config.h" + +#include <signal.h> +#include <time.h> + +#ifndef DRIZZLED +#include "mysql_priv.h" +#endif + +#include "ha_pbxt.h" + +#include "xactlog_xt.h" +#include "database_xt.h" +#include "util_xt.h" +#include "strutil_xt.h" +#include "filesys_xt.h" +#include "restart_xt.h" +#include "myxt_xt.h" +#include "trace_xt.h" + +#ifdef DEBUG +//#define DEBUG_PRINT +//#define DEBUG_KEEP_LOGS +//#define PRINT_LOG_ON_RECOVERY +//#define TRACE_RECORD_DATA +//#define SKIP_STARTUP_CHECKPOINT +//#define NEVER_CHECKPOINT +//#define TRACE_CHECKPOINT +#endif + +#define PRINTF printf +//#define PRINTF xt_ftracef +//#define PRINTF xt_trace + +void xt_print_bytes(xtWord1 *buf, u_int len) +{ + for (u_int i=0; i<len; i++) { + PRINTF("%02x ", (u_int) *buf); + buf++; + } +} + +void xt_print_log_record(xtLogID log, xtLogOffset offset, XTXactLogBufferDPtr record) +{ + const char *type = NULL; + const char *rec_type = NULL; + xtOpSeqNo op_no = 0; + xtTableID tab_id = 0; + xtRowID row_id = 0; + xtRecordID rec_id = 0; + xtBool xn_set = FALSE; + xtXactID xn_id = 0; + char buffer[200]; + XTTabRecExtDPtr rec_buf; + XTTabRecExtDPtr ext_rec; + XTTabRecFixDPtr fix_rec; + u_int rec_len; + xtLogID log_id = 0; + xtLogOffset log_offset = 0; + + rec_buf = NULL; + ext_rec = NULL; + fix_rec = NULL; + rec_len = 0; + switch (record->xl.xl_status_1) { + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_DELETE_BG: + op_no = XT_GET_DISK_4(record->xu.xu_op_seq_4); + tab_id = XT_GET_DISK_4(record->xu.xu_tab_id_4); + rec_id = XT_GET_DISK_4(record->xu.xu_rec_id_4); + xn_id = XT_GET_DISK_4(record->xu.xu_xact_id_4); + row_id = XT_GET_DISK_4(record->xu.xu_row_id_4); + rec_len = XT_GET_DISK_2(record->xu.xu_size_2); + xn_set = TRUE; + type="rec"; + rec_buf = (XTTabRecExtDPtr) &record->xu.xu_rec_type_1; + ext_rec = (XTTabRecExtDPtr) &record->xu.xu_rec_type_1; + if (XT_REC_IS_EXT_DLOG(ext_rec->tr_rec_type_1)) { + log_id = XT_GET_DISK_2(ext_rec->re_log_id_2); + log_offset = XT_GET_DISK_6(ext_rec->re_log_offs_6); + } + else { + ext_rec = NULL; + fix_rec = (XTTabRecFixDPtr) &record->xu.xu_rec_type_1; + } + break; + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_DELETE_FL: + case XT_LOG_ENT_UPDATE_FL_BG: + case XT_LOG_ENT_INSERT_FL_BG: + case XT_LOG_ENT_DELETE_FL_BG: + op_no = XT_GET_DISK_4(record->xf.xf_op_seq_4); + tab_id = XT_GET_DISK_4(record->xf.xf_tab_id_4); + rec_id = XT_GET_DISK_4(record->xf.xf_rec_id_4); + xn_id = XT_GET_DISK_4(record->xf.xf_xact_id_4); + row_id = XT_GET_DISK_4(record->xf.xf_row_id_4); + rec_len = XT_GET_DISK_2(record->xf.xf_size_2); + xn_set = TRUE; + type="rec"; + rec_buf = (XTTabRecExtDPtr) &record->xf.xf_rec_type_1; + ext_rec = (XTTabRecExtDPtr) &record->xf.xf_rec_type_1; + if (XT_REC_IS_EXT_DLOG(ext_rec->tr_rec_type_1)) { + log_id = XT_GET_DISK_2(ext_rec->re_log_id_2); + log_offset = XT_GET_DISK_6(ext_rec->re_log_offs_6); + } + else { + ext_rec = NULL; + fix_rec = (XTTabRecFixDPtr) &record->xf.xf_rec_type_1; + } + break; + case XT_LOG_ENT_REC_FREED: + case XT_LOG_ENT_REC_REMOVED: + case XT_LOG_ENT_REC_REMOVED_EXT: + op_no = XT_GET_DISK_4(record->fr.fr_op_seq_4); + tab_id = XT_GET_DISK_4(record->fr.fr_tab_id_4); + rec_id = XT_GET_DISK_4(record->fr.fr_rec_id_4); + xn_id = XT_GET_DISK_4(record->fr.fr_xact_id_4); + xn_set = TRUE; + type="rec"; + break; + case XT_LOG_ENT_REC_REMOVED_BI: + op_no = XT_GET_DISK_4(record->rb.rb_op_seq_4); + tab_id = XT_GET_DISK_4(record->rb.rb_tab_id_4); + rec_id = XT_GET_DISK_4(record->rb.rb_rec_id_4); + xn_id = XT_GET_DISK_4(record->rb.rb_xact_id_4); + row_id = XT_GET_DISK_4(record->rb.rb_row_id_4); + rec_len = XT_GET_DISK_2(record->rb.rb_size_2); + xn_set = TRUE; + type="rec"; + rec_buf = (XTTabRecExtDPtr) &record->rb.rb_rec_type_1; + ext_rec = (XTTabRecExtDPtr) &record->rb.rb_rec_type_1; + if (XT_REC_IS_EXT_DLOG(record->rb.rb_rec_type_1)) { + log_id = XT_GET_DISK_2(ext_rec->re_log_id_2); + log_offset = XT_GET_DISK_6(ext_rec->re_log_offs_6); + } + else { + ext_rec = NULL; + fix_rec = (XTTabRecFixDPtr) &record->rb.rb_rec_type_1; + } + break; + case XT_LOG_ENT_REC_MOVED: + op_no = XT_GET_DISK_4(record->xw.xw_op_seq_4); + tab_id = XT_GET_DISK_4(record->xw.xw_tab_id_4); + rec_id = XT_GET_DISK_4(record->xw.xw_rec_id_4); + log_id = XT_GET_DISK_2(&record->xw.xw_rec_type_1); // This is actually correct + log_offset = XT_GET_DISK_6(record->xw.xw_next_rec_id_4); // This is actually correct! + type="rec"; + break; + case XT_LOG_ENT_REC_CLEANED: + case XT_LOG_ENT_REC_CLEANED_1: + case XT_LOG_ENT_REC_UNLINKED: + op_no = XT_GET_DISK_4(record->xw.xw_op_seq_4); + tab_id = XT_GET_DISK_4(record->xw.xw_tab_id_4); + rec_id = XT_GET_DISK_4(record->xw.xw_rec_id_4); + type="rec"; + break; + case XT_LOG_ENT_ROW_NEW: + case XT_LOG_ENT_ROW_NEW_FL: + case XT_LOG_ENT_ROW_ADD_REC: + case XT_LOG_ENT_ROW_SET: + case XT_LOG_ENT_ROW_FREED: + op_no = XT_GET_DISK_4(record->xa.xa_op_seq_4); + tab_id = XT_GET_DISK_4(record->xa.xa_tab_id_4); + rec_id = XT_GET_DISK_4(record->xa.xa_row_id_4); + type="row"; + break; + case XT_LOG_ENT_NO_OP: + op_no = XT_GET_DISK_4(record->no.no_op_seq_4); + tab_id = XT_GET_DISK_4(record->no.no_tab_id_4); + type="-"; + break; + case XT_LOG_ENT_END_OF_LOG: + break; + } + + switch (record->xl.xl_status_1) { + case XT_LOG_ENT_HEADER: + rec_type = "HEADER"; + break; + case XT_LOG_ENT_NEW_LOG: + rec_type = "NEW LOG"; + break; + case XT_LOG_ENT_DEL_LOG: + sprintf(buffer, "DEL LOG log=%d ", (int) XT_GET_DISK_4(record->xl.xl_log_id_4)); + rec_type = buffer; + break; + case XT_LOG_ENT_NEW_TAB: + rec_type = "NEW TABLE"; + break; + case XT_LOG_ENT_COMMIT: + rec_type = "COMMIT"; + xn_id = XT_GET_DISK_4(record->xe.xe_xact_id_4); + xn_set = TRUE; + break; + case XT_LOG_ENT_ABORT: + rec_type = "ABORT"; + xn_id = XT_GET_DISK_4(record->xe.xe_xact_id_4); + xn_set = TRUE; + break; + case XT_LOG_ENT_CLEANUP: + rec_type = "CLEANUP"; + xn_id = XT_GET_DISK_4(record->xc.xc_xact_id_4); + xn_set = TRUE; + break; + case XT_LOG_ENT_REC_MODIFIED: + rec_type = "MODIFIED"; + break; + case XT_LOG_ENT_UPDATE: + rec_type = "UPDATE"; + break; + case XT_LOG_ENT_UPDATE_FL: + rec_type = "UPDATE-FL"; + break; + case XT_LOG_ENT_INSERT: + rec_type = "INSERT"; + break; + case XT_LOG_ENT_INSERT_FL: + rec_type = "INSERT-FL"; + break; + case XT_LOG_ENT_DELETE: + rec_type = "DELETE"; + break; + case XT_LOG_ENT_DELETE_FL: + rec_type = "DELETE-FL-BG"; + break; + case XT_LOG_ENT_UPDATE_BG: + rec_type = "UPDATE-BG"; + break; + case XT_LOG_ENT_UPDATE_FL_BG: + rec_type = "UPDATE-FL-BG"; + break; + case XT_LOG_ENT_INSERT_BG: + rec_type = "INSERT-BG"; + break; + case XT_LOG_ENT_INSERT_FL_BG: + rec_type = "INSERT-FL-BG"; + break; + case XT_LOG_ENT_DELETE_BG: + rec_type = "DELETE-BG"; + break; + case XT_LOG_ENT_DELETE_FL_BG: + rec_type = "DELETE-FL-BG"; + break; + case XT_LOG_ENT_REC_FREED: + rec_type = "FREE REC"; + break; + case XT_LOG_ENT_REC_REMOVED: + rec_type = "REMOVED REC"; + break; + case XT_LOG_ENT_REC_REMOVED_EXT: + rec_type = "REMOVED-X REC"; + break; + case XT_LOG_ENT_REC_REMOVED_BI: + rec_type = "REMOVED-BI REC"; + break; + case XT_LOG_ENT_REC_MOVED: + rec_type = "MOVED REC"; + break; + case XT_LOG_ENT_REC_CLEANED: + rec_type = "CLEAN REC"; + break; + case XT_LOG_ENT_REC_CLEANED_1: + rec_type = "CLEAN REC-1"; + break; + case XT_LOG_ENT_REC_UNLINKED: + rec_type = "UNLINK REC"; + break; + case XT_LOG_ENT_ROW_NEW: + rec_type = "NEW ROW"; + break; + case XT_LOG_ENT_ROW_NEW_FL: + rec_type = "NEW ROW-FL"; + break; + case XT_LOG_ENT_ROW_ADD_REC: + rec_type = "REC ADD ROW"; + break; + case XT_LOG_ENT_ROW_SET: + rec_type = "SET ROW"; + break; + case XT_LOG_ENT_ROW_FREED: + rec_type = "FREE ROW"; + break; + case XT_LOG_ENT_OP_SYNC: + rec_type = "OP SYNC"; + break; + case XT_LOG_ENT_NO_OP: + rec_type = "NO OP"; + break; + case XT_LOG_ENT_END_OF_LOG: + rec_type = "END OF LOG"; + break; + } + + if (log) + PRINTF("log=%d offset=%d ", (int) log, (int) offset); + PRINTF("%s ", rec_type); + if (type) + PRINTF("op=%lu tab=%lu %s=%lu ", (u_long) op_no, (u_long) tab_id, type, (u_long) rec_id); + if (row_id) + PRINTF("row=%lu ", (u_long) row_id); + if (log_id) + PRINTF("log=%lu offset=%lu ", (u_long) log_id, (u_long) log_offset); + if (xn_set) + PRINTF("xact=%lu ", (u_long) xn_id); + +#ifdef TRACE_RECORD_DATA + if (rec_buf) { + switch (rec_buf->tr_rec_type_1 & XT_TAB_STATUS_MASK) { + case XT_TAB_STATUS_FREED: + PRINTF("FREE"); + break; + case XT_TAB_STATUS_DELETE: + PRINTF("DELE"); + break; + case XT_TAB_STATUS_FIXED: + PRINTF("FIX-"); + break; + case XT_TAB_STATUS_VARIABLE: + PRINTF("VAR-"); + break; + case XT_TAB_STATUS_EXT_DLOG: + PRINTF("EXT-"); + break; + } + if (rec_buf->tr_rec_type_1 & XT_TAB_STATUS_CLEANED_BIT) + PRINTF("C"); + else + PRINTF(" "); + } + if (ext_rec) { + rec_len -= offsetof(XTTabRecExtDRec, re_data); + xt_print_bytes((xtWord1 *) ext_rec, offsetof(XTTabRecExtDRec, re_data)); + PRINTF("| "); + if (rec_len > 20) + rec_len = 20; + xt_print_bytes(ext_rec->re_data, rec_len); + } + if (fix_rec) { + rec_len -= offsetof(XTTabRecFixDRec, rf_data); + xt_print_bytes((xtWord1 *) fix_rec, offsetof(XTTabRecFixDRec, rf_data)); + PRINTF("| "); + if (rec_len > 20) + rec_len = 20; + xt_print_bytes(fix_rec->rf_data, rec_len); + } +#endif + + PRINTF("\n"); +} + +#ifdef DEBUG_PRINT +void check_rows(void) +{ + static XTOpenFilePtr of = NULL; + + if (!of) + of = xt_open_file_ns("./test/test_tab-1.xtr", XT_FS_DEFAULT); + if (of) { + size_t size = (size_t) xt_seek_eof_file(NULL, of); + xtWord8 *buffer = (xtWord8 *) xt_malloc_ns(size); + xt_pread_file(of, 0, size, size, buffer, NULL); + for (size_t i=0; i<size/8; i++) { + if (!buffer[i]) + printf("%d is NULL\n", (int) i); + } + } +} + +#endif + +/* ---------------------------------------------------------------------- + * APPLYING CHANGES IN SEQUENCE + */ + +typedef struct XTOperation { + xtOpSeqNo or_op_seq; + xtWord4 or_op_len; + xtLogID or_log_id; + xtLogOffset or_log_offset; +} XTOperationRec, *XTOperationPtr; + +static int xres_cmp_op_seq(struct XTThread *self __attribute__((unused)), register const void *thunk __attribute__((unused)), register const void *a, register const void *b) +{ + xtOpSeqNo lf_op_seq = *((xtOpSeqNo *) a); + XTOperationPtr lf_ptr = (XTOperationPtr) b; + + if (lf_op_seq == lf_ptr->or_op_seq) + return 0; + if (XTTableSeq::xt_op_is_before(lf_op_seq, lf_ptr->or_op_seq)) + return -1; + return 1; +} + +xtPublic void xt_xres_init_tab(XTThreadPtr self, XTTableHPtr tab) +{ + tab->tab_op_list = xt_new_sortedlist(self, sizeof(XTOperationRec), 20, 1000, xres_cmp_op_seq, NULL, NULL, TRUE, FALSE); +} + +xtPublic void xt_xres_exit_tab(XTThreadPtr self, XTTableHPtr tab) +{ + if (tab->tab_op_list) { + xt_free_sortedlist(self, tab->tab_op_list); + tab->tab_op_list = NULL; + } +} + +static xtBool xres_open_table(XTThreadPtr self, XTWriterStatePtr ws, xtTableID tab_id) +{ + XTOpenTablePtr ot; + + if ((ot = ws->ws_ot)) { + if (ot->ot_table->tab_id == tab_id) + return OK; + xt_db_return_table_to_pool(self, ot); + ws->ws_ot = NULL; + } + + if (ws->ws_tab_gone == tab_id) + return FAILED; + if ((ws->ws_ot = xt_db_open_pool_table(self, ws->ws_db, tab_id, NULL, TRUE))) { + XTTableHPtr tab; + + tab = ws->ws_ot->ot_table; + if (!tab->tab_ind_rec_log_id) { + /* Should not happen... */ + tab->tab_ind_rec_log_id = ws->ws_ind_rec_log_id; + tab->tab_ind_rec_log_offset = ws->ws_ind_rec_log_offset; + } + return OK; + } + ws->ws_tab_gone = tab_id; + return FAILED; +} + +/* {INDEX-RECOV_ROWID} + * Add missing index entries during recovery. + * Set the row ID even if the index entry + * is not committed. It will be removed later by + * the sweeper. + */ +static xtBool xres_add_index_entries(XTOpenTablePtr ot, xtRowID row_id, xtRecordID rec_id, xtWord1 *rec_data) +{ + XTTableHPtr tab = ot->ot_table; + u_int idx_cnt; + XTIndexPtr *ind; + //XTIdxSearchKeyRec key; + + if (tab->tab_dic.dic_disable_index) + return OK; + + for (idx_cnt=0, ind=tab->tab_dic.dic_keys; idx_cnt<tab->tab_dic.dic_key_count; idx_cnt++, ind++) { + /* + key.sk_on_key = FALSE; + key.sk_key_value.sv_flags = XT_SEARCH_WHOLE_KEY; + key.sk_key_value.sv_rec_id = rec_offset; + key.sk_key_value.sv_key = key.sk_key_buf; + key.sk_key_value.sv_length = myxt_create_key_from_row(*ind, key.sk_key_buf, rec_data, NULL); + if (!xt_idx_search(ot, *ind, &key)) { + ot->ot_err_index_no = (*ind)->mi_index_no; + return FAILED; + } + if (!key.sk_on_key) { + } + */ + if (!xt_idx_insert(ot, *ind, row_id, rec_id, rec_data, NULL, TRUE)) { + /* Check the error, certain errors are recoverable! */ + XTThreadPtr self = xt_get_self(); + + if (self->t_exception.e_xt_err == XT_SYSTEM_ERROR && + (XT_FILE_IN_USE(self->t_exception.e_sys_err) || + XT_FILE_ACCESS_DENIED(self->t_exception.e_sys_err) || + XT_FILE_TOO_MANY_OPEN(self->t_exception.e_sys_err) || + self->t_exception.e_sys_err == XT_ENOMEM)) { + ot->ot_err_index_no = (*ind)->mi_index_no; + return FAILED; + } + + /* TODO: Write something to the index header to indicate that + * it is corrupted. + */ + tab->tab_dic.dic_disable_index = XT_INDEX_CORRUPTED; + xt_log_and_clear_exception_ns(); + return OK; + } + } + return OK; +} + +static void xres_remove_index_entries(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1 *rec_data) +{ + XTTableHPtr tab = ot->ot_table; + u_int idx_cnt; + XTIndexPtr *ind; + + if (tab->tab_dic.dic_disable_index) + return; + + for (idx_cnt=0, ind=tab->tab_dic.dic_keys; idx_cnt<tab->tab_dic.dic_key_count; idx_cnt++, ind++) { + if (!xt_idx_delete(ot, *ind, rec_id, rec_data)) + xt_log_and_clear_exception_ns(); + } +} + +static xtWord1 *xres_load_record(XTThreadPtr self, XTOpenTablePtr ot, xtRecordID rec_id, xtWord1 *data, size_t red_size, XTInfoBufferPtr rec_buf, u_int cols_req) +{ + XTTableHPtr tab = ot->ot_table; + xtWord1 *rec_data; + + rec_data = ot->ot_row_rbuffer; + + ASSERT(red_size <= ot->ot_row_rbuf_size); + ASSERT(tab->tab_dic.dic_rec_size <= ot->ot_row_rbuf_size); + if (data) { + if (rec_data != data) + memcpy(rec_data, data, red_size); + } + else { + /* It can be that less than 'dic_rec_size' was written for + * variable length type records. + * If this is the last record in the file, then we will read + * less than actual record size. + */ + if (!XT_PREAD_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), tab->tab_dic.dic_rec_size, 0, rec_data, &red_size, &self->st_statistics.st_rec, self)) + goto failed; + + if (red_size < sizeof(XTTabRecHeadDRec)) + return NULL; + } + + if (XT_REC_IS_FIXED(rec_data[0])) + rec_data = ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE; + else { + if (!xt_ib_alloc(NULL, rec_buf, tab->tab_dic.dic_mysql_buf_size)) + goto failed; + if (XT_REC_IS_VARIABLE(rec_data[0])) { + if (!myxt_load_row(ot, rec_data + XT_REC_FIX_HEADER_SIZE, rec_buf->ib_db.db_data, cols_req)) + goto failed; + } + else if (XT_REC_IS_EXT_DLOG(rec_data[0])) { + if (red_size < XT_REC_EXT_HEADER_SIZE) + return NULL; + + ASSERT(cols_req); + if (cols_req && cols_req <= tab->tab_dic.dic_fix_col_count) { + if (!myxt_load_row(ot, rec_data + XT_REC_EXT_HEADER_SIZE, rec_buf->ib_db.db_data, cols_req)) + goto failed; + } + else { + if (!xt_tab_load_ext_data(ot, rec_id, rec_buf->ib_db.db_data, cols_req)) + goto failed; + } + } + else + /* This is possible, the record has already been cleaned up. */ + return NULL; + rec_data = rec_buf->ib_db.db_data; + } + + return rec_data; + + failed: + /* Running out of memory should not be ignored. */ + if (self->t_exception.e_xt_err == XT_SYSTEM_ERROR && + self->t_exception.e_sys_err == XT_ENOMEM) + xt_throw(self); + xt_log_and_clear_exception_ns(); + return NULL; +} + +/* + * Apply a change from the log. + * + * This function is basically very straight forward, were it not + * for the option to apply operations out of sequence. + * (i.e. in_sequence == FALSE) + * + * If operations are applied in sequence, then they can be + * applied blindly. The update operation is just executed as + * it was logged. + * + * If the changes are not in sequence, then some operation are missing, + * however, the operations that are present are in the correct order. + * + * This can only happen at the end of recovery!!! + * After we have applied all operations in the log we may be + * left with some operations that have not been applied + * because operations were logged out of sequence. + * + * The application of these operations there has to take into + * account the current state of the database. + * They are then applied in a manner that maintains the + * database consistency. + * + * For example, a record that is freed, is free by placing it + * on the current free list. Part of the data logged for the + * operation is ignored. Namely: the "next block" pointer + * that was originally written into the freed record. + */ +static void xres_apply_change(XTThreadPtr self, XTOpenTablePtr ot, XTXactLogBufferDPtr record, xtBool in_sequence, xtBool check_index, XTInfoBufferPtr rec_buf) +{ + XTTableHPtr tab = ot->ot_table; + size_t len; + xtRecordID rec_id; + xtRefID free_ref_id; + XTTabRecFreeDRec free_rec; + xtRowID row_id; + XTTabRowRefDRec row_buf; + XTTabRecHeadDRec rec_head; + size_t tfer; + xtRecordID link_rec_id, prev_link_rec_id; + xtWord1 *rec_data = NULL; + XTTabRecFreeDPtr free_data; + + switch (record->xl.xl_status_1) { + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_DELETE_BG: + rec_id = XT_GET_DISK_4(record->xu.xu_rec_id_4); + len = (size_t) XT_GET_DISK_2(record->xu.xu_size_2); + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), len, (xtWord1 *) &record->xu.xu_rec_type_1, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += len; + + if (check_index && ot->ot_table->tab_dic.dic_key_count) { + switch (record->xl.xl_status_1) { + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_DELETE_BG: + break; + case XT_LOG_ENT_REC_MODIFIED: + if ((rec_data = xres_load_record(self, ot, rec_id, NULL, 0, rec_buf, tab->tab_dic.dic_ind_cols_req))) + xres_remove_index_entries(ot, rec_id, rec_data); + /* No break required: */ + default: + if ((rec_data = xres_load_record(self, ot, rec_id, &record->xu.xu_rec_type_1, len, rec_buf, tab->tab_dic.dic_ind_cols_req))) { + row_id = XT_GET_DISK_4(record->xu.xu_row_id_4); + if (!xres_add_index_entries(ot, row_id, rec_id, rec_data)) + xt_throw(self); + } + break; + } + } + + if (!in_sequence) { + /* A record has been allocated from the EOF, but out of sequence. + * This could leave a gap where other records were allocated + * from the EOF, but those operations have been lost! + * We compensate for this by adding all blocks between + * to the free list. + */ + free_rec.rf_rec_type_1 = XT_TAB_STATUS_FREED; + free_rec.rf_not_used_1 = 0; + while (tab->tab_head_rec_eof_id < rec_id) { + XT_SET_DISK_4(free_rec.rf_next_rec_id_4, tab->tab_head_rec_free_id); + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, tab->tab_head_rec_eof_id, sizeof(XTTabRecFreeDRec), (xtWord1 *) &free_rec, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += sizeof(XTTabRecFreeDRec); + tab->tab_head_rec_free_id = tab->tab_head_rec_eof_id; + tab->tab_head_rec_eof_id++; + } + } + if (tab->tab_head_rec_eof_id < rec_id + 1) + tab->tab_head_rec_eof_id = rec_id + 1; + tab->tab_flush_pending = TRUE; + break; + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_DELETE_FL: + case XT_LOG_ENT_UPDATE_FL_BG: + case XT_LOG_ENT_INSERT_FL_BG: + case XT_LOG_ENT_DELETE_FL_BG: + rec_id = XT_GET_DISK_4(record->xf.xf_rec_id_4); + len = (size_t) XT_GET_DISK_2(record->xf.xf_size_2); + free_ref_id = XT_GET_DISK_4(record->xf.xf_free_rec_id_4); + + if (check_index && + record->xf.xf_status_1 != XT_LOG_ENT_DELETE_FL && + record->xf.xf_status_1 != XT_LOG_ENT_DELETE_FL_BG) { + if ((rec_data = xres_load_record(self, ot, rec_id, &record->xf.xf_rec_type_1, len, rec_buf, tab->tab_dic.dic_ind_cols_req))) { + row_id = XT_GET_DISK_4(record->xf.xf_row_id_4); + if (!xres_add_index_entries(ot, row_id, rec_id, rec_data)) + xt_throw(self); + } + } + + if (!in_sequence) { + /* This record was allocated from the free list. + * Because this operation is out of sequence, there + * could have been other allocations from the + * free list before this, that have gone missing. + * For this reason we have to search the current + * free list and remove the record. + */ + link_rec_id = tab->tab_head_rec_free_id; + prev_link_rec_id = 0; + while (link_rec_id) { + if (!XT_PREAD_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, link_rec_id), sizeof(XTTabRecFreeDRec), sizeof(XTTabRecFreeDRec), (xtWord1 *) &free_rec, NULL, &self->st_statistics.st_rec, self)) + xt_throw(self); + if (link_rec_id == rec_id) + break; + prev_link_rec_id = link_rec_id; + link_rec_id = XT_GET_DISK_4(free_rec.rf_next_rec_id_4); + } + if (link_rec_id == rec_id) { + /* The block was found on the free list. + * remove it: */ + if (prev_link_rec_id) { + /* We write the record from position 'link_rec_id' into + * position 'prev_link_rec_id'. This unlinks 'link_rec_id'! + */ + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, prev_link_rec_id), sizeof(XTTabRecFreeDRec), (xtWord1 *) &free_rec, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += sizeof(XTTabRecFreeDRec); + free_ref_id = tab->tab_head_rec_free_id; + } + else + /* The block is at the front of the list: */ + free_ref_id = XT_GET_DISK_4(free_rec.rf_next_rec_id_4); + } + else { + /* Not found on the free list? */ + if (tab->tab_head_rec_eof_id < rec_id + 1) + tab->tab_head_rec_eof_id = rec_id + 1; + goto write_mod_data; + } + } + if (tab->tab_head_rec_eof_id < rec_id + 1) + tab->tab_head_rec_eof_id = rec_id + 1; + tab->tab_head_rec_free_id = free_ref_id; + tab->tab_head_rec_fnum--; + write_mod_data: + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), len, (xtWord1 *) &record->xf.xf_rec_type_1, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += len; + tab->tab_flush_pending = TRUE; + break; + case XT_LOG_ENT_REC_REMOVED: + case XT_LOG_ENT_REC_REMOVED_EXT: { + xtBool record_loaded; + XTTabRecExtDPtr ext_rec; + size_t red_size; + xtWord4 log_over_size = 0; + xtLogID data_log_id = 0; + xtLogOffset data_log_offset = 0; + u_int cols_required = 0; + + rec_id = XT_GET_DISK_4(record->fr.fr_rec_id_4); + free_data = (XTTabRecFreeDPtr) &record->fr.fr_rec_type_1; + + /* This is a short-cut, it does not require loading the record: */ + if (!check_index && !tab->tab_dic.dic_blob_count && record->fr.fr_status_1 != XT_LOG_ENT_REC_REMOVED_EXT) + goto do_rec_freed; + + ext_rec = (XTTabRecExtDPtr) ot->ot_row_rbuffer; + + if (!XT_PREAD_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), tab->tab_dic.dic_rec_size, 0, ext_rec, &red_size, &self->st_statistics.st_rec, self)) { + xt_log_and_clear_exception_ns(); + goto do_rec_freed; + } + + if (red_size < sizeof(XTTabRecHeadDRec)) + goto do_rec_freed; + + /* Check that the record is the same as the one originally removed. + * This can be different if recovery is repeated. + * For example: + * + * log=21 offset=6304472 REMOVED-X REC op=360616 tab=7 rec=25874 + * log=21 offset=6309230 UPDATE-FL op=360618 tab=7 rec=25874 row=26667 log=1 offset=26503077 xact=209 + * log=21 offset=6317500 CLEAN REC op=360631 tab=7 rec=25874 + * + * If this recovery sequence is repeated, then the REMOVED-X will free the + * extended record belonging to the update that came afterwards! + * + * Additional situation to consider: + * + * - A record "x" is created, and index entries created. + * - A checkpoint is made done. + * - Record "x" is deleted due to UPDATE. + * - The index entries are removed, but the index is not + * flushed. + * - This deletion is written to disk by the writer. + * So we have the situation that the remove is on disk, + * but the index changes have not been made. + * + * In this case, skipping to "do_rec_freed" is incorrect. + */ + if (record->fr.fr_stat_id_1 != ext_rec->tr_stat_id_1 || + XT_GET_DISK_4(record->fr.fr_xact_id_4) != XT_GET_DISK_4(ext_rec->tr_xact_id_4)) + goto dont_remove_x_record; + + if (record->xl.xl_status_1 == XT_LOG_ENT_REC_REMOVED_EXT) { + if (!XT_REC_IS_EXT_DLOG(ext_rec->tr_rec_type_1)) + goto dont_remove_x_record; + if (red_size < offsetof(XTTabRecExtDRec, re_data)) + goto dont_remove_x_record; + + /* Save this for later (can be overwritten by xres_load_record(): */ + data_log_id = XT_GET_DISK_2(ext_rec->re_log_id_2); + data_log_offset = XT_GET_DISK_6(ext_rec->re_log_offs_6); + log_over_size = XT_GET_DISK_4(ext_rec->re_log_dat_siz_4); + } + dont_remove_x_record: + + record_loaded = FALSE; + + if (check_index) { + cols_required = tab->tab_dic.dic_ind_cols_req; + if (tab->tab_dic.dic_blob_cols_req > cols_required) + cols_required = tab->tab_dic.dic_blob_cols_req; + if (!(rec_data = xres_load_record(self, ot, rec_id, ot->ot_row_rbuffer, red_size, rec_buf, cols_required))) + goto do_rec_freed; + record_loaded = TRUE; + xres_remove_index_entries(ot, rec_id, rec_data); + } + + if (tab->tab_dic.dic_blob_count) { + if (!record_loaded) { + if (tab->tab_dic.dic_blob_cols_req > cols_required) + cols_required = tab->tab_dic.dic_blob_cols_req; + if (!(rec_data = xres_load_record(self, ot, rec_id, ot->ot_row_rbuffer, red_size, rec_buf, cols_required))) + /* [(7)] REMOVE is followed by FREE: + goto get_rec_offset; + */ + goto do_rec_freed; + record_loaded = TRUE; + } +#ifdef XT_STREAMING + myxt_release_blobs(ot, rec_data, rec_id); +#endif + } + + if (record->xl.xl_status_1 == XT_LOG_ENT_REC_REMOVED_EXT) { + /* Note: dlb_delete_log() may be repeated, but should handle this: + * + * Example: + * log=5 offset=213334 CLEAN REC op=28175 tab=1 rec=317428 + * ... + * log=6 offset=321063 REMOVED-X REC op=33878 tab=1 rec=317428 + * + * When this sequence is repeated during recovery, then CLEAN REC + * will reset the status byte of the record so that it + * comes back to here! + * + * The check for zero is probably not required here. + */ + if (data_log_id && data_log_offset && log_over_size) { + if (!ot->ot_thread->st_dlog_buf.dlb_delete_log(data_log_id, data_log_offset, log_over_size, tab->tab_id, rec_id, self)) { + if (ot->ot_thread->t_exception.e_xt_err != XT_ERR_BAD_EXT_RECORD && + ot->ot_thread->t_exception.e_xt_err != XT_ERR_DATA_LOG_NOT_FOUND) + xt_log_and_clear_exception_ns(); + } + } + } + + goto do_rec_freed; + } + case XT_LOG_ENT_REC_REMOVED_BI: { + /* + * For deletion we need the complete before image because of the following problem. + * + * DROP TABLE IF EXISTS t1; + * CREATE TABLE t1 (ID int primary key auto_increment, value int, index (value)) engine=pbxt; + * + * insert t1(value) values(50); + * + * -- CHECKPOINT -- + * + * update t1 set value = 60; + * + * -- PAUSE -- + * + * update t1 set value = 70; + * + * -- CRASH -- + * + * select value from t1; + * select * from t1; + * + * 081203 12:11:46 [Note] PBXT: Recovering from 1-148, bytes to read: 33554284 + * log=1 offset=148 UPDATE-BG op=5 tab=1 rec=2 row=1 xact=3 + * log=1 offset=188 REC ADD ROW op=6 tab=1 row=1 + * log=1 offset=206 COMMIT xact=3 + * log=1 offset=216 REMOVED REC op=7 tab=1 rec=1 xact=2 + * log=1 offset=241 CLEAN REC op=8 tab=1 rec=2 + * log=1 offset=261 CLEANUP xact=3 + * log=1 offset=267 UPDATE-FL-BG op=9 tab=1 rec=1 row=1 xact=4 + * log=1 offset=311 REC ADD ROW op=10 tab=1 row=1 + * log=1 offset=329 COMMIT xact=4 + * log=1 offset=339 REMOVED REC op=11 tab=1 rec=2 xact=3 + * log=1 offset=364 CLEAN REC op=12 tab=1 rec=1 + * log=1 offset=384 CLEANUP xact=4 + * 081203 12:12:15 [Note] PBXT: Recovering complete at 1-390, bytes read: 33554284 + * + * mysql> select value from t1; + * +-------+ + * | value | + * +-------+ + * | 50 | + * | 70 | + * +-------+ + * 2 rows in set (55.99 sec) + * + * mysql> select * from t1; + * +----+-------+ + * | ID | value | + * +----+-------+ + * | 1 | 70 | + * +----+-------+ + * 1 row in set (0.00 sec) + */ + XTTabRecExtDPtr ext_rec; + xtWord4 log_over_size = 0; + xtLogID data_log_id = 0; + xtLogOffset data_log_offset = 0; + u_int cols_required = 0; + xtBool record_loaded; + size_t rec_size; + + rec_id = XT_GET_DISK_4(record->rb.rb_rec_id_4); + rec_size = XT_GET_DISK_2(record->rb.rb_size_2); + + ext_rec = (XTTabRecExtDPtr) &record->rb.rb_rec_type_1; + + if (XT_REC_IS_EXT_DLOG(record->rb.rb_rec_type_1)) { + /* Save this for later (can be overwritten by xres_load_record(): */ + data_log_id = XT_GET_DISK_2(ext_rec->re_log_id_2); + data_log_offset = XT_GET_DISK_6(ext_rec->re_log_offs_6); + log_over_size = XT_GET_DISK_4(ext_rec->re_log_dat_siz_4); + } + + record_loaded = FALSE; + + if (check_index) { + cols_required = tab->tab_dic.dic_ind_cols_req; +#ifdef XT_STREAMING + if (tab->tab_dic.dic_blob_cols_req > cols_required) + cols_required = tab->tab_dic.dic_blob_cols_req; +#endif + if (!(rec_data = xres_load_record(self, ot, rec_id, &record->rb.rb_rec_type_1, rec_size, rec_buf, cols_required))) + goto go_on_to_free; + record_loaded = TRUE; + xres_remove_index_entries(ot, rec_id, rec_data); + } + +#ifdef XT_STREAMING + if (tab->tab_dic.dic_blob_count) { + if (!record_loaded) { + cols_required = tab->tab_dic.dic_blob_cols_req; + if (!(rec_data = xres_load_record(self, ot, rec_id, &record->rb.rb_rec_type_1, rec_size, rec_buf, cols_required))) + /* [(7)] REMOVE is followed by FREE: + goto get_rec_offset; + */ + goto go_on_to_free; + record_loaded = TRUE; + } + myxt_release_blobs(ot, rec_data, rec_id); + } +#endif + + if (data_log_id && data_log_offset && log_over_size) { + if (!ot->ot_thread->st_dlog_buf.dlb_delete_log(data_log_id, data_log_offset, log_over_size, tab->tab_id, rec_id, self)) { + if (ot->ot_thread->t_exception.e_xt_err != XT_ERR_BAD_EXT_RECORD && + ot->ot_thread->t_exception.e_xt_err != XT_ERR_DATA_LOG_NOT_FOUND) + xt_log_and_clear_exception_ns(); + } + } + + go_on_to_free: + /* Use the new record type: */ + record->rb.rb_rec_type_1 = record->rb.rb_new_rec_type_1; + free_data = (XTTabRecFreeDPtr) &record->rb.rb_rec_type_1; + goto do_rec_freed; + } + case XT_LOG_ENT_REC_FREED: + rec_id = XT_GET_DISK_4(record->fr.fr_rec_id_4); + free_data = (XTTabRecFreeDPtr) &record->fr.fr_rec_type_1; + do_rec_freed: + if (!in_sequence) { + size_t red_size; + + /* Free the record. + * We place the record on front of the current + * free list. + * + * However, before we do this, we remove the record + * from its row list, if the record is on a row list. + * + * We do this here, because in the normal removal + * from the row list uses the operations: + * + * XT_LOG_ENT_REC_UNLINKED, XT_LOG_ENT_ROW_SET and + * XT_LOG_ENT_ROW_FREED. + * + * When operations are performed out of sequence, + * these operations are ignored for the purpose + * of removing the record from the row. + */ + if (!XT_PREAD_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), sizeof(XTTabRecHeadDRec), sizeof(XTTabRecHeadDRec), (xtWord1 *) &rec_head, NULL, &self->st_statistics.st_rec, self)) + xt_throw(self); + /* The record is already free: */ + if (XT_REC_IS_FREE(rec_head.tr_rec_type_1)) + goto free_done; + row_id = XT_GET_DISK_4(rec_head.tr_row_id_4); + + /* Search the row for this record: */ + if (!XT_PREAD_RR_FILE(ot->ot_row_file, xt_row_id_to_row_offset(tab, row_id), sizeof(XTTabRowRefDRec), sizeof(XTTabRowRefDRec), (xtWord1 *) &row_buf, NULL, &self->st_statistics.st_rec, self)) + xt_throw(self); + link_rec_id = XT_GET_DISK_4(row_buf.rr_ref_id_4); + prev_link_rec_id = 0; + while (link_rec_id) { + if (!XT_PREAD_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, link_rec_id), sizeof(XTTabRecHeadDRec), 0, (xtWord1 *) &rec_head, &red_size, &self->st_statistics.st_rec, self)) { + xt_log_and_clear_exception(self); + break; + } + if (red_size < sizeof(XTTabRecHeadDRec)) + break; + if (link_rec_id == rec_id) + break; + if (XT_GET_DISK_4(rec_head.tr_row_id_4) != row_id) + break; + switch (rec_head.tr_rec_type_1 & XT_TAB_STATUS_MASK) { + case XT_TAB_STATUS_FREED: + break; + case XT_TAB_STATUS_DELETE: + case XT_TAB_STATUS_FIXED: + case XT_TAB_STATUS_VARIABLE: + case XT_TAB_STATUS_EXT_DLOG: + break; + default: + ASSERT(FALSE); + goto exit_loop; + } + if (rec_head.tr_rec_type_1 & ~(XT_TAB_STATUS_CLEANED_BIT | XT_TAB_STATUS_MASK)) { + ASSERT(FALSE); + break; + } + prev_link_rec_id = link_rec_id; + link_rec_id = XT_GET_DISK_4(rec_head.tr_prev_rec_id_4); + } + + exit_loop: + if (link_rec_id == rec_id) { + /* The record was found on the row list, remove it: */ + if (prev_link_rec_id) { + /* We write the previous variation pointer from position 'link_rec_id' into + * variation pointer of the 'prev_link_rec_id' record. This unlinks 'link_rec_id'! + */ + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, prev_link_rec_id) + offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4), XT_RECORD_ID_SIZE, (xtWord1 *) &rec_head.tr_prev_rec_id_4, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += XT_RECORD_ID_SIZE; + } + else { + /* The record is at the front of the row list: */ + xtRefID ref_id = XT_GET_DISK_4(rec_head.tr_prev_rec_id_4); + XT_SET_DISK_4(row_buf.rr_ref_id_4, ref_id); + if (!XT_PWRITE_RR_FILE(ot->ot_row_file, xt_row_id_to_row_offset(tab, row_id), sizeof(XTTabRowRefDRec), (xtWord1 *) &row_buf, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += sizeof(XTTabRowRefDRec); + } + } + + /* Now we free the record, by placing it at the front of + * the free list: + */ + XT_SET_DISK_4(free_data->rf_next_rec_id_4, tab->tab_head_rec_free_id); + } + tab->tab_head_rec_free_id = rec_id; + tab->tab_head_rec_fnum++; + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), sizeof(XTTabRecFreeDRec), (xtWord1 *) free_data, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += sizeof(XTTabRecFreeDRec); + tab->tab_flush_pending = TRUE; + free_done: + break; + case XT_LOG_ENT_REC_MOVED: + len = 8; + rec_id = XT_GET_DISK_4(record->xw.xw_rec_id_4); + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id) + offsetof(XTTabRecExtDRec, re_log_id_2), len, (xtWord1 *) &record->xw.xw_rec_type_1, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += len; + tab->tab_flush_pending = TRUE; + break; + case XT_LOG_ENT_REC_CLEANED: + len = offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE; + goto get_rec_offset; + case XT_LOG_ENT_REC_CLEANED_1: + len = 1; + goto get_rec_offset; + case XT_LOG_ENT_REC_UNLINKED: + if (!in_sequence) { + /* Unlink the record. + * This is done when the record is freed. + */ + break; + } + len = offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE; + get_rec_offset: + rec_id = XT_GET_DISK_4(record->xw.xw_rec_id_4); + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), len, (xtWord1 *) &record->xw.xw_rec_type_1, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += len; + tab->tab_flush_pending = TRUE; + break; + case XT_LOG_ENT_ROW_NEW: + len = offsetof(XTactRowAddedEntryDRec, xa_free_list_4); + row_id = XT_GET_DISK_4(record->xa.xa_row_id_4); + if (!in_sequence) { + /* A row was allocated from the EOF. Because operations are missing. + * The blocks between the current EOF and the new EOF need to be + * place on the free list! + */ + while (tab->tab_head_row_eof_id < row_id) { + XT_SET_DISK_4(row_buf.rr_ref_id_4, tab->tab_head_row_free_id); + if (!XT_PWRITE_RR_FILE(ot->ot_row_file, xt_row_id_to_row_offset(tab, tab->tab_head_row_eof_id), sizeof(XTTabRowRefDRec), (xtWord1 *) &row_buf, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += sizeof(XTTabRowRefDRec); + tab->tab_head_row_free_id = tab->tab_head_row_eof_id; + tab->tab_head_row_eof_id++; + } + } + if (tab->tab_head_row_eof_id < row_id + 1) + tab->tab_head_row_eof_id = row_id + 1; + tab->tab_flush_pending = TRUE; + break; + case XT_LOG_ENT_ROW_NEW_FL: + len = sizeof(XTactRowAddedEntryDRec); + row_id = XT_GET_DISK_4(record->xa.xa_row_id_4); + free_ref_id = XT_GET_DISK_4(record->xa.xa_free_list_4); + if (!in_sequence) { + size_t red_size; + /* The record was taken from the free list. + * If the operations were in sequence, then this would be + * the front of the free list now. + * However, because operations are missing, it may no + * longer be the front of the free list! + * Search and remove: + */ + link_rec_id = tab->tab_head_row_free_id; + prev_link_rec_id = 0; + while (link_rec_id) { + if (!XT_PREAD_RR_FILE(ot->ot_row_file, xt_row_id_to_row_offset(tab, link_rec_id), sizeof(XTTabRowRefDRec), 0, (xtWord1 *) &row_buf, &red_size, &self->st_statistics.st_rec, self)) { + xt_log_and_clear_exception(self); + break; + } + if (red_size < sizeof(XTTabRowRefDRec)) + break; + if (link_rec_id == row_id) + break; + prev_link_rec_id = link_rec_id; + link_rec_id = XT_GET_DISK_4(row_buf.rr_ref_id_4); + } + if (link_rec_id == row_id) { + /* The block was found on the free list, remove it: */ + if (prev_link_rec_id) { + /* We write the record from position 'link_rec_id' into + * position 'prev_link_rec_id'. This unlinks 'link_rec_id'! + */ + if (!XT_PWRITE_RR_FILE(ot->ot_row_file, xt_row_id_to_row_offset(tab, prev_link_rec_id), sizeof(XTTabRowRefDRec), (xtWord1 *) &row_buf, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += sizeof(XTTabRowRefDRec); + free_ref_id = tab->tab_head_row_free_id; + } + else + /* The block is at the front of the free list: */ + free_ref_id = XT_GET_DISK_4(row_buf.rr_ref_id_4); + } + else { + /* Not found? */ + if (tab->tab_head_row_eof_id < row_id + 1) + tab->tab_head_row_eof_id = row_id + 1; + break; + } + + } + if (tab->tab_head_row_eof_id < row_id + 1) + tab->tab_head_row_eof_id = row_id + 1; + tab->tab_head_row_free_id = free_ref_id; + tab->tab_head_row_fnum--; + tab->tab_flush_pending = TRUE; + break; + case XT_LOG_ENT_ROW_FREED: + row_id = XT_GET_DISK_4(record->wr.wr_row_id_4); + if (!in_sequence) { + /* Free the row. + * Since this operation is being performed out of sequence, we + * must assume that some other free and allocation operations + * must be missing. + * For this reason, we add the row to the front of the + * existing free list. + */ + XT_SET_DISK_4(record->wr.wr_ref_id_4, tab->tab_head_row_free_id); + } + tab->tab_head_row_free_id = row_id; + tab->tab_head_row_fnum++; + goto write_row_data; + case XT_LOG_ENT_ROW_ADD_REC: + row_id = XT_GET_DISK_4(record->wr.wr_row_id_4); + if (!in_sequence) { + if (!XT_PREAD_RR_FILE(ot->ot_row_file, xt_row_id_to_row_offset(tab, row_id), sizeof(XTTabRowRefDRec), 0, (xtWord1 *) &row_buf, &tfer, &self->st_statistics.st_rec, self)) + xt_throw(self); + if (tfer == sizeof(XTTabRowRefDRec)) { + /* Add a record to the front of the row. + * This is easy, but we have to make sure that the next + * pointer in the record is correct. + */ + rec_id = XT_GET_DISK_4(record->wr.wr_ref_id_4); + if (!XT_PREAD_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), sizeof(XTTabRecHeadDRec), 0, (xtWord1 *) &rec_head, &tfer, &self->st_statistics.st_rec, self)) + xt_throw(self); + if (tfer == sizeof(XTTabRecHeadDRec) && XT_GET_DISK_4(rec_head.tr_row_id_4) == row_id) { + /* This is now the correct next pointer: */ + xtRecordID next_ref_id = XT_GET_DISK_4(row_buf.rr_ref_id_4); + if (XT_GET_DISK_4(rec_head.tr_prev_rec_id_4) != next_ref_id && + rec_id != next_ref_id) { + XT_SET_DISK_4(rec_head.tr_prev_rec_id_4, next_ref_id); + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, rec_id), sizeof(XTTabRecHeadDRec), (xtWord1 *) &rec_head, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + xt_throw(self); + tab->tab_bytes_to_flush += sizeof(XTTabRecHeadDRec); + } + } + } + + } + goto write_row_data; + case XT_LOG_ENT_ROW_SET: + if (!in_sequence) + /* This operation is ignored when out of sequence! + * The operation is used to remove a record from a row. + * This is done automatically when the record is freed. + */ + break; + row_id = XT_GET_DISK_4(record->wr.wr_row_id_4); + write_row_data: + ASSERT_NS(XT_GET_DISK_4(record->wr.wr_ref_id_4) < tab->tab_head_rec_eof_id); + if (!XT_PWRITE_RR_FILE(ot->ot_row_file, xt_row_id_to_row_offset(tab, row_id), sizeof(XTTabRowRefDRec), (xtWord1 *) &record->wr.wr_ref_id_4, &ot->ot_thread->st_statistics.st_rec, self)) + xt_throw(self); + tab->tab_bytes_to_flush += sizeof(XTTabRowRefDRec); + if (tab->tab_head_row_eof_id < row_id + 1) + tab->tab_head_row_eof_id = row_id + 1; + tab->tab_flush_pending = TRUE; + break; + case XT_LOG_ENT_NO_OP: + case XT_LOG_ENT_END_OF_LOG: + break; + } +} + +/* + * Apply all operations that have been buffered + * for a particular table. + * Operations are buffered if they are + * read from the log out of sequence. + * + * In this case we buffer, and wait for the + * out of sequence operations to arrive. + * + * When the server is running, this will always be + * the case. A delay occurs while a transaction + * fills its private log buffer. + */ +static void xres_apply_operations(XTThreadPtr self, XTWriterStatePtr ws, xtBool in_sequence) +{ + XTTableHPtr tab = ws->ws_ot->ot_table; + u_int i = 0; + XTOperationPtr op; + xtBool check_index; + +// XTDatabaseHPtr db, XTOpenTablePtr ot, XTXactSeqReadPtr sr, XTDataBufferPtr databuf + xt_sl_lock(self, tab->tab_op_list); + for (;;) { + op = (XTOperationPtr) xt_sl_item_at(tab->tab_op_list, i); + if (!op) + break; + if (in_sequence && tab->tab_head_op_seq+1 != op->or_op_seq) + break; + xt_db_set_size(self, &ws->ws_databuf, (size_t) op->or_op_len); + if (!ws->ws_db->db_xlog.xlog_rnd_read(&ws->ws_seqread, op->or_log_id, op->or_log_offset, (size_t) op->or_op_len, ws->ws_databuf.db_data, NULL, self)) + xt_throw(self); + check_index = ws->ws_in_recover && xt_comp_log_pos(op->or_log_id, op->or_log_offset, ws->ws_ind_rec_log_id, ws->ws_ind_rec_log_offset) >= 0; + xres_apply_change(self, ws->ws_ot, (XTXactLogBufferDPtr) ws->ws_databuf.db_data, in_sequence, check_index, &ws->ws_rec_buf); + tab->tab_head_op_seq = op->or_op_seq; + if (tab->tab_wr_wake_freeer) { + if (!XTTableSeq::xt_op_is_before(tab->tab_head_op_seq, tab->tab_wake_freeer_op)) + xt_wr_wake_freeer(self); + } + i++; + } + xt_sl_remove_from_front(self, tab->tab_op_list, i); + xt_sl_unlock(self, tab->tab_op_list); +} + +/* Check for operations still remaining on tables. + * These operations are applied even though operations + * in sequence are missing. + */ +xtBool xres_sync_operations(XTThreadPtr self, XTDatabaseHPtr db, XTWriterStatePtr ws) +{ + u_int edx; + XTTableEntryPtr te_ptr; + XTTableHPtr tab; + xtBool op_synced = FALSE; + + xt_enum_tables_init(&edx); + while ((te_ptr = xt_enum_tables_next(self, db, &edx))) { + /* Dirty read of tab_op_list OK, here because this is the + * only thread that updates the list! + */ + if ((tab = te_ptr->te_table)) { + if (xt_sl_get_size(tab->tab_op_list)) { + op_synced = TRUE; + if (xres_open_table(self, ws, te_ptr->te_tab_id)) + xres_apply_operations(self, ws, FALSE); + } + + /* Update the pointer cache: */ + tab->tab_seq.xt_op_seq_set(self, tab->tab_head_op_seq+1); + tab->tab_row_eof_id = tab->tab_head_row_eof_id; + tab->tab_row_free_id = tab->tab_head_row_free_id; + tab->tab_row_fnum = tab->tab_head_row_fnum; + tab->tab_rec_eof_id = tab->tab_head_rec_eof_id; + tab->tab_rec_free_id = tab->tab_head_rec_free_id; + tab->tab_rec_fnum = tab->tab_head_rec_fnum; + } + } + return op_synced; +} + +/* + * Operations from the log are applied in sequence order. + * If the operations are out of sequence, they are buffered + * until the missing operations appear. + * + * NOTE: No lock is required because there should only be + * one thread that does this! + */ +xtPublic void xt_xres_apply_in_order(XTThreadPtr self, XTWriterStatePtr ws, xtLogID log_id, xtLogOffset log_offset, XTXactLogBufferDPtr record) +{ + xtOpSeqNo op_seq; + xtTableID tab_id; + size_t len; + xtBool check_index; + +// XTDatabaseHPtr db, XTOpenTablePtr *ot, XTXactSeqReadPtr sr, XTDataBufferPtr databuf + switch (record->xl.xl_status_1) { + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_DELETE_BG: + len = offsetof(XTactUpdateEntryDRec, xu_rec_type_1) + (size_t) XT_GET_DISK_2(record->xu.xu_size_2); + op_seq = XT_GET_DISK_4(record->xu.xu_op_seq_4); + tab_id = XT_GET_DISK_4(record->xu.xu_tab_id_4); + break; + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_DELETE_FL: + case XT_LOG_ENT_UPDATE_FL_BG: + case XT_LOG_ENT_INSERT_FL_BG: + case XT_LOG_ENT_DELETE_FL_BG: + len = offsetof(XTactUpdateFLEntryDRec, xf_rec_type_1) + (size_t) XT_GET_DISK_2(record->xf.xf_size_2); + op_seq = XT_GET_DISK_4(record->xf.xf_op_seq_4); + tab_id = XT_GET_DISK_4(record->xf.xf_tab_id_4); + break; + case XT_LOG_ENT_REC_FREED: + case XT_LOG_ENT_REC_REMOVED: + case XT_LOG_ENT_REC_REMOVED_EXT: + /* [(7)] REMOVE is now a extended version of FREE! */ + len = offsetof(XTactFreeRecEntryDRec, fr_rec_type_1) + sizeof(XTTabRecFreeDRec); + goto fixed_len_data; + case XT_LOG_ENT_REC_REMOVED_BI: + len = offsetof(XTactRemoveBIEntryDRec, rb_rec_type_1) + (size_t) XT_GET_DISK_2(record->rb.rb_size_2); + op_seq = XT_GET_DISK_4(record->rb.rb_op_seq_4); + tab_id = XT_GET_DISK_4(record->rb.rb_tab_id_4); + break; + case XT_LOG_ENT_REC_MOVED: + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1) + 8; + goto fixed_len_data; + case XT_LOG_ENT_REC_CLEANED: + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1) + offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE; + goto fixed_len_data; + case XT_LOG_ENT_REC_CLEANED_1: + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1) + 1; + goto fixed_len_data; + case XT_LOG_ENT_REC_UNLINKED: + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1) + offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE; + fixed_len_data: + op_seq = XT_GET_DISK_4(record->xw.xw_op_seq_4); + tab_id = XT_GET_DISK_4(record->xw.xw_tab_id_4); + break; + case XT_LOG_ENT_ROW_NEW: + len = sizeof(XTactRowAddedEntryDRec) - 4; + goto new_row; + case XT_LOG_ENT_ROW_NEW_FL: + len = sizeof(XTactRowAddedEntryDRec); + new_row: + op_seq = XT_GET_DISK_4(record->xa.xa_op_seq_4); + tab_id = XT_GET_DISK_4(record->xa.xa_tab_id_4); + break; + case XT_LOG_ENT_ROW_ADD_REC: + case XT_LOG_ENT_ROW_SET: + case XT_LOG_ENT_ROW_FREED: + len = offsetof(XTactWriteRowEntryDRec, wr_ref_id_4) + sizeof(XTTabRowRefDRec); + op_seq = XT_GET_DISK_4(record->wr.wr_op_seq_4); + tab_id = XT_GET_DISK_4(record->wr.wr_tab_id_4); + break; + case XT_LOG_ENT_NO_OP: + case XT_LOG_ENT_END_OF_LOG: + return; + default: + return; + } + + if (!xres_open_table(self, ws, tab_id)) + return; + + XTTableHPtr tab = ws->ws_ot->ot_table; + + /* NOTE: + * + * During normal operation this is actually given. + * + * During recovery, it only applies to the record/row files + * The index file is flushed indepently, and changes may + * have been applied to the index (due to a call to flush index, + * which comes as a result of out of memory) that have not been + * applied to the record/row files. + * + * As a result we need to do the index checks that apply to this + * change. + * + * At the moment, I will just do everything, which should not + * hurt! + * + * This error can be repeated by running the test + * runTest(OUT_OF_CACHE_UPDATE_TEST, 32, OUT_OF_CACHE_UPDATE_TEST_UPDATE_COUNT, OUT_OF_CACHE_UPDATE_TEST_SET_SIZE) + * and crashing after a while. + * + * Do this by setting not_this to NULL. This will cause the test to + * hang after a while. After a restart the indexes are corrupt if the + * ws->ws_in_recover condition is not present here. + */ + if (ws->ws_in_recover) { + if (!tab->tab_recovery_done) { + /* op_seq <= tab_head_op_seq + 1: */ + ASSERT(XTTableSeq::xt_op_is_before(op_seq, tab->tab_head_op_seq+2)); + if (XTTableSeq::xt_op_is_before(op_seq-1, tab->tab_head_op_seq)) + /* Adjust the operation sequence number: */ + tab->tab_head_op_seq = op_seq-1; + tab->tab_recovery_done = TRUE; + } + } + + if (!XTTableSeq::xt_op_is_before(tab->tab_head_op_seq, op_seq)) + return; + + if (tab->tab_head_op_seq+1 == op_seq) { + /* I could use tab_ind_rec_log_id, but this may be a problem, if + * recovery does not recover up to the last committed transaction. + */ + check_index = ws->ws_in_recover && xt_comp_log_pos(log_id, log_offset, ws->ws_ind_rec_log_id, ws->ws_ind_rec_log_offset) >= 0; + xres_apply_change(self, ws->ws_ot, record, TRUE, check_index, &ws->ws_rec_buf); + tab->tab_head_op_seq = op_seq; + if (tab->tab_wr_wake_freeer) { + if (!XTTableSeq::xt_op_is_before(tab->tab_head_op_seq, tab->tab_wake_freeer_op)) + xt_wr_wake_freeer(self); + } + + /* Apply any operations in the list that now follow on... + * NOTE: the tab_op_list only has be locked for modification. + * This is because only one thread ever changes the list + * (on startup and the writer), but the checkpoint thread + * reads it. + */ + XTOperationPtr op; + if ((op = (XTOperationPtr) xt_sl_first_item(tab->tab_op_list))) { + if (tab->tab_head_op_seq+1 == op->or_op_seq) { + xres_apply_operations(self, ws, TRUE); + } + } + } + else { + /* Add the operation to the list: */ + XTOperationRec op; + + op.or_op_seq = op_seq; + op.or_op_len = len; + op.or_log_id = log_id; + op.or_log_offset = log_offset; + xt_sl_lock(self, tab->tab_op_list); + xt_sl_insert(self, tab->tab_op_list, &op_seq, &op); + ASSERT(tab->tab_op_list->sl_usage_count < 1000000); + xt_sl_unlock(self, tab->tab_op_list); + } +} + +/* ---------------------------------------------------------------------- + * CHECKPOINTING FUNCTIONALITY + */ + +static xtBool xres_delete_data_log(XTDatabaseHPtr db, xtLogID log_id) +{ + XTDataLogFilePtr data_log; + char path[PATH_MAX]; + + db->db_datalogs.dlc_name(PATH_MAX, path, log_id); + + if (!db->db_datalogs.dlc_remove_data_log(log_id, TRUE)) + return FAILED; + + if (xt_fs_exists(path)) { +#ifdef DEBUG_LOG_DELETE + printf("-- delete log: %s\n", path); +#endif + if (!xt_fs_delete(NULL, path)) + return FAILED; + } + /* The log was deleted: */ + if (!db->db_datalogs.dlc_get_data_log(&data_log, log_id, TRUE, NULL)) + return FAILED; + if (data_log) { + if (!db->db_datalogs.dls_set_log_state(data_log, XT_DL_DELETED)) + return FAILED; + } + return OK; +} + +static int xres_comp_flush_tabs(XTThreadPtr self __attribute__((unused)), register const void *thunk __attribute__((unused)), register const void *a, register const void *b) +{ + xtTableID tab_id = *((xtTableID *) a); + XTCheckPointTablePtr cp_tab = (XTCheckPointTablePtr) b; + + if (tab_id < cp_tab->cpt_tab_id) + return -1; + if (tab_id > cp_tab->cpt_tab_id) + return 1; + return 0; +} + +static void xres_init_checkpoint_state(XTThreadPtr self, XTCheckPointStatePtr cp) +{ + xt_init_mutex_with_autoname(self, &cp->cp_state_lock); +} + +static void xres_free_checkpoint_state(XTThreadPtr self, XTCheckPointStatePtr cp) +{ + xt_free_mutex(&cp->cp_state_lock); + if (cp->cp_table_ids) { + xt_free_sortedlist(self, cp->cp_table_ids); + cp->cp_table_ids = NULL; + } +} + +/* + * Remove the deleted logs so that they can be re-used. + * This is only possible after a checkpoint has been + * written that does _not_ include these logs as logs + * to be deleted! + */ +static xtBool xres_remove_data_logs(XTDatabaseHPtr db) +{ + u_int no_of_logs = xt_sl_get_size(db->db_datalogs.dlc_deleted); + xtLogID *log_id_ptr; + + for (u_int i=0; i<no_of_logs; i++) { + log_id_ptr = (xtLogID *) xt_sl_item_at(db->db_datalogs.dlc_deleted, i); + if (!db->db_datalogs.dlc_remove_data_log(*log_id_ptr, FALSE)) + return FAILED; + } + xt_sl_set_size(db->db_datalogs.dlc_deleted, 0); + return OK; +} + +/* ---------------------------------------------------------------------- + * INIT & EXIT + */ + +xtPublic void xt_xres_init(XTThreadPtr self, XTDatabaseHPtr db) +{ + xtLogID max_log_id; + + xt_init_mutex_with_autoname(self, &db->db_cp_lock); + xt_init_cond(self, &db->db_cp_cond); + + xres_init_checkpoint_state(self, &db->db_cp_state); + db->db_restart.xres_init(self, db, &db->db_wr_log_id, &db->db_wr_log_offset, &max_log_id); + + /* It is also the position where transactions will start writing the + * log: + */ + if (!db->db_xlog.xlog_set_write_offset(db->db_wr_log_id, db->db_wr_log_offset, max_log_id, self)) + xt_throw(self); +} + +xtPublic void xt_xres_exit(XTThreadPtr self, XTDatabaseHPtr db) +{ + db->db_restart.xres_exit(self); + xres_free_checkpoint_state(self, &db->db_cp_state); + xt_free_mutex(&db->db_cp_lock); + xt_free_cond(&db->db_cp_cond); +} + +/* ---------------------------------------------------------------------- + * RESTART FUNCTIONALITY + */ + +/* + * Restart the database. This function loads the restart position, and + * applies all changes in the logs, until the end of the log, or + * a corrupted record is found. + * + * The restart position is the position in the log where we know that + * all the changes up to that point have been flushed to the + * database. + * + * This is called the checkpoint position. The checkpoint position + * is written alternatively to 2 restart files. + * + * To make a checkpoint: + * Get the current log writer log offset. + * For each table: + * Get the log offset of the next operation on the table, if an + * operation is queued for the table. + * Flush that table, and the operation sequence to the table. + * For each unclean transaction: + * Get the log offset of the begin of the transaction. + * Write the lowest of all log offsets to the restart file! + */ + +void XTXactRestart::xres_init(XTThreadPtr self, XTDatabaseHPtr db, xtLogID *log_id, xtLogOffset *log_offset, xtLogID *max_log_id) +{ + char path[PATH_MAX]; + XTOpenFilePtr of = NULL; + XTXlogCheckpointDPtr res_1_buffer = NULL; + XTXlogCheckpointDPtr res_2_buffer = NULL; + XTXlogCheckpointDPtr use_buffer; + xtLogID ind_rec_log_id = 0; + xtLogOffset ind_rec_log_offset = 0; + + enter_(); + xres_db = db; + + ASSERT(!self->st_database); + /* The following call stack: + * XTDatabaseLog::xlog_flush_pending() + * XTDatabaseLog::xlog_flush() + * xt_xlog_flush_log() + * xt_flush_indices() + * idx_out_of_memory_failure() + * xt_idx_delete() + * xres_remove_index_entries() + * xres_apply_change() + * xt_xres_apply_in_order() + * XTXactRestart::xres_restart() + * XTXactRestart::xres_init() + * Leads to st_database being used! + */ + self->st_database = db; + +#ifdef SKIP_STARTUP_CHECKPOINT + /* When debugging, we do not checkpoint immediately, just in case + * we detect a problem during recovery. + */ + xres_cp_required = FALSE; +#else + xres_cp_required = TRUE; +#endif + xres_cp_number = 0; + try_(a) { + + /* Figure out which restart file to use. + */ + xres_name(PATH_MAX, path, 1); + if ((of = xt_open_file(self, path, XT_FS_MISSING_OK))) { + size_t res_1_size; + + res_1_size = (size_t) xt_seek_eof_file(self, of); + res_1_buffer = (XTXlogCheckpointDPtr) xt_malloc(self, res_1_size); + if (!xt_pread_file(of, 0, res_1_size, res_1_size, res_1_buffer, NULL, &self->st_statistics.st_x, self)) + xt_throw(self); + xt_close_file(self, of); + of = NULL; + if (!xres_check_checksum(res_1_buffer, res_1_size)) { + xt_free(self, res_1_buffer); + res_1_buffer = NULL; + } + } + + xres_name(PATH_MAX, path, 2); + if ((of = xt_open_file(self, path, XT_FS_MISSING_OK))) { + size_t res_2_size; + + res_2_size = (size_t) xt_seek_eof_file(self, of); + res_2_buffer = (XTXlogCheckpointDPtr) xt_malloc(self, res_2_size); + if (!xt_pread_file(of, 0, res_2_size, res_2_size, res_2_buffer, NULL, &self->st_statistics.st_x, self)) + xt_throw(self); + xt_close_file(self, of); + of = NULL; + if (!xres_check_checksum(res_2_buffer, res_2_size)) { + xt_free(self, res_2_buffer); + res_2_buffer = NULL; + } + } + + if (res_1_buffer && res_2_buffer) { + if (xt_comp_log_pos( + XT_GET_DISK_4(res_1_buffer->xcp_log_id_4), + XT_GET_DISK_6(res_1_buffer->xcp_log_offs_6), + XT_GET_DISK_4(res_2_buffer->xcp_log_id_4), + XT_GET_DISK_6(res_2_buffer->xcp_log_offs_6)) > 0) { + /* The first log is the further along than the second: */ + xt_free(self, res_2_buffer); + res_2_buffer = NULL; + } + else { + if (XT_GET_DISK_6(res_1_buffer->xcp_chkpnt_no_6) > + XT_GET_DISK_6(res_2_buffer->xcp_chkpnt_no_6)) { + xt_free(self, res_2_buffer); + res_2_buffer = NULL; + } + else { + xt_free(self, res_1_buffer); + res_1_buffer = NULL; + } + } + } + + if (res_1_buffer) { + use_buffer = res_1_buffer; + xres_next_res_no = 2; + } + else { + use_buffer = res_2_buffer; + xres_next_res_no = 1; + } + + /* Read the checkpoint data: */ + if (use_buffer) { + u_int no_of_logs; + xtLogID xt_log_id; + xtTableID xt_tab_id; + + xres_cp_number = XT_GET_DISK_6(use_buffer->xcp_chkpnt_no_6); + xres_cp_log_id = XT_GET_DISK_4(use_buffer->xcp_log_id_4); + xres_cp_log_offset = XT_GET_DISK_6(use_buffer->xcp_log_offs_6); + xt_tab_id = XT_GET_DISK_4(use_buffer->xcp_tab_id_4); + if (xt_tab_id > db->db_curr_tab_id) + db->db_curr_tab_id = xt_tab_id; + db->db_xn_curr_id = XT_GET_DISK_4(use_buffer->xcp_xact_id_4); + ind_rec_log_id = XT_GET_DISK_4(use_buffer->xcp_ind_rec_log_id_4); + ind_rec_log_offset = XT_GET_DISK_6(use_buffer->xcp_ind_rec_log_offs_6); + no_of_logs = XT_GET_DISK_2(use_buffer->xcp_log_count_2); + +#ifdef DEBUG_PRINT + printf("CHECKPOINT log=%d offset=%d ", (int) xres_cp_log_id, (int) xres_cp_log_offset); + if (no_of_logs) + printf("DELETED LOGS: "); +#endif + + /* Logs that are deleted are locked until _after_ the next + * checkpoint. + * + * To prevent the following problem from occuring: + * - Recovery is performed, and log X is deleted + * - After delete a log is free for re-use. + * New data is writen to log X. + * - Server crashes. + * - Recovery is performed from previous checkpoint, + * and log X is deleted again. + * + * To lock the logs the are placed on the deleted list. + * After the next checkpoint, all logs on this list + * will be removed. + */ + for (u_int i=0; i<no_of_logs; i++) { + xt_log_id = (xtLogID) XT_GET_DISK_2(use_buffer->xcp_del_log[i]); +#ifdef DEBUG_PRINT + if (i != 0) + printf(", "); + printf("%d", (int) xt_log_id); +#endif +#ifdef DEBUG_KEEP_LOGS + xt_dl_set_to_delete(self, db, xt_log_id); +#else + if (!xres_delete_data_log(db, xt_log_id)) + xt_throw(self); +#endif + } + +#ifdef DEBUG_PRINT + printf("\n"); +#endif + } + else { + /* Try to determine the correct start point. */ + xres_cp_number = 0; + xres_cp_log_id = xt_xlog_get_min_log(self, db); + xres_cp_log_offset = 0; + ind_rec_log_id = xres_cp_log_id; + ind_rec_log_offset = xres_cp_log_offset; + +#ifdef DEBUG_PRINT + printf("CHECKPOINT log=1 offset=0\n"); +#endif + } + + if (res_1_buffer) { + xt_free(self, res_1_buffer); + res_1_buffer = NULL; + } + if (res_2_buffer) { + xt_free(self, res_2_buffer); + res_2_buffer = NULL; + } + + if (!xres_restart(self, log_id, log_offset, ind_rec_log_id, ind_rec_log_offset, max_log_id)) + xt_throw(self); + } + catch_(a) { + self->st_database = NULL; + if (of) + xt_close_file(self, of); + if (res_1_buffer) + xt_free(self, res_1_buffer); + if (res_2_buffer) + xt_free(self, res_2_buffer); + xres_exit(self); + throw_(); + } + cont_(a); + self->st_database = NULL; + + exit_(); +} + +void XTXactRestart::xres_exit(XTThreadPtr self __attribute__((unused))) +{ +} + +void XTXactRestart::xres_name(size_t size, char *path, xtLogID log_id) +{ + char name[50]; + + sprintf(name, "restart-%lu.xt", (u_long) log_id); + xt_strcpy(size, path, xres_db->db_main_path); + xt_add_system_dir(size, path); + xt_add_dir_char(size, path); + xt_strcat(size, path, name); +} + +xtBool XTXactRestart::xres_check_checksum(XTXlogCheckpointDPtr buffer, size_t size) +{ + size_t head_size; + + /* The minimum size: */ + if (size < offsetof(XTXlogCheckpointDRec, xcp_head_size_4) + 4) + return FAILED; + + /* Check the sizes: */ + head_size = XT_GET_DISK_4(buffer->xcp_head_size_4); + if (size < head_size) + return FAILED; + + if (XT_GET_DISK_2(buffer->xcp_checksum_2) != xt_get_checksum(((xtWord1 *) buffer) + 2, size - 2, 1)) + return FAILED; + + if (XT_GET_DISK_2(buffer->xcp_version_2) != XT_CHECKPOINT_VERSION) + return FAILED; + + return OK; +} + +void XTXactRestart::xres_recover_progress(XTThreadPtr self, XTOpenFilePtr *of, int perc) +{ +#ifdef XT_USE_GLOBAL_DB + if (!perc) { + char file_path[PATH_MAX]; + + xt_strcpy(PATH_MAX, file_path, xres_db->db_main_path); + xt_add_pbxt_file(PATH_MAX, file_path, "recovery-progress"); + *of = xt_open_file(self, file_path, XT_FS_CREATE | XT_FS_MAKE_PATH); + xt_set_eof_file(self, *of, 0); + } + + if (perc > 100) { + char file_path[PATH_MAX]; + + if (*of) { + xt_close_file(self, *of); + *of = NULL; + } + xt_strcpy(PATH_MAX, file_path, xres_db->db_main_path); + xt_add_pbxt_file(PATH_MAX, file_path, "recovery-progress"); + if (xt_fs_exists(file_path)) + xt_fs_delete(self, file_path); + } + else { + char number[40]; + + sprintf(number, "%d", perc); + if (!xt_pwrite_file(*of, 0, strlen(number), number, &self->st_statistics.st_x, self)) + xt_throw(self); + if (!xt_flush_file(*of, &self->st_statistics.st_x, self)) + xt_throw(self); + } +#endif +} + +xtBool XTXactRestart::xres_restart(XTThreadPtr self, xtLogID *log_id, xtLogOffset *log_offset, xtLogID ind_rec_log_id, xtLogOffset ind_rec_log_offset, xtLogID *max_log_id) +{ + xtBool ok = TRUE; + XTDatabaseHPtr db = xres_db; + XTXactLogBufferDPtr record; + xtXactID xn_id; + XTXactDataPtr xact; + xtTableID tab_id; + XTWriterStateRec ws; + off_t bytes_read = 0; + off_t bytes_to_read; + volatile xtBool print_progress = FALSE; + volatile off_t perc_size = 0, next_goal = 0; + int perc_complete = 1; + XTOpenFilePtr progress_file = NULL; + xtBool min_ram_xn_id_set = FALSE; + u_int log_count; + + memset(&ws, 0, sizeof(ws)); + + ws.ws_db = db; + ws.ws_in_recover = TRUE; + ws.ws_ind_rec_log_id = ind_rec_log_id; + ws.ws_ind_rec_log_offset = ind_rec_log_offset; + + /* Initialize the data log buffer (required if extended data is + * referenced). + * Note: this buffer is freed later. It is part of the thread + * "open database" state, and this means that a thread + * may not have another database open (in use) when + * it calls this functions. + */ + self->st_dlog_buf.dlb_init(db, xt_db_log_buffer_size); + + if (!db->db_xlog.xlog_seq_init(&ws.ws_seqread, xt_db_log_buffer_size, TRUE)) + return FAILED; + + bytes_to_read = xres_bytes_to_read(self, db, &log_count, max_log_id); + /* Don't print anything about recovering an empty database: */ + if (bytes_to_read != 0) + xt_logf(XT_NT_INFO, "PBXT: Recovering from %lu-%llu, bytes to read: %llu\n", (u_long) xres_cp_log_id, (u_llong) xres_cp_log_offset, (u_llong) bytes_to_read); + if (bytes_to_read >= 10*1024*1024) { + print_progress = TRUE; + perc_size = bytes_to_read / 100; + next_goal = perc_size; + xres_recover_progress(self, &progress_file, 0); + } + + if (!db->db_xlog.xlog_seq_start(&ws.ws_seqread, xres_cp_log_id, xres_cp_log_offset, FALSE)) { + ok = FALSE; + goto failed; + } + + try_(a) { + for (;;) { + if (!db->db_xlog.xlog_seq_next(&ws.ws_seqread, &record, TRUE, self)) { + ok = FALSE; + break; + } + /* Increment before. If record is NULL then xseq_record_len will be zero, + * UNLESS the last record was of type XT_LOG_ENT_END_OF_LOG + * which fills the log to align to block of size 512. + */ + bytes_read += ws.ws_seqread.xseq_record_len; + if (!record) + break; +#ifdef PRINT_LOG_ON_RECOVERY + xt_print_log_record(ws.ws_seqread.xseq_rec_log_id, ws.ws_seqread.xseq_rec_log_offset, record); +#endif + if (print_progress && bytes_read > next_goal) { + if (((perc_complete - 1) % 25) == 0) + xt_logf(XT_NT_INFO, "PBXT: "); + if ((perc_complete % 25) == 0) + xt_logf(XT_NT_INFO, "%2d\n", (int) perc_complete); + else + xt_logf(XT_NT_INFO, "%2d ", (int) perc_complete); + xt_log_flush(self); + xres_recover_progress(self, &progress_file, perc_complete); + next_goal += perc_size; + perc_complete++; + } + switch (record->xl.xl_status_1) { + case XT_LOG_ENT_HEADER: + break; + case XT_LOG_ENT_NEW_LOG: { + /* Adjust the bytes read for the fact that logs are written + * on 512 byte boundaries. + */ + off_t offs, eof = ws.ws_seqread.xseq_log_eof; + + offs = ws.ws_seqread.xseq_rec_log_offset + ws.ws_seqread.xseq_record_len; + if (eof > offs) + bytes_read += eof - offs; + if (!db->db_xlog.xlog_seq_start(&ws.ws_seqread, XT_GET_DISK_4(record->xl.xl_log_id_4), 0, TRUE)) + xt_throw(self); + break; + } + case XT_LOG_ENT_NEW_TAB: + tab_id = XT_GET_DISK_4(record->xt.xt_tab_id_4); + if (tab_id > db->db_curr_tab_id) + db->db_curr_tab_id = tab_id; + break; + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_DELETE_BG: + xn_id = XT_GET_DISK_4(record->xu.xu_xact_id_4); + goto start_xact; + case XT_LOG_ENT_UPDATE_FL_BG: + case XT_LOG_ENT_INSERT_FL_BG: + case XT_LOG_ENT_DELETE_FL_BG: + xn_id = XT_GET_DISK_4(record->xf.xf_xact_id_4); + start_xact: + if (xt_xn_is_before(db->db_xn_curr_id, xn_id)) + db->db_xn_curr_id = xn_id; + + if (!(xact = xt_xn_add_old_xact(db, xn_id, self))) + xt_throw(self); + + xact->xd_begin_log = ws.ws_seqread.xseq_rec_log_id; + xact->xd_begin_offset = ws.ws_seqread.xseq_rec_log_offset; + + xact->xd_end_xn_id = xn_id; + xact->xd_end_time = db->db_xn_end_time; + xact->xd_flags = (XT_XN_XAC_LOGGED | XT_XN_XAC_ENDED | XT_XN_XAC_RECOVERED | XT_XN_XAC_SWEEP); + + /* This may affect the "minimum RAM transaction": */ + if (!min_ram_xn_id_set || xt_xn_is_before(xn_id, db->db_xn_min_ram_id)) { + min_ram_xn_id_set = TRUE; + db->db_xn_min_ram_id = xn_id; + } + xt_xres_apply_in_order(self, &ws, ws.ws_seqread.xseq_rec_log_id, ws.ws_seqread.xseq_rec_log_offset, record); + break; + case XT_LOG_ENT_COMMIT: + case XT_LOG_ENT_ABORT: + xn_id = XT_GET_DISK_4(record->xe.xe_xact_id_4); + if ((xact = xt_xn_get_xact(db, xn_id, self))) { + xact->xd_end_xn_id = xn_id; + xact->xd_flags |= XT_XN_XAC_ENDED | XT_XN_XAC_SWEEP; + xact->xd_flags &= ~XT_XN_XAC_RECOVERED; // We can expect an end record on cleanup! + if (record->xl.xl_status_1 == XT_LOG_ENT_COMMIT) + xact->xd_flags |= XT_XN_XAC_COMMITTED; + } + break; + case XT_LOG_ENT_CLEANUP: + /* The transaction was cleaned up: */ + xn_id = XT_GET_DISK_4(record->xc.xc_xact_id_4); + xt_xn_delete_xact(db, xn_id, self); + break; + case XT_LOG_ENT_OP_SYNC: + xres_sync_operations(self, db, &ws); + break; + case XT_LOG_ENT_DEL_LOG: + xtLogID rec_log_id; + + rec_log_id = XT_GET_DISK_4(record->xl.xl_log_id_4); + xt_dl_set_to_delete(self, db, rec_log_id); + break; + default: + xt_xres_apply_in_order(self, &ws, ws.ws_seqread.xseq_rec_log_id, ws.ws_seqread.xseq_rec_log_offset, record); + break; + } + } + + if (xres_sync_operations(self, db, &ws)) { + XTactOpSyncEntryDRec op_sync; + time_t now = time(NULL); + + op_sync.os_status_1 = XT_LOG_ENT_OP_SYNC; + op_sync.os_checksum_1 = XT_CHECKSUM_1(now) ^ XT_CHECKSUM_1(ws.ws_seqread.xseq_rec_log_id); + XT_SET_DISK_4(op_sync.os_time_4, (xtWord4) now); + /* TODO: If this is done, check to see that + * the byte written here are read back by the writter. + * This is in order to be in sync with 'xl_log_bytes_written'. + * i.e. xl_log_bytes_written == xl_log_bytes_read + */ + if (!db->db_xlog.xlog_write_thru(&ws.ws_seqread, sizeof(XTactOpSyncEntryDRec), (xtWord1 *) &op_sync, self)) + xt_throw(self); + } + } + catch_(a) { + ok = FALSE; + } + cont_(a); + + if (ok) { + if (print_progress) { + while (perc_complete <= 100) { + if (((perc_complete - 1) % 25) == 0) + xt_logf(XT_NT_INFO, "PBXT: "); + if ((perc_complete % 25) == 0) + xt_logf(XT_NT_INFO, "%2d\n", (int) perc_complete); + else + xt_logf(XT_NT_INFO, "%2d ", (int) perc_complete); + xt_log_flush(self); + xres_recover_progress(self, &progress_file, perc_complete); + perc_complete++; + } + } + if (bytes_to_read != 0) + xt_logf(XT_NT_INFO, "PBXT: Recovering complete at %lu-%llu, bytes read: %llu\n", (u_long) ws.ws_seqread.xseq_rec_log_id, (u_llong) ws.ws_seqread.xseq_rec_log_offset, (u_llong) bytes_read); + + *log_id = ws.ws_seqread.xseq_rec_log_id; + *log_offset = ws.ws_seqread.xseq_rec_log_offset; + + if (!min_ram_xn_id_set) + /* This is true because if no transaction was placed in RAM then + * the next transaction in RAM will have the next ID: */ + db->db_xn_min_ram_id = db->db_xn_curr_id + 1; + } + + failed: + xt_free_writer_state(self, &ws); + self->st_dlog_buf.dlb_exit(self); + xres_recover_progress(self, &progress_file, 101); + return ok; +} + +xtBool XTXactRestart::xres_is_checkpoint_pending(xtLogID curr_log_id, xtLogOffset curr_log_offset) +{ + return xt_bytes_since_last_checkpoint(xres_db, curr_log_id, curr_log_offset) >= xt_db_checkpoint_frequency / 2; +} + +/* + * Calculate the bytes to be read for recovery. + * This is only an estimate of the number of bytes that + * will be read. + */ +off_t XTXactRestart::xres_bytes_to_read(XTThreadPtr self, XTDatabaseHPtr db, u_int *log_count, xtLogID *max_log_id) +{ + off_t to_read = 0, eof; + xtLogID log_id = xres_cp_log_id; + char log_path[PATH_MAX]; + XTOpenFilePtr of; + XTXactLogHeaderDRec log_head; + size_t head_size; + size_t red_size; + + *max_log_id = log_id; + *log_count = 0; + for (;;) { + db->db_xlog.xlog_name(PATH_MAX, log_path, log_id); + of = NULL; + if (!xt_open_file_ns(&of, log_path, XT_FS_MISSING_OK)) + xt_throw(self); + if (!of) + break; + pushr_(xt_close_file, of); + + /* Check the first record of the log, to see if it is valid. */ + if (!xt_pread_file(of, 0, sizeof(XTXactLogHeaderDRec), 0, (xtWord1 *) &log_head, &red_size, &self->st_statistics.st_xlog, self)) + xt_throw(self); + /* The minimum size (old log size): */ + if (red_size < XT_MIN_LOG_HEAD_SIZE) + goto done; + head_size = XT_GET_DISK_4(log_head.xh_size_4); + if (log_head.xh_status_1 != XT_LOG_ENT_HEADER) + goto done; + if (log_head.xh_checksum_1 != XT_CHECKSUM_1(log_id)) + goto done; + if (XT_LOG_HEAD_MAGIC(&log_head, head_size) != XT_LOG_FILE_MAGIC) + goto done; + if (head_size > offsetof(XTXactLogHeaderDRec, xh_log_id_4) + 4) { + if (XT_GET_DISK_4(log_head.xh_log_id_4) != log_id) + goto done; + } + if (head_size > offsetof(XTXactLogHeaderDRec, xh_version_2) + 4) { + if (XT_GET_DISK_2(log_head.xh_version_2) > XT_LOG_VERSION_NO) + xt_throw_ulxterr(XT_CONTEXT, XT_ERR_NEW_TYPE_OF_XLOG, (u_long) log_id); + } + + eof = xt_seek_eof_file(self, of); + freer_(); // xt_close_file(of) + if (log_id == xres_cp_log_id) + to_read += (eof - xres_cp_log_offset); + else + to_read += eof; + (*log_count)++; + *max_log_id = log_id; + log_id++; + } + return to_read; + + done: + freer_(); // xt_close_file(of) + return to_read; +} + + +/* ---------------------------------------------------------------------- + * C H E C K P O I N T P R O C E S S + */ + +typedef enum XTFileType { + XT_FT_RECROW_FILE, + XT_FT_INDEX_FILE +} XTFileType; + +typedef struct XTDirtyFile { + xtTableID df_tab_id; + XTFileType df_file_type; +} XTDirtyFileRec, *XTDirtyFilePtr; + +#define XT_MAX_FLUSH_FILES 200 +#define XT_FLUSH_THRESHOLD (2 * 1024 * 1024) + +/* Sort files to be flused. */ +#ifdef USE_LATER +static void xres_cp_flush_files(XTThreadPtr self, XTDatabaseHPtr db) +{ + u_int edx; + XTTableEntryPtr te; + XTDirtyFileRec flush_list[XT_MAX_FLUSH_FILES]; + u_int file_count = 0; + XTIndexPtr *iptr; + u_int dirty_blocks; + XTOpenTablePtr ot; + XTTableHPtr tab; + + retry: + xt_enum_tables_init(&edx); + xt_ht_lock(self, db->db_tables); + pushr_(xt_ht_unlock, db->db_tables); + while (file_count < XT_MAX_FLUSH_FILES && + (te = xt_enum_tables_next(self, db, &edx))) { + if ((tab = te->te_table)) { + if (tab->tab_bytes_to_flush >= XT_FLUSH_THRESHOLD) { + flush_list[file_count].df_tab_id = te->te_tab_id; + flush_list[file_count].df_file_type = XT_FT_RECROW_FILE; + file_count++; + } + if (file_count == XT_MAX_FLUSH_FILES) + break; + iptr = tab->tab_dic.dic_keys; + dirty_blocks = 0; + for (u_int i=0;i<tab->tab_dic.dic_key_count; i++) { + dirty_blocks += (*iptr)->mi_dirty_blocks; + iptr++; + } + if ((dirty_blocks * XT_INDEX_PAGE_SIZE) >= XT_FLUSH_THRESHOLD) { + flush_list[file_count].df_tab_id = te->te_tab_id; + flush_list[file_count].df_file_type = XT_FT_INDEX_FILE; + file_count++; + } + } + } + freer_(); // xt_ht_unlock(db->db_tables) + + for (u_int i=0;i<file_count && !self->t_quit; i++) { + /* We want to flush about once a second: */ + xt_sleep_milli_second(400); + if ((ot = xt_db_open_pool_table(self, db, flush_list[i].df_tab_id, NULL, TRUE))) { + pushr_(xt_db_return_table_to_pool, ot); + + if (flush_list[i].df_file_type == XT_FT_RECROW_FILE) { + if (!xt_flush_record_row(ot, NULL)) + xt_throw(self); + } + else { + if (!xt_flush_indices(ot, NULL)) + xt_throw(self); + } + + freer_(); // xt_db_return_table_to_pool(ot) + } + } + + if (file_count == 100) + goto retry; +} +#endif + +#ifdef xxx +void XTXactRestart::xres_checkpoint_pending(xtLogID log_id, xtLogOffset log_offset) +{ +#ifdef TRACE_CHECKPOINT_ACTIVITY + xtBool tmp = xres_cp_pending; +#endif + xres_cp_pending = xres_is_checkpoint_pending(log_id, log_offset); +#ifdef TRACE_CHECKPOINT_ACTIVITY + if (tmp) { + if (!xres_cp_pending) + printf("%s xres_cp_pending = FALSE\n", xt_get_self()->t_name); + } + else { + if (xres_cp_pending) + printf("%s xres_cp_pending = TRUE\n", xt_get_self()->t_name); + } +#endif +} + + + xres_checkpoint_pending(); + + if (!xres_cp_required && + !xres_cp_pending && + xt_sl_get_size(db->db_datalogs.dlc_to_delete) == 0 && + xt_sl_get_size(db->db_datalogs.dlc_deleted) == 0) + return FALSE; +#endif + +#ifdef NEVER_CHECKPOINT +xtBool no_checkpoint = TRUE; +#endif + +#define XT_CHECKPOINT_IF_NO_ACTIVITY 0 +#define XT_CHECKPOINT_PAUSE_IF_ACTIVITY 1 +#define XT_CHECKPOINT_NO_PAUSE 2 + +/* + * This function performs table flush, as long as the system is idle. + */ +static xtBool xres_cp_checkpoint(XTThreadPtr self, XTDatabaseHPtr db, u_int curr_writer_total, xtBool force_checkpoint) +{ + XTCheckPointStatePtr cp = &db->db_cp_state; + XTOpenTablePtr ot; + XTCheckPointTablePtr to_flush_ptr; + XTCheckPointTableRec to_flush; + u_int table_count = 0; + xtBool checkpoint_done; + off_t bytes_flushed = 0; + int check_type; + +#ifdef NEVER_CHECKPOINT + if (no_checkpoint) + return FALSE; +#endif + if (force_checkpoint) { + if (db->db_restart.xres_cp_required) + check_type = XT_CHECKPOINT_NO_PAUSE; + else + check_type = XT_CHECKPOINT_PAUSE_IF_ACTIVITY; + } + else + check_type = XT_CHECKPOINT_IF_NO_ACTIVITY; + + to_flush.cpt_tab_id = 0; + to_flush.cpt_flushed = 0; + + /* Start a checkpoint: */ + if (!xt_begin_checkpoint(db, FALSE, self)) + xt_throw(self); + + while (!self->t_quit) { + xt_lock_mutex_ns(&cp->cp_state_lock); + table_count = 0; + if (cp->cp_table_ids) + table_count = xt_sl_get_size(cp->cp_table_ids); + if (!cp->cp_running || cp->cp_flush_count >= table_count) { + xt_unlock_mutex_ns(&cp->cp_state_lock); + break; + } + if (cp->cp_next_to_flush > table_count) + cp->cp_next_to_flush = 0; + + to_flush_ptr = (XTCheckPointTablePtr) xt_sl_item_at(cp->cp_table_ids, cp->cp_next_to_flush); + if (to_flush_ptr) + to_flush = *to_flush_ptr; + xt_unlock_mutex_ns(&cp->cp_state_lock); + + if (to_flush_ptr) { + if ((ot = xt_db_open_pool_table(self, db, to_flush.cpt_tab_id, NULL, TRUE))) { + pushr_(xt_db_return_table_to_pool, ot); + + if (!(to_flush.cpt_flushed & XT_CPT_REC_ROW_FLUSHED)) { + if (!xt_flush_record_row(ot, &bytes_flushed, FALSE)) + xt_throw(self); + } + + xt_lock_mutex_ns(&cp->cp_state_lock); + to_flush_ptr = NULL; + if (cp->cp_running) + to_flush_ptr = (XTCheckPointTablePtr) xt_sl_item_at(cp->cp_table_ids, cp->cp_next_to_flush); + if (to_flush_ptr) + to_flush = *to_flush_ptr; + xt_unlock_mutex_ns(&cp->cp_state_lock); + + if (to_flush_ptr && !self->t_quit) { + if (!(to_flush.cpt_flushed & XT_CPT_INDEX_FLUSHED)) { + switch (check_type) { + case XT_CHECKPOINT_IF_NO_ACTIVITY: + if (bytes_flushed > 0 && curr_writer_total != db->db_xn_total_writer_count) { + freer_(); // xt_db_return_table_to_pool(ot) + goto end_checkpoint; + } + break; + case XT_CHECKPOINT_PAUSE_IF_ACTIVITY: + if (bytes_flushed > 2 * 1024 * 1024 && curr_writer_total != db->db_xn_total_writer_count) { + curr_writer_total = db->db_xn_total_writer_count; + bytes_flushed = 0; + xt_sleep_milli_second(400); + } + break; + case XT_CHECKPOINT_NO_PAUSE: + break; + } + + if (!self->t_quit) { + if (!xt_flush_indices(ot, &bytes_flushed, FALSE)) + xt_throw(self); + to_flush.cpt_flushed |= XT_CPT_INDEX_FLUSHED; + } + } + } + + freer_(); // xt_db_return_table_to_pool(ot) + } + + if ((to_flush.cpt_flushed & XT_CPT_ALL_FLUSHED) == XT_CPT_ALL_FLUSHED) + cp->cp_next_to_flush++; + } + else + cp->cp_next_to_flush++; + + if (self->t_quit) + break; + + switch (check_type) { + case XT_CHECKPOINT_IF_NO_ACTIVITY: + if (bytes_flushed > 0 && curr_writer_total != db->db_xn_total_writer_count) + goto end_checkpoint; + break; + case XT_CHECKPOINT_PAUSE_IF_ACTIVITY: + if (bytes_flushed > 2 * 1024 * 1024 && curr_writer_total != db->db_xn_total_writer_count) { + curr_writer_total = db->db_xn_total_writer_count; + bytes_flushed = 0; + xt_sleep_milli_second(400); + } + break; + case XT_CHECKPOINT_NO_PAUSE: + break; + } + } + + end_checkpoint: + if (!xt_end_checkpoint(db, self, &checkpoint_done)) + xt_throw(self); + return checkpoint_done; +} + + +/* Wait for the log writer to tell us to do something. + */ +static void xres_cp_wait_for_log_writer(XTThreadPtr self, XTDatabaseHPtr db, u_long milli_secs) +{ + xt_lock_mutex(self, &db->db_cp_lock); + pushr_(xt_unlock_mutex, &db->db_cp_lock); + if (!self->t_quit) + xt_timed_wait_cond(self, &db->db_cp_cond, &db->db_cp_lock, milli_secs); + freer_(); // xt_unlock_mutex(&db->db_cp_lock) +} + +/* + * This is the way checkpoint works: + * + * To write a checkpoint we need to flush all tables in + * the database. + * + * Before flushing the first table we get the checkpoint + * log position. + * + * After flushing all files we write of the checkpoint + * log position. + */ +static void xres_cp_main(XTThreadPtr self) +{ + XTDatabaseHPtr db = self->st_database; + u_int curr_writer_total; + time_t now; + + xt_set_low_priority(self); + + + while (!self->t_quit) { + /* Wait 2 seconds: */ + curr_writer_total = db->db_xn_total_writer_count; + xt_db_approximate_time = time(NULL); + now = xt_db_approximate_time; + while (!self->t_quit && xt_db_approximate_time < now + 2 && !db->db_restart.xres_cp_required) { + xres_cp_wait_for_log_writer(self, db, 400); + xt_db_approximate_time = time(NULL); + xt_db_free_unused_open_tables(self, db); + } + + if (self->t_quit) + break; + + if (curr_writer_total == db->db_xn_total_writer_count) + /* No activity in 2 seconds: */ + xres_cp_checkpoint(self, db, curr_writer_total, FALSE); + else { + /* There server is busy, check if we need to + * write a checkpoint anyway... + */ + if (db->db_restart.xres_cp_required || + db->db_restart.xres_is_checkpoint_pending(db->db_xlog.xl_write_log_id, db->db_xlog.xl_write_log_offset)) { + /* Flush tables, until the checkpoint is complete. */ + xres_cp_checkpoint(self, db, curr_writer_total, TRUE); + } + } + + if (curr_writer_total == db->db_xn_total_writer_count) { + /* We did a checkpoint, and still, nothing has + * happened.... + * + * Wait for something to happen: + */ + xtLogID log_id; + xtLogOffset log_offset; + + while (!self->t_quit && curr_writer_total == db->db_xn_total_writer_count) { + /* The writer position: */ + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + log_id = db->db_wr_log_id; + log_offset = db->db_wr_log_offset; + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + + /* This condition means we could checkpoint: */ + if (!(xt_sl_get_size(db->db_datalogs.dlc_to_delete) == 0 && + xt_sl_get_size(db->db_datalogs.dlc_deleted) == 0 && + xt_comp_log_pos(log_id, log_offset, db->db_restart.xres_cp_log_id, db->db_restart.xres_cp_log_offset) <= 0)) + break; + + xres_cp_wait_for_log_writer(self, db, 400); + xt_db_approximate_time = time(NULL); + xt_db_free_unused_open_tables(self, db); + } + } + } +} + +static void *xres_cp_run_thread(XTThreadPtr self) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) self->t_data; + int count; + void *mysql_thread; + + mysql_thread = myxt_create_thread(); + + while (!self->t_quit) { + try_(a) { + /* + * The garbage collector requires that the database + * is in use because. + */ + xt_use_database(self, db, XT_FOR_CHECKPOINTER); + + /* This action is both safe and required (see details elsewhere) */ + xt_heap_release(self, self->st_database); + + xres_cp_main(self); + } + catch_(a) { + /* This error is "normal"! */ + if (self->t_exception.e_xt_err != XT_ERR_NO_DICTIONARY && + !(self->t_exception.e_xt_err == XT_SIGNAL_CAUGHT && + self->t_exception.e_sys_err == SIGTERM)) + xt_log_and_clear_exception(self); + } + cont_(a); + + /* Avoid releasing the database (done above) */ + self->st_database = NULL; + xt_unuse_database(self, self); + + /* After an exception, pause before trying again... */ + /* Number of seconds */ + count = 60; + while (!self->t_quit && count > 0) { + sleep(1); + count--; + } + } + + myxt_destroy_thread(mysql_thread, TRUE); + return NULL; +} + +static void xres_cp_free_thread(XTThreadPtr self, void *data) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) data; + + if (db->db_cp_thread) { + xt_lock_mutex(self, &db->db_cp_lock); + pushr_(xt_unlock_mutex, &db->db_cp_lock); + db->db_cp_thread = NULL; + freer_(); // xt_unlock_mutex(&db->db_cp_lock) + } +} + +/* Start a checkpoint, if none has been started. */ +xtPublic xtBool xt_begin_checkpoint(XTDatabaseHPtr db, xtBool have_table_lock, XTThreadPtr thread) +{ + XTCheckPointStatePtr cp = &db->db_cp_state; + xtLogID log_id; + xtLogOffset log_offset; + xtLogID ind_rec_log_id; + xtLogOffset ind_rec_log_offset; + u_int edx; + XTTableEntryPtr te_ptr; + XTTableHPtr tab; + XTOperationPtr op; + XTCheckPointTableRec cpt; + XTSortedListPtr tables = NULL; + + /* First check if a checkpoint is already running: */ + xt_lock_mutex_ns(&cp->cp_state_lock); + if (cp->cp_running) { + xt_unlock_mutex_ns(&cp->cp_state_lock); + return OK; + } + if (cp->cp_table_ids) { + xt_free_sortedlist(NULL, cp->cp_table_ids); + cp->cp_table_ids = NULL; + } + xt_unlock_mutex_ns(&cp->cp_state_lock); + + /* Flush the log before we continue. This is to ensure that + * before we write a checkpoint, that the changes + * done by the sweeper and the compactor, have been + * applied. + * + * Note, the sweeper does not flush the log, so this is + * necessary! + * + * --- I have removed this flush. It is actually just a + * minor optimisation, which pushes the flush position + * below ahead. + * + * Note that the writer position used for the checkpoint + * _will_ be behind the current log flush position. + * + * This is because the writer cannot apply log changes + * until they are flushed. + */ + /* This is an alternative to the above. + if (!xt_xlog_flush_log(self)) + xt_throw(self); + */ + xt_lock_mutex_ns(&db->db_wr_lock); + + /* The theoretical maximum restart log postion, is the + * position of the writer thread: + */ + log_id = db->db_wr_log_id; + log_offset = db->db_wr_log_offset; + + ind_rec_log_id = db->db_xlog.xl_flush_log_id; + ind_rec_log_offset = db->db_xlog.xl_flush_log_offset; + + xt_unlock_mutex_ns(&db->db_wr_lock); + + /* Go through all the transactions, and find + * the lowest log start position of all the transactions. + */ + for (u_int i=0; i<XT_XN_NO_OF_SEGMENTS; i++) { + XTXactSegPtr seg; + + seg = &db->db_xn_idx[i]; + XT_XACT_WRITE_LOCK(&seg->xs_tab_lock, self); + for (u_int j=0; j<XT_XN_HASH_TABLE_SIZE; j++) { + XTXactDataPtr xact; + + xact = seg->xs_table[j]; + while (xact) { + /* If the transaction is logged, but not cleaned: */ + if ((xact->xd_flags & (XT_XN_XAC_LOGGED | XT_XN_XAC_CLEANED)) == XT_XN_XAC_LOGGED) { + if (xt_comp_log_pos(log_id, log_offset, xact->xd_begin_log, xact->xd_begin_offset) > 0) { + log_id = xact->xd_begin_log; + log_offset = xact->xd_begin_offset; + } + } + xact = xact->xd_next_xact; + } + } + XT_XACT_UNLOCK(&seg->xs_tab_lock, self); + } + +#ifdef TRACE_CHECKPOINT + printf("BEGIN CHECKPOINT %d-%llu\n", (int) log_id, (u_llong) log_offset); +#endif + /* Go through all tables, and find the lowest log position. + * The log position stored by each table shows the position of + * the next operation that still needs to be applied. + * + * This comes from the list of operations which are + * queued for the table. + * + * This function also builds a list of tables! + */ + + if (!(tables = xt_new_sortedlist_ns(sizeof(XTCheckPointTableRec), 20, xres_comp_flush_tabs, NULL, NULL))) + return FAILED; + + xt_enum_tables_init(&edx); + if (!have_table_lock) + xt_ht_lock(NULL, db->db_tables); + while ((te_ptr = xt_enum_tables_next(NULL, db, &edx))) { + if ((tab = te_ptr->te_table)) { + xt_sl_lock_ns(tab->tab_op_list, thread); + if ((op = (XTOperationPtr) xt_sl_first_item(tab->tab_op_list))) { + if (xt_comp_log_pos(log_id, log_offset, op->or_log_id, op->or_log_offset) > 0) { + log_id = op->or_log_id; + log_offset = op->or_log_offset; + } + } + xt_sl_unlock(NULL, tab->tab_op_list); + cpt.cpt_flushed = 0; + cpt.cpt_tab_id = tab->tab_id; +#ifdef TRACE_CHECKPOINT + printf("to flush: %d %s\n", (int) tab->tab_id, tab->tab_name->ps_path); +#endif + if (!xt_sl_insert(NULL, tables, &tab->tab_id, &cpt)) { + if (!have_table_lock) + xt_ht_unlock(NULL, db->db_tables); + xt_free_sortedlist(NULL, tables); + return FAILED; + } + } + } + if (!have_table_lock) + xt_ht_unlock(NULL, db->db_tables); + + xt_lock_mutex_ns(&cp->cp_state_lock); + /* If there is a table list, then someone was faster than me! */ + if (!cp->cp_running && log_id && log_offset) { + cp->cp_running = TRUE; + cp->cp_log_id = log_id; + cp->cp_log_offset = log_offset; + + cp->cp_ind_rec_log_id = ind_rec_log_id; + cp->cp_ind_rec_log_offset = ind_rec_log_offset; + + cp->cp_flush_count = 0; + cp->cp_next_to_flush = 0; + cp->cp_table_ids = tables; + } + else + xt_free_sortedlist(NULL, tables); + xt_unlock_mutex_ns(&cp->cp_state_lock); + + /* At this point, log flushing can begin... */ + return OK; +} + +/* End a checkpoint, if a checkpoint has been started, + * and all checkpoint tables have been flushed + */ +xtPublic xtBool xt_end_checkpoint(XTDatabaseHPtr db, XTThreadPtr thread, xtBool *checkpoint_done) +{ + XTCheckPointStatePtr cp = &db->db_cp_state; + XTXlogCheckpointDPtr cp_buf = NULL; + char path[PATH_MAX]; + XTOpenFilePtr of; + u_int table_count; + size_t chk_size = 0; + u_int no_of_logs = 0; + +#ifdef NEVER_CHECKPOINT + return OK; +#endif + /* Lock the checkpoint state so that only on thread can do this! */ + xt_lock_mutex_ns(&cp->cp_state_lock); + if (!cp->cp_running) + goto checkpoint_done; + + table_count = 0; + if (cp->cp_table_ids) + table_count = xt_sl_get_size(cp->cp_table_ids); + if (cp->cp_flush_count < table_count) { + /* Checkpoint is not done, yet! */ + xt_unlock_mutex_ns(&cp->cp_state_lock); + if (checkpoint_done) + *checkpoint_done = FALSE; + return OK; + } + + /* Check if anything has changed since the last checkpoint, + * if not, there is no need to write a new checkpoint! + */ + if (xt_sl_get_size(db->db_datalogs.dlc_to_delete) == 0 && + xt_sl_get_size(db->db_datalogs.dlc_deleted) == 0 && + xt_comp_log_pos(cp->cp_log_id, cp->cp_log_offset, db->db_restart.xres_cp_log_id, db->db_restart.xres_cp_log_offset) <= 0) { + /* A checkpoint is required if the size of the deleted + * list is not zero. The reason is, I cannot remove the + * logs from the deleted list BEFORE a checkpoint has been + * done which does NOT include these logs. + * + * Even though the logs have already been deleted. They + * remain on the deleted list to ensure that they are NOT + * reused during this time, until the next checkpoint. + * + * This is done because if they are used, then on restart + * they would be deleted! + */ +#ifdef TRACE_CHECKPOINT + printf("--- END CHECKPOINT - no write\n"); +#endif + goto checkpoint_done; + } + +#ifdef TRACE_CHECKPOINT + printf("--- END CHECKPOINT - write start point\n"); +#endif + xt_lock_mutex_ns(&db->db_datalogs.dlc_lock); + + no_of_logs = xt_sl_get_size(db->db_datalogs.dlc_to_delete); + chk_size = offsetof(XTXlogCheckpointDRec, xcp_del_log) + no_of_logs * 2; + xtLogID *log_id_ptr; + + if (!(cp_buf = (XTXlogCheckpointDPtr) xt_malloc_ns(chk_size))) { + xt_unlock_mutex_ns(&db->db_datalogs.dlc_lock); + goto failed_0; + } + + /* Increment the checkpoint number. This value is used if 2 checkpoint have the + * same log number. In this case checkpoints may differ in the log files + * that should be deleted. Here it is important to use the most recent + * log file! + */ + db->db_restart.xres_cp_number++; + + /* Create the checkpoint record: */ + XT_SET_DISK_4(cp_buf->xcp_head_size_4, chk_size); + XT_SET_DISK_2(cp_buf->xcp_version_2, XT_CHECKPOINT_VERSION); + XT_SET_DISK_6(cp_buf->xcp_chkpnt_no_6, db->db_restart.xres_cp_number); + XT_SET_DISK_4(cp_buf->xcp_log_id_4, cp->cp_log_id); + XT_SET_DISK_6(cp_buf->xcp_log_offs_6, cp->cp_log_offset); + XT_SET_DISK_4(cp_buf->xcp_tab_id_4, db->db_curr_tab_id); + XT_SET_DISK_4(cp_buf->xcp_xact_id_4, db->db_xn_curr_id); + XT_SET_DISK_4(cp_buf->xcp_ind_rec_log_id_4, cp->cp_ind_rec_log_id); + XT_SET_DISK_6(cp_buf->xcp_ind_rec_log_offs_6, cp->cp_ind_rec_log_offset); + XT_SET_DISK_2(cp_buf->xcp_log_count_2, no_of_logs); + + for (u_int i=0; i<no_of_logs; i++) { + log_id_ptr = (xtLogID *) xt_sl_item_at(db->db_datalogs.dlc_to_delete, i); + XT_SET_DISK_2(cp_buf->xcp_del_log[i], (xtWord2) *log_id_ptr); + } + + XT_SET_DISK_2(cp_buf->xcp_checksum_2, xt_get_checksum(((xtWord1 *) cp_buf) + 2, chk_size - 2, 1)); + + xt_unlock_mutex_ns(&db->db_datalogs.dlc_lock); + + /* Write the checkpoint: */ + db->db_restart.xres_name(PATH_MAX, path, db->db_restart.xres_next_res_no); + if (!(of = xt_open_file_ns(path, XT_FS_CREATE | XT_FS_MAKE_PATH))) + goto failed_1; + + if (!xt_set_eof_file(NULL, of, 0)) + goto failed_2; + if (!xt_pwrite_file(of, 0, chk_size, (xtWord1 *) cp_buf, &thread->st_statistics.st_x, thread)) + goto failed_2; + if (!xt_flush_file(of, &thread->st_statistics.st_x, thread)) + goto failed_2; + + xt_close_file_ns(of); + + /* Next time write the other restart file: */ + db->db_restart.xres_next_res_no = (db->db_restart.xres_next_res_no % 2) + 1; + db->db_restart.xres_cp_log_id = cp->cp_log_id; + db->db_restart.xres_cp_log_offset = cp->cp_log_offset; + db->db_restart.xres_cp_required = FALSE; + + /* + * Remove all the data logs that were deleted on the + * last checkpoint: + */ + if (!xres_remove_data_logs(db)) + goto failed_0; + +#ifndef DEBUG_KEEP_LOGS + /* After checkpoint, we can delete transaction logs that will no longer be required + * for recovery... + */ + if (cp->cp_log_id > 1) { + xtLogID current_log_id = cp->cp_log_id; + xtLogID del_log_id; + +#ifdef XT_NUMBER_OF_LOGS_TO_SAVE + if (pbxt_crash_debug) { + /* To save the logs, we just consider them in use: */ + if (current_log_id > XT_NUMBER_OF_LOGS_TO_SAVE) + current_log_id -= XT_NUMBER_OF_LOGS_TO_SAVE; + else + current_log_id = 1; + } +#endif + + del_log_id = current_log_id - 1; + + while (del_log_id > 0) { + db->db_xlog.xlog_name(PATH_MAX, path, del_log_id); + if (!xt_fs_exists(path)) + break; + del_log_id--; + } + + /* This was the lowest log ID that existed: */ + del_log_id++; + + /* Delete all logs that still exist, that come before + * the current log: + * + * Do this from least to greatest to ensure no "holes" appear. + */ + while (del_log_id < current_log_id) { + switch (db->db_xlog.xlog_delete_log(del_log_id, thread)) { + case OK: + break; + case FAILED: + goto exit_loop; + case XT_ERR: + goto failed_0; + } + del_log_id++; + } + exit_loop:; + } + + /* And we can delete data logs in the list, and place them + * on the deleted list. + */ + xtLogID log_id; + for (u_int i=0; i<no_of_logs; i++) { + log_id = (xtLogID) XT_GET_DISK_2(cp_buf->xcp_del_log[i]); + if (!xres_delete_data_log(db, log_id)) + goto failed_0; + } +#endif + + xt_free_ns(cp_buf); + cp_buf = NULL; + + checkpoint_done: + cp->cp_running = FALSE; + if (cp->cp_table_ids) { + xt_free_sortedlist(NULL, cp->cp_table_ids); + cp->cp_table_ids = NULL; + } + cp->cp_flush_count = 0; + cp->cp_next_to_flush = 0; + db->db_restart.xres_cp_required = FALSE; + xt_unlock_mutex_ns(&cp->cp_state_lock); + if (checkpoint_done) + *checkpoint_done = TRUE; + return OK; + + failed_2: + xt_close_file_ns(of); + + failed_1: + xt_free_ns(cp_buf); + + failed_0: + if (cp_buf) + xt_free_ns(cp_buf); + xt_unlock_mutex_ns(&cp->cp_state_lock); + return FAILED; +} + +xtPublic xtWord8 xt_bytes_since_last_checkpoint(XTDatabaseHPtr db, xtLogID curr_log_id, xtLogOffset curr_log_offset) +{ + xtLogID log_id; + xtLogOffset log_offset; + size_t byte_count = 0; + + log_id = db->db_restart.xres_cp_log_id; + log_offset = db->db_restart.xres_cp_log_offset; + + /* Assume the logs have the threshold: */ + if (log_id < curr_log_id) { + if (log_offset < xt_db_log_file_threshold) + byte_count = (size_t) (xt_db_log_file_threshold - log_offset); + log_offset = 0; + log_id++; + } + while (log_id < curr_log_id) { + byte_count += (size_t) xt_db_log_file_threshold; + log_id++; + } + if (log_offset < curr_log_offset) + byte_count += (size_t) (curr_log_offset - log_offset); + + return byte_count; +} + +xtPublic void xt_start_checkpointer(XTThreadPtr self, XTDatabaseHPtr db) +{ + char name[PATH_MAX]; + + sprintf(name, "CP-%s", xt_last_directory_of_path(db->db_main_path)); + xt_remove_dir_char(name); + db->db_cp_thread = xt_create_daemon(self, name); + xt_set_thread_data(db->db_cp_thread, db, xres_cp_free_thread); + xt_run_thread(self, db->db_cp_thread, xres_cp_run_thread); +} + +xtPublic void xt_wait_for_checkpointer(XTThreadPtr self, XTDatabaseHPtr db) +{ + time_t then, now; + xtBool message = FALSE; + xtLogID log_id; + xtLogOffset log_offset; + + if (db->db_cp_thread) { + then = time(NULL); + for (;;) { + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + log_id = db->db_wr_log_id; + log_offset = db->db_wr_log_offset; + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + + if (xt_sl_get_size(db->db_datalogs.dlc_to_delete) == 0 && + xt_sl_get_size(db->db_datalogs.dlc_deleted) == 0 && + xt_comp_log_pos(log_id, log_offset, db->db_restart.xres_cp_log_id, db->db_restart.xres_cp_log_offset) <= 0) + break; + + /* Do a final checkpoint before shutdown: */ + db->db_restart.xres_cp_required = TRUE; + + xt_lock_mutex(self, &db->db_cp_lock); + pushr_(xt_unlock_mutex, &db->db_cp_lock); + if (!xt_broadcast_cond_ns(&db->db_cp_cond)) { + xt_log_and_clear_exception_ns(); + break; + } + freer_(); // xt_unlock_mutex(&db->db_cp_lock) + + xt_sleep_milli_second(10); + + now = time(NULL); + if (now >= then + 16) { + xt_logf(XT_NT_INFO, "Aborting wait for '%s' checkpointer\n", db->db_name); + message = FALSE; + break; + } + if (now >= then + 2) { + if (!message) { + message = TRUE; + xt_logf(XT_NT_INFO, "Waiting for '%s' checkpointer...\n", db->db_name); + } + } + } + + if (message) + xt_logf(XT_NT_INFO, "Checkpointer '%s' done.\n", db->db_name); + } +} + +xtPublic void xt_stop_checkpointer(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTThreadPtr thr_wr; + + if (db->db_cp_thread) { + xt_lock_mutex(self, &db->db_cp_lock); + pushr_(xt_unlock_mutex, &db->db_cp_lock); + + /* This pointer is safe as long as you have the transaction lock. */ + if ((thr_wr = db->db_cp_thread)) { + xtThreadID tid = thr_wr->t_id; + + /* Make sure the thread quits when woken up. */ + xt_terminate_thread(self, thr_wr); + + xt_wake_checkpointer(self, db); + + freer_(); // xt_unlock_mutex(&db->db_cp_lock) + + /* + * GOTCHA: This is a wierd thing but the SIGTERM directed + * at a particular thread (in this case the sweeper) was + * being caught by a different thread and killing the server + * sometimes. Disconcerting. + * (this may only be a problem on Mac OS X) + xt_kill_thread(thread); + */ + xt_wait_for_thread(tid, FALSE); + + /* PMC - This should not be necessary to set the signal here, but in the + * debugger the handler is not called!!? + thr_wr->t_delayed_signal = SIGTERM; + xt_kill_thread(thread); + */ + db->db_cp_thread = NULL; + } + else + freer_(); // xt_unlock_mutex(&db->db_cp_lock) + } +} + +xtPublic void xt_wake_checkpointer(XTThreadPtr self, XTDatabaseHPtr db) +{ + if (!xt_broadcast_cond_ns(&db->db_cp_cond)) + xt_log_and_clear_exception(self); +} + +xtPublic void xt_free_writer_state(struct XTThread *self, XTWriterStatePtr ws) +{ + if (ws->ws_db) + ws->ws_db->db_xlog.xlog_seq_exit(&ws->ws_seqread); + xt_db_set_size(self, &ws->ws_databuf, 0); + xt_ib_free(self, &ws->ws_rec_buf); + if (ws->ws_ot) { + xt_db_return_table_to_pool(self, ws->ws_ot); + ws->ws_ot = NULL; + } +} + +xtPublic void xt_dump_xlogs(XTDatabaseHPtr db, xtLogID start_log) +{ + XTXactSeqReadRec seq; + XTXactLogBufferDPtr record; + xtLogID log_id = db->db_restart.xres_cp_log_id; + char log_path[PATH_MAX]; + XTThreadPtr thread = xt_get_self(); + + /* Find the first log that still exists:*/ + for (;;) { + log_id--; + db->db_xlog.xlog_name(PATH_MAX, log_path, log_id); + if (!xt_fs_exists(log_path)) + break; + } + log_id++; + + if (!db->db_xlog.xlog_seq_init(&seq, xt_db_log_buffer_size, FALSE)) + return; + + if (log_id < start_log) + log_id = start_log; + + for (;;) { + db->db_xlog.xlog_name(PATH_MAX, log_path, log_id); + if (!xt_fs_exists(log_path)) + break; + + if (!db->db_xlog.xlog_seq_start(&seq, log_id, 0, FALSE)) + goto done; + + PRINTF("---------- DUMP LOG %d\n", (int) log_id); + for (;;) { + if (!db->db_xlog.xlog_seq_next(&seq, &record, TRUE, thread)) { + PRINTF("---------- DUMP LOG %d ERROR\n", (int) log_id); + xt_log_and_clear_exception_ns(); + break; + } + if (!record) { + PRINTF("---------- DUMP LOG %d DONE\n", (int) log_id); + break; + } + xt_print_log_record(seq.xseq_rec_log_id, seq.xseq_rec_log_offset, record); + } + + log_id++; + } + + done: + db->db_xlog.xlog_seq_exit(&seq); +} diff --git a/storage/pbxt/src/restart_xt.h b/storage/pbxt/src/restart_xt.h new file mode 100644 index 00000000000..259b3cbda90 --- /dev/null +++ b/storage/pbxt/src/restart_xt.h @@ -0,0 +1,134 @@ +/* Copyright (c) 2007 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2007-11-12 Paul McCullagh + * + * H&G2JCtL + * + * Restart and write data to the database. + */ + +#ifndef __restart_xt_h__ +#define __restart_xt_h__ + +#include "pthread_xt.h" +#include "filesys_xt.h" +#include "sortedlist_xt.h" +#include "util_xt.h" +#include "xactlog_xt.h" + +struct XTThread; +struct XTOpenTable; +struct XTDatabase; +struct XTTable; + +typedef struct XTWriterState { + struct XTDatabase *ws_db; + xtBool ws_in_recover; + xtLogID ws_ind_rec_log_id; + xtLogOffset ws_ind_rec_log_offset; + XTXactSeqReadRec ws_seqread; + XTDataBufferRec ws_databuf; + XTInfoBufferRec ws_rec_buf; + xtTableID ws_tab_gone; /* Cache the ID of the last table that does not exist. */ + struct XTOpenTable *ws_ot; +} XTWriterStateRec, *XTWriterStatePtr; + +#define XT_CHECKPOINT_VERSION 1 + +typedef struct XTXlogCheckpoint { + XTDiskValue2 xcp_checksum_2; /* The checksum of the all checkpoint data. */ + XTDiskValue4 xcp_head_size_4; + XTDiskValue2 xcp_version_2; /* The version of the checkpoint record. */ + XTDiskValue6 xcp_chkpnt_no_6; /* Incremented for each checkpoint. */ + XTDiskValue4 xcp_log_id_4; /* The restart log ID. */ + XTDiskValue6 xcp_log_offs_6; /* The restart log offset. */ + XTDiskValue4 xcp_tab_id_4; /* The current high table ID. */ + XTDiskValue4 xcp_xact_id_4; /* The current high transaction ID. */ + XTDiskValue4 xcp_ind_rec_log_id_4; /* The index recovery log ID. */ + XTDiskValue6 xcp_ind_rec_log_offs_6; /* The index recovery log offset. */ + XTDiskValue2 xcp_log_count_2; /* Number of logs to be deleted in the area below. */ + XTDiskValue2 xcp_del_log[XT_VAR_LENGTH]; +} XTXlogCheckpointDRec, *XTXlogCheckpointDPtr; + +typedef struct XTXactRestart { + struct XTDatabase *xres_db; + int xres_next_res_no; /* The next restart file to be written. */ + xtLogID xres_cp_log_id; /* Log number of the last checkpoint. */ + xtLogOffset xres_cp_log_offset; /* Log offset of the last checkpoint */ + xtBool xres_cp_required; /* Checkpoint required (startup and shutdown). */ + xtWord8 xres_cp_number; /* The checkpoint number (used to decide which is the latest checkpoint). */ + +public: + void xres_init(struct XTThread *self, struct XTDatabase *db, xtLogID *log_id, xtLogOffset *log_offset, xtLogID *max_log_id); + void xres_exit(struct XTThread *self); + xtBool xres_is_checkpoint_pending(xtLogID log_id, xtLogOffset log_offset); + void xres_checkpoint_pending(xtLogID log_id, xtLogOffset log_offset); + xtBool xres_checkpoint(struct XTThread *self); + void xres_name(size_t size, char *path, xtLogID log_id); + +private: + xtBool xres_check_checksum(XTXlogCheckpointDPtr buffer, size_t size); + void xres_recover_progress(XTThreadPtr self, XTOpenFilePtr *of, int perc); + xtBool xres_restart(struct XTThread *self, xtLogID *log_id, xtLogOffset *log_offset, xtLogID ind_rec_log_id, off_t ind_rec_log_offset, xtLogID *max_log_id); + off_t xres_bytes_to_read(struct XTThread *self, struct XTDatabase *db, u_int *log_count, xtLogID *max_log_id); +} XTXactRestartRec, *XTXactRestartPtr; + +typedef struct XTCheckPointState { + xt_mutex_type cp_state_lock; /* Lock and the entire checkpoint state. */ + xtBool cp_running; /* TRUE if a checkpoint is running. */ + xtLogID cp_log_id; + xtLogOffset cp_log_offset; + xtLogID cp_ind_rec_log_id; + xtLogOffset cp_ind_rec_log_offset; + XTSortedListPtr cp_table_ids; /* List of tables to be flushed for the checkpoint. */ + u_int cp_flush_count; /* The number of tables flushed. */ + u_int cp_next_to_flush; /* The next table to be flushed. */ +} XTCheckPointStateRec, *XTCheckPointStatePtr; + +#define XT_CPT_NONE_FLUSHED 0 +#define XT_CPT_REC_ROW_FLUSHED 1 +#define XT_CPT_INDEX_FLUSHED 2 +#define XT_CPT_ALL_FLUSHED (XT_CPT_REC_ROW_FLUSHED | XT_CPT_INDEX_FLUSHED) + +typedef struct XTCheckPointTable { + u_int cpt_flushed; + xtTableID cpt_tab_id; +} XTCheckPointTableRec, *XTCheckPointTablePtr; + +void xt_xres_init(struct XTThread *self, struct XTDatabase *db); +void xt_xres_exit(struct XTThread *self, struct XTDatabase *db); + +void xt_xres_init_tab(struct XTThread *self, struct XTTable *tab); +void xt_xres_exit_tab(struct XTThread *self, struct XTTable *tab); + +void xt_xres_apply_in_order(struct XTThread *self, XTWriterStatePtr ws, xtLogID log_id, xtLogOffset log_offset, XTXactLogBufferDPtr record); + +xtBool xt_begin_checkpoint(struct XTDatabase *db, xtBool have_table_lock, struct XTThread *thread); +xtBool xt_end_checkpoint(struct XTDatabase *db, struct XTThread *thread, xtBool *checkpoint_done); +void xt_start_checkpointer(struct XTThread *self, struct XTDatabase *db); +void xt_wait_for_checkpointer(struct XTThread *self, struct XTDatabase *db); +void xt_stop_checkpointer(struct XTThread *self, struct XTDatabase *db); +void xt_wake_checkpointer(struct XTThread *self, struct XTDatabase *db); +void xt_free_writer_state(struct XTThread *self, XTWriterStatePtr ws); +xtWord8 xt_bytes_since_last_checkpoint(struct XTDatabase *db, xtLogID curr_log_id, xtLogOffset curr_log_offset); + +void xt_print_log_record(xtLogID log, off_t offset, XTXactLogBufferDPtr record); +void xt_dump_xlogs(struct XTDatabase *db, xtLogID start_log); + +#endif diff --git a/storage/pbxt/src/sortedlist_xt.cc b/storage/pbxt/src/sortedlist_xt.cc new file mode 100644 index 00000000000..b4c525dbb22 --- /dev/null +++ b/storage/pbxt/src/sortedlist_xt.cc @@ -0,0 +1,352 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-02-04 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include "pthread_xt.h" +#include "thread_xt.h" +#include "sortedlist_xt.h" + +XTSortedListPtr xt_new_sortedlist_ns(u_int item_size, u_int grow_size, XTCompareFunc comp_func, void *thunk, XTFreeFunc free_func) +{ + XTSortedListPtr sl; + + if (!(sl = (XTSortedListPtr) xt_calloc_ns(sizeof(XTSortedListRec)))) + return NULL; + sl->sl_item_size = item_size; + sl->sl_grow_size = grow_size; + sl->sl_comp_func = comp_func; + sl->sl_thunk = thunk; + sl->sl_free_func = free_func; + sl->sl_current_size = 0; + return sl; +} + +XTSortedListPtr xt_new_sortedlist(XTThreadPtr self, u_int item_size, u_int initial_size, u_int grow_size, XTCompareFunc comp_func, void *thunk, XTFreeFunc free_func, xtBool with_lock, xtBool with_cond) +{ + XTSortedListPtr sl; + + sl = (XTSortedListPtr) xt_calloc(self, sizeof(XTSortedListRec)); + xt_init_sortedlist(self, sl, item_size, initial_size, grow_size, comp_func, thunk, free_func, with_lock, with_cond); + return sl; +} + +xtPublic void xt_init_sortedlist(XTThreadPtr self, XTSortedListPtr sl, u_int item_size, u_int initial_size, u_int grow_size, XTCompareFunc comp_func, void *thunk, XTFreeFunc free_func, xtBool with_lock, xtBool with_cond) +{ + sl->sl_item_size = item_size; + sl->sl_grow_size = grow_size; + sl->sl_comp_func = comp_func; + sl->sl_thunk = thunk; + sl->sl_free_func = free_func; + sl->sl_current_size = initial_size; + + if (initial_size) { + try_(a) { + sl->sl_data = (char *) xt_malloc(self, initial_size * item_size); + } + catch_(a) { + xt_free(self, sl); + throw_(); + } + cont_(a); + } + + if (with_lock || with_cond) { + sl->sl_lock = (xt_mutex_type *) xt_calloc(self, sizeof(xt_mutex_type)); + try_(b) { + xt_init_mutex_with_autoname(self, sl->sl_lock); + } + catch_(b) { + xt_free(self, sl->sl_lock); + sl->sl_lock = NULL; + xt_free_sortedlist(self, sl); + throw_(); + } + cont_(b); + } + + if (with_cond) { + sl->sl_cond = (xt_cond_type *) xt_calloc(self, sizeof(xt_cond_type)); + try_(c) { + xt_init_cond(self, sl->sl_cond); + } + catch_(c) { + xt_free(self, sl->sl_cond); + sl->sl_cond = NULL; + xt_free_sortedlist(self, sl); + throw_(); + } + cont_(c); + } +} + +xtPublic void xt_empty_sortedlist(XTThreadPtr self, XTSortedListPtr sl) +{ + if (sl->sl_lock) + xt_lock_mutex(self, sl->sl_lock); + if (sl->sl_data) { + while (sl->sl_usage_count > 0) { + sl->sl_usage_count--; + if (sl->sl_free_func) + (*sl->sl_free_func)(self, sl->sl_thunk, &sl->sl_data[sl->sl_usage_count * sl->sl_item_size]); + } + } + if (sl->sl_lock) + xt_unlock_mutex(self, sl->sl_lock); +} + +xtPublic void xt_free_sortedlist(XTThreadPtr self, XTSortedListPtr sl) +{ + xt_empty_sortedlist(self, sl); + if (sl->sl_data) { + xt_free(self, sl->sl_data); + sl->sl_data = NULL; + } + if (sl->sl_lock) { + xt_free_mutex(sl->sl_lock); + xt_free(self, sl->sl_lock); + } + if (sl->sl_cond) { + xt_free_cond(sl->sl_cond); + xt_free(self, sl->sl_cond); + } + xt_free(self, sl); +} + +xtPublic void *xt_sl_find(XTThreadPtr self, XTSortedListPtr sl, void *key) +{ + void *result; + size_t idx; + + if (sl->sl_usage_count == 0) + return NULL; + else if (sl->sl_usage_count == 1) { + if ((*sl->sl_comp_func)(self, sl->sl_thunk, key, sl->sl_data) == 0) + return sl->sl_data; + return NULL; + } + result = xt_bsearch(self, key, sl->sl_data, sl->sl_usage_count, sl->sl_item_size, &idx, sl->sl_thunk, sl->sl_comp_func); + return result; +} + +/* + * Returns: + * 1 = Value inserted. + * 2 = Value not inserted, already in the list. + * 0 = An error occurred. + */ +xtPublic int xt_sl_insert(XTThreadPtr self, XTSortedListPtr sl, void *key, void *data) +{ + size_t idx; + + if (sl->sl_usage_count == 0) + idx = 0; + else if (sl->sl_usage_count == 1) { + int r; + + if ((r = (*sl->sl_comp_func)(self, sl->sl_thunk, key, sl->sl_data)) == 0) { + if (sl->sl_free_func) + (*sl->sl_free_func)(self, sl->sl_thunk, data); + return 2; + } + if (r < 0) + idx = 0; + else + idx = 1; + } + else { + if (xt_bsearch(self, key, sl->sl_data, sl->sl_usage_count, sl->sl_item_size, &idx, sl->sl_thunk, sl->sl_comp_func)) { + if (sl->sl_free_func) + (*sl->sl_free_func)(self, sl->sl_thunk, data); + return 2; + } + } + if (sl->sl_usage_count == sl->sl_current_size) { + if (!xt_realloc_ns((void **) &sl->sl_data, (sl->sl_current_size + sl->sl_grow_size) * sl->sl_item_size)) { + if (sl->sl_free_func) + (*sl->sl_free_func)(self, sl->sl_thunk, data); + if (self) + xt_throw(self); + return 0; + } + sl->sl_current_size = sl->sl_current_size + sl->sl_grow_size; + } + XT_MEMMOVE(sl->sl_data, &sl->sl_data[(idx+1) * sl->sl_item_size], &sl->sl_data[idx * sl->sl_item_size], (sl->sl_usage_count-idx) * sl->sl_item_size); + XT_MEMCPY(sl->sl_data, &sl->sl_data[idx * sl->sl_item_size], data, sl->sl_item_size); + sl->sl_usage_count++; + return 1; +} + +xtPublic xtBool xt_sl_delete(XTThreadPtr self, XTSortedListPtr sl, void *key) +{ + void *result; + size_t idx; + + if (sl->sl_usage_count == 0) + return FALSE; + if (sl->sl_usage_count == 1) { + if ((*sl->sl_comp_func)(self, sl->sl_thunk, key, sl->sl_data) != 0) + return FALSE; + idx = 0; + result = sl->sl_data; + } + else { + if (!(result = xt_bsearch(self, key, sl->sl_data, sl->sl_usage_count, sl->sl_item_size, &idx, sl->sl_thunk, sl->sl_comp_func))) + return FALSE; + } + if (sl->sl_free_func) + (*sl->sl_free_func)(self, sl->sl_thunk, result); + sl->sl_usage_count--; + XT_MEMMOVE(sl->sl_data, &sl->sl_data[idx * sl->sl_item_size], &sl->sl_data[(idx+1) * sl->sl_item_size], (sl->sl_usage_count-idx) * sl->sl_item_size); + return TRUE; +} + +xtPublic void xt_sl_delete_item_at(struct XTThread *self, XTSortedListPtr sl, size_t idx) +{ + void *result; + + if (idx >= sl->sl_usage_count) + return; + result = &sl->sl_data[idx * sl->sl_item_size]; + if (sl->sl_free_func) + (*sl->sl_free_func)(self, sl->sl_thunk, result); + sl->sl_usage_count--; + XT_MEMMOVE(sl->sl_data, &sl->sl_data[idx * sl->sl_item_size], &sl->sl_data[(idx+1) * sl->sl_item_size], (sl->sl_usage_count-idx) * sl->sl_item_size); +} + +xtPublic void xt_sl_remove_from_front(struct XTThread *self __attribute__((unused)), XTSortedListPtr sl, size_t items) +{ + if (sl->sl_usage_count <= items) + xt_sl_set_size(sl, 0); + else { + XT_MEMMOVE(sl->sl_data, sl->sl_data, &sl->sl_data[items * sl->sl_item_size], (sl->sl_usage_count-items) * sl->sl_item_size); + sl->sl_usage_count -= items; + } +} + +xtPublic void xt_sl_delete_from_info(XTThreadPtr self, XTSortedListInfoPtr li_undo) +{ + xt_sl_delete(self, li_undo->li_sl, li_undo->li_key); +} + +xtPublic size_t xt_sl_get_size(XTSortedListPtr sl) +{ + return sl->sl_usage_count; +} + +xtPublic void xt_sl_set_size(XTSortedListPtr sl, size_t new_size) +{ + sl->sl_usage_count = new_size; + if (sl->sl_usage_count + sl->sl_grow_size <= sl->sl_current_size) { + size_t curr_size; + + curr_size = sl->sl_usage_count; + if (curr_size < sl->sl_grow_size) + curr_size = sl->sl_grow_size; + + if (xt_realloc(NULL, (void **) &sl->sl_data, curr_size * sl->sl_item_size)) + sl->sl_current_size = curr_size; + } +} + +xtPublic void *xt_sl_item_at(XTSortedListPtr sl, size_t idx) +{ + if (idx < sl->sl_usage_count) + return &sl->sl_data[idx * sl->sl_item_size]; + return NULL; +} + +xtPublic void *xt_sl_last_item(XTSortedListPtr sl) +{ + if (sl->sl_usage_count > 0) + return xt_sl_item_at(sl, sl->sl_usage_count - 1); + return NULL; +} + +xtPublic void *xt_sl_first_item(XTSortedListPtr sl) +{ + if (sl->sl_usage_count > 0) + return xt_sl_item_at(sl, 0); + return NULL; +} + +xtPublic xtBool xt_sl_lock(XTThreadPtr self, XTSortedListPtr sl) +{ + xtBool r = OK; + + if (sl->sl_locker != self) + r = xt_lock_mutex(self, sl->sl_lock); + if (r) { + sl->sl_locker = self; + sl->sl_lock_count++; + } + return r; +} + +xtPublic void xt_sl_unlock(XTThreadPtr self, XTSortedListPtr sl) +{ + ASSERT(!self || sl->sl_locker == self); + ASSERT(sl->sl_lock_count > 0); + + sl->sl_lock_count--; + if (!sl->sl_lock_count) { + sl->sl_locker = NULL; + xt_unlock_mutex(self, sl->sl_lock); + } +} + +xtPublic void xt_sl_lock_ns(XTSortedListPtr sl, XTThreadPtr thread) +{ + if (sl->sl_locker != thread) + xt_lock_mutex_ns(sl->sl_lock); + sl->sl_locker = thread; + sl->sl_lock_count++; +} + +xtPublic void xt_sl_unlock_ns(XTSortedListPtr sl) +{ + ASSERT_NS(!sl->sl_locker || sl->sl_locker == xt_get_self()); + ASSERT_NS(sl->sl_lock_count > 0); + + sl->sl_lock_count--; + if (!sl->sl_lock_count) { + sl->sl_locker = NULL; + xt_unlock_mutex_ns(sl->sl_lock); + } +} + +xtPublic void xt_sl_wait(XTThreadPtr self, XTSortedListPtr sl) +{ + xt_wait_cond(self, sl->sl_cond, sl->sl_lock); +} + +xtPublic xtBool xt_sl_signal(XTThreadPtr self, XTSortedListPtr sl) +{ + return xt_signal_cond(self, sl->sl_cond); +} + +xtPublic void xt_sl_broadcast(XTThreadPtr self, XTSortedListPtr sl) +{ + xt_broadcast_cond(self, sl->sl_cond); +} + diff --git a/storage/pbxt/src/sortedlist_xt.h b/storage/pbxt/src/sortedlist_xt.h new file mode 100644 index 00000000000..cf3066981fe --- /dev/null +++ b/storage/pbxt/src/sortedlist_xt.h @@ -0,0 +1,79 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-02-04 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_sortedlist_h__ +#define __xt_sortedlist_h__ + +#include "pthread_xt.h" +#include "bsearch_xt.h" + +struct XTThread; + +typedef struct XTSortedList { + u_int sl_item_size; + u_int sl_grow_size; + XTCompareFunc sl_comp_func; + void *sl_thunk; + XTFreeFunc sl_free_func; + xt_mutex_type *sl_lock; + struct XTThread *sl_locker; + u_int sl_lock_count; + xt_cond_type *sl_cond; + + u_int sl_current_size; + u_int sl_usage_count; + char *sl_data; +} XTSortedListRec, *XTSortedListPtr; + +typedef struct XTSortedListInfo { + XTSortedListPtr li_sl; + void *li_key; +} XTSortedListInfoRec, *XTSortedListInfoPtr; + +XTSortedListPtr xt_new_sortedlist(struct XTThread *self, u_int item_size, u_int initial_size, u_int grow_size, XTCompareFunc comp_func, void *thunk, XTFreeFunc free_func, xtBool with_lock, xtBool with_cond); +void xt_init_sortedlist(struct XTThread *self, XTSortedListPtr sl, u_int item_size, u_int initial_size, u_int grow_size, XTCompareFunc comp_func, void *thunk, XTFreeFunc free_func, xtBool with_lock, xtBool with_cond); +void xt_free_sortedlist(struct XTThread *self, XTSortedListPtr ld); +void xt_empty_sortedlist(struct XTThread *self, XTSortedListPtr sl); +XTSortedListPtr xt_new_sortedlist_ns(u_int item_size, u_int grow_size, XTCompareFunc comp_func, void *thunk, XTFreeFunc free_func); + +xtBool xt_sl_insert(struct XTThread *self, XTSortedListPtr sl, void *key, void *data); +void *xt_sl_find(struct XTThread *self, XTSortedListPtr sl, void *key); +xtBool xt_sl_delete(struct XTThread *self, XTSortedListPtr sl, void *key); +void xt_sl_delete_item_at(struct XTThread *self, XTSortedListPtr sl, size_t i); +void xt_sl_remove_from_front(struct XTThread *self, XTSortedListPtr sl, size_t items); +void xt_sl_delete_from_info(struct XTThread *self, XTSortedListInfoPtr li); +size_t xt_sl_get_size(XTSortedListPtr sl); +void xt_sl_set_size(XTSortedListPtr sl, size_t new_size); +void *xt_sl_item_at(XTSortedListPtr sl, size_t i); +void *xt_sl_last_item(XTSortedListPtr sl); +void *xt_sl_first_item(XTSortedListPtr sl); + +xtBool xt_sl_lock(struct XTThread *self, XTSortedListPtr sl); +void xt_sl_unlock(struct XTThread *self, XTSortedListPtr sl); +void xt_sl_lock_ns(XTSortedListPtr sl, struct XTThread *thread); +void xt_sl_unlock_ns(XTSortedListPtr sl); + +void xt_sl_wait(struct XTThread *self, XTSortedListPtr sl); +xtBool xt_sl_signal(struct XTThread *self, XTSortedListPtr sl); +void xt_sl_broadcast(struct XTThread *self, XTSortedListPtr sl); + +#endif diff --git a/storage/pbxt/src/streaming_xt.cc b/storage/pbxt/src/streaming_xt.cc new file mode 100755 index 00000000000..710b3256d60 --- /dev/null +++ b/storage/pbxt/src/streaming_xt.cc @@ -0,0 +1,624 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-06-07 Paul McCullagh + * + * H&G2JCtL + * + * This file contains PBXT streaming interface. + */ + +#include "xt_config.h" + +#ifdef XT_STREAMING +#include "ha_pbxt.h" + +#include "thread_xt.h" +#include "strutil_xt.h" +#include "table_xt.h" +#include "myxt_xt.h" +#include "xaction_xt.h" +#include "database_xt.h" +#include "streaming_xt.h" + +extern PBMSEngineRec pbxt_engine; + +static PBMS_API pbxt_streaming; + +/* ---------------------------------------------------------------------- + * INIT & EXIT + */ + +xtPublic xtBool xt_init_streaming(void) +{ + XTThreadPtr self = NULL; + int err; + PBMSResultRec result; + + if ((err = pbxt_streaming.registerEngine(&pbxt_engine, &result))) { + xt_logf(XT_CONTEXT, XT_LOG_ERROR, "%s\n", result.mr_message); + return FAILED; + } + return OK; +} + +xtPublic void xt_exit_streaming(void) +{ + pbxt_streaming.deregisterEngine(&pbxt_engine); +} + +/* ---------------------------------------------------------------------- + * UTILITY FUNCTIONS + */ + +static void str_result_to_exception(XTExceptionPtr e, int r, PBMSResultPtr result) +{ + char *str, *end_str; + + e->e_xt_err = r; + e->e_sys_err = result->mr_code; + xt_strcpy(XT_ERR_MSG_SIZE, e->e_err_msg, result->mr_message); + + e->e_source_line = 0; + str = result->mr_stack; + if ((end_str = strchr(str, '('))) { + xt_strcpy_term(XT_MAX_FUNC_NAME_SIZE, e->e_func_name, str, '('); + str = end_str+1; + if ((end_str = strchr(str, ':'))) { + xt_strcpy_term(XT_SOURCE_FILE_NAME_SIZE, e->e_source_file, str, ':'); + str = end_str+1; + if ((end_str = strchr(str, ')'))) { + char number[40]; + + xt_strcpy_term(40, number, str, ')'); + e->e_source_line = atol(number); + str = end_str+1; + if (*str == '\n') + str++; + } + } + } + + if (e->e_source_line == 0) { + *e->e_func_name = 0; + *e->e_source_file = 0; + xt_strcpy(XT_ERR_MSG_SIZE, e->e_catch_trace, result->mr_stack); + } + else + xt_strcpy(XT_ERR_MSG_SIZE, e->e_catch_trace, str); +} + +static void str_exception_to_result(XTExceptionPtr e, PBMSResultPtr result) +{ + int len; + + if (e->e_sys_err) + result->mr_code = e->e_sys_err; + else + result->mr_code = e->e_xt_err; + xt_strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, e->e_err_msg); + xt_strcpy(MS_RESULT_STACK_SIZE, result->mr_stack, e->e_func_name); + xt_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, "("); + xt_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, e->e_source_file); + xt_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, ":"); + xt_strcati(MS_RESULT_STACK_SIZE, result->mr_stack, (int) e->e_source_line); + xt_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, ")"); + len = strlen(result->mr_stack); + if (strncmp(result->mr_stack, e->e_catch_trace, len) == 0) + xt_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, e->e_catch_trace + len); + else { + xt_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, "\n"); + xt_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, e->e_catch_trace); + } +} + +static XTIndexPtr str_find_index(XTTableHPtr tab, u_int *col_list, u_int col_cnt) +{ + u_int i, j; + XTIndexPtr *ind; /* MySQL/PBXT key description */ + + ind = tab->tab_dic.dic_keys; + for (i=0; i<tab->tab_dic.dic_key_count; i++) { + if ((*ind)->mi_seg_count == col_cnt) { + for (j=0; j<(*ind)->mi_seg_count; j++) { + if ((*ind)->mi_seg[j].col_idx != col_list[j]) + goto loop; + } + return *ind; + } + + loop: + ind++; + } + return NULL; +} + +static XTThreadPtr str_set_current_thread(THD *thd, PBMSResultPtr result) +{ + XTThreadPtr self; + XTExceptionRec e; + + if (!(self = xt_ha_set_current_thread(thd, &e))) { + str_exception_to_result(&e, result); + return NULL; + } + return self; +} + +/* ---------------------------------------------------------------------- + * BLOB STREAMING INTERFACE + */ + +static void pbxt_close_conn(void *thread) +{ + xt_ha_close_connection((THD *) thread); +} + +static int pbxt_open_table(void *thread, const char *table_url, void **open_table, PBMSResultPtr result) +{ + THD *thd = (THD *) thread; + XTThreadPtr self; + XTTableHPtr tab = NULL; + XTOpenTablePtr ot = NULL; + int err = MS_OK; + + if (!(self = str_set_current_thread(thd, result))) + return MS_ERR_ENGINE; + + try_(a) { + xt_ha_open_database_of_table(self, (XTPathStrPtr) table_url); + if (!(tab = xt_use_table(self, (XTPathStrPtr) table_url, FALSE, TRUE, NULL))) { + err = MS_ERR_UNKNOWN_TABLE; + goto done; + } + if (!(ot = xt_open_table(tab))) + throw_(); + ot->ot_thread = self; + done:; + } + catch_(a) { + str_exception_to_result(&self->t_exception, result); + err = MS_ERR_ENGINE; + } + cont_(a); + if (tab) + xt_heap_release(self, tab); + *open_table = ot; + return err; +} + +static void pbxt_close_table(void *thread, void *open_table_ptr) +{ + THD *thd = (THD *) thread; + volatile XTThreadPtr self, new_self = NULL; + XTOpenTablePtr ot = (XTOpenTablePtr) open_table_ptr; + XTExceptionRec e; + + if (thd) { + if (!(self = xt_ha_set_current_thread(thd, &e))) { + xt_log_exception(NULL, &e, XT_LOG_DEFAULT); + return; + } + } + else if (!(self = xt_get_self())) { + if (!(new_self = xt_create_thread("TempForClose", FALSE, TRUE, &e))) { + xt_log_exception(NULL, &e, XT_LOG_DEFAULT); + return; + } + self = new_self; + } + + ot->ot_thread = self; + try_(a) { + xt_close_table(ot, TRUE, FALSE); + } + catch_(a) { + xt_log_and_clear_exception(self); + } + cont_(a); + if (new_self) + xt_free_thread(self); +} + +static int pbxt_lock_table(void *thread, int *xact, void *open_table, int lock_type, PBMSResultPtr result) +{ + THD *thd = (THD *) thread; + XTThreadPtr self; + XTOpenTablePtr ot = (XTOpenTablePtr) open_table; + int err = MS_OK; + + if (!(self = str_set_current_thread(thd, result))) + return MS_ERR_ENGINE; + + if (lock_type != MS_LOCK_NONE) { + try_(a) { + xt_ha_open_database_of_table(self, ot->ot_table->tab_name); + ot->ot_thread = self; + } + catch_(a) { + str_exception_to_result(&self->t_exception, result); + err = MS_ERR_ENGINE; + } + cont_(a); + } + + if (!err && *xact == MS_XACT_BEGIN) { + if (self->st_xact_data) + *xact = MS_XACT_NONE; + else { + if (xt_xn_begin(self)) { + *xact = MS_XACT_COMMIT; + } + else { + str_exception_to_result(&self->t_exception, result); + err = MS_ERR_ENGINE; + } + } + } + + return err; +} + +static int pbxt_unlock_table(void *thread, int xact, void *open_table __attribute__((unused)), PBMSResultPtr result) +{ + THD *thd = (THD *) thread; + XTThreadPtr self = xt_ha_thd_to_self(thd); + int err = MS_OK; + + if (xact == MS_XACT_COMMIT) { + if (!xt_xn_commit(self)) { + str_exception_to_result(&self->t_exception, result); + err = MS_ERR_ENGINE; + } + } + else if (xact == MS_XACT_ROLLBACK) { + xt_xn_rollback(self); + } + + return err; +} + +static int pbxt_send_blob(void *thread, void *open_table, const char *blob_column, const char *blob_url_p, void *stream, PBMSResultPtr result) +{ + THD *thd = (THD *) thread; + XTThreadPtr self = xt_ha_thd_to_self(thd); + XTOpenTablePtr ot = (XTOpenTablePtr) open_table; + int err = MS_OK; + u_int blob_col_idx, col_idx; + char col_name[XT_IDENTIFIER_NAME_SIZE]; + XTStringBufferRec value; + u_int col_list[XT_MAX_COLS_PER_INDEX]; + u_int col_cnt; + char col_names[XT_ERR_MSG_SIZE - 200]; + XTIdxSearchKeyRec search_key; + XTIndexPtr ind; + char *blob_data; + size_t blob_len; + const char *blob_url = blob_url_p; + + memset(&value, 0, sizeof(value)); + + *col_names = 0; + + ot->ot_thread = self; + try_(a) { + if (ot->ot_row_wbuf_size < ot->ot_table->tab_dic.dic_mysql_buf_size) { + xt_realloc(self, (void **) &ot->ot_row_wbuffer, ot->ot_table->tab_dic.dic_mysql_buf_size); + ot->ot_row_wbuf_size = ot->ot_table->tab_dic.dic_mysql_buf_size; + } + + xt_strcpy_url(XT_IDENTIFIER_NAME_SIZE, col_name, blob_column); + if (!myxt_find_column(ot, &blob_col_idx, col_name)) + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_COLUMN_NOT_FOUND, ot->ot_table->tab_name, blob_column); + + /* Prepare a row for the condition: */ + const char *ptr; + + col_cnt = 0; + while (*blob_url) { + ptr = xt_strchr(blob_url, '='); + xt_strncpy_url(XT_IDENTIFIER_NAME_SIZE, col_name, blob_url, (size_t) (ptr - blob_url)); + if (!myxt_find_column(ot, &col_idx, col_name)) + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_COLUMN_NOT_FOUND, ot->ot_table->tab_name, col_name); + if (*col_names) + xt_strcat(sizeof(col_names), col_names, ", "); + xt_strcat(sizeof(col_names), col_names, col_name); + blob_url = ptr; + if (*blob_url == '=') + blob_url++; + ptr = xt_strchr(blob_url, '&'); + value.sb_len = 0; + xt_sb_concat_url_len(self, &value, blob_url, (size_t) (ptr - blob_url)); + blob_url = ptr; + if (*blob_url == '&') + blob_url++; + if (!myxt_set_column(ot, (char *) ot->ot_row_rbuffer, col_idx, value.sb_cstring, value.sb_len)) + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_CONVERSION, ot->ot_table->tab_name, col_name); + if (col_cnt < XT_MAX_COLS_PER_INDEX) { + col_list[col_cnt] = col_idx; + col_cnt++; + } + } + + /* Find a matching index: */ + if (!(ind = str_find_index(ot->ot_table, col_list, col_cnt))) + xt_throw_ixterr(XT_CONTEXT, XT_ERR_NO_MATCHING_INDEX, col_names); + + search_key.sk_key_value.sv_flags = 0; + search_key.sk_key_value.sv_rec_id = 0; + search_key.sk_key_value.sv_row_id = 0; + search_key.sk_key_value.sv_key = search_key.sk_key_buf; + search_key.sk_key_value.sv_length = myxt_create_key_from_row(ind, search_key.sk_key_buf, ot->ot_row_rbuffer, NULL); + search_key.sk_on_key = FALSE; + + if (!xt_idx_search(ot, ind, &search_key)) + xt_throw(self); + + if (!ot->ot_curr_rec_id) + xt_throw_taberr(XT_CONTEXT, XT_ERR_NO_ROWS, ot->ot_table->tab_name); + + while (ot->ot_curr_rec_id) { + if (!search_key.sk_on_key) + xt_throw_taberr(XT_CONTEXT, XT_ERR_NO_ROWS, ot->ot_table->tab_name); + + retry: + /* X TODO - Check if the write buffer is big enough here! */ + switch (xt_tab_read_record(ot, ot->ot_row_wbuffer)) { + case FALSE: + if (xt_idx_next(ot, ind, &search_key)) + break; + case XT_ERR: + xt_throw(self); + case XT_NEW: + if (xt_idx_match_search(ot, ind, &search_key, ot->ot_row_wbuffer, XT_S_MODE_MATCH)) + goto success; + if (!xt_idx_next(ot, ind, &search_key)) + xt_throw(self); + break; + case XT_RETRY: + goto retry; + default: + goto success; + } + } + + success: + myxt_get_column_data(ot, (char *) ot->ot_row_wbuffer, blob_col_idx, &blob_data, &blob_len); + + /* + * Write the content length, then write the HTTP + * header, and then the content. + */ + err = pbxt_streaming.setContentLength(stream, blob_len, result); + if (!err) + err = pbxt_streaming.writeHead(stream, result); + if (!err) + err = pbxt_streaming.writeStream(stream, (void *) blob_data, blob_len, result); + } + catch_(a) { + str_exception_to_result(&self->t_exception, result); + if (result->mr_code == XT_ERR_NO_ROWS) + err = MS_ERR_NOT_FOUND; + else + err = MS_ERR_ENGINE; + } + cont_(a); + xt_sb_set_size(NULL, &value, 0); + return err; +} + +int pbxt_lookup_ref(void *thread, void *open_table, unsigned short col_index, PBMSEngineRefPtr eng_ref, PBMSFieldRefPtr field_ref, PBMSResultPtr result) +{ + THD *thd = (THD *) thread; + XTThreadPtr self = xt_ha_thd_to_self(thd); + XTOpenTablePtr ot = (XTOpenTablePtr) open_table; + int err = MS_OK; + u_int i, len; + char *data; + XTIndexPtr ind = NULL; + + ot->ot_thread = self; + if (ot->ot_row_wbuf_size < ot->ot_table->tab_dic.dic_mysql_buf_size) { + xt_realloc(self, (void **) &ot->ot_row_wbuffer, ot->ot_table->tab_dic.dic_mysql_buf_size); + ot->ot_row_wbuf_size = ot->ot_table->tab_dic.dic_mysql_buf_size; + } + + ot->ot_curr_rec_id = (xtRecordID) XT_GET_DISK_8(eng_ref->er_data); + switch (xt_tab_dirty_read_record(ot, ot->ot_row_wbuffer)) { + case FALSE: + err = MS_ERR_ENGINE; + break; + default: + break; + } + + if (err) { + str_exception_to_result(&self->t_exception, result); + goto exit; + } + + myxt_get_column_name(ot, col_index, PBMS_FIELD_COL_SIZE, field_ref->fr_column); + + for (i=0; i<ot->ot_table->tab_dic.dic_key_count; i++) { + ind = ot->ot_table->tab_dic.dic_keys[i]; + if (ind->mi_flags & (HA_UNIQUE_CHECK | HA_NOSAME)) + break; + } + + if (ind) { + len = 0; + data = field_ref->fr_cond; + for (i=0; i<ind->mi_seg_count; i++) { + if (i > 0) { + xt_strcat(PBMS_FIELD_COND_SIZE, data, "&"); + len = strlen(data); + } + myxt_get_column_name(ot, ind->mi_seg[i].col_idx, PBMS_FIELD_COND_SIZE - len, data + len); + len = strlen(data); + xt_strcat(PBMS_FIELD_COND_SIZE, data, "="); + len = strlen(data); + myxt_get_column_as_string(ot, (char *) ot->ot_row_wbuffer, ind->mi_seg[i].col_idx, PBMS_FIELD_COND_SIZE - len, data + len); + len = strlen(data); + } + } + else + xt_strcpy(PBMS_FIELD_COND_SIZE, field_ref->fr_cond, "*no unique key*"); + + exit: + return err; +} + +PBMSEngineRec pbxt_engine = { + MS_ENGINE_VERSION, + 0, + FALSE, + "PBXT", + NULL, + pbxt_close_conn, + pbxt_open_table, + pbxt_close_table, + pbxt_lock_table, + pbxt_unlock_table, + pbxt_send_blob, + pbxt_lookup_ref +}; + +/* ---------------------------------------------------------------------- + * CALL IN FUNCTIONS + */ + +xtPublic void xt_pbms_close_all_tables(const char *table_url) +{ + pbxt_streaming.closeAllTables(table_url); +} + +xtPublic xtBool xt_pbms_close_connection(void *thd, XTExceptionPtr e) +{ + PBMSResultRec result; + int err; + + err = pbxt_streaming.closeConn(thd, &result); + if (err) { + str_result_to_exception(e, err, &result); + return FAILED; + } + return OK; +} + +xtPublic xtBool xt_pbms_open_table(void **open_table, char *table_path) +{ + PBMSResultRec result; + int err; + + err = pbxt_streaming.openTable(open_table, table_path, &result); + if (err) { + XTThreadPtr thread = xt_get_self(); + + str_result_to_exception(&thread->t_exception, err, &result); + return FAILED; + } + return OK; +} + +xtPublic void xt_pbms_close_table(void *open_table) +{ + PBMSResultRec result; + int err; + + err = pbxt_streaming.closeTable(open_table, &result); + if (err) { + XTThreadPtr thread = xt_get_self(); + + str_result_to_exception(&thread->t_exception, err, &result); + xt_log_exception(thread, &thread->t_exception, XT_LOG_DEFAULT); + } +} + +xtPublic xtBool xt_pbms_use_blob(void *open_table, char **ret_blob_url, char *blob_url, unsigned short col_index) +{ + PBMSResultRec result; + int err; + + err = pbxt_streaming.useBlob(open_table, ret_blob_url, blob_url, col_index, &result); + if (err) { + XTThreadPtr thread = xt_get_self(); + + str_result_to_exception(&thread->t_exception, err, &result); + return FAILED; + } + return OK; +} + +xtPublic xtBool xt_pbms_retain_blobs(void *open_table, PBMSEngineRefPtr eng_ref) +{ + PBMSResultRec result; + int err; + + err = pbxt_streaming.retainBlobs(open_table, eng_ref, &result); + if (err) { + XTThreadPtr thread = xt_get_self(); + + str_result_to_exception(&thread->t_exception, err, &result); + return FAILED; + } + return OK; +} + +xtPublic void xt_pbms_release_blob(void *open_table, char *blob_url, unsigned short col_index, PBMSEngineRefPtr eng_ref) +{ + PBMSResultRec result; + int err; + + err = pbxt_streaming.releaseBlob(open_table, blob_url, col_index, eng_ref, &result); + if (err) { + XTThreadPtr thread = xt_get_self(); + + str_result_to_exception(&thread->t_exception, err, &result); + xt_log_exception(thread, &thread->t_exception, XT_LOG_DEFAULT); + } +} + +xtPublic void xt_pbms_drop_table(const char *table_path) +{ + PBMSResultRec result; + int err; + + err = pbxt_streaming.dropTable(table_path, &result); + if (err) { + XTThreadPtr thread = xt_get_self(); + + str_result_to_exception(&thread->t_exception, err, &result); + xt_log_exception(thread, &thread->t_exception, XT_LOG_DEFAULT); + } +} + +xtPublic void xt_pbms_rename_table(const char *from_table, const char *to_table) +{ + PBMSResultRec result; + int err; + + err = pbxt_streaming.renameTable(from_table, to_table, &result); + if (err) { + XTThreadPtr thread = xt_get_self(); + + str_result_to_exception(&thread->t_exception, err, &result); + xt_log_exception(thread, &thread->t_exception, XT_LOG_DEFAULT); + } +} + +#endif // XT_STREAMING diff --git a/storage/pbxt/src/streaming_xt.h b/storage/pbxt/src/streaming_xt.h new file mode 100755 index 00000000000..6fe36822383 --- /dev/null +++ b/storage/pbxt/src/streaming_xt.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-06-07 Paul McCullagh + * + * H&G2JCtL + * + * This file contains PBXT streaming interface. + */ + +#ifndef __streaming_xt_h__ +#define __streaming_xt_h__ + +#include "xt_defs.h" +#define PBMS_API pbms_api_PBXT +#include "pbms.h" + +xtBool xt_init_streaming(void); +void xt_exit_streaming(void); + +void xt_pbms_close_all_tables(const char *table_url); +xtBool xt_pbms_close_connection(void *thd, XTExceptionPtr e); +xtBool xt_pbms_open_table(void **open_table, char *table_path); +void xt_pbms_close_table(void *open_table); +xtBool xt_pbms_use_blob(void *open_table, char **ret_blob_url, char *blob_url, unsigned short col_index); +xtBool xt_pbms_retain_blobs(void *open_table, PBMSEngineRefPtr eng_ref); +void xt_pbms_release_blob(void *open_table, char *blob_url, unsigned short col_index, PBMSEngineRefPtr eng_ref); +void xt_pbms_drop_table(const char *table_path); +void xt_pbms_rename_table(const char *from_table, const char *to_table); + +#endif diff --git a/storage/pbxt/src/strutil_xt.cc b/storage/pbxt/src/strutil_xt.cc new file mode 100644 index 00000000000..60e45c455d1 --- /dev/null +++ b/storage/pbxt/src/strutil_xt.cc @@ -0,0 +1,567 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-03 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "strutil_xt.h" + +xtPublic void xt_strcpy(size_t size, char *to, c_char *from) +{ + if (size > 0) { + size--; + while (*from && size--) + *to++ = *from++; + *to = 0; + } +} + +xtPublic void xt_strncpy(size_t size, char *to, c_char *from, size_t len_from) +{ + if (size > 0) { + size--; + while (len_from-- && size--) + *to++ = *from++; + *to = 0; + } +} + +xtPublic void xt_strcpy_term(size_t size, char *to, c_char *from, char term) +{ + if (size > 0) { + size--; + while (*from && *from != term && size--) + *to++ = *from++; + *to = 0; + } +} + +xtPublic void xt_strcat_term(size_t size, char *to, c_char *from, char term) +{ + while (*to && size--) to++; + if (size > 0) { + size--; + while (*from && *from != term && size--) + *to++ = *from++; + *to = 0; + } +} + +xtPublic void xt_strcat(size_t size, char *to, c_char *from) +{ + while (*to && size--) to++; + xt_strcpy(size, to, from); +} + +xtPublic void xt_strcati(size_t size, char *to, int i) +{ + char buffer[50]; + + sprintf(buffer, "%d", i); + xt_strcat(size, to, buffer); +} + +xtPublic xtBool xt_ends_with(c_char *str, c_char *sub) +{ + unsigned long len = strlen(str); + + if (len >= strlen(sub)) + return strcmp(&str[len-strlen(sub)], sub) == 0; + return FALSE; +} + +xtPublic xtPublic xtBool xt_starts_with(c_char *str, c_char *sub) +{ + return (strstr(str, sub) == str); +} + +/* This function returns "" if the path ends with a dir char */ +xtPublic void xt_2nd_last_name_of_path(size_t size, char *dest, c_char *path) +{ + size_t len; + c_char *ptr, *pend; + + len = strlen(path); + if (!len) { + *dest = 0; + return; + } + ptr = path + len - 1; + while (ptr != path && !XT_IS_DIR_CHAR(*ptr)) + ptr--; + if (!XT_IS_DIR_CHAR(*ptr)) { + *dest = 0; + return; + } + pend = ptr; + ptr--; + while (ptr != path && !XT_IS_DIR_CHAR(*ptr)) + ptr--; + if (XT_IS_DIR_CHAR(*ptr)) + ptr++; + len = (size_t) (pend - ptr); + if (len > size-1) + len = size-1; + memcpy(dest, ptr, len); + dest[len] = 0; +} + +/* This function returns "" if the path ends with a dir char */ +xtPublic char *xt_last_name_of_path(c_char *path) +{ + size_t length; + c_char *ptr; + + length = strlen(path); + if (!length) + return (char *) path; + ptr = path + length - 1; + while (ptr != path && !XT_IS_DIR_CHAR(*ptr)) ptr--; + if (XT_IS_DIR_CHAR(*ptr)) ptr++; + return (char *) ptr; +} + +xtPublic char *xt_last_2_names_of_path(c_char *path) +{ + size_t length; + c_char *ptr; + + length = strlen(path); + if (!length) + return (char *) path; + ptr = path + length - 1; + while (ptr != path && !XT_IS_DIR_CHAR(*ptr)) ptr--; + if (XT_IS_DIR_CHAR(*ptr)) { + ptr--; + while (ptr != path && !XT_IS_DIR_CHAR(*ptr)) ptr--; + if (XT_IS_DIR_CHAR(*ptr)) + ptr++; + } + return (char *) ptr; +} + +xtPublic c_char *xt_last_directory_of_path(c_char *path) +/* This function returns the last name component, even if the path ends with a dir char */ +{ + size_t length; + c_char *ptr; + + length = strlen(path); + if (!length) + return(path); + ptr = path + length - 1; + /* Path may end with multiple slashes: */ + while (ptr != path && XT_IS_DIR_CHAR(*ptr)) + ptr--; + while (ptr != path && !XT_IS_DIR_CHAR(*ptr)) + ptr--; + if (XT_IS_DIR_CHAR(*ptr)) ptr++; + return(ptr); +} + +xtPublic char *xt_find_extension(c_char *file_name) +{ + c_char *ptr; + + for (ptr = file_name + strlen(file_name) - 1; ptr >= file_name; ptr--) { + if (XT_IS_DIR_CHAR(*ptr)) + break; + if (*ptr == '.') + return (char *) (ptr + 1); + } + return NULL; +} + +xtPublic void xt_remove_extension(char *file_name) +{ + char *ptr = xt_find_extension(file_name); + + if (ptr) + *(ptr - 1) = 0; +} + +xtPublic xtBool xt_is_extension(c_char *file_name, c_char *ext) +{ + char *ptr; + + if (!(ptr = xt_find_extension(file_name))) + return FALSE; + return strcmp(ptr, ext) == 0; +} + +/* + * Optionally remove trailing directory delimiters (If the directory name consists of one + * character, the directory delimiter is not removed). + */ +xtPublic xtBool xt_remove_dir_char(char *dir_name) +{ + size_t length; + xtBool removed = FALSE; + + length = strlen(dir_name); + while (length > 1 && XT_IS_DIR_CHAR(dir_name[length - 1])) { + dir_name[length - 1] = '\0'; + length--; + removed = TRUE; + } + return removed; +} + +xtPublic void xt_remove_last_name_of_path(char *path) +{ + char *ptr; + + if ((ptr = xt_last_name_of_path(path))) + *ptr = 0; +} + +xtBool xt_add_dir_char(size_t max, char *path) +{ + size_t slen = strlen(path); + + if (slen >= max) + return FALSE; + + if (slen == 0) { + /* If no path is given we will be at the current working directory, under UNIX we must + * NOT add a directory delimiter character: + */ + return FALSE; + } + + if (!XT_IS_DIR_CHAR(path[slen - 1])) { + path[slen] = XT_DIR_CHAR; + path[slen + 1] = '\0'; + return TRUE; + } + return FALSE; +} + +xtPublic xtInt8 xt_str_to_int8(c_char *ptr, xtBool *overflow) +{ + xtInt8 value = 0; + + if (overflow) + *overflow = FALSE; + while (*ptr == '0') ptr++; + if (!*ptr) + value = (xtInt8) 0; + else { + sscanf(ptr, "%"PRId64, &value); + if (!value && overflow) + *overflow = TRUE; + } + return value; +} + +xtPublic void xt_int8_to_str(xtInt8 value, char *string) +{ + sprintf(string, "%"PRId64, value); +} + +xtPublic void xt_double_to_str(double value, int scale, char *string) +{ + char *ptr; + + sprintf(string, "%.*f", scale, value); + ptr = string + strlen(string) - 1; + + if (strchr(string, '.') && (*ptr == '0' || *ptr == '.')) { + while (ptr-1 > string && *(ptr-1) == '0') ptr--; + if (ptr-1 > string && *(ptr-1) == '.') ptr--; + *ptr = 0; + } +} + +/* + * This function understand GB, MB, KB. + */ +xtPublic xtInt8 xt_byte_size_to_int8(c_char *ptr) +{ + char number[101], *num_ptr; + xtInt8 size; + + while (*ptr && isspace(*ptr)) + ptr++; + + num_ptr = number; + while (*ptr && isdigit(*ptr)) { + if (num_ptr < number+100) { + *num_ptr = *ptr; + num_ptr++; + } + ptr++; + } + *num_ptr = 0; + size = xt_str_to_int8(number, NULL); + + while (*ptr && isspace(*ptr)) + ptr++; + + switch (toupper(*ptr)) { + case 'P': + size *= 1024; + case 'T': + size *= 1024; + case 'G': + size *= 1024; + case 'M': + size *= 1024; + case 'K': + size *= 1024; + break; + } + + return size; +} + +xtPublic void xt_int8_to_byte_size(xtInt8 value, char *string) +{ + double v; + c_char *unit; + char val_str[100]; + + if (value >= (xtInt8) (1024 * 1024 * 1024)) { + v = (double) value / (double) (1024 * 1024 * 1024); + unit = "GB"; + } + else if (value >= (xtInt8) (1024 * 1024)) { + v = (double) value / (double) (1024 * 1024); + unit = "MB"; + } + else if (value >= (xtInt8) 1024) { + v = (double) value / (double) (1024); + unit = "Kb"; + } + else { + v = (double) value; + unit = "bytes"; + } + + xt_double_to_str(v, 2, val_str); + sprintf(string, "%s %s (%"PRId64" bytes)", val_str, unit, value); +} + +xtPublic c_char *xt_get_version(void) +{ + return "1.0.08 RC"; +} + +/* Copy and URL decode! */ +xtPublic void xt_strcpy_url(size_t size, char *to, c_char *from) +{ + if (size > 0) { + size--; + while (*from && size--) { + if (*from == '%' && isxdigit(*(from+1)) && isxdigit(*(from+2))) { + unsigned char a = xt_hex_digit(*(from+1)); + unsigned char b = xt_hex_digit(*(from+2)); + *to++ = a << 4 | b; + from += 3; + } + else + *to++ = *from++; + } + *to = 0; + } +} + +/* Copy and URL decode! */ +xtPublic void xt_strncpy_url(size_t size, char *to, c_char *from, size_t len_from) +{ + if (size > 0) { + size--; + while (len_from-- && size--) { + if (*from == '%' && len_from >= 2 && isxdigit(*(from+1)) && isxdigit(*(from+2))) { + unsigned char a = xt_hex_digit(*(from+1)); + unsigned char b = xt_hex_digit(*(from+2)); + *to++ = a << 4 | b; + from += 3; + } + else + *to++ = *from++; + } + *to = 0; + } +} + +/* Returns a pointer to the end of the string if nothing found! */ +const char *xt_strchr(const char *str, char ch) +{ + while (*str && *str != ch) str++; + return str; +} + +unsigned char xt_hex_digit(char ch) +{ + if (isdigit(ch)) + return((unsigned char) ch - (unsigned char) '0'); + + ch = toupper(ch); + if (ch >= 'A' && ch <= 'F') + return((unsigned char) ch - (unsigned char) 'A' + (unsigned char) 10); + + return((unsigned char) 0); +} + +#ifdef XT_WIN +xtPublic void xt_win_dialog(char *message) +{ + MessageBoxA(NULL, message, "Debug Me!", MB_ICONWARNING | MB_OK); +} +#endif + +/* + * --------------- SYSTEM STATISTICS ------------------ + */ + +static char su_t_unit[10] = "usec"; +/* + * Note times, are return in microseconds, but the display in xtstat is currently + * in milliseconds. + */ +static XTStatMetaDataRec pbxt_stat_meta_data[XT_STAT_MAXIMUM] = { + { XT_STAT_TIME_CURRENT, "Current Time", "time", "curr", XT_STAT_DATE, + "The current time in seconds" }, + { XT_STAT_TIME_PASSED, "Time Since Last Call", "time", su_t_unit, XT_STAT_ACCUMULATIVE | XT_STAT_TIME_VALUE, + "Time passed in %sseconds since last statistics call" }, + + { XT_STAT_COMMITS, "Commit Count", "xact", "commt", XT_STAT_ACCUMULATIVE, + "Number of transactions committed" }, + { XT_STAT_ROLLBACKS, "Rollback Count", "xact", "rollb", XT_STAT_ACCUMULATIVE, + "Number of transactions rolled back" }, + { XT_STAT_WAIT_FOR_XACT, "Wait for Xact Count", "xact", "waits", XT_STAT_ACCUMULATIVE, + "Number of times waited for another transaction" }, + { XT_STAT_XACT_TO_CLEAN, "Dirty Xact Count", "xact", "dirty", 0, + "Number of transactions still to be cleaned up" }, + + { XT_STAT_STAT_READS, "Read Statements", "stat", "read", XT_STAT_ACCUMULATIVE, + "Number of SELECT statements" }, + { XT_STAT_STAT_WRITES, "Write Statements", "stat", "write", XT_STAT_ACCUMULATIVE, + "Number of UPDATE/INSERT/DELETE statements" }, + + { XT_STAT_REC_BYTES_IN, "Record Bytes Read", "rec", "in", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes read from the record/row files" }, + { XT_STAT_REC_BYTES_OUT, "Record Bytes Written", "rec", "out", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes written from the record/row files" }, + { XT_STAT_REC_SYNC_COUNT, "Record File Flushes", "rec", "syncs", XT_STAT_ACCUMULATIVE | XT_STAT_COMBO_FIELD, + "Number of flushes to record/row files" }, + { XT_STAT_REC_SYNC_TIME, "Record Flush Time", "rec", su_t_unit, XT_STAT_ACCUMULATIVE | XT_STAT_TIME_VALUE | XT_STAT_COMBO_FIELD_2, + "The time in %sseconds to flush record/row files" }, + { XT_STAT_REC_CACHE_HIT, "Record Cache Hits", "rec", "hits", XT_STAT_ACCUMULATIVE, + "Hits when accessing the record cache" }, + { XT_STAT_REC_CACHE_MISS, "Record Cache Misses", "rec", "miss", XT_STAT_ACCUMULATIVE, + "Misses when accessing the record cache" }, + { XT_STAT_REC_CACHE_FREES, "Record Cache Frees", "rec", "frees", XT_STAT_ACCUMULATIVE, + "Number of record cache pages freed" }, + { XT_STAT_REC_CACHE_USAGE, "Record Cache Usage", "rec", "%use", XT_STAT_PERCENTAGE, + "Percentage of record cache in use" }, + + { XT_STAT_IND_BYTES_IN, "Index Bytes Read", "ind", "in", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes read from the index files" }, + { XT_STAT_IND_BYTES_OUT, "Index Bytes Written", "ind", "out", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes written from the index files" }, + { XT_STAT_IND_SYNC_COUNT, "Index File Flushes", "ind", "syncs", XT_STAT_ACCUMULATIVE | XT_STAT_COMBO_FIELD, + "Number of flushes to index files" }, + { XT_STAT_IND_SYNC_TIME, "Index Flush Time", "ind", su_t_unit, XT_STAT_ACCUMULATIVE | XT_STAT_TIME_VALUE | XT_STAT_COMBO_FIELD_2, + "The time in %sseconds to flush index files" }, + { XT_STAT_IND_CACHE_HIT, "Index Cache Hits", "ind", "hits", XT_STAT_ACCUMULATIVE, + "Hits when accessing the index cache" }, + { XT_STAT_IND_CACHE_MISS, "Index Cache Misses", "ind", "miss", XT_STAT_ACCUMULATIVE, + "Misses when accessing the index cache" }, + { XT_STAT_IND_CACHE_USAGE, "Index Cache Usage", "ind", "%use", XT_STAT_PERCENTAGE, + "Percentage of index cache used" }, + { XT_STAT_ILOG_BYTES_IN, "Index Log Bytes In", "ilog", "in", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes read from the index log files" }, + { XT_STAT_ILOG_BYTES_OUT, "Index Log Bytes Out", "ilog", "out", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes written from the index log files" }, + { XT_STAT_ILOG_SYNC_COUNT, "Index Log File Syncs", "ilog", "syncs", XT_STAT_ACCUMULATIVE | XT_STAT_COMBO_FIELD, + "Number of flushes to index log files" }, + { XT_STAT_ILOG_SYNC_TIME, "Index Log Sync Time", "ilog", su_t_unit, XT_STAT_ACCUMULATIVE | XT_STAT_TIME_VALUE | XT_STAT_COMBO_FIELD_2, + "The time in %sseconds to flush index log files" }, + + { XT_STAT_XLOG_BYTES_IN, "Xact Log Bytes In", "xlog", "in", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes read from the transaction log files" }, + { XT_STAT_XLOG_BYTES_OUT, "Xact Log Bytes Out", "xlog", "out", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes written from the transaction log files" }, + { XT_STAT_XLOG_SYNC_COUNT, "Xact Log File Syncs", "xlog", "syncs", XT_STAT_ACCUMULATIVE, + "Number of flushes to transaction log files" }, + { XT_STAT_XLOG_SYNC_TIME, "Xact Log Sync Time", "xlog", su_t_unit, XT_STAT_ACCUMULATIVE | XT_STAT_TIME_VALUE, + "The time in %sseconds to flush transaction log files" }, + { XT_STAT_XLOG_CACHE_HIT, "Xact Log Cache Hits", "xlog", "hits", XT_STAT_ACCUMULATIVE, + "Hits when accessing the transaction log cache" }, + { XT_STAT_XLOG_CACHE_MISS, "Xact Log Cache Misses","xlog", "miss", XT_STAT_ACCUMULATIVE, + "Misses when accessing the transaction log cache" }, + { XT_STAT_XLOG_CACHE_USAGE, "Xact Log Cache Usage", "xlog", "%use", XT_STAT_PERCENTAGE, + "Percentage of transaction log cache used" }, + + { XT_STAT_DATA_BYTES_IN, "Data Log Bytes In", "data", "in", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes read from the data log files" }, + { XT_STAT_DATA_BYTES_OUT, "Data Log Bytes Out", "data", "out", XT_STAT_ACCUMULATIVE | XT_STAT_BYTE_COUNT, + "Bytes written from the data log files" }, + { XT_STAT_DATA_SYNC_COUNT, "Data Log File Syncs", "data", "syncs", XT_STAT_ACCUMULATIVE, + "Number of flushes to data log files" }, + { XT_STAT_DATA_SYNC_TIME, "Data Log Sync Time", "data", su_t_unit, XT_STAT_ACCUMULATIVE | XT_STAT_TIME_VALUE, + "The time in %sseconds to flush data log files" }, + + { XT_STAT_BYTES_TO_CHKPNT, "Bytes to Checkpoint", "to", "chkpt", XT_STAT_BYTE_COUNT, + "Bytes written to the log since the last checkpoint" }, + { XT_STAT_LOG_BYTES_TO_WRITE, "Log Bytes to Write", "to", "write", XT_STAT_BYTE_COUNT, + "Bytes written to the log, still to be written to the database" }, + { XT_STAT_BYTES_TO_SWEEP, "Log Bytes to Sweep", "to", "sweep", XT_STAT_BYTE_COUNT, + "Bytes written to the log, still to be read by the sweeper" }, + { XT_STAT_SWEEPER_WAITS, "Sweeper Wait on Xact", "sweep", "waits", XT_STAT_ACCUMULATIVE, + "Attempts to cleanup a transaction" }, + + { XT_STAT_SCAN_INDEX, "Index Scan Count", "scan", "index", XT_STAT_ACCUMULATIVE, + "Number of index scans" }, + { XT_STAT_SCAN_TABLE, "Table Scan Count", "scan", "table", XT_STAT_ACCUMULATIVE, + "Number of table scans" }, + { XT_STAT_ROW_SELECT, "Select Row Count", "row", "sel", XT_STAT_ACCUMULATIVE, + "Number of rows selected" }, + { XT_STAT_ROW_INSERT, "Insert Row Count", "row", "ins", XT_STAT_ACCUMULATIVE, + "Number of rows inserted" }, + { XT_STAT_ROW_UPDATE, "Update Row Count", "row", "upd", XT_STAT_ACCUMULATIVE, + "Number of rows updated" }, + { XT_STAT_ROW_DELETE, "Delete Row Count", "row", "del", XT_STAT_ACCUMULATIVE, + "Number of rows deleted" }, + + { XT_STAT_RETRY_INDEX_SCAN, "Index Scan Retries", "retry", "iscan", XT_STAT_ACCUMULATIVE, + "Index scans restarted because of locked record" }, + { XT_STAT_REREAD_REC_LIST, "Record List Rereads", "retry", "rlist", XT_STAT_ACCUMULATIVE, + "Record list rescanned due to lock" } +}; + +xtPublic XTStatMetaDataPtr xt_get_stat_meta_data(int i) +{ + return &pbxt_stat_meta_data[i]; +} + +xtPublic void xt_set_time_unit(const char *u) +{ + xt_strcpy(10, su_t_unit, u); +} + diff --git a/storage/pbxt/src/strutil_xt.h b/storage/pbxt/src/strutil_xt.h new file mode 100644 index 00000000000..62067e0b671 --- /dev/null +++ b/storage/pbxt/src/strutil_xt.h @@ -0,0 +1,164 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-03 Paul McCullagh + * + * H&G2JCtL + */ + +#ifndef __xt_strutil_h__ +#define __xt_strutil_h__ + +#include <string.h> + +#include "xt_defs.h" + +#ifdef XT_WIN +#define XT_DIR_CHAR '\\' +#define XT_IS_DIR_CHAR(c) ((c) == '/' || (c) == '\\') +#else +#define XT_DIR_CHAR '/' +#define XT_IS_DIR_CHAR(c) ((c) == '/') +#endif + +#define MAX_INT8_STRING_SIZE 100 + +void xt_strcpy(size_t size, char *to, c_char *from); +void xt_strncpy(size_t size, char *to, c_char *from, size_t len_from); +void xt_strcat(size_t size, char *to, c_char *from); +void xt_strcati(size_t size, char *to, int i); +void xt_strcpy_term(size_t size, char *to, c_char *from, char term); +void xt_strcat_term(size_t size, char *to, c_char *from, char term); + +xtBool xt_ends_with(c_char *str, c_char *sub); +xtBool xt_starts_with(c_char *str, c_char *sub); + +char *xt_last_2_names_of_path(c_char *path); +char *xt_last_name_of_path(c_char *path); +void xt_2nd_last_name_of_path(size_t size, char *dest, c_char *path); +c_char *xt_last_directory_of_path(c_char *path); +xtBool xt_remove_dir_char(char *dir_name); +xtBool xt_add_dir_char(size_t max, char *path); +void xt_remove_last_name_of_path(char *path); +char *xt_find_extension(c_char *file_name); +void xt_remove_extension(char *file_name); +xtBool xt_is_extension(c_char *file_name, c_char *ext); + +xtInt8 xt_str_to_int8(c_char *ptr, xtBool *overflow); +void xt_int8_to_str(xtInt8 value, char *string); +void xt_double_to_str(double value, int scale, char *string); + +xtInt8 xt_byte_size_to_int8(c_char *ptr); +void xt_int8_to_byte_size(xtInt8 value, char *string); + +c_char *xt_get_version(void); + +void xt_strcpy_url(size_t size, char *to, c_char *from); +void xt_strncpy_url(size_t size, char *to, c_char *from, size_t len_from); + +const char *xt_strchr(const char *str, char ch); +unsigned char xt_hex_digit(char ch); + +#define XT_STAT_TIME_CURRENT 0 +#define XT_STAT_TIME_PASSED 1 + +#define XT_STAT_COMMITS 2 +#define XT_STAT_ROLLBACKS 3 +#define XT_STAT_WAIT_FOR_XACT 4 +#define XT_STAT_XACT_TO_CLEAN 5 + +#define XT_STAT_STAT_READS 6 +#define XT_STAT_STAT_WRITES 7 + +#define XT_STAT_REC_BYTES_IN 8 +#define XT_STAT_REC_BYTES_OUT 9 +#define XT_STAT_REC_SYNC_COUNT 10 +#define XT_STAT_REC_SYNC_TIME 11 +#define XT_STAT_REC_CACHE_HIT 12 +#define XT_STAT_REC_CACHE_MISS 13 +#define XT_STAT_REC_CACHE_FREES 14 +#define XT_STAT_REC_CACHE_USAGE 15 + +#define XT_STAT_IND_BYTES_IN 16 +#define XT_STAT_IND_BYTES_OUT 17 +#define XT_STAT_IND_SYNC_COUNT 18 +#define XT_STAT_IND_SYNC_TIME 19 +#define XT_STAT_IND_CACHE_HIT 20 +#define XT_STAT_IND_CACHE_MISS 21 +#define XT_STAT_IND_CACHE_USAGE 22 +#define XT_STAT_ILOG_BYTES_IN 23 +#define XT_STAT_ILOG_BYTES_OUT 24 +#define XT_STAT_ILOG_SYNC_COUNT 25 +#define XT_STAT_ILOG_SYNC_TIME 26 + +#define XT_STAT_XLOG_BYTES_IN 27 +#define XT_STAT_XLOG_BYTES_OUT 28 +#define XT_STAT_XLOG_SYNC_COUNT 29 +#define XT_STAT_XLOG_SYNC_TIME 30 +#define XT_STAT_XLOG_CACHE_HIT 31 +#define XT_STAT_XLOG_CACHE_MISS 32 +#define XT_STAT_XLOG_CACHE_USAGE 33 + +#define XT_STAT_DATA_BYTES_IN 34 +#define XT_STAT_DATA_BYTES_OUT 35 +#define XT_STAT_DATA_SYNC_COUNT 36 +#define XT_STAT_DATA_SYNC_TIME 37 + +#define XT_STAT_BYTES_TO_CHKPNT 38 +#define XT_STAT_LOG_BYTES_TO_WRITE 39 +#define XT_STAT_BYTES_TO_SWEEP 40 +#define XT_STAT_SWEEPER_WAITS 41 + +#define XT_STAT_SCAN_INDEX 42 +#define XT_STAT_SCAN_TABLE 43 +#define XT_STAT_ROW_SELECT 44 +#define XT_STAT_ROW_INSERT 45 +#define XT_STAT_ROW_UPDATE 46 +#define XT_STAT_ROW_DELETE 47 + +#define XT_STAT_CURRENT_MAX 48 + +#define XT_STAT_RETRY_INDEX_SCAN 48 +#define XT_STAT_REREAD_REC_LIST 49 +#define XT_STAT_MAXIMUM 50 + +#define XT_STAT_ACCUMULATIVE 1 +#define XT_STAT_BYTE_COUNT 2 +#define XT_STAT_PERCENTAGE 4 +#define XT_STAT_COMBO_FIELD 8 /* Field is short, 2 chars instead of 5. */ +#define XT_STAT_COMBO_FIELD_2 16 /* Field is short, 2 chars instead of 5. */ +#define XT_STAT_TIME_VALUE 32 +#define XT_STAT_DATE 64 + +typedef struct XTStatMetaData { + int sm_id; + const char *sm_name; + const char *sm_short_line_1; + const char *sm_short_line_2; + int sm_flags; + const char *sm_description; +} XTStatMetaDataRec, *XTStatMetaDataPtr; + +XTStatMetaDataPtr xt_get_stat_meta_data(int i); +void xt_set_time_unit(const char *u); + +#ifdef XT_WIN +void xt_win_dialog(char *message); +#endif + +#endif diff --git a/storage/pbxt/src/systab_xt.cc b/storage/pbxt/src/systab_xt.cc new file mode 100644 index 00000000000..73ecc7a07cb --- /dev/null +++ b/storage/pbxt/src/systab_xt.cc @@ -0,0 +1,656 @@ +/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany + * + * PrimeBase Media Stream for MySQL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Paul McCullagh + * + * 2007-07-18 + * + * H&G2JCtL + * + * System tables. + * + */ + +#include "xt_config.h" + +#include <stdlib.h> +#include <time.h> +#ifdef DRIZZLED +#include <drizzled/server_includes.h> +#include <drizzled/current_session.h> +#endif + +#include "ha_pbxt.h" +#include "systab_xt.h" +#include "discover_xt.h" +#include "table_xt.h" +#include "strutil_xt.h" +#include "database_xt.h" +#include "trace_xt.h" + +#if MYSQL_VERSION_ID >= 50120 +#define byte uchar +#endif + +/* + * ------------------------------------------------------------------------- + * SYSTEM TABLE DEFINITIONS + */ + +//-------------------------------- +static DT_FIELD_INFO xt_location_info[] = +{ + { "Path", 128, NULL, MYSQL_TYPE_VARCHAR, (CHARSET_INFO *) system_charset_info, 0, "The location of PBXT tables"}, + { "Table_count", 0, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The number of PBXT table in this location"}, + { NULL, 0, NULL, MYSQL_TYPE_STRING, NULL, 0, NULL} +}; + +static DT_FIELD_INFO xt_statistics_info[] = +{ + { "ID", 0, NULL, MYSQL_TYPE_LONG, NULL, NOT_NULL_FLAG, "The ID of the statistic"}, + { "Name", 40, NULL, MYSQL_TYPE_VARCHAR, (CHARSET_INFO *) system_charset_info, 0, "The name of the statistic"}, + { "Value", 0, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The accumulated value"}, + { NULL, 0, NULL, MYSQL_TYPE_STRING, NULL, 0, NULL} +}; + +/* +static DT_FIELD_INFO xt_reference_info[] = +{ + {"Table_name", 128, NULL, MYSQL_TYPE_STRING, system_charset_info, NOT_NULL_FLAG, "The name of the referencing table"}, + {"Blob_id", NULL, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The BLOB reference number - part of the BLOB URL"}, + {"Column_name", 50, NULL, MYSQL_TYPE_STRING, system_charset_info, NOT_NULL_FLAG, "The column name of the referencing field"}, + {"Row_condition", 50, NULL, MYSQL_TYPE_VARCHAR, system_charset_info, 0, "This condition identifies the row in the table"}, + {"Blob_url", 50, NULL, MYSQL_TYPE_VARCHAR, system_charset_info, NOT_NULL_FLAG, "The BLOB URL for HTTP GET access"}, + {"Repository_id", NULL, NULL, MYSQL_TYPE_LONG, NULL, NOT_NULL_FLAG, "The repository file number of the BLOB"}, + {"Repo_blob_offset",NULL, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The offset in the repository file"}, + {"Blob_size", NULL, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The size of the BLOB in bytes"}, + {"Deletion_time", NULL, NULL, MYSQL_TYPE_TIMESTAMP, NULL, 0, "The time the BLOB was deleted"}, + {"Remove_in", NULL, NULL, MYSQL_TYPE_LONG, NULL, 0, "The number of seconds before the reference/BLOB is removed perminently"}, + {"Temp_log_id", NULL, NULL, MYSQL_TYPE_LONG, NULL, 0, "Temporary log number of the referencing deletion entry"}, + {"Temp_log_offset", NULL, NULL, MYSQL_TYPE_LONGLONG, NULL, 0, "Temporary log offset of the referencing deletion entry"}, + {NULL, NULL, NULL, MYSQL_TYPE_STRING, NULL, 0, NULL} +}; +*/ + +#define XT_SYSTAB_INVALID 0 +#define XT_SYSTAB_LOCATION_ID 1 +#define XT_SYSTAB_STATISTICS_ID 2 + +static THR_LOCK sys_location_lock; +static THR_LOCK sys_statistics_lock; +static xtBool sys_lock_inited = FALSE; + +static XTSystemTableShareRec xt_internal_tables[] = +{ + { XT_SYSTAB_LOCATION_ID, "pbxt.location", &sys_location_lock, xt_location_info, NULL, FALSE}, + { XT_SYSTAB_STATISTICS_ID, "pbxt.statistics", &sys_statistics_lock, xt_statistics_info, NULL, FALSE}, + { XT_SYSTAB_INVALID, NULL, NULL, NULL, NULL, FALSE} +}; + + +/* +static int pbms_discover_handler(handlerton *hton, THD* thd, const char *db, const char *name, uchar **frmblob, size_t *frmlen) +{ + int err = 1, i = 0; + MY_STAT stat_info; + + // Check that the database exists! + if ((!db) || ! my_stat(db,&stat_info,MYF(0))) + return err; + + while (pbms_internal_tables[i].name) { + if (!strcasecmp(name, pbms_internal_tables[i].name)) { + err = ms_create_table_frm(hton, thd, db, name, pbms_internal_tables[i].info, pbms_internal_tables[i].keys, frmblob, frmlen); + break; + } + i++; + } + + return err; +} +*/ + +/* + * ------------------------------------------------------------------------- + * MYSQL UTILITIES + */ + +void xt_my_set_notnull_in_record(Field *field, char *record) +{ + if (field->null_ptr) + record[(uint) (field->null_ptr - (uchar *) field->table->record[0])] &= (uchar) ~field->null_bit; +} + +/* + * ------------------------------------------------------------------------- + * OPEN SYSTEM TABLES + */ + +XTOpenSystemTable::XTOpenSystemTable(XTThreadPtr self, XTDatabaseHPtr db, XTSystemTableShare *share, TABLE *table): +XTObject() +{ + ost_share = share; + ost_my_table = table; + ost_db = db; + xt_heap_reference(self, db); +} + +XTOpenSystemTable::~XTOpenSystemTable() +{ + XTSystemTableShare::releaseSystemTable(this); +} + +/* + * ------------------------------------------------------------------------- + * LOCATION TABLE + */ + +XTLocationTable::XTLocationTable(XTThreadPtr self, XTDatabaseHPtr db, XTSystemTableShare *share, TABLE *table): +XTOpenSystemTable(self, db, share, table) +{ +} + +XTLocationTable::~XTLocationTable() +{ + unuse(); +} + +bool XTLocationTable::use() +{ + return true; +} + +bool XTLocationTable::unuse() +{ + return true; +} + + +bool XTLocationTable::seqScanInit() +{ + lt_index = 0; + return true; +} + +bool XTLocationTable::seqScanNext(char *buf, bool *eof) +{ + bool ok = true; + + *eof = false; + + xt_ht_lock(NULL, ost_db->db_tables); + if (lt_index >= xt_sl_get_size(ost_db->db_table_paths)) { + ok = false; + *eof = true; + goto done; + } + loadRow(buf, lt_index); + lt_index++; + + done: + xt_ht_unlock(NULL, ost_db->db_tables); + return ok; +#ifdef xxx + csWord4 last_access; + csWord4 last_ref; + csWord4 creation_time; + csWord4 access_code; + csWord2 cont_type; + size_t ref_size; + csWord2 head_size; + csWord8 blob_size; + uint32 len; + Field *curr_field; + byte *save; + MY_BITMAP *save_write_set; + + last_access = CS_GET_DISK_4(blob->rb_last_access_4); + last_ref = CS_GET_DISK_4(blob->rb_last_ref_4); + creation_time = CS_GET_DISK_4(blob->rb_create_time_4); + cont_type = CS_GET_DISK_2(blob->rb_cont_type_2); + ref_size = CS_GET_DISK_1(blob->rb_ref_size_1); + head_size = CS_GET_DISK_2(blob->rb_head_size_2); + blob_size = CS_GET_DISK_6(blob->rb_blob_size_6); + access_code = CS_GET_DISK_4(blob->rb_auth_code_4); + + /* ASSERT_COLUMN_MARKED_FOR_WRITE is failing when + * I use store()!?? + * But I want to use it! :( + */ + save_write_set = table->write_set; + table->write_set = NULL; + + memset(buf, 0xFF, table->s->null_bytes); + for (Field **field=table->field ; *field ; field++) { + curr_field = *field; + + save = curr_field->ptr; +#if MYSQL_VERSION_ID < 50114 + curr_field->ptr = (byte *) buf + curr_field->offset(); +#else + curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]); +#endif + switch (curr_field->field_name[0]) { + case 'A': + ASSERT(strcmp(curr_field->field_name, "Access_code") == 0); + curr_field->store(access_code, true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'R': + switch (curr_field->field_name[6]) { + case 't': + // Repository_id INT + ASSERT(strcmp(curr_field->field_name, "Repository_id") == 0); + curr_field->store(iRepoFile->myRepo->getRepoID(), true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'l': + // Repo_blob_offset BIGINT + ASSERT(strcmp(curr_field->field_name, "Repo_blob_offset") == 0); + curr_field->store(iRepoOffset, true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + } + break; + case 'B': + switch (curr_field->field_name[5]) { + case 's': + // Blob_size BIGINT + ASSERT(strcmp(curr_field->field_name, "Blob_size") == 0); + curr_field->store(blob_size, true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'd': + // Blob_data LONGBLOB + ASSERT(strcmp(curr_field->field_name, "Blob_data") == 0); + if (blob_size <= 0xFFFFFFF) { + iBlobBuffer->setLength((u_int) blob_size); + len = iRepoFile->read(iBlobBuffer->getBuffer(0), iRepoOffset + head_size, (size_t) blob_size, 0); + ((Field_blob *) curr_field)->set_ptr(len, (byte *) iBlobBuffer->getBuffer(0)); + xt_my_set_notnull_in_record(curr_field, buf); + } + break; + } + break; + case 'H': + // Head_size SMALLINT UNSIGNED + ASSERT(strcmp(curr_field->field_name, "Head_size") == 0); + curr_field->store(head_size, true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'C': + switch (curr_field->field_name[1]) { + case 'r': + // Creation_time TIMESTAMP + ASSERT(strcmp(curr_field->field_name, "Creation_time") == 0); + curr_field->store(ms_my_1970_to_mysql_time(creation_time), true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'o': + // Content_type CHAR(128) + ASSERT(strcmp(curr_field->field_name, "Content_type") == 0); + CSString *cont_type_str = ost_share->mySysDatabase->getContentType(cont_type); + if (cont_type_str) { + curr_field->store(cont_type_str->getCString(), cont_type_str->length(), &my_charset_utf8_general_ci); + cont_type_str->release(); + xt_my_set_notnull_in_record(curr_field, buf); + } + break; + } + break; + case 'L': + switch (curr_field->field_name[5]) { + case 'r': + // Last_ref_time TIMESTAMP + ASSERT(strcmp(curr_field->field_name, "Last_ref_time") == 0); + curr_field->store(ms_my_1970_to_mysql_time(last_ref), true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'a': + // Last_access_time TIMESTAMP + ASSERT(strcmp(curr_field->field_name, "Last_access_time") == 0); + curr_field->store(ms_my_1970_to_mysql_time(last_access), true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + } + break; + } + curr_field->ptr = save; + } + + table->write_set = save_write_set; + return true; +#endif + return false; +} + +void XTLocationTable::loadRow(char *buf, xtWord4 row_id) +{ + TABLE *table = ost_my_table; + Field *curr_field; + XTTablePathPtr tp_ptr; + byte *save; + MY_BITMAP *save_write_set; + + /* ASSERT_COLUMN_MARKED_FOR_WRITE is failing when + * I use store()!?? + * But I want to use it! :( + */ + save_write_set = table->write_set; + table->write_set = NULL; + + memset(buf, 0xFF, table->s->null_bytes); + + tp_ptr = *((XTTablePathPtr *) xt_sl_item_at(ost_db->db_table_paths, row_id)); + + for (Field **field=table->field ; *field ; field++) { + curr_field = *field; + + save = curr_field->ptr; +#if MYSQL_VERSION_ID < 50114 + curr_field->ptr = (byte *) buf + curr_field->offset(); +#else + curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]); +#endif + switch (curr_field->field_name[0]) { + case 'P': + // Path VARCHAR(128) + ASSERT_NS(strcmp(curr_field->field_name, "Path") == 0); + curr_field->store(tp_ptr->tp_path, strlen(tp_ptr->tp_path), &my_charset_utf8_general_ci); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'T': + // Table_count INT + ASSERT_NS(strcmp(curr_field->field_name, "Table_count") == 0); + curr_field->store(tp_ptr->tp_tab_count, true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + } + curr_field->ptr = save; + } + table->write_set = save_write_set; +} + +xtWord4 XTLocationTable::seqScanPos(xtWord1 *buf __attribute__((unused))) +{ + return lt_index-1; +} + +bool XTLocationTable::seqScanRead(xtWord4 rec_id, char *buf) +{ + loadRow(buf, rec_id); + return true; +} + +/* + * ------------------------------------------------------------------------- + * STATISTICS TABLE + */ + +XTStatisticsTable::XTStatisticsTable(XTThreadPtr self, XTDatabaseHPtr db, XTSystemTableShare *share, TABLE *table): +XTOpenSystemTable(self, db, share, table) +{ +} + +XTStatisticsTable::~XTStatisticsTable() +{ + unuse(); +} + +bool XTStatisticsTable::use() +{ + return true; +} + +bool XTStatisticsTable::unuse() +{ + return true; +} + + +bool XTStatisticsTable::seqScanInit() +{ + tt_index = 0; + xt_gather_statistics(&tt_statistics); + return true; +} + +bool XTStatisticsTable::seqScanNext(char *buf, bool *eof) +{ + bool ok = true; + + *eof = false; + + if (tt_index >= XT_STAT_CURRENT_MAX) { + ok = false; + *eof = true; + goto done; + } + loadRow(buf, tt_index); + tt_index++; + + done: + return ok; +} + +void XTStatisticsTable::loadRow(char *buf, xtWord4 rec_id) +{ + TABLE *table = ost_my_table; + MY_BITMAP *save_write_set; + Field *curr_field; + byte *save; + const char *stat_name; + u_llong stat_value; + + /* ASSERT_COLUMN_MARKED_FOR_WRITE is failing when + * I use store()!?? + * But I want to use it! :( + */ + save_write_set = table->write_set; + table->write_set = NULL; + + memset(buf, 0xFF, table->s->null_bytes); + + stat_name = xt_get_stat_meta_data(rec_id)->sm_name; + stat_value = xt_get_statistic(&tt_statistics, ost_db, rec_id); + + for (Field **field=table->field ; *field ; field++) { + curr_field = *field; + + save = curr_field->ptr; +#if MYSQL_VERSION_ID < 50114 + curr_field->ptr = (byte *) buf + curr_field->offset(); +#else + curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]); +#endif + switch (curr_field->field_name[0]) { + case 'I': + // Value BIGINT + ASSERT_NS(strcmp(curr_field->field_name, "ID") == 0); + curr_field->store(rec_id+1, true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'N': + // Name VARCHAR(40) + ASSERT_NS(strcmp(curr_field->field_name, "Name") == 0); + curr_field->store(stat_name, strlen(stat_name), &my_charset_utf8_general_ci); + xt_my_set_notnull_in_record(curr_field, buf); + break; + case 'V': + // Value BIGINT + ASSERT_NS(strcmp(curr_field->field_name, "Value") == 0); + curr_field->store(stat_value, true); + xt_my_set_notnull_in_record(curr_field, buf); + break; + } + curr_field->ptr = save; + } + table->write_set = save_write_set; +} + +xtWord4 XTStatisticsTable::seqScanPos(xtWord1 *buf __attribute__((unused))) +{ + return tt_index-1; +} + +bool XTStatisticsTable::seqScanRead(xtWord4 rec_id, char *buf) +{ + loadRow(buf, rec_id); + return true; +} + +/* + * ------------------------------------------------------------------------- + * SYSTEM TABLE SHARES + */ + +void st_path_to_table_name(size_t size, char *buffer, const char *path) +{ + char *str; + + xt_strcpy(size, buffer, xt_last_2_names_of_path(path)); + xt_remove_extension(buffer); + if ((str = strchr(buffer, '\\'))) + *str = '.'; + if ((str = strchr(buffer, '/'))) + *str = '.'; +} + +void XTSystemTableShare::startUp(XTThreadPtr self __attribute__((unused))) +{ + thr_lock_init(&sys_location_lock); + thr_lock_init(&sys_statistics_lock); + sys_lock_inited = TRUE; +} + +void XTSystemTableShare::shutDown(XTThreadPtr self __attribute__((unused))) +{ + if (sys_lock_inited) { + thr_lock_delete(&sys_location_lock); + thr_lock_delete(&sys_statistics_lock); + sys_lock_inited = FALSE; + } +} + +bool XTSystemTableShare::isSystemTable(const char *table_path) +{ + int i = 0; + char tab_name[100]; + + st_path_to_table_name(100, tab_name, table_path); + while (xt_internal_tables[i].sts_path) { + if (strcasecmp(tab_name, xt_internal_tables[i].sts_path) == 0) + return true; + i++; + } + return false; +} + +void XTSystemTableShare::setSystemTableDeleted(const char *table_path) +{ + int i = 0; + char tab_name[100]; + + st_path_to_table_name(100, tab_name, table_path); + while (xt_internal_tables[i].sts_path) { + if (strcasecmp(tab_name, xt_internal_tables[i].sts_path) == 0) { + xt_internal_tables[i].sts_exists = FALSE; + break; + } + i++; + } +} + +bool XTSystemTableShare::doesSystemTableExist() +{ + int i = 0; + + while (xt_internal_tables[i].sts_path) { + if (xt_internal_tables[i].sts_exists) + return true; + i++; + } + return false; +} + +void XTSystemTableShare::createSystemTables(XTThreadPtr self __attribute__((unused)), XTDatabaseHPtr db __attribute__((unused))) +{ + int i = 0; + + while (xt_internal_tables[i].sts_path) { + if (!xt_create_table_frm(pbxt_hton, + current_thd, "pbxt", + strchr(xt_internal_tables[i].sts_path, '.') + 1, + xt_internal_tables[i].sts_info, + xt_internal_tables[i].sts_keys, + TRUE /*do not recreate*/)) + xt_internal_tables[i].sts_exists = TRUE; + i++; + } +} + +XTOpenSystemTable *XTSystemTableShare::openSystemTable(XTThreadPtr self, const char *table_path, TABLE *table) +{ + XTSystemTableShare *share; + XTOpenSystemTable *otab = NULL; + int i = 0; + char tab_name[100]; + + st_path_to_table_name(100, tab_name, table_path); + while (xt_internal_tables[i].sts_path) { + if (strcasecmp(tab_name, xt_internal_tables[i].sts_path) == 0) { + share = &xt_internal_tables[i]; + goto found; + } + i++; + } + return NULL; + + found: + share->sts_exists = TRUE; + switch (share->sts_id) { + case XT_SYSTAB_LOCATION_ID: + if (!(otab = new XTLocationTable(self, self->st_database, share, table))) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + break; + case XT_SYSTAB_STATISTICS_ID: + if (!(otab = new XTStatisticsTable(self, self->st_database, share, table))) + xt_throw_errno(XT_CONTEXT, XT_ENOMEM); + break; + default: + xt_throw_taberr(XT_CONTEXT, XT_ERR_TABLE_NOT_FOUND, (XTPathStrPtr) table_path); + break; + } + + return otab; +} + +void XTSystemTableShare::releaseSystemTable(XTOpenSystemTable *tab) +{ + if (tab->ost_db) { + XTThreadPtr self = xt_get_self(); + + try_(a) { + xt_heap_release(self, tab->ost_db); + } + catch_(a) { + } + cont_(a); + tab->ost_db = NULL; + } +} diff --git a/storage/pbxt/src/systab_xt.h b/storage/pbxt/src/systab_xt.h new file mode 100644 index 00000000000..e64bcc816f4 --- /dev/null +++ b/storage/pbxt/src/systab_xt.h @@ -0,0 +1,155 @@ +/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Paul McCullagh + * + * 2007-07-18 + * + * H&G2JCtL + * + * PBXT System tables. + * + */ + +/* + +DROP TABLE IF EXISTS pbms_repository; +CREATE TABLE pbms_repository ( + Repository_id INT COMMENT 'The reppository file number', + Repo_blob_offset BIGINT COMMENT 'The offset of the BLOB in the repository file', + Blob_size BIGINT COMMENT 'The size of the BLOB in bytes', + Head_size SMALLINT UNSIGNED COMMENT 'The size of the BLOB header - preceeds the BLOB data', + Access_code INT COMMENT 'The 4-byte authorisation code required to access the BLOB - part of the BLOB URL', + Creation_time TIMESTAMP COMMENT 'The time the BLOB was created', + Last_ref_time TIMESTAMP COMMENT 'The last time the BLOB was referenced', + Last_access_time TIMESTAMP COMMENT 'The last time the BLOB was accessed (read)', + Content_type CHAR(128) COMMENT 'The content type of the BLOB - returned by HTTP GET calls', + Blob_data LONGBLOB COMMENT 'The data of this BLOB' +) ENGINE=PBMS; + + PRIMARY KEY (Repository_id, Repo_blob_offset) + +DROP TABLE IF EXISTS pbms_reference; +CREATE TABLE pbms_reference ( + Table_name CHAR(64) COMMENT 'The name of the referencing table', + Blob_id BIGINT COMMENT 'The BLOB reference number - part of the BLOB URL', + Column_name CHAR(64) COMMENT 'The column name of the referencing field', + Row_condition VARCHAR(255) COMMENT 'This condition identifies the row in the table', + Blob_url VARCHAR(200) COMMENT 'The BLOB URL for HTTP GET access', + Repository_id INT COMMENT 'The repository file number of the BLOB', + Repo_blob_offset BIGINT COMMENT 'The offset in the repository file', + Blob_size BIGINT COMMENT 'The size of the BLOB in bytes', + Deletion_time TIMESTAMP COMMENT 'The time the BLOB was deleted', + Remove_in INT COMMENT 'The number of seconds before the reference/BLOB is removed perminently', + Temp_log_id INT COMMENT 'Temporary log number of the referencing deletion entry', + Temp_log_offset BIGINT COMMENT 'Temporary log offset of the referencing deletion entry' +) ENGINE=PBMS; + + PRIMARY KEY (Table_name, Blob_id, Column_name, Condition) +*/ + +#ifndef __SYSTAB_XT_H__ +#define __SYSTAB_XT_H__ + +#include "ccutils_xt.h" +#include "discover_xt.h" +#include "thread_xt.h" + +struct XTSystemTableShare; +struct XTDatabase; + +class XTOpenSystemTable : public XTObject { +public: + XTSystemTableShare *ost_share; + TABLE *ost_my_table; + struct XTDatabase *ost_db; + + XTOpenSystemTable(XTThreadPtr self, struct XTDatabase *db, XTSystemTableShare *share, TABLE *table); + virtual ~XTOpenSystemTable(); + + virtual bool use() { return true; } + virtual bool unuse() { return true; } + virtual bool seqScanInit() { return true; } + virtual bool seqScanNext(char *buf __attribute__((unused)), bool *eof) { + *eof = true; + return false; + } + virtual int getRefLen() { return 4; } + virtual xtWord4 seqScanPos(xtWord1 *buf __attribute__((unused))) { + return 0; + } + virtual bool seqScanRead(xtWord4 rec_id __attribute__((unused)), char *buf __attribute__((unused))) { + return true; + } + +private: +}; + +class XTLocationTable : public XTOpenSystemTable { + u_int lt_index; + +public: + XTLocationTable(XTThreadPtr self, struct XTDatabase *db, XTSystemTableShare *share, TABLE *table); + virtual ~XTLocationTable(); + + virtual bool use(); + virtual bool unuse(); + virtual bool seqScanInit(); + virtual bool seqScanNext(char *buf, bool *eof); + virtual void loadRow(char *buf, xtWord4 row_id); + virtual xtWord4 seqScanPos(xtWord1 *buf); + virtual bool seqScanRead(xtWord4 rec_id, char *buf); +}; + +class XTStatisticsTable : public XTOpenSystemTable { + u_int tt_index; + XTStatisticsRec tt_statistics; + +public: + XTStatisticsTable(XTThreadPtr self, struct XTDatabase *db, XTSystemTableShare *share, TABLE *table); + virtual ~XTStatisticsTable(); + + virtual bool use(); + virtual bool unuse(); + virtual bool seqScanInit(); + virtual bool seqScanNext(char *buf, bool *eof); + virtual void loadRow(char *buf, xtWord4 row_id); + virtual xtWord4 seqScanPos(xtWord1 *buf); + virtual bool seqScanRead(xtWord4 rec_id, char *buf); +}; + +typedef struct XTSystemTableShare { + u_int sts_id; + const char *sts_path; + THR_LOCK *sts_my_lock; + DT_FIELD_INFO *sts_info; + DT_KEY_INFO *sts_keys; + xtBool sts_exists; + + static void startUp(XTThreadPtr self); + static void shutDown(XTThreadPtr self); + + static bool isSystemTable(const char *table_path); + static void setSystemTableDeleted(const char *table_path); + static bool doesSystemTableExist(); + static void createSystemTables(XTThreadPtr self, struct XTDatabase *db); + static XTOpenSystemTable *openSystemTable(XTThreadPtr self, const char *table_path, TABLE *table); + static void releaseSystemTable(XTOpenSystemTable *tab); +} XTSystemTableShareRec, *XTSystemTableSharePtr; + +#endif diff --git a/storage/pbxt/src/tabcache_xt.cc b/storage/pbxt/src/tabcache_xt.cc new file mode 100644 index 00000000000..b9f9ccd37e1 --- /dev/null +++ b/storage/pbxt/src/tabcache_xt.cc @@ -0,0 +1,1254 @@ +/* Copyright (c) 2007 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2007-10-30 Paul McCullagh + * + * H&G2JCtL + * + * The new table cache. Caches all non-index data. This includes the data + * files and the row pointer files. + */ + +#include "xt_config.h" + +#include <signal.h> + +#include "pthread_xt.h" +#include "tabcache_xt.h" +#include "table_xt.h" +#include "database_xt.h" +#include "trace_xt.h" +#include "myxt_xt.h" + +xtPublic XTTabCacheMemRec xt_tab_cache; + +static void tabc_fr_wait_for_cache(XTThreadPtr self, u_int msecs); + +xtPublic void xt_tc_set_cache_size(size_t cache_size) +{ + xt_tab_cache.tcm_cache_size = cache_size; + xt_tab_cache.tcm_low_level = cache_size / 4 * 3; // Current 75% + xt_tab_cache.tcm_high_level = cache_size / 100 * 95; // Current 95% +} + +/* + * Initialize the disk cache. + */ +xtPublic void xt_tc_init(XTThreadPtr self, size_t cache_size) +{ + xt_tc_set_cache_size(cache_size); + + xt_tab_cache.tcm_approx_page_count = cache_size / sizeof(XTTabCachePageRec); + /* Determine the size of the hash table. + * The size is set to 2* the number of pages! + */ + xt_tab_cache.tcm_hash_size = (xt_tab_cache.tcm_approx_page_count * 2) / XT_TC_SEGMENT_COUNT; + + try_(a) { + for (u_int i=0; i<XT_TC_SEGMENT_COUNT; i++) { + xt_tab_cache.tcm_segment[i].tcs_cache_in_use = 0; + xt_tab_cache.tcm_segment[i].tcs_hash_table = (XTTabCachePagePtr *) xt_calloc(self, xt_tab_cache.tcm_hash_size * sizeof(XTTabCachePagePtr)); + xt_rwmutex_init_with_autoname(self, &xt_tab_cache.tcm_segment[i].tcs_lock); + } + + xt_init_mutex_with_autoname(self, &xt_tab_cache.tcm_lock); + xt_init_cond(self, &xt_tab_cache.tcm_cond); + xt_init_mutex_with_autoname(self, &xt_tab_cache.tcm_freeer_lock); + xt_init_cond(self, &xt_tab_cache.tcm_freeer_cond); + } + catch_(a) { + xt_tc_exit(self); + throw_(); + } + cont_(a); +} + +xtPublic void xt_tc_exit(XTThreadPtr self) +{ + for (u_int i=0; i<XT_TC_SEGMENT_COUNT; i++) { + if (xt_tab_cache.tcm_segment[i].tcs_hash_table) { + if (xt_tab_cache.tcm_segment[i].tcs_cache_in_use) { + XTTabCachePagePtr page, tmp_page; + + for (size_t j=0; j<xt_tab_cache.tcm_hash_size; j++) { + page = xt_tab_cache.tcm_segment[i].tcs_hash_table[j]; + while (page) { + tmp_page = page; + page = page->tcp_next; + xt_free(self, tmp_page); + } + } + } + + xt_free(self, xt_tab_cache.tcm_segment[i].tcs_hash_table); + xt_tab_cache.tcm_segment[i].tcs_hash_table = NULL; + xt_rwmutex_free(self, &xt_tab_cache.tcm_segment[i].tcs_lock); + } + } + + xt_free_mutex(&xt_tab_cache.tcm_lock); + xt_free_cond(&xt_tab_cache.tcm_cond); + xt_free_mutex(&xt_tab_cache.tcm_freeer_lock); + xt_free_cond(&xt_tab_cache.tcm_freeer_cond); +} + +xtPublic xtInt8 xt_tc_get_usage() +{ + xtInt8 size = 0; + + for (u_int i=0; i<XT_TC_SEGMENT_COUNT; i++) { + size += xt_tab_cache.tcm_segment[i].tcs_cache_in_use; + } + return size; +} + +xtPublic xtInt8 xt_tc_get_size() +{ + return (xtInt8) xt_tab_cache.tcm_cache_size; +} + +xtPublic xtInt8 xt_tc_get_high() +{ + return (xtInt8) xt_tab_cache.tcm_cache_high; +} + +#ifdef DEBUG +xtPublic void xt_check_table_cache(XTTableHPtr tab) +{ + XTTabCachePagePtr page, ppage; + + xt_lock_mutex_ns(&xt_tab_cache.tcm_lock); + ppage = NULL; + page = xt_tab_cache.tcm_lru_page; + while (page) { + if (tab) { + if (page->tcp_db_id == tab->tab_db->db_id && page->tcp_tab_id == tab->tab_id) { + ASSERT_NS(!XTTableSeq::xt_op_is_before(tab->tab_seq.ts_next_seq, page->tcp_op_seq)); + } + } + ASSERT_NS(page->tcp_lr_used == ppage); + ppage = page; + page = page->tcp_mr_used; + } + ASSERT_NS(xt_tab_cache.tcm_mru_page == ppage); + xt_unlock_mutex_ns(&xt_tab_cache.tcm_lock); +} +#endif + +void XTTabCache::xt_tc_setup(XTTableHPtr tab, size_t head_size, size_t rec_size) +{ + tci_table = tab; + tci_header_size = head_size; + tci_rec_size = rec_size; + tci_rows_per_page = (XT_TC_PAGE_SIZE / rec_size) + 1; + if (tci_rows_per_page < 2) + tci_rows_per_page = 2; + tci_page_size = tci_rows_per_page * rec_size; +} + +/* + * This function assumes that we never write past the boundary of a page. + * This should be the case, because we should never write more than + * a row, and there are only whole rows on a page. + */ +xtBool XTTabCache::xt_tc_write(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t inc, size_t size, xtWord1 *data, xtOpSeqNo *op_seq, xtBool read, XTThreadPtr thread) +{ + size_t offset; + XTTabCachePagePtr page; + XTTabCacheSegPtr seg; + + /* + retry: + */ + if (!tc_fetch(file, ref_id, &seg, &page, &offset, read, thread)) + return FAILED; + /* Don't write while there is a read lock on the page, + * which can happen during a sequential scan... + * + * This will have to be OK. + * I cannot wait for the lock because a thread locks + * itself out when updating during a sequential scan. + * + * However, I don't think this is a problem, because + * the only records that are changed, are records + * containing uncommitted data. Such records should + * be ignored by a sequential scan. As long as + * we don't crash due to reading half written + * data! + * + if (page->tcp_lock_count) { + if (!xt_timed_wait_cond_ns(&seg->tcs_cond, &seg->tcs_lock, 100)) { + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + return FAILED; + } + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + // The page may have dissappeared from the cache, while we were sleeping! + goto retry; + } + */ + + ASSERT_NS(offset + inc + 4 <= tci_page_size); + memcpy(page->tcp_data + offset + inc, data, size); + /* GOTCHA, this was "op_seq > page->tcp_op_seq", however + * this does not handle overflow! + if (XTTableSeq::xt_op_is_before(page->tcp_op_seq, op_seq)) + page->tcp_op_seq = op_seq; + */ + + page->tcp_dirty = TRUE; + ASSERT_NS(page->tcp_db_id == tci_table->tab_db->db_id && page->tcp_tab_id == tci_table->tab_id); + *op_seq = tci_table->tab_seq.ts_set_op_seq(page); + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + return OK; +} + +/* + * This is a special version of write which is used to set the "clean" bit. + * The alternative would be to read the record first, but this + * is much quicker! + * + * This function also checks if xn_id, row_id and other data match (the checks + * are similar to xn_sw_cleanup_done) before modifying the record, otherwise it + * assumes that the record was already updated earlier and we must not set it to + * clean. + * + * If the record was not modified the function returns FALSE. + * + * The function has a self pointer and can throw an exception. + */ +xtBool XTTabCache::xt_tc_write_cond(XTThreadPtr self, XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord1 new_type, xtOpSeqNo *op_seq, + xtXactID xn_id, xtRowID row_id, u_int stat_id, u_int rec_type) +{ + size_t offset; + XTTabCachePagePtr page; + XTTabCacheSegPtr seg; + XTTabRecHeadDPtr rec_head; + + if (!tc_fetch(file, ref_id, &seg, &page, &offset, TRUE, self)) + xt_throw(self); + + ASSERT(offset + 1 <= tci_page_size); + + rec_head = (XTTabRecHeadDPtr)(page->tcp_data + offset); + + /* Transaction must match: */ + if (XT_GET_DISK_4(rec_head->tr_xact_id_4) != xn_id) + goto no_change; + + /* Record header must match expected value from + * log or clean has been done, or is not required. + * + * For example, it is not required if a record + * has been overwritten in a transaction. + */ + if (rec_head->tr_rec_type_1 != rec_type || + rec_head->tr_stat_id_1 != stat_id) + goto no_change; + + /* Row must match: */ + if (XT_GET_DISK_4(rec_head->tr_row_id_4) != row_id) + goto no_change; + + *(page->tcp_data + offset) = new_type; + + page->tcp_dirty = TRUE; + ASSERT(page->tcp_db_id == tci_table->tab_db->db_id && page->tcp_tab_id == tci_table->tab_id); + *op_seq = tci_table->tab_seq.ts_set_op_seq(page); + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + return TRUE; + + no_change: + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + return FALSE; +} + +xtBool XTTabCache::xt_tc_read(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t size, xtWord1 *data, XTThreadPtr thread) +{ + return tc_read_direct(file, ref_id, size, data, thread); +} + +xtBool XTTabCache::xt_tc_read_4(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord4 *value, XTThreadPtr thread) +{ + register u_int page_idx; + register XTTabCachePagePtr page; + register XTTabCacheSegPtr seg; + register u_int hash_idx; + register XTTabCacheMemPtr dcg = &xt_tab_cache; + off_t address; + + ASSERT_NS(ref_id); + ref_id--; + page_idx = ref_id / this->tci_rows_per_page; + address = (off_t) ref_id * (off_t) this->tci_rec_size + (off_t) this->tci_header_size; + + hash_idx = page_idx + (file->fr_id * 223); + seg = &dcg->tcm_segment[hash_idx & XT_TC_SEGMENT_MASK]; + hash_idx = (hash_idx >> XT_TC_SEGMENT_SHIFTS) % dcg->tcm_hash_size; + + xt_rwmutex_slock(&seg->tcs_lock, thread->t_id); + page = seg->tcs_hash_table[hash_idx]; + while (page) { + if (page->tcp_page_idx == page_idx && page->tcp_file_id == file->fr_id) { + size_t offset; + xtWord1 *buffer; + + offset = (ref_id % this->tci_rows_per_page) * this->tci_rec_size; + ASSERT_NS(offset + 4 <= this->tci_page_size); + buffer = page->tcp_data + offset; + *value = XT_GET_DISK_4(buffer); + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + return OK; + } + page = page->tcp_next; + } + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + +#ifdef XT_USE_ROW_REC_MMAP_FILES + return xt_pread_fmap_4(file, address, value, &thread->st_statistics.st_rec, thread); +#else + xtWord1 data[4]; + + if (!XT_PREAD_RR_FILE(file, address, 4, 4, data, NULL, &thread->st_statistics.st_rec, thread)) + return FAILED; + *value = XT_GET_DISK_4(data); + return OK; +#endif +} + +xtBool XTTabCache::xt_tc_get_page(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCachePagePtr *ret_page, size_t *offset, XTThreadPtr thread) +{ + XTTabCachePagePtr page; + XTTabCacheSegPtr seg; + +#ifdef XT_SEQ_SCAN_FROM_MEMORY + if (!tc_fetch_direct(file, ref_id, &seg, &page, offset, thread)) + return FAILED; + if (!seg) { + *ret_page = NULL; + return OK; + } +#else + if (!tc_fetch(file, ref_id, &seg, &page, offset, TRUE, thread)) + return FAILED; +#endif + page->tcp_lock_count++; + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + *ret_page = page; + return OK; +} + +void XTTabCache::xt_tc_release_page(XT_ROW_REC_FILE_PTR file __attribute__((unused)), XTTabCachePagePtr page, XTThreadPtr thread) +{ + XTTabCacheSegPtr seg; + + seg = &xt_tab_cache.tcm_segment[page->tcp_seg]; + xt_rwmutex_xlock(&seg->tcs_lock, thread->t_id); + +#ifdef DEBUG + XTTabCachePagePtr lpage, ppage; + + ppage = NULL; + lpage = seg->tcs_hash_table[page->tcp_hash_idx]; + while (lpage) { + if (lpage->tcp_page_idx == page->tcp_page_idx && + lpage->tcp_file_id == page->tcp_file_id) + break; + ppage = lpage; + lpage = lpage->tcp_next; + } + + ASSERT_NS(page == lpage); + ASSERT_NS(page->tcp_lock_count > 0); +#endif + + if (page->tcp_lock_count > 0) + page->tcp_lock_count--; + + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); +} + +xtBool XTTabCache::xt_tc_read_page(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord1 *data, XTThreadPtr thread) +{ + return tc_read_direct(file, ref_id, this->tci_page_size, data, thread); +} + +/* Read row and record files directly. + * This by-passed the cache when reading, which mean + * we rely in the OS for caching. + * This probably only makes sense when these files + * are memory mapped. + */ +xtBool XTTabCache::tc_read_direct(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t size, xtWord1 *data, XTThreadPtr thread) +{ + register u_int page_idx; + register XTTabCachePagePtr page; + register XTTabCacheSegPtr seg; + register u_int hash_idx; + register XTTabCacheMemPtr dcg = &xt_tab_cache; + size_t red_size; + off_t address; + + ASSERT_NS(ref_id); + ref_id--; + page_idx = ref_id / this->tci_rows_per_page; + address = (off_t) ref_id * (off_t) this->tci_rec_size + (off_t) this->tci_header_size; + + hash_idx = page_idx + (file->fr_id * 223); + seg = &dcg->tcm_segment[hash_idx & XT_TC_SEGMENT_MASK]; + hash_idx = (hash_idx >> XT_TC_SEGMENT_SHIFTS) % dcg->tcm_hash_size; + + xt_rwmutex_slock(&seg->tcs_lock, thread->t_id); + page = seg->tcs_hash_table[hash_idx]; + while (page) { + if (page->tcp_page_idx == page_idx && page->tcp_file_id == file->fr_id) { + size_t offset; + + offset = (ref_id % this->tci_rows_per_page) * this->tci_rec_size; + ASSERT_NS(offset + size <= this->tci_page_size); + memcpy(data, page->tcp_data + offset, size); + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + return OK; + } + page = page->tcp_next; + } + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + if (!XT_PREAD_RR_FILE(file, address, size, 0, data, &red_size, &thread->st_statistics.st_rec, thread)) + return FAILED; + memset(data + red_size, 0, size - red_size); + return OK; +} + +xtBool XTTabCache::tc_fetch_direct(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCacheSegPtr *ret_seg, XTTabCachePagePtr *ret_page, size_t *offset, XTThreadPtr thread) +{ + register u_int page_idx; + register XTTabCachePagePtr page; + register XTTabCacheSegPtr seg; + register u_int hash_idx; + register XTTabCacheMemPtr dcg = &xt_tab_cache; + + ASSERT_NS(ref_id); + ref_id--; + page_idx = ref_id / this->tci_rows_per_page; + *offset = (ref_id % this->tci_rows_per_page) * this->tci_rec_size; + + hash_idx = page_idx + (file->fr_id * 223); + seg = &dcg->tcm_segment[hash_idx & XT_TC_SEGMENT_MASK]; + hash_idx = (hash_idx >> XT_TC_SEGMENT_SHIFTS) % dcg->tcm_hash_size; + + xt_rwmutex_xlock(&seg->tcs_lock, thread->t_id); + page = seg->tcs_hash_table[hash_idx]; + while (page) { + if (page->tcp_page_idx == page_idx && page->tcp_file_id == file->fr_id) { + *ret_seg = seg; + *ret_page = page; + return OK; + } + page = page->tcp_next; + } + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + *ret_seg = NULL; + *ret_page = NULL; + return OK; +} + +/* + * Note, this function may return an exclusive, or a shared lock. + * If the page is in cache it will return a shared lock of the segment. + * If the page was just added to the cache it will return an + * exclusive lock. + */ +xtBool XTTabCache::tc_fetch(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCacheSegPtr *ret_seg, XTTabCachePagePtr *ret_page, size_t *offset, xtBool read, XTThreadPtr thread) +{ + register u_int page_idx; + register XTTabCachePagePtr page, new_page; + register XTTabCacheSegPtr seg; + register u_int hash_idx; + register XTTabCacheMemPtr dcg = &xt_tab_cache; + size_t red_size; + off_t address; + + ASSERT_NS(ref_id); + ref_id--; + page_idx = ref_id / this->tci_rows_per_page; + address = (off_t) page_idx * (off_t) this->tci_page_size + (off_t) this->tci_header_size; + *offset = (ref_id % this->tci_rows_per_page) * this->tci_rec_size; + + hash_idx = page_idx + (file->fr_id * 223); + seg = &dcg->tcm_segment[hash_idx & XT_TC_SEGMENT_MASK]; + hash_idx = (hash_idx >> XT_TC_SEGMENT_SHIFTS) % dcg->tcm_hash_size; + + xt_rwmutex_slock(&seg->tcs_lock, thread->t_id); + page = seg->tcs_hash_table[hash_idx]; + while (page) { + if (page->tcp_page_idx == page_idx && page->tcp_file_id == file->fr_id) { + /* This page has been most recently used: */ + if (XT_TIME_DIFF(page->tcp_ru_time, dcg->tcm_ru_now) > (dcg->tcm_approx_page_count >> 1)) { + /* Move to the front of the MRU list: */ + xt_lock_mutex_ns(&dcg->tcm_lock); + + page->tcp_ru_time = ++dcg->tcm_ru_now; + if (dcg->tcm_mru_page != page) { + /* Remove from the MRU list: */ + if (dcg->tcm_lru_page == page) + dcg->tcm_lru_page = page->tcp_mr_used; + if (page->tcp_lr_used) + page->tcp_lr_used->tcp_mr_used = page->tcp_mr_used; + if (page->tcp_mr_used) + page->tcp_mr_used->tcp_lr_used = page->tcp_lr_used; + + /* Make the page the most recently used: */ + if ((page->tcp_lr_used = dcg->tcm_mru_page)) + dcg->tcm_mru_page->tcp_mr_used = page; + page->tcp_mr_used = NULL; + dcg->tcm_mru_page = page; + if (!dcg->tcm_lru_page) + dcg->tcm_lru_page = page; + } + xt_unlock_mutex_ns(&dcg->tcm_lock); + } + *ret_seg = seg; + *ret_page = page; + thread->st_statistics.st_rec_cache_hit++; + return OK; + } + page = page->tcp_next; + } + xt_rwmutex_unlock(&seg->tcs_lock, thread->t_id); + + /* Page not found, allocate a new page: */ + size_t page_size = offsetof(XTTabCachePageRec, tcp_data) + this->tci_page_size; + if (!(new_page = (XTTabCachePagePtr) xt_malloc_ns(page_size))) + return FAILED; + /* Increment cache used. */ + seg->tcs_cache_in_use += page_size; + + /* Check the level of the cache: */ + size_t cache_used = 0; + for (int i=0; i<XT_TC_SEGMENT_COUNT; i++) + cache_used += dcg->tcm_segment[i].tcs_cache_in_use; + + if (cache_used > dcg->tcm_cache_high) + dcg->tcm_cache_high = cache_used; + + if (cache_used > dcg->tcm_cache_size) { + XTThreadPtr self; + time_t now; + + /* Wait for the cache level to go down. + * If this happens, then the freeer is not working fast + * enough! + */ + + /* But before I do this, I must flush my own log because: + * - The freeer might be waiting for a page to be cleaned. + * - The page can only be cleaned once it has been written to + * the database. + * - The writer cannot write the page data until it has been + * flushed to the log. + * - The log won't be flushed, unless this thread does it. + * So there could be a deadlock if I don't flush the log! + */ + if ((self = xt_get_self())) { + if (!xt_xlog_flush_log(self)) + goto failed; + } + + /* Wait for the free'er thread: */ + xt_lock_mutex_ns(&dcg->tcm_freeer_lock); + now = time(NULL); + do { + /* I have set the timeout to 2 here because of the following situation: + * 1. Transaction allocates an op seq + * 2. Transaction goes to update cache, but must wait for + * cache to be freed (after this, the op would be written to + * the log). + * 3. The free'er wants to free cache, but is waiting for the writter. + * 4. The writer cannot continue because an op seq is missing! + * So the writer is waiting for the transaction thread to write + * the op seq. + * - So we have a deadlock situation. + * - However, this situation can only occur if there is not enougn + * cache. + * The timeout helps, but will not solve the problem, unless we + * ignore cache level here, after a while, and just continue. + */ + + /* Wake freeer before we go to sleep: */ + if (!dcg->tcm_freeer_busy) { + if (!xt_broadcast_cond_ns(&dcg->tcm_freeer_cond)) + xt_log_and_clear_exception_ns(); + } + + dcg->tcm_threads_waiting++; +#ifdef DEBUG + if (!xt_timed_wait_cond_ns(&dcg->tcm_freeer_cond, &dcg->tcm_freeer_lock, 30000)) { + dcg->tcm_threads_waiting--; + break; + } +#else + if (!xt_timed_wait_cond_ns(&dcg->tcm_freeer_cond, &dcg->tcm_freeer_lock, 1000)) { + dcg->tcm_threads_waiting--; + break; + } +#endif + dcg->tcm_threads_waiting--; + + cache_used = 0; + for (int i=0; i<XT_TC_SEGMENT_COUNT; i++) + cache_used += dcg->tcm_segment[i].tcs_cache_in_use; + + if (cache_used <= dcg->tcm_high_level) + break; + /* + * If there is too little cache we can get stuck here. + * The problem is that seg numbers are allocated before fetching a + * record to be updated. + * + * It can happen that we end up waiting for that seq number + * to be written to the log before we can continue here. + * + * This happens as follows: + * 1. This thread waits for the freeer. + * 2. The freeer cannot free a page because it has not been + * written by the writter. + * 3. The writter cannot continue because it is waiting + * for a missing sequence number. + * 4. The missing sequence number is the one allocated + * before we entered this function! + * + * So don't wait for more than 5 seconds here! + */ + } + while (time(NULL) < now + 5); + xt_unlock_mutex_ns(&dcg->tcm_freeer_lock); + } + else if (cache_used > dcg->tcm_high_level) { + /* Wake up the freeer because the cache level, + * is higher than the high level. + */ + if (!dcg->tcm_freeer_busy) { + xt_lock_mutex_ns(&xt_tab_cache.tcm_freeer_lock); + if (!xt_broadcast_cond_ns(&xt_tab_cache.tcm_freeer_cond)) + xt_log_and_clear_exception_ns(); + xt_unlock_mutex_ns(&xt_tab_cache.tcm_freeer_lock); + } + } + + /* Read the page into memory.... */ + new_page->tcp_dirty = FALSE; + new_page->tcp_seg = (xtWord1) ((page_idx + (file->fr_id * 223)) & XT_TC_SEGMENT_MASK); + new_page->tcp_lock_count = 0; + new_page->tcp_hash_idx = hash_idx; + new_page->tcp_page_idx = page_idx; + new_page->tcp_file_id = file->fr_id; + new_page->tcp_db_id = this->tci_table->tab_db->db_id; + new_page->tcp_tab_id = this->tci_table->tab_id; + new_page->tcp_data_size = this->tci_page_size; + new_page->tcp_op_seq = 0; // Value not used because not dirty + + if (read) { + if (!XT_PREAD_RR_FILE(file, address, this->tci_page_size, 0, new_page->tcp_data, &red_size, &thread->st_statistics.st_rec, thread)) + goto failed; + } + +#ifdef XT_MEMSET_UNUSED_SPACE + /* Removing this is an optimization. It should not be required + * to clear the unused space in the page. + */ + memset(new_page->tcp_data + red_size, 0, this->tci_page_size - red_size); +#endif + + /* Add the page to the cache! */ + xt_rwmutex_xlock(&seg->tcs_lock, thread->t_id); + page = seg->tcs_hash_table[hash_idx]; + while (page) { + if (page->tcp_page_idx == page_idx && page->tcp_file_id == file->fr_id) { + /* Oops, someone else was faster! */ + xt_free_ns(new_page); + goto done_ok; + } + page = page->tcp_next; + } + page = new_page; + + /* Make the page the most recently used: */ + xt_lock_mutex_ns(&dcg->tcm_lock); + page->tcp_ru_time = ++dcg->tcm_ru_now; + if ((page->tcp_lr_used = dcg->tcm_mru_page)) + dcg->tcm_mru_page->tcp_mr_used = page; + page->tcp_mr_used = NULL; + dcg->tcm_mru_page = page; + if (!dcg->tcm_lru_page) + dcg->tcm_lru_page = page; + xt_unlock_mutex_ns(&dcg->tcm_lock); + + /* Add the page to the hash table: */ + page->tcp_next = seg->tcs_hash_table[hash_idx]; + seg->tcs_hash_table[hash_idx] = page; + + done_ok: + *ret_seg = seg; + *ret_page = page; +#ifdef DEBUG_CHECK_CACHE + //XT_TC_check_cache(); +#endif + thread->st_statistics.st_rec_cache_miss++; + return OK; + + failed: + xt_free_ns(new_page); + return FAILED; +} + + +/* ---------------------------------------------------------------------- + * OPERATION SEQUENCE + */ + +xtBool XTTableSeq::ts_log_no_op(XTThreadPtr thread, xtTableID tab_id, xtOpSeqNo op_seq) +{ + XTactNoOpEntryDRec ent_rec; + xtWord4 sum = (xtWord4) tab_id ^ (xtWord4) op_seq; + + ent_rec.no_status_1 = XT_LOG_ENT_NO_OP; + ent_rec.no_checksum_1 = XT_CHECKSUM_1(sum); + XT_SET_DISK_4(ent_rec.no_tab_id_4, tab_id); + XT_SET_DISK_4(ent_rec.no_op_seq_4, op_seq); + /* TODO - If this also fails we have a problem. + * From this point on we should actually not generate + * any more op IDs. The problem is that the + * some will be missing, so the writer will not + * be able to contniue. + */ + return xt_xlog_log_data(thread, sizeof(XTactNoOpEntryDRec), (XTXactLogBufferDPtr) &ent_rec, FALSE); +} + +#ifdef XT_NOT_INLINE +xtOpSeqNo XTTableSeq::ts_set_op_seq(XTTabCachePagePtr page) +{ + xtOpSeqNo seq; + + xt_lock_mutex_ns(&ts_ns_lock); + page->tcp_op_seq = seq = ts_next_seq++; + xt_unlock_mutex_ns(&ts_ns_lock); + return seq; +} + +xtOpSeqNo XTTableSeq::ts_get_op_seq() +{ + xtOpSeqNo seq; + + xt_lock_mutex_ns(&ts_ns_lock); + seq = ts_next_seq++; + xt_unlock_mutex_ns(&ts_ns_lock); + return seq; +} +#endif + +#ifdef XT_NOT_INLINE +/* + * Return TRUE if the current sequence is before the + * target (then) sequence number. This function + * takes into account overflow. Overflow is detected + * by checking the difference between the 2 values. + * If the difference is very large, then we + * assume overflow. + */ +xtBool XTTableSeq::xt_op_is_before(register xtOpSeqNo now, register xtOpSeqNo then) +{ + ASSERT_NS(sizeof(xtOpSeqNo) == 4); + /* The now time is being incremented. + * If it is after the then time (which is static, then + * it is not before! + */ + if (now >= then) { + if ((now - then) > (xtOpSeqNo) 0xFFFFFFFF/2) + return TRUE; + return FALSE; + } + + /* If it appears to be before, we still have to check + * for overflow. If the gap is bigger then half of + * the MAX value, then we can assume it has wrapped around + * because we know that no then can be so far in the + * future! + */ + if ((then - now) > (xtOpSeqNo) 0xFFFFFFFF/2) + return FALSE; + return TRUE; +} +#endif + + +/* ---------------------------------------------------------------------- + * F R E E E R P R O C E S S + */ + +/* + * Used by the writer to wake the freeer. + */ +xtPublic void xt_wr_wake_freeer(XTThreadPtr self) +{ + xt_lock_mutex(self, &xt_tab_cache.tcm_freeer_lock); + pushr_(xt_unlock_mutex, &xt_tab_cache.tcm_freeer_lock); + if (!xt_broadcast_cond_ns(&xt_tab_cache.tcm_freeer_cond)) + xt_log_and_clear_exception_ns(); + freer_(); // xt_unlock_mutex(&xt_tab_cache.tcm_freeer_lock) +} + +/* Wait for a transaction to quit: */ +static void tabc_fr_wait_for_cache(XTThreadPtr self, u_int msecs) +{ + if (!self->t_quit) + xt_timed_wait_cond(NULL, &xt_tab_cache.tcm_freeer_cond, &xt_tab_cache.tcm_freeer_lock, msecs); +} + +typedef struct TCResource { + XTOpenTablePtr tc_ot; +} TCResourceRec, *TCResourcePtr; + +static void tabc_free_fr_resources(XTThreadPtr self, TCResourcePtr tc) +{ + if (tc->tc_ot) { + xt_db_return_table_to_pool(self, tc->tc_ot); + tc->tc_ot = NULL; + } +} + +static XTTableHPtr tabc_get_table(XTThreadPtr self, TCResourcePtr tc, xtDatabaseID db_id, xtTableID tab_id) +{ + XTTableHPtr tab; + XTDatabaseHPtr db; + + if (tc->tc_ot) { + tab = tc->tc_ot->ot_table; + if (tab->tab_id == tab_id && tab->tab_db->db_id == db_id) + return tab; + + xt_db_return_table_to_pool(self, tc->tc_ot); + tc->tc_ot = NULL; + } + + if (!tc->tc_ot) { + if (!(db = xt_get_database_by_id(self, db_id))) + return NULL; + + pushr_(xt_heap_release, db); + tc->tc_ot = xt_db_open_pool_table(self, db, tab_id, NULL, TRUE); + freer_(); // xt_heap_release(db); + if (!tc->tc_ot) + return NULL; + } + + return tc->tc_ot->ot_table; +} + +/* + * Free the given page, or the least recently used page. + * Return the amount of bytes freed. + */ +static size_t tabc_free_page(XTThreadPtr self, TCResourcePtr tc) +{ + register XTTabCacheMemPtr dcg = &xt_tab_cache; + XTTableHPtr tab = NULL; + XTTabCachePagePtr page, lpage, ppage; + XTTabCacheSegPtr seg; + u_int page_cnt; + xtBool was_dirty; + +#ifdef DEBUG_CHECK_CACHE + //XT_TC_check_cache(); +#endif + dcg->tcm_free_try_count = 0; + + retry: + /* Note, handling the page is safe because + * there is only one free'er thread which + * can remove pages from the cache! + */ + page_cnt = 0; + if (!(page = dcg->tcm_lru_page)) { + dcg->tcm_free_try_count = 0; + return 0; + } + + retry_2: + if ((was_dirty = page->tcp_dirty)) { + /* Do all this stuff without a lock, because to + * have a lock while doing this is too expensive! + */ + + /* Wait for the page to be cleaned. */ + tab = tabc_get_table(self, tc, page->tcp_db_id, page->tcp_tab_id); + } + + seg = &dcg->tcm_segment[page->tcp_seg]; + xt_rwmutex_xlock(&seg->tcs_lock, self->t_id); + + if (page->tcp_dirty) { + if (!was_dirty) { + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + goto retry_2; + } + + if (tab) { + ASSERT(!XTTableSeq::xt_op_is_before(tab->tab_seq.ts_next_seq, page->tcp_op_seq+1)); + /* This should never happen. However, is has been occuring, + * during multi_update test on Windows. + * In particular it occurs after rename of a table, during ALTER. + * As if the table was not flushed before the rename!? + * To guard against an infinite loop below, I will just continue here. + */ + if (XTTableSeq::xt_op_is_before(tab->tab_seq.ts_next_seq, page->tcp_op_seq+1)) + goto go_on; + /* OK, we have the table, now we check where the current + * sequence number is. + */ + if (XTTableSeq::xt_op_is_before(tab->tab_head_op_seq, page->tcp_op_seq)) { + XTDatabaseHPtr db = tab->tab_db; + + rewait: + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + + /* Flush the log, in case this is holding up the + * writer! + */ + if (!db->db_xlog.xlog_flush(self)) { + dcg->tcm_free_try_count = 0; + xt_throw(self); + } + + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + + /* The freeer is now waiting: */ + db->db_wr_freeer_waiting = TRUE; + + /* If the writer is idle, wake it up. + * The writer will commit the changes to the database + * which will allow the freeer to free up the cache. + */ + if (db->db_wr_idle) { + if (!xt_broadcast_cond_ns(&db->db_wr_cond)) + xt_log_and_clear_exception_ns(); + } + + /* Go to sleep on the writer's condition. + * The writer will wake the free'er before it goes to + * sleep! + */ + tab->tab_wake_freeer_op = page->tcp_op_seq; + tab->tab_wr_wake_freeer = TRUE; + if (!xt_timed_wait_cond_ns(&db->db_wr_cond, &db->db_wr_lock, 30000)) { + tab->tab_wr_wake_freeer = FALSE; + db->db_wr_freeer_waiting = FALSE; + xt_throw(self); + } + tab->tab_wr_wake_freeer = FALSE; + db->db_wr_freeer_waiting = FALSE; + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + + xt_rwmutex_xlock(&seg->tcs_lock, self->t_id); + if (XTTableSeq::xt_op_is_before(tab->tab_head_op_seq, page->tcp_op_seq)) + goto rewait; + } + go_on:; + } + } + + /* Wait if the page is being read or locked. */ + if (page->tcp_lock_count) { + /* (1) If the page is being read, then we should not free + * it immediately. + * (2) If a page is locked, the locker may be waiting + * for the freeer to free some cache - this + * causes a deadlock. + * + * Therefore, we move on, and try to free another page... + */ + if (page_cnt < (dcg->tcm_approx_page_count >> 1)) { + /* Page has not changed MRU position, and we + * have looked at less than half of the pages. + * Go to the next page... + */ + if ((page = page->tcp_mr_used)) { + page_cnt++; + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + goto retry_2; + } + } + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + dcg->tcm_free_try_count++; + + /* Starting to spin, free the threads: */ + if (dcg->tcm_threads_waiting) { + if (!xt_broadcast_cond_ns(&dcg->tcm_freeer_cond)) + xt_log_and_clear_exception_ns(); + } + goto retry; + } + + /* Page is clean, remove from the hash table: */ + + /* Find the page on the list: */ + u_int page_idx = page->tcp_page_idx; + u_int file_id = page->tcp_file_id; + + ppage = NULL; + lpage = seg->tcs_hash_table[page->tcp_hash_idx]; + while (lpage) { + if (lpage->tcp_page_idx == page_idx && lpage->tcp_file_id == file_id) + break; + ppage = lpage; + lpage = lpage->tcp_next; + } + + if (page == lpage) { + /* Should be the case! */ + if (ppage) + ppage->tcp_next = page->tcp_next; + else + seg->tcs_hash_table[page->tcp_hash_idx] = page->tcp_next; + } +#ifdef DEBUG + else + ASSERT_NS(FALSE); +#endif + + /* Remove from the MRU list: */ + xt_lock_mutex_ns(&dcg->tcm_lock); + if (dcg->tcm_lru_page == page) + dcg->tcm_lru_page = page->tcp_mr_used; + if (dcg->tcm_mru_page == page) + dcg->tcm_mru_page = page->tcp_lr_used; + if (page->tcp_lr_used) + page->tcp_lr_used->tcp_mr_used = page->tcp_mr_used; + if (page->tcp_mr_used) + page->tcp_mr_used->tcp_lr_used = page->tcp_lr_used; + xt_unlock_mutex_ns(&dcg->tcm_lock); + + /* Free the page: */ + size_t freed_space = offsetof(XTTabCachePageRec, tcp_data) + page->tcp_data_size; + seg->tcs_cache_in_use -= freed_space; + xt_free_ns(page); + + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + self->st_statistics.st_rec_cache_frees++; + dcg->tcm_free_try_count = 0; + return freed_space; +} + +static void tabc_fr_main(XTThreadPtr self) +{ + register XTTabCacheMemPtr dcg = &xt_tab_cache; + TCResourceRec tc = { 0 }; + + xt_set_low_priority(self); + dcg->tcm_freeer_busy = TRUE; + + while (!self->t_quit) { + size_t cache_used, freed; + + pushr_(tabc_free_fr_resources, &tc); + + while (!self->t_quit) { + /* Total up the cache memory used: */ + cache_used = 0; + for (int i=0; i<XT_TC_SEGMENT_COUNT; i++) + cache_used += dcg->tcm_segment[i].tcs_cache_in_use; + if (cache_used > dcg->tcm_cache_high) { + dcg->tcm_cache_high = cache_used; + } + + /* Check if the cache usage is over 95%: */ + if (self->t_quit || cache_used < dcg->tcm_high_level) + break; + + /* Reduce cache to the 75% level: */ + while (!self->t_quit && cache_used > dcg->tcm_low_level) { + freed = tabc_free_page(self, &tc); + cache_used -= freed; + if (cache_used <= dcg->tcm_high_level) { + /* Wakeup any threads that are waiting for some cache to be + * freed. + */ + if (dcg->tcm_threads_waiting) { + if (!xt_broadcast_cond_ns(&dcg->tcm_freeer_cond)) + xt_log_and_clear_exception_ns(); + } + } + } + } + + freer_(); // tabc_free_fr_resources(&tc) + + xt_lock_mutex(self, &dcg->tcm_freeer_lock); + pushr_(xt_unlock_mutex, &dcg->tcm_freeer_lock); + + if (dcg->tcm_threads_waiting) { + /* Wake threads before we go to sleep: */ + if (!xt_broadcast_cond_ns(&dcg->tcm_freeer_cond)) + xt_log_and_clear_exception_ns(); + } + + /* Wait for a thread that allocates data to signal + * that the cache level has exceeeded the upper limit: + */ + xt_db_approximate_time = time(NULL); + dcg->tcm_freeer_busy = FALSE; + tabc_fr_wait_for_cache(self, 500); + //tabc_fr_wait_for_cache(self, 30*1000); + dcg->tcm_freeer_busy = TRUE; + xt_db_approximate_time = time(NULL); + freer_(); // xt_unlock_mutex(&dcg->tcm_freeer_lock) + } +} + +static void *tabc_fr_run_thread(XTThreadPtr self) +{ + int count; + void *mysql_thread; + + mysql_thread = myxt_create_thread(); + + while (!self->t_quit) { + try_(a) { + tabc_fr_main(self); + } + catch_(a) { + /* This error is "normal"! */ + if (!(self->t_exception.e_xt_err == XT_SIGNAL_CAUGHT && + self->t_exception.e_sys_err == SIGTERM)) + xt_log_and_clear_exception(self); + } + cont_(a); + + /* After an exception, pause before trying again... */ + /* Number of seconds */ +#ifdef DEBUG + count = 10; +#else + count = 2*60; +#endif + while (!self->t_quit && count > 0) { + xt_db_approximate_time = xt_trace_clock(); + sleep(1); + count--; + } + } + + myxt_destroy_thread(mysql_thread, TRUE); + return NULL; +} + +static void tabc_fr_free_thread(XTThreadPtr self, void *data __attribute__((unused))) +{ + if (xt_tab_cache.tcm_freeer_thread) { + xt_lock_mutex(self, &xt_tab_cache.tcm_freeer_lock); + pushr_(xt_unlock_mutex, &xt_tab_cache.tcm_freeer_lock); + xt_tab_cache.tcm_freeer_thread = NULL; + freer_(); // xt_unlock_mutex(&xt_tab_cache.tcm_freeer_lock) + } +} + +xtPublic void xt_start_freeer(XTThreadPtr self) +{ + xt_tab_cache.tcm_freeer_thread = xt_create_daemon(self, "free-er"); + xt_set_thread_data(xt_tab_cache.tcm_freeer_thread, NULL, tabc_fr_free_thread); + xt_run_thread(self, xt_tab_cache.tcm_freeer_thread, tabc_fr_run_thread); +} + +xtPublic void xt_quit_freeer(XTThreadPtr self) +{ + if (xt_tab_cache.tcm_freeer_thread) { + xt_lock_mutex(self, &xt_tab_cache.tcm_freeer_lock); + pushr_(xt_unlock_mutex, &xt_tab_cache.tcm_freeer_lock); + xt_terminate_thread(self, xt_tab_cache.tcm_freeer_thread); + freer_(); // xt_unlock_mutex(&xt_tab_cache.tcm_freeer_lock) + } +} + +xtPublic void xt_stop_freeer(XTThreadPtr self) +{ + XTThreadPtr thr_fr; + + if (xt_tab_cache.tcm_freeer_thread) { + xt_lock_mutex(self, &xt_tab_cache.tcm_freeer_lock); + pushr_(xt_unlock_mutex, &xt_tab_cache.tcm_freeer_lock); + + /* This pointer is safe as long as you have the transaction lock. */ + if ((thr_fr = xt_tab_cache.tcm_freeer_thread)) { + xtThreadID tid = thr_fr->t_id; + + /* Make sure the thread quits when woken up. */ + xt_terminate_thread(self, thr_fr); + + /* Wake the freeer to get it to quit: */ + if (!xt_broadcast_cond_ns(&xt_tab_cache.tcm_freeer_cond)) + xt_log_and_clear_exception_ns(); + + freer_(); // xt_unlock_mutex(&xt_tab_cache.tcm_freeer_lock) + + /* + * GOTCHA: This is a wierd thing but the SIGTERM directed + * at a particular thread (in this case the sweeper) was + * being caught by a different thread and killing the server + * sometimes. Disconcerting. + * (this may only be a problem on Mac OS X) + xt_kill_thread(thread); + */ + xt_wait_for_thread(tid, FALSE); + + /* PMC - This should not be necessary to set the signal here, but in the + * debugger the handler is not called!!? + thr_fr->t_delayed_signal = SIGTERM; + xt_kill_thread(thread); + */ + xt_tab_cache.tcm_freeer_thread = NULL; + } + else + freer_(); // xt_unlock_mutex(&xt_tab_cache.tcm_freeer_lock) + } +} + +xtPublic void xt_load_pages(XTThreadPtr self, XTOpenTablePtr ot) +{ + XTTableHPtr tab = ot->ot_table; + xtRecordID rec_id; + XTTabCachePagePtr page; + XTTabCacheSegPtr seg; + size_t poffset; + + rec_id = 1; + while (rec_id<tab->tab_row_eof_id) { + if (!tab->tab_rows.tc_fetch(ot->ot_row_file, rec_id, &seg, &page, &poffset, TRUE, self)) + xt_throw(self); + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + rec_id += tab->tab_rows.tci_rows_per_page; + } + + rec_id = 1; + while (rec_id<tab->tab_rec_eof_id) { + if (!tab->tab_recs.tc_fetch(ot->ot_rec_file, rec_id, &seg, &page, &poffset, TRUE, self)) + xt_throw(self); + xt_rwmutex_unlock(&seg->tcs_lock, self->t_id); + rec_id += tab->tab_recs.tci_rows_per_page; + } +} + + diff --git a/storage/pbxt/src/tabcache_xt.h b/storage/pbxt/src/tabcache_xt.h new file mode 100644 index 00000000000..694244835b4 --- /dev/null +++ b/storage/pbxt/src/tabcache_xt.h @@ -0,0 +1,250 @@ +/* Copyright (c) 2007 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2007-10-31 Paul McCullagh + * + * H&G2JCtL + * + * The new table cache. Caches all non-index data. This includes the data + * files and the row pointer files. + */ +#ifndef __tabcache_h__ +#define __tabcache_h__ + +struct XTTable; +struct XTOpenTable; +struct XTTabCache; + +#include "thread_xt.h" +#include "filesys_xt.h" +#include "lock_xt.h" + +#ifdef DEBUG +//#define XT_USE_CACHE_DEBUG_SIZES +//#define XT_NOT_INLINE +#endif + +#ifdef XT_USE_CACHE_DEBUG_SIZES + +#define XT_TC_PAGE_SIZE (4*1024) +#define XT_TC_SEGMENT_SHIFTS 1 + +#else + +#define XT_TC_PAGE_SIZE (32*1024) +#define XT_TC_SEGMENT_SHIFTS 3 + +#endif + +#define XT_TIME_DIFF(start, now) (\ + ((xtWord4) (now) < (xtWord4) (start)) ? \ + ((xtWord4) 0XFFFFFFFF - ((xtWord4) (start) - (xtWord4) (now))) : \ + ((xtWord4) (now) - (xtWord4) (start))) + +#define XT_TC_SEGMENT_COUNT ((off_t) 1 << XT_TC_SEGMENT_SHIFTS) +#define XT_TC_SEGMENT_MASK (XT_TC_SEGMENT_COUNT - 1) + +typedef struct XTTabCachePage { + xtWord1 tcp_dirty; /* TRUE if the page is dirty. */ + xtWord1 tcp_seg; /* Segement number of the page. */ + u_int tcp_lock_count; /* Number of read locks on this page. */ + u_int tcp_hash_idx; /* The hash index of the page. */ + u_int tcp_page_idx; /* The page address. */ + u_int tcp_file_id; /* The file id of the page. */ + xtDatabaseID tcp_db_id; /* The ID of the database. */ + xtTableID tcp_tab_id; /* The ID of the table of this cache page. */ + xtWord4 tcp_data_size; /* Size of the data on this page. */ + xtOpSeqNo tcp_op_seq; /* The operation sequence number (dirty pages have a operations sequence) */ + xtWord4 tcp_ru_time; /* If this is in the top 1/4 don't change position in MRU list. */ + struct XTTabCachePage *tcp_next; /* Pointer to next page on hash list, or next free page on free list. */ + struct XTTabCachePage *tcp_mr_used; /* More recently used pages. */ + struct XTTabCachePage *tcp_lr_used; /* Less recently used pages. */ + xtWord1 tcp_data[XT_TC_PAGE_SIZE]; /* This is actually tci_page_size! */ +} XTTabCachePageRec, *XTTabCachePagePtr; + +/* + * Each table has a "table operation sequence". This sequence is incremented by + * each operation on the table. Each operation in the log is tagged by a + * sequence number. + * + * The writter threads re-order operations in the log, and write the operations + * to the database in sequence. + * + * It is safe to free a cache page when the sequence number of the cache page, + * is less than or equal to the written sequence number. + */ +typedef struct XTTableSeq { + xtOpSeqNo ts_next_seq; /* The next sequence number for operations on the table. */ + xt_mutex_type ts_ns_lock; /* Lock for the next sequence number. */ + + xtBool ts_log_no_op(XTThreadPtr thread, xtTableID tab_id, xtOpSeqNo op_seq); + + /* Return the next operation sequence number. */ +#ifdef XT_NOT_INLINE + xtOpSeqNo ts_set_op_seq(XTTabCachePagePtr page); + + xtOpSeqNo ts_get_op_seq(); +#else + xtOpSeqNo ts_set_op_seq(XTTabCachePagePtr page) + { + xtOpSeqNo seq; + + xt_lock_mutex_ns(&ts_ns_lock); + page->tcp_op_seq = seq = ts_next_seq++; + xt_unlock_mutex_ns(&ts_ns_lock); + return seq; + } + + xtOpSeqNo ts_get_op_seq() + { + xtOpSeqNo seq; + + xt_lock_mutex_ns(&ts_ns_lock); + seq = ts_next_seq++; + xt_unlock_mutex_ns(&ts_ns_lock); + return seq; + } +#endif + + void xt_op_seq_init(XTThreadPtr self) { + xt_init_mutex_with_autoname(self, &ts_ns_lock); + } + + void xt_op_seq_set(XTThreadPtr self __attribute__((unused)), xtOpSeqNo n) { + ts_next_seq = n; + } + + void xt_op_seq_exit(XTThreadPtr self __attribute__((unused))) { + xt_free_mutex(&ts_ns_lock); + } + +#ifdef XT_NOT_INLINE + static xtBool xt_op_is_before(register xtOpSeqNo now, register xtOpSeqNo then); +#else + static inline xtBool xt_op_is_before(register xtOpSeqNo now, register xtOpSeqNo then) + { + if (now >= then) { + if ((now - then) > (xtOpSeqNo) 0xFFFFFFFF/2) + return TRUE; + return FALSE; + } + if ((then - now) > (xtOpSeqNo) 0xFFFFFFFF/2) + return FALSE; + return TRUE; + } +#endif +} XTTableSeqRec, *XTTableSeqPtr; + +/* A disk cache segment. The cache is divided into a number of segments + * to improve concurrency. + */ +typedef struct XTTabCacheSeg { + XTRWMutexRec tcs_lock; /* The cache segment read/write lock. */ + //xt_cond_type tcs_cond; + XTTabCachePagePtr *tcs_hash_table; + size_t tcs_cache_in_use; +} XTTabCacheSegRec, *XTTabCacheSegPtr; + +/* + * The free'er thread has a list of tables to be purged from the cache. + * If a table is in the list then it is not allowed to fetch a cache page from + * that table. + * The free'er thread goes through all the cache, and removes + * all cache pages for any table in the purge list. + * When a table has been purged it signals any threads waiting for the + * purge to complete (this is usually due to a drop table). + */ +typedef struct XTTabCachePurge { + int tcp_state; /* The state of the purge. */ + XTTableSeqPtr tcp_tab_seq; /* Identifies the table to be purged from cache. */ +} XTTabCachePurgeRec, *XTTabCachePurgePtr; + +typedef struct XTTabCacheMem { + xt_mutex_type tcm_lock; /* The public cache lock. */ + xt_cond_type tcm_cond; /* The public cache wait condition. */ + XTTabCacheSegRec tcm_segment[XT_TC_SEGMENT_COUNT]; + XTTabCachePagePtr tcm_lru_page; + XTTabCachePagePtr tcm_mru_page; + xtWord4 tcm_ru_now; + size_t tcm_approx_page_count; + size_t tcm_hash_size; + u_int tcm_writer_thread_count; + size_t tcm_cache_size; + size_t tcm_cache_high; /* The high water level of cache allocation. */ + size_t tcm_low_level; /* This is the level to which the freeer will free, once it starts working. */ + size_t tcm_high_level; /* This is the level at which the freeer will start to work (to avoid waiting)! */ + + /* The free'er thread: */ + struct XTThread *tcm_freeer_thread; /* The freeer thread . */ + xt_mutex_type tcm_freeer_lock; /* The public cache lock. */ + xt_cond_type tcm_freeer_cond; /* The public cache wait condition. */ + u_int tcm_purge_list_len; /* The length of the purge list. */ + XTTabCachePurgePtr tcm_purge_list; /* Non-NULL if a table is to be purged. */ + u_int tcm_threads_waiting; /* Count of the number of threads waiting for the freeer. */ + xtBool tcm_freeer_busy; + u_int tcm_free_try_count; +} XTTabCacheMemRec, *XTTabCacheMemPtr; + +/* + * This structure contains the information about a particular table + * for the cache. Each table has its own page size, row size + * and rows per page. + * Tables also have + */ +typedef struct XTTabCache { + struct XTTable *tci_table; + size_t tci_header_size; + size_t tci_page_size; + size_t tci_rec_size; + size_t tci_rows_per_page; + +public: + void xt_tc_setup(struct XTTable *tab, size_t head_size, size_t row_size); + xtBool xt_tc_write(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t offset, size_t size, xtWord1 *data, xtOpSeqNo *op_seq, xtBool read, XTThreadPtr thread); + xtBool xt_tc_write_cond(XTThreadPtr self, XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord1 new_type, xtOpSeqNo *op_seq, xtXactID xn_id, xtRowID row_id, u_int stat_id, u_int rec_type); + xtBool xt_tc_read(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t size, xtWord1 *data, XTThreadPtr thread); + xtBool xt_tc_read_4(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord4 *data, XTThreadPtr thread); + xtBool xt_tc_read_page(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, xtWord1 *data, XTThreadPtr thread); + xtBool xt_tc_get_page(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCachePagePtr *page, size_t *offset, XTThreadPtr thread); + void xt_tc_release_page(XT_ROW_REC_FILE_PTR file, XTTabCachePagePtr page, XTThreadPtr thread); + xtBool tc_fetch(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCacheSegPtr *ret_seg, XTTabCachePagePtr *ret_page, size_t *offset, xtBool read, XTThreadPtr thread); + +private: + xtBool tc_read_direct(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, size_t size, xtWord1 *data, XTThreadPtr thread); + xtBool tc_fetch_direct(XT_ROW_REC_FILE_PTR file, xtRefID ref_id, XTTabCacheSegPtr *ret_seg, XTTabCachePagePtr *ret_page, size_t *offset, XTThreadPtr thread); +} XTTabCacheRec, *XTTabCachePtr; + +extern XTTabCacheMemRec xt_tab_cache; + +void xt_tc_init(XTThreadPtr self, size_t cache_size); +void xt_tc_exit(XTThreadPtr self); +void xt_tc_set_cache_size(size_t cache_size); +xtInt8 xt_tc_get_usage(); +xtInt8 xt_tc_get_size(); +xtInt8 xt_tc_get_high(); +void xt_load_pages(XTThreadPtr self, struct XTOpenTable *ot); +#ifdef DEBUG +void xt_check_table_cache(struct XTTable *tab); +#endif + +void xt_quit_freeer(XTThreadPtr self); +void xt_stop_freeer(XTThreadPtr self); +void xt_start_freeer(XTThreadPtr self); +void xt_wr_wake_freeer(XTThreadPtr self); + +#endif diff --git a/storage/pbxt/src/table_xt.cc b/storage/pbxt/src/table_xt.cc new file mode 100644 index 00000000000..fc9ae6156cb --- /dev/null +++ b/storage/pbxt/src/table_xt.cc @@ -0,0 +1,5115 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-02-08 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <string.h> +#include <stdio.h> +#ifndef XT_WIN +#include <strings.h> +#endif +#include <ctype.h> +#include <time.h> + +#ifdef DRIZZLED +#include <drizzled/common.h> +#include <mysys/thr_lock.h> +#include <drizzled/dtcollation.h> +#include <drizzled/handlerton.h> +#else +#include "mysql_priv.h" +#endif + +#include "table_xt.h" +#include "database_xt.h" +#include "heap_xt.h" +#include "strutil_xt.h" +#include "myxt_xt.h" +#include "cache_xt.h" +#include "trace_xt.h" +#ifdef XT_STREAMING +#include "streaming_xt.h" +#endif +#include "index_xt.h" +#include "restart_xt.h" +#include "systab_xt.h" + +#ifdef DEBUG +//#define TRACE_VARIATIONS +//#define TRACE_VARIATIONS_IN_DUP_CHECK +//#define DUMP_CHECK_TABLE +//#define CHECK_INDEX_ON_CHECK_TABLE +//#define TRACE_TABLE_IDS +//#define TRACE_FLUSH +//#define TRACE_CREATE_TABLES +#endif + +#define CHECK_TABLE_STATS + +#ifdef TRACE_TABLE_IDS +//#define PRINTF xt_ftracef +#define PRINTF xt_trace +#endif + +/* + * ----------------------------------------------------------------------- + * Internal structures + */ + +#define XT_MAX_TABLE_FILE_NAME_SIZE (XT_TABLE_NAME_SIZE+6+40) + +/* + * ----------------------------------------------------------------------- + * Compare paths: + */ + +/* GOTCHA! The problem: + * + * The server uses names like: "./test/my_tab", + * the BLOB streaming engine uses: "test/my_tab" + * which leads to the same table being loaded twice. + */ +xtPublic int xt_tab_compare_paths(char *n1, char *n2) +{ + n1 = xt_last_2_names_of_path(n1); + n2 = xt_last_2_names_of_path(n2); + if (pbxt_ignore_case) + return strcasecmp(n1, n2); + return strcmp(n1, n2); +} + +/* + * This function only compares only the last 2 components of + * the path because table names must differ in this area. + */ +xtPublic int xt_tab_compare_names(const char *n1, const char *n2) +{ + n1 = xt_last_2_names_of_path(n1); + n2 = xt_last_2_names_of_path(n2); + if (pbxt_ignore_case) + return strcasecmp(n1, n2); + return strcmp(n1, n2); +} + +/* + * ----------------------------------------------------------------------- + * Private utilities + */ + +static xtBool tab_list_comp(void *key, void *data) +{ + XTTableHPtr tab = (XTTableHPtr) data; + + return strcmp(xt_last_2_names_of_path((char *) key), xt_last_2_names_of_path(tab->tab_name->ps_path)) == 0; +} + +static xtHashValue tab_list_hash(xtBool is_key, void *key_data) +{ + XTTableHPtr tab = (XTTableHPtr) key_data; + + if (is_key) + return xt_ht_hash(xt_last_2_names_of_path((char *) key_data)); + return xt_ht_hash(xt_last_2_names_of_path(tab->tab_name->ps_path)); +} + +static xtBool tab_list_comp_ci(void *key, void *data) +{ + XTTableHPtr tab = (XTTableHPtr) data; + + return strcasecmp(xt_last_2_names_of_path((char *) key), xt_last_2_names_of_path(tab->tab_name->ps_path)) == 0; +} + +static xtHashValue tab_list_hash_ci(xtBool is_key, void *key_data) +{ + XTTableHPtr tab = (XTTableHPtr) key_data; + + if (is_key) + return xt_ht_casehash(xt_last_2_names_of_path((char *) key_data)); + return xt_ht_casehash(xt_last_2_names_of_path(tab->tab_name->ps_path)); +} + +static void tab_list_free(XTThreadPtr self, void *data) +{ + XTTableHPtr tab = (XTTableHPtr) data; + XTDatabaseHPtr db = tab->tab_db; + XTTableEntryPtr te_ptr; + + /* Remove the reference from the ID list, whem the table is + * removed from the name list: + */ + if ((te_ptr = (XTTableEntryPtr) xt_sl_find(self, db->db_table_by_id, &tab->tab_id))) + te_ptr->te_table = NULL; + + if (tab->tab_dic.dic_table) + tab->tab_dic.dic_table->removeReferences(self); + xt_heap_release(self, tab); +} + +static void tab_close_mapped_files(XTThreadPtr self, XTTableHPtr tab) +{ + if (tab->tab_rec_file) { + xt_fs_release_file(self, tab->tab_rec_file); + tab->tab_rec_file = NULL; + } + if (tab->tab_row_file) { + xt_fs_release_file(self, tab->tab_row_file); + tab->tab_row_file = NULL; + } +} + +static void tab_finalize(XTThreadPtr self, void *x) +{ + XTTableHPtr tab = (XTTableHPtr) x; + + xt_exit_row_locks(&tab->tab_locks); + + xt_xres_exit_tab(self, tab); + + if (tab->tab_ind_free_list) { + XTIndFreeListPtr list, flist; + + list = tab->tab_ind_free_list; + while (list) { + flist = list; + list = list->fl_next_list; + xt_free(self, flist); + } + tab->tab_ind_free_list = NULL; + } + + if (tab->tab_ind_file) { + xt_fs_release_file(self, tab->tab_ind_file); + tab->tab_ind_file = NULL; + } + tab_close_mapped_files(self, tab); + + if (tab->tab_index_head) { + xt_free(self, tab->tab_index_head); + tab->tab_index_head = NULL; + } + +#ifdef TRACE_TABLE_IDS + PRINTF("%s: free TABLE: db=%d tab=%d %s\n", self->t_name, (int) tab->tab_db ? tab->tab_db->db_id : 0, (int) tab->tab_id, + tab->tab_name ? xt_last_2_names_of_path(tab->tab_name->ps_path) : "?"); +#endif + if (tab->tab_name) { + xt_free(self, tab->tab_name); + tab->tab_name = NULL; + } + myxt_free_dictionary(self, &tab->tab_dic); + if (tab->tab_free_locks) { + tab->tab_seq.xt_op_seq_exit(self); + xt_spinlock_free(self, &tab->tab_ainc_lock); + xt_free_mutex(&tab->tab_rec_flush_lock); + xt_free_mutex(&tab->tab_ind_flush_lock); + xt_free_mutex(&tab->tab_dic_field_lock); + xt_free_mutex(&tab->tab_row_lock); + xt_free_mutex(&tab->tab_ind_lock); + xt_free_mutex(&tab->tab_rec_lock); + for (u_int i=0; i<XT_ROW_RWLOCKS; i++) + XT_TAB_ROW_FREE_LOCK(self, &tab->tab_row_rwlock[i]); + } +} + +static void tab_onrelease(XTThreadPtr self, void *x) +{ + XTTableHPtr tab = (XTTableHPtr) x; + + /* Signal threads waiting for exclusive use of the table: */ + if (tab->tab_db->db_tables) + xt_ht_signal(self, tab->tab_db->db_tables); +} + +/* + * ----------------------------------------------------------------------- + * PUBLIC METHODS + */ + +/* + * This function sets the table name to "", if the file + * does not belong to XT. + */ +xtPublic char *xt_tab_file_to_name(size_t size, char *tab_name, char *file_name) +{ + char *cptr; + size_t len; + + file_name = xt_last_name_of_path(file_name); + cptr = file_name + strlen(file_name) - 1; + while (cptr > file_name && *cptr != '.') + cptr--; + if (cptr > file_name && *cptr == '.') { + if (strcmp(cptr, ".xtl") == 0 || strcmp(cptr, ".xtr") == 0) { + cptr--; + while (cptr > file_name && isdigit(*cptr)) + cptr--; + } + else { + const char **ext = pbxt_extensions; + + while (*ext) { + if (strcmp(cptr, *ext) == 0) + goto ret_name; + ext++; + } + cptr = file_name; + } + } + + ret_name: + len = cptr - file_name; + if (len > size-1) + len = size-1; + + memcpy(tab_name, file_name, len); + tab_name[len] = 0; + + /* Return a pointer to what was removed! */ + return file_name + len; +} + +static void tab_get_row_file_name(char *table_name, char *name, xtTableID tab_id) +{ + sprintf(table_name, "%s-%lu.xtr", name, (u_long) tab_id); +} + +static void tab_get_data_file_name(char *table_name, char *name, xtTableID tab_id __attribute__((unused))) +{ + sprintf(table_name, "%s.xtd", name); +} + +static void tab_get_index_file_name(char *table_name, char *name, xtTableID tab_id __attribute__((unused))) +{ + sprintf(table_name, "%s.xti", name); +} + +static void tab_free_by_id(XTThreadPtr self __attribute__((unused)), void *thunk __attribute__((unused)), void *item) +{ + XTTableEntryPtr te_ptr = (XTTableEntryPtr) item; + + if (te_ptr->te_tab_name) { + xt_free(self, te_ptr->te_tab_name); + te_ptr->te_tab_name = NULL; + } + te_ptr->te_tab_id = 0; + te_ptr->te_table = NULL; +} + +static int tab_comp_by_id(XTThreadPtr self __attribute__((unused)), register const void *thunk __attribute__((unused)), register const void *a, register const void *b) +{ + xtTableID te_id = *((xtTableID *) a); + XTTableEntryPtr te_ptr = (XTTableEntryPtr) b; + + if (te_id < te_ptr->te_tab_id) + return -1; + if (te_id == te_ptr->te_tab_id) + return 0; + return 1; +} + +static void tab_free_path(XTThreadPtr self __attribute__((unused)), void *thunk __attribute__((unused)), void *item) +{ + XTTablePathPtr tp_ptr = *((XTTablePathPtr *) item); + + xt_free(self, tp_ptr); +} + +static int tab_comp_path(XTThreadPtr self __attribute__((unused)), register const void *thunk __attribute__((unused)), register const void *a, register const void *b) +{ + char *path = (char *) a; + XTTablePathPtr tp_ptr = *((XTTablePathPtr *) b); + + return xt_tab_compare_paths(path, tp_ptr->tp_path); +} + +xtPublic void xt_describe_tables_init(XTThreadPtr self, XTDatabaseHPtr db, XTTableDescPtr td) +{ + td->td_db = db; + td->td_path_idx = 0; + if (td->td_path_idx < xt_sl_get_size(db->db_table_paths)) { + XTTablePathPtr *tp_ptr; + + tp_ptr = (XTTablePathPtr *) xt_sl_item_at(db->db_table_paths, td->td_path_idx); + td->td_tab_path = *tp_ptr; + td->td_open_dir = xt_dir_open(self, td->td_tab_path->tp_path, "*.xtr"); + } + else + td->td_open_dir = NULL; +} + +xtPublic xtBool xt_describe_tables_next(XTThreadPtr self, XTTableDescPtr td) +{ + char *tab_name; + xtBool r = FALSE; + + enter_(); + retry: + if (!td->td_open_dir) + return_(FALSE); + try_(a) { + r = xt_dir_next(self, td->td_open_dir); + } + catch_(a) { + xt_describe_tables_exit(self, td); + throw_(); + } + cont_(a); + if (!r) { + XTTablePathPtr *tp_ptr; + + if (td->td_path_idx+1 >= xt_sl_get_size(td->td_db->db_table_paths)) + return_(FALSE); + + if (td->td_open_dir) + xt_dir_close(NULL, td->td_open_dir); + td->td_open_dir = NULL; + + td->td_path_idx++; + tp_ptr = (XTTablePathPtr *) xt_sl_item_at(td->td_db->db_table_paths, td->td_path_idx); + td->td_tab_path = *tp_ptr; + td->td_open_dir = xt_dir_open(self, td->td_tab_path->tp_path, "*.xtr"); + goto retry; + } + + tab_name = xt_dir_name(self, td->td_open_dir); + td->td_file_name = tab_name; + td->td_tab_id = (xtTableID) xt_file_name_to_id(tab_name); + xt_tab_file_to_name(XT_TABLE_NAME_SIZE, td->td_tab_name, tab_name); + return_(TRUE); +} + +xtPublic void xt_describe_tables_exit(XTThreadPtr self __attribute__((unused)), XTTableDescPtr td) +{ + if (td->td_open_dir) + xt_dir_close(NULL, td->td_open_dir); + td->td_open_dir = NULL; + td->td_tab_path = NULL; +} + +xtPublic void xt_tab_init_db(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTTableDescRec desc; + XTTableEntryRec te_tab; + XTTablePathPtr db_path; + int len; + + enter_(); + pushr_(xt_tab_exit_db, db); + if (pbxt_ignore_case) + db->db_tables = xt_new_hashtable(self, tab_list_comp_ci, tab_list_hash_ci, tab_list_free, TRUE, TRUE); + else + db->db_tables = xt_new_hashtable(self, tab_list_comp, tab_list_hash, tab_list_free, TRUE, TRUE); + db->db_table_by_id = xt_new_sortedlist(self, sizeof(XTTableEntryRec), 20, 20, tab_comp_by_id, db, tab_free_by_id, FALSE, FALSE); + db->db_table_paths = xt_new_sortedlist(self, sizeof(XTTablePathPtr), 20, 20, tab_comp_path, db, tab_free_path, FALSE, FALSE); + + if (db->db_multi_path) { + XTOpenFilePtr of; + char *buffer, *ptr, *path; + char pbuf[PATH_MAX]; + + xt_strcpy(PATH_MAX, pbuf, db->db_main_path); + xt_add_location_file(PATH_MAX, pbuf); + if (xt_fs_exists(pbuf)) { + of = xt_open_file(self, pbuf, XT_FS_DEFAULT); + pushr_(xt_close_file, of); + len = (int) xt_seek_eof_file(self, of); + buffer = (char *) xt_malloc(self, len + 1); + pushr_(xt_free, buffer); + if (!xt_pread_file(of, 0, len, len, buffer, NULL, &self->st_statistics.st_x, self)) + xt_throw(self); + buffer[len] = 0; + ptr = buffer; + while (*ptr) { + /* Ignore preceeding space: */ + while (*ptr && isspace(*ptr)) + ptr++; + path = ptr; + while (*ptr && *ptr != '\n' && *ptr != '\r') { +#ifdef XT_WIN + /* Undo the conversion below: */ + if (*ptr == '/') + *ptr = '\\'; +#endif + ptr++; + } + if (*path != '#' && ptr > path) { + len = (int) (ptr - path); + db_path = (XTTablePathPtr) xt_malloc(self, offsetof(XTTablePathRec, tp_path) + len + 1); + db_path->tp_tab_count = 0; + memcpy(db_path->tp_path, path, len); + db_path->tp_path[len] = 0; + xt_sl_insert(self, db->db_table_paths, db_path->tp_path, &db_path); + } + ptr++; + } + freer_(); // xt_free(buffer) + freer_(); // xt_close_file(of) + } + } + else { + len = (int) strlen(db->db_main_path); + db_path = (XTTablePathPtr) xt_malloc(self, offsetof(XTTablePathRec, tp_path) + len + 1); + db_path->tp_tab_count = 0; + strcpy(db_path->tp_path, db->db_main_path); + xt_sl_insert(self, db->db_table_paths, db_path->tp_path, &db_path); + } + + xt_describe_tables_init(self, db, &desc); + pushr_(xt_describe_tables_exit, &desc); + while (xt_describe_tables_next(self, &desc)) { + te_tab.te_tab_id = desc.td_tab_id; + + if (te_tab.te_tab_id > db->db_curr_tab_id) + db->db_curr_tab_id = te_tab.te_tab_id; + + te_tab.te_tab_name = xt_dup_string(self, desc.td_tab_name); + te_tab.te_tab_path = desc.td_tab_path; + desc.td_tab_path->tp_tab_count++; + te_tab.te_table = NULL; + xt_sl_insert(self, db->db_table_by_id, &desc.td_tab_id, &te_tab); + } + freer_(); // xt_describe_tables_exit(&desc) + + popr_(); // Discard xt_tab_exit_db(db) + exit_(); +} + +static void tab_save_table_paths(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTTablePathPtr *tp_ptr; + XTStringBufferRec buffer; + XTOpenFilePtr of; + char path[PATH_MAX]; + + memset(&buffer, 0, sizeof(buffer)); + + xt_strcpy(PATH_MAX, path, db->db_main_path); + xt_add_location_file(PATH_MAX, path); + + if (xt_sl_get_size(db->db_table_paths)) { + pushr_(xt_sb_free, &buffer); + for (u_int i=0; i<xt_sl_get_size(db->db_table_paths); i++) { + tp_ptr = (XTTablePathPtr *) xt_sl_item_at(db->db_table_paths, i); + xt_sb_concat(self, &buffer, (*tp_ptr)->tp_path); + xt_sb_concat(self, &buffer, "\n"); + } + +#ifdef XT_WIN + /* To make the location file cross-platform (at least + * as long as relative paths are used) we replace all '\' + * with '/': */ + char *ptr; + + ptr = buffer.sb_cstring; + while (*ptr) { + if (*ptr == '\\') + *ptr = '/'; + ptr++; + } +#endif + + of = xt_open_file(self, path, XT_FS_CREATE | XT_FS_MAKE_PATH); + pushr_(xt_close_file, of); + if (!xt_pwrite_file(of, 0, strlen(buffer.sb_cstring), buffer.sb_cstring, &self->st_statistics.st_x, self)) + xt_throw(self); + xt_set_eof_file(self, of, strlen(buffer.sb_cstring)); + freer_(); // xt_close_file(of) + + freer_(); // xt_sb_free(&buffer); + } + else + xt_fs_delete(NULL, path); +} + +static XTTablePathPtr tab_get_table_path(XTThreadPtr self, XTDatabaseHPtr db, XTPathStrPtr tab_name, xtBool save_it) +{ + XTTablePathPtr *tp, tab_path; + char path[PATH_MAX]; + + xt_strcpy(PATH_MAX, path, tab_name->ps_path); + xt_remove_last_name_of_path(path); + xt_remove_dir_char(path); + tp = (XTTablePathPtr *) xt_sl_find(self, db->db_table_paths, path); + if (tp) + tab_path = *tp; + else { + int len = (int) strlen(path); + + tab_path = (XTTablePathPtr) xt_malloc(self, offsetof(XTTablePathRec, tp_path) + len + 1); + tab_path->tp_tab_count = 0; + memcpy(tab_path->tp_path, path, len); + tab_path->tp_path[len] = 0; + xt_sl_insert(self, db->db_table_paths, tab_path->tp_path, &tab_path); + if (save_it) { + tab_save_table_paths(self, db); + if (xt_sl_get_size(db->db_table_paths) == 1) { + XTSystemTableShare::createSystemTables(self, db); + } + } + } + tab_path->tp_tab_count++; + return tab_path; +} + +static void tab_remove_table_path(XTThreadPtr self, XTDatabaseHPtr db, XTTablePathPtr tab_path) +{ + if (tab_path->tp_tab_count > 0) { + tab_path->tp_tab_count--; + if (tab_path->tp_tab_count == 0) { + xt_sl_delete(self, db->db_table_paths, tab_path->tp_path); + tab_save_table_paths(self, db); + } + } +} + +static void tab_free_table_path(XTThreadPtr self, XTTablePathPtr tab_path) +{ + XTDatabaseHPtr db = self->st_database; + + tab_remove_table_path(self, db, tab_path); +} + +xtPublic void xt_tab_exit_db(XTThreadPtr self, XTDatabaseHPtr db) +{ + if (db->db_tables) { + xt_free_hashtable(self, db->db_tables); + db->db_tables = NULL; + } + if (db->db_table_by_id) { + xt_free_sortedlist(self, db->db_table_by_id); + db->db_table_by_id = NULL; + } + if (db->db_table_paths) { + xt_free_sortedlist(self, db->db_table_paths); + db->db_table_paths = NULL; + } +} + +static void tab_check_table(XTThreadPtr self __attribute__((unused)), XTTableHPtr tab __attribute__((unused))) +{ + enter_(); + exit_(); +} + +xtPublic void xt_check_tables(XTThreadPtr self) +{ + u_int edx; + XTTableEntryPtr te_ptr; + volatile XTTableHPtr tab; + char path[PATH_MAX]; + + enter_(); + xt_logf(XT_INFO, "Check %s: Table...\n", self->st_database->db_main_path); + xt_enum_tables_init(&edx); + try_(a) { + for (;;) { + xt_ht_lock(self, self->st_database->db_tables); + pushr_(xt_ht_unlock, self->st_database->db_tables); + te_ptr = xt_enum_tables_next(self, self->st_database, &edx); + freer_(); // xt_ht_unlock(db->db_tables) + if (!te_ptr) + break; + xt_strcpy(PATH_MAX, path, te_ptr->te_tab_path->tp_path); + xt_add_dir_char(PATH_MAX, path); + xt_strcat(PATH_MAX, path, te_ptr->te_tab_name); + tab = xt_use_table(self, (XTPathStrPtr) path, FALSE, FALSE, NULL); + tab_check_table(self, tab); + xt_heap_release(self, tab); + tab = NULL; + } + } + catch_(a) { + if (tab) + xt_heap_release(self, tab); + throw_(); + } + cont_(a); + exit_(); +} + +xtPublic xtBool xt_table_exists(XTDatabaseHPtr db) +{ + return xt_sl_get_size(db->db_table_by_id) > 0; +} + +/* + * Enumerate all tables in the current database. + */ + +xtPublic void xt_enum_tables_init(u_int *edx) +{ + *edx = 0; +} + +xtPublic XTTableEntryPtr xt_enum_tables_next(XTThreadPtr self __attribute__((unused)), XTDatabaseHPtr db, u_int *edx) +{ + XTTableEntryPtr en_ptr; + + if (*edx >= xt_sl_get_size(db->db_table_by_id)) + return NULL; + en_ptr = (XTTableEntryPtr) xt_sl_item_at(db->db_table_by_id, *edx); + (*edx)++; + return en_ptr; +} + +xtPublic void xt_enum_files_of_tables_init(XTPathStrPtr tab_name, xtTableID tab_id, XTFilesOfTablePtr ft) +{ + ft->ft_state = 0; + ft->ft_tab_name = tab_name; + ft->ft_tab_id = tab_id; +} + +xtPublic xtBool xt_enum_files_of_tables_next(XTFilesOfTablePtr ft) +{ + char file_name[XT_MAX_TABLE_FILE_NAME_SIZE]; + + retry: + switch (ft->ft_state) { + case 0: + tab_get_row_file_name(file_name, xt_last_name_of_path(ft->ft_tab_name->ps_path), ft->ft_tab_id); + break; + case 1: + tab_get_data_file_name(file_name, xt_last_name_of_path(ft->ft_tab_name->ps_path), ft->ft_tab_id); + break; + case 2: + tab_get_index_file_name(file_name, xt_last_name_of_path(ft->ft_tab_name->ps_path), ft->ft_tab_id); + break; + default: + return FAILED; + } + + ft->ft_state++; + xt_strcpy(PATH_MAX, ft->ft_file_path, ft->ft_tab_name->ps_path); + xt_remove_last_name_of_path(ft->ft_file_path); + xt_strcat(PATH_MAX, ft->ft_file_path, file_name); + if (!xt_fs_exists(ft->ft_file_path)) + goto retry; + + return TRUE; +} + +static xtBool tab_find_table(XTThreadPtr self, XTDatabaseHPtr db, XTPathStrPtr name, xtTableID *tab_id) +{ + u_int edx; + XTTableEntryPtr te_ptr; + char path[PATH_MAX]; + + xt_enum_tables_init(&edx); + while ((te_ptr = xt_enum_tables_next(self, db, &edx))) { + xt_strcpy(PATH_MAX, path, te_ptr->te_tab_path->tp_path); + xt_add_dir_char(PATH_MAX, path); + xt_strcat(PATH_MAX, path, te_ptr->te_tab_name); + if (xt_tab_compare_names(path, name->ps_path) == 0) { + *tab_id = te_ptr->te_tab_id; + return TRUE; + } + } + return FALSE; +} + +xtPublic void xt_tab_set_index_error(XTTableHPtr tab) +{ + switch (tab->tab_dic.dic_disable_index) { + case XT_INDEX_OK: + break; + case XT_INDEX_TOO_OLD: + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_OLD_VERSION, tab->tab_name); + break; + case XT_INDEX_TOO_NEW: + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_NEW_VERSION, tab->tab_name); + break; + case XT_INDEX_BAD_BLOCK: + char number[40]; + + sprintf(number, "%d", (int) tab->tab_index_page_size); + xt_register_i2xterr(XT_REG_CONTEXT, XT_ERR_BAD_IND_BLOCK_SIZE, xt_last_name_of_path(tab->tab_name->ps_path), number); + break; + case XT_INDEX_CORRUPTED: + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_CORRUPTED, tab->tab_name); + break; + case XT_INDEX_MISSING: + xt_register_taberr(XT_REG_CONTEXT, XT_ERR_INDEX_MISSING, tab->tab_name); + break; + } +} + +static void tab_load_index_header(XTThreadPtr self, XTTableHPtr tab, XTOpenFilePtr file, XTPathStrPtr table_name) +{ + XT_NODE_TEMP; + XTIndexPtr *ind; + xtWord1 *data; + XTIndexFormatDPtr index_fmt; + + /* Load the pointers: */ + if (tab->tab_index_head) + xt_free_ns(tab->tab_index_head); + tab->tab_index_head = (XTIndexHeadDPtr) xt_calloc(self, XT_INDEX_HEAD_SIZE); + + if (file) { + if (!xt_pread_file(file, 0, XT_INDEX_HEAD_SIZE, 0, tab->tab_index_head, NULL, &self->st_statistics.st_ind, self)) + xt_throw(self); + + tab->tab_index_format_offset = XT_GET_DISK_4(tab->tab_index_head->tp_format_offset_4); + index_fmt = (XTIndexFormatDPtr) (((xtWord1 *) tab->tab_index_head) + tab->tab_index_format_offset); + + /* If the table version is less than or equal to an incompatible (unsupported + * version), or greater than the current version, then we cannot open this table + */ + if (XT_GET_DISK_2(index_fmt->if_tab_version_2) <= XT_TAB_INCOMPATIBLE_VERSION || + XT_GET_DISK_2(index_fmt->if_tab_version_2) > XT_TAB_CURRENT_VERSION) { + switch (XT_GET_DISK_2(index_fmt->if_tab_version_2)) { + case 4: + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_UPGRADE_TABLE, table_name, "0.9.91 Beta"); + break; + case 3: + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_UPGRADE_TABLE, table_name, "0.9.85 Beta"); + break; + default: + xt_throw_taberr(XT_CONTEXT, XT_ERR_BAD_TABLE_VERSION, table_name); + break; + } + return; + } + + tab->tab_dic.dic_index_ver = XT_GET_DISK_2(index_fmt->if_ind_version_2); + tab->tab_dic.dic_disable_index = XT_INDEX_OK; + + if (tab->tab_dic.dic_index_ver == 1) { + tab->tab_index_header_size = 1024 * 16; + tab->tab_index_page_size = 1024 * 16; + } + else { + tab->tab_index_header_size = XT_GET_DISK_4(tab->tab_index_head->tp_header_size_4); + tab->tab_index_page_size = XT_GET_DISK_4(index_fmt->if_page_size_4); + } + + /* Incorrect version of index is handled by allowing a sequential scan, but no index access. + * Recovery with the wrong index type will not recover the indexes, a REPAIR TABLE + * will be required! + */ + if (tab->tab_dic.dic_index_ver != XT_IND_CURRENT_VERSION) { + if (tab->tab_dic.dic_index_ver != XT_IND_CURRENT_VERSION) + tab->tab_dic.dic_disable_index = XT_INDEX_TOO_OLD; + else + tab->tab_dic.dic_disable_index = XT_INDEX_TOO_NEW; + } + else if (tab->tab_index_page_size != XT_INDEX_PAGE_SIZE) + tab->tab_dic.dic_disable_index = XT_INDEX_BAD_BLOCK; + } + else { + memset(tab->tab_index_head, 0, XT_INDEX_HEAD_SIZE); + tab->tab_dic.dic_disable_index = XT_INDEX_MISSING; + tab->tab_index_header_size = XT_INDEX_HEAD_SIZE; + tab->tab_index_page_size = XT_INDEX_PAGE_SIZE; + tab->tab_dic.dic_index_ver = 0; + tab->tab_index_format_offset = 0; + } + + + if (tab->tab_dic.dic_disable_index) { + xt_tab_set_index_error(tab); + xt_log_and_clear_exception_ns(); + } + + if (tab->tab_dic.dic_disable_index) { + /* Reset, as if we have empty indexes. + * Flush will wipe things out, of course. + * REPAIR TABLE will be required... + */ + XT_NODE_ID(tab->tab_ind_eof) = 1; + XT_NODE_ID(tab->tab_ind_free) = 0; + + ind = tab->tab_dic.dic_keys; + for (u_int i=0; i<tab->tab_dic.dic_key_count; i++, ind++) + XT_NODE_ID((*ind)->mi_root) = 0; + } + else { + XT_NODE_ID(tab->tab_ind_eof) = (xtIndexNodeID) XT_GET_DISK_6(tab->tab_index_head->tp_ind_eof_6); + XT_NODE_ID(tab->tab_ind_free) = (xtIndexNodeID) XT_GET_DISK_6(tab->tab_index_head->tp_ind_free_6); + + data = tab->tab_index_head->tp_data; + ind = tab->tab_dic.dic_keys; + for (u_int i=0; i<tab->tab_dic.dic_key_count; i++, ind++) { + (*ind)->mi_root = XT_GET_NODE_REF(tab, data); + data += XT_NODE_REF_SIZE; + } + } +} + +static void tab_load_table_format(XTThreadPtr self, XTOpenFilePtr file, XTPathStrPtr table_name, size_t *ret_format_offset, size_t *ret_head_size, XTDictionaryPtr dic) +{ + XTDiskValue4 size_buf; + size_t head_size; + XTTableFormatDRec tab_fmt; + size_t fmt_size; + + if (!xt_pread_file(file, 0, 4, 4, &size_buf, NULL, &self->st_statistics.st_rec, self)) + xt_throw(self); + + head_size = XT_GET_DISK_4(size_buf); + *ret_format_offset = head_size; + + /* Load the table format information: */ + if (!xt_pread_file(file, head_size, offsetof(XTTableFormatDRec, tf_definition), offsetof(XTTableFormatDRec, tf_tab_version_2) + 2, &tab_fmt, NULL, &self->st_statistics.st_rec, self)) + xt_throw(self); + + /* If the table version is less than or equal to an incompatible (unsupported + * version), or greater than the current version, then we cannot open this table + */ + if (XT_GET_DISK_2(tab_fmt.tf_tab_version_2) <= XT_TAB_INCOMPATIBLE_VERSION || + XT_GET_DISK_2(tab_fmt.tf_tab_version_2) > XT_TAB_CURRENT_VERSION) { + switch (XT_GET_DISK_2(tab_fmt.tf_tab_version_2)) { + case 4: + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_UPGRADE_TABLE, table_name, "0.9.91 Beta"); + break; + case 3: + xt_throw_tabcolerr(XT_CONTEXT, XT_ERR_UPGRADE_TABLE, table_name, "0.9.85 Beta"); + break; + default: + xt_throw_taberr(XT_CONTEXT, XT_ERR_BAD_TABLE_VERSION, table_name); + break; + } + return; + } + + fmt_size = XT_GET_DISK_4(tab_fmt.tf_format_size_4); + *ret_head_size = XT_GET_DISK_4(tab_fmt.tf_tab_head_size_4); + dic->dic_rec_size = XT_GET_DISK_4(tab_fmt.tf_rec_size_4); + dic->dic_rec_fixed = XT_GET_DISK_1(tab_fmt.tf_rec_fixed_1); + dic->dic_tab_flags = XT_GET_DISK_2(tab_fmt.tf_tab_flags_2); + dic->dic_min_auto_inc = XT_GET_DISK_8(tab_fmt.tf_min_auto_inc_8); + if (fmt_size > offsetof(XTTableFormatDRec, tf_definition)) { + size_t def_size = fmt_size - offsetof(XTTableFormatDRec, tf_definition); + char *def_sql; + + pushsr_(def_sql, xt_free, (char *) xt_malloc(self, def_size)); + if (!xt_pread_file(file, head_size+offsetof(XTTableFormatDRec, tf_definition), def_size, def_size, def_sql, NULL, &self->st_statistics.st_rec, self)) + xt_throw(self); + dic->dic_table = xt_ri_create_table(self, false, table_name, def_sql, myxt_create_table_from_table(self, dic->dic_my_table)); + freer_(); // xt_free(def_sql) + } + else + dic->dic_table = myxt_create_table_from_table(self, dic->dic_my_table); +} + +static void tab_load_table_header(XTThreadPtr self, XTTableHPtr tab, XTOpenFilePtr file) +{ + XTTableHeadDRec rec_head; + + if (!xt_pread_file(file, 0, sizeof(XTTableHeadDRec), sizeof(XTTableHeadDRec), (xtWord1 *) &rec_head, NULL, &self->st_statistics.st_rec, self)) + xt_throw(self); + + tab->tab_head_op_seq = XT_GET_DISK_4(rec_head.th_op_seq_4); + tab->tab_head_row_free_id = (xtRowID) XT_GET_DISK_6(rec_head.th_row_free_6); + tab->tab_head_row_eof_id = (xtRowID) XT_GET_DISK_6(rec_head.th_row_eof_6); + tab->tab_head_row_fnum = (xtWord4) XT_GET_DISK_6(rec_head.th_row_fnum_6); + tab->tab_head_rec_free_id = (xtRecordID) XT_GET_DISK_6(rec_head.th_rec_free_6); + tab->tab_head_rec_eof_id = (xtRecordID) XT_GET_DISK_6(rec_head.th_rec_eof_6); + tab->tab_head_rec_fnum = (xtWord4) XT_GET_DISK_6(rec_head.th_rec_fnum_6); +} + +xtPublic void xt_tab_store_header(XTOpenTablePtr ot, XTTableHeadDPtr rec_head) +{ + XTTableHPtr tab = ot->ot_table; + + XT_SET_DISK_4(rec_head->th_op_seq_4, tab->tab_head_op_seq); + XT_SET_DISK_6(rec_head->th_row_free_6, tab->tab_head_row_free_id); + XT_SET_DISK_6(rec_head->th_row_eof_6, tab->tab_head_row_eof_id); + XT_SET_DISK_6(rec_head->th_row_fnum_6, tab->tab_head_row_fnum); + XT_SET_DISK_6(rec_head->th_rec_free_6, tab->tab_head_rec_free_id); + XT_SET_DISK_6(rec_head->th_rec_eof_6, tab->tab_head_rec_eof_id); + XT_SET_DISK_6(rec_head->th_rec_fnum_6, tab->tab_head_rec_fnum); +} + +xtPublic xtBool xt_tab_write_header(XTOpenTablePtr ot, XTTableHeadDPtr rec_head, struct XTThread *thread) +{ + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, offsetof(XTTableHeadDRec, th_op_seq_4), 40, (xtWord1 *) rec_head->th_op_seq_4, &thread->st_statistics.st_rec, thread)) + return FAILED; + if (!XT_FLUSH_RR_FILE(ot->ot_rec_file, &thread->st_statistics.st_rec, thread)) + return FAILED; + return OK; +} + +xtPublic xtBool xt_tab_write_min_auto_inc(XTOpenTablePtr ot) +{ + xtWord1 value[8]; + off_t offset; + + XT_SET_DISK_8(value, ot->ot_table->tab_dic.dic_min_auto_inc); + offset = ot->ot_table->tab_table_format_offset + offsetof(XTTableFormatDRec, tf_min_auto_inc_8); + if (!XT_PWRITE_RR_FILE(ot->ot_rec_file, offset, 8, value, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + return FAILED; + if (!XT_FLUSH_RR_FILE(ot->ot_rec_file, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + return FAILED; + return OK; +} + +/* a helper function to remove table from the open tables hash on exception + * used in tab_new_handle() below + */ +static void xt_del_from_db_tables_ht(XTThreadPtr self, XTTableHPtr tab) +{ + XTTableEntryPtr te_ptr; + XTDatabaseHPtr db = tab->tab_db; + xtTableID tab_id = tab->tab_id; + + /* Oops! should use tab->tab_name, instead of tab! */ + xt_ht_del(self, db->db_tables, tab->tab_name); + + /* Remove the reference from the ID list, when a table is + * removed from the table name list: + */ + if ((te_ptr = (XTTableEntryPtr) xt_sl_find(self, db->db_table_by_id, &tab_id))) + te_ptr->te_table = NULL; +} + +/* + * Create a new table handle (i.e. open a table). + * Return NULL if the table is missing, and it is OK for the table + * to be missing. + */ +static int tab_new_handle(XTThreadPtr self, XTTableHPtr *r_tab, XTDatabaseHPtr db, xtTableID tab_id, XTPathStrPtr tab_path, xtBool missing_ok, XTDictionaryPtr dic) +{ + char path[PATH_MAX]; + XTTableHPtr tab; + char file_name[XT_MAX_TABLE_FILE_NAME_SIZE]; + XTOpenFilePtr of_rec, of_ind; + XTTableEntryPtr te_ptr; + size_t tab_format_offset; + size_t tab_head_size; + + enter_(); + + tab = (XTTableHPtr) xt_heap_new(self, sizeof(XTTableHRec), tab_finalize); + pushr_(xt_heap_release, tab); + + tab->tab_name = (XTPathStrPtr) xt_dup_string(self, tab_path->ps_path); + tab->tab_db = db; + tab->tab_id = tab_id; +#ifdef TRACE_TABLE_IDS + PRINTF("%s: allocated TABLE: db=%d tab=%d %s\n", self->t_name, (int) db->db_id, (int) tab->tab_id, xt_last_2_names_of_path(tab->tab_name->ps_path)); +#endif + + if (dic) { + myxt_move_dictionary(&tab->tab_dic, dic); + myxt_setup_dictionary(self, &tab->tab_dic); + } + else { + if (!myxt_load_dictionary(self, &tab->tab_dic, db, tab_path)) { + freer_(); // xt_heap_release(tab) + return_(XT_TAB_NO_DICTIONARY); + } + } + + tab->tab_seq.xt_op_seq_init(self); + xt_spinlock_init_with_autoname(self, &tab->tab_ainc_lock); + xt_init_mutex_with_autoname(self, &tab->tab_rec_flush_lock); + xt_init_mutex_with_autoname(self, &tab->tab_ind_flush_lock); + xt_init_mutex_with_autoname(self, &tab->tab_dic_field_lock); + xt_init_mutex_with_autoname(self, &tab->tab_row_lock); + xt_init_mutex_with_autoname(self, &tab->tab_ind_lock); + xt_init_mutex_with_autoname(self, &tab->tab_rec_lock); + for (u_int i=0; i<XT_ROW_RWLOCKS; i++) + XT_TAB_ROW_INIT_LOCK(self, &tab->tab_row_rwlock[i]); + tab->tab_free_locks = TRUE; + + xt_strcpy(PATH_MAX, path, tab_path->ps_path); + xt_remove_last_name_of_path(path); + tab_get_row_file_name(file_name, xt_last_name_of_path(tab_path->ps_path), tab_id); + xt_strcat(PATH_MAX, path, file_name); + tab->tab_row_file = xt_fs_get_file(self, path); + + xt_remove_last_name_of_path(path); + tab_get_data_file_name(file_name, xt_last_name_of_path(tab_path->ps_path), tab_id); + xt_strcat(PATH_MAX, path, file_name); + tab->tab_rec_file = xt_fs_get_file(self, path); + + xt_remove_last_name_of_path(path); + tab_get_index_file_name(file_name, xt_last_name_of_path(tab_path->ps_path), tab_id); + xt_strcat(PATH_MAX, path, file_name); + tab->tab_ind_file = xt_fs_get_file(self, path); + + of_ind = xt_open_file(self, tab->tab_ind_file->fil_path, XT_FS_MISSING_OK); + if (of_ind) { + pushr_(xt_close_file, of_ind); + tab_load_index_header(self, tab, of_ind, tab_path); + freer_(); // xt_close_file(of_ind) + } + else + tab_load_index_header(self, tab, of_ind, tab_path); + + of_rec = xt_open_file(self, tab->tab_rec_file->fil_path, missing_ok ? XT_FS_MISSING_OK : XT_FS_DEFAULT); + if (!of_rec) { + freer_(); // xt_heap_release(tab) + return_(XT_TAB_NOT_FOUND); + } + pushr_(xt_close_file, of_rec); + tab_load_table_format(self, of_rec, tab_path, &tab_format_offset, &tab_head_size, &tab->tab_dic); + tab->tab_table_format_offset = tab_format_offset; + tab->tab_table_head_size = tab_head_size; + tab->tab_dic.dic_table->dt_table = tab; + tab_load_table_header(self, tab, of_rec); + freer_(); // xt_close_file(of_rec) + + tab->tab_seq.xt_op_seq_set(self, tab->tab_head_op_seq+1); + tab->tab_row_eof_id = tab->tab_head_row_eof_id; + tab->tab_row_free_id = tab->tab_head_row_free_id; + tab->tab_row_fnum = tab->tab_head_row_fnum; + tab->tab_rec_eof_id = tab->tab_head_rec_eof_id; + tab->tab_rec_free_id = tab->tab_head_rec_free_id; + tab->tab_rec_fnum = tab->tab_head_rec_fnum; + + tab->tab_rows.xt_tc_setup(tab, sizeof(XTTabRowHeadDRec), sizeof(XTTabRowRefDRec)); + tab->tab_recs.xt_tc_setup(tab, tab_head_size, tab->tab_dic.dic_rec_size); + + xt_xres_init_tab(self, tab); + + if (!xt_init_row_locks(&tab->tab_locks)) + xt_throw(self); + + xt_heap_set_release_callback(self, tab, tab_onrelease); + + popr_(); // Discard xt_heap_release(tab) + + xt_ht_put(self, db->db_tables, tab); + + /* Add a reference to the ID list, when a table is + * added to the table name list: + */ + if ((te_ptr = (XTTableEntryPtr) xt_sl_find(self, db->db_table_by_id, &tab->tab_id))) + te_ptr->te_table = tab; + + /* Moved from after xt_init_row_locks() above, so that calling + * xt_use_table_no_lock() with no_load == FALSE from attachReferences() + * will work if we have cyclic foreign key references. + */ + if (tab->tab_dic.dic_table) { + pushr_(xt_del_from_db_tables_ht, tab); + tab->tab_dic.dic_table->attachReferences(self, db); + popr_(); + } + + *r_tab = tab; + return_(XT_TAB_OK); +} + + +/* + * Get a reference to a table in the current database. The table reference is valid, + * as long as the thread is using the database!!! + */ +xtPublic XTTableHPtr xt_use_table_no_lock(XTThreadPtr self, XTDatabaseHPtr db, XTPathStrPtr name, xtBool no_load, xtBool missing_ok, XTDictionaryPtr dic, xtBool *opened) +{ + XTTableHPtr tab; + + if (!db) + xt_throw_xterr(XT_CONTEXT, XT_ERR_NO_DATABASE_IN_USE); + + tab = (XTTableHPtr) xt_ht_get(self, db->db_tables, name); + if (!tab && !no_load) { + xtTableID tab_id = 0; + + if (!tab_find_table(self, db, name, &tab_id)) { + if (missing_ok) + return NULL; + xt_throw_taberr(XT_CONTEXT, XT_ERR_TABLE_NOT_FOUND, name); + } + + if (tab_new_handle(self, &tab, db, tab_id, name, FALSE, dic) == XT_TAB_NO_DICTIONARY) + xt_throw_taberr(XT_CONTEXT, XT_ERR_NO_DICTIONARY, name); + + if (opened) + *opened = TRUE; + } + + if (tab) + xt_heap_reference(self, tab); + + return tab; +} + +static void tab_close_table(XTOpenTablePtr ot) +{ + xt_ind_free_reserved(ot); + + if (ot->ot_rec_file) { + XT_CLOSE_RR_FILE_NS(ot->ot_rec_file); + ot->ot_rec_file = NULL; + + } + if (ot->ot_ind_file) { + xt_close_file_ns(ot->ot_ind_file); + ot->ot_ind_file = NULL; + + } + if (ot->ot_row_file) { + XT_CLOSE_RR_FILE_NS(ot->ot_row_file); + ot->ot_row_file = NULL; + + } + if (ot->ot_table) { + xt_heap_release(xt_get_self(), ot->ot_table); + ot->ot_table = NULL; + } + if (ot->ot_ind_rhandle) { + xt_ind_release_handle(ot->ot_ind_rhandle, FALSE, ot->ot_thread); + ot->ot_ind_rhandle = NULL; + } + if (ot->ot_row_rbuffer) { + xt_free_ns(ot->ot_row_rbuffer); + ot->ot_row_rbuf_size = 0; + ot->ot_row_rbuffer = NULL; + } + if (ot->ot_row_wbuffer) { + xt_free_ns(ot->ot_row_wbuffer); + ot->ot_row_wbuf_size = 0; + ot->ot_row_wbuffer = NULL; + } +#ifdef XT_TRACK_RETURNED_ROWS + if (ot->ot_rows_returned) { + xt_free_ns(ot->ot_rows_returned); + ot->ot_rows_returned = NULL; + } + ot->ot_rows_ret_curr = 0; + ot->ot_rows_ret_max = 0; +#endif + xt_free(NULL, ot); +} + +/* + * This function locks a particular table by locking the table directory + * and waiting for all open tables handles to close. + * + * Things are a bit complicated because the sweeper must be turned off before + * the table directory is locked. + */ +static XTOpenTablePoolPtr tab_lock_table(XTThreadPtr self, XTPathStrPtr name, xtBool no_load, xtBool flush_table, xtBool missing_ok, XTTableHPtr *tab) +{ + XTOpenTablePoolPtr table_pool; + XTDatabaseHPtr db = self->st_database; + + enter_(); + /* Lock the table, and close all references: */ + pushsr_(table_pool, xt_db_unlock_table_pool, xt_db_lock_table_pool_by_name(self, db, name, no_load, flush_table, missing_ok, FALSE, tab)); + if (!table_pool) { + freer_(); // xt_db_unlock_table_pool(db) + return_(NULL); + } + +#ifdef XT_STREAMING + /* Tell PBMS to close all open tables of this sort: */ + xt_pbms_close_all_tables(name->ps_path); +#endif + + /* Wait for all open tables to close: */ + xt_db_wait_for_open_tables(self, table_pool); + + popr_(); // Discard xt_db_unlock_table_pool(table_pool) + return_(table_pool); +} + +static void tab_delete_table_files(XTThreadPtr self, XTPathStrPtr tab_name, xtTableID tab_id) +{ + XTFilesOfTableRec ft; + + xt_enum_files_of_tables_init(tab_name, tab_id, &ft); + while (xt_enum_files_of_tables_next(&ft)) { + if (!xt_fs_delete(NULL, ft.ft_file_path)) + xt_log_and_clear_exception(self); + } +} + +xtPublic void xt_create_table(XTThreadPtr self, XTPathStrPtr name, XTDictionaryPtr dic) +{ + char table_name[XT_MAX_TABLE_FILE_NAME_SIZE]; + char path[PATH_MAX]; + XTDatabaseHPtr db = self->st_database; + XTOpenTablePoolPtr table_pool; + XTTableHPtr tab; + XTTableHPtr old_tab = NULL; + xtTableID old_tab_id = 0; + xtTableID tab_id = 0; + XTTabRowHeadDRec row_head; + XTTableHeadDRec rec_head; + XTTableFormatDRec table_fmt; + XTIndexFormatDPtr index_fmt; + XTStringBufferRec tab_def = { 0, 0, 0 }; + XTTableEntryRec te_tab; + XTSortedListInfoRec li_undo; + +#ifdef TRACE_CREATE_TABLES + printf("CREATE %s\n", name->ps_path); +#endif + enter_(); + if (strlen(xt_last_name_of_path(name->ps_path)) > XT_TABLE_NAME_SIZE-1) + xt_throw_taberr(XT_CONTEXT, XT_ERR_NAME_TOO_LONG, name); + if (!db) + xt_throw_xterr(XT_CONTEXT, XT_ERR_NO_DATABASE_IN_USE); + + /* Lock to prevent table list change during creation. */ + table_pool = tab_lock_table(self, name, FALSE, TRUE, TRUE, &old_tab); + pushr_(xt_db_unlock_table_pool, table_pool); + xt_ht_lock(self, db->db_tables); + pushr_(xt_ht_unlock, db->db_tables); + pushr_(xt_heap_release, old_tab); + + /* This must be done before we remove the old table + * from the directory, or we will not be able + * to find the table, which could is require + * for TRUNCATE! + */ + if (xt_sl_get_size(db->db_table_by_id) >= XT_MAX_TABLES) + xt_throw_ulxterr(XT_CONTEXT, XT_ERR_TOO_MANY_TABLES, (u_long) XT_MAX_TABLES); + + tab_id = db->db_curr_tab_id + 1; + + if (old_tab) { + old_tab_id = old_tab->tab_id; + xt_dl_delete_ext_data(self, old_tab, FALSE, TRUE); + freer_(); // xt_heap_release(self, old_tab) + + /* For the Windows version this must be done before we + * start to delete the underlying files! + */ + tab_close_mapped_files(self, old_tab); + + tab_delete_table_files(self, name, old_tab_id); + + /* Remove the PBMS table: */ + ASSERT(xt_get_self() == self); +#ifdef XT_STREAMING + xt_pbms_drop_table(name->ps_path); +#endif + + /* Remove the table from the directory. It will get a new + * ID so the handle in the directory will no longer be valid. + */ + xt_ht_del(self, db->db_tables, name); + } + else { + freer_(); // xt_heap_release(self, old_tab) + } + + /* Add the table to the directory, well remove on error! */ + li_undo.li_sl = db->db_table_by_id; + li_undo.li_key = &tab_id; + te_tab.te_tab_id = tab_id; + te_tab.te_tab_name = xt_dup_string(self, xt_last_name_of_path(name->ps_path)); + te_tab.te_tab_path = tab_get_table_path(self, db, name, TRUE); + te_tab.te_table = NULL; + xt_sl_insert(self, db->db_table_by_id, &tab_id, &te_tab); + pushr_(xt_sl_delete_from_info, &li_undo); + + *path = 0; + try_(a) { + XTOpenFilePtr of_row, of_rec, of_ind; + off_t eof; + size_t def_len = 0; + + tab = (XTTableHPtr) xt_heap_new(self, sizeof(XTTableHRec), tab_finalize); + pushr_(xt_heap_release, tab); + + /* The length of the foreign key definition: */ + if (dic->dic_table) { + dic->dic_table->loadString(self, &tab_def); + def_len = tab_def.sb_len + 1; + } + + tab->tab_head_op_seq = 0; +#ifdef DEBUG + //tab->tab_head_op_seq = 0xFFFFFFFF - 12; +#endif + + /* ------- ROW FILE: */ + xt_strcpy(PATH_MAX, path, name->ps_path); + xt_remove_last_name_of_path(path); + tab_get_row_file_name(table_name, xt_last_name_of_path(name->ps_path), tab_id); + xt_strcat(PATH_MAX, path, table_name); + + of_row = xt_open_file(self, path, XT_FS_CREATE | XT_FS_EXCLUSIVE); + pushr_(xt_close_file, of_row); + XT_SET_DISK_4(row_head.rh_magic_4, XT_TAB_ROW_MAGIC); + if (!xt_pwrite_file(of_row, 0, sizeof(row_head), &row_head, &self->st_statistics.st_rec, self)) + xt_throw(self); + freer_(); // xt_close_file(of_row) + + (void) ASSERT(sizeof(XTTabRowHeadDRec) == sizeof(XTTabRowRefDRec)); + (void) ASSERT(sizeof(XTTabRowRefDRec) == 1 << XT_TAB_ROW_SHIFTS); + + tab->tab_row_eof_id = 1; + tab->tab_row_free_id = 0; + tab->tab_row_fnum = 0; + + tab->tab_head_row_eof_id = 1; + tab->tab_head_row_free_id = 0; + tab->tab_head_row_fnum = 0; + + /* ------------ DATA FILE: */ + xt_remove_last_name_of_path(path); + tab_get_data_file_name(table_name, xt_last_name_of_path(name->ps_path), tab_id); + xt_strcat(PATH_MAX, path, table_name); + of_rec = xt_open_file(self, path, XT_FS_CREATE | XT_FS_EXCLUSIVE); + pushr_(xt_close_file, of_rec); + + /* Calculate the offset of the first record in the data handle file. */ + eof = sizeof(XTTableHeadDRec) + offsetof(XTTableFormatDRec, tf_definition) + def_len + XT_FORMAT_DEF_SPACE; + eof = (eof + 1024 - 1) / 1024 * 1024; // Round to a value divisible by 1024 + + tab->tab_table_format_offset = sizeof(XTTableHeadDRec); + tab->tab_table_head_size = (size_t) eof; + + tab->tab_rec_eof_id = 1; // This is the first record ID! + tab->tab_rec_free_id = 0; + tab->tab_rec_fnum = 0; + + tab->tab_head_rec_eof_id = 1; // The first record ID + tab->tab_head_rec_free_id = 0; + tab->tab_head_rec_fnum = 0; + + tab->tab_dic.dic_rec_size = dic->dic_rec_size; + tab->tab_dic.dic_rec_fixed = dic->dic_rec_fixed; + tab->tab_dic.dic_tab_flags = dic->dic_tab_flags; + tab->tab_dic.dic_min_auto_inc = dic->dic_min_auto_inc; + tab->tab_dic.dic_def_ave_row_size = dic->dic_def_ave_row_size; + + XT_SET_DISK_4(rec_head.th_head_size_4, sizeof(XTTableHeadDRec)); + XT_SET_DISK_4(rec_head.th_op_seq_4, tab->tab_head_op_seq); + XT_SET_DISK_6(rec_head.th_row_free_6, tab->tab_head_row_free_id); + XT_SET_DISK_6(rec_head.th_row_eof_6, tab->tab_head_row_eof_id); + XT_SET_DISK_6(rec_head.th_row_fnum_6, tab->tab_head_row_fnum); + XT_SET_DISK_6(rec_head.th_rec_free_6, tab->tab_head_rec_free_id); + XT_SET_DISK_6(rec_head.th_rec_eof_6, tab->tab_head_rec_eof_id); + XT_SET_DISK_6(rec_head.th_rec_fnum_6, tab->tab_head_rec_fnum); + + if (!xt_pwrite_file(of_rec, 0, sizeof(XTTableHeadDRec), &rec_head, &self->st_statistics.st_rec, self)) + xt_throw(self); + + /* Store the table format: */ + memset(&table_fmt, 0, offsetof(XTTableFormatDRec, tf_definition)); + XT_SET_DISK_4(table_fmt.tf_format_size_4, offsetof(XTTableFormatDRec, tf_definition) + def_len); + XT_SET_DISK_4(table_fmt.tf_tab_head_size_4, eof); + XT_SET_DISK_2(table_fmt.tf_tab_version_2, XT_TAB_CURRENT_VERSION); + XT_SET_DISK_4(table_fmt.tf_rec_size_4, tab->tab_dic.dic_rec_size); + XT_SET_DISK_1(table_fmt.tf_rec_fixed_1, tab->tab_dic.dic_rec_fixed); + XT_SET_DISK_2(table_fmt.tf_tab_flags_2, tab->tab_dic.dic_tab_flags); + XT_SET_DISK_8(table_fmt.tf_min_auto_inc_8, tab->tab_dic.dic_min_auto_inc); + + if (!xt_pwrite_file(of_rec, sizeof(XTTableHeadDRec), offsetof(XTTableFormatDRec, tf_definition), &table_fmt, &self->st_statistics.st_rec, self)) + xt_throw(self); + if (def_len) { + if (!xt_pwrite_file(of_rec, sizeof(XTTableHeadDRec) + offsetof(XTTableFormatDRec, tf_definition), def_len, tab_def.sb_cstring, &self->st_statistics.st_rec, self)) + xt_throw(self); + } + + freer_(); // xt_close_file(of_rec) + + /* ----------- INDEX FILE: */ + xt_remove_last_name_of_path(path); + tab_get_index_file_name(table_name, xt_last_name_of_path(name->ps_path), tab_id); + xt_strcat(PATH_MAX, path, table_name); + of_ind = xt_open_file(self, path, XT_FS_CREATE | XT_FS_EXCLUSIVE); + pushr_(xt_close_file, of_ind); + + /* This is the size of the index header: */ + tab->tab_index_format_offset = offsetof(XTIndexHeadDRec, tp_data) + dic->dic_key_count * XT_NODE_REF_SIZE; + if (!(tab->tab_index_head = (XTIndexHeadDPtr) xt_calloc_ns(XT_INDEX_HEAD_SIZE))) + xt_throw(self); + + XT_NODE_ID(tab->tab_ind_eof) = 1; + XT_NODE_ID(tab->tab_ind_free) = 0; + + XT_SET_DISK_4(tab->tab_index_head->tp_header_size_4, XT_INDEX_HEAD_SIZE); + XT_SET_DISK_4(tab->tab_index_head->tp_format_offset_4, tab->tab_index_format_offset); + XT_SET_DISK_6(tab->tab_index_head->tp_ind_eof_6, XT_NODE_ID(tab->tab_ind_eof)); + XT_SET_DISK_6(tab->tab_index_head->tp_ind_free_6, XT_NODE_ID(tab->tab_ind_free)); + + /* Store the index format: */ + index_fmt = (XTIndexFormatDPtr) (((xtWord1 *) tab->tab_index_head) + tab->tab_index_format_offset); + XT_SET_DISK_4(index_fmt->if_format_size_4, sizeof(XTIndexFormatDRec)); + XT_SET_DISK_2(index_fmt->if_tab_version_2, XT_TAB_CURRENT_VERSION); + XT_SET_DISK_2(index_fmt->if_ind_version_2, XT_IND_CURRENT_VERSION); + XT_SET_DISK_1(index_fmt->if_node_ref_size_1, XT_NODE_REF_SIZE); + XT_SET_DISK_1(index_fmt->if_rec_ref_size_1, XT_RECORD_REF_SIZE); + XT_SET_DISK_4(index_fmt->if_page_size_4, XT_INDEX_PAGE_SIZE); + + /* Save the header: */ + if (!xt_pwrite_file(of_ind, 0, XT_INDEX_HEAD_SIZE, tab->tab_index_head, &self->st_statistics.st_ind, self)) + xt_throw(self); + + freer_(); // xt_close_file(of_ind) + + /* ------------ */ + /* Log the new table ID! */ + db->db_curr_tab_id = tab_id; + if (!xt_xn_log_tab_id(self, tab_id)) { + db->db_curr_tab_id = tab_id - 1; + xt_throw(self); + } + + freer_(); // xt_heap_release(tab) + + /* {LOAD-FOR-FKS} + * 2008-12-10: Note, there is another problem, example: + * set storage_engine = pbxt; + * + * CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 INT); + * CREATE TABLE t2 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t1 (s1) ON UPDATE CASCADE); + * CREATE TABLE t3 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t2 (s1) ON UPDATE CASCADE); + * + * DROP TABLE IF EXISTS t2,t1; + * CREATE TABLE t1 (s1 ENUM('a','b') PRIMARY KEY); + * CREATE TABLE t2 (s1 ENUM('A','B'), FOREIGN KEY (s1) REFERENCES t1 (s1)); + * + * DROP TABLE IF EXISTS t2,t1; + * + * In the example above. The second create t2 does not fail, although t3 references it, + * and the data types do not match. + * + * The main problem is that this error comes on DROP TABLE IF EXISTS t2! Which prevents + * the table from being dropped - not good. + * + * So my idea here is to open the table, and if it fails, then the create table fails + * as well. + */ + if (!old_tab_id) { + tab = xt_use_table_no_lock(self, db, name, FALSE, FALSE, NULL, NULL); + xt_heap_release(self, tab); + } + } + catch_(a) { + /* Creation failed, delete the table files: */ + if (*path) + tab_delete_table_files(self, name, tab_id); + tab_remove_table_path(self, db, te_tab.te_tab_path); + xt_sb_set_size(self, &tab_def, 0); + throw_(); + } + cont_(a); + + xt_sb_set_size(self, &tab_def, 0); + + if (old_tab_id) { + try_(b) { + XTTableEntryPtr te_ptr; + + if ((te_ptr = (XTTableEntryPtr) xt_sl_find(self, db->db_table_by_id, &old_tab_id))) { + tab_remove_table_path(self, db, te_ptr->te_tab_path); + xt_sl_delete(self, db->db_table_by_id, &old_tab_id); + } + + /* Same purpose as above {LOAD-FOR-FKS} (although this should work, + * beacuse this is a TRUNCATE TABLE. + */ + tab = xt_use_table_no_lock(self, db, name, FALSE, FALSE, NULL, NULL); + xt_heap_release(self, tab); + } + catch_(b) { + /* Log this error, but do not return it, because + * it just involves the cleanup of the old table, + * the new table has been successfully created. + */ + xt_log_and_clear_exception(self); + } + cont_(b); + } + + popr_(); // Discard xt_sl_delete_from_info(&li_undo) + + freer_(); // xt_ht_unlock(db->db_tables) + freer_(); // xt_db_unlock_table_pool(table_pool) + + /* I open the table here, because I cannot rely on MySQL to do + * it after a create. This is normally OK, but with foreign keys + * tables can be referenced and then they are not opened + * before use. In this example, the INSERT opens t2, but t1 is + * not opened of the create. As a result the foreign key + * reference is not resolved. + * + * drop table t1, t2; + * CREATE TABLE t1 + * ( + * id INT PRIMARY KEY + * ) ENGINE=pbxt; + * + * CREATE TABLE t2 + * ( + * v INT, + * CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) + * ) ENGINE=pbxt; + * + * --error 1452 + * INSERT INTO t2 VALUES(2); + */ + /* this code is not needed anymore as we open tables referred by FKs as necessary during checks + xt_ht_lock(self, db->db_tables); + pushr_(xt_ht_unlock, db->db_tables); + tab = xt_use_table_no_lock(self, db, name, FALSE, FALSE, NULL, NULL); + freer_(); // xt_ht_unlock(db->db_tables) + xt_heap_release(self, tab); + * CHANGED see {LOAD-FOR-FKS} above. + */ + + exit_(); +} + +xtPublic void xt_drop_table(XTThreadPtr self, XTPathStrPtr tab_name) +{ + XTDatabaseHPtr db = self->st_database; + XTOpenTablePoolPtr table_pool; + XTTableHPtr tab = NULL; + xtTableID tab_id = 0; + xtBool can_drop = TRUE; + + enter_(); + +#ifdef TRACE_CREATE_TABLES + printf("DROP %s\n", tab_name->ps_path); +#endif + + table_pool = tab_lock_table(self, tab_name, FALSE, TRUE, TRUE, &tab); + pushr_(xt_db_unlock_table_pool, table_pool); + xt_ht_lock(self, db->db_tables); + pushr_(xt_ht_unlock, db->db_tables); + pushr_(xt_heap_release, tab); + + if (table_pool) { + tab_id = tab->tab_id; /* tab is not null if returned table_pool is not null */ + /* check if other tables refer this */ + if (!self->st_ignore_fkeys) + can_drop = tab->tab_dic.dic_table->checkCanDrop(); + } + + if (can_drop) { + if (tab_id) { + XTTableEntryPtr te_ptr; + + xt_dl_delete_ext_data(self, tab, FALSE, TRUE); + freer_(); // xt_heap_release(self, tab) + + /* For the Windows version this must be done before we + * start to delete the underlying files! + */ + tab_close_mapped_files(self, tab); + + tab_delete_table_files(self, tab_name, tab_id); + + ASSERT(xt_get_self() == self); +#ifdef XT_STREAMING + xt_pbms_drop_table(tab_name->ps_path); +#endif + if ((te_ptr = (XTTableEntryPtr) xt_sl_find(self, db->db_table_by_id, &tab_id))) { + tab_remove_table_path(self, db, te_ptr->te_tab_path); + xt_sl_delete(self, db->db_table_by_id, &tab_id); + } + } + else { + freer_(); // xt_heap_release(self, tab) + } + + xt_ht_del(self, db->db_tables, tab_name); + } + else { /* cannot drop table because of FK dependencies */ + xt_throw_xterr(XT_CONTEXT, XT_ERR_ROW_IS_REFERENCED); + } + + freer_(); // xt_ht_unlock(db->db_tables) + freer_(); // xt_db_unlock_table_pool(table_pool) + exit_(); +} + +/* + * Record buffer size: + * ------------------- + * The size of the record buffer used to hold the row + * in memory. This buffer size does not include the BLOB data. + * About 8 bytes (a pointer and a size) is reserved for each BLOB + * in this buffer. + * + * The buffer size includes a number of "NULL" bytes followed by + * the data area. The NULL bytes contain 1 bit for every column, + * to indicate of the columns is NULL or not. + * + * The size of the buffer is 4/8-byte aligned, so it may be padded + * at the end. + * + * Fixed length rec. len.: + * ----------------------- + * If the record does not include any BLOBs then this is the size of the + * fixed length record. The size if the data in the data handle record + * need never be bigger then this length, if the record does not + * contain BLOBs. So this should be the maximum size set for + * AVG_ROW_LENGTH in this case. + * + * Handle data record size: + * ------------------------ + * This is the size of the handle data record. It is the data size + * plus the "max header size". + * + * Min/max header size: + * The min and max header size of the header in the data handle file. + * The larger header is used if a record has an extended data (data log + * file) component. + * + * Min/avg/max record size: + * ------------------------ + * These are variable length records sizes. That is, the size of records + * when stored in the variable length format. Variable length records + * do not have fixed fields sizes, instead the fields are packed one + * after the other, prefixed by a number of size indicator bytes. + * + * The average is an estimate of the average record size. This estimate + * is used if no AVG_ROW_LENGTH is specifically given. + * + * If the average estimate is withing 20% of the maximum size of the record, + * then the record will be handled as a fixed length record. + * + * Avg row len set for tab: + * ------------------------ + * This is the value set using AVG_ROW_LENGTH when the table is declared. + * + * Rows fixed length: + * ------------------ + * YES if the records of this table are handled as a fixed length records. + * In this case the table records will never have an extended record + * component. + * + * The size of the data area in the handle data record is set to the + * size of the MySQL data record ("Fixed length rec. len."). + * + * It also means that the record format used is identical to the MySQL + * record format. + * + * If the records are not fixed, then the variable length record format + * is used. Records size are then in the range specified by + * "Min/avg/max record size". + * + * Maximum fixed size: + * ------------------- + * This is the maximum size of a data log record. + * + * Minimum variable size: + * ------------------------ + * Records below this size are handled as a fixed length record size, unless + * the AVG_ROW_LENGTH is specifically set. + */ +xtPublic void xt_check_table(XTThreadPtr self, XTOpenTablePtr ot) +{ + XTTableHPtr tab = ot->ot_table; + xtRecordID prec_id; + XTTabRecExtDPtr rec_buf = (XTTabRecExtDPtr) ot->ot_row_rbuffer; + XTactExtRecEntryDRec ext_rec; + size_t log_size; + xtLogID log_id; + xtLogOffset log_offset; + xtRecordID rec_id; + xtRecordID prev_rec_id; + xtXactID xn_id; + xtRowID row_id; + u_llong free_rec_count = 0, free_count2 = 0; + u_llong delete_rec_count = 0; + u_llong alloc_rec_count = 0; + u_llong alloc_rec_bytes = 0; + u_llong min_comp_rec_len = 0; + u_llong max_comp_rec_len = 0; + size_t rec_size; + size_t row_size; + +#if defined(DUMP_CHECK_TABLE) || defined(CHECK_TABLE_STATS) + printf("\nCHECK TABLE: %s\n", tab->tab_name->ps_path); +#endif + + xt_lock_mutex(self, &tab->tab_db->db_co_ext_lock); + pushr_(xt_unlock_mutex, &tab->tab_db->db_co_ext_lock); + + xt_lock_mutex(self, &tab->tab_rec_lock); + pushr_(xt_unlock_mutex, &tab->tab_rec_lock); + +#ifdef CHECK_TABLE_STATS + printf("Record buffer size = %lu\n", (u_long) tab->tab_dic.dic_mysql_buf_size); + printf("Fixed length rec. len. = %lu\n", (u_long) tab->tab_dic.dic_mysql_rec_size); + printf("Handle data record size = %lu\n", (u_long) tab->tab_dic.dic_rec_size); + printf("Min/max header size = %d/%d\n", (int) offsetof(XTTabRecFix, rf_data), tab->tab_dic.dic_rec_fixed ? (int) offsetof(XTTabRecFix, rf_data) : (int) offsetof(XTTabRecExtDRec, re_data)); + printf("Min/avg/max record size = %llu/%llu/%llu\n", (u_llong) tab->tab_dic.dic_min_row_size, (u_llong) tab->tab_dic.dic_ave_row_size, (u_llong) tab->tab_dic.dic_max_row_size); + if (tab->tab_dic.dic_def_ave_row_size) + printf("Avg row len set for tab = %lu\n", (u_long) tab->tab_dic.dic_def_ave_row_size); + else + printf("Avg row len set for tab = not specified\n"); + printf("Rows fixed length = %s\n", tab->tab_dic.dic_rec_fixed ? "YES" : "NO"); + if (tab->tab_dic.dic_tab_flags & XT_TAB_FLAGS_TEMP_TAB) + printf("Table type = TEMP\n"); + if (tab->tab_dic.dic_def_ave_row_size) + printf("Maximum fixed size = %lu\n", (u_long) XT_TAB_MAX_FIX_REC_LENGTH_SPEC); + else + printf("Maximum fixed size = %lu\n", (u_long) XT_TAB_MAX_FIX_REC_LENGTH); + printf("Minimum variable size = %lu\n", (u_long) XT_TAB_MIN_VAR_REC_LENGTH); + printf("Minimum auto-increment = %llu\n", (u_llong) tab->tab_dic.dic_min_auto_inc); + printf("Number of columns = %lu\n", (u_long) tab->tab_dic.dic_no_of_cols); + printf("Number of fixed columns = %lu\n", (u_long) tab->tab_dic.dic_fix_col_count); + printf("Columns req. for index = %lu\n", (u_long) tab->tab_dic.dic_ind_cols_req); + if (tab->tab_dic.dic_ind_rec_len) + printf("Rec len req. for index = %llu\n", (u_llong) tab->tab_dic.dic_ind_rec_len); + printf("Columns req. for blobs = %lu\n", (u_long) tab->tab_dic.dic_blob_cols_req); + printf("Number of blob columns = %lu\n", (u_long) tab->tab_dic.dic_blob_count); + printf("Number of indices = %lu\n", (u_long) tab->tab_dic.dic_key_count); +#endif + +#ifdef DUMP_CHECK_TABLE + printf("Records:-\n"); + printf("Free list: %llu (%llu)\n", (u_llong) tab->tab_rec_free_id, (u_llong) tab->tab_rec_fnum); + printf("EOF: %llu\n", (u_llong) tab->tab_rec_eof_id); +#endif + + rec_size = XT_REC_EXT_HEADER_SIZE; + if (rec_size > tab->tab_recs.tci_rec_size) + rec_size = tab->tab_recs.tci_rec_size; + rec_id = 1; + while (rec_id < tab->tab_rec_eof_id) { + if (!xt_tab_get_rec_data(ot, rec_id, tab->tab_dic.dic_rec_size, ot->ot_row_rbuffer)) + xt_throw(self); + +#ifdef DUMP_CHECK_TABLE + printf("%-4llu ", (u_llong) rec_id); +#endif + switch (rec_buf->tr_rec_type_1 & XT_TAB_STATUS_MASK) { + case XT_TAB_STATUS_FREED: +#ifdef DUMP_CHECK_TABLE + printf("======== "); +#endif + free_rec_count++; + break; + case XT_TAB_STATUS_DELETE: +#ifdef DUMP_CHECK_TABLE + printf("delete "); +#endif + delete_rec_count++; + break; + case XT_TAB_STATUS_FIXED: +#ifdef DUMP_CHECK_TABLE + printf("record-F "); +#endif + alloc_rec_count++; + row_size = myxt_store_row_length(ot, (char *) ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE); + alloc_rec_bytes += row_size; + if (!min_comp_rec_len || row_size < min_comp_rec_len) + min_comp_rec_len = row_size; + if (row_size > max_comp_rec_len) + max_comp_rec_len = row_size; + break; + case XT_TAB_STATUS_VARIABLE: +#ifdef DUMP_CHECK_TABLE + printf("record-V "); +#endif + alloc_rec_count++; + row_size = myxt_load_row_length(ot, tab->tab_dic.dic_rec_size, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, NULL); + alloc_rec_bytes += row_size; + if (!min_comp_rec_len || row_size < min_comp_rec_len) + min_comp_rec_len = row_size; + if (row_size > max_comp_rec_len) + max_comp_rec_len = row_size; + break; + case XT_TAB_STATUS_EXT_DLOG: +#ifdef DUMP_CHECK_TABLE + printf("record-X "); +#endif + alloc_rec_count++; + row_size = XT_GET_DISK_4(rec_buf->re_log_dat_siz_4) + ot->ot_rec_size - XT_REC_EXT_HEADER_SIZE; + alloc_rec_bytes += row_size; + if (!min_comp_rec_len || row_size < min_comp_rec_len) + min_comp_rec_len = row_size; + if (row_size > max_comp_rec_len) + max_comp_rec_len = row_size; + break; + } +#ifdef DUMP_CHECK_TABLE + if (rec_buf->tr_rec_type_1 & XT_TAB_STATUS_CLEANED_BIT) + printf("C"); + else + printf(" "); +#endif + prev_rec_id = XT_GET_DISK_4(rec_buf->tr_prev_rec_id_4); + xn_id = XT_GET_DISK_4(rec_buf->tr_xact_id_4); + row_id = XT_GET_DISK_4(rec_buf->tr_row_id_4); + switch (rec_buf->tr_rec_type_1 & XT_TAB_STATUS_MASK) { + case XT_TAB_STATUS_FREED: +#ifdef DUMP_CHECK_TABLE + printf(" prev=%-3llu (xact=%-3llu row=%lu)\n", (u_llong) prev_rec_id, (u_llong) xn_id, (u_long) row_id); +#endif + break; + case XT_TAB_STATUS_EXT_DLOG: +#ifdef DUMP_CHECK_TABLE + printf(" prev=%-3llu xact=%-3llu row=%lu Xlog=%lu Xoff=%llu Xsiz=%lu\n", (u_llong) prev_rec_id, (u_llong) xn_id, (u_long) row_id, (u_long) XT_GET_DISK_2(rec_buf->re_log_id_2), (u_llong) XT_GET_DISK_6(rec_buf->re_log_offs_6), (u_long) XT_GET_DISK_4(rec_buf->re_log_dat_siz_4)); +#endif + + log_size = XT_GET_DISK_4(rec_buf->re_log_dat_siz_4); + XT_GET_LOG_REF(log_id, log_offset, rec_buf); + if (!self->st_dlog_buf.dlb_read_log(log_id, log_offset, offsetof(XTactExtRecEntryDRec, er_data), (xtWord1 *) &ext_rec, self)) + xt_log_and_clear_exception(self); + else { + size_t log_size2; + xtTableID curr_tab_id; + xtRecordID curr_rec_id; + + log_size2 = XT_GET_DISK_4(ext_rec.er_data_size_4); + curr_tab_id = XT_GET_DISK_4(ext_rec.er_tab_id_4); + curr_rec_id = XT_GET_DISK_4(ext_rec.er_rec_id_4); + if (log_size2 != log_size || curr_tab_id != tab->tab_id || curr_rec_id != rec_id) { + xt_logf(XT_INFO, "Table %s: record %llu, extended record %lu:%llu not valid\n", tab->tab_name, (u_llong) rec_id, (u_long) log_id, (u_llong) log_offset); + } + } + break; + default: +#ifdef DUMP_CHECK_TABLE + printf(" prev=%-3llu xact=%-3llu row=%lu\n", (u_llong) prev_rec_id, (u_llong) xn_id, (u_long) row_id); +#endif + break; + } + rec_id++; + } + +#ifdef CHECK_TABLE_STATS + if (alloc_rec_count) { + printf("Minumum comp. rec. len. = %llu\n", (u_llong) min_comp_rec_len); + printf("Average comp. rec. len. = %llu\n", (u_llong) ((double) alloc_rec_bytes / (double) alloc_rec_count + (double) 0.5)); + printf("Maximum comp. rec. len. = %llu\n", (u_llong) max_comp_rec_len); + } + printf("Free record count = %llu\n", (u_llong) free_rec_count); + printf("Deleted record count = %llu\n", (u_llong) delete_rec_count); + printf("Allocated record count = %llu\n", (u_llong) alloc_rec_count); +#endif + if (tab->tab_rec_fnum != free_rec_count) + xt_logf(XT_INFO, "Table %s: incorrect number of free blocks, %llu, should be: %llu\n", tab->tab_name, (u_llong) free_rec_count, (u_llong) tab->tab_rec_fnum); + + /* Checking the free list: */ + prec_id = 0; + rec_id = tab->tab_rec_free_id; + while (rec_id) { + if (rec_id >= tab->tab_rec_eof_id) { + xt_logf(XT_INFO, "Table %s: invalid reference on free list: %llu, ", tab->tab_name, (u_llong) rec_id); + if (prec_id) + xt_logf(XT_INFO, "reference by: %llu\n", (u_llong) prec_id); + else + xt_logf(XT_INFO, "reference by list head pointer\n"); + break; + } + if (!xt_tab_get_rec_data(ot, rec_id, XT_REC_FIX_HEADER_SIZE, (xtWord1 *) rec_buf)) { + xt_log_and_clear_exception(self); + break; + } + if ((rec_buf->tr_rec_type_1 & XT_TAB_STATUS_MASK) != XT_TAB_STATUS_FREED) + xt_logf(XT_INFO, "Table %s: record, %llu, on free list is not free\n", tab->tab_name, (u_llong) rec_id); + free_count2++; + prec_id = rec_id; + rec_id = XT_GET_DISK_4(rec_buf->tr_prev_rec_id_4); + } + if (free_count2 < free_rec_count) + xt_logf(XT_INFO, "Table %s: not all free blocks (%llu) on free list: %llu\n", tab->tab_name, (u_llong) free_rec_count, (u_llong) free_count2); + + freer_(); // xt_unlock_mutex_ns(&tab->tab_rec_lock); + + xtRefID ref_id; + + xt_lock_mutex(self, &tab->tab_row_lock); + pushr_(xt_unlock_mutex, &tab->tab_row_lock); + +#ifdef DUMP_CHECK_TABLE + printf("Rows:-\n"); + printf("Free list: %llu (%llu)\n", (u_llong) tab->tab_row_free_id, (u_llong) tab->tab_row_fnum); + printf("EOF: %llu\n", (u_llong) tab->tab_row_eof_id); +#endif + + rec_id = 1; + while (rec_id < tab->tab_row_eof_id) { + if (!tab->tab_rows.xt_tc_read_4(ot->ot_row_file, rec_id, &ref_id, self)) + xt_throw(self); +#ifdef DUMP_CHECK_TABLE + printf("%-3llu ", (u_llong) rec_id); +#endif +#ifdef DUMP_CHECK_TABLE + if (ref_id == 0) + printf("====== 0\n"); + else + printf("in use %llu\n", (u_llong) ref_id); +#endif + rec_id++; + } + + freer_(); // xt_unlock_mutex(&tab->tab_row_lock); + +#ifdef CHECK_INDEX_ON_CHECK_TABLE + xt_check_indices(ot); +#endif + freer_(); // xt_unlock_mutex(&tab->tab_db->db_co_ext_lock); +} + +xtPublic void xt_rename_table(XTThreadPtr self, XTPathStrPtr old_name, XTPathStrPtr new_name) +{ + XTDatabaseHPtr db = self->st_database; + XTOpenTablePoolPtr table_pool; + XTTableHPtr tab = NULL; + char table_name[XT_MAX_TABLE_FILE_NAME_SIZE]; + char *postfix; + XTFilesOfTableRec ft; + XTDictionaryRec dic; + xtTableID tab_id; + XTTableEntryPtr te_ptr; + char *te_new_name; + XTTablePathPtr te_new_path; + XTTablePathPtr te_old_path; + char to_path[PATH_MAX]; + + memset(&dic, 0, sizeof(dic)); + +#ifdef TRACE_CREATE_TABLES + printf("RENAME %s --> %s\n", old_name->ps_path, new_name->ps_path); +#endif + if (strlen(xt_last_name_of_path(new_name->ps_path)) > XT_TABLE_NAME_SIZE-1) + xt_throw_taberr(XT_CONTEXT, XT_ERR_NAME_TOO_LONG, new_name); + + /* MySQL renames the table while it is in use. Here is + * the sequence: + * + * OPEN tab1 + * CREATE tmp_tab + * OPEN tmp_tab + * COPY tab1 -> tmp_tab + * CLOSE tmp_tab + * RENAME tab1 -> tmp2_tab + * RENAME tmp_tab -> tab1 + * CLOSE tab1 (tmp2_tab) + * DELETE tmp2_tab + * OPEN tab1 + * + * Since the table is open when it is renamed, I cannot + * get exclusive use of the table for this operation. + * + * So instead we just make sure that the sweeper is not + * using the table. + */ + table_pool = tab_lock_table(self, old_name, FALSE, TRUE, FALSE, &tab); + pushr_(xt_db_unlock_table_pool, table_pool); + xt_ht_lock(self, db->db_tables); + pushr_(xt_ht_unlock, db->db_tables); + tab_id = tab->tab_id; + myxt_move_dictionary(&dic, &tab->tab_dic); + pushr_(myxt_free_dictionary, &dic); + pushr_(xt_heap_release, tab); + + /* Unmap the memory mapped table files: + * For windows this must be done before we + * can rename the files. + */ + tab_close_mapped_files(self, tab); + + freer_(); // xt_heap_release(self, old_tab) + + /* Create the new name and path: */ + te_new_name = xt_dup_string(self, xt_last_name_of_path(new_name->ps_path)); + pushr_(xt_free, te_new_name); + te_new_path = tab_get_table_path(self, db, new_name, FALSE); + pushr_(tab_free_table_path, te_new_path); + + te_ptr = (XTTableEntryPtr) xt_sl_find(self, db->db_table_by_id, &tab_id); + + /* Remove the table from the Database directory: */ + xt_ht_del(self, db->db_tables, old_name); + + xt_enum_files_of_tables_init(old_name, tab_id, &ft); + while (xt_enum_files_of_tables_next(&ft)) { + postfix = xt_tab_file_to_name(XT_MAX_TABLE_FILE_NAME_SIZE, table_name, ft.ft_file_path); + + xt_strcpy(PATH_MAX, to_path, new_name->ps_path); + xt_strcat(PATH_MAX, to_path, postfix); + + if (!xt_fs_rename(NULL, ft.ft_file_path, to_path)) + xt_log_and_clear_exception(self); + } + + /* Switch the table name and path: */ + xt_free(self, te_ptr->te_tab_name); + te_ptr->te_tab_name = te_new_name; + te_old_path = te_ptr->te_tab_path; + te_ptr->te_tab_path = te_new_path; + tab_remove_table_path(self, db, te_old_path); + + popr_(); // Discard tab_free_table_path(te_new_path); + popr_(); // Discard xt_free(te_new_name); + + tab = xt_use_table_no_lock(self, db, new_name, FALSE, FALSE, &dic, NULL); + xt_heap_release(self, tab); + + freer_(); // myxt_free_dictionary(&dic) + freer_(); // xt_ht_unlock(db->db_tables) + freer_(); // xt_db_unlock_table_pool(table_pool) +} + +xtPublic XTTableHPtr xt_use_table(XTThreadPtr self, XTPathStrPtr name, xtBool no_load, xtBool missing_ok, xtBool *opened) +{ + XTTableHPtr tab; + XTDatabaseHPtr db = self->st_database; + + xt_ht_lock(self, db->db_tables); + pushr_(xt_ht_unlock, db->db_tables); + tab = xt_use_table_no_lock(self, db, name, no_load, missing_ok, NULL, opened); + freer_(); + return tab; +} + +xtPublic void xt_sync_flush_table(XTThreadPtr self, XTOpenTablePtr ot) +{ + XTTableHPtr tab = ot->ot_table; + XTDatabaseHPtr db = tab->tab_db; + + /* Wakeup the sweeper: + * We want the sweeper to check if there is anything to do, + * so we must wake it up. + * Once it has done all it can, it will go back to sleep. + * This should be good enough. + * + * NOTE: I all cases, we do not wait if the sweeper is in + * error state. + */ + if (db->db_sw_idle) { + u_int check_count = db->db_sw_check_count; + + for (;;) { + xt_wakeup_sweeper(db); + if (!db->db_sw_thread || db->db_sw_idle != XT_THREAD_IDLE || check_count != db->db_sw_check_count) + break; + xt_sleep_milli_second(10); + } + } + + /* Wait for the sweeper to become idle: */ + xt_lock_mutex(self, &db->db_sw_lock); + pushr_(xt_unlock_mutex, &db->db_sw_lock); + while (db->db_sw_thread && !db->db_sw_idle) { + xt_timed_wait_cond(self, &db->db_sw_cond, &db->db_sw_lock, 10); + } + freer_(); // xt_unlock_mutex(&db->db_sw_lock) + + /* Wait for the writer to write out all operations on the table: + * We also do not wait for the writer if it is in + * error state. + */ + while (db->db_wr_thread && + db->db_wr_idle != XT_THREAD_INERR && + XTTableSeq::xt_op_is_before(tab->tab_head_op_seq+1, tab->tab_seq.ts_next_seq)) { + /* Flush the log, in case this is holding up the + * writer! + */ + if (!db->db_xlog.xlog_flush(self)) + xt_throw(self); + + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + db->db_wr_thread_waiting++; + /* + * Wake the writer if it is sleeping. In order to + * flush a table we must wait for the writer to complete + * committing all the changes in the table to the database. + */ + if (db->db_wr_idle) { + if (!xt_broadcast_cond_ns(&db->db_wr_cond)) + xt_log_and_clear_exception_ns(); + } + + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + xt_sleep_milli_second(10); + + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + db->db_wr_thread_waiting--; + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + } + + xt_flush_table(self, ot); +} + +xtPublic xtBool xt_flush_record_row(XTOpenTablePtr ot, off_t *bytes_flushed, xtBool have_table_lock) +{ + XTTableHeadDRec rec_head; + XTTableHPtr tab = ot->ot_table; + off_t to_flush; + XTCheckPointTablePtr cp_tab; + XTCheckPointStatePtr cp = NULL; + + if (!xt_begin_checkpoint(tab->tab_db, have_table_lock, ot->ot_thread)) + return FAILED; + + xt_lock_mutex_ns(&tab->tab_rec_flush_lock); + + ASSERT_NS(ot->ot_thread == xt_get_self()); + /* Make sure that the table recovery point, in + * particular the operation ID is recorded + * before all other flush activity! + * + * This is because only operations after the + * recovery point in the header are applied + * to the table on recovery. + * + * So the operation ID is recorded before the + * flush activity, and written after all is done. + */ + xt_tab_store_header(ot, &rec_head); + +#ifdef TRACE_FLUSH + printf("FLUSH rec/row %d %s\n", (int) tab->tab_bytes_to_flush, tab->tab_name->ps_path); + fflush(stdout); +#endif + /* Write the table header: */ + if (tab->tab_flush_pending) { + tab->tab_flush_pending = FALSE; + // Want to see how much was to be flushed in the debugger: + to_flush = tab->tab_bytes_to_flush; + tab->tab_bytes_to_flush = 0; + if (bytes_flushed) + *bytes_flushed += to_flush; + /* Flush the table data: */ + if (!(tab->tab_dic.dic_tab_flags & XT_TAB_FLAGS_TEMP_TAB)) { + if (!XT_FLUSH_RR_FILE(ot->ot_rec_file, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread) || + !XT_FLUSH_RR_FILE(ot->ot_row_file, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) { + tab->tab_flush_pending = TRUE; + goto failed; + } + } + + /* The header includes the operation number which + * must be written AFTER all other data, + * because operations will not be applied again. + */ + if (!xt_tab_write_header(ot, &rec_head, ot->ot_thread)) { + tab->tab_flush_pending = TRUE; + goto failed; + } + } + + /* Flush the auto-increment: */ + if (xt_db_auto_increment_mode == 1) { + if (tab->tab_auto_inc != tab->tab_dic.dic_min_auto_inc) { + tab->tab_dic.dic_min_auto_inc = tab->tab_auto_inc; + if (!xt_tab_write_min_auto_inc(ot)) + goto failed; + } + } + + /* Mark this table as record/row flushed: */ + cp = &tab->tab_db->db_cp_state; + xt_lock_mutex_ns(&cp->cp_state_lock); + if (cp->cp_running) { + cp_tab = (XTCheckPointTablePtr) xt_sl_find(NULL, cp->cp_table_ids, &tab->tab_id); + if (cp_tab && (cp_tab->cpt_flushed & XT_CPT_ALL_FLUSHED) != XT_CPT_ALL_FLUSHED) { + cp_tab->cpt_flushed |= XT_CPT_REC_ROW_FLUSHED; + if ((cp_tab->cpt_flushed & XT_CPT_ALL_FLUSHED) == XT_CPT_ALL_FLUSHED) { + ASSERT_NS(cp->cp_flush_count < xt_sl_get_size(cp->cp_table_ids)); + cp->cp_flush_count++; + } + } + } + xt_unlock_mutex_ns(&cp->cp_state_lock); + +#ifdef TRACE_FLUSH + printf("FLUSH --end-- %s\n", tab->tab_name->ps_path); + fflush(stdout); +#endif + xt_unlock_mutex_ns(&tab->tab_rec_flush_lock); + + if (!xt_end_checkpoint(tab->tab_db, ot->ot_thread, NULL)) + return FAILED; + return OK; + + failed: + xt_unlock_mutex_ns(&tab->tab_rec_flush_lock); + return FAILED; +} + +xtPublic void xt_flush_table(XTThreadPtr self, XTOpenTablePtr ot) +{ + /* GOTCHA [*10*]: This bug was difficult to find. + * It occured on Windows in the multi_update + * test, sometimes. + * + * What happens is the checkpointer starts to + * flush the table, and gets to the + * XT_FLUSH_RR_FILE part. + * + * Then a rename occurs, and the user thread + * flushes the table, and goes through and + * writes the table header, with the most + * recent table operation (the last operation + * that occurred). + * + * The checkpointer the completes and + * also writes the header, but with old + * values (as read in xt_tab_store_header()). + * + * The then user thread continues, and + * reopens the table after rename. + * On reopen, it reads the old value from the header, + * and sets the current operation number. + * + * Now there is a problem in the able cache, + * because some cache pages have operation numbers + * that are greater than current operation + * number! + * + * This later lead to the free-er hanging while + * it waited for an operation to be + * written to the disk that never would be. + * This is because a page can only be freed when + * the head operation number has passed the + * page operation number. + * + * Which indicates that the page has been written + * to disk. + */ + + if (!xt_flush_record_row(ot, NULL, FALSE)) + xt_throw(self); + + /* This was before the table data flush, + * (after xt_tab_store_header() above, + * but I don't think it makes any difference. + * Because in the checkpointer it was at this + * position. + */ + if (!xt_flush_indices(ot, NULL, FALSE)) + xt_throw(self); + +} + +xtPublic XTOpenTablePtr tab_open_table(XTTableHPtr tab) +{ + volatile XTOpenTablePtr ot; + XTThreadPtr self; + + if (!(ot = (XTOpenTablePtr) xt_malloc_ns(sizeof(XTOpenTableRec)))) + return NULL; + memset(ot, 0, offsetof(XTOpenTableRec, ot_ind_wbuf)); + + self = xt_get_self(); + try_(a) { + xt_heap_reference(self, tab); + ot->ot_table = tab; +#ifdef XT_USE_ROW_REC_MMAP_FILES + ot->ot_row_file = xt_open_fmap(self, ot->ot_table->tab_row_file->fil_path, xt_db_row_file_grow_size); + ot->ot_rec_file = xt_open_fmap(self, ot->ot_table->tab_rec_file->fil_path, xt_db_data_file_grow_size); +#else + ot->ot_row_file = xt_open_file(self, ot->ot_table->tab_row_file->fil_path, XT_FS_DEFAULT); + ot->ot_rec_file = xt_open_file(self, ot->ot_table->tab_rec_file->fil_path, XT_FS_DEFAULT); +#endif +#ifdef XT_USE_DIRECT_IO_ON_INDEX + ot->ot_ind_file = xt_open_file(self, ot->ot_table->tab_ind_file->fil_path, XT_FS_MISSING_OK | XT_FS_DIRECT_IO); +#else + ot->ot_ind_file = xt_open_file(self, ot->ot_table->tab_ind_file->fil_path, XT_FS_MISSING_OK); +#endif + } + catch_(a) { + ; + } + cont_(a); + + if (!ot->ot_table || !ot->ot_row_file || !ot->ot_rec_file) + goto failed; + + if (!(ot->ot_row_rbuffer = (xtWord1 *) xt_malloc_ns(ot->ot_table->tab_dic.dic_rec_size))) + goto failed; + ot->ot_row_rbuf_size = ot->ot_table->tab_dic.dic_rec_size; + if (!(ot->ot_row_wbuffer = (xtWord1 *) xt_malloc_ns(ot->ot_table->tab_dic.dic_rec_size))) + goto failed; + ot->ot_row_wbuf_size = ot->ot_table->tab_dic.dic_rec_size; + + /* Cache this stuff to speed access a bit: */ + ot->ot_rec_fixed = ot->ot_table->tab_dic.dic_rec_fixed; + ot->ot_rec_size = ot->ot_table->tab_dic.dic_rec_size; + + return ot; + + failed: + tab_close_table(ot); + return NULL; +} + +xtPublic XTOpenTablePtr xt_open_table(XTTableHPtr tab) +{ + return tab_open_table(tab); +} + +xtPublic void xt_close_table(XTOpenTablePtr ot, xtBool flush, xtBool have_table_lock) +{ + if (flush) { + if (!xt_flush_record_row(ot, NULL, have_table_lock)) + xt_log_and_clear_exception_ns(); + + if (!xt_flush_indices(ot, NULL, have_table_lock)) + xt_log_and_clear_exception_ns(); + } + tab_close_table(ot); +} + +xtPublic int xt_use_table_by_id(XTThreadPtr self, XTTableHPtr *r_tab, XTDatabaseHPtr db, xtTableID tab_id) +{ + XTTableEntryPtr te_ptr; + XTTableHPtr tab = NULL; + int r = XT_TAB_OK; + char path[PATH_MAX]; + + if (!db) + xt_throw_xterr(XT_CONTEXT, XT_ERR_NO_DATABASE_IN_USE); + xt_ht_lock(self, db->db_tables); + pushr_(xt_ht_unlock, db->db_tables); + + te_ptr = (XTTableEntryPtr) xt_sl_find(self, db->db_table_by_id, &tab_id); + if (te_ptr) { + if (!(tab = te_ptr->te_table)) { + /* Open the table: */ + xt_strcpy(PATH_MAX, path, te_ptr->te_tab_path->tp_path); + xt_add_dir_char(PATH_MAX, path); + xt_strcat(PATH_MAX, path, te_ptr->te_tab_name); + r = tab_new_handle(self, &tab, db, tab_id, (XTPathStrPtr) path, TRUE, NULL); + } + } + else + r = XT_TAB_NOT_FOUND; + + if (tab) + xt_heap_reference(self, tab); + *r_tab = tab; + + freer_(); // xt_ht_unlock(db->db_tables) + return r; +} + +/* The fixed part of the record is already in the row buffer. + * This function loads the extended part, expanding the row + * buffer if necessary. + */ +xtPublic xtBool xt_tab_load_ext_data(XTOpenTablePtr ot, xtRecordID load_rec_id, xtWord1 *buffer, u_int cols_req) +{ + size_t log_size; + xtLogID log_id; + xtLogOffset log_offset; + xtWord1 save_buffer[offsetof(XTactExtRecEntryDRec, er_data)]; + xtBool retried = FALSE; + XTactExtRecEntryDPtr ext_data_ptr; + size_t log_size2; + xtTableID curr_tab_id; + xtRecordID curr_rec_id; + + log_size = XT_GET_DISK_4(((XTTabRecExtDPtr) ot->ot_row_rbuffer)->re_log_dat_siz_4); + XT_GET_LOG_REF(log_id, log_offset, (XTTabRecExtDPtr) ot->ot_row_rbuffer); + + if (ot->ot_rec_size + log_size > ot->ot_row_rbuf_size) { + if (!xt_realloc_ns((void **) &ot->ot_row_rbuffer, ot->ot_rec_size + log_size)) + return FAILED; + ot->ot_row_rbuf_size = ot->ot_rec_size + log_size; + } + + /* Read the extended part first: */ + ext_data_ptr = (XTactExtRecEntryDPtr) (ot->ot_row_rbuffer + ot->ot_rec_size - offsetof(XTactExtRecEntryDRec, er_data)); + + /* Save the data which the header will overwrite: */ + memcpy(save_buffer, ext_data_ptr, offsetof(XTactExtRecEntryDRec, er_data)); + + reread: + if (!ot->ot_thread->st_dlog_buf.dlb_read_log(log_id, log_offset, offsetof(XTactExtRecEntryDRec, er_data) + log_size, (xtWord1 *) ext_data_ptr, ot->ot_thread)) + goto retry_read; + + log_size2 = XT_GET_DISK_4(ext_data_ptr->er_data_size_4); + curr_tab_id = XT_GET_DISK_4(ext_data_ptr->er_tab_id_4); + curr_rec_id = XT_GET_DISK_4(ext_data_ptr->er_rec_id_4); + + if (log_size2 != log_size || curr_tab_id != ot->ot_table->tab_id || curr_rec_id != load_rec_id) { + /* [(3)] This can happen in the following circumstances: + * - A new record is created, but the data log is not + * flushed. + * - The server quits. + * - On restart the transaction is rolled back, but the data record + * was not written, so later a new record could be written at this + * location. + * - Later the sweeper tries to cleanup this record, and finds + * that a different record has been written at this position. + * + * NOTE: Index entries can only be written to disk for records + * that have been committed to the disk, because uncommitted + * records may not exist in order to remove the index entry + * on cleanup. + */ + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_BAD_EXT_RECORD); + goto retry_read; + } + + /* Restore the saved area: */ + memcpy(ext_data_ptr, save_buffer, offsetof(XTactExtRecEntryDRec, er_data)); + + if (retried) + xt_unlock_mutex_ns(&ot->ot_table->tab_db->db_co_ext_lock); + return myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_EXT_HEADER_SIZE, buffer, cols_req); + + retry_read: + if (!retried) { + /* (1) It may be that reading the log fails because the garbage collector + * has moved the record since we determined the location. + * We handle this here, by re-reading the data the garbage collector + * would have updated. + * + * (2) It may also happen that a new record is just being updated or + * inserted. It is possible that the handle part of the record + * has been written, but not yet the overflow. + * This means that repeating the read attempt could work. + * + * (3) The extended data has been written by another handler and not yet + * flushed. This should not happen because on committed extended + * records are read, and all data should be flushed before + * commit! + * + * NOTE: (2) above is not a problem when versioning is working + * correctly. In this case, we should never try to read the extended + * part of an uncommitted record (belonging to some other thread/ + * transaction). + */ + XTTabRecExtDRec rec_buf; + + xt_lock_mutex_ns(&ot->ot_table->tab_db->db_co_ext_lock); + retried = TRUE; + + if (!xt_tab_get_rec_data(ot, load_rec_id, XT_REC_EXT_HEADER_SIZE, (xtWord1 *) &rec_buf)) + goto failed; + + XT_GET_LOG_REF(log_id, log_offset, &rec_buf); + goto reread; + } + + failed: + if (retried) + xt_unlock_mutex_ns(&ot->ot_table->tab_db->db_co_ext_lock); + return FAILED; +} + +xtPublic xtBool xt_tab_put_rec_data(XTOpenTablePtr ot, xtRecordID rec_id, size_t size, xtWord1 *buffer, xtOpSeqNo *op_seq) +{ + register XTTableHPtr tab = ot->ot_table; + + ASSERT_NS(rec_id); + + return tab->tab_recs.xt_tc_write(ot->ot_rec_file, rec_id, 0, size, buffer, op_seq, TRUE, ot->ot_thread); +} + +xtPublic xtBool xt_tab_put_log_op_rec_data(XTOpenTablePtr ot, u_int status, xtRecordID free_rec_id, xtRecordID rec_id, size_t size, xtWord1 *buffer) +{ + register XTTableHPtr tab = ot->ot_table; + xtOpSeqNo op_seq; + + ASSERT_NS(rec_id); + + if (status == XT_LOG_ENT_REC_MOVED) { + if (!tab->tab_recs.xt_tc_write(ot->ot_rec_file, rec_id, offsetof(XTTabRecExtDRec, re_log_id_2), size, buffer, &op_seq, TRUE, ot->ot_thread)) + return FAILED; + } +#ifdef DEBUG + else if (status == XT_LOG_ENT_REC_CLEANED_1) { + ASSERT_NS(0); // shouldn't be used anymore + } +#endif + else { + if (!tab->tab_recs.xt_tc_write(ot->ot_rec_file, rec_id, 0, size, buffer, &op_seq, TRUE, ot->ot_thread)) + return FAILED; + } + + return xt_xlog_modify_table(ot, status, op_seq, free_rec_id, rec_id, size, buffer); +} + +xtPublic xtBool xt_tab_put_log_rec_data(XTOpenTablePtr ot, u_int status, xtRecordID free_rec_id, xtRecordID rec_id, size_t size, xtWord1 *buffer, xtOpSeqNo *op_seq) +{ + register XTTableHPtr tab = ot->ot_table; + + ASSERT_NS(rec_id); + + if (status == XT_LOG_ENT_REC_MOVED) { + if (!tab->tab_recs.xt_tc_write(ot->ot_rec_file, rec_id, offsetof(XTTabRecExtDRec, re_log_id_2), size, buffer, op_seq, TRUE, ot->ot_thread)) + return FAILED; + } + else { + if (!tab->tab_recs.xt_tc_write(ot->ot_rec_file, rec_id, 0, size, buffer, op_seq, TRUE, ot->ot_thread)) + return FAILED; + } + + return xt_xlog_modify_table(ot, status, *op_seq, free_rec_id, rec_id, size, buffer); +} + +xtPublic xtBool xt_tab_get_rec_data(XTOpenTablePtr ot, xtRecordID rec_id, size_t size, xtWord1 *buffer) +{ + register XTTableHPtr tab = ot->ot_table; + + ASSERT_NS(rec_id); + + return tab->tab_recs.xt_tc_read(ot->ot_rec_file, rec_id, (size_t) size, buffer, ot->ot_thread); +} + +/* + * Note: this function grants locks even to transactions that + * are not specifically waiting for this transaction. + * This is required, because all threads waiting for + * a lock should be considered "equal". In other words, + * they should not have to wait for the "right" transaction + * before they get the lock, or it will turn into a + * race to wait for the correct transaction. + * + * A transaction T1 can end up waiting for the wrong transaction + * T2, because T2 has released the lock, and given it to T3. + * Of course, T1 will wake up soon and realize this, but + * it is a matter of timing. + * + * The main point is that T2 has release the lock because + * it has ended (see {RELEASING-LOCKS} for more details) + * and therefore, there is no danger of it claiming the + * lock again, which can lead to a deadlock if T1 is + * given the lock instead of T3 in the example above. + * Then, if T2 tries to regain the lock before T1 + * realizes that it has the lock. + */ +//static xtBool tab_get_lock_after_wait(XTThreadPtr thread, XTLockWaitPtr lw) +//{ +// register XTTableHPtr tab = lw->lw_ot->ot_table; + + /* {ROW-LIST-LOCK} + * I don't believe this lock is required. If it is, please explain why!! + * XT_TAB_ROW_READ_LOCK(&tab->tab_row_rwlock[gl->lw_row_id % XT_ROW_RWLOCKS], thread); + * + * With the old row lock implementation a XT_TAB_ROW_WRITE_LOCK was required because + * the row locking did not have its own locks. + * The new list locking has its own locks. I was using XT_TAB_ROW_READ_LOCK, + * but i don't think this is required. + */ +// return tab->tab_locks.xt_set_temp_lock(lw->lw_ot, lw, &lw->lw_thread->st_lock_list); +//} + +/* + * NOTE: Previously this function did not gain the row lock. + * If this change is a problem, please document why! + * The previously implementation did wait until no lock was on the + * row. + * + * I am thinking that it is simply a good idea to grab the lock, + * instead of waiting for no lock, before the retry. But it could + * result in locking more than required! + */ +static xtBool tab_wait_for_update(register XTOpenTablePtr ot, xtRowID row_id, xtXactID xn_id, XTThreadPtr thread) +{ + XTLockWaitRec lw; + XTXactWaitRec xw; + xtBool ok; + + xw.xw_xn_id = xn_id; + + lw.lw_thread = thread; + lw.lw_ot = ot; + lw.lw_row_id = row_id; + lw.lw_row_updated = FALSE; + + /* First try to get the lock: */ + if (!ot->ot_table->tab_locks.xt_set_temp_lock(ot, &lw, &thread->st_lock_list)) + return FAILED; + if (lw.lw_curr_lock != XT_NO_LOCK) + /* Wait for the lock, then the transaction: */ + ok = xt_xn_wait_for_xact(thread, &xw, &lw); + else + /* Just wait for the transaction: */ + ok = xt_xn_wait_for_xact(thread, &xw, NULL); + +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif + return ok; +} + +/* {WAIT-FOR} + * XT_OLD - The record is old. No longer visible because there is + * newer committed record before it in the record list. + * This is a special case of FALSE (the record is not visible). + * (see {WAIT-FOR} for details). + * It is significant because if we find too many of these when + * searching for records, then we have reason to believe the + * sweeper is far behind. This can happen in a test like this: + * runTest(INCREMENT_TEST, 2, INCREMENT_TEST_UPDATE_COUNT); + * What happens is T1 detects an updated row by T2, + * but T2 has not committed yet. + * It waits for T2. T2 commits and updates again before T1 + * can update. + * + * Of course if we got a lock on the row when T2 quits, then + * this would not happen! + */ + +/* + * Is a record visible? + * Returns TRUE, FALSE, XT_ERR. + * + * TRUE - The record is visible. + * FALSE - The record is not visible. + * XT_ERR - An exception (error) occurred. + * XT_NEW - The most recent variation of this row has been returned + * and is to be used instead of the input! + * XT_REREAD - Re-read the record, and try again. + * + * Basically, a record is visible if it was committed on or before + * the transactions "visible time" (st_visible_time), and there + * are no other visible records before this record in the + * variation chain for the record. + * + * This holds in general, but you don't always get to see the + * visible record (as defined in this sence). + * + * On any kind of update (SELECT FOR UPDATE, UPDATE or DELETE), you + * get to see the most recent variation of the row! + * + * So on update, this function will wait if necessary for a recent + * update to be committed. + * + * So an update is a kind of "committed read" with a wait for + * uncommitted records. + * + * The result: + * - INSERTS may not seen by the update read, depending on when + * they occur. + * - Records may be returned in non-index order. + * - New records returned must be checked again by an index scan + * to make sure they conform to the condition! + * + * CREATE TABLE test_tab (ID int primary key, Value int, Name varchar(20), + * index(Value, Name)) ENGINE=pbxt; + * INSERT test_tab values(4, 2, 'D'); + * INSERT test_tab values(5, 2, 'E'); + * INSERT test_tab values(6, 2, 'F'); + * INSERT test_tab values(7, 2, 'G'); + * + * -- C1 + * begin; + * select * from test_tab where id = 6 for update; + * -- C2 + * begin; + * select * from test_tab where value = 2 order by value, name for update; + * -- C1 + * update test_tab set Name = 'A' where id = 7; + * commit; + * -- C2 + * Result order D, E, F, A. + * + * But Jim does it like this, so it should be OK. + */ +static int tab_visible(register XTOpenTablePtr ot, XTTabRecHeadDPtr rec_head, xtRecordID *new_rec_id) +{ + XTThreadPtr thread = ot->ot_thread; + xtXactID xn_id; + XTTabRecHeadDRec var_head; + xtRowID row_id; + xtRecordID var_rec_id; + register XTTableHPtr tab; + xtBool wait = FALSE; + xtXactID wait_xn_id = 0; +#ifdef TRACE_VARIATIONS + char t_buf[500]; + int len; +#endif + int result = TRUE; + xtBool rec_clean; + xtRecordID invalid_rec; + + retry: + /* It can be that between the time that I read the index, + * and the time that I try to access the + * record, that the record is removed by + * the sweeper! + */ + if (XT_REC_NOT_VALID(rec_head->tr_rec_type_1)) + return FALSE; + + row_id = XT_GET_DISK_4(rec_head->tr_row_id_4); + + /* This can happen if the row has been removed, and + * reused: + */ + if (ot->ot_curr_row_id && row_id != ot->ot_curr_row_id) + return FALSE; + +#ifdef TRACE_VARIATIONS + len = sprintf(t_buf, "row=%d rec=%d ", (int) row_id, (int) ot->ot_curr_rec_id); +#endif + if (!(rec_clean = XT_REC_IS_CLEAN(rec_head->tr_rec_type_1))) { + /* The record is not clean, which means it has not been swept. + * So we have to check if it is visible. + */ + xn_id = XT_GET_DISK_4(rec_head->tr_xact_id_4); + switch (xt_xn_status(ot, xn_id, ot->ot_curr_rec_id)) { + case XT_XN_VISIBLE: + break; + case XT_XN_NOT_VISIBLE: + if (ot->ot_for_update) { + /* It is visible, only if it is an insert, + * which means if has no previous variation. + * Note, if an insert is updated, the record + * should be overwritten (TODO - check this). + */ + var_rec_id = XT_GET_DISK_4(rec_head->tr_prev_rec_id_4); + if (!var_rec_id) + break; +#ifdef TRACE_VARIATIONS + if (len <= 450) + len += sprintf(t_buf+len, "OTHER COMMIT (OVERWRITTEN) T%d\n", (int) xn_id); + xt_ttracef(thread, "%s", t_buf); +#endif + } +#ifdef TRACE_VARIATIONS + else { + if (len <= 450) + len += sprintf(t_buf+len, "OTHER COMMIT T%d\n", (int) xn_id); + xt_ttracef(thread, "%s", t_buf); + } +#endif + /* {WAKE-SW} + * The record is not visible, although it has been committed. + * Clean the transaction ASAP. + */ + ot->ot_table->tab_db->db_sw_faster |= XT_SW_DIRTY_RECORD_FOUND; + return FALSE; + case XT_XN_ABORTED: + /* {WAKE-SW} + * Reading an aborted record, this transaction + * must be cleaned up ASAP! + */ + ot->ot_table->tab_db->db_sw_faster |= XT_SW_DIRTY_RECORD_FOUND; +#ifdef TRACE_VARIATIONS + if (len <= 450) + len += sprintf(t_buf+len, "ABORTED T%d\n", (int) xn_id); + xt_ttracef(thread, "%s", t_buf); +#endif + return FALSE; + case XT_XN_MY_UPDATE: + /* This is a record written by this transaction. */ + if (thread->st_is_update) { + /* Check that it was not written by the current update statement: */ + if (XT_STAT_ID_MASK(thread->st_update_id) == rec_head->tr_stat_id_1) { +#ifdef TRACE_VARIATIONS + if (len <= 450) + len += sprintf(t_buf+len, "MY UPDATE IN THIS STATEMENT T%d\n", (int) xn_id); + xt_ttracef(thread, "%s", t_buf); +#endif + return FALSE; + } + } + ot->ot_curr_row_id = row_id; + ot->ot_curr_updated = TRUE; + if (!(xt_tab_get_row(ot, row_id, &var_rec_id))) + return XT_ERR; + /* It is visible if it is at the front of the list. + * An update can end up not being at the front of the list + * if it is deleted afterwards! + */ +#ifdef TRACE_VARIATIONS + if (len <= 450) { + if (var_rec_id == ot->ot_curr_rec_id) + len += sprintf(t_buf+len, "MY UPDATE T%d\n", (int) xn_id); + else + len += sprintf(t_buf+len, "MY UPDATE (OVERWRITTEN) T%d\n", (int) xn_id); + } + xt_ttracef(thread, "%s", t_buf); +#endif + return var_rec_id == ot->ot_curr_rec_id; + case XT_XN_OTHER_UPDATE: + if (ot->ot_for_update) { + /* If this is an insert, we are interested! + * Updated values are handled below. This is because + * the changed (new) records returned below are always + * followed (in the version chain) by the record + * we would have returned (if nothing had changed). + * + * As a result, we only return records here which have + * no "history". + */ + var_rec_id = XT_GET_DISK_4(rec_head->tr_prev_rec_id_4); + if (!var_rec_id) { +#ifdef TRACE_VARIATIONS + if (len <= 450) + len += sprintf(t_buf+len, "OTHER INSERT (WAIT FOR) T%d\n", (int) xn_id); + xt_ttracef(thread, "%s", t_buf); +#endif + if (!tab_wait_for_update(ot, row_id, xn_id, thread)) + return XT_ERR; + if (!xt_tab_get_rec_data(ot, ot->ot_curr_rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) &var_head)) + return XT_ERR; + rec_head = &var_head; + goto retry; + } + } +#ifdef TRACE_VARIATIONS + if (len <= 450) + len += sprintf(t_buf+len, "OTHER UPDATE T%d\n", (int) xn_id); + xt_ttracef(thread, "%s", t_buf); +#endif + return FALSE; + case XT_XN_REREAD: +#ifdef TRACE_VARIATIONS + if (len <= 450) + len += sprintf(t_buf+len, "REREAD?! T%d\n", (int) xn_id); + xt_ttracef(thread, "%s", t_buf); +#endif + return XT_REREAD; + } + } + + /* Follow the variation chain until we come to this record. + * If it is not the first visible variation then + * it is not visible at all. If it in not found on the + * variation chain, it is also not visible. + */ + tab = ot->ot_table; + + retry_2: + +#ifdef XT_USE_LIST_BASED_ROW_LOCKS + /* The list based row locks used there own locks, so + * it is not necessary to get a write lock here. + */ + XT_TAB_ROW_READ_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], thread); +#else + if (ot->ot_for_update) + XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], thread); + else + XT_TAB_ROW_READ_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], thread); +#endif + + invalid_rec = 0; + retry_3: + if (!(xt_tab_get_row(ot, row_id, &var_rec_id))) + goto failed; +#ifdef TRACE_VARIATIONS + len += sprintf(t_buf+len, "ROW=%d", (int) row_id); +#endif + while (var_rec_id != ot->ot_curr_rec_id) { + if (!var_rec_id) { +#ifdef TRACE_VARIATIONS + xt_ttracef(thread, "row=%d rec=%d NOT VISI not found in list\n", (int) row_id, (int) ot->ot_curr_rec_id); +#endif + goto not_found; + } + if (!xt_tab_get_rec_data(ot, var_rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) &var_head)) + goto failed; +#ifdef TRACE_VARIATIONS + if (len <= 450) + len += sprintf(t_buf+len, " -> %d(%d)", (int) var_rec_id, (int) var_head.tr_rec_type_1); +#endif + /* All clean records are visible, by all transactions: */ + if (XT_REC_IS_CLEAN(var_head.tr_rec_type_1)) { +#ifdef TRACE_VARIATIONS + xt_ttracef(thread, "row=%d rec=%d NOT VISI clean rec found\n", (int) row_id, (int) ot->ot_curr_rec_id); +#endif + goto not_found; + } + if (XT_REC_IS_FREE(var_head.tr_rec_type_1)) { +#ifdef TRACE_VARIATIONS + xt_ttracef(thread, "row=%d rec=%d NOT VISI free rec found?!\n", (int) row_id, (int) ot->ot_curr_rec_id); +#endif + /* + * After an analysis we came to conclusion that this situation is + * possible and valid. It can happen if index scan and row deletion + * go in parallel: + * + * Client Thread Sweeper + * ------------- ------- + * 1. start index scan, lock the index file. + * 2. start row deletion, wait for index lock + * 3. unlock the index file, start search for + * the valid version of the record + * 4. delete the row, mark record as freed, + * but not yet cleaned by sweeper + * 5. observe the record being freed + * + * after these steps we can get here, if the record was marked as free after + * the tab_visible was entered by the scanning thread. + * + */ + if (invalid_rec != var_rec_id) { + /* This was "var_rec_id = invalid_rec", caused an infinite loop (bug #310184!) */ + invalid_rec = var_rec_id; + goto retry_3; + } + /* Assume end of list. */ + goto not_found; + } + + /* This can happen if the row has been removed, and + * reused: + */ + if (row_id != XT_GET_DISK_4(var_head.tr_row_id_4)) + goto not_found; + + xn_id = XT_GET_DISK_4(var_head.tr_xact_id_4); + /* This variation is visibleif committed before this + * transaction started, or updated by this transaction. + * + * We now know that this is the valid variation for + * this record (for this table) for this transaction! + * This will not change, unless the transaction + * updates the record (again). + * + * So we can store this information as a hint, if + * we see other variations belonging to this record, + * then we can ignore them immediately! + */ + switch (xt_xn_status(ot, xn_id, var_rec_id)) { + case XT_XN_VISIBLE: + /* {WAKE-SW} + * We have encountered a record that has been overwritten, if the + * record has not been cleaned, then the sweeper is too far + * behind! + */ + if (!rec_clean) + ot->ot_table->tab_db->db_sw_faster |= XT_SW_DIRTY_RECORD_FOUND; +#ifdef TRACE_VARIATIONS + xt_ttracef(thread, "row=%d rec=%d NOT VISI committed rec found\n", (int) row_id, (int) ot->ot_curr_rec_id); +#endif + goto not_found; + case XT_XN_NOT_VISIBLE: + if (ot->ot_for_update) { + /* Substitute this record for the one we + * are reading!! + */ + if (result == TRUE) { + if (XT_REC_IS_DELETE(var_head.tr_rec_type_1)) + result = FALSE; + else { + *new_rec_id = var_rec_id; + result = XT_NEW; + } + } + } + break; + case XT_XN_ABORTED: + /* Ignore the record, it will be removed. */ + break; + case XT_XN_MY_UPDATE: +#ifdef TRACE_VARIATIONS + xt_ttracef(thread, "row=%d rec=%d NOT VISI my update found\n", (int) row_id, (int) ot->ot_curr_rec_id); +#endif + goto not_found; + case XT_XN_OTHER_UPDATE: + /* Wait for this update to commit or abort: */ + if (!wait) { + wait = TRUE; + wait_xn_id = xn_id; + } +#ifdef TRACE_VARIATIONS + if (len <= 450) + len += sprintf(t_buf+len, "-T%d", (int) wait_xn_id); +#endif + break; + case XT_XN_REREAD: + if (invalid_rec != var_rec_id) { + invalid_rec = var_rec_id; + goto retry_3; + } + /* Assume end of list. */ +#ifdef XT_CRASH_DEBUG + /* Should not happen! */ + xt_crash_me(); +#endif + goto not_found; + } + var_rec_id = XT_GET_DISK_4(var_head.tr_prev_rec_id_4); + } +#ifdef TRACE_VARIATIONS + if (len <= 450) + sprintf(t_buf+len, " -> %d(%d)\n", (int) var_rec_id, (int) rec_head->tr_rec_type_1); + else + sprintf(t_buf+len, " ...\n"); + //xt_ttracef(thread, "%s", t_buf); +#endif + + if (ot->ot_for_update) { + xtBool ok; + XTLockWaitRec lw; + + if (wait) { + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], thread); +#ifdef TRACE_VARIATIONS + xt_ttracef(thread, "T%d WAIT FOR T%d (will retry)\n", (int) thread->st_xact_data->xd_start_xn_id, (int) wait_xn_id); +#endif + if (!tab_wait_for_update(ot, row_id, wait_xn_id, thread)) + return XT_ERR; + wait = FALSE; + wait_xn_id = 0; + /* + * Retry in order to try to avoid missing + * any records that we should see in FOR UPDATE + * mode. + * + * We also want to take another look at the record + * we just tried to read. + * + * If it has been updated, then a new record has + * been created. This will be detected when we + * try to read it again, and XT_NEW will be returned. + */ + thread->st_statistics.st_retry_index_scan++; + return XT_RETRY; + } + + /* {ROW-LIST-LOCK} */ + lw.lw_thread = thread; + lw.lw_ot = ot; + lw.lw_row_id = row_id; + lw.lw_row_updated = FALSE; + ok = tab->tab_locks.xt_set_temp_lock(ot, &lw, &thread->st_lock_list); + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], thread); + if (!ok) { +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif + return XT_ERR; + } + if (lw.lw_curr_lock != XT_NO_LOCK) { +#ifdef TRACE_VARIATIONS + xt_ttracef(thread, "T%d WAIT FOR LOCK(%D) T%d\n", (int) thread->st_xact_data->xd_start_xn_id, (int) lock_type, (int) xn_id); +#endif + if (!xt_xn_wait_for_xact(thread, NULL, &lw)) { +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif + return XT_ERR; + } +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif +#ifdef TRACE_VARIATIONS + len = sprintf(t_buf, "(retry): row=%d rec=%d ", (int) row_id, (int) ot->ot_curr_rec_id); +#endif + /* GOTCHA! + * Reset the result before we go down the list again, to make sure we + * get the latest record!! + */ + result = TRUE; + thread->st_statistics.st_reread_record_list++; + goto retry_2; + } +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif + } + else { + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], thread); + } + +#ifdef TRACE_VARIATIONS + if (result == XT_NEW) + xt_ttracef(thread, "row=%d rec=%d RETURN NEW %d\n", (int) row_id, (int) ot->ot_curr_rec_id, (int) *new_rec_id); + else if (result) + xt_ttracef(thread, "row=%d rec=%d VISIBLE\n", (int) row_id, (int) ot->ot_curr_rec_id); + else + xt_ttracef(thread, "row=%d rec=%d RETURN NOT VISIBLE (NEW)\n", (int) row_id, (int) ot->ot_curr_rec_id); +#endif + + ot->ot_curr_row_id = row_id; + ot->ot_curr_updated = FALSE; + return result; + + not_found: + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], thread); + return FALSE; + + failed: + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], thread); + return XT_ERR; +} + +/* + * Return TRUE if the record has been read, and is visible. + * Return FALSE if the record is not visible. + * Return XT_ERR if an error occurs. + */ +xtPublic int xt_tab_visible(XTOpenTablePtr ot) +{ + xtRowID row_id; + XTTabRecHeadDRec rec_head; + xtRecordID new_rec_id; + xtBool read_again = FALSE; + int r; + + if ((row_id = ot->ot_curr_row_id)) { + /* Fast track, do a quick check. + * Row ID is only set if this record has been committed, + * (and swept). + * Check if it is the first on the list! + */ + xtRecordID var_rec_id; + + retry: + if (!(xt_tab_get_row(ot, row_id, &var_rec_id))) + return XT_ERR; + if (ot->ot_curr_rec_id == var_rec_id) { + /* Looks good.. */ + if (ot->ot_for_update) { + XTThreadPtr thread = ot->ot_thread; + XTTableHPtr tab = ot->ot_table; + XTLockWaitRec lw; + + /* {ROW-LIST-LOCK} */ + lw.lw_thread = thread; + lw.lw_ot = ot; + lw.lw_row_id = row_id; + lw.lw_row_updated = FALSE; + if (!tab->tab_locks.xt_set_temp_lock(ot, &lw, &thread->st_lock_list)) { +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif + return XT_ERR; + } + if (lw.lw_curr_lock != XT_NO_LOCK) { + if (!xt_xn_wait_for_xact(thread, NULL, &lw)) { +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif + return XT_ERR; + } +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif + goto retry; + } +#ifdef DEBUG_LOCK_QUEUE + ot->ot_table->tab_locks.rl_check(&lw); +#endif + } + return TRUE; + } + } + + reread: + if (!xt_tab_get_rec_data(ot, ot->ot_curr_rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) &rec_head)) + return XT_ERR; + + switch ((r = tab_visible(ot, &rec_head, &new_rec_id))) { + case XT_NEW: + ot->ot_curr_rec_id = new_rec_id; + break; + case XT_REREAD: + /* Avoid infinite loop: */ + if (read_again) { + /* Should not happen! */ +#ifdef XT_CRASH_DEBUG + /* Generate a core dump! */ + xt_crash_me(); +#endif + return FALSE; + } + read_again = TRUE; + goto reread; + default: + break; + } + return r; +} + +/* + * Read a record, and return one of the following: + * TRUE - the record has been read, and is visible. + * FALSE - the record is not visible. + * XT_ERR - an error occurs. + * XT_NEW - Means the expected record has been changed. + * When doing an index scan, the conditions must be checked again! + */ +xtPublic int xt_tab_read_record(register XTOpenTablePtr ot, xtWord1 *buffer) +{ + register XTTableHPtr tab = ot->ot_table; + size_t rec_size = tab->tab_dic.dic_rec_size; + xtRecordID new_rec_id; + int result; + xtBool read_again = FALSE; + + if (!(ot->ot_thread->st_xact_data)) { + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_NO_TRANSACTION); + return XT_ERR; + } + + reread: + if (!xt_tab_get_rec_data(ot, ot->ot_curr_rec_id, rec_size, ot->ot_row_rbuffer)) + return XT_ERR; + + switch (tab_visible(ot, (XTTabRecHeadDPtr) ot->ot_row_rbuffer, &new_rec_id)) { + case FALSE: + return FALSE; + case XT_ERR: + return XT_ERR; + case XT_NEW: + if (!xt_tab_get_rec_data(ot, new_rec_id, rec_size, ot->ot_row_rbuffer)) + return XT_ERR; + ot->ot_curr_rec_id = new_rec_id; + result = XT_NEW; + break; + case XT_RETRY: + return XT_RETRY; + case XT_REREAD: + /* Avoid infinite loop: */ + if (read_again) { + /* Should not happen! */ +#ifdef XT_CRASH_DEBUG + /* Generate a core dump! */ + xt_crash_me(); +#endif + return FALSE; + } + read_again = TRUE; + goto reread; + default: + result = OK; + break; + } + + if (ot->ot_rec_fixed) + memcpy(buffer, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, rec_size - XT_REC_FIX_HEADER_SIZE); + else if (ot->ot_row_rbuffer[0] == XT_TAB_STATUS_VARIABLE || ot->ot_row_rbuffer[0] == XT_TAB_STATUS_VAR_CLEAN) { + if (!myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, buffer, ot->ot_cols_req)) + return XT_ERR; + } + else { + u_int cols_req = ot->ot_cols_req; + + ASSERT_NS(cols_req); + if (cols_req && cols_req <= tab->tab_dic.dic_fix_col_count) { + if (!myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_EXT_HEADER_SIZE, buffer, cols_req)) + return XT_ERR; + } + else { + if (!xt_tab_load_ext_data(ot, ot->ot_curr_rec_id, buffer, cols_req)) + return XT_ERR; + } + } + + return result; +} + +/* + * Returns: + * + * TRUE/OK - record was read. + * FALSE/FAILED - An error occurred. + */ +xtPublic int xt_tab_dirty_read_record(register XTOpenTablePtr ot, xtWord1 *buffer) +{ + register XTTableHPtr tab = ot->ot_table; + size_t rec_size = tab->tab_dic.dic_rec_size; + + if (!xt_tab_get_rec_data(ot, ot->ot_curr_rec_id, rec_size, ot->ot_row_rbuffer)) + return FAILED; + + if (XT_REC_NOT_VALID(ot->ot_row_rbuffer[0])) { + /* Should not happen! */ + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_RECORD_DELETED); + return FAILED; + } + + ot->ot_curr_row_id = XT_GET_DISK_4(((XTTabRecHeadDPtr) ot->ot_row_rbuffer)->tr_row_id_4); + ot->ot_curr_updated = + (XT_GET_DISK_4(((XTTabRecHeadDPtr) ot->ot_row_rbuffer)->tr_xact_id_4) == ot->ot_thread->st_xact_data->xd_start_xn_id); + + if (ot->ot_rec_fixed) + memcpy(buffer, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, rec_size - XT_REC_FIX_HEADER_SIZE); + else if (ot->ot_row_rbuffer[0] == XT_TAB_STATUS_VARIABLE || ot->ot_row_rbuffer[0] == XT_TAB_STATUS_VAR_CLEAN) { + if (!myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, buffer, ot->ot_cols_req)) + return FAILED; + } + else { + u_int cols_req = ot->ot_cols_req; + + ASSERT_NS(cols_req); + if (cols_req && cols_req <= tab->tab_dic.dic_fix_col_count) { + if (!myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_EXT_HEADER_SIZE, buffer, cols_req)) + return FAILED; + } + else { + if (!xt_tab_load_ext_data(ot, ot->ot_curr_rec_id, buffer, cols_req)) + return FAILED; + } + } + + return OK; +} + +/* + * Pull the entire row pointer file into memory. + */ +xtPublic void xt_tab_load_row_pointers(XTThreadPtr self, XTOpenTablePtr ot) +{ + XTTableHPtr tab = ot->ot_table; + xtRecordID eof_rec_id = tab->tab_row_eof_id; + xtInt8 usage; + xtWord1 *buffer = NULL; + + /* Check if there is enough cache: */ + usage = xt_tc_get_usage(); + if (xt_tc_get_high() > usage) + usage = xt_tc_get_high(); + if (usage + ((xtInt8) eof_rec_id * (xtInt8) tab->tab_rows.tci_rec_size) < xt_tc_get_size()) { + xtRecordID rec_id; + size_t poffset, tfer; + off_t offset, end_offset; + XTTabCachePagePtr page; + + end_offset = xt_row_id_to_row_offset(tab, eof_rec_id); + rec_id = 1; + while (rec_id < eof_rec_id) { + if (!tab->tab_rows.xt_tc_get_page(ot->ot_row_file, rec_id, &page, &poffset, self)) + xt_throw(self); + if (page) + tab->tab_rows.xt_tc_release_page(ot->ot_row_file, page, self); + else { + xtWord1 *buff_ptr; + + if (!buffer) + buffer = (xtWord1 *) xt_malloc(self, tab->tab_rows.tci_page_size); + offset = xt_row_id_to_row_offset(tab, rec_id); + tfer = tab->tab_rows.tci_page_size; + if (offset + (off_t) tfer > end_offset) + tfer = (size_t) (end_offset - offset); + XT_LOCK_MEMORY_PTR(buff_ptr, ot->ot_row_file, offset, tfer, &self->st_statistics.st_rec, self); + if (buff_ptr) { + memcpy(buffer, buff_ptr, tfer); + XT_UNLOCK_MEMORY_PTR(ot->ot_row_file, self); + } + } + rec_id += tab->tab_rows.tci_rows_per_page; + } + if (buffer) + xt_free(self, buffer); + } +} + +xtPublic void xt_tab_load_table(XTThreadPtr self, XTOpenTablePtr ot) +{ + xt_load_pages(self, ot); + xt_load_indices(self, ot); +} + +xtPublic xtBool xt_tab_load_record(register XTOpenTablePtr ot, xtRecordID rec_id, XTInfoBufferPtr rec_buf) +{ + register XTTableHPtr tab = ot->ot_table; + size_t rec_size = tab->tab_dic.dic_rec_size; + + if (!xt_tab_get_rec_data(ot, rec_id, rec_size, ot->ot_row_rbuffer)) + return FAILED; + + if (XT_REC_NOT_VALID(ot->ot_row_rbuffer[0])) { + /* Should not happen! */ + XTThreadPtr self = ot->ot_thread; + + xt_log(XT_WARNING, "Recently updated record invalid\n"); + return OK; + } + + ot->ot_curr_row_id = XT_GET_DISK_4(((XTTabRecHeadDPtr) ot->ot_row_rbuffer)->tr_row_id_4); + ot->ot_curr_updated = + (XT_GET_DISK_4(((XTTabRecHeadDPtr) ot->ot_row_rbuffer)->tr_xact_id_4) == ot->ot_thread->st_xact_data->xd_start_xn_id); + + if (ot->ot_rec_fixed) { + size_t size = rec_size - XT_REC_FIX_HEADER_SIZE; + if (!xt_ib_alloc(NULL, rec_buf, size)) + return FAILED; + memcpy(rec_buf->ib_db.db_data, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, size); + } + else { + if (!xt_ib_alloc(NULL, rec_buf, tab->tab_dic.dic_mysql_buf_size)) + return FAILED; + if (ot->ot_row_rbuffer[0] == XT_TAB_STATUS_VARIABLE || ot->ot_row_rbuffer[0] == XT_TAB_STATUS_VAR_CLEAN) { + if (!myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, rec_buf->ib_db.db_data, ot->ot_cols_req)) + return FAILED; + } + else { + u_int cols_req = ot->ot_cols_req; + + ASSERT_NS(cols_req); + if (cols_req && cols_req <= tab->tab_dic.dic_fix_col_count) { + if (!myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_EXT_HEADER_SIZE, rec_buf->ib_db.db_data, cols_req)) + return FAILED; + } + else { + if (!xt_tab_load_ext_data(ot, ot->ot_curr_rec_id, rec_buf->ib_db.db_data, cols_req)) + return FAILED; + } + } + } + + return OK; +} + +xtPublic xtBool xt_tab_free_row(XTOpenTablePtr ot, XTTableHPtr tab, xtRowID row_id) +{ + XTTabRowRefDRec free_row; + xtRowID prev_row; + xtOpSeqNo op_seq; + + ASSERT_NS(row_id); // Cannot free the header! + + xt_lock_mutex_ns(&tab->tab_row_lock); + prev_row = tab->tab_row_free_id; + XT_SET_DISK_4(free_row.rr_ref_id_4, prev_row); + if (!tab->tab_rows.xt_tc_write(ot->ot_row_file, row_id, 0, sizeof(XTTabRowRefDRec), (xtWord1 *) &free_row, &op_seq, TRUE, ot->ot_thread)) { + xt_unlock_mutex_ns(&tab->tab_row_lock); + return FAILED; + } + tab->tab_row_free_id = row_id; + tab->tab_row_fnum++; + xt_unlock_mutex_ns(&tab->tab_row_lock); + + if (!xt_xlog_modify_table(ot, XT_LOG_ENT_ROW_FREED, op_seq, 0, row_id, sizeof(XTTabRowRefDRec), (xtWord1 *) &free_row)) + return FAILED; + + return OK; +} + +static void tab_free_ext_record_on_fail(XTOpenTablePtr ot, xtRecordID rec_id, XTTabRecExtDPtr ext_rec, xtBool log_err) +{ + xtWord4 log_over_size = XT_GET_DISK_4(ext_rec->re_log_dat_siz_4); + xtLogID log_id; + xtLogOffset log_offset; + + XT_GET_LOG_REF(log_id, log_offset, ext_rec); + + if (!ot->ot_thread->st_dlog_buf.dlb_delete_log(log_id, log_offset, log_over_size, ot->ot_table->tab_id, rec_id, ot->ot_thread)) { + if (log_err) + xt_log_and_clear_exception_ns(); + } +} + +static void tab_save_exception(XTExceptionPtr e) +{ + XTThreadPtr self = xt_get_self(); + + *e = self->t_exception; +} + +static void tab_restore_exception(XTExceptionPtr e) +{ + XTThreadPtr self = xt_get_self(); + + self->t_exception = *e; +} + +/* + * This function assumes that a record may be partially written. + * It removes all associated data and references to the record. + * + * This function return XT_ERR if an error occurs. + * TRUE if the record has been removed, and may be freed. + * FALSE if the record has already been freed. + * + */ +xtPublic int xt_tab_remove_record(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1 *rec_data, xtRecordID *prev_var_id, xtBool clean_delete, xtRowID row_id, xtXactID xn_id __attribute__((unused))) +{ + register XTTableHPtr tab = ot->ot_table; + size_t rec_size; + xtWord1 old_rec_type; + u_int cols_req; + u_int cols_in_buffer; + + *prev_var_id = 0; + + if (!rec_id) + return FALSE; + + /* + * NOTE: This function uses the read buffer. This should be OK because + * the function is only called by the sweeper. The read buffer + * is REQUIRED because of the call to xt_tab_load_ext_data()!!! + */ + rec_size = tab->tab_dic.dic_rec_size; + if (!xt_tab_get_rec_data(ot, rec_id, rec_size, ot->ot_row_rbuffer)) + return XT_ERR; + old_rec_type = ot->ot_row_rbuffer[0]; + + /* Check of the record has not already been freed: */ + if (XT_REC_IS_FREE(old_rec_type)) + return FALSE; + + /* This record must belong to the given row: */ + if (XT_GET_DISK_4(((XTTabRecExtDPtr) ot->ot_row_rbuffer)->tr_row_id_4) != row_id) + return FALSE; + + /* The transaction ID of the record must be BEFORE or equal to the given + * transaction ID. + * + * No, this does not always hold. Because we wait for updates now, + * a "younger" transaction can update before an older + * transaction. + * Commit order determined the actual order in which the transactions + * should be replicated. This is determined by the log number of + * the commit record! + if (db->db_xn_curr_id(xn_id, XT_GET_DISK_4(((XTTabRecExtDPtr) ot->ot_row_rbuffer)->tr_xact_id_4))) + return FALSE; + */ + + *prev_var_id = XT_GET_DISK_4(((XTTabRecExtDPtr) ot->ot_row_rbuffer)->tr_prev_rec_id_4); + + if (tab->tab_dic.dic_key_count) { + XTIndexPtr *ind; + + switch (old_rec_type) { + case XT_TAB_STATUS_DELETE: + case XT_TAB_STATUS_DEL_CLEAN: + rec_size = sizeof(XTTabRecHeadDRec); + goto set_removed; + case XT_TAB_STATUS_FIXED: + case XT_TAB_STATUS_FIX_CLEAN: + /* We know that for a fixed length record, + * dic_ind_rec_len <= dic_rec_size! */ + rec_size = (size_t) tab->tab_dic.dic_ind_rec_len + XT_REC_FIX_HEADER_SIZE; + rec_data = ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE; + break; + case XT_TAB_STATUS_VARIABLE: + case XT_TAB_STATUS_VAR_CLEAN: + cols_req = tab->tab_dic.dic_ind_cols_req; + + cols_in_buffer = cols_req; + rec_size = myxt_load_row_length(ot, rec_size - XT_REC_FIX_HEADER_SIZE, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, &cols_in_buffer); + if (cols_in_buffer < cols_req) + rec_size = tab->tab_dic.dic_rec_size; + else + rec_size += XT_REC_FIX_HEADER_SIZE; + if (!myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, rec_data, cols_req)) { + xt_log_and_clear_exception_ns(); + goto set_removed; + } + break; + case XT_TAB_STATUS_EXT_DLOG: + case XT_TAB_STATUS_EXT_CLEAN: + cols_req = tab->tab_dic.dic_ind_cols_req; + + ASSERT_NS(cols_req); + cols_in_buffer = cols_req; + rec_size = myxt_load_row_length(ot, rec_size - XT_REC_EXT_HEADER_SIZE, ot->ot_row_rbuffer + XT_REC_EXT_HEADER_SIZE, &cols_in_buffer); + if (cols_in_buffer < cols_req) { + rec_size = tab->tab_dic.dic_rec_size; + if (!xt_tab_load_ext_data(ot, rec_id, rec_data, cols_req)) { + /* This is actually quite possible after recovery, see [(3)] */ + if (ot->ot_thread->t_exception.e_xt_err != XT_ERR_BAD_EXT_RECORD && + ot->ot_thread->t_exception.e_xt_err != XT_ERR_DATA_LOG_NOT_FOUND) + xt_log_and_clear_exception_ns(); + goto set_removed; + } + } + else { + /* All the records we require are in the buffer... */ + rec_size += XT_REC_EXT_HEADER_SIZE; + if (!myxt_load_row(ot, ot->ot_row_rbuffer + XT_REC_EXT_HEADER_SIZE, rec_data, cols_req)) { + xt_log_and_clear_exception_ns(); + goto set_removed; + } + } + break; + default: + break; + } + + /* Could this be the case?: This change may only be flushed after the + * operation below has been flushed to the log. + * + * No, remove records are never "undone". The sweeper will delete + * the record again if it does not land in the log. + * + * The fact that the index entries have already been removed is not + * a problem. + */ + if (!tab->tab_dic.dic_disable_index) { + ind = tab->tab_dic.dic_keys; + for (u_int i=0; i<tab->tab_dic.dic_key_count; i++, ind++) { + if (!xt_idx_delete(ot, *ind, rec_id, rec_data)) + xt_log_and_clear_exception_ns(); + } + } + } + else { + /* No indices: */ + switch (old_rec_type) { + case XT_TAB_STATUS_DELETE: + case XT_TAB_STATUS_DEL_CLEAN: + rec_size = XT_REC_FIX_HEADER_SIZE; + break; + case XT_TAB_STATUS_FIXED: + case XT_TAB_STATUS_FIX_CLEAN: + case XT_TAB_STATUS_VARIABLE: + case XT_TAB_STATUS_VAR_CLEAN: + rec_size = XT_REC_FIX_HEADER_SIZE; + break; + case XT_TAB_STATUS_EXT_DLOG: + case XT_TAB_STATUS_EXT_CLEAN: + rec_size = XT_REC_EXT_HEADER_SIZE; + break; + } + } + +#ifdef XT_STREAMING + if (tab->tab_dic.dic_blob_count) { + /* If the record contains any LONGBLOB then check how much + * space we need. + */ + size_t blob_size; + + switch (old_rec_type) { + case XT_TAB_STATUS_DELETE: + case XT_TAB_STATUS_DEL_CLEAN: + break; + case XT_TAB_STATUS_FIXED: + case XT_TAB_STATUS_FIX_CLEAN: + /* Should not be the case, record with LONGBLOB can never be fixed! */ + break; + case XT_TAB_STATUS_VARIABLE: + case XT_TAB_STATUS_VAR_CLEAN: + cols_req = tab->tab_dic.dic_blob_cols_req; + cols_in_buffer = cols_req; + blob_size = myxt_load_row_length(ot, rec_size - XT_REC_FIX_HEADER_SIZE, ot->ot_row_rbuffer + XT_REC_FIX_HEADER_SIZE, &cols_in_buffer); + if (cols_in_buffer < cols_req) + blob_size = tab->tab_dic.dic_rec_size; + else + blob_size += XT_REC_FIX_HEADER_SIZE; + if (blob_size > rec_size) + rec_size = blob_size; + break; + case XT_TAB_STATUS_EXT_DLOG: + case XT_TAB_STATUS_EXT_CLEAN: + cols_req = tab->tab_dic.dic_blob_cols_req; + cols_in_buffer = cols_req; + blob_size = myxt_load_row_length(ot, rec_size - XT_REC_EXT_HEADER_SIZE, ot->ot_row_rbuffer + XT_REC_EXT_HEADER_SIZE, &cols_in_buffer); + if (cols_in_buffer < cols_req) + blob_size = tab->tab_dic.dic_rec_size; + else + blob_size += XT_REC_EXT_HEADER_SIZE; + if (blob_size > rec_size) + rec_size = blob_size; + break; + } + } +#endif + + set_removed: + if (XT_REC_IS_EXT_DLOG(old_rec_type)) { + /* {LOCK-EXT-REC} Lock, and read again to make sure that the + * compactor does not change this record, while + * we are removing it! */ + xt_lock_mutex_ns(&tab->tab_db->db_co_ext_lock); + if (!xt_tab_get_rec_data(ot, rec_id, XT_REC_EXT_HEADER_SIZE, ot->ot_row_rbuffer)) { + xt_unlock_mutex_ns(&tab->tab_db->db_co_ext_lock); + return FAILED; + } + xt_unlock_mutex_ns(&tab->tab_db->db_co_ext_lock); + + } + + xtOpSeqNo op_seq; + XTTabRecFreeDPtr free_rec = (XTTabRecFreeDPtr) ot->ot_row_rbuffer; + xtRecordID prev_rec_id; + + /* A record is "clean" deleted if the record was + * XT_TAB_STATUS_DELETE which was comitted. + * This makes sure that the record will still invalidate + * following records in a row. + * + * Example: + * + * 1. INSERT A ROW, then DELETE it, assume the sweeper is delayed. + * + * We now have the sequence row X --> del rec A --> valid rec B. + * + * 2. A SELECT can still find B. Assume it now goes to check + * if the record is valid, it reads row X, and gets A. + * + * 3. Now the sweeper gets control and removes X, A and B. + * It frees A with the clean bit. + * + * 4. Now the SELECT gets control and reads A. Normally a freed record + * would be ignored, and it would go onto B, which would then + * be considered valid (note, even after the free, the next + * pointer is not affected). + * + * However, because the clean bit has been set, it will stop at A + * and consider B invalid (which is the desired result). + * + * NOTE: We assume it is not possible for A to be allocated and refer + * to B, because B is freed before A. This means that B may refer to + * A after the next allocation. + */ + + xtWord1 new_rec_type = XT_TAB_STATUS_FREED | (clean_delete ? XT_TAB_STATUS_CLEANED_BIT : 0); + + xt_lock_mutex_ns(&tab->tab_rec_lock); + free_rec->rf_rec_type_1 = new_rec_type; + prev_rec_id = tab->tab_rec_free_id; + XT_SET_DISK_4(free_rec->rf_next_rec_id_4, prev_rec_id); + if (!xt_tab_put_rec_data(ot, rec_id, sizeof(XTTabRecFreeDRec), ot->ot_row_rbuffer, &op_seq)) { + xt_unlock_mutex_ns(&tab->tab_rec_lock); + return FAILED; + } + tab->tab_rec_free_id = rec_id; + ASSERT_NS(tab->tab_rec_free_id < tab->tab_rec_eof_id); + tab->tab_rec_fnum++; + xt_unlock_mutex_ns(&tab->tab_rec_lock); + + free_rec->rf_rec_type_1 = old_rec_type; + return xt_xlog_modify_table(ot, XT_LOG_ENT_REC_REMOVED_BI, op_seq, (xtRecordID) new_rec_type, rec_id, rec_size, ot->ot_row_rbuffer); +} + +static xtRowID tab_new_row(XTOpenTablePtr ot, XTTableHPtr tab) +{ + xtRowID row_id; + xtOpSeqNo op_seq; + xtRowID next_row_id = 0; + u_int status; + + xt_lock_mutex_ns(&tab->tab_row_lock); + if ((row_id = tab->tab_row_free_id)) { + status = XT_LOG_ENT_ROW_NEW_FL; + + if (!tab->tab_rows.xt_tc_read_4(ot->ot_row_file, row_id, &next_row_id, ot->ot_thread)) { + xt_unlock_mutex_ns(&tab->tab_row_lock); + return 0; + } + tab->tab_row_free_id = next_row_id; + tab->tab_row_fnum--; + } + else { + status = XT_LOG_ENT_ROW_NEW; + row_id = tab->tab_row_eof_id; + if (row_id == 0xFFFFFFFF) { + xt_unlock_mutex_ns(&tab->tab_row_lock); + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_MAX_ROW_COUNT); + return 0; + } + if (((row_id - 1) % tab->tab_rows.tci_rows_per_page) == 0) { + /* By fetching the page now, we avoid reading it later... */ + XTTabCachePagePtr page; + XTTabCacheSegPtr seg; + size_t poffset; + + if (!tab->tab_rows.tc_fetch(ot->ot_row_file, row_id, &seg, &page, &poffset, FALSE, ot->ot_thread)) { + xt_unlock_mutex_ns(&tab->tab_row_lock); + return 0; + } + xt_rwmutex_unlock(&seg->tcs_lock, ot->ot_thread->t_id); + } + tab->tab_row_eof_id++; + } + op_seq = tab->tab_seq.ts_get_op_seq(); + xt_unlock_mutex_ns(&tab->tab_row_lock); + + if (!xt_xlog_modify_table(ot, status, op_seq, next_row_id, row_id, 0, NULL)) + return 0; + + XT_DISABLED_TRACE(("new row tx=%d row=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_xn_id, (int) row_id)); + ASSERT_NS(row_id); + return row_id; +} + +xtPublic xtBool xt_tab_get_row(register XTOpenTablePtr ot, xtRowID row_id, xtRecordID *var_rec_id) +{ + register XTTableHPtr tab = ot->ot_table; + + (void) ASSERT_NS(sizeof(XTTabRowRefDRec) == 4); + + if (!tab->tab_rows.xt_tc_read_4(ot->ot_row_file, row_id, var_rec_id, ot->ot_thread)) + return FAILED; + return OK; +} + +xtPublic xtBool xt_tab_set_row(XTOpenTablePtr ot, u_int status, xtRowID row_id, xtRecordID var_rec_id) +{ + register XTTableHPtr tab = ot->ot_table; + XTTabRowRefDRec row_buf; + xtOpSeqNo op_seq; + + ASSERT_NS(var_rec_id < tab->tab_rec_eof_id); + XT_SET_DISK_4(row_buf.rr_ref_id_4, var_rec_id); + + if (!tab->tab_rows.xt_tc_write(ot->ot_row_file, row_id, 0, sizeof(XTTabRowRefDRec), (xtWord1 *) &row_buf, &op_seq, TRUE, ot->ot_thread)) + return FAILED; + + return xt_xlog_modify_table(ot, status, op_seq, 0, row_id, sizeof(XTTabRowRefDRec), (xtWord1 *) &row_buf); +} + +xtPublic xtBool xt_tab_free_record(XTOpenTablePtr ot, u_int status, xtRecordID rec_id, xtBool clean_delete) +{ + register XTTableHPtr tab = ot->ot_table; + XTTabRecHeadDRec rec_head; + XTactFreeRecEntryDRec free_rec; + xtRecordID prev_rec_id; + + /* Don't free the record if it is already free! */ + if (!xt_tab_get_rec_data(ot, rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) &rec_head)) + return FAILED; + + if (!XT_REC_IS_FREE(rec_head.tr_rec_type_1)) { + xtOpSeqNo op_seq; + + /* This information will be used to determine if the resources of the record + * should be removed. + */ + free_rec.fr_stat_id_1 = rec_head.tr_stat_id_1; + XT_COPY_DISK_4(free_rec.fr_xact_id_4, rec_head.tr_xact_id_4); + + /* A record is "clean" deleted if the record was + * XT_TAB_STATUS_DELETE which was comitted. + * This makes sure that the record will still invalidate + * following records in a row. + * + * Example: + * + * 1. INSERT A ROW, then DELETE it, assume the sweeper is delayed. + * + * We now have the sequence row X --> del rec A --> valid rec B. + * + * 2. A SELECT can still find B. Assume it now goes to check + * if the record is valid, ti reads row X, and gets A. + * + * 3. Now the sweeper gets control and removes X, A and B. + * It frees A with the clean bit. + * + * 4. Now the SELECT gets control and reads A. Normally a freed record + * would be ignored, and it would go onto B, which would then + * be considered valid (note, even after the free, the next + * pointer is not affected). + * + * However, because the clean bit has been set, it will stop at A + * and consider B invalid (which is the desired result). + * + * NOTE: We assume it is not possible for A to be allocated and refer + * to B, because B is freed before A. This means that B may refer to + * A after the next allocation. + */ + + (void) ASSERT_NS(sizeof(XTTabRecFreeDRec) == sizeof(XTactFreeRecEntryDRec) - offsetof(XTactFreeRecEntryDRec, fr_rec_type_1)); + free_rec.fr_rec_type_1 = XT_TAB_STATUS_FREED | (clean_delete ? XT_TAB_STATUS_CLEANED_BIT : 0); + free_rec.fr_not_used_1 = 0; + + xt_lock_mutex_ns(&tab->tab_rec_lock); + prev_rec_id = tab->tab_rec_free_id; + XT_SET_DISK_4(free_rec.fr_next_rec_id_4, prev_rec_id); + if (!xt_tab_put_rec_data(ot, rec_id, sizeof(XTTabRecFreeDRec), &free_rec.fr_rec_type_1, &op_seq)) { + xt_unlock_mutex_ns(&tab->tab_rec_lock); + return FAILED; + } + tab->tab_rec_free_id = rec_id; + ASSERT_NS(tab->tab_rec_free_id < tab->tab_rec_eof_id); + tab->tab_rec_fnum++; + xt_unlock_mutex_ns(&tab->tab_rec_lock); + + if (!xt_xlog_modify_table(ot, status, op_seq, rec_id, rec_id, sizeof(XTactFreeRecEntryDRec) - offsetof(XTactFreeRecEntryDRec, fr_stat_id_1), &free_rec.fr_stat_id_1)) + return FAILED; + } + return OK; +} + +static void tab_free_row_on_fail(XTOpenTablePtr ot, XTTableHPtr tab, xtRowID row_id) +{ + XTExceptionRec e; + + tab_save_exception(&e); + xt_tab_free_row(ot, tab, row_id); + tab_restore_exception(&e); +} + +static xtBool tab_add_record(XTOpenTablePtr ot, XTTabRecInfoPtr rec_info, u_int status) +{ + register XTTableHPtr tab = ot->ot_table; + XTThreadPtr thread = ot->ot_thread; + xtRecordID rec_id; + xtLogID log_id; + xtLogOffset log_offset; + xtOpSeqNo op_seq; + xtRecordID next_rec_id = 0; + + if (rec_info->ri_ext_rec) { + /* Determine where the overflow will go... */ + if (!thread->st_dlog_buf.dlb_get_log_offset(&log_id, &log_offset, rec_info->ri_log_data_size + offsetof(XTactExtRecEntryDRec, er_data), ot->ot_thread)) + return FAILED; + XT_SET_LOG_REF(rec_info->ri_ext_rec, log_id, log_offset); + } + + /* Write the record to disk: */ + xt_lock_mutex_ns(&tab->tab_rec_lock); + if ((rec_id = tab->tab_rec_free_id)) { + XTTabRecFreeDRec free_block; + + ASSERT_NS(rec_id < tab->tab_rec_eof_id); + if (!xt_tab_get_rec_data(ot, rec_id, sizeof(XTTabRecFreeDRec), (xtWord1 *) &free_block)) { + xt_unlock_mutex_ns(&tab->tab_rec_lock); + return FAILED; + } + next_rec_id = XT_GET_DISK_4(free_block.rf_next_rec_id_4); + tab->tab_rec_free_id = next_rec_id; + + tab->tab_rec_fnum--; + + /* XT_LOG_ENT_UPDATE --> XT_LOG_ENT_UPDATE_FL */ + /* XT_LOG_ENT_INSERT --> XT_LOG_ENT_INSERT_FL */ + /* XT_LOG_ENT_DELETE --> XT_LOG_ENT_DELETE_FL */ + status += 2; + + if (!xt_tab_put_rec_data(ot, rec_id, rec_info->ri_rec_buf_size, (xtWord1 *) rec_info->ri_fix_rec_buf, &op_seq)) { + xt_unlock_mutex_ns(&tab->tab_rec_lock); + return FAILED; + } + } + else { + xtBool read; + + rec_id = tab->tab_rec_eof_id; + tab->tab_rec_eof_id++; + + /* If we are writing to a new page (at the EOF) + * then we do not need to read the page from the + * file because it is new. + * + * Note that this only works because we are holding + * a lock on the record file. + */ + read = ((rec_id - 1) % tab->tab_recs.tci_rows_per_page) != 0; + + if (!tab->tab_recs.xt_tc_write(ot->ot_rec_file, rec_id, 0, rec_info->ri_rec_buf_size, (xtWord1 *) rec_info->ri_fix_rec_buf, &op_seq, read, ot->ot_thread)) { + xt_unlock_mutex_ns(&tab->tab_rec_lock); + return FAILED; + } + } + xt_unlock_mutex_ns(&tab->tab_rec_lock); + + if (!xt_xlog_modify_table(ot, status, op_seq, next_rec_id, rec_id, rec_info->ri_rec_buf_size, (xtWord1 *) rec_info->ri_fix_rec_buf)) + return FAILED; + + if (rec_info->ri_ext_rec) { + /* Write the log buffer overflow: */ + rec_info->ri_log_buf->er_status_1 = XT_LOG_ENT_EXT_REC_OK; + XT_SET_DISK_4(rec_info->ri_log_buf->er_data_size_4, rec_info->ri_log_data_size); + XT_SET_DISK_4(rec_info->ri_log_buf->er_tab_id_4, tab->tab_id); + XT_SET_DISK_4(rec_info->ri_log_buf->er_rec_id_4, rec_id); + if (!thread->st_dlog_buf.dlb_append_log(log_id, log_offset, offsetof(XTactExtRecEntryDRec, er_data) + rec_info->ri_log_data_size, (xtWord1 *) rec_info->ri_log_buf, ot->ot_thread)) { + /* Failed to write the overflow, free the record allocated above: */ + return FAILED; + } + } + + XT_DISABLED_TRACE(("new rec tx=%d val=%d\n", (int) thread->st_xact_data->xd_start_xn_id, (int) rec_id)); + rec_info->ri_rec_id = rec_id; + return OK; +} + +static void tab_delete_record_on_fail(XTOpenTablePtr ot, xtRowID row_id, xtRecordID rec_id, XTTabRecHeadDPtr row_ptr, xtWord1 *rec_data, u_int key_count) +{ + XTExceptionRec e; + xtBool log_err = TRUE; + XTTabRecInfoRec rec_info; + + tab_save_exception(&e); + + if (e.e_xt_err == XT_ERR_DUPLICATE_KEY || + e.e_xt_err == XT_ERR_DUPLICATE_FKEY) { + /* If the error does not cause rollback, then we will ignore the + * error if an error occurs in the UNDO! + */ + log_err = FALSE; + tab_restore_exception(&e); + } + if (key_count) { + XTIndexPtr *ind; + + ind = ot->ot_table->tab_dic.dic_keys; + for (u_int i=0; i<key_count; i++, ind++) { + if (!xt_idx_delete(ot, *ind, rec_id, rec_data)) { + if (log_err) + xt_log_and_clear_exception_ns(); + } + } + } + + if (row_ptr->tr_rec_type_1 == XT_TAB_STATUS_EXT_DLOG || row_ptr->tr_rec_type_1 == XT_TAB_STATUS_EXT_CLEAN) + tab_free_ext_record_on_fail(ot, rec_id, (XTTabRecExtDPtr) row_ptr, log_err); + + rec_info.ri_fix_rec_buf = (XTTabRecFixDPtr) ot->ot_row_wbuffer; + rec_info.ri_rec_buf_size = offsetof(XTTabRecFixDRec, rf_data); + rec_info.ri_ext_rec = NULL; + rec_info.ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_DELETE; + rec_info.ri_fix_rec_buf->tr_stat_id_1 = 0; + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_row_id_4, row_id); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_prev_rec_id_4, rec_id); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_xact_id_4, ot->ot_thread->st_xact_data->xd_start_xn_id); + + if (!tab_add_record(ot, &rec_info, XT_LOG_ENT_DELETE)) + goto failed; + + if (!xt_tab_set_row(ot, XT_LOG_ENT_ROW_ADD_REC, row_id, rec_info.ri_rec_id)) + goto failed; + + if (log_err) + tab_restore_exception(&e); + return; + + failed: + if (log_err) + xt_log_and_clear_exception_ns(); + else + tab_restore_exception(&e); +} + +/* + * Wait until all the variations between the start of the chain, and + * the given record have been rolled-back. + * If any is committed, register a locked error, and return FAILED. + */ +static xtBool tab_wait_for_rollback(XTOpenTablePtr ot, xtRowID row_id, xtRecordID commit_rec_id) +{ + register XTTableHPtr tab = ot->ot_table; + xtRecordID var_rec_id; + XTTabRecHeadDRec var_head; + xtXactID xn_id; + xtRecordID invalid_rec = 0; + XTXactWaitRec xw; + + retry: + if (!xt_tab_get_row(ot, row_id, &var_rec_id)) + return FAILED; + + while (var_rec_id != commit_rec_id) { + if (!var_rec_id) + goto locked; + if (!xt_tab_get_rec_data(ot, var_rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) &var_head)) + return FAILED; + if (XT_REC_IS_CLEAN(var_head.tr_rec_type_1)) + goto locked; + if (XT_REC_IS_FREE(var_head.tr_rec_type_1)) + /* Should not happen: */ + goto record_invalid; + xn_id = XT_GET_DISK_4(var_head.tr_xact_id_4); + switch (xt_xn_status(ot, xn_id, var_rec_id)) { + case XT_XN_VISIBLE: + case XT_XN_NOT_VISIBLE: + goto locked; + case XT_XN_ABORTED: + /* Ingore the record, it will be removed. */ + break; + case XT_XN_MY_UPDATE: + /* Should not happen: */ + goto locked; + case XT_XN_OTHER_UPDATE: + /* Wait for the transaction to commit or rollback: */ + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + xw.xw_xn_id = xn_id; + if (!xt_xn_wait_for_xact(ot->ot_thread, &xw, NULL)) { + XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + return FAILED; + } + XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + goto retry; + case XT_XN_REREAD: + goto record_invalid; + } + var_rec_id = XT_GET_DISK_4(var_head.tr_prev_rec_id_4); + } + return OK; + + locked: + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_RECORD_CHANGED); + return FAILED; + + record_invalid: + /* Prevent an infinite loop due to a bad record: */ + if (invalid_rec != var_rec_id) { + var_rec_id = invalid_rec; + goto retry; + } + /* The record is invalid, it will be "overwritten"... */ +#ifdef XT_CRASH_DEBUG + /* Should not happen! */ + xt_crash_me(); +#endif + return OK; +} + +/* Check if a record may be visible: + * Return TRUE of the record may be visible now. + * Return XT_MAYBE if the record may be visible in the future (set out_xn_id). + * Return FALSE of the record is not valid (freed or is a delete record). + * Return XT_ERR if an error occurred. + */ +xtPublic int xt_tab_maybe_committed(XTOpenTablePtr ot, xtRecordID rec_id, xtXactID *out_xn_id, xtRowID *out_rowid, xtBool *out_updated) +{ + XTTabRecHeadDRec rec_head; + xtXactID rec_xn_id = 0; + xtBool wait = FALSE; + xtXactID wait_xn_id = 0; + xtRowID row_id; + xtRecordID var_rec_id; + xtXactID xn_id; + register XTTableHPtr tab; +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + char t_buf[500]; + int len; + char *t_type = "C"; +#endif + xtRecordID invalid_rec = 0; + + reread: + if (!xt_tab_get_rec_data(ot, rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) &rec_head)) + return XT_ERR; + + if (XT_REC_NOT_VALID(rec_head.tr_rec_type_1)) + return FALSE; + + if (!XT_REC_IS_CLEAN(rec_head.tr_rec_type_1)) { + rec_xn_id = XT_GET_DISK_4(rec_head.tr_xact_id_4); + switch (xt_xn_status(ot, rec_xn_id, rec_id)) { + case XT_XN_VISIBLE: +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + t_type="V"; +#endif + break; + case XT_XN_NOT_VISIBLE: +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + t_type="NV"; +#endif + break; + case XT_XN_ABORTED: + return FALSE; + case XT_XN_MY_UPDATE: +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + t_type="My-Upd"; +#endif + break; + case XT_XN_OTHER_UPDATE: +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + t_type="Wait"; +#endif + wait = TRUE; + wait_xn_id = rec_xn_id; + break; + case XT_XN_REREAD: +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + t_type="Re-read"; +#endif + /* Avoid infinite loop: */ + if (invalid_rec == rec_id) { + /* Should not happen! */ +#ifdef XT_CRASH_DEBUG + /* Generate a core dump! */ + xt_crash_me(); +#endif + return FALSE; + } + invalid_rec = rec_id; + goto reread; + } + } + + /* Follow the variation chain until we come to this record. + * If it is not the first visible variation then + * it is not visible at all. If it in not found on the + * variation chain, it is also not visible. + */ + row_id = XT_GET_DISK_4(rec_head.tr_row_id_4); + + tab = ot->ot_table; + XT_TAB_ROW_READ_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + + invalid_rec = 0; + retry: + if (!(xt_tab_get_row(ot, row_id, &var_rec_id))) + goto failed; +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + len = sprintf(t_buf, "dup row=%d", (int) row_id); +#endif + while (var_rec_id != rec_id) { + if (!var_rec_id) + goto not_found; +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + if (len <= 450) + len += sprintf(t_buf+len, " -> %d", (int) var_rec_id); +#endif + if (!xt_tab_get_rec_data(ot, var_rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) &rec_head)) + goto failed; + /* All clean records are visible, by all transactions: */ + if (XT_REC_IS_CLEAN(rec_head.tr_rec_type_1)) + goto not_found; + + if (XT_REC_IS_FREE(rec_head.tr_rec_type_1)) { + /* Should not happen: */ + if (invalid_rec != var_rec_id) { + var_rec_id = invalid_rec; + goto retry; + } + /* Assume end of list. */ +#ifdef XT_CRASH_DEBUG + /* Should not happen! */ + xt_crash_me(); +#endif + goto not_found; + } + + xn_id = XT_GET_DISK_4(rec_head.tr_xact_id_4); + switch (xt_xn_status(ot, xn_id, var_rec_id)) { + case XT_XN_VISIBLE: + case XT_XN_NOT_VISIBLE: + goto not_found; + case XT_XN_ABORTED: + /* Ingore the record, it will be removed. */ +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + if (len <= 450) + len += sprintf(t_buf+len, "(T%d-A)", (int) xn_id); +#endif + break; + case XT_XN_MY_UPDATE: + goto not_found; + case XT_XN_OTHER_UPDATE: +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + if (len <= 450) + len += sprintf(t_buf+len, "(T%d-wait)", (int) xn_id); +#endif + /* Wait for this update to commit or abort: */ + if (!wait) { + wait = TRUE; + wait_xn_id = xn_id; + } + break; + case XT_XN_REREAD: + if (invalid_rec != var_rec_id) { + var_rec_id = invalid_rec; + goto retry; + } + /* Assume end of list. */ +#ifdef XT_CRASH_DEBUG + /* Should not happen! */ + xt_crash_me(); +#endif + goto not_found; + } + var_rec_id = XT_GET_DISK_4(rec_head.tr_prev_rec_id_4); + } +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + if (len <= 450) + sprintf(t_buf+len, " -> %d(T%d-%s)\n", (int) var_rec_id, (int) rec_xn_id, t_type); + else + sprintf(t_buf+len, " ...(T%d-%s)\n", (int) rec_xn_id, t_type); +#endif + + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + if (wait) { + *out_xn_id = wait_xn_id; + return XT_MAYBE; + } +#ifdef TRACE_VARIATIONS_IN_DUP_CHECK + xt_ttracef(thread, "%s", t_buf); +#endif + if (out_rowid) { + *out_rowid = row_id; + *out_updated = (rec_xn_id == ot->ot_thread->st_xact_data->xd_start_xn_id); + } + return TRUE; + + not_found: + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + return FALSE; + + failed: + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + return XT_ERR; +} + +xtPublic xtBool xt_tab_new_record(XTOpenTablePtr ot, xtWord1 *rec_buf) +{ + register XTTableHPtr tab = ot->ot_table; + register XTThreadPtr self = ot->ot_thread; + XTTabRecInfoRec rec_info; + xtRowID row_id; + u_int idx_cnt = 0; + XTIndexPtr *ind; +#ifdef XT_STREAMING + void *pbms_table; + + /* PBMS: Reference BLOBs!? */ + if (tab->tab_dic.dic_blob_count) { + if (!myxt_use_blobs(ot, &pbms_table, rec_buf)) + return FAILED; + } +#endif + + if (!myxt_store_row(ot, &rec_info, (char *) rec_buf)) + goto failed_0; + + /* Get a new row ID: */ + if (!(row_id = tab_new_row(ot, tab))) + goto failed_0; + + rec_info.ri_fix_rec_buf->tr_stat_id_1 = self->st_update_id; + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_row_id_4, row_id); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_prev_rec_id_4, 0); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_xact_id_4, self->st_xact_data->xd_start_xn_id); + + /* Note, it is important that this record is written BEFORE the row + * due to the problem distributed here [(5)] + */ + if (!tab_add_record(ot, &rec_info, XT_LOG_ENT_INSERT)) + goto failed_1; + +#ifdef TRACE_VARIATIONS + xt_ttracef(self, "insert: row=%d rec=%d T%d\n", (int) row_id, (int) rec_info.ri_rec_id, (int) self->st_xact_data->xd_start_xn_id); +#endif + if (!xt_tab_set_row(ot, XT_LOG_ENT_ROW_ADD_REC, row_id, rec_info.ri_rec_id)) + goto failed_1; + XT_DISABLED_TRACE(("set new tx=%d row=%d rec=%d\n", (int) self->st_xact_data->xd_start_xn_id, (int) row_id, (int) rec_info.ri_rec_id)); + + /* Add the index references: */ + for (idx_cnt=0, ind=tab->tab_dic.dic_keys; idx_cnt<tab->tab_dic.dic_key_count; idx_cnt++, ind++) { + if (!xt_idx_insert(ot, *ind, 0, rec_info.ri_rec_id, rec_buf, NULL, FALSE)) { + ot->ot_err_index_no = (*ind)->mi_index_no; + goto failed_2; + } + } + +#ifdef XT_STREAMING + /* Reference the BLOBs in the row: */ + if (tab->tab_dic.dic_blob_count) { + if (!myxt_retain_blobs(ot, pbms_table, rec_info.ri_rec_id)) { + pbms_table = NULL; + goto failed_2; + } + pbms_table = NULL; + } +#endif + + /* Do the foreign key stuff: */ + if (ot->ot_table->tab_dic.dic_table->dt_fkeys.size() > 0) { + if (!ot->ot_table->tab_dic.dic_table->insertRow(ot, rec_buf)) + goto failed_2; + } + + self->st_statistics.st_row_insert++; + return OK; + + failed_2: + /* Once the row has been inserted, it is to late to remove it! + * Now all we can do is delete it! + */ + tab_delete_record_on_fail(ot, row_id, rec_info.ri_rec_id, (XTTabRecHeadDPtr) rec_info.ri_fix_rec_buf, rec_buf, idx_cnt); + goto failed_0; + + failed_1: + tab_free_row_on_fail(ot, tab, row_id); + + failed_0: +#ifdef XT_STREAMING + if (tab->tab_dic.dic_blob_count && pbms_table) + myxt_unuse_blobs(ot, pbms_table); +#endif + return FAILED; +} + +/* We cannot remove a change we have made to a row while a transaction + * is running, so we have to undo what we have done by + * overwriting the record we just created with + * the before image! + */ +static xtBool tab_overwrite_record_on_fail(XTOpenTablePtr ot, XTTabRecInfoPtr rec_info, xtWord1 *before_buf, xtWord1 *after_buf, u_int idx_cnt) +{ + register XTTableHPtr tab = ot->ot_table; + XTTabRecHeadDRec prev_rec_head; + u_int i; + XTIndexPtr *ind; + XTThreadPtr thread = ot->ot_thread; + xtLogID log_id; + xtLogOffset log_offset; + xtRecordID rec_id = rec_info->ri_rec_id; + + /* Remove the new extended record: */ + if (rec_info->ri_ext_rec) + tab_free_ext_record_on_fail(ot, rec_id, (XTTabRecExtDPtr) rec_info->ri_fix_rec_buf, TRUE); + + /* Undo index entries of the new record: */ + if (after_buf) { + for (i=0, ind=tab->tab_dic.dic_keys; i<idx_cnt; i++, ind++) { + if (!xt_idx_delete(ot, *ind, rec_id, after_buf)) + return FAILED; + } + } + + memcpy(&prev_rec_head, rec_info->ri_fix_rec_buf, sizeof(XTTabRecHeadDRec)); + + if (!before_buf) { + /* Can happen if the delete was called from some cascaded action. + * And this is better than a crash... + * + * TODO: to make sure the change will not be applied in case the + * transaction will be commited, we'd need to add a log entry to + * restore the record like it's done for top-level operation. In + * order to do this we'd need to read the before-image of the + * record before modifying it. + */ + if (!ot->ot_thread->t_exception.e_xt_err) + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_NO_BEFORE_IMAGE); + return FAILED; + } + + /* Restore the previous record! */ + if (!myxt_store_row(ot, rec_info, (char *) before_buf)) + return FAILED; + + memcpy(rec_info->ri_fix_rec_buf, &prev_rec_head, sizeof(XTTabRecHeadDRec)); + + if (rec_info->ri_ext_rec) { + /* Determine where the overflow will go... */ + if (!thread->st_dlog_buf.dlb_get_log_offset(&log_id, &log_offset, rec_info->ri_log_data_size + offsetof(XTactExtRecEntryDRec, er_data), ot->ot_thread)) + return FAILED; + XT_SET_LOG_REF(rec_info->ri_ext_rec, log_id, log_offset); + } + + if (!xt_tab_put_log_op_rec_data(ot, XT_LOG_ENT_REC_MODIFIED, 0, rec_id, rec_info->ri_rec_buf_size, (xtWord1 *) rec_info->ri_fix_rec_buf)) + return FAILED; + + if (rec_info->ri_ext_rec) { + /* Write the log buffer overflow: */ + rec_info->ri_log_buf->er_status_1 = XT_LOG_ENT_EXT_REC_OK; + XT_SET_DISK_4(rec_info->ri_log_buf->er_data_size_4, rec_info->ri_log_data_size); + XT_SET_DISK_4(rec_info->ri_log_buf->er_tab_id_4, tab->tab_id); + XT_SET_DISK_4(rec_info->ri_log_buf->er_rec_id_4, rec_id); + if (!thread->st_dlog_buf.dlb_append_log(log_id, log_offset, offsetof(XTactExtRecEntryDRec, er_data) + rec_info->ri_log_data_size, (xtWord1 *) rec_info->ri_log_buf, ot->ot_thread)) + return FAILED; + } + + /* Put the index entries back: */ + for (idx_cnt=0, ind=tab->tab_dic.dic_keys; idx_cnt<tab->tab_dic.dic_key_count; idx_cnt++, ind++) { + if (!xt_idx_insert(ot, *ind, 0, rec_id, before_buf, after_buf, TRUE)) + /* Incomplete restore, there will be a rollback... */ + return FAILED; + } + + return OK; +} + +/* + * GOTCHA: + * If a transaction updates the same record over again, we should update + * in place. This prevents producing unnecessary variations! + */ +static xtBool tab_overwrite_record(XTOpenTablePtr ot, xtWord1 *before_buf, xtWord1 *after_buf) +{ + register XTTableHPtr tab = ot->ot_table; + xtRowID row_id = ot->ot_curr_row_id; + register XTThreadPtr self = ot->ot_thread; + xtRecordID rec_id = ot->ot_curr_rec_id; + XTTabRecExtDRec prev_rec_head; + XTTabRecInfoRec rec_info; + u_int idx_cnt = 0, i; + XTIndexPtr *ind; + xtLogID log_id; + xtLogOffset log_offset; + xtBool prev_ext_rec; + +#ifdef XT_STREAMING + void *pbms_table; + + if (tab->tab_dic.dic_blob_count) { + if (!myxt_use_blobs(ot, &pbms_table, after_buf)) + return FAILED; + } +#endif + + if (!myxt_store_row(ot, &rec_info, (char *) after_buf)) + goto failed_0; + + /* Read before we overwrite! */ + if (!xt_tab_get_rec_data(ot, rec_id, XT_REC_EXT_HEADER_SIZE, (xtWord1 *) &prev_rec_head)) + goto failed_0; + + prev_ext_rec = prev_rec_head.tr_rec_type_1 & XT_TAB_STATUS_EXT_DLOG; + + if (rec_info.ri_ext_rec) { + /* Determine where the overflow will go... */ + if (!self->st_dlog_buf.dlb_get_log_offset(&log_id, &log_offset, offsetof(XTactExtRecEntryDRec, er_data) + rec_info.ri_log_data_size, ot->ot_thread)) + goto failed_0; + XT_SET_LOG_REF(rec_info.ri_ext_rec, log_id, log_offset); + } + + rec_info.ri_fix_rec_buf->tr_stat_id_1 = self->st_update_id; + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_row_id_4, row_id); + XT_COPY_DISK_4(rec_info.ri_fix_rec_buf->tr_prev_rec_id_4, prev_rec_head.tr_prev_rec_id_4); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_xact_id_4, self->st_xact_data->xd_start_xn_id); + + /* Remove the index references, that have changed: */ + for (idx_cnt=0, ind=tab->tab_dic.dic_keys; idx_cnt<tab->tab_dic.dic_key_count; idx_cnt++, ind++) { + if (!xt_idx_delete(ot, *ind, rec_id, before_buf)) { + goto failed_0; + } + } + +#ifdef TRACE_VARIATIONS + xt_ttracef(self, "overwrite: row=%d rec=%d T%d\n", (int) row_id, (int) rec_id, (int) self->st_xact_data->xd_start_xn_id); +#endif + /* Overwrite the record: */ + if (!xt_tab_put_log_op_rec_data(ot, XT_LOG_ENT_REC_MODIFIED, 0, rec_id, rec_info.ri_rec_buf_size, (xtWord1 *) rec_info.ri_fix_rec_buf)) + goto failed_0; + + if (rec_info.ri_ext_rec) { + /* Write the log buffer overflow: */ + rec_info.ri_log_buf->er_status_1 = XT_LOG_ENT_EXT_REC_OK; + XT_SET_DISK_4(rec_info.ri_log_buf->er_data_size_4, rec_info.ri_log_data_size); + XT_SET_DISK_4(rec_info.ri_log_buf->er_tab_id_4, tab->tab_id); + XT_SET_DISK_4(rec_info.ri_log_buf->er_rec_id_4, rec_id); + if (!self->st_dlog_buf.dlb_append_log(log_id, log_offset, offsetof(XTactExtRecEntryDRec, er_data) + rec_info.ri_log_data_size, (xtWord1 *) rec_info.ri_log_buf, ot->ot_thread)) + goto failed_1; + } + + /* Add the index references that have changed: */ + for (idx_cnt=0, ind=tab->tab_dic.dic_keys; idx_cnt<tab->tab_dic.dic_key_count; idx_cnt++, ind++) { + if (!xt_idx_insert(ot, *ind, 0, rec_id, after_buf, before_buf, FALSE)) { + ot->ot_err_index_no = (*ind)->mi_index_no; + goto failed_2; + } + } + + /* Do the foreign key stuff: */ + if (ot->ot_table->tab_dic.dic_table->dt_trefs || ot->ot_table->tab_dic.dic_table->dt_fkeys.size() > 0) { + if (!ot->ot_table->tab_dic.dic_table->updateRow(ot, before_buf, after_buf)) + goto failed_2; + } + + /* Delete the previous overflow area: */ + if (prev_ext_rec) + tab_free_ext_record_on_fail(ot, rec_id, &prev_rec_head, TRUE); + +#ifdef XT_STREAMING + if (tab->tab_dic.dic_blob_count) { + /* Retain the BLOBs new record: */ + if (!myxt_retain_blobs(ot, pbms_table, rec_id)) + return FAILED; + /* Release the BLOBs in the old record: */ + myxt_release_blobs(ot, before_buf, rec_id); + } +#endif + + return OK; + + failed_2: + /* Remove the new extended record: */ + if (rec_info.ri_ext_rec) + tab_free_ext_record_on_fail(ot, rec_id, (XTTabRecExtDPtr) rec_info.ri_fix_rec_buf, TRUE); + + /* Restore the previous record! */ + /* Undo index entries: */ + for (i=0, ind=tab->tab_dic.dic_keys; i<idx_cnt; i++, ind++) { + if (!xt_idx_delete(ot, *ind, rec_id, after_buf)) + goto failed_1; + } + + /* Restore the record: */ + if (!myxt_store_row(ot, &rec_info, (char *) before_buf)) + goto failed_1; + + if (rec_info.ri_ext_rec) + memcpy(rec_info.ri_fix_rec_buf, &prev_rec_head, XT_REC_EXT_HEADER_SIZE); + else + memcpy(rec_info.ri_fix_rec_buf, &prev_rec_head, sizeof(XTTabRecHeadDRec)); + + if (!xt_tab_put_log_op_rec_data(ot, XT_LOG_ENT_REC_MODIFIED, 0, rec_id, rec_info.ri_rec_buf_size, (xtWord1 *) rec_info.ri_fix_rec_buf)) + goto failed_1; + + /* Put the index entries back: */ + for (idx_cnt=0, ind=tab->tab_dic.dic_keys; idx_cnt<tab->tab_dic.dic_key_count; idx_cnt++, ind++) { + if (!xt_idx_insert(ot, *ind, 0, rec_id, before_buf, after_buf, TRUE)) + /* Incomplete restore, there will be a rollback... */ + goto failed_0; + } + + /* The previous record has now been restored. */ + goto failed_0; + + failed_1: + /* The old record is overwritten, I must free the previous extended record: */ + if (prev_ext_rec) + tab_free_ext_record_on_fail(ot, rec_id, &prev_rec_head, TRUE); + + failed_0: +#ifdef XT_STREAMING + /* Unuse the BLOBs of the new record: */ + if (tab->tab_dic.dic_blob_count && pbms_table) + myxt_unuse_blobs(ot, pbms_table); +#endif + return FAILED; +} + +xtPublic xtBool xt_tab_update_record(XTOpenTablePtr ot, xtWord1 *before_buf, xtWord1 *after_buf) +{ + register XTTableHPtr tab; + xtRowID row_id; + register XTThreadPtr self; + xtRecordID curr_var_rec_id; + XTTabRecInfoRec rec_info; + u_int idx_cnt = 0; + XTIndexPtr *ind; + +#ifdef XT_STREAMING + void *pbms_table; +#endif + + /* + * Originally only the flag ot->ot_curr_updated was checked, and if it was on, then + * tab_overwrite_record() was called, but this caused crashes in some cases like: + * + * set @@autocommit = 0; + * create table t1 (s1 int primary key); + * create table t2 (s1 int primary key, foreign key (s1) references t1 (s1) on update cascade); + * insert into t1 values (1); + * insert into t2 values (1); + * update t1 set s1 = 1; + * + * the last update lead to a crash on t2 cascade update because before_buf argument is NULL + * in the call below. It is NULL only during cascade update of child table. In that case we + * cannot pass before_buf value from XTDDTableRef::modifyRow as the before_buf is the original + * row for the parent (t1) table and it would be used to update any existing indexes + * in the child table which would be wrong of course. + * + * Alternative solution would be to copy the after_info in the XTDDTableRef::modifyRow(): + * + * ... + * if (!xt_tab_load_record(ot, ot->ot_curr_rec_id, &after_info)) + * goto failed_2; + * ... + * + * here the xt_tab_load_record() loads the original row, so we can copy it from there, but in + * that case we'd need to allocate a new (possibly up to 65536 bytes long) buffer, which makes + * the optimization questionable + * + */ + if (ot->ot_curr_updated && before_buf) + /* This record has already been updated by this transaction. + * Do the update in place! + */ + return tab_overwrite_record(ot, before_buf, after_buf); + + tab = ot->ot_table; + row_id = ot->ot_curr_row_id; + self = ot->ot_thread; + +#ifdef XT_STREAMING + /* PBMS: Reference BLOBs!? */ + if (tab->tab_dic.dic_blob_count) { + if (!myxt_use_blobs(ot, &pbms_table, after_buf)) + return FAILED; + } +#endif + + if (!myxt_store_row(ot, &rec_info, (char *) after_buf)) + goto failed_0; + + rec_info.ri_fix_rec_buf->tr_stat_id_1 = self->st_update_id; + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_row_id_4, row_id); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_prev_rec_id_4, ot->ot_curr_rec_id); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_xact_id_4, self->st_xact_data->xd_start_xn_id); + + /* Create the new record: */ + if (!tab_add_record(ot, &rec_info, XT_LOG_ENT_UPDATE)) + goto failed_0; + + /* Link the new variation into the list: */ + XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + + if (!xt_tab_get_row(ot, row_id, &curr_var_rec_id)) + goto failed_1; + + if (curr_var_rec_id != ot->ot_curr_rec_id) { + /* If the transaction does not rollback, I will get an + * exception here: + */ + if (!tab_wait_for_rollback(ot, row_id, ot->ot_curr_rec_id)) + goto failed_1; + /* [(4)] This is the situation when we overwrite the + * reference to curr_var_rec_id! + * When curr_var_rec_id is cleaned up by the sweeper, the + * sweeper will notice that the record is no longer in + * the row list. + */ + } + +#ifdef TRACE_VARIATIONS + xt_ttracef(self, "update: row=%d rec=%d T%d\n", (int) row_id, (int) rec_info.ri_rec_id, (int) self->st_xact_data->xd_start_xn_id); +#endif + if (!xt_tab_set_row(ot, XT_LOG_ENT_ROW_ADD_REC, row_id, rec_info.ri_rec_id)) + goto failed_1; + XT_DISABLED_TRACE(("set upd tx=%d row=%d rec=%d\n", (int) self->st_xact_data->xd_start_xn_id, (int) row_id, (int) rec_info.ri_rec_id)); + + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + + /* Add the index references: */ + for (idx_cnt=0, ind=tab->tab_dic.dic_keys; idx_cnt<tab->tab_dic.dic_key_count; idx_cnt++, ind++) { + if (!xt_idx_insert(ot, *ind, 0, rec_info.ri_rec_id, after_buf, before_buf, FALSE)) { + ot->ot_err_index_no = (*ind)->mi_index_no; + goto failed_2; + } + } + +#ifdef XT_STREAMING + /* Reference the BLOBs in the row: */ + if (tab->tab_dic.dic_blob_count) { + if (!myxt_retain_blobs(ot, pbms_table, rec_info.ri_rec_id)) { + pbms_table = NULL; + goto failed_2; + } + pbms_table = NULL; + } +#endif + + if (ot->ot_table->tab_dic.dic_table->dt_trefs || ot->ot_table->tab_dic.dic_table->dt_fkeys.size() > 0) { + if (!ot->ot_table->tab_dic.dic_table->updateRow(ot, before_buf, after_buf)) + goto failed_2; + } + + ot->ot_thread->st_statistics.st_row_update++; + return OK; + + failed_2: + tab_overwrite_record_on_fail(ot, &rec_info, before_buf, after_buf, idx_cnt); + goto failed_0; + + failed_1: + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + + failed_0: +#ifdef XT_STREAMING + if (tab->tab_dic.dic_blob_count && pbms_table) + myxt_unuse_blobs(ot, pbms_table); +#endif + return FAILED; +} + +xtPublic xtBool xt_tab_delete_record(XTOpenTablePtr ot, xtWord1 *rec_buf) +{ + register XTTableHPtr tab = ot->ot_table; + xtRowID row_id = ot->ot_curr_row_id; + xtRecordID curr_var_rec_id; + XTTabRecInfoRec rec_info; + + /* Setup a delete record: */ + rec_info.ri_fix_rec_buf = (XTTabRecFixDPtr) ot->ot_row_wbuffer; + rec_info.ri_rec_buf_size = offsetof(XTTabRecFixDRec, rf_data); + rec_info.ri_ext_rec = NULL; + rec_info.ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_DELETE; + rec_info.ri_fix_rec_buf->tr_stat_id_1 = 0; + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_row_id_4, row_id); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_prev_rec_id_4, ot->ot_curr_rec_id); + XT_SET_DISK_4(rec_info.ri_fix_rec_buf->tr_xact_id_4, ot->ot_thread->st_xact_data->xd_start_xn_id); + + if (!tab_add_record(ot, &rec_info, XT_LOG_ENT_DELETE)) + return FAILED; + + XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + + if (!xt_tab_get_row(ot, row_id, &curr_var_rec_id)) + goto failed_1; + + if (curr_var_rec_id != ot->ot_curr_rec_id) { + if (!tab_wait_for_rollback(ot, row_id, ot->ot_curr_rec_id)) + goto failed_1; + } + +#ifdef TRACE_VARIATIONS + xt_ttracef(ot->ot_thread, "update: row=%d rec=%d T%d\n", (int) row_id, (int) rec_info.ri_rec_id, (int) ot->ot_thread->st_xact_data->xd_start_xn_id); +#endif + if (!xt_tab_set_row(ot, XT_LOG_ENT_ROW_ADD_REC, row_id, rec_info.ri_rec_id)) + goto failed_1; + XT_DISABLED_TRACE(("del row tx=%d row=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_xn_id, (int) row_id, (int) rec_info.ri_rec_id)); + + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + + if (ot->ot_table->tab_dic.dic_table->dt_trefs) { + if (!ot->ot_table->tab_dic.dic_table->deleteRow(ot, rec_buf)) + goto failed_2; + } + + ot->ot_thread->st_statistics.st_row_delete++; + return OK; + + failed_2: + tab_overwrite_record_on_fail(ot, &rec_info, rec_buf, NULL, 0); + return FAILED; + + failed_1: + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], ot->ot_thread); + return FAILED; +} + +xtPublic xtBool xt_tab_restrict_rows(XTBasicListPtr list, XTThreadPtr thread) +{ + u_int i; + XTRestrictItemPtr item; + XTOpenTablePtr pot = NULL; + XTDatabaseHPtr db = thread->st_database; + xtBool ok = TRUE; + + for (i=0; i<list->bl_count; i++) { + item = (XTRestrictItemPtr) xt_bl_item_at(list, i); + if (item) + if (pot) { + if (pot->ot_table->tab_id == item->ri_tab_id) + goto check_action; + xt_db_return_table_to_pool_ns(pot); + pot = NULL; + } + + if (!xt_db_open_pool_table_ns(&pot, db, item->ri_tab_id)) { + /* Should not happen, but just in case, we just don't + * remove the lock. We will probably end up with a deadlock + * somewhere. + */ + xt_log_and_clear_exception_ns(); + goto skip_check_action; + } + if (!pot) + /* Can happen of the table has been dropped: */ + goto skip_check_action; + + check_action: + if (!pot->ot_table->tab_dic.dic_table->checkNoAction(pot, item->ri_rec_id)) { + ok = FALSE; + break; + } + skip_check_action:; + } + + if (pot) + xt_db_return_table_to_pool_ns(pot); + xt_bl_free(NULL, list); + return ok; +} + + +xtPublic xtBool xt_tab_seq_init(XTOpenTablePtr ot) +{ + register XTTableHPtr tab = ot->ot_table; + + ot->ot_seq_page = NULL; + ot->ot_on_page = FALSE; + ot->ot_seq_offset = 0; + + ot->ot_curr_rec_id = 0; // 0 is an invalid position! + ot->ot_curr_row_id = 0; // 0 is an invalid row ID! + ot->ot_curr_updated = FALSE; + + /* We note the current EOF before we start a sequential scan. + * It is basically possible to update the same record more than + * once because an updated record creates a new record which + * has a new position which may be in the area that is + * still to be scanned. + * + * By noting the EOF before we start a sequential scan we + * reduce the possibility of this. + * + * However, the possibility still remains, but it should + * not be a problem because a record is not modified + * if there is nothing to change, which is the case + * if the record has already been changed! + * + * NOTE (2008-01-29) There is no longer a problem with updating a + * record twice because records are marked by an update. + * + * [(10)] I have changed this (see below). I now check the + * current EOF of the table. + * + * The reason is that committed read must be able to see the + * changes that occur during table table scan. * + */ + ot->ot_seq_eof_id = tab->tab_rec_eof_id; + + if (!ot->ot_thread->st_xact_data) { + /* MySQL ignores this error, so we + * setup the sequential scan so that it will + * deliver nothing! + */ + ot->ot_seq_rec_id = ot->ot_seq_eof_id; + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_NO_TRANSACTION); + return FAILED; + } + + ot->ot_seq_rec_id = 1; + ot->ot_thread->st_statistics.st_scan_table++; + return OK; +} + +xtPublic void xt_tab_seq_reset(XTOpenTablePtr ot) +{ + ot->ot_seq_rec_id = 0; + ot->ot_seq_eof_id = 0; + ot->ot_seq_page = NULL; + ot->ot_on_page = FALSE; + ot->ot_seq_offset = 0; +} + +xtPublic void xt_tab_seq_exit(XTOpenTablePtr ot) +{ + register XTTableHPtr tab = ot->ot_table; + + if (ot->ot_seq_page) { + tab->tab_recs.xt_tc_release_page(ot->ot_rec_file, ot->ot_seq_page, ot->ot_thread); + ot->ot_seq_page = NULL; + } + ot->ot_on_page = FALSE; +} + +xtPublic xtBool xt_tab_seq_next(XTOpenTablePtr ot, xtWord1 *buffer, xtBool *eof) +{ + register XTTableHPtr tab = ot->ot_table; + register size_t rec_size = tab->tab_dic.dic_rec_size; + xtWord1 *buff_ptr; + xtRecordID new_rec_id; + xtBool ptr_locked; + xtRecordID invalid_rec = 0; + XTTabRecHeadDRec rec_head; + + next_page: + if (!ot->ot_on_page) { + if (!(ot->ot_on_page = tab->tab_recs.xt_tc_get_page(ot->ot_rec_file, ot->ot_seq_rec_id, &ot->ot_seq_page, &ot->ot_seq_offset, ot->ot_thread))) + return FAILED; + } + + next_record: + /* [(10)] The current EOF is used: */ + if (ot->ot_seq_rec_id >= ot->ot_seq_eof_id) { + *eof = TRUE; + return OK; + } + + if (ot->ot_seq_offset >= tab->tab_recs.tci_page_size) { + if (ot->ot_seq_page) { + tab->tab_recs.xt_tc_release_page(ot->ot_rec_file, ot->ot_seq_page, ot->ot_thread); + ot->ot_seq_page = NULL; + } + ot->ot_on_page = FALSE; + goto next_page; + } + + if (ot->ot_seq_page) { + ptr_locked = FALSE; + buff_ptr = ot->ot_seq_page->tcp_data + ot->ot_seq_offset; + } + else { + size_t red_size; + + ptr_locked = TRUE; + if (!xt_pread_fmap(ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, ot->ot_seq_rec_id), sizeof(XTTabRecHeadDRec), sizeof(XTTabRecHeadDRec), &rec_head, &red_size, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread)) + return FAILED; + buff_ptr = (xtWord1 *) &rec_head; + } + + /* This is the current record: */ + ot->ot_curr_rec_id = ot->ot_seq_rec_id; + ot->ot_curr_row_id = 0; + + /* Move to the next record: */ + ot->ot_seq_rec_id++; + ot->ot_seq_offset += rec_size; + + retry: + switch (tab_visible(ot, (XTTabRecHeadDPtr) buff_ptr, &new_rec_id)) { + case FALSE: + goto next_record; + case XT_ERR: + goto failed; + case XT_NEW: + ptr_locked = FALSE; + buff_ptr = ot->ot_row_rbuffer; + if (!xt_tab_get_rec_data(ot, new_rec_id, rec_size, ot->ot_row_rbuffer)) + return XT_ERR; + ot->ot_curr_rec_id = new_rec_id; + break; + case XT_RETRY: + goto retry; + case XT_REREAD: + if (invalid_rec != ot->ot_curr_rec_id) { + /* Don't re-read for the same record twice: */ + invalid_rec = ot->ot_curr_rec_id; + + /* Undo move to next: */ + ot->ot_seq_rec_id--; + ot->ot_seq_offset -= rec_size; + + /* Prepare to reread the page: */ + if (ot->ot_seq_page) { + tab->tab_recs.xt_tc_release_page(ot->ot_rec_file, ot->ot_seq_page, ot->ot_thread); + ot->ot_seq_page = NULL; + } + ot->ot_on_page = FALSE; + goto next_page; + } +#ifdef XT_CRASH_DEBUG + /* Should not happen! */ + xt_crash_me(); +#endif + /* Continue, and skip the record... */ + invalid_rec = 0; + goto next_record; + default: + if (ptr_locked) + XT_LOCK_MEMORY_PTR(buff_ptr, ot->ot_rec_file, xt_rec_id_to_rec_offset(tab, ot->ot_curr_rec_id), tab->tab_rows.tci_page_size, &ot->ot_thread->st_statistics.st_rec, ot->ot_thread); + break; + } + + switch (*buff_ptr) { + case XT_TAB_STATUS_FIXED: + case XT_TAB_STATUS_FIX_CLEAN: + memcpy(buffer, buff_ptr + XT_REC_FIX_HEADER_SIZE, rec_size - XT_REC_FIX_HEADER_SIZE); + break; + case XT_TAB_STATUS_VARIABLE: + case XT_TAB_STATUS_VAR_CLEAN: + if (!myxt_load_row(ot, buff_ptr + XT_REC_FIX_HEADER_SIZE, buffer, ot->ot_cols_req)) + goto failed_1; + break; + case XT_TAB_STATUS_EXT_DLOG: + case XT_TAB_STATUS_EXT_CLEAN: { + u_int cols_req = ot->ot_cols_req; + + ASSERT_NS(cols_req); + if (cols_req && cols_req <= tab->tab_dic.dic_fix_col_count) { + if (!myxt_load_row(ot, buff_ptr + XT_REC_EXT_HEADER_SIZE, buffer, cols_req)) + goto failed_1; + } + else { + if (buff_ptr != ot->ot_row_rbuffer) + memcpy(ot->ot_row_rbuffer, buff_ptr, rec_size); + if (!xt_tab_load_ext_data(ot, ot->ot_curr_rec_id, buffer, cols_req)) + goto failed_1; + } + break; + } + } + if (ptr_locked) + XT_UNLOCK_MEMORY_PTR(ot->ot_rec_file, ot->ot_thread); + + *eof = FALSE; + return OK; + + failed_1: + if (ptr_locked) + XT_UNLOCK_MEMORY_PTR(ot->ot_rec_file, ot->ot_thread); + + failed: + return FAILED; +} + diff --git a/storage/pbxt/src/table_xt.h b/storage/pbxt/src/table_xt.h new file mode 100644 index 00000000000..6ba3eadd2ae --- /dev/null +++ b/storage/pbxt/src/table_xt.h @@ -0,0 +1,607 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-02-08 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_table_h__ +#define __xt_table_h__ + +#include <time.h> + +#include "datalog_xt.h" +#include "filesys_xt.h" +#include "hashtab_xt.h" +#include "index_xt.h" +#include "cache_xt.h" +#include "util_xt.h" +#include "heap_xt.h" +#include "tabcache_xt.h" +#include "xactlog_xt.h" +#include "lock_xt.h" + +struct XTDatabase; +struct XTThread; +struct XTCache; +struct XTOpenTable; +struct XTTablePath; + +#define XT_TAB_INCOMPATIBLE_VERSION 4 +#define XT_TAB_CURRENT_VERSION 5 + +#define XT_IND_CURRENT_VERSION 3 + +#define XT_HEAD_BUFFER_SIZE 1024 + +#ifdef DEBUG +//#define XT_TRACK_INDEX_UPDATES +//#define XT_TRACK_RETURNED_ROWS +#endif + +/* + * NOTE: Records may only be freed (placed on the free list), after + * all currently running transactions have ended. + * The reason is, running transactions may have references in memory + * to these records (a sequential scan has a large buffer). + * If the records are freed they may be re-used. This will + * cause problems because the references will then refer to + * new data. + * + * As a result, deleted records are first placed in the + * REMOVED state. Later, when transactions have quit, they + * are freed. + */ +#define XT_TAB_STATUS_FREED 0x00 /* On the free list. */ +#define XT_TAB_STATUS_DELETE 0x01 /* A transactional delete record (an "update" that indicates a delete). */ +#define XT_TAB_STATUS_FIXED 0x02 +#define XT_TAB_STATUS_VARIABLE 0x03 /* Uses one block, but has the variable format. */ +#define XT_TAB_STATUS_EXT_DLOG 0x04 /* Variable format, and the trailing part of the record in the data log. */ +#define XT_TAB_STATUS_EXT_HDATA 0x05 /* Variable format, and the trailing part of the record in the handle data file. */ +#define XT_TAB_STATUS_DATA 0x06 /* A block of data with a next pointer (5 bytes overhead). */ +#define XT_TAB_STATUS_END_DATA 0x07 /* An block of data without an end pointer (1 byte overhead). */ +#define XT_TAB_STATUS_MASK 0x0F + +#define XT_TAB_STATUS_DEL_CLEAN (XT_TAB_STATUS_DELETE | XT_TAB_STATUS_CLEANED_BIT) +#define XT_TAB_STATUS_FIX_CLEAN (XT_TAB_STATUS_FIXED | XT_TAB_STATUS_CLEANED_BIT) +#define XT_TAB_STATUS_VAR_CLEAN (XT_TAB_STATUS_VARIABLE | XT_TAB_STATUS_CLEANED_BIT) +#define XT_TAB_STATUS_EXT_CLEAN (XT_TAB_STATUS_EXT_DLOG | XT_TAB_STATUS_CLEANED_BIT) + +#define XT_TAB_STATUS_CLEANED_BIT 0x80 /* This bit is set when the record is cleaned and committed. */ + +#define XT_REC_IS_CLEAN(x) ((x) & XT_TAB_STATUS_CLEANED_BIT) +#define XT_REC_IS_FREE(x) (((x) & XT_TAB_STATUS_MASK) == XT_TAB_STATUS_FREED) +#define XT_REC_IS_DELETE(x) (((x) & XT_TAB_STATUS_MASK) == XT_TAB_STATUS_DELETE) +#define XT_REC_IS_FIXED(x) (((x) & XT_TAB_STATUS_MASK) == XT_TAB_STATUS_FIXED) +#define XT_REC_IS_VARIABLE(x) (((x) & XT_TAB_STATUS_MASK) == XT_TAB_STATUS_VARIABLE) +#define XT_REC_IS_EXT_DLOG(x) (((x) & XT_TAB_STATUS_MASK) == XT_TAB_STATUS_EXT_DLOG) +#define XT_REC_IS_EXT_HDATA(x) (((x) & XT_TAB_STATUS_MASK) == XT_TAB_STATUS_EXT_HDATA) +#define XT_REC_NOT_VALID(x) (XT_REC_IS_FREE(x) || XT_REC_IS_DELETE(x)) + +/* Results for xt_use_table_by_id(): */ +#define XT_TAB_OK 0 +#define XT_TAB_NOT_FOUND 1 +#define XT_TAB_NO_DICTIONARY 2 +#define XT_TAB_POOL_CLOSED 3 /* Cannot open table at the moment, the pool is closed. */ +#define XT_TAB_FAILED 4 + +#define XT_TAB_ROW_USE_RW_MUTEX + +#ifdef XT_TAB_ROW_USE_FASTWRLOCK +#define XT_TAB_ROW_LOCK_TYPE XTFastRWLockRec +#define XT_TAB_ROW_INIT_LOCK(s, i) xt_fastrwlock_init(s, i) +#define XT_TAB_ROW_FREE_LOCK(s, i) xt_fastrwlock_free(s, i) +#define XT_TAB_ROW_READ_LOCK(i, s) xt_fastrwlock_slock(i, s) +#define XT_TAB_ROW_WRITE_LOCK(i, s) xt_fastrwlock_xlock(i, s) +#define XT_TAB_ROW_UNLOCK(i, s) xt_fastrwlock_unlock(i, s) +#elif defined(XT_TAB_ROW_USE_PTHREAD_RW) +#define XT_TAB_ROW_LOCK_TYPE xt_rwlock_type +#define XT_TAB_ROW_INIT_LOCK(s, i) xt_init_rwlock(s, i) +#define XT_TAB_ROW_FREE_LOCK(s, i) xt_free_rwlock(i) +#define XT_TAB_ROW_READ_LOCK(i, s) xt_slock_rwlock_ns(i) +#define XT_TAB_ROW_WRITE_LOCK(i, s) xt_xlock_rwlock_ns(i) +#define XT_TAB_ROW_UNLOCK(i, s) xt_unlock_rwlock_ns(i) +#elif defined(XT_TAB_ROW_USE_RW_MUTEX) +#define XT_TAB_ROW_LOCK_TYPE XTRWMutexRec +#define XT_TAB_ROW_INIT_LOCK(s, i) xt_rwmutex_init_with_autoname(s, i) +#define XT_TAB_ROW_FREE_LOCK(s, i) xt_rwmutex_free(s, i) +#define XT_TAB_ROW_READ_LOCK(i, s) xt_rwmutex_slock(i, (s)->t_id) +#define XT_TAB_ROW_WRITE_LOCK(i, s) xt_rwmutex_xlock(i, (s)->t_id) +#define XT_TAB_ROW_UNLOCK(i, s) xt_rwmutex_unlock(i, (s)->t_id) +#else +#define XT_TAB_ROW_LOCK_TYPE XTSpinLockRec +#define XT_TAB_ROW_INIT_LOCK(s, i) xt_spinlock_init(s, i) +#define XT_TAB_ROW_FREE_LOCK(s, i) xt_spinlock_free(s, i) +#define XT_TAB_ROW_READ_LOCK(i, s) xt_spinlock_lock(i) +#define XT_TAB_ROW_WRITE_LOCK(i, s) xt_spinlock_lock(i) +#define XT_TAB_ROW_UNLOCK(i, s) xt_spinlock_unlock(i) +#endif + +/* ------- TABLE DATA FILE ------- */ + +#define XT_TAB_DATA_MAGIC 0x1234ABCD + +#define XT_FORMAT_DEF_SPACE 512 + +#define XT_TAB_FLAGS_TEMP_TAB 1 + +/* + * This header ensures that no record in the data file has the offset 0. + */ +typedef struct XTTableHead { + XTDiskValue4 th_head_size_4; /* The size of the table header. */ + XTDiskValue4 th_op_seq_4; + XTDiskValue6 th_row_free_6; + XTDiskValue6 th_row_eof_6; + XTDiskValue6 th_row_fnum_6; + XTDiskValue6 th_rec_free_6; + XTDiskValue6 th_rec_eof_6; + XTDiskValue6 th_rec_fnum_6; +} XTTableHeadDRec, *XTTableHeadDPtr; + +typedef struct XTTableFormat { + XTDiskValue4 tf_format_size_4; /* The size of this structure (table format). */ + XTDiskValue4 tf_tab_head_size_4; /* The offset of the first record in the data handle file. */ + XTDiskValue2 tf_tab_version_2; /* The table version number. */ + XTDiskValue2 tf_tab_flags_2; /* Table flags XT_TAB_FLAGS_* */ + XTDiskValue4 tf_rec_size_4; /* The maximum size of records in the table. */ + XTDiskValue1 tf_rec_fixed_1; /* Set to 1 if this table contains fixed length records. */ + XTDiskValue1 tf_reserved_1; /* - */ + XTDiskValue8 tf_min_auto_inc_8; /* This is the minimum auto-increment value. */ + xtWord1 tf_reserved[64]; /* Reserved, set to 0. */ + char tf_definition[XT_VAR_LENGTH]; /* A cstring, currently it only contains the foreign key information. */ +} XTTableFormatDRec, *XTTableFormatDPtr; + +#define XT_STAT_ID_MASK(x) ((x) & (u_int) 0x000000FF) + +/* A record that fits completely in the data file record */ +typedef struct XTTabRecHead { + xtWord1 tr_rec_type_1; + xtWord1 tr_stat_id_1; + xtDiskRecordID4 tr_prev_rec_id_4; /* The previous variation of this record. */ + XTDiskValue4 tr_xact_id_4; /* The transaction ID. */ + XTDiskValue4 tr_row_id_4; /* The row ID of this record. */ +} XTTabRecHeadDRec, *XTTabRecHeadDPtr; + +typedef struct XTTabRecFix { + xtWord1 tr_rec_type_1; /* XT_TAB_STATUS_FREED, XT_TAB_STATUS_DELETE, + * XT_TAB_STATUS_FIXED, XT_TAB_STATUS_VARIABLE */ + xtWord1 tr_stat_id_1; + xtDiskRecordID4 tr_prev_rec_id_4; /* The previous variation of this record. */ + XTDiskValue4 tr_xact_id_4; /* The transaction ID. */ + XTDiskValue4 tr_row_id_4; /* The row ID of this record. */ + xtWord1 rf_data[XT_VAR_LENGTH]; /* NOTE: This data is in RAW MySQL format. */ +} XTTabRecFixDRec, *XTTabRecFixDPtr; + +/* An extended record that overflows into the log file: */ +typedef struct XTTabRecExt { + xtWord1 tr_rec_type_1; /* XT_TAB_STATUS_EXT_DLOG */ + xtWord1 tr_stat_id_1; + xtDiskRecordID4 tr_prev_rec_id_4; /* The previous variation of this record. */ + XTDiskValue4 tr_xact_id_4; /* The transaction ID. */ + XTDiskValue4 tr_row_id_4; /* The row ID of this record. */ + XTDiskValue2 re_log_id_2; /* Reference to overflow area, log ID */ + XTDiskValue6 re_log_offs_6; /* Reference to the overflow area, log offset */ + XTDiskValue4 re_log_dat_siz_4; /* Size of the overflow data. */ + xtWord1 re_data[XT_VAR_LENGTH]; /* This data is in packed PBXT format. */ +} XTTabRecExtDRec, *XTTabRecExtDPtr; + +typedef struct XTTabRecExtHdat { + xtWord1 tr_rec_type_1; /* XT_TAB_STATUS_EXT_HDATA */ + xtWord1 tr_stat_id_1; + xtDiskRecordID4 tr_prev_rec_id_4; /* The previous variation of this record. */ + XTDiskValue4 tr_xact_id_4; /* The transaction ID. */ + XTDiskValue4 tr_row_id_4; /* The row ID of this record. */ + XTDiskValue4 eh_blk_rec_id_4; /* The record ID of the next block. */ + XTDiskValue2 eh_blk_siz_2; /* The total size of the data in the trailing blocks */ + xtWord1 eh_data[XT_VAR_LENGTH]; /* This data is in packed PBXT format. */ +} XTTabRecExtHdatDRec, *XTTabRecExtHdatDPtr; + +typedef struct XTTabRecData { + xtWord1 tr_rec_type_1; /* XT_TAB_STATUS_DATA */ + XTDiskValue4 rd_blk_rec_id_4; /* The record ID of the next block. */ + xtWord1 rd_data[XT_VAR_LENGTH]; /* This data is in packed PBXT format. */ +} XTTabRecDataDRec, *XTTabRecDataDPtr; + +typedef struct XTTabRecEndDat { + xtWord1 tr_rec_type_1; /* XT_TAB_STATUS_END_DATA */ + xtWord1 ed_data[XT_VAR_LENGTH]; /* This data is in packed PBXT format. */ +} XTTabRecEndDatDRec, *XTTabRecEndDatDPtr; + +#define XT_REC_FIX_HEADER_SIZE sizeof(XTTabRecHeadDRec) +#define XT_REC_EXT_HEADER_SIZE offsetof(XTTabRecExtDRec, re_data) +#define XT_REC_FIX_EXT_HEADER_DIFF (XT_REC_EXT_HEADER_SIZE - XT_REC_FIX_HEADER_SIZE) + +typedef struct XTTabRecFree { + xtWord1 rf_rec_type_1; + xtWord1 rf_not_used_1; + xtDiskRecordID4 rf_next_rec_id_4; /* The next block on the free list. */ +} XTTabRecFreeDRec, *XTTabRecFreeDPtr; + +typedef struct XTTabRecInfo { + XTTabRecFixDPtr ri_fix_rec_buf; /* This references the start of the buffer (set for all types of records) */ + XTTabRecExtDPtr ri_ext_rec; /* This is only set for extended records. */ + xtWord4 ri_rec_buf_size; + XTactExtRecEntryDPtr ri_log_buf; + xtWord4 ri_log_data_size; /* This size of the data in the log record. */ + xtRecordID ri_rec_id; /* The record ID. */ +} XTTabRecInfoRec, *XTTabRecInfoPtr; + +/* ------- TABLE ROW FILE ------- */ + +#define XT_TAB_ROW_SHIFTS 2 +#define XT_TAB_ROW_MAGIC 0x4567CDEF +//#define XT_TAB_ROW_FREE 0 +//#define XT_TAB_ROW_IN_USE 1 + +/* + * NOTE: The shift count assumes the size of a table row + * reference is 8 bytes (XT_TAB_ROW_SHIFTS) + */ +typedef struct XTTabRowRef { + XTDiskValue4 rr_ref_id_4; /* 4-byte reference, could be a RowID or a RecordID + * If this row is free, then it is a RowID, which + * references the next free row. + * If it is in use, then it is a RecordID which + * points to the first record in the variation + * list for the row. + */ +} XTTabRowRefDRec, *XTTabRowRefDPtr; + +/* + * This is the header for the row file. The size MUST be a + * the same size as sizeof(XTTabRowRefDRec) + */ +typedef struct XTTabRowHead { + XTDiskValue4 rh_magic_4; +} XTTabRowHeadDRec, *XTTabRowHeadDPtr; + +/* ------- TABLE & OPEN TABLES & TABLE LISTING ------- */ + +/* {TEMP-TABLES} + * Temporary tables do not need to be flused, + * and they also do not need to be recovered! + * Currently this is determined by the name of the + * table! + */ +typedef struct XTTable : public XTHeap { + struct XTDatabase *tab_db; /* Heap pointer */ + XTPathStrPtr tab_name; + xtBool tab_free_locks; + xtTableID tab_id; + + xtWord8 tab_auto_inc; /* The last value returned as an auto-increment value {PRE-INC}. */ + XTSpinLockRec tab_ainc_lock; /* Lock for the auto-increment counter. */ + + size_t tab_index_format_offset; + size_t tab_index_header_size; + size_t tab_index_page_size; + u_int tab_index_block_shifts; + XTIndexHeadDPtr tab_index_head; + size_t tab_table_format_offset; + size_t tab_table_head_size; + XTDictionaryRec tab_dic; + xt_mutex_type tab_dic_field_lock; /* Lock for setting field->ptr!. */ + + XTRowLocksRec tab_locks; /* The locks held on this table. */ + + XTTableSeqRec tab_seq; /* The table operation sequence. */ + XTTabCacheRec tab_rows; + XTTabCacheRec tab_recs; + + /* Used to apply operations to the database in order. */ + XTSortedListPtr tab_op_list; /* The operation list. Operations to be applied. */ + + /* Values that belong in the header when flushed! */ + xtBool tab_flush_pending; /* TRUE if the table needs to be flushed */ + xtBool tab_recovery_done; /* TRUE if the table has been recovered */ + xtBool tab_temporary; /* TRUE if this is a temporary table {TEMP-TABLES}. */ + off_t tab_bytes_to_flush; /* Number of bytes of the record/row files to flush. */ + + xtOpSeqNo tab_head_op_seq; /* The number of the operation last applied to the database. */ + xtRowID tab_head_row_free_id; + xtRowID tab_head_row_eof_id; + xtWord4 tab_head_row_fnum; + xtRecordID tab_head_rec_free_id; + xtRecordID tab_head_rec_eof_id; + xtWord4 tab_head_rec_fnum; + + xtOpSeqNo tab_co_op_seq; /* The operation last applied by the compactor. */ + + xtBool tab_wr_wake_freeer; /* Set to TRUE if the writer must wake the freeer. */ + xtOpSeqNo tab_wake_freeer_op; /* Set to the sequence number the freeer is waiting for. */ + + XTFilePtr tab_row_file; + xtRowID tab_row_eof_id; /* Indicates the EOF of the table row file. */ + xtRowID tab_row_free_id; /* The start of the free list in the table row file. */ + xtWord4 tab_row_fnum; /* The count of the number of free rows on the free list. */ + xt_mutex_type tab_row_lock; /* Lock for updating the EOF and free list. */ + XT_TAB_ROW_LOCK_TYPE tab_row_rwlock[XT_ROW_RWLOCKS]; /* Used to lock a row during update. */ + + xt_mutex_type tab_rec_flush_lock; /* Required while the record/row files are being flushed. */ + XTFilePtr tab_rec_file; + xtRecordID tab_rec_eof_id; /* This value can only grow. */ + xtRecordID tab_rec_free_id; + xtWord4 tab_rec_fnum; /* The count of the number of free rows on the free list. */ + xt_mutex_type tab_rec_lock; /* Lock for the free list. */ + + xt_mutex_type tab_ind_flush_lock; /* Required while the index file is being flushed. */ + xtLogID tab_ind_rec_log_id; /* The point before which index entries have been written. */ + xtLogOffset tab_ind_rec_log_offset; /* The log offset of the write point. */ + XTFilePtr tab_ind_file; + xtIndexNodeID tab_ind_eof; /* This value can only grow. */ + xtIndexNodeID tab_ind_free; /* The start of the free page list of the index. */ + XTIndFreeListPtr tab_ind_free_list; /* A cache of the free list (if exists, don't go to disk!) */ + xt_mutex_type tab_ind_lock; /* Lock for reading and writing the index free list. */ + xtWord2 tab_ind_flush_seq; +} XTTableHRec, *XTTableHPtr; /* Heap pointer */ + +/* Used for an in-memory list of the tables, ordered by ID. */ +typedef struct XTTableEntry { + xtTableID te_tab_id; + char *te_tab_name; + struct XTTablePath *te_tab_path; + XTTableHPtr te_table; +} XTTableEntryRec, *XTTableEntryPtr; + +typedef struct XTOpenTable { + struct XTThread *ot_thread; /* The thread currently using this open table. */ + XTTableHPtr ot_table; /* PBXT table information. */ + + struct XTOpenTable *ot_otp_next_free; /* Next free open table in the open table pool. */ + struct XTOpenTable *ot_otp_mr_used; + struct XTOpenTable *ot_otp_lr_used; + time_t ot_otp_free_time; /* The time this table was place on the free list. */ + + //struct XTOpenTable *ot_pool_next; /* Next pointer for open table pool. */ + + XT_ROW_REC_FILE_PTR ot_rec_file; + XT_ROW_REC_FILE_PTR ot_row_file; + XTOpenFilePtr ot_ind_file; + u_int ot_err_index_no; /* The number of the index on which the last error occurred */ + + xtBool ot_rec_fixed; /* Cached from table for quick access. */ + size_t ot_rec_size; /* Cached from table for quick access. */ + + char ot_error_key[XT_IDENTIFIER_NAME_SIZE]; + xtBool ot_for_update; /* True if reading FOR UPDATE. */ + xtBool ot_is_modify; /* True if UPDATE or DELETE. */ + xtRowID ot_temp_row_lock; /* The temporary row lock set on this table. */ + u_int ot_cols_req; /* The number of columns required from the table. */ + + /* GOTCHA: Separate buffers for reading and writing rows because + * of blob references, to this buffer, as in this test: + * + * drop table if exists t1; + * CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc TEXT, + * bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, + * f FLOAT DEFAULT 0, total BIGINT UNSIGNED, + * y YEAR, t DATE) + * PARTITION BY RANGE (YEAR(t)) + * (PARTITION p1 VALUES LESS THAN (2005), + * PARTITION p2 VALUES LESS THAN MAXVALUE); + * + * INSERT INTO t1 VALUES(412,1,'eTesting MySQL databases is a cool ', + * 'EEEMust make it bug free for the customer', + * 654321.4321,15.21,0,1965,"2005-11-14"); + * + * UPDATE t1 SET b1 = 0, t="2006-02-22" WHERE id = 412; + * + */ + size_t ot_row_rbuf_size; /* The current size of the read row buffer (resized dynamically). */ + xtWord1 *ot_row_rbuffer; /* The row buffer for reading rows. */ + size_t ot_row_wbuf_size; /* The current size of the write row buffer (resized dynamically). */ + xtWord1 *ot_row_wbuffer; /* The row buffer for writing rows. */ + + /* Details of the current record: */ + xtRecordID ot_curr_rec_id; /* The offset of the current record. */ + xtRowID ot_curr_row_id; /* The row ID of the current record. */ + xtBool ot_curr_updated; /* TRUE if the current record was updated by the current transaction. */ + + XTIndBlockPtr ot_ind_res_bufs; /* A list of reserved index buffers. */ + u_int ot_ind_res_count; /* The number of reserved buffers. */ +#ifdef XT_TRACK_INDEX_UPDATES + u_int ot_ind_changed; + u_int ot_ind_reserved; + u_int ot_ind_reads; +#endif +#ifdef XT_TRACK_RETURNED_ROWS + u_int ot_rows_ret_max; + u_int ot_rows_ret_curr; + xtRecordID *ot_rows_returned; +#endif + /* GOTCHA: Separate buffers for reading and writing the index are required + * because MySQL sometimes scans and updates an index with the same + * table handler. + */ + XTIdxItemRec ot_ind_state; /* Decribes the state of the index buffer. */ + XTIndHandlePtr ot_ind_rhandle; /* This handle references a block which is being used in a sequential scan. */ + //XTIdxBranchDRec ot_ind_rbuf; /* The index read buffer. */ + XTIdxBranchDRec ot_ind_wbuf; /* Buffer for the current index node for writing. */ + xtWord1 ot_ind_wbuf2[XT_INDEX_PAGE_SIZE]; /* Overflow for the write buffer when a node is too big. */ + + /* Note: the fields below ot_ind_rbuf are not zero'ed out on creation + * of this structure! + */ + xtRecordID ot_seq_rec_id; /* Current position of a sequential scan. */ + xtRecordID ot_seq_eof_id; /* The EOF at the start of the sequential scan. */ + XTTabCachePagePtr ot_seq_page; /* If ot_seq_buffer is non-NULL, then a page has been locked! */ + xtBool ot_on_page; + size_t ot_seq_offset; /* Offset on the current page. */ +} XTOpenTableRec, *XTOpenTablePtr; + +#define XT_DATABASE_NAME_SIZE XT_IDENTIFIER_NAME_SIZE + +typedef struct XTTableDesc { + char td_tab_name[XT_TABLE_NAME_SIZE+4]; // 4 extra for DEL# (tables being deleted) + xtTableID td_tab_id; + char *td_file_name; + + struct XTDatabase *td_db; + struct XTTablePath *td_tab_path; // The path of the table. + u_int td_path_idx; + XTOpenDirPtr td_open_dir; +} XTTableDescRec, *XTTableDescPtr; + + +typedef struct XTFilesOfTable { + int ft_state; + XTPathStrPtr ft_tab_name; + xtTableID ft_tab_id; + char ft_file_path[PATH_MAX]; +} XTFilesOfTableRec, *XTFilesOfTablePtr; + +typedef struct XTRestrictItem { + xtTableID ri_tab_id; + xtRecordID ri_rec_id; +} XTRestrictItemRec, *XTRestrictItemPtr; + +int xt_tab_compare_names(const char *n1, const char *n2); +int xt_tab_compare_paths(char *n1, char *n2); +void xt_tab_init_db(struct XTThread *self, struct XTDatabase *db); +void xt_tab_exit_db(struct XTThread *self, struct XTDatabase *db); +void xt_check_tables(struct XTThread *self); + +char *xt_tab_file_to_name(size_t size, char *tab_name, char *file_name); + +void xt_create_table(struct XTThread *self, XTPathStrPtr name, XTDictionaryPtr dic); +XTTableHPtr xt_use_table(struct XTThread *self, XTPathStrPtr name, xtBool no_load, xtBool missing_ok, xtBool *opened); +void xt_sync_flush_table(struct XTThread *self, XTOpenTablePtr ot); +xtBool xt_flush_record_row(XTOpenTablePtr ot, off_t *bytes_flushed, xtBool have_table_loc); +void xt_flush_table(struct XTThread *self, XTOpenTablePtr ot); +XTTableHPtr xt_use_table_no_lock(XTThreadPtr self, struct XTDatabase *db, XTPathStrPtr name, xtBool no_load, xtBool missing_ok, XTDictionaryPtr dic, xtBool *opened); +int xt_use_table_by_id(struct XTThread *self, XTTableHPtr *tab, struct XTDatabase *db, xtTableID tab_id); +XTOpenTablePtr xt_open_table(XTTableHPtr tab); +void xt_close_table(XTOpenTablePtr ot, xtBool flush, xtBool have_table_lock); +void xt_drop_table(struct XTThread *self, XTPathStrPtr name); +void xt_check_table(XTThreadPtr self, XTOpenTablePtr tab); +void xt_rename_table(struct XTThread *self, XTPathStrPtr old_name, XTPathStrPtr new_name); + +void xt_describe_tables_init(struct XTThread *self, struct XTDatabase *db, XTTableDescPtr td); +xtBool xt_describe_tables_next(struct XTThread *self, XTTableDescPtr td); +void xt_describe_tables_exit(struct XTThread *self, XTTableDescPtr td); + +xtBool xt_table_exists(struct XTDatabase *db); + +void xt_enum_tables_init(u_int *edx); +XTTableEntryPtr xt_enum_tables_next(struct XTThread *self, struct XTDatabase *db, u_int *edx); + +void xt_enum_files_of_tables_init(struct XTDatabase *db, char *tab_name, xtTableID tab_id, XTFilesOfTablePtr ft); +xtBool xt_enum_files_of_tables_next(XTFilesOfTablePtr ft); + +xtBool xt_tab_seq_init(XTOpenTablePtr ot); +void xt_tab_seq_reset(XTOpenTablePtr ot); +void xt_tab_seq_exit(XTOpenTablePtr ot); +xtBool xt_tab_seq_next(XTOpenTablePtr ot, xtWord1 *buffer, xtBool *eof); + +xtBool xt_tab_new_record(XTOpenTablePtr ot, xtWord1 *buffer); +xtBool xt_tab_delete_record(XTOpenTablePtr ot, xtWord1 *buffer); +xtBool xt_tab_restrict_rows(XTBasicListPtr list, struct XTThread *thread); +xtBool xt_tab_update_record(XTOpenTablePtr ot, xtWord1 *before_buf, xtWord1 *after_buf); +int xt_tab_visible(XTOpenTablePtr ot); +int xt_tab_read_record(register XTOpenTablePtr ot, xtWord1 *buffer); +int xt_tab_dirty_read_record(register XTOpenTablePtr ot, xtWord1 *buffer); +void xt_tab_load_row_pointers(XTThreadPtr self, XTOpenTablePtr ot); +void xt_tab_load_table(struct XTThread *self, XTOpenTablePtr ot); +xtBool xt_tab_load_record(register XTOpenTablePtr ot, xtRecordID rec_id, XTInfoBufferPtr rec_buf); +int xt_tab_remove_record(XTOpenTablePtr ot, xtRecordID rec_id, xtWord1 *rec_data, xtRecordID *prev_var_rec_id, xtBool clean_delete, xtRowID row_id, xtXactID xn_id); +int xt_tab_maybe_committed(XTOpenTablePtr ot, xtRecordID rec_id, xtXactID *xn_id, xtRowID *out_rowid, xtBool *out_updated); +xtBool xt_tab_free_record(XTOpenTablePtr ot, u_int status, xtRecordID rec_id, xtBool clean_delete); +void xt_tab_store_header(XTOpenTablePtr ot, XTTableHeadDPtr rec_head); +xtBool xt_tab_write_header(XTOpenTablePtr ot, XTTableHeadDPtr rec_head, struct XTThread *thread); +xtBool xt_tab_write_min_auto_inc(XTOpenTablePtr ot); + +xtBool xt_tab_get_row(register XTOpenTablePtr ot, xtRowID row_id, xtRecordID *var_rec_id); +xtBool xt_tab_set_row(XTOpenTablePtr ot, u_int status, xtRowID row_id, xtRecordID var_rec_id); +xtBool xt_tab_free_row(XTOpenTablePtr ot, XTTableHPtr tab, xtRowID row_id); + +xtBool xt_tab_load_ext_data(XTOpenTablePtr ot, xtRecordID load_rec_id, xtWord1 *buffer, u_int cols_req); +xtBool xt_tab_put_rec_data(XTOpenTablePtr ot, xtRecordID rec_id, size_t size, xtWord1 *buffer, xtOpSeqNo *op_seq); +xtBool xt_tab_put_eof_rec_data(XTOpenTablePtr ot, xtRecordID rec_id, size_t size, xtWord1 *buffer, xtOpSeqNo *op_seq); +xtBool xt_tab_put_log_op_rec_data(XTOpenTablePtr ot, u_int status, xtRecordID free_rec_id, xtRecordID rec_id, size_t size, xtWord1 *buffer); +xtBool xt_tab_put_log_rec_data(XTOpenTablePtr ot, u_int status, xtRecordID free_rec_id, xtRecordID rec_id, size_t size, xtWord1 *buffer, xtOpSeqNo *op_seq); +xtBool xt_tab_get_rec_data(register XTOpenTablePtr ot, xtRecordID rec_id, size_t size, xtWord1 *buffer); +void xt_tab_set_index_error(XTTableHPtr tab); + +inline off_t xt_row_id_to_row_offset(register XTTableHPtr tab, xtRowID row_id) +{ + return (off_t) tab->tab_rows.tci_header_size + (off_t) (row_id - 1) * (off_t) tab->tab_rows.tci_rec_size; +} + +inline xtRowID xt_row_offset_row_id(register XTTableHPtr tab, off_t rec_offs) +{ +#ifdef DEBUG + if (((rec_offs - (off_t) tab->tab_rows.tci_header_size) % (off_t) tab->tab_rows.tci_rec_size) != 0) { + printf("ERROR! Not a valid record offset!\n"); + } +#endif + return (xtRowID) ((rec_offs - (off_t) tab->tab_rows.tci_header_size) / (off_t) tab->tab_rows.tci_rec_size) + 1; +} + +inline off_t xt_rec_id_to_rec_offset(register XTTableHPtr tab, xtRefID ref_id) +{ + if (!ref_id) + return (off_t) 0; + return (off_t) tab->tab_recs.tci_header_size + (off_t) (ref_id-1) * (off_t) tab->tab_recs.tci_rec_size; +} + +inline xtRefID xt_rec_offset_rec_id(register XTTableHPtr tab, off_t ref_offs) +{ + if (!ref_offs) + return (xtRefID) 0; +#ifdef DEBUG + if (((ref_offs - (off_t) tab->tab_recs.tci_header_size) % (off_t) tab->tab_recs.tci_rec_size) != 0) { + printf("ERROR! Not a valid record offset!\n"); + } +#endif + + return (xtRefID) ((ref_offs - (off_t) tab->tab_recs.tci_header_size) / (off_t) tab->tab_recs.tci_rec_size)+1; +} + +inline off_t xt_ind_node_to_offset(register XTTableHPtr tab, xtIndexNodeID node_id) +{ + if (!XT_NODE_ID(node_id)) + return (off_t) 0; + return (off_t) tab->tab_index_header_size + (off_t) (XT_NODE_ID(node_id)-1) * (off_t) tab->tab_index_page_size; +} + +inline xtIndexNodeID xt_ind_offset_to_node(register XTTableHPtr tab, off_t ind_offs) +{ + XT_NODE_TEMP; + + if (!ind_offs) + return XT_RET_NODE_ID(0); +#ifdef DEBUG + if (((ind_offs - (off_t) tab->tab_index_header_size) % (off_t) tab->tab_index_page_size) != 0) { + printf("ERROR! Not a valid index offset!\n"); + } +#endif + + return XT_RET_NODE_ID(((ind_offs - (off_t) tab->tab_index_header_size) / (off_t) tab->tab_index_page_size)+1); +} + +#define XT_RESIZE_ROW_BUFFER(thr, rb, size) \ + do { \ + if (rb->rb_size < size) { \ + xt_realloc(thr, (void **) &rb->x.rb_buffer, size); \ + rb->rb_size = size; \ + } \ + } \ + while (0) + +#endif diff --git a/storage/pbxt/src/thread_xt.cc b/storage/pbxt/src/thread_xt.cc new file mode 100644 index 00000000000..bd7dca31cb5 --- /dev/null +++ b/storage/pbxt/src/thread_xt.cc @@ -0,0 +1,2300 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-03 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#ifndef XT_WIN +#include <unistd.h> +#include <sys/time.h> +#include <sys/resource.h> +#endif +#include <time.h> +#include <stdarg.h> +#include <signal.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> + +#include "xt_defs.h" +#include "strutil_xt.h" +#include "pthread_xt.h" +#include "thread_xt.h" +#include "memory_xt.h" +#include "sortedlist_xt.h" +#include "trace_xt.h" +#include "myxt_xt.h" +#include "database_xt.h" + +void xt_db_init_thread(XTThreadPtr self, XTThreadPtr new_thread); +void xt_db_exit_thread(XTThreadPtr self); + +static void thr_accumulate_statistics(XTThreadPtr self); + +/* + * ----------------------------------------------------------------------- + * THREAD GLOBALS + */ + +xtPublic u_int xt_thr_maximum_threads; +xtPublic u_int xt_thr_current_thread_count; +xtPublic u_int xt_thr_current_max_threads; + +/* This structure is a double linked list of thread, with a wait + * condition on it. + */ +static XTLinkedListPtr thr_list; + +/* This structure maps thread ID's to thread pointers. */ +xtPublic XTThreadPtr *xt_thr_array; +static xt_mutex_type thr_array_lock; + +/* Global accumulated statistics: */ +static XTStatisticsRec thr_statistics; + +/* + * ----------------------------------------------------------------------- + * Error logging + */ + +static xt_mutex_type log_mutex; +static int log_level = 0; +static FILE *log_file = NULL; +static xtBool log_newline = TRUE; + +xtPublic xtBool xt_init_logging(void) +{ + int err; + + log_file = stdout; + log_level = XT_LOG_TRACE; + err = xt_p_mutex_init_with_autoname(&log_mutex, NULL); + if (err) { + xt_log_errno(XT_NS_CONTEXT, err); + log_file = NULL; + log_level = 0; + return FALSE; + } + if (!xt_init_trace()) { + xt_exit_logging(); + return FALSE; + } + return TRUE; +} + +xtPublic void xt_exit_logging(void) +{ + if (log_file) { + xt_free_mutex(&log_mutex); + log_file = NULL; + } + xt_exit_trace(); +} + +xtPublic void xt_get_now(char *buffer, size_t len) +{ + time_t ticks; + struct tm ltime; + + ticks = time(NULL); + if (ticks == (time_t) -1) { +#ifdef XT_WIN + printf(buffer, "** error %d getting time **", errno); +#else + snprintf(buffer, len, "** error %d getting time **", errno); +#endif + return; + } + localtime_r(&ticks, <ime); + strftime(buffer, len, "%y%m%d %H:%M:%S", <ime); +} + +static void thr_log_newline(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level) +{ + c_char *level_str; + char time_str[200]; + char thr_name[XT_THR_NAME_SIZE+3]; + + xt_get_now(time_str, 200); + if (self && *self->t_name) { + xt_strcpy(XT_THR_NAME_SIZE+3, thr_name, " "); + xt_strcat(XT_THR_NAME_SIZE+3, thr_name, self->t_name); + } + else + thr_name[0] = 0; + switch (level) { + case XT_LOG_FATAL: level_str = " [Fatal]"; break; + case XT_LOG_ERROR: level_str = " [Error]"; break; + case XT_LOG_WARNING: level_str = " [Warning]"; break; + case XT_LOG_INFO: level_str = " [Note]"; break; + case XT_LOG_TRACE: level_str = " [Trace]"; break; + default: level_str = " "; break; + } + if (func && *func && *func != '-') { + char func_name[XT_MAX_FUNC_NAME_SIZE]; + + xt_strcpy_term(XT_MAX_FUNC_NAME_SIZE, func_name, func, '('); + if (file && *file) + fprintf(log_file, "%s%s%s %s(%s:%d) ", time_str, level_str, thr_name, func_name, xt_last_name_of_path(file), line); + else + fprintf(log_file, "%s%s%s %s() ", time_str, level_str, thr_name, func_name); + } + else { + if (file && *file) + fprintf(log_file, "%s%s%s [%s:%d] ", time_str, level_str, thr_name, xt_last_name_of_path(file), line); + else + fprintf(log_file, "%s%s%s ", time_str, level_str, thr_name); + } +} + +#ifdef XT_WIN +/* Windows uses printf()!! */ +#define DEFAULT_LOG_BUFFER_SIZE 2000 +#else +#ifdef DEBUG +#define DEFAULT_LOG_BUFFER_SIZE 10 +#else +#define DEFAULT_LOG_BUFFER_SIZE 2000 +#endif +#endif + +void xt_log_flush(XTThreadPtr self __attribute__((unused))) +{ + fflush(log_file); +} + +/* + * Log the given formated string information to the log file. + * Before each new line, this function writes the + * log header, which includes the time, log level, + * and source file and line number (optional). + */ +static void thr_log_va(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *fmt, va_list ap) +{ + char buffer[DEFAULT_LOG_BUFFER_SIZE]; + char *log_string = NULL; + + if (level > log_level) + return; + + xt_lock_mutex_ns(&log_mutex); + +#ifdef XT_WIN + vsprintf(buffer, fmt, ap); + log_string = buffer; +#else +#if !defined(va_copy) || defined(XT_SOLARIS) + int len; + + len = vsnprintf(buffer, DEFAULT_LOG_BUFFER_SIZE-1, fmt, ap); + if (len > DEFAULT_LOG_BUFFER_SIZE-1) + len = DEFAULT_LOG_BUFFER_SIZE-1; + buffer[len] = 0; + log_string = buffer; +#else + /* Use the buffer, unless it is too small */ + va_list ap2; + + va_copy(ap2, ap); + if (vsnprintf(buffer, DEFAULT_LOG_BUFFER_SIZE, fmt, ap) >= DEFAULT_LOG_BUFFER_SIZE) { + if (vasprintf(&log_string, fmt, ap2) == -1) + log_string = NULL; + } + else + log_string = buffer; +#endif +#endif + + if (log_string) { + char *str, *str_end, tmp_ch; + + str = log_string; + while (*str) { + if (log_newline) { + thr_log_newline(self, func, file, line, level); + log_newline = FALSE; + } + str_end = strchr(str, '\n'); + if (str_end) { + str_end++; + tmp_ch = *str_end; + *str_end = 0; + log_newline = TRUE; + } + else { + str_end = str + strlen(str); + tmp_ch = 0; + } + fprintf(log_file, "%s", str); + fflush(log_file); + *str_end = tmp_ch; + str = str_end; + } + + if (log_string != buffer) + free(log_string); + } + + xt_unlock_mutex_ns(&log_mutex); +} + +xtPublic void xt_logf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + thr_log_va(self, func, file, line, level, fmt, ap); + va_end(ap); +} + +xtPublic void xt_log(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *string) +{ + xt_logf(self, func, file, line, level, "%s", string); +} + +static int thr_log_error_va(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *fmt, va_list ap) +{ + int default_level; + char xt_err_string[50]; + + *xt_err_string = 0; + switch (xt_err) { + case XT_ASSERTION_FAILURE: + strcpy(xt_err_string, "Assertion"); + default_level = XT_LOG_FATAL; + break; + case XT_SYSTEM_ERROR: + strcpy(xt_err_string, "errno"); + default_level = XT_LOG_ERROR; + break; + case XT_SIGNAL_CAUGHT: + strcpy(xt_err_string, "Signal"); + default_level = XT_LOG_ERROR; + break; + default: + sprintf(xt_err_string, "%d", xt_err); + default_level = XT_LOG_ERROR; + break; + } + if (level == XT_LOG_DEFAULT) + level = default_level; + + if (*xt_err_string) { + if (sys_err) + xt_logf(self, func, file, line, level, "%s (%d): ", xt_err_string, sys_err); + else + xt_logf(self, func, file, line, level, "%s: ", xt_err_string); + } + thr_log_va(self, func, file, line, level, fmt, ap); + xt_logf(self, func, file, line, level, "\n"); + return level; +} + +/* The function returns the actual log level used. */ +xtPublic int xt_log_errorf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + level = thr_log_error_va(self, func, file, line, level, xt_err, sys_err, fmt, ap); + va_end(ap); + return level; +} + +/* The function returns the actual log level used. */ +xtPublic int xt_log_error(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *string) +{ + return xt_log_errorf(self, func, file, line, level, xt_err, sys_err, "%s", string); +} + +xtPublic void xt_log_exception(XTThreadPtr self, XTExceptionPtr e, int level) +{ + level = xt_log_error( + self, + e->e_func_name, + e->e_source_file, + e->e_source_line, + level, + e->e_xt_err, + e->e_sys_err, + e->e_err_msg); + /* Dump the catch trace: */ + if (*e->e_catch_trace) + xt_logf(self, NULL, NULL, 0, level, "%s", e->e_catch_trace); +} + +xtPublic void xt_log_and_clear_exception(XTThreadPtr self) +{ + xt_log_exception(self, &self->t_exception, XT_LOG_DEFAULT); + xt_clear_exception(self); +} + +xtPublic void xt_log_and_clear_exception_ns(void) +{ + xt_log_and_clear_exception(xt_get_self()); +} + +xtPublic void xt_log_and_clear_warning(XTThreadPtr self) +{ + xt_log_exception(self, &self->t_exception, XT_LOG_WARNING); + xt_clear_exception(self); +} + +xtPublic void xt_log_and_clear_warning_ns(void) +{ + xt_log_and_clear_warning(xt_get_self()); +} + +/* + * ----------------------------------------------------------------------- + * Exceptions + */ + +static void thr_add_catch_trace(XTExceptionPtr e, c_char *func, c_char *file, u_int line) +{ + if (func && *func && *func != '-') { + xt_strcat_term(XT_CATCH_TRACE_SIZE, e->e_catch_trace, func, '('); + xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, "("); + } + if (file && *file) { + xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, xt_last_name_of_path(file)); + if (line) { + char buffer[40]; + + sprintf(buffer, "%u", line); + xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, ":"); + xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, buffer); + } + } + if (func && *func && *func != '-') + xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, ")"); + xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, "\n"); +} + +static void thr_save_error_va(XTExceptionPtr e, XTThreadPtr self, xtBool throw_it, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, va_list ap) +{ + int i; + + if (!e) + return; + + e->e_xt_err = xt_err; + e->e_sys_err = sys_err; + vsnprintf(e->e_err_msg, XT_ERR_MSG_SIZE, fmt, ap); + + /* Make the first character of the message upper case: */ + if (isalpha(e->e_err_msg[0]) && islower(e->e_err_msg[0])) + e->e_err_msg[0] = (char) toupper(e->e_err_msg[0]); + + if (func && *func && *func != '-') + xt_strcpy_term(XT_MAX_FUNC_NAME_SIZE, e->e_func_name, func, '('); + else + *e->e_func_name = 0; + if (file && *file) { + xt_strcpy(XT_SOURCE_FILE_NAME_SIZE, e->e_source_file, xt_last_name_of_path(file)); + e->e_source_line = line; + } + else { + *e->e_source_file = 0; + e->e_source_line = 0; + } + *e->e_catch_trace = 0; + + if (!self) + return; + + /* Create a stack trace for this exception: */ + thr_add_catch_trace(e, func, file, line); + for (i=self->t_call_top-1; i>=0; i--) + thr_add_catch_trace(e, self->t_call_stack[i].cs_func, self->t_call_stack[i].cs_file, self->t_call_stack[i].cs_line); + + if (throw_it) + xt_throw(self); +} + +/* + * ----------------------------------------------------------------------- + * THROWING EXCEPTIONS + */ + +/* If we have to allocate resources and the hold them temporarily during which + * time an exception could occur, then these functions provide a holding + * place for the data, which will be freed in the case of an exception. + * + * Note: the free functions could themselves allocated resources. + * to make sure all things work out we only remove the resource from + * then stack when it is freed. + */ +static void thr_free_resources(XTThreadPtr self, XTResourcePtr top) +{ + XTResourcePtr rp; + XTThreadFreeFunc free_func; + + if (!top) + return; + while (self->t_res_top > top) { + /* Pop the top resource: */ + rp = (XTResourcePtr) (((char *) self->t_res_top) - self->t_res_top->r_prev_size); + + /* Free the resource: */ + if (rp->r_free_func) { + free_func = rp->r_free_func; + rp->r_free_func = NULL; + free_func(self, rp->r_data); + } + + self->t_res_top = rp; + } +} + +xtPublic void xt_bug(XTThreadPtr self __attribute__((unused))) +{ + static int *bug_ptr = NULL; + + bug_ptr = NULL; +} + +/* + * This function is called when an exception is caught. + * It restores the function call top and frees + * any resource allocated by lower levels. + */ +xtPublic void xt_caught(XTThreadPtr self) +{ + /* Restore the call top: */ + self->t_call_top = self->t_jmp_env[self->t_jmp_depth].jb_call_top; + + /* Free the temporary data that would otherwize be lost + * This should do nothing, because we actually free things on throw + * (se below). + */ + thr_free_resources(self, self->t_jmp_env[self->t_jmp_depth].jb_res_top); +} + +/* Throw an already registered error: */ +xtPublic void xt_throw(XTThreadPtr self) +{ + if (self) { + ASSERT_NS(self->t_exception.e_xt_err); + if (self->t_jmp_depth > 0 && self->t_jmp_depth <= XT_MAX_JMP) { + /* As recommended by Barry: rree the resources before the stack is invalid! */ + thr_free_resources(self, self->t_jmp_env[self->t_jmp_depth-1].jb_res_top); + + /* Then do the longjmp: */ + longjmp(self->t_jmp_env[self->t_jmp_depth-1].jb_buffer, 1); + } + } + + /* + * We cannot throw an error, because it will not be caught. + * This means there is no try ... catch block above. + * In this case, we just return. + * The calling functions must handle errors... + xt_caught(self); + xt_log(XT_CONTEXT, XT_LOG_FATAL, "Uncaught exception\n"); + xt_exit_thread(self, NULL); + */ +} + +xtPublic void xt_throwf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...) +{ + va_list ap; + XTThreadPtr thread = self ? self : xt_get_self(); + + va_start(ap, fmt); + thr_save_error_va(thread ? &thread->t_exception : NULL, thread, self ? TRUE : FALSE, func, file, line, xt_err, sys_err, fmt, ap); + va_end(ap); +} + +xtPublic void xt_throw_error(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg) +{ + xt_throwf(self, func, file, line, xt_err, sys_err, "%s", msg); +} + +#define XT_SYS_ERR_SIZE 300 + +static c_char *thr_get_sys_error(int err, char *err_msg __attribute__((unused))) +{ +#ifdef XT_WIN + char *ptr; + + if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, + err, 0, err_msg, XT_SYS_ERR_SIZE, NULL)) { + return strerror(err); + } + + ptr = &err_msg[strlen(err_msg)]; + while (ptr-1 > err_msg) { + if (*(ptr-1) != '\n' && *(ptr-1) != '\r' && *(ptr-1) != '.') + break; + ptr--; + } + *ptr = 0; +return err_msg; +#else + return strerror(err); +#endif +} + +static c_char *thr_get_err_string(int xt_err) +{ + c_char *str; + + switch (xt_err) { + case XT_ERR_STACK_OVERFLOW: str = "Stack overflow"; break; + case XT_ERR_JUMP_OVERFLOW: str = "Jump overflow"; break; + case XT_ERR_TABLE_EXISTS: str = "Table `%s` already exists"; break; + case XT_ERR_NAME_TOO_LONG: str = "Name '%s' is too long"; break; + case XT_ERR_TABLE_NOT_FOUND: str = "Table `%s` not found"; break; + case XT_ERR_SESSION_NOT_FOUND: str = "Session %s not found"; break; + case XT_ERR_BAD_ADDRESS: str = "Incorrect address '%s'"; break; + case XT_ERR_UNKNOWN_SERVICE: str = "Unknown service '%s'"; break; + case XT_ERR_UNKNOWN_HOST: str = "Host '%s' not found"; break; + case XT_ERR_TOKEN_EXPECTED: str = "%s expected in place of %s"; break; + case XT_ERR_PROPERTY_REQUIRED: str = "Property '%s' required"; break; + case XT_ERR_DEADLOCK: str = "Deadlock, transaction aborted"; break; + case XT_ERR_CANNOT_CHANGE_DB: str = "Cannot change database while transaction is in progress"; break; + case XT_ERR_ILLEGAL_CHAR: str = "Illegal character: '%s'"; break; + case XT_ERR_UNTERMINATED_STRING:str = "Unterminated string: %s"; break; + case XT_ERR_SYNTAX: str = "Syntax error near %s"; break; + case XT_ERR_ILLEGAL_INSTRUCTION:str = "Illegal instruction"; break; + case XT_ERR_OUT_OF_BOUNDS: str = "Memory reference out of bounds"; break; + case XT_ERR_STACK_UNDERFLOW: str = "Stack underflow"; break; + case XT_ERR_TYPE_MISMATCH: str = "Type mismatch"; break; + case XT_ERR_ILLEGAL_TYPE: str = "Illegal type for operator"; break; + case XT_ERR_ID_TOO_LONG: str = "Identifier too long: %s"; break; + case XT_ERR_TYPE_OVERFLOW: str = "Type overflow: %s"; break; + case XT_ERR_TABLE_IN_USE: str = "Table `%s` in use"; break; + case XT_ERR_NO_DATABASE_IN_USE: str = "No database in use"; break; + case XT_ERR_CANNOT_RESOLVE_TYPE:str = "Cannot resolve type with ID: %s"; break; + case XT_ERR_BAD_INDEX_DESC: str = "Unsupported index description: %s"; break; + case XT_ERR_WRONG_NO_OF_VALUES: str = "Incorrect number of values"; break; + case XT_ERR_CANNOT_OUTPUT_VALUE:str = "Cannot output given type"; break; + case XT_ERR_COLUMN_NOT_FOUND: str = "Column `%s.%s` not found"; break; + case XT_ERR_NOT_IMPLEMENTED: str = "Not implemented"; break; + case XT_ERR_UNEXPECTED_EOS: str = "Connection unexpectedly lost"; break; + case XT_ERR_BAD_TOKEN: str = "Incorrect binary token"; break; + case XT_ERR_RES_STACK_OVERFLOW: str = "Internal error: resource stack overflow"; break; + case XT_ERR_BAD_INDEX_TYPE: str = "Unsupported index type: %s"; break; + case XT_ERR_INDEX_EXISTS: str = "Index '%s' already exists"; break; + case XT_ERR_INDEX_STRUC_EXISTS: str = "Index '%s' has an identical structure"; break; + case XT_ERR_INDEX_NOT_FOUND: str = "Index '%s' not found"; break; + case XT_ERR_INDEX_CORRUPT: str = "Cannot read index '%s'"; break; + case XT_ERR_TYPE_NOT_SUPPORTED: str = "Data type %s not supported"; break; + case XT_ERR_BAD_TABLE_VERSION: str = "Table `%s` version not supported, upgrade required"; break; + case XT_ERR_BAD_RECORD_FORMAT: str = "Record format unknown, either corrupted or upgrade required"; break; + case XT_ERR_BAD_EXT_RECORD: str = "Extended record part does not match reference"; break; + case XT_ERR_RECORD_CHANGED: str = "Record already updated, transaction aborted"; break; + case XT_ERR_XLOG_WAS_CORRUPTED: str = "Corrupted transaction log has been truncated"; break; + case XT_ERR_DUPLICATE_KEY: str = "Duplicate unique key"; break; + case XT_ERR_NO_DICTIONARY: str = "Table `%s` has not yet been opened by MySQL"; break; + case XT_ERR_TOO_MANY_TABLES: str = "Limit of %s tables per database exceeded"; break; + case XT_ERR_KEY_TOO_LARGE: str = "Index '%s' exceeds the key size limit of %s"; break; + case XT_ERR_MULTIPLE_DATABASES: str = "Multiple database in a single transaction is not permitted"; break; + case XT_ERR_NO_TRANSACTION: str = "Internal error: no transaction running"; break; + case XT_ERR_A_EXPECTED_NOT_B: str = "%s expected in place of %s"; break; + case XT_ERR_NO_MATCHING_INDEX: str = "Matching index required for '%s'"; break; + case XT_ERR_TABLE_LOCKED: str = "Table `%s` locked"; break; + case XT_ERR_NO_REFERENCED_ROW: str = "Constraint: `%s`"; break; // "Foreign key '%s', referenced row does not exist" + case XT_ERR_ROW_IS_REFERENCED: str = "Constraint: `%s`"; break; // "Foreign key '%s', has a referencing row" + case XT_ERR_BAD_DICTIONARY: str = "Internal dictionary does not match MySQL dictionary"; break; + case XT_ERR_LOADING_MYSQL_DIC: str = "Error %s loading MySQL .frm file"; break; + case XT_ERR_COLUMN_IS_NOT_NULL: str = "Column `%s` is NOT NULL"; break; + case XT_ERR_INCORRECT_NO_OF_COLS: str = "Incorrect number of columns near %s"; break; + case XT_ERR_FK_ON_TEMP_TABLE: str = "Cannot create foreign key on temporary table"; break; + case XT_ERR_REF_TABLE_NOT_FOUND: str = "Referenced table `%s` not found"; break; + case XT_ERR_REF_TYPE_WRONG: str = "Incorrect data type on referenced column `%s`"; break; + case XT_ERR_DUPLICATE_FKEY: str = "Duplicate unique foreign key, contraint: %s"; break; + case XT_ERR_INDEX_FILE_TO_LARGE: str = "Index file has grown too large: %s"; break; + case XT_ERR_UPGRADE_TABLE: str = "Table `%s` must be upgraded from PBXT version %s"; break; + case XT_ERR_INDEX_NEW_VERSION: str = "Table `%s` index created by a newer version, upgrade required"; break; + case XT_ERR_LOCK_TIMEOUT: str = "Lock timeout on table `%s`"; break; + case XT_ERR_CONVERSION: str = "Error converting value for column `%s.%s`"; break; + case XT_ERR_NO_ROWS: str = "No matching row found in table `%s`"; break; + case XT_ERR_DATA_LOG_NOT_FOUND: str = "Data log not found: '%s'"; break; + case XT_ERR_LOG_MAX_EXCEEDED: str = "Maximum log count, %s, exceeded"; break; + case XT_ERR_MAX_ROW_COUNT: str = "Maximum row count reached"; break; + case XT_ERR_FILE_TOO_LONG: str = "File cannot be mapped, too large: '%s'"; break; + case XT_ERR_BAD_IND_BLOCK_SIZE: str = "Table `%s`, incorrect index block size: %s"; break; + case XT_ERR_INDEX_CORRUPTED: str = "Table `%s` index is corrupted, REPAIR TABLE required"; break; + case XT_ERR_NO_INDEX_CACHE: str = "Not enough index cache memory to handle concurrent updates"; break; + case XT_ERR_INDEX_LOG_CORRUPT: str = "Index log corrupt: '%s'"; break; + case XT_ERR_TOO_MANY_THREADS: str = "Too many threads: %s, increase max_connections"; break; + case XT_ERR_TOO_MANY_WAITERS: str = "Too many waiting threads: %s"; break; + case XT_ERR_INDEX_OLD_VERSION: str = "Table `%s` index created by an older version, REPAIR TABLE required"; break; + case XT_ERR_PBXT_TABLE_EXISTS: str = "System table cannot be dropped because PBXT table still exists"; break; + case XT_ERR_SERVER_RUNNING: str = "A server is possibly already running"; break; + case XT_ERR_INDEX_MISSING: str = "Index file of table '%s' is missing"; break; + case XT_ERR_RECORD_DELETED: str = "Record was deleted"; break; + case XT_ERR_NEW_TYPE_OF_XLOG: str = "Transaction log %s, is using a newer format, upgrade required"; break; + case XT_ERR_NO_BEFORE_IMAGE: str = "Internal error: no before image"; break; + case XT_ERR_FK_REF_TEMP_TABLE: str = "Foreign key may not reference temporary table"; break; + default: str = "Unknown XT error"; break; + } + return str; +} + +xtPublic void xt_throw_i2xterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item, c_char *item2) +{ + xt_throwf(self, func, file, line, xt_err, 0, thr_get_err_string(xt_err), item, item2); +} + +xtPublic void xt_throw_ixterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item) +{ + xt_throw_i2xterr(self, func, file, line, xt_err, item, NULL); +} + +xtPublic void xt_throw_tabcolerr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item, c_char *item2) +{ + char buffer[XT_IDENTIFIER_NAME_SIZE + XT_IDENTIFIER_NAME_SIZE + XT_IDENTIFIER_NAME_SIZE + 3]; + + xt_2nd_last_name_of_path(sizeof(buffer), buffer, tab_item->ps_path); + xt_strcat(sizeof(buffer), buffer, "."); + xt_strcat(sizeof(buffer), buffer, xt_last_name_of_path(tab_item->ps_path)); + + xt_throw_i2xterr(self, func, file, line, xt_err, buffer, item2); +} + +xtPublic void xt_throw_taberr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item) +{ + char buffer[XT_IDENTIFIER_NAME_SIZE + XT_IDENTIFIER_NAME_SIZE + XT_IDENTIFIER_NAME_SIZE + 3]; + + xt_2nd_last_name_of_path(sizeof(buffer), buffer, tab_item->ps_path); + xt_strcat(sizeof(buffer), buffer, "."); + xt_strcat(sizeof(buffer), buffer, xt_last_name_of_path(tab_item->ps_path)); + + xt_throw_ixterr(self, func, file, line, xt_err, buffer); +} + +xtPublic void xt_throw_ulxterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, u_long value) +{ + char buffer[100]; + + sprintf(buffer, "%lu", value); + xt_throw_ixterr(self, func, file, line, xt_err, buffer); +} + +xtPublic void xt_throw_sulxterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item, u_long value) +{ + char buffer[100]; + + sprintf(buffer, "%lu", value); + xt_throw_i2xterr(self, func, file, line, xt_err, item, buffer); +} + +xtPublic void xt_throw_xterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err) +{ + xt_throw_ixterr(self, func, file, line, xt_err, NULL); +} + +xtPublic void xt_throw_errno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err) +{ + char err_msg[XT_SYS_ERR_SIZE]; + + xt_throw_error(self, func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg)); +} + +xtPublic void xt_throw_ferrno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err, c_char *path) +{ + char err_msg[XT_SYS_ERR_SIZE]; + + xt_throwf(self, func, file, line, XT_SYSTEM_ERROR, err, "%s: '%s'", thr_get_sys_error(err, err_msg), path); +} + +xtPublic void xt_throw_assertion(XTThreadPtr self, c_char *func, c_char *file, u_int line, c_char *str) +{ + xt_throw_error(self, func, file, line, XT_ASSERTION_FAILURE, 0, str); +} + +static void xt_log_assertion(XTThreadPtr self, c_char *func, c_char *file, u_int line, c_char *str) +{ + xt_log_error(self, func, file, line, XT_LOG_DEFAULT, XT_ASSERTION_FAILURE, 0, str); +} + +xtPublic void xt_throw_signal(XTThreadPtr self, c_char *func, c_char *file, u_int line, int sig) +{ +#ifdef XT_WIN + char buffer[100]; + + sprintf(buffer, "Signal #%d", sig); + xt_throw_error(self, func, file, line, XT_SIGNAL_CAUGHT, sig, buffer); +#else + xt_throw_error(self, func, file, line, XT_SIGNAL_CAUGHT, sig, strsignal(sig)); +#endif +} + +/* + * ----------------------------------------------------------------------- + * REGISTERING EXCEPTIONS + */ + +xtPublic void xt_registerf(c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...) +{ + va_list ap; + XTThreadPtr thread = xt_get_self(); + + va_start(ap, fmt); + thr_save_error_va(thread ? &thread->t_exception : NULL, thread, FALSE, func, file, line, xt_err, sys_err, fmt, ap); + va_end(ap); +} + +xtPublic void xt_register_i2xterr(c_char *func, c_char *file, u_int line, int xt_err, c_char *item, c_char *item2) +{ + xt_registerf(func, file, line, xt_err, 0, thr_get_err_string(xt_err), item, item2); +} + +xtPublic void xt_register_ixterr(c_char *func, c_char *file, u_int line, int xt_err, c_char *item) +{ + xt_register_i2xterr(func, file, line, xt_err, item, NULL); +} + +xtPublic void xt_register_tabcolerr(c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item, c_char *item2) +{ + char buffer[XT_IDENTIFIER_NAME_SIZE + XT_IDENTIFIER_NAME_SIZE + XT_IDENTIFIER_NAME_SIZE + 3]; + + xt_2nd_last_name_of_path(sizeof(buffer), buffer, tab_item->ps_path); + xt_strcat(sizeof(buffer), buffer, "."); + xt_strcpy(sizeof(buffer), buffer, xt_last_name_of_path(tab_item->ps_path)); + xt_strcat(sizeof(buffer), buffer, "."); + xt_strcat(sizeof(buffer), buffer, item2); + + xt_register_ixterr(func, file, line, xt_err, buffer); +} + +xtPublic void xt_register_taberr(c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item) +{ + char buffer[XT_IDENTIFIER_NAME_SIZE + XT_IDENTIFIER_NAME_SIZE + XT_IDENTIFIER_NAME_SIZE + 3]; + + xt_2nd_last_name_of_path(sizeof(buffer), buffer, tab_item->ps_path); + xt_strcat(sizeof(buffer), buffer, "."); + xt_strcpy(sizeof(buffer), buffer, xt_last_name_of_path(tab_item->ps_path)); + + xt_register_ixterr(func, file, line, xt_err, buffer); +} + +xtPublic void xt_register_ulxterr(c_char *func, c_char *file, u_int line, int xt_err, u_long value) +{ + char buffer[100]; + + sprintf(buffer, "%lu", value); + xt_register_ixterr(func, file, line, xt_err, buffer); +} + +xtPublic xtBool xt_register_ferrno(c_char *func, c_char *file, u_int line, int err, c_char *path) +{ + char err_msg[XT_SYS_ERR_SIZE]; + + xt_registerf(func, file, line, XT_SYSTEM_ERROR, err, "%s: '%s'", thr_get_sys_error(err, err_msg), path); + return FAILED; +} + +xtPublic void xt_register_error(c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg) +{ + xt_registerf(func, file, line, xt_err, sys_err, "%s", msg); +} + +xtPublic xtBool xt_register_errno(c_char *func, c_char *file, u_int line, int err) +{ + char err_msg[XT_SYS_ERR_SIZE]; + + xt_register_error(func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg)); + return FAILED; +} + +xtPublic void xt_register_xterr(c_char *func, c_char *file, u_int line, int xt_err) +{ + xt_register_error(func, file, line, xt_err, 0, thr_get_err_string(xt_err)); +} + +/* + * ----------------------------------------------------------------------- + * CREATING EXCEPTIONS + */ + +xtPublic void xt_exceptionf(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + thr_save_error_va(e, self, FALSE, func, file, line, xt_err, sys_err, fmt, ap); + va_end(ap); +} + +xtPublic void xt_exception_error(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg) +{ + xt_exceptionf(e, self, func, file, line, xt_err, sys_err, "%s", msg); +} + +xtPublic xtBool xt_exception_errno(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int err) +{ + char err_msg[XT_SYS_ERR_SIZE]; + + xt_exception_error(e, self, func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg)); + return FAILED; +} + +/* + * ----------------------------------------------------------------------- + * LOG ERRORS + */ + +xtPublic void xt_log_errno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err) +{ + XTExceptionRec e; + + xt_exception_errno(&e, self, func, file, line, err); + xt_log_exception(self, &e, XT_LOG_DEFAULT); +} + +/* + * ----------------------------------------------------------------------- + * Assertions and failures (one breakpoints for all failures) + */ + +xtPublic xtBool xt_assert(XTThreadPtr self __attribute__((unused)), c_char *expr, c_char *func, c_char *file, u_int line) +{ +#ifdef DEBUG + //xt_set_fflush(TRUE); + //xt_dump_trace(); + printf("%s(%s:%d) %s\n", func, file, (int) line, expr); +#ifdef XT_WIN + FatalAppExit(0, "Assertion Failed!"); +#endif +#else + xt_throw_assertion(self, func, file, line, expr); +#endif + return FALSE; +} + +xtPublic xtBool xt_assume(XTThreadPtr self, c_char *expr, c_char *func, c_char *file, u_int line) +{ + xt_log_assertion(self, func, file, line, expr); + return FALSE; +} + +/* + * ----------------------------------------------------------------------- + * Create and destroy threads + */ + +typedef struct ThreadData { + xtBool td_started; + XTThreadPtr td_thr; + void *(*td_start_routine)(XTThreadPtr self); +} ThreadDataRec, *ThreadDataPtr; + +#ifdef XT_WIN +pthread_key(void *, thr_key); +#else +static pthread_key_t thr_key; +#endif + +#ifdef HANDLE_SIGNALS +static void thr_ignore_signal(int sig) +{ +#pragma unused(sig) +} + +static void thr_throw_signal(int sig) +{ + XTThreadPtr self; + + self = xt_get_self(); + + if (self->t_main) { + /* The main thread will pass on a signal to all threads: */ + xt_signal_all_threads(self, sig); + if (sig != SIGTERM) { + if (self->t_disable_interrupts) { + self->t_delayed_signal = sig; + self->t_disable_interrupts = FALSE; /* Prevent infinite loop */ + } + else { + self->t_delayed_signal = 0; + xt_throw_signal(self, "thr_throw_signal", NULL, 0, sig); + } + } + } + else { + if (self->t_disable_interrupts) { + self->t_delayed_signal = sig; + self->t_disable_interrupts = FALSE; /* Prevent infinite loop */ + } + else { + self->t_delayed_signal = 0; + xt_throw_signal(self, "thr_throw_signal", NULL, 0, sig); + } + } +} + +static xtBool thr_setup_signals(void) +{ + struct sigaction action; + + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = thr_ignore_signal; + + if (sigaction(SIGPIPE, &action, NULL) == -1) + goto error_occurred; + if (sigaction(SIGHUP, &action, NULL) == -1) + goto error_occurred; + + action.sa_handler = thr_throw_signal; + + if (sigaction(SIGQUIT, &action, NULL) == -1) + goto error_occurred; + if (sigaction(SIGTERM, &action, NULL) == -1) + goto error_occurred; +#ifndef DEBUG + if (sigaction(SIGILL, &action, NULL) == -1) + goto error_occurred; + if (sigaction(SIGBUS, &action, NULL) == -1) + goto error_occurred; + if (sigaction(SIGSEGV, &action, NULL) == -1) + goto error_occurred; +#endif + return TRUE; + + error_occurred: + xt_log_errno(XT_NS_CONTEXT, errno); + return FALSE; +} +#endif + +static void *thr_main(void *data) +{ + ThreadDataPtr td = (ThreadDataPtr) data; + XTThreadPtr self = td->td_thr; + void *(*start_routine)(XTThreadPtr); + void *return_data; + + enter_(); + self->t_pthread = pthread_self(); + start_routine = td->td_start_routine; + return_data = NULL; + +#ifdef HANDLE_SIGNALS + if (!thr_setup_signals()) + return NULL; +#endif + + try_(a) { + if (!xt_set_key(thr_key, self, &self->t_exception)) + throw_(); + td->td_started = TRUE; + return_data = (*start_routine)(self); + } + catch_(a) { + xt_log_and_clear_exception(self); + } + cont_(a); + + outer_(); + xt_free_thread(self); + return return_data; +} + +static void thr_free_data(XTThreadPtr self) +{ + if (self->t_free_data) { + (*self->t_free_data)(self, self->t_data); + self->t_data = NULL; + } +} + +xtPublic void xt_set_thread_data(XTThreadPtr self, void *data, XTThreadFreeFunc free_func) +{ + thr_free_data(self); + self->t_free_data = free_func; + self->t_data = data; +} + +static void thr_exit(XTThreadPtr self) +{ + /* Free the thread temporary data. */ + thr_free_resources(self, (XTResourcePtr) self->x.t_res_stack); + xt_db_exit_thread(self); + thr_free_data(self); /* Free custom user data. */ + + if (self->t_id > 0) { + ASSERT(self->t_id < xt_thr_current_max_threads); + xt_lock_mutex(self, &thr_array_lock); + pushr_(xt_unlock_mutex, &thr_array_lock); + thr_accumulate_statistics(self); + xt_thr_array[self->t_id] = NULL; + xt_thr_current_thread_count--; + if (self->t_id+1 == xt_thr_current_max_threads) { + /* We can reduce the current maximum, + * this makes operations that scan the array faster! + */ + u_int i; + + i = self->t_id; + for(;;) { + if (xt_thr_array[i]) + break; + if (!i) + break; + i--; + } + xt_thr_current_max_threads = i+1; + } + freer_(); // xt_unlock_mutex(&thr_array_lock) + } + + xt_free_cond(&self->t_cond); + xt_free_mutex(&self->t_lock); + + self->st_thread_list_count = 0; + self->st_thread_list_size = 0; + if (self->st_thread_list) { + xt_free_ns(self->st_thread_list); + self->st_thread_list = NULL; + } +} + +static void thr_init(XTThreadPtr self, XTThreadPtr new_thread) +{ + new_thread->t_res_top = (XTResourcePtr) new_thread->x.t_res_stack; + + new_thread->st_thread_list_count = 0; + new_thread->st_thread_list_size = 0; + new_thread->st_thread_list = NULL; + try_(a) { + xt_init_cond(self, &new_thread->t_cond); + xt_init_mutex_with_autoname(self, &new_thread->t_lock); + + xt_lock_mutex(self, &thr_array_lock); + pushr_(xt_unlock_mutex, &thr_array_lock); + + ASSERT(xt_thr_current_thread_count <= xt_thr_current_max_threads); + ASSERT(xt_thr_current_max_threads <= xt_thr_maximum_threads); + if (xt_thr_current_thread_count == xt_thr_maximum_threads) + xt_throw_ulxterr(XT_CONTEXT, XT_ERR_TOO_MANY_THREADS, (u_long) xt_thr_maximum_threads+1); + if (xt_thr_current_thread_count == xt_thr_current_max_threads) { + new_thread->t_id = xt_thr_current_thread_count; + xt_thr_array[new_thread->t_id] = new_thread; + xt_thr_current_max_threads++; + } + else { + /* There must be a free slot: */ + for (u_int i=0; i<xt_thr_current_max_threads; i++) { + if (!xt_thr_array[i]) { + new_thread->t_id = i; + xt_thr_array[i] = new_thread; + break; + } + } + } + xt_thr_current_thread_count++; + freer_(); // xt_unlock_mutex(&thr_array_lock) + + xt_db_init_thread(self, new_thread); + } + catch_(a) { + thr_exit(new_thread); + throw_(); + } + cont_(a); + +} + +/* + * The caller of this function automatically becomes the main thread. + */ +xtPublic XTThreadPtr xt_init_threading(u_int max_threads) +{ + volatile XTThreadPtr self = NULL; + XTExceptionRec e; + int err; + + /* Align the number of threads: */ + xt_thr_maximum_threads = xt_align_size(max_threads, XT_XS_LOCK_ALIGN); + +#ifdef HANDLE_SIGNALS + if (!thr_setup_signals()) + return NULL; +#endif + + xt_p_init_threading(); + + err = pthread_key_create(&thr_key, NULL); + if (err) { + xt_log_errno(XT_NS_CONTEXT, err); + return NULL; + } + + if ((err = xt_p_mutex_init_with_autoname(&thr_array_lock, NULL))) { + xt_log_errno(XT_NS_CONTEXT, err); + goto failed; + } + + if (!(xt_thr_array = (XTThreadPtr *) malloc(xt_thr_maximum_threads * sizeof(XTThreadPtr)))) { + xt_log_errno(XT_NS_CONTEXT, XT_ENOMEM); + goto failed; + } + + xt_thr_array[0] = (XTThreadPtr) 1; // Dummy, not used + xt_thr_current_thread_count = 1; + xt_thr_current_max_threads = 1; + + /* Create the main thread: */ + self = xt_create_thread("MainThread", TRUE, FALSE, &e); + if (!self) { + xt_log_exception(NULL, &e, XT_LOG_DEFAULT); + goto failed; + } + + try_(a) { + XTThreadPtr thread = self; + thr_list = xt_new_linkedlist(thread, NULL, NULL, TRUE); + } + catch_(a) { + XTThreadPtr thread = self; + xt_log_and_clear_exception(thread); + xt_exit_threading(thread); + } + cont_(a); + + return self; + + failed: + xt_exit_threading(NULL); + return NULL; +} + +xtPublic void xt_exit_threading(XTThreadPtr self) +{ + if (thr_list) { + xt_free_linkedlist(self, thr_list); + thr_list = NULL; + } + + /* This should be the main thread! */ + if (self) { + ASSERT(self->t_main); + xt_free_thread(self); + } + + if (xt_thr_array) { + free(xt_thr_array); + xt_thr_array = NULL; + xt_free_mutex(&thr_array_lock); + } + + xt_thr_current_thread_count = 0; + xt_thr_current_max_threads = 0; + + /* I no longer delete 'thr_key' because + * functions that call xt_get_self() after this + * point will get junk back if we delete + * thr_key. In particular the XT_THREAD_LOCK_INFO + * code fails + if (thr_key) { + pthread_key_delete(thr_key); + thr_key = (pthread_key_t) 0; + } + */ +} + +xtPublic void xt_wait_for_all_threads(XTThreadPtr self) +{ + if (thr_list) + xt_ll_wait_till_empty(self, thr_list); +} + +/* + * Call this function in a busy wait loop! + * Use if for wait loops that are not + * time critical. + */ +xtPublic void xt_busy_wait(void) +{ +#ifdef XT_WIN + Sleep(1); +#else + usleep(10); +#endif +} + +xtPublic void xt_critical_wait(void) +{ + /* NOTE: On Mac xt_busy_wait() works better than xt_yield() + */ +#if defined(XT_MAC) || defined(XT_WIN) + xt_busy_wait(); +#else + xt_yield(); +#endif +} + + +/* + * Use this for loops that time critical. + * Time critical means we need to get going + * as soon as possible! + */ +xtPublic void xt_yield(void) +{ +#ifdef XT_WIN + Sleep(0); +#elif defined(XT_MAC) || defined(XT_SOLARIS) + usleep(0); +#elif defined(XT_NETBSD) + sched_yield(); +#else + pthread_yield(); +#endif +} + +xtPublic void xt_sleep_milli_second(u_int t) +{ +#ifdef XT_WIN + Sleep(t); +#else + usleep(t * 1000); +#endif +} + +xtPublic void xt_signal_all_threads(XTThreadPtr self, int sig) +{ + XTLinkedItemPtr li; + XTThreadPtr sig_thr; + + xt_ll_lock(self, thr_list); + try_(a) { + li = thr_list->ll_items; + while (li) { + sig_thr = (XTThreadPtr) li; + if (sig_thr != self) + pthread_kill(sig_thr->t_pthread, sig); + li = li->li_next; + } + } + catch_(a) { + xt_ll_unlock(self, thr_list); + throw_(); + } + cont_(a); + xt_ll_unlock(self, thr_list); +} + +/* + * Apply the given function to all threads except self! + */ +xtPublic void xt_do_to_all_threads(XTThreadPtr self, void (*do_func_ptr)(XTThreadPtr self, XTThreadPtr to_thr, void *thunk), void *thunk) +{ + XTLinkedItemPtr li; + XTThreadPtr to_thr; + + xt_ll_lock(self, thr_list); + pushr_(xt_ll_unlock, thr_list); + + li = thr_list->ll_items; + while (li) { + to_thr = (XTThreadPtr) li; + if (to_thr != self) + (*do_func_ptr)(self, to_thr, thunk); + li = li->li_next; + } + + freer_(); // xt_ll_unlock(thr_list) +} + +xtPublic XTThreadPtr xt_get_self(void) +{ + XTThreadPtr self; + + /* First check if the handler has the data: */ + if ((self = myxt_get_self())) + return self; + /* Then it must be a background process, and the + * thread info is stored in the local key: */ + return (XTThreadPtr) xt_get_key(thr_key); +} + +xtPublic void xt_set_self(XTThreadPtr self) +{ + xt_set_key(thr_key, self, NULL); +} + +xtPublic void xt_clear_exception(XTThreadPtr thread) +{ + thread->t_exception.e_xt_err = 0; + thread->t_exception.e_sys_err = 0; + *thread->t_exception.e_err_msg = 0; + *thread->t_exception.e_func_name = 0; + *thread->t_exception.e_source_file = 0; + thread->t_exception.e_source_line = 0; + *thread->t_exception.e_catch_trace = 0; +} + +/* + * Create a thread without requiring thread to do it (as in xt_create_daemon()). + * + * This function returns NULL on error. + */ +xtPublic XTThreadPtr xt_create_thread(c_char *name, xtBool main_thread, xtBool user_thread, XTExceptionPtr e) +{ + volatile XTThreadPtr self; + + self = (XTThreadPtr) xt_calloc_ns(sizeof(XTThreadRec)); + if (!self) { + xt_exception_errno(e, XT_CONTEXT, ENOMEM); + return NULL; + } + + if (!xt_set_key(thr_key, self, e)) { + xt_free_ns(self); + return NULL; + } + + xt_strcpy(XT_THR_NAME_SIZE, self->t_name, name); + self->t_main = main_thread; + self->t_daemon = FALSE; + + try_(a) { + thr_init(self, self); + } + catch_(a) { + *e = self->t_exception; + xt_set_key(thr_key, NULL, NULL); + xt_free_ns(self); + self = NULL; + } + cont_(a); + + if (self && user_thread) { + /* Add non-temporary threads to the thread list. */ + try_(b) { + xt_ll_add(self, thr_list, &self->t_links, TRUE); + } + catch_(b) { + *e = self->t_exception; + xt_free_thread(self); + self = NULL; + } + cont_(b); + } + + return self; +} + +/* + * Create a daemon thread. + */ +xtPublic XTThreadPtr xt_create_daemon(XTThreadPtr self, c_char *name) +{ + XTThreadPtr new_thread; + + /* NOTE: thr_key will be set when this thread start running. */ + + new_thread = (XTThreadPtr) xt_calloc(self, sizeof(XTThreadRec)); + xt_strcpy(XT_THR_NAME_SIZE, new_thread->t_name, name); + new_thread->t_main = FALSE; + new_thread->t_daemon = TRUE; + + try_(a) { + thr_init(self, new_thread); + } + catch_(a) { + xt_free(self, new_thread); + throw_(); + } + cont_(a); + return new_thread; +} + +void xt_free_thread(XTThreadPtr self) +{ + thr_exit(self); + if (!self->t_daemon && thr_list) + xt_ll_remove(self, thr_list, &self->t_links, TRUE); + /* Note, if I move this before thr_exit() then self = xt_get_self(); will fail in + * xt_close_file_ns() which is called by xt_unuse_database()! + */ + + /* + * Do not clear the pthread's key value unless it is the same as the thread just released. + * This can happen during shutdown when the engine is deregistered with the PBMS engine. + * + * What happens is that during deregistration the PBMS engine calls close to close all + * PBXT resources on all MySQL THDs created by PBMS for it's own pthreads. So the 'self' + * being freed is not the same 'self' associated with the PBXT 'thr_key'. + */ + if (thr_key && (self == ((XTThreadPtr) xt_get_key(thr_key)))) { + xt_set_key(thr_key, NULL, NULL); + } + xt_free_ns(self); +} + +xtPublic pthread_t xt_run_thread(XTThreadPtr self, XTThreadPtr child, void *(*start_routine)(XTThreadPtr)) +{ + ThreadDataRec data; + int err; + pthread_t child_thread; + + enter_(); + + // 'data' can be on the stack because we are waiting for the thread to start + // before exiting the function. + data.td_started = FALSE; + data.td_thr = child; + data.td_start_routine = start_routine; +#ifdef XT_WIN + { + pthread_attr_t attr = { 0, 0, 0 }; + + attr.priority = THREAD_PRIORITY_NORMAL; + err = pthread_create(&child_thread, &attr, thr_main, &data); + } +#else + err = pthread_create(&child_thread, NULL, thr_main, &data); +#endif + if (err) { + xt_free_thread(child); + xt_throw_errno(XT_CONTEXT, err); + } + while (!data.td_started) { + /* Check that the self is still alive: */ + if (pthread_kill(child_thread, 0)) + break; + xt_busy_wait(); + } + return_(child_thread); +} + +xtPublic void xt_exit_thread(XTThreadPtr self, void *result) +{ + xt_free_thread(self); + pthread_exit(result); +} + +xtPublic void *xt_wait_for_thread(xtThreadID tid, xtBool ignore_error) +{ + int err; + void *value_ptr = NULL; + xtBool ok = FALSE; + XTThreadPtr thread; + pthread_t t1 = 0; + + xt_lock_mutex_ns(&thr_array_lock); + if (tid < xt_thr_maximum_threads) { + if ((thread = xt_thr_array[tid])) { + t1 = thread->t_pthread; + ok = TRUE; + } + } + xt_unlock_mutex_ns(&thr_array_lock); + if (ok) { + err = xt_p_join(t1, &value_ptr); + if (err && !ignore_error) + xt_log_errno(XT_NS_CONTEXT, err); + } + return value_ptr; +} + +/* + * Kill the given thead, and wait for it to terminate. + * This function just returns if the self is already dead. + */ +xtPublic void xt_kill_thread(pthread_t t1) +{ + int err; + void *value_ptr = NULL; + + err = pthread_kill(t1, SIGTERM); + if (err) + return; + err = xt_p_join(t1, &value_ptr); + if (err) + xt_log_errno(XT_NS_CONTEXT, err); +} + +/* + * ----------------------------------------------------------------------- + * Read/write locking + */ + +#ifdef XT_THREAD_LOCK_INFO +xtPublic xtBool xt_init_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock, const char *name) +#else +xtPublic xtBool xt_init_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock) +#endif +{ + int err; + +#ifdef XT_THREAD_LOCK_INFO + err = xt_p_rwlock_init_with_name(rwlock, NULL, name); +#else + err = xt_p_rwlock_init(rwlock, NULL); +#endif + + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return FAILED; + } + return OK; +} + +xtPublic void xt_free_rwlock(xt_rwlock_type *rwlock) +{ + int err; + + for (;;) { + err = xt_p_rwlock_destroy(rwlock); + if (err != XT_EBUSY) + break; + xt_busy_wait(); + } + /* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed! + * This generates a lot of log entries. But I have no desire to only call + * free for those articles that I have init'ed! + if (err) + xt_log_errno(XT_NS_CONTEXT, err); + */ +} + +xtPublic xt_rwlock_type *xt_slock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock) +{ + int err; + + for (;;) { + err = xt_slock_rwlock_ns(rwlock); + if (err != XT_EAGAIN) + break; + xt_busy_wait(); + } + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return NULL; + } + return rwlock; +} + +xtPublic xt_rwlock_type *xt_xlock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock) +{ + int err; + + for (;;) { + err = xt_xlock_rwlock_ns(rwlock); + if (err != XT_EAGAIN) + break; + xt_busy_wait(); + } + + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return NULL; + } + return rwlock; +} + +xtPublic void xt_unlock_rwlock(XTThreadPtr XT_UNUSED(self), xt_rwlock_type *rwlock) +{ + int err; + + err = xt_unlock_rwlock_ns(rwlock); + if (err) + xt_log_errno(XT_NS_CONTEXT, err); +} + +/* + * ----------------------------------------------------------------------- + * Mutex locking + */ + +xtPublic xt_mutex_type *xt_new_mutex(XTThreadPtr self) +{ + xt_mutex_type *mx; + + if (!(mx = (xt_mutex_type *) xt_calloc(self, sizeof(xt_mutex_type)))) + return NULL; + pushr_(xt_free, mx); + if (!xt_init_mutex_with_autoname(self, mx)) { + freer_(); + return NULL; + } + popr_(); + return mx; +} + +xtPublic void xt_delete_mutex(XTThreadPtr self, xt_mutex_type *mx) +{ + if (mx) { + xt_free_mutex(mx); + xt_free(self, mx); + } +} + +#ifdef XT_THREAD_LOCK_INFO +xtPublic xtBool xt_init_mutex(XTThreadPtr self, xt_mutex_type *mx, const char *name) +#else +xtPublic xtBool xt_init_mutex(XTThreadPtr self, xt_mutex_type *mx) +#endif +{ + int err; + + err = xt_p_mutex_init_with_name(mx, NULL, name); + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return FALSE; + } + return TRUE; +} + +void xt_free_mutex(xt_mutex_type *mx) +{ + int err; + + for (;;) { + err = xt_p_mutex_destroy(mx); + if (err != XT_EBUSY) + break; + xt_busy_wait(); + } + /* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed! + if (err) + xt_log_errno(XT_NS_CONTEXT, err); + */ +} + +xtPublic xtBool xt_lock_mutex(XTThreadPtr self, xt_mutex_type *mx) +{ + int err; + + for (;;) { + err = xt_lock_mutex_ns(mx); + if (err != XT_EAGAIN) + break; + xt_busy_wait(); + } + + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return FALSE; + } + return TRUE; +} + +xtPublic void xt_unlock_mutex(XTThreadPtr self, xt_mutex_type *mx) +{ + int err; + + err = xt_unlock_mutex_ns(mx); + if (err) + xt_throw_errno(XT_CONTEXT, err); +} + +xtPublic xtBool xt_set_key(pthread_key_t key, const void *value, XTExceptionPtr e) +{ +#ifdef XT_WIN + my_pthread_setspecific_ptr(thr_key, (void *) value); +#else + int err; + + err = pthread_setspecific(key, value); + if (err) { + if (e) + xt_exception_errno(e, XT_NS_CONTEXT, err); + return FALSE; + } +#endif + return TRUE; +} + +xtPublic void *xt_get_key(pthread_key_t key) +{ +#ifdef XT_WIN + return my_pthread_getspecific_ptr(void *, thr_key); +#else + return pthread_getspecific(key); +#endif +} + +xtPublic xt_cond_type *xt_new_cond(XTThreadPtr self) +{ + xt_cond_type *cond; + + if (!(cond = (xt_cond_type *) xt_calloc(self, sizeof(xt_cond_type)))) + return NULL; + pushr_(xt_free, cond); + if (!xt_init_cond(self, cond)) { + freer_(); + return NULL; + } + popr_(); + return cond; +} + +xtPublic void xt_delete_cond(XTThreadPtr self, xt_cond_type *cond) +{ + if (cond) { + xt_free_cond(cond); + xt_free(self, cond); + } +} + +xtPublic xtBool xt_init_cond(XTThreadPtr self, xt_cond_type *cond) +{ + int err; + + err = pthread_cond_init(cond, NULL); + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return FALSE; + } + return TRUE; +} + +xtPublic void xt_free_cond(xt_cond_type *cond) +{ + int err; + + for (;;) { + err = pthread_cond_destroy(cond); + if (err != XT_EBUSY) + break; + xt_busy_wait(); + } + /* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed! + if (err) + xt_log_errno(XT_NS_CONTEXT, err); + */ +} + +xtPublic xtBool xt_throw_delayed_signal(XTThreadPtr self, c_char *func, c_char *file, u_int line) +{ + XTThreadPtr me = self ? self : xt_get_self(); + + if (me->t_delayed_signal) { + int sig = me->t_delayed_signal; + + me->t_delayed_signal = 0; + xt_throw_signal(self, func, file, line, sig); + return FAILED; + } + return OK; +} + +xtPublic xtBool xt_wait_cond(XTThreadPtr self, xt_cond_type *cond, xt_mutex_type *mutex) +{ + int err; + XTThreadPtr me = self ? self : xt_get_self(); + + /* PMC - In my tests, if I throw an exception from within the wait + * the condition and the mutex remain locked. + */ + me->t_disable_interrupts = TRUE; + err = xt_p_cond_wait(cond, mutex); + me->t_disable_interrupts = FALSE; + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return FALSE; + } + if (me->t_delayed_signal) { + xt_throw_delayed_signal(XT_CONTEXT); + return FALSE; + } + return TRUE; +} + +xtPublic xtBool xt_suspend(XTThreadPtr thread) +{ + xtBool ok; + + // You can only suspend yourself. + ASSERT_NS(pthread_equal(thread->t_pthread, pthread_self())); + + xt_lock_mutex_ns(&thread->t_lock); + ok = xt_wait_cond(NULL, &thread->t_cond, &thread->t_lock); + xt_unlock_mutex_ns(&thread->t_lock); + return ok; +} + +xtPublic xtBool xt_unsuspend(XTThreadPtr target) +{ + return xt_broadcast_cond_ns(&target->t_cond); +} + +xtPublic void xt_lock_thread(XTThreadPtr thread) +{ + xt_lock_mutex_ns(&thread->t_lock); +} + +xtPublic void xt_unlock_thread(XTThreadPtr thread) +{ + xt_unlock_mutex_ns(&thread->t_lock); +} + +xtPublic xtBool xt_wait_thread(XTThreadPtr thread) +{ + return xt_wait_cond(NULL, &thread->t_cond, &thread->t_lock); +} + +xtPublic void xt_signal_thread(XTThreadPtr target) +{ + xt_broadcast_cond_ns(&target->t_cond); +} + +xtPublic void xt_terminate_thread(XTThreadPtr self __attribute__((unused)), XTThreadPtr target) +{ + target->t_quit = TRUE; + target->t_delayed_signal = SIGTERM; +} + +xtPublic xtProcID xt_getpid() +{ +#ifdef XT_WIN + return GetCurrentProcessId(); +#else + return getpid(); +#endif +} + +xtPublic xtBool xt_process_exists(xtProcID pid) +{ + xtBool found; + +#ifdef XT_WIN + HANDLE h; + DWORD code; + + found = FALSE; + h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + if (h) { + if (GetExitCodeProcess(h, &code)) { + if (code == STILL_ACTIVE) + found = TRUE; + } + CloseHandle(h); + } + else { + int err; + + err = HRESULT_CODE(GetLastError()); + if (err != ERROR_INVALID_PARAMETER) + found = TRUE; + } +#else + found = TRUE; + if (kill(pid, 0) == -1) { + if (errno == ESRCH) + found = FALSE; + } +#endif + return found; +} + +xtPublic xtBool xt_timed_wait_cond(XTThreadPtr self, xt_cond_type *cond, xt_mutex_type *mutex, u_long milli_sec) +{ + int err; + struct timespec abstime; + XTThreadPtr me = self ? self : xt_get_self(); + +#ifdef XT_WIN + union ft64 now; + + GetSystemTimeAsFileTime(&now.ft); + + /* System time is measured in 100ns units. + * This calculation will be reversed by the Windows implementation + * of pthread_cond_timedwait(), in order to extract the + * milli-second timeout! + */ + abstime.tv.i64 = now.i64 + (milli_sec * 10000); + + abstime.max_timeout_msec = milli_sec; +#else + struct timeval now; + u_llong micro_sec; + + /* Get the current time in microseconds: */ + gettimeofday(&now, NULL); + micro_sec = (u_llong) now.tv_sec * (u_llong) 1000000 + (u_llong) now.tv_usec; + + /* Add the timeout which is in milli seconds */ + micro_sec += (u_llong) milli_sec * (u_llong) 1000; + + /* Setup the end time, which is in nano-seconds. */ + abstime.tv_sec = (long) (micro_sec / 1000000); /* seconds */ + abstime.tv_nsec = (long) ((micro_sec % 1000000) * 1000); /* and nanoseconds */ +#endif + + me->t_disable_interrupts = TRUE; + err = xt_p_cond_timedwait(cond, mutex, &abstime); + me->t_disable_interrupts = FALSE; + if (err && err != ETIMEDOUT) { + xt_throw_errno(XT_CONTEXT, err); + return FALSE; + } + if (me->t_delayed_signal) { + xt_throw_delayed_signal(XT_CONTEXT); + return FALSE; + } + return TRUE; +} + +xtPublic xtBool xt_signal_cond(XTThreadPtr self, xt_cond_type *cond) +{ + int err; + + err = pthread_cond_signal(cond); + if (err) { + xt_throw_errno(XT_CONTEXT, err); + return FAILED; + } + return OK; +} + +xtPublic void xt_broadcast_cond(XTThreadPtr self, xt_cond_type *cond) +{ + int err; + + err = pthread_cond_broadcast(cond); + if (err) + xt_throw_errno(XT_CONTEXT, err); +} + +xtPublic xtBool xt_broadcast_cond_ns(xt_cond_type *cond) +{ + int err; + + err = pthread_cond_broadcast(cond); + if (err) { + xt_register_errno(XT_REG_CONTEXT, err); + return FAILED; + } + return OK; +} + +static int prof_setjmp_count = 0; + +xtPublic int prof_setjmp(void) +{ + prof_setjmp_count++; + return 0; +} + +xtPublic void xt_set_low_priority(XTThreadPtr self) +{ + int err = xt_p_set_low_priority(self->t_pthread); + if (err) { + self = NULL; /* Will cause logging, instead of throwing exception */ + xt_throw_errno(XT_CONTEXT, err); + } +} + +xtPublic void xt_set_normal_priority(XTThreadPtr self) +{ + int err = xt_p_set_normal_priority(self->t_pthread); + if (err) { + self = NULL; /* Will cause logging, instead of throwing exception */ + xt_throw_errno(XT_CONTEXT, err); + } +} + +xtPublic void xt_set_high_priority(XTThreadPtr self) +{ + int err = xt_p_set_high_priority(self->t_pthread); + if (err) { + self = NULL; /* Will cause logging, instead of throwing exception */ + xt_throw_errno(XT_CONTEXT, err); + } +} + +xtPublic void xt_set_priority(XTThreadPtr self, int priority) +{ + if (priority < XT_PRIORITY_NORMAL) + xt_set_low_priority(self); + else if (priority > XT_PRIORITY_NORMAL) + xt_set_high_priority(self); + else + xt_set_normal_priority(self); +} + +/* + * ----------------------------------------------------------------------- + * STATISTICS + */ + +xtPublic void xt_gather_statistics(XTStatisticsPtr stats) +{ + XTThreadPtr *thr; + xtWord8 s; + + xt_lock_mutex_ns(&thr_array_lock); + *stats = thr_statistics; + // Ignore index 0, it is not used! + thr = &xt_thr_array[1]; + for (u_int i=1; i<xt_thr_current_max_threads; i++) { + if (*thr) { + stats->st_commits += (*thr)->st_statistics.st_commits; + stats->st_rollbacks += (*thr)->st_statistics.st_rollbacks; + stats->st_stat_read += (*thr)->st_statistics.st_stat_read; + stats->st_stat_write += (*thr)->st_statistics.st_stat_write; + + XT_ADD_STATS(stats->st_rec, (*thr)->st_statistics.st_rec); + if ((s = (*thr)->st_statistics.st_rec.ts_flush_start)) + stats->st_rec.ts_flush_time += xt_trace_clock() - s; + stats->st_rec_cache_hit += (*thr)->st_statistics.st_rec_cache_hit; + stats->st_rec_cache_miss += (*thr)->st_statistics.st_rec_cache_miss; + stats->st_rec_cache_frees += (*thr)->st_statistics.st_rec_cache_frees; + + XT_ADD_STATS(stats->st_ind, (*thr)->st_statistics.st_ind); + if ((s = (*thr)->st_statistics.st_ind.ts_flush_start)) + stats->st_ind.ts_flush_time += xt_trace_clock() - s; + stats->st_ind_cache_hit += (*thr)->st_statistics.st_ind_cache_hit; + stats->st_ind_cache_miss += (*thr)->st_statistics.st_ind_cache_miss; + XT_ADD_STATS(stats->st_ilog, (*thr)->st_statistics.st_ilog); + + XT_ADD_STATS(stats->st_xlog, (*thr)->st_statistics.st_xlog); + if ((s = (*thr)->st_statistics.st_xlog.ts_flush_start)) + stats->st_xlog.ts_flush_time += xt_trace_clock() - s; + stats->st_xlog_cache_hit += (*thr)->st_statistics.st_xlog_cache_hit; + stats->st_xlog_cache_miss += (*thr)->st_statistics.st_xlog_cache_miss; + + XT_ADD_STATS(stats->st_data, (*thr)->st_statistics.st_data); + if ((s = (*thr)->st_statistics.st_data.ts_flush_start)) + stats->st_data.ts_flush_time += xt_trace_clock() - s; + + stats->st_scan_index += (*thr)->st_statistics.st_scan_index; + stats->st_scan_table += (*thr)->st_statistics.st_scan_table; + stats->st_row_select += (*thr)->st_statistics.st_row_select; + stats->st_row_insert += (*thr)->st_statistics.st_row_insert; + stats->st_row_update += (*thr)->st_statistics.st_row_update; + stats->st_row_delete += (*thr)->st_statistics.st_row_delete; + + stats->st_wait_for_xact += (*thr)->st_statistics.st_wait_for_xact; + stats->st_retry_index_scan += (*thr)->st_statistics.st_retry_index_scan; + stats->st_reread_record_list += (*thr)->st_statistics.st_reread_record_list; + } + thr++; + } + xt_unlock_mutex_ns(&thr_array_lock); +} + +static void thr_accumulate_statistics(XTThreadPtr self) +{ + thr_statistics.st_commits += self->st_statistics.st_commits; + thr_statistics.st_rollbacks += self->st_statistics.st_rollbacks; + thr_statistics.st_stat_read += self->st_statistics.st_stat_read; + thr_statistics.st_stat_write += self->st_statistics.st_stat_write; + + XT_ADD_STATS(thr_statistics.st_rec, self->st_statistics.st_rec); + thr_statistics.st_rec_cache_hit += self->st_statistics.st_rec_cache_hit; + thr_statistics.st_rec_cache_miss += self->st_statistics.st_rec_cache_miss; + thr_statistics.st_rec_cache_frees += self->st_statistics.st_rec_cache_frees; + + XT_ADD_STATS(thr_statistics.st_ind, self->st_statistics.st_ind); + thr_statistics.st_ind_cache_hit += self->st_statistics.st_ind_cache_hit; + thr_statistics.st_ind_cache_miss += self->st_statistics.st_ind_cache_miss; + XT_ADD_STATS(thr_statistics.st_ilog, self->st_statistics.st_ilog); + + XT_ADD_STATS(thr_statistics.st_xlog, self->st_statistics.st_xlog); + thr_statistics.st_xlog_cache_hit += self->st_statistics.st_xlog_cache_hit; + thr_statistics.st_xlog_cache_miss += self->st_statistics.st_xlog_cache_miss; + + XT_ADD_STATS(thr_statistics.st_data, self->st_statistics.st_data); + + thr_statistics.st_scan_index += self->st_statistics.st_scan_index; + thr_statistics.st_scan_table += self->st_statistics.st_scan_table; + thr_statistics.st_row_select += self->st_statistics.st_row_select; + thr_statistics.st_row_insert += self->st_statistics.st_row_insert; + thr_statistics.st_row_update += self->st_statistics.st_row_update; + thr_statistics.st_row_delete += self->st_statistics.st_row_delete; + + thr_statistics.st_wait_for_xact += self->st_statistics.st_wait_for_xact; + thr_statistics.st_retry_index_scan += self->st_statistics.st_retry_index_scan; + thr_statistics.st_reread_record_list += self->st_statistics.st_reread_record_list; +} + +xtPublic u_llong xt_get_statistic(XTStatisticsPtr stats, XTDatabaseHPtr db, u_int rec_id) +{ + u_llong stat_value; + + switch (rec_id) { + case XT_STAT_TIME_CURRENT: + stat_value = (u_llong) time(NULL); + break; + case XT_STAT_TIME_PASSED: + stat_value = (u_llong) xt_trace_clock(); + break; + case XT_STAT_COMMITS: + stat_value = stats->st_commits; + break; + case XT_STAT_ROLLBACKS: + stat_value = stats->st_rollbacks; + break; + case XT_STAT_STAT_READS: + stat_value = stats->st_stat_read; + break; + case XT_STAT_STAT_WRITES: + stat_value = stats->st_stat_write; + break; + + case XT_STAT_REC_BYTES_IN: + stat_value = stats->st_rec.ts_read; + break; + case XT_STAT_REC_BYTES_OUT: + stat_value = stats->st_rec.ts_write; + break; + case XT_STAT_REC_SYNC_COUNT: + stat_value = stats->st_rec.ts_flush; + break; + case XT_STAT_REC_SYNC_TIME: + stat_value = stats->st_rec.ts_flush_time; + break; + case XT_STAT_REC_CACHE_HIT: + stat_value = stats->st_rec_cache_hit; + break; + case XT_STAT_REC_CACHE_MISS: + stat_value = stats->st_rec_cache_miss; + break; + case XT_STAT_REC_CACHE_FREES: + stat_value = stats->st_rec_cache_frees; + break; + case XT_STAT_REC_CACHE_USAGE: + stat_value = (u_llong) xt_tc_get_usage(); + break; + + case XT_STAT_IND_BYTES_IN: + stat_value = stats->st_ind.ts_read; + break; + case XT_STAT_IND_BYTES_OUT: + stat_value = stats->st_ind.ts_write; + break; + case XT_STAT_IND_SYNC_COUNT: + stat_value = stats->st_ind.ts_flush; + break; + case XT_STAT_IND_SYNC_TIME: + stat_value = stats->st_ind.ts_flush_time; + break; + case XT_STAT_IND_CACHE_HIT: + stat_value = stats->st_ind_cache_hit; + break; + case XT_STAT_IND_CACHE_MISS: + stat_value = stats->st_ind_cache_miss; + break; + case XT_STAT_IND_CACHE_USAGE: + stat_value = (u_llong) xt_ind_get_usage(); + break; + case XT_STAT_ILOG_BYTES_IN: + stat_value = stats->st_ilog.ts_read; + break; + case XT_STAT_ILOG_BYTES_OUT: + stat_value = stats->st_ilog.ts_write; + break; + case XT_STAT_ILOG_SYNC_COUNT: + stat_value = stats->st_ilog.ts_flush; + break; + case XT_STAT_ILOG_SYNC_TIME: + stat_value = stats->st_ilog.ts_flush_time; + break; + + case XT_STAT_XLOG_BYTES_IN: + stat_value = stats->st_xlog.ts_read; + break; + case XT_STAT_XLOG_BYTES_OUT: + stat_value = stats->st_xlog.ts_write; + break; + case XT_STAT_XLOG_SYNC_COUNT: + stat_value = stats->st_xlog.ts_flush; + break; + case XT_STAT_XLOG_SYNC_TIME: + stat_value = stats->st_xlog.ts_flush_time; + break; + case XT_STAT_XLOG_CACHE_HIT: + stat_value = stats->st_xlog_cache_hit; + break; + case XT_STAT_XLOG_CACHE_MISS: + stat_value = stats->st_xlog_cache_miss; + break; + case XT_STAT_XLOG_CACHE_USAGE: + stat_value = (u_llong) xt_xlog_get_usage(); + break; + + case XT_STAT_DATA_BYTES_IN: + stat_value = stats->st_data.ts_read; + break; + case XT_STAT_DATA_BYTES_OUT: + stat_value = stats->st_data.ts_write; + break; + case XT_STAT_DATA_SYNC_COUNT: + stat_value = stats->st_data.ts_flush; + break; + case XT_STAT_DATA_SYNC_TIME: + stat_value = stats->st_data.ts_flush_time; + break; + + case XT_STAT_BYTES_TO_CHKPNT: + stat_value = db ? xt_bytes_since_last_checkpoint(db, db->db_xlog.xl_write_log_id, db->db_xlog.xl_write_log_offset) : 0; + break; + case XT_STAT_LOG_BYTES_TO_WRITE: + stat_value = db ? db->db_xlog.xl_log_bytes_written - db->db_xlog.xl_log_bytes_read : 0;//db->db_xlog.xlog_bytes_to_write(); + break; + case XT_STAT_BYTES_TO_SWEEP: + /* This stat is potentially very expensive: */ + stat_value = db ? xt_xn_bytes_to_sweep(db, xt_get_self()) : 0; + break; + case XT_STAT_WAIT_FOR_XACT: + stat_value = stats->st_wait_for_xact; + break; + case XT_STAT_XACT_TO_CLEAN: + stat_value = db ? db->db_xn_curr_id + 1 - db->db_xn_to_clean_id : 0; + break; + case XT_STAT_SWEEPER_WAITS: + stat_value = db ? db->db_stat_sweep_waits : 0; + break; + + case XT_STAT_SCAN_INDEX: + stat_value = stats->st_scan_index; + break; + case XT_STAT_SCAN_TABLE: + stat_value = stats->st_scan_table; + break; + case XT_STAT_ROW_SELECT: + stat_value = stats->st_row_select; + break; + case XT_STAT_ROW_INSERT: + stat_value = stats->st_row_insert; + break; + case XT_STAT_ROW_UPDATE: + stat_value = stats->st_row_update; + break; + case XT_STAT_ROW_DELETE: + stat_value = stats->st_row_delete; + break; + + case XT_STAT_RETRY_INDEX_SCAN: + stat_value = stats->st_retry_index_scan; + break; + case XT_STAT_REREAD_REC_LIST: + stat_value = stats->st_reread_record_list; + break; + default: + stat_value = 0; + break; + } + return stat_value; +} diff --git a/storage/pbxt/src/thread_xt.h b/storage/pbxt/src/thread_xt.h new file mode 100644 index 00000000000..4344c5335b9 --- /dev/null +++ b/storage/pbxt/src/thread_xt.h @@ -0,0 +1,675 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-01-03 Paul McCullagh + * + * H&G2JCtL + */ + +#ifndef __xt_thread_h__ +#define __xt_thread_h__ + +#include <stdio.h> +#ifndef XT_WIN +#include <sys/param.h> +#endif +#include <setjmp.h> + +#include "xt_defs.h" +#include "xt_errno.h" +#include "linklist_xt.h" +#include "memory_xt.h" +#include "xactlog_xt.h" +#include "datalog_xt.h" +#include "lock_xt.h" +#include "locklist_xt.h" + +/* + * ----------------------------------------------------------------------- + * Macros and defines + */ + +#ifdef XT_WIN +#define __FUNC__ __FUNCTION__ +#elif defined(XT_SOLARIS) +#define __FUNC__ "__func__" +#else +#define __FUNC__ __PRETTY_FUNCTION__ +#endif + +#define XT_ERR_MSG_SIZE (PATH_MAX + 200) + +#ifdef DEBUG +#define ASSERT(expr) ((expr) ? TRUE : xt_assert(self, #expr, __FUNC__, __FILE__, __LINE__)) +#else +#define ASSERT(expr) ((void) 0) +#endif + +#ifdef DEBUG +#define ASSUME(expr) ((expr) ? TRUE : xt_assume(self, #expr, __FUNC__, __FILE__, __LINE__)) +#else +#define ASSUME(expr) ((void) 0) +#endif + +#ifdef DEBUG +#define ASSERT_NS(expr) ((expr) ? TRUE : xt_assert(NULL, #expr, __FUNC__, __FILE__, __LINE__)) +#else +#define ASSERT_NS(expr) ((void) 0) +#endif + +#define XT_THROW_ASSERTION(str) xt_throw_assertion(self, __FUNC__, __FILE__, __LINE__, str) + +/* Log levels */ +#define XT_LOG_DEFAULT -1 +#define XT_LOG_PROTOCOL 0 +#define XT_LOG_FATAL 1 +#define XT_LOG_ERROR 2 +#define XT_LOG_WARNING 3 +#define XT_LOG_INFO 4 +#define XT_LOG_TRACE 5 + +#define XT_PROTOCOL self, "", NULL, 0, XT_LOG_PROTOCOL +#define XT_WARNING self, "", NULL, 0, XT_LOG_WARNING +#define XT_INFO self, "", NULL, 0, XT_LOG_INFO +#define XT_ERROR self, "", NULL, 0, XT_LOG_ERROR +#define XT_TRACE self, "", NULL, 0, XT_LOG_TRACE + +#define XT_NT_PROTOCOL NULL, "", NULL, 0, XT_LOG_PROTOCOL +#define XT_NT_WARNING NULL, "", NULL, 0, XT_LOG_WARNING +#define XT_NT_INFO NULL, "", NULL, 0, XT_LOG_INFO +#define XT_NT_ERROR NULL, "", NULL, 0, XT_LOG_ERROR +#define XT_NT_TRACE NULL, "", NULL, 0, XT_LOG_TRACE + +#define XT_ERROR_CONTEXT(func) self, __FUNC__, __FILE__, __LINE__, XT_LOG_ERROR + +/* Thread types */ +#define XT_THREAD_MAIN 0 +#define XT_THREAD_WORKER 1 + +/* Thread Priorities: */ +#define XT_PRIORITY_LOW 0 +#define XT_PRIORITY_NORMAL 1 +#define XT_PRIORITY_HIGH 2 + +#define XT_CONTEXT self, __FUNC__, __FILE__, __LINE__ +#define XT_NS_CONTEXT NULL, __FUNC__, __FILE__, __LINE__ +#define XT_REG_CONTEXT __FUNC__, __FILE__, __LINE__ + +#define XT_MAX_JMP 20 +#define XT_MAX_CALL_STACK 100 /* The number of functions recorded by enter_() and exit() */ +#define XT_RES_STACK_SIZE 4000 /* The size of the stack resource stack in bytes. */ +#define XT_MAX_RESOURCE_USAGE 5 /* The maximum number of temp slots used per routine. */ +#define XT_CATCH_TRACE_SIZE 1024 +#define XT_MAX_FUNC_NAME_SIZE 120 +#define XT_SOURCE_FILE_NAME_SIZE 40 +#define XT_THR_NAME_SIZE 80 + +#ifdef XT_THREAD_LOCK_INFO +#define xt_init_rwlock_with_autoname(a,b) xt_init_rwlock(a,b,LOCKLIST_ARG_SUFFIX(b)) +#else +#define xt_init_rwlock_with_autoname(a,b) xt_init_rwlock(a,b) +#endif + +typedef struct XTException { + int e_xt_err; /* The XT error number (ALWAYS non-zero on error, else zero) */ + int e_sys_err; /* The system error number (0 if none) */ + char e_err_msg[XT_ERR_MSG_SIZE]; /* The error message text (0 terminated string) */ + char e_func_name[XT_MAX_FUNC_NAME_SIZE]; /* The name of the function in which the exception occurred */ + char e_source_file[XT_SOURCE_FILE_NAME_SIZE]; /* The source file in which the exception was thrown */ + u_int e_source_line; /* The source code line number on which the exception was thrown */ + char e_catch_trace[XT_CATCH_TRACE_SIZE]; /* A string of the catch trace. */ +} XTExceptionRec, *XTExceptionPtr; + +struct XTThread; +struct XTSortedList; +struct XTXactLog; +struct XTXactData; +struct XTDatabase; + +typedef void (*XTThreadFreeFunc)(struct XTThread *self, void *data); + +typedef struct XTResourceArgs { + void *ra_p1; + xtWord4 ra_p2; +} XTResourceArgsRec, *XTResourceArgsPtr; + +/* This structure represents a temporary resource on the resource stack. + * Resource are automatically freed if an exception occurs. + */ +typedef struct XTResource { + xtWord4 r_prev_size; /* The size of the previous resource on the stack (must be first!) */ + void *r_data; /* A pointer to the resource data (this may be on the resource stack) */ + XTThreadFreeFunc r_free_func; /* The function used to free the resource. */ +} XTResourceRec, *XTResourcePtr; + +typedef struct XTJumpBuf { + XTResourcePtr jb_res_top; + int jb_call_top; + jmp_buf jb_buffer; +} XTJumpBufRec, *XTJumpBufPtr; + +typedef struct XTCallStack { + c_char *cs_func; + c_char *cs_file; + u_int cs_line; +} XTCallStackRec, *XTCallStackPtr; + +typedef struct XTIOStats { + u_int ts_read; /* The number of bytes read. */ + u_int ts_write; /* The number of bytes written. */ + xtWord8 ts_flush_time; /* The accumulated flush time. */ + xtWord8 ts_flush_start; /* Start time, non-zero if a timer is running. */ + u_int ts_flush; /* The number of flush operations. */ +} XTIOStatsRec, *XTIOStatsPtr; + +#define XT_ADD_STATS(x, y) { \ + (x).ts_read += (y).ts_read; \ + (x).ts_write += (y).ts_write; \ + (x).ts_flush_time += (y).ts_flush_time; \ + (x).ts_flush += (y).ts_flush; \ +} + +typedef struct XTStatistics { + u_int st_commits; + u_int st_rollbacks; + u_int st_stat_read; + u_int st_stat_write; + + XTIOStatsRec st_rec; + u_int st_rec_cache_hit; + u_int st_rec_cache_miss; + u_int st_rec_cache_frees; + + XTIOStatsRec st_ind; + u_int st_ind_cache_hit; + u_int st_ind_cache_miss; + XTIOStatsRec st_ilog; + + XTIOStatsRec st_xlog; + u_int st_xlog_cache_hit; + u_int st_xlog_cache_miss; + + XTIOStatsRec st_data; + + XTIOStatsRec st_x; + + u_int st_scan_index; + u_int st_scan_table; + u_int st_row_select; + u_int st_row_insert; + u_int st_row_update; + u_int st_row_delete; + + u_int st_wait_for_xact; + u_int st_retry_index_scan; + u_int st_reread_record_list; + XTIOStatsRec st_ind_flush_time; +} XTStatisticsRec, *XTStatisticsPtr; + +/* + * PBXT supports COMMITTED READ and REPEATABLE READ. + * + * As Jim says, multi-versioning cannot implement SERIALIZABLE. Basically + * you need locking to do this. Although phantom reads do not occur with + * MVCC, it is still not serializable. + * + * This can be seen from the following example: + * + * T1: INSERT t1 VALUE (1, 1); + * T2: INSERT t1 VALUE (2, 2); + * T1: UPDATE t1 SET b = 3 WHERE a IN (1, 2); + * T2: UPDATE t1 SET b = 4 WHERE a IN (1, 2); + * Serialized result (T1, T2) or (T2, T1): + * a b or a b + * 1 4 1 3 + * 2 4 1 3 + * Non-serialized (MVCC) result: + * a b + * 1 3 + * 2 4 + */ +#define XT_XACT_UNCOMMITTED_READ 0 +#define XT_XACT_COMMITTED_READ 1 +#define XT_XACT_REPEATABLE_READ 2 /* Guarentees rows already read will not change. */ +#define XT_XACT_SERIALIZABLE 3 + +typedef struct XTThread { + XTLinkedItemRec t_links; /* Required to be a member of a double-linked list. */ + + char t_name[XT_THR_NAME_SIZE]; /* The name of the thread. */ + xtBool t_main; /* TRUE if this is the main (initial) thread */ + xtBool t_quit; /* TRUE if this thread should stop running. */ + xtBool t_daemon; /* TRUE if this thread is a daemon. */ + xtThreadID t_id; /* The thread ID (0=main), index into thread array. */ + pthread_t t_pthread; /* The pthread associated with xt thread */ + xtBool t_disable_interrupts; /* TRUE if interrupts are disabled. */ + int t_delayed_signal; /* Throw this signal as soon as you can! */ + + void *t_data; /* Data passed to the thread. */ + XTThreadFreeFunc t_free_data; /* Routine used to free the thread data */ + + int t_call_top; /* A pointer to the top of the call stack. */ + XTCallStackRec t_call_stack[XT_MAX_CALL_STACK];/* Records the function under execution (to be output on error). */ + + XTResourcePtr t_res_top; /* The top of the resource stack (reference next free space). */ + union { + char t_res_stack[XT_RES_STACK_SIZE]; /* Temporary data to be freed if an exception occurs. */ + xtWord4 t_align_res_stack; + } x; + + int t_jmp_depth; /* The current jump depth */ + XTJumpBufRec t_jmp_env[XT_MAX_JMP]; /* The process environment to be restored on exception */ + XTExceptionRec t_exception; /* The exception details. */ + + xt_cond_type t_cond; /* The pthread condition used for suspending the thread. */ + xt_mutex_type t_lock; /* Thread lock, used for operations on a thread that may be done by other threads. + * for example xt_unuse_database(). + */ + + /* Application specific data: */ + struct XTDatabase *st_database; /* The database in use by the thread. */ + u_int st_lock_count; /* We count the number of locks MySQL has set in order to know when they are all released. */ + u_int st_stat_count; /* start statement count. */ + struct XTXactData *st_xact_data; /* The transaction data, not NULL if the transaction performs an update. */ + xtBool st_xact_writer; /* TRUE if the transaction has written somthing to the log. */ + time_t st_xact_write_time; /* Approximate first write time (uses xt_db_approximate_time). */ + xtBool st_xact_long_running; /* TRUE if this is a long running writer transaction. */ + xtWord4 st_visible_time; /* Transactions committed before this time are visible. */ + XTDataLogBufferRec st_dlog_buf; + + int st_xact_mode; /* The transaction mode. */ + xtBool st_ignore_fkeys; /* TRUE if we must ignore foreign keys. */ + xtBool st_auto_commit; /* TRUE if this is an auto-commit transaction. */ + xtBool st_table_trans; /* TRUE transactions is a result of LOCK TABLES. */ + xtBool st_abort_trans; /* TRUE if the transaction should be aborted. */ + xtBool st_stat_ended; /* TRUE if the statement was ended. */ + xtBool st_stat_trans; /* TRUE if a statement transaction is running (started on UPDATE). */ + xtBool st_stat_modify; /* TRUE if the statement is an INSERT/UPDATE/DELETE */ +#ifdef XT_IMPLEMENT_NO_ACTION + XTBasicListRec st_restrict_list; /* These records have been deleted and should have no reference. */ +#endif + /* Local thread list. */ + u_int st_thread_list_count; + u_int st_thread_list_size; + xtThreadID *st_thread_list; + + /* Used to prevent a record from being updated twice in one statement. */ + xtBool st_is_update; /* TRUE if this is an UPDATE statement. */ + u_int st_update_id; /* The update statement ID. */ + + XTRowLockListRec st_lock_list; /* The thread row lock list (drop locks on transaction end). */ + XTStatisticsRec st_statistics; /* Accumulated statistics for this thread. */ +#ifdef XT_THREAD_LOCK_INFO + /* list of locks (spins, mutextes, etc) that this thread currently holds (debugging) */ + XTThreadLockInfoPtr st_thread_lock_list[XT_THREAD_LOCK_INFO_MAX_COUNT]; + int st_thread_lock_count; +#endif +} XTThreadRec, *XTThreadPtr; + +/* + * ----------------------------------------------------------------------- + * Call stack + */ + +#define XT_INIT_CHECK_STACK char xt_chk_buffer[512]; memset(xt_chk_buffer, 0xFE, 512); +#define XT_RE_CHECK_STACK memset(xt_chk_buffer, 0xFE, 512); + +/* + * This macro must be placed at the start of every function. + * It records the current context so that we can + * dump a type of stack trace later if necessary. + * + * It also sets up the current thread pointer 'self'. + */ +#ifdef DEBUG +#define XT_STACK_TRACE +#endif + +/* + * These macros generate a stack trace which can be used + * to locate an error on exception. + */ +#ifdef XT_STACK_TRACE + +/* + * Place this call at the top of a function, + * after the declaration of local variable, and + * before the first code is executed. + */ +#define enter_() int xt_frame = self->t_call_top++; \ + do { \ + if (xt_frame < XT_MAX_CALL_STACK) { \ + self->t_call_stack[xt_frame].cs_func = __FUNC__; \ + self->t_call_stack[xt_frame].cs_file = __FILE__; \ + self->t_call_stack[xt_frame].cs_line = __LINE__; \ + } \ + } while (0) + +#define outer_() self->t_call_top = xt_frame; + +/* + * On exit to a function, either exit_() or + * return_() must be called. + */ +#define exit_() do { \ + outer_(); \ + return; \ + } while (0) + +#define return_(x) do { \ + outer_(); \ + return(x); \ + } while (0) + +#define returnc_(x, typ) do { \ + typ rv; \ + rv = (x); \ + outer_(); \ + return(rv); \ + } while (0) + +/* + * Sets the line number before a call to get a better + * stack trace; + */ +#define call_(x) do { self->t_call_stack[xt_frame].cs_line = __LINE__; x; } while (0) + +#else +#define enter_() +#define outer_() +#define exit_() return; +#define return_(x) return (x) +#define returnc_(x, typ) return (x) +#define call_(x) x +#endif + +/* + * ----------------------------------------------------------------------- + * Throwing and catching + */ + +int prof_setjmp(void); + +#define TX_CHK_JMP() if ((self)->t_jmp_depth < 0 || (self)->t_jmp_depth >= XT_MAX_JMP) xt_throw_xterr(self, __FUNC__, __FILE__, __LINE__, XT_ERR_JUMP_OVERFLOW) +#ifdef PROFILE +#define profile_setjmp prof_setjmp() +#else +#define profile_setjmp +#endif + +#define try_(n) TX_CHK_JMP(); \ + (self)->t_jmp_env[(self)->t_jmp_depth].jb_res_top = (self)->t_res_top; \ + (self)->t_jmp_env[(self)->t_jmp_depth].jb_call_top = (self)->t_call_top; \ + (self)->t_jmp_depth++; profile_setjmp; if (setjmp((self)->t_jmp_env[(self)->t_jmp_depth-1].jb_buffer)) goto catch_##n; +#define catch_(n) (self)->t_jmp_depth--; goto cont_##n; catch_##n: (self)->t_jmp_depth--; xt_caught(self); +#define cont_(n) cont_##n: +#define throw_() xt_throw(self) + +/* + * ----------------------------------------------------------------------- + * Resource stack + */ + +//#define DEBUG_RESOURCE_STACK + +#ifdef DEBUG_RESOURCE_STACK +#define CHECK_RS if ((char *) (self)->t_res_top < (self)->x.t_res_stack) xt_bug(self); +#define CHECK_NS_RS { XTThreadPtr self = xt_get_self(); CHECK_RS; } +#else +#define CHECK_RS remove this! +#define CHECK_NS_RS remove this! +#endif + +/* + * Allocate a resource on the resource stack. The resource will be freed + * automatocally if an exception occurs. Before exiting the current + * procedure you must free the resource using popr_() or freer_(). + * v = value to be set to the resource, + * f = function which frees the resource, + * s = the size of the resource, + */ + +/* GOTCHA: My experience is that contructs such as *((xtWordPS *) &(v)) = (xtWordPS) (x) + * cause optimised versions to crash?! + */ +#define allocr_(v, f, s, t) do { \ + if (((char *) (self)->t_res_top) > (self)->x.t_res_stack + XT_RES_STACK_SIZE - sizeof(XTResourceRec) + (s) + 4) \ + xt_throw_xterr(self, __FUNC__, __FILE__, __LINE__, XT_ERR_RES_STACK_OVERFLOW); \ + v = (t) (((char *) (self)->t_res_top) + sizeof(XTResourceRec)); \ + (self)->t_res_top->r_data = (v); \ + (self)->t_res_top->r_free_func = (XTThreadFreeFunc) (f); \ + (self)->t_res_top = (XTResourcePtr) (((char *) (self)->t_res_top) + sizeof(XTResourceRec) + (s)); \ + (self)->t_res_top->r_prev_size = sizeof(XTResourceRec) + (s); \ + } while (0) + +#define alloczr_(v, f, s, t) do { allocr_(v, f, s, t); \ + memset(v, 0, s); } while (0) + +/* Push and set a resource: + * v = value to be set to the resource, + * f = function which frees the resource, + * r = the resource, + * NOTE: the expression (r) must come first because it may contain + * calls which use the resource stack!! + */ +#define pushsr_(v, f, r) do { \ + if (((char *) (self)->t_res_top) > (self)->x.t_res_stack + XT_RES_STACK_SIZE - sizeof(XTResourceRec) + 4) \ + xt_throw_xterr(self, __FUNC__, __FILE__, __LINE__, XT_ERR_RES_STACK_OVERFLOW); \ + v = (r); \ + (self)->t_res_top->r_data = (v); \ + (self)->t_res_top->r_free_func = (XTThreadFreeFunc) (f); \ + (self)->t_res_top = (XTResourcePtr) (((char *) (self)->t_res_top) + sizeof(XTResourceRec)); \ + (self)->t_res_top->r_prev_size = sizeof(XTResourceRec); \ + } while (0) + +/* Push a resource. In the event of an exception it will be freed + * the free routine. + * f = function which frees the resource, + * r = a pointer to the resource, + */ +#define pushr_(f, r) do { \ + if (((char *) (self)->t_res_top) > (self)->x.t_res_stack + XT_RES_STACK_SIZE - sizeof(XTResourceRec) + 4) \ + xt_throw_xterr(self, __FUNC__, __FILE__, __LINE__, XT_ERR_RES_STACK_OVERFLOW); \ + (self)->t_res_top->r_data = (r); \ + (self)->t_res_top->r_free_func = (XTThreadFreeFunc) (f); \ + (self)->t_res_top = (XTResourcePtr) (((char *) (self)->t_res_top) + sizeof(XTResourceRec)); \ + (self)->t_res_top->r_prev_size = sizeof(XTResourceRec); \ + } while (0) + +/* Pop a resource without freeing it: */ +#ifdef DEBUG_RESOURCE_STACK +#define popr_() do { \ + (self)->t_res_top = (XTResourcePtr) (((char *) (self)->t_res_top) - (self)->t_res_top->r_prev_size); \ + if ((char *) (self)->t_res_top < (self)->x.t_res_stack) \ + xt_bug(self); \ + } while (0) +#else +#define popr_() do { (self)->t_res_top = (XTResourcePtr) (((char *) (self)->t_res_top) - (self)->t_res_top->r_prev_size); } while (0) +#endif + +#define setr_(r) do { ((XTResourcePtr) (((char *) (self)->t_res_top) - (self)->t_res_top->r_prev_size))->r_data = (r); } while (0) + +/* Pop and free a resource: */ +#ifdef DEBUG_RESOURCE_STACK +#define freer_() do { \ + register XTResourcePtr rp; \ + rp = (XTResourcePtr) (((char *) (self)->t_res_top) - (self)->t_res_top->r_prev_size); \ + if ((char *) rp < (self)->x.t_res_stack) \ + xt_bug(self); \ + (rp->r_free_func)((self), rp->r_data); \ + (self)->t_res_top = rp; \ + } while (0) +#else +#define freer_() do { \ + register XTResourcePtr rp; \ + rp = (XTResourcePtr) (((char *) (self)->t_res_top) - (self)->t_res_top->r_prev_size); \ + (rp->r_free_func)((self), rp->r_data); \ + (self)->t_res_top = rp; \ + } while (0) +#endif + +/* + * ----------------------------------------------------------------------- + * Thread globals + */ + +extern u_int xt_thr_maximum_threads; +extern u_int xt_thr_current_thread_count; +extern u_int xt_thr_current_max_threads; +extern struct XTThread **xt_thr_array; + +/* + * ----------------------------------------------------------------------- + * Function prototypes + */ + +void xt_get_now(char *buffer, size_t len); +xtBool xt_init_logging(void); +void xt_exit_logging(void); +void xt_log_flush(XTThreadPtr self); +void xt_logf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *fmt, ...); +void xt_log(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *string); +int xt_log_errorf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *fmt, ...); +int xt_log_error(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *string); +void xt_log_exception(XTThreadPtr self, XTExceptionPtr e, int level); +void xt_clear_exception(XTThreadPtr self); +void xt_log_and_clear_exception(XTThreadPtr self); +void xt_log_and_clear_exception_ns(void); +void xt_log_and_clear_warning(XTThreadPtr self); +void xt_log_and_clear_warning_ns(void); + +void xt_bug(XTThreadPtr self); +void xt_caught(XTThreadPtr self); +void xt_throw(XTThreadPtr self); +void xt_throwf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *format, ...); +void xt_throw_error(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *message); +void xt_throw_i2xterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item, c_char *item2); +void xt_throw_ixterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item); +void xt_throw_tabcolerr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item, c_char *item2); +void xt_throw_taberr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item); +void xt_throw_ulxterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, u_long value); +void xt_throw_sulxterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item, u_long value); +void xt_throw_xterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err); +void xt_throw_errno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err_no); +void xt_throw_ferrno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err_no, c_char *path); +void xt_throw_assertion(XTThreadPtr self, c_char *func, c_char *file, u_int line, c_char *str); +void xt_throw_signal(XTThreadPtr self, c_char *func, c_char *file, u_int line, int sig); +xtBool xt_throw_delayed_signal(XTThreadPtr self, c_char *func, c_char *file, u_int line); + +void xt_registerf(c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...); +void xt_register_i2xterr(c_char *func, c_char *file, u_int line, int xt_err, c_char *item, c_char *item2); +void xt_register_ixterr(c_char *func, c_char *file, u_int line, int xt_err, c_char *item); +void xt_register_tabcolerr(c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item, c_char *item2); +void xt_register_taberr(c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item); +void xt_register_ulxterr(c_char *func, c_char *file, u_int line, int xt_err, u_long value); +xtBool xt_register_ferrno(c_char *func, c_char *file, u_int line, int err, c_char *path); +void xt_register_error(c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg); +xtBool xt_register_errno(c_char *func, c_char *file, u_int line, int err); +void xt_register_xterr(c_char *func, c_char *file, u_int line, int xt_err); + +void xt_exceptionf(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...); +void xt_exception_error(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg); +xtBool xt_exception_errno(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int err); + +void xt_log_errno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err); + +xtBool xt_assert(XTThreadPtr self, c_char *expr, c_char *func, c_char *file, u_int line); +xtBool xt_assume(XTThreadPtr self, c_char *expr, c_char *func, c_char *file, u_int line); + +XTThreadPtr xt_init_threading(u_int max_threads); +void xt_exit_threading(XTThreadPtr self); + +XTThreadPtr xt_create_thread(c_char *name, xtBool main_thread, xtBool temp_thread, XTExceptionPtr e); +XTThreadPtr xt_create_daemon(XTThreadPtr parent, c_char *name); +void xt_free_thread(XTThreadPtr self); +void xt_set_thread_data(XTThreadPtr self, void *data, XTThreadFreeFunc free_func); +pthread_t xt_run_thread(XTThreadPtr parent, XTThreadPtr child, void *(*start_routine)(XTThreadPtr)); +void xt_exit_thread(XTThreadPtr self, void *result); +void *xt_wait_for_thread(xtThreadID tid, xtBool ignore_error); +void xt_signal_all_threads(XTThreadPtr self, int sig); +void xt_do_to_all_threads(XTThreadPtr self, void (*do_func_ptr)(XTThreadPtr self, XTThreadPtr to_thr, void *thunk), void *thunk); +void xt_kill_thread(pthread_t t1); +XTThreadPtr xt_get_self(void); +void xt_set_self(XTThreadPtr self); +void xt_wait_for_all_threads(XTThreadPtr self); +void xt_busy_wait(void); +void xt_critical_wait(void); +void xt_yield(void); +void xt_sleep_milli_second(u_int t); +xtBool xt_suspend(XTThreadPtr self); +xtBool xt_unsuspend(XTThreadPtr self, XTThreadPtr target); +void xt_lock_thread(XTThreadPtr thread); +void xt_unlock_thread(XTThreadPtr thread); +xtBool xt_wait_thread(XTThreadPtr thread); +void xt_signal_thread(XTThreadPtr target); +void xt_terminate_thread(XTThreadPtr self, XTThreadPtr target); +xtProcID xt_getpid(); +xtBool xt_process_exists(xtProcID pid); + +#ifdef XT_THREAD_LOCK_INFO +#define xt_init_rwlock_with_autoname(a,b) xt_init_rwlock(a,b,LOCKLIST_ARG_SUFFIX(b)) +xtBool xt_init_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock, const char *name); +#else +#define xt_init_rwlock_with_autoname(a,b) xt_init_rwlock(a,b) +xtBool xt_init_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock); +#endif + +void xt_free_rwlock(xt_rwlock_type *rwlock); +xt_rwlock_type *xt_slock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock); +xt_rwlock_type *xt_xlock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock); +void xt_unlock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock); + +xt_mutex_type *xt_new_mutex(XTThreadPtr self); +void xt_delete_mutex(XTThreadPtr self, xt_mutex_type *mx); +#ifdef XT_THREAD_LOCK_INFO +#define xt_init_mutex_with_autoname(a,b) xt_init_mutex(a,b,LOCKLIST_ARG_SUFFIX(b)) +xtBool xt_init_mutex(XTThreadPtr self, xt_mutex_type *mx, const char *name); +#else +#define xt_init_mutex_with_autoname(a,b) xt_init_mutex(a,b) +xtBool xt_init_mutex(XTThreadPtr self, xt_mutex_type *mx); +#endif +void xt_free_mutex(xt_mutex_type *mx); +xtBool xt_lock_mutex(XTThreadPtr self, xt_mutex_type *mx); +void xt_unlock_mutex(XTThreadPtr self, xt_mutex_type *mx); + +pthread_cond_t *xt_new_cond(XTThreadPtr self); +void xt_delete_cond(XTThreadPtr self, pthread_cond_t *cond); + +xtBool xt_init_cond(XTThreadPtr self, pthread_cond_t *cond); +void xt_free_cond(pthread_cond_t *cond); +xtBool xt_wait_cond(XTThreadPtr self, pthread_cond_t *cond, xt_mutex_type *mutex); +xtBool xt_timed_wait_cond(XTThreadPtr self, pthread_cond_t *cond, xt_mutex_type *mutex, u_long milli_sec); +xtBool xt_signal_cond(XTThreadPtr self, pthread_cond_t *cond); +void xt_broadcast_cond(XTThreadPtr self, pthread_cond_t *cond); +xtBool xt_broadcast_cond_ns(xt_cond_type *cond); + +xtBool xt_set_key(pthread_key_t key, const void *value, XTExceptionPtr e); +void *xt_get_key(pthread_key_t key); + +void xt_set_low_priority(XTThreadPtr self); +void xt_set_normal_priority(XTThreadPtr self); +void xt_set_high_priority(XTThreadPtr self); +void xt_set_priority(XTThreadPtr self, int priority); + +void xt_gather_statistics(XTStatisticsPtr stats); +u_llong xt_get_statistic(XTStatisticsPtr stats, struct XTDatabase *db, u_int rec_id); + +#define xt_timed_wait_cond_ns(a, b, c) xt_timed_wait_cond(NULL, a, b, c) + +#endif + diff --git a/storage/pbxt/src/trace_xt.cc b/storage/pbxt/src/trace_xt.cc new file mode 100644 index 00000000000..e5881cb6d12 --- /dev/null +++ b/storage/pbxt/src/trace_xt.cc @@ -0,0 +1,345 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-02-07 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <stdlib.h> +#include <time.h> + +#include "trace_xt.h" +#include "pthread_xt.h" +#include "thread_xt.h" + +#ifdef DEBUG +//#define PRINT_TRACE +//#define RESET_AFTER_DUMP +#endif + +static xtBool trace_initialized = FALSE; +static xt_mutex_type trace_mutex; +static size_t trace_log_size; +static size_t trace_log_offset; +static size_t trace_log_end; +static char *trace_log_buffer; +static u_long trace_stat_count; +static FILE *trace_dump_file; +static xtBool trace_flush_dump = FALSE; + +#define DEFAULT_TRACE_LOG_SIZE (40*1024*1204) +#define MAX_PRINT_LEN 2000 + +xtPublic xtBool xt_init_trace(void) +{ + int err; + + err = xt_p_mutex_init_with_autoname(&trace_mutex, NULL); + if (err) { + xt_log_errno(XT_NS_CONTEXT, err); + trace_initialized = FALSE; + return FALSE; + } + trace_initialized = TRUE; + trace_log_buffer = (char *) malloc(DEFAULT_TRACE_LOG_SIZE+1); + if (!trace_log_buffer) { + xt_log_errno(XT_NS_CONTEXT, ENOMEM); + xt_exit_trace(); + return FALSE; + } + trace_log_size = DEFAULT_TRACE_LOG_SIZE; + trace_log_offset = 0; + trace_log_end = 0; + trace_stat_count = 0; + return TRUE; +} + +xtPublic void xt_exit_trace(void) +{ + if (trace_initialized) { +#ifdef DEBUG + xt_dump_trace(); +#endif + xt_free_mutex(&trace_mutex); + trace_initialized = FALSE; + if (trace_log_buffer) + free(trace_log_buffer); + trace_log_buffer = NULL; + trace_log_size = 0; + trace_log_offset = 0; + trace_log_end = 0; + trace_stat_count = 0; + } + if (trace_dump_file) { + fclose(trace_dump_file); + trace_dump_file = NULL; + } +} + +xtPublic void xt_print_trace(void) +{ + if (trace_log_offset) { + xt_lock_mutex_ns(&trace_mutex); + if (trace_log_end > trace_log_offset+1) { + trace_log_buffer[trace_log_end] = 0; + printf("%s", trace_log_buffer + trace_log_offset + 1); + } + trace_log_buffer[trace_log_offset] = 0; + printf("%s", trace_log_buffer); + trace_log_offset = 0; + trace_log_end = 0; + xt_unlock_mutex_ns(&trace_mutex); + } +} + +xtPublic void xt_dump_trace(void) +{ + FILE *fp; + + if (trace_log_offset) { + fp = fopen("pbxt.log", "w"); + + xt_lock_mutex_ns(&trace_mutex); + if (fp) { + if (trace_log_end > trace_log_offset+1) { + trace_log_buffer[trace_log_end] = 0; + fprintf(fp, "%s", trace_log_buffer + trace_log_offset + 1); + } + trace_log_buffer[trace_log_offset] = 0; + fprintf(fp, "%s", trace_log_buffer); + fclose(fp); + } + +#ifdef RESET_AFTER_DUMP + trace_log_offset = 0; + trace_log_end = 0; + trace_stat_count = 0; +#endif + xt_unlock_mutex_ns(&trace_mutex); + } + + if (trace_dump_file) { + xt_lock_mutex_ns(&trace_mutex); + if (trace_dump_file) { + fflush(trace_dump_file); + fclose(trace_dump_file); + trace_dump_file = NULL; + } + xt_unlock_mutex_ns(&trace_mutex); + } +} + +xtPublic void xt_trace(const char *fmt, ...) +{ + va_list ap; + size_t len; + + va_start(ap, fmt); + xt_lock_mutex_ns(&trace_mutex); + + if (trace_log_offset + MAX_PRINT_LEN > trace_log_size) { + /* Start at the beginning of the buffer again: */ + trace_log_end = trace_log_offset; + trace_log_offset = 0; + } + + len = (size_t) vsnprintf(trace_log_buffer + trace_log_offset, trace_log_size - trace_log_offset, fmt, ap); + trace_log_offset += len; + + xt_unlock_mutex_ns(&trace_mutex); + va_end(ap); + +#ifdef PRINT_TRACE + xt_print_trace(); +#endif +} + +xtPublic void xt_ttracef(XTThreadPtr self, char *fmt, ...) +{ + va_list ap; + size_t len; + + va_start(ap, fmt); + xt_lock_mutex_ns(&trace_mutex); + + if (trace_log_offset + MAX_PRINT_LEN > trace_log_size) { + trace_log_end = trace_log_offset; + trace_log_offset = 0; + } + + trace_stat_count++; + len = (size_t) sprintf(trace_log_buffer + trace_log_offset, "%lu %s: ", trace_stat_count, self->t_name); + trace_log_offset += len; + len = (size_t) vsnprintf(trace_log_buffer + trace_log_offset, trace_log_size - trace_log_offset, fmt, ap); + trace_log_offset += len; + + xt_unlock_mutex_ns(&trace_mutex); + va_end(ap); + +#ifdef PRINT_TRACE + xt_print_trace(); +#endif +} + +xtPublic void xt_ttraceq(XTThreadPtr self, char *query) +{ + size_t qlen = strlen(query), tlen; + char *ptr, *qptr; + + if (!self) + self = xt_get_self(); + + xt_lock_mutex_ns(&trace_mutex); + + if (trace_log_offset + qlen + 100 >= trace_log_size) { + /* Start at the beginning of the buffer again: */ + trace_log_end = trace_log_offset; + trace_log_offset = 0; + } + + trace_stat_count++; + tlen = (size_t) sprintf(trace_log_buffer + trace_log_offset, "%lu %s: ", trace_stat_count, self->t_name); + trace_log_offset += tlen; + + ptr = trace_log_buffer + trace_log_offset; + qlen = 0; + qptr = query; + while (*qptr) { + if (*qptr == '\n' || *qptr == '\r') + *ptr = ' '; + else + *ptr = *qptr; + if (*qptr == '\n' || *qptr == '\r' || *qptr == ' ') { + qptr++; + while (*qptr == '\n' || *qptr == '\r' || *qptr == ' ') + qptr++; + } + else + qptr++; + ptr++; + qlen++; + } + + trace_log_offset += qlen; + *(trace_log_buffer + trace_log_offset) = '\n'; + *(trace_log_buffer + trace_log_offset + 1) = '\0'; + trace_log_offset++; + + xt_unlock_mutex_ns(&trace_mutex); + +#ifdef PRINT_TRACE + xt_print_trace(); +#endif +} + +/* + * Returns the time in microseconds. + * (1/1000000 of a second) + */ +xtPublic xtWord8 xt_trace_clock(void) +{ + static xtWord8 trace_start_clock = 0; + xtWord8 now; + +#ifdef XT_WIN + now = ((xtWord8) GetTickCount()) * (xtWord8) 1000; +#else + struct timeval tv; + + gettimeofday(&tv, NULL); + now = (xtWord8) tv.tv_sec * (xtWord8) 1000000 + tv.tv_usec; +#endif + if (trace_start_clock) + return now - trace_start_clock; + trace_start_clock = now; + return 0; +} + +xtPublic char *xt_trace_clock_str(char *ptr) +{ + static char buffer[50]; + xtWord8 now = xt_trace_clock(); + + if (!ptr) + ptr = buffer; + + sprintf(ptr, "%d.%06d", (int) (now / (xtWord8) 1000000), (int) (now % (xtWord8) 1000000)); + return ptr; +} + +xtPublic char *xt_trace_clock_diff(char *ptr) +{ + static xtWord8 trace_last_clock = 0; + static char buffer[50]; + xtWord8 now = xt_trace_clock(); + + if (!ptr) + ptr = buffer; + + sprintf(ptr, "%d.%06d (%d)", (int) (now / (xtWord8) 1000000), (int) (now % (xtWord8) 1000000), (int) (now - trace_last_clock)); + trace_last_clock = now; + return ptr; +} + +xtPublic char *xt_trace_clock_diff(char *ptr, xtWord8 start_time) +{ + xtWord8 now = xt_trace_clock(); + + sprintf(ptr, "%d.%06d (%d)", (int) (now / (xtWord8) 1000000), (int) (now % (xtWord8) 1000000), (int) (now - start_time)); + return ptr; +} + + +xtPublic void xt_set_fflush(xtBool on) +{ + trace_flush_dump = on; +} + +xtPublic void xt_ftracef(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xt_lock_mutex_ns(&trace_mutex); + + if (!trace_dump_file) { + char buffer[100]; + + for (int i=1; ;i++) { + sprintf(buffer, "pbxt-dump-%d.log", i); + if (!xt_fs_exists(buffer)) { + trace_dump_file = fopen(buffer, "w"); + break; + } + } + } + + vfprintf(trace_dump_file, fmt, ap); + if (trace_flush_dump) + fflush(trace_dump_file); + + xt_unlock_mutex_ns(&trace_mutex); + va_end(ap); +} + diff --git a/storage/pbxt/src/trace_xt.h b/storage/pbxt/src/trace_xt.h new file mode 100644 index 00000000000..44cfa9945f1 --- /dev/null +++ b/storage/pbxt/src/trace_xt.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-02-07 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_trace_h__ +#define __xt_trace_h__ + +#include "xt_defs.h" + +xtBool xt_init_trace(void); +void xt_exit_trace(void); +void xt_dump_trace(void); +void xt_print_trace(void); + +void xt_trace(const char *fmt, ...); +void xt_ttraceq(struct XTThread *self, char *query); +void xt_ttracef(struct XTThread *self, char *fmt, ...); +xtWord8 xt_trace_clock(void); +char *xt_trace_clock_str(char *ptr); +char *xt_trace_clock_diff(char *ptr); +char *xt_trace_clock_diff(char *ptr, xtWord8 start_time); +void xt_set_fflush(xtBool on); +void xt_ftracef(char *fmt, ...); + +#define XT_DEBUG_TRACE(x) +#define XT_DISABLED_TRACE(x) +#ifdef DEBUG +//#define PBXT_HANDLER_TRACE +#endif + +#endif diff --git a/storage/pbxt/src/util_xt.cc b/storage/pbxt/src/util_xt.cc new file mode 100644 index 00000000000..6e1db1f5f73 --- /dev/null +++ b/storage/pbxt/src/util_xt.cc @@ -0,0 +1,414 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2004-01-03 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <stdio.h> +#include <time.h> +#include <ctype.h> +#ifndef XT_WIN +#include <sys/param.h> +#endif + +#include "util_xt.h" +#include "strutil_xt.h" +#include "memory_xt.h" + +xtPublic int xt_comp_log_pos(xtLogID id1, off_t off1, xtLogID id2, off_t off2) +{ + if (id1 < id2) + return -1; + if (id1 > id2) + return 1; + if (off1 < off2) + return -1; + if (off1 > off2) + return 1; + return 0; +} + +/* + * This function returns the current time in micorsonds since + * 00:00:00 UTC, January 1, 1970. + * Currently it is accurate to the second :( + */ +xtPublic xtWord8 xt_time_now(void) +{ + xtWord8 ms; + + ms = (xtWord8) time(NULL); + ms *= 1000000; + return ms; +} + +xtPublic void xt_free_nothing(struct XTThread XT_UNUSED(*thr), void XT_UNUSED(*x)) +{ +} + +/* + * A file name has the form: + * <text>-<number>[.<ext>] + * This function return the number part as a + * u_long. + */ +xtPublic xtWord4 xt_file_name_to_id(char *file_name) +{ + u_long value = 0; + + if (file_name) { + char *num = file_name + strlen(file_name) - 1; + + while (num >= file_name && *num != '-') + num--; + num++; + if (isdigit(*num)) + sscanf(num, "%lu", &value); + } + return (xtWord4) value; +} + +/* + * now is moving forward. then is a static time in the + * future. What is the time difference? + * + * These variables can overflow. + */ +xtPublic int xt_time_difference(register xtWord4 now, register xtWord4 then) +{ + /* now is after then, so the now time has passed + * then. So we return a negative difference. + */ + if (now >= then) { + /* now has gone past then. If the difference is + * great, then we assume an overflow, and reverse! + */ + if ((now - then) > (xtWord4) 0xFFFFFFFF/2) + return (int) (0xFFFFFFFF - (now - then)); + + return (int) now - (int) then; + } + /* If now is before then, we check the difference. + * If the difference is very large, then we assume + * that now has gone past then, and overflowed. + */ + if ((then - now) > (xtWord4) 0xFFFFFFFF/2) + return - (int) (0xFFFFFFFF - (then - now)); + return then - now; +} + +xtPublic xtWord2 xt_get_checksum(xtWord1 *data, size_t len, u_int interval) +{ + register xtWord4 sum = 0, g; + xtWord1 *chk; + + chk = data + len - 1; + while (chk > data) { + sum = (sum << 4) + *chk; + if ((g = sum & 0xF0000000)) { + sum = sum ^ (g >> 24); + sum = sum ^ g; + } + chk -= interval; + } + return (xtWord2) (sum ^ (sum >> 16)); +} + +xtPublic xtWord1 xt_get_checksum1(xtWord1 *data, size_t len) +{ + register xtWord4 sum = 0, g; + xtWord1 *chk; + + chk = data + len - 1; + while (chk > data) { + sum = (sum << 4) + *chk; + if ((g = sum & 0xF0000000)) { + sum = sum ^ (g >> 24); + sum = sum ^ g; + } + chk--; + } + return (xtWord1) (sum ^ (sum >> 24) ^ (sum >> 16) ^ (sum >> 8)); +} + +/* + * --------------- Data Buffer ------------------ + */ + +xtPublic xtBool xt_db_set_size(struct XTThread *self, XTDataBufferPtr dbuf, size_t size) +{ + if (dbuf->db_size < size) { + if (!xt_realloc(self, (void **) &dbuf->db_data, size)) + return FAILED; + dbuf->db_size = size; + } + else if (!size) { + if (dbuf->db_data) + xt_free(self, dbuf->db_data); + dbuf->db_data = NULL; + dbuf->db_size = 0; + } + return OK; +} + +/* + * --------------- Data Buffer ------------------ + */ + +xtPublic xtBool xt_ib_alloc(struct XTThread *self, XTInfoBufferPtr ib, size_t size) +{ + if (!ib->ib_free) { + ib->ib_db.db_size = 0; + ib->ib_db.db_data = NULL; + } + if (size <= ib->ib_db.db_size) + return OK; + + if (size <= XT_IB_DEFAULT_SIZE) { + ib->ib_db.db_size = XT_IB_DEFAULT_SIZE; + ib->ib_db.db_data = ib->ib_data; + return OK; + } + + if (ib->ib_db.db_data == ib->ib_data) { + ib->ib_db.db_size = 0; + ib->ib_db.db_data = NULL; + } + + ib->ib_free = TRUE; + return xt_db_set_size(self, &ib->ib_db, size); +} + +void xt_ib_free(struct XTThread *self, XTInfoBufferPtr ib) +{ + if (ib->ib_free) { + xt_db_set_size(self, &ib->ib_db, 0); + ib->ib_free = FALSE; + } +} + +/* + * --------------- Basic List ------------------ + */ + +xtPublic xtBool xt_bl_set_size(struct XTThread *self, XTBasicListPtr bl, size_t size) +{ + if (bl->bl_size < size) { + if (!xt_realloc(self, (void **) &bl->bl_data, size * bl->bl_item_size)) + return FAILED; + bl->bl_size = size; + } + else if (!size) { + if (bl->bl_data) + xt_free(self, bl->bl_data); + bl->bl_data = NULL; + bl->bl_size = 0; + bl->bl_count = 0; + } + return OK; +} + +xtPublic xtBool xt_bl_dup(struct XTThread *self, XTBasicListPtr from_bl, XTBasicListPtr to_bl) +{ + to_bl->bl_item_size = from_bl->bl_item_size; + to_bl->bl_size = 0; + to_bl->bl_count = from_bl->bl_count; + to_bl->bl_data = NULL; + if (!xt_bl_set_size(self, to_bl, from_bl->bl_count)) + return FAILED; + memcpy(to_bl->bl_data, from_bl->bl_data, to_bl->bl_count * to_bl->bl_item_size); + return OK; +} + +xtPublic xtBool xt_bl_append(struct XTThread *self, XTBasicListPtr bl, void *value) +{ + if (bl->bl_count == bl->bl_size) { + if (!xt_bl_set_size(self, bl, bl->bl_count+1)) + return FAILED; + } + memcpy(&bl->bl_data[bl->bl_count * bl->bl_item_size], value, bl->bl_item_size); + bl->bl_count++; + return OK; +} + +xtPublic void *xt_bl_last_item(XTBasicListPtr bl) +{ + if (!bl->bl_count) + return NULL; + return &bl->bl_data[(bl->bl_count-1) * bl->bl_item_size]; +} + +xtPublic void *xt_bl_item_at(XTBasicListPtr bl, u_int i) +{ + if (i >= bl->bl_count) + return NULL; + return &bl->bl_data[i * bl->bl_item_size]; +} + +xtPublic void xt_bl_free(struct XTThread *self, XTBasicListPtr wl) +{ + xt_bl_set_size(self, wl, 0); +} + +/* + * --------------- Basic Queue ------------------ + */ + +xtPublic xtBool xt_bq_set_size(struct XTThread *self, XTBasicQueuePtr bq, size_t size) +{ + if (bq->bq_size < size) { + if (!xt_realloc(self, (void **) &bq->bq_data, size * bq->bq_item_size)) + return FAILED; + bq->bq_size = size; + } + else if (!size) { + if (bq->bq_data) + xt_free(self, bq->bq_data); + bq->bq_data = NULL; + bq->bq_size = 0; + bq->bq_front = 0; + bq->bq_back = 0; + } + return OK; +} + +xtPublic void *xt_bq_get(XTBasicQueuePtr bq) +{ + if (bq->bq_back == bq->bq_front) + return NULL; + return &bq->bq_data[bq->bq_back * bq->bq_item_size]; +} + +xtPublic void xt_bq_next(XTBasicQueuePtr bq) +{ + if (bq->bq_back < bq->bq_front) { + bq->bq_back++; + if (bq->bq_front == bq->bq_back) { + bq->bq_front = 0; + bq->bq_back = 0; + } + } +} + +xtPublic xtBool xt_bq_add(struct XTThread *self, XTBasicQueuePtr bq, void *value) +{ + if (bq->bq_front == bq->bq_size) { + if (bq->bq_back >= bq->bq_max_waste) { + bq->bq_front -= bq->bq_back; + memmove(bq->bq_data, &bq->bq_data[bq->bq_back * bq->bq_item_size], bq->bq_front * bq->bq_item_size); + bq->bq_back = 0; + } + else { + if (!xt_bq_set_size(self, bq, bq->bq_front+bq->bq_item_inc)) + return FAILED; + } + } + memcpy(&bq->bq_data[bq->bq_front * bq->bq_item_size], value, bq->bq_item_size); + bq->bq_front++; + return OK; +} + +xtPublic void xt_sb_free(struct XTThread *self, XTStringBufferPtr dbuf) +{ + xt_sb_set_size(self, dbuf, 0); +} + +xtPublic xtBool xt_sb_set_size(struct XTThread *self, XTStringBufferPtr dbuf, size_t size) +{ + if (dbuf->sb_size < size) { + if (!xt_realloc(self, (void **) &dbuf->sb_cstring, size)) + return FAILED; + dbuf->sb_size = size; + } + else if (!size) { + if (dbuf->sb_cstring) + xt_free(self, dbuf->sb_cstring); + dbuf->sb_cstring = NULL; + dbuf->sb_size = 0; + dbuf->sb_len = 0; + } + return OK; +} + +xtPublic xtBool xt_sb_concat_len(struct XTThread *self, XTStringBufferPtr dbuf, c_char *str, size_t len) +{ + if (!xt_sb_set_size(self, dbuf, dbuf->sb_len + len + 1)) + return FAILED; + memcpy(dbuf->sb_cstring + dbuf->sb_len, str, len); + dbuf->sb_len += len; + dbuf->sb_cstring[dbuf->sb_len] = 0; + return OK; +} + +xtPublic xtBool xt_sb_concat(struct XTThread *self, XTStringBufferPtr dbuf, c_char *str) +{ + return xt_sb_concat_len(self, dbuf, str, strlen(str)); +} + +xtPublic xtBool xt_sb_concat_char(struct XTThread *self, XTStringBufferPtr dbuf, int ch) +{ + if (!xt_sb_set_size(self, dbuf, dbuf->sb_len + 1 + 1)) + return FAILED; + dbuf->sb_cstring[dbuf->sb_len] = (char) ch; + dbuf->sb_len++; + dbuf->sb_cstring[dbuf->sb_len] = 0; + return OK; +} + +xtPublic xtBool xt_sb_concat_int8(struct XTThread *self, XTStringBufferPtr dbuf, xtInt8 val) +{ + char buffer[200]; + + sprintf(buffer, "%"PRId64, val); + return xt_sb_concat(self, dbuf, buffer); +} + +xtPublic char *xt_sb_take_cstring(XTStringBufferPtr sbuf) +{ + char *str = sbuf->sb_cstring; + + sbuf->sb_cstring = NULL; + sbuf->sb_size = 0; + sbuf->sb_len = 0; + return str; +} + +xtPublic xtBool xt_sb_concat_url_len(struct XTThread *self, XTStringBufferPtr dbuf, c_char *from, size_t len_from) +{ + if (!xt_sb_set_size(self, dbuf, dbuf->sb_len + len_from + 1)) + return FAILED; + while (len_from--) { + if (*from == '%' && len_from >= 2 && isxdigit(*(from+1)) && isxdigit(*(from+2))) { + unsigned char a = xt_hex_digit(*(from+1)); + unsigned char b = xt_hex_digit(*(from+2)); + dbuf->sb_cstring[dbuf->sb_len] = a << 4 | b; + from += 3; + } + else + dbuf->sb_cstring[dbuf->sb_len] = *from++; + dbuf->sb_len++; + } + dbuf->sb_cstring[dbuf->sb_len] = 0; + return OK; +} + + diff --git a/storage/pbxt/src/util_xt.h b/storage/pbxt/src/util_xt.h new file mode 100644 index 00000000000..bb5003b10fb --- /dev/null +++ b/storage/pbxt/src/util_xt.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2004-01-03 Paul McCullagh + * + * H&G2JCtL + */ + +#ifndef __xt_xtutil_h__ +#define __xt_xtutil_h__ + +#include <stddef.h> + +#include "xt_defs.h" + +#define XT_CHECKSUM_1(sum) ((xtWord1) ((sum) ^ ((sum) >> 24) ^ ((sum) >> 16) ^ ((sum) >> 8))) +#define XT_CHECKSUM_2(sum) ((xtWord2) ((sum) ^ ((sum) >> 16))) +#define XT_CHECKSUM4_8(sum) ((xtWord4) (sum) ^ (xtWord4) ((sum) >> 32)) + +int xt_comp_log_pos(xtLogID id1, off_t off1, xtLogID id2, off_t off2); +xtWord8 xt_time_now(void); +void xt_free_nothing(struct XTThread *self, void *x); +xtWord4 xt_file_name_to_id(char *file_name); +xtBool xt_time_difference(register xtWord4 now, register xtWord4 then); +xtWord2 xt_get_checksum(xtWord1 *data, size_t len, u_int interval); +xtWord1 xt_get_checksum1(xtWord1 *data, size_t len); + +typedef struct XTDataBuffer { + size_t db_size; + xtWord1 *db_data; +} XTDataBufferRec, *XTDataBufferPtr; + +xtBool xt_db_set_size(struct XTThread *self, XTDataBufferPtr db, size_t size); + +#define XT_IB_DEFAULT_SIZE 512 + +typedef struct XTInfoBuffer { + xtBool ib_free; + XTDataBufferRec ib_db; + xtWord1 ib_data[XT_IB_DEFAULT_SIZE]; +} XTInfoBufferRec, *XTInfoBufferPtr; + +xtBool xt_ib_alloc(struct XTThread *self, XTInfoBufferPtr ib, size_t size); +void xt_ib_free(struct XTThread *self, XTInfoBufferPtr ib); + +typedef struct XTBasicList { + u_int bl_item_size; + u_int bl_size; + u_int bl_count; + xtWord1 *bl_data; +} XTBasicListRec, *XTBasicListPtr; + +xtBool xt_bl_set_size(struct XTThread *self, XTBasicListPtr wl, size_t size); +xtBool xt_bl_dup(struct XTThread *self, XTBasicListPtr from_bl, XTBasicListPtr to_bl); +xtBool xt_bl_append(struct XTThread *self, XTBasicListPtr wl, void *value); +void *xt_bl_last_item(XTBasicListPtr wl); +void *xt_bl_item_at(XTBasicListPtr wl, u_int i); +void xt_bl_free(struct XTThread *self, XTBasicListPtr wl); + +typedef struct XTBasicQueue { + u_int bq_item_size; + u_int bq_max_waste; + u_int bq_item_inc; + u_int bq_size; + u_int bq_front; + u_int bq_back; + xtWord1 *bq_data; +} XTBasicQueueRec, *XTBasicQueuePtr; + +xtBool xt_bq_set_size(struct XTThread *self, XTBasicQueuePtr wq, size_t size); +void *xt_bq_get(XTBasicQueuePtr wq); +void xt_bq_next(XTBasicQueuePtr wq); +xtBool xt_bq_add(struct XTThread *self, XTBasicQueuePtr wl, void *value); + +typedef struct XTStringBuffer { + size_t sb_size; + size_t sb_len; + char *sb_cstring; +} XTStringBufferRec, *XTStringBufferPtr; + +void xt_sb_free(struct XTThread *self, XTStringBufferPtr db); +xtBool xt_sb_set_size(struct XTThread *self, XTStringBufferPtr db, size_t size); +xtBool xt_sb_concat_len(struct XTThread *self, XTStringBufferPtr dbuf, c_char *str, size_t len); +xtBool xt_sb_concat(struct XTThread *self, XTStringBufferPtr dbuf, c_char *str); +xtBool xt_sb_concat_char(struct XTThread *self, XTStringBufferPtr dbuf, int ch); +xtBool xt_sb_concat_int8(struct XTThread *self, XTStringBufferPtr dbuf, xtInt8 val); +char *xt_sb_take_cstring(XTStringBufferPtr dbuf); +xtBool xt_sb_concat_url_len(struct XTThread *self, XTStringBufferPtr dbuf, c_char *str, size_t len); + +static inline size_t xt_align_size(size_t size, size_t align) +{ + register size_t diff = size % align; + + if (diff) + return size + align - diff; + return size; +} + +static inline off_t xt_align_offset(off_t size, size_t align) +{ + register off_t diff = size % (off_t) align; + + if (diff) + return size + align - diff; + return size; +} + +#endif diff --git a/storage/pbxt/src/win_inttypes.h b/storage/pbxt/src/win_inttypes.h new file mode 100644 index 00000000000..c8561939e54 --- /dev/null +++ b/storage/pbxt/src/win_inttypes.h @@ -0,0 +1,259 @@ +/* Copyright (C) 1997-2001, 2004, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + * ISO C99: 7.8 Format conversion of integer types <inttypes.h> + */ + +/* + * this is a reduced verion of the original linux inttypes.h file + */ + +#ifndef _INTTYPES_H +#define _INTTYPES_H 1 + +/* The ISO C99 standard specifies that these macros must only be + defined if explicitly requested. */ +#if !defined __cplusplus || defined __STDC_FORMAT_MACROS + +# if __WORDSIZE == 64 +# define __PRI64_PREFIX "l" +# define __PRIPTR_PREFIX "l" +# else +# define __PRI64_PREFIX "ll" +# define __PRIPTR_PREFIX +# endif + +/* Macros for printing format specifiers. */ + +/* Decimal notation. */ +# define PRId8 "d" +# define PRId16 "d" +# define PRId32 "d" +# define PRId64 __PRI64_PREFIX "d" + +# define PRIdLEAST8 "d" +# define PRIdLEAST16 "d" +# define PRIdLEAST32 "d" +# define PRIdLEAST64 __PRI64_PREFIX "d" + +# define PRIdFAST8 "d" +# define PRIdFAST16 __PRIPTR_PREFIX "d" +# define PRIdFAST32 __PRIPTR_PREFIX "d" +# define PRIdFAST64 __PRI64_PREFIX "d" + + +# define PRIi8 "i" +# define PRIi16 "i" +# define PRIi32 "i" +# define PRIi64 __PRI64_PREFIX "i" + +# define PRIiLEAST8 "i" +# define PRIiLEAST16 "i" +# define PRIiLEAST32 "i" +# define PRIiLEAST64 __PRI64_PREFIX "i" + +# define PRIiFAST8 "i" +# define PRIiFAST16 __PRIPTR_PREFIX "i" +# define PRIiFAST32 __PRIPTR_PREFIX "i" +# define PRIiFAST64 __PRI64_PREFIX "i" + +/* Octal notation. */ +# define PRIo8 "o" +# define PRIo16 "o" +# define PRIo32 "o" +# define PRIo64 __PRI64_PREFIX "o" + +# define PRIoLEAST8 "o" +# define PRIoLEAST16 "o" +# define PRIoLEAST32 "o" +# define PRIoLEAST64 __PRI64_PREFIX "o" + +# define PRIoFAST8 "o" +# define PRIoFAST16 __PRIPTR_PREFIX "o" +# define PRIoFAST32 __PRIPTR_PREFIX "o" +# define PRIoFAST64 __PRI64_PREFIX "o" + +/* Unsigned integers. */ +# define PRIu8 "u" +# define PRIu16 "u" +# define PRIu32 "u" +# define PRIu64 __PRI64_PREFIX "u" + +# define PRIuLEAST8 "u" +# define PRIuLEAST16 "u" +# define PRIuLEAST32 "u" +# define PRIuLEAST64 __PRI64_PREFIX "u" + +# define PRIuFAST8 "u" +# define PRIuFAST16 __PRIPTR_PREFIX "u" +# define PRIuFAST32 __PRIPTR_PREFIX "u" +# define PRIuFAST64 __PRI64_PREFIX "u" + +/* lowercase hexadecimal notation. */ +# define PRIx8 "x" +# define PRIx16 "x" +# define PRIx32 "x" +# define PRIx64 __PRI64_PREFIX "x" + +# define PRIxLEAST8 "x" +# define PRIxLEAST16 "x" +# define PRIxLEAST32 "x" +# define PRIxLEAST64 __PRI64_PREFIX "x" + +# define PRIxFAST8 "x" +# define PRIxFAST16 __PRIPTR_PREFIX "x" +# define PRIxFAST32 __PRIPTR_PREFIX "x" +# define PRIxFAST64 __PRI64_PREFIX "x" + +/* UPPERCASE hexadecimal notation. */ +# define PRIX8 "X" +# define PRIX16 "X" +# define PRIX32 "X" +# define PRIX64 __PRI64_PREFIX "X" + +# define PRIXLEAST8 "X" +# define PRIXLEAST16 "X" +# define PRIXLEAST32 "X" +# define PRIXLEAST64 __PRI64_PREFIX "X" + +# define PRIXFAST8 "X" +# define PRIXFAST16 __PRIPTR_PREFIX "X" +# define PRIXFAST32 __PRIPTR_PREFIX "X" +# define PRIXFAST64 __PRI64_PREFIX "X" + + +/* Macros for printing `intmax_t' and `uintmax_t'. */ +# define PRIdMAX __PRI64_PREFIX "d" +# define PRIiMAX __PRI64_PREFIX "i" +# define PRIoMAX __PRI64_PREFIX "o" +# define PRIuMAX __PRI64_PREFIX "u" +# define PRIxMAX __PRI64_PREFIX "x" +# define PRIXMAX __PRI64_PREFIX "X" + + +/* Macros for printing `intptr_t' and `uintptr_t'. */ +# define PRIdPTR __PRIPTR_PREFIX "d" +# define PRIiPTR __PRIPTR_PREFIX "i" +# define PRIoPTR __PRIPTR_PREFIX "o" +# define PRIuPTR __PRIPTR_PREFIX "u" +# define PRIxPTR __PRIPTR_PREFIX "x" +# define PRIXPTR __PRIPTR_PREFIX "X" + + +/* Macros for scanning format specifiers. */ + +/* Signed decimal notation. */ +# define SCNd8 "hhd" +# define SCNd16 "hd" +# define SCNd32 "d" +# define SCNd64 __PRI64_PREFIX "d" + +# define SCNdLEAST8 "hhd" +# define SCNdLEAST16 "hd" +# define SCNdLEAST32 "d" +# define SCNdLEAST64 __PRI64_PREFIX "d" + +# define SCNdFAST8 "hhd" +# define SCNdFAST16 __PRIPTR_PREFIX "d" +# define SCNdFAST32 __PRIPTR_PREFIX "d" +# define SCNdFAST64 __PRI64_PREFIX "d" + +/* Signed decimal notation. */ +# define SCNi8 "hhi" +# define SCNi16 "hi" +# define SCNi32 "i" +# define SCNi64 __PRI64_PREFIX "i" + +# define SCNiLEAST8 "hhi" +# define SCNiLEAST16 "hi" +# define SCNiLEAST32 "i" +# define SCNiLEAST64 __PRI64_PREFIX "i" + +# define SCNiFAST8 "hhi" +# define SCNiFAST16 __PRIPTR_PREFIX "i" +# define SCNiFAST32 __PRIPTR_PREFIX "i" +# define SCNiFAST64 __PRI64_PREFIX "i" + +/* Unsigned decimal notation. */ +# define SCNu8 "hhu" +# define SCNu16 "hu" +# define SCNu32 "u" +# define SCNu64 __PRI64_PREFIX "u" + +# define SCNuLEAST8 "hhu" +# define SCNuLEAST16 "hu" +# define SCNuLEAST32 "u" +# define SCNuLEAST64 __PRI64_PREFIX "u" + +# define SCNuFAST8 "hhu" +# define SCNuFAST16 __PRIPTR_PREFIX "u" +# define SCNuFAST32 __PRIPTR_PREFIX "u" +# define SCNuFAST64 __PRI64_PREFIX "u" + +/* Octal notation. */ +# define SCNo8 "hho" +# define SCNo16 "ho" +# define SCNo32 "o" +# define SCNo64 __PRI64_PREFIX "o" + +# define SCNoLEAST8 "hho" +# define SCNoLEAST16 "ho" +# define SCNoLEAST32 "o" +# define SCNoLEAST64 __PRI64_PREFIX "o" + +# define SCNoFAST8 "hho" +# define SCNoFAST16 __PRIPTR_PREFIX "o" +# define SCNoFAST32 __PRIPTR_PREFIX "o" +# define SCNoFAST64 __PRI64_PREFIX "o" + +/* Hexadecimal notation. */ +# define SCNx8 "hhx" +# define SCNx16 "hx" +# define SCNx32 "x" +# define SCNx64 __PRI64_PREFIX "x" + +# define SCNxLEAST8 "hhx" +# define SCNxLEAST16 "hx" +# define SCNxLEAST32 "x" +# define SCNxLEAST64 __PRI64_PREFIX "x" + +# define SCNxFAST8 "hhx" +# define SCNxFAST16 __PRIPTR_PREFIX "x" +# define SCNxFAST32 __PRIPTR_PREFIX "x" +# define SCNxFAST64 __PRI64_PREFIX "x" + + +/* Macros for scanning `intmax_t' and `uintmax_t'. */ +# define SCNdMAX __PRI64_PREFIX "d" +# define SCNiMAX __PRI64_PREFIX "i" +# define SCNoMAX __PRI64_PREFIX "o" +# define SCNuMAX __PRI64_PREFIX "u" +# define SCNxMAX __PRI64_PREFIX "x" + +/* Macros for scaning `intptr_t' and `uintptr_t'. */ +# define SCNdPTR __PRIPTR_PREFIX "d" +# define SCNiPTR __PRIPTR_PREFIX "i" +# define SCNoPTR __PRIPTR_PREFIX "o" +# define SCNuPTR __PRIPTR_PREFIX "u" +# define SCNxPTR __PRIPTR_PREFIX "x" + +#endif /* C++ && format macros */ + + +#endif /* inttypes.h */ diff --git a/storage/pbxt/src/xaction_xt.cc b/storage/pbxt/src/xaction_xt.cc new file mode 100644 index 00000000000..be3cb650bcb --- /dev/null +++ b/storage/pbxt/src/xaction_xt.cc @@ -0,0 +1,2685 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-04-10 Paul McCullagh + * + * H&G2JCtL + */ + +#include "xt_config.h" + +#include <time.h> +#include <signal.h> + +#include "xaction_xt.h" +#include "database_xt.h" +#include "strutil_xt.h" +#include "heap_xt.h" +#include "trace_xt.h" +#include "myxt_xt.h" +#include "tabcache_xt.h" + +#ifdef DEBUG +//#define TRACE_WAIT_FOR +//#define TRACE_VARIATIONS +//#define TRACE_SWEEPER_ACTIVITY + +/* Enable to trace the statements executed by the engine: */ +//#define TRACE_STATEMENTS +#endif + +#if defined(TRACE_STATEMENTS) || defined(TRACE_VARIATIONS) +#define TRACE_TRANSACTION +#endif + +static void xn_sw_wait_for_xact(XTThreadPtr self, XTDatabaseHPtr db, u_int hsecs); +static xtBool xn_get_xact_details(XTDatabaseHPtr db, xtXactID xn_id, XTThreadPtr thread __attribute__((unused)), int *flags, xtXactID *start, xtXactID *end, xtThreadID *thd_id); +static xtBool xn_get_xact_pointer(XTDatabaseHPtr db, xtXactID xn_id, XTXactDataPtr *xact_ptr); + +/* ============================================================================================== */ + +typedef struct XNSWRecItem { + xtTableID ri_tab_id; + xtRecordID ri_rec_id; +} XNSWRecItemRec, *XNSWRecItemPtr; + +typedef struct XNSWToFreeItem { + xtTableID ri_tab_id; /* If non-zero, then this is the table of the data record to be freed. + * If zero, then this free the transaction below must be freed. + */ + union { + xtRecordID ri_rec_id; + xtXactID ri_xn_id; + } x; + xtXactID ri_wait_xn_id; /* Wait for this transaction to be cleaned (or being cleaned up) + * before freeing this resource. */ +} XNSWToFreeItemRec, *XNSWToFreeItemPtr; + +/* ---------------------------------------------------------------------- + * TRANSACTION/THREAD WAIT LIST + */ + +typedef struct XNWaitThread { + /* The wait condition of the thread. */ + xt_mutex_type wt_lock; + xt_cond_type wt_cond; + + /* The list of threads waiting for this thread. */ + XTSpinLockRec wt_wait_list_lock; + u_int wt_wait_list_count; + u_int wt_wait_list_size; + xtThreadID *wt_wait_list; +} XNWaitThreadRec, *XNWaitThreadPtr; + +static XNWaitThreadPtr xn_wait_thread_array; + +xtPublic void xt_thread_wait_init(XTThreadPtr self) +{ + xn_wait_thread_array = (XNWaitThreadPtr) xt_calloc(self, xt_thr_maximum_threads * sizeof(XNWaitThreadRec)); + for (u_int i=0; i<xt_thr_maximum_threads; i++) { + xt_init_mutex_with_autoname(self, &xn_wait_thread_array[i].wt_lock); + xt_init_cond(self, &xn_wait_thread_array[i].wt_cond); + xn_wait_thread_array[i].wt_wait_list = NULL; + xn_wait_thread_array[i].wt_wait_list_count = 0; + xn_wait_thread_array[i].wt_wait_list_size = 0; + xt_spinlock_init_with_autoname(self, &xn_wait_thread_array[i].wt_wait_list_lock); + } +} + +xtPublic void xt_thread_wait_exit(XTThreadPtr self) +{ + if (xn_wait_thread_array) { + for (u_int i=0; i<xt_thr_maximum_threads; i++) { + xt_free_mutex(&xn_wait_thread_array[i].wt_lock); + xt_free_cond(&xn_wait_thread_array[i].wt_cond); + if (xn_wait_thread_array[i].wt_wait_list) + xt_free(self, xn_wait_thread_array[i].wt_wait_list); + xt_spinlock_free(self, &xn_wait_thread_array[i].wt_wait_list_lock); + } + xt_free(self, xn_wait_thread_array); + } +} + +static xtBool xn_wait_for_thread(xtThreadID waiting_id, xtThreadID wait_for_id) +{ + XNWaitThreadPtr wt; + + wt = &xn_wait_thread_array[wait_for_id]; + xt_spinlock_lock(&wt->wt_wait_list_lock); + if (wt->wt_wait_list_count == wt->wt_wait_list_size) { + if (!xt_realloc_ns((void **) &wt->wt_wait_list, (wt->wt_wait_list_size+1) * sizeof(xtThreadID))) + return FAILED; + wt->wt_wait_list_size++; + } + for (u_int i=0; i<wt->wt_wait_list_count; i++) { + if (wt->wt_wait_list[i] == waiting_id) + goto done; + } + wt->wt_wait_list[wt->wt_wait_list_count] = waiting_id; + wt->wt_wait_list_count++; + done: + xt_spinlock_unlock(&wt->wt_wait_list_lock); + return OK; +} + +xtPublic void xt_xn_wakeup_thread(xtThreadID thd_id) +{ + XNWaitThreadPtr target_wt; + + target_wt = &xn_wait_thread_array[thd_id]; + xt_lock_mutex_ns(&target_wt->wt_lock); + xt_broadcast_cond_ns(&target_wt->wt_cond); + xt_unlock_mutex_ns(&target_wt->wt_lock); +} + +xtPublic void xt_xn_wakeup_thread_list(XTThreadPtr thread) +{ + XNWaitThreadPtr target_wt; + + for (u_int i=0; i<thread->st_thread_list_count; i++) { + target_wt = &xn_wait_thread_array[thread->st_thread_list[i]]; + xt_lock_mutex_ns(&target_wt->wt_lock); + xt_broadcast_cond_ns(&target_wt->wt_cond); + xt_unlock_mutex_ns(&target_wt->wt_lock); + } + thread->st_thread_list_count = 0; +} + +xtPublic void xt_xn_wakeup_waiting_threads(XTThreadPtr thread) +{ + XNWaitThreadPtr wt; + XNWaitThreadPtr target_wt; + + wt = &xn_wait_thread_array[thread->t_id]; + if (!wt->wt_wait_list_count) + return; + + xt_spinlock_lock(&wt->wt_wait_list_lock); + if (thread->st_thread_list_size < wt->wt_wait_list_count) { + if (!xt_realloc_ns((void **) &thread->st_thread_list, wt->wt_wait_list_count * sizeof(xtThreadID))) + goto failed; + thread->st_thread_list_size = wt->wt_wait_list_count; + } + memcpy(thread->st_thread_list, wt->wt_wait_list, wt->wt_wait_list_count * sizeof(xtThreadID)); + thread->st_thread_list_count = wt->wt_wait_list_count; + wt->wt_wait_list_count = 0; + xt_spinlock_unlock(&wt->wt_wait_list_lock); + + xt_xn_wakeup_thread_list(thread); + return; + + failed: + for (u_int i=0; i<wt->wt_wait_list_count; i++) { + target_wt = &xn_wait_thread_array[wt->wt_wait_list[i]]; + xt_lock_mutex_ns(&target_wt->wt_lock); + xt_broadcast_cond_ns(&target_wt->wt_cond); + xt_unlock_mutex_ns(&target_wt->wt_lock); + } + wt->wt_wait_list_count = 0; + xt_spinlock_unlock(&wt->wt_wait_list_lock); +} + +/* ---------------------------------------------------------------------- + * WAIT FOR TRANSACTIONS + */ + +typedef struct XNWaitFor { + xtXactID wf_waiting_xn_id; /* The transaction of the waiting thread. */ + xtXactID wf_for_me_xn_id; /* The transaction we are waiting for. */ +} XNWaitForRec, *XNWaitForPtr; + +static int xn_compare_wait_for(XTThreadPtr XT_UNUSED(self), register const void XT_UNUSED(*thunk), register const void *a, register const void *b) +{ + xtXactID *x = (xtXactID *) a; + XNWaitForPtr y = (XNWaitForPtr) b; + + if (*x == y->wf_waiting_xn_id) + return 0; + if (xt_xn_is_before(*x, y->wf_waiting_xn_id)) + return -1; + return 1; +} + +static void xn_free_wait_for(XTThreadPtr XT_UNUSED(self), void XT_UNUSED(*thunk), void XT_UNUSED(*item)) +{ +} + +/* + * A deadlock occurs when a transaction is waiting for itself! + * For example A is waiting for B which is waiting for A. + * By repeatedly scanning the wait_for list we can find out if a + * transaction is waiting for itself. + */ +static xtBool xn_detect_deadlock(XTDatabaseHPtr db, xtXactID waiting, xtXactID for_me) +{ + XNWaitForPtr wf; + + for (;;) { + if (waiting == for_me) { +#ifdef TRACE_WAIT_FOR + for (u_int i=0; i<xt_sl_get_size(db->db_xn_wait_for); i++) { + wf = (XNWaitForPtr) xt_sl_item_at(db->db_xn_wait_for, i); + xt_trace("T%lu --> T%lu\n", (u_long) wf->wf_waiting_xn_id, (u_long) wf->wf_for_me_xn_id); + } + xt_ttracef(xt_get_self(), "DEADLOCK\n"); + xt_dump_trace(); +#endif + xt_register_xterr(XT_REG_CONTEXT, XT_ERR_DEADLOCK); + return TRUE; + } + if (!(wf = (XNWaitForPtr) xt_sl_find(NULL, db->db_xn_wait_for, &for_me))) + break; + for_me = wf->wf_for_me_xn_id; + } + return FALSE; +} + +#ifdef XT_USE_SPINLOCK_WAIT_FOR + +#if defined(XT_MAC) || defined(XT_WIN) +#define WAIT_SPIN_COUNT 10 +#else +#define WAIT_SPIN_COUNT 50 +#endif + +/* Should not be required, but we wait for a second, + * just in case the wakeup is missed! + */ +#ifdef DEBUG +#define WAIT_FOR_XACT_TIME 30000 +#else +#define WAIT_FOR_XACT_TIME 1000 +#endif + +static xtBool xn_add_to_wait_for(XTDatabaseHPtr db, XNWaitForPtr wf, XTThreadPtr thread) +{ + /* If we are waiting for a transaction to end, + * put this thread on the wait list... + * + * As long as the temporary lock is removed + * or turned into a permanent lock before + * a thread waits again, all should be OK! + */ + xt_spinlock_lock(&db->db_xn_wait_spinlock); + +#ifdef TRACE_WAIT_FOR + xt_ttracef(thread, "T%lu -wait-> T%lu\n", (u_long) thread->st_xact_data->xd_start_xn_id, (u_long) wait_xn_id); +#endif + /* Check for a deadlock: */ + if (xn_detect_deadlock(db, wf->wf_waiting_xn_id, wf->wf_for_me_xn_id)) + goto failed; + + /* We will wait for this transaction... */ + db->db_xn_wait_count++; + if (thread->st_xact_writer) + db->db_xn_writer_wait_count++; + + if (!xt_sl_insert(NULL, db->db_xn_wait_for, &wf->wf_waiting_xn_id, wf)) { + db->db_xn_wait_count--; + goto failed; + } + + xt_spinlock_unlock(&db->db_xn_wait_spinlock); + return OK; + + failed: + xt_spinlock_unlock(&db->db_xn_wait_spinlock); + return FAILED; +} + +inline void xn_remove_from_wait_for(XTDatabaseHPtr db, XNWaitForPtr wf, XTThreadPtr thread) +{ + xt_spinlock_lock(&db->db_xn_wait_spinlock); + + xt_sl_delete(NULL, db->db_xn_wait_for, &wf->wf_waiting_xn_id); + db->db_xn_wait_count--; + if (thread->st_xact_writer) + db->db_xn_writer_wait_count--; + +#ifdef TRACE_WAIT_FOR + xt_ttracef(thread, "T%lu -wait-> T%lu FAILED\n", (u_long) thread->st_xact_data->xd_start_xn_id, (u_long) wait_xn_id); +#endif + xt_spinlock_unlock(&db->db_xn_wait_spinlock); +} + +/* Wait for a transation to terminate or a lock to be granted. + * + * If term_req is TRUE, then the termination of the transaction is required + * before continuing. + * + * If pw_func is set then this function will not return before this call has + * succeeded. + * + * This function returns FAILE on error. + */ +xtPublic xtBool xt_xn_wait_for_xact(XTThreadPtr thread, XTXactWaitPtr xw, XTLockWaitPtr lw) +{ + XTDatabaseHPtr db = thread->st_database; + XNWaitForRec wf; + int flags = 0; + xtXactID start = 0; + XTXactDataPtr wait_xact_ptr; + xtBool on_wait_list = FALSE; + XTXactWaitRec xw_new; + u_int loop_count = 0; + XNWaitThreadPtr my_wt; + + ASSERT_NS(thread->st_xact_data); + thread->st_statistics.st_wait_for_xact++; + + wf.wf_waiting_xn_id = thread->st_xact_data->xd_start_xn_id; + + if (lw) { + /* If we are here, then the lw structure is on the wait + * queue for the given lock. + */ + xtXactID locking_xn_id; + + wait_for_locker: + locking_xn_id = lw->lw_xn_id; + wf.wf_for_me_xn_id = lw->lw_xn_id; + if (!xn_add_to_wait_for(db, &wf, thread)) { + lw->lw_ot->ot_table->tab_locks.xt_cancel_temp_lock(lw); + return FAILED; + } + + while (loop_count < WAIT_SPIN_COUNT) { + loop_count++; + + switch (lw->lw_curr_lock) { + case XT_LOCK_ERR: + xn_remove_from_wait_for(db, &wf, thread); + return FAILED; + case XT_NO_LOCK: + /* Got the lock: */ + /* Check if we must also wait for the transaction: */ + if (lw->lw_row_updated) { + /* This will override the xw passed in. + * The reason is, because we are actually waiting + * for a lock, and the lock owner may have changed + * while we were waiting for the lock. + */ + xw_new.xw_xn_id = lw->lw_updating_xn_id; + xw = &xw_new; + } + if (xw) { + if (wf.wf_for_me_xn_id == xw->xw_xn_id) + on_wait_list = TRUE; + else + xn_remove_from_wait_for(db, &wf, thread); + goto wait_for_xact; + } + xn_remove_from_wait_for(db, &wf, thread); + return OK; + case XT_TEMP_LOCK: + case XT_PERM_LOCK: + if (locking_xn_id != lw->lw_xn_id) { + /* Change the transaction that we are waiting for: */ + xn_remove_from_wait_for(db, &wf, thread); + goto wait_for_locker; + } + break; + } + + xt_critical_wait(); + } + + + /* The non-spinning version... */ + wait_for_locker_no_spin: + my_wt = &xn_wait_thread_array[thread->t_id]; + xt_lock_mutex_ns(&my_wt->wt_lock); + + for (;;) { + switch (lw->lw_curr_lock) { + case XT_LOCK_ERR: + xt_unlock_mutex_ns(&my_wt->wt_lock); + xn_remove_from_wait_for(db, &wf, thread); + return FAILED; + case XT_NO_LOCK: + xt_unlock_mutex_ns(&my_wt->wt_lock); + if (lw->lw_row_updated) { + xw_new.xw_xn_id = lw->lw_updating_xn_id; + xw = &xw_new; + } + if (xw) { + if (wf.wf_for_me_xn_id == xw->xw_xn_id) + on_wait_list = TRUE; + else + xn_remove_from_wait_for(db, &wf, thread); + goto wait_for_xact; + } + xn_remove_from_wait_for(db, &wf, thread); + return OK; + case XT_TEMP_LOCK: + case XT_PERM_LOCK: + if (locking_xn_id != lw->lw_xn_id) { + /* Change the transaction that we are waiting for: */ + xt_unlock_mutex_ns(&my_wt->wt_lock); + xn_remove_from_wait_for(db, &wf, thread); + locking_xn_id = lw->lw_xn_id; + wf.wf_for_me_xn_id = lw->lw_xn_id; + if (!xn_add_to_wait_for(db, &wf, thread)) { + lw->lw_ot->ot_table->tab_locks.xt_cancel_temp_lock(lw); + return FAILED; + } + goto wait_for_locker_no_spin; + } + break; + } + + xt_timed_wait_cond_ns(&my_wt->wt_cond, &my_wt->wt_lock, WAIT_FOR_XACT_TIME); + } + + xt_unlock_mutex_ns(&my_wt->wt_lock); + } + + if (xw) { + xtThreadID tn_thd_id; + + wait_for_xact: + wf.wf_for_me_xn_id = xw->xw_xn_id; + + if (!xn_get_xact_pointer(db, xw->xw_xn_id, &wait_xact_ptr)) + /* The transaction was not found... */ + goto wait_done; + + if (wait_xact_ptr) { + /* This is a dirty read, but it should work! */ + flags = wait_xact_ptr->xd_flags; + start = wait_xact_ptr->xd_start_xn_id; + tn_thd_id = wait_xact_ptr->xd_thread_id; + } + else { + tn_thd_id = 0; + if (!xn_get_xact_details(db, xw->xw_xn_id, thread, &flags, &start, NULL, &tn_thd_id)) + flags = XT_XN_XAC_ENDED | XT_XN_XAC_SWEEP; + } + + if ((flags & XT_XN_XAC_ENDED) || start != xw->xw_xn_id) + /* The transaction has terminated! */ + goto wait_done; + + /* Tell the thread we are waiting for it: */ + xn_wait_for_thread(thread->t_id, tn_thd_id); + + if (!on_wait_list) { + if (!xn_add_to_wait_for(db, &wf, thread)) + return FAILED; + on_wait_list = TRUE; + } + + /* The spinning version: */ + while (loop_count < WAIT_SPIN_COUNT) { + loop_count++; + + xt_critical_wait(); + + if (wait_xact_ptr) { + /* This is a dirty read, but it should work! */ + flags = wait_xact_ptr->xd_flags; + start = wait_xact_ptr->xd_start_xn_id; + } + else { + if (!xn_get_xact_details(db, xw->xw_xn_id, thread, &flags, &start, NULL, NULL)) + flags = XT_XN_XAC_ENDED | XT_XN_XAC_SWEEP; + } + + if ((flags & XT_XN_XAC_ENDED) || start != xw->xw_xn_id) + /* The transaction has terminated! */ + goto wait_done; + } + + /* The non-spinning version: + * + * I believe I can avoid missing the wakeup signal + * by locking before we check if the transaction + * is still running. + * + * Even though db->db_xn_wait_on_cond is "dirty read". + * + * The reason is, before the signal is sent the + * lock is also aquired. This is not possible until + * this thread is safely sleaping. + */ + my_wt = &xn_wait_thread_array[thread->t_id]; + xt_lock_mutex_ns(&my_wt->wt_lock); + + for (;;) { + if (wait_xact_ptr) { + /* This is a dirty read, but it should work! */ + flags = wait_xact_ptr->xd_flags; + start = wait_xact_ptr->xd_start_xn_id; + } + else { + if (!xn_get_xact_details(db, xw->xw_xn_id, thread, &flags, &start, NULL, NULL)) + flags = XT_XN_XAC_ENDED | XT_XN_XAC_SWEEP; + } + + if ((flags & XT_XN_XAC_ENDED) || start != xw->xw_xn_id) + /* The transaction has terminated! */ + break; + + xt_timed_wait_cond_ns(&my_wt->wt_cond, &my_wt->wt_lock, WAIT_FOR_XACT_TIME); + } + + xt_unlock_mutex_ns(&my_wt->wt_lock); + + wait_done: + if (on_wait_list) + xn_remove_from_wait_for(db, &wf, thread); + } + + return OK; +} + +#else // XT_USE_SPINLOCK_WAIT_FOR +/* + * The given thread must wait for the specified transaction to terminate. This + * function places the transaction of the thread on a list of waiting threads. + * + * Before waiting we make a check for deadlocks. A deadlock occurs + * if waiting would introduce a cycle. + */ +xtPublic xtBool old_xt_xn_wait_for_xact(XTThreadPtr thread, xtXactID xn_id, xtBool will_retry, XTLockWaitFuncPtr pw_func, XTLockWaitPtr pw_data) +{ + XTDatabaseHPtr db = thread->st_database; + XNWaitForRec wf; + int flags = 0; + xtXactID start = 0; + + ASSERT_NS(thread->st_xact_data); + + thread->st_statistics.st_wait_for_xact++; + wf.wf_waiting_xn_id = thread->st_xact_data->xd_start_xn_id; + wf.wf_for_me_xn_id = xn_id; + wf.wf_thread_id = thread->t_id; + + xt_lock_mutex_ns(&db->db_xn_wait_lock); + +#ifdef TRACE_WAIT_FOR + xt_ttracef(thread, "T%lu -wait-> T%lu\n", (u_long) thread->st_xact_data->xd_start_xn_id, (u_long) xn_id); +#endif + for (;;) { + if (!xn_get_xact_details(db, xn_id, thread, &flags, &start, NULL, NULL)) + break; + + /* This is a dirty read, but it should work! */ + if ((flags & XT_XN_XAC_ENDED) || start != xn_id) + break; + + if (xn_detect_deadlock(db, wf.wf_waiting_xn_id, wf.wf_for_me_xn_id)) + goto failed; + + /* We will wait for this transaction... */ + db->db_xn_wait_count++; + if (thread->st_xact_writer) + db->db_xn_writer_wait_count++; + + if (!xt_sl_insert(NULL, db->db_xn_wait_for, &wf.wf_waiting_xn_id, &wf)) { + db->db_xn_wait_count--; + goto failed; + } + + if (!xn_get_xact_details(db, xn_id, thread, &flags, &start, NULL, NULL)) { + xt_sl_delete(NULL, db->db_xn_wait_for, &wf.wf_waiting_xn_id); + db->db_xn_wait_count--; + if (thread->st_xact_writer) + db->db_xn_writer_wait_count--; + break; + } + + if ((flags & XT_XN_XAC_ENDED) || start != xn_id) { + xt_sl_delete(NULL, db->db_xn_wait_for, &wf.wf_waiting_xn_id); + db->db_xn_wait_count--; + if (thread->st_xact_writer) + db->db_xn_writer_wait_count--; + break; + } + + db->db_xn_post_wait[thread->t_id].pw_call_me = pw_func; + db->db_xn_post_wait[thread->t_id].pw_thread = thread; + db->db_xn_post_wait[thread->t_id].pw_data = pw_data; + + /* Timed wait because it is possible that transaction quits before + * we go to sleep. + */ + if (!xt_timed_wait_cond(NULL, &db->db_xn_wait_cond, &db->db_xn_wait_lock, 2 * 1000)) { + xt_sl_delete(NULL, db->db_xn_wait_for, &wf.wf_waiting_xn_id); + db->db_xn_wait_count--; + if (thread->st_xact_writer) + db->db_xn_writer_wait_count--; + goto failed; + } + + db->db_xn_post_wait[thread->t_id].pw_call_me = NULL; + xt_sl_delete(NULL, db->db_xn_wait_for, &wf.wf_waiting_xn_id); + db->db_xn_wait_count--; + if (thread->st_xact_writer) + db->db_xn_writer_wait_count--; + + if (will_retry) + break; + } + +#ifdef TRACE_WAIT_FOR + xt_ttracef(thread, "T%lu -wait-> T%lu DONE\n", (u_long) thread->st_xact_data->xd_start_xn_id, (u_long) xn_id); +#endif + xt_unlock_mutex_ns(&db->db_xn_wait_lock); + return OK; + + failed: +#ifdef TRACE_WAIT_FOR + xt_ttracef(self, "T%lu -wait-> T%lu FAILED\n", (u_long) self->st_xact_data->xd_start_xn_id, (u_long) xn_id); +#endif + xt_unlock_mutex_ns(&db->db_xn_wait_lock); + return FAILED; +} + +xtPublic void old_xt_xn_wakeup_transactions(XTDatabaseHPtr db, XTThreadPtr thread) +{ + u_int len; + XNWaitForPtr wf; + + xt_lock_mutex_ns(&db->db_xn_wait_lock); + /* The idea here is to release the oldest transactions + * first. Although this may not be completely fair + * it has the advantage that older transactions are + * encouraged to complete first. + * + * I have found the following problem with this test: + * runTest(INCREMENT_TEST, 16, INCREMENT_TEST_UPDATE_COUNT); + * with a bit of bad luck a transaction can be starved. + * This results in the sweeper stalling because it is + * waiting for an old transaction to quite so that + * it continue. + * + * Because the sweeper is waiting, the number of + * versions of the record to be updated + * begins to increase. In the above test over + * 1600 transaction remain uncleaned. + * + * This means that there are 1600 version of the + * row which must be scanned to find the most + * recent version. + */ + if ((len = (u_int) xt_sl_get_size(db->db_xn_wait_for))) { + for (u_int i=0; i<len; i++) { + wf = (XNWaitForPtr) xt_sl_item_at(db->db_xn_wait_for, i); + if (db->db_xn_post_wait[wf->wf_thread_id].pw_call_me) { + if (db->db_xn_post_wait[wf->wf_thread_id].pw_call_me(thread, &db->db_xn_post_wait[wf->wf_thread_id])) + db->db_xn_post_wait[wf->wf_thread_id].pw_call_me = NULL; + } + } + if (!xt_broadcast_cond_ns(&db->db_xn_wait_cond)) + xt_log_and_clear_exception_ns(); + } + ASSERT_NS(db->db_xn_wait_count == len); + xt_unlock_mutex_ns(&db->db_xn_wait_lock); +} +#endif // XT_USE_SPINLOCK_WAIT_FOR + +/* ---------------------------------------------------------------------- + * Utilities + */ + +//#define HIGH_X +#ifdef HIGH_X +u_long tot_alloced; +u_long high_alloced; +u_long not_clean_max; +u_long in_ram_max; +#endif + +static void xn_free_xact(XTDatabaseHPtr db, XTXactSegPtr seg, XTXactDataPtr xact) +{ +#ifdef HIGH_X + tot_alloced--; +#endif + /* This indicates the structure is free: */ + xact->xd_start_xn_id = 0; + if ((xtWord1 *) xact >= db->db_xn_data && (xtWord1 *) xact < db->db_xn_data_end) { + /* Put it in the free list: */ + xact->xd_next_xact = seg->xs_free_list; + seg->xs_free_list = xact; + return; + } + xt_free_ns(xact); +} + +/* + * GOTCHA: The value db->db_xn_curr_id may be a bit larger + * than the actual transaction created because there is + * a gap between the issude of the transaction ID + * and the creation of a memory structure. + * (indicated here: {GAP-INC-ADD-XACT}) + * + * This function returns the actuall current transaction ID. + * This is the number of the last transaction actually + * created in memory. + * + * This means that if you call xt_xn_get_xact() with any + * number less than or equal to this value, not finding + * the transaction means it has already ended! + */ +xtPublic xtXactID xt_xn_get_curr_id(XTDatabaseHPtr db) +{ + int i; + xtXactID curr_xn_id; + register XTXactSegPtr seg = db->db_xn_idx; + + /* Find the highest transaction ID actually created... */ + curr_xn_id = seg->xs_last_xn_id; + seg++; + for (i=1; i<XT_XN_NO_OF_SEGMENTS; i++, seg++) { + if (xt_xn_is_before(curr_xn_id, seg->xs_last_xn_id)) + curr_xn_id = seg->xs_last_xn_id; + } + return curr_xn_id; +} + +xtPublic XTXactDataPtr xt_xn_add_old_xact(XTDatabaseHPtr db, xtXactID xn_id, XTThreadPtr thread __attribute__((unused))) +{ + register XTXactDataPtr xact; + register XTXactSegPtr seg; + register XTXactDataPtr *hash; + + seg = &db->db_xn_idx[xn_id & XT_XN_SEGMENT_MASK]; + XT_XACT_WRITE_LOCK(&seg->xs_tab_lock, thread); + hash = &seg->xs_table[(xn_id >> XT_XN_SEGMENT_SHIFTS) % XT_XN_HASH_TABLE_SIZE]; + xact = *hash; + while (xact) { + if (xact->xd_start_xn_id == xn_id) + goto done_ok; + xact = xact->xd_next_xact; + } + + if ((xact = seg->xs_free_list)) + seg->xs_free_list = xact->xd_next_xact; + else { + /* We have used up all the free transaction slots, + * the sweeper should work faster to free them + * up... + */ + db->db_sw_faster |= XT_SW_NO_MORE_XACT_SLOTS; + if (!(xact = (XTXactDataPtr) xt_malloc_ns(sizeof(XTXactDataRec)))) { + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); + return NULL; + } + } + + xact->xd_next_xact = *hash; + *hash = xact; + + xact->xd_start_xn_id = xn_id; + xact->xd_end_xn_id = 0; + xact->xd_end_time = 0; + xact->xd_begin_log = 0; + xact->xd_flags = 0; + + /* Get the largest transaction id. */ + if (xt_xn_is_before(seg->xs_last_xn_id, xn_id)) + seg->xs_last_xn_id = xn_id; + + done_ok: + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); +#ifdef HIGH_X + tot_alloced++; + if (tot_alloced > high_alloced) + high_alloced = tot_alloced; +#endif + return xact; +} + +static XTXactDataPtr xn_add_new_xact(XTDatabaseHPtr db, xtXactID xn_id, XTThreadPtr thread __attribute__((unused))) +{ + register XTXactDataPtr xact; + register XTXactSegPtr seg; + register XTXactDataPtr *hash; + + seg = &db->db_xn_idx[xn_id & XT_XN_SEGMENT_MASK]; + XT_XACT_WRITE_LOCK(&seg->xs_tab_lock, thread); + hash = &seg->xs_table[(xn_id >> XT_XN_SEGMENT_SHIFTS) % XT_XN_HASH_TABLE_SIZE]; + + if ((xact = seg->xs_free_list)) + seg->xs_free_list = xact->xd_next_xact; + else { + /* We have used up all the free transaction slots, + * the sweeper should work faster to free them + * up... + */ + db->db_sw_faster |= XT_SW_NO_MORE_XACT_SLOTS; + if (!(xact = (XTXactDataPtr) xt_malloc_ns(sizeof(XTXactDataRec)))) { + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); + return NULL; + } + } + + xact->xd_next_xact = *hash; + *hash = xact; + + xact->xd_thread_id = thread->t_id; + xact->xd_start_xn_id = xn_id; + xact->xd_end_xn_id = 0; + xact->xd_end_time = 0; + xact->xd_begin_log = 0; + xact->xd_flags = 0; + + seg->xs_last_xn_id = xn_id; + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); +#ifdef HIGH_X + tot_alloced++; + if (tot_alloced > high_alloced) + high_alloced = tot_alloced; +#endif + return xact; +} + +static xtBool xn_get_xact_details(XTDatabaseHPtr db, xtXactID xn_id, XTThreadPtr thread __attribute__((unused)), int *flags, xtXactID *start, xtWord4 *end, xtThreadID *thd_id) +{ + register XTXactSegPtr seg; + register XTXactDataPtr xact; + xtBool found = FALSE; + + seg = &db->db_xn_idx[xn_id & XT_XN_SEGMENT_MASK]; + XT_XACT_READ_LOCK(&seg->xs_tab_lock, thread); + xact = seg->xs_table[(xn_id >> XT_XN_SEGMENT_SHIFTS) % XT_XN_HASH_TABLE_SIZE]; + while (xact) { + if (xact->xd_start_xn_id == xn_id) { + found = TRUE; + if (flags) + *flags = xact->xd_flags; + if (start) + *start = xact->xd_start_xn_id; + if (end) + *end = xact->xd_end_time; + if (thd_id) + *thd_id = xact->xd_thread_id; + break; + } + xact = xact->xd_next_xact; + } + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); + return found; +} + +static xtBool xn_get_xact_pointer(XTDatabaseHPtr db, xtXactID xn_id, XTXactDataPtr *xact_ptr) +{ + register XTXactSegPtr seg; + register XTXactDataPtr xact; + xtBool found = FALSE; + + *xact_ptr = NULL; + seg = &db->db_xn_idx[xn_id & XT_XN_SEGMENT_MASK]; + XT_XACT_READ_LOCK(&seg->xs_tab_lock, thread); + xact = seg->xs_table[(xn_id >> XT_XN_SEGMENT_SHIFTS) % XT_XN_HASH_TABLE_SIZE]; + while (xact) { + if (xact->xd_start_xn_id == xn_id) { + found = TRUE; + /* We only return pointers to transaction structures that are permanently + * allocated! + */ + if ((xtWord1 *) xact >= db->db_xn_data && (xtWord1 *) xact < db->db_xn_data_end) + *xact_ptr = xact; + break; + } + xact = xact->xd_next_xact; + } + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); + return found; +} + +static xtBool xn_get_xact_start(XTDatabaseHPtr db, xtXactID xn_id, XTThreadPtr thread __attribute__((unused)), xtLogID *log_id, xtLogOffset *log_offset) +{ + register XTXactSegPtr seg; + register XTXactDataPtr xact; + xtBool found = FALSE; + + seg = &db->db_xn_idx[xn_id & XT_XN_SEGMENT_MASK]; + XT_XACT_READ_LOCK(&seg->xs_tab_lock, thread); + xact = seg->xs_table[(xn_id >> XT_XN_SEGMENT_SHIFTS) % XT_XN_HASH_TABLE_SIZE]; + while (xact) { + if (xact->xd_start_xn_id == xn_id) { + found = TRUE; + *log_id = xact->xd_begin_log; + *log_offset = xact->xd_begin_offset; + break; + } + xact = xact->xd_next_xact; + } + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); + return found; +} + +/* NOTE: this function may only be used by the sweeper or the recovery process. */ +xtPublic XTXactDataPtr xt_xn_get_xact(XTDatabaseHPtr db, xtXactID xn_id, XTThreadPtr thread __attribute__((unused))) +{ + register XTXactSegPtr seg; + register XTXactDataPtr xact; + + seg = &db->db_xn_idx[xn_id & XT_XN_SEGMENT_MASK]; + XT_XACT_READ_LOCK(&seg->xs_tab_lock, thread); + xact = seg->xs_table[(xn_id >> XT_XN_SEGMENT_SHIFTS) % XT_XN_HASH_TABLE_SIZE]; + while (xact) { + if (xact->xd_start_xn_id == xn_id) + break; + xact = xact->xd_next_xact; + } + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); + return xact; +} + +/* + * Delete a transaction, return TRUE if the transaction + * was found. + */ +xtPublic xtBool xt_xn_delete_xact(XTDatabaseHPtr db, xtXactID xn_id, XTThreadPtr thread __attribute__((unused))) +{ + XTXactDataPtr xact, pxact = NULL; + XTXactSegPtr seg; + + seg = &db->db_xn_idx[xn_id & XT_XN_SEGMENT_MASK]; + XT_XACT_WRITE_LOCK(&seg->xs_tab_lock, thread); + xact = seg->xs_table[(xn_id >> XT_XN_SEGMENT_SHIFTS) % XT_XN_HASH_TABLE_SIZE]; + while (xact) { + if (xact->xd_start_xn_id == xn_id) { + if (pxact) + pxact->xd_next_xact = xact->xd_next_xact; + else + seg->xs_table[(xn_id >> XT_XN_SEGMENT_SHIFTS) % XT_XN_HASH_TABLE_SIZE] = xact->xd_next_xact; + xn_free_xact(db, seg, xact); + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); + return TRUE; + } + pxact = xact; + xact = xact->xd_next_xact; + } + XT_XACT_UNLOCK(&seg->xs_tab_lock, thread); + return FALSE; +} + +//#define DEBUG_RAM_LIST +#ifdef DEBUG_RAM_LIST + +#define DEBUG_RAM_LIST_SIZE 80 + +int check_ram_init_count = 0; +xt_rwlock_type check_ram_lock; +xtXactID check_ram_trns[DEBUG_RAM_LIST_SIZE]; +int check_ram_dummy; + +static void check_ram_init(void) +{ + if (check_ram_init_count == 0) + xt_init_rwlock(NULL, &check_ram_lock); + check_ram_init_count++; +} + +static void check_ram_free(void) +{ + check_ram_init_count--; + if (check_ram_init_count == 0) + xt_free_rwlock(&check_ram_lock); +} + +static void check_ram_min_id(XTDatabaseHPtr db) +{ + int i; + + xt_slock_rwlock_ns(&check_ram_lock); + for (i=0; i<DEBUG_RAM_LIST_SIZE; i++) { + if (check_ram_trns[i] && xt_xn_is_before(check_ram_trns[i], db->db_xn_min_ram_id)) { + /* This should never happen! */ + XTXactDataPtr x_ptr; + + check_ram_dummy = 0; + for (i=0; i<DEBUG_RAM_LIST_SIZE; i++) { + if (check_ram_trns[i]) { + x_ptr = xt_xn_get_xact(db, check_ram_trns[i]); + check_ram_dummy = 1; + } + } + break; + } + } + xt_unlock_rwlock_ns(&check_ram_lock); +} + +static void check_ram_add(xtXactID xn_id) +{ + int i; + + xt_xlock_rwlock_ns(&check_ram_lock); + for (i=0; i<DEBUG_RAM_LIST_SIZE; i++) { + if (!check_ram_trns[i]) { + check_ram_trns[i] = xn_id; + xt_unlock_rwlock_ns(&check_ram_lock); + return; + } + } + xt_unlock_rwlock_ns(&check_ram_lock); + printf("DEBUG --- List too small\n"); +} + +static void check_ram_del(xtXactID xn_id) +{ + int i; + + xt_xlock_rwlock_ns(&check_ram_lock); + for (i=0; i<DEBUG_RAM_LIST_SIZE; i++) { + if (check_ram_trns[i] == xn_id) { + check_ram_trns[i] = 0; + xt_unlock_rwlock_ns(&check_ram_lock); + return; + } + } + xt_unlock_rwlock_ns(&check_ram_lock); +} +#endif + +/* ---------------------------------------------------------------------- + * Init and Exit + */ + +xtPublic void xt_xn_init_db(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTXactDataPtr xact; + XTXactSegPtr seg; + +#ifdef DEBUG_RAM_LIST + check_ram_init(); +#endif + xt_spinlock_init_with_autoname(self, &db->db_xn_id_lock); + xt_spinlock_init_with_autoname(self, &db->db_xn_wait_spinlock); + //xt_init_mutex_with_autoname(self, &db->db_xn_wait_lock); + //xt_init_cond(self, &db->db_xn_wait_cond); + xt_init_mutex_with_autoname(self, &db->db_sw_lock); + xt_init_cond(self, &db->db_sw_cond); + xt_init_mutex_with_autoname(self, &db->db_wr_lock); + xt_init_cond(self, &db->db_wr_cond); + + /* Pre-allocate transaction data structures: */ + db->db_xn_data = (xtWord1 *) xt_malloc(self, sizeof(XTXactDataRec) * XT_XN_DATA_ALLOC_COUNT * XT_XN_NO_OF_SEGMENTS); + db->db_xn_data_end = db->db_xn_data + sizeof(XTXactDataRec) * XT_XN_DATA_ALLOC_COUNT * XT_XN_NO_OF_SEGMENTS; + xact = (XTXactDataPtr) db->db_xn_data; + for (u_int i=0; i<XT_XN_NO_OF_SEGMENTS; i++) { + seg = &db->db_xn_idx[i]; + XT_XACT_INIT_LOCK(self, &seg->xs_tab_lock); + for (u_int j=0; j<XT_XN_DATA_ALLOC_COUNT; j++) { + xact->xd_next_xact = seg->xs_free_list; + seg->xs_free_list = xact; + xact++; + } + } + + /* Initialize the data logs: */ + db->db_datalogs.dlc_init(self, db); + + /* Setup the transaction log: */ + db->db_xlog.xlog_setup(self, db, (off_t) xt_db_log_file_threshold, xt_db_transaction_buffer_size, xt_db_log_file_count); + + db->db_xn_end_time = 1; + + /* Initializing the restart file, also does + * recovery. This returns the log position after recovery. + * + * This is the log position where the writer thread will + * begin. The writer thread writes changes to the database that + * have been flushed to the log. + */ + xt_xres_init(self, db); + + /* Initialize the "last transaction in memory", by default + * this is the current transaction ID, which is the ID + * of the last transaction. + */ + for (u_int i=0; i<XT_XN_NO_OF_SEGMENTS; i++) { + seg = &db->db_xn_idx[i]; + XT_XACT_INIT_LOCK(self, &seg->xs_tab_lock); + seg->xs_last_xn_id = db->db_xn_curr_id; + } + + /* + * The next transaction to clean is the lowest transaction + * in memory: + */ + db->db_xn_to_clean_id = db->db_xn_min_ram_id; + + /* + * No transactions are running, so the minimum transaction + * ID is the next one to run: + */ + db->db_xn_min_run_id = db->db_xn_curr_id + 1; + + db->db_xn_wait_for = xt_new_sortedlist(self, sizeof(XNWaitForRec), 100, 50, xn_compare_wait_for, db, xn_free_wait_for, FALSE, FALSE); +} + +xtPublic void xt_xn_exit_db(XTThreadPtr self, XTDatabaseHPtr db) +{ +#ifdef HIGH_X + printf("=========> MOST TXs CURR ALLOC: %lu\n", tot_alloced); + printf("=========> MOST TXs HIGH ALLOC: %lu\n", high_alloced); + printf("=========> MAX TXs NOT CLEAN: %lu\n", not_clean_max); + printf("=========> MAX TXs IN RAM: %lu\n", in_ram_max); +#endif + + xt_stop_sweeper(self, db); // Should be done already! + xt_stop_writer(self, db); // Should be done already! + + xt_xres_exit(self, db); + db->db_xlog.xlog_exit(self); + + db->db_datalogs.dlc_exit(self); + + for (u_int i=0; i<XT_XN_NO_OF_SEGMENTS; i++) { + XTXactSegPtr seg; + + seg = &db->db_xn_idx[i]; + for (u_int j=0; j<XT_XN_HASH_TABLE_SIZE; j++) { + XTXactDataPtr xact, nxact; + + xact = seg->xs_table[j]; + while (xact) { + nxact = xact->xd_next_xact; + xn_free_xact(db, seg, xact); + xact = nxact; + } + } + XT_XACT_FREE_LOCK(self, &seg->xs_tab_lock); + } + if (db->db_xn_wait_for) { + xt_free_sortedlist(self, db->db_xn_wait_for); + db->db_xn_wait_for = NULL; + } + if (db->db_xn_data) { + xt_free(self, db->db_xn_data); + db->db_xn_data = NULL; + db->db_xn_data_end = NULL; + } + + xt_free_cond(&db->db_wr_cond); + xt_free_mutex(&db->db_wr_lock); + xt_free_cond(&db->db_sw_cond); + xt_free_mutex(&db->db_sw_lock); + //xt_free_cond(&db->db_xn_wait_cond); + //xt_free_mutex(&db->db_xn_wait_lock); + xt_spinlock_free(self, &db->db_xn_wait_spinlock); + xt_spinlock_free(self, &db->db_xn_id_lock); +#ifdef DEBUG_RAM_LIST + check_ram_free(); +#endif +} + +xtPublic void xt_xn_init_thread(XTThreadPtr self, int what_for) +{ + ASSERT(self->st_database); + + if (!xt_init_row_lock_list(&self->st_lock_list)) + xt_throw(self); + switch (what_for) { + case XT_FOR_COMPACTOR: + self->st_dlog_buf.dlb_init(self->st_database, xt_db_log_buffer_size); + break; + case XT_FOR_WRITER: + /* The writer does not need a transaction buffer. */ + self->st_dlog_buf.dlb_init(self->st_database, 0); + break; + case XT_FOR_SWEEPER: + self->st_dlog_buf.dlb_init(self->st_database, 0); + break; + case XT_FOR_USER: + self->st_dlog_buf.dlb_init(self->st_database, xt_db_log_buffer_size); + break; + } +} + +xtPublic void xt_xn_exit_thread(XTThreadPtr self) +{ + if (self->st_xact_data) + xt_xn_rollback(self); + self->st_dlog_buf.dlb_exit(self); + xt_exit_row_lock_list(&self->st_lock_list); +} + +/* ---------------------------------------------------------------------- + * Begin and End Transactions + */ + +xtPublic xtBool xt_xn_begin(XTThreadPtr self) +{ + XTDatabaseHPtr db = self->st_database; + xtXactID xn_id; + + ASSERT(!self->st_xact_data); + + xt_spinlock_lock(&db->db_xn_id_lock); + xn_id = ++db->db_xn_curr_id; + xt_spinlock_unlock(&db->db_xn_id_lock); + +#ifdef HIGH_X + if (xt_xn_is_before(not_clean_max, xn_id - db->db_xn_to_clean_id)) + not_clean_max = xn_id - db->db_xn_to_clean_id; + if (xt_xn_is_before(in_ram_max, xn_id - db->db_xn_min_ram_id)) + in_ram_max = xn_id - db->db_xn_min_ram_id; +#endif + /* {GAP-INC-ADD-XACT} This is the gap between incrementing the ID, + * and creating the transaction in memory. + * See xt_xn_get_curr_id(). + */ + + if (!(self->st_xact_data = xn_add_new_xact(db, xn_id, self))) + return FAILED; + self->st_xact_writer = FALSE; + + /* All transactions that committed before or at this time + * are this one are visible: */ + self->st_visible_time = db->db_xn_end_time; + +#ifdef TRACE_TRANSACTION + xt_ttracef(self, "BEGIN T%lu\n", (u_long) self->st_xact_data->xd_start_xn_id); +#endif + return OK; +} + +static xtBool xn_end_xact(XTThreadPtr thread, u_int status) +{ + XTXactDataPtr xact; + xtBool ok = TRUE; + + ASSERT_NS(thread->st_xact_data); + if ((xact = thread->st_xact_data)) { + XTDatabaseHPtr db = thread->st_database; + xtXactID xn_id = xact->xd_start_xn_id; + xtBool writer; + + if ((writer = thread->st_xact_writer)) { + /* The transaction wrote something: */ + XTXactEndEntryDRec entry; + xtWord4 sum; + + sum = XT_CHECKSUM4_XACT(xn_id) ^ XT_CHECKSUM4_XACT(0); + entry.xe_status_1 = status; + entry.xe_checksum_1 = XT_CHECKSUM_1(sum); + XT_SET_DISK_4(entry.xe_xact_id_4, xn_id); + XT_SET_DISK_4(entry.xe_not_used_4, 0); + +#ifdef XT_IMPLEMENT_NO_ACTION + /* This will check any resticts that have been delayed to the end of the statement. */ + if (thread->st_restrict_list.bl_count) { + if (!xt_tab_restrict_rows(&thread->st_restrict_list, thread)) { + ok = FALSE; + status = XT_LOG_ENT_ABORT; + } + } +#endif + + /* Flush the data log: */ + if (!thread->st_dlog_buf.dlb_flush_log(TRUE, thread)) { + ok = FALSE; + status = XT_LOG_ENT_ABORT; + } + + /* Write and flush the transaction log: */ + if (!xt_xlog_log_data(thread, sizeof(XTXactEndEntryDRec), (XTXactLogBufferDPtr) &entry, TRUE)) { + ok = FALSE; + status = XT_LOG_ENT_ABORT; + /* Make sure this is done, if we failed to log + * the transction end! + */ + if (thread->st_xact_writer) { + /* Adjust this in case of error, but don't forget + * to lock! + */ + xt_spinlock_lock(&db->db_xlog.xl_buffer_lock); + db->db_xn_writer_count--; + thread->st_xact_writer = FALSE; + if (thread->st_xact_long_running) { + db->db_xn_long_running_count--; + thread->st_xact_long_running = FALSE; + } + xt_spinlock_unlock(&db->db_xlog.xl_buffer_lock); + } + } + + /* Setting this flag completes the transaction, + * Do this before we release the locks, because + * the unlocked transactions expect the + * transaction they are waiting for to be + * gone! + */ + xact->xd_end_time = ++db->db_xn_end_time; + if (status == XT_LOG_ENT_COMMIT) { + thread->st_statistics.st_commits++; + xact->xd_flags |= (XT_XN_XAC_COMMITTED | XT_XN_XAC_ENDED); + } + else { + thread->st_statistics.st_rollbacks++; + xact->xd_flags |= XT_XN_XAC_ENDED; + } + + /* {REMOVE-LOCKS} Drop locks is you have any: */ + thread->st_lock_list.xt_remove_all_locks(db, thread); + + /* Do this afterwards to make sure the sweeper + * does not cleanup transactions start cleaning up + * before any transactions that were waiting for + * this transaction have completed! + */ + xact->xd_end_xn_id = db->db_xn_curr_id; + + /* Now you can sweep! */ + xact->xd_flags |= XT_XN_XAC_SWEEP; + } + else { + /* Read-only transaction can be removed, immediately */ + xact->xd_end_time = ++db->db_xn_end_time; + xact->xd_flags |= (XT_XN_XAC_COMMITTED | XT_XN_XAC_ENDED); + + /* Drop locks is you have any: */ + thread->st_lock_list.xt_remove_all_locks(db, thread); + + xact->xd_end_xn_id = db->db_xn_curr_id; + + xact->xd_flags |= XT_XN_XAC_SWEEP; + + if (xt_xn_delete_xact(db, xn_id, thread)) { + if (db->db_xn_min_ram_id == xn_id) + db->db_xn_min_ram_id = xn_id+1; + } + } + +#ifdef TRACE_TRANSACTION + if (status == XT_LOG_ENT_COMMIT) + xt_ttracef(thread, "COMMIT T%lu\n", (u_long) xn_id); + else + xt_ttracef(thread, "ABORT T%lu\n", (u_long) xn_id); +#endif + + if (db->db_xn_min_run_id == xn_id) + db->db_xn_min_run_id = xn_id+1; + + thread->st_xact_data = NULL; + + xt_xn_wakeup_waiting_threads(thread); + + /* {WAKE-SW} Waking the sweeper + * is no longer unconditional. + * (see all comments to {WAKE-SW}) + * + * We now wake the sweeper if it is + * supposed to work faster. + * + * There are now 2 cases: + * - We run out of transaction slots. + * - We encounter old index entries. + * + * The following test: + * runTest(INCREMENT_TEST, 16, INCREMENT_TEST_UPDATE_COUNT); + * has extreme problems with sweeping every 1/10s + * because a huge number of index entries accumulate + * that need to be cleaned. + * + * New code detects this case. + */ + if (db->db_sw_faster) + xt_wakeup_sweeper(db); + + /* Don't get too far ahead of the sweeper! */ + if (writer) { + if ((db->db_sw_faster & XT_SW_TOO_FAR_BEHIND) != 0) { + xtWord8 then = xt_trace_clock() + (xtWord8) 20000; + + for (;;) { + xt_critical_wait(); + if (db->db_sw_faster & XT_SW_TOO_FAR_BEHIND) + break; + if (xt_trace_clock() >= then) + break; + } + } + } + } + return ok; +} + +xtPublic xtBool xt_xn_commit(XTThreadPtr thread) +{ + return xn_end_xact(thread, XT_LOG_ENT_COMMIT); +} + +xtPublic xtBool xt_xn_rollback(XTThreadPtr thread) +{ + return xn_end_xact(thread, XT_LOG_ENT_ABORT); +} + +xtPublic xtBool xt_xn_log_tab_id(XTThreadPtr self, xtTableID tab_id) +{ + XTXactNewTabEntryDRec entry; + + entry.xt_status_1 = XT_LOG_ENT_NEW_TAB; + entry.xt_checksum_1 = XT_CHECKSUM_1(tab_id); + XT_SET_DISK_4(entry.xt_tab_id_4, tab_id); + return xt_xlog_log_data(self, sizeof(XTXactNewTabEntryDRec), (XTXactLogBufferDPtr) &entry, TRUE); +} + +xtPublic int xt_xn_status(XTOpenTablePtr ot, xtXactID xn_id, xtRecordID XT_UNUSED(rec_id)) +{ + register XTThreadPtr self = ot->ot_thread; + int flags; + xtWord4 end; + +#ifdef DRIZZLED + /* Conditional waste of time! + * Drizzle has strict warnings. + * I know this is not necessary! + */ + flags = 0; + end = 0; +#endif + if (xn_id == self->st_xact_data->xd_start_xn_id) + return XT_XN_MY_UPDATE; + if (xt_xn_is_before(xn_id, self->st_database->db_xn_min_ram_id) || + !xn_get_xact_details(self->st_database, xn_id, ot->ot_thread, &flags, NULL, &end, NULL)) { + /* Not in RAM, rollback done: */ +//*DBG*/xt_dump_xlogs(self->st_database, 0); +//*DBG*/xt_check_table(self, ot); +//*DBG*/xt_dump_trace(); + /* {XACT-NOT-IN-RAM} + * This should never happen (CHANGED see below)! + * + * Because if the transaction is no longer in RAM, then it has been + * cleaned up. So the record should be marked as clean, or not + * exist. + * + * After sweeping, we wait for all transactions to quit that were + * running at the time of cleanup before removing the transaction record. + * (see {XACT-NOT-IN-RAM}) + * + * If this was not the case, then we could be here because: + * - The user transaction (T2) reads record x and notes that the record + * has not been cleaned (CLEAN bit not set). + * + * - The sweeper is busy sweeping the transaction (T1) that created + * record x. + * The SW sets the CLEAN bit on record x, and the schedules T1 for + * deletion. + * + * Now T1 should not be deleted before T2 quits. If it does happen + * then we land up here. + * + * THIS CAN NOW HAPPEN! + * + * First of all, a MYSTERY: + * This did happen, dispite the description above! The reason why + * is left as an exercise to the reader (really, I don't now why!) + * + * This has force me to add code to handle the situation. This + * is done by re-reading the record that is being checked by this + * function. After re-reading, the record should either be + * invalid (free) or clean (CLEAN bit set). + * + * If this is the case, then we will not run land up here + * again. + * + * Because we are only here because the record was valid but not + * clean (you can confirm this by looking at the code that + * calls this function). + */ + return XT_XN_REREAD; + } + if (!(flags & XT_XN_XAC_ENDED)) + /* Transaction not ended, may be visible. */ + return XT_XN_OTHER_UPDATE; + /* Visible if the transaction was committed: */ + if (flags & XT_XN_XAC_COMMITTED) { + if (!xt_xn_is_before(self->st_visible_time, end)) // was self->st_visible_time >= xact->xd_end_time + return XT_XN_VISIBLE; + return XT_XN_NOT_VISIBLE; + } + return XT_XN_ABORTED; +} + +xtPublic xtWord8 xt_xn_bytes_to_sweep(XTDatabaseHPtr db, XTThreadPtr thread) +{ + xtXactID xn_id; + xtXactID curr_xn_id; + xtLogID xn_log_id = 0; + xtLogOffset xn_log_offset = 0; + xtLogID x_log_id = 0; + xtLogOffset x_log_offset = 0; + xtLogID log_id; + xtLogOffset log_offset; + xtWord8 byte_count = 0; + + xn_id = db->db_xn_to_clean_id; + curr_xn_id = xt_xn_get_curr_id(db); + // Limit the number of transactions checked! + for (int i=0; i<1000; i++) { + if (xt_xn_is_before(curr_xn_id, xn_id)) + break; + if (xn_get_xact_start(db, xn_id, thread, &x_log_id, &x_log_offset)) { + if (xn_log_id) { + if (xt_comp_log_pos(x_log_id, x_log_offset, xn_log_id, xn_log_offset) < 0) { + xn_log_id = x_log_id; + xn_log_offset = x_log_offset; + } + } + else { + xn_log_id = x_log_id; + x_log_offset = x_log_offset; + } + } + xn_id++; + } + if (!xn_log_id) + return 0; + + /* Assume the logs have the threshold: */ + log_id = db->db_xlog.xl_write_log_id; + log_offset = db->db_xlog.xl_write_log_offset; + if (xn_log_id < log_id) { + if (xn_log_offset < xt_db_log_file_threshold) + byte_count = (size_t) (xt_db_log_file_threshold - xn_log_offset); + xn_log_offset = 0; + xn_log_id++; + } + while (xn_log_id < log_id) { + byte_count += (size_t) xt_db_log_file_threshold; + xn_log_id++; + } + if (xn_log_offset < log_offset) + byte_count += (size_t) (log_offset - xn_log_offset); + + return byte_count; +} + +/* ---------------------------------------------------------------------- + * S W E E P E R P R O C E S S + */ + +typedef struct XNSweeperState { + XTDatabaseHPtr ss_db; + XTXactSeqReadRec ss_seqread; + XTDataBufferRec ss_databuf; + u_int ss_call_cnt; + XTBasicQueueRec ss_to_free; + xtBool ss_flush_pending; + XTOpenTablePtr ss_ot; +} XNSweeperStateRec, *XNSweeperStatePtr; + +static XTOpenTablePtr xn_sw_get_open_table(XTThreadPtr self, XNSweeperStatePtr ss, xtTableID tab_id, int *r) +{ + if (ss->ss_ot) { + if (ss->ss_ot->ot_table->tab_id == tab_id) + return ss->ss_ot; + + xt_db_return_table_to_pool(self, ss->ss_ot); + ss->ss_ot = NULL; + } + + if (!ss->ss_ot) { + if (!(ss->ss_ot = xt_db_open_pool_table(self, ss->ss_db, tab_id, r, TRUE))) + return NULL; + } + + return ss->ss_ot; +} + +static void xn_sw_close_open_table(XTThreadPtr self, XNSweeperStatePtr ss) +{ + if (ss->ss_ot) { + xt_db_return_table_to_pool(self, ss->ss_ot); + ss->ss_ot = NULL; + } +} + +/* + * A thread can set a bit in db_sw_faster to make + * the sweeper go faster. + */ +static void xn_sw_could_go_faster(XTThreadPtr self, XTDatabaseHPtr db) +{ + if (db->db_sw_faster) { + if (!db->db_sw_fast) { + xt_set_priority(self, xt_db_sweeper_priority+1); + db->db_sw_fast = TRUE; + } + } +} + +static void xn_sw_go_slower(XTThreadPtr self, XTDatabaseHPtr db) +{ + if (db->db_sw_fast) { + xt_set_priority(self, xt_db_sweeper_priority); + db->db_sw_fast = FALSE; + } + db->db_sw_faster = XT_SW_WORK_NORMAL; +} + +/* Add a record to the "to free" queue. We note the current + * transaction at the time this is done. The record will + * only be freed once this transaction terminated, together + * with all transactions that started before it! + * + * The reason for this is that a sequential scan or some + * other operation may read a committed record which is no longer + * valid because it is no longer the latest variation (the first + * variation reachable from the row pointer). + * + * In this case, the sweeper will free the variation. + * If the variation is re-used and committed before + * the sequential scan or read completes, and by some + * fluke is used by the same record as previously, + * the system will think the record is valid + * again. + * + * Without re-reading the record the sequential + * scan or other read will find it on the variation list, and + * return the record data as if valid! + * + * ------------ 2008-01-03 + * + * An example of this is: + * + * Assume we have 3 records. + * The 3rd record is deleted, and committed. + * Before cleanup can be performed + * a sequential scan takes a copy of the records. + * + * Now assume a new insert is done before + * the sequential scan gets to the 3rd record. + * + * The insert allocates the 3rd row and 3rd record + * again. + * + * Now, when the sequential scan gets to the old copy of the 3rd record, + * this is valid because the row points to this record again. + * + * HOWEVER! I have now changed the sequential scan so that it accesses + * the records from the cache, without making a copy. + * + * This means that this problem cannot occur because the sequential scan + * always reads the current data from the cache. + * + * There is also no race condition (although no lock is taken), because + * the record is writen before the row (see here [(5)]). + * + * This means that the row does not point to the record before the + * record has been modified. + * + * Once the record has been modified then the sequential scan will see + * that the record belongs to a new transaction. + * + * If the row pointer was set before the record updated then a race + * condition would exist when the sequential scan reads the record + * after the insert has updated the row pointer but before it has + * changed the record. + * + * AS A RESULT: + * + * I believe I can remove the delayed free record! + * + * This means I can combine the REMOVE and FREE operations. + * + * This is good because this takes care of the problem + * that records are lost when: + * + * The server crashes when the delayed free list still has items on it. + * AND + * The transaction that freed the records has been cleaned, and this + * fact has been committed to the log. + * + * So I have removed the delay here: [(6)] + * + * ------------ 2008-12-03 + * + * This code to delay removal of records was finally removed (see above) + */ + +/* + * As above, but instead a transaction is added to the "to free" queue. + * + * It is important that transactions remain in memory until all + * currently running transactions have ended. This is because + * sequential and index scans have copies of old data. + * + * In the old data a record may not be indicated as cleaned. Such + * a record is considered invalid if the transaction is not in RAM. + * + * GOTCHA: + * + * And this problem is demonstrated by the following example + * which was derived from flush_table.test. + * + * Each handler command below is a separate transaction. + * However the buffer is loaded by 'read first'. + * Depending on when cleanup occurs, records can disappear + * in some of the next commands. + * + * 2 solutions for the test. Use begin ... commit around + * handler open ... close. Or use analyze table t1 before + * open. analyze table waits for the sweeper to complete! + * + * create table dummy(table_id char(20) primary key); + * let $1=100; + * while ($1) + * { + * drop table if exists t1; + * create table t1(table_id char(20) primary key); + * insert into t1 values ('Record-01'); + * insert into t1 values ('Record-02'); + * insert into t1 values ('Record-03'); + * insert into t1 values ('Record-04'); + * insert into t1 values ('Record-05'); + * handler t1 open; + * handler t1 read first limit 1; + * handler t1 read next limit 1; + * handler t1 read next limit 1; + * handler t1 read next limit 1; + * handler t1 close; + * commit; + * dec $1; + * } + * + */ +#ifdef MUST_DELAY_REMOVE +static void xn_sw_add_xact_to_free(XTThreadPtr self, XNSweeperStatePtr ss, xtXactID xn_id) +{ + XNSWToFreeItemRec free_item; + + if ((ss->ss_to_free.bq_front - ss->ss_to_free.bq_back) >= XT_TN_MAX_TO_FREE) { + /* If the queue is full, try to free some items: + * We use the call count to avoid doing this every time, + * when the queue overflows! + */ + if ((ss->ss_call_cnt % XT_TN_MAX_TO_FREE_CHECK) == 0) + /* GOTCHA: This call was not locking the sweeper, + * this could cause failure, of course: + */ + xn_sw_service_to_free(self, ss, TRUE); + ss->ss_call_cnt++; + } + + free_item.ri_wait_xn_id = ss->ss_db->db_xn_curr_id; + free_item.ri_tab_id = 0; + free_item.x.ri_xn_id = xn_id; + + xt_bq_add(self, &ss->ss_to_free, &free_item); +} +#endif + +static void xt_sw_delete_variations(XTThreadPtr self, XNSweeperStatePtr ss, XTOpenTablePtr ot, xtRecordID rec_id, xtRowID row_id, xtXactID xn_id) +{ + xtRecordID prev_var_rec_id; + + while (rec_id) { + switch (xt_tab_remove_record(ot, rec_id, ss->ss_databuf.db_data, &prev_var_rec_id, FALSE, row_id, xn_id)) { + case XT_ERR: + throw_(); + return; + case TRUE: + break; + } + rec_id = prev_var_rec_id; + } +} + +static void xt_sw_delete_variation(XTThreadPtr self, XNSweeperStatePtr ss, XTOpenTablePtr ot, xtRecordID rec_id, xtBool clean_delete, xtRowID row_id, xtXactID xn_id) +{ + xtRecordID prev_var_rec_id; + + switch (xt_tab_remove_record(ot, rec_id, ss->ss_databuf.db_data, &prev_var_rec_id, clean_delete, row_id, xn_id)) { + case XT_ERR: + throw_(); + return; + case TRUE: + break; + case FALSE: + break; + } +} + +/* Set rec_type to this value in order to force cleanup, without + * a check. + */ +#define XN_FORCE_CLEANUP XT_TAB_STATUS_FREED + +/* + * Read the record to be cleaned. Return TRUE if the cleanup has already been done. + */ +static xtBool xn_sw_cleanup_done(XTThreadPtr self, XTOpenTablePtr ot, xtRecordID rec_id, xtXactID xn_id, u_int rec_type, u_int stat_id, xtRowID row_id, XTTabRecHeadDPtr rec_head) +{ + if (!xt_tab_get_rec_data(ot, rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) rec_head)) + throw_(); + + if (rec_type == XN_FORCE_CLEANUP) { + if (XT_REC_IS_FREE(rec_head->tr_rec_type_1)) + return TRUE; + } + else { + /* Transaction must match: */ + if (XT_GET_DISK_4(rec_head->tr_xact_id_4) != xn_id) + return TRUE; + + /* Record header must match expected value from + * log or clean has been done, or is not required. + * + * For example, it is not required if a record + * has been overwritten in a transaction. + */ + if (rec_head->tr_rec_type_1 != rec_type || + rec_head->tr_stat_id_1 != stat_id) + return TRUE; + + /* Row must match: */ + if (XT_GET_DISK_4(rec_head->tr_row_id_4) != row_id) + return TRUE; + } + + return FALSE; +} + +static void xn_sw_clean_indices(XTThreadPtr self __attribute__((unused)), XTOpenTablePtr ot, xtRecordID rec_id, xtRowID row_id, xtWord1 *rec_data, xtWord1 *rec_buffer) +{ + XTTableHPtr tab = ot->ot_table; + u_int cols_req; + XTIndexPtr *ind; + + if (!tab->tab_dic.dic_key_count) + return; + + cols_req = tab->tab_dic.dic_ind_cols_req; + if (XT_REC_IS_FIXED(rec_data[0])) + rec_buffer = rec_data + XT_REC_FIX_HEADER_SIZE; + else { + if (XT_REC_IS_VARIABLE(rec_data[0])) { + if (!myxt_load_row(ot, rec_data + XT_REC_FIX_HEADER_SIZE, rec_buffer, cols_req)) + goto failed; + } + else if (XT_REC_IS_EXT_DLOG(rec_data[0])) { + ASSERT(cols_req); + if (cols_req && cols_req <= tab->tab_dic.dic_fix_col_count) { + if (!myxt_load_row(ot, rec_data + XT_REC_EXT_HEADER_SIZE, rec_buffer, cols_req)) + goto failed; + } + else { + if (rec_data != ot->ot_row_rbuffer) + memcpy(ot->ot_row_rbuffer, rec_data, tab->tab_dic.dic_rec_size); + if (!xt_tab_load_ext_data(ot, rec_id, rec_buffer, cols_req)) + goto failed; + } + } + else + /* This is possible, the record has already been cleaned up. */ + return; + } + + ind = tab->tab_dic.dic_keys; + for (u_int i=0; i<tab->tab_dic.dic_key_count; i++, ind++) { + if (!xt_idx_update_row_id(ot, *ind, rec_id, row_id, rec_buffer)) + xt_log_and_clear_exception_ns(); + } + return; + + failed: + xt_log_and_clear_exception_ns(); +} + +/* + * Return TRUE if the cleanup was done. FAILED if cleanup could not be done + * because dictionary information is not available. + */ +static xtBool xn_sw_cleanup_variation(XTThreadPtr self, XNSweeperStatePtr ss, XTXactDataPtr xact, xtTableID tab_id, xtRecordID rec_id, u_int status, u_int rec_type, u_int stat_id, xtRowID row_id, xtWord1 *rec_buf) +{ + XTOpenTablePtr ot; + XTTableHPtr tab; + XTTabRecHeadDRec rec_head; + xtRecordID after_rec_id; + xtXactID xn_id; + int r; + + if (!(ot = xn_sw_get_open_table(self, ss, tab_id, &r))) { + /* The table no longer exists, consider cleanup done: */ + switch (r) { + case XT_TAB_NOT_FOUND: + break; + case XT_TAB_NO_DICTIONARY: + case XT_TAB_POOL_CLOSED: + return FALSE; + } + return TRUE; + } + + tab = ot->ot_table; + + /* Make sure the buffer is large enough! */ + xt_db_set_size(self, &ss->ss_databuf, (size_t) tab->tab_dic.dic_mysql_buf_size); + + xn_id = xact->xd_start_xn_id; + if (xact->xd_flags & XT_XN_XAC_COMMITTED) { + /* The transaction has been committed. Clean the record and + * remove variations no longer in use. + */ + switch (status) { + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_UPDATE_FL_BG: + if (xn_sw_cleanup_done(self, ot, rec_id, xn_id, rec_type, stat_id, row_id, &rec_head)) + goto done_ok; + after_rec_id = XT_GET_DISK_4(rec_head.tr_prev_rec_id_4); + xt_sw_delete_variations(self, ss, ot, after_rec_id, row_id, xn_id); + rec_head.tr_rec_type_1 |= XT_TAB_STATUS_CLEANED_BIT; + XT_SET_NULL_DISK_4(rec_head.tr_prev_rec_id_4); + if (!xt_tab_put_log_op_rec_data(ot, XT_LOG_ENT_REC_CLEANED, 0, rec_id, offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE, (xtWord1 *) &rec_head)) + throw_(); + xn_sw_clean_indices(self, ot, rec_id, row_id, rec_buf, ss->ss_databuf.db_data); + break; + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_INSERT_FL_BG: { + /* POTENTIAL BUG 1: + * + * DROP TABLE IF EXISTS t1; + * CREATE TABLE t1 ( id int, name varchar(300)) engine=pbxt; + * + * begin; + * insert t1(id, name) values(1, "aaa"); + * update t1 set name=REPEAT('A', 300) where id = 1; + * commit; + * flush tables; + * select * from t1; + * + * Because the type of record changes, from VARIABLE to + * EXTENDED, the cleanup needs to take this into account. + * + * The input new status value which is written here + * depends on the first write to the record. + * However, the second write changes the record status. + * + * Previously we used a OR function to write the bit and + * return the byte value of the result. + * + * The write funtion now checks the record to be written + * to make sure it matches the record that needs to be + * cleaned. So OR'ing the bit is no longer required. + * + * POTENTIAL BUG 2: + * + * We have changed this to fix the following bug: + * + * T1 starts + * T2 starts + * T2 insert record 100 in row 50 + * T2 commits + * T1 updates row 50 and adds record 101 + * + * The sweeper does cleanup in order T1, T2, ... + * + * The sweeper cleans T1 by removing record 100 from the + * row 50 variation list. + * This means that record 100 is free. + * + * The sweeper cleans T2 by marking record 100 as clean. + * !BUG! record 100 has already been freed! + * + * To avoid this we have to check a record before + * cleaning (as we do above for update in xn_sw_cleanup_done()) + * We check that the record is, in fact, the exact + * record that was inserted. + * + * This is now done be xt_tc_write_cond(). + */ + xtOpSeqNo op_seq; + + rec_head.tr_rec_type_1 = rec_type | XT_TAB_STATUS_CLEANED_BIT; + if(!tab->tab_recs.xt_tc_write_cond(self, ot->ot_rec_file, rec_id, rec_head.tr_rec_type_1, &op_seq, xn_id, row_id, stat_id, rec_type)) + /* this means record was not updated by xt_tc_write_bor and doesn't need to */ + break; + if (!xt_xlog_modify_table(ot, XT_LOG_ENT_REC_CLEANED_1, op_seq, 0, rec_id, 1, &rec_head.tr_rec_type_1)) + throw_(); + xn_sw_clean_indices(self, ot, rec_id, row_id, rec_buf, ss->ss_databuf.db_data); + break; + } + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_DELETE_FL: + case XT_LOG_ENT_DELETE_BG: + case XT_LOG_ENT_DELETE_FL_BG: + if (xn_sw_cleanup_done(self, ot, rec_id, xn_id, rec_type, stat_id, row_id, &rec_head)) + goto done_ok; + after_rec_id = XT_GET_DISK_4(rec_head.tr_prev_rec_id_4); + xt_sw_delete_variations(self, ss, ot, after_rec_id, row_id, xn_id); + xt_sw_delete_variation(self, ss, ot, rec_id, TRUE, row_id, xn_id); + if (row_id) { + if (!xt_tab_free_row(ot, tab, row_id)) + throw_(); + } + break; + } + } + else { + /* The transaction has been aborted. Remove the variation from the + * variation list. If this means the list is empty, then remove + * the record as well. + */ + xtRecordID first_rec_id, next_rec_id, prev_rec_id; + XTTabRecHeadDRec prev_rec_head; + + if (xn_sw_cleanup_done(self, ot, rec_id, xn_id, rec_type, stat_id, row_id, &rec_head)) + goto done_ok; + + if (!row_id) + row_id = XT_GET_DISK_4(rec_head.tr_row_id_4); + after_rec_id = XT_GET_DISK_4(rec_head.tr_prev_rec_id_4); + if (!row_id) + goto unlink_done; + + /* Now remove the record from the variation list, + * (if it is still on the list). + */ + XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], self); + + /* Find the variation before the variation we wish to remove: */ + if (!(xt_tab_get_row(ot, row_id, &first_rec_id))) + goto failed; + prev_rec_id = 0; + next_rec_id = first_rec_id; + while (next_rec_id != rec_id) { + if (!next_rec_id) { + /* The record was not found in the list (we are done) */ + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], self); + goto unlink_done; + } + if (!xt_tab_get_rec_data(ot, next_rec_id, sizeof(XTTabRecHeadDRec), (xtWord1 *) &prev_rec_head)) { + xt_log_and_clear_exception(self); + break; + } + prev_rec_id = next_rec_id; + next_rec_id = XT_GET_DISK_4(prev_rec_head.tr_prev_rec_id_4); + } + + if (next_rec_id == rec_id) { + /* The record was found on the list: */ + if (prev_rec_id) { + /* Unlink the deleted variation: + * I have found the following sequence: + * + * 17933 in use 1906112 + * 1906112 delete xact=2901 row=17933 prev=2419240 + * 2419240 delete xact=2899 row=17933 prev=2153360 + * 2153360 record-X C xact=2599 row=17933 prev=0 Xlog=151 Xoff=16824 Xsiz=100 + * + * Despite the following facts which should prevent chains from + * forming: + * + * --- Only one transaction can modify a row + * at any one time. So it is not possible for a new change + * to be linked onto an uncommitted change. + * + * --- Transactions that modify the same row + * twice do not allocate a new record for each change. + * + * -- A change that has been + * rolled back will not be linked onto. Instead + * the new transaction will link to the last. + * Comitted record. + * + * So if the sweeper is slow in doing its job + * we can have the situation that a number of records + * can refer to the last committed record of the + * row. + * + * Only one will be reference by the row pointer. + * + * The other, will all have been rolled back. + * This occurs over here: [(4)] + */ + XT_SET_DISK_4(prev_rec_head.tr_prev_rec_id_4, after_rec_id); + if (!xt_tab_put_log_op_rec_data(ot, XT_LOG_ENT_REC_UNLINKED, 0, prev_rec_id, offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE, (xtWord1 *) &prev_rec_head)) + goto failed; + } + else { + /* Variation to be removed at the front of the list. */ + ASSERT(rec_id == first_rec_id); + if (after_rec_id) { + /* Unlink the deleted variation, from the front of the list: */ + if (!xt_tab_set_row(ot, XT_LOG_ENT_ROW_SET, row_id, after_rec_id)) + goto failed; + } + else { + /* No more variations, remove the row: */ + if (!xt_tab_free_row(ot, tab, row_id)) + goto failed; + } + } + } + + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], self); + + /* Note: even when not found on the row list, the record must still + * be freed. + * + * There might be an exception to this, but there are very definite + * cases where this is required, for example when an unreferenced + * record is found and added to the clean up list xn_add_cu_record(). + */ + + unlink_done: + /* Delete the extended record and index entries: + * + * NOTE! This must be done after we have release the row lock. Because + * a thread that does a duplicate check locks the index, and then + * check whether a row is valid, and can deadlock with + * code that locks a row, then an index! + * + * However, this should all be OK, because the variation has been removed from the + * row variation list at this stage, and now just need to be deleted. + */ + xt_sw_delete_variation(self, ss, ot, rec_id, FALSE, row_id, xn_id); + } + + done_ok: + return OK; + + failed: + XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[row_id % XT_ROW_RWLOCKS], self); + throw_(); + return FAILED; +} + +/* Go through all updated records of a transaction and cleanup. + * This means, of the transaction was aborted, then all the variations written + * by the transaction must be removed. + * If the transaction was committed then we remove older variations. + * If a delete was committed this can lead to the row being removed. + * + * After a transaction has been cleaned it can be removed from RAM. + * If this was the last transaction in a log, and the log has reached + * threshold, and the log is no longer in exclusive use, then the log + * can be deleted. + * + * This function returns OK if the transaction was cleaned up, FALSE + * if a retry is required. Othersize an error is thrown. + */ +static xtBool xn_sw_cleanup_xact(XTThreadPtr self, XNSweeperStatePtr ss, XTXactDataPtr xact) +{ + XTDatabaseHPtr db = ss->ss_db; + XTXactLogBufferDPtr record; + xtTableID tab_id; + xtRecordID rec_id; + xtXactID xn_id; + xtRowID row_id; + + if (!db->db_xlog.xlog_seq_start(&ss->ss_seqread, xact->xd_begin_log, xact->xd_begin_offset, FALSE)) + xt_throw(self); + + for (;;) { + if (self->t_quit) + return FAILED; + + xn_sw_could_go_faster(self, db); + + if (!db->db_xlog.xlog_seq_next(&ss->ss_seqread, &record, FALSE, self)) + xt_throw(self); + if (!record) { + /* Recovered transactions are considered cleaned when we + * reach the end of the transaction log. + * This is required, because transactions that do + * not have a commit (or rollback) record, because they were + * running when the server last went down, will otherwise not + * have the cleanup completed!! + */ + ASSERT(xact->xd_flags & XT_XN_XAC_RECOVERED); + if (!(xact->xd_flags & XT_XN_XAC_RECOVERED)) + return FAILED; + goto cleanup_done; + } + switch (record->xh.xh_status_1) { + case XT_LOG_ENT_NEW_LOG: + if (!db->db_xlog.xlog_seq_start(&ss->ss_seqread, XT_GET_DISK_4(record->xl.xl_log_id_4), 0, FALSE)) + xt_throw(self); + break; + case XT_LOG_ENT_COMMIT: + case XT_LOG_ENT_ABORT: + xn_id = XT_GET_DISK_4(record->xe.xe_xact_id_4); + if (xn_id == xact->xd_start_xn_id) + goto cleanup_done; + break; + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_DELETE_BG: + xn_id = XT_GET_DISK_4(record->xu.xu_xact_id_4); + if (xn_id != xact->xd_start_xn_id) + break; + tab_id = XT_GET_DISK_4(record->xu.xu_tab_id_4); + rec_id = XT_GET_DISK_4(record->xu.xu_rec_id_4); + row_id = XT_GET_DISK_4(record->xu.xu_row_id_4); + if (!xn_sw_cleanup_variation(self, ss, xact, tab_id, rec_id, record->xu.xu_status_1, record->xu.xu_rec_type_1, record->xu.xu_stat_id_1, row_id, &record->xu.xu_rec_type_1)) + return FAILED; + break; + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_DELETE_FL: + case XT_LOG_ENT_UPDATE_FL_BG: + case XT_LOG_ENT_INSERT_FL_BG: + case XT_LOG_ENT_DELETE_FL_BG: + xn_id = XT_GET_DISK_4(record->xf.xf_xact_id_4); + if (xn_id != xact->xd_start_xn_id) + break; + tab_id = XT_GET_DISK_4(record->xf.xf_tab_id_4); + rec_id = XT_GET_DISK_4(record->xf.xf_rec_id_4); + row_id = XT_GET_DISK_4(record->xf.xf_row_id_4); + if (!xn_sw_cleanup_variation(self, ss, xact, tab_id, rec_id, record->xf.xf_status_1, record->xf.xf_rec_type_1, record->xf.xf_stat_id_1, row_id, &record->xf.xf_rec_type_1)) + return FAILED; + break; + default: + break; + } + } + + cleanup_done: + /* Write the log to indicate the transaction has been cleaned: */ + XTXactCleanupEntryDRec cu; + + cu.xc_status_1 = XT_LOG_ENT_CLEANUP; + cu.xc_checksum_1 = XT_CHECKSUM_1(XT_CHECKSUM4_XACT(xact->xd_start_xn_id)); + XT_SET_DISK_4(cu.xc_xact_id_4, xact->xd_start_xn_id); + + if (!xt_xlog_log_data(self, sizeof(XTXactCleanupEntryDRec), (XTXactLogBufferDPtr) &cu, FALSE)) + return FAILED; + + ss->ss_flush_pending = TRUE; + + xact->xd_flags |= XT_XN_XAC_CLEANED; + ASSERT(db->db_xn_to_clean_id == xact->xd_start_xn_id); +#ifdef MUST_DELAY_REMOVE + xn_sw_add_xact_to_free(self, ss, xact->xd_start_xn_id); +#else + xn_id = xact->xd_start_xn_id; + if (xt_xn_delete_xact(db, xn_id, self)) { + /* Recalculate the minimum memory transaction: */ + ASSERT(!xt_xn_is_before(xn_id, db->db_xn_min_ram_id)); + + if (db->db_xn_min_ram_id == xn_id) { + db->db_xn_min_ram_id = xn_id+1; + } + else { + xtXactID xn_curr_xn_id = xt_xn_get_curr_id(db); + + while (!xt_xn_is_before(xn_curr_xn_id, db->db_xn_min_ram_id)) { // was db->db_xn_min_ram_id <= xn_curr_xn_id + /* db_xn_min_ram_id may be changed, by some other process! */ + xn_id = db->db_xn_min_ram_id; + if (xn_get_xact_details(db, xn_id, self, NULL, NULL, NULL, NULL)) + break; + db->db_xn_min_ram_id = xn_id+1; + } + } + } +#endif + + return OK; +} + +static void xn_free_sw_state(XTThreadPtr self, XNSweeperStatePtr ss) +{ + xn_sw_close_open_table(self, ss); + if (ss->ss_db) + ss->ss_db->db_xlog.xlog_seq_exit(&ss->ss_seqread); + xt_db_set_size(self, &ss->ss_databuf, 0); + xt_bq_set_size(self, &ss->ss_to_free, 0); +} + +static void xn_sw_main(XTThreadPtr self) +{ + XTDatabaseHPtr db = self->st_database; + XNSweeperStatePtr ss; + XTXactDataPtr xact, xact2; + time_t idle_start = 0; + xtXactID curr_id; + + xt_set_priority(self, xt_db_sweeper_priority); + + alloczr_(ss, xn_free_sw_state, sizeof(XNSweeperStateRec), XNSweeperStatePtr); + ss->ss_db = db; + + if (!db->db_xlog.xlog_seq_init(&ss->ss_seqread, xt_db_log_buffer_size, FALSE)) + xt_throw(self); + + ss->ss_to_free.bq_item_size = sizeof(XNSWToFreeItemRec); + ss->ss_to_free.bq_max_waste = XT_TN_MAX_TO_FREE_WASTE; + ss->ss_to_free.bq_item_inc = XT_TN_MAX_TO_FREE_INC; + ss->ss_call_cnt = 0; + ss->ss_flush_pending = FALSE; + + while (!self->t_quit) { + while (!self->t_quit) { + /* We are just about to check the condition for sleeping, + * so if the condition for sleeping holds, then we wil + * exit the loop and sleep. + * + * We will then sleep if nobody sets the flag before we + * actually do sleep! + */ + curr_id = xt_xn_get_curr_id(db); + if (xt_xn_is_before(curr_id, db->db_xn_to_clean_id)) { + db->db_sw_faster &= ~XT_SW_TOO_FAR_BEHIND; + break; + } + /* {TUNING} How far to we allow the sweeper to get behind? + * The higher this is, the higher burst performance can + * be. But too high and the sweeper falls out of reading the + * transaction log cache, and also starts to spread + * changes around in index and data blocks that are no + * longer hot. + */ + if (curr_id - db->db_xn_to_clean_id > 250) + db->db_sw_faster |= XT_SW_TOO_FAR_BEHIND; + else + db->db_sw_faster &= ~XT_SW_TOO_FAR_BEHIND; + xn_sw_could_go_faster(self, db); + idle_start = 0; + + if ((xact = xt_xn_get_xact(db, db->db_xn_to_clean_id, self))) { + xtXactID xn_id; + + if (!(xact->xd_flags & XT_XN_XAC_SWEEP)) + /* Transaction has not yet ending, and ready to sweep. */ + goto sleep; + + /* Check if we can cleanup the transaction. + * We do this by checking to see if there is any running + * transaction which start before the end of this transaction. + */ + xn_id = xact->xd_start_xn_id; + while (xt_xn_is_before(xn_id, xact->xd_end_xn_id)) { + xn_id++; + if ((xact2 = xt_xn_get_xact(db, xn_id, self))) { + if (!(xact2->xd_flags & XT_XN_XAC_ENDED)) { + /* A transaction was started before the end of + * the transaction we wish to sweep, and this + * transaction has not committed, the we have to + * wait. + */ + db->db_stat_sweep_waits++; + goto sleep; + } + } + } + + /* Can cleanup the transaction, and move to the next. */ + if (xact->xd_flags & XT_XN_XAC_LOGGED) { +#ifdef TRACE_SWEEPER_ACTIVITY + printf("SWEEPER: cleanup %d\n", (int) xact->xd_start_xn_id); +#endif + if (!xn_sw_cleanup_xact(self, ss, xact)) { + /* We failed to clean (try again later)... */ +#ifdef TRACE_SWEEPER_ACTIVITY + printf("SWEEPER: cleanup retry...\n", (int) xact->xd_start_xn_id); +#endif + goto sleep; + } +#ifdef TRACE_SWEEPER_ACTIVITY + printf("SWEEPER: cleanup DONE\n", (int) xact->xd_start_xn_id); +#endif + } + else { + /* This was a read-only transaction, it is safe to + * just remove the transaction structure from memory. + * (should not be necessary because RO transactions + * do this themselves): + */ + if (xt_xn_delete_xact(db, db->db_xn_to_clean_id, self)) { + if (db->db_xn_min_ram_id == db->db_xn_to_clean_id) + db->db_xn_min_ram_id = db->db_xn_to_clean_id+1; + } + } + } + + /* Move on to clean the next: */ + db->db_xn_to_clean_id++; + } + + sleep: + + xn_sw_close_open_table(self, ss); + + xn_sw_go_slower(self, db); + + /* Shrink the free list, if it is empty, and larger then + * the default: + */ + if (ss->ss_to_free.bq_size > XT_TN_MAX_TO_FREE) { + if (ss->ss_to_free.bq_front == 0 && ss->ss_to_free.bq_back == 0) + xt_bq_set_size(self, &ss->ss_to_free, XT_TN_MAX_TO_FREE); + } + + /* Windows: close the log file that we have open for reading, if we + * read past the end of the log on the last transaction. + * This makes sure that the log is closed when the checkpointer + * tries to remove or rename it!! + */ + if (ss->ss_seqread.xseq_log_file) { + if (ss->ss_seqread.xseq_rec_log_id != ss->ss_seqread.xseq_log_id) + db->db_xlog.xlog_seq_close(&ss->ss_seqread); + } + + if (ss->ss_flush_pending) { + /* Flush pending means we have written something to the log. + * + * if so we flush the log so that the writer will also do + * its work! + * + * This will lead to the freeer continuing if it is waiting. + */ + + time_t now = time(NULL); + if (idle_start) { + /* By default, we wait for 2 seconds idle time, the + * we flush the log. + */ + if (now >= idle_start + 2) { + if (!xt_xlog_flush_log(self)) + xt_throw(self); + ss->ss_flush_pending = FALSE; + } + } + else + idle_start = now; + } + + /* {WAKE-SW} Waking up the sweeper is very expensive! + * Cost is 3% of execution time on the test: + * runTest(SMALL_SELECT_TEST, 2, 100000) + * + * On the other hand, polling every 1/10 second + * is cheap, because the check for transactions + * ready for cleanup is very quick. + * + * So this is the prefered method. + */ + xn_sw_wait_for_xact(self, db, 10); + } + + if (ss->ss_flush_pending) { + xt_xlog_flush_log(self); + ss->ss_flush_pending = FALSE; + } + + freer_(); // xn_free_sw_state(ss) +} + +static void *xn_sw_run_thread(XTThreadPtr self) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) self->t_data; + int count; + void *mysql_thread; + + mysql_thread = myxt_create_thread(); + + while (!self->t_quit) { + try_(a) { + /* + * The garbage collector requires that the database + * is in use because. + */ + xt_use_database(self, db, XT_FOR_SWEEPER); + + /* This action is both safe and required: + * + * safe: releasing the database is safe because as + * long as this thread is running the database + * reference is valid, and this reference cannot + * be the only one to the database because + * otherwize this thread would not be running. + * + * required: releasing the database is necessary + * otherwise we cannot close the database + * correctly because we only shutdown this + * thread when the database is closed and we + * only close the database when all references + * are removed. + */ + xt_heap_release(self, self->st_database); + + xn_sw_main(self); + } + catch_(a) { + /* This error is "normal"! */ + if (self->t_exception.e_xt_err != XT_ERR_NO_DICTIONARY && + !(self->t_exception.e_xt_err == XT_SIGNAL_CAUGHT && + self->t_exception.e_sys_err == SIGTERM)) + xt_log_and_clear_exception(self); + } + cont_(a); + + /* Avoid releasing the database (done above) */ + self->st_database = NULL; + xt_unuse_database(self, self); + + /* After an exception, pause before trying again... */ + /* Number of seconds */ +#ifdef DEBUG + count = 10; +#else + count = 2*60; +#endif + db->db_sw_idle = XT_THREAD_INERR; + while (!self->t_quit && count > 0) { + sleep(1); + count--; + } + db->db_sw_idle = XT_THREAD_BUSY; + } + + myxt_destroy_thread(mysql_thread, TRUE); + return NULL; +} + +static void xn_sw_free_thread(XTThreadPtr self, void *data) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) data; + + if (db->db_sw_thread) { + xt_lock_mutex(self, &db->db_sw_lock); + pushr_(xt_unlock_mutex, &db->db_sw_lock); + db->db_sw_thread = NULL; + freer_(); // xt_unlock_mutex(&db->db_sw_lock) + } +} + +/* Wait for a transaction to quit: */ +static void xn_sw_wait_for_xact(XTThreadPtr self, XTDatabaseHPtr db, u_int hsecs) +{ + xt_lock_mutex(self, &db->db_sw_lock); + pushr_(xt_unlock_mutex, &db->db_sw_lock); + db->db_sw_idle = XT_THREAD_IDLE; + if (!self->t_quit && !db->db_sw_faster) + xt_timed_wait_cond(self, &db->db_sw_cond, &db->db_sw_lock, hsecs * 10); + db->db_sw_idle = XT_THREAD_BUSY; + db->db_sw_check_count++; + freer_(); // xt_unlock_mutex(&db->db_sw_lock) +} + +xtPublic void xt_start_sweeper(XTThreadPtr self, XTDatabaseHPtr db) +{ + char name[PATH_MAX]; + + sprintf(name, "SW-%s", xt_last_directory_of_path(db->db_main_path)); + xt_remove_dir_char(name); + db->db_sw_thread = xt_create_daemon(self, name); + xt_set_thread_data(db->db_sw_thread, db, xn_sw_free_thread); + xt_run_thread(self, db->db_sw_thread, xn_sw_run_thread); +} + +xtPublic void xt_wait_for_sweeper(XTThreadPtr self, XTDatabaseHPtr db, int abort_time) +{ + time_t then, now; + xtBool message = FALSE; + + if (db->db_sw_thread) { + then = time(NULL); + while (!xt_xn_is_before(xt_xn_get_curr_id(db), db->db_xn_to_clean_id)) { // was db->db_xn_to_clean_id <= xt_xn_get_curr_id(db) + xt_lock_mutex(self, &db->db_sw_lock); + pushr_(xt_unlock_mutex, &db->db_sw_lock); + xt_wakeup_sweeper(db); + freer_(); // xt_unlock_mutex(&db->db_sw_lock) + xt_sleep_milli_second(10); + now = time(NULL); + if (abort_time && now >= then + abort_time) { + xt_logf(XT_NT_INFO, "Aborting wait for '%s' sweeper\n", db->db_name); + message = FALSE; + break; + } + if (now >= then + 2) { + if (!message) { + message = TRUE; + xt_logf(XT_NT_INFO, "Waiting for '%s' sweeper...\n", db->db_name); + } + } + } + + if (message) + xt_logf(XT_NT_INFO, "Sweeper '%s' done.\n", db->db_name); + } +} + +xtPublic void xt_stop_sweeper(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTThreadPtr thr_sw; + + if (db->db_sw_thread) { + xt_lock_mutex(self, &db->db_sw_lock); + pushr_(xt_unlock_mutex, &db->db_sw_lock); + + /* This pointer is safe as long as you have the transaction lock. */ + if ((thr_sw = db->db_sw_thread)) { + xtThreadID tid = thr_sw->t_id; + + /* Make sure the thread quits when woken up. */ + xt_terminate_thread(self, thr_sw); + + xt_wakeup_sweeper(db); + + freer_(); // xt_unlock_mutex(&db->db_sw_lock) + + /* + * GOTCHA: This is a wierd thing but the SIGTERM directed + * at a particular thread (in this case the sweeper) was + * being caught by a different thread and killing the server + * sometimes. Disconcerting. + * (this may only be a problem on Mac OS X) + xt_kill_thread(thread); + */ + xt_wait_for_thread(tid, FALSE); + + /* PMC - This should not be necessary to set the signal here, but in the + * debugger the handler is not called!!? + thr_sw->t_delayed_signal = SIGTERM; + xt_kill_thread(thread); + */ + db->db_sw_thread = NULL; + } + else + freer_(); // xt_unlock_mutex(&db->db_sw_lock) + } +} + +xtPublic void xt_wakeup_sweeper(XTDatabaseHPtr db) +{ + /* This flag makes the gap for the race condition + * very small. + * + * However, this posibility still remains because + * we do not lock the mutex db_sw_lock here. + * + * The reason is that it is too expensive. + * + * In the event that the wakeup is missed the sleeper + * wait will timeout eventually. + */ + if (db->db_sw_idle) { + if (!xt_broadcast_cond_ns(&db->db_sw_cond)) + xt_log_and_clear_exception_ns(); + } +} diff --git a/storage/pbxt/src/xaction_xt.h b/storage/pbxt/src/xaction_xt.h new file mode 100644 index 00000000000..9a651fc2532 --- /dev/null +++ b/storage/pbxt/src/xaction_xt.h @@ -0,0 +1,184 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2005-04-10 Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_xaction_h__ +#define __xt_xaction_h__ + +#include "filesys_xt.h" +#include "lock_xt.h" + +struct XTThread; +struct XTDatabase; +struct XTOpenTable; + +#ifdef DEBUG +//#define XT_USE_XACTION_DEBUG_SIZES +#endif + +#ifdef XT_USE_XACTION_DEBUG_SIZES + +#define XT_XN_DATA_ALLOC_COUNT 400 +#define XT_XN_SEGMENT_SHIFTS 1 +#define XT_XN_HASH_TABLE_SIZE 31 +#define XT_TN_NUMBER_INCREMENT 20 +#define XT_TN_MAX_TO_FREE 20 +#define XT_TN_MAX_TO_FREE_WASTE 3 +#define XT_TN_MAX_TO_FREE_CHECK 3 +#define XT_TN_MAX_TO_FREE_INC 3 + +#else + +#define XT_XN_DATA_ALLOC_COUNT 1250 // Number of pre-allocated transaction data structures per segment +#define XT_XN_SEGMENT_SHIFTS 5 // (32) +#define XT_XN_HASH_TABLE_SIZE 1279 // This is a prime number! +#define XT_TN_NUMBER_INCREMENT 100 // The increment of the transaction number on restart +#define XT_TN_MAX_TO_FREE 800 // The maximum size of the "to free" list +#define XT_TN_MAX_TO_FREE_WASTE 400 +#define XT_TN_MAX_TO_FREE_CHECK 100 // Once we have exceeded the limit, we only try in intervals +#define XT_TN_MAX_TO_FREE_INC 100 + +#endif + +#define XT_XN_NO_OF_SEGMENTS (1 << XT_XN_SEGMENT_SHIFTS) +#define XT_XN_SEGMENT_MASK (XT_XN_NO_OF_SEGMENTS - 1) + +#define XT_XN_XAC_LOGGED 1 +#define XT_XN_XAC_ENDED 2 /* The transaction has ended. */ +#define XT_XN_XAC_COMMITTED 4 /* The transaction was committed. */ +#define XT_XN_XAC_CLEANED 8 /* The transaction has been cleaned. */ +#define XT_XN_XAC_RECOVERED 16 /* This transaction was detected on recovery. */ +#define XT_XN_XAC_SWEEP 32 /* End ID has been set, OK to sweep. */ + +#define XT_XN_VISIBLE 0 /* The transaction is committed, and the record is visible. */ +#define XT_XN_NOT_VISIBLE 1 /* The transaction is committed, but not visible. */ +#define XT_XN_ABORTED 2 /* Transaction was aborted. */ +#define XT_XN_MY_UPDATE 3 /* The record was update by me. */ +#define XT_XN_OTHER_UPDATE 4 /* The record was updated by someone else. */ +#define XT_XN_REREAD 5 /* The transaction is not longer in RAM, status is unkown, retry. */ + +typedef struct XTXactData { + xtXactID xd_start_xn_id; /* Note: may be zero!. */ + xtXactID xd_end_xn_id; /* Note: may be zero!. */ + + /* The begin position: */ + xtLogID xd_begin_log; /* Non-zero if begin has been logged. */ + xtLogOffset xd_begin_offset; + int xd_flags; + xtWord4 xd_end_time; + xtThreadID xd_thread_id; + + /* A transaction may be indexed twice in the hash table. + * Once on the start sequence number, and once on the + * end sequence number. + */ + struct XTXactData *xd_next_xact; /* Next pointer in the hash table, also used by the free list. */ + +} XTXactDataRec, *XTXactDataPtr; + +#define XT_XACT_USE_SPINLOCK + +#ifdef XT_XACT_USE_FASTWRLOCK +#define XT_XACT_LOCK_TYPE XTFastRWLockRec +#define XT_XACT_INIT_LOCK(s, i) xt_fastrwlock_init(s, i) +#define XT_XACT_FREE_LOCK(s, i) xt_fastrwlock_free(s, i) +#define XT_XACT_READ_LOCK(i, s) xt_fastrwlock_slock(i, s) +#define XT_XACT_WRITE_LOCK(i, s) xt_fastrwlock_xlock(i, s) +#define XT_XACT_UNLOCK(i, s) xt_fastrwlock_unlock(i, s) +#elif defined(XT_XACT_USE_PTHREAD_RW) +#define XT_XACT_LOCK_TYPE xt_rwlock_type +#define XT_XACT_INIT_LOCK(s, i) xt_init_rwlock(s, i) +#define XT_XACT_FREE_LOCK(s, i) xt_free_rwlock(i) +#define XT_XACT_READ_LOCK(i, s) xt_slock_rwlock_ns(i) +#define XT_XACT_WRITE_LOCK(i, s) xt_xlock_rwlock_ns(i) +#define XT_XACT_UNLOCK(i, s) xt_unlock_rwlock_ns(i) +#elif defined(XT_XACT_USE_RW_MUTEX) +#define XT_XACT_LOCK_TYPE XTRWMutexRec +#define XT_XACT_INIT_LOCK(s, i) xt_rwmutex_init(s, i) +#define XT_XACT_FREE_LOCK(s, i) xt_rwmutex_free(s, i) +#define XT_XACT_READ_LOCK(i, s) xt_rwmutex_slock(i, (s)->t_id) +#define XT_XACT_WRITE_LOCK(i, s) xt_rwmutex_xlock(i, (s)->t_id) +#define XT_XACT_UNLOCK(i, s) xt_rwmutex_unlock(i, (s)->t_id) +#else +#define XT_XACT_LOCK_TYPE XTSpinLockRec +#define XT_XACT_INIT_LOCK(s, i) xt_spinlock_init_with_autoname(s, i) +#define XT_XACT_FREE_LOCK(s, i) xt_spinlock_free(s, i) +#define XT_XACT_READ_LOCK(i, s) xt_spinlock_lock(i) +#define XT_XACT_WRITE_LOCK(i, s) xt_spinlock_lock(i) +#define XT_XACT_UNLOCK(i, s) xt_spinlock_unlock(i) +#endif + +/* We store the transactions in a number of segments, each + * segment has a hash table. + */ +typedef struct XTXactSeg { + XT_XACT_LOCK_TYPE xs_tab_lock; /* Lock for hash table. */ + xtXactID xs_last_xn_id; /* The last transaction ID added. */ + XTXactDataPtr xs_free_list; /* List of transaction data structures. */ + XTXactDataPtr xs_table[XT_XN_HASH_TABLE_SIZE]; /* Hash table containing the transaction data structures. */ +} XTXactSegRec, *XTXactSegPtr; + +typedef struct XTXactWait { + xtXactID xw_xn_id; +} XTXactWaitRec, *XTXactWaitPtr; + +void xt_thread_wait_init(struct XTThread *self); +void xt_thread_wait_exit(struct XTThread *self); + +void xt_xn_init_db(struct XTThread *self, struct XTDatabase *db); +void xt_xn_exit_db(struct XTThread *self, struct XTDatabase *db); +void xt_start_sweeper(struct XTThread *self, struct XTDatabase *db); +void xt_wait_for_sweeper(struct XTThread *self, struct XTDatabase *db, int abort_time); +void xt_stop_sweeper(struct XTThread *self, struct XTDatabase *db); + +void xt_xn_init_thread(struct XTThread *self, int what_for); +void xt_xn_exit_thread(struct XTThread *self); +void xt_wakeup_sweeper(struct XTDatabase *db); + +xtBool xt_xn_begin(struct XTThread *self); +xtBool xt_xn_commit(struct XTThread *self); +xtBool xt_xn_rollback(struct XTThread *self); +xtBool xt_xn_log_tab_id(struct XTThread *self, xtTableID tab_id); +int xt_xn_status(struct XTOpenTable *ot, xtXactID xn_id, xtRecordID rec_id); +xtBool xt_xn_wait_for_xact(struct XTThread *self, XTXactWaitPtr xw, struct XTLockWait *lw); +void xt_xn_wakeup_waiting_threads(struct XTThread *thread); +void xt_xn_wakeup_thread_list(struct XTThread *thread); +void xt_xn_wakeup_thread(xtThreadID thd_id); +xtXactID xt_xn_get_curr_id(struct XTDatabase *db); +xtWord8 xt_xn_bytes_to_sweep(struct XTDatabase *db, struct XTThread *thread); + +XTXactDataPtr xt_xn_add_old_xact(struct XTDatabase *db, xtXactID xn_id, struct XTThread *thread); +XTXactDataPtr xt_xn_get_xact(struct XTDatabase *db, xtXactID xn_id, struct XTThread *thread); +xtBool xt_xn_delete_xact(struct XTDatabase *db, xtXactID xn_id, struct XTThread *thread); + +inline xtBool xt_xn_is_before(register xtXactID now, register xtXactID then) +{ + if (now >= then) { + if ((now - then) > (xtXactID) 0xFFFFFFFF/2) + return TRUE; + return FALSE; + } + if ((then - now) > (xtXactID) 0xFFFFFFFF/2) + return FALSE; + return TRUE; +} + +#endif diff --git a/storage/pbxt/src/xactlog_xt.cc b/storage/pbxt/src/xactlog_xt.cc new file mode 100644 index 00000000000..82c0d85b770 --- /dev/null +++ b/storage/pbxt/src/xactlog_xt.cc @@ -0,0 +1,2853 @@ +/* Copyright (c) 2007 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2007-10-30 Paul McCullagh + * + * H&G2JCtL + * + * The transaction log contains all operations on the data handle + * and row pointer files of a table. + * + * The transaction log does not contain operations on index data. + */ + +#include "xt_config.h" + +#include <signal.h> + +#include "xactlog_xt.h" +#include "database_xt.h" +#include "util_xt.h" +#include "strutil_xt.h" +#include "filesys_xt.h" +#include "myxt_xt.h" +#include "trace_xt.h" + +#ifdef DEBUG +//#define PRINT_TABLE_MODIFICATIONS +//#define TRACE_WRITER_ACTIVITY +#endif +#ifndef XT_WIN +#ifndef XT_MAC +#define PREWRITE_LOG_COMPLETELY +#endif +#endif + +static void xlog_wr_log_written(XTDatabaseHPtr db); + +/* + * ----------------------------------------------------------------------- + * T R A N S A C T I O L O G C A C H E + */ + +static XTXLogCacheRec xt_xlog_cache; + +/* + * Initialize the disk cache. + */ +xtPublic void xt_xlog_init(XTThreadPtr self, size_t cache_size) +{ + XTXLogBlockPtr block; + + /* + * This is required to ensure that the block + * works! + */ + + /* Determine the number of block that will fit into the given memory: */ + /* + xt_xlog_cache.xlc_hash_size = (cache_size / (XLC_SEGMENT_COUNT * sizeof(XTXLogBlockPtr) + sizeof(XTXLogBlockRec))) / (XLC_SEGMENT_COUNT >> 1); + xt_xlog_cache.xlc_block_count = (cache_size - (XLC_SEGMENT_COUNT * xt_xlog_cache.xlc_hash_size * sizeof(XTXLogBlockPtr))) / sizeof(XTXLogBlockRec); + */ + /* Do not count the size of the cache directory towards the cache size: */ + xt_xlog_cache.xlc_block_count = cache_size / sizeof(XTXLogBlockRec); + xt_xlog_cache.xlc_upper_limit = ((xtWord8) xt_xlog_cache.xlc_block_count * (xtWord8) XT_XLC_BLOCK_SIZE * (xtWord8) 3) / (xtWord8) 4; + xt_xlog_cache.xlc_hash_size = xt_xlog_cache.xlc_block_count / (XLC_SEGMENT_COUNT >> 1); + if (!xt_xlog_cache.xlc_hash_size) + xt_xlog_cache.xlc_hash_size = 1; + + try_(a) { + for (u_int i=0; i<XLC_SEGMENT_COUNT; i++) { + xt_xlog_cache.xlc_segment[i].lcs_hash_table = (XTXLogBlockPtr *) xt_calloc(self, xt_xlog_cache.xlc_hash_size * sizeof(XTXLogBlockPtr)); + xt_init_mutex_with_autoname(self, &xt_xlog_cache.xlc_segment[i].lcs_lock); + xt_init_cond(self, &xt_xlog_cache.xlc_segment[i].lcs_cond); + } + + block = (XTXLogBlockPtr) xt_malloc(self, xt_xlog_cache.xlc_block_count * sizeof(XTXLogBlockRec)); + xt_xlog_cache.xlc_blocks = block; + xt_xlog_cache.xlc_blocks_end = (XTXLogBlockPtr) ((char *) block + (xt_xlog_cache.xlc_block_count * sizeof(XTXLogBlockRec))); + xt_xlog_cache.xlc_next_to_free = block; + xt_init_mutex_with_autoname(self, &xt_xlog_cache.xlc_lock); + xt_init_cond(self, &xt_xlog_cache.xlc_cond); + + for (u_int i=0; i<xt_xlog_cache.xlc_block_count; i++) { + block->xlb_address = 0; + block->xlb_log_id = 0; + block->xlb_state = XLC_BLOCK_FREE; + block++; + } + xt_xlog_cache.xlc_free_count = xt_xlog_cache.xlc_block_count; + } + catch_(a) { + xt_xlog_exit(self); + throw_(); + } + cont_(a); +} + +xtPublic void xt_xlog_exit(XTThreadPtr self) +{ + for (u_int i=0; i<XLC_SEGMENT_COUNT; i++) { + if (xt_xlog_cache.xlc_segment[i].lcs_hash_table) { + xt_free(self, xt_xlog_cache.xlc_segment[i].lcs_hash_table); + xt_xlog_cache.xlc_segment[i].lcs_hash_table = NULL; + xt_free_mutex(&xt_xlog_cache.xlc_segment[i].lcs_lock); + xt_free_cond(&xt_xlog_cache.xlc_segment[i].lcs_cond); + } + } + + if (xt_xlog_cache.xlc_blocks) { + xt_free(self, xt_xlog_cache.xlc_blocks); + xt_xlog_cache.xlc_blocks = NULL; + xt_free_mutex(&xt_xlog_cache.xlc_lock); + xt_free_cond(&xt_xlog_cache.xlc_cond); + } + memset(&xt_xlog_cache, 0, sizeof(xt_xlog_cache)); +} + +xtPublic xtInt8 xt_xlog_get_usage() +{ + xtInt8 size; + + size = (xtInt8) (xt_xlog_cache.xlc_block_count - xt_xlog_cache.xlc_free_count) * sizeof(XTXLogBlockRec); + return size; +} + +xtPublic xtInt8 xt_xlog_get_size() +{ + xtInt8 size; + + size = (xtInt8) xt_xlog_cache.xlc_block_count * sizeof(XTXLogBlockRec); + return size; +} + +xtPublic xtLogID xt_xlog_get_min_log(XTThreadPtr self, XTDatabaseHPtr db) +{ + char path[PATH_MAX]; + XTOpenDirPtr od; + char *file; + xtLogID log_id, min_log = 0; + + xt_strcpy(PATH_MAX, path, db->db_main_path); + xt_add_system_dir(PATH_MAX, path); + if (xt_fs_exists(path)) { + pushsr_(od, xt_dir_close, xt_dir_open(self, path, NULL)); + while (xt_dir_next(self, od)) { + file = xt_dir_name(self, od); + if (xt_starts_with(file, "xlog")) { + if ((log_id = (xtLogID) xt_file_name_to_id(file))) { + if (!min_log || log_id < min_log) + min_log = log_id; + } + } + } + freer_(); // xt_dir_close(od) + } + if (!min_log) + return 1; + return min_log; +} + +xtPublic void xt_xlog_delete_logs(XTThreadPtr self, XTDatabaseHPtr db) +{ + char path[PATH_MAX]; + XTOpenDirPtr od; + char *file; + + /* Close all the index logs before we delete them: */ + db->db_indlogs.ilp_close(self, TRUE); + + /* Close the transaction logs too: */ + db->db_xlog.xlog_close(self); + + xt_strcpy(PATH_MAX, path, db->db_main_path); + xt_add_system_dir(PATH_MAX, path); + if (!xt_fs_exists(path)) + return; + pushsr_(od, xt_dir_close, xt_dir_open(self, path, NULL)); + while (xt_dir_next(self, od)) { + file = xt_dir_name(self, od); + if (xt_ends_with(file, ".xt")) { + xt_add_dir_char(PATH_MAX, path); + xt_strcat(PATH_MAX, path, file); + xt_fs_delete(self, path); + xt_remove_last_name_of_path(path); + } + } + freer_(); // xt_dir_close(od) + + /* I no longer attach the condition: !db->db_multi_path + * to removing this directory. This is because + * the pbxt directory must now be removed explicitly + * by drop database, or by delete all the PBXT + * system tables. + */ + if (!xt_fs_rmdir(NULL, path)) + xt_log_and_clear_exception(self); +} + +#ifdef DEBUG_CHECK_CACHE +static void xt_xlog_check_cache(void) +{ + XTXLogBlockPtr block, pblock; + u_int used_count; + u_int free_count; + + // Check the LRU list: + used_count = 0; + pblock = NULL; + block = xt_xlog_cache.xlc_lru_block; + while (block) { + used_count++; + ASSERT_NS(block->xlb_state != XLC_BLOCK_FREE); + ASSERT_NS(block->xlb_lr_used == pblock); + pblock = block; + block = block->xlb_mr_used; + } + ASSERT_NS(xt_xlog_cache.xlc_mru_block == pblock); + ASSERT_NS(xt_xlog_cache.xlc_free_count + used_count == xt_xlog_cache.xlc_block_count); + + // Check the free list: + free_count = 0; + block = xt_xlog_cache.xlc_free_list; + while (block) { + free_count++; + ASSERT_NS(block->xlb_state == XLC_BLOCK_FREE); + block = block->xlb_next; + } + ASSERT_NS(xt_xlog_cache.xlc_free_count == free_count); +} +#endif + +#ifdef FOR_DEBUG +static void xlog_check_lru_list(XTXLogBlockPtr block) +{ + XTXLogBlockPtr list_block, plist_block; + + plist_block = NULL; + list_block = xt_xlog_cache.xlc_lru_block; + while (list_block) { + ASSERT_NS(block != list_block); + ASSERT_NS(list_block->xlb_lr_used == plist_block); + plist_block = list_block; + list_block = list_block->xlb_mr_used; + } + ASSERT_NS(xt_xlog_cache.xlc_mru_block == plist_block); +} +#endif + +/* + * Log cache blocks are used and freed on a round-robin basis. + * In addition, only data read by restart, and data transfered + * from the transaction log are stored in the transaction log. + * + * This ensures that the transaction log contains the most + * recently written log data. + * + * If the sweeper gets behind due to a long running transacation + * then it falls out of the log cache, and must read from + * the log files directly. + * + * This data read is no longer cached as it was previously. + * This has the advantage that it does not disturn the writter + * thread which would otherwise hit the cache. + * + * If transactions are not too long, it should be possible + * to keep the sweeper in the log cache. + */ +static xtBool xlog_free_block(XTXLogBlockPtr to_free) +{ + XTXLogBlockPtr block, pblock; + xtLogID log_id; + off_t address; + XTXLogCacheSegPtr seg; + u_int hash_idx; + + retry: + log_id = to_free->xlb_log_id; + address = to_free->xlb_address; + + seg = &xt_xlog_cache.xlc_segment[((u_int) address >> XT_XLC_BLOCK_SHIFTS) & XLC_SEGMENT_MASK]; + hash_idx = (((u_int) (address >> (XT_XLC_SEGMENT_SHIFTS + XT_XLC_BLOCK_SHIFTS))) ^ (log_id << 16)) % xt_xlog_cache.xlc_hash_size; + + xt_lock_mutex_ns(&seg->lcs_lock); + if (to_free->xlb_state == XLC_BLOCK_FREE) + goto done_ok; + if (to_free->xlb_log_id != log_id || to_free->xlb_address != address) { + xt_unlock_mutex_ns(&seg->lcs_lock); + goto retry; + } + + pblock = NULL; + block = seg->lcs_hash_table[hash_idx]; + while (block) { + if (block->xlb_address == address && block->xlb_log_id == log_id) { + ASSERT_NS(block == to_free); + ASSERT_NS(block->xlb_state != XLC_BLOCK_FREE); + + /* Wait if the block is being read: */ + if (block->xlb_state == XLC_BLOCK_READING) { + /* Wait for the block to be read, then try again. */ + if (!xt_timed_wait_cond_ns(&seg->lcs_cond, &seg->lcs_lock, 100)) + goto failed; + xt_unlock_mutex_ns(&seg->lcs_lock); + goto retry; + } + + goto free_the_block; + } + pblock = block; + block = block->xlb_next; + } + + /* We did not find the block, someone else freed it... */ + xt_unlock_mutex_ns(&seg->lcs_lock); + goto retry; + + free_the_block: + ASSERT_NS(block->xlb_state == XLC_BLOCK_CLEAN); + + /* Remove from the hash table: */ + if (pblock) + pblock->xlb_next = block->xlb_next; + else + seg->lcs_hash_table[hash_idx] = block->xlb_next; + + /* Free the block: */ + xt_xlog_cache.xlc_free_count++; + block->xlb_state = XLC_BLOCK_FREE; + + done_ok: + xt_unlock_mutex_ns(&seg->lcs_lock); + return OK; + + failed: + xt_unlock_mutex_ns(&seg->lcs_lock); + return FAILED; +} + +#define XT_FETCH_READ 0 +#define XT_FETCH_BLANK 1 +#define XT_FETCH_TEST 2 + +static xtBool xlog_fetch_block(XTXLogBlockPtr *ret_block, XTOpenFilePtr file, xtLogID log_id, off_t address, XTXLogCacheSegPtr *ret_seg, int fetch_type, XTThreadPtr thread) +{ + register XTXLogBlockPtr block; + register XTXLogCacheSegPtr seg; + register u_int hash_idx; + register XTXLogCacheRec *dcg = &xt_xlog_cache; + size_t red_size; + + /* Make sure we have a free block ready (to avoid unlock below): */ + if (fetch_type != XT_FETCH_TEST && dcg->xlc_next_to_free->xlb_state != XLC_BLOCK_FREE) { + if (!xlog_free_block(dcg->xlc_next_to_free)) + return FAILED; + } + + seg = &dcg->xlc_segment[((u_int) address >> XT_XLC_BLOCK_SHIFTS) & XLC_SEGMENT_MASK]; + hash_idx = (((u_int) (address >> (XT_XLC_SEGMENT_SHIFTS + XT_XLC_BLOCK_SHIFTS))) ^ (log_id << 16)) % dcg->xlc_hash_size; + + xt_lock_mutex_ns(&seg->lcs_lock); + retry: + block = seg->lcs_hash_table[hash_idx]; + while (block) { + if (block->xlb_address == address && block->xlb_log_id == log_id) { + ASSERT_NS(block->xlb_state != XLC_BLOCK_FREE); + + /* + * Wait if the block is being read. + */ + if (block->xlb_state == XLC_BLOCK_READING) { + if (!xt_timed_wait_cond_ns(&seg->lcs_cond, &seg->lcs_lock, 100)) { + xt_unlock_mutex_ns(&seg->lcs_lock); + return FAILED; + } + goto retry; + } + + *ret_seg = seg; + *ret_block = block; + thread->st_statistics.st_xlog_cache_hit++; + return OK; + } + block = block->xlb_next; + } + + if (fetch_type == XT_FETCH_TEST) { + xt_unlock_mutex_ns(&seg->lcs_lock); + *ret_seg = NULL; + *ret_block = NULL; + thread->st_statistics.st_xlog_cache_miss++; + return OK; + } + + /* Block not found: */ + get_free_block: + if (dcg->xlc_next_to_free->xlb_state != XLC_BLOCK_FREE) { + xt_unlock_mutex_ns(&seg->lcs_lock); + if (!xlog_free_block(dcg->xlc_next_to_free)) + return FAILED; + xt_lock_mutex_ns(&seg->lcs_lock); + } + + xt_lock_mutex_ns(&dcg->xlc_lock); + block = dcg->xlc_next_to_free; + if (block->xlb_state != XLC_BLOCK_FREE) { + xt_unlock_mutex_ns(&dcg->xlc_lock); + goto get_free_block; + } + dcg->xlc_next_to_free++; + if (dcg->xlc_next_to_free == dcg->xlc_blocks_end) + dcg->xlc_next_to_free = dcg->xlc_blocks; + dcg->xlc_free_count--; + + if (fetch_type == XT_FETCH_READ) { + block->xlb_address = address; + block->xlb_log_id = log_id; + block->xlb_state = XLC_BLOCK_READING; + + xt_unlock_mutex_ns(&dcg->xlc_lock); + + /* Add the block to the hash table: */ + block->xlb_next = seg->lcs_hash_table[hash_idx]; + seg->lcs_hash_table[hash_idx] = block; + + /* Read the block into memory: */ + xt_unlock_mutex_ns(&seg->lcs_lock); + + if (!xt_pread_file(file, address, XT_XLC_BLOCK_SIZE, 0, block->xlb_data, &red_size, &thread->st_statistics.st_xlog, thread)) + return FAILED; + memset(block->xlb_data + red_size, 0, XT_XLC_BLOCK_SIZE - red_size); + thread->st_statistics.st_xlog_cache_miss++; + + xt_lock_mutex_ns(&seg->lcs_lock); + block->xlb_state = XLC_BLOCK_CLEAN; + xt_cond_wakeall(&seg->lcs_cond); + } + else { + block->xlb_address = address; + block->xlb_log_id = log_id; + block->xlb_state = XLC_BLOCK_CLEAN; + memset(block->xlb_data, 0, XT_XLC_BLOCK_SIZE); + + xt_unlock_mutex_ns(&dcg->xlc_lock); + + /* Add the block to the hash table: */ + block->xlb_next = seg->lcs_hash_table[hash_idx]; + seg->lcs_hash_table[hash_idx] = block; + } + + *ret_seg = seg; + *ret_block = block; +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + return OK; +} + +static xtBool xlog_transfer_to_cache(XTOpenFilePtr file, xtLogID log_id, off_t offset, size_t size, xtWord1 *data, XTThreadPtr thread) +{ + off_t address; + XTXLogBlockPtr block; + XTXLogCacheSegPtr seg; + size_t boff; + size_t tfer; + xtBool read_block = FALSE; + +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + /* We have to read the first block, if we are + * not at the begining of the file: + */ + if (offset) + read_block = TRUE; + address = offset & ~XT_XLC_BLOCK_MASK; + + boff = (size_t) (offset - address); + tfer = XT_XLC_BLOCK_SIZE - boff; + if (tfer > size) + tfer = size; + while (size > 0) { + if (!xlog_fetch_block(&block, file, log_id, address, &seg, read_block ? XT_FETCH_READ : XT_FETCH_BLANK, thread)) { +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + return FAILED; + } + ASSERT_NS(block && block->xlb_state == XLC_BLOCK_CLEAN); + memcpy(block->xlb_data + boff, data, tfer); + xt_unlock_mutex_ns(&seg->lcs_lock); + size -= tfer; + data += tfer; + + /* Following block need not be read + * because we always transfer to the + * end of the file! + */ + read_block = FALSE; + address += XT_XLC_BLOCK_SIZE; + + boff = 0; + tfer = size; + if (tfer > XT_XLC_BLOCK_SIZE) + tfer = XT_XLC_BLOCK_SIZE; + } +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + return OK; +} + +static xtBool xt_xlog_read(XTOpenFilePtr file, xtLogID log_id, off_t offset, size_t size, xtWord1 *data, xtBool load_cache, XTThreadPtr thread) +{ + off_t address; + XTXLogBlockPtr block; + XTXLogCacheSegPtr seg; + size_t boff; + size_t tfer; + +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + address = offset & ~XT_XLC_BLOCK_MASK; + boff = (size_t) (offset - address); + tfer = XT_XLC_BLOCK_SIZE - boff; + if (tfer > size) + tfer = size; + while (size > 0) { + if (!xlog_fetch_block(&block, file, log_id, address, &seg, load_cache ? XT_FETCH_READ : XT_FETCH_TEST, thread)) + return FAILED; + if (!block) { + size_t red_size; + + if (!xt_pread_file(file, address + boff, size, 0, data, &red_size, &thread->st_statistics.st_xlog, thread)) + return FAILED; + memset(data + red_size, 0, size - red_size); + return OK; + } + memcpy(data, block->xlb_data + boff, tfer); + xt_unlock_mutex_ns(&seg->lcs_lock); + size -= tfer; + data += tfer; + address += XT_XLC_BLOCK_SIZE; + boff = 0; + tfer = size; + if (tfer > XT_XLC_BLOCK_SIZE) + tfer = XT_XLC_BLOCK_SIZE; + } +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + return OK; +} + +static xtBool xt_xlog_write(XTOpenFilePtr file, xtLogID log_id, off_t offset, size_t size, xtWord1 *data, XTThreadPtr thread) +{ + if (!xt_pwrite_file(file, offset, size, data, &thread->st_statistics.st_xlog, thread)) + return FAILED; + return xlog_transfer_to_cache(file, log_id, offset, size, data, thread); +} + +/* + * ----------------------------------------------------------------------- + * D A T A B A S E T R A N S A C T I O N L O G S + */ + +void XTDatabaseLog::xlog_setup(XTThreadPtr self, XTDatabaseHPtr db, off_t inp_log_file_size, size_t transaction_buffer_size, int log_count) +{ + volatile off_t log_file_size = inp_log_file_size; + size_t log_size; + + try_(a) { + memset(this, 0, sizeof(XTDatabaseLogRec)); + + if (log_count <= 1) + log_count = 1; + else if (log_count > 1000000) + log_count = 1000000; + + xl_db = db; + + xl_log_file_threshold = xt_align_offset(log_file_size, 1024); + xl_log_file_count = log_count; + xl_size_of_buffers = transaction_buffer_size; + + xt_init_mutex_with_autoname(self, &xl_write_lock); + xt_init_cond(self, &xl_write_cond); + xt_writing = 0; + xl_log_id = 0; + xl_log_file = 0; + + xt_spinlock_init_with_autoname(self, &xl_buffer_lock); + + /* Note that we allocate a little bit more for each buffer + * in order to make sure that we can write a trailing record + * to the log buffer. + */ + log_size = transaction_buffer_size + sizeof(XTXactNewLogEntryDRec); + + /* Add in order to round the buffer to an integral of 512 */ + if (log_size % 512) + log_size += (512 - (log_size % 512)); + + xl_write_log_id = 0; + xl_write_log_offset = 0; + xl_write_buf_pos = 0; + xl_write_buf_pos_start = 0; + xl_write_buffer = (xtWord1 *) xt_malloc(self, log_size); + xl_write_done = TRUE; + + xl_append_log_id = 0; + xl_append_log_offset = 0; + xl_append_buf_pos = 0; + xl_append_buf_pos_start = 0; + xl_append_buffer = (xtWord1 *) xt_malloc(self, log_size); + + xl_last_flush_time = 10; + xl_flush_log_id = 0; + xl_flush_log_offset = 0; + } + catch_(a) { + xlog_exit(self); + throw_(); + } + cont_(a); +} + +xtBool XTDatabaseLog::xlog_set_write_offset(xtLogID log_id, xtLogOffset log_offset, xtLogID max_log_id, XTThreadPtr thread) +{ + xl_max_log_id = max_log_id; + + xl_write_log_id = log_id; + xl_write_log_offset = log_offset; + xl_write_buf_pos = 0; + xl_write_buf_pos_start = 0; + xl_write_done = TRUE; + + xl_append_log_id = log_id; + xl_append_log_offset = log_offset; + if (log_offset == 0) { + XTXactLogHeaderDPtr log_head; + + log_head = (XTXactLogHeaderDPtr) xl_append_buffer; + memset(log_head, 0, sizeof(XTXactLogHeaderDRec)); + log_head->xh_status_1 = XT_LOG_ENT_HEADER; + log_head->xh_checksum_1 = XT_CHECKSUM_1(log_id); + XT_SET_DISK_4(log_head->xh_size_4, sizeof(XTXactLogHeaderDRec)); + XT_SET_DISK_4(log_head->xh_log_id_4, log_id); + XT_SET_DISK_2(log_head->xh_version_2, XT_LOG_VERSION_NO); + XT_SET_DISK_4(log_head->xh_magic_4, XT_LOG_FILE_MAGIC); + xl_append_buf_pos = sizeof(XTXactLogHeaderDRec); + xl_append_buf_pos_start = 0; + } + else { + /* Start the log buffer at a block boundary: */ + size_t buf_pos = (size_t) (log_offset % 512); + + xl_append_buf_pos = buf_pos; + xl_append_buf_pos_start = buf_pos; + xl_append_log_offset = log_offset - buf_pos; + + if (!xlog_open_log(log_id, log_offset, thread)) + return FAILED; + + if (!xt_pread_file(xl_log_file, xl_append_log_offset, buf_pos, buf_pos, xl_append_buffer, NULL, &thread->st_statistics.st_xlog, thread)) + return FAILED; + } + + xl_flush_log_id = log_id; + xl_flush_log_offset = log_offset; + return OK; +} + +void XTDatabaseLog::xlog_close(XTThreadPtr self) +{ + if (xl_log_file) { + xt_close_file(self, xl_log_file); + xl_log_file = NULL; + } +} + +void XTDatabaseLog::xlog_exit(XTThreadPtr self) +{ + xt_spinlock_free(self, &xl_buffer_lock); + xt_free_mutex(&xl_write_lock); + xt_free_cond(&xl_write_cond); + xlog_close(self); + if (xl_write_buffer) { + xt_free(self, xl_write_buffer); + xl_write_buffer = NULL; + } + if (xl_append_buffer) { + xt_free(self, xl_append_buffer); + xl_append_buffer = NULL; + } +} + +#define WR_NO_SPACE 1 +#define WR_FLUSH 2 + +xtBool XTDatabaseLog::xlog_flush(XTThreadPtr thread) +{ + if (!xlog_flush_pending()) + return OK; + return xlog_append(thread, 0, NULL, 0, NULL, TRUE, NULL, NULL); +} + +xtBool XTDatabaseLog::xlog_flush_pending() +{ + xtLogID req_flush_log_id; + xtLogOffset req_flush_log_offset; + + xt_lck_slock(&xl_buffer_lock); + req_flush_log_id = xl_append_log_id; + req_flush_log_offset = xl_append_log_offset + xl_append_buf_pos; + if (xt_comp_log_pos(req_flush_log_id, req_flush_log_offset, xl_flush_log_id, xl_flush_log_offset) <= 0) { + xt_spinlock_unlock(&xl_buffer_lock); + return FALSE; + } + xt_spinlock_unlock(&xl_buffer_lock); + return TRUE; +} + +/* + * Write data to the end of the log buffer. + * + * commit is set to true if the caller also requires + * the log to be flushed, after writing the data. + * + * This function returns the log ID and offset of + * the data write position. + */ +xtBool XTDatabaseLog::xlog_append(XTThreadPtr thread, size_t size1, xtWord1 *data1, size_t size2, xtWord1 *data2, xtBool commit, xtLogID *log_id, xtLogOffset *log_offset) +{ + int write_reason = 0; + xtLogID req_flush_log_id; + xtLogOffset req_flush_log_offset; + size_t part_size; + xtWord8 flush_time; + + if (!size1) { + /* Just flush the buffer... */ + xt_lck_slock(&xl_buffer_lock); + write_reason = WR_FLUSH; + req_flush_log_id = xl_append_log_id; + req_flush_log_offset = xl_append_log_offset + xl_append_buf_pos; + xt_spinlock_unlock(&xl_buffer_lock); + goto write_log_to_file; + } + else { + req_flush_log_id = 0; + req_flush_log_offset = 0; + } + + /* + * This is a dirty read, which will send us to the + * best starting position: + * + * If there is space, now, then there is probably + * still enough space, after we have locked the + * buffer for writting. + */ + if (xl_append_buf_pos + size1 + size2 <= xl_size_of_buffers) + goto copy_to_log_buffer; + + /* + * There is not enough space in the append buffer. + * So we need to write the log, until there is space. + */ + write_reason = WR_NO_SPACE; + + write_log_to_file: + if (write_reason) { + /* We need to write for one of 2 reasons: not + * enough space in the buffer, or a flush + * is required. + */ + + /* + * The objective of the following code is to + * pick one writer, out of all threads. + * The others rest will wait for the writer. + */ + xtBool i_am_writer; + + if (write_reason == WR_FLUSH) { + /* Before we flush, check if we should wait for running + * transactions that may commit shortly. + */ + if (xl_db->db_xn_writer_count - xl_db->db_xn_writer_wait_count - xl_db->db_xn_long_running_count > 0 && xl_last_flush_time) { + /* Wait for about as long as the last flush took, + * the idea is to saturate the disk with flushing...: */ + xtWord8 then = xt_trace_clock() + (xtWord8) xl_last_flush_time; + + for (;;) { + xt_critical_wait(); + /* If a thread leaves this loop because times up, or + * a thread manages to flush so fast that this thread + * sleeps during this time, then it could be that + * the required flush occurs before other conditions + * of this loop are met! + * + * So we check here to make sure that the log has not been + * flushed as we require: + */ + if (xt_comp_log_pos(req_flush_log_id, req_flush_log_offset, xl_flush_log_id, xl_flush_log_offset) <= 0) { + ASSERT_NS(xt_comp_log_pos(xl_write_log_id, xl_write_log_offset, xl_append_log_id, xl_append_log_offset) <= 0); + return OK; + } + + if (xl_db->db_xn_writer_count - xl_db->db_xn_writer_wait_count - xl_db->db_xn_long_running_count > 0) + break; + if (xt_trace_clock() >= then) + break; + } + } + } + + i_am_writer = FALSE; + xt_lock_mutex_ns(&xl_write_lock); + if (xt_writing) { + if (!xt_timed_wait_cond_ns(&xl_write_cond, &xl_write_lock, 500)) { + xt_unlock_mutex_ns(&xl_write_lock); + return FALSE; + } + } + else { + xt_writing = TRUE; + i_am_writer = TRUE; + } + xt_unlock_mutex_ns(&xl_write_lock); + + if (!i_am_writer) { + /* If I am not the writer, then I just waited for the + * writer. So it may be that my requirements have now + * been met! + */ + if (write_reason == WR_FLUSH) { + /* If the reason was to flush, then + * check the last flush sequence, maybe it is passed + * our required sequence. + */ + if (xt_comp_log_pos(req_flush_log_id, req_flush_log_offset, xl_flush_log_id, xl_flush_log_offset) <= 0) { + /* The required flush position of the log is before + * or equal to the actual flush position. This means the condition + * for this thread have been satified (via group commit). + * Nothing more to do! + */ + ASSERT_NS(xt_comp_log_pos(xl_write_log_id, xl_write_log_offset, xl_append_log_id, xl_append_log_offset) <= 0); + return OK; + } + goto write_log_to_file; + } + + /* It may be that there is now space in the append buffer: */ + if (xl_append_buf_pos + size1 + size2 <= xl_size_of_buffers) + goto copy_to_log_buffer; + + goto write_log_to_file; + } + + /* I am the writer, check the conditions, again: */ + if (write_reason == WR_FLUSH) { + /* The writer wants the log to be flushed to a particular point: */ + if (xt_comp_log_pos(req_flush_log_id, req_flush_log_offset, xl_flush_log_id, xl_flush_log_offset) <= 0) { + /* The writers required flush position is before or equal + * to the actual position, so the writer is done... + */ + xt_writing = FALSE; + xt_cond_wakeall(&xl_write_cond); + ASSERT_NS(xt_comp_log_pos(xl_write_log_id, xl_write_log_offset, xl_append_log_id, xl_append_log_offset) <= 0); + return OK; + } + /* Not flushed, but what about written? */ + if (xt_comp_log_pos(req_flush_log_id, req_flush_log_offset, xl_write_log_id, xl_write_log_offset + (xl_write_done ? xl_write_buf_pos : 0)) <= 0) { + /* The write position is after or equal to the required flush + * position. This means that all we have to do is flush + * to satisfy the writers condition. + */ + xtBool ok = TRUE; + + if (xl_log_id != xl_write_log_id) + ok = xlog_open_log(xl_write_log_id, xl_write_log_offset + (xl_write_done ? xl_write_buf_pos : 0), thread); + + if (ok) { + if (xl_db->db_co_busy) { + /* [(8)] Flush the compactor log. */ + xt_lock_mutex_ns(&xl_db->db_co_dlog_lock); + ok = xl_db->db_co_thread->st_dlog_buf.dlb_flush_log(TRUE, thread); + xt_unlock_mutex_ns(&xl_db->db_co_dlog_lock); + } + } + + if (ok) { + flush_time = thread->st_statistics.st_xlog.ts_flush_time; + if ((ok = xt_flush_file(xl_log_file, &thread->st_statistics.st_xlog, thread))) { + xl_last_flush_time = (u_int) (thread->st_statistics.st_xlog.ts_flush_time - flush_time); + xl_log_bytes_flushed = xl_log_bytes_written; + + xt_lock_mutex_ns(&xl_db->db_wr_lock); + xl_flush_log_id = xl_write_log_id; + xl_flush_log_offset = xl_write_log_offset + (xl_write_done ? xl_write_buf_pos : 0); + /* + * We have written data to the log, wake the writer to commit + * the data to the database. + */ + xlog_wr_log_written(xl_db); + xt_unlock_mutex_ns(&xl_db->db_wr_lock); + } + } + xt_writing = FALSE; + xt_cond_wakeall(&xl_write_cond); + ASSERT_NS(xt_comp_log_pos(xl_write_log_id, xl_write_log_offset, xl_append_log_id, xl_append_log_offset) <= 0); + return ok; + } + } + else { + /* If there is space in the buffer, then we can go on + * to copy our data into the buffer: + */ + if (xl_append_buf_pos + size1 + size2 <= xl_size_of_buffers) { + xt_writing = FALSE; + xt_cond_wakeall(&xl_write_cond); + goto copy_to_log_buffer; + } + } + + rewrite: + /* If the current write buffer has been written, then + * switch the logs. Otherwise we must try to existing + * write buffer. + */ + if (xl_write_done) { + /* This means that the current write buffer has been writen, + * i.e. it is empty! + */ + xt_spinlock_lock(&xl_buffer_lock); + xtWord1 *tmp_buffer = xl_write_buffer; + + /* The write position is now the append position: */ + xl_write_log_id = xl_append_log_id; + xl_write_log_offset = xl_append_log_offset; + xl_write_buf_pos = xl_append_buf_pos; + xl_write_buf_pos_start = xl_append_buf_pos_start; + xl_write_buffer = xl_append_buffer; + xl_write_done = FALSE; + + /* We have to maintain 512 byte alignment: */ + ASSERT_NS((xl_write_log_offset % 512) == 0); + part_size = xl_write_buf_pos % 512; + if (part_size != 0) + memcpy(tmp_buffer, xl_write_buffer + xl_write_buf_pos - part_size, part_size); + + /* The new append position will be after the + * current append position: + */ + xl_append_log_offset += xl_append_buf_pos - part_size; + xl_append_buf_pos = part_size; + xl_append_buf_pos_start = part_size; + xl_append_buffer = tmp_buffer; // The old write buffer (which is empty) + + /* + * If the append offset exceeds the log threshhold, then + * we set the append buffer to a new log file: + * + * NOTE: This algorithm will cause the log to be overwriten by a maximum + * of the log buffer size! + */ + if (xl_append_log_offset >= xl_log_file_threshold) { + XTXactNewLogEntryDPtr log_tail; + XTXactLogHeaderDPtr log_head; + + xl_append_log_id++; + + /* Write the final record to the old log. + * There is enough space for this because we allocate the + * buffer a little bigger than required. + */ + log_tail = (XTXactNewLogEntryDPtr) (xl_write_buffer + xl_write_buf_pos); + log_tail->xl_status_1 = XT_LOG_ENT_NEW_LOG; + log_tail->xl_checksum_1 = XT_CHECKSUM_1(xl_append_log_id) ^ XT_CHECKSUM_1(xl_write_log_id); + XT_SET_DISK_4(log_tail->xl_log_id_4, xl_append_log_id); + xl_write_buf_pos += sizeof(XTXactNewLogEntryDRec); + + /* We add the header to the next log. */ + log_head = (XTXactLogHeaderDPtr) xl_append_buffer; + memset(log_head, 0, sizeof(XTXactLogHeaderDRec)); + log_head->xh_status_1 = XT_LOG_ENT_HEADER; + log_head->xh_checksum_1 = XT_CHECKSUM_1(xl_append_log_id); + XT_SET_DISK_4(log_head->xh_size_4, sizeof(XTXactLogHeaderDRec)); + XT_SET_DISK_4(log_head->xh_log_id_4, xl_append_log_id); + XT_SET_DISK_2(log_head->xh_version_2, XT_LOG_VERSION_NO); + XT_SET_DISK_4(log_head->xh_magic_4, XT_LOG_FILE_MAGIC); + + xl_append_log_offset = 0; + xl_append_buf_pos = sizeof(XTXactLogHeaderDRec); + xl_append_buf_pos_start = 0; + } + xt_spinlock_unlock(&xl_buffer_lock); + /* We have completed the switch. The append buffer is empty, and + * other threads can begin to write to it. + * + * Meanwhile, this thread will write the write buffer... + */ + } + + /* Make sure we have the correct log open: */ + if (xl_log_id != xl_write_log_id) { + if (!xlog_open_log(xl_write_log_id, xl_write_log_offset, thread)) + goto write_failed; + } + + /* Write the buffer. */ + /* Always write an integral number of 512 byte blocks: */ + ASSERT_NS((xl_write_log_offset % 512) == 0); + if ((part_size = xl_write_buf_pos % 512)) { + part_size = 512 - part_size; + xl_write_buffer[xl_write_buf_pos] = XT_LOG_ENT_END_OF_LOG; + if (!xt_pwrite_file(xl_log_file, xl_write_log_offset, xl_write_buf_pos+part_size, xl_write_buffer, &thread->st_statistics.st_xlog, thread)) + goto write_failed; + } + else { + if (!xt_pwrite_file(xl_log_file, xl_write_log_offset, xl_write_buf_pos, xl_write_buffer, &thread->st_statistics.st_xlog, thread)) + goto write_failed; + } + + /* This part has not been written: */ + part_size = xl_write_buf_pos - xl_write_buf_pos_start; + + /* We have written the data to the log, transfer + * the buffer data into the cache. */ + if (!xlog_transfer_to_cache(xl_log_file, xl_log_id, xl_write_log_offset+xl_write_buf_pos_start, part_size, xl_write_buffer+xl_write_buf_pos_start, thread)) + goto write_failed; + + xl_write_done = TRUE; + xl_log_bytes_written += part_size; + + if (write_reason == WR_FLUSH) { + if (xl_db->db_co_busy) { + /* [(8)] Flush the compactor log. */ + xt_lock_mutex_ns(&xl_db->db_co_dlog_lock); + if (!xl_db->db_co_thread->st_dlog_buf.dlb_flush_log(TRUE, thread)) { + xt_unlock_mutex_ns(&xl_db->db_co_dlog_lock); + goto write_failed; + } + xt_unlock_mutex_ns(&xl_db->db_co_dlog_lock); + } + + /* And flush if required: */ + flush_time = thread->st_statistics.st_xlog.ts_flush_time; + if (!xt_flush_file(xl_log_file, &thread->st_statistics.st_xlog, thread)) + goto write_failed; + xl_last_flush_time = (u_int) (thread->st_statistics.st_xlog.ts_flush_time - flush_time); + + xl_log_bytes_flushed = xl_log_bytes_written; + + xt_lock_mutex_ns(&xl_db->db_wr_lock); + xl_flush_log_id = xl_write_log_id; + xl_flush_log_offset = xl_write_log_offset + xl_write_buf_pos; + /* + * We have written data to the log, wake the writer to commit + * the data to the database. + */ + xlog_wr_log_written(xl_db); + xt_unlock_mutex_ns(&xl_db->db_wr_lock); + + /* Check that the require flush condition has arrived. */ + if (xt_comp_log_pos(req_flush_log_id, req_flush_log_offset, xl_flush_log_id, xl_flush_log_offset) > 0) + /* The required position is still after the current flush + * position, continue writing: */ + goto rewrite; + + xt_writing = FALSE; + xt_cond_wakeall(&xl_write_cond); + ASSERT_NS(xt_comp_log_pos(xl_write_log_id, xl_write_log_offset, xl_append_log_id, xl_append_log_offset) <= 0); + return OK; + } + else + xlog_wr_log_written(xl_db); + + /* + * Check that the buffer is now available, otherwise, + * switch and write again! + */ + if (xl_append_buf_pos + size1 + size2 > xl_size_of_buffers) + goto rewrite; + + xt_writing = FALSE; + xt_cond_wakeall(&xl_write_cond); + } + + copy_to_log_buffer: + xt_spinlock_lock(&xl_buffer_lock); + /* Now we have to check again. The check above was a dirty read! + */ + if (xl_append_buf_pos + size1 + size2 > xl_size_of_buffers) { + xt_spinlock_unlock(&xl_buffer_lock); + /* Not enough space, write the buffer, and return here. */ + write_reason = WR_NO_SPACE; + goto write_log_to_file; + } + + memcpy(xl_append_buffer + xl_append_buf_pos, data1, size1); + if (size2) + memcpy(xl_append_buffer + xl_append_buf_pos + size1, data2, size2); + /* Add the log ID to the checksum! + * This is required because log files are re-used, and we don't + * want the records to be valid when the log is re-used. + */ + register XTXactLogBufferDPtr record; + + /* + * Adjust db_xn_writer_count here. It is protected by + * xl_buffer_lock. + */ + record = (XTXactLogBufferDPtr) (xl_append_buffer + xl_append_buf_pos); + switch (record->xh.xh_status_1) { + case XT_LOG_ENT_HEADER: + case XT_LOG_ENT_END_OF_LOG: + break; + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_UPDATE_FL_BG: + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_INSERT_FL_BG: + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_DELETE_BG: + case XT_LOG_ENT_DELETE_FL: + case XT_LOG_ENT_DELETE_FL_BG: + xtWord2 sum; + + sum = XT_GET_DISK_2(record->xu.xu_checksum_2) ^ XT_CHECKSUM_2(xl_append_log_id); + XT_SET_DISK_2(record->xu.xu_checksum_2, sum); + + if (!thread->st_xact_writer) { + thread->st_xact_writer = TRUE; + thread->st_xact_write_time = xt_db_approximate_time; + xl_db->db_xn_writer_count++; + xl_db->db_xn_total_writer_count++; + } + break; + case XT_LOG_ENT_ROW_NEW: + case XT_LOG_ENT_ROW_NEW_FL: + record->xl.xl_checksum_1 ^= XT_CHECKSUM_1(xl_append_log_id); + + if (!thread->st_xact_writer) { + thread->st_xact_writer = TRUE; + thread->st_xact_write_time = xt_db_approximate_time; + xl_db->db_xn_writer_count++; + xl_db->db_xn_total_writer_count++; + } + break; + case XT_LOG_ENT_COMMIT: + case XT_LOG_ENT_ABORT: + ASSERT_NS(thread->st_xact_writer); + ASSERT_NS(xl_db->db_xn_writer_count > 0); + if (thread->st_xact_writer) { + xl_db->db_xn_writer_count--; + thread->st_xact_writer = FALSE; + if (thread->st_xact_long_running) { + xl_db->db_xn_long_running_count--; + thread->st_xact_long_running = FALSE; + } + } + /* No break required! */ + default: + record->xl.xl_checksum_1 ^= XT_CHECKSUM_1(xl_append_log_id); + break; + } +#ifdef DEBUG + ASSERT_NS(xlog_verify(record, size1 + size2, xl_append_log_id)); +#endif + if (log_id) + *log_id = xl_append_log_id; + if (log_offset) + *log_offset = xl_append_log_offset + xl_append_buf_pos; + xl_append_buf_pos += size1 + size2; + if (commit) { + write_reason = WR_FLUSH; + req_flush_log_id = xl_append_log_id; + req_flush_log_offset = xl_append_log_offset + xl_append_buf_pos; + xt_spinlock_unlock(&xl_buffer_lock); + goto write_log_to_file; + } + + // Failed sometime when outside the spinlock! + ASSERT_NS(xt_comp_log_pos(xl_write_log_id, xl_write_log_offset, xl_append_log_id, xl_append_log_offset + xl_append_buf_pos) <= 0); + xt_spinlock_unlock(&xl_buffer_lock); + + return OK; + + write_failed: + xt_writing = FALSE; + xt_cond_wakeall(&xl_write_cond); + return FAILED; +} + +/* + * This function does not always delete the log. It may just rename a + * log to a new log which it will need. + * This speeds things up: + * + * - No need to pre-allocate the new log. + * - Log data is already flushed (i.e. disk blocks allocated) + * - Log is already in OS cache. + * + * However, it means that I need to checksum things differently + * on each log to make sure I do not treat an old record + * as valid! + * + * Return OK, FAILED or XT_ERR + */ +int XTDatabaseLog::xlog_delete_log(xtLogID del_log_id, XTThreadPtr thread) +{ + char path[PATH_MAX]; + + if (xl_max_log_id < xl_write_log_id) + xl_max_log_id = xl_write_log_id; + + xlog_name(PATH_MAX, path, del_log_id); + + if (xt_db_offline_log_function == XT_RECYCLE_LOGS) { + char new_path[PATH_MAX]; + xtLogID new_log_id; + xtBool ok; + + /* Make sure that the total logs is less than or equal to the log file count + * (plus dynamic component). + */ + while (xl_max_log_id - del_log_id + 1 <= (xl_log_file_count + xt_log_file_dyn_count) && + /* And the number of logs after the current log (including the current log) + * must be less or equal to the log file count. */ + xl_max_log_id - xl_write_log_id + 1 <= xl_log_file_count) { + new_log_id = xl_max_log_id+1; + xlog_name(PATH_MAX, new_path, new_log_id); + ok = xt_fs_rename(NULL, path, new_path); + if (ok) { + xl_max_log_id = new_log_id; + goto done; + } + if (!xt_fs_exists(new_path)) { + /* Try again later: */ + if (thread->t_exception.e_xt_err == XT_SYSTEM_ERROR && + XT_FILE_IN_USE(thread->t_exception.e_sys_err)) + return FAILED; + + return XT_ERR; + } + xl_max_log_id = new_log_id; + } + } + + if (xt_db_offline_log_function != XT_KEEP_LOGS) { + if (!xt_fs_delete(NULL, path)) { + if (thread->t_exception.e_xt_err == XT_SYSTEM_ERROR && + XT_FILE_IN_USE(thread->t_exception.e_sys_err)) + return FAILED; + + return XT_ERR; + } + } + + done: + return OK; +} + +/* PRIVATE FUNCTIONS */ +xtBool XTDatabaseLog::xlog_open_log(xtLogID log_id, off_t curr_write_pos, XTThreadPtr thread) +{ + char log_path[PATH_MAX]; + off_t eof; + + if (xl_log_id == log_id) + return OK; + + if (xl_log_file) { + if (!xt_flush_file(xl_log_file, &thread->st_statistics.st_xlog, thread)) + return FAILED; + xt_close_file_ns(xl_log_file); + xl_log_file = NULL; + xl_log_id = 0; + } + + xlog_name(PATH_MAX, log_path, log_id); + if (!(xl_log_file = xt_open_file_ns(log_path, XT_FS_CREATE | XT_FS_MAKE_PATH))) + return FAILED; + /* Allocate space until the required size: */ + if (curr_write_pos < xl_log_file_threshold) { + eof = xt_seek_eof_file(NULL, xl_log_file); + if (eof == 0) { + /* A new file (bad), we need a greater file count: */ + xt_log_file_dyn_count++; + xt_log_file_dyn_dec = 4; + } + else { + /* An existing file (good): */ + if (xt_log_file_dyn_count > 0) { + if (xt_log_file_dyn_dec > 0) + xt_log_file_dyn_dec--; + else + xt_log_file_dyn_count--; + } + } + if (eof < xl_log_file_threshold) { + char buffer[2048]; + size_t tfer; + + memset(buffer, 0, 2048); + + curr_write_pos = xt_align_offset(curr_write_pos, 512); +#ifdef PREWRITE_LOG_COMPLETELY + while (curr_write_pos < xl_log_file_threshold) { + tfer = 2048; + if ((off_t) tfer > xl_log_file_threshold - curr_write_pos) + tfer = (size_t) (xl_log_file_threshold - curr_write_pos); + if (curr_write_pos == 0) + *buffer = XT_LOG_ENT_END_OF_LOG; + if (!xt_pwrite_file(xl_log_file, curr_write_pos, tfer, buffer, &thread->st_statistics.st_xlog, thread)) + return FAILED; + *buffer = 0; + curr_write_pos += tfer; + } +#else + if (curr_write_pos < xl_log_file_threshold) { + tfer = 2048; + + if (curr_write_pos < xl_log_file_threshold - 2048) + curr_write_pos = xl_log_file_threshold - 2048; + if ((off_t) tfer > xl_log_file_threshold - curr_write_pos) + tfer = (size_t) (xl_log_file_threshold - curr_write_pos); + if (!xt_pwrite_file(xl_log_file, curr_write_pos, tfer, buffer, &thread->st_statistics.st_xlog, thread)) + return FAILED; + } +#endif + } + else if (eof > xl_log_file_threshold + (128 * 1024 * 1024)) { + if (!xt_set_eof_file(NULL, xl_log_file, xl_log_file_threshold)) + return FAILED; + } + } + xl_log_id = log_id; + return OK; +} + +void XTDatabaseLog::xlog_name(size_t size, char *path, xtLogID log_id) +{ + char name[50]; + + sprintf(name, "xlog-%lu.xt", (u_long) log_id); + xt_strcpy(size, path, xl_db->db_main_path); + xt_add_system_dir(size, path); + xt_add_dir_char(size, path); + xt_strcat(size, path, name); +} + +/* + * ----------------------------------------------------------------------- + * T H R E A D T R A N S A C T I O N B U F F E R + */ + +xtPublic xtBool xt_xlog_flush_log(XTThreadPtr thread) +{ + return thread->st_database->db_xlog.xlog_flush(thread); +} + +xtPublic xtBool xt_xlog_log_data(XTThreadPtr thread, size_t size, XTXactLogBufferDPtr log_entry, xtBool commit) +{ + return thread->st_database->db_xlog.xlog_append(thread, size, (xtWord1 *) log_entry, 0, NULL, commit, NULL, NULL); +} + +/* Allocate a record from the free list. */ +xtPublic xtBool xt_xlog_modify_table(struct XTOpenTable *ot, u_int status, xtOpSeqNo op_seq, xtRecordID free_rec_id, xtRecordID rec_id, size_t size, xtWord1 *data) +{ + XTXactLogBufferDRec log_entry; + XTThreadPtr thread = ot->ot_thread; + XTTableHPtr tab = ot->ot_table; + size_t len; + xtWord4 sum = 0; + int check_size = 1; + XTXactDataPtr xact = NULL; + + switch (status) { + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_DELETE: + check_size = 2; + XT_SET_DISK_4(log_entry.xu.xu_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.xu.xu_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.xu.xu_rec_id_4, rec_id); + XT_SET_DISK_2(log_entry.xu.xu_size_2, size); + len = offsetof(XTactUpdateEntryDRec, xu_rec_type_1); + if (!(thread->st_xact_data->xd_flags & XT_XN_XAC_LOGGED)) { + /* Add _BG: */ + status++; + xact = thread->st_xact_data; + xact->xd_flags |= XT_XN_XAC_LOGGED; + } + break; + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_DELETE_FL: + check_size = 2; + XT_SET_DISK_4(log_entry.xf.xf_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.xf.xf_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.xf.xf_rec_id_4, rec_id); + XT_SET_DISK_2(log_entry.xf.xf_size_2, size); + XT_SET_DISK_4(log_entry.xf.xf_free_rec_id_4, free_rec_id); + sum ^= XT_CHECKSUM4_REC(free_rec_id); + len = offsetof(XTactUpdateFLEntryDRec, xf_rec_type_1); + if (!(thread->st_xact_data->xd_flags & XT_XN_XAC_LOGGED)) { + /* Add _BG: */ + status++; + xact = thread->st_xact_data; + xact->xd_flags |= XT_XN_XAC_LOGGED; + } + break; + case XT_LOG_ENT_REC_FREED: + case XT_LOG_ENT_REC_REMOVED: + case XT_LOG_ENT_REC_REMOVED_EXT: + ASSERT_NS(size == 1 + XT_XACT_ID_SIZE + sizeof(XTTabRecFreeDRec)); + XT_SET_DISK_4(log_entry.fr.fr_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.fr.fr_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.fr.fr_rec_id_4, rec_id); + len = offsetof(XTactFreeRecEntryDRec, fr_stat_id_1); + break; + case XT_LOG_ENT_REC_REMOVED_BI: + check_size = 2; + XT_SET_DISK_4(log_entry.rb.rb_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.rb.rb_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.rb.rb_rec_id_4, rec_id); + XT_SET_DISK_2(log_entry.rb.rb_size_2, size); + log_entry.rb.rb_new_rec_type_1 = (xtWord1) free_rec_id; + sum ^= XT_CHECKSUM4_REC(free_rec_id); + len = offsetof(XTactRemoveBIEntryDRec, rb_rec_type_1); + break; + case XT_LOG_ENT_REC_MOVED: + ASSERT_NS(size == 8); + XT_SET_DISK_4(log_entry.xw.xw_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.xw.xw_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.xw.xw_rec_id_4, rec_id); + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1); + break; + case XT_LOG_ENT_REC_CLEANED: + ASSERT_NS(size == offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE); + XT_SET_DISK_4(log_entry.xw.xw_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.xw.xw_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.xw.xw_rec_id_4, rec_id); + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1); + break; + case XT_LOG_ENT_REC_CLEANED_1: + ASSERT_NS(size == 1); + XT_SET_DISK_4(log_entry.xw.xw_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.xw.xw_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.xw.xw_rec_id_4, rec_id); + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1); + break; + case XT_LOG_ENT_REC_UNLINKED: + ASSERT_NS(size == offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE); + XT_SET_DISK_4(log_entry.xw.xw_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.xw.xw_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.xw.xw_rec_id_4, rec_id); + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1); + break; + case XT_LOG_ENT_ROW_NEW: + ASSERT_NS(size == 0); + XT_SET_DISK_4(log_entry.xa.xa_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.xa.xa_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.xa.xa_row_id_4, rec_id); + len = offsetof(XTactRowAddedEntryDRec, xa_row_id_4) + XT_ROW_ID_SIZE; + break; + case XT_LOG_ENT_ROW_NEW_FL: + ASSERT_NS(size == 0); + XT_SET_DISK_4(log_entry.xa.xa_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.xa.xa_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.xa.xa_row_id_4, rec_id); + XT_SET_DISK_4(log_entry.xa.xa_free_list_4, free_rec_id); + sum ^= XT_CHECKSUM4_REC(free_rec_id); + len = offsetof(XTactRowAddedEntryDRec, xa_free_list_4) + XT_ROW_ID_SIZE; + break; + case XT_LOG_ENT_ROW_ADD_REC: + case XT_LOG_ENT_ROW_SET: + case XT_LOG_ENT_ROW_FREED: + ASSERT_NS(size == sizeof(XTTabRowRefDRec)); + XT_SET_DISK_4(log_entry.wr.wr_op_seq_4, op_seq); + XT_SET_DISK_4(log_entry.wr.wr_tab_id_4, tab->tab_id); + XT_SET_DISK_4(log_entry.wr.wr_row_id_4, rec_id); + len = offsetof(XTactWriteRowEntryDRec, wr_ref_id_4); + break; + default: + ASSERT_NS(FALSE); + len = 0; + break; + } + + xtWord1 *dptr = data; + xtWord4 g; + + sum ^= op_seq ^ (tab->tab_id << 8) ^ XT_CHECKSUM4_REC(rec_id); + if ((g = sum & 0xF0000000)) { + sum = sum ^ (g >> 24); + sum = sum ^ g; + } + for (u_int i=0; i<(u_int) size; i++) { + sum = (sum << 4) + *dptr; + if ((g = sum & 0xF0000000)) { + sum = sum ^ (g >> 24); + sum = sum ^ g; + } + dptr++; + } + + log_entry.xh.xh_status_1 = status; + if (check_size == 1) { + log_entry.xh.xh_checksum_1 = XT_CHECKSUM_1(sum); + } + else { + xtWord2 c; + + c = XT_CHECKSUM_2(sum); + XT_SET_DISK_2(log_entry.xu.xu_checksum_2, c); + } +#ifdef PRINT_TABLE_MODIFICATIONS + xt_print_log_record(0, 0, &log_entry); +#endif + if (xact) + return thread->st_database->db_xlog.xlog_append(thread, len, (xtWord1 *) &log_entry, size, data, FALSE, &xact->xd_begin_log, &xact->xd_begin_offset); + + return thread->st_database->db_xlog.xlog_append(thread, len, (xtWord1 *) &log_entry, size, data, FALSE, NULL, NULL); +} + +/* + * ----------------------------------------------------------------------- + * S E Q U E N T I A L L O G R E A D I N G + */ + +/* + * Use the log buffer for sequential reading the log. + */ +xtBool XTDatabaseLog::xlog_seq_init(XTXactSeqReadPtr seq, size_t buffer_size, xtBool load_cache) +{ + seq->xseq_buffer_size = buffer_size; + seq->xseq_load_cache = load_cache; + + seq->xseq_log_id = 0; + seq->xseq_log_file = NULL; + seq->xseq_log_eof = 0; + + seq->xseq_buf_log_offset = 0; + seq->xseq_buffer_len = 0; + seq->xseq_buffer = (xtWord1 *) xt_malloc_ns(buffer_size); + + seq->xseq_rec_log_id = 0; + seq->xseq_rec_log_offset = 0; + seq->xseq_record_len = 0; + + return seq->xseq_buffer != NULL; +} + +void XTDatabaseLog::xlog_seq_exit(XTXactSeqReadPtr seq) +{ + xlog_seq_close(seq); + if (seq->xseq_buffer) { + xt_free_ns(seq->xseq_buffer); + seq->xseq_buffer = NULL; + } +} + +void XTDatabaseLog::xlog_seq_close(XTXactSeqReadPtr seq) +{ + if (seq->xseq_log_file) { + xt_close_file_ns(seq->xseq_log_file); + seq->xseq_log_file = NULL; + } + seq->xseq_log_id = 0; + seq->xseq_log_eof = 0; +} + +xtBool XTDatabaseLog::xlog_seq_start(XTXactSeqReadPtr seq, xtLogID log_id, xtLogOffset log_offset, xtBool missing_ok __attribute__((unused))) +{ + if (seq->xseq_rec_log_id != log_id) { + seq->xseq_rec_log_id = log_id; + seq->xseq_buf_log_offset = seq->xseq_rec_log_offset; + seq->xseq_buffer_len = 0; + } + + /* Windows version: this will help to switch + * to the new log file. + * Due to reading from the log buffers, this was + * not always done! + */ + if (seq->xseq_log_id != log_id) { + if (seq->xseq_log_file) { + xt_close_file_ns(seq->xseq_log_file); + seq->xseq_log_file = NULL; + } + } + seq->xseq_rec_log_offset = log_offset; + seq->xseq_record_len = 0; + return OK; +} + +size_t XTDatabaseLog::xlog_bytes_to_write() +{ + xtLogID log_id; + xtLogOffset log_offset; + xtLogID to_log_id; + xtLogOffset to_log_offset; + size_t byte_count = 0; + + log_id = xl_db->db_wr_log_id; + log_offset = xl_db->db_wr_log_offset; + to_log_id = xl_db->db_xlog.xl_flush_log_id; + to_log_offset = xl_db->db_xlog.xl_flush_log_offset; + + /* Assume the logs have the threshold: */ + if (log_id < to_log_id) { + if (log_offset < xt_db_log_file_threshold) + byte_count = (size_t) (xt_db_log_file_threshold - log_offset); + log_offset = 0; + log_id++; + } + while (log_id < to_log_id) { + byte_count += (size_t) xt_db_log_file_threshold; + log_id++; + } + if (log_offset < to_log_offset) + byte_count += (size_t) (to_log_offset - log_offset); + + return byte_count; +} + +xtBool XTDatabaseLog::xlog_read_from_cache(XTXactSeqReadPtr seq, xtLogID log_id, xtLogOffset log_offset, size_t size, off_t eof, xtWord1 *buffer, size_t *data_read, XTThreadPtr thread) +{ + /* xseq_log_file could be NULL because xseq_log_id is not set + * to zero when xseq_log_file is set to NULL! + * This bug caused a crash in TeamDrive. + */ + if (seq->xseq_log_id != log_id || !seq->xseq_log_file) { + char path[PATH_MAX]; + + if (seq->xseq_log_file) { + xt_close_file_ns(seq->xseq_log_file); + seq->xseq_log_file = NULL; + } + + xlog_name(PATH_MAX, path, log_id); + if (!xt_open_file_ns(&seq->xseq_log_file, path, XT_FS_MISSING_OK)) + return FAILED; + if (!seq->xseq_log_file) { + if (data_read) + *data_read = 0; + return OK; + } + seq->xseq_log_id = log_id; + seq->xseq_log_eof = 0; + } + + if (!eof) { + if (!seq->xseq_log_eof) + seq->xseq_log_eof = xt_seek_eof_file(NULL, seq->xseq_log_file); + eof = seq->xseq_log_eof; + } + + if (log_offset >= eof) { + if (data_read) + *data_read = 0; + return OK; + } + + if ((off_t) size > eof - log_offset) + size = (size_t) (eof - log_offset); + + if (data_read) + *data_read = size; + return xt_xlog_read(seq->xseq_log_file, seq->xseq_log_id, log_offset, size, buffer, seq->xseq_load_cache, thread); +} + +xtBool XTDatabaseLog::xlog_rnd_read(XTXactSeqReadPtr seq, xtLogID log_id, xtLogOffset log_offset, size_t size, xtWord1 *buffer, size_t *data_read, XTThreadPtr thread) +{ + /* Fast track to reading from cache: */ + if (log_id < xl_write_log_id) + return xlog_read_from_cache(seq, log_id, log_offset, size, 0, buffer, data_read, thread); + + if (log_id == xl_write_log_id && log_offset + (xtLogOffset) size <= xl_write_log_offset) + return xlog_read_from_cache(seq, log_id, log_offset, size, xl_write_log_offset, buffer, data_read, thread); + + /* May be in the log write or append buffer: */ + xt_lck_slock(&xl_buffer_lock); + + if (log_id < xl_write_log_id) { + xt_spinlock_unlock(&xl_buffer_lock); + return xlog_read_from_cache(seq, log_id, log_offset, size, 0, buffer, data_read, thread); + } + + /* Check the write buffer: */ + if (log_id == xl_write_log_id) { + if (log_offset + (xtLogOffset) size <= xl_write_log_offset) { + xt_spinlock_unlock(&xl_buffer_lock); + return xlog_read_from_cache(seq, log_id, log_offset, size, xl_write_log_offset, buffer, data_read, thread); + } + + if (log_offset < xl_write_log_offset + (xtLogOffset) xl_write_buf_pos) { + /* Reading partially from the write buffer: */ + if (log_offset >= xl_write_log_offset) { + /* Completely in the buffer. */ + off_t offset = log_offset - xl_write_log_offset; + + if (size > xl_write_buf_pos - offset) + size = (size_t) (xl_write_buf_pos - offset); + + memcpy(buffer, xl_write_buffer + offset, size); + if (data_read) + *data_read = size; + goto unlock_and_return; + } + + /* End part in the buffer: */ + size_t tfer; + + /* The amount that will be taken from the cache: */ + tfer = (size_t) (xl_write_log_offset - log_offset); + + size -= tfer; + if (size > xl_write_buf_pos) + size = xl_write_buf_pos; + + memcpy(buffer + tfer, xl_write_buffer, size); + + xt_spinlock_unlock(&xl_buffer_lock); + + /* Read the first part from the cache: */ + if (data_read) + *data_read = tfer + size; + return xlog_read_from_cache(seq, log_id, log_offset, tfer, log_offset + tfer, buffer, NULL, thread); + } + } + + /* Check the append buffer: */ + if (log_id == xl_append_log_id) { + if (log_offset >= xl_append_log_offset && log_offset < xl_append_log_offset + (xtLogOffset) xl_append_buf_pos) { + /* It is in the append buffer: */ + size_t offset = (size_t) (log_offset - xl_append_log_offset); + + if (size > xl_append_buf_pos - offset) + size = xl_append_buf_pos - offset; + + memcpy(buffer, xl_append_buffer + offset, size); + if (data_read) + *data_read = size; + goto unlock_and_return; + } + } + + if (xl_append_log_id == 0) { + /* This catches the case that + * the log has not yet been initialized + * for writing. + */ + xt_spinlock_unlock(&xl_buffer_lock); + return xlog_read_from_cache(seq, log_id, log_offset, size, 0, buffer, data_read, thread); + } + + if (data_read) + *data_read = 0; + + unlock_and_return: + xt_spinlock_unlock(&xl_buffer_lock); + return OK; +} + +xtBool XTDatabaseLog::xlog_write_thru(XTXactSeqReadPtr seq, size_t size, xtWord1 *data, XTThreadPtr thread) +{ + if (!xt_xlog_write(seq->xseq_log_file, seq->xseq_log_id, seq->xseq_rec_log_offset, size, data, thread)) + return FALSE; + xl_log_bytes_written += size; + seq->xseq_rec_log_offset += size; + return TRUE; +} + +xtBool XTDatabaseLog::xlog_verify(XTXactLogBufferDPtr record, size_t rec_size, xtLogID log_id) +{ + xtWord4 sum = 0; + xtOpSeqNo op_seq; + xtTableID tab_id; + xtRecordID rec_id, free_rec_id; + int check_size = 1; + xtWord1 *dptr; + + switch (record->xh.xh_status_1) { + case XT_LOG_ENT_HEADER: + if (record->xh.xh_checksum_1 != XT_CHECKSUM_1(log_id)) + return FALSE; + if (XT_LOG_HEAD_MAGIC(record, rec_size) != XT_LOG_FILE_MAGIC) + return FALSE; + if (rec_size >= offsetof(XTXactLogHeaderDRec, xh_log_id_4) + 4) { + if (XT_GET_DISK_4(record->xh.xh_log_id_4) != log_id) + return FALSE; + } + return TRUE; + case XT_LOG_ENT_NEW_LOG: + case XT_LOG_ENT_DEL_LOG: + return record->xl.xl_checksum_1 == (XT_CHECKSUM_1(XT_GET_DISK_4(record->xl.xl_log_id_4)) ^ XT_CHECKSUM_1(log_id)); + case XT_LOG_ENT_NEW_TAB: + return record->xl.xl_checksum_1 == (XT_CHECKSUM_1(XT_GET_DISK_4(record->xt.xt_tab_id_4)) ^ XT_CHECKSUM_1(log_id)); + case XT_LOG_ENT_COMMIT: + case XT_LOG_ENT_ABORT: + sum = XT_CHECKSUM4_XACT(XT_GET_DISK_4(record->xe.xe_xact_id_4)) ^ XT_CHECKSUM4_XACT(XT_GET_DISK_4(record->xe.xe_not_used_4)); + return record->xe.xe_checksum_1 == (XT_CHECKSUM_1(sum) ^ XT_CHECKSUM_1(log_id)); + case XT_LOG_ENT_CLEANUP: + sum = XT_CHECKSUM4_XACT(XT_GET_DISK_4(record->xc.xc_xact_id_4)); + return record->xc.xc_checksum_1 == (XT_CHECKSUM_1(sum) ^ XT_CHECKSUM_1(log_id)); + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_DELETE_BG: + check_size = 2; + op_seq = XT_GET_DISK_4(record->xu.xu_op_seq_4); + tab_id = XT_GET_DISK_4(record->xu.xu_tab_id_4); + rec_id = XT_GET_DISK_4(record->xu.xu_rec_id_4); + dptr = &record->xu.xu_rec_type_1; + rec_size -= offsetof(XTactUpdateEntryDRec, xu_rec_type_1); + break; + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_DELETE_FL: + case XT_LOG_ENT_UPDATE_FL_BG: + case XT_LOG_ENT_INSERT_FL_BG: + case XT_LOG_ENT_DELETE_FL_BG: + check_size = 2; + op_seq = XT_GET_DISK_4(record->xf.xf_op_seq_4); + tab_id = XT_GET_DISK_4(record->xf.xf_tab_id_4); + rec_id = XT_GET_DISK_4(record->xf.xf_rec_id_4); + free_rec_id = XT_GET_DISK_4(record->xf.xf_free_rec_id_4); + sum ^= XT_CHECKSUM4_REC(free_rec_id); + dptr = &record->xf.xf_rec_type_1; + rec_size -= offsetof(XTactUpdateFLEntryDRec, xf_rec_type_1); + break; + case XT_LOG_ENT_REC_FREED: + case XT_LOG_ENT_REC_REMOVED: + case XT_LOG_ENT_REC_REMOVED_EXT: + op_seq = XT_GET_DISK_4(record->fr.fr_op_seq_4); + tab_id = XT_GET_DISK_4(record->fr.fr_tab_id_4); + rec_id = XT_GET_DISK_4(record->fr.fr_rec_id_4); + dptr = &record->fr.fr_stat_id_1; + rec_size -= offsetof(XTactFreeRecEntryDRec, fr_stat_id_1); + break; + case XT_LOG_ENT_REC_REMOVED_BI: + check_size = 2; + op_seq = XT_GET_DISK_4(record->rb.rb_op_seq_4); + tab_id = XT_GET_DISK_4(record->rb.rb_tab_id_4); + rec_id = XT_GET_DISK_4(record->rb.rb_rec_id_4); + free_rec_id = (xtWord4) record->rb.rb_new_rec_type_1; + sum ^= XT_CHECKSUM4_REC(free_rec_id); + dptr = &record->rb.rb_rec_type_1; + rec_size -= offsetof(XTactRemoveBIEntryDRec, rb_rec_type_1); + break; + case XT_LOG_ENT_REC_MOVED: + case XT_LOG_ENT_REC_CLEANED: + case XT_LOG_ENT_REC_CLEANED_1: + case XT_LOG_ENT_REC_UNLINKED: + op_seq = XT_GET_DISK_4(record->xw.xw_op_seq_4); + tab_id = XT_GET_DISK_4(record->xw.xw_tab_id_4); + rec_id = XT_GET_DISK_4(record->xw.xw_rec_id_4); + dptr = &record->xw.xw_rec_type_1; + rec_size -= offsetof(XTactWriteRecEntryDRec, xw_rec_type_1); + break; + case XT_LOG_ENT_ROW_NEW: + case XT_LOG_ENT_ROW_NEW_FL: + op_seq = XT_GET_DISK_4(record->xa.xa_op_seq_4); + tab_id = XT_GET_DISK_4(record->xa.xa_tab_id_4); + rec_id = XT_GET_DISK_4(record->xa.xa_row_id_4); + if (record->xh.xh_status_1 == XT_LOG_ENT_ROW_NEW) { + dptr = (xtWord1 *) record + offsetof(XTactRowAddedEntryDRec, xa_free_list_4); + rec_size -= offsetof(XTactRowAddedEntryDRec, xa_free_list_4); + } + else { + free_rec_id = XT_GET_DISK_4(record->xa.xa_free_list_4); + sum ^= XT_CHECKSUM4_REC(free_rec_id); + dptr = (xtWord1 *) record + sizeof(XTactRowAddedEntryDRec); + rec_size -= sizeof(XTactRowAddedEntryDRec); + } + break; + case XT_LOG_ENT_ROW_ADD_REC: + case XT_LOG_ENT_ROW_SET: + case XT_LOG_ENT_ROW_FREED: + op_seq = XT_GET_DISK_4(record->wr.wr_op_seq_4); + tab_id = XT_GET_DISK_4(record->wr.wr_tab_id_4); + rec_id = XT_GET_DISK_4(record->wr.wr_row_id_4); + dptr = (xtWord1 *) &record->wr.wr_ref_id_4; + rec_size -= offsetof(XTactWriteRowEntryDRec, wr_ref_id_4); + break; + case XT_LOG_ENT_OP_SYNC: + return record->xl.xl_checksum_1 == (XT_CHECKSUM_1(XT_GET_DISK_4(record->os.os_time_4)) ^ XT_CHECKSUM_1(log_id)); + case XT_LOG_ENT_NO_OP: + sum = XT_GET_DISK_4(record->no.no_tab_id_4) ^ XT_GET_DISK_4(record->no.no_op_seq_4); + return record->xe.xe_checksum_1 == (XT_CHECKSUM_1(sum) ^ XT_CHECKSUM_1(log_id)); + case XT_LOG_ENT_END_OF_LOG: + return FALSE; + default: + ASSERT_NS(FALSE); + return FALSE; + } + + xtWord4 g; + + sum ^= (xtWord4) op_seq ^ ((xtWord4) tab_id << 8) ^ XT_CHECKSUM4_REC(rec_id); + + if ((g = sum & 0xF0000000)) { + sum = sum ^ (g >> 24); + sum = sum ^ g; + } + for (u_int i=0; i<(u_int) rec_size; i++) { + sum = (sum << 4) + *dptr; + if ((g = sum & 0xF0000000)) { + sum = sum ^ (g >> 24); + sum = sum ^ g; + } + dptr++; + } + + if (check_size == 1) { + if (record->xh.xh_checksum_1 != (XT_CHECKSUM_1(sum) ^ XT_CHECKSUM_1(log_id))) { + return FAILED; + } + } + else { + if (XT_GET_DISK_2(record->xu.xu_checksum_2) != (XT_CHECKSUM_2(sum) ^ XT_CHECKSUM_2(log_id))) { + return FAILED; + } + } + return TRUE; +} + +xtBool XTDatabaseLog::xlog_seq_next(XTXactSeqReadPtr seq, XTXactLogBufferDPtr *ret_entry, xtBool verify, XTThreadPtr thread) +{ + XTXactLogBufferDPtr record; + size_t tfer; + size_t len; + size_t rec_offset; + size_t max_rec_len; + size_t size; + u_int check_size = 1; + + /* Go to the next record (xseq_record_len must be initialized + * to 0 for this to work. + */ + seq->xseq_rec_log_offset += seq->xseq_record_len; + seq->xseq_record_len = 0; + + if (seq->xseq_rec_log_offset < seq->xseq_buf_log_offset || + seq->xseq_rec_log_offset >= seq->xseq_buf_log_offset + (xtLogOffset) seq->xseq_buffer_len) { + /* The current position is nowhere near the buffer, read data into the + * buffer: + */ + tfer = seq->xseq_buffer_size; + if (!xlog_rnd_read(seq, seq->xseq_rec_log_id, seq->xseq_rec_log_offset, tfer, seq->xseq_buffer, &tfer, thread)) + return FAILED; + seq->xseq_buf_log_offset = seq->xseq_rec_log_offset; + seq->xseq_buffer_len = tfer; + + /* Should we go to the next log? */ + if (!tfer) { + goto return_empty; + } + } + + /* The start of the record is in the buffer: */ + read_from_buffer: + rec_offset = (size_t) (seq->xseq_rec_log_offset - seq->xseq_buf_log_offset); + max_rec_len = seq->xseq_buffer_len - rec_offset; + size = 0; + + /* Check the type of record: */ + record = (XTXactLogBufferDPtr) (seq->xseq_buffer + rec_offset); + switch (record->xh.xh_status_1) { + case XT_LOG_ENT_HEADER: + len = sizeof(XTXactLogHeaderDRec); + break; + case XT_LOG_ENT_NEW_LOG: + case XT_LOG_ENT_DEL_LOG: + len = sizeof(XTXactNewLogEntryDRec); + break; + case XT_LOG_ENT_NEW_TAB: + len = sizeof(XTXactNewTabEntryDRec); + break; + case XT_LOG_ENT_COMMIT: + case XT_LOG_ENT_ABORT: + len = sizeof(XTXactEndEntryDRec); + break; + case XT_LOG_ENT_CLEANUP: + len = sizeof(XTXactCleanupEntryDRec); + break; + case XT_LOG_ENT_REC_MODIFIED: + case XT_LOG_ENT_UPDATE: + case XT_LOG_ENT_INSERT: + case XT_LOG_ENT_DELETE: + case XT_LOG_ENT_UPDATE_BG: + case XT_LOG_ENT_INSERT_BG: + case XT_LOG_ENT_DELETE_BG: + check_size = 2; + len = offsetof(XTactUpdateEntryDRec, xu_rec_type_1); + if (len > max_rec_len) + /* The size is not in the buffer: */ + goto read_more; + len += (size_t) XT_GET_DISK_2(record->xu.xu_size_2); + break; + case XT_LOG_ENT_UPDATE_FL: + case XT_LOG_ENT_INSERT_FL: + case XT_LOG_ENT_DELETE_FL: + case XT_LOG_ENT_UPDATE_FL_BG: + case XT_LOG_ENT_INSERT_FL_BG: + case XT_LOG_ENT_DELETE_FL_BG: + check_size = 2; + len = offsetof(XTactUpdateFLEntryDRec, xf_rec_type_1); + if (len > max_rec_len) + /* The size is not in the buffer: */ + goto read_more; + len += (size_t) XT_GET_DISK_2(record->xf.xf_size_2); + break; + case XT_LOG_ENT_REC_FREED: + case XT_LOG_ENT_REC_REMOVED: + case XT_LOG_ENT_REC_REMOVED_EXT: + /* [(7)] REMOVE is now a extended version of FREE! */ + len = offsetof(XTactFreeRecEntryDRec, fr_rec_type_1) + sizeof(XTTabRecFreeDRec); + break; + case XT_LOG_ENT_REC_REMOVED_BI: + check_size = 2; + len = offsetof(XTactRemoveBIEntryDRec, rb_rec_type_1); + if (len > max_rec_len) + /* The size is not in the buffer: */ + goto read_more; + len += (size_t) XT_GET_DISK_2(record->rb.rb_size_2); + break; + case XT_LOG_ENT_REC_MOVED: + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1) + 8; + break; + case XT_LOG_ENT_REC_CLEANED: + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1) + offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE; + break; + case XT_LOG_ENT_REC_CLEANED_1: + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1) + 1; + break; + case XT_LOG_ENT_REC_UNLINKED: + len = offsetof(XTactWriteRecEntryDRec, xw_rec_type_1) + offsetof(XTTabRecHeadDRec, tr_prev_rec_id_4) + XT_RECORD_ID_SIZE; + break; + case XT_LOG_ENT_ROW_NEW: + len = offsetof(XTactRowAddedEntryDRec, xa_row_id_4) + XT_ROW_ID_SIZE; + break; + case XT_LOG_ENT_ROW_NEW_FL: + len = offsetof(XTactRowAddedEntryDRec, xa_free_list_4) + XT_ROW_ID_SIZE; + break; + case XT_LOG_ENT_ROW_ADD_REC: + case XT_LOG_ENT_ROW_SET: + case XT_LOG_ENT_ROW_FREED: + len = offsetof(XTactWriteRowEntryDRec, wr_ref_id_4) + XT_REF_ID_SIZE; + break; + case XT_LOG_ENT_OP_SYNC: + len = sizeof(XTactOpSyncEntryDRec); + break; + case XT_LOG_ENT_NO_OP: + len = sizeof(XTactNoOpEntryDRec); + break; + case XT_LOG_ENT_END_OF_LOG: { + off_t eof = seq->xseq_log_eof, adjust; + + if (eof > seq->xseq_rec_log_offset) { + adjust = eof - seq->xseq_rec_log_offset; + + seq->xseq_record_len = (size_t) adjust; + } + goto return_empty; + } + default: + ASSERT_NS(FALSE); + seq->xseq_record_len = 0; + goto return_empty; + } + + ASSERT_NS(len <= seq->xseq_buffer_size); + if (len <= max_rec_len) { + if (verify) { + if (!xlog_verify(record, len, seq->xseq_rec_log_id)) { + goto return_empty; + } + } + + /* The record is completely in the buffer: */ + seq->xseq_record_len = len; + *ret_entry = record; + return OK; + } + + /* The record is partially in the buffer. */ + memmove(seq->xseq_buffer, seq->xseq_buffer + rec_offset, max_rec_len); + seq->xseq_buf_log_offset += rec_offset; + seq->xseq_buffer_len = max_rec_len; + + /* Read the rest, as far as possible: */ + tfer = seq->xseq_buffer_size - max_rec_len; + if (!xlog_rnd_read(seq, seq->xseq_rec_log_id, seq->xseq_buf_log_offset + max_rec_len, tfer, seq->xseq_buffer + max_rec_len, &tfer, thread)) + return FAILED; + seq->xseq_buffer_len += tfer; + + if (seq->xseq_buffer_len < len) { + /* A partial record is in the log, must be the end of the log: */ + goto return_empty; + } + + /* The record is not completely in the buffer: */ + seq->xseq_record_len = len; + *ret_entry = (XTXactLogBufferDPtr) seq->xseq_buffer; + return OK; + + read_more: + ASSERT_NS(len <= seq->xseq_buffer_size); + memmove(seq->xseq_buffer, seq->xseq_buffer + rec_offset, max_rec_len); + seq->xseq_buf_log_offset += rec_offset; + seq->xseq_buffer_len = max_rec_len; + + /* Read the rest, as far as possible: */ + tfer = seq->xseq_buffer_size - max_rec_len; + if (!xlog_rnd_read(seq, seq->xseq_rec_log_id, seq->xseq_buf_log_offset + max_rec_len, tfer, seq->xseq_buffer + max_rec_len, &tfer, thread)) + return FAILED; + seq->xseq_buffer_len += tfer; + + if (seq->xseq_buffer_len < len + size) { + /* We did not get as much as we need, return an empty record: */ + goto return_empty; + } + + goto read_from_buffer; + + return_empty: + *ret_entry = NULL; + return OK; +} + +void XTDatabaseLog::xlog_seq_skip(XTXactSeqReadPtr seq, size_t size) +{ + seq->xseq_record_len += size; +} + +/* ---------------------------------------------------------------------- + * W R I T E R P R O C E S S + */ + +/* + * The log has been written. Wake the writer to commit the + * data to disk, if the transaction log cache is full. + * + * Data may not be written to the database until it has been + * flushed to the log. + * + * This is because there is no way to undo changes to the + * database. + * + * However, I have dicovered that writing constantly in the + * background can disturb the I/O in the foreground. + * + * So we can delay the writing of the database. But we should + * not delay it longer than we have transaction log cache. + * + * If so, the data that we need will fall out of the cache + * and we will have to read it again. + */ +static void xlog_wr_log_written(XTDatabaseHPtr db) +{ + if (db->db_wr_idle) { + xtWord8 cached_bytes; + + /* Determine if the cached log data is about to fall out of the cache. */ + cached_bytes = db->db_xlog.xl_log_bytes_written - db->db_xlog.xl_log_bytes_read; + /* The limit is 75%: */ + if (cached_bytes >= xt_xlog_cache.xlc_upper_limit) { + if (!xt_broadcast_cond_ns(&db->db_wr_cond)) + xt_log_and_clear_exception_ns(); + } + } +} + +#define XT_MORE_TO_WRITE 1 +#define XT_FREER_WAITING 2 +#define XT_NO_ACTIVITY 3 +#define XT_LOG_CACHE_FULL 4 +#define XT_CHECKPOINT_REQ 5 +#define XT_THREAD_WAITING 6 +#define XT_TIME_TO_WRITE 7 + +/* + * Wait for a transaction to quit, i.e. the log to be flushed. + */ +static void xlog_wr_wait_for_log_flush(XTThreadPtr self, XTDatabaseHPtr db) +{ + xtXactID last_xn_id; + xtWord8 cached_bytes; + int reason = XT_MORE_TO_WRITE; + +#ifdef TRACE_WRITER_ACTIVITY + printf("WRITER --- DONE\n"); +#endif + + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + + /* + * Wake the freeer if it is waiting for this writer, before + * we go to sleep! + */ + if (db->db_wr_freeer_waiting) { + if (!xt_broadcast_cond_ns(&db->db_wr_cond)) + xt_log_and_clear_exception_ns(); + } + + if (db->db_wr_flush_point_log_id == db->db_xlog.xl_flush_log_id && + db->db_wr_flush_point_log_offset == db->db_xlog.xl_flush_log_offset) { + /* Wake the checkpointer to flush the indexes: + * PMC 15.05.2008 - Not doing this anymore! + xt_wake_checkpointer(self, db); + */ + + /* Sleep as long as the flush point has not changed, from the last + * target flush point. + */ + while (!self->t_quit && + db->db_wr_flush_point_log_id == db->db_xlog.xl_flush_log_id && + db->db_wr_flush_point_log_offset == db->db_xlog.xl_flush_log_offset && + reason != XT_LOG_CACHE_FULL && + reason != XT_TIME_TO_WRITE && + reason != XT_CHECKPOINT_REQ) { + + /* + * Sleep as long as there is no reason to write any more... + */ + while (!self->t_quit) { + last_xn_id = db->db_xn_curr_id; + db->db_wr_idle = XT_THREAD_IDLE; + xt_timed_wait_cond(self, &db->db_wr_cond, &db->db_wr_lock, 500); + db->db_wr_idle = XT_THREAD_BUSY; + /* These are the reasons for doing work: */ + /* The free'er thread is waiting for the writer: */ + if (db->db_wr_freeer_waiting) { + reason = XT_FREER_WAITING; + break; + } + /* Some thread is waiting for the writer: */ + if (db->db_wr_thread_waiting) { + reason = XT_THREAD_WAITING; + break; + } + /* Check if the cache will soon overflow... */ + ASSERT(db->db_xlog.xl_log_bytes_written >= db->db_xlog.xl_log_bytes_read); + ASSERT(db->db_xlog.xl_log_bytes_written >= db->db_xlog.xl_log_bytes_flushed); + /* Sanity check: */ + ASSERT(db->db_xlog.xl_log_bytes_written < db->db_xlog.xl_log_bytes_read + 500000000); + /* This is the amount of data still to be written: */ + cached_bytes = db->db_xlog.xl_log_bytes_written - db->db_xlog.xl_log_bytes_read; + /* The limit is 75%: */ + if (cached_bytes >= xt_xlog_cache.xlc_upper_limit) { + reason = XT_LOG_CACHE_FULL; + break; + } + + /* TODO: Create a system variable which specifies the write frequency. *//* + if (cached_bytes >= (12 * 1024 * 1024)) { + reason = XT_TIME_TO_WRITE; + break; + } + */ + + /* Check if we are holding up a checkpoint: */ + if (db->db_restart.xres_cp_required || + db->db_restart.xres_is_checkpoint_pending(db->db_xlog.xl_write_log_id, db->db_xlog.xl_write_log_offset)) { + /* Enough data has been flushed for a checkpoint: */ + if (!db->db_restart.xres_is_checkpoint_pending(db->db_wr_log_id, db->db_wr_log_offset)) { + /* But not enough data has been written for a checkpoint: */ + reason = XT_CHECKPOINT_REQ; + break; + } + } + /* There is no activity, if the current ID has not changed during + * the wait, and the sweeper has nothing to do, and the checkpointer. + */ + if (db->db_xn_curr_id == last_xn_id && + xt_xn_is_before(xt_xn_get_curr_id(db), db->db_xn_to_clean_id) && // db->db_xn_curr_id < db->db_xn_to_clean_id + !db->db_restart.xres_is_checkpoint_pending(db->db_xlog.xl_write_log_id, db->db_xlog.xl_write_log_offset)) { + /* There seems to be no activity at the moment. + * this might be a good time to write the log data. + */ + reason = XT_NO_ACTIVITY; + break; + } + } + } + } + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + + if (reason == XT_LOG_CACHE_FULL || reason == XT_TIME_TO_WRITE || reason == XT_CHECKPOINT_REQ) { + /* Make sure that we have something to write: */ + if (db->db_xlog.xlog_bytes_to_write() < 2 * 1204 * 1024) + xt_xlog_flush_log(self); + } + +#ifdef TRACE_WRITER_ACTIVITY + switch (reason) { + case XT_MORE_TO_WRITE: printf("WRITER --- still more to write...\n"); break; + case XT_FREER_WAITING: printf("WRITER --- free'er waiting for writer...\n"); break; + case XT_NO_ACTIVITY: printf("WRITER --- no activity...\n"); break; + case XT_LOG_CACHE_FULL: printf("WRITER --- running out of log cache...\n"); break; + case XT_CHECKPOINT_REQ: printf("WRITER --- enough flushed for a checkpoint...\n"); break; + case XT_THREAD_WAITING: printf("WRITER --- thread waiting for writer...\n"); break; + case XT_TIME_TO_WRITE: printf("WRITER --- limit of 12MB reached, time to write...\n"); break; + } +#endif +} + +static void xlog_wr_could_go_faster(XTThreadPtr self, XTDatabaseHPtr db) +{ + if (db->db_wr_faster) { + if (!db->db_wr_fast) { + xt_set_normal_priority(self); + db->db_wr_fast = TRUE; + } + db->db_wr_faster = FALSE; + } +} + +static void xlog_wr_could_go_slower(XTThreadPtr self, XTDatabaseHPtr db) +{ + if (db->db_wr_fast && !db->db_wr_faster) { + xt_set_low_priority(self); + db->db_wr_fast = FALSE; + } +} + +static void xlog_wr_main(XTThreadPtr self) +{ + XTDatabaseHPtr db = self->st_database; + XTWriterStatePtr ws; + XTXactLogBufferDPtr record; + + xt_set_low_priority(self); + + alloczr_(ws, xt_free_writer_state, sizeof(XTWriterStateRec), XTWriterStatePtr); + ws->ws_db = db; + ws->ws_in_recover = FALSE; + + if (!db->db_xlog.xlog_seq_init(&ws->ws_seqread, xt_db_log_buffer_size, FALSE)) + xt_throw(self); + + if (!db->db_xlog.xlog_seq_start(&ws->ws_seqread, db->db_wr_log_id, db->db_wr_log_offset, FALSE)) + xt_throw(self); + + while (!self->t_quit) { + while (!self->t_quit) { + /* Determine the point to which we can write. + * This is the current log flush point! + */ + xt_lock_mutex_ns(&db->db_wr_lock); + db->db_wr_flush_point_log_id = db->db_xlog.xl_flush_log_id; + db->db_wr_flush_point_log_offset = db->db_xlog.xl_flush_log_offset; + xt_unlock_mutex_ns(&db->db_wr_lock); + + if (xt_comp_log_pos(db->db_wr_log_id, db->db_wr_log_offset, db->db_wr_flush_point_log_id, db->db_wr_flush_point_log_offset) >= 0) { + break; + } + + while (!self->t_quit) { + xlog_wr_could_go_faster(self, db); + + /* This is the restart position: */ + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + db->db_wr_log_id = ws->ws_seqread.xseq_rec_log_id; + db->db_wr_log_offset = ws->ws_seqread.xseq_rec_log_offset + ws->ws_seqread.xseq_record_len; + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + + if (xt_comp_log_pos(db->db_wr_log_id, db->db_wr_log_offset, db->db_wr_flush_point_log_id, db->db_wr_flush_point_log_offset) >= 0) { + break; + } + + /* Apply all changes that have been flushed to the log, to the + * database. + */ + if (!db->db_xlog.xlog_seq_next(&ws->ws_seqread, &record, FALSE, self)) + xt_throw(self); + if (!record) { + break; + } + /* Count the number of bytes read from the log: */ + db->db_xlog.xl_log_bytes_read += ws->ws_seqread.xseq_record_len; + + switch (record->xl.xl_status_1) { + case XT_LOG_ENT_HEADER: + break; + case XT_LOG_ENT_NEW_LOG: + if (!db->db_xlog.xlog_seq_start(&ws->ws_seqread, XT_GET_DISK_4(record->xl.xl_log_id_4), 0, TRUE)) + xt_throw(self); + break; + case XT_LOG_ENT_NEW_TAB: + case XT_LOG_ENT_COMMIT: + case XT_LOG_ENT_ABORT: + case XT_LOG_ENT_CLEANUP: + case XT_LOG_ENT_OP_SYNC: + break; + case XT_LOG_ENT_DEL_LOG: + xtLogID log_id; + + log_id = XT_GET_DISK_4(record->xl.xl_log_id_4); + xt_dl_set_to_delete(self, db, log_id); + break; + default: + xt_xres_apply_in_order(self, ws, ws->ws_seqread.xseq_rec_log_id, ws->ws_seqread.xseq_rec_log_offset, record); + break; + } + } + } + + if (ws->ws_ot) { + xt_db_return_table_to_pool(self, ws->ws_ot); + ws->ws_ot = NULL; + } + + xlog_wr_could_go_slower(self, db); + + /* Note, we delay writing the database for a maximum of + * 2 seconds. + */ + xlog_wr_wait_for_log_flush(self, db); + } + + freer_(); // xt_free_writer_state(ss) +} + +static void *xlog_wr_run_thread(XTThreadPtr self) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) self->t_data; + int count; + void *mysql_thread; + + mysql_thread = myxt_create_thread(); + + while (!self->t_quit) { + try_(a) { + /* + * The garbage collector requires that the database + * is in use because. + */ + xt_use_database(self, db, XT_FOR_WRITER); + + /* This action is both safe and required (see details elsewhere) */ + xt_heap_release(self, self->st_database); + + xlog_wr_main(self); + } + catch_(a) { + /* This error is "normal"! */ + if (self->t_exception.e_xt_err != XT_ERR_NO_DICTIONARY && + !(self->t_exception.e_xt_err == XT_SIGNAL_CAUGHT && + self->t_exception.e_sys_err == SIGTERM)) + xt_log_and_clear_exception(self); + } + cont_(a); + + /* Avoid releasing the database (done above) */ + self->st_database = NULL; + xt_unuse_database(self, self); + + /* After an exception, pause before trying again... */ + /* Number of seconds */ +#ifdef DEBUG + count = 10; +#else + count = 2*60; +#endif + db->db_wr_idle = XT_THREAD_INERR; + while (!self->t_quit && count > 0) { + sleep(1); + count--; + } + db->db_wr_idle = XT_THREAD_BUSY; + } + + myxt_destroy_thread(mysql_thread, TRUE); + return NULL; +} + +static void xlog_wr_free_thread(XTThreadPtr self, void *data) +{ + XTDatabaseHPtr db = (XTDatabaseHPtr) data; + + if (db->db_wr_thread) { + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + db->db_wr_thread = NULL; + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + } +} + +xtPublic void xt_start_writer(XTThreadPtr self, XTDatabaseHPtr db) +{ + char name[PATH_MAX]; + + sprintf(name, "WR-%s", xt_last_directory_of_path(db->db_main_path)); + xt_remove_dir_char(name); + db->db_wr_thread = xt_create_daemon(self, name); + xt_set_thread_data(db->db_wr_thread, db, xlog_wr_free_thread); + xt_run_thread(self, db->db_wr_thread, xlog_wr_run_thread); +} + +/* + * This function is called on database shutdown. + * We will wait a certain amounnt of time for the writer to + * complete its work. + * If it takes to long we will abort! + */ +xtPublic void xt_wait_for_writer(XTThreadPtr self, XTDatabaseHPtr db) +{ + time_t then, now; + xtBool message = FALSE; + + if (db->db_wr_thread) { + then = time(NULL); + while (xt_comp_log_pos(db->db_wr_log_id, db->db_wr_log_offset, db->db_wr_flush_point_log_id, db->db_wr_flush_point_log_offset) < 0) { + + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + db->db_wr_thread_waiting++; + /* Wake the writer so that it con complete its work. */ + if (db->db_wr_idle) { + if (!xt_broadcast_cond_ns(&db->db_wr_cond)) + xt_log_and_clear_exception_ns(); + } + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + + xt_sleep_milli_second(10); + + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + db->db_wr_thread_waiting--; + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + + now = time(NULL); + if (now >= then + 16) { + xt_logf(XT_NT_INFO, "Aborting wait for '%s' writer\n", db->db_name); + message = FALSE; + break; + } + if (now >= then + 2) { + if (!message) { + message = TRUE; + xt_logf(XT_NT_INFO, "Waiting for '%s' writer...\n", db->db_name); + } + } + } + + if (message) + xt_logf(XT_NT_INFO, "Writer '%s' done.\n", db->db_name); + } +} + +xtPublic void xt_stop_writer(XTThreadPtr self, XTDatabaseHPtr db) +{ + XTThreadPtr thr_wr; + + if (db->db_wr_thread) { + xt_lock_mutex(self, &db->db_wr_lock); + pushr_(xt_unlock_mutex, &db->db_wr_lock); + + /* This pointer is safe as long as you have the transaction lock. */ + if ((thr_wr = db->db_wr_thread)) { + xtThreadID tid = thr_wr->t_id; + + /* Make sure the thread quits when woken up. */ + xt_terminate_thread(self, thr_wr); + + /* Wake the writer thread so that it will quit: */ + xt_broadcast_cond(self, &db->db_wr_cond); + + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + + /* + * GOTCHA: This is a wierd thing but the SIGTERM directed + * at a particular thread (in this case the sweeper) was + * being caught by a different thread and killing the server + * sometimes. Disconcerting. + * (this may only be a problem on Mac OS X) + xt_kill_thread(thread); + */ + xt_wait_for_thread(tid, FALSE); + + /* PMC - This should not be necessary to set the signal here, but in the + * debugger the handler is not called!!? + thr_wr->t_delayed_signal = SIGTERM; + xt_kill_thread(thread); + */ + db->db_wr_thread = NULL; + } + else + freer_(); // xt_unlock_mutex(&db->db_wr_lock) + } +} + +#ifdef NOT_USED +static void xlog_add_to_flush_buffer(u_int flush_count, XTXLogBlockPtr *flush_buffer, XTXLogBlockPtr block) +{ + register u_int count = flush_count; + register u_int i; + register u_int guess; + register xtInt8 r; + + i = 0; + while (i < count) { + guess = (i + count - 1) >> 1; + r = (xtInt8) block->xlb_address - (xtInt8) flush_buffer[guess]->xlb_address; + if (r == 0) { + // Should not happen... + ASSERT_NS(FALSE); + return; + } + if (r < (xtInt8) 0) + count = guess; + else + i = guess + 1; + } + + /* Insert at position i */ + memmove(flush_buffer + i + 1, flush_buffer + i, (flush_count - i) * sizeof(XTXLogBlockPtr)); + flush_buffer[i] = block; +} + +static XTXLogBlockPtr xlog_find_block(XTOpenFilePtr file, xtLogID log_id, off_t address, XTXLogCacheSegPtr *ret_seg) +{ + register XTXLogCacheSegPtr seg; + register XTXLogBlockPtr block; + register u_int hash_idx; + register XTXLogCacheRec *dcg = &xt_xlog_cache; + + seg = &dcg->xlc_segment[((u_int) address >> XT_XLC_BLOCK_SHIFTS) & XLC_SEGMENT_MASK]; + hash_idx = (((u_int) (address >> (XT_XLC_SEGMENT_SHIFTS + XT_XLC_BLOCK_SHIFTS))) ^ (log_id << 16)) % dcg->xlc_hash_size; + + xt_lock_mutex_ns(&seg->lcs_lock); + retry: + block = seg->lcs_hash_table[hash_idx]; + while (block) { + if (block->xlb_address == address && block->xlb_log_id == log_id) { + ASSERT_NS(block->xlb_state != XLC_BLOCK_FREE); + + /* Wait if the block is being read or written. + * If we will just read the data, then we don't care + * if the buffer is being written. + */ + if (block->xlb_state == XLC_BLOCK_READING) { + if (!xt_timed_wait_cond_ns(&seg->lcs_cond, &seg->lcs_lock, 100)) + break; + goto retry; + } + + *ret_seg = seg; + return block; + } + block = block->xlb_next; + } + + /* Block not found: */ + xt_unlock_mutex_ns(&seg->lcs_lock); + return NULL; +} + +static int xlog_cmp_log_files(struct XTThread *self, register const void *thunk, register const void *a, register const void *b) +{ +#pragma unused(self, thunk) + xtLogID lf_id = *((xtLogID *) a); + XTXactLogFilePtr lf_ptr = (XTXactLogFilePtr) b; + + if (lf_id < lf_ptr->lf_log_id) + return -1; + if (lf_id == lf_ptr->lf_log_id) + return 0; + return 1; +} + +#endif + + +#ifdef OLD_CODE +static xtBool xlog_free_lru_blocks() +{ + XTXLogBlockPtr block, pblock; + xtWord4 ru_time; + xtLogID log_id; + off_t address; + //off_t hash; + XTXLogCacheSegPtr seg; + u_int hash_idx; + xtBool have_global_lock = FALSE; + +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + retry: + if (!(block = xt_xlog_cache.xlc_lru_block)) + return OK; + + ru_time = block->xlb_ru_time; + log_id = block->xlb_log_id; + address = block->xlb_address; + + /* + hash = (address >> XT_XLC_BLOCK_SHIFTS) ^ ((off_t) log_id << 28); + seg = &xt_xlog_cache.xlc_segment[hash & XLC_SEGMENT_MASK]; + hash_idx = (hash >> XT_XLC_SEGMENT_SHIFTS) % xt_xlog_cache.xlc_hash_size; + */ + seg = &xt_xlog_cache.xlc_segment[((u_int) address >> XT_XLC_BLOCK_SHIFTS) & XLC_SEGMENT_MASK]; + hash_idx = (((u_int) (address >> (XT_XLC_SEGMENT_SHIFTS + XT_XLC_BLOCK_SHIFTS))) ^ (log_id << 16)) % xt_xlog_cache.xlc_hash_size; + + xt_lock_mutex_ns(&seg->lcs_lock); + + free_more: + pblock = NULL; + block = seg->lcs_hash_table[hash_idx]; + while (block) { + if (block->xlb_address == address && block->xlb_log_id == log_id) { + ASSERT_NS(block->xlb_state != XLC_BLOCK_FREE); + + /* Try again if the block has been used in the meantime: */ + if (ru_time != block->xlb_ru_time) { + if (have_global_lock) + /* Having this lock means we have already freed at least one block so + * don't bother to free more if we are having trouble. + */ + goto done_ok; + + /* If the recently used time has changed, then the + * block is probably no longer the LR used. + */ + xt_unlock_mutex_ns(&seg->lcs_lock); + goto retry; + } + + /* Wait if the block is being read: */ + if (block->xlb_state == XLC_BLOCK_READING) { + if (have_global_lock) + goto done_ok; + + /* Wait for the block to be read, then try again. */ + if (!xt_timed_wait_cond_ns(&seg->lcs_cond, &seg->lcs_lock, 100)) + goto failed; + xt_unlock_mutex_ns(&seg->lcs_lock); + goto retry; + } + + goto free_the_block; + } + pblock = block; + block = block->xlb_next; + } + + if (have_global_lock) { + xt_unlock_mutex_ns(&xt_xlog_cache.xlc_lock); + have_global_lock = FALSE; + } + + /* We did not find the block, someone else freed it... */ + xt_unlock_mutex_ns(&seg->lcs_lock); + goto retry; + + free_the_block: + ASSERT_NS(block->xlb_state == XLC_BLOCK_CLEAN); + + /* Remove from the hash table: */ + if (pblock) + pblock->xlb_next = block->xlb_next; + else + seg->lcs_hash_table[hash_idx] = block->xlb_next; + + /* Now free the block */ + if (!have_global_lock) { + xt_lock_mutex_ns(&xt_xlog_cache.xlc_lock); + have_global_lock = TRUE; + } + + /* Remove from the MRU list: */ + if (xt_xlog_cache.xlc_lru_block == block) + xt_xlog_cache.xlc_lru_block = block->xlb_mr_used; + if (xt_xlog_cache.xlc_mru_block == block) + xt_xlog_cache.xlc_mru_block = block->xlb_lr_used; + if (block->xlb_lr_used) + block->xlb_lr_used->xlb_mr_used = block->xlb_mr_used; + if (block->xlb_mr_used) + block->xlb_mr_used->xlb_lr_used = block->xlb_lr_used; + + /* Put the block on the free list: */ + block->xlb_next = xt_xlog_cache.xlc_free_list; + xt_xlog_cache.xlc_free_list = block; + xt_xlog_cache.xlc_free_count++; + block->xlb_state = XLC_BLOCK_FREE; + + if (xt_xlog_cache.xlc_free_count < XT_XLC_MAX_FREE_COUNT) { + /* Now that we have all the locks, try to free some more in this segment: */ + block = block->xlb_mr_used; + for (u_int i=0; block && i<XLC_SEGMENT_COUNT; i++) { + ru_time = block->xlb_ru_time; + log_id = block->xlb_log_id; + address = block->xlb_address; + + if (seg == &xt_xlog_cache.xlc_segment[((u_int) address >> XT_XLC_BLOCK_SHIFTS) & XLC_SEGMENT_MASK]) { + hash_idx = (((u_int) (address >> (XT_XLC_SEGMENT_SHIFTS + XT_XLC_BLOCK_SHIFTS))) ^ (log_id << 16)) % xt_xlog_cache.xlc_hash_size; + goto free_more; + } + block = block->xlb_mr_used; + } + } + + done_ok: + xt_unlock_mutex_ns(&xt_xlog_cache.xlc_lock); + xt_unlock_mutex_ns(&seg->lcs_lock); +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + return OK; + + failed: + xt_unlock_mutex_ns(&seg->lcs_lock); +#ifdef DEBUG_CHECK_CACHE + //xt_xlog_check_cache(); +#endif + return FAILED; +} + +#endif diff --git a/storage/pbxt/src/xactlog_xt.h b/storage/pbxt/src/xactlog_xt.h new file mode 100644 index 00000000000..391b646b53f --- /dev/null +++ b/storage/pbxt/src/xactlog_xt.h @@ -0,0 +1,460 @@ +/* Copyright (c) 2007 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2007-10-31 Paul McCullagh + * + * H&G2JCtL + * + * The new table cache. Caches all non-index data. This includes the data + * files and the row pointer files. + */ + +#ifndef __xactlog_xt_h__ +#define __xactlog_xt_h__ + +#include "pthread_xt.h" +#include "filesys_xt.h" +#include "sortedlist_xt.h" + +struct XTThread; +struct XTOpenTable; +struct XTDatabase; + +#ifdef DEBUG +//#define XT_USE_CACHE_DEBUG_SIZES +#endif + +#ifdef XT_USE_CACHE_DEBUG_SIZES +#define XT_XLC_BLOCK_SHIFTS 5 +#define XT_XLC_FILE_SLOTS 7 +#define XT_XLC_SEGMENT_SHIFTS 1 +#define XT_XLC_MAX_FLUSH_SEG_COUNT 10 +#define XT_XLC_MAX_FREE_COUNT 10 +#else +/* Block size is determined by the number of shifts 1 << 15 = 32K */ +#define XT_XLC_BLOCK_SHIFTS 15 +#define XT_XLC_FILE_SLOTS 71 +/* The number of segments are determined by the segment shifts 1 << 3 = 8 */ +#define XT_XLC_SEGMENT_SHIFTS 3 +#define XT_XLC_MAX_FLUSH_SEG_COUNT 250 +#define XT_XLC_MAX_FREE_COUNT 100 +#endif + +#define XT_XLC_BLOCK_SIZE (1 << XT_XLC_BLOCK_SHIFTS) +#define XT_XLC_BLOCK_MASK (XT_XLC_BLOCK_SIZE - 1) + +#define XT_TIME_DIFF(start, now) (\ + ((xtWord4) (now) < (xtWord4) (start)) ? \ + ((xtWord4) 0XFFFFFFFF - ((xtWord4) (start) - (xtWord4) (now))) : \ + ((xtWord4) (now) - (xtWord4) (start))) + +#define XLC_SEGMENT_COUNT ((off_t) 1 << XT_XLC_SEGMENT_SHIFTS) +#define XLC_SEGMENT_MASK (XLC_SEGMENT_COUNT - 1) +#define XLC_MAX_FLUSH_COUNT (XT_XLC_MAX_FLUSH_SEG_COUNT * XLC_SEGMENT_COUNT) + +#define XLC_BLOCK_FREE 0 +#define XLC_BLOCK_READING 1 +#define XLC_BLOCK_CLEAN 2 + +#define XT_RECYCLE_LOGS 0 +#define XT_DELETE_LOGS 1 +#define XT_KEEP_LOGS 2 + +/* LOG CACHE ---------------------------------------------------- */ + +typedef struct XTXLogBlock { + off_t xlb_address; /* The block address. */ + xtLogID xlb_log_id; /* The log id of the block. */ + xtWord4 xlb_state; /* Block status. */ + struct XTXLogBlock *xlb_next; /* Pointer to next block on hash list, or next free block on free list. */ + xtWord1 xlb_data[XT_XLC_BLOCK_SIZE]; +} XTXLogBlockRec, *XTXLogBlockPtr; + +/* A disk cache segment. The cache is divided into a number of segments + * to improve concurrency. + */ +typedef struct XTXLogCacheSeg { + xt_mutex_type lcs_lock; /* The cache segment lock. */ + xt_cond_type lcs_cond; + XTXLogBlockPtr *lcs_hash_table; +} XTXLogCacheSegRec, *XTXLogCacheSegPtr; + +typedef struct XTXLogCache { + xt_mutex_type xlc_lock; /* The public cache lock. */ + xt_cond_type xlc_cond; /* The public cache wait condition. */ + XTXLogCacheSegRec xlc_segment[XLC_SEGMENT_COUNT]; + XTXLogBlockPtr xlc_blocks; + XTXLogBlockPtr xlc_blocks_end; + XTXLogBlockPtr xlc_next_to_free; + xtWord4 xlc_free_count; + xtWord4 xlc_hash_size; + xtWord4 xlc_block_count; + xtWord8 xlc_upper_limit; +} XTXLogCacheRec; + +/* LOG ENTRIES ---------------------------------------------------- */ + +#define XT_LOG_ENT_EOF 0 +#define XT_LOG_ENT_HEADER 1 +#define XT_LOG_ENT_NEW_LOG 2 /* Move to the next log! NOTE!! May not appear in a group!! */ +#define XT_LOG_ENT_DEL_LOG 3 /* Delete the given transaction/data log. */ +#define XT_LOG_ENT_NEW_TAB 4 /* This record indicates a new table was created. */ + +#define XT_LOG_ENT_COMMIT 5 /* Transaction was committed. */ +#define XT_LOG_ENT_ABORT 6 /* Transaction was aborted. */ +#define XT_LOG_ENT_CLEANUP 7 /* Written after a cleanup. */ + +#define XT_LOG_ENT_REC_MODIFIED 8 /* This records has been modified by the transaction. */ +#define XT_LOG_ENT_UPDATE 9 +#define XT_LOG_ENT_UPDATE_BG 10 +#define XT_LOG_ENT_UPDATE_FL 11 +#define XT_LOG_ENT_UPDATE_FL_BG 12 +#define XT_LOG_ENT_INSERT 13 +#define XT_LOG_ENT_INSERT_BG 14 +#define XT_LOG_ENT_INSERT_FL 15 +#define XT_LOG_ENT_INSERT_FL_BG 16 +#define XT_LOG_ENT_DELETE 17 +#define XT_LOG_ENT_DELETE_BG 18 +#define XT_LOG_ENT_DELETE_FL 19 +#define XT_LOG_ENT_DELETE_FL_BG 20 + +#define XT_LOG_ENT_REC_FREED 21 /* This record has been placed in the free list. */ +#define XT_LOG_ENT_REC_REMOVED 22 /* Free record and dependecies: index references, blob references. */ +#define XT_LOG_ENT_REC_REMOVED_EXT 23 /* Free record and dependecies: index references, extended data, blob references. */ +#define XT_LOG_ENT_REC_REMOVED_BI 38 /* Free record and dependecies: includes before image of record, for freeing index, etc. */ + +#define XT_LOG_ENT_REC_MOVED 24 /* The record has been moved by the compactor. */ +#define XT_LOG_ENT_REC_CLEANED 25 /* This record has been cleaned by the sweeper. */ +#define XT_LOG_ENT_REC_CLEANED_1 26 /* This record has been cleaned by the sweeper (short form). */ +#define XT_LOG_ENT_REC_UNLINKED 27 /* The record after this record is unlinked from the variation list. */ + +#define XT_LOG_ENT_ROW_NEW 28 /* Row allocated from the EOF. */ +#define XT_LOG_ENT_ROW_NEW_FL 29 /* Row allocated from the free list. */ +#define XT_LOG_ENT_ROW_ADD_REC 30 /* Record added to the row. */ +#define XT_LOG_ENT_ROW_SET 31 +#define XT_LOG_ENT_ROW_FREED 32 + +#define XT_LOG_ENT_OP_SYNC 33 /* Operations syncronised. */ +#define XT_LOG_ENT_EXT_REC_OK 34 /* An extended record */ +#define XT_LOG_ENT_EXT_REC_DEL 35 /* A deleted extended record */ + +#define XT_LOG_ENT_NO_OP 36 /* If write to the database fails, we still try to log the + * op code, in an attempt to continue, if writting to log + * still works. + */ +#define XT_LOG_ENT_END_OF_LOG 37 /* This is a record that indicates the end of the log, and + * fills to the end of a 512 byte block. + */ + +#define XT_LOG_FILE_MAGIC 0xAE88FE12 +#define XT_LOG_VERSION_NO 1 + +typedef struct XTXactLogHeader { + xtWord1 xh_status_1; /* XT_LOG_ENT_HEADER */ + xtWord1 xh_checksum_1; + XTDiskValue4 xh_size_4; /* Must be set to sizeof(XTXactLogHeaderDRec). */ + XTDiskValue8 xh_free_space_8; /* The accumulated free space in this file. */ + XTDiskValue8 xh_file_len_8; /* The last confirmed correct file length (always set on close). */ + XTDiskValue8 xh_comp_pos_8; /* Compaction position (XT_DL_STATUS_CO_SOURCE only). */ + xtWord1 xh_comp_stat_1; /* The compaction status XT_DL_STATUS_CO_SOURCE/XT_DL_STATUS_CO_TARGET */ + XTDiskValue4 xh_log_id_4; + XTDiskValue4 xh_version_2; /* XT_LOG_VERSION_NO */ + XTDiskValue4 xh_magic_4; /* MUST always be at the end of the structure!! */ +} XTXactLogHeaderDRec, *XTXactLogHeaderDPtr; + +/* This is the original log head size (don't change): */ +#define XT_MIN_LOG_HEAD_SIZE (offsetof(XTXactLogHeaderDRec, xh_log_id_4) + 4) +#define XT_LOG_HEAD_MAGIC(b, l) XT_GET_DISK_4(((xtWord1 *) (b)) + (l) - 4) + +typedef struct XTXactNewLogEntry { + xtWord1 xl_status_1; /* XT_LOG_ENT_NEW_LOG, XT_LOG_ENT_DEL_LOG */ + xtWord1 xl_checksum_1; + XTDiskValue4 xl_log_id_4; /* Store the current table ID. */ +} XTXactNewLogEntryDRec, *XTXactNewLogEntryDPtr; + +typedef struct XTXactNewTabEntry { + xtWord1 xt_status_1; /* XT_LOG_ENT_NEW_TAB */ + xtWord1 xt_checksum_1; + XTDiskValue4 xt_tab_id_4; /* Store the current table ID. */ +} XTXactNewTabEntryDRec, *XTXactNewTabEntryDPtr; + +/* This record must appear in a transaction group, and therefore has no transaction ID: */ +typedef struct XTXactEndEntry { + xtWord1 xe_status_1; /* XT_LOG_ENT_COMMIT, XT_LOG_ENT_ABORT */ + xtWord1 xe_checksum_1; + XTDiskValue4 xe_xact_id_4; /* The transaction. */ + XTDiskValue4 xe_not_used_4; /* Was the end sequence number (no longer used - v1.0.04+), set to zero). */ +} XTXactEndEntryDRec, *XTXactEndEntryDPtr; + +typedef struct XTXactCleanupEntry { + xtWord1 xc_status_1; /* XT_LOG_ENT_CLEANUP */ + xtWord1 xc_checksum_1; + XTDiskValue4 xc_xact_id_4; /* The transaction that was cleaned up. */ +} XTXactCleanupEntryDRec, *XTXactCleanupEntryDPtr; + +typedef struct XTactUpdateEntry { + xtWord1 xu_status_1; /* XT_LOG_ENT_REC_MODIFIED, XT_LOG_ENT_UPDATE, XT_LOG_ENT_INSERT, XT_LOG_ENT_DELETE */ + /* XT_LOG_ENT_UPDATE_BG, XT_LOG_ENT_INSERT_BG, XT_LOG_ENT_DELETE_BG */ + XTDiskValue2 xu_checksum_2; + XTDiskValue4 xu_op_seq_4; /* Operation sequence number. */ + XTDiskValue4 xu_tab_id_4; /* Table ID of the record. */ + xtDiskRecordID4 xu_rec_id_4; /* Offset of the new updated record. */ + XTDiskValue2 xu_size_2; /* Size of the record data. */ + /* This is the start of the actual record data: */ + xtWord1 xu_rec_type_1; /* Type of the record. */ + xtWord1 xu_stat_id_1; + xtDiskRecordID4 xu_prev_rec_id_4; /* The previous variation of this record. */ + XTDiskValue4 xu_xact_id_4; /* The transaction ID. */ + XTDiskValue4 xu_row_id_4; /* The row ID of this record. */ +} XTactUpdateEntryDRec, *XTactUpdateEntryDPtr; + +typedef struct XTactUpdateFLEntry { + xtWord1 xf_status_1; /* XT_LOG_ENT_UPDATE_FL, XT_LOG_ENT_INSERT_FL, XT_LOG_ENT_DELETE_FL */ + /* XT_LOG_ENT_UPDATE_FL_BG, XT_LOG_ENT_INSERT_FL_BG, XT_LOG_ENT_DELETE_FL_BG */ + XTDiskValue2 xf_checksum_2; + XTDiskValue4 xf_op_seq_4; /* Operation sequence number. */ + XTDiskValue4 xf_tab_id_4; /* Table ID of the record. */ + xtDiskRecordID4 xf_rec_id_4; /* Offset of the new updated record. */ + XTDiskValue2 xf_size_2; /* Size of the record data. */ + xtDiskRecordID4 xf_free_rec_id_4; /* Update to the free list. */ + /* This is the start of the actual record data: */ + xtWord1 xf_rec_type_1; /* Type of the record. */ + xtWord1 xf_stat_id_1; + xtDiskRecordID4 xf_prev_rec_id_4; /* The previous variation of this record. */ + XTDiskValue4 xf_xact_id_4; /* The transaction ID. */ + XTDiskValue4 xf_row_id_4; /* The row ID of this record. */ +} XTactUpdateFLEntryDRec, *XTactUpdateFLEntryDPtr; + +typedef struct XTactFreeRecEntry { + xtWord1 fr_status_1; /* XT_LOG_ENT_REC_REMOVED, XT_LOG_ENT_REC_REMOVED_EXT, XT_LOG_ENT_REC_FREED */ + xtWord1 fr_checksum_1; + XTDiskValue4 fr_op_seq_4; /* Operation sequence number. */ + XTDiskValue4 fr_tab_id_4; /* Table ID of the record. */ + xtDiskRecordID4 fr_rec_id_4; /* Offset of the new written record. */ + /* This data confirms the record state for release of + * attached resources (extended records, indexes and blobs) + */ + xtWord1 fr_stat_id_1; /* The statement ID of the record. */ + XTDiskValue4 fr_xact_id_4; /* The transaction ID of the record. */ + /* This is the start of the actual record data: */ + xtWord1 fr_rec_type_1; + xtWord1 fr_not_used_1; + xtDiskRecordID4 fr_next_rec_id_4; /* The next block on the free list. */ +} XTactFreeRecEntryDRec, *XTactFreeRecEntryDPtr; + +typedef struct XTactRemoveBIEntry { + xtWord1 rb_status_1; /* XT_LOG_ENT_REC_REMOVED_BI */ + XTDiskValue2 rb_checksum_2; + XTDiskValue4 rb_op_seq_4; /* Operation sequence number. */ + XTDiskValue4 rb_tab_id_4; /* Table ID of the record. */ + xtDiskRecordID4 rb_rec_id_4; /* Offset of the new written record. */ + XTDiskValue2 rb_size_2; /* Size of the record data. */ + + xtWord1 rb_new_rec_type_1; /* New type of the record (needed for below). */ + + /* This is the start of the record data, with some fields overwritten for the free: */ + xtWord1 rb_rec_type_1; /* Type of the record. */ + xtWord1 rb_stat_id_1; + xtDiskRecordID4 rb_next_rec_id_4; /* The next block on the free list (overwritten). */ + XTDiskValue4 rb_xact_id_4; /* The transaction ID. */ + XTDiskValue4 rb_row_id_4; /* The row ID of this record. */ +} XTactRemoveBIEntryDRec, *XTactRemoveBIEntryDPtr; + +typedef struct XTactWriteRecEntry { + xtWord1 xw_status_1; /* XT_LOG_ENT_REC_MOVED, XT_LOG_ENT_REC_CLEANED, XT_LOG_ENT_REC_CLEANED_1, + * XT_LOG_ENT_REC_UNLINKED */ + xtWord1 xw_checksum_1; + XTDiskValue4 xw_op_seq_4; /* Operation sequence number. */ + XTDiskValue4 xw_tab_id_4; /* Table ID of the record. */ + xtDiskRecordID4 xw_rec_id_4; /* Offset of the new written record. */ + /* This is the start of the actual record data: */ + xtWord1 xw_rec_type_1; + xtWord1 xw_stat_id_1; + xtDiskRecordID4 xw_next_rec_id_4; /* The next block on the free list. */ +} XTactWriteRecEntryDRec, *XTactWriteRecEntryDPtr; + +typedef struct XTactRowAddedEntry { + xtWord1 xa_status_1; /* XT_LOG_ENT_ROW_NEW or XT_LOG_ENT_ROW_NEW_FL */ + xtWord1 xa_checksum_1; + XTDiskValue4 xa_op_seq_4; /* Operation sequence number. */ + XTDiskValue4 xa_tab_id_4; /* Table ID of the record. */ + XTDiskValue4 xa_row_id_4; /* The row ID of the row allocated. */ + XTDiskValue4 xa_free_list_4; /* Change to the free list (ONLY for XT_LOG_ENT_ROW_NEW_FL). */ +} XTactRowAddedEntryDRec, *XTactRowAddedEntryDPtr; + +typedef struct XTactWriteRowEntry { + xtWord1 wr_status_1; /* XT_LOG_ENT_ROW_ADD_REC, XT_LOG_ENT_ROW_SET, XT_LOG_ENT_ROW_FREED */ + xtWord1 wr_checksum_1; + XTDiskValue4 wr_op_seq_4; /* Operation sequence number. */ + XTDiskValue4 wr_tab_id_4; /* Table ID of the record. */ + XTDiskValue4 wr_row_id_4; /* Row ID of the row that was modified. */ + /* This is the start of the actual record data: */ + XTDiskValue4 wr_ref_id_4; /* The row reference data. */ +} XTactWriteRowEntryDRec, *XTactWriteRowEntryDPtr; + +typedef struct XTactOpSyncEntry { + xtWord1 os_status_1; /* XT_LOG_ENT_OP_SYNC */ + xtWord1 os_checksum_1; + XTDiskValue4 os_time_4; /* Time of the restart. */ +} XTactOpSyncEntryDRec, *XTactOpSyncEntryDPtr; + +typedef struct XTactNoOpEntry { + xtWord1 no_status_1; /* XT_LOG_ENT_NO_OP */ + xtWord1 no_checksum_1; + XTDiskValue4 no_op_seq_4; /* Operation sequence number. */ + XTDiskValue4 no_tab_id_4; /* Table ID of the record. */ +} XTactNoOpEntryDRec, *XTactNoOpEntryDPtr; + +typedef struct XTactExtRecEntry { + xtWord1 er_status_1; /* XT_LOG_ENT_EXT_REC_OK, XT_LOG_ENT_EXT_REC_DEL */ + XTDiskValue4 er_data_size_4; /* Size of this record data area only. */ + XTDiskValue4 er_tab_id_4; /* The table referencing this extended record. */ + xtDiskRecordID4 er_rec_id_4; /* The ID of the reference record. */ + xtWord1 er_data[XT_VAR_LENGTH]; +} XTactExtRecEntryDRec, *XTactExtRecEntryDPtr; + +typedef union XTXactLogBuffer { + XTXactLogHeaderDRec xh; + XTXactNewLogEntryDRec xl; + XTXactNewTabEntryDRec xt; + XTXactEndEntryDRec xe; + XTXactCleanupEntryDRec xc; + XTactUpdateEntryDRec xu; + XTactUpdateFLEntryDRec xf; + XTactFreeRecEntryDRec fr; + XTactRemoveBIEntryDRec rb; + XTactWriteRecEntryDRec xw; + XTactRowAddedEntryDRec xa; + XTactWriteRowEntryDRec wr; + XTactOpSyncEntryDRec os; + XTactExtRecEntryDRec er; + XTactNoOpEntryDRec no; +} XTXactLogBufferDRec, *XTXactLogBufferDPtr; + +/* ---------------------------------------- */ + +typedef struct XTXactSeqRead { + size_t xseq_buffer_size; /* Size of the buffer. */ + xtBool xseq_load_cache; /* TRUE if reads should load the cache! */ + + xtLogID xseq_log_id; + XTOpenFilePtr xseq_log_file; + off_t xseq_log_eof; + + xtLogOffset xseq_buf_log_offset; /* File offset of the buffer. */ + size_t xseq_buffer_len; /* Amount of data in the buffer. */ + xtWord1 *xseq_buffer; + + xtLogID xseq_rec_log_id; /* The current record log ID. */ + xtLogOffset xseq_rec_log_offset; /* The current log read position. */ + size_t xseq_record_len; /* The length of the current record. */ +} XTXactSeqReadRec, *XTXactSeqReadPtr; + +typedef struct XTXactLogFile { + xtLogID lf_log_id; + off_t lr_file_len; /* The log file size (0 means this is the last log) */ +} XTXactLogFileRec, *XTXactLogFilePtr; + +/* + * The transaction log. Each database has one. + */ +typedef struct XTDatabaseLog { + struct XTDatabase *xl_db; + + off_t xl_log_file_threshold; + u_int xl_log_file_count; /* Number of logs to use (>= 1). */ + u_int xt_log_file_dyn_count; /* A dynamic value to add to log file count. */ + u_int xt_log_file_dyn_dec; /* Used to descide when to decrement the dynamic count. */ + size_t xl_size_of_buffers; /* The size of both log buffers. */ + xtWord8 xl_log_bytes_written; /* The total number of bytes written to the log, after recovery. */ + xtWord8 xl_log_bytes_flushed; /* The total number of bytes flushed to the log, after recovery. */ + xtWord8 xl_log_bytes_read; /* The total number of log bytes read, after recovery. */ + + u_int xl_last_flush_time; /* Last flush time in micro-seconds. */ + + /* The writer log buffer: */ + xt_mutex_type xl_write_lock; + xt_cond_type xl_write_cond; + xtBool xt_writing; /* TRUE if a thread is writing. */ + xtLogID xl_log_id; /* The number of the write log. */ + XTOpenFilePtr xl_log_file; /* The open write log. */ + + XTSpinLockRec xl_buffer_lock; /* This locks both the write and the append log buffers. */ + + xtLogID xl_max_log_id; /* The ID of the highest log on disk. */ + + xtLogID xl_write_log_id; /* This is the log ID were the write data will go. */ + xtLogOffset xl_write_log_offset; /* The file offset of the write log. */ + size_t xl_write_buf_pos; + size_t xl_write_buf_pos_start; + xtWord1 *xl_write_buffer; + xtBool xl_write_done; /* TRUE if the write buffer has been written! */ + + xtLogID xl_append_log_id; /* This is the log ID were the append data will go. */ + xtLogOffset xl_append_log_offset; /* The file offset in the log were the append data will go. */ + size_t xl_append_buf_pos; /* The amount of data in the append buffer. */ + size_t xl_append_buf_pos_start; /* The amount of data in the append buffer already written. */ + xtWord1 *xl_append_buffer; + + xtLogID xl_flush_log_id; /* The last log flushed. */ + xtLogOffset xl_flush_log_offset; /* The position in the log flushed. */ + + void xlog_setup(struct XTThread *self, struct XTDatabase *db, off_t log_file_size, size_t transaction_buffer_size, int log_count); + xtBool xlog_set_write_offset(xtLogID log_id, xtLogOffset log_offset, xtLogID max_log_id, struct XTThread *thread); + void xlog_close(struct XTThread *self); + void xlog_exit(struct XTThread *self); + void xlog_name(size_t size, char *path, xtLogID log_id); + int xlog_delete_log(xtLogID del_log_id, struct XTThread *thread); + + xtBool xlog_append(struct XTThread *thread, size_t size1, xtWord1 *data1, size_t size2, xtWord1 *data2, xtBool commit, xtLogID *log_id, xtLogOffset *log_offset); + xtBool xlog_flush(struct XTThread *thread); + xtBool xlog_flush_pending(); + + xtBool xlog_seq_init(XTXactSeqReadPtr seq, size_t buffer_size, xtBool load_cache); + void xlog_seq_exit(XTXactSeqReadPtr seq); + void xlog_seq_close(XTXactSeqReadPtr seq); + xtBool xlog_seq_start(XTXactSeqReadPtr seq, xtLogID log_id, xtLogOffset log_offset, xtBool missing_ok); + xtBool xlog_rnd_read(XTXactSeqReadPtr seq, xtLogID log_id, xtLogOffset log_offset, size_t size, xtWord1 *data, size_t *read, struct XTThread *thread); + size_t xlog_bytes_to_write(); + xtBool xlog_read_from_cache(XTXactSeqReadPtr seq, xtLogID log_id, xtLogOffset log_offset, size_t size, off_t eof, xtWord1 *buffer, size_t *data_read, struct XTThread *thread); + xtBool xlog_write_thru(XTXactSeqReadPtr seq, size_t size, xtWord1 *data, struct XTThread *thread); + xtBool xlog_verify(XTXactLogBufferDPtr record, size_t rec_size, xtLogID log_id); + xtBool xlog_seq_next(XTXactSeqReadPtr seq, XTXactLogBufferDPtr *entry, xtBool verify, struct XTThread *thread); + void xlog_seq_skip(XTXactSeqReadPtr seq, size_t size); + +private: + xtBool xlog_open_log(xtLogID log_id, off_t curr_eof, struct XTThread *thread); +} XTDatabaseLogRec, *XTDatabaseLogPtr; + +xtBool xt_xlog_flush_log(struct XTThread *thread); +xtBool xt_xlog_log_data(struct XTThread *thread, size_t len, XTXactLogBufferDPtr log_entry, xtBool commit); +xtBool xt_xlog_modify_table(struct XTOpenTable *ot, u_int status, xtOpSeqNo op_seq, xtRecordID free_list, xtRecordID address, size_t size, xtWord1 *data); + +void xt_xlog_init(struct XTThread *self, size_t cache_size); +void xt_xlog_exit(struct XTThread *self); +xtInt8 xt_xlog_get_usage(); +xtInt8 xt_xlog_get_size(); +xtLogID xt_xlog_get_min_log(struct XTThread *self, struct XTDatabase *db); +void xt_xlog_delete_logs(struct XTThread *self, struct XTDatabase *db); + +void xt_start_writer(struct XTThread *self, struct XTDatabase *db); +void xt_wait_for_writer(struct XTThread *self, struct XTDatabase *db); +void xt_stop_writer(struct XTThread *self, struct XTDatabase *db); + +#endif + diff --git a/storage/pbxt/src/xt_config.h b/storage/pbxt/src/xt_config.h new file mode 100644 index 00000000000..6571ebdaebe --- /dev/null +++ b/storage/pbxt/src/xt_config.h @@ -0,0 +1,99 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2006-03-22 Paul McCullagh + * + * H&G2JCtL + * + * This header file should be included in every source, before all other + * headers. + * + * In particular: BEFORE THE SYSTEM HEADERS + */ + +#ifndef __xt_config_h__ +#define __xt_config_h__ + +#define MYSQL_SERVER 1 + +#ifdef DRIZZLED +#include "drizzled/global.h" +const int max_connections = 500; +#else +#include <mysql_version.h> +#include "my_global.h" +#endif + +/* + * This enables everything that GNU can do. The macro is actually + * recommended for new programs. + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +/* + * Make sure we use the thread safe version of the library. + */ +#define _THREAD_SAFE + +/* + * This causes things to be defined like stuff in inttypes.h + * which is used in printf() + */ +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +/* + * This define is not required by Linux because the _GNU_SOURCE + * definition includes POSIX complience. But I need it for + * Mac OS X. + */ +//#define _POSIX_C_SOURCE 2 +//#define _ANSI_SOURCE + +#ifdef __APPLE__ +#define XT_MAC +#endif + +#if defined(MSDOS) || defined(__WIN__) +#define XT_WIN +#endif + +#ifdef XT_WIN +#ifdef _DEBUG +#define DEBUG +#endif // _DEBUG +#else +#define XT_STREAMING +#endif + +#ifdef __FreeBSD__ +#define XT_FREEBSD +#endif + +#ifdef __NetBSD__ +#define XT_NETBSD +#endif + +#ifdef __sun +#define XT_SOLARIS +#endif + +#endif diff --git a/storage/pbxt/src/xt_defs.h b/storage/pbxt/src/xt_defs.h new file mode 100644 index 00000000000..16981ddc672 --- /dev/null +++ b/storage/pbxt/src/xt_defs.h @@ -0,0 +1,782 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Paul McCullagh + * + * H&G2JCtL + */ +#ifndef __xt_defs_h__ +#define __xt_defs_h__ + +#ifdef XT_WIN +#include "win_inttypes.h" +#else +#include <inttypes.h> +#endif +#include <sys/types.h> +#include <assert.h> +#include <stddef.h> +#include <string.h> + +//#include "pthread_xt.h" + +#ifdef DEBUG +//#define DEBUG_LOG_DELETE +#endif + +/* the following macros are used to quote compile-time numeric + * constants into strings, e.g. __LINE__ + */ +#define _QUOTE(x) #x +#define QUOTE(x) _QUOTE(x) + +/* ---------------------------------------------------------------------- + * CRASH DEBUGGING + */ + +/* Define this if crash debug should be on by default: + * pbxt_crash_debug set to TRUE by default. + * It can be turned off by creating a file called 'no-debug' + * in the pbxt database. + * It can be turned on by defining the file 'crash-debug' + * in the pbxt database. + */ +//#define XT_CRASH_DEBUG + +/* These are the things crash debug will do: */ +/* Create a core dump (windows only): */ +#define XT_COREDUMP + +/* Backup the datadir before recovery after a crash: */ +//#define XT_BACKUP_BEFORE_RECOVERY + +/* Keep this number of transaction logs around + * for analysis after a crash. + */ +#define XT_NUMBER_OF_LOGS_TO_SAVE 5 + +/* ---------------------------------------------------------------------- + * GENERIC GLOBAL TYPES + */ + +#ifdef XT_WIN + +#define xtInt1 __int8 +#define xtInt2 __int16 +#define xtInt4 __int32 +#define xtInt8 __int64 + +#define xtWord1 unsigned __int8 +#define xtWord2 unsigned __int16 +#define xtWord4 unsigned __int32 +#define xtWord8 unsigned __int64 + +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif +#ifndef NAME_MAX +#define NAME_MAX MAX_PATH +#endif + +/* XT actually assumes that off_t is 8 bytes: */ +#define off_t xtWord8 + +#else // XT_WIN + +#define xtInt1 int8_t +#define xtInt2 int16_t +#define xtInt4 int32_t +#define xtInt8 int64_t + +#ifdef XT_SOLARIS +#define u_int8_t uint8_t +#define u_int16_t uint16_t +#define u_int32_t uint32_t +#define u_int64_t uint64_t +#endif + +#define xtWord1 u_int8_t +#define xtWord2 u_int16_t +#define xtWord4 u_int32_t +#define xtWord8 u_int64_t + +#endif // XT_WIN + +/* A pointer sized word value: */ +#define xtWordPS ptrdiff_t + +#define XT_MAX_INT_1 ((xtInt1) 0x7F) +#define XT_MIN_INT_1 ((xtInt1) 0x80) +#define XT_MAX_INT_2 ((xtInt2) 0x7FFF) +#define XT_MIN_INT_2 ((xtInt2) 0x8000) +#define XT_MAX_INT_4 ((xtInt4) 0x7FFFFFFF) +#define XT_MIN_INT_4 ((xtInt4) 0x80000000) + +#define xtReal4 float +#define xtReal8 double + +#ifndef u_int +#define u_int unsigned int /* Assumed at least 4 bytes long! */ +#define u_long unsigned long /* Assumed at least 4 bytes long! */ +#endif +#define llong long long /* Assumed at least 8 bytes long! */ +#define u_llong unsigned long long /* Assumed at least 8 bytes long! */ + +#define c_char const char + +#ifndef NULL +#define NULL 0 +#endif + +#define xtPublic + +#define xtBool int +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* Additional return codes: */ +#define XT_MAYBE 2 +#define XT_ERR -1 +#define XT_NEW -2 +#define XT_RETRY -3 +#define XT_REREAD -4 + +#ifdef OK +#undef OK +#endif +#define OK TRUE + +#ifdef FAILED +#undef FAILED +#endif +#define FAILED FALSE + +typedef xtWord1 XTDiskValue1[1]; +typedef xtWord1 XTDiskValue2[2]; +typedef xtWord1 XTDiskValue3[3]; +typedef xtWord1 XTDiskValue4[4]; +typedef xtWord1 XTDiskValue6[6]; +typedef xtWord1 XTDiskValue8[8]; + +#ifdef DEBUG +#define XT_VAR_LENGTH 100 +#else +#define XT_VAR_LENGTH 1 +#endif + +typedef struct XTPathStr { + char ps_path[XT_VAR_LENGTH]; +} *XTPathStrPtr; + +#define XT_UNUSED(x) x __attribute__((__unused__)) + +/* ---------------------------------------------------------------------- + * MAIN CONSTANTS + */ + +/* + * Define if there should only be one database per server instance: + */ +#define XT_USE_GLOBAL_DB + +/* + * The rollover size is the write limit of a log file. + * After this size is reached, a thread will start a + * new log. + * + * However, logs can grow much larger than this size. + * The reason is, a transaction single transaction + * may not span more than one data log file. + * + * This means the log rollover size is actually a + * minimum size. + */ + +#ifdef DEBUG +//#define XT_USE_GLOBAL_DEBUG_SIZES +#endif + +/* + * I believe the MySQL limit is 16. This limit is currently only used for + * BLOB streaming. + */ +#define XT_MAX_COLS_PER_INDEX 32 + +/* + * The maximum number of tables that can be created in a PBXT + * database. The amount is based on the fact that XT creates + * about 5 files per table in the database, and also + * uses directory listing to find tables. + */ +#define XT_MAX_TABLES 10000 + +/* + * When the amount of garbage in the file is greater than the + * garbage threshold, then compactor is activated. + */ +#define XT_GARBAGE_THRESHOLD ((double) 50.0) + +/* A record that does not contain blobs will be handled as a fixed + * length record if its maximum size is less than this amount, + * regardless of the size of the VARCHAR fields it contains. + */ +#define XT_TAB_MIN_VAR_REC_LENGTH 320 + +/* No record in the data handle file may exceed this size: */ +#define XT_TAB_MAX_FIX_REC_LENGTH (16 * 1024) + +/* No record in the data handle file may exceed this size, if + * AVG_ROW_LENGTH is set. + */ +#define XT_TAB_MAX_FIX_REC_LENGTH_SPEC (64 * 1024) + +/* + * Determines the page size of the indexes. The value is given + * in shifts of 1 to the left (e.g. 1 << 11 == 2048, + * 1 << 12 == 4096). + * + * PMC: Note the performance of sysbench is better with 11 + * than with 12. + * + * InnoDB uses 16K pages: + * 1 << 14 == 16384. + */ +#define XT_INDEX_PAGE_SHIFTS 14 + +/* The number of RW locks used to scatter locks on the rows + * of a table. The locks are only help for a short time during which + * the row list is scanned. + * + * For more details see [(9)]. + */ +#define XT_ROW_RWLOCKS 223 + +/* + * These are the number of row lock "slots" per table. + * Row locks are taken on UPDATE/DELETE or SELECT FOR UPDATE. + */ +#define XT_ROW_LOCK_COUNT (XT_ROW_RWLOCKS * 91) + +/* + * The size of index write buffer. Must be at least as large as the + * largest index page, plus overhead. + */ +#define XT_INDEX_WRITE_BUFFER_SIZE (1024 * 1024) + +/* This is the time in seconds that a open table in the open + * table pool must be on the free list before it + * is actually freed from the pool. + * + * This is to reduce the affect from MySQL with a very low + * table cache size, which causes tables to be openned and + * closed very rapidly. + */ +#define XT_OPEN_TABLE_FREE_TIME 30 + +#ifdef XT_USE_GLOBAL_DEBUG_SIZES +/* + * DEBUG SIZES! + * Reduce the thresholds to make things happen faster. + */ + +//#undef XT_ROW_RWLOCKS +//#define XT_ROW_RWLOCKS 2 + +//#undef XT_TAB_MIN_VAR_REC_LENGTH +//#define XT_TAB_MIN_VAR_REC_LENGTH 20 + +//#undef XT_ROW_LOCK_COUNT +//#define XT_ROW_LOCK_COUNT (XT_ROW_RWLOCKS * 2) + +//#undef XT_INDEX_PAGE_SHIFTS +//#define XT_INDEX_PAGE_SHIFTS 12 + +//#undef XT_INDEX_WRITE_BUFFER_SIZE +//#define XT_INDEX_WRITE_BUFFER_SIZE (40 * 1024) + +#endif + +/* Define this in order to use memory mapped files: */ +#define XT_USE_ROW_REC_MMAP_FILES + +/* Define this in order to use direct I/O on index files: */ +/* NOTE: DO NOT ENABLE! + * {DIRECT-IO} + * It currently does not work, because of changes to the inde + * cache. + */ +//#define XT_USE_DIRECT_IO_ON_INDEX + +#ifdef XT_USE_ROW_REC_MMAP_FILES + +#define XT_SEQ_SCAN_FROM_MEMORY +#define XT_ROW_REC_FILE_PTR XTMapFilePtr +#define XT_PWRITE_RR_FILE xt_pwrite_fmap +#define XT_PREAD_RR_FILE xt_pread_fmap +#define XT_FLUSH_RR_FILE xt_flush_fmap +#define XT_CLOSE_RR_FILE_NS xt_close_fmap_ns + +#else + +#define XT_ROW_REC_FILE_PTR XTOpenFilePtr +#define XT_PWRITE_RR_FILE xt_pwrite_file +#define XT_PREAD_RR_FILE xt_pread_file +#define XT_FLUSH_RR_FILE xt_flush_file +#define XT_CLOSE_RR_FILE_NS xt_close_file_ns + +#endif + +#ifdef XT_SEQ_SCAN_FROM_MEMORY +#define XT_LOCK_MEMORY_PTR(x, f, a, s, v, c) do { x = xt_lock_fmap_ptr(f, a, s, v, c); } while (0) +#define XT_UNLOCK_MEMORY_PTR(f, v) xt_unlock_fmap_ptr(f, v); +#else +#define XT_LOCK_MEMORY_PTR(x, f, a, v, c) +#define XT_UNLOCK_MEMORY_PTR(f, v) +#endif + +/* {NO-ACTION-BUG} + * Define this to implement NO ACTION correctly + * NOTE: this does not work currently because of a bug + * in MySQL + * + * The bug prevent returning of an error in external_lock() + * on statement end. In this case an assertion fails. + * + * set storage_engine = pbxt; + * DROP TABLE IF EXISTS t4,t3,t2,t1; + * CREATE TABLE t1 (s1 INT PRIMARY KEY); + * CREATE TABLE t2 (s1 INT PRIMARY KEY, FOREIGN KEY (s1) REFERENCES t1 (s1) ON DELETE NO ACTION); + * + * INSERT INTO t1 VALUES (1); + * INSERT INTO t2 VALUES (1); + * + * begin; + * INSERT INTO t1 VALUES (2); + * DELETE FROM t1 where s1 = 1; + * <-- Assertion fails here because this DELETE returns + * an error from external_lock() + */ +//#define XT_IMPLEMENT_NO_ACTION + +/* ---------------------------------------------------------------------- + * GLOBAL CONSTANTS + */ + +#define XT_INDEX_PAGE_SIZE (1 << XT_INDEX_PAGE_SHIFTS) +#define XT_INDEX_PAGE_MASK (XT_INDEX_PAGE_SIZE - 1) + +/* The index file uses direct I/O. This is the minimum block. + * size that can be used when doing direct I/O. + */ +#define XT_BLOCK_SIZE_FOR_DIRECT_IO 512 + +/* + * The header is currently a fixed size, so the information must + * fit in this block! + * + * This must also be a multiple of XT_INDEX_MIN_BLOCK_SIZE + */ +#define XT_INDEX_HEAD_SIZE (XT_BLOCK_SIZE_FOR_DIRECT_IO * 8) // 4K + +#define XT_IDENTIFIER_CHAR_COUNT 64 + +#define XT_IDENTIFIER_NAME_SIZE ((XT_IDENTIFIER_CHAR_COUNT * 3) + 1) // The identifier length as UTF-8 +#define XT_TABLE_NAME_SIZE ((XT_IDENTIFIER_CHAR_COUNT * 5) + 1) // The maximum length of a file name that has been normalized + +#define XT_ADD_PTR(p, l) ((void *) ((char *) (p) + (l))) + +/* ---------------------------------------------------------------------- + * BYTE ORDER + */ + +/* + * Byte order on the disk is little endian! This is the byte order of the i386. + * Little endian byte order starts with the least significant byte. + * + * The reason for choosing this byte order for the disk is 2-fold: + * Firstly the i386 is the cheapest and fasted platform today. + * Secondly the i386, unlike RISK chips (with big endian) can address + * memory that is not aligned! + * + * Since the disk image of PrimeBase XT is not aligned, the second point + * is significant. A RISK chip needs to access it byte-wise, so we might as + * well do the byte swapping at the same time. + * + * The macros below are of 4 general types: + * + * GET/SET - Get and set 1,2,4,8 byte values (short, int, long, etc). + * Values are swapped only on big endian platforms. This makes these + * functions very efficient on little-endian platforms. + * + * COPY - Transfer data without swapping regardless of platform. This + * function is a bit more efficient on little-endian platforms + * because alignment is not an issue. + * + * MOVE - Similar to get and set, but the deals with memory instead + * of values. Since no swapping is done on little-endian platforms + * this function is identical to COPY on little-endian platforms. + * + * SWAP - Transfer and swap data regardless of the platform type. + * Aligment is not assumed. + * + * The DISK component of the macro names indicates that alignment of + * the value cannot be assumed. + * + */ +#if BYTE_ORDER == BIG_ENDIAN +/* The native order of the machine is big endian. Since the native disk + * disk order of XT is little endian, all data to and from disk + * must be swapped. + */ +#define XT_SET_DISK_1(d, s) ((d)[0] = (xtWord1) (s)) + +#define XT_SET_DISK_2(d, s) do { (d)[0] = (xtWord1) (((xtWord2) (s)) & 0xFF); (d)[1] = (xtWord1) ((((xtWord2) (s)) >> 8 ) & 0xFF); } while (0) + +#define XT_SET_DISK_3(d, s) do { (d)[0] = (xtWord1) (((xtWord4) (s)) & 0xFF); (d)[1] = (xtWord1) ((((xtWord4) (s)) >> 8 ) & 0xFF); \ + (d)[2] = (xtWord1) ((((xtWord4) (s)) >> 16) & 0xFF); } while (0) + +#define XT_SET_DISK_4(d, s) do { (d)[0] = (xtWord1) (((xtWord4) (s)) & 0xFF); (d)[1] = (xtWord1) ((((xtWord4) (s)) >> 8 ) & 0xFF); \ + (d)[2] = (xtWord1) ((((xtWord4) (s)) >> 16) & 0xFF); (d)[3] = (xtWord1) ((((xtWord4) (s)) >> 24) & 0xFF); } while (0) + +#define XT_SET_DISK_6(d, s) do { (d)[0] = (xtWord1) (((xtWord8) (s)) & 0xFF); (d)[1] = (xtWord1) ((((xtWord8) (s)) >> 8 ) & 0xFF); \ + (d)[2] = (xtWord1) ((((xtWord8) (s)) >> 16) & 0xFF); (d)[3] = (xtWord1) ((((xtWord8) (s)) >> 24) & 0xFF); \ + (d)[4] = (xtWord1) ((((xtWord8) (s)) >> 32) & 0xFF); (d)[5] = (xtWord1) ((((xtWord8) (s)) >> 40) & 0xFF); } while (0) + +#define XT_SET_DISK_8(d, s) do { (d)[0] = (xtWord1) (((xtWord8) (s)) & 0xFF); (d)[1] = (xtWord1) ((((xtWord8) (s)) >> 8 ) & 0xFF); \ + (d)[2] = (xtWord1) ((((xtWord8) (s)) >> 16) & 0xFF); (d)[3] = (xtWord1) ((((xtWord8) (s)) >> 24) & 0xFF); \ + (d)[4] = (xtWord1) ((((xtWord8) (s)) >> 32) & 0xFF); (d)[5] = (xtWord1) ((((xtWord8) (s)) >> 40) & 0xFF); \ + (d)[6] = (xtWord1) ((((xtWord8) (s)) >> 48) & 0xFF); (d)[7] = (xtWord1) ((((xtWord8) (s)) >> 56) & 0xFF); } while (0) + +#define XT_GET_DISK_1(s) ((s)[0]) + +#define XT_GET_DISK_2(s) ((xtWord2) (((xtWord2) (s)[0]) | (((xtWord2) (s)[1]) << 8))) + +#define XT_GET_DISK_3(s) ((xtWord4) (((xtWord4) (s)[0]) | (((xtWord4) (s)[1]) << 8) | (((xtWord4) (s)[2]) << 16))) + +#define XT_GET_DISK_4(s) (((xtWord4) (s)[0]) | (((xtWord4) (s)[1]) << 8 ) | \ + (((xtWord4) (s)[2]) << 16) | (((xtWord4) (s)[3]) << 24)) + +#define XT_GET_DISK_6(s) (((xtWord8) (s)[0]) | (((xtWord8) (s)[1]) << 8 ) | \ + (((xtWord8) (s)[2]) << 16) | (((xtWord8) (s)[3]) << 24) | \ + (((xtWord8) (s)[4]) << 32) | (((xtWord8) (s)[5]) << 40)) + +#define XT_GET_DISK_8(s) (((xtWord8) (s)[0]) | (((xtWord8) (s)[1]) << 8 ) | \ + (((xtWord8) (s)[2]) << 16) | (((xtWord8) (s)[3]) << 24) | \ + (((xtWord8) (s)[4]) << 32) | (((xtWord8) (s)[5]) << 40) | \ + (((xtWord8) (s)[6]) << 48) | (((xtWord8) (s)[7]) << 56)) + +/* Move will copy memory, and swap the bytes on a big endian machine. + * On a little endian machine it is the same as COPY. + */ +#define XT_MOVE_DISK_1(d, s) ((d)[0] = (s)[0]) +#define XT_MOVE_DISK_2(d, s) do { (d)[0] = (s)[1]; (d)[1] = (s)[0]; } while (0) +#define XT_MOVE_DISK_3(d, s) do { (d)[0] = (s)[2]; (d)[1] = (s)[1]; (d)[2] = (s)[0]; } while (0) +#define XT_MOVE_DISK_4(d, s) do { (d)[0] = (s)[3]; (d)[1] = (s)[2]; (d)[2] = (s)[1]; (d)[3] = (s)[0]; } while (0) +#define XT_MOVE_DISK_8(d, s) do { (d)[0] = (s)[7]; (d)[1] = (s)[6]; \ + (d)[2] = (s)[5]; (d)[3] = (s)[4]; \ + (d)[4] = (s)[3]; (d)[5] = (s)[2]; \ + (d)[6] = (s)[1]; (d)[7] = (s)[0]; } while (0) + +/* + * Copy just copies the number of bytes assuming the data is not alligned. + */ +#define XT_COPY_DISK_1(d, s) (d)[0] = s +#define XT_COPY_DISK_2(d, s) do { (d)[0] = (s)[0]; (d)[1] = (s)[1]; } while (0) +#define XT_COPY_DISK_3(d, s) do { (d)[0] = (s)[0]; (d)[1] = (s)[1]; (d)[2] = (s)[2]; } while (0) +#define XT_COPY_DISK_4(d, s) do { (d)[0] = (s)[0]; (d)[1] = (s)[1]; (d)[2] = (s)[2]; (d)[3] = (s)[3]; } while (0) +#define XT_COPY_DISK_6(d, s) memcpy(&((d)[0]), &((s)[0]), 6) +#define XT_COPY_DISK_8(d, s) memcpy(&((d)[0]), &((s)[0]), 8) +#define XT_COPY_DISK_10(d, s) memcpy(&((d)[0]), &((s)[0]), 10) + +#define XT_SET_NULL_DISK_1(d) XT_SET_DISK_1(d, 0) +#define XT_SET_NULL_DISK_2(d) do { (d)[0] = 0; (d)[1] = 0; } while (0) +#define XT_SET_NULL_DISK_4(d) do { (d)[0] = 0; (d)[1] = 0; (d)[2] = 0; (d)[3] = 0; } while (0) +#define XT_SET_NULL_DISK_6(d) do { (d)[0] = 0; (d)[1] = 0; (d)[2] = 0; (d)[3] = 0; (d)[4] = 0; (d)[5] = 0; } while (0) +#define XT_SET_NULL_DISK_8(d) do { (d)[0] = 0; (d)[1] = 0; (d)[2] = 0; (d)[3] = 0; (d)[4] = 0; (d)[5] = 0; (d)[6] = 0; (d)[7] = 0; } while (0) + +#define XT_IS_NULL_DISK_1(d) (!(XT_GET_DISK_1(d))) +#define XT_IS_NULL_DISK_4(d) (!(d)[0] && !(d)[1] && !(d)[2] && !(d)[3]) +#define XT_IS_NULL_DISK_8(d) (!(d)[0] && !(d)[1] && !(d)[2] && !(d)[3] && !(d)[4] && !(d)[5] && !(d)[6] && !(7)[3]) + +#define XT_EQ_DISK_4(d, s) ((d)[0] == (s)[0] && (d)[1] == (s)[1] && (d)[2] == (s)[2] && (d)[3] == (s)[3]) +#define XT_EQ_DISK_8(d, s) ((d)[0] == (s)[0] && (d)[1] == (s)[1] && (d)[2] == (s)[2] && (d)[3] == (s)[3] && \ + (d)[4] == (s)[4] && (d)[5] == (s)[5] && (d)[6] == (s)[6] && (d)[7] == (s)[7]) + +#define XT_IS_FF_DISK_4(d) ((d)[0] == 0xFF && (d)[1] == 0xFF && (d)[2] == 0xFF && (d)[3] == 0xFF) +#else +/* + * The native order of the machine is little endian. This means the data to + * and from disk need not be swapped. In addition to this, since + * the i386 can access non-aligned memory we are not required to + * handle the data byte-for-byte. + */ +#define XT_SET_DISK_1(d, s) ((d)[0] = (xtWord1) (s)) +#define XT_SET_DISK_2(d, s) (*((xtWord2 *) &((d)[0])) = (xtWord2) (s)) +#define XT_SET_DISK_3(d, s) do { (*((xtWord2 *) &((d)[0])) = (xtWord2) (s)); *((xtWord1 *) &((d)[2])) = (xtWord1) (((xtWord4) (s)) >> 16); } while (0) +#define XT_SET_DISK_4(d, s) (*((xtWord4 *) &((d)[0])) = (xtWord4) (s)) +#define XT_SET_DISK_6(d, s) do { *((xtWord4 *) &((d)[0])) = (xtWord4) (s); *((xtWord2 *) &((d)[4])) = (xtWord2) (((xtWord8) (s)) >> 32); } while (0) +#define XT_SET_DISK_8(d, s) (*((xtWord8 *) &((d)[0])) = (xtWord8) (s)) + +#define XT_GET_DISK_1(s) ((s)[0]) +#define XT_GET_DISK_2(s) *((xtWord2 *) &((s)[0])) +#define XT_GET_DISK_3(s) ((xtWord4) *((xtWord2 *) &((s)[0])) | (((xtWord4) *((xtWord1 *) &((s)[2]))) << 16)) +#define XT_GET_DISK_4(s) *((xtWord4 *) &((s)[0])) +#define XT_GET_DISK_6(s) ((xtWord8) *((xtWord4 *) &((s)[0])) | (((xtWord8) *((xtWord2 *) &((s)[4]))) << 32)) +#define XT_GET_DISK_8(s) *((xtWord8 *) &((s)[0])) + +#define XT_MOVE_DISK_1(d, s) ((d)[0] = (s)[0]) +#define XT_MOVE_DISK_2(d, s) XT_COPY_DISK_2(d, s) +#define XT_MOVE_DISK_3(d, s) XT_COPY_DISK_3(d, s) +#define XT_MOVE_DISK_4(d, s) XT_COPY_DISK_4(d, s) +#define XT_MOVE_DISK_8(d, s) XT_COPY_DISK_8(d, s) + +#define XT_COPY_DISK_1(d, s) (d)[0] = s +#define XT_COPY_DISK_2(d, s) (*((xtWord2 *) &((d)[0])) = (*((xtWord2 *) &((s)[0])))) +#define XT_COPY_DISK_3(d, s) do { *((xtWord2 *) &((d)[0])) = *((xtWord2 *) &((s)[0])); (d)[2] = (s)[2]; } while (0) +#define XT_COPY_DISK_4(d, s) (*((xtWord4 *) &((d)[0])) = (*((xtWord4 *) &((s)[0])))) +#define XT_COPY_DISK_6(d, s) do { *((xtWord4 *) &((d)[0])) = *((xtWord4 *) &((s)[0])); *((xtWord2 *) &((d)[4])) = *((xtWord2 *) &((s)[4])); } while (0) +#define XT_COPY_DISK_8(d, s) (*((xtWord8 *) &(d[0])) = (*((xtWord8 *) &((s)[0])))) +#define XT_COPY_DISK_10(d, s) memcpy(&((d)[0]), &((s)[0]), 10) + +#define XT_SET_NULL_DISK_1(d) XT_SET_DISK_1(d, 0) +#define XT_SET_NULL_DISK_2(d) XT_SET_DISK_2(d, 0) +#define XT_SET_NULL_DISK_3(d) XT_SET_DISK_3(d, 0) +#define XT_SET_NULL_DISK_4(d) XT_SET_DISK_4(d, 0L) +#define XT_SET_NULL_DISK_6(d) XT_SET_DISK_6(d, 0LL) +#define XT_SET_NULL_DISK_8(d) XT_SET_DISK_8(d, 0LL) + +#define XT_IS_NULL_DISK_1(d) (!(XT_GET_DISK_1(d))) +#define XT_IS_NULL_DISK_2(d) (!(XT_GET_DISK_2(d))) +#define XT_IS_NULL_DISK_3(d) (!(XT_GET_DISK_3(d))) +#define XT_IS_NULL_DISK_4(d) (!(XT_GET_DISK_4(d))) +#define XT_IS_NULL_DISK_8(d) (!(XT_GET_DISK_8(d))) + +#define XT_EQ_DISK_4(d, s) (XT_GET_DISK_4(d) == XT_GET_DISK_4(s)) +#define XT_EQ_DISK_8(d, s) (XT_GET_DISK_8(d) == XT_GET_DISK_8(s)) + +#define XT_IS_FF_DISK_4(d) (XT_GET_DISK_4(d) == 0xFFFFFFFF) +#endif + +#define XT_CMP_DISK_4(a, b) ((xtInt4) XT_GET_DISK_4(a) - (xtInt4) XT_GET_DISK_4(b)) +#define XT_CMP_DISK_8(d, s) memcmp(&((d)[0]), &((s)[0]), 8) +//#define XT_CMP_DISK_8(d, s) (XT_CMP_DISK_4((d).h_number_4, (s).h_number_4) == 0 ? XT_CMP_DISK_4((d).h_file_4, (s).h_file_4) : XT_CMP_DISK_4((d).h_number_4, (s).h_number_4)) + +#define XT_SWAP_DISK_2(d, s) do { (d)[0] = (s)[1]; (d)[1] = (s)[0]; } while (0) +#define XT_SWAP_DISK_3(d, s) do { (d)[0] = (s)[2]; (d)[1] = (s)[1]; (d)[2] = (s)[0]; } while (0) +#define XT_SWAP_DISK_4(d, s) do { (d)[0] = (s)[3]; (d)[1] = (s)[2]; (d)[2] = (s)[1]; (d)[3] = (s)[0]; } while (0) +#define XT_SWAP_DISK_8(d, s) do { (d)[0] = (s)[7]; (d)[1] = (s)[6]; (d)[2] = (s)[5]; (d)[3] = (s)[4]; \ + (d)[4] = (s)[3]; (d)[5] = (s)[2]; (d)[6] = (s)[1]; (d)[7] = (s)[0]; } while (0) + +/* ---------------------------------------------------------------------- + * GLOBAL APPLICATION TYPES & MACROS + */ + +struct XTThread; + +typedef void (*XTFreeFunc)(struct XTThread *self, void *thunk, void *item); +typedef int (*XTCompareFunc)(struct XTThread *self, register const void *thunk, register const void *a, register const void *b); + +/* Log ID and offset: */ +#define xtLogID xtWord4 +#define xtLogOffset off_t + +#define xtDatabaseID xtWord4 +#define xtTableID xtWord4 +#define xtOpSeqNo xtWord4 +#define xtXactID xtWord4 +#define xtThreadID xtWord4 + +#ifdef DEBUG +//#define XT_USE_NODE_ID_STRUCT +#endif + +#ifdef XT_USE_NODE_ID_STRUCT +typedef struct xtIndexNodeID { + xtWord4 x; +} xtIndexNodeID; +#define XT_NODE_TEMP xtWord4 xt_node_temp +#define XT_NODE_ID(a) (a).x +#define XT_RET_NODE_ID(a) *((xtIndexNodeID *) &(xt_node_temp = (a))) +#else +#define XT_NODE_TEMP +#define xtIndexNodeID xtWord4 +#define XT_NODE_ID(a) a +#define XT_RET_NODE_ID(a) ((xtIndexNodeID) (a)) +#endif + +/* Row, Record ID and Record offsets: */ +#define xtRowID xtWord4 +#define xtRecordID xtWord4 /* NOTE: Record offset == header-size + record-id * record-size! */ +#define xtRefID xtWord4 /* Must be big enough to contain a xtRowID and a xtRecordID! */ +#define xtRecOffset off_t +#define xtDiskRecordID4 XTDiskValue4 +#ifdef XT_WIN +#define xtProcID DWORD +#else +#define xtProcID pid_t +#endif + +#define XT_ROW_ID_SIZE 4 +#define XT_RECORD_ID_SIZE 4 +#define XT_REF_ID_SIZE 4 /* max(XT_ROW_ID_SIZE, XT_RECORD_ID_SIZE) */ +#define XT_RECORD_OFFS_SIZE 4 +#define XT_RECORD_REF_SIZE (XT_RECORD_ID_SIZE + XT_ROW_ID_SIZE) +#define XT_CHECKSUM4_REC(x) (x) + +#define XT_XACT_ID_SIZE 4 +#define XT_CHECKSUM4_XACT(x) (x) + +/* ---------------------------------------------------------------------- + * GLOBAL VARIABLES + */ + +extern bool pbxt_inited; +extern xtBool pbxt_ignore_case; +extern const char *pbxt_extensions[]; +extern xtBool pbxt_crash_debug; + + +/* ---------------------------------------------------------------------- + * DRIZZLE MAPPINGS VARIABLES + */ + +#ifdef DRIZZLED +/* Drizzle is stuck at this level: */ +#define MYSQL_VERSION_ID 60005 + +#define TABLE_LIST TableList +#define TABLE Table +#define THD Session +#define MYSQL_THD Session * +#define THR_THD THR_Session +#define STRUCT_TABLE class Table + +#define MYSQL_TYPE_STRING DRIZZLE_TYPE_VARCHAR +#define MYSQL_TYPE_VARCHAR DRIZZLE_TYPE_VARCHAR +#define MYSQL_TYPE_LONGLONG DRIZZLE_TYPE_LONGLONG +#define MYSQL_TYPE_BLOB DRIZZLE_TYPE_BLOB +#define MYSQL_TYPE_ENUM DRIZZLE_TYPE_ENUM +#define MYSQL_TYPE_LONG DRIZZLE_TYPE_LONG +#define MYSQL_PLUGIN_VAR_HEADER DRIZZLE_PLUGIN_VAR_HEADER +#define MYSQL_SYSVAR_STR DRIZZLE_SYSVAR_STR +#define MYSQL_SYSVAR_INT DRIZZLE_SYSVAR_INT +#define MYSQL_SYSVAR DRIZZLE_SYSVAR +#define MYSQL_STORAGE_ENGINE_PLUGIN DRIZZLE_STORAGE_ENGINE_PLUGIN +#define MYSQL_INFORMATION_SCHEMA_PLUGIN DRIZZLE_INFORMATION_SCHEMA_PLUGIN +#define memcpy_fixed memcpy +#define bfill(m, len, ch) memset(m, ch, len) + +#define mx_tmp_use_all_columns(x, y) (x)->use_all_columns(y) +#define mx_tmp_restore_column_map(x, y) (x)->restore_column_map(y) + +#define MX_TABLE_TYPES_T handler::Table_flags +#define MX_UINT8_T uint8_t +#define MX_ULONG_T uint32_t +#define MX_ULONGLONG_T uint64_t +#define MX_LONGLONG_T uint64_t +#define MX_CHARSET_INFO struct charset_info_st +#define MX_CONST_CHARSET_INFO const struct charset_info_st +#define MX_CONST const +#define my_bool bool +#define int16 int16_t +#define int32 int32_t +#define uint16 uint16_t +#define uint32 uint32_t +#define uchar unsigned char +#define longlong int64_t +#define ulonglong uint64_t + +#define HAVE_LONG_LONG + +#define my_malloc(x, y) malloc(x) +#define my_free(x, y) free(x) + +#define HA_CAN_SQL_HANDLER 0 +#define HA_CAN_INSERT_DELAYED 0 + +#define max cmax +#define min cmin + +#define NullS NULL + +#define thd_charset session_charset +#define thd_query session_query +#define thd_slave_thread session_slave_thread +#define thd_non_transactional_update session_non_transactional_update +#define thd_binlog_format session_binlog_format +#define thd_mark_transaction_to_rollback session_mark_transaction_to_rollback +#define thd_ha_data session_ha_data +#define current_thd current_session +#define thd_sql_command session_sql_command +#define thd_test_options session_test_options +#define thd_killed session_killed +#define thd_tx_isolation session_tx_isolation +#define thd_in_lock_tables session_in_lock_tables +#define thd_tablespace_op session_tablespace_op +#define thd_alloc session_alloc +#define thd_make_lex_string session_make_lex_string + +#define my_pthread_setspecific_ptr(T, V) pthread_setspecific(T, (void*) (V)) + +#define mysql_real_data_home drizzle_real_data_home + +#define mi_int4store(T,A) { uint32_t def_temp= (uint32_t) (A);\ + ((unsigned char*) (T))[3]= (unsigned char) (def_temp);\ + ((unsigned char*) (T))[2]= (unsigned char) (def_temp >> 8);\ + ((unsigned char*) (T))[1]= (unsigned char) (def_temp >> 16);\ + ((unsigned char*) (T))[0]= (unsigned char) (def_temp >> 24); } + +#define mi_uint4korr(A) ((uint32_t) (((uint32_t) (((const unsigned char*) (A))[3])) +\ + (((uint32_t) (((const unsigned char*) (A))[2])) << 8) +\ + (((uint32_t) (((const unsigned char*) (A))[1])) << 16) +\ + (((uint32_t) (((const unsigned char*) (A))[0])) << 24))) + +#else // DRIZZLED +/* The MySQL case: */ +#if MYSQL_VERSION_ID >= 60008 +#define STRUCT_TABLE struct TABLE +#else +#define STRUCT_TABLE struct st_table +#endif + +#define mx_tmp_use_all_columns dbug_tmp_use_all_columns +#define mx_tmp_restore_column_map(x, y) dbug_tmp_restore_column_map((x)->read_set, y) + +#define MX_TABLE_TYPES_T ulonglong +#define MX_UINT8_T uint8 +#define MX_ULONG_T ulong +#define MX_ULONGLONG_T ulonglong +#define MX_LONGLONG_T longlong +#define MX_CHARSET_INFO CHARSET_INFO +#define MX_CONST_CHARSET_INFO struct charset_info_st +#define MX_CONST + +#endif // DRIZZLED + +#ifndef XT_SCAN_CORE_DEFINED +#define XT_SCAN_CORE_DEFINED +xtBool xt_mm_scan_core(void); +#endif + +//#define DEBUG_LOCK_QUEUE + +#endif diff --git a/storage/pbxt/src/xt_errno.h b/storage/pbxt/src/xt_errno.h new file mode 100644 index 00000000000..4d74589efe3 --- /dev/null +++ b/storage/pbxt/src/xt_errno.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2005 PrimeBase Technologies GmbH + * + * PrimeBase XT + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Paul McCullagh + * + * H&G2JCtL + */ + +#define XT_NO_ERR 0 +#define XT_SYSTEM_ERROR -1 +#define XT_ERR_STACK_OVERFLOW -2 +#define XT_ASSERTION_FAILURE -3 +#define XT_SIGNAL_CAUGHT -4 +#define XT_ERR_JUMP_OVERFLOW -5 +#define XT_ERR_BAD_HANDLE -6 +#define XT_ERR_TABLE_EXISTS -7 +#define XT_ERR_NAME_TOO_LONG -8 +#define XT_ERR_TABLE_NOT_FOUND -9 +#define XT_ERR_SESSION_NOT_FOUND -10 +#define XT_ERR_BAD_ADDRESS -11 +#define XT_ERR_UNKNOWN_SERVICE -12 +#define XT_ERR_UNKNOWN_HOST -13 +#define XT_ERR_TOKEN_EXPECTED -14 +#define XT_ERR_PROPERTY_REQUIRED -15 +#define XT_ERR_BAD_XACTION -16 +#define XT_ERR_INVALID_SLOT -17 +#define XT_ERR_DEADLOCK -18 +#define XT_ERR_CANNOT_CHANGE_DB -19 +#define XT_ERR_ILLEGAL_CHAR -20 +#define XT_ERR_UNTERMINATED_STRING -21 +#define XT_ERR_SYNTAX -22 +#define XT_ERR_ILLEGAL_INSTRUCTION -23 +#define XT_ERR_OUT_OF_BOUNDS -24 +#define XT_ERR_STACK_UNDERFLOW -25 +#define XT_ERR_TYPE_MISMATCH -26 +#define XT_ERR_ILLEGAL_TYPE -27 +#define XT_ERR_ID_TOO_LONG -28 +#define XT_ERR_TYPE_OVERFLOW -29 +#define XT_ERR_TABLE_IN_USE -30 +#define XT_ERR_NO_DATABASE_IN_USE -31 +#define XT_ERR_CANNOT_RESOLVE_TYPE -32 +#define XT_ERR_BAD_INDEX_DESC -33 +#define XT_ERR_WRONG_NO_OF_VALUES -34 +#define XT_ERR_CANNOT_OUTPUT_VALUE -35 +#define XT_ERR_COLUMN_NOT_FOUND -36 +#define XT_ERR_NOT_IMPLEMENTED -37 +#define XT_ERR_UNEXPECTED_EOS -38 +#define XT_ERR_BAD_TOKEN -39 +#define XT_ERR_RES_STACK_OVERFLOW -40 +#define XT_ERR_BAD_INDEX_TYPE -41 +#define XT_ERR_INDEX_EXISTS -42 +#define XT_ERR_INDEX_STRUC_EXISTS -43 +#define XT_ERR_INDEX_NOT_FOUND -44 +#define XT_ERR_INDEX_CORRUPT -45 +#define XT_ERR_DUPLICATE_KEY -46 +#define XT_ERR_TYPE_NOT_SUPPORTED -47 +#define XT_ERR_BAD_TABLE_VERSION -48 +#define XT_ERR_BAD_RECORD_FORMAT -49 +#define XT_ERR_BAD_EXT_RECORD -50 +#define XT_ERR_RECORD_CHANGED -51 // Record has already been updated by some other transaction +#define XT_ERR_XLOG_WAS_CORRUPTED -52 +#define XT_ERR_NO_DICTIONARY -53 +#define XT_ERR_TOO_MANY_TABLES -54 // Maximum number of table exceeded. +#define XT_ERR_KEY_TOO_LARGE -55 // Maximum size of an index key exceeded +#define XT_ERR_MULTIPLE_DATABASES -56 +#define XT_ERR_NO_TRANSACTION -57 +#define XT_ERR_A_EXPECTED_NOT_B -58 +#define XT_ERR_NO_MATCHING_INDEX -59 +#define XT_ERR_TABLE_LOCKED -60 +#define XT_ERR_NO_REFERENCED_ROW -61 +#define XT_ERR_BAD_DICTIONARY -62 +#define XT_ERR_LOADING_MYSQL_DIC -63 +#define XT_ERR_ROW_IS_REFERENCED -64 +#define XT_ERR_COLUMN_IS_NOT_NULL -65 +#define XT_ERR_INCORRECT_NO_OF_COLS -66 +#define XT_ERR_FK_ON_TEMP_TABLE -67 +#define XT_ERR_REF_TABLE_NOT_FOUND -68 +#define XT_ERR_REF_TYPE_WRONG -69 +#define XT_ERR_DUPLICATE_FKEY -70 +#define XT_ERR_INDEX_FILE_TO_LARGE -71 +#define XT_ERR_UPGRADE_TABLE -72 +#define XT_ERR_INDEX_NEW_VERSION -73 +#define XT_ERR_LOCK_TIMEOUT -74 +#define XT_ERR_CONVERSION -75 +#define XT_ERR_NO_ROWS -76 +#define XT_ERR_MYSQL_ERROR -77 +#define XT_ERR_DATA_LOG_NOT_FOUND -78 +#define XT_ERR_LOG_MAX_EXCEEDED -79 +#define XT_ERR_MAX_ROW_COUNT -80 +#define XT_ERR_FILE_TOO_LONG -81 +#define XT_ERR_BAD_IND_BLOCK_SIZE -82 +#define XT_ERR_INDEX_CORRUPTED -83 +#define XT_ERR_NO_INDEX_CACHE -84 +#define XT_ERR_INDEX_LOG_CORRUPT -85 +#define XT_ERR_TOO_MANY_THREADS -86 +#define XT_ERR_TOO_MANY_WAITERS -87 +#define XT_ERR_INDEX_OLD_VERSION -88 +#define XT_ERR_PBXT_TABLE_EXISTS -89 +#define XT_ERR_SERVER_RUNNING -90 +#define XT_ERR_INDEX_MISSING -91 +#define XT_ERR_RECORD_DELETED -92 +#define XT_ERR_NEW_TYPE_OF_XLOG -93 +#define XT_ERR_NO_BEFORE_IMAGE -94 +#define XT_ERR_FK_REF_TEMP_TABLE -95 + +#ifdef XT_WIN +#define XT_ENOMEM ERROR_NOT_ENOUGH_MEMORY +#define XT_EAGAIN ERROR_RETRY +#define XT_EBUSY ERROR_BUSY +#else +#define XT_ENOMEM ENOMEM +#define XT_EAGAIN EAGAIN +#define XT_EBUSY EBUSY +#endif |