diff --git a/mysql-test/suite/parts/r/alter_table.result b/mysql-test/suite/parts/r/alter_table.result index fa458c977c2..24532a59cc6 100644 --- a/mysql-test/suite/parts/r/alter_table.result +++ b/mysql-test/suite/parts/r/alter_table.result @@ -358,3 +358,177 @@ disconnect con1; connection default; drop user u@localhost; drop database db; +# +# MDEV-22164 without validation for exchange partition/convert in +# +create table validation(x int); +drop table validation; +create table t (a int primary key); +create table tp (a int primary key) partition by range (a) ( +partition p0 values less than (100), +# Cunning syntax (same as above) +p1 values less (300)); +insert into t values (1), (99); +insert into tp values (2), (200); +select * from t order by a; +a +1 +99 +select * from tp partition (p0) order by a; +a +2 +select * from tp partition (p1) order by a; +a +200 +alter table tp exchange partition p0 with table t; +select * from t order by a; +a +2 +select * from tp partition (p0) order by a; +a +1 +99 +select * from tp partition (p1) order by a; +a +200 +alter table tp exchange partition p0 with table t; +select * from t order by a; +a +1 +99 +select * from tp partition (p0) order by a; +a +2 +select * from tp partition (p1) order by a; +a +200 +alter table tp exchange partition p1 with table t; +ERROR HY000: Found a row that does not match the partition +alter table tp exchange partition p1 with table t with validation; +ERROR HY000: Found a row that does not match the partition +alter table tp exchange partition p1 with table t without validation; +select * from t order by a; +a +200 +select * from tp partition (p1) order by a; +a +1 +99 +alter table tp check partition p0; +Table Op Msg_type Msg_text +test.tp check status OK +alter table tp check partition p1; +Table Op Msg_type Msg_text +test.tp check error Found a misplaced row +test.tp check error Partition p1 returned error +test.tp check error Upgrade required. Please do "REPAIR TABLE `tp`" or dump/reload to fix it! +alter table tp exchange partition p1 with table t with validation; +alter table tp exchange partition p1 with table t with validation; +ERROR HY000: Found a row that does not match the partition +select * from t order by a; +a +1 +99 +select * from tp partition (p1) order by a; +a +200 +create or replace procedure validation() +alter table tp exchange partition p1 with table t with validation; +create or replace procedure without_validation() +alter table tp exchange partition p1 with table t without validation; +call validation; +ERROR HY000: Found a row that does not match the partition +call without_validation; +call validation; +call validation; +ERROR HY000: Found a row that does not match the partition +call without_validation; +select * from t order by a; +a +200 +select * from tp partition (p1) order by a; +a +1 +99 +call validation; +select * from t order by a; +a +1 +99 +select * from tp partition (p1) order by a; +a +200 +drop procedure validation; +drop procedure without_validation; +prepare validation from "alter table tp exchange partition p1 with table t with validation"; +prepare without_validation from "alter table tp exchange partition p1 with table t without validation"; +execute validation; +ERROR HY000: Found a row that does not match the partition +execute without_validation; +execute validation; +execute validation; +ERROR HY000: Found a row that does not match the partition +execute without_validation; +select * from t order by a; +a +200 +select * from tp partition (p1) order by a; +a +1 +99 +execute validation; +select * from t order by a; +a +1 +99 +select * from tp partition (p1) order by a; +a +200 +drop prepare validation; +drop prepare without_validation; +alter table tp convert table t to partition p2 values less (maxvalue); +ERROR HY000: Found a row that does not match the partition +alter table tp convert table t to partition p2 values less (maxvalue) with validation; +ERROR HY000: Found a row that does not match the partition +alter table tp convert table t to partition p2 values less (maxvalue) without validation; +select * from tp partition (p0) order by a; +a +2 +select * from tp partition (p1) order by a; +a +200 +select * from tp partition (p2) order by a; +a +1 +99 +create table t (a int primary key); +insert t values (1), (2); +create or replace table tp (a int primary key) +partition by hash(a) partitions 2; +insert tp values (1), (2), (3), (4); +alter table tp exchange partition p0 with table t; +ERROR HY000: Found a row that does not match the partition +alter table tp exchange partition p0 with table t without validation; +select * from t; +a +2 +4 +alter table tp exchange partition p0 with table t; +drop table tp; +create or replace table tp (a int primary key) +partition by list(a) ( +partition p0 values in (2, 3, 4), +partition p1 values in (12, 13, 14), +partition p2 values in (52, 53, 54)); +insert tp values (12), (2), (3), (4); +alter table tp exchange partition p0 with table t; +ERROR HY000: Table has no partition for value 0 +alter table tp exchange partition p0 with table t without validation; +select * from t; +a +2 +3 +4 +alter table tp exchange partition p0 with table t; +drop tables tp, t; +# End of 11.4 tests diff --git a/mysql-test/suite/parts/t/alter_table.test b/mysql-test/suite/parts/t/alter_table.test index 9b75add3afa..c1e6df2840b 100644 --- a/mysql-test/suite/parts/t/alter_table.test +++ b/mysql-test/suite/parts/t/alter_table.test @@ -319,3 +319,132 @@ alter table t1 convert table tp to partition p2 values less than (1000); --connection default drop user u@localhost; drop database db; + +--echo # +--echo # MDEV-22164 without validation for exchange partition/convert in +--echo # + +create table validation(x int); +drop table validation; + +create table t (a int primary key); + +create table tp (a int primary key) partition by range (a) ( + partition p0 values less than (100), + # Cunning syntax (same as above) + p1 values less (300)); + +insert into t values (1), (99); +insert into tp values (2), (200); + +select * from t order by a; +select * from tp partition (p0) order by a; +select * from tp partition (p1) order by a; + +alter table tp exchange partition p0 with table t; +select * from t order by a; +select * from tp partition (p0) order by a; +select * from tp partition (p1) order by a; + +alter table tp exchange partition p0 with table t; +select * from t order by a; +select * from tp partition (p0) order by a; +select * from tp partition (p1) order by a; + +--error ER_ROW_DOES_NOT_MATCH_PARTITION +alter table tp exchange partition p1 with table t; +--error ER_ROW_DOES_NOT_MATCH_PARTITION +alter table tp exchange partition p1 with table t with validation; +alter table tp exchange partition p1 with table t without validation; +select * from t order by a; +select * from tp partition (p1) order by a; +alter table tp check partition p0; +alter table tp check partition p1; + +alter table tp exchange partition p1 with table t with validation; +--error ER_ROW_DOES_NOT_MATCH_PARTITION +alter table tp exchange partition p1 with table t with validation; +select * from t order by a; +select * from tp partition (p1) order by a; + +# SP +create or replace procedure validation() +alter table tp exchange partition p1 with table t with validation; +create or replace procedure without_validation() +alter table tp exchange partition p1 with table t without validation; +--error ER_ROW_DOES_NOT_MATCH_PARTITION +call validation; +call without_validation; +call validation; +--error ER_ROW_DOES_NOT_MATCH_PARTITION +call validation; +call without_validation; +select * from t order by a; +select * from tp partition (p1) order by a; +call validation; +select * from t order by a; +select * from tp partition (p1) order by a; +drop procedure validation; +drop procedure without_validation; + +# PS +prepare validation from "alter table tp exchange partition p1 with table t with validation"; +prepare without_validation from "alter table tp exchange partition p1 with table t without validation"; +--error ER_ROW_DOES_NOT_MATCH_PARTITION +execute validation; +execute without_validation; +execute validation; +--error ER_ROW_DOES_NOT_MATCH_PARTITION +execute validation; +execute without_validation; +select * from t order by a; +select * from tp partition (p1) order by a; +execute validation; +select * from t order by a; +select * from tp partition (p1) order by a; +drop prepare validation; +drop prepare without_validation; + +# CONVERT IN +--error ER_ROW_DOES_NOT_MATCH_PARTITION +alter table tp convert table t to partition p2 values less (maxvalue); +--error ER_ROW_DOES_NOT_MATCH_PARTITION +alter table tp convert table t to partition p2 values less (maxvalue) with validation; +alter table tp convert table t to partition p2 values less (maxvalue) without validation; +select * from tp partition (p0) order by a; +select * from tp partition (p1) order by a; +select * from tp partition (p2) order by a; + +# Hash +create table t (a int primary key); +insert t values (1), (2); + +create or replace table tp (a int primary key) +partition by hash(a) partitions 2; + +insert tp values (1), (2), (3), (4); +--error ER_ROW_DOES_NOT_MATCH_PARTITION +alter table tp exchange partition p0 with table t; +alter table tp exchange partition p0 with table t without validation; +select * from t; +alter table tp exchange partition p0 with table t; +drop table tp; + +# List +create or replace table tp (a int primary key) +partition by list(a) ( + partition p0 values in (2, 3, 4), + partition p1 values in (12, 13, 14), + partition p2 values in (52, 53, 54)); + + +insert tp values (12), (2), (3), (4); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +alter table tp exchange partition p0 with table t; +alter table tp exchange partition p0 with table t without validation; +select * from t; +alter table tp exchange partition p0 with table t; + +drop tables tp, t; + +--echo # End of 11.4 tests diff --git a/sql/lex.h b/sql/lex.h index fc48ace64dc..4900ef59625 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -714,6 +714,7 @@ SYMBOL symbols[] = { { "UTC_DATE", SYM(UTC_DATE_SYM)}, { "UTC_TIME", SYM(UTC_TIME_SYM)}, { "UTC_TIMESTAMP", SYM(UTC_TIMESTAMP_SYM)}, + { "VALIDATION", SYM(VALIDATION_SYM)}, { "VALUE", SYM(VALUE_SYM)}, { "VALUES", SYM(VALUES)}, { "VARBINARY", SYM(VARBINARY)}, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a84fd29affc..76210b5e56a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1301,6 +1301,7 @@ void LEX::start(THD *thd_arg) default_used= 0; with_rownum= FALSE; is_lex_started= 1; + without_validation= 0; create_info.lex_start(); name= null_clex_str; @@ -3932,7 +3933,7 @@ LEX::LEX() : explain(NULL), result(0), part_info(NULL), arena_for_set_stmt(0), mem_root_for_set_stmt(0), json_table(NULL), analyze_stmt(0), default_used(0), - with_rownum(0), is_lex_started(0), option_type(OPT_DEFAULT), + with_rownum(0), is_lex_started(0), without_validation(0), option_type(OPT_DEFAULT), context_analysis_only(0), sphead(0), sp_mem_root_ptr(nullptr), limit_rows_examined_cnt(ULONGLONG_MAX) { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7c2a112c56e..f0c20040996 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3440,6 +3440,7 @@ public: bool default_used:1; /* using default() function */ bool with_rownum:1; /* Using rownum() function */ bool is_lex_started:1; /* If lex_start() did run. For debugging. */ + bool without_validation:1; /* exchange or convert partition WITHOUT VALIDATION */ /* This variable is used in post-parse stage to declare that sum-functions, diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 958c52fd95c..466542b92e9 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4107,6 +4107,9 @@ bool verify_data_with_partition(TABLE *table, TABLE *part_table, DBUG_ASSERT(table && table->file && part_table && part_table->part_info && part_table->file); + if (table->in_use->lex->without_validation) + DBUG_RETURN(false); + /* Verify all table rows. First implementation uses full scan + evaluates partition functions for diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index fcfe490c035..380fbed7c6c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1151,6 +1151,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token UPGRADE_SYM %token USER_SYM /* SQL-2003-R */ %token USE_FRM +%token VALIDATION_SYM /* MYSQL */ %token VALUE_SYM /* SQL-2003-R */ %token VARCHAR2_MARIADB_SYM %token VARCHAR2_ORACLE_SYM /* Oracle-R, PLSQL-R */ @@ -4932,6 +4933,10 @@ part_name: } ; +opt_than: + /* empty */ + | THAN_SYM; + opt_part_values: /* empty */ { @@ -4949,7 +4954,7 @@ opt_part_values: else part_info->part_type= HASH_PARTITION; } - | VALUES_LESS_SYM THAN_SYM + | VALUES_LESS_SYM opt_than { LEX *lex= Lex; partition_info *part_info= lex->part_info; @@ -7497,13 +7502,13 @@ alter_commands: } | reorg_partition_rule | EXCHANGE_SYM PARTITION_SYM alt_part_name_item - WITH TABLE_SYM table_ident have_partitioning + WITH TABLE_SYM table_ident opt_without_validation have_partitioning { if (Lex->stmt_alter_table_exchange_partition($6)) MYSQL_YYABORT; } | CONVERT_SYM PARTITION_SYM alt_part_name_item - TO_SYM TABLE_SYM table_ident have_partitioning + TO_SYM TABLE_SYM table_ident opt_without_validation have_partitioning { LEX *lex= Lex; if (Lex->stmt_alter_table($6)) @@ -7543,7 +7548,7 @@ alter_commands: lex->alter_info.partition_flags|= ALTER_PARTITION_ADD | ALTER_PARTITION_CONVERT_IN; } - TO_SYM PARTITION_SYM part_definition + TO_SYM PARTITION_SYM part_definition opt_without_validation have_partitioning { LEX *lex= Lex; lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table(); @@ -7870,6 +7875,18 @@ alter_list_item: } ; +opt_without_validation: + /* empty */ + | WITH VALIDATION_SYM + { + Lex->without_validation= 0; + } + | WITHOUT VALIDATION_SYM + { + Lex->without_validation= 1; + } + ; + opt_index_lock_algorithm: /* empty */ | alter_lock_option @@ -16303,6 +16320,7 @@ keyword_sp_var_and_label: | VIEW_SYM | VIRTUAL_SYM | VISIBLE_SYM + | VALIDATION_SYM | VALUE_SYM | WARNINGS | WAIT_SYM