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.
This commit is contained in:
parent
b0fec77df9
commit
094f4cf778
@ -108,3 +108,44 @@ select * from t1;
|
||||
|
||||
drop table t1,t2;
|
||||
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
|
||||
300 30 30
|
||||
drop table t1,t2;
|
||||
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
|
||||
300 30 30
|
||||
drop table t1,t2;
|
||||
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,
|
||||
bool allow_rowid, uint *cached_field_index_ptr);
|
||||
Field *
|
||||
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 */
|
||||
|
||||
|
@ -8460,7 +8460,9 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -8524,7 +8526,9 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
|
||||
if (item_field && item_field->field &&
|
||||
(table= item_field->field->table) &&
|
||||
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;
|
||||
@ -8604,7 +8608,10 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
|
||||
}
|
||||
/* Update virtual fields*/
|
||||
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;
|
||||
thd->abort_on_warning= abort_on_warning_saved;
|
||||
DBUG_RETURN(thd->is_error());
|
||||
@ -8657,7 +8664,9 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
|
||||
{
|
||||
TABLE *table= (*ptr)->table;
|
||||
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;
|
||||
|
||||
|
@ -313,7 +313,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
||||
while (!(error=info.read_record(&info)) && !thd->killed &&
|
||||
! 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->is_error() is tested to disallow delete row on error
|
||||
if (!select || select->skip_record(thd) > 0)
|
||||
|
@ -8066,7 +8066,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
||||
copy_ptr->do_copy(copy_ptr);
|
||||
}
|
||||
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())
|
||||
{
|
||||
error= 1;
|
||||
|
@ -490,7 +490,9 @@ int mysql_update(THD *thd,
|
||||
|
||||
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++;
|
||||
if (!select || (error= select->skip_record(thd)) > 0)
|
||||
{
|
||||
@ -605,7 +607,9 @@ int mysql_update(THD *thd,
|
||||
|
||||
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++;
|
||||
if (!select || select->skip_record(thd) > 0)
|
||||
{
|
||||
|
21
sql/table.cc
21
sql/table.cc
@ -5500,22 +5500,25 @@ size_t max_row_length(TABLE *table, const uchar *data)
|
||||
|
||||
@param thd Thread handle
|
||||
@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
|
||||
The function computes the values of the virtual columns of the table and
|
||||
stores them in the table record buffer.
|
||||
Only fields from vcol_set are computed, and, when the flag for_write is not
|
||||
set to TRUE, a virtual field is computed only if it's not stored.
|
||||
The flag for_write is set to TRUE for row insert/update operations.
|
||||
|
||||
If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are
|
||||
computed. Otherwise, only fields from vcol_set are computed: all of them,
|
||||
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
|
||||
0 Success
|
||||
@retval
|
||||
>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");
|
||||
Field **vfield_ptr, *vfield;
|
||||
@ -5529,9 +5532,9 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
|
||||
{
|
||||
vfield= (*vfield_ptr);
|
||||
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) &&
|
||||
(for_write || !vfield->stored_in_db))
|
||||
if ((bitmap_is_set(table->vcol_set, vfield->field_index) &&
|
||||
(vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) ||
|
||||
vcol_update_mode == VCOL_UPDATE_ALL)
|
||||
{
|
||||
/* Compute the actual value of the virtual fields */
|
||||
error= vfield->vcol_info->expr_item->save_in_field(vfield, 0);
|
||||
|
@ -156,6 +156,13 @@ enum frm_type_enum
|
||||
|
||||
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
|
||||
{
|
||||
IO_CACHE *io_cache; /* If sorted through filesort */
|
||||
|
Loading…
x
Reference in New Issue
Block a user