maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #10327
MDEV-11913 Split sp_get_item_value() into methods in Type_handler
Hello Sanja,
Can you please review a patch for MDEV-11913?
Thanks!
commit 269368e696aa9b03be743e7fbc0a5838ba54f49a
Author: Alexander Barkov <bar@xxxxxxxxxxx>
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;
};