From d891d23ec33fb8432b7cd9bf90b8a5b41fdbab42 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 29 Sep 2025 11:14:10 +1000 Subject: [PATCH 01/12] MDEV-37724: Debug Memory leak with InnoDB ALTER TABLE ALGORITHM=INSTANT Instrumented debug mode triggering of instant_insert_fail failed to free partition memory like the que_eval_sql function who's failure it intended to emulate. Corrected by freeing the partition information when this internal debug mode instrumented condition occured. --- storage/innobase/handler/handler0alter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 1bd59e49929..43ea8c1466d 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -5528,6 +5528,7 @@ static bool innodb_insert_sys_columns( DBUG_EXECUTE_IF("instant_insert_fail", my_error(ER_INTERNAL_ERROR, MYF(0), "InnoDB: Insert into SYS_COLUMNS failed"); + pars_info_free(info); return true;); if (DB_SUCCESS != que_eval_sql( From 6aa749831382b053cce122bfdd490b80ce35a629 Mon Sep 17 00:00:00 2001 From: bsrikanth-mariadb Date: Mon, 15 Sep 2025 17:54:25 +0530 Subject: [PATCH 02/12] MDEV-31744: Assertion with COUNT(*) OVER (ORDER BY const RANGE BETWEEN...) When the query uses several Window Functions: SELECT WIN_FUNC1() OVER (ORDER BY 'const', col1), WIN_FUNC2() OVER (ORDER BY col1 RANGE BETWEEN CURRENT ROW AND 5 FOLLOWING) compare_window_funcs_by_window_specs() will try to get the Window Specs to reuse the ORDER BY lists. If the lists produce the same order (like above) Window Spec of the WIN_FUNC2 will reuse the ORDER BY list of WIN_FUNC1. However, WIN_FUNC2 has a RANGE-type window frame. It expects to get ORDER BY list with one element, which it will use to compute frame bounds. Proving it with ORDER BY list from WIN_FUNC1 ('const', col1) was caused an assertion failure The fix is to: Use the original ORDER BY list when constructing RANGE-type frames Fix an apparent typo bug in compare_window_funcs_by_window_specs(): assignment win_spec1->save_order_list= win_spec2->order_list; Saved the order list from the wrong spec. Instead, take one from win_spec1. --- mysql-test/main/win.result | 50 +++++++++++++++++ mysql-test/main/win.test | 53 +++++++++++++++++++ .../encryption/r/tempfiles_encrypted.result | 50 +++++++++++++++++ sql/sql_window.cc | 20 +++++-- 4 files changed, 169 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/win.result b/mysql-test/main/win.result index ec9d3fd4cb9..8f38c424ddf 100644 --- a/mysql-test/main/win.result +++ b/mysql-test/main/win.result @@ -4745,3 +4745,53 @@ DROP TABLE t1, t2; # # End of 10.6 tests # +# +# MDEV-31744: Assertion `order_list->elements == 1' failure +# during Frame_range_n_bottom object creation +# +CREATE TABLE t1 (a int, b int, c int, d int) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,1,1,1); +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT +LEAD(a) OVER (ORDER BY b, c) AS c1, +COUNT(*) OVER (ORDER BY d RANGE BETWEEN CURRENT ROW AND 5 FOLLOWING) AS c2 +FROM v1; +c1 c2 +NULL 1 +# +# test similar query as above for Frame_range_n_top +# +SELECT +LEAD(a) OVER (ORDER BY b, c) AS c1, +COUNT(*) OVER (ORDER BY d RANGE BETWEEN 5 PRECEDING AND CURRENT ROW) AS c2 +FROM v1; +c1 c2 +NULL 1 +DROP TABLE t1; +DROP VIEW v1; +# +# test queries as above but on the table instead of view +# +CREATE TABLE t1 (a int) ENGINE=MyISAM; +INSERT INTO t1 values (1), (2); +SELECT +COUNT(*) OVER (ORDER BY 'abc', a) AS c1, +COUNT(*) OVER (ORDER BY a RANGE BETWEEN CURRENT ROW AND 5 FOLLOWING) AS c2 +from t1; +c1 c2 +1 2 +2 1 +# +# similar query on table with Frame_range_n_top +# +SELECT +COUNT(*) OVER (ORDER BY 'abc', a) AS c1, +COUNT(*) OVER (ORDER BY a RANGE BETWEEN 5 PRECEDING AND CURRENT ROW) AS c2 +from t1; +c1 c2 +1 1 +2 2 +DROP TABLE t1; +# +# End of 10.11 tests +# diff --git a/mysql-test/main/win.test b/mysql-test/main/win.test index 23f14bad573..35f59041d3b 100644 --- a/mysql-test/main/win.test +++ b/mysql-test/main/win.test @@ -3058,3 +3058,56 @@ DROP TABLE t1, t2; --echo # --echo # End of 10.6 tests --echo # + +--echo # +--echo # MDEV-31744: Assertion `order_list->elements == 1' failure +--echo # during Frame_range_n_bottom object creation +--echo # + +CREATE TABLE t1 (a int, b int, c int, d int) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,1,1,1); +CREATE VIEW v1 AS SELECT * FROM t1; + +SELECT + LEAD(a) OVER (ORDER BY b, c) AS c1, + COUNT(*) OVER (ORDER BY d RANGE BETWEEN CURRENT ROW AND 5 FOLLOWING) AS c2 +FROM v1; + +--echo # +--echo # test similar query as above for Frame_range_n_top +--echo # + +SELECT + LEAD(a) OVER (ORDER BY b, c) AS c1, + COUNT(*) OVER (ORDER BY d RANGE BETWEEN 5 PRECEDING AND CURRENT ROW) AS c2 +FROM v1; + +DROP TABLE t1; +DROP VIEW v1; + +--echo # +--echo # test queries as above but on the table instead of view +--echo # + +CREATE TABLE t1 (a int) ENGINE=MyISAM; +INSERT INTO t1 values (1), (2); + +SELECT + COUNT(*) OVER (ORDER BY 'abc', a) AS c1, + COUNT(*) OVER (ORDER BY a RANGE BETWEEN CURRENT ROW AND 5 FOLLOWING) AS c2 +from t1; + +--echo # +--echo # similar query on table with Frame_range_n_top +--echo # + +SELECT + COUNT(*) OVER (ORDER BY 'abc', a) AS c1, + COUNT(*) OVER (ORDER BY a RANGE BETWEEN 5 PRECEDING AND CURRENT ROW) AS c2 +from t1; + +DROP TABLE t1; + +--echo # +--echo # End of 10.11 tests +--echo # diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result index b1725acee79..aff2b9306aa 100644 --- a/mysql-test/suite/encryption/r/tempfiles_encrypted.result +++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result @@ -4752,6 +4752,56 @@ DROP TABLE t1, t2; # End of 10.6 tests # # +# MDEV-31744: Assertion `order_list->elements == 1' failure +# during Frame_range_n_bottom object creation +# +CREATE TABLE t1 (a int, b int, c int, d int) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,1,1,1); +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT +LEAD(a) OVER (ORDER BY b, c) AS c1, +COUNT(*) OVER (ORDER BY d RANGE BETWEEN CURRENT ROW AND 5 FOLLOWING) AS c2 +FROM v1; +c1 c2 +NULL 1 +# +# test similar query as above for Frame_range_n_top +# +SELECT +LEAD(a) OVER (ORDER BY b, c) AS c1, +COUNT(*) OVER (ORDER BY d RANGE BETWEEN 5 PRECEDING AND CURRENT ROW) AS c2 +FROM v1; +c1 c2 +NULL 1 +DROP TABLE t1; +DROP VIEW v1; +# +# test queries as above but on the table instead of view +# +CREATE TABLE t1 (a int) ENGINE=MyISAM; +INSERT INTO t1 values (1), (2); +SELECT +COUNT(*) OVER (ORDER BY 'abc', a) AS c1, +COUNT(*) OVER (ORDER BY a RANGE BETWEEN CURRENT ROW AND 5 FOLLOWING) AS c2 +from t1; +c1 c2 +1 2 +2 1 +# +# similar query on table with Frame_range_n_top +# +SELECT +COUNT(*) OVER (ORDER BY 'abc', a) AS c1, +COUNT(*) OVER (ORDER BY a RANGE BETWEEN 5 PRECEDING AND CURRENT ROW) AS c2 +from t1; +c1 c2 +1 1 +2 2 +DROP TABLE t1; +# +# End of 10.11 tests +# +# # MDEV-23867: select crash in compute_window_func # set @save_sort_buffer_size=@@sort_buffer_size; diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 5fa63f2a65d..aa612d7e4e0 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -665,12 +665,12 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1, */ if (!win_spec1->name() && win_spec2->name()) { - win_spec1->save_order_list= win_spec2->order_list; + win_spec1->save_order_list= win_spec1->order_list; win_spec1->order_list= win_spec2->order_list; } else { - win_spec1->save_order_list= win_spec2->order_list; + win_spec2->save_order_list= win_spec2->order_list; win_spec2->order_list= win_spec1->order_list; } @@ -2490,13 +2490,25 @@ Frame_cursor *get_frame_cursor(THD *thd, Window_spec *spec, bool is_top_bound) } else { + /* + compare_window_funcs_by_window_specs() will try to get the + Window Specs to reuse the ORDER BY lists. + RANGE-type window frame expects a single ORDER BY element, + and if the list from a different window spec having more than 1 + ORDER BY element is used, then an ASSERT is raised. + + So, use the original ORDER BY list when constructing + RANGE-type frames. + */ + SQL_I_List *order_list= + spec->save_order_list ? spec->save_order_list : spec->order_list; if (is_top_bound) return new Frame_range_n_top( - thd, spec->partition_list, spec->order_list, + thd, spec->partition_list, order_list, is_preceding, bound->offset); return new Frame_range_n_bottom(thd, - spec->partition_list, spec->order_list, + spec->partition_list, order_list, is_preceding, bound->offset); } } From f0bef17b82bd8917f99a04dd6d9c093d08755924 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Wed, 17 Sep 2025 18:10:22 +0530 Subject: [PATCH 03/12] MDEV-30277: Assertion failure in Diagnostics_area::set_error_status / Reprepare_observer::report_error Analysis: Error is not reported when we hit invalid default parameter error Fix: Return appropriate value on error. --- mysql-test/main/ps.result | 12 ++++++++++++ mysql-test/main/ps.test | 17 +++++++++++++++++ sql/sql_parse.cc | 3 +++ 3 files changed, 32 insertions(+) diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index 0231974fed9..7c425718af9 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -6047,3 +6047,15 @@ a b c 1 1970-01-01 09:00:01 6 DROP TABLE t; # End of 10.6 tests +# Beginning of 10.11 test +# +# MDEV-30277: Assertion failure in Diagnostics_area::set_error_status +# / Reprepare_observer::report_error +# +CREATE TABLE t (a INT); +PREPARE stmt FROM " DELETE FROM t LIMIT ?"; +ALTER TABLE t FORCE; +EXECUTE stmt USING DEFAULT; +ERROR HY000: Default/ignore value is not supported for such parameter usage +DROP TABLE t; +# End of 10.11 test diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index 54666d64012..185cd065aea 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -5498,3 +5498,20 @@ SELECT * FROM t; DROP TABLE t; --echo # End of 10.6 tests + +--echo # Beginning of 10.11 test + +--echo # +--echo # MDEV-30277: Assertion failure in Diagnostics_area::set_error_status +--echo # / Reprepare_observer::report_error +--echo # + +CREATE TABLE t (a INT); +PREPARE stmt FROM " DELETE FROM t LIMIT ?"; +ALTER TABLE t FORCE; +--error ER_INVALID_DEFAULT_PARAM +EXECUTE stmt USING DEFAULT; + +DROP TABLE t; + +--echo # End of 10.11 test diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index faed5e33ac3..007af961396 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4894,6 +4894,9 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) DBUG_ASSERT(select_lex->limit_params.offset_limit == 0); unit->set_limit(select_lex); + if (thd->is_error()) + goto error; + MYSQL_DELETE_START(thd->query()); Protocol *save_protocol= NULL; From ee65b7bd1ff14e37ddb486bf9f6c2342a9aae9ee Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 26 Sep 2025 16:51:49 +0300 Subject: [PATCH 04/12] Fix compiler warnings - Removed conversion from size_t to uint32 - Removed not used variables and silence warnings from mronga/vendor/gronga/lib/ii.c --- sql/item_xmlfunc.h | 2 +- storage/mroonga/vendor/groonga/lib/ii.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h index b895d93af34..2fbae54ca31 100644 --- a/sql/item_xmlfunc.h +++ b/sql/item_xmlfunc.h @@ -55,7 +55,7 @@ public: } uint32 elements() const { - return length() / sizeof(MY_XPATH_FLT); + return length() / (uint32) sizeof(MY_XPATH_FLT); } }; diff --git a/storage/mroonga/vendor/groonga/lib/ii.c b/storage/mroonga/vendor/groonga/lib/ii.c index 87476604793..5364eb84ba2 100644 --- a/storage/mroonga/vendor/groonga/lib/ii.c +++ b/storage/mroonga/vendor/groonga/lib/ii.c @@ -488,7 +488,7 @@ chunk_new(grn_ctx *ctx, grn_ii *ii, uint32_t *res, uint32_t size) return ctx->rc; } else { uint32_t *vp; - int m, aligned_size; + int m; if (size > (1 << GRN_II_W_LEAST_CHUNK)) { int es = size - 1; GRN_BIT_SCAN_REV(es, m); @@ -496,7 +496,6 @@ chunk_new(grn_ctx *ctx, grn_ii *ii, uint32_t *res, uint32_t size) } else { m = GRN_II_W_LEAST_CHUNK; } - aligned_size = 1 << (m - GRN_II_W_LEAST_CHUNK); if (ii->header->ngarbages[m - GRN_II_W_LEAST_CHUNK] > N_GARBAGES_TH) { grn_ii_ginfo *ginfo; uint32_t *gseg; @@ -2856,7 +2855,7 @@ chunk_merge(grn_ctx *ctx, grn_ii *ii, buffer *sb, buffer_term *bt, if (scp) { uint16_t nextb = *nextbp; - uint32_t snn = 0, *srp, *ssp = NULL, *stp, *sop = NULL, *snp; + uint32_t *srp, *ssp = NULL, *stp, *sop = NULL, *snp; uint8_t *sbp = *sbpp; datavec rdv[MAX_N_ELEMENTS + 1]; size_t bufsize = S_SEGMENT * ii->n_elements; @@ -2873,7 +2872,6 @@ chunk_merge(grn_ctx *ctx, grn_ii *ii, buffer *sb, buffer_term *bt, if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) { ssp = rdv[j++].data; } stp = rdv[j++].data; if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { sop = rdv[j++].data; } - snn = rdv[j].data_size; snp = rdv[j].data; } datavec_reset(ctx, dv, ii->n_elements, sdf + S_SEGMENT, bufsize); @@ -3044,7 +3042,7 @@ buffer_merge(grn_ctx *ctx, grn_ii *ii, uint32_t seg, grn_hash *h, chunk_info *cinfo = NULL; grn_id crid = GRN_ID_NIL; docinfo cid = {0, 0, 0, 0, 0}, lid = {0, 0, 0, 0, 0}, bid = {0, 0, 0, 0, 0}; - uint32_t sdf = 0, snn = 0, ndf; + uint32_t sdf = 0, ndf; uint32_t *srp = NULL, *ssp = NULL, *stp = NULL, *sop = NULL, *snp = NULL; if (!bt->tid) { nterms_void++; @@ -3130,7 +3128,6 @@ buffer_merge(grn_ctx *ctx, grn_ii *ii, uint32_t seg, grn_hash *h, if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) { ssp = rdv[j++].data; } stp = rdv[j++].data; if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { sop = rdv[j++].data; } - snn = rdv[j].data_size; snp = rdv[j].data; } datavec_reset(ctx, dv, ii->n_elements, sdf + S_SEGMENT, size); @@ -3541,8 +3538,12 @@ grn_ii_buffer_check(grn_ctx *ctx, grn_ii *ii, uint32_t seg) chunk_info *cinfo = NULL; grn_id crid = GRN_ID_NIL; docinfo bid = {0, 0, 0, 0, 0}; - uint32_t sdf = 0, snn = 0; - uint32_t *srp = NULL, *ssp = NULL, *stp = NULL, *sop = NULL, *snp = NULL; + uint32_t sdf = 0; + uint32_t *srp __attribute__((unused)) = NULL; + uint32_t *ssp __attribute__((unused)) = NULL; + uint32_t *stp __attribute__((unused)) = NULL; + uint32_t *sop __attribute__((unused)) = NULL; + uint32_t *snp __attribute__((unused)) = NULL; if (!bt->tid && !bt->pos_in_buffer && !bt->size_in_buffer) { nterms_void++; continue; @@ -3597,7 +3598,6 @@ grn_ii_buffer_check(grn_ctx *ctx, grn_ii *ii, uint32_t seg) stp = rdv[j++].data; if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { sop = rdv[j++].data; } GRN_OUTPUT_INT64(rdv[j].data_size); - snn = rdv[j].data_size; snp = rdv[j].data; } nterm_with_chunk++; @@ -4119,7 +4119,7 @@ buffer_new_lexicon_pat(grn_ctx *ctx, *lseg == GRN_II_PSEG_NOT_ASSIGNED && (tid = grn_pat_cursor_next(ctx, cursor))) { void *current_key; - int current_key_size; + int current_key_size __attribute__((unused)); current_key_size = grn_pat_cursor_get_key(ctx, cursor, ¤t_key); if (memcmp(((char *)current_key) + target_key_size, From 78aa5fb62319b7a8605e36d5cde2bfa7f7046d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 30 Sep 2025 16:42:58 +0300 Subject: [PATCH 05/12] MDEV-37299 fixup: cmake -DPLUGIN_PERFSCHEMA=NO --- .../suite/encryption/r/innodb-read-only.result | 12 ++++++++---- mysql-test/suite/encryption/t/innodb-read-only.test | 10 ++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/encryption/r/innodb-read-only.result b/mysql-test/suite/encryption/r/innodb-read-only.result index 3d23d3142f4..c40f5c4f9ba 100644 --- a/mysql-test/suite/encryption/r/innodb-read-only.result +++ b/mysql-test/suite/encryption/r/innodb-read-only.result @@ -1,16 +1,20 @@ # Wait max 10 min for key encryption threads to encrypt all spaces # Success! SET GLOBAL innodb_encryption_threads=4; -SELECT COUNT(*) AS encrypt_threads_running +SET @encryption_threads_running=4; +SELECT COUNT(*) INTO @encrypt_threads_running FROM performance_schema.threads WHERE NAME LIKE '%encrypt%'; -encrypt_threads_running +SELECT @encryption_threads_running; +@encryption_threads_running 4 # restart: --innodb-read-only=1 --innodb-encrypt-tables=1 SET GLOBAL innodb_encryption_threads=4; -SELECT COUNT(*) AS encrypt_threads_running +SET @encryption_threads_running=0; +SELECT COUNT(*) INTO @encryption_threads_running FROM performance_schema.threads WHERE NAME LIKE '%encrypt%'; -encrypt_threads_running +SELECT @encryption_threads_running; +@encryption_threads_running 0 # All done diff --git a/mysql-test/suite/encryption/t/innodb-read-only.test b/mysql-test/suite/encryption/t/innodb-read-only.test index d51825e1da5..d85257f3711 100644 --- a/mysql-test/suite/encryption/t/innodb-read-only.test +++ b/mysql-test/suite/encryption/t/innodb-read-only.test @@ -27,9 +27,12 @@ if (!$success) # Server in normal mode SET GLOBAL innodb_encryption_threads=4; -SELECT COUNT(*) AS encrypt_threads_running +SET @encryption_threads_running=4; +--error 0,ER_NO_SUCH_TABLE +SELECT COUNT(*) INTO @encrypt_threads_running FROM performance_schema.threads WHERE NAME LIKE '%encrypt%'; +SELECT @encryption_threads_running; # # MDEV-11835: InnoDB: Failing assertion: free_slot != NULL on @@ -40,7 +43,10 @@ WHERE NAME LIKE '%encrypt%'; # Server read-only mode SET GLOBAL innodb_encryption_threads=4; -SELECT COUNT(*) AS encrypt_threads_running +SET @encryption_threads_running=0; +--error 0,ER_NO_SUCH_TABLE +SELECT COUNT(*) INTO @encryption_threads_running FROM performance_schema.threads WHERE NAME LIKE '%encrypt%'; +SELECT @encryption_threads_running; --echo # All done From 35767042e545a89f96d39727457a2f2c83256b63 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 26 Sep 2025 09:26:32 +0200 Subject: [PATCH 06/12] MDEV-37743 Frequent timeouts of the test innodb.innodb_bug38231 a comment in the test says # do not clean up - we do not know which of the three has been released # so the --reap command may hang because the command that is being executed # in that connection is still running/waiting --- mysql-test/suite/innodb/r/innodb_bug38231.result | 1 - mysql-test/suite/innodb/t/innodb_bug38231.test | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_bug38231.result b/mysql-test/suite/innodb/r/innodb_bug38231.result index 3108e32d1a6..23c5b0cc2f7 100644 --- a/mysql-test/suite/innodb/r/innodb_bug38231.result +++ b/mysql-test/suite/innodb/r/innodb_bug38231.result @@ -1,2 +1 @@ SET default_storage_engine=InnoDB; -connection default; diff --git a/mysql-test/suite/innodb/t/innodb_bug38231.test b/mysql-test/suite/innodb/t/innodb_bug38231.test index 0c139c338c4..b6a7d452c34 100644 --- a/mysql-test/suite/innodb/t/innodb_bug38231.test +++ b/mysql-test/suite/innodb/t/innodb_bug38231.test @@ -15,7 +15,6 @@ SET default_storage_engine=InnoDB; -- disable_query_log -- disable_result_log -DROP TABLE IF EXISTS bug38231_1; CREATE TABLE bug38231_1 (a INT); -- connect (lock_gain,localhost,root,,) @@ -63,14 +62,15 @@ UNLOCK TABLES; -- connection default --- disconnect lock_gain --- disconnect lock_wait1 --- disconnect lock_wait2 --- disconnect truncate_wait +-- dirty_close lock_gain +-- dirty_close lock_wait1 +-- dirty_close lock_wait2 +-- dirty_close truncate_wait DROP TABLE bug38231_1; -- enable_query_log -- enable_result_log --- connection default +-- let $count_sessions= 1 +-- source include/wait_until_count_sessions.inc From e1f15d50ce81f09b0c8219f702294279f249deea Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 29 Sep 2025 23:08:02 +0200 Subject: [PATCH 07/12] MDEV-23731 SIGSEGV in replace_user_table when changing mysql db tables check that privilege tables have a PK and it has the correct number ok key parts also fixes: * MDEV-24206 SIGSEGV in replace_db_table on GRANT * MDEV-24814 SIGSEGV in replace_table_table on GRANT * MDEV-27842 SIGSEGV in replace_routine_table on GRANT * MDEV-28128 SIGSEGV in replace_column_table on GRANT * MDEV-27893 SIGSEGV in replace_proxies_priv_table on GRANT PROXY --- mysql-test/main/grant4.result | 4 +- mysql-test/main/grant4.test | 4 +- mysql-test/main/grant5.result | 4 +- mysql-test/main/grant5.test | 4 +- mysql-test/main/grant_repair.result | 74 +++++++++++++++++++++++++ mysql-test/main/grant_repair.test | 84 +++++++++++++++++++++++++++-- sql/sql_acl.cc | 69 ++++++++++++++---------- 7 files changed, 205 insertions(+), 38 deletions(-) diff --git a/mysql-test/main/grant4.result b/mysql-test/main/grant4.result index 321eee1847d..3c8c752d885 100644 --- a/mysql-test/main/grant4.result +++ b/mysql-test/main/grant4.result @@ -143,11 +143,11 @@ drop temporary table mysql.user; rename table mysql.user1 to mysql.user; # switching back from mysql.user to mysql.global_priv # switching from mysql.global_priv to mysql.user -call mtr.add_suppression('mysql.user table is damaged'); +call mtr.add_suppression('mysql\\.user'); rename table mysql.user to mysql.user1; create table mysql.user (Host char(100), User char(100)); flush privileges; -ERROR HY000: Fatal error: mysql.user table is damaged or in unsupported 3.20 format +ERROR HY000: Cannot load from mysql.user. The table is probably corrupted drop table mysql.user; rename table mysql.user1 to mysql.user; # switching back from mysql.user to mysql.global_priv diff --git a/mysql-test/main/grant4.test b/mysql-test/main/grant4.test index cda1c5fb281..6179af8cee2 100644 --- a/mysql-test/main/grant4.test +++ b/mysql-test/main/grant4.test @@ -169,10 +169,10 @@ source include/switch_to_mysql_global_priv.inc; # Bug#28986737: RENAMING AND REPLACING MYSQL.USER TABLE CAN LEAD TO A SERVER CRASH # source include/switch_to_mysql_user.inc; -call mtr.add_suppression('mysql.user table is damaged'); +call mtr.add_suppression('mysql\\.user'); rename table mysql.user to mysql.user1; create table mysql.user (Host char(100), User char(100)); ---error ER_UNKNOWN_ERROR +--error ER_CANNOT_LOAD_FROM_TABLE_V2 flush privileges; drop table mysql.user; rename table mysql.user1 to mysql.user; diff --git a/mysql-test/main/grant5.result b/mysql-test/main/grant5.result index 5aeedb89409..d960ed97d49 100644 --- a/mysql-test/main/grant5.result +++ b/mysql-test/main/grant5.result @@ -448,11 +448,11 @@ disconnect con1; connection default; drop database db; drop user foo; -call mtr.add_suppression('mysql.host table is damaged'); +call mtr.add_suppression('mysql\\.host'); create table mysql.host (c1 int); insert mysql.host values (1); flush privileges; -ERROR HY000: Fatal error: mysql.host table is damaged or in unsupported 3.20 format +ERROR HY000: Cannot load from mysql.host. The table is probably corrupted drop table mysql.host; # # MDEV-30826 Invalid data on mysql.host segfaults the server after an upgrade to 10.4 diff --git a/mysql-test/main/grant5.test b/mysql-test/main/grant5.test index a33cecbfc6d..b58173feea3 100644 --- a/mysql-test/main/grant5.test +++ b/mysql-test/main/grant5.test @@ -402,10 +402,10 @@ drop user foo; # # MDEV-23009 SIGSEGV in get_field from acl_load (on optimized builds) # -call mtr.add_suppression('mysql.host table is damaged'); +call mtr.add_suppression('mysql\\.host'); create table mysql.host (c1 int); insert mysql.host values (1); ---error ER_UNKNOWN_ERROR +--error ER_CANNOT_LOAD_FROM_TABLE_V2 flush privileges; drop table mysql.host; diff --git a/mysql-test/main/grant_repair.result b/mysql-test/main/grant_repair.result index 6ebe043e4d4..02199fbed57 100644 --- a/mysql-test/main/grant_repair.result +++ b/mysql-test/main/grant_repair.result @@ -1,3 +1,6 @@ +# +# MDEV-20257 Server crashes in Grant_table_base::init_read_record upon crash-upgrade +# call mtr.add_suppression("mysql.user"); # switching from mysql.global_priv to mysql.user flush tables; @@ -7,3 +10,74 @@ Error 145 Got error '145 "Table was marked as crashed and should be repaired"' f Warning 1034 12544 clients are using or haven't closed the table properly Note 1034 Table is fixed # switching back from mysql.user to mysql.global_priv +# +# MDEV-28128 SIGSEGV in replace_column_table on GRANT +# +call mtr.add_suppression("The table is probably corrupted"); +create user a@localhost; +rename table mysql.columns_priv to mysql.columns_priv_bak; +create table mysql.columns_priv select * from mysql.columns_priv_bak; +create table t (c int); +grant update (c) on t to a@localhost; +ERROR HY000: Cannot load from mysql.columns_priv. The table is probably corrupted +drop table t; +drop table mysql.columns_priv; +rename table mysql.columns_priv_bak to mysql.columns_priv; +drop user a@localhost; +# +# MDEV-23731 SIGSEGV in replace_user_table when changing mysql db tables +# +rename table mysql.global_priv to mysql.global_priv_bak; +rename table mysql.user to mysql.user_bak; +create table mysql.user (host char(100), user char(100)) engine=merge; +alter user 'a' identified by ''; +ERROR HY000: Cannot load from mysql.user. The table is probably corrupted +drop table mysql.user; +rename table mysql.global_priv_bak to mysql.global_priv; +rename table mysql.user_bak to mysql.user; +# +# MDEV-24206 SIGSEGV in replace_db_table on GRANT +# +rename table mysql.db to mysql.db_bak; +create table mysql.db engine=memory select * from mysql.db_bak; +grant select on mysql.* to 'a'@'a' identified by 'a'; +ERROR HY000: Cannot load from mysql.db. The table is probably corrupted +drop table mysql.db; +rename table mysql.db_bak to mysql.db; +# +# MDEV-24814 SIGSEGV in replace_table_table on GRANT +# +create user m@localhost; +rename table mysql.tables_priv to mysql.tables_priv_bak; +create table t (c int); +create table mysql.tables_priv select * from mysql.tables_priv_bak; +grant select on t to m@localhost; +ERROR HY000: Cannot load from mysql.tables_priv. The table is probably corrupted +drop table mysql.tables_priv; +rename table mysql.tables_priv_bak to mysql.tables_priv; +drop user m@localhost; +drop table t; +# +# MDEV-27842 SIGSEGV in replace_routine_table on GRANT +# +create user a@b; +set global log_bin_trust_function_creators=1; +rename table mysql.procs_priv to mysql.procs_priv_bak; +create table mysql.procs_priv (dummy int); +create function f() returns int return (select 1 t); +grant execute on function f to a@b; +ERROR HY000: Cannot load from mysql.procs_priv. The table is probably corrupted +drop table mysql.procs_priv; +rename table mysql.procs_priv_bak to mysql.procs_priv; +drop function f; +drop user a@b; +# +# MDEV-27893 SIGSEGV in replace_proxies_priv_table on GRANT PROXY +# +rename table mysql.proxies_priv to mysql.proxies_priv_bak; +create table mysql.proxies_priv select * from mysql.proxies_priv_bak; +grant proxy on grant_plug to grant_plug_dest; +ERROR HY000: Cannot load from mysql.proxies_priv. The table is probably corrupted +drop table mysql.proxies_priv; +rename table mysql.proxies_priv_bak to mysql.proxies_priv; +# End of 10.11 tests diff --git a/mysql-test/main/grant_repair.test b/mysql-test/main/grant_repair.test index f07e4df3ae6..de37ac607ea 100644 --- a/mysql-test/main/grant_repair.test +++ b/mysql-test/main/grant_repair.test @@ -1,6 +1,6 @@ -# -# MDEV-20257 Server crashes in Grant_table_base::init_read_record upon crash-upgrade -# +--echo # +--echo # MDEV-20257 Server crashes in Grant_table_base::init_read_record upon crash-upgrade +--echo # source include/not_embedded.inc; call mtr.add_suppression("mysql.user"); @@ -19,3 +19,81 @@ replace_result \\ /; flush privileges; source include/switch_to_mysql_global_priv.inc; + +--echo # +--echo # MDEV-28128 SIGSEGV in replace_column_table on GRANT +--echo # +call mtr.add_suppression("The table is probably corrupted"); +create user a@localhost; +rename table mysql.columns_priv to mysql.columns_priv_bak; +create table mysql.columns_priv select * from mysql.columns_priv_bak; +create table t (c int); +--error ER_CANNOT_LOAD_FROM_TABLE_V2 +grant update (c) on t to a@localhost; +drop table t; +drop table mysql.columns_priv; +rename table mysql.columns_priv_bak to mysql.columns_priv; +drop user a@localhost; + +--echo # +--echo # MDEV-23731 SIGSEGV in replace_user_table when changing mysql db tables +--echo # +rename table mysql.global_priv to mysql.global_priv_bak; +rename table mysql.user to mysql.user_bak; +create table mysql.user (host char(100), user char(100)) engine=merge; +--error ER_CANNOT_LOAD_FROM_TABLE_V2 +alter user 'a' identified by ''; +drop table mysql.user; +rename table mysql.global_priv_bak to mysql.global_priv; +rename table mysql.user_bak to mysql.user; + +--echo # +--echo # MDEV-24206 SIGSEGV in replace_db_table on GRANT +--echo # +rename table mysql.db to mysql.db_bak; +create table mysql.db engine=memory select * from mysql.db_bak; +--error ER_CANNOT_LOAD_FROM_TABLE_V2 +grant select on mysql.* to 'a'@'a' identified by 'a'; +drop table mysql.db; +rename table mysql.db_bak to mysql.db; + +--echo # +--echo # MDEV-24814 SIGSEGV in replace_table_table on GRANT +--echo # +create user m@localhost; +rename table mysql.tables_priv to mysql.tables_priv_bak; +create table t (c int); +create table mysql.tables_priv select * from mysql.tables_priv_bak; +--error ER_CANNOT_LOAD_FROM_TABLE_V2 +grant select on t to m@localhost; +drop table mysql.tables_priv; +rename table mysql.tables_priv_bak to mysql.tables_priv; +drop user m@localhost; +drop table t; + +--echo # +--echo # MDEV-27842 SIGSEGV in replace_routine_table on GRANT +--echo # +create user a@b; +set global log_bin_trust_function_creators=1; +rename table mysql.procs_priv to mysql.procs_priv_bak; +create table mysql.procs_priv (dummy int); +create function f() returns int return (select 1 t); +--error ER_CANNOT_LOAD_FROM_TABLE_V2 +grant execute on function f to a@b; +drop table mysql.procs_priv; +rename table mysql.procs_priv_bak to mysql.procs_priv; +drop function f; +drop user a@b; + +--echo # +--echo # MDEV-27893 SIGSEGV in replace_proxies_priv_table on GRANT PROXY +--echo # +rename table mysql.proxies_priv to mysql.proxies_priv_bak; +create table mysql.proxies_priv select * from mysql.proxies_priv_bak; +--error ER_CANNOT_LOAD_FROM_TABLE_V2 +grant proxy on grant_plug to grant_plug_dest; +drop table mysql.proxies_priv; +rename table mysql.proxies_priv_bak to mysql.proxies_priv; + +--echo # End of 10.11 tests diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9f1c4452ba9..49c4c01a7eb 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -883,10 +883,10 @@ class Grant_table_base A privilege column is of type enum('Y', 'N'). Privilege columns are expected to be one after another. */ - void set_table(TABLE *table) + bool set_table(TABLE *table) { if (!(m_table= table)) // Table does not exist or not opened. - return; + return 0; for (end_priv_columns= 0; end_priv_columns < num_fields(); end_priv_columns++) { @@ -900,8 +900,17 @@ class Grant_table_base else if (start_priv_columns) break; } + + if (!table->key_info || table->key_info->user_defined_key_parts != pk_parts) + { + my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(ME_ERROR_LOG), + table->s->db.str, table->s->table_name.str); + return 1; + } + return 0; } + virtual ~Grant_table_base() = default; /* the min number of columns a table should have */ uint min_columns; @@ -909,6 +918,8 @@ class Grant_table_base uint start_priv_columns; /* The index after the last privilege column */ uint end_priv_columns; + /* number of key_parts in PK */ + uint pk_parts; TABLE *m_table; }; @@ -1322,7 +1333,7 @@ class User_table_tabular: public User_table friend class Grant_tables; /* Only Grant_tables can instantiate this class. */ - User_table_tabular() { min_columns= 13; /* As in 3.20.13 */ } + User_table_tabular() { min_columns= 13; /* As in 3.20.13 */ pk_parts= 2; } /* The user table is a bit different compared to the other Grant tables. Usually, we only add columns to the grant tables when adding functionality. @@ -1733,6 +1744,7 @@ class User_table_json: public User_table int set_password_expired (bool x) const override { return x ? set_password_last_changed(0) : 0; } + User_table_json() { pk_parts= 2; } ~User_table_json() override = default; private: friend class Grant_tables; @@ -1877,7 +1889,7 @@ class Db_table: public Grant_table_base private: friend class Grant_tables; - Db_table() { min_columns= 9; /* as in 3.20.13 */ } + Db_table() { min_columns= 9; /* as in 3.20.13 */ pk_parts= 3; } }; class Tables_priv_table: public Grant_table_base @@ -1895,7 +1907,7 @@ class Tables_priv_table: public Grant_table_base private: friend class Grant_tables; - Tables_priv_table() { min_columns= 8; /* as in 3.22.26a */ } + Tables_priv_table() { min_columns= 8; /* as in 3.22.26a */ pk_parts= 4; } }; class Columns_priv_table: public Grant_table_base @@ -1912,7 +1924,7 @@ class Columns_priv_table: public Grant_table_base private: friend class Grant_tables; - Columns_priv_table() { min_columns= 7; /* as in 3.22.26a */ } + Columns_priv_table() { min_columns= 7; /* as in 3.22.26a */ pk_parts= 5; } }; class Host_table: public Grant_table_base @@ -1924,7 +1936,7 @@ class Host_table: public Grant_table_base private: friend class Grant_tables; - Host_table() { min_columns= 8; /* as in 3.20.13 */ } + Host_table() { min_columns= 8; /* as in 3.20.13 */ pk_parts= 2;} }; class Procs_priv_table: public Grant_table_base @@ -1942,7 +1954,7 @@ class Procs_priv_table: public Grant_table_base private: friend class Grant_tables; - Procs_priv_table() { min_columns=8; } + Procs_priv_table() { min_columns=8; pk_parts= 5; } }; class Proxies_priv_table: public Grant_table_base @@ -1959,7 +1971,7 @@ class Proxies_priv_table: public Grant_table_base private: friend class Grant_tables; - Proxies_priv_table() { min_columns= 7; } + Proxies_priv_table() { min_columns= 7; pk_parts= 4; } }; class Roles_mapping_table: public Grant_table_base @@ -1973,7 +1985,7 @@ class Roles_mapping_table: public Grant_table_base private: friend class Grant_tables; - Roles_mapping_table() { min_columns= 4; } + Roles_mapping_table() { min_columns= 4; pk_parts= 3; } }; /** @@ -2037,18 +2049,14 @@ class Grant_tables (USER_TABLE + 1) * sizeof *tables, MYF(MY_WME))); int res= -1; + uint counter; if (!tables) DBUG_RETURN(res); if (build_table_list(thd, &first, which_tables, lock_type, tables)) - { - func_exit: - my_free(tables); - DBUG_RETURN(res); - } + goto func_exit; - uint counter; res= really_open(thd, first, &counter); /* if User_table_json wasn't found, let's try User_table_tabular */ @@ -2077,23 +2085,30 @@ class Grant_tables if (res) goto func_exit; - if (lock_tables(thd, first, counter, - MYSQL_LOCK_IGNORE_TIMEOUT | + if (lock_tables(thd, first, counter, MYSQL_LOCK_IGNORE_TIMEOUT | MYSQL_OPEN_IGNORE_LOGGING_FORMAT)) { res= -1; + close_mysql_tables(thd); goto func_exit; } - p_user_table->set_table(tables[USER_TABLE].table); - m_db_table.set_table(tables[DB_TABLE].table); - m_tables_priv_table.set_table(tables[TABLES_PRIV_TABLE].table); - m_columns_priv_table.set_table(tables[COLUMNS_PRIV_TABLE].table); - m_host_table.set_table(tables[HOST_TABLE].table); - m_procs_priv_table.set_table(tables[PROCS_PRIV_TABLE].table); - m_proxies_priv_table.set_table(tables[PROXIES_PRIV_TABLE].table); - m_roles_mapping_table.set_table(tables[ROLES_MAPPING_TABLE].table); - goto func_exit; + if (p_user_table->set_table(tables[USER_TABLE].table) || + m_db_table.set_table(tables[DB_TABLE].table) || + m_tables_priv_table.set_table(tables[TABLES_PRIV_TABLE].table) || + m_columns_priv_table.set_table(tables[COLUMNS_PRIV_TABLE].table) || + m_host_table.set_table(tables[HOST_TABLE].table) || + m_procs_priv_table.set_table(tables[PROCS_PRIV_TABLE].table) || + m_proxies_priv_table.set_table(tables[PROXIES_PRIV_TABLE].table) || + m_roles_mapping_table.set_table(tables[ROLES_MAPPING_TABLE].table)) + { + res= -1; + close_mysql_tables(thd); + } + +func_exit: + my_free(tables); + DBUG_RETURN(res); } inline const User_table& user_table() const From b163b8f1c5607b25e7885490eebaf3150dcf0c71 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 30 Sep 2025 11:47:44 +0200 Subject: [PATCH 08/12] MDEV-28773 SIGSEGV in TABLE::use_all_columns, replace_roles_mapping_table as elsewhere, it a priv table doesn't exist - skip it only update in-memory structures --- mysql-test/main/grant_repair.result | 7 +++++++ mysql-test/main/grant_repair.test | 8 ++++++++ sql/sql_acl.cc | 6 +++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/grant_repair.result b/mysql-test/main/grant_repair.result index 02199fbed57..19f1829c7dd 100644 --- a/mysql-test/main/grant_repair.result +++ b/mysql-test/main/grant_repair.result @@ -80,4 +80,11 @@ grant proxy on grant_plug to grant_plug_dest; ERROR HY000: Cannot load from mysql.proxies_priv. The table is probably corrupted drop table mysql.proxies_priv; rename table mysql.proxies_priv_bak to mysql.proxies_priv; +# +# MDEV-28773 SIGSEGV in TABLE::use_all_columns, replace_roles_mapping_table +# +rename table mysql.roles_mapping to mysql.roles_mapping_bak; +create role r1; +drop role r1; +rename table mysql.roles_mapping_bak to mysql.roles_mapping; # End of 10.11 tests diff --git a/mysql-test/main/grant_repair.test b/mysql-test/main/grant_repair.test index de37ac607ea..25a5a92861c 100644 --- a/mysql-test/main/grant_repair.test +++ b/mysql-test/main/grant_repair.test @@ -96,4 +96,12 @@ grant proxy on grant_plug to grant_plug_dest; drop table mysql.proxies_priv; rename table mysql.proxies_priv_bak to mysql.proxies_priv; +--echo # +--echo # MDEV-28773 SIGSEGV in TABLE::use_all_columns, replace_roles_mapping_table +--echo # +rename table mysql.roles_mapping to mysql.roles_mapping_bak; +create role r1; +drop role r1; +rename table mysql.roles_mapping_bak to mysql.roles_mapping; + --echo # End of 10.11 tests diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 49c4c01a7eb..3f390d1f057 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -11261,11 +11261,11 @@ bool mysql_create_user(THD *thd, List &list, bool handle_as_role) /* TODO(cvicentiu) refactor replace_roles_mapping_table to use Roles_mapping_table instead of TABLE directly. */ - if (replace_roles_mapping_table(tables.roles_mapping_table().table(), + if (tables.roles_mapping_table().table_exists() && + replace_roles_mapping_table(tables.roles_mapping_table().table(), &thd->lex->definer->user, &thd->lex->definer->host, - &user_name->user, true, - NULL, false)) + &user_name->user, true, NULL, false)) { append_user(thd, &wrong_users, user_name); if (grantee) From 957ec8bba6ca616a6aeb5d53cdac9c17df938d4c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 30 Sep 2025 13:11:03 +0200 Subject: [PATCH 09/12] MDEV-35622 SEGV, ASAN use-after-poison when reading system table with less than expected number of columns validate mysql.servers structure --- mysql-test/main/grant_repair.result | 9 ++++ mysql-test/main/grant_repair.test | 10 +++++ sql/sql_servers.cc | 70 ++++++++++++++++++++++++++--- 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/grant_repair.result b/mysql-test/main/grant_repair.result index 19f1829c7dd..f3baa5143b0 100644 --- a/mysql-test/main/grant_repair.result +++ b/mysql-test/main/grant_repair.result @@ -87,4 +87,13 @@ rename table mysql.roles_mapping to mysql.roles_mapping_bak; create role r1; drop role r1; rename table mysql.roles_mapping_bak to mysql.roles_mapping; +# +# MDEV-35622 SEGV, ASAN use-after-poison when reading system table with less than expected number of columns +# +call mtr.add_suppression("mysql.servers"); +alter table mysql.servers drop column owner; +insert into mysql.servers values(0,0,0,0,0,0,0,0); +flush privileges; +ERROR HY000: Cannot load from mysql.servers. The table is probably corrupted +alter table mysql.servers add column Owner varchar(512) not null default ''; # End of 10.11 tests diff --git a/mysql-test/main/grant_repair.test b/mysql-test/main/grant_repair.test index 25a5a92861c..c20ec32b461 100644 --- a/mysql-test/main/grant_repair.test +++ b/mysql-test/main/grant_repair.test @@ -104,4 +104,14 @@ create role r1; drop role r1; rename table mysql.roles_mapping_bak to mysql.roles_mapping; +--echo # +--echo # MDEV-35622 SEGV, ASAN use-after-poison when reading system table with less than expected number of columns +--echo # +call mtr.add_suppression("mysql.servers"); +alter table mysql.servers drop column owner; +insert into mysql.servers values(0,0,0,0,0,0,0,0); +--error ER_CANNOT_LOAD_FROM_TABLE_V2 +flush privileges; +alter table mysql.servers add column Owner varchar(512) not null default ''; + --echo # End of 10.11 tests diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 0c492b32de9..57f5d2168e6 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -56,6 +56,60 @@ static MEM_ROOT mem; static mysql_rwlock_t THR_LOCK_servers; static LEX_CSTRING MYSQL_SERVERS_NAME= {STRING_WITH_LEN("servers") }; +static const TABLE_FIELD_TYPE servers_table_fields[] = +{ + { + { STRING_WITH_LEN("Server_name") }, + { STRING_WITH_LEN("char(") }, + { STRING_WITH_LEN("utf8mb") } + }, + { + { STRING_WITH_LEN("Host") }, + { STRING_WITH_LEN("varchar(") }, + { STRING_WITH_LEN("utf8mb") } + }, + { + { STRING_WITH_LEN("Db") }, + { STRING_WITH_LEN("char(") }, + { STRING_WITH_LEN("utf8mb") } + }, + { + { STRING_WITH_LEN("Username") }, + { STRING_WITH_LEN("char(") }, + { STRING_WITH_LEN("utf8mb") } + }, + { + { STRING_WITH_LEN("Password") }, + { STRING_WITH_LEN("char(") }, + { STRING_WITH_LEN("utf8mb") } + }, + { + { STRING_WITH_LEN("Port") }, + { STRING_WITH_LEN("int(") }, + {NULL, 0} + }, + { + { STRING_WITH_LEN("Socket") }, + { STRING_WITH_LEN("char(") }, + { STRING_WITH_LEN("utf8mb") } + }, + { + { STRING_WITH_LEN("Wrapper") }, + { STRING_WITH_LEN("char(") }, + { STRING_WITH_LEN("utf8mb") } + }, + { + { STRING_WITH_LEN("Owner") }, + { STRING_WITH_LEN("varchar(") }, + { STRING_WITH_LEN("utf8mb") } + } +}; +static const TABLE_FIELD_DEF servers_table_def= +{ + array_elements(servers_table_fields), servers_table_fields, 0, NULL +}; + +static Table_check_intact_log_error table_intact; static bool get_server_from_table_to_cache(TABLE *table); @@ -332,17 +386,16 @@ end: bool servers_reload(THD *thd) { - TABLE_LIST tables[1]; + TABLE_LIST tables; bool return_val= TRUE; DBUG_ENTER("servers_reload"); DBUG_PRINT("info", ("locking servers_cache")); mysql_rwlock_wrlock(&THR_LOCK_servers); - tables[0].init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_SERVERS_NAME, 0, TL_READ); + tables.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_SERVERS_NAME, 0, TL_READ); - if (unlikely(open_and_lock_tables(thd, tables, FALSE, - MYSQL_LOCK_IGNORE_TIMEOUT))) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { /* Execution might have been interrupted; only print the error message @@ -355,7 +408,14 @@ bool servers_reload(THD *thd) goto end; } - if ((return_val= servers_load(thd, tables))) + if (table_intact.check(tables.table, &servers_table_def)) + { + my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), + tables.db.str, tables.table_name.str); + goto end; + } + + if ((return_val= servers_load(thd, &tables))) { // Error. Revert to old list /* blast, for now, we have no servers, discuss later way to preserve */ From b6fd9f1e77d925d31298739a967893b8660aa0b8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 30 Sep 2025 13:50:10 +0200 Subject: [PATCH 10/12] MDEV-28482 SIGSEGV in get_access_value_from_val_int also check number of columns --- mysql-test/main/grant_repair.result | 9 +++++++++ mysql-test/main/grant_repair.test | 10 ++++++++++ sql/sql_acl.cc | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/grant_repair.result b/mysql-test/main/grant_repair.result index f3baa5143b0..84cf569ca5f 100644 --- a/mysql-test/main/grant_repair.result +++ b/mysql-test/main/grant_repair.result @@ -96,4 +96,13 @@ insert into mysql.servers values(0,0,0,0,0,0,0,0); flush privileges; ERROR HY000: Cannot load from mysql.servers. The table is probably corrupted alter table mysql.servers add column Owner varchar(512) not null default ''; +# +# MDEV-28482 SIGSEGV in get_access_value_from_val_int +# +create temporary table t1 select * from mysql.tables_priv; +alter table mysql.tables_priv drop column timestamp; +flush privileges; +ERROR HY000: Cannot load from mysql.tables_priv. The table is probably corrupted +alter table mysql.tables_priv add column Timestamp timestamp not null default now() on update now() after grantor; +replace mysql.tables_priv select * from t1; # End of 10.11 tests diff --git a/mysql-test/main/grant_repair.test b/mysql-test/main/grant_repair.test index c20ec32b461..70bef66485d 100644 --- a/mysql-test/main/grant_repair.test +++ b/mysql-test/main/grant_repair.test @@ -114,4 +114,14 @@ insert into mysql.servers values(0,0,0,0,0,0,0,0); flush privileges; alter table mysql.servers add column Owner varchar(512) not null default ''; +--echo # +--echo # MDEV-28482 SIGSEGV in get_access_value_from_val_int +--echo # +create temporary table t1 select * from mysql.tables_priv; +alter table mysql.tables_priv drop column timestamp; +--error ER_CANNOT_LOAD_FROM_TABLE_V2 +flush privileges; +alter table mysql.tables_priv add column Timestamp timestamp not null default now() on update now() after grantor; +replace mysql.tables_priv select * from t1; + --echo # End of 10.11 tests diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3f390d1f057..47b21433475 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -901,7 +901,8 @@ class Grant_table_base break; } - if (!table->key_info || table->key_info->user_defined_key_parts != pk_parts) + if (num_fields() < min_columns || !table->key_info || + table->key_info->user_defined_key_parts != pk_parts) { my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(ME_ERROR_LOG), table->s->db.str, table->s->table_name.str); From 4809bbdefb6d1bd66d025f7469f21bf5093a4cc1 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 1 Oct 2025 07:13:44 +1000 Subject: [PATCH 11/12] MDEV-37776: connect engine Debian packaging shouldn't depend explictly on libxml2 The dependency on libxml2 will be populated by its shlibs:Depends directive. Thanks Simon Chopin for pointing out the error of our ways. ref: https://bugs.launchpad.net/ubuntu/+source/libxml2/+bug/2125555 --- debian/control | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 9b2f8a0dbbb..5aee125a4dd 100644 --- a/debian/control +++ b/debian/control @@ -803,8 +803,7 @@ Description: Backup tool for MariaDB server Package: mariadb-plugin-connect Architecture: any -Depends: libxml2, - mariadb-server (= ${server:Version}), +Depends: mariadb-server (= ${server:Version}), unixodbc, ${misc:Depends}, ${shlibs:Depends} From db135822f635f549ad399bbe1e3b559c551db71c Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 18 Sep 2025 13:37:44 +1000 Subject: [PATCH 12/12] MDEV-37680/MDEV-24941: RHEL9+,Centos-stream and Fedora to pull mysql-selinux-1.0.14+ dependency mysql-selinux-1.0.14 provides the necessary labels for MariaDB to function correctly. Thanks Pavol Sloboda for the bug forwarding and a ready to package solution. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2395701 --- cmake/cpack_rpm.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index b116268dcc7..e2dad545315 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -322,6 +322,9 @@ IF(RPM MATCHES "fedora") ALTERNATIVE_NAME("shared" "mariadb-connector-c" ${MARIADB_CONNECTOR_C_VERSION}-1) ENDIF() +IF(RPM MATCHES "fedora|rhel|centos" AND NOT RPM MATCHES "rhel[78]") + SETA(CPACK_RPM_server_PACKAGE_REQUIRES "(mysql-selinux >= 1.0.14 if selinux-policy-targeted)") +ENDIF() SET(PYTHON_SHEBANG "/usr/bin/python3" CACHE STRING "python shebang") # If we want to build build MariaDB-shared-compat,