diff options
Diffstat (limited to 'sql/sql_cte.cc')
-rw-r--r-- | sql/sql_cte.cc | 148 |
1 files changed, 112 insertions, 36 deletions
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 2e672591d09..e22aa1ebd6f 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -21,6 +21,7 @@ #include "sql_view.h" // for make_valid_column_names #include "sql_parse.h" #include "sql_select.h" +#include "sql_show.h" // append_definer, append_identifier /** @@ -170,9 +171,9 @@ bool LEX::resolve_references_to_cte(TABLE_LIST *tables, if (copy_db_to(&tbl->db)) return true; if (!(tbl->table_options & TL_OPTION_ALIAS)) - tbl->mdl_request.init(MDL_key::TABLE, tbl->db.str, - tbl->table_name.str, - tbl->mdl_type, MDL_TRANSACTION); + MDL_REQUEST_INIT(&tbl->mdl_request, MDL_key::TABLE, + tbl->db.str, tbl->table_name.str, + tbl->mdl_type, MDL_TRANSACTION); tbl->mdl_request.set_type((tbl->lock_type >= TL_WRITE_ALLOW_WRITE) ? MDL_SHARED_WRITE : MDL_SHARED_READ); } @@ -1170,9 +1171,9 @@ err: false otherwise */ -bool -With_element::rename_columns_of_derived_unit(THD *thd, - st_select_lex_unit *unit) +bool +With_element::process_columns_of_derived_unit(THD *thd, + st_select_lex_unit *unit) { if (unit->columns_are_renamed) return false; @@ -1182,7 +1183,7 @@ With_element::rename_columns_of_derived_unit(THD *thd, if (column_list.elements) // The column list is optional { List_iterator_fast<Item> it(select->item_list); - List_iterator_fast<LEX_CSTRING> nm(column_list); + List_iterator_fast<Lex_ident_sys> nm(column_list); Item *item; LEX_CSTRING *name; @@ -1198,8 +1199,8 @@ With_element::rename_columns_of_derived_unit(THD *thd, /* Rename the columns of the first select in the unit */ while ((item= it++, name= nm++)) { - item->set_name(thd, name->str, (uint) name->length, system_charset_info); - item->is_autogenerated_name= false; + item->set_name(thd, *name); + item->common_flags&= ~IS_AUTO_GENERATED_NAME; } if (arena) @@ -1208,6 +1209,43 @@ With_element::rename_columns_of_derived_unit(THD *thd, else make_valid_column_names(thd, select->item_list); + if (cycle_list) + { + List_iterator_fast<Item> it(select->item_list); + List_iterator_fast<Lex_ident_sys> nm(*cycle_list); + List_iterator_fast<Lex_ident_sys> nm_check(*cycle_list); + DBUG_ASSERT(cycle_list->elements != 0); + while (LEX_CSTRING *name= nm++) + { + Item *item; + /* + Check for uniqueness of each element in the cycle list: + It's sufficient to check that there is no duplicate of 'name' + among the elements that precede it. + */ + LEX_CSTRING *check; + nm_check.rewind(); + while ((check= nm_check++) && check != name) + { + if (check->length == name->length && + strncmp(check->str, name->str, name->length) == 0) + { + my_error(ER_DUP_FIELDNAME, MYF(0), check->str); + return true; + } + } + /* Check that 'name' is the name of a column of the processed CTE */ + while ((item= it++) && + (item->name.length != name->length || + strncmp(item->name.str, name->str, name->length) != 0)); + if (item == NULL) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), name->str, "CYCLE clause"); + return true; + } + item->common_flags|= IS_IN_WITH_CYCLE; + } + } unit->columns_are_renamed= true; return false; @@ -1244,7 +1282,7 @@ bool With_element::prepare_unreferenced(THD *thd) thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; if (!spec->prepared && (spec->prepare(spec->derived, 0, 0) || - rename_columns_of_derived_unit(thd, spec) || + process_columns_of_derived_unit(thd, spec) || check_duplicate_names(thd, first_sl->item_list, 1))) rc= true; @@ -1570,16 +1608,17 @@ bool st_select_lex::check_subqueries_with_recursive_references() /** @brief Print this with clause - + + @param thd Thread handle @param str Where to print to - @param query_type The mode of printing - + @param query_type The mode of printing + @details - The method prints a string representation of this clause in the + The method prints a string representation of this clause in the string str. The parameter query_type specifies the mode of printing. -*/ +*/ -void With_clause::print(String *str, enum_query_type query_type) +void With_clause::print(THD *thd, String *str, enum_query_type query_type) { /* Any with clause contains just definitions of CTE tables. @@ -1596,7 +1635,22 @@ void With_clause::print(String *str, enum_query_type query_type) { if (with_elem != with_list.first) str->append(", "); - with_elem->print(str, query_type); + with_elem->print(thd, str, query_type); + } +} + + +static void list_strlex_print(THD *thd, String *str, List<Lex_ident_sys> *list) +{ + List_iterator_fast<Lex_ident_sys> li(*list); + bool first= TRUE; + while(Lex_ident_sys *col_name= li++) + { + if (first) + first= FALSE; + else + str->append(','); + append_identifier(thd, str, col_name); } } @@ -1604,38 +1658,37 @@ void With_clause::print(String *str, enum_query_type query_type) /** @brief Print this with element - + + @param thd Thread handle @param str Where to print to - @param query_type The mode of printing - + @param query_type The mode of printing + @details - The method prints a string representation of this with element in the + The method prints a string representation of this with element in the string str. The parameter query_type specifies the mode of printing. */ -void With_element::print(String *str, enum_query_type query_type) +void With_element::print(THD *thd, String *str, enum_query_type query_type) { str->append(get_name()); if (column_list.elements) { - List_iterator_fast<LEX_CSTRING> li(column_list); + List_iterator_fast<Lex_ident_sys> li(column_list); str->append('('); - for (LEX_CSTRING *col_name= li++; ; ) - { - str->append(col_name); - col_name= li++; - if (!col_name) - { - str->append(')'); - break; - } - str->append(','); - } + list_strlex_print(thd, str, &column_list); + str->append(')'); } - str->append(STRING_WITH_LEN(" as ")); - str->append('('); + str->append(STRING_WITH_LEN(" as (")); spec->print(str, query_type); str->append(')'); + + if (cycle_list) + { + DBUG_ASSERT(cycle_list->elements != 0); + str->append(STRING_WITH_LEN(" CYCLE ")); + list_strlex_print(thd, str, cycle_list); + str->append(STRING_WITH_LEN(" RESTRICT ")); + } } @@ -1660,3 +1713,26 @@ bool With_element::instantiate_tmp_tables() return false; } +void With_element::set_cycle_list(List<Lex_ident_sys> *cycle_list_arg) +{ + cycle_list= cycle_list_arg; + + /* + If a CTE table with columns c1,...,cn is defined with a cycle + clause CYCLE(ci1,...,cik) then no two rows r1 and r2 from the + table shall have r1.ci1=r2.ci1 && ... && r1.cik=r2.cik. + + If a cycle clause is used in the specification of a CTE then + each UNION ALL at the top level of the specification is interpreted + as a UNION DISTINCT over the cycle columns. + */ + for (st_select_lex *sl= spec->first_select(); sl; sl= sl->next_select()) + { + spec->union_distinct= sl; + if (sl != spec->first_select()) + { + sl->distinct= TRUE; + sl->with_all_modifier= FALSE; + } + } +} |