Skip to content
/ server Public

Commit 9f70e0a

Browse files
committed
MDEV-32299 Segfault when preparing unreferenced select in recursive CTE
With_element::prepare_unreferenced() contains query from recursive CTE which is upper owner of unreferenced CTE itself. Such recursive derived table is resolved into its expression and it tries to resolve fields or any other data from subqueries which are not yet prepared. These subqueries are preparing in upper frames of the same stack after prepare_unreferenced() finishes. That does not happen when recursion happens in referenced CTE because in that case there are links between the derived tables defined by the parser and descending into such recursion descends further into all the dependency queries. No such link exists in unreferenced query therefore it misses its upper dependencies. The fix moves prepare_unreferenced() later after JOIN::prepare() so it has the chance to access all the prepared data. There may be another fix of failing unreferenced queries with error as such kind of queries seem to be not usable.
1 parent 9fad7ac commit 9f70e0a

File tree

7 files changed

+249
-7
lines changed

7 files changed

+249
-7
lines changed

mysql-test/main/cte_recursive.result

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5975,4 +5975,111 @@ drop table t1;
59755975
#
59765976
SELECT ( WITH RECURSIVE x AS ( WITH x AS ( SELECT 1 FROM t14 ) SELECT x ) , t14 AS ( SELECT 1 UNION SELECT 'x' FROM x ) SELECT x FROM x WHERE ( SELECT x FROM x ) ) ;
59775977
ERROR 42S22: Unknown column 'x' in 'SELECT'
5978+
#
5979+
# MDEV-32299 Segfault when preparing unreferenced select in recursive CTE
5980+
#
5981+
SELECT ( WITH RECURSIVE x AS ( SELECT * FROM ( SELECT UTC_TIMESTAMP FROM ( SELECT ( WITH x AS ( WITH x AS ( SELECT * FROM x ) SELECT 1 ) SELECT 1 ) ) x ) x UNION SELECT NULL ) ( SELECT x FROM x ) ) ;
5982+
ERROR 42S22: Unknown column 'x' in 'SELECT'
5983+
select (
5984+
with recursive x as (
5985+
select * from (
5986+
select utc_timestamp
5987+
from (
5988+
select (
5989+
with x as (
5990+
with x as (
5991+
select * from x
5992+
)
5993+
select 1
5994+
)
5995+
select 1
5996+
) s
5997+
) y
5998+
) z
5999+
union
6000+
select null
6001+
)
6002+
(select x from x)
6003+
);
6004+
ERROR 42S22: Unknown column 'x' in 'SELECT'
6005+
select (
6006+
with recursive r as (
6007+
select * from (
6008+
with a as (
6009+
select * from r
6010+
)
6011+
select 1
6012+
) y
6013+
union
6014+
select 1
6015+
)
6016+
(select * from r)
6017+
);
6018+
(
6019+
with recursive r as (
6020+
select * from (
6021+
with a as (
6022+
select * from r
6023+
)
6024+
select 1
6025+
) y
6026+
union
6027+
select 1
6028+
)
6029+
(select * from r)
6030+
)
6031+
1
6032+
create table t1 (x int);
6033+
with recursive r as (
6034+
select f1 from (
6035+
with a as (
6036+
select x from t1
6037+
)
6038+
select 1 as f1
6039+
) y
6040+
union
6041+
select null
6042+
)
6043+
(select * from r);
6044+
f1
6045+
1
6046+
NULL
6047+
with recursive r as (
6048+
select f1 from (
6049+
with a as (
6050+
select f2 from t1
6051+
)
6052+
select 1 as f1
6053+
) y
6054+
union
6055+
select null
6056+
)
6057+
(select * from r);
6058+
ERROR 42S22: Unknown column 'f2' in 'SELECT'
6059+
drop table t1;
6060+
with recursive r as (
6061+
select 1 as f1
6062+
union
6063+
select f1 from (
6064+
with a as (
6065+
select f1 from r
6066+
)
6067+
select 1 as f1
6068+
) y
6069+
)
6070+
(select f1 from r);
6071+
f1
6072+
1
6073+
with recursive r as (
6074+
select 1 as f1
6075+
union
6076+
select f1 from (
6077+
with a as (
6078+
select f2 from r
6079+
)
6080+
select 1 as f1
6081+
) y
6082+
)
6083+
(select f1 from r);
6084+
ERROR 42S22: Unknown column 'f2' in 'SELECT'
59786085
# End of 10.6 tests

