diff options
-rw-r--r-- | mysql-test/r/check_constraint.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/gcol/inc/gcol_column_def_options.inc | 2 | ||||
-rw-r--r-- | mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result | 2 | ||||
-rw-r--r-- | mysql-test/t/check_constraint.test | 6 | ||||
-rw-r--r-- | sql/field.h | 27 | ||||
-rw-r--r-- | sql/item.cc | 9 | ||||
-rw-r--r-- | sql/item.h | 5 | ||||
-rw-r--r-- | sql/table.cc | 18 |
9 files changed, 59 insertions, 14 deletions
diff --git a/mysql-test/r/check_constraint.result b/mysql-test/r/check_constraint.result index 7447550ed09..fcda0a84fcb 100644 --- a/mysql-test/r/check_constraint.result +++ b/mysql-test/r/check_constraint.result @@ -140,6 +140,8 @@ create table t1 (a int, b int, check(a>0)); alter table t1 drop column a; ERROR 42S22: Unknown column 'a' in 'CHECK' drop table t1; +create or replace table t1( c1 int auto_increment primary key, check( c1 > 0 or c1 is null ) ); +ERROR HY000: Function or expression 'AUTO_INCREMENT' cannot be used in the CHECK clause of `c1` create table t1 (a int check (@b in (select user from mysql.user))); ERROR HY000: Function or expression 'select ...' cannot be used in the CHECK clause of `a` create table t1 (a int check (a > @b)); diff --git a/mysql-test/suite/gcol/inc/gcol_column_def_options.inc b/mysql-test/suite/gcol/inc/gcol_column_def_options.inc index f132c2f2f63..ac70701e2cc 100644 --- a/mysql-test/suite/gcol/inc/gcol_column_def_options.inc +++ b/mysql-test/suite/gcol/inc/gcol_column_def_options.inc @@ -198,7 +198,7 @@ drop table t1; create table t1 (a int, b int generated always as(-b) virtual, c int generated always as (b + 1) virtual); --error ER_EXPRESSION_REFERS_TO_UNINIT_FIELD create table t1 (a int, b int generated always as(-c) virtual, c int generated always as (b + 1) virtual); ---error ER_EXPRESSION_REFERS_TO_UNINIT_FIELD +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED create table t1 (pk int auto_increment primary key, col_int_nokey int generated always as (pk + col_int_key) stored, col_int_key int); --echo # Bug#20339347: FAIL TO USE CREATE ....SELECT STATEMENT TO CREATE A NEW TABLE diff --git a/mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result b/mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result index c4a54999614..e93d3bf025a 100644 --- a/mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result @@ -259,7 +259,7 @@ ERROR 01000: Expression for field `b` is refering to uninitialized field `b` create table t1 (a int, b int generated always as(-c) virtual, c int generated always as (b + 1) virtual); ERROR 01000: Expression for field `b` is refering to uninitialized field `c` create table t1 (pk int auto_increment primary key, col_int_nokey int generated always as (pk + col_int_key) stored, col_int_key int); -ERROR 01000: Expression for field `col_int_nokey` is refering to uninitialized field `pk` +ERROR HY000: Function or expression 'AUTO_INCREMENT' cannot be used in the GENERATED ALWAYS AS clause of `pk` # Bug#20339347: FAIL TO USE CREATE ....SELECT STATEMENT TO CREATE A NEW TABLE create table t1 (a int, b int generated always as(-a) virtual, c int generated always as (b + 1) stored); insert into t1(a) values(1),(2); diff --git a/mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result b/mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result index 0f66b3ad779..563883adce0 100644 --- a/mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result @@ -259,7 +259,7 @@ ERROR 01000: Expression for field `b` is refering to uninitialized field `b` create table t1 (a int, b int generated always as(-c) virtual, c int generated always as (b + 1) virtual); ERROR 01000: Expression for field `b` is refering to uninitialized field `c` create table t1 (pk int auto_increment primary key, col_int_nokey int generated always as (pk + col_int_key) stored, col_int_key int); -ERROR 01000: Expression for field `col_int_nokey` is refering to uninitialized field `pk` +ERROR HY000: Function or expression 'AUTO_INCREMENT' cannot be used in the GENERATED ALWAYS AS clause of `pk` # Bug#20339347: FAIL TO USE CREATE ....SELECT STATEMENT TO CREATE A NEW TABLE create table t1 (a int, b int generated always as(-a) virtual, c int generated always as (b + 1) stored); insert into t1(a) values(1),(2); diff --git a/mysql-test/t/check_constraint.test b/mysql-test/t/check_constraint.test index 437463ee457..c70a208f774 100644 --- a/mysql-test/t/check_constraint.test +++ b/mysql-test/t/check_constraint.test @@ -88,6 +88,12 @@ alter table t1 drop column a; drop table t1; # +# MDEV-11117 CHECK constraint fails on intermediate step of ALTER +# +-- error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create or replace table t1( c1 int auto_increment primary key, check( c1 > 0 or c1 is null ) ); + +# # MDEV-12421 Check constraint with query crashes server and renders DB unusable # --error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED diff --git a/sql/field.h b/sql/field.h index 7aa45cf1177..14f14afdaf7 100644 --- a/sql/field.h +++ b/sql/field.h @@ -563,7 +563,10 @@ inline bool is_temporal_type_with_time(enum_field_types type) enum enum_vcol_info_type { VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, - VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE + VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE, + /* Additional types should be added here */ + /* Following is the highest value last */ + VCOL_TYPE_NONE = 127 // Since the 0 value is already in use }; static inline const char *vcol_type_name(enum_vcol_info_type type) @@ -578,6 +581,8 @@ static inline const char *vcol_type_name(enum_vcol_info_type type) case VCOL_CHECK_FIELD: case VCOL_CHECK_TABLE: return "CHECK"; + case VCOL_TYPE_NONE: + return "UNTYPED"; } return 0; } @@ -591,7 +596,8 @@ static inline const char *vcol_type_name(enum_vcol_info_type type) #define VCOL_NON_DETERMINISTIC 2 #define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */ #define VCOL_TIME_FUNC 8 -#define VCOL_IMPOSSIBLE 16 +#define VCOL_AUTO_INC 16 +#define VCOL_IMPOSSIBLE 32 #define VCOL_NOT_STRICTLY_DETERMINISTIC \ (VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC) @@ -609,6 +615,7 @@ static inline const char *vcol_type_name(enum_vcol_info_type type) class Virtual_column_info: public Sql_alloc { private: + enum_vcol_info_type vcol_type; /* Virtual column expression type */ /* The following data is only updated by the parser and read when a Create_field object is created/initialized. @@ -626,7 +633,8 @@ public: uint flags; Virtual_column_info() - : field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL), + : vcol_type((enum_vcol_info_type)VCOL_TYPE_NONE), + field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL), in_partitioning_expr(FALSE), stored_in_db(FALSE), utf8(TRUE), expr(NULL), flags(0) { @@ -634,6 +642,19 @@ public: name.length= 0; }; ~Virtual_column_info() {} + enum_vcol_info_type get_vcol_type() const + { + return vcol_type; + } + void set_vcol_type(enum_vcol_info_type v_type) + { + vcol_type= v_type; + } + const char *get_vcol_type_name() const + { + DBUG_ASSERT(vcol_type != VCOL_TYPE_NONE); + return vcol_type_name(vcol_type); + } enum_field_types get_real_type() const { return field_type; diff --git a/sql/item.cc b/sql/item.cc index 08316d95276..446176ff398 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -979,7 +979,7 @@ bool Item_field::register_field_in_write_map(void *arg) This means: - For default fields we can't access the same field or a field after itself that doesn't have a non-constant default value. - - A virtual fields can't access itself or a virtual field after itself. + - A virtual field can't access itself or a virtual field after itself. - user-specified values will not see virtual fields or default expressions, as in INSERT t1 (a) VALUES (b); - no virtual fields can access auto-increment values @@ -995,13 +995,6 @@ bool Item_field::check_field_expression_processor(void *arg) Field *org_field= (Field*) arg; if (field->flags & NO_DEFAULT_VALUE_FLAG) return 0; - if (field->flags & AUTO_INCREMENT_FLAG) - { - my_error(ER_EXPRESSION_REFERS_TO_UNINIT_FIELD, - MYF(0), - org_field->field_name, field->field_name); - return 1; - } if ((field->default_value && field->default_value->flags) || field->vcol_info) { if (field == org_field || diff --git a/sql/item.h b/sql/item.h index 6d69e3b60de..078641c490c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2611,6 +2611,11 @@ public: bool check_vcol_func_processor(void *arg) { context= 0; + if (field && (field->unireg_check == Field::NEXT_NUMBER)) + { + // Auto increment fields are unsupported + return mark_unsupported_function(field_name, arg, VCOL_FIELD_REF | VCOL_AUTO_INC); + } return mark_unsupported_function(field_name, arg, VCOL_FIELD_REF); } void cleanup(); diff --git a/sql/table.cc b/sql/table.cc index 6d1a3a7f8d8..380da5fcd7b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1962,6 +1962,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, unireg_check == Field::TIMESTAMP_DN_FIELD) { reg_field->default_value= new (&share->mem_root) Virtual_column_info(); + reg_field->default_value->set_vcol_type(VCOL_DEFAULT); reg_field->default_value->stored_in_db= 1; share->default_expressions++; } @@ -2361,6 +2362,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (!(vcol_info= new (&share->mem_root) Virtual_column_info())) goto err; + /* The following can only be true for check_constraints */ if (field_nr != UINT_MAX16) @@ -2370,6 +2372,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE; + vcol_info->set_vcol_type((enum_vcol_info_type) type); vcol_info->name.length= name_length; if (name_length) vcol_info->name.str= strmake_root(&share->mem_root, @@ -2811,6 +2814,20 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, "???", "?????"); DBUG_RETURN(1); } + else if (res.errors & VCOL_AUTO_INC) + { + /* + An auto_increment field may not be used in an expression for + a check constraint, a default value or a generated column + + Note that this error condition is not detected during parsing + of the statement because the field item does not have a field + pointer at that time + */ + my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), + "AUTO_INCREMENT", vcol->get_vcol_type_name(), res.name); + DBUG_RETURN(1); + } vcol->flags= res.errors; if (vcol->flags & VCOL_SESSION_FUNC) @@ -2879,6 +2896,7 @@ unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table, if (error) goto end; + vcol_storage.vcol_info->set_vcol_type(vcol->get_vcol_type()); vcol_storage.vcol_info->stored_in_db= vcol->stored_in_db; vcol_storage.vcol_info->name= vcol->name; vcol_storage.vcol_info->utf8= vcol->utf8; |