diff options
author | Nikita Malyavin <nikitamalyavin@gmail.com> | 2022-10-10 19:41:09 +0300 |
---|---|---|
committer | Nikita Malyavin <nikitamalyavin@gmail.com> | 2022-10-12 20:49:45 +0300 |
commit | 128356b4b1cf3c8289ac1ba7e69a44d42e06e40c (patch) | |
tree | a2a1a5b1da8d81d0530d30594aa81f90c9fa865a | |
parent | 3cd2c1e8b6fa8435e634360c2ff63f5d645b65dc (diff) | |
download | mariadb-git-128356b4b1cf3c8289ac1ba7e69a44d42e06e40c.tar.gz |
MDEV-29753 An error is wrongly reported during INSERT with vcol index
See also commits aa8a31da and 64678c for a Bug #22990029 fix.
In this scenario INSERT chose to check if delete unmarking is available for
a just deleted record. To build an update vector, it needed to calculate
the vcols as well. Since this INSERT was not IGNORE-flagged, recalculation
failed.
Solutiuon: temporarily set abort_on_warning=true, while calculating the
column for delete-unmarked insert.
-rw-r--r-- | mysql-test/suite/gcol/r/innodb_virtual_index.result | 34 | ||||
-rw-r--r-- | mysql-test/suite/gcol/t/innodb_virtual_index.test | 21 | ||||
-rw-r--r-- | sql/table.cc | 17 | ||||
-rw-r--r-- | storage/innobase/include/row0upd.h | 5 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 2 | ||||
-rw-r--r-- | storage/innobase/row/row0log.cc | 2 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 3 |
7 files changed, 75 insertions, 9 deletions
diff --git a/mysql-test/suite/gcol/r/innodb_virtual_index.result b/mysql-test/suite/gcol/r/innodb_virtual_index.result index d5ad08cd4bf..b0c29da2f22 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_index.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_index.result @@ -249,12 +249,15 @@ ENGINE=InnoDB; INSERT IGNORE INTO t1 (a,b) VALUES(1,20190132); Warnings: Warning 1265 Data truncated for column 'vb' at row 1 +SELECT * FROM t1; +a b vb +1 20190132 0000-00-00 BEGIN; DELETE FROM t1; INSERT INTO t1 (a,b) VALUES(1,20190123); -ERROR 22007: Incorrect date value: '20190132' for column `test`.`t1`.`vb` at row 1 SELECT * FROM t1; a b vb +1 20190123 2019-01-23 ROLLBACK; SELECT * FROM t1; a b vb @@ -340,4 +343,33 @@ Warnings: Warning 1365 Division by 0 disconnect stop_purge; DROP TABLE t, t_odd; +# +# MDEV-29753 An error is wrongly reported during INSERT with vcol index +# See also Bug #22990029 +# +CREATE TABLE t(pk INT PRIMARY KEY, +fld1 INT NOT NULL, +fld2 INT AS (100/fld1) VIRTUAL, +KEY(fld1), KEY(fld2)); +INSERT IGNORE t(pk, fld1) VALUES(1, 0); +Warnings: +Warning 1365 Division by 0 +SELECT * FROM t; +pk fld1 fld2 +1 0 NULL +Warnings: +Warning 1365 Division by 0 +BEGIN; +DELETE FROM t; +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +INSERT INTO t (pk, fld1) VALUES(1,1); +SELECT * FROM t; +pk fld1 fld2 +1 1 100 +# Cleanup +ROLLBACK; +DROP TABLE t; # End of 10.3 tests diff --git a/mysql-test/suite/gcol/t/innodb_virtual_index.test b/mysql-test/suite/gcol/t/innodb_virtual_index.test index 10a7ac51562..747a2fdb64c 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_index.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_index.test @@ -275,9 +275,9 @@ DROP TABLE t1; CREATE TABLE t1(a INT PRIMARY KEY, b INT, vb DATE AS(b) VIRTUAL, KEY(vb)) ENGINE=InnoDB; INSERT IGNORE INTO t1 (a,b) VALUES(1,20190132); +SELECT * FROM t1; BEGIN; DELETE FROM t1; ---error ER_TRUNCATED_WRONG_VALUE INSERT INTO t1 (a,b) VALUES(1,20190123); SELECT * FROM t1; ROLLBACK; @@ -361,5 +361,24 @@ SELECT fld2 FROM t FORCE INDEX(fld1); --disconnect stop_purge DROP TABLE t, t_odd; +--echo # +--echo # MDEV-29753 An error is wrongly reported during INSERT with vcol index +--echo # See also Bug #22990029 +--echo # + +CREATE TABLE t(pk INT PRIMARY KEY, + fld1 INT NOT NULL, + fld2 INT AS (100/fld1) VIRTUAL, + KEY(fld1), KEY(fld2)); +INSERT IGNORE t(pk, fld1) VALUES(1, 0); +SELECT * FROM t; +BEGIN; +DELETE FROM t; +INSERT INTO t (pk, fld1) VALUES(1,1); +SELECT * FROM t; + +--echo # Cleanup +ROLLBACK; +DROP TABLE t; --echo # End of 10.3 tests diff --git a/sql/table.cc b/sql/table.cc index 65b429a1b5a..1d0edf88fb7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8158,9 +8158,10 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) /* Calculate the virtual field value for a specified field. @param vf A field to calculate - @param ignore_warnings Ignore calculation warnings. This usually - means that a calculation is internal and is - not expected to fail. + @param ignore_warnings Ignore the warnings and also make the + calculations permissive. This usually means + that a calculation is internal and is not + expected to fail. */ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) { @@ -8169,8 +8170,13 @@ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) Counting_error_handler count_errors; Suppress_warnings_error_handler warning_handler; in_use->push_internal_handler(&count_errors); + bool abort_on_warning; if (ignore_warnings) + { + abort_on_warning= in_use->abort_on_warning; + in_use->abort_on_warning= false; in_use->push_internal_handler(&warning_handler); + } /* TODO: this may impose memory leak until table flush. See comment in @@ -8183,7 +8189,12 @@ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) in_use->restore_active_arena(expr_arena, &backup_arena); in_use->pop_internal_handler(); if (ignore_warnings) + { + in_use->abort_on_warning= abort_on_warning; in_use->pop_internal_handler(); + // This is an internal calculation, we expect it to always succeed + DBUG_ASSERT(count_errors.errors == 0); + } DBUG_RETURN(count_errors.errors); } diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index c0139ee7911..9721e975a0a 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -215,6 +215,8 @@ the equal ordering fields. NOTE: we compare the fields as binary strings! @param[in] offsets rec_get_offsets(rec,index), or NULL @param[in] no_sys skip the system columns DB_TRX_ID and DB_ROLL_PTR +@param[in] ignore_warnings ignore warnings during vcol calculation, which + means that this calculation is internal only @param[in] trx transaction (for diagnostics), or NULL @param[in] heap memory heap from which allocated @@ -230,11 +232,12 @@ row_upd_build_difference_binary( const rec_t* rec, const rec_offs* offsets, bool no_sys, + bool ignore_warnings, trx_t* trx, mem_heap_t* heap, TABLE* mysql_table, dberr_t* error) - MY_ATTRIBUTE((nonnull(1,2,3,7,9), warn_unused_result)); + MY_ATTRIBUTE((nonnull(1,2,3,8,10), warn_unused_result)); /** Apply an update vector to an index entry. @param[in,out] entry index entry to be updated; the clustered index record must be covered by a lock or a page latch to prevent diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index f03381a2fcf..8330e3ef0c8 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -307,7 +307,7 @@ row_ins_clust_index_entry_by_modify( } update = row_upd_build_difference_binary( - cursor->index, entry, rec, NULL, true, + cursor->index, entry, rec, NULL, true, true, thr_get_trx(thr), heap, mysql_table, &err); if (err != DB_SUCCESS) { return(err); diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index c91f5b96617..aa001a84deb 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -2248,7 +2248,7 @@ func_exit_committed: row, NULL, index, heap, ROW_BUILD_NORMAL); upd_t* update = row_upd_build_difference_binary( index, entry, btr_pcur_get_rec(&pcur), cur_offsets, - false, NULL, heap, dup->table, &error); + false, false, NULL, heap, dup->table, &error); if (error != DB_SUCCESS) { goto func_exit; } diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index cadfc181916..599aece23f5 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1044,6 +1044,7 @@ row_upd_build_difference_binary( const rec_t* rec, const rec_offs* offsets, bool no_sys, + bool ignore_warnings, trx_t* trx, mem_heap_t* heap, TABLE* mysql_table, @@ -1153,7 +1154,7 @@ row_upd_build_difference_binary( dfield_t* vfield = innobase_get_computed_value( update->old_vrow, col, index, &vc.heap, heap, NULL, thd, mysql_table, record, - NULL, NULL); + NULL, NULL, ignore_warnings); if (vfield == NULL) { *error = DB_COMPUTE_VALUE_FAILED; return(NULL); |