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.cc196
1 files changed, 118 insertions, 78 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b9162daadaa..20b000392df 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -324,6 +324,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
this->group= group_list != 0;
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
unit->select_limit_cnt);
+ do_send_rows = (unit->select_limit_cnt) ? 1 : 0;
this->unit= unit;
#ifdef RESTRICTED_GROUP
@@ -366,19 +367,24 @@ JOIN::optimize()
{
conds->fix_fields(thd, tables_list, &conds);
conds->change_ref_to_fields(thd, tables_list);
+ conds->top_level_item();
having= 0;
}
}
#endif
- conds=optimize_cond(conds,&cond_value);
- if (thd->fatal_error || thd->net.report_error)
+ conds= optimize_cond(conds,&cond_value);
+ if (thd->fatal_error)
{
+ // quick abort
delete procedure;
- error = 0;
+ error= 0;
DBUG_RETURN(1);
- }
- if (cond_value == Item::COND_FALSE || !unit->select_limit_cnt)
+ } else if (thd->net.report_error)
+ // normal error processing & cleanup
+ DBUG_RETURN(-1);
+
+ if (cond_value == Item::COND_FALSE || (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
{ /* Impossible cond */
zero_result_cause= "Impossible WHERE";
DBUG_RETURN(0);
@@ -395,13 +401,7 @@ JOIN::optimize()
zero_result_cause= "No matching min/max row";
DBUG_RETURN(0);
}
- if (select_options & SELECT_DESCRIBE)
- {
- select_describe(this, false, false, false,
- "Select tables optimized away");
- delete procedure;
- DBUG_RETURN(1);
- }
+ zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
}
}
@@ -663,7 +663,8 @@ JOIN::exec()
{ // Only test of functions
error=0;
if (select_options & SELECT_DESCRIBE)
- select_describe(this, false, false, false, "No tables used");
+ select_describe(this, false, false, false,
+ (zero_result_cause?zero_result_cause:"No tables used"));
else
{
result->send_fields(fields_list,1);
@@ -672,7 +673,10 @@ JOIN::exec()
if (do_send_rows && result->send_data(fields_list))
error= 1;
else
+ {
error= (int) result->send_eof();
+ send_records=1;
+ }
}
else
error=(int) result->send_eof();
@@ -957,6 +961,7 @@ JOIN::exec()
sort_table_cond)))
DBUG_VOID_RETURN;
table->select_cond=table->select->cond;
+ table->select_cond->top_level_item();
DBUG_EXECUTE("where",print_where(table->select->cond,
"select and having"););
having_list= make_cond_for_table(having_list, ~ (table_map) 0,
@@ -994,7 +999,8 @@ JOIN::exec()
}
having=having_list; // Actually a parameter
thd->proc_info="Sending data";
- error=do_select(this, &fields_list, NULL, procedure);
+ error= thd->net.report_error ||
+ do_select(this, &fields_list, NULL, procedure);
DBUG_VOID_RETURN;
}
@@ -1034,6 +1040,24 @@ JOIN::cleanup(THD *thd)
DBUG_RETURN(error);
}
+bool JOIN::check_loop(uint id)
+{
+ DBUG_ENTER("JOIN::check_loop");
+ Item *item;
+ List_iterator<Item> it(all_fields);
+ DBUG_PRINT("info", ("all_fields:"));
+ while ((item= it++))
+ if (item->check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_PRINT("info", ("where:"));
+ if (select_lex->where && select_lex->where->check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_PRINT("info", ("having:"));
+ if (select_lex->having && select_lex->having->check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
int
mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
ORDER *order, ORDER *group,Item *having, ORDER *proc_param,
@@ -1068,6 +1092,23 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
{
DBUG_RETURN(-1);
}
+ if (thd->possible_loops)
+ {
+ Item *item;
+ while(thd->possible_loops->elements)
+ {
+ item= thd->possible_loops->pop();
+ if (item->check_loop(thd->check_loops_counter++))
+ {
+ delete thd->possible_loops;
+ thd->possible_loops= 0;
+ my_message(ER_CYCLIC_REFERENCE, ER(ER_CYCLIC_REFERENCE), MYF(0));
+ return 1;
+ }
+ }
+ delete thd->possible_loops;
+ thd->possible_loops= 0;
+ }
}
switch (join->optimize())
@@ -1078,7 +1119,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
goto err;
}
- if (free_join && join->global_optimize())
+ if (thd->net.report_error || (free_join && join->global_optimize()))
goto err;
join->exec();
@@ -1393,7 +1434,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
select->quick=0;
if (records != HA_POS_ERROR)
{
- s->found_records=records;
+ s->records=s->found_records=records;
s->read_time= (ha_rows) (s->quick ? s->quick->read_time : 0.0);
}
}
@@ -1926,7 +1967,7 @@ static void
find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
double read_time)
{
- ulong rec;
+ ha_rows rec;
double tmp;
THD *thd= join->thd;
@@ -2119,7 +2160,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
records
This gives the formula:
records= (x * (b-a) + a*c-b)/(c-1)
-
+
b = records matched by whole key
a = records matched by first key part (10% of all records?)
c = number of key parts in key
@@ -2188,7 +2229,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{ // Check full join
if (s->on_expr)
{
- tmp=s->found_records; // Can't use read cache
+ tmp=rows2double(s->found_records); // Can't use read cache
}
else
{
@@ -2207,11 +2248,11 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
will ensure that this will be used
*/
best=tmp;
- records=s->found_records;
+ records= rows2double(s->found_records);
best_key=0;
}
}
- join->positions[idx].records_read=(double) records;
+ join->positions[idx].records_read= records;
join->positions[idx].key=best_key;
join->positions[idx].table= s;
if (!best_key && idx == join->const_tables &&
@@ -2548,7 +2589,7 @@ bool
store_val_in_field(Field *field,Item *item)
{
THD *thd=current_thd;
- ulong cuted_fields=thd->cuted_fields;
+ ha_rows cuted_fields=thd->cuted_fields;
thd->count_cuted_fields=1;
(void) item->save_in_field(field);
thd->count_cuted_fields=0;
@@ -2577,8 +2618,8 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join->sum_funcs=0;
join->send_records=(ha_rows) 0;
join->group=0;
- join->do_send_rows = 1;
join->row_limit=join->unit->select_limit_cnt;
+ join->do_send_rows = (join->row_limit) ? 1 : 0;
join_tab->cache.buff=0; /* No cacheing */
join_tab->table=tmp_table;
@@ -2636,7 +2677,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
use_quick_range=1;
tab->use_quick=1;
tab->ref.key_parts=0; // Don't use ref key.
- join->best_positions[i].records_read=tab->quick->records;
+ join->best_positions[i].records_read= rows2double(tab->quick->records);
}
COND *tmp=make_cond_for_table(cond,used_tables,current_map);
@@ -2911,27 +2952,43 @@ join_free(JOIN *join)
*/
if (join->tables > join->const_tables) // Test for not-const tables
free_io_cache(join->table[join->const_tables]);
- for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ if (join->select_lex->dependent)
+ for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ {
+ if (tab->table)
+ {
+ if (tab->table->key_read)
+ {
+ tab->table->key_read= 0;
+ tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ /* Don't free index if we are using read_record */
+ if (!tab->read_record.table)
+ tab->table->file->index_end();
+ }
+ }
+ else
{
- delete tab->select;
- delete tab->quick;
- x_free(tab->cache.buff);
- if (tab->table)
+ for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
{
- if (tab->table->key_read)
+ delete tab->select;
+ delete tab->quick;
+ x_free(tab->cache.buff);
+ if (tab->table)
{
- tab->table->key_read=0;
- tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ if (tab->table->key_read)
+ {
+ tab->table->key_read= 0;
+ tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ /* Don't free index if we are using read_record */
+ if (!tab->read_record.table)
+ tab->table->file->index_end();
}
- /* Don't free index if we are using read_record */
- if (!tab->read_record.table)
- tab->table->file->index_end();
+ end_read_record(&tab->read_record);
}
- end_read_record(&tab->read_record);
+ join->table= 0;
}
- //TODO: is enough join_free at the end of mysql_select?
- if (!join->select_lex->dependent)
- join->table=0;
}
/*
We are not using tables anymore
@@ -3893,7 +3950,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*blob_field= 0; // End marker
/* If result table is small; use a heap */
- if (blob_count || using_unique_constraint || group_null_items ||
+ if (blob_count || using_unique_constraint ||
(select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
OPTION_BIG_TABLES)
{
@@ -4512,7 +4569,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (error == -1)
table->file->print_error(my_errno,MYF(0));
}
- DBUG_RETURN(error);
+ DBUG_RETURN(error || join->thd->net.report_error);
}
@@ -5492,6 +5549,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
else
{
+ if (end_of_records)
+ DBUG_RETURN(0);
join->first_record=1;
VOID(test_if_group_changed(join->group_fields));
}
@@ -5561,6 +5620,7 @@ make_cond_for_table(COND *cond,table_map tables,table_map used_table)
{
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
{
+ /* Create new top level AND item */
Item_cond_and *new_cond=new Item_cond_and;
if (!new_cond)
return (COND*) 0; // OOM /* purecov: inspected */
@@ -5598,6 +5658,7 @@ make_cond_for_table(COND *cond,table_map tables,table_map used_table)
new_cond->argument_list()->push_back(fix);
}
new_cond->used_tables_cache=((Item_cond_or*) cond)->used_tables_cache;
+ new_cond->top_level_item();
return new_cond;
}
}
@@ -5949,6 +6010,7 @@ static bool fix_having(JOIN *join, Item **having)
sort_table_cond)))
return 1;
table->select_cond=table->select->cond;
+ table->select_cond->top_level_item();
DBUG_EXECUTE("where",print_where(table->select_cond,
"select and having"););
*having=make_cond_for_table(*having,~ (table_map) 0,~used_tables);
@@ -7377,56 +7439,32 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
if (tab->use_quick == 2)
{
- sprintf(buff_ptr,"range checked for each record (index map: %u)",
+ sprintf(buff_ptr,"; Range checked for each record (index map: %u)",
tab->keys);
buff_ptr=strend(buff_ptr);
}
else
- buff_ptr=strmov(buff_ptr,"where used");
+ buff_ptr=strmov(buff_ptr,"; Using where");
}
if (key_read)
- {
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Using index");
- }
+ buff_ptr= strmov(buff_ptr,"; Using index");
if (table->reginfo.not_exists_optimize)
- {
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Not exists");
- }
+ buff_ptr= strmov(buff_ptr,"; Not exists");
if (need_tmp_table)
{
need_tmp_table=0;
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Using temporary");
+ buff_ptr= strmov(buff_ptr,"; Using temporary");
}
if (need_order)
{
need_order=0;
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Using filesort");
+ buff_ptr= strmov(buff_ptr,"; Using filesort");
}
if (distinct & test_all_bits(used_tables,thd->used_tables))
- {
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Distinct");
- }
- item_list.push_back(new Item_string(buff,(uint) (buff_ptr - buff),
+ buff_ptr= strmov(buff_ptr,"; Distinct");
+ if (buff_ptr == buff)
+ buff_ptr+= 2; // Skip inital "; "
+ item_list.push_back(new Item_string(buff+2,(uint) (buff_ptr - buff)-2,
default_charset_info));
// For next iteration
used_tables|=table->map;
@@ -7458,8 +7496,10 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
((sl->next_select_in_list())?"PRIMARY":
"SIMPLE"):
((sl == first)?
+ ((sl->linkage == DERIVED_TABLE_TYPE) ?
+ "DERIVED":
((sl->dependent)?"DEPENDENT SUBSELECT":
- "SUBSELECT"):
+ "SUBSELECT")):
((sl->dependent)?"DEPENDENT UNION":
"UNION"))),
result);
@@ -7467,8 +7507,8 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
break;
}
- if (res > 0)
- res= -res; // mysql_explain_select do not report error
+ if (res > 0 || thd->net.report_error)
+ res= -1; // mysql_explain_select do not report error
DBUG_RETURN(res);
}