From 8455b6e1c9d318e5785110648d133d9939ed36da Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Thu, 24 May 2018 12:10:02 +0200 Subject: [PATCH 1/2] Changed default character set from utf8 (see fix for CONC-315) to latin1, which is also default behavior in MariaDB 10.1 To use another default character set, MariaDB Connector/C has to be build with CMake parameter -DDEFAUT_CHARSET=name. --- CMakeLists.txt | 5 +++++ include/ma_config.h.in | 2 ++ libmariadb/mariadb_charset.c | 2 +- libmariadb/mariadb_lib.c | 18 ++++++++++-------- unittest/libmariadb/connection.c | 7 ++++--- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b0cf187a..c3bba33c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -256,6 +256,11 @@ INCLUDE(${CC_SOURCE_DIR}/cmake/CheckFunctions.cmake) # check for various types INCLUDE(${CC_SOURCE_DIR}/cmake/CheckTypes.cmake) +IF(NOT DEFAULT_CHARSET) + SET(DEFAULT_CHARSET "latin1") +ENDIF() + + # convert SSL options to uppercase IF(WITH_SSL) STRING(TOUPPER ${WITH_SSL} WITH_SSL) diff --git a/include/ma_config.h.in b/include/ma_config.h.in index c25662fa..31ff0b87 100644 --- a/include/ma_config.h.in +++ b/include/ma_config.h.in @@ -265,3 +265,5 @@ #cmakedefine SOCKET_SIZE_TYPE @SOCKET_SIZE_TYPE@ +#define MARIADB_DEFAULT_CHARSET "@DEFAULT_CHARSET@" + diff --git a/libmariadb/mariadb_charset.c b/libmariadb/mariadb_charset.c index b249bf34..a406af2f 100644 --- a/libmariadb/mariadb_charset.c +++ b/libmariadb/mariadb_charset.c @@ -22,7 +22,7 @@ #include #include -MARIADB_CHARSET_INFO *ma_default_charset_info = (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[21]; +MARIADB_CHARSET_INFO *ma_default_charset_info; /* will be set in mysql_server_init */ MARIADB_CHARSET_INFO *ma_charset_bin= (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[32]; MARIADB_CHARSET_INFO *ma_charset_latin1= (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[5]; MARIADB_CHARSET_INFO *ma_charset_utf8_general_ci= (MARIADB_CHARSET_INFO *)&mariadb_compiled_charsets[21]; diff --git a/libmariadb/mariadb_lib.c b/libmariadb/mariadb_lib.c index 4a41ec00..0bba6132 100644 --- a/libmariadb/mariadb_lib.c +++ b/libmariadb/mariadb_lib.c @@ -90,6 +90,7 @@ extern my_bool mysql_ps_subsystem_initialized; extern my_bool mysql_handle_local_infile(MYSQL *mysql, const char *filename); extern const MARIADB_CHARSET_INFO * mysql_find_charset_nr(uint charsetnr); extern const MARIADB_CHARSET_INFO * mysql_find_charset_name(const char * const name); +extern my_bool set_default_charset_by_name(const char *cs_name, myf flags __attribute__((unused))); extern int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, const char *data_plugin, const char *db); extern int net_add_multi_command(NET *net, uchar command, const uchar *packet, @@ -994,7 +995,7 @@ mysql_init(MYSQL *mysql) goto error; mysql->options.report_data_truncation= 1; mysql->options.connect_timeout=CONNECT_TIMEOUT; - mysql->charset= ma_default_charset_info; + mysql->charset= mysql_find_charset_name(MARIADB_DEFAULT_CHARSET); mysql->methods= &MARIADB_DEFAULT_METHODS; strcpy(mysql->net.sqlstate, "00000"); mysql->net.last_error[0]= mysql->net.last_errno= 0; @@ -1483,7 +1484,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, if (mysql->options.charset_name) mysql->charset= mysql_find_charset_name(mysql->options.charset_name); else - mysql->charset=ma_default_charset_info; + mysql->charset=mysql_find_charset_name(MARIADB_DEFAULT_CHARSET); if (!mysql->charset) { @@ -1729,9 +1730,9 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, db=""; if (mysql->options.charset_name) - mysql->charset =mysql_find_charset_name(mysql->options.charset_name); + mysql->charset= mysql_find_charset_name(mysql->options.charset_name); else - mysql->charset=ma_default_charset_info; + mysql->charset=mysql_find_charset_name(MARIADB_DEFAULT_CHARSET); mysql->user= strdup(user ? user : ""); mysql->passwd= strdup(passwd ? passwd : ""); @@ -2909,16 +2910,16 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) { uchar *buffer; void *arg2= va_arg(ap, void *); - size_t key_len= arg1 ? strlen((char *)arg1) : 0, + size_t storage_len, key_len= arg1 ? strlen((char *)arg1) : 0, value_len= arg2 ? strlen((char *)arg2) : 0; if (!key_len || !value_len) { SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0); goto end; } - size_t storage_len= key_len + value_len + - get_store_length(key_len) + - get_store_length(value_len); + storage_len= key_len + value_len + + get_store_length(key_len) + + get_store_length(value_len); /* since we store terminating zero character in hash, we need * to increase lengths */ @@ -3486,6 +3487,7 @@ static void mysql_once_init() ma_init(); /* Will init threads */ init_client_errs(); get_default_configuration_dirs(); + set_default_charset_by_name(MARIADB_DEFAULT_CHARSET, 0); if (mysql_client_plugin_init()) { #ifdef _WIN32 diff --git a/unittest/libmariadb/connection.c b/unittest/libmariadb/connection.c index a2108270..fd5dac43 100644 --- a/unittest/libmariadb/connection.c +++ b/unittest/libmariadb/connection.c @@ -1365,12 +1365,13 @@ static int test_conc315(MYSQL *mysql) return SKIP; mysql_get_optionv(mysql, MYSQL_SET_CHARSET_NAME, (void *)&csname); - FAIL_UNLESS(strcmp(csname, "utf8") == 0, "Wrong default character set"); + diag("csname=%s", csname); + FAIL_UNLESS(strcmp(csname, MARIADB_DEFAULT_CHARSET) == 0, "Wrong default character set"); rc= mysql_change_user(mysql, username, password, schema); check_mysql_rc(rc, mysql); mysql_get_optionv(mysql, MYSQL_SET_CHARSET_NAME, (void *)&csname); - FAIL_UNLESS(strcmp(csname, "utf8") == 0, "Wrong default character set"); + FAIL_UNLESS(strcmp(csname, MARIADB_DEFAULT_CHARSET) == 0, "Wrong default character set"); return OK; } #ifndef WIN32 @@ -1491,7 +1492,7 @@ struct my_tests_st my_tests[] = { {"test_conc327", test_conc327, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc317", test_conc317, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, #endif - {"test_conc315", test_conc315, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"test_conc315", test_conc315, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_expired_pw", test_expired_pw, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc276", test_conc276, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_mdev13100", test_mdev13100, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, From 53c40f5aaab7262c2329863e0ac4fa52091167a0 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Tue, 29 May 2018 09:49:35 +0200 Subject: [PATCH 2/2] Fix for CONC334: Copy all members of MYSQL_FIELD from mysql->fields to stmt->fields. --- libmariadb/mariadb_stmt.c | 9 ++++++++- unittest/libmariadb/ps_bugs.c | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index d0ce3c29..9630387e 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -1854,6 +1854,12 @@ int stmt_read_execute_response(MYSQL_STMT *stmt) for (i=0; i < stmt->field_count; i++) { + memcpy(&stmt->fields[i], &mysql->fields[i], sizeof(MYSQL_FIELD)); + + /* since all pointers will be incorrect if another statement will + be executed, so we need to allocate memory and copy the + information */ + stmt->fields[i].extension= 0; /* not in use yet */ if (mysql->fields[i].db) stmt->fields[i].db= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].db); if (mysql->fields[i].table) @@ -1866,7 +1872,8 @@ int stmt_read_execute_response(MYSQL_STMT *stmt) stmt->fields[i].org_name= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].org_name); if (mysql->fields[i].catalog) stmt->fields[i].catalog= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].catalog); - stmt->fields[i].def= mysql->fields[i].def ? ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].def) : NULL; + if (mysql->fields[i].def) + stmt->fields[i].def= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].def); } } diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index 5fa72b74..5ad5345a 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -4690,7 +4690,43 @@ static int test_codbc138(MYSQL *mysql) return OK; } +static int test_conc334(MYSQL *mysql) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + MYSQL_RES *result; + MYSQL_FIELD *field; + int rc; + + rc= mysql_stmt_prepare(stmt, SL("SHOW ENGINES")); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + + result= mysql_stmt_result_metadata(stmt); + if (!result) + { + diag("Coudn't retrieve result set"); + mysql_stmt_close(stmt); + return FAIL; + } + + mysql_field_seek(result, 0); + + while ((field= mysql_fetch_field(result))) + { + FAIL_IF(field->name_length == 0, "Invalid name length (0)"); + FAIL_IF(field->table_length == 0, "Invalid name length (0)"); + } + mysql_free_result(result); + mysql_stmt_close(stmt); + + return OK; +} + + struct my_tests_st my_tests[] = { + {"test_conc334", test_conc334, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_compress", test_compress, TEST_CONNECTION_NEW, CLIENT_COMPRESS, NULL, NULL}, {"test_codbc138", test_codbc138, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc208", test_conc208, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},