diff options
Diffstat (limited to 'sql/sql_union.cc')
-rw-r--r-- | sql/sql_union.cc | 104 |
1 files changed, 93 insertions, 11 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc index e8bdbcba2f2..bc99dc497e9 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1294,6 +1294,52 @@ bool init_item_int(THD* thd, Item_int* &item) return true; } +/** + @brief + Look for provision of the select_handler interface by a foreign engine. + This interface must support processing UNITs (multiple SELECTs combined + with UNION/EXCEPT/INTERSECT operators) + + @param thd The thread handler + + @details + The function checks that this is an upper level UNIT and if so looks + through its tables searching for one whose handlerton owns a + create_unit call-back function. If the call of this function returns + a select_handler interface object then the server will push the + query into this engine. + This is a responsibility of the create_unit call-back function to + check whether the engine can execute the query. + + @retval the found select_handler if the search is successful + 0 otherwise +*/ + +select_handler *find_unit_handler(THD *thd, + SELECT_LEX_UNIT *unit) +{ + if (unit->outer_select()) + return nullptr; + + for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + { + if (!(sl->join)) + continue; + for (TABLE_LIST *tbl= sl->join->tables_list; tbl; tbl= tbl->next_local) + { + if (!tbl->table) + continue; + handlerton *ht= tbl->table->file->partition_ht(); + if (!ht->create_unit) + continue; + select_handler *sh= ht->create_unit(thd, unit); + if (sh) + return sh; + } + } + return nullptr; +} + bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg, select_result *sel_result, @@ -1882,6 +1928,13 @@ cont: } } + pushdown_unit= find_unit_handler(thd, this); + if (pushdown_unit) + { + if (unlikely(pushdown_unit->prepare())) + DBUG_RETURN(TRUE); + } + thd->lex->current_select= lex_select_save; DBUG_RETURN(saved_error || thd->is_fatal_error); @@ -2053,6 +2106,7 @@ void st_select_lex_unit::optimize_bag_operation(bool is_outer_distinct) bag_set_op_optimized= true; } +select_handler *find_select_handler(THD *thd, SELECT_LEX *select_lex); /** Run optimization phase. @@ -2141,6 +2195,15 @@ bool st_select_lex_unit::optimize() (lim.is_unlimited() || sl->braces) ? sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union; + if (!this->pushdown_unit) + { + /* + If the UNIT hasn't been pushed down to the engine as a whole, + try to push down partial SELECTs of this UNIT separately + */ + sl->pushdown_select= find_select_handler(thd, sl); + } + saved_error= sl->join->optimize(); } @@ -2158,18 +2221,33 @@ bool st_select_lex_unit::optimize() } -bool st_select_lex_unit::exec() +bool st_select_lex_unit::exec() +{ + DBUG_ENTER("st_select_lex_unit::exec"); + if (executed && !uncacheable && !describe) + DBUG_RETURN(FALSE); + + if (pushdown_unit) + { + create_explain_query_if_not_exists(thd->lex, thd->mem_root); + if (!executed) + save_union_explain(thd->lex->explain); + DBUG_RETURN(pushdown_unit->execute()); + } + + DBUG_RETURN(exec_inner()); +} + + +bool st_select_lex_unit::exec_inner() { SELECT_LEX *lex_select_save= thd->lex->current_select; SELECT_LEX *select_cursor=first_select(); ulonglong add_rows=0; ha_rows examined_rows= 0; bool first_execution= !executed; - DBUG_ENTER("st_select_lex_unit::exec"); bool was_executed= executed; - if (executed && !uncacheable && !describe) - DBUG_RETURN(FALSE); executed= 1; if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item && !item->with_recursive_reference) @@ -2183,7 +2261,7 @@ bool st_select_lex_unit::exec() save_union_explain(thd->lex->explain); if (unlikely(saved_error)) - DBUG_RETURN(saved_error); + return saved_error; if (union_result) { @@ -2200,6 +2278,7 @@ bool st_select_lex_unit::exec() { if (!fake_select_lex && !(with_element && with_element->is_recursive)) union_result->cleanup(); + for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { ha_rows records_at_start= 0; @@ -2259,8 +2338,8 @@ bool st_select_lex_unit::exec() { // This is UNION DISTINCT, so there should be a fake_select_lex DBUG_ASSERT(fake_select_lex != NULL); - if (unlikely(table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))) - DBUG_RETURN(TRUE); + if (unlikely(table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))) + return true; table->no_keyread=1; } if (!sl->tvc) @@ -2272,14 +2351,14 @@ bool st_select_lex_unit::exec() if (union_result->flush()) { thd->lex->current_select= lex_select_save; - DBUG_RETURN(1); + return true; } } } if (unlikely(saved_error)) { thd->lex->current_select= lex_select_save; - DBUG_RETURN(saved_error); + return saved_error; } if (fake_select_lex != NULL) { @@ -2288,7 +2367,7 @@ bool st_select_lex_unit::exec() if (unlikely(error)) { table->file->print_error(error, MYF(0)); - DBUG_RETURN(1); + return true; } } if (found_rows_for_union && !sl->braces && @@ -2430,7 +2509,7 @@ bool st_select_lex_unit::exec() thd->lex->current_select= lex_select_save; err: thd->lex->set_limit_rows_examined(); - DBUG_RETURN(saved_error); + return saved_error; } @@ -2659,6 +2738,9 @@ bool st_select_lex_unit::cleanup() } } + delete pushdown_unit; + pushdown_unit= nullptr; + DBUG_RETURN(error); } |