summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2022-10-10 19:41:09 +0300
committerNikita Malyavin <nikitamalyavin@gmail.com>2022-10-12 20:49:45 +0300
commit128356b4b1cf3c8289ac1ba7e69a44d42e06e40c (patch)
treea2a1a5b1da8d81d0530d30594aa81f90c9fa865a
parent3cd2c1e8b6fa8435e634360c2ff63f5d645b65dc (diff)
downloadmariadb-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.result34
-rw-r--r--mysql-test/suite/gcol/t/innodb_virtual_index.test21
-rw-r--r--sql/table.cc17
-rw-r--r--storage/innobase/include/row0upd.h5
-rw-r--r--storage/innobase/row/row0ins.cc2
-rw-r--r--storage/innobase/row/row0log.cc2
-rw-r--r--storage/innobase/row/row0upd.cc3
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);