From 344cd04b1ec15b8ccea834381b4668f86d6822d5 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 29 Sep 2009 09:55:53 -0300 Subject: [PATCH 1/4] Bug#41728: Dropped symbol but no soname change Restore a stub of the removed mysql_odbc_escape_string function to fix a ABI breakage. The function was intended to be private and used only by Connector/ODBC, but, unfortunately, it was exported as part of the ABI. Nonetheless, only a stub is restored as the original function is inherently broken and shouldn't be used. This restoration only applies to MySQL 5.0. This will be addressed differently in later versions -- reworked library versioning. --- include/mysql.h | 10 +++ include/mysql_h.ic | 184 ++++++++++++++++++++-------------------- libmysql/libmysql.c | 12 +++ libmysql/libmysql.def | 1 + libmysqld/libmysqld.def | 1 + 5 files changed, 117 insertions(+), 91 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index f2303abb241..b3e0dc45496 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -550,6 +550,16 @@ 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.ic b/include/mysql_h.ic index 1d4f3ce2758..2ad8121fbc7 100644 --- a/include/mysql_h.ic +++ b/include/mysql_h.ic @@ -40,7 +40,7 @@ typedef struct st_list LIST; typedef struct st_mem_root MEM_ROOT; # 255 "mysql.h" typedef struct st_mysql MYSQL; -# 647 "mysql.h" +# 657 "mysql.h" typedef struct st_mysql_bind MYSQL_BIND; # 97 "mysql.h" typedef struct st_mysql_field MYSQL_FIELD; @@ -56,7 +56,7 @@ typedef struct st_mysql_res MYSQL_RES; typedef char * * MYSQL_ROW; # 144 "mysql.h" typedef MYSQL_ROWS * MYSQL_ROW_OFFSET; -# 675 "mysql.h" +# 685 "mysql.h" typedef struct st_mysql_stmt MYSQL_STMT; # 240 "mysql.h" typedef struct character_set MY_CHARSET_INFO; @@ -80,7 +80,7 @@ typedef unsigned long long int my_ulonglong; typedef struct embedded_query_result EMBEDDED_QUERY_RESULT; # 149 "mysql.h" typedef struct st_mysql_data MYSQL_DATA; -# 744 "mysql.h" +# 754 "mysql.h" typedef struct st_mysql_methods MYSQL_METHODS; # 47 "mysql_time.h" typedef struct st_mysql_time MYSQL_TIME; @@ -173,7 +173,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned void * thd; my_bool * unbuffered_fetch_owner; }; -# 647 "mysql.h" +# 657 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_bind { unsigned long int * length; @@ -246,7 +246,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned int net_buf_size; char last_error[256]; }; -# 744 "mysql.h" +# 754 "mysql.h" struct __attribute__((aligned(__alignof__(void *)))) st_mysql_methods { my_bool (* read_query_result)(MYSQL * mysql); @@ -340,7 +340,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned MYSQL_ROW data; unsigned long int length; }; -# 675 "mysql.h" +# 685 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long long int)))) st_mysql_stmt { MEM_ROOT mem_root; @@ -508,7 +508,7 @@ enum enum_mysql_set_option MYSQL_OPTION_MULTI_STATEMENTS_ON = 0, MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1, }; -# 577 "mysql.h" +# 587 "mysql.h" enum enum_mysql_stmt_state { MYSQL_STMT_INIT_DONE = 1, @@ -559,7 +559,7 @@ enum enum_server_command COM_STMT_FETCH = 28, COM_END = 29, }; -# 721 "mysql.h" +# 731 "mysql.h" enum enum_stmt_attr_type { STMT_ATTR_UPDATE_MAX_LENGTH = 0, @@ -627,25 +627,25 @@ enum mysql_status MYSQL_STATUS_GET_RESULT = 1, MYSQL_STATUS_USE_RESULT = 2, }; -# 427 "mysql_com.h" +# 431 "mysql_com.h" extern my_bool check_scramble(char const * reply, char const * message, unsigned char const * hash_stage2); -# 420 "mysql_com.h" +# 424 "mysql_com.h" extern my_bool check_scramble_323(char const *, char const * message, unsigned long int * salt); # 32 "typelib.h" extern TYPELIB * copy_typelib(MEM_ROOT * root, TYPELIB * from); -# 415 "mysql_com.h" +# 419 "mysql_com.h" extern void create_random_string(char * to, unsigned int, struct rand_struct * rand_st); # 29 "typelib.h" extern int find_type(char * x, TYPELIB * typelib, unsigned int); -# 429 "mysql_com.h" +# 433 "mysql_com.h" extern void get_salt_from_password(unsigned char * res, char const * password); -# 422 "mysql_com.h" +# 426 "mysql_com.h" extern void get_salt_from_password_323(unsigned long int * res, char const * password); -# 435 "mysql_com.h" +# 439 "mysql_com.h" extern char * get_tty_password(char * opt_message); # 31 "typelib.h" extern char const * get_type(TYPELIB * typelib, unsigned int); -# 417 "mysql_com.h" +# 421 "mysql_com.h" extern void hash_password(unsigned long int * to, char const * password, unsigned int); # 30 "my_list.h" extern LIST * list_add(LIST * root, LIST * element); @@ -661,23 +661,23 @@ extern unsigned int list_length(LIST *); extern LIST * list_reverse(LIST * root); # 36 "my_list.h" extern int list_walk(LIST *, list_walk_action, gptr); -# 444 "mysql_com.h" +# 448 "mysql_com.h" extern int load_defaults(char const * conf_file, char const * * groups, int * argc, char * * * argv); -# 430 "mysql_com.h" +# 434 "mysql_com.h" extern void make_password_from_salt(char * to, unsigned char const * hash_stage2); -# 423 "mysql_com.h" +# 427 "mysql_com.h" extern void make_password_from_salt_323(char * to, unsigned long int const * salt); -# 425 "mysql_com.h" +# 429 "mysql_com.h" extern void make_scrambled_password(char * to, char const * password); -# 418 "mysql_com.h" +# 422 "mysql_com.h" extern void make_scrambled_password_323(char * to, char const * password); # 30 "typelib.h" extern void make_type(char * to, unsigned int, TYPELIB * typelib); -# 441 "mysql_com.h" +# 445 "mysql_com.h" extern int modify_defaults_file(char const * file_location, char const * option, char const * option_value, char const * section_name, int); # 358 "mysql_com.h" extern int my_connect(my_socket, struct sockaddr const * name, unsigned int, unsigned int); -# 440 "mysql_com.h" +# 444 "mysql_com.h" extern my_bool my_init(void); # 335 "mysql_com.h" extern my_bool my_net_init(NET * net, Vio * vio); @@ -687,27 +687,27 @@ extern void my_net_local_init(NET * net); extern unsigned long int my_net_read(NET * net); # 341 "mysql_com.h" extern my_bool my_net_write(NET * net, char const * packet, unsigned long int); -# 414 "mysql_com.h" +# 418 "mysql_com.h" extern double my_rnd(struct rand_struct *); -# 447 "mysql_com.h" +# 451 "mysql_com.h" extern void my_thread_end(void); -# 446 "mysql_com.h" +# 450 "mysql_com.h" extern my_bool my_thread_init(void); -# 553 "mysql.h" +# 563 "mysql.h" extern void myodbc_remove_escape(MYSQL * mysql, char * name); # 505 "mysql.h" extern int mysql_add_slave(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); # 414 "mysql.h" extern my_ulonglong mysql_affected_rows(MYSQL * mysql); -# 817 "mysql.h" +# 827 "mysql.h" extern my_bool mysql_autocommit(MYSQL * mysql, my_bool); # 430 "mysql.h" extern my_bool mysql_change_user(MYSQL * mysql, char const * user, char const * passwd, char const * db); # 422 "mysql.h" extern char const * mysql_character_set_name(MYSQL * mysql); -# 820 "mysql.h" +# 830 "mysql.h" extern void mysql_close(MYSQL * sock); -# 815 "mysql.h" +# 825 "mysql.h" extern my_bool mysql_commit(MYSQL * mysql); # 534 "mysql.h" extern void mysql_data_seek(MYSQL_RES * result, my_ulonglong); @@ -719,7 +719,7 @@ extern void mysql_disable_reads_from_master(MYSQL * mysql); extern void mysql_disable_rpl_parse(MYSQL * mysql); # 513 "mysql.h" extern int mysql_dump_debug_info(MYSQL * mysql); -# 555 "mysql.h" +# 565 "mysql.h" extern my_bool mysql_embedded(void); # 490 "mysql.h" extern void mysql_enable_reads_from_master(MYSQL * mysql); @@ -729,7 +729,7 @@ extern void mysql_enable_rpl_parse(MYSQL * mysql); extern my_bool mysql_eof(MYSQL_RES * res); # 416 "mysql.h" extern unsigned int mysql_errno(MYSQL * mysql); -# 436 "mysql_com.h" +# 440 "mysql_com.h" extern char const * mysql_errno_to_sqlstate(unsigned int); # 417 "mysql.h" extern char const * mysql_error(MYSQL * mysql); @@ -789,28 +789,30 @@ extern MYSQL_RES * mysql_list_fields(MYSQL * mysql, char const * table, char con extern MYSQL_RES * mysql_list_processes(MYSQL * mysql); # 529 "mysql.h" extern MYSQL_RES * mysql_list_tables(MYSQL * mysql, char const * wild); -# 562 "mysql.h" +# 572 "mysql.h" extern void mysql_manager_close(MYSQL_MANAGER * con); -# 563 "mysql.h" +# 573 "mysql.h" extern int mysql_manager_command(MYSQL_MANAGER * con, char const * cmd, int); -# 557 "mysql.h" +# 567 "mysql.h" extern MYSQL_MANAGER * mysql_manager_connect(MYSQL_MANAGER * con, char const * host, char const * user, char const * passwd, unsigned int); -# 565 "mysql.h" +# 575 "mysql.h" extern int mysql_manager_fetch_line(MYSQL_MANAGER * con, char * res_buf, int); -# 556 "mysql.h" +# 566 "mysql.h" extern MYSQL_MANAGER * mysql_manager_init(MYSQL_MANAGER * con); # 449 "mysql.h" extern my_bool mysql_master_query(MYSQL * mysql, char const * q, unsigned long int); # 451 "mysql.h" extern my_bool mysql_master_send_query(MYSQL * mysql, char const * q, unsigned long int); -# 818 "mysql.h" +# 828 "mysql.h" extern my_bool mysql_more_results(MYSQL * mysql); -# 819 "mysql.h" +# 829 "mysql.h" extern int mysql_next_result(MYSQL * mysql); # 405 "mysql.h" extern unsigned int mysql_num_fields(MYSQL_RES * res); # 404 "mysql.h" extern my_ulonglong mysql_num_rows(MYSQL_RES * res); +# 553 "mysql.h" +extern char * mysql_odbc_escape_string(MYSQL * mysql, char * to, unsigned long int, char const * from, unsigned long int, void * param, char * (* extend_buffer)(void *, char * to, unsigned long int * length)); # 531 "mysql.h" extern int mysql_options(MYSQL * mysql, enum mysql_option, char const * arg); # 520 "mysql.h" @@ -819,7 +821,7 @@ extern int mysql_ping(MYSQL * mysql); extern unsigned int mysql_port; # 440 "mysql.h" extern int mysql_query(MYSQL * mysql, char const * q); -# 568 "mysql.h" +# 578 "mysql.h" extern my_bool mysql_read_query_result(MYSQL * mysql); # 493 "mysql.h" extern my_bool mysql_reads_from_master_enabled(MYSQL * mysql); @@ -831,7 +833,7 @@ extern unsigned long int mysql_real_escape_string(MYSQL * mysql, char * to, char extern int mysql_real_query(MYSQL * mysql, char const * q, unsigned long int); # 514 "mysql.h" extern int mysql_refresh(MYSQL * mysql, unsigned int); -# 816 "mysql.h" +# 826 "mysql.h" extern my_bool mysql_rollback(MYSQL * mysql); # 536 "mysql.h" extern MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES * result, MYSQL_ROW_OFFSET); @@ -873,59 +875,59 @@ extern char const * mysql_sqlstate(MYSQL * mysql); extern my_bool mysql_ssl_set(MYSQL * mysql, char const * key, char const * cert, char const * ca, char const * capath, char const * cipher); # 521 "mysql.h" extern char const * mysql_stat(MYSQL * mysql); -# 811 "mysql.h" +# 821 "mysql.h" extern my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT * stmt); -# 789 "mysql.h" +# 799 "mysql.h" extern my_bool mysql_stmt_attr_get(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void * attr); -# 786 "mysql.h" -extern my_bool mysql_stmt_attr_set(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void const * attr); -# 792 "mysql.h" -extern my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); -# 793 "mysql.h" -extern my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); -# 794 "mysql.h" -extern my_bool mysql_stmt_close(MYSQL_STMT * stmt); -# 809 "mysql.h" -extern void mysql_stmt_data_seek(MYSQL_STMT * stmt, my_ulonglong); -# 803 "mysql.h" -extern unsigned int mysql_stmt_errno(MYSQL_STMT * stmt); -# 804 "mysql.h" -extern char const * mysql_stmt_error(MYSQL_STMT * stmt); -# 779 "mysql.h" -extern int mysql_stmt_execute(MYSQL_STMT * stmt); -# 780 "mysql.h" -extern int mysql_stmt_fetch(MYSQL_STMT * stmt); -# 781 "mysql.h" -extern int mysql_stmt_fetch_column(MYSQL_STMT * stmt, MYSQL_BIND * bind_arg, unsigned int, unsigned long int); -# 813 "mysql.h" -extern unsigned int mysql_stmt_field_count(MYSQL_STMT * stmt); # 796 "mysql.h" -extern my_bool mysql_stmt_free_result(MYSQL_STMT * stmt); -# 776 "mysql.h" -extern MYSQL_STMT * mysql_stmt_init(MYSQL * mysql); -# 812 "mysql.h" -extern my_ulonglong mysql_stmt_insert_id(MYSQL_STMT * stmt); -# 810 "mysql.h" -extern my_ulonglong mysql_stmt_num_rows(MYSQL_STMT * stmt); -# 785 "mysql.h" -extern unsigned long int mysql_stmt_param_count(MYSQL_STMT * stmt); +extern my_bool mysql_stmt_attr_set(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void const * attr); # 802 "mysql.h" -extern MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT * stmt); -# 777 "mysql.h" -extern int mysql_stmt_prepare(MYSQL_STMT * stmt, char const * query, unsigned long int); -# 795 "mysql.h" -extern my_bool mysql_stmt_reset(MYSQL_STMT * stmt); -# 801 "mysql.h" -extern MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT * stmt); +extern my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +# 803 "mysql.h" +extern my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +# 804 "mysql.h" +extern my_bool mysql_stmt_close(MYSQL_STMT * stmt); +# 819 "mysql.h" +extern void mysql_stmt_data_seek(MYSQL_STMT * stmt, my_ulonglong); +# 813 "mysql.h" +extern unsigned int mysql_stmt_errno(MYSQL_STMT * stmt); +# 814 "mysql.h" +extern char const * mysql_stmt_error(MYSQL_STMT * stmt); +# 789 "mysql.h" +extern int mysql_stmt_execute(MYSQL_STMT * stmt); +# 790 "mysql.h" +extern int mysql_stmt_fetch(MYSQL_STMT * stmt); +# 791 "mysql.h" +extern int mysql_stmt_fetch_column(MYSQL_STMT * stmt, MYSQL_BIND * bind_arg, unsigned int, unsigned long int); +# 823 "mysql.h" +extern unsigned int mysql_stmt_field_count(MYSQL_STMT * stmt); # 806 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT * stmt, MYSQL_ROW_OFFSET); -# 808 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT * stmt); -# 797 "mysql.h" -extern my_bool mysql_stmt_send_long_data(MYSQL_STMT * stmt, unsigned int, char const * data, unsigned long int); +extern my_bool mysql_stmt_free_result(MYSQL_STMT * stmt); +# 786 "mysql.h" +extern MYSQL_STMT * mysql_stmt_init(MYSQL * mysql); +# 822 "mysql.h" +extern my_ulonglong mysql_stmt_insert_id(MYSQL_STMT * stmt); +# 820 "mysql.h" +extern my_ulonglong mysql_stmt_num_rows(MYSQL_STMT * stmt); +# 795 "mysql.h" +extern unsigned long int mysql_stmt_param_count(MYSQL_STMT * stmt); +# 812 "mysql.h" +extern MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT * stmt); +# 787 "mysql.h" +extern int mysql_stmt_prepare(MYSQL_STMT * stmt, char const * query, unsigned long int); # 805 "mysql.h" +extern my_bool mysql_stmt_reset(MYSQL_STMT * stmt); +# 811 "mysql.h" +extern MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT * stmt); +# 816 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT * stmt, MYSQL_ROW_OFFSET); +# 818 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT * stmt); +# 807 "mysql.h" +extern my_bool mysql_stmt_send_long_data(MYSQL_STMT * stmt, unsigned int, char const * data, unsigned long int); +# 815 "mysql.h" extern char const * mysql_stmt_sqlstate(MYSQL_STMT * stmt); -# 784 "mysql.h" +# 794 "mysql.h" extern int mysql_stmt_store_result(MYSQL_STMT * stmt); # 445 "mysql.h" extern MYSQL_RES * mysql_store_result(MYSQL * mysql); @@ -935,7 +937,7 @@ extern void mysql_thread_end(void); extern unsigned long int mysql_thread_id(MYSQL * mysql); # 396 "mysql.h" extern my_bool mysql_thread_init(void); -# 554 "mysql.h" +# 564 "mysql.h" extern unsigned int mysql_thread_safe(void); # 79 "mysql.h" extern char * mysql_unix_port; @@ -955,13 +957,13 @@ extern int net_real_write(NET * net, char const * packet, unsigned long int); extern my_bool net_realloc(NET * net, unsigned long int); # 342 "mysql_com.h" extern my_bool net_write_command(NET * net, unsigned char, char const * header, unsigned long int, char const * packet, unsigned long int); -# 431 "mysql_com.h" +# 435 "mysql_com.h" extern char * octet2hex(char * to, char const * str, unsigned int); -# 412 "mysql_com.h" +# 416 "mysql_com.h" extern void randominit(struct rand_struct *, unsigned long int, unsigned long int); -# 426 "mysql_com.h" +# 430 "mysql_com.h" extern void scramble(char * to, char const * message, char const * password); -# 419 "mysql_com.h" +# 423 "mysql_com.h" extern void scramble_323(char * to, char const * message, char const * password); # 34 "typelib.h" extern TYPELIB sql_protocol_typelib; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 1fa3181b1be..92a90ba79b3 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1613,6 +1613,18 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, return escape_string_for_mysql(mysql->charset, to, 0, from, length); } + +char * STDCALL +mysql_odbc_escape_string(MYSQL *mysql, + char *to, ulong to_length, + const char *from, ulong from_length, + void *param, + char * (*extend_buffer) + (void *, char *, ulong *)) +{ + return NULL; +} + void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name) { diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 81f86dc8726..8c6b71d9553 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -78,6 +78,7 @@ 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/libmysqld.def b/libmysqld/libmysqld.def index 8aed164a30e..8829112fefd 100644 --- a/libmysqld/libmysqld.def +++ b/libmysqld/libmysqld.def @@ -71,6 +71,7 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows + mysql_odbc_escape_string mysql_options mysql_ping mysql_query From 520795fa2a0bcf2384c37267f7202d7bff70af70 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 27 Oct 2009 15:15:53 +0000 Subject: [PATCH 2/4] BUG#48297: Schema name is ignored when LOAD DATA is written into binlog, replication aborts In SBR or MBR, the schema name is not being written to the binlog when executing a LOAD DATA statement. This becomes a problem when the current database (lets call it db1) is different from the table's schema (lets call it db2). For instance, take the following statements: use db1; load data local infile 'infile.txt' into table db2.t Should this statement be logged without t's schema (db2), when replaying it, one can get db1.t populated instead of db2.t (if db1.t exists). On the other hand, if there is no db1.t at all, replication will stop. We fix this by always logging the table (in load file) with fully qualified name when its schema is different from the current database or when no default database was selected. --- mysql-test/extra/rpl_tests/rpl_loaddata.test | 61 ++++++++++++++++++++ mysql-test/suite/rpl/r/rpl_loaddata.result | 29 ++++++++++ sql/sql_load.cc | 30 ++++++++-- 3 files changed, 115 insertions(+), 5 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_loaddata.test b/mysql-test/extra/rpl_tests/rpl_loaddata.test index 26916642cae..7db12600456 100644 --- a/mysql-test/extra/rpl_tests/rpl_loaddata.test +++ b/mysql-test/extra/rpl_tests/rpl_loaddata.test @@ -158,4 +158,65 @@ LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1; DROP TABLE IF EXISTS t1; +# BUG#48297: Schema name is ignored when LOAD DATA is written into binlog, +# replication aborts +-- source include/master-slave-reset.inc + +-- let $db1= b48297_db1 +-- let $db2= b42897_db2 + +-- connection master + +-- disable_warnings +-- eval drop database if exists $db1 +-- eval drop database if exists $db2 +-- enable_warnings + +-- eval create database $db1 +-- eval create database $db2 + +-- eval use $db1 +-- eval CREATE TABLE t1 (c1 VARCHAR(256)) engine=$engine_type; + +-- eval use $db2 + +-- echo ### assertion: works with cross-referenced database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 + +-- eval use $db1 +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- echo ### assertion: works with fully qualified name on current database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 + +-- echo ### assertion: works without fully qualified name on current database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1 + +-- echo ### create connection without default database +-- echo ### connect (conn2,localhost,root,,*NO-ONE*); +connect (conn2,localhost,root,,*NO-ONE*); +-- connection conn2 +-- echo ### assertion: works without stating the default database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 +-- echo ### disconnect and switch back to master connection +-- disconnect conn2 +-- connection master + +-- sync_slave_with_master +-- eval use $db1 + +let $diff_table_1=master:$db1.t1; +let $diff_table_2=slave:$db1.t1; +source include/diff_tables.inc; + +-- connection master + +-- eval DROP DATABASE $db1 +-- eval DROP DATABASE $db2 + +-- sync_slave_with_master + # End of 4.1 tests diff --git a/mysql-test/suite/rpl/r/rpl_loaddata.result b/mysql-test/suite/rpl/r/rpl_loaddata.result index 0653936f0ec..ca9c14691b0 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata.result @@ -86,3 +86,32 @@ CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=INNODB; LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1; ERROR 23000: Duplicate entry 'Aarhus' for key 'PRIMARY' DROP TABLE IF EXISTS t1; +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; +drop database if exists b48297_db1; +drop database if exists b42897_db2; +create database b48297_db1; +create database b42897_db2; +use b48297_db1; +CREATE TABLE t1 (c1 VARCHAR(256)) engine=MyISAM;; +use b42897_db2; +### assertion: works with cross-referenced database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +use b48297_db1; +### assertion: works with fully qualified name on current database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +### assertion: works without fully qualified name on current database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1; +### create connection without default database +### connect (conn2,localhost,root,,*NO-ONE*); +### assertion: works without stating the default database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +### disconnect and switch back to master connection +use b48297_db1; +Comparing tables master:b48297_db1.t1 and slave:b48297_db1.t1 +DROP DATABASE b48297_db1; +DROP DATABASE b42897_db2; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 59ba7b16d62..5500439b619 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -84,7 +84,7 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, bool ignore_check_option_errors); #ifndef EMBEDDED_LIBRARY static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, - const char* db_arg, + const char* db_arg, /* table's database */ const char* table_name_arg, enum enum_duplicates duplicates, bool ignore, @@ -501,7 +501,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, ex, - tdb, table_list->table_name, + table_list->db, + table_list->table_name, handle_duplicates, ignore, transactional_table, errcode); @@ -548,7 +549,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); write_execute_load_query_log_event(thd, ex, - tdb, table_list->table_name, + table_list->db, table_list->table_name, handle_duplicates, ignore, transactional_table, errcode); @@ -573,7 +574,7 @@ err: /* Not a very useful function; just to avoid duplication of code */ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, - const char* db_arg, + const char* db_arg, /* table's database */ const char* table_name_arg, enum enum_duplicates duplicates, bool ignore, @@ -590,8 +591,27 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, Item *item, *val; String pfield, pfields; int n; + const char *tbl= table_name_arg; + const char *tdb= (thd->db != NULL ? thd->db : db_arg); + String string_buf; - Load_log_event lle(thd, ex, db_arg, table_name_arg, fv, duplicates, + if (!thd->db || strcmp(db_arg, thd->db)) + { + /* + If used database differs from table's database, + prefix table name with database name so that it + becomes a FQ name. + */ + string_buf.set_charset(system_charset_info); + string_buf.append(db_arg); + string_buf.append("`"); + string_buf.append("."); + string_buf.append("`"); + string_buf.append(table_name_arg); + tbl= string_buf.c_ptr_safe(); + } + + Load_log_event lle(thd, ex, tdb, tbl, fv, duplicates, ignore, transactional_table); /* From f539e0c8252aa8a54ddb0ca52e9708ec463c829b Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Mon, 2 Nov 2009 13:24:07 +0100 Subject: [PATCH 3/4] Bug#47925: regression of range optimizer and date comparison in 5.1.39! When a query was using a DATE or DATETIME value formatted using any other separator characters beside hyphen '-', a query with a greater-or-equal '>=' condition matching only the greatest value in an indexed column, the result was empty if index range scan was employed. The range optimizer got a new feature between 5.1.38 and 5.1.39 that changes a greater-or-equal condition to a greater-than if the value matching that in the query was not present in the table. But the value comparison function compared the dates as strings instead of dates. The bug was fixed by splitting the function get_date_from_str in two: One part that parses and does error checking. This function is now visible outside the module. The old get_date_from_str now calls the new function. --- mysql-test/r/range.result | 197 ++++++++++++++++++++++++++++++++++++++ mysql-test/t/range.test | 79 +++++++++++++++ sql/item.cc | 79 +++++++-------- sql/item.h | 2 +- sql/item_cmpfunc.cc | 102 ++++++++++++-------- sql/item_cmpfunc.h | 3 + sql/opt_range.cc | 6 +- sql/time.cc | 16 ++-- 8 files changed, 390 insertions(+), 94 deletions(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 0d44e79b39a..2306f8b501e 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1406,4 +1406,201 @@ INSERT INTO t1 VALUES (1), (NULL); SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); a DROP TABLE t1; +# +# Bug#47925: regression of range optimizer and date comparison in 5.1.39! +# +CREATE TABLE t1 ( a DATE, KEY ( a ) ); +CREATE TABLE t2 ( a DATETIME, KEY ( a ) ); +# Make optimizer choose range scan +INSERT INTO t1 VALUES ('2009-09-22'), ('2009-09-22'), ('2009-09-22'); +INSERT INTO t1 VALUES ('2009-09-23'), ('2009-09-23'), ('2009-09-23'); +INSERT INTO t2 VALUES ('2009-09-22 12:00:00'), ('2009-09-22 12:00:00'), +('2009-09-22 12:00:00'); +INSERT INTO t2 VALUES ('2009-09-23 12:00:00'), ('2009-09-23 12:00:00'), +('2009-09-23 12:00:00'); +# DATE vs DATE +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t1 WHERE a >= '2009/09/23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '20090923'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= 20090923; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009-9-23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009.09.23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009:09:23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +# DATE vs DATETIME +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t2 WHERE a >= '2009/09/23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009/09/23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '20090923'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= 20090923; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009-9-23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009.09.23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009:09:23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +# DATETIME vs DATETIME +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '20090923120000'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= 20090923120000; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009-9-23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009.09.23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009:09:23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +# DATETIME vs DATE +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '20090923000000'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= 20090923000000; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009-9-23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009.09.23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009:09:23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +# Test of the new get_date_from_str implementation +# Behavior differs slightly between the trunk and mysql-pe. +# The former may give errors for the truncated values, while the latter +# gives warnings. The purpose of this test is not to interfere, and only +# preserve existing behavior. +SELECT str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND +str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20'; +str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND +str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20' +1 +Warnings: +Warning 1292 Truncated incorrect date value: '' +SELECT str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND +str_to_date('2007-20-00', '%Y-%m-%d') <= ''; +str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND +str_to_date('2007-20-00', '%Y-%m-%d') <= '' +NULL +Warnings: +Warning 1292 Truncated incorrect date value: '' +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +SELECT str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20'; +str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20' +1 +Warnings: +Warning 1292 Truncated incorrect datetime value: '' +SELECT str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND ''; +str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND '' +NULL +Warnings: +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +SELECT str_to_date('', '%Y-%m-%d'); +str_to_date('', '%Y-%m-%d') +0000-00-00 +DROP TABLE t1, t2; End of 5.1 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index f0fa99f3d95..3a845471cd0 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1181,4 +1181,83 @@ INSERT INTO t1 VALUES (1), (NULL); SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); DROP TABLE t1; +--echo # +--echo # Bug#47925: regression of range optimizer and date comparison in 5.1.39! +--echo # +CREATE TABLE t1 ( a DATE, KEY ( a ) ); +CREATE TABLE t2 ( a DATETIME, KEY ( a ) ); + +--echo # Make optimizer choose range scan +INSERT INTO t1 VALUES ('2009-09-22'), ('2009-09-22'), ('2009-09-22'); +INSERT INTO t1 VALUES ('2009-09-23'), ('2009-09-23'), ('2009-09-23'); + +INSERT INTO t2 VALUES ('2009-09-22 12:00:00'), ('2009-09-22 12:00:00'), + ('2009-09-22 12:00:00'); +INSERT INTO t2 VALUES ('2009-09-23 12:00:00'), ('2009-09-23 12:00:00'), + ('2009-09-23 12:00:00'); + +--echo # DATE vs DATE +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23'; +SELECT * FROM t1 WHERE a >= '2009/09/23'; +SELECT * FROM t1 WHERE a >= '20090923'; +SELECT * FROM t1 WHERE a >= 20090923; +SELECT * FROM t1 WHERE a >= '2009-9-23'; +SELECT * FROM t1 WHERE a >= '2009.09.23'; +SELECT * FROM t1 WHERE a >= '2009:09:23'; + +--echo # DATE vs DATETIME +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '20090923'; +SELECT * FROM t2 WHERE a >= 20090923; +SELECT * FROM t2 WHERE a >= '2009-9-23'; +SELECT * FROM t2 WHERE a >= '2009.09.23'; +SELECT * FROM t2 WHERE a >= '2009:09:23'; + +--echo # DATETIME vs DATETIME +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +SELECT * FROM t2 WHERE a >= '20090923120000'; +SELECT * FROM t2 WHERE a >= 20090923120000; +SELECT * FROM t2 WHERE a >= '2009-9-23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009.09.23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009:09:23 12:00:00'; + +--echo # DATETIME vs DATE +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '20090923000000'; +SELECT * FROM t1 WHERE a >= 20090923000000; +SELECT * FROM t1 WHERE a >= '2009-9-23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009.09.23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009:09:23 00:00:00'; + +--echo # Test of the new get_date_from_str implementation +--echo # Behavior differs slightly between the trunk and mysql-pe. +--echo # The former may give errors for the truncated values, while the latter +--echo # gives warnings. The purpose of this test is not to interfere, and only +--echo # preserve existing behavior. +SELECT str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND + str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20'; + +SELECT str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND + str_to_date('2007-20-00', '%Y-%m-%d') <= ''; + +SELECT str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20'; +SELECT str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND ''; + +SELECT str_to_date('', '%Y-%m-%d'); + +DROP TABLE t1, t2; + --echo End of 5.1 tests diff --git a/sql/item.cc b/sql/item.cc index f637f9ffaea..5bace670e9b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6866,72 +6866,61 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) } /** - Compare the value stored in field, with the original item. + Compare the value stored in field with the expression from the query. - @param field field which the item is converted and stored in - @param item original item + @param field Field which the Item is stored in after conversion + @param item Original expression from query - @return Return an integer greater than, equal to, or less than 0 if - the value stored in the field is greater than, equal to, - or less than the original item + @return Returns an integer greater than, equal to, or less than 0 if + the value stored in the field is greater than, equal to, + or less than the original Item. A 0 may also be returned if + out of memory. @note We only use this on the range optimizer/partition pruning, because in some cases we can't store the value in the field without some precision/character loss. */ -int stored_field_cmp_to_item(Field *field, Item *item) +int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) { - Item_result res_type=item_cmp_type(field->result_type(), item->result_type()); if (res_type == STRING_RESULT) { char item_buff[MAX_FIELD_WIDTH]; char field_buff[MAX_FIELD_WIDTH]; - String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result; + + String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin); String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); - enum_field_types field_type; - item_result=item->val_str(&item_tmp); + String *item_result= item->val_str(&item_tmp); + /* + Some implementations of Item::val_str(String*) actually modify + the field Item::null_value, hence we can't check it earlier. + */ if (item->null_value) return 0; - field->val_str(&field_tmp); + String *field_result= field->val_str(&field_tmp); - /* - If comparing DATE with DATETIME, append the time-part to the DATE. - So that the strings are equally formatted. - A DATE converted to string is 10 (MAX_DATE_WIDTH) characters, - and a DATETIME converted to string is 19 (MAX_DATETIME_WIDTH) characters. - */ - field_type= field->type(); - uint32 item_length= item_result->length(); - if (field_type == MYSQL_TYPE_DATE && - item_length == MAX_DATETIME_WIDTH) - field_tmp.append(" 00:00:00"); - else if (field_type == MYSQL_TYPE_DATETIME) + enum_field_types field_type= field->type(); + + if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME) { - if (item_length == MAX_DATE_WIDTH) - item_result->append(" 00:00:00"); - else if (item_length > MAX_DATETIME_WIDTH) - { - /* - We don't store microsecond part of DATETIME in field - but item_result contains it. As we compare DATETIMEs as strings - we must trim trailing 0's in item_result's microsecond part - to ensure "YYYY-MM-DD HH:MM:SS" == "YYYY-MM-DD HH:MM:SS.0000" - */ - char *end= (char *) item_result->ptr() + item_length - 1; - /* Trim trailing 0's */ - while (*end == '0') - end--; - /* Trim '.' if no microseconds */ - if (*end == '.') - end--; - DBUG_ASSERT(end - item_result->ptr() + 1 >= MAX_DATETIME_WIDTH); - item_result->length(end - item_result->ptr() + 1); - } + enum_mysql_timestamp_type type= MYSQL_TIMESTAMP_ERROR; + + if (field_type == MYSQL_TYPE_DATE) + type= MYSQL_TIMESTAMP_DATE; + + if (field_type == MYSQL_TYPE_DATETIME) + type= MYSQL_TIMESTAMP_DATETIME; + + const char *field_name= field->field_name; + MYSQL_TIME field_time, item_time; + get_mysql_time_from_str(thd, field_result, type, field_name, &field_time); + get_mysql_time_from_str(thd, item_result, type, field_name, &item_time); + + return my_time_compare(&field_time, &item_time); } - return stringcmp(&field_tmp,item_result); + return stringcmp(field_result, item_result); } if (res_type == INT_RESULT) return 0; // Both are of type int diff --git a/sql/item.h b/sql/item.h index a2cff3ab3a9..405588917ee 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3125,4 +3125,4 @@ void mark_select_range_as_dependent(THD *thd, extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); -extern int stored_field_cmp_to_item(Field *field, Item *item); +extern int stored_field_cmp_to_item(THD *thd, Field *field, Item *item); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c29031d25b5..9fc52bb8876 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -636,6 +636,62 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) return 0; } +/** + Parse date provided in a string to a MYSQL_TIME. + + @param[in] thd Thread handle + @param[in] str A string to convert + @param[in] warn_type Type of the timestamp for issuing the warning + @param[in] warn_name Field name for issuing the warning + @param[out] l_time The MYSQL_TIME objects is initialized. + + Parses a date provided in the string str into a MYSQL_TIME object. If the + string contains an incorrect date or doesn't correspond to a date at all + then a warning is issued. The warn_type and the warn_name arguments are used + as the name and the type of the field when issuing the warning. If any input + was discarded (trailing or non-timestamp-y characters), return value will be + TRUE. + + @return Status flag + @retval FALSE Success. + @retval True Indicates failure. +*/ + +bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, + const char *warn_name, MYSQL_TIME *l_time) +{ + bool value; + int error; + enum_mysql_timestamp_type timestamp_type; + + timestamp_type= + str_to_datetime(str->ptr(), str->length(), l_time, + (TIME_FUZZY_DATE | MODE_INVALID_DATES | + (thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))), + &error); + + if (timestamp_type == MYSQL_TIMESTAMP_DATETIME || + timestamp_type == MYSQL_TIMESTAMP_DATE) + /* + Do not return yet, we may still want to throw a "trailing garbage" + warning. + */ + value= FALSE; + else + { + value= TRUE; + error= 1; /* force warning */ + } + + if (error > 0) + make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + str->ptr(), str->length(), + warn_type, warn_name); + + return value; +} + /** @brief Convert date provided in a string to the int representation. @@ -650,51 +706,21 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) representation. If the string contains wrong date or doesn't contain it at all then a warning is issued. The warn_type and the warn_name arguments are used as the name and the type of the - field when issuing the warning. If any input was discarded - (trailing or non-timestampy characters), was_cut will be non-zero. - was_type will return the type str_to_datetime() could correctly - extract. + field when issuing the warning. @return converted value. 0 on error and on zero-dates -- check 'failure' */ - -static ulonglong -get_date_from_str(THD *thd, String *str, timestamp_type warn_type, - char *warn_name, bool *error_arg) +static ulonglong get_date_from_str(THD *thd, String *str, + timestamp_type warn_type, + const char *warn_name, bool *error_arg) { - ulonglong value= 0; - int error; MYSQL_TIME l_time; - enum_mysql_timestamp_type ret; + *error_arg= get_mysql_time_from_str(thd, str, warn_type, warn_name, &l_time); - ret= str_to_datetime(str->ptr(), str->length(), &l_time, - (TIME_FUZZY_DATE | MODE_INVALID_DATES | - (thd->variables.sql_mode & - (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))), - &error); - - if (ret == MYSQL_TIMESTAMP_DATETIME || ret == MYSQL_TIMESTAMP_DATE) - { - /* - Do not return yet, we may still want to throw a "trailing garbage" - warning. - */ - *error_arg= FALSE; - value= TIME_to_ulonglong_datetime(&l_time); - } - else - { - *error_arg= TRUE; - error= 1; /* force warning */ - } - - if (error > 0) - make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - str->ptr(), str->length(), - warn_type, warn_name); - - return value; + if (*error_arg) + return 0; + return TIME_to_ulonglong_datetime(&l_time); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index c2227fa04e0..437d9541e50 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1721,3 +1721,6 @@ inline Item *and_conds(Item *a, Item *b) } Item *and_expressions(Item *a, Item *b, Item **org_item); + +bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, + const char *warn_name, MYSQL_TIME *l_time); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2f2506f02b1..5f9bae22c70 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5968,7 +5968,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, switch (type) { case Item_func::LT_FUNC: - if (stored_field_cmp_to_item(field,value) == 0) + if (stored_field_cmp_to_item(param->thd, field, value) == 0) tree->max_flag=NEAR_MAX; /* fall through */ case Item_func::LE_FUNC: @@ -5983,14 +5983,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, case Item_func::GT_FUNC: /* Don't use open ranges for partial key_segments */ if ((!(key_part->flag & HA_PART_KEY_SEG)) && - (stored_field_cmp_to_item(field, value) <= 0)) + (stored_field_cmp_to_item(param->thd, field, value) <= 0)) tree->min_flag=NEAR_MIN; tree->max_flag= NO_MAX_RANGE; break; case Item_func::GE_FUNC: /* Don't use open ranges for partial key_segments */ if ((!(key_part->flag & HA_PART_KEY_SEG)) && - (stored_field_cmp_to_item(field,value) < 0)) + (stored_field_cmp_to_item(param->thd, field, value) < 0)) tree->min_flag= NEAR_MIN; tree->max_flag=NO_MAX_RANGE; break; diff --git a/sql/time.cc b/sql/time.cc index 962b65e454c..8b554beb94b 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -965,20 +965,22 @@ calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign, longlong *s 0 - a == b 1 - a > b - NOTES - TIME.second_part is not considered during comparison */ -int -my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) +int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) { - my_ulonglong a_t= TIME_to_ulonglong_datetime(a); - my_ulonglong b_t= TIME_to_ulonglong_datetime(b); + ulonglong a_t= TIME_to_ulonglong_datetime(a); + ulonglong b_t= TIME_to_ulonglong_datetime(b); + if (a_t < b_t) + return -1; if (a_t > b_t) return 1; - else if (a_t < b_t) + + if (a->second_part < b->second_part) return -1; + if (a->second_part > b->second_part) + return 1; return 0; } From 9a431db024d0f4a9d5e9d8d46961585df7b80595 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Mon, 2 Nov 2009 18:10:21 -0200 Subject: [PATCH 4/4] Bug#44952: Ndbd file system inconsistency error Backport a ndb patch: fix bug with crash during restart, where a mbyte incorrectly could be skipped, leading to "end of log wo/ finding gci". --- ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index e4ff1d1dbb6..73779be0ef4 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -14577,7 +14577,7 @@ void Dblqh::srLogLimits(Signal* signal) while(true) { ndbrequire(tmbyte < 16); if (logPartPtr.p->logExecState == LogPartRecord::LES_SEARCH_STOP) { - if (logFilePtr.p->logMaxGciCompleted[tmbyte] < logPartPtr.p->logLastGci) { + if (logFilePtr.p->logMaxGciCompleted[tmbyte] <= logPartPtr.p->logLastGci) { jam(); /* -------------------------------------------------------------------- * WE ARE STEPPING BACKWARDS FROM MBYTE TO MBYTE. THIS IS THE FIRST