diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 93ae8c3cdd0..009a12574ce 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2816,10 +2816,11 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, { switch (attr_type) { case STMT_ATTR_UPDATE_MAX_LENGTH: + *(my_bool*) value= stmt->update_max_length; break; case STMT_ATTR_CURSOR_TYPE: *(ulong*) value= stmt->flags; - break; + break; case STMT_ATTR_PREFETCH_ROWS: *(ulong*) value= stmt->prefetch_rows; break; diff --git a/mysql-test/r/ctype_cp932_binlog_stm.result b/mysql-test/r/ctype_cp932_binlog_stm.result index 4ea1ecb6999..d354a8b99f7 100644 --- a/mysql-test/r/ctype_cp932_binlog_stm.result +++ b/mysql-test/r/ctype_cp932_binlog_stm.result @@ -15,3 +15,32 @@ SELECT HEX(f1) FROM t1; HEX(f1) 8300 DROP table t1; +CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1, +s2 CHAR(50) CHARACTER SET cp932, +d DECIMAL(10,2))| +CREATE PROCEDURE bug18293 (IN ins1 CHAR(50), +IN ins2 CHAR(50) CHARACTER SET cp932, +IN ind DECIMAL(10,2)) +BEGIN +INSERT INTO t4 VALUES (ins1, ins2, ind); +END| +CALL bug18293("Foo's a Bar", _cp932 0xED40ED41ED42, 47.93)| +SELECT HEX(s1),HEX(s2),d FROM t4| +HEX(s1) HEX(s2) d +466F6F2773206120426172 ED40ED41ED42 47.93 +DROP PROCEDURE bug18293| +DROP TABLE t4| +SHOW BINLOG EVENTS FROM 397| +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 397 Query 1 560 use `test`; CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1, +s2 CHAR(50) CHARACTER SET cp932, +d DECIMAL(10,2)) +master-bin.000001 560 Query 1 805 use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE bug18293 (IN ins1 CHAR(50), +IN ins2 CHAR(50) CHARACTER SET cp932, +IN ind DECIMAL(10,2)) +BEGIN +INSERT INTO t4 VALUES (ins1, ins2, ind); +END +master-bin.000001 805 Query 1 1010 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1'Foo\'s a Bar'), NAME_CONST('ins2',_cp932 0xED40ED41ED42), NAME_CONST('ind',47.93)) +master-bin.000001 1010 Query 1 1096 use `test`; DROP PROCEDURE bug18293 +master-bin.000001 1096 Query 1 1172 use `test`; DROP TABLE t4 diff --git a/mysql-test/t/ctype_cp932_binlog_stm.test b/mysql-test/t/ctype_cp932_binlog_stm.test index 83a9ec59000..7a0ac671417 100644 --- a/mysql-test/t/ctype_cp932_binlog_stm.test +++ b/mysql-test/t/ctype_cp932_binlog_stm.test @@ -3,3 +3,27 @@ -- source include/have_binlog_format_statement.inc -- source extra/binlog_tests/ctype_cp932_binlog.test + +# +# Bug#18293: Values in stored procedure written to binlog unescaped +# + +delimiter |; +CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1, + s2 CHAR(50) CHARACTER SET cp932, + d DECIMAL(10,2))| +CREATE PROCEDURE bug18293 (IN ins1 CHAR(50), + IN ins2 CHAR(50) CHARACTER SET cp932, + IN ind DECIMAL(10,2)) + BEGIN + INSERT INTO t4 VALUES (ins1, ins2, ind); + END| +CALL bug18293("Foo's a Bar", _cp932 0xED40ED41ED42, 47.93)| +SELECT HEX(s1),HEX(s2),d FROM t4| +DROP PROCEDURE bug18293| +DROP TABLE t4| +SHOW BINLOG EVENTS FROM 397| +delimiter ;| + +# End of 5.0 tests + diff --git a/sql/item.cc b/sql/item.cc index a734984a496..567957db583 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2646,25 +2646,8 @@ const String *Item_param::query_val_str(String* str) const case STRING_VALUE: case LONG_DATA_VALUE: { - char *buf, *ptr; str->length(0); - if (str->reserve(str_value.length()*2+3)) - break; - - buf= str->c_ptr_quick(); - ptr= buf; - if (value.cs_info.character_set_client->escape_with_backslash_is_dangerous) - { - ptr= str_to_hex(ptr, str_value.ptr(), str_value.length()); - } - else - { - *ptr++= '\''; - ptr+= escape_string_for_mysql(str_value.charset(), ptr, 0, - str_value.ptr(), str_value.length()); - *ptr++='\''; - } - str->length((uint32) (ptr - buf)); + append_query_string(value.cs_info.character_set_client, &str_value, str); break; } case NULL_VALUE: diff --git a/sql/log_event.cc b/sql/log_event.cc index a177629590b..d7ad9501ffd 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -256,6 +256,37 @@ char *str_to_hex(char *to, const char *from, uint len) return to; // pointer to end 0 of 'to' } +/* + Append a version of the 'from' string suitable for use in a query to + the 'to' string. To generate a correct escaping, the character set + information in 'csinfo' is used. + */ +#ifndef MYSQL_CLIENT +int +append_query_string(CHARSET_INFO *csinfo, + String const *from, String *to) +{ + char *beg, *ptr; + uint32 const orig_len= to->length(); + if (to->reserve(orig_len + from->length()*2+3)) + return 1; + + beg= to->c_ptr_quick() + to->length(); + ptr= beg; + if (csinfo->escape_with_backslash_is_dangerous) + ptr= str_to_hex(ptr, from->ptr(), from->length()); + else + { + *ptr++= '\''; + ptr+= escape_string_for_mysql(from->charset(), ptr, 0, + from->ptr(), from->length()); + *ptr++='\''; + } + to->length(orig_len + ptr - beg); + return 0; +} +#endif + /* Prints a "session_var=value" string. Used by mysqlbinlog to print some SET commands just before it prints a query. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2eea891d51f..2068e7823db 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -547,6 +547,8 @@ bool delete_precheck(THD *thd, TABLE_LIST *tables); bool insert_precheck(THD *thd, TABLE_LIST *tables); bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); +int append_query_string(CHARSET_INFO *csinfo, + String const *from, String *to); void get_default_definer(THD *thd, LEX_USER *definer); LEX_USER *create_default_definer(THD *thd); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index ea2f67b3ba5..cec3a19a542 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -80,8 +80,8 @@ sp_map_item_type(enum enum_field_types type) /* Return a string representation of the Item value. - NOTE: this is a legacy-compatible implementation. It fails if the value - contains non-ordinary symbols, which should be escaped. + NOTE: If the item has a string result type, the string is escaped + according to its character set. SYNOPSIS item a pointer to the Item @@ -119,9 +119,9 @@ sp_get_item_value(Item *item, String *str) buf.append('_'); buf.append(result->charset()->csname); - buf.append('\''); - buf.append(*result); - buf.append('\''); + if (result->charset()->escape_with_backslash_is_dangerous) + buf.append(' '); + append_query_string(result->charset(), result, &buf); str->copy(buf); return str;