1 /*
2 Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4 The MySQL Connector/C is licensed under the terms of the GPLv2
5 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
6 MySQL Connectors. There are special exceptions to the terms and
7 conditions of the GPLv2 as it is applied to this software, see the
8 FLOSS License Exception
9 <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
10 
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published
13 by the Free Software Foundation; version 2 of the License.
14 
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 for more details.
19 
20 You should have received a copy of the GNU General Public License along
21 with this program; if not, write to the Free Software Foundation, Inc.,
22 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include "my_test.h"
26 
27 /*
28  test gbk charset escaping
29 
30  The important part is that 0x27 (') is the second-byte in a invalid
31  two-byte GBK character here. But 0xbf5c is a valid GBK character, so
32  it needs to be escaped as 0x5cbf27
33 
34 */
35 #define TEST_BUG8378_IN  "\xef\xbb\xbf\x27\xbf\x10"
36 #define TEST_BUG8378_OUT "\xef\xbb\x5c\xbf\x5c\x27\x5c\xbf\x10"
37 
38 /* set connection options */
39 struct my_option_st opt_bug8378[] = {
40   {MYSQL_SET_CHARSET_NAME, (char *) "gbk"},
41   {0, NULL}
42 };
43 
bug_8378(MYSQL * mysql)44 int bug_8378(MYSQL *mysql) {
45   int rc, len;
46   char out[9], buf[256];
47   MYSQL_RES *res;
48   MYSQL_ROW row;
49 
50   len= mysql_real_escape_string(mysql, out, TEST_BUG8378_IN, 4);
51   FAIL_IF(memcmp(out, TEST_BUG8378_OUT, len), "wrong result");
52 
53   sprintf(buf, "SELECT '%s' FROM DUAL", TEST_BUG8378_OUT);
54 
55   rc= mysql_query(mysql, buf);
56   check_mysql_rc(rc, mysql);
57 
58   if ((res= mysql_store_result(mysql))) {
59     row= mysql_fetch_row(res);
60     if (memcmp(row[0], TEST_BUG8378_IN, 4)) {
61       mysql_free_result(res);
62       return FAIL;
63     }
64     mysql_free_result(res);
65   } else
66     return FAIL;
67 
68   return OK;
69 }
70 
test_client_character_set(MYSQL * mysql)71 int test_client_character_set(MYSQL *mysql)
72 {
73   MY_CHARSET_INFO cs;
74   char *csname= (char*) "utf8";
75   char *csdefault= (char*)mysql_character_set_name(mysql);
76 
77   FAIL_IF(mysql_set_character_set(mysql, csname), mysql_error(mysql));
78 
79   mysql_get_character_set_info(mysql, &cs);
80 
81   FAIL_IF(strcmp(cs.csname, "utf8") || strcmp(cs.name, "utf8_general_ci"), "Character set != UTF8");
82   FAIL_IF(mysql_set_character_set(mysql, csdefault), mysql_error(mysql));
83 
84   return OK;
85 }
86 
87 /*
88  * Regression test for bug #10214
89  *
90  * Test escaping with NO_BACKSLASH_ESCAPES
91  *
92  */
bug_10214(MYSQL * mysql)93 int bug_10214(MYSQL *mysql)
94 {
95   int   len, rc;
96   char  out[8];
97 
98   /* reset sql_mode */
99   rc= mysql_query(mysql, "SET sql_mode=''");
100   check_mysql_rc(rc, mysql);
101 
102   len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
103   FAIL_IF(memcmp(out, "a\\'b\\\\c", len), "wrong result");
104 
105   rc= mysql_query(mysql, "set sql_mode='NO_BACKSLASH_ESCAPES'");
106   check_mysql_rc(rc, mysql);
107   FAIL_IF(!(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES),
108           "wrong server status: NO_BACKSLASH_ESCAPES not set");
109 
110   len= mysql_real_escape_string(mysql, out, "a'b\\c", 5);
111   FAIL_IF(memcmp(out, "a''b\\c", len), "wrong result");
112 
113   return OK;
114 }
115 
116 /*
117  *  simple escaping of special chars
118  */
test_escaping(MYSQL * mysql)119 int test_escaping(MYSQL *mysql)
120 {
121   int i= 0, rc, len;
122   char out[20];
123   const char *escape_chars[] = {"'", "\x0", "\n", "\r", "\\", "\0", NULL};
124 
125   /* reset sql_mode, mysql_change_user call doesn't reset it */
126   rc= mysql_query(mysql, "SET sql_mode=''");
127   check_mysql_rc(rc, mysql);
128 
129   while (escape_chars[i]) {
130     len= mysql_real_escape_string(mysql, out, escape_chars[i], 1);
131     FAIL_IF(len < 2, "Len < 2");
132     i++;
133   }
134 
135   return OK;
136 }
137 
138 /*
139  * server doesn't reset sql_mode after COM_CHANGE_USER
140  */
bug_41785(MYSQL * mysql)141 int bug_41785(MYSQL *mysql)
142 {
143   char out[10];
144   int rc, len;
145 
146   len= mysql_real_escape_string(mysql, out, "\\", 1);
147   FAIL_IF(len != 2, "len != 2");
148 
149   rc= mysql_query(mysql, "SET SQL_MODE=NO_BACKSLASH_ESCAPES");
150   check_mysql_rc(rc, mysql);
151   rc= mysql_query(mysql, "SET sql_mode=''");
152   check_mysql_rc(rc, mysql);
153 
154   mysql_change_user(mysql, "root", "", "test");
155 
156   len= mysql_real_escape_string(mysql, out, "\\", 1);
157   FAIL_IF(len != 2, "len != 2");
158 
159   return OK;
160 }
161 
test_conversion(MYSQL * mysql)162 static int test_conversion(MYSQL *mysql)
163 {
164   MYSQL_STMT *stmt;
165   const char *stmt_text;
166   int rc;
167   MYSQL_BIND my_bind[1];
168   uchar buff[4];
169   ulong length;
170 
171   stmt_text= "DROP TABLE IF EXISTS t1";
172   rc= mysql_real_query(mysql, SL(stmt_text));
173   check_mysql_rc(rc, mysql);
174   stmt_text= "CREATE TABLE t1 (a TEXT) DEFAULT CHARSET latin1";
175   rc= mysql_real_query(mysql, SL(stmt_text));
176   check_mysql_rc(rc, mysql);
177   stmt_text= "SET character_set_connection=utf8, character_set_client=utf8, "
178              " character_set_results=latin1";
179   rc= mysql_real_query(mysql, SL(stmt_text));
180   check_mysql_rc(rc, mysql);
181 
182   stmt= mysql_stmt_init(mysql);
183   FAIL_IF(!stmt, mysql_error(mysql));
184   stmt_text= "INSERT INTO t1 (a) VALUES (?)";
185   rc= mysql_stmt_prepare(stmt, SL(stmt_text));
186   check_stmt_rc(rc, stmt);
187 
188   memset(my_bind, '\0', sizeof(my_bind));
189   my_bind[0].buffer= (char*) buff;
190   my_bind[0].length= &length;
191   my_bind[0].buffer_type= MYSQL_TYPE_STRING;
192 
193   mysql_stmt_bind_param(stmt, my_bind);
194 
195   buff[0]= (uchar) 0xC3;
196   buff[1]= (uchar) 0xA0;
197   length= 2;
198 
199   rc= mysql_stmt_execute(stmt);
200   check_stmt_rc(rc, stmt);
201 
202   stmt_text= "SELECT a FROM t1";
203   rc= mysql_stmt_prepare(stmt, SL(stmt_text));
204   check_stmt_rc(rc, stmt);
205   rc= mysql_stmt_execute(stmt);
206   check_stmt_rc(rc, stmt);
207 
208   my_bind[0].buffer_length= sizeof(buff);
209   mysql_stmt_bind_result(stmt, my_bind);
210 
211   rc= mysql_stmt_fetch(stmt);
212   check_stmt_rc(rc, stmt);
213   FAIL_UNLESS(length == 1, "length != 1");
214   FAIL_UNLESS(buff[0] == 0xE0, "buff[0] != 0xE0");
215   rc= mysql_stmt_fetch(stmt);
216   FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
217 
218   mysql_stmt_close(stmt);
219   stmt_text= "DROP TABLE t1";
220   rc= mysql_real_query(mysql, SL(stmt_text));
221   check_mysql_rc(rc, mysql);
222   stmt_text= "SET NAMES DEFAULT";
223   rc= mysql_real_query(mysql, SL(stmt_text));
224   check_mysql_rc(rc, mysql);
225 
226   return OK;
227 }
228 
test_bug27876(MYSQL * mysql)229 static int test_bug27876(MYSQL *mysql)
230 {
231   int rc;
232   MYSQL_RES *result;
233 
234   uchar utf8_func[] =
235   {
236     0xd1, 0x84, 0xd1, 0x83, 0xd0, 0xbd, 0xd0, 0xba,
237     0xd1, 0x86, 0xd0, 0xb8, 0xd0, 0xb9, 0xd0, 0xba,
238     0xd0, 0xb0,
239     0x00
240   };
241 
242   uchar utf8_param[] =
243   {
244     0xd0, 0xbf, 0xd0, 0xb0, 0xd1, 0x80, 0xd0, 0xb0,
245     0xd0, 0xbc, 0xd0, 0xb5, 0xd1, 0x82, 0xd1, 0x8a,
246     0xd1, 0x80, 0x5f, 0xd0, 0xb2, 0xd0, 0xb5, 0xd1,
247     0x80, 0xd1, 0x81, 0xd0, 0xb8, 0xd1, 0x8f,
248     0x00
249   };
250 
251   char query[500];
252 
253   rc= mysql_query(mysql, "set names utf8");
254   check_mysql_rc(rc, mysql);
255 
256   rc= mysql_query(mysql, "select version()");
257   check_mysql_rc(rc, mysql);
258   result= mysql_store_result(mysql);
259   FAIL_IF(!result, "Invalid result set");
260   mysql_free_result(result);
261 
262   sprintf(query, "DROP FUNCTION IF EXISTS %s", (char*) utf8_func);
263   rc= mysql_query(mysql, query);
264   check_mysql_rc(rc, mysql);
265 
266   sprintf(query,
267           "CREATE FUNCTION %s( %s VARCHAR(25))"
268           " RETURNS VARCHAR(25) DETERMINISTIC RETURN %s",
269           (char*) utf8_func, (char*) utf8_param, (char*) utf8_param);
270   rc= mysql_query(mysql, query);
271   check_mysql_rc(rc, mysql);
272   sprintf(query, "SELECT %s(VERSION())", (char*) utf8_func);
273   rc= mysql_query(mysql, query);
274   check_mysql_rc(rc, mysql);
275   result= mysql_store_result(mysql);
276   FAIL_IF(!result, "Invalid result set");
277   mysql_free_result(result);
278 
279   sprintf(query, "DROP FUNCTION %s", (char*) utf8_func);
280   rc= mysql_query(mysql, query);
281   check_mysql_rc(rc, mysql);
282 
283   rc= mysql_query(mysql, "set names default");
284   check_mysql_rc(rc, mysql);
285   return OK;
286 }
287 
test_ps_i18n(MYSQL * mysql)288 static int test_ps_i18n(MYSQL *mysql)
289 {
290   MYSQL_STMT *stmt;
291   int rc;
292   const char *stmt_text;
293   MYSQL_BIND bind_array[2];
294 
295   /* Represented as numbers to keep UTF8 tools from clobbering them. */
296   const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
297   const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
298   char buf1[16], buf2[16];
299   ulong buf1_len, buf2_len;
300 
301   stmt_text= "DROP TABLE IF EXISTS t1";
302   rc= mysql_real_query(mysql, SL(stmt_text));
303   check_mysql_rc(rc, mysql);
304 
305   /*
306     Create table with binary columns, set session character set to cp1251,
307     client character set to koi8, and make sure that there is conversion
308     on insert and no conversion on select
309   */
310 
311   stmt_text= "CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))";
312   rc= mysql_real_query(mysql, SL(stmt_text));
313   check_mysql_rc(rc, mysql);
314 
315   stmt_text= "SET CHARACTER_SET_CLIENT=koi8r, "
316                  "CHARACTER_SET_CONNECTION=cp1251, "
317                  "CHARACTER_SET_RESULTS=koi8r";
318 
319   rc= mysql_real_query(mysql, SL(stmt_text));
320   check_mysql_rc(rc, mysql);
321 
322   memset(bind_array, '\0', sizeof(bind_array));
323   bind_array[0].buffer_type= MYSQL_TYPE_STRING;
324   bind_array[0].buffer= (void *) koi8;
325   bind_array[0].buffer_length= (unsigned long)strlen(koi8);
326 
327   bind_array[1].buffer_type= MYSQL_TYPE_STRING;
328   bind_array[1].buffer= (void *) koi8;
329   bind_array[1].buffer_length= (unsigned long)strlen(koi8);
330 
331   stmt= mysql_stmt_init(mysql);
332   check_stmt_rc(rc, stmt);
333 
334   stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
335 
336   rc= mysql_stmt_prepare(stmt, SL(stmt_text));
337   check_stmt_rc(rc, stmt);
338   mysql_stmt_bind_param(stmt, bind_array);
339   check_stmt_rc(rc, stmt);
340 
341 //  mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
342 
343   rc= mysql_stmt_execute(stmt);
344   check_stmt_rc(rc, stmt);
345   stmt_text= "SELECT c1, c2 FROM t1";
346 
347   /* c1 and c2 are binary so no conversion will be done on select */
348   rc= mysql_stmt_prepare(stmt, SL(stmt_text));
349   check_stmt_rc(rc, stmt);
350   rc= mysql_stmt_execute(stmt);
351   check_stmt_rc(rc, stmt);
352   bind_array[0].buffer= buf1;
353   bind_array[0].buffer_length= sizeof(buf1);
354   bind_array[0].length= &buf1_len;
355 
356   bind_array[1].buffer= buf2;
357   bind_array[1].buffer_length= sizeof(buf2);
358   bind_array[1].length= &buf2_len;
359 
360   mysql_stmt_bind_result(stmt, bind_array);
361 
362   rc= mysql_stmt_fetch(stmt);
363   check_stmt_rc(rc, stmt);
364   FAIL_UNLESS(buf1_len == strlen(cp1251), "buf1_len != strlen(cp1251)");
365   FAIL_UNLESS(buf2_len == strlen(cp1251), "buf2_len != strlen(cp1251)");
366   FAIL_UNLESS(!memcmp(buf1, cp1251, buf1_len), "buf1 != cp1251");
367   FAIL_UNLESS(!memcmp(buf2, cp1251, buf1_len), "buf2 != cp1251");
368 
369   rc= mysql_stmt_fetch(stmt);
370   FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
371 
372   stmt_text= "DROP TABLE IF EXISTS t1";
373   rc= mysql_real_query(mysql, SL(stmt_text));
374   check_mysql_rc(rc, mysql);
375 
376   /*
377     Now create table with two cp1251 columns, set client character
378     set to koi8 and supply columns of one row as string and another as
379     binary data. Binary data must not be converted on insert, and both
380     columns must be converted to client character set on select.
381   */
382 
383   stmt_text= "CREATE TABLE t1 (c1 VARCHAR(255) CHARACTER SET cp1251, "
384                               "c2 VARCHAR(255) CHARACTER SET cp1251)";
385 
386   rc= mysql_real_query(mysql, SL(stmt_text));
387   check_mysql_rc(rc, mysql);
388 
389   stmt_text= "INSERT INTO t1 (c1, c2) VALUES (?, ?)";
390 
391   rc= mysql_stmt_prepare(stmt, SL(stmt_text));
392   check_stmt_rc(rc, stmt);
393   /* this data must be converted */
394   bind_array[0].buffer_type= MYSQL_TYPE_STRING;
395   bind_array[0].buffer= (void *) koi8;
396   bind_array[0].buffer_length= (unsigned long)strlen(koi8);
397 
398   bind_array[1].buffer_type= MYSQL_TYPE_STRING;
399   bind_array[1].buffer= (void *) koi8;
400   bind_array[1].buffer_length= (unsigned long)strlen(koi8);
401 
402   mysql_stmt_bind_param(stmt, bind_array);
403 
404 //  mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
405 
406   rc= mysql_stmt_execute(stmt);
407   check_stmt_rc(rc, stmt);
408   /* this data must not be converted */
409   bind_array[0].buffer_type= MYSQL_TYPE_BLOB;
410   bind_array[0].buffer= (void *) cp1251;
411   bind_array[0].buffer_length= (unsigned long)strlen(cp1251);
412 
413   bind_array[1].buffer_type= MYSQL_TYPE_BLOB;
414   bind_array[1].buffer= (void *) cp1251;
415   bind_array[1].buffer_length= (unsigned long)strlen(cp1251);
416 
417   mysql_stmt_bind_param(stmt, bind_array);
418 
419 //  mysql_stmt_send_long_data(stmt, 0, cp1251, strlen(cp1251));
420 
421   rc= mysql_stmt_execute(stmt);
422   check_stmt_rc(rc, stmt);
423   /* Fetch data and verify that rows are in koi8 */
424 
425   stmt_text= "SELECT c1, c2 FROM t1";
426 
427   /* c1 and c2 are binary so no conversion will be done on select */
428   rc= mysql_stmt_prepare(stmt, SL(stmt_text));
429   check_stmt_rc(rc, stmt);
430   rc= mysql_stmt_execute(stmt);
431   check_stmt_rc(rc, stmt);
432   bind_array[0].buffer= buf1;
433   bind_array[0].buffer_length= sizeof(buf1);
434   bind_array[0].length= &buf1_len;
435 
436   bind_array[1].buffer= buf2;
437   bind_array[1].buffer_length= sizeof(buf2);
438   bind_array[1].length= &buf2_len;
439 
440   mysql_stmt_bind_result(stmt, bind_array);
441 
442   while ((rc= mysql_stmt_fetch(stmt)) == 0)
443   {
444     FAIL_UNLESS(buf1_len == strlen(koi8), "buf1_len != strlen(koi8)");
445     FAIL_UNLESS(buf2_len == strlen(koi8), "buf2_len != strlen(koi8)");
446     FAIL_UNLESS(!memcmp(buf1, koi8, buf1_len), "buf1 != koi8");
447     FAIL_UNLESS(!memcmp(buf2, koi8, buf1_len), "buf2 != koi8");
448   }
449   FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA");
450   mysql_stmt_close(stmt);
451 
452   stmt_text= "DROP TABLE t1";
453   rc= mysql_real_query(mysql, SL(stmt_text));
454   check_mysql_rc(rc, mysql);
455   stmt_text= "SET NAMES DEFAULT";
456   rc= mysql_real_query(mysql, SL(stmt_text));
457   check_mysql_rc(rc, mysql);
458   return OK;
459 }
460 
461 /*
462   Bug#30472: libmysql doesn't reset charset, insert_id after succ.
463   mysql_change_user() call row insertions.
464 */
465 
bug30472_retrieve_charset_info(MYSQL * con,char * character_set_name,char * character_set_client,char * character_set_results,char * collation_connection)466 static int bug30472_retrieve_charset_info(MYSQL *con,
467                                            char *character_set_name,
468                                            char *character_set_client,
469                                            char *character_set_results,
470                                            char *collation_connection)
471 {
472   MYSQL_RES *rs;
473   MYSQL_ROW row;
474   int       rc;
475 
476   /* Get the cached client character set name. */
477 
478   strcpy(character_set_name, mysql_character_set_name(con));
479 
480   /* Retrieve server character set information. */
481 
482   rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_client'");
483   check_mysql_rc(rc, con);
484 
485   rs= mysql_store_result(con);
486   FAIL_IF(!rs, "Invalid result set");
487   row= mysql_fetch_row(rs);
488   FAIL_IF(!row, "Couldn't fetch row");
489   strcpy(character_set_client, row[1]);
490   mysql_free_result(rs);
491 
492   rc= mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'");
493   check_mysql_rc(rc, con);
494   rs= mysql_store_result(con);
495   FAIL_IF(!rs, "Invalid result set");
496   row= mysql_fetch_row(rs);
497   FAIL_IF(!row, "Couldn't fetch row");
498   strcpy(character_set_results, row[1]);
499   mysql_free_result(rs);
500 
501   rc= mysql_query(con, "SHOW VARIABLES LIKE 'collation_connection'");
502   check_mysql_rc(rc, con);
503   rs= mysql_store_result(con);
504   FAIL_IF(!rs, "Invalid result set");
505   row= mysql_fetch_row(rs);
506   FAIL_IF(!row, "Couldn't fetch row");
507   strcpy(collation_connection, row[1]);
508   mysql_free_result(rs);
509   return OK;
510 }
511 
512 #define MY_CS_NAME_SIZE 32
513 
test_bug30472(MYSQL * mysql)514 static int test_bug30472(MYSQL *mysql)
515 {
516   int   rc;
517 
518   char character_set_name_1[MY_CS_NAME_SIZE];
519   char character_set_client_1[MY_CS_NAME_SIZE];
520   char character_set_results_1[MY_CS_NAME_SIZE];
521   char collation_connnection_1[MY_CS_NAME_SIZE];
522 
523   char character_set_name_2[MY_CS_NAME_SIZE];
524   char character_set_client_2[MY_CS_NAME_SIZE];
525   char character_set_results_2[MY_CS_NAME_SIZE];
526   char collation_connnection_2[MY_CS_NAME_SIZE];
527 
528   char character_set_name_3[MY_CS_NAME_SIZE];
529   char character_set_client_3[MY_CS_NAME_SIZE];
530   char character_set_results_3[MY_CS_NAME_SIZE];
531   char collation_connnection_3[MY_CS_NAME_SIZE];
532 
533   char character_set_name_4[MY_CS_NAME_SIZE];
534   char character_set_client_4[MY_CS_NAME_SIZE];
535   char character_set_results_4[MY_CS_NAME_SIZE];
536   char collation_connnection_4[MY_CS_NAME_SIZE];
537 
538   SKIP_MAXSCALE;
539 
540   if (mysql_get_server_version(mysql) < 50100 || !is_mariadb)
541   {
542     diag("Test requires MySQL Server version 5.1 or above");
543     return SKIP;
544   }
545   /* Retrieve character set information. */
546 
547   mysql_set_character_set(mysql, "latin1");
548   bug30472_retrieve_charset_info(mysql,
549                                  character_set_name_1,
550                                  character_set_client_1,
551                                  character_set_results_1,
552                                  collation_connnection_1);
553 
554   /* Switch client character set. */
555 
556   FAIL_IF(mysql_set_character_set(mysql, "utf8"), "Setting cs to utf8 failed");
557 
558   /* Retrieve character set information. */
559 
560   bug30472_retrieve_charset_info(mysql,
561                                  character_set_name_2,
562                                  character_set_client_2,
563                                  character_set_results_2,
564                                  collation_connnection_2);
565 
566   /*
567     Check that
568       1) character set has been switched and
569       2) new character set is different from the original one.
570   */
571 
572   FAIL_UNLESS(strncmp(character_set_name_2, "utf8", 4) == 0, "cs_name != utf8");
573   FAIL_UNLESS(strncmp(character_set_client_2, "utf8", 4) == 0, "cs_client != utf8");
574   FAIL_UNLESS(strncmp(character_set_results_2, "utf8", 4) == 0, "cs_result != ut8");
575   if (mariadb_connection(mysql) && mysql_get_server_version(mysql) < 100600) {
576     FAIL_UNLESS(strcmp(collation_connnection_2, "utf8_general_ci") == 0, "collation != utf8_general_ci");
577   } else {
578     FAIL_UNLESS(strcmp(collation_connnection_2, "utf8mb3_general_ci") == 0, "collation != utf8_general_ci");
579   }
580 
581   diag("%s %s", character_set_name_1, character_set_name_2);
582   FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_2) != 0, "cs_name1 = cs_name2");
583   FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_2) != 0, "cs_client1 = cs_client2");
584   FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_2) != 0, "cs_result1 = cs_result2");
585   FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_2) != 0, "collation1 = collation2");
586 
587   /* Call mysql_change_user() with the same username, password, database. */
588 
589   rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
590   mysql_set_character_set(mysql, "latin1");
591   check_mysql_rc(rc, mysql);
592 
593   /* Retrieve character set information. */
594 
595   bug30472_retrieve_charset_info(mysql,
596                                  character_set_name_3,
597                                  character_set_client_3,
598                                  character_set_results_3,
599                                  collation_connnection_3);
600 
601   /* Check that character set information has been reset. */
602 
603   FAIL_UNLESS(strcmp(character_set_name_1, character_set_name_3) == 0, "cs_name1 != cs_name3");
604   FAIL_UNLESS(strcmp(character_set_client_1, character_set_client_3) == 0, "cs_client1 != cs_client3");
605   FAIL_UNLESS(strcmp(character_set_results_1, character_set_results_3) == 0, "cs_result1 != cs_result3");
606   FAIL_UNLESS(strcmp(collation_connnection_1, collation_connnection_3) == 0, "collation1 != collation3");
607 
608   /* Change connection-default character set in the client. */
609 
610   mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8");
611 
612   /*
613     Call mysql_change_user() in order to check that new connection will
614     have UTF8 character set on the client and on the server.
615   */
616 
617   rc= mysql_change_user(mysql, username, password, (schema) ? schema : "test");
618   check_mysql_rc(rc, mysql);
619 
620   /* Retrieve character set information. */
621 
622   bug30472_retrieve_charset_info(mysql,
623                                  character_set_name_4,
624                                  character_set_client_4,
625                                  character_set_results_4,
626                                  collation_connnection_4);
627 
628   /* Check that we have UTF8 on the server and on the client. */
629   FAIL_UNLESS(strcmp(character_set_name_4, "utf8") == 0, "cs_name != utf8");
630   if (mariadb_connection(mysql) && mysql_get_server_version(mysql) < 100600) {
631     FAIL_UNLESS(strcmp(character_set_client_4, "utf8") == 0, "cs_client != utf8");
632     FAIL_UNLESS(strcmp(character_set_results_4, "utf8") == 0, "cs_result != utf8");
633     FAIL_UNLESS(strcmp(collation_connnection_4, "utf8_general_ci") == 0, "collation_connection != utf8_general_ci");
634   } else {
635     FAIL_UNLESS(strcmp(character_set_client_4, "utf8mb3") == 0, "cs_client != utf8");
636     FAIL_UNLESS(strcmp(character_set_results_4, "utf8mb3") == 0, "cs_result != utf8");
637     FAIL_UNLESS(strcmp(collation_connnection_4, "utf8mb3_general_ci") == 0, "collation_connection != utf8_general_ci");
638   }
639 
640   /* That's it. Cleanup. */
641 
642   return OK;
643 }
644 
test_bug_54100(MYSQL * mysql)645 static int test_bug_54100(MYSQL *mysql)
646 {
647   MYSQL_RES *result;
648   MYSQL_ROW row;
649   int rc;
650 
651   rc= mysql_query(mysql, "SHOW CHARACTER SET");
652   check_mysql_rc(rc, mysql);
653 
654   result= mysql_store_result(mysql);
655 
656   while ((row= mysql_fetch_row(result)))
657   {
658     /* ignore ucs2 */
659     if (strcmp(row[0], "ucs2")
660         && strcmp(row[0], "utf16le")
661         && (strcmp(row[0], "utf8mb4") && mariadb_connection(mysql) && mysql_get_server_version(mysql) < 100600)
662         && (strcmp(row[0], "utf8") && mariadb_connection(mysql) && mysql_get_server_version(mysql) >= 100600)
663         && strcmp(row[0], "utf16")
664         && strcmp(row[0], "utf32")) {
665       rc= mysql_set_character_set(mysql, row[0]);
666       check_mysql_rc(rc, mysql);
667     }
668   }
669   mysql_free_result(result);
670 
671   return OK;
672 }
673 
674 
675 /* We need this internal function for the test */
676 
test_utf16_utf32_noboms(MYSQL * mysql)677 static int test_utf16_utf32_noboms(MYSQL *mysql __attribute__((unused)))
678 {
679 #ifndef HAVE_ICONV
680   diag("MariaDB Connector/C was built without iconv support");
681   return SKIP;
682 #else
683   const char *csname[]= {"utf16", "utf16le", "utf32", "utf8"};
684   MARIADB_CHARSET_INFO  *csinfo[sizeof(csname)/sizeof(char*)];
685 
686   const int     UTF8= sizeof(csname)/sizeof(char*) - 1;
687 
688   unsigned char in_string[][8]= {"\xd8\x02\xdc\x60\0",      /* utf16(be) */
689                                  "\x02\xd8\x60\xdc\0",      /* utf16le   */
690                                  "\x00\x01\x08\x60\0\0\0",  /* utf32(be) */
691                                  "\xF0\x90\xA1\xA0" };      /* utf8      */
692   size_t       in_oct_len[]= {6, 6, 8, 5};
693 
694   char   buffer[8], as_hex[16];
695   int    i, error;
696   size_t rc, in_len, out_len;
697 
698   for (i= 0; i < (int)(sizeof(csname)/sizeof(char*)); ++i)
699   {
700     csinfo[i]= mariadb_get_charset_by_name(csname[i]);
701 
702     if (csinfo[i] == NULL)
703     {
704       diag("Could not get cs info for %s", csname[i]);
705       return FAIL;
706     }
707   }
708 
709   for (i= 0; i < UTF8; ++i)
710   {
711     in_len=  in_oct_len[i];
712     out_len= sizeof(buffer);
713 
714     diag("Converting %s->%s", csname[i], csname[UTF8]);
715     rc= mariadb_convert_string((char *)in_string[i], &in_len, csinfo[i], buffer, &out_len, csinfo[UTF8], &error);
716 
717     FAIL_IF(rc == (size_t)-1, "Conversion failed");
718     FAIL_IF(rc != in_oct_len[UTF8], "Incorrect number of written bytes");
719 
720     if (memcmp(buffer, in_string[UTF8], rc) != 0)
721     {
722       mysql_hex_string(as_hex, buffer, (unsigned long)rc);
723       diag("Converted string(%s) does not match the expected one", as_hex);
724       return FAIL;
725     }
726 
727     in_len=  in_oct_len[UTF8];
728     out_len= sizeof(buffer);
729 
730     diag("Converting %s->%s", csname[UTF8], csname[i]);
731     rc= mariadb_convert_string((char *)in_string[UTF8], &in_len, csinfo[UTF8], buffer, &out_len, csinfo[i], &error);
732 
733     FAIL_IF(rc == (size_t)-1, "Conversion failed");
734     diag("rc=%lu oct_len: %lu", (unsigned long)rc, (unsigned long)in_oct_len[i]);
735     FAIL_IF(rc != in_oct_len[i], "Incorrect number of written bytes");
736 
737     if (memcmp(buffer, in_string[i], rc) != 0)
738     {
739       mysql_hex_string(as_hex, buffer, (unsigned long)rc);
740       diag("Converted string(%s) does not match the expected one", as_hex);
741       return FAIL;
742     }
743   }
744 
745   return OK;
746 #endif
747 }
748 
charset_auto(MYSQL * my)749 static int charset_auto(MYSQL *my __attribute__((unused)))
750 {
751   const char *csname1, *csname2;
752   const char *osname;
753   MYSQL *mysql= mysql_init(NULL);
754   int rc;
755 
756   osname= madb_get_os_character_set();
757 
758   mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "auto");
759 
760   FAIL_IF(!my_test_connect(mysql, hostname, username,
761                              password, schema, port, socketname, 0),
762          mysql_error(mysql));
763 
764   csname1= mysql_character_set_name(mysql);
765   diag("Character set: %s os charset: %s", csname1, osname);
766 
767   FAIL_IF(strcmp(osname, csname1), "character set is not os character set");
768 
769   if (strcmp(osname, "utf8"))
770   {
771     rc= mysql_set_character_set(mysql, "utf8");
772     check_mysql_rc(rc, mysql);
773 
774     csname2= mysql_character_set_name(mysql);
775     diag("Character set: %s", csname2);
776 
777     FAIL_IF(!strcmp(csname2, csname1), "Wrong charset: expected utf8");
778 
779     rc= mysql_set_character_set(mysql, "auto");
780     check_mysql_rc(rc, mysql);
781 
782     csname2= mysql_character_set_name(mysql);
783     diag("Character set: %s", csname2);
784     FAIL_IF(strcmp(csname2, osname), "Wrong charset: expected os charset");
785   }
786   mysql_close(mysql);
787   return OK;
788 }
789 
790 /* check if all server character sets are supported */
test_conc223(MYSQL * mysql)791 static int test_conc223(MYSQL *mysql)
792 {
793   int rc;
794   MYSQL_RES *res;
795   MYSQL_ROW row;
796   int found= 0;
797 
798   SKIP_MYSQL(mysql);
799 
800   rc= mysql_query(mysql, "SELECT ID, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLLATIONS");
801   check_mysql_rc(rc, mysql);
802 
803   res= mysql_store_result(mysql);
804   while ((row = mysql_fetch_row(res)))
805   {
806     int id= atoi(row[0]);
807     if (!mariadb_get_charset_by_nr(id))
808     {
809       diag("%04d %s %s", id, row[1], row[2]);
810       found++;
811     }
812   }
813   mysql_free_result(res);
814   if (found)
815   {
816     diag("%d character sets/collations not found", found);
817     return FAIL;
818   }
819   return OK;
820 }
821 
822 struct my_tests_st my_tests[] = {
823   {"test_conc223", test_conc223, TEST_CONNECTION_DEFAULT, 0,  NULL, NULL},
824   {"charset_auto", charset_auto, TEST_CONNECTION_DEFAULT, 0,  NULL, NULL},
825   {"bug_8378: mysql_real_escape with gbk", bug_8378, TEST_CONNECTION_NEW, 0,  opt_bug8378,  NULL},
826   {"test_client_character_set", test_client_character_set, TEST_CONNECTION_DEFAULT, 0,  NULL,  NULL},
827   {"bug_10214: mysql_real_escape with NO_BACKSLASH_ESCAPES", bug_10214, TEST_CONNECTION_DEFAULT, 0,  NULL, NULL},
828   {"test_escaping", test_escaping, TEST_CONNECTION_DEFAULT, 0,  NULL, NULL},
829   {"test_conversion", test_conversion, TEST_CONNECTION_DEFAULT, 0,  NULL, NULL},
830   {"bug_41785", bug_41785, TEST_CONNECTION_DEFAULT, 0,  NULL, "not fixed yet"},
831   {"test_bug27876", test_bug27876, TEST_CONNECTION_DEFAULT, 0,  NULL, NULL},
832   {"test_bug30472", test_bug30472, TEST_CONNECTION_NEW, 0,  NULL, NULL},
833   {"test_ps_i18n", test_ps_i18n, TEST_CONNECTION_DEFAULT, 0,  NULL, NULL},
834   {"test_bug_54100", test_bug_54100, TEST_CONNECTION_NEW, 0, NULL, NULL},
835   {"test_utf16_utf32_noboms", test_utf16_utf32_noboms, TEST_CONNECTION_DEFAULT, 0,  NULL, NULL},
836   {NULL, NULL, 0, 0, NULL, 0}
837 };
838 
839 
main(int argc,char ** argv)840 int main(int argc, char **argv)
841 {
842   if (argc > 1)
843    get_options(argc, argv);
844 
845   get_envvars();
846 
847   run_tests(my_tests);
848 
849   return(exit_status());
850 }
851