diff options
-rw-r--r-- | include/lf.h | 2 | ||||
-rw-r--r-- | mysql-test/main/innodb_ext_key.result | 2 | ||||
-rw-r--r-- | mysql-test/main/innodb_ext_key.test | 1 | ||||
-rw-r--r-- | mysql-test/main/range_notembedded.result | 16 | ||||
-rw-r--r-- | mysql-test/main/range_notembedded.test | 32 | ||||
-rw-r--r-- | mysql-test/main/table_value_constr.result | 108 | ||||
-rw-r--r-- | mysql-test/main/table_value_constr.test | 57 | ||||
-rw-r--r-- | mysql-test/suite/compat/oracle/r/table_value_constr.result | 4 | ||||
-rw-r--r-- | mysys/CMakeLists.txt | 2 | ||||
-rw-r--r-- | mysys/lf_hash.cc (renamed from mysys/lf_hash.c) | 55 | ||||
-rw-r--r-- | sql/opt_range.cc | 46 | ||||
-rw-r--r-- | sql/opt_range.h | 2 | ||||
-rw-r--r-- | sql/sql_lex.cc | 23 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_tvc.cc | 67 | ||||
-rw-r--r-- | sql/wsrep_schema.cc | 36 | ||||
-rw-r--r-- | storage/perfschema/pfs_engine_table.cc | 4 | ||||
-rw-r--r-- | storage/perfschema/pfs_instr.cc | 24 | ||||
-rw-r--r-- | storage/perfschema/pfs_instr.h | 2 |
19 files changed, 386 insertions, 99 deletions
diff --git a/include/lf.h b/include/lf.h index 88ac644c349..267a66aeeaf 100644 --- a/include/lf.h +++ b/include/lf.h @@ -125,7 +125,7 @@ void *lf_alloc_new(LF_PINS *pins); C_MODE_END /* - extendible hash, lf_hash.c + extendible hash, lf_hash.cc */ #include <hash.h> diff --git a/mysql-test/main/innodb_ext_key.result b/mysql-test/main/innodb_ext_key.result index 4c502a46981..0d3e27e5bf0 100644 --- a/mysql-test/main/innodb_ext_key.result +++ b/mysql-test/main/innodb_ext_key.result @@ -813,7 +813,7 @@ PRIMARY KEY(pk) INSERT INTO t2 SELECT a,a FROM t1; EXPLAIN SELECT pk FROM t2 FORCE INDEX(k1); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL k1 23 NULL 10 Using index +1 SIMPLE t2 index NULL k1 23 NULL # Using index DROP TABLE t1,t2; set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent_sample_pages= @innodb_stats_persistent_sample_pages_save; diff --git a/mysql-test/main/innodb_ext_key.test b/mysql-test/main/innodb_ext_key.test index 70d0009af27..77eda0df6f6 100644 --- a/mysql-test/main/innodb_ext_key.test +++ b/mysql-test/main/innodb_ext_key.test @@ -640,6 +640,7 @@ CREATE TABLE t2 ( )ENGINE=INNODB; INSERT INTO t2 SELECT a,a FROM t1; +--replace_column 9 # EXPLAIN SELECT pk FROM t2 FORCE INDEX(k1); DROP TABLE t1,t2; diff --git a/mysql-test/main/range_notembedded.result b/mysql-test/main/range_notembedded.result index 87fa85d3ac6..0ecf47c892e 100644 --- a/mysql-test/main/range_notembedded.result +++ b/mysql-test/main/range_notembedded.result @@ -159,7 +159,6 @@ left(@json, 2500) ] ] ## Repeat the above with a bit higher max_weight: -set @tmp9750_weight=@@optimizer_max_sel_arg_weight; set optimizer_max_sel_arg_weight=120; explain select * from t1 where kp1 in (1,2,3,4,5,6,7,8,9,10) and @@ -225,3 +224,18 @@ SELECT * FROM mysql.help_relation ignore index (help_topic_id) WHERE (help_topic_id = 8 OR help_keyword_id = 0) AND help_keyword_id != 2 AND help_topic_id >= 1900; help_topic_id help_keyword_id +# +# MDEV-24953: 10.5.9 crashes with large IN() list +# +CREATE TABLE t1 ( +notification_type_id smallint(4) unsigned NOT NULL DEFAULT 0, +item_id int(10) unsigned NOT NULL DEFAULT 0, +item_parent_id int(10) unsigned NOT NULL DEFAULT 0, +user_id int(10) unsigned NOT NULL DEFAULT 0, +PRIMARY KEY (notification_type_id,item_id,item_parent_id,user_id) +); +insert into t1 values (1,1,1,1), (2,2,2,2), (3,3,3,3); +# Run crashing query +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 2 NULL 3 Using where +drop table t1; diff --git a/mysql-test/main/range_notembedded.test b/mysql-test/main/range_notembedded.test index a70749ced6b..5f6a05e8d91 100644 --- a/mysql-test/main/range_notembedded.test +++ b/mysql-test/main/range_notembedded.test @@ -82,7 +82,6 @@ set @json= json_detailed(json_extract(@trace, '$**.setup_range_conditions')); select left(@json, 2500); --echo ## Repeat the above with a bit higher max_weight: -set @tmp9750_weight=@@optimizer_max_sel_arg_weight; set optimizer_max_sel_arg_weight=120; explain select * from t1 where kp1 in (1,2,3,4,5,6,7,8,9,10) and @@ -110,3 +109,34 @@ SELECT * FROM mysql.help_relation ignore index (help_topic_id) WHERE (help_topic_id = 8 OR help_keyword_id = 0) AND help_keyword_id != 2 AND help_topic_id >= 1900; +--echo # +--echo # MDEV-24953: 10.5.9 crashes with large IN() list +--echo # +--source include/have_sequence.inc + +CREATE TABLE t1 ( + notification_type_id smallint(4) unsigned NOT NULL DEFAULT 0, + item_id int(10) unsigned NOT NULL DEFAULT 0, + item_parent_id int(10) unsigned NOT NULL DEFAULT 0, + user_id int(10) unsigned NOT NULL DEFAULT 0, + PRIMARY KEY (notification_type_id,item_id,item_parent_id,user_id) +); +insert into t1 values (1,1,1,1), (2,2,2,2), (3,3,3,3); + +let $consts=`select group_concat(concat("'",seq,"'")) from seq_1_to_4642`; + +--echo # Run crashing query +--disable_query_log +eval +explain +DELETE FROM t1 +WHERE + notification_type_id IN (3, 4, 5, 6, 23) + AND + user_id = '5044' + AND + item_parent_id IN ($consts) +; +--enable_query_log + +drop table t1; diff --git a/mysql-test/main/table_value_constr.result b/mysql-test/main/table_value_constr.result index 7ab9666c373..3bb27589f66 100644 --- a/mysql-test/main/table_value_constr.result +++ b/mysql-test/main/table_value_constr.result @@ -748,7 +748,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00 2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1)) `tvc_0`) where 1 +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1)) `tvc_0`) where 1 explain extended select * from t1 where a in (select * from (values (1)) as tvc_0); id select_type table type possible_keys key key_len ref rows filtered Extra @@ -983,7 +983,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00 2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1 +Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1 explain extended select * from t1 where a = any (select * from (values (1),(2)) as tvc_0); id select_type table type possible_keys key key_len ref rows filtered Extra @@ -2776,6 +2776,110 @@ id select_type table type possible_keys key key_len ref rows Extra 2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where drop table t1; # +# MDEV-24910: TVC containing subquery used as a subselect +# +create table t1 (a int) engine=myisam; +insert into t1 values (3), (7), (1); +create table t2 (b int) engine=myisam; +insert into t2 values (1), (2); +select (values ((select 2))) from t2; +(values ((select 2))) +2 +2 +explain select (values ((select 2))) from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +4 SUBQUERY <derived2> ALL NULL NULL NULL NULL 2 +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1249 Select 3 was reduced during optimization +prepare stmt from "select (values ((select 2))) from t2"; +execute stmt; +(values ((select 2))) +2 +2 +execute stmt; +(values ((select 2))) +2 +2 +deallocate prepare stmt; +select (values ((select * from t1 where a > 10))) from t2; +(values ((select * from t1 where a > 10))) +NULL +NULL +explain select (values ((select * from t1 where a > 10))) from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +4 SUBQUERY <derived2> ALL NULL NULL NULL NULL 2 +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +3 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where +prepare stmt from "select (values ((select * from t1 where a > 10))) from t2"; +execute stmt; +(values ((select * from t1 where a > 10))) +NULL +NULL +execute stmt; +(values ((select * from t1 where a > 10))) +NULL +NULL +deallocate prepare stmt; +create table t3 (a int); +insert into t3 values +(3), (7), (7), (1), (3), (9), (7), (9), (8), (7), (8); +create view v1 as select count(a) as c from t3 group by a; +select +(values ((select * from t3 where a in (select * from v1)))); +(values ((select * from t3 where a in (select * from v1)))) +1 +explain select +(values ((select * from t3 where a in (select * from v1)))); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +6 SUBQUERY <derived2> ALL NULL NULL NULL NULL 2 +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +3 SUBQUERY t3 ALL NULL NULL NULL NULL 11 Using where +3 SUBQUERY <derived5> ref key0 key0 8 test.t3.a 2 Using where; FirstMatch(t3) +5 DERIVED t3 ALL NULL NULL NULL NULL 11 Using temporary; Using filesort +prepare stmt from "select +(values ((select * from t3 where a in (select * from v1))))"; +execute stmt; +(values ((select * from t3 where a in (select * from v1)))) +1 +execute stmt; +(values ((select * from t3 where a in (select * from v1)))) +1 +deallocate prepare stmt; +select +(values ((select * from t3 +where a > 10 and a in (select * from v1)))); +(values ((select * from t3 +where a > 10 and a in (select * from v1)))) +NULL +explain select +(values ((select * from t3 +where a > 10 and a in (select * from v1)))); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +6 SUBQUERY <derived2> ALL NULL NULL NULL NULL 2 +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +3 SUBQUERY t3 ALL NULL NULL NULL NULL 11 Using where +3 SUBQUERY <derived5> ref key0 key0 8 test.t3.a 2 Using where; FirstMatch(t3) +5 DERIVED t3 ALL NULL NULL NULL NULL 11 Using temporary; Using filesort +prepare stmt from "select +(values ((select * from t3 +where a > 10 and a in (select * from v1))))"; +execute stmt; +(values ((select * from t3 +where a > 10 and a in (select * from v1)))) +NULL +execute stmt; +(values ((select * from t3 +where a > 10 and a in (select * from v1)))) +NULL +deallocate prepare stmt; +drop view v1; +drop table t1,t2,t3; +# # End of 10.3 tests # # diff --git a/mysql-test/main/table_value_constr.test b/mysql-test/main/table_value_constr.test index 66463cb1f1a..d2baccd1e7e 100644 --- a/mysql-test/main/table_value_constr.test +++ b/mysql-test/main/table_value_constr.test @@ -1460,6 +1460,63 @@ eval explain $q3; drop table t1; --echo # +--echo # MDEV-24910: TVC containing subquery used as a subselect +--echo # + +create table t1 (a int) engine=myisam; +insert into t1 values (3), (7), (1); +create table t2 (b int) engine=myisam; +insert into t2 values (1), (2); + +let $q1= +select (values ((select 2))) from t2; +eval $q1; +eval explain $q1; +eval prepare stmt from "$q1"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +let $q2= +select (values ((select * from t1 where a > 10))) from t2; +eval $q2; +eval explain $q2; +eval prepare stmt from "$q2"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +create table t3 (a int); +insert into t3 values + (3), (7), (7), (1), (3), (9), (7), (9), (8), (7), (8); + +create view v1 as select count(a) as c from t3 group by a; + +let $q3= +select +(values ((select * from t3 where a in (select * from v1)))); +eval $q3; +eval explain $q3; +eval prepare stmt from "$q3"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +let $q4= +select +(values ((select * from t3 + where a > 10 and a in (select * from v1)))); +eval $q4; +eval explain $q4; +eval prepare stmt from "$q4"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +drop view v1; +drop table t1,t2,t3; + +--echo # --echo # End of 10.3 tests --echo # diff --git a/mysql-test/suite/compat/oracle/r/table_value_constr.result b/mysql-test/suite/compat/oracle/r/table_value_constr.result index 3621006d7dc..108163ed782 100644 --- a/mysql-test/suite/compat/oracle/r/table_value_constr.result +++ b/mysql-test/suite/compat/oracle/r/table_value_constr.result @@ -746,7 +746,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00 2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1)) "tvc_0") where 1 +Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1)) "tvc_0") where 1 explain extended select * from t1 where a in (select * from (values (1)) as tvc_0); id select_type table type possible_keys key key_len ref rows filtered Extra @@ -981,7 +981,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00 2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1),(2)) "tvc_0") where 1 +Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1),(2)) "tvc_0") where 1 explain extended select * from t1 where a = any (select * from (values (1),(2)) as tvc_0); id select_type table type possible_keys key key_len ref rows filtered Extra diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index bd743472537..fe3c3fe7eca 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -39,7 +39,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c crc32ieee.cc my_default.c tree.c typelib.c base64.c my_memmem.c my_getpagesize.c guess_malloc_library.c - lf_alloc-pin.c lf_dynarray.c lf_hash.c + lf_alloc-pin.c lf_dynarray.c lf_hash.cc safemalloc.c my_new.cc my_getncpus.c my_safehash.c my_chmod.c my_rnd.c my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c ../sql-common/my_time.c diff --git a/mysys/lf_hash.c b/mysys/lf_hash.cc index fd005b4584b..bc3504bc0dd 100644 --- a/mysys/lf_hash.c +++ b/mysys/lf_hash.cc @@ -28,13 +28,14 @@ #include <my_bit.h> #include <lf.h> #include "my_cpu.h" +#include "assume_aligned.h" /* An element of the list */ typedef struct { - intptr volatile link; /* a pointer to the next element in a list and a flag */ - uint32 hashnr; /* reversed hash number, for sorting */ + intptr link; /* a pointer to the next element in a list and a flag */ const uchar *key; size_t keylen; + uint32 hashnr; /* reversed hash number, for sorting */ /* data is stored here, directly after the keylen. thus the pointer to data is (void*)(slist_element_ptr+1) @@ -48,7 +49,7 @@ const int LF_HASH_OVERHEAD= sizeof(LF_SLIST); in a list) from l_find to l_insert/l_delete */ typedef struct { - intptr volatile *prev; + intptr *prev; LF_SLIST *curr, *next; } CURSOR; @@ -85,7 +86,7 @@ typedef struct { 0 - ok 1 - error (callbck returned 1) */ -static int l_find(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, +static int l_find(LF_SLIST **head, CHARSET_INFO *cs, uint32 hashnr, const uchar *key, size_t keylen, CURSOR *cursor, LF_PINS *pins, my_hash_walk_action callback) { @@ -98,11 +99,11 @@ static int l_find(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, DBUG_ASSERT(!keylen || !callback); /* should not be set both */ retry: - cursor->prev= (intptr *)head; + cursor->prev= (intptr *) my_assume_aligned<sizeof(intptr)>(head); do { /* PTR() isn't necessary below, head is a dummy node */ - cursor->curr= (LF_SLIST *)(*cursor->prev); + cursor->curr= my_assume_aligned<sizeof(LF_SLIST *)>((LF_SLIST *)(*cursor->prev)); lf_pin(pins, 1, cursor->curr); - } while (my_atomic_loadptr((void**)cursor->prev) != cursor->curr && + } while (my_atomic_loadptr((void **)my_assume_aligned<sizeof(LF_SLIST *)>(cursor->prev)) != cursor->curr && LF_BACKOFF()); for (;;) { @@ -111,11 +112,14 @@ retry: cur_hashnr= cursor->curr->hashnr; cur_keylen= cursor->curr->keylen; + /* The key element needs to be aligned, not necessary what it points to */ + my_assume_aligned<sizeof(const uchar *)>(&cursor->curr->key); cur_key= cursor->curr->key; do { + /* attempting to my_assume_aligned onlink below broke the implementation */ link= cursor->curr->link; - cursor->next= PTR(link); + cursor->next= my_assume_aligned<sizeof(LF_SLIST *)>(PTR(link)); lf_pin(pins, 0, cursor->next); } while (link != cursor->curr->link && LF_BACKOFF()); @@ -155,6 +159,10 @@ retry: } } + +/* static l_find is the only user my_assume_aligned, keep the rest as c scoped */ +C_MODE_START + /* DESCRIPTION insert a 'node' in the list that starts from 'head' in the correct @@ -168,7 +176,7 @@ retry: it uses pins[0..2], on return all pins are removed. if there're nodes with the same key value, a new node is added before them. */ -static LF_SLIST *l_insert(LF_SLIST * volatile *head, CHARSET_INFO *cs, +static LF_SLIST *l_insert(LF_SLIST **head, CHARSET_INFO *cs, LF_SLIST *node, LF_PINS *pins, uint flags) { CURSOR cursor; @@ -220,7 +228,7 @@ static LF_SLIST *l_insert(LF_SLIST * volatile *head, CHARSET_INFO *cs, NOTE it uses pins[0..2], on return all pins are removed. */ -static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, +static int l_delete(LF_SLIST **head, CHARSET_INFO *cs, uint32 hashnr, const uchar *key, uint keylen, LF_PINS *pins) { CURSOR cursor; @@ -278,7 +286,7 @@ static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, it uses pins[0..2], on return the pin[2] keeps the node found all other pins are removed. */ -static LF_SLIST *l_search(LF_SLIST * volatile *head, CHARSET_INFO *cs, +static LF_SLIST *l_search(LF_SLIST **head, CHARSET_INFO *cs, uint32 hashnr, const uchar *key, uint keylen, LF_PINS *pins) { @@ -319,13 +327,14 @@ static inline my_hash_value_type calc_hash(CHARSET_INFO *cs, #define MAX_LOAD 1.0 /* average number of elements in a bucket */ -static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *); +static int initialize_bucket(LF_HASH *, LF_SLIST **, uint, LF_PINS *); static void default_initializer(LF_HASH *hash, void *dst, const void *src) { memcpy(dst, src, hash->element_size); } + /* Initializes lf_hash, the arguments are compatible with hash_init @@ -398,7 +407,7 @@ void lf_hash_destroy(LF_HASH *hash) int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) { int csize, bucket, hashnr; - LF_SLIST *node, * volatile *el; + LF_SLIST *node, **el; node= (LF_SLIST *)lf_alloc_new(pins); if (unlikely(!node)) @@ -407,7 +416,7 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) node->key= hash_key(hash, (uchar *)(node+1), &node->keylen); hashnr= hash->hash_function(hash->charset, node->key, node->keylen) & INT_MAX32; bucket= hashnr % hash->size; - el= lf_dynarray_lvalue(&hash->array, bucket); + el= (LF_SLIST **)lf_dynarray_lvalue(&hash->array, bucket); if (unlikely(!el)) return -1; if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) @@ -437,7 +446,7 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) */ int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) { - LF_SLIST * volatile *el; + LF_SLIST **el; uint bucket, hashnr; hashnr= hash->hash_function(hash->charset, (uchar *)key, keylen) & INT_MAX32; @@ -445,7 +454,7 @@ int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) /* hide OOM errors - if we cannot initialize a bucket, try the previous one */ for (bucket= hashnr % hash->size; ;bucket= my_clear_highest_bit(bucket)) { - el= lf_dynarray_lvalue(&hash->array, bucket); + el= (LF_SLIST **)lf_dynarray_lvalue(&hash->array, bucket); if (el && (*el || initialize_bucket(hash, el, bucket, pins) == 0)) break; if (unlikely(bucket == 0)) @@ -473,13 +482,13 @@ void *lf_hash_search_using_hash_value(LF_HASH *hash, LF_PINS *pins, my_hash_value_type hashnr, const void *key, uint keylen) { - LF_SLIST * volatile *el, *found; + LF_SLIST **el, *found; uint bucket; /* hide OOM errors - if we cannot initialize a bucket, try the previous one */ for (bucket= hashnr % hash->size; ;bucket= my_clear_highest_bit(bucket)) { - el= lf_dynarray_lvalue(&hash->array, bucket); + el= (LF_SLIST **)lf_dynarray_lvalue(&hash->array, bucket); if (el && (*el || initialize_bucket(hash, el, bucket, pins) == 0)) break; if (unlikely(bucket == 0)) @@ -507,9 +516,9 @@ int lf_hash_iterate(LF_HASH *hash, LF_PINS *pins, CURSOR cursor; uint bucket= 0; int res; - LF_SLIST * volatile *el; + LF_SLIST **el; - el= lf_dynarray_lvalue(&hash->array, bucket); + el= (LF_SLIST **)lf_dynarray_lvalue(&hash->array, bucket); if (unlikely(!el)) return 0; /* if there's no bucket==0, the hash is empty */ if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) @@ -539,14 +548,14 @@ static const uchar *dummy_key= (uchar*)""; 0 - ok -1 - out of memory */ -static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node, +static int initialize_bucket(LF_HASH *hash, LF_SLIST **node, uint bucket, LF_PINS *pins) { uint parent= my_clear_highest_bit(bucket); LF_SLIST *dummy= (LF_SLIST *)my_malloc(key_memory_lf_slist, sizeof(LF_SLIST), MYF(MY_WME)); LF_SLIST **tmp= 0, *cur; - LF_SLIST * volatile *el= lf_dynarray_lvalue(&hash->array, parent); + LF_SLIST **el= (LF_SLIST **)lf_dynarray_lvalue(&hash->array, parent); if (unlikely(!el || !dummy)) return -1; if (*el == NULL && bucket && @@ -574,3 +583,5 @@ static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node, */ return 0; } + +C_MODE_END diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3684db40242..a02b6171a20 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9800,7 +9800,6 @@ and_all_keys(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, key1->right= key1->left= &null_element; key1->next= key1->prev= 0; } - uint new_weight= 0; for (next=key1->first(); next ; next=next->next) { @@ -9813,22 +9812,21 @@ and_all_keys(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, continue; } next->next_key_part=tmp; - new_weight += 1 + tmp->weight; if (use_count) next->increment_use_count(use_count); if (param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS) break; } else - { - new_weight += 1 + key2->weight; next->next_key_part=key2; - } } if (!key1) return &null_element; // Impossible ranges key1->use_count++; - key1->weight= new_weight; + + /* Re-compute the result tree's weight. */ + key1->update_weight_locally(); + key1->max_part_no= MY_MAX(key2->max_part_no, key2->part+1); return key1; } @@ -9992,6 +9990,30 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) return 0; } +/* + @brief + Update the tree weight. + + @detail + Utility function to be called on a SEL_ARG tree root after doing local + modifications concerning changes at this key part. + Assumes that the weight of the graphs connected via next_key_part is + up to dayte. +*/ +void SEL_ARG::update_weight_locally() +{ + uint new_weight= 0; + const SEL_ARG *sl; + for (sl= first(); sl ; sl= sl->next) + { + new_weight++; + if (sl->next_key_part) + new_weight += sl->next_key_part->weight; + } + weight= new_weight; +} + + #ifndef DBUG_OFF /* Verify SEL_TREE's weight. @@ -10728,17 +10750,7 @@ end: key1->use_count++; /* Re-compute the result tree's weight. */ - { - uint new_weight= 0; - const SEL_ARG *sl; - for (sl= key1->first(); sl ; sl= sl->next) - { - new_weight++; - if (sl->next_key_part) - new_weight += sl->next_key_part->weight; - } - key1->weight= new_weight; - } + key1->update_weight_locally(); key1->max_part_no= max_part_no; return key1; diff --git a/sql/opt_range.h b/sql/opt_range.h index 50cd43c0e85..1014176ecc5 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -316,6 +316,8 @@ public: */ uint weight; enum { MAX_WEIGHT = 32000 }; + + void update_weight_locally(); #ifndef DBUG_OFF uint verify_weight(); #endif diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 0ebf3907b58..b129181100c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3068,6 +3068,8 @@ void st_select_lex_node::add_slave(st_select_lex_node *slave_arg) { slave= slave_arg; slave_arg->master= this; + slave->prev= &master->slave; + slave->next= 0; } } @@ -3090,6 +3092,27 @@ void st_select_lex_node::link_chain_down(st_select_lex_node *first) } /* + @brief + Substitute this node in select tree for a newly creates node + + @param subst the node to substitute for + + @details + The function substitute this node in the select tree for a newly + created node subst. This node is just removed from the tree but all + its link fields and the attached sub-tree remain untouched. +*/ + +void st_select_lex_node::substitute_in_tree(st_select_lex_node *subst) +{ + if ((subst->next= next)) + next->prev= &subst->next; + subst->prev= prev; + (*prev)= subst; + subst->master= master; +} + +/* include on level down (but do not link) SYNOPSYS diff --git a/sql/sql_lex.h b/sql/sql_lex.h index be288ebaf3b..a1b9d5f2886 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -793,7 +793,7 @@ public: link_next= NULL; link_prev= NULL; } - + void substitute_in_tree(st_select_lex_node *subst); void set_slave(st_select_lex_node *slave_arg) { slave= slave_arg; } void move_node(st_select_lex_node *where_to_move) diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index e8a201aecfc..b9bdd04eede 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -685,44 +685,61 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl, Query_arena backup; Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup); + + Item *item; + SELECT_LEX *wrapper_sl; + SELECT_LEX_UNIT *derived_unit; + /* - Create SELECT_LEX of the select used in the result of transformation + Create SELECT_LEX wrapper_sl of the select used in the result + of the transformation */ - lex->current_select= tvc_sl; - if (mysql_new_select(lex, 0, NULL)) + if (!(wrapper_sl= new (thd->mem_root) SELECT_LEX())) goto err; - mysql_init_select(lex); - /* Create item list as '*' for the subquery SQ */ - Item *item; - SELECT_LEX *wrapper_sl; - wrapper_sl= lex->current_select; + wrapper_sl->select_number= ++thd->lex->stmt_lex->current_select_number; + wrapper_sl->parent_lex= lex; /* Used in init_query. */ + wrapper_sl->init_query(); + wrapper_sl->init_select(); + + wrapper_sl->nest_level= tvc_sl->nest_level; + wrapper_sl->parsing_place= tvc_sl->parsing_place; wrapper_sl->set_linkage(tvc_sl->get_linkage()); - wrapper_sl->parsing_place= SELECT_LIST; + + lex->current_select= wrapper_sl; item= new (thd->mem_root) Item_field(thd, &wrapper_sl->context, star_clex_str); if (item == NULL || add_item_to_list(thd, item)) goto err; (wrapper_sl->with_wild)++; - - /* Exclude SELECT with TVC */ - tvc_sl->exclude(); + + /* Include the newly created select into the global list of selects */ + wrapper_sl->include_global((st_select_lex_node**)&lex->all_selects_list); + + /* Substitute select node used of TVC for the newly created select */ + tvc_sl->substitute_in_tree(wrapper_sl); + /* - Create derived table DT that will wrap TVC in the result of transformation + Create a unit for the substituted select used for TVC and attach it + to the the wrapper select wrapper_sl as the only unit. The created + unit is the unit for the derived table tvc_x of the transformation. */ - SELECT_LEX *tvc_select; // select for tvc - SELECT_LEX_UNIT *derived_unit; // unit for tvc_select - if (mysql_new_select(lex, 1, tvc_sl)) + if (!(derived_unit= new (thd->mem_root) SELECT_LEX_UNIT())) goto err; - tvc_select= lex->current_select; - derived_unit= tvc_select->master_unit(); - tvc_select->set_linkage(DERIVED_TABLE_TYPE); + derived_unit->init_query(); + derived_unit->thd= thd; + derived_unit->include_down(wrapper_sl); - lex->current_select= wrapper_sl; + /* + Attach the select used of TVC as the only slave to the unit for + the derived table tvc_x of the transformation + */ + derived_unit->add_slave(tvc_sl); + tvc_sl->set_linkage(DERIVED_TABLE_TYPE); /* - Create the name of the wrapping derived table and - add it to the FROM list of the wrapper - */ + Generate the name of the derived table created for TVC and + add it to the FROM list of the wrapping select + */ Table_ident *ti; LEX_CSTRING alias; TABLE_LIST *derived_tab; @@ -741,10 +758,6 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl, wrapper_sl->table_list.first->derived_type= DTYPE_TABLE | DTYPE_MATERIALIZE; lex->derived_tables|= DERIVED_SUBQUERY; - wrapper_sl->where= 0; - wrapper_sl->set_braces(false); - derived_unit->set_with_clause(0); - if (arena) thd->restore_active_arena(arena, &backup); thd->lex->result= save_result; diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index f92700629bb..bd3ef3b60f0 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -584,14 +584,24 @@ static int end_index_scan(TABLE* table) { return 0; } -static void make_key(TABLE* table, uchar* key, key_part_map* map, int parts) { +static void make_key(TABLE* table, uchar** key, key_part_map* map, int parts) { uint prefix_length= 0; KEY_PART_INFO* key_part= table->key_info->key_part; + for (int i=0; i < parts; i++) prefix_length += key_part[i].store_length; + *map= make_prev_keypart_map(parts); - key_copy(key, table->record[0], table->key_info, prefix_length); + + if (!(*key= (uchar *) my_malloc(PSI_NOT_INSTRUMENTED, prefix_length + 1, MYF(MY_WME)))) + { + WSREP_ERROR("Failed to allocate memory for key prefix_length %u", prefix_length); + assert(0); + } + + key_copy(*key, table->record[0], table->key_info, prefix_length); } + } /* namespace Wsrep_schema_impl */ @@ -976,7 +986,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd, Wsrep_schema_impl::binlog_off binlog_off(thd); int error; - uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; + uchar *key=NULL; key_part_map key_map= 0; TABLE* frag_table= 0; @@ -991,7 +1001,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd, Wsrep_schema_impl::store(frag_table, 0, ws_meta.server_id()); Wsrep_schema_impl::store(frag_table, 1, ws_meta.transaction_id().get()); Wsrep_schema_impl::store(frag_table, 2, -1); - Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3); + Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3); if ((error= Wsrep_schema_impl::init_for_index_scan(frag_table, key, key_map))) @@ -1005,9 +1015,11 @@ int Wsrep_schema::update_fragment_meta(THD* thd, } Wsrep_schema_impl::finish_stmt(thd); thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); + my_free(key); DBUG_RETURN(1); } + my_free(key); /* Copy the original record to frag_table->record[1] */ store_record(frag_table, record[1]); @@ -1042,7 +1054,7 @@ static int remove_fragment(THD* thd, seqno.get()); int ret= 0; int error; - uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; + uchar *key= NULL; key_part_map key_map= 0; DBUG_ASSERT(server_id.is_undefined() == false); @@ -1056,7 +1068,7 @@ static int remove_fragment(THD* thd, Wsrep_schema_impl::store(frag_table, 0, server_id); Wsrep_schema_impl::store(frag_table, 1, transaction_id.get()); Wsrep_schema_impl::store(frag_table, 2, seqno.get()); - Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3); + Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3); if ((error= Wsrep_schema_impl::init_for_index_scan(frag_table, key, @@ -1078,6 +1090,8 @@ static int remove_fragment(THD* thd, ret= 1; } + if (key) + my_free(key); Wsrep_schema_impl::end_index_scan(frag_table); return ret; } @@ -1168,7 +1182,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, int ret= 1; int error; TABLE* frag_table= 0; - uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; + uchar *key=NULL; key_part_map key_map= 0; for (std::vector<wsrep::seqno>::const_iterator i= fragments.begin(); @@ -1185,7 +1199,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, Wsrep_schema_impl::store(frag_table, 0, ws_meta.server_id()); Wsrep_schema_impl::store(frag_table, 1, ws_meta.transaction_id().get()); Wsrep_schema_impl::store(frag_table, 2, i->get()); - Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3); + Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3); int error= Wsrep_schema_impl::init_for_index_scan(frag_table, key, @@ -1232,6 +1246,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, Wsrep_schema_impl::finish_stmt(&thd); DBUG_RETURN(1); } + error= Wsrep_schema_impl::init_for_index_scan(frag_table, key, key_map); @@ -1245,6 +1260,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, } error= Wsrep_schema_impl::delete_row(frag_table); + if (error) { WSREP_WARN("Could not delete row from streaming log table: %d", error); @@ -1254,8 +1270,12 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, } Wsrep_schema_impl::end_index_scan(frag_table); Wsrep_schema_impl::finish_stmt(&thd); + my_free(key); + key= NULL; } + if (key) + my_free(key); DBUG_RETURN(ret); } diff --git a/storage/perfschema/pfs_engine_table.cc b/storage/perfschema/pfs_engine_table.cc index 3c8d18826f5..77573f8f168 100644 --- a/storage/perfschema/pfs_engine_table.cc +++ b/storage/perfschema/pfs_engine_table.cc @@ -1536,11 +1536,11 @@ bool pfs_show_status(handlerton *hton, THD *thd, break; case 147: name= "(filename_hash).count"; - size= filename_hash.count; + size= pfs_filename_hash.count; break; case 148: name= "(filename_hash).size"; - size= filename_hash.size; + size= pfs_filename_hash.size; break; case 149: name= "(host_hash).count"; diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc index f1064e2731c..cd82014696c 100644 --- a/storage/perfschema/pfs_instr.cc +++ b/storage/perfschema/pfs_instr.cc @@ -91,8 +91,8 @@ PFS_memory_stat *global_instr_class_memory_array= NULL; static PFS_ALIGNED PFS_cacheline_uint64 thread_internal_id_counter; /** Hash table for instrumented files. */ -LF_HASH filename_hash; -/** True if filename_hash is initialized. */ +LF_HASH pfs_filename_hash; +/** True if pfs_filename_hash is initialized. */ static bool filename_hash_inited= false; my_bool show_compatibility_56= 0; @@ -276,7 +276,7 @@ int init_file_hash(const PFS_global_param *param) { if ((! filename_hash_inited) && (param->m_file_sizing != 0)) { - lf_hash_init(&filename_hash, sizeof(PFS_file*), LF_HASH_UNIQUE, + lf_hash_init(&pfs_filename_hash, sizeof(PFS_file*), LF_HASH_UNIQUE, 0, 0, filename_hash_get_key, &my_charset_bin); filename_hash_inited= true; } @@ -288,7 +288,7 @@ void cleanup_file_hash(void) { if (filename_hash_inited) { - lf_hash_destroy(&filename_hash); + lf_hash_destroy(&pfs_filename_hash); filename_hash_inited= false; } } @@ -722,7 +722,7 @@ void destroy_thread(PFS_thread *pfs) } /** - Get the hash pins for @c filename_hash. + Get the hash pins for @pfs_filename_hash. @param thread The running thread. @returns The LF_HASH pins for the thread. */ @@ -732,7 +732,7 @@ LF_PINS* get_filename_hash_pins(PFS_thread *thread) { if (! filename_hash_inited) return NULL; - thread->m_filename_hash_pins= lf_hash_get_pins(&filename_hash); + thread->m_filename_hash_pins= lf_hash_get_pins(&pfs_filename_hash); } return thread->m_filename_hash_pins; } @@ -849,7 +849,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, search: entry= reinterpret_cast<PFS_file**> - (lf_hash_search(&filename_hash, pins, + (lf_hash_search(&pfs_filename_hash, pins, normalized_filename, normalized_length)); if (entry && (entry != MY_ERRPTR)) { @@ -883,7 +883,7 @@ search: int res; pfs->m_lock.dirty_to_allocated(& dirty_state); - res= lf_hash_insert(&filename_hash, pins, + res= lf_hash_insert(&pfs_filename_hash, pins, &pfs); if (likely(res == 0)) { @@ -990,7 +990,7 @@ void find_and_rename_file(PFS_thread *thread, const char *old_filename, PFS_file **entry; entry= reinterpret_cast<PFS_file**> - (lf_hash_search(&filename_hash, pins, + (lf_hash_search(&pfs_filename_hash, pins, normalized_filename, normalized_length)); if (entry && (entry != MY_ERRPTR)) @@ -1001,7 +1001,7 @@ void find_and_rename_file(PFS_thread *thread, const char *old_filename, return; } - lf_hash_delete(&filename_hash, pins, + lf_hash_delete(&pfs_filename_hash, pins, pfs->m_filename, pfs->m_filename_length); /* @@ -1052,7 +1052,7 @@ void find_and_rename_file(PFS_thread *thread, const char *old_filename, pfs->m_filename_length= normalized_length; int res; - res= lf_hash_insert(&filename_hash, pins, &pfs); + res= lf_hash_insert(&pfs_filename_hash, pins, &pfs); if (likely(res == 0)) return; @@ -1095,7 +1095,7 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs) LF_PINS *pins= get_filename_hash_pins(thread); DBUG_ASSERT(pins != NULL); - lf_hash_delete(&filename_hash, pins, + lf_hash_delete(&pfs_filename_hash, pins, pfs->m_filename, pfs->m_filename_length); if (klass->is_singleton()) klass->m_singleton= NULL; diff --git a/storage/perfschema/pfs_instr.h b/storage/perfschema/pfs_instr.h index c15d30b50e9..ec7dff7d350 100644 --- a/storage/perfschema/pfs_instr.h +++ b/storage/perfschema/pfs_instr.h @@ -807,7 +807,7 @@ void update_thread_derived_flags(); /** Update derived flags for all instruments. */ void update_instruments_derived_flags(); -extern LF_HASH filename_hash; +extern LF_HASH pfs_filename_hash; /** @} */ #endif |