Details
-
Bug
-
Status: Open (View Workflow)
-
Major
-
Resolution: Unresolved
-
11.0.6
-
None
Description
When using C API prepared statements with a client character set different from the character set used for a table column, the statement can not be replicated.
Using the Connector/C specifically with these steps:
- mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "gbk");
- CREATE TABLE with a VARCHAR COLLATE utf8mb4
- mysql_stmt_prepare, mysql_stmt_bind_param
On the primary, the data given with mysql_stmt_bind_param will be interpreted as specified with MYSQL_SET_CHARSET_NAME, but the binary log will contain this:
SET @@session.character_set_client=gbk,@@session.collation_connection=28,@@session.collation_server=8/*!*/; |
INSERT INTO test_charset SET c=X'2D3E20B8B1B1BE203C2D' |
The hexadecimal literal here will be interpreted using the column's character set (which is not valid, because this is not UTF8).
Full C code:
#include "stdafx.h"
|
#include <assert.h>
|
#include "mysql.h"
|
|
|
int main(int argc, char* argv[]) |
{
|
int error_code; |
MYSQL* mysql = mysql_init(NULL);
|
assert(mysql != NULL); |
|
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "gbk"); |
MYSQL* mysql2 = mysql_real_connect(mysql, "localhost", "root", "", "test", 3307, NULL, 0); |
assert(mysql2 != NULL); |
error_code = mysql_query(mysql,
|
"CREATE TABLE IF NOT EXISTS `test_charset` (" |
"`c` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci'," |
"`t` TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()" |
")"); |
assert(error_code == 0); |
|
MYSQL_BIND bind;
|
MYSQL_STMT *stmt = mysql_stmt_init(mysql);
|
assert(stmt != NULL); |
char insert_statement[] = "INSERT INTO test_charset SET c=?"; |
// char insert_statement[] = "INSERT INTO test_charset SET c=CONVERT(?, CHAR)";
|
error_code = mysql_stmt_prepare(stmt, insert_statement, strlen(insert_statement)); |
assert(error_code == 0); |
memset(&bind, 0, sizeof(bind)); |
bind.buffer_type = MYSQL_TYPE_STRING;
|
bind.buffer = "-> \xB8\xB1\xB1\xBE <-"; |
bind.buffer_length = strlen((char*)bind.buffer); |
bind.length = &bind.buffer_length;
|
error_code = mysql_stmt_bind_param(stmt, &bind);
|
assert(error_code == 0); |
error_code = mysql_stmt_execute(stmt);
|
assert(error_code == 0); |
|
mysql_close(mysql);
|
|
return 0; |
}
|
I am honestly not sure where the bug here is.
- Is my prepared statement wrong, and I should have used CONVERT(?, CHAR) in the first place?
- Is the Connector/C doing something wrong here?
- Is the statement recorded in the binary log wrong?
- Should any binary string when converted to a text string interpreted according to character_set_connection (or character_set_client)?