summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2022-08-17 18:46:04 +0300
committerNikita Malyavin <nikitamalyavin@gmail.com>2022-10-12 20:49:45 +0300
commit3cd2c1e8b6fa8435e634360c2ff63f5d645b65dc (patch)
tree9cb684504929ed314b124e1d1c4ddb0f90bbe818 /sql
parent4fec99a2ba6034592d273d918402540d3d4fe772 (diff)
downloadmariadb-git-3cd2c1e8b6fa8435e634360c2ff63f5d645b65dc.tar.gz
MDEV-29299 SELECT from table with vcol index reports warning
As of now innodb does not store trx_id for each record in secondary index. The idea behind is following: let us store only per-page max_trx_id, and delete-mark the records when they are deleted/updated. If the read starts, it rememders the lowest id of currently active transaction. Innodb refers to it as trx->read_view->m_up_limit_id. See also ReadView::open. When the page is fetched, its max_trx_id is compared to m_up_limit_id. If the value is lower, and the secondary index record is not delete-marked, then this page is just safe to read as is. Else, a clustered index could be needed ato access. See page_get_max_trx_id call in row_search_mvcc, and the corresponding switch (row_search_idx_cond_check(...)) below. Virtual columns are required to be updated in case if the record was delete-marked. The motivation behind it is documented in Row_sel_get_clust_rec_for_mysql::operator() near row_sel_sec_rec_is_for_clust_rec call. This was basically a description why virtual column computation can normally happen during SELECT, and, generally, a vcol index access. Sometimes stats tables are updated by innodb. This starts a new transaction, and it can happen that it didn't finish to the moment of SELECT execution, forcing virtual columns recomputation. If the result was a something that normally outputs a warning, like division by zero, then it could be outputted in a racy manner. The solution is to suppress the warnings when a column is computed for the described purpose. ignore_wrnings argument is added innobase_get_computed_value. Currently, it is only true for a call from row_sel_sec_rec_is_for_clust_rec.
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_class.h15
-rw-r--r--sql/table.cc14
-rw-r--r--sql/table.h2
3 files changed, 29 insertions, 2 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 7e06f0b0903..4d1f5b40db5 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1856,6 +1856,21 @@ private:
};
+struct Suppress_warnings_error_handler : public Internal_error_handler
+{
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char *sqlstate,
+ Sql_condition::enum_warning_level *level,
+ const char *msg,
+ Sql_condition **cond_hdl)
+ {
+ return *level == Sql_condition::WARN_LEVEL_WARN;
+ }
+};
+
+
+
/**
Tables that were locked with LOCK TABLES statement.
diff --git a/sql/table.cc b/sql/table.cc
index 5d91026963a..65b429a1b5a 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -8155,12 +8155,22 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
DBUG_RETURN(in_use->is_error());
}
-int TABLE::update_virtual_field(Field *vf)
+/*
+ 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.
+*/
+int TABLE::update_virtual_field(Field *vf, bool ignore_warnings)
{
DBUG_ENTER("TABLE::update_virtual_field");
Query_arena backup_arena;
Counting_error_handler count_errors;
+ Suppress_warnings_error_handler warning_handler;
in_use->push_internal_handler(&count_errors);
+ if (ignore_warnings)
+ in_use->push_internal_handler(&warning_handler);
/*
TODO: this may impose memory leak until table flush.
See comment in
@@ -8172,6 +8182,8 @@ int TABLE::update_virtual_field(Field *vf)
vf->vcol_info->expr->save_in_field(vf, 0);
in_use->restore_active_arena(expr_arena, &backup_arena);
in_use->pop_internal_handler();
+ if (ignore_warnings)
+ in_use->pop_internal_handler();
DBUG_RETURN(count_errors.errors);
}
diff --git a/sql/table.h b/sql/table.h
index 1eb09f119ed..577c11c37ee 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1610,7 +1610,7 @@ public:
uint actual_n_key_parts(KEY *keyinfo);
ulong actual_key_flags(KEY *keyinfo);
- int update_virtual_field(Field *vf);
+ int update_virtual_field(Field *vf, bool ignore_warnings);
int update_virtual_fields(handler *h, enum_vcol_update_mode update_mode);
int update_default_fields(bool ignore_errors);
void evaluate_update_default_function();