summaryrefslogtreecommitdiff
path: root/sql/sql_union.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_union.cc')
-rw-r--r--sql/sql_union.cc104
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);
}