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.cc130
1 files changed, 79 insertions, 51 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index dfe6f159703..3d9949a2e07 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -54,7 +54,38 @@ int select_unit::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
return 0;
}
+/**
+ This called by SELECT_LEX_UNIT::exec when select chenged
+*/
+
+void select_unit::change_select()
+{
+ uint current_select_number= thd->lex->current_select->select_number;
+ DBUG_ENTER("select_unit::change_select");
+ DBUG_PRINT("enter", ("select in unit change: %u -> %u",
+ curr_sel, current_select_number));
+ DBUG_ASSERT(curr_sel != current_select_number);
+ curr_sel= current_select_number;
+ /* New SELECT processing starts */
+ DBUG_ASSERT(table->file->inited == 0);
+ switch (thd->lex->current_select->linkage)
+ {
+ case INTERSECT_TYPE:
+ case EXCEPT_TYPE:
+ step= thd->lex->current_select->linkage;
+ break;
+ default:
+ step= UNION_TYPE;
+ break;
+ }
+ if (step == INTERSECT_TYPE)
+ {
+ intersect_mark->value= prev_step= curr_step;
+ curr_step= current_select_number;
+ }
+ DBUG_VOID_RETURN;
+}
/**
Fill temporary tables for UNION/EXCEPT/INTERSECT
@@ -82,31 +113,6 @@ int select_unit::send_data(List<Item> &values)
{
int rc;
int not_reported_error= 0;
- if (curr_sel != thd->lex->current_select->select_number)
- {
- curr_sel= thd->lex->current_select->select_number;
- /* New SELECT processing starts */
- DBUG_ASSERT(table->file->inited == 0);
- switch (thd->lex->current_select->linkage)
- {
- case INTERSECT_TYPE:
- step= intersect_step;
- break;
- case EXCEPT_TYPE:
- step= except_step;
- break;
- default:
- step= union_step;
- break;
- }
-
- if (step == intersect_step)
- {
- prev_step= curr_step;
- intersect_mark->value= prev_step;
- curr_step= thd->lex->current_select->select_number;
- }
- }
if (unit->offset_limit_cnt)
{ // using limit offset,count
unit->offset_limit_cnt--;
@@ -117,8 +123,12 @@ int select_unit::send_data(List<Item> &values)
if (table->no_rows_with_nulls)
table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
if (intersect_mark)
- values.push_front(intersect_mark);
- fill_record(thd, table, table->field, values, TRUE, FALSE);
+ {
+ fill_record(thd, table, table->field + 1, values, TRUE, FALSE);
+ table->field[0]->store((ulonglong) curr_step, 1);
+ }
+ else
+ fill_record(thd, table, table->field, values, TRUE, FALSE);
if (thd->is_error())
{
rc= 1;
@@ -134,9 +144,10 @@ int select_unit::send_data(List<Item> &values)
}
}
+ // select_unit::change_select() change step & Co correctly for each SELECT
switch (step)
{
- case union_step:
+ case UNION_TYPE:
{
if ((write_err= table->file->ha_write_tmp_row(table->record[0])))
{
@@ -169,7 +180,7 @@ int select_unit::send_data(List<Item> &values)
}
break;
}
- case except_step:
+ case EXCEPT_TYPE:
{
int find_res;
/*
@@ -185,10 +196,13 @@ int select_unit::send_data(List<Item> &values)
goto end;
}
else
- DBUG_ASSERT(find_res == 1);
+ {
+ if ((rc= not_reported_error= (find_res != 1)))
+ goto end;
+ }
break;
}
- case intersect_step:
+ case INTERSECT_TYPE:
{
int find_res;
/*
@@ -200,10 +214,7 @@ int select_unit::send_data(List<Item> &values)
DBUG_ASSERT(!table->triggers);
if (table->field[0]->val_int() != prev_step)
{
- table->status|= STATUS_DELETED;
- not_reported_error=
- table->file->ha_delete_tmp_row(table->record[0]);
- rc= MY_TEST(not_reported_error);
+ rc= 0;
goto end;
}
store_record(table, record[1]);
@@ -215,9 +226,14 @@ int select_unit::send_data(List<Item> &values)
goto end;
}
else
- DBUG_ASSERT(find_res == 1);
+ {
+ if ((rc= not_reported_error= (find_res != 1)))
+ goto end;
+ }
break;
}
+ default:
+ DBUG_ASSERT(0);
}
rc= 0;
@@ -227,14 +243,12 @@ end:
DBUG_ASSERT(rc);
table->file->print_error(not_reported_error, MYF(0));
}
- if (intersect_mark)
- values.pop();
return rc;
}
bool select_unit::send_eof()
{
- if (step != intersect_step ||
+ if (step != INTERSECT_TYPE ||
(thd->lex->current_select->next_select() &&
thd->lex->current_select->next_select()->linkage == INTERSECT_TYPE))
{
@@ -250,7 +264,7 @@ bool select_unit::send_eof()
It is last select in the sequence of INTERSECTs so we should filter out
all records except marked with actual counter.
- TODO: as optimisation for simple case this could be moved to
+ TODO: as optimization for simple case this could be moved to
'fake_select' WHERE condition
*/
handler *file= table->file;
@@ -262,15 +276,18 @@ bool select_unit::send_eof()
do
{
error= file->ha_rnd_next(table->record[0]);
- if (error == HA_ERR_RECORD_DELETED)
- {
- error= 0;
- continue;
- }
if (error)
{
if (error == HA_ERR_END_OF_FILE)
+ {
+ error= 0;
+ break;
+ }
+ if (unlikely(error == HA_ERR_RECORD_DELETED))
+ {
error= 0;
+ continue;
+ }
break;
}
if (table->field[0]->val_int() != curr_step)
@@ -943,6 +960,12 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
hidden= 1;
if (!intersect_mark)
{
+ /*
+ For intersect we add a hidden column first that contains
+ the current select number of the time when the row was
+ added to the temporary table
+ */
+
Query_arena *arena, backup_arena;
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
@@ -959,14 +982,16 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
types.push_front(union_result->intersect_mark= intersect_mark);
union_result->intersect_mark->name= (char *)"___";
}
- if (union_result->create_result_table(thd, &types,
- MY_TEST(union_distinct),
- create_options, "", false,
- instantiate_tmp_table, false,
- hidden))
- goto err;
+ bool error=
+ union_result->create_result_table(thd, &types,
+ MY_TEST(union_distinct),
+ create_options, "", false,
+ instantiate_tmp_table, false,
+ hidden);
if (intersect_mark)
types.pop();
+ if (error)
+ goto err;
}
if (fake_select_lex && !fake_select_lex->first_cond_optimization)
{
@@ -993,6 +1018,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
saved_error= table->fill_item_list(&item_list);
+ // Item_list is inherited from 'types', so there could be the counter
if (intersect_mark)
item_list.pop(); // remove intersect counter
@@ -1182,6 +1208,8 @@ bool st_select_lex_unit::exec()
{
ha_rows records_at_start= 0;
thd->lex->current_select= sl;
+ if (union_result)
+ union_result->change_select();
if (fake_select_lex)
{
if (sl != &thd->lex->select_lex)