diff --git a/mysql-test/r/histograms_debug.result b/mysql-test/r/histograms_debug.result index eeac842771f..201b3f93dcf 100644 --- a/mysql-test/r/histograms_debug.result +++ b/mysql-test/r/histograms_debug.result @@ -111,6 +111,63 @@ test t1 col1 {"buckets": [[0.00004702340815870409, 0.25838108012301947, 0.25, 13 SET DEBUG='-d,histogram_force_sampling'; DROP TABLE t1; # +# We will inject a dummy histogram to verify forward compatibility. +# +SET debug='+d,skip_dd_table_access_check'; +# +# The dummy histogram will be removed on drop table. +# +CREATE TABLE tbl_int (col1 int); +INSERT mysql.column_statistics +VALUES (1, 1, unhex("746573741F74626C5F696E741F636F6C31"), +"test", "tbl_int", "col1", +"{\"histogram-type\":\"dummy\",\"data-type\":\"int\"}", +NULL); +DROP TABLE tbl_int; +SELECT COUNT(*) AS should_be_0 from information_schema.COLUMN_STATISTICS; +should_be_0 +0 +# +# The dummy histogram will be removed on drop histogram. +# +CREATE TABLE tbl_int (col1 int); +INSERT mysql.column_statistics +VALUES (1, 1, unhex("746573741F74626C5F696E741F636F6C31"), +"test", "tbl_int", "col1", +"{\"histogram-type\":\"dummy\",\"data-type\":\"int\"}", +NULL); +ANALYZE TABLE tbl_int drop histogram on col1; +Table Op Msg_type Msg_text +test.tbl_int histogram status Histogram statistics removed for column 'col1'. +SELECT COUNT(*) AS should_be_0 FROM information_schema.COLUMN_STATISTICS; +should_be_0 +0 +DROP TABLE tbl_int; +# +# The dummy histogram will be overwritten on update histogram. +# +CREATE TABLE tbl_int (col1 int); +INSERT mysql.column_statistics +VALUES (1, 1, unhex("746573741F74626C5F696E741F636F6C31"), +"test", "tbl_int", "col1", +"{\"histogram-type\":\"dummy\",\"data-type\":\"int\"}", +NULL); +INSERT tbl_int VALUES (1); +SELECT JSON_REMOVE(histogram, '$."last-updated"') FROM information_schema.COLUMN_STATISTICS; +JSON_REMOVE(histogram, '$."last-updated"') +{"data-type": "int", "histogram-type": "dummy"} +ANALYZE TABLE tbl_int update histogram on col1; +Table Op Msg_type Msg_text +test.tbl_int histogram status Histogram statistics created for column 'col1'. +SELECT JSON_REMOVE(histogram, '$."last-updated"') FROM information_schema.COLUMN_STATISTICS; +JSON_REMOVE(histogram, '$."last-updated"') +{"buckets": [[1, 1.0]], "data-type": "int", "null-values": 0.0, "collation-id": 8, "sampling-rate": 1.0, "histogram-type": "singleton", "number-of-buckets-specified": 100} +SELECT * FROM tbl_int; +col1 +1 +DROP TABLE tbl_int; +SET DEBUG='-d,skip_dd_table_access_check'; +# # Bug#26020352 WL8943:ASSERTION `M_THD->GET_TRANSACTION()->IS_EMPTY( # TRANSACTION_CTX::STMT) && M # diff --git a/mysql-test/t/histograms_debug.test b/mysql-test/t/histograms_debug.test index 0426f760afe..aabbf642d7b 100644 --- a/mysql-test/t/histograms_debug.test +++ b/mysql-test/t/histograms_debug.test @@ -93,6 +93,58 @@ FROM information_schema.COLUMN_STATISTICS; SET DEBUG='-d,histogram_force_sampling'; DROP TABLE t1; +--echo # +--echo # We will inject a dummy histogram to verify forward compatibility. +--echo # +SET debug='+d,skip_dd_table_access_check'; + +--echo # +--echo # The dummy histogram will be removed on drop table. +--echo # +CREATE TABLE tbl_int (col1 int); +INSERT mysql.column_statistics +VALUES (1, 1, unhex("746573741F74626C5F696E741F636F6C31"), + "test", "tbl_int", "col1", + "{\"histogram-type\":\"dummy\",\"data-type\":\"int\"}", + NULL); +DROP TABLE tbl_int; +SELECT COUNT(*) AS should_be_0 from information_schema.COLUMN_STATISTICS; + +--echo # +--echo # The dummy histogram will be removed on drop histogram. +--echo # +CREATE TABLE tbl_int (col1 int); +INSERT mysql.column_statistics +VALUES (1, 1, unhex("746573741F74626C5F696E741F636F6C31"), + "test", "tbl_int", "col1", + "{\"histogram-type\":\"dummy\",\"data-type\":\"int\"}", + NULL); +ANALYZE TABLE tbl_int drop histogram on col1; +SELECT COUNT(*) AS should_be_0 FROM information_schema.COLUMN_STATISTICS; +DROP TABLE tbl_int; + +--echo # +--echo # The dummy histogram will be overwritten on update histogram. +--echo # +CREATE TABLE tbl_int (col1 int); +INSERT mysql.column_statistics +VALUES (1, 1, unhex("746573741F74626C5F696E741F636F6C31"), + "test", "tbl_int", "col1", + "{\"histogram-type\":\"dummy\",\"data-type\":\"int\"}", + NULL); +INSERT tbl_int VALUES (1); +--disable_query_log +call mtr.add_suppression("Unsupported histogram type on column '[^']*'"); +--enable_query_log +SELECT JSON_REMOVE(histogram, '$."last-updated"') FROM information_schema.COLUMN_STATISTICS; +ANALYZE TABLE tbl_int update histogram on col1; +SELECT JSON_REMOVE(histogram, '$."last-updated"') FROM information_schema.COLUMN_STATISTICS; +SELECT * FROM tbl_int; +DROP TABLE tbl_int; + +SET DEBUG='-d,skip_dd_table_access_check'; + + --echo # --echo # Bug#26020352 WL8943:ASSERTION `M_THD->GET_TRANSACTION()->IS_EMPTY( --echo # TRANSACTION_CTX::STMT) && M diff --git a/share/errmsg-utf8.txt b/share/errmsg-utf8.txt index d8501e49099..41d04130ced 100644 --- a/share/errmsg-utf8.txt +++ b/share/errmsg-utf8.txt @@ -19229,6 +19229,9 @@ ER_JSON_VALUE_OUT_OF_RANGE_FOR_FUNC_INDEX 22003 ER_LDAP_EMPTY_USERDN_PASSWORD eng "Empty user dn or password is not allowed, not attempting LDAP bind." +ER_WARN_UNSUPPORTED_HISTOGRAM_TYPE + eng "Unsupported histogram type on column '%s.%s.%s'". + # # End of 8.0 error messages intended to be logged to the server error log. # diff --git a/sql/dd/impl/types/column_statistics_impl.cc b/sql/dd/impl/types/column_statistics_impl.cc index 666b6d6a499..459a75c53ad 100644 --- a/sql/dd/impl/types/column_statistics_impl.cc +++ b/sql/dd/impl/types/column_statistics_impl.cc @@ -117,8 +117,10 @@ bool Column_statistics_impl::restore_attributes(const Raw_record &r) { m_histogram = histograms::Histogram::json_to_histogram( &m_mem_root, {m_schema_name.data(), m_schema_name.size()}, {m_table_name.data(), m_table_name.size()}, - {m_column_name.data(), m_column_name.size()}, *json_object); - if (m_histogram == nullptr) return true; /* purecov: deadcode */ + {m_column_name.data(), m_column_name.size()}, *json_object, + &m_unsupported); + if (!m_unsupported && m_histogram == nullptr) + return true; /* purecov: inspected */ return false; } diff --git a/sql/dd/impl/types/column_statistics_impl.h b/sql/dd/impl/types/column_statistics_impl.h index 873f1be0c19..399587b9c60 100644 --- a/sql/dd/impl/types/column_statistics_impl.h +++ b/sql/dd/impl/types/column_statistics_impl.h @@ -57,7 +57,8 @@ class Column_statistics_impl final : public Entity_object_impl, public Column_statistics { public: Column_statistics_impl() - : m_schema_name(), m_table_name(), m_column_name(), m_histogram(nullptr) { + : m_schema_name(), m_table_name(), m_column_name(), m_histogram(nullptr), + m_unsupported() { init_alloc_root(key_memory_DD_column_statistics, &m_mem_root, 256, 0); } @@ -68,7 +69,8 @@ class Column_statistics_impl final : public Entity_object_impl, m_schema_name(column_statistics.m_schema_name), m_table_name(column_statistics.m_table_name), m_column_name(column_statistics.m_column_name), - m_histogram(nullptr) { + m_histogram(nullptr), + m_unsupported() { init_alloc_root(key_memory_DD_column_statistics, &m_mem_root, 256, 0); if (column_statistics.m_histogram != nullptr) @@ -80,7 +82,10 @@ class Column_statistics_impl final : public Entity_object_impl, static void register_tables(Open_dictionary_tables_ctx *otx); - bool validate() const override { return m_histogram == nullptr; } + bool validate() const override { + // Unsupported histogram is assumed valid and never used. + return !m_unsupported && m_histogram == nullptr; + } bool store_attributes(Raw_record *r) override; @@ -121,6 +126,8 @@ class Column_statistics_impl final : public Entity_object_impl, m_histogram = std::move(histogram); } + bool unsupported() const override { return m_unsupported; } + Entity_object_impl *impl() override { return Entity_object_impl::impl(); } const Entity_object_impl *impl() const override { @@ -156,6 +163,7 @@ class Column_statistics_impl final : public Entity_object_impl, String_type m_table_name; String_type m_column_name; const histograms::Histogram *m_histogram; + bool m_unsupported; Column_statistics *clone() const override { return new Column_statistics_impl(*this); diff --git a/sql/dd/types/column_statistics.h b/sql/dd/types/column_statistics.h index 4829bebb0fe..54a74a14415 100644 --- a/sql/dd/types/column_statistics.h +++ b/sql/dd/types/column_statistics.h @@ -88,6 +88,8 @@ class Column_statistics : virtual public Entity_object { virtual const histograms::Histogram *histogram() const = 0; virtual void set_histogram(const histograms::Histogram *histogram) = 0; + virtual bool unsupported() const = 0; + /** Converts *this into json. diff --git a/sql/histograms/histogram.cc b/sql/histograms/histogram.cc index afb9ba3ea2c..d3495fe9479 100644 --- a/sql/histograms/histogram.cc +++ b/sql/histograms/histogram.cc @@ -359,7 +359,8 @@ Histogram *Histogram::json_to_histogram(MEM_ROOT *mem_root, const std::string &schema_name, const std::string &table_name, const std::string &column_name, - const Json_object &json_object) { + const Json_object &json_object, + bool *unsupported) { // Histogram type (equi-height or singleton). const Json_dom *histogram_type_dom = json_object.get(Histogram::histogram_type_str()); @@ -460,6 +461,7 @@ Histogram *Histogram::json_to_histogram(MEM_ROOT *mem_root, } } else { // Unsupported histogram type. + *unsupported = true; return nullptr; /* purecov: deadcode */ } @@ -1271,7 +1273,8 @@ bool rename_histograms(THD *thd, const char *old_schema_name, bool find_histogram(THD *thd, const std::string &schema_name, const std::string &table_name, const std::string &column_name, - const Histogram **histogram) { + const Histogram **histogram, + bool *unsupported) { DBUG_ASSERT(*histogram == nullptr); if (schema_name == "mysql" || table_name == "column_statistics") return false; @@ -1286,6 +1289,7 @@ bool find_histogram(THD *thd, const std::string &schema_name, if (column_statistics == nullptr) return false; + *unsupported = column_statistics->unsupported(); *histogram = column_statistics->histogram(); return false; } diff --git a/sql/histograms/histogram.h b/sql/histograms/histogram.h index c3257a34574..0d039cb0ca5 100644 --- a/sql/histograms/histogram.h +++ b/sql/histograms/histogram.h @@ -406,15 +406,18 @@ class Histogram { @param table_name the table name @param column_name the column name @param json_object output where the histogram is stored + @param unsupported[out] the histogram in the json is unsupported, it may be + persisted by some newer code. - @return nullptr on error. Otherwise a histogram allocated on the provided - MEM_ROOT. + @return nullptr on error or unsupported. Otherwise a histogram allocated on + the provided MEM_ROOT. */ static Histogram *json_to_histogram(MEM_ROOT *mem_root, const std::string &schema_name, const std::string &table_name, const std::string &column_name, - const Json_object &json_object); + const Json_object &json_object, + bool *unsupported); /** Make a clone of the current histogram @@ -572,7 +575,8 @@ bool rename_histograms(THD *thd, const char *old_schema_name, bool find_histogram(THD *thd, const std::string &schema_name, const std::string &table_name, const std::string &column_name, - const Histogram **histogram); + const Histogram **histogram, + bool *unsupported); } // namespace histograms #endif diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3283d1b0da5..a5d975d30ad 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -584,9 +584,11 @@ static bool read_histograms(THD *thd, TABLE_SHARE *share, if (column->is_se_hidden()) continue; const histograms::Histogram *histogram = nullptr; + bool unsupported = false; if (histograms::find_histogram(thd, schema->name().c_str(), table_def->name().c_str(), - column->name().c_str(), &histogram)) { + column->name().c_str(), &histogram, + &unsupported)) { // Any error is reported by the dictionary subsystem. return true; /* purecov: deadcode */ } @@ -602,6 +604,13 @@ static bool read_histograms(THD *thd, TABLE_SHARE *share, share->m_histograms->emplace(column->ordinal_position() - 1, histogram_copy); } + + if (unsupported) { + LogErr(WARNING_LEVEL, ER_WARN_UNSUPPORTED_HISTOGRAM_TYPE, + schema->name().c_str(), + table_def->name().c_str(), + column->name().c_str()); + } } return false;