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.cc328
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);
}