mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
Subquery cache (MWL#66) added.
libmysqld/Makefile.am: The new file added. mysql-test/r/index_merge_myisam.result: subquery_cache optimization option added. mysql-test/r/myisam_mrr.result: subquery_cache optimization option added. mysql-test/r/subquery_cache.result: The subquery cache tests added. mysql-test/r/subselect3.result: Subquery cache switched off to avoid changing read statistics. mysql-test/r/subselect3_jcl6.result: Subquery cache switched off to avoid changing read statistics. mysql-test/r/subselect_no_mat.result: subquery_cache optimization option added. mysql-test/r/subselect_no_opts.result: subquery_cache optimization option added. mysql-test/r/subselect_no_semijoin.result: subquery_cache optimization option added. mysql-test/r/subselect_sj.result: subquery_cache optimization option added. mysql-test/r/subselect_sj_jcl6.result: subquery_cache optimization option added. mysql-test/t/subquery_cache.test: The subquery cache tests added. mysql-test/t/subselect3.test: Subquery cache switched off to avoid changing read statistics. sql/CMakeLists.txt: The new file added. sql/Makefile.am: The new files added. sql/item.cc: Expression cache item (Item_cache_wrapper) added. Item_ref and Item_field fixed for correct usage of result field and fast resolwing in SP. sql/item.h: Expression cache item (Item_cache_wrapper) added. Item_ref and Item_field fixed for correct usage of result field and fast resolwing in SP. sql/item_cmpfunc.cc: Subquery cache added. sql/item_cmpfunc.h: Subquery cache added. sql/item_subselect.cc: Subquery cache added. sql/item_subselect.h: Subquery cache added. sql/item_sum.cc: Registration of subquery parameters added. sql/mysql_priv.h: subquery_cache optimization option added. sql/mysqld.cc: subquery_cache optimization option added. sql/opt_range.cc: Fix due to subquery cache. sql/opt_subselect.cc: Parameters of the function cahnged. sql/procedure.h: .h file guard added. sql/sql_base.cc: Registration of subquery parameters added. sql/sql_class.cc: Option to allow add indeces to temporary table. sql/sql_class.h: Item iterators added. Option to allow add indeces to temporary table. sql/sql_expression_cache.cc: Expression cache for caching subqueries added. sql/sql_expression_cache.h: Expression cache for caching subqueries added. sql/sql_lex.cc: Registration of subquery parameters added. sql/sql_lex.h: Registration of subqueries and subquery parameters added. sql/sql_select.cc: Subquery cache added. sql/sql_select.h: Subquery cache added. sql/sql_union.cc: A new parameter to the function added. sql/sql_update.cc: A new parameter to the function added. sql/table.cc: Procedures to manage temporarty tables index added. sql/table.h: Procedures to manage temporarty tables index added. storage/maria/ha_maria.cc: Fix of handler to allow destoy a table in case of error during the table creation. storage/maria/ha_maria.h: .h file guard added. storage/myisam/ha_myisam.cc: Fix of handler to allow destoy a table in case of error during the table creation.
This commit is contained in:
parent
e5f238a051
commit
ceb5468fd8
43 changed files with 4255 additions and 164 deletions
|
@ -80,7 +80,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
|
|||
sql_tablespace.cc create_options.cc \
|
||||
rpl_injector.cc my_user.c partition_info.cc \
|
||||
sql_servers.cc event_parse_data.cc opt_table_elimination.cc \
|
||||
multi_range_read.cc opt_index_cond_pushdown.cc
|
||||
multi_range_read.cc opt_index_cond_pushdown.cc \
|
||||
sql_expression_cache.cc
|
||||
|
||||
libmysqld_int_a_SOURCES= $(libmysqld_sources)
|
||||
nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)
|
||||
|
|
|
@ -1419,19 +1419,19 @@ drop table t1;
|
|||
#
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='index_merge=off,index_merge_union=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='index_merge_union=on';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,index_merge_sort_union=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch=4;
|
||||
ERROR 42000: Variable 'optimizer_switch' can't be set to the value of '4'
|
||||
set optimizer_switch=NULL;
|
||||
|
@ -1458,21 +1458,21 @@ set optimizer_switch=default;
|
|||
set optimizer_switch='index_merge=off,index_merge_union=off,default';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch=default;
|
||||
select @@global.optimizer_switch;
|
||||
@@global.optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set @@global.optimizer_switch=default;
|
||||
select @@global.optimizer_switch;
|
||||
@@global.optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
#
|
||||
# Check index_merge's @@optimizer_switch flags
|
||||
#
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (a int, b int, c int, filler char(100),
|
||||
|
@ -1582,5 +1582,5 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||
set optimizer_switch=default;
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
drop table t0, t1;
|
||||
|
|
|
@ -394,7 +394,7 @@ drop table t0, t1;
|
|||
# - engine_condition_pushdown does not affect ICP
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (a int, b int, key(a));
|
||||
|
|
1840
mysql-test/r/subquery_cache.result
Normal file
1840
mysql-test/r/subquery_cache.result
Normal file
File diff suppressed because it is too large
Load diff
|
@ -105,6 +105,7 @@ Variable_name Value
|
|||
Handler_read_rnd_next 5
|
||||
delete from t2;
|
||||
insert into t2 values (NULL, 0),(NULL, 0), (NULL, 0), (NULL, 0);
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
select oref, a, a in (select a from t1 where oref=t2.oref) Z from t2;
|
||||
oref a Z
|
||||
|
@ -123,6 +124,7 @@ Handler_read_rnd_next 29
|
|||
select 'No key lookups, seq reads: 29= 5 reads from t2 + 4 * 6 reads from t1.' Z;
|
||||
Z
|
||||
No key lookups, seq reads: 29= 5 reads from t2 + 4 * 6 reads from t1.
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2;
|
||||
create table t1 (a int, b int, primary key (a));
|
||||
insert into t1 values (1,1), (3,1),(100,1);
|
||||
|
@ -952,6 +954,8 @@ i1 i2
|
|||
4 NULL
|
||||
5 0
|
||||
FLUSH STATUS;
|
||||
set @save_optimizer_switch2=@@optimizer_switch;
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
|
||||
SELECT i1, i2
|
||||
FROM t1
|
||||
|
@ -984,6 +988,7 @@ i1 i2
|
|||
SHOW STATUS LIKE '%Handler_read_rnd_next';
|
||||
Variable_name Value
|
||||
Handler_read_rnd_next 19
|
||||
set @@optimizer_switch=@save_optimizer_switch2;
|
||||
DROP TABLE t1,t2;
|
||||
End of 5.1 tests
|
||||
CREATE TABLE t1 (
|
||||
|
|
|
@ -109,6 +109,7 @@ Variable_name Value
|
|||
Handler_read_rnd_next 5
|
||||
delete from t2;
|
||||
insert into t2 values (NULL, 0),(NULL, 0), (NULL, 0), (NULL, 0);
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
select oref, a, a in (select a from t1 where oref=t2.oref) Z from t2;
|
||||
oref a Z
|
||||
|
@ -127,6 +128,7 @@ Handler_read_rnd_next 29
|
|||
select 'No key lookups, seq reads: 29= 5 reads from t2 + 4 * 6 reads from t1.' Z;
|
||||
Z
|
||||
No key lookups, seq reads: 29= 5 reads from t2 + 4 * 6 reads from t1.
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
drop table t1, t2;
|
||||
create table t1 (a int, b int, primary key (a));
|
||||
insert into t1 values (1,1), (3,1),(100,1);
|
||||
|
@ -956,6 +958,8 @@ i1 i2
|
|||
4 NULL
|
||||
5 0
|
||||
FLUSH STATUS;
|
||||
set @save_optimizer_switch2=@@optimizer_switch;
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
|
||||
SELECT i1, i2
|
||||
FROM t1
|
||||
|
@ -988,6 +992,7 @@ i1 i2
|
|||
SHOW STATUS LIKE '%Handler_read_rnd_next';
|
||||
Variable_name Value
|
||||
Handler_read_rnd_next 19
|
||||
set @@optimizer_switch=@save_optimizer_switch2;
|
||||
DROP TABLE t1,t2;
|
||||
End of 5.1 tests
|
||||
CREATE TABLE t1 (
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='materialization=off';
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
|
@ -4927,4 +4927,4 @@ DROP TABLE t1;
|
|||
set optimizer_switch=default;
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='materialization=off,semijoin=off';
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
|
@ -4927,4 +4927,4 @@ DROP TABLE t1;
|
|||
set optimizer_switch=default;
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='semijoin=off';
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
|
||||
set @save_optimizer_switch=@@optimizer_switch;
|
||||
|
@ -4927,4 +4927,4 @@ DROP TABLE t1;
|
|||
set optimizer_switch=default;
|
||||
show variables like 'optimizer_switch';
|
||||
Variable_name Value
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
|
|
|
@ -202,39 +202,39 @@ BUG#37120 optimizer_switch allowable values not according to specification
|
|||
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,materialization=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,semijoin=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,loosescan=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,semijoin=off,materialization=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,materialization=off,semijoin=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,semijoin=off,materialization=off,loosescan=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,semijoin=off,loosescan=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,materialization=off,loosescan=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch=default;
|
||||
drop table t0, t1, t2;
|
||||
drop table t10, t11, t12;
|
||||
|
|
|
@ -206,39 +206,39 @@ BUG#37120 optimizer_switch allowable values not according to specification
|
|||
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,materialization=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,semijoin=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,loosescan=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,semijoin=off,materialization=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,materialization=off,semijoin=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=on,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,semijoin=off,materialization=off,loosescan=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,semijoin=off,loosescan=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch='default,materialization=off,loosescan=off';
|
||||
select @@optimizer_switch;
|
||||
@@optimizer_switch
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on
|
||||
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_condition_pushdown=on,firstmatch=on,loosescan=off,materialization=off,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on
|
||||
set optimizer_switch=default;
|
||||
drop table t0, t1, t2;
|
||||
drop table t10, t11, t12;
|
||||
|
|
509
mysql-test/t/subquery_cache.test
Normal file
509
mysql-test/t/subquery_cache.test
Normal file
|
@ -0,0 +1,509 @@
|
|||
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
create table t1 (a int, b int);
|
||||
insert into t1 values (1,2),(3,4),(1,2),(3,4),(3,4),(4,5),(4,5),(5,6),(5,6),(4,5);
|
||||
create table t2 (c int, d int);
|
||||
insert into t2 values (2,3),(3,4),(5,6),(4,1);
|
||||
|
||||
--echo *
|
||||
--echo * Test subquery as top item in different clauses
|
||||
--echo *
|
||||
--echo #single value subquery test (SELECT list)
|
||||
flush status;
|
||||
select a, (select d from t2 where b=c) from t1;
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
|
||||
select a, (select d from t2 where b=c) from t1;
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
|
||||
--echo #single value subquery test (where)
|
||||
flush status;
|
||||
select a from t1 where (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
|
||||
select a from t1 where (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
--echo #single value subquery test (having)
|
||||
flush status;
|
||||
select a from t1 where a > 0 having (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
|
||||
select a from t1 where a > 0 having (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
--echo #single value subquery test (OUTER JOIN ON)
|
||||
flush status;
|
||||
select ta.a, tb.a from t1 ta join t1 tb on (select d from t2 where tb.b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
|
||||
select ta.a, tb.a from t1 ta join t1 tb on (select d from t2 where tb.b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
--echo #single value subquery test (GROUP BY)
|
||||
flush status;
|
||||
select max(a) from t1 GROUP BY (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
|
||||
flush status;
|
||||
select max(a) from t1 GROUP BY (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
--echo #single value subquery test (distinct GROUP BY)
|
||||
flush status;
|
||||
select distinct max(a) from t1 GROUP BY (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
|
||||
flush status;
|
||||
select distinct max(a) from t1 GROUP BY (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
--echo #single value subquery test (ORDER BY)
|
||||
flush status;
|
||||
select a from t1 ORDER BY (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
|
||||
flush status;
|
||||
select a from t1 ORDER BY (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
--echo #single value subquery test (distinct ORDER BY)
|
||||
flush status;
|
||||
select distinct a from t1 ORDER BY (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
|
||||
flush status;
|
||||
select distinct a from t1 ORDER BY (select d from t2 where b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
--echo #single value subquery test (LEFT JOIN ON)
|
||||
flush status;
|
||||
select ta.a, tb.a from t1 ta left join t1 tb on (select d from t2 where tb.b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
|
||||
select ta.a, tb.a from t1 ta left join t1 tb on (select d from t2 where tb.b=c);
|
||||
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
|
||||
--echo #single value subquery test (PS)
|
||||
prepare stmt1 from 'select a, (select d from t2 where b=c) + 1 from t1';
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
deallocate prepare stmt1;
|
||||
|
||||
--echo #single value subquery test (SP)
|
||||
CREATE PROCEDURE p1() select a, (select d from t2 where b=c) + 1 from t1;
|
||||
|
||||
call p1;
|
||||
call p1;
|
||||
|
||||
drop procedure p1;
|
||||
|
||||
--echo #IN subquery test
|
||||
flush status;
|
||||
|
||||
show status like "subquery_cache%";
|
||||
select a, b , b in (select d from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
insert into t1 values (7,8),(9,NULL);
|
||||
select a, b , b in (select d from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
insert into t2 values (8,NULL);
|
||||
select a, b , b in (select d from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
--echo # multicolumn NOT IN with NULLs
|
||||
flush status;
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
select a, b, (b, a) not in (select d, c from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
select a, b, (b, a) not in (select d, c from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
--echo # multicolumn NOT IN with NULLs (other order)
|
||||
flush status;
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
select a, b, (a, b) not in (select d, c from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
select a, b, (a, b) not in (select d, c from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
--echo # multicolumn IN with NULLs
|
||||
flush status;
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
select a, b, (b, a) in (select d, c from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
select a, b, (b, a) in (select d, c from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
--echo # multicolumn IN with NULLs (other order)
|
||||
flush status;
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
select a, b, (a, b) in (select d, c from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
select a, b, (a, b) in (select d, c from t2) as SUBS from t1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
--echo #IN subquery test (PS)
|
||||
delete from t1 where a > 6;
|
||||
delete from t2 where c > 6;
|
||||
|
||||
prepare stmt1 from 'select a, b , b in (select d from t2) as SUBS from t1';
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
insert into t1 values (7,8),(9,NULL);
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
insert into t2 values (8,NULL);
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
|
||||
deallocate prepare stmt1;
|
||||
|
||||
|
||||
--echo #IN subquery test (SP)
|
||||
delete from t1 where a > 6;
|
||||
delete from t2 where c > 6;
|
||||
|
||||
CREATE PROCEDURE p1() select a, b , b in (select d from t2) as SUBS from t1;
|
||||
|
||||
call p1();
|
||||
show status like "subquery_cache%";
|
||||
call p1();
|
||||
show status like "subquery_cache%";
|
||||
|
||||
insert into t1 values (7,8),(9,NULL);
|
||||
call p1();
|
||||
show status like "subquery_cache%";
|
||||
call p1();
|
||||
show status like "subquery_cache%";
|
||||
|
||||
insert into t2 values (8,NULL);
|
||||
call p1();
|
||||
show status like "subquery_cache%";
|
||||
call p1();
|
||||
show status like "subquery_cache%";
|
||||
|
||||
drop procedure p1;
|
||||
|
||||
|
||||
--echo # test of simple exists
|
||||
select a, b , exists (select * from t2 where b=d) as SUBS from t1;
|
||||
|
||||
--echo # test of prepared statement exists
|
||||
show status like "subquery_cache%";
|
||||
prepare stmt1 from 'select a, b , exists (select * from t2 where b=d) as SUBS from t1';
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
execute stmt1;
|
||||
show status like "subquery_cache%";
|
||||
deallocate prepare stmt1;
|
||||
|
||||
--echo # test of stored procedure exists
|
||||
CREATE PROCEDURE p1() select a, b , exists (select * from t2 where b=d) as SUBS from t1;
|
||||
call p1;
|
||||
call p1;
|
||||
drop procedure p1;
|
||||
|
||||
--echo #several subqueries
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
select a, b , exists (select * from t2 where b=d) as SUBSE, b in (select d from t2) as SUBSI, (select d from t2 where b=c) SUBSR from t1;
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
flush status;
|
||||
select a, b , exists (select * from t2 where b=d) as SUBSE, b in (select d from t2) as SUBSI, (select d from t2 where b=c) SUBSR from t1;
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
--echo #several subqueries (several levels)
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
select a, b, (select exists (select * from t2 where b=d) from t2 where b=c) as SUNS1 from t1;
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
flush status;
|
||||
select a, b, (select exists (select * from t2 where b=d) from t2 where b=c) as SUNS1 from t1;
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
|
||||
--echo #clean up
|
||||
drop table t1,t2;
|
||||
|
||||
--echo test different types
|
||||
--echo #int
|
||||
CREATE TABLE t1 ( a int, b int);
|
||||
INSERT INTO t1 VALUES(1,1),(2,2),(3,3);
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = 2);
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #char
|
||||
CREATE TABLE t1 ( a char(1), b char (1));
|
||||
INSERT INTO t1 VALUES('1','1'),('2','2'),('3','3');
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2');
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #decimal
|
||||
CREATE TABLE t1 ( a decimal(3,1), b decimal(3,1));
|
||||
INSERT INTO t1 VALUES(1,1),(2,2),(3,3);
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = 2);
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #date
|
||||
CREATE TABLE t1 ( a date, b date);
|
||||
INSERT INTO t1 VALUES('1000-01-01','1000-01-01'),('2000-02-01','2000-02-01'),('3000-03-03','3000-03-03');
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2000-02-01');
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #datetime
|
||||
CREATE TABLE t1 ( a datetime, b datetime);
|
||||
INSERT INTO t1 VALUES('1000-01-01 01:01:01','1000-01-01 01:01:01'),('2000-02-02 02:02:02','2000-02-02 02:02:02'),('3000-03-03 03:03:03','3000-03-03 03:03:03');
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2000-02-02 02:02:02');
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #time
|
||||
CREATE TABLE t1 ( a time, b time);
|
||||
INSERT INTO t1 VALUES('01:01:01','01:01:01'),('02:02:02','02:02:02'),('03:03:03','03:03:03');
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '02:02:02');
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #timestamp
|
||||
CREATE TABLE t1 ( a timestamp, b timestamp);
|
||||
INSERT INTO t1 VALUES('2000-02-02 01:01:01','2000-02-02 01:01:01'),('2000-02-02 02:02:02','2000-02-02 02:02:02'),('2000-02-02 03:03:03','2000-02-02 03:03:03');
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2000-02-02 02:02:02');
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #bit
|
||||
CREATE TABLE t1 ( a bit(20), b bit(20));
|
||||
INSERT INTO t1 VALUES(1,1),(2,2),(3,3);
|
||||
SELECT a+0 FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = 2);
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #enum
|
||||
CREATE TABLE t1 ( a enum('1','2','3'), b enum('1','2','3'));
|
||||
INSERT INTO t1 VALUES('1','1'),('2','2'),('3','3');
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2');
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #set
|
||||
CREATE TABLE t1 ( a set('1','2','3'), b set('1','2','3'));
|
||||
INSERT INTO t1 VALUES('1','1'),('2','2'),('3','3');
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2');
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #blob
|
||||
CREATE TABLE t1 ( a blob, b blob);
|
||||
INSERT INTO t1 VALUES('1','1'),('2','2'),('3','3');
|
||||
SELECT a FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = '2');
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #geometry
|
||||
CREATE TABLE t1 ( a geometry, b geometry);
|
||||
INSERT INTO t1 VALUES(POINT(1,1),POINT(1,1)),(POINT(2,2),POINT(2,2)),(POINT(3,3),POINT(3,3));
|
||||
SELECT astext(a) FROM t1 WHERE NOT a IN (SELECT a FROM t1 WHERE b = POINT(2,2));
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #uncacheable queries test (random and side effect)
|
||||
flush status;
|
||||
CREATE TABLE t1 (a int);
|
||||
INSERT INTO t1 VALUES (2), (4), (1), (3);
|
||||
select a, a in (select a from t1) from t1 as ext;
|
||||
show status like "subquery_cache%";
|
||||
select a, a in (select a from t1 where -1 < rand()) from t1 as ext;
|
||||
show status like "subquery_cache%";
|
||||
select a, a in (select a from t1 where -1 < benchmark(a,100)) from t1 as ext;
|
||||
show status like "subquery_cache%";
|
||||
drop table t1;
|
||||
|
||||
--echo #test of sql_big_tables switch and outer table reference in subquery with grouping
|
||||
set option sql_big_tables=1;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
|
||||
INSERT INTO t1 VALUES (1,1),(2,1),(3,2),(4,2),(5,3),(6,3);
|
||||
SELECT (SELECT t1_outer.a FROM t1 AS t1_inner GROUP BY b LIMIT 1) FROM t1 AS t1_outer;
|
||||
drop table t1;
|
||||
set option sql_big_tables=0;
|
||||
|
||||
--echo #test of function reference to outer query
|
||||
set local group_concat_max_len=400;
|
||||
create table t2 (a int, b int);
|
||||
insert into t2 values (1,1), (2,2);
|
||||
select b x, (select group_concat(x) from t2) from t2;
|
||||
drop table t2;
|
||||
set local group_concat_max_len=default;
|
||||
|
||||
--echo #aggregate functions
|
||||
CREATE TABLE t1 (a int, b INT);
|
||||
CREATE TABLE t2 (c int, d INT);
|
||||
|
||||
insert into t1 values (2,1), (3,1), (2,4), (3,4), (10,2), (20,2), (2,5),
|
||||
(3,5), (100,3), (200,3), (10,6), (20,6), (20,7), (100,8), (200,8);
|
||||
insert into t2 values (1,1),(3,3),(20,20);
|
||||
|
||||
--echo aggregate function as parameter of subquery
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
select max(a), (select max(a) from t2 where max(a)=c) from t1 group by b;
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
flush status;
|
||||
select max(a), (select max(a) from t2 where max(a)=c) from t1 group by b;
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
--echo argument of aggregate function as parameter of subquery (illegal use)
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
select max(a), (select a from t2 where a=c) from t1 group by b;
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
set optimizer_switch='subquery_cache=on';
|
||||
flush status;
|
||||
select max(a), (select a from t2 where a=c) from t1 group by b;
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
drop table t1,t2;
|
||||
|
||||
--echo #test of flattening subquery optimisations and cache
|
||||
create table t0 (a int);
|
||||
insert into t0 values (9),(8),(7),(6),(5),(4),(3),(2),(1),(0);
|
||||
|
||||
create table t1(a int, b int);
|
||||
insert into t1 values
|
||||
(0,0),(1,1),(2,2),(0,0),(1,1),(2,2),(0,0),(1,1),(2,2),(0,0),(1,1),(2,2),(0,0),(1,1),(2,2);
|
||||
|
||||
create table t2 (pk int, a int, primary key(pk));
|
||||
insert into t2 select a,a from t0;
|
||||
|
||||
set optimizer_switch='default,semijoin=on,materialization=on,subquery_cache=on';
|
||||
flush status;
|
||||
select * from t1 where a in (select pk from t2);
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
alter table t2 drop primary key;
|
||||
set optimizer_switch='default,semijoin=off,materialization=off,subquery_cache=off';
|
||||
|
||||
explain select * from t1 where a in (select pk from t2);
|
||||
flush status;
|
||||
select * from t1 where a in (select pk from t2);
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
set optimizer_switch='default,semijoin=off,materialization=off,subquery_cache=on';
|
||||
|
||||
explain select * from t1 where a in (select pk from t2);
|
||||
flush status;
|
||||
select * from t1 where a in (select pk from t2);
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
#TODO: switch off cache if materialization used
|
||||
set optimizer_switch='default,semijoin=off,materialization=on,subquery_cache=on';
|
||||
|
||||
explain select * from t1 where a in (select pk from t2);
|
||||
flush status;
|
||||
select * from t1 where a in (select pk from t2);
|
||||
show status like "subquery_cache%";
|
||||
show status like '%Handler_read%';
|
||||
|
||||
drop table t0,t1,t2;
|
||||
|
||||
set optimizer_switch='default';
|
|
@ -98,10 +98,12 @@ show status like '%Handler_read_rnd_next';
|
|||
delete from t2;
|
||||
insert into t2 values (NULL, 0),(NULL, 0), (NULL, 0), (NULL, 0);
|
||||
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
flush status;
|
||||
select oref, a, a in (select a from t1 where oref=t2.oref) Z from t2;
|
||||
show status like '%Handler_read%';
|
||||
select 'No key lookups, seq reads: 29= 5 reads from t2 + 4 * 6 reads from t1.' Z;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
|
@ -794,6 +796,8 @@ SELECT i1, i2 FROM t1;
|
|||
SELECT i1, i2 FROM t2 ORDER BY i1;
|
||||
|
||||
FLUSH STATUS;
|
||||
set @save_optimizer_switch2=@@optimizer_switch;
|
||||
set optimizer_switch='subquery_cache=off';
|
||||
|
||||
--echo
|
||||
SELECT i1, i2
|
||||
|
@ -822,7 +826,7 @@ WHERE (i1, i2)
|
|||
--echo # (read record from t1, but do not read from t2)
|
||||
SHOW STATUS LIKE '%Handler_read_rnd_next';
|
||||
|
||||
|
||||
set @@optimizer_switch=@save_optimizer_switch2;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
|
|
@ -82,6 +82,7 @@ SET (SQL_SOURCE
|
|||
opt_subselect.cc
|
||||
opt_index_cond_pushdown.cc
|
||||
create_options.cc
|
||||
sql_expression_cache.cc
|
||||
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
|
||||
${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
|
||||
${PROJECT_SOURCE_DIR}/include/mysqld_error.h
|
||||
|
|
|
@ -81,7 +81,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||
sql_partition.h partition_info.h partition_element.h \
|
||||
contributors.h sql_servers.h \
|
||||
multi_range_read.h \
|
||||
create_options.h
|
||||
create_options.h \
|
||||
sql_expression_cache.h
|
||||
|
||||
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
||||
item.cc item_sum.cc item_buff.cc item_func.cc \
|
||||
|
@ -131,7 +132,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
|||
sql_servers.cc event_parse_data.cc \
|
||||
opt_table_elimination.cc create_options.cc \
|
||||
multi_range_read.cc \
|
||||
opt_index_cond_pushdown.cc
|
||||
opt_index_cond_pushdown.cc sql_expression_cache.cc
|
||||
|
||||
nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c client_plugin.c
|
||||
|
||||
|
|
554
sql/item.cc
554
sql/item.cc
|
@ -28,6 +28,9 @@
|
|||
|
||||
const String my_null_string("NULL", 4, default_charset_info);
|
||||
|
||||
static int save_field_in_field(Field *from, my_bool *null_value,
|
||||
Field *to, bool no_conversions);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Hybrid_type_traits {_real} */
|
||||
|
@ -541,6 +544,36 @@ Item* Item::transform(Item_transformer transformer, uchar *arg)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Create and set up an expression cache for this item
|
||||
|
||||
@param thd Thread handle
|
||||
@param depends_on List of the expression parameters
|
||||
|
||||
@details
|
||||
The function creates an expression cache for an item and its parameters
|
||||
specified by the 'depends_on' list. Then the expression cache is placed
|
||||
into a cache wrapper that is returned as the result of the function.
|
||||
|
||||
@returns
|
||||
A pointer to created wrapper item if successful, NULL - otherwise
|
||||
*/
|
||||
|
||||
Item* Item::set_expr_cache(THD *thd, List<Item *> &depends_on)
|
||||
{
|
||||
DBUG_ENTER("Item::set_expr_cache");
|
||||
Item_cache_wrapper *wrapper;
|
||||
if ((wrapper= new Item_cache_wrapper(this)) &&
|
||||
!wrapper->fix_fields(thd, (Item**)&wrapper))
|
||||
{
|
||||
if (wrapper->set_cache(thd, depends_on))
|
||||
DBUG_RETURN(this);
|
||||
DBUG_RETURN(wrapper);
|
||||
}
|
||||
DBUG_RETURN(this);
|
||||
}
|
||||
|
||||
|
||||
Item_ident::Item_ident(Name_resolution_context *context_arg,
|
||||
const char *db_name_arg,const char *table_name_arg,
|
||||
const char *field_name_arg)
|
||||
|
@ -549,7 +582,7 @@ Item_ident::Item_ident(Name_resolution_context *context_arg,
|
|||
db_name(db_name_arg), table_name(table_name_arg),
|
||||
field_name(field_name_arg),
|
||||
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
|
||||
cached_table(0), depended_from(0)
|
||||
cached_table(0), depended_from(0), can_be_depended(TRUE)
|
||||
{
|
||||
name = (char*) field_name_arg;
|
||||
}
|
||||
|
@ -561,7 +594,7 @@ Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg)
|
|||
db_name(NullS), table_name(view_arg->alias),
|
||||
field_name(field_name_arg),
|
||||
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
|
||||
cached_table(NULL), depended_from(NULL)
|
||||
cached_table(NULL), depended_from(NULL), can_be_depended(TRUE)
|
||||
{
|
||||
name = (char*) field_name_arg;
|
||||
}
|
||||
|
@ -583,7 +616,8 @@ Item_ident::Item_ident(THD *thd, Item_ident *item)
|
|||
alias_name_used(item->alias_name_used),
|
||||
cached_field_index(item->cached_field_index),
|
||||
cached_table(item->cached_table),
|
||||
depended_from(item->depended_from)
|
||||
depended_from(item->depended_from),
|
||||
can_be_depended(item->can_be_depended)
|
||||
{}
|
||||
|
||||
void Item_ident::cleanup()
|
||||
|
@ -601,7 +635,8 @@ void Item_ident::cleanup()
|
|||
db_name= orig_db_name;
|
||||
table_name= orig_table_name;
|
||||
field_name= orig_field_name;
|
||||
depended_from= 0;
|
||||
/* Store if this Item was depended */
|
||||
can_be_depended= test(depended_from);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -1424,7 +1459,7 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
|
|||
/* An item of type Item_sum is registered <=> ref_by != 0 */
|
||||
if (type() == SUM_FUNC_ITEM && skip_registered &&
|
||||
((Item_sum *) this)->ref_by)
|
||||
return;
|
||||
return;
|
||||
if ((type() != SUM_FUNC_ITEM && with_sum_func) ||
|
||||
(type() == FUNC_ITEM &&
|
||||
(((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC ||
|
||||
|
@ -1745,7 +1780,10 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
|
|||
subselect transformation does not happen in view_prepare_mode
|
||||
and thus val_...() methods can not be called for const items.
|
||||
*/
|
||||
bool resolve_const= ((*arg)->type() == Item::SUBSELECT_ITEM &&
|
||||
bool resolve_const= (((*arg)->type() == Item::SUBSELECT_ITEM ||
|
||||
((*arg)->get_cached_item() &&
|
||||
(*arg)->get_cached_item()->type() ==
|
||||
Item::SUBSELECT_ITEM)) &&
|
||||
thd->lex->view_prepare_mode) ? FALSE : TRUE;
|
||||
conv= new Item_func_conv_charset(*arg, coll.collation, resolve_const);
|
||||
}
|
||||
|
@ -2131,6 +2169,12 @@ bool Item_field::get_time(MYSQL_TIME *ltime)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Item_field::save_result(Field *to)
|
||||
{
|
||||
save_field_in_field(result_field, &null_value, to, TRUE);
|
||||
}
|
||||
|
||||
|
||||
double Item_field::val_result()
|
||||
{
|
||||
if ((null_value=result_field->is_null()))
|
||||
|
@ -3596,6 +3640,15 @@ bool Item::fix_fields(THD *thd, Item **ref)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void Item_ref_null_helper::save_val(Field *to)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
(*ref)->save_val(to);
|
||||
owner->was_null|= null_value= (*ref)->null_value;
|
||||
}
|
||||
|
||||
|
||||
double Item_ref_null_helper::val_real()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
|
@ -3668,7 +3721,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
|
|||
const char *table_name= (resolved_item->table_name ?
|
||||
resolved_item->table_name : "");
|
||||
/* store pointer on SELECT_LEX from which item is dependent */
|
||||
if (mark_item)
|
||||
if (mark_item && mark_item->can_be_depended)
|
||||
mark_item->depended_from= last;
|
||||
if (current->mark_as_dependent(thd, last, /** resolved_item psergey-thu
|
||||
**/mark_item))
|
||||
|
@ -4134,7 +4187,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
|
||||
(Item_ident*) (*reference) :
|
||||
0));
|
||||
|
||||
context->select_lex->
|
||||
register_dependency_item(last_checked_context->select_lex,
|
||||
reference);
|
||||
/*
|
||||
A reference to a view field had been found and we
|
||||
substituted it instead of this Item (find_field_in_tables
|
||||
|
@ -4236,6 +4291,10 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||
context->select_lex, rf,
|
||||
rf);
|
||||
context->select_lex->
|
||||
register_dependency_item(last_checked_context->select_lex,
|
||||
reference);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
|
@ -4243,6 +4302,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||
context->select_lex,
|
||||
this, (Item_ident*)*reference);
|
||||
context->select_lex->
|
||||
register_dependency_item(last_checked_context->select_lex,
|
||||
reference);
|
||||
if (last_checked_context->select_lex->having_fix_field)
|
||||
{
|
||||
Item_ref *rf;
|
||||
|
@ -4549,6 +4611,7 @@ void Item_field::cleanup()
|
|||
{
|
||||
DBUG_ENTER("Item_field::cleanup");
|
||||
Item_ident::cleanup();
|
||||
depended_from= NULL;
|
||||
/*
|
||||
Even if this object was created by direct link to field in setup_wild()
|
||||
it will be linked correctly next time by name of field and table alias.
|
||||
|
@ -5107,47 +5170,69 @@ void Item_field::make_field(Send_field *tmp_field)
|
|||
|
||||
|
||||
/**
|
||||
Set a field's value from a item.
|
||||
Save a field value in another field
|
||||
|
||||
@param from Field to take the value from
|
||||
@param [out] null_value Pointer to the null_value flag to set
|
||||
@param to Field to save the value in
|
||||
@param no_conversions How to deal with NULL value
|
||||
|
||||
@details
|
||||
The function takes the value of the field 'from' and, if this value
|
||||
is not null, it saves in the field 'to' setting off the flag referenced
|
||||
by 'null_value'. Otherwise this flag is set on and field 'to' is
|
||||
also set to null possibly with conversion.
|
||||
|
||||
@note
|
||||
This function is used by the functions Item_field::save_in_field,
|
||||
Item_field::save_org_in_field and Item_ref::save_in_field
|
||||
|
||||
@retval FALSE OK
|
||||
@retval TRUE Error
|
||||
|
||||
*/
|
||||
|
||||
void Item_field::save_org_in_field(Field *to)
|
||||
{
|
||||
if (field->is_null())
|
||||
{
|
||||
null_value=1;
|
||||
set_field_to_null_with_conversions(to, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
to->set_notnull();
|
||||
field_conv(to,field);
|
||||
null_value=0;
|
||||
}
|
||||
}
|
||||
|
||||
int Item_field::save_in_field(Field *to, bool no_conversions)
|
||||
static int save_field_in_field(Field *from, my_bool *null_value,
|
||||
Field *to, bool no_conversions)
|
||||
{
|
||||
int res;
|
||||
if (result_field->is_null())
|
||||
DBUG_ENTER("save_field_in_field");
|
||||
if (from->is_null())
|
||||
{
|
||||
null_value=1;
|
||||
return set_field_to_null_with_conversions(to, no_conversions);
|
||||
(*null_value)= 1;
|
||||
DBUG_RETURN(set_field_to_null_with_conversions(to, no_conversions));
|
||||
}
|
||||
to->set_notnull();
|
||||
|
||||
/*
|
||||
If we're setting the same field as the one we're reading from there's
|
||||
nothing to do. This can happen in 'SET x = x' type of scenarios.
|
||||
*/
|
||||
if (to == result_field)
|
||||
*/
|
||||
if (to == from)
|
||||
{
|
||||
null_value=0;
|
||||
return 0;
|
||||
(*null_value)= 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
res= field_conv(to,result_field);
|
||||
null_value=0;
|
||||
return res;
|
||||
res= field_conv(to, from);
|
||||
(*null_value)= 0;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set a field's value from a item.
|
||||
*/
|
||||
|
||||
void Item_field::save_org_in_field(Field *to)
|
||||
{
|
||||
save_field_in_field(field, &null_value, to, TRUE);
|
||||
}
|
||||
|
||||
|
||||
int Item_field::save_in_field(Field *to, bool no_conversions)
|
||||
{
|
||||
return save_field_in_field(result_field, &null_value, to, no_conversions);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6037,6 +6122,9 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||
refer_type == FIELD_ITEM) ?
|
||||
(Item_ident*) (*reference) :
|
||||
0));
|
||||
context->select_lex->
|
||||
register_dependency_item(last_checked_context->select_lex,
|
||||
reference);
|
||||
/*
|
||||
view reference found, we substituted it instead of this
|
||||
Item, so can quit
|
||||
|
@ -6087,6 +6175,9 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||
thd->change_item_tree(reference, fld);
|
||||
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||
thd->lex->current_select, fld, fld);
|
||||
context->select_lex->
|
||||
register_dependency_item(last_checked_context->select_lex,
|
||||
reference);
|
||||
/*
|
||||
A reference is resolved to a nest level that's outer or the same as
|
||||
the nest level of the enclosing set function : adjust the value of
|
||||
|
@ -6110,6 +6201,9 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||
DBUG_ASSERT(*ref && (*ref)->fixed);
|
||||
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||
context->select_lex, this, this);
|
||||
context->select_lex->
|
||||
register_dependency_item(last_checked_context->select_lex,
|
||||
reference);
|
||||
/*
|
||||
A reference is resolved to a nest level that's outer or the same as
|
||||
the nest level of the enclosing set function : adjust the value of
|
||||
|
@ -6124,7 +6218,11 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||
}
|
||||
else
|
||||
{
|
||||
;
|
||||
if (depended_from && reference)
|
||||
{
|
||||
DBUG_ASSERT(context->select_lex != depended_from);
|
||||
context->select_lex->register_dependency_item(depended_from, reference);
|
||||
}
|
||||
/*
|
||||
It could be that we're referring to something that's in ancestor selects.
|
||||
We must make an appropriate mark_as_dependent() call for each such
|
||||
|
@ -6315,6 +6413,25 @@ bool Item_ref::val_bool_result()
|
|||
}
|
||||
|
||||
|
||||
void Item_ref::save_result(Field *to)
|
||||
{
|
||||
if (result_field)
|
||||
{
|
||||
save_field_in_field(result_field, &null_value, to, TRUE);
|
||||
return;
|
||||
}
|
||||
(*ref)->save_result(to);
|
||||
null_value= (*ref)->null_value;
|
||||
}
|
||||
|
||||
|
||||
void Item_ref::save_val(Field *to)
|
||||
{
|
||||
(*ref)->save_result(to);
|
||||
null_value= (*ref)->null_value;
|
||||
}
|
||||
|
||||
|
||||
double Item_ref::val_real()
|
||||
{
|
||||
DBUG_ASSERT(fixed);
|
||||
|
@ -6432,6 +6549,13 @@ void Item_ref_null_helper::print(String *str, enum_query_type query_type)
|
|||
}
|
||||
|
||||
|
||||
void Item_direct_ref::save_val(Field *to)
|
||||
{
|
||||
(*ref)->save_val(to);
|
||||
null_value=(*ref)->null_value;
|
||||
}
|
||||
|
||||
|
||||
double Item_direct_ref::val_real()
|
||||
{
|
||||
double tmp=(*ref)->val_real();
|
||||
|
@ -6484,6 +6608,364 @@ bool Item_direct_ref::get_date(MYSQL_TIME *ltime,uint fuzzydate)
|
|||
}
|
||||
|
||||
|
||||
Item_cache_wrapper::~Item_cache_wrapper()
|
||||
{
|
||||
delete expr_cache;
|
||||
/* expr_value is Item so it will be destroyed from list of Items */
|
||||
}
|
||||
|
||||
|
||||
Item_cache_wrapper::Item_cache_wrapper(Item *item_arg)
|
||||
:orig_item(item_arg), expr_cache(NULL), expr_value(NULL)
|
||||
{
|
||||
DBUG_ASSERT(orig_item->fixed);
|
||||
max_length= orig_item->max_length;
|
||||
maybe_null= orig_item->maybe_null;
|
||||
decimals= orig_item->decimals;
|
||||
collation.set(orig_item->collation);
|
||||
with_sum_func= orig_item->with_sum_func;
|
||||
unsigned_flag= orig_item->unsigned_flag;
|
||||
name= item_arg->name;
|
||||
name_length= item_arg->name_length;
|
||||
|
||||
if ((expr_value= Item_cache::get_cache(orig_item)))
|
||||
expr_value->setup(orig_item);
|
||||
|
||||
fixed= 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Prepare the expression cache wrapper (do nothing)
|
||||
|
||||
@retval FALSE OK
|
||||
*/
|
||||
|
||||
bool Item_cache_wrapper::fix_fields(THD *thd __attribute__((unused)),
|
||||
Item **it __attribute__((unused)))
|
||||
{
|
||||
DBUG_ASSERT(orig_item->fixed);
|
||||
DBUG_ASSERT(fixed);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Clean the expression cache wrapper up before reusing it.
|
||||
*/
|
||||
|
||||
void Item_cache_wrapper::cleanup()
|
||||
{
|
||||
delete expr_cache;
|
||||
expr_cache= 0;
|
||||
// expr_value is Item so it will be destroyed from list of Items
|
||||
expr_value= 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create an expression cache that uses a temporary table
|
||||
|
||||
@param thd Thread handle
|
||||
@param depends_on Parameters of the expression to create cache for
|
||||
|
||||
@details
|
||||
The function takes 'depends_on' as the list of all parameters for
|
||||
the expression wrapped into this object and creates an expression
|
||||
cache in a temporary table containing the field for the parameters
|
||||
and the result of the expression.
|
||||
|
||||
@retval FALSE OK
|
||||
@retval TRUE Error
|
||||
*/
|
||||
|
||||
bool Item_cache_wrapper::set_cache(THD *thd, List<Item*> &depends_on)
|
||||
{
|
||||
DBUG_ENTER("Item_cache_wrapper::set_cache");
|
||||
expr_cache= new Expression_cache_tmptable(thd, depends_on, expr_value);
|
||||
DBUG_RETURN(expr_cache == NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check if the current values of the parameters are in the expression cache
|
||||
|
||||
@details
|
||||
The function checks whether the current set of the parameters of the
|
||||
referenced item can be found in the expression cache. If so the function
|
||||
returns the item by which the result of the expression can be easily
|
||||
extracted from the cache with the corresponding val_* method.
|
||||
|
||||
@retval NULL - parameters are not in the cache
|
||||
@retval <item*> - item providing the result of the expression found in cache
|
||||
*/
|
||||
|
||||
Item *Item_cache_wrapper::check_cache()
|
||||
{
|
||||
DBUG_ENTER("Item_cache_wrapper::check_cache");
|
||||
if (expr_cache)
|
||||
{
|
||||
Expression_cache_tmptable::result res;
|
||||
Item *cached_value;
|
||||
res= expr_cache->check_value(&cached_value);
|
||||
if (res == Expression_cache_tmptable::HIT)
|
||||
DBUG_RETURN(cached_value);
|
||||
}
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the value of the cached expression and put it in the cache
|
||||
*/
|
||||
|
||||
inline void Item_cache_wrapper::cache()
|
||||
{
|
||||
expr_value->store(orig_item);
|
||||
expr_value->cache_value();
|
||||
expr_cache->put_value(expr_value); // put in expr_cache
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the value of the possibly cached item into the field.
|
||||
*/
|
||||
|
||||
void Item_cache_wrapper::save_val(Field *to)
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::val_int");
|
||||
if (!expr_cache)
|
||||
{
|
||||
orig_item->save_val(to);
|
||||
null_value= orig_item->null_value;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
{
|
||||
cached_value->save_val(to);
|
||||
null_value= cached_value->null_value;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
cache();
|
||||
null_value= expr_value->null_value;
|
||||
expr_value->save_val(to);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the integer value of the possibly cached item.
|
||||
*/
|
||||
|
||||
longlong Item_cache_wrapper::val_int()
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::val_int");
|
||||
if (!expr_cache)
|
||||
{
|
||||
longlong tmp= orig_item->val_int();
|
||||
null_value= orig_item->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
{
|
||||
longlong tmp= cached_value->val_int();
|
||||
null_value= cached_value->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
cache();
|
||||
null_value= expr_value->null_value;
|
||||
DBUG_RETURN(expr_value->val_int());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the real value of the possibly cached item
|
||||
*/
|
||||
|
||||
double Item_cache_wrapper::val_real()
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::val_real");
|
||||
if (!expr_cache)
|
||||
{
|
||||
double tmp= orig_item->val_real();
|
||||
null_value= orig_item->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
{
|
||||
double tmp= cached_value->val_real();
|
||||
null_value= cached_value->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
cache();
|
||||
null_value= expr_value->null_value;
|
||||
DBUG_RETURN(expr_value->val_real());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the string value of the possibly cached item
|
||||
*/
|
||||
|
||||
String *Item_cache_wrapper::val_str(String* str)
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::val_str");
|
||||
if (!expr_cache)
|
||||
{
|
||||
String *tmp= orig_item->val_str(str);
|
||||
null_value= orig_item->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
{
|
||||
String *tmp= cached_value->val_str(str);
|
||||
null_value= cached_value->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
cache();
|
||||
if ((null_value= expr_value->null_value))
|
||||
DBUG_RETURN(NULL);
|
||||
DBUG_RETURN(expr_value->val_str(str));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the decimal value of the possibly cached item
|
||||
*/
|
||||
|
||||
my_decimal *Item_cache_wrapper::val_decimal(my_decimal* decimal_value)
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::val_decimal");
|
||||
if (!expr_cache)
|
||||
{
|
||||
my_decimal *tmp= orig_item->val_decimal(decimal_value);
|
||||
null_value= orig_item->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
{
|
||||
my_decimal *tmp= cached_value->val_decimal(decimal_value);
|
||||
null_value= cached_value->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
cache();
|
||||
if ((null_value= expr_value->null_value))
|
||||
DBUG_RETURN(NULL);
|
||||
DBUG_RETURN(expr_value->val_decimal(decimal_value));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the boolean value of the possibly cached item
|
||||
*/
|
||||
|
||||
bool Item_cache_wrapper::val_bool()
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::val_bool");
|
||||
if (!expr_cache)
|
||||
{
|
||||
bool tmp= orig_item->val_bool();
|
||||
null_value= orig_item->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
{
|
||||
bool tmp= cached_value->val_bool();
|
||||
null_value= cached_value->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
cache();
|
||||
null_value= expr_value->null_value;
|
||||
DBUG_RETURN(expr_value->val_bool());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check for NULL the value of the possibly cached item
|
||||
*/
|
||||
|
||||
bool Item_cache_wrapper::is_null()
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::is_null");
|
||||
if (!expr_cache)
|
||||
{
|
||||
bool tmp= orig_item->is_null();
|
||||
null_value= orig_item->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
{
|
||||
bool tmp= cached_value->is_null();
|
||||
null_value= cached_value->null_value;
|
||||
DBUG_RETURN(tmp);
|
||||
}
|
||||
cache();
|
||||
DBUG_RETURN((null_value= expr_value->null_value));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the date value of the possibly cached item
|
||||
*/
|
||||
|
||||
bool Item_cache_wrapper::get_date(MYSQL_TIME *ltime, uint fuzzydate)
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::get_date");
|
||||
if (!expr_cache)
|
||||
DBUG_RETURN((null_value= orig_item->get_date(ltime, fuzzydate)));
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
DBUG_RETURN((null_value= cached_value->get_date(ltime, fuzzydate)));
|
||||
|
||||
cache();
|
||||
DBUG_RETURN((null_value= expr_value->get_date(ltime, fuzzydate)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the time value of the possibly cached item
|
||||
*/
|
||||
|
||||
bool Item_cache_wrapper::get_time(MYSQL_TIME *ltime)
|
||||
{
|
||||
Item *cached_value;
|
||||
DBUG_ENTER("Item_cache_wrapper::get_time");
|
||||
if (!expr_cache)
|
||||
DBUG_RETURN((null_value= orig_item->get_time(ltime)));
|
||||
|
||||
if ((cached_value= check_cache()))
|
||||
DBUG_RETURN((null_value= cached_value->get_time(ltime)));
|
||||
|
||||
cache();
|
||||
DBUG_RETURN((null_value= expr_value->get_time(ltime)));
|
||||
}
|
||||
|
||||
|
||||
int Item_cache_wrapper::save_in_field(Field *to, bool no_conversions)
|
||||
{
|
||||
int res;
|
||||
DBUG_ASSERT(!result_field);
|
||||
res= orig_item->save_in_field(to, no_conversions);
|
||||
null_value= orig_item->null_value;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Prepare referenced field then call usual Item_direct_ref::fix_fields .
|
||||
|
||||
|
|
170
sql/item.h
170
sql/item.h
|
@ -507,7 +507,7 @@ public:
|
|||
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
|
||||
PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM,
|
||||
XPATH_NODESET, XPATH_NODESET_CMP,
|
||||
VIEW_FIXER_ITEM};
|
||||
VIEW_FIXER_ITEM, EXPR_CACHE_ITEM};
|
||||
|
||||
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
|
||||
|
||||
|
@ -737,6 +737,17 @@ public:
|
|||
*/
|
||||
virtual bool val_bool();
|
||||
virtual String *val_nodeset(String*) { return 0; }
|
||||
|
||||
/*
|
||||
save_val() is method of val_* family which stores value in the given
|
||||
field.
|
||||
*/
|
||||
virtual void save_val(Field *to) { save_org_in_field(to); }
|
||||
/*
|
||||
save_result() is method of val*result() family which stores value in
|
||||
the given field.
|
||||
*/
|
||||
virtual void save_result(Field *to) { save_val(to); }
|
||||
/* Helper functions, see item_sum.cc */
|
||||
String *val_string_from_real(String *str);
|
||||
String *val_string_from_int(String *str);
|
||||
|
@ -1092,6 +1103,8 @@ public:
|
|||
|
||||
virtual Item *neg_transformer(THD *thd) { return NULL; }
|
||||
virtual Item *update_value_transformer(uchar *select_arg) { return this; }
|
||||
virtual Item *expr_cache_insert_transformer(uchar *thd_arg) { return this; }
|
||||
virtual bool expr_cache_is_needed(THD *) { return FALSE; }
|
||||
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
|
||||
void delete_self()
|
||||
{
|
||||
|
@ -1145,6 +1158,9 @@ public:
|
|||
{ return Field::GEOM_GEOMETRY; };
|
||||
String *check_well_formed_result(String *str, bool send_error= 0);
|
||||
bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs);
|
||||
|
||||
Item* set_expr_cache(THD *thd, List<Item*> &depends_on);
|
||||
virtual Item *get_cached_item() { return NULL; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -1524,6 +1540,19 @@ public:
|
|||
*/
|
||||
TABLE_LIST *cached_table;
|
||||
st_select_lex *depended_from;
|
||||
/*
|
||||
Some Items resolved in another select should not be marked as dependency
|
||||
of the subquery where they are. During normal name resolution, we check
|
||||
this. Stored procedures and prepared statements first try to resolve an
|
||||
ident item using a cached table reference and field position from the
|
||||
previous query execution (cached_table/cached_field_index). If the
|
||||
tables were not changed, the ident matches the table/field, and we have
|
||||
faster resolution of the ident without looking through all tables and
|
||||
fields in the query. But in this case, we can not check all conditions
|
||||
about this ident item dependency, so we should cache the condition in
|
||||
this variable.
|
||||
*/
|
||||
bool can_be_depended;
|
||||
Item_ident(Name_resolution_context *context_arg,
|
||||
const char *db_name_arg, const char *table_name_arg,
|
||||
const char *field_name_arg);
|
||||
|
@ -1606,6 +1635,7 @@ public:
|
|||
longlong val_int();
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
String *val_str(String*);
|
||||
void save_result(Field *to);
|
||||
double val_result();
|
||||
longlong val_int_result();
|
||||
String *str_result(String* tmp);
|
||||
|
@ -1926,8 +1956,6 @@ public:
|
|||
virtual void print(String *str, enum_query_type query_type);
|
||||
Item_num *neg ();
|
||||
uint decimal_precision() const { return max_length; }
|
||||
bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
|
||||
bool check_vcol_func_processor(uchar *arg) { return FALSE;}
|
||||
};
|
||||
|
||||
|
||||
|
@ -2389,6 +2417,8 @@ public:
|
|||
Item *it= ((Item *) item)->real_item();
|
||||
return ref && (*ref)->eq(it, binary_cmp);
|
||||
}
|
||||
void save_val(Field *to);
|
||||
void save_result(Field *to);
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
|
@ -2519,6 +2549,7 @@ public:
|
|||
alias_name_used_arg)
|
||||
{}
|
||||
|
||||
void save_val(Field *to);
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
String *val_str(String* tmp);
|
||||
|
@ -2529,6 +2560,134 @@ public:
|
|||
virtual Ref_Type ref_type() { return DIRECT_REF; }
|
||||
};
|
||||
|
||||
class Expression_cache;
|
||||
class Item_cache;
|
||||
|
||||
|
||||
/**
|
||||
The objects of this class can store its values in an expression cache.
|
||||
*/
|
||||
|
||||
class Item_cache_wrapper :public Item_result_field
|
||||
{
|
||||
private:
|
||||
/* Pointer on the cached expression */
|
||||
Item *orig_item;
|
||||
Expression_cache *expr_cache;
|
||||
/*
|
||||
In order to put the expression into the expression cache and return
|
||||
value of val_*() method, we will need to get the expression value twice
|
||||
(probably in different types). In order to avoid making two
|
||||
(potentially costly) orig_item->val_*() calls, we store expression value
|
||||
in this Item_cache object.
|
||||
*/
|
||||
Item_cache *expr_value;
|
||||
|
||||
Item *check_cache();
|
||||
inline void cache();
|
||||
|
||||
public:
|
||||
Item_cache_wrapper(Item *item_arg);
|
||||
~Item_cache_wrapper();
|
||||
|
||||
const char *func_name() const { return "<expr_cache>"; }
|
||||
enum Type type() const { return EXPR_CACHE_ITEM; }
|
||||
virtual Item *get_cached_item() { return orig_item; }
|
||||
|
||||
bool set_cache(THD *thd, List<Item*> &depends_on);
|
||||
|
||||
bool fix_fields(THD *thd, Item **it);
|
||||
void fix_length_and_dec() {}
|
||||
void cleanup();
|
||||
|
||||
/* Methods of getting value which should be cached in the cache */
|
||||
void save_val(Field *to);
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
String *val_str(String* tmp);
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
bool val_bool();
|
||||
bool is_null();
|
||||
bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
|
||||
bool get_time(MYSQL_TIME *ltime);
|
||||
bool send(Protocol *protocol, String *buffer)
|
||||
{
|
||||
if (result_field)
|
||||
return protocol->store(result_field);
|
||||
return Item::send(protocol, buffer);
|
||||
}
|
||||
void save_org_in_field(Field *field)
|
||||
{
|
||||
save_val(field);
|
||||
}
|
||||
void save_in_result_field(bool no_conversions)
|
||||
{
|
||||
save_val(result_field);
|
||||
}
|
||||
|
||||
/* Following methods make this item transparent as much as possible */
|
||||
|
||||
virtual void print(String *str, enum_query_type query_type)
|
||||
{
|
||||
/* TODO: maybe print something for EXPLAIN EXTENDED */
|
||||
return orig_item->print(str, query_type);
|
||||
}
|
||||
virtual const char *full_name() const { return orig_item->full_name(); }
|
||||
virtual void make_field(Send_field *field) { orig_item->make_field(field); }
|
||||
bool eq(const Item *item, bool binary_cmp) const
|
||||
{
|
||||
Item *it= ((Item *) item)->real_item();
|
||||
return orig_item->eq(it, binary_cmp);
|
||||
}
|
||||
void fix_after_pullout(st_select_lex *new_parent, Item **refptr)
|
||||
{
|
||||
orig_item->fix_after_pullout(new_parent, &orig_item);
|
||||
}
|
||||
int save_in_field(Field *to, bool no_conversions);
|
||||
enum Item_result result_type () const { return orig_item->result_type(); }
|
||||
enum_field_types field_type() const { return orig_item->field_type(); }
|
||||
table_map used_tables() const { return orig_item->used_tables(); }
|
||||
void update_used_tables() { orig_item->update_used_tables(); }
|
||||
bool const_item() const { return orig_item->const_item(); }
|
||||
table_map not_null_tables() const { return orig_item->not_null_tables(); }
|
||||
bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
|
||||
{
|
||||
return orig_item->walk(processor, walk_subquery, arg) ||
|
||||
(this->*processor)(arg);
|
||||
}
|
||||
bool enumerate_field_refs_processor(uchar *arg)
|
||||
{ return orig_item->enumerate_field_refs_processor(arg); }
|
||||
bool result_as_longlong() { return orig_item->result_as_longlong(); }
|
||||
Item_field *filed_for_view_update()
|
||||
{ return orig_item->filed_for_view_update(); }
|
||||
|
||||
/* Row emulation: forwarding of ROW-related calls to orig_item */
|
||||
uint cols()
|
||||
{ return result_type() == ROW_RESULT ? orig_item->cols() : 1; }
|
||||
Item* element_index(uint i)
|
||||
{ return result_type() == ROW_RESULT ? orig_item->element_index(i) : this; }
|
||||
Item** addr(uint i)
|
||||
{ return result_type() == ROW_RESULT ? orig_item->addr(i) : 0; }
|
||||
bool check_cols(uint c)
|
||||
{
|
||||
return (result_type() == ROW_RESULT ?
|
||||
orig_item->check_cols(c) :
|
||||
Item::check_cols(c));
|
||||
}
|
||||
bool null_inside()
|
||||
{ return result_type() == ROW_RESULT ? orig_item->null_inside() : 0; }
|
||||
void bring_value()
|
||||
{
|
||||
if (result_type() == ROW_RESULT)
|
||||
orig_item->bring_value();
|
||||
}
|
||||
bool check_vcol_func_processor(uchar *arg)
|
||||
{
|
||||
return trace_unsupported_by_check_vcol_func_processor("cache");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Class for view fields, the same as Item_direct_ref, but call fix_fields
|
||||
of reference if it is not called yet
|
||||
|
@ -2638,6 +2797,7 @@ public:
|
|||
const char *table_name_arg, const char *field_name_arg)
|
||||
:Item_ref(context_arg, item, table_name_arg, field_name_arg),
|
||||
owner(master) {}
|
||||
void save_val(Field *to);
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
String* val_str(String* s);
|
||||
|
@ -3172,7 +3332,8 @@ public:
|
|||
example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING),
|
||||
value_cached(0)
|
||||
{
|
||||
fixed= 1;
|
||||
fixed= 1;
|
||||
maybe_null= 1;
|
||||
null_value= 1;
|
||||
}
|
||||
Item_cache(enum_field_types field_type_arg):
|
||||
|
@ -3180,6 +3341,7 @@ public:
|
|||
value_cached(0)
|
||||
{
|
||||
fixed= 1;
|
||||
maybe_null= 1;
|
||||
null_value= 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1750,6 +1750,45 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Add an expression cache for this subquery if it is needed
|
||||
|
||||
@param thd_arg Thread handle
|
||||
|
||||
@details
|
||||
The function checks whether an expression cache is needed for this item
|
||||
and if if so wraps the item into an item of the class
|
||||
Item_exp_cache_wrapper with an appropriate expression cache set up there.
|
||||
|
||||
@note
|
||||
used from Item::transform()
|
||||
|
||||
@return
|
||||
new wrapper item if an expression cache is needed,
|
||||
this item - otherwise
|
||||
*/
|
||||
|
||||
Item *Item_in_optimizer::expr_cache_insert_transformer(uchar *thd_arg)
|
||||
{
|
||||
THD *thd= (THD*) thd_arg;
|
||||
DBUG_ENTER("Item_in_optimizer::expr_cache_insert_transformer");
|
||||
List<Item*> &depends_on= ((Item_subselect *)args[1])->depends_on;
|
||||
|
||||
/* Add left expression to the list of the parameters of the subquery */
|
||||
if (args[0]->cols() == 1)
|
||||
depends_on.push_front((Item**)args);
|
||||
else
|
||||
for (int i= 0; i < args[0]->cols(); i++)
|
||||
{
|
||||
depends_on.push_front(args[0]->addr(i));
|
||||
}
|
||||
|
||||
if (args[1]->expr_cache_is_needed(thd))
|
||||
DBUG_RETURN(set_expr_cache(thd, depends_on));
|
||||
DBUG_RETURN(this);
|
||||
}
|
||||
|
||||
|
||||
longlong Item_in_optimizer::val_int()
|
||||
{
|
||||
bool tmp;
|
||||
|
|
|
@ -264,6 +264,7 @@ public:
|
|||
Item_cache **get_cache() { return &cache; }
|
||||
void keep_top_level_cache();
|
||||
Item *transform(Item_transformer transformer, uchar *arg);
|
||||
virtual Item *expr_cache_insert_transformer(uchar *thd_arg);
|
||||
};
|
||||
|
||||
class Comp_creator
|
||||
|
|
|
@ -93,6 +93,8 @@ void Item_subselect::init(st_select_lex *select_lex,
|
|||
SELECT_LEX *upper= unit->outer_select();
|
||||
if (upper->parsing_place == IN_HAVING)
|
||||
upper->subquery_in_having= 1;
|
||||
/* The subquery is an expression cache candidate */
|
||||
upper->expr_cache_may_be_used[upper->parsing_place]= TRUE;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -116,6 +118,7 @@ void Item_subselect::cleanup()
|
|||
}
|
||||
if (engine)
|
||||
engine->cleanup();
|
||||
depends_on.empty();
|
||||
reset();
|
||||
value_assigned= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
|
@ -486,6 +489,56 @@ bool Item_subselect::exec()
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Check if an expression cache is needed for this subquery
|
||||
|
||||
@param thd Thread handle
|
||||
|
||||
@details
|
||||
The function checks whether a cache is needed for a subquery and whether
|
||||
the result of the subquery can be put in cache.
|
||||
|
||||
@retval TRUE cache is needed
|
||||
@retval FALSE otherwise
|
||||
*/
|
||||
|
||||
bool Item_subselect::expr_cache_is_needed(THD *thd)
|
||||
{
|
||||
return (depends_on.elements &&
|
||||
engine->cols() == 1 &&
|
||||
optimizer_flag(thd, OPTIMIZER_SWITCH_SUBQUERY_CACHE) &&
|
||||
!(engine->uncacheable() & (UNCACHEABLE_RAND |
|
||||
UNCACHEABLE_SIDEEFFECT)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check if an expression cache is needed for this subquery
|
||||
|
||||
@param thd Thread handle
|
||||
|
||||
@details
|
||||
The function checks whether a cache is needed for a subquery and whether
|
||||
the result of the subquery can be put in cache.
|
||||
|
||||
@note
|
||||
This method allows many columns in the subquery because it is supported by
|
||||
Item_in optimizer and result of the IN subquery will be scalar in this
|
||||
case.
|
||||
|
||||
@retval TRUE cache is needed
|
||||
@retval FALSE otherwise
|
||||
*/
|
||||
|
||||
bool Item_in_subselect::expr_cache_is_needed(THD *thd)
|
||||
{
|
||||
return (depends_on.elements &&
|
||||
optimizer_flag(thd, OPTIMIZER_SWITCH_SUBQUERY_CACHE) &&
|
||||
!(engine->uncacheable() & (UNCACHEABLE_RAND |
|
||||
UNCACHEABLE_SIDEEFFECT)));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Compute the IN predicate if the left operand's cache changed.
|
||||
*/
|
||||
|
@ -784,6 +837,36 @@ void Item_singlerow_subselect::fix_length_and_dec()
|
|||
maybe_null= engine->may_be_null();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Add an expression cache for this subquery if it is needed
|
||||
|
||||
@param thd_arg Thread handle
|
||||
|
||||
@details
|
||||
The function checks whether an expression cache is needed for this item
|
||||
and if if so wraps the item into an item of the class
|
||||
Item_exp_cache_wrapper with an appropriate expression cache set up there.
|
||||
|
||||
@note
|
||||
used from Item::transform()
|
||||
|
||||
@return
|
||||
new wrapper item if an expression cache is needed,
|
||||
this item - otherwise
|
||||
*/
|
||||
|
||||
Item* Item_singlerow_subselect::expr_cache_insert_transformer(uchar *thd_arg)
|
||||
{
|
||||
THD *thd= (THD*) thd_arg;
|
||||
DBUG_ENTER("Item_singlerow_subselect::expr_cache_insert_transformer");
|
||||
|
||||
if (expr_cache_is_needed(thd))
|
||||
DBUG_RETURN(set_expr_cache(thd, depends_on));
|
||||
DBUG_RETURN(this);
|
||||
}
|
||||
|
||||
|
||||
uint Item_singlerow_subselect::cols()
|
||||
{
|
||||
return engine->cols();
|
||||
|
@ -976,6 +1059,36 @@ void Item_exists_subselect::fix_length_and_dec()
|
|||
unit->global_parameters->select_limit= new Item_int((int32) 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Add an expression cache for this subquery if it is needed
|
||||
|
||||
@param thd_arg Thread handle
|
||||
|
||||
@details
|
||||
The function checks whether an expression cache is needed for this item
|
||||
and if if so wraps the item into an item of the class
|
||||
Item_exp_cache_wrapper with an appropriate expression cache set up there.
|
||||
|
||||
@note
|
||||
used from Item::transform()
|
||||
|
||||
@return
|
||||
new wrapper item if an expression cache is needed,
|
||||
this item - otherwise
|
||||
*/
|
||||
|
||||
Item* Item_exists_subselect::expr_cache_insert_transformer(uchar *thd_arg)
|
||||
{
|
||||
THD *thd= (THD*) thd_arg;
|
||||
DBUG_ENTER("Item_exists_subselect::expr_cache_insert_transformer");
|
||||
|
||||
if (substype() == EXISTS_SUBS && expr_cache_is_needed(thd))
|
||||
DBUG_RETURN(set_expr_cache(thd, depends_on));
|
||||
DBUG_RETURN(this);
|
||||
}
|
||||
|
||||
|
||||
double Item_exists_subselect::val_real()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
|
@ -3841,6 +3954,7 @@ subselect_uniquesubquery_engine*
|
|||
subselect_hash_sj_engine::make_unique_engine()
|
||||
{
|
||||
Item_in_subselect *item_in= (Item_in_subselect *) item;
|
||||
Item_iterator_row it(item_in->left_expr);
|
||||
/* The only index on the temporary table. */
|
||||
KEY *tmp_key= tmp_table->key_info;
|
||||
/* Number of keyparts in tmp_key. */
|
||||
|
@ -3858,41 +3972,9 @@ subselect_hash_sj_engine::make_unique_engine()
|
|||
*/
|
||||
if (!(tab= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB))))
|
||||
DBUG_RETURN(NULL);
|
||||
tab->table= tmp_table;
|
||||
tab->ref.key= 0; /* The only temp table index. */
|
||||
tab->ref.key_length= tmp_key->key_length;
|
||||
if (!(tab->ref.key_buff=
|
||||
(uchar*) thd->calloc(ALIGN_SIZE(tmp_key->key_length) * 2)) ||
|
||||
!(tab->ref.key_copy=
|
||||
(store_key**) thd->alloc((sizeof(store_key*) *
|
||||
(tmp_key_parts + 1)))) ||
|
||||
!(tab->ref.items=
|
||||
(Item**) thd->alloc(sizeof(Item*) * tmp_key_parts)))
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
KEY_PART_INFO *cur_key_part= tmp_key->key_part;
|
||||
store_key **ref_key= tab->ref.key_copy;
|
||||
uchar *cur_ref_buff= tab->ref.key_buff;
|
||||
|
||||
for (uint i= 0; i < tmp_key_parts; i++, cur_key_part++, ref_key++)
|
||||
{
|
||||
tab->ref.items[i]= item_in->left_expr->element_index(i);
|
||||
int null_count= test(cur_key_part->field->real_maybe_null());
|
||||
*ref_key= new store_key_item(thd, cur_key_part->field,
|
||||
/* TIMOUR:
|
||||
the NULL byte is taken into account in
|
||||
cur_key_part->store_length, so instead of
|
||||
cur_ref_buff + test(maybe_null), we could
|
||||
use that information instead.
|
||||
*/
|
||||
cur_ref_buff + null_count,
|
||||
null_count ? tab->ref.key_buff : 0,
|
||||
cur_key_part->length, tab->ref.items[i]);
|
||||
cur_ref_buff+= cur_key_part->store_length;
|
||||
}
|
||||
*ref_key= NULL; /* End marker. */
|
||||
tab->ref.key_err= 1;
|
||||
tab->ref.key_parts= tmp_key_parts;
|
||||
tab->table= tmp_table;
|
||||
tab->ref.tmp_table_index_lookup_init(thd, tmp_key, it, FALSE);
|
||||
|
||||
DBUG_RETURN(new subselect_uniquesubquery_engine(thd, tab, item,
|
||||
semi_join_conds));
|
||||
|
|
|
@ -88,11 +88,19 @@ public:
|
|||
*/
|
||||
List<Ref_to_outside> upper_refs;
|
||||
st_select_lex *parent_select;
|
||||
|
||||
/*
|
||||
|
||||
/**
|
||||
List of references on items subquery depends on (externally resolved);
|
||||
|
||||
@note We can't store direct links on Items because it could be
|
||||
substituted with other item (for example for grouping).
|
||||
*/
|
||||
List<Item*> depends_on;
|
||||
|
||||
/*
|
||||
TRUE<=>Table Elimination has made it redundant to evaluate this select
|
||||
(and so it is not part of QEP, etc)
|
||||
*/
|
||||
*/
|
||||
bool eliminated;
|
||||
|
||||
/* changed engine indicator */
|
||||
|
@ -185,6 +193,7 @@ public:
|
|||
*/
|
||||
st_select_lex* get_select_lex();
|
||||
const char *func_name() const { DBUG_ASSERT(0); return "subselect"; }
|
||||
virtual bool expr_cache_is_needed(THD *);
|
||||
|
||||
friend class select_result_interceptor;
|
||||
friend class Item_in_optimizer;
|
||||
|
@ -243,6 +252,8 @@ public:
|
|||
*/
|
||||
st_select_lex* invalidate_and_restore_select_lex();
|
||||
|
||||
Item* expr_cache_insert_transformer(uchar *thd_arg);
|
||||
|
||||
friend class select_singlerow_subselect;
|
||||
};
|
||||
|
||||
|
@ -290,6 +301,8 @@ public:
|
|||
void fix_length_and_dec();
|
||||
virtual void print(String *str, enum_query_type query_type);
|
||||
|
||||
Item* expr_cache_insert_transformer(uchar *thd_arg);
|
||||
|
||||
friend class select_exists_subselect;
|
||||
friend class subselect_uniquesubquery_engine;
|
||||
friend class subselect_indexsubquery_engine;
|
||||
|
@ -434,6 +447,7 @@ public:
|
|||
/* Inform 'this' that it was computed, and contains a valid result. */
|
||||
void set_first_execution() { if (first_execution) first_execution= FALSE; }
|
||||
bool is_expensive_processor(uchar *arg);
|
||||
bool expr_cache_is_needed(THD *thd);
|
||||
|
||||
/*
|
||||
Return the identifier that we could use to identify the subquery for the
|
||||
|
@ -813,7 +827,7 @@ public:
|
|||
{
|
||||
return materialize_engine->cols();
|
||||
}
|
||||
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
|
||||
uint8 uncacheable() { return materialize_engine->uncacheable(); }
|
||||
table_map upper_select_const_tables() { return 0; }
|
||||
bool no_rows() { return !tmp_table->file->stats.records; }
|
||||
virtual enum_engine_type engine_type() { return HASH_SJ_ENGINE; }
|
||||
|
|
|
@ -319,6 +319,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
|
|||
if (aggr_level >= 0)
|
||||
{
|
||||
ref_by= ref;
|
||||
thd->lex->current_select->register_dependency_item(aggr_sel, ref);
|
||||
/* Add the object to the list of registered objects assigned to aggr_sel */
|
||||
if (!aggr_sel->inner_sum_func_list)
|
||||
next= this;
|
||||
|
|
|
@ -570,12 +570,13 @@ protected:
|
|||
#define OPTIMIZER_SWITCH_SEMIJOIN 256
|
||||
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE 512
|
||||
#define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN 1024
|
||||
#define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1<<11)
|
||||
|
||||
#ifdef DBUG_OFF
|
||||
# define OPTIMIZER_SWITCH_LAST 2048
|
||||
# define OPTIMIZER_SWITCH_LAST (1<<12)
|
||||
#else
|
||||
# define OPTIMIZER_SWITCH_TABLE_ELIMINATION 2048
|
||||
# define OPTIMIZER_SWITCH_LAST 4096
|
||||
# define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1<<12)
|
||||
# define OPTIMIZER_SWITCH_LAST (1<<13)
|
||||
#endif
|
||||
|
||||
#ifdef DBUG_OFF
|
||||
|
@ -590,7 +591,8 @@ protected:
|
|||
OPTIMIZER_SWITCH_MATERIALIZATION | \
|
||||
OPTIMIZER_SWITCH_SEMIJOIN | \
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\
|
||||
OPTIMIZER_SWITCH_SUBQUERY_CACHE)
|
||||
#else
|
||||
# define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
|
||||
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
|
||||
|
@ -603,7 +605,8 @@ protected:
|
|||
OPTIMIZER_SWITCH_MATERIALIZATION | \
|
||||
OPTIMIZER_SWITCH_SEMIJOIN | \
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)
|
||||
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\
|
||||
OPTIMIZER_SWITCH_SUBQUERY_CACHE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -683,7 +686,8 @@ enum enum_parsing_place
|
|||
SELECT_LIST,
|
||||
IN_WHERE,
|
||||
IN_ON,
|
||||
IN_GROUP_BY
|
||||
IN_GROUP_BY,
|
||||
PARSING_PLACE_SIZE /* always should be the last */
|
||||
};
|
||||
|
||||
struct st_table;
|
||||
|
@ -925,6 +929,7 @@ bool general_log_write(THD *thd, enum enum_server_command command,
|
|||
#ifdef MYSQL_SERVER
|
||||
#include "sql_servers.h"
|
||||
#include "opt_range.h"
|
||||
#include "sql_expression_cache.h"
|
||||
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
struct Query_cache_query_flags
|
||||
|
@ -1258,6 +1263,9 @@ bool mysql_select(THD *thd, Item ***rref_pointer_array,
|
|||
Item *having, ORDER *proc_param, ulonglong select_type,
|
||||
select_result *result, SELECT_LEX_UNIT *unit,
|
||||
SELECT_LEX *select_lex);
|
||||
|
||||
int join_read_key2(THD *thd, struct st_join_table *tab, TABLE *table,
|
||||
struct st_table_ref *table_ref);
|
||||
void free_underlaid_joins(THD *thd, SELECT_LEX *select);
|
||||
bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
|
||||
select_result *result);
|
||||
|
@ -1277,6 +1285,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
|||
bool table_cant_handle_bit_fields,
|
||||
bool make_copy_field,
|
||||
uint convert_blob_length);
|
||||
bool open_tmp_table(TABLE *table);
|
||||
void sp_prepare_create_field(THD *thd, Create_field *sql_field);
|
||||
int prepare_create_field(Create_field *sql_field,
|
||||
uint *blob_columns,
|
||||
|
@ -1832,7 +1841,7 @@ bool close_cached_connection_tables(THD *thd, bool wait_for_refresh,
|
|||
bool have_lock = FALSE);
|
||||
void copy_field_from_tmp_record(Field *field,int offset);
|
||||
bool fill_record(THD *thd, Field **field, List<Item> &values,
|
||||
bool ignore_errors);
|
||||
bool ignore_errors, bool use_value);
|
||||
bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
|
||||
List<Item> &values,
|
||||
bool ignore_errors,
|
||||
|
|
|
@ -307,6 +307,7 @@ static const char *optimizer_switch_names[]=
|
|||
"firstmatch","loosescan","materialization", "semijoin",
|
||||
"partial_match_rowid_merge",
|
||||
"partial_match_table_scan",
|
||||
"subquery_cache",
|
||||
#ifndef DBUG_OFF
|
||||
"table_elimination",
|
||||
#endif
|
||||
|
@ -327,6 +328,7 @@ static const unsigned int optimizer_switch_names_len[]=
|
|||
sizeof("semijoin") - 1,
|
||||
sizeof("partial_match_rowid_merge") - 1,
|
||||
sizeof("partial_match_table_scan") - 1,
|
||||
sizeof("subquery_cache") - 1,
|
||||
#ifndef DBUG_OFF
|
||||
sizeof("table_elimination") - 1,
|
||||
#endif
|
||||
|
@ -406,8 +408,9 @@ static const char *sql_mode_str= "OFF";
|
|||
static const char *optimizer_switch_str="index_merge=on,index_merge_union=on,"
|
||||
"index_merge_sort_union=on,"
|
||||
"index_merge_intersection=on,"
|
||||
"index_condition_pushdown=on"
|
||||
#ifndef DBUG_OFF
|
||||
"index_condition_pushdown=on,"
|
||||
"subquery_cache=on"
|
||||
#ifndef DBUG_OFF
|
||||
",table_elimination=on";
|
||||
#else
|
||||
;
|
||||
|
@ -5890,7 +5893,9 @@ enum options_mysqld
|
|||
OPT_RECORD_RND_BUFFER, OPT_DIV_PRECINCREMENT, OPT_RELAY_LOG_SPACE_LIMIT,
|
||||
OPT_RELAY_LOG_PURGE,
|
||||
OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
|
||||
OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_ROWID_MERGE_BUFF_SIZE,
|
||||
OPT_SLAVE_TRANS_RETRIES,
|
||||
OPT_SUBQUERY_CACHE,
|
||||
OPT_READONLY, OPT_ROWID_MERGE_BUFF_SIZE,
|
||||
OPT_DEBUGGING, OPT_DEBUG_FLUSH,
|
||||
OPT_SORT_BUFFER, OPT_TABLE_OPEN_CACHE, OPT_TABLE_DEF_CACHE,
|
||||
OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
|
||||
|
@ -7222,7 +7227,7 @@ The minimum value for this variable is 4096.",
|
|||
{"optimizer_switch", OPT_OPTIMIZER_SWITCH,
|
||||
"optimizer_switch=option=val[,option=val...], where option={index_merge, "
|
||||
"index_merge_union, index_merge_sort_union, index_merge_intersection, "
|
||||
"index_condition_pushdown"
|
||||
"index_condition_pushdown, subquery_cache"
|
||||
#ifndef DBUG_OFF
|
||||
", table_elimination"
|
||||
#endif
|
||||
|
@ -7936,6 +7941,12 @@ SHOW_VAR status_vars[]= {
|
|||
{"Ssl_version", (char*) &show_ssl_get_version, SHOW_FUNC},
|
||||
#endif /* HAVE_OPENSSL */
|
||||
{"Syncs", (char*) &my_sync_count, SHOW_LONG_NOFLUSH},
|
||||
/*
|
||||
Expression cache used only for caching subqueries now, so its statistic
|
||||
variables we call subquery_cache*.
|
||||
*/
|
||||
{"Subquery_cache_hit", (char*) &subquery_cache_hit, SHOW_LONG},
|
||||
{"Subquery_cache_miss", (char*) &subquery_cache_miss, SHOW_LONG},
|
||||
{"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG},
|
||||
{"Table_locks_waited", (char*) &locks_waited, SHOW_LONG},
|
||||
#ifdef HAVE_MMAP
|
||||
|
@ -8075,6 +8086,7 @@ static int mysql_init_variables(void)
|
|||
abort_loop= select_thread_in_use= signal_thread_in_use= 0;
|
||||
ready_to_exit= shutdown_in_progress= grant_option= 0;
|
||||
aborted_threads= aborted_connects= 0;
|
||||
subquery_cache_miss= subquery_cache_hit= 0;
|
||||
delayed_insert_threads= delayed_insert_writes= delayed_rows_in_use= 0;
|
||||
delayed_insert_errors= thread_created= 0;
|
||||
specialflag= 0;
|
||||
|
|
|
@ -9569,7 +9569,9 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item,
|
|||
the MIN/MAX argument field, and disallow the optimization only if this is
|
||||
so.
|
||||
*/
|
||||
if (cond_type == Item::SUBSELECT_ITEM)
|
||||
if (cond_type == Item::SUBSELECT_ITEM ||
|
||||
(cond->get_cached_item() &&
|
||||
cond->get_cached_item()->type() == Item::SUBSELECT_ITEM))
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
/*
|
||||
|
|
|
@ -2297,7 +2297,8 @@ bool setup_sj_materialization(JOIN_TAB *tab)
|
|||
*/
|
||||
cur_ref_buff + null_count,
|
||||
null_count ? tab_ref->key_buff : 0,
|
||||
cur_key_part->length, tab_ref->items[i]);
|
||||
cur_key_part->length, tab_ref->items[i],
|
||||
FALSE);
|
||||
cur_ref_buff+= cur_key_part->store_length;
|
||||
}
|
||||
*ref_key= NULL; /* End marker. */
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifndef PROCEDURE_INCLUDED
|
||||
#define PROCEDURE_INCLUDED
|
||||
|
||||
/* When using sql procedures */
|
||||
|
||||
|
@ -153,3 +155,5 @@ public:
|
|||
|
||||
Procedure *setup_procedure(THD *thd,ORDER *proc_param,select_result *result,
|
||||
List<Item> &field_list,int *error);
|
||||
|
||||
#endif /* PROCEDURE_INCLUDED */
|
||||
|
|
|
@ -1375,10 +1375,10 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
|
|||
bool found_old_table= 0;
|
||||
TABLE *table= *table_ptr;
|
||||
DBUG_ENTER("close_thread_table");
|
||||
DBUG_ASSERT(table->key_read == 0);
|
||||
DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);
|
||||
DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
|
||||
table->s->table_name.str, (long) table));
|
||||
DBUG_ASSERT(table->key_read == 0);
|
||||
DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);
|
||||
|
||||
if (table->file)
|
||||
{
|
||||
|
@ -6328,12 +6328,21 @@ find_field_in_tables(THD *thd, Item_ident *item,
|
|||
sub query as dependent on the outer query
|
||||
*/
|
||||
if (current_sel != last_select)
|
||||
{
|
||||
mark_select_range_as_dependent(thd, last_select, current_sel,
|
||||
found, *ref, item);
|
||||
if (item->can_be_depended)
|
||||
{
|
||||
DBUG_ASSERT((*ref) == (Item*)item);
|
||||
current_sel->register_dependency_item(last_select, ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
}
|
||||
else
|
||||
item->can_be_depended= TRUE;
|
||||
|
||||
if (db && lower_case_table_names)
|
||||
{
|
||||
|
@ -8083,6 +8092,10 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
|||
if (*conds)
|
||||
{
|
||||
thd->where="where clause";
|
||||
DBUG_EXECUTE("where",
|
||||
print_where(*conds,
|
||||
"WHERE in setup_conds",
|
||||
QT_ORDINARY););
|
||||
if ((!(*conds)->fixed && (*conds)->fix_fields(thd, conds)) ||
|
||||
(*conds)->check_cols(1))
|
||||
goto err_no_arena;
|
||||
|
@ -8341,6 +8354,7 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
|
|||
ptr pointer on pointer to record
|
||||
values list of fields
|
||||
ignore_errors TRUE if we should ignore errors
|
||||
use_value forces usage of value of the items instead of result
|
||||
|
||||
NOTE
|
||||
fill_record() may set table->auto_increment_field_not_null and a
|
||||
|
@ -8353,7 +8367,8 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
|
|||
*/
|
||||
|
||||
bool
|
||||
fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
|
||||
fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors,
|
||||
bool use_value)
|
||||
{
|
||||
List_iterator_fast<Item> v(values);
|
||||
List<TABLE> tbl_list;
|
||||
|
@ -8395,8 +8410,11 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
|
|||
field->field_name, table->s->table_name.str);
|
||||
thd->abort_on_warning= abort_on_warning_saved;
|
||||
}
|
||||
if (value->save_in_field(field, 0) < 0)
|
||||
goto err;
|
||||
if (use_value)
|
||||
value->save_val(field);
|
||||
else
|
||||
if (value->save_in_field(field, 0) < 0)
|
||||
goto err;
|
||||
tbl_list.push_back(table);
|
||||
}
|
||||
/* Update virtual fields*/
|
||||
|
@ -8465,7 +8483,7 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
|
|||
enum trg_event_type event)
|
||||
{
|
||||
bool result;
|
||||
result= (fill_record(thd, ptr, values, ignore_errors) ||
|
||||
result= (fill_record(thd, ptr, values, ignore_errors, FALSE) ||
|
||||
(triggers && triggers->process_triggers(thd, event,
|
||||
TRG_ACTION_BEFORE, TRUE)));
|
||||
/*
|
||||
|
|
|
@ -3052,6 +3052,7 @@ void TMP_TABLE_PARAM::init()
|
|||
table_charset= 0;
|
||||
precomputed_group_by= 0;
|
||||
bit_fields_as_long= 0;
|
||||
skip_create_table= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,76 @@
|
|||
#include "log.h"
|
||||
#include "rpl_tblmap.h"
|
||||
|
||||
|
||||
/**
|
||||
Interface for Item iterator
|
||||
*/
|
||||
|
||||
class Item_iterator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Shall set this iterator to the position before the first item
|
||||
|
||||
@note
|
||||
This method also may perform some other initialization actions like
|
||||
allocation of certain resources.
|
||||
*/
|
||||
virtual void open()= 0;
|
||||
/**
|
||||
Shall return the next Item (or NULL if there is no next item) and
|
||||
move pointer to position after it.
|
||||
*/
|
||||
virtual Item *next()= 0;
|
||||
/**
|
||||
Shall force iterator to free resources (if it holds them)
|
||||
|
||||
@note
|
||||
One should not use the iterator without open() call after close()
|
||||
*/
|
||||
virtual void close()= 0;
|
||||
|
||||
virtual ~Item_iterator() {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Item iterator over List_iterator_fast for Item references
|
||||
*/
|
||||
|
||||
class Item_iterator_ref_list: public Item_iterator
|
||||
{
|
||||
List_iterator_fast<Item*> list;
|
||||
public:
|
||||
Item_iterator_ref_list(List_iterator_fast<Item*> &arg_list):
|
||||
list(arg_list) {}
|
||||
void open() { list.rewind(); }
|
||||
Item *next() { return *(list++); }
|
||||
void close() {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Item iterator over Item interface for rows
|
||||
*/
|
||||
|
||||
class Item_iterator_row: public Item_iterator
|
||||
{
|
||||
Item *base_item;
|
||||
uint current;
|
||||
public:
|
||||
Item_iterator_row(Item *base) : base_item(base), current(0) {}
|
||||
void open() { current= 0; }
|
||||
Item *next()
|
||||
{
|
||||
if (current >= base_item->cols())
|
||||
return NULL;
|
||||
return base_item->element_index(current++);
|
||||
}
|
||||
void close() {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
An interface that is used to take an action when
|
||||
the locking module notices that a table version has changed
|
||||
|
@ -2796,12 +2866,17 @@ public:
|
|||
that MEMORY tables cannot index BIT columns.
|
||||
*/
|
||||
bool bit_fields_as_long;
|
||||
/*
|
||||
Whether to create or postpone actual creation of this temporary table.
|
||||
TRUE <=> create_tmp_table will create only the TABLE structure.
|
||||
*/
|
||||
bool skip_create_table;
|
||||
|
||||
TMP_TABLE_PARAM()
|
||||
:copy_field(0), group_parts(0),
|
||||
group_length(0), group_null_parts(0), convert_blob_length(0),
|
||||
schema_table(0), precomputed_group_by(0), force_copy_fields(0),
|
||||
bit_fields_as_long(0)
|
||||
bit_fields_as_long(0), skip_create_table(0)
|
||||
{}
|
||||
~TMP_TABLE_PARAM()
|
||||
{
|
||||
|
|
314
sql/sql_expression_cache.cc
Normal file
314
sql/sql_expression_cache.cc
Normal file
|
@ -0,0 +1,314 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
/*
|
||||
Expression cache is used only for caching subqueries now, so its statistic
|
||||
variables we call subquery_cache*.
|
||||
*/
|
||||
ulonglong subquery_cache_miss, subquery_cache_hit;
|
||||
|
||||
Expression_cache_tmptable::Expression_cache_tmptable(THD *thd,
|
||||
List<Item*> &dependants,
|
||||
Item *value)
|
||||
:cache_table(NULL), table_thd(thd), list(&dependants), val(value),
|
||||
equalities(NULL), inited (0)
|
||||
{
|
||||
DBUG_ENTER("Expression_cache_tmptable::Expression_cache_tmptable");
|
||||
DBUG_VOID_RETURN;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Build and of equalities for the expression's parameters of certain types
|
||||
|
||||
@details
|
||||
If the temporary table used as an expression cache contains fields of
|
||||
certain types then it's not enough to perform a lookup into the table to
|
||||
verify that there is no row in the table for a given set of parameters.
|
||||
Additionally for those fields we have to check equalities of the form
|
||||
fld=val, where val is the value of the parameter stored in the column
|
||||
fld.
|
||||
The function generates a conjunction of all such equality predicates
|
||||
and saves a pointer to it in the field 'equalities'.
|
||||
|
||||
@retval FALSE OK
|
||||
@retval TRUE Error
|
||||
*/
|
||||
|
||||
bool Expression_cache_tmptable::make_equalities()
|
||||
{
|
||||
List<Item> args;
|
||||
List_iterator_fast<Item*> li(*list);
|
||||
Item **ref;
|
||||
Name_resolution_context *cn= NULL;
|
||||
DBUG_ENTER("Expression_cache_tmptable::make_equalities");
|
||||
|
||||
for (uint i= 1 /* skip result filed */; (ref= li++); i++)
|
||||
{
|
||||
Field *fld= cache_table->field[i];
|
||||
/* Only some field types should be checked after lookup */
|
||||
if (fld->type() == MYSQL_TYPE_VARCHAR ||
|
||||
fld->type() == MYSQL_TYPE_TINY_BLOB ||
|
||||
fld->type() == MYSQL_TYPE_MEDIUM_BLOB ||
|
||||
fld->type() == MYSQL_TYPE_LONG_BLOB ||
|
||||
fld->type() == MYSQL_TYPE_BLOB ||
|
||||
fld->type() == MYSQL_TYPE_VAR_STRING ||
|
||||
fld->type() == MYSQL_TYPE_STRING ||
|
||||
fld->type() == MYSQL_TYPE_NEWDECIMAL ||
|
||||
fld->type() == MYSQL_TYPE_DECIMAL)
|
||||
{
|
||||
if (!cn)
|
||||
{
|
||||
// dummy resolution context
|
||||
cn= new Name_resolution_context();
|
||||
cn->init();
|
||||
}
|
||||
args.push_front(new Item_func_eq(new Item_ref(cn, ref, "", "", FALSE),
|
||||
new Item_field(fld)));
|
||||
}
|
||||
}
|
||||
if (args.elements == 1)
|
||||
equalities= args.head();
|
||||
else
|
||||
equalities= new Item_cond_and(args);
|
||||
|
||||
DBUG_RETURN(equalities->fix_fields(table_thd, &equalities));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Field enumerator for TABLE::add_tmp_key
|
||||
|
||||
@param arg reference variable with current field number
|
||||
|
||||
@return field number
|
||||
*/
|
||||
|
||||
static uint field_enumerator(uchar *arg)
|
||||
{
|
||||
return ((uint*)arg)[0]++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize temporary table and auxiliary structures for the expression
|
||||
cache
|
||||
|
||||
@details
|
||||
The function creates a temporary table for the expression cache, defines
|
||||
the search index and initializes auxiliary search structures used to check
|
||||
whether a given set of of values of the expression parameters is in some
|
||||
cache entry.
|
||||
*/
|
||||
|
||||
void Expression_cache_tmptable::init()
|
||||
{
|
||||
List_iterator_fast<Item*> li(*list);
|
||||
Item_iterator_ref_list it(li);
|
||||
Item **item;
|
||||
uint field_counter;
|
||||
DBUG_ENTER("Expression_cache_tmptable::init");
|
||||
DBUG_ASSERT(!inited);
|
||||
inited= TRUE;
|
||||
|
||||
if (!(ULONGLONG_MAX >> (list->elements + 1)))
|
||||
{
|
||||
DBUG_PRINT("info", ("Too many dependencies"));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
cache_table= NULL;
|
||||
|
||||
cache_table_param.init();
|
||||
/* dependent items and result */
|
||||
cache_table_param.field_count= list->elements + 1;
|
||||
/* postpone table creation to index description */
|
||||
cache_table_param.skip_create_table= 1;
|
||||
cache_table= NULL;
|
||||
|
||||
while ((item= li++))
|
||||
{
|
||||
DBUG_ASSERT(item);
|
||||
DBUG_ASSERT(*item);
|
||||
DBUG_ASSERT((*item)->fixed);
|
||||
items.push_back((*item));
|
||||
}
|
||||
items.push_front(val);
|
||||
|
||||
if (!(cache_table= create_tmp_table(table_thd, &cache_table_param,
|
||||
items, (ORDER*) NULL,
|
||||
FALSE, FALSE,
|
||||
((table_thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS) &
|
||||
~(OPTION_BIG_TABLES |
|
||||
TMP_TABLE_FORCE_MYISAM)),
|
||||
HA_POS_ERROR,
|
||||
(char *)"subquery-cache-table")))
|
||||
{
|
||||
DBUG_PRINT("error", ("create_tmp_table failed, caching switched off"));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
if (cache_table->s->db_type() != heap_hton)
|
||||
{
|
||||
DBUG_PRINT("error", ("we need only heap table"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* This list do not contain result field */
|
||||
it.open();
|
||||
|
||||
field_counter=1;
|
||||
|
||||
if (cache_table->alloc_keys(1) ||
|
||||
(cache_table->add_tmp_key(0, items.elements - 1,
|
||||
&field_enumerator,
|
||||
(uchar*)&field_counter) < 0) ||
|
||||
ref.tmp_table_index_lookup_init(table_thd, cache_table->key_info, it,
|
||||
TRUE))
|
||||
{
|
||||
DBUG_PRINT("error", ("creating index failed"));
|
||||
goto error;
|
||||
}
|
||||
cache_table->s->keys= 1;
|
||||
cache_table->s->uniques= 1;
|
||||
ref.null_rejecting= 1;
|
||||
ref.disable_cache= FALSE;
|
||||
ref.has_record= 0;
|
||||
ref.use_count= 0;
|
||||
|
||||
|
||||
if (open_tmp_table(cache_table))
|
||||
{
|
||||
DBUG_PRINT("error", ("Opening (creating) temporary table failed"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(cached_result= new Item_field(cache_table->field[0])))
|
||||
{
|
||||
DBUG_PRINT("error", ("Creating Item_field failed"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (make_equalities())
|
||||
{
|
||||
DBUG_PRINT("error", ("Creating equalities failed"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
error:
|
||||
/* switch off cache */
|
||||
free_tmp_table(table_thd, cache_table);
|
||||
cache_table= NULL;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
Expression_cache_tmptable::~Expression_cache_tmptable()
|
||||
{
|
||||
if (cache_table)
|
||||
free_tmp_table(table_thd, cache_table);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check if a given set of parameters of the expression is in the cache
|
||||
|
||||
@param [out] value the expression value found in the cache if any
|
||||
|
||||
@details
|
||||
For a given set of the parameters of the expression the function
|
||||
checks whether it can be found in some entry of the cache. If so
|
||||
the function returns the result of the expression extracted from
|
||||
the cache.
|
||||
|
||||
@retval Expression_cache::HIT if the set of parameters is in the cache
|
||||
@retval Expression_cache::MISS - otherwise
|
||||
*/
|
||||
|
||||
Expression_cache::result Expression_cache_tmptable::check_value(Item **value)
|
||||
{
|
||||
int res;
|
||||
DBUG_ENTER("Expression_cache_tmptable::check_value");
|
||||
|
||||
/*
|
||||
We defer cache initialization to get item references that are
|
||||
used at the execution phase.
|
||||
*/
|
||||
if (!inited)
|
||||
init();
|
||||
|
||||
if (cache_table)
|
||||
{
|
||||
DBUG_PRINT("info", ("status: %u has_record %u",
|
||||
(uint)cache_table->status, (uint)ref.has_record));
|
||||
if ((res= join_read_key2(table_thd, NULL, cache_table, &ref)) == 1)
|
||||
DBUG_RETURN(ERROR);
|
||||
if (res || (equalities && !equalities->val_int()))
|
||||
{
|
||||
subquery_cache_miss++;
|
||||
DBUG_RETURN(MISS);
|
||||
}
|
||||
|
||||
subquery_cache_hit++;
|
||||
*value= cached_result;
|
||||
DBUG_RETURN(Expression_cache::HIT);
|
||||
}
|
||||
DBUG_RETURN(Expression_cache::MISS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Put a new entry into the expression cache
|
||||
|
||||
@param value the result of the expression to be put into the cache
|
||||
|
||||
@details
|
||||
The function evaluates 'value' and puts the result into the cache as the
|
||||
result of the expression for the current set of parameters.
|
||||
|
||||
@retval FALSE OK
|
||||
@retval TRUE Error
|
||||
*/
|
||||
|
||||
my_bool Expression_cache_tmptable::put_value(Item *value)
|
||||
{
|
||||
int error;
|
||||
DBUG_ENTER("Expression_cache_tmptable::put_value");
|
||||
DBUG_ASSERT(inited);
|
||||
|
||||
if (!cache_table)
|
||||
{
|
||||
DBUG_PRINT("info", ("No table so behave as we successfully put value"));
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
*(items.head_ref())= value;
|
||||
fill_record(table_thd, cache_table->field, items, TRUE, TRUE);
|
||||
if (table_thd->is_error())
|
||||
goto err;;
|
||||
|
||||
if ((error= cache_table->file->ha_write_row(cache_table->record[0])))
|
||||
{
|
||||
/* create_myisam_from_heap will generate error if needed */
|
||||
if (cache_table->file->is_fatal_error(error, HA_CHECK_DUP) &&
|
||||
create_internal_tmp_table_from_heap(table_thd, cache_table,
|
||||
cache_table_param.start_recinfo,
|
||||
&cache_table_param.recinfo,
|
||||
error, 1))
|
||||
goto err;
|
||||
}
|
||||
cache_table->status= 0; /* cache_table->record contains an existed record */
|
||||
ref.has_record= TRUE; /* the same as above */
|
||||
DBUG_PRINT("info", ("has_record: TRUE status: 0"));
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
err:
|
||||
free_tmp_table(table_thd, cache_table);
|
||||
cache_table= NULL;
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
80
sql/sql_expression_cache.h
Normal file
80
sql/sql_expression_cache.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
#ifndef SQL_EXPRESSION_CACHE_INCLUDED
|
||||
#define SQL_EXPRESSION_CACHE_INCLUDED
|
||||
|
||||
#include "sql_select.h"
|
||||
|
||||
/**
|
||||
Interface for expression cache
|
||||
|
||||
@note
|
||||
Parameters of an expression cache interface are set on the creation of the
|
||||
cache. They are passed when a cache object of the implementation class is
|
||||
constructed. That's why they are not visible in this interface.
|
||||
*/
|
||||
|
||||
extern ulonglong subquery_cache_miss, subquery_cache_hit;
|
||||
|
||||
class Expression_cache :public Sql_alloc
|
||||
{
|
||||
public:
|
||||
enum result {ERROR, HIT, MISS};
|
||||
|
||||
Expression_cache(){};
|
||||
virtual ~Expression_cache() {};
|
||||
/**
|
||||
Shall check the presence of expression value in the cache for a given
|
||||
set of values of the expression parameters. Return the result of the
|
||||
expression if it's found in the cache.
|
||||
*/
|
||||
virtual result check_value(Item **value)= 0;
|
||||
/**
|
||||
Shall put the value of an expression for given set of its parameters
|
||||
into the expression cache
|
||||
*/
|
||||
virtual my_bool put_value(Item *value)= 0;
|
||||
};
|
||||
|
||||
struct st_table_ref;
|
||||
struct st_join_table;
|
||||
class Item_field;
|
||||
|
||||
|
||||
/**
|
||||
Implementation of expression cache over a temporary table
|
||||
*/
|
||||
|
||||
class Expression_cache_tmptable :public Expression_cache
|
||||
{
|
||||
public:
|
||||
Expression_cache_tmptable(THD *thd, List<Item*> &dependants, Item *value);
|
||||
virtual ~Expression_cache_tmptable();
|
||||
virtual result check_value(Item **value);
|
||||
virtual my_bool put_value(Item *value);
|
||||
|
||||
private:
|
||||
void init();
|
||||
bool make_equalities();
|
||||
|
||||
/* tmp table parameters */
|
||||
TMP_TABLE_PARAM cache_table_param;
|
||||
/* temporary table to store this cache */
|
||||
TABLE *cache_table;
|
||||
/* Thread handle for the temporary table */
|
||||
THD *table_thd;
|
||||
/* TABLE_REF for index lookup */
|
||||
struct st_table_ref ref;
|
||||
/* Cached result */
|
||||
Item_field *cached_result;
|
||||
/* List of references to the parameters of the expression */
|
||||
List<Item*> *list;
|
||||
/* List of items */
|
||||
List<Item> items;
|
||||
/* Value Item example */
|
||||
Item *val;
|
||||
/* Expression to check after index lookup */
|
||||
Item *equalities;
|
||||
/* Set on if the object has been succesfully initialized with init() */
|
||||
bool inited;
|
||||
};
|
||||
|
||||
#endif /* SQL_EXPRESSION_CACHE_INCLUDED */
|
|
@ -1632,6 +1632,8 @@ void st_select_lex::init_query()
|
|||
nest_level= 0;
|
||||
link_next= 0;
|
||||
lock_option= TL_READ_DEFAULT;
|
||||
|
||||
bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used));
|
||||
}
|
||||
|
||||
void st_select_lex::init_select()
|
||||
|
@ -1829,6 +1831,55 @@ void st_select_lex_unit::exclude_tree()
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Register reference to an item which the subqueries depends on
|
||||
|
||||
@param def_sel select against which the item is resolved
|
||||
@param dependency reference to the item
|
||||
|
||||
@details
|
||||
This function puts the reference dependency to an item that is either an
|
||||
outer field or an aggregate function resolved against an outer select into
|
||||
the list 'depends_on'. It adds it to the 'depends_on' lists for each
|
||||
subquery between this one and 'def_sel' - the subquery against which the
|
||||
item is resolved.
|
||||
*/
|
||||
|
||||
void st_select_lex::register_dependency_item(st_select_lex *def_sel,
|
||||
Item **dependency)
|
||||
{
|
||||
SELECT_LEX *s= this;
|
||||
DBUG_ENTER("st_select_lex::register_dependency_item");
|
||||
DBUG_ASSERT(this != def_sel);
|
||||
DBUG_ASSERT(*dependency);
|
||||
do
|
||||
{
|
||||
/* check duplicates */
|
||||
List_iterator_fast<Item*> li(s->master_unit()->item->depends_on);
|
||||
Item **dep;
|
||||
while ((dep= li++))
|
||||
{
|
||||
if ((*dep)->eq(*dependency, FALSE))
|
||||
{
|
||||
DBUG_PRINT("info", ("dependency %s already present",
|
||||
((*dependency)->name ?
|
||||
(*dependency)->name :
|
||||
"<no name>")));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
s->master_unit()->item->depends_on.push_back(dependency);
|
||||
DBUG_PRINT("info", ("depends_on: Select: %d added: %s",
|
||||
s->select_number,
|
||||
((*dependency)->name ?
|
||||
(*dependency)->name :
|
||||
"<no name>")));
|
||||
} while ((s= s->outer_select()) != def_sel);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
st_select_lex_node::mark_as_dependent mark all st_select_lex struct from
|
||||
this to 'last' as dependent
|
||||
|
|
|
@ -660,6 +660,11 @@ public:
|
|||
|
||||
/* explicit LIMIT clause was used */
|
||||
bool explicit_limit;
|
||||
/*
|
||||
This array is used to note whether we have any candidates for
|
||||
expression caching in the corresponding clauses
|
||||
*/
|
||||
bool expr_cache_may_be_used[PARSING_PLACE_SIZE];
|
||||
/*
|
||||
there are subquery in HAVING clause => we can't close tables before
|
||||
query processing end even if we use temporary table
|
||||
|
@ -749,6 +754,7 @@ public:
|
|||
inline bool is_subquery_function() { return master_unit()->item != 0; }
|
||||
|
||||
bool mark_as_dependent(THD *thd, st_select_lex *last, Item *dependency);
|
||||
void register_dependency_item(st_select_lex *last, Item **dependency);
|
||||
|
||||
bool set_braces(bool value);
|
||||
bool inc_in_sum_expr();
|
||||
|
|
|
@ -152,7 +152,6 @@ static int join_read_const_table(JOIN_TAB *tab, POSITION *pos);
|
|||
static int join_read_system(JOIN_TAB *tab);
|
||||
static int join_read_const(JOIN_TAB *tab);
|
||||
static int join_read_key(JOIN_TAB *tab);
|
||||
static int join_read_key2(JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref);
|
||||
static void join_read_key_unlock_row(st_join_table *tab);
|
||||
static int join_read_always_key(JOIN_TAB *tab);
|
||||
static int join_read_last_key(JOIN_TAB *tab);
|
||||
|
@ -1293,6 +1292,9 @@ JOIN::optimize()
|
|||
int res;
|
||||
if ((res= rewrite_to_index_subquery_engine(this)) != -1)
|
||||
DBUG_RETURN(res);
|
||||
if (setup_subquery_caches())
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/*
|
||||
Need to tell handlers that to play it safe, it should fetch all
|
||||
columns of the primary key of the tables: this is because MySQL may
|
||||
|
@ -1514,6 +1516,152 @@ setup_subq_exit:
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Transform given item with changing it in all_fields if it is needed.
|
||||
|
||||
@param expr Reference on expression to transform
|
||||
@param transformer Transformer to apply to the expression
|
||||
|
||||
@details
|
||||
The function transforms the expression expr and, if the top item of the
|
||||
expression has changed, the function looks for the item in
|
||||
JOIN::all_fields and replaces it with the result of transformation.
|
||||
*/
|
||||
|
||||
void JOIN::transform_and_change_in_all_fields(Item** expr,
|
||||
Item_transformer transformer)
|
||||
{
|
||||
DBUG_ENTER("JOIN::transform_and_change_in_all_fields");
|
||||
Item *new_item= (*expr)->transform(transformer,
|
||||
(uchar*) thd);
|
||||
if (new_item != (*expr))
|
||||
{
|
||||
List_iterator<Item> li(all_fields);
|
||||
Item *it;
|
||||
|
||||
/*
|
||||
Check if this item already has expression cache and if it has then use
|
||||
that cache instead of the cache we have just created
|
||||
*/
|
||||
while ((it= li++))
|
||||
{
|
||||
if (((*expr) == it->get_cached_item()))
|
||||
{
|
||||
/*
|
||||
We have to forget about the created cache, but this situation is
|
||||
really rare.
|
||||
*/
|
||||
new_item->cleanup();
|
||||
new_item= it;
|
||||
DBUG_PRINT("info", ("Other cache found"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
li.rewind();
|
||||
while ((it= li++))
|
||||
{
|
||||
if (it == (*expr))
|
||||
{
|
||||
li.replace(new_item);
|
||||
DBUG_PRINT("info", ("Cache Added"));
|
||||
}
|
||||
}
|
||||
*expr= new_item;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Setup expression caches for subqueries that need them
|
||||
|
||||
@details
|
||||
The function wraps correlated subquery expressions that return one value
|
||||
into objects of the class Item_cache_wrapper setting up an expression
|
||||
cache for each of them. The result values of the subqueries are to be
|
||||
cached together with the corresponding sets of the parameters - outer
|
||||
references of the subqueries.
|
||||
|
||||
@retval FALSE OK
|
||||
@retval TRUE Error
|
||||
*/
|
||||
|
||||
bool JOIN::setup_subquery_caches()
|
||||
{
|
||||
DBUG_ENTER("JOIN::setup_subquery_caches");
|
||||
|
||||
/*
|
||||
We have to check all this condition together because items created in
|
||||
one of this clauses can be moved to another one by optimizer
|
||||
*/
|
||||
if (select_lex->expr_cache_may_be_used[IN_WHERE] ||
|
||||
select_lex->expr_cache_may_be_used[IN_HAVING] ||
|
||||
select_lex->expr_cache_may_be_used[IN_ON] ||
|
||||
select_lex->expr_cache_may_be_used[NO_MATTER])
|
||||
{
|
||||
if (conds)
|
||||
conds= conds->transform(&Item::expr_cache_insert_transformer,
|
||||
(uchar*) thd);
|
||||
for (JOIN_TAB *tab= join_tab + const_tables;
|
||||
tab < join_tab + tables ;
|
||||
tab++)
|
||||
{
|
||||
if (tab->select_cond)
|
||||
tab->select_cond=
|
||||
tab->select_cond->transform(&Item::expr_cache_insert_transformer,
|
||||
(uchar*) thd);
|
||||
if (tab->cache_select && tab->cache_select->cond)
|
||||
tab->cache_select->cond=
|
||||
tab->cache_select->
|
||||
cond->transform(&Item::expr_cache_insert_transformer,
|
||||
(uchar*) thd);
|
||||
|
||||
}
|
||||
|
||||
if (having)
|
||||
having= having->transform(&Item::expr_cache_insert_transformer,
|
||||
(uchar*) thd);
|
||||
if (tmp_having)
|
||||
{
|
||||
DBUG_ASSERT(having == NULL);
|
||||
tmp_having= tmp_having->transform(&Item::expr_cache_insert_transformer,
|
||||
(uchar*) thd);
|
||||
}
|
||||
}
|
||||
if (select_lex->expr_cache_may_be_used[SELECT_LIST] ||
|
||||
select_lex->expr_cache_may_be_used[IN_GROUP_BY] ||
|
||||
select_lex->expr_cache_may_be_used[NO_MATTER])
|
||||
{
|
||||
List_iterator<Item> li(fields_list);
|
||||
Item *item;
|
||||
while ((item= li++))
|
||||
{
|
||||
Item *new_item=
|
||||
item->transform(&Item::expr_cache_insert_transformer, (uchar*) thd);
|
||||
if (new_item != item)
|
||||
{
|
||||
thd->change_item_tree(li.ref(), new_item);
|
||||
}
|
||||
}
|
||||
for (ORDER *group= group_list; group ; group= group->next)
|
||||
{
|
||||
transform_and_change_in_all_fields(group->item,
|
||||
&Item::expr_cache_insert_transformer);
|
||||
}
|
||||
}
|
||||
if (select_lex->expr_cache_may_be_used[NO_MATTER])
|
||||
{
|
||||
for (ORDER *ord= order; ord; ord= ord->next)
|
||||
{
|
||||
transform_and_change_in_all_fields(ord->item,
|
||||
&Item::expr_cache_insert_transformer);
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Restore values in temporary join.
|
||||
*/
|
||||
|
@ -5244,7 +5392,7 @@ greedy_search(JOIN *join,
|
|||
'join->best_positions' contains a complete optimal extension of the
|
||||
current partial QEP.
|
||||
*/
|
||||
DBUG_EXECUTE("opt", print_plan(join, join->tables,
|
||||
DBUG_EXECUTE("opt", print_plan(join, n_tables,
|
||||
record_count, read_time, read_time,
|
||||
"optimal"););
|
||||
DBUG_RETURN(FALSE);
|
||||
|
@ -6035,7 +6183,8 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|||
store_key_item tmp(thd, keyinfo->key_part[i].field,
|
||||
key_buff + maybe_null,
|
||||
maybe_null ? key_buff : 0,
|
||||
keyinfo->key_part[i].length, keyuse->val);
|
||||
keyinfo->key_part[i].length, keyuse->val,
|
||||
FALSE);
|
||||
if (thd->is_fatal_error)
|
||||
DBUG_RETURN(TRUE);
|
||||
tmp.copy();
|
||||
|
@ -6117,7 +6266,7 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
|
|||
key_buff + maybe_null,
|
||||
maybe_null ? key_buff : 0,
|
||||
key_part->length,
|
||||
keyuse->val);
|
||||
keyuse->val, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7156,7 +7305,7 @@ end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||
if (item->is_null())
|
||||
DBUG_RETURN(NESTED_LOOP_OK);
|
||||
}
|
||||
fill_record(thd, table->field, sjm->sjm_table_cols, 1);
|
||||
fill_record(thd, table->field, sjm->sjm_table_cols, TRUE, FALSE);
|
||||
if (thd->is_error())
|
||||
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
|
||||
if ((error= table->file->ha_write_row(table->record[0])))
|
||||
|
@ -7721,6 +7870,72 @@ void JOIN_TAB::cleanup()
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Build a TABLE_REF structure for index lookup in the temporary table
|
||||
|
||||
@param thd Thread handle
|
||||
@param tmp_key The temporary table key
|
||||
@param it The iterator of items for lookup in the key
|
||||
|
||||
@details
|
||||
Build TABLE_REF object for lookup in the key 'tmp_key' using items
|
||||
accessible via item iterator 'it'.
|
||||
|
||||
@retval TRUE Error
|
||||
@retval FALSE OK
|
||||
*/
|
||||
|
||||
bool TABLE_REF::tmp_table_index_lookup_init(THD *thd,
|
||||
KEY *tmp_key,
|
||||
Item_iterator &it,
|
||||
bool value)
|
||||
{
|
||||
uint tmp_key_parts= tmp_key->key_parts;
|
||||
DBUG_ENTER("TABLE_REF::tmp_table_index_lookup_init");
|
||||
|
||||
key= 0; /* The only temp table index. */
|
||||
key_length= tmp_key->key_length;
|
||||
if (!(key_buff=
|
||||
(uchar*) thd->calloc(ALIGN_SIZE(tmp_key->key_length) * 2)) ||
|
||||
!(key_copy=
|
||||
(store_key**) thd->alloc((sizeof(store_key*) *
|
||||
(tmp_key_parts + 1)))) ||
|
||||
!(items=
|
||||
(Item**) thd->alloc(sizeof(Item*) * tmp_key_parts)))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
key_buff2= key_buff + ALIGN_SIZE(tmp_key->key_length);
|
||||
|
||||
KEY_PART_INFO *cur_key_part= tmp_key->key_part;
|
||||
store_key **ref_key= key_copy;
|
||||
uchar *cur_ref_buff= key_buff;
|
||||
|
||||
it.open();
|
||||
for (uint i= 0; i < tmp_key_parts; i++, cur_key_part++, ref_key++)
|
||||
{
|
||||
Item *item= it.next();
|
||||
DBUG_ASSERT(item);
|
||||
items[i]= item;
|
||||
int null_count= test(cur_key_part->field->real_maybe_null());
|
||||
*ref_key= new store_key_item(thd, cur_key_part->field,
|
||||
/* TIMOUR:
|
||||
the NULL byte is taken into account in
|
||||
cur_key_part->store_length, so instead of
|
||||
cur_ref_buff + test(maybe_null), we could
|
||||
use that information instead.
|
||||
*/
|
||||
cur_ref_buff + null_count,
|
||||
null_count ? key_buff : 0,
|
||||
cur_key_part->length, items[i], value);
|
||||
cur_ref_buff+= cur_key_part->store_length;
|
||||
}
|
||||
*ref_key= NULL; /* End marker. */
|
||||
key_err= 1;
|
||||
key_parts= tmp_key_parts;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Partially cleanup JOIN after it has executed: close index or rnd read
|
||||
(table cursors), free quick selects.
|
||||
|
@ -10829,6 +11044,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
|||
case Item::REF_ITEM:
|
||||
case Item::NULL_ITEM:
|
||||
case Item::VARBIN_ITEM:
|
||||
case Item::CACHE_ITEM:
|
||||
case Item::EXPR_CACHE_ITEM:
|
||||
if (make_copy_field)
|
||||
{
|
||||
DBUG_ASSERT(((Item_result_field*)item)->result_field);
|
||||
|
@ -11089,6 +11306,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
if (item->used_tables() & OUTER_REF_TABLE_BIT)
|
||||
item->update_used_tables();
|
||||
if (type == Item::SUBSELECT_ITEM ||
|
||||
(item->get_cached_item() &&
|
||||
item->get_cached_item()->type() == Item::SUBSELECT_ITEM ) ||
|
||||
(item->used_tables() & ~OUTER_REF_TABLE_BIT))
|
||||
{
|
||||
/*
|
||||
|
@ -11616,7 +11835,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
¶m->recinfo, select_options))
|
||||
goto err;
|
||||
}
|
||||
if (open_tmp_table(table))
|
||||
DBUG_PRINT("info", ("skip_create_table: %d", (int)param->skip_create_table));
|
||||
if (!param->skip_create_table && open_tmp_table(table))
|
||||
goto err;
|
||||
|
||||
thd->mem_root= mem_root_save;
|
||||
|
@ -12609,7 +12829,8 @@ sub_select_sjm(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
|
|||
else
|
||||
{
|
||||
/* Do index lookup in the materialized table */
|
||||
if ((res= join_read_key2(join_tab, sjm->table, sjm->tab_ref)) == 1)
|
||||
if ((res= join_read_key2(join_tab->join->thd, join_tab,
|
||||
sjm->table, sjm->tab_ref)) == 1)
|
||||
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
|
||||
if (res || !sjm->in_equality->val_int())
|
||||
DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
|
||||
|
@ -13409,25 +13630,24 @@ join_read_const(JOIN_TAB *tab)
|
|||
static int
|
||||
join_read_key(JOIN_TAB *tab)
|
||||
{
|
||||
return join_read_key2(tab, tab->table, &tab->ref);
|
||||
return join_read_key2(tab->join->thd, tab, tab->table, &tab->ref);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
eq_ref access handler but generalized a bit to support TABLE and TABLE_REF
|
||||
not from the join_tab. See join_read_key for detailed synopsis.
|
||||
*/
|
||||
static int
|
||||
join_read_key2(JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref)
|
||||
int join_read_key2(THD *thd, JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref)
|
||||
{
|
||||
int error;
|
||||
if (!table->file->inited)
|
||||
{
|
||||
table->file->ha_index_init(table_ref->key, tab->sorted);
|
||||
table->file->ha_index_init(table_ref->key, (tab ? tab->sorted : TRUE));
|
||||
}
|
||||
|
||||
/* TODO: Why don't we do "Late NULLs Filtering" here? */
|
||||
if (cmp_buffer_with_ref(tab->join->thd, table, table_ref) ||
|
||||
if (cmp_buffer_with_ref(thd, table, table_ref) ||
|
||||
(table->status & (STATUS_GARBAGE | STATUS_NO_PARENT | STATUS_NULL_ROW)))
|
||||
{
|
||||
if (table_ref->key_err)
|
||||
|
@ -13439,10 +13659,10 @@ join_read_key2(JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref)
|
|||
Moving away from the current record. Unlock the row
|
||||
in the handler if it did not match the partial WHERE.
|
||||
*/
|
||||
if (tab->ref.has_record && tab->ref.use_count == 0)
|
||||
if (tab && tab->ref.has_record && tab->ref.use_count == 0)
|
||||
{
|
||||
tab->read_record.file->unlock_row();
|
||||
tab->ref.has_record= FALSE;
|
||||
table_ref->has_record= FALSE;
|
||||
}
|
||||
error=table->file->ha_index_read_map(table->record[0],
|
||||
table_ref->key_buff,
|
||||
|
@ -13453,14 +13673,14 @@ join_read_key2(JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref)
|
|||
|
||||
if (! error)
|
||||
{
|
||||
tab->ref.has_record= TRUE;
|
||||
tab->ref.use_count= 1;
|
||||
table_ref->has_record= TRUE;
|
||||
table_ref->use_count= 1;
|
||||
}
|
||||
}
|
||||
else if (table->status == 0)
|
||||
{
|
||||
DBUG_ASSERT(tab->ref.has_record);
|
||||
tab->ref.use_count++;
|
||||
DBUG_ASSERT(table_ref->has_record);
|
||||
table_ref->use_count++;
|
||||
}
|
||||
table->null_row=0;
|
||||
return table->status ? -1 : 0;
|
||||
|
@ -16960,6 +17180,8 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
|
|||
}
|
||||
else if ((real_pos->type() == Item::FUNC_ITEM ||
|
||||
real_pos->type() == Item::SUBSELECT_ITEM ||
|
||||
(real_pos->get_cached_item() &&
|
||||
real_pos->get_cached_item()->type() == Item::SUBSELECT_ITEM) ||
|
||||
real_pos->type() == Item::CACHE_ITEM ||
|
||||
real_pos->type() == Item::COND_ITEM) &&
|
||||
!real_pos->with_sum_func)
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
#ifndef SQL_SELECT_INCLUDED
|
||||
#define SQL_SELECT_INCLUDED
|
||||
/**
|
||||
@file
|
||||
|
||||
|
@ -114,6 +116,9 @@ typedef struct st_table_ref
|
|||
|
||||
*/
|
||||
bool disable_cache;
|
||||
|
||||
bool tmp_table_index_lookup_init(THD *thd, KEY *tmp_key, Item_iterator &it,
|
||||
bool value);
|
||||
} TABLE_REF;
|
||||
|
||||
|
||||
|
@ -1729,6 +1734,7 @@ public:
|
|||
((group || tmp_table_param.sum_func_count) && !group_list)) ?
|
||||
NULL : join_tab+const_tables;
|
||||
}
|
||||
bool setup_subquery_caches();
|
||||
private:
|
||||
/**
|
||||
TRUE if the query contains an aggregate function but has no GROUP
|
||||
|
@ -1736,6 +1742,8 @@ private:
|
|||
*/
|
||||
bool implicit_grouping;
|
||||
bool make_simple_join(JOIN *join, TABLE *tmp_table);
|
||||
void transform_and_change_in_all_fields(Item** item,
|
||||
Item_transformer transformer);
|
||||
};
|
||||
|
||||
|
||||
|
@ -1867,12 +1875,17 @@ class store_key_item :public store_key
|
|||
{
|
||||
protected:
|
||||
Item *item;
|
||||
/*
|
||||
Flag that forces usage of save_val() method which save value of the
|
||||
item instead of save_in_field() method which saves result.
|
||||
*/
|
||||
bool use_value;
|
||||
public:
|
||||
store_key_item(THD *thd, Field *to_field_arg, uchar *ptr,
|
||||
uchar *null_ptr_arg, uint length, Item *item_arg)
|
||||
uchar *null_ptr_arg, uint length, Item *item_arg, bool val)
|
||||
:store_key(thd, to_field_arg, ptr,
|
||||
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
|
||||
&err : (uchar*) 0, length), item(item_arg)
|
||||
&err : (uchar*) 0, length), item(item_arg), use_value(val)
|
||||
{}
|
||||
const char *name() const { return "func"; }
|
||||
|
||||
|
@ -1882,7 +1895,11 @@ public:
|
|||
TABLE *table= to_field->table;
|
||||
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
|
||||
table->write_set);
|
||||
int res= item->save_in_field(to_field, 1);
|
||||
int res= FALSE;
|
||||
if (use_value)
|
||||
item->save_val(to_field);
|
||||
else
|
||||
res= item->save_in_field(to_field, 1);
|
||||
/*
|
||||
Item::save_in_field() may call Item::val_xxx(). And if this is a subquery
|
||||
we need to check for errors executing it and react accordingly
|
||||
|
@ -1906,7 +1923,7 @@ public:
|
|||
Item *item_arg)
|
||||
:store_key_item(thd, to_field_arg,ptr,
|
||||
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
|
||||
&err : (uchar*) 0, length, item_arg), inited(0)
|
||||
&err : (uchar*) 0, length, item_arg, FALSE), inited(0)
|
||||
{
|
||||
}
|
||||
const char *name() const { return "const"; }
|
||||
|
@ -1997,6 +2014,4 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
|
|||
bool open_tmp_table(TABLE *table);
|
||||
void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* SQL_SELECT_INCLUDED */
|
||||
|
|
|
@ -57,7 +57,7 @@ bool select_union::send_data(List<Item> &values)
|
|||
unit->offset_limit_cnt--;
|
||||
return 0;
|
||||
}
|
||||
fill_record(thd, table->field, values, 1);
|
||||
fill_record(thd, table->field, values, TRUE, FALSE);
|
||||
if (thd->is_error())
|
||||
return 1;
|
||||
|
||||
|
|
|
@ -1866,7 +1866,7 @@ bool multi_update::send_data(List<Item> ¬_used_values)
|
|||
/* Store regular updated fields in the row. */
|
||||
fill_record(thd,
|
||||
tmp_table->field + 1 + unupdated_check_opt_tables.elements,
|
||||
*values_for_table[offset], 1);
|
||||
*values_for_table[offset], TRUE, FALSE);
|
||||
|
||||
/* Write row, ignoring duplicated updates to a row */
|
||||
error= tmp_table->file->ha_write_row(tmp_table->record[0]);
|
||||
|
|
122
sql/table.cc
122
sql/table.cc
|
@ -21,6 +21,8 @@
|
|||
#include "create_options.h"
|
||||
#include <m_ctype.h>
|
||||
#include "my_md5.h"
|
||||
#include "my_bit.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
/* INFORMATION_SCHEMA name */
|
||||
LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")};
|
||||
|
@ -5130,6 +5132,126 @@ void st_table::mark_virtual_columns_for_write(void)
|
|||
file->column_bitmaps_signal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Allocate space for keys
|
||||
|
||||
@param key_count number of keys to allocate.
|
||||
|
||||
@details
|
||||
Allocates space enough to fit 'key_count' keys for this table.
|
||||
|
||||
@return FALSE space was successfully allocated.
|
||||
@return TRUE an error occur.
|
||||
*/
|
||||
|
||||
bool TABLE::alloc_keys(uint key_count)
|
||||
{
|
||||
DBUG_ASSERT(!s->keys);
|
||||
key_info= s->key_info= (KEY*) alloc_root(&mem_root, sizeof(KEY)*key_count);
|
||||
max_keys= key_count;
|
||||
return !(key_info);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Add a key to a temporary table
|
||||
|
||||
@param key the number of the key
|
||||
@param key_parts number of components of the key
|
||||
@param next_field_no the call-back function that returns the number of
|
||||
the field used as the next component of the key
|
||||
@param arg the argument for the above function
|
||||
|
||||
@details
|
||||
The function adds a new key to the table that is assumed to be
|
||||
temprary table. The call-back function must at each call must return
|
||||
the number of the field that used as next component of this key
|
||||
|
||||
@return FALSE is a success
|
||||
@return TRUE if a failure
|
||||
*/
|
||||
|
||||
bool TABLE::add_tmp_key(uint key, uint key_parts,
|
||||
uint (*next_field_no) (uchar *), uchar *arg)
|
||||
{
|
||||
DBUG_ASSERT(key < max_keys);
|
||||
|
||||
char buf[NAME_CHAR_LEN];
|
||||
KEY* keyinfo;
|
||||
Field **reg_field;
|
||||
uint i;
|
||||
bool key_start= TRUE;
|
||||
KEY_PART_INFO* key_part_info=
|
||||
(KEY_PART_INFO*) alloc_root(&mem_root, sizeof(KEY_PART_INFO)*key_parts);
|
||||
if (!key_part_info)
|
||||
return TRUE;
|
||||
keyinfo= key_info + key;
|
||||
keyinfo->key_part= key_part_info;
|
||||
keyinfo->usable_key_parts= keyinfo->key_parts = key_parts;
|
||||
keyinfo->key_length=0;
|
||||
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
|
||||
keyinfo->flags= HA_GENERATED_KEY;
|
||||
sprintf(buf, "key%i", key);
|
||||
if (!(keyinfo->name= strdup_root(&mem_root, buf)))
|
||||
return TRUE;
|
||||
keyinfo->rec_per_key= (ulong*) alloc_root(&mem_root,
|
||||
sizeof(ulong)*key_parts);
|
||||
if (!keyinfo->rec_per_key)
|
||||
return TRUE;
|
||||
bzero(keyinfo->rec_per_key, sizeof(ulong)*key_parts);
|
||||
for (i= 0; i < key_parts; i++)
|
||||
{
|
||||
reg_field= field + next_field_no(arg);
|
||||
if (key_start)
|
||||
(*reg_field)->key_start.set_bit(key);
|
||||
key_start= FALSE;
|
||||
(*reg_field)->part_of_key.set_bit(key);
|
||||
(*reg_field)->flags|= PART_KEY_FLAG;
|
||||
key_part_info->null_bit= (*reg_field)->null_bit;
|
||||
key_part_info->null_offset= (uint) ((*reg_field)->null_ptr -
|
||||
(uchar*) record[0]);
|
||||
key_part_info->field= *reg_field;
|
||||
key_part_info->offset= (*reg_field)->offset(record[0]);
|
||||
key_part_info->length= (uint16) (*reg_field)->pack_length();
|
||||
keyinfo->key_length+= key_part_info->length;
|
||||
key_part_info->key_part_flag= 0;
|
||||
/* TODO:
|
||||
The below method of computing the key format length of the
|
||||
key part is a copy/paste from opt_range.cc, and table.cc.
|
||||
This should be factored out, e.g. as a method of Field.
|
||||
In addition it is not clear if any of the Field::*_length
|
||||
methods is supposed to compute the same length. If so, it
|
||||
might be reused.
|
||||
*/
|
||||
key_part_info->store_length= key_part_info->length;
|
||||
|
||||
if ((*reg_field)->real_maybe_null())
|
||||
{
|
||||
key_part_info->store_length+= HA_KEY_NULL_LENGTH;
|
||||
keyinfo->key_length+= HA_KEY_NULL_LENGTH;
|
||||
}
|
||||
if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
|
||||
(*reg_field)->real_type() == MYSQL_TYPE_VARCHAR)
|
||||
{
|
||||
key_part_info->store_length+= HA_KEY_BLOB_LENGTH;
|
||||
keyinfo->key_length+= HA_KEY_BLOB_LENGTH; // ???
|
||||
}
|
||||
|
||||
key_part_info->type= (uint8) (*reg_field)->key_type();
|
||||
key_part_info->key_type =
|
||||
((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
|
||||
(ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
|
||||
(ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
|
||||
0 : FIELDFLAG_BINARY;
|
||||
key_part_info++;
|
||||
}
|
||||
set_if_bigger(s->max_key_length, keyinfo->key_length);
|
||||
s->keys++;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief Check if this is part of a MERGE table with attached children.
|
||||
|
||||
|
|
|
@ -785,6 +785,7 @@ struct st_table {
|
|||
uint temp_pool_slot; /* Used by intern temp tables */
|
||||
uint status; /* What's in record[0] */
|
||||
uint db_stat; /* mode of file as in handler.h */
|
||||
uint max_keys; /* Size of allocated key_info array. */
|
||||
/* number of select if it is derived table */
|
||||
uint derived_select_number;
|
||||
int current_lock; /* Type of lock on table */
|
||||
|
@ -917,6 +918,9 @@ struct st_table {
|
|||
*/
|
||||
inline bool needs_reopen_or_name_lock()
|
||||
{ return s->version != refresh_version; }
|
||||
bool alloc_keys(uint key_count);
|
||||
bool add_tmp_key(uint key, uint key_parts,
|
||||
uint (*next_field_no) (uchar *), uchar *arg);
|
||||
bool is_children_attached(void);
|
||||
inline void enable_keyread()
|
||||
{
|
||||
|
|
|
@ -994,6 +994,8 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked)
|
|||
int ha_maria::close(void)
|
||||
{
|
||||
MARIA_HA *tmp= file;
|
||||
if (!tmp)
|
||||
return 0;
|
||||
file= 0;
|
||||
return maria_close(tmp);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifndef HA_MARIA_INCLUDED
|
||||
#define HA_MARIA_INCLUDED
|
||||
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class implementation */
|
||||
|
@ -189,3 +191,5 @@ private:
|
|||
DsMrr_impl ds_mrr;
|
||||
friend ICP_RESULT index_cond_func_maria(void *arg);
|
||||
};
|
||||
|
||||
#endif /* HA_MARIA_INCLUDED */
|
||||
|
|
|
@ -770,6 +770,8 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
|
|||
int ha_myisam::close(void)
|
||||
{
|
||||
MI_INFO *tmp=file;
|
||||
if (!tmp)
|
||||
return 0;
|
||||
file=0;
|
||||
return mi_close(tmp);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue