Merge fix for BUG#868908
This commit is contained in:
commit
8e96081764
@ -1729,6 +1729,29 @@ FROM t4 , t5
|
||||
f1 f5
|
||||
DROP TABLE t1, t2, t3, t4, t5;
|
||||
#
|
||||
# BUG#868908: Crash in check_simple_equality() with semijoin + materialization + prepared statement
|
||||
#
|
||||
CREATE TABLE t1 ( a int );
|
||||
CREATE TABLE t3 ( b int, c int) ;
|
||||
CREATE TABLE t2 ( a int ) ;
|
||||
CREATE TABLE t4 ( a int , c int) ;
|
||||
PREPARE st1 FROM "
|
||||
SELECT STRAIGHT_JOIN *
|
||||
FROM t1
|
||||
WHERE ( 3 ) IN (
|
||||
SELECT t3.b
|
||||
FROM t3
|
||||
LEFT JOIN (
|
||||
t2 STRAIGHT_JOIN t4 ON ( t4.c = t2.a )
|
||||
) ON ( t4.a = t3.c )
|
||||
);
|
||||
";
|
||||
EXECUTE st1;
|
||||
a
|
||||
EXECUTE st1;
|
||||
a
|
||||
DROP TABLE t1,t2,t3,t4;
|
||||
#
|
||||
# BUG#901032: Wrong result for MIN/MAX on an indexed column with materialization and semijoin
|
||||
#
|
||||
CREATE TABLE t1 ( a INT, KEY(a) );
|
||||
|
@ -1765,6 +1765,29 @@ FROM t4 , t5
|
||||
f1 f5
|
||||
DROP TABLE t1, t2, t3, t4, t5;
|
||||
#
|
||||
# BUG#868908: Crash in check_simple_equality() with semijoin + materialization + prepared statement
|
||||
#
|
||||
CREATE TABLE t1 ( a int );
|
||||
CREATE TABLE t3 ( b int, c int) ;
|
||||
CREATE TABLE t2 ( a int ) ;
|
||||
CREATE TABLE t4 ( a int , c int) ;
|
||||
PREPARE st1 FROM "
|
||||
SELECT STRAIGHT_JOIN *
|
||||
FROM t1
|
||||
WHERE ( 3 ) IN (
|
||||
SELECT t3.b
|
||||
FROM t3
|
||||
LEFT JOIN (
|
||||
t2 STRAIGHT_JOIN t4 ON ( t4.c = t2.a )
|
||||
) ON ( t4.a = t3.c )
|
||||
);
|
||||
";
|
||||
EXECUTE st1;
|
||||
a
|
||||
EXECUTE st1;
|
||||
a
|
||||
DROP TABLE t1,t2,t3,t4;
|
||||
#
|
||||
# BUG#901032: Wrong result for MIN/MAX on an indexed column with materialization and semijoin
|
||||
#
|
||||
CREATE TABLE t1 ( a INT, KEY(a) );
|
||||
|
@ -1427,6 +1427,29 @@ ON ( t2.f5 ) IN (
|
||||
);
|
||||
|
||||
DROP TABLE t1, t2, t3, t4, t5;
|
||||
--echo #
|
||||
--echo # BUG#868908: Crash in check_simple_equality() with semijoin + materialization + prepared statement
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 ( a int );
|
||||
CREATE TABLE t3 ( b int, c int) ;
|
||||
CREATE TABLE t2 ( a int ) ;
|
||||
CREATE TABLE t4 ( a int , c int) ;
|
||||
|
||||
PREPARE st1 FROM "
|
||||
SELECT STRAIGHT_JOIN *
|
||||
FROM t1
|
||||
WHERE ( 3 ) IN (
|
||||
SELECT t3.b
|
||||
FROM t3
|
||||
LEFT JOIN (
|
||||
t2 STRAIGHT_JOIN t4 ON ( t4.c = t2.a )
|
||||
) ON ( t4.a = t3.c )
|
||||
);
|
||||
";
|
||||
EXECUTE st1;
|
||||
EXECUTE st1;
|
||||
DROP TABLE t1,t2,t3,t4;
|
||||
|
||||
--echo #
|
||||
--echo # BUG#901032: Wrong result for MIN/MAX on an indexed column with materialization and semijoin
|
||||
|
@ -1197,7 +1197,8 @@ Item_in_subselect::Item_in_subselect(Item * left_exp,
|
||||
Item_exists_subselect(),
|
||||
left_expr_cache(0), first_execution(TRUE), in_strategy(SUBS_NOT_TRANSFORMED),
|
||||
optimizer(0), pushed_cond_guards(NULL), emb_on_expr_nest(NULL),
|
||||
is_jtbm_merged(FALSE), is_flattenable_semijoin(FALSE),
|
||||
is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE),
|
||||
is_flattenable_semijoin(FALSE),
|
||||
is_registered_semijoin(FALSE),
|
||||
upper_item(0)
|
||||
{
|
||||
@ -4182,6 +4183,8 @@ bool subselect_hash_sj_engine::init(List<Item> *tmp_columns, uint subquery_id)
|
||||
*/
|
||||
if (tmp_table->s->keys == 0)
|
||||
{
|
||||
//fprintf(stderr, "Q: %s\n", current_thd->query());
|
||||
DBUG_ASSERT(0);
|
||||
DBUG_ASSERT(
|
||||
tmp_table->s->uniques ||
|
||||
tmp_table->key_info->key_length >= tmp_table->file->max_key_length() ||
|
||||
|
@ -449,6 +449,7 @@ public:
|
||||
double jtbm_read_time;
|
||||
double jtbm_record_count;
|
||||
bool is_jtbm_merged;
|
||||
bool is_jtbm_const_tab;
|
||||
|
||||
/*
|
||||
TRUE<=>this is a flattenable semi-join, false overwise.
|
||||
@ -490,7 +491,7 @@ public:
|
||||
:Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE),
|
||||
abort_on_null(0), in_strategy(SUBS_NOT_TRANSFORMED), optimizer(0),
|
||||
pushed_cond_guards(NULL), func(NULL), emb_on_expr_nest(NULL),
|
||||
is_jtbm_merged(FALSE),
|
||||
is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE),
|
||||
upper_item(0)
|
||||
{}
|
||||
void cleanup();
|
||||
|
10
sql/lock.cc
10
sql/lock.cc
@ -866,8 +866,10 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
||||
for (i=tables=lock_count=0 ; i < count ; i++)
|
||||
{
|
||||
TABLE *t= table_ptr[i];
|
||||
|
||||
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
|
||||
|
||||
|
||||
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE &&
|
||||
t->s->tmp_table != INTERNAL_TMP_TABLE)
|
||||
{
|
||||
tables+= t->file->lock_count();
|
||||
lock_count++;
|
||||
@ -895,7 +897,9 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
||||
TABLE *table;
|
||||
enum thr_lock_type lock_type;
|
||||
THR_LOCK_DATA **locks_start;
|
||||
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
|
||||
table= table_ptr[i];
|
||||
if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE ||
|
||||
table->s->tmp_table == INTERNAL_TMP_TABLE)
|
||||
continue;
|
||||
lock_type= table->reginfo.lock_type;
|
||||
DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);
|
||||
|
@ -1266,10 +1266,9 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
|
||||
List_iterator_fast<TABLE_LIST> si(subq_lex->leaf_tables);
|
||||
while ((tl= si++))
|
||||
{
|
||||
tl->table->tablenr= table_no;
|
||||
tl->table->map= ((table_map)1) << table_no;
|
||||
tl->set_tablenr(table_no);
|
||||
if (tl->is_jtbm())
|
||||
tl->jtbm_table_no= tl->table->tablenr;
|
||||
tl->jtbm_table_no= table_no;
|
||||
SELECT_LEX *old_sl= tl->select_lex;
|
||||
tl->select_lex= parent_join->select_lex;
|
||||
for (TABLE_LIST *emb= tl->embedding;
|
||||
@ -1427,25 +1426,12 @@ static bool convert_subq_to_jtbm(JOIN *parent_join,
|
||||
List<TABLE_LIST> *emb_join_list= &parent_lex->top_join_list;
|
||||
TABLE_LIST *emb_tbl_nest= NULL; // will change when we learn to handle outer joins
|
||||
TABLE_LIST *tl;
|
||||
double rows;
|
||||
double read_time;
|
||||
DBUG_ENTER("convert_subq_to_jtbm");
|
||||
|
||||
bool optimization_delayed= TRUE;
|
||||
subq_pred->set_strategy(SUBS_MATERIALIZATION);
|
||||
if (subq_pred->optimize(&rows, &read_time))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
subq_pred->jtbm_read_time= read_time;
|
||||
subq_pred->jtbm_record_count=rows;
|
||||
subq_pred->is_jtbm_merged= TRUE;
|
||||
|
||||
if (subq_pred->engine->engine_type() != subselect_engine::HASH_SJ_ENGINE)
|
||||
{
|
||||
*remove_item= FALSE;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
*remove_item= TRUE;
|
||||
|
||||
TABLE_LIST *jtbm;
|
||||
@ -1481,7 +1467,18 @@ static bool convert_subq_to_jtbm(JOIN *parent_join,
|
||||
tl->next_local= jtbm;
|
||||
|
||||
/* A theory: no need to re-connect the next_global chain */
|
||||
if (optimization_delayed)
|
||||
{
|
||||
DBUG_ASSERT(parent_join->table_count < MAX_TABLES);
|
||||
|
||||
jtbm->jtbm_table_no= parent_join->table_count;
|
||||
|
||||
create_subquery_temptable_name(tbl_alias,
|
||||
subq_pred->unit->first_select()->select_number);
|
||||
jtbm->alias= tbl_alias;
|
||||
parent_join->table_count++;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
subselect_hash_sj_engine *hash_sj_engine=
|
||||
((subselect_hash_sj_engine*)subq_pred->engine);
|
||||
jtbm->table= hash_sj_engine->tmp_table;
|
||||
|
@ -3644,12 +3644,12 @@ bool st_select_lex::save_leaf_tables(THD *thd)
|
||||
{
|
||||
if (leaf_tables_exec.push_back(table))
|
||||
return 1;
|
||||
table->tablenr_exec= table->table->tablenr;
|
||||
table->map_exec= table->table->map;
|
||||
table->tablenr_exec= table->get_tablenr();
|
||||
table->map_exec= table->get_map();
|
||||
if (join && (join->select_options & SELECT_DESCRIBE))
|
||||
table->maybe_null_exec= 0;
|
||||
else
|
||||
table->maybe_null_exec= table->table->maybe_null;
|
||||
table->maybe_null_exec= table->table? table->table->maybe_null: 0;
|
||||
}
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
|
@ -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?
|
||||
|
||||
setup_table_map(table->table, table, table->jtbm_table_no);
|
||||
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;
|
||||
|
||||
Item *sj_conds= hash_sj_engine->semi_join_conds;
|
||||
TABLE *dummy_table= create_dummy_tmp_table(join->thd);
|
||||
table->table= dummy_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);
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
@ -974,7 +1033,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);
|
||||
|
||||
@ -3120,6 +3179,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;
|
||||
@ -9669,8 +9736,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;
|
||||
}
|
||||
/*
|
||||
@ -11944,7 +12019,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();
|
||||
}
|
||||
@ -12001,7 +12076,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)
|
||||
@ -12014,7 +12089,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.
|
||||
@ -15577,6 +15652,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)))
|
||||
|
@ -5922,6 +5922,8 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view)
|
||||
int TABLE_LIST::fetch_number_of_rows()
|
||||
{
|
||||
int error= 0;
|
||||
if (jtbm_subselect)
|
||||
return 0;
|
||||
if (is_materialized_derived() && !fill_me)
|
||||
|
||||
{
|
||||
|
20
sql/table.h
20
sql/table.h
@ -1377,6 +1377,26 @@ struct TABLE_LIST
|
||||
select_union *derived_result;
|
||||
/* Stub used for materialized derived tables. */
|
||||
table_map map; /* ID bit of table (1,2,4,8,16...) */
|
||||
table_map get_map()
|
||||
{
|
||||
return jtbm_subselect? table_map(1) << jtbm_table_no : table->map;
|
||||
}
|
||||
uint get_tablenr()
|
||||
{
|
||||
return jtbm_subselect? jtbm_table_no : table->tablenr;
|
||||
}
|
||||
void set_tablenr(uint new_tablenr)
|
||||
{
|
||||
if (jtbm_subselect)
|
||||
{
|
||||
jtbm_table_no= new_tablenr;
|
||||
}
|
||||
if (table)
|
||||
{
|
||||
table->tablenr= new_tablenr;
|
||||
table->map= table_map(1) << new_tablenr;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Reference from aux_tables to local list entry of main select of
|
||||
multi-delete statement:
|
||||
|
Loading…
x
Reference in New Issue
Block a user