Skip to content

Commit

Permalink
Added a proper check for acceptable mutually recursive CTE.
Browse files Browse the repository at this point in the history
  • Loading branch information
igorbabaev committed Jun 30, 2016
1 parent 22c37c1 commit 8c6a9aa
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 36 deletions.
17 changes: 16 additions & 1 deletion mysql-test/r/cte_recursive.result
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ insert into t1 values
insert into t1 values
(3,'eee'), (7,'bb'), (1,'fff'), (4,'ggg');
with recursive
t as
(
select * from t1 where t1.b >= 'c'
union
select * from r
),
r as
(
select * from t
union
select t1.* from t1,r where r.a+1 = t1.a
)
select * from r;
ERROR HY000: Unacceptable mutual recursion with anchored table 't'
with recursive
a1(a,b) as
(select * from t1 where t1.a>3
union
Expand All @@ -19,7 +34,7 @@ c1(a,b) as
union
select * from b1 where b1.b > 'auu')
select * from c1;
ERROR HY000: No anchors for recursive WITH element 'b1'
ERROR HY000: Unacceptable mutual recursion with anchored table 'a1'
drop table t1;
# WITH RECURSIVE vs just WITH
create table t1 (a int);
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
Original file line number Diff line number Diff line change
Expand Up @@ -1996,7 +1996,7 @@ NUMERIC_MAX_VALUE 4294967295
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
+COMMAND_LINE_ARGUMENT OPTIONAL
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME MAX_SEEKS_FOR_KEY
SESSION_VALUE 4294967295
GLOBAL_VALUE 4294967295
Expand Down
19 changes: 18 additions & 1 deletion mysql-test/t/cte_recursive.test
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,24 @@ insert into t1 values
insert into t1 values
(3,'eee'), (7,'bb'), (1,'fff'), (4,'ggg');

--ERROR ER_RECURSIVE_WITHOUT_ANCHORS
--ERROR ER_UNACCEPTABLE_MUTUAL_RECURSION
with recursive
t as
(
select * from t1 where t1.b >= 'c'
union
select * from r
),
r as
(
select * from t
union
select t1.* from t1,r where r.a+1 = t1.a
)
select * from r;


--ERROR ER_UNACCEPTABLE_MUTUAL_RECURSION
with recursive
a1(a,b) as
(select * from t1 where t1.a>3
Expand Down
2 changes: 2 additions & 0 deletions sql/share/errmsg-utf8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7154,6 +7154,8 @@ ER_DUP_QUERY_NAME
eng "Duplicate query name in WITH clause"
ER_RECURSIVE_WITHOUT_ANCHORS
eng "No anchors for recursive WITH element '%s'"
ER_UNACCEPTABLE_MUTUAL_RECURSION
eng "Unacceptable mutual recursion with anchored table '%s'"
ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED
eng "Reference to recursive WITH table '%s' in materiazed derived"
ER_NOT_STANDARDS_COMPLIANT_RECURSIVE
Expand Down
73 changes: 40 additions & 33 deletions sql/sql_cte.cc
Original file line number Diff line number Diff line change
Expand Up @@ -292,43 +292,50 @@ bool With_clause::check_anchors()
with_elem != NULL;
with_elem= with_elem->next_elem)
{
if (!with_elem->is_recursive || with_elem->with_anchor)
if (!with_elem->is_recursive)
continue;

table_map anchored= 0;
for (With_element *elem= with_elem;
elem != NULL;
elem= elem->next_elem)
{
if (elem->mutually_recursive && elem->with_anchor)
anchored |= elem->get_elem_map();
}
table_map non_anchored= with_elem->mutually_recursive & ~anchored;
with_elem->work_dep_map= non_anchored & with_elem->base_dep_map;
}

/*Building transitive clousure on work_dep_map*/
for (With_element *with_elem= first_elem;
with_elem != NULL;
with_elem= with_elem->next_elem)
{
table_map with_elem_map= with_elem->get_elem_map();
for (With_element *elem= first_elem; elem != NULL; elem= elem->next_elem)

if (!with_elem->with_anchor)
{
if (elem->work_dep_map & with_elem_map)
elem->work_dep_map|= with_elem->work_dep_map;
With_element *elem= with_elem;
while ((elem= elem->get_next_mutually_recursive()) != with_elem)
{
if (elem->with_anchor)
break;
}
if (elem == with_elem)
{
my_error(ER_RECURSIVE_WITHOUT_ANCHORS, MYF(0),
with_elem->query_name->str);
return true;
}
}
}

for (With_element *with_elem= first_elem;
with_elem != NULL;
with_elem= with_elem->next_elem)
{
if (with_elem->work_dep_map & with_elem->get_elem_map())
else
{
my_error(ER_RECURSIVE_WITHOUT_ANCHORS, MYF(0),
with_elem->query_name->str);
return true;
With_element *elem= with_elem;
while ((elem= elem->get_next_mutually_recursive()) != with_elem)
elem->work_dep_map= elem->base_dep_map & elem->mutually_recursive;
elem= with_elem;
while ((elem= elem->get_next_mutually_recursive()) != with_elem)
{
table_map elem_map= elem->get_elem_map();
With_element *el= with_elem;
while ((el= el->get_next_mutually_recursive()) != with_elem)
{
if (el->work_dep_map & elem_map)
el->work_dep_map|= elem->work_dep_map;
}
}
elem= with_elem;
while ((elem= elem->get_next_mutually_recursive()) != with_elem)
{
if (elem->work_dep_map & elem->get_elem_map())
{
my_error(ER_UNACCEPTABLE_MUTUAL_RECURSION, MYF(0),
with_elem->query_name->str);
return true;
}
}
}
}

Expand Down

0 comments on commit 8c6a9aa

Please sign in to comment.