diff options
Diffstat (limited to 'sql/sql_derived.cc')
-rw-r--r-- | sql/sql_derived.cc | 198 |
1 files changed, 152 insertions, 46 deletions
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 6785bf8e815..1f465a100c9 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -22,7 +22,7 @@ */ -#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "unireg.h" #include "sql_derived.h" @@ -175,10 +175,11 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) DBUG_ENTER("mysql_handle_single_derived"); DBUG_PRINT("enter", ("phases: 0x%x allowed: 0x%x alias: '%s'", phases, allowed_phases, - (derived->alias ? derived->alias : "<NULL>"))); + (derived->alias.str ? derived->alias.str : "<NULL>"))); if (!lex->derived_tables) DBUG_RETURN(FALSE); + derived->select_lex->changed_elements|= TOUCHED_SEL_DERIVED; lex->thd->derived_tables_processing= TRUE; for (uint phase= 0; phase < DT_PHASES; phase++) @@ -336,7 +337,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) Query_arena *arena, backup; DBUG_ENTER("mysql_derived_merge"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", - (derived->alias ? derived->alias : "<NULL>"), + (derived->alias.str ? derived->alias.str : "<NULL>"), derived->get_unit())); if (derived->merged) @@ -436,9 +437,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) derived->prep_on_expr= expr->copy_andor_structure(thd); } if (derived->on_expr && - ((!derived->on_expr->fixed && - derived->on_expr->fix_fields(thd, &derived->on_expr)) || - derived->on_expr->check_cols(1))) + derived->on_expr->fix_fields_if_needed_for_bool(thd, &derived->on_expr)) { res= TRUE; /* purecov: inspected */ goto exit_merge; @@ -489,7 +488,7 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) { DBUG_ENTER("mysql_derived_merge_for_insert"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", - (derived->alias ? derived->alias : "<NULL>"), + (derived->alias.str ? derived->alias.str : "<NULL>"), derived->get_unit())); DBUG_PRINT("info", ("merged_for_insert: %d is_materialized_derived: %d " "is_multitable: %d single_table_updatable: %d " @@ -547,7 +546,7 @@ bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived) SELECT_LEX_UNIT *unit= derived->get_unit(); DBUG_ENTER("mysql_derived_init"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", - (derived->alias ? derived->alias : "<NULL>"), + (derived->alias.str ? derived->alias.str : "<NULL>"), derived->get_unit())); // Skip already prepared views/DT @@ -622,11 +621,10 @@ bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived) bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) { SELECT_LEX_UNIT *unit= derived->get_unit(); - DBUG_ENTER("mysql_derived_prepare"); bool res= FALSE; - DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", - (derived->alias ? derived->alias : "<NULL>"), - unit)); + DBUG_ENTER("mysql_derived_prepare"); + DBUG_PRINT("enter", ("unit: %p table_list: %p alias: '%s'", + unit, derived, derived->alias.str)); if (!unit) DBUG_RETURN(FALSE); @@ -646,7 +644,8 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) table reference from a subquery for this. */ DBUG_ASSERT(derived->with->get_sq_rec_ref()); - if (mysql_derived_prepare(lex->thd, lex, derived->with->get_sq_rec_ref())) + if (unlikely(mysql_derived_prepare(lex->thd, lex, + derived->with->get_sq_rec_ref()))) DBUG_RETURN(TRUE); } @@ -659,7 +658,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) specification has been already prepared (a secondary recursive table reference. */ - if (!(derived->derived_result= new (thd->mem_root) select_union(thd))) + if (!(derived->derived_result= new (thd->mem_root) select_unit(thd))) DBUG_RETURN(TRUE); // out of memory thd->create_tmp_table_for_derived= TRUE; res= derived->derived_result->create_result_table( @@ -667,10 +666,10 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) (first_select->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS), - derived->alias, FALSE, FALSE); + &derived->alias, FALSE, FALSE, FALSE, 0); thd->create_tmp_table_for_derived= FALSE; - if (!res && !derived->table) + if (likely(!res) && !derived->table) { derived->derived_result->set_unit(unit); derived->table= derived->derived_result->table; @@ -690,7 +689,39 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) !(derived->is_multitable() && (thd->lex->sql_command == SQLCOM_UPDATE_MULTI || thd->lex->sql_command == SQLCOM_DELETE_MULTI)))) + { + /* + System versioned tables may still require to get versioning conditions + when modifying view (see vers_setup_conds()). Only UPDATE and DELETE are + affected because they use WHERE condition. + */ + if (!unit->prepared && + derived->table->versioned() && + derived->merge_underlying_list && + /* choose only those merged views that do not select from other views */ + !derived->merge_underlying_list->merge_underlying_list) + { + switch (thd->lex->sql_command) + { + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + if ((res= first_select->vers_setup_conds(thd, + derived->merge_underlying_list))) + goto exit; + if (derived->merge_underlying_list->where) + { + Query_arena_stmt on_stmt_arena(thd); + derived->where= and_items(thd, derived->where, + derived->merge_underlying_list->where); + } + default: + break; + } + } DBUG_RETURN(FALSE); + } /* prevent name resolving out of derived table */ for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select()) @@ -719,8 +750,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) } } - unit->derived= derived; - /* Above cascade call of prepare is important for PS protocol, but after it is called we can check if we really need prepare for this derived @@ -733,12 +762,12 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) derived->fill_me= FALSE; - if (!(derived->derived_result= new (thd->mem_root) select_union(thd))) + if (!(derived->derived_result= new (thd->mem_root) select_unit(thd))) DBUG_RETURN(TRUE); // out of memory lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; // st_select_lex_unit::prepare correctly work for single select - if ((res= unit->prepare(thd, derived->derived_result, 0))) + if ((res= unit->prepare(derived, derived->derived_result, 0))) goto exit; if (derived->with && (res= derived->with->rename_columns_of_derived_unit(thd, unit))) @@ -761,7 +790,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) As 'distinct' parameter we always pass FALSE (0), because underlying query will control distinct condition by itself. Correct test of - distinct underlying query will be is_union && + distinct underlying query will be is_unit_op && !unit->union_distinct->next_select() (i.e. it is union and last distinct SELECT is last SELECT of UNION). */ @@ -771,8 +800,9 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) (first_select->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS), - derived->alias, - FALSE, FALSE, FALSE)) + &derived->alias, + FALSE, FALSE, FALSE, + 0)) { thd->create_tmp_table_for_derived= FALSE; goto exit; @@ -795,8 +825,8 @@ exit: thd->get_stmt_da()->sql_errno() == ER_SP_DOES_NOT_EXIST)) { thd->clear_error(); - my_error(ER_VIEW_INVALID, MYF(0), derived->db, - derived->table_name); + my_error(ER_VIEW_INVALID, MYF(0), derived->db.str, + derived->table_name.str); } } @@ -809,7 +839,7 @@ exit: { if (!derived->is_with_table_recursive_reference()) { - if (derived->table) + if (derived->table && derived->table->s->tmp_table) free_tmp_table(thd, derived->table); delete derived->derived_result; } @@ -866,11 +896,10 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) SELECT_LEX_UNIT *unit= derived->get_unit(); SELECT_LEX *first_select= unit->first_select(); SELECT_LEX *save_current_select= lex->current_select; - bool res= FALSE; DBUG_ENTER("mysql_derived_optimize"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", - (derived->alias ? derived->alias : "<NULL>"), + (derived->alias.str ? derived->alias.str : "<NULL>"), derived->get_unit())); if (derived->merged) { @@ -878,12 +907,12 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) DBUG_RETURN(FALSE); } - if (unit->optimized) - DBUG_RETURN(FALSE); lex->current_select= first_select; - if (unit->is_union()) + if (unit->is_unit_op()) { + if (unit->optimized) + DBUG_RETURN(FALSE); // optimize union without execution res= unit->optimize(); } @@ -893,7 +922,20 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) { JOIN *join= first_select->join; unit->set_limit(unit->global_parameters()); - unit->optimized= TRUE; + if (join && + join->optimization_state == JOIN::OPTIMIZATION_PHASE_1_DONE && + join->with_two_phase_optimization) + { + if (unit->optimized_2) + DBUG_RETURN(FALSE); + unit->optimized_2= TRUE; + } + else + { + if (unit->optimized) + DBUG_RETURN(FALSE); + unit->optimized= TRUE; + } if ((res= join->optimize())) goto err; if (join->table_count == join->const_tables) @@ -943,14 +985,14 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived) { DBUG_ENTER("mysql_derived_create"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", - (derived->alias ? derived->alias : "<NULL>"), + (derived->alias.str ? derived->alias.str : "<NULL>"), derived->get_unit())); TABLE *table= derived->table; SELECT_LEX_UNIT *unit= derived->get_unit(); if (table->is_created()) DBUG_RETURN(FALSE); - select_union *result= derived->derived_result; + select_unit *result= derived->derived_result; if (table->s->db_type() == TMP_ENGINE_HTON) { result->tmp_table_param.keyinfo= table->s->key_info; @@ -969,6 +1011,20 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived) } +void TABLE_LIST::register_as_derived_with_rec_ref(With_element *rec_elem) +{ + rec_elem->derived_with_rec_ref.link_in_list(this, &this->next_with_rec_ref); + is_derived_with_recursive_reference= true; + get_unit()->uncacheable|= UNCACHEABLE_DEPENDENT; +} + + +bool TABLE_LIST::is_nonrecursive_derived_with_rec_ref() +{ + return is_derived_with_recursive_reference; +} + + /** @brief Fill the recursive with table @@ -1044,7 +1100,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) bool res= FALSE; DBUG_ENTER("mysql_derived_fill"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", - (derived->alias ? derived->alias : "<NULL>"), + (derived->alias.str ? derived->alias.str : "<NULL>"), derived->get_unit())); if (unit->executed && !unit->uncacheable && !unit->describe && @@ -1052,9 +1108,25 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) DBUG_RETURN(FALSE); /*check that table creation passed without problems. */ DBUG_ASSERT(derived->table && derived->table->is_created()); - select_union *derived_result= derived->derived_result; + select_unit *derived_result= derived->derived_result; SELECT_LEX *save_current_select= lex->current_select; bool derived_recursive_is_filled= false; + + if (unit->executed && !derived_is_recursive && + (unit->uncacheable & UNCACHEABLE_DEPENDENT)) + { + if ((res= derived->table->file->ha_delete_all_rows())) + goto err; + JOIN *join= unit->first_select()->join; + join->first_record= false; + for (uint i= join->top_join_tab_count; + i < join->top_join_tab_count + join->aggr_tables; + i++) + { + if ((res= join->join_tab[i].table->file->ha_delete_all_rows())) + goto err; + } + } if (derived_is_recursive) { @@ -1070,7 +1142,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) derived_recursive_is_filled= true; } } - else if (unit->is_union()) + else if (unit->is_unit_op()) { // execute union without clean up res= unit->exec(); @@ -1122,10 +1194,9 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) } } } - - if (res || (!lex->describe && - (!derived_is_recursive || - derived_recursive_is_filled))) +err: + if (res || (!lex->describe && !unit->uncacheable && + (!derived_is_recursive || derived_recursive_is_filled))) unit->cleanup(); lex->current_select= save_current_select; @@ -1154,7 +1225,7 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived) { DBUG_ENTER("mysql_derived_reinit"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", - (derived->alias ? derived->alias : "<NULL>"), + (derived->alias.str ? derived->alias.str : "<NULL>"), derived->get_unit())); st_select_lex_unit *unit= derived->get_unit(); @@ -1252,15 +1323,51 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) st_select_lex *save_curr_select= thd->lex->current_select; for (; sl; sl= sl->next_select()) { + Item *extracted_cond_copy; if (!sl->cond_pushdown_is_allowed()) continue; thd->lex->current_select= sl; + if (sl->have_window_funcs()) + { + if (sl->join->group_list || sl->join->implicit_grouping) + continue; + ORDER *common_partition_fields= + sl->find_common_window_func_partition_fields(thd); + if (!common_partition_fields) + continue; + extracted_cond_copy= !sl->next_select() ? + extracted_cond : + extracted_cond->build_clone(thd); + if (!extracted_cond_copy) + continue; + + Item *cond_over_partition_fields;; + sl->collect_grouping_fields(thd, common_partition_fields); + sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy, + derived); + cond_over_partition_fields= + sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true); + if (cond_over_partition_fields) + cond_over_partition_fields= cond_over_partition_fields->transform(thd, + &Item::derived_grouping_field_transformer_for_where, + (uchar*) sl); + if (cond_over_partition_fields) + { + cond_over_partition_fields->walk( + &Item::cleanup_excluding_const_fields_processor, 0, 0); + sl->cond_pushed_into_where= cond_over_partition_fields; + } + + continue; + } + /* For each select of the unit except the last one create a clone of extracted_cond */ - Item *extracted_cond_copy= !sl->next_select() ? extracted_cond : - extracted_cond->build_clone(thd, thd->mem_root); + extracted_cond_copy= !sl->next_select() ? + extracted_cond : + extracted_cond->build_clone(thd); if (!extracted_cond_copy) continue; @@ -1285,7 +1392,7 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) that could be pushed into the where clause of sl */ Item *cond_over_grouping_fields; - sl->collect_grouping_fields(thd); + sl->collect_grouping_fields(thd, sl->join->group_list); sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy, derived); cond_over_grouping_fields= @@ -1333,4 +1440,3 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) thd->lex->current_select= save_curr_select; DBUG_RETURN(false); } - |