mariadb/mysql-test/suite/vcol/t/update.test
Sergei Golubchik f73bdb685d bugfix: UPDATE and virtual BLOBs
When updating a table with virtual BLOB columns, the following might happen:
- an old record is read from the table, it has no virtual blob values
- update_virtual_fields() is run, vcol blob gets its value into the
  record. But only a pointer to the value is in the table->record[0],
  the value is in Field_blob::value String (but it doesn't have to be!
  it can be in the record, if the column is just a copy of another
  columns: ... b VARCHAR, c BLOB AS (b) ...)
- store_record(table,record[1]), old record now is in record[1]
- fill_record() prepares new values in record[0], vcol blob is updated,
  new value replaces the old one in the Field_blob::value
- now both record[1] and record[0] have a pointer that points to the
  *new* vcol blob value. Or record[1] has a pointer to nowhere if
  Field_blob::value had to realloc.

To resolve this we unlink vcol blobs from the pointer to the
data (in the record[1]). Because the value is not *always* in
the Field_blob::value String, we need to remember what blobs
were unlinked. The orphan memory must be freed manually.

To complicate the matter, ha_update_row() is also used in
multi-update, in REPLACE, in INSERT ... ON DUPLICATE KEY UPDATE,
also on REPLACE ... SELECT, REPLACE DELAYED, and LOAD DATA REPLACE, etc
2016-12-12 20:27:38 +01:00

112 lines
3.6 KiB
Text

#
# Test how UPDATE detects what columns need to be read (or generated) in a row
#
# stored column depends on virtual column depends on updated column.
# this tests TABLE::mark_virtual_columns_for_write()
#
create table t1 (a int, b int as (a+1), c int as (b+1) stored);
insert t1 set a=1;
select * from t1;
update t1 set a=2;
select * from t1;
drop table t1;
#
# one keypart is virtual, the other keypart is updated
# this tests TABLE::mark_columns_needed_for_update()
#
create table t1 (a int, c int as(a), p varchar(20) as(y), y char(20), index (p,c));
insert into t1 (a,y) values(1, "yyy");
update t1 set a = 100 where a = 1;
drop table t1;
#
# note: prefix keys below
#
create table t1 (
a varchar(10000),
b varchar(3000),
c varchar(14000) generated always as (concat(a,b)) virtual,
d varchar(5000) generated always as (b) virtual,
e int(11) generated always as (10) virtual,
h int(11) not null primary key,
index(c(100), d(20)));
insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
update t1 set a = repeat(cast(1 as char), 2000);
drop table t1;
create table t1 (
a varchar(10000),
b varchar(3000),
c varchar(14000) generated always as (concat(a,b)) virtual,
i varchar(5000) generated always as (b) virtual,
d varchar(5000) generated always as (i) virtual,
e int(11) generated always as (10) virtual,
h int(11) not null primary key,
index(c(100), d(20)));
insert t1 (a,b,h) values (repeat('g', 10000), repeat('x', 2800), 1);
update t1 set a = repeat(cast(1 as char), 2000);
drop table t1;
#
# UPDATE disguised as INSERT
#
create table t1(a blob not null, b int, c varbinary (10) generated always as (a) virtual, unique (c(9)));
insert t1 (a,b) values ('a', 1);
replace t1 set a = 'a',b =1;
insert t1 (a,b) values ('a', 1) on duplicate key update a='b', b=2;
select * from t1;
drop table t1;
#
# multi-UPDATE and const tables
#
create table t (a int primary key, b int, c int as (b), index (c));
insert t (a,b) values (9,0);
create table t2 select * from t;
update t, t2 set t.b=10 where t.a=t2.a;
check table t; select * from t;
drop table t, t2;
#
# blobs
# This tests BLOB_VALUE_ORPHANAGE
#
create table t1 (a int, b int, c int, d int, e int);
insert t1 values (1,2,3,4,5), (1,2,3,4,5);
create table t (a int primary key,
b int, c blob as (b), index (c(57)),
d blob, e blob as (d), index (e(57)))
replace select * from t1;
check table t; select * from t;
update t set a=10, b=1, d=1;
check table t; select * from t;
replace t (a,b,d) values (10,2,2);
check table t; select * from t;
--error ER_WRONG_VALUE_COUNT_ON_ROW
insert t(a,b,d) values (10) on duplicate key update b=3;
insert t(a,b,d) values (10,2,2) on duplicate key update b=3, d=3;
check table t; select * from t;
replace t (a,b,d) select 10,4,4;
check table t; select * from t;
insert t(a,b,d) select 10,4,4 on duplicate key update b=5, d=5;
check table t; select * from t;
replace delayed t (a,b,d) values (10,6,6);
flush tables;
check table t; select * from t;
insert delayed t(a,b,d) values (10,6,6) on duplicate key update b=7, d=7;
flush tables;
check table t; select * from t;
--write_file $MYSQLTEST_VARDIR/tmp/vblobs.txt
10 8 foo 8 foo
EOF
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--eval load data infile '$MYSQLTEST_VARDIR/tmp/vblobs.txt' replace into table t
--remove_file $MYSQLTEST_VARDIR/tmp/vblobs.txt
check table t; select * from t;
update t set a=11, b=9, d=9 where a>5;
check table t; select * from t;
create table t2 select * from t;
update t, t2 set t.b=10, t.d=10 where t.a=t2.a;
check table t; select * from t;
update t, t tt set t.b=11, tt.d=11 where t.a=tt.a;
check table t; select * from t;
drop table t, t1, t2;