mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-11117 CHECK constraint fails on intermediate step of ALTER
Fixed the bug by failing the statement with an error message that explains that an auto-increment column may not be used in an expression for a check constraint. Added a test case in check_constraint.test. Updated existing tests and results.
This commit is contained in:
@@ -140,6 +140,8 @@ create table t1 (a int, b int, check(a>0));
|
|||||||
alter table t1 drop column a;
|
alter table t1 drop column a;
|
||||||
ERROR 42S22: Unknown column 'a' in 'CHECK'
|
ERROR 42S22: Unknown column 'a' in 'CHECK'
|
||||||
drop table t1;
|
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)));
|
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`
|
ERROR HY000: Function or expression 'select ...' cannot be used in the CHECK clause of `a`
|
||||||
create table t1 (a int check (a > @b));
|
create table t1 (a int check (a > @b));
|
||||||
|
@@ -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);
|
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
|
--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);
|
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);
|
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
|
--echo # Bug#20339347: FAIL TO USE CREATE ....SELECT STATEMENT TO CREATE A NEW TABLE
|
||||||
|
@@ -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);
|
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`
|
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);
|
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
|
# 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);
|
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);
|
insert into t1(a) values(1),(2);
|
||||||
|
@@ -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);
|
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`
|
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);
|
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
|
# 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);
|
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);
|
insert into t1(a) values(1),(2);
|
||||||
|
@@ -87,6 +87,12 @@ create table t1 (a int, b int, check(a>0));
|
|||||||
alter table t1 drop column a;
|
alter table t1 drop column a;
|
||||||
drop table t1;
|
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
|
# MDEV-12421 Check constraint with query crashes server and renders DB unusable
|
||||||
#
|
#
|
||||||
|
27
sql/field.h
27
sql/field.h
@@ -563,7 +563,10 @@ inline bool is_temporal_type_with_time(enum_field_types type)
|
|||||||
enum enum_vcol_info_type
|
enum enum_vcol_info_type
|
||||||
{
|
{
|
||||||
VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED,
|
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)
|
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_FIELD:
|
||||||
case VCOL_CHECK_TABLE:
|
case VCOL_CHECK_TABLE:
|
||||||
return "CHECK";
|
return "CHECK";
|
||||||
|
case VCOL_TYPE_NONE:
|
||||||
|
return "UNTYPED";
|
||||||
}
|
}
|
||||||
return 0;
|
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_NON_DETERMINISTIC 2
|
||||||
#define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */
|
#define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */
|
||||||
#define VCOL_TIME_FUNC 8
|
#define VCOL_TIME_FUNC 8
|
||||||
#define VCOL_IMPOSSIBLE 16
|
#define VCOL_AUTO_INC 16
|
||||||
|
#define VCOL_IMPOSSIBLE 32
|
||||||
|
|
||||||
#define VCOL_NOT_STRICTLY_DETERMINISTIC \
|
#define VCOL_NOT_STRICTLY_DETERMINISTIC \
|
||||||
(VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC)
|
(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
|
class Virtual_column_info: public Sql_alloc
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
enum_vcol_info_type vcol_type; /* Virtual column expression type */
|
||||||
/*
|
/*
|
||||||
The following data is only updated by the parser and read
|
The following data is only updated by the parser and read
|
||||||
when a Create_field object is created/initialized.
|
when a Create_field object is created/initialized.
|
||||||
@@ -626,7 +633,8 @@ public:
|
|||||||
uint flags;
|
uint flags;
|
||||||
|
|
||||||
Virtual_column_info()
|
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),
|
in_partitioning_expr(FALSE), stored_in_db(FALSE),
|
||||||
utf8(TRUE), expr(NULL), flags(0)
|
utf8(TRUE), expr(NULL), flags(0)
|
||||||
{
|
{
|
||||||
@@ -634,6 +642,19 @@ public:
|
|||||||
name.length= 0;
|
name.length= 0;
|
||||||
};
|
};
|
||||||
~Virtual_column_info() {}
|
~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
|
enum_field_types get_real_type() const
|
||||||
{
|
{
|
||||||
return field_type;
|
return field_type;
|
||||||
|
@@ -979,7 +979,7 @@ bool Item_field::register_field_in_write_map(void *arg)
|
|||||||
This means:
|
This means:
|
||||||
- For default fields we can't access the same field or a field after
|
- For default fields we can't access the same field or a field after
|
||||||
itself that doesn't have a non-constant default value.
|
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,
|
- user-specified values will not see virtual fields or default expressions,
|
||||||
as in INSERT t1 (a) VALUES (b);
|
as in INSERT t1 (a) VALUES (b);
|
||||||
- no virtual fields can access auto-increment values
|
- 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;
|
Field *org_field= (Field*) arg;
|
||||||
if (field->flags & NO_DEFAULT_VALUE_FLAG)
|
if (field->flags & NO_DEFAULT_VALUE_FLAG)
|
||||||
return 0;
|
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->default_value && field->default_value->flags) || field->vcol_info)
|
||||||
{
|
{
|
||||||
if (field == org_field ||
|
if (field == org_field ||
|
||||||
|
@@ -2611,6 +2611,11 @@ public:
|
|||||||
bool check_vcol_func_processor(void *arg)
|
bool check_vcol_func_processor(void *arg)
|
||||||
{
|
{
|
||||||
context= 0;
|
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);
|
return mark_unsupported_function(field_name, arg, VCOL_FIELD_REF);
|
||||||
}
|
}
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
18
sql/table.cc
18
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)
|
unireg_check == Field::TIMESTAMP_DN_FIELD)
|
||||||
{
|
{
|
||||||
reg_field->default_value= new (&share->mem_root) Virtual_column_info();
|
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;
|
reg_field->default_value->stored_in_db= 1;
|
||||||
share->default_expressions++;
|
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()))
|
if (!(vcol_info= new (&share->mem_root) Virtual_column_info()))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* The following can only be true for check_constraints */
|
/* The following can only be true for check_constraints */
|
||||||
|
|
||||||
if (field_nr != UINT_MAX16)
|
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_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE;
|
||||||
|
vcol_info->set_vcol_type((enum_vcol_info_type) type);
|
||||||
vcol_info->name.length= name_length;
|
vcol_info->name.length= name_length;
|
||||||
if (name_length)
|
if (name_length)
|
||||||
vcol_info->name.str= strmake_root(&share->mem_root,
|
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);
|
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;
|
vcol->flags= res.errors;
|
||||||
|
|
||||||
if (vcol->flags & VCOL_SESSION_FUNC)
|
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)
|
if (error)
|
||||||
goto end;
|
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->stored_in_db= vcol->stored_in_db;
|
||||||
vcol_storage.vcol_info->name= vcol->name;
|
vcol_storage.vcol_info->name= vcol->name;
|
||||||
vcol_storage.vcol_info->utf8= vcol->utf8;
|
vcol_storage.vcol_info->utf8= vcol->utf8;
|
||||||
|
Reference in New Issue
Block a user