diff options
Diffstat (limited to 'sql/sql_lex.cc')
-rw-r--r-- | sql/sql_lex.cc | 86 |
1 files changed, 80 insertions, 6 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 608eccbaff6..cc6e33263b8 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4413,7 +4413,7 @@ void st_select_lex::set_explain_type(bool on_the_fly) { type= is_uncacheable ? "UNCACHEABLE UNION": "UNION"; if (this == master_unit()->fake_select_lex) - type= "UNION RESULT"; + type= unit_operation_text[master_unit()->common_op()]; /* join below may be =NULL when this functions is called at an early stage. It will be later called again and we will set the correct @@ -4484,6 +4484,7 @@ void SELECT_LEX::increase_derived_records(ha_rows records) // in worse case none of record will be removed break; default: + // usual UNION result->records+= records; break; } @@ -4740,6 +4741,42 @@ void LEX::restore_set_statement_var() DBUG_VOID_RETURN; } +unit_common_op st_select_lex_unit::common_op() +{ + SELECT_LEX *first= first_select(); + bool first_op= TRUE; + unit_common_op operation= OP_MIX; // if no op + for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) + { + if (sl != first) + { + unit_common_op op; + switch (sl->linkage) + { + case INTERSECT_TYPE: + op= OP_INTERSECT; + break; + case EXCEPT_TYPE: + op= OP_EXCEPT; + break; + default: + op= OP_UNION; + break; + } + if (first_op) + { + operation= op; + first_op= TRUE; + } + else + { + if (operation != op) + operation= OP_MIX; + } + } + } + return operation; +} /* Save explain structures of a UNION. The only variable member is whether the union has "Using filesort". @@ -4776,11 +4813,10 @@ int st_select_lex_unit::save_union_explain(Explain_query *output) Note: Non-merged semi-joins cannot be made out of UNIONs currently, so we dont ever set EXPLAIN_NODE_NON_MERGED_SJ. */ - for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) eu->add_select(sl->select_number); - eu->fake_select_type= "UNION RESULT"; + eu->fake_select_type= unit_operation_text[eu->operation= common_op()]; eu->using_filesort= MY_TEST(global_parameters()->order_list.first); eu->using_tmp= union_needs_tmp_table(); @@ -4836,6 +4872,12 @@ bool LEX::is_partition_management() const } +/** + Exclude last added SELECT_LEX (current) in the UNIT and return pointer in it + (previous become currect) + + @return detached SELECT_LEX or NULL in case of error +*/ SELECT_LEX *LEX::exclude_last_select() { @@ -4857,6 +4899,26 @@ SELECT_LEX *LEX::exclude_last_select() DBUG_RETURN(exclude); } + +/** + Put given (new) SELECT_LEX level below after currect (last) SELECT + + LAST SELECT -> DUMMY SELECT + | + V + NEW UNIT + | + V + NEW SELECT + + SELECT (*LAST*) ... FROM (SELECT (*NEW*) ... ) + + @param nselect Select to put one level below + + @retval TRUE Error + @retval FALSE OK +*/ + bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) { DBUG_ENTER("LEX::add_unit_in_brackets"); @@ -4872,7 +4934,7 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) Name_resolution_context *context= &dummy_select->context; context->init(); - /* add SELECT list*/ + /* add SELECT list*/ Item *item= new (thd->mem_root) Item_field(thd, context, NULL, NULL, "*"); if (item == NULL) @@ -4895,8 +4957,11 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) char buff[10]; LEX_STRING alias; alias.length= my_snprintf(buff, sizeof(buff), - "__%d", dummy_select->select_number); - alias.str= thd->strdup(buff); + "__%u", dummy_select->select_number); + alias.str= thd->strmake(buff, alias.length); + if (!alias.str) + DBUG_RETURN(TRUE); + TABLE_LIST *table_list; if (!(table_list= dummy_select->add_table_to_list(thd, ti, &alias, 0, TL_READ, @@ -4912,6 +4977,15 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) DBUG_RETURN(rc); } + +/** + Checks if we need finish "automatic brackets" mode + + INTERSECT has higher priority then UNION and EXCEPT, so when it is need we + automatically create lower layer for INTERSECT (automatic brackets) and + here we check if we should return back one level up during parsing procedure. +*/ + void LEX::check_automatic_up(enum sub_select_type type) { if (type != INTERSECT_TYPE && |