Skip to content

Commit 094f4cf

Browse files
committed
Fixed bug mdev-3845.
If triggers are used for an insert/update/delete statement than the values of all virtual columns must be computed as any of them may be used by the triggers.
1 parent b0fec77 commit 094f4cf

File tree

10 files changed

+165
-18
lines changed

10 files changed

+165
-18
lines changed

mysql-test/suite/vcol/inc/vcol_trigger_sp.inc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,44 @@ select * from t1;
108108

109109
drop table t1,t2;
110110
drop procedure p1;
111+
112+
--echo #
113+
--echo # Bug mdev-3845: values of virtual columns are not computed for triggers
114+
--echo #
115+
116+
CREATE TABLE t1 (
117+
a INTEGER UNSIGNED NULL DEFAULT NULL,
118+
b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL
119+
);
120+
121+
CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL);
122+
123+
DELIMITER |;
124+
125+
CREATE TRIGGER t1_ins_aft
126+
AFTER INSERT
127+
ON t1
128+
FOR EACH ROW
129+
BEGIN
130+
INSERT INTO t2 (c) VALUES (NEW.b);
131+
END |
132+
133+
CREATE TRIGGER t1_del_bef
134+
BEFORE DELETE
135+
ON t1
136+
FOR EACH ROW
137+
BEGIN
138+
INSERT INTO t2 (c) VALUES (OLD.b);
139+
END |
140+
141+
DELIMITER ;|
142+
143+
INSERT INTO t1 (a) VALUES (1), (2), (3);
144+
SELECT * FROM t2;
145+
DELETE FROM t1;
146+
SELECT * FROM t2;
147+
148+
DROP TRIGGER t1_ins_aft;
149+
DROP TRIGGER t1_del_bef;
150+
DROP TABLE t1,t2;
151+

mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,43 @@ a b c
8585
300 30 30
8686
drop table t1,t2;
8787
drop procedure p1;
88+
#
89+
# Bug mdev-3845: values of virtual columns are not computed for triggers
90+
#
91+
CREATE TABLE t1 (
92+
a INTEGER UNSIGNED NULL DEFAULT NULL,
93+
b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL
94+
);
95+
CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL);
96+
CREATE TRIGGER t1_ins_aft
97+
AFTER INSERT
98+
ON t1
99+
FOR EACH ROW
100+
BEGIN
101+
INSERT INTO t2 (c) VALUES (NEW.b);
102+
END |
103+
CREATE TRIGGER t1_del_bef
104+
BEFORE DELETE
105+
ON t1
106+
FOR EACH ROW
107+
BEGIN
108+
INSERT INTO t2 (c) VALUES (OLD.b);
109+
END |
110+
INSERT INTO t1 (a) VALUES (1), (2), (3);
111+
SELECT * FROM t2;
112+
c
113+
1
114+
2
115+
3
116+
DELETE FROM t1;
117+
SELECT * FROM t2;
118+
c
119+
1
120+
2
121+
3
122+
1
123+
2
124+
3
125+
DROP TRIGGER t1_ins_aft;
126+
DROP TRIGGER t1_del_bef;
127+
DROP TABLE t1,t2;

mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,43 @@ a b c
8585
300 30 30
8686
drop table t1,t2;
8787
drop procedure p1;
88+
#
89+
# Bug mdev-3845: values of virtual columns are not computed for triggers
90+
#
91+
CREATE TABLE t1 (
92+
a INTEGER UNSIGNED NULL DEFAULT NULL,
93+
b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL
94+
);
95+
CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL);
96+
CREATE TRIGGER t1_ins_aft
97+
AFTER INSERT
98+
ON t1
99+
FOR EACH ROW
100+
BEGIN
101+
INSERT INTO t2 (c) VALUES (NEW.b);
102+
END |
103+
CREATE TRIGGER t1_del_bef
104+
BEFORE DELETE
105+
ON t1
106+
FOR EACH ROW
107+
BEGIN
108+
INSERT INTO t2 (c) VALUES (OLD.b);
109+
END |
110+
INSERT INTO t1 (a) VALUES (1), (2), (3);
111+
SELECT * FROM t2;
112+
c
113+
1
114+
2
115+
3
116+
DELETE FROM t1;
117+
SELECT * FROM t2;
118+
c
119+
1
120+
2
121+
3
122+
1
123+
2
124+
3
125+
DROP TRIGGER t1_ins_aft;
126+
DROP TRIGGER t1_del_bef;
127+
DROP TABLE t1,t2;

sql/mysql_priv.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,8 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
13661366
bool allow_rowid, uint *cached_field_index_ptr);
13671367
Field *
13681368
find_field_in_table_sef(TABLE *table, const char *name);
1369-
int update_virtual_fields(THD *thd, TABLE *table, bool ignore_stored= FALSE);
1369+
int update_virtual_fields(THD *thd, TABLE *table,
1370+
enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ);
13701371

13711372
#endif /* MYSQL_SERVER */
13721373

