Commit 86d60fc9 authored by Daniel Black's avatar Daniel Black

Merge remote-tracking branch 'origin/10.4' into 10.5

parents e0ba68ba ef96ec3b
......@@ -748,7 +748,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00
2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1)) `tvc_0`) where 1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1)) `tvc_0`) where 1
explain extended select * from t1
where a in (select * from (values (1)) as tvc_0);
id select_type table type possible_keys key key_len ref rows filtered Extra
......@@ -983,7 +983,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00
2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1),(2)) `tvc_0`) where 1
explain extended select * from t1
where a = any (select * from (values (1),(2)) as tvc_0);
id select_type table type possible_keys key key_len ref rows filtered Extra
......@@ -2776,6 +2776,110 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
drop table t1;
#
# MDEV-24910: TVC containing subquery used as a subselect
#
create table t1 (a int) engine=myisam;
insert into t1 values (3), (7), (1);
create table t2 (b int) engine=myisam;
insert into t2 values (1), (2);
select (values ((select 2))) from t2;
(values ((select 2)))
2
2
explain select (values ((select 2))) from t2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
4 SUBQUERY <derived2> ALL NULL NULL NULL NULL 2
2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1249 Select 3 was reduced during optimization
prepare stmt from "select (values ((select 2))) from t2";
execute stmt;
(values ((select 2)))
2
2
execute stmt;
(values ((select 2)))
2
2
deallocate prepare stmt;
select (values ((select * from t1 where a > 10))) from t2;
(values ((select * from t1 where a > 10)))
NULL
NULL
explain select (values ((select * from t1 where a > 10))) from t2;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
4 SUBQUERY <derived2> ALL NULL NULL NULL NULL 2
2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
3 SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
prepare stmt from "select (values ((select * from t1 where a > 10))) from t2";
execute stmt;
(values ((select * from t1 where a > 10)))
NULL
NULL
execute stmt;
(values ((select * from t1 where a > 10)))
NULL
NULL
deallocate prepare stmt;
create table t3 (a int);
insert into t3 values
(3), (7), (7), (1), (3), (9), (7), (9), (8), (7), (8);
create view v1 as select count(a) as c from t3 group by a;
select
(values ((select * from t3 where a in (select * from v1))));
(values ((select * from t3 where a in (select * from v1))))
1
explain select
(values ((select * from t3 where a in (select * from v1))));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
6 SUBQUERY <derived2> ALL NULL NULL NULL NULL 2
2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
3 SUBQUERY t3 ALL NULL NULL NULL NULL 11 Using where
3 SUBQUERY <derived5> ref key0 key0 8 test.t3.a 2 Using where; FirstMatch(t3)
5 DERIVED t3 ALL NULL NULL NULL NULL 11 Using temporary; Using filesort
prepare stmt from "select
(values ((select * from t3 where a in (select * from v1))))";
execute stmt;
(values ((select * from t3 where a in (select * from v1))))
1
execute stmt;
(values ((select * from t3 where a in (select * from v1))))
1
deallocate prepare stmt;
select
(values ((select * from t3
where a > 10 and a in (select * from v1))));
(values ((select * from t3
where a > 10 and a in (select * from v1))))
NULL
explain select
(values ((select * from t3
where a > 10 and a in (select * from v1))));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
6 SUBQUERY <derived2> ALL NULL NULL NULL NULL 2
2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
3 SUBQUERY t3 ALL NULL NULL NULL NULL 11 Using where
3 SUBQUERY <derived5> ref key0 key0 8 test.t3.a 2 Using where; FirstMatch(t3)
5 DERIVED t3 ALL NULL NULL NULL NULL 11 Using temporary; Using filesort
prepare stmt from "select
(values ((select * from t3
where a > 10 and a in (select * from v1))))";
execute stmt;
(values ((select * from t3
where a > 10 and a in (select * from v1))))
NULL
execute stmt;
(values ((select * from t3
where a > 10 and a in (select * from v1))))
NULL
deallocate prepare stmt;
drop view v1;
drop table t1,t2,t3;
#
# End of 10.3 tests
#
#
......
......@@ -1459,6 +1459,63 @@ eval explain $q3;
drop table t1;
--echo #
--echo # MDEV-24910: TVC containing subquery used as a subselect
--echo #
create table t1 (a int) engine=myisam;
insert into t1 values (3), (7), (1);
create table t2 (b int) engine=myisam;
insert into t2 values (1), (2);
let $q1=
select (values ((select 2))) from t2;
eval $q1;
eval explain $q1;
eval prepare stmt from "$q1";
execute stmt;
execute stmt;
deallocate prepare stmt;
let $q2=
select (values ((select * from t1 where a > 10))) from t2;
eval $q2;
eval explain $q2;
eval prepare stmt from "$q2";
execute stmt;
execute stmt;
deallocate prepare stmt;
create table t3 (a int);
insert into t3 values
(3), (7), (7), (1), (3), (9), (7), (9), (8), (7), (8);
create view v1 as select count(a) as c from t3 group by a;
let $q3=
select
(values ((select * from t3 where a in (select * from v1))));
eval $q3;
eval explain $q3;
eval prepare stmt from "$q3";
execute stmt;
execute stmt;
deallocate prepare stmt;
let $q4=
select
(values ((select * from t3
where a > 10 and a in (select * from v1))));
eval $q4;
eval explain $q4;
eval prepare stmt from "$q4";
execute stmt;
execute stmt;
deallocate prepare stmt;
drop view v1;
drop table t1,t2,t3;
--echo #
--echo # End of 10.3 tests
--echo #
......
......@@ -746,7 +746,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00
2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1)) "tvc_0") where 1
Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1)) "tvc_0") where 1
explain extended select * from t1
where a in (select * from (values (1)) as tvc_0);
id select_type table type possible_keys key key_len ref rows filtered Extra
......@@ -981,7 +981,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
3 MATERIALIZED <derived2> ALL NULL NULL NULL NULL 2 100.00
2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1),(2)) "tvc_0") where 1
Note 1003 /* select#1 */ select "test"."t1"."a" AS "a","test"."t1"."b" AS "b" from "test"."t1" semi join ((values (1),(2)) "tvc_0") where 1
explain extended select * from t1
where a = any (select * from (values (1),(2)) as tvc_0);
id select_type table type possible_keys key key_len ref rows filtered Extra
......
......@@ -3068,6 +3068,8 @@ void st_select_lex_node::add_slave(st_select_lex_node *slave_arg)
{
slave= slave_arg;
slave_arg->master= this;
slave->prev= &master->slave;
slave->next= 0;
}
}
......@@ -3089,6 +3091,27 @@ void st_select_lex_node::link_chain_down(st_select_lex_node *first)
slave= first;
}
/*
@brief
Substitute this node in select tree for a newly creates node
@param subst the node to substitute for
@details
The function substitute this node in the select tree for a newly
created node subst. This node is just removed from the tree but all
its link fields and the attached sub-tree remain untouched.
*/
void st_select_lex_node::substitute_in_tree(st_select_lex_node *subst)
{
if ((subst->next= next))
next->prev= &subst->next;
subst->prev= prev;
(*prev)= subst;
subst->master= master;
}
/*
include on level down (but do not link)
......
......@@ -793,7 +793,7 @@ class st_select_lex_node {
link_next= NULL;
link_prev= NULL;
}
void substitute_in_tree(st_select_lex_node *subst);
void set_slave(st_select_lex_node *slave_arg) { slave= slave_arg; }
void move_node(st_select_lex_node *where_to_move)
......
......@@ -685,44 +685,61 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl,
Query_arena backup;
Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup);
Item *item;
SELECT_LEX *wrapper_sl;
SELECT_LEX_UNIT *derived_unit;
/*
Create SELECT_LEX of the select used in the result of transformation
Create SELECT_LEX wrapper_sl of the select used in the result
of the transformation
*/
lex->current_select= tvc_sl;
if (mysql_new_select(lex, 0, NULL))
if (!(wrapper_sl= new (thd->mem_root) SELECT_LEX()))
goto err;
mysql_init_select(lex);
/* Create item list as '*' for the subquery SQ */
Item *item;
SELECT_LEX *wrapper_sl;
wrapper_sl= lex->current_select;
wrapper_sl->select_number= ++thd->lex->stmt_lex->current_select_number;
wrapper_sl->parent_lex= lex; /* Used in init_query. */
wrapper_sl->init_query();
wrapper_sl->init_select();
wrapper_sl->nest_level= tvc_sl->nest_level;
wrapper_sl->parsing_place= tvc_sl->parsing_place;
wrapper_sl->set_linkage(tvc_sl->get_linkage());
wrapper_sl->parsing_place= SELECT_LIST;
lex->current_select= wrapper_sl;
item= new (thd->mem_root) Item_field(thd, &wrapper_sl->context,
star_clex_str);
if (item == NULL || add_item_to_list(thd, item))
goto err;
(wrapper_sl->with_wild)++;
/* Exclude SELECT with TVC */
tvc_sl->exclude();
/* Include the newly created select into the global list of selects */
wrapper_sl->include_global((st_select_lex_node**)&lex->all_selects_list);
/* Substitute select node used of TVC for the newly created select */
tvc_sl->substitute_in_tree(wrapper_sl);
/*
Create derived table DT that will wrap TVC in the result of transformation
Create a unit for the substituted select used for TVC and attach it
to the the wrapper select wrapper_sl as the only unit. The created
unit is the unit for the derived table tvc_x of the transformation.
*/
SELECT_LEX *tvc_select; // select for tvc
SELECT_LEX_UNIT *derived_unit; // unit for tvc_select
if (mysql_new_select(lex, 1, tvc_sl))
if (!(derived_unit= new (thd->mem_root) SELECT_LEX_UNIT()))
goto err;
tvc_select= lex->current_select;
derived_unit= tvc_select->master_unit();
tvc_select->set_linkage(DERIVED_TABLE_TYPE);
derived_unit->init_query();
derived_unit->thd= thd;
derived_unit->include_down(wrapper_sl);
lex->current_select= wrapper_sl;
/*
Attach the select used of TVC as the only slave to the unit for
the derived table tvc_x of the transformation
*/
derived_unit->add_slave(tvc_sl);
tvc_sl->set_linkage(DERIVED_TABLE_TYPE);
/*
Create the name of the wrapping derived table and
add it to the FROM list of the wrapper
*/
Generate the name of the derived table created for TVC and
add it to the FROM list of the wrapping select
*/
Table_ident *ti;
LEX_CSTRING alias;
TABLE_LIST *derived_tab;
......@@ -741,10 +758,6 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl,
wrapper_sl->table_list.first->derived_type= DTYPE_TABLE | DTYPE_MATERIALIZE;
lex->derived_tables|= DERIVED_SUBQUERY;
wrapper_sl->where= 0;
wrapper_sl->set_braces(false);
derived_unit->set_with_clause(0);
if (arena)
thd->restore_active_arena(arena, &backup);
thd->lex->result= save_result;
......
......@@ -584,14 +584,24 @@ static int end_index_scan(TABLE* table) {
return 0;
}
static void make_key(TABLE* table, uchar* key, key_part_map* map, int parts) {
static void make_key(TABLE* table, uchar** key, key_part_map* map, int parts) {
uint prefix_length= 0;
KEY_PART_INFO* key_part= table->key_info->key_part;
for (int i=0; i < parts; i++)
prefix_length += key_part[i].store_length;
*map= make_prev_keypart_map(parts);
key_copy(key, table->record[0], table->key_info, prefix_length);
if (!(*key= (uchar *) my_malloc(PSI_NOT_INSTRUMENTED, prefix_length + 1, MYF(MY_WME))))
{
WSREP_ERROR("Failed to allocate memory for key prefix_length %u", prefix_length);
assert(0);
}
key_copy(*key, table->record[0], table->key_info, prefix_length);
}
} /* namespace Wsrep_schema_impl */
......@@ -976,7 +986,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd,
Wsrep_schema_impl::binlog_off binlog_off(thd);
int error;
uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
uchar *key=NULL;
key_part_map key_map= 0;
TABLE* frag_table= 0;
......@@ -991,7 +1001,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd,
Wsrep_schema_impl::store(frag_table, 0, ws_meta.server_id());
Wsrep_schema_impl::store(frag_table, 1, ws_meta.transaction_id().get());
Wsrep_schema_impl::store(frag_table, 2, -1);
Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3);
Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3);
if ((error= Wsrep_schema_impl::init_for_index_scan(frag_table,
key, key_map)))
......@@ -1005,9 +1015,11 @@ int Wsrep_schema::update_fragment_meta(THD* thd,
}
Wsrep_schema_impl::finish_stmt(thd);
thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
my_free(key);
DBUG_RETURN(1);
}
my_free(key);
/* Copy the original record to frag_table->record[1] */
store_record(frag_table, record[1]);
......@@ -1042,7 +1054,7 @@ static int remove_fragment(THD* thd,
seqno.get());
int ret= 0;
int error;
uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
uchar *key= NULL;
key_part_map key_map= 0;
DBUG_ASSERT(server_id.is_undefined() == false);
......@@ -1056,7 +1068,7 @@ static int remove_fragment(THD* thd,
Wsrep_schema_impl::store(frag_table, 0, server_id);
Wsrep_schema_impl::store(frag_table, 1, transaction_id.get());
Wsrep_schema_impl::store(frag_table, 2, seqno.get());
Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3);
Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3);
if ((error= Wsrep_schema_impl::init_for_index_scan(frag_table,
key,
......@@ -1078,6 +1090,8 @@ static int remove_fragment(THD* thd,
ret= 1;
}
if (key)
my_free(key);
Wsrep_schema_impl::end_index_scan(frag_table);
return ret;
}
......@@ -1168,7 +1182,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd,
int ret= 1;
int error;
TABLE* frag_table= 0;
uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
uchar *key=NULL;
key_part_map key_map= 0;
for (std::vector<wsrep::seqno>::const_iterator i= fragments.begin();
......@@ -1185,7 +1199,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd,
Wsrep_schema_impl::store(frag_table, 0, ws_meta.server_id());
Wsrep_schema_impl::store(frag_table, 1, ws_meta.transaction_id().get());
Wsrep_schema_impl::store(frag_table, 2, i->get());
Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3);
Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3);
int error= Wsrep_schema_impl::init_for_index_scan(frag_table,
key,
......@@ -1232,6 +1246,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd,
Wsrep_schema_impl::finish_stmt(&thd);
DBUG_RETURN(1);
}
error= Wsrep_schema_impl::init_for_index_scan(frag_table,
key,
key_map);
......@@ -1245,6 +1260,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd,
}
error= Wsrep_schema_impl::delete_row(frag_table);
if (error)
{
WSREP_WARN("Could not delete row from streaming log table: %d", error);
......@@ -1254,8 +1270,12 @@ int Wsrep_schema::replay_transaction(THD* orig_thd,
}
Wsrep_schema_impl::end_index_scan(frag_table);
Wsrep_schema_impl::finish_stmt(&thd);
my_free(key);
key= NULL;
}
if (key)
my_free(key);
DBUG_RETURN(ret);
}
......
......@@ -1536,11 +1536,11 @@ bool pfs_show_status(handlerton *hton, THD *thd,
break;
case 147:
name= "(filename_hash).count";
size= filename_hash.count;
size= pfs_filename_hash.count;
break;
case 148:
name= "(filename_hash).size";
size= filename_hash.size;
size= pfs_filename_hash.size;
break;
case 149:
name= "(host_hash).count";
......
......@@ -91,8 +91,8 @@ PFS_memory_stat *global_instr_class_memory_array= NULL;
static PFS_ALIGNED PFS_cacheline_uint64 thread_internal_id_counter;
/** Hash table for instrumented files. */
LF_HASH filename_hash;
/** True if filename_hash is initialized. */
LF_HASH pfs_filename_hash;
/** True if pfs_filename_hash is initialized. */
static bool filename_hash_inited= false;
my_bool show_compatibility_56= 0;
......@@ -276,7 +276,7 @@ int init_file_hash(const PFS_global_param *param)
{
if ((! filename_hash_inited) && (param->m_file_sizing != 0))
{
lf_hash_init(&filename_hash, sizeof(PFS_file*), LF_HASH_UNIQUE,
lf_hash_init(&pfs_filename_hash, sizeof(PFS_file*), LF_HASH_UNIQUE,
0, 0, filename_hash_get_key, &my_charset_bin);
filename_hash_inited= true;
}
......@@ -288,7 +288,7 @@ void cleanup_file_hash(void)
{
if (filename_hash_inited)
{
lf_hash_destroy(&filename_hash);
lf_hash_destroy(&pfs_filename_hash);
filename_hash_inited= false;
}
}
......@@ -722,7 +722,7 @@ void destroy_thread(PFS_thread *pfs)
}
/**
Get the hash pins for @c filename_hash.
Get the hash pins for @pfs_filename_hash.
@param thread The running thread.
@returns The LF_HASH pins for the thread.
*/
......@@ -732,7 +732,7 @@ LF_PINS* get_filename_hash_pins(PFS_thread *thread)
{
if (! filename_hash_inited)
return NULL;
thread->m_filename_hash_pins= lf_hash_get_pins(&filename_hash);
thread->m_filename_hash_pins= lf_hash_get_pins(&pfs_filename_hash);
}
return thread->m_filename_hash_pins;
}
......@@ -849,7 +849,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
search:
entry= reinterpret_cast<PFS_file**>
(lf_hash_search(&filename_hash, pins,
(lf_hash_search(&pfs_filename_hash, pins,
normalized_filename, normalized_length));
if (entry && (entry != MY_ERRPTR))
{
......@@ -883,7 +883,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
int res;
pfs->m_lock.dirty_to_allocated(& dirty_state);
res= lf_hash_insert(&filename_hash, pins,
res= lf_hash_insert(&pfs_filename_hash, pins,
&pfs);
if (likely(res == 0))
{
......@@ -990,7 +990,7 @@ void find_and_rename_file(PFS_thread *thread, const char *old_filename,
PFS_file **entry;
entry= reinterpret_cast<PFS_file**>
(lf_hash_search(&filename_hash, pins,
(lf_hash_search(&pfs_filename_hash, pins,
normalized_filename, normalized_length));
if (entry && (entry != MY_ERRPTR))
......@@ -1001,7 +1001,7 @@ void find_and_rename_file(PFS_thread *thread, const char *old_filename,
return;
}
lf_hash_delete(&filename_hash, pins,
lf_hash_delete(&pfs_filename_hash, pins,
pfs->m_filename, pfs->m_filename_length);
/*
......@@ -1052,7 +1052,7 @@ void find_and_rename_file(PFS_thread *thread, const char *old_filename,
pfs->m_filename_length= normalized_length;
int res;
res= lf_hash_insert(&filename_hash, pins, &pfs);
res= lf_hash_insert(&pfs_filename_hash, pins, &pfs);
if (likely(res == 0))
return;
......@@ -1095,7 +1095,7 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs)
LF_PINS *pins= get_filename_hash_pins(thread);
DBUG_ASSERT(pins != NULL);
lf_hash_delete(&filename_hash, pins,
lf_hash_delete(&pfs_filename_hash, pins,
pfs->m_filename, pfs->m_filename_length);
if (klass->is_singleton())
klass->m_singleton= NULL;
......
......@@ -807,7 +807,7 @@ void update_thread_derived_flags();
/** Update derived flags for all instruments. */
void update_instruments_derived_flags();
extern LF_HASH filename_hash;
extern LF_HASH pfs_filename_hash;
/** @} */
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment