mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-23619: Merge 10.4 into 10.5
This commit is contained in:
@ -3998,6 +3998,240 @@ YEAR d1 d2
|
|||||||
DROP PROCEDURE p;
|
DROP PROCEDURE p;
|
||||||
DROP TABLE t1,t2,t3,t4;
|
DROP TABLE t1,t2,t3,t4;
|
||||||
#
|
#
|
||||||
|
# MDEV-23619: recursive CTE used only in the second operand of UNION
|
||||||
|
#
|
||||||
|
create table t1 (
|
||||||
|
a bigint(10) not null auto_increment,
|
||||||
|
b int(5) not null,
|
||||||
|
c bigint(10) default null,
|
||||||
|
primary key (a)
|
||||||
|
) engine myisam;
|
||||||
|
insert into t1 values
|
||||||
|
(1,3,12), (2,7,15), (3,1,3), (4,3,1);
|
||||||
|
explain with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t;
|
||||||
|
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
|
||||||
|
2 DERIVED s ALL NULL NULL NULL NULL 4
|
||||||
|
3 RECURSIVE UNION t1 ALL NULL NULL NULL NULL 4 Using where
|
||||||
|
3 RECURSIVE UNION <derived2> ref key0 key0 9 test.t1.c 2
|
||||||
|
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
|
||||||
|
4 RECURSIVE UNION <derived2> ALL NULL NULL NULL NULL 4
|
||||||
|
with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t;
|
||||||
|
b
|
||||||
|
0
|
||||||
|
3
|
||||||
|
7
|
||||||
|
1
|
||||||
|
3
|
||||||
|
analyze format=json with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t;
|
||||||
|
ANALYZE
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"union_result": {
|
||||||
|
"table_name": "<union1,4>",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 0,
|
||||||
|
"r_rows": null,
|
||||||
|
"query_specifications": [
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"message": "No tables used"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 4,
|
||||||
|
"operation": "UNION",
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"table": {
|
||||||
|
"table_name": "<derived2>",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 1,
|
||||||
|
"rows": 4,
|
||||||
|
"r_rows": 4,
|
||||||
|
"r_table_time_ms": "REPLACED",
|
||||||
|
"r_other_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100,
|
||||||
|
"materialized": {
|
||||||
|
"query_block": {
|
||||||
|
"recursive_union": {
|
||||||
|
"table_name": "<union2,3>",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 0,
|
||||||
|
"r_rows": null,
|
||||||
|
"query_specifications": [
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 2,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"table": {
|
||||||
|
"table_name": "s",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 1,
|
||||||
|
"rows": 4,
|
||||||
|
"r_rows": 4,
|
||||||
|
"r_table_time_ms": "REPLACED",
|
||||||
|
"r_other_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 3,
|
||||||
|
"operation": "UNION",
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"table": {
|
||||||
|
"table_name": "t1",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 1,
|
||||||
|
"rows": 4,
|
||||||
|
"r_rows": 4,
|
||||||
|
"r_table_time_ms": "REPLACED",
|
||||||
|
"r_other_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100,
|
||||||
|
"attached_condition": "t1.c is not null"
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"table_name": "<derived2>",
|
||||||
|
"access_type": "ref",
|
||||||
|
"possible_keys": ["key0"],
|
||||||
|
"key": "key0",
|
||||||
|
"key_length": "9",
|
||||||
|
"used_key_parts": ["a"],
|
||||||
|
"ref": ["test.t1.c"],
|
||||||
|
"r_loops": 4,
|
||||||
|
"rows": 2,
|
||||||
|
"r_rows": 0.5,
|
||||||
|
"r_table_time_ms": "REPLACED",
|
||||||
|
"r_other_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prepare stmt from "with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t";
|
||||||
|
execute stmt;
|
||||||
|
b
|
||||||
|
0
|
||||||
|
3
|
||||||
|
7
|
||||||
|
1
|
||||||
|
3
|
||||||
|
execute stmt;
|
||||||
|
b
|
||||||
|
0
|
||||||
|
3
|
||||||
|
7
|
||||||
|
1
|
||||||
|
3
|
||||||
|
deallocate prepare stmt;
|
||||||
|
#checking hanging cte that uses a recursive cte
|
||||||
|
explain with h_cte as
|
||||||
|
( with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||||
|
select * from t1 as tt;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY tt ALL NULL NULL NULL NULL 4
|
||||||
|
with h_cte as
|
||||||
|
( with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||||
|
select * from t1 as tt;
|
||||||
|
a b c
|
||||||
|
1 3 12
|
||||||
|
2 7 15
|
||||||
|
3 1 3
|
||||||
|
4 3 1
|
||||||
|
analyze format=json with h_cte as
|
||||||
|
( with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||||
|
select * from t1 as tt;
|
||||||
|
ANALYZE
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"r_loops": 1,
|
||||||
|
"r_total_time_ms": "REPLACED",
|
||||||
|
"table": {
|
||||||
|
"table_name": "tt",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"r_loops": 1,
|
||||||
|
"rows": 4,
|
||||||
|
"r_rows": 4,
|
||||||
|
"r_table_time_ms": "REPLACED",
|
||||||
|
"r_other_time_ms": "REPLACED",
|
||||||
|
"filtered": 100,
|
||||||
|
"r_filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prepare stmt from "with h_cte as
|
||||||
|
( with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||||
|
select * from t1 as tt";
|
||||||
|
execute stmt;
|
||||||
|
a b c
|
||||||
|
1 3 12
|
||||||
|
2 7 15
|
||||||
|
3 1 3
|
||||||
|
4 3 1
|
||||||
|
execute stmt;
|
||||||
|
a b c
|
||||||
|
1 3 12
|
||||||
|
2 7 15
|
||||||
|
3 1 3
|
||||||
|
4 3 1
|
||||||
|
deallocate prepare stmt;
|
||||||
|
drop table t1;
|
||||||
|
#
|
||||||
# End of 10.2 tests
|
# End of 10.2 tests
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -2675,6 +2675,56 @@ SELECT * FROM t4;
|
|||||||
DROP PROCEDURE p;
|
DROP PROCEDURE p;
|
||||||
DROP TABLE t1,t2,t3,t4;
|
DROP TABLE t1,t2,t3,t4;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-23619: recursive CTE used only in the second operand of UNION
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (
|
||||||
|
a bigint(10) not null auto_increment,
|
||||||
|
b int(5) not null,
|
||||||
|
c bigint(10) default null,
|
||||||
|
primary key (a)
|
||||||
|
) engine myisam;
|
||||||
|
insert into t1 values
|
||||||
|
(1,3,12), (2,7,15), (3,1,3), (4,3,1);
|
||||||
|
|
||||||
|
let $q=
|
||||||
|
with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t;
|
||||||
|
|
||||||
|
eval explain $q;
|
||||||
|
eval $q;
|
||||||
|
--source include/analyze-format.inc
|
||||||
|
eval analyze format=json $q;
|
||||||
|
eval prepare stmt from "$q";
|
||||||
|
execute stmt;
|
||||||
|
execute stmt;
|
||||||
|
deallocate prepare stmt;
|
||||||
|
|
||||||
|
--echo #checking hanging cte that uses a recursive cte
|
||||||
|
let $q1=
|
||||||
|
with h_cte as
|
||||||
|
( with recursive r_cte as
|
||||||
|
( select * from t1 as s
|
||||||
|
union
|
||||||
|
select t1.* from t1, r_cte as r where t1.c = r.a )
|
||||||
|
select 0 as b FROM dual union all select b FROM r_cte as t)
|
||||||
|
select * from t1 as tt;
|
||||||
|
|
||||||
|
eval explain $q1;
|
||||||
|
eval $q1;
|
||||||
|
--source include/analyze-format.inc
|
||||||
|
eval analyze format=json $q1;
|
||||||
|
eval prepare stmt from "$q1";
|
||||||
|
execute stmt;
|
||||||
|
execute stmt;
|
||||||
|
deallocate prepare stmt;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.2 tests
|
--echo # End of 10.2 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -5430,14 +5430,16 @@ void st_select_lex::set_explain_type(bool on_the_fly)
|
|||||||
/*
|
/*
|
||||||
pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
|
pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
|
||||||
*/
|
*/
|
||||||
if (tab->table && tab->table->pos_in_table_list &&
|
if (!tab->table);
|
||||||
tab->table->pos_in_table_list->with &&
|
else if (const TABLE_LIST *pos= tab->table->pos_in_table_list)
|
||||||
tab->table->pos_in_table_list->with->is_recursive)
|
{
|
||||||
|
if (pos->with && pos->with->is_recursive)
|
||||||
{
|
{
|
||||||
uses_cte= true;
|
uses_cte= true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (uses_cte)
|
if (uses_cte)
|
||||||
type= "RECURSIVE UNION";
|
type= "RECURSIVE UNION";
|
||||||
}
|
}
|
||||||
|
@ -13768,6 +13768,9 @@ void JOIN::join_free()
|
|||||||
for (tmp_unit= select_lex->first_inner_unit();
|
for (tmp_unit= select_lex->first_inner_unit();
|
||||||
tmp_unit;
|
tmp_unit;
|
||||||
tmp_unit= tmp_unit->next_unit())
|
tmp_unit= tmp_unit->next_unit())
|
||||||
|
{
|
||||||
|
if (tmp_unit->with_element && tmp_unit->with_element->is_recursive)
|
||||||
|
continue;
|
||||||
for (sl= tmp_unit->first_select(); sl; sl= sl->next_select())
|
for (sl= tmp_unit->first_select(); sl; sl= sl->next_select())
|
||||||
{
|
{
|
||||||
Item_subselect *subselect= sl->master_unit()->item;
|
Item_subselect *subselect= sl->master_unit()->item;
|
||||||
@ -13785,7 +13788,7 @@ void JOIN::join_free()
|
|||||||
/* Can't unlock if at least one JOIN is still needed */
|
/* Can't unlock if at least one JOIN is still needed */
|
||||||
can_unlock= can_unlock && full_local;
|
can_unlock= can_unlock && full_local;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
We are not using tables anymore
|
We are not using tables anymore
|
||||||
Unlock all tables. We may be in an INSERT .... SELECT statement.
|
Unlock all tables. We may be in an INSERT .... SELECT statement.
|
||||||
|
@ -2541,13 +2541,7 @@ bool st_select_lex_unit::cleanup()
|
|||||||
{
|
{
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
/*
|
if (with_element && with_element->is_recursive && union_result)
|
||||||
When processing a PS/SP or an EXPLAIN command cleanup of a unit can
|
|
||||||
be performed immediately when the unit is reached in the cleanup
|
|
||||||
traversal initiated by the cleanup of the main unit.
|
|
||||||
*/
|
|
||||||
if (!thd->stmt_arena->is_stmt_prepare() && !thd->lex->describe &&
|
|
||||||
with_element && with_element->is_recursive && union_result)
|
|
||||||
{
|
{
|
||||||
select_union_recursive *result= with_element->rec_result;
|
select_union_recursive *result= with_element->rec_result;
|
||||||
if (++result->cleanup_count == with_element->rec_outer_references)
|
if (++result->cleanup_count == with_element->rec_outer_references)
|
||||||
@ -2729,12 +2723,9 @@ bool st_select_lex::cleanup()
|
|||||||
|
|
||||||
if (join)
|
if (join)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT((st_select_lex*)join->select_lex == this);
|
List_iterator<TABLE_LIST> ti(leaf_tables);
|
||||||
error= join->destroy();
|
TABLE_LIST *tbl;
|
||||||
delete join;
|
while ((tbl= ti++))
|
||||||
join= 0;
|
|
||||||
}
|
|
||||||
for (TABLE_LIST *tbl= get_table_list(); tbl; tbl= tbl->next_local)
|
|
||||||
{
|
{
|
||||||
if (tbl->is_recursive_with_table() &&
|
if (tbl->is_recursive_with_table() &&
|
||||||
!tbl->is_with_table_recursive_reference())
|
!tbl->is_with_table_recursive_reference())
|
||||||
@ -2747,9 +2738,16 @@ bool st_select_lex::cleanup()
|
|||||||
error|= (bool) error | (uint) unit->cleanup();
|
error|= (bool) error | (uint) unit->cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DBUG_ASSERT((st_select_lex*)join->select_lex == this);
|
||||||
|
error= join->destroy();
|
||||||
|
delete join;
|
||||||
|
join= 0;
|
||||||
|
}
|
||||||
for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
|
for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
|
||||||
lex_unit= lex_unit->next_unit())
|
lex_unit= lex_unit->next_unit())
|
||||||
{
|
{
|
||||||
|
if (lex_unit->with_element && lex_unit->with_element->is_recursive)
|
||||||
|
continue;
|
||||||
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
|
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
|
||||||
}
|
}
|
||||||
inner_refs_list.empty();
|
inner_refs_list.empty();
|
||||||
@ -2769,8 +2767,12 @@ void st_select_lex::cleanup_all_joins(bool full)
|
|||||||
join->cleanup(full);
|
join->cleanup(full);
|
||||||
|
|
||||||
for (unit= first_inner_unit(); unit; unit= unit->next_unit())
|
for (unit= first_inner_unit(); unit; unit= unit->next_unit())
|
||||||
|
{
|
||||||
|
if (unit->with_element && unit->with_element->is_recursive)
|
||||||
|
continue;
|
||||||
for (sl= unit->first_select(); sl; sl= sl->next_select())
|
for (sl= unit->first_select(); sl; sl= sl->next_select())
|
||||||
sl->cleanup_all_joins(full);
|
sl->cleanup_all_joins(full);
|
||||||
|
}
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user