Skip to content

Commit cb1f9f6

Browse files
author
Benny Wang
committed
Fixed bug#22680839: DEFAULT IS NOT DETERMINISTIC AND SHOULD NOT BE ALLOWED IN
GENERATED COLUMNS Since it is possible to change the DEFAULT value for a column using ALTER TABLE, the DEFAULT function may not be considered deterministic. This can cause inconsistent results if the DEFAULT function is used in definition of generated columns after changing the DEFAULT value for a column. To avoid this problem, this patch make table rebuild if any column changes the default value and there is a dependency on DEFAULT function in a generated expression.
1 parent 8870f82 commit cb1f9f6

File tree

5 files changed

+191
-0
lines changed

5 files changed

+191
-0
lines changed

mysql-test/suite/gcol/inc/gcol_column_def_options.inc

+59
Original file line numberDiff line numberDiff line change
@@ -578,3 +578,62 @@ SET sql_mode= @sql_mode_save;
578578
DROP TABLE t1;
579579
--enable_warnings
580580
}
581+
582+
583+
--echo #
584+
--echo # Bug#22680839: DEFAULT IS NOT DETERMINISTIC AND SHOULD NOT BE
585+
--echo # ALLOWED IN GENERATED COLUMNS
586+
--echo #
587+
if ($support_virtual_index)
588+
{
589+
CREATE TABLE tzz(a INT DEFAULT 5,
590+
gc1 INT AS (a+DEFAULT(a)) VIRTUAL,
591+
gc2 INT AS (a+DEFAULT(a)) STORED,
592+
KEY k1(gc1));
593+
INSERT INTO tzz(A) VALUES (1);
594+
SELECT * FROM tzz;
595+
SELECT gc1 FROM tzz;
596+
597+
ALTER TABLE tzz MODIFY COLUMN a INT DEFAULT 6;
598+
SELECT * FROM tzz;
599+
SELECT gc1 FROM tzz;
600+
DROP TABLE tzz;
601+
}
602+
603+
--echo # Test 1: ALTER DEFAULT
604+
--echo #
605+
CREATE TABLE t1(a INT PRIMARY KEY DEFAULT 5,
606+
b INT AS (1 + DEFAULT(a)) STORED,
607+
c INT AS (1 + DEFAULT(a)) VIRTUAL);
608+
INSERT INTO t1 VALUES ();
609+
--error ER_ALTER_OPERATION_NOT_SUPPORTED
610+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7, ALGORITHM = INPLACE;
611+
--disable_warnings
612+
# Check how many rows are accessed: >0 = COPY
613+
--enable_info
614+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7;
615+
ALTER TABLE t1 MODIFY COLUMN a INT DEFAULT 8;
616+
ALTER TABLE t1 CHANGE COLUMN a a DOUBLE DEFAULT 5;
617+
--disable_info
618+
DROP TABLE t1;
619+
620+
--echo # Test 2: ALTER DEFAULT + ADD GCOL
621+
--echo #
622+
CREATE TABLE t1(a INT PRIMARY KEY DEFAULT 5);
623+
INSERT INTO t1 VALUES();
624+
--error ER_ALTER_OPERATION_NOT_SUPPORTED
625+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
626+
ADD COLUMN b INT AS (1 + DEFAULT(a)) STORED,
627+
ALGORITHM = INPLACE;
628+
--error ER_ALTER_OPERATION_NOT_SUPPORTED, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
629+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
630+
ADD COLUMN c INT AS (1 + DEFAULT(a)) VIRTUAL,
631+
ALGORITHM = INPLACE;
632+
# Check how many rows are accessed: >0 = COPY
633+
--enable_info
634+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
635+
ADD COLUMN b INT AS (1 + DEFAULT(a)) STORED,
636+
ADD COLUMN c INT AS (1 + DEFAULT(a)) VIRTUAL;
637+
--disable_info
638+
DROP TABLE t1;
639+
--enable_warnings

mysql-test/suite/gcol/r/gcol_column_def_options_innodb.result

