From 6b94fc579fdf3ddf4905a5b2c3c9e76d445f1304 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 1 Jun 2007 11:14:04 +0300 Subject: [PATCH 1/7] Bug #27716 multi-update did partially and has not binlogged Implementation of mysql_multi_update did not call multi_update::send_error method in some cases (see the test reported on bug page and test cases in changeset). Fixed with deploying the method, ::send_error() is refined to get binlogging code which works whenever there is modified non-transactional table. thd->no_trans_update.stmt flag is set in to TRUE to ease testing though being the beginning of relative bug#27417 fix (addresses a part of those issues). Eliminating two minor issues (small bugs) in multi_update methods. This patch for multi-update also addresses a part of the issues reported in bug#13270,bug#23333. mysql-test/r/innodb.result: result changed mysql-test/r/multi_update.result: results changed mysql-test/t/innodb.test: regression test for the bug combining transactional and non-transaction tables mysql-test/t/multi_update.test: regression tests added - erred query must be binlogged sql/sql_update.cc: making a call to multi_update::send_error when mysql_select return an error; deploying binlogging inside of ::send_error; refining multi_update::send_eof() to mark binlogging work done when its call to ::do_updates() errs and the query is binlogged with the error. ::send_error() will be called after all but do not do anything; thd->no_trans_update.stmt is corrected to be set to TRUE according to the existed code pattern. Although this part relates to another bugs (bug#27417 etc) it is needed here for testing; Eliminating a separate issue in multi_update::do_updates where either one of the class members trans_safe, transactional_tables was set after the per-table loop whereas both should be calculated during looping. Eliminating a separate issue in ::send_eof() where thd->no_trans_update.all won't be set TRUE when amoung others there'd be at least one modified transactional table. Binlogging is done to satisfy to general character bug#13270,bug#23333 so that those won't have fixes specific for multi-update. --- mysql-test/r/innodb.result | 45 +++++++++++++--- mysql-test/r/multi_update.result | 34 ++++++++++++ mysql-test/t/innodb.test | 39 ++++++++++++++ mysql-test/t/multi_update.test | 41 +++++++++++++++ sql/sql_update.cc | 90 +++++++++++++++++++++++++++----- 5 files changed, 229 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 0638152ba42..272f5dbb58e 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1086,6 +1086,39 @@ n d 1 30 2 20 drop table t1,t2; +CREATE TABLE `t1` ( +`a` int(11) NOT NULL auto_increment, +`b` int(11) default NULL, +PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; +CREATE TABLE `t2` ( +`a` int(11) NOT NULL auto_increment, +`b` int(11) default NULL, +PRIMARY KEY (`a`) +) ENGINE=INNODB DEFAULT CHARSET=latin1 ; +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(4,4); +reset master; +UPDATE t2,t1 SET t2.a=t1.a+2; +ERROR 23000: Duplicate entry '3' for key 1 +select * from t2 /* must be (3,1), (4,4) */; +a b +1 1 +4 4 +show master status /* there must no UPDATE in binlog */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 98 +delete from t1; +delete from t2; +insert into t1 values (1,2),(3,4),(4,4); +insert into t2 values (1,2),(3,4),(4,4); +reset master; +UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; +ERROR 23000: Duplicate entry '4' for key 1 +show master status /* there must be no UPDATE query event */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 98 +drop table t1, t2; create table t1 (a int, b int) engine=innodb; insert into t1 values(20,null); select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on @@ -1642,14 +1675,14 @@ t2 CREATE TABLE `t2` ( drop table t2, t1; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 155 +Binlog_cache_use 158 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 0 create table t1 (a int) engine=innodb; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 156 +Binlog_cache_use 159 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 1 @@ -1658,7 +1691,7 @@ delete from t1; commit; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 157 +Binlog_cache_use 160 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 1 @@ -1782,13 +1815,13 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 2070 +Innodb_rows_deleted 2072 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 31727 +Innodb_rows_inserted 31732 show status like "Innodb_rows_updated"; Variable_name Value -Innodb_rows_updated 29530 +Innodb_rows_updated 29532 show status like "Innodb_row_lock_waits"; Variable_name Value Innodb_row_lock_waits 0 diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 78872f27c47..0f624e3ee8d 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -524,3 +524,37 @@ a 30 drop view v1; drop table t1, t2; +CREATE TABLE `t1` ( +`a` int(11) NOT NULL auto_increment, +`b` int(11) default NULL, +PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; +CREATE TABLE `t2` ( +`a` int(11) NOT NULL auto_increment, +`b` int(11) default NULL, +PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(4,4); +reset master; +UPDATE t2,t1 SET t2.a=t1.a+2; +ERROR 23000: Duplicate entry '3' for key 1 +select * from t2 /* must be (3,1), (4,4) */; +a b +3 1 +4 4 +show master status /* there must be the UPDATE query event */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 189 +delete from t1; +delete from t2; +insert into t1 values (1,2),(3,4),(4,4); +insert into t2 values (1,2),(3,4),(4,4); +reset master; +UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; +ERROR 23000: Duplicate entry '4' for key 1 +show master status /* there must be the UPDATE query event */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 204 +drop table t1, t2; +end of tests diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index e762d740d66..3d5443a7200 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -753,6 +753,45 @@ select * from t1; select * from t2; drop table t1,t2; +# +# Bug#27716 multi-update did partially and has not binlogged +# + +CREATE TABLE `t1` ( + `a` int(11) NOT NULL auto_increment, + `b` int(11) default NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; + +CREATE TABLE `t2` ( + `a` int(11) NOT NULL auto_increment, + `b` int(11) default NULL, + PRIMARY KEY (`a`) +) ENGINE=INNODB DEFAULT CHARSET=latin1 ; + +# A. testing multi_update::send_eof() execution branch +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(4,4); +reset master; +--error ER_DUP_ENTRY +UPDATE t2,t1 SET t2.a=t1.a+2; +# check +select * from t2 /* must be (3,1), (4,4) */; +show master status /* there must no UPDATE in binlog */; + +# B. testing multi_update::send_error() execution branch +delete from t1; +delete from t2; +insert into t1 values (1,2),(3,4),(4,4); +insert into t2 values (1,2),(3,4),(4,4); +reset master; +--error ER_DUP_ENTRY +UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; +show master status /* there must be no UPDATE query event */; + +# cleanup bug#27716 +drop table t1, t2; + # # Testing of IFNULL # diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index da19a18c73a..84e6a444d47 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -534,3 +534,44 @@ select * from t1; select * from t2; drop view v1; drop table t1, t2; + +# +# Bug#27716 multi-update did partially and has not binlogged +# + +CREATE TABLE `t1` ( + `a` int(11) NOT NULL auto_increment, + `b` int(11) default NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; + +CREATE TABLE `t2` ( + `a` int(11) NOT NULL auto_increment, + `b` int(11) default NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; + +# A. testing multi_update::send_eof() execution branch +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(4,4); +reset master; +--error ER_DUP_ENTRY +UPDATE t2,t1 SET t2.a=t1.a+2; +# check +select * from t2 /* must be (3,1), (4,4) */; +show master status /* there must be the UPDATE query event */; + +# B. testing multi_update::send_error() execution branch +delete from t1; +delete from t2; +insert into t1 values (1,2),(3,4),(4,4); +insert into t2 values (1,2),(3,4),(4,4); +reset master; +--error ER_DUP_ENTRY +UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; +show master status /* there must be the UPDATE query event */; + +# cleanup bug#27716 +drop table t1, t2; + +--echo end of tests diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 6f6c4538040..7d038caa7cb 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -914,6 +914,7 @@ bool mysql_multi_update(THD *thd, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) { multi_update *result; + bool res; DBUG_ENTER("mysql_multi_update"); if (!(result= new multi_update(table_list, @@ -928,7 +929,7 @@ bool mysql_multi_update(THD *thd, MODE_STRICT_ALL_TABLES)); List total_list; - (void) mysql_select(thd, &select_lex->ref_pointer_array, + res= mysql_select(thd, &select_lex->ref_pointer_array, table_list, select_lex->with_wild, total_list, conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, @@ -936,6 +937,15 @@ bool mysql_multi_update(THD *thd, options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE, result, unit, select_lex); + DBUG_PRINT("info",("res: %d report_error: %d", res, + thd->net.report_error)); + res|= thd->net.report_error; + if (unlikely(res)) + { + /* If we had a another error reported earlier then this will be ignored */ + result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); + result->abort(); + } delete result; thd->abort_on_warning= 0; DBUG_RETURN(FALSE); @@ -1249,8 +1259,9 @@ multi_update::~multi_update() if (copy_field) delete [] copy_field; thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting - if (!trans_safe) + if (!trans_safe) // todo: remove since redundant thd->no_trans_update.all= TRUE; + DBUG_ASSERT(trans_safe || thd->no_trans_update.all); } @@ -1336,8 +1347,15 @@ bool multi_update::send_data(List ¬_used_values) } else { - if (!table->file->has_transactions()) + /* non-transactional or transactional table got modified */ + /* either multi_update class' flag is raised in its branch */ + if (table->file->has_transactions()) + transactional_tables= 1; + else + { + trans_safe= 0; thd->no_trans_update.stmt= TRUE; + } if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)) @@ -1379,8 +1397,8 @@ void multi_update::send_error(uint errcode,const char *err) my_error(errcode, MYF(0), err); /* If nothing updated return */ - if (!updated) - return; + if (updated == 0) /* the counter might be reset in send_eof */ + return; /* and then the query has been binlogged */ /* Something already updated so we have to invalidate cache */ query_cache_invalidate3(thd, update_tables, 1); @@ -1391,11 +1409,43 @@ void multi_update::send_error(uint errcode,const char *err) */ if (trans_safe) - ha_rollback_stmt(thd); - else if (do_update && table_count > 1) { - /* Add warning here */ - VOID(do_updates(0)); + DBUG_ASSERT(transactional_tables); + (void) ha_autocommit_or_rollback(thd, 1); + } + else + { + DBUG_ASSERT(thd->no_trans_update.stmt); + if (do_update && table_count > 1) + { + /* Add warning here */ + /* + todo/fixme: do_update() is never called with the arg 1. + should it change the signature to become argless? + */ + VOID(do_updates(0)); + } + } + if (thd->no_trans_update.stmt) + { + /* + The query has to binlog because there's a modified non-transactional table + either from the query's list or via a stored routine: bug#13270,23333 + */ + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_tables, FALSE); + mysql_bin_log.write(&qinfo); + } + if (!trans_safe) + thd->no_trans_update.all= TRUE; + } + DBUG_ASSERT(trans_safe || !updated || thd->no_trans_update.stmt); + + if (transactional_tables) + { + (void) ha_autocommit_or_rollback(thd, 1); } } @@ -1502,9 +1552,12 @@ int multi_update::do_updates(bool from_send_error) if (updated != org_updated) { if (table->file->has_transactions()) - transactional_tables= 1; + transactional_tables= 1; else - trans_safe= 0; // Can't do safe rollback + { + trans_safe= 0; // Can't do safe rollback + thd->no_trans_update.stmt= TRUE; + } } (void) table->file->ha_rnd_end(); (void) tmp_table->file->ha_rnd_end(); @@ -1527,7 +1580,10 @@ err2: if (table->file->has_transactions()) transactional_tables= 1; else + { trans_safe= 0; + thd->no_trans_update.stmt= TRUE; + } } DBUG_RETURN(1); } @@ -1556,20 +1612,26 @@ bool multi_update::send_eof() Write the SQL statement to the binlog if we updated rows and we succeeded or if we updated some non transactional tables. + + The query has to binlog because there's a modified non-transactional table + either from the query's list or via a stored routine: bug#13270,23333 */ - if ((local_error == 0) || (updated && !trans_safe)) + DBUG_ASSERT(trans_safe || !updated || thd->no_trans_update.stmt); + if (local_error == 0 || thd->no_trans_update.stmt) { if (mysql_bin_log.is_open()) { if (local_error == 0) thd->clear_error(); + else + updated= 0; /* if there's an error binlog it here not in ::send_error */ Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); if (mysql_bin_log.write(&qinfo) && trans_safe) local_error= 1; // Rollback update } - if (!transactional_tables) + if (!trans_safe) thd->no_trans_update.all= TRUE; } @@ -1581,7 +1643,7 @@ bool multi_update::send_eof() if (local_error > 0) // if the above log write did not fail ... { - /* Safety: If we haven't got an error before (should not happen) */ + /* Safety: If we haven't got an error before (can happen in do_updates) */ my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update", MYF(0)); return TRUE; From 2971d645c16c548678b8f94796ca1bcfd54f9c8e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Jun 2007 13:16:49 +0500 Subject: [PATCH 2/7] Bug#26711 "Binary content 0x00 sometimes becomes 0x5C 0x00 after dump/load" Problem: "SELECT INTO OUTFILE" created incorrect dumps for BLOBs, so "LOAD DATA" later incorrectly interpreted 0x5C as the second byte of a multi-byte sequence, instead of escape character. Fix: adding escaping of multi-byte heads. mysql-test/r/ctype_big5.result: Adding test case mysql-test/t/ctype_big5.test: Adding test case sql/sql_class.cc: Add escape characters before multi-byte heads. strings/ctype-big5.c: Flagging character set as dangerous for escaping. strings/ctype-gbk.c: Flagging character set as dangerous for escaping. strings/ctype-sjis.c: Flagging character set as dangerous for escaping. --- mysql-test/r/ctype_big5.result | 13 ++++++++ mysql-test/t/ctype_big5.test | 18 ++++++++++- sql/sql_class.cc | 59 ++++++++++++++++++++++++++++++---- strings/ctype-big5.c | 4 +-- strings/ctype-gbk.c | 4 +-- strings/ctype-sjis.c | 4 +-- 6 files changed, 89 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/ctype_big5.result b/mysql-test/r/ctype_big5.result index 6574908101c..3f1a87838cf 100644 --- a/mysql-test/r/ctype_big5.result +++ b/mysql-test/r/ctype_big5.result @@ -192,3 +192,16 @@ drop table t1; select hex(convert(_big5 0xC84041 using ucs2)); hex(convert(_big5 0xC84041 using ucs2)) 003F0041 +End of 4.1 tests +create table t1 (a blob); +insert into t1 values (0xEE00); +delete from t1; +select hex(load_file('test/t1.txt')); +hex(load_file('test/t1.txt')) +5CEE5C300A +load data infile 't1.txt' into table t1; +select hex(a) from t1; +hex(a) +EE00 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/ctype_big5.test b/mysql-test/t/ctype_big5.test index 200002cd235..8e17a27c550 100644 --- a/mysql-test/t/ctype_big5.test +++ b/mysql-test/t/ctype_big5.test @@ -63,4 +63,20 @@ drop table t1; # select hex(convert(_big5 0xC84041 using ucs2)); -# End of 4.1 tests +--echo End of 4.1 tests + +# +# Bug#26711 "binary content 0x00 sometimes becomes 0x5C 0x00 after dump/load" +# +create table t1 (a blob); +insert into t1 values (0xEE00); +--exec $MYSQL_DUMP --default-character-set=big5 -T $MYSQLTEST_VARDIR/master-data/test test t1 +delete from t1; +select hex(load_file('test/t1.txt')); +load data infile 't1.txt' into table t1; +select hex(a) from t1; +--exec rm $MYSQLTEST_VARDIR/master-data/test/t1.txt +--exec rm $MYSQLTEST_VARDIR/master-data/test/t1.sql +drop table t1; + +--echo End of 5.0 tests diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 010dc101e0d..788026d2f67 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1221,6 +1221,11 @@ select_export::prepare(List &list, SELECT_LEX_UNIT *u) } +#define NEED_ESCAPING(x) ((int) (uchar) (x) == escape_char || \ + (int) (uchar) (x) == field_sep_char || \ + (int) (uchar) (x) == line_sep_char || \ + !(x)) + bool select_export::send_data(List &items) { @@ -1280,14 +1285,20 @@ bool select_export::send_data(List &items) used_length=res->length(); if (result_type == STRING_RESULT && escape_char != -1) { - char *pos,*start,*end; - + char *pos, *start, *end; + CHARSET_INFO *res_charset= res->charset(); + CHARSET_INFO *character_set_client= thd->variables. + character_set_client; + bool check_second_byte= (res_charset == &my_charset_bin) && + character_set_client-> + escape_with_backslash_is_dangerous; + DBUG_ASSERT(character_set_client->mbmaxlen == 2 || + !character_set_client->escape_with_backslash_is_dangerous); for (start=pos=(char*) res->ptr(),end=pos+used_length ; pos != end ; pos++) { #ifdef USE_MB - CHARSET_INFO *res_charset=res->charset(); if (use_mb(res_charset)) { int l; @@ -1298,9 +1309,45 @@ bool select_export::send_data(List &items) } } #endif - if ((int) *pos == escape_char || (int) *pos == field_sep_char || - (int) *pos == line_sep_char || !*pos) - { + + /* + Special case when dumping BINARY/VARBINARY/BLOB values + for the clients with character sets big5, cp932, gbk and sjis, + which can have the escape character (0x5C "\" by default) + as the second byte of a multi-byte sequence. + + If + - pos[0] is a valid multi-byte head (e.g 0xEE) and + - pos[1] is 0x00, which will be escaped as "\0", + + then we'll get "0xEE + 0x5C + 0x30" in the output file. + + If this file is later loaded using this sequence of commands: + + mysql> create table t1 (a varchar(128)) character set big5; + mysql> LOAD DATA INFILE 'dump.txt' INTO TABLE t1; + + then 0x5C will be misinterpreted as the second byte + of a multi-byte character "0xEE + 0x5C", instead of + escape character for 0x00. + + To avoid this confusion, we'll escape the multi-byte + head character too, so the sequence "0xEE + 0x00" will be + dumped as "0x5C + 0xEE + 0x5C + 0x30". + + Note, in the condition below we only check if + mbcharlen is equal to 2, because there are no + character sets with mbmaxlen longer than 2 + and with escape_with_backslash_is_dangerous set. + DBUG_ASSERT before the loop makes that sure. + */ + + if (NEED_ESCAPING(*pos) || + (check_second_byte && + my_mbcharlen(character_set_client, (uchar) *pos) == 2 && + pos + 1 < end && + NEED_ESCAPING(pos[1]))) + { char tmp_buff[2]; tmp_buff[0]= escape_char; tmp_buff[1]= *pos ? *pos : '0'; diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index be04d19a756..8bbbcac63e4 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -6400,7 +6400,7 @@ CHARSET_INFO my_charset_big5_chinese_ci= 0, /* min_sort_char */ 255, /* max_sort_char */ ' ', /* pad char */ - 0, /* escape_with_backslash_is_dangerous */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_big5_handler, &my_collation_big5_chinese_ci_handler }; @@ -6433,7 +6433,7 @@ CHARSET_INFO my_charset_big5_bin= 0, /* min_sort_char */ 255, /* max_sort_char */ ' ', /* pad char */ - 0, /* escape_with_backslash_is_dangerous */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_big5_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index c7160e923a9..8ac7d62c9da 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -10046,7 +10046,7 @@ CHARSET_INFO my_charset_gbk_chinese_ci= 0, /* min_sort_char */ 255, /* max_sort_char */ ' ', /* pad char */ - 0, /* escape_with_backslash_is_dangerous */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -10078,7 +10078,7 @@ CHARSET_INFO my_charset_gbk_bin= 0, /* min_sort_char */ 255, /* max_sort_char */ ' ', /* pad char */ - 0, /* escape_with_backslash_is_dangerous */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index a66a7a000a6..6a7c7d7c0a0 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4694,7 +4694,7 @@ CHARSET_INFO my_charset_sjis_japanese_ci= 0, /* min_sort_char */ 255, /* max_sort_char */ ' ', /* pad char */ - 0, /* escape_with_backslash_is_dangerous */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_ci_handler }; @@ -4726,7 +4726,7 @@ CHARSET_INFO my_charset_sjis_bin= 0, /* min_sort_char */ 255, /* max_sort_char */ ' ', /* pad char */ - 0, /* escape_with_backslash_is_dangerous */ + 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, &my_collation_mb_bin_handler }; From af0a3afe054cc2be3600180cfdeef28761be2f7e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Jun 2007 17:55:55 +0500 Subject: [PATCH 3/7] Bug#28916 LDML doesn't work for utf8 and is not described in the manual - Adding missing initialization for utf8 collations - Minor code clean-ups: renaming variables, moving code into a new separate function. - Adding test, to check that both ucs2 and utf8 user defined collations work (ucs2_test_ci and utf8_test_ci) - Adding Vietnamese collation as a complex user defined collation example. include/m_ctype.h: Renaming variable names to match collation names (for convenience). mysys/charset-def.c: - Removing redundant declarations for variables declared in m_ctype.h - Renaming variable names to match collation names (for convenience). mysys/charset.c: - Renaming "new" to "newcs", to avoid using C reserved word as a variable name - Moving UCA initialization code into a separate function - The bug fix itself: adding initialization of utf8 collations strings/ctype-uca.c: Renaming variable names to match collation names (for convenience). strings/ctype.c: Increasing buffer size to fit tailoring for languages with complex rules (e.g. Vietnamese). mysql-test/r/ctype_ldml.result: Adding test case mysql-test/std_data/Index.xml: Adding Index.xml example with user defined collations. mysql-test/t/ctype_ldml-master.opt: Adding OPT file for the test case, to use the example Index.xml file. mysql-test/t/ctype_ldml.test: Adding test case --- include/m_ctype.h | 3 +- mysql-test/r/ctype_ldml.result | 296 +++++++++++++++++++++++++++++ mysql-test/std_data/Index.xml | 71 +++++++ mysql-test/t/ctype_ldml-master.opt | 2 + mysql-test/t/ctype_ldml.test | 63 ++++++ mysys/charset-def.c | 6 +- mysys/charset.c | 36 ++-- strings/ctype-uca.c | 4 +- strings/ctype.c | 2 +- 9 files changed, 464 insertions(+), 19 deletions(-) create mode 100644 mysql-test/r/ctype_ldml.result create mode 100644 mysql-test/std_data/Index.xml create mode 100644 mysql-test/t/ctype_ldml-master.opt create mode 100644 mysql-test/t/ctype_ldml.test diff --git a/include/m_ctype.h b/include/m_ctype.h index f33fd015733..9f21ac16a05 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -281,10 +281,11 @@ extern CHARSET_INFO my_charset_tis620_thai_ci; extern CHARSET_INFO my_charset_tis620_bin; extern CHARSET_INFO my_charset_ucs2_general_ci; extern CHARSET_INFO my_charset_ucs2_bin; -extern CHARSET_INFO my_charset_ucs2_general_uca; +extern CHARSET_INFO my_charset_ucs2_unicode_ci; extern CHARSET_INFO my_charset_ujis_japanese_ci; extern CHARSET_INFO my_charset_ujis_bin; extern CHARSET_INFO my_charset_utf8_general_ci; +extern CHARSET_INFO my_charset_utf8_unicode_ci; extern CHARSET_INFO my_charset_utf8_bin; extern CHARSET_INFO my_charset_cp1250_czech_ci; diff --git a/mysql-test/r/ctype_ldml.result b/mysql-test/r/ctype_ldml.result new file mode 100644 index 00000000000..f3d3ff700f0 --- /dev/null +++ b/mysql-test/r/ctype_ldml.result @@ -0,0 +1,296 @@ +drop table if exists t1; +set names utf8; +show variables like 'character_sets_dir%'; +Variable_name Value +character_sets_dir MYSQL_TEST_DIR/std_data/ +show collation like 'utf8_test_ci'; +Collation Charset Id Default Compiled Sortlen +utf8_test_ci utf8 240 8 +create table t1 (c1 char(1) character set utf8 collate utf8_test_ci); +insert into t1 values ('a'); +select * from t1 where c1='b'; +c1 +a +drop table t1; +show collation like 'ucs2_test_ci'; +Collation Charset Id Default Compiled Sortlen +ucs2_test_ci ucs2 241 8 +create table t1 (c1 char(1) character set ucs2 collate ucs2_test_ci); +insert into t1 values ('a'); +select * from t1 where c1='b'; +c1 +a +drop table t1; +show collation like 'ucs2_vn_ci'; +Collation Charset Id Default Compiled Sortlen +ucs2_vn_ci ucs2 242 8 +create table t1 (c1 char(1) character set ucs2 collate ucs2_vn_ci); +insert into t1 values (0x0061),(0x0041),(0x00E0),(0x00C0),(0x1EA3),(0x1EA2), +(0x00E3),(0x00C3),(0x00E1),(0x00C1),(0x1EA1),(0x1EA0); +insert into t1 values (0x0103),(0x0102),(0x1EB1),(0x1EB0),(0x1EB3),(0x1EB2), +(0x1EB5),(0x1EB4),(0x1EAF),(0x1EAE),(0x1EB7),(0x1EB6); +insert into t1 values (0x00E2),(0x00C2),(0x1EA7),(0x1EA6),(0x1EA9),(0x1EA8), +(0x1EAB),(0x1EAA),(0x1EA5),(0x1EA4),(0x1EAD),(0x1EAC); +insert into t1 values ('b'),('B'),('c'),('C'); +insert into t1 values ('d'),('D'),(0x0111),(0x0110); +insert into t1 values (0x0065),(0x0045),(0x00E8),(0x00C8),(0x1EBB),(0x1EBA), +(0x1EBD),(0x1EBC),(0x00E9),(0x00C9),(0x1EB9),(0x1EB8); +insert into t1 values (0x00EA),(0x00CA),(0x1EC1),(0x1EC0),(0x1EC3),(0x1EC2), +(0x1EC5),(0x1EC4),(0x1EBF),(0x1EBE),(0x1EC7),(0x1EC6); +insert into t1 values ('g'),('G'),('h'),('H'); +insert into t1 values (0x0069),(0x0049),(0x00EC),(0x00CC),(0x1EC9),(0x1EC8), +(0x0129),(0x0128),(0x00ED),(0x00CD),(0x1ECB),(0x1ECA); +insert into t1 values ('k'),('K'),('l'),('L'),('m'),('M'); +insert into t1 values (0x006F),(0x004F),(0x00F2),(0x00D2),(0x1ECF),(0x1ECE), +(0x00F5),(0x00D5),(0x00F3),(0x00D3),(0x1ECD),(0x1ECC); +insert into t1 values (0x00F4),(0x00D4),(0x1ED3),(0x1ED2),(0x1ED5),(0x1ED4), +(0x1ED7),(0x1ED6),(0x1ED1),(0x1ED0),(0x1ED9),(0x1ED8); +insert into t1 values (0x01A1),(0x01A0),(0x1EDD),(0x1EDC),(0x1EDF),(0x1EDE), +(0x1EE1),(0x1EE0),(0x1EDB),(0x1EDA),(0x1EE3),(0x1EE2); +insert into t1 values ('p'),('P'),('q'),('Q'),('r'),('R'),('s'),('S'),('t'),('T'); +insert into t1 values (0x0075),(0x0055),(0x00F9),(0x00D9),(0x1EE7),(0x1EE6), +(0x0169),(0x0168),(0x00FA),(0x00DA),(0x1EE5),(0x1EE4); +insert into t1 values (0x01B0),(0x01AF),(0x1EEB),(0x1EEA),(0x1EED),(0x1EEC), +(0x1EEF),(0x1EEE),(0x1EE9),(0x1EE8),(0x1EF1),(0x1EF0); +insert into t1 values ('v'),('V'),('x'),('X'); +insert into t1 values (0x0079),(0x0059),(0x1EF3),(0x1EF2),(0x1EF7),(0x1EF6), +(0x1EF9),(0x1EF8),(0x00FD),(0x00DD),(0x1EF5),(0x1EF4); +select hex(c1) as h, c1 from t1 order by c1, h; +h c1 +0041 A +0061 a +00C0 À +00C1 Á +00C3 Ã +00E0 à +00E1 á +00E3 ã +1EA0 Ạ +1EA1 ạ +1EA2 Ả +1EA3 ả +0102 Ă +0103 ă +1EAE Ắ +1EAF ắ +1EB0 Ằ +1EB1 ằ +1EB2 Ẳ +1EB3 ẳ +1EB4 Ẵ +1EB5 ẵ +1EB6 Ặ +1EB7 ặ +00C2 Â +00E2 â +1EA4 Ấ +1EA5 ấ +1EA6 Ầ +1EA7 ầ +1EA8 Ẩ +1EA9 ẩ +1EAA Ẫ +1EAB ẫ +1EAC Ậ +1EAD ậ +0042 B +0062 b +0043 C +0063 c +0044 D +0064 d +0110 Đ +0111 đ +0045 E +0065 e +00C8 È +00C9 É +00E8 è +00E9 é +1EB8 Ẹ +1EB9 ẹ +1EBA Ẻ +1EBB ẻ +1EBC Ẽ +1EBD ẽ +00CA Ê +00EA ê +1EBE Ế +1EBF ế +1EC0 Ề +1EC1 ề +1EC2 Ể +1EC3 ể +1EC4 Ễ +1EC5 ễ +1EC6 Ệ +1EC7 ệ +0047 G +0067 g +0048 H +0068 h +0049 I +0069 i +00CC Ì +00CD Í +00EC ì +00ED í +0128 Ĩ +0129 ĩ +1EC8 Ỉ +1EC9 ỉ +1ECA Ị +1ECB ị +004B K +006B k +004C L +006C l +004D M +006D m +004F O +006F o +00D2 Ò +00D3 Ó +00D5 Õ +00F2 ò +00F3 ó +00F5 õ +1ECC Ọ +1ECD ọ +1ECE Ỏ +1ECF ỏ +00D4 Ô +00F4 ô +1ED0 Ố +1ED1 ố +1ED2 Ồ +1ED3 ồ +1ED4 Ổ +1ED5 ổ +1ED6 Ỗ +1ED7 ỗ +1ED8 Ộ +1ED9 ộ +01A0 Ơ +01A1 ơ +1EDA Ớ +1EDB ớ +1EDC Ờ +1EDD ờ +1EDE Ở +1EDF ở +1EE0 Ỡ +1EE1 ỡ +1EE2 Ợ +1EE3 ợ +0050 P +0070 p +0051 Q +0071 q +0052 R +0072 r +0053 S +0073 s +0054 T +0074 t +0055 U +0075 u +00D9 Ù +00DA Ú +00F9 ù +00FA ú +0168 Ũ +0169 ũ +1EE4 Ụ +1EE5 ụ +1EE6 Ủ +1EE7 ủ +01AF Ư +01B0 ư +1EE8 Ứ +1EE9 ứ +1EEA Ừ +1EEB ừ +1EEC Ử +1EED ử +1EEE Ữ +1EEF ữ +1EF0 Ự +1EF1 ự +0056 V +0076 v +0058 X +0078 x +0059 Y +0079 y +00DD Ý +00FD ý +1EF2 Ỳ +1EF3 ỳ +1EF4 Ỵ +1EF5 ỵ +1EF6 Ỷ +1EF7 ỷ +1EF8 Ỹ +1EF9 ỹ +select group_concat(hex(c1) order by hex(c1)) from t1 group by c1; +group_concat(hex(c1) order by hex(c1)) +0041,0061,00C0,00C1,00C3,00E0,00E1,00E3,1EA0,1EA1,1EA2,1EA3 +0102,0103,1EAE,1EAF,1EB0,1EB1,1EB2,1EB3,1EB4,1EB5,1EB6,1EB7 +00C2,00E2,1EA4,1EA5,1EA6,1EA7,1EA8,1EA9,1EAA,1EAB,1EAC,1EAD +0042,0062 +0043,0063 +0044,0064 +0110,0111 +0045,0065,00C8,00C9,00E8,00E9,1EB8,1EB9,1EBA,1EBB,1EBC,1EBD +00CA,00EA,1EBE,1EBF,1EC0,1EC1,1EC2,1EC3,1EC4,1EC5,1EC6,1EC7 +0047,0067 +0048,0068 +0049,0069,00CC,00CD,00EC,00ED,0128,0129,1EC8,1EC9,1ECA,1ECB +004B,006B +004C,006C +004D,006D +004F,006F,00D2,00D3,00D5,00F2,00F3,00F5,1ECC,1ECD,1ECE,1ECF +00D4,00F4,1ED0,1ED1,1ED2,1ED3,1ED4,1ED5,1ED6,1ED7,1ED8,1ED9 +01A0,01A1,1EDA,1EDB,1EDC,1EDD,1EDE,1EDF,1EE0,1EE1,1EE2,1EE3 +0050,0070 +0051,0071 +0052,0072 +0053,0073 +0054,0074 +0055,0075,00D9,00DA,00F9,00FA,0168,0169,1EE4,1EE5,1EE6,1EE7 +01AF,01B0,1EE8,1EE9,1EEA,1EEB,1EEC,1EED,1EEE,1EEF,1EF0,1EF1 +0056,0076 +0058,0078 +0059,0079,00DD,00FD,1EF2,1EF3,1EF4,1EF5,1EF6,1EF7,1EF8,1EF9 +select group_concat(c1 order by hex(c1) SEPARATOR '') from t1 group by c1; +group_concat(c1 order by hex(c1) SEPARATOR '') +AaÀÁÃàáãẠạẢả +ĂăẮắẰằẲẳẴẵẶặ +ÂâẤấẦầẨẩẪẫẬậ +Bb +Cc +Dd +Đđ +EeÈÉèéẸẹẺẻẼẽ +ÊêẾếỀềỂểỄễỆệ +Gg +Hh +IiÌÍìíĨĩỈỉỊị +Kk +Ll +Mm +OoÒÓÕòóõỌọỎỏ +ÔôỐốỒồỔổỖỗỘộ +ƠơỚớỜờỞởỠỡỢợ +Pp +Qq +Rr +Ss +Tt +UuÙÚùúŨũỤụỦủ +ƯưỨứỪừỬửỮữỰự +Vv +Xx +YyÝýỲỳỴỵỶỷỸỹ +drop table t1; diff --git a/mysql-test/std_data/Index.xml b/mysql-test/std_data/Index.xml new file mode 100644 index 00000000000..988dddcc68a --- /dev/null +++ b/mysql-test/std_data/Index.xml @@ -0,0 +1,71 @@ + + + + + + a + b + + + + + + + + + a + b + + + + + + A +