mysql-test/main/cte_recursive.test

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
--source include/no_msan_without_big.inc
44
--source include/not_valgrind.inc
55
--source include/have_innodb.inc
6+
# --view-protocol fails due to MDEV-37119 for MDEV-32299
7+
--source include/no_view_protocol.inc
68

79
create table t1 (a int, b varchar(32));
810
insert into t1 values
@@ -4064,4 +4066,121 @@ drop table t1;
40644066
--error ER_BAD_FIELD_ERROR
40654067
SELECT ( WITH RECURSIVE x AS ( WITH x AS ( SELECT 1 FROM t14 ) SELECT x ) , t14 AS ( SELECT 1 UNION SELECT 'x' FROM x ) SELECT x FROM x WHERE ( SELECT x FROM x ) ) ;
40664068

4069+
--echo #
4070+
--echo # MDEV-32299 Segfault when preparing unreferenced select in recursive CTE
4071+
--echo #
4072+
4073+
# As in bug report
4074+
--error ER_BAD_FIELD_ERROR
4075+
SELECT ( WITH RECURSIVE x AS ( SELECT * FROM ( SELECT UTC_TIMESTAMP FROM ( SELECT ( WITH x AS ( WITH x AS ( SELECT * FROM x ) SELECT 1 ) SELECT 1 ) ) x ) x UNION SELECT NULL ) ( SELECT x FROM x ) ) ;
4076+
4077+
#0 0x00005555569dff7b in TABLE_LIST::reset_const_table (this=0x7fffe0019938) at ../src/sql/table.cc:9615
4078+
#1 0x00005555569dffd4 in TABLE_LIST::reset_const_table (this=0x7fffe001a8c0) at ../src/sql/table.cc:9622
4079+
--error ER_BAD_FIELD_ERROR
4080+
select (
4081+
with recursive x as (
4082+
select * from (
4083+
select utc_timestamp
4084+
from (
4085+
select (
4086+
with x as (
4087+
with x as (
4088+
select * from x
4089+
)
4090+
select 1
4091+
)
4092+
select 1
4093+
) s
4094+
) y
4095+
) z
4096+
4097+
union
4098+
4099+
select null
4100+
)
4101+
(select x from x)
4102+
);
4103+
4104+
#6 0x00007ffff7639206 in __assert_fail (assertion=0x555555e121b6 "table_ref->table || table_ref->view", file=0x555555cdf138 "../src/sql/table.cc", line=7305, function=0x555555e30e24 "void Field_iterator_table_ref::set_field_iterator()") at ./assert/assert.c:101
4105+
#7 0x00005555569da013 in Field_iterator_table_ref::set_field_iterator (this=0x7ffff0a9afc0) at ../src/sql/table.cc:7305
4106+
select (
4107+
with recursive r as (
4108+
select * from (
4109+
with a as (
4110+
select * from r
4111+
)
4112+
select 1
4113+
) y
4114+
4115+
union
4116+
4117+
select 1
4118+
)
4119+
(select * from r)
4120+
);
4121+
4122+
# Field resolution in unreferenced:
4123+
create table t1 (x int);
4124+
4125+
with recursive r as (
4126+
select f1 from (
4127+
with a as (
4128+
select x from t1
4129+
)
4130+
select 1 as f1
4131+
) y
4132+
4133+
union
4134+
4135+
select null
4136+
)
4137+
(select * from r);
4138+
4139+
--error ER_BAD_FIELD_ERROR
4140+
with recursive r as (
4141+
select f1 from (
4142+
with a as (
4143+
select f2 from t1
4144+
)
4145+
select 1 as f1
4146+
) y
4147+
4148+
union
4149+
4150+
select null
4151+
)
4152+
(select * from r);
4153+
4154+
drop table t1;
4155+
4156+
with recursive r as (
4157+
select 1 as f1
4158+
4159+
union
4160+
4161+
select f1 from (
4162+
with a as (
4163+
select f1 from r
4164+
)
4165+
select 1 as f1
4166+
) y
4167+
)
4168+
(select f1 from r);
4169+
4170+
--error ER_BAD_FIELD_ERROR
4171+
with recursive r as (
4172+
select 1 as f1
4173+
4174+
union
4175+
4176+
select f1 from (
4177+
with a as (
4178+
select f2 from r
4179+
)
4180+
select 1 as f1
4181+
) y
4182+
)
4183+
(select f1 from r);
4184+
4185+
40674186
--echo # End of 10.6 tests

