Commit 094f4cf7 authored by Igor Babaev's avatar Igor Babaev

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.
parent b0fec77d
...@@ -108,3 +108,44 @@ select * from t1; ...@@ -108,3 +108,44 @@ select * from t1;
drop table t1,t2; drop table t1,t2;
drop procedure p1; drop procedure p1;
--echo #
--echo # Bug mdev-3845: values of virtual columns are not computed for triggers
--echo #
CREATE TABLE t1 (
a INTEGER UNSIGNED NULL DEFAULT NULL,
b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL
);
CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL);
DELIMITER |;
CREATE TRIGGER t1_ins_aft
AFTER INSERT
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2 (c) VALUES (NEW.b);
END |
CREATE TRIGGER t1_del_bef
BEFORE DELETE
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2 (c) VALUES (OLD.b);
END |
DELIMITER ;|
INSERT INTO t1 (a) VALUES (1), (2), (3);
SELECT * FROM t2;
DELETE FROM t1;
SELECT * FROM t2;
DROP TRIGGER t1_ins_aft;
DROP TRIGGER t1_del_bef;
DROP TABLE t1,t2;
...@@ -85,3 +85,43 @@ a b c ...@@ -85,3 +85,43 @@ a b c
300 30 30 300 30 30
drop table t1,t2; drop table t1,t2;
drop procedure p1; drop procedure p1;
#
# Bug mdev-3845: values of virtual columns are not computed for triggers
#
CREATE TABLE t1 (
a INTEGER UNSIGNED NULL DEFAULT NULL,
b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL
);
CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL);
CREATE TRIGGER t1_ins_aft
AFTER INSERT
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2 (c) VALUES (NEW.b);
END |
CREATE TRIGGER t1_del_bef
BEFORE DELETE
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2 (c) VALUES (OLD.b);
END |
INSERT INTO t1 (a) VALUES (1), (2), (3);
SELECT * FROM t2;
c
1
2
3
DELETE FROM t1;
SELECT * FROM t2;
c
1
2
3
1
2
3
DROP TRIGGER t1_ins_aft;
DROP TRIGGER t1_del_bef;
DROP TABLE t1,t2;
...@@ -85,3 +85,43 @@ a b c ...@@ -85,3 +85,43 @@ a b c
300 30 30 300 30 30
drop table t1,t2; drop table t1,t2;
drop procedure p1; drop procedure p1;
#
# Bug mdev-3845: values of virtual columns are not computed for triggers
#
CREATE TABLE t1 (
a INTEGER UNSIGNED NULL DEFAULT NULL,
b INTEGER UNSIGNED GENERATED ALWAYS AS (a) VIRTUAL
);
CREATE TABLE t2 (c INTEGER UNSIGNED NOT NULL);
CREATE TRIGGER t1_ins_aft
AFTER INSERT
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2 (c) VALUES (NEW.b);
END |
CREATE TRIGGER t1_del_bef
BEFORE DELETE
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2 (c) VALUES (OLD.b);
END |
INSERT INTO t1 (a) VALUES (1), (2), (3);
SELECT * FROM t2;
c
1
2
3
DELETE FROM t1;
SELECT * FROM t2;
c
1
2
3
1
2
3
DROP TRIGGER t1_ins_aft;
DROP TRIGGER t1_del_bef;
DROP TABLE t1,t2;
...@@ -1366,7 +1366,8 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, ...@@ -1366,7 +1366,8 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
bool allow_rowid, uint *cached_field_index_ptr); bool allow_rowid, uint *cached_field_index_ptr);
Field * Field *
find_field_in_table_sef(TABLE *table, const char *name); find_field_in_table_sef(TABLE *table, const char *name);
int update_virtual_fields(THD *thd, TABLE *table, bool ignore_stored= FALSE); int update_virtual_fields(THD *thd, TABLE *table,
enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ);
#endif /* MYSQL_SERVER */ #endif /* MYSQL_SERVER */
......
...@@ -8460,7 +8460,9 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values, ...@@ -8460,7 +8460,9 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
{ {
if (vcol_table->vfield) if (vcol_table->vfield)
{ {
if (update_virtual_fields(thd, vcol_table, TRUE)) if (update_virtual_fields(thd, vcol_table,
vcol_table->triggers ? VCOL_UPDATE_ALL :
VCOL_UPDATE_FOR_WRITE))
goto err; goto err;
} }
} }
...@@ -8524,7 +8526,9 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields, ...@@ -8524,7 +8526,9 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
if (item_field && item_field->field && if (item_field && item_field->field &&
(table= item_field->field->table) && (table= item_field->field->table) &&
table->vfield) table->vfield)
result= update_virtual_fields(thd, table, TRUE); result= update_virtual_fields(thd, table,
table->triggers ? VCOL_UPDATE_ALL :
VCOL_UPDATE_FOR_WRITE);
} }
} }
return result; return result;
...@@ -8604,7 +8608,10 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors) ...@@ -8604,7 +8608,10 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
} }
/* Update virtual fields*/ /* Update virtual fields*/
thd->abort_on_warning= FALSE; thd->abort_on_warning= FALSE;
if (table->vfield && update_virtual_fields(thd, table, TRUE)) if (table->vfield &&
update_virtual_fields(thd, table,
table->triggers ? VCOL_UPDATE_ALL :
VCOL_UPDATE_FOR_WRITE))
goto err; goto err;
thd->abort_on_warning= abort_on_warning_saved; thd->abort_on_warning= abort_on_warning_saved;
DBUG_RETURN(thd->is_error()); DBUG_RETURN(thd->is_error());
...@@ -8657,7 +8664,9 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr, ...@@ -8657,7 +8664,9 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
{ {
TABLE *table= (*ptr)->table; TABLE *table= (*ptr)->table;
if (table->vfield) if (table->vfield)
result= update_virtual_fields(thd, table, TRUE); result= update_virtual_fields(thd, table,
table->triggers ? VCOL_UPDATE_ALL :
VCOL_UPDATE_FOR_WRITE);
} }
return result; return result;
......
...@@ -313,7 +313,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -313,7 +313,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
while (!(error=info.read_record(&info)) && !thd->killed && while (!(error=info.read_record(&info)) && !thd->killed &&
! thd->is_error()) ! thd->is_error())
{ {
update_virtual_fields(thd, table); update_virtual_fields(thd, table,
triggers_applicable ? VCOL_UPDATE_ALL :
VCOL_UPDATE_FOR_READ);
thd->examined_row_count++; thd->examined_row_count++;
// thd->is_error() is tested to disallow delete row on error // thd->is_error() is tested to disallow delete row on error
if (!select || select->skip_record(thd) > 0) if (!select || select->skip_record(thd) > 0)
......
...@@ -8066,7 +8066,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, ...@@ -8066,7 +8066,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
copy_ptr->do_copy(copy_ptr); copy_ptr->do_copy(copy_ptr);
} }
prev_insert_id= to->file->next_insert_id; prev_insert_id= to->file->next_insert_id;
update_virtual_fields(thd, to, TRUE); update_virtual_fields(thd, to, VCOL_UPDATE_FOR_WRITE);
if (thd->is_error()) if (thd->is_error())
{ {
error= 1; error= 1;
......
...@@ -490,7 +490,9 @@ int mysql_update(THD *thd, ...@@ -490,7 +490,9 @@ int mysql_update(THD *thd,
while (!(error=info.read_record(&info)) && !thd->killed) while (!(error=info.read_record(&info)) && !thd->killed)
{ {
update_virtual_fields(thd, table); update_virtual_fields(thd, table,
table->triggers ? VCOL_UPDATE_ALL :
VCOL_UPDATE_FOR_READ);
thd->examined_row_count++; thd->examined_row_count++;
if (!select || (error= select->skip_record(thd)) > 0) if (!select || (error= select->skip_record(thd)) > 0)
{ {
...@@ -605,7 +607,9 @@ int mysql_update(THD *thd, ...@@ -605,7 +607,9 @@ int mysql_update(THD *thd,
while (!(error=info.read_record(&info)) && !thd->killed) while (!(error=info.read_record(&info)) && !thd->killed)
{ {
update_virtual_fields(thd, table); update_virtual_fields(thd, table,
table->triggers ? VCOL_UPDATE_ALL :
VCOL_UPDATE_FOR_READ);
thd->examined_row_count++; thd->examined_row_count++;
if (!select || select->skip_record(thd) > 0) if (!select || select->skip_record(thd) > 0)
{ {
......
...@@ -5500,14 +5500,16 @@ size_t max_row_length(TABLE *table, const uchar *data) ...@@ -5500,14 +5500,16 @@ size_t max_row_length(TABLE *table, const uchar *data)
@param thd Thread handle @param thd Thread handle
@param table The TABLE object @param table The TABLE object
@param for_write Requests to compute only fields needed for write @param vcol_update_mode Specifies what virtual column are computed
@details @details
The function computes the values of the virtual columns of the table and The function computes the values of the virtual columns of the table and
stores them in the table record buffer. stores them in the table record buffer.
Only fields from vcol_set are computed, and, when the flag for_write is not If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are
set to TRUE, a virtual field is computed only if it's not stored. computed. Otherwise, only fields from vcol_set are computed: all of them,
The flag for_write is set to TRUE for row insert/update operations. if vcol_update_mode is set to VCOL_UPDATE_FOR_WRITE, and, only those with
the stored_in_db flag set to false, if vcol_update_mode is equal to
VCOL_UPDATE_FOR_READ.
@retval @retval
0 Success 0 Success
...@@ -5515,7 +5517,8 @@ size_t max_row_length(TABLE *table, const uchar *data) ...@@ -5515,7 +5517,8 @@ size_t max_row_length(TABLE *table, const uchar *data)
>0 Error occurred when storing a virtual field value >0 Error occurred when storing a virtual field value
*/ */
int update_virtual_fields(THD *thd, TABLE *table, bool for_write) int update_virtual_fields(THD *thd, TABLE *table,
enum enum_vcol_update_mode vcol_update_mode)
{ {
DBUG_ENTER("update_virtual_fields"); DBUG_ENTER("update_virtual_fields");
Field **vfield_ptr, *vfield; Field **vfield_ptr, *vfield;
...@@ -5529,9 +5532,9 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write) ...@@ -5529,9 +5532,9 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
{ {
vfield= (*vfield_ptr); vfield= (*vfield_ptr);
DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item); DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item);
/* Only update those fields that are marked in the vcol_set bitmap */ if ((bitmap_is_set(table->vcol_set, vfield->field_index) &&
if (bitmap_is_set(table->vcol_set, vfield->field_index) && (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) ||
(for_write || !vfield->stored_in_db)) vcol_update_mode == VCOL_UPDATE_ALL)
{ {
/* Compute the actual value of the virtual fields */ /* Compute the actual value of the virtual fields */
error= vfield->vcol_info->expr_item->save_in_field(vfield, 0); error= vfield->vcol_info->expr_item->save_in_field(vfield, 0);
......
...@@ -156,6 +156,13 @@ enum frm_type_enum ...@@ -156,6 +156,13 @@ enum frm_type_enum
enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP }; enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP };
enum enum_vcol_update_mode
{
VCOL_UPDATE_FOR_READ= 0,
VCOL_UPDATE_FOR_WRITE,
VCOL_UPDATE_ALL
};
typedef struct st_filesort_info typedef struct st_filesort_info
{ {
IO_CACHE *io_cache; /* If sorted through filesort */ IO_CACHE *io_cache; /* If sorted through filesort */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment