summaryrefslogtreecommitdiffstats
path: root/libmariadb/unittest/libmariadb/charset.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmariadb/unittest/libmariadb/charset.c')
-rw-r--r--libmariadb/unittest/libmariadb/charset.c881
1 files changed, 881 insertions, 0 deletions
diff --git a/libmariadb/unittest/libmariadb/charset.c b/libmariadb/unittest/libmariadb/charset.c
new file mode 100644
index 00000000..b438f8d9
--- /dev/null
+++ b/libmariadb/unittest/libmariadb/charset.c
@@ -0,0 +1,881 @@
+/*
+Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+
+The MySQL Connector/C is licensed under the terms of the GPLv2
+<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
+MySQL Connectors. There are special exceptions to the terms and
+conditions of the GPLv2 as it is applied to this software, see the
+FLOSS License Exception
+<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published
+by the Free Software Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "my_test.h"
+
+/*
+ test gbk charset escaping
+
+ The important part is that 0x27 (') is the second-byte in a invalid
+ two-byte GBK character here. But 0xbf5c is a valid GBK character, so
+ it needs to be escaped as 0x5cbf27
+
+*/
+#define TEST_BUG8378_IN "\xef\xbb\xbf\x27\xbf\x10"
+#define TEST_BUG8378_OUT "\xef\xbb\x5c\xbf\x5c\x27\x5c\xbf\x10"
+
+/* set connection options */
+struct my_option_st opt_bug8378[] = {
+ {MYSQL_SET_CHARSET_NAME, (char *) "gbk"},
+ {0, NULL}
+};
+
+int bug_8378(MYSQL *mysql) {
+ int rc, len;
+ char out[9], buf[256];
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+
+ len= mysql_real_escape_string(mysql, out, TEST_BUG8378_IN, 4);
+ FAIL_IF(memcmp(out, TEST_BUG8378_OUT, len), "wrong result");
+
+ sprintf(buf, "SELECT '%s' FROM DUAL", TEST_BUG8378_OUT);
+
+ rc= mysql_query(mysql, buf);
+ check_mysql_rc(rc, mysql);
+
+ if ((res= mysql_store_result(mysql))) {
+ row= mysql_fetch_row(res);
+ if (memcmp(row[0], TEST_BUG8378_IN, 4)) {
+ mysql_free_result(res);
+ return FAIL;
+ }
+ mysql_free_result(res);
+ } else
+ return FAIL;
+
+ return OK;
+}
+
+int test_client_character_set(MYSQL *mysql)
+{
+ MY_CHARSET_INFO cs;
+ char *csname= (char*) "latin2";
+ char *csdefault= (char*)mysql_character_set_name(mysql);
+
+
+ FAIL_IF(mysql_set_character_set(mysql, csname), mysql_error(mysql));
+
+ mysql_get_character_set_info(mysql, &cs);
+
+ FAIL_IF(strcmp(cs.csname, "latin2") || strcmp(cs.name, "latin2_general_ci"),
+ "Character set != latin2");
+ FAIL_IF(mysql_set_character_set(mysql, csdefault), mysql_error(mysql));
+
+ return OK;
+}
+
+/*
+ * Regression test for bug #10214
+ *
+ * Test escaping with NO_BACKSLASH_ESCAPES
+ *
+ */
+int bug_10214(MYSQL *mysql)
+{
+ int len, rc;
+ char out[8];
+
+ /* reset sql_mode */
+ rc= mysql_query(mysql, "SET sql_mode=''");
+ check_mysql_rc(rc, mysql);
+
+ len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
+ FAIL_IF(memcmp(out, "a\\'b\\\\c", len), "wrong result");
+
+ rc= mysql_query(mysql, "set sql_mode='NO_BACKSLASH_ESCAPES'");
+ check_mysql_rc(rc, mysql);
+ FAIL_IF(!(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES),
+ "wrong server status: NO_BACKSLASH_ESCAPES not set");
+
+ len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
+ FAIL_IF(memcmp(out, "a''b\\c", len), "wrong result");
+
+ return OK;
+}
+
+/*
+ * simple escaping of special chars
+ */
+int test_escaping(MYSQL *mysql)
+{
+ int i= 0, rc, len;
+ char out[20];
+ const char *escape_chars[] = {"'", "\x0", "\n", "\r", "\\", "\0", NULL};
+
+ /* reset sql_mode, mysql_change_user call doesn't reset it */
+ rc= mysql_query(mysql, "SET sql_mode=''");
+ check_mysql_rc(rc, mysql);
+
+ while (escape_chars[i]) {
+ len= mysql_real_escape_string(mysql, out, escape_chars[i], 1);
+ FAIL_IF(len < 2, "Len < 2");
+ i++;
+ }
+
+ return OK;
+}
+
+/*
+ * server doesn't reset sql_mode after COM_CHANGE_USER
+ */
+int bug_41785(MYSQL *mysql)
+{
+ char out[10];
+ int rc, len;
+
+ len= mysql_real_escape_string(mysql, out, "\\", 1);
+ FAIL_IF(len != 2, "len != 2");
+
+ rc= mysql_query(mysql, "SET SQL_MODE=NO_BACKSLASH_ESCAPES");
+ check_mysql_rc(rc, mysql);
+ rc= mysql_query(mysql, "SET sql_mode=''");
+ check_mysql_rc(rc, mysql);
+
+ mysql_change_user(mysql, "root", "", "test");
+
+ len= mysql_real_escape_string(mysql, out, "\\", 1);
+ FAIL_IF(len != 2, "len != 2");
+
+ return OK;
+}
+
+static int test_conversion(MYSQL *mysql)
+{
+ MYSQL_STMT *stmt;
+ const char *stmt_text;
+ int rc;
+ MYSQL_BIND my_bind[1];
+ uchar buff[4];
+ ulong length;
+
+ stmt_text= "DROP TABLE IF EXISTS t1";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+ stmt_text= "CREATE TABLE t1 (a TEXT) DEFAULT CHARSET latin1";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+ stmt_text= "SET character_set_connection=utf8, character_set_client=utf8, "
+ " character_set_results=latin1";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+
+ stmt= mysql_stmt_init(mysql);
+ FAIL_IF(!stmt, mysql_error(mysql));
+ stmt_text= "INSERT INTO t1 (a) VALUES (?)";
+ rc= mysql_stmt_prepare(stmt, SL(stmt_text));
+ check_stmt_rc(rc, stmt);
+
+ memset(my_bind, '\0', sizeof(my_bind));
+ my_bind[0].buffer= (char*) buff;
+ my_bind[0].length= &length;
+ my_bind[0].buffer_type= MYSQL_TYPE_STRING;
+
+ mysql_stmt_bind_param(stmt, my_bind);
+
+ buff[0]= (uchar) 0xC3;
+ buff[1]= (uchar) 0xA0;
+ length= 2;
+
+ rc= mysql_stmt_execute(stmt);
+ check_stmt_rc(rc, stmt);
+
+ stmt_text= "SELECT a FROM t1";
+ rc= mysql_stmt_prepare(stmt, SL(stmt_text));
+ check_stmt_rc(rc, stmt);
+ rc= mysql_stmt_execute(stmt);
+ check_stmt_rc(rc, stmt);
+
+ my_bind[0].buffer_length= sizeof(buff);
+ mysql_stmt_bind_result(stmt, my_bind);
+
+ rc= mysql_stmt_fetch(stmt);
+ check_stmt_rc(rc, stmt);
+ FAIL_UNLESS(length == 1, "length != 1");
+ FAIL_UNLESS(buff[0] == 0xE0, "buff[0] != 0xE0");
+ rc= mysql_stmt_fetch(stmt);
+ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+
+ mysql_stmt_close(stmt);
+ stmt_text= "DROP TABLE t1";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+ stmt_text= "SET NAMES DEFAULT";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+
+ return OK;
+}
+
+static int test_bug27876(MYSQL *mysql)
+{
+ int rc;
+ MYSQL_RES *result;
+
+ uchar utf8_func[] =
+ {
+ 0xd1, 0x84, 0xd1, 0x83, 0xd0, 0xbd, 0xd0, 0xba,
+ 0xd1, 0x86, 0xd0, 0xb8, 0xd0, 0xb9, 0xd0, 0xba,
+ 0xd0, 0xb0,
+ 0x00
+ };
+
+ uchar utf8_param[] =
+ {
+ 0xd0, 0xbf, 0xd0, 0xb0, 0xd1, 0x80, 0xd0, 0xb0,
+ 0xd0, 0xbc, 0xd0, 0xb5, 0xd1, 0x82, 0xd1, 0x8a,
+ 0xd1, 0x80, 0x5f, 0xd0, 0xb2, 0xd0, 0xb5, 0xd1,
+ 0x80, 0xd1, 0x81, 0xd0, 0xb8, 0xd1, 0x8f,
+ 0x00
+ };
+
+ char query[500];
+
+ rc= mysql_query(mysql, "set names utf8");
+ check_mysql_rc(rc, mysql);
+
+ rc= mysql_query(mysql, "select version()");
+ check_mysql_rc(rc, mysql);
+ result= mysql_store_result(mysql);
+ FAIL_IF(!result, "Invalid result set");
+ mysql_free_result(result);
+
+ sprintf(query, "DROP FUNCTION IF EXISTS %s", (char*) utf8_func);
+ rc= mysql_query(mysql, query);
+ check_mysql_rc(rc, mysql);
+
+ sprintf(query,
+ "CREATE FUNCTION %s( %s VARCHAR(25))"
+ " RETURNS VARCHAR(25) DETERMINISTIC RETURN %s",
+ (char*) utf8_func, (char*) utf8_param, (char*) utf8_param);
+ rc= mysql_query(mysql, query);
+ check_mysql_rc(rc, mysql);
+ sprintf(query, "SELECT %s(VERSION())", (char*) utf8_func);
+ rc= mysql_query(mysql, query);
+ check_mysql_rc(rc, mysql);
+ result= mysql_store_result(mysql);
+ FAIL_IF(!result, "Invalid result set");
+ mysql_free_result(result);
+
+ sprintf(query, "DROP FUNCTION %s", (char*) utf8_func);
+ rc= mysql_query(mysql, query);
+ check_mysql_rc(rc, mysql);
+
+ rc= mysql_query(mysql, "set names default");
+ check_mysql_rc(rc, mysql);
+ return OK;
+}
+
+static int test_ps_i18n(MYSQL *mysql)
+{
+ MYSQL_STMT *stmt;
+ int rc;
+ const char *stmt_text;
+ MYSQL_BIND bind_array[2];
+
+ /* Represented as numbers to keep UTF8 tools from clobbering them. */
+ const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
+ const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
+ char buf1[16], buf2[16];
+ ulong buf1_len, buf2_len;
+
+ stmt_text= "DROP TABLE IF EXISTS t1";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+
+ /*
+ Create table with binary columns, set session character set to cp1251,
+ client character set to koi8, and make sure that there is conversion
+ on insert and no conversion on select
+ */
+
+ stmt_text= "CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+
+ stmt_text= "SET CHARACTER_SET_CLIENT=koi8r, "
+ "CHARACTER_SET_CONNECTION=cp1251, "
+ "CHARACTER_SET_RESULTS=koi8r";
+
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+
+ memset(bind_array, '\0', sizeof(bind_array));
+ bind_array[0].buffer_type= MYSQL_TYPE_STRING;
+ bind_array[0].buffer= (void *) koi8;
+ bind_array[0].buffer_length= (unsigned long)strlen(koi8);
+
+ bind_array[1].buffer_type= MYSQL_TYPE_STRING;
+ bind_array[1].buffer= (void *) koi8;
+ bind_array[1].buffer_length= (unsigned long)strlen(koi8);
+
+ stmt= mysql_stmt_init(mysql);
+ check_stmt_rc(rc, stmt);
+
+ stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
+
+ rc= mysql_stmt_prepare(stmt, SL(stmt_text));
+ check_stmt_rc(rc, stmt);
+ mysql_stmt_bind_param(stmt, bind_array);
+ check_stmt_rc(rc, stmt);
+
+// mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
+
+ rc= mysql_stmt_execute(stmt);
+ check_stmt_rc(rc, stmt);
+ stmt_text= "SELECT c1, c2 FROM t1";
+
+ /* c1 and c2 are binary so no conversion will be done on select */
+ rc= mysql_stmt_prepare(stmt, SL(stmt_text));
+ check_stmt_rc(rc, stmt);
+ rc= mysql_stmt_execute(stmt);
+ check_stmt_rc(rc, stmt);
+ bind_array[0].buffer= buf1;
+ bind_array[0].buffer_length= sizeof(buf1);
+ bind_array[0].length= &buf1_len;
+
+ bind_array[1].buffer= buf2;
+ bind_array[1].buffer_length= sizeof(buf2);
+ bind_array[1].length= &buf2_len;
+
+ mysql_stmt_bind_result(stmt, bind_array);
+
+ rc= mysql_stmt_fetch(stmt);
+ check_stmt_rc(rc, stmt);
+ FAIL_UNLESS(buf1_len == strlen(cp1251), "buf1_len != strlen(cp1251)");
+ FAIL_UNLESS(buf2_len == strlen(cp1251), "buf2_len != strlen(cp1251)");
+ FAIL_UNLESS(!memcmp(buf1, cp1251, buf1_len), "buf1 != cp1251");
+ FAIL_UNLESS(!memcmp(buf2, cp1251, buf1_len), "buf2 != cp1251");
+
+ rc= mysql_stmt_fetch(stmt);
+ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+
+ stmt_text= "DROP TABLE IF EXISTS t1";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+
+ /*
+ Now create table with two cp1251 columns, set client character
+ set to koi8 and supply columns of one row as string and another as
+ binary data. Binary data must not be converted on insert, and both
+ columns must be converted to client character set on select.
+ */
+
+ stmt_text= "CREATE TABLE t1 (c1 VARCHAR(255) CHARACTER SET cp1251, "
+ "c2 VARCHAR(255) CHARACTER SET cp1251)";
+
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+
+ stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
+
+ rc= mysql_stmt_prepare(stmt, SL(stmt_text));
+ check_stmt_rc(rc, stmt);
+ /* this data must be converted */
+ bind_array[0].buffer_type= MYSQL_TYPE_STRING;
+ bind_array[0].buffer= (void *) koi8;
+ bind_array[0].buffer_length= (unsigned long)strlen(koi8);
+
+ bind_array[1].buffer_type= MYSQL_TYPE_STRING;
+ bind_array[1].buffer= (void *) koi8;
+ bind_array[1].buffer_length= (unsigned long)strlen(koi8);
+
+ mysql_stmt_bind_param(stmt, bind_array);
+
+// mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
+
+ rc= mysql_stmt_execute(stmt);
+ check_stmt_rc(rc, stmt);
+ /* this data must not be converted */
+ bind_array[0].buffer_type= MYSQL_TYPE_BLOB;
+ bind_array[0].buffer= (void *) cp1251;
+ bind_array[0].buffer_length= (unsigned long)strlen(cp1251);
+
+ bind_array[1].buffer_type= MYSQL_TYPE_BLOB;
+ bind_array[1].buffer= (void *) cp1251;
+ bind_array[1].buffer_length= (unsigned long)strlen(cp1251);
+
+ mysql_stmt_bind_param(stmt, bind_array);
+
+// mysql_stmt_send_long_data(stmt, 0, cp1251, strlen(cp1251));
+
+ rc= mysql_stmt_execute(stmt);
+ check_stmt_rc(rc, stmt);
+ /* Fetch data and verify that rows are in koi8 */
+
+ stmt_text= "SELECT c1, c2 FROM t1";
+
+ /* c1 and c2 are binary so no conversion will be done on select */
+ rc= mysql_stmt_prepare(stmt, SL(stmt_text));
+ check_stmt_rc(rc, stmt);
+ rc= mysql_stmt_execute(stmt);
+ check_stmt_rc(rc, stmt);
+ bind_array[0].buffer= buf1;
+ bind_array[0].buffer_length= sizeof(buf1);
+ bind_array[0].length= &buf1_len;
+
+ bind_array[1].buffer= buf2;
+ bind_array[1].buffer_length= sizeof(buf2);
+ bind_array[1].length= &buf2_len;
+
+ mysql_stmt_bind_result(stmt, bind_array);
+
+ while ((rc= mysql_stmt_fetch(stmt)) == 0)
+ {
+ FAIL_UNLESS(buf1_len == strlen(koi8), "buf1_len != strlen(koi8)");
+ FAIL_UNLESS(buf2_len == strlen(koi8), "buf2_len != strlen(koi8)");
+ FAIL_UNLESS(!memcmp(buf1, koi8, buf1_len), "buf1 != koi8");
+ FAIL_UNLESS(!memcmp(buf2, koi8, buf1_len), "buf2 != koi8");
+ }
+ FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
+ mysql_stmt_close(stmt);
+
+ stmt_text= "DROP TABLE t1";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+ stmt_text= "SET NAMES DEFAULT";
+ rc= mysql_real_query(mysql, SL(stmt_text));
+ check_mysql_rc(rc, mysql);
+ return OK;
+}
+
+/*
+ Bug#30472: libmysql doesn't reset charset, insert_id after succ.
+ mysql_change_user() call row insertions.
+*/
+
+static int bug30472_retrieve_charset_info(MYSQL *con,
+ char *character_set_name,
+ char *character_set_client,
+ char *character_set_results,
+ char *collation_connection)
+{
+ MYSQL_RES *rs;
+ MYSQL_ROW row;
+ int rc;
+
+ /* Get the cached client character set name. */
+
+ strcpy(character_set_name, mysql_character_set_name(con));
+
+ /* Retrieve server character set information. */
+
+ rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_client'");
+ check_mysql_rc(rc, con);
+
+ rs= mysql_store_result(con);
+ FAIL_IF(!rs, "Invalid result set");
+ row= mysql_fetch_row(rs);
+ FAIL_IF(!row, "Couldn't fetch row");
+ strcpy(character_set_client, row[1]);
+ mysql_free_result(rs);
+
+ rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'");
+ check_mysql_rc(rc, con);
+ rs= mysql_store_result(con);
+ FAIL_IF(!rs, "Invalid result set");
+ row= mysql_fetch_row(rs);
+ FAIL_IF(!row, "Couldn't fetch row");
+ strcpy(character_set_results, row[1]);
+ mysql_free_result(rs);
+
+ rc= mysql_query(con, "SHOW VARIABLES LIKE 'collation_connection'");
+ check_mysql_rc(rc, con);
+ rs= mysql_store_result(con);
+ FAIL_IF(!rs, "Invalid result set");
+ row= mysql_fetch_row(rs);
+ FAIL_IF(!row, "Couldn't fetch row");
+ strcpy(collation_connection, row[1]);
+ mysql_free_result(rs);
+ return OK;
+}
+
+#define MY_CS_NAME_SIZE 32
+
+static int test_bug30472(MYSQL *mysql)
+{
+ int rc;
+
+ char character_set_name_1[MY_CS_NAME_SIZE];
+ char character_set_client_1[MY_CS_NAME_SIZE];
+ char character_set_results_1[MY_CS_NAME_SIZE];
+ char collation_connnection_1[MY_CS_NAME_SIZE];
+
+ char character_set_name_2[MY_CS_NAME_SIZE];
+ char character_set_client_2[MY_CS_NAME_SIZE];
+ char character_set_results_2[MY_CS_NAME_SIZE];
+ char collation_connnection_2[MY_CS_NAME_SIZE];
+
+ char character_set_name_3[MY_CS_NAME_SIZE];
+ char character_set_client_3[MY_CS_NAME_SIZE];
+ char character_set_results_3[MY_CS_NAME_SIZE];
+ char collation_connnection_3[MY_CS_NAME_SIZE];
+
+ char character_set_name_4[MY_CS_NAME_SIZE];
+ char character_set_client_4[MY_CS_NAME_SIZE];
+ char character_set_results_4[MY_CS_NAME_SIZE];
+ char collation_connnection_4[MY_CS_NAME_SIZE];
+
+ SKIP_MAXSCALE;
+
+ if (mysql_get_server_version(mysql) < 50100 || !is_mariadb)
+ {
+ diag("Test requires MySQL Server version 5.1 or above");
+ return SKIP;
+ }
+ /* Retrieve character set information. */
+
+ mysql_set_character_set(mysql, "latin1");
+ bug30472_retrieve_charset_info(mysql,
+ character_set_name_1,
+ character_set_client_1,
+ character_set_results_1,
+ collation_connnection_1);
+
+ /* Switch client character set. */
+
+ FAIL_IF(mysql_set_character_set(mysql, "ascii"),
+ "Setting cs to ascii failed");
+
+ /* Retrieve character set information. */
+
+ bug30472_retrieve_charset_info(mysql,
+ character_set_name_2,
+ character_set_client_2,
+ character_set_results_2,
+ collation_connnection_2);
+
+ /*
+ Check that
+ 1) character set has been switched and
+ 2) new character set is different from the original one.
+ */
+
+ FAIL_UNLESS(strcmp(character_set_name_2, "ascii") == 0, "cs_name != ascii");
+ FAIL_UNLESS(strcmp(character_set_client_2, "ascii") == 0, "cs_client != ascii");
+ FAIL_UNLESS(strcmp(character_set_results_2, "ascii") == 0, "cs_result != ascii");
+ FAIL_UNLESS(strcmp(collation_connnection_2, "ascii_general_ci") == 0,
+ "collation != ascii_general_ci");
+
+ diag("%s %s", character_set_name_1, character_set_name_2);
+ FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_2) != 0, "cs_name1 = cs_name2");
+ FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_2) != 0, "cs_client1 = cs_client2");
+ FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_2) != 0, "cs_result1 = cs_result2");
+ FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_2) != 0, "collation1 = collation2");
+
+ /* Call mysql_change_user() with the same username, password, database. */
+
+ rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
+ mysql_set_character_set(mysql, "latin1");
+ check_mysql_rc(rc, mysql);
+
+ /* Retrieve character set information. */
+
+ bug30472_retrieve_charset_info(mysql,
+ character_set_name_3,
+ character_set_client_3,
+ character_set_results_3,
+ collation_connnection_3);
+
+ /* Check that character set information has been reset. */
+
+ FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_3) == 0, "cs_name1 != cs_name3");
+ FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_3) == 0, "cs_client1 != cs_client3");
+ FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_3) == 0, "cs_result1 != cs_result3");
+ FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_3) == 0, "collation1 != collation3");
+
+ /* Change connection-default character set in the client. */
+
+ mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "latin2");
+
+ /*
+ Call mysql_change_user() in order to check that new connection will
+ have UTF8 character set on the client and on the server.
+ */
+
+ rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
+ check_mysql_rc(rc, mysql);
+
+ /* Retrieve character set information. */
+
+ bug30472_retrieve_charset_info(mysql,
+ character_set_name_4,
+ character_set_client_4,
+ character_set_results_4,
+ collation_connnection_4);
+
+ /* Check that we have UTF8 on the server and on the client. */
+
+ FAIL_UNLESS(strcmp(character_set_name_4, "latin2") == 0, "cs_name != latin2");
+ FAIL_UNLESS(strcmp(character_set_client_4, "latin2") == 0, "cs_client != latin2");
+ FAIL_UNLESS(strcmp(character_set_results_4, "latin2") == 0, "cs_result != latin2");
+ FAIL_UNLESS(strcmp(collation_connnection_4, "latin2_general_ci") == 0,
+ "collation_connection != latin2_general_ci");
+
+ /* That's it. Cleanup. */
+
+ return OK;
+}
+
+static int test_bug_54100(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ int rc;
+
+ rc= mysql_query(mysql, "SHOW CHARACTER SET");
+ check_mysql_rc(rc, mysql);
+
+ result= mysql_store_result(mysql);
+
+ while ((row= mysql_fetch_row(result)))
+ {
+ /* ignore ucs2 */
+ if (strcmp(row[0], "ucs2")
+ && strcmp(row[0], "utf16le")
+ && (strcmp(row[0], "utf8mb4") && mariadb_connection(mysql) && mysql_get_server_version(mysql) < 100600)
+ && (strcmp(row[0], "utf8") && mariadb_connection(mysql) && mysql_get_server_version(mysql) >= 100600)
+ && strcmp(row[0], "utf16")
+ && strcmp(row[0], "utf32")) {
+ rc= mysql_set_character_set(mysql, row[0]);
+ check_mysql_rc(rc, mysql);
+ }
+ }
+ mysql_free_result(result);
+
+ return OK;
+}
+
+
+/* We need this internal function for the test */
+
+static int test_utf16_utf32_noboms(MYSQL *mysql __attribute__((unused)))
+{
+#ifndef HAVE_ICONV
+ diag("MariaDB Connector/C was built without iconv support");
+ return SKIP;
+#else
+ const char *csname[]= {"utf16", "utf16le", "utf32", "utf8"};
+ MARIADB_CHARSET_INFO *csinfo[sizeof(csname)/sizeof(char*)];
+
+ const int UTF8= sizeof(csname)/sizeof(char*) - 1;
+
+ unsigned char in_string[][8]= {"\xd8\x02\xdc\x60\0", /* utf16(be) */
+ "\x02\xd8\x60\xdc\0", /* utf16le */
+ "\x00\x01\x08\x60\0\0\0", /* utf32(be) */
+ "\xF0\x90\xA1\xA0" }; /* utf8 */
+ size_t in_oct_len[]= {6, 6, 8, 5};
+
+ char buffer[8], as_hex[16];
+ int i, error;
+ size_t rc, in_len, out_len;
+
+ for (i= 0; i < (int)(sizeof(csname)/sizeof(char*)); ++i)
+ {
+ csinfo[i]= mariadb_get_charset_by_name(csname[i]);
+
+ if (csinfo[i] == NULL)
+ {
+ diag("Could not get cs info for %s", csname[i]);
+ return FAIL;
+ }
+ }
+
+ for (i= 0; i < UTF8; ++i)
+ {
+ in_len= in_oct_len[i];
+ out_len= sizeof(buffer);
+
+ diag("Converting %s->%s", csname[i], csname[UTF8]);
+ rc= mariadb_convert_string((char *)in_string[i], &in_len, csinfo[i], buffer, &out_len, csinfo[UTF8], &error);
+
+ FAIL_IF(rc == (size_t)-1, "Conversion failed");
+ FAIL_IF(rc != in_oct_len[UTF8], "Incorrect number of written bytes");
+
+ if (memcmp(buffer, in_string[UTF8], rc) != 0)
+ {
+ mysql_hex_string(as_hex, buffer, (unsigned long)rc);
+ diag("Converted string(%s) does not match the expected one", as_hex);
+ return FAIL;
+ }
+
+ in_len= in_oct_len[UTF8];
+ out_len= sizeof(buffer);
+
+ diag("Converting %s->%s", csname[UTF8], csname[i]);
+ rc= mariadb_convert_string((char *)in_string[UTF8], &in_len, csinfo[UTF8], buffer, &out_len, csinfo[i], &error);
+
+ FAIL_IF(rc == (size_t)-1, "Conversion failed");
+ diag("rc=%lu oct_len: %lu", (unsigned long)rc, (unsigned long)in_oct_len[i]);
+ FAIL_IF(rc != in_oct_len[i], "Incorrect number of written bytes");
+
+ if (memcmp(buffer, in_string[i], rc) != 0)
+ {
+ mysql_hex_string(as_hex, buffer, (unsigned long)rc);
+ diag("Converted string(%s) does not match the expected one", as_hex);
+ return FAIL;
+ }
+ }
+
+ return OK;
+#endif
+}
+
+static int charset_auto(MYSQL *my __attribute__((unused)))
+{
+ const char *csname1, *csname2;
+ const char *osname;
+ MYSQL *mysql= mysql_init(NULL);
+ int rc;
+
+ osname= madb_get_os_character_set();
+
+ mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "auto");
+
+ FAIL_IF(!my_test_connect(mysql, hostname, username,
+ password, schema, port, socketname, 0),
+ mysql_error(mysql));
+
+ csname1= mysql_character_set_name(mysql);
+ diag("Character set: %s os charset: %s", csname1, osname);
+
+ FAIL_IF(!strcasecmp(osname,"utf8") ? strncmp(osname, csname1, 4) :
+ strcmp(osname, csname1),
+ "character set is not os character set");
+ if (strcmp(osname, "utf8"))
+ {
+ rc= mysql_set_character_set(mysql, "utf8");
+ check_mysql_rc(rc, mysql);
+
+ csname2= mysql_character_set_name(mysql);
+ diag("Character set: %s", csname2);
+ FAIL_IF(!strcmp(csname2, csname1), "Wrong charset: expected utf8");
+
+ rc= mysql_set_character_set(mysql, "auto");
+ check_mysql_rc(rc, mysql);
+
+ csname2= mysql_character_set_name(mysql);
+ diag("Character set: %s", csname2);
+ FAIL_IF(strcmp(csname2, osname), "Wrong charset: expected os charset");
+ }
+ mysql_close(mysql);
+ return OK;
+}
+
+/* check if all server character sets are supported */
+static int test_conc223(MYSQL *mysql)
+{
+ int rc;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ int found= 0;
+ int mdev27266= 0;
+
+ SKIP_MYSQL(mysql);
+
+ /*
+ Test if we're running against an MDEV-27266 server.
+ It can be detected by the presense of the FULL_COLLATION_NAME
+ column in I_S.COLLATION_CHARACTER_SET_APPLICABILITY.
+ */
+ rc= mysql_query(mysql,
+ "SELECT COUNT(*) "
+ "FROM INFORMATION_SCHEMA.COLUMNS "
+ "WHERE COLUMN_NAME='FULL_COLLATION_NAME' "
+ " AND TABLE_NAME='COLLATION_CHARACTER_SET_APPLICABILITY'");
+ check_mysql_rc(rc, mysql);
+ res= mysql_store_result(mysql);
+ if ((row= mysql_fetch_row(res)))
+ mdev27266= atoi(row[0]);
+ mysql_free_result(res);
+ diag("MDEV-27266 aware server: %d", mdev27266);
+
+ /*
+ Now get the list of collations either from I_S.COLLATIONS
+ or I_S.COLLATION_CHARACTER_SET_APPLICABILITY,
+ depending on the MDEV-27266 server awareness.
+ */
+ if (mdev27266)
+ rc= mysql_query(mysql,
+ "SELECT ID, CHARACTER_SET_NAME, FULL_COLLATION_NAME "
+ "FROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY");
+ else
+ rc= mysql_query(mysql,
+ "SELECT ID, CHARACTER_SET_NAME, COLLATION_NAME "
+ "FROM INFORMATION_SCHEMA.COLLATIONS");
+ check_mysql_rc(rc, mysql);
+
+ res= mysql_store_result(mysql);
+ while ((row = mysql_fetch_row(res)))
+ {
+ int id;
+
+ if (row[0])
+ {
+ id= atoi(row[0]);
+ if (!mariadb_get_charset_by_nr(id))
+ {
+ diag("%04d %s %s", id, row[1], row[2]);
+ found++;
+ }
+ }
+ }
+ mysql_free_result(res);
+ if (found)
+ {
+ diag("%d character sets/collations not found", found);
+ return FAIL;
+ }
+ return OK;
+}
+
+struct my_tests_st my_tests[] = {
+ {"test_conc223", test_conc223, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {"charset_auto", charset_auto, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {"bug_8378: mysql_real_escape with gbk", bug_8378, TEST_CONNECTION_NEW, 0, opt_bug8378, NULL},
+ {"test_client_character_set", test_client_character_set, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {"bug_10214: mysql_real_escape with NO_BACKSLASH_ESCAPES", bug_10214, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {"test_escaping", test_escaping, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {"test_conversion", test_conversion, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {"bug_41785", bug_41785, TEST_CONNECTION_DEFAULT, 0, NULL, "not fixed yet"},
+ {"test_bug27876", test_bug27876, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {"test_bug30472", test_bug30472, TEST_CONNECTION_NEW, 0, NULL, NULL},
+ {"test_ps_i18n", test_ps_i18n, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {"test_bug_54100", test_bug_54100, TEST_CONNECTION_NEW, 0, NULL, NULL},
+ {"test_utf16_utf32_noboms", test_utf16_utf32_noboms, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
+ {NULL, NULL, 0, 0, NULL, 0}
+};
+
+
+int main(int argc, char **argv)
+{
+ if (argc > 1)
+ get_options(argc, argv);
+
+ get_envvars();
+
+ run_tests(my_tests);
+
+ return(exit_status());
+}