sql/sql_base.cc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8460,7 +8460,9 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
84608460
{
84618461
if (vcol_table->vfield)
84628462
{
8463-
if (update_virtual_fields(thd, vcol_table, TRUE))
8463+
if (update_virtual_fields(thd, vcol_table,
8464+
vcol_table->triggers ? VCOL_UPDATE_ALL :
8465+
VCOL_UPDATE_FOR_WRITE))
84648466
goto err;
84658467
}
84668468
}
@@ -8524,7 +8526,9 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
85248526
if (item_field && item_field->field &&
85258527
(table= item_field->field->table) &&
85268528
table->vfield)
8527-
result= update_virtual_fields(thd, table, TRUE);
8529+
result= update_virtual_fields(thd, table,
8530+
table->triggers ? VCOL_UPDATE_ALL :
8531+
VCOL_UPDATE_FOR_WRITE);
85288532
}
85298533
}
85308534
return result;
@@ -8604,7 +8608,10 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
86048608
}
86058609
/* Update virtual fields*/
86068610
thd->abort_on_warning= FALSE;
8607-
if (table->vfield && update_virtual_fields(thd, table, TRUE))
8611+
if (table->vfield &&
8612+
update_virtual_fields(thd, table,
8613+
table->triggers ? VCOL_UPDATE_ALL :
8614+
VCOL_UPDATE_FOR_WRITE))
86088615
goto err;
86098616
thd->abort_on_warning= abort_on_warning_saved;
86108617
DBUG_RETURN(thd->is_error());
@@ -8657,7 +8664,9 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
86578664
{
86588665
TABLE *table= (*ptr)->table;
86598666
if (table->vfield)
8660-
result= update_virtual_fields(thd, table, TRUE);
8667+
result= update_virtual_fields(thd, table,
8668+
table->triggers ? VCOL_UPDATE_ALL :
8669+
VCOL_UPDATE_FOR_WRITE);
86618670
}
86628671
return result;
86638672

sql/sql_delete.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
313313
while (!(error=info.read_record(&info)) && !thd->killed &&
314314
! thd->is_error())
315315
{
316-
update_virtual_fields(thd, table);
316+
update_virtual_fields(thd, table,
317+
triggers_applicable ? VCOL_UPDATE_ALL :
318+
VCOL_UPDATE_FOR_READ);
317319
thd->examined_row_count++;
318320
// thd->is_error() is tested to disallow delete row on error
319321
if (!select || select->skip_record(thd) > 0)

sql/sql_table.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8066,7 +8066,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
80668066
copy_ptr->do_copy(copy_ptr);
80678067
}
80688068
prev_insert_id= to->file->next_insert_id;
8069-
update_virtual_fields(thd, to, TRUE);
8069+
update_virtual_fields(thd, to, VCOL_UPDATE_FOR_WRITE);
80708070
if (thd->is_error())
80718071
{
80728072
error= 1;

sql/sql_update.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,9 @@ int mysql_update(THD *thd,
490490

491491
while (!(error=info.read_record(&info)) && !thd->killed)
492492
{
493-
update_virtual_fields(thd, table);
493+
update_virtual_fields(thd, table,
494+
table->triggers ? VCOL_UPDATE_ALL :
495+
VCOL_UPDATE_FOR_READ);
494496
thd->examined_row_count++;
495497
if (!select || (error= select->skip_record(thd)) > 0)
496498
{
@@ -605,7 +607,9 @@ int mysql_update(THD *thd,
605607

606608
while (!(error=info.read_record(&info)) && !thd->killed)
607609
{
608-
update_virtual_fields(thd, table);
610+
update_virtual_fields(thd, table,
611+
table->triggers ? VCOL_UPDATE_ALL :
612+
VCOL_UPDATE_FOR_READ);
609613
thd->examined_row_count++;
610614
if (!select || select->skip_record(thd) > 0)
611615
{

sql/table.cc

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5500,22 +5500,25 @@ size_t max_row_length(TABLE *table, const uchar *data)
55005500
55015501
@param thd Thread handle
55025502
@param table The TABLE object
5503-
@param for_write Requests to compute only fields needed for write
5503+
@param vcol_update_mode Specifies what virtual column are computed
55045504
55055505
@details
55065506
The function computes the values of the virtual columns of the table and
55075507
stores them in the table record buffer.
5508-
Only fields from vcol_set are computed, and, when the flag for_write is not
5509-
set to TRUE, a virtual field is computed only if it's not stored.
5510-
The flag for_write is set to TRUE for row insert/update operations.
5511-
5508+
If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are
5509+
computed. Otherwise, only fields from vcol_set are computed: all of them,
5510+
if vcol_update_mode is set to VCOL_UPDATE_FOR_WRITE, and, only those with
5511+
the stored_in_db flag set to false, if vcol_update_mode is equal to
5512+
VCOL_UPDATE_FOR_READ.
5513+
55125514
@retval
55135515
0 Success
55145516
@retval
55155517
>0 Error occurred when storing a virtual field value
55165518
*/
55175519

5518-
int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
5520+
int update_virtual_fields(THD *thd, TABLE *table,
5521+
enum enum_vcol_update_mode vcol_update_mode)
55195522
{
55205523
DBUG_ENTER("update_virtual_fields");
55215524
Field **vfield_ptr, *vfield;
@@ -5529,9 +5532,9 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
55295532
{
55305533
vfield= (*vfield_ptr);
55315534
DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item);
5532-
/* Only update those fields that are marked in the vcol_set bitmap */
5533-
if (bitmap_is_set(table->vcol_set, vfield->field_index) &&
5534-
(for_write || !vfield->stored_in_db))
5535+
if ((bitmap_is_set(table->vcol_set, vfield->field_index) &&
5536+
(vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) ||
5537+
vcol_update_mode == VCOL_UPDATE_ALL)
55355538
{
55365539
/* Compute the actual value of the virtual fields */
55375540
error= vfield->vcol_info->expr_item->save_in_field(vfield, 0);

sql/table.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ enum frm_type_enum
156156

157157
enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP };
158158

159+
enum enum_vcol_update_mode
160+
{
161+
VCOL_UPDATE_FOR_READ= 0,
162+
VCOL_UPDATE_FOR_WRITE,
163+
VCOL_UPDATE_ALL
164+
};
165+
159166
typedef struct st_filesort_info
160167
{
161168
IO_CACHE *io_cache; /* If sorted through filesort */

0 commit comments

Comments
 (0)