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.cc107
1 files changed, 93 insertions, 14 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 374e92c6a52..68419708182 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -105,6 +105,7 @@ bool select_union::flush()
options create options
table_alias name of the temporary table
bit_fields_as_long convert bit fields to ulonglong
+ create_table whether to physically create result table
DESCRIPTION
Create a temporary table that is used to store the result of a UNION,
@@ -119,7 +120,7 @@ bool
select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
bool is_union_distinct, ulonglong options,
const char *alias,
- bool bit_fields_as_long)
+ bool bit_fields_as_long, bool create_table)
{
DBUG_ASSERT(table == 0);
tmp_table_param.init();
@@ -128,10 +129,14 @@ select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1,
- options, HA_POS_ERROR, (char*) alias)))
+ options, HA_POS_ERROR, (char*) alias,
+ !create_table)))
return TRUE;
- table->file->extra(HA_EXTRA_WRITE_CACHE);
- table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ if (create_table)
+ {
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ }
return FALSE;
}
@@ -285,6 +290,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
(is_union_select ? (ORDER*) 0 :
(ORDER*) thd_arg->lex->proc_list.first),
sl, this);
+
/* There are no * in the statement anymore (for PS) */
sl->with_wild= 0;
last_procedure= join->procedure;
@@ -347,6 +353,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
List_iterator_fast<Item> tp(types);
Item *type;
ulonglong create_options;
+ uint save_tablenr;
+ table_map save_map;
while ((type= tp++))
{
@@ -399,12 +407,22 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
create_options= create_options | TMP_TABLE_FORCE_MYISAM;
if (union_result->create_result_table(thd, &types, test(union_distinct),
- create_options, "", FALSE))
+ create_options, "", FALSE, TRUE))
goto err;
+ if (fake_select_lex && !fake_select_lex->first_cond_optimization)
+ {
+ save_tablenr= result_table_list.tablenr_exec;
+ save_map= result_table_list.map_exec;
+ }
bzero((char*) &result_table_list, sizeof(result_table_list));
result_table_list.db= (char*) "";
result_table_list.table_name= result_table_list.alias= (char*) "union";
result_table_list.table= table= union_result->table;
+ if (fake_select_lex && !fake_select_lex->first_cond_optimization)
+ {
+ result_table_list.tablenr_exec= save_tablenr;
+ result_table_list.map_exec= save_map;
+ }
thd_arg->lex->current_select= lex_select_save;
if (!item_list.elements)
@@ -469,18 +487,21 @@ err:
}
-bool st_select_lex_unit::exec()
+/**
+ Run optimization phase.
+
+ @return FALSE unit successfully passed optimization phase.
+ @return TRUE an error occur.
+*/
+bool st_select_lex_unit::optimize()
{
SELECT_LEX *lex_select_save= thd->lex->current_select;
SELECT_LEX *select_cursor=first_select();
- ulonglong add_rows=0;
- ha_rows examined_rows= 0;
- DBUG_ENTER("st_select_lex_unit::exec");
+ DBUG_ENTER("st_select_lex_unit::optimize");
- if (executed && !uncacheable && !describe)
+ if (optimized && !uncacheable && !describe)
DBUG_RETURN(FALSE);
- executed= 1;
-
+
if (uncacheable || !item || !item->assigned() || describe)
{
if (item)
@@ -501,7 +522,6 @@ bool st_select_lex_unit::exec()
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
- ha_rows records_at_start= 0;
thd->lex->current_select= sl;
if (optimized)
@@ -528,6 +548,66 @@ bool st_select_lex_unit::exec()
sl->join->select_options=
(select_limit_cnt == HA_POS_ERROR || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
+
+ saved_error= sl->join->optimize();
+ }
+
+ if (saved_error)
+ {
+ thd->lex->current_select= lex_select_save;
+ DBUG_RETURN(saved_error);
+ }
+ }
+ }
+ optimized= 1;
+
+ thd->lex->current_select= lex_select_save;
+ DBUG_RETURN(saved_error);
+}
+
+
+bool st_select_lex_unit::exec()
+{
+ SELECT_LEX *lex_select_save= thd->lex->current_select;
+ SELECT_LEX *select_cursor=first_select();
+ ulonglong add_rows=0;
+ ha_rows examined_rows= 0;
+ DBUG_ENTER("st_select_lex_unit::exec");
+
+ if (executed && !uncacheable && !describe)
+ DBUG_RETURN(FALSE);
+ executed= 1;
+
+ saved_error= optimize();
+
+ if (uncacheable || !item || !item->assigned() || describe)
+ {
+ for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
+ {
+ ha_rows records_at_start= 0;
+ thd->lex->current_select= sl;
+
+ {
+ set_limit(sl);
+ if (sl == global_parameters || describe)
+ {
+ offset_limit_cnt= 0;
+ /*
+ We can't use LIMIT at this stage if we are using ORDER BY for the
+ whole query
+ */
+ if (sl->order_list.first || describe)
+ select_limit_cnt= HA_POS_ERROR;
+ }
+
+ /*
+ When using braces, SQL_CALC_FOUND_ROWS affects the whole query:
+ we don't calculate found_rows() per union part.
+ Otherwise, SQL_CALC_FOUND_ROWS should be done on all sub parts.
+ */
+ sl->join->select_options=
+ (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
+ sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
saved_error= sl->join->optimize();
}
if (!saved_error)
@@ -580,7 +660,6 @@ bool st_select_lex_unit::exec()
}
}
}
- optimized= 1;
/* Send result to 'result' */
saved_error= TRUE;