summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc816
1 files changed, 469 insertions, 347 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 5e18299ef87..7e5130e93ab 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -65,7 +65,8 @@ static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
static int return_zero_rows(select_result *res,TABLE_LIST *tables,
List<Item> &fields, bool send_row,
uint select_options, const char *info,
- Item *having, Procedure *proc);
+ Item *having, Procedure *proc,
+ SELECT_LEX_UNIT *unit);
static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
@@ -155,7 +156,20 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
{
int res;
register SELECT_LEX *select_lex = &lex->select_lex;
- if (select_lex->next)
+ if (select_lex->next_select_in_list())
+ {
+ /* Fix tables 'to-be-unioned-from' list to point at opened tables */
+ for (SELECT_LEX *sl= select_lex;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
+ cursor;
+ cursor=cursor->next)
+ cursor->table= cursor->table_list->table;
+ }
+ }
+ if (select_lex->next_select())
res=mysql_union(thd,lex,result);
else
res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first,
@@ -166,7 +180,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
select_lex->having,
(ORDER*) lex->proc_list.first,
select_lex->options | thd->options,
- result);
+ result, &(lex->unit));
if (res && result)
result->abort();
delete result;
@@ -179,49 +193,43 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
** mysql_select assumes that all tables are already opened
*****************************************************************************/
+/*
+ Prepare of whole select (including subselect in future).
+ return -1 on error
+ 0 on success
+*/
int
-mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
- ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
- ulong select_options,select_result *result)
+JOIN::prepare(TABLE_LIST *tables_init,
+ COND *conds_init, ORDER *order_init, ORDER *group_init,
+ Item *having_init,
+ ORDER *proc_param_init, SELECT_LEX *select, SELECT_LEX_UNIT *unit)
{
- TABLE *tmp_table;
- int error, tmp_error;
- bool need_tmp,hidden_group_fields;
- bool simple_order,simple_group,no_order, skip_sort_order, buffer_result;
- Item::cond_result cond_value;
- SQL_SELECT *select;
- DYNAMIC_ARRAY keyuse;
- JOIN join;
- Procedure *procedure;
- List<Item> all_fields(fields);
- bool select_distinct;
- SELECT_LEX *select_lex = &(thd->lex.select_lex);
- SELECT_LEX *cur_sel = thd->lex.select;
- DBUG_ENTER("mysql_select");
-
+ DBUG_ENTER("JOIN::prepare");
+
+ conds= conds_init;
+ order= order_init;
+ group_list= group_init;
+ having= having_init;
+ proc_param= proc_param_init;
+ tables_list= tables_init;
+ select_lex= select;
+ union_part= (unit->first_select()->next_select() != 0);
+
/* Check that all tables, fields, conds and order are ok */
- select_distinct=test(select_options & SELECT_DISTINCT);
- buffer_result=test(select_options & OPTION_BUFFER_RESULT) && !test(select_options & OPTION_FOUND_ROWS);
- tmp_table=0;
- select=0;
- no_order=skip_sort_order=0;
- bzero((char*) &keyuse,sizeof(keyuse));
- thd->proc_info="init";
- thd->used_tables=0; // Updated by setup_fields
-
- if (setup_tables(tables) ||
- setup_fields(thd,tables,fields,1,&all_fields,1) ||
- setup_conds(thd,tables,&conds) ||
- setup_order(thd,tables,fields,all_fields,order) ||
- setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
+ if (setup_tables(tables_list) ||
+ setup_fields(thd,tables_list,fields_list,1,&all_fields,1) ||
+ setup_conds(thd,tables_list,&conds) ||
+ setup_order(thd,tables_list,fields_list,all_fields,order) ||
+ setup_group(thd,tables_list,fields_list,all_fields,group_list,
+ &hidden_group_fields))
DBUG_RETURN(-1); /* purecov: inspected */
if (having)
{
thd->where="having clause";
thd->allow_sum_func=1;
- if (having->fix_fields(thd,tables) || thd->fatal_error)
+ if (having->fix_fields(thd,tables_list) || thd->fatal_error)
DBUG_RETURN(-1); /* purecov: inspected */
if (having->with_sum_func)
having->split_sum_func(all_fields);
@@ -234,13 +242,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
TODO: Add check of calculation of GROUP functions and fields:
SELECT COUNT(*)+table.col1 from table1;
*/
- join.table=0;
- join.tables=0;
{
- if (!group)
+ if (!group_list)
{
uint flag=0;
- List_iterator_fast<Item> it(fields);
+ List_iterator_fast<Item> it(fields_list);
Item *item;
while ((item= it++))
{
@@ -256,22 +262,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
}
TABLE_LIST *table;
- for (table=tables ; table ; table=table->next)
- join.tables++;
+ for (table=tables_list ; table ; table=table->next)
+ tables++;
}
- procedure=setup_procedure(thd,proc_param,result,fields,&error);
+ procedure=setup_procedure(thd,proc_param,result,fields_list,&error);
if (error)
DBUG_RETURN(-1); /* purecov: inspected */
if (procedure)
{
- if (setup_new_fields(thd,tables,fields,all_fields,procedure->param_fields))
+ if (setup_new_fields(thd, tables_list, fields_list, all_fields,
+ procedure->param_fields))
{ /* purecov: inspected */
delete procedure; /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
if (procedure->group)
{
- if (!test_if_subpart(procedure->group,group))
+ if (!test_if_subpart(procedure->group,group_list))
{ /* purecov: inspected */
my_message(0,"Can't handle procedures with differents groups yet",
MYF(0)); /* purecov: inspected */
@@ -280,7 +287,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
}
#ifdef NOT_NEEDED
- else if (!group && procedure->flags & PROC_GROUP)
+ else if (!group_list && procedure->flags & PROC_GROUP)
{
my_message(0,"Select must have a group with this procedure",MYF(0));
delete procedure;
@@ -296,51 +303,53 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
/* Init join struct */
- join.thd=thd;
- join.lock=thd->lock;
- join.join_tab=0;
- join.tmp_table_param.copy_field=0;
- join.sum_funcs=0;
- join.send_records=join.found_records=join.examined_rows=0;
- join.tmp_table_param.end_write_records= HA_POS_ERROR;
- join.first_record=join.sort_and_group=0;
- join.select_options=select_options;
- join.result=result;
- count_field_types(&join.tmp_table_param,all_fields,0);
- join.const_tables=0;
- join.having=0;
- join.do_send_rows = 1;
- join.group= group != 0;
- join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR :
- thd->select_limit);
+ count_field_types(&tmp_table_param, all_fields, 0);
+ this->group= group_list != 0;
+ row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
+ unit->select_limit_cnt);
+ this->unit= unit;
#ifdef RESTRICTED_GROUP
- if (join.sum_func_count && !group && (join.func_count || join.field_count))
+ if (sum_func_count && !group_list && (func_count || field_count))
{
my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
delete procedure;
DBUG_RETURN(-1);
}
#endif
- if (!procedure && result->prepare(fields))
+ if (!procedure && result->prepare(fields_list, unit))
{ /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
+ DBUG_RETURN(0); // All OK
+}
+
+/*
+ global select optimisation.
+ return 0 - success
+ 1 - go out
+ -1 - go out with cleaning
+ error code saved in field 'error'
+*/
+int
+JOIN::optimize()
+{
+ DBUG_ENTER("JOIN::optimize");
#ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */
- if (having && !group && ! join.sum_func_count)
+ if (having && !group_list && ! sum_func_count)
{
if (!conds)
{
- conds=having;
- having=0;
+ conds= having;
+ having= 0;
}
else if ((conds=new Item_cond_and(conds,having)))
{
- conds->fix_fields(thd,tables);
- conds->change_ref_to_fields(thd,tables);
- having=0;
+ conds->fix_fields(thd, tables_list);
+ conds->change_ref_to_fields(thd, tables_list);
+ having= 0;
}
}
#endif
@@ -349,110 +358,87 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
if (thd->fatal_error) // Out of memory
{
delete procedure;
- DBUG_RETURN(0);
+ error = 0;
+ DBUG_RETURN(1);
}
- if (cond_value == Item::COND_FALSE || !thd->select_limit)
+ if (cond_value == Item::COND_FALSE || !unit->select_limit_cnt)
{ /* Impossible cond */
- if (select_options & SELECT_DESCRIBE && select_lex->next)
- select_describe(&join,false,false,false,"Impossible WHERE");
- else
- error=return_zero_rows(result, tables, fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,"Impossible WHERE",having,
- procedure);
- delete procedure;
- DBUG_RETURN(error);
+ zero_result_cause= "Impossible WHERE";
+ DBUG_RETURN(0);
}
/* Optimize count(*), min() and max() */
- if (tables && join.tmp_table_param.sum_func_count && ! group)
+ if (tables_list && tmp_table_param.sum_func_count && ! group_list)
{
int res;
- if ((res=opt_sum_query(tables, all_fields, conds)))
+ if ((res=opt_sum_query(tables_list, all_fields, conds)))
{
if (res < 0)
{
- if (select_options & SELECT_DESCRIBE && select_lex->next)
- select_describe(&join,false,false,false,"No matching min/max row");
- else
- error=return_zero_rows(result, tables, fields, !group,
- select_options,"No matching min/max row",
- having,procedure);
- delete procedure;
- DBUG_RETURN(error);
+ zero_result_cause= "No matching min/max row";
+ DBUG_RETURN(0);
}
if (select_options & SELECT_DESCRIBE)
{
- if (select_lex->next)
- select_describe(&join,false,false,false,"Select tables optimized away");
+ if (union_part)
+ select_describe(this, false, false, false,
+ "Select tables optimized away");
else
- describe_info(thd,"Select tables optimized away");
+ describe_info(thd, "Select tables optimized away");
delete procedure;
- DBUG_RETURN(error);
+ DBUG_RETURN(1);
}
- tables=0; // All tables resolved
+ tables_list= 0; // All tables resolved
}
}
- if (!tables)
- { // Only test of functions
- error=0;
- if (select_options & SELECT_DESCRIBE)
- {
- if (select_lex->next)
- select_describe(&join,false,false,false,"No tables used");
- else
- describe_info(thd,"No tables used");
- }
- else
- {
- result->send_fields(fields,1);
- if (!having || having->val_int())
- {
- if (join.do_send_rows && result->send_data(fields))
- {
- result->send_error(0,NullS); /* purecov: inspected */
- error=1;
- }
- else
- error=(int) result->send_eof();
- }
- else
- error=(int) result->send_eof();
- }
- delete procedure;
- DBUG_RETURN(error);
+
+ if (!tables_list)
+ {
+ test_function_query= 1;
+ DBUG_RETURN(0);
}
- error = -1;
- join.sort_by_table=get_sort_by_table(order,group,tables);
+ error= -1;
+ sort_by_table= get_sort_by_table(order, group_list, tables_list);
/* Calculate how to do the join */
- thd->proc_info="statistics";
- if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error)
- goto err;
- thd->proc_info="preparing";
- result->initialize_tables(&join);
- if (join.const_table_map != join.found_const_table_map &&
+ thd->proc_info= "statistics";
+ if (make_join_statistics(this, tables_list, conds, &keyuse) ||
+ thd->fatal_error)
+ DBUG_RETURN(-1);
+
+ if (select_lex->depended)
+ {
+ /*
+ Just remove all const-table optimization in case of depended query
+ TODO: optimize
+ */
+ const_table_map= 0;
+ const_tables= 0;
+ found_const_table_map= 0;
+ }
+ thd->proc_info= "preparing";
+ result->initialize_tables(this);
+ if (const_table_map != found_const_table_map &&
!(select_options & SELECT_DESCRIBE))
{
- error=return_zero_rows(result,tables,fields,
- join.tmp_table_param.sum_func_count != 0 &&
- !group,0,"",having,procedure);
- goto err;
+ zero_result_cause= "";
+ select_options= 0; //TODO why option in return_zero_rows was droped
+ DBUG_RETURN(0);
}
if (!(thd->options & OPTION_BIG_SELECTS) &&
- join.best_read > (double) thd->max_join_size &&
+ best_read > (double) thd->max_join_size &&
!(select_options & SELECT_DESCRIBE))
{ /* purecov: inspected */
result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */
error= 1; /* purecov: inspected */
- goto err; /* purecov: inspected */
+ DBUG_RETURN(-1);
}
- if (join.const_tables && !thd->locked_tables &&
+ if (const_tables && !thd->locked_tables &&
!(select_options & SELECT_NO_UNLOCK))
{
TABLE **table, **end;
- for (table=join.table, end=table + join.const_tables ;
+ for (table=this->table, end=table + const_tables ;
table != end;
table++)
{
@@ -464,97 +450,94 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
(*table)->file->index_end();
}
- mysql_unlock_some_tables(thd, join.table,join.const_tables);
+ mysql_unlock_some_tables(thd, this->table, const_tables);
}
- if (!conds && join.outer_join)
+ if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */
conds=new Item_int((longlong) 1,1); // Always true
}
- select=make_select(*join.table, join.const_table_map,
- join.const_table_map,conds,&error);
+ select=make_select(*table, const_table_map,
+ const_table_map, conds, &error);
if (error)
{ /* purecov: inspected */
error= -1; /* purecov: inspected */
- goto err; /* purecov: inspected */
- }
- if (make_join_select(&join,select,conds))
- {
- if (select_options & SELECT_DESCRIBE && select_lex->next)
- select_describe(&join,false,false,false,"Impossible WHERE noticed after reading const tables");
- else
- error=return_zero_rows(result,tables,fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,
- "Impossible WHERE noticed after reading const tables",
- having,procedure);
- goto err;
+ DBUG_RETURN(-1);
+ }
+ if (make_join_select(this, select, conds))
+ {
+ zero_result_cause=
+ "Impossible WHERE noticed after reading const tables";
+ DBUG_RETURN(0);
}
error= -1; /* if goto err */
/* Optimize distinct away if possible */
- order=remove_const(&join,order,conds,&simple_order);
- if (group || join.tmp_table_param.sum_func_count)
+ order= remove_const(this, order, conds, &simple_order);
+ if (group_list || tmp_table_param.sum_func_count)
{
if (! hidden_group_fields)
select_distinct=0;
}
- else if (select_distinct && join.tables - join.const_tables == 1 &&
- (thd->select_limit == HA_POS_ERROR ||
- (join.select_options & OPTION_FOUND_ROWS) ||
+ else if (select_distinct && tables - const_tables == 1 &&
+ (unit->select_limit_cnt == HA_POS_ERROR ||
+ (select_options & OPTION_FOUND_ROWS) ||
order &&
!(skip_sort_order=
- test_if_skip_sort_order(&join.join_tab[join.const_tables],
- order, thd->select_limit,1))))
+ test_if_skip_sort_order(&join_tab[const_tables],
+ order,
+ unit->select_limit_cnt,
+ 1))))
{
- if ((group=create_distinct_group(order,fields)))
+ if ((group_list= create_distinct_group(order, fields_list)))
{
- select_distinct=0;
+ select_distinct= 0;
no_order= !order;
- join.group=1; // For end_write_group
+ group= 1; // For end_write_group
}
else if (thd->fatal_error) // End of memory
- goto err;
+ DBUG_RETURN(-1);
}
- group=remove_const(&join,group,conds,&simple_group);
- if (!group && join.group)
+ group_list= remove_const(this, group_list, conds, &simple_group);
+ if (!group_list && group)
{
order=0; // The output has only one row
simple_order=1;
}
- calc_group_buffer(&join,group);
- join.send_group_parts=join.tmp_table_param.group_parts; /* Save org parts */
+ calc_group_buffer(this, group_list);
+ send_group_parts= tmp_table_param.group_parts; /* Save org parts */
if (procedure && procedure->group)
{
- group=procedure->group=remove_const(&join,procedure->group,conds,
- &simple_group);
- calc_group_buffer(&join,group);
+ group_list= procedure->group= remove_const(this, procedure->group, conds,
+ &simple_group);
+ calc_group_buffer(this, group_list);
}
- if (test_if_subpart(group,order) ||
- (!group && join.tmp_table_param.sum_func_count))
+ if (test_if_subpart(group_list, order) ||
+ (!group_list && tmp_table_param.sum_func_count))
order=0;
// Can't use sort on head table if using row cache
- if (join.full_join)
+ if (full_join)
{
- if (group)
+ if (group_list)
simple_group=0;
if (order)
simple_order=0;
}
- need_tmp= (join.const_tables != join.tables &&
+ need_tmp= (const_tables != tables &&
((select_distinct || !simple_order || !simple_group) ||
- (group && order) || buffer_result));
+ (group_list && order) || buffer_result));
// No cache for MATCH
- make_join_readinfo(&join,
+ make_join_readinfo(this,
(select_options & (SELECT_DESCRIBE |
SELECT_NO_JOIN_CACHE)) |
- (cur_sel->ftfunc_list.elements ? SELECT_NO_JOIN_CACHE : 0));
+ (thd->lex.select->ftfunc_list.elements ?
+ SELECT_NO_JOIN_CACHE : 0));
/* Need to tell Innobase that to play it safe, it should fetch all
columns of the tables: this is because MySQL
@@ -563,60 +546,150 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
by MySQL. */
#ifdef HAVE_INNOBASE_DB
- if (need_tmp || select_distinct || group || order)
+ if (need_tmp || select_distinct || group_list || order)
{
- for (uint i_h = join.const_tables; i_h < join.tables; i_h++)
+ for (uint i_h = const_tables; i_h < tables; i_h++)
{
- TABLE* table_h = join.join_tab[i_h].table;
+ TABLE* table_h = join_tab[i_h].table;
if (table_h->db_type == DB_TYPE_INNODB)
table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
}
}
#endif
- DBUG_EXECUTE("info",TEST_join(&join););
+ DBUG_EXECUTE("info",TEST_join(this););
/*
Because filesort always does a full table scan or a quick range scan
we must add the removed reference to the select for the table.
We only need to do this when we have a simple_order or simple_group
as in other cases the join is done before the sort.
*/
- if ((order || group) && join.join_tab[join.const_tables].type != JT_ALL &&
- join.join_tab[join.const_tables].type != JT_FT &&
- (order && simple_order || group && simple_group))
+ if ((order || group_list) && join_tab[const_tables].type != JT_ALL &&
+ join_tab[const_tables].type != JT_FT &&
+ (order && simple_order || group_list && simple_group))
{
- if (add_ref_to_table_cond(thd,&join.join_tab[join.const_tables]))
- goto err;
+ if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
+ DBUG_RETURN(-1);
}
if (!(select_options & SELECT_BIG_RESULT) &&
- ((group && join.const_tables != join.tables &&
+ ((group_list && const_tables != tables &&
(!simple_group ||
- !test_if_skip_sort_order(&join.join_tab[join.const_tables], group,
- thd->select_limit,0))) ||
+ !test_if_skip_sort_order(&join_tab[const_tables], group_list,
+ unit->select_limit_cnt,
+ 0))) ||
select_distinct) &&
- join.tmp_table_param.quick_group && !procedure)
+ tmp_table_param.quick_group && !procedure)
{
need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort
}
+ DBUG_RETURN(0);
+}
+
+/*
+ Global optimization (with subselect) must be here (TODO)
+*/
+
+int
+JOIN::global_optimize()
+{
+ return 0;
+}
+
+int
+JOIN::reinit()
+{
+ DBUG_ENTER("JOIN::reinit");
+ //TODO move to unit reinit
+ unit->offset_limit_cnt =select_lex->offset_limit;
+ unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit;
+ if (unit->select_limit_cnt < select_lex->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // no limit
+ if (unit->select_limit_cnt == HA_POS_ERROR)
+ select_lex->options&= ~OPTION_FOUND_ROWS;
+
+ if (setup_tables(tables_list))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Exec select
+*/
+void
+JOIN::exec()
+{
+ int tmp_error;
+
+ DBUG_ENTER("JOIN::exec");
+
+ if (test_function_query)
+ { // Only test of functions
+ error=0;
+ if (select_options & SELECT_DESCRIBE)
+ {
+ if (union_part)
+ select_describe(this, false, false, false, "No tables used");
+ else
+ describe_info(thd, "No tables used");
+ }
+ else
+ {
+ result->send_fields(fields_list,1);
+ if (!having || having->val_int())
+ {
+ if (do_send_rows && result->send_data(fields_list))
+ {
+ result->send_error(0,NullS); /* purecov: inspected */
+ error=1;
+ }
+ else
+ error=(int) result->send_eof();
+ }
+ else
+ error=(int) result->send_eof();
+ }
+ delete procedure;
+ DBUG_VOID_RETURN;
+ }
+
+ if (zero_result_cause)
+ {
+ if (select_options & SELECT_DESCRIBE && union_part)
+ select_describe(this, false, false, false, zero_result_cause);
+ else
+ error=return_zero_rows(result, tables_list, fields_list,
+ tmp_table_param.sum_func_count != 0 &&
+ !group_list,
+ select_options,
+ zero_result_cause,
+ having,procedure,
+ unit);
+ DBUG_VOID_RETURN;
+ }
+
+ Item *having_list = having;
+ having = 0;
if (select_options & SELECT_DESCRIBE)
{
if (!order && !no_order)
- order=group;
+ order=group_list;
if (order &&
- (join.const_tables == join.tables ||
+ (const_tables == tables ||
(simple_order &&
- test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
- (join.const_tables != join.tables - 1 ||
- (join.select_options & OPTION_FOUND_ROWS)) ?
- HA_POS_ERROR : thd->select_limit,0))))
+ test_if_skip_sort_order(&join_tab[const_tables], order,
+ (const_tables != tables - 1 ||
+ (select_options & OPTION_FOUND_ROWS)) ?
+ HA_POS_ERROR : unit->select_limit_cnt,
+ 0))))
order=0;
- select_describe(&join,need_tmp,
+ select_describe(this, need_tmp,
order != 0 && !skip_sort_order,
select_distinct);
error=0;
- goto err;
+ DBUG_VOID_RETURN;
}
/* Perform FULLTEXT search before all regular searches */
@@ -628,44 +701,45 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
DBUG_PRINT("info",("Creating tmp table"));
thd->proc_info="Creating tmp table";
- if (!(tmp_table =
- create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ if (!(exec_tmp_table =
+ create_tmp_table(thd, &tmp_table_param, all_fields,
((!simple_group && !procedure &&
!(test_flags & TEST_NO_KEY_GROUP)) ?
- group : (ORDER*) 0),
- group ? 0 : select_distinct,
- group && simple_group,
+ group_list : (ORDER*) 0),
+ group_list ? 0 : select_distinct,
+ group_list && simple_group,
(order == 0 || skip_sort_order) &&
- !(join.select_options & OPTION_FOUND_ROWS),
- join.select_options)))
- goto err; /* purecov: inspected */
+ !(select_options & OPTION_FOUND_ROWS),
+ select_options, unit)))
+ DBUG_VOID_RETURN;
- if (having && (join.sort_and_group || (tmp_table->distinct && !group)))
- join.having=having;
+ if (having_list &&
+ (sort_and_group || (exec_tmp_table->distinct && !group_list)))
+ having=having_list;
/* if group or order on first table, sort first */
- if (group && simple_group)
+ if (group_list && simple_group)
{
DBUG_PRINT("info",("Sorting for group"));
thd->proc_info="Sorting for group";
- if (create_sort_index(&join.join_tab[join.const_tables],group,
+ if (create_sort_index(&join_tab[const_tables], group_list,
HA_POS_ERROR) ||
- make_sum_func_list(&join,all_fields) ||
- alloc_group_fields(&join,group))
- goto err;
- group=0;
+ make_sum_func_list(this, all_fields) ||
+ alloc_group_fields(this, group_list))
+ DBUG_VOID_RETURN;
+ group_list=0;
}
else
{
- if (make_sum_func_list(&join,all_fields))
- goto err;
- if (!group && ! tmp_table->distinct && order && simple_order)
+ if (make_sum_func_list(this, all_fields))
+ DBUG_VOID_RETURN;
+ if (!group_list && ! exec_tmp_table->distinct && order && simple_order)
{
DBUG_PRINT("info",("Sorting for order"));
thd->proc_info="Sorting for order";
- if (create_sort_index(&join.join_tab[join.const_tables],order,
- HA_POS_ERROR))
- goto err; /* purecov: inspected */
+ if (create_sort_index(&join_tab[const_tables], order,
+ HA_POS_ERROR))
+ DBUG_VOID_RETURN;
order=0;
}
}
@@ -676,58 +750,58 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
In this case we can stop scanning t2 when we have found one t1.a
*/
- if (tmp_table->distinct)
+ if (exec_tmp_table->distinct)
{
table_map used_tables= thd->used_tables;
- JOIN_TAB *join_tab=join.join_tab+join.tables-1;
+ JOIN_TAB *join_tab= this->join_tab+tables-1;
do
{
if (used_tables & join_tab->table->map)
break;
join_tab->not_used_in_distinct=1;
- } while (join_tab-- != join.join_tab);
+ } while (join_tab-- != this->join_tab);
/* Optimize "select distinct b from t1 order by key_part_1 limit #" */
if (order && skip_sort_order)
{
- (void) test_if_skip_sort_order(&join.join_tab[join.const_tables],
- order, thd->select_limit,0);
+ (void) test_if_skip_sort_order(&this->join_tab[const_tables],
+ order, unit->select_limit_cnt, 0);
order=0;
}
}
/* Copy data to the temporary table */
- thd->proc_info="Copying to tmp table";
- if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0)))
+ thd->proc_info= "Copying to tmp table";
+ if ((tmp_error= do_select(this, (List<Item> *) 0, exec_tmp_table, 0)))
{
- error=tmp_error;
- goto err; /* purecov: inspected */
+ error= tmp_error;
+ DBUG_VOID_RETURN;
}
- if (join.having)
- join.having=having=0; // Allready done
+ if (having)
+ having= having_list= 0; // Allready done
/* Change sum_fields reference to calculated fields in tmp_table */
- if (join.sort_and_group || tmp_table->group)
+ if (sort_and_group || exec_tmp_table->group)
{
if (change_to_use_tmp_fields(all_fields))
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count+
- join.tmp_table_param.func_count;
- join.tmp_table_param.sum_func_count=join.tmp_table_param.func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.sum_func_count+
+ tmp_table_param.func_count;
+ tmp_table_param.sum_func_count= tmp_table_param.func_count= 0;
}
else
{
if (change_refs_to_tmp_fields(thd,all_fields))
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.func_count;
- join.tmp_table_param.func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.func_count;
+ tmp_table_param.func_count= 0;
}
if (procedure)
procedure->update_refs();
- if (tmp_table->group)
+ if (exec_tmp_table->group)
{ // Already grouped
if (!order && !no_order)
- order=group; /* order by group */
- group=0;
+ order= group_list; /* order by group */
+ group_list= 0;
}
/*
@@ -738,153 +812,196 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
** like SEC_TO_TIME(SUM(...)).
*/
- if (group && (!test_if_subpart(group,order) || select_distinct) ||
+ if (group_list && (!test_if_subpart(group_list,order) ||
+ select_distinct) ||
(select_distinct &&
- join.tmp_table_param.using_indirect_summary_function))
+ tmp_table_param.using_indirect_summary_function))
{ /* Must copy to another table */
TABLE *tmp_table2;
DBUG_PRINT("info",("Creating group table"));
/* Free first data from old join */
- join_free(&join);
- if (make_simple_join(&join,tmp_table))
- goto err;
- calc_group_buffer(&join,group);
- count_field_types(&join.tmp_table_param,all_fields,
- select_distinct && !group);
- join.tmp_table_param.hidden_field_count=(all_fields.elements-
- fields.elements);
+ join_free(this);
+ if (make_simple_join(this, exec_tmp_table))
+ DBUG_VOID_RETURN;
+ calc_group_buffer(this, group_list);
+ count_field_types(&tmp_table_param, all_fields,
+ select_distinct && !group_list);
+ tmp_table_param.hidden_field_count= (all_fields.elements-
+ fields_list.elements);
/* group data to new table */
- if (!(tmp_table2 = create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ if (!(tmp_table2 = create_tmp_table(thd, &tmp_table_param, all_fields,
(ORDER*) 0,
- select_distinct && !group,
+ select_distinct && !group_list,
1, 0,
- join.select_options)))
- goto err; /* purecov: inspected */
- if (group)
+ select_options, unit)))
+ DBUG_VOID_RETURN;
+ if (group_list)
{
thd->proc_info="Creating sort index";
- if (create_sort_index(join.join_tab,group,HA_POS_ERROR) ||
- alloc_group_fields(&join,group))
+ if (create_sort_index(join_tab, group_list, HA_POS_ERROR) ||
+ alloc_group_fields(this, group_list))
{
free_tmp_table(thd,tmp_table2); /* purecov: inspected */
- goto err; /* purecov: inspected */
+ DBUG_VOID_RETURN;
}
- group=0;
+ group_list= 0;
}
thd->proc_info="Copying to group table";
tmp_error= -1;
- if (make_sum_func_list(&join,all_fields) ||
- (tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0)))
+ if (make_sum_func_list(this, all_fields) ||
+ (tmp_error=do_select(this, (List<Item> *) 0,tmp_table2,0)))
{
error=tmp_error;
free_tmp_table(thd,tmp_table2);
- goto err; /* purecov: inspected */
+ DBUG_VOID_RETURN;
}
- end_read_record(&join.join_tab->read_record);
- free_tmp_table(thd,tmp_table);
- join.const_tables=join.tables; // Mark free for join_free()
- tmp_table=tmp_table2;
- join.join_tab[0].table=0; // Table is freed
+ end_read_record(&join_tab->read_record);
+ free_tmp_table(thd,exec_tmp_table);
+ const_tables= tables; // Mark free for join_free()
+ exec_tmp_table= tmp_table2;
+ join_tab[0].table= 0; // Table is freed
if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count;
- join.tmp_table_param.sum_func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.sum_func_count;
+ tmp_table_param.sum_func_count= 0;
}
- if (tmp_table->distinct)
+ if (exec_tmp_table->distinct)
select_distinct=0; /* Each row is unique */
- join_free(&join); /* Free quick selects */
- if (select_distinct && ! group)
+ join_free(this); /* Free quick selects */
+ if (select_distinct && ! group_list)
{
thd->proc_info="Removing duplicates";
- if (having)
- having->update_used_tables();
- if (remove_duplicates(&join,tmp_table,fields, having))
- goto err; /* purecov: inspected */
- having=0;
+ if (having_list)
+ having_list->update_used_tables();
+ if (remove_duplicates(this, exec_tmp_table, fields_list, having_list))
+ DBUG_VOID_RETURN;
+ having_list=0;
select_distinct=0;
}
- tmp_table->reginfo.lock_type=TL_UNLOCK;
- if (make_simple_join(&join,tmp_table))
- goto err;
- calc_group_buffer(&join,group);
- count_field_types(&join.tmp_table_param,all_fields,0);
+ exec_tmp_table->reginfo.lock_type=TL_UNLOCK;
+ if (make_simple_join(this, exec_tmp_table))
+ DBUG_VOID_RETURN;
+ calc_group_buffer(this, group_list);
+ count_field_types(&tmp_table_param, all_fields, 0);
}
if (procedure)
{
- if (procedure->change_columns(fields) ||
- result->prepare(fields))
- goto err;
- count_field_types(&join.tmp_table_param,all_fields,0);
+ if (procedure->change_columns(fields_list) ||
+ result->prepare(fields_list, unit))
+ DBUG_VOID_RETURN;
+ count_field_types(&tmp_table_param, all_fields, 0);
}
- if (join.group || join.tmp_table_param.sum_func_count ||
+ if (group || tmp_table_param.sum_func_count ||
(procedure && (procedure->flags & PROC_GROUP)))
{
- alloc_group_fields(&join,group);
- setup_copy_fields(thd, &join.tmp_table_param,all_fields);
- if (make_sum_func_list(&join,all_fields) || thd->fatal_error)
- goto err; /* purecov: inspected */
+ alloc_group_fields(this, group_list);
+ setup_copy_fields(thd, &tmp_table_param,all_fields);
+ if (make_sum_func_list(this, all_fields) || thd->fatal_error)
+ DBUG_VOID_RETURN;
}
- if (group || order)
+ if (group_list || order)
{
DBUG_PRINT("info",("Sorting for send_fields"));
thd->proc_info="Sorting result";
/* If we have already done the group, add HAVING to sorted table */
- if (having && ! group && ! join.sort_and_group)
+ if (having_list && ! group_list && ! sort_and_group)
{
- having->update_used_tables(); // Some tables may have been const
- JOIN_TAB *table=&join.join_tab[join.const_tables];
- table_map used_tables= join.const_table_map | table->table->map;
+ having_list->update_used_tables(); // Some tables may have been const
+ JOIN_TAB *table= &join_tab[const_tables];
+ table_map used_tables= const_table_map | table->table->map;
- Item* sort_table_cond=make_cond_for_table(having,used_tables,used_tables);
+ Item* sort_table_cond= make_cond_for_table(having_list, used_tables,
+ used_tables);
if (sort_table_cond)
{
if (!table->select)
if (!(table->select=new SQL_SELECT))
- goto err;
+ DBUG_VOID_RETURN;
if (!table->select->cond)
table->select->cond=sort_table_cond;
else // This should never happen
if (!(table->select->cond=new Item_cond_and(table->select->cond,
sort_table_cond)))
- goto err;
+ DBUG_VOID_RETURN;
table->select_cond=table->select->cond;
DBUG_EXECUTE("where",print_where(table->select->cond,
"select and having"););
- having=make_cond_for_table(having,~ (table_map) 0,~used_tables);
+ having_list= make_cond_for_table(having_list, ~ (table_map) 0,
+ ~used_tables);
DBUG_EXECUTE("where",print_where(conds,"having after sort"););
}
}
- if (create_sort_index(&join.join_tab[join.const_tables],
- group ? group : order,
- (having || group ||
- join.const_tables != join.tables - 1 ||
- (join.select_options & OPTION_FOUND_ROWS)) ?
- HA_POS_ERROR : thd->select_limit))
- goto err; /* purecov: inspected */
+ if (create_sort_index(&join_tab[const_tables],
+ group_list ? group_list : order,
+ (having_list || group_list ||
+ const_tables != tables - 1 ||
+ (select_options & OPTION_FOUND_ROWS)) ?
+ HA_POS_ERROR : unit->select_limit_cnt))
+ DBUG_VOID_RETURN;
}
- join.having=having; // Actually a parameter
+ having=having_list; // Actually a parameter
thd->proc_info="Sending data";
- error=do_select(&join,&fields,NULL,procedure);
+ error=do_select(this, &fields_list, NULL, procedure);
+ DBUG_VOID_RETURN;
+}
-err:
- thd->limit_found_rows = join.send_records;
- thd->examined_row_count = join.examined_rows;
- thd->proc_info="end";
- join.lock=0; // It's faster to unlock later
- join_free(&join);
- thd->proc_info="end2"; // QQ
- if (tmp_table)
- free_tmp_table(thd,tmp_table);
- thd->proc_info="end3"; // QQ
+/*
+ Clean up join. Return error that hold JOIN.
+*/
+
+int
+JOIN::cleanup(THD *thd)
+{
+ lock=0; // It's faster to unlock later
+ join_free(this);
+ if (exec_tmp_table)
+ free_tmp_table(thd, exec_tmp_table);
delete select;
delete_dynamic(&keyuse);
delete procedure;
- thd->proc_info="end4"; // QQ
+ return error;
+}
+
+int
+mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
+ ORDER *order, ORDER *group,Item *having, ORDER *proc_param,
+ ulong select_options, select_result *result, SELECT_LEX_UNIT *unit)
+{
+ JOIN *join = new JOIN(thd, fields, select_options, result);
+
+ DBUG_ENTER("mysql_select");
+ thd->proc_info="init";
+ thd->used_tables=0; // Updated by setup_fields
+
+ if (join->prepare(tables, conds, order, group, having, proc_param,
+ &(thd->lex.select_lex), unit))
+ {
+ DBUG_RETURN(-1);
+ }
+ switch(join->optimize())
+ {
+ case 1:
+ DBUG_RETURN(join->error);
+ case -1:
+ goto err;
+ }
+
+ if(join->global_optimize())
+ goto err;
+
+ join->exec();
+
+err:
+ thd->limit_found_rows = join->send_records;
+ thd->examined_row_count = join->examined_rows;
+ thd->proc_info="end";
+ int error= join->cleanup(thd);
+ delete join;
DBUG_RETURN(error);
}
@@ -2480,7 +2597,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if ((tab->keys & ~ tab->const_keys && i > 0) ||
(tab->const_keys && i == join->const_tables &&
- join->thd->select_limit < join->best_positions[i].records_read &&
+ join->unit->select_limit_cnt <
+ join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
/* Join with outer join condition */
@@ -2491,7 +2609,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
(join->select_options &
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
- join->thd->select_limit)) < 0)
+ join->unit->select_limit_cnt)) < 0)
DBUG_RETURN(1); // Impossible range
sel->cond=orig_cond;
}
@@ -2533,7 +2651,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
static void
-make_join_readinfo(JOIN *join,uint options)
+make_join_readinfo(JOIN *join, uint options)
{
uint i;
SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
@@ -2713,7 +2831,9 @@ join_free(JOIN *join)
}
end_read_record(&tab->read_record);
}
- join->table=0;
+ //TODO: is enough join_free at the end of mysql_select?
+ if (!join->select_lex->depended)
+ join->table=0;
}
// We are not using tables anymore
// Unlock all tables. We may be in an INSERT .... SELECT statement.
@@ -2929,7 +3049,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
static int
return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
bool send_row, uint select_options,const char *info,
- Item *having, Procedure *procedure)
+ Item *having, Procedure *procedure, SELECT_LEX_UNIT *unit)
{
DBUG_ENTER("return_zero_rows");
@@ -2940,7 +3060,7 @@ return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
}
if (procedure)
{
- if (result->prepare(fields)) // This hasn't been done yet
+ if (result->prepare(fields, unit)) // This hasn't been done yet
DBUG_RETURN(-1);
}
if (send_row)
@@ -3475,7 +3595,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- bool allow_distinct_limit, ulong select_options)
+ bool allow_distinct_limit, ulong select_options,
+ SELECT_LEX_UNIT *unit)
{
TABLE *table;
uint i,field_count,reclength,null_count,null_pack_length,
@@ -3847,8 +3968,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
test(null_pack_length));
if (allow_distinct_limit)
{
- set_if_smaller(table->max_rows,thd->select_limit);
- param->end_write_records=thd->select_limit;
+ set_if_smaller(table->max_rows, unit->select_limit_cnt);
+ param->end_write_records= unit->select_limit_cnt;
}
else
param->end_write_records= HA_POS_ERROR;
@@ -4894,7 +5015,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
error=join->result->send_data(*join->fields);
if (error)
DBUG_RETURN(-1); /* purecov: inspected */
- if (++join->send_records >= join->thd->select_limit && join->do_send_rows)
+ if (++join->send_records >= join->unit->select_limit_cnt &&
+ join->do_send_rows)
{
if (join->select_options & OPTION_FOUND_ROWS)
{
@@ -4910,8 +5032,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
else
{
- join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->do_send_rows= 0;
+ join->unit->select_limit= HA_POS_ERROR;
DBUG_RETURN(0);
}
}
@@ -4974,13 +5096,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
join->send_records++;
DBUG_RETURN(0);
}
- if (!error && ++join->send_records >= join->thd->select_limit &&
+ if (!error && ++join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
DBUG_RETURN(-3); // Abort nicely
join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->unit->select_limit_cnt = HA_POS_ERROR;
}
}
}
@@ -5061,7 +5183,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!(join->select_options & OPTION_FOUND_ROWS))
DBUG_RETURN(-3);
join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->unit->select_limit_cnt = HA_POS_ERROR;
DBUG_RETURN(0);
}
}
@@ -5760,7 +5882,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
if (!field_count)
{ // only const items
- join->thd->select_limit=1; // Only send first row
+ join->unit->select_limit_cnt= 1; // Only send first row
DBUG_RETURN(0);
}
Field **first_field=entry->field+entry->fields - field_count;
@@ -7162,7 +7284,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
result->send_error(0,NullS);
}
}
- if (!join->thd->lex.select->next)
+ if (!join->thd->lex.select->next_select())
{
save_lock=thd->lock;
thd->lock=(MYSQL_LOCK *)0;