summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_select.h10
-rw-r--r--sql/sql_union.cc57
3 files changed, 51 insertions, 18 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c62a19b2752..ebc48c2967c 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2416,7 +2416,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
if ((table->s->system || table->file->records <= 1) && ! s->dependent &&
!(table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
- !table->fulltext_searched)
+ !table->fulltext_searched && !join->no_const_tables)
{
set_position(join,const_count++,s,(KEYUSE*) 0);
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 4f9f6e9ed48..5be4f111bef 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -277,6 +277,14 @@ public:
SELECT_LEX_UNIT *unit;
// select that processed
SELECT_LEX *select_lex;
+ /*
+ TRUE <=> optimizer must not mark any table as a constant table.
+ This is needed for subqueries in form "a IN (SELECT .. UNION SELECT ..):
+ when we optimize the select that reads the results of the union from a
+ temporary table, we must not mark the temp. table as constant because
+ the number of rows in it may vary from one subquery execution to another.
+ */
+ bool no_const_tables;
JOIN *tmp_join; // copy of this JOIN to be used with temporary tables
ROLLUP rollup; // Used with rollup
@@ -397,6 +405,8 @@ public:
tmp_table_param.init();
tmp_table_param.end_write_records= HA_POS_ERROR;
rollup.state= ROLLUP::STATE_NONE;
+
+ no_const_tables= FALSE;
}
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 373b03d45e6..16c4eeab4bb 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -545,6 +545,10 @@ bool st_select_lex_unit::exec()
/*
allocate JOIN for fake select only once (prevent
mysql_select automatic allocation)
+ TODO: The above is nonsense. mysql_select() will not allocate the
+ join if one already exists. There must be some other reason why we
+ don't let it allocate the join. Perhaps this is because we need
+ some special parameter values passed to join constructor?
*/
if (!(fake_select_lex->join= new JOIN(thd, item_list,
fake_select_lex->options, result)))
@@ -552,33 +556,52 @@ bool st_select_lex_unit::exec()
fake_select_lex->table_list.empty();
DBUG_RETURN(TRUE);
}
+ fake_select_lex->join->no_const_tables= TRUE;
/*
Fake st_select_lex should have item list for correctref_array
allocation.
*/
fake_select_lex->item_list= item_list;
+ saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
+ &result_table_list,
+ 0, item_list, NULL,
+ global_parameters->order_list.elements,
+ (ORDER*)global_parameters->order_list.first,
+ (ORDER*) NULL, NULL, (ORDER*) NULL,
+ fake_select_lex->options | SELECT_NO_UNLOCK,
+ result, this, fake_select_lex);
}
else
{
- JOIN_TAB *tab,*end;
- for (tab=join->join_tab, end=tab+join->tables ;
- tab && tab != end ;
- tab++)
- {
- delete tab->select;
- delete tab->quick;
- }
- join->init(thd, item_list, fake_select_lex->options, result);
+ if (describe)
+ {
+ /*
+ In EXPLAIN command, constant subqueries that do not use any
+ tables are executed two times:
+ - 1st time is a real evaluation to get the subquery value
+ - 2nd time is to produce EXPLAIN output rows.
+ 1st execution sets certain members (e.g. select_result) to perform
+ subquery execution rather than EXPLAIN line production. In order
+ to reset them back, we re-do all of the actions (yes it is ugly):
+ */
+ join->init(thd, item_list, fake_select_lex->options, result);
+ saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
+ &result_table_list,
+ 0, item_list, NULL,
+ global_parameters->order_list.elements,
+ (ORDER*)global_parameters->order_list.first,
+ (ORDER*) NULL, NULL, (ORDER*) NULL,
+ fake_select_lex->options | SELECT_NO_UNLOCK,
+ result, this, fake_select_lex);
+ }
+ else
+ {
+ join->examined_rows= 0;
+ join->reinit();
+ saved_error= join->exec();
+ }
}
- saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
- &result_table_list,
- 0, item_list, NULL,
- global_parameters->order_list.elements,
- (ORDER*)global_parameters->order_list.first,
- (ORDER*) NULL, NULL, (ORDER*) NULL,
- fake_select_lex->options | SELECT_NO_UNLOCK,
- result, this, fake_select_lex);
fake_select_lex->table_list.empty();
if (!saved_error)