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.cc188
1 files changed, 87 insertions, 101 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index a54fb613fd2..8d36889df76 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -24,14 +24,20 @@
#include "mysql_priv.h"
#include "sql_select.h"
-int mysql_union(THD *thd, LEX *lex, select_result *result,
- SELECT_LEX_UNIT *unit)
+bool mysql_union(THD *thd, LEX *lex, select_result *result,
+ SELECT_LEX_UNIT *unit, ulong setup_tables_done_option)
{
DBUG_ENTER("mysql_union");
- int res= 0;
- if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK, "")))
+ bool res;
+ if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK |
+ setup_tables_done_option, "")))
res= unit->exec();
- res|= unit->cleanup();
+ if (!res && thd->cursor && thd->cursor->is_open())
+ {
+ thd->cursor->set_unit(unit);
+ }
+ else
+ res|= unit->cleanup();
DBUG_RETURN(res);
}
@@ -43,12 +49,6 @@ int mysql_union(THD *thd, LEX *lex, select_result *result,
select_union::select_union(TABLE *table_par)
:table(table_par)
{
- bzero((char*) &info,sizeof(info));
- /*
- We can always use IGNORE because the temporary table will only
- contain a unique key if we are using not using UNION ALL
- */
- info.ignore= 1;
}
select_union::~select_union()
@@ -65,22 +65,21 @@ int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
bool select_union::send_data(List<Item> &values)
{
+ int error= 0;
if (unit->offset_limit_cnt)
{ // using limit offset,count
unit->offset_limit_cnt--;
return 0;
}
- fill_record(table->field, values, 1);
- if (thd->net.report_error || write_record(table,&info))
+ fill_record(thd, table->field, values, 1);
+ if (thd->net.report_error)
+ return 1;
+
+ if ((error= table->file->write_row(table->record[0])))
{
- if (thd->net.last_errno == ER_RECORD_FILE_FULL)
- {
- thd->clear_error(); // do not report user about table overflow
- if (create_myisam_from_heap(thd, table, &tmp_table_param,
- info.last_errno, 1))
- return 1;
- }
- else
+ /* create_myisam_from_heap will generate error if needed */
+ if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE &&
+ create_myisam_from_heap(thd, table, &tmp_table_param, error, 1))
return 1;
}
return 0;
@@ -98,8 +97,7 @@ bool select_union::flush()
int error;
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{
- table->file->print_error(error,MYF(0));
- ::send_error(thd);
+ table->file->print_error(error, MYF(0));
return 1;
}
return 0;
@@ -117,33 +115,21 @@ bool select_union::flush()
options of SELECT
*/
-ulong
+void
st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
{
- ulong options_tmp= thd->options | fake_select_lex->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->ftfunc_list_alloc.empty();
fake_select_lex->ftfunc_list= &fake_select_lex->ftfunc_list_alloc;
fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
(byte **)
- &result_table_list.next);
- return options_tmp;
+ &result_table_list.next_local);
}
-int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
- ulong additional_options,
- const char *tmp_table_alias)
+bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
+ ulong additional_options,
+ const char *tmp_table_alias)
{
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
SELECT_LEX *sl, *first_select;
@@ -173,16 +159,16 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (!sl->join->procedure &&
result->prepare(sl->join->fields_list, this))
{
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
sl->join->select_options|= SELECT_DESCRIBE;
sl->join->reinit();
}
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
prepared= 1;
- res= 0;
+ res= FALSE;
thd_arg->lex->current_select= sl= first_select= first_select_in_union();
found_rows_for_union= first_select->options & OPTION_FOUND_ROWS;
@@ -208,22 +194,24 @@ 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);
+ /*
+ setup_tables_done_option should be set only for very first SELECT,
+ because it protect from secont setup_tables call for select-like non
+ select commands (DELETE/INSERT/...) and they use only very first
+ SELECT (for union it can be only INSERT ... SELECT).
+ */
+ additional_options&= ~OPTION_SETUP_TABLES_DONE;
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
- can_skip_order_by= is_union &&
- (!sl->braces || select_limit_cnt == HA_POS_ERROR);
+ can_skip_order_by= is_union && !(sl->braces && sl->explicit_limit);
res= join->prepare(&sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first, sl->with_wild,
sl->where,
- (can_skip_order_by ? 0 : sl->order_list.elements) +
+ (can_skip_order_by ? 0 : sl->order_list.elements) +
sl->group_list.elements,
can_skip_order_by ?
(ORDER*) 0 : (ORDER *)sl->order_list.first,
@@ -235,7 +223,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
/* There are no * in the statement anymore (for PS) */
sl->with_wild= 0;
last_procedure= join->procedure;
- if (res || thd_arg->is_fatal_error)
+
+ if ((res= (res || thd_arg->is_fatal_error)))
goto err;
if (sl == first_select)
{
@@ -273,7 +262,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
while ((type= tp++, item_tmp= it++))
{
if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
}
@@ -287,6 +276,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
List_iterator_fast<Item> tp(types);
Item_arena *arena= thd->current_arena;
Item *type;
+
while ((type= tp++))
{
if (type->result_type() == STRING_RESULT &&
@@ -310,21 +300,17 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
bzero((char*) &result_table_list, sizeof(result_table_list));
result_table_list.db= (char*) "";
- result_table_list.real_name= result_table_list.alias= (char*) "union";
+ result_table_list.table_name= result_table_list.alias= (char*) "union";
result_table_list.table= table;
union_result->set_table(table);
thd_arg->lex->current_select= lex_select_save;
if (!item_list.elements)
{
- /*
- We're in statement prepare or in execution
- of a conventional statement.
- */
+ Field **field;
Item_arena *tmp_arena,backup;
tmp_arena= thd->change_arena_if_needed(&backup);
- Field **field;
for (field= table->field; *field; field++)
{
Item_field *item= new Item_field(*field);
@@ -332,7 +318,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
if (tmp_arena)
thd->restore_backup_item_arena(tmp_arena, &backup);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
if (tmp_arena)
@@ -340,12 +326,16 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (arena->is_stmt_prepare())
{
/* prepare fake select to initialize it correctly */
- (void) init_prepare_fake_select_lex(thd);
+ init_prepare_fake_select_lex(thd);
+ /*
+ Should be done only once (the only item_list per statement).
+ */
+ DBUG_ASSERT(fake_select_lex->join == 0);
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
result)))
{
fake_select_lex->table_list.empty();
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
fake_select_lex->item_list= item_list;
@@ -362,17 +352,17 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
fake_select_lex->table_list.empty();
}
}
- else if (arena->is_stmt_execute())
+ else if (!arena->is_conventional())
{
/*
- We're in execution of a prepared statement: reset field items
- to point at fields from the created temporary table.
+ We're in execution of a prepared statement or stored procedure:
+ reset field items to point at fields from the created temporary table.
*/
List_iterator_fast<Item> it(item_list);
for (Field **field= table->field; *field; field++)
{
Item_field *item_field= (Item_field*) it++;
- DBUG_ASSERT(item_field);
+ DBUG_ASSERT(item_field != 0);
item_field->reset_field(*field);
}
}
@@ -380,15 +370,15 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= lex_select_save;
- DBUG_RETURN(res || thd_arg->is_fatal_error ? 1 : 0);
+ DBUG_RETURN(res || thd_arg->is_fatal_error);
err:
thd_arg->lex->current_select= lex_select_save;
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
-int st_select_lex_unit::exec()
+bool st_select_lex_unit::exec()
{
SELECT_LEX *lex_select_save= thd->lex->current_select;
SELECT_LEX *select_cursor=first_select_in_union();
@@ -397,7 +387,7 @@ int st_select_lex_unit::exec()
DBUG_ENTER("st_select_lex_unit::exec");
if (executed && !uncacheable && !describe)
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
executed= 1;
if (uncacheable || !item || !item->assigned() || describe)
@@ -425,12 +415,8 @@ int st_select_lex_unit::exec()
res= sl->join->reinit();
else
{
- if (sl != global_parameters && !describe)
- {
- offset_limit_cnt= sl->offset_limit;
- select_limit_cnt= sl->select_limit+sl->offset_limit;
- }
- else
+ set_limit(sl);
+ if (sl == global_parameters || describe)
{
offset_limit_cnt= 0;
/*
@@ -439,11 +425,7 @@ int st_select_lex_unit::exec()
*/
if (sl->order_list.first || describe)
select_limit_cnt= HA_POS_ERROR;
- else
- select_limit_cnt= sl->select_limit+sl->offset_limit;
- }
- if (select_limit_cnt < sl->select_limit)
- select_limit_cnt= HA_POS_ERROR; // no limit
+ }
/*
When using braces, SQL_CALC_FOUND_ROWS affects the whole query:
@@ -462,7 +444,7 @@ int st_select_lex_unit::exec()
if (sl == union_distinct)
{
if (table->file->disable_indexes(HA_KEY_SWITCH_ALL))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
table->no_keyread=1;
}
res= sl->join->error;
@@ -501,14 +483,15 @@ int st_select_lex_unit::exec()
optimized= 1;
/* Send result to 'result' */
- res= -1;
+ res= TRUE;
{
List<Item_func_match> empty_list;
empty_list.empty();
if (!thd->is_fatal_error) // Check if EOM
{
- ulong options_tmp= init_prepare_fake_select_lex(thd);
+ set_limit(global_parameters);
+ init_prepare_fake_select_lex(thd);
JOIN *join= fake_select_lex->join;
if (!join)
{
@@ -516,11 +499,11 @@ int st_select_lex_unit::exec()
allocate JOIN for fake select only once (prevent
mysql_select automatic allocation)
*/
- if (!(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)))
{
fake_select_lex->table_list.empty();
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/*
@@ -532,12 +515,14 @@ int st_select_lex_unit::exec()
else
{
JOIN_TAB *tab,*end;
- for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ for (tab=join->join_tab, end=tab+join->tables ;
+ tab && tab != end ;
+ tab++)
{
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,
@@ -545,7 +530,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);
fake_select_lex->table_list.empty();
@@ -565,14 +550,15 @@ int st_select_lex_unit::exec()
}
-int st_select_lex_unit::cleanup()
+bool st_select_lex_unit::cleanup()
{
int error= 0;
+ JOIN *join;
DBUG_ENTER("st_select_lex_unit::cleanup");
if (cleaned)
{
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
cleaned= 1;
@@ -584,9 +570,8 @@ int st_select_lex_unit::cleanup()
free_tmp_table(thd, table);
table= 0; // Safety
}
- JOIN *join;
- SELECT_LEX *sl= first_select_in_union();
- for (; sl; sl= sl->next_select())
+
+ for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
{
if ((join= sl->join))
{
@@ -611,6 +596,7 @@ int st_select_lex_unit::cleanup()
error|= join->cleanup();
delete join;
}
+
DBUG_RETURN(error);
}
@@ -646,19 +632,19 @@ void st_select_lex_unit::reinit_exec_mechanism()
old_result old select_result object
RETURN
- 0 - OK
- -1 - error
+ FALSE - OK
+ TRUE - error
*/
-int st_select_lex_unit::change_result(select_subselect *result,
- select_subselect *old_result)
+bool st_select_lex_unit::change_result(select_subselect *result,
+ select_subselect *old_result)
{
- int res= 0;
+ bool res= FALSE;
for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
{
if (sl->join && sl->join->result == old_result)
- if ((res= sl->join->change_result(result)))
- return (res);
+ if (sl->join->change_result(result))
+ return TRUE;
}
if (fake_select_lex && fake_select_lex->join)
res= fake_select_lex->join->change_result(result);