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