diff options
author | Sergey Petrunya <psergey@askmonty.org> | 2012-06-18 22:38:11 +0400 |
---|---|---|
committer | Sergey Petrunya <psergey@askmonty.org> | 2012-06-18 22:38:11 +0400 |
commit | 90fbd8b22b4b84cdc027fed26012efd87c2b6737 (patch) | |
tree | 48eff1dbe5fd3468e7583d1748de6b5cc8b16c92 | |
parent | db6dbadb5a9edd9e93398b6afe8e3196eb768e0a (diff) | |
parent | 64aa1fcb1354ffa24999a1512258c897116b0928 (diff) | |
download | mariadb-git-90fbd8b22b4b84cdc027fed26012efd87c2b6737.tar.gz |
Merge 5.2->5.3
-rw-r--r-- | client/mysqltest.cc | 11 | ||||
-rw-r--r-- | include/keycache.h | 3 | ||||
-rw-r--r-- | mysql-test/r/func_in.result | 13 | ||||
-rw-r--r-- | mysql-test/r/func_test.result | 41 | ||||
-rw-r--r-- | mysql-test/r/mysqltest_256.result | 1 | ||||
-rw-r--r-- | mysql-test/r/negation_elimination.result | 4 | ||||
-rw-r--r-- | mysql-test/r/ps.result | 65 | ||||
-rw-r--r-- | mysql-test/r/user_var.result | 7 | ||||
-rw-r--r-- | mysql-test/suite/pbxt/r/negation_elimination.result | 4 | ||||
-rw-r--r-- | mysql-test/t/func_in.test | 12 | ||||
-rw-r--r-- | mysql-test/t/func_test.test | 20 | ||||
-rw-r--r-- | mysql-test/t/mysqltest_256.test | 17 | ||||
-rw-r--r-- | mysql-test/t/ps.test | 75 | ||||
-rw-r--r-- | mysql-test/t/user_var.test | 11 | ||||
-rw-r--r-- | mysys/mf_keycache.c | 252 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 41 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 3 | ||||
-rw-r--r-- | sql/item_func.cc | 1 | ||||
-rw-r--r-- | sql/item_row.cc | 1 | ||||
-rw-r--r-- | sql/item_sum.cc | 3 | ||||
-rw-r--r-- | sql/sql_class.h | 3 | ||||
-rw-r--r-- | sql/sql_select.cc | 2 |
22 files changed, 514 insertions, 76 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 612a4885303..bfed483134a 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -8356,8 +8356,12 @@ int main(int argc, char **argv) command->abort_on_error= (command->expected_errors.count == 0 && abort_on_error); - /* delimiter needs to be executed so we can continue to parse */ - ok_to_do= cur_block->ok || command->type == Q_DELIMITER; + /* + some commmands need to be executed or at least parsed unconditionally, + because they change the grammar. + */ + ok_to_do= cur_block->ok || command->type == Q_DELIMITER + || command->type == Q_PERL; /* Some commands need to be "done" the first time if they may get re-iterated over in a true context. This can only happen if there's @@ -8368,8 +8372,7 @@ int main(int argc, char **argv) if (command->type == Q_SOURCE || command->type == Q_ERROR || command->type == Q_WRITE_FILE || - command->type == Q_APPEND_FILE || - command->type == Q_PERL) + command->type == Q_APPEND_FILE) { for (struct st_block *stb= cur_block-1; stb >= block_stack; stb--) { diff --git a/include/keycache.h b/include/keycache.h index 12338037ea1..c19fa5988f8 100644 --- a/include/keycache.h +++ b/include/keycache.h @@ -150,9 +150,10 @@ typedef struct st_key_cache ulong param_partitions; /* number of the key cache partitions */ my_bool key_cache_inited; /* <=> key cache has been created */ my_bool can_be_used; /* usage of cache for read/write is allowed */ - my_bool in_init; /* Set to 1 in MySQL during init/resize */ + my_bool in_init; /* set to 1 in MySQL during init/resize */ uint partitions; /* actual number of partitions */ size_t key_cache_mem_size; /* specified size of the cache memory */ + pthread_mutex_t op_lock; /* to serialize operations like 'resize' */ } KEY_CACHE; diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 91f766468b0..f6d50764cc9 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -150,8 +150,8 @@ Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` A drop table t1; set names utf8; create table t1 (a char(10) character set utf8 not null); -insert into t1 values ('bbbb'),(_koi8r'ÃÃÃÃ'),(_latin1'ÄÄÄÄ'); -select a from t1 where a in ('bbbb',_koi8r'ÃÃÃÃ',_latin1'ÄÄÄÄ') order by a; +insert into t1 values ('bbbb'),(_koi8r'ÃÃÃÃ'),(_latin1'ÄÄÄÄ'); +select a from t1 where a in ('bbbb',_koi8r'ÃÃÃÃ',_latin1'ÄÄÄÄ') order by a; a ÄÄÄÄ bbbb @@ -787,6 +787,15 @@ DROP TABLE t1; # End of test BUG#13012483 # End of 5.1 tests +# +# LP bug#992380 Crash when creating PS for a query with +# subquery in WHERE (see also mysql bug#13012483) +# +CREATE TABLE t1 (a INT); +PREPARE s FROM "SELECT 1 FROM t1 WHERE 1 < ALL (SELECT @:= (1 IN (SELECT 1 FROM t1)) FROM t1)"; +EXECUTE s; +1 +DROP TABLE t1; create table t1 (a bigint, b int); insert t1 values (1,1),(2,2),(3,3); select * from t1 where a in ('2.1'); diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index 5ac1bd7a0ac..ea9d653402c 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -279,3 +279,44 @@ NULL SELECT GREATEST(1.5E+2,1.3E+2,NULL) FROM DUAL; GREATEST(1.5E+2,1.3E+2,NULL) NULL +create table t1 (a int); +insert into t1 values (1), (100), (0), (NULL); +select not a from t1; +not a +0 +0 +1 +NULL +explain extended select not a from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 +Warnings: +Note 1003 select (`test`.`t1`.`a` = 0) AS `not a` from `test`.`t1` +select * from t1 where not a; +a +0 +explain extended select * from t1 where not a; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 0) +select not (a+0) from t1; +not (a+0) +0 +0 +1 +NULL +explain extended select not (a+0) from t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 +Warnings: +Note 1003 select (not((`test`.`t1`.`a` + 0))) AS `not (a+0)` from `test`.`t1` +select * from t1 where not (a+0); +a +0 +explain extended select * from t1 where not (a+0); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (not((`test`.`t1`.`a` + 0))) +drop table t1; diff --git a/mysql-test/r/mysqltest_256.result b/mysql-test/r/mysqltest_256.result new file mode 100644 index 00000000000..043c7208382 --- /dev/null +++ b/mysql-test/r/mysqltest_256.result @@ -0,0 +1 @@ +# Done diff --git a/mysql-test/r/negation_elimination.result b/mysql-test/r/negation_elimination.result index 5b09b0fc511..d32f8a0c3f9 100644 --- a/mysql-test/r/negation_elimination.result +++ b/mysql-test/r/negation_elimination.result @@ -321,7 +321,7 @@ select * from t1 where not(NULL or a); a explain select * from t1 where not(NULL and a); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 5 NULL 21 Using where; Using index +1 SIMPLE t1 ref a a 5 const 1 Using where; Using index select * from t1 where not(NULL and a); a 0 @@ -502,5 +502,5 @@ explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like " id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range a a 5 NULL 4 100.00 Using where; Using index Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a` <> 0) AS `not(not(a))`,((`test`.`t1`.`a` > 2) or `test`.`t1`.`a`) AS `not(a <= 2 and not(a))`,(`test`.`t1`.`a` like '1') AS `not(a not like "1")`,(`test`.`t1`.`a` in (1,2)) AS `not (a not in (1,2))`,(`test`.`t1`.`a` = 2) AS `not(a != 2)` from `test`.`t1` where (`test`.`t1`.`a` <> 0) having (`test`.`t1`.`a` <> 0) +Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a` <> 0) AS `not(not(a))`,((`test`.`t1`.`a` > 2) or (`test`.`t1`.`a` <> 0)) AS `not(a <= 2 and not(a))`,(`test`.`t1`.`a` like '1') AS `not(a not like "1")`,(`test`.`t1`.`a` in (1,2)) AS `not (a not in (1,2))`,(`test`.`t1`.`a` = 2) AS `not(a != 2)` from `test`.`t1` where (`test`.`t1`.`a` <> 0) having (`test`.`t1`.`a` <> 0) drop table t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 4825b4db403..0da031c4686 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -254,15 +254,15 @@ deallocate prepare StMt1; deallocate prepare Stmt1; ERROR HY000: Unknown prepared statement handler (Stmt1) given to DEALLOCATE PREPARE set names utf8; -prepare `ü` from 'select 1234'; -execute `ü` ; +prepare `ü` from 'select 1234'; +execute `ü` ; 1234 1234 set names latin1; -execute `ü`; +execute `ü`; 1234 1234 -deallocate prepare `ü`; +deallocate prepare `ü`; set names default; create table t1 (a varchar(10)) charset=utf8; insert into t1 (a) values ('yahoo'); @@ -3049,6 +3049,62 @@ id select_type table type possible_keys key key_len ref rows Extra DEALLOCATE PREPARE stmt; DROP TABLE t1; End of 5.1 tests. +# +# LP bug#1001500 Crash on the second execution of the PS for +# a query with degenerated conjunctive condition +# (see also mysql bug#12582849) +# +CREATE TABLE t1 ( +pk INTEGER AUTO_INCREMENT, +col_int_nokey INTEGER, +col_int_key INTEGER, +col_varchar_key VARCHAR(1), +col_varchar_nokey VARCHAR(1), +PRIMARY KEY (pk), +KEY (col_int_key), +KEY (col_varchar_key, col_int_key) +); +INSERT INTO t1 ( +col_int_key, col_int_nokey, +col_varchar_key, col_varchar_nokey +) VALUES +(4, 2, 'v', 'v'), +(62, 150, 'v', 'v'); +CREATE TABLE t2 ( +pk INTEGER AUTO_INCREMENT, +col_int_nokey INTEGER, +col_int_key INTEGER, +col_varchar_key VARCHAR(1), +col_varchar_nokey VARCHAR(1), +PRIMARY KEY (pk), +KEY (col_int_key), +KEY (col_varchar_key, col_int_key) +); +INSERT INTO t2 ( +col_int_key, col_int_nokey, +col_varchar_key, col_varchar_nokey +) VALUES +(8, NULL, 'x', 'x'), +(7, 8, 'd', 'd'); +PREPARE stmt FROM ' +SELECT + ( SELECT MAX( SQ1_alias2 .col_int_nokey ) AS SQ1_field1 + FROM ( t2 AS SQ1_alias1 RIGHT JOIN t1 AS SQ1_alias2 + ON ( SQ1_alias2.col_varchar_key = SQ1_alias1.col_varchar_nokey ) + ) + WHERE SQ1_alias2.pk < alias1.col_int_nokey OR alias1.pk + ) AS field1 +FROM ( t1 AS alias1 JOIN t2 AS alias2 ON alias2.pk ) +GROUP BY field1 +'; +EXECUTE stmt; +field1 +150 +EXECUTE stmt; +field1 +150 +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2; prepare stmt from "select date('2010-10-10') between '2010-09-09' and ?"; set @a='2010-11-11'; execute stmt using @a; @@ -3229,3 +3285,4 @@ c1 c2 count(c3) 2012-03-01 01:00:00 3 1 2012-03-01 02:00:00 3 1 DEALLOCATE PREPARE s1; +# End of 5.3 tests diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 374520ff610..19cb54ad2bc 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -456,4 +456,11 @@ SELECT (@v:=a) <> (@v:=1) FROM t1; (@v:=a) <> (@v:=1) 1 DROP TABLE t1; +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2); +SELECT DISTINCT @a:=MIN(t1.a) FROM t1, t1 AS t2 +GROUP BY @b:=(SELECT COUNT(*) > t2.a); +@a:=MIN(t1.a) +1 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/suite/pbxt/r/negation_elimination.result b/mysql-test/suite/pbxt/r/negation_elimination.result index 5c6abad6b4c..0818d2b812e 100644 --- a/mysql-test/suite/pbxt/r/negation_elimination.result +++ b/mysql-test/suite/pbxt/r/negation_elimination.result @@ -321,7 +321,7 @@ select * from t1 where not(NULL or a); a explain select * from t1 where not(NULL and a); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 5 NULL 21 Using where; Using index +1 SIMPLE t1 ref a a 5 const 1 Using where; Using index select * from t1 where not(NULL and a); a 0 @@ -390,5 +390,5 @@ explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like " id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 index a a 5 NULL 5 40.00 Using where; Using index Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a` <> 0) AS `not(not(a))`,((`test`.`t1`.`a` > 2) or `test`.`t1`.`a`) AS `not(a <= 2 and not(a))`,(`test`.`t1`.`a` like '1') AS `not(a not like "1")`,(`test`.`t1`.`a` in (1,2)) AS `not (a not in (1,2))`,(`test`.`t1`.`a` = 2) AS `not(a != 2)` from `test`.`t1` where (`test`.`t1`.`a` <> 0) having (`test`.`t1`.`a` <> 0) +Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a` <> 0) AS `not(not(a))`,((`test`.`t1`.`a` > 2) or (`test`.`t1`.`a` <> 0)) AS `not(a <= 2 and not(a))`,(`test`.`t1`.`a` like '1') AS `not(a not like "1")`,(`test`.`t1`.`a` in (1,2)) AS `not (a not in (1,2))`,(`test`.`t1`.`a` = 2) AS `not(a != 2)` from `test`.`t1` where (`test`.`t1`.`a` <> 0) having (`test`.`t1`.`a` <> 0) drop table t1; diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index ece19882acc..fea3a2ed6d3 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -577,6 +577,16 @@ DROP TABLE t1; --echo # --echo End of 5.1 tests +--echo # +--echo # LP bug#992380 Crash when creating PS for a query with +--echo # subquery in WHERE (see also mysql bug#13012483) +--echo # +CREATE TABLE t1 (a INT); +PREPARE s FROM "SELECT 1 FROM t1 WHERE 1 < ALL (SELECT @:= (1 IN (SELECT 1 FROM t1)) FROM t1)"; +EXECUTE s; + +DROP TABLE t1; + # # lp:817966 int_column IN (string_constant) # @@ -595,4 +605,4 @@ select * from t1 where a='2.1'; select * from t1 where b='2.1'; select * from t1 where IF(1,a,a)='2.1'; drop table t1; - +--echo # End of 5.3 tests diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index 77bf3be5e72..4cba29986a1 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -160,3 +160,23 @@ SELECT LEAST(1.1,1.2,NULL,1.0) FROM DUAL; SELECT GREATEST(1.5E+2,1.3E+2,NULL) FROM DUAL; # End of 4.1 tests + +# +# test of replacing NOT <field> +# +create table t1 (a int); +insert into t1 values (1), (100), (0), (NULL); + +select not a from t1; +explain extended select not a from t1; + +select * from t1 where not a; +explain extended select * from t1 where not a; + +select not (a+0) from t1; +explain extended select not (a+0) from t1; + +select * from t1 where not (a+0); +explain extended select * from t1 where not (a+0); + +drop table t1; diff --git a/mysql-test/t/mysqltest_256.test b/mysql-test/t/mysqltest_256.test new file mode 100644 index 00000000000..fd9447cd2d8 --- /dev/null +++ b/mysql-test/t/mysqltest_256.test @@ -0,0 +1,17 @@ +# +# MDEV-256 lp:995501 - mysqltest attempts to parse Perl code inside a block +# with false condition, gets confused and throws wrong errors +# + +let $run = 0; +if ($run) +{ + --perl + foreach (1) + { + print "In perl\n"; + } + EOF + SELECT 1; +} +--echo # Done diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 2f101b4e42f..89b9f4642e9 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -276,11 +276,11 @@ deallocate prepare Stmt1; # also check that statement names are in right charset. set names utf8; -prepare `ü` from 'select 1234'; -execute `ü` ; +prepare `ü` from 'select 1234'; +execute `ü` ; set names latin1; -execute `ü`; -deallocate prepare `ü`; +execute `ü`; +deallocate prepare `ü`; set names default; @@ -3117,6 +3117,71 @@ DROP TABLE t1; --echo End of 5.1 tests. +--echo # +--echo # LP bug#1001500 Crash on the second execution of the PS for +--echo # a query with degenerated conjunctive condition +--echo # (see also mysql bug#12582849) +--echo # + +CREATE TABLE t1 ( + pk INTEGER AUTO_INCREMENT, + col_int_nokey INTEGER, + col_int_key INTEGER, + + col_varchar_key VARCHAR(1), + col_varchar_nokey VARCHAR(1), + + PRIMARY KEY (pk), + KEY (col_int_key), + KEY (col_varchar_key, col_int_key) +); + +INSERT INTO t1 ( + col_int_key, col_int_nokey, + col_varchar_key, col_varchar_nokey +) VALUES +(4, 2, 'v', 'v'), +(62, 150, 'v', 'v'); + +CREATE TABLE t2 ( + pk INTEGER AUTO_INCREMENT, + col_int_nokey INTEGER, + col_int_key INTEGER, + + col_varchar_key VARCHAR(1), + col_varchar_nokey VARCHAR(1), + + PRIMARY KEY (pk), + KEY (col_int_key), + KEY (col_varchar_key, col_int_key) +); + +INSERT INTO t2 ( + col_int_key, col_int_nokey, + col_varchar_key, col_varchar_nokey +) VALUES +(8, NULL, 'x', 'x'), +(7, 8, 'd', 'd'); + +PREPARE stmt FROM ' +SELECT + ( SELECT MAX( SQ1_alias2 .col_int_nokey ) AS SQ1_field1 + FROM ( t2 AS SQ1_alias1 RIGHT JOIN t1 AS SQ1_alias2 + ON ( SQ1_alias2.col_varchar_key = SQ1_alias1.col_varchar_nokey ) + ) + WHERE SQ1_alias2.pk < alias1.col_int_nokey OR alias1.pk + ) AS field1 +FROM ( t1 AS alias1 JOIN t2 AS alias2 ON alias2.pk ) +GROUP BY field1 +'; + +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; + +DROP TABLE t1, t2; + # # restoring of the Item tree in BETWEEN with dates # @@ -3243,3 +3308,5 @@ GROUP BY c1, c2; EXECUTE s1; DEALLOCATE PREPARE s1; + +--echo # End of 5.3 tests diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index efaf8afd91e..2782f61994d 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -365,4 +365,15 @@ SELECT (@v:=a) <> (@v:=1) FROM t1; DROP TABLE t1; +# +# LP BUG#1001506 Crash on a query with GROUP BY and user variables +# MySQL Bug #11764372 57197: EVEN MORE USER VARIABLE CRASHING FUN +# + +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2); +SELECT DISTINCT @a:=MIN(t1.a) FROM t1, t1 AS t2 +GROUP BY @b:=(SELECT COUNT(*) > t2.a); +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index e0d495ce8e0..dc2d7fdd127 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -5863,31 +5863,31 @@ static KEY_CACHE_FUNCS partitioned_key_cache_funcs = ******************************************************************************/ +static +int repartition_key_cache_internal(KEY_CACHE *keycache, + uint key_cache_block_size, size_t use_mem, + uint division_limit, uint age_threshold, + uint partitions, my_bool use_op_lock); /* - Initialize a key cache + Initialize a key cache : internal SYNOPSIS - init_key_cache() + init_key_cache_internal() keycache pointer to the key cache to be initialized key_cache_block_size size of blocks to keep cached data use_mem total memory to use for cache buffers/structures division_limit division limit (may be zero) age_threshold age threshold (may be zero) partitions number of partitions in the key cache + use_op_lock if TRUE use keycache->op_lock, otherwise - ignore it DESCRIPTION - The function creates a control block structure for a key cache and - places the pointer to this block in the structure keycache. - If the value of the parameter 'partitions' is 0 then a simple key cache - is created. Otherwise a partitioned key cache with the specified number - of partitions is created. - The parameter key_cache_block_size specifies the size of the blocks in - the key cache to be created. The parameters division_limit and - age_threshold determine the initial values of those characteristics of - the key cache that are used for midpoint insertion strategy. The parameter - use_mem specifies the total amount of memory to be allocated for the - key cache buffers and for all auxiliary structures. + The function performs the actions required from init_key_cache(). + It has an additional parameter: use_op_lock. When the parameter + is TRUE than the function initializes keycache->op_lock if needed, + then locks it, and unlocks it before the return. Otherwise the actions + with the lock are omitted. RETURN VALUE total number of blocks in key cache partitions, if successful, @@ -5896,19 +5896,22 @@ static KEY_CACHE_FUNCS partitioned_key_cache_funcs = NOTES if keycache->key_cache_inited != 0 we assume that the memory for the control block of the key cache has been already allocated. - - It's assumed that no two threads call this function simultaneously - referring to the same key cache handle. */ -int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, - size_t use_mem, uint division_limit, - uint age_threshold, uint partitions) +static +int init_key_cache_internal(KEY_CACHE *keycache, uint key_cache_block_size, + size_t use_mem, uint division_limit, + uint age_threshold, uint partitions, + my_bool use_op_lock) { void *keycache_cb; int blocks; if (keycache->key_cache_inited) + { + if (use_op_lock) + pthread_mutex_lock(&keycache->op_lock); keycache_cb= keycache->keycache_cb; + } else { if (partitions == 0) @@ -5929,8 +5932,17 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, keycache->key_cache_type= PARTITIONED_KEY_CACHE; keycache->interface_funcs= &partitioned_key_cache_funcs; } + /* + Initialize op_lock if it's not initialized before. + The mutex may have been initialized before if we are being called + from repartition_key_cache_internal(). + */ + if (use_op_lock) + pthread_mutex_init(&keycache->op_lock, MY_MUTEX_INIT_FAST); keycache->keycache_cb= keycache_cb; keycache->key_cache_inited= 1; + if (use_op_lock) + pthread_mutex_lock(&keycache->op_lock); } if (partitions != 0) @@ -5951,11 +5963,58 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, ((SIMPLE_KEY_CACHE_CB *) keycache_cb)->key_cache_mem_size; if (blocks > 0) keycache->can_be_used= 1; + if (use_op_lock) + pthread_mutex_unlock(&keycache->op_lock); return blocks; } /* + Initialize a key cache + + SYNOPSIS + init_key_cache() + keycache pointer to the key cache to be initialized + key_cache_block_size size of blocks to keep cached data + use_mem total memory to use for cache buffers/structures + division_limit division limit (may be zero) + age_threshold age threshold (may be zero) + partitions number of partitions in the key cache + + DESCRIPTION + The function creates a control block structure for a key cache and + places the pointer to this block in the structure keycache. + If the value of the parameter 'partitions' is 0 then a simple key cache + is created. Otherwise a partitioned key cache with the specified number + of partitions is created. + The parameter key_cache_block_size specifies the size of the blocks in + the key cache to be created. The parameters division_limit and + age_threshold determine the initial values of those characteristics of + the key cache that are used for midpoint insertion strategy. The parameter + use_mem specifies the total amount of memory to be allocated for the + key cache buffers and for all auxiliary structures. + The function calls init_key_cache_internal() to perform all these actions + with the last parameter set to TRUE. + + RETURN VALUE + total number of blocks in key cache partitions, if successful, + <= 0 - otherwise. + + NOTES + It's assumed that no two threads call this function simultaneously + referring to the same key cache handle. +*/ + +int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + size_t use_mem, uint division_limit, + uint age_threshold, uint partitions) +{ + return init_key_cache_internal(keycache, key_cache_block_size, use_mem, + division_limit, age_threshold, partitions, 1); +} + + +/* Resize a key cache SYNOPSIS @@ -5995,11 +6054,13 @@ int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, int blocks= -1; if (keycache->key_cache_inited) { + pthread_mutex_lock(&keycache->op_lock); if ((uint) keycache->param_partitions != keycache->partitions && use_mem) - blocks= repartition_key_cache(keycache, - key_cache_block_size, use_mem, - division_limit, age_threshold, - (uint) keycache->param_partitions); + blocks= repartition_key_cache_internal(keycache, + key_cache_block_size, use_mem, + division_limit, age_threshold, + (uint) keycache->param_partitions, + 0); else { blocks= keycache->interface_funcs->resize(keycache->keycache_cb, @@ -6018,6 +6079,7 @@ int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, ((SIMPLE_KEY_CACHE_CB *)(keycache->keycache_cb))->key_cache_mem_size; keycache->can_be_used= (blocks >= 0); + pthread_mutex_unlock(&keycache->op_lock); } return blocks; } @@ -6051,33 +6113,37 @@ void change_key_cache_param(KEY_CACHE *keycache, uint division_limit, { if (keycache->key_cache_inited) { - + pthread_mutex_lock(&keycache->op_lock); keycache->interface_funcs->change_param(keycache->keycache_cb, division_limit, - age_threshold); + age_threshold); + pthread_mutex_unlock(&keycache->op_lock); } } /* - Destroy a key cache + Destroy a key cache : internal SYNOPSIS - end_key_cache() + end_key_cache_internal() keycache pointer to the key cache to be destroyed cleanup <=> complete free + use_op_lock if TRUE use keycache->op_lock, otherwise - ignore it DESCRIPTION - The function frees the memory allocated for the cache blocks and - auxiliary structures used by the key cache keycache. If the value - of the parameter cleanup is TRUE then all resources used by the key - cache are to be freed. + The function performs the actions required from end_key_cache(). + It has an additional parameter: use_op_lock. When the parameter + is TRUE than the function destroys keycache->op_lock if cleanup is true. + Otherwise the action with the lock is omitted. RETURN VALUE none */ -void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) +static +void end_key_cache_internal(KEY_CACHE *keycache, my_bool cleanup, + my_bool use_op_lock) { if (keycache->key_cache_inited) { @@ -6089,6 +6155,12 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) my_free((uchar *) keycache->keycache_cb, MYF(0)); keycache->keycache_cb= 0; } + /* + We do not destroy op_lock if we are going to reuse the same key cache. + This happens if we are called from repartition_key_cache_internal(). + */ + if (use_op_lock) + pthread_mutex_destroy(&keycache->op_lock); keycache->key_cache_inited= 0; } keycache->can_be_used= 0; @@ -6097,6 +6169,32 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) /* + Destroy a key cache + + SYNOPSIS + end_key_cache() + keycache pointer to the key cache to be destroyed + cleanup <=> complete free + + DESCRIPTION + The function frees the memory allocated for the cache blocks and + auxiliary structures used by the key cache keycache. If the value + of the parameter cleanup is TRUE then all resources used by the key + cache are to be freed. + The function calls end_key_cache_internal() to perform all these actions + with the last parameter set to TRUE. + + RETURN VALUE + none +*/ + +void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) +{ + end_key_cache_internal(keycache, cleanup, 1); +} + + +/* Read a block of data from a key cache into a buffer SYNOPSIS @@ -6140,7 +6238,7 @@ uchar *key_cache_read(KEY_CACHE *keycache, uchar *buff, uint length, uint block_length, int return_buffer) { - if (keycache->key_cache_inited && keycache->can_be_used) + if (keycache->can_be_used) return keycache->interface_funcs->read(keycache->keycache_cb, file, filepos, level, buff, length, @@ -6192,7 +6290,7 @@ int key_cache_insert(KEY_CACHE *keycache, File file, my_off_t filepos, int level, uchar *buff, uint length) { - if (keycache->key_cache_inited && keycache->can_be_used) + if (keycache->can_be_used) return keycache->interface_funcs->insert(keycache->keycache_cb, file, filepos, level, buff, length); @@ -6247,7 +6345,7 @@ int key_cache_write(KEY_CACHE *keycache, uchar *buff, uint length, uint block_length, int force_write) { - if (keycache->key_cache_inited && keycache->can_be_used) + if (keycache->can_be_used) return keycache->interface_funcs->write(keycache->keycache_cb, file, file_extra, filepos, level, @@ -6299,7 +6397,7 @@ int flush_key_blocks(KEY_CACHE *keycache, int file, void *file_extra, enum flush_type type) { - if (keycache->key_cache_inited) + if (keycache->can_be_used) return keycache->interface_funcs->flush(keycache->keycache_cb, file, file_extra, type); return 0; @@ -6330,13 +6428,15 @@ int flush_key_blocks(KEY_CACHE *keycache, int reset_key_cache_counters(const char *name __attribute__((unused)), KEY_CACHE *keycache) { + int rc= 0; if (keycache->key_cache_inited) { - - return keycache->interface_funcs->reset_counters(name, - keycache->keycache_cb); + pthread_mutex_lock(&keycache->op_lock); + rc= keycache->interface_funcs->reset_counters(name, + keycache->keycache_cb); + pthread_mutex_unlock(&keycache->op_lock); } - return 0; + return rc; } @@ -6366,11 +6466,63 @@ void get_key_cache_statistics(KEY_CACHE *keycache, uint partition_no, { if (keycache->key_cache_inited) { + pthread_mutex_lock(&keycache->op_lock); keycache->interface_funcs->get_stats(keycache->keycache_cb, partition_no, key_cache_stats); + pthread_mutex_unlock(&keycache->op_lock); } } + +/* + Repartition a key cache : internal + + SYNOPSIS + repartition_key_cache_internal() + keycache pointer to the key cache to be repartitioned + key_cache_block_size size of blocks to keep cached data + use_mem total memory to use for the new key cache + division_limit new division limit (if not zero) + age_threshold new age threshold (if not zero) + partitions new number of partitions in the key cache + use_op_lock if TRUE use keycache->op_lock, otherwise - ignore it + + DESCRIPTION + The function performs the actions required from repartition_key_cache(). + It has an additional parameter: use_op_lock. When the parameter + is TRUE then the function locks keycache->op_lock at start and + unlocks it before the return. Otherwise the actions with the lock + are omitted. + + RETURN VALUE + number of blocks in the key cache, if successful, + 0 - otherwise. +*/ + +static +int repartition_key_cache_internal(KEY_CACHE *keycache, + uint key_cache_block_size, size_t use_mem, + uint division_limit, uint age_threshold, + uint partitions, my_bool use_op_lock) +{ + uint blocks= -1; + if (keycache->key_cache_inited) + { + if (use_op_lock) + pthread_mutex_lock(&keycache->op_lock); + keycache->interface_funcs->resize(keycache->keycache_cb, + key_cache_block_size, 0, + division_limit, age_threshold); + end_key_cache_internal(keycache, 1, 0); + blocks= init_key_cache_internal(keycache, key_cache_block_size, use_mem, + division_limit, age_threshold, partitions, + 0); + if (use_op_lock) + pthread_mutex_unlock(&keycache->op_lock); + } + return blocks; +} + /* Repartition a key cache @@ -6394,16 +6546,14 @@ void get_key_cache_statistics(KEY_CACHE *keycache, uint partition_no, that are used for midpoint insertion strategy. The parameter use_mem specifies the total amount of memory to be allocated for the new key cache buffers and for all auxiliary structures. + The function calls repartition_key_cache_internal() to perform all these + actions with the last parameter set to TRUE. RETURN VALUE number of blocks in the key cache, if successful, 0 - otherwise. NOTES - The function does not block the calls and executions of other functions - from the key cache interface. However it assumes that the calls of - resize_key_cache itself are serialized. - Currently the function is called when the value of the variable key_cache_partitions is being reset for the key cache keycache. */ @@ -6412,16 +6562,8 @@ int repartition_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, size_t use_mem, uint division_limit, uint age_threshold, uint partitions) { - uint blocks= -1; - if (keycache->key_cache_inited) - { - keycache->interface_funcs->resize(keycache->keycache_cb, - key_cache_block_size, 0, - division_limit, age_threshold); - end_key_cache(keycache, 1); - blocks= init_key_cache(keycache, key_cache_block_size, use_mem, - division_limit, age_threshold, partitions); - } - return blocks; + return repartition_key_cache_internal(keycache, key_cache_block_size, use_mem, + division_limit, age_threshold, + partitions, 1); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 0983fb1e81d..f5960bb6c15 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1497,6 +1497,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) } if (args[1]->maybe_null) maybe_null=1; + with_subselect= 1; with_sum_func= with_sum_func || args[1]->with_sum_func; with_field= with_field || args[1]->with_field; used_tables_cache|= args[1]->used_tables(); @@ -4175,6 +4176,22 @@ Item_cond::fix_fields(THD *thd, Item **ref) if (abort_on_null) item->top_level_item(); + /* + replace degraded condition: + was: <field> + become: <field> = 1 + */ + if (item->type() == FIELD_ITEM) + { + Query_arena backup, *arena; + Item *new_item; + arena= thd->activate_stmt_arena_if_needed(&backup); + if ((new_item= new Item_func_ne(item, new Item_int(0, 1)))) + li.replace(item= new_item); + if (arena) + thd->restore_active_arena(arena, &backup); + } + // item can be substituted in fix_fields if ((!item->fixed && item->fix_fields(thd, li.ref())) || @@ -4861,6 +4878,7 @@ Item_func_regex::fix_fields(THD *thd, Item **ref) return TRUE; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; with_field= args[0]->with_field || args[1]->with_field; + with_subselect|= args[0]->with_subselect | args[1]->with_subselect; max_length= 1; decimals= 0; @@ -5233,6 +5251,28 @@ Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */ } +bool Item_func_not::fix_fields(THD *thd, Item **ref) +{ + if (args[0]->type() == FIELD_ITEM) + { + /* replace "NOT <field>" with "<filed> == 0" */ + Query_arena backup, *arena; + Item *new_item; + bool rc= TRUE; + arena= thd->activate_stmt_arena_if_needed(&backup); + if ((new_item= new Item_func_eq(args[0], new Item_int(0, 1)))) + { + new_item->name= name; + rc= (*ref= new_item)->fix_fields(thd, ref); + } + if (arena) + thd->restore_active_arena(arena, &backup); + return rc; + } + return Item_func::fix_fields(thd, ref); +} + + Item *Item_bool_rowready_func2::neg_transformer(THD *thd) { Item *item= negated_item(); @@ -5641,6 +5681,7 @@ bool Item_equal::fix_fields(THD *thd, Item **ref) used_tables_cache|= item->used_tables(); tmp_table_map= item->not_null_tables(); not_null_tables_cache|= tmp_table_map; + DBUG_ASSERT(!item->with_sum_func && !item->with_subselect); if (item->maybe_null) maybe_null= 1; if (!item->get_item_equal()) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index f047440a244..143fef87abd 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -437,6 +437,7 @@ public: enum Functype functype() const { return NOT_FUNC; } const char *func_name() const { return "not"; } Item *neg_transformer(THD *thd); + bool fix_fields(THD *, Item **); virtual void print(String *str, enum_query_type query_type); }; @@ -503,6 +504,8 @@ public: longlong val_int(); enum Functype functype() const { return NOT_ALL_FUNC; } const char *func_name() const { return "<not>"; } + bool fix_fields(THD *thd, Item **ref) + {return Item_func::fix_fields(thd, ref);} virtual void print(String *str, enum_query_type query_type); void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; }; void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; }; diff --git a/sql/item_func.cc b/sql/item_func.cc index e5225de62f9..00f8496b63b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3027,6 +3027,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, func->maybe_null=1; func->with_sum_func= func->with_sum_func || item->with_sum_func; func->with_field= func->with_field || item->with_field; + func->with_subselect|= item->with_subselect; used_tables_cache|=item->used_tables(); const_item_cache&=item->const_item(); f_args.arg_type[i]=item->result_type(); diff --git a/sql/item_row.cc b/sql/item_row.cc index e2f62bfc868..5136c0100d6 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -89,6 +89,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref) maybe_null|= item->maybe_null; with_sum_func= with_sum_func || item->with_sum_func; with_field= with_field || item->with_field; + with_subselect|= item->with_subselect; } fixed= 1; return FALSE; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 60ec27863bd..86aef19efc0 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -588,6 +588,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) return TRUE; set_if_bigger(decimals, args[i]->decimals); + with_subselect|= args[i]->with_subselect; } result_field=0; max_length=float_length(decimals); @@ -618,6 +619,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) (item= args[0])->check_cols(1)) return TRUE; decimals=item->decimals; + with_subselect= args[0]->with_subselect; switch (hybrid_type= item->result_type()) { case INT_RESULT: @@ -3253,6 +3255,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) args[i]->fix_fields(thd, args + i)) || args[i]->check_cols(1)) return TRUE; + with_subselect|= args[i]->with_subselect; } if (agg_item_charsets(collation, func_name(), diff --git a/sql/sql_class.h b/sql/sql_class.h index 20ca9bd47c5..54ed0860dc1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3120,7 +3120,8 @@ public: if (copy_field) /* Fix for Intel compiler */ { delete [] copy_field; - save_copy_field= copy_field= 0; + save_copy_field= copy_field= NULL; + save_copy_field_end= copy_field_end= NULL; } } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bf5ed800a1d..41fb4cd0f25 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20152,6 +20152,8 @@ copy_fields(TMP_TABLE_PARAM *param) Copy_field *ptr=param->copy_field; Copy_field *end=param->copy_field_end; + DBUG_ASSERT((ptr != NULL && end >= ptr) || (ptr == NULL && end == NULL)); + for (; ptr != end; ptr++) (*ptr->do_copy)(ptr); |