summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/sql_class.h21
-rw-r--r--sql/sql_cte.cc304
-rw-r--r--sql/sql_cte.h139
-rw-r--r--sql/sql_derived.cc79
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h13
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc8
-rw-r--r--sql/sql_union.cc253
-rw-r--r--sql/sql_yacc.yy17
-rw-r--r--sql/table.cc79
-rw-r--r--sql/table.h7
14 files changed, 856 insertions, 73 deletions
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 376c1eb9d0d..f2a5666f1b1 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7154,6 +7154,10 @@ ER_WRONG_ORDER_IN_WITH_CLAUSE
eng "The definition of the table '%s' refers to the table '%s' defined later in a non-recursive WITH clause"
ER_RECURSIVE_QUERY_IN_WITH_CLAUSE
eng "Recursive queries in WITH clause are not supported yet"
+ER_RECURSIVE_WITHOUT_ANCHORS
+ eng "No anchors for recursive WITH element '%s'"
+ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED
+ eng "Reference to recursive WITH table '%s' in materiazed derived"
#
# Internal errors, not used
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e0792a4059f..0100a9807f5 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4196,6 +4196,7 @@ protected:
/* Something used only by the parser: */
public:
select_result(THD *thd_arg): select_result_sink(thd_arg) {}
+ void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
virtual ~select_result() {};
/**
Change wrapped select_result.
@@ -4637,6 +4638,7 @@ public:
}
};
+
class select_union :public select_result_interceptor
{
public:
@@ -4674,6 +4676,25 @@ public:
};
+class select_union_recursive :public select_union
+{
+ public:
+ TABLE *incr_table;
+ List<TABLE> rec_tables;
+
+ select_union_recursive(THD *thd_arg):
+ select_union(thd_arg), incr_table(0) {};
+
+ int send_data(List<Item> &items);
+ bool create_result_table(THD *thd, List<Item> *column_types,
+ bool is_distinct, ulonglong options,
+ const char *alias,
+ bool bit_fields_as_long,
+ bool create_table,
+ bool keep_row_order= FALSE);
+ void cleanup();
+};
+
/**
UNION result that is passed directly to the receiving select_result
without filling a temporary table.
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index 77f0bcf04ba..04d53495400 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -21,14 +21,17 @@
true on failure
*/
-bool check_dependencies_in_with_clauses(With_clause *with_clauses_list)
+bool check_dependencies_in_with_clauses(THD *thd, 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())
+ if (with_clause->check_dependencies(thd))
return true;
+ if (with_clause->check_anchors())
+ return true;
+ with_clause->move_anchors_ahead();
}
return false;
}
@@ -57,7 +60,7 @@ bool check_dependencies_in_with_clauses(With_clause *with_clauses_list)
false otherwise
*/
-bool With_clause::check_dependencies()
+bool With_clause::check_dependencies(THD *thd)
{
if (dependencies_are_checked)
return false;
@@ -84,18 +87,23 @@ bool With_clause::check_dependencies()
return true;
}
}
- with_elem->check_dependencies_in_unit(with_elem->spec);
+ if (with_elem->check_dependencies_in_spec(thd))
+ 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)
+ 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)
{
table_map with_elem_map= with_elem->get_elem_map();
for (With_element *elem= first_elem; elem != NULL; elem= elem->next_elem)
{
- if (elem->dependency_map & with_elem_map)
- elem->dependency_map |= with_elem->dependency_map;
+ if (elem->derived_dep_map & with_elem_map)
+ elem->derived_dep_map |= with_elem->derived_dep_map;
}
}
@@ -107,7 +115,7 @@ bool With_clause::check_dependencies()
with_elem != NULL;
with_elem= with_elem->next_elem)
{
- if (with_elem->dependency_map & with_elem->get_elem_map())
+ if (with_elem->derived_dep_map & with_elem->get_elem_map())
with_elem->is_recursive= true;
}
for (With_element *with_elem= first_elem;
@@ -115,10 +123,12 @@ bool With_clause::check_dependencies()
with_elem= with_elem->next_elem)
{
if (with_elem->is_recursive)
- {
+ {
+#if 0
my_error(ER_RECURSIVE_QUERY_IN_WITH_CLAUSE, MYF(0),
with_elem->query_name->str);
return true;
+#endif
}
}
@@ -152,7 +162,39 @@ bool With_clause::check_dependencies()
}
-/**
+bool With_element::check_dependencies_in_spec(THD *thd)
+{
+ for (st_select_lex *sl= spec->first_select(); sl; sl= sl->next_select())
+ {
+ check_dependencies_in_select(sl, sl->with_dep);
+ base_dep_map|= sl->with_dep;
+ }
+ return false;
+}
+
+
+void With_element::check_dependencies_in_select(st_select_lex *sl, table_map &dep_map)
+{
+ for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local)
+ {
+ tbl->with_internal_reference_map= 0;
+ if (!tbl->with)
+ tbl->with= owner->find_table_def(tbl);
+ if (!tbl->with && tbl->select_lex)
+ tbl->with= tbl->select_lex->find_table_def_in_with_clauses(tbl);
+ if (tbl->with && tbl->with->owner== this->owner)
+ {
+ dep_map|= tbl->with->get_elem_map();
+ tbl->with_internal_reference_map= get_elem_map();
+ }
+ }
+ 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, dep_map);
+}
+
+
+ /**
@brief
Check dependencies on the sibling with tables used in the given unit
@@ -166,24 +208,102 @@ bool With_clause::check_dependencies()
dependency_map of this element.
*/
-void With_element::check_dependencies_in_unit(st_select_lex_unit *unit)
+void With_element::check_dependencies_in_unit(st_select_lex_unit *unit,
+ table_map &dep_map)
{
st_select_lex *sl= unit->first_select();
for (; sl; sl= sl->next_select())
{
- for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local)
+ check_dependencies_in_select(sl, dep_map);
+ }
+}
+
+
+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)
+ {
+ if (!with_elem->is_recursive)
+ continue;
+
+ 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)
{
- if (!tbl->with)
- tbl->with= owner->find_table_def(tbl);
- if (!tbl->with && tbl->select_lex)
- tbl->with= tbl->select_lex->find_table_def_in_with_clauses(tbl);
- if (tbl->with && tbl->with->owner== this->owner)
- set_dependency_on(tbl->with);
+ if (!elem->is_recursive)
+ continue;
+
+ if (elem == with_elem ||
+ ((elem->derived_dep_map & with_elem_map) &&
+ (with_elem_dep & elem->get_elem_map())))
+ {
+ with_elem->mutually_recursive|= elem->get_elem_map();
+ elem->mutually_recursive|= with_elem_map;
+ }
}
- 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);
+
+ for (st_select_lex *sl= with_elem->spec->first_select();
+ sl;
+ sl= sl->next_select())
+ {
+ if (!(with_elem->mutually_recursive & sl->with_dep))
+ {
+ with_elem->with_anchor= true;
+ break;
+ }
+ }
+ }
+
+ for (With_element *with_elem= first_elem;
+ with_elem != NULL;
+ with_elem= with_elem->next_elem)
+ {
+ if (!with_elem->is_recursive || with_elem->with_anchor)
+ 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 (elem->work_dep_map & with_elem_map)
+ elem->work_dep_map|= with_elem->work_dep_map;
+ }
+ }
+
+ 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())
+ {
+ my_error(ER_RECURSIVE_WITHOUT_ANCHORS, MYF(0),
+ with_elem->query_name->str);
+ return true;
+ }
+ }
+
+ return false;
}
@@ -438,8 +558,8 @@ With_element::rename_columns_of_derived_unit(THD *thd,
item->is_autogenerated_name= false;
}
}
-
- make_valid_column_names(thd, select->item_list);
+ else
+ make_valid_column_names(thd, select->item_list);
unit->columns_are_renamed= true;
@@ -486,6 +606,47 @@ 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);
+}
+
+
/**
@brief
Search for the definition of the given table referred in this select node
@@ -540,7 +701,7 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table)
bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem)
{
with= with_elem;
- if (!with_elem->is_referenced())
+ if (!with_elem->is_referenced() || with_elem->is_recursive)
derived= with_elem->spec;
else
{
@@ -553,6 +714,102 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem)
}
+bool TABLE_LIST::is_recursive_with_table()
+{
+ return with && with->is_recursive;
+}
+
+
+bool TABLE_LIST::is_with_table_recursive_reference()
+{
+ return (with_internal_reference_map &&
+ (with->mutually_recursive & with_internal_reference_map));
+}
+
+
+
+bool st_select_lex::check_unrestricted_recursive()
+{
+ With_element *with_elem= get_with_element();
+ if (!with_elem)
+ return false;
+ table_map unrestricted= 0;
+ table_map encountered= 0;
+ if (with_elem->check_unrestricted_recursive(this,
+ unrestricted,
+ encountered))
+ return true;
+ with_elem->owner->unrestricted|= unrestricted;
+ return false;
+}
+
+
+bool With_element::check_unrestricted_recursive(st_select_lex *sel,
+ table_map &unrestricted,
+ table_map &encountered)
+{
+ List_iterator<TABLE_LIST> ti(sel->leaf_tables);
+ TABLE_LIST *tbl;
+ while ((tbl= ti++))
+ {
+ if (tbl->get_unit() && !tbl->is_with_table())
+ {
+ st_select_lex_unit *unit= tbl->get_unit();
+ if (tbl->is_materialized_derived())
+ {
+ table_map dep_map;
+ check_dependencies_in_unit(unit, dep_map);
+ if (dep_map & get_elem_map())
+ {
+ my_error(ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED,
+ MYF(0), query_name->str);
+ return true;
+ }
+ }
+ if (check_unrestricted_recursive(unit->first_select(),
+ unrestricted,
+ encountered))
+ return true;
+ if (!(tbl->is_recursive_with_table() && unit->with_element->owner == owner))
+ continue;
+ With_element *with_elem= unit->with_element;
+ if (encountered & with_elem->get_elem_map())
+ unrestricted|= with_elem->mutually_recursive;
+ else
+ 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)
+ {
+ if (!with_elem->is_recursive && (unrestricted & with_elem->get_elem_map()))
+ continue;
+ if (encountered & with_elem->get_elem_map())
+ {
+ uint cnt= 0;
+ table_map mutually_recursive= with_elem->mutually_recursive;
+ for (table_map map= mutually_recursive >> with_elem->number;
+ map != 0;
+ map>>= 1)
+ {
+ if (map & 1)
+ {
+ if (cnt)
+ {
+ unrestricted|= with_elem->mutually_recursive;
+ break;
+ }
+ else
+ cnt++;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
/**
@brief
Print this with clause
@@ -602,3 +859,4 @@ void With_element::print(String *str, enum_query_type query_type)
str->append(')');
}
+
diff --git a/sql/sql_cte.h b/sql/sql_cte.h
index 0cbc9247af9..b559be93de5 100644
--- a/sql/sql_cte.h
+++ b/sql/sql_cte.h
@@ -4,6 +4,7 @@
#include "sql_lex.h"
class With_clause;
+class select_union;
/**
@class With_clause
@@ -21,13 +22,22 @@ 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)
+ table_map elem_map; // The map where with only one 1 set in this->number
/*
- The map dependency_map has 1 in the i-th position if the query that
- specifies this element contains a reference to the element number i
+ 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
in the query FROM list.
+ (In this case this with element depends directly on the i-th with element.)
*/
- table_map elem_map; // The map where with only one 1 set in this->number
- table_map dependency_map;
+ 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;
+ 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;
/*
Total number of references to this element in the FROM lists of
the queries that are in the scope of the element (including
@@ -43,6 +53,8 @@ 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
@@ -64,20 +76,40 @@ public:
*/
bool is_recursive;
+ bool with_anchor;
+
+ st_select_lex *first_recursive;
+
+ uint level;
+
+ select_union *partial_result;
+ select_union *final_result;
+ select_union_recursive *rec_result;
+ TABLE *result_table;
+
With_element(LEX_STRING *name,
List <LEX_STRING> list,
st_select_lex_unit *unit)
- : next_elem(NULL), dependency_map(0), references(0),
+ : next_elem(NULL), base_dep_map(0), derived_dep_map(0),
+ work_dep_map(0), mutually_recursive(0),
+ references(0), table(NULL),
query_name(name), column_list(list), spec(unit),
- is_recursive(false) {}
-
- void check_dependencies_in_unit(st_select_lex_unit *unit);
-
+ is_recursive(false), with_anchor(false),
+ partial_result(NULL), final_result(NULL),
+ rec_result(NULL), result_table(NULL)
+ { reset();}
+
+ bool check_dependencies_in_spec(THD *thd);
+
+ void check_dependencies_in_select(st_select_lex *sl, table_map &dep_map);
+
+ void check_dependencies_in_unit(st_select_lex_unit *unit, table_map &dep_map);
+
void set_dependency_on(With_element *with_elem)
- { dependency_map|= with_elem->get_elem_map(); }
+ { base_dep_map|= with_elem->get_elem_map(); }
bool check_dependency_on(With_element *with_elem)
- { return dependency_map & with_elem->get_elem_map(); }
+ { return base_dep_map & with_elem->get_elem_map(); }
bool set_unparsed_spec(THD *thd, char *spec_start, char *spec_end);
@@ -91,9 +123,42 @@ public:
bool prepare_unreferenced(THD *thd);
- void print(String *str, enum_query_type query_type);
+ bool check_unrestricted_recursive(st_select_lex *sel,
+ table_map &unrestricted,
+ table_map &encountered);
+
+ void print(String *str, enum_query_type query_type);
+
+ 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();
+
+ void reset()
+ {
+ level= 0;
+ }
+
+ void set_result_table(TABLE *tab) { result_table= tab; }
friend class With_clause;
+ friend
+ bool st_select_lex::check_unrestricted_recursive();
+ friend
+ bool TABLE_LIST::is_with_table_recursive_reference();
};
@@ -126,6 +191,10 @@ private:
/* Set to true if dependencies between with elements have been checked */
bool dependencies_are_checked;
+ table_map unrestricted;
+ table_map with_prepared_anchor;
+ table_map cleaned;
+
public:
/* If true the specifier RECURSIVE is present in the with clause */
bool with_recursive;
@@ -133,7 +202,8 @@ public:
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),
- dependencies_are_checked(false),
+ dependencies_are_checked(false),
+ unrestricted(0), with_prepared_anchor(0), cleaned(0),
with_recursive(recursive_fl)
{ last_next= &first_elem; }
@@ -159,7 +229,11 @@ public:
With_clause *pop() { return embedding_with_clause; }
- bool check_dependencies();
+ bool check_dependencies(THD *thd);
+
+ bool check_anchors();
+
+ void move_anchors_ahead();
With_element *find_table_def(TABLE_LIST *table);
@@ -169,10 +243,45 @@ public:
void print(String *str, enum_query_type query_type);
+ friend class With_element;
+
+ friend
+ bool check_dependencies_in_with_clauses(THD *thd, With_clause *with_clauses_list);
friend
- bool check_dependencies_in_with_clauses(With_clause *with_clauses_list);
+ bool st_select_lex::check_unrestricted_recursive();
};
+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();
+}
+
+inline
+void With_element::mark_as_cleaned()
+{
+ owner->cleaned|= get_elem_map();
+}
#endif /* SQL_CTE_INCLUDED */
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 79e57cded81..63302c1c6db 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -30,6 +30,7 @@
#include "sql_base.h"
#include "sql_view.h" // check_duplicate_names
#include "sql_acl.h" // SELECT_ACL
+#include "sql_class.h"
#include "sql_cte.h"
typedef bool (*dt_processor)(THD *thd, LEX *lex, TABLE_LIST *derived);
@@ -627,6 +628,7 @@ bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived)
true Error
*/
+
bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
{
SELECT_LEX_UNIT *unit= derived->get_unit();
@@ -634,6 +636,34 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
bool res= FALSE;
DBUG_PRINT("enter", ("unit 0x%lx", (ulong) unit));
+ SELECT_LEX *first_select= unit->first_select();
+
+ if (unit->prepared && derived->is_recursive_with_table() &&
+ !derived->table)
+ {
+ if (!(derived->derived_result= new (thd->mem_root) select_union(thd)))
+ DBUG_RETURN(TRUE); // out of memory
+ thd->create_tmp_table_for_derived= TRUE;
+ if (!derived->table)
+ res= derived->derived_result->create_result_table(
+ thd, &unit->types, FALSE,
+ (first_select->options |
+ thd->variables.option_bits |
+ TMP_TABLE_ALL_COLUMNS),
+ derived->alias, FALSE, TRUE);
+ thd->create_tmp_table_for_derived= FALSE;
+
+ if (!res && !derived->table)
+ {
+ derived->derived_result->set_unit(unit);
+ derived->table= derived->derived_result->table;
+ if (derived->is_with_table_recursive_reference())
+ unit->with_element->rec_result->rec_tables.push_back(derived->table);
+ }
+ DBUG_ASSERT(derived->table || res);
+ goto exit;
+ }
+
// Skip already prepared views/DT
if (!unit || unit->prepared ||
(derived->merged_for_insert &&
@@ -642,16 +672,16 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
thd->lex->sql_command == SQLCOM_DELETE_MULTI))))
DBUG_RETURN(FALSE);
- SELECT_LEX *first_select= unit->first_select();
-
/* prevent name resolving out of derived table */
for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
{
sl->context.outer_context= 0;
- // Prepare underlying views/DT first.
- if ((res= sl->handle_derived(lex, DT_PREPARE)))
- goto exit;
-
+ if (!derived->is_with_table_recursive_reference())
+ {
+ // Prepare underlying views/DT first.
+ if ((res= sl->handle_derived(lex, DT_PREPARE)))
+ goto exit;
+ }
if (derived->outer_join && sl->first_cond_optimization)
{
/* Mark that table is part of OUTER JOIN and fields may be NULL */
@@ -697,19 +727,21 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
SELECT is last SELECT of UNION).
*/
thd->create_tmp_table_for_derived= TRUE;
- if (derived->derived_result->create_result_table(thd, &unit->types, FALSE,
- (first_select->options |
- thd->variables.option_bits |
- TMP_TABLE_ALL_COLUMNS),
- derived->alias,
- FALSE, FALSE))
+ if (!(derived->table) &&
+ derived->derived_result->create_result_table(thd, &unit->types, FALSE,
+ (first_select->options |
+ thd->variables.option_bits |
+ TMP_TABLE_ALL_COLUMNS),
+ derived->alias,
+ FALSE, FALSE, FALSE))
{
thd->create_tmp_table_for_derived= FALSE;
goto exit;
}
thd->create_tmp_table_for_derived= FALSE;
- derived->table= derived->derived_result->table;
+ if (!derived->table)
+ derived->table= derived->derived_result->table;
DBUG_ASSERT(derived->table);
if (derived->is_derived() && derived->is_merged_derived())
first_select->mark_as_belong_to_derived(derived);
@@ -756,8 +788,11 @@ exit:
}
#endif
/* Add new temporary table to list of open derived tables */
- table->next= thd->derived_tables;
- thd->derived_tables= table;
+ if (!derived->is_with_table_recursive_reference())
+ {
+ table->next= thd->derived_tables;
+ thd->derived_tables= table;
+ }
/* If table is used by a left join, mark that any column may be null */
if (derived->outer_join)
@@ -909,6 +944,14 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
SELECT_LEX_UNIT *unit= derived->get_unit();
bool res= FALSE;
+ if (derived->is_recursive_with_table() && unit->executed)
+ {
+ TABLE *src= unit->with_element->rec_result->table;
+ TABLE *dest= derived->table;
+ res= src->insert_all_rows_into(thd, dest, true);
+ DBUG_RETURN(res);
+ }
+
if (unit->executed && !unit->uncacheable && !unit->describe)
DBUG_RETURN(FALSE);
/*check that table creation passed without problems. */
@@ -919,6 +962,8 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
if (unit->is_union())
{
// execute union without clean up
+ if (derived->is_recursive_with_table())
+ unit->with_element->set_result_table(derived->table);
res= unit->exec();
}
else
@@ -948,7 +993,9 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
res= TRUE;
unit->executed= TRUE;
}
- if (res || !lex->describe)
+ if (res ||
+ (!lex->describe &&
+ !(unit->with_element && unit->with_element->is_recursive)))
unit->cleanup();
lex->current_select= save_current_select;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index de345b4dd1c..42058319fc9 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2172,6 +2172,7 @@ void st_select_lex::init_select()
m_non_agg_field_used= false;
m_agg_func_used= false;
name_visibility_map= 0;
+ with_dep= 0;
join= 0;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 10247bd33a2..09463635b94 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -546,6 +546,14 @@ public:
LEX_STRING *option= 0);
virtual void set_lock_for_tables(thr_lock_type lock_type) {}
void set_slave(st_select_lex_node *slave_arg) { slave= slave_arg; }
+ void move_node(st_select_lex_node *where_to_move)
+ {
+ if (where_to_move == this)
+ return;
+ *prev= next;
+ *where_to_move->prev= this;
+ next= where_to_move;
+ }
st_select_lex_node *insert_chain_before(st_select_lex_node **ptr_pos_to_insert,
st_select_lex_node *end_chain_node);
friend class st_select_lex_unit;
@@ -695,6 +703,7 @@ public:
bool prepare(THD *thd, select_result *result, ulong additional_options);
bool optimize();
bool exec();
+ bool exec_recursive();
bool cleanup();
inline void unclean() { cleaned= 0; }
void reinit_exec_mechanism();
@@ -911,6 +920,8 @@ public:
/* namp of nesting SELECT visibility (for aggregate functions check) */
nesting_map name_visibility_map;
+ table_map with_dep;
+
void init_query();
void init_select();
st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; }
@@ -1097,6 +1108,8 @@ public:
return master_unit()->with_element;
}
With_element *find_table_def_in_with_clauses(TABLE_LIST *table);
+ bool check_unrestricted_recursive();
+
List<Window_spec> window_specs;
void prepare_add_window_spec(THD *thd);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a6bb89f05df..ecf27bd1239 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -6215,7 +6215,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(lex->with_clauses_list))
+ if (check_dependencies_in_with_clauses(thd, lex->with_clauses_list))
return 1;
if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0)))
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 2d6a7302afc..453ca936a88 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -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(lex->with_clauses_list))
+ if (check_dependencies_in_with_clauses(thd,lex->with_clauses_list))
goto error;
if (tables)
{
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 6c4d2e1fc9c..0a961b4a53a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3669,6 +3669,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
s->checked_keys.init();
s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
+ s->tab_list= tables;
table->pos_in_table_list= tables;
error= tables->fetch_number_of_rows();
set_statistics_for_table(join->thd, table);
@@ -11423,6 +11424,11 @@ bool error_if_full_join(JOIN *join)
void JOIN_TAB::cleanup()
{
DBUG_ENTER("JOIN_TAB::cleanup");
+
+ if (tab_list && tab_list->is_with_table_recursive_reference() &&
+ tab_list->with->is_cleaned())
+ DBUG_VOID_RETURN;
+
DBUG_PRINT("enter", ("tab: %p table %s.%s",
this,
(table ? table->s->db.str : "?"),
@@ -11592,7 +11598,7 @@ bool JOIN_TAB::preread_init()
}
/* Materialize derived table/view. */
- if (!derived->get_unit()->executed &&
+ if ((!derived->get_unit()->executed || derived->is_recursive_with_table()) &&
mysql_handle_single_derived(join->thd->lex,
derived, DT_CREATE | DT_FILL))
return TRUE;
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 87b836f40d9..ac582c115d8 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -28,6 +28,8 @@
#include "sql_cursor.h"
#include "sql_base.h" // fill_record
#include "filesort.h" // filesort_free_buffers
+#include "sql_view.h"
+#include "sql_cte.h"
bool mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option)
@@ -98,6 +100,26 @@ int select_union::send_data(List<Item> &values)
return 0;
}
+int select_union_recursive::send_data(List<Item> &values)
+{
+ int rc= select_union::send_data(values);
+
+ if (!write_err)
+ {
+ int err;
+ if ((err= incr_table->file->ha_write_tmp_row(table->record[0])))
+ {
+ bool is_duplicate;
+ rc= create_internal_tmp_table_from_heap(thd, incr_table,
+ tmp_table_param.start_recinfo,
+ &tmp_table_param.recinfo,
+ err, 1, &is_duplicate);
+ }
+ }
+
+ return rc;
+}
+
bool select_union::send_eof()
{
@@ -171,6 +193,61 @@ select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
return FALSE;
}
+bool
+select_union_recursive::create_result_table(THD *thd_arg,
+ List<Item> *column_types,
+ bool is_union_distinct,
+ ulonglong options,
+ const char *alias,
+ bool bit_fields_as_long,
+ bool create_table,
+ bool keep_row_order)
+{
+ if (select_union::create_result_table(thd_arg, column_types,
+ is_union_distinct, options,
+ alias, bit_fields_as_long,
+ create_table, keep_row_order))
+ return true;
+
+ if (! (incr_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
+ (ORDER*) 0, false, 1,
+ options, HA_POS_ERROR, alias,
+ !create_table, keep_row_order)))
+ return true;
+
+ incr_table->keys_in_use_for_query.clear_all();
+ for (uint i=0; i < table->s->fields; i++)
+ incr_table->field[i]->flags &= ~PART_KEY_FLAG;
+
+ if (create_table)
+ {
+ incr_table->file->extra(HA_EXTRA_WRITE_CACHE);
+ incr_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ }
+
+ TABLE *rec_table= 0;
+ if (! (rec_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
+ (ORDER*) 0, false, 1,
+ options, HA_POS_ERROR, alias,
+ !create_table, keep_row_order)))
+ return true;
+
+ rec_table->keys_in_use_for_query.clear_all();
+ for (uint i=0; i < table->s->fields; i++)
+ rec_table->field[i]->flags &= ~PART_KEY_FLAG;
+
+ if (create_table)
+ {
+ rec_table->file->extra(HA_EXTRA_WRITE_CACHE);
+ rec_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ }
+
+ if (rec_tables.push_back(rec_table))
+ return true;
+
+ return false;
+}
+
/**
Reset and empty the temporary table that stores the materialized query
@@ -187,6 +264,29 @@ void select_union::cleanup()
}
+void select_union_recursive::cleanup()
+{
+ select_union::cleanup();
+ free_tmp_table(thd, table);
+
+ incr_table->file->extra(HA_EXTRA_RESET_STATE);
+ incr_table->file->ha_delete_all_rows();
+ //free_io_cache(incr_table);
+ //filesort_free_buffers(incr_table,0);
+ free_tmp_table(thd, incr_table);
+
+ List_iterator<TABLE> it(rec_tables);
+ TABLE *tab;
+ while ((tab= it++))
+ {
+ tab->file->extra(HA_EXTRA_RESET_STATE);
+ tab->file->ha_delete_all_rows();
+ //free_io_cache(tab);
+ //filesort_free_buffers(tab,0);
+ free_tmp_table(thd, tab);
+ }
+}
+
/**
Replace the current result with new_result and prepare it.
@@ -332,11 +432,14 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg,
}
+
+
bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
ulong additional_options)
{
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
SELECT_LEX *sl, *first_sl= first_select();
+ bool is_recursive= with_element && with_element->is_recursive;
select_result *tmp_result;
bool is_union_select;
bool instantiate_tmp_table= false;
@@ -404,8 +507,15 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
else
{
- if (!(tmp_result= union_result=
- new (thd_arg->mem_root) select_union(thd_arg)))
+ if (!is_recursive)
+ union_result= new (thd_arg->mem_root) select_union(thd_arg);
+ else
+ {
+ with_element->rec_result=
+ new (thd_arg->mem_root) select_union_recursive(thd_arg);
+ union_result= with_element->rec_result;
+ }
+ if (!(tmp_result= union_result))
goto err; /* purecov: inspected */
instantiate_tmp_table= true;
}
@@ -414,7 +524,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
tmp_result= sel_result;
sl->context.resolve_in_select_list= TRUE;
-
+
for (;sl; sl= sl->next_select())
{
bool can_skip_order_by;
@@ -477,6 +587,13 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
types= first_sl->item_list;
else if (sl == first_sl)
{
+ if (is_recursive)
+ {
+ if (derived->with->rename_columns_of_derived_unit(thd, this))
+ goto err;
+ if (check_duplicate_names(thd, sl->item_list, 0))
+ goto err;
+ }
types.empty();
List_iterator_fast<Item> it(sl->item_list);
Item *item_tmp;
@@ -489,6 +606,23 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (thd_arg->is_fatal_error)
goto err; // out of memory
+
+ if (is_recursive)
+ {
+
+ ulonglong create_options;
+ create_options= (first_sl->options | thd_arg->variables.option_bits |
+ TMP_TABLE_ALL_COLUMNS);
+ if (union_result->create_result_table(thd, &types,
+ MY_TEST(union_distinct),
+ create_options, "", false,
+ instantiate_tmp_table, false))
+ goto err;
+ if (!derived->table)
+ derived->table= derived->derived_result->table=
+ with_element->rec_result->rec_tables.head();
+ with_element->mark_as_with_prepared_anchor();
+ }
}
else
{
@@ -507,6 +641,10 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
DBUG_RETURN(TRUE);
}
}
+ if (with_element && !with_element->is_anchor(sl))
+ {
+ sl->uncacheable|= UNCACHEABLE_UNITED;
+ }
}
/*
@@ -580,9 +718,11 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (global_parameters()->ftfunc_list->elements)
create_options= create_options | TMP_TABLE_FORCE_MYISAM;
- if (union_result->create_result_table(thd, &types, MY_TEST(union_distinct),
- create_options, "", false,
- instantiate_tmp_table))
+
+ if (!is_recursive &&
+ union_result->create_result_table(thd, &types, MY_TEST(union_distinct),
+ create_options, "", false,
+ instantiate_tmp_table, false))
goto err;
if (fake_select_lex && !fake_select_lex->first_cond_optimization)
{
@@ -784,6 +924,12 @@ bool st_select_lex_unit::exec()
if (saved_error)
DBUG_RETURN(saved_error);
+ if (with_element && with_element->is_recursive && !describe)
+ {
+ saved_error= exec_recursive();
+ DBUG_RETURN(saved_error);
+ }
+
if (uncacheable || !item || !item->assigned() || describe)
{
if (!fake_select_lex)
@@ -1009,6 +1155,89 @@ err:
}
+
+bool st_select_lex_unit::exec_recursive()
+{
+ st_select_lex *lex_select_save= thd->lex->current_select;
+ st_select_lex *first_recursive_sel= with_element->first_recursive;
+ TABLE *incr_table= with_element->rec_result->incr_table;
+ TABLE *result_table= with_element->result_table;
+ ha_rows last_union_records= 0;
+ ha_rows examined_rows= 0;
+ bool unrestricted= with_element->is_unrestricted();
+ bool is_stabilized= false;
+ DBUG_ENTER("st_select_lex_unit::exec_recursive");
+ bool with_anchor= with_element->with_anchor;
+ st_select_lex *first_sl= first_select();
+ st_select_lex *barrier= with_anchor ? first_recursive_sel : NULL;
+ List_iterator_fast<TABLE> li(with_element->rec_result->rec_tables);
+ TABLE *rec_table;
+
+ do
+ {
+ if ((saved_error= incr_table->file->ha_delete_all_rows()))
+ goto err;
+
+ for (st_select_lex *sl= first_sl ; sl != barrier; sl= sl->next_select())
+ {
+ thd->lex->current_select= sl;
+ sl->join->exec();
+ saved_error= sl->join->error;
+ if (!saved_error)
+ {
+ examined_rows+= thd->get_examined_row_count();
+ thd->set_examined_row_count(0);
+ if (union_result->flush())
+ {
+ thd->lex->current_select= lex_select_save;
+ DBUG_RETURN(1);
+ }
+ }
+ if (saved_error)
+ {
+ thd->lex->current_select= lex_select_save;
+ goto err;
+ }
+ }
+
+ if (with_element->level == 0)
+ {
+ first_sl= first_recursive_sel;
+ barrier= NULL;
+ }
+
+ table->file->info(HA_STATUS_VARIABLE);
+ if (table->file->stats.records == last_union_records)
+ {
+ is_stabilized= true;
+ }
+ else
+ {
+ last_union_records= table->file->stats.records;
+ with_element->level++;
+ }
+ li.rewind();
+ while ((rec_table= li++))
+ {
+ if ((saved_error= incr_table->insert_all_rows_into(thd, rec_table,
+ !unrestricted)))
+ goto err;
+ }
+ } while (!is_stabilized);
+
+ if ((saved_error= table->insert_all_rows_into(thd,
+ result_table,
+ true)))
+ goto err;
+
+ thd->lex->current_select= lex_select_save;
+err:
+ thd->lex->set_limit_rows_examined();
+ DBUG_RETURN(saved_error);
+
+}
+
+
bool st_select_lex_unit::cleanup()
{
int error= 0;
@@ -1023,6 +1252,13 @@ 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();
@@ -1046,7 +1282,10 @@ bool st_select_lex_unit::cleanup()
}
}
- if (union_result)
+ if (with_element && with_element->is_recursive)
+ with_element->mark_as_cleaned();
+
+ if (union_result && !(with_element->is_recursive))
{
delete union_result;
union_result=0; // Safety
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 04c1ba7e99a..0d83efcae04 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -978,6 +978,7 @@ bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
List<Item> *item_list;
List<Statement_information_item> *stmt_info_list;
List<String> *string_list;
+ List<LEX_STRING> *lex_str_list;
Statement_information_item *stmt_info_item;
String *string;
TABLE_LIST *table_list;
@@ -2053,6 +2054,8 @@ END_OF_INPUT
%type <lex_str_ptr> query_name
+%type <lex_str_list> opt_with_column_list
+
%%
@@ -14077,13 +14080,18 @@ with_list:
with_list_element:
query_name
opt_with_column_list
+ {
+ $2= new List<LEX_STRING> (Lex->with_column_list);
+ if ($2 == NULL)
+ MYSQL_YYABORT;
+ Lex->with_column_list.empty();
+ }
AS '(' remember_name subselect remember_end ')'
{
- With_element *elem= new With_element($1, Lex->with_column_list, $6->master_unit());
+ With_element *elem= new With_element($1, *$2, $7->master_unit());
if (elem == NULL || Lex->curr_with_clause->add_with_element(elem))
MYSQL_YYABORT;
- Lex->with_column_list.empty();
- if (elem->set_unparsed_spec(thd, $5+1, $7))
+ if (elem->set_unparsed_spec(thd, $6+1, $8))
MYSQL_YYABORT;
}
;
@@ -14091,8 +14099,9 @@ with_list_element:
opt_with_column_list:
/* empty */
- {}
+ { $$= NULL; }
| '(' with_column_list ')'
+ { $$= NULL; }
;
diff --git a/sql/table.cc b/sql/table.cc
index dc1730b5b6f..6109c16fb37 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -41,6 +41,7 @@
#include "mdl.h" // MDL_wait_for_graph_visitor
#include "sql_view.h"
#include "rpl_filter.h"
+#include "sql_cte.h"
/* INFORMATION_SCHEMA name */
LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")};
@@ -7089,7 +7090,7 @@ bool TABLE::validate_default_values_of_unset_fields(THD *thd) const
/*
We're here if:
- validate_value_in_record_with_warn() failed and
- strict mode converted WARN to ERROR
+ strict mo validate_default_values_of_unset_fieldsde converted WARN to ERROR
- or the connection was killed, or closed unexpectedly
*/
DBUG_RETURN(true);
@@ -7100,6 +7101,59 @@ bool TABLE::validate_default_values_of_unset_fields(THD *thd) const
}
+bool TABLE::insert_all_rows_into(THD *thd, TABLE *dest, bool with_cleanup)
+{
+ int write_err= 0;
+
+ DBUG_ENTER("TABLE::insert_all_rows_into");
+
+ if (with_cleanup)
+ {
+ if ((write_err= dest->file->ha_delete_all_rows()))
+ goto err;
+ }
+
+ if (file->indexes_are_disabled())
+ dest->file->ha_disable_indexes(HA_KEY_SWITCH_ALL);
+ file->ha_index_or_rnd_end();
+
+ if (file->ha_rnd_init_with_error(1))
+ DBUG_RETURN(1);
+
+ if (dest->no_rows)
+ dest->file->extra(HA_EXTRA_NO_ROWS);
+ else
+ {
+ /* update table->file->stats.records */
+ file->info(HA_STATUS_VARIABLE);
+ dest->file->ha_start_bulk_insert(file->stats.records);
+ }
+
+ while (!file->ha_rnd_next(dest->record[1]))
+ {
+ write_err= dest->file->ha_write_tmp_row(dest->record[1]);
+ if (write_err)
+ goto err;
+ if (thd->check_killed())
+ {
+ thd->send_kill_message();
+ goto err_killed;
+ }
+ }
+ if (!dest->no_rows && dest->file->ha_end_bulk_insert())
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ DBUG_PRINT("error",("Got error: %d",write_err));
+ file->print_error(write_err, MYF(0));
+err_killed:
+ (void) file->ha_rnd_end();
+ DBUG_RETURN(1);
+}
+
+
+
/*
@brief Reset const_table flag
@@ -7140,20 +7194,34 @@ void TABLE_LIST::reset_const_table()
bool TABLE_LIST::handle_derived(LEX *lex, uint phases)
{
- SELECT_LEX_UNIT *unit;
+ SELECT_LEX_UNIT *unit= get_unit();
DBUG_ENTER("handle_derived");
DBUG_PRINT("enter", ("phases: 0x%x", phases));
- if ((unit= get_unit()))
+
+ if (is_with_table_recursive_reference())
+ {
+ if (!(with->with_anchor || with->is_with_prepared_anchor()))
+ {
+ for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
+ if (sl->handle_derived(lex, phases))
+ DBUG_RETURN(TRUE);
+ }
+ else if (mysql_handle_single_derived(lex, this, phases))
+ DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
+ }
+
+ if (unit)
{
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
if (sl->handle_derived(lex, phases))
DBUG_RETURN(TRUE);
- DBUG_RETURN(mysql_handle_single_derived(lex, this, phases));
+ if (mysql_handle_single_derived(lex, this, phases))
+ DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
}
-
/**
@brief
Return unit of this derived table/view
@@ -7430,6 +7498,7 @@ bool TABLE_LIST::is_with_table()
return derived && derived->with_element;
}
+
uint TABLE_SHARE::actual_n_key_parts(THD *thd)
{
return use_ext_keys &&
diff --git a/sql/table.h b/sql/table.h
index a105df31e93..122b036cae5 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1416,6 +1416,8 @@ public:
inline Field **field_to_fill();
bool validate_default_values_of_unset_fields(THD *thd) const;
+
+ bool insert_all_rows_into(THD *thd, TABLE *dest, bool with_cleanup);
};
@@ -1856,6 +1858,8 @@ struct TABLE_LIST
*/
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
With_element *with; /* With element of with_table */
+ table_map with_internal_reference_map;
+ bool block_handle_derived;
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
st_select_lex *schema_select_lex;
/*
@@ -2227,6 +2231,9 @@ struct TABLE_LIST
return (derived_type & DTYPE_TABLE);
}
bool is_with_table();
+ bool is_recursive_with_table();
+ bool is_with_table_recursive_reference();
+
inline void set_view()
{
derived_type= DTYPE_VIEW;