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.cc502
1 files changed, 382 insertions, 120 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 66be0a2e4c2..5eb5333a06c 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -50,8 +50,8 @@ const char *copy_to_tmp_table= "Copying to tmp table";
struct st_sargable_param;
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
-static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds,
- DYNAMIC_ARRAY *keyuse);
+static bool make_join_statistics(JOIN *join, List<TABLE_LIST> &leaves,
+ COND *conds, DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
JOIN_TAB *join_tab,
uint tables, COND *conds,
@@ -100,7 +100,8 @@ static void update_depend_map(JOIN *join);
static void update_depend_map(JOIN *join, ORDER *order);
static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
bool change_list, bool *simple_order);
-static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables,
+static int return_zero_rows(JOIN *join, select_result *res,
+ List<TABLE_LIST> &tables,
List<Item> &fields, bool send_row,
ulonglong select_options, const char *info,
Item *having);
@@ -211,7 +212,7 @@ static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array,
List<Item> &all_fields,
bool *all_order_by_fields_used);
static bool test_if_subpart(ORDER *a,ORDER *b);
-static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
+static TABLE *get_sort_by_table(ORDER *a,ORDER *b,List<TABLE_LIST> &tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
static bool make_group_fields(JOIN *main_join, JOIN *curr_join);
static bool alloc_group_fields(JOIN *join,ORDER *group);
@@ -236,6 +237,7 @@ static void select_describe(JOIN *join, bool need_tmp_table,bool need_order,
bool distinct, const char *message=NullS);
static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab);
static uint make_join_orderinfo(JOIN *join);
+static bool generate_derived_keys(DYNAMIC_ARRAY *keyuse_array);
static int
join_read_record_no_init(JOIN_TAB *tab);
@@ -426,7 +428,7 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
*/
inline int setup_without_group(THD *thd, Item **ref_pointer_array,
TABLE_LIST *tables,
- TABLE_LIST *leaves,
+ List<TABLE_LIST> &leaves,
List<Item> &fields,
List<Item> &all_fields,
COND **conds,
@@ -504,21 +506,22 @@ JOIN::prepare(Item ***rref_pointer_array,
join_list= &select_lex->top_join_list;
union_part= unit_arg->is_union();
+ if (select_lex->handle_derived(thd->lex, DT_PREPARE))
+ DBUG_RETURN(1);
+
thd->lex->current_select->is_item_list_lookup= 1;
/*
If we have already executed SELECT, then it have not sense to prevent
its table from update (see unique_table())
+ Affects only materialized derived tables.
*/
- if (thd->derived_tables_processing)
- select_lex->exclude_from_table_unique_test= TRUE;
-
/* Check that all tables, fields, conds and order are ok */
-
if (!(select_options & OPTION_SETUP_TABLES_DONE) &&
setup_tables_and_check_access(thd, &select_lex->context, join_list,
- tables_list, &select_lex->leaf_tables,
- FALSE, SELECT_ACL, SELECT_ACL))
+ tables_list, select_lex->leaf_tables,
+ FALSE, SELECT_ACL, SELECT_ACL, FALSE))
DBUG_RETURN(-1);
+
/*
TRUE if the SELECT list mixes elements with and without grouping,
and there is no GROUP BY clause. Mixing non-aggregated fields with
@@ -547,10 +550,12 @@ JOIN::prepare(Item ***rref_pointer_array,
}
}
}
+
+ tables= select_lex->leaf_tables.elements;
- for (TABLE_LIST *table_ptr= select_lex->leaf_tables;
- table_ptr;
- table_ptr= table_ptr->next_leaf)
+ TABLE_LIST *tbl;
+ List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
+ while ((tbl= li++))
{
tables++; /* Count the number of tables in the join. */
/*
@@ -560,7 +565,7 @@ JOIN::prepare(Item ***rref_pointer_array,
semantic analysis to take into account this change of nullability.
*/
if (mixed_implicit_grouping)
- table_ptr->table->maybe_null= 1;
+ tbl->table->maybe_null= 1;
}
if ((wild_num && setup_wild(thd, tables_list, fields_list, &all_fields,
@@ -678,10 +683,6 @@ JOIN::prepare(Item ***rref_pointer_array,
}
}
- if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
- DBUG_RETURN(-1);
-
-
/*
Check if there are references to un-aggregated columns when computing
aggregate functions with implicit grouping (there is no GROUP BY).
@@ -815,16 +816,44 @@ JOIN::optimize()
if (optimized)
DBUG_RETURN(0);
optimized= 1;
-
thd_proc_info(thd, "optimizing");
set_allowed_join_cache_types();
- /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
- if (transform_max_min_subquery() ||
- convert_join_subqueries_to_semijoins(this))
+ /* Run optimize phase for all derived tables/views used in this SELECT. */
+ if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
+ DBUG_RETURN(1);
+
+ if (select_lex->first_cond_optimization)
+ {
+ //Do it only for the first execution
+ /* Merge all mergeable derived tables/views in this SELECT. */
+ if (select_lex->handle_derived(thd->lex, DT_MERGE))
+ DBUG_RETURN(TRUE);
+ tables= select_lex->leaf_tables.elements;
+ select_lex->update_used_tables();
+ }
+
+ if (transform_max_min_subquery())
DBUG_RETURN(1); /* purecov: inspected */
- /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
+
+ if (select_lex->first_cond_optimization)
+ {
+ /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
+ if (convert_join_subqueries_to_semijoins(this))
+ DBUG_RETURN(1); /* purecov: inspected */
+ /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
+ select_lex->update_used_tables();
+
+ /* Save this info for the next executions */
+ if (select_lex->save_leaf_tables(thd))
+ DBUG_RETURN(1);
+ }
+
+ tables= select_lex->leaf_tables.elements;
+
+ if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
+ DBUG_RETURN(-1);
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
unit->select_limit_cnt);
@@ -858,7 +887,8 @@ JOIN::optimize()
}
}
#endif
- SELECT_LEX *sel= thd->lex->current_select;
+
+ SELECT_LEX *sel= select_lex;
if (sel->first_cond_optimization)
{
/*
@@ -922,7 +952,8 @@ JOIN::optimize()
#ifdef WITH_PARTITION_STORAGE_ENGINE
{
TABLE_LIST *tbl;
- for (tbl= select_lex->leaf_tables; tbl; tbl= tbl->next_leaf)
+ List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
+ while ((tbl= li++))
{
/*
If tbl->embedding!=NULL that means that this table is in the inner
@@ -1021,6 +1052,8 @@ JOIN::optimize()
DBUG_RETURN(1);
}
+ drop_unused_derived_keys();
+
if (rollup.state != ROLLUP::STATE_NONE)
{
if (rollup_process_const_fields())
@@ -1156,6 +1189,7 @@ JOIN::optimize()
{
zero_result_cause=
"Impossible WHERE noticed after reading const tables";
+ select_lex->mark_const_derived(zero_result_cause);
goto setup_subq_exit;
}
@@ -1485,7 +1519,7 @@ JOIN::optimize()
if (select_options & SELECT_DESCRIBE)
{
error= 0;
- DBUG_RETURN(0);
+ goto derived_exit;
}
having= 0;
@@ -1514,6 +1548,9 @@ setup_subq_exit:
if (optimize_unflattened_subqueries())
DBUG_RETURN(1);
error= 0;
+
+derived_exit:
+ select_lex->mark_const_derived(zero_result_cause);
DBUG_RETURN(0);
}
@@ -2076,6 +2113,11 @@ JOIN::exec()
!tables ? "No tables used" : NullS);
DBUG_VOID_RETURN;
}
+ else
+ {
+ /* it's a const select, materialize it. */
+ select_lex->mark_const_derived(zero_result_cause);
+ }
if (!initialized && init_execution())
DBUG_VOID_RETURN;
@@ -2864,12 +2906,11 @@ typedef struct st_sargable_param
*/
static bool
-make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
- DYNAMIC_ARRAY *keyuse_array)
+make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
+ COND *conds, DYNAMIC_ARRAY *keyuse_array)
{
- int error;
+ int error= 0;
TABLE *table;
- TABLE_LIST *tables= tables_arg;
uint i,table_count,const_count,key;
table_map found_const_table_map, all_table_map, found_ref, refs;
key_map const_ref, eq_part;
@@ -2880,6 +2921,8 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
table_map no_rows_const_tables= 0;
SARGABLE_PARAM *sargables= 0;
JOIN_TAB *stat_vector[MAX_TABLES+1];
+ List_iterator<TABLE_LIST> ti(tables_list);
+ TABLE_LIST *tables;
DBUG_ENTER("make_join_statistics");
table_count=join->tables;
@@ -2895,9 +2938,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
found_const_table_map= all_table_map=0;
const_count=0;
- for (s= stat, i= 0;
- tables;
- s++, tables= tables->next_leaf, i++)
+ for (s= stat, i= 0; (tables= ti++); s++, i++)
{
TABLE_LIST *embedding= tables->embedding;
stat_vector[i]=s;
@@ -2907,7 +2948,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
table->pos_in_table_list= tables;
- error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ error= tables->fetch_number_of_rows();
if (error)
{
table->file->print_error(error, MYF(0));
@@ -2979,6 +3020,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
no_rows_const_tables |= table->map;
}
}
+
stat_vector[i]=0;
join->outer_join=outer_join;
@@ -3251,7 +3293,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
}
/* Approximate found rows and time to read them */
s->found_records=s->records=s->table->file->stats.records;
- s->read_time=(ha_rows) s->table->file->scan_time();
+ s->scan_time();
/*
Set a max range of how many seeks we can expect when using keys
@@ -3336,19 +3378,35 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
if (optimize_semijoin_nests(join, all_table_map))
DBUG_RETURN(TRUE); /* purecov: inspected */
- /* Find an optimal join order of the non-constant tables. */
- if (join->const_tables != join->tables)
- {
- if (choose_plan(join, all_table_map & ~join->const_table_map))
- goto error;
- }
- else
{
- memcpy((uchar*) join->best_positions,(uchar*) join->positions,
- sizeof(POSITION)*join->const_tables);
- join->record_count= 1.0;
- join->best_read=1.0;
+ ha_rows records= 1;
+ SELECT_LEX_UNIT *unit= join->select_lex->master_unit();
+
+ /* Find an optimal join order of the non-constant tables. */
+ if (join->const_tables != join->tables)
+ {
+ if (choose_plan(join, all_table_map & ~join->const_table_map))
+ goto error;
+ /*
+ Calculate estimated number of rows for materialized derived
+ table/view.
+ */
+ for (i= 0; i < join->tables ; i++)
+ records*= join->best_positions[i].records_read ?
+ (ha_rows)join->best_positions[i].records_read : 1;
+ }
+ else
+ {
+ memcpy((uchar*) join->best_positions,(uchar*) join->positions,
+ sizeof(POSITION)*join->const_tables);
+ join->record_count= 1.0;
+ join->best_read=1.0;
+ }
+
+ if (unit->derived && unit->derived->is_materialized_derived())
+ join->select_lex->increase_derived_records(records);
}
+
if (join->choose_subquery_plan(all_table_map & ~join->const_table_map))
goto error;
@@ -3362,8 +3420,12 @@ error:
may not be assigned yet by this function (which is building join_tab).
Dangling TABLE::reginfo.join_tab may cause part_of_refkey to choke.
*/
- for (tables= tables_arg; tables; tables= tables->next_leaf)
- tables->table->reginfo.join_tab= NULL;
+ {
+ TABLE_LIST *table;
+ List_iterator<TABLE_LIST> ti(tables_list);
+ while ((table= ti++))
+ table->table->reginfo.join_tab= NULL;
+ }
DBUG_RETURN (1);
}
@@ -3629,8 +3691,11 @@ add_key_field(JOIN *join,
table_map usable_tables, SARGABLE_PARAM **sargables)
{
uint optimize= 0;
- if (eq_func && join->is_allowed_hash_join_access() &&
- field->hash_join_is_possible())
+ if (eq_func &&
+ ((join->is_allowed_hash_join_access() &&
+ field->hash_join_is_possible()) ||
+ (field->table->pos_in_table_list->is_materialized_derived() &&
+ !field->table->created)))
{
optimize= KEY_OPTIMIZE_EQ;
}
@@ -3665,7 +3730,7 @@ add_key_field(JOIN *join,
else
{
JOIN_TAB *stat=field->table->reginfo.join_tab;
- key_map possible_keys=field->key_start;
+ key_map possible_keys=field->get_possible_keys();
possible_keys.intersect(field->table->keys_in_use_for_query);
stat[0].keys.merge(possible_keys); // Add possible keys
@@ -3836,7 +3901,7 @@ is_local_field (Item *field)
{
return field->real_item()->type() == Item::FIELD_ITEM
&& !(field->used_tables() & OUTER_REF_TABLE_BIT)
- && !((Item_field *)field->real_item())->depended_from;
+ && !((Item_field *)field->real_item())->get_depended_from();
}
@@ -4141,10 +4206,6 @@ add_keyuse(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field,
}
else
{
- /*
- If this is a key use for hash join then keypart of
- the added element actually contains the field number.
- */
keyuse.keypart= field->field_index;
keyuse.keypart_map= (key_part_map) 0;
}
@@ -4285,6 +4346,9 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
return (int) (a->table->tablenr - b->table->tablenr);
if (a->key != b->key)
return (int) (a->key - b->key);
+ if (a->key == MAX_KEY && b->key == MAX_KEY &&
+ a->used_tables != b->used_tables)
+ return (int) ((ulong) a->used_tables - (ulong) b->used_tables);
if (a->keypart != b->keypart)
return (int) (a->keypart - b->keypart);
// Place const values before other ones
@@ -4434,19 +4498,21 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
return TRUE;
+
if (cond)
{
+ KEY_FIELD *saved_field= field;
add_key_fields(join_tab->join, &end, &and_level, cond, normal_tables,
sargables);
for (; field != end ; field++)
{
- if (add_key_part(keyuse,field))
- return TRUE;
+
/* Mark that we can optimize LEFT JOIN */
if (field->val->type() == Item::NULL_ITEM &&
!field->field->real_maybe_null())
field->field->table->reginfo.not_exists_optimize=1;
}
+ field= saved_field;
}
for (i=0 ; i < tables ; i++)
{
@@ -4515,6 +4581,8 @@ static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse)
my_qsort(keyuse->buffer, keyuse->elements, sizeof(KEYUSE),
(qsort_cmp) sort_keyuse);
+ generate_derived_keys(keyuse);
+
bzero((char*) &key_end, sizeof(key_end)); /* Add for easy testing */
if (insert_dynamic(keyuse, (uchar*) &key_end))
return TRUE;
@@ -4590,7 +4658,7 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
~OUTER_REF_TABLE_BIT)))
{
uint tablenr;
- for (tablenr=0 ; ! (map & 1) ; map>>=1, tablenr++) ;
+ tablenr= my_count_bits(map);
if (map == 1) // Only one table
{
TABLE *tmp_table=join->all_tables[tablenr];
@@ -5264,7 +5332,7 @@ best_access_path(JOIN *join,
else
{
/* Estimate cost of reading table. */
- tmp= s->table->file->scan_time();
+ tmp= s->scan_time();
if ((s->table->map & join->outer_join) || disable_jbuf) // Can't use join cache
{
/*
@@ -5616,6 +5684,7 @@ optimize_straight_join(JOIN *join, table_map join_tables)
{
JOIN_TAB *s;
uint idx= join->const_tables;
+ bool disable_jbuf= join->thd->variables.join_cache_level == 0;
double record_count= 1.0;
double read_time= 0.0;
POSITION loose_scan_pos;
@@ -5623,7 +5692,7 @@ optimize_straight_join(JOIN *join, table_map join_tables)
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
{
/* Find the best access method from 's' to the current partial plan */
- best_access_path(join, s, join_tables, idx, FALSE, record_count,
+ best_access_path(join, s, join_tables, idx, disable_jbuf, record_count,
join->positions + idx, &loose_scan_pos);
/* compute the cost of the new plan extended with 's' */
@@ -6012,6 +6081,7 @@ best_extension_by_limited_search(JOIN *join,
JOIN_TAB *s;
double best_record_count= DBL_MAX;
double best_read_time= DBL_MAX;
+ bool disable_jbuf= join->thd->variables.join_cache_level == 0;
DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time,
"part_plan"););
@@ -6037,8 +6107,8 @@ best_extension_by_limited_search(JOIN *join,
/* Find the best access method from 's' to the current partial plan */
POSITION loose_scan_pos;
- best_access_path(join, s, remaining_tables, idx, FALSE, record_count,
- join->positions + idx, &loose_scan_pos);
+ best_access_path(join, s, remaining_tables, idx, disable_jbuf,
+ record_count, join->positions + idx, &loose_scan_pos);
/* Compute the cost of extending the plan with 's' */
@@ -6183,6 +6253,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
JOIN_TAB *s;
double best_record_count=DBL_MAX,best_read_time=DBL_MAX;
+ bool disable_jbuf= join->thd->variables.join_cache_level == 0;
for (JOIN_TAB **pos=join->best_ref+idx ; (s=*pos) ; pos++)
{
table_map real_table_bit=s->table->map;
@@ -6191,7 +6262,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
double records, best;
POSITION loose_scan_pos;
- best_access_path(join, s, rest_tables, idx, FALSE, record_count,
+ best_access_path(join, s, rest_tables, idx, disable_jbuf, record_count,
join->positions + idx, &loose_scan_pos);
records= join->positions[idx].records_read;
best= join->positions[idx].read_time;
@@ -6731,8 +6802,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
if (keyuse->null_rejecting)
j->ref.null_rejecting |= 1 << i;
keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables;
- if (!keyuse->used_tables &&
- !(join->select_options & SELECT_DESCRIBE))
+ if (!keyuse->used_tables && !thd->lex->describe)
{ // Compare against constant
store_key_item tmp(thd,
keyinfo->key_part[i].field,
@@ -6809,9 +6879,10 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
}
else if (keyuse->val->type() == Item::FIELD_ITEM ||
(keyuse->val->type() == Item::REF_ITEM &&
- ((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF &&
- (*(Item_ref**)((Item_ref*)keyuse->val)->ref)->ref_type() ==
- Item_ref::DIRECT_REF &&
+ ((((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF &&
+ (*(Item_ref**)((Item_ref*)keyuse->val)->ref)->ref_type() ==
+ Item_ref::DIRECT_REF) ||
+ ((Item_ref*)keyuse->val)->ref_type() == Item_ref::VIEW_REF) &&
keyuse->val->real_item()->type() == Item::FIELD_ITEM))
return new store_key_field(thd,
key_part->field,
@@ -7167,7 +7238,7 @@ make_outerjoin_info(JOIN *join)
for ( ; embedding ; embedding= embedding->embedding)
{
/* Ignore sj-nests: */
- if (!embedding->on_expr)
+ if (!(embedding->on_expr && embedding->outer_join))
continue;
NESTED_JOIN *nested_join= embedding->nested_join;
if (!nested_join->counter)
@@ -7698,6 +7769,133 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
}
+static
+uint get_next_field_for_derived_key(uchar *arg)
+{
+ KEYUSE *keyuse= *(KEYUSE **) arg;
+ if (!keyuse)
+ return (uint) (-1);
+ TABLE *table= keyuse->table;
+ uint key= keyuse->key;
+ uint fldno= keyuse->keypart;
+ uint keypart= keyuse->keypart_map == (key_part_map) 1 ?
+ 0 : (keyuse-1)->keypart+1;
+ for ( ;
+ keyuse->table == table && keyuse->key == key && keyuse->keypart == fldno;
+ keyuse++)
+ keyuse->keypart= keypart;
+ if (keyuse->key != key)
+ keyuse= 0;
+ return fldno;
+}
+
+
+static
+bool generate_derived_keys_for_table(KEYUSE *keyuse, uint count, uint keys)
+{
+ TABLE *table= keyuse->table;
+ if (table->alloc_keys(keys))
+ return TRUE;
+ uint keyno= 0;
+ KEYUSE *first_keyuse= keyuse;
+ uint prev_part= (uint) (-1);
+ uint parts= 0;
+ uint i= 0;
+ do
+ {
+ keyuse->key= keyno;
+ keyuse->keypart_map= (key_part_map) (1 << parts);
+ keyuse++;
+ if (++i == count || keyuse->used_tables != first_keyuse->used_tables)
+ {
+ if (table->add_tmp_key(keyno, ++parts,
+ get_next_field_for_derived_key,
+ (uchar *) &first_keyuse,
+ FALSE))
+ return TRUE;
+ table->reginfo.join_tab->keys.set_bit(keyno);
+ first_keyuse= keyuse;
+ keyno++;
+ parts= 0;
+ }
+ else if (keyuse->keypart != prev_part)
+ {
+ parts++;
+ prev_part= keyuse->keypart;
+ }
+ } while (keyno < keys);
+ return FALSE;
+}
+
+
+static
+bool generate_derived_keys(DYNAMIC_ARRAY *keyuse_array)
+{
+ KEYUSE *keyuse= dynamic_element(keyuse_array, 0, KEYUSE*);
+ uint elements= keyuse_array->elements;
+ TABLE *prev_table= 0;
+ for (uint i= 0; i < elements; i++, keyuse++)
+ {
+ KEYUSE *first_table_keyuse= NULL;
+ table_map last_used_tables= 0;
+ uint count= 0;
+ uint keys= 0;
+ TABLE_LIST *derived= NULL;
+ if (keyuse->table != prev_table)
+ derived= keyuse->table->pos_in_table_list;
+ while (derived && derived->is_materialized_derived() &&
+ keyuse->key == MAX_KEY)
+ {
+ if (keyuse->table != prev_table)
+ {
+ prev_table= keyuse->table;
+ first_table_keyuse= keyuse;
+ last_used_tables= keyuse->used_tables;
+ count= 0;
+ keys= 0;
+ }
+ else if (keyuse->used_tables != last_used_tables)
+ {
+ keys++;
+ last_used_tables= keyuse->used_tables;
+ }
+ count++;
+ keyuse++;
+ i++;
+ if (keyuse->table != prev_table &&
+ generate_derived_keys_for_table(first_table_keyuse, count, ++keys))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ @brief
+ Drops unused keys for each materialized derived table/view
+
+ @details
+ For materialized derived tables only ref access can be used, it employs
+ only one index, thus we don't need the rest. For each materialized derived
+ table/view call TABLE::use_index to save one index chosen by the optimizer
+ and free others. No key is chosen then all keys will be dropped.
+*/
+
+void JOIN::drop_unused_derived_keys()
+{
+ for (uint i= const_tables ; i < tables ; i++)
+ {
+ JOIN_TAB *tab=join_tab+i;
+ TABLE *table=tab->table;
+ if (!table->pos_in_table_list->is_materialized_derived() ||
+ table->max_keys <= 1)
+ continue;
+ table->use_index(tab->ref.key);
+ tab->ref.key= 0;
+ }
+}
+
/*
Determine {after which table we'll produce ordered set}
@@ -8692,6 +8890,28 @@ void JOIN_TAB::cleanup()
DBUG_VOID_RETURN;
}
+/**
+ Initialize the join_tab before reading.
+ Currently only derived table/view materialization is done here.
+*/
+bool JOIN_TAB::preread_init()
+{
+ TABLE_LIST *derived= table->pos_in_table_list;
+ if (!derived || !derived->is_materialized_derived())
+ {
+ preread_init_done= TRUE;
+ return FALSE;
+ }
+
+ /* Materialize derived table/view. */
+ if (!derived->get_unit()->executed &&
+ mysql_handle_single_derived(join->thd->lex,
+ derived, DT_CREATE | DT_FILL))
+ return TRUE;
+ preread_init_done= TRUE;
+ return FALSE;
+}
+
/**
Build a TABLE_REF structure for index lookup in the temporary table
@@ -9195,7 +9415,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
static int
-return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
+return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
List<Item> &fields, bool send_row, ulonglong select_options,
const char *info, Item *having)
{
@@ -9211,7 +9431,9 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
if (send_row)
{
- for (TABLE_LIST *table= tables; table; table= table->next_leaf)
+ List_iterator<TABLE_LIST> ti(tables);
+ TABLE_LIST *table;
+ while ((table= ti++))
mark_as_null_row(table->table); // All fields are NULL
if (having && having->val_int() == 0)
send_row=0;
@@ -9413,21 +9635,21 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
if (left_item->type() == Item::REF_ITEM &&
((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF)
{
- if (((Item_ref*)left_item)->depended_from)
+ if (((Item_ref*)left_item)->get_depended_from())
return FALSE;
left_item= left_item->real_item();
}
if (right_item->type() == Item::REF_ITEM &&
((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF)
{
- if (((Item_ref*)right_item)->depended_from)
+ if (((Item_ref*)right_item)->get_depended_from())
return FALSE;
right_item= right_item->real_item();
}
if (left_item->type() == Item::FIELD_ITEM &&
right_item->type() == Item::FIELD_ITEM &&
- !((Item_field*)left_item)->depended_from &&
- !((Item_field*)right_item)->depended_from)
+ !((Item_field*)left_item)->get_depended_from() &&
+ !((Item_field*)right_item)->get_depended_from())
{
/* The predicate the form field1=field2 is processed */
@@ -9510,7 +9732,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
Item_field *field_item= 0;
Item *orig_field_item= 0;
if (left_item->type() == Item::FIELD_ITEM &&
- !((Item_field*)left_item)->depended_from &&
+ !((Item_field*)left_item)->get_depended_from() &&
right_item->const_item())
{
orig_field_item= left_item;
@@ -9518,7 +9740,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
const_item= right_item;
}
else if (right_item->type() == Item::FIELD_ITEM &&
- !((Item_field*)right_item)->depended_from &&
+ !((Item_field*)right_item)->get_depended_from() &&
left_item->const_item())
{
orig_field_item= right_item;
@@ -10942,14 +11164,16 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
{
TABLE_LIST *tbl;
List_iterator<TABLE_LIST> it(nested_join->join_list);
+ List<TABLE_LIST> repl_list;
while ((tbl= it++))
{
tbl->embedding= table->embedding;
if (!tbl->embedding && !tbl->on_expr && tbl->table)
tbl->table->maybe_null= FALSE;
tbl->join_list= table->join_list;
+ repl_list.push_back(tbl);
}
- li.replace(nested_join->join_list);
+ li.replace(repl_list);
/* Need to update the name resolution table chain when flattening joins */
fix_name_res= TRUE;
table= *li.ref();
@@ -11919,13 +12143,29 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
If item have to be able to store NULLs but underlaid field can't do it,
create_tmp_field_from_field() can't be used for tmp field creation.
*/
- if (field->maybe_null && field->in_rollup && !field->field->maybe_null())
+ if (((field->maybe_null && field->in_rollup) ||
+ (orig_item && orig_item->maybe_null)) && /* for outer joined views/dt*/
+ !field->field->maybe_null())
{
+ bool save_maybe_null= FALSE;
+ /*
+ The item the ref points to may have maybe_null flag set while
+ the ref doesn't have it. This may happen for outer fields
+ when the outer query decided at some point after name resolution phase
+ that this field might be null. Take this into account here.
+ */
+ if (orig_item)
+ {
+ save_maybe_null= item->maybe_null;
+ item->maybe_null= orig_item->maybe_null;
+ }
result= create_tmp_field_from_item(thd, item, table, NULL,
modify_item, convert_blob_length);
*from_field= field->field;
if (result && modify_item)
field->result_field= result;
+ if (orig_item)
+ item->maybe_null= save_maybe_null;
}
else if (table_cant_handle_bit_fields && field->field->type() ==
MYSQL_TYPE_BIT)
@@ -12079,7 +12319,7 @@ TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
ulonglong select_options, ha_rows rows_limit,
- char *table_alias)
+ char *table_alias, bool do_not_open)
{
MEM_ROOT *mem_root_save, own_root;
TABLE *table;
@@ -12652,7 +12892,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
share->uniques= test(using_unique_constraint);
table->key_info= table->s->key_info= keyinfo;
keyinfo->key_part=key_part_info;
- keyinfo->flags=HA_NOSAME;
+ keyinfo->flags=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
keyinfo->usable_key_parts=keyinfo->key_parts= param->group_parts;
keyinfo->key_length=0;
keyinfo->rec_per_key=0;
@@ -12737,7 +12977,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bzero((void*) key_part_info, keyinfo->key_parts * sizeof(KEY_PART_INFO));
table->key_info= table->s->key_info= keyinfo;
keyinfo->key_part=key_part_info;
- keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL;
+ keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL | HA_BINARY_PACK_KEY | HA_PACK_KEY;
keyinfo->key_length= 0; // Will compute the sum of the parts below.
keyinfo->name= (char*) "distinct_key";
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
@@ -12805,15 +13045,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (thd->is_fatal_error) // If end of memory
goto err; /* purecov: inspected */
share->db_record_offset= 1;
- if (share->db_type() == TMP_ENGINE_HTON)
- {
- if (create_internal_tmp_table(table, param->keyinfo, param->start_recinfo,
- &param->recinfo, select_options))
- goto err;
- }
- DBUG_PRINT("info", ("skip_create_table: %d", (int)param->skip_create_table));
- if (!param->skip_create_table)
+ if (!do_not_open)
{
+ if (share->db_type() == TMP_ENGINE_HTON)
+ {
+ if (create_internal_tmp_table(table, param->keyinfo, param->start_recinfo,
+ &param->recinfo, select_options))
+ goto err;
+ }
if (open_tmp_table(table))
goto err;
}
@@ -12973,6 +13212,7 @@ bool open_tmp_table(TABLE *table)
}
table->db_stat= HA_OPEN_KEYFILE+HA_OPEN_RNDFILE;
(void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
+ table->created= TRUE;
return(0);
}
@@ -13281,6 +13521,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
}
status_var_increment(table->in_use->status_var.created_tmp_disk_tables);
share->db_record_offset= 1;
+ table->created= TRUE;
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@@ -13444,7 +13685,7 @@ free_tmp_table(THD *thd, TABLE *entry)
save_proc_info=thd->proc_info;
thd_proc_info(thd, "removing tmp table");
- if (entry->file)
+ if (entry->file && entry->created)
{
if (entry->db_stat)
entry->file->ha_drop_table(entry->s->table_name.str);
@@ -13627,8 +13868,9 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
With implicit grouping all fields of special row produced for an
empty result are NULL. See return_zero_rows() for the same behavior.
*/
- for (TABLE_LIST *table= join->select_lex->leaf_tables;
- table; table= table->next_leaf)
+ TABLE_LIST *table;
+ List_iterator_fast<TABLE_LIST> li(join->select_lex->leaf_tables);
+ while ((table= li++))
mark_as_null_row(table->table);
rc= join->result->send_data(*columns_list) > 0;
}
@@ -14067,6 +14309,9 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
do_sj_reset(join_tab->flush_weedout_table);
}
+ if (!join_tab->preread_init_done && join_tab->preread_init())
+ DBUG_RETURN(NESTED_LOOP_ERROR);
+
if (join->resume_nested_loop)
{
/* If not the last table, plunge down the nested loop */
@@ -14441,13 +14686,21 @@ static int
join_read_const_table(JOIN_TAB *tab, POSITION *pos)
{
int error;
+ TABLE_LIST *tbl;
DBUG_ENTER("join_read_const_table");
TABLE *table=tab->table;
table->const_table=1;
table->null_row=0;
table->status=STATUS_NO_RECORD;
- if (tab->type == JT_SYSTEM)
+ if (tab->table->pos_in_table_list->is_materialized_derived() &&
+ !tab->table->pos_in_table_list->fill_me)
+ {
+ //TODO: don't get here at all
+ /* Skip materialized derived tables/views. */
+ DBUG_RETURN(0);
+ }
+ else if (tab->type == JT_SYSTEM)
{
if ((error=join_read_system(tab)))
{ // Info for DESCRIBE
@@ -14511,26 +14764,27 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
if (!table->null_row)
table->maybe_null=0;
- /* Check appearance of new constant items in Item_equal objects */
- JOIN *join= tab->join;
- if (join->conds)
- update_const_equal_items(join->conds, tab);
- TABLE_LIST *tbl;
- for (tbl= join->select_lex->leaf_tables; tbl; tbl= tbl->next_leaf)
{
- TABLE_LIST *embedded;
- TABLE_LIST *embedding= tbl;
- do
- {
- embedded= embedding;
- if (embedded->on_expr)
- update_const_equal_items(embedded->on_expr, tab);
- embedding= embedded->embedding;
+ JOIN *join= tab->join;
+ List_iterator<TABLE_LIST> ti(join->select_lex->leaf_tables);
+ /* Check appearance of new constant items in Item_equal objects */
+ if (join->conds)
+ update_const_equal_items(join->conds, tab);
+ while ((tbl= ti++))
+ {
+ TABLE_LIST *embedded;
+ TABLE_LIST *embedding= tbl;
+ do
+ {
+ embedded= embedding;
+ if (embedded->on_expr)
+ update_const_equal_items(embedded->on_expr, tab);
+ embedding= embedded->embedding;
+ }
+ while (embedding &&
+ embedding->nested_join->join_list.head() == embedded);
}
- while (embedding &&
- embedding->nested_join->join_list.head() == embedded);
}
-
DBUG_RETURN(0);
}
@@ -14877,6 +15131,8 @@ int join_init_read_record(JOIN_TAB *tab)
{
if (tab->select && tab->select->quick && tab->select->quick->reset())
return 1;
+ if (!tab->preread_init_done && tab->preread_init())
+ return 1;
if (init_read_record(&tab->read_record, tab->join->thd, tab->table,
tab->select,1,1, FALSE))
return 1;
@@ -17002,6 +17258,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
get_schema_tables_result(join, PROCESSED_BY_CREATE_SORT_INDEX))
goto err;
+ if (!tab->preread_init_done && tab->preread_init())
+ goto err;
if (table->s->tmp_table)
table->file->info(HA_STATUS_VARIABLE); // Get record count
table->sort.found_records=filesort(thd, table,join->sortorder, length,
@@ -17563,7 +17821,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
order->in_field_list= 1;
order->counter= count;
order->counter_used= 1;
- return FALSE;
+ return FALSE;
}
/* Lookup the current GROUP/ORDER field in the SELECT clause. */
select_item= find_item_in_list(order_item, fields, &counter,
@@ -18008,8 +18266,10 @@ test_if_subpart(ORDER *a,ORDER *b)
*/
static TABLE *
-get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
+get_sort_by_table(ORDER *a,ORDER *b, List<TABLE_LIST> &tables)
{
+ TABLE_LIST *table;
+ List_iterator<TABLE_LIST> ti(tables);
table_map map= (table_map) 0;
DBUG_ENTER("get_sort_by_table");
@@ -18027,11 +18287,11 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)))
DBUG_RETURN(0);
- for (; !(map & tables->table->map); tables= tables->next_leaf) ;
- if (map != tables->table->map)
+ while ((table= ti++) && !(map & table->table->map)) ;
+ if (map != table->table->map)
DBUG_RETURN(0); // More than one table
- DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr));
- DBUG_RETURN(tables->table);
+ DBUG_PRINT("exit",("sort by table: %d",table->table->tablenr));
+ DBUG_RETURN(table->table);
}
@@ -19433,7 +19693,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (result->send_data(item_list))
join->error= 1;
}
- else
+ else if (!join->select_lex->master_unit()->derived ||
+ join->select_lex->master_unit()->derived->is_materialized_derived())
{
table_map used_tables=0;
@@ -19779,6 +20040,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (examined_rows)
f= (float) (100.0 * join->best_positions[i].records_read /
examined_rows);
+ set_if_smaller(f, 100.0);
item_list.push_back(new Item_float(f, 2));
}
}