Commit 8c6a9aa3 authored by Igor Babaev's avatar Igor Babaev

Added a proper check for acceptable mutually recursive CTE.

parent 22c37c1f
...@@ -4,6 +4,21 @@ insert into t1 values ...@@ -4,6 +4,21 @@ insert into t1 values
insert into t1 values insert into t1 values
(3,'eee'), (7,'bb'), (1,'fff'), (4,'ggg'); (3,'eee'), (7,'bb'), (1,'fff'), (4,'ggg');
with recursive 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 a1(a,b) as
(select * from t1 where t1.a>3 (select * from t1 where t1.a>3
union union
...@@ -19,7 +34,7 @@ c1(a,b) as ...@@ -19,7 +34,7 @@ c1(a,b) as
union union
select * from b1 where b1.b > 'auu') select * from b1 where b1.b > 'auu')
select * from c1; select * from c1;
ERROR HY000: No anchors for recursive WITH element 'b1' ERROR HY000: Unacceptable mutual recursion with anchored table 'a1'
drop table t1; drop table t1;
# WITH RECURSIVE vs just WITH # WITH RECURSIVE vs just WITH
create table t1 (a int); create table t1 (a int);
......
...@@ -1996,7 +1996,7 @@ NUMERIC_MAX_VALUE 4294967295 ...@@ -1996,7 +1996,7 @@ NUMERIC_MAX_VALUE 4294967295
NUMERIC_BLOCK_SIZE 1 NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL ENUM_VALUE_LIST NULL
READ_ONLY NO READ_ONLY NO
+COMMAND_LINE_ARGUMENT OPTIONAL COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME MAX_SEEKS_FOR_KEY VARIABLE_NAME MAX_SEEKS_FOR_KEY
SESSION_VALUE 4294967295 SESSION_VALUE 4294967295
GLOBAL_VALUE 4294967295 GLOBAL_VALUE 4294967295
......
...@@ -4,7 +4,24 @@ insert into t1 values ...@@ -4,7 +4,24 @@ insert into t1 values
insert into t1 values insert into t1 values
(3,'eee'), (7,'bb'), (1,'fff'), (4,'ggg'); (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 with recursive
a1(a,b) as a1(a,b) as
(select * from t1 where t1.a>3 (select * from t1 where t1.a>3
......
...@@ -7154,6 +7154,8 @@ ER_DUP_QUERY_NAME ...@@ -7154,6 +7154,8 @@ ER_DUP_QUERY_NAME
eng "Duplicate query name in WITH clause" eng "Duplicate query name in WITH clause"
ER_RECURSIVE_WITHOUT_ANCHORS ER_RECURSIVE_WITHOUT_ANCHORS
eng "No anchors for recursive WITH element '%s'" 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 ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED
eng "Reference to recursive WITH table '%s' in materiazed derived" eng "Reference to recursive WITH table '%s' in materiazed derived"
ER_NOT_STANDARDS_COMPLIANT_RECURSIVE ER_NOT_STANDARDS_COMPLIANT_RECURSIVE
......
...@@ -292,45 +292,52 @@ bool With_clause::check_anchors() ...@@ -292,45 +292,52 @@ bool With_clause::check_anchors()
with_elem != NULL; with_elem != NULL;
with_elem= with_elem->next_elem) with_elem= with_elem->next_elem)
{ {
if (!with_elem->is_recursive || with_elem->with_anchor) if (!with_elem->is_recursive)
continue; continue;
table_map anchored= 0; if (!with_elem->with_anchor)
for (With_element *elem= with_elem;
elem != NULL;
elem= elem->next_elem)
{ {
if (elem->mutually_recursive && elem->with_anchor) With_element *elem= with_elem;
anchored |= elem->get_elem_map(); while ((elem= elem->get_next_mutually_recursive()) != with_elem)
{
if (elem->with_anchor)
break;
} }
table_map non_anchored= with_elem->mutually_recursive & ~anchored; if (elem == with_elem)
with_elem->work_dep_map= non_anchored & with_elem->base_dep_map; {
my_error(ER_RECURSIVE_WITHOUT_ANCHORS, MYF(0),
with_elem->query_name->str);
return true;
} }
}
/*Building transitive clousure on work_dep_map*/ else
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(); With_element *elem= with_elem;
for (With_element *elem= first_elem; elem != NULL; elem= elem->next_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 (elem->work_dep_map & with_elem_map) if (el->work_dep_map & elem_map)
elem->work_dep_map|= with_elem->work_dep_map; el->work_dep_map|= elem->work_dep_map;
} }
} }
elem= with_elem;
for (With_element *with_elem= first_elem; while ((elem= elem->get_next_mutually_recursive()) != with_elem)
with_elem != NULL;
with_elem= with_elem->next_elem)
{ {
if (with_elem->work_dep_map & with_elem->get_elem_map()) if (elem->work_dep_map & elem->get_elem_map())
{ {
my_error(ER_RECURSIVE_WITHOUT_ANCHORS, MYF(0), my_error(ER_UNACCEPTABLE_MUTUAL_RECURSION, MYF(0),
with_elem->query_name->str); with_elem->query_name->str);
return true; return true;
} }
} }
}
}
return false; return false;
} }
......
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