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.cc105
1 files changed, 61 insertions, 44 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 75fd9be88bd..7ac5c23a54d 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -112,6 +112,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
SELECT_LEX *sl, *first_select;
select_result *tmp_result;
+ ORDER *tmp_order;
DBUG_ENTER("st_select_lex_unit::prepare");
/*
@@ -150,12 +151,12 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
JOIN *join= new JOIN(thd_arg, sl->item_list,
sl->options | thd_arg->options | additional_options,
tmp_result);
+ if (!join)
+ goto err;
+
thd_arg->lex->current_select= sl;
- offset_limit_cnt= sl->offset_limit;
- select_limit_cnt= sl->select_limit+sl->offset_limit;
- if (select_limit_cnt < sl->select_limit)
- select_limit_cnt= HA_POS_ERROR; // no limit
- if (select_limit_cnt == HA_POS_ERROR || sl->braces)
+ set_limit(sl, sl);
+ if (sl->braces)
sl->options&= ~OPTION_FOUND_ROWS;
res= join->prepare(&sl->ref_pointer_array,
@@ -178,6 +179,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
Item *item_tmp;
while ((item_tmp= it++))
{
+ /* Error's in 'new' will be detected after loop */
types.push_back(new Item_type_holder(thd_arg, item_tmp));
}
@@ -203,12 +205,14 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
}
+ item_list.empty();
+ // it is not single select
if (first_select->next_select())
{
union_result->tmp_table_param.field_count= types.elements;
if (!(table= create_tmp_table(thd_arg,
&union_result->tmp_table_param, types,
- (ORDER*) 0, !union_option, 1,
+ (ORDER*) 0, union_distinct, 1,
(first_select_in_union()->options |
thd_arg->options |
TMP_TABLE_ALL_COLUMNS),
@@ -222,15 +226,25 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
result_table_list.table= table;
union_result->set_table(table);
- item_list.empty();
thd_arg->lex->current_select= lex_select_save;
{
+ Statement *stmt= thd->current_statement;
+ Statement backup;
+ if (stmt)
+ thd->set_n_backup_item_arena(stmt, &backup);
Field **field;
for (field= table->field; *field; field++)
{
- if (item_list.push_back(new Item_field(*field)))
+ Item_field *item= new Item_field(*field);
+ if (!item || item_list.push_back(item))
+ {
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
DBUG_RETURN(-1);
+ }
}
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
}
}
else
@@ -265,6 +279,8 @@ int st_select_lex_unit::exec()
item->reset();
table->file->delete_all_rows();
}
+ if (union_distinct) // for subselects
+ table->file->extra(HA_EXTRA_CHANGE_KEY_TO_UNIQUE);
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
ha_rows records_at_start= 0;
@@ -309,33 +325,14 @@ int st_select_lex_unit::exec()
sl->options|= found_rows_for_union;
}
sl->join->select_options=sl->options;
- /*
- As far as union share table space we should reassign table map,
- which can be spoiled by 'prepare' of JOIN of other UNION parts
- if it use same tables
- */
- uint tablenr=0;
- for (TABLE_LIST *table_list= (TABLE_LIST*) sl->table_list.first;
- table_list;
- table_list= table_list->next, tablenr++)
- {
- if (table_list->shared)
- {
- /*
- review notes: Check it carefully. I still can't understand
- why I should not touch table->used_keys. For my point of
- view we should do here same procedura as it was done by
- setup_table
- */
- setup_table_map(table_list->table, table_list, tablenr);
- }
- }
res= sl->join->optimize();
}
if (!res)
{
records_at_start= table->file->records;
sl->join->exec();
+ if (sl == union_distinct)
+ table->file->extra(HA_EXTRA_CHANGE_KEY_TO_DUP);
res= sl->join->error;
offset_limit_cnt= sl->offset_limit;
if (!res && union_result->flush())
@@ -376,18 +373,13 @@ int st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM
{
- ulong options_tmp= thd->options;
thd->lex->current_select= fake_select_lex;
- offset_limit_cnt= global_parameters->offset_limit;
- select_limit_cnt= global_parameters->select_limit +
- global_parameters->offset_limit;
-
- if (select_limit_cnt < global_parameters->select_limit)
- select_limit_cnt= HA_POS_ERROR; // no limit
- if (select_limit_cnt == HA_POS_ERROR)
- options_tmp&= ~OPTION_FOUND_ROWS;
- else if (found_rows_for_union && !thd->lex->describe)
- options_tmp|= OPTION_FOUND_ROWS;
+ fake_select_lex->options= thd->options;
+ set_limit(global_parameters, fake_select_lex);
+
+ if (found_rows_for_union && !thd->lex->describe &&
+ select_limit_cnt != HA_POS_ERROR)
+ fake_select_lex->options|= OPTION_FOUND_ROWS;
fake_select_lex->ftfunc_list= &empty_list;
fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
(byte **)
@@ -399,7 +391,10 @@ int st_select_lex_unit::exec()
allocate JOIN for fake select only once (privent
mysql_select automatic allocation)
*/
- fake_select_lex->join= new JOIN(thd, item_list, thd->options, result);
+ if (!(fake_select_lex->join= new JOIN(thd, item_list,
+ fake_select_lex->options, result)))
+ DBUG_RETURN(-1);
+
/*
Fake st_select_lex should have item list for correctref_array
allocation.
@@ -414,7 +409,7 @@ int st_select_lex_unit::exec()
delete tab->select;
delete tab->quick;
}
- join->init(thd, item_list, thd->options, result);
+ join->init(thd, item_list, fake_select_lex->options, result);
}
res= mysql_select(thd, &fake_select_lex->ref_pointer_array,
&result_table_list,
@@ -422,7 +417,7 @@ int st_select_lex_unit::exec()
global_parameters->order_list.elements,
(ORDER*)global_parameters->order_list.first,
(ORDER*) NULL, NULL, (ORDER*) NULL,
- options_tmp | SELECT_NO_UNLOCK,
+ fake_select_lex->options | SELECT_NO_UNLOCK,
result, this, fake_select_lex);
if (!res)
thd->limit_found_rows = (ulonglong)table->file->records + add_rows;
@@ -446,7 +441,7 @@ int st_select_lex_unit::cleanup()
{
DBUG_RETURN(0);
}
- cleaned= 0;
+ cleaned= 1;
if (union_result)
{
@@ -474,3 +469,25 @@ int st_select_lex_unit::cleanup()
}
DBUG_RETURN(error);
}
+
+
+void st_select_lex_unit::reinit_exec_mechanism()
+{
+ prepared= optimized= executed= 0;
+#ifndef DBUG_OFF
+ if (first_select()->next_select())
+ {
+ List_iterator_fast<Item> it(item_list);
+ Item *field;
+ while ((field= it++))
+ {
+ /*
+ we can't cleanup here, because it broke link to temporary table field,
+ but have to drop fixed flag to allow next fix_field of this field
+ during re-executing
+ */
+ field->fixed= 0;
+ }
+ }
+#endif
+}