diff options
Diffstat (limited to 'sql/sql_union.cc')
-rw-r--r-- | sql/sql_union.cc | 328 |
1 files changed, 200 insertions, 128 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 60563801d68..1a18759eb5b 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -24,31 +24,104 @@ #include "mysql_priv.h" #include "sql_select.h" +int mysql_union(THD *thd, LEX *lex, select_result *result) +{ + DBUG_ENTER("mysql_union"); + SELECT_LEX_UNIT *unit= &lex->unit; + int res= 0; + if (!(res= unit->prepare(thd, result))) + res= unit->exec(); + res|= unit->cleanup(); + DBUG_RETURN(res); +} + + +/*************************************************************************** +** store records in temporary table for UNION +***************************************************************************/ + +select_union::select_union(TABLE *table_par) + :table(table_par) +{ + bzero((char*) &info,sizeof(info)); + /* + We can always use DUP_IGNORE because the temporary table will only + contain a unique key if we are using not using UNION ALL + */ + info.handle_duplicates= DUP_IGNORE; +} + +select_union::~select_union() +{ +} + + +int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u) +{ + unit= u; + if (save_time_stamp && list.elements != table->fields) + { + my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, + ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); + return -1; + } + return 0; +} + +bool select_union::send_data(List<Item> &values) +{ + if (unit->offset_limit_cnt) + { // using limit offset,count + unit->offset_limit_cnt--; + return 0; + } + fill_record(table->field,values); + if ((write_record(table,&info))) + { + if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0)) + return 1; + } + return 0; +} + +bool select_union::send_eof() +{ + return 0; +} -int mysql_union(THD *thd, LEX *lex,select_result *result) +bool select_union::flush() { - SELECT_LEX *sl; - SELECT_LEX_UNIT *unit= &(lex->unit); - List<Item> item_list; - TABLE *table; - int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0; - int res; - bool found_rows_for_union=false; - TABLE_LIST result_table_list; + int error; + if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) + { + table->file->print_error(error,MYF(0)); + ::send_error(thd); + return 1; + } + return 0; +} + +typedef JOIN * JOIN_P; +int st_select_lex_unit::prepare(THD *thd, select_result *result) +{ + describe=(first_select()->options & SELECT_DESCRIBE) ? 1 : 0; + res= 0; + found_rows_for_union= false; TMP_TABLE_PARAM tmp_table_param; - select_union *union_result; - DBUG_ENTER("mysql_union"); - st_select_lex_node * global; + DBUG_ENTER("st_select_lex_unit::prepare"); + this->thd= thd; + this->result= result; + SELECT_LEX *lex_select_save= thd->lex.select; /* Global option */ - if (((void*)(global= unit->global_parameters)) == ((void*)unit)) + if (((void*)(global_parameters)) == ((void*)this)) { - found_rows_for_union= (lex->select_lex.options & OPTION_FOUND_ROWS && - !describe && global->select_limit); + found_rows_for_union= first_select()->options & OPTION_FOUND_ROWS && + !describe && global_parameters->select_limit; if (found_rows_for_union) - lex->select_lex.options ^= OPTION_FOUND_ROWS; + first_select()->options ^= OPTION_FOUND_ROWS; } - + item_list.empty(); if (describe) { Item *item; @@ -70,26 +143,27 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) else { Item *item; - List_iterator<Item> it(lex->select_lex.item_list); - TABLE_LIST *first_table= (TABLE_LIST*) lex->select_lex.table_list.first; + List_iterator<Item> it(first_select()->item_list); + TABLE_LIST *first_table= (TABLE_LIST*) first_select()->table_list.first; /* Create a list of items that will be in the result set */ while ((item= it++)) if (item_list.push_back(item)) - DBUG_RETURN(-1); + goto err; if (setup_fields(thd,first_table,item_list,0,0,1)) - DBUG_RETURN(-1); + goto err; } bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); tmp_table_param.field_count=item_list.elements; if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, - (ORDER*) 0, !describe & !lex->union_option, + (ORDER*) 0, !describe & + !thd->lex.union_option, 1, 0, - (lex->select_lex.options | thd->options | + (first_select()->options | thd->options | TMP_TABLE_ALL_COLUMNS), - unit))) - DBUG_RETURN(-1); + this))) + goto err; table->file->extra(HA_EXTRA_WRITE_CACHE); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); bzero((char*) &result_table_list,sizeof(result_table_list)); @@ -98,46 +172,90 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) result_table_list.table=table; if (!(union_result=new select_union(table))) - { - res= -1; - goto exit; - } + goto err; + union_result->save_time_stamp=!describe; union_result->tmp_table_param=&tmp_table_param; - for (sl= &lex->select_lex; sl; sl= sl->next_select()) + + // prepare selects + joins.empty(); + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { - lex->select=sl; - unit->offset_limit_cnt= sl->offset_limit; - unit->select_limit_cnt= sl->select_limit+sl->offset_limit; - if (unit->select_limit_cnt < sl->select_limit) - unit->select_limit_cnt= HA_POS_ERROR; // no limit - if (unit->select_limit_cnt == HA_POS_ERROR) + JOIN *join= new JOIN(thd, sl->item_list, + sl->options | thd->options | SELECT_NO_UNLOCK | + ((describe) ? SELECT_DESCRIBE : 0), + union_result); + joins.push_back(new JOIN_P(join)); + thd->lex.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->options&= ~OPTION_FOUND_ROWS; - res= mysql_select(thd, - (TABLE_LIST*) sl->table_list.first, - sl->item_list, - sl->where, - (sl->braces) ? - (ORDER *)sl->order_list.first : (ORDER *) 0, - (ORDER*) sl->group_list.first, - sl->having, - (ORDER*) NULL, - sl->options | thd->options | - SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0), - union_result, unit); - if (res) - goto exit; + res= join->prepare((TABLE_LIST*) sl->table_list.first, + sl->where, + (sl->braces) ? + (ORDER *)sl->order_list.first : (ORDER *) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl, this, 0); + if (res | thd->fatal_error) + goto err; } + thd->lex.select= lex_select_save; + DBUG_RETURN(res | thd->fatal_error); +err: + thd->lex.select= lex_select_save; + DBUG_RETURN(-1); +} + +int st_select_lex_unit::exec() +{ + DBUG_ENTER("st_select_lex_unit::exec"); + if(depended || !item || !item->assigned()) + { + if (optimized && item && item->assigned()) + item->assigned(0); // We will reinit & rexecute unit + SELECT_LEX *lex_select_save= thd->lex.select; + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + thd->lex.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->options&= ~OPTION_FOUND_ROWS; + + if (!optimized) + sl->join->optimize(); + else + sl->join->reinit(); + + sl->join->exec(); + res= sl->join->error; + + if (res) + { + thd->lex.select= lex_select_save; + DBUG_RETURN(res); + } + } + thd->lex.select= lex_select_save; + optimized= 1; + } + if (union_result->flush()) { res= 1; // Error is already sent - goto exit; + DBUG_RETURN(res); } - delete union_result; /* Send result to 'result' */ - lex->select = &lex->select_lex; + thd->lex.select = first_select(); res =-1; { /* Create a list of fields in the temporary table */ @@ -147,7 +265,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) List<Item_func_match> ftfunc_list; ftfunc_list.empty(); #else - thd->lex.select_lex.ftfunc_list.empty(); + List<Item_func_match> empty_list; + empty_list.empty(); + thd->lex.select_lex.ftfunc_list= &empty_list; #endif for (field=table->field ; *field ; field++) @@ -157,93 +277,45 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) } if (!thd->fatal_error) // Check if EOM { - st_select_lex_node * global= unit->global_parameters; - unit->offset_limit_cnt= global->offset_limit; - unit->select_limit_cnt= global->select_limit+global->offset_limit; - if (unit->select_limit_cnt < global->select_limit) - unit->select_limit_cnt= HA_POS_ERROR; // no limit - if (unit->select_limit_cnt == HA_POS_ERROR) + 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) thd->options&= ~OPTION_FOUND_ROWS; if (describe) - unit->select_limit_cnt= HA_POS_ERROR; // no limit + select_limit_cnt= HA_POS_ERROR; // no limit res= mysql_select(thd,&result_table_list, item_list, NULL, - (describe) ? 0 : (ORDER*)global->order_list.first, + (describe) ? + 0: + (ORDER*)global_parameters->order_list.first, (ORDER*) NULL, NULL, (ORDER*) NULL, - thd->options, result, unit); + thd->options, result, this, first_select(), 1); if (found_rows_for_union && !res) thd->limit_found_rows = (ulonglong)table->file->records; } } - -exit: - free_tmp_table(thd,table); + thd->lex.select_lex.ftfunc_list= &thd->lex.select_lex.ftfunc_list_alloc; DBUG_RETURN(res); } - -/*************************************************************************** -** store records in temporary table for UNION -***************************************************************************/ - -select_union::select_union(TABLE *table_par) - :table(table_par) +int st_select_lex_unit::cleanup() { - bzero((char*) &info,sizeof(info)); - /* - We can always use DUP_IGNORE because the temporary table will only - contain a unique key if we are using not using UNION ALL - */ - info.handle_duplicates= DUP_IGNORE; -} - -select_union::~select_union() -{ -} - - -int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u) -{ - unit= u; - if (save_time_stamp && list.elements != table->fields) - { - my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, - ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); - return -1; - } - return 0; -} - -bool select_union::send_data(List<Item> &values) -{ - if (unit->offset_limit_cnt) - { // using limit offset,count - unit->offset_limit_cnt--; - return 0; - } - - fill_record(table->field,values); - if ((write_record(table,&info))) - { - if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0)) - return 1; - } - return 0; -} - -bool select_union::send_eof() -{ - return 0; -} - -bool select_union::flush() -{ - int error; - if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) + DBUG_ENTER("st_select_lex_unit::cleanup"); + delete union_result; + free_tmp_table(thd,table); + table= 0; // Safety + + List_iterator<JOIN*> j(joins); + JOIN** join; + while ((join= j++)) { - table->file->print_error(error,MYF(0)); - ::send_error(thd); - return 1; + (*join)->cleanup(thd); + delete *join; + delete join; } - return 0; + joins.empty(); + DBUG_RETURN(0); } |