2015-12-17 21:52:14 +01:00
|
|
|
#ifndef SQL_CTE_INCLUDED
|
|
|
|
#define SQL_CTE_INCLUDED
|
|
|
|
#include "sql_list.h"
|
|
|
|
#include "sql_lex.h"
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
class select_union;
|
2016-05-24 20:29:52 +02:00
|
|
|
struct st_unit_ctxt_elem;
|
2015-12-17 21:52:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
@class With_clause
|
|
|
|
@brief Set of with_elements
|
|
|
|
|
|
|
|
It has a reference to the first with element from this with clause.
|
|
|
|
This reference allows to navigate through all the elements of the with clause.
|
|
|
|
It contains a reference to the unit to which this with clause is attached.
|
|
|
|
It also contains a flag saying whether this with clause was specified as recursive.
|
|
|
|
*/
|
|
|
|
|
|
|
|
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
|
|
|
|
uint number; // number of the element in the with clause (starting from 0)
|
2016-05-09 22:39:10 +02:00
|
|
|
table_map elem_map; // The map where with only one 1 set in this->number
|
2015-12-17 21:52:14 +01:00
|
|
|
/*
|
2016-05-09 22:39:10 +02:00
|
|
|
The map base_dep_map has 1 in the i-th position if the query that
|
|
|
|
specifies this with element contains a reference to the with element number i
|
2015-12-17 21:52:14 +01:00
|
|
|
in the query FROM list.
|
2016-05-09 22:39:10 +02:00
|
|
|
(In this case this with element depends directly on the i-th with element.)
|
2015-12-17 21:52:14 +01:00
|
|
|
*/
|
2016-05-09 22:39:10 +02:00
|
|
|
table_map base_dep_map;
|
|
|
|
/*
|
|
|
|
The map derived_dep_map has 1 in i-th position if this with element depends
|
|
|
|
directly or indirectly from the i-th with element.
|
|
|
|
*/
|
|
|
|
table_map derived_dep_map;
|
2016-05-19 21:07:53 +02:00
|
|
|
table_map sq_dep_map;
|
2016-05-09 22:39:10 +02:00
|
|
|
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;
|
2016-06-26 06:38:40 +02:00
|
|
|
With_element *next_mutually_recursive;
|
2015-12-17 21:52:14 +01:00
|
|
|
/*
|
|
|
|
Total number of references to this element in the FROM lists of
|
|
|
|
the queries that are in the scope of the element (including
|
|
|
|
subqueries and specifications of other with elements).
|
|
|
|
*/
|
|
|
|
uint references;
|
|
|
|
/*
|
|
|
|
Unparsed specification of the query that specifies this element.
|
|
|
|
It used to build clones of the specification if they are needed.
|
|
|
|
*/
|
|
|
|
LEX_STRING unparsed_spec;
|
|
|
|
|
|
|
|
/* Return the map where 1 is set only in the position for this element */
|
|
|
|
table_map get_elem_map() { return 1 << number; }
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
TABLE *table;
|
|
|
|
|
2015-12-17 21:52:14 +01:00
|
|
|
public:
|
|
|
|
/*
|
|
|
|
The name of the table introduced by this with elememt. The name
|
|
|
|
can be used in FROM lists of the queries in the scope of the element.
|
|
|
|
*/
|
|
|
|
LEX_STRING *query_name;
|
|
|
|
/*
|
|
|
|
Optional list of column names to name the columns of the table introduced
|
|
|
|
by this with element. It is used in the case when the names are not
|
|
|
|
inherited from the query that specified the table. Otherwise the list is
|
|
|
|
always empty.
|
|
|
|
*/
|
|
|
|
List <LEX_STRING> column_list;
|
|
|
|
/* The query that specifies the table introduced by this with element */
|
|
|
|
st_select_lex_unit *spec;
|
|
|
|
/*
|
|
|
|
Set to true is recursion is used (directly or indirectly)
|
|
|
|
for the definition of this element
|
|
|
|
*/
|
|
|
|
bool is_recursive;
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
bool with_anchor;
|
|
|
|
|
|
|
|
st_select_lex *first_recursive;
|
|
|
|
|
2016-06-08 00:01:34 +02:00
|
|
|
/* The number of the last performed iteration for recursive table */
|
2016-05-09 22:39:10 +02:00
|
|
|
uint level;
|
|
|
|
|
|
|
|
select_union_recursive *rec_result;
|
2016-05-12 22:23:12 +02:00
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
TABLE *result_table;
|
2016-06-26 06:38:40 +02:00
|
|
|
|
|
|
|
TABLE *first_rec_table_to_update;
|
2016-05-09 22:39:10 +02:00
|
|
|
|
2016-06-06 19:01:16 +02:00
|
|
|
|
2015-12-17 21:52:14 +01:00
|
|
|
With_element(LEX_STRING *name,
|
|
|
|
List <LEX_STRING> list,
|
|
|
|
st_select_lex_unit *unit)
|
2016-05-09 22:39:10 +02:00
|
|
|
: next_elem(NULL), base_dep_map(0), derived_dep_map(0),
|
2016-06-26 06:38:40 +02:00
|
|
|
sq_dep_map(0), work_dep_map(0), mutually_recursive(0),
|
|
|
|
next_mutually_recursive(NULL),
|
2016-05-09 22:39:10 +02:00
|
|
|
references(0), table(NULL),
|
2015-12-17 21:52:14 +01:00
|
|
|
query_name(name), column_list(list), spec(unit),
|
2016-05-09 22:39:10 +02:00
|
|
|
is_recursive(false), with_anchor(false),
|
2016-06-26 06:38:40 +02:00
|
|
|
level(0), rec_result(NULL), result_table(NULL),
|
|
|
|
first_rec_table_to_update(NULL)
|
2016-05-12 22:23:12 +02:00
|
|
|
{}
|
2016-05-09 22:39:10 +02:00
|
|
|
|
|
|
|
bool check_dependencies_in_spec(THD *thd);
|
|
|
|
|
2016-05-24 20:29:52 +02:00
|
|
|
void check_dependencies_in_select(st_select_lex *sl, st_unit_ctxt_elem *ctxt,
|
|
|
|
bool in_subq, table_map *dep_map);
|
2016-05-09 22:39:10 +02:00
|
|
|
|
2016-05-24 20:29:52 +02:00
|
|
|
void check_dependencies_in_unit(st_select_lex_unit *unit,
|
|
|
|
st_unit_ctxt_elem *ctxt,
|
|
|
|
bool in_subq,
|
|
|
|
table_map *dep_map);
|
|
|
|
|
|
|
|
void check_dependencies_in_with_clause(With_clause *with_clause,
|
|
|
|
st_unit_ctxt_elem *ctxt,
|
|
|
|
bool in_subq,
|
|
|
|
table_map *dep_map);
|
|
|
|
|
2015-12-17 21:52:14 +01:00
|
|
|
void set_dependency_on(With_element *with_elem)
|
2016-05-09 22:39:10 +02:00
|
|
|
{ base_dep_map|= with_elem->get_elem_map(); }
|
2015-12-17 21:52:14 +01:00
|
|
|
|
|
|
|
bool check_dependency_on(With_element *with_elem)
|
2016-05-09 22:39:10 +02:00
|
|
|
{ return base_dep_map & with_elem->get_elem_map(); }
|
2015-12-17 21:52:14 +01:00
|
|
|
|
|
|
|
bool set_unparsed_spec(THD *thd, char *spec_start, char *spec_end);
|
|
|
|
|
|
|
|
st_select_lex_unit *clone_parsed_spec(THD *thd, TABLE_LIST *with_table);
|
|
|
|
|
|
|
|
bool is_referenced() { return references != 0; }
|
|
|
|
|
|
|
|
void inc_references() { references++; }
|
|
|
|
|
2016-02-17 23:30:25 +01:00
|
|
|
bool rename_columns_of_derived_unit(THD *thd, st_select_lex_unit *unit);
|
|
|
|
|
2015-12-17 21:52:14 +01:00
|
|
|
bool prepare_unreferenced(THD *thd);
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
bool check_unrestricted_recursive(st_select_lex *sel,
|
|
|
|
table_map &unrestricted,
|
|
|
|
table_map &encountered);
|
|
|
|
|
2016-05-24 20:29:52 +02:00
|
|
|
void print(String *str, enum_query_type query_type);
|
|
|
|
|
|
|
|
With_clause *get_owner() { return owner; }
|
|
|
|
|
|
|
|
bool contains_sq_with_recursive_reference()
|
|
|
|
{ return sq_dep_map & mutually_recursive; }
|
|
|
|
|
|
|
|
table_map get_mutually_recursive() { return mutually_recursive; }
|
2016-05-09 22:39:10 +02:00
|
|
|
|
2016-06-26 06:38:40 +02:00
|
|
|
With_element *get_next_mutually_recursive()
|
|
|
|
{ return next_mutually_recursive; }
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
void set_table(TABLE *tab) { table= tab; }
|
|
|
|
|
|
|
|
TABLE *get_table() { return table; }
|
|
|
|
|
|
|
|
bool is_anchor(st_select_lex *sel);
|
|
|
|
|
|
|
|
void move_anchors_ahead();
|
|
|
|
|
|
|
|
bool is_unrestricted();
|
|
|
|
|
|
|
|
bool is_with_prepared_anchor();
|
|
|
|
|
|
|
|
void mark_as_with_prepared_anchor();
|
|
|
|
|
|
|
|
bool is_cleaned();
|
|
|
|
|
|
|
|
void mark_as_cleaned();
|
|
|
|
|
2016-05-12 22:23:12 +02:00
|
|
|
void reset_for_exec();
|
2016-05-09 22:39:10 +02:00
|
|
|
|
2016-06-06 19:01:16 +02:00
|
|
|
void cleanup_stabilized();
|
|
|
|
|
|
|
|
void set_as_stabilized();
|
|
|
|
|
|
|
|
bool is_stabilized();
|
|
|
|
|
|
|
|
bool all_are_stabilized();
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
void set_result_table(TABLE *tab) { result_table= tab; }
|
2015-12-17 21:52:14 +01:00
|
|
|
|
|
|
|
friend class With_clause;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@class With_element
|
|
|
|
@brief Definition of a CTE table
|
|
|
|
|
|
|
|
It contains a reference to the name of the table introduced by this with element,
|
|
|
|
and a reference to the unit that specificies this table. Also it contains
|
|
|
|
a reference to the with clause to which this element belongs to.
|
|
|
|
*/
|
|
|
|
|
|
|
|
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 with clause immediately containing this with clause if there is any,
|
|
|
|
otherwise NULL. Now used only at parsing.
|
|
|
|
*/
|
|
|
|
With_clause *embedding_with_clause;
|
|
|
|
/*
|
|
|
|
The next with the clause of the chain of with clauses encountered
|
|
|
|
in the current statement
|
|
|
|
*/
|
|
|
|
With_clause *next_with_clause;
|
|
|
|
/* Set to true if dependencies between with elements have been checked */
|
|
|
|
bool dependencies_are_checked;
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
table_map unrestricted;
|
|
|
|
table_map with_prepared_anchor;
|
|
|
|
table_map cleaned;
|
2016-06-06 19:01:16 +02:00
|
|
|
table_map stabilized;
|
2016-05-09 22:39:10 +02:00
|
|
|
|
2015-12-17 21:52:14 +01:00
|
|
|
public:
|
|
|
|
/* If true the specifier RECURSIVE is present in the with clause */
|
|
|
|
bool with_recursive;
|
|
|
|
|
|
|
|
With_clause(bool recursive_fl, With_clause *emb_with_clause)
|
|
|
|
: owner(NULL), first_elem(NULL), elements(0),
|
|
|
|
embedding_with_clause(emb_with_clause), next_with_clause(NULL),
|
2016-05-09 22:39:10 +02:00
|
|
|
dependencies_are_checked(false),
|
2016-06-06 19:01:16 +02:00
|
|
|
unrestricted(0), with_prepared_anchor(0), cleaned(0),
|
2016-06-26 06:38:40 +02:00
|
|
|
stabilized(0),
|
2015-12-17 21:52:14 +01:00
|
|
|
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;
|
2016-05-24 20:29:52 +02:00
|
|
|
elem->spec->with_element= elem;
|
2015-12-17 21:52:14 +01:00
|
|
|
*last_next= elem;
|
|
|
|
last_next= &elem->next_elem;
|
|
|
|
elements++;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add this with clause to the list of with clauses used in the statement */
|
|
|
|
void add_to_list(With_clause ** &last_next)
|
|
|
|
{
|
|
|
|
*last_next= this;
|
|
|
|
last_next= &this->next_with_clause;
|
|
|
|
}
|
|
|
|
|
2016-05-24 20:29:52 +02:00
|
|
|
void set_owner(st_select_lex_unit *unit) { owner= unit; }
|
|
|
|
|
2015-12-17 21:52:14 +01:00
|
|
|
With_clause *pop() { return embedding_with_clause; }
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
bool check_dependencies(THD *thd);
|
|
|
|
|
|
|
|
bool check_anchors();
|
|
|
|
|
|
|
|
void move_anchors_ahead();
|
2015-12-17 21:52:14 +01:00
|
|
|
|
2016-05-24 20:29:52 +02:00
|
|
|
With_element *find_table_def(TABLE_LIST *table, With_element *barrier);
|
2015-12-17 21:52:14 +01:00
|
|
|
|
|
|
|
With_element *find_table_def_in_with_clauses(TABLE_LIST *table);
|
|
|
|
|
|
|
|
bool prepare_unreferenced_elements(THD *thd);
|
|
|
|
|
2016-05-24 20:29:52 +02:00
|
|
|
void add_unrestricted(table_map map) { unrestricted|= map; }
|
|
|
|
|
2015-12-17 21:52:14 +01:00
|
|
|
void print(String *str, enum_query_type query_type);
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
friend class With_element;
|
|
|
|
|
|
|
|
friend
|
2016-05-19 21:07:53 +02:00
|
|
|
bool
|
|
|
|
check_dependencies_in_with_clauses(THD *thd, With_clause *with_clauses_list);
|
2015-12-17 21:52:14 +01:00
|
|
|
};
|
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
inline
|
|
|
|
bool With_element::is_unrestricted()
|
|
|
|
{
|
|
|
|
return owner->unrestricted & get_elem_map();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
|
|
|
|
|
|
|
bool With_element::is_with_prepared_anchor()
|
|
|
|
{
|
|
|
|
return owner->with_prepared_anchor & get_elem_map();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
|
|
|
void With_element::mark_as_with_prepared_anchor()
|
|
|
|
{
|
|
|
|
owner->with_prepared_anchor|= mutually_recursive;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline
|
|
|
|
bool With_element::is_cleaned()
|
|
|
|
{
|
|
|
|
return owner->cleaned & get_elem_map();
|
|
|
|
}
|
|
|
|
|
2016-06-06 19:01:16 +02:00
|
|
|
|
2016-05-09 22:39:10 +02:00
|
|
|
inline
|
|
|
|
void With_element::mark_as_cleaned()
|
|
|
|
{
|
|
|
|
owner->cleaned|= get_elem_map();
|
|
|
|
}
|
2015-12-17 21:52:14 +01:00
|
|
|
|
2016-05-12 22:23:12 +02:00
|
|
|
|
|
|
|
inline
|
|
|
|
void With_element::reset_for_exec()
|
|
|
|
{
|
|
|
|
level= 0;
|
|
|
|
owner->with_prepared_anchor&= ~mutually_recursive;
|
2016-06-06 19:01:16 +02:00
|
|
|
owner->cleaned&= ~get_elem_map();
|
2016-06-26 06:38:40 +02:00
|
|
|
first_rec_table_to_update= NULL;
|
2016-06-06 19:01:16 +02:00
|
|
|
cleanup_stabilized();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline
|
|
|
|
void With_element::cleanup_stabilized()
|
|
|
|
{
|
|
|
|
owner->stabilized&= ~mutually_recursive;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline
|
|
|
|
void With_element::set_as_stabilized()
|
|
|
|
{
|
|
|
|
owner->stabilized|= get_elem_map();
|
2016-05-12 22:23:12 +02:00
|
|
|
}
|
|
|
|
|
2016-06-06 19:01:16 +02:00
|
|
|
|
|
|
|
inline
|
|
|
|
bool With_element::is_stabilized()
|
|
|
|
{
|
|
|
|
return owner->stabilized & get_elem_map();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline
|
|
|
|
bool With_element::all_are_stabilized()
|
|
|
|
{
|
|
|
|
return (owner->stabilized & mutually_recursive) == mutually_recursive;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-24 20:29:52 +02:00
|
|
|
inline
|
|
|
|
void st_select_lex_unit::set_with_clause(With_clause *with_cl)
|
|
|
|
{
|
|
|
|
with_clause= with_cl;
|
|
|
|
if (with_clause)
|
|
|
|
with_clause->set_owner(this);
|
|
|
|
}
|
|
|
|
|
2016-06-06 19:01:16 +02:00
|
|
|
|
2016-05-24 20:29:52 +02:00
|
|
|
inline
|
|
|
|
void st_select_lex::set_with_clause(With_clause *with_clause)
|
|
|
|
{
|
|
|
|
master_unit()->with_clause= with_clause;
|
|
|
|
if (with_clause)
|
|
|
|
with_clause->set_owner(master_unit());
|
|
|
|
}
|
2016-05-12 22:23:12 +02:00
|
|
|
|
2015-12-17 21:52:14 +01:00
|
|
|
#endif /* SQL_CTE_INCLUDED */
|