summaryrefslogtreecommitdiff
path: root/sql/opt_subselect.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/opt_subselect.cc')
-rw-r--r--sql/opt_subselect.cc140
1 files changed, 99 insertions, 41 deletions
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 0ad90e2ef3d..3d470b6ff5c 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -617,6 +617,18 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
thd->stmt_arena->state != Query_arena::PREPARED)
*/
{
+ SELECT_LEX *current= thd->lex->current_select;
+ thd->lex->current_select= current->return_after_parsing();
+ char const *save_where= thd->where;
+ thd->where= "IN/ALL/ANY subquery";
+
+ bool failure= !in_subs->left_expr->fixed &&
+ in_subs->left_expr->fix_fields(thd, &in_subs->left_expr);
+ thd->lex->current_select= current;
+ thd->where= save_where;
+ if (failure)
+ DBUG_RETURN(-1); /* purecov: deadcode */
+
/*
Check if the left and right expressions have the same # of
columns, i.e. we don't have a case like
@@ -630,18 +642,6 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
my_error(ER_OPERAND_COLUMNS, MYF(0), in_subs->left_expr->cols());
DBUG_RETURN(-1);
}
-
- SELECT_LEX *current= thd->lex->current_select;
- thd->lex->current_select= current->return_after_parsing();
- char const *save_where= thd->where;
- thd->where= "IN/ALL/ANY subquery";
-
- bool failure= !in_subs->left_expr->fixed &&
- in_subs->left_expr->fix_fields(thd, &in_subs->left_expr);
- thd->lex->current_select= current;
- thd->where= save_where;
- if (failure)
- DBUG_RETURN(-1); /* purecov: deadcode */
}
DBUG_PRINT("info", ("Checking if subq can be converted to semi-join"));
@@ -704,6 +704,12 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
if (!optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS) &&
!optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION))
my_error(ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES, MYF(0));
+ /*
+ Transform each subquery predicate according to its overloaded
+ transformer.
+ */
+ if (subselect->select_transformer(join))
+ DBUG_RETURN(-1);
/*
If the subquery predicate is IN/=ANY, analyse and set all possible
@@ -755,12 +761,6 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
allany_subs->add_strategy(strategy);
}
- /*
- Transform each subquery predicate according to its overloaded
- transformer.
- */
- if (subselect->select_transformer(join))
- DBUG_RETURN(-1);
}
}
DBUG_RETURN(0);
@@ -1593,8 +1593,19 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
if (subq_pred->left_expr->cols() == 1)
{
nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr);
+ /*
+ Create Item_func_eq. Note that
+ 1. this is done on the statement, not execution, arena
+ 2. if it's a PS then this happens only once - on the first execution.
+ On following re-executions, the item will be fix_field-ed normally.
+ 3. Thus it should be created as if it was fix_field'ed, in particular
+ all pointers to items in the execution arena should be protected
+ with thd->change_item_tree
+ */
Item_func_eq *item_eq=
- new Item_func_eq(subq_pred->left_expr, subq_lex->ref_pointer_array[0]);
+ new Item_func_eq(subq_pred->left_expr_orig, subq_lex->ref_pointer_array[0]);
+ if (subq_pred->left_expr_orig != subq_pred->left_expr)
+ thd->change_item_tree(item_eq->arguments(), subq_pred->left_expr);
item_eq->in_equality_no= 0;
sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
}
@@ -4362,6 +4373,74 @@ int init_dups_weedout(JOIN *join, uint first_table, int first_fanout_table, uint
/*
+ @brief
+ Set up semi-join Loose Scan strategy for execution
+
+ @detail
+ Other strategies are done in setup_semijoin_dups_elimination(),
+ however, we need to set up Loose Scan earlier, before make_join_select is
+ called. This is to prevent make_join_select() from switching full index
+ scans into quick selects (which will break Loose Scan access).
+
+ @return
+ 0 OK
+ 1 Error
+*/
+
+int setup_semijoin_loosescan(JOIN *join)
+{
+ uint i;
+ DBUG_ENTER("setup_semijoin_loosescan");
+
+ POSITION *pos= join->best_positions + join->const_tables;
+ for (i= join->const_tables ; i < join->top_join_tab_count; )
+ {
+ JOIN_TAB *tab=join->join_tab + i;
+ switch (pos->sj_strategy) {
+ case SJ_OPT_MATERIALIZE:
+ case SJ_OPT_MATERIALIZE_SCAN:
+ i+= 1; /* join tabs are embedded in the nest */
+ pos += pos->n_sj_tables;
+ break;
+ case SJ_OPT_LOOSE_SCAN:
+ {
+ /* We jump from the last table to the first one */
+ tab->loosescan_match_tab= tab + pos->n_sj_tables - 1;
+
+ /* LooseScan requires records to be produced in order */
+ if (tab->select && tab->select->quick)
+ tab->select->quick->need_sorted_output();
+
+ for (uint j= i; j < i + pos->n_sj_tables; j++)
+ join->join_tab[j].inside_loosescan_range= TRUE;
+
+ /* Calculate key length */
+ uint keylen= 0;
+ uint keyno= pos->loosescan_picker.loosescan_key;
+ for (uint kp=0; kp < pos->loosescan_picker.loosescan_parts; kp++)
+ keylen += tab->table->key_info[keyno].key_part[kp].store_length;
+
+ tab->loosescan_key= keyno;
+ tab->loosescan_key_len= keylen;
+ if (pos->n_sj_tables > 1)
+ tab[pos->n_sj_tables - 1].do_firstmatch= tab;
+ i+= pos->n_sj_tables;
+ pos+= pos->n_sj_tables;
+ break;
+ }
+ default:
+ {
+ i++;
+ pos++;
+ break;
+ }
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
Setup the strategies to eliminate semi-join duplicates.
SYNOPSIS
@@ -4469,8 +4548,6 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options,
for (i= join->const_tables ; i < join->top_join_tab_count; )
{
JOIN_TAB *tab=join->join_tab + i;
- //POSITION *pos= join->best_positions + i;
- uint keylen, keyno;
switch (pos->sj_strategy) {
case SJ_OPT_MATERIALIZE:
case SJ_OPT_MATERIALIZE_SCAN:
@@ -4480,26 +4557,7 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options,
break;
case SJ_OPT_LOOSE_SCAN:
{
- /* We jump from the last table to the first one */
- tab->loosescan_match_tab= tab + pos->n_sj_tables - 1;
-
- /* LooseScan requires records to be produced in order */
- if (tab->select && tab->select->quick)
- tab->select->quick->need_sorted_output();
-
- for (uint j= i; j < i + pos->n_sj_tables; j++)
- join->join_tab[j].inside_loosescan_range= TRUE;
-
- /* Calculate key length */
- keylen= 0;
- keyno= pos->loosescan_picker.loosescan_key;
- for (uint kp=0; kp < pos->loosescan_picker.loosescan_parts; kp++)
- keylen += tab->table->key_info[keyno].key_part[kp].store_length;
-
- tab->loosescan_key= keyno;
- tab->loosescan_key_len= keylen;
- if (pos->n_sj_tables > 1)
- tab[pos->n_sj_tables - 1].do_firstmatch= tab;
+ /* Setup already handled by setup_semijoin_loosescan */
i+= pos->n_sj_tables;
pos+= pos->n_sj_tables;
break;