Commit c14957ec authored by Aleksey Midenkov's avatar Aleksey Midenkov

MDEV-34033 Exchange partition with virtual columns fails

MDEV-28127 did is_equal() which compared vcol expressions
literally. But another table vcol expression is not equal because of
different table name.

We implement another comparison method is_identical() which respects
different table name in vcol comparison. If any field item points to
table_A and compared field item points to table_B, such items are
treated as equal in (table_A, table_B) comparison. This is done by
cloning table_B expression and renaming any table_B entries to table_A
in it.
parent be164fc4
...@@ -1321,3 +1321,25 @@ CREATE TABLE t2 (a INT, PRIMARY KEY(a)) CHECKSUM=1, ENGINE=InnoDB; ...@@ -1321,3 +1321,25 @@ CREATE TABLE t2 (a INT, PRIMARY KEY(a)) CHECKSUM=1, ENGINE=InnoDB;
ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2; ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2;
ERROR HY000: Tables have different definitions ERROR HY000: Tables have different definitions
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# MDEV-34033 Exchange partition with virtual columns fails
#
create or replace table t1(
id int primary key,
col1 int,
col2 boolean as (col1 is null))
partition by list (id) ( partition p1 values in (1)
);
create or replace table t1_working like t1;
alter table t1_working remove partitioning;
alter table t1 exchange partition p1 with table t1_working;
create or replace table t2(
id int primary key,
col1 int,
col2 boolean as (true))
partition by list (id) ( partition p1 values in (1)
);
create or replace table t2_working like t2;
alter table t2_working remove partitioning;
alter table t2 exchange partition p1 with table t2_working;
drop tables t1, t1_working, t2, t2_working;
...@@ -554,3 +554,35 @@ ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2; ...@@ -554,3 +554,35 @@ ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2;
# Cleanup # Cleanup
DROP TABLE t1, t2; DROP TABLE t1, t2;
--echo #
--echo # MDEV-34033 Exchange partition with virtual columns fails
--echo #
# this fails when the virtual persistent column
# references another column
create or replace table t1(
id int primary key,
col1 int,
col2 boolean as (col1 is null))
partition by list (id) ( partition p1 values in (1)
);
create or replace table t1_working like t1;
alter table t1_working remove partitioning;
alter table t1 exchange partition p1 with table t1_working;
# this works when the virtual persistent column
# does not reference another column
create or replace table t2(
id int primary key,
col1 int,
col2 boolean as (true))
partition by list (id) ( partition p1 values in (1)
);
create or replace table t2_working like t2;
alter table t2_working remove partitioning;
alter table t2 exchange partition p1 with table t2_working;
# Cleanup
drop tables t1, t1_working, t2, t2_working;
...@@ -659,6 +659,9 @@ class Virtual_column_info: public Sql_alloc, ...@@ -659,6 +659,9 @@ class Virtual_column_info: public Sql_alloc,
bool cleanup_session_expr(); bool cleanup_session_expr();
bool fix_and_check_expr(THD *thd, TABLE *table); bool fix_and_check_expr(THD *thd, TABLE *table);
inline bool is_equal(const Virtual_column_info* vcol) const; inline bool is_equal(const Virtual_column_info* vcol) const;
/* Same as is_equal() but for comparing with different table */
inline bool is_identical(THD *thd, TABLE_SHARE *share, TABLE_SHARE *vcol_share,
const Virtual_column_info* vcol, bool &error) const;
inline void print(String*); inline void print(String*);
}; };
......
...@@ -829,6 +829,30 @@ bool Item_field::rename_fields_processor(void *arg) ...@@ -829,6 +829,30 @@ bool Item_field::rename_fields_processor(void *arg)
return 0; return 0;
} }
/**
Rename table and clean field for EXCHANGE comparison
*/
bool Item_field::rename_table_processor(void *arg)
{
Item::func_processor_rename_table *p= (Item::func_processor_rename_table*) arg;
/* If (db_name, table_name) matches (p->old_db, p->old_table)
rename to (p->new_db, p->new_table) */
if (((!db_name.str && !p->old_db.str) ||
db_name.streq(p->old_db)) &&
((!table_name.str && !p->old_table.str) ||
table_name.streq(p->old_table)))
{
db_name= p->new_db;
table_name= p->new_table;
}
/* Item_field equality is done by field pointer if it is set, we need to avoid that */
field= NULL;
return 0;
}
/** /**
Check if an Item_field references some field from a list of fields. Check if an Item_field references some field from a list of fields.
......
...@@ -2148,6 +2148,7 @@ class Item: public Value_source, ...@@ -2148,6 +2148,7 @@ class Item: public Value_source,
virtual bool check_partition_func_processor(void *arg) { return 1;} virtual bool check_partition_func_processor(void *arg) { return 1;}
virtual bool post_fix_fields_part_expr_processor(void *arg) { return 0; } virtual bool post_fix_fields_part_expr_processor(void *arg) { return 0; }
virtual bool rename_fields_processor(void *arg) { return 0; } virtual bool rename_fields_processor(void *arg) { return 0; }
virtual bool rename_table_processor(void *arg) { return 0; }
/* /*
TRUE if the function is knowingly TRUE or FALSE. TRUE if the function is knowingly TRUE or FALSE.
Not to be used for AND/OR formulas. Not to be used for AND/OR formulas.
...@@ -2176,6 +2177,13 @@ class Item: public Value_source, ...@@ -2176,6 +2177,13 @@ class Item: public Value_source,
LEX_CSTRING table_name; LEX_CSTRING table_name;
List<Create_field> fields; List<Create_field> fields;
}; };
struct func_processor_rename_table
{
Lex_ident_db old_db;
Lex_ident_table old_table;
Lex_ident_db new_db;
Lex_ident_table new_table;
};
virtual bool check_vcol_func_processor(void *arg) virtual bool check_vcol_func_processor(void *arg)
{ {
return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE);
...@@ -3665,6 +3673,7 @@ class Item_field :public Item_ident, ...@@ -3665,6 +3673,7 @@ class Item_field :public Item_ident,
bool switch_to_nullable_fields_processor(void *arg) override; bool switch_to_nullable_fields_processor(void *arg) override;
bool update_vcol_processor(void *arg) override; bool update_vcol_processor(void *arg) override;
bool rename_fields_processor(void *arg) override; bool rename_fields_processor(void *arg) override;
bool rename_table_processor(void *arg) override;
bool check_vcol_func_processor(void *arg) override; bool check_vcol_func_processor(void *arg) override;
bool set_fields_as_dependent_processor(void *arg) override bool set_fields_as_dependent_processor(void *arg) override
{ {
...@@ -7805,6 +7814,27 @@ inline bool Virtual_column_info::is_equal(const Virtual_column_info* vcol) const ...@@ -7805,6 +7814,27 @@ inline bool Virtual_column_info::is_equal(const Virtual_column_info* vcol) const
&& expr->eq(vcol->expr, true); && expr->eq(vcol->expr, true);
} }
inline bool
Virtual_column_info::is_identical(THD *thd, TABLE_SHARE *share, TABLE_SHARE *vcol_share,
const Virtual_column_info* vcol, bool &error) const
{
error= true;
Item *cmp_expr= vcol->expr->build_clone(thd);
if (!cmp_expr)
return false;
Item::func_processor_rename_table param;
param.old_db= Lex_ident_db(vcol_share->db);
param.old_table= Lex_ident_table(vcol_share->table_name);
param.new_db= Lex_ident_db(share->db);
param.new_table= Lex_ident_table(share->table_name);
cmp_expr->walk(&Item::rename_table_processor, 1, &param);
error= false;
return type_handler() == vcol->type_handler()
&& is_stored() == vcol->is_stored()
&& expr->eq(cmp_expr, true);
}
inline void Virtual_column_info::print(String* str) inline void Virtual_column_info::print(String* str)
{ {
expr->print_for_table_def(str); expr->print_for_table_def(str);
......
...@@ -241,6 +241,8 @@ static bool compare_table_with_partition(THD *thd, TABLE *table, ...@@ -241,6 +241,8 @@ static bool compare_table_with_partition(THD *thd, TABLE *table,
part_create_info.row_type= table->s->row_type; part_create_info.row_type= table->s->row_type;
} }
part_create_info.table= part_table;
/* /*
NOTE: ha_blackhole does not support check_if_compatible_data, NOTE: ha_blackhole does not support check_if_compatible_data,
so this always fail for blackhole tables. so this always fail for blackhole tables.
......
...@@ -7854,8 +7854,12 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info, ...@@ -7854,8 +7854,12 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info,
{ {
if (!tmp_new_field->field->vcol_info) if (!tmp_new_field->field->vcol_info)
DBUG_RETURN(false); DBUG_RETURN(false);
if (!field->vcol_info->is_equal(tmp_new_field->field->vcol_info)) bool err;
if (!field->vcol_info->is_identical(thd, table->s, create_info->table->s,
tmp_new_field->field->vcol_info, err))
DBUG_RETURN(false); DBUG_RETURN(false);
if (err)
DBUG_RETURN(true);
} }
/* /*
......
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