summaryrefslogtreecommitdiff
path: root/storage/innobase/handler
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2021-10-27 18:37:33 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-10-28 07:32:27 +0300
commit1f5ca66e53b165c29ea733acd0fab79975a43eda (patch)
tree2552b55cb6a1e16cfa2a8648520adba9160c525a /storage/innobase/handler
parent3a9967d7579a31e5a43606d563584335348caaa5 (diff)
downloadmariadb-git-1f5ca66e53b165c29ea733acd0fab79975a43eda.tar.gz
MDEV-26866 FOREIGN KEY…SET NULL corrupts an index on a virtual column
The initial test case for MySQL Bug #33053297 is based on mysql/mysql-server@27130e25078864b010d81266f9613d389d4a229b. innobase_get_field_from_update_vector is not a suitable function to fetch updated row info, as well as parent table's update vector is not always suitable. For instance, in case of DELETE it contains undefined data. castade->update vector seems to be good enough to fetch all base columns update data, and besides faster, and less error-prone.
Diffstat (limited to 'storage/innobase/handler')
-rw-r--r--storage/innobase/handler/ha_innodb.cc64
1 files changed, 13 insertions, 51 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 91d245ad0e2..37748cb497a 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -21795,48 +21795,6 @@ innobase_rename_vc_templ(
table->vc_templ->tb_name = t_tbname;
}
-/** Get the updated parent field value from the update vector for the
-given col_no.
-@param[in] foreign foreign key information
-@param[in] update updated parent vector.
-@param[in] col_no base column position of the child table to check
-@return updated field from the parent update vector, else NULL */
-static
-dfield_t*
-innobase_get_field_from_update_vector(
- dict_foreign_t* foreign,
- upd_t* update,
- ulint col_no)
-{
- dict_table_t* parent_table = foreign->referenced_table;
- dict_index_t* parent_index = foreign->referenced_index;
- ulint parent_field_no;
- ulint parent_col_no;
- ulint prefix_col_no;
-
- for (ulint i = 0; i < foreign->n_fields; i++) {
- if (dict_index_get_nth_col_no(foreign->foreign_index, i)
- != col_no) {
- continue;
- }
-
- parent_col_no = dict_index_get_nth_col_no(parent_index, i);
- parent_field_no = dict_table_get_nth_col_pos(
- parent_table, parent_col_no, &prefix_col_no);
-
- for (ulint j = 0; j < update->n_fields; j++) {
- upd_field_t* parent_ufield
- = &update->fields[j];
-
- if (parent_ufield->field_no == parent_field_no) {
- return(&parent_ufield->new_val);
- }
- }
- }
-
- return (NULL);
-}
-
/**
Allocate a heap and record for calculating virtual fields
@@ -21919,9 +21877,10 @@ void innobase_report_computed_value_failed(dtuple_t *row)
@param[in] ifield index field
@param[in] thd MySQL thread handle
@param[in,out] mysql_table mysql table object
+@param[in,out] mysql_rec MariaDB record buffer
@param[in] old_table during ALTER TABLE, this is the old table
or NULL.
-@param[in] parent_update update vector for the parent row
+@param[in] update update vector for the row, if any
@param[in] foreign foreign key information
@return the field filled with computed value, or NULL if just want
to store the value in passed in "my_rec" */
@@ -21937,8 +21896,7 @@ innobase_get_computed_value(
TABLE* mysql_table,
byte* mysql_rec,
const dict_table_t* old_table,
- upd_t* parent_update,
- dict_foreign_t* foreign)
+ const upd_t* update)
{
byte rec_buf2[REC_VERSION_56_MAX_INDEX_COL_LEN];
byte* buf;
@@ -21951,6 +21909,8 @@ innobase_get_computed_value(
ulint ret = 0;
+ dict_index_t *clust_index= dict_table_get_first_index(index->table);
+
ut_ad(index->table->vc_templ);
ut_ad(thd != NULL);
ut_ad(mysql_table);
@@ -21980,14 +21940,16 @@ innobase_get_computed_value(
= index->table->vc_templ->vtempl[col_no];
const byte* data;
- if (parent_update != NULL) {
- /** Get the updated field from update vector
- of the parent table. */
- row_field = innobase_get_field_from_update_vector(
- foreign, parent_update, col_no);
+ if (update) {
+ ulint clust_no = dict_col_get_clust_pos(base_col,
+ clust_index);
+ if (const upd_field_t *uf = upd_get_field_by_field_no(
+ update, clust_no, false)) {
+ row_field = &uf->new_val;
+ }
}
- if (row_field == NULL) {
+ if (!row_field) {
row_field = dtuple_get_nth_field(row, col_no);
}