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.cc224
1 files changed, 178 insertions, 46 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 36582223703..02d2187970a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -798,13 +798,46 @@ err:
}
+/*
+ Create a dummy temporary table, useful only for the sake of having a
+ TABLE* object with map,tablenr and maybe_null properties.
+
+ This is used by non-mergeable semi-join materilization code to handle
+ degenerate cases where materialized subquery produced "Impossible WHERE"
+ and thus wasn't materialized.
+*/
+
+TABLE *create_dummy_tmp_table(THD *thd)
+{
+ DBUG_ENTER("create_dummy_tmp_table");
+ TABLE *table;
+ TMP_TABLE_PARAM sjm_table_param;
+ sjm_table_param.init();
+ sjm_table_param.field_count= 1;
+ List<Item> sjm_table_cols;
+ Item *column_item= new Item_int(1);
+ sjm_table_cols.push_back(column_item);
+ if (!(table= create_tmp_table(thd, &sjm_table_param,
+ sjm_table_cols, (ORDER*) 0,
+ TRUE /* distinct */,
+ 1, /*save_sum_fields*/
+ thd->options | TMP_TABLE_ALL_COLUMNS,
+ HA_POS_ERROR /*rows_limit */,
+ (char*)"dummy", TRUE /* Do not open */)))
+ {
+ DBUG_RETURN(NULL);
+ }
+ DBUG_RETURN(table);
+}
+
+
void
-inject_jtbm_conds(JOIN *join, List<TABLE_LIST> *join_list, Item **join_where)
+setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list, Item **join_where)
{
TABLE_LIST *table;
NESTED_JOIN *nested_join;
List_iterator<TABLE_LIST> li(*join_list);
- DBUG_ENTER("inject_jtbm_conds");
+ DBUG_ENTER("setup_jtbm_semi_joins");
while ((table= li++))
@@ -817,34 +850,60 @@ inject_jtbm_conds(JOIN *join, List<TABLE_LIST> *join_list, Item **join_where)
double rows;
double read_time;
- //DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION));
subq_pred->optimize(&rows, &read_time);
-
subq_pred->jtbm_read_time= read_time;
subq_pred->jtbm_record_count=rows;
subq_pred->is_jtbm_merged= TRUE;
+ JOIN *subq_join= subq_pred->unit->first_select()->join;
+ if (!subq_join->tables_list || !subq_join->table_count)
+ {
+ /*
+ This is an empty and constant table.
- subselect_hash_sj_engine *hash_sj_engine=
- ((subselect_hash_sj_engine*)item->engine);
-
-
- //repeat of convert_subq_to_jtbm:
- table->table= hash_sj_engine->tmp_table;
- table->table->pos_in_table_list= table;
+ TODO: what if this is not empty but still constant?
+
+ We'll need to check the equality but there's no materializatnion
+ table?
+
+ A: create an IN-equality from
+ - left_expr
+ - right_expr. Q: how can right-expr exist in the context of
+ parent select? We don't have refs from outside to inside!
+ A: create/check in the context of the child select?
+
+ for injection, check how in->exists is performed.
+ */
+ subq_pred->is_jtbm_const_tab= TRUE;
- setup_table_map(table->table, table, table->jtbm_table_no);
+ TABLE *dummy_table= create_dummy_tmp_table(join->thd);
+ table->table= dummy_table;
+ table->table->pos_in_table_list= table;
- Item *sj_conds= hash_sj_engine->semi_join_conds;
+ setup_table_map(table->table, table, table->jtbm_table_no);
+ }
+ else
+ {
+ DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION));
+ subq_pred->is_jtbm_const_tab= FALSE;
+ subselect_hash_sj_engine *hash_sj_engine=
+ ((subselect_hash_sj_engine*)item->engine);
+
+ table->table= hash_sj_engine->tmp_table;
+ table->table->pos_in_table_list= table;
- (*join_where)= and_items(*join_where, sj_conds);
- if (!(*join_where)->fixed)
- (*join_where)->fix_fields(join->thd, join_where);
- //parent_join->select_lex->where= parent_join->conds;
+ setup_table_map(table->table, table, table->jtbm_table_no);
+
+ Item *sj_conds= hash_sj_engine->semi_join_conds;
+
+ (*join_where)= and_items(*join_where, sj_conds);
+ if (!(*join_where)->fixed)
+ (*join_where)->fix_fields(join->thd, join_where);
+ }
}
if ((nested_join= table->nested_join))
{
- inject_jtbm_conds(join, &nested_join->join_list, join_where);
+ setup_jtbm_semi_joins(join, &nested_join->join_list, join_where);
}
}
DBUG_VOID_RETURN;
@@ -971,7 +1030,7 @@ JOIN::optimize()
thd->restore_active_arena(arena, &backup);
}
- inject_jtbm_conds(this, join_list, &conds);
+ setup_jtbm_semi_joins(this, join_list, &conds);
conds= optimize_cond(this, conds, join_list, &cond_value, &cond_equal);
@@ -1449,7 +1508,7 @@ JOIN::optimize()
order=0;
// Can't use sort on head table if using join buffering
- if (full_join)
+ if (full_join || hash_join)
{
TABLE *stable= (sort_by_table == (TABLE *) 1 ?
join_tab[const_tables].table : sort_by_table);
@@ -3130,6 +3189,14 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
set_position(join,const_count++,s,(KEYUSE*) 0);
no_rows_const_tables |= table->map;
}
+
+ /* SJ-Materialization handling: */
+ if (table->pos_in_table_list->jtbm_subselect &&
+ table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
+ {
+ set_position(join,const_count++,s,(KEYUSE*) 0);
+ no_rows_const_tables |= table->map;
+ }
}
stat_vector[i]=0;
@@ -5391,7 +5458,9 @@ best_access_path(JOIN *join,
(1) s is inner table of semi-join -> join cache is allowed for semijoins
(2) s is inner table of outer join -> join cache is allowed for outer joins
*/
- if (idx > join->const_tables && best_key == 0 &&
+ if (idx > join->const_tables && best_key == 0 &&
+ (join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) &&
+ join->max_allowed_join_cache_level > 2 &&
!bitmap_is_clear_all(eq_join_set) && !disable_jbuf &&
(!s->emb_sj_nest ||
join->allowed_semijoin_with_cache) && // (1)
@@ -7044,6 +7113,7 @@ get_best_combination(JOIN *join)
DBUG_RETURN(TRUE);
join->full_join=0;
+ join->hash_join= FALSE;
used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read
@@ -7133,6 +7203,11 @@ get_best_combination(JOIN *join)
}
else if (create_ref_for_key(join, j, keyuse, used_tables))
DBUG_RETURN(TRUE); // Something went wrong
+
+ if ((j->type == JT_REF || j->type == JT_EQ_REF) &&
+ is_hash_join_key_no(j->ref.key))
+ join->hash_join= TRUE;
+
loop_end:
/*
Save records_read in JOIN_TAB so that select_describe()/etc don't have
@@ -7193,10 +7268,26 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
do
{
- if (!(~used_tables & keyuse->used_tables) &&
- (first_keyuse || keyuse->keypart != (keyuse-1)->keypart))
- key_parts++;
- first_keyuse= FALSE;
+ if (!(~used_tables & keyuse->used_tables))
+ {
+ if (first_keyuse)
+ {
+ key_parts++;
+ first_keyuse= FALSE;
+ }
+ else
+ {
+ KEYUSE *curr= org_keyuse;
+ for( ; curr < keyuse; curr++)
+ {
+ if (curr->keypart == keyuse->keypart &&
+ !(~used_tables & curr->used_tables))
+ break;
+ }
+ if (curr == keyuse)
+ key_parts++;
+ }
+ }
keyuse++;
} while (keyuse->table == table && keyuse->is_for_hash_join());
if (!key_parts)
@@ -7221,15 +7312,31 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
keyuse= org_keyuse;
do
{
- if (!(~used_tables & keyuse->used_tables) &&
- (first_keyuse || keyuse->keypart != (keyuse-1)->keypart))
- {
- Field *field= table->field[keyuse->keypart];
- uint fieldnr= keyuse->keypart+1;
- table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr);
- first_keyuse= FALSE;
- key_part_info++;
+ if (!(~used_tables & keyuse->used_tables))
+ {
+ bool add_key_part= TRUE;
+ if (!first_keyuse)
+ {
+ for(KEYUSE *curr= org_keyuse; curr < keyuse; curr++)
+ {
+ if (curr->keypart == keyuse->keypart &&
+ !(~used_tables & curr->used_tables))
+ {
+ keyuse->keypart= NO_KEYPART;
+ add_key_part= FALSE;
+ break;
+ }
+ }
+ }
+ if (add_key_part)
+ {
+ Field *field= table->field[keyuse->keypart];
+ uint fieldnr= keyuse->keypart+1;
+ table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr);
+ key_part_info++;
+ }
}
+ first_keyuse= FALSE;
keyuse++;
} while (keyuse->table == table && keyuse->is_for_hash_join());
@@ -7312,8 +7419,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
{
if (are_tables_local(j, keyuse->val->used_tables()))
{
- if ((is_hash_join_key_no(key) &&
- (keyparts == 0 || keyuse->keypart != (keyuse-1)->keypart)) ||
+ if ((is_hash_join_key_no(key) && keyuse->keypart != NO_KEYPART) ||
(!is_hash_join_key_no(key) && keyparts == keyuse->keypart &&
!(found_part_ref_or_null & keyuse->optimize)))
{
@@ -7367,6 +7473,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
for (i=0 ; i < keyparts ; keyuse++,i++)
{
while (((~used_tables) & keyuse->used_tables) ||
+ keyuse->keypart == NO_KEYPART ||
(keyuse->keypart !=
(is_hash_join_key_no(key) ?
keyinfo->key_part[i].field->field_index : i)) ||
@@ -8777,8 +8884,7 @@ void revise_cache_usage(JOIN_TAB *join_tab)
first_inner= join_tab->first_sj_inner_tab;
for (tab= join_tab-1; tab >= first_inner; tab--)
{
- if (tab->first_sj_inner_tab == first_inner)
- set_join_cache_denial(tab);
+ set_join_cache_denial(tab);
}
}
else set_join_cache_denial(join_tab);
@@ -9638,8 +9744,16 @@ void JOIN_TAB::cleanup()
if (table->pos_in_table_list &&
table->pos_in_table_list->jtbm_subselect)
{
- end_read_record(&read_record);
- table->pos_in_table_list->jtbm_subselect->cleanup();
+ if (table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
+ {
+ free_tmp_table(join->thd, table);
+ table= NULL;
+ }
+ else
+ {
+ end_read_record(&read_record);
+ table->pos_in_table_list->jtbm_subselect->cleanup();
+ }
DBUG_VOID_RETURN;
}
/*
@@ -11913,7 +12027,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
{
if (!table->prep_on_expr)
table->prep_on_expr= table->on_expr;
- used_tables= table->table->map;
+ used_tables= table->get_map();
if (conds)
not_null_tables= conds->not_null_tables();
}
@@ -11970,7 +12084,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
table->embedding->on_expr_dep_tables|= table->on_expr->used_tables();
}
else
- table->dep_tables&= ~table->table->map;
+ table->dep_tables&= ~table->get_map();
}
if (prev_table)
@@ -11983,7 +12097,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
prev_table->dep_tables|= table->on_expr_dep_tables;
table_map prev_used_tables= prev_table->nested_join ?
prev_table->nested_join->used_tables :
- prev_table->table->map;
+ prev_table->get_map();
/*
If on expression contains only references to inner tables
we still make the inner tables dependent on the outer tables.
@@ -13946,10 +14060,22 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
key_part_info->store_length= key_part_info->length;
if ((*reg_field)->real_maybe_null())
+ {
key_part_info->store_length+= HA_KEY_NULL_LENGTH;
- if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
- (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR)
- key_part_info->store_length+= HA_KEY_BLOB_LENGTH;
+ key_part_info->key_part_flag |= HA_NULL_PART;
+ }
+ if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
+ (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
+ (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
+ {
+ if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
+ (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
+ key_part_info->key_part_flag|= HA_BLOB_PART;
+ else
+ key_part_info->key_part_flag|= HA_VAR_LENGTH_PART;
+
+ key_part_info->store_length+=HA_KEY_BLOB_LENGTH;
+ }
keyinfo->key_length+= key_part_info->store_length;
@@ -15537,6 +15663,12 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
/* Skip materialized derived tables/views. */
DBUG_RETURN(0);
}
+ else if (tab->table->pos_in_table_list->jtbm_subselect &&
+ tab->table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
+ {
+ /* Row will not be found */
+ DBUG_RETURN(-1);
+ }
else if (tab->type == JT_SYSTEM)
{
if ((error=join_read_system(tab)))
@@ -20654,7 +20786,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
/* id */
item_list.push_back(new Item_uint((uint32)select_id));
/* select_type */
- const char* stype= printing_materialize_nest? "SUBQUERY" :
+ const char* stype= printing_materialize_nest? "MATERIALIZED" :
join->select_lex->type;
item_list.push_back(new Item_string(stype, strlen(stype), cs));