\u0103

\u0102 + \u1EB1\u1EB0 + \u1EB3\u1EB2 + \u1EB5\u1EB4 + \u1EAF\u1EAE + \u1EB7\u1EB6 +

\u00E2

\u00C2 + \u1EA7\u1EA6 + \u1EA9\u1EA8 + \u1EAB\u1EAA + \u1EA5\u1EA4 + \u1EAD\u1EAC + D +

\u0111

\u0110 + E +

\u00EA

\u00CA + \u1EC1\u1EC0 + \u1EC3\u1EC2 + \u1EC5\u1EC4 + \u1EBF\u1EBE + \u1EC7\u1EC6 + O +

\u00F4

\u00D4 + \u1ED3\u1ED2 + \u1ED5\u1ED4 + \u1ED7\u1ED6 + \u1ED1\u1ED0 + \u1ED9\u1ED8 +

\u01A1

\u01A0 + \u1EDD\u1EDC + \u1EDF\u1EDE + \u1EE1\u1EE0 + \u1EDB\u1EDA + \u1EE3\u1EE2 + U +

\u01B0

\u01AF + \u1EEB\u1EEA + \u1EED\u1EEC + \u1EEF\u1EEE + \u1EE9\u1EE8 + \u1EF1\u1EF0 +
+ +
+ +
+ +
diff --git a/mysql-test/t/ctype_ldml-master.opt b/mysql-test/t/ctype_ldml-master.opt new file mode 100644 index 00000000000..a2532d4cfd9 --- /dev/null +++ b/mysql-test/t/ctype_ldml-master.opt @@ -0,0 +1,2 @@ +--character-sets-dir=$MYSQL_TEST_DIR/std_data/ + diff --git a/mysql-test/t/ctype_ldml.test b/mysql-test/t/ctype_ldml.test new file mode 100644 index 00000000000..fc6ed0f2579 --- /dev/null +++ b/mysql-test/t/ctype_ldml.test @@ -0,0 +1,63 @@ +--source include/have_ucs2.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +set names utf8; + +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +show variables like 'character_sets_dir%'; + +show collation like 'utf8_test_ci'; +create table t1 (c1 char(1) character set utf8 collate utf8_test_ci); +insert into t1 values ('a'); +select * from t1 where c1='b'; +drop table t1; + +show collation like 'ucs2_test_ci'; +create table t1 (c1 char(1) character set ucs2 collate ucs2_test_ci); +insert into t1 values ('a'); +select * from t1 where c1='b'; +drop table t1; + +# +# Vietnamese experimental collation +# + +show collation like 'ucs2_vn_ci'; +create table t1 (c1 char(1) character set ucs2 collate ucs2_vn_ci); +insert into t1 values (0x0061),(0x0041),(0x00E0),(0x00C0),(0x1EA3),(0x1EA2), + (0x00E3),(0x00C3),(0x00E1),(0x00C1),(0x1EA1),(0x1EA0); +insert into t1 values (0x0103),(0x0102),(0x1EB1),(0x1EB0),(0x1EB3),(0x1EB2), + (0x1EB5),(0x1EB4),(0x1EAF),(0x1EAE),(0x1EB7),(0x1EB6); +insert into t1 values (0x00E2),(0x00C2),(0x1EA7),(0x1EA6),(0x1EA9),(0x1EA8), + (0x1EAB),(0x1EAA),(0x1EA5),(0x1EA4),(0x1EAD),(0x1EAC); +insert into t1 values ('b'),('B'),('c'),('C'); +insert into t1 values ('d'),('D'),(0x0111),(0x0110); +insert into t1 values (0x0065),(0x0045),(0x00E8),(0x00C8),(0x1EBB),(0x1EBA), + (0x1EBD),(0x1EBC),(0x00E9),(0x00C9),(0x1EB9),(0x1EB8); +insert into t1 values (0x00EA),(0x00CA),(0x1EC1),(0x1EC0),(0x1EC3),(0x1EC2), + (0x1EC5),(0x1EC4),(0x1EBF),(0x1EBE),(0x1EC7),(0x1EC6); +insert into t1 values ('g'),('G'),('h'),('H'); +insert into t1 values (0x0069),(0x0049),(0x00EC),(0x00CC),(0x1EC9),(0x1EC8), + (0x0129),(0x0128),(0x00ED),(0x00CD),(0x1ECB),(0x1ECA); +insert into t1 values ('k'),('K'),('l'),('L'),('m'),('M'); +insert into t1 values (0x006F),(0x004F),(0x00F2),(0x00D2),(0x1ECF),(0x1ECE), + (0x00F5),(0x00D5),(0x00F3),(0x00D3),(0x1ECD),(0x1ECC); +insert into t1 values (0x00F4),(0x00D4),(0x1ED3),(0x1ED2),(0x1ED5),(0x1ED4), + (0x1ED7),(0x1ED6),(0x1ED1),(0x1ED0),(0x1ED9),(0x1ED8); +insert into t1 values (0x01A1),(0x01A0),(0x1EDD),(0x1EDC),(0x1EDF),(0x1EDE), + (0x1EE1),(0x1EE0),(0x1EDB),(0x1EDA),(0x1EE3),(0x1EE2); +insert into t1 values ('p'),('P'),('q'),('Q'),('r'),('R'),('s'),('S'),('t'),('T'); +insert into t1 values (0x0075),(0x0055),(0x00F9),(0x00D9),(0x1EE7),(0x1EE6), + (0x0169),(0x0168),(0x00FA),(0x00DA),(0x1EE5),(0x1EE4); +insert into t1 values (0x01B0),(0x01AF),(0x1EEB),(0x1EEA),(0x1EED),(0x1EEC), + (0x1EEF),(0x1EEE),(0x1EE9),(0x1EE8),(0x1EF1),(0x1EF0); +insert into t1 values ('v'),('V'),('x'),('X'); +insert into t1 values (0x0079),(0x0059),(0x1EF3),(0x1EF2),(0x1EF7),(0x1EF6), + (0x1EF9),(0x1EF8),(0x00FD),(0x00DD),(0x1EF5),(0x1EF4); +select hex(c1) as h, c1 from t1 order by c1, h; +select group_concat(hex(c1) order by hex(c1)) from t1 group by c1; +select group_concat(c1 order by hex(c1) SEPARATOR '') from t1 group by c1; +drop table t1; diff --git a/mysys/charset-def.c b/mysys/charset-def.c index 394fe6de1f3..36ff4139d9c 100644 --- a/mysys/charset-def.c +++ b/mysys/charset-def.c @@ -24,7 +24,6 @@ #ifdef HAVE_UCA_COLLATIONS #ifdef HAVE_CHARSET_ucs2 -extern CHARSET_INFO my_charset_ucs2_general_uca; extern CHARSET_INFO my_charset_ucs2_icelandic_uca_ci; extern CHARSET_INFO my_charset_ucs2_latvian_uca_ci; extern CHARSET_INFO my_charset_ucs2_romanian_uca_ci; @@ -46,7 +45,6 @@ extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci; #endif #ifdef HAVE_CHARSET_utf8 -extern CHARSET_INFO my_charset_utf8_general_uca_ci; extern CHARSET_INFO my_charset_utf8_icelandic_uca_ci; extern CHARSET_INFO my_charset_utf8_latvian_uca_ci; extern CHARSET_INFO my_charset_utf8_romanian_uca_ci; @@ -134,7 +132,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_ucs2_general_ci); add_compiled_collation(&my_charset_ucs2_bin); #ifdef HAVE_UCA_COLLATIONS - add_compiled_collation(&my_charset_ucs2_general_uca); + add_compiled_collation(&my_charset_ucs2_unicode_ci); add_compiled_collation(&my_charset_ucs2_icelandic_uca_ci); add_compiled_collation(&my_charset_ucs2_latvian_uca_ci); add_compiled_collation(&my_charset_ucs2_romanian_uca_ci); @@ -168,7 +166,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf8_general_cs); #endif #ifdef HAVE_UCA_COLLATIONS - add_compiled_collation(&my_charset_utf8_general_uca_ci); + add_compiled_collation(&my_charset_utf8_unicode_ci); add_compiled_collation(&my_charset_utf8_icelandic_uca_ci); add_compiled_collation(&my_charset_utf8_latvian_uca_ci); add_compiled_collation(&my_charset_utf8_romanian_uca_ci); diff --git a/mysys/charset.c b/mysys/charset.c index cce97677b14..9ea17c6515c 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -202,6 +202,19 @@ static my_bool simple_cs_is_full(CHARSET_INFO *cs) } +static void +copy_uca_collation(CHARSET_INFO *to, CHARSET_INFO *from) +{ + to->cset= from->cset; + to->coll= from->coll; + to->strxfrm_multiply= from->strxfrm_multiply; + to->min_sort_char= from->min_sort_char; + to->max_sort_char= from->max_sort_char; + to->mbminlen= from->mbminlen; + to->mbmaxlen= from->mbmaxlen; +} + + static int add_collation(CHARSET_INFO *cs) { if (cs->name && (cs->number || @@ -225,29 +238,30 @@ static int add_collation(CHARSET_INFO *cs) if (!(all_charsets[cs->number]->state & MY_CS_COMPILED)) { - CHARSET_INFO *new= all_charsets[cs->number]; + CHARSET_INFO *newcs= all_charsets[cs->number]; if (cs_copy_data(all_charsets[cs->number],cs)) return MY_XML_ERROR; if (!strcmp(cs->csname,"ucs2") ) { #if defined(HAVE_CHARSET_ucs2) && defined(HAVE_UCA_COLLATIONS) - new->cset= my_charset_ucs2_general_uca.cset; - new->coll= my_charset_ucs2_general_uca.coll; - new->strxfrm_multiply= my_charset_ucs2_general_uca.strxfrm_multiply; - new->min_sort_char= my_charset_ucs2_general_uca.min_sort_char; - new->max_sort_char= my_charset_ucs2_general_uca.max_sort_char; - new->mbminlen= 2; - new->mbmaxlen= 2; - new->state |= MY_CS_AVAILABLE | MY_CS_LOADED; + copy_uca_collation(newcs, &my_charset_ucs2_unicode_ci); + newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED; #endif + } + else if (!strcmp(cs->csname, "utf8")) + { +#if defined (HAVE_CHARSET_utf8) && defined(HAVE_UCA_COLLATIONS) + copy_uca_collation(newcs, &my_charset_utf8_unicode_ci); + newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED; +#endif } else { uchar *sort_order= all_charsets[cs->number]->sort_order; simple_cs_init_functions(all_charsets[cs->number]); - new->mbminlen= 1; - new->mbmaxlen= 1; + newcs->mbminlen= 1; + newcs->mbmaxlen= 1; if (simple_cs_is_full(all_charsets[cs->number])) { all_charsets[cs->number]->state |= MY_CS_LOADED; diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 1263882846d..4dbda0b9239 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -8073,7 +8073,7 @@ MY_COLLATION_HANDLER my_collation_ucs2_uca_handler = my_propagate_complex }; -CHARSET_INFO my_charset_ucs2_general_uca= +CHARSET_INFO my_charset_ucs2_unicode_ci= { 128,0,0, /* number */ MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, @@ -8734,7 +8734,7 @@ static uchar ctype_utf8[] = { extern MY_CHARSET_HANDLER my_charset_utf8_handler; -CHARSET_INFO my_charset_utf8_general_uca_ci= +CHARSET_INFO my_charset_utf8_unicode_ci= { 192,0,0, /* number */ MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, diff --git a/strings/ctype.c b/strings/ctype.c index f02b5542e78..e7399c5438b 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -123,7 +123,7 @@ static struct my_cs_file_section_st * cs_file_sec(const char *attr, uint len) } #define MY_CS_CSDESCR_SIZE 64 -#define MY_CS_TAILORING_SIZE 128 +#define MY_CS_TAILORING_SIZE 1024 typedef struct my_cs_file_info { From b307fc4d8fd5380cec948c07550b5ae73624e274 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Jun 2007 14:51:32 +0500 Subject: [PATCH 4/7] Makefile.am: Installing the new file required for tests. mysql-test/Makefile.am: Installing the new file required for tests. --- mysql-test/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 6c7207b0b2d..ebc2bbb83e8 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -60,6 +60,7 @@ dist-hook: $(INSTALL_DATA) $(srcdir)/include/*.test $(distdir)/include $(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r $(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(distdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/Index.xml $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.dat $(srcdir)/std_data/*.000001 $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(distdir)/std_data @@ -94,6 +95,7 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(DESTDIR)$(testdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/Index.xml $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.MY* $(DESTDIR)$(testdir)/std_data From c8bdab11370f87e56d4f631d3a5963e7817f8b1e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Jun 2007 13:21:16 +0300 Subject: [PATCH 5/7] Bug #27583 slave sql fails to read from iocache when slave got stopped at pos==4 forgotten merge with 5.0. There can be some bugs waiting for this fix in 5.0 like Bug@29232 sql/log_event.cc: file name is changed in step with the position. --- sql/log_event.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/log_event.cc b/sql/log_event.cc index 6eb247488b0..4d9fde9f9df 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3397,6 +3397,8 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) memcpy(rli->group_master_log_name, new_log_ident, ident_len+1); rli->notify_group_master_log_name_update(); rli->group_master_log_pos= pos; + strmake(rli->group_relay_log_name, rli->event_relay_log_name, + sizeof(rli->group_relay_log_name) - 1); rli->group_relay_log_pos= rli->event_relay_log_pos; DBUG_PRINT("info", ("group_master_log_name: '%s' group_master_log_pos:\ %lu", From 39cc31b3077e245128f36293abb6e4c03faf6b65 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Jun 2007 14:24:31 +0200 Subject: [PATCH 6/7] BUG#29030 (DROP USER command that errors still gets written to binary log and replicated): A DROP USER statement with a non-existing user was correctly written to the binary log (there might be users that were removed, but not all), but the error code was not set, which caused the slave to stop with an error. The error reporting code was moved to before the statement was logged to ensure that the error information for the thread was correctly set up. This works since my_error() will set the fields net.last_errno and net.last_error for the thread that is reporting the error, and this will then be picked up when the Query_log_event is created and written to the binary log. sql/sql_acl.cc: Moving error reporting code to ensure that thd->net.last_err{or,no} is set and adding debug printout. mysql-test/r/rpl_grant.result: New BitKeeper file ``mysql-test/r/rpl_grant.result'' mysql-test/t/rpl_grant.test: New BitKeeper file ``mysql-test/t/rpl_grant.test'' --- mysql-test/r/rpl_grant.result | 77 +++++++++++++++++++++++++++++++++++ mysql-test/t/rpl_grant.test | 38 +++++++++++++++++ sql/sql_acl.cc | 8 +++- 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 mysql-test/r/rpl_grant.result create mode 100644 mysql-test/t/rpl_grant.test diff --git a/mysql-test/r/rpl_grant.result b/mysql-test/r/rpl_grant.result new file mode 100644 index 00000000000..7610deca51a --- /dev/null +++ b/mysql-test/r/rpl_grant.result @@ -0,0 +1,77 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +**** On Master **** +CREATE USER dummy@localhost; +CREATE USER dummy1@localhost, dummy2@localhost; +SELECT user, host FROM mysql.user; +user host +root 127.0.0.1 +dummy localhost +dummy1 localhost +dummy2 localhost +root localhost +root romeo.kindahl.net +**** On Slave **** +SELECT user,host FROM mysql.user; +user host +root 127.0.0.1 +dummy localhost +dummy1 localhost +dummy2 localhost +root localhost +root romeo.kindahl.net +**** On Master **** +DROP USER nonexisting@localhost; +ERROR HY000: Operation DROP USER failed for 'nonexisting'@'localhost' +DROP USER nonexisting@localhost, dummy@localhost; +ERROR HY000: Operation DROP USER failed for 'nonexisting'@'localhost' +DROP USER dummy1@localhost, dummy2@localhost; +SELECT user, host FROM mysql.user; +user host +root 127.0.0.1 +root localhost +root romeo.kindahl.net +**** On Slave **** +SELECT user,host FROM mysql.user; +user host +root 127.0.0.1 +root localhost +root romeo.kindahl.net +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 609 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 609 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # diff --git a/mysql-test/t/rpl_grant.test b/mysql-test/t/rpl_grant.test new file mode 100644 index 00000000000..592cf7630da --- /dev/null +++ b/mysql-test/t/rpl_grant.test @@ -0,0 +1,38 @@ +# Tests of grants and users + +source include/master-slave.inc; +source include/not_embedded.inc; + +--echo **** On Master **** +connection master; + +CREATE USER dummy@localhost; +CREATE USER dummy1@localhost, dummy2@localhost; + +SELECT user, host FROM mysql.user; +sync_slave_with_master; +--echo **** On Slave **** +SELECT user,host FROM mysql.user; + +--echo **** On Master **** +connection master; + +# No user exists +error ER_CANNOT_USER; +DROP USER nonexisting@localhost; + +# At least one user exists, but not all +error ER_CANNOT_USER; +DROP USER nonexisting@localhost, dummy@localhost; + +# All users exist +DROP USER dummy1@localhost, dummy2@localhost; + +SELECT user, host FROM mysql.user; +sync_slave_with_master; +--echo **** On Slave **** +SELECT user,host FROM mysql.user; + +--replace_result $MASTER_MYPORT MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # 33 # +query_vertical SHOW SLAVE STATUS; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index cae1f6eb243..f9bd2c6ba0d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5378,6 +5378,12 @@ bool mysql_drop_user(THD *thd, List &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); + if (result) + my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); + + DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno)); + DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error)); + if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); @@ -5386,8 +5392,6 @@ bool mysql_drop_user(THD *thd, List &list) rw_unlock(&LOCK_grant); close_thread_tables(thd); - if (result) - my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); DBUG_RETURN(result); } From 8b3c5753c7961297d43a5fd87481bca06bcc245d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Jun 2007 16:55:52 +0200 Subject: [PATCH 7/7] Test fix --- mysql-test/r/rpl_grant.result | 32 ++++++++++++++++---------------- mysql-test/t/rpl_grant.test | 12 ++++++++---- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/rpl_grant.result b/mysql-test/r/rpl_grant.result index 7610deca51a..4d7ad298ce4 100644 --- a/mysql-test/r/rpl_grant.result +++ b/mysql-test/r/rpl_grant.result @@ -7,40 +7,40 @@ start slave; **** On Master **** CREATE USER dummy@localhost; CREATE USER dummy1@localhost, dummy2@localhost; -SELECT user, host FROM mysql.user; +SELECT user, host FROM mysql.user WHERE user != 'root'; user host -root 127.0.0.1 dummy localhost dummy1 localhost dummy2 localhost -root localhost -root romeo.kindahl.net +SELECT COUNT(*) FROM mysql.user; +COUNT(*) +6 **** On Slave **** -SELECT user,host FROM mysql.user; +SELECT user,host FROM mysql.user WHERE user != 'root'; user host -root 127.0.0.1 dummy localhost dummy1 localhost dummy2 localhost -root localhost -root romeo.kindahl.net +SELECT COUNT(*) FROM mysql.user; +COUNT(*) +6 **** On Master **** DROP USER nonexisting@localhost; ERROR HY000: Operation DROP USER failed for 'nonexisting'@'localhost' DROP USER nonexisting@localhost, dummy@localhost; ERROR HY000: Operation DROP USER failed for 'nonexisting'@'localhost' DROP USER dummy1@localhost, dummy2@localhost; -SELECT user, host FROM mysql.user; +SELECT user, host FROM mysql.user WHERE user != 'root'; user host -root 127.0.0.1 -root localhost -root romeo.kindahl.net +SELECT COUNT(*) FROM mysql.user; +COUNT(*) +3 **** On Slave **** -SELECT user,host FROM mysql.user; +SELECT user,host FROM mysql.user WHERE user != 'root'; user host -root 127.0.0.1 -root localhost -root romeo.kindahl.net +SELECT COUNT(*) FROM mysql.user; +COUNT(*) +3 SHOW SLAVE STATUS; Slave_IO_State # Master_Host 127.0.0.1 diff --git a/mysql-test/t/rpl_grant.test b/mysql-test/t/rpl_grant.test index 592cf7630da..71e36342584 100644 --- a/mysql-test/t/rpl_grant.test +++ b/mysql-test/t/rpl_grant.test @@ -9,10 +9,12 @@ connection master; CREATE USER dummy@localhost; CREATE USER dummy1@localhost, dummy2@localhost; -SELECT user, host FROM mysql.user; +SELECT user, host FROM mysql.user WHERE user != 'root'; # root host non-determ +SELECT COUNT(*) FROM mysql.user; sync_slave_with_master; --echo **** On Slave **** -SELECT user,host FROM mysql.user; +SELECT user,host FROM mysql.user WHERE user != 'root'; # root host non-determ +SELECT COUNT(*) FROM mysql.user; --echo **** On Master **** connection master; @@ -28,10 +30,12 @@ DROP USER nonexisting@localhost, dummy@localhost; # All users exist DROP USER dummy1@localhost, dummy2@localhost; -SELECT user, host FROM mysql.user; +SELECT user, host FROM mysql.user WHERE user != 'root'; # root host non-determ +SELECT COUNT(*) FROM mysql.user; sync_slave_with_master; --echo **** On Slave **** -SELECT user,host FROM mysql.user; +SELECT user,host FROM mysql.user WHERE user != 'root'; # root host non-determ +SELECT COUNT(*) FROM mysql.user; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 8 # 9 # 23 # 33 #