diff options
Diffstat (limited to 'sql/sql_union.cc')
-rw-r--r-- | sql/sql_union.cc | 130 |
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) |