+59
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,65 @@ a b c
723723
DELETE FROM t1 where a= 2;
724724
SET sql_mode= @sql_mode_save;
725725
DROP TABLE t1;
726+
#
727+
# Bug#22680839: DEFAULT IS NOT DETERMINISTIC AND SHOULD NOT BE
728+
# ALLOWED IN GENERATED COLUMNS
729+
#
730+
CREATE TABLE tzz(a INT DEFAULT 5,
731+
gc1 INT AS (a+DEFAULT(a)) VIRTUAL,
732+
gc2 INT AS (a+DEFAULT(a)) STORED,
733+
KEY k1(gc1));
734+
INSERT INTO tzz(A) VALUES (1);
735+
SELECT * FROM tzz;
736+
a gc1 gc2
737+
1 6 6
738+
SELECT gc1 FROM tzz;
739+
gc1
740+
6
741+
ALTER TABLE tzz MODIFY COLUMN a INT DEFAULT 6;
742+
SELECT * FROM tzz;
743+
a gc1 gc2
744+
1 7 7
745+
SELECT gc1 FROM tzz;
746+
gc1
747+
7
748+
DROP TABLE tzz;
749+
# Test 1: ALTER DEFAULT
750+
#
751+
CREATE TABLE t1(a INT PRIMARY KEY DEFAULT 5,
752+
b INT AS (1 + DEFAULT(a)) STORED,
753+
c INT AS (1 + DEFAULT(a)) VIRTUAL);
754+
INSERT INTO t1 VALUES ();
755+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7, ALGORITHM = INPLACE;
756+
ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY.
757+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7;
758+
affected rows: 1
759+
info: Records: 1 Duplicates: 0 Warnings: 0
760+
ALTER TABLE t1 MODIFY COLUMN a INT DEFAULT 8;
761+
affected rows: 1
762+
info: Records: 1 Duplicates: 0 Warnings: 0
763+
ALTER TABLE t1 CHANGE COLUMN a a DOUBLE DEFAULT 5;
764+
affected rows: 1
765+
info: Records: 1 Duplicates: 0 Warnings: 0
766+
DROP TABLE t1;
767+
# Test 2: ALTER DEFAULT + ADD GCOL
768+
#
769+
CREATE TABLE t1(a INT PRIMARY KEY DEFAULT 5);
770+
INSERT INTO t1 VALUES();
771+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
772+
ADD COLUMN b INT AS (1 + DEFAULT(a)) STORED,
773+
ALGORITHM = INPLACE;
774+
ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY.
775+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
776+
ADD COLUMN c INT AS (1 + DEFAULT(a)) VIRTUAL,
777+
ALGORITHM = INPLACE;
778+
Got one of the listed errors
779+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
780+
ADD COLUMN b INT AS (1 + DEFAULT(a)) STORED,
781+
ADD COLUMN c INT AS (1 + DEFAULT(a)) VIRTUAL;
782+
affected rows: 1
783+
info: Records: 1 Duplicates: 0 Warnings: 0
784+
DROP TABLE t1;
726785
DROP VIEW IF EXISTS v1,v2;
727786
DROP TABLE IF EXISTS t1,t2,t3;
728787
DROP PROCEDURE IF EXISTS p1;

mysql-test/suite/gcol/r/gcol_column_def_options_myisam.result

