diff options
Diffstat (limited to 'sql/sql_lex.cc')
-rw-r--r-- | sql/sql_lex.cc | 782 |
1 files changed, 667 insertions, 115 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index bd08e6c4f63..984b4c998b4 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -27,6 +27,7 @@ #include <hash.h> #include "sp.h" #include "sp_head.h" +#include "sql_select.h" static int lex_one_token(void *arg, void *yythd); @@ -180,6 +181,7 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) return TRUE; context->resolve_in_table_list_only(table_list); lex->use_only_table_context= TRUE; + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VCOL_EXPR; select_lex->cur_pos_in_select_list= UNDEF_POS; table->map= 1; //To ensure correct calculation of const item table->get_fields_in_item_tree= TRUE; @@ -466,7 +468,6 @@ void lex_start(THD *thd) lex->context_analysis_only= 0; lex->derived_tables= 0; lex->safe_to_cache_query= 1; - lex->leaf_tables_insert= 0; lex->parsing_options.reset(); lex->empty_field_list_on_rset= 0; lex->select_lex.select_number= 1; @@ -1036,45 +1037,48 @@ int lex_one_token(void *arg, void *yythd) yylval->lex_str.length=2; return NULL_SYM; } + /* Fall through */ case MY_LEX_CHAR: // Unknown or single char token case MY_LEX_SKIP: // This should not happen - if (c == '-' && lip->yyPeek() == '-' && + if (c != ')') + lip->next_state= MY_LEX_START; // Allow signed numbers + return((int) c); + + case MY_LEX_MINUS_OR_COMMENT: + if (lip->yyPeek() == '-' && (my_isspace(cs,lip->yyPeekn(1)) || my_iscntrl(cs,lip->yyPeekn(1)))) { state=MY_LEX_COMMENT; break; } + lip->next_state= MY_LEX_START; // Allow signed numbers + return((int) c); - if (c != ')') - lip->next_state= MY_LEX_START; // Allow signed numbers - - if (c == ',') - { - /* - Warning: - This is a work around, to make the "remember_name" rule in - sql/sql_yacc.yy work properly. - The problem is that, when parsing "select expr1, expr2", - the code generated by bison executes the *pre* action - remember_name (see select_item) *before* actually parsing the - first token of expr2. - */ - lip->restart_token(); - } - else - { - /* - Check for a placeholder: it should not precede a possible identifier - because of binlogging: when a placeholder is replaced with - its value in a query for the binlog, the query must stay - grammatically correct. - */ - if (c == '?' && lip->stmt_prepare_mode && - !ident_map[(uchar) lip->yyPeek()]) + case MY_LEX_PLACEHOLDER: + /* + Check for a placeholder: it should not precede a possible identifier + because of binlogging: when a placeholder is replaced with + its value in a query for the binlog, the query must stay + grammatically correct. + */ + lip->next_state= MY_LEX_START; // Allow signed numbers + if (lip->stmt_prepare_mode && !ident_map[(uchar) lip->yyPeek()]) return(PARAM_MARKER); - } + return((int) c); + case MY_LEX_COMMA: + lip->next_state= MY_LEX_START; // Allow signed numbers + /* + Warning: + This is a work around, to make the "remember_name" rule in + sql/sql_yacc.yy work properly. + The problem is that, when parsing "select expr1, expr2", + the code generated by bison executes the *pre* action + remember_name (see select_item) *before* actually parsing the + first token of expr2. + */ + lip->restart_token(); return((int) c); case MY_LEX_IDENT_OR_NCHAR: @@ -1809,6 +1813,7 @@ void st_select_lex_unit::init_query() describe= 0; found_rows_for_union= 0; insert_table_with_stored_vcol= 0; + derived= 0; } void st_select_lex::init_query() @@ -1817,7 +1822,9 @@ void st_select_lex::init_query() table_list.empty(); top_join_list.empty(); join_list= &top_join_list; - embedding= leaf_tables= 0; + embedding= 0; + leaf_tables_prep.empty(); + leaf_tables.empty(); item_list.empty(); join= 0; having= prep_having= where= prep_where= 0; @@ -1849,6 +1856,7 @@ void st_select_lex::init_query() exclude_from_table_unique_test= no_wrap_view_item= FALSE; nest_level= 0; link_next= 0; + is_prep_leaf_list_saved= FALSE; bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used)); } @@ -1857,6 +1865,7 @@ void st_select_lex::init_select() { st_select_lex_node::init_select(); sj_nests.empty(); + sj_subselects.empty(); group_list.empty(); type= db= 0; having= 0; @@ -1883,6 +1892,8 @@ void st_select_lex::init_select() cond_value= having_value= Item::COND_UNDEF; inner_refs_list.empty(); full_group_by_flag= 0; + insert_tables= 0; + merged_into= 0; } /* @@ -1900,6 +1911,31 @@ void st_select_lex_node::include_down(st_select_lex_node *upper) slave= 0; } + +void st_select_lex_node::add_slave(st_select_lex_node *slave_arg) +{ + for (; slave; slave= slave->next) + if (slave == slave_arg) + return; + + if (slave) + { + st_select_lex_node *slave_arg_slave= slave_arg->slave; + /* Insert in the front of list of slaves if any. */ + slave_arg->include_neighbour(slave); + /* include_neighbour() sets slave_arg->slave=0, restore it. */ + slave_arg->slave= slave_arg_slave; + /* Count on include_neighbour() setting the master. */ + DBUG_ASSERT(slave_arg->master == this); + } + else + { + slave= slave_arg; + slave_arg->master= this; + } +} + + /* include on level down (but do not link) @@ -1951,17 +1987,29 @@ void st_select_lex_node::fast_exclude() } + +/* + Exclude a node from the tree lex structure, but leave it in the global + list of nodes. +*/ + +void st_select_lex_node::exclude_from_tree() +{ + if ((*prev= next)) + next->prev= prev; +} + + /* - excluding select_lex structure (except first (first select can't be + Exclude select_lex structure (except first (first select can't be deleted, because it is most upper select)) */ void st_select_lex_node::exclude() { - //exclude from global list + /* exclude from global list */ fast_exclude(); - //exclude from other structures - if ((*prev= next)) - next->prev= prev; + /* exclude from other structures */ + exclude_from_tree(); /* We do not need following statements, because prev pointer of first list element point to master->slave @@ -2048,55 +2096,6 @@ void st_select_lex_unit::exclude_tree() } -/** - Register reference to an item which the subqueries depends on - - @param def_sel select against which the item is resolved - @param dependency reference to the item - - @details - This function puts the reference dependency to an item that is either an - outer field or an aggregate function resolved against an outer select into - the list 'depends_on'. It adds it to the 'depends_on' lists for each - subquery between this one and 'def_sel' - the subquery against which the - item is resolved. -*/ - -void st_select_lex::register_dependency_item(st_select_lex *def_sel, - Item **dependency) -{ - SELECT_LEX *s= this; - DBUG_ENTER("st_select_lex::register_dependency_item"); - DBUG_ASSERT(this != def_sel); - DBUG_ASSERT(*dependency); - do - { - /* check duplicates */ - List_iterator_fast<Item*> li(s->master_unit()->item->depends_on); - Item **dep; - while ((dep= li++)) - { - if ((*dep)->eq(*dependency, FALSE)) - { - DBUG_PRINT("info", ("dependency %s already present", - ((*dependency)->name ? - (*dependency)->name : - "<no name>"))); - DBUG_VOID_RETURN; - } - } - - s->master_unit()->item->depends_on.push_back(dependency); - DBUG_PRINT("info", ("depends_on: Select: %d added: %s", - s->select_number, - ((*dependency)->name ? - (*dependency)->name : - "<no name>"))); - } while ((s= s->outer_select()) != def_sel); - DBUG_VOID_RETURN; -} - - /* st_select_lex_node::mark_as_dependent mark all st_select_lex struct from this to 'last' as dependent @@ -2121,18 +2120,19 @@ bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last, Item *depen SELECT_LEX *s= this; do { - if (!(s->uncacheable & UNCACHEABLE_DEPENDENT)) + if (!(s->uncacheable & UNCACHEABLE_DEPENDENT_GENERATED)) { // Select is dependent of outer select s->uncacheable= (s->uncacheable & ~UNCACHEABLE_UNITED) | - UNCACHEABLE_DEPENDENT; + UNCACHEABLE_DEPENDENT_GENERATED; SELECT_LEX_UNIT *munit= s->master_unit(); munit->uncacheable= (munit->uncacheable & ~UNCACHEABLE_UNITED) | - UNCACHEABLE_DEPENDENT; + UNCACHEABLE_DEPENDENT_GENERATED; for (SELECT_LEX *sl= munit->first_select(); sl ; sl= sl->next_select()) { if (sl != s && - !(sl->uncacheable & (UNCACHEABLE_DEPENDENT | UNCACHEABLE_UNITED))) + !(sl->uncacheable & (UNCACHEABLE_DEPENDENT_GENERATED | + UNCACHEABLE_UNITED))) sl->uncacheable|= UNCACHEABLE_UNITED; } } @@ -2270,20 +2270,22 @@ ulong st_select_lex::get_table_join_options() bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) { + DBUG_ENTER("st_select_lex::setup_ref_array"); + if (ref_pointer_array) - return 0; + DBUG_RETURN(0); /* - We have to create array in prepared statement memory if it is + We have to create array in prepared statement memory if it is a prepared statement */ - Query_arena *arena= thd->stmt_arena; - return (ref_pointer_array= - (Item **)arena->alloc(sizeof(Item*) * (n_child_sum_items + - item_list.elements + - select_n_having_items + - select_n_where_fields + - order_group_num)*5)) == 0; + ref_pointer_array= + (Item **)thd->stmt_arena->alloc(sizeof(Item*) * (n_child_sum_items + + item_list.elements + + select_n_having_items + + select_n_where_fields + + order_group_num)*5); + DBUG_RETURN(ref_pointer_array == 0); } @@ -2328,9 +2330,27 @@ void st_select_lex::print_order(String *str, { if (order->counter_used) { - char buffer[20]; - size_t length= my_snprintf(buffer, 20, "%d", order->counter); - str->append(buffer, (uint) length); + if (query_type != QT_VIEW_INTERNAL) + { + char buffer[20]; + size_t length= my_snprintf(buffer, 20, "%d", order->counter); + str->append(buffer, (uint) length); + } + else + { + /* replace numeric reference with expression */ + if (order->item[0]->type() == Item::INT_ITEM && + order->item[0]->basic_const_item()) + { + char buffer[20]; + size_t length= my_snprintf(buffer, 20, "%d", order->counter); + str->append(buffer, (uint) length); + /* make it expression instead of integer constant */ + str->append(STRING_WITH_LEN("+0")); + } + else + (*order->item)->print(str, query_type); + } } else (*order->item)->print(str, query_type); @@ -2356,17 +2376,6 @@ void st_select_lex::print_limit(THD *thd, subs_type == Item_subselect::IN_SUBS || subs_type == Item_subselect::ALL_SUBS) { - DBUG_ASSERT(!item->fixed || - /* - If not using materialization both: - select_limit == 1, and there should be no offset_limit. - */ - (((subs_type == Item_subselect::IN_SUBS) && - ((Item_in_subselect*)item)->exec_method == - Item_in_subselect::MATERIALIZATION) ? - TRUE : - (select_limit->val_int() == 1LL) && - offset_limit == 0)); return; } } @@ -3179,10 +3188,14 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl) { if (tbl->on_expr) { - tbl->prep_on_expr= tbl->on_expr; + thd->check_and_register_item_tree(&tbl->prep_on_expr, &tbl->on_expr); tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); } - fix_prepare_info_in_table_list(thd, tbl->merge_underlying_list); + if (tbl->is_view_or_derived() && tbl->is_merged_derived()) + { + SELECT_LEX *sel= tbl->get_single_select(); + fix_prepare_info_in_table_list(thd, sel->get_table_list()); + } } } @@ -3213,12 +3226,12 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds, first_execution= 0; if (*conds) { - prep_where= *conds; + thd->check_and_register_item_tree(&prep_where, conds); *conds= where= prep_where->copy_andor_structure(thd); } if (*having_conds) { - prep_having= *having_conds; + thd->check_and_register_item_tree(&prep_having, having_conds); *having_conds= having= prep_having->copy_andor_structure(thd); } fix_prepare_info_in_table_list(thd, table_list.first); @@ -3297,6 +3310,545 @@ bool st_select_lex::add_index_hint (THD *thd, char *str, uint length) str, length)); } + +bool st_select_lex::optimize_unflattened_subqueries() +{ + for (SELECT_LEX_UNIT *un= first_inner_unit(); un; un= un->next_unit()) + { + Item_subselect *subquery_predicate= un->item; + + if (subquery_predicate) + { + if (subquery_predicate->substype() == Item_subselect::IN_SUBS) + { + Item_in_subselect *in_subs=(Item_in_subselect*)subquery_predicate; + if (in_subs->is_jtbm_merged) + continue; + } + + for (SELECT_LEX *sl= un->first_select(); sl; sl= sl->next_select()) + { + JOIN *inner_join= sl->join; + if (!inner_join) + continue; + SELECT_LEX *save_select= un->thd->lex->current_select; + ulonglong save_options; + int res; + /* We need only 1 row to determine existence */ + un->set_limit(un->global_parameters); + un->thd->lex->current_select= sl; + save_options= inner_join->select_options; + if (options & SELECT_DESCRIBE) + { + /* Optimize the subquery in the context of EXPLAIN. */ + sl->set_explain_type(); + sl->options|= SELECT_DESCRIBE; + inner_join->select_options|= SELECT_DESCRIBE; + } + res= inner_join->optimize(); + inner_join->select_options= save_options; + un->thd->lex->current_select= save_select; + if (res) + return TRUE; + } + } + } + return FALSE; +} + + + +/** + @brief Process all derived tables/views of the SELECT. + + @param lex LEX of this thread + @param phase phases to run derived tables/views through + + @details + This function runs specified 'phases' on all tables from the + table_list of this select. + + @return FALSE ok. + @return TRUE an error occur. +*/ + +bool st_select_lex::handle_derived(LEX *lex, uint phases) +{ + for (TABLE_LIST *cursor= (TABLE_LIST*) table_list.first; + cursor; + cursor= cursor->next_local) + { + if (cursor->is_view_or_derived() && cursor->handle_derived(lex, phases)) + return TRUE; + } + return FALSE; +} + + +/** + @brief + Returns first unoccupied table map and table number + + @param map [out] return found map + @param tablenr [out] return found tablenr + + @details + Returns first unoccupied table map and table number in this select. + Map and table are returned in *'map' and *'tablenr' accordingly. + + @retrun TRUE no free table map/table number + @return FALSE found free table map/table number +*/ + +bool st_select_lex::get_free_table_map(table_map *map, uint *tablenr) +{ + *map= 0; + *tablenr= 0; + TABLE_LIST *tl; + List_iterator<TABLE_LIST> ti(leaf_tables); + while ((tl= ti++)) + { + if (tl->table->map > *map) + *map= tl->table->map; + if (tl->table->tablenr > *tablenr) + *tablenr= tl->table->tablenr; + } + (*map)<<= 1; + (*tablenr)++; + if (*tablenr >= MAX_TABLES) + return TRUE; + return FALSE; +} + + +/** + @brief + Append given table to the leaf_tables list. + + @param link Offset to which list in table structure to use + @param table Table to append + + @details + Append given 'table' to the leaf_tables list using the 'link' offset. + If the 'table' is linked with other tables through next_leaf/next_local + chains then whole list will be appended. +*/ + +void st_select_lex::append_table_to_list(TABLE_LIST *TABLE_LIST::*link, + TABLE_LIST *table) +{ + TABLE_LIST *tl; + for (tl= leaf_tables.head(); tl->*link; tl= tl->*link) ; + tl->*link= table; +} + +/* + @brief + Remove given table from the leaf_tables list. + + @param link Offset to which list in table structure to use + @param table Table to remove + + @details + Remove 'table' from the leaf_tables list using the 'link' offset. +*/ + +void st_select_lex::remove_table_from_list(TABLE_LIST *table) +{ + TABLE_LIST *tl; + List_iterator<TABLE_LIST> ti(leaf_tables); + while ((tl= ti++)) + { + if (tl == table) + { + ti.remove(); + break; + } + } +} + + +/** + @brief + Assigns new table maps to tables in the leaf_tables list + + @param derived Derived table to take initial table map from + @param map table map to begin with + @param tablenr table number to begin with + @param parent_lex new parent select_lex + + @details + Assign new table maps/table numbers to all tables in the leaf_tables list. + 'map'/'tablenr' are used for the first table and shifted to left/ + increased for each consequent table in the leaf_tables list. + If the 'derived' table is given then it's table map/number is used for the + first table in the list and 'map'/'tablenr' are used for the second and + all consequent tables. + The 'parent_lex' is set as the new parent select_lex for all tables in the + list. +*/ + +void st_select_lex::remap_tables(TABLE_LIST *derived, table_map map, + uint tablenr, SELECT_LEX *parent_lex) +{ + bool first_table= TRUE; + TABLE_LIST *tl; + table_map first_map; + uint first_tablenr; + + if (derived && derived->table) + { + first_map= derived->table->map; + first_tablenr= derived->table->tablenr; + } + else + { + first_map= map; + map<<= 1; + first_tablenr= tablenr++; + } + /* + Assign table bit/table number. + To the first table of the subselect the table bit/tablenr of the + derived table is assigned. The rest of tables are getting bits + sequentially, starting from the provided table map/tablenr. + */ + List_iterator<TABLE_LIST> ti(leaf_tables); + while ((tl= ti++)) + { + if (first_table) + { + first_table= FALSE; + tl->table->set_table_map(first_map, first_tablenr); + } + else + { + tl->table->set_table_map(map, tablenr); + tablenr++; + map<<= 1; + } + SELECT_LEX *old_sl= tl->select_lex; + tl->select_lex= parent_lex; + for(TABLE_LIST *emb= tl->embedding; + emb && emb->select_lex == old_sl; + emb= emb->embedding) + emb->select_lex= parent_lex; + } +} + +/** + @brief + Merge a subquery into this select. + + @param derived derived table of the subquery to be merged + @param subq_select select_lex of the subquery + @param map table map for assigning to merged tables from subquery + @param table_no table number for assigning to merged tables from subquery + + @details + This function merges a subquery into its parent select. In short the + merge operation appends the subquery FROM table list to the parent's + FROM table list. In more details: + .) the top_join_list of the subquery is wrapped into a join_nest + and attached to 'derived' + .) subquery's leaf_tables list is merged with the leaf_tables + list of this select_lex + .) the table maps and table numbers of the tables merged from + the subquery are adjusted to reflect their new binding to + this select + + @return TRUE an error occur + @return FALSE ok +*/ + +bool SELECT_LEX::merge_subquery(THD *thd, TABLE_LIST *derived, + SELECT_LEX *subq_select, + uint table_no, table_map map) +{ + derived->wrap_into_nested_join(subq_select->top_join_list); + /* Reconnect the next_leaf chain. */ + leaf_tables.concat(&subq_select->leaf_tables); + + ftfunc_list->concat(subq_select->ftfunc_list); + if (join || + thd->lex->sql_command == SQLCOM_UPDATE_MULTI || + thd->lex->sql_command == SQLCOM_DELETE_MULTI) + { + List_iterator_fast<Item_in_subselect> li(subq_select->sj_subselects); + Item_in_subselect *in_subq; + while ((in_subq= li++)) + { + sj_subselects.push_back(in_subq); + if (in_subq->emb_on_expr_nest == NO_JOIN_NEST) + in_subq->emb_on_expr_nest= derived; + } + } + /* + Remove merged table from chain. + When merge_subquery is called at a subquery-to-semijoin transformation + the derived isn't in the leaf_tables list, so in this case the call of + remove_table_from_list does not cause any actions. + */ + remove_table_from_list(derived); + + /* Walk through child's tables and adjust table map, tablenr, + * parent_lex */ + subq_select->remap_tables(derived, map, table_no, this); + subq_select->merged_into= this; + return FALSE; +} + + +/** + @brief + Mark tables from the leaf_tables list as belong to a derived table. + + @param derived tables will be marked as belonging to this derived + + @details + Run through the leaf_list and mark all tables as belonging to the 'derived'. +*/ + +void SELECT_LEX::mark_as_belong_to_derived(TABLE_LIST *derived) +{ + /* Mark tables as belonging to this DT */ + TABLE_LIST *tl; + List_iterator<TABLE_LIST> ti(leaf_tables); + while ((tl= ti++)) + { + tl->open_type= OT_BASE_ONLY; + tl->belong_to_derived= derived; + } +} + + +/** + @brief + Update used_tables cache for this select + + @details + This function updates used_tables cache of ON expressions of all tables + in the leaf_tables list and of the conds expression (if any). +*/ + +void SELECT_LEX::update_used_tables() +{ + TABLE_LIST *tl; + List_iterator<TABLE_LIST> ti(leaf_tables); + while ((tl= ti++)) + { + TABLE_LIST *embedding; + embedding= tl; + do + { + bool maybe_null; + if ((maybe_null= test(embedding->outer_join))) + { + tl->table->maybe_null= maybe_null; + break; + } + } + while ((embedding= embedding->embedding)); + if (tl->on_expr) + { + tl->on_expr->update_used_tables(); + tl->on_expr->walk(&Item::eval_not_null_tables, 0, NULL); + } + embedding= tl->embedding; + while (embedding) + { + if (embedding->on_expr && + embedding->nested_join->join_list.head() == tl) + { + embedding->on_expr->update_used_tables(); + embedding->on_expr->walk(&Item::eval_not_null_tables, 0, NULL); + } + tl= embedding; + embedding= tl->embedding; + } + } + if (join->conds) + { + join->conds->update_used_tables(); + join->conds->walk(&Item::eval_not_null_tables, 0, NULL); + } + if (join->having) + { + join->having->update_used_tables(); + } + + Item *item; + List_iterator_fast<Item> it(join->fields_list); + while ((item= it++)) + { + item->update_used_tables(); + } + Item_outer_ref *ref; + List_iterator_fast<Item_outer_ref> ref_it(inner_refs_list); + while ((ref= ref_it++)) + { + item= ref->outer_ref; + item->update_used_tables(); + } + for (ORDER *order= group_list.first; order; order= order->next) + (*order->item)->update_used_tables(); + if (!master_unit()->is_union()) + { + for (ORDER *order= order_list.first; order; order= order->next) + (*order->item)->update_used_tables(); + } +} + + +/** + Set the EXPLAIN type for this subquery. +*/ + +void st_select_lex::set_explain_type() +{ + bool is_primary= FALSE; + if (next_select()) + is_primary= TRUE; + + if (!is_primary && first_inner_unit()) + { + /* + If there is at least one materialized derived|view then it's a PRIMARY select. + Otherwise, all derived tables/views were merged and this select is a SIMPLE one. + */ + for (SELECT_LEX_UNIT *un= first_inner_unit(); un; un= un->next_unit()) + { + if ((!un->derived || un->derived->is_materialized_derived())) + { + is_primary= TRUE; + break; + } + } + } + + SELECT_LEX *first= master_unit()->first_select(); + /* drop UNCACHEABLE_EXPLAIN, because it is for internal usage only */ + uint8 is_uncacheable= (uncacheable & ~UNCACHEABLE_EXPLAIN); + + type= ((&master_unit()->thd->lex->select_lex == this) ? + (is_primary ? "PRIMARY" : "SIMPLE"): + ((this == first) ? + ((linkage == DERIVED_TABLE_TYPE) ? + "DERIVED" : + ((is_uncacheable & UNCACHEABLE_DEPENDENT) ? + "DEPENDENT SUBQUERY" : + (is_uncacheable ? "UNCACHEABLE SUBQUERY" : + "SUBQUERY"))) : + ((is_uncacheable & UNCACHEABLE_DEPENDENT) ? + "DEPENDENT UNION": + is_uncacheable ? "UNCACHEABLE UNION": + "UNION"))); + options|= SELECT_DESCRIBE; +} + + +/** + @brief + Increase estimated number of records for a derived table/view + + @param records number of records to increase estimate by + + @details + This function increases estimated number of records by the 'records' + for the derived table to which this select belongs to. +*/ + +void SELECT_LEX::increase_derived_records(ha_rows records) +{ + SELECT_LEX_UNIT *unit= master_unit(); + DBUG_ASSERT(unit->derived); + + select_union *result= (select_union*)unit->result; + result->records+= records; +} + + +/** + @brief + Mark select's derived table as a const one. + + @param empty Whether select has an empty result set + + @details + Mark derived table/view of this select as a constant one (to + materialize it at the optimization phase) unless this select belongs to a + union. Estimated number of rows is incremented if this select has non empty + result set. +*/ + +void SELECT_LEX::mark_const_derived(bool empty) +{ + TABLE_LIST *derived= master_unit()->derived; + if (!join->thd->lex->describe && derived) + { + if (!empty) + increase_derived_records(1); + if (!master_unit()->is_union() && !derived->is_merged_derived()) + derived->fill_me= TRUE; + } +} + + +bool st_select_lex::save_leaf_tables(THD *thd) +{ + Query_arena *arena= thd->stmt_arena, backup; + if (arena->is_conventional()) + arena= 0; + else + thd->set_n_backup_active_arena(arena, &backup); + + List_iterator_fast<TABLE_LIST> li(leaf_tables); + TABLE_LIST *table; + while ((table= li++)) + { + if (leaf_tables_exec.push_back(table)) + return 1; + table->tablenr_exec= table->table->tablenr; + table->map_exec= table->table->map; + if (join && (join->select_options & SELECT_DESCRIBE)) + table->maybe_null_exec= 0; + else + table->maybe_null_exec= table->table->maybe_null; + } + if (arena) + thd->restore_active_arena(arena, &backup); + + return 0; +} + + +bool st_select_lex::save_prep_leaf_tables(THD *thd) +{ + if (!thd->save_prep_leaf_list) + return 0; + + Query_arena *arena= thd->stmt_arena, backup; + if (arena->is_conventional()) + arena= 0; + else + thd->set_n_backup_active_arena(arena, &backup); + + List_iterator_fast<TABLE_LIST> li(leaf_tables); + TABLE_LIST *table; + while ((table= li++)) + { + if (leaf_tables_prep.push_back(table)) + return 1; + } + thd->lex->select_lex.is_prep_leaf_list_saved= TRUE; + thd->save_prep_leaf_list= FALSE; + if (arena) + thd->restore_active_arena(arena, &backup); + + return 0; +} + + /** A routine used by the parser to decide whether we are specifying a full partitioning or if only partitions to add or to split. |