Hello Sanja, Can you please review a patch for MDEV-11913?
Thanks!
commit 269368e696aa9b03be743e7fbc0a5838ba54f49a Author: Alexander Barkov <b...@mariadb.org> Date: Thu Jan 26 13:01:52 2017 +0400 MDEV-11913 Split sp_get_item_value() into methods in Type_handler This patch also fixes: MDEV-11815 SP variables of temporal data types do not replicate correctly diff --git a/mysql-test/suite/binlog/r/binlog_stm_sp.result b/mysql-test/suite/binlog/r/binlog_stm_sp.result new file mode 100644 index 0000000..6c47051 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_stm_sp.result @@ -0,0 +1,86 @@ +# +# MDEV-11815 SP variables of temporal data types do not replicate correctly +# +CREATE TABLE t1(a INT); +CREATE PROCEDURE p1() +BEGIN +DECLARE i INT DEFAULT 123; +DECLARE b8 BIT(8) DEFAULT 0x61; +DECLARE t0 TIME DEFAULT '01:01:01'; +DECLARE t6 TIME(6) DEFAULT '01:01:01.123456'; +DECLARE d DATE DEFAULT '2001-01-01'; +DECLARE dt0 DATETIME DEFAULT '2001-01-01 01:01:01'; +DECLARE dt6 DATETIME(6) DEFAULT '2001-01-01 01:01:01.123456'; +DECLARE ts0 TIMESTAMP DEFAULT '2001-01-01 01:01:01'; +DECLARE ts6 TIMESTAMP(6) DEFAULT '2001-01-01 01:01:01.123456'; +INSERT INTO t1 VALUES (i=0x61); +INSERT INTO t1 VALUES (b8=0x61); +INSERT INTO t1 VALUES (t0=10101); +INSERT INTO t1 VALUES (t6=10101); +INSERT INTO t1 VALUES (d=20010101); +INSERT INTO t1 VALUES (dt0=20010101010101); +INSERT INTO t1 VALUES (dt6=20010101010101); +INSERT INTO t1 VALUES (ts0=20010101010101); +INSERT INTO t1 VALUES (ts6=20010101010101); +END; +$$ +CALL p1; +DROP TABLE t1; +DROP PROCEDURE p1; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE TABLE t1(a INT) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +BEGIN +DECLARE i INT DEFAULT 123; +DECLARE b8 BIT(8) DEFAULT 0x61; +DECLARE t0 TIME DEFAULT '01:01:01'; +DECLARE t6 TIME(6) DEFAULT '01:01:01.123456'; +DECLARE d DATE DEFAULT '2001-01-01'; +DECLARE dt0 DATETIME DEFAULT '2001-01-01 01:01:01'; +DECLARE dt6 DATETIME(6) DEFAULT '2001-01-01 01:01:01.123456'; +DECLARE ts0 TIMESTAMP DEFAULT '2001-01-01 01:01:01'; +DECLARE ts6 TIMESTAMP(6) DEFAULT '2001-01-01 01:01:01.123456'; +INSERT INTO t1 VALUES (i=0x61); +INSERT INTO t1 VALUES (b8=0x61); +INSERT INTO t1 VALUES (t0=10101); +INSERT INTO t1 VALUES (t6=10101); +INSERT INTO t1 VALUES (d=20010101); +INSERT INTO t1 VALUES (dt0=20010101010101); +INSERT INTO t1 VALUES (dt6=20010101010101); +INSERT INTO t1 VALUES (ts0=20010101010101); +INSERT INTO t1 VALUES (ts6=20010101010101); +END +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('i',123)=0x61) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('b8',_binary'a' COLLATE 'binary')=0x61) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('t0',TIME'01:01:01')=10101) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('t6',TIME'01:01:01.123456')=10101) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('d',DATE'2001-01-01')=20010101) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('dt0',TIMESTAMP'2001-01-01 01:01:01')=20010101010101) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('dt6',TIMESTAMP'2001-01-01 01:01:01.123456')=20010101010101) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('ts0',TIMESTAMP'2001-01-01 01:01:01')=20010101010101) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('ts6',TIMESTAMP'2001-01-01 01:01:01.123456')=20010101010101) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP PROCEDURE p1 diff --git a/mysql-test/suite/binlog/t/binlog_stm_sp.test b/mysql-test/suite/binlog/t/binlog_stm_sp.test new file mode 100644 index 0000000..095b4c7 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_stm_sp.test @@ -0,0 +1,41 @@ +--source include/have_binlog_format_statement.inc + +--disable_query_log +reset master; # get rid of previous tests binlog +--enable_query_log + +--echo # +--echo # MDEV-11815 SP variables of temporal data types do not replicate correctly +--echo # + +CREATE TABLE t1(a INT); +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE i INT DEFAULT 123; + DECLARE b8 BIT(8) DEFAULT 0x61; + DECLARE t0 TIME DEFAULT '01:01:01'; + DECLARE t6 TIME(6) DEFAULT '01:01:01.123456'; + DECLARE d DATE DEFAULT '2001-01-01'; + DECLARE dt0 DATETIME DEFAULT '2001-01-01 01:01:01'; + DECLARE dt6 DATETIME(6) DEFAULT '2001-01-01 01:01:01.123456'; + DECLARE ts0 TIMESTAMP DEFAULT '2001-01-01 01:01:01'; + DECLARE ts6 TIMESTAMP(6) DEFAULT '2001-01-01 01:01:01.123456'; + INSERT INTO t1 VALUES (i=0x61); + INSERT INTO t1 VALUES (b8=0x61); + INSERT INTO t1 VALUES (t0=10101); + INSERT INTO t1 VALUES (t6=10101); + INSERT INTO t1 VALUES (d=20010101); + INSERT INTO t1 VALUES (dt0=20010101010101); + INSERT INTO t1 VALUES (dt6=20010101010101); + INSERT INTO t1 VALUES (ts0=20010101010101); + INSERT INTO t1 VALUES (ts6=20010101010101); +END; +$$ +DELIMITER ;$$ +CALL p1; +DROP TABLE t1; +DROP PROCEDURE p1; + +--let $binlog_file = LAST +source include/show_binlog_events.inc; diff --git a/mysql-test/suite/rpl/r/rpl_stm_sp.result b/mysql-test/suite/rpl/r/rpl_stm_sp.result new file mode 100644 index 0000000..4e2d4c8 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_stm_sp.result @@ -0,0 +1,26 @@ +include/master-slave.inc +[connection master] +# +# MDEV-11815 SP variables of temporal data types do not replicate correctly +# +connection master; +CREATE TABLE t1(a INT); +CREATE PROCEDURE p1() +BEGIN +DECLARE a TIME DEFAULT '01:01:01'; +INSERT INTO t1 VALUES (a=10101); +END; +$$ +CALL p1; +SELECT * FROM t1; +a +1 +connection slave; +SELECT * FROM t1; +a +1 +connection master; +DROP TABLE t1; +DROP PROCEDURE p1; +connection slave; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_sp.test b/mysql-test/suite/rpl/t/rpl_stm_sp.test new file mode 100644 index 0000000..b99906b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_sp.test @@ -0,0 +1,30 @@ +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--echo # +--echo # MDEV-11815 SP variables of temporal data types do not replicate correctly +--echo # + +connection master; +CREATE TABLE t1(a INT); +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE a TIME DEFAULT '01:01:01'; + INSERT INTO t1 VALUES (a=10101); +END; +$$ +DELIMITER ;$$ +CALL p1; +SELECT * FROM t1; + +sync_slave_with_master; +SELECT * FROM t1; + +connection master; +DROP TABLE t1; +DROP PROCEDURE p1; +sync_slave_with_master; + + +--source include/rpl_end.inc diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 441de33..f55320f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -92,65 +92,6 @@ sp_map_item_type(enum enum_field_types type) } -/** - Return a string representation of the Item value. - - @param thd thread handle - @param str string buffer for representation of the value - - @note - If the item has a string result type, the string is escaped - according to its character set. - - @retval - NULL on error - @retval - non-NULL a pointer to valid a valid string on success -*/ - -static String * -sp_get_item_value(THD *thd, Item *item, String *str) -{ - switch (item->result_type()) { - case REAL_RESULT: - case INT_RESULT: - case DECIMAL_RESULT: - if (item->field_type() != MYSQL_TYPE_BIT) - return item->val_str(str); - else {/* Bit type is handled as binary string */} - case STRING_RESULT: - { - String *result= item->val_str(str); - - if (!result) - return NULL; - - { - StringBuffer<STRING_BUFFER_USUAL_SIZE> buf(result->charset()); - CHARSET_INFO *cs= thd->variables.character_set_client; - - buf.append('_'); - buf.append(result->charset()->csname); - if (cs->escape_with_backslash_is_dangerous) - buf.append(' '); - append_query_string(cs, &buf, result->ptr(), result->length(), - thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES); - buf.append(" COLLATE '"); - buf.append(item->collation.collation->name); - buf.append('\''); - str->copy(buf); - - return str; - } - } - - case ROW_RESULT: - default: - return NULL; - } -} - - bool Item_splocal::append_for_log(THD *thd, String *str) { if (fix_fields(thd, NULL)) @@ -165,7 +106,9 @@ bool Item_splocal::append_for_log(THD *thd, String *str) return true; StringBuffer<STRING_BUFFER_USUAL_SIZE> str_value_holder(&my_charset_latin1); - String *str_value= sp_get_item_value(thd, this_item(), &str_value_holder); + Item *item= this_item(); + String *str_value= item->type_handler()->sp_get_item_value(thd, item, + &str_value_holder); if (str_value) return str->append(*str_value) || str->append(')'); else @@ -1758,9 +1701,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, if (arg_no) binlog_buf.append(','); - str_value= sp_get_item_value(thd, nctx->get_item(arg_no), - &str_value_holder); - + Item *item= nctx->get_item(arg_no); + str_value= item->type_handler()->sp_get_item_value(thd, item, + &str_value_holder); if (str_value) binlog_buf.append(*str_value); else diff --git a/sql/sql_type.cc b/sql/sql_type.cc index d43dd2c..0826595 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -2013,3 +2013,99 @@ bool Type_handler_temporal_result:: return func->get_date_native(ltime, fuzzydate); } +/***************************************************************************/ + +String *Type_handler_row:: + sp_get_item_value(THD *thd, Item *item, String *str) const +{ + DBUG_ASSERT(0); + return NULL; +} + + +String *Type_handler:: + sp_get_item_value_csstr(THD *thd, Item *item, String *str) const +{ + String *result= item->val_str(str); + + if (!result) + return NULL; + + StringBuffer<STRING_BUFFER_USUAL_SIZE> buf(result->charset()); + CHARSET_INFO *cs= thd->variables.character_set_client; + + buf.append('_'); + buf.append(result->charset()->csname); + if (cs->escape_with_backslash_is_dangerous) + buf.append(' '); + append_query_string(cs, &buf, result->ptr(), result->length(), + thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES); + buf.append(" COLLATE '"); + buf.append(item->collation.collation->name); + buf.append('\''); + str->copy(buf); + + return str; +} + + +String *Type_handler_numeric:: + sp_get_item_value(THD *thd, Item *item, String *str) const +{ + return item->val_str(str); +} + + +String *Type_handler:: + sp_get_item_value_temporal(THD *thd, Item *item, String *str, + const Name &type_name, String *buf) const +{ + String *result= item->val_str(buf); + return !result || + str->realloc(type_name.length() + result->length() + 2) || + str->copy(type_name.ptr(), type_name.length(), &my_charset_latin1) || + str->append('\'') || + str->append(result->ptr(), result->length()) || + str->append('\'') ? + NULL : + str; +} + + +String *Type_handler_time_common:: + sp_get_item_value(THD *thd, Item *item, String *str) const +{ + StringBuffer<MAX_TIME_FULL_WIDTH+1> buf; + return sp_get_item_value_temporal(thd, item, str, + Name(C_STRING_WITH_LEN("TIME")), &buf); +} + + +String *Type_handler_date_common:: + sp_get_item_value(THD *thd, Item *item, String *str) const +{ + StringBuffer<MAX_DATE_WIDTH+1> buf; + return sp_get_item_value_temporal(thd, item, str, + Name(C_STRING_WITH_LEN("DATE")), &buf); +} + + +String *Type_handler_datetime_common:: + sp_get_item_value(THD *thd, Item *item, String *str) const +{ + StringBuffer<MAX_DATETIME_FULL_WIDTH+1> buf; + return sp_get_item_value_temporal(thd, item, str, + Name(C_STRING_WITH_LEN("TIMESTAMP")), &buf); +} + + +String *Type_handler_timestamp_common:: + sp_get_item_value(THD *thd, Item *item, String *str) const +{ + StringBuffer<MAX_DATETIME_FULL_WIDTH+1> buf; + return sp_get_item_value_temporal(thd, item, str, + Name(C_STRING_WITH_LEN("TIMESTAMP")), &buf); +} + + +/***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index 29e1a29..4a99e65 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -259,6 +259,9 @@ class Name: private LEX_CSTRING class Type_handler { protected: + String *sp_get_item_value_csstr(THD *thd, Item *item, String *str) const; + String *sp_get_item_value_temporal(THD *thd, Item *item, String *str, + const Name &type_name, String *buf) const; void make_sort_key_longlong(uchar *to, bool maybe_null, bool null_value, bool unsigned_flag, @@ -347,6 +350,24 @@ class Type_handler virtual uint32 max_display_length(const Item *item) const= 0; virtual int Item_save_in_field(Item *item, Field *field, bool no_conversions) const= 0; + + /** + Return a string representation of the Item value. + + @param thd thread handle + @param str string buffer for representation of the value + + @note + If the item has a string result type, the string is escaped + according to its character set. + + @retval + NULL on error + @retval + non-NULL a pointer to valid a valid string on success + */ + virtual String *sp_get_item_value(THD *thd, Item *item, String *str) const= 0; + /** Check if WHERE expr=value AND expr=const @@ -481,6 +502,7 @@ class Type_handler_row: public Type_handler DBUG_ASSERT(0); return 1; } + String *sp_get_item_value(THD *thd, Item *item, String *str) const; bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, Item *target_value, Item_bool_func2 *source, @@ -585,6 +607,7 @@ class Type_handler_numeric: public Type_handler const Type_handler *handler) const; public: + String *sp_get_item_value(THD *thd, Item *item, String *str) const; double Item_func_min_max_val_real(Item_func_min_max *) const; longlong Item_func_min_max_val_int(Item_func_min_max *) const; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, @@ -788,6 +811,10 @@ class Type_handler_string_result: public Type_handler SORT_FIELD_ATTR *attr) const; uint32 max_display_length(const Item *item) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; + String *sp_get_item_value(THD *thd, Item *item, String *str) const + { + return sp_get_item_value_csstr(thd, item, str); + } bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, Item *target_value, Item_bool_func2 *source, @@ -934,6 +961,10 @@ class Type_handler_bit: public Type_handler_int_result const Name name() const { return m_name_bit; } enum_field_types field_type() const { return MYSQL_TYPE_BIT; } uint32 max_display_length(const Item *item) const; + String *sp_get_item_value(THD *thd, Item *item, String *str) const + { + return sp_get_item_value_csstr(thd, item, str); + } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; @@ -975,6 +1006,7 @@ class Type_handler_time_common: public Type_handler_temporal_result enum_field_types field_type() const { return MYSQL_TYPE_TIME; } const Type_handler *type_handler_for_comparison() const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; + String *sp_get_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const; @@ -1019,6 +1051,7 @@ class Type_handler_date_common: public Type_handler_temporal_with_date virtual ~Type_handler_date_common() {} const Name name() const { return m_name_date; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + String *sp_get_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; }; @@ -1048,6 +1081,7 @@ class Type_handler_datetime_common: public Type_handler_temporal_with_date virtual ~Type_handler_datetime_common() {} const Name name() const { return m_name_datetime; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } + String *sp_get_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; }; @@ -1079,6 +1113,7 @@ class Type_handler_timestamp_common: public Type_handler_temporal_with_date virtual ~Type_handler_timestamp_common() {} const Name name() const { return m_name_timestamp; } enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; } + String *sp_get_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; };
_______________________________________________ Mailing list: https://launchpad.net/~maria-developers Post to : maria-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~maria-developers More help : https://help.launchpad.net/ListHelp