+40
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,46 @@ col1 col2 col3 col4 vgc1 sgc1
617617
1 10 100 111 1000 1000
618618
2 20 200 222 4000 4000
619619
DROP TABLE t1;
620+
#
621+
# Bug#22680839: DEFAULT IS NOT DETERMINISTIC AND SHOULD NOT BE
622+
# ALLOWED IN GENERATED COLUMNS
623+
#
624+
# Test 1: ALTER DEFAULT
625+
#
626+
CREATE TABLE t1(a INT PRIMARY KEY DEFAULT 5,
627+
b INT AS (1 + DEFAULT(a)) STORED,
628+
c INT AS (1 + DEFAULT(a)) VIRTUAL);
629+
INSERT INTO t1 VALUES ();
630+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7, ALGORITHM = INPLACE;
631+
ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY.
632+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7;
633+
affected rows: 1
634+
info: Records: 1 Duplicates: 0 Warnings: 0
635+
ALTER TABLE t1 MODIFY COLUMN a INT DEFAULT 8;
636+
affected rows: 1
637+
info: Records: 1 Duplicates: 0 Warnings: 0
638+
ALTER TABLE t1 CHANGE COLUMN a a DOUBLE DEFAULT 5;
639+
affected rows: 1
640+
info: Records: 1 Duplicates: 0 Warnings: 0
641+
DROP TABLE t1;
642+
# Test 2: ALTER DEFAULT + ADD GCOL
643+
#
644+
CREATE TABLE t1(a INT PRIMARY KEY DEFAULT 5);
645+
INSERT INTO t1 VALUES();
646+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
647+
ADD COLUMN b INT AS (1 + DEFAULT(a)) STORED,
648+
ALGORITHM = INPLACE;
649+
ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY.
650+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
651+
ADD COLUMN c INT AS (1 + DEFAULT(a)) VIRTUAL,
652+
ALGORITHM = INPLACE;
653+
Got one of the listed errors
654+
ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 7,
655+
ADD COLUMN b INT AS (1 + DEFAULT(a)) STORED,
656+
ADD COLUMN c INT AS (1 + DEFAULT(a)) VIRTUAL;
657+
affected rows: 1
658+
info: Records: 1 Duplicates: 0 Warnings: 0
659+
DROP TABLE t1;
620660
DROP VIEW IF EXISTS v1,v2;
621661
DROP TABLE IF EXISTS t1,t2,t3;
622662
DROP PROCEDURE IF EXISTS p1;

sql/item.h

+13
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,16 @@ class Item : public Parse_tree_node
20442044
virtual bool check_gcol_func_processor(uchar *int_arg)
20452045
{ return true; }
20462046

2047+
/**
2048+
Check if a generated expression depends on DEFAULT function.
2049+
2050+
@param arg ignored
2051+
2052+
@returns false if the function is not DEFAULT(), otherwise true.
2053+
*/
2054+
virtual bool check_gcol_depend_default_processor(uchar *arg)
2055+
{ return false; }
2056+
20472057
/**
20482058
@brief update_indexed_column_map
20492059
Update columns map for index.
@@ -4910,6 +4920,9 @@ class Item_default_value : public Item_field
49104920
((walk & WALK_POSTFIX) && (this->*processor)(args));
49114921
}
49124922

4923+
bool check_gcol_depend_default_processor(uchar *arg)
4924+
{ return true; }
4925+
49134926
Item *transform(Item_transformer transformer, uchar *args);
49144927
};
49154928

sql/sql_table.cc

+20
Original file line numberDiff line numberDiff line change
@@ -7187,6 +7187,26 @@ static bool is_inplace_alter_impossible(TABLE *table,
71877187
if (!table->s->mysql_version)
71887188
DBUG_RETURN(true);
71897189

7190+
/*
7191+
If default value is changed and the table includes or will include
7192+
generated columns that depend on the DEFAULT function, we cannot
7193+
do the operation inplace as indexes or value of stored generated
7194+
columns might become invalid.
7195+
*/
7196+
if ((alter_info->flags &
7197+
(Alter_info::ALTER_CHANGE_COLUMN_DEFAULT |
7198+
Alter_info::ALTER_CHANGE_COLUMN)) &&
7199+
table->has_gcol())
7200+
{
7201+
for (Field **vfield= table->vfield; *vfield; vfield++)
7202+
{
7203+
if ((*vfield)->gcol_info->expr_item->walk(
7204+
&Item::check_gcol_depend_default_processor,
7205+
Item::WALK_POSTFIX, NULL))
7206+
DBUG_RETURN(true);
7207+
}
7208+
}
7209+
71907210
DBUG_RETURN(false);
71917211
}
71927212

0 commit comments

Comments
 (0)