mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
mdev-9864: cleanup, re-factoring.
Added comments.
This commit is contained in:
@@ -128,6 +128,11 @@ public:
|
||||
/* TRUE <=> The underlying SELECT is correlated w.r.t some ancestor select */
|
||||
bool is_correlated;
|
||||
|
||||
/*
|
||||
TRUE <=> the subquery contains a recursive reference in the FROM list
|
||||
of one of its selects. In this case some of subquery optimization
|
||||
strategies cannot be applied for the subquery;
|
||||
*/
|
||||
bool with_recursive_reference;
|
||||
|
||||
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
|
||||
|
@@ -7157,7 +7157,7 @@ ER_RECURSIVE_WITHOUT_ANCHORS
|
||||
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"
|
||||
eng "Reference to recursive WITH table '%s' in materialized derived"
|
||||
ER_NOT_STANDARDS_COMPLIANT_RECURSIVE
|
||||
eng "Restrictions imposed on recursive definitions are violated for table '%s'"
|
||||
#
|
||||
|
@@ -4682,10 +4682,12 @@ class select_union_recursive :public select_union
|
||||
{
|
||||
public:
|
||||
TABLE *incr_table;
|
||||
TABLE *first_rec_table_to_update;
|
||||
List<TABLE> rec_tables;
|
||||
|
||||
select_union_recursive(THD *thd_arg):
|
||||
select_union(thd_arg), incr_table(0) {};
|
||||
select_union(thd_arg),
|
||||
incr_table(0), first_rec_table_to_update(0) {};
|
||||
|
||||
int send_data(List<Item> &items);
|
||||
bool create_result_table(THD *thd, List<Item> *column_types,
|
||||
|
565
sql/sql_cte.cc
565
sql/sql_cte.cc
@@ -14,21 +14,25 @@
|
||||
with_clauses_list Pointer to the first clause in the list
|
||||
|
||||
@details
|
||||
The procedure just calls the method With_clause::check_dependencies
|
||||
for each member of the given list.
|
||||
For each with clause from the given list the procedure finds all
|
||||
dependencies between tables defined in the clause by calling the
|
||||
method With_clause::checked_dependencies.
|
||||
Additionally, based on the info collected by this method the procedure
|
||||
finds anchors for each recursive definition and moves them at the head
|
||||
of the definition.
|
||||
|
||||
@retval
|
||||
false on success
|
||||
true on failure
|
||||
*/
|
||||
|
||||
bool check_dependencies_in_with_clauses(THD *thd, With_clause *with_clauses_list)
|
||||
bool check_dependencies_in_with_clauses(With_clause *with_clauses_list)
|
||||
{
|
||||
for (With_clause *with_clause= with_clauses_list;
|
||||
with_clause;
|
||||
with_clause= with_clause->next_with_clause)
|
||||
{
|
||||
if (with_clause->check_dependencies(thd))
|
||||
if (with_clause->check_dependencies())
|
||||
return true;
|
||||
if (with_clause->check_anchors())
|
||||
return true;
|
||||
@@ -43,43 +47,38 @@ bool check_dependencies_in_with_clauses(THD *thd, With_clause *with_clauses_list
|
||||
Check dependencies between tables defined in this with clause
|
||||
|
||||
@details
|
||||
The method performs the following actions for this with clause:
|
||||
|
||||
1. Test for definitions of the tables with the same name.
|
||||
2. For each table T defined in this with clause look for tables
|
||||
from the same with clause that are used in the query that
|
||||
specifies T and set the dependencies of T on these tables
|
||||
in dependency_map.
|
||||
3. Build the transitive closure of the above direct dependencies
|
||||
The method performs the following for this with clause:
|
||||
- checks that there are no definitions of the tables with the same name
|
||||
- for each table T defined in this with clause looks for the tables
|
||||
from the same with clause that are used in the query that specifies T
|
||||
and set the dependencies of T on these tables in a bitmap.
|
||||
- builds the transitive closure of the above direct dependencies
|
||||
to find out all recursive definitions.
|
||||
4. If this with clause is not specified as recursive then
|
||||
for each with table T defined in this with clause check whether
|
||||
it is used in any definition that follows the definition of T.
|
||||
|
||||
@retval
|
||||
true if an error is reported
|
||||
false otherwise
|
||||
*/
|
||||
|
||||
bool With_clause::check_dependencies(THD *thd)
|
||||
bool With_clause::check_dependencies()
|
||||
{
|
||||
if (dependencies_are_checked)
|
||||
return false;
|
||||
/*
|
||||
Look for for definitions with the same query name.
|
||||
When found report an error and return true immediately.
|
||||
For each table T defined in this with clause look for all other tables from
|
||||
the same with with clause that are used in the specification of T.
|
||||
For each table T defined in this with clause look for all other tables
|
||||
from the same with clause that are used in the specification of T.
|
||||
For each such table set the dependency bit in the dependency map of
|
||||
with element for T.
|
||||
the with element for T.
|
||||
*/
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
for (With_element *elem= first_elem;
|
||||
for (With_element *elem= with_list.first;
|
||||
elem != with_elem;
|
||||
elem= elem->next_elem)
|
||||
elem= elem->next)
|
||||
{
|
||||
if (my_strcasecmp(system_charset_info, with_elem->query_name->str,
|
||||
elem->query_name->str) == 0)
|
||||
@@ -88,20 +87,20 @@ bool With_clause::check_dependencies(THD *thd)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (with_elem->check_dependencies_in_spec(thd))
|
||||
if (with_elem->check_dependencies_in_spec())
|
||||
return true;
|
||||
}
|
||||
/* Build the transitive closure of the direct dependencies found above */
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
with_elem->derived_dep_map= with_elem->base_dep_map;
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
table_map with_elem_map= with_elem->get_elem_map();
|
||||
for (With_element *elem= first_elem; elem != NULL; elem= elem->next_elem)
|
||||
for (With_element *elem= with_list.first; elem; elem= elem->next)
|
||||
{
|
||||
if (elem->derived_dep_map & with_elem_map)
|
||||
elem->derived_dep_map |= with_elem->derived_dep_map;
|
||||
@@ -109,12 +108,12 @@ bool With_clause::check_dependencies(THD *thd)
|
||||
}
|
||||
|
||||
/*
|
||||
Mark those elements where tables are defined with direct or indirect recursion.
|
||||
Report an error when recursion (direct or indirect) is used to define a table.
|
||||
Mark those elements where tables are defined with direct or indirect
|
||||
make recursion.
|
||||
*/
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
if (with_elem->derived_dep_map & with_elem->get_elem_map())
|
||||
with_elem->is_recursive= true;
|
||||
@@ -125,13 +124,35 @@ bool With_clause::check_dependencies(THD *thd)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This structure describes an element of the stack of embedded units.
|
||||
The stack is used when looking for a definition of a table in
|
||||
with clauses. The definition can be found only in the scopes
|
||||
of the with clauses attached to the units from the stack.
|
||||
The with clauses are looked through from starting from the top
|
||||
element of the stack.
|
||||
*/
|
||||
|
||||
struct st_unit_ctxt_elem
|
||||
{
|
||||
st_unit_ctxt_elem *prev;
|
||||
st_unit_ctxt_elem *prev; // the previous element of the stack
|
||||
st_select_lex_unit *unit;
|
||||
};
|
||||
|
||||
bool With_element::check_dependencies_in_spec(THD *thd)
|
||||
|
||||
/**
|
||||
@brief
|
||||
Find the dependencies of this element on its siblings in its specification
|
||||
|
||||
@details
|
||||
For each table reference ref(T) from the FROM list of every select sl
|
||||
immediately contained in the specification query of this element this
|
||||
method searches for the definition of T in the the with clause which
|
||||
this element belongs to. If such definition is found then the dependency
|
||||
on it is set in sl->with_dep and in this->base_dep_map.
|
||||
*/
|
||||
|
||||
bool With_element::check_dependencies_in_spec()
|
||||
{
|
||||
for (st_select_lex *sl= spec->first_select(); sl; sl= sl->next_select())
|
||||
{
|
||||
@@ -144,6 +165,62 @@ bool With_element::check_dependencies_in_spec(THD *thd)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Search for the definition of a table among the elements of this with clause
|
||||
|
||||
@param table The reference to the table that is looked for
|
||||
@param barrier The barrier with element for the search
|
||||
|
||||
@details
|
||||
The function looks through the elements of this with clause trying to find
|
||||
the definition of the given table. When it encounters the element with
|
||||
the same query name as the table's name it returns this element. If no
|
||||
such definitions are found the function returns NULL.
|
||||
|
||||
@retval
|
||||
found with element if the search succeeded
|
||||
NULL - otherwise
|
||||
*/
|
||||
|
||||
With_element *With_clause::find_table_def(TABLE_LIST *table,
|
||||
With_element *barrier)
|
||||
{
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem != barrier;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
if (my_strcasecmp(system_charset_info, with_elem->query_name->str,
|
||||
table->table_name) == 0)
|
||||
{
|
||||
table->set_derived();
|
||||
return with_elem;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Search for the definition of a table in with clauses
|
||||
|
||||
@param tbl The reference to the table that is looked for
|
||||
@param ctxt The context describing in what with clauses of the upper
|
||||
levels the table has to be searched for.
|
||||
|
||||
@details
|
||||
The function looks for the definition of the table tbl in the definitions
|
||||
of the with clauses from the upper levels specified by the parameter ctxt.
|
||||
When it encounters the element with the same query name as the table's name
|
||||
it returns this element. If no such definitions are found the function
|
||||
returns NULL.
|
||||
|
||||
@retval
|
||||
found with element if the search succeeded
|
||||
NULL - otherwise
|
||||
*/
|
||||
|
||||
With_element *find_table_def_in_with_clauses(TABLE_LIST *tbl,
|
||||
st_unit_ctxt_elem *ctxt)
|
||||
{
|
||||
@@ -159,12 +236,41 @@ With_element *find_table_def_in_with_clauses(TABLE_LIST *tbl,
|
||||
return tbl->with;
|
||||
barrier= NULL;
|
||||
if (unit->with_element && !unit->with_element->get_owner()->with_recursive)
|
||||
{
|
||||
/*
|
||||
This unit is the specification if the with element unit->with_element.
|
||||
The with element belongs to a with clause without the specifier RECURSIVE.
|
||||
So when searching for the matching definition of tbl this with clause must
|
||||
be looked up to this with element
|
||||
*/
|
||||
barrier= unit->with_element;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Find the dependencies of this element on its siblings in a select
|
||||
|
||||
@param sl The select where to look for the dependencies
|
||||
@param ctxt The structure specifying the scope of the definitions
|
||||
of the with elements of the upper levels
|
||||
@param in_sbq if true mark dependencies found in subqueries in
|
||||
this->sq_dep_map
|
||||
@param dep_map IN/OUT The bit where to mark the found dependencies
|
||||
|
||||
@details
|
||||
For each table reference ref(T) from the FROM list of the select sl
|
||||
the method searches in with clauses for the definition of the table T.
|
||||
If the found definition belongs to the same with clause as this with
|
||||
element then the method set dependency on T in the in/out parameter
|
||||
dep_map, add if required - in this->sq_dep_map.
|
||||
The parameter ctxt describes the proper context for the search
|
||||
of the definition of T.
|
||||
*/
|
||||
|
||||
void With_element::check_dependencies_in_select(st_select_lex *sl,
|
||||
st_unit_ctxt_elem *ctxt,
|
||||
bool in_subq,
|
||||
@@ -176,36 +282,62 @@ void With_element::check_dependencies_in_select(st_select_lex *sl,
|
||||
if (tbl->derived || tbl->nested_join)
|
||||
continue;
|
||||
tbl->with_internal_reference_map= 0;
|
||||
/*
|
||||
If there is a with clause attached to the unit containing sl
|
||||
look first for the definition of tbl in this with clause.
|
||||
If such definition is not found there look in the with
|
||||
clauses of the upper levels.
|
||||
If the definition of tbl is found somewhere in with clauses
|
||||
then tbl->with is set to point to this definition
|
||||
*/
|
||||
if (with_clause && !tbl->with)
|
||||
tbl->with= with_clause->find_table_def(tbl, NULL);
|
||||
if (!tbl->with)
|
||||
tbl->with= find_table_def_in_with_clauses(tbl, ctxt);
|
||||
|
||||
if (tbl->with && tbl->with->owner== this->owner)
|
||||
{
|
||||
/*
|
||||
The found definition T of tbl belongs to the same
|
||||
with clause as this with element. In this case:
|
||||
- set the dependence on T in the bitmap dep_map
|
||||
- set tbl->with_internal_reference_map with
|
||||
the bitmap for this definition
|
||||
- set the dependence on T in the bitmap this->sq_dep_map
|
||||
if needed
|
||||
*/
|
||||
*dep_map|= tbl->with->get_elem_map();
|
||||
tbl->with_internal_reference_map= get_elem_map();
|
||||
if (in_subq)
|
||||
sq_dep_map|= tbl->with->get_elem_map();
|
||||
}
|
||||
}
|
||||
/* Now look for the dependencies in the subqueries of sl */
|
||||
st_select_lex_unit *inner_unit= sl->first_inner_unit();
|
||||
for (; inner_unit; inner_unit= inner_unit->next_unit())
|
||||
check_dependencies_in_unit(inner_unit, ctxt, in_subq, dep_map);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
@brief
|
||||
Check dependencies on the sibling with tables used in the given unit
|
||||
Find the dependencies of this element on its siblings in a unit
|
||||
|
||||
@param unit The unit where the siblings are to be searched for
|
||||
@param unit The unit where to look for the dependencies
|
||||
@param ctxt The structure specifying the scope of the definitions
|
||||
of the with elements of the upper levels
|
||||
@param in_sbq if true mark dependencies found in subqueries in
|
||||
this->sq_dep_map
|
||||
@param dep_map IN/OUT The bit where to mark the found dependencies
|
||||
|
||||
@details
|
||||
The method recursively looks through all from lists encountered
|
||||
the given unit. If it finds a reference to a table that is
|
||||
defined in the same with clause to which this element belongs
|
||||
the method set the bit of dependency on this table in the
|
||||
dependency_map of this element.
|
||||
This method searches in the unit 'unit' for the the references in FROM
|
||||
lists of all selects contained in this unit and in the with clause
|
||||
attached to this unit that refer to definitions of tables from the
|
||||
same with clause as this element.
|
||||
If such definitions are found then the dependencies on them are
|
||||
set in the in/out parameter dep_map and optionally in this->sq_dep_map.
|
||||
The parameter ctxt describes the proper context for the search.
|
||||
*/
|
||||
|
||||
void With_element::check_dependencies_in_unit(st_select_lex_unit *unit,
|
||||
@@ -224,39 +356,83 @@ void With_element::check_dependencies_in_unit(st_select_lex_unit *unit,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Find the dependencies of this element on its siblings in a with clause
|
||||
|
||||
@param witt_clause The with clause where to look for the dependencies
|
||||
@param ctxt The structure specifying the scope of the definitions
|
||||
of the with elements of the upper levels
|
||||
@param in_sbq if true mark dependencies found in subqueries in
|
||||
this->sq_dep_map
|
||||
@param dep_map IN/OUT The bit where to mark the found dependencies
|
||||
|
||||
@details
|
||||
This method searches in the with_clause for the the references in FROM
|
||||
lists of all selects contained in the specifications of the with elements
|
||||
from this with_clause that refer to definitions of tables from the
|
||||
same with clause as this element.
|
||||
If such definitions are found then the dependencies on them are
|
||||
set in the in/out parameter dep_map and optionally in this->sq_dep_map.
|
||||
The parameter ctxt describes the proper context for the search.
|
||||
*/
|
||||
|
||||
void
|
||||
With_element::check_dependencies_in_with_clause(With_clause *with_clause,
|
||||
st_unit_ctxt_elem *ctxt,
|
||||
bool in_subq,
|
||||
table_map *dep_map)
|
||||
{
|
||||
for (With_element *with_elem= with_clause->first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_clause->with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
check_dependencies_in_unit(with_elem->spec, ctxt, in_subq, dep_map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Find mutually recursive with elements and check that they have ancors
|
||||
|
||||
@details
|
||||
This method performs the following:
|
||||
- for each recursive with element finds all mutually recursive with it
|
||||
- links each group of mutually recursive with elements into a ring chain
|
||||
- checks that every group of mutually recursive with elements contains
|
||||
at least one anchor
|
||||
- checks that after removing any with element with anchor the remaining
|
||||
with elements mutually recursive with the removed one are not recursive
|
||||
anymore
|
||||
|
||||
@retval
|
||||
true if an error is reported
|
||||
false otherwise
|
||||
*/
|
||||
|
||||
bool With_clause::check_anchors()
|
||||
{
|
||||
/* Find mutually recursive with elements */
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
if (!with_elem->is_recursive)
|
||||
continue;
|
||||
|
||||
/*
|
||||
It with_elem is recursive with element find all elements mutually recursive
|
||||
with it (any recursive element is mutually recursive with itself). Mark all
|
||||
these elements in the bitmap->mutually_recursive. Also link all these
|
||||
elements into a ring chain.
|
||||
*/
|
||||
if (!with_elem->next_mutually_recursive)
|
||||
{
|
||||
With_element *last_mutually_recursive= with_elem;
|
||||
table_map with_elem_dep= with_elem->derived_dep_map;
|
||||
table_map with_elem_map= with_elem->get_elem_map();
|
||||
for (With_element *elem= with_elem;
|
||||
elem != NULL;
|
||||
elem= elem->next_elem)
|
||||
for (With_element *elem= with_elem; elem; elem= elem->next)
|
||||
{
|
||||
if (!elem->is_recursive)
|
||||
continue;
|
||||
@@ -277,11 +453,16 @@ bool With_clause::check_anchors()
|
||||
elem->mutually_recursive= with_elem->mutually_recursive;
|
||||
}
|
||||
|
||||
/*
|
||||
For each select from the specification of 'with_elem' check whether
|
||||
it is an anchor i.e. does not depend on any with elements mutually
|
||||
recursive with 'with_elem".
|
||||
*/
|
||||
for (st_select_lex *sl= with_elem->spec->first_select();
|
||||
sl;
|
||||
sl= sl->next_select())
|
||||
{
|
||||
if (!(with_elem->mutually_recursive & sl->with_dep))
|
||||
if (with_elem->is_anchor(sl))
|
||||
{
|
||||
with_elem->with_anchor= true;
|
||||
break;
|
||||
@@ -289,15 +470,25 @@ bool With_clause::check_anchors()
|
||||
}
|
||||
}
|
||||
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
/*
|
||||
Check that for any group of mutually recursive with elements
|
||||
- there is at least one anchor
|
||||
- after removing any with element with anchor the remaining with elements
|
||||
mutually recursive with the removed one are not recursive anymore
|
||||
*/
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
if (!with_elem->is_recursive)
|
||||
continue;
|
||||
|
||||
if (!with_elem->with_anchor)
|
||||
{
|
||||
/*
|
||||
Check that the other with elements mutually recursive with 'with_elem'
|
||||
contain at least one anchor.
|
||||
*/
|
||||
With_element *elem= with_elem;
|
||||
while ((elem= elem->get_next_mutually_recursive()) != with_elem)
|
||||
{
|
||||
@@ -313,7 +504,13 @@ bool With_clause::check_anchors()
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 'with_elem' is a with element with an anchor */
|
||||
With_element *elem= with_elem;
|
||||
/*
|
||||
For the other with elements mutually recursive with 'with_elem'
|
||||
set dependency bits between those elements in the field work_dep_map
|
||||
and build transitive closure of these dependencies
|
||||
*/
|
||||
while ((elem= elem->get_next_mutually_recursive()) != with_elem)
|
||||
elem->work_dep_map= elem->base_dep_map & elem->mutually_recursive;
|
||||
elem= with_elem;
|
||||
@@ -327,6 +524,7 @@ bool With_clause::check_anchors()
|
||||
el->work_dep_map|= elem->work_dep_map;
|
||||
}
|
||||
}
|
||||
/* If the transitive closure displays any cycle report an arror */
|
||||
elem= with_elem;
|
||||
while ((elem= elem->get_next_mutually_recursive()) != with_elem)
|
||||
{
|
||||
@@ -346,36 +544,53 @@ bool With_clause::check_anchors()
|
||||
|
||||
/**
|
||||
@brief
|
||||
Search for the definition of a table among the elements of this with clause
|
||||
|
||||
@param table The reference to the table that is looked for
|
||||
Move anchors at the beginning of the specifications for with elements
|
||||
|
||||
@details
|
||||
The function looks through the elements of this with clause trying to find
|
||||
the definition of the given table. When it encounters the element with
|
||||
the same query name as the table's name it returns this element. If no
|
||||
such definitions are found the function returns NULL.
|
||||
|
||||
@retval
|
||||
found with element if the search succeeded
|
||||
NULL - otherwise
|
||||
This method moves anchors at the beginning of the specifications for
|
||||
all recursive with elements.
|
||||
*/
|
||||
|
||||
With_element *With_clause::find_table_def(TABLE_LIST *table,
|
||||
With_element *barrier)
|
||||
void With_clause::move_anchors_ahead()
|
||||
{
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != barrier;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
if (my_strcasecmp(system_charset_info, with_elem->query_name->str,
|
||||
table->table_name) == 0)
|
||||
if (with_elem->is_recursive)
|
||||
with_elem->move_anchors_ahead();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Move anchors at the beginning of the specification of this with element
|
||||
|
||||
@details
|
||||
If the specification of this with element contains anchors the method
|
||||
moves them at the very beginning of the specification.
|
||||
*/
|
||||
|
||||
void With_element::move_anchors_ahead()
|
||||
{
|
||||
st_select_lex *next_sl;
|
||||
st_select_lex *new_pos= spec->first_select();
|
||||
st_select_lex *last_sl;
|
||||
new_pos->linkage= UNION_TYPE;
|
||||
for (st_select_lex *sl= new_pos; sl; sl= next_sl)
|
||||
{
|
||||
table->set_derived();
|
||||
return with_elem;
|
||||
next_sl= sl->next_select();
|
||||
if (is_anchor(sl))
|
||||
{
|
||||
sl->move_node(new_pos);
|
||||
new_pos= sl->next_select();
|
||||
}
|
||||
last_sl= sl;
|
||||
}
|
||||
return NULL;
|
||||
if (spec->union_distinct)
|
||||
spec->union_distinct= last_sl;
|
||||
first_recursive= new_pos;
|
||||
}
|
||||
|
||||
|
||||
@@ -397,9 +612,9 @@ With_element *With_clause::find_table_def(TABLE_LIST *table,
|
||||
|
||||
bool With_clause::prepare_unreferenced_elements(THD *thd)
|
||||
{
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
if (!with_elem->is_referenced() && with_elem->prepare_unreferenced(thd))
|
||||
return true;
|
||||
@@ -418,9 +633,9 @@ bool With_clause::prepare_unreferenced_elements(THD *thd)
|
||||
@param spec_end The end of the specification in the input string
|
||||
|
||||
@details
|
||||
The method creates for a string copy of the specification used in this element.
|
||||
The method is called when the element is parsed. The copy may be used to
|
||||
create clones of the specification whenever they are needed.
|
||||
The method creates for a string copy of the specification used in this
|
||||
element. The method is called when the element is parsed. The copy may be
|
||||
used to create clones of the specification whenever they are needed.
|
||||
|
||||
@retval
|
||||
false on success
|
||||
@@ -646,41 +861,6 @@ bool With_element::prepare_unreferenced(THD *thd)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void With_clause::move_anchors_ahead()
|
||||
{
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
{
|
||||
if (with_elem->is_recursive)
|
||||
with_elem->move_anchors_ahead();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void With_element::move_anchors_ahead()
|
||||
{
|
||||
st_select_lex *next_sl;
|
||||
st_select_lex *new_pos= spec->first_select();
|
||||
st_select_lex *last_sl;
|
||||
new_pos->linkage= UNION_TYPE;
|
||||
for (st_select_lex *sl= new_pos; sl; sl= next_sl)
|
||||
{
|
||||
next_sl= sl->next_select();
|
||||
if (is_anchor(sl))
|
||||
{
|
||||
sl->move_node(new_pos);
|
||||
new_pos= sl->next_select();
|
||||
}
|
||||
last_sl= sl;
|
||||
}
|
||||
if (spec->union_distinct)
|
||||
spec->union_distinct= last_sl;
|
||||
first_recursive= new_pos;
|
||||
}
|
||||
|
||||
|
||||
bool With_element::is_anchor(st_select_lex *sel)
|
||||
{
|
||||
return !(mutually_recursive & sel->with_dep);
|
||||
@@ -694,10 +874,10 @@ bool With_element::is_anchor(st_select_lex *sel)
|
||||
@param table reference to the table whose definition is searched for
|
||||
|
||||
@details
|
||||
The method looks for the definition the table whose reference is occurred
|
||||
The method looks for the definition of the table whose reference is occurred
|
||||
in the FROM list of this select node. First it searches for it in the
|
||||
with clause attached to the unit this select node belongs to. If such a
|
||||
definition is not found there the embedding units are looked through.
|
||||
definition is not found then the embedding units are looked through.
|
||||
|
||||
@retval
|
||||
pointer to the found definition if the search has been successful
|
||||
@@ -770,6 +950,12 @@ bool TABLE_LIST::is_recursive_with_table()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
A reference to a with table T is recursive if it occurs somewhere
|
||||
in the query specifying T or in the query specifying one of the tables
|
||||
mutually recursive with T.
|
||||
*/
|
||||
|
||||
bool TABLE_LIST::is_with_table_recursive_reference()
|
||||
{
|
||||
return (with_internal_reference_map &&
|
||||
@@ -777,12 +963,67 @@ bool TABLE_LIST::is_with_table_recursive_reference()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Specifications of with tables with recursive table references
|
||||
in non-mergeable derived tables are not allowed in this
|
||||
implementation.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
We say that the specification of a with table T is restricted
|
||||
if all below is true.
|
||||
1. Any immediate select of the specification contains at most one
|
||||
recursive table reference taking into account table references
|
||||
from mergeable derived tables.
|
||||
2. Any recursive table reference is not an inner operand of an
|
||||
outer join operation used in an immediate select of the
|
||||
specification.
|
||||
3. Any immediate select from the specification of T does not
|
||||
contain aggregate functions.
|
||||
4. The specification of T does not contain recursive table references.
|
||||
|
||||
If the specification of T is not restricted we call the corresponding
|
||||
with element unrestricted.
|
||||
|
||||
The SQL standards allows only with elements with restricted specification.
|
||||
By default we comply with the standards here.
|
||||
|
||||
Yet we allow unrestricted specification if the status variable
|
||||
'standards_compliant_cte' set to 'off'(0).
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Check if this select makes the including specification unrestricted
|
||||
|
||||
@param
|
||||
only_standards_compliant true if the system variable
|
||||
'standards_compliant_cte' is set to 'on'
|
||||
@details
|
||||
This method checks whether the conditions 1-4 (see the comment above)
|
||||
are satisfied for this select. If not then mark this element as
|
||||
unrestricted and report an error if 'only_standards_compliant' is true.
|
||||
|
||||
@retval
|
||||
true if an error is reported
|
||||
false otherwise
|
||||
*/
|
||||
|
||||
bool st_select_lex::check_unrestricted_recursive(bool only_standards_compliant)
|
||||
{
|
||||
With_element *with_elem= get_with_element();
|
||||
if (!with_elem ||!with_elem->is_recursive)
|
||||
{
|
||||
/*
|
||||
If this select is not from the specifiocation of a with elememt or
|
||||
if this not a recursive with element then there is nothing to check.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check conditions 1-2 for restricted specification*/
|
||||
table_map unrestricted= 0;
|
||||
table_map encountered= 0;
|
||||
if (with_elem->check_unrestricted_recursive(this,
|
||||
@@ -790,10 +1031,15 @@ bool st_select_lex::check_unrestricted_recursive(bool only_standards_compliant)
|
||||
encountered))
|
||||
return true;
|
||||
with_elem->get_owner()->add_unrestricted(unrestricted);
|
||||
|
||||
|
||||
/* Check conditions 3-4 for restricted specification*/
|
||||
if (with_sum_func ||
|
||||
(with_elem->contains_sq_with_recursive_reference()))
|
||||
with_elem->get_owner()->add_unrestricted(
|
||||
with_elem->get_mutually_recursive());
|
||||
|
||||
/* Report an error on unrestricted specification if this is required */
|
||||
if (only_standards_compliant && with_elem->is_unrestricted())
|
||||
{
|
||||
my_error(ER_NOT_STANDARDS_COMPLIANT_RECURSIVE,
|
||||
@@ -805,10 +1051,30 @@ bool st_select_lex::check_unrestricted_recursive(bool only_standards_compliant)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Check if a select from the spec of this with element is partially restricted
|
||||
|
||||
@param
|
||||
sel select from the specification of this element where to check
|
||||
whether conditions 1-2 are satisfied
|
||||
unrestricted IN/OUT bitmap where to mark unrestricted specs
|
||||
encountered IN/OUT bitmap where to mark encountered recursive references
|
||||
@details
|
||||
This method checks whether the conditions 1-2 (see the comment above)
|
||||
are satisfied for the select sel.
|
||||
This method is called recursively for derived tables.
|
||||
|
||||
@retval
|
||||
true if an error is reported
|
||||
false otherwise
|
||||
*/
|
||||
|
||||
bool With_element::check_unrestricted_recursive(st_select_lex *sel,
|
||||
table_map &unrestricted,
|
||||
table_map &encountered)
|
||||
{
|
||||
/* Check conditions 1-for restricted specification*/
|
||||
List_iterator<TABLE_LIST> ti(sel->leaf_tables);
|
||||
TABLE_LIST *tbl;
|
||||
while ((tbl= ti++))
|
||||
@@ -843,9 +1109,9 @@ bool With_element::check_unrestricted_recursive(st_select_lex *sel,
|
||||
encountered|= with_elem->get_elem_map();
|
||||
}
|
||||
}
|
||||
for (With_element *with_elem= sel->get_with_element()->owner->first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= sel->get_with_element()->owner->with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
if (!with_elem->is_recursive && (unrestricted & with_elem->get_elem_map()))
|
||||
continue;
|
||||
@@ -870,6 +1136,9 @@ bool With_element::check_unrestricted_recursive(st_select_lex *sel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check conditions 2 for restricted specification*/
|
||||
ti.rewind();
|
||||
while ((tbl= ti++))
|
||||
{
|
||||
@@ -886,7 +1155,25 @@ bool With_element::check_unrestricted_recursive(st_select_lex *sel,
|
||||
}
|
||||
|
||||
|
||||
void st_select_lex::check_subqueries_with_recursive_references()
|
||||
/**
|
||||
@brief
|
||||
Check subqueries with recursive table references from FROM list of this select
|
||||
|
||||
@details
|
||||
For each recursive table reference from the FROM list of this select
|
||||
this method checks:
|
||||
- whether this reference is within a materialized derived table and
|
||||
if so it report an error
|
||||
- whether this reference is within a subquery and if so it set a flag
|
||||
in this subquery that disallows some optimization strategies for
|
||||
this subquery.
|
||||
|
||||
@retval
|
||||
true if an error is reported
|
||||
false otherwise
|
||||
*/
|
||||
|
||||
bool st_select_lex::check_subqueries_with_recursive_references()
|
||||
{
|
||||
st_select_lex_unit *sl_master= master_unit();
|
||||
List_iterator<TABLE_LIST> ti(leaf_tables);
|
||||
@@ -895,15 +1182,27 @@ void st_select_lex::check_subqueries_with_recursive_references()
|
||||
{
|
||||
if (!(tbl->is_with_table_recursive_reference() && sl_master->item))
|
||||
continue;
|
||||
With_element *with_elem= tbl->with;
|
||||
bool check_embedding_materialized_derived= true;
|
||||
for (st_select_lex *sl= this; sl; sl= sl_master->outer_select())
|
||||
{
|
||||
sl_master= sl->master_unit();
|
||||
if (with_elem->get_owner() == sl_master->with_clause)
|
||||
check_embedding_materialized_derived= false;
|
||||
if (check_embedding_materialized_derived && !sl_master->with_element &&
|
||||
sl_master->derived && sl_master->derived->is_materialized_derived())
|
||||
{
|
||||
my_error(ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED,
|
||||
MYF(0), with_elem->query_name->str);
|
||||
return true;
|
||||
}
|
||||
if (!sl_master->item)
|
||||
continue;
|
||||
Item_subselect *subq= (Item_subselect *) sl_master->item;
|
||||
subq->with_recursive_reference= true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -924,12 +1223,12 @@ void With_clause::print(String *str, enum_query_type query_type)
|
||||
str->append(STRING_WITH_LEN("with "));
|
||||
if (with_recursive)
|
||||
str->append(STRING_WITH_LEN("recursive "));
|
||||
for (With_element *with_elem= first_elem;
|
||||
with_elem != NULL;
|
||||
with_elem= with_elem->next_elem)
|
||||
for (With_element *with_elem= with_list.first;
|
||||
with_elem;
|
||||
with_elem= with_elem->next)
|
||||
{
|
||||
with_elem->print(str, query_type);
|
||||
if (with_elem != first_elem)
|
||||
if (with_elem != with_list.first)
|
||||
str->append(", ");
|
||||
}
|
||||
}
|
||||
|
110
sql/sql_cte.h
110
sql/sql_cte.h
@@ -21,7 +21,7 @@ class With_element : public Sql_alloc
|
||||
{
|
||||
private:
|
||||
With_clause *owner; // with clause this object belongs to
|
||||
With_element *next_elem; // next element in the with clause
|
||||
With_element *next; // next element in the with clause
|
||||
uint number; // number of the element in the with clause (starting from 0)
|
||||
table_map elem_map; // The map where with only one 1 set in this->number
|
||||
/*
|
||||
@@ -36,10 +36,22 @@ private:
|
||||
directly or indirectly from the i-th with element.
|
||||
*/
|
||||
table_map derived_dep_map;
|
||||
/*
|
||||
The map sq_dep_map has 1 in i-th position if there is a reference to this
|
||||
with element somewhere in subqueries of the specifications of the tables
|
||||
defined in the with clause containing this element;
|
||||
*/
|
||||
table_map sq_dep_map;
|
||||
table_map work_dep_map; // dependency map used for work
|
||||
/* Dependency map of with elements mutually recursive with this with element */
|
||||
table_map mutually_recursive;
|
||||
/*
|
||||
The next with element from the circular chain of the with elements
|
||||
mutually recursive with this with element.
|
||||
(If This element is simply recursive than next_mutually_recursive contains
|
||||
the pointer to itself. If it's not recursive than next_mutually_recursive
|
||||
is set to NULL.)
|
||||
*/
|
||||
With_element *next_mutually_recursive;
|
||||
/*
|
||||
Total number of references to this element in the FROM lists of
|
||||
@@ -56,8 +68,6 @@ private:
|
||||
/* Return the map where 1 is set only in the position for this element */
|
||||
table_map get_elem_map() { return 1 << number; }
|
||||
|
||||
TABLE *table;
|
||||
|
||||
public:
|
||||
/*
|
||||
The name of the table introduced by this with elememt. The name
|
||||
@@ -79,34 +89,48 @@ public:
|
||||
*/
|
||||
bool is_recursive;
|
||||
|
||||
/*
|
||||
Any non-recursive select in the specification of a recursive
|
||||
with element is a called anchor. In the case mutually recursive
|
||||
elements the specification of some them may be without any anchor.
|
||||
Yet at least one of them must contain an anchor.
|
||||
All anchors of any recursivespecification are moved ahead before
|
||||
the prepare stage.
|
||||
*/
|
||||
/* Set to true if this is a recursive element with an anchor */
|
||||
bool with_anchor;
|
||||
|
||||
/*
|
||||
Set to the first recursive select of the unit specifying the element
|
||||
after all anchor have been moved to the head of the unit.
|
||||
*/
|
||||
st_select_lex *first_recursive;
|
||||
|
||||
/* The number of the last performed iteration for recursive table */
|
||||
/*
|
||||
The number of the last performed iteration for recursive table
|
||||
(the number of the initial non-recursive step is 0, the number
|
||||
of the first iteration is 1).
|
||||
*/
|
||||
uint level;
|
||||
|
||||
/*
|
||||
The pointer to the object used to materialize this with element
|
||||
if it's recursive. This object is built at the end of prepare
|
||||
stage and is used at the execution stage.
|
||||
*/
|
||||
select_union_recursive *rec_result;
|
||||
|
||||
TABLE *result_table;
|
||||
|
||||
TABLE *first_rec_table_to_update;
|
||||
|
||||
|
||||
With_element(LEX_STRING *name,
|
||||
List <LEX_STRING> list,
|
||||
st_select_lex_unit *unit)
|
||||
: next_elem(NULL), base_dep_map(0), derived_dep_map(0),
|
||||
: next(NULL), base_dep_map(0), derived_dep_map(0),
|
||||
sq_dep_map(0), work_dep_map(0), mutually_recursive(0),
|
||||
next_mutually_recursive(NULL),
|
||||
references(0), table(NULL),
|
||||
next_mutually_recursive(NULL), references(0),
|
||||
query_name(name), column_list(list), spec(unit),
|
||||
is_recursive(false), with_anchor(false),
|
||||
level(0), rec_result(NULL), result_table(NULL),
|
||||
first_rec_table_to_update(NULL)
|
||||
level(0), rec_result(NULL)
|
||||
{}
|
||||
|
||||
bool check_dependencies_in_spec(THD *thd);
|
||||
bool check_dependencies_in_spec();
|
||||
|
||||
void check_dependencies_in_select(st_select_lex *sl, st_unit_ctxt_elem *ctxt,
|
||||
bool in_subq, table_map *dep_map);
|
||||
@@ -155,10 +179,6 @@ public:
|
||||
With_element *get_next_mutually_recursive()
|
||||
{ return next_mutually_recursive; }
|
||||
|
||||
void set_table(TABLE *tab) { table= tab; }
|
||||
|
||||
TABLE *get_table() { return table; }
|
||||
|
||||
bool is_anchor(st_select_lex *sel);
|
||||
|
||||
void move_anchors_ahead();
|
||||
@@ -173,7 +193,7 @@ public:
|
||||
|
||||
void mark_as_cleaned();
|
||||
|
||||
void reset_for_exec();
|
||||
void reset_recursive_for_exec();
|
||||
|
||||
void cleanup_stabilized();
|
||||
|
||||
@@ -183,8 +203,6 @@ public:
|
||||
|
||||
bool all_are_stabilized();
|
||||
|
||||
void set_result_table(TABLE *tab) { result_table= tab; }
|
||||
|
||||
bool instantiate_tmp_tables();
|
||||
|
||||
void prepare_for_next_iteration();
|
||||
@@ -206,9 +224,9 @@ class With_clause : public Sql_alloc
|
||||
{
|
||||
private:
|
||||
st_select_lex_unit *owner; // the unit this with clause attached to
|
||||
With_element *first_elem; // the first definition in this with clause
|
||||
With_element **last_next; // here is set the link for the next added element
|
||||
uint elements; // number of the elements/defintions in this with clauses
|
||||
|
||||
/* The list of all with elements from this with clause */
|
||||
SQL_I_List<With_element> with_list;
|
||||
/*
|
||||
The with clause immediately containing this with clause if there is any,
|
||||
otherwise NULL. Now used only at parsing.
|
||||
@@ -222,9 +240,22 @@ private:
|
||||
/* Set to true if dependencies between with elements have been checked */
|
||||
bool dependencies_are_checked;
|
||||
|
||||
/*
|
||||
The bitmap of all recursive with elements whose specifications
|
||||
are not complied with restrictions imposed by the SQL standards
|
||||
on recursive specifications.
|
||||
*/
|
||||
table_map unrestricted;
|
||||
/*
|
||||
The bitmap of all recursive with elements whose anchors
|
||||
has been already prepared.
|
||||
*/
|
||||
table_map with_prepared_anchor;
|
||||
table_map cleaned;
|
||||
/*
|
||||
The bitmap of all recursive with elements that
|
||||
has been already materialized
|
||||
*/
|
||||
table_map stabilized;
|
||||
|
||||
public:
|
||||
@@ -232,23 +263,20 @@ public:
|
||||
bool with_recursive;
|
||||
|
||||
With_clause(bool recursive_fl, With_clause *emb_with_clause)
|
||||
: owner(NULL), first_elem(NULL), elements(0),
|
||||
: owner(NULL),
|
||||
embedding_with_clause(emb_with_clause), next_with_clause(NULL),
|
||||
dependencies_are_checked(false),
|
||||
unrestricted(0), with_prepared_anchor(0), cleaned(0),
|
||||
stabilized(0),
|
||||
dependencies_are_checked(false), unrestricted(0),
|
||||
with_prepared_anchor(0), cleaned(0), stabilized(0),
|
||||
with_recursive(recursive_fl)
|
||||
{ last_next= &first_elem; }
|
||||
{ }
|
||||
|
||||
/* Add a new element to the current with clause */
|
||||
bool add_with_element(With_element *elem)
|
||||
{
|
||||
elem->owner= this;
|
||||
elem->number= elements;
|
||||
elem->number= with_list.elements;
|
||||
elem->spec->with_element= elem;
|
||||
*last_next= elem;
|
||||
last_next= &elem->next_elem;
|
||||
elements++;
|
||||
with_list.link_in_list(elem, &elem->next);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -263,7 +291,7 @@ public:
|
||||
|
||||
With_clause *pop() { return embedding_with_clause; }
|
||||
|
||||
bool check_dependencies(THD *thd);
|
||||
bool check_dependencies();
|
||||
|
||||
bool check_anchors();
|
||||
|
||||
@@ -283,7 +311,7 @@ public:
|
||||
|
||||
friend
|
||||
bool
|
||||
check_dependencies_in_with_clauses(THD *thd, With_clause *with_clauses_list);
|
||||
check_dependencies_in_with_clauses(With_clause *with_clauses_list);
|
||||
};
|
||||
|
||||
inline
|
||||
@@ -321,16 +349,18 @@ void With_element::mark_as_cleaned()
|
||||
|
||||
|
||||
inline
|
||||
void With_element::reset_for_exec()
|
||||
void With_element::reset_recursive_for_exec()
|
||||
{
|
||||
DBUG_ASSERT(is_recursive);
|
||||
level= 0;
|
||||
owner->with_prepared_anchor&= ~mutually_recursive;
|
||||
owner->cleaned&= ~get_elem_map();
|
||||
first_rec_table_to_update= NULL;
|
||||
cleanup_stabilized();
|
||||
rec_result->first_rec_table_to_update= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
void With_element::cleanup_stabilized()
|
||||
{
|
||||
@@ -365,7 +395,7 @@ void With_element::prepare_for_next_iteration()
|
||||
With_element *with_elem= this;
|
||||
while ((with_elem= with_elem->get_next_mutually_recursive()) != this)
|
||||
{
|
||||
TABLE *rec_table= with_elem->first_rec_table_to_update;
|
||||
TABLE *rec_table= with_elem->rec_result->first_rec_table_to_update;
|
||||
if (rec_table)
|
||||
rec_table->reginfo.join_tab->preread_init_done= false;
|
||||
}
|
||||
|
@@ -1109,7 +1109,7 @@ public:
|
||||
}
|
||||
With_element *find_table_def_in_with_clauses(TABLE_LIST *table);
|
||||
bool check_unrestricted_recursive(bool only_standards_compliant);
|
||||
void check_subqueries_with_recursive_references();
|
||||
bool check_subqueries_with_recursive_references();
|
||||
|
||||
List<Window_spec> window_specs;
|
||||
void prepare_add_window_spec(THD *thd);
|
||||
@@ -2475,7 +2475,7 @@ struct LEX: public Query_tables_list
|
||||
SELECT_LEX *all_selects_list;
|
||||
/* current with clause in parsing if any, otherwise 0*/
|
||||
With_clause *curr_with_clause;
|
||||
/* pointer to the first with clause in the current statemant */
|
||||
/* pointer to the first with clause in the current statement */
|
||||
With_clause *with_clauses_list;
|
||||
/*
|
||||
(*with_clauses_list_last_next) contains a pointer to the last
|
||||
|
@@ -6233,7 +6233,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
|
||||
new (thd->mem_root) Item_int(thd,
|
||||
(ulonglong) thd->variables.select_limit);
|
||||
}
|
||||
if (check_dependencies_in_with_clauses(thd, lex->with_clauses_list))
|
||||
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
|
||||
return 1;
|
||||
|
||||
if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0)))
|
||||
|
@@ -1509,7 +1509,7 @@ static int mysql_test_select(Prepared_statement *stmt,
|
||||
lex->select_lex.context.resolve_in_select_list= TRUE;
|
||||
|
||||
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
|
||||
if (check_dependencies_in_with_clauses(thd,lex->with_clauses_list))
|
||||
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
|
||||
goto error;
|
||||
if (tables)
|
||||
{
|
||||
|
@@ -1231,8 +1231,8 @@ bool st_select_lex_unit::exec_recursive()
|
||||
{
|
||||
saved_error=
|
||||
incr_table->insert_all_rows_into(thd, rec_table, !is_unrestricted);
|
||||
if (!with_element->first_rec_table_to_update)
|
||||
with_element->first_rec_table_to_update= rec_table;
|
||||
if (!with_element->rec_result->first_rec_table_to_update)
|
||||
with_element->rec_result->first_rec_table_to_update= rec_table;
|
||||
if (with_element->level == 1)
|
||||
rec_table->reginfo.join_tab->preread_init_done= true;
|
||||
}
|
||||
@@ -1258,13 +1258,6 @@ bool st_select_lex_unit::cleanup()
|
||||
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
|
||||
error|= sl->cleanup();
|
||||
|
||||
if (union_result && with_element && with_element->is_recursive)
|
||||
{
|
||||
((select_union_recursive *) union_result)->cleanup();
|
||||
delete union_result;
|
||||
union_result= 0;
|
||||
}
|
||||
|
||||
if (fake_select_lex)
|
||||
{
|
||||
error|= fake_select_lex->cleanup();
|
||||
@@ -1289,9 +1282,18 @@ bool st_select_lex_unit::cleanup()
|
||||
}
|
||||
|
||||
if (with_element && with_element->is_recursive)
|
||||
{
|
||||
if (union_result )
|
||||
{
|
||||
((select_union_recursive *) union_result)->cleanup();
|
||||
delete union_result;
|
||||
union_result= 0;
|
||||
}
|
||||
with_element->mark_as_cleaned();
|
||||
|
||||
if (union_result && !(with_element &&with_element->is_recursive))
|
||||
}
|
||||
else
|
||||
{
|
||||
if (union_result)
|
||||
{
|
||||
delete union_result;
|
||||
union_result=0; // Safety
|
||||
@@ -1299,6 +1301,7 @@ bool st_select_lex_unit::cleanup()
|
||||
free_tmp_table(thd, table);
|
||||
table= 0; // Safety
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
@@ -1325,7 +1328,7 @@ void st_select_lex_unit::reinit_exec_mechanism()
|
||||
}
|
||||
#endif
|
||||
if (with_element && with_element->is_recursive)
|
||||
with_element->reset_for_exec();
|
||||
with_element->reset_recursive_for_exec();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -430,7 +430,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
|
||||
lex->link_first_table_back(view, link_to_local);
|
||||
view->open_type= OT_BASE_ONLY;
|
||||
|
||||
if (check_dependencies_in_with_clauses(thd, lex->with_clauses_list))
|
||||
if (check_dependencies_in_with_clauses(lex->with_clauses_list))
|
||||
{
|
||||
res= TRUE;
|
||||
goto err;
|
||||
@@ -1390,7 +1390,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
|
||||
TABLE_LIST *tbl;
|
||||
Security_context *security_ctx= 0;
|
||||
|
||||
if (check_dependencies_in_with_clauses(thd, thd->lex->with_clauses_list))
|
||||
if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
|
@@ -1857,7 +1857,8 @@ struct TABLE_LIST
|
||||
derived tables. Use TABLE_LIST::is_anonymous_derived_table().
|
||||
*/
|
||||
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
|
||||
With_element *with; /* With element of with_table */
|
||||
With_element *with; /* With element defining this table (if any) */
|
||||
/* Bitmap of the defining with element */
|
||||
table_map with_internal_reference_map;
|
||||
bool block_handle_derived;
|
||||
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
|
||||
|
Reference in New Issue
Block a user