diff options
277 files changed, 8973 insertions, 2167 deletions
diff --git a/.bzrignore b/.bzrignore index e1e2083e2d2..c87963acb3e 100644 --- a/.bzrignore +++ b/.bzrignore @@ -392,6 +392,7 @@ client/rpl_record_old.h client/rpl_tblmap.h client/rpl_tblmap.cc client/rpl_utility.h +client/rpl_utility.cc client/select_test client/sql_string.cpp client/ssl_test @@ -1142,6 +1143,7 @@ libmysqld/rpl_filter.cc libmysqld/rpl_injector.cc libmysqld/rpl_record.cc libmysqld/rpl_record_old.cc +libmysqld/rpl_utility.cc libmysqld/scheduler.cc libmysqld/set_var.cc libmysqld/simple-test diff --git a/Makefile.am b/Makefile.am index 49ab3103c25..821f7e4fd0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -196,10 +196,6 @@ test-bt-fast: -cd mysql-test ; MTR_BUILD_THREAD=auto \ @PERL@ ./mysql-test-run.pl --force --comment=stress --suite=stress -test-bt-fast: - -cd mysql-test ; MTR_BUILD_THREAD=auto \ - @PERL@ ./mysql-test-run.pl --force --comment=ps --ps-protocol --report-features - test-bt-debug: -cd mysql-test ; MTR_BUILD_THREAD=auto \ @PERL@ ./mysql-test-run.pl --comment=debug --force --timer \ diff --git a/client/Makefile.am b/client/Makefile.am index ccd0d8aada0..14343bc60c3 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -104,9 +104,10 @@ DEFS = -DMYSQL_CLIENT_NO_THREADS \ -DMYSQL_DATADIR="\"$(localstatedir)\"" sql_src=log_event.h mysql_priv.h rpl_constants.h \ - rpl_utility.h rpl_tblmap.h rpl_tblmap.cc \ + rpl_tblmap.h rpl_tblmap.cc \ log_event.cc my_decimal.h my_decimal.cc \ log_event_old.h log_event_old.cc \ + rpl_utility.h rpl_utility.cc \ rpl_record_old.h rpl_record_old.cc strings_src=decimal.c diff --git a/client/mysql.cc b/client/mysql.cc index b76a3d624ab..9d078153a33 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -4335,7 +4335,7 @@ com_status(String *buffer __attribute__((unused)), Don't remove "limit 1", it is protection againts SQL_SELECT_LIMIT=0 */ - if (mysql_store_result_for_lazy(&result)) + if (!mysql_store_result_for_lazy(&result)) { MYSQL_ROW cur=mysql_fetch_row(result); if (cur) @@ -4379,7 +4379,7 @@ com_status(String *buffer __attribute__((unused)), if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) return 0; } - if (mysql_store_result_for_lazy(&result)) + if (!mysql_store_result_for_lazy(&result)) { MYSQL_ROW cur=mysql_fetch_row(result); if (cur) @@ -4474,9 +4474,7 @@ server_version_string(MYSQL *con) */ if (server_version == NULL) - { - server_version= strdup(mysql_get_server_info(con)); - } + server_version= my_strdup(mysql_get_server_info(con), MYF(MY_WME)); } return server_version ? server_version : ""; diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index cf56713ec0d..32945f0cf89 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -2139,4 +2139,4 @@ int main(int argc, char** argv) #include "my_decimal.cc" #include "log_event.cc" #include "log_event_old.cc" - +#include "rpl_utility.cc" diff --git a/client/mysqltest.cc b/client/mysqltest.cc index cb1d21ebe8a..e0cdec42a60 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -6827,10 +6827,8 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, MYSQL_STMT *stmt; DYNAMIC_STRING ds_prepare_warnings; DYNAMIC_STRING ds_execute_warnings; - ulonglong affected_rows; DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); - LINT_INIT(affected_rows); /* Init a new stmt if it's not already one created for this connection @@ -6966,8 +6964,7 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, warnings here */ { - ulonglong affected_rows; - LINT_INIT(affected_rows); + ulonglong UNINIT_VAR(affected_rows); if (!disable_info) affected_rows= mysql_affected_rows(mysql); diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4 index 1eec0e9e18c..996ac62e025 100644 --- a/config/ac-macros/misc.m4 +++ b/config/ac-macros/misc.m4 @@ -601,15 +601,15 @@ dnl --------------------------------------------------------------------------- dnl MYSQL_NEEDS_MYSYS_NEW AC_DEFUN([MYSQL_NEEDS_MYSYS_NEW], -[AC_CACHE_CHECK([needs mysys_new helpers], mysql_use_mysys_new, +[AC_CACHE_CHECK([needs mysys_new helpers], mysql_cv_use_mysys_new, [ AC_LANG_PUSH(C++) AC_TRY_LINK([], [ class A { public: int b; }; A *a=new A; a->b=10; delete a; -], mysql_use_mysys_new=no, mysql_use_mysys_new=yes) +], mysql_cv_use_mysys_new=no, mysql_cv_use_mysys_new=yes) AC_LANG_POP(C++) ]) -if test "$mysql_use_mysys_new" = "yes" +if test "$mysql_cv_use_mysys_new" = "yes" then AC_DEFINE([USE_MYSYS_NEW], [1], [Needs to use mysys_new helpers]) fi diff --git a/configure.in b/configure.in index fb5517659ba..8107884ec3c 100644 --- a/configure.in +++ b/configure.in @@ -10,9 +10,15 @@ AC_CANONICAL_SYSTEM # # When changing major version number please also check switch statement # in mysqlbinlog::check_master_version(). -AM_INIT_AUTOMAKE(mysql, 5.1.42) +AM_INIT_AUTOMAKE(mysql, 5.1.43) AM_CONFIG_HEADER([include/config.h:config.h.in]) +# Request support for automake silent-rules if available. +# Default to verbose output. One can use the configure-time +# option --enable-silent-rules or make V=0 to activate +# silent rules. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([no])]) + PROTOCOL_VERSION=10 DOT_FRM_VERSION=6 # See the libtool docs for information on how to do shared lib versions. diff --git a/extra/comp_err.c b/extra/comp_err.c index e36e85f6f0c..9326444ade9 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -660,7 +660,7 @@ static ha_checksum checksum_format_specifier(const char* msg) case 'u': case 'x': case 's': - chksum= my_checksum(chksum, start, (uint) (p - start)); + chksum= my_checksum(chksum, start, (uint) (p + 1 - start)); start= 0; /* Not in format specifier anymore */ break; @@ -1030,8 +1030,10 @@ static char *parse_text_line(char *pos) { int i, nr; char *row= pos; + size_t len; DBUG_ENTER("parse_text_line"); + len= strlen (pos); while (*pos) { if (*pos == '\\') @@ -1039,11 +1041,11 @@ static char *parse_text_line(char *pos) switch (*++pos) { case '\\': case '"': - VOID(strmov(pos - 1, pos)); + VOID(memmove (pos - 1, pos, len - (row - pos))); break; case 'n': pos[-1]= '\n'; - VOID(strmov(pos, pos + 1)); + VOID(memmove (pos, pos + 1, len - (row - pos))); break; default: if (*pos >= '0' && *pos < '8') @@ -1053,10 +1055,10 @@ static char *parse_text_line(char *pos) nr= nr * 8 + (*(pos++) - '0'); pos -= i; pos[-1]= nr; - VOID(strmov(pos, pos + i)); + VOID(memmove (pos, pos + i, len - (row - pos))); } else if (*pos) - VOID(strmov(pos - 1, pos)); /* Remove '\' */ + VOID(memmove (pos - 1, pos, len - (row - pos))); /* Remove '\' */ } } else diff --git a/include/mysql.h b/include/mysql.h index 68cce3196a0..d114afb6c93 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -557,16 +557,6 @@ unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); void STDCALL mysql_debug(const char *debug); -char * STDCALL mysql_odbc_escape_string(MYSQL *mysql, - char *to, - unsigned long to_length, - const char *from, - unsigned long from_length, - void *param, - char * - (*extend_buffer) - (void *, char *to, - unsigned long *length)); void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); my_bool STDCALL mysql_embedded(void); diff --git a/include/mysql.h.pp b/include/mysql.h.pp index bd4c79916dd..633cde41130 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -518,16 +518,6 @@ unsigned long mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); void mysql_debug(const char *debug); -char * mysql_odbc_escape_string(MYSQL *mysql, - char *to, - unsigned long to_length, - const char *from, - unsigned long from_length, - void *param, - char * - (*extend_buffer) - (void *, char *to, - unsigned long *length)); void myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int mysql_thread_safe(void); my_bool mysql_embedded(void); diff --git a/include/violite.h b/include/violite.h index 3f68ccde10f..1eef3ef5730 100644 --- a/include/violite.h +++ b/include/violite.h @@ -224,8 +224,8 @@ struct st_vio #endif /* HAVE_SMEM */ #ifdef _WIN32 OVERLAPPED pipe_overlapped; - DWORD read_timeout_millis; - DWORD write_timeout_millis; + DWORD read_timeout_ms; + DWORD write_timeout_ms; #endif }; #endif /* vio_violite_h_ */ diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 77ff2a01d7c..1264f2765ba 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1629,20 +1629,6 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, return (uint) escape_string_for_mysql(mysql->charset, to, 0, from, length); } - -char * STDCALL -mysql_odbc_escape_string(MYSQL *mysql __attribute__((unused)), - char *to __attribute__((unused)), - ulong to_length __attribute__((unused)), - const char *from __attribute__((unused)), - ulong from_length __attribute__((unused)), - void *param __attribute__((unused)), - char * (*extend_buffer)(void *, char *, ulong *) - __attribute__((unused))) -{ - return NULL; -} - void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name) { diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 8c6b71d9553..81f86dc8726 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -78,7 +78,6 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows - mysql_odbc_escape_string mysql_options mysql_stmt_param_count mysql_stmt_param_metadata diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 17dd2eed5b2..526e394dd27 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -55,7 +55,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ item_geofunc.cc item_subselect.cc item_row.cc\ item_xmlfunc.cc \ key.cc lock.cc log.cc sql_state.c \ - log_event.cc rpl_record.cc \ + log_event.cc rpl_record.cc rpl_utility.cc \ log_event_old.cc rpl_record_old.cc \ protocol.cc net_serv.cc opt_range.cc \ opt_sum.cc procedure.cc records.cc sql_acl.cc \ diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def index e0f02003963..047cfe0fe57 100644 --- a/libmysqld/libmysqld.def +++ b/libmysqld/libmysqld.def @@ -50,7 +50,6 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows - mysql_odbc_escape_string mysql_options mysql_ping mysql_query diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index b4e934735a6..4248b5b4087 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -13,15 +13,13 @@ funcs_1.ndb* # joro : NDB tests marked as experiment funcs_2.ndb_charset # joro : NDB tests marked as experimental as agreed with bochklin main.ctype_gbk_binlog @solaris # Bug#46010: main.ctype_gbk_binlog fails sporadically : Table 't2' already exists -main.innodb-autoinc* # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin main.plugin_load @solaris # Bug#42144 ndb.* # joro : NDB tests marked as experimental as agreed with bochklin -rpl.rpl_cross_version* # Bug #43913 2009-10-26 joro rpl_cross_version can't pass on conflicts complainig clash with --slave-load-tm -rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 +rpl.rpl_cross_version* # Bug#48340 2009-12-01 Daogang rpl_cross_version: Found warnings/errors in server log file! +rpl.rpl_get_master_version_and_clock* # Bug #49191 2009-12-01 Daogang rpl_get_master_version_and_clock failed on PB2: COM_REGISTER_SLAVE failed rpl.rpl_innodb_bug28430* @solaris # Bug#46029 -rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails on PB2 rpl.rpl_trigger* # Bug#47810 2009-10-04 joro rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin rpl_ndb.* # joro : NDB tests marked as experimental as agreed with bochklin diff --git a/mysql-test/extra/rpl_tests/check_type.inc b/mysql-test/extra/rpl_tests/check_type.inc new file mode 100644 index 00000000000..63491d81da4 --- /dev/null +++ b/mysql-test/extra/rpl_tests/check_type.inc @@ -0,0 +1,52 @@ +# Helper file to perform one insert of a value into a table with +# different types on master and slave. The file will insert the +# result into the type_conversions table *on the slave* to get a +# summary of failing and succeeding tests. + +# Input: +# $source_type Type on the master +# $target_type Type on the slave +# $source_value Value on the master (inserted into the table) +# $target_value Value on the slave (expected value in the table +# on the slave) +# $can_convert True if conversion shall work, false if it +# shall generate an error + + +connection master; +disable_warnings; +DROP TABLE IF EXISTS t1; +enable_warnings; +eval CREATE TABLE t1 (a $source_type); +sync_slave_with_master; +eval ALTER TABLE t1 MODIFY a $target_type; + +connection master; +eval INSERT INTO t1 VALUES($source_value); +if ($can_convert) { + sync_slave_with_master; + eval SELECT a = $target_value into @compare FROM t1; + eval INSERT INTO type_conversions SET + Source = "$source_type", + Target = "$target_type", + Flags = @@slave_type_conversions, + On_Master = $source_value, + Expected = $target_value, + Compare = @compare; + UPDATE type_conversions + SET On_Slave = (SELECT a FROM t1) + WHERE TestNo = LAST_INSERT_ID(); +} +if (!$can_convert) { + connection slave; + wait_for_slave_to_stop; + let $error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); + eval INSERT INTO type_conversions SET + Source = "$source_type", + Target = "$target_type", + Flags = @@slave_type_conversions, + On_Master = $source_value, + Error = "$error"; + SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; + START SLAVE; +} diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index 46168d6b97a..69b375677b6 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -36,6 +36,9 @@ sync_slave_with_master; STOP SLAVE; RESET SLAVE; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; + eval CREATE TABLE t1 (a INT, b INT PRIMARY KEY, c CHAR(20), d FLOAT DEFAULT '2.00', e CHAR(4) DEFAULT 'TEST') @@ -62,6 +65,8 @@ SELECT * FROM t1 ORDER BY a; sync_slave_with_master; SELECT * FROM t1 ORDER BY a; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; + --echo *** Drop t1 *** connection master; DROP TABLE t1; @@ -515,7 +520,7 @@ sync_slave_with_master; --echo *** Create t11 on slave *** STOP SLAVE; RESET SLAVE; -eval CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT, +eval CREATE TABLE t11 (a INT KEY, b BLOB, f INT, c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE=$engine_type; --echo *** Create t11 on Master *** diff --git a/mysql-test/extra/rpl_tests/rpl_row_basic.test b/mysql-test/extra/rpl_tests/rpl_row_basic.test index 0ba27c69a55..a45527848be 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_basic.test +++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test @@ -6,6 +6,7 @@ # First we test tables with only an index. # +connection master; eval CREATE TABLE t1 (C1 CHAR(1), C2 CHAR(1), INDEX (C1)$extra_index_t1) ENGINE = $type ; SELECT * FROM t1; sync_slave_with_master; @@ -156,6 +157,12 @@ SELECT * FROM t5,t2,t3 WHERE t5.C2='Q' AND t2.c12='R' AND t3.C3 ='S' ORDER BY t5 # Testing special column types # +if (`select char_length('$bit_field_special') > 0`) { + SET @saved_slave_type_conversions = @@SLAVE_TYPE_CONVERSIONS; + connection slave; + eval SET GLOBAL SLAVE_TYPE_CONVERSIONS = '$bit_field_special'; +} + connection master; eval CREATE TABLE t4 (C1 CHAR(1) PRIMARY KEY, B1 BIT(1), B2 BIT(1) NOT NULL DEFAULT 0, C2 CHAR(1) NOT NULL DEFAULT 'A') ENGINE = $type ; @@ -164,6 +171,10 @@ SELECT C1,HEX(B1),HEX(B2) FROM t4 ORDER BY C1; sync_slave_with_master; SELECT C1,HEX(B1),HEX(B2) FROM t4 ORDER BY C1; +if (`select char_length('$bit_field_special') > 0`) { + SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; +} + # # Testing conflicting operations # @@ -350,6 +361,10 @@ eval CREATE TABLE t7 (i INT NOT NULL, c CHAR(255) CHARACTER SET utf8 NOT NULL, j INT NOT NULL) ENGINE = $type ; +connection slave; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; + --echo [expecting slave to replicate correctly] connection master; INSERT INTO t1 VALUES (1, "", 1); @@ -370,17 +385,9 @@ let $diff_table_1=master:test.t2; let $diff_table_2=slave:test.t2; source include/diff_tables.inc; ---echo [expecting slave to stop] -connection master; -INSERT INTO t3 VALUES (1, "", 1); -INSERT INTO t3 VALUES (2, repeat(_utf8'a', 128), 2); - connection slave; -source include/wait_for_slave_sql_to_stop.inc; -let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); -disable_query_log; -eval SELECT "$last_error" AS Last_SQL_Error; -enable_query_log; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; + connection master; RESET MASTER; connection slave; @@ -600,7 +607,15 @@ sync_slave_with_master; connection master; +# Since t1 contain a bit field, we have to do this trick to handle InnoDB +if (`select char_length('$bit_field_special') > 0`) { + SET @saved_slave_type_conversions = @@SLAVE_TYPE_CONVERSIONS; + connection slave; + eval SET GLOBAL SLAVE_TYPE_CONVERSIONS = '$bit_field_special'; +} + --disable_warnings +connection master; eval CREATE TABLE t1 (a bit) ENGINE=$type; INSERT IGNORE INTO t1 VALUES (NULL); INSERT INTO t1 ( a ) VALUES ( 0 ); @@ -645,6 +660,10 @@ UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 3; sync_slave_with_master; +if (`select char_length('$bit_field_special') > 0`) { + SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; +} + let $diff_table_1=master:test.t1; let $diff_table_2=slave:test.t1; source include/diff_tables.inc; diff --git a/mysql-test/extra/rpl_tests/rpl_stm_000001.test b/mysql-test/extra/rpl_tests/rpl_stm_000001.test index 323d626c95f..1276b00d882 100644 --- a/mysql-test/extra/rpl_tests/rpl_stm_000001.test +++ b/mysql-test/extra/rpl_tests/rpl_stm_000001.test @@ -1,6 +1,11 @@ --- source include/have_binlog_format_mixed_or_statement.inc +# Requires binlog_format=statement format since query involving +# get_lock() is logged in row format if binlog_format=mixed or row. +-- source include/have_binlog_format_statement.inc -- source include/master-slave.inc +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); + +# Load some data into t1 create table t1 (word char(20) not null); load data infile '../../std_data/words.dat' into table t1; --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR @@ -10,9 +15,7 @@ select * from t1 limit 10; # # Test slave with wrong password # -save_master_pos; -connection slave; -sync_with_master; +sync_slave_with_master; stop slave; connection master; set password for root@"localhost" = password('foo'); @@ -29,16 +32,12 @@ sleep 2; create table t3(n int); insert into t3 values(1),(2); -save_master_pos; -connection slave; -sync_with_master; +sync_slave_with_master; select * from t3; select sum(length(word)) from t1; connection master; drop table t1,t3; -save_master_pos; -connection slave; -sync_with_master; +sync_slave_with_master; # Test if the slave SQL thread can be more than 16K behind the slave # I/O thread (> IO_SIZE) @@ -77,12 +76,13 @@ unlock tables; connection master; create table t2(id int); insert into t2 values(connection_id()); -save_master_pos; connection master1; # Avoid generating result create temporary table t3(n int); +--disable_warnings insert into t3 select get_lock('crash_lock%20C', 1) from t2; +--enable_warnings connection master; send update t1 set n = n + get_lock('crash_lock%20C', 2); @@ -93,8 +93,11 @@ kill @id; # We don't drop t3 as this is a temporary table drop table t2; connection master; +# The get_lock function causes warning for unsafe statement. +--disable_warnings --error 1317,2013 reap; +--enable_warnings connection slave; # The SQL slave thread should now have stopped because the query was killed on # the master (so it has a non-zero error code in the binlog). @@ -117,16 +120,12 @@ insert into mysql.user (Host, User, Password) select select_priv,user from mysql.user where user = _binary'blafasel2'; update mysql.user set Select_priv = "Y" where User= _binary"blafasel2"; select select_priv,user from mysql.user where user = _binary'blafasel2'; -save_master_pos; -connection slave; -sync_with_master; +sync_slave_with_master; select n from t1; select select_priv,user from mysql.user where user = _binary'blafasel2'; connection master1; drop table t1; delete from mysql.user where user="blafasel2"; -save_master_pos; -connection slave; -sync_with_master; +sync_slave_with_master; # End of 4.1 tests diff --git a/mysql-test/extra/rpl_tests/type_conversions.test b/mysql-test/extra/rpl_tests/type_conversions.test new file mode 100644 index 00000000000..2be1f6c0bec --- /dev/null +++ b/mysql-test/extra/rpl_tests/type_conversions.test @@ -0,0 +1,710 @@ +# File containing different lossy and non-lossy type conversions. + +# Integral conversion testing, we do not reduce the test using +# transitivity of conversions since the implementation is not using a +# transitivity strategy. Instead we do an exhaustive testing. + +disable_query_log; +connection slave; +--let $conv = `select @@slave_type_conversions` +--echo **** Running tests with @@SLAVE_TYPE_CONVERSIONS = '$conv' **** + +let $if_is_lossy = `SELECT FIND_IN_SET('ALL_LOSSY', @@SLAVE_TYPE_CONVERSIONS)`; +let $if_is_non_lossy = `SELECT FIND_IN_SET('ALL_NON_LOSSY', @@SLAVE_TYPE_CONVERSIONS)`; + +let $source_type = BIT(1); +let $target_type = BIT(1); +let $source_value = b'1'; +let $target_value = b'1'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type = DATE; +let $target_type = DATE; +let $source_value = '2009-11-21'; +let $target_value = '2009-11-21'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type = ENUM('master','slave'); +let $target_type = ENUM('master','slave'); +let $source_value = 'master'; +let $target_value = 'master'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type = CHAR(10); +let $target_type = ENUM('master','slave'); +let $source_value = 'master'; +let $target_value = 'master'; +let $can_convert = 0; +source extra/rpl_tests/check_type.inc; + +let $source_type = CHAR(10); +let $target_type = SET('master','slave'); +let $source_value = 'master'; +let $target_value = 'master'; +let $can_convert = 0; +source extra/rpl_tests/check_type.inc; + +let $source_type = ENUM('master','slave'); +let $target_type = CHAR(10); +let $source_value = 'master'; +let $target_value = 'master'; +let $can_convert = 0; +source extra/rpl_tests/check_type.inc; + +let $source_type = SET('master','slave'); +let $target_type = CHAR(10); +let $source_value = 'master'; +let $target_value = 'master'; +let $can_convert = 0; +source extra/rpl_tests/check_type.inc; + +let $source_type = SET('master','slave'); +let $target_type = SET('master','slave'); +let $source_value = ''; +let $target_value = ''; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type = SET('master','slave'); +let $target_type = SET('master','slave'); +let $source_value = 'master,slave'; +let $target_value = 'master,slave'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type = TINYINT; +let $target_type = TINYINT; +let $source_value = 1; +let $target_value = 1; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type = TINYINT; +let $target_type = SMALLINT; +let $source_value = 1; +let $target_value = 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TINYINT; +let $target_type= MEDIUMINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TINYINT; +let $target_type= INT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TINYINT; +let $target_type= BIGINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= SMALLINT; +let $target_type= TINYINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= SMALLINT; +let $target_type= TINYINT; +let $source_value= 1 << 9; +let $target_value= (1 << 7) - 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= SMALLINT; +let $target_type= TINYINT UNSIGNED; +let $source_value= 1 << 9; +let $target_value= (1 << 8) - 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= SMALLINT; +let $target_type= SMALLINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= SMALLINT; +let $target_type= MEDIUMINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= SMALLINT; +let $target_type= INT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= SMALLINT; +let $target_type= BIGINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMINT; +let $target_type= TINYINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMINT; +let $target_type= TINYINT; +let $source_value= 1 << 20; +let $target_value= (1 << 7) - 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMINT; +let $target_type= TINYINT UNSIGNED; +let $source_value= 1 << 20; +let $target_value= (1 << 8) - 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMINT; +let $target_type= SMALLINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMINT; +let $target_type= MEDIUMINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMINT; +let $target_type= INT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMINT; +let $target_type= BIGINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= INT; +let $target_type= TINYINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= INT; +let $target_type= TINYINT; +let $source_value= (1 << 30); +let $target_value= (1 << 7) - 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= INT; +let $target_type= TINYINT UNSIGNED; +let $source_value= (1 << 30); +let $target_value= (1 << 8) - 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= INT; +let $target_type= SMALLINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= INT; +let $target_type= MEDIUMINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= INT; +let $target_type= INT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= INT; +let $target_type= BIGINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIGINT; +let $target_type= TINYINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIGINT; +let $target_type= SMALLINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIGINT; +let $target_type= MEDIUMINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIGINT; +let $target_type= INT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIGINT; +let $target_type= BIGINT; +let $source_value= 1; +let $target_value= 1; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= CHAR(20); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= CHAR(30); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= CHAR(10); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnood'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= VARCHAR(20); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= VARCHAR(30); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= VARCHAR(10); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnood'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= TINYTEXT; +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= TEXT; +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= MEDIUMTEXT; +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= CHAR(20); +let $target_type= LONGTEXT; +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= VARCHAR(20); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= VARCHAR(30); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= VARCHAR(10); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnood'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= CHAR(30); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= CHAR(10); +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnood'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= TINYTEXT; +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= TEXT; +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= MEDIUMTEXT; +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(20); +let $target_type= LONGTEXT; +let $source_value= 'Smoothnoodlemaps'; +let $target_value= 'Smoothnoodlemaps'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $blob = `select repeat('abcd', 125)`; +let $truncated_blob = `select left('$blob', 255)`; + +let $source_type= VARCHAR(500); +let $target_type= VARCHAR(500); +let $source_value= '$blob'; +let $target_value= '$blob'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(500); +let $target_type= VARCHAR(510); +let $source_value= '$blob'; +let $target_value= '$blob'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(500); +let $target_type= VARCHAR(255); +let $source_value= '$blob'; +let $target_value= '$truncated_blob'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(500); +let $target_type= TINYTEXT; +let $source_value= '$blob'; +let $target_value= '$truncated_blob'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(500); +let $target_type= TEXT; +let $source_value= '$blob'; +let $target_value= '$blob'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(500); +let $target_type= MEDIUMTEXT; +let $source_value= '$blob'; +let $target_value= '$blob'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= VARCHAR(500); +let $target_type= LONGTEXT; +let $source_value= '$blob'; +let $target_value= '$blob'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $tiny_blob = `select repeat('tiny blob ', 25)`; +let $truncated_tiny_blob = `select left('$tiny_blob', 254)`; + +let $source_type= TINYTEXT; +let $target_type= VARCHAR(500); +let $source_value= '$tiny_blob'; +let $target_value= '$tiny_blob'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TEXT; +let $target_type= VARCHAR(500); +let $source_value= '$blob'; +let $target_value= '$blob'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMTEXT; +let $target_type= VARCHAR(500); +let $source_value= '$blob'; +let $target_value= '$blob'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= LONGTEXT; +let $target_type= VARCHAR(500); +let $source_value= '$blob'; +let $target_value= '$blob'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TINYTEXT; +let $target_type= CHAR(255); +let $source_value= '$tiny_blob'; +let $target_value= '$tiny_blob'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TINYTEXT; +let $target_type= CHAR(250); +let $source_value= '$tiny_blob'; +let $target_value= left('$tiny_blob', 250); +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TEXT; +let $target_type= CHAR(255); +let $source_value= '$blob'; +let $target_value= left('$blob', 255); +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= MEDIUMTEXT; +let $target_type= CHAR(255); +let $source_value= '$blob'; +let $target_value= left('$blob', 255); +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= LONGTEXT; +let $target_type= CHAR(255); +let $source_value= '$blob'; +let $target_value= left('$blob', 255); +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TINYTEXT; +let $target_type= TINYTEXT; +let $source_value= '$tiny_blob'; +let $target_value= '$tiny_blob'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= TINYTEXT; +let $target_type= TEXT; +let $source_value= '$tiny_blob'; +let $target_value= '$tiny_blob'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= TEXT; +let $target_type= TINYTEXT; +let $source_value= '$blob'; +let $target_value= left('$blob',255); +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= DECIMAL(10,5); +let $source_value= 3.14159; +let $target_value= 3.14159; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= DECIMAL(10,6); +let $source_value= 3.14159; +let $target_value= 3.141590; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= DECIMAL(11,5); +let $source_value= 3.14159; +let $target_value= 3.14159; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= DECIMAL(11,6); +let $source_value= 3.14159; +let $target_value= 3.141590; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= DECIMAL(10,4); +let $source_value= 3.14159; +let $target_value= 3.1416; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= DECIMAL(9,5); +let $source_value= 3.14159; +let $target_value= 3.14159; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= DECIMAL(9,4); +let $source_value= 3.14159; +let $target_value= 3.1416; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= FLOAT; +let $target_type= DECIMAL(10,5); +let $source_value= 3.15625; +let $target_value= 3.15625; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DOUBLE; +let $target_type= DECIMAL(10,5); +let $source_value= 3.15625; +let $target_value= 3.15625; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= FLOAT; +let $source_value= 3.15625; +let $target_value= 3.15625; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DECIMAL(10,5); +let $target_type= DOUBLE; +let $source_value= 3.15625; +let $target_value= 3.15625; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= FLOAT; +let $target_type= FLOAT; +let $source_value= 3.15625; +let $target_value= 3.15625; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= DOUBLE; +let $target_type= DOUBLE; +let $source_value= 3.15625; +let $target_value= 3.15625; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= FLOAT; +let $target_type= DOUBLE; +let $source_value= 3.15625; +let $target_value= 3.15625; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= DOUBLE; +let $target_type= FLOAT; +let $source_value= 3.15625; +let $target_value= 3.15625; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIT(5); +let $target_type= BIT(5); +let $source_value= b'11001'; +let $target_value= b'11001'; +let $can_convert = 1; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIT(5); +let $target_type= BIT(6); +let $source_value= b'11001'; +let $target_value= b'11001'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIT(6); +let $target_type= BIT(5); +let $source_value= b'111001'; +let $target_value= b'11111'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIT(5); +let $target_type= BIT(12); +let $source_value= b'11001'; +let $target_value= b'11001'; +let $can_convert = $if_is_non_lossy; +source extra/rpl_tests/check_type.inc; + +let $source_type= BIT(12); +let $target_type= BIT(5); +let $source_value= b'101100111000'; +let $target_value= b'11111'; +let $can_convert = $if_is_lossy; +source extra/rpl_tests/check_type.inc; + +disable_warnings; +source include/reset_master_and_slave.inc; +enable_warnings; +enable_query_log;
\ No newline at end of file diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index 57e7cb97d48..b2cc86fbd46 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -175,6 +175,15 @@ INSERT INTO global_suppressions VALUES ("Can't find file: '.\\\\test\\\\\\?{8}.frm'"), ("Slave: Unknown table 't1' Error_code: 1051"), + /* + Transient network failures that cause warnings on reconnect. + BUG#47743 and BUG#47983. + */ + ("Slave I/O: Get master SERVER_ID failed with error:.*"), + ("Slave I/O: Get master clock failed with error:.*"), + ("Slave I/O: Get master COLLATION_SERVER failed with error:.*"), + ("Slave I/O: Get master TIME_ZONE failed with error:.*"), + ("THE_LAST_SUPPRESSION")|| diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index bf73b45ecdf..ef3c2a43e87 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -520,6 +520,10 @@ sub collect_one_suite($) next if ($test->{'name'} eq 'sys_vars.innodb_thread_concurrency_basic'); # Can't work with InnoPlug. Test framework needs to be re-designed. next if ($test->{'name'} eq 'main.innodb_bug46000'); + # Fails with innodb plugin + next if ($test->{'name'} eq 'main.innodb-autoinc'); + # Fails with innodb plugin: r6185 Testcases changes not included + next if ($test->{'name'} eq 'main.innodb_bug44369'); # Copy test options my $new_test= My::Test->new(); while (my ($key, $value) = each(%$test)) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index e865d775c6a..c620eb97cab 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -12717,3 +12717,14 @@ COUNT(t1.a) 729 DROP TABLE t1; SET @@join_buffer_size= @save_join_buffer_size; +SHOW CREATE TABLE t1; +ERROR HY000: Table upgrade required. Please do "REPAIR TABLE `t1`" or dump/reload to fix it! +SELECT * FROM t1; +ERROR HY000: Table upgrade required. Please do "REPAIR TABLE `t1`" or dump/reload to fix it! +INSERT INTO t1 (col1, col2) VALUES (1, "value"); +ERROR HY000: Table upgrade required. Please do "REPAIR TABLE `t1`" or dump/reload to fix it! +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair Error Table upgrade required. Please do "REPAIR TABLE `t1`" or dump/reload to fix it! +test.t1 repair error Corrupt +DROP TABLE t1; diff --git a/mysql-test/r/bug47671.result b/mysql-test/r/bug47671.result new file mode 100644 index 00000000000..2cff6f1b59c --- /dev/null +++ b/mysql-test/r/bug47671.result @@ -0,0 +1,13 @@ +# +# Bug#47671 - wrong character-set after upgrade from 5.1.34 to 5.1.39 +# +# Extract only charset information from 'status' command output using regex +-------------- + +Server characterset: utf8 +Db characterset: utf8 +Client characterset: utf8 +Conn. characterset: utf8 + +-------------- + diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index 4d5d656f3ce..d8048a703a2 100644 --- a/mysql-test/r/delayed.result +++ b/mysql-test/r/delayed.result @@ -310,4 +310,16 @@ a b 2 2 drop table t1; set global low_priority_updates = @old_delayed_updates; +# +# Bug #47682 strange behaviour of INSERT DELAYED +# +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (f1 integer); +CREATE TABLE t2 (f1 integer); +FLUSH TABLES WITH READ LOCK; +LOCK TABLES t1 READ; +INSERT DELAYED INTO t2 VALUES (1); +Got one of the listed errors +UNLOCK TABLES; +DROP TABLE t1, t2; End of 5.1 tests diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index 0124a7da35a..1df19a75854 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -324,3 +324,16 @@ a 1 2 DROP TABLE t1, t2, t3; +# +# Bug #46425 crash in Diagnostics_area::set_ok_status, +# empty statement, DELETE IGNORE +# +CREATE table t1 (i INTEGER); +INSERT INTO t1 VALUES (1); +CREATE TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW +BEGIN +INSERT INTO t1 SELECT * FROM t1 AS A; +END | +DELETE IGNORE FROM t1; +ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. +DROP TABLE t1; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index a5216189d9a..6022231907b 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -551,3 +551,42 @@ EXECUTE s; MATCH (col) AGAINST('findme') DEALLOCATE PREPARE s; DROP TABLE t1; +# +# Bug #47930: MATCH IN BOOLEAN MODE returns too many results +# inside subquery +# +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 (a int, b2 char(10), FULLTEXT KEY b2 (b2)); +INSERT INTO t2 VALUES (1,'Scargill'); +CREATE TABLE t3 (a int, b int); +INSERT INTO t3 VALUES (1,1), (2,1); +# t2 should use full text index +EXPLAIN +SELECT count(*) FROM t1 WHERE +not exists( +SELECT 1 FROM t2, t3 +WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) +); +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 t2 fulltext b2 b2 0 1 Using where +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +# should return 0 +SELECT count(*) FROM t1 WHERE +not exists( +SELECT 1 FROM t2, t3 +WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) +); +count(*) +0 +# should return 0 +SELECT count(*) FROM t1 WHERE +not exists( +SELECT 1 FROM t2 IGNORE INDEX (b2), t3 +WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) +); +count(*) +0 +DROP TABLE t1,t2,t3; +End of 5.1 tests diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 94147640cde..b36f561578b 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -885,7 +885,7 @@ cast(sum(distinct df) as signed) 3 select cast(min(df) as signed) from t1; cast(min(df) as signed) -0 +1 select 1e8 * sum(distinct df) from t1; 1e8 * sum(distinct df) 330000000 @@ -1520,4 +1520,197 @@ max i # Cleanup # DROP TABLE t1; +# +# Bug#43668: Wrong comparison and MIN/MAX for YEAR(2) +# +create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime); +insert into t1 values +(98,1998,19980101,"1998-01-01 00:00:00"), +(00,2000,20000101,"2000-01-01 00:00:01"), +(02,2002,20020101,"2002-01-01 23:59:59"), +(60,2060,20600101,"2060-01-01 11:11:11"), +(70,1970,19700101,"1970-11-11 22:22:22"), +(NULL,NULL,NULL,NULL); +select min(f1),max(f1) from t1; +min(f1) max(f1) +70 60 +select min(f2),max(f2) from t1; +min(f2) max(f2) +1970 2060 +select min(f3),max(f3) from t1; +min(f3) max(f3) +1970-01-01 2060-01-01 +select min(f4),max(f4) from t1; +min(f4) max(f4) +1970-11-11 22:22:22 2060-01-01 11:11:11 +select a.f1 as a, b.f1 as b, a.f1 > b.f1 as gt, +a.f1 < b.f1 as lt, a.f1<=>b.f1 as eq +from t1 a, t1 b; +a b gt lt eq +98 98 0 0 1 +00 98 1 0 0 +02 98 1 0 0 +60 98 1 0 0 +70 98 0 1 0 +NULL 98 NULL NULL 0 +98 00 0 1 0 +00 00 0 0 1 +02 00 1 0 0 +60 00 1 0 0 +70 00 0 1 0 +NULL 00 NULL NULL 0 +98 02 0 1 0 +00 02 0 1 0 +02 02 0 0 1 +60 02 1 0 0 +70 02 0 1 0 +NULL 02 NULL NULL 0 +98 60 0 1 0 +00 60 0 1 0 +02 60 0 1 0 +60 60 0 0 1 +70 60 0 1 0 +NULL 60 NULL NULL 0 +98 70 1 0 0 +00 70 1 0 0 +02 70 1 0 0 +60 70 1 0 0 +70 70 0 0 1 +NULL 70 NULL NULL 0 +98 NULL NULL NULL 0 +00 NULL NULL NULL 0 +02 NULL NULL NULL 0 +60 NULL NULL NULL 0 +70 NULL NULL NULL 0 +NULL NULL NULL NULL 1 +select a.f1 as a, b.f2 as b, a.f1 > b.f2 as gt, +a.f1 < b.f2 as lt, a.f1<=>b.f2 as eq +from t1 a, t1 b; +a b gt lt eq +98 1998 0 0 1 +00 1998 1 0 0 +02 1998 1 0 0 +60 1998 1 0 0 +70 1998 0 1 0 +NULL 1998 NULL NULL 0 +98 2000 0 1 0 +00 2000 0 0 1 +02 2000 1 0 0 +60 2000 1 0 0 +70 2000 0 1 0 +NULL 2000 NULL NULL 0 +98 2002 0 1 0 +00 2002 0 1 0 +02 2002 0 0 1 +60 2002 1 0 0 +70 2002 0 1 0 +NULL 2002 NULL NULL 0 +98 2060 0 1 0 +00 2060 0 1 0 +02 2060 0 1 0 +60 2060 0 0 1 +70 2060 0 1 0 +NULL 2060 NULL NULL 0 +98 1970 1 0 0 +00 1970 1 0 0 +02 1970 1 0 0 +60 1970 1 0 0 +70 1970 0 0 1 +NULL 1970 NULL NULL 0 +98 NULL NULL NULL 0 +00 NULL NULL NULL 0 +02 NULL NULL NULL 0 +60 NULL NULL NULL 0 +70 NULL NULL NULL 0 +NULL NULL NULL NULL 1 +select a.f1 as a, b.f3 as b, a.f1 > b.f3 as gt, +a.f1 < b.f3 as lt, a.f1<=>b.f3 as eq +from t1 a, t1 b; +a b gt lt eq +98 1998-01-01 0 1 0 +00 1998-01-01 1 0 0 +02 1998-01-01 1 0 0 +60 1998-01-01 1 0 0 +70 1998-01-01 0 1 0 +NULL 1998-01-01 NULL NULL 0 +98 2000-01-01 0 1 0 +00 2000-01-01 0 1 0 +02 2000-01-01 1 0 0 +60 2000-01-01 1 0 0 +70 2000-01-01 0 1 0 +NULL 2000-01-01 NULL NULL 0 +98 2002-01-01 0 1 0 +00 2002-01-01 0 1 0 +02 2002-01-01 0 1 0 +60 2002-01-01 1 0 0 +70 2002-01-01 0 1 0 +NULL 2002-01-01 NULL NULL 0 +98 2060-01-01 0 1 0 +00 2060-01-01 0 1 0 +02 2060-01-01 0 1 0 +60 2060-01-01 0 1 0 +70 2060-01-01 0 1 0 +NULL 2060-01-01 NULL NULL 0 +98 1970-01-01 1 0 0 +00 1970-01-01 1 0 0 +02 1970-01-01 1 0 0 +60 1970-01-01 1 0 0 +70 1970-01-01 0 1 0 +NULL 1970-01-01 NULL NULL 0 +98 NULL NULL NULL 0 +00 NULL NULL NULL 0 +02 NULL NULL NULL 0 +60 NULL NULL NULL 0 +70 NULL NULL NULL 0 +NULL NULL NULL NULL 1 +select a.f1 as a, b.f4 as b, a.f1 > b.f4 as gt, +a.f1 < b.f4 as lt, a.f1<=>b.f4 as eq +from t1 a, t1 b; +a b gt lt eq +98 1998-01-01 00:00:00 0 1 0 +00 1998-01-01 00:00:00 1 0 0 +02 1998-01-01 00:00:00 1 0 0 +60 1998-01-01 00:00:00 1 0 0 +70 1998-01-01 00:00:00 0 1 0 +NULL 1998-01-01 00:00:00 NULL NULL 0 +98 2000-01-01 00:00:01 0 1 0 +00 2000-01-01 00:00:01 0 1 0 +02 2000-01-01 00:00:01 1 0 0 +60 2000-01-01 00:00:01 1 0 0 +70 2000-01-01 00:00:01 0 1 0 +NULL 2000-01-01 00:00:01 NULL NULL 0 +98 2002-01-01 23:59:59 0 1 0 +00 2002-01-01 23:59:59 0 1 0 +02 2002-01-01 23:59:59 0 1 0 +60 2002-01-01 23:59:59 1 0 0 +70 2002-01-01 23:59:59 0 1 0 +NULL 2002-01-01 23:59:59 NULL NULL 0 +98 2060-01-01 11:11:11 0 1 0 +00 2060-01-01 11:11:11 0 1 0 +02 2060-01-01 11:11:11 0 1 0 +60 2060-01-01 11:11:11 0 1 0 +70 2060-01-01 11:11:11 0 1 0 +NULL 2060-01-01 11:11:11 NULL NULL 0 +98 1970-11-11 22:22:22 1 0 0 +00 1970-11-11 22:22:22 1 0 0 +02 1970-11-11 22:22:22 1 0 0 +60 1970-11-11 22:22:22 1 0 0 +70 1970-11-11 22:22:22 0 1 0 +NULL 1970-11-11 22:22:22 NULL NULL 0 +98 NULL NULL NULL 0 +00 NULL NULL NULL 0 +02 NULL NULL NULL 0 +60 NULL NULL NULL 0 +70 NULL NULL NULL 0 +NULL NULL NULL NULL 1 +select *, f1 = f2 from t1; +f1 f2 f3 f4 f1 = f2 +98 1998 1998-01-01 1998-01-01 00:00:00 1 +00 2000 2000-01-01 2000-01-01 00:00:01 1 +02 2002 2002-01-01 2002-01-01 23:59:59 1 +60 2060 2060-01-01 2060-01-01 11:11:11 1 +70 1970 1970-01-01 1970-11-11 22:22:22 1 +NULL NULL NULL NULL NULL +drop table t1; +# End of 5.1 tests diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 461ad78bbb6..75d3d5819f4 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -443,3 +443,30 @@ DROP TABLE db1.t1, db1.t2; DROP USER mysqltest1@localhost; DROP DATABASE db1; End of 5.0 tests +USE mysql; +SELECT LEFT(CURRENT_USER(),INSTR(CURRENT_USER(),'@')-1) INTO @u; +SELECT MID(CURRENT_USER(),INSTR(CURRENT_USER(),'@')+1) INTO @h; +SELECT password FROM user WHERE user=@u AND host=@h INTO @pwd; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost Y +UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost N +GRANT INSERT ON *.* TO CURRENT_USER(); +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost Y +UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h; +GRANT INSERT ON *.* TO CURRENT_USER() IDENTIFIED BY 'keksdose'; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost *0BB7188CF0DE9B403BA66E9DD810D82652D002EB Y +UPDATE user SET password=@pwd WHERE user=@u AND host=@h; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +user host password insert_priv +root localhost Y +FLUSH PRIVILEGES; +USE test; +End of 5.1 tests diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 620f5dc19ec..662cc5be034 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2501,6 +2501,17 @@ SELECT a, MAX(b) FROM t WHERE b > 0 AND b < 2 GROUP BY a; a MAX(b) 2 1 DROP TABLE t; +# +# Bug #48472: Loose index scan inappropriately chosen for some WHERE +# conditions +# +CREATE TABLE t (a INT, b INT, INDEX (a,b)); +INSERT INTO t VALUES (2,0), (2,0), (2,1), (2,1); +INSERT INTO t SELECT * FROM t; +SELECT a, MAX(b) FROM t WHERE 0=b+0 GROUP BY a; +a MAX(b) +2 0 +DROP TABLE t; End of 5.0 tests # # Bug #46607: Assertion failed: (cond_type == Item::FUNC_ITEM) results in diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index a40a13dbe9f..2e0d2c1d776 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -875,11 +875,11 @@ ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; SELECT * FROM t1; d1 1 -3 +2 SELECT * FROM t1; d1 1 -3 +2 INSERT INTO t1 VALUES(null); Got one of the listed errors ALTER TABLE t1 AUTO_INCREMENT = 3; @@ -888,13 +888,13 @@ Table Create Table t1 CREATE TABLE `t1` ( `d1` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`d1`) -) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 INSERT INTO t1 VALUES(null); SELECT * FROM t1; d1 1 +2 3 -4 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SHOW VARIABLES LIKE "%auto_inc%"; @@ -1126,3 +1126,67 @@ SELECT * FROM T1; c1 c2 10 0 DROP TABLE T1; +DROP TABLE IF EXISTS T1; +Warnings: +Note 1051 Unknown table 'T1' +CREATE TABLE T1(C1 DOUBLE AUTO_INCREMENT KEY, C2 CHAR(10)) ENGINE=InnoDB; +INSERT INTO T1(C1, C2) VALUES (1, 'innodb'), (3, 'innodb'); +INSERT INTO T1(C2) VALUES ('innodb'); +SHOW CREATE TABLE T1; +Table Create Table +T1 CREATE TABLE `T1` ( + `C1` double NOT NULL AUTO_INCREMENT, + `C2` char(10) DEFAULT NULL, + PRIMARY KEY (`C1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +DROP TABLE T1; +CREATE TABLE T1(C1 FLOAT AUTO_INCREMENT KEY, C2 CHAR(10)) ENGINE=InnoDB; +INSERT INTO T1(C1, C2) VALUES (1, 'innodb'), (3, 'innodb'); +INSERT INTO T1(C2) VALUES ('innodb'); +SHOW CREATE TABLE T1; +Table Create Table +T1 CREATE TABLE `T1` ( + `C1` float NOT NULL AUTO_INCREMENT, + `C2` char(10) DEFAULT NULL, + PRIMARY KEY (`C1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +DROP TABLE T1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 (c1 INT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 SET c1 = 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 +INSERT INTO t1 SET c1 = 2; +INSERT INTO t1 SET c1 = -1; +SELECT * FROM t1; +c1 +-1 +1 +2 +INSERT INTO t1 SET c1 = -1; +Got one of the listed errors +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +REPLACE INTO t1 VALUES (-1); +SELECT * FROM t1; +c1 +-1 +1 +2 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/r/innodb_lock_wait_timeout_1.result b/mysql-test/r/innodb_lock_wait_timeout_1.result index a635b0d527a..bd8760b8f79 100644 --- a/mysql-test/r/innodb_lock_wait_timeout_1.result +++ b/mysql-test/r/innodb_lock_wait_timeout_1.result @@ -48,6 +48,24 @@ commit; set autocommit=default; drop table t1; # +# Bug #37183 insert ignore into .. select ... hangs +# after deadlock was encountered +# +create table t1(id int primary key,v int)engine=innodb; +insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +create table t2 like t1; +begin; +update t1 set v=id*2 where id=1; +begin; +update t1 set v=id*2 where id=2; +update t1 set v=id*2 where id=2; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +insert ignore into t2 select * from t1 where id=1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +rollback; +drop table t1, t2; +# # Bug#41756 Strange error messages about locks from InnoDB # drop table if exists t1; diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index c882d2af1ed..402ab3c1b16 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -2251,4 +2251,26 @@ c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; 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; +# +# Bug #46175: NULL read_view and consistent read assertion +# +CREATE TABLE t1(a CHAR(13),KEY(a)) ENGINE=innodb; +CREATE TABLE t2(b DATETIME,KEY(b)) ENGINE=innodb; +INSERT INTO t1 VALUES (),(); +INSERT INTO t2 VALUES (),(); +CREATE OR REPLACE VIEW v1 AS SELECT 1 FROM t2 +WHERE b =(SELECT a FROM t1 LIMIT 1); +CREATE PROCEDURE p1(num INT) +BEGIN +DECLARE i INT DEFAULT 0; +REPEAT +SHOW CREATE VIEW v1; +SET i:=i+1; +UNTIL i>num END REPEAT; +END| +# Should not crash +# Should not crash +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1,t2; End of 5.1 tests diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index c02073df677..5c6a0e2f93d 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -229,5 +229,4 @@ a: b </row> </resultset> drop table t1; - -End of tests +End of 5.0 tests diff --git a/mysql-test/r/mysqlbinlog_row_innodb.result b/mysql-test/r/mysqlbinlog_row_innodb.result index 86f0b67ebb3..f11cc3221ad 100644 --- a/mysql-test/r/mysqlbinlog_row_innodb.result +++ b/mysql-test/r/mysqlbinlog_row_innodb.result @@ -2365,7 +2365,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Write_rows: table id # flags: STMT_END_F ### INSERT INTO test.t1 ### SET -### @1=b'00000000' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'0' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'0000000000000000000000000000000000000000000000000000000000000000' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=-128 (128) /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -2458,7 +2458,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Write_rows: table id # flags: STMT_END_F ### INSERT INTO test.t1 ### SET -### @1=b'00000001' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'1111111111111111111111111111111111111111111111111111111111111111' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=127 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=-1 (255) /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -2553,7 +2553,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Write_rows: table id # flags: STMT_END_F ### INSERT INTO test.t1 ### SET -### @1=NULL /* type=16 meta=256 nullable=1 is_null=1 */ +### @1=NULL /* type=16 meta=1 nullable=1 is_null=1 */ ### @2=NULL /* type=16 meta=2048 nullable=1 is_null=1 */ ### @3=NULL /* type=1 meta=0 nullable=1 is_null=1 */ ### @4=NULL /* type=1 meta=0 nullable=1 is_null=1 */ @@ -2580,7 +2580,7 @@ BEGIN ### @25=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @26=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @27=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ -### @28=NULL /* type=10 meta=0 nullable=1 is_null=1 */ +### @28=NULL /* type=14 meta=0 nullable=1 is_null=1 */ ### @29=NULL /* type=12 meta=0 nullable=1 is_null=1 */ ### @30=1000000000 /* TIMESTAMP meta=0 nullable=0 is_null=0 */ ### @31=NULL /* TIMESTAMP meta=0 nullable=1 is_null=1 */ @@ -2634,7 +2634,7 @@ BEGIN ### @79=3 /* INT meta=0 nullable=1 is_null=0 */ ### INSERT INTO test.t1 ### SET -### @1=b'00000001' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'1111111111111111111111111111111111111111111111111111111111111111' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=127 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -2727,7 +2727,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Update_rows: table id # flags: STMT_END_F ### UPDATE test.t1 ### WHERE -### @1=b'00000000' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'0' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'0000000000000000000000000000000000000000000000000000000000000000' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=-128 (128) /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -2807,7 +2807,7 @@ BEGIN ### @78=b'00000000' /* SET(1 bytes) meta=63489 nullable=1 is_null=0 */ ### @79=1 /* INT meta=0 nullable=1 is_null=0 */ ### SET -### @1=b'00000001' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'1111111111111111111111111111111111111111111111111111111111111111' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=127 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=-1 (255) /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -2900,7 +2900,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Update_rows: table id # flags: STMT_END_F ### UPDATE test.t1 ### WHERE -### @1=b'00000001' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'1111111111111111111111111111111111111111111111111111111111111111' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=127 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=-1 (255) /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -2980,7 +2980,7 @@ BEGIN ### @78=b'00000111' /* SET(1 bytes) meta=63489 nullable=1 is_null=0 */ ### @79=2 /* INT meta=0 nullable=1 is_null=0 */ ### SET -### @1=b'00000000' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'0' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'0000000000000000000000000000000000000000000000000000000000000000' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=-128 (128) /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -3073,7 +3073,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Update_rows: table id # flags: STMT_END_F ### UPDATE test.t1 ### WHERE -### @1=NULL /* type=16 meta=256 nullable=1 is_null=1 */ +### @1=NULL /* type=16 meta=1 nullable=1 is_null=1 */ ### @2=NULL /* type=16 meta=2048 nullable=1 is_null=1 */ ### @3=NULL /* type=1 meta=0 nullable=1 is_null=1 */ ### @4=NULL /* type=1 meta=0 nullable=1 is_null=1 */ @@ -3100,7 +3100,7 @@ BEGIN ### @25=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @26=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @27=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ -### @28=NULL /* type=10 meta=0 nullable=1 is_null=1 */ +### @28=NULL /* type=14 meta=0 nullable=1 is_null=1 */ ### @29=NULL /* type=12 meta=0 nullable=1 is_null=1 */ ### @30=1000000000 /* TIMESTAMP meta=0 nullable=0 is_null=0 */ ### @31=NULL /* TIMESTAMP meta=0 nullable=1 is_null=1 */ @@ -3153,7 +3153,7 @@ BEGIN ### @78=NULL /* TIMESTAMP meta=63489 nullable=1 is_null=1 */ ### @79=3 /* INT meta=0 nullable=1 is_null=0 */ ### SET -### @1=b'00000001' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'1111111111111111111111111111111111111111111111111111111111111111' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=127 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -3246,7 +3246,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Update_rows: table id # flags: STMT_END_F ### UPDATE test.t1 ### WHERE -### @1=b'00000001' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'1111111111111111111111111111111111111111111111111111111111111111' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=127 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -3326,7 +3326,7 @@ BEGIN ### @78=b'00000110' /* SET(1 bytes) meta=63489 nullable=1 is_null=0 */ ### @79=4 /* INT meta=0 nullable=1 is_null=0 */ ### SET -### @1=NULL /* type=16 meta=256 nullable=1 is_null=1 */ +### @1=NULL /* type=16 meta=1 nullable=1 is_null=1 */ ### @2=NULL /* type=16 meta=2048 nullable=1 is_null=1 */ ### @3=NULL /* type=1 meta=0 nullable=1 is_null=1 */ ### @4=NULL /* type=1 meta=0 nullable=1 is_null=1 */ @@ -3353,7 +3353,7 @@ BEGIN ### @25=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @26=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @27=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ -### @28=NULL /* type=10 meta=0 nullable=1 is_null=1 */ +### @28=NULL /* type=14 meta=0 nullable=1 is_null=1 */ ### @29=NULL /* type=12 meta=0 nullable=1 is_null=1 */ ### @30=1000000000 /* TIMESTAMP meta=0 nullable=0 is_null=0 */ ### @31=NULL /* TIMESTAMP meta=0 nullable=1 is_null=1 */ @@ -3419,7 +3419,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Delete_rows: table id # flags: STMT_END_F ### DELETE FROM test.t1 ### WHERE -### @1=b'00000001' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'1111111111111111111111111111111111111111111111111111111111111111' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=127 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=-1 (255) /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -3512,7 +3512,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Delete_rows: table id # flags: STMT_END_F ### DELETE FROM test.t1 ### WHERE -### @1=b'00000000' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'0' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'0000000000000000000000000000000000000000000000000000000000000000' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=-128 (128) /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -3605,7 +3605,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Delete_rows: table id # flags: STMT_END_F ### DELETE FROM test.t1 ### WHERE -### @1=b'00000001' /* BIT(8) meta=256 nullable=1 is_null=0 */ +### @1=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @2=b'1111111111111111111111111111111111111111111111111111111111111111' /* BIT(64) meta=2048 nullable=1 is_null=0 */ ### @3=127 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* TINYINT meta=0 nullable=1 is_null=0 */ @@ -3698,7 +3698,7 @@ BEGIN #010909 4:46:40 server id 1 end_log_pos # Delete_rows: table id # flags: STMT_END_F ### DELETE FROM test.t1 ### WHERE -### @1=NULL /* type=16 meta=256 nullable=1 is_null=1 */ +### @1=NULL /* type=16 meta=1 nullable=1 is_null=1 */ ### @2=NULL /* type=16 meta=2048 nullable=1 is_null=1 */ ### @3=NULL /* type=1 meta=0 nullable=1 is_null=1 */ ### @4=NULL /* type=1 meta=0 nullable=1 is_null=1 */ @@ -3725,7 +3725,7 @@ BEGIN ### @25=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @26=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @27=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ -### @28=NULL /* type=10 meta=0 nullable=1 is_null=1 */ +### @28=NULL /* type=14 meta=0 nullable=1 is_null=1 */ ### @29=NULL /* type=12 meta=0 nullable=1 is_null=1 */ ### @30=1000000000 /* TIMESTAMP meta=0 nullable=0 is_null=0 */ ### @31=NULL /* TIMESTAMP meta=0 nullable=1 is_null=1 */ diff --git a/mysql-test/r/mysqlbinlog_row_myisam.result b/mysql-test/r/mysqlbinlog_row_myisam.result index b9366d941f8..4d1050af916 100644 --- a/mysql-test/r/mysqlbinlog_row_myisam.result +++ b/mysql-test/r/mysqlbinlog_row_myisam.result @@ -2584,7 +2584,7 @@ BEGIN ### @25=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @26=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @27=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ -### @28=NULL /* type=10 meta=0 nullable=1 is_null=1 */ +### @28=NULL /* type=14 meta=0 nullable=1 is_null=1 */ ### @29=NULL /* type=12 meta=0 nullable=1 is_null=1 */ ### @30=1000000000 /* TIMESTAMP meta=0 nullable=0 is_null=0 */ ### @31=NULL /* TIMESTAMP meta=0 nullable=1 is_null=1 */ @@ -3110,7 +3110,7 @@ BEGIN ### @25=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @26=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @27=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ -### @28=NULL /* type=10 meta=0 nullable=1 is_null=1 */ +### @28=NULL /* type=14 meta=0 nullable=1 is_null=1 */ ### @29=NULL /* type=12 meta=0 nullable=1 is_null=1 */ ### @30=1000000000 /* TIMESTAMP meta=0 nullable=0 is_null=0 */ ### @31=NULL /* TIMESTAMP meta=0 nullable=1 is_null=1 */ @@ -3365,7 +3365,7 @@ BEGIN ### @25=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @26=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @27=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ -### @28=NULL /* type=10 meta=0 nullable=1 is_null=1 */ +### @28=NULL /* type=14 meta=0 nullable=1 is_null=1 */ ### @29=NULL /* type=12 meta=0 nullable=1 is_null=1 */ ### @30=1000000000 /* TIMESTAMP meta=0 nullable=0 is_null=0 */ ### @31=NULL /* TIMESTAMP meta=0 nullable=1 is_null=1 */ @@ -3745,7 +3745,7 @@ BEGIN ### @25=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @26=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ ### @27=NULL /* type=246 meta=2560 nullable=1 is_null=1 */ -### @28=NULL /* type=10 meta=0 nullable=1 is_null=1 */ +### @28=NULL /* type=14 meta=0 nullable=1 is_null=1 */ ### @29=NULL /* type=12 meta=0 nullable=1 is_null=1 */ ### @30=1000000000 /* TIMESTAMP meta=0 nullable=0 is_null=0 */ ### @31=NULL /* TIMESTAMP meta=0 nullable=1 is_null=1 */ diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index a7516d97888..8fb6f787795 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -753,4 +753,16 @@ b 100 NULL DROP TABLE t1, t2; +# +# Bug #48475: DISTINCT is ignored with GROUP BY WITH ROLLUP +# and only const tables +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP; +b +1 +NULL +DROP TABLE t1, t2; End of 5.0 tests diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 0c72f816c21..4add29a446f 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1444,6 +1444,27 @@ FROM t3; 2 NULL DROP TABLE t1, t2, t3; +# +# Bug #42760: Select doesn't return desired results when we have null +# values +# +CREATE TABLE t1 ( +a INT, +c INT, +UNIQUE KEY a_c (a,c), +KEY (a)); +INSERT INTO t1 VALUES (1, 10), (2, NULL); +# Must use ref-or-null on the a_c index +EXPLAIN +SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a_c,a a_c 10 const,const 1 Using where +# Must return 1 row +SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c; +col +1 +DROP TABLE t1; +End of 5.0 tests CREATE TABLE t2 (a varchar(32), b int(11), c float, d double, UNIQUE KEY a (a,b,c), KEY b (b), KEY c (c)); CREATE TABLE t1 (a varchar(32), b char(3), UNIQUE KEY a (a,b), KEY b (b)); diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 6611d39628f..7e14a0ea7c8 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1,4 +1,10 @@ drop table if exists t1, t2; +CREATE TABLE t1 (a INT, b INT) +PARTITION BY LIST (a) +SUBPARTITION BY HASH (b) +(PARTITION p1 VALUES IN (1)); +ALTER TABLE t1 ADD COLUMN c INT; +DROP TABLE t1; CREATE TABLE t1 ( a int NOT NULL, b int NOT NULL); @@ -50,6 +56,13 @@ t1 CREATE TABLE `t1` ( PARTITION p3 VALUES LESS THAN (733969) ENGINE = MyISAM, PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ DROP TABLE t1; +create table t1 (a int NOT NULL, b varchar(5) NOT NULL) +default charset=utf8 +partition by list (a) +subpartition by key (b) +(partition p0 values in (1), +partition p1 values in (2)); +drop table t1; create table t1 (a int, b int, key(a)) partition by list (a) ( partition p0 values in (1), @@ -2045,10 +2058,15 @@ DROP TABLE t1; # # Bug #45807: crash accessing partitioned table and sql_mode # contains ONLY_FULL_GROUP_BY +# Bug#46923: select count(*) from partitioned table fails with +# ONLY_FULL_GROUP_BY # SET SESSION SQL_MODE='ONLY_FULL_GROUP_BY'; CREATE TABLE t1(id INT,KEY(id)) ENGINE=MYISAM PARTITION BY HASH(id) PARTITIONS 2; +SELECT COUNT(*) FROM t1; +COUNT(*) +0 DROP TABLE t1; SET SESSION SQL_MODE=DEFAULT; # diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 2306f8b501e..64e00521cd2 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1603,4 +1603,54 @@ SELECT str_to_date('', '%Y-%m-%d'); str_to_date('', '%Y-%m-%d') 0000-00-00 DROP TABLE t1, t2; +# +# Bug#48459: valgrind errors with query using 'Range checked for each +# record' +# +CREATE TABLE t1 ( +a INT, +b CHAR(2), +c INT, +d INT, +KEY ( c ), +KEY ( d, a, b ( 2 ) ), +KEY ( b ( 1 ) ) +); +INSERT INTO t1 VALUES ( NULL, 'a', 1, 2 ), ( NULL, 'a', 1, 2 ), +( 1, 'a', 1, 2 ), ( 1, 'a', 1, 2 ); +CREATE TABLE t2 ( +a INT, +c INT, +e INT, +KEY ( e ) +); +INSERT INTO t2 VALUES ( 1, 1, NULL ), ( 1, 1, NULL ); +# Should not give Valgrind warnings +SELECT 1 +FROM t1, t2 +WHERE t1.d <> '1' AND t1.b > '1' +AND t1.a = t2.a AND t1.c = t2.c; +1 +1 +1 +1 +1 +DROP TABLE t1, t2; +# +# Bug #48665: sql-bench's insert test fails due to wrong result +# +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (0,0), (1,1); +EXPLAIN +SELECT * FROM t1 FORCE INDEX (PRIMARY) +WHERE (a>=1 AND a<=2) OR (a>=4 AND a<=5) OR (a>=0 AND a <=10); +id select_type table type possible_keys key key_len ref rows Extra +@ @ @ range @ @ @ @ @ @ +# Should return 2 rows +SELECT * FROM t1 FORCE INDEX (PRIMARY) +WHERE (a>=1 AND a<=2) OR (a>=4 AND a<=5) OR (a>=0 AND a <=10); +a b +0 0 +1 1 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 1b615233a14..d0b2a575a32 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4427,6 +4427,20 @@ ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1)) INTO @var0; ERROR 21000: Subquery returns more than 1 row DROP TABLE t1; +# +# Bug #48458: simple query tries to allocate enormous amount of +# memory +# +CREATE TABLE t1(a INT NOT NULL, b YEAR); +INSERT INTO t1 VALUES (); +Warnings: +Warning 1364 Field 'a' doesn't have a default value +CREATE TABLE t2(c INT); +# Should not err out because of out-of-memory +SELECT 1 FROM t2 JOIN t1 ON 1=1 +WHERE a != '1' AND NOT a >= b OR NOT ROW(b,a )<> ROW(a,a); +1 +DROP TABLE t1,t2; End of 5.0 tests create table t1(a INT, KEY (a)); INSERT INTO t1 VALUES (1),(2),(3),(4),(5); @@ -4577,4 +4591,22 @@ field2 15:13:38 drop table A,AA,B,BB; #end of test for bug#45266 +# +# BUG#48052: Valgrind warning - uninitialized value in init_read_record() +# +CREATE TABLE t1 ( +pk int(11) NOT NULL, +i int(11) DEFAULT NULL, +v varchar(1) DEFAULT NULL, +PRIMARY KEY (pk) +); +INSERT INTO t1 VALUES (2,7,'m'); +INSERT INTO t1 VALUES (3,9,'m'); +SELECT v +FROM t1 +WHERE NOT pk > 0 +HAVING v <= 't' +ORDER BY pk; +v +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/sp-destruct.result b/mysql-test/r/sp-destruct.result index d7d44061b76..b6891df2420 100644 --- a/mysql-test/r/sp-destruct.result +++ b/mysql-test/r/sp-destruct.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted"); use test; drop procedure if exists bug14233; drop function if exists bug14233; @@ -11,11 +12,13 @@ create table t1 (id int); create trigger t1_ai after insert on t1 for each row call bug14233(); alter table mysql.proc drop type; call bug14233(); -ERROR HY000: Failed to load routine test.bug14233. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5) +ERROR HY000: Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted create view v1 as select bug14233_f(); -ERROR HY000: Failed to load routine test.bug14233_f. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5) +ERROR HY000: Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted insert into t1 values (0); -ERROR HY000: Failed to load routine test.bug14233. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5) +ERROR HY000: Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted +show procedure status; +ERROR HY000: Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted flush table mysql.proc; call bug14233(); ERROR HY000: Incorrect information in file: './mysql/proc.frm' @@ -88,3 +91,28 @@ show procedure status where db=DATABASE(); Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation show function status where db=DATABASE(); Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation +DROP TABLE IF EXISTS proc_backup; +DROP PROCEDURE IF EXISTS p1; +# Backup the proc table +RENAME TABLE mysql.proc TO proc_backup; +CREATE TABLE mysql.proc LIKE proc_backup; +FLUSH TABLE mysql.proc; +# Test with a valid table. +CREATE PROCEDURE p1() +SET @foo = 10; +CALL p1(); +SHOW PROCEDURE STATUS; +Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation +test p1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER latin1 latin1_swedish_ci latin1_swedish_ci +# Modify a field of the table. +ALTER TABLE mysql.proc MODIFY comment CHAR (32); +CREATE PROCEDURE p2() +SET @foo = 10; +ERROR HY000: Cannot load from mysql.proc. The table is probably corrupted +# Procedure loaded from the cache +CALL p1(); +SHOW PROCEDURE STATUS; +ERROR HY000: Cannot load from mysql.proc. The table is probably corrupted +DROP TABLE mysql.proc; +RENAME TABLE proc_backup TO mysql.proc; +FLUSH TABLE mysql.proc; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index ecac8fed8c4..4ea26d1021a 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -510,4 +510,60 @@ DROP USER mysqltest_u1@localhost; DROP PROCEDURE p_suid; DROP FUNCTION f_suid; DROP TABLE t1; +# +# Bug #48872 : Privileges for stored functions ignored if function name +# is mixed case +# +CREATE DATABASE B48872; +USE B48872; +CREATE TABLE `TestTab` (id INT); +INSERT INTO `TestTab` VALUES (1),(2); +CREATE FUNCTION `f_Test`() RETURNS INT RETURN 123; +CREATE FUNCTION `f_Test_denied`() RETURNS INT RETURN 123; +CREATE USER 'tester'; +CREATE USER 'Tester'; +GRANT SELECT ON TABLE `TestTab` TO 'tester'; +GRANT EXECUTE ON FUNCTION `f_Test` TO 'tester'; +GRANT EXECUTE ON FUNCTION `f_Test_denied` TO 'Tester'; +SELECT f_Test(); +f_Test() +123 +SELECT * FROM TestTab; +id +1 +2 +SELECT * FROM TestTab; +id +1 +2 +SELECT `f_Test`(); +`f_Test`() +123 +SELECT `F_TEST`(); +`F_TEST`() +123 +SELECT f_Test(); +f_Test() +123 +SELECT F_TEST(); +F_TEST() +123 +SELECT * FROM TestTab; +SELECT `f_Test`(); +SELECT `F_TEST`(); +SELECT f_Test(); +SELECT F_TEST(); +SELECT `f_Test_denied`(); +`f_Test_denied`() +123 +SELECT `F_TEST_DENIED`(); +`F_TEST_DENIED`() +123 +DROP TABLE `TestTab`; +DROP FUNCTION `f_Test`; +DROP FUNCTION `f_Test_denied`; +USE test; +DROP USER 'tester'; +DROP USER 'Tester'; +DROP DATABASE B48872; End of 5.0 tests. diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index b517721c6d2..dd3ada2ee86 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6970,6 +6970,64 @@ CALL p1; ERROR 42S22: Unknown column 'A.b' in 'IN/ALL/ANY subquery' DROP PROCEDURE p1; DROP TABLE t1, t2; +# +# Bug#47627: SET @@{global.session}.local_variable in stored routine causes crash +# Bug#48626: Crash or lost connection using SET for declared variables with @@ +# +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +CREATE PROCEDURE p1() +BEGIN +DECLARE v INT DEFAULT 0; +SET @@SESSION.v= 10; +END// +ERROR HY000: Unknown system variable 'v' +CREATE PROCEDURE p2() +BEGIN +DECLARE v INT DEFAULT 0; +SET v= 10; +END// +call p2()// +CREATE PROCEDURE p3() +BEGIN +DECLARE v INT DEFAULT 0; +SELECT @@SESSION.v; +END// +ERROR HY000: Unknown system variable 'v' +CREATE PROCEDURE p4() +BEGIN +DECLARE v INT DEFAULT 0; +SET @@GLOBAL.v= 10; +END// +ERROR HY000: Unknown system variable 'v' +CREATE PROCEDURE p5() +BEGIN +DECLARE init_connect INT DEFAULT 0; +SET init_connect= 10; +SET @@GLOBAL.init_connect= 'SELECT 1'; +SET @@SESSION.IDENTITY= 1; +SELECT @@SESSION.IDENTITY; +SELECT @@GLOBAL.init_connect; +SELECT init_connect; +END// +CREATE PROCEDURE p6() +BEGIN +DECLARE v INT DEFAULT 0; +SET @@v= 0; +END// +ERROR HY000: Unknown system variable 'v' +SET @old_init_connect= @@GLOBAL.init_connect; +CALL p5(); +@@SESSION.IDENTITY +1 +@@GLOBAL.init_connect +SELECT 1 +init_connect +10 +SET @@GLOBAL.init_connect= @old_init_connect; +DROP PROCEDURE p2; +DROP PROCEDURE p5; # ------------------------------------------------------------------ # -- End of 5.1 tests # ------------------------------------------------------------------ diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 748aadee4fb..70ee3a56cf3 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1630,3 +1630,287 @@ SELECT my_col FROM t1; my_col 0.012345687012345687012345687012 DROP TABLE t1; +# +# Bug#45261: Crash, stored procedure + decimal +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 SELECT +/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001 +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001. +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */ +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 +AS c1; +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */ +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999.999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */ +AS c1; +DESC t1; +Field Type Null Key Default Extra +c1 decimal(31,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +1.100000000000000000000000000000 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ +AS c1; +DESC t1; +Field Type Null Key Default Extra +c1 decimal(31,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +1.100000000000000000000000000000 +DROP TABLE t1; +CREATE TABLE t1 SELECT +.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ +AS c1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(30,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +0.100000000000000000000000000000 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */ +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999.999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */ +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,1) NO 0.0 +SELECT * FROM t1; +c1 +9999999999999999999999999999999999999999999999999999999999999999.9 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */ +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,1) NO 0.0 +SELECT * FROM t1; +c1 +9999999999999999999999999999999999999999999999999999999999999999.9 +DROP TABLE t1; +CREATE TABLE t1 SELECT +.123456789012345678901234567890123456789012345678901234567890123456 /* 66 */ +AS c1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(30,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +0.123456789012345678901234567890 +DROP TABLE t1; +CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(33,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +123.123456789012345678901234567890 +DROP TABLE t1; +CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1; +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +2.100000000000000000000000000000 +DROP TABLE t1; +# +# Test that the integer and decimal parts are properly calculated. +# +CREATE TABLE t1 (a DECIMAL(30,30)); +INSERT INTO t1 VALUES (0.1),(0.2),(0.3); +CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 3 +DESC t2; +Field Type Null Key Default Extra +c1 decimal(32,30) YES NULL +DROP TABLE t1,t2; +CREATE TABLE t1 (a DECIMAL(30,30)); +INSERT INTO t1 VALUES (0.1),(0.2),(0.3); +CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +Note 1265 Data truncated for column 'c1' at row 2 +Note 1265 Data truncated for column 'c1' at row 3 +DESC t2; +Field Type Null Key Default Extra +c1 decimal(34,0) YES NULL +DROP TABLE t1,t2; +CREATE TABLE t1 (a DECIMAL(30,30)); +INSERT INTO t1 VALUES (0.1),(0.2),(0.3); +CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +DESC t2; +Field Type Null Key Default Extra +c1 decimal(65,30) YES NULL +DROP TABLE t1,t2; +# +# Test that variables get maximum precision. +# +SET @decimal= 1.1; +CREATE TABLE t1 SELECT @decimal AS c1; +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,30) YES NULL +SELECT * FROM t1; +c1 +1.100000000000000000000000000000 +DROP TABLE t1; +# +# Bug #45261 : Crash, stored procedure + decimal +# Original test by the reporter. +# +# should not crash +CREATE TABLE t1 +SELECT .123456789012345678901234567890123456789012345678901234567890123456 AS a; +Warnings: +Note 1265 Data truncated for column 'a' at row 1 +DROP TABLE t1; +CREATE PROCEDURE test_proc() +BEGIN +# The las non critical CUSER definition is: +# DECLARE mycursor CURSOR FOR SELECT 1 % +# .12345678912345678912345678912345678912345678912345678912345678912 AS my_col; +DECLARE mycursor CURSOR FOR +SELECT 1 % +.123456789123456789123456789123456789123456789123456789123456789123456789123456789 +AS my_col; +OPEN mycursor; +CLOSE mycursor; +END| +# should not crash +CALL test_proc(); +DROP PROCEDURE test_proc; +# +# Bug #48370 Absolutely wrong calculations with GROUP BY and +# decimal fields when using IF +# +CREATE TABLE currencies (id int, rate decimal(16,4), +PRIMARY KEY (id), KEY (rate)); +INSERT INTO currencies VALUES (11,0.7028); +INSERT INTO currencies VALUES (1,1); +CREATE TABLE payments ( +id int, +supplier_id int, +status int, +currency_id int, +vat decimal(7,4), +PRIMARY KEY (id), +KEY currency_id (currency_id), +KEY supplier_id (supplier_id) +); +INSERT INTO payments (id,status,vat,supplier_id,currency_id) VALUES +(3001,2,0.0000,344,11), (1,2,0.0000,1,1); +CREATE TABLE sub_tasks ( +id int, +currency_id int, +price decimal(16,4), +discount decimal(10,4), +payment_id int, +PRIMARY KEY (id), +KEY currency_id (currency_id), +KEY payment_id (payment_id) +) ; +INSERT INTO sub_tasks (id, price, discount, payment_id, currency_id) VALUES +(52, 12.60, 0, 3001, 11), (56, 14.58, 0, 3001, 11); +# should return 1 and the same values in col 2 and 3 +select STRAIGHT_JOIN +(1 + PAY.vat) AS mult, +SUM(ROUND((SUB.price - ROUND(ROUND(SUB.price, 2) * SUB.discount, 2)) * +CUR.rate / CUR.rate, 2) +) v_net_with_discount, +SUM(ROUND((SUB.price - ROUND(ROUND(SUB.price, 2) * SUB.discount, 1)) * +CUR.rate / CUR.rate , 2) +* (1 + PAY.vat) +) v_total +from +currencies CUR, payments PAY, sub_tasks SUB +where +SUB.payment_id = PAY.id and +PAY.currency_id = CUR.id and +PAY.id > 2 +group by PAY.id + 1; +mult v_net_with_discount v_total +1.0000 27.18 27.180000 +DROP TABLE currencies, payments, sub_tasks; +End of 5.1 tests diff --git a/mysql-test/std_data/bug47012.ARM b/mysql-test/std_data/bug47012.ARM Binary files differnew file mode 100644 index 00000000000..86bbaf829d2 --- /dev/null +++ b/mysql-test/std_data/bug47012.ARM diff --git a/mysql-test/std_data/bug47012.ARZ b/mysql-test/std_data/bug47012.ARZ Binary files differnew file mode 100644 index 00000000000..f2aa19ffea6 --- /dev/null +++ b/mysql-test/std_data/bug47012.ARZ diff --git a/mysql-test/std_data/bug47012.frm b/mysql-test/std_data/bug47012.frm Binary files differnew file mode 100644 index 00000000000..6c0a535cce7 --- /dev/null +++ b/mysql-test/std_data/bug47012.frm diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index f9de96c6c07..268d390a1a1 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -1,3 +1,4 @@ +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); drop table if exists t1, t2; create table t1 (a int) engine=innodb; create table t2 (a int) engine=myisam; @@ -224,6 +225,8 @@ create table t0 (n int); insert t0 select * from t1; set autocommit=1; insert into t0 select GET_LOCK("lock1",null); +Warnings: +Note 1592 Statement may not be safe to log in statement format. set autocommit=0; create table t2 (n int) engine=innodb; insert into t2 values (3); diff --git a/mysql-test/suite/binlog/r/binlog_stm_row.result b/mysql-test/suite/binlog/r/binlog_stm_row.result index f96073a2b92..e74a05e8827 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_row.result +++ b/mysql-test/suite/binlog/r/binlog_stm_row.result @@ -1,3 +1,4 @@ +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; set @saved_global_binlog_format = @@global.binlog_format; @@ -29,6 +30,8 @@ SELECT RELEASE_LOCK('Bug#34306'); RELEASE_LOCK('Bug#34306') 1 # con2 +Warnings: +Note 1592 Statement may not be safe to log in statement format. SELECT RELEASE_LOCK('Bug#34306'); RELEASE_LOCK('Bug#34306') 1 diff --git a/mysql-test/suite/binlog/r/binlog_unsafe.result b/mysql-test/suite/binlog/r/binlog_unsafe.result index 8efb1991233..c3ce1783f95 100644 --- a/mysql-test/suite/binlog/r/binlog_unsafe.result +++ b/mysql-test/suite/binlog/r/binlog_unsafe.result @@ -382,4 +382,87 @@ master-bin.000001 13657 Write_rows 1 13695 table_id: 48 master-bin.000001 13695 Write_rows 1 13729 table_id: 47 flags: STMT_END_F master-bin.000001 13729 Query 1 13798 COMMIT DROP TABLE t1,t2,t3; +SET SESSION binlog_format = STATEMENT; +CREATE TABLE t1 (a VARCHAR(1000)); +INSERT INTO t1 VALUES (CURRENT_USER()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (FOUND_ROWS()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (GET_LOCK('tmp', 1)); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (IS_FREE_LOCK('tmp')); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (IS_USED_LOCK('tmp')); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (LOAD_FILE('../../std_data/words2.dat')); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (MASTER_POS_WAIT('dummy arg', 4711, 1)); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (RELEASE_LOCK('tmp')); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (ROW_COUNT()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (SESSION_USER()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (SLEEP(1)); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (SYSDATE()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (SYSTEM_USER()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (USER()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (UUID()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (UUID_SHORT()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +INSERT INTO t1 VALUES (VERSION()); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +DELETE FROM t1; +SET TIMESTAMP=1000000; +INSERT INTO t1 VALUES +(CURDATE()), +(CURRENT_DATE()), +(CURRENT_TIME()), +(CURRENT_TIMESTAMP()), +(CURTIME()), +(LOCALTIME()), +(LOCALTIMESTAMP()), +(NOW()), +(UNIX_TIMESTAMP()), +(UTC_DATE()), +(UTC_TIME()), +(UTC_TIMESTAMP()); +SELECT * FROM t1; +a +1970-01-12 +1970-01-12 +16:46:40 +1970-01-12 16:46:40 +16:46:40 +1970-01-12 16:46:40 +1970-01-12 16:46:40 +1970-01-12 16:46:40 +1000000 +1970-01-12 +13:46:40 +1970-01-12 13:46:40 +DROP TABLE t1; "End of tests" diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index d4aa91140cf..2e261f6fafd 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -1,5 +1,5 @@ -- source include/have_innodb.inc --- source include/have_binlog_format_mixed_or_statement.inc +-- source include/have_binlog_format_statement.inc # You cannot use `KILL' with the Embedded MySQL Server library, # because the embedded server merely runs inside the threads of the host diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index e4661526982..ba3da73dead 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -2,6 +2,9 @@ # For both statement and row based bin logs 9/19/2005 [jbm] -- source include/have_binlog_format_statement.inc + +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); + -- source extra/binlog_tests/mix_innodb_myisam_binlog.test set @@session.binlog_format=statement; diff --git a/mysql-test/suite/binlog/t/binlog_stm_row.test b/mysql-test/suite/binlog/t/binlog_stm_row.test index e923faae940..29b0a69330d 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_row.test +++ b/mysql-test/suite/binlog/t/binlog_stm_row.test @@ -1,5 +1,8 @@ --source include/have_log_bin.inc ---source include/have_binlog_format_row_or_statement.inc +# Test sets its own binlog_format, so we restrict it to run only once +--source include/have_binlog_format_row.inc + +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); # Get rid of previous tests binlog --disable_query_log diff --git a/mysql-test/suite/binlog/t/binlog_unsafe.test b/mysql-test/suite/binlog/t/binlog_unsafe.test index 1cda75cdb6d..09e1241e5c7 100644 --- a/mysql-test/suite/binlog/t/binlog_unsafe.test +++ b/mysql-test/suite/binlog/t/binlog_unsafe.test @@ -426,7 +426,7 @@ eval SHOW BINLOG EVENTS FROM $pos0_master; # clean up DROP TABLE t1,t2; DROP FUNCTION func_modify_t1; - +# # Test case2: stmt that have more than one different tables # to update with autoinc columns should produce # unsafe warning when invoking a trigger @@ -456,4 +456,56 @@ eval SHOW BINLOG EVENTS FROM $pos1_master; # clean up DROP TABLE t1,t2,t3; +# +# BUG#47995: Mark user functions as unsafe +# +# Test that the system functions that are supposed to be marked unsafe +# generate a warning. Each INSERT statement below should generate a +# warning. +# +SET SESSION binlog_format = STATEMENT; + +CREATE TABLE t1 (a VARCHAR(1000)); +INSERT INTO t1 VALUES (CURRENT_USER()); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (FOUND_ROWS()); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (GET_LOCK('tmp', 1)); +INSERT INTO t1 VALUES (IS_FREE_LOCK('tmp')); +INSERT INTO t1 VALUES (IS_USED_LOCK('tmp')); +INSERT INTO t1 VALUES (LOAD_FILE('../../std_data/words2.dat')); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (MASTER_POS_WAIT('dummy arg', 4711, 1)); +INSERT INTO t1 VALUES (RELEASE_LOCK('tmp')); +INSERT INTO t1 VALUES (ROW_COUNT()); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (SESSION_USER()); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (SLEEP(1)); +INSERT INTO t1 VALUES (SYSDATE()); +INSERT INTO t1 VALUES (SYSTEM_USER()); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (USER()); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (UUID()); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (UUID_SHORT()); #marked unsafe before BUG#47995 +INSERT INTO t1 VALUES (VERSION()); +DELETE FROM t1; + +# Since we replicate the TIMESTAMP variable, functions affected by the +# TIMESTAMP variable are safe to replicate. So we check that the +# following following functions depend on the TIMESTAMP variable and +# don't generate a warning. + +SET TIMESTAMP=1000000; +INSERT INTO t1 VALUES + (CURDATE()), + (CURRENT_DATE()), + (CURRENT_TIME()), + (CURRENT_TIMESTAMP()), + (CURTIME()), + (LOCALTIME()), + (LOCALTIMESTAMP()), + (NOW()), + (UNIX_TIMESTAMP()), + (UTC_DATE()), + (UTC_TIME()), + (UTC_TIMESTAMP()); +SELECT * FROM t1; + +DROP TABLE t1; + --echo "End of tests" diff --git a/mysql-test/suite/innodb/r/innodb-index.result b/mysql-test/suite/innodb/r/innodb-index.result index a7d66b15300..67fbe0dce02 100644 --- a/mysql-test/suite/innodb/r/innodb-index.result +++ b/mysql-test/suite/innodb/r/innodb-index.result @@ -968,6 +968,7 @@ create index t1u on t1 (u(1)); drop table t1; set global innodb_file_per_table=0; set global innodb_file_format=Antelope; +set global innodb_file_format_check=Antelope; SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; CREATE TABLE t1( diff --git a/mysql-test/suite/innodb/r/innodb_bug46676.result b/mysql-test/suite/innodb/r/innodb_bug46676.result new file mode 100644 index 00000000000..996799ce931 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug46676.result @@ -0,0 +1,9 @@ +SET foreign_key_checks=0; +CREATE TABLE t1 (id int, foreign key (id) references t2(id)) ENGINE=INNODB; +CREATE TABLE t2 (id int, foreign key (id) references t1(id)) ENGINE=INNODB; +SET foreign_key_checks=1; +SELECT COUNT(*) FROM information_schema.key_column_usage WHERE REFERENCED_TABLE_NAME in ('t1', 't2'); +COUNT(*) +2 +SET foreign_key_checks=0; +DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/r/innodb_bug47167.result b/mysql-test/suite/innodb/r/innodb_bug47167.result new file mode 100644 index 00000000000..cbec363d78f --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug47167.result @@ -0,0 +1,24 @@ +set @old_innodb_file_format_check=@@innodb_file_format_check; +select @old_innodb_file_format_check; +@old_innodb_file_format_check +Antelope +set global innodb_file_format_check = Barracuda; +select @@innodb_file_format_check; +@@innodb_file_format_check +Barracuda +set global innodb_file_format_check = DEFAULT; +select @@innodb_file_format_check; +@@innodb_file_format_check +Barracuda +set global innodb_file_format_check = @old_innodb_file_format_check; +select @@innodb_file_format_check; +@@innodb_file_format_check +Antelope +set global innodb_file_format_check = cheetah; +ERROR HY000: Incorrect arguments to SET +set global innodb_file_format_check = Bear; +ERROR HY000: Incorrect arguments to SET +set global innodb_file_format_check = on; +ERROR HY000: Incorrect arguments to SET +set global innodb_file_format_check = off; +ERROR HY000: Incorrect arguments to SET diff --git a/mysql-test/suite/innodb/r/innodb_file_format.result b/mysql-test/suite/innodb/r/innodb_file_format.result index fbc67ada1bb..36f176c616a 100644 --- a/mysql-test/suite/innodb/r/innodb_file_format.result +++ b/mysql-test/suite/innodb/r/innodb_file_format.result @@ -31,8 +31,6 @@ select @@innodb_file_format_check; @@innodb_file_format_check Barracuda set global innodb_file_format_check=default; -Warnings: -Warning 1210 Ignoring SET innodb_file_format=on select @@innodb_file_format_check; @@innodb_file_format_check Barracuda diff --git a/mysql-test/suite/innodb/t/innodb-consistent-master.opt b/mysql-test/suite/innodb/t/innodb-consistent-master.opt index e76299453d3..cb48f1aaf60 100644 --- a/mysql-test/suite/innodb/t/innodb-consistent-master.opt +++ b/mysql-test/suite/innodb/t/innodb-consistent-master.opt @@ -1 +1 @@ ---innodb_lock_wait_timeout=2 +--loose-innodb_lock_wait_timeout=2 diff --git a/mysql-test/suite/innodb/t/innodb-index.test b/mysql-test/suite/innodb/t/innodb-index.test index 54aff3a42c0..b5dd2e037e7 100644 --- a/mysql-test/suite/innodb/t/innodb-index.test +++ b/mysql-test/suite/innodb/t/innodb-index.test @@ -1,5 +1,7 @@ -- source include/have_innodb.inc +let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; + create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak'); commit; @@ -398,6 +400,7 @@ create index t1u on t1 (u(1)); drop table t1; eval set global innodb_file_per_table=$per_table; eval set global innodb_file_format=$format; +eval set global innodb_file_format_check=$format; # # Test to check whether CREATE INDEX handles implicit foreign key @@ -532,3 +535,10 @@ disconnect a; disconnect b; DROP TABLE t1; + +# +# restore environment to the state it was before this test execution +# + +-- disable_query_log +eval SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb/t/innodb_bug46676.test b/mysql-test/suite/innodb/t/innodb_bug46676.test new file mode 100644 index 00000000000..440666c4226 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug46676.test @@ -0,0 +1,16 @@ +# This is the test for bug 46676: mysqld got exception 0xc0000005 +# It is reproducible with InnoDB plugin 1.0.4 + MySQL 5.1.37. +# But no longer reproducible after MySQL 5.1.38 (with plugin 1.0.5). + +--source include/have_innodb.inc + +SET foreign_key_checks=0; +CREATE TABLE t1 (id int, foreign key (id) references t2(id)) ENGINE=INNODB; +CREATE TABLE t2 (id int, foreign key (id) references t1(id)) ENGINE=INNODB; +SET foreign_key_checks=1; + +# Server crashes +SELECT COUNT(*) FROM information_schema.key_column_usage WHERE REFERENCED_TABLE_NAME in ('t1', 't2'); + +SET foreign_key_checks=0; +DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/t/innodb_bug47167.test b/mysql-test/suite/innodb/t/innodb_bug47167.test new file mode 100644 index 00000000000..df056b91ff9 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug47167.test @@ -0,0 +1,46 @@ +# This is the unit test for bug *47167. +# It tests setting the global variable +# "innodb_file_format_check" with a +# user-Defined Variable. + +--source include/have_innodb.inc +-- source suite/innodb/include/have_innodb_plugin.inc + +# Save the value (Antelope) in 'innodb_file_format_check' to +# 'old_innodb_file_format_check' +set @old_innodb_file_format_check=@@innodb_file_format_check; + +# @old_innodb_file_format_check shall have the value of 'Antelope' +select @old_innodb_file_format_check; + +# Reset the value in 'innodb_file_format_check' to 'Barracuda' +set global innodb_file_format_check = Barracuda; + +select @@innodb_file_format_check; + +# Set 'innodb_file_format_check' to its default value, which +# is the latest file format supported in the current release. +set global innodb_file_format_check = DEFAULT; + +select @@innodb_file_format_check; + +# Put the saved value back to 'innodb_file_format_check' +set global innodb_file_format_check = @old_innodb_file_format_check; + +# Check whether 'innodb_file_format_check' get its original value. +select @@innodb_file_format_check; + +# Following are negative tests, all should fail. +--disable_warnings +--error ER_WRONG_ARGUMENTS +set global innodb_file_format_check = cheetah; + +--error ER_WRONG_ARGUMENTS +set global innodb_file_format_check = Bear; + +--error ER_WRONG_ARGUMENTS +set global innodb_file_format_check = on; + +--error ER_WRONG_ARGUMENTS +set global innodb_file_format_check = off; +--enable_warnings diff --git a/mysql-test/suite/rpl/r/rpl_bug31076.result b/mysql-test/suite/rpl/r/rpl_bug31076.result index fd66ca85d57..76bce39fc43 100644 --- a/mysql-test/suite/rpl/r/rpl_bug31076.result +++ b/mysql-test/suite/rpl/r/rpl_bug31076.result @@ -4,6 +4,8 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; CREATE DATABASE track; USE track; CREATE TABLE `visits` ( @@ -65,5 +67,6 @@ visits_id myid src ip cc org ref time host entry visit_exit user_id visit_start SELECT * FROM visits_events; event_id visit_id timestamp src data visits_events_id 20000 21231038 2007-09-18 03:59:02 Downloads/MySQL-4.1/mysql-4.1.12a-win32.zip 33712207 +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; DROP DATABASE track; End of 5.1 tests diff --git a/mysql-test/suite/rpl/r/rpl_colSize.result b/mysql-test/suite/rpl/r/rpl_colSize.result index 91456742833..ae1ac3c7fed 100644 --- a/mysql-test/suite/rpl/r/rpl_colSize.result +++ b/mysql-test/suite/rpl/r/rpl_colSize.result @@ -9,6 +9,8 @@ DROP TABLE IF EXISTS t1; *** Create "wider" table on slave *** STOP SLAVE; RESET SLAVE; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; CREATE TABLE t1 ( a float (47), b double (143,9), @@ -177,3 +179,4 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 *** Cleanup *** DROP TABLE t1; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; diff --git a/mysql-test/suite/rpl/r/rpl_err_ignoredtable.result b/mysql-test/suite/rpl/r/rpl_err_ignoredtable.result index f211d5d9a2f..75fefdad2a2 100644 --- a/mysql-test/suite/rpl/r/rpl_err_ignoredtable.result +++ b/mysql-test/suite/rpl/r/rpl_err_ignoredtable.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); create table t1 (a int primary key); create table t4 (a int primary key); insert into t1 values (1),(1); diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index 21d9fc5a919..a9b8c2de107 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -9,6 +9,8 @@ call mtr.add_suppression("Slave: Unknown table 't6' Error_code: 1051"); *** On Slave *** STOP SLAVE; RESET SLAVE; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; CREATE TABLE t1 (a INT, b INT PRIMARY KEY, c CHAR(20), d FLOAT DEFAULT '2.00', e CHAR(4) DEFAULT 'TEST') @@ -32,6 +34,7 @@ a b c d e 1 2 TEXAS 2 TEST 2 1 AUSTIN 2 TEST 3 4 QA 2 TEST +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; *** Drop t1 *** DROP TABLE t1; *** Create t2 on slave *** @@ -73,8 +76,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -91,8 +94,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 STOP SLAVE; @@ -142,8 +145,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Last_Errno 1642 +Last_Error Column 0 of table 'test.t3' cannot be converted from type 'tinyblob' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -160,8 +163,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t3' cannot be converted from type 'tinyblob' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -206,8 +209,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Last_Errno 1642 +Last_Error Column 0 of table 'test.t4' cannot be converted from type 'decimal(8,2)' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -224,8 +227,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t4' cannot be converted from type 'decimal(8,2)' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -270,8 +273,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Last_Errno 1642 +Last_Error Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -288,8 +291,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Last_SQL_Errno 1642 +Last_SQL_Error Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -333,8 +336,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Last_Errno 1642 +Last_Error Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -351,8 +354,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Last_SQL_Errno 1642 +Last_SQL_Error Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; @@ -471,8 +474,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -489,8 +492,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -500,7 +503,7 @@ DROP TABLE t10; *** Create t11 on slave *** STOP SLAVE; RESET SLAVE; -CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT, +CREATE TABLE t11 (a INT KEY, b BLOB, f INT, c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='InnoDB'; *** Create t11 on Master *** CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254) @@ -534,8 +537,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -552,8 +555,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -928,8 +931,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 +Last_Errno 1642 +Last_Error Column 0 of table 'test.t17' cannot be converted from type 'bigint' to type 'smallint(6)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -946,8 +949,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t17' cannot be converted from type 'bigint' to type 'smallint(6)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index 053dee9067b..4075d31c915 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -9,6 +9,8 @@ call mtr.add_suppression("Slave: Unknown table 't6' Error_code: 1051"); *** On Slave *** STOP SLAVE; RESET SLAVE; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; CREATE TABLE t1 (a INT, b INT PRIMARY KEY, c CHAR(20), d FLOAT DEFAULT '2.00', e CHAR(4) DEFAULT 'TEST') @@ -32,6 +34,7 @@ a b c d e 1 2 TEXAS 2 TEST 2 1 AUSTIN 2 TEST 3 4 QA 2 TEST +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; *** Drop t1 *** DROP TABLE t1; *** Create t2 on slave *** @@ -73,8 +76,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -91,8 +94,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 STOP SLAVE; @@ -142,8 +145,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Last_Errno 1642 +Last_Error Column 0 of table 'test.t3' cannot be converted from type 'tinyblob' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -160,8 +163,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t3' cannot be converted from type 'tinyblob' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -206,8 +209,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Last_Errno 1642 +Last_Error Column 0 of table 'test.t4' cannot be converted from type 'decimal(8,2)' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -224,8 +227,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t4' cannot be converted from type 'decimal(8,2)' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -270,8 +273,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Last_Errno 1642 +Last_Error Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -288,8 +291,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Last_SQL_Errno 1642 +Last_SQL_Error Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -333,8 +336,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Last_Errno 1642 +Last_Error Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -351,8 +354,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Last_SQL_Errno 1642 +Last_SQL_Error Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; @@ -471,8 +474,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -489,8 +492,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -500,7 +503,7 @@ DROP TABLE t10; *** Create t11 on slave *** STOP SLAVE; RESET SLAVE; -CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT, +CREATE TABLE t11 (a INT KEY, b BLOB, f INT, c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='MyISAM'; *** Create t11 on Master *** CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254) @@ -534,8 +537,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -552,8 +555,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -928,8 +931,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 +Last_Errno 1642 +Last_Error Column 0 of table 'test.t17' cannot be converted from type 'bigint' to type 'smallint(6)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -946,8 +949,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t17' cannot be converted from type 'bigint' to type 'smallint(6)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result index ffc42c852be..25fb6f03832 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result @@ -567,8 +567,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -585,8 +585,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -644,8 +644,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -662,8 +662,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -1722,8 +1722,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -1740,8 +1740,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -1799,8 +1799,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -1817,8 +1817,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -2877,8 +2877,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -2895,8 +2895,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -2954,8 +2954,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -2972,8 +2972,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result index 0c3dd7ed21d..63f1e49239e 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result @@ -567,8 +567,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -585,8 +585,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -644,8 +644,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -662,8 +662,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -1722,8 +1722,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -1740,8 +1740,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -1799,8 +1799,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -1817,8 +1817,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -2877,8 +2877,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -2895,8 +2895,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'double' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -2954,8 +2954,8 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_Errno 1642 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -2972,8 +2972,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Last_SQL_Errno 1642 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'tinyblob' to type 'varchar(254)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; diff --git a/mysql-test/suite/rpl/r/rpl_get_lock.result b/mysql-test/suite/rpl/r/rpl_get_lock.result index f7c9541bd9f..cbad759b17f 100644 --- a/mysql-test/suite/rpl/r/rpl_get_lock.result +++ b/mysql-test/suite/rpl/r/rpl_get_lock.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); create table t1(n int); insert into t1 values(get_lock("lock",2)); select get_lock("lock",2); diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_symlink.result b/mysql-test/suite/rpl/r/rpl_loaddata_symlink.result new file mode 100644 index 00000000000..c7806f5ecce --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_loaddata_symlink.result @@ -0,0 +1,17 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +create table t1(a int not null auto_increment, b int, primary key(a) ); +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +select * from t1; +a b +1 10 +2 15 +select * from t1; +a b +1 10 +2 15 +drop table t1; diff --git a/mysql-test/suite/rpl/r/rpl_nondeterministic_functions.result b/mysql-test/suite/rpl/r/rpl_nondeterministic_functions.result new file mode 100644 index 00000000000..c4842a284cd --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_nondeterministic_functions.result @@ -0,0 +1,26 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1 (a VARCHAR(1000)); +INSERT INTO t1 VALUES (CONNECTION_ID()); +INSERT INTO t1 VALUES (CONNECTION_ID()); +INSERT INTO t1 VALUES +(CURDATE()), +(CURRENT_DATE()), +(CURRENT_TIME()), +(CURRENT_TIMESTAMP()), +(CURTIME()), +(LOCALTIME()), +(LOCALTIMESTAMP()), +(NOW()), +(UNIX_TIMESTAMP()), +(UTC_DATE()), +(UTC_TIME()), +(UTC_TIMESTAMP()); +INSERT INTO t1 VALUES (RAND()); +INSERT INTO t1 VALUES (LAST_INSERT_ID()); +Comparing tables master:test.t1 and slave:test.t1 +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result index a980092ac37..9c8f87af5af 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result @@ -476,6 +476,8 @@ ALTER TABLE t6 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL; CREATE TABLE t7 (i INT NOT NULL, c CHAR(255) CHARACTER SET utf8 NOT NULL, j INT NOT NULL) ENGINE = 'MYISAM' ; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; [expecting slave to replicate correctly] INSERT INTO t1 VALUES (1, "", 1); INSERT INTO t1 VALUES (2, repeat(_utf8'a', 16), 2); @@ -484,11 +486,7 @@ Comparing tables master:test.t1 and slave:test.t1 INSERT INTO t2 VALUES (1, "", 1); INSERT INTO t2 VALUES (2, repeat(_utf8'a', 16), 2); Comparing tables master:test.t2 and slave:test.t2 -[expecting slave to stop] -INSERT INTO t3 VALUES (1, "", 1); -INSERT INTO t3 VALUES (2, repeat(_utf8'a', 128), 2); -Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 384, test.t3 on slave has size 49. Master's column size should be <= the slave's column size. +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; RESET MASTER; STOP SLAVE; RESET SLAVE; @@ -501,7 +499,7 @@ Comparing tables master:test.t4 and slave:test.t4 INSERT INTO t5 VALUES (1, "", 1); INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2); Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 765, test.t5 on slave has size 49. Master's column size should be <= the slave's column size. +Column 1 of table 'test.t5' cannot be converted from type 'char(255)' to type 'char(16)' RESET MASTER; STOP SLAVE; RESET SLAVE; @@ -510,7 +508,7 @@ START SLAVE; INSERT INTO t6 VALUES (1, "", 1); INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2); Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 765, test.t6 on slave has size 385. Master's column size should be <= the slave's column size. +Column 1 of table 'test.t6' cannot be converted from type 'char(255)' to type 'char(128)' RESET MASTER; STOP SLAVE; RESET SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result index ea0c322fe6d..4cf4c9fb27d 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result @@ -354,6 +354,8 @@ X Q 5 7 R 49 X Y 2 S 1 X Q 5 7 R 49 X Z 2 S 2 X Q 5 9 R 81 X Y 2 S 1 X Q 5 9 R 81 X Z 2 S 2 +SET @saved_slave_type_conversions = @@SLAVE_TYPE_CONVERSIONS; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_LOSSY'; CREATE TABLE t4 (C1 CHAR(1) PRIMARY KEY, B1 BIT(1), B2 BIT(1) NOT NULL DEFAULT 0, C2 CHAR(1) NOT NULL DEFAULT 'A') ENGINE = 'INNODB' ; INSERT INTO t4 SET C1 = 1; SELECT C1,HEX(B1),HEX(B2) FROM t4 ORDER BY C1; @@ -362,6 +364,7 @@ C1 HEX(B1) HEX(B2) SELECT C1,HEX(B1),HEX(B2) FROM t4 ORDER BY C1; C1 HEX(B1) HEX(B2) 1 NULL 0 +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; CREATE TABLE t7 (C1 INT PRIMARY KEY, C2 INT) ENGINE = 'INNODB' ; --- on slave: original values --- INSERT INTO t7 VALUES (1,3), (2,6), (3,9); @@ -476,6 +479,8 @@ ALTER TABLE t6 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL; CREATE TABLE t7 (i INT NOT NULL, c CHAR(255) CHARACTER SET utf8 NOT NULL, j INT NOT NULL) ENGINE = 'INNODB' ; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; [expecting slave to replicate correctly] INSERT INTO t1 VALUES (1, "", 1); INSERT INTO t1 VALUES (2, repeat(_utf8'a', 16), 2); @@ -484,11 +489,7 @@ Comparing tables master:test.t1 and slave:test.t1 INSERT INTO t2 VALUES (1, "", 1); INSERT INTO t2 VALUES (2, repeat(_utf8'a', 16), 2); Comparing tables master:test.t2 and slave:test.t2 -[expecting slave to stop] -INSERT INTO t3 VALUES (1, "", 1); -INSERT INTO t3 VALUES (2, repeat(_utf8'a', 128), 2); -Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 384, test.t3 on slave has size 49. Master's column size should be <= the slave's column size. +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; RESET MASTER; STOP SLAVE; RESET SLAVE; @@ -501,7 +502,7 @@ Comparing tables master:test.t4 and slave:test.t4 INSERT INTO t5 VALUES (1, "", 1); INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2); Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 765, test.t5 on slave has size 49. Master's column size should be <= the slave's column size. +Column 1 of table 'test.t5' cannot be converted from type 'char(255)' to type 'char(16)' RESET MASTER; STOP SLAVE; RESET SLAVE; @@ -510,7 +511,7 @@ START SLAVE; INSERT INTO t6 VALUES (1, "", 1); INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2); Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 765, test.t6 on slave has size 385. Master's column size should be <= the slave's column size. +Column 1 of table 'test.t6' cannot be converted from type 'char(255)' to type 'char(128)' RESET MASTER; STOP SLAVE; RESET SLAVE; @@ -597,6 +598,8 @@ UPDATE t1 SET a = 0 WHERE a < 4; UPDATE t1 SET a = 8 WHERE a < 5; Comparing tables master:test.t1 and slave:test.t1 drop table t1; +SET @saved_slave_type_conversions = @@SLAVE_TYPE_CONVERSIONS; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_LOSSY'; CREATE TABLE t1 (a bit) ENGINE='INNODB' ; INSERT IGNORE INTO t1 VALUES (NULL); INSERT INTO t1 ( a ) VALUES ( 0 ); @@ -637,5 +640,6 @@ DELETE FROM t1 WHERE a < 3 LIMIT 0; UPDATE t1 SET a = 8 WHERE a = 5 LIMIT 2; INSERT INTO t1 ( a ) VALUES ( 1 ); UPDATE t1 SET a = 9 WHERE a < 5 LIMIT 3; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; Comparing tables master:test.t1 and slave:test.t1 drop table t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_colSize.result b/mysql-test/suite/rpl/r/rpl_row_colSize.result index acda689ca9b..fd9d9f76ec9 100644 --- a/mysql-test/suite/rpl/r/rpl_row_colSize.result +++ b/mysql-test/suite/rpl/r/rpl_row_colSize.result @@ -37,8 +37,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'decimal(20,10)' to type 'decimal(5,2)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -55,8 +55,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'decimal(20,10)' to type 'decimal(5,2)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -93,8 +93,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 12, test.t1 on slave has size 12. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'decimal(27,18)' to type 'decimal(27,9)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -111,8 +111,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 12, test.t1 on slave has size 12. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'decimal(27,18)' to type 'decimal(27,9)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -149,8 +149,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'decimal(20,10)' to type 'decimal(5,2)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -167,8 +167,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'decimal(20,10)' to type 'decimal(5,2)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -206,8 +206,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 5, test.t1 has type 4 +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'double' to type 'float' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -224,8 +224,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 5, test.t1 has type 4 +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'double' to type 'float' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -263,8 +263,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 8, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'bit(64)' to type 'bit(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -281,8 +281,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 8, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'bit(64)' to type 'bit(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -319,8 +319,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 2. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'bit(12)' to type 'bit(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -337,8 +337,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 2. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'bit(12)' to type 'bit(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -376,8 +376,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'set' to type 'set('4')' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -394,8 +394,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'set' to type 'set('4')' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -433,8 +433,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 20, test.t1 on slave has size 11. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'char(20)' to type 'char(10)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -451,8 +451,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 20, test.t1 on slave has size 11. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'char(20)' to type 'char(10)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -521,8 +521,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'enum' to type 'enum('44','54')' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -539,8 +539,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'enum' to type 'enum('44','54')' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -578,8 +578,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 100. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'varchar(2000)' to type 'varchar(100)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -596,8 +596,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 100. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'varchar(2000)' to type 'varchar(100)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -634,8 +634,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 200, test.t1 on slave has size 10. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'varchar(200)' to type 'varchar(10)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -652,8 +652,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 200, test.t1 on slave has size 10. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'varchar(200)' to type 'varchar(10)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -690,8 +690,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 1000. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'varchar(2000)' to type 'varchar(1000)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -708,8 +708,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 1000. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'varchar(2000)' to type 'varchar(1000)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; @@ -747,8 +747,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 4, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Last_Errno 1642 +Last_Error Column 0 of table 'test.t1' cannot be converted from type 'tinyblob' to type 'tinyblob' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -765,8 +765,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 4, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1642 +Last_SQL_Error Column 0 of table 'test.t1' cannot be converted from type 'tinyblob' to type 'tinyblob' Replicate_Ignore_Server_Ids Master_Server_Id 1 SELECT COUNT(*) FROM t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_create_table.result b/mysql-test/suite/rpl/r/rpl_row_create_table.result index e23b3e33317..9fc48e32645 100644 --- a/mysql-test/suite/rpl/r/rpl_row_create_table.result +++ b/mysql-test/suite/rpl/r/rpl_row_create_table.result @@ -476,4 +476,30 @@ master-bin.000001 # Table_map # # table_id: # (mysqltest1.with_select) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT DROP DATABASE mysqltest1; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TEMPORARY TABLE t7(c1 INT); +CREATE TABLE t5(c1 INT); +CREATE TABLE t4(c1 INT); +CREATE VIEW bug48506_t1 AS SELECT 1; +CREATE VIEW bug48506_t2 AS SELECT * FROM t4; +CREATE VIEW bug48506_t3 AS SELECT t5.c1 AS A, t4.c1 AS B FROM t5, t4; +CREATE TABLE bug48506_t4(c1 INT); +DROP VIEW bug48506_t1, bug48506_t2, bug48506_t3; +DROP TABLE bug48506_t4; +CREATE TABLE IF NOT EXISTS bug48506_t1 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t2 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t3 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t4 LIKE t7; +SHOW TABLES LIKE 'bug48506%'; +Tables_in_test (bug48506%) +bug48506_t4 +DROP VIEW IF EXISTS bug48506_t1, bug48506_t2, bug48506_t3; +DROP TEMPORARY TABLES t7; +DROP TABLES t4, t5; +DROP TABLES IF EXISTS bug48506_t4; end of the tests diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result index cb91fd95fab..99d2154f364 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result @@ -180,7 +180,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 +Last_Errno 1642 Last_Error <Last_Error> Skip_Counter 0 Exec_Master_Log_Pos # @@ -198,7 +198,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno <Last_IO_Errno> Last_IO_Error <Last_IO_Error> -Last_SQL_Errno 1535 +Last_SQL_Errno 1642 Last_SQL_Error <Last_SQL_Error> Replicate_Ignore_Server_Ids Master_Server_Id 1 @@ -225,7 +225,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 +Last_Errno 1642 Last_Error <Last_Error> Skip_Counter 0 Exec_Master_Log_Pos # @@ -243,7 +243,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno <Last_IO_Errno> Last_IO_Error <Last_IO_Error> -Last_SQL_Errno 1535 +Last_SQL_Errno 1642 Last_SQL_Error <Last_SQL_Error> Replicate_Ignore_Server_Ids Master_Server_Id 1 @@ -270,7 +270,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 +Last_Errno 1642 Last_Error <Last_Error> Skip_Counter 0 Exec_Master_Log_Pos # @@ -288,7 +288,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno <Last_IO_Errno> Last_IO_Error <Last_IO_Error> -Last_SQL_Errno 1535 +Last_SQL_Errno 1642 Last_SQL_Error <Last_SQL_Error> Replicate_Ignore_Server_Ids Master_Server_Id 1 diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result index 8a87c3ca7a0..5f0d2be9149 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result @@ -180,7 +180,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 +Last_Errno 1642 Last_Error <Last_Error> Skip_Counter 0 Exec_Master_Log_Pos # @@ -198,7 +198,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno <Last_IO_Errno> Last_IO_Error <Last_IO_Error> -Last_SQL_Errno 1535 +Last_SQL_Errno 1642 Last_SQL_Error <Last_SQL_Error> Replicate_Ignore_Server_Ids Master_Server_Id 1 @@ -225,7 +225,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 +Last_Errno 1642 Last_Error <Last_Error> Skip_Counter 0 Exec_Master_Log_Pos # @@ -243,7 +243,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno <Last_IO_Errno> Last_IO_Error <Last_IO_Error> -Last_SQL_Errno 1535 +Last_SQL_Errno 1642 Last_SQL_Error <Last_SQL_Error> Replicate_Ignore_Server_Ids Master_Server_Id 1 @@ -270,7 +270,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 +Last_Errno 1642 Last_Error <Last_Error> Skip_Counter 0 Exec_Master_Log_Pos # @@ -288,7 +288,7 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno <Last_IO_Errno> Last_IO_Error <Last_IO_Error> -Last_SQL_Errno 1535 +Last_SQL_Errno 1642 Last_SQL_Error <Last_SQL_Error> Replicate_Ignore_Server_Ids Master_Server_Id 1 diff --git a/mysql-test/suite/rpl/r/rpl_row_trunc_temp.result b/mysql-test/suite/rpl/r/rpl_row_trunc_temp.result new file mode 100644 index 00000000000..f9181be9bc0 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_row_trunc_temp.result @@ -0,0 +1,29 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TEMPORARY TABLE t1(c1 INTEGER); +CREATE TABLE t2(c1 INTEGER); +CREATE TABLE t1(c1 INTEGER); +INSERT INTO t1 VALUES(1), (2); +INSERT INTO t2 VALUES(1), (2); +SELECT * FROM t1; +c1 +1 +2 +SELECT * FROM t2; +c1 +1 +2 +TRUNCATE t1; +TRUNCATE t2; +SELECT * FROM t1; +c1 +1 +2 +SELECT * FROM t2; +c1 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/suite/rpl/r/rpl_slow_query_log.result b/mysql-test/suite/rpl/r/rpl_slow_query_log.result index ced357b21e9..9d1cc602b68 100644 --- a/mysql-test/suite/rpl/r/rpl_slow_query_log.result +++ b/mysql-test/suite/rpl/r/rpl_slow_query_log.result @@ -14,6 +14,8 @@ include/start_slave.inc CREATE TABLE t1 (a int, b int); INSERT INTO t1 values(1, 1); INSERT INTO t1 values(1, sleep(3)); +Warnings: +Note 1592 Statement may not be safe to log in statement format. TRUNCATE mysql.slow_log; SELECT 1, sleep(3); 1 sleep(3) diff --git a/mysql-test/suite/rpl/r/rpl_stm_000001.result b/mysql-test/suite/rpl/r/rpl_stm_000001.result index 24e454eb876..c2a24cbaa82 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_000001.result +++ b/mysql-test/suite/rpl/r/rpl_stm_000001.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); create table t1 (word char(20) not null); load data infile '../../std_data/words.dat' into table t1; load data local infile 'MYSQL_TEST_DIR/std_data/words.dat' into table t1; diff --git a/mysql-test/suite/rpl/r/rpl_trigger.result b/mysql-test/suite/rpl/r/rpl_trigger.result index 3d7757613a7..86534fa8f7d 100644 --- a/mysql-test/suite/rpl/r/rpl_trigger.result +++ b/mysql-test/suite/rpl/r/rpl_trigger.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; DROP TABLE IF EXISTS t3; diff --git a/mysql-test/suite/rpl/r/rpl_typeconv.result b/mysql-test/suite/rpl/r/rpl_typeconv.result new file mode 100644 index 00000000000..716956cf2cf --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_typeconv.result @@ -0,0 +1,466 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +set @saved_slave_type_conversions = @@global.slave_type_conversions; +CREATE TABLE type_conversions ( +TestNo INT AUTO_INCREMENT PRIMARY KEY, +Source TEXT, +Target TEXT, +Flags TEXT, +On_Master TEXT, +On_Slave TEXT, +Expected TEXT, +Compare INT, +Error TEXT); +SELECT @@global.slave_type_conversions; +@@global.slave_type_conversions + +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +SELECT @@global.slave_type_conversions; +@@global.slave_type_conversions + +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +SELECT @@global.slave_type_conversions; +@@global.slave_type_conversions +ALL_NON_LOSSY +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY'; +SELECT @@global.slave_type_conversions; +@@global.slave_type_conversions +ALL_LOSSY +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY'; +SELECT @@global.slave_type_conversions; +@@global.slave_type_conversions +ALL_LOSSY,ALL_NON_LOSSY +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY,NONEXISTING_BIT'; +ERROR 42000: Variable 'slave_type_conversions' can't be set to the value of 'NONEXISTING_BIT' +SELECT @@global.slave_type_conversions; +@@global.slave_type_conversions +ALL_LOSSY,ALL_NON_LOSSY +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +**** Running tests with @@SLAVE_TYPE_CONVERSIONS = '' **** +**** Resetting master and slave **** +include/stop_slave.inc +RESET SLAVE; +RESET MASTER; +include/start_slave.inc +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +**** Running tests with @@SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY' **** +**** Resetting master and slave **** +include/stop_slave.inc +RESET SLAVE; +RESET MASTER; +include/start_slave.inc +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY'; +**** Running tests with @@SLAVE_TYPE_CONVERSIONS = 'ALL_LOSSY' **** +**** Resetting master and slave **** +include/stop_slave.inc +RESET SLAVE; +RESET MASTER; +include/start_slave.inc +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY'; +**** Running tests with @@SLAVE_TYPE_CONVERSIONS = 'ALL_LOSSY,ALL_NON_LOSSY' **** +**** Resetting master and slave **** +include/stop_slave.inc +RESET SLAVE; +RESET MASTER; +include/start_slave.inc +**** Result of conversions **** +Source_Type Target_Type All_Type_Conversion_Flags Value_On_Slave +BIT(1) BIT(1) <Correct value> +DATE DATE <Correct value> +ENUM('master',' ENUM('master',' <Correct value> +CHAR(10) ENUM('master',' <Correct error> +CHAR(10) SET('master','s <Correct error> +ENUM('master',' CHAR(10) <Correct error> +SET('master','s CHAR(10) <Correct error> +SET('master','s SET('master','s <Correct value> +SET('master','s SET('master','s <Correct value> +TINYINT TINYINT <Correct value> +TINYINT SMALLINT <Correct error> +TINYINT MEDIUMINT <Correct error> +TINYINT INT <Correct error> +TINYINT BIGINT <Correct error> +SMALLINT TINYINT <Correct error> +SMALLINT TINYINT <Correct error> +SMALLINT TINYINT UNSIGNE <Correct error> +SMALLINT SMALLINT <Correct value> +SMALLINT MEDIUMINT <Correct error> +SMALLINT INT <Correct error> +SMALLINT BIGINT <Correct error> +MEDIUMINT TINYINT <Correct error> +MEDIUMINT TINYINT <Correct error> +MEDIUMINT TINYINT UNSIGNE <Correct error> +MEDIUMINT SMALLINT <Correct error> +MEDIUMINT MEDIUMINT <Correct value> +MEDIUMINT INT <Correct error> +MEDIUMINT BIGINT <Correct error> +INT TINYINT <Correct error> +INT TINYINT <Correct error> +INT TINYINT UNSIGNE <Correct error> +INT SMALLINT <Correct error> +INT MEDIUMINT <Correct error> +INT INT <Correct value> +INT BIGINT <Correct error> +BIGINT TINYINT <Correct error> +BIGINT SMALLINT <Correct error> +BIGINT MEDIUMINT <Correct error> +BIGINT INT <Correct error> +BIGINT BIGINT <Correct value> +CHAR(20) CHAR(20) <Correct value> +CHAR(20) CHAR(30) <Correct error> +CHAR(20) CHAR(10) <Correct error> +CHAR(20) VARCHAR(20) <Correct error> +CHAR(20) VARCHAR(30) <Correct error> +CHAR(20) VARCHAR(10) <Correct error> +CHAR(20) TINYTEXT <Correct error> +CHAR(20) TEXT <Correct error> +CHAR(20) MEDIUMTEXT <Correct error> +CHAR(20) LONGTEXT <Correct error> +VARCHAR(20) VARCHAR(20) <Correct value> +VARCHAR(20) VARCHAR(30) <Correct error> +VARCHAR(20) VARCHAR(10) <Correct error> +VARCHAR(20) CHAR(30) <Correct error> +VARCHAR(20) CHAR(10) <Correct error> +VARCHAR(20) TINYTEXT <Correct error> +VARCHAR(20) TEXT <Correct error> +VARCHAR(20) MEDIUMTEXT <Correct error> +VARCHAR(20) LONGTEXT <Correct error> +VARCHAR(500) VARCHAR(500) <Correct value> +VARCHAR(500) VARCHAR(510) <Correct error> +VARCHAR(500) VARCHAR(255) <Correct error> +VARCHAR(500) TINYTEXT <Correct error> +VARCHAR(500) TEXT <Correct error> +VARCHAR(500) MEDIUMTEXT <Correct error> +VARCHAR(500) LONGTEXT <Correct error> +TINYTEXT VARCHAR(500) <Correct error> +TEXT VARCHAR(500) <Correct error> +MEDIUMTEXT VARCHAR(500) <Correct error> +LONGTEXT VARCHAR(500) <Correct error> +TINYTEXT CHAR(255) <Correct error> +TINYTEXT CHAR(250) <Correct error> +TEXT CHAR(255) <Correct error> +MEDIUMTEXT CHAR(255) <Correct error> +LONGTEXT CHAR(255) <Correct error> +TINYTEXT TINYTEXT <Correct value> +TINYTEXT TEXT <Correct error> +TEXT TINYTEXT <Correct error> +DECIMAL(10,5) DECIMAL(10,5) <Correct value> +DECIMAL(10,5) DECIMAL(10,6) <Correct error> +DECIMAL(10,5) DECIMAL(11,5) <Correct error> +DECIMAL(10,5) DECIMAL(11,6) <Correct error> +DECIMAL(10,5) DECIMAL(10,4) <Correct error> +DECIMAL(10,5) DECIMAL(9,5) <Correct error> +DECIMAL(10,5) DECIMAL(9,4) <Correct error> +FLOAT DECIMAL(10,5) <Correct error> +DOUBLE DECIMAL(10,5) <Correct error> +DECIMAL(10,5) FLOAT <Correct error> +DECIMAL(10,5) DOUBLE <Correct error> +FLOAT FLOAT <Correct value> +DOUBLE DOUBLE <Correct value> +FLOAT DOUBLE <Correct error> +DOUBLE FLOAT <Correct error> +BIT(5) BIT(5) <Correct value> +BIT(5) BIT(6) <Correct error> +BIT(6) BIT(5) <Correct error> +BIT(5) BIT(12) <Correct error> +BIT(12) BIT(5) <Correct error> +BIT(1) BIT(1) ALL_NON_LOSSY <Correct value> +DATE DATE ALL_NON_LOSSY <Correct value> +ENUM('master',' ENUM('master',' ALL_NON_LOSSY <Correct value> +CHAR(10) ENUM('master',' ALL_NON_LOSSY <Correct error> +CHAR(10) SET('master','s ALL_NON_LOSSY <Correct error> +ENUM('master',' CHAR(10) ALL_NON_LOSSY <Correct error> +SET('master','s CHAR(10) ALL_NON_LOSSY <Correct error> +SET('master','s SET('master','s ALL_NON_LOSSY <Correct value> +SET('master','s SET('master','s ALL_NON_LOSSY <Correct value> +TINYINT TINYINT ALL_NON_LOSSY <Correct value> +TINYINT SMALLINT ALL_NON_LOSSY <Correct value> +TINYINT MEDIUMINT ALL_NON_LOSSY <Correct value> +TINYINT INT ALL_NON_LOSSY <Correct value> +TINYINT BIGINT ALL_NON_LOSSY <Correct value> +SMALLINT TINYINT ALL_NON_LOSSY <Correct error> +SMALLINT TINYINT ALL_NON_LOSSY <Correct error> +SMALLINT TINYINT UNSIGNE ALL_NON_LOSSY <Correct error> +SMALLINT SMALLINT ALL_NON_LOSSY <Correct value> +SMALLINT MEDIUMINT ALL_NON_LOSSY <Correct value> +SMALLINT INT ALL_NON_LOSSY <Correct value> +SMALLINT BIGINT ALL_NON_LOSSY <Correct value> +MEDIUMINT TINYINT ALL_NON_LOSSY <Correct error> +MEDIUMINT TINYINT ALL_NON_LOSSY <Correct error> +MEDIUMINT TINYINT UNSIGNE ALL_NON_LOSSY <Correct error> +MEDIUMINT SMALLINT ALL_NON_LOSSY <Correct error> +MEDIUMINT MEDIUMINT ALL_NON_LOSSY <Correct value> +MEDIUMINT INT ALL_NON_LOSSY <Correct value> +MEDIUMINT BIGINT ALL_NON_LOSSY <Correct value> +INT TINYINT ALL_NON_LOSSY <Correct error> +INT TINYINT ALL_NON_LOSSY <Correct error> +INT TINYINT UNSIGNE ALL_NON_LOSSY <Correct error> +INT SMALLINT ALL_NON_LOSSY <Correct error> +INT MEDIUMINT ALL_NON_LOSSY <Correct error> +INT INT ALL_NON_LOSSY <Correct value> +INT BIGINT ALL_NON_LOSSY <Correct value> +BIGINT TINYINT ALL_NON_LOSSY <Correct error> +BIGINT SMALLINT ALL_NON_LOSSY <Correct error> +BIGINT MEDIUMINT ALL_NON_LOSSY <Correct error> +BIGINT INT ALL_NON_LOSSY <Correct error> +BIGINT BIGINT ALL_NON_LOSSY <Correct value> +CHAR(20) CHAR(20) ALL_NON_LOSSY <Correct value> +CHAR(20) CHAR(30) ALL_NON_LOSSY <Correct value> +CHAR(20) CHAR(10) ALL_NON_LOSSY <Correct error> +CHAR(20) VARCHAR(20) ALL_NON_LOSSY <Correct value> +CHAR(20) VARCHAR(30) ALL_NON_LOSSY <Correct value> +CHAR(20) VARCHAR(10) ALL_NON_LOSSY <Correct error> +CHAR(20) TINYTEXT ALL_NON_LOSSY <Correct value> +CHAR(20) TEXT ALL_NON_LOSSY <Correct value> +CHAR(20) MEDIUMTEXT ALL_NON_LOSSY <Correct value> +CHAR(20) LONGTEXT ALL_NON_LOSSY <Correct value> +VARCHAR(20) VARCHAR(20) ALL_NON_LOSSY <Correct value> +VARCHAR(20) VARCHAR(30) ALL_NON_LOSSY <Correct value> +VARCHAR(20) VARCHAR(10) ALL_NON_LOSSY <Correct error> +VARCHAR(20) CHAR(30) ALL_NON_LOSSY <Correct value> +VARCHAR(20) CHAR(10) ALL_NON_LOSSY <Correct error> +VARCHAR(20) TINYTEXT ALL_NON_LOSSY <Correct value> +VARCHAR(20) TEXT ALL_NON_LOSSY <Correct value> +VARCHAR(20) MEDIUMTEXT ALL_NON_LOSSY <Correct value> +VARCHAR(20) LONGTEXT ALL_NON_LOSSY <Correct value> +VARCHAR(500) VARCHAR(500) ALL_NON_LOSSY <Correct value> +VARCHAR(500) VARCHAR(510) ALL_NON_LOSSY <Correct value> +VARCHAR(500) VARCHAR(255) ALL_NON_LOSSY <Correct error> +VARCHAR(500) TINYTEXT ALL_NON_LOSSY <Correct error> +VARCHAR(500) TEXT ALL_NON_LOSSY <Correct value> +VARCHAR(500) MEDIUMTEXT ALL_NON_LOSSY <Correct value> +VARCHAR(500) LONGTEXT ALL_NON_LOSSY <Correct value> +TINYTEXT VARCHAR(500) ALL_NON_LOSSY <Correct value> +TEXT VARCHAR(500) ALL_NON_LOSSY <Correct error> +MEDIUMTEXT VARCHAR(500) ALL_NON_LOSSY <Correct error> +LONGTEXT VARCHAR(500) ALL_NON_LOSSY <Correct error> +TINYTEXT CHAR(255) ALL_NON_LOSSY <Correct value> +TINYTEXT CHAR(250) ALL_NON_LOSSY <Correct error> +TEXT CHAR(255) ALL_NON_LOSSY <Correct error> +MEDIUMTEXT CHAR(255) ALL_NON_LOSSY <Correct error> +LONGTEXT CHAR(255) ALL_NON_LOSSY <Correct error> +TINYTEXT TINYTEXT ALL_NON_LOSSY <Correct value> +TINYTEXT TEXT ALL_NON_LOSSY <Correct value> +TEXT TINYTEXT ALL_NON_LOSSY <Correct error> +DECIMAL(10,5) DECIMAL(10,5) ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(10,6) ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(11,5) ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(11,6) ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(10,4) ALL_NON_LOSSY <Correct error> +DECIMAL(10,5) DECIMAL(9,5) ALL_NON_LOSSY <Correct error> +DECIMAL(10,5) DECIMAL(9,4) ALL_NON_LOSSY <Correct error> +FLOAT DECIMAL(10,5) ALL_NON_LOSSY <Correct error> +DOUBLE DECIMAL(10,5) ALL_NON_LOSSY <Correct error> +DECIMAL(10,5) FLOAT ALL_NON_LOSSY <Correct error> +DECIMAL(10,5) DOUBLE ALL_NON_LOSSY <Correct error> +FLOAT FLOAT ALL_NON_LOSSY <Correct value> +DOUBLE DOUBLE ALL_NON_LOSSY <Correct value> +FLOAT DOUBLE ALL_NON_LOSSY <Correct value> +DOUBLE FLOAT ALL_NON_LOSSY <Correct error> +BIT(5) BIT(5) ALL_NON_LOSSY <Correct value> +BIT(5) BIT(6) ALL_NON_LOSSY <Correct value> +BIT(6) BIT(5) ALL_NON_LOSSY <Correct error> +BIT(5) BIT(12) ALL_NON_LOSSY <Correct value> +BIT(12) BIT(5) ALL_NON_LOSSY <Correct error> +BIT(1) BIT(1) ALL_LOSSY <Correct value> +DATE DATE ALL_LOSSY <Correct value> +ENUM('master',' ENUM('master',' ALL_LOSSY <Correct value> +CHAR(10) ENUM('master',' ALL_LOSSY <Correct error> +CHAR(10) SET('master','s ALL_LOSSY <Correct error> +ENUM('master',' CHAR(10) ALL_LOSSY <Correct error> +SET('master','s CHAR(10) ALL_LOSSY <Correct error> +SET('master','s SET('master','s ALL_LOSSY <Correct value> +SET('master','s SET('master','s ALL_LOSSY <Correct value> +TINYINT TINYINT ALL_LOSSY <Correct value> +TINYINT SMALLINT ALL_LOSSY <Correct error> +TINYINT MEDIUMINT ALL_LOSSY <Correct error> +TINYINT INT ALL_LOSSY <Correct error> +TINYINT BIGINT ALL_LOSSY <Correct error> +SMALLINT TINYINT ALL_LOSSY <Correct value> +SMALLINT TINYINT ALL_LOSSY <Correct value> +SMALLINT TINYINT UNSIGNE ALL_LOSSY <Correct value> +SMALLINT SMALLINT ALL_LOSSY <Correct value> +SMALLINT MEDIUMINT ALL_LOSSY <Correct error> +SMALLINT INT ALL_LOSSY <Correct error> +SMALLINT BIGINT ALL_LOSSY <Correct error> +MEDIUMINT TINYINT ALL_LOSSY <Correct value> +MEDIUMINT TINYINT ALL_LOSSY <Correct value> +MEDIUMINT TINYINT UNSIGNE ALL_LOSSY <Correct value> +MEDIUMINT SMALLINT ALL_LOSSY <Correct value> +MEDIUMINT MEDIUMINT ALL_LOSSY <Correct value> +MEDIUMINT INT ALL_LOSSY <Correct error> +MEDIUMINT BIGINT ALL_LOSSY <Correct error> +INT TINYINT ALL_LOSSY <Correct value> +INT TINYINT ALL_LOSSY <Correct value> +INT TINYINT UNSIGNE ALL_LOSSY <Correct value> +INT SMALLINT ALL_LOSSY <Correct value> +INT MEDIUMINT ALL_LOSSY <Correct value> +INT INT ALL_LOSSY <Correct value> +INT BIGINT ALL_LOSSY <Correct error> +BIGINT TINYINT ALL_LOSSY <Correct value> +BIGINT SMALLINT ALL_LOSSY <Correct value> +BIGINT MEDIUMINT ALL_LOSSY <Correct value> +BIGINT INT ALL_LOSSY <Correct value> +BIGINT BIGINT ALL_LOSSY <Correct value> +CHAR(20) CHAR(20) ALL_LOSSY <Correct value> +CHAR(20) CHAR(30) ALL_LOSSY <Correct error> +CHAR(20) CHAR(10) ALL_LOSSY <Correct value> +CHAR(20) VARCHAR(20) ALL_LOSSY <Correct error> +CHAR(20) VARCHAR(30) ALL_LOSSY <Correct error> +CHAR(20) VARCHAR(10) ALL_LOSSY <Correct value> +CHAR(20) TINYTEXT ALL_LOSSY <Correct error> +CHAR(20) TEXT ALL_LOSSY <Correct error> +CHAR(20) MEDIUMTEXT ALL_LOSSY <Correct error> +CHAR(20) LONGTEXT ALL_LOSSY <Correct error> +VARCHAR(20) VARCHAR(20) ALL_LOSSY <Correct value> +VARCHAR(20) VARCHAR(30) ALL_LOSSY <Correct error> +VARCHAR(20) VARCHAR(10) ALL_LOSSY <Correct value> +VARCHAR(20) CHAR(30) ALL_LOSSY <Correct error> +VARCHAR(20) CHAR(10) ALL_LOSSY <Correct value> +VARCHAR(20) TINYTEXT ALL_LOSSY <Correct error> +VARCHAR(20) TEXT ALL_LOSSY <Correct error> +VARCHAR(20) MEDIUMTEXT ALL_LOSSY <Correct error> +VARCHAR(20) LONGTEXT ALL_LOSSY <Correct error> +VARCHAR(500) VARCHAR(500) ALL_LOSSY <Correct value> +VARCHAR(500) VARCHAR(510) ALL_LOSSY <Correct error> +VARCHAR(500) VARCHAR(255) ALL_LOSSY <Correct value> +VARCHAR(500) TINYTEXT ALL_LOSSY <Correct value> +VARCHAR(500) TEXT ALL_LOSSY <Correct error> +VARCHAR(500) MEDIUMTEXT ALL_LOSSY <Correct error> +VARCHAR(500) LONGTEXT ALL_LOSSY <Correct error> +TINYTEXT VARCHAR(500) ALL_LOSSY <Correct error> +TEXT VARCHAR(500) ALL_LOSSY <Correct value> +MEDIUMTEXT VARCHAR(500) ALL_LOSSY <Correct value> +LONGTEXT VARCHAR(500) ALL_LOSSY <Correct value> +TINYTEXT CHAR(255) ALL_LOSSY <Correct error> +TINYTEXT CHAR(250) ALL_LOSSY <Correct value> +TEXT CHAR(255) ALL_LOSSY <Correct value> +MEDIUMTEXT CHAR(255) ALL_LOSSY <Correct value> +LONGTEXT CHAR(255) ALL_LOSSY <Correct value> +TINYTEXT TINYTEXT ALL_LOSSY <Correct value> +TINYTEXT TEXT ALL_LOSSY <Correct error> +TEXT TINYTEXT ALL_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(10,5) ALL_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(10,6) ALL_LOSSY <Correct error> +DECIMAL(10,5) DECIMAL(11,5) ALL_LOSSY <Correct error> +DECIMAL(10,5) DECIMAL(11,6) ALL_LOSSY <Correct error> +DECIMAL(10,5) DECIMAL(10,4) ALL_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(9,5) ALL_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(9,4) ALL_LOSSY <Correct value> +FLOAT DECIMAL(10,5) ALL_LOSSY <Correct value> +DOUBLE DECIMAL(10,5) ALL_LOSSY <Correct value> +DECIMAL(10,5) FLOAT ALL_LOSSY <Correct value> +DECIMAL(10,5) DOUBLE ALL_LOSSY <Correct value> +FLOAT FLOAT ALL_LOSSY <Correct value> +DOUBLE DOUBLE ALL_LOSSY <Correct value> +FLOAT DOUBLE ALL_LOSSY <Correct error> +DOUBLE FLOAT ALL_LOSSY <Correct value> +BIT(5) BIT(5) ALL_LOSSY <Correct value> +BIT(5) BIT(6) ALL_LOSSY <Correct error> +BIT(6) BIT(5) ALL_LOSSY <Correct value> +BIT(5) BIT(12) ALL_LOSSY <Correct error> +BIT(12) BIT(5) ALL_LOSSY <Correct value> +BIT(1) BIT(1) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DATE DATE ALL_LOSSY,ALL_NON_LOSSY <Correct value> +ENUM('master',' ENUM('master',' ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(10) ENUM('master',' ALL_LOSSY,ALL_NON_LOSSY <Correct error> +CHAR(10) SET('master','s ALL_LOSSY,ALL_NON_LOSSY <Correct error> +ENUM('master',' CHAR(10) ALL_LOSSY,ALL_NON_LOSSY <Correct error> +SET('master','s CHAR(10) ALL_LOSSY,ALL_NON_LOSSY <Correct error> +SET('master','s SET('master','s ALL_LOSSY,ALL_NON_LOSSY <Correct value> +SET('master','s SET('master','s ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYINT TINYINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYINT SMALLINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYINT MEDIUMINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYINT INT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYINT BIGINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +SMALLINT TINYINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +SMALLINT TINYINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +SMALLINT TINYINT UNSIGNE ALL_LOSSY,ALL_NON_LOSSY <Correct value> +SMALLINT SMALLINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +SMALLINT MEDIUMINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +SMALLINT INT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +SMALLINT BIGINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMINT TINYINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMINT TINYINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMINT TINYINT UNSIGNE ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMINT SMALLINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMINT MEDIUMINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMINT INT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMINT BIGINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +INT TINYINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +INT TINYINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +INT TINYINT UNSIGNE ALL_LOSSY,ALL_NON_LOSSY <Correct value> +INT SMALLINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +INT MEDIUMINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +INT INT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +INT BIGINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIGINT TINYINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIGINT SMALLINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIGINT MEDIUMINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIGINT INT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIGINT BIGINT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) CHAR(20) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) CHAR(30) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) CHAR(10) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) VARCHAR(20) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) VARCHAR(30) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) VARCHAR(10) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) TINYTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) TEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) MEDIUMTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +CHAR(20) LONGTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) VARCHAR(20) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) VARCHAR(30) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) VARCHAR(10) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) CHAR(30) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) CHAR(10) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) TINYTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) TEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) MEDIUMTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(20) LONGTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(500) VARCHAR(500) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(500) VARCHAR(510) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(500) VARCHAR(255) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(500) TINYTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(500) TEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(500) MEDIUMTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +VARCHAR(500) LONGTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYTEXT VARCHAR(500) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TEXT VARCHAR(500) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMTEXT VARCHAR(500) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +LONGTEXT VARCHAR(500) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYTEXT CHAR(255) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYTEXT CHAR(250) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TEXT CHAR(255) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +MEDIUMTEXT CHAR(255) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +LONGTEXT CHAR(255) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYTEXT TINYTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TINYTEXT TEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +TEXT TINYTEXT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(10,5) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(10,6) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(11,5) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(11,6) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(10,4) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(9,5) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DECIMAL(9,4) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +FLOAT DECIMAL(10,5) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DOUBLE DECIMAL(10,5) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) FLOAT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DECIMAL(10,5) DOUBLE ALL_LOSSY,ALL_NON_LOSSY <Correct value> +FLOAT FLOAT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DOUBLE DOUBLE ALL_LOSSY,ALL_NON_LOSSY <Correct value> +FLOAT DOUBLE ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DOUBLE FLOAT ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIT(5) BIT(5) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIT(5) BIT(6) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIT(6) BIT(5) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIT(5) BIT(12) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +BIT(12) BIT(5) ALL_LOSSY,ALL_NON_LOSSY <Correct value> +DROP TABLE type_conversions; +DROP TABLE t1; +set global slave_type_conversions = @saved_slave_type_conversions; diff --git a/mysql-test/suite/rpl/r/rpl_typeconv_innodb.result b/mysql-test/suite/rpl/r/rpl_typeconv_innodb.result new file mode 100644 index 00000000000..0b4286c54eb --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_typeconv_innodb.result @@ -0,0 +1,18 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +**** Resetting master and slave **** +include/stop_slave.inc +RESET SLAVE; +RESET MASTER; +include/start_slave.inc +SET @saved_slave_type_conversions = @@GLOBAL.SLAVE_TYPE_CONVERSIONS; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = ''; +CREATE TABLE t1(b1 BIT(1), b2 BIT(2), b3 BIT(3)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (b'0', b'01', b'101'); +Comparing tables master:test.t1 and slave:test.t1 +DROP TABLE t1; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 38fc9e21322..c222d3dd523 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -11,3 +11,4 @@ ############################################################################## rpl_cross_version : Bug#42311 2009-03-27 joro rpl_cross_version fails on macosx +rpl_row_create_table : Bug#45576 2009-12-01 joro rpl_row_create_table fails on PB2 diff --git a/mysql-test/suite/rpl/t/rpl_bug31076.test b/mysql-test/suite/rpl/t/rpl_bug31076.test index 9176bafe022..1f488aae64e 100644 --- a/mysql-test/suite/rpl/t/rpl_bug31076.test +++ b/mysql-test/suite/rpl/t/rpl_bug31076.test @@ -1,5 +1,8 @@ source include/master-slave.inc; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; + CREATE DATABASE track; USE track; @@ -130,7 +133,10 @@ VALUES ('3m3l4rhs6do0sf5p1i9lr94g928a272v', '', '', INET_ATON('71.118.124.98'), SELECT * FROM visits; SELECT * FROM visits_events; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; + # Cleanup DROP DATABASE track; sync_slave_with_master; + --echo End of 5.1 tests diff --git a/mysql-test/suite/rpl/t/rpl_colSize.test b/mysql-test/suite/rpl/t/rpl_colSize.test index 07fd8041b18..4c808ef3dfd 100644 --- a/mysql-test/suite/rpl/t/rpl_colSize.test +++ b/mysql-test/suite/rpl/t/rpl_colSize.test @@ -19,6 +19,9 @@ STOP SLAVE; --source include/wait_for_slave_to_stop.inc RESET SLAVE; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; + eval CREATE TABLE t1 ( a float (47), b double (143,9), @@ -219,4 +222,6 @@ connection master; DROP TABLE t1; sync_slave_with_master; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; + # END 5.1 Test Case diff --git a/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test b/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test index a955de02c0f..f358c0ee356 100644 --- a/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test +++ b/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test @@ -7,6 +7,8 @@ -- source include/master-slave.inc +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); + connection master; create table t1 (a int primary key); create table t4 (a int primary key); @@ -46,8 +48,11 @@ kill @id; drop table t2,t3; insert into t4 values (3),(4); connection master; +# The get_lock function causes warning for unsafe statement. +--disable_warnings --error 0,1317,2013 reap; +--enable_warnings connection master1; sync_slave_with_master; SELECT * FROM test.t4 ORDER BY a; diff --git a/mysql-test/suite/rpl/t/rpl_get_lock.test b/mysql-test/suite/rpl/t/rpl_get_lock.test index 945bd98c993..87366f41ba2 100644 --- a/mysql-test/suite/rpl/t/rpl_get_lock.test +++ b/mysql-test/suite/rpl/t/rpl_get_lock.test @@ -1,7 +1,12 @@ source include/master-slave.inc; +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); + create table t1(n int); +# Use of get_lock gives a warning for unsafeness if binlog_format=statement +--disable_warnings insert into t1 values(get_lock("lock",2)); +--enable_warnings dirty_close master; connection master1; select get_lock("lock",2); diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.opt b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.opt new file mode 100644 index 00000000000..719832a2862 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.opt @@ -0,0 +1 @@ +--secure-file-priv=$MYSQLTEST_VARDIR/std_data_master_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh new file mode 100644 index 00000000000..066f72926af --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh @@ -0,0 +1 @@ +ln -s $MYSQLTEST_VARDIR/std_data $MYSQLTEST_VARDIR/std_data_master_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.opt b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.opt new file mode 100644 index 00000000000..a112e81a714 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.opt @@ -0,0 +1 @@ +--slave-load-tmpdir=$MYSQLTEST_VARDIR/std_data_slave_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh new file mode 100644 index 00000000000..218209a2542 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh @@ -0,0 +1 @@ +ln -s $MYSQLTEST_VARDIR/std_data $MYSQLTEST_VARDIR/std_data_slave_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink.test b/mysql-test/suite/rpl/t/rpl_loaddata_symlink.test new file mode 100644 index 00000000000..d3ee2766314 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink.test @@ -0,0 +1,20 @@ +# +# BUG#43913 +# This test verifies if loading data infile will work fine +# if the path of the load data file is a symbolic link. +# +--source include/master-slave.inc +--source include/have_binlog_format_statement.inc + +create table t1(a int not null auto_increment, b int, primary key(a) ); +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +select * from t1; + +sync_slave_with_master; +connection slave; +select * from t1; + +connection master; +drop table t1; +sync_slave_with_master; + diff --git a/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test b/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test new file mode 100644 index 00000000000..a30eb3be374 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test @@ -0,0 +1,53 @@ +# ==== Purpose ==== +# +# Test that nondeterministic system functions are correctly replicated. +# +# (Some functions are only correctly replicated if binlog_format=MIXED +# or ROW. See binlog_unsafe.test for a test that those variables are +# indeed unsafe.) +# +# ==== Implementation ==== +# +# We insert the values of each unsafe function into a table. Then we +# replicate and check that the table is identical on slave. +# +# ==== Related bugs ==== +# +# BUG#47995 + +--source include/master-slave.inc + +CREATE TABLE t1 (a VARCHAR(1000)); + +# We replicate the connection_id in the query_log_event +INSERT INTO t1 VALUES (CONNECTION_ID()); +--connection master1 +INSERT INTO t1 VALUES (CONNECTION_ID()); + +# We replicate the TIMESTAMP variable, so the following functions that +# are affected by the TIMESTAMP variable should be safe to replicate. +INSERT INTO t1 VALUES + (CURDATE()), + (CURRENT_DATE()), + (CURRENT_TIME()), + (CURRENT_TIMESTAMP()), + (CURTIME()), + (LOCALTIME()), + (LOCALTIMESTAMP()), + (NOW()), + (UNIX_TIMESTAMP()), + (UTC_DATE()), + (UTC_TIME()), + (UTC_TIMESTAMP()); + +# We replicate the random seed in a rand_log_event +INSERT INTO t1 VALUES (RAND()); +# We replicate the last_insert_id in an intvar_log_event +INSERT INTO t1 VALUES (LAST_INSERT_ID()); + +--sync_slave_with_master +--let $diff_table_1= master:test.t1 +--let $diff_table_2= slave:test.t1 +--source include/diff_tables.inc + +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_3innodb.test b/mysql-test/suite/rpl/t/rpl_row_basic_3innodb.test index 3786a697e3f..41cf1cc622a 100644 --- a/mysql-test/suite/rpl/t/rpl_row_basic_3innodb.test +++ b/mysql-test/suite/rpl/t/rpl_row_basic_3innodb.test @@ -2,6 +2,8 @@ -- source include/have_binlog_format_row.inc -- source include/master-slave.inc +connection slave; +let $bit_field_special = ALL_LOSSY; let $type= 'INNODB' ; let $extra_index= ; -- source extra/rpl_tests/rpl_row_basic.test diff --git a/mysql-test/suite/rpl/t/rpl_row_create_table.test b/mysql-test/suite/rpl/t/rpl_row_create_table.test index 33457d759b8..de5de130c58 100644 --- a/mysql-test/suite/rpl/t/rpl_row_create_table.test +++ b/mysql-test/suite/rpl/t/rpl_row_create_table.test @@ -300,4 +300,40 @@ connection master; DROP DATABASE mysqltest1; sync_slave_with_master; +# +# BUG#48506: crash in CREATE TABLE <existing_view> IF NOT EXISTS LIKE +# <tmp_tbl> with RBL +# + +source include/master-slave-reset.inc; + +connection master; +CREATE TEMPORARY TABLE t7(c1 INT); +CREATE TABLE t5(c1 INT); +CREATE TABLE t4(c1 INT); +CREATE VIEW bug48506_t1 AS SELECT 1; +CREATE VIEW bug48506_t2 AS SELECT * FROM t4; +CREATE VIEW bug48506_t3 AS SELECT t5.c1 AS A, t4.c1 AS B FROM t5, t4; +CREATE TABLE bug48506_t4(c1 INT); +--disable_warnings +sync_slave_with_master; +DROP VIEW bug48506_t1, bug48506_t2, bug48506_t3; +DROP TABLE bug48506_t4; + +connection master; +CREATE TABLE IF NOT EXISTS bug48506_t1 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t2 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t3 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t4 LIKE t7; +--enable_warnings +sync_slave_with_master; + +SHOW TABLES LIKE 'bug48506%'; + +connection master; +DROP VIEW IF EXISTS bug48506_t1, bug48506_t2, bug48506_t3; +DROP TEMPORARY TABLES t7; +DROP TABLES t4, t5; +DROP TABLES IF EXISTS bug48506_t4; +source include/master-slave-end.inc; --echo end of the tests diff --git a/mysql-test/suite/rpl/t/rpl_row_trunc_temp.test b/mysql-test/suite/rpl/t/rpl_row_trunc_temp.test new file mode 100644 index 00000000000..60e1cd73200 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_trunc_temp.test @@ -0,0 +1,35 @@ +# +# Bug#48350 truncate temporary table crashes replication +# +# All statements operating on temporary tables should not be binlogged in RBR. +# However, before fix of bug#48350, 'TRUNCATE ...' statement on a temporary +# table was binlogged in RBR. +# + +--source include/master-slave.inc +--source include/have_binlog_format_row.inc + +#This statement is not binlogged in RBR. +CREATE TEMPORARY TABLE t1(c1 INTEGER); +CREATE TABLE t2(c1 INTEGER); +sync_slave_with_master; + +CREATE TABLE t1(c1 INTEGER); +INSERT INTO t1 VALUES(1), (2); +INSERT INTO t2 VALUES(1), (2); +SELECT * FROM t1; +SELECT * FROM t2; + +connection master; +TRUNCATE t1; +TRUNCATE t2; +sync_slave_with_master; +# t1 will have nothing, if 'TRUNCATE t1' has been replicate from master to +# slave. +SELECT * FROM t1; +SELECT * FROM t2; + +DROP TABLE t1; +connection master; +DROP TABLE t2; +--source include/master-slave-end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slow_query_log.test b/mysql-test/suite/rpl/t/rpl_slow_query_log.test index 1d5fcf950f2..3523af4c951 100644 --- a/mysql-test/suite/rpl/t/rpl_slow_query_log.test +++ b/mysql-test/suite/rpl/t/rpl_slow_query_log.test @@ -24,7 +24,7 @@ # row format slow queries do not get slow query logged. source include/master-slave.inc; -source include/have_binlog_format_mixed_or_statement.inc; +source include/have_binlog_format_statement.inc; # Prepare slave for different long_query_time we need to stop the slave diff --git a/mysql-test/suite/rpl/t/rpl_trigger.test b/mysql-test/suite/rpl/t/rpl_trigger.test index a7547a14433..e296da01bad 100644 --- a/mysql-test/suite/rpl/t/rpl_trigger.test +++ b/mysql-test/suite/rpl/t/rpl_trigger.test @@ -5,6 +5,8 @@ --source include/have_binlog_format_mixed_or_statement.inc --source include/master-slave.inc +CALL mtr.add_suppression("Statement may not be safe to log in statement format."); + --disable_warnings DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; @@ -91,7 +93,11 @@ end | delimiter ;| +# The trigger causes a warning for unsafe statement when +# binlog_format=statement since it uses get_lock. +--disable_warnings insert into t1 set a = now(); +--enable_warnings select a=b && a=c from t1; let $time=`select a from t1`; @@ -137,7 +143,11 @@ disconnect con2; truncate table t1; drop trigger t1_first; +# The trigger causes a warning for unsafe statement when +# binlog_format=statement since it uses get_lock. +--disable_warnings insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now()); +--enable_warnings select a=b && a=c from t1; drop function bug12480; diff --git a/mysql-test/suite/rpl/t/rpl_typeconv-slave.opt b/mysql-test/suite/rpl/t/rpl_typeconv-slave.opt new file mode 100644 index 00000000000..73ca7001985 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_typeconv-slave.opt @@ -0,0 +1 @@ +--innodb
\ No newline at end of file diff --git a/mysql-test/suite/rpl/t/rpl_typeconv.test b/mysql-test/suite/rpl/t/rpl_typeconv.test new file mode 100644 index 00000000000..2a6a3f3b33d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_typeconv.test @@ -0,0 +1,69 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +connection slave; +set @saved_slave_type_conversions = @@global.slave_type_conversions; +CREATE TABLE type_conversions ( + TestNo INT AUTO_INCREMENT PRIMARY KEY, + Source TEXT, + Target TEXT, + Flags TEXT, + On_Master TEXT, + On_Slave TEXT, + Expected TEXT, + Compare INT, + Error TEXT); + +SELECT @@global.slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +SELECT @@global.slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +SELECT @@global.slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY'; +SELECT @@global.slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY'; +SELECT @@global.slave_type_conversions; +--error ER_WRONG_VALUE_FOR_VAR +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY,NONEXISTING_BIT'; +SELECT @@global.slave_type_conversions; + +# Checking strict interpretation of type conversions +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +source extra/rpl_tests/type_conversions.test; + +# Checking lossy integer type conversions +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +source extra/rpl_tests/type_conversions.test; + +# Checking non-lossy integer type conversions +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY'; +source extra/rpl_tests/type_conversions.test; + +# Checking all type conversions +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY'; +source extra/rpl_tests/type_conversions.test; + +connection slave; +--echo **** Result of conversions **** +disable_query_log; +SELECT RPAD(Source, 15, ' ') AS Source_Type, + RPAD(Target, 15, ' ') AS Target_Type, + RPAD(Flags, 25, ' ') AS All_Type_Conversion_Flags, + IF(Compare IS NULL AND Error IS NOT NULL, '<Correct error>', + IF(Compare, '<Correct value>', + CONCAT("'", On_Slave, "' != '", Expected, "'"))) + AS Value_On_Slave + FROM type_conversions; +enable_query_log; +DROP TABLE type_conversions; + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +set global slave_type_conversions = @saved_slave_type_conversions; + diff --git a/mysql-test/suite/rpl/t/rpl_typeconv_innodb.test b/mysql-test/suite/rpl/t/rpl_typeconv_innodb.test new file mode 100644 index 00000000000..729a622348f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_typeconv_innodb.test @@ -0,0 +1,29 @@ +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +# +# BUG#49618: Field length stored incorrectly in binary log for InnoDB +# + +source include/reset_master_and_slave.inc; + +connection slave; +SET @saved_slave_type_conversions = @@GLOBAL.SLAVE_TYPE_CONVERSIONS; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = ''; + +connection master; +CREATE TABLE t1(b1 BIT(1), b2 BIT(2), b3 BIT(3)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (b'0', b'01', b'101'); +sync_slave_with_master; + +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result index 8a32cff0cd3..e08d21b4dcb 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result @@ -9,6 +9,8 @@ call mtr.add_suppression("Slave: Unknown table 't6' Error_code: 1051"); *** On Slave *** STOP SLAVE; RESET SLAVE; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; CREATE TABLE t1 (a INT, b INT PRIMARY KEY, c CHAR(20), d FLOAT DEFAULT '2.00', e CHAR(4) DEFAULT 'TEST') @@ -32,6 +34,7 @@ a b c d e 1 2 TEXAS NULL NULL 2 1 AUSTIN NULL NULL 3 4 QA NULL NULL +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; *** Drop t1 *** DROP TABLE t1; *** Create t2 on slave *** @@ -73,8 +76,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Last_Errno 1641 +Last_Error Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -91,8 +94,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Last_SQL_Errno 1641 +Last_SQL_Error Column 2 of table 'test.t2' cannot be converted from type 'char(10)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 STOP SLAVE; @@ -142,8 +145,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Last_Errno 1641 +Last_Error Column 0 of table 'test.t3' cannot be converted from type 'tinyblob' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -160,8 +163,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Last_SQL_Errno 1641 +Last_SQL_Error Column 0 of table 'test.t3' cannot be converted from type 'tinyblob' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -206,8 +209,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Last_Errno 1641 +Last_Error Column 0 of table 'test.t4' cannot be converted from type 'decimal(8,2)' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -224,8 +227,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Last_SQL_Errno 1641 +Last_SQL_Error Column 0 of table 'test.t4' cannot be converted from type 'decimal(8,2)' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -270,8 +273,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Last_Errno 1641 +Last_Error Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -288,8 +291,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Last_SQL_Errno 1641 +Last_SQL_Error Column 1 of table 'test.t5' cannot be converted from type 'varchar(6)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -333,8 +336,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Last_Errno 1641 +Last_Error Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -351,8 +354,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Last_SQL_Errno 1641 +Last_SQL_Error Column 1 of table 'test.t6' cannot be converted from type 'varchar(6)' to type 'char(5)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; @@ -447,8 +450,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Last_Errno 1641 +Last_Error Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -465,8 +468,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Last_SQL_Errno 1641 +Last_SQL_Error Column 2 of table 'test.t10' cannot be converted from type 'char(5)' to type 'double' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -476,7 +479,7 @@ DROP TABLE t10; *** Create t11 on slave *** STOP SLAVE; RESET SLAVE; -CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT, +CREATE TABLE t11 (a INT KEY, b BLOB, f INT, c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='NDB'; *** Create t11 on Master *** CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254) @@ -510,8 +513,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Last_Errno 1641 +Last_Error Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -528,8 +531,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Last_SQL_Errno 1641 +Last_SQL_Error Column 2 of table 'test.t11' cannot be converted from type 'varchar(254)' to type 'int(11)' Replicate_Ignore_Server_Ids Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; @@ -904,8 +907,8 @@ Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1535 -Last_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 +Last_Errno 1641 +Last_Error Column 0 of table 'test.t17' cannot be converted from type 'bigint' to type 'smallint(6)' Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -922,10 +925,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1535 -Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 -Replicate_Ignore_Server_Ids -Master_Server_Id 1 +Last_SQL_Errno 1641 +Last_SQL_Error Column 0 of table 'test.t17' cannot be converted from type 'bigint' to type 'smallint(6)' SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; ** DROP table t17 *** diff --git a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result index 409397cb3d1..603bb61e2d5 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result @@ -476,6 +476,8 @@ ALTER TABLE t6 MODIFY c CHAR(128) CHARACTER SET utf8 NOT NULL; CREATE TABLE t7 (i INT NOT NULL, c CHAR(255) CHARACTER SET utf8 NOT NULL, j INT NOT NULL) ENGINE = 'NDB' ; +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; [expecting slave to replicate correctly] INSERT INTO t1 VALUES (1, "", 1); INSERT INTO t1 VALUES (2, repeat(_utf8'a', 16), 2); @@ -484,11 +486,7 @@ Comparing tables master:test.t1 and slave:test.t1 INSERT INTO t2 VALUES (1, "", 1); INSERT INTO t2 VALUES (2, repeat(_utf8'a', 16), 2); Comparing tables master:test.t2 and slave:test.t2 -[expecting slave to stop] -INSERT INTO t3 VALUES (1, "", 1); -INSERT INTO t3 VALUES (2, repeat(_utf8'a', 128), 2); -Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 384, test.t3 on slave has size 49. Master's column size should be <= the slave's column size. +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; RESET MASTER; STOP SLAVE; RESET SLAVE; @@ -501,7 +499,7 @@ Comparing tables master:test.t4 and slave:test.t4 INSERT INTO t5 VALUES (1, "", 1); INSERT INTO t5 VALUES (2, repeat(_utf8'a', 255), 2); Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 765, test.t5 on slave has size 49. Master's column size should be <= the slave's column size. +Column 1 of table 'test.t5' cannot be converted from type 'char(255)' to type 'char(16)' RESET MASTER; STOP SLAVE; RESET SLAVE; @@ -510,7 +508,7 @@ START SLAVE; INSERT INTO t6 VALUES (1, "", 1); INSERT INTO t6 VALUES (2, repeat(_utf8'a', 255), 2); Last_SQL_Error -Table definition on master and slave does not match: Column 1 size mismatch - master has size 765, test.t6 on slave has size 385. Master's column size should be <= the slave's column size. +Column 1 of table 'test.t6' cannot be converted from type 'char(255)' to type 'char(128)' RESET MASTER; STOP SLAVE; RESET SLAVE; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index aad3d19455d..90f5b1b0b53 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1623,3 +1623,24 @@ INSERT INTO t1 VALUES('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), SELECT COUNT(t1.a) FROM t1, t1 a, t1 b, t1 c, t1 d, t1 e; DROP TABLE t1; SET @@join_buffer_size= @save_join_buffer_size; + +# +# BUG#47012 archive tables are not upgradeable, and server crashes on any access +# +let $MYSQLD_DATADIR= `SELECT @@datadir`; +copy_file std_data/bug47012.frm $MYSQLD_DATADIR/test/t1.frm; +copy_file std_data/bug47012.ARZ $MYSQLD_DATADIR/test/t1.ARZ; +copy_file std_data/bug47012.ARM $MYSQLD_DATADIR/test/t1.ARM; + +--error ER_TABLE_NEEDS_UPGRADE +SHOW CREATE TABLE t1; + +--error ER_TABLE_NEEDS_UPGRADE +SELECT * FROM t1; + +--error ER_TABLE_NEEDS_UPGRADE +INSERT INTO t1 (col1, col2) VALUES (1, "value"); + +REPAIR TABLE t1; +DROP TABLE t1; +remove_file $MYSQLD_DATADIR/test/t1.ARM; diff --git a/mysql-test/t/bug47671-master.opt b/mysql-test/t/bug47671-master.opt new file mode 100644 index 00000000000..0afdf49e022 --- /dev/null +++ b/mysql-test/t/bug47671-master.opt @@ -0,0 +1 @@ +--default-character-set=utf8 --skip-character-set-client-handshake diff --git a/mysql-test/t/bug47671.test b/mysql-test/t/bug47671.test new file mode 100644 index 00000000000..c3f66a9f502 --- /dev/null +++ b/mysql-test/t/bug47671.test @@ -0,0 +1,9 @@ +# Embedded server doesn't support external clients +--source include/not_embedded.inc + +--echo # +--echo # Bug#47671 - wrong character-set after upgrade from 5.1.34 to 5.1.39 +--echo # +--echo # Extract only charset information from 'status' command output using regex +--replace_regex /.*mysql.*// /Connection.*// /Current.*// /SSL.*// /Using.*// /Server version.*// /Protocol.*// /UNIX.*// /Uptime.*// /Threads.*// /TCP.*// +--exec $MYSQL -e "status"; diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test index 94ad22b80d0..689341391c9 100644 --- a/mysql-test/t/delayed.test +++ b/mysql-test/t/delayed.test @@ -328,4 +328,28 @@ drop table t1; set global low_priority_updates = @old_delayed_updates; + +--echo # +--echo # Bug #47682 strange behaviour of INSERT DELAYED +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +CREATE TABLE t1 (f1 integer); +CREATE TABLE t2 (f1 integer); + +FLUSH TABLES WITH READ LOCK; +LOCK TABLES t1 READ; + +# ER_CANT_UPDATE_WITH_READLOCK with normal execution +# ER_TABLE_NOT_LOCKED when executed as prepared statement +--error ER_CANT_UPDATE_WITH_READLOCK, ER_TABLE_NOT_LOCKED +INSERT DELAYED INTO t2 VALUES (1); + +UNLOCK TABLES; +DROP TABLE t1, t2; + + --echo End of 5.1 tests diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index d77f5eb128b..a5dff38c078 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -336,3 +336,25 @@ SELECT * FROM t2; SELECT * FROM t3; DROP TABLE t1, t2, t3; + +--echo # +--echo # Bug #46425 crash in Diagnostics_area::set_ok_status, +--echo # empty statement, DELETE IGNORE +--echo # + +CREATE table t1 (i INTEGER); + +INSERT INTO t1 VALUES (1); + +--delimiter | + +CREATE TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW +BEGIN + INSERT INTO t1 SELECT * FROM t1 AS A; +END | + +--delimiter ; +--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG +DELETE IGNORE FROM t1; + +DROP TABLE t1;
\ No newline at end of file diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index ad7617b9403..378b810fcbb 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -11,7 +11,5 @@ ############################################################################## kill : Bug#37780 2008-12-03 HHunger need some changes to be robust enough for pushbuild. query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically -partition_innodb_builtin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes -partition_innodb_plugin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes -innodb-autoinc : Bug#48482 2009-11-02 svoj innodb-autoinc.test fails with results difference rpl_killed_ddl : Bug#45520: rpl_killed_ddl fails sporadically in pb2 +innodb-autoinc : Bug#49267 2009-12-02 test fails on windows because of different case mode diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 80c8658d35c..4537559509d 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -484,3 +484,44 @@ PREPARE s FROM EXECUTE s; DEALLOCATE PREPARE s; DROP TABLE t1; + +--echo # +--echo # Bug #47930: MATCH IN BOOLEAN MODE returns too many results +--echo # inside subquery +--echo # + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1), (2); + +CREATE TABLE t2 (a int, b2 char(10), FULLTEXT KEY b2 (b2)); +INSERT INTO t2 VALUES (1,'Scargill'); + +CREATE TABLE t3 (a int, b int); +INSERT INTO t3 VALUES (1,1), (2,1); + +--echo # t2 should use full text index +EXPLAIN +SELECT count(*) FROM t1 WHERE + not exists( + SELECT 1 FROM t2, t3 + WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) + ); + +--echo # should return 0 +SELECT count(*) FROM t1 WHERE + not exists( + SELECT 1 FROM t2, t3 + WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) + ); + +--echo # should return 0 +SELECT count(*) FROM t1 WHERE + not exists( + SELECT 1 FROM t2 IGNORE INDEX (b2), t3 + WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE) + ); + +DROP TABLE t1,t2,t3; + + +--echo End of 5.1 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 6e39795a5d6..6dbc8a05789 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1053,4 +1053,35 @@ ORDER BY max; --echo # DROP TABLE t1; +--echo # +--echo # Bug#43668: Wrong comparison and MIN/MAX for YEAR(2) +--echo # +create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime); +insert into t1 values + (98,1998,19980101,"1998-01-01 00:00:00"), + (00,2000,20000101,"2000-01-01 00:00:01"), + (02,2002,20020101,"2002-01-01 23:59:59"), + (60,2060,20600101,"2060-01-01 11:11:11"), + (70,1970,19700101,"1970-11-11 22:22:22"), + (NULL,NULL,NULL,NULL); +select min(f1),max(f1) from t1; +select min(f2),max(f2) from t1; +select min(f3),max(f3) from t1; +select min(f4),max(f4) from t1; +select a.f1 as a, b.f1 as b, a.f1 > b.f1 as gt, + a.f1 < b.f1 as lt, a.f1<=>b.f1 as eq +from t1 a, t1 b; +select a.f1 as a, b.f2 as b, a.f1 > b.f2 as gt, + a.f1 < b.f2 as lt, a.f1<=>b.f2 as eq +from t1 a, t1 b; +select a.f1 as a, b.f3 as b, a.f1 > b.f3 as gt, + a.f1 < b.f3 as lt, a.f1<=>b.f3 as eq +from t1 a, t1 b; +select a.f1 as a, b.f4 as b, a.f1 > b.f4 as gt, + a.f1 < b.f4 as lt, a.f1<=>b.f4 as eq +from t1 a, t1 b; +select *, f1 = f2 from t1; +drop table t1; +--echo # --echo End of 5.1 tests + diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 54cdf8d6cc1..447848013f9 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -632,5 +632,40 @@ DROP DATABASE db1; --echo End of 5.0 tests +# +# Bug #48319: Server crashes on "GRANT/REVOKE ... TO CURRENT_USER" +# + +# work out who we are. +USE mysql; +SELECT LEFT(CURRENT_USER(),INSTR(CURRENT_USER(),'@')-1) INTO @u; +SELECT MID(CURRENT_USER(),INSTR(CURRENT_USER(),'@')+1) INTO @h; +SELECT password FROM user WHERE user=@u AND host=@h INTO @pwd; + +# show current privs. +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; + +# toggle INSERT +UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; + +# show that GRANT ... TO CURRENT_USER() no longer crashes +GRANT INSERT ON *.* TO CURRENT_USER(); +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; +UPDATE user SET insert_priv='N' WHERE user=@u AND host=@h; + +# show that GRANT ... TO CURRENT_USER() IDENTIFIED BY ... works now +GRANT INSERT ON *.* TO CURRENT_USER() IDENTIFIED BY 'keksdose'; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; + +UPDATE user SET password=@pwd WHERE user=@u AND host=@h; +SELECT user,host,password,insert_priv FROM user WHERE user=@u AND host=@h; + +FLUSH PRIVILEGES; + +USE test; + +--echo End of 5.1 tests + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index c09a4fbf490..f623df372fa 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -1016,6 +1016,18 @@ SELECT a, MAX(b) FROM t WHERE b > 0 AND b < 2 GROUP BY a; DROP TABLE t; +--echo # +--echo # Bug #48472: Loose index scan inappropriately chosen for some WHERE +--echo # conditions +--echo # + +CREATE TABLE t (a INT, b INT, INDEX (a,b)); +INSERT INTO t VALUES (2,0), (2,0), (2,1), (2,1); +INSERT INTO t SELECT * FROM t; + +SELECT a, MAX(b) FROM t WHERE 0=b+0 GROUP BY a; + +DROP TABLE t; --echo End of 5.0 tests diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index 3f45bb9d003..4fa5ab022ad 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -620,3 +620,40 @@ SHOW CREATE TABLE T1; INSERT INTO T1 (c2) values (0); SELECT * FROM T1; DROP TABLE T1; + +## +# 49032: Use the correct function to read the AUTOINC column value +# +DROP TABLE IF EXISTS T1; +CREATE TABLE T1(C1 DOUBLE AUTO_INCREMENT KEY, C2 CHAR(10)) ENGINE=InnoDB; +INSERT INTO T1(C1, C2) VALUES (1, 'innodb'), (3, 'innodb'); +# Restart the server +-- source include/restart_mysqld.inc +INSERT INTO T1(C2) VALUES ('innodb'); +SHOW CREATE TABLE T1; +DROP TABLE T1; +CREATE TABLE T1(C1 FLOAT AUTO_INCREMENT KEY, C2 CHAR(10)) ENGINE=InnoDB; +INSERT INTO T1(C1, C2) VALUES (1, 'innodb'), (3, 'innodb'); +# Restart the server +-- source include/restart_mysqld.inc +INSERT INTO T1(C2) VALUES ('innodb'); +SHOW CREATE TABLE T1; +DROP TABLE T1; + +## +# 47720: REPLACE INTO Autoincrement column with negative values +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 SET c1 = 1; +SHOW CREATE TABLE t1; +INSERT INTO t1 SET c1 = 2; +INSERT INTO t1 SET c1 = -1; +SELECT * FROM t1; +-- error ER_DUP_ENTRY,1062 +INSERT INTO t1 SET c1 = -1; +SHOW CREATE TABLE t1; +REPLACE INTO t1 VALUES (-1); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/t/innodb_lock_wait_timeout_1.test b/mysql-test/t/innodb_lock_wait_timeout_1.test index e42e9f3e37c..fcbf2b1cfc7 100644 --- a/mysql-test/t/innodb_lock_wait_timeout_1.test +++ b/mysql-test/t/innodb_lock_wait_timeout_1.test @@ -71,6 +71,40 @@ set autocommit=default; drop table t1; --echo # +--echo # Bug #37183 insert ignore into .. select ... hangs +--echo # after deadlock was encountered +--echo # +connect (con1,localhost,root,,); +create table t1(id int primary key,v int)engine=innodb; +insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +create table t2 like t1; + +--connection con1 +begin; +update t1 set v=id*2 where id=1; + +--connection default +begin; +update t1 set v=id*2 where id=2; + +--connection con1 +--error 1205 +update t1 set v=id*2 where id=2; + +--connection default +--error 1205 +insert ignore into t2 select * from t1 where id=1; +rollback; + +--connection con1 +rollback; + +--connection default +disconnect con1; +drop table t1, t2; + + +--echo # --echo # Bug#41756 Strange error messages about locks from InnoDB --echo # --disable_warnings diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index 7055879ce1a..a2a1113598d 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -489,5 +489,51 @@ EXPLAIN SELECT * FROM t1 WHERE a = 'TEST' AND c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; DROP TABLE t1; +--echo # +--echo # Bug #46175: NULL read_view and consistent read assertion +--echo # + +CREATE TABLE t1(a CHAR(13),KEY(a)) ENGINE=innodb; +CREATE TABLE t2(b DATETIME,KEY(b)) ENGINE=innodb; +INSERT INTO t1 VALUES (),(); +INSERT INTO t2 VALUES (),(); +CREATE OR REPLACE VIEW v1 AS SELECT 1 FROM t2 + WHERE b =(SELECT a FROM t1 LIMIT 1); + +--disable_query_log +--disable_result_log +CONNECT (con1, localhost, root,,); +--enable_query_log +--enable_result_log +CONNECTION default; + +DELIMITER |; +CREATE PROCEDURE p1(num INT) +BEGIN + DECLARE i INT DEFAULT 0; + REPEAT + SHOW CREATE VIEW v1; + SET i:=i+1; + UNTIL i>num END REPEAT; +END| +DELIMITER ;| + +--echo # Should not crash +--disable_query_log +--disable_result_log +--send CALL p1(1000) +CONNECTION con1; +--echo # Should not crash +CALL p1(1000); + +CONNECTION default; +--reap +--enable_query_log +--enable_result_log + +DISCONNECT con1; +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1,t2; --echo End of 5.1 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index cffa6392fa3..7e28358ba8b 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -385,10 +385,16 @@ drop tables t1, t2; # # Bug #27884: mysql --html does not quote HTML special characters in output # ---exec $MYSQL --html test -e "select '< & >' as '<'" +--write_file $MYSQLTEST_VARDIR/tmp/bug27884.sql +SELECT '< & >' AS `<`; +EOF +--exec $MYSQL --html test < $MYSQLTEST_VARDIR/tmp/bug27884.sql + +remove_file $MYSQLTEST_VARDIR/tmp/bug27884.sql; + # -# Bug #27884: mysql client + null byte +# Bug #28203: mysql client + null byte # create table t1 (a char(5)); insert into t1 values ('\0b\0'); @@ -401,5 +407,5 @@ insert into t1 values ('\0b\0'); --exec $MYSQL --xml test -e "select a from t1" drop table t1; ---echo ---echo End of tests + +--echo End of 5.0 tests diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 8f672af40a3..fec5df1a1c7 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -390,4 +390,17 @@ SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP; DROP TABLE t1, t2; +--echo # +--echo # Bug #48475: DISTINCT is ignored with GROUP BY WITH ROLLUP +--echo # and only const tables + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); + +SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP; + +DROP TABLE t1, t2; + --echo End of 5.0 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index ac2bbaaeeac..0b42caa8703 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -867,6 +867,31 @@ SELECT DROP TABLE t1, t2, t3; +--echo # +--echo # Bug #42760: Select doesn't return desired results when we have null +--echo # values +--echo # + +CREATE TABLE t1 ( + a INT, + c INT, + UNIQUE KEY a_c (a,c), + KEY (a)); + +INSERT INTO t1 VALUES (1, 10), (2, NULL); + +--echo # Must use ref-or-null on the a_c index +EXPLAIN +SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c; +--echo # Must return 1 row +SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c; + +DROP TABLE t1; + + +--echo End of 5.0 tests + + # # Bug #35206: select query result different if the key is indexed or not # diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 1dfc53c6232..0ff4b118426 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -15,6 +15,15 @@ drop table if exists t1, t2; --enable_warnings # +# Bug#48276: can't add column if subpartition exists +CREATE TABLE t1 (a INT, b INT) +PARTITION BY LIST (a) +SUBPARTITION BY HASH (b) +(PARTITION p1 VALUES IN (1)); +ALTER TABLE t1 ADD COLUMN c INT; +DROP TABLE t1; + +# # Bug#46639: 1030 (HY000): Got error 124 from storage engine on # INSERT ... SELECT ... CREATE TABLE t1 ( @@ -62,6 +71,17 @@ SHOW CREATE TABLE t1; DROP TABLE t1; # +# Bug#45904: Error when CHARSET=utf8 and subpartitioning +# +create table t1 (a int NOT NULL, b varchar(5) NOT NULL) +default charset=utf8 +partition by list (a) +subpartition by key (b) +(partition p0 values in (1), + partition p1 values in (2)); +drop table t1; + +# # Bug#44059: rec_per_key on empty partition gives weird optimiser results # create table t1 (a int, b int, key(a)) @@ -2031,11 +2051,14 @@ DROP TABLE t1; --echo # --echo # Bug #45807: crash accessing partitioned table and sql_mode --echo # contains ONLY_FULL_GROUP_BY +--echo # Bug#46923: select count(*) from partitioned table fails with +--echo # ONLY_FULL_GROUP_BY --echo # SET SESSION SQL_MODE='ONLY_FULL_GROUP_BY'; CREATE TABLE t1(id INT,KEY(id)) ENGINE=MYISAM PARTITION BY HASH(id) PARTITIONS 2; +SELECT COUNT(*) FROM t1; DROP TABLE t1; SET SESSION SQL_MODE=DEFAULT; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 3a845471cd0..5d5ad180f1a 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1260,4 +1260,57 @@ SELECT str_to_date('', '%Y-%m-%d'); DROP TABLE t1, t2; +--echo # +--echo # Bug#48459: valgrind errors with query using 'Range checked for each +--echo # record' +--echo # +CREATE TABLE t1 ( + a INT, + b CHAR(2), + c INT, + d INT, + KEY ( c ), + KEY ( d, a, b ( 2 ) ), + KEY ( b ( 1 ) ) +); + +INSERT INTO t1 VALUES ( NULL, 'a', 1, 2 ), ( NULL, 'a', 1, 2 ), + ( 1, 'a', 1, 2 ), ( 1, 'a', 1, 2 ); + +CREATE TABLE t2 ( + a INT, + c INT, + e INT, + KEY ( e ) +); + +INSERT INTO t2 VALUES ( 1, 1, NULL ), ( 1, 1, NULL ); + +--echo # Should not give Valgrind warnings +SELECT 1 +FROM t1, t2 +WHERE t1.d <> '1' AND t1.b > '1' +AND t1.a = t2.a AND t1.c = t2.c; + +DROP TABLE t1, t2; + +--echo # +--echo # Bug #48665: sql-bench's insert test fails due to wrong result +--echo # + +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)); + +INSERT INTO t1 VALUES (0,0), (1,1); + +--replace_column 1 @ 2 @ 3 @ 5 @ 6 @ 7 @ 8 @ 9 @ 10 @ +EXPLAIN +SELECT * FROM t1 FORCE INDEX (PRIMARY) + WHERE (a>=1 AND a<=2) OR (a>=4 AND a<=5) OR (a>=0 AND a <=10); + +--echo # Should return 2 rows +SELECT * FROM t1 FORCE INDEX (PRIMARY) + WHERE (a>=1 AND a<=2) OR (a>=4 AND a<=5) OR (a>=0 AND a <=10); + +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 51f0cd73374..ac65e5cbaf5 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3772,6 +3772,19 @@ INTO @var0; DROP TABLE t1; +--echo # +--echo # Bug #48458: simple query tries to allocate enormous amount of +--echo # memory +--echo # + +CREATE TABLE t1(a INT NOT NULL, b YEAR); +INSERT INTO t1 VALUES (); +CREATE TABLE t2(c INT); +--echo # Should not err out because of out-of-memory +SELECT 1 FROM t2 JOIN t1 ON 1=1 + WHERE a != '1' AND NOT a >= b OR NOT ROW(b,a )<> ROW(a,a); +DROP TABLE t1,t2; + --echo End of 5.0 tests @@ -3918,4 +3931,37 @@ SELECT table1 .`time_key` field2 FROM B table1 LEFT JOIN BB JOIN A table5 ON drop table A,AA,B,BB; --echo #end of test for bug#45266 + +--echo # +--echo # BUG#48052: Valgrind warning - uninitialized value in init_read_record() +--echo # + +# Needed in 6.0 codebase +#--echo # Disable Index condition pushdown +#--replace_column 1 # +#SELECT @old_icp:=@@engine_condition_pushdown; +#SET SESSION engine_condition_pushdown = 'OFF'; + +CREATE TABLE t1 ( + pk int(11) NOT NULL, + i int(11) DEFAULT NULL, + v varchar(1) DEFAULT NULL, + PRIMARY KEY (pk) +); + +INSERT INTO t1 VALUES (2,7,'m'); +INSERT INTO t1 VALUES (3,9,'m'); + +SELECT v +FROM t1 +WHERE NOT pk > 0 +HAVING v <= 't' +ORDER BY pk; + +# Needed in 6.0 codebase +#--echo # Restore old value for Index condition pushdown +#SET SESSION engine_condition_pushdown=@old_icp; + +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/sp-destruct.test b/mysql-test/t/sp-destruct.test index 14c38a2fdb4..720c24b2c24 100644 --- a/mysql-test/t/sp-destruct.test +++ b/mysql-test/t/sp-destruct.test @@ -12,6 +12,9 @@ # mysqltest should be fixed to allow REPLACE_RESULT in error message -- source include/not_embedded.inc +# Supress warnings written to the log file +call mtr.add_suppression("Column count of mysql.proc is wrong. Expected 20, found 19. The table is probably corrupted"); + # Backup proc table let $MYSQLD_DATADIR= `select @@datadir`; --copy_file $MYSQLD_DATADIR/mysql/proc.frm $MYSQLTEST_VARDIR/tmp/proc.frm @@ -38,15 +41,14 @@ create trigger t1_ai after insert on t1 for each row call bug14233(); # Unsupported tampering with the mysql.proc definition alter table mysql.proc drop type; ---replace_result $MYSQL_TEST_DIR . ---error ER_SP_PROC_TABLE_CORRUPT +--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED call bug14233(); ---replace_result $MYSQL_TEST_DIR . ---error ER_SP_PROC_TABLE_CORRUPT +--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED create view v1 as select bug14233_f(); ---replace_result $MYSQL_TEST_DIR . ---error ER_SP_PROC_TABLE_CORRUPT +--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED insert into t1 values (0); +--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED +show procedure status; flush table mysql.proc; @@ -155,3 +157,43 @@ drop procedure bug14233_3; # Assert: These should show nothing. show procedure status where db=DATABASE(); show function status where db=DATABASE(); + +# +# Bug#41726 upgrade from 5.0 to 5.1.30 crashes if you didn't run mysql_upgrade +# + + +--disable_warnings +DROP TABLE IF EXISTS proc_backup; +DROP PROCEDURE IF EXISTS p1; +--enable_warnings + +--echo # Backup the proc table + +RENAME TABLE mysql.proc TO proc_backup; +CREATE TABLE mysql.proc LIKE proc_backup; +FLUSH TABLE mysql.proc; + +--echo # Test with a valid table. + +CREATE PROCEDURE p1() + SET @foo = 10; +CALL p1(); +--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00' +SHOW PROCEDURE STATUS; + +--echo # Modify a field of the table. + +ALTER TABLE mysql.proc MODIFY comment CHAR (32); + +--error ER_CANNOT_LOAD_FROM_TABLE +CREATE PROCEDURE p2() + SET @foo = 10; +--echo # Procedure loaded from the cache +CALL p1(); +--error ER_CANNOT_LOAD_FROM_TABLE +SHOW PROCEDURE STATUS; + +DROP TABLE mysql.proc; +RENAME TABLE proc_backup TO mysql.proc; +FLUSH TABLE mysql.proc; diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index a80fe89082a..96f82c92248 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -865,6 +865,65 @@ DROP PROCEDURE p_suid; DROP FUNCTION f_suid; DROP TABLE t1; +--echo # +--echo # Bug #48872 : Privileges for stored functions ignored if function name +--echo # is mixed case +--echo # + +CREATE DATABASE B48872; +USE B48872; +CREATE TABLE `TestTab` (id INT); +INSERT INTO `TestTab` VALUES (1),(2); +CREATE FUNCTION `f_Test`() RETURNS INT RETURN 123; +CREATE FUNCTION `f_Test_denied`() RETURNS INT RETURN 123; +CREATE USER 'tester'; +CREATE USER 'Tester'; +GRANT SELECT ON TABLE `TestTab` TO 'tester'; +GRANT EXECUTE ON FUNCTION `f_Test` TO 'tester'; +GRANT EXECUTE ON FUNCTION `f_Test_denied` TO 'Tester'; + +SELECT f_Test(); +SELECT * FROM TestTab; + +CONNECT (con_tester,localhost,tester,,B48872); +CONNECT (con_tester_denied,localhost,Tester,,B48872); +CONNECTION con_tester; + +SELECT * FROM TestTab; +SELECT `f_Test`(); +SELECT `F_TEST`(); +SELECT f_Test(); +SELECT F_TEST(); + +CONNECTION con_tester_denied; + +--disable_result_log +--error ER_TABLEACCESS_DENIED_ERROR +SELECT * FROM TestTab; +--error ER_PROCACCESS_DENIED_ERROR +SELECT `f_Test`(); +--error ER_PROCACCESS_DENIED_ERROR +SELECT `F_TEST`(); +--error ER_PROCACCESS_DENIED_ERROR +SELECT f_Test(); +--error ER_PROCACCESS_DENIED_ERROR +SELECT F_TEST(); +--enable_result_log +SELECT `f_Test_denied`(); +SELECT `F_TEST_DENIED`(); + +CONNECTION default; +DISCONNECT con_tester; +DISCONNECT con_tester_denied; +DROP TABLE `TestTab`; +DROP FUNCTION `f_Test`; +DROP FUNCTION `f_Test_denied`; + +USE test; +DROP USER 'tester'; +DROP USER 'Tester'; +DROP DATABASE B48872; + --echo End of 5.0 tests. # Wait till all disconnects are completed diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 5a41c6e3ac8..2b7e89c106b 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -8258,6 +8258,73 @@ CALL p1; DROP PROCEDURE p1; DROP TABLE t1, t2; +--echo # +--echo # Bug#47627: SET @@{global.session}.local_variable in stored routine causes crash +--echo # Bug#48626: Crash or lost connection using SET for declared variables with @@ +--echo # + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +--enable_warnings + +delimiter //; + +--error ER_UNKNOWN_SYSTEM_VARIABLE +CREATE PROCEDURE p1() +BEGIN + DECLARE v INT DEFAULT 0; + SET @@SESSION.v= 10; +END// + +CREATE PROCEDURE p2() +BEGIN + DECLARE v INT DEFAULT 0; + SET v= 10; +END// +call p2()// + +--error ER_UNKNOWN_SYSTEM_VARIABLE +CREATE PROCEDURE p3() +BEGIN + DECLARE v INT DEFAULT 0; + SELECT @@SESSION.v; +END// + +--error ER_UNKNOWN_SYSTEM_VARIABLE +CREATE PROCEDURE p4() +BEGIN + DECLARE v INT DEFAULT 0; + SET @@GLOBAL.v= 10; +END// + +CREATE PROCEDURE p5() +BEGIN + DECLARE init_connect INT DEFAULT 0; + SET init_connect= 10; + SET @@GLOBAL.init_connect= 'SELECT 1'; + SET @@SESSION.IDENTITY= 1; + SELECT @@SESSION.IDENTITY; + SELECT @@GLOBAL.init_connect; + SELECT init_connect; +END// + +--error ER_UNKNOWN_SYSTEM_VARIABLE +CREATE PROCEDURE p6() +BEGIN + DECLARE v INT DEFAULT 0; + SET @@v= 0; +END// + +delimiter ;// + +SET @old_init_connect= @@GLOBAL.init_connect; +CALL p5(); +SET @@GLOBAL.init_connect= @old_init_connect; + +DROP PROCEDURE p2; +DROP PROCEDURE p5; --echo # ------------------------------------------------------------------ --echo # -- End of 5.1 tests diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index cd3c3f81510..2cf7ab8fbdf 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1286,3 +1286,229 @@ CREATE TABLE t1 SELECT 1 % .1234567891234567891234567891234567891234567891234567 DESCRIBE t1; SELECT my_col FROM t1; DROP TABLE t1; + +--echo # +--echo # Bug#45261: Crash, stored procedure + decimal +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 SELECT + /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001 + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001. + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + .100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + .123456789012345678901234567890123456789012345678901234567890123456 /* 66 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +--echo # +--echo # Test that the integer and decimal parts are properly calculated. +--echo # + +CREATE TABLE t1 (a DECIMAL(30,30)); +INSERT INTO t1 VALUES (0.1),(0.2),(0.3); +CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1; +DESC t2; +DROP TABLE t1,t2; + +CREATE TABLE t1 (a DECIMAL(30,30)); +INSERT INTO t1 VALUES (0.1),(0.2),(0.3); +CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1; +DESC t2; +DROP TABLE t1,t2; + +CREATE TABLE t1 (a DECIMAL(30,30)); +INSERT INTO t1 VALUES (0.1),(0.2),(0.3); +CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1; +DESC t2; +DROP TABLE t1,t2; + +--echo # +--echo # Test that variables get maximum precision. +--echo # + +SET @decimal= 1.1; +CREATE TABLE t1 SELECT @decimal AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +--echo # +--echo # Bug #45261 : Crash, stored procedure + decimal +--echo # Original test by the reporter. +--echo # + +--echo # should not crash +CREATE TABLE t1 +SELECT .123456789012345678901234567890123456789012345678901234567890123456 AS a; +DROP TABLE t1; + +delimiter |; +CREATE PROCEDURE test_proc() +BEGIN + # The las non critical CUSER definition is: + # DECLARE mycursor CURSOR FOR SELECT 1 % + # .12345678912345678912345678912345678912345678912345678912345678912 AS my_col; + DECLARE mycursor CURSOR FOR +SELECT 1 % +.123456789123456789123456789123456789123456789123456789123456789123456789123456789 + AS my_col; + + OPEN mycursor; + CLOSE mycursor; +END| +delimiter ;| +--echo # should not crash +CALL test_proc(); +DROP PROCEDURE test_proc; + +--echo # +--echo # Bug #48370 Absolutely wrong calculations with GROUP BY and +--echo # decimal fields when using IF +--echo # + +CREATE TABLE currencies (id int, rate decimal(16,4), + PRIMARY KEY (id), KEY (rate)); + +INSERT INTO currencies VALUES (11,0.7028); +INSERT INTO currencies VALUES (1,1); + +CREATE TABLE payments ( + id int, + supplier_id int, + status int, + currency_id int, + vat decimal(7,4), + PRIMARY KEY (id), + KEY currency_id (currency_id), + KEY supplier_id (supplier_id) +); + +INSERT INTO payments (id,status,vat,supplier_id,currency_id) VALUES +(3001,2,0.0000,344,11), (1,2,0.0000,1,1); + +CREATE TABLE sub_tasks ( + id int, + currency_id int, + price decimal(16,4), + discount decimal(10,4), + payment_id int, + PRIMARY KEY (id), + KEY currency_id (currency_id), + KEY payment_id (payment_id) +) ; + +INSERT INTO sub_tasks (id, price, discount, payment_id, currency_id) VALUES +(52, 12.60, 0, 3001, 11), (56, 14.58, 0, 3001, 11); + +--echo # should return 1 and the same values in col 2 and 3 +select STRAIGHT_JOIN + (1 + PAY.vat) AS mult, + SUM(ROUND((SUB.price - ROUND(ROUND(SUB.price, 2) * SUB.discount, 2)) * + CUR.rate / CUR.rate, 2) + ) v_net_with_discount, + + SUM(ROUND((SUB.price - ROUND(ROUND(SUB.price, 2) * SUB.discount, 1)) * + CUR.rate / CUR.rate , 2) + * (1 + PAY.vat) + ) v_total +from + currencies CUR, payments PAY, sub_tasks SUB +where + SUB.payment_id = PAY.id and + PAY.currency_id = CUR.id and + PAY.id > 2 +group by PAY.id + 1; + +DROP TABLE currencies, payments, sub_tasks; + + +--echo End of 5.1 tests diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index f444e0f0c94..d24f328cdf0 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -438,17 +438,17 @@ invalid value '%s'", else if (optp->arg_type == OPT_ARG && (((optp->var_type & GET_TYPE_MASK) == GET_BOOL) || (optp->var_type & GET_TYPE_MASK) == GET_ENUM)) - { - if (optend == disabled_my_option) - *((my_bool*) value)= (my_bool) 0; - else - { - if (!optend) /* No argument -> enable option */ - *((my_bool*) value)= (my_bool) 1; - else - argument= optend; - } - } + { + if (optend == disabled_my_option) + init_one_value(optp, value, 0); + else + { + if (!optend) /* No argument -> enable option */ + init_one_value(optp, value, 1); + else + argument= optend; + } + } else if (optp->arg_type == REQUIRED_ARG && !optend) { /* Check if there are more arguments after this one, diff --git a/mysys/my_sync.c b/mysys/my_sync.c index ba6964b00d6..97540f5eb48 100644 --- a/mysys/my_sync.c +++ b/mysys/my_sync.c @@ -103,11 +103,11 @@ static const char cur_dir_name[]= {FN_CURLIB, 0}; int my_sync_dir(const char *dir_name, myf my_flags) { #ifdef NEED_EXPLICIT_SYNC_DIR - DBUG_ENTER("my_sync_dir"); - DBUG_PRINT("my",("Dir: '%s' my_flags: %d", dir_name, my_flags)); File dir_fd; int res= 0; const char *correct_dir_name; + DBUG_ENTER("my_sync_dir"); + DBUG_PRINT("my",("Dir: '%s' my_flags: %d", dir_name, my_flags)); /* Sometimes the path does not contain an explicit directory */ correct_dir_name= (dir_name[0] == 0) ? cur_dir_name : dir_name; /* diff --git a/mysys/typelib.c b/mysys/typelib.c index a0fe8a96a89..cb72c91e20d 100644 --- a/mysys/typelib.c +++ b/mysys/typelib.c @@ -184,7 +184,7 @@ my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err) i= x; while (*x && *x != field_separator) x++; - if (x[0] && x[1]) // skip separator if found + if (x[0] && x[1]) /* skip separator if found */ x++; if ((find= find_type(i, lib, 2 | 8) - 1) < 0) DBUG_RETURN(0); diff --git a/scripts/make_win_bin_dist b/scripts/make_win_bin_dist index c65439181ef..a08a41bb283 100755 --- a/scripts/make_win_bin_dist +++ b/scripts/make_win_bin_dist @@ -340,7 +340,7 @@ mkdir $DESTDIR/mysql-test cp mysql-test/mysql-test-run.pl $DESTDIR/mysql-test/ cp mysql-test/mysql-stress-test.pl $DESTDIR/mysql-test/ cp mysql-test/README $DESTDIR/mysql-test/ -cp -R mysql-test/{t,r,include,suite,std_data,lib} $DESTDIR/mysql-test/ +cp -R mysql-test/{t,r,include,suite,std_data,lib,collections} $DESTDIR/mysql-test/ # Note that this will not copy "extra" if a soft link if [ -d mysql-test/extra ] ; then diff --git a/scripts/mysql_secure_installation.pl.in b/scripts/mysql_secure_installation.pl.in index 4eeb50e6d2f..25339f9b916 100755 --- a/scripts/mysql_secure_installation.pl.in +++ b/scripts/mysql_secure_installation.pl.in @@ -17,16 +17,41 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use Fcntl; +use File::Spec; +use if $^O eq 'MSWin32', 'Term::ReadKey' => qw/ReadMode/; use strict; my $config = ".my.cnf.$$"; my $command = ".mysql.$$"; my $hadpass = 0; +my $mysql; # How to call the mysql client +my $rootpass = ""; -# FIXME -# trap "interrupt" 2 -my $rootpass = ""; +$SIG{QUIT} = $SIG{INT} = sub { + print "\nAborting!\n\n"; + echo_on(); + cleanup(); + exit 1; +}; + + +END { + # Remove temporary files, even if exiting via die(), etc. + cleanup(); +} + + +sub read_without_echo { + my ($prompt) = @_; + print $prompt; + echo_off(); + my $answer = <STDIN>; + echo_on(); + print "\n"; + chomp($answer); + return $answer; +} sub echo_on { if ($^O eq 'MSWin32') { @@ -55,6 +80,25 @@ sub write_file { } sub prepare { + # Locate the mysql client; look in current directory first, then + # in path + our $SAVEERR; # Suppress Perl warning message + open SAVEERR, ">& STDERR"; + close STDERR; + for my $m (File::Spec->catfile('bin', 'mysql'), 'mysql') { + # mysql --version should always work + qx($m --no-defaults --version); + next unless $? == 0; + + $mysql = $m; + last; + } + open STDERR, ">& SAVEERR"; + + die "Can't find a 'mysql' client in PATH or ./bin\n" + unless $mysql; + + # Create safe files to avoid leaking info to other users foreach my $file ( $config, $command ) { next if -f $file; # Already exists local *FILE; @@ -64,30 +108,50 @@ sub prepare { } } +# Simple escape mechanism (\-escape any ' and \), suitable for two contexts: +# - single-quoted SQL strings +# - single-quoted option values on the right hand side of = in my.cnf +# +# These two contexts don't handle escapes identically. SQL strings allow +# quoting any character (\C => C, for any C), but my.cnf parsing allows +# quoting only \, ' or ". For example, password='a\b' quotes a 3-character +# string in my.cnf, but a 2-character string in SQL. +# +# This simple escape works correctly in both places. +sub basic_single_escape { + my ($str) = @_; + # Inside a character class, \ is not special; this escapes both \ and ' + $str =~ s/([\'])/\\$1/g; + return $str; +} + sub do_query { my $query = shift; write_file($command, $query); - system("mysql --defaults-file=$config < $command"); - return $?; + my $rv = system("$mysql --defaults-file=$config < $command"); + # system() returns -1 if exec fails (e.g., command not found, etc.); die + # in this case because nothing is going to work + die "Failed to execute mysql client '$mysql'\n" if $rv == -1; + # Return true if query executed OK, or false if there was some problem + # (for example, SQL error or wrong password) + return ($rv == 0 ? 1 : undef); } sub make_config { my $password = shift; + my $esc_pass = basic_single_escape($rootpass); write_file($config, "# mysql_secure_installation config file", "[mysql]", "user=root", - "password=$rootpass"); + "password='$esc_pass'"); } sub get_root_password { - my $status = 1; - while ( $status == 1 ) { - echo_off(); - print "Enter current password for root (enter for none): "; - my $password = <STDIN>; - echo_on(); + my $attempts = 3; + for (;;) { + my $password = read_without_echo("Enter current password for root (enter for none): "); if ( $password ) { $hadpass = 1; } else { @@ -95,64 +159,56 @@ sub get_root_password { } $rootpass = $password; make_config($rootpass); - do_query(""); - $status = $?; + last if do_query(""); + + die "Unable to connect to the server as root user, giving up.\n" + if --$attempts == 0; } print "OK, successfully used password, moving on...\n\n"; } sub set_root_password { - echo_off(); - print "New password: "; - my $password1 = <STDIN>; - print "\nRe-enter new password: "; - my $password2 = <STDIN>; - print "\n"; - echo_on(); + my $password1; + for (;;) { + $password1 = read_without_echo("New password: "); - if ( $password1 eq $password2 ) { - print "Sorry, passwords do not match.\n\n"; - return 1; - } + if ( !$password1 ) { + print "Sorry, you can't use an empty password here.\n\n"; + next; + } - if ( !$password1 ) { - print "Sorry, you can't use an empty password here.\n\n"; - return 1; - } + my $password2 = read_without_echo("Re-enter new password: "); - do_query("UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';"); - if ( $? == 0 ) { - print "Password updated successfully!\n"; - print "Reloading privilege tables..\n"; - if ( !reload_privilege_tables() ) { - exit 1; + if ( $password1 ne $password2 ) { + print "Sorry, passwords do not match.\n\n"; + next; } - print "\n"; - $rootpass = $password1; - make_config($rootpass); - } else { - print "Password update failed!\n"; - exit 1; + + last; } - return 0; + my $esc_pass = basic_single_escape($password1); + do_query("UPDATE mysql.user SET Password=PASSWORD('$esc_pass') WHERE User='root';") + or die "Password update failed!\n"; + + print "Password updated successfully!\n"; + print "Reloading privilege tables..\n"; + reload_privilege_tables() + or die "Can not continue.\n"; + + print "\n"; + $rootpass = $password1; + make_config($rootpass); } sub remove_anonymous_users { - do_query("DELETE FROM mysql.user WHERE User='';"); - if ( $? == 0 ) { - print " ... Success!\n"; - } else { - print " ... Failed!\n"; - exit 1; - } - - return 0; + do_query("DELETE FROM mysql.user WHERE User='';") + or die print " ... Failed!\n"; + print " ... Success!\n"; } sub remove_remote_root { - do_query("DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';"); - if ( $? == 0 ) { + if (do_query("DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';")) { print " ... Success!\n"; } else { print " ... Failed!\n"; @@ -161,44 +217,31 @@ sub remove_remote_root { sub remove_test_database { print " - Dropping test database...\n"; - do_query("DROP DATABASE test;"); - if ( $? == 0 ) { + if (do_query("DROP DATABASE test;")) { print " ... Success!\n"; } else { print " ... Failed! Not critical, keep moving...\n"; } print " - Removing privileges on test database...\n"; - do_query("DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'"); - if ( $? == 0 ) { + if (do_query("DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'")) { print " ... Success!\n"; } else { print " ... Failed! Not critical, keep moving...\n"; } - - return 0; } sub reload_privilege_tables { - do_query("FLUSH PRIVILEGES;"); - if ( $? == 0 ) { + if (do_query("FLUSH PRIVILEGES;")) { print " ... Success!\n"; - return 0; + return 1; } else { print " ... Failed!\n"; - return 1; + return undef; } } -sub interrupt { - print "\nAborting!\n\n"; - cleanup(); - echo_on(); - exit 1; -} - sub cleanup { - print "Cleaning up...\n"; unlink($config,$command); } @@ -242,11 +285,7 @@ my $reply = <STDIN>; if ( $reply =~ /n/i ) { print " ... skipping.\n"; } else { - my $status = 1; - while ( $status == 1 ) { - set_root_password(); - $status = $?; - } + set_root_password(); } print "\n"; @@ -334,8 +373,6 @@ if ( $reply =~ /n/i ) { } print "\n"; -cleanup(); - print <<HERE; diff --git a/scripts/mysql_secure_installation.sh b/scripts/mysql_secure_installation.sh index 6c2d88d6d29..25d6343ee2c 100644 --- a/scripts/mysql_secure_installation.sh +++ b/scripts/mysql_secure_installation.sh @@ -38,16 +38,39 @@ prepare() { } do_query() { - echo $1 >$command + echo "$1" >$command + #sed 's,^,> ,' < $command # Debugging mysql --defaults-file=$config <$command return $? } +# Simple escape mechanism (\-escape any ' and \), suitable for two contexts: +# - single-quoted SQL strings +# - single-quoted option values on the right hand side of = in my.cnf +# +# These two contexts don't handle escapes identically. SQL strings allow +# quoting any character (\C => C, for any C), but my.cnf parsing allows +# quoting only \, ' or ". For example, password='a\b' quotes a 3-character +# string in my.cnf, but a 2-character string in SQL. +# +# This simple escape works correctly in both places. +basic_single_escape () { + # The quoting on this sed command is a bit complex. Single-quoted strings + # don't allow *any* escape mechanism, so they cannot contain a single + # quote. The string sed gets (as argv[1]) is: s/\(['\]\)/\\\1/g + # + # Inside a character class, \ and ' are not special, so the ['\] character + # class is balanced and contains two characters. + echo "$1" | sed 's/\(['"'"'\]\)/\\\1/g' +} + make_config() { echo "# mysql_secure_installation config file" >$config echo "[mysql]" >>$config echo "user=root" >>$config - echo "password=$rootpass" >>$config + esc_pass=`basic_single_escape "$rootpass"` + echo "password='$esc_pass'" >>$config + #sed 's,^,> ,' < $config # Debugging } get_root_password() { @@ -94,13 +117,12 @@ set_root_password() { return 1 fi - do_query "UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';" + esc_pass=`basic_single_escape "$password1"` + do_query "UPDATE mysql.user SET Password=PASSWORD('$esc_pass') WHERE User='root';" if [ $? -eq 0 ]; then echo "Password updated successfully!" echo "Reloading privilege tables.." - if ! reload_privilege_tables; then - exit 1 - fi + reload_privilege_tables || exit 1 echo rootpass=$password1 make_config diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 8faab5023da..9f3863eb2b0 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -26,7 +26,7 @@ */ static -const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = +const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] = { { { C_STRING_WITH_LEN("db") }, @@ -151,6 +151,24 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = } }; +static const TABLE_FIELD_DEF + event_table_def= {ET_FIELD_COUNT, event_table_fields}; + +class Event_db_intact : public Table_check_intact +{ +protected: + void report_error(uint, const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + error_log_print(ERROR_LEVEL, fmt, args); + va_end(args); + } +}; + +/** In case of an error, a message is printed to the error log. */ +static Event_db_intact table_intact; + /** Puts some data common to CREATE and ALTER EVENT into a row. @@ -1117,10 +1135,8 @@ Event_db_repository::check_system_tables(THD *thd) } else { - if (table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT, - mysql_db_table_fields)) + if (table_intact.check(tables.table, &mysql_db_table_def)) ret= 1; - /* in case of an error, the message is printed inside table_check_intact */ close_thread_tables(thd); } @@ -1154,9 +1170,8 @@ Event_db_repository::check_system_tables(THD *thd) } else { - if (table_check_intact(tables.table, ET_FIELD_COUNT, event_table_fields)) + if (table_intact.check(tables.table, &event_table_def)) ret= 1; - /* in case of an error, the message is printed inside table_check_intact */ close_thread_tables(thd); } diff --git a/sql/field.cc b/sql/field.cc index 354c911e1c0..21082550ba7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -59,6 +59,8 @@ const char field_separator=','; #define ASSERT_COLUMN_MARKED_FOR_READ DBUG_ASSERT(!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))) #define ASSERT_COLUMN_MARKED_FOR_WRITE DBUG_ASSERT(!table || (!table->write_set || bitmap_is_set(table->write_set, field_index))) +#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "") + /* Rules for merging different types of fields in UNION @@ -997,6 +999,22 @@ test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend) /** + Function to compare two unsigned integers for their relative order. + Used below. In an anonymous namespace to not clash with definitions + in other files. + */ +namespace { + int compare(unsigned int a, unsigned int b) + { + if (a < b) + return -1; + if (b < a) + return 1; + return 0; +} +} + +/** Detect Item_result by given field type of UNION merge result. @param field_type given field type @@ -1367,22 +1385,48 @@ bool Field::send_binary(Protocol *protocol) /** Check to see if field size is compatible with destination. - This method is used in row-based replication to verify that the slave's - field size is less than or equal to the master's field size. The - encoded field metadata (from the master or source) is decoded and compared - to the size of this field (the slave or destination). + This method is used in row-based replication to verify that the + slave's field size is less than or equal to the master's field + size. The encoded field metadata (from the master or source) is + decoded and compared to the size of this field (the slave or + destination). + + @note + + The comparison is made so that if the source data (from the master) + is less than the target data (on the slave), -1 is returned in @c + <code>*order_var</code>. This implies that a conversion is + necessary, but that it is lossy and can result in truncation of the + value. + + If the source data is strictly greater than the target data, 1 is + returned in <code>*order_var</code>. This implies that the source + type can is contained in the target type and that a conversion is + necessary but is non-lossy. + + If no conversion is required to fit the source type in the target + type, 0 is returned in <code>*order_var</code>. @param field_metadata Encoded size in field metadata + @param mflags Flags from the table map event for the table. + @param order_var Pointer to variable where the order + between the source field and this field + will be returned. - @retval 0 if this field's size is < the source field's size - @retval 1 if this field's size is >= the source field's size + @return @c true if this field's size is compatible with the + master's field size, @c false otherwise. */ -int Field::compatible_field_size(uint field_metadata, - const Relay_log_info *rli_arg __attribute__((unused))) +bool Field::compatible_field_size(uint field_metadata, + Relay_log_info *rli_arg __attribute__((unused)), + uint16 mflags __attribute__((unused)), + int *order_var) { uint const source_size= pack_length_from_metadata(field_metadata); uint const destination_size= row_pack_length(); - return (source_size <= destination_size); + DBUG_PRINT("debug", ("real_type: %d, source_size: %u, destination_size: %u", + real_type(), source_size, destination_size)); + *order_var = compare(source_size, destination_size); + return true; } @@ -2486,6 +2530,50 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg, } +Field *Field_new_decimal::create_from_item (Item *item) +{ + uint8 dec= item->decimals; + uint8 intg= item->decimal_precision() - dec; + uint32 len= item->max_length; + + DBUG_ASSERT (item->result_type() == DECIMAL_RESULT); + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + signed int overflow; + + dec= min(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + +1: for decimal point + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, + item->unsigned_flag); + + overflow= required_length - len; + + if (overflow > 0) + dec= max(0, dec - overflow); // too long, discard fract + else + /* Corrected value fits. */ + len= required_length; + } + return new Field_new_decimal(len, item->maybe_null, item->name, + dec, item->unsigned_flag); +} + + int Field_new_decimal::reset(void) { store_value(&decimal_zero); @@ -2822,33 +2910,16 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) } -/** - Check to see if field size is compatible with destination. - - This method is used in row-based replication to verify that the slave's - field size is less than or equal to the master's field size. The - encoded field metadata (from the master or source) is decoded and compared - to the size of this field (the slave or destination). - - @param field_metadata Encoded size in field metadata - - @retval 0 if this field's size is < the source field's size - @retval 1 if this field's size is >= the source field's size -*/ -int Field_new_decimal::compatible_field_size(uint field_metadata, - const Relay_log_info * __attribute__((unused))) +bool Field_new_decimal::compatible_field_size(uint field_metadata, + Relay_log_info * __attribute__((unused)), + uint16 mflags __attribute__((unused)), + int *order_var) { - int compatible= 0; uint const source_precision= (field_metadata >> 8U) & 0x00ff; uint const source_decimal= field_metadata & 0x00ff; - uint const source_size= my_decimal_get_binary_size(source_precision, - source_decimal); - uint const destination_size= row_pack_length(); - compatible= (source_size <= destination_size); - if (compatible) - compatible= (source_precision <= precision) && - (source_decimal <= decimals()); - return (compatible); + int order= compare(source_precision, precision); + *order_var= order != 0 ? order : compare(source_decimal, dec); + return true; } @@ -6611,8 +6682,11 @@ check_field_for_37426(const void *param_arg) } #endif -int Field_string::compatible_field_size(uint field_metadata, - const Relay_log_info *rli_arg) +bool +Field_string::compatible_field_size(uint field_metadata, + Relay_log_info *rli_arg, + uint16 mflags __attribute__((unused)), + int *order_var) { #ifdef HAVE_REPLICATION const Check_field_param check_param = { this }; @@ -6620,7 +6694,7 @@ int Field_string::compatible_field_size(uint field_metadata, check_field_for_37426, &check_param)) return FALSE; // Not compatible field sizes #endif - return Field::compatible_field_size(field_metadata, rli_arg); + return Field::compatible_field_size(field_metadata, rli_arg, mflags, order_var); } @@ -6682,6 +6756,8 @@ uchar *Field_string::pack(uchar *to, const uchar *from, { uint length= min(field_length,max_length); uint local_char_length= max_length/field_charset->mbmaxlen; + DBUG_PRINT("debug", ("Packing field '%s' - length: %u ", field_name, length)); + if (length > local_char_length) local_char_length= my_charpos(field_charset, from, from+length, local_char_length); @@ -7529,6 +7605,7 @@ Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, cs), packlength(blob_pack_length) { + DBUG_ASSERT(blob_pack_length <= 4); // Only pack lengths 1-4 supported currently flags|= BLOB_FLAG; share->blob_fields++; /* TODO: why do not fill table->s->blob_field array here? */ @@ -7939,8 +8016,10 @@ int Field_blob::key_cmp(const uchar *a,const uchar *b) */ int Field_blob::do_save_field_metadata(uchar *metadata_ptr) { + DBUG_ENTER("Field_blob::do_save_field_metadata"); *metadata_ptr= pack_length_no_ptr(); - return 1; + DBUG_PRINT("debug", ("metadata: %u (pack_length_no_ptr)", *metadata_ptr)); + DBUG_RETURN(1); } @@ -8881,6 +8960,9 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7), bytes_in_rec(len_arg / 8) { + DBUG_ENTER("Field_bit::Field_bit"); + DBUG_PRINT("enter", ("ptr_arg: %p, null_ptr_arg: %p, len_arg: %u, bit_len: %u, bytes_in_rec: %u", + ptr_arg, null_ptr_arg, len_arg, bit_len, bytes_in_rec)); flags|= UNSIGNED_FLAG; /* Ensure that Field::eq() can distinguish between two different bit fields. @@ -8888,6 +8970,7 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, */ if (!null_ptr_arg) null_bit= bit_ofs_arg; + DBUG_VOID_RETURN; } @@ -9172,9 +9255,17 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg) */ int Field_bit::do_save_field_metadata(uchar *metadata_ptr) { - *metadata_ptr= bit_len; - *(metadata_ptr + 1)= bytes_in_rec; - return 2; + DBUG_ENTER("Field_bit::do_save_field_metadata"); + DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d", + bit_len, bytes_in_rec)); + /* + Since this class and Field_bit_as_char have different ideas of + what should be stored here, we compute the values of the metadata + explicitly using the field_length. + */ + metadata_ptr[0]= field_length % 8; + metadata_ptr[1]= field_length / 8; + DBUG_RETURN(2); } @@ -9199,34 +9290,34 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata) } -/** - Check to see if field size is compatible with destination. - - This method is used in row-based replication to verify that the slave's - field size is less than or equal to the master's field size. The - encoded field metadata (from the master or source) is decoded and compared - to the size of this field (the slave or destination). +bool +Field_bit::compatible_field_size(uint field_metadata, + Relay_log_info * __attribute__((unused)), + uint16 mflags, + int *order_var) +{ + DBUG_ENTER("Field_bit::compatible_field_size"); + DBUG_ASSERT((field_metadata >> 16) == 0); + uint from_bit_len= + 8 * (field_metadata >> 8) + (field_metadata & 0xff); + uint to_bit_len= max_display_length(); + DBUG_PRINT("debug", ("from_bit_len: %u, to_bit_len: %u", + from_bit_len, to_bit_len)); + /* + If the bit length exact flag is clear, we are dealing with an old + master, so we allow some less strict behaviour if replicating by + moving both bit lengths to an even multiple of 8. - @param field_metadata Encoded size in field metadata + We do this by computing the number of bytes to store the field + instead, and then compare the result. + */ + if (!(mflags & Table_map_log_event::TM_BIT_LEN_EXACT_F)) { + from_bit_len= (from_bit_len + 7) / 8; + to_bit_len= (to_bit_len + 7) / 8; + } - @retval 0 if this field's size is < the source field's size - @retval 1 if this field's size is >= the source field's size -*/ -int Field_bit::compatible_field_size(uint field_metadata, - const Relay_log_info * __attribute__((unused))) -{ - int compatible= 0; - uint const source_size= pack_length_from_metadata(field_metadata); - uint const destination_size= row_pack_length(); - uint const from_bit_len= field_metadata & 0x00ff; - uint const from_len= (field_metadata >> 8U) & 0x00ff; - if ((bit_len == 0) || (from_bit_len == 0)) - compatible= (source_size <= destination_size); - else if (from_bit_len > bit_len) - compatible= (from_len < bytes_in_rec); - else - compatible= ((from_bit_len <= bit_len) && (from_len <= bytes_in_rec)); - return (compatible); + *order_var= compare(from_bit_len, to_bit_len); + DBUG_RETURN(TRUE); } @@ -9292,8 +9383,15 @@ const uchar * Field_bit::unpack(uchar *to, const uchar *from, uint param_data, bool low_byte_first __attribute__((unused))) { + DBUG_ENTER("Field_bit::unpack"); + DBUG_PRINT("enter", ("to: %p, from: %p, param_data: 0x%x", + to, from, param_data)); + DBUG_PRINT("debug", ("bit_ptr: %p, bit_len: %u, bit_ofs: %u", + bit_ptr, bit_len, bit_ofs)); uint const from_len= (param_data >> 8U) & 0x00ff; uint const from_bit_len= param_data & 0x00ff; + DBUG_PRINT("debug", ("from_len: %u, from_bit_len: %u", + from_len, from_bit_len)); /* If the parameter data is zero (i.e., undefined), or if the master and slave have the same sizes, then use the old unpack() method. @@ -9314,7 +9412,7 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data, from++; } memcpy(to, from, bytes_in_rec); - return from + bytes_in_rec; + DBUG_RETURN(from + bytes_in_rec); } /* @@ -9340,7 +9438,7 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data, bitmap_set_bit(table->write_set,field_index); store(value, new_len, system_charset_info); my_afree(value); - return from + len; + DBUG_RETURN(from + len); } @@ -9468,8 +9566,11 @@ void Create_field::create_length_to_internal_length(void) */ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, uint32 length_arg, uint32 decimals_arg, - bool maybe_null, bool is_unsigned) + bool maybe_null, bool is_unsigned, + uint pack_length) { + DBUG_ENTER("Create_field::init_for_tmp_table"); + field_name= ""; sql_type= sql_type_arg; char_length= length= length_arg;; @@ -9477,10 +9578,92 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, interval= 0; charset= &my_charset_bin; geom_type= Field::GEOM_GEOMETRY; - pack_flag= (FIELDFLAG_NUMBER | - ((decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) | - (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) | - (is_unsigned ? 0 : FIELDFLAG_DECIMAL)); + + DBUG_PRINT("enter", ("sql_type: %d, length: %u, pack_length: %u", + sql_type_arg, length_arg, pack_length)); + + /* + These pack flags are crafted to get it correctly through the + branches of make_field(). + */ + switch (sql_type_arg) + { + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_SET: + pack_flag= 0; + break; + + case MYSQL_TYPE_GEOMETRY: + pack_flag= FIELDFLAG_GEOM; + break; + + case MYSQL_TYPE_ENUM: + pack_flag= FIELDFLAG_INTERVAL; + break; + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + pack_flag= FIELDFLAG_DECIMAL | FIELDFLAG_NUMBER | + (decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT; + break; + + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + pack_flag= FIELDFLAG_BLOB; + break; + + case MYSQL_TYPE_BIT: + pack_flag= FIELDFLAG_NUMBER | FIELDFLAG_TREAT_BIT_AS_CHAR; + break; + + default: + pack_flag= FIELDFLAG_NUMBER; + break; + } + + /* + Set the pack flag correctly for the blob-like types. This sets the + packtype to something that make_field can use. If the pack type is + not set correctly, the packlength will be reeeeally wierd (like + 129 or so). + */ + switch (sql_type_arg) + { + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_GEOMETRY: + // If you are going to use the above types, you have to pass a + // pack_length as parameter. Assert that is really done. + DBUG_ASSERT(pack_length != ~0U); + pack_flag|= pack_length_to_packflag(pack_length); + break; + default: + /* Nothing */ + break; + } + + pack_flag|= + (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) | + (is_unsigned ? 0 : FIELDFLAG_DECIMAL); + + DBUG_PRINT("debug", ("pack_flag: %s%s%s%s%s, pack_type: %d", + FLAGSTR(pack_flag, FIELDFLAG_BINARY), + FLAGSTR(pack_flag, FIELDFLAG_NUMBER), + FLAGSTR(pack_flag, FIELDFLAG_INTERVAL), + FLAGSTR(pack_flag, FIELDFLAG_GEOM), + FLAGSTR(pack_flag, FIELDFLAG_BLOB), + f_packtype(pack_flag))); + DBUG_VOID_RETURN; } @@ -9987,6 +10170,14 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length, default: break; } + DBUG_PRINT("debug", ("field_type: %d, field_length: %u, interval: %p, pack_flag: %s%s%s%s%s", + field_type, field_length, interval, + FLAGSTR(pack_flag, FIELDFLAG_BINARY), + FLAGSTR(pack_flag, FIELDFLAG_INTERVAL), + FLAGSTR(pack_flag, FIELDFLAG_NUMBER), + FLAGSTR(pack_flag, FIELDFLAG_PACK), + FLAGSTR(pack_flag, FIELDFLAG_BLOB))); + if (f_is_alpha(pack_flag)) { if (!f_is_packed(pack_flag)) diff --git a/sql/field.h b/sql/field.h index 18b017516a7..041610f5385 100644 --- a/sql/field.h +++ b/sql/field.h @@ -167,22 +167,13 @@ public: table, which is located on disk). */ virtual uint32 pack_length_in_rec() const { return pack_length(); } - virtual int compatible_field_size(uint field_metadata, - const Relay_log_info *); + virtual bool compatible_field_size(uint metadata, Relay_log_info *rli, + uint16 mflags, int *order); virtual uint pack_length_from_metadata(uint field_metadata) - { return field_metadata; } - /* - This method is used to return the size of the data in a row-based - replication row record. The default implementation of returning 0 is - designed to allow fields that do not use metadata to return TRUE (1) - from compatible_field_size() which uses this function in the comparison. - The default value for field metadata for fields that do not have - metadata is 0. Thus, 0 == 0 means the fields are compatible in size. - - Note: While most classes that override this method return pack_length(), - the classes Field_string, Field_varstring, and Field_blob return - field_length + 1, field_length, and pack_length_no_ptr() respectfully. - */ + { + DBUG_ENTER("Field::pack_length_from_metadata"); + DBUG_RETURN(field_metadata); + } virtual uint row_pack_length() { return 0; } virtual int save_field_metadata(uchar *first_byte) { return do_save_field_metadata(first_byte); } @@ -641,6 +632,13 @@ public: int store_decimal(const my_decimal *); my_decimal *val_decimal(my_decimal *); uint is_equal(Create_field *new_field); + uint row_pack_length() { return pack_length(); } + uint32 pack_length_from_metadata(uint field_metadata) { + uint32 length= pack_length(); + DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u", + field_metadata, length)); + return length; + } int check_int(CHARSET_INFO *cs, const char *str, int length, const char *int_end, int error); bool get_int(CHARSET_INFO *cs, const char *from, uint len, @@ -805,11 +803,12 @@ public: uint32 pack_length() const { return (uint32) bin_size; } uint pack_length_from_metadata(uint field_metadata); uint row_pack_length() { return pack_length(); } - int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); + bool compatible_field_size(uint field_metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); uint is_equal(Create_field *new_field); virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data, bool low_byte_first); + static Field *create_from_item (Item *); }; @@ -1500,9 +1499,9 @@ public: return row_pack_length(); return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff); } - int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); - uint row_pack_length() { return (field_length + 1); } + bool compatible_field_size(uint field_metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); + uint row_pack_length() { return field_length; } int pack_cmp(const uchar *a,const uchar *b,uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update); @@ -1964,8 +1963,8 @@ public: uint pack_length_from_metadata(uint field_metadata); uint row_pack_length() { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } - int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); + bool compatible_field_size(uint metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); void sql_type(String &str) const; virtual uchar *pack(uchar *to, const uchar *from, uint max_length, bool low_byte_first); @@ -2068,7 +2067,8 @@ public: /* Init for a tmp table field. To be extended if need be. */ void init_for_tmp_table(enum_field_types sql_type_arg, uint32 max_length, uint32 decimals, - bool maybe_null, bool is_unsigned); + bool maybe_null, bool is_unsigned, + uint pack_length = ~0U); bool init(THD *thd, char *field_name, enum_field_types type, char *length, char *decimals, uint type_modifier, Item *default_value, diff --git a/sql/item.cc b/sql/item.cc index 8f487872f1b..b35a6ae3d6e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4899,9 +4899,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) switch (field_type()) { case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: - field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0, - Field::NONE, name, decimals, 0, - unsigned_flag); + field= Field_new_decimal::create_from_item(this); break; case MYSQL_TYPE_TINY: field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, @@ -6940,9 +6938,24 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) Item_cache* Item_cache::get_cache(const Item *item) { - switch (item->result_type()) { + return get_cache(item, item->result_type()); +} + + +/** + Get a cache item of given type. + + @param item value to be cached + @param type required type of cache + + @return cache item +*/ + +Item_cache* Item_cache::get_cache(const Item *item, const Item_result type) +{ + switch (type) { case INT_RESULT: - return new Item_cache_int(); + return new Item_cache_int(item->field_type()); case REAL_RESULT: return new Item_cache_real(); case DECIMAL_RESULT: @@ -6958,6 +6971,13 @@ Item_cache* Item_cache::get_cache(const Item *item) } } +void Item_cache::store(Item *item) +{ + example= item; + if (!item) + null_value= TRUE; + value_cached= FALSE; +} void Item_cache::print(String *str, enum_query_type query_type) { @@ -6969,17 +6989,22 @@ void Item_cache::print(String *str, enum_query_type query_type) str->append(')'); } - -void Item_cache_int::store(Item *item) +bool Item_cache_int::cache_value() { - value= item->val_int_result(); - null_value= item->null_value; - unsigned_flag= item->unsigned_flag; + if (!example) + return FALSE; + value_cached= TRUE; + value= example->val_int_result(); + null_value= example->null_value; + unsigned_flag= example->unsigned_flag; + return TRUE; } void Item_cache_int::store(Item *item, longlong val_arg) { + /* An explicit values is given, save it. */ + value_cached= TRUE; value= val_arg; null_value= item->null_value; unsigned_flag= item->unsigned_flag; @@ -6989,6 +7014,8 @@ void Item_cache_int::store(Item *item, longlong val_arg) String *Item_cache_int::val_str(String *str) { DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return NULL; str->set(value, default_charset()); return str; } @@ -6997,21 +7024,52 @@ String *Item_cache_int::val_str(String *str) my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return NULL; int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); return decimal_val; } +double Item_cache_int::val_real() +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return 0.0; + return (double) value; +} -void Item_cache_real::store(Item *item) +longlong Item_cache_int::val_int() { - value= item->val_result(); - null_value= item->null_value; + DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return 0; + return value; +} + +bool Item_cache_real::cache_value() +{ + if (!example) + return FALSE; + value_cached= TRUE; + value= example->val_result(); + null_value= example->null_value; + return TRUE; } +double Item_cache_real::val_real() +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return 0.0; + return value; +} + longlong Item_cache_real::val_int() { DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return 0; return (longlong) rint(value); } @@ -7019,6 +7077,8 @@ longlong Item_cache_real::val_int() String* Item_cache_real::val_str(String *str) { DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return NULL; str->set_real(value, decimals, default_charset()); return str; } @@ -7027,22 +7087,30 @@ String* Item_cache_real::val_str(String *str) my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return NULL; double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); return decimal_val; } -void Item_cache_decimal::store(Item *item) +bool Item_cache_decimal::cache_value() { - my_decimal *val= item->val_decimal_result(&decimal_value); - if (!(null_value= item->null_value) && val != &decimal_value) + if (!example) + return FALSE; + value_cached= TRUE; + my_decimal *val= example->val_decimal_result(&decimal_value); + if (!(null_value= example->null_value) && val != &decimal_value) my_decimal2decimal(val, &decimal_value); + return TRUE; } double Item_cache_decimal::val_real() { DBUG_ASSERT(fixed); double res; + if (!value_cached && !cache_value()) + return NULL; my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); return res; } @@ -7051,6 +7119,8 @@ longlong Item_cache_decimal::val_int() { DBUG_ASSERT(fixed); longlong res; + if (!value_cached && !cache_value()) + return 0; my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res); return res; } @@ -7058,6 +7128,8 @@ longlong Item_cache_decimal::val_int() String* Item_cache_decimal::val_str(String *str) { DBUG_ASSERT(fixed); + if (!value_cached && !cache_value()) + return NULL; my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE, &decimal_value); my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str); @@ -7067,15 +7139,20 @@ String* Item_cache_decimal::val_str(String *str) my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) { DBUG_ASSERT(fixed); + if (!value_cached && !cache_value()) + return NULL; return &decimal_value; } -void Item_cache_str::store(Item *item) +bool Item_cache_str::cache_value() { - value_buff.set(buffer, sizeof(buffer), item->collation.collation); - value= item->str_result(&value_buff); - if ((null_value= item->null_value)) + if (!example) + return FALSE; + value_cached= TRUE; + value_buff.set(buffer, sizeof(buffer), example->collation.collation); + value= example->str_result(&value_buff); + if ((null_value= example->null_value)) value= 0; else if (value != &value_buff) { @@ -7090,6 +7167,7 @@ void Item_cache_str::store(Item *item) value_buff.copy(*value); value= &value_buff; } + return TRUE; } double Item_cache_str::val_real() @@ -7097,6 +7175,8 @@ double Item_cache_str::val_real() DBUG_ASSERT(fixed == 1); int err_not_used; char *end_not_used; + if (!value_cached && !cache_value()) + return 0.0; if (value) return my_strntod(value->charset(), (char*) value->ptr(), value->length(), &end_not_used, &err_not_used); @@ -7108,6 +7188,8 @@ longlong Item_cache_str::val_int() { DBUG_ASSERT(fixed == 1); int err; + if (!value_cached && !cache_value()) + return 0; if (value) return my_strntoll(value->charset(), value->ptr(), value->length(), 10, (char**) 0, &err); @@ -7115,9 +7197,21 @@ longlong Item_cache_str::val_int() return (longlong)0; } + +String* Item_cache_str::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return 0; + return value; +} + + my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); + if (!value_cached && !cache_value()) + return NULL; if (value) string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); else @@ -7128,6 +7222,8 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) int Item_cache_str::save_in_field(Field *field, bool no_conversions) { + if (!value_cached && !cache_value()) + return 0; int res= Item_cache::save_in_field(field, no_conversions); return (is_varbinary && field->type() == MYSQL_TYPE_STRING && value->length() < field->field_length) ? 1 : res; @@ -7162,13 +7258,30 @@ bool Item_cache_row::setup(Item * item) void Item_cache_row::store(Item * item) { + example= item; + if (!item) + { + null_value= TRUE; + return; + } + for (uint i= 0; i < item_count; i++) + values[i]->store(item->element_index(i)); +} + + +bool Item_cache_row::cache_value() +{ + if (!example) + return FALSE; + value_cached= TRUE; null_value= 0; - item->bring_value(); + example->bring_value(); for (uint i= 0; i < item_count; i++) { - values[i]->store(item->element_index(i)); + values[i]->cache_value(); null_value|= values[i]->null_value; } + return TRUE; } diff --git a/sql/item.h b/sql/item.h index e83634843be..f37938aedbd 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1027,7 +1027,11 @@ class sp_head; class Item_basic_constant :public Item { + table_map used_table_map; public: + Item_basic_constant(): Item(), used_table_map(0) {}; + void set_used_tables(table_map map) { used_table_map= map; } + table_map used_tables() const { return used_table_map; } /* to prevent drop fixed flag (no need parent cleanup call) */ void cleanup() { @@ -2137,6 +2141,23 @@ public: save_in_field(result_field, no_conversions); } void cleanup(); + /* + This method is used for debug purposes to print the name of an + item to the debug log. The second use of this method is as + a helper function of print() and error messages, where it is + applicable. To suit both goals it should return a meaningful, + distinguishable and sintactically correct string. This method + should not be used for runtime type identification, use enum + {Sum}Functype and Item_func::functype()/Item_sum::sum_func() + instead. + Added here, to the parent class of both Item_func and Item_sum_func. + + NOTE: for Items inherited from Item_sum, func_name() return part of + function name till first argument (including '(') to make difference in + names for functions with 'distinct' clause and without 'distinct' and + also to make printing of items inherited from Item_sum uniform. + */ + virtual const char *func_name() const= 0; }; @@ -2892,15 +2913,25 @@ protected: */ Field *cached_field; enum enum_field_types cached_field_type; + /* + TRUE <=> cache holds value of the last stored item (i.e actual value). + store() stores item to be cached and sets this flag to FALSE. + On the first call of val_xxx function if this flag is set to FALSE the + cache_value() will be called to actually cache value of saved item. + cache_value() will set this flag to TRUE. + */ + bool value_cached; public: - Item_cache(): - example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING) + Item_cache(): + example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING), + value_cached(0) { fixed= 1; null_value= 1; } Item_cache(enum_field_types field_type_arg): - example(0), used_table_map(0), cached_field(0), cached_field_type(field_type_arg) + example(0), used_table_map(0), cached_field(0), cached_field_type(field_type_arg), + value_cached(0) { fixed= 1; null_value= 1; @@ -2920,10 +2951,10 @@ public: cached_field= ((Item_field *)item)->field; return 0; }; - virtual void store(Item *)= 0; enum Type type() const { return CACHE_ITEM; } enum_field_types field_type() const { return cached_field_type; } static Item_cache* get_cache(const Item *item); + static Item_cache* get_cache(const Item* item, const Item_result type); table_map used_tables() const { return used_table_map; } virtual void keep_array() {} virtual void print(String *str, enum_query_type query_type); @@ -2935,6 +2966,8 @@ public: { return this == item; } + virtual void store(Item *item); + virtual bool cache_value()= 0; }; @@ -2943,18 +2976,19 @@ class Item_cache_int: public Item_cache protected: longlong value; public: - Item_cache_int(): Item_cache(), value(0) {} + Item_cache_int(): Item_cache(), + value(0) {} Item_cache_int(enum_field_types field_type_arg): Item_cache(field_type_arg), value(0) {} - void store(Item *item); void store(Item *item, longlong val_arg); - double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } - longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } + double val_real(); + longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return INT_RESULT; } bool result_as_longlong() { return TRUE; } + bool cache_value(); }; @@ -2962,14 +2996,15 @@ class Item_cache_real: public Item_cache { double value; public: - Item_cache_real(): Item_cache(), value(0) {} + Item_cache_real(): Item_cache(), + value(0) {} - void store(Item *item); - double val_real() { DBUG_ASSERT(fixed == 1); return value; } + double val_real(); longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return REAL_RESULT; } + bool cache_value(); }; @@ -2980,12 +3015,12 @@ protected: public: Item_cache_decimal(): Item_cache() {} - void store(Item *item); double val_real(); longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return DECIMAL_RESULT; } + bool cache_value(); }; @@ -3003,14 +3038,14 @@ public: MYSQL_TYPE_VARCHAR && !((const Item_field *) item)->field->has_charset()) {} - void store(Item *item); double val_real(); longlong val_int(); - String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; } + String* val_str(String *); my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return STRING_RESULT; } CHARSET_INFO *charset() const { return value->charset(); }; int save_in_field(Field *field, bool no_conversions); + bool cache_value(); }; class Item_cache_row: public Item_cache @@ -3020,7 +3055,8 @@ class Item_cache_row: public Item_cache bool save_array; public: Item_cache_row() - :Item_cache(), values(0), item_count(2), save_array(0) {} + :Item_cache(), values(0), item_count(2), + save_array(0) {} /* 'allocate' used only in row transformer, to preallocate space for row @@ -3078,6 +3114,7 @@ public: values= 0; DBUG_VOID_RETURN; } + bool cache_value(); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c6b88cd8188..fd5eca8911a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -30,6 +30,9 @@ #include "sql_select.h" static bool convert_constant_item(THD *, Item_field *, Item **); +static longlong +get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null); static Item_result item_store_type(Item_result a, Item *item, my_bool unsigned_flag) @@ -533,11 +536,12 @@ void Item_bool_func2::fix_length_and_dec() } -int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) +int Arg_comparator::set_compare_func(Item_result_field *item, Item_result type) { owner= item; func= comparator_matrix[type] - [test(owner->functype() == Item_func::EQUAL_FUNC)]; + [is_owner_equal_func()]; + switch (type) { case ROW_RESULT: { @@ -557,7 +561,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols()); return 1; } - if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i))) + if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i), + set_null)) return 1; } break; @@ -571,7 +576,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) if (cmp_collation.set((*a)->collation, (*b)->collation) || cmp_collation.derivation == DERIVATION_NONE) { - my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name()); + my_coll_agg_error((*a)->collation, (*b)->collation, + owner->func_name()); return 1; } if (cmp_collation.collation == &my_charset_bin) @@ -785,15 +791,21 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value) if (cmp_type != CMP_DATE_DFLT) { + THD *thd= current_thd; /* Do not cache GET_USER_VAR() function as its const_item() may return TRUE for the current thread but it still may change during the execution. + Don't use cache while in the context analysis mode only (i.e. for + EXPLAIN/CREATE VIEW and similar queries). Cache is useless in such + cases and can cause problems. For example evaluating subqueries can + confuse storage engines since in context analysis mode tables + aren't locked. */ - if (cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() && + if (!thd->is_context_analysis_only() && + cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() && (str_arg->type() != Item::FUNC_ITEM || ((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC)) { - THD *thd= current_thd; ulonglong value; bool error; String tmp, *str_val= 0; @@ -875,19 +887,21 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg, } -int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, +int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, Item **a1, Item **a2, Item_result type) { enum enum_date_cmp_type cmp_type; ulonglong const_value= (ulonglong)-1; + thd= current_thd; + owner= owner_arg; a= a1; b= a2; + owner= owner_arg; + thd= current_thd; if ((cmp_type= can_compare_as_dates(*a, *b, &const_value))) { - thd= current_thd; - owner= owner_arg; a_type= (*a)->field_type(); b_type= (*b)->field_type(); a_cache= 0; @@ -895,6 +909,10 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, if (const_value != (ulonglong)-1) { + /* + cache_converted_constant can't be used here because it can't + correctly convert a DATETIME value from string to int representation. + */ Item_cache_int *cache= new Item_cache_int(); /* Mark the cache as non-const to prevent re-caching. */ cache->set_used_tables(1); @@ -911,22 +929,22 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, b= (Item **)&b_cache; } } - is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC); + is_nulls_eq= is_owner_equal_func(); func= &Arg_comparator::compare_datetime; - get_value_func= &get_datetime_value; + get_value_a_func= &get_datetime_value; + get_value_b_func= &get_datetime_value; return 0; } else if (type == STRING_RESULT && (*a)->field_type() == MYSQL_TYPE_TIME && (*b)->field_type() == MYSQL_TYPE_TIME) { /* Compare TIME values as integers. */ - thd= current_thd; - owner= owner_arg; a_cache= 0; b_cache= 0; - is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC); + is_nulls_eq= is_owner_equal_func(); func= &Arg_comparator::compare_datetime; - get_value_func= &get_time_value; + get_value_a_func= &get_time_value; + get_value_b_func= &get_time_value; return 0; } else if (type == STRING_RESULT && @@ -935,20 +953,89 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, { DTCollation coll; coll.set((*a)->collation.collation); - if (agg_item_set_converter(coll, owner_arg->func_name(), + if (agg_item_set_converter(coll, owner->func_name(), b, 1, MY_COLL_CMP_CONV, 1)) return 1; + } else if (type != ROW_RESULT && ((*a)->field_type() == MYSQL_TYPE_YEAR || + (*b)->field_type() == MYSQL_TYPE_YEAR)) + { + is_nulls_eq= is_owner_equal_func(); + year_as_datetime= FALSE; + + if ((*a)->is_datetime()) + { + year_as_datetime= TRUE; + get_value_a_func= &get_datetime_value; + } else if ((*a)->field_type() == MYSQL_TYPE_YEAR) + get_value_a_func= &get_year_value; + else + { + /* + Because convert_constant_item is called only for EXECUTE in PS mode + the value of get_value_x_func set in PREPARE might be not + valid for EXECUTE. + */ + get_value_a_func= NULL; + } + + if ((*b)->is_datetime()) + { + year_as_datetime= TRUE; + get_value_b_func= &get_datetime_value; + } else if ((*b)->field_type() == MYSQL_TYPE_YEAR) + get_value_b_func= &get_year_value; + else + get_value_b_func= NULL; + + func= &Arg_comparator::compare_year; + return 0; } + a= cache_converted_constant(thd, a, &a_cache, type); + b= cache_converted_constant(thd, b, &b_cache, type); return set_compare_func(owner_arg, type); } -void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1) +/** + Convert and cache a constant. + + @param value [in] An item to cache + @param cache_item [out] Placeholder for the cache item + @param type [in] Comparison type + + @details + When given item is a constant and its type differs from comparison type + then cache its value to avoid type conversion of this constant on each + evaluation. In this case the value is cached and the reference to the cache + is returned. + Original value is returned otherwise. + + @return cache item or original value. +*/ + +Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value, + Item **cache_item, + Item_result type) +{ + /* Don't need cache if doing context analysis only. */ + if (!thd->is_context_analysis_only() && + (*value)->const_item() && type != (*value)->result_type()) + { + Item_cache *cache= Item_cache::get_cache(*value, type); + cache->store(*value); + *cache_item= cache; + return cache_item; + } + return value; +} + + +void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg, + Item **a1, Item **b1) { thd= current_thd; - /* A caller will handle null values by itself. */ - owner= NULL; + owner= owner_arg; a= a1; b= b1; a_type= (*a)->field_type(); @@ -957,7 +1044,8 @@ void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1) b_cache= 0; is_nulls_eq= FALSE; func= &Arg_comparator::compare_datetime; - get_value_func= &get_datetime_value; + get_value_a_func= &get_datetime_value; + get_value_b_func= &get_datetime_value; } @@ -1057,6 +1145,51 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, return value; } + +/* + Retrieves YEAR value of 19XX form from given item. + + SYNOPSIS + get_year_value() + thd thread handle + item_arg [in/out] item to retrieve YEAR value from + cache_arg [in/out] pointer to place to store the caching item to + warn_item [in] item for issuing the conversion warning + is_null [out] TRUE <=> the item_arg is null + + DESCRIPTION + Retrieves the YEAR value of 19XX form from given item for comparison by the + compare_year() function. + + RETURN + obtained value +*/ + +static longlong +get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null) +{ + longlong value= 0; + Item *item= **item_arg; + + value= item->val_int(); + *is_null= item->null_value; + if (*is_null) + return ~(ulonglong) 0; + + /* + Coerce value to the 19XX form in order to correctly compare + YEAR(2) & YEAR(4) types. + */ + if (value < 70) + value+= 100; + if (value <= 1900) + value+= 1900; + + return value; +} + + /* Compare items values as dates. @@ -1089,25 +1222,25 @@ int Arg_comparator::compare_datetime() longlong a_value, b_value; /* Get DATE/DATETIME/TIME value of the 'a' item. */ - a_value= (*get_value_func)(thd, &a, &a_cache, *b, &a_is_null); + a_value= (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null); if (!is_nulls_eq && a_is_null) { - if (owner) + if (set_null) owner->null_value= 1; return -1; } /* Get DATE/DATETIME/TIME value of the 'b' item. */ - b_value= (*get_value_func)(thd, &b, &b_cache, *a, &b_is_null); + b_value= (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null); if (a_is_null || b_is_null) { - if (owner) + if (set_null) owner->null_value= is_nulls_eq ? 0 : 1; return is_nulls_eq ? (a_is_null == b_is_null) : -1; } /* Here we have two not-NULL values. */ - if (owner) + if (set_null) owner->null_value= 0; /* Compare values. */ @@ -1120,15 +1253,17 @@ int Arg_comparator::compare_datetime() int Arg_comparator::compare_string() { String *res1,*res2; - if ((res1= (*a)->val_str(&owner->tmp_value1))) + if ((res1= (*a)->val_str(&value1))) { - if ((res2= (*b)->val_str(&owner->tmp_value2))) + if ((res2= (*b)->val_str(&value2))) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; return sortcmp(res1,res2,cmp_collation.collation); } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1147,18 +1282,20 @@ int Arg_comparator::compare_string() int Arg_comparator::compare_binary_string() { String *res1,*res2; - if ((res1= (*a)->val_str(&owner->tmp_value1))) + if ((res1= (*a)->val_str(&value1))) { - if ((res2= (*b)->val_str(&owner->tmp_value2))) + if ((res2= (*b)->val_str(&value2))) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; uint res1_length= res1->length(); uint res2_length= res2->length(); int cmp= memcmp(res1->ptr(), res2->ptr(), min(res1_length,res2_length)); return cmp ? cmp : (int) (res1_length - res2_length); } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1171,8 +1308,8 @@ int Arg_comparator::compare_binary_string() int Arg_comparator::compare_e_string() { String *res1,*res2; - res1= (*a)->val_str(&owner->tmp_value1); - res2= (*b)->val_str(&owner->tmp_value2); + res1= (*a)->val_str(&value1); + res2= (*b)->val_str(&value2); if (!res1 || !res2) return test(res1 == res2); return test(sortcmp(res1, res2, cmp_collation.collation) == 0); @@ -1182,8 +1319,8 @@ int Arg_comparator::compare_e_string() int Arg_comparator::compare_e_binary_string() { String *res1,*res2; - res1= (*a)->val_str(&owner->tmp_value1); - res2= (*b)->val_str(&owner->tmp_value2); + res1= (*a)->val_str(&value1); + res2= (*b)->val_str(&value2); if (!res1 || !res2) return test(res1 == res2); return test(stringcmp(res1, res2) == 0); @@ -1204,13 +1341,15 @@ int Arg_comparator::compare_real() val2= (*b)->val_real(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1224,11 +1363,13 @@ int Arg_comparator::compare_decimal() my_decimal *val2= (*b)->val_decimal(&value2); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; return my_decimal_cmp(val1, val2); } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1266,7 +1407,8 @@ int Arg_comparator::compare_real_fixed() val2= (*b)->val_real(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (val1 == val2 || fabs(val1 - val2) < precision) return 0; if (val1 < val2) @@ -1274,7 +1416,8 @@ int Arg_comparator::compare_real_fixed() return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1297,13 +1440,15 @@ int Arg_comparator::compare_int_signed() longlong val2= (*b)->val_int(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1320,13 +1465,15 @@ int Arg_comparator::compare_int_unsigned() ulonglong val2= (*b)->val_int(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1343,7 +1490,8 @@ int Arg_comparator::compare_int_signed_unsigned() ulonglong uval2= (ulonglong)(*b)->val_int(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (sval1 < 0 || (ulonglong)sval1 < uval2) return -1; if ((ulonglong)sval1 == uval2) @@ -1351,7 +1499,8 @@ int Arg_comparator::compare_int_signed_unsigned() return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1368,7 +1517,8 @@ int Arg_comparator::compare_int_unsigned_signed() longlong sval2= (*b)->val_int(); if (!(*b)->null_value) { - owner->null_value= 0; + if (set_null) + owner->null_value= 0; if (sval2 < 0) return 1; if (uval1 < (ulonglong)sval2) @@ -1378,7 +1528,8 @@ int Arg_comparator::compare_int_unsigned_signed() return 1; } } - owner->null_value= 1; + if (set_null) + owner->null_value= 1; return -1; } @@ -1414,10 +1565,11 @@ int Arg_comparator::compare_row() for (uint i= 0; i<n; i++) { res= comparators[i].compare(); - if (owner->null_value) + /* Aggregate functions don't need special null handling. */ + if (owner->null_value && owner->type() == Item::FUNC_ITEM) { // NULL was compared - switch (owner->functype()) { + switch (((Item_func*)owner)->functype()) { case Item_func::NE_FUNC: break; // NE never aborts on NULL even if abort_on_null is set case Item_func::LT_FUNC: @@ -1426,7 +1578,7 @@ int Arg_comparator::compare_row() case Item_func::GE_FUNC: return -1; // <, <=, > and >= always fail on NULL default: // EQ_FUNC - if (owner->abort_on_null) + if (((Item_bool_func2*)owner)->abort_on_null) return -1; // We do not need correct NULL returning } was_null= 1; @@ -1463,6 +1615,67 @@ int Arg_comparator::compare_e_row() } +/** + Compare values as YEAR. + + @details + Compare items as YEAR for EQUAL_FUNC and for other comparison functions. + The YEAR values of form 19XX are obtained with help of the get_year_value() + function. + If one of arguments is of DATE/DATETIME type its value is obtained + with help of the get_datetime_value function. In this case YEAR values + prior to comparison are converted to the ulonglong YYYY-00-00 00:00:00 + DATETIME form. + If an argument type neither YEAR nor DATE/DATEIME then val_int function + is used to obtain value for comparison. + + RETURN + If is_nulls_eq is TRUE: + 1 if items are equal or both are null + 0 otherwise + If is_nulls_eq is FALSE: + -1 a < b + 0 a == b or at least one of items is null + 1 a > b + See the table: + is_nulls_eq | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | + a_is_null | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | + b_is_null | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | + result | 1 | 0 | 0 |0/1| 0 | 0 | 0 |-1/0/1| +*/ + +int Arg_comparator::compare_year() +{ + bool a_is_null, b_is_null; + ulonglong val1= get_value_a_func ? + (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null) : + (*a)->val_int(); + ulonglong val2= get_value_b_func ? + (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null) : + (*b)->val_int(); + if (!(*a)->null_value) + { + if (!(*b)->null_value) + { + if (set_null) + owner->null_value= 0; + /* Convert year to DATETIME of form YYYY-00-00 00:00:00 when necessary. */ + if((*a)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) + val1*= 10000000000LL; + if((*b)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) + val2*= 10000000000LL; + + if (val1 < val2) return is_nulls_eq ? 0 : -1; + if (val1 == val2) return is_nulls_eq ? 1 : 0; + return is_nulls_eq ? 0 : 1; + } + } + if (set_null) + owner->null_value= is_nulls_eq ? 0 : 1; + return (is_nulls_eq && (*a)->null_value == (*b)->null_value) ? 1 : 0; +} + + void Item_func_truth::fix_length_and_dec() { maybe_null= 0; @@ -1582,6 +1795,7 @@ longlong Item_in_optimizer::val_int() bool tmp; DBUG_ASSERT(fixed == 1); cache->store(args[0]); + cache->cache_value(); if (cache->null_value) { @@ -1749,8 +1963,8 @@ longlong Item_func_lt::val_int() longlong Item_func_strcmp::val_int() { DBUG_ASSERT(fixed == 1); - String *a=args[0]->val_str(&tmp_value1); - String *b=args[1]->val_str(&tmp_value2); + String *a=args[0]->val_str(&cmp.value1); + String *b=args[1]->val_str(&cmp.value2); if (!a || !b) { null_value=1; @@ -2033,8 +2247,8 @@ void Item_func_between::fix_length_and_dec() if (compare_as_dates) { - ge_cmp.set_datetime_cmp_func(args, args + 1); - le_cmp.set_datetime_cmp_func(args, args + 2); + ge_cmp.set_datetime_cmp_func(this, args, args + 1); + le_cmp.set_datetime_cmp_func(this, args, args + 2); } else if (time_items_found == 3) { @@ -4362,13 +4576,13 @@ void Item_func_isnotnull::print(String *str, enum_query_type query_type) longlong Item_func_like::val_int() { DBUG_ASSERT(fixed == 1); - String* res = args[0]->val_str(&tmp_value1); + String* res = args[0]->val_str(&cmp.value1); if (args[0]->null_value) { null_value=1; return 0; } - String* res2 = args[1]->val_str(&tmp_value2); + String* res2 = args[1]->val_str(&cmp.value2); if (args[1]->null_value) { null_value=1; @@ -4392,7 +4606,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const { if (args[1]->const_item()) { - String* res2= args[1]->val_str((String *)&tmp_value2); + String* res2= args[1]->val_str((String *)&cmp.value2); if (!res2) return OPTIMIZE_NONE; @@ -4423,7 +4637,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) if (escape_item->const_item()) { /* If we are on execution stage */ - String *escape_str= escape_item->val_str(&tmp_value1); + String *escape_str= escape_item->val_str(&cmp.value1); if (escape_str) { if (escape_used_in_parsing && ( @@ -4478,7 +4692,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) if (args[1]->const_item() && !use_strnxfrm(collation.collation) && !(specialflag & SPECIAL_NO_NEW_FUNC)) { - String* res2 = args[1]->val_str(&tmp_value2); + String* res2 = args[1]->val_str(&cmp.value2); if (!res2) return FALSE; // Null argument diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index ec703d0a9f9..71ed5cf99dd 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -35,7 +35,7 @@ class Arg_comparator: public Sql_alloc { Item **a, **b; arg_cmp_func func; - Item_bool_func2 *owner; + Item_result_field *owner; Arg_comparator *comparators; // used only for compare_row() double precision; /* Fields used in DATE/DATETIME comparison. */ @@ -43,30 +43,42 @@ class Arg_comparator: public Sql_alloc enum_field_types a_type, b_type; // Types of a and b items Item *a_cache, *b_cache; // Cached values of a and b items bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC + bool set_null; // TRUE <=> set owner->null_value + // when one of arguments is NULL. + bool year_as_datetime; // TRUE <=> convert YEAR value to + // the YYYY-00-00 00:00:00 DATETIME + // format. See compare_year. enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE, CMP_DATE_WITH_STR, CMP_STR_WITH_DATE }; - longlong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg, - Item *warn_item, bool *is_null); + longlong (*get_value_a_func)(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null); + longlong (*get_value_b_func)(THD *thd, Item ***item_arg, Item **cache_arg, + Item *warn_item, bool *is_null); public: DTCollation cmp_collation; + /* Allow owner function to use string buffers. */ + String value1, value2; - Arg_comparator(): thd(0), a_cache(0), b_cache(0) {}; + Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0), + year_as_datetime(0), get_value_a_func(0), get_value_b_func(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0), - a_cache(0), b_cache(0) {}; + a_cache(0), b_cache(0), set_null(0), year_as_datetime(0), + get_value_a_func(0), get_value_b_func(0) {}; - int set_compare_func(Item_bool_func2 *owner, Item_result type); - inline int set_compare_func(Item_bool_func2 *owner_arg) + int set_compare_func(Item_result_field *owner, Item_result type); + inline int set_compare_func(Item_result_field *owner_arg) { return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(), (*b)->result_type())); } - int set_cmp_func(Item_bool_func2 *owner_arg, + int set_cmp_func(Item_result_field *owner_arg, Item **a1, Item **a2, Item_result type); - inline int set_cmp_func(Item_bool_func2 *owner_arg, - Item **a1, Item **a2) + inline int set_cmp_func(Item_result_field *owner_arg, + Item **a1, Item **a2, bool set_null_arg) { + set_null= set_null_arg; return set_cmp_func(owner_arg, a1, a2, item_cmp_type((*a1)->result_type(), (*a2)->result_type())); @@ -92,12 +104,20 @@ public: int compare_real_fixed(); int compare_e_real_fixed(); int compare_datetime(); // compare args[0] & args[1] as DATETIMEs + int compare_year(); static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b, ulonglong *const_val_arg); - void set_datetime_cmp_func(Item **a1, Item **b1); + Item** cache_converted_constant(THD *thd, Item **value, Item **cache, + Item_result type); + void set_datetime_cmp_func(Item_result_field *owner_arg, Item **a1, Item **b1); static arg_cmp_func comparator_matrix [5][2]; + inline bool is_owner_equal_func() + { + return (owner->type() == Item::FUNC_ITEM && + ((Item_func*)owner)->functype() == Item_func::EQUAL_FUNC); + } friend class Item_func; }; @@ -327,7 +347,6 @@ class Item_bool_func2 :public Item_int_func { /* Bool with 2 string args */ protected: Arg_comparator cmp; - String tmp_value1,tmp_value2; bool abort_on_null; public: @@ -336,7 +355,7 @@ public: void fix_length_and_dec(); void set_cmp_func() { - cmp.set_cmp_func(this, tmp_arg, tmp_arg+1); + cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE); } optimize_type select_optimize() const { return OPTIMIZE_OP; } virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; } diff --git a/sql/item_create.cc b/sql/item_create.cc index 7991d9adf82..53aa8081da1 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -3524,6 +3524,7 @@ Create_func_get_lock Create_func_get_lock::s_singleton; Item* Create_func_get_lock::create(THD *thd, Item *arg1, Item *arg2) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_get_lock(arg1, arg2); } @@ -3635,6 +3636,7 @@ Create_func_is_free_lock Create_func_is_free_lock::s_singleton; Item* Create_func_is_free_lock::create(THD *thd, Item *arg1) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_is_free_lock(arg1); } @@ -3645,6 +3647,7 @@ Create_func_is_used_lock Create_func_is_used_lock::s_singleton; Item* Create_func_is_used_lock::create(THD *thd, Item *arg1) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_is_used_lock(arg1); } @@ -3961,6 +3964,8 @@ Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name, Item *func= NULL; int arg_count= 0; + thd->lex->set_stmt_unsafe(); + if (item_list != NULL) arg_count= item_list->elements; @@ -4203,6 +4208,7 @@ Create_func_release_lock Create_func_release_lock::s_singleton; Item* Create_func_release_lock::create(THD *thd, Item *arg1) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_release_lock(arg1); } @@ -4325,6 +4331,7 @@ Create_func_sleep Create_func_sleep::s_singleton; Item* Create_func_sleep::create(THD *thd, Item *arg1) { + thd->lex->set_stmt_unsafe(); thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); return new (thd->mem_root) Item_func_sleep(arg1); } @@ -4591,6 +4598,7 @@ Create_func_version Create_func_version::s_singleton; Item* Create_func_version::create(THD *thd) { + thd->lex->set_stmt_unsafe(); return new (thd->mem_root) Item_static_string_func("version()", server_version, (uint) strlen(server_version), diff --git a/sql/item_func.cc b/sql/item_func.cc index ac52f36474a..977a0de39af 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -451,45 +451,8 @@ Field *Item_func::tmp_table_field(TABLE *table) return make_string_field(table); break; case DECIMAL_RESULT: - { - uint8 dec= decimals; - uint8 intg= decimal_precision() - dec; - uint32 len= max_length; - - /* - Trying to put too many digits overall in a DECIMAL(prec,dec) - will always throw a warning. We must limit dec to - DECIMAL_MAX_SCALE however to prevent an assert() later. - */ - - if (dec > 0) - { - int overflow; - - dec= min(dec, DECIMAL_MAX_SCALE); - - /* - If the value still overflows the field with the corrected dec, - we'll throw out decimals rather than integers. This is still - bad and of course throws a truncation warning. - */ - - const int required_length= - my_decimal_precision_to_length(intg + dec, dec, - unsigned_flag); - - overflow= required_length - len; - - if (overflow > 0) - dec= max(0, dec - overflow); // too long, discard fract - else - /* Corrected value fits. */ - len= required_length; - } - - field= new Field_new_decimal(len, maybe_null, name, dec, unsigned_flag); + field= Field_new_decimal::create_from_item(this); break; - } case ROW_RESULT: default: // This case should never be chosen diff --git a/sql/item_func.h b/sql/item_func.h index 6f2b3f0bfc2..f22bc0c301c 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -127,17 +127,6 @@ public: virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; } virtual bool have_rev_func() const { return 0; } virtual Item *key_item() const { return args[0]; } - /* - This method is used for debug purposes to print the name of an - item to the debug log. The second use of this method is as - a helper function of print(), where it is applicable. - To suit both goals it should return a meaningful, - distinguishable and sintactically correct string. This method - should not be used for runtime type identification, use enum - {Sum}Functype and Item_func::functype()/Item_sum::sum_func() - instead. - */ - virtual const char *func_name() const= 0; virtual bool const_item() const { return const_item_cache; } inline Item **arguments() const { return args; } void set_arguments(List<Item> &list); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 3c5990eb359..8c38cb2a859 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -511,8 +511,8 @@ err: longlong Item_func_spatial_rel::val_int() { DBUG_ASSERT(fixed == 1); - String *res1= args[0]->val_str(&tmp_value1); - String *res2= args[1]->val_str(&tmp_value2); + String *res1= args[0]->val_str(&cmp.value1); + String *res2= args[1]->val_str(&cmp.value2); Geometry_buffer buffer1, buffer2; Geometry *g1, *g2; MBR mbr1, mbr2; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 39c4b8e7033..183a628f8e4 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1827,8 +1827,9 @@ String *Item_func_database::val_str(String *str) /** - @todo - make USER() replicate properly (currently it is replicated to "") + @note USER() is replicated correctly if binlog_format=ROW or (as of + BUG#28086) binlog_format=MIXED, but is incorrectly replicated to '' + if binlog_format=STATEMENT. */ bool Item_func_user::init(const char *user, const char *host) { diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index fa776ea3dca..26d3833f72c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -480,6 +480,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) void Item_singlerow_subselect::store(uint i, Item *item) { row[i]->store(item); + row[i]->cache_value(); } enum Item_result Item_singlerow_subselect::result_type() const @@ -1831,6 +1832,7 @@ void subselect_engine::set_row(List<Item> &item_list, Item_cache **row) if (!(row[i]= Item_cache::get_cache(sel_item))) return; row[i]->setup(sel_item); + row[i]->store(sel_item); } if (item_list.elements > 1) res_type= ROW_RESULT; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index ea59521aab1..3503d42edc0 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -135,6 +135,7 @@ public: @return the SELECT_LEX structure associated with this Item */ st_select_lex* get_select_lex(); + const char *func_name() const { DBUG_ASSERT(0); return "subselect"; } friend class select_subselect; friend class Item_in_optimizer; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 38251294053..4ab8e75ddf5 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -517,8 +517,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, name, table->s, collation.collation); break; case DECIMAL_RESULT: - field= new Field_new_decimal(max_length, maybe_null, name, - decimals, unsigned_flag); + field= Field_new_decimal::create_from_item(this); break; case ROW_RESULT: default: @@ -615,35 +614,6 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) } -Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) - :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type), - hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), - was_values(item->was_values) -{ - /* copy results from old value */ - switch (hybrid_type) { - case INT_RESULT: - sum_int= item->sum_int; - break; - case DECIMAL_RESULT: - my_decimal2decimal(&item->sum_dec, &sum_dec); - break; - case REAL_RESULT: - sum= item->sum; - break; - case STRING_RESULT: - /* - This can happen with ROLLUP. Note that the value is already - copied at function call. - */ - break; - case ROW_RESULT: - default: - DBUG_ASSERT(0); - } - collation.set(item->collation); -} - bool Item_sum_hybrid::fix_fields(THD *thd, Item **ref) { @@ -663,15 +633,12 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) switch (hybrid_type= item->result_type()) { case INT_RESULT: max_length= 20; - sum_int= 0; break; case DECIMAL_RESULT: max_length= item->max_length; - my_decimal_set_zero(&sum_dec); break; case REAL_RESULT: max_length= float_length(decimals); - sum= 0.0; break; case STRING_RESULT: max_length= item->max_length; @@ -680,10 +647,10 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) default: DBUG_ASSERT(0); }; + setup(args[0], NULL); /* MIN/MAX can return NULL for empty set indepedent of the used column */ maybe_null= 1; unsigned_flag=item->unsigned_flag; - collation.set(item->collation); result_field=0; null_value=1; fix_length_and_dec(); @@ -701,6 +668,30 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) return FALSE; } + +/** + MIN/MAX function setup. + + @param item argument of MIN/MAX function + @param value_arg calculated value of MIN/MAX function + + @details + Setup cache/comparator of MIN/MAX functions. When called by the + copy_or_same function value_arg parameter contains calculated value + of the original MIN/MAX object and it is saved in this object's cache. +*/ + +void Item_sum_hybrid::setup(Item *item, Item *value_arg) +{ + value= Item_cache::get_cache(item); + value->setup(item); + value->store(value_arg); + cmp= new Arg_comparator(); + cmp->set_cmp_func(this, args, (Item**)&value, FALSE); + collation.set(item->collation); +} + + Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table, uint convert_blob_length) { @@ -1270,8 +1261,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, 0, name, &my_charset_bin); } else if (hybrid_type == DECIMAL_RESULT) - field= new Field_new_decimal(max_length, maybe_null, name, - decimals, unsigned_flag); + field= Field_new_decimal::create_from_item(this); else field= new Field_double(max_length, maybe_null, name, decimals, TRUE); if (field) @@ -1592,19 +1582,7 @@ void Item_sum_variance::update_field() void Item_sum_hybrid::clear() { - switch (hybrid_type) { - case INT_RESULT: - sum_int= 0; - break; - case DECIMAL_RESULT: - my_decimal_set_zero(&sum_dec); - break; - case REAL_RESULT: - sum= 0.0; - break; - default: - value.length(0); - } + value->null_value= 1; null_value= 1; } @@ -1613,30 +1591,7 @@ double Item_sum_hybrid::val_real() DBUG_ASSERT(fixed == 1); if (null_value) return 0.0; - switch (hybrid_type) { - case STRING_RESULT: - { - char *end_not_used; - int err_not_used; - String *res; res=val_str(&str_value); - return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(), - &end_not_used, &err_not_used) : 0.0); - } - case INT_RESULT: - if (unsigned_flag) - return ulonglong2double(sum_int); - return (double) sum_int; - case DECIMAL_RESULT: - my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum); - return sum; - case REAL_RESULT: - return sum; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - return 0; - } + return value->val_real(); } longlong Item_sum_hybrid::val_int() @@ -1644,18 +1599,7 @@ longlong Item_sum_hybrid::val_int() DBUG_ASSERT(fixed == 1); if (null_value) return 0; - switch (hybrid_type) { - case INT_RESULT: - return sum_int; - case DECIMAL_RESULT: - { - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result); - return sum_int; - } - default: - return (longlong) rint(Item_sum_hybrid::val_real()); - } + return value->val_int(); } @@ -1664,26 +1608,7 @@ my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val) DBUG_ASSERT(fixed == 1); if (null_value) return 0; - switch (hybrid_type) { - case STRING_RESULT: - string2my_decimal(E_DEC_FATAL_ERROR, &value, val); - break; - case REAL_RESULT: - double2my_decimal(E_DEC_FATAL_ERROR, sum, val); - break; - case DECIMAL_RESULT: - val= &sum_dec; - break; - case INT_RESULT: - int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val); - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - break; - } - return val; // Keep compiler happy + return value->val_decimal(val); } @@ -1693,25 +1618,7 @@ Item_sum_hybrid::val_str(String *str) DBUG_ASSERT(fixed == 1); if (null_value) return 0; - switch (hybrid_type) { - case STRING_RESULT: - return &value; - case REAL_RESULT: - str->set_real(sum,decimals, &my_charset_bin); - break; - case DECIMAL_RESULT: - my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str); - return str; - case INT_RESULT: - str->set_int(sum_int, unsigned_flag, &my_charset_bin); - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - break; - } - return str; // Keep compiler happy + return value->val_str(str); } @@ -1720,7 +1627,9 @@ void Item_sum_hybrid::cleanup() DBUG_ENTER("Item_sum_hybrid::cleanup"); Item_sum::cleanup(); forced_const= FALSE; - + if (cmp) + delete cmp; + cmp= 0; /* by default it is TRUE to avoid TRUE reporting by Item_func_not_all/Item_func_nop_all if this item was never called. @@ -1741,63 +1650,22 @@ void Item_sum_hybrid::no_rows_in_result() Item *Item_sum_min::copy_or_same(THD* thd) { - return new (thd->mem_root) Item_sum_min(thd, this); + Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this); + item->setup(args[0], value); + return item; } bool Item_sum_min::add() { - switch (hybrid_type) { - case STRING_RESULT: + /* args[0] < value */ + int res= cmp->compare(); + if (!args[0]->null_value && + (null_value || res < 0)) { - String *result=args[0]->val_str(&tmp_value); - if (!args[0]->null_value && - (null_value || sortcmp(&value,result,collation.collation) > 0)) - { - value.copy(*result); - null_value=0; - } - } - break; - case INT_RESULT: - { - longlong nr=args[0]->val_int(); - if (!args[0]->null_value && (null_value || - (unsigned_flag && - (ulonglong) nr < (ulonglong) sum_int) || - (!unsigned_flag && nr < sum_int))) - { - sum_int=nr; - null_value=0; - } - } - break; - case DECIMAL_RESULT: - { - my_decimal value_buff, *val= args[0]->val_decimal(&value_buff); - if (!args[0]->null_value && - (null_value || (my_decimal_cmp(&sum_dec, val) > 0))) - { - my_decimal2decimal(val, &sum_dec); - null_value= 0; - } - } - break; - case REAL_RESULT: - { - double nr= args[0]->val_real(); - if (!args[0]->null_value && (null_value || nr < sum)) - { - sum=nr; - null_value=0; - } - } - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - break; + value->store(args[0]); + value->cache_value(); + null_value= 0; } return 0; } @@ -1805,63 +1673,22 @@ bool Item_sum_min::add() Item *Item_sum_max::copy_or_same(THD* thd) { - return new (thd->mem_root) Item_sum_max(thd, this); + Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this); + item->setup(args[0], value); + return item; } bool Item_sum_max::add() { - switch (hybrid_type) { - case STRING_RESULT: + /* args[0] > value */ + int res= cmp->compare(); + if (!args[0]->null_value && + (null_value || res > 0)) { - String *result=args[0]->val_str(&tmp_value); - if (!args[0]->null_value && - (null_value || sortcmp(&value,result,collation.collation) < 0)) - { - value.copy(*result); - null_value=0; - } - } - break; - case INT_RESULT: - { - longlong nr=args[0]->val_int(); - if (!args[0]->null_value && (null_value || - (unsigned_flag && - (ulonglong) nr > (ulonglong) sum_int) || - (!unsigned_flag && nr > sum_int))) - { - sum_int=nr; - null_value=0; - } - } - break; - case DECIMAL_RESULT: - { - my_decimal value_buff, *val= args[0]->val_decimal(&value_buff); - if (!args[0]->null_value && - (null_value || (my_decimal_cmp(val, &sum_dec) > 0))) - { - my_decimal2decimal(val, &sum_dec); - null_value= 0; - } - } - break; - case REAL_RESULT: - { - double nr= args[0]->val_real(); - if (!args[0]->null_value && (null_value || nr > sum)) - { - sum=nr; - null_value=0; - } - } - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - break; + value->store(args[0]); + value->cache_value(); + null_value= 0; } return 0; } @@ -2226,14 +2053,15 @@ void Item_sum_hybrid::update_field() void Item_sum_hybrid::min_max_update_str_field() { - String *res_str=args[0]->val_str(&value); + DBUG_ASSERT(cmp); + String *res_str=args[0]->val_str(&cmp->value1); if (!args[0]->null_value) { - result_field->val_str(&tmp_value); + result_field->val_str(&cmp->value2); if (result_field->is_null() || - (cmp_sign * sortcmp(res_str,&tmp_value,collation.collation)) < 0) + (cmp_sign * sortcmp(res_str,&cmp->value2,collation.collation)) < 0) result_field->store(res_str->ptr(),res_str->length(),res_str->charset()); result_field->set_notnull(); } diff --git a/sql/item_sum.h b/sql/item_sum.h index 993ec1597b4..da9ad9963c5 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -326,22 +326,6 @@ public: virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - /* - This method is used for debug purposes to print the name of an - item to the debug log. The second use of this method is as - a helper function of print(), where it is applicable. - To suit both goals it should return a meaningful, - distinguishable and sintactically correct string. This method - should not be used for runtime type identification, use enum - {Sum}Functype and Item_func::functype()/Item_sum::sum_func() - instead. - - NOTE: for Items inherited from Item_sum, func_name() return part of - function name till first argument (including '(') to make difference in - names for functions with 'distinct' clause and without 'distinct' and - also to make printing of items inherited from Item_sum uniform. - */ - virtual const char *func_name() const= 0; virtual Item *result_item(Field *field) { return new Item_field(field); } table_map used_tables() const { return used_tables_cache; } @@ -667,6 +651,7 @@ public: } void fix_length_and_dec() {} enum Item_result result_type () const { return hybrid_type; } + const char *func_name() const { DBUG_ASSERT(0); return "avg_field"; } }; @@ -735,6 +720,7 @@ public: } void fix_length_and_dec() {} enum Item_result result_type () const { return hybrid_type; } + const char *func_name() const { DBUG_ASSERT(0); return "variance_field"; } }; @@ -810,6 +796,7 @@ public: my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return REAL_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} + const char *func_name() const { DBUG_ASSERT(0); return "std_field"; } }; /* @@ -835,14 +822,13 @@ class Item_sum_std :public Item_sum_variance }; // This class is a string or number function depending on num_func - +class Arg_comparator; +class Item_cache; class Item_sum_hybrid :public Item_sum { protected: - String value,tmp_value; - double sum; - longlong sum_int; - my_decimal sum_dec; + Item_cache *value; + Arg_comparator *cmp; Item_result hybrid_type; enum_field_types hybrid_field_type; int cmp_sign; @@ -850,12 +836,17 @@ protected: public: Item_sum_hybrid(Item *item_par,int sign) - :Item_sum(item_par), sum(0.0), sum_int(0), + :Item_sum(item_par), value(0), cmp(0), hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG), cmp_sign(sign), was_values(TRUE) { collation.set(&my_charset_bin); } - Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); + Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) + :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type), + hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), + was_values(item->was_values) + { } bool fix_fields(THD *, Item **); + void setup(Item *item, Item *value_arg); void clear(); double val_real(); longlong val_int(); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index b5037c08b3c..b293145cc27 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -386,7 +386,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, if (tmp - val > 6) tmp= (char*) val + 6; l_time->second_part= (int) my_strtoll10(val, &tmp, &error); - frac_part= 6 - (uint) (tmp - val); + frac_part= 6 - (int) (tmp - val); if (frac_part > 0) l_time->second_part*= (ulong) log_10_int[frac_part]; val= tmp; @@ -876,9 +876,9 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs, value= value*LL(10) + (longlong) (*str - '0'); if (transform_msec && i == count - 1) // microseconds always last { - long msec_length= 6 - (uint) (str - start); + int msec_length= 6 - (int)(str - start); if (msec_length > 0) - value*= (long) log_10_int[msec_length]; + value*= (long)log_10_int[msec_length]; } values[i]= value; while (str != end && !my_isdigit(cs,*str)) diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 1eff00027f2..3e20b90e68e 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -941,14 +941,16 @@ static Item *create_comparator(MY_XPATH *xpath, in a loop through all of the nodes in the node set. */ - Item *fake= new Item_string("", 0, xpath->cs); + Item_string *fake= new Item_string("", 0, xpath->cs); + /* Don't cache fake because its value will be changed during comparison.*/ + fake->set_used_tables(RAND_TABLE_BIT); Item_nodeset_func *nodeset; Item *scalar, *comp; if (a->type() == Item::XPATH_NODESET) { nodeset= (Item_nodeset_func*) a; scalar= b; - comp= eq_func(oper, fake, scalar); + comp= eq_func(oper, (Item*)fake, scalar); } else { diff --git a/sql/log.cc b/sql/log.cc index 1c95b21f533..5a7d3368abd 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3989,11 +3989,8 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans) DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); - Table_map_log_event::flag_set const - flags= Table_map_log_event::TM_NO_FLAGS; - Table_map_log_event - the_event(this, table, table->s->table_map_id, is_trans, flags); + the_event(this, table, table->s->table_map_id, is_trans); if (is_trans && binlog_table_maps == 0) binlog_start_trans_and_stmt(); @@ -5839,9 +5836,8 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) Xid_log_event *xev=(Xid_log_event *)ev; uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid, sizeof(xev->xid)); - if (! x) + if (!x || my_hash_insert(&xids, x)) goto err2; - my_hash_insert(&xids, x); } delete ev; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 060b675b0e4..d0c8c245175 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -29,7 +29,6 @@ #include "rpl_rli.h" #include "rpl_mi.h" #include "rpl_filter.h" -#include "rpl_utility.h" #include "rpl_record.h" #include <my_dir.h> @@ -37,6 +36,7 @@ #include <base64.h> #include <my_bitmap.h> +#include "rpl_utility.h" #define log_cs &my_charset_latin1 @@ -1570,37 +1570,14 @@ log_event_print_value(IO_CACHE *file, const uchar *ptr, /* a long CHAR() field: see #37426 */ length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4); type= byte0 | 0x30; - goto beg; - } - - switch (byte0) - { - case MYSQL_TYPE_SET: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_STRING: - type= byte0; - length= byte1; - break; - - default: - - { - char tmp[5]; - my_snprintf(tmp, sizeof(tmp), "%04X", meta); - my_b_printf(file, - "!! Don't know how to handle column type=%d meta=%d (%s)", - type, meta, tmp); - return 0; - } } + else + length = meta & 0xFF; } else length= meta; } - -beg: - switch (type) { case MYSQL_TYPE_LONG: { @@ -1737,6 +1714,33 @@ beg: return 3; } + case MYSQL_TYPE_NEWDATE: + { + uint32 tmp= uint3korr(ptr); + int part; + char buf[10]; + char *pos= &buf[10]; + + /* Copied from field.cc */ + *pos--=0; // End NULL + part=(int) (tmp & 31); + *pos--= (char) ('0'+part%10); + *pos--= (char) ('0'+part/10); + *pos--= ':'; + part=(int) (tmp >> 5 & 15); + *pos--= (char) ('0'+part%10); + *pos--= (char) ('0'+part/10); + *pos--= ':'; + part=(int) (tmp >> 9); + *pos--= (char) ('0'+part%10); part/=10; + *pos--= (char) ('0'+part%10); part/=10; + *pos--= (char) ('0'+part%10); part/=10; + *pos= (char) ('0'+part); + my_b_printf(file , "'%s'", buf); + my_snprintf(typestr, typestr_length, "DATE"); + return 3; + } + case MYSQL_TYPE_DATE: { uint i32= uint3korr(ptr); @@ -1755,7 +1759,7 @@ beg: } case MYSQL_TYPE_ENUM: - switch (length) { + switch (meta & 0xFF) { case 1: my_b_printf(file, "%d", (int) *ptr); my_snprintf(typestr, typestr_length, "ENUM(1 byte)"); @@ -1768,15 +1772,15 @@ beg: return 2; } default: - my_b_printf(file, "!! Unknown ENUM packlen=%d", length); + my_b_printf(file, "!! Unknown ENUM packlen=%d", meta & 0xFF); return 0; } break; case MYSQL_TYPE_SET: - my_b_write_bit(file, ptr , length * 8); - my_snprintf(typestr, typestr_length, "SET(%d bytes)", length); - return length; + my_b_write_bit(file, ptr , (meta & 0xFF) * 8); + my_snprintf(typestr, typestr_length, "SET(%d bytes)", meta & 0xFF); + return meta & 0xFF; case MYSQL_TYPE_BLOB: switch (meta) { @@ -7341,11 +7345,18 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) */ { + DBUG_PRINT("debug", ("Checking compability of tables to lock - tables_to_lock: %p", + rli->tables_to_lock)); RPL_TABLE_LIST *ptr= rli->tables_to_lock; for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global)) { - if (ptr->m_tabledef.compatible_with(rli, ptr->table)) + TABLE *conv_table; + if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli), + ptr->table, &conv_table)) { + DBUG_PRINT("debug", ("Table: %s.%s is not compatible with master", + ptr->table->s->db.str, + ptr->table->s->table_name.str)); /* We should not honour --slave-skip-errors at this point as we are having severe errors which should not be skiped. @@ -7356,12 +7367,17 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(ERR_BAD_TABLE_DEF); } + DBUG_PRINT("debug", ("Table: %s.%s is compatible with master" + " - conv_table: %p", + ptr->table->s->db.str, + ptr->table->s->table_name.str, conv_table)); + ptr->m_conv_table= conv_table; } } /* - ... and then we add all the tables to the table map and remove - them from tables to lock. + ... and then we add all the tables to the table map and but keep + them in the tables to lock list. We also invalidate the query cache for all the tables, since they will now be changed. @@ -7839,7 +7855,10 @@ int Table_map_log_event::save_field_metadata() DBUG_ENTER("Table_map_log_event::save_field_metadata"); int index= 0; for (unsigned int i= 0 ; i < m_table->s->fields ; i++) + { + DBUG_PRINT("debug", ("field_type: %d", m_coltype[i])); index+= m_table->s->field[i]->save_field_metadata(&m_field_metadata[index]); + } DBUG_RETURN(index); } #endif /* !defined(MYSQL_CLIENT) */ @@ -7851,7 +7870,7 @@ int Table_map_log_event::save_field_metadata() */ #if !defined(MYSQL_CLIENT) Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, - bool is_transactional, uint16 flags) + bool is_transactional) : Log_event(thd, 0, true), m_table(tbl), m_dbnam(tbl->s->db.str), @@ -7861,7 +7880,7 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, m_colcnt(tbl->s->fields), m_memory(NULL), m_table_id(tid), - m_flags(flags), + m_flags(TM_BIT_LEN_EXACT_F), m_data_size(0), m_field_metadata(0), m_field_metadata_size(0), @@ -8119,8 +8138,10 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) inside Relay_log_info::clear_tables_to_lock() by calling the table_def destructor explicitly. */ - new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt, - m_field_metadata, m_field_metadata_size, m_null_bits); + new (&table_list->m_tabledef) + table_def(m_coltype, m_colcnt, + m_field_metadata, m_field_metadata_size, + m_null_bits, m_flags); table_list->m_tabledef_valid= TRUE; /* diff --git a/sql/log_event.h b/sql/log_event.h index cd5e659c910..d4168a87331 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3304,16 +3304,14 @@ public: /* Special constants representing sets of flags */ enum { - TM_NO_FLAGS = 0U + TM_NO_FLAGS = 0U, + TM_BIT_LEN_EXACT_F = (1U << 0) }; - void set_flags(flag_set flag) { m_flags |= flag; } - void clear_flags(flag_set flag) { m_flags &= ~flag; } flag_set get_flags(flag_set flag) const { return m_flags & flag; } #ifndef MYSQL_CLIENT - Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, - bool is_transactional, uint16 flags); + Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, bool is_transactional); #endif #ifdef HAVE_REPLICATION Table_map_log_event(const char *buf, uint event_len, @@ -3326,7 +3324,7 @@ public: table_def *create_table_def() { return new table_def(m_coltype, m_colcnt, m_field_metadata, - m_field_metadata_size, m_null_bits); + m_field_metadata_size, m_null_bits, m_flags); } ulong get_table_id() const { return m_table_id; } const char *get_table_name() const { return m_tblnam; } diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 7ed36ed33b0..4edf060450c 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -107,14 +107,24 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info RPL_TABLE_LIST *ptr= rli->tables_to_lock; for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global)) { - if (ptr->m_tabledef.compatible_with(rli, ptr->table)) + TABLE *conv_table; + if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli), + ptr->table, &conv_table)) { + DBUG_PRINT("debug", ("Table: %s.%s is not compatible with master", + ptr->table->s->db.str, + ptr->table->s->table_name.str)); mysql_unlock_tables(thd, thd->lock); thd->lock= 0; thd->is_slave_error= 1; const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(Old_rows_log_event::ERR_BAD_TABLE_DEF); } + DBUG_PRINT("debug", ("Table: %s.%s is compatible with master" + " - conv_table: %p", + ptr->table->s->db.str, + ptr->table->s->table_name.str, conv_table)); + ptr->m_conv_table= conv_table; } } @@ -1550,7 +1560,9 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) RPL_TABLE_LIST *ptr= rli->tables_to_lock; for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global)) { - if (ptr->m_tabledef.compatible_with(rli, ptr->table)) + TABLE *conv_table; + if (ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli), + ptr->table, &conv_table)) { mysql_unlock_tables(thd, thd->lock); thd->lock= 0; @@ -1558,12 +1570,14 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(ERR_BAD_TABLE_DEF); } + ptr->m_conv_table= conv_table; } } /* - ... and then we add all the tables to the table map and remove - them from tables to lock. + ... and then we add all the tables to the table map but keep + them in the tables to lock list. + We also invalidate the query cache for all the tables, since they will now be changed. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ca7dfc4e204..abd1d58d4e9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1926,6 +1926,7 @@ extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_slave_compressed_protocol, use_temp_pool; extern ulong slave_exec_mode_options; +extern ulong slave_type_conversions_options; extern my_bool opt_readonly, lower_case_file_system; extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; extern my_bool opt_secure_auth; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8468e7cf79a..ce471f42aaa 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -527,6 +527,8 @@ ulong open_files_limit, max_binlog_size, max_relay_log_size; ulong slave_net_timeout, slave_trans_retries; ulong slave_exec_mode_options; const char *slave_exec_mode_str= "STRICT"; +ulong slave_type_conversions_options; +const char *slave_type_conversions_default= ""; ulong thread_cache_size=0, thread_pool_size= 0; ulong binlog_cache_size=0; ulonglong max_binlog_cache_size=0; @@ -3899,6 +3901,27 @@ will be ignored as the --log-bin option is not defined."); if (opt_bin_log) { + /* Reports an error and aborts, if the --log-bin's path + is a directory.*/ + if (opt_bin_logname && + opt_bin_logname[strlen(opt_bin_logname) - 1] == FN_LIBCHAR) + { + sql_print_error("Path '%s' is a directory name, please specify \ +a file name for --log-bin option", opt_bin_logname); + unireg_abort(1); + } + + /* Reports an error and aborts, if the --log-bin-index's path + is a directory.*/ + if (opt_binlog_index_name && + opt_binlog_index_name[strlen(opt_binlog_index_name) - 1] + == FN_LIBCHAR) + { + sql_print_error("Path '%s' is a directory name, please specify \ +a file name for --log-bin-index option", opt_binlog_index_name); + unireg_abort(1); + } + char buf[FN_REFLEN]; const char *ln; ln= mysql_bin_log.generate_name(opt_bin_logname, "-bin", 1, buf); @@ -5205,12 +5228,16 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) pthread_handler_t handle_connections_namedpipes(void *arg) { HANDLE hConnectedPipe; - OVERLAPPED connectOverlapped = {0}; + OVERLAPPED connectOverlapped= {0}; THD *thd; my_thread_init(); DBUG_ENTER("handle_connections_namedpipes"); - connectOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - + connectOverlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL); + if (!connectOverlapped.hEvent) + { + sql_print_error("Can't create event, last error=%u", GetLastError()); + unireg_abort(1); + } DBUG_PRINT("general",("Waiting for named pipe connections.")); while (!abort_loop) { @@ -5233,7 +5260,8 @@ pthread_handler_t handle_connections_namedpipes(void *arg) { CloseHandle(hPipe); if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, + PIPE_ACCESS_DUPLEX | + FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -5253,7 +5281,8 @@ pthread_handler_t handle_connections_namedpipes(void *arg) hConnectedPipe = hPipe; /* create new pipe for new connection */ if ((hPipe = CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, + PIPE_ACCESS_DUPLEX | + FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -5696,6 +5725,7 @@ enum options_mysqld #endif /* defined(ENABLED_DEBUG_SYNC) */ OPT_OLD_MODE, OPT_SLAVE_EXEC_MODE, + OPT_SLAVE_TYPE_CONVERSIONS, OPT_GENERAL_LOG_FILE, OPT_SLOW_QUERY_LOG_FILE, OPT_IGNORE_BUILTIN_INNODB, @@ -6377,6 +6407,15 @@ replicating a LOAD DATA INFILE command.", {"slave-exec-mode", OPT_SLAVE_EXEC_MODE, "Modes for how replication events should be executed. Legal values are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, replication will not stop for operations that are idempotent. In STRICT mode, replication will stop on any unexpected difference between the master and the slave.", (uchar**) &slave_exec_mode_str, (uchar**) &slave_exec_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"slave-type-conversions", OPT_SLAVE_TYPE_CONVERSIONS, + "Set of slave type conversions that are enabled. Legal values are:" + " ALL_LOSSY to enable lossy conversions and" + " ALL_NON_LOSSY to enable non-lossy conversions." + " If the variable is assigned the empty set, no conversions are" + " allowed and it is expected that the types match exactly.", + (uchar**) &slave_type_conversions_default, + (uchar**) &slave_type_conversions_default, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"slow-query-log", OPT_SLOW_LOG, "Enable|disable slow query log", (uchar**) &opt_slow_log, @@ -7694,6 +7733,11 @@ static int mysql_init_variables(void) slave_exec_mode_options= (uint) find_bit_type_or_exit(slave_exec_mode_str, &slave_exec_mode_typelib, NULL, &error); + /* Slave type conversions */ + slave_type_conversions_options= 0; + slave_type_conversions_options= + find_bit_type_or_exit(slave_type_conversions_default, &slave_type_conversions_typelib, + NULL, &error); if (error) return 1; opt_specialflag= SPECIAL_ENGLISH; @@ -7919,6 +7963,12 @@ mysqld_get_one_option(int optid, if (error) return 1; break; + case OPT_SLAVE_TYPE_CONVERSIONS: + slave_type_conversions_options= (uint) + find_bit_type_or_exit(argument, &slave_type_conversions_typelib, "", &error); + if (error) + return 1; + break; #endif case OPT_SAFEMALLOC_MEM_LIMIT: #if !defined(DBUG_OFF) && defined(SAFEMALLOC) @@ -8639,14 +8689,8 @@ static int fix_paths(void) pos[0]= FN_LIBCHAR; pos[1]= 0; } - convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); - my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); - mysql_unpacked_real_data_home_len= strlen(mysql_unpacked_real_data_home); - if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) - --mysql_unpacked_real_data_home_len; - - convert_dirname(language,language,NullS); + convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home); @@ -8654,6 +8698,12 @@ static int fix_paths(void) get_relative_path(PLUGINDIR), mysql_home); opt_plugin_dir_ptr= opt_plugin_dir; + my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); + mysql_unpacked_real_data_home_len= + (int) strlen(mysql_unpacked_real_data_home); + if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) + --mysql_unpacked_real_data_home_len; + char *sharedir=get_relative_path(SHAREDIR); if (test_if_hard_path(sharedir)) strmake(buff,sharedir,sizeof(buff)-1); /* purecov: tested */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 5f9bae22c70..94204962345 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -446,9 +446,9 @@ public: range_key, *range_key_flag); *range_key_flag|= key_tree->min_flag; if (key_tree->next_key_part && + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && key_tree->next_key_part->part == key_tree->part+1 && - !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) && - key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN))) res+= key_tree->next_key_part->store_min_key(key, range_key, range_key_flag); return res; @@ -462,9 +462,9 @@ public: range_key, *range_key_flag); (*range_key_flag)|= key_tree->max_flag; if (key_tree->next_key_part && + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && key_tree->next_key_part->part == key_tree->part+1 && - !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) && - key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX))) res+= key_tree->next_key_part->store_max_key(key, range_key, range_key_flag); return res; @@ -1700,6 +1700,7 @@ SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, tmp->prev= *next_arg; // Link into next/prev chain (*next_arg)->next=tmp; (*next_arg)= tmp; + tmp->part= this->part; } else { @@ -6671,6 +6672,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) else if ((cmp=tmp->cmp_max_to_min(key2)) < 0) { // Found tmp.max < key2.min SEL_ARG *next=tmp->next; + /* key1 on the left of key2 non-overlapping */ if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part)) { // Join near ranges like tmp.max < 0 and key2.min >= 0 @@ -6699,6 +6701,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) int tmp_cmp; if ((tmp_cmp=tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max { + /* tmp is on the right of key2 non-overlapping */ if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part)) { // ranges are connected tmp->copy_min_to_min(key2); @@ -6733,25 +6736,52 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) } } - // tmp.max >= key2.min && tmp.min <= key.max (overlapping ranges) + /* + tmp.min >= key2.min && tmp.min <= key.max (overlapping ranges) + key2.min <= tmp.min <= key2.max + */ if (eq_tree(tmp->next_key_part,key2->next_key_part)) { if (tmp->is_same(key2)) { + /* + Found exact match of key2 inside key1. + Use the relevant range in key1. + */ tmp->merge_flags(key2); // Copy maybe flags key2->increment_use_count(-1); // Free not used tree } else { SEL_ARG *last=tmp; + SEL_ARG *first=tmp; + /* + Find the last range in tmp that overlaps key2 and has the same + condition on the rest of the keyparts. + */ while (last->next && last->next->cmp_min_to_max(key2) <= 0 && eq_tree(last->next->next_key_part,key2->next_key_part)) { + /* + We've found the last overlapping key1 range in last. + This means that the ranges between (and including) the + first overlapping range (tmp) and the last overlapping range + (last) are fully nested into the current range of key2 + and can safely be discarded. We just need the minimum endpoint + of the first overlapping range (tmp) so we can compare it with + the minimum endpoint of the enclosing key2 range. + */ SEL_ARG *save=last; last=last->next; key1=key1->tree_delete(save); } - last->copy_min(tmp); + /* + The tmp range (the first overlapping range) could have been discarded + by the previous loop. We should re-direct tmp to the new united range + that's taking its place. + */ + tmp= last; + last->copy_min(first); bool full_range= last->copy_min(key2); if (!full_range) { @@ -7261,27 +7291,25 @@ int test_rb_tree(SEL_ARG *element,SEL_ARG *parent) } -/* - Count how many times SEL_ARG graph "root" refers to its part "key" +/** + Count how many times SEL_ARG graph "root" refers to its part "key" via + transitive closure. - SYNOPSIS - count_key_part_usage() - root An RB-Root node in a SEL_ARG graph. - key Another RB-Root node in that SEL_ARG graph. - - DESCRIPTION - The passed "root" node may refer to "key" node via root->next_key_part, - root->next->n - - This function counts how many times the node "key" is referred (via - SEL_ARG::next_key_part) by - - intervals of RB-tree pointed by "root", - - intervals of RB-trees that are pointed by SEL_ARG::next_key_part from - intervals of RB-tree pointed by "root", - - and so on. + @param root An RB-Root node in a SEL_ARG graph. + @param key Another RB-Root node in that SEL_ARG graph. + + The passed "root" node may refer to "key" node via root->next_key_part, + root->next->n + + This function counts how many times the node "key" is referred (via + SEL_ARG::next_key_part) by + - intervals of RB-tree pointed by "root", + - intervals of RB-trees that are pointed by SEL_ARG::next_key_part from + intervals of RB-tree pointed by "root", + - and so on. - Here is an example (horizontal links represent next_key_part pointers, - vertical links - next/prev prev pointers): + Here is an example (horizontal links represent next_key_part pointers, + vertical links - next/prev prev pointers): +----+ $ |root|-----------------+ @@ -7301,8 +7329,8 @@ int test_rb_tree(SEL_ARG *element,SEL_ARG *parent) ... +---+ $ | | |------------+ +---+ $ - RETURN - Number of links to "key" from nodes reachable from "root". + @return + Number of links to "key" from nodes reachable from "root". */ static ulong count_key_part_usage(SEL_ARG *root, SEL_ARG *key) @@ -7557,8 +7585,8 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree, param->first_null_comp= key_tree->part+1; if (key_tree->next_key_part && - key_tree->next_key_part->part == key_tree->part+1 && - key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && + key_tree->next_key_part->part == key_tree->part+1) { // const key as prefix if (min_key_length == max_key_length && !memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) && @@ -7839,8 +7867,8 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, &tmp_max_key,max_key_flag); if (key_tree->next_key_part && - key_tree->next_key_part->part == key_tree->part+1 && - key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && + key_tree->next_key_part->part == key_tree->part+1) { // const key as prefix if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && memcmp(min_key, max_key, (uint)(tmp_max_key - max_key))==0 && @@ -9822,7 +9850,11 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, } else if (cur_arg->const_item()) { - DBUG_RETURN(TRUE); + /* + For predicates of the form "const OP expr" we also have to check 'expr' + to make a decision. + */ + continue; } else DBUG_RETURN(FALSE); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index cbc22406460..8a8403d1725 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -558,7 +558,12 @@ HOSTS"; goto err; } si->server_id = log_server_id; - my_hash_insert(&slave_list, (uchar*)si); + if (my_hash_insert(&slave_list, (uchar*)si)) + { + error= "the slave is out of memory"; + pthread_mutex_unlock(&LOCK_slave_list); + goto err; + } } strmake(si->host, row[1], sizeof(si->host)-1); si->port = atoi(row[port_ind]); diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 8e80620dd2c..00f586cfdd8 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -104,10 +104,10 @@ pack_row(TABLE *table, MY_BITMAP const* cols, #endif pack_ptr= field->pack(pack_ptr, field->ptr + offset, field->max_data_length(), TRUE); - DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" + DBUG_PRINT("debug", ("field: %s; real_type: %d, pack_ptr: 0x%lx;" " pack_ptr':0x%lx; bytes: %d", - field->field_name, (ulong) old_pack_ptr, - (ulong) pack_ptr, + field->field_name, field->real_type(), + (ulong) old_pack_ptr, (ulong) pack_ptr, (int) (pack_ptr - old_pack_ptr))); } @@ -202,10 +202,30 @@ unpack_row(Relay_log_info const *rli, // The "current" null bits unsigned int null_bits= *null_ptr++; uint i= 0; - table_def *tabledef= ((Relay_log_info*)rli)->get_tabledef(table); + table_def *tabledef; + TABLE *conv_table; + bool table_found= rli->get_table_data(table, &tabledef, &conv_table); + DBUG_PRINT("debug", ("Table data: table_found: %d, tabldef: %p, conv_table: %p", + table_found, tabledef, conv_table)); + DBUG_ASSERT(table_found); + if (!table_found) + return HA_ERR_GENERIC; + for (field_ptr= begin_ptr ; field_ptr < end_ptr && *field_ptr ; ++field_ptr) { - Field *const f= *field_ptr; + /* + If there is a conversion table, we pick up the field pointer to + the conversion table. If the conversion table or the field + pointer is NULL, no conversions are necessary. + */ + Field *conv_field= + conv_table ? conv_table->field[field_ptr - begin_ptr] : NULL; + Field *const f= + conv_field ? conv_field : *field_ptr; + DBUG_PRINT("debug", ("Conversion %srequired for field '%s' (#%d)", + conv_field ? "" : "not ", + (*field_ptr)->field_name, field_ptr - begin_ptr)); + DBUG_ASSERT(f != NULL); /* No need to bother about columns that does not exist: they have @@ -275,6 +295,39 @@ unpack_row(Relay_log_info const *rli, (int) (pack_ptr - old_pack_ptr))); } + /* + If conv_field is set, then we are doing a conversion. In this + case, we have unpacked the master data to the conversion + table, so we need to copy the value stored in the conversion + table into the final table and do the conversion at the same time. + */ + if (conv_field) + { + Copy_field copy; +#ifndef DBUG_OFF + char source_buf[MAX_FIELD_WIDTH]; + char value_buf[MAX_FIELD_WIDTH]; + String source_type(source_buf, sizeof(source_buf), system_charset_info); + String value_string(value_buf, sizeof(value_buf), system_charset_info); + conv_field->sql_type(source_type); + conv_field->val_str(&value_string); + DBUG_PRINT("debug", ("Copying field '%s' of type '%s' with value '%s'", + (*field_ptr)->field_name, + source_type.c_ptr(), value_string.c_ptr())); +#endif + copy.set(*field_ptr, f, TRUE); + (*copy.do_copy)(©); +#ifndef DBUG_OFF + char target_buf[MAX_FIELD_WIDTH]; + String target_type(target_buf, sizeof(target_buf), system_charset_info); + (*field_ptr)->sql_type(target_type); + (*field_ptr)->val_str(&value_string); + DBUG_PRINT("debug", ("Value of field '%s' of type '%s' is now '%s'", + (*field_ptr)->field_name, + target_type.c_ptr(), value_string.c_ptr())); +#endif + } + null_mask <<= 1; } i++; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 14b560600d8..e35ca613d23 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -106,7 +106,8 @@ int init_relay_log_info(Relay_log_info* rli, rli->tables_to_lock_count= 0; char pattern[FN_REFLEN]; - if (fn_format(pattern, PREFIX_SQL_LOAD, slave_load_tmpdir, "", + (void) my_realpath(pattern, slave_load_tmpdir, 0); + if (fn_format(pattern, PREFIX_SQL_LOAD, pattern, "", MY_SAFE_PATH | MY_RETURN_REAL_PATH) == NullS) { pthread_mutex_unlock(&rli->data_lock); @@ -133,6 +134,29 @@ int init_relay_log_info(Relay_log_info* rli, rli->relay_log.max_size (and mysql_bin_log.max_size). */ { + /* Reports an error and returns, if the --relay-log's path + is a directory.*/ + if (opt_relay_logname && + opt_relay_logname[strlen(opt_relay_logname) - 1] == FN_LIBCHAR) + { + pthread_mutex_unlock(&rli->data_lock); + sql_print_error("Path '%s' is a directory name, please specify \ +a file name for --relay-log option", opt_relay_logname); + DBUG_RETURN(1); + } + + /* Reports an error and returns, if the --relay-log-index's path + is a directory.*/ + if (opt_relaylog_index_name && + opt_relaylog_index_name[strlen(opt_relaylog_index_name) - 1] + == FN_LIBCHAR) + { + pthread_mutex_unlock(&rli->data_lock); + sql_print_error("Path '%s' is a directory name, please specify \ +a file name for --relay-log-index option", opt_relaylog_index_name); + DBUG_RETURN(1); + } + char buf[FN_REFLEN]; const char *ln; static bool name_warning_sent= 0; diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 1dc7f3ef0d2..7c43f821295 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -333,13 +333,21 @@ public: uint tables_to_lock_count; /* RBR: Count of tables to lock */ table_mapping m_table_map; /* RBR: Mapping table-id to table */ - inline table_def *get_tabledef(TABLE *tbl) + bool get_table_data(TABLE *table_arg, table_def **tabledef_var, TABLE **conv_table_var) const { - table_def *td= 0; - for (TABLE_LIST *ptr= tables_to_lock; ptr && !td; ptr= ptr->next_global) - if (ptr->table == tbl) - td= &((RPL_TABLE_LIST *)ptr)->m_tabledef; - return (td); + DBUG_ASSERT(tabledef_var && conv_table_var); + for (TABLE_LIST *ptr= tables_to_lock ; ptr != NULL ; ptr= ptr->next_global) + if (ptr->table == table_arg) + { + *tabledef_var= &static_cast<RPL_TABLE_LIST*>(ptr)->m_tabledef; + *conv_table_var= static_cast<RPL_TABLE_LIST*>(ptr)->m_conv_table; + DBUG_PRINT("debug", ("Fetching table data for table %s.%s:" + " tabledef: %p, conv_table: %p", + table_arg->s->db.str, table_arg->s->table_name.str, + *tabledef_var, *conv_table_var)); + return true; + } + return false; } /* diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc index a004c354263..6ef9a8623fe 100644 --- a/sql/rpl_tblmap.cc +++ b/sql/rpl_tblmap.cc @@ -119,7 +119,13 @@ int table_mapping::set_table(ulong table_id, TABLE* table) } e->table_id= table_id; e->table= table; - my_hash_insert(&m_table_ids,(uchar *)e); + if (my_hash_insert(&m_table_ids,(uchar *)e)) + { + /* we add this entry to the chain of free (free for use) entries */ + e->next= m_free; + m_free= e; + DBUG_RETURN(ERR_MEMORY_ALLOCATION); + } DBUG_PRINT("info", ("tid %lu -> table 0x%lx (%s)", table_id, (long) e->table, diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index e34f8561051..3a69c71b34c 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -14,8 +14,176 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "rpl_utility.h" + +#ifndef MYSQL_CLIENT #include "rpl_rli.h" +/** + Function to compare two size_t integers for their relative + order. Used below. + */ +int compare(size_t a, size_t b) +{ + if (a < b) + return -1; + if (b < a) + return 1; + return 0; +} + + +/** + Max value for an unsigned integer of 'bits' bits. + + The somewhat contorted expression is to avoid overflow. + */ +uint32 uint_max(int bits) { + return (((1UL << (bits - 1)) - 1) << 1) | 1; +} + + +/** + Compute the maximum display length of a field. + + @param sql_type Type of the field + @param metadata The metadata from the master for the field. + @return Maximum length of the field in bytes. + */ +static uint32 +max_display_length_for_field(enum_field_types sql_type, unsigned int metadata) +{ + DBUG_PRINT("debug", ("sql_type: %d, metadata: 0x%x", sql_type, metadata)); + DBUG_ASSERT(metadata >> 16 == 0); + + switch (sql_type) { + case MYSQL_TYPE_NEWDECIMAL: + return metadata >> 8; + + case MYSQL_TYPE_FLOAT: + return 12; + + case MYSQL_TYPE_DOUBLE: + return 22; + + case MYSQL_TYPE_SET: + case MYSQL_TYPE_ENUM: + return metadata & 0x00ff; + + case MYSQL_TYPE_STRING: + { + uchar type= metadata >> 8; + if (type == MYSQL_TYPE_SET || type == MYSQL_TYPE_ENUM) + return metadata & 0xff; + else + /* This is taken from Field_string::unpack. */ + return (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff); + } + + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_TINY: + return 4; + + case MYSQL_TYPE_SHORT: + return 6; + + case MYSQL_TYPE_INT24: + return 9; + + case MYSQL_TYPE_LONG: + return 11; + +#ifdef HAVE_LONG_LONG + case MYSQL_TYPE_LONGLONG: + return 20; + +#endif + case MYSQL_TYPE_NULL: + return 0; + + case MYSQL_TYPE_NEWDATE: + return 3; + + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + return 3; + + case MYSQL_TYPE_TIMESTAMP: + return 4; + + case MYSQL_TYPE_DATETIME: + return 8; + + case MYSQL_TYPE_BIT: + /* + Decode the size of the bit field from the master. + */ + DBUG_ASSERT((metadata & 0xff) <= 7); + return 8 * (metadata >> 8U) + (metadata & 0x00ff); + + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_VARCHAR: + return metadata; + + /* + The actual length for these types does not really matter since + they are used to calc_pack_length, which ignores the given + length for these types. + + Since we want this to be accurate for other uses, we return the + maximum size in bytes of these BLOBs. + */ + + case MYSQL_TYPE_TINY_BLOB: + return uint_max(1 * 8); + + case MYSQL_TYPE_MEDIUM_BLOB: + return uint_max(3 * 8); + + case MYSQL_TYPE_BLOB: + /* + For the blob type, Field::real_type() lies and say that all + blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look + at the length instead to decide what the max display size is. + */ + return uint_max(metadata * 8); + + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_GEOMETRY: + return uint_max(4 * 8); + + default: + return ~(uint32) 0; + } +} + + +/* + Compare the pack lengths of a source field (on the master) and a + target field (on the slave). + + @param field Target field. + @param type Source field type. + @param metadata Source field metadata. + + @retval -1 The length of the source field is smaller than the target field. + @retval 0 The length of the source and target fields are the same. + @retval 1 The length of the source field is greater than the target field. + */ +int compare_lengths(Field *field, enum_field_types source_type, uint16 metadata) +{ + DBUG_ENTER("compare_lengths"); + size_t const source_length= + max_display_length_for_field(source_type, metadata); + size_t const target_length= field->max_display_length(); + DBUG_PRINT("debug", ("source_length: %lu, source_type: %u," + " target_length: %lu, target_type: %u", + (unsigned long) source_length, source_type, + (unsigned long) target_length, field->real_type())); + int result= compare(source_length, target_length); + DBUG_PRINT("result", ("%d", result)); + DBUG_RETURN(result); +} + /********************************************************************* * table_def member definitions * *********************************************************************/ @@ -169,58 +337,704 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const return length; } -/* + +/** + */ +void show_sql_type(enum_field_types type, uint16 metadata, String *str) +{ + DBUG_ENTER("show_sql_type"); + DBUG_PRINT("enter", ("type: %d, metadata: 0x%x", type, metadata)); + + switch (type) + { + case MYSQL_TYPE_TINY: + str->set_ascii(STRING_WITH_LEN("tinyint")); + break; + + case MYSQL_TYPE_SHORT: + str->set_ascii(STRING_WITH_LEN("smallint")); + break; + + case MYSQL_TYPE_LONG: + str->set_ascii(STRING_WITH_LEN("int")); + break; + + case MYSQL_TYPE_FLOAT: + str->set_ascii(STRING_WITH_LEN("float")); + break; + + case MYSQL_TYPE_DOUBLE: + str->set_ascii(STRING_WITH_LEN("double")); + break; + + case MYSQL_TYPE_NULL: + str->set_ascii(STRING_WITH_LEN("null")); + break; + + case MYSQL_TYPE_TIMESTAMP: + str->set_ascii(STRING_WITH_LEN("timestamp")); + break; + + case MYSQL_TYPE_LONGLONG: + str->set_ascii(STRING_WITH_LEN("bigint")); + break; + + case MYSQL_TYPE_INT24: + str->set_ascii(STRING_WITH_LEN("mediumint")); + break; + + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATE: + str->set_ascii(STRING_WITH_LEN("date")); + break; + + case MYSQL_TYPE_TIME: + str->set_ascii(STRING_WITH_LEN("time")); + break; + + case MYSQL_TYPE_DATETIME: + str->set_ascii(STRING_WITH_LEN("datetime")); + break; + + case MYSQL_TYPE_YEAR: + str->set_ascii(STRING_WITH_LEN("year")); + break; + + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_VARCHAR: + { + CHARSET_INFO *cs= str->charset(); + uint32 length= + cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), + "varchar(%u)", metadata); + str->length(length); + } + break; + + case MYSQL_TYPE_BIT: + { + CHARSET_INFO *cs= str->charset(); + int bit_length= 8 * (metadata >> 8) + (metadata & 0xFF); + uint32 length= + cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), + "bit(%d)", bit_length); + str->length(length); + } + break; + + case MYSQL_TYPE_DECIMAL: + { + CHARSET_INFO *cs= str->charset(); + uint32 length= + cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), + "decimal(%d,?)", metadata); + str->length(length); + } + break; + + case MYSQL_TYPE_NEWDECIMAL: + { + CHARSET_INFO *cs= str->charset(); + uint32 length= + cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), + "decimal(%d,%d)", metadata >> 8, metadata & 0xff); + str->length(length); + } + break; + + case MYSQL_TYPE_ENUM: + str->set_ascii(STRING_WITH_LEN("enum")); + break; + + case MYSQL_TYPE_SET: + str->set_ascii(STRING_WITH_LEN("set")); + break; + + case MYSQL_TYPE_BLOB: + /* + Field::real_type() lies regarding the actual type of a BLOB, so + it is necessary to check the pack length to figure out what kind + of blob it really is. + */ + switch (get_blob_type_from_length(metadata)) + { + case MYSQL_TYPE_TINY_BLOB: + str->set_ascii(STRING_WITH_LEN("tinyblob")); + break; + + case MYSQL_TYPE_MEDIUM_BLOB: + str->set_ascii(STRING_WITH_LEN("mediumblob")); + break; + + case MYSQL_TYPE_LONG_BLOB: + str->set_ascii(STRING_WITH_LEN("longblob")); + break; + + case MYSQL_TYPE_BLOB: + str->set_ascii(STRING_WITH_LEN("blob")); + break; + + default: + DBUG_ASSERT(0); + break; + } + break; + + case MYSQL_TYPE_STRING: + { + /* + This is taken from Field_string::unpack. + */ + CHARSET_INFO *cs= str->charset(); + uint bytes= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff); + uint32 length= + cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), + "char(%d)", bytes / cs->mbmaxlen); + str->length(length); + } + break; + + case MYSQL_TYPE_GEOMETRY: + str->set_ascii(STRING_WITH_LEN("geometry")); + break; + + default: + str->set_ascii(STRING_WITH_LEN("<unknown type>")); + } + DBUG_VOID_RETURN; +} + + +/** + Check the order variable and print errors if the order is not + acceptable according to the current settings. + + @param order The computed order of the conversion needed. + @param rli The relay log info data structure: for error reporting. + */ +bool is_conversion_ok(int order, Relay_log_info *rli) +{ + DBUG_ENTER("is_conversion_ok"); + bool allow_non_lossy= + bit_is_set(slave_type_conversions_options, SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY); + bool allow_lossy= + bit_is_set(slave_type_conversions_options, SLAVE_TYPE_CONVERSIONS_ALL_LOSSY); + + DBUG_PRINT("enter", ("order: %d, flags:%s%s", order, + allow_non_lossy ? " ALL_NON_LOSSY" : "", + allow_lossy ? " ALL_LOSSY" : "")); + if (order < 0 && !allow_non_lossy) + { + /* !!! Add error message saying that non-lossy conversions need to be allowed. */ + DBUG_RETURN(false); + } + + if (order > 0 && !allow_lossy) + { + /* !!! Add error message saying that lossy conversions need to be allowed. */ + DBUG_RETURN(false); + } + + DBUG_RETURN(true); +} + + +/** + Can a type potentially be converted to another type? + + This function check if the types are convertible and what + conversion is required. + + If conversion is not possible, and error is printed. + + If conversion is possible: + + - *order will be set to -1 if source type is smaller than target + type and a non-lossy conversion can be required. This includes + the case where the field types are different but types could + actually be converted in either direction. + + - *order will be set to 0 if no conversion is required. + + - *order will be set to 1 if the source type is strictly larger + than the target type and that conversion is potentially lossy. + + @param[in] field Target field + @param[in] type Source field type + @param[in] metadata Source field metadata + @param[in] rli Relay log info (for error reporting) + @param[in] mflags Flags from the table map event + @param[out] order Order between source field and target field + + @return @c true if conversion is possible according to the current + settings, @c false if conversion is not possible according to the + current setting. + */ +static bool +can_convert_field_to(Field *field, + enum_field_types source_type, uint16 metadata, + Relay_log_info *rli, uint16 mflags, + int *order_var) +{ + DBUG_ENTER("can_convert_field_to"); +#ifndef DBUG_OFF + char field_type_buf[MAX_FIELD_WIDTH]; + String field_type(field_type_buf, sizeof(field_type_buf), field->charset()); + field->sql_type(field_type); + DBUG_PRINT("enter", ("field_type: %s, target_type: %d, source_type: %d, source_metadata: 0x%x", + field_type.c_ptr(), field->real_type(), source_type, metadata)); +#endif + /* + If the real type is the same, we need to check the metadata to + decide if conversions are allowed. + */ + if (field->real_type() == source_type) + { + DBUG_PRINT("debug", ("Base types are identical, doing field size comparison")); + if (field->compatible_field_size(metadata, rli, mflags, order_var)) + DBUG_RETURN(is_conversion_ok(*order_var, rli)); + else + DBUG_RETURN(false); + } + else if (!slave_type_conversions_options) + DBUG_RETURN(false); + + /* + Here, from and to will always be different. Since the types are + different, we cannot use the compatible_field_size() function, but + have to rely on hard-coded max-sizes for fields. + */ + + DBUG_PRINT("debug", ("Base types are different, checking conversion")); + switch (source_type) // Source type (on master) + { + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + switch (field->real_type()) + { + case MYSQL_TYPE_NEWDECIMAL: + /* + Then the other type is either FLOAT, DOUBLE, or old style + DECIMAL, so we require lossy conversion. + */ + *order_var= 1; + DBUG_RETURN(is_conversion_ok(*order_var, rli)); + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + { + if (source_type == MYSQL_TYPE_NEWDECIMAL || + source_type == MYSQL_TYPE_DECIMAL) + *order_var = 1; // Always require lossy conversions + else + *order_var= compare_lengths(field, source_type, metadata); + DBUG_ASSERT(*order_var != 0); + DBUG_RETURN(is_conversion_ok(*order_var, rli)); + } + + default: + DBUG_RETURN(false); + } + break; + + /* + The length comparison check will do the correct job of comparing + the field lengths (in bytes) of two integer types. + */ + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + switch (field->real_type()) + { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + *order_var= compare_lengths(field, source_type, metadata); + DBUG_ASSERT(*order_var != 0); + DBUG_RETURN(is_conversion_ok(*order_var, rli)); + + default: + DBUG_RETURN(false); + } + break; + + /* + Since source and target type is different, and it is not possible + to convert bit types to anything else, this will return false. + */ + case MYSQL_TYPE_BIT: + DBUG_RETURN(false); + + /* + If all conversions are disabled, it is not allowed to convert + between these types. Since the TEXT vs. BINARY is distinguished by + the charset, and the charset is not replicated, we cannot + currently distinguish between , e.g., TEXT and BLOB. + */ + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_VARCHAR: + switch (field->real_type()) + { + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_VARCHAR: + *order_var= compare_lengths(field, source_type, metadata); + /* + Here we know that the types are different, so if the order + gives that they do not require any conversion, we still need + to have non-lossy conversion enabled to allow conversion + between different (string) types of the same length. + */ + if (*order_var == 0) + *order_var= -1; + DBUG_RETURN(is_conversion_ok(*order_var, rli)); + + default: + DBUG_RETURN(false); + } + break; + + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + DBUG_RETURN(false); + } + DBUG_RETURN(false); // To keep GCC happy +} + + +/** Is the definition compatible with a table? + This function will compare the master table with an existing table + on the slave and see if they are compatible with respect to the + current settings of @c SLAVE_TYPE_CONVERSIONS. + + If the tables are compatible and conversions are required, @c + *tmp_table_var will be set to a virtual temporary table with field + pointers for the fields that require conversions. This allow simple + checking of whether a conversion are to be applied or not. + + If tables are compatible, but no conversions are necessary, @c + *tmp_table_var will be set to NULL. + + @param rli_arg[in] + Relay log info, for error reporting. + + @param table[in] + Table to compare with + + @param tmp_table_var[out] + Virtual temporary table for performing conversions, if necessary. + + @retval true Master table is compatible with slave table. + @retval false Master table is not compatible with slave table. */ -int -table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table) +bool +table_def::compatible_with(THD *thd, Relay_log_info *rli, + TABLE *table, TABLE **conv_table_var) const { /* We only check the initial columns for the tables. */ uint const cols_to_check= min(table->s->fields, size()); - int error= 0; - Relay_log_info const *rli= const_cast<Relay_log_info*>(rli_arg); - - TABLE_SHARE const *const tsh= table->s; + TABLE *tmp_table= NULL; for (uint col= 0 ; col < cols_to_check ; ++col) { Field *const field= table->field[col]; - if (field->type() != type(col)) + int order; + if (can_convert_field_to(field, type(col), field_metadata(col), rli, m_flags, &order)) { - DBUG_ASSERT(col < size() && col < tsh->fields); - DBUG_ASSERT(tsh->db.str && tsh->table_name.str); - error= 1; - char buf[256]; - my_snprintf(buf, sizeof(buf), "Column %d type mismatch - " - "received type %d, %s.%s has type %d", - col, type(col), tsh->db.str, tsh->table_name.str, - field->type()); - rli->report(ERROR_LEVEL, ER_BINLOG_ROW_WRONG_TABLE_DEF, - ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf); + DBUG_PRINT("debug", ("Checking column %d -" + " field '%s' can be converted - order: %d", + col, field->field_name, order)); + DBUG_ASSERT(order >= -1 && order <= 1); + + /* + If order is not 0, a conversion is required, so we need to set + up the conversion table. + */ + if (order != 0 && tmp_table == NULL) + { + /* + This will create the full table with all fields. This is + necessary to ge the correct field lengths for the record. + */ + tmp_table= create_conversion_table(thd, rli, table); + if (tmp_table == NULL) + return false; + /* + Clear all fields up to, but not including, this column. + */ + for (unsigned int i= 0; i < col; ++i) + tmp_table->field[i]= NULL; + } + + if (order == 0 && tmp_table != NULL) + tmp_table->field[col]= NULL; } - /* - Check the slave's field size against that of the master. - */ - if (!error && - !field->compatible_field_size(field_metadata(col), rli_arg)) + else { - error= 1; - char buf[256]; - my_snprintf(buf, sizeof(buf), "Column %d size mismatch - " - "master has size %d, %s.%s on slave has size %d." - " Master's column size should be <= the slave's " - "column size.", col, - field->pack_length_from_metadata(m_field_metadata[col]), - tsh->db.str, tsh->table_name.str, - field->row_pack_length()); - rli->report(ERROR_LEVEL, ER_BINLOG_ROW_WRONG_TABLE_DEF, - ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf); + DBUG_PRINT("debug", ("Checking column %d -" + " field '%s' can not be converted", + col, field->field_name)); + DBUG_ASSERT(col < size() && col < table->s->fields); + DBUG_ASSERT(table->s->db.str && table->s->table_name.str); + const char *db_name= table->s->db.str; + const char *tbl_name= table->s->table_name.str; + char source_buf[MAX_FIELD_WIDTH]; + char target_buf[MAX_FIELD_WIDTH]; + String source_type(source_buf, sizeof(source_buf), field->charset()); + String target_type(target_buf, sizeof(target_buf), field->charset()); + show_sql_type(type(col), field_metadata(col), &source_type); + field->sql_type(target_type); + rli->report(ERROR_LEVEL, ER_SLAVE_CONVERSION_FAILED, + ER(ER_SLAVE_CONVERSION_FAILED), + col, db_name, tbl_name, + source_type.c_ptr(), target_type.c_ptr()); + return false; } } - return error; +#ifndef DBUG_OFF + if (tmp_table) + { + for (unsigned int col= 0; col < tmp_table->s->fields; ++col) + if (tmp_table->field[col]) + { + char source_buf[MAX_FIELD_WIDTH]; + char target_buf[MAX_FIELD_WIDTH]; + String source_type(source_buf, sizeof(source_buf), table->field[col]->charset()); + String target_type(target_buf, sizeof(target_buf), table->field[col]->charset()); + tmp_table->field[col]->sql_type(source_type); + table->field[col]->sql_type(target_type); + DBUG_PRINT("debug", ("Field %s - conversion required." + " Source type: '%s', Target type: '%s'", + tmp_table->field[col]->field_name, + source_type.c_ptr(), target_type.c_ptr())); + } + } +#endif + + *conv_table_var= tmp_table; + return true; } + +/** + Create a conversion table. + + If the function is unable to create the conversion table, an error + will be printed and NULL will be returned. + + @return Pointer to conversion table, or NULL if unable to create + conversion table. + */ + +TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *target_table) const +{ + DBUG_ENTER("table_def::create_conversion_table"); + + List<Create_field> field_list; + + for (uint col= 0 ; col < size() ; ++col) + { + Create_field *field_def= + (Create_field*) alloc_root(thd->mem_root, sizeof(Create_field)); + if (field_list.push_back(field_def)) + DBUG_RETURN(NULL); + + uint decimals= 0; + TYPELIB* interval= NULL; + uint pack_length= 0; + uint32 max_length= + max_display_length_for_field(type(col), field_metadata(col)); + + switch(type(col)) + { + int precision; + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + interval= static_cast<Field_enum*>(target_table->field[col])->typelib; + pack_length= field_metadata(col) & 0x00ff; + break; + + case MYSQL_TYPE_NEWDECIMAL: + /* + The display length of a DECIMAL type is not the same as the + length that should be supplied to make_field, so we correct + the length here. + */ + precision= field_metadata(col) >> 8; + decimals= field_metadata(col) & 0x00ff; + max_length= + my_decimal_precision_to_length(precision, decimals, FALSE); + break; + + case MYSQL_TYPE_DECIMAL: + precision= field_metadata(col); + decimals= static_cast<Field_num*>(target_table->field[col])->dec; + max_length= field_metadata(col); + break; + + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_GEOMETRY: + pack_length= field_metadata(col) & 0x00ff; + break; + + default: + break; + } + + DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d," + " maybe_null: %d, unsigned_flag: %d, pack_length: %u", + type(col), target_table->field[col]->field_name, + max_length, decimals, TRUE, FALSE, pack_length)); + field_def->init_for_tmp_table(type(col), + max_length, + decimals, + maybe_null(col), // maybe_null + FALSE, // unsigned_flag + pack_length); + field_def->charset= target_table->field[col]->charset(); + field_def->interval= interval; + } + + TABLE *conv_table= create_virtual_tmp_table(thd, field_list); + if (conv_table == NULL) + rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION, + ER(ER_SLAVE_CANT_CREATE_CONVERSION), + target_table->s->db.str, + target_table->s->table_name.str); + DBUG_RETURN(conv_table); +} + +#endif /* MYSQL_CLIENT */ + +table_def::table_def(unsigned char *types, ulong size, + uchar *field_metadata, int metadata_size, + uchar *null_bitmap, uint16 flags) + : m_size(size), m_type(0), m_field_metadata_size(metadata_size), + m_field_metadata(0), m_null_bits(0), m_flags(flags), + m_memory(NULL) +{ + m_memory= (uchar *)my_multi_malloc(MYF(MY_WME), + &m_type, size, + &m_field_metadata, + size * sizeof(uint16), + &m_null_bits, (size + 7) / 8, + NULL); + + bzero(m_field_metadata, size * sizeof(uint16)); + + if (m_type) + memcpy(m_type, types, size); + else + m_size= 0; + /* + Extract the data from the table map into the field metadata array + iff there is field metadata. The variable metadata_size will be + 0 if we are replicating from an older version server since no field + metadata was written to the table map. This can also happen if + there were no fields in the master that needed extra metadata. + */ + if (m_size && metadata_size) + { + int index= 0; + for (unsigned int i= 0; i < m_size; i++) + { + switch (m_type[i]) { + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_FLOAT: + { + /* + These types store a single byte. + */ + m_field_metadata[i]= field_metadata[index]; + index++; + break; + } + case MYSQL_TYPE_SET: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_STRING: + { + uint16 x= field_metadata[index++] << 8U; // real_type + x+= field_metadata[index++]; // pack or field length + m_field_metadata[i]= x; + break; + } + case MYSQL_TYPE_BIT: + { + uint16 x= field_metadata[index++]; + x = x + (field_metadata[index++] << 8U); + m_field_metadata[i]= x; + break; + } + case MYSQL_TYPE_VARCHAR: + { + /* + These types store two bytes. + */ + char *ptr= (char *)&field_metadata[index]; + m_field_metadata[i]= uint2korr(ptr); + index= index + 2; + break; + } + case MYSQL_TYPE_NEWDECIMAL: + { + uint16 x= field_metadata[index++] << 8U; // precision + x+= field_metadata[index++]; // decimals + m_field_metadata[i]= x; + break; + } + default: + m_field_metadata[i]= 0; + break; + } + } + } + if (m_size && null_bitmap) + memcpy(m_null_bits, null_bitmap, (m_size + 7) / 8); +} + + +table_def::~table_def() +{ + my_free(m_memory, MYF(0)); +#ifndef DBUG_OFF + m_type= 0; + m_size= 0; +#endif +} + diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 1f4ca246ff1..4b9bf3be93f 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -21,6 +21,7 @@ #endif #include "mysql_priv.h" +#include "mysql_com.h" class Relay_log_info; @@ -32,127 +33,24 @@ class Relay_log_info; - Extract and decode table definition data from the table map event - Check if table definition in table map is compatible with table definition on slave - - Currently, the only field type data available is an array of the - type operators that are present in the table map event. - - @todo Add type operands to this structure to allow detection of - difference between, e.g., BIT(5) and BIT(10). */ class table_def { public: /** - Convenience declaration of the type of the field type data in a - table map event. - */ - typedef unsigned char field_type; - - /** Constructor. - @param types Array of types + @param types Array of types, each stored as a byte @param size Number of elements in array 'types' @param field_metadata Array of extra information about fields @param metadata_size Size of the field_metadata array @param null_bitmap The bitmap of fields that can be null */ - table_def(field_type *types, ulong size, uchar *field_metadata, - int metadata_size, uchar *null_bitmap) - : m_size(size), m_type(0), m_field_metadata_size(metadata_size), - m_field_metadata(0), m_null_bits(0), m_memory(NULL) - { - m_memory= (uchar *)my_multi_malloc(MYF(MY_WME), - &m_type, size, - &m_field_metadata, - size * sizeof(uint16), - &m_null_bits, (size + 7) / 8, - NULL); - - bzero(m_field_metadata, size * sizeof(uint16)); - - if (m_type) - memcpy(m_type, types, size); - else - m_size= 0; - /* - Extract the data from the table map into the field metadata array - iff there is field metadata. The variable metadata_size will be - 0 if we are replicating from an older version server since no field - metadata was written to the table map. This can also happen if - there were no fields in the master that needed extra metadata. - */ - if (m_size && metadata_size) - { - int index= 0; - for (unsigned int i= 0; i < m_size; i++) - { - switch (m_type[i]) { - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_DOUBLE: - case MYSQL_TYPE_FLOAT: - { - /* - These types store a single byte. - */ - m_field_metadata[i]= field_metadata[index]; - index++; - break; - } - case MYSQL_TYPE_SET: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_STRING: - { - uint16 x= field_metadata[index++] << 8U; // real_type - x+= field_metadata[index++]; // pack or field length - m_field_metadata[i]= x; - break; - } - case MYSQL_TYPE_BIT: - { - uint16 x= field_metadata[index++]; - x = x + (field_metadata[index++] << 8U); - m_field_metadata[i]= x; - break; - } - case MYSQL_TYPE_VARCHAR: - { - /* - These types store two bytes. - */ - char *ptr= (char *)&field_metadata[index]; - m_field_metadata[i]= uint2korr(ptr); - index= index + 2; - break; - } - case MYSQL_TYPE_NEWDECIMAL: - { - uint16 x= field_metadata[index++] << 8U; // precision - x+= field_metadata[index++]; // decimals - m_field_metadata[i]= x; - break; - } - default: - m_field_metadata[i]= 0; - break; - } - } - } - if (m_size && null_bitmap) - memcpy(m_null_bits, null_bitmap, (m_size + 7) / 8); - } + table_def(unsigned char *types, ulong size, uchar *field_metadata, + int metadata_size, uchar *null_bitmap, uint16 flags); - ~table_def() { - my_free(m_memory, MYF(0)); -#ifndef DBUG_OFF - m_type= 0; - m_size= 0; -#endif - } + ~table_def(); /** Return the number of fields there is type data for. @@ -171,10 +69,40 @@ public: <code>index</code>. Currently, only the type identifier is returned. */ - field_type type(ulong index) const + enum_field_types type(ulong index) const { DBUG_ASSERT(index < m_size); - return m_type[index]; + /* + If the source type is MYSQL_TYPE_STRING, it can in reality be + either MYSQL_TYPE_STRING, MYSQL_TYPE_ENUM, or MYSQL_TYPE_SET, so + we might need to modify the type to get the real type. + */ + enum_field_types source_type= static_cast<enum_field_types>(m_type[index]); + uint16 source_metadata= m_field_metadata[index]; + switch (source_type) + { + case MYSQL_TYPE_STRING: + { + int real_type= source_metadata >> 8; + if (real_type == MYSQL_TYPE_ENUM || real_type == MYSQL_TYPE_SET) + source_type= static_cast<enum_field_types>(real_type); + break; + } + + /* + This type has not been used since before row-based replication, + so we can safely assume that it really is MYSQL_TYPE_NEWDATE. + */ + case MYSQL_TYPE_DATE: + source_type= MYSQL_TYPE_NEWDATE; + break; + + default: + /* Do nothing */ + break; + } + + return source_type; } @@ -226,26 +154,62 @@ public: with it. A table definition is compatible with a table if: - - the columns types of the table definition is a (not - necessarily proper) prefix of the column type of the table, or - - the other way around + - The columns types of the table definition is a (not + necessarily proper) prefix of the column type of the table. + + - The other way around. + - Each column on the master that also exists on the slave can be + converted according to the current settings of @c + SLAVE_TYPE_CONVERSIONS. + + @param thd @param rli Pointer to relay log info @param table Pointer to table to compare with. + @param[out] tmp_table_var Pointer to temporary table for holding + conversion table. + @retval 1 if the table definition is not compatible with @c table @retval 0 if the table definition is compatible with @c table */ #ifndef MYSQL_CLIENT - int compatible_with(Relay_log_info const *rli, TABLE *table) const; + bool compatible_with(THD *thd, Relay_log_info *rli, TABLE *table, + TABLE **conv_table_var) const; + + /** + Create a virtual in-memory temporary table structure. + + The table structure has records and field array so that a row can + be unpacked into the record for further processing. + + In the virtual table, each field that requires conversion will + have a non-NULL value, while fields that do not require + conversion will have a NULL value. + + Some information that is missing in the events, such as the + character set for string types, are taken from the table that the + field is going to be pushed into, so the target table that the data + eventually need to be pushed into need to be supplied. + + @param thd Thread to allocate memory from. + @param rli Relay log info structure, for error reporting. + @param target_table Target table for fields. + + @return A pointer to a temporary table with memory allocated in the + thread's memroot, NULL if the table could not be created + */ + TABLE *create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *target_table) const; #endif + private: ulong m_size; // Number of elements in the types array - field_type *m_type; // Array of type descriptors + unsigned char *m_type; // Array of type descriptors uint m_field_metadata_size; uint16 *m_field_metadata; uchar *m_null_bits; + uint16 m_flags; // Table flags uchar *m_memory; }; @@ -260,6 +224,7 @@ struct RPL_TABLE_LIST { bool m_tabledef_valid; table_def m_tabledef; + TABLE *m_conv_table; }; diff --git a/sql/set_var.cc b/sql/set_var.cc index 579dcbb2a8d..54c305fa236 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -92,6 +92,33 @@ TYPELIB delay_key_write_typelib= delay_key_write_type_names, NULL }; +/** + SLAVE_TYPE_CONVERSIONS variable. + + Definition is equivalent to + @code + SET('ALL_NON_LOSSY', 'ALL_LOSSY') + @endcode + */ +const char *slave_type_conversions_type_name[]= { + "ALL_LOSSY", + "ALL_NON_LOSSY", + NullS +}; + +unsigned int slave_type_conversions_type_length[]= { + sizeof("ALL_LOSSY")-1, + sizeof("ALL_NON_LOSSY")-1, + 0 +}; + +TYPELIB slave_type_conversions_typelib= +{ + array_elements(slave_type_conversions_type_name)-1, "", + slave_type_conversions_type_name, + slave_type_conversions_type_length +}; + const char *slave_exec_mode_names[]= { "STRICT", "IDEMPOTENT", NullS }; static const unsigned int slave_exec_mode_names_len[]= @@ -577,6 +604,12 @@ static sys_var_set_slave_mode slave_exec_mode(&vars, &slave_exec_mode_options, &slave_exec_mode_typelib, 0); +static sys_var_set slave_type_conversions(&vars, + "slave_type_conversions", + &slave_type_conversions_options, + &slave_type_conversions_typelib, + 0); + static sys_var_long_ptr sys_slow_launch_time(&vars, "slow_launch_time", &slow_launch_time); static sys_var_thd_ulong sys_sort_buffer(&vars, "sort_buffer_size", @@ -1256,7 +1289,6 @@ bool sys_var_thd_binlog_format::check(THD *thd, set_var *var) { return result; } - bool sys_var_thd_binlog_format::is_readonly() const { /* diff --git a/sql/set_var.h b/sql/set_var.h index 9257a6e3081..1bc97916876 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -35,6 +35,7 @@ typedef struct my_locale_st MY_LOCALE; extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib, optimizer_switch_typelib, slave_exec_mode_typelib; +extern TYPELIB slave_type_conversions_typelib; typedef int (*sys_check_func)(THD *, set_var *); typedef bool (*sys_update_func)(THD *, set_var *); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 91cb8c261df..c3d9235bc30 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6216,3 +6216,8 @@ ER_DEBUG_SYNC_TIMEOUT ER_DEBUG_SYNC_HIT_LIMIT eng "debug sync point hit limit reached" ger "Debug Sync Point Hit Limit erreicht" + +ER_SLAVE_CONVERSION_FAILED + eng "Column %d of table '%-.192s.%-.192s' cannot be converted from type '%-.32s' to type '%-.32s'" +ER_SLAVE_CANT_CREATE_CONVERSION + eng "Can't create conversion table for table '%-.192s.%-.192s'" diff --git a/sql/sp.cc b/sql/sp.cc index fd420732628..d3c5dfb96d0 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -70,6 +70,122 @@ enum MYSQL_PROC_FIELD_COUNT }; +static const +TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] = +{ + { + { C_STRING_WITH_LEN("db") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("name") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("type") }, + { C_STRING_WITH_LEN("enum('FUNCTION','PROCEDURE')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("specific_name") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("language") }, + { C_STRING_WITH_LEN("enum('SQL')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("sql_data_access") }, + { C_STRING_WITH_LEN("enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("is_deterministic") }, + { C_STRING_WITH_LEN("enum('YES','NO')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("security_type") }, + { C_STRING_WITH_LEN("enum('INVOKER','DEFINER')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("param_list") }, + { C_STRING_WITH_LEN("blob") }, + { NULL, 0 } + }, + + { + { C_STRING_WITH_LEN("returns") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("body") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("definer") }, + { C_STRING_WITH_LEN("char(77)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("created") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("modified") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("sql_mode") }, + { C_STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES'," + "'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION'," + "'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB'," + "'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40'," + "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES'," + "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES'," + "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER'," + "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("comment") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("character_set_client") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("collation_connection") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("db_collation") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("body_utf8") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + } +}; + +static const TABLE_FIELD_DEF + proc_table_def= {MYSQL_PROC_FIELD_COUNT, proc_table_fields}; + /*************************************************************************/ /** @@ -247,6 +363,50 @@ Stored_routine_creation_ctx::load_from_db(THD *thd, /*************************************************************************/ +class Proc_table_intact : public Table_check_intact +{ +private: + bool m_print_once; + +public: + Proc_table_intact() : m_print_once(TRUE) {} + +protected: + void report_error(uint code, const char *fmt, ...); +}; + + +/** + Report failure to validate the mysql.proc table definition. + Print a message to the error log only once. +*/ + +void Proc_table_intact::report_error(uint code, const char *fmt, ...) +{ + va_list args; + char buf[512]; + + va_start(args, fmt); + my_vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (code) + my_message(code, buf, MYF(0)); + else + my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "proc"); + + if (m_print_once) + { + m_print_once= FALSE; + sql_print_error("%s", buf); + } +}; + + +/** Single instance used to control printing to the error log. */ +static Proc_table_intact proc_table_intact; + + /** Open the mysql.proc table for read. @@ -266,15 +426,17 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) DBUG_ENTER("open_proc_table_for_read"); TABLE_LIST table; - bzero((char*) &table, sizeof(table)); - table.db= (char*) "mysql"; - table.table_name= table.alias= (char*)"proc"; - table.lock_type= TL_READ; + table.init_one_table("mysql", "proc", TL_READ); - if (!open_system_tables_for_read(thd, &table, backup)) + if (open_system_tables_for_read(thd, &table, backup)) + DBUG_RETURN(NULL); + + if (!proc_table_intact.check(table.table, &proc_table_def)) DBUG_RETURN(table.table); - else - DBUG_RETURN(0); + + close_system_tables(thd, backup); + + DBUG_RETURN(NULL); } @@ -296,13 +458,19 @@ static TABLE *open_proc_table_for_update(THD *thd) { DBUG_ENTER("open_proc_table_for_update"); - TABLE_LIST table; - bzero((char*) &table, sizeof(table)); - table.db= (char*) "mysql"; - table.table_name= table.alias= (char*)"proc"; - table.lock_type= TL_WRITE; + TABLE *table; + TABLE_LIST table_list; + table_list.init_one_table("mysql", "proc", TL_WRITE); + + if (!(table= open_system_table_for_update(thd, &table_list))) + DBUG_RETURN(NULL); - DBUG_RETURN(open_system_table_for_update(thd, &table)); + if (!proc_table_intact.check(table, &proc_table_def)) + DBUG_RETURN(table); + + close_thread_tables(thd); + + DBUG_RETURN(NULL); } @@ -1506,7 +1674,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, rn->key.length= key->length; rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry); memcpy(rn->key.str, key->str, key->length + 1); - my_hash_insert(&lex->sroutines, (uchar *)rn); + if (my_hash_insert(&lex->sroutines, (uchar *)rn)) + return FALSE; lex->sroutines_list.link_in_list((uchar *)rn, (uchar **)&rn->next); rn->belong_to_view= belong_to_view; return TRUE; @@ -1584,16 +1753,24 @@ void sp_remove_not_own_routines(LEX *lex) dependant on time of life of elements from source hash. It also won't touch lists linking elements in source and destination hashes. + + @returns + @return TRUE Failure + @return FALSE Success */ -void sp_update_sp_used_routines(HASH *dst, HASH *src) +bool sp_update_sp_used_routines(HASH *dst, HASH *src) { for (uint i=0 ; i < src->records ; i++) { Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i); if (!hash_search(dst, (uchar *)rt->key.str, rt->key.length)) - my_hash_insert(dst, (uchar *)rt); + { + if (my_hash_insert(dst, (uchar *)rt)) + return TRUE; + } } + return FALSE; } @@ -69,7 +69,7 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking, void sp_add_used_routine(LEX *lex, Query_arena *arena, sp_name *rt, char rt_type); void sp_remove_not_own_routines(LEX *lex); -void sp_update_sp_used_routines(HASH *dst, HASH *src); +bool sp_update_sp_used_routines(HASH *dst, HASH *src); int sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock); int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 64898915b7e..b8209a373a2 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -36,10 +36,16 @@ public: sp_cache(); ~sp_cache(); - inline void insert(sp_head *sp) + /** + Inserts a sp_head object into a hash table. + + @returns Success status + @return TRUE Failure + @return FALSE Success + */ + inline bool insert(sp_head *sp) { - /* TODO: why don't we check return value? */ - my_hash_insert(&m_hashtable, (const uchar *)sp); + return my_hash_insert(&m_hashtable, (const uchar *)sp); } inline sp_head *lookup(char *name, uint namelen) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 6a0ab4bfc46..4320f037ac6 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2088,8 +2088,18 @@ sp_head::reset_lex(THD *thd) DBUG_RETURN(FALSE); } -/// Restore lex during parsing, after we have parsed a sub statement. -void + +/** + Restore lex during parsing, after we have parsed a sub statement. + + @param thd Thread handle + + @return + @retval TRUE failure + @retval FALSE success +*/ + +bool sp_head::restore_lex(THD *thd) { DBUG_ENTER("sp_head::restore_lex"); @@ -2100,7 +2110,7 @@ sp_head::restore_lex(THD *thd) oldlex= (LEX *)m_lex.pop(); if (! oldlex) - return; // Nothing to restore + DBUG_RETURN(FALSE); // Nothing to restore oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); @@ -2116,7 +2126,8 @@ sp_head::restore_lex(THD *thd) Add routines which are used by statement to respective set for this routine. */ - sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines); + if (sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines)) + DBUG_RETURN(TRUE); /* Merge tables used by this statement (but not by its functions or procedures) to multiset of tables used by this routine. @@ -2128,7 +2139,7 @@ sp_head::restore_lex(THD *thd) delete sublex; } thd->lex= oldlex; - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } /** @@ -3866,7 +3877,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) tab->lock_type= table->lock_type; tab->lock_count= tab->query_lock_count= 1; tab->trg_event_map= table->trg_event_map; - my_hash_insert(&m_sptabs, (uchar *)tab); + if (my_hash_insert(&m_sptabs, (uchar *)tab)) + return FALSE; } } return TRUE; diff --git a/sql/sp_head.h b/sql/sp_head.h index dd11f8693ac..00c96d44f70 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -340,7 +340,7 @@ public: @todo Conflicting comment in sp_head.cc */ - void + bool restore_lex(THD *thd); /// Put the instruction on the backpatch list, associated with the label. diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 9b237b3e7cc..be8f705a53e 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -617,7 +617,7 @@ sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr } m_case_expr_holders[case_expr_id]->store(case_expr_item); - + m_case_expr_holders[case_expr_id]->cache_value(); return FALSE; } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0592bb3be1d..77c72066429 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -31,9 +31,8 @@ #include "sp_head.h" #include "sp.h" -time_t mysql_db_table_last_check= 0L; - -TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = { +static const +TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = { { { C_STRING_WITH_LEN("Host") }, { C_STRING_WITH_LEN("char(60)") }, @@ -146,6 +145,8 @@ TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = { } }; +const TABLE_FIELD_DEF + mysql_db_table_def= {MYSQL_DB_FIELD_COUNT, mysql_db_table_fields}; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -2404,7 +2405,12 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) privs = cols = 0; /* purecov: deadcode */ return; /* purecov: deadcode */ } - my_hash_insert(&hash_columns, (uchar *) mem_check); + if (my_hash_insert(&hash_columns, (uchar *) mem_check)) + { + /* Invalidate this entry */ + privs= cols= 0; + return; + } } while (!col_privs->file->index_next(col_privs->record[0]) && !key_cmp_if_same(col_privs,key,0,key_prefix_len)); col_privs->file->ha_index_end(); @@ -2438,14 +2444,17 @@ static GRANT_NAME *name_hash_search(HASH *name_hash, const char *host,const char* ip, const char *db, const char *user, const char *tname, - bool exact) + bool exact, bool name_tolower) { - char helping [NAME_LEN*2+USERNAME_LENGTH+3]; + char helping [NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr; uint len; GRANT_NAME *grant_name,*found=0; HASH_SEARCH_STATE state; - len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1; + name_ptr= strmov(strmov(helping, user) + 1, db) + 1; + len = (uint) (strmov(name_ptr, tname) - helping) + 1; + if (name_tolower) + my_casedn_str(files_charset_info, name_ptr); for (grant_name= (GRANT_NAME*) hash_first(name_hash, (uchar*) helping, len, &state); grant_name ; @@ -2478,7 +2487,7 @@ routine_hash_search(const char *host, const char *ip, const char *db, { return (GRANT_TABLE*) name_hash_search(proc ? &proc_priv_hash : &func_priv_hash, - host, ip, db, user, tname, exact); + host, ip, db, user, tname, exact, TRUE); } @@ -2487,7 +2496,7 @@ table_hash_search(const char *host, const char *ip, const char *db, const char *user, const char *tname, bool exact) { return (GRANT_TABLE*) name_hash_search(&column_priv_hash, host, ip, db, - user, tname, exact); + user, tname, exact, FALSE); } @@ -2609,7 +2618,11 @@ static int replace_column_table(GRANT_TABLE *g_t, goto end; /* purecov: inspected */ } grant_column= new GRANT_COLUMN(column->column,privileges); - my_hash_insert(&g_t->hash_columns,(uchar*) grant_column); + if (my_hash_insert(&g_t->hash_columns,(uchar*) grant_column)) + { + result= -1; + goto end; + } } } @@ -3134,12 +3147,12 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, Str->user.str, table_name, rights, column_priv); - if (!grant_table) // end of memory + if (!grant_table || + my_hash_insert(&column_priv_hash,(uchar*) grant_table)) { result= TRUE; /* purecov: deadcode */ continue; /* purecov: deadcode */ } - my_hash_insert(&column_priv_hash,(uchar*) grant_table); } /* If revoke_grant, calculate the new column privilege for tables_priv */ @@ -3343,12 +3356,13 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, grant_name= new GRANT_NAME(Str->host.str, db_name, Str->user.str, table_name, rights, TRUE); - if (!grant_name) + if (!grant_name || + my_hash_insert(is_proc ? + &proc_priv_hash : &func_priv_hash,(uchar*) grant_name)) { result= TRUE; continue; } - my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) grant_name); } if (replace_routine_table(thd, grant_name, tables[1].table, *Str, @@ -3451,6 +3465,13 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, result= TRUE; continue; } + /* + No User, but a password? + They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... ! + Get the current user, and shallow-copy the new password to them! + */ + if (!tmp_Str->user.str && tmp_Str->password.str) + Str->password= tmp_Str->password; if (replace_user_table(thd, tables[0].table, *Str, (!db ? rights : 0), revoke_grant, create_new_users, test(thd->variables.sql_mode & diff --git a/sql/sql_acl.h b/sql/sql_acl.h index c0622bd747c..3104c2ff1a7 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -162,8 +162,7 @@ enum mysql_db_table_field MYSQL_DB_FIELD_COUNT }; -extern TABLE_FIELD_W_TYPE mysql_db_table_fields[]; -extern time_t mysql_db_table_last_check; +extern const TABLE_FIELD_DEF mysql_db_table_def; /* Classes */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 776fea20676..d1dc86b9f07 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2935,7 +2935,12 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, DBUG_PRINT("info", ("inserting table '%s'.'%s' 0x%lx into the cache", table->s->db.str, table->s->table_name.str, (long) table)); - VOID(my_hash_insert(&open_cache,(uchar*) table)); + if (my_hash_insert(&open_cache,(uchar*) table)) + { + my_free(table, MYF(0)); + VOID(pthread_mutex_unlock(&LOCK_open)); + DBUG_RETURN(NULL); + } } check_unused(); // Debugging call diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 861bd97928d..f862cbed4f1 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -421,12 +421,16 @@ TYPELIB query_cache_type_typelib= effect by another thread. This enables a quick path in execution to skip waits when the outcome is known. + @param use_timeout TRUE if the lock can abort because of a timeout. + + @note use_timeout is optional and default value is FALSE. + @return @retval FALSE An exclusive lock was taken @retval TRUE The locking attempt failed */ -bool Query_cache::try_lock(void) +bool Query_cache::try_lock(bool use_timeout) { bool interrupt= FALSE; DBUG_ENTER("Query_cache::try_lock"); @@ -456,7 +460,26 @@ bool Query_cache::try_lock(void) else { DBUG_ASSERT(m_cache_lock_status == Query_cache::LOCKED); - pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex); + /* + To prevent send_result_to_client() and query_cache_insert() from + blocking execution for too long a timeout is put on the lock. + */ + if (use_timeout) + { + struct timespec waittime; + set_timespec_nsec(waittime,(ulong)(50000000L)); /* Wait for 50 msec */ + int res= pthread_cond_timedwait(&COND_cache_status_changed, + &structure_guard_mutex,&waittime); + if (res == ETIMEDOUT) + { + interrupt= TRUE; + break; + } + } + else + { + pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex); + } } } pthread_mutex_unlock(&structure_guard_mutex); @@ -1190,8 +1213,14 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", A table- or a full flush operation can potentially take a long time to finish. We choose not to wait for them and skip caching statements instead. + + In case the wait time can't be determined there is an upper limit which + causes try_lock() to abort with a time out. + + The 'TRUE' parameter indicate that the lock is allowed to timeout + */ - if (try_lock()) + if (try_lock(TRUE)) DBUG_VOID_RETURN; if (query_cache_size == 0) { @@ -1385,8 +1414,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Try to obtain an exclusive lock on the query cache. If the cache is disabled or if a full cache flush is in progress, the attempt to get the lock is aborted. + + The 'TRUE' parameter indicate that the lock is allowed to timeout */ - if (try_lock()) + if (try_lock(TRUE)) goto err; if (query_cache_size == 0) diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 777ddd39280..44fc3123b98 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -485,7 +485,7 @@ protected: const char *name); my_bool in_blocks(Query_cache_block * point); - bool try_lock(void); + bool try_lock(bool use_timeout= FALSE); void lock(void); void lock_and_suspend(void); void unlock(void); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a041df23cc5..10cea24a8e7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -412,6 +412,8 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, str.append(proc_info); } + pthread_mutex_lock(&thd->LOCK_thd_data); + if (thd->query()) { if (max_query_len < 1) @@ -421,6 +423,9 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, str.append('\n'); str.append(thd->query(), len); } + + pthread_mutex_unlock(&thd->LOCK_thd_data); + if (str.c_ptr_safe() == buffer) return buffer; diff --git a/sql/sql_class.h b/sql/sql_class.h index 05f2cb50ff6..0ea1930c2d2 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -90,6 +90,12 @@ enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT, SLAVE_EXEC_MODE_IDEMPOTENT, SLAVE_EXEC_MODE_LAST_BIT}; +enum enum_slave_type_conversions { + SLAVE_TYPE_CONVERSIONS_ALL_LOSSY, + SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY, + SLAVE_TYPE_CONVERSIONS_COUNT +}; + enum enum_mark_columns { MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE}; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b80138af7f2..6b9a83e695b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -426,7 +426,8 @@ cleanup: } DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table); free_underlaid_joins(thd, select_lex); - if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error)) + if (error < 0 || + (thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error)) { /* If a TRUNCATE TABLE was issued, the number of rows should be reported as @@ -1089,6 +1090,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) TABLE *table; bool error; uint path_length; + bool is_temporary_table= false; DBUG_ENTER("mysql_truncate"); bzero((char*) &create_info,sizeof(create_info)); @@ -1099,6 +1101,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) /* If it is a temporary table, close and regenerate it */ if (!dont_send_ok && (table= find_temporary_table(thd, table_list))) { + is_temporary_table= true; handlerton *table_type= table->s->db_type(); TABLE_SHARE *share= table->s; if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE)) @@ -1162,11 +1165,9 @@ end: { if (!error) { - /* - TRUNCATE must always be statement-based binlogged (not row-based) so - we don't test current_stmt_binlog_row_based. - */ - write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + /* In RBR, the statement is not binlogged if the table is temporary. */ + if (!is_temporary_table || !thd->current_stmt_binlog_row_based) + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); my_ok(thd); // This should return record count } VOID(pthread_mutex_lock(&LOCK_open)); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 6e2b3903b52..e9a36629c66 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -500,6 +500,22 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) DBUG_ENTER("open_and_lock_for_insert_delayed"); #ifndef EMBEDDED_LIBRARY + if (thd->locked_tables && thd->global_read_lock) + { + /* + If this connection has the global read lock, the handler thread + will not be able to lock the table. It will wait for the global + read lock to go away, but this will never happen since the + connection thread will be stuck waiting for the handler thread + to open and lock the table. + If we are not in locked tables mode, INSERT will seek protection + against the global read lock (and fail), thus we will only get + to this point in locked tables mode. + */ + my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0)); + DBUG_RETURN(TRUE); + } + if (delayed_get_table(thd, table_list)) DBUG_RETURN(TRUE); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 8dda4a52466..8109ca4313e 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -304,8 +304,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else { (void) fn_format(name, ex->file_name, mysql_real_data_home, "", - MY_RELATIVE_PATH | MY_UNPACK_FILENAME); - + MY_RELATIVE_PATH | MY_UNPACK_FILENAME | + MY_RETURN_REAL_PATH); #if !defined(__WIN__) && ! defined(__NETWARE__) MY_STAT stat_info; if (!my_stat(name,&stat_info,MYF(MY_WME))) @@ -348,12 +348,16 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_ASSERT(FALSE); #endif } - else if (opt_secure_file_priv && - strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv))) + else if (opt_secure_file_priv) { - /* Read only allowed from within dir specified by secure_file_priv */ - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); - DBUG_RETURN(TRUE); + char secure_file_real_path[FN_REFLEN]; + (void) my_realpath(secure_file_real_path, opt_secure_file_priv, 0); + if (strncmp(secure_file_real_path, name, strlen(secure_file_real_path))) + { + /* Read only allowed from within dir specified by secure_file_priv */ + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); + DBUG_RETURN(TRUE); + } } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0a6c04b82ce..2210fd87070 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7427,6 +7427,9 @@ void get_default_definer(THD *thd, LEX_USER *definer) definer->host.str= (char *) sctx->priv_host; definer->host.length= strlen(definer->host.str); + + definer->password.str= NULL; + definer->password.length= 0; } @@ -7478,6 +7481,8 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) definer->user= *user_name; definer->host= *host_name; + definer->password.str= NULL; + definer->password.length= 0; return definer; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 5a622740638..251e695f79b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -200,26 +200,27 @@ bool partition_default_handling(TABLE *table, partition_info *part_info, { DBUG_ENTER("partition_default_handling"); - if (part_info->use_default_no_partitions) + if (!is_create_table_ind) { - if (!is_create_table_ind && - table->file->get_no_parts(normalized_path, &part_info->no_parts)) + if (part_info->use_default_no_partitions) { - DBUG_RETURN(TRUE); + if (table->file->get_no_parts(normalized_path, &part_info->no_parts)) + { + DBUG_RETURN(TRUE); + } } - } - else if (part_info->is_sub_partitioned() && - part_info->use_default_no_subpartitions) - { - uint no_parts; - if (!is_create_table_ind && - (table->file->get_no_parts(normalized_path, &no_parts))) + else if (part_info->is_sub_partitioned() && + part_info->use_default_no_subpartitions) { - DBUG_RETURN(TRUE); + uint no_parts; + if (table->file->get_no_parts(normalized_path, &no_parts)) + { + DBUG_RETURN(TRUE); + } + DBUG_ASSERT(part_info->no_parts > 0); + DBUG_ASSERT((no_parts % part_info->no_parts) == 0); + part_info->no_subparts= no_parts / part_info->no_parts; } - DBUG_ASSERT(part_info->no_parts > 0); - part_info->no_subparts= no_parts / part_info->no_parts; - DBUG_ASSERT((no_parts % part_info->no_parts) == 0); } part_info->set_up_defaults_for_partitioning(table->file, (ulonglong)0, (uint)0); @@ -909,6 +910,8 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, char* db_name; char db_name_string[FN_REFLEN]; bool save_use_only_table_context; + uint8 saved_full_group_by_flag; + nesting_map saved_allow_sum_func; DBUG_ENTER("fix_fields_part_func"); if (part_info->fixed) @@ -978,9 +981,19 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, save_use_only_table_context= thd->lex->use_only_table_context; thd->lex->use_only_table_context= TRUE; thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS; + saved_full_group_by_flag= thd->lex->current_select->full_group_by_flag; + saved_allow_sum_func= thd->lex->allow_sum_func; + thd->lex->allow_sum_func= 0; error= func_expr->fix_fields(thd, (Item**)&func_expr); + /* + Restore full_group_by_flag and allow_sum_func, + fix_fields should not affect mysql_select later, see Bug#46923. + */ + thd->lex->current_select->full_group_by_flag= saved_full_group_by_flag; + thd->lex->allow_sum_func= saved_allow_sum_func; + thd->lex->use_only_table_context= save_use_only_table_context; context->table_list= save_table_list; @@ -1683,7 +1696,7 @@ bool fix_partition_func(THD *thd, TABLE *table, if (((part_info->part_type != HASH_PARTITION || part_info->list_of_part_fields == FALSE) && check_part_func_fields(part_info->part_field_array, TRUE)) || - (part_info->list_of_part_fields == FALSE && + (part_info->list_of_subpart_fields == FALSE && part_info->is_sub_partitioned() && check_part_func_fields(part_info->subpart_field_array, TRUE))) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cdaebef49f6..0e3b3511283 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -982,14 +982,20 @@ JOIN::optimize() DBUG_RETURN(1); } - if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields()) + if (rollup.state != ROLLUP::STATE_NONE) { - DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); - DBUG_RETURN(1); + if (rollup_process_const_fields()) + { + DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); + DBUG_RETURN(1); + } + } + else + { + /* Remove distinct if only const tables */ + select_distinct= select_distinct && (const_tables != tables); } - /* Remove distinct if only const tables */ - select_distinct= select_distinct && (const_tables != tables); thd_proc_info(thd, "preparing"); if (result->initialize_tables(this)) { @@ -1288,11 +1294,14 @@ JOIN::optimize() - We are using an ORDER BY or GROUP BY on fields not in the first table - We are using different ORDER BY and GROUP BY orders - The user wants us to buffer the result. + When the WITH ROLLUP modifier is present, we cannot skip temporary table + creation for the DISTINCT clause just because there are only const tables. */ - need_tmp= (const_tables != tables && + need_tmp= ((const_tables != tables && ((select_distinct || !simple_order || !simple_group) || (group_list && order) || - test(select_options & OPTION_BUFFER_RESULT))); + test(select_options & OPTION_BUFFER_RESULT))) || + (rollup.state != ROLLUP::STATE_NONE && select_distinct)); // No cache for MATCH make_join_readinfo(this, @@ -2122,17 +2131,13 @@ JOIN::exec() DBUG_VOID_RETURN; if (!curr_table->select->cond) curr_table->select->cond= sort_table_cond; - else // This should never happen + else { if (!(curr_table->select->cond= new Item_cond_and(curr_table->select->cond, sort_table_cond))) DBUG_VOID_RETURN; - /* - Item_cond_and do not need fix_fields for execution, its parameters - are fixed or do not need fix_fields, too - */ - curr_table->select->cond->quick_fix_field(); + curr_table->select->cond->fix_fields(thd, 0); } curr_table->select_cond= curr_table->select->cond; curr_table->select_cond->top_level_item(); @@ -6478,6 +6483,56 @@ void rr_unlock_row(st_join_table *tab) +/** + Pick the appropriate access method functions + + Sets the functions for the selected table access method + + @param tab Table reference to put access method +*/ + +static void +pick_table_access_method(JOIN_TAB *tab) +{ + switch (tab->type) + { + case JT_REF: + tab->read_first_record= join_read_always_key; + tab->read_record.read_record= join_read_next_same; + break; + + case JT_REF_OR_NULL: + tab->read_first_record= join_read_always_key_or_null; + tab->read_record.read_record= join_read_next_same_or_null; + break; + + case JT_CONST: + tab->read_first_record= join_read_const; + tab->read_record.read_record= join_no_more_records; + break; + + case JT_EQ_REF: + tab->read_first_record= join_read_key; + tab->read_record.read_record= join_no_more_records; + break; + + case JT_FT: + tab->read_first_record= join_ft_read_first; + tab->read_record.read_record= join_ft_read_next; + break; + + case JT_SYSTEM: + tab->read_first_record= join_read_system; + tab->read_record.read_record= join_no_more_records; + break; + + /* keep gcc happy */ + default: + break; + } +} + + static void make_join_readinfo(JOIN *join, ulonglong options) { @@ -6512,45 +6567,15 @@ make_join_readinfo(JOIN *join, ulonglong options) tab->sorted= sorted; sorted= 0; // only first must be sorted + table->status=STATUS_NO_RECORD; + pick_table_access_method (tab); + switch (tab->type) { - case JT_SYSTEM: // Only happens with left join - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_read_system; - tab->read_record.read_record= join_no_more_records; - break; - case JT_CONST: // Only happens with left join - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_read_const; - tab->read_record.read_record= join_no_more_records; - if (table->covering_keys.is_set(tab->ref.key) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } - break; case JT_EQ_REF: - table->status=STATUS_NO_RECORD; - if (tab->select) - { - delete tab->select->quick; - tab->select->quick=0; - } - delete tab->quick; - tab->quick=0; - tab->read_first_record= join_read_key; tab->read_record.unlock_row= join_read_key_unlock_row; - tab->read_record.read_record= join_no_more_records; - if (table->covering_keys.is_set(tab->ref.key) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } - break; + /* fall through */ case JT_REF_OR_NULL: case JT_REF: - table->status=STATUS_NO_RECORD; if (tab->select) { delete tab->select->quick; @@ -6558,34 +6583,20 @@ make_join_readinfo(JOIN *join, ulonglong options) } delete tab->quick; tab->quick=0; + /* fall through */ + case JT_CONST: // Only happens with left join if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) { table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); } - if (tab->type == JT_REF) - { - tab->read_first_record= join_read_always_key; - tab->read_record.read_record= join_read_next_same; - } - else - { - tab->read_first_record= join_read_always_key_or_null; - tab->read_record.read_record= join_read_next_same_or_null; - } - break; - case JT_FT: - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_ft_read_first; - tab->read_record.read_record= join_ft_read_next; break; case JT_ALL: /* If previous table use cache If the incoming data set is already sorted don't use cache. */ - table->status=STATUS_NO_RECORD; if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) && tab->use_quick != 2 && !tab->first_inner && !ordered_set) { @@ -6665,6 +6676,9 @@ make_join_readinfo(JOIN *join, ulonglong options) } } break; + case JT_FT: + case JT_SYSTEM: + break; default: DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */ break; /* purecov: deadcode */ @@ -7816,12 +7830,12 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, { item_equal->fix_length_and_dec(); item_equal->update_used_tables(); + set_if_bigger(thd->lex->current_select->max_equal_elems, + item_equal->members()); + return item_equal; } - else - item_equal= (Item_equal *) eq_list.pop(); - set_if_bigger(thd->lex->current_select->max_equal_elems, - item_equal->members()); - return item_equal; + + return eq_list.pop(); } else { @@ -9452,47 +9466,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: - { - uint8 dec= item->decimals; - uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; - uint32 len= item->max_length; - - /* - Trying to put too many digits overall in a DECIMAL(prec,dec) - will always throw a warning. We must limit dec to - DECIMAL_MAX_SCALE however to prevent an assert() later. - */ - - if (dec > 0) - { - signed int overflow; - - dec= min(dec, DECIMAL_MAX_SCALE); - - /* - If the value still overflows the field with the corrected dec, - we'll throw out decimals rather than integers. This is still - bad and of course throws a truncation warning. - +1: for decimal point - */ - - const int required_length= - my_decimal_precision_to_length(intg + dec, dec, - item->unsigned_flag); - - overflow= required_length - len; - - if (overflow > 0) - dec= max(0, dec - overflow); // too long, discard fract - else - /* Corrected value fits. */ - len= required_length; - } - - new_field= new Field_new_decimal(len, maybe_null, item->name, - dec, item->unsigned_flag); + new_field= Field_new_decimal::create_from_item(item); break; - } case ROW_RESULT: default: // This case should never be choosen @@ -10543,6 +10518,18 @@ TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list) null_bit= 1; } } + if (cur_field->type() == MYSQL_TYPE_BIT && + cur_field->key_type() == HA_KEYTYPE_BIT) + { + /* This is a Field_bit since key_type is HA_KEYTYPE_BIT */ + static_cast<Field_bit*>(cur_field)->set_bit_ptr(null_pos, null_bit); + null_bit+= cur_field->field_length & 7; + if (null_bit > 7) + { + null_pos++; + null_bit-= 8; + } + } cur_field->reset(); field_pos+= cur_field->pack_length(); @@ -13186,6 +13173,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, if (create_ref_for_key(tab->join, tab, keyuse, tab->join->const_table_map)) DBUG_RETURN(0); + + pick_table_access_method(tab); } else { @@ -13991,7 +13980,10 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, goto err; } else - (void) my_hash_insert(&hash, org_key_pos); + { + if (my_hash_insert(&hash, org_key_pos)) + goto err; + } key_pos+=extra_length; } my_free((char*) key_buffer,MYF(0)); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cb9ff6163a8..ca4f5c9f1bc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5329,12 +5329,20 @@ binlog: } VOID(pthread_mutex_unlock(&LOCK_open)); - IF_DBUG(int result=) - store_create_info(thd, table, &query, - create_info, FALSE /* show_database */); + /* + The condition avoids a crash as described in BUG#48506. Other + binlogging problems related to CREATE TABLE IF NOT EXISTS LIKE + when the existing object is a view will be solved by BUG 47442. + */ + if (!table->view) + { + IF_DBUG(int result=) + store_create_info(thd, table, &query, + create_info, FALSE /* show_database */); - DBUG_ASSERT(result == 0); // store_create_info() always return 0 - write_bin_log(thd, TRUE, query.ptr(), query.length()); + DBUG_ASSERT(result == 0); // store_create_info() always return 0 + write_bin_log(thd, TRUE, query.ptr(), query.length()); + } } else // Case 1 write_bin_log(thd, TRUE, thd->query(), thd->query_length()); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 577f0b5ef71..d0bf24bd02b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -389,6 +389,138 @@ void case_stmt_action_end_case(LEX *lex, bool simple) lex->sphead->do_cont_backpatch(); } + +static bool +find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp) +{ + tmp->var= find_sys_var(thd, tmp->base_name.str, tmp->base_name.length); + + if (tmp->var == NULL) + my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), tmp->base_name.str); + else + tmp->base_name= null_lex_str; + + return thd->is_error(); +} + + +/** + Helper action for a SET statement. + Used to push a system variable into the assignment list. + + @param thd the current thread + @param tmp the system variable with base name + @param var_type the scope of the variable + @param val the value being assigned to the variable + + @return TRUE if error, FALSE otherwise. +*/ + +static bool +set_system_variable(THD *thd, struct sys_var_with_base *tmp, + enum enum_var_type var_type, Item *val) +{ + set_var *var; + LEX *lex= thd->lex; + + /* No AUTOCOMMIT from a stored function or trigger. */ + if (lex->spcont && tmp->var == &sys_autocommit) + lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + + if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val))) + return TRUE; + + return lex->var_list.push_back(var); +} + + +/** + Helper action for a SET statement. + Used to push a SP local variable into the assignment list. + + @param thd the current thread + @param var_type the SP local variable + @param val the value being assigned to the variable + + @return TRUE if error, FALSE otherwise. +*/ + +static bool +set_local_variable(THD *thd, sp_variable_t *spv, Item *val) +{ + Item *it; + LEX *lex= thd->lex; + sp_instr_set *sp_set; + + if (val) + it= val; + else if (spv->dflt) + it= spv->dflt; + else + { + it= new (thd->mem_root) Item_null(); + if (it == NULL) + return TRUE; + } + + sp_set= new sp_instr_set(lex->sphead->instructions(), lex->spcont, + spv->offset, it, spv->type, lex, TRUE); + + return (sp_set == NULL || lex->sphead->add_instr(sp_set)); +} + + +/** + Helper action for a SET statement. + Used to SET a field of NEW row. + + @param thd the current thread + @param name the field name + @param val the value being assigned to the row + + @return TRUE if error, FALSE otherwise. +*/ + +static bool +set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val) +{ + LEX *lex= thd->lex; + Item_trigger_field *trg_fld; + sp_instr_set_trigger_field *sp_fld; + + /* QQ: Shouldn't this be field's default value ? */ + if (! val) + val= new Item_null(); + + DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE && + (lex->trg_chistics.event == TRG_EVENT_INSERT || + lex->trg_chistics.event == TRG_EVENT_UPDATE)); + + trg_fld= new (thd->mem_root) + Item_trigger_field(lex->current_context(), + Item_trigger_field::NEW_ROW, + name->str, UPDATE_ACL, FALSE); + + if (trg_fld == NULL) + return TRUE; + + sp_fld= new sp_instr_set_trigger_field(lex->sphead->instructions(), + lex->spcont, trg_fld, val, lex); + + if (sp_fld == NULL) + return TRUE; + + /* + Let us add this item to list of all Item_trigger_field + objects in trigger. + */ + lex->trg_table_fields.link_in_list((uchar *) trg_fld, + (uchar **) &trg_fld->next_trg_field); + + return lex->sphead->add_instr(sp_fld); +} + + /** Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>. See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383. @@ -2398,8 +2530,8 @@ sp_decl: } pctx->declare_var_boundary(0); - lex->sphead->restore_lex(YYTHD); - + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; $$.vars= $2; $$.conds= $$.hndlrs= $$.curs= 0; } @@ -2509,7 +2641,8 @@ sp_cursor_stmt: } lex->sp_lex_in_use= TRUE; $$= lex; - lex->sphead->restore_lex(YYTHD); + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; } ; @@ -2728,7 +2861,8 @@ sp_proc_stmt_statement: sp->add_instr(i)) MYSQL_YYABORT; } - sp->restore_lex(thd); + if (sp->restore_lex(thd)) + MYSQL_YYABORT; } ; @@ -2756,7 +2890,8 @@ sp_proc_stmt_return: MYSQL_YYABORT; sp->m_flags|= sp_head::HAS_RETURN; } - sp->restore_lex(YYTHD); + if (sp->restore_lex(YYTHD)) + MYSQL_YYABORT; } ; @@ -2996,7 +3131,8 @@ sp_if: sp->add_cont_backpatch(i) || sp->add_instr(i)) MYSQL_YYABORT; - sp->restore_lex(YYTHD); + if (sp->restore_lex(YYTHD)) + MYSQL_YYABORT; } sp_proc_stmts1 { @@ -3042,7 +3178,9 @@ simple_case_stmt: if (case_stmt_action_expr(lex, $3)) MYSQL_YYABORT; - lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + /* For expr $3 */ + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; } simple_when_clause_list else_clause_opt @@ -3092,7 +3230,9 @@ simple_when_clause: LEX *lex= Lex; if (case_stmt_action_when(lex, $3, true)) MYSQL_YYABORT; - lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + /* For expr $3 */ + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; } THEN_SYM sp_proc_stmts1 @@ -3113,7 +3253,9 @@ searched_when_clause: LEX *lex= Lex; if (case_stmt_action_when(lex, $3, false)) MYSQL_YYABORT; - lex->sphead->restore_lex(YYTHD); /* For expr $3 */ + /* For expr $3 */ + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; } THEN_SYM sp_proc_stmts1 @@ -3290,7 +3432,8 @@ sp_unlabeled_control: sp->new_cont_backpatch(i) || sp->add_instr(i)) MYSQL_YYABORT; - sp->restore_lex(YYTHD); + if (sp->restore_lex(YYTHD)) + MYSQL_YYABORT; } sp_proc_stmts1 END WHILE_SYM { @@ -3316,7 +3459,8 @@ sp_unlabeled_control: if (i == NULL || lex->sphead->add_instr(i)) MYSQL_YYABORT; - lex->sphead->restore_lex(YYTHD); + if (lex->sphead->restore_lex(YYTHD)) + MYSQL_YYABORT; /* We can shortcut the cont_backpatch here */ i->m_cont_dest= ip+1; } @@ -7562,6 +7706,14 @@ function_call_nonkeyword: } | SYSDATE optional_braces { + /* + Unlike other time-related functions, SYSDATE() is + replication-unsafe because it is not affected by the + TIMESTAMP variable. It is unsafe even if + sysdate_is_now=1, because the slave may have + sysdate_is_now=0. + */ + Lex->set_stmt_unsafe(); if (global_system_variables.sysdate_is_now == 0) $$= new (YYTHD->mem_root) Item_func_sysdate_local(); else @@ -11761,7 +11913,8 @@ option_type_value: if (sp->add_instr(i)) MYSQL_YYABORT; } - lex->sphead->restore_lex(thd); + if (lex->sphead->restore_lex(thd)) + MYSQL_YYABORT; } } ; @@ -11801,98 +11954,42 @@ sys_option_value: option_type internal_variable_name equal set_expr_or_default { THD *thd= YYTHD; - LEX *lex=Lex; + LEX *lex= Lex; + LEX_STRING *name= &$2.base_name; if ($2.var == trg_new_row_fake_var) { /* We are in trigger and assigning value to field of new row */ - Item *it; - Item_trigger_field *trg_fld; - sp_instr_set_trigger_field *sp_fld; - LINT_INIT(sp_fld); if ($1) { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } - if ($4) - it= $4; - else - { - /* QQ: Shouldn't this be field's default value ? */ - it= new Item_null(); - } - - DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE && - (lex->trg_chistics.event == TRG_EVENT_INSERT || - lex->trg_chistics.event == TRG_EVENT_UPDATE)); - - trg_fld= new (thd->mem_root) - Item_trigger_field(Lex->current_context(), - Item_trigger_field::NEW_ROW, - $2.base_name.str, - UPDATE_ACL, FALSE); - if (trg_fld == NULL) - MYSQL_YYABORT; - - sp_fld= new sp_instr_set_trigger_field(lex->sphead-> - instructions(), - lex->spcont, - trg_fld, - it, lex); - if (sp_fld == NULL) - MYSQL_YYABORT; - - /* - Let us add this item to list of all Item_trigger_field - objects in trigger. - */ - lex->trg_table_fields.link_in_list((uchar *)trg_fld, - (uchar **) &trg_fld-> - next_trg_field); - - if (lex->sphead->add_instr(sp_fld)) + if (set_trigger_new_row(YYTHD, name, $4)) MYSQL_YYABORT; } else if ($2.var) - { /* System variable */ + { if ($1) lex->option_type= $1; - set_var *var= new set_var(lex->option_type, $2.var, - &$2.base_name, $4); - if (var == NULL) + + /* It is a system variable. */ + if (set_system_variable(thd, &$2, lex->option_type, $4)) MYSQL_YYABORT; - lex->var_list.push_back(var); } else { - /* An SP local variable */ - sp_pcontext *ctx= lex->spcont; - sp_variable_t *spv; - sp_instr_set *sp_set; - Item *it; + sp_pcontext *spc= lex->spcont; + sp_variable_t *spv= spc->find_variable(name); + if ($1) { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } - spv= ctx->find_variable(&$2.base_name); - - if ($4) - it= $4; - else if (spv->dflt) - it= spv->dflt; - else - { - it= new (thd->mem_root) Item_null(); - if (it == NULL) - MYSQL_YYABORT; - } - sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, - spv->offset, it, spv->type, lex, TRUE); - if (sp_set == NULL || - lex->sphead->add_instr(sp_set)) + /* It is a local variable. */ + if (set_local_variable(thd, spv, $4)) MYSQL_YYABORT; } } @@ -11928,11 +12025,16 @@ option_value: } | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default { - LEX *lex=Lex; - set_var *var= new set_var($3, $4.var, &$4.base_name, $6); - if (var == NULL) + THD *thd= YYTHD; + struct sys_var_with_base tmp= $4; + /* Lookup if necessary: must be a system variable. */ + if (tmp.var == NULL) + { + if (find_sys_var_null_base(thd, &tmp)) + MYSQL_YYABORT; + } + if (set_system_variable(thd, &tmp, $3, $6)) MYSQL_YYABORT; - lex->var_list.push_back(var); } | charset old_or_new_charset_name_or_default { @@ -12025,31 +12127,26 @@ internal_variable_name: ident { THD *thd= YYTHD; - LEX *lex= thd->lex; - sp_pcontext *spc= lex->spcont; + sp_pcontext *spc= thd->lex->spcont; sp_variable_t *spv; - /* We have to lookup here since local vars can shadow sysvars */ + /* Best effort lookup for system variable. */ if (!spc || !(spv = spc->find_variable(&$1))) { + struct sys_var_with_base tmp= {NULL, $1}; + /* Not an SP local variable */ - sys_var *tmp=find_sys_var(thd, $1.str, $1.length); - if (!tmp) + if (find_sys_var_null_base(thd, &tmp)) MYSQL_YYABORT; - $$.var= tmp; - $$.base_name= null_lex_str; - if (spc && tmp == &sys_autocommit) - { - /* - We don't allow setting AUTOCOMMIT from a stored function - or trigger. - */ - lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; - } + + $$= tmp; } else { - /* An SP local variable */ + /* + Possibly an SP local variable (or a shadowed sysvar). + Will depend on the context of the SET statement. + */ $$.var= NULL; $$.base_name= $1; } diff --git a/sql/table.cc b/sql/table.cc index d2538eb4d59..752b6ba0bd4 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1315,8 +1315,16 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, share->timestamp_field_offset= i; if (use_hash) - (void) my_hash_insert(&share->name_hash, - (uchar*) field_ptr); // never fail + if (my_hash_insert(&share->name_hash, (uchar*) field_ptr) ) + { + /* + Set return code 8 here to indicate that an error has + occurred but that the error message already has been + sent (OOM). + */ + error= 8; + goto err; + } } *field_ptr=0; // End marker @@ -2803,34 +2811,38 @@ bool check_column_name(const char *name) and such errors never reach the user. */ -my_bool -table_check_intact(TABLE *table, const uint table_f_count, - const TABLE_FIELD_W_TYPE *table_def) +bool +Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) { uint i; my_bool error= FALSE; - my_bool fields_diff_count; + const TABLE_FIELD_TYPE *field_def= table_def->field; DBUG_ENTER("table_check_intact"); DBUG_PRINT("info",("table: %s expected_count: %d", - table->alias, table_f_count)); + table->alias, table_def->count)); + + /* Whether the table definition has already been validated. */ + if (table->s->table_field_def_cache == table_def) + DBUG_RETURN(FALSE); - fields_diff_count= (table->s->fields != table_f_count); - if (fields_diff_count) + if (table->s->fields != table_def->count) { DBUG_PRINT("info", ("Column count has changed, checking the definition")); /* previous MySQL version */ if (MYSQL_VERSION_ID > table->s->mysql_version) { - sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE), - table->alias, table_f_count, table->s->fields, - table->s->mysql_version, MYSQL_VERSION_ID); + report_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE, + ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE), + table->alias, table_def->count, table->s->fields, + table->s->mysql_version, MYSQL_VERSION_ID); DBUG_RETURN(TRUE); } else if (MYSQL_VERSION_ID == table->s->mysql_version) { - sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias, - table_f_count, table->s->fields); + report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED, + ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias, + table_def->count, table->s->fields); DBUG_RETURN(TRUE); } /* @@ -2842,7 +2854,7 @@ table_check_intact(TABLE *table, const uint table_f_count, */ } char buffer[STRING_BUFFER_USUAL_SIZE]; - for (i=0 ; i < table_f_count; i++, table_def++) + for (i=0 ; i < table_def->count; i++, field_def++) { String sql_type(buffer, sizeof(buffer), system_charset_info); sql_type.length(0); @@ -2850,18 +2862,18 @@ table_check_intact(TABLE *table, const uint table_f_count, { Field *field= table->field[i]; - if (strncmp(field->field_name, table_def->name.str, - table_def->name.length)) + if (strncmp(field->field_name, field_def->name.str, + field_def->name.length)) { /* Name changes are not fatal, we use ordinal numbers to access columns. Still this can be a sign of a tampered table, output an error to the error log. */ - sql_print_error("Incorrect definition of table %s.%s: " - "expected column '%s' at position %d, found '%s'.", - table->s->db.str, table->alias, table_def->name.str, i, - field->field_name); + report_error(0, "Incorrect definition of table %s.%s: " + "expected column '%s' at position %d, found '%s'.", + table->s->db.str, table->alias, field_def->name.str, i, + field->field_name); } field->sql_type(sql_type); /* @@ -2881,47 +2893,51 @@ table_check_intact(TABLE *table, const uint table_f_count, the new table definition is backward compatible with the original one. */ - if (strncmp(sql_type.c_ptr_safe(), table_def->type.str, - table_def->type.length - 1)) + if (strncmp(sql_type.c_ptr_safe(), field_def->type.str, + field_def->type.length - 1)) { - sql_print_error("Incorrect definition of table %s.%s: " - "expected column '%s' at position %d to have type " - "%s, found type %s.", table->s->db.str, table->alias, - table_def->name.str, i, table_def->type.str, - sql_type.c_ptr_safe()); + report_error(0, "Incorrect definition of table %s.%s: " + "expected column '%s' at position %d to have type " + "%s, found type %s.", table->s->db.str, table->alias, + field_def->name.str, i, field_def->type.str, + sql_type.c_ptr_safe()); error= TRUE; } - else if (table_def->cset.str && !field->has_charset()) + else if (field_def->cset.str && !field->has_charset()) { - sql_print_error("Incorrect definition of table %s.%s: " - "expected the type of column '%s' at position %d " - "to have character set '%s' but the type has no " - "character set.", table->s->db.str, table->alias, - table_def->name.str, i, table_def->cset.str); + report_error(0, "Incorrect definition of table %s.%s: " + "expected the type of column '%s' at position %d " + "to have character set '%s' but the type has no " + "character set.", table->s->db.str, table->alias, + field_def->name.str, i, field_def->cset.str); error= TRUE; } - else if (table_def->cset.str && - strcmp(field->charset()->csname, table_def->cset.str)) + else if (field_def->cset.str && + strcmp(field->charset()->csname, field_def->cset.str)) { - sql_print_error("Incorrect definition of table %s.%s: " - "expected the type of column '%s' at position %d " - "to have character set '%s' but found " - "character set '%s'.", table->s->db.str, table->alias, - table_def->name.str, i, table_def->cset.str, - field->charset()->csname); + report_error(0, "Incorrect definition of table %s.%s: " + "expected the type of column '%s' at position %d " + "to have character set '%s' but found " + "character set '%s'.", table->s->db.str, table->alias, + field_def->name.str, i, field_def->cset.str, + field->charset()->csname); error= TRUE; } } else { - sql_print_error("Incorrect definition of table %s.%s: " - "expected column '%s' at position %d to have type %s " - " but the column is not found.", - table->s->db.str, table->alias, - table_def->name.str, i, table_def->type.str); + report_error(0, "Incorrect definition of table %s.%s: " + "expected column '%s' at position %d to have type %s " + " but the column is not found.", + table->s->db.str, table->alias, + field_def->name.str, i, field_def->type.str); error= TRUE; } } + + if (! error) + table->s->table_field_def_cache= table_def; + DBUG_RETURN(error); } diff --git a/sql/table.h b/sql/table.h index f9da0637b4b..cc4257c826d 100644 --- a/sql/table.h +++ b/sql/table.h @@ -288,6 +288,36 @@ typedef enum enum_table_category TABLE_CATEGORY; TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name); + +typedef struct st_table_field_type +{ + LEX_STRING name; + LEX_STRING type; + LEX_STRING cset; +} TABLE_FIELD_TYPE; + + +typedef struct st_table_field_def +{ + uint count; + const TABLE_FIELD_TYPE *field; +} TABLE_FIELD_DEF; + + +class Table_check_intact +{ +protected: + virtual void report_error(uint code, const char *fmt, ...)= 0; + +public: + Table_check_intact() {} + virtual ~Table_check_intact() {} + + /** Checks whether a table is intact. */ + bool check(TABLE *table, const TABLE_FIELD_DEF *table_def); +}; + + /* This structure is shared between different table objects. There is one instance of table share per one table in the database. @@ -424,6 +454,18 @@ typedef struct st_table_share handlerton *default_part_db_type; #endif + /** + Cache the checked structure of this table. + + The pointer data is used to describe the structure that + a instance of the table must have. Each element of the + array specifies a field that must exist on the table. + + The pointer is cached in order to perform the check only + once -- when the table is loaded from the disk. + */ + const TABLE_FIELD_DEF *table_field_def_cache; + /** place to store storage engine specific data */ void *ha_data; @@ -1665,17 +1707,6 @@ typedef struct st_open_table_list{ uint32 in_use,locked; } OPEN_TABLE_LIST; -typedef struct st_table_field_w_type -{ - LEX_STRING name; - LEX_STRING type; - LEX_STRING cset; -} TABLE_FIELD_W_TYPE; - - -my_bool -table_check_intact(TABLE *table, const uint table_f_count, - const TABLE_FIELD_W_TYPE *table_def); static inline my_bitmap_map *tmp_use_all_columns(TABLE *table, MY_BITMAP *bitmap) diff --git a/storage/archive/CMakeLists.txt b/storage/archive/CMakeLists.txt index ce4d92d3f99..f4492c3ce77 100644..100755 --- a/storage/archive/CMakeLists.txt +++ b/storage/archive/CMakeLists.txt @@ -13,6 +13,9 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") +SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") + INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") SET(ARCHIVE_SOURCES azio.c ha_archive.cc ha_archive.h) MYSQL_STORAGE_ENGINE(ARCHIVE) diff --git a/storage/archive/azio.c b/storage/archive/azio.c index 916dd8ba59d..c1dd6e6f38c 100644 --- a/storage/archive/azio.c +++ b/storage/archive/azio.c @@ -69,7 +69,8 @@ int az_open (azio_stream *s, const char *path, int Flags, File fd) s->transparent = 0; s->mode = 'r'; s->version = (unsigned char)az_magic[1]; /* this needs to be a define to version */ - s->version = (unsigned char)az_magic[2]; /* minor version */ + s->minor_version= (unsigned char) az_magic[2]; /* minor version */ + s->dirty= AZ_STATE_CLEAN; /* We do our own version of append by nature. @@ -352,10 +353,19 @@ void read_header(azio_stream *s, unsigned char *buffer) s->comment_length= (unsigned int)uint4korr(buffer + AZ_COMMENT_LENGTH_POS); s->dirty= (unsigned int)buffer[AZ_DIRTY_POS]; } - else + else if (buffer[0] == gz_magic[0] && buffer[1] == gz_magic[1]) { - DBUG_ASSERT(buffer[0] == az_magic[0] && buffer[1] == az_magic[1]); - return; + /* + Set version number to previous version (2). + */ + s->version= (unsigned char) 2; + } else { + /* + Unknown version. + Most probably due to a corrupt archive. + */ + s->dirty= AZ_STATE_DIRTY; + s->z_err= Z_VERSION_ERROR; } } diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 6fa8333c1b7..4648ca798da 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -360,6 +360,12 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, int *rc) stats.auto_increment_value= archive_tmp.auto_increment + 1; share->rows_recorded= (ha_rows)archive_tmp.rows; share->crashed= archive_tmp.dirty; + /* + If archive version is less than 3, It should be upgraded before + use. + */ + if (archive_tmp.version < ARCHIVE_VERSION) + *rc= HA_ERR_TABLE_NEEDS_UPGRADE; azclose(&archive_tmp); VOID(my_hash_insert(&archive_open_tables, (uchar*) share)); @@ -491,7 +497,15 @@ int ha_archive::open(const char *name, int mode, uint open_options) (open_options & HA_OPEN_FOR_REPAIR) ? "yes" : "no")); share= get_share(name, &rc); - if (rc == HA_ERR_CRASHED_ON_USAGE && !(open_options & HA_OPEN_FOR_REPAIR)) + /* + Allow open on crashed table in repair mode only. + Block open on 5.0 ARCHIVE table. Though we have almost all + routines to access these tables, they were not well tested. + For now we have to refuse to open such table to avoid + potential data loss. + */ + if ((rc == HA_ERR_CRASHED_ON_USAGE && !(open_options & HA_OPEN_FOR_REPAIR)) + || rc == HA_ERR_TABLE_NEEDS_UPGRADE) { /* purecov: begin inspected */ free_share(); diff --git a/storage/federated/CMakeLists.txt b/storage/federated/CMakeLists.txt index fa54d36481a..d371c0fc02b 100644..100755 --- a/storage/federated/CMakeLists.txt +++ b/storage/federated/CMakeLists.txt @@ -1,18 +1,21 @@ # Copyright (C) 2006 MySQL AB -# +# # 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; version 2 of the License. -# +# # 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") +SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") + INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") SET(FEDERATED_SOURCES ha_federated.cc) MYSQL_STORAGE_ENGINE(FEDERATED) diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 6e8b43aeb8d..5e8831b5d5e 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -709,8 +709,15 @@ btr_create( } else { /* It is a non-ibuf tree: create a file segment for leaf pages */ - fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF, - mtr); + if (!fseg_create(space, page_no, + PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) { + /* Not enough space for new segment, free root + segment before return. */ + btr_free_root(space, page_no, mtr); + + return(FIL_NULL); + } + /* The fseg create acquires a second latch on the page, therefore we must declare it: */ #ifdef UNIV_SYNC_DEBUG diff --git a/storage/innobase/data/data0type.c b/storage/innobase/data/data0type.c index 305000d7c0a..a3cfe691404 100644 --- a/storage/innobase/data/data0type.c +++ b/storage/innobase/data/data0type.c @@ -252,6 +252,22 @@ dtype_print( fputs("DATA_SYS", stderr); break; + case DATA_FLOAT: + fputs("DATA_FLOAT", stderr); + break; + + case DATA_DOUBLE: + fputs("DATA_DOUBLE", stderr); + break; + + case DATA_DECIMAL: + fputs("DATA_DECIMAL", stderr); + break; + + case DATA_VARMYSQL: + fputs("DATA_VARMYSQL", stderr); + break; + default: fprintf(stderr, "type %lu", (ulong) mtype); break; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 41d76c5ec55..30b4fc13012 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -662,6 +662,12 @@ convert_error_code_to_mysql( } else if (error == (int) DB_DUPLICATE_KEY) { + /* Be cautious with returning this error, since + mysql could re-enter the storage layer to get + duplicated key info, the operation requires a + valid table handle and/or transaction information, + which might not always be available in the error + handling stage. */ return(HA_ERR_FOUND_DUPP_KEY); } else if (error == (int) DB_FOREIGN_DUPLICATE_KEY) { @@ -765,35 +771,6 @@ convert_error_code_to_mysql( } /***************************************************************** -If you want to print a thd that is not associated with the current thread, -you must call this function before reserving the InnoDB kernel_mutex, to -protect MySQL from setting thd->query NULL. If you print a thd of the current -thread, we know that MySQL cannot modify thd->query, and it is not necessary -to call this. Call innobase_mysql_end_print_arbitrary_thd() after you release -the kernel_mutex. -NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this -function! */ -extern "C" -void -innobase_mysql_prepare_print_arbitrary_thd(void) -/*============================================*/ -{ - VOID(pthread_mutex_lock(&LOCK_thread_count)); -} - -/***************************************************************** -Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd(). -NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this -function! */ -extern "C" -void -innobase_mysql_end_print_arbitrary_thd(void) -/*========================================*/ -{ - VOID(pthread_mutex_unlock(&LOCK_thread_count)); -} - -/***************************************************************** Prints info of a THD object (== user session thread) to the given file. NOTE that /mysql/innobase/trx/trx0trx.c must contain the prototype for this function! */ @@ -1499,70 +1476,148 @@ innobase_invalidate_query_cache( #endif } -/********************************************************************* -Display an SQL identifier. */ -extern "C" -void -innobase_print_identifier( -/*======================*/ - FILE* f, /* in: output stream */ - trx_t* trx, /* in: transaction */ - ibool table_id,/* in: TRUE=print a table name, - FALSE=print other identifier */ - const char* name, /* in: name to print */ - ulint namelen)/* in: length of name */ -{ - const char* s = name; - char* qname = NULL; +/*****************************************************************//** +Convert an SQL identifier to the MySQL system_charset_info (UTF-8) +and quote it if needed. +@return pointer to the end of buf */ +static +char* +innobase_convert_identifier( +/*========================*/ + char* buf, /*!< out: buffer for converted identifier */ + ulint buflen, /*!< in: length of buf, in bytes */ + const char* id, /*!< in: identifier to convert */ + ulint idlen, /*!< in: length of id, in bytes */ + void* thd, /*!< in: MySQL connection thread, or NULL */ + ibool file_id)/*!< in: TRUE=id is a table or database name; + FALSE=id is an UTF-8 string */ +{ + char nz[NAME_LEN + 1]; +#if MYSQL_VERSION_ID >= 50141 + char nz2[NAME_LEN + 1 + EXPLAIN_FILENAME_MAX_EXTRA_LENGTH]; +#else /* MYSQL_VERSION_ID >= 50141 */ + char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix]; +#endif /* MYSQL_VERSION_ID >= 50141 */ + + const char* s = id; int q; - if (table_id) { - /* Decode the table name. The filename_to_tablename() - function expects a NUL-terminated string. The input and - output strings buffers must not be shared. The function - only produces more output when the name contains other - characters than [0-9A-Z_a-z]. */ - char* temp_name = (char*) my_malloc((uint) namelen + 1, MYF(MY_WME)); - uint qnamelen = (uint) (namelen - + (1 + sizeof srv_mysql50_table_name_prefix)); - - if (temp_name) { - qname = (char*) my_malloc(qnamelen, MYF(MY_WME)); - if (qname) { - memcpy(temp_name, name, namelen); - temp_name[namelen] = 0; - s = qname; - namelen = filename_to_tablename(temp_name, - qname, qnamelen); - } - my_free(temp_name, MYF(0)); + if (file_id) { + /* Decode the table name. The MySQL function expects + a NUL-terminated string. The input and output strings + buffers must not be shared. */ + + if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) { + idlen = (sizeof nz) - 1; } - } - if (!trx || !trx->mysql_thd) { + memcpy(nz, id, idlen); + nz[idlen] = 0; + + s = nz2; +#if MYSQL_VERSION_ID >= 50141 + idlen = explain_filename((THD*) thd, nz, nz2, sizeof nz2, + EXPLAIN_PARTITIONS_AS_COMMENT); + goto no_quote; +#else /* MYSQL_VERSION_ID >= 50141 */ + idlen = filename_to_tablename(nz, nz2, sizeof nz2); +#endif /* MYSQL_VERSION_ID >= 50141 */ + } + /* See if the identifier needs to be quoted. */ + if (UNIV_UNLIKELY(!thd)) { q = '"'; } else { - q = get_quote_char_for_identifier((THD*) trx->mysql_thd, - s, (int) namelen); + q = get_quote_char_for_identifier((THD*) thd, s, (int) idlen); } if (q == EOF) { - fwrite(s, 1, namelen, f); - } else { - const char* e = s + namelen; - putc(q, f); - while (s < e) { - int c = *s++; - if (c == q) { - putc(c, f); +#if MYSQL_VERSION_ID >= 50141 +no_quote: +#endif /* MYSQL_VERSION_ID >= 50141 */ + if (UNIV_UNLIKELY(idlen > buflen)) { + idlen = buflen; + } + memcpy(buf, s, idlen); + return(buf + idlen); + } + + /* Quote the identifier. */ + if (buflen < 2) { + return(buf); + } + + *buf++ = q; + buflen--; + + for (; idlen; idlen--) { + int c = *s++; + if (UNIV_UNLIKELY(c == q)) { + if (UNIV_UNLIKELY(buflen < 3)) { + break; } - putc(c, f); + + *buf++ = c; + *buf++ = c; + buflen -= 2; + } else { + if (UNIV_UNLIKELY(buflen < 2)) { + break; + } + + *buf++ = c; + buflen--; } - putc(q, f); } - my_free(qname, MYF(MY_ALLOW_ZERO_PTR)); + *buf++ = q; + return(buf); +} + +/*****************************************************************//** +Convert a table or index name to the MySQL system_charset_info (UTF-8) +and quote it if needed. +@return pointer to the end of buf */ +extern "C" +char* +innobase_convert_name( +/*==================*/ + char* buf, /*!< out: buffer for converted identifier */ + ulint buflen, /*!< in: length of buf, in bytes */ + const char* id, /*!< in: identifier to convert */ + ulint idlen, /*!< in: length of id, in bytes */ + void* thd, /*!< in: MySQL connection thread, or NULL */ + ibool table_id)/*!< in: TRUE=id is a table or database name; + FALSE=id is an index name */ +{ + char* s = buf; + const char* bufend = buf + buflen; + + if (table_id) { + const char* slash = (const char*) memchr(id, '/', idlen); + if (!slash) { + + goto no_db_name; + } + + /* Print the database name and table name separately. */ + s = innobase_convert_identifier(s, bufend - s, id, slash - id, + thd, TRUE); + if (UNIV_LIKELY(s < bufend)) { + *s++ = '.'; + s = innobase_convert_identifier(s, bufend - s, + slash + 1, idlen + - (slash - id) - 1, + thd, TRUE); + } + } else { +no_db_name: + s = innobase_convert_identifier(buf, buflen, id, idlen, + thd, table_id); + } + + return(s); + } /************************************************************************** @@ -3976,24 +4031,29 @@ no_commit: update the table upper limit. Note: last_value will be 0 if get_auto_increment() was not called.*/ - if (auto_inc <= col_max_value - && auto_inc >= prebuilt->autoinc_last_value) { + if (auto_inc >= prebuilt->autoinc_last_value) { set_max_autoinc: - ut_a(prebuilt->autoinc_increment > 0); + /* This should filter out the negative + values set explicitly by the user. */ + if (auto_inc <= col_max_value) { + ut_a(prebuilt->autoinc_increment > 0); - ulonglong need; - ulonglong offset; + ulonglong need; + ulonglong offset; - offset = prebuilt->autoinc_offset; - need = prebuilt->autoinc_increment; + offset = prebuilt->autoinc_offset; + need = prebuilt->autoinc_increment; - auto_inc = innobase_next_autoinc( - auto_inc, need, offset, col_max_value); + auto_inc = innobase_next_autoinc( + auto_inc, + need, offset, col_max_value); - err = innobase_set_max_autoinc(auto_inc); + err = innobase_set_max_autoinc( + auto_inc); - if (err != DB_SUCCESS) { - error = err; + if (err != DB_SUCCESS) { + error = err; + } } } break; @@ -5960,6 +6020,24 @@ ha_innobase::rename_table( innobase_commit_low(trx); trx_free_for_mysql(trx); + /* Add a special case to handle the Duplicated Key error + and return DB_ERROR instead. + This is to avoid a possible SIGSEGV error from mysql error + handling code. Currently, mysql handles the Duplicated Key + error by re-entering the storage layer and getting dup key + info by calling get_dup_key(). This operation requires a valid + table handle ('row_prebuilt_t' structure) which could no + longer be available in the error handling stage. The suggested + solution is to report a 'table exists' error message (since + the dup key error here is due to an existing table whose name + is the one we are trying to rename to) and return the generic + error code. */ + if (error == (int) DB_DUPLICATE_KEY) { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to); + + error = DB_ERROR; + } + error = convert_error_code_to_mysql(error, NULL); DBUG_RETURN(error); @@ -8194,8 +8272,7 @@ innobase_xa_prepare( executing XA PREPARE and XA COMMIT commands. In this case we cannot know how many minutes or hours will be between XA PREPARE and XA COMMIT, and we don't want - to block for undefined period of time. - */ + to block for undefined period of time. */ pthread_mutex_lock(&prepare_commit_mutex); trx->active_trans = 2; } diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 6bfc43579b3..ce790814818 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -24,18 +24,21 @@ innobase_convert_string( CHARSET_INFO* from_cs, uint* errors); -/********************************************************************* -Display an SQL identifier. */ +/*****************************************************************//** +Convert a table or index name to the MySQL system_charset_info (UTF-8) +and quote it if needed. +@return pointer to the end of buf */ -void -innobase_print_identifier( -/*======================*/ - FILE* f, /* in: output stream */ - trx_t* trx, /* in: transaction */ - ibool table_id,/* in: TRUE=print a table name, - FALSE=print other identifier */ - const char* name, /* in: name to print */ - ulint namelen);/* in: length of name */ +char* +innobase_convert_name( +/*==================*/ + char* buf, /*!< out: buffer for converted identifier */ + ulint buflen, /*!< in: length of buf, in bytes */ + const char* id, /*!< in: identifier to convert */ + ulint idlen, /*!< in: length of id, in bytes */ + void* thd, /*!< in: MySQL connection thread, or NULL */ + ibool table_id);/*!< in: TRUE=id is a table or database name; + FALSE=id is an index name */ /********************************************************************** Returns true if the thread is the replication thread on the slave diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h index 25b619b3f12..d6e040ba9ca 100644 --- a/storage/innobase/include/mach0data.h +++ b/storage/innobase/include/mach0data.h @@ -266,8 +266,8 @@ UNIV_INLINE double mach_double_read( /*=============*/ - /* out: double read */ - byte* b); /* in: pointer to memory from where to read */ + /* out: double read */ + const byte* b); /* in: pointer to memory from where to read */ /************************************************************* Writes a double. It is stored in a little-endian format. */ UNIV_INLINE @@ -282,8 +282,8 @@ UNIV_INLINE float mach_float_read( /*============*/ - /* out: float read */ - byte* b); /* in: pointer to memory from where to read */ + /* out: float read */ + const byte* b); /* in: pointer to memory from where to read */ /************************************************************* Writes a float. It is stored in a little-endian format. */ UNIV_INLINE diff --git a/storage/innobase/include/mach0data.ic b/storage/innobase/include/mach0data.ic index ec15c10c661..dc7918c287b 100644 --- a/storage/innobase/include/mach0data.ic +++ b/storage/innobase/include/mach0data.ic @@ -504,8 +504,8 @@ UNIV_INLINE double mach_double_read( /*=============*/ - /* out: double read */ - byte* b) /* in: pointer to memory from where to read */ + /* out: double read */ + const byte* b) /* in: pointer to memory from where to read */ { double d; ulint i; @@ -553,8 +553,8 @@ UNIV_INLINE float mach_float_read( /*============*/ - /* out: float read */ - byte* b) /* in: pointer to memory from where to read */ + /* out: float read */ + const byte* b) /* in: pointer to memory from where to read */ { float d; ulint i; diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 9eb44d3f4a8..e09e1e00408 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -96,6 +96,8 @@ log. */ to become available again */ #define OS_FILE_SHARING_VIOLATION 76 #define OS_FILE_ERROR_NOT_SPECIFIED 77 + /* 78 is used in the plugin */ +#define OS_FILE_OPERATION_ABORTED 79 /* Types for aio operations */ #define OS_FILE_READ 10 diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index f0833bc6f21..cdbf1970715 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -318,9 +318,7 @@ trx_commit_step( /************************************************************************** Prints info about a transaction to the given file. The caller must own the -kernel mutex and must have called -innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL -or InnoDB cannot meanwhile change the info printed here. */ +kernel mutex. */ void trx_print( diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index 5afd19aa7e7..80aef45ea35 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -22,31 +22,6 @@ Created 5/7/1996 Heikki Tuuri #include "trx0sys.h" -/* 2 function prototypes copied from ha_innodb.cc: */ - -/***************************************************************** -If you want to print a thd that is not associated with the current thread, -you must call this function before reserving the InnoDB kernel_mutex, to -protect MySQL from setting thd->query NULL. If you print a thd of the current -thread, we know that MySQL cannot modify thd->query, and it is not necessary -to call this. Call innobase_mysql_end_print_arbitrary_thd() after you release -the kernel_mutex. -NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this -function! */ - -void -innobase_mysql_prepare_print_arbitrary_thd(void); -/*============================================*/ - -/***************************************************************** -Relases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd(). -NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this -function! */ - -void -innobase_mysql_end_print_arbitrary_thd(void); -/*========================================*/ - /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -4222,11 +4197,6 @@ lock_print_info_summary( /*====================*/ FILE* file) /* in: file where to print */ { - /* We must protect the MySQL thd->query field with a MySQL mutex, and - because the MySQL mutex must be reserved before the kernel_mutex of - InnoDB, we call innobase_mysql_prepare_print_arbitrary_thd() here. */ - - innobase_mysql_prepare_print_arbitrary_thd(); lock_mutex_enter_kernel(); if (lock_deadlock_found) { @@ -4314,7 +4284,6 @@ loop: if (trx == NULL) { lock_mutex_exit_kernel(); - innobase_mysql_end_print_arbitrary_thd(); ut_ad(lock_validate()); @@ -4386,7 +4355,6 @@ loop: if (load_page_first) { lock_mutex_exit_kernel(); - innobase_mysql_end_print_arbitrary_thd(); mtr_start(&mtr); @@ -4397,7 +4365,6 @@ loop: load_page_first = FALSE; - innobase_mysql_prepare_print_arbitrary_thd(); lock_mutex_enter_kernel(); goto loop; diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index 8fd959512c1..085f62daacc 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -257,6 +257,13 @@ os_file_get_last_error( " software or another instance\n" "InnoDB: of MySQL." " Please close it to get rid of this error.\n"); + } else if (err == ERROR_OPERATION_ABORTED) { + fprintf(stderr, + "InnoDB: The error means that the I/O" + " operation has been aborted\n" + "InnoDB: because of either a thread exit" + " or an application request.\n" + "InnoDB: Retry attempt is made.\n"); } else { fprintf(stderr, "InnoDB: Some operating system error numbers" @@ -278,6 +285,8 @@ os_file_get_last_error( } else if (err == ERROR_SHARING_VIOLATION || err == ERROR_LOCK_VIOLATION) { return(OS_FILE_SHARING_VIOLATION); + } else if (err == ERROR_OPERATION_ABORTED) { + return(OS_FILE_OPERATION_ABORTED); } else { return(100 + err); } @@ -402,6 +411,10 @@ os_file_handle_error_cond_exit( os_thread_sleep(10000000); /* 10 sec */ return(TRUE); + } else if (err == OS_FILE_OPERATION_ABORTED) { + + os_thread_sleep(100000); /* 100 ms */ + return(TRUE); } else { if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); @@ -3692,6 +3705,7 @@ os_aio_windows_handle( ibool ret_val; BOOL ret; DWORD len; + BOOL retry = FALSE; if (segment == ULINT_UNDEFINED) { array = os_aio_sync_array; @@ -3745,14 +3759,52 @@ os_aio_windows_handle( ut_a(TRUE == os_file_flush(slot->file)); } # endif /* UNIV_DO_FLUSH */ + } else if (os_file_handle_error(slot->name, "Windows aio")) { + + retry = TRUE; } else { - os_file_handle_error(slot->name, "Windows aio"); ret_val = FALSE; } os_mutex_exit(array->mutex); + if (retry) { + /* retry failed read/write operation synchronously. + No need to hold array->mutex. */ + + switch (slot->type) { + case OS_FILE_WRITE: + ret = WriteFile(slot->file, slot->buf, + slot->len, &len, + &(slot->control)); + + break; + case OS_FILE_READ: + ret = ReadFile(slot->file, slot->buf, + slot->len, &len, + &(slot->control)); + + break; + default: + ut_error; + } + + if (!ret && GetLastError() == ERROR_IO_PENDING) { + /* aio was queued successfully! + We want a synchronous i/o operation on a + file where we also use async i/o: in Windows + we must use the same wait mechanism as for + async i/o */ + + ret = GetOverlappedResult(slot->file, + &(slot->control), + &len, TRUE); + } + + ret_val = ret && len == slot->len; + } + os_aio_array_free_slot(array, slot); return(ret_val); diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 1746fb39f43..38902bca905 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -4514,6 +4514,7 @@ row_search_autoinc_read_column( dict_index_t* index, /* in: index to read from */ const rec_t* rec, /* in: current rec */ ulint col_no, /* in: column number */ + ulint mtype, /*!< in: column main type */ ibool unsigned_type) /* in: signed or unsigned flag */ { ulint len; @@ -4535,9 +4536,26 @@ row_search_autoinc_read_column( data = rec_get_nth_field((rec_t*)rec, offsets, col_no, &len); ut_a(len != UNIV_SQL_NULL); - ut_a(len <= sizeof value); - value = mach_read_int_type(data, len, unsigned_type); + switch (mtype) { + case DATA_INT: + ut_a(len <= sizeof value); + value = mach_read_int_type(data, len, unsigned_type); + break; + + case DATA_FLOAT: + ut_a(len == sizeof(float)); + value = mach_float_read(data); + break; + + case DATA_DOUBLE: + ut_a(len == sizeof(double)); + value = mach_double_read(data); + break; + + default: + ut_error; + } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); @@ -4625,7 +4643,8 @@ row_search_max_autoinc( dfield->col->prtype & DATA_UNSIGNED); *value = row_search_autoinc_read_column( - index, rec, i, unsigned_type); + index, rec, i, + dfield->col->mtype, unsigned_type); } } diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 8ada38845c5..fae479feddc 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -1652,9 +1652,7 @@ trx_mark_sql_stat_end( /************************************************************************** Prints info about a transaction to the given file. The caller must own the -kernel mutex and must have called -innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL -or InnoDB cannot meanwhile change the info printed here. */ +kernel mutex. */ void trx_print( diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index 6b5bcef1830..3b26d83bbb9 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -19,6 +19,7 @@ Created 5/11/1994 Heikki Tuuri #include "ut0sort.h" #include "trx0trx.h" #include "ha_prototypes.h" +#include "mysql_com.h" /* NAME_LEN */ ibool ut_always_false = FALSE; @@ -484,26 +485,17 @@ ut_print_namel( const char* name, /* in: name to print */ ulint namelen)/* in: length of name */ { -#ifdef UNIV_HOTBACKUP - fwrite(name, 1, namelen, f); -#else - if (table_id) { - char* slash = memchr(name, '/', namelen); - if (!slash) { + /* 2 * NAME_LEN for database and table name, + and some slack for the #mysql50# prefix and quotes */ + char buf[3 * NAME_LEN]; + const char* bufend; - goto no_db_name; - } + bufend = innobase_convert_name(buf, sizeof buf, + name, namelen, + trx ? trx->mysql_thd : NULL, + table_id); - /* Print the database name and table name separately. */ - innobase_print_identifier(f, trx, TRUE, name, slash - name); - putc('.', f); - innobase_print_identifier(f, trx, TRUE, slash + 1, - namelen - (slash - name) - 1); - } else { -no_db_name: - innobase_print_identifier(f, trx, table_id, name, namelen); - } -#endif + fwrite(buf, 1, bufend - buf, f); } /************************************************************************** diff --git a/storage/innodb_plugin/CMakeLists.txt b/storage/innodb_plugin/CMakeLists.txt index 25cd212a473..ad483779152 100644 --- a/storage/innodb_plugin/CMakeLists.txt +++ b/storage/innodb_plugin/CMakeLists.txt @@ -81,4 +81,4 @@ SET(INNODB_PLUGIN_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c) ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) -MYSQL_STORAGE_ENGINE(INNODB_PLUGIN) +MYSQL_STORAGE_ENGINE(INNOBASE) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 70225ffd9d9..1a6e07fd147 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,87 @@ +2009-11-20 The InnoDB Team + + * handler/ha_innodb.cc: + Add a workaround to prevent a crash due to Bug#45961 DDL on + partitioned innodb tables leaves data dictionary in an inconsistent + state + +2009-11-19 The InnoDB Team + + * btr/btr0btr.c: + Fix Bug#48469 when innodb tablespace is configured too small, crash + and corruption! + +2009-11-19 The InnoDB Team + + * data/data0type.c: + Fix Bug#48526 Data type for float and double is incorrectly reported + in InnoDB table monitor + +2009-11-19 The InnoDB Team + + * CMakeLists.txt: + Fix Bug#48317 cannot build innodb as static library + +2009-11-18 The InnoDB Team + + * handler/handler0alter.cc: + Fix Bug#48782 On lock wait timeout, CREATE INDEX (creating primary key) + attempts DROP TABLE + +2009-11-17 The InnoDB Team + + * handler/ha_innodb.cc, mysql-test/innodb.result, + mysql-test/innodb.test, mysql-test/innodb_bug44369.result, + mysql-test/innodb_bug44369.test, mysql-test/patches/innodb-index.diff, + row/row0mysql.c: + Report duplicate table names to the client connection, not to the + error log. + +2009-11-12 The InnoDB Team + + * handler/ha_innodb.cc, include/db0err.h, row/row0merge.c, + row/row0mysql.c: + Allow CREATE INDEX to be interrupted. + Also, when CHECK TABLE is interrupted, report ER_QUERY_INTERRUPTED. + +2009-11-11 The InnoDB Team + + * handler/ha_innodb.cc, mysql-test/innodb_bug47167.result, + mysql-test/innodb_bug47167.test, mysql-test/innodb_file_format.result: + Fix Bug#47167 "set global innodb_file_format_check" cannot set value + by User-Defined Variable + +2009-11-11 The InnoDB Team + + * include/os0file.h, os/os0file.c: + Fix Bug#3139 Mysql crashes: 'windows error 995' after several selects + on a large DB + +2009-11-04 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#32430 'show innodb status' causes errors + Invalid (old?) table or database name in logs + +2009-11-02 The InnoDB Team + + * btr/btr0sea.c, buf/buf0buf.c, dict/dict0dict.c, fil/fil0fil.c, + ibuf/ibuf0ibuf.c, include/btr0sea.h, include/dict0dict.h, + include/fil0fil.h, include/ibuf0ibuf.h, include/lock0lock.h, + include/log0log.h, include/log0recv.h, include/mem0mem.h, + include/mem0pool.h, include/os0file.h, include/pars0pars.h, + include/srv0srv.h, include/thr0loc.h, include/trx0i_s.h, + include/trx0purge.h, include/trx0rseg.h, include/trx0sys.h, + include/trx0undo.h, include/usr0sess.h, lock/lock0lock.c, + log/log0log.c, log/log0recv.c, mem/mem0dbg.c, mem/mem0pool.c, + os/os0file.c, os/os0sync.c, os/os0thread.c, pars/lexyy.c, + pars/pars0lex.l, que/que0que.c, srv/srv0srv.c, srv/srv0start.c, + sync/sync0arr.c, sync/sync0sync.c, thr/thr0loc.c, trx/trx0i_s.c, + trx/trx0purge.c, trx/trx0rseg.c, trx/trx0sys.c, trx/trx0undo.c, + usr/usr0sess.c, ut/ut0mem.c: + Fix Bug #45992 innodb memory not freed after shutdown + Fix Bug #46656 InnoDB plugin: memory leaks (Valgrind) + 2009-10-29 The InnoDB Team * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, @@ -66,6 +150,12 @@ Fix Bug#47058 Failure to compile innodb_plugin on solaris 10u7 + spro cc/CC 5.10 +2009-10-13 The InnoDB Team + + * buf/buf0flu.c: + Call fsync() on datafiles after a batch of pages is written to disk + even when skip_innodb_doublewrite is set. + 2009-10-05 The InnoDB Team * buf/buf0buf.c: diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index 94b34ecece1..086b3a0a599 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -790,8 +790,15 @@ btr_create( } else { /* It is a non-ibuf tree: create a file segment for leaf pages */ - fseg_create(space, page_no, - PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr); + if (!fseg_create(space, page_no, + PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) { + /* Not enough space for new segment, free root + segment before return. */ + btr_free_root(space, zip_size, page_no, mtr); + + return(FIL_NULL); + } + /* The fseg create acquires a second latch on the page, therefore we must declare it: */ buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); diff --git a/storage/innodb_plugin/btr/btr0sea.c b/storage/innodb_plugin/btr/btr0sea.c index 0a80c61a58d..ef7afeb1039 100644 --- a/storage/innodb_plugin/btr/btr0sea.c +++ b/storage/innodb_plugin/btr/btr0sea.c @@ -175,6 +175,21 @@ btr_search_sys_create( btr_search_sys->hash_index = ha_create(hash_size, 0, 0); } +/*****************************************************************//** +Frees the adaptive search system at a database shutdown. */ +UNIV_INTERN +void +btr_search_sys_free(void) +/*=====================*/ +{ + mem_free(btr_search_latch_temp); + btr_search_latch_temp = NULL; + mem_heap_free(btr_search_sys->hash_index->heap); + hash_table_free(btr_search_sys->hash_index); + mem_free(btr_search_sys); + btr_search_sys = NULL; +} + /********************************************************************//** Disable the adaptive hash search system and empty the index. */ UNIV_INTERN diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index ff31457d200..111d396fbc5 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -1020,7 +1020,11 @@ buf_pool_free(void) os_mem_free_large(chunk->mem, chunk->mem_size); } - buf_pool->n_chunks = 0; + mem_free(buf_pool->chunks); + hash_table_free(buf_pool->page_hash); + hash_table_free(buf_pool->zip_hash); + mem_free(buf_pool); + buf_pool = NULL; } /********************************************************************//** diff --git a/storage/innodb_plugin/data/data0type.c b/storage/innodb_plugin/data/data0type.c index 8429775e7d8..e834fd2ec55 100644 --- a/storage/innodb_plugin/data/data0type.c +++ b/storage/innodb_plugin/data/data0type.c @@ -237,6 +237,22 @@ dtype_print( fputs("DATA_SYS", stderr); break; + case DATA_FLOAT: + fputs("DATA_FLOAT", stderr); + break; + + case DATA_DOUBLE: + fputs("DATA_DOUBLE", stderr); + break; + + case DATA_DECIMAL: + fputs("DATA_DECIMAL", stderr); + break; + + case DATA_VARMYSQL: + fputs("DATA_VARMYSQL", stderr); + break; + default: fprintf(stderr, "type %lu", (ulong) mtype); break; diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index aedaf7cec1d..2e524a5a2e3 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -1200,7 +1200,7 @@ dict_index_too_big_for_undo( = TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE + 2 /* next record pointer */ + 1 /* type_cmpl */ - + 11 /* trx->undo_no */ - 11 /* table->id */ + + 11 /* trx->undo_no */ + 11 /* table->id */ + 1 /* rec_get_info_bits() */ + 11 /* DB_TRX_ID */ + 11 /* DB_ROLL_PTR */ @@ -4652,6 +4652,26 @@ dict_ind_init(void) dict_ind_redundant->cached = dict_ind_compact->cached = TRUE; } +/**********************************************************************//** +Frees dict_ind_redundant and dict_ind_compact. */ +static +void +dict_ind_free(void) +/*===============*/ +{ + dict_table_t* table; + + table = dict_ind_compact->table; + dict_mem_index_free(dict_ind_compact); + dict_ind_compact = NULL; + dict_mem_table_free(table); + + table = dict_ind_redundant->table; + dict_mem_index_free(dict_ind_redundant); + dict_ind_redundant = NULL; + dict_mem_table_free(table); +} + #ifndef UNIV_HOTBACKUP /**********************************************************************//** Get index by name @@ -4777,4 +4797,55 @@ dict_table_check_for_dup_indexes( } } #endif /* UNIV_DEBUG */ + +/************************************************************************** +Closes the data dictionary module. */ +UNIV_INTERN +void +dict_close(void) +/*============*/ +{ + ulint i; + + /* Free the hash elements. We don't remove them from the table + because we are going to destroy the table anyway. */ + for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) { + dict_table_t* table; + + table = HASH_GET_FIRST(dict_sys->table_hash, i); + + while (table) { + dict_table_t* prev_table = table; + + table = HASH_GET_NEXT(name_hash, prev_table); +#ifdef UNIV_DEBUG + ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N); +#endif + /* Acquire only because it's a pre-condition. */ + mutex_enter(&dict_sys->mutex); + + dict_table_remove_from_cache(prev_table); + + mutex_exit(&dict_sys->mutex); + } + } + + hash_table_free(dict_sys->table_hash); + + /* The elements are the same instance as in dict_sys->table_hash, + therefore we don't delete the individual elements. */ + hash_table_free(dict_sys->table_id_hash); + + dict_ind_free(); + + mutex_free(&dict_sys->mutex); + + rw_lock_free(&dict_operation_lock); + memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock)); + + mutex_free(&dict_foreign_err_mutex); + + mem_free(dict_sys); + dict_sys = NULL; +} #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c index ba6f2f8666f..112a0e27d50 100644 --- a/storage/innodb_plugin/fil/fil0fil.c +++ b/storage/innodb_plugin/fil/fil0fil.c @@ -321,6 +321,17 @@ fil_get_space_id_for_table( /*=======================*/ const char* name); /*!< in: table name in the standard 'databasename/tablename' format */ +/*******************************************************************//** +Frees a space object from the tablespace memory cache. Closes the files in +the chain but does not delete them. There must not be any pending i/o's or +flushes on the files. */ +static +ibool +fil_space_free( +/*===========*/ + /* out: TRUE if success */ + ulint id, /* in: space id */ + ibool own_mutex);/* in: TRUE if own system->mutex */ /********************************************************************//** Reads data from a space to a buffer. Remember that the possible incomplete blocks at the end of file are ignored: they are not taken into account when @@ -1144,7 +1155,7 @@ try_again: mutex_exit(&fil_system->mutex); - fil_space_free(namesake_id); + fil_space_free(namesake_id, FALSE); goto try_again; } @@ -1269,17 +1280,21 @@ Frees a space object from the tablespace memory cache. Closes the files in the chain but does not delete them. There must not be any pending i/o's or flushes on the files. @return TRUE if success */ -UNIV_INTERN +static ibool fil_space_free( /*===========*/ - ulint id) /*!< in: space id */ + /* out: TRUE if success */ + ulint id, /* in: space id */ + ibool own_mutex) /* in: TRUE if own system->mutex */ { fil_space_t* space; fil_space_t* namespace; fil_node_t* fil_node; - mutex_enter(&fil_system->mutex); + if (!own_mutex) { + mutex_enter(&fil_system->mutex); + } space = fil_space_get_by_id(id); @@ -1326,7 +1341,9 @@ fil_space_free( ut_a(0 == UT_LIST_GET_LEN(space->chain)); - mutex_exit(&fil_system->mutex); + if (!own_mutex) { + mutex_exit(&fil_system->mutex); + } rw_lock_free(&(space->latch)); @@ -1586,6 +1603,8 @@ fil_close_all_files(void) space = UT_LIST_GET_FIRST(fil_system->space_list); while (space != NULL) { + fil_space_t* prev_space = space; + node = UT_LIST_GET_FIRST(space->chain); while (node != NULL) { @@ -1595,6 +1614,7 @@ fil_close_all_files(void) node = UT_LIST_GET_NEXT(chain, node); } space = UT_LIST_GET_NEXT(space_list, space); + fil_space_free(prev_space->id, TRUE); } mutex_exit(&fil_system->mutex); @@ -2226,7 +2246,7 @@ try_again: #endif /* printf("Deleting tablespace %s id %lu\n", space->name, id); */ - success = fil_space_free(id); + success = fil_space_free(id, FALSE); if (success) { success = os_file_delete(path); @@ -4753,3 +4773,26 @@ fil_page_get_type( return(mach_read_from_2(page + FIL_PAGE_TYPE)); } + +/******************************************************************** +Initializes the tablespace memory cache. */ +UNIV_INTERN +void +fil_close(void) +/*===========*/ +{ + /* The mutex should already have been freed. */ + ut_ad(fil_system->mutex.magic_n == 0); + + hash_table_free(fil_system->spaces); + + hash_table_free(fil_system->name_hash); + + ut_a(UT_LIST_GET_LEN(fil_system->LRU) == 0); + ut_a(UT_LIST_GET_LEN(fil_system->unflushed_spaces) == 0); + ut_a(UT_LIST_GET_LEN(fil_system->space_list) == 0); + + mem_free(fil_system); + + fil_system = NULL; +} diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index ac710ea2b15..b51e9186fe4 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -269,10 +269,10 @@ innobase_file_format_check_on_off( /************************************************************//** Validate the file format check config parameters, as a side effect it sets the srv_check_file_format_at_startup variable. -@return true if valid config value */ +@return the format_id if valid config value, otherwise, return -1 */ static -bool -innobase_file_format_check_validate( +int +innobase_file_format_validate_and_set( /*================================*/ const char* format_check); /*!< in: parameter value */ /****************************************************************//** @@ -785,11 +785,20 @@ convert_error_code_to_mysql( case DB_SUCCESS: return(0); + case DB_INTERRUPTED: + my_error(ER_QUERY_INTERRUPTED, MYF(0)); + /* fall through */ case DB_ERROR: default: return(-1); /* unspecified error */ case DB_DUPLICATE_KEY: + /* Be cautious with returning this error, since + mysql could re-enter the storage layer to get + duplicated key info, the operation requires a + valid table handle and/or transaction information, + which might not always be available in the error + handling stage. */ return(HA_ERR_FOUND_DUPP_KEY); case DB_FOREIGN_DUPLICATE_KEY: @@ -890,36 +899,6 @@ convert_error_code_to_mysql( } /*************************************************************//** -If you want to print a thd that is not associated with the current thread, -you must call this function before reserving the InnoDB kernel_mutex, to -protect MySQL from setting thd->query NULL. If you print a thd of the current -thread, we know that MySQL cannot modify thd->query, and it is not necessary -to call this. Call innobase_mysql_end_print_arbitrary_thd() after you release -the kernel_mutex. */ -extern "C" UNIV_INTERN -void -innobase_mysql_prepare_print_arbitrary_thd(void) -/*============================================*/ -{ - ut_ad(!mutex_own(&kernel_mutex)); - VOID(pthread_mutex_lock(&LOCK_thread_count)); -} - -/*************************************************************//** -Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd(). -In the InnoDB latching order, the mutex sits right above the -kernel_mutex. In debug builds, we assert that the kernel_mutex is -released before this function is invoked. */ -extern "C" UNIV_INTERN -void -innobase_mysql_end_print_arbitrary_thd(void) -/*========================================*/ -{ - ut_ad(!mutex_own(&kernel_mutex)); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); -} - -/*************************************************************//** Prints info of a THD object (== user session thread) to the given file. */ extern "C" UNIV_INTERN void @@ -1707,15 +1686,19 @@ innobase_convert_identifier( FALSE=id is an UTF-8 string */ { char nz[NAME_LEN + 1]; +#if MYSQL_VERSION_ID >= 50141 + char nz2[NAME_LEN + 1 + EXPLAIN_FILENAME_MAX_EXTRA_LENGTH]; +#else /* MYSQL_VERSION_ID >= 50141 */ char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix]; +#endif /* MYSQL_VERSION_ID >= 50141 */ const char* s = id; int q; if (file_id) { - /* Decode the table name. The filename_to_tablename() - function expects a NUL-terminated string. The input and - output strings buffers must not be shared. */ + /* Decode the table name. The MySQL function expects + a NUL-terminated string. The input and output strings + buffers must not be shared. */ if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) { idlen = (sizeof nz) - 1; @@ -1725,7 +1708,13 @@ innobase_convert_identifier( nz[idlen] = 0; s = nz2; +#if MYSQL_VERSION_ID >= 50141 + idlen = explain_filename((THD*) thd, nz, nz2, sizeof nz2, + EXPLAIN_PARTITIONS_AS_COMMENT); + goto no_quote; +#else /* MYSQL_VERSION_ID >= 50141 */ idlen = filename_to_tablename(nz, nz2, sizeof nz2); +#endif /* MYSQL_VERSION_ID >= 50141 */ } /* See if the identifier needs to be quoted. */ @@ -1736,6 +1725,9 @@ innobase_convert_identifier( } if (q == EOF) { +#if MYSQL_VERSION_ID >= 50141 +no_quote: +#endif /* MYSQL_VERSION_ID >= 50141 */ if (UNIV_UNLIKELY(idlen > buflen)) { idlen = buflen; } @@ -2133,8 +2125,8 @@ mem_free_and_error: /* Did the user specify a format name that we support ? As a side effect it will update the variable srv_check_file_format_at_startup */ - if (!innobase_file_format_check_validate( - innobase_file_format_check)) { + if (innobase_file_format_validate_and_set( + innobase_file_format_check) < 0) { sql_print_error("InnoDB: invalid " "innodb_file_format_check value: " @@ -5225,8 +5217,10 @@ ha_innobase::change_active_index( prebuilt->index); if (UNIV_UNLIKELY(!prebuilt->index_usable)) { - sql_print_warning("InnoDB: insufficient history for index %u", - keynr); + push_warning_printf(user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_TABLE_DEF_CHANGED, + "InnoDB: insufficient history for index %u", + keynr); /* The caller seems to ignore this. Thus, we must check this again in row_search_for_mysql(). */ DBUG_RETURN(2); @@ -5713,17 +5707,8 @@ create_table_def( /* First check whether the column to be added has a system reserved name. */ if (dict_col_name_is_reserved(field->field_name)){ - push_warning_printf( - (THD*) trx->mysql_thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_CANT_CREATE_TABLE, - "Error creating table '%s' with " - "column name '%s'. '%s' is a " - "reserved name. Please try to " - "re-create the table with a " - "different column name.", - table->name, (char*) field->field_name, - (char*) field->field_name); + my_error(ER_WRONG_COLUMN_NAME, MYF(0), + field->field_name); dict_mem_table_free(table); trx_commit_for_mysql(trx); @@ -5745,6 +5730,14 @@ create_table_def( error = row_create_table_for_mysql(table, trx); + if (error == DB_DUPLICATE_KEY) { + char buf[100]; + innobase_convert_identifier(buf, sizeof buf, + table_name, strlen(table_name), + trx->mysql_thd, TRUE); + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), buf); + } + error_ret: error = convert_error_code_to_mysql(error, flags, NULL); @@ -6798,6 +6791,24 @@ ha_innobase::rename_table( innobase_commit_low(trx); trx_free_for_mysql(trx); + /* Add a special case to handle the Duplicated Key error + and return DB_ERROR instead. + This is to avoid a possible SIGSEGV error from mysql error + handling code. Currently, mysql handles the Duplicated Key + error by re-entering the storage layer and getting dup key + info by calling get_dup_key(). This operation requires a valid + table handle ('row_prebuilt_t' structure) which could no + longer be available in the error handling stage. The suggested + solution is to report a 'table exists' error message (since + the dup key error here is due to an existing table whose name + is the one we are trying to rename to) and return the generic + error code. */ + if (error == (int) DB_DUPLICATE_KEY) { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to); + + error = DB_ERROR; + } + error = convert_error_code_to_mysql(error, 0, NULL); DBUG_RETURN(error); @@ -7348,11 +7359,15 @@ ha_innobase::check( ret = row_check_table_for_mysql(prebuilt); - if (ret == DB_SUCCESS) { + switch (ret) { + case DB_SUCCESS: return(HA_ADMIN_OK); + case DB_INTERRUPTED: + my_error(ER_QUERY_INTERRUPTED, MYF(0)); + return(-1); + default: + return(HA_ADMIN_CORRUPT); } - - return(HA_ADMIN_CORRUPT); } /*************************************************************//** @@ -7899,7 +7914,10 @@ ha_innobase::external_lock( ulong const tx_isolation = thd_tx_isolation(ha_thd()); if (tx_isolation <= ISO_READ_COMMITTED && binlog_format == BINLOG_FORMAT_STMT - && thd_binlog_filter_ok(thd)) +#if MYSQL_VERSION_ID > 50140 + && thd_binlog_filter_ok(thd) +#endif /* MYSQL_VERSION_ID > 50140 */ + ) { char buf[256]; my_snprintf(buf, sizeof(buf), @@ -9148,8 +9166,7 @@ innobase_xa_prepare( executing XA PREPARE and XA COMMIT commands. In this case we cannot know how many minutes or hours will be between XA PREPARE and XA COMMIT, and we don't want - to block for undefined period of time. - */ + to block for undefined period of time. */ pthread_mutex_lock(&prepare_commit_mutex); trx->active_trans = 2; } @@ -9491,25 +9508,24 @@ innobase_file_format_check_on_off( /************************************************************//** Validate the file format check config parameters, as a side effect it sets the srv_check_file_format_at_startup variable. -@return true if valid config value */ +@return the format_id if valid config value, otherwise, return -1 */ static -bool -innobase_file_format_check_validate( +int +innobase_file_format_validate_and_set( /*================================*/ const char* format_check) /*!< in: parameter value */ { uint format_id; - bool ret = true; format_id = innobase_file_format_name_lookup(format_check); if (format_id < DICT_TF_FORMAT_MAX + 1) { srv_check_file_format_at_startup = format_id; + + return((int) format_id); } else { - ret = false; + return(-1); } - - return(ret); } /*************************************************************//** @@ -9544,7 +9560,11 @@ innodb_file_format_name_validate( if (format_id <= DICT_TF_FORMAT_MAX) { - *static_cast<const char**>(save) = file_format_input; + /* Save a pointer to the name in the + 'file_format_name_map' constant array. */ + *static_cast<const char**>(save) = + trx_sys_file_format_id_to_name(format_id); + return(0); } } @@ -9607,6 +9627,7 @@ innodb_file_format_check_validate( const char* file_format_input; char buff[STRING_BUFFER_USUAL_SIZE]; int len = sizeof(buff); + int format_id; ut_a(save != NULL); ut_a(value != NULL); @@ -9619,24 +9640,35 @@ innodb_file_format_check_validate( message if they did so. */ if (innobase_file_format_check_on_off(file_format_input)) { - sql_print_warning( + push_warning_printf(thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WRONG_ARGUMENTS, "InnoDB: invalid innodb_file_format_check " "value; on/off can only be set at startup or " "in the configuration file"); - } else if (innobase_file_format_check_validate( - file_format_input)) { + } else { + format_id = innobase_file_format_validate_and_set( + file_format_input); - *static_cast<const char**>(save) = file_format_input; + if (format_id >= 0) { + /* Save a pointer to the name in the + 'file_format_name_map' constant array. */ + *static_cast<const char**>(save) = + trx_sys_file_format_id_to_name( + (uint)format_id); - return(0); + return(0); - } else { - sql_print_warning( - "InnoDB: invalid innodb_file_format_check " - "value; can be any format up to %s " - "or its equivalent numeric id", - trx_sys_file_format_id_to_name( - DICT_TF_FORMAT_MAX)); + } else { + push_warning_printf(thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WRONG_ARGUMENTS, + "InnoDB: invalid innodb_file_format_check " + "value; can be any format up to %s " + "or its equivalent numeric id", + trx_sys_file_format_id_to_name( + DICT_TF_FORMAT_MAX)); + } } } @@ -9906,12 +9938,15 @@ static MYSQL_SYSVAR_STR(file_format, innobase_file_format_name, innodb_file_format_name_validate, innodb_file_format_name_update, "Antelope"); +/* If a new file format is introduced, the file format +name needs to be updated accordingly. Please refer to +file_format_name_map[] defined in trx0sys.c for the next +file format name. */ static MYSQL_SYSVAR_STR(file_format_check, innobase_file_format_check, PLUGIN_VAR_OPCMDARG, "The highest file format in the tablespace.", innodb_file_format_check_validate, - innodb_file_format_check_update, - "on"); + innodb_file_format_check_update, "Barracuda"); static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit, PLUGIN_VAR_OPCMDARG, diff --git a/storage/innodb_plugin/handler/ha_innodb.h b/storage/innodb_plugin/handler/ha_innodb.h index 4779651ee27..31e88ed8530 100644 --- a/storage/innodb_plugin/handler/ha_innodb.h +++ b/storage/innodb_plugin/handler/ha_innodb.h @@ -258,12 +258,14 @@ int thd_binlog_format(const MYSQL_THD thd); */ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); +#if MYSQL_VERSION_ID > 50140 /** Check if binary logging is filtered for thread's current db. @param thd Thread handle @retval 1 the query is not filtered, 0 otherwise. */ bool thd_binlog_filter_ok(const MYSQL_THD thd); +#endif /* MYSQL_VERSION_ID > 50140 */ } typedef struct trx_struct trx_t; diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc index 37aed06b28a..a5008991400 100644 --- a/storage/innodb_plugin/handler/handler0alter.cc +++ b/storage/innodb_plugin/handler/handler0alter.cc @@ -765,10 +765,11 @@ err_exit: ut_ad(error == DB_SUCCESS); /* Commit the data dictionary transaction in order to release - the table locks on the system tables. Unfortunately, this - means that if MySQL crashes while creating a new primary key - inside row_merge_build_indexes(), indexed_table will not be - dropped on crash recovery. Thus, it will become orphaned. */ + the table locks on the system tables. This means that if + MySQL crashes while creating a new primary key inside + row_merge_build_indexes(), indexed_table will not be dropped + by trx_rollback_active(). It will have to be recovered or + dropped by the database administrator. */ trx_commit_for_mysql(trx); row_mysql_unlock_data_dictionary(trx); @@ -882,7 +883,9 @@ error: /* fall through */ default: if (new_primary) { - row_merge_drop_table(trx, indexed_table); + if (indexed_table != innodb_table) { + row_merge_drop_table(trx, indexed_table); + } } else { if (!dict_locked) { row_mysql_lock_data_dictionary(trx); diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c index 37c68391477..08986fac0ef 100644 --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c @@ -390,6 +390,27 @@ ibuf_count_set( #endif /******************************************************************//** +Closes insert buffer and frees the data structures. */ +UNIV_INTERN +void +ibuf_close(void) +/*============*/ +{ + mutex_free(&ibuf_pessimistic_insert_mutex); + memset(&ibuf_pessimistic_insert_mutex, + 0x0, sizeof(ibuf_pessimistic_insert_mutex)); + + mutex_free(&ibuf_mutex); + memset(&ibuf_mutex, 0x0, sizeof(ibuf_mutex)); + + mutex_free(&ibuf_bitmap_mutex); + memset(&ibuf_bitmap_mutex, 0x0, sizeof(ibuf_mutex)); + + mem_free(ibuf); + ibuf = NULL; +} + +/******************************************************************//** Updates the size information of the ibuf, assuming the segment size has not changed. */ static diff --git a/storage/innodb_plugin/include/btr0sea.h b/storage/innodb_plugin/include/btr0sea.h index 631b3bd386c..f98ba386f9c 100644 --- a/storage/innodb_plugin/include/btr0sea.h +++ b/storage/innodb_plugin/include/btr0sea.h @@ -41,6 +41,12 @@ void btr_search_sys_create( /*==================*/ ulint hash_size); /*!< in: hash index hash table size */ +/*****************************************************************//** +Frees the adaptive search system at a database shutdown. */ +UNIV_INTERN +void +btr_search_sys_free(void); +/*=====================*/ /********************************************************************//** Disable the adaptive hash search system and empty the index. */ diff --git a/storage/innodb_plugin/include/db0err.h b/storage/innodb_plugin/include/db0err.h index 23898583b72..747e9b5364e 100644 --- a/storage/innodb_plugin/include/db0err.h +++ b/storage/innodb_plugin/include/db0err.h @@ -32,6 +32,7 @@ enum db_err { /* The following are error codes */ DB_ERROR, + DB_INTERRUPTED, DB_OUT_OF_MEMORY, DB_OUT_OF_FILE_SPACE, DB_LOCK_WAIT, diff --git a/storage/innodb_plugin/include/dict0dict.h b/storage/innodb_plugin/include/dict0dict.h index d425241a3a2..12396556c2d 100644 --- a/storage/innodb_plugin/include/dict0dict.h +++ b/storage/innodb_plugin/include/dict0dict.h @@ -1151,6 +1151,13 @@ void dict_ind_init(void); /*===============*/ +/**********************************************************************//** +Closes the data dictionary module. */ +UNIV_INTERN +void +dict_close(void); +/*============*/ + #ifndef UNIV_NONINL #include "dict0dict.ic" #endif diff --git a/storage/innodb_plugin/include/fil0fil.h b/storage/innodb_plugin/include/fil0fil.h index a36deaf16ce..74d0fbcdacd 100644 --- a/storage/innodb_plugin/include/fil0fil.h +++ b/storage/innodb_plugin/include/fil0fil.h @@ -224,15 +224,6 @@ fil_space_create( 0 for uncompressed tablespaces */ ulint purpose);/*!< in: FIL_TABLESPACE, or FIL_LOG if log */ /*******************************************************************//** -Frees a space object from a the tablespace memory cache. Closes the files in -the chain but does not delete them. -@return TRUE if success */ -UNIV_INTERN -ibool -fil_space_free( -/*===========*/ - ulint id); /*!< in: space id */ -/*******************************************************************//** Returns the size of the space in pages. The tablespace must be cached in the memory cache. @return space size, 0 if space not found */ @@ -278,6 +269,12 @@ fil_init( ulint hash_size, /*!< in: hash table size */ ulint max_n_open); /*!< in: max number of open files */ /*******************************************************************//** +Initializes the tablespace memory cache. */ +UNIV_INTERN +void +fil_close(void); +/*===========*/ +/*******************************************************************//** Opens all log files and system tablespace data files. They stay open until the database server shutdown. This should be called at a server startup after the space objects for the log and the system tablespace have been created. The diff --git a/storage/innodb_plugin/include/ha_prototypes.h b/storage/innodb_plugin/include/ha_prototypes.h index e8789d1638b..b737a00b3dc 100644 --- a/storage/innodb_plugin/include/ha_prototypes.h +++ b/storage/innodb_plugin/include/ha_prototypes.h @@ -153,28 +153,6 @@ get_innobase_type_from_mysql_type( const void* field) /*!< in: MySQL Field */ __attribute__((nonnull)); -/*************************************************************//** -If you want to print a thd that is not associated with the current thread, -you must call this function before reserving the InnoDB kernel_mutex, to -protect MySQL from setting thd->query NULL. If you print a thd of the current -thread, we know that MySQL cannot modify thd->query, and it is not necessary -to call this. Call innobase_mysql_end_print_arbitrary_thd() after you release -the kernel_mutex. */ -UNIV_INTERN -void -innobase_mysql_prepare_print_arbitrary_thd(void); -/*============================================*/ - -/*************************************************************//** -Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd(). -In the InnoDB latching order, the mutex sits right above the -kernel_mutex. In debug builds, we assert that the kernel_mutex is -released before this function is invoked. */ -UNIV_INTERN -void -innobase_mysql_end_print_arbitrary_thd(void); -/*========================================*/ - /******************************************************************//** Get the variable length bounds of the given character set. */ UNIV_INTERN diff --git a/storage/innodb_plugin/include/ibuf0ibuf.h b/storage/innodb_plugin/include/ibuf0ibuf.h index 21330997df3..8aa21fb9d95 100644 --- a/storage/innodb_plugin/include/ibuf0ibuf.h +++ b/storage/innodb_plugin/include/ibuf0ibuf.h @@ -356,6 +356,12 @@ void ibuf_print( /*=======*/ FILE* file); /*!< in: file where to print */ +/******************************************************************//** +Closes insert buffer and frees the data structures. */ +UNIV_INTERN +void +ibuf_close(void); +/*============*/ #define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO #define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO diff --git a/storage/innodb_plugin/include/lock0lock.h b/storage/innodb_plugin/include/lock0lock.h index aeabe39e1a9..82e4c9bd976 100644 --- a/storage/innodb_plugin/include/lock0lock.h +++ b/storage/innodb_plugin/include/lock0lock.h @@ -59,6 +59,12 @@ lock_sys_create( /*============*/ ulint n_cells); /*!< in: number of slots in lock hash table */ /*********************************************************************//** +Closes the lock system at database shutdown. */ +UNIV_INTERN +void +lock_sys_close(void); +/*================*/ +/*********************************************************************//** Checks if some transaction has an implicit x-lock on a record in a clustered index. @return transaction which has the x-lock, or NULL */ diff --git a/storage/innodb_plugin/include/log0log.h b/storage/innodb_plugin/include/log0log.h index 299b4a05b40..135aeb69e2d 100644 --- a/storage/innodb_plugin/include/log0log.h +++ b/storage/innodb_plugin/include/log0log.h @@ -572,6 +572,18 @@ UNIV_INTERN void log_refresh_stats(void); /*===================*/ +/********************************************************** +Shutdown the log system but do not release all the memory. */ +UNIV_INTERN +void +log_shutdown(void); +/*==============*/ +/********************************************************** +Free the log system data structures. */ +UNIV_INTERN +void +log_mem_free(void); +/*==============*/ extern log_t* log_sys; @@ -584,7 +596,7 @@ extern log_t* log_sys; #define LOG_RECOVER 98887331 /* The counting of lsn's starts from this value: this must be non-zero */ -#define LOG_START_LSN ((ib_uint64_t) (16 * OS_FILE_LOG_BLOCK_SIZE)) +#define LOG_START_LSN ((ib_uint64_t) (16 * OS_FILE_LOG_BLOCK_SIZE)) #define LOG_BUFFER_SIZE (srv_log_buffer_size * UNIV_PAGE_SIZE) #define LOG_ARCHIVE_BUF_SIZE (srv_log_buffer_size * UNIV_PAGE_SIZE / 4) @@ -721,9 +733,12 @@ struct log_group_struct{ ulint lsn_offset; /*!< the offset of the above lsn */ ulint n_pending_writes;/*!< number of currently pending flush writes for this log group */ + byte** file_header_bufs_ptr;/*!< unaligned buffers */ byte** file_header_bufs;/*!< buffers for each file header in the group */ +#ifdef UNIV_LOG_ARCHIVE /*-----------------------------*/ + byte** archive_file_header_bufs_ptr;/*!< unaligned buffers */ byte** archive_file_header_bufs;/*!< buffers for each file header in the group */ ulint archive_space_id;/*!< file space which @@ -742,10 +757,12 @@ struct log_group_struct{ completion function then sets the new value to ..._file_no */ ulint next_archived_offset; /*!< like the preceding field */ +#endif /* UNIV_LOG_ARCHIVE */ /*-----------------------------*/ ib_uint64_t scanned_lsn; /*!< used only in recovery: recovery scan succeeded up to this lsn in this log group */ + byte* checkpoint_buf_ptr;/*!< unaligned checkpoint header */ byte* checkpoint_buf; /*!< checkpoint header is written from this buffer to the group */ UT_LIST_NODE_T(log_group_t) @@ -763,6 +780,7 @@ struct log_struct{ #ifndef UNIV_HOTBACKUP mutex_t mutex; /*!< mutex protecting the log */ #endif /* !UNIV_HOTBACKUP */ + byte* buf_ptr; /* unaligned log buffer */ byte* buf; /*!< log buffer */ ulint buf_size; /*!< log buffer size in bytes */ ulint max_buf_free; /*!< recommended maximum value of @@ -899,6 +917,7 @@ struct log_struct{ should wait for this without owning the log mutex */ #endif /* !UNIV_HOTBACKUP */ + byte* checkpoint_buf_ptr;/* unaligned checkpoint header */ byte* checkpoint_buf; /*!< checkpoint header is read to this buffer */ /* @} */ diff --git a/storage/innodb_plugin/include/log0recv.h b/storage/innodb_plugin/include/log0recv.h index 6de735be945..a3d2bd050f5 100644 --- a/storage/innodb_plugin/include/log0recv.h +++ b/storage/innodb_plugin/include/log0recv.h @@ -239,6 +239,18 @@ UNIV_INTERN void recv_sys_create(void); /*=================*/ +/**********************************************************//** +Release recovery system mutexes. */ +UNIV_INTERN +void +recv_sys_close(void); +/*================*/ +/********************************************************//** +Frees the recovery system memory. */ +UNIV_INTERN +void +recv_sys_mem_free(void); +/*===================*/ /********************************************************//** Inits the recovery system for a recovery operation. */ UNIV_INTERN @@ -246,6 +258,12 @@ void recv_sys_init( /*==========*/ ulint available_memory); /*!< in: available memory in bytes */ +/********************************************************//** +Reset the state of the recovery system variables. */ +UNIV_INTERN +void +recv_sys_var_init(void); +/*===================*/ /*******************************************************************//** Empties the hash table of stored log records, applying them to appropriate pages. */ diff --git a/storage/innodb_plugin/include/mem0mem.h b/storage/innodb_plugin/include/mem0mem.h index a092b024219..98f8748e529 100644 --- a/storage/innodb_plugin/include/mem0mem.h +++ b/storage/innodb_plugin/include/mem0mem.h @@ -82,6 +82,13 @@ void mem_init( /*=====*/ ulint size); /*!< in: common pool size in bytes */ +/******************************************************************//** +Closes the memory system. */ +UNIV_INTERN +void +mem_close(void); +/*===========*/ + /**************************************************************//** Use this macro instead of the corresponding function! Macro for memory heap creation. */ diff --git a/storage/innodb_plugin/include/mem0pool.h b/storage/innodb_plugin/include/mem0pool.h index 18f988241d6..5e93bf88a47 100644 --- a/storage/innodb_plugin/include/mem0pool.h +++ b/storage/innodb_plugin/include/mem0pool.h @@ -62,6 +62,13 @@ mem_pool_create( /*============*/ ulint size); /*!< in: pool size in bytes */ /********************************************************************//** +Frees a memory pool. */ +UNIV_INTERN +void +mem_pool_free( +/*==========*/ + mem_pool_t* pool); /*!< in, own: memory pool */ +/********************************************************************//** Allocates memory from a pool. NOTE: This low-level function should only be used in mem0mem.*! @return own: allocated memory buffer */ diff --git a/storage/innodb_plugin/include/os0file.h b/storage/innodb_plugin/include/os0file.h index 8535ef092c3..16568579f31 100644 --- a/storage/innodb_plugin/include/os0file.h +++ b/storage/innodb_plugin/include/os0file.h @@ -158,6 +158,7 @@ log. */ #define OS_FILE_SHARING_VIOLATION 76 #define OS_FILE_ERROR_NOT_SPECIFIED 77 #define OS_FILE_INSUFFICIENT_RESOURCE 78 +#define OS_FILE_OPERATION_ABORTED 79 /* @} */ /** Types for aio operations @{ */ @@ -620,6 +621,13 @@ os_aio_init( ulint n_write_segs, /*<! in: number of writer threads */ ulint n_slots_sync); /*<! in: number of slots in the sync aio array */ +/*********************************************************************** +Frees the asynchronous io system. */ +UNIV_INTERN +void +os_aio_free(void); +/*=============*/ + /*******************************************************************//** Requests an asynchronous i/o operation. @return TRUE if request was queued successfully, FALSE if fail */ diff --git a/storage/innodb_plugin/include/pars0pars.h b/storage/innodb_plugin/include/pars0pars.h index a7de7f2292e..fe5d76ebbb0 100644 --- a/storage/innodb_plugin/include/pars0pars.h +++ b/storage/innodb_plugin/include/pars0pars.h @@ -583,6 +583,12 @@ pars_info_get_bound_id( pars_info_t* info, /*!< in: info struct */ const char* name); /*!< in: bound id name to find */ +/******************************************************************//** +Release any resources used by the lexer. */ +UNIV_INTERN +void +pars_lexer_close(void); +/*==================*/ /** Extra information supplied for pars_sql(). */ struct pars_info_struct { diff --git a/storage/innodb_plugin/include/srv0srv.h b/storage/innodb_plugin/include/srv0srv.h index 23472bd100e..228c9f6600a 100644 --- a/storage/innodb_plugin/include/srv0srv.h +++ b/storage/innodb_plugin/include/srv0srv.h @@ -411,7 +411,7 @@ void srv_init(void); /*==========*/ /*********************************************************************//** -Frees the OS fast mutex created in srv_boot(). */ +Frees the data structures created in srv_init(). */ UNIV_INTERN void srv_free(void); diff --git a/storage/innodb_plugin/include/thr0loc.h b/storage/innodb_plugin/include/thr0loc.h index b4bdc33e615..b7eb29f2ed0 100644 --- a/storage/innodb_plugin/include/thr0loc.h +++ b/storage/innodb_plugin/include/thr0loc.h @@ -39,6 +39,12 @@ UNIV_INTERN void thr_local_init(void); /*================*/ + /****************************************************************//** +Close the thread local storage module. */ +UNIV_INTERN +void +thr_local_close(void); +/*=================*/ /*******************************************************************//** Creates a local storage struct for the calling new thread. */ UNIV_INTERN diff --git a/storage/innodb_plugin/include/trx0i_s.h b/storage/innodb_plugin/include/trx0i_s.h index 9bf032de9f9..7bd4e1b88c8 100644 --- a/storage/innodb_plugin/include/trx0i_s.h +++ b/storage/innodb_plugin/include/trx0i_s.h @@ -141,6 +141,13 @@ void trx_i_s_cache_init( /*===============*/ trx_i_s_cache_t* cache); /*!< out: cache to init */ +/*******************************************************************//** +Free the INFORMATION SCHEMA trx related cache. */ +UNIV_INTERN +void +trx_i_s_cache_free( +/*===============*/ + trx_i_s_cache_t* cache); /*!< in/out: cache to free */ /*******************************************************************//** Issue a shared/read lock on the tables cache. */ diff --git a/storage/innodb_plugin/include/trx0purge.h b/storage/innodb_plugin/include/trx0purge.h index 7812ad7eb92..908760580f6 100644 --- a/storage/innodb_plugin/include/trx0purge.h +++ b/storage/innodb_plugin/include/trx0purge.h @@ -71,6 +71,12 @@ void trx_purge_sys_create(void); /*======================*/ /********************************************************************//** +Frees the global purge system control structure. */ +UNIV_INTERN +void +trx_purge_sys_close(void); +/*======================*/ +/************************************************************************ Adds the update undo log as the first log in the history list. Removes the update undo log segment from the rseg slot if it is too big for reuse. */ UNIV_INTERN diff --git a/storage/innodb_plugin/include/trx0rseg.h b/storage/innodb_plugin/include/trx0rseg.h index dbc732651ca..ba1fc88b6c4 100644 --- a/storage/innodb_plugin/include/trx0rseg.h +++ b/storage/innodb_plugin/include/trx0rseg.h @@ -125,6 +125,13 @@ trx_rseg_create( ulint max_size, /*!< in: max size in pages */ ulint* id, /*!< out: rseg id */ mtr_t* mtr); /*!< in: mtr */ +/*************************************************************************** +Free's an instance of the rollback segment in memory. */ +UNIV_INTERN +void +trx_rseg_mem_free( +/*==============*/ + trx_rseg_t* rseg); /* in, own: instance to free */ /* Number of undo log slots in a rollback segment file copy */ diff --git a/storage/innodb_plugin/include/trx0sys.h b/storage/innodb_plugin/include/trx0sys.h index 812e8cfa0ba..a53296a06d9 100644 --- a/storage/innodb_plugin/include/trx0sys.h +++ b/storage/innodb_plugin/include/trx0sys.h @@ -334,6 +334,12 @@ void trx_sys_file_format_tag_init(void); /*==============================*/ /*****************************************************************//** +Shutdown/Close the transaction system. */ +UNIV_INTERN +void +trx_sys_close(void); +/*===============*/ +/*****************************************************************//** Get the name representation of the file format from its id. @return pointer to the name */ UNIV_INTERN diff --git a/storage/innodb_plugin/include/trx0trx.h b/storage/innodb_plugin/include/trx0trx.h index d2a59740c93..5f2c1246f37 100644 --- a/storage/innodb_plugin/include/trx0trx.h +++ b/storage/innodb_plugin/include/trx0trx.h @@ -338,9 +338,7 @@ trx_commit_step( /**********************************************************************//** Prints info about a transaction to the given file. The caller must own the -kernel mutex and must have called -innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL -or InnoDB cannot meanwhile change the info printed here. */ +kernel mutex. */ UNIV_INTERN void trx_print( diff --git a/storage/innodb_plugin/include/trx0undo.h b/storage/innodb_plugin/include/trx0undo.h index 4db10eaa92e..a084f2394b5 100644 --- a/storage/innodb_plugin/include/trx0undo.h +++ b/storage/innodb_plugin/include/trx0undo.h @@ -333,6 +333,13 @@ trx_undo_parse_discard_latest( byte* end_ptr,/*!< in: buffer end */ page_t* page, /*!< in: page or NULL */ mtr_t* mtr); /*!< in: mtr or NULL */ +/************************************************************************ +Frees an undo log memory copy. */ +UNIV_INTERN +void +trx_undo_mem_free( +/*==============*/ + trx_undo_t* undo); /* in: the undo object to be freed */ /* Types of an undo log segment */ #define TRX_UNDO_INSERT 1 /* contains undo entries for inserts */ diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index 5d0361658af..2081e136590 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MINOR 0 -#define INNODB_VERSION_BUGFIX 5 +#define INNODB_VERSION_BUGFIX 6 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; diff --git a/storage/innodb_plugin/include/usr0sess.h b/storage/innodb_plugin/include/usr0sess.h index 7638a0c69e2..2c288f7d455 100644 --- a/storage/innodb_plugin/include/usr0sess.h +++ b/storage/innodb_plugin/include/usr0sess.h @@ -44,14 +44,12 @@ sess_t* sess_open(void); /*============*/ /*********************************************************************//** -Closes a session, freeing the memory occupied by it, if it is in a state -where it should be closed. -@return TRUE if closed */ +Closes a session, freeing the memory occupied by it. */ UNIV_INTERN -ibool -sess_try_close( -/*===========*/ - sess_t* sess); /*!< in, own: session object */ +void +sess_close( +/*=======*/ + sess_t* sess); /* in, own: session object */ /* The session handle. All fields are protected by the kernel mutex */ struct sess_struct{ diff --git a/storage/innodb_plugin/lock/lock0lock.c b/storage/innodb_plugin/lock/lock0lock.c index 67b2eac7219..1fce8002bdf 100644 --- a/storage/innodb_plugin/lock/lock0lock.c +++ b/storage/innodb_plugin/lock/lock0lock.c @@ -578,6 +578,23 @@ lock_sys_create( } /*********************************************************************//** +Closes the lock system at database shutdown. */ +UNIV_INTERN +void +lock_sys_close(void) +/*================*/ +{ + if (lock_latest_err_file != NULL) { + fclose(lock_latest_err_file); + lock_latest_err_file = NULL; + } + + hash_table_free(lock_sys->rec_hash); + mem_free(lock_sys); + lock_sys = NULL; +} + +/*********************************************************************//** Gets the size of a lock struct. @return size in bytes */ UNIV_INTERN @@ -4307,11 +4324,6 @@ lock_print_info_summary( /*====================*/ FILE* file) /*!< in: file where to print */ { - /* We must protect the MySQL thd->query field with a MySQL mutex, and - because the MySQL mutex must be reserved before the kernel_mutex of - InnoDB, we call innobase_mysql_prepare_print_arbitrary_thd() here. */ - - innobase_mysql_prepare_print_arbitrary_thd(); lock_mutex_enter_kernel(); if (lock_deadlock_found) { @@ -4394,7 +4406,6 @@ loop: if (trx == NULL) { lock_mutex_exit_kernel(); - innobase_mysql_end_print_arbitrary_thd(); ut_ad(lock_validate()); @@ -4478,7 +4489,6 @@ loop: } lock_mutex_exit_kernel(); - innobase_mysql_end_print_arbitrary_thd(); mtr_start(&mtr); @@ -4489,7 +4499,6 @@ loop: load_page_first = FALSE; - innobase_mysql_prepare_print_arbitrary_thd(); lock_mutex_enter_kernel(); goto loop; diff --git a/storage/innodb_plugin/log/log0log.c b/storage/innodb_plugin/log/log0log.c index a23dd20772a..d5b696074b3 100644 --- a/storage/innodb_plugin/log/log0log.c +++ b/storage/innodb_plugin/log/log0log.c @@ -771,8 +771,6 @@ void log_init(void) /*==========*/ { - byte* buf; - log_sys = mem_alloc(sizeof(log_t)); mutex_create(&log_sys->mutex, SYNC_LOG); @@ -787,8 +785,8 @@ log_init(void) ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE); ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE); - buf = mem_alloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE); - log_sys->buf = ut_align(buf, OS_FILE_LOG_BLOCK_SIZE); + log_sys->buf_ptr = mem_alloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE); + log_sys->buf = ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE); log_sys->buf_size = LOG_BUFFER_SIZE; @@ -833,9 +831,9 @@ log_init(void) rw_lock_create(&log_sys->checkpoint_lock, SYNC_NO_ORDER_CHECK); - log_sys->checkpoint_buf - = ut_align(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE), - OS_FILE_LOG_BLOCK_SIZE); + log_sys->checkpoint_buf_ptr = mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE); + log_sys->checkpoint_buf = ut_align(log_sys->checkpoint_buf_ptr, + OS_FILE_LOG_BLOCK_SIZE); memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE); /*----------------------------*/ @@ -918,23 +916,33 @@ log_group_init( group->lsn_offset = LOG_FILE_HDR_SIZE; group->n_pending_writes = 0; + group->file_header_bufs_ptr = mem_alloc(sizeof(byte*) * n_files); group->file_header_bufs = mem_alloc(sizeof(byte*) * n_files); #ifdef UNIV_LOG_ARCHIVE + group->archive_file_header_bufs_ptr = mem_alloc( + sizeof(byte*) * n_files); group->archive_file_header_bufs = mem_alloc(sizeof(byte*) * n_files); #endif /* UNIV_LOG_ARCHIVE */ for (i = 0; i < n_files; i++) { - *(group->file_header_bufs + i) = ut_align( - mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE), + group->file_header_bufs_ptr[i] = mem_alloc( + LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE); + + group->file_header_bufs[i] = ut_align( + group->file_header_bufs_ptr[i], OS_FILE_LOG_BLOCK_SIZE); memset(*(group->file_header_bufs + i), '\0', LOG_FILE_HDR_SIZE); #ifdef UNIV_LOG_ARCHIVE - *(group->archive_file_header_bufs + i) = ut_align( - mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE), + group->archive_file_header_bufs_ptr[i] = mem_alloc( + LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE); + + group->archive_file_header_bufs[i] = ut_align( + group->archive_file_header_bufs_ptr[i], OS_FILE_LOG_BLOCK_SIZE); + memset(*(group->archive_file_header_bufs + i), '\0', LOG_FILE_HDR_SIZE); #endif /* UNIV_LOG_ARCHIVE */ @@ -947,8 +955,9 @@ log_group_init( group->archived_offset = 0; #endif /* UNIV_LOG_ARCHIVE */ - group->checkpoint_buf = ut_align( - mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE); + group->checkpoint_buf_ptr = mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE); + group->checkpoint_buf = ut_align(group->checkpoint_buf_ptr, + OS_FILE_LOG_BLOCK_SIZE); memset(group->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE); @@ -3364,4 +3373,95 @@ log_refresh_stats(void) log_sys->n_log_ios_old = log_sys->n_log_ios; log_sys->last_printout_time = time(NULL); } + +/********************************************************************** +Closes a log group. */ +static +void +log_group_close( +/*===========*/ + log_group_t* group) /* in,own: log group to close */ +{ + ulint i; + + for (i = 0; i < group->n_files; i++) { + mem_free(group->file_header_bufs_ptr[i]); +#ifdef UNIV_LOG_ARCHIVE + mem_free(group->archive_file_header_bufs_ptr[i]); +#endif /* UNIV_LOG_ARCHIVE */ + } + + mem_free(group->file_header_bufs_ptr); + mem_free(group->file_header_bufs); + +#ifdef UNIV_LOG_ARCHIVE + mem_free(group->archive_file_header_bufs_ptr); + mem_free(group->archive_file_header_bufs); +#endif /* UNIV_LOG_ARCHIVE */ + + mem_free(group->checkpoint_buf_ptr); + + mem_free(group); +} + +/********************************************************** +Shutdown the log system but do not release all the memory. */ +UNIV_INTERN +void +log_shutdown(void) +/*==============*/ +{ + log_group_t* group; + + group = UT_LIST_GET_FIRST(log_sys->log_groups); + + while (UT_LIST_GET_LEN(log_sys->log_groups) > 0) { + log_group_t* prev_group = group; + + group = UT_LIST_GET_NEXT(log_groups, group); + UT_LIST_REMOVE(log_groups, log_sys->log_groups, prev_group); + + log_group_close(prev_group); + } + + mem_free(log_sys->buf_ptr); + log_sys->buf_ptr = NULL; + log_sys->buf = NULL; + mem_free(log_sys->checkpoint_buf_ptr); + log_sys->checkpoint_buf_ptr = NULL; + log_sys->checkpoint_buf = NULL; + + os_event_free(log_sys->no_flush_event); + os_event_free(log_sys->one_flushed_event); + + rw_lock_free(&log_sys->checkpoint_lock); + + mutex_free(&log_sys->mutex); + +#ifdef UNIV_LOG_ARCHIVE + rw_lock_free(&log_sys->archive_lock); + os_event_create(log_sys->archiving_on); +#endif /* UNIV_LOG_ARCHIVE */ + +#ifdef UNIV_LOG_DEBUG + recv_sys_debug_free(); +#endif + + recv_sys_close(); +} + +/********************************************************** +Free the log system data structures. */ +UNIV_INTERN +void +log_mem_free(void) +/*==============*/ +{ + if (log_sys != NULL) { + recv_sys_mem_free(); + mem_free(log_sys); + + log_sys = NULL; + } +} #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innodb_plugin/log/log0recv.c b/storage/innodb_plugin/log/log0recv.c index 81dcc9cd4f8..ddbc71d4b71 100644 --- a/storage/innodb_plugin/log/log0recv.c +++ b/storage/innodb_plugin/log/log0recv.c @@ -69,15 +69,15 @@ UNIV_INTERN recv_sys_t* recv_sys = NULL; /** TRUE when applying redo log records during crash recovery; FALSE otherwise. Note that this is FALSE while a background thread is rolling back incomplete transactions. */ -UNIV_INTERN ibool recv_recovery_on = FALSE; +UNIV_INTERN ibool recv_recovery_on; #ifdef UNIV_LOG_ARCHIVE /** TRUE when applying redo log records from an archived log file */ -UNIV_INTERN ibool recv_recovery_from_backup_on = FALSE; +UNIV_INTERN ibool recv_recovery_from_backup_on; #endif /* UNIV_LOG_ARCHIVE */ #ifndef UNIV_HOTBACKUP /** TRUE when recv_init_crash_recovery() has been called. */ -UNIV_INTERN ibool recv_needed_recovery = FALSE; +UNIV_INTERN ibool recv_needed_recovery; # ifdef UNIV_DEBUG /** TRUE if writing to the redo log (mtr_commit) is forbidden. Protected by log_sys->mutex. */ @@ -87,7 +87,7 @@ UNIV_INTERN ibool recv_no_log_write = FALSE; /** TRUE if buf_page_is_corrupted() should check if the log sequence number (FIL_PAGE_LSN) is in the future. Initially FALSE, and set by recv_recovery_from_checkpoint_start_func(). */ -UNIV_INTERN ibool recv_lsn_checks_on = FALSE; +UNIV_INTERN ibool recv_lsn_checks_on; /** There are two conditions under which we scan the logs, the first is normal startup and the second is when we do a recovery from an @@ -97,7 +97,7 @@ startup. If we find log entries that were written after the last checkpoint we know that the server was not cleanly shutdown. We must then initialize the crash recovery environment before attempting to store these entries in the log hash table. */ -static ibool recv_log_scan_is_startup_type = FALSE; +static ibool recv_log_scan_is_startup_type; /** If the following is TRUE, the buffer pool file pages must be invalidated after recovery and no ibuf operations are allowed; this becomes TRUE if @@ -108,7 +108,7 @@ buffer pool before the pages have been recovered to the up-to-date state. TRUE means that recovery is running and no operations on the log files are allowed yet: the variable name is misleading. */ -UNIV_INTERN ibool recv_no_ibuf_operations = FALSE; +UNIV_INTERN ibool recv_no_ibuf_operations; /** TRUE when the redo log is being backed up */ # define recv_is_making_a_backup FALSE /** TRUE when recovering from a backed up redo log file */ @@ -116,30 +116,30 @@ UNIV_INTERN ibool recv_no_ibuf_operations = FALSE; #else /* !UNIV_HOTBACKUP */ # define recv_needed_recovery FALSE /** TRUE when the redo log is being backed up */ -UNIV_INTERN ibool recv_is_making_a_backup = FALSE; +UNIV_INTERN ibool recv_is_making_a_backup = FALSE; /** TRUE when recovering from a backed up redo log file */ UNIV_INTERN ibool recv_is_from_backup = FALSE; # define buf_pool_get_curr_size() (5 * 1024 * 1024) #endif /* !UNIV_HOTBACKUP */ /** The following counter is used to decide when to print info on log scan */ -static ulint recv_scan_print_counter = 0; +static ulint recv_scan_print_counter; /** The type of the previous parsed redo log record */ -static ulint recv_previous_parsed_rec_type = 999999; +static ulint recv_previous_parsed_rec_type; /** The offset of the previous parsed redo log record */ -static ulint recv_previous_parsed_rec_offset = 0; +static ulint recv_previous_parsed_rec_offset; /** The 'multi' flag of the previous parsed redo log record */ -static ulint recv_previous_parsed_rec_is_multi = 0; +static ulint recv_previous_parsed_rec_is_multi; /** Maximum page number encountered in the redo log */ -UNIV_INTERN ulint recv_max_parsed_page_no = 0; +UNIV_INTERN ulint recv_max_parsed_page_no; /** This many frames must be left free in the buffer pool when we scan the log and store the scanned log records in the buffer pool: we will use these free frames to read in pages when we start applying the log records to the database. */ -UNIV_INTERN ulint recv_n_pool_free_frames = 256; +UNIV_INTERN ulint recv_n_pool_free_frames; /** The maximum lsn we see for a page during the recovery process. If this is bigger than the lsn we are able to scan up to, that is an indication that @@ -170,7 +170,8 @@ recv_sys_create(void) return; } - recv_sys = mem_alloc(sizeof(recv_sys_t)); + recv_sys = mem_alloc(sizeof(*recv_sys)); + memset(recv_sys, 0x0, sizeof(*recv_sys)); mutex_create(&recv_sys->mutex, SYNC_RECV); @@ -179,6 +180,106 @@ recv_sys_create(void) } /********************************************************//** +Release recovery system mutexes. */ +UNIV_INTERN +void +recv_sys_close(void) +/*================*/ +{ + if (recv_sys != NULL) { + if (recv_sys->addr_hash != NULL) { + hash_table_free(recv_sys->addr_hash); + } + + if (recv_sys->heap != NULL) { + mem_heap_free(recv_sys->heap); + } + + if (recv_sys->buf != NULL) { + ut_free(recv_sys->buf); + } + + if (recv_sys->last_block_buf_start != NULL) { + mem_free(recv_sys->last_block_buf_start); + } + + mutex_free(&recv_sys->mutex); + + mem_free(recv_sys); + recv_sys = NULL; + } +} + +/********************************************************//** +Frees the recovery system memory. */ +UNIV_INTERN +void +recv_sys_mem_free(void) +/*===================*/ +{ + if (recv_sys != NULL) { + if (recv_sys->addr_hash != NULL) { + hash_table_free(recv_sys->addr_hash); + } + + if (recv_sys->heap != NULL) { + mem_heap_free(recv_sys->heap); + } + + if (recv_sys->buf != NULL) { + ut_free(recv_sys->buf); + } + + if (recv_sys->last_block_buf_start != NULL) { + mem_free(recv_sys->last_block_buf_start); + } + + mem_free(recv_sys); + recv_sys = NULL; + } +} + +/************************************************************ +Reset the state of the recovery system variables. */ +UNIV_INTERN +void +recv_sys_var_init(void) +/*===================*/ +{ + recv_lsn_checks_on = FALSE; + + recv_n_pool_free_frames = 256; + + recv_recovery_on = FALSE; + +#ifdef UNIV_LOG_ARCHIVE + recv_recovery_from_backup_on = FALSE; +#endif /* UNIV_LOG_ARCHIVE */ + + recv_needed_recovery = FALSE; + + recv_lsn_checks_on = FALSE; + + recv_log_scan_is_startup_type = FALSE; + + recv_no_ibuf_operations = FALSE; + + recv_scan_print_counter = 0; + + recv_previous_parsed_rec_type = 999999; + + recv_previous_parsed_rec_offset = 0; + + recv_previous_parsed_rec_is_multi = 0; + + recv_max_parsed_page_no = 0; + + recv_n_pool_free_frames = 256; + + recv_max_page_lsn = 0; +} + +/************************************************************ Inits the recovery system for a recovery operation. */ UNIV_INTERN void @@ -253,8 +354,8 @@ recv_sys_empty_hash(void) Frees the recovery system. */ static void -recv_sys_free(void) -/*===============*/ +recv_sys_debug_free(void) +/*=====================*/ { mutex_enter(&(recv_sys->mutex)); @@ -263,8 +364,10 @@ recv_sys_free(void) ut_free(recv_sys->buf); mem_free(recv_sys->last_block_buf_start); - recv_sys->addr_hash = NULL; + recv_sys->buf = NULL; recv_sys->heap = NULL; + recv_sys->addr_hash = NULL; + recv_sys->last_block_buf_start = NULL; mutex_exit(&(recv_sys->mutex)); } @@ -3149,7 +3252,7 @@ recv_recovery_from_checkpoint_finish(void) recv_recovery_on = FALSE; #ifndef UNIV_LOG_DEBUG - recv_sys_free(); + recv_sys_debug_free(); #endif /* Roll back any recovered data dictionary transactions, so that the data dictionary tables will be free of any locks. diff --git a/storage/innodb_plugin/mem/mem0dbg.c b/storage/innodb_plugin/mem/mem0dbg.c index a20eb2ad7d2..01eda20ec45 100644 --- a/storage/innodb_plugin/mem/mem0dbg.c +++ b/storage/innodb_plugin/mem/mem0dbg.c @@ -170,6 +170,17 @@ mem_init( mem_comm_pool = mem_pool_create(size); } + +/******************************************************************//** +Closes the memory system. */ +UNIV_INTERN +void +mem_close(void) +/*===========*/ +{ + mem_pool_free(mem_comm_pool); + mem_comm_pool = NULL; +} #endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_MEM_DEBUG diff --git a/storage/innodb_plugin/mem/mem0pool.c b/storage/innodb_plugin/mem/mem0pool.c index c8fea97a6a3..c4f8af607e0 100644 --- a/storage/innodb_plugin/mem/mem0pool.c +++ b/storage/innodb_plugin/mem/mem0pool.c @@ -261,6 +261,18 @@ mem_pool_create( } /********************************************************************//** +Frees a memory pool. */ +UNIV_INTERN +void +mem_pool_free( +/*==========*/ + mem_pool_t* pool) /*!< in, own: memory pool */ +{ + ut_free(pool->buf); + ut_free(pool); +} + +/********************************************************************//** Fills the specified free list. @return TRUE if we were able to insert a block to the free list */ static diff --git a/storage/innodb_plugin/os/os0file.c b/storage/innodb_plugin/os/os0file.c index 0cb76d1796f..37edad442db 100644 --- a/storage/innodb_plugin/os/os0file.c +++ b/storage/innodb_plugin/os/os0file.c @@ -323,6 +323,13 @@ os_file_get_last_error( "InnoDB: The error means that there are no" " sufficient system resources or quota to" " complete the operation.\n"); + } else if (err == ERROR_OPERATION_ABORTED) { + fprintf(stderr, + "InnoDB: The error means that the I/O" + " operation has been aborted\n" + "InnoDB: because of either a thread exit" + " or an application request.\n" + "InnoDB: Retry attempt is made.\n"); } else { fprintf(stderr, "InnoDB: Some operating system error numbers" @@ -347,6 +354,8 @@ os_file_get_last_error( } else if (err == ERROR_WORKING_SET_QUOTA || err == ERROR_NO_SYSTEM_RESOURCES) { return(OS_FILE_INSUFFICIENT_RESOURCE); + } else if (err == ERROR_OPERATION_ABORTED) { + return(OS_FILE_OPERATION_ABORTED); } else { return(100 + err); } @@ -469,6 +478,10 @@ os_file_handle_error_cond_exit( os_thread_sleep(100000); /* 100 ms */ return(TRUE); + } else if (err == OS_FILE_OPERATION_ABORTED) { + + os_thread_sleep(100000); /* 100 ms */ + return(TRUE); } else { if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); @@ -3029,6 +3042,34 @@ os_aio_array_create( return(array); } +/************************************************************************//** +Frees an aio wait array. */ +static +void +os_aio_array_free( +/*==============*/ + os_aio_array_t* array) /*!< in, own: array to free */ +{ +#ifdef WIN_ASYNC_IO + ulint i; + + for (i = 0; i < array->n_slots; i++) { + os_aio_slot_t* slot = os_aio_array_get_nth_slot(array, i); + os_event_free(slot->event); + } +#endif /* WIN_ASYNC_IO */ + +#ifdef __WIN__ + ut_free(array->native_events); +#endif /* __WIN__ */ + os_mutex_free(array->mutex); + os_event_free(array->not_full); + os_event_free(array->is_empty); + + ut_free(array->slots); + ut_free(array); +} + /*********************************************************************** Initializes the asynchronous io system. Creates one array each for ibuf and log i/o. Also creates one array each for read and write where each @@ -3099,6 +3140,35 @@ os_aio_init( } +/*********************************************************************** +Frees the asynchronous io system. */ +UNIV_INTERN +void +os_aio_free(void) +/*=============*/ +{ + ulint i; + + os_aio_array_free(os_aio_ibuf_array); + os_aio_ibuf_array = NULL; + os_aio_array_free(os_aio_log_array); + os_aio_log_array = NULL; + os_aio_array_free(os_aio_read_array); + os_aio_read_array = NULL; + os_aio_array_free(os_aio_write_array); + os_aio_write_array = NULL; + os_aio_array_free(os_aio_sync_array); + os_aio_sync_array = NULL; + + for (i = 0; i < os_aio_n_segments; i++) { + os_event_free(os_aio_segment_wait_events[i]); + } + + ut_free(os_aio_segment_wait_events); + os_aio_segment_wait_events = 0; + os_aio_n_segments = 0; +} + #ifdef WIN_ASYNC_IO /************************************************************************//** Wakes up all async i/o threads in the array in Windows async i/o at @@ -3709,6 +3779,7 @@ os_aio_windows_handle( ibool ret_val; BOOL ret; DWORD len; + BOOL retry = FALSE; if (segment == ULINT_UNDEFINED) { array = os_aio_sync_array; @@ -3762,14 +3833,52 @@ os_aio_windows_handle( ut_a(TRUE == os_file_flush(slot->file)); } #endif /* UNIV_DO_FLUSH */ + } else if (os_file_handle_error(slot->name, "Windows aio")) { + + retry = TRUE; } else { - os_file_handle_error(slot->name, "Windows aio"); ret_val = FALSE; } os_mutex_exit(array->mutex); + if (retry) { + /* retry failed read/write operation synchronously. + No need to hold array->mutex. */ + + switch (slot->type) { + case OS_FILE_WRITE: + ret = WriteFile(slot->file, slot->buf, + slot->len, &len, + &(slot->control)); + + break; + case OS_FILE_READ: + ret = ReadFile(slot->file, slot->buf, + slot->len, &len, + &(slot->control)); + + break; + default: + ut_error; + } + + if (!ret && GetLastError() == ERROR_IO_PENDING) { + /* aio was queued successfully! + We want a synchronous i/o operation on a + file where we also use async i/o: in Windows + we must use the same wait mechanism as for + async i/o */ + + ret = GetOverlappedResult(slot->file, + &(slot->control), + &len, TRUE); + } + + ret_val = ret && len == slot->len; + } + os_aio_array_free_slot(array, slot); return(ret_val); diff --git a/storage/innodb_plugin/os/os0sync.c b/storage/innodb_plugin/os/os0sync.c index 4ec340b72b5..60467242e14 100644 --- a/storage/innodb_plugin/os/os0sync.c +++ b/storage/innodb_plugin/os/os0sync.c @@ -86,6 +86,9 @@ os_sync_init(void) UT_LIST_INIT(os_event_list); UT_LIST_INIT(os_mutex_list); + os_sync_mutex = NULL; + os_sync_mutex_inited = FALSE; + os_sync_mutex = os_mutex_create(NULL); os_sync_mutex_inited = TRUE; @@ -713,6 +716,7 @@ os_fast_mutex_free( os_mutex_enter(os_sync_mutex); } + ut_ad(os_fast_mutex_count > 0); os_fast_mutex_count--; if (UNIV_LIKELY(os_sync_mutex_inited)) { diff --git a/storage/innodb_plugin/os/os0thread.c b/storage/innodb_plugin/os/os0thread.c index 9a2d95cb166..34818ada804 100644 --- a/storage/innodb_plugin/os/os0thread.c +++ b/storage/innodb_plugin/os/os0thread.c @@ -233,6 +233,7 @@ os_thread_exit( #ifdef __WIN__ ExitThread((DWORD)exit_value); #else + pthread_detach(pthread_self()); pthread_exit(exit_value); #endif } diff --git a/storage/innodb_plugin/pars/lexyy.c b/storage/innodb_plugin/pars/lexyy.c index 37d892e51e3..815395ea316 100644 --- a/storage/innodb_plugin/pars/lexyy.c +++ b/storage/innodb_plugin/pars/lexyy.c @@ -2778,3 +2778,16 @@ static void yyfree (void * ptr ) + +/********************************************************************** +Release any resources used by the lexer. */ +UNIV_INTERN +void +pars_lexer_close(void) +/*==================*/ +{ + yylex_destroy(); + free(stringbuf); + stringbuf = NULL; + stringbuf_len_alloc = stringbuf_len = 0; +} diff --git a/storage/innodb_plugin/pars/pars0lex.l b/storage/innodb_plugin/pars/pars0lex.l index 4abff65e98b..55ed17f82e1 100644 --- a/storage/innodb_plugin/pars/pars0lex.l +++ b/storage/innodb_plugin/pars/pars0lex.l @@ -661,3 +661,16 @@ In the state 'id', only two actions are possible (defined below). */ } %% + +/********************************************************************** +Release any resources used by the lexer. */ +UNIV_INTERN +void +pars_lexer_close(void) +/*==================*/ +{ + yylex_destroy(); + free(stringbuf); + stringbuf = NULL; + stringbuf_len_alloc = stringbuf_len = 0; +} diff --git a/storage/innodb_plugin/que/que0que.c b/storage/innodb_plugin/que/que0que.c index 54b1e7535fa..2fe046fa9b8 100644 --- a/storage/innodb_plugin/que/que0que.c +++ b/storage/innodb_plugin/que/que0que.c @@ -518,6 +518,7 @@ que_graph_free_recursive( upd_node_t* upd; tab_node_t* cre_tab; ind_node_t* cre_ind; + purge_node_t* purge; if (node == NULL) { @@ -579,6 +580,13 @@ que_graph_free_recursive( mem_heap_free(ins->entry_sys_heap); break; + case QUE_NODE_PURGE: + purge = node; + + mem_heap_free(purge->heap); + + break; + case QUE_NODE_UPDATE: upd = node; diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c index a303a2f3278..25f041c0885 100644 --- a/storage/innodb_plugin/row/row0merge.c +++ b/storage/innodb_plugin/row/row0merge.c @@ -1200,6 +1200,12 @@ row_merge_read_clustered_index( in order to release the latch on the old page. */ if (btr_pcur_is_after_last_on_page(&pcur)) { + if (UNIV_UNLIKELY(trx_is_interrupted(trx))) { + i = 0; + err = DB_INTERRUPTED; + goto err_exit; + } + btr_pcur_store_position(&pcur, &mtr); mtr_commit(&mtr); mtr_start(&mtr); @@ -1557,6 +1563,7 @@ static __attribute__((nonnull)) ulint row_merge( /*======*/ + trx_t* trx, /*!< in: transaction */ const dict_index_t* index, /*!< in: index being created */ merge_file_t* file, /*!< in/out: file containing index entries */ @@ -1590,6 +1597,10 @@ row_merge( for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) { ulint ahalf; /*!< arithmetic half the input file */ + if (UNIV_UNLIKELY(trx_is_interrupted(trx))) { + return(DB_INTERRUPTED); + } + error = row_merge_blocks(index, file, block, &foffs0, &foffs1, &of, table); @@ -1617,6 +1628,10 @@ row_merge( /* Copy the last blocks, if there are any. */ while (foffs0 < ihalf) { + if (UNIV_UNLIKELY(trx_is_interrupted(trx))) { + return(DB_INTERRUPTED); + } + if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) { return(DB_CORRUPTION); } @@ -1625,6 +1640,10 @@ row_merge( ut_ad(foffs0 == ihalf); while (foffs1 < file->offset) { + if (UNIV_UNLIKELY(trx_is_interrupted(trx))) { + return(DB_INTERRUPTED); + } + if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) { return(DB_CORRUPTION); } @@ -1653,6 +1672,7 @@ static ulint row_merge_sort( /*===========*/ + trx_t* trx, /*!< in: transaction */ const dict_index_t* index, /*!< in: index being created */ merge_file_t* file, /*!< in/out: file containing index entries */ @@ -1671,7 +1691,8 @@ row_merge_sort( do { ulint error; - error = row_merge(index, file, &half, block, tmpfd, table); + error = row_merge(trx, index, file, &half, + block, tmpfd, table); if (error != DB_SUCCESS) { return(error); @@ -2490,7 +2511,7 @@ row_merge_build_indexes( sorting and inserting. */ for (i = 0; i < n_indexes; i++) { - error = row_merge_sort(indexes[i], &merge_files[i], + error = row_merge_sort(trx, indexes[i], &merge_files[i], block, &tmpfd, table); if (error == DB_SUCCESS) { diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 540a4450045..181c39de881 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -1880,6 +1880,8 @@ err_exit: if (UNIV_UNLIKELY(err != DB_SUCCESS)) { trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, NULL); + /* TO DO: free table? The code below will dereference + table->name, though. */ } switch (err) { @@ -1898,31 +1900,6 @@ err_exit: break; case DB_DUPLICATE_KEY: - ut_print_timestamp(stderr); - fputs(" InnoDB: Error: table ", stderr); - ut_print_name(stderr, trx, TRUE, table->name); - fputs(" already exists in InnoDB internal\n" - "InnoDB: data dictionary. Have you deleted" - " the .frm file\n" - "InnoDB: and not used DROP TABLE?" - " Have you used DROP DATABASE\n" - "InnoDB: for InnoDB tables in" - " MySQL version <= 3.23.43?\n" - "InnoDB: See the Restrictions section" - " of the InnoDB manual.\n" - "InnoDB: You can drop the orphaned table" - " inside InnoDB by\n" - "InnoDB: creating an InnoDB table with" - " the same name in another\n" - "InnoDB: database and copying the .frm file" - " to the current database.\n" - "InnoDB: Then MySQL thinks the table exists," - " and DROP TABLE will\n" - "InnoDB: succeed.\n" - "InnoDB: You can look for further help from\n" - "InnoDB: " REFMAN "innodb-troubleshooting.html\n", - stderr); - /* We may also get err == DB_ERROR if the .ibd file for the table already exists */ @@ -4157,6 +4134,7 @@ row_check_table_for_mysql( } if (trx_is_interrupted(prebuilt->trx)) { + ret = DB_INTERRUPTED; break; } diff --git a/storage/innodb_plugin/srv/srv0srv.c b/storage/innodb_plugin/srv/srv0srv.c index d638b23692e..639da1ed2f3 100644 --- a/storage/innodb_plugin/srv/srv0srv.c +++ b/storage/innodb_plugin/srv/srv0srv.c @@ -1006,13 +1006,26 @@ srv_init(void) } /*********************************************************************//** -Frees the OS fast mutex created in srv_init(). */ +Frees the data structures created in srv_init(). */ UNIV_INTERN void srv_free(void) /*==========*/ { os_fast_mutex_free(&srv_conc_mutex); + mem_free(srv_conc_slots); + srv_conc_slots = NULL; + + mem_free(srv_sys->threads); + mem_free(srv_sys); + srv_sys = NULL; + + mem_free(kernel_mutex_temp); + kernel_mutex_temp = NULL; + mem_free(srv_mysql_table); + srv_mysql_table = NULL; + + trx_i_s_cache_free(trx_i_s_cache); } /*********************************************************************//** @@ -1024,6 +1037,8 @@ srv_general_init(void) /*==================*/ { ut_mem_init(); + /* Reset the system variables in the recovery module. */ + recv_sys_var_init(); os_sync_init(); sync_init(); mem_init(srv_mem_pool_size); diff --git a/storage/innodb_plugin/srv/srv0start.c b/storage/innodb_plugin/srv/srv0start.c index 796541a9f1a..d5f6120ca31 100644 --- a/storage/innodb_plugin/srv/srv0start.c +++ b/storage/innodb_plugin/srv/srv0start.c @@ -103,6 +103,7 @@ Created 2/16/1996 Heikki Tuuri # include "row0row.h" # include "row0mysql.h" # include "btr0pcur.h" +# include "thr0loc.h" # include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ /** Log sequence number immediately after startup */ @@ -495,6 +496,8 @@ io_handler_thread( mutex_exit(&ios_mutex); } + thr_local_free(os_thread_get_curr_id()); + /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. The thread actually never comes here because it is exited in an @@ -531,32 +534,6 @@ srv_normalize_path_for_win( #endif } -/*********************************************************************//** -Adds a slash or a backslash to the end of a string if it is missing -and the string is not empty. -@return string which has the separator if the string is not empty */ -UNIV_INTERN -char* -srv_add_path_separator_if_needed( -/*=============================*/ - char* str) /*!< in: null-terminated character string */ -{ - char* out_str; - ulint len = ut_strlen(str); - - if (len == 0 || str[len - 1] == SRV_PATH_SEPARATOR) { - - return(str); - } - - out_str = ut_malloc(len + 2); - memcpy(out_str, str, len); - out_str[len] = SRV_PATH_SEPARATOR; - out_str[len + 1] = 0; - - return(out_str); -} - #ifndef UNIV_HOTBACKUP /*********************************************************************//** Calculates the low 32 bits when a file size which is given as a number @@ -605,19 +582,24 @@ open_or_create_log_file( ulint size; ulint size_high; char name[10000]; + ulint dirnamelen; UT_NOT_USED(create_new_db); *log_file_created = FALSE; srv_normalize_path_for_win(srv_log_group_home_dirs[k]); - srv_log_group_home_dirs[k] = srv_add_path_separator_if_needed( - srv_log_group_home_dirs[k]); - ut_a(strlen(srv_log_group_home_dirs[k]) - < (sizeof name) - 10 - sizeof "ib_logfile"); - sprintf(name, "%s%s%lu", srv_log_group_home_dirs[k], - "ib_logfile", (ulong) i); + dirnamelen = strlen(srv_log_group_home_dirs[k]); + ut_a(dirnamelen < (sizeof name) - 10 - sizeof "ib_logfile"); + memcpy(name, srv_log_group_home_dirs[k], dirnamelen); + + /* Add a path separator if needed. */ + if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { + name[dirnamelen++] = SRV_PATH_SEPARATOR; + } + + sprintf(name + dirnamelen, "%s%lu", "ib_logfile", (ulong) i); files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_NORMAL, OS_LOG_FILE, &ret); @@ -780,14 +762,22 @@ open_or_create_data_files( *create_new_db = FALSE; srv_normalize_path_for_win(srv_data_home); - srv_data_home = srv_add_path_separator_if_needed(srv_data_home); for (i = 0; i < srv_n_data_files; i++) { + ulint dirnamelen; + srv_normalize_path_for_win(srv_data_file_names[i]); + dirnamelen = strlen(srv_data_home); - ut_a(strlen(srv_data_home) + strlen(srv_data_file_names[i]) + ut_a(dirnamelen + strlen(srv_data_file_names[i]) < (sizeof name) - 1); - sprintf(name, "%s%s", srv_data_home, srv_data_file_names[i]); + memcpy(name, srv_data_home, dirnamelen); + /* Add a path separator if needed. */ + if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { + name[dirnamelen++] = SRV_PATH_SEPARATOR; + } + + strcpy(name + dirnamelen, srv_data_file_names[i]); if (srv_data_file_is_raw_partition[i] == 0) { @@ -1009,7 +999,7 @@ skip_size_check: return(DB_SUCCESS); } -/****************************************************************//** +/******************************************************************** Starts InnoDB and creates a new database if database files are not found and the user wants. @return DB_SUCCESS or error code */ @@ -1120,7 +1110,7 @@ innobase_start_or_create_for_mysql(void) if (srv_start_has_been_called) { fprintf(stderr, - "InnoDB: Error:startup called second time" + "InnoDB: Error: startup called second time" " during the process lifetime.\n" "InnoDB: In the MySQL Embedded Server Library" " you cannot call server_init()\n" @@ -1959,8 +1949,10 @@ innobase_shutdown_for_mysql(void) /* All the threads have exited or are just exiting; NOTE that the threads may not have completed their exit yet. Should we use pthread_join() to make sure - they have exited? Now we just sleep 0.1 seconds and - hope that is enough! */ + they have exited? If we did, we would have to + remove the pthread_detach() from + os_thread_exit(). Now we just sleep 0.1 + seconds and hope that is enough! */ os_mutex_exit(os_sync_mutex); @@ -1999,37 +1991,41 @@ innobase_shutdown_for_mysql(void) srv_misc_tmpfile = 0; } + /* This must be disabled before closing the buffer pool + and closing the data dictionary. */ + btr_search_disable(); + + ibuf_close(); + log_shutdown(); + lock_sys_close(); + thr_local_close(); trx_sys_file_format_close(); + trx_sys_close(); mutex_free(&srv_monitor_file_mutex); mutex_free(&srv_dict_tmpfile_mutex); mutex_free(&srv_misc_tmpfile_mutex); + dict_close(); + btr_search_sys_free(); /* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside them */ + os_aio_free(); sync_close(); + srv_free(); + fil_close(); /* 4. Free the os_conc_mutex and all os_events and os_mutexes */ - srv_free(); os_sync_free(); - /* Check that all read views are closed except read view owned - by a purge. */ - - if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) { - fprintf(stderr, - "InnoDB: Error: all read views were not closed" - " before shutdown:\n" - "InnoDB: %lu read views open \n", - UT_LIST_GET_LEN(trx_sys->view_list) - 1); - } - - /* 5. Free all allocated memory and the os_fast_mutex created in - ut0mem.c */ + /* 5. Free all allocated memory */ + pars_lexer_close(); + log_mem_free(); buf_pool_free(); ut_free_all_mem(); + mem_close(); if (os_thread_count != 0 || os_event_count != 0 @@ -2060,6 +2056,7 @@ innobase_shutdown_for_mysql(void) } srv_was_started = FALSE; + srv_start_has_been_called = FALSE; return((int) DB_SUCCESS); } diff --git a/storage/innodb_plugin/sync/sync0arr.c b/storage/innodb_plugin/sync/sync0arr.c index d78ee8f3191..ed9e25bf2f2 100644 --- a/storage/innodb_plugin/sync/sync0arr.c +++ b/storage/innodb_plugin/sync/sync0arr.c @@ -227,24 +227,21 @@ sync_array_create( SYNC_ARRAY_MUTEX: determines the type of mutex protecting the data structure */ { + ulint sz; sync_array_t* arr; - sync_cell_t* cell_array; - sync_cell_t* cell; - ulint i; ut_a(n_cells > 0); /* Allocate memory for the data structures */ arr = ut_malloc(sizeof(sync_array_t)); + memset(arr, 0x0, sizeof(*arr)); - cell_array = ut_malloc(sizeof(sync_cell_t) * n_cells); + sz = sizeof(sync_cell_t) * n_cells; + arr->array = ut_malloc(sz); + memset(arr->array, 0x0, sz); arr->n_cells = n_cells; - arr->n_reserved = 0; - arr->array = cell_array; arr->protection = protection; - arr->sg_count = 0; - arr->res_count = 0; /* Then create the mutex to protect the wait array complex */ if (protection == SYNC_ARRAY_OS_MUTEX) { @@ -255,13 +252,6 @@ sync_array_create( ut_error; } - for (i = 0; i < n_cells; i++) { - cell = sync_array_get_nth_cell(arr, i); - cell->wait_object = NULL; - cell->waiting = FALSE; - cell->signal_count = 0; - } - return(arr); } diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 5ad143075a7..569fc6328c4 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -1377,7 +1377,12 @@ sync_close(void) mutex_free(&mutex_list_mutex); #ifdef UNIV_SYNC_DEBUG mutex_free(&sync_thread_mutex); + + /* Switch latching order checks on in sync0sync.c */ + sync_order_checks_on = FALSE; #endif /* UNIV_SYNC_DEBUG */ + + sync_initialized = FALSE; } /*******************************************************************//** diff --git a/storage/innodb_plugin/thr/thr0loc.c b/storage/innodb_plugin/thr/thr0loc.c index 49275be1d7d..59a234a6b72 100644 --- a/storage/innodb_plugin/thr/thr0loc.c +++ b/storage/innodb_plugin/thr/thr0loc.c @@ -246,3 +246,34 @@ thr_local_init(void) mutex_create(&thr_local_mutex, SYNC_THR_LOCAL); } + +/******************************************************************** +Close the thread local storage module. */ +UNIV_INTERN +void +thr_local_close(void) +/*=================*/ +{ + ulint i; + + ut_a(thr_local_hash != NULL); + + /* Free the hash elements. We don't remove them from the table + because we are going to destroy the table anyway. */ + for (i = 0; i < hash_get_n_cells(thr_local_hash); i++) { + thr_local_t* local; + + local = HASH_GET_FIRST(thr_local_hash, i); + + while (local) { + thr_local_t* prev_local = local; + + local = HASH_GET_NEXT(hash, prev_local); + ut_a(prev_local->magic_n == THR_LOCAL_MAGIC_N); + mem_free(prev_local); + } + } + + hash_table_free(thr_local_hash); + thr_local_hash = NULL; +} diff --git a/storage/innodb_plugin/trx/trx0i_s.c b/storage/innodb_plugin/trx/trx0i_s.c index 0d809806edc..1b20eaabf42 100644 --- a/storage/innodb_plugin/trx/trx0i_s.c +++ b/storage/innodb_plugin/trx/trx0i_s.c @@ -60,7 +60,7 @@ Created July 17, 2007 Vasil Dimov /** @brief The maximum number of chunks to allocate for a table cache. The rows of a table cache are stored in a set of chunks. When a new -row is added a new chunk is allocated if necessary. Assuming that the +row is added a new chunk is allocated if necessary. Assuming that the first one is 1024 rows (TABLE_CACHE_INITIAL_ROWSNUM) and each subsequent is N/2 where N is the number of rows we have allocated till now, then 39th chunk would accommodate 1677416425 rows and all chunks @@ -238,6 +238,27 @@ table_cache_init( } /*******************************************************************//** +Frees a table cache. */ +static +void +table_cache_free( +/*=============*/ + i_s_table_cache_t* table_cache) /*!< in/out: table cache */ +{ + ulint i; + + for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) { + + /* the memory is actually allocated in + table_cache_create_empty_row() */ + if (table_cache->chunks[i].base) { + mem_free(table_cache->chunks[i].base); + table_cache->chunks[i].base = NULL; + } + } +} + +/*******************************************************************//** Returns an empty row from a table cache. The row is allocated if no more empty rows are available. The number of used rows is incremented. If the memory limit is hit then NULL is returned and nothing is @@ -1184,9 +1205,6 @@ trx_i_s_possibly_fetch_data_into_cache( return(1); } - /* We are going to access trx->query in all transactions */ - innobase_mysql_prepare_print_arbitrary_thd(); - /* We need to read trx_sys and record/table lock queues */ mutex_enter(&kernel_mutex); @@ -1194,8 +1212,6 @@ trx_i_s_possibly_fetch_data_into_cache( mutex_exit(&kernel_mutex); - innobase_mysql_end_print_arbitrary_thd(); - return(0); } @@ -1252,6 +1268,22 @@ trx_i_s_cache_init( } /*******************************************************************//** +Free the INFORMATION SCHEMA trx related cache. */ +UNIV_INTERN +void +trx_i_s_cache_free( +/*===============*/ + trx_i_s_cache_t* cache) /*!< in, own: cache to free */ +{ + hash_table_free(cache->locks_hash); + ha_storage_free(cache->storage); + table_cache_free(&cache->innodb_trx); + table_cache_free(&cache->innodb_locks); + table_cache_free(&cache->innodb_lock_waits); + memset(cache, 0, sizeof *cache); +} + +/*******************************************************************//** Issue a shared/read lock on the tables cache. */ UNIV_INTERN void diff --git a/storage/innodb_plugin/trx/trx0purge.c b/storage/innodb_plugin/trx/trx0purge.c index cd79fd1c315..abbfa3d7f81 100644 --- a/storage/innodb_plugin/trx/trx0purge.c +++ b/storage/innodb_plugin/trx/trx0purge.c @@ -249,6 +249,44 @@ trx_purge_sys_create(void) purge_sys->heap); } +/************************************************************************ +Frees the global purge system control structure. */ +UNIV_INTERN +void +trx_purge_sys_close(void) +/*======================*/ +{ + ut_ad(!mutex_own(&kernel_mutex)); + + que_graph_free(purge_sys->query); + + ut_a(purge_sys->sess->trx->is_purge); + purge_sys->sess->trx->conc_state = TRX_NOT_STARTED; + sess_close(purge_sys->sess); + purge_sys->sess = NULL; + + if (purge_sys->view != NULL) { + /* Because acquiring the kernel mutex is a pre-condition + of read_view_close(). We don't really need it here. */ + mutex_enter(&kernel_mutex); + + read_view_close(purge_sys->view); + purge_sys->view = NULL; + + mutex_exit(&kernel_mutex); + } + + trx_undo_arr_free(purge_sys->arr); + + rw_lock_free(&purge_sys->latch); + mutex_free(&purge_sys->mutex); + + mem_heap_free(purge_sys->heap); + mem_free(purge_sys); + + purge_sys = NULL; +} + /*================ UNDO LOG HISTORY LIST =============================*/ /********************************************************************//** diff --git a/storage/innodb_plugin/trx/trx0rseg.c b/storage/innodb_plugin/trx/trx0rseg.c index 580762e8716..8d754788e2a 100644 --- a/storage/innodb_plugin/trx/trx0rseg.c +++ b/storage/innodb_plugin/trx/trx0rseg.c @@ -132,6 +132,49 @@ trx_rseg_header_create( } /***********************************************************************//** +Free's an instance of the rollback segment in memory. */ +UNIV_INTERN +void +trx_rseg_mem_free( +/*==============*/ + trx_rseg_t* rseg) /* in, own: instance to free */ +{ + trx_undo_t* undo; + + mutex_free(&rseg->mutex); + + /* There can't be any active transactions. */ + ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0); + ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0); + + undo = UT_LIST_GET_FIRST(rseg->update_undo_cached); + + while (undo != NULL) { + trx_undo_t* prev_undo = undo; + + undo = UT_LIST_GET_NEXT(undo_list, undo); + UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, prev_undo); + + trx_undo_mem_free(prev_undo); + } + + undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached); + + while (undo != NULL) { + trx_undo_t* prev_undo = undo; + + undo = UT_LIST_GET_NEXT(undo_list, undo); + UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, prev_undo); + + trx_undo_mem_free(prev_undo); + } + + trx_sys_set_nth_rseg(trx_sys, rseg->id, NULL); + + mem_free(rseg); +} + +/*************************************************************************** Creates and initializes a rollback segment object. The values for the fields are read from the header. The object is inserted to the rseg list of the trx system object and a pointer is inserted in the rseg diff --git a/storage/innodb_plugin/trx/trx0sys.c b/storage/innodb_plugin/trx/trx0sys.c index ef10119587d..79e5af1c677 100644 --- a/storage/innodb_plugin/trx/trx0sys.c +++ b/storage/innodb_plugin/trx/trx0sys.c @@ -40,6 +40,7 @@ Created 3/26/1996 Heikki Tuuri #include "trx0purge.h" #include "log0log.h" #include "os0file.h" +#include "read0read.h" /** The file format tag structure with id and name. */ struct file_format_struct { @@ -1533,3 +1534,80 @@ trx_sys_file_format_id_to_name( } #endif /* !UNIV_HOTBACKUP */ + +/********************************************************************* +Shutdown/Close the transaction system. */ +UNIV_INTERN +void +trx_sys_close(void) +/*===============*/ +{ + trx_rseg_t* rseg; + read_view_t* view; + + ut_ad(trx_sys != NULL); + + /* Check that all read views are closed except read view owned + by a purge. */ + + if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) { + fprintf(stderr, + "InnoDB: Error: all read views were not closed" + " before shutdown:\n" + "InnoDB: %lu read views open \n", + UT_LIST_GET_LEN(trx_sys->view_list) - 1); + } + + sess_close(trx_dummy_sess); + trx_dummy_sess = NULL; + + trx_purge_sys_close(); + + mutex_enter(&kernel_mutex); + + /* Free the double write data structures. */ + ut_a(trx_doublewrite != NULL); + ut_free(trx_doublewrite->write_buf_unaligned); + trx_doublewrite->write_buf_unaligned = NULL; + + mem_free(trx_doublewrite->buf_block_arr); + trx_doublewrite->buf_block_arr = NULL; + + mutex_free(&trx_doublewrite->mutex); + mem_free(trx_doublewrite); + trx_doublewrite = NULL; + + /* There can't be any active transactions. */ + rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); + + while (rseg != NULL) { + trx_rseg_t* prev_rseg = rseg; + + rseg = UT_LIST_GET_NEXT(rseg_list, prev_rseg); + UT_LIST_REMOVE(rseg_list, trx_sys->rseg_list, prev_rseg); + + trx_rseg_mem_free(prev_rseg); + } + + view = UT_LIST_GET_FIRST(trx_sys->view_list); + + while (view != NULL) { + read_view_t* prev_view = view; + + view = UT_LIST_GET_NEXT(view_list, prev_view); + + /* Views are allocated from the trx_sys->global_read_view_heap. + So, we simply remove the element here. */ + UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view); + } + + ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == 0); + ut_a(UT_LIST_GET_LEN(trx_sys->rseg_list) == 0); + ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0); + ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0); + + mem_free(trx_sys); + + trx_sys = NULL; + mutex_exit(&kernel_mutex); +} diff --git a/storage/innodb_plugin/trx/trx0trx.c b/storage/innodb_plugin/trx/trx0trx.c index 21ba6e481a7..0951b98b79f 100644 --- a/storage/innodb_plugin/trx/trx0trx.c +++ b/storage/innodb_plugin/trx/trx0trx.c @@ -1636,9 +1636,7 @@ trx_mark_sql_stat_end( /**********************************************************************//** Prints info about a transaction to the given file. The caller must own the -kernel mutex and must have called -innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL -or InnoDB cannot meanwhile change the info printed here. */ +kernel mutex. */ UNIV_INTERN void trx_print( diff --git a/storage/innodb_plugin/trx/trx0undo.c b/storage/innodb_plugin/trx/trx0undo.c index 9af96f14526..3bb1b1cdf6c 100644 --- a/storage/innodb_plugin/trx/trx0undo.c +++ b/storage/innodb_plugin/trx/trx0undo.c @@ -1522,7 +1522,7 @@ trx_undo_mem_init_for_reuse( /********************************************************************//** Frees an undo log memory copy. */ -static +UNIV_INTERN void trx_undo_mem_free( /*==============*/ diff --git a/storage/innodb_plugin/usr/usr0sess.c b/storage/innodb_plugin/usr/usr0sess.c index 990991a2c06..8087dcb4170 100644 --- a/storage/innodb_plugin/usr/usr0sess.c +++ b/storage/innodb_plugin/usr/usr0sess.c @@ -32,14 +32,6 @@ Created 6/25/1996 Heikki Tuuri #include "trx0trx.h" /*********************************************************************//** -Closes a session, freeing the memory occupied by it. */ -static -void -sess_close( -/*=======*/ - sess_t* sess); /*!< in, own: session object */ - -/*********************************************************************//** Opens a session. @return own: session object */ UNIV_INTERN @@ -64,35 +56,16 @@ sess_open(void) /*********************************************************************//** Closes a session, freeing the memory occupied by it. */ -static +UNIV_INTERN void sess_close( /*=======*/ sess_t* sess) /*!< in, own: session object */ { - ut_ad(mutex_own(&kernel_mutex)); - ut_ad(sess->trx == NULL); - - mem_free(sess); -} - -/*********************************************************************//** -Closes a session, freeing the memory occupied by it, if it is in a state -where it should be closed. -@return TRUE if closed */ -UNIV_INTERN -ibool -sess_try_close( -/*===========*/ - sess_t* sess) /*!< in, own: session object */ -{ - ut_ad(mutex_own(&kernel_mutex)); + ut_ad(!mutex_own(&kernel_mutex)); - if (UT_LIST_GET_LEN(sess->graphs) == 0) { - sess_close(sess); + ut_a(UT_LIST_GET_LEN(sess->graphs) == 0); - return(TRUE); - } - - return(FALSE); + trx_free_for_background(sess->trx); + mem_free(sess); } diff --git a/storage/innodb_plugin/ut/ut0mem.c b/storage/innodb_plugin/ut/ut0mem.c index edb63c95700..35a325b9ccd 100644 --- a/storage/innodb_plugin/ut/ut0mem.c +++ b/storage/innodb_plugin/ut/ut0mem.c @@ -433,6 +433,8 @@ ut_free_all_mem(void) " total allocated memory is %lu\n", (ulong) ut_total_allocated_memory); } + + ut_mem_block_list_inited = FALSE; } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c index 0a2847be514..492261c5efc 100644 --- a/storage/myisam/ft_boolean_search.c +++ b/storage/myisam/ft_boolean_search.c @@ -475,8 +475,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) int i; FTB_WORD *ftbw; - if ((ftb->state != READY && ftb->state !=INDEX_DONE) || - ftb->keynr == NO_SUCH_KEY) + if (ftb->state == UNINITIALIZED || ftb->keynr == NO_SUCH_KEY) return; ftb->state=INDEX_SEARCH; diff --git a/vio/vio.c b/vio/vio.c index fd8e2e5a402..4253651bf84 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -62,10 +62,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->timeout=vio_win32_timeout; /* Set default timeout */ - vio->read_timeout_millis = INFINITE; - vio->write_timeout_millis = INFINITE; - - memset(&(vio->pipe_overlapped), 0, sizeof(OVERLAPPED)); + vio->read_timeout_ms= INFINITE; + vio->write_timeout_ms= INFINITE; vio->pipe_overlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL); DBUG_VOID_RETURN; } @@ -90,8 +88,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type, /* Currently, shared memory is on Windows only, hence the below is ok*/ vio->timeout= vio_win32_timeout; /* Set default timeout */ - vio->read_timeout_millis= INFINITE; - vio->write_timeout_millis= INFINITE; + vio->read_timeout_ms= INFINITE; + vio->write_timeout_ms= INFINITE; DBUG_VOID_RETURN; } #endif @@ -115,22 +113,20 @@ static void vio_init(Vio* vio, enum enum_vio_type type, DBUG_VOID_RETURN; } #endif /* HAVE_OPENSSL */ - { - vio->viodelete =vio_delete; - vio->vioerrno =vio_errno; - vio->read= (flags & VIO_BUFFERED_READ) ? vio_read_buff : vio_read; - vio->write =vio_write; - vio->fastsend =vio_fastsend; - vio->viokeepalive =vio_keepalive; - vio->should_retry =vio_should_retry; - vio->was_interrupted=vio_was_interrupted; - vio->vioclose =vio_close; - vio->peer_addr =vio_peer_addr; - vio->in_addr =vio_in_addr; - vio->vioblocking =vio_blocking; - vio->is_blocking =vio_is_blocking; - vio->timeout =vio_timeout; - } + vio->viodelete =vio_delete; + vio->vioerrno =vio_errno; + vio->read= (flags & VIO_BUFFERED_READ) ? vio_read_buff : vio_read; + vio->write =vio_write; + vio->fastsend =vio_fastsend; + vio->viokeepalive =vio_keepalive; + vio->should_retry =vio_should_retry; + vio->was_interrupted=vio_was_interrupted; + vio->vioclose =vio_close; + vio->peer_addr =vio_peer_addr; + vio->in_addr =vio_in_addr; + vio->vioblocking =vio_blocking; + vio->is_blocking =vio_is_blocking; + vio->timeout =vio_timeout; DBUG_VOID_RETURN; } diff --git a/vio/viosocket.c b/vio/viosocket.c index c929cac2a05..f73b890c697 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -415,14 +415,14 @@ void vio_timeout(Vio *vio, uint which, uint timeout) /* Finish pending IO on pipe. Honor wait timeout */ -static int pipe_complete_io(Vio* vio, char* buf, size_t size, DWORD timeout_millis) +static size_t pipe_complete_io(Vio* vio, char* buf, size_t size, DWORD timeout_ms) { DWORD length; DWORD ret; DBUG_ENTER("pipe_complete_io"); - ret= WaitForSingleObject(vio->pipe_overlapped.hEvent, timeout_millis); + ret= WaitForSingleObject(vio->pipe_overlapped.hEvent, timeout_ms); /* WaitForSingleObjects will normally return WAIT_OBJECT_O (success, IO completed) or WAIT_TIMEOUT. @@ -431,14 +431,14 @@ static int pipe_complete_io(Vio* vio, char* buf, size_t size, DWORD timeout_mill { CancelIo(vio->hPipe); DBUG_PRINT("error",("WaitForSingleObject() returned %d", ret)); - DBUG_RETURN(-1); + DBUG_RETURN((size_t)-1); } if (!GetOverlappedResult(vio->hPipe,&(vio->pipe_overlapped),&length, FALSE)) { DBUG_PRINT("error",("GetOverlappedResult() returned last error %d", GetLastError())); - DBUG_RETURN(-1); + DBUG_RETURN((size_t)-1); } DBUG_RETURN(length); @@ -448,49 +448,58 @@ static int pipe_complete_io(Vio* vio, char* buf, size_t size, DWORD timeout_mill size_t vio_read_pipe(Vio * vio, uchar *buf, size_t size) { DWORD bytes_read; + size_t retval; DBUG_ENTER("vio_read_pipe"); DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %u", vio->sd, (long) buf, (uint) size)); - if (!ReadFile(vio->hPipe, buf, (DWORD)size, &bytes_read, + if (ReadFile(vio->hPipe, buf, (DWORD)size, &bytes_read, &(vio->pipe_overlapped))) { + retval= bytes_read; + } + else + { if (GetLastError() != ERROR_IO_PENDING) { DBUG_PRINT("error",("ReadFile() returned last error %d", GetLastError())); DBUG_RETURN((size_t)-1); } - bytes_read= pipe_complete_io(vio, buf, size,vio->read_timeout_millis); + retval= pipe_complete_io(vio, buf, size,vio->read_timeout_ms); } - DBUG_PRINT("exit", ("%d", bytes_read)); - DBUG_RETURN(bytes_read); + DBUG_PRINT("exit", ("%lld", (longlong)retval)); + DBUG_RETURN(retval); } size_t vio_write_pipe(Vio * vio, const uchar* buf, size_t size) { DWORD bytes_written; + size_t retval; DBUG_ENTER("vio_write_pipe"); DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %u", vio->sd, (long) buf, (uint) size)); - if (!WriteFile(vio->hPipe, buf, (DWORD)size, &bytes_written, + if (WriteFile(vio->hPipe, buf, (DWORD)size, &bytes_written, &(vio->pipe_overlapped))) { + retval= bytes_written; + } + else + { if (GetLastError() != ERROR_IO_PENDING) { DBUG_PRINT("vio_error",("WriteFile() returned last error %d", GetLastError())); DBUG_RETURN((size_t)-1); } - bytes_written = pipe_complete_io(vio, (char *)buf, size, - vio->write_timeout_millis); + retval= pipe_complete_io(vio, (char *)buf, size, vio->write_timeout_ms); } - DBUG_PRINT("exit", ("%d", bytes_written)); - DBUG_RETURN(bytes_written); + DBUG_PRINT("exit", ("%lld", (longlong)retval)); + DBUG_RETURN(retval); } @@ -515,21 +524,21 @@ int vio_close_pipe(Vio * vio) void vio_win32_timeout(Vio *vio, uint which , uint timeout_sec) { - DWORD timeout_millis; + DWORD timeout_ms; /* Windows is measuring timeouts in milliseconds. Check for possible int overflow. */ if (timeout_sec > UINT_MAX/1000) - timeout_millis= INFINITE; + timeout_ms= INFINITE; else - timeout_millis= timeout_sec * 1000; + timeout_ms= timeout_sec * 1000; /* which == 1 means "write", which == 0 means "read".*/ if(which) - vio->write_timeout_millis= timeout_millis; + vio->write_timeout_ms= timeout_ms; else - vio->read_timeout_millis= timeout_millis; + vio->read_timeout_ms= timeout_ms; } @@ -564,7 +573,7 @@ size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size) WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail. We can't read anything */ if (WaitForMultipleObjects(array_elements(events), events, FALSE, - vio->read_timeout_millis) != WAIT_OBJECT_0) + vio->read_timeout_ms) != WAIT_OBJECT_0) { DBUG_RETURN(-1); }; @@ -621,7 +630,7 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size) while (remain != 0) { if (WaitForMultipleObjects(array_elements(events), events, FALSE, - vio->write_timeout_millis) != WAIT_OBJECT_0) + vio->write_timeout_ms) != WAIT_OBJECT_0) { DBUG_RETURN((size_t) -1); } diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 51d049b18b9..d0a0a69f70b 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -19,7 +19,6 @@ static my_bool ssl_algorithms_added = FALSE; static my_bool ssl_error_strings_loaded= FALSE; -static int verify_depth = 0; static unsigned char dh512_p[]= { |