sql/sql_cte.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,19 @@ bool LEX::check_dependencies_in_with_clauses()
100100
}
101101

102102

103+
bool LEX::prepare_unreferenced_in_with_clauses()
104+
{
105+
for (With_clause *with_clause= with_clauses_list;
106+
with_clause;
107+
with_clause= with_clause->next_with_clause)
108+
{
109+
if (with_clause->prepare_unreferenced_elements(thd))
110+
return true;
111+
}
112+
return false;
113+
}
114+
115+
103116
/**
104117
@brief
105118
Resolve table references to CTE from a sub-chain of table references

sql/sql_cte.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -438,9 +438,7 @@ class With_clause : public Sql_alloc
438438
void print(THD *thd, String *str, enum_query_type query_type);
439439

440440
friend class With_element;
441-
442-
friend
443-
bool LEX::check_dependencies_in_with_clauses();
441+
friend struct LEX;
444442
};
445443

446444
inline

sql/sql_lex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4954,6 +4954,7 @@ struct LEX: public Query_tables_list
49544954
DDL_options ddl_options);
49554955

49564956
bool check_dependencies_in_with_clauses();
4957+
bool prepare_unreferenced_in_with_clauses();
49574958
bool check_cte_dependencies_and_resolve_references();
49584959
bool resolve_references_to_cte(TABLE_LIST *tables,
49594960
TABLE_LIST **tables_last,

sql/sql_prepare.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,10 @@ static int mysql_test_select(Prepared_statement *stmt,
16281628
*/
16291629
if (unit->prepare(unit->derived, 0, 0))
16301630
goto error;
1631+
1632+
if (thd->lex->prepare_unreferenced_in_with_clauses())
1633+
goto error;
1634+
16311635
if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare())
16321636
{
16331637
/* Make copy of item list, as change_columns may change it */

sql/sql_select.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,10 +1645,6 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
16451645
}
16461646
}
16471647

1648-
With_clause *with_clause=select_lex->get_with_clause();
1649-
if (with_clause && with_clause->prepare_unreferenced_elements(thd))
1650-
DBUG_RETURN(1);
1651-
16521648
With_element *with_elem= select_lex->get_with_element();
16531649
if (with_elem &&
16541650
select_lex->check_unrestricted_recursive(
@@ -5265,6 +5261,10 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
52655261
}
52665262

52675263
thd->get_stmt_da()->reset_current_row_for_warning(1);
5264+
5265+
if (thd->lex->prepare_unreferenced_in_with_clauses())
5266+
goto err;
5267+
52685268
/* Look for a table owned by an engine with the select_handler interface */
52695269
select_lex->pushdown_select= find_select_handler(thd, select_lex);
52705270

0 commit comments

Comments
 (0)