Skip to content

Commit 0932c58

Browse files
committed
MDEV-20515 multi-update tries to position updated table by null reference
Cause Join tmp table inserts null row because of OUTER JOIN, that's expected. Since `multi_update::prepare2()` converted `Item_temptable_rowid` into `Item_field` (28dbdf3) `multi_update::send_data()` accesses join tmp record directly and treats it as a normal row ignoring null status of ref field. NULL ref field is then treated as normal in `multi_update::do_updates()` which tries to position updated table by reference 0. Note that reference 0 may be valid reference and the first row of table can be wrongly updated (see multi_update.test). Fix Do not add row into multi-update tmp table in case of null ref field. Join tmp table does not have null_row status at this time (as well as `STATUS_NULL_ROW`) and cannot be skipped by these properties (see first comment in multi_update::send_data()). But it has all null fields (including the ref field).
1 parent ba34f40 commit 0932c58

File tree

5 files changed

+63
-0
lines changed

5 files changed

+63
-0
lines changed

mysql-test/main/multi_update.result

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,3 +1081,20 @@ b c
10811081
2 0
10821082
drop view v1;
10831083
drop table t0, t1,t2;
1084+
#
1085+
# MDEV-20515 multi-update tries to position updated table by null reference
1086+
#
1087+
create or replace table t1 (a int);
1088+
insert into t1 values (0), (2);
1089+
create or replace table t2 (b int);
1090+
insert into t2 values (1), (2);
1091+
select * from t1 left join t2 on a = b order by b;
1092+
a b
1093+
0 NULL
1094+
2 2
1095+
update t1 left join t2 on a = b set b= 3 order by b;
1096+
select * from t2;
1097+
b
1098+
1
1099+
3
1100+
drop tables t1, t2;

mysql-test/main/multi_update.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,3 +1019,18 @@ update v1,t0 set c=1 where b<3 and x=c order by x,b limit 1;
10191019
select * from v1;
10201020
drop view v1;
10211021
drop table t0, t1,t2;
1022+
1023+
--echo #
1024+
--echo # MDEV-20515 multi-update tries to position updated table by null reference
1025+
--echo #
1026+
create or replace table t1 (a int);
1027+
insert into t1 values (0), (2);
1028+
1029+
create or replace table t2 (b int);
1030+
insert into t2 values (1), (2);
1031+
1032+
select * from t1 left join t2 on a = b order by b;
1033+
update t1 left join t2 on a = b set b= 3 order by b;
1034+
select * from t2;
1035+
1036+
drop tables t1, t2;

mysql-test/suite/versioning/r/partition.result

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,17 @@ insert into t2 values (1),(2);
615615
update t1, t2 set a = 1;
616616
drop table t1, t2;
617617
#
618+
# MDEV-20515 multi-update tries to position updated table by null reference
619+
#
620+
create or replace table t1 (a int);
621+
insert into t1 values (0), (1);
622+
create or replace table t2 (b int) with system versioning
623+
partition by system_time
624+
(partition p1 history, partition pn current);
625+
insert into t2 values (0), (2);
626+
update t1 left join t2 on a > b set b= 2 order by b;
627+
drop table t1, t2;
628+
#
618629
# MDEV-17091 Assertion `old_part_id == m_last_part' failed in
619630
# ha_partition::update_row or `part_id == m_last_part' in
620631
# ha_partition::delete_row upon UPDATE/DELETE after dropping versioning

mysql-test/suite/versioning/t/partition.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,22 @@ update t1, t2 set a = 1;
567567
# cleanup
568568
drop table t1, t2;
569569

570+
--echo #
571+
--echo # MDEV-20515 multi-update tries to position updated table by null reference
572+
--echo #
573+
create or replace table t1 (a int);
574+
insert into t1 values (0), (1);
575+
576+
create or replace table t2 (b int) with system versioning
577+
partition by system_time
578+
(partition p1 history, partition pn current);
579+
580+
insert into t2 values (0), (2);
581+
update t1 left join t2 on a > b set b= 2 order by b;
582+
583+
# cleanup
584+
drop table t1, t2;
585+
570586
--source suite/versioning/common_finish.inc
571587
--echo #
572588
--echo # MDEV-17091 Assertion `old_part_id == m_last_part' failed in

sql/sql_update.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,6 +2467,9 @@ int multi_update::send_data(List<Item> &not_used_values)
24672467
TABLE *tmp_table= tmp_tables[offset];
24682468
if (copy_funcs(tmp_table_param[offset].items_to_copy, thd))
24692469
DBUG_RETURN(1);
2470+
/* rowid field is NULL if join tmp table has null row from outer join */
2471+
if (tmp_table->field[0]->is_null())
2472+
continue;
24702473
/* Store regular updated fields in the row. */
24712474
DBUG_ASSERT(1 + unupdated_check_opt_tables.elements ==
24722475
tmp_table_param[offset].func_count);
@@ -2671,6 +2674,7 @@ int multi_update::do_updates()
26712674
uint field_num= 0;
26722675
do
26732676
{
2677+
DBUG_ASSERT(!tmp_table->field[field_num]->is_null());
26742678
if (unlikely((local_error=
26752679
tbl->file->ha_rnd_pos(tbl->record[0],
26762680
(uchar *) tmp_table->

0 commit comments

Comments
 (0)