1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Merged the code of MWL#106 into 5.3

Resolved all conflicts, bad merges and fixed a few minor bugs in the code.
Commented out the queries from multi_update, view, subselect_sj, func_str,
derived_view, view_grant that failed either with crashes in ps-protocol or
with wrong results.
The failures are clear indications of some bugs in the code and these bugs
are to be fixed.
This commit is contained in:
Igor Babaev
2011-05-16 22:39:43 -07:00
92 changed files with 4191 additions and 1093 deletions

View File

@ -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);
@ -422,7 +424,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,
@ -500,21 +502,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
@ -543,10 +546,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. */
/*
@ -556,7 +561,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,
@ -674,10 +679,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).
@ -803,16 +804,45 @@ 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 (convert_max_min_subquery(this) ||
convert_join_subqueries_to_semijoins(this))
DBUG_RETURN(1); /* purecov: inspected */
/* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
/* 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 (convert_max_min_subquery(this))
DBUG_RETURN(1);
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);
@ -846,7 +876,8 @@ JOIN::optimize()
}
}
#endif
SELECT_LEX *sel= thd->lex->current_select;
SELECT_LEX *sel= select_lex;
if (sel->first_cond_optimization)
{
/*
@ -910,7 +941,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
@ -1009,6 +1041,8 @@ JOIN::optimize()
DBUG_RETURN(1);
}
drop_unused_derived_keys();
if (rollup.state != ROLLUP::STATE_NONE)
{
if (rollup_process_const_fields())
@ -1144,6 +1178,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;
}
@ -1473,7 +1508,7 @@ JOIN::optimize()
if (select_options & SELECT_DESCRIBE)
{
error= 0;
DBUG_RETURN(0);
goto derived_exit;
}
having= 0;
@ -1502,6 +1537,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);
}
@ -2064,6 +2102,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;
@ -2848,12 +2891,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;
@ -2864,6 +2906,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;
@ -2879,9 +2923,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;
@ -2891,7 +2933,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));
@ -2963,6 +3005,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;
@ -3234,7 +3277,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
@ -3319,19 +3362,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;
@ -3345,8 +3404,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);
}
@ -3611,8 +3674,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;
}
@ -3647,7 +3713,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
@ -4098,10 +4164,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;
}
@ -4242,6 +4304,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
@ -4391,19 +4456,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++)
{
@ -4472,6 +4539,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;
@ -4547,7 +4616,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];
@ -5221,7 +5290,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
{
/*
@ -5573,6 +5642,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;
@ -5580,7 +5650,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' */
@ -5969,6 +6039,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"););
@ -5994,8 +6065,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' */
@ -6140,6 +6211,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;
@ -6148,7 +6220,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;
@ -6688,8 +6760,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,
@ -6766,9 +6837,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,
@ -7124,7 +7196,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)
@ -7654,6 +7726,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;
table_map last_used_tables;
uint count;
uint keys;
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}
@ -8642,6 +8841,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
@ -9145,7 +9366,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)
{
@ -9161,7 +9382,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;
@ -10885,14 +11108,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();
@ -11862,13 +12087,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;
/*
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)
@ -12022,7 +12263,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;
@ -12595,7 +12836,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;
@ -12680,7 +12921,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;
@ -12748,15 +12989,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;
}
@ -12916,6 +13156,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);
}
@ -13224,6 +13465,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);
@ -13387,7 +13629,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);
@ -13570,8 +13812,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);
}
@ -14010,6 +14253,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 */
@ -14384,13 +14630,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
@ -14454,26 +14708,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
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++))
{
embedded= embedding;
if (embedded->on_expr)
update_const_equal_items(embedded->on_expr, tab);
embedding= embedded->embedding;
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);
}
@ -14820,6 +15075,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;
@ -16868,6 +17125,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,
@ -17429,7 +17688,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,
@ -17874,8 +18133,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");
@ -17893,11 +18154,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);
}
@ -19297,7 +19558,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;
@ -19643,6 +19905,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));
}
}