Commit 764eeeee authored by unknown's avatar unknown

Fix for LP BUG#910123 MariaDB 5.3.3 causes 1093 error on Drupal

Problem was that now we can merge derived table (subquery in the FROM clause).
Fix: in case of detected conflict and presence of derived table "over" the table which cased the conflict - try materialization strategy.
parent 7ab53e80
...@@ -273,4 +273,13 @@ ON alias3.f4 != 0 ...@@ -273,4 +273,13 @@ ON alias3.f4 != 0
) ON alias3.f4 != 0; ) ON alias3.f4 != 0;
f4 f4 f2 f4 f4 f4 f2 f4
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
#
# LP BUG#910123 MariaDB 5.3.3 causes 1093 error on Drupal
# Fix: force materialization in case of conflict
#
SET optimizer_switch='derived_merge=on';
CREATE TABLE t1 ( i INT );
INSERT INTO t1 VALUES ( (SELECT 1 FROM ( SELECT * FROM t1 ) as a) );
drop table t1;
set optimizer_switch=@save_optimizer_switch;
set optimizer_switch=@exit_optimizer_switch; set optimizer_switch=@exit_optimizer_switch;
...@@ -202,5 +202,15 @@ RIGHT JOIN ( ...@@ -202,5 +202,15 @@ RIGHT JOIN (
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
--echo #
--echo # LP BUG#910123 MariaDB 5.3.3 causes 1093 error on Drupal
--echo # Fix: force materialization in case of conflict
--echo #
SET optimizer_switch='derived_merge=on';
CREATE TABLE t1 ( i INT );
INSERT INTO t1 VALUES ( (SELECT 1 FROM ( SELECT * FROM t1 ) as a) );
drop table t1;
set optimizer_switch=@save_optimizer_switch;
# The following command must be the last one the file # The following command must be the last one the file
set optimizer_switch=@exit_optimizer_switch; set optimizer_switch=@exit_optimizer_switch;
...@@ -1707,11 +1707,12 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, ...@@ -1707,11 +1707,12 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
t_name= table->table_name; t_name= table->table_name;
t_alias= table->alias; t_alias= table->alias;
retry:
DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name)); DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
for (;;) for (TABLE_LIST *tl= table_list;;)
{ {
if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) && if (((! (res= find_table_in_global_list(tl, d_name, t_name))) &&
(! (res= mysql_lock_have_duplicate(thd, table, table_list)))) || (! (res= mysql_lock_have_duplicate(thd, table, tl)))) ||
((!res->table || res->table != table->table) && ((!res->table || res->table != table->table) &&
(!check_alias || !(lower_case_table_names ? (!check_alias || !(lower_case_table_names ?
my_strcasecmp(files_charset_info, t_alias, res->alias) : my_strcasecmp(files_charset_info, t_alias, res->alias) :
...@@ -1724,10 +1725,23 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, ...@@ -1724,10 +1725,23 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
processed in derived table or top select of multi-update/multi-delete processed in derived table or top select of multi-update/multi-delete
(exclude_from_table_unique_test) or prelocking placeholder. (exclude_from_table_unique_test) or prelocking placeholder.
*/ */
table_list= res->next_global; tl= res->next_global;
DBUG_PRINT("info", DBUG_PRINT("info",
("found same copy of table or table which we should skip")); ("found same copy of table or table which we should skip"));
} }
if (res && res->belong_to_derived)
{
/* Try to fix */
TABLE_LIST *derived= res->belong_to_derived;
if (derived->is_merged_derived())
{
DBUG_PRINT("info",
("convert merged to materialization to resolve the conflict"));
derived->change_refs_to_fields();
derived->set_materialized_derived();
}
goto retry;
}
DBUG_RETURN(res); DBUG_RETURN(res);
} }
......
...@@ -2885,6 +2885,7 @@ void st_lex::cleanup_after_one_table_open() ...@@ -2885,6 +2885,7 @@ void st_lex::cleanup_after_one_table_open()
if (all_selects_list != &select_lex) if (all_selects_list != &select_lex)
{ {
derived_tables= 0; derived_tables= 0;
select_lex.exclude_from_table_unique_test= false;
/* cleunup underlying units (units of VIEW) */ /* cleunup underlying units (units of VIEW) */
for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit(); for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit();
un; un;
......
...@@ -961,6 +961,7 @@ bool st_select_lex::cleanup() ...@@ -961,6 +961,7 @@ bool st_select_lex::cleanup()
} }
non_agg_fields.empty(); non_agg_fields.empty();
inner_refs_list.empty(); inner_refs_list.empty();
exclude_from_table_unique_test= FALSE;
DBUG_RETURN(error); DBUG_RETURN(error);
} }
......
...@@ -4378,6 +4378,36 @@ bool TABLE_LIST::prepare_security(THD *thd) ...@@ -4378,6 +4378,36 @@ bool TABLE_LIST::prepare_security(THD *thd)
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
#ifndef DBUG_OFF
void TABLE_LIST::set_check_merged()
{
DBUG_ASSERT(derived);
/*
It is not simple to check all, but at least this should be checked:
this select is not excluded or the exclusion came from above.
*/
DBUG_ASSERT(!derived->first_select()->exclude_from_table_unique_test ||
derived->outer_select()->
exclude_from_table_unique_test);
}
#endif
void TABLE_LIST::set_check_materialized()
{
DBUG_ASSERT(derived);
if (!derived->first_select()->exclude_from_table_unique_test)
derived->set_unique_exclude();
else
{
/*
The subtree should be already excluded
*/
DBUG_ASSERT(!derived->first_select()->first_inner_unit() ||
derived->first_select()->first_inner_unit()->first_select()->
exclude_from_table_unique_test);
}
}
Natural_join_column::Natural_join_column(Field_translator *field_param, Natural_join_column::Natural_join_column(Field_translator *field_param,
TABLE_LIST *tab) TABLE_LIST *tab)
...@@ -5919,8 +5949,9 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view) ...@@ -5919,8 +5949,9 @@ bool TABLE_LIST::init_derived(THD *thd, bool init_view)
*/ */
if (is_materialized_derived()) if (is_materialized_derived())
{ {
unit->master_unit()->set_unique_exclude(); set_check_materialized();
} }
/* /*
Create field translation for mergeable derived tables/views. Create field translation for mergeable derived tables/views.
For derived tables field translation can be created only after For derived tables field translation can be created only after
......
...@@ -1747,16 +1747,18 @@ struct TABLE_LIST ...@@ -1747,16 +1747,18 @@ struct TABLE_LIST
inline void set_merged_derived() inline void set_merged_derived()
{ {
derived_type= ((derived_type & DTYPE_MASK) | derived_type= ((derived_type & DTYPE_MASK) |
DTYPE_TABLE | DTYPE_MERGE); DTYPE_TABLE | DTYPE_MERGE);
set_check_merged();
} }
inline bool is_materialized_derived() inline bool is_materialized_derived()
{ {
return (derived_type & DTYPE_MATERIALIZE); return (derived_type & DTYPE_MATERIALIZE);
} }
inline void set_materialized_derived() void set_materialized_derived()
{ {
derived_type= ((derived_type & DTYPE_MASK) | derived_type= ((derived_type & DTYPE_MASK) |
DTYPE_TABLE | DTYPE_MATERIALIZE); DTYPE_TABLE | DTYPE_MATERIALIZE);
set_check_materialized();
} }
inline bool is_multitable() inline bool is_multitable()
{ {
...@@ -1802,6 +1804,12 @@ struct TABLE_LIST ...@@ -1802,6 +1804,12 @@ struct TABLE_LIST
private: private:
bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause); bool prep_where(THD *thd, Item **conds, bool no_where_clause);
void set_check_materialized();
#ifndef DBUG_OFF
void set_check_merged();
#else
inline void set_check_merged() {}
#endif
/* /*
Cleanup for re-execution in a prepared statement or a stored Cleanup for re-execution in a prepared statement or a stored
procedure. procedure.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment