diff options
28 files changed, 396 insertions, 91 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 41f1d074dd9..80bb24765a7 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -7719,6 +7719,7 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) { uint count; MYSQL_RES *warn_res; + DYNAMIC_STRING res; DBUG_ENTER("append_warnings"); if (!(count= mysql_warning_count(mysql))) @@ -7738,11 +7739,18 @@ int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) die("Warning count is %u but didn't get any warnings", count); - append_result(ds, warn_res); + init_dynamic_string(&res, "", 1024, 1024); + + append_result(&res, warn_res); mysql_free_result(warn_res); - DBUG_PRINT("warnings", ("%s", ds->str)); + DBUG_PRINT("warnings", ("%s", res.str)); + if (display_result_sorted) + dynstr_append_sorted(ds, &res, 0); + else + dynstr_append_mem(ds, res.str, res.length); + dynstr_free(&res); DBUG_RETURN(count); } diff --git a/mysql-test/r/create_or_replace.result b/mysql-test/r/create_or_replace.result index e6589807c2b..0403e1a0a35 100644 --- a/mysql-test/r/create_or_replace.result +++ b/mysql-test/r/create_or_replace.result @@ -427,4 +427,16 @@ THREAD_ID LOCK_MODE LOCK_DURATION LOCK_TYPE TABLE_SCHEMA TABLE_NAME # MDL_SHARED_READ MDL_EXPLICIT Table metadata lock test t2 drop table t1; unlock tables; +# +# MDEV-6560 +# Assertion `! is_set() ' failed in Diagnostics_area::set_ok_status +# +CREATE TABLE t1 (col_int_nokey INT) ENGINE=InnoDB; +CREATE OR REPLACE TEMPORARY TABLE tmp LIKE t1; +LOCK TABLE t1 WRITE; +CREATE OR REPLACE TABLE t1 LIKE tmp;; +KILL QUERY 3; +CREATE OR REPLACE TABLE t1 (a int);; +KILL QUERY 3; +drop table t1; DROP TABLE t2; diff --git a/mysql-test/r/ctype_partitions.result b/mysql-test/r/ctype_partitions.result new file mode 100644 index 00000000000..a39ecc11529 --- /dev/null +++ b/mysql-test/r/ctype_partitions.result @@ -0,0 +1,51 @@ +# +# MDEV-6255 DUPLICATE KEY Errors on SELECT .. GROUP BY that uses temporary and filesort +# +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET cp1251 COLLATE cp1251_ukrainian_ci); +INSERT INTO t1 VALUES (0x20),(0x60),(0x6060),(0x606060); +SELECT HEX(a) FROM t1 WHERE a=0x60; +HEX(a) +20 +60 +6060 +606060 +ALTER TABLE t1 PARTITION BY KEY(a) PARTITIONS 3; +SELECT HEX(a) FROM t1 WHERE a=0x60; +HEX(a) +20 +60 +6060 +606060 +DROP TABLE t1; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET koi8u COLLATE koi8u_general_ci); +INSERT INTO t1 VALUES (0x20),(0x60),(0x6060),(0x606060); +SELECT HEX(a) FROM t1 WHERE a=0x60; +HEX(a) +20 +60 +6060 +606060 +ALTER TABLE t1 PARTITION BY KEY(a) PARTITIONS 3; +SELECT HEX(a) FROM t1 WHERE a=0x60; +HEX(a) +20 +60 +6060 +606060 +DROP TABLE t1; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET cp1250 COLLATE cp1250_general_ci); +INSERT INTO t1 VALUES (0x20),(0xA0),(0xA0A0),(0xA0A0A0); +SELECT HEX(a) FROM t1 WHERE a=0xA0; +HEX(a) +20 +A0 +A0A0 +A0A0A0 +ALTER TABLE t1 PARTITION BY KEY(a) PARTITIONS 3; +SELECT HEX(a) FROM t1 WHERE a=0xA0; +HEX(a) +20 +A0 +A0A0 +A0A0A0 +DROP TABLE t1; diff --git a/mysql-test/suite/multi_source/gtid.result b/mysql-test/suite/multi_source/gtid.result index 8e6028afa17..ce926ddc995 100644 --- a/mysql-test/suite/multi_source/gtid.result +++ b/mysql-test/suite/multi_source/gtid.result @@ -141,8 +141,8 @@ include/reset_master_slave.inc SET GLOBAL gtid_domain_id=0; STOP ALL SLAVES; Warnings: -Note 1938 SLAVE 'slave2' stopped Note 1938 SLAVE 'slave1' stopped +Note 1938 SLAVE 'slave2' stopped include/reset_master_slave.inc SET GLOBAL gtid_domain_id=0; include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/gtid.test b/mysql-test/suite/multi_source/gtid.test index 0ab486b1f41..7a085823693 100644 --- a/mysql-test/suite/multi_source/gtid.test +++ b/mysql-test/suite/multi_source/gtid.test @@ -141,12 +141,14 @@ DROP TABLE t3; SET GLOBAL gtid_domain_id=0; --let $wait_condition= SELECT COUNT(*)=0 FROM information_schema.tables WHERE table_name IN ("t1", "t2", "t3") AND table_schema = "test" --source include/wait_condition.inc +--sorted_result STOP ALL SLAVES; --source reset_master_slave.inc --disconnect slave1 --connection slave2 SET GLOBAL gtid_domain_id=0; +--sorted_result STOP ALL SLAVES; --source reset_master_slave.inc --disconnect slave2 diff --git a/mysql-test/suite/multi_source/gtid_ignore_duplicates.result b/mysql-test/suite/multi_source/gtid_ignore_duplicates.result index 9bd09330ae7..5426091b635 100644 --- a/mysql-test/suite/multi_source/gtid_ignore_duplicates.result +++ b/mysql-test/suite/multi_source/gtid_ignore_duplicates.result @@ -245,8 +245,8 @@ a SET GLOBAL gtid_domain_id=0; STOP ALL SLAVES; Warnings: -Note 1938 SLAVE 'c2a' stopped Note 1938 SLAVE 'b2a' stopped +Note 1938 SLAVE 'c2a' stopped SET GLOBAL slave_parallel_threads= @old_parallel; SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates; SET GLOBAL gtid_domain_id=0; diff --git a/mysql-test/suite/multi_source/gtid_ignore_duplicates.test b/mysql-test/suite/multi_source/gtid_ignore_duplicates.test index 3e98d7c76cb..cf1c750fc19 100644 --- a/mysql-test/suite/multi_source/gtid_ignore_duplicates.test +++ b/mysql-test/suite/multi_source/gtid_ignore_duplicates.test @@ -261,24 +261,28 @@ SELECT * FROM t1 WHERE a >= 20 ORDER BY a; # Clean up. --connection server_1 SET GLOBAL gtid_domain_id=0; +--sorted_result STOP ALL SLAVES; SET GLOBAL slave_parallel_threads= @old_parallel; SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates; --connection server_2 SET GLOBAL gtid_domain_id=0; +--sorted_result STOP ALL SLAVES; SET GLOBAL slave_parallel_threads= @old_parallel; SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates; --connection server_3 SET GLOBAL gtid_domain_id=0; +--sorted_result STOP ALL SLAVES; SET GLOBAL slave_parallel_threads= @old_parallel; SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates; --connection server_4 SET GLOBAL gtid_domain_id=0; +--sorted_result STOP ALL SLAVES; SET GLOBAL slave_parallel_threads= @old_parallel; SET GLOBAL gtid_ignore_duplicates= @old_ignore_duplicates; diff --git a/mysql-test/suite/multi_source/load_data.result b/mysql-test/suite/multi_source/load_data.result index ef55abc5321..3a04156ce6a 100644 --- a/mysql-test/suite/multi_source/load_data.result +++ b/mysql-test/suite/multi_source/load_data.result @@ -23,8 +23,8 @@ drop table t1; drop table t2; stop all slaves; Warnings: -Note 1938 SLAVE 'master2' stopped Note 1938 SLAVE '' stopped +Note 1938 SLAVE 'master2' stopped include/reset_master_slave.inc include/reset_master_slave.inc include/reset_master_slave.inc diff --git a/mysql-test/suite/multi_source/load_data.test b/mysql-test/suite/multi_source/load_data.test index e6e1399cbf3..ca2391a9c8d 100644 --- a/mysql-test/suite/multi_source/load_data.test +++ b/mysql-test/suite/multi_source/load_data.test @@ -58,6 +58,7 @@ drop table t2; --sync_with_master 0,'master2' --connection slave +--sorted_result stop all slaves; --source reset_master_slave.inc diff --git a/mysql-test/suite/rpl/r/create_or_replace2.result b/mysql-test/suite/rpl/r/create_or_replace2.result new file mode 100644 index 00000000000..b96a0f8ae13 --- /dev/null +++ b/mysql-test/suite/rpl/r/create_or_replace2.result @@ -0,0 +1,31 @@ +include/master-slave.inc +[connection master] +# +# MDEV-6525 ; Problems with CREATE OR REPLACE under lock +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(a) FROM t1 ); +connect con1,localhost,root,,test; +CREATE TEMPORARY TABLE tmp (b INT) ENGINE=InnoDB; +LOCK TABLE t1 WRITE; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +CREATE OR REPLACE TABLE t1 LIKE tmp; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +connection default; +set session lock_wait_timeout=1; +SELECT f1(); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +set session lock_wait_timeout=@@global.lock_wait_timeout; +SELECT f1(); +connection con1; +unlock tables; +connection default; +ERROR 42S22: Unknown column 'a' in 'field list' +disconnect con1; +drop function f1; +drop table t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace2.test b/mysql-test/suite/rpl/t/create_or_replace2.test new file mode 100644 index 00000000000..79c92a7ec5b --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace2.test @@ -0,0 +1,44 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_row_or_statement.inc +--source include/have_metadata_lock_info.inc +--source include/master-slave.inc +--enable_connect_log + +--echo # +--echo # MDEV-6525 ; Problems with CREATE OR REPLACE under lock +--echo # + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(a) FROM t1 ); + +--connect (con1,localhost,root,,test) + +CREATE TEMPORARY TABLE tmp (b INT) ENGINE=InnoDB; +LOCK TABLE t1 WRITE; + +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; + +CREATE OR REPLACE TABLE t1 LIKE tmp; +SHOW CREATE TABLE t1; + +--connection default +set session lock_wait_timeout=1; +--error 1205 +SELECT f1(); + +set session lock_wait_timeout=@@global.lock_wait_timeout; +--send SELECT f1() +--connection con1 +# This is here just in case, any timeout should be ok +--sleep 1 +unlock tables; +--connection default +--error 1054 +--reap +--disconnect con1 + +# Cleanup +drop function f1; +drop table t1; +--disable_connect_log +--source include/rpl_end.inc diff --git a/mysql-test/t/create_or_replace.test b/mysql-test/t/create_or_replace.test index 384768a87d5..c7b980f9107 100644 --- a/mysql-test/t/create_or_replace.test +++ b/mysql-test/t/create_or_replace.test @@ -332,6 +332,38 @@ select * from information_schema.metadata_lock_info; drop table t1; unlock tables; +--echo # +--echo # MDEV-6560 +--echo # Assertion `! is_set() ' failed in Diagnostics_area::set_ok_status +--echo # + +CREATE TABLE t1 (col_int_nokey INT) ENGINE=InnoDB; + +--let $con_id = `SELECT CONNECTION_ID()` +CREATE OR REPLACE TEMPORARY TABLE tmp LIKE t1; +LOCK TABLE t1 WRITE; + +--connect (con1,localhost,root,,test) + +--connection default +--send CREATE OR REPLACE TABLE t1 LIKE tmp; +--connection con1 +eval KILL QUERY $con_id; + +--connection default +--error 0,ER_QUERY_INTERRUPTED +--reap +--send CREATE OR REPLACE TABLE t1 (a int); + +--connection con1 +eval KILL QUERY $con_id; + +--connection default +--error 0,ER_QUERY_INTERRUPTED +--reap +--disconnect con1 +drop table t1; + # # Cleanup # diff --git a/mysql-test/t/ctype_partitions.test b/mysql-test/t/ctype_partitions.test new file mode 100644 index 00000000000..f80a2c98a1b --- /dev/null +++ b/mysql-test/t/ctype_partitions.test @@ -0,0 +1,29 @@ +--source include/have_partition.inc + +--echo # +--echo # MDEV-6255 DUPLICATE KEY Errors on SELECT .. GROUP BY that uses temporary and filesort +--echo # + +# cp1251_ukrainian_ci: 0x20 SPACE is equal to 0x60 GRAVE ACCENT +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET cp1251 COLLATE cp1251_ukrainian_ci); +INSERT INTO t1 VALUES (0x20),(0x60),(0x6060),(0x606060); +SELECT HEX(a) FROM t1 WHERE a=0x60; +ALTER TABLE t1 PARTITION BY KEY(a) PARTITIONS 3; +SELECT HEX(a) FROM t1 WHERE a=0x60; +DROP TABLE t1; + +# koi8u_general_ci: 0x20 SPACE is equal to 0x60 GRAVE ACCENT +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET koi8u COLLATE koi8u_general_ci); +INSERT INTO t1 VALUES (0x20),(0x60),(0x6060),(0x606060); +SELECT HEX(a) FROM t1 WHERE a=0x60; +ALTER TABLE t1 PARTITION BY KEY(a) PARTITIONS 3; +SELECT HEX(a) FROM t1 WHERE a=0x60; +DROP TABLE t1; + +# cp1250_general_ci: 0x20 SPACE is equal to 0xA0 NO-BREAK SPACE +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET cp1250 COLLATE cp1250_general_ci); +INSERT INTO t1 VALUES (0x20),(0xA0),(0xA0A0),(0xA0A0A0); +SELECT HEX(a) FROM t1 WHERE a=0xA0; +ALTER TABLE t1 PARTITION BY KEY(a) PARTITIONS 3; +SELECT HEX(a) FROM t1 WHERE a=0xA0; +DROP TABLE t1; diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index f1bc19e27eb..ca190104d79 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -412,6 +412,17 @@ fun:__libc_start_main } +# +# dl_init reports leaked memory in memalign on OpenSuse 12.3 + +{ + memory "loss" from _dl_init + Memcheck:Leak + fun:memalign + ... + fun:call_init + fun:_dl_init +} # # dlclose can allocate memory for error message, the memory will be diff --git a/sql/slave.cc b/sql/slave.cc index b9f06c15fd4..edfc92a1666 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2230,6 +2230,7 @@ slave_killed_err: static bool wait_for_relay_log_space(Relay_log_info* rli) { bool slave_killed=0; + bool ignore_log_space_limit; Master_info* mi = rli->mi; PSI_stage_info old_stage; THD* thd = mi->io_thd; @@ -2245,6 +2246,11 @@ static bool wait_for_relay_log_space(Relay_log_info* rli) !rli->ignore_log_space_limit) mysql_cond_wait(&rli->log_space_cond, &rli->log_space_lock); + ignore_log_space_limit= rli->ignore_log_space_limit; + rli->ignore_log_space_limit= 0; + + thd->EXIT_COND(&old_stage); + /* Makes the IO thread read only one event at a time until the SQL thread is able to purge the relay @@ -2268,7 +2274,8 @@ static bool wait_for_relay_log_space(Relay_log_info* rli) thread sleeps waiting for events. */ - if (rli->ignore_log_space_limit) + + if (ignore_log_space_limit) { #ifndef DBUG_OFF { @@ -2290,11 +2297,8 @@ static bool wait_for_relay_log_space(Relay_log_info* rli) mysql_mutex_unlock(&mi->data_lock); rli->sql_force_rotate_relay= false; } - - rli->ignore_log_space_limit= false; } - thd->EXIT_COND(&old_stage); DBUG_RETURN(slave_killed); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 342a45247c5..5dd8a5b8abc 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2925,6 +2925,7 @@ Locked_tables_list::reopen_tables(THD *thd) size_t reopen_count= 0; MYSQL_LOCK *lock; MYSQL_LOCK *merged_lock; + DBUG_ENTER("Locked_tables_list::reopen_tables"); for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list= table_list->next_global) @@ -2936,7 +2937,7 @@ Locked_tables_list::reopen_tables(THD *thd) if (open_table(thd, table_list, thd->mem_root, &ot_ctx)) { unlink_all_closed_tables(thd, 0, reopen_count); - return TRUE; + DBUG_RETURN(TRUE); } table_list->table->pos_in_locked_tables= table_list; /* See also the comment on lock type in init_locked_tables(). */ @@ -2968,11 +2969,11 @@ Locked_tables_list::reopen_tables(THD *thd) unlink_all_closed_tables(thd, lock, reopen_count); if (! thd->killed) my_error(ER_LOCK_DEADLOCK, MYF(0)); - return TRUE; + DBUG_RETURN(TRUE); } thd->lock= merged_lock; } - return FALSE; + DBUG_RETURN(FALSE); } /** diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a4aeb24a326..b429772613e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4453,9 +4453,18 @@ extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd) return binlog_filter->db_ok(thd->db); } +/* + This is similar to sqlcom_can_generate_row_events, with the expection + that we only return 1 if we are going to generate row events in a + transaction. + CREATE OR REPLACE is always safe to do as this will run in it's own + transaction. +*/ + extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd) { - return sqlcom_can_generate_row_events(thd); + return (sqlcom_can_generate_row_events(thd) && thd->lex->sql_command != + SQLCOM_CREATE_TABLE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ca1290b2753..f4412512522 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5029,7 +5029,10 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, */ thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables); if (thd->locked_tables_list.reopen_tables(thd)) + { thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + result= 1; + } else { TABLE *table= pos_in_locked_tables->table; @@ -5292,6 +5295,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, if (res) { + /* is_error() may be 0 if table existed and we generated a warning */ res= thd->is_error(); goto err; } @@ -5374,7 +5378,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, */ thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables); if (thd->locked_tables_list.reopen_tables(thd)) + { thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + res= 1; // We got an error + } else { /* diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c index 6b96e1c31a3..c6205508a90 100644 --- a/storage/heap/hp_write.c +++ b/storage/heap/hp_write.c @@ -385,7 +385,8 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, pos=empty; do { - if (! hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 1)) + if (pos->hash_of_key == hash_of_key && + ! hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 1)) { DBUG_RETURN(my_errno=HA_ERR_FOUND_DUPP_KEY); } diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 4ac267ffb8a..0a89babb205 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -5515,6 +5515,8 @@ static int sort_key_write(MARIA_SORT_PARAM *sort_param, const uchar *a) } if ((sort_param->keyinfo->flag & HA_NOSAME) && cmp == 0) { + DBUG_EXECUTE("key", _ma_print_keydata(DBUG_FILE, sort_param->seg, a, + USE_WHOLE_KEY);); sort_info->dupp++; sort_info->info->cur_row.lastpos= get_record_for_key(sort_param->keyinfo, a); diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 4beb7047d00..3ca4ba2b430 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -288,9 +288,7 @@ void my_hash_sort_8bit_bin(CHARSET_INFO *cs __attribute__((unused)), for (; key < end ; key++) { - tmp1^= (ulong) ((((uint) tmp1 & 63) + tmp2) * - ((uint) *key)) + (tmp1 << 8); - tmp2+= 3; + MY_HASH_ADD(tmp1, tmp2, (uint) *key); } *nr1= tmp1; @@ -307,9 +305,7 @@ void my_hash_sort_bin(CHARSET_INFO *cs __attribute__((unused)), for (; key < end ; key++) { - tmp1^= (ulong) ((((uint) tmp1 & 63) + tmp2) * - ((uint) *key)) + (tmp1 << 8); - tmp2+= 3; + MY_HASH_ADD(tmp1, tmp2, (uint) *key); } *nr1= tmp1; diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c index 2c84f86fad0..babf74599ea 100644 --- a/strings/ctype-latin1.c +++ b/strings/ctype-latin1.c @@ -691,6 +691,8 @@ void my_hash_sort_latin1_de(CHARSET_INFO *cs __attribute__((unused)), ulong *nr1, ulong *nr2) { const uchar *end; + register ulong m1= *nr1, m2= *nr2; + /* Remove end space. We have to do this to be able to compare 'AE' and 'Ä' as identical @@ -700,14 +702,14 @@ void my_hash_sort_latin1_de(CHARSET_INFO *cs __attribute__((unused)), for (; key < end ; key++) { uint X= (uint) combo1map[(uint) *key]; - nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * X) + (nr1[0] << 8); - nr2[0]+=3; + MY_HASH_ADD(m1, m2, X); if ((X= combo2map[*key])) { - nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * X) + (nr1[0] << 8); - nr2[0]+=3; + MY_HASH_ADD(m1, m2, X); } } + *nr1= m1; + *nr2= m2; } diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index f4e70fd1dd5..1ef772e1d5e 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -680,6 +680,8 @@ void my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len,ulong *nr1, ulong *nr2) { + register ulong m1= *nr1, m2= *nr2; + /* Remove trailing spaces. We have to do this to be able to compare 'A ' and 'A' as identical @@ -688,10 +690,10 @@ my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)), for (; key < end ; key++) { - nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * - ((uint)*key)) + (nr1[0] << 8); - nr2[0]+=3; + MY_HASH_ADD(m1, m2, (uint)*key); } + *nr1= m1; + *nr2= m2; } diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index f5484965314..0785ba35700 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -306,24 +306,48 @@ void my_hash_sort_simple(CHARSET_INFO *cs, { register const uchar *sort_order=cs->sort_order; const uchar *end; - ulong n1, n2; + register ulong m1= *nr1, m2= *nr2; + uint16 space_weight= sort_order[' ']; /* - Remove end space. We have to do this to be able to compare - 'A ' and 'A' as identical + Remove all trailing characters that are equal to space. + We have to do this to be able to compare 'A ' and 'A' as identical. + + If the key is long enough, cut the trailing spaces (0x20) using an + optimized function implemented in skip_trailing_spaces(). + + "len > 16" is just some heuristic here. + Calling skip_triling_space() for short values is not desirable, + because its initialization block may be more expensive than the + performance gained. + */ + + end= len > 16 ? skip_trailing_space(key, len) : key + len; + + /* + We removed all trailing characters that are binary equal to space 0x20. + Now remove all trailing characters that have weights equal to space. + Some 8bit simple collations may have such characters: + - cp1250_general_ci 0xA0 NO-BREAK SPACE == 0x20 SPACE + - cp1251_ukrainian_ci 0x60 GRAVE ACCENT == 0x20 SPACE + - koi8u_general_ci 0x60 GRAVE ACCENT == 0x20 SPACE */ - end= skip_trailing_space(key, len); - n1= *nr1; - n2= *nr2; + for ( ; key < end ; ) + { + if (sort_order[*--end] != space_weight) + { + end++; + break; + } + } + for (; key < (uchar*) end ; key++) { - n1^=(ulong) ((((uint) n1 & 63)+n2) * - ((uint) sort_order[(uint) *key])) + (n1 << 8); - n2+=3; + MY_HASH_ADD(m1, m2, (uint) sort_order[(uint) *key]); } - *nr1= n1; - *nr2= n2; + *nr1= m1; + *nr2= m2; } diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 5165a43e852..19ce17c3856 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -20873,21 +20873,45 @@ static int my_strnncollsp_uca(CHARSET_INFO *cs, static void my_hash_sort_uca(CHARSET_INFO *cs, my_uca_scanner_handler *scanner_handler, const uchar *s, size_t slen, - ulong *n1, ulong *n2) + ulong *nr1, ulong *nr2) { int s_res; my_uca_scanner scanner; - - slen= cs->cset->lengthsp(cs, (char*) s, slen); + int space_weight= my_space_weight(cs); + register ulong m1= *nr1, m2= *nr2; + scanner_handler->init(&scanner, cs, &cs->uca->level[0], s, slen); while ((s_res= scanner_handler->next(&scanner)) >0) { - n1[0]^= (((n1[0] & 63)+n2[0])*(s_res >> 8))+ (n1[0] << 8); - n2[0]+=3; - n1[0]^= (((n1[0] & 63)+n2[0])*(s_res & 0xFF))+ (n1[0] << 8); - n2[0]+=3; + if (s_res == space_weight) + { + /* Combine all spaces to be able to skip end spaces */ + uint count= 0; + do + { + count++; + if ((s_res= scanner_handler->next(&scanner)) <= 0) + { + /* Skip strings at end of string */ + goto end; + } + } + while (s_res == space_weight); + + /* Add back that has for the space characters */ + do + { + MY_HASH_ADD_16(m1, m2, space_weight); + } + while (--count != 0); + + } + MY_HASH_ADD_16(m1, m2, s_res); } +end: + *nr1= m1; + *nr2= m2; } diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index d2f7d34f0aa..593f9a12950 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1222,23 +1222,23 @@ my_caseup_utf16(CHARSET_INFO *cs, char *src, size_t srclen, static void my_hash_sort_utf16(CHARSET_INFO *cs, const uchar *s, size_t slen, - ulong *n1, ulong *n2) + ulong *nr1, ulong *nr2) { my_wc_t wc; my_charset_conv_mb_wc mb_wc= cs->cset->mb_wc; int res; const uchar *e= s + cs->cset->lengthsp(cs, (const char *) s, slen); MY_UNICASE_INFO *uni_plane= cs->caseinfo; + register ulong m1= *nr1, m2= *nr2; while ((s < e) && (res= mb_wc(cs, &wc, (uchar *) s, (uchar *) e)) > 0) { my_tosort_utf16(uni_plane, &wc); - n1[0]^= (((n1[0] & 63) + n2[0]) * (wc & 0xFF)) + (n1[0] << 8); - n2[0]+= 3; - n1[0]^= (((n1[0] & 63) + n2[0]) * (wc >> 8)) + (n1[0] << 8); - n2[0]+= 3; + MY_HASH_ADD_16(m1, m2, wc); s+= res; } + *nr1= m1; + *nr2= m2; } @@ -1611,12 +1611,14 @@ my_hash_sort_utf16_bin(CHARSET_INFO *cs, const uchar *pos, size_t len, ulong *nr1, ulong *nr2) { const uchar *end= pos + cs->cset->lengthsp(cs, (const char *) pos, len); + register ulong m1= *nr1, m2= *nr2; + for ( ; pos < end ; pos++) { - nr1[0]^= (ulong) ((((uint) nr1[0] & 63) + nr2[0]) * - ((uint)*pos)) + (nr1[0] << 8); - nr2[0]+= 3; + MY_HASH_ADD(m1, m2, (uint)*pos); } + *nr1= m1; + *nr2= m2; } @@ -2007,22 +2009,15 @@ my_caseup_utf32(CHARSET_INFO *cs, char *src, size_t srclen, } -static inline void -my_hash_add(ulong *n1, ulong *n2, uint ch) -{ - n1[0]^= (((n1[0] & 63) + n2[0]) * (ch)) + (n1[0] << 8); - n2[0]+= 3; -} - - static void my_hash_sort_utf32(CHARSET_INFO *cs, const uchar *s, size_t slen, - ulong *n1, ulong *n2) + ulong *nr1, ulong *nr2) { my_wc_t wc; int res; const uchar *e= s + slen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; + register ulong m1= *nr1, m2= *nr2; /* Skip trailing spaces */ while (e > s + 3 && e[-1] == ' ' && !e[-2] && !e[-3] && !e[-4]) @@ -2031,12 +2026,14 @@ my_hash_sort_utf32(CHARSET_INFO *cs, const uchar *s, size_t slen, while ((res= my_utf32_uni(cs, &wc, (uchar*) s, (uchar*) e)) > 0) { my_tosort_utf32(uni_plane, &wc); - my_hash_add(n1, n2, (uint) (wc >> 24)); - my_hash_add(n1, n2, (uint) (wc >> 16) & 0xFF); - my_hash_add(n1, n2, (uint) (wc >> 8) & 0xFF); - my_hash_add(n1, n2, (uint) (wc & 0xFF)); + MY_HASH_ADD(m1, m2, (uint) (wc >> 24)); + MY_HASH_ADD(m1, m2, (uint) (wc >> 16) & 0xFF); + MY_HASH_ADD(m1, m2, (uint) (wc >> 8) & 0xFF); + MY_HASH_ADD(m1, m2, (uint) (wc & 0xFF)); s+= res; } + *nr1= m1; + *nr2= m2; } @@ -2976,12 +2973,13 @@ static size_t my_caseup_ucs2(CHARSET_INFO *cs, char *src, size_t srclen, static void my_hash_sort_ucs2(CHARSET_INFO *cs, const uchar *s, size_t slen, - ulong *n1, ulong *n2) + ulong *nr1, ulong *nr2) { my_wc_t wc; int res; const uchar *e=s+slen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; + register ulong m1= *nr1, m2= *nr2; while (e > s+1 && e[-1] == ' ' && e[-2] == '\0') e-= 2; @@ -2989,12 +2987,11 @@ static void my_hash_sort_ucs2(CHARSET_INFO *cs, const uchar *s, size_t slen, while ((s < e) && (res=my_ucs2_uni(cs,&wc, (uchar *)s, (uchar*)e)) >0) { my_tosort_ucs2(uni_plane, &wc); - n1[0]^= (((n1[0] & 63)+n2[0])*(wc & 0xFF))+ (n1[0] << 8); - n2[0]+=3; - n1[0]^= (((n1[0] & 63)+n2[0])*(wc >> 8))+ (n1[0] << 8); - n2[0]+=3; + MY_HASH_ADD_16(m1, m2, wc); s+=res; } + *nr1= m1; + *nr2= m2; } @@ -3312,16 +3309,17 @@ void my_hash_sort_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len,ulong *nr1, ulong *nr2) { const uchar *end = key + len; + register ulong m1= *nr1, m2= *nr2; while (end > key+1 && end[-1] == ' ' && end[-2] == '\0') end-= 2; for (; key < (uchar*) end ; key++) { - nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) * - ((uint)*key)) + (nr1[0] << 8); - nr2[0]+=3; + MY_HASH_ADD(m1, m2, (uint)*key); } + *nr1= m1; + *nr2= m2; } diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 96d5ea26a3c..d0a64d11c84 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -5087,12 +5087,13 @@ static size_t my_caseup_utf8(CHARSET_INFO *cs, char *src, size_t srclen, static void my_hash_sort_utf8(CHARSET_INFO *cs, const uchar *s, size_t slen, - ulong *n1, ulong *n2) + ulong *nr1, ulong *nr2) { my_wc_t wc; int res; const uchar *e=s+slen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; + register ulong m1= *nr1, m2= *nr2; /* Remove end space. We have to do this to be able to compare @@ -5104,12 +5105,11 @@ static void my_hash_sort_utf8(CHARSET_INFO *cs, const uchar *s, size_t slen, while ((s < e) && (res=my_utf8_uni(cs,&wc, (uchar *)s, (uchar*)e))>0 ) { my_tosort_unicode(uni_plane, &wc, cs->state); - n1[0]^= (((n1[0] & 63)+n2[0])*(wc & 0xFF))+ (n1[0] << 8); - n2[0]+=3; - n1[0]^= (((n1[0] & 63)+n2[0])*(wc >> 8))+ (n1[0] << 8); - n2[0]+=3; + MY_HASH_ADD_16(m1, m2, wc); s+=res; } + *nr1= m1; + *nr2= m2; } @@ -7597,22 +7597,15 @@ my_caseup_utf8mb4(CHARSET_INFO *cs, char *src, size_t srclen, } -static inline void -my_hash_add(ulong *n1, ulong *n2, uint ch) -{ - n1[0]^= (((n1[0] & 63) + n2[0]) * (ch)) + (n1[0] << 8); - n2[0]+= 3; -} - - static void my_hash_sort_utf8mb4(CHARSET_INFO *cs, const uchar *s, size_t slen, - ulong *n1, ulong *n2) + ulong *nr1, ulong *nr2) { my_wc_t wc; int res; const uchar *e= s + slen; MY_UNICASE_INFO *uni_plane= cs->caseinfo; + register ulong m1= *nr1, m2= *nr2; /* Remove end space. We do this to be able to compare @@ -7624,8 +7617,7 @@ my_hash_sort_utf8mb4(CHARSET_INFO *cs, const uchar *s, size_t slen, while ((res= my_mb_wc_utf8mb4(cs, &wc, (uchar*) s, (uchar*) e)) > 0) { my_tosort_unicode(uni_plane, &wc, cs->state); - my_hash_add(n1, n2, (uint) (wc & 0xFF)); - my_hash_add(n1, n2, (uint) (wc >> 8) & 0xFF); + MY_HASH_ADD_16(m1, m2, (uint) (wc & 0xFFFF)); if (wc > 0xFFFF) { /* @@ -7635,10 +7627,12 @@ my_hash_sort_utf8mb4(CHARSET_INFO *cs, const uchar *s, size_t slen, This is useful to keep order of records in test results, e.g. for "SHOW GRANTS". */ - my_hash_add(n1, n2, (uint) (wc >> 16) & 0xFF); + MY_HASH_ADD(m1, m2, (uint) ((wc >> 16) & 0xFF)); } s+= res; } + *nr1= m1; + *nr2= m2; } diff --git a/strings/strings_def.h b/strings/strings_def.h index 6bd8e8f5575..d601f5ca697 100644 --- a/strings/strings_def.h +++ b/strings/strings_def.h @@ -100,4 +100,20 @@ static inline const uchar *skip_trailing_space(const uchar *ptr,size_t len) end--; return (end); } + +/* Macros for hashing characters */ + +#define MY_HASH_ADD(A, B, value) \ + do { A^= (((A & 63)+B)*((value)))+ (A << 8); B+=3; } while(0) + +#define MY_HASH_ADD_16(A, B, value) \ + do { MY_HASH_ADD(A, B, ((value) & 0xFF)) ; MY_HASH_ADD(A, B, ((value >>8 ))); } while(0) + +/* + This one is needed to ensure we get the exact same hash as MariaDB 5.1 + This is needed to ensure that old partitioned tables still work as before. +*/ +#define MY_HASH_ADD_16_INV(A, B, value) \ + do { MY_HASH_ADD(A, B, ((value >> 8))) ; MY_HASH_ADD(A, B, ((value & 0xFF ))); } while(0) + #endif |