Commit 128356b4 authored by Nikita Malyavin's avatar Nikita Malyavin

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.
parent 3cd2c1e8
...@@ -249,12 +249,15 @@ ENGINE=InnoDB; ...@@ -249,12 +249,15 @@ ENGINE=InnoDB;
INSERT IGNORE INTO t1 (a,b) VALUES(1,20190132); INSERT IGNORE INTO t1 (a,b) VALUES(1,20190132);
Warnings: Warnings:
Warning 1265 Data truncated for column 'vb' at row 1 Warning 1265 Data truncated for column 'vb' at row 1
SELECT * FROM t1;
a b vb
1 20190132 0000-00-00
BEGIN; BEGIN;
DELETE FROM t1; DELETE FROM t1;
INSERT INTO t1 (a,b) VALUES(1,20190123); 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; SELECT * FROM t1;
a b vb a b vb
1 20190123 2019-01-23
ROLLBACK; ROLLBACK;
SELECT * FROM t1; SELECT * FROM t1;
a b vb a b vb
...@@ -340,4 +343,33 @@ Warnings: ...@@ -340,4 +343,33 @@ Warnings:
Warning 1365 Division by 0 Warning 1365 Division by 0
disconnect stop_purge; disconnect stop_purge;
DROP TABLE t, t_odd; 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 # End of 10.3 tests
...@@ -275,9 +275,9 @@ DROP TABLE t1; ...@@ -275,9 +275,9 @@ DROP TABLE t1;
CREATE TABLE t1(a INT PRIMARY KEY, b INT, vb DATE AS(b) VIRTUAL, KEY(vb)) CREATE TABLE t1(a INT PRIMARY KEY, b INT, vb DATE AS(b) VIRTUAL, KEY(vb))
ENGINE=InnoDB; ENGINE=InnoDB;
INSERT IGNORE INTO t1 (a,b) VALUES(1,20190132); INSERT IGNORE INTO t1 (a,b) VALUES(1,20190132);
SELECT * FROM t1;
BEGIN; BEGIN;
DELETE FROM t1; DELETE FROM t1;
--error ER_TRUNCATED_WRONG_VALUE
INSERT INTO t1 (a,b) VALUES(1,20190123); INSERT INTO t1 (a,b) VALUES(1,20190123);
SELECT * FROM t1; SELECT * FROM t1;
ROLLBACK; ROLLBACK;
...@@ -361,5 +361,24 @@ SELECT fld2 FROM t FORCE INDEX(fld1); ...@@ -361,5 +361,24 @@ SELECT fld2 FROM t FORCE INDEX(fld1);
--disconnect stop_purge --disconnect stop_purge
DROP TABLE t, t_odd; 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 --echo # End of 10.3 tests
...@@ -8158,9 +8158,10 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) ...@@ -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. Calculate the virtual field value for a specified field.
@param vf A field to calculate @param vf A field to calculate
@param ignore_warnings Ignore calculation warnings. This usually @param ignore_warnings Ignore the warnings and also make the
means that a calculation is internal and is calculations permissive. This usually means
not expected to fail. that a calculation is internal and is not
expected to fail.
*/ */
int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) int TABLE::update_virtual_field(Field *vf, bool ignore_warnings)
{ {
...@@ -8169,8 +8170,13 @@ 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; Counting_error_handler count_errors;
Suppress_warnings_error_handler warning_handler; Suppress_warnings_error_handler warning_handler;
in_use->push_internal_handler(&count_errors); in_use->push_internal_handler(&count_errors);
bool abort_on_warning;
if (ignore_warnings) if (ignore_warnings)
{
abort_on_warning= in_use->abort_on_warning;
in_use->abort_on_warning= false;
in_use->push_internal_handler(&warning_handler); in_use->push_internal_handler(&warning_handler);
}
/* /*
TODO: this may impose memory leak until table flush. TODO: this may impose memory leak until table flush.
See comment in See comment in
...@@ -8183,7 +8189,12 @@ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) ...@@ -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->restore_active_arena(expr_arena, &backup_arena);
in_use->pop_internal_handler(); in_use->pop_internal_handler();
if (ignore_warnings) if (ignore_warnings)
{
in_use->abort_on_warning= abort_on_warning;
in_use->pop_internal_handler(); 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); DBUG_RETURN(count_errors.errors);
} }
......
...@@ -215,6 +215,8 @@ the equal ordering fields. NOTE: we compare the fields as binary strings! ...@@ -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] offsets rec_get_offsets(rec,index), or NULL
@param[in] no_sys skip the system columns @param[in] no_sys skip the system columns
DB_TRX_ID and DB_ROLL_PTR 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), @param[in] trx transaction (for diagnostics),
or NULL or NULL
@param[in] heap memory heap from which allocated @param[in] heap memory heap from which allocated
...@@ -230,11 +232,12 @@ row_upd_build_difference_binary( ...@@ -230,11 +232,12 @@ row_upd_build_difference_binary(
const rec_t* rec, const rec_t* rec,
const rec_offs* offsets, const rec_offs* offsets,
bool no_sys, bool no_sys,
bool ignore_warnings,
trx_t* trx, trx_t* trx,
mem_heap_t* heap, mem_heap_t* heap,
TABLE* mysql_table, TABLE* mysql_table,
dberr_t* error) 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. /** Apply an update vector to an index entry.
@param[in,out] entry index entry to be updated; the clustered index record @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 must be covered by a lock or a page latch to prevent
......
...@@ -307,7 +307,7 @@ row_ins_clust_index_entry_by_modify( ...@@ -307,7 +307,7 @@ row_ins_clust_index_entry_by_modify(
} }
update = row_upd_build_difference_binary( 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); thr_get_trx(thr), heap, mysql_table, &err);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
return(err); return(err);
......
...@@ -2248,7 +2248,7 @@ row_log_table_apply_update( ...@@ -2248,7 +2248,7 @@ row_log_table_apply_update(
row, NULL, index, heap, ROW_BUILD_NORMAL); row, NULL, index, heap, ROW_BUILD_NORMAL);
upd_t* update = row_upd_build_difference_binary( upd_t* update = row_upd_build_difference_binary(
index, entry, btr_pcur_get_rec(&pcur), cur_offsets, 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) { if (error != DB_SUCCESS) {
goto func_exit; goto func_exit;
} }
......
...@@ -1044,6 +1044,7 @@ row_upd_build_difference_binary( ...@@ -1044,6 +1044,7 @@ row_upd_build_difference_binary(
const rec_t* rec, const rec_t* rec,
const rec_offs* offsets, const rec_offs* offsets,
bool no_sys, bool no_sys,
bool ignore_warnings,
trx_t* trx, trx_t* trx,
mem_heap_t* heap, mem_heap_t* heap,
TABLE* mysql_table, TABLE* mysql_table,
...@@ -1153,7 +1154,7 @@ row_upd_build_difference_binary( ...@@ -1153,7 +1154,7 @@ row_upd_build_difference_binary(
dfield_t* vfield = innobase_get_computed_value( dfield_t* vfield = innobase_get_computed_value(
update->old_vrow, col, index, update->old_vrow, col, index,
&vc.heap, heap, NULL, thd, mysql_table, record, &vc.heap, heap, NULL, thd, mysql_table, record,
NULL, NULL); NULL, NULL, ignore_warnings);
if (vfield == NULL) { if (vfield == NULL) {
*error = DB_COMPUTE_VALUE_FAILED; *error = DB_COMPUTE_VALUE_FAILED;
return(NULL); return(NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment