From da58c0c137a066ccdad682dacef4cb2c57331e86 Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 13 May 2026 17:04:01 +0300 Subject: [PATCH 01/29] Ensure that mtr.out-of-source is not acccidently calling itself Calling itself will cause extensive memory usage that can kill the machine when it runs out of memory (happend to me). Fixed by having mtr.out-of-source checking that it is not calling itself. In addition added a check for cmake to expand symlinks to make the check if we are running mtr 'out of source' safer. Author: Sergei Golubchik (CMakeList.txt changes) --- mysql-test/CMakeLists.txt | 5 +++++ mysql-test/mtr.out-of-source | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/mysql-test/CMakeLists.txt b/mysql-test/CMakeLists.txt index 07bc3c7088661..73fcfe8538f86 100644 --- a/mysql-test/CMakeLists.txt +++ b/mysql-test/CMakeLists.txt @@ -16,6 +16,11 @@ INSTALL_MYSQL_TEST("." "") +IF (NOT CMAKE_REAL_SOURCE_DIR) + get_filename_component(CMAKE_REAL_SOURCE_DIR "${CMAKE_SOURCE_DIR}" REALPATH) + get_filename_component(CMAKE_REAL_BINARY_DIR "${CMAKE_BINARY_DIR}" REALPATH) +ENDIF() + IF(NOT ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) # Enable running mtr from build directory CONFIGURE_FILE( diff --git a/mysql-test/mtr.out-of-source b/mysql-test/mtr.out-of-source index abab0be90df6c..dbaa521e2f50f 100644 --- a/mysql-test/mtr.out-of-source +++ b/mysql-test/mtr.out-of-source @@ -1,5 +1,14 @@ #!/usr/bin/env perl # Call mtr in out-of-source build + +use Cwd qw(cwd abs_path); $ENV{MTR_BINDIR} = '@CMAKE_BINARY_DIR@'; +my $dir= cwd(); +my $new_dir= abs_path('@CMAKE_SOURCE_DIR@'); +if ($dir eq $new_dir . '/mysql-test') +{ + print stderr "Something went wrong. Do 'git checkout mysql-test/mariadb-test-run.pl' and try again"; + exit 1; +} chdir('@CMAKE_SOURCE_DIR@/mysql-test'); exit(system($^X, '@CMAKE_SOURCE_DIR@/mysql-test/mariadb-test-run.pl', @ARGV) >> 8); From f0ae019e1a7d736500072ce62e6e107d0fb71062 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 18 May 2026 12:22:33 -0400 Subject: [PATCH 02/29] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7fa0a03e5b67e..d0ca98664bab0 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=6 -MYSQL_VERSION_PATCH=26 +MYSQL_VERSION_PATCH=27 SERVER_MATURITY=stable From 61d251c656e17da804ea71d811b07871b7c79c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 19 May 2026 08:27:29 +0300 Subject: [PATCH 03/29] MDEV-13542 fixup: Remove orphan trx_print() --- storage/innobase/include/trx0trx.h | 12 +----------- storage/innobase/trx/trx0trx.cc | 24 +----------------------- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index d79aafb1cedb1..61ecae6efc8f4 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -218,23 +218,13 @@ trx_print_low( /*!< in: mem_heap_get_size(trx->lock.lock_heap) */ /**********************************************************************//** -Prints info about a transaction. -When possible, use trx_print() instead. */ +Prints info about a transaction. */ void trx_print_latched( /*==============*/ FILE* f, /*!< in: output stream */ const trx_t* trx); /*!< in: transaction */ -/**********************************************************************//** -Prints info about a transaction. -Acquires and releases lock_sys.latch. */ -void -trx_print( -/*======*/ - FILE* f, /*!< in: output stream */ - const trx_t* trx); /*!< in: transaction */ - /**********************************************************************//** Determines if a transaction is in the given state. The caller must hold trx->mutex, or it must be the thread diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index fbd63376ede3f..2d2492600b5f9 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1836,8 +1836,7 @@ trx_print_low( /**********************************************************************//** Prints info about a transaction. -The caller must hold lock_sys.latch. -When possible, use trx_print() instead. */ +The caller must hold lock_sys.latch. */ void trx_print_latched( /*==============*/ @@ -1852,27 +1851,6 @@ trx_print_latched( mem_heap_get_size(trx->lock.lock_heap)); } -/**********************************************************************//** -Prints info about a transaction. -Acquires and releases lock_sys.latch. */ -TRANSACTIONAL_TARGET -void -trx_print( -/*======*/ - FILE* f, /*!< in: output stream */ - const trx_t* trx) /*!< in: transaction */ -{ - ulint n_rec_locks, n_trx_locks, heap_size; - { - TMLockMutexGuard g{SRW_LOCK_CALL}; - n_rec_locks= trx->lock.n_rec_locks; - n_trx_locks= UT_LIST_GET_LEN(trx->lock.trx_locks); - heap_size= mem_heap_get_size(trx->lock.lock_heap); - } - - trx_print_low(f, trx, n_rec_locks, n_trx_locks, heap_size); -} - /** Prepare a transaction. @return log sequence number that makes the XA PREPARE durable @retval 0 if no changes needed to be made durable */ From 13e6808f0138175ad48bf91b6487f56f33c51919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 20 May 2026 10:20:17 +0300 Subject: [PATCH 04/29] MDEV-39676 : Galera Cluster-peer > Donor command execution Add verification of wsrep_sst_donor, wsrep_sst_method and wsrep_sst_receive_address so that they contain only supported characters. But allow NULL or empty value. --- .../galera/r/galera_var_sst_donor.result | 30 ++++++++++ .../galera/r/galera_var_sst_method.result | 44 ++++++++++++++ .../r/galera_var_sst_receive_address.result | 17 ++++++ .../suite/galera/t/galera_var_sst_donor.test | 27 +++++++++ .../suite/galera/t/galera_var_sst_method.test | 36 ++++++++++++ .../t/galera_var_sst_receive_address.test | 26 +++++++++ .../sys_vars/r/wsrep_sst_donor_basic.result | 11 ++-- .../r/wsrep_sst_receive_address_basic.result | 19 +++---- .../sys_vars/t/wsrep_sst_donor_basic.test | 5 +- .../t/wsrep_sst_receive_address_basic.test | 9 ++- sql/wsrep_sst.cc | 57 +++++++++++++++---- 11 files changed, 247 insertions(+), 34 deletions(-) create mode 100644 mysql-test/suite/galera/r/galera_var_sst_donor.result create mode 100644 mysql-test/suite/galera/r/galera_var_sst_method.result create mode 100644 mysql-test/suite/galera/r/galera_var_sst_receive_address.result create mode 100644 mysql-test/suite/galera/t/galera_var_sst_donor.test create mode 100644 mysql-test/suite/galera/t/galera_var_sst_method.test create mode 100644 mysql-test/suite/galera/t/galera_var_sst_receive_address.test diff --git a/mysql-test/suite/galera/r/galera_var_sst_donor.result b/mysql-test/suite/galera/r/galera_var_sst_donor.result new file mode 100644 index 0000000000000..e9cb5d696c981 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_var_sst_donor.result @@ -0,0 +1,30 @@ +connection node_2; +connection node_1; +connection node_1; +SET @sst_donor_orig=@@GLOBAL.wsrep_sst_donor; +set global wsrep_sst_donor='127.0.0.1;'; +ERROR 42000: Variable 'wsrep_sst_donor' can't be set to the value of '127.0.0.1;' +select @@wsrep_sst_donor; +@@wsrep_sst_donor + +set global wsrep_sst_donor='node1\''; +ERROR 42000: Variable 'wsrep_sst_donor' can't be set to the value of 'node1'' +select @@wsrep_sst_donor; +@@wsrep_sst_donor + +set global wsrep_sst_donor='node_2&'; +ERROR 42000: Variable 'wsrep_sst_donor' can't be set to the value of 'node_2&' +select @@wsrep_sst_donor; +@@wsrep_sst_donor + +set global wsrep_sst_donor='127.0.0.1|'; +ERROR 42000: Variable 'wsrep_sst_donor' can't be set to the value of '127.0.0.1|' +select @@wsrep_sst_donor; +@@wsrep_sst_donor + +set global wsrep_sst_donor='node2'; +select @@wsrep_sst_donor; +@@wsrep_sst_donor +node2 +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/r/galera_var_sst_method.result b/mysql-test/suite/galera/r/galera_var_sst_method.result new file mode 100644 index 0000000000000..3cdd757544cf3 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_var_sst_method.result @@ -0,0 +1,44 @@ +connection node_2; +connection node_1; +connection node_1; +SET @sst_method_orig=@@GLOBAL.wsrep_sst_method; +set global wsrep_sst_method='mariabackup;'; +ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'mariabackup;' +select @@wsrep_sst_method; +@@wsrep_sst_method +rsync +set global wsrep_sst_method='mariabackup\''; +ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'mariabackup'' +select @@wsrep_sst_method; +@@wsrep_sst_method +rsync +set global wsrep_sst_method='mariabackup&'; +ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'mariabackup&' +select @@wsrep_sst_method; +@@wsrep_sst_method +rsync +set global wsrep_sst_method='mariabackup|'; +ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'mariabackup|' +select @@wsrep_sst_method; +@@wsrep_sst_method +rsync +set global wsrep_sst_method=NULL; +ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'NULL' +select @@wsrep_sst_method; +@@wsrep_sst_method +rsync +set global wsrep_sst_method=''; +ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of '' +select @@wsrep_sst_method; +@@wsrep_sst_method +rsync +set global wsrep_sst_method='mariabackup'; +select @@wsrep_sst_method; +@@wsrep_sst_method +mariabackup +set global wsrep_sst_method='rsync'; +select @@wsrep_sst_method; +@@wsrep_sst_method +rsync +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/r/galera_var_sst_receive_address.result b/mysql-test/suite/galera/r/galera_var_sst_receive_address.result new file mode 100644 index 0000000000000..3c20305b62827 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_var_sst_receive_address.result @@ -0,0 +1,17 @@ +connection node_2; +connection node_1; +connection node_1; +SET @sst_receive_address_orig=@@GLOBAL.wsrep_sst_receive_address; +set global wsrep_sst_receive_address='127.0.0.1;'; +ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1;' +set global wsrep_sst_receive_address='127.0.0.1\''; +ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1'' +set global wsrep_sst_receive_address='127.0.0.1&'; +ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1&' +set global wsrep_sst_receive_address='127.0.0.1|'; +ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1|' +set global wsrep_sst_receive_address=NULL; +set global wsrep_sst_receive_address=''; +set global wsrep_sst_receive_address='127.0.0.1:19000'; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/t/galera_var_sst_donor.test b/mysql-test/suite/galera/t/galera_var_sst_donor.test new file mode 100644 index 0000000000000..a83d68bf531da --- /dev/null +++ b/mysql-test/suite/galera/t/galera_var_sst_donor.test @@ -0,0 +1,27 @@ +# +# Check the handling of @@wsrep_sst_donor +# +--source include/galera_cluster.inc + +--connection node_1 +SET @sst_donor_orig=@@GLOBAL.wsrep_sst_donor; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_donor='127.0.0.1;'; +select @@wsrep_sst_donor; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_donor='node1\''; +select @@wsrep_sst_donor; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_donor='node_2&'; +select @@wsrep_sst_donor; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_donor='127.0.0.1|'; +select @@wsrep_sst_donor; +set global wsrep_sst_donor='node2'; +select @@wsrep_sst_donor; + +--disable_query_log +SET GLOBAL wsrep_sst_donor = @sst_donor_orig; +--enable_query_log + +--source include/galera_end.inc diff --git a/mysql-test/suite/galera/t/galera_var_sst_method.test b/mysql-test/suite/galera/t/galera_var_sst_method.test new file mode 100644 index 0000000000000..a0215ce37466e --- /dev/null +++ b/mysql-test/suite/galera/t/galera_var_sst_method.test @@ -0,0 +1,36 @@ +# +# Check the handling of @@wsrep_sst_method +# +--source include/galera_cluster.inc + +--connection node_1 +SET @sst_method_orig=@@GLOBAL.wsrep_sst_method; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_method='mariabackup;'; +select @@wsrep_sst_method; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_method='mariabackup\''; +select @@wsrep_sst_method; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_method='mariabackup&'; +select @@wsrep_sst_method; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_method='mariabackup|'; +select @@wsrep_sst_method; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_method=NULL; +select @@wsrep_sst_method; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_method=''; +select @@wsrep_sst_method; + +set global wsrep_sst_method='mariabackup'; +select @@wsrep_sst_method; +set global wsrep_sst_method='rsync'; +select @@wsrep_sst_method; + +--disable_query_log +SET GLOBAL wsrep_sst_method = @sst_method_orig; +--enable_query_log + +--source include/galera_end.inc diff --git a/mysql-test/suite/galera/t/galera_var_sst_receive_address.test b/mysql-test/suite/galera/t/galera_var_sst_receive_address.test new file mode 100644 index 0000000000000..aa97e86219e62 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_var_sst_receive_address.test @@ -0,0 +1,26 @@ +# +# Check the handling of @@wsrep_sst_receive_address +# + +--source include/galera_cluster.inc + +--connection node_1 +SET @sst_receive_address_orig=@@GLOBAL.wsrep_sst_receive_address; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_receive_address='127.0.0.1;'; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_receive_address='127.0.0.1\''; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_receive_address='127.0.0.1&'; +--error ER_WRONG_VALUE_FOR_VAR +set global wsrep_sst_receive_address='127.0.0.1|'; + +set global wsrep_sst_receive_address=NULL; +set global wsrep_sst_receive_address=''; +set global wsrep_sst_receive_address='127.0.0.1:19000'; + +--disable_query_log +SET GLOBAL wsrep_sst_receive_address = @sst_receive_address_orig; +--enable_query_log + +--source include/galera_end.inc diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result index dbe4cc23bf9ab..e3fbce72708ae 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result @@ -37,18 +37,17 @@ SET @@global.wsrep_sst_donor=''; SELECT @@global.wsrep_sst_donor; @@global.wsrep_sst_donor +SET @@global.wsrep_sst_donor=NULL; +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor +NULL # invalid values SET @@global.wsrep_sst_donor=1; ERROR 42000: Incorrect argument type to variable 'wsrep_sst_donor' SELECT @@global.wsrep_sst_donor; @@global.wsrep_sst_donor - -SET @@global.wsrep_sst_donor=NULL; -ERROR 42000: Variable 'wsrep_sst_donor' can't be set to the value of 'NULL' -SELECT @@global.wsrep_sst_donor; -@@global.wsrep_sst_donor - +NULL # restore the initial value SET @@global.wsrep_sst_donor = @wsrep_sst_donor_global_saved; diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result index 3e1fb6cad79de..2f3f1bc6e120e 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result @@ -28,16 +28,19 @@ SET @@global.wsrep_sst_receive_address='192.168.2.254'; SELECT @@global.wsrep_sst_receive_address; @@global.wsrep_sst_receive_address 192.168.2.254 - -# invalid values +SET @@global.wsrep_sst_receive_address=NULL; SELECT @@global.wsrep_sst_receive_address; @@global.wsrep_sst_receive_address -192.168.2.254 -SET @@global.wsrep_sst_receive_address=NULL; -ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of 'NULL' +NULL +SET @@global.wsrep_sst_receive_address=''; SELECT @@global.wsrep_sst_receive_address; @@global.wsrep_sst_receive_address -192.168.2.254 + + +# invalid values +SELECT @@global.wsrep_sst_receive_address; +@@global.wsrep_sst_receive_address + SET @@global.wsrep_sst_receive_address='OFF'; SELECT @@global.wsrep_sst_receive_address; @@global.wsrep_sst_receive_address @@ -46,10 +49,6 @@ SET @@global.wsrep_sst_receive_address=ON; SELECT @@global.wsrep_sst_receive_address; @@global.wsrep_sst_receive_address ON -SET @@global.wsrep_sst_receive_address=''; -SELECT @@global.wsrep_sst_receive_address; -@@global.wsrep_sst_receive_address - SET @@global.wsrep_sst_receive_address='junk'; SELECT @@global.wsrep_sst_receive_address; @@global.wsrep_sst_receive_address diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test index c4b32bb8af6ab..2824f56ca055a 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test @@ -29,15 +29,14 @@ SET @@global.wsrep_sst_donor=default; SELECT @@global.wsrep_sst_donor; SET @@global.wsrep_sst_donor=''; SELECT @@global.wsrep_sst_donor; +SET @@global.wsrep_sst_donor=NULL; +SELECT @@global.wsrep_sst_donor; --echo --echo # invalid values --error ER_WRONG_TYPE_FOR_VAR SET @@global.wsrep_sst_donor=1; SELECT @@global.wsrep_sst_donor; ---error ER_WRONG_VALUE_FOR_VAR -SET @@global.wsrep_sst_donor=NULL; -SELECT @@global.wsrep_sst_donor; --echo --echo # restore the initial value diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test index 59f69c14dfb87..f65ddee3ca85a 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test @@ -24,21 +24,20 @@ SET @@global.wsrep_sst_receive_address=default; SELECT @@global.wsrep_sst_receive_address; SET @@global.wsrep_sst_receive_address='192.168.2.254'; SELECT @@global.wsrep_sst_receive_address; +SET @@global.wsrep_sst_receive_address=NULL; +SELECT @@global.wsrep_sst_receive_address; +SET @@global.wsrep_sst_receive_address=''; +SELECT @@global.wsrep_sst_receive_address; --echo --echo # invalid values SELECT @@global.wsrep_sst_receive_address; ---error ER_WRONG_VALUE_FOR_VAR -SET @@global.wsrep_sst_receive_address=NULL; -SELECT @@global.wsrep_sst_receive_address; # Currently there is no strict checking performed for wsrep_sst_receive_address # so following values jusr pass through. SET @@global.wsrep_sst_receive_address='OFF'; SELECT @@global.wsrep_sst_receive_address; SET @@global.wsrep_sst_receive_address=ON; SELECT @@global.wsrep_sst_receive_address; -SET @@global.wsrep_sst_receive_address=''; -SELECT @@global.wsrep_sst_receive_address; SET @@global.wsrep_sst_receive_address='junk'; SELECT @@global.wsrep_sst_receive_address; diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 1c449c431e3ea..e71dfdbf0a8a1 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -1,5 +1,5 @@ -/* Copyright 2008-2022 Codership Oy - Copyright (c) 2008, 2022, MariaDB +/* Copyright (C) 2008, 2025 Codership Oy + Copyright (c) 2008, 2026, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -178,6 +178,12 @@ static bool filename_char(int const c) return isalnum(c) || (c == '-') || (c == '_') || (c == '.'); } +/* return true if string is comma seprated list */ +static bool comma_char(int const c) +{ + return (c == ','); +} + /* return true if character can be a part of an address string */ static bool address_char(int const c) { @@ -185,6 +191,12 @@ static bool address_char(int const c) (c == ':') || (c == '[') || (c == ']') || (c == '/'); } +/* return true if character can be a part of an address string list */ +static bool names_list(int const c) +{ + return address_char(c) || comma_char(c); +} + static bool check_request_str(const char* const str, bool (*check) (int c), bool log_warn = true) @@ -256,8 +268,19 @@ static void make_wsrep_defaults_file() bool wsrep_sst_receive_address_check (sys_var *self, THD* thd, set_var* var) { - if ((! var->save_result.string_value.str) || - (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + /* Allow empty value */ + if (!var->save_result.string_value.str || var->save_result.string_value.length == 0) + return 0; + + /* Check length */ + if ((var->save_result.string_value.length > (FN_REFLEN - 1))) // safety + { + goto err; + } + + /* check also that address contains only accepted characters */ + if (check_request_str(var->save_result.string_value.str, + address_char, false)) { goto err; } @@ -339,16 +362,30 @@ void wsrep_sst_auth_init () bool wsrep_sst_donor_check (sys_var *self, THD* thd, set_var* var) { - if ((! var->save_result.string_value.str) || - (var->save_result.string_value.length > (FN_REFLEN -1))) // safety + /* Allow empty value */ + if (!var->save_result.string_value.str || var->save_result.string_value.length == 0) + return 0; + + /* Check length */ + if ((var->save_result.string_value.length > (FN_REFLEN -1))) // safety { - my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, - var->save_result.string_value.str ? - var->save_result.string_value.str : "NULL"); - return 1; + goto err; + } + + /* check also that donor string contains only accepted characters */ + if (check_request_str(var->save_result.string_value.str, + names_list, false)) + { + goto err; } return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, + var->save_result.string_value.str ? + var->save_result.string_value.str : "NULL"); + return 1; } bool wsrep_sst_donor_update (sys_var *self, THD* thd, enum_var_type type) From 03e040ea90d75be093d1932232b4392dddd2fe34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 20 May 2026 10:25:50 +0300 Subject: [PATCH 05/29] Fix test failure on galera_sst_mariabackup_encrypt_with_key_server Joiner mariadbd exits when SST is aborted; the exit code varies by platform (clean 0 on some systems, signalled 134 / 1 on others). pkill exit code can also vary by platform (clean 0 on some systems, signalled 1 others). --- .../t/galera_sst_mariabackup_encrypt_with_key_server.test | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_encrypt_with_key_server.test b/mysql-test/suite/galera/t/galera_sst_mariabackup_encrypt_with_key_server.test index 238158a2dc0e3..0418be4d797a0 100644 --- a/mysql-test/suite/galera/t/galera_sst_mariabackup_encrypt_with_key_server.test +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_encrypt_with_key_server.test @@ -45,7 +45,9 @@ call mtr.add_suppression('Removing .*/xtrabackup_galera_info file due to signal' --exec echo ssl-key=$MYSQL_TEST_DIR/std_data/server-new-key.pem >> $MYSQLTEST_VARDIR/my.cnf --echo # start the server ---error 0 +# Joiner mariadbd exits when SST is aborted; the exit code varies by +# platform (clean 0 on some systems, signalled 134 / 1 on others). +--error 0,134,1 --exec $MYSQLD_LAST_CMD --echo # the server failed to start @@ -55,6 +57,8 @@ call mtr.add_suppression('Removing .*/xtrabackup_galera_info file due to signal' --echo # cleanup # we have to kill joiner's socat here, because the donor has aborted SST # and joiner's socat will timeout in 5 minutes +# pkill exit code varies by platform 0 or 1 +--error 0,1 --exec pkill -f 'socat.*server-new-cert' --exec echo ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert.pem >> $MYSQLTEST_VARDIR/my.cnf --exec echo ssl-key=$MYSQL_TEST_DIR/std_data/server-key.pem >> $MYSQLTEST_VARDIR/my.cnf From 3a3c1e403ba6b94a98d40425bb50a17d7cf6edc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 20 May 2026 10:27:40 +0300 Subject: [PATCH 06/29] Prepare for Galera library version 26.4.27 --- mysql-test/suite/wsrep/r/wsrep_protocol_versions.result | 2 +- mysql-test/suite/wsrep/t/variables.test | 2 +- mysql-test/suite/wsrep/t/variables_debug.test | 2 +- mysql-test/suite/wsrep/t/wsrep_protocol_versions.test | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/wsrep/r/wsrep_protocol_versions.result b/mysql-test/suite/wsrep/r/wsrep_protocol_versions.result index 35139f5b9cf35..0d2759aaa8949 100644 --- a/mysql-test/suite/wsrep/r/wsrep_protocol_versions.result +++ b/mysql-test/suite/wsrep/r/wsrep_protocol_versions.result @@ -2,6 +2,6 @@ show status like 'wsrep_protocol%'; Variable_name Value wsrep_protocol_application 4 -wsrep_protocol_gcs 5 +wsrep_protocol_gcs 6 wsrep_protocol_replicator 11 wsrep_protocol_version 11 diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index c82d0ae02c2ff..1b5cf30b6de09 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -3,7 +3,7 @@ --source include/have_innodb.inc --source include/galera_no_debug_sync.inc ---let $galera_version=26.4.23 +--let $galera_version=26.4.27 source include/check_galera_version.inc; source include/galera_variables_ok.inc; diff --git a/mysql-test/suite/wsrep/t/variables_debug.test b/mysql-test/suite/wsrep/t/variables_debug.test index e50cee28a1592..abae2e15b8350 100644 --- a/mysql-test/suite/wsrep/t/variables_debug.test +++ b/mysql-test/suite/wsrep/t/variables_debug.test @@ -5,7 +5,7 @@ --source include/have_debug_sync.inc --source include/galera_have_debug_sync.inc ---let $galera_version=26.4.23 +--let $galera_version=26.4.27 source include/check_galera_version.inc; source include/galera_variables_ok_debug.inc; diff --git a/mysql-test/suite/wsrep/t/wsrep_protocol_versions.test b/mysql-test/suite/wsrep/t/wsrep_protocol_versions.test index f8979050686f1..860ab1905201b 100644 --- a/mysql-test/suite/wsrep/t/wsrep_protocol_versions.test +++ b/mysql-test/suite/wsrep/t/wsrep_protocol_versions.test @@ -2,7 +2,7 @@ --source include/force_restart.inc --source include/have_innodb.inc ---let $galera_version=26.4.21 +--let $galera_version=26.4.27 source include/check_galera_version.inc; --sorted_result From 1648170c5c33cf39dec34d92c653551c4fdd6f9b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 11 May 2026 22:06:51 +0200 Subject: [PATCH 07/29] MDEV-39565 missing filename check in mariadb-backup --decompress check for tablename-safe characters in backed up table files --- extra/mariabackup/backup_copy.cc | 8 ++++++++ mysql-test/suite/mariabackup/options_check.result | 9 +++++++++ mysql-test/suite/mariabackup/options_check.test | 13 +++++++++++++ 3 files changed, 30 insertions(+) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index 38b9618335749..ba26694f42885 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -2117,6 +2117,14 @@ decrypt_decompress_file(const char *filepath, uint thread_n) msg(thread_n,"%s\n", message.str().c_str()); + /* all valid *.qp files are table-name-safe */ + for (const char *s=filepath; *s; s++) + if (!isalnum(*s) && !strchr("-.@/_#", *s)) + { + msg(thread_n,"Error: invalid file name\n"); + return(false); + } + if (system(cmd.str().c_str()) != 0) { return(false); } diff --git a/mysql-test/suite/mariabackup/options_check.result b/mysql-test/suite/mariabackup/options_check.result index 59666754f04af..71ccf29dcaa5a 100644 --- a/mysql-test/suite/mariabackup/options_check.result +++ b/mysql-test/suite/mariabackup/options_check.result @@ -6,3 +6,12 @@ # Check if uknown options that follow --mysqld-args are ingored # Check if [mariadb-client] group is not loaded (MDEV-22894) # Check if --help presents +# +# MDEV-39565 missing filename check in mariadb-backup --decompress +# +[##] ####-##-## ##:##:## decompressing ./a;touch b.qp + +[##] ####-##-## ##:##:## Error: invalid file name + +[##] ####-##-## ##:##:## Error: thread # failed. +# End of 10.6 tests diff --git a/mysql-test/suite/mariabackup/options_check.test b/mysql-test/suite/mariabackup/options_check.test index 022bcbd5d1017..b6c45c01a7a57 100644 --- a/mysql-test/suite/mariabackup/options_check.test +++ b/mysql-test/suite/mariabackup/options_check.test @@ -67,3 +67,16 @@ exec $XTRABACKUP --help; exec $XTRABACKUP -?; --enable_result_log +--echo # +--echo # MDEV-39565 missing filename check in mariadb-backup --decompress +--echo # +--write_file "$MYSQL_TMP_DIR/a;touch b.qp" +foo +EOF + +--replace_regex /.*based.*\n// /\d/#/ /[\\]/\// +--error 1 +exec $XTRABACKUP --decompress --target-dir=$MYSQL_TMP_DIR 2>&1; +--list_files $MYSQL_TMP_DIR b.qp + +--echo # End of 10.6 tests From c5409caab0430c6ec93afa881418d681e00543c9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 11 May 2026 16:43:34 +0200 Subject: [PATCH 08/29] MDEV-39564 One-byte OOB write in PROXY protocol v1 header parser --- sql/proxy_protocol.cc | 2 +- tests/mysql_client_test.c | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/sql/proxy_protocol.cc b/sql/proxy_protocol.cc index 689d1af88f04e..bb8e3ccb64260 100644 --- a/sql/proxy_protocol.cc +++ b/sql/proxy_protocol.cc @@ -195,7 +195,7 @@ int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info) if (have_v1_header) { /* Read until end of header (newline character)*/ - while(pos < sizeof(hdr)) + while(pos < sizeof(hdr)-1) { long len= (long)vio_read(vio, hdr + pos, 1); if (len < 0) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 21496294ce126..97a7d270de3c8 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -20568,12 +20568,12 @@ static void test_proxy_header_tcp(const char *ipaddr, int port) MYSQL_RES *result; int family = (strchr(ipaddr,':') == NULL)?AF_INET:AF_INET6; char query[256]; - char text_header[256]; + char text_header[256], bad_text_header[256]; char addr_bin[16]; v2_proxy_header v2_header; - void *header_data[2]; - size_t header_lengths[2]; - int i; + void *header_data[3]; + size_t header_lengths[3]; + size_t i; // normalize IPv4-mapped IPv6 addresses, e.g ::ffff:127.0.0.2 to 127.0.0.2 const char *normalized_addr= strncmp(ipaddr, "::ffff:", 7)?ipaddr : ipaddr + 7; @@ -20611,9 +20611,13 @@ static void test_proxy_header_tcp(const char *ipaddr, int port) header_data[0]= text_header; header_data[1]= &v2_header; + header_data[2]= bad_text_header; header_lengths[0]= strlen(text_header); header_lengths[1]= family == AF_INET ? 28 : 52; + header_lengths[2]= sizeof(text_header)-4; + memset(bad_text_header, ' ', sizeof(bad_text_header)); + memcpy(bad_text_header, text_header, header_lengths[1]-6); for (i = 0; i < 2; i++) { @@ -20624,9 +20628,8 @@ static void test_proxy_header_tcp(const char *ipaddr, int port) DIE_UNLESS(m); mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, header_data[i], header_lengths[i]); if (!mysql_real_connect(m, opt_host, "u", "password", NULL, opt_port, opt_unix_socket, 0)) - { - DIE_UNLESS(0); - } + DIE(0); + rc= mysql_query(m, "select host from information_schema.processlist WHERE ID = connection_id()"); myquery(rc); /* get the result */ @@ -20643,6 +20646,20 @@ static void test_proxy_header_tcp(const char *ipaddr, int port) /* do "dirty" close, to get aborted message in error log.*/ mariadb_cancel(m); } + + mysql_close(m); + } + for (; i < array_elements(header_data); i++) + { + MYSQL *m; + m = mysql_client_init(NULL); + DIE_UNLESS(m); + mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, header_data[i], header_lengths[i]); + if (mysql_real_connect(m, opt_host, "u", "password", NULL, opt_port, opt_unix_socket, 0)) + DIE(0); + printf("pass %zu error %i - %s\n", i, mysql_errno(m), + mysql_error(m)); + DIE_IF(i == 2 && mysql_errno(m) != ER_UNKNOWN_ERROR); mysql_close(m); } sprintf(query,"DROP USER 'u'@'%s'",normalized_addr); From 31319c7bc618f669e34d5de1823142df4ec67e33 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 12 May 2026 13:16:57 +0200 Subject: [PATCH 09/29] proxy protocol v2: fix a harmless typo according to the rfc, the length is 2 bytes, but the max length is 226 and there's a validity check for length <= 240. --- sql/proxy_protocol.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/proxy_protocol.cc b/sql/proxy_protocol.cc index bb8e3ccb64260..05826b9e12318 100644 --- a/sql/proxy_protocol.cc +++ b/sql/proxy_protocol.cc @@ -217,7 +217,7 @@ int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info) if (len < 0) return -1; // 2 last bytes are the length in network byte order of the part following header - ushort trail_len= ((ushort)hdr[PROXY_V2_HEADER_LEN-2] >> 8) + hdr[PROXY_V2_HEADER_LEN-1]; + ushort trail_len= ((ushort)hdr[PROXY_V2_HEADER_LEN-2] << 8) + hdr[PROXY_V2_HEADER_LEN-1]; if (trail_len > sizeof(hdr) - PROXY_V2_HEADER_LEN) return -1; if (trail_len > 0) From 05663d1910dbbf5d63270812216326694511e73f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 12 May 2026 17:06:43 +0200 Subject: [PATCH 10/29] MDEV-39576 PROXY v2 protocol uninitialized memory reads --- sql/proxy_protocol.cc | 4 ++++ tests/mysql_client_test.c | 13 ++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/sql/proxy_protocol.cc b/sql/proxy_protocol.cc index 05826b9e12318..9e0ed7bc0ee3f 100644 --- a/sql/proxy_protocol.cc +++ b/sql/proxy_protocol.cc @@ -129,11 +129,15 @@ static int parse_v2_header(uchar *hdr, size_t len,proxy_peer_info *peer_info) switch (fam) { case 0x11: /* TCPv4 */ + if (len < 25) + return -1; sin->sin_family= AF_INET; memcpy(&(sin->sin_addr), hdr + 16, 4); peer_info->port= (hdr[24] << 8) + hdr[25]; break; case 0x21: /* TCPv6 */ + if (len < 49) + return -1; sin6->sin6_family= AF_INET6; memcpy(&(sin6->sin6_addr), hdr + 16, 16); peer_info->port= (hdr[48] << 8) + hdr[49]; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 97a7d270de3c8..d4eacd3e3cc0e 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -20570,9 +20570,9 @@ static void test_proxy_header_tcp(const char *ipaddr, int port) char query[256]; char text_header[256], bad_text_header[256]; char addr_bin[16]; - v2_proxy_header v2_header; - void *header_data[3]; - size_t header_lengths[3]; + v2_proxy_header v2_header, bad_v2_header; + void *header_data[4]; + size_t header_lengths[4]; size_t i; // normalize IPv4-mapped IPv6 addresses, e.g ::ffff:127.0.0.2 to 127.0.0.2 @@ -20612,13 +20612,19 @@ static void test_proxy_header_tcp(const char *ipaddr, int port) header_data[0]= text_header; header_data[1]= &v2_header; header_data[2]= bad_text_header; + header_data[3]= &bad_v2_header; header_lengths[0]= strlen(text_header); header_lengths[1]= family == AF_INET ? 28 : 52; header_lengths[2]= sizeof(text_header)-4; + header_lengths[3]= header_lengths[1]; + memset(bad_text_header, ' ', sizeof(bad_text_header)); memcpy(bad_text_header, text_header, header_lengths[1]-6); + bad_v2_header= v2_header; + bad_v2_header.len= 0; + for (i = 0; i < 2; i++) { MYSQL *m; @@ -20660,6 +20666,7 @@ static void test_proxy_header_tcp(const char *ipaddr, int port) printf("pass %zu error %i - %s\n", i, mysql_errno(m), mysql_error(m)); DIE_IF(i == 2 && mysql_errno(m) != ER_UNKNOWN_ERROR); + DIE_IF(i == 3 && mysql_errno(m) != ER_UNKNOWN_ERROR); mysql_close(m); } sprintf(query,"DROP USER 'u'@'%s'",normalized_addr); From 9a3e15318816616bbdbc2b83a8f7171fa4fd42f8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 12 May 2026 19:00:09 +0200 Subject: [PATCH 11/29] MDEV-39581 dynamic column header missing sanity checks --- mysql-test/main/dyncol.result | 7 +++++++ mysql-test/main/dyncol.test | 10 ++++++++++ mysys/ma_dyncol.c | 10 +++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/dyncol.result b/mysql-test/main/dyncol.result index 7b09a5efa851f..24b98b2b31570 100644 --- a/mysql-test/main/dyncol.result +++ b/mysql-test/main/dyncol.result @@ -1979,4 +1979,11 @@ drop table t1; # SELECT COLUMN_JSON(1000); ERROR HY000: Encountered illegal format of dynamic column string +# +# MDEV-39581 dynamic column header missing sanity checks +# +SELECT COLUMN_LIST(0x040100FFFF00000300666F6F21626172); +ERROR HY000: Encountered illegal format of dynamic column string +SELECT COLUMN_JSON(CONCAT(0x040200020001000000000000004241, REPEAT('D', 512))); +ERROR HY000: Encountered illegal format of dynamic column string # End of 10.6 tests diff --git a/mysql-test/main/dyncol.test b/mysql-test/main/dyncol.test index 7f38c82f5fbcc..9ee276f4bef82 100644 --- a/mysql-test/main/dyncol.test +++ b/mysql-test/main/dyncol.test @@ -1033,4 +1033,14 @@ drop table t1; --error ER_DYN_COL_WRONG_FORMAT SELECT COLUMN_JSON(1000); + +--echo # +--echo # MDEV-39581 dynamic column header missing sanity checks +--echo # +--error ER_DYN_COL_WRONG_FORMAT +SELECT COLUMN_LIST(0x040100FFFF00000300666F6F21626172); + +--error ER_DYN_COL_WRONG_FORMAT +SELECT COLUMN_JSON(CONCAT(0x040200020001000000000000004241, REPEAT('D', 512))); + --echo # End of 10.6 tests diff --git a/mysys/ma_dyncol.c b/mysys/ma_dyncol.c index 60aaffba2278a..e0107a5601a18 100644 --- a/mysys/ma_dyncol.c +++ b/mysys/ma_dyncol.c @@ -658,6 +658,7 @@ static struct st_service_funcs fmt_data[2]= static enum enum_dyncol_func_result init_read_hdr(DYN_HEADER *hdr, DYNAMIC_COLUMN *str) { + size_t nodata_size; if (read_fixed_header(hdr, str)) return ER_DYNCOL_FORMAT; hdr->header= (uchar*)str->str + fmt_data[hdr->format].fixed_hdr; @@ -666,8 +667,11 @@ init_read_hdr(DYN_HEADER *hdr, DYNAMIC_COLUMN *str) hdr->column_count); hdr->nmpool= hdr->header + hdr->header_size; hdr->dtpool= hdr->nmpool + hdr->nmpool_size; - hdr->data_size= str->length - fmt_data[hdr->format].fixed_hdr - - hdr->header_size - hdr->nmpool_size; + nodata_size= fmt_data[hdr->format].fixed_hdr + hdr->header_size + + hdr->nmpool_size; + if (str->length < nodata_size) + return ER_DYNCOL_FORMAT; + hdr->data_size= str->length - nodata_size; hdr->data_end= (uchar*)str->str + str->length; return ER_DYNCOL_OK; } @@ -2018,7 +2022,7 @@ static my_bool read_name(DYN_HEADER *hdr, uchar *entry, LEX_STRING *name) else { size_t next_nmoffset= uint2korr(next_entry); - if (next_nmoffset > hdr->nmpool_size) + if (next_nmoffset > hdr->nmpool_size || next_nmoffset < nmoffset) return 1; name->length= next_nmoffset - nmoffset; } From 11c41cd93d2c3732862ba043afd18508021440c0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 15 May 2026 13:34:46 +0200 Subject: [PATCH 12/29] MDEV-39622 OBJECT_INSTANCE_BEGIN in P_S are unstable, difficult to compare let's show stable values that don't change between runs --- storage/perfschema/table_events_waits.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/storage/perfschema/table_events_waits.cc b/storage/perfschema/table_events_waits.cc index 59b99dabc0f37..dbfe98e105de4 100644 --- a/storage/perfschema/table_events_waits.cc +++ b/storage/perfschema/table_events_waits.cc @@ -39,6 +39,8 @@ THR_LOCK table_events_waits_current::m_table_lock; +#define OBJECT_INSTANCE_BEGIN(X) (((intptr)X) - ((intptr) &pfs_truncatable_acl)) + PFS_engine_table_share_state table_events_waits_current::m_share_state = { false /* m_checked */ @@ -251,7 +253,7 @@ int table_events_waits_common::make_table_object_columns(PFS_events_waits *wait) m_row.m_index_name_length= 0; } - m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + m_row.m_object_instance_addr= OBJECT_INSTANCE_BEGIN(wait->m_object_instance_addr); return 0; } @@ -266,7 +268,7 @@ int table_events_waits_common::make_file_object_columns(PFS_events_waits *wait) m_row.m_object_type= "FILE"; m_row.m_object_type_length= 4; m_row.m_object_schema_length= 0; - m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + m_row.m_object_instance_addr= OBJECT_INSTANCE_BEGIN(wait->m_object_instance_addr); if (safe_file->get_version() == wait->m_weak_version) { @@ -298,7 +300,7 @@ int table_events_waits_common::make_socket_object_columns(PFS_events_waits *wait m_row.m_object_type= "SOCKET"; m_row.m_object_type_length= 6; m_row.m_object_schema_length= 0; - m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + m_row.m_object_instance_addr= OBJECT_INSTANCE_BEGIN(wait->m_object_instance_addr); if (safe_socket->get_version() == wait->m_weak_version) { @@ -432,7 +434,7 @@ int table_events_waits_common::make_metadata_lock_object_columns(PFS_events_wait if (m_row.m_object_name_length > 0) memcpy(m_row.m_object_name, mdl->name(), m_row.m_object_name_length); - m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + m_row.m_object_instance_addr= OBJECT_INSTANCE_BEGIN(wait->m_object_instance_addr); } else { @@ -498,17 +500,17 @@ void table_events_waits_common::make_row(PFS_events_waits *wait) break; case WAIT_CLASS_MUTEX: clear_object_columns(); - m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + m_row.m_object_instance_addr= OBJECT_INSTANCE_BEGIN(wait->m_object_instance_addr); safe_class= sanitize_mutex_class((PFS_mutex_class*) wait->m_class); break; case WAIT_CLASS_RWLOCK: clear_object_columns(); - m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + m_row.m_object_instance_addr= OBJECT_INSTANCE_BEGIN(wait->m_object_instance_addr); safe_class= sanitize_rwlock_class((PFS_rwlock_class*) wait->m_class); break; case WAIT_CLASS_COND: clear_object_columns(); - m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + m_row.m_object_instance_addr= OBJECT_INSTANCE_BEGIN(wait->m_object_instance_addr); safe_class= sanitize_cond_class((PFS_cond_class*) wait->m_class); break; case WAIT_CLASS_TABLE: From 32ab8a2d4c0fd04e89713f63f04c6cf40248b63d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 May 2026 18:33:06 +0200 Subject: [PATCH 13/29] MDEV-39657 ASAN error on malformed WKB point check data length for Gis_point --- mysql-test/main/gis.result | 6 ++++++ mysql-test/main/gis.test | 5 +++++ sql/spatial.cc | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/gis.result b/mysql-test/main/gis.result index 6c782eb671f44..6a69811e93f69 100644 --- a/mysql-test/main/gis.result +++ b/mysql-test/main/gis.result @@ -5595,4 +5595,10 @@ mp SELECT ST_GeomFromWKB(x'01070000000100000001070000000100000001070000000100000001020000000100000000000000') IS NOT NULL AS gc; gc 0 +# +# MDEV-39657 ASAN error on malformed WKB point +# +SELECT HEX(ST_GeometryN(0x000000000107000000010000000101000000, 1)); +HEX(ST_GeometryN(0x000000000107000000010000000101000000, 1)) +NULL # End of 10.6 tests diff --git a/mysql-test/main/gis.test b/mysql-test/main/gis.test index 1c8fe1a2c492f..3a068d7eb2636 100644 --- a/mysql-test/main/gis.test +++ b/mysql-test/main/gis.test @@ -3568,4 +3568,9 @@ SELECT ST_GeomFromWKB(x'01050000000200000001020000000200000000000000000000000000 SELECT ST_GeomFromWKB(x'01060000000100000001030000000100000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000') IS NOT NULL AS mp; SELECT ST_GeomFromWKB(x'01070000000100000001070000000100000001070000000100000001020000000100000000000000') IS NOT NULL AS gc; +--echo # +--echo # MDEV-39657 ASAN error on malformed WKB point +--echo # +SELECT HEX(ST_GeometryN(0x000000000107000000010000000101000000, 1)); + --echo # End of 10.6 tests diff --git a/sql/spatial.cc b/sql/spatial.cc index e23ed1ab7b4ff..25c7955bcb8d9 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -913,7 +913,7 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, uint32 Gis_point::get_data_size() const { - return POINT_DATA_SIZE; + return no_data(m_data, POINT_DATA_SIZE) ? GET_SIZE_ERROR : POINT_DATA_SIZE; } From 52bbe5b6e7fe274f0c4738685326283c0d65944d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 May 2026 18:36:30 +0200 Subject: [PATCH 14/29] MDEV-39658 ASAN crash on invalid proxy_protocol_networks value max_subnet estimate was off by one. * only allow address with a known family (trips an assert in addr_matches_subnet()) * adjust max_subnet estimate accordinly --- .../sys_vars/r/proxy_protocol_networks_grant.result | 9 ++++++--- .../sys_vars/t/proxy_protocol_networks_grant.test | 10 +++++++--- sql/proxy_protocol.cc | 4 +++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/proxy_protocol_networks_grant.result b/mysql-test/suite/sys_vars/r/proxy_protocol_networks_grant.result index b6bae2724430a..4d663628c91e9 100644 --- a/mysql-test/suite/sys_vars/r/proxy_protocol_networks_grant.result +++ b/mysql-test/suite/sys_vars/r/proxy_protocol_networks_grant.result @@ -7,7 +7,6 @@ CREATE USER user1@localhost; GRANT ALL PRIVILEGES ON *.* TO user1@localhost; REVOKE CONNECTION ADMIN, SUPER ON *.* FROM user1@localhost; connect user1,localhost,user1,,; -connection user1; SET GLOBAL proxy_protocol_networks=""; ERROR 42000: Access denied; you need (at least one of) the SUPER, CONNECTION ADMIN privilege(s) for this operation SET proxy_protocol_networks=""; @@ -21,7 +20,6 @@ DROP USER user1@localhost; CREATE USER user1@localhost; GRANT CONNECTION ADMIN ON *.* TO user1@localhost; connect user1,localhost,user1,,; -connection user1; SET GLOBAL proxy_protocol_networks=""; SET proxy_protocol_networks=""; ERROR HY000: Variable 'proxy_protocol_networks' is a GLOBAL variable and should be set with SET GLOBAL @@ -34,7 +32,6 @@ DROP USER user1@localhost; CREATE USER user1@localhost; GRANT SUPER ON *.* TO user1@localhost; connect user1,localhost,user1,,; -connection user1; SET GLOBAL proxy_protocol_networks=""; SET proxy_protocol_networks=""; ERROR HY000: Variable 'proxy_protocol_networks' is a GLOBAL variable and should be set with SET GLOBAL @@ -43,4 +40,10 @@ ERROR HY000: Variable 'proxy_protocol_networks' is a GLOBAL variable and should disconnect user1; connection default; DROP USER user1@localhost; +# +# MDEV-39658 ASAN crash on invalid proxy_protocol_networks value +# +SET GLOBAL proxy_protocol_networks='1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0'; +ERROR 42000: Error parsing proxy_protocol_networks parameter, near '1' +# End of 10.6 tests SET @@global.proxy_protocol_networks=@global; diff --git a/mysql-test/suite/sys_vars/t/proxy_protocol_networks_grant.test b/mysql-test/suite/sys_vars/t/proxy_protocol_networks_grant.test index f2dd815842489..b2ef86fd04739 100644 --- a/mysql-test/suite/sys_vars/t/proxy_protocol_networks_grant.test +++ b/mysql-test/suite/sys_vars/t/proxy_protocol_networks_grant.test @@ -12,7 +12,6 @@ CREATE USER user1@localhost; GRANT ALL PRIVILEGES ON *.* TO user1@localhost; REVOKE CONNECTION ADMIN, SUPER ON *.* FROM user1@localhost; --connect(user1,localhost,user1,,) ---connection user1 --error ER_SPECIFIC_ACCESS_DENIED_ERROR SET GLOBAL proxy_protocol_networks=""; --error ER_GLOBAL_VARIABLE @@ -28,7 +27,6 @@ DROP USER user1@localhost; CREATE USER user1@localhost; GRANT CONNECTION ADMIN ON *.* TO user1@localhost; --connect(user1,localhost,user1,,) ---connection user1 SET GLOBAL proxy_protocol_networks=""; --error ER_GLOBAL_VARIABLE SET proxy_protocol_networks=""; @@ -43,7 +41,6 @@ DROP USER user1@localhost; CREATE USER user1@localhost; GRANT SUPER ON *.* TO user1@localhost; --connect(user1,localhost,user1,,) ---connection user1 SET GLOBAL proxy_protocol_networks=""; --error ER_GLOBAL_VARIABLE SET proxy_protocol_networks=""; @@ -53,4 +50,11 @@ SET SESSION proxy_protocol_networks=""; --connection default DROP USER user1@localhost; +--echo # +--echo # MDEV-39658 ASAN crash on invalid proxy_protocol_networks value +--echo # +--error ER_PARSE_ERROR +SET GLOBAL proxy_protocol_networks='1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0'; + +--echo # End of 10.6 tests SET @@global.proxy_protocol_networks=@global; diff --git a/sql/proxy_protocol.cc b/sql/proxy_protocol.cc index 9e0ed7bc0ee3f..7460b2e6cc59d 100644 --- a/sql/proxy_protocol.cc +++ b/sql/proxy_protocol.cc @@ -307,6 +307,8 @@ static int parse_subnet(char *addr_str, struct subnet *subnet) subnet->bits= 0; return 0; } + else + return -1; char *pmask= strchr(addr_str, '/'); if (!pmask) @@ -367,7 +369,7 @@ static int parse_networks(const char *subnets_str, subnet **out_subnets, size_t goto end; } - max_subnets= MY_MAX(3,strlen(subnets_str)/2); + max_subnets= MY_MAX(3,strlen(subnets_str)/3+1); subnets= (subnet *)my_malloc(PSI_INSTRUMENT_ME, max_subnets * sizeof(subnet), MY_ZEROFILL); From fe3039eef7b8b6d86458d9ef63554647d85dcd54 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 19 May 2026 20:39:01 +0200 Subject: [PATCH 15/29] MDEV-39673 group_concat ignores max_allowed_packet GROUP_CONCAT is limited by group_concat_max_len, but also, as a string function it must respect max_allowed_packet. Let's introduce THD::gconcat_max_len() helper to simplify checks. Also: * make max group_concat_max_len value the same as max max_allowed_packet * use the same MY_MIN((ulonglong) ..., UINT_MAX32) in Item_func_json_objectagg as in Item_func_group_concat * use overflow-safe type for lengths in Item_func_quote (MAX_MAX_ALLOWED_PACKET is 1G so uint cannot overflow yet, but it's a fragile assumption) --- mysql-test/main/func_gconcat.result | 18 ++++++++++++++ mysql-test/main/func_gconcat.test | 12 ++++++++++ mysql-test/main/func_json_notembedded.result | 2 +- mysql-test/main/func_json_notembedded.test | 2 +- .../r/group_concat_max_len_func.result | 24 +++---------------- .../sys_vars/r/sysvars_server_embedded.result | 2 +- .../r/sysvars_server_notembedded.result | 2 +- .../sys_vars/t/group_concat_max_len_func.test | 10 -------- sql/field.cc | 2 +- sql/item_jsonfunc.cc | 7 +++--- sql/item_strfunc.cc | 2 +- sql/item_sum.cc | 11 ++++----- sql/sql_class.h | 3 +++ sql/sys_vars.cc | 5 ++-- 14 files changed, 54 insertions(+), 48 deletions(-) diff --git a/mysql-test/main/func_gconcat.result b/mysql-test/main/func_gconcat.result index d725029a5335a..6c50416ee2717 100644 --- a/mysql-test/main/func_gconcat.result +++ b/mysql-test/main/func_gconcat.result @@ -1538,3 +1538,21 @@ DROP VIEW v1; DROP TABLE t1; SET NAMES latin1; # End of 10.5 tests +# +# MDEV-39673 group_concat ignores max_allowed_packet +# +connect u,localhost,root; +set group_concat_max_len=2*1024*1024*1024; +Warnings: +Warning 1292 Truncated incorrect group_concat_max_len value: '2147483648' +select @@group_concat_max_len; +@@group_concat_max_len +1073741824 +select length(group_concat(repeat('a', @@max_allowed_packet-1), repeat('a', @@max_allowed_packet-1))) from dual; +length(group_concat(repeat('a', @@max_allowed_packet-1), repeat('a', @@max_allowed_packet-1))) +16777216 +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +disconnect u; +connection default; +# End of 10.6 tests diff --git a/mysql-test/main/func_gconcat.test b/mysql-test/main/func_gconcat.test index 5694c245033f3..90bfc9188e7dd 100644 --- a/mysql-test/main/func_gconcat.test +++ b/mysql-test/main/func_gconcat.test @@ -1125,3 +1125,15 @@ DROP TABLE t1; SET NAMES latin1; --echo # End of 10.5 tests + +--echo # +--echo # MDEV-39673 group_concat ignores max_allowed_packet +--echo # +connect u,localhost,root; +set group_concat_max_len=2*1024*1024*1024; +select @@group_concat_max_len; +select length(group_concat(repeat('a', @@max_allowed_packet-1), repeat('a', @@max_allowed_packet-1))) from dual; +disconnect u; +connection default; + +--echo # End of 10.6 tests diff --git a/mysql-test/main/func_json_notembedded.result b/mysql-test/main/func_json_notembedded.result index 756d2e85f7c34..4a7bd82809868 100644 --- a/mysql-test/main/func_json_notembedded.result +++ b/mysql-test/main/func_json_notembedded.result @@ -3,7 +3,7 @@ connect u,localhost,root; # # MDEV-24909 JSON functions don't respect KILL QUERY / max_statement_time limit # -set group_concat_max_len= 4294967295; +set group_concat_max_len= 1000000000; set @obj=concat_ws('','{', repeat('"a":"b",', 1250000/2), '"c":"d"}'); set @arr=concat_ws('','[', repeat('1234567,', 1250000/2), '2345678]'); select length(@obj), length(@arr); diff --git a/mysql-test/main/func_json_notembedded.test b/mysql-test/main/func_json_notembedded.test index 893b248301c19..d1a7bfdeb02af 100644 --- a/mysql-test/main/func_json_notembedded.test +++ b/mysql-test/main/func_json_notembedded.test @@ -8,7 +8,7 @@ connect u,localhost,root; --echo # --echo # MDEV-24909 JSON functions don't respect KILL QUERY / max_statement_time limit --echo # -set group_concat_max_len= 4294967295; +set group_concat_max_len= 1000000000; set @obj=concat_ws('','{', repeat('"a":"b",', 1250000/2), '"c":"d"}'); set @arr=concat_ws('','[', repeat('1234567,', 1250000/2), '2345678]'); diff --git a/mysql-test/suite/sys_vars/r/group_concat_max_len_func.result b/mysql-test/suite/sys_vars/r/group_concat_max_len_func.result index 01f44ae51be67..e38f1f6ccb2b6 100644 --- a/mysql-test/suite/sys_vars/r/group_concat_max_len_func.result +++ b/mysql-test/suite/sys_vars/r/group_concat_max_len_func.result @@ -118,29 +118,11 @@ SELECT * FROM ( SELECT GROUP_CONCAT(val) AS nested FROM t1) As tmp; nested bar,foo SET group_concat_max_len = 1073741825; +Warnings: +Warning 1292 Truncated incorrect group_concat_max_len value: '1073741825' SHOW VARIABLES LIKE 'group_concat_max_len'; Variable_name Value -group_concat_max_len 1073741825 -SELECT GROUP_CONCAT(val) AS simple FROM t1; -simple -bar,foo -SELECT * FROM ( SELECT GROUP_CONCAT(val) AS nested FROM t1) As tmp; -nested -bar,foo -SET group_concat_max_len = 1073741826; -SHOW VARIABLES LIKE 'group_concat_max_len'; -Variable_name Value -group_concat_max_len 1073741826 -SELECT GROUP_CONCAT(val) AS simple FROM t1; -simple -bar,foo -SELECT * FROM ( SELECT GROUP_CONCAT(val) AS nested FROM t1) As tmp; -nested -bar,foo -SET group_concat_max_len = 2147483649; -SHOW VARIABLES LIKE 'group_concat_max_len'; -Variable_name Value -group_concat_max_len 2147483649 +group_concat_max_len 1073741824 SELECT GROUP_CONCAT(val) AS simple FROM t1; simple bar,foo diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 977afb94f0d50..e180131318374 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -1087,7 +1087,7 @@ VARIABLE_SCOPE SESSION VARIABLE_TYPE INT UNSIGNED VARIABLE_COMMENT The maximum length of the result of function GROUP_CONCAT() NUMERIC_MIN_VALUE 4 -NUMERIC_MAX_VALUE 4294967295 +NUMERIC_MAX_VALUE 1073741824 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY NO diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index c5781705847d3..5add3ed05dc70 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -1107,7 +1107,7 @@ VARIABLE_SCOPE SESSION VARIABLE_TYPE INT UNSIGNED VARIABLE_COMMENT The maximum length of the result of function GROUP_CONCAT() NUMERIC_MIN_VALUE 4 -NUMERIC_MAX_VALUE 4294967295 +NUMERIC_MAX_VALUE 1073741824 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY NO diff --git a/mysql-test/suite/sys_vars/t/group_concat_max_len_func.test b/mysql-test/suite/sys_vars/t/group_concat_max_len_func.test index 4957afc088057..d590fd5915e99 100644 --- a/mysql-test/suite/sys_vars/t/group_concat_max_len_func.test +++ b/mysql-test/suite/sys_vars/t/group_concat_max_len_func.test @@ -155,16 +155,6 @@ SHOW VARIABLES LIKE 'group_concat_max_len'; SELECT GROUP_CONCAT(val) AS simple FROM t1; SELECT * FROM ( SELECT GROUP_CONCAT(val) AS nested FROM t1) As tmp; -SET group_concat_max_len = 1073741826; -SHOW VARIABLES LIKE 'group_concat_max_len'; -SELECT GROUP_CONCAT(val) AS simple FROM t1; -SELECT * FROM ( SELECT GROUP_CONCAT(val) AS nested FROM t1) As tmp; - -SET group_concat_max_len = 2147483649; -SHOW VARIABLES LIKE 'group_concat_max_len'; -SELECT GROUP_CONCAT(val) AS simple FROM t1; -SELECT * FROM ( SELECT GROUP_CONCAT(val) AS nested FROM t1) As tmp; - DROP TABLE t1; SET @@global.group_concat_max_len = @save; diff --git a/sql/field.cc b/sql/field.cc index 51cf631151cc6..7fed7cdfc760d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8772,7 +8772,7 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs) DBUG_ASSERT(length <= max_data_length()); new_length= length; - copy_length= table->in_use->variables.group_concat_max_len; + copy_length= table->in_use->gconcat_max_len(); if (new_length > copy_length) { new_length= Well_formed_prefix(cs, diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 90783732afc71..64455cb2d9c4e 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -4103,9 +4103,10 @@ Item_func_json_objectagg::fix_fields(THD *thd, Item **ref) result.set_charset(collation.collation); result_field= 0; null_value= 1; - max_length= (uint32)(thd->variables.group_concat_max_len - / collation.collation->mbminlen - * collation.collation->mbmaxlen); + max_length= (uint32) MY_MIN((ulonglong) thd->gconcat_max_len() + / collation.collation->mbminlen + * collation.collation->mbmaxlen, UINT_MAX32); + if (check_sum_func(thd, ref)) return TRUE; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c725873523882..33d9712d0028f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -4149,7 +4149,7 @@ String *Item_func_quote::val_str(String *str) ulong max_allowed_packet= current_thd->variables.max_allowed_packet; char *from, *to, *end, *start; String *arg= args[0]->val_str(&tmp_value); - uint arg_length, new_length; + size_t arg_length, new_length; if (!arg) // Null argument { /* Return the string 'NULL' */ diff --git a/sql/item_sum.cc b/sql/item_sum.cc index f7b5e97188bdd..15caf8b9a8ebc 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3810,7 +3810,7 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), { Item_func_group_concat *item= (Item_func_group_concat *) item_arg; TABLE *table= item->table; - uint max_length= table->in_use->variables.group_concat_max_len; + uint max_length= table->in_use->gconcat_max_len(); String tmp((char *)table->record[1], table->s->reclength, default_charset_info); String tmp2; @@ -4140,7 +4140,7 @@ bool Item_func_group_concat::repack_tree(THD *thd) DBUG_ASSERT(tree->size_of_element == st.tree.size_of_element); st.table= table; st.len= 0; - st.maxlen= thd->variables.group_concat_max_len; + st.maxlen= thd->gconcat_max_len(); tree_walk(tree, ©_to_tree, &st, left_root_right); if (st.len <= st.maxlen) // Copying aborted. Must be OOM { @@ -4219,7 +4219,7 @@ bool Item_func_group_concat::add(bool exclude_nulls) { THD *thd= table->in_use; table->field[0]->store(row_str_len, FALSE); - if ((tree_len >> GCONCAT_REPACK_FACTOR) > thd->variables.group_concat_max_len + if ((tree_len >> GCONCAT_REPACK_FACTOR) > thd->gconcat_max_len() && tree->elements_in_tree > 1) if (repack_tree(thd)) return 1; @@ -4272,7 +4272,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) result.set_charset(collation.collation); result_field= 0; null_value= 1; - max_length= (uint32) MY_MIN((ulonglong) thd->variables.group_concat_max_len + max_length= (uint32) MY_MIN((ulonglong) thd->gconcat_max_len() / collation.collation->mbminlen * collation.collation->mbmaxlen, UINT_MAX32); @@ -4364,8 +4364,7 @@ bool Item_func_group_concat::setup(THD *thd) Prepend the field to store the length of the string representation of this row. Used to detect when the tree goes over group_concat_max_len */ - Item *item= new (thd->mem_root) - Item_uint(thd, thd->variables.group_concat_max_len); + Item *item= new (thd->mem_root) Item_uint(thd, thd->gconcat_max_len()); if (!item || all_fields.push_front(item, thd->mem_root)) DBUG_RETURN(TRUE); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 0627c0a32b622..7cca7721856ce 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5836,6 +5836,9 @@ class THD: public THD_count, /* this must be first */ (lex->describe && // Is EXPLAIN (variables.note_verbosity & NOTE_VERBOSITY_EXPLAIN))); } + + uint gconcat_max_len() + { return MY_MIN(variables.group_concat_max_len, variables.max_allowed_packet); } }; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 79cb29056cf50..eaa099e65ab06 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1640,7 +1640,7 @@ static Sys_var_ulong Sys_max_allowed_packet( "max_allowed_packet", "Max packet length to send to or receive from the server", SESSION_VAR(max_allowed_packet), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1024, 1024*1024*1024), DEFAULT(16*1024*1024), + VALID_RANGE(1024, MAX_MAX_ALLOWED_PACKET), DEFAULT(16*1024*1024), BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_max_allowed_packet)); @@ -4950,7 +4950,8 @@ static Sys_var_uint Sys_group_concat_max_len( "group_concat_max_len", "The maximum length of the result of function GROUP_CONCAT()", SESSION_VAR(group_concat_max_len), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(4, UINT_MAX32), DEFAULT(1024*1024), BLOCK_SIZE(1)); + VALID_RANGE(4, MAX_MAX_ALLOWED_PACKET), DEFAULT(1024*1024), + BLOCK_SIZE(1)); static char *glob_hostname_ptr; static Sys_var_charptr Sys_hostname( From 5cedbdfcc65b07d15ab25164cdce677cf0d256fa Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 May 2026 18:33:04 +0200 Subject: [PATCH 16/29] fix columnstore for new cmake --- storage/columnstore/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/columnstore/CMakeLists.txt b/storage/columnstore/CMakeLists.txt index 2eb146a848af7..a1f7f77e61057 100644 --- a/storage/columnstore/CMakeLists.txt +++ b/storage/columnstore/CMakeLists.txt @@ -22,6 +22,7 @@ CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") MY_CHECK_AND_SET_COMPILER_FLAG("-fno-lto") SET(PCRE_INCLUDES "${PCRE_INCLUDE_DIRS}") + set(CMAKE_POLICY_VERSION_MINIMUM 3.5) add_subdirectory(columnstore) IF(TARGET columnstore) From dae315a7b2bf8bd2fd0449467e711e5a2db26669 Mon Sep 17 00:00:00 2001 From: Hemant Dangi Date: Mon, 18 May 2026 16:10:13 +0530 Subject: [PATCH 17/29] MDEV-39648: wsrep_sst_rsync.sh: apply safe() to joiner-supplied parameters Issue: wsrep_sst_rsync.sh interpolated WSREP_SST_OPT_REMOTE_USER and WSREP_SST_OPT_REMOTE_PSWD verbatim. Because both values originate from the joiner side of the SST request, a newline in either could splice an extra directive into the donor-written stunnel.conf (silently downgrading peer-cert verification) or an extra line into the rsync magic file. MDEV-39413 had introduced safe() for the same threat class in wsrep_sst_mariabackup but did not extend it to the rsync script. Solution: Routing the rsync interpolations through safe() closes the gap, and extending safe() to also reject tab and newline ensures multi-line values cannot survive into a config-file heredoc. --- ...a_sst_rsync_encrypt_with_key_server.result | 27 +++++ ...lera_sst_rsync_encrypt_with_key_server.cnf | 13 +++ ...era_sst_rsync_encrypt_with_key_server.test | 99 +++++++++++++++++++ scripts/wsrep_sst_rsync.sh | 7 +- 4 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 mysql-test/suite/galera/r/galera_sst_rsync_encrypt_with_key_server.result create mode 100644 mysql-test/suite/galera/t/galera_sst_rsync_encrypt_with_key_server.cnf create mode 100644 mysql-test/suite/galera/t/galera_sst_rsync_encrypt_with_key_server.test diff --git a/mysql-test/suite/galera/r/galera_sst_rsync_encrypt_with_key_server.result b/mysql-test/suite/galera/r/galera_sst_rsync_encrypt_with_key_server.result new file mode 100644 index 0000000000000..48b296a96f56d --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_rsync_encrypt_with_key_server.result @@ -0,0 +1,27 @@ +connection node_2; +connection node_1; +SELECT 1; +1 +1 +connection node_2; +FOUND 1 /wsrep_sst_rsync/ in mysqld.1.err +connection node_1; +call mtr.add_suppression('Invalid value for WSREP_SST_OPT_REMOTE_USER'); +call mtr.add_suppression('Failed to read from: wsrep_sst_rsync'); +call mtr.add_suppression('Process completed with error: wsrep_sst_rsync'); +call mtr.add_suppression('Command did not run: wsrep_sst_rsync'); +call mtr.add_suppression('State transfer to .* failed'); +call mtr.add_suppression('Will never receive state. Need to abort'); +call mtr.add_suppression('Error while getting data from donor node'); +call mtr.add_suppression('Cleanup after exit with status'); +call mtr.add_suppression('Removing .*/sst_in_progress'); +call mtr.add_suppression('Parent mysqld process .* terminated unexpectedly'); +connection node_2; +connection node_1; +FOUND 1 /Invalid value for WSREP_SST_OPT_REMOTE_USER/ in mysqld.1.err +connection node_2; +# restart +call mtr.add_suppression('Will never receive state. Need to abort'); +call mtr.add_suppression('Parent mysqld process .* terminated unexpectedly'); +call mtr.add_suppression('Cleanup after exit with status'); +call mtr.add_suppression('State transfer to .* failed'); diff --git a/mysql-test/suite/galera/t/galera_sst_rsync_encrypt_with_key_server.cnf b/mysql-test/suite/galera/t/galera_sst_rsync_encrypt_with_key_server.cnf new file mode 100644 index 0000000000000..9b919145a316d --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_rsync_encrypt_with_key_server.cnf @@ -0,0 +1,13 @@ +!include ../galera_2nodes.cnf + +[mysqld] +wsrep_sst_method=rsync +wsrep_sst_auth="root:" +wsrep_debug=1 + +ssl-cert=@ENV.MYSQL_TEST_DIR/std_data/server-cert.pem +ssl-key=@ENV.MYSQL_TEST_DIR/std_data/server-key.pem +ssl-ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem + +[sst] +ssl-mode=VERIFY_CA diff --git a/mysql-test/suite/galera/t/galera_sst_rsync_encrypt_with_key_server.test b/mysql-test/suite/galera/t/galera_sst_rsync_encrypt_with_key_server.test new file mode 100644 index 0000000000000..f0458e1f62fd2 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_rsync_encrypt_with_key_server.test @@ -0,0 +1,99 @@ +# +# Verifies that wsrep_sst_rsync.sh rejects a joiner-supplied certificate +# whose CN contains shell-unsafe characters. +# +# Brings up a 2-node cluster with rsync SST and ssl-mode=VERIFY_CA, then +# forces a fresh SST on node_2 using std_data/server-new-cert.pem -- a +# cert whose CN intentionally contains shell metacharacters. Confirms +# that the donor (node_1) logs +# "Invalid value for WSREP_SST_OPT_REMOTE_USER" +# i.e. the rsync SST script refuses the value rather than interpolating +# it into stunnel.conf or the rsync magic file. +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT 1; + +--connection node_2 +--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'WSREP_LOCAL_STATE_COMMENT' +--source include/wait_condition.inc + +# Confirm the initial SST went via rsync + stunnel (sanity check for the +# test configuration). +--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err +--let SEARCH_PATTERN = wsrep_sst_rsync +--source include/search_pattern_in_file.inc + + +# Reject shell-unsafe joiner-supplied auth (rsync) + +# Suppressions are per-server. node_1 will log the donor-side rejection +# ("Invalid value for WSREP_SST_OPT_REMOTE_USER"); node_2 will log the +# joiner-side "Will never receive state" abort. Add to both. +--connection node_1 +call mtr.add_suppression('Invalid value for WSREP_SST_OPT_REMOTE_USER'); +call mtr.add_suppression('Failed to read from: wsrep_sst_rsync'); +call mtr.add_suppression('Process completed with error: wsrep_sst_rsync'); +call mtr.add_suppression('Command did not run: wsrep_sst_rsync'); +call mtr.add_suppression('State transfer to .* failed'); +call mtr.add_suppression('Will never receive state. Need to abort'); +call mtr.add_suppression('Error while getting data from donor node'); +call mtr.add_suppression('Cleanup after exit with status'); +call mtr.add_suppression('Removing .*/sst_in_progress'); +call mtr.add_suppression('Parent mysqld process .* terminated unexpectedly'); + +--connection node_2 +--source include/shutdown_mysqld.inc + +# force SST again +--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat +# using a cert with shell-unsafe CN +--exec echo '[mysqld.2]' >> $MYSQLTEST_VARDIR/my.cnf +--exec echo ssl-cert=$MYSQL_TEST_DIR/std_data/server-new-cert.pem >> $MYSQLTEST_VARDIR/my.cnf +--exec echo ssl-key=$MYSQL_TEST_DIR/std_data/server-new-key.pem >> $MYSQLTEST_VARDIR/my.cnf + +# start the server +# Joiner mariadbd exits when SST is aborted; the exit code varies by +# platform (clean 0 on some systems, signalled 134 / 1 on others). +--error 0,1,134 +--exec $MYSQLD_LAST_CMD +# the donor refused the SST request + +--connection node_1 +# safe() in wsrep_sst_common.sh logs this when it rejects the joiner CN; +# wsrep_sst_rsync.sh wraps the joiner-supplied REMOTE_USER with $(safe ..) +# at line 249 so the value never reaches the stunnel.conf heredoc. +--let SEARCH_PATTERN = Invalid value for WSREP_SST_OPT_REMOTE_USER +--source include/search_pattern_in_file.inc + +# cleanup +# Kill joiner's stunnel / rsync that may linger after the aborted SST. +# Use a perl block because --exec with pkill -f matches the mtr cmdline +# itself (which contains the pattern) and tears down the wrong process. +perl; + open(my $fh, '-|', 'ps', '-eo', 'pid,args') or die "ps: $!"; + while (<$fh>) { + next unless /server-new-cert/; + next unless /^\s*(\d+)\s+(?:.*\/)?(stunnel|socat|rsync)\b/; + kill 'TERM', $1; + } + close $fh; +EOF +--exec echo ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert.pem >> $MYSQLTEST_VARDIR/my.cnf +--exec echo ssl-key=$MYSQL_TEST_DIR/std_data/server-key.pem >> $MYSQLTEST_VARDIR/my.cnf + +# Switch back to node_2 before restarting it; the connection associates +# with the soon-to-be-restarted server so mtr auto-reconnects and the +# wait_condition + late suppressions land on the new instance. +--connection node_2 +--source $MYSQL_TEST_DIR/include/start_mysqld.inc + +--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc + +call mtr.add_suppression('Will never receive state. Need to abort'); +call mtr.add_suppression('Parent mysqld process .* terminated unexpectedly'); +call mtr.add_suppression('Cleanup after exit with status'); +call mtr.add_suppression('State transfer to .* failed'); diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 90d439b9316bf..53ff8cc196308 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -246,7 +246,7 @@ if [ "${SSLMODE#VERIFY}" != "$SSLMODE" ]; then exit 22 # EINVAL fi if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then - CHECK_OPT="checkHost = $WSREP_SST_OPT_REMOTE_USER" + CHECK_OPT="checkHost = $(safe WSREP_SST_OPT_REMOTE_USER)" elif [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then # check if the address is an ip-address (v4 or v6): if echo "$WSREP_SST_OPT_HOST_UNESCAPED" | \ @@ -640,8 +640,9 @@ FILTER="-f '- /lost+found' echo "$STATE" > "$MAGIC_FILE" if [ -n "$WSREP_SST_OPT_REMOTE_PSWD" ]; then - # Let joiner know that we know its secret - echo "$SECRET_TAG $WSREP_SST_OPT_REMOTE_PSWD" >> "$MAGIC_FILE" + # Let joiner know that we know its secret. + WSREP_SST_OPT_REMOTE_PSWD_=$(safe WSREP_SST_OPT_REMOTE_PSWD) + echo "$SECRET_TAG $WSREP_SST_OPT_REMOTE_PSWD_" >> "$MAGIC_FILE" fi if [ $WSREP_SST_OPT_BYPASS -ne 0 ]; then From a9e2f7f648f339c6f49b5bbe0435fa6b04a27ed2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 21 May 2026 11:19:44 +0200 Subject: [PATCH 18/29] MDEV-39676 disallow global.wsrep_sst_donor=NULL again it crashes in galera.mdev-28433 --- .../suite/sys_vars/r/wsrep_sst_donor_basic.result | 11 ++++++----- .../suite/sys_vars/t/wsrep_sst_donor_basic.test | 5 +++-- sql/wsrep_sst.cc | 13 ++++++------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result index e3fbce72708ae..dbe4cc23bf9ab 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result @@ -37,17 +37,18 @@ SET @@global.wsrep_sst_donor=''; SELECT @@global.wsrep_sst_donor; @@global.wsrep_sst_donor -SET @@global.wsrep_sst_donor=NULL; -SELECT @@global.wsrep_sst_donor; -@@global.wsrep_sst_donor -NULL # invalid values SET @@global.wsrep_sst_donor=1; ERROR 42000: Incorrect argument type to variable 'wsrep_sst_donor' SELECT @@global.wsrep_sst_donor; @@global.wsrep_sst_donor -NULL + +SET @@global.wsrep_sst_donor=NULL; +ERROR 42000: Variable 'wsrep_sst_donor' can't be set to the value of 'NULL' +SELECT @@global.wsrep_sst_donor; +@@global.wsrep_sst_donor + # restore the initial value SET @@global.wsrep_sst_donor = @wsrep_sst_donor_global_saved; diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test index 2824f56ca055a..c4b32bb8af6ab 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test @@ -29,14 +29,15 @@ SET @@global.wsrep_sst_donor=default; SELECT @@global.wsrep_sst_donor; SET @@global.wsrep_sst_donor=''; SELECT @@global.wsrep_sst_donor; -SET @@global.wsrep_sst_donor=NULL; -SELECT @@global.wsrep_sst_donor; --echo --echo # invalid values --error ER_WRONG_TYPE_FOR_VAR SET @@global.wsrep_sst_donor=1; SELECT @@global.wsrep_sst_donor; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_sst_donor=NULL; +SELECT @@global.wsrep_sst_donor; --echo --echo # restore the initial value diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index e71dfdbf0a8a1..d40c7a77026c4 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -362,15 +362,14 @@ void wsrep_sst_auth_init () bool wsrep_sst_donor_check (sys_var *self, THD* thd, set_var* var) { - /* Allow empty value */ - if (!var->save_result.string_value.str || var->save_result.string_value.length == 0) - return 0; - /* Check length */ - if ((var->save_result.string_value.length > (FN_REFLEN -1))) // safety - { + if (!var->save_result.string_value.str || + var->save_result.string_value.length > FN_REFLEN-1) // safety goto err; - } + + /* Allow empty value */ + if (var->save_result.string_value.length == 0) + return 0; /* check also that donor string contains only accepted characters */ if (check_request_str(var->save_result.string_value.str, From f2296f377efdf5329c2c9678e8a5cae52dd75d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 21 May 2026 13:06:37 +0300 Subject: [PATCH 19/29] MDEV-39685 : galera multi table update crash This is regression caused by MDEV-28750 commit 1f349968. In multi-table update table list could contain tables that are not yet opened because update does not really change them. This can happen e.g. when update changes table that is referenced by foreign key by table that is not part of multi-table update. Fixed by first checking is wsrep write set size limited. If it is not multi-table update can continue normally. If write set size is limited then check has update updated both transactional and non-transactional tables and those tables that have not yet been opened can be safely skipped as they are not updated. --- mysql-test/suite/galera/r/MDEV-39685.result | 13 +++++ mysql-test/suite/galera/t/MDEV-39685.test | 18 +++++++ sql/sql_update.cc | 58 +++++++++++++-------- 3 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-39685.result create mode 100644 mysql-test/suite/galera/t/MDEV-39685.test diff --git a/mysql-test/suite/galera/r/MDEV-39685.result b/mysql-test/suite/galera/r/MDEV-39685.result new file mode 100644 index 0000000000000..ab4d01526b9f3 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-39685.result @@ -0,0 +1,13 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 ( +pk int PRIMARY KEY, +c varchar(8), +i int +) ENGINE=InnoDB; +CREATE TABLE t2 (f int) ENGINE=InnoDB; +CREATE TABLE t3 (x int, +FOREIGN KEY (x) REFERENCES t1 (pk) +) ENGINE=InnoDB; +UPDATE t1 JOIN t2 ON t1.i = t2.f SET t1.c = 'foo'; +DROP TABLE t3, t2, t1; diff --git a/mysql-test/suite/galera/t/MDEV-39685.test b/mysql-test/suite/galera/t/MDEV-39685.test new file mode 100644 index 0000000000000..19775610d0add --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-39685.test @@ -0,0 +1,18 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +CREATE TABLE t1 ( + pk int PRIMARY KEY, + c varchar(8), + i int +) ENGINE=InnoDB; + +CREATE TABLE t2 (f int) ENGINE=InnoDB; + +CREATE TABLE t3 (x int, + FOREIGN KEY (x) REFERENCES t1 (pk) +) ENGINE=InnoDB; + +UPDATE t1 JOIN t2 ON t1.i = t2.f SET t1.c = 'foo'; + +DROP TABLE t3, t2, t1; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 7a18cc640ee5c..891624f2f7edc 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -2037,29 +2037,43 @@ bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, #ifdef WITH_WSREP if (WSREP(thd)) { - bool transactional= false; - bool non_trans= false; - for (TABLE_LIST *tablel= table_list; tablel; tablel= tablel->next_global) - { - TABLE *table= tablel->table; - if (table->file->has_transactions_and_rollback()) - transactional= true; - else - non_trans= true; - } - /* In multi-table update Galera does not support update to both - transactional and non-transactional engines if write-set - size is limited. */ - bool limited = (wsrep_max_ws_rows || wsrep_max_ws_size != WSREP_MAX_WS_SIZE); - if (transactional && non_trans && limited) + const bool limited = (wsrep_max_ws_rows || + (wsrep_max_ws_size != WSREP_MAX_WS_SIZE)); + + if (limited) { - my_error(ER_GALERA_REPLICATION_NOT_SUPPORTED, MYF(0)); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_GALERA_REPLICATION_NOT_SUPPORTED, - "Galera does not support multi-table update", - " to both transactional and non-transactional engines" - " if write-set size is limited."); - DBUG_RETURN(1); + /* Write set size is limited, check if this update contains + updates to both transactional and non-transactional table. */ + bool transactional= false; + bool non_trans= false; + for (TABLE_LIST *tablel= table_list; tablel; tablel= tablel->next_global) + { + TABLE *table= tablel->table; + /* This can happen on multi-table update if one of the + tables updated is referenced by foreign key from other not + updated table. Not updated table is not yet opened, thus + there is item on table list but actual table is NULL. */ + if (!table) + continue; + /* Table has been opened, check is SE transactional or not. */ + if (table->file->has_transactions_and_rollback()) + transactional= true; + else + non_trans= true; + } + /* In multi-table update Galera does not support update to both + transactional and non-transactional engines if write-set + size is limited. */ + if (transactional && non_trans) + { + my_error(ER_GALERA_REPLICATION_NOT_SUPPORTED, MYF(0)); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_GALERA_REPLICATION_NOT_SUPPORTED, + "Galera does not support multi-table update", + " to both transactional and non-transactional engines" + " if write-set size is limited."); + DBUG_RETURN(1); + } } } #endif /* WITH_WSREP */ From e7374f2ae7fe46bc933b20523558f4e88b7421c7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 May 2026 19:24:03 +0200 Subject: [PATCH 20/29] Revert "MDEV-17677: Keywords followed by .number parsed as identifiers" This reverts commit 895b28d6721eadfad0d47723fcc949eae75cf8cf. --- mysql-test/main/parser.result | 41 ----------------- mysql-test/main/parser.test | 46 ------------------- .../suite/funcs_1/r/innodb_trig_0407.result | 2 +- .../suite/funcs_1/r/memory_trig_0407.result | 2 +- .../suite/funcs_1/r/myisam_trig_0407.result | 2 +- sql/sql_lex.cc | 4 +- 6 files changed, 5 insertions(+), 92 deletions(-) diff --git a/mysql-test/main/parser.result b/mysql-test/main/parser.result index f25c51944e6fb..b52af23eb4921 100644 --- a/mysql-test/main/parser.result +++ b/mysql-test/main/parser.result @@ -2269,44 +2269,3 @@ $$ # # End of 10.6 tests # -# -# MDEV-17677 : Keywords are parsed as identifiers when followed by a dot -# -SET NAMES utf8; -test for Nd (should work) -SELECT.1; -.1 -0.1 -SELECT.123+0; -.123+0 -0.123 -SELECT.5 * 2; -.5 * 2 -1.0 -test for Mn -SELECT.́1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT.́1' at line 1 -SELECT.̈abc; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT.̈abc' at line 1 -test for Mc -SELECT.ःtest; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT.ःtest' at line 1 -test for Pc -SELECT.‿a; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT.‿a' at line 1 -test for Cf -SELECT.‎abc; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT.‎abc' at line 1 -test for Middle-dot and underscore -SELECT.·123; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT.·123' at line 1 -ٍSELECT._1; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'ٍSELECT._1' at line 1 -still work as identifier -CREATE TABLE `SELECT` (a INT); -INSERT INTO `SELECT` VALUES (5); -SELECT `SELECT`.a FROM `SELECT`; -a -5 -DROP TABLE `SELECT`; -SET NAMES DEFAULT; diff --git a/mysql-test/main/parser.test b/mysql-test/main/parser.test index e54137b092b77..5ddbaf29314fd 100644 --- a/mysql-test/main/parser.test +++ b/mysql-test/main/parser.test @@ -2067,49 +2067,3 @@ DELIMITER ;$$ --echo # --echo # End of 10.6 tests --echo # - ---echo # ---echo # MDEV-17677 : Keywords are parsed as identifiers when followed by a dot ---echo # - -SET NAMES utf8; - ---echo test for Nd (should work) -SELECT.1; -SELECT.123+0; -SELECT.5 * 2; - ---character_set utf8mb4 ---echo test for Mn ---error ER_PARSE_ERROR -SELECT.́1; - ---error ER_PARSE_ERROR -SELECT.̈abc; - - --- echo test for Mc ---error ER_PARSE_ERROR -SELECT.ःtest; - ---echo test for Pc ---error ER_PARSE_ERROR -SELECT.‿a; - ---echo test for Cf ---error ER_PARSE_ERROR -SELECT.‎abc; - ---echo test for Middle-dot and underscore ---error ER_PARSE_ERROR -SELECT.·123; ---error ER_PARSE_ERROR -ٍSELECT._1; - ---echo still work as identifier -CREATE TABLE `SELECT` (a INT); -INSERT INTO `SELECT` VALUES (5); -SELECT `SELECT`.a FROM `SELECT`; -DROP TABLE `SELECT`; - -SET NAMES DEFAULT; diff --git a/mysql-test/suite/funcs_1/r/innodb_trig_0407.result b/mysql-test/suite/funcs_1/r/innodb_trig_0407.result index 5b9a16d2f17fd..281e4e8d0f6c3 100644 --- a/mysql-test/suite/funcs_1/r/innodb_trig_0407.result +++ b/mysql-test/suite/funcs_1/r/innodb_trig_0407.result @@ -138,7 +138,7 @@ create table t1_433a (f1a char (5)) engine = ; CREATE TRIGGER trg3 BEFORE INSERT on t1_433 for each row set new.f1 = 'Trigger 3.5.4.3'; Drop trigger t1.433.trg3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.433.trg3' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.trg3' at line 1 Drop trigger db_drop3.t1.433.trg3; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.433.trg3' at line 1 Drop trigger mysql.trg3; diff --git a/mysql-test/suite/funcs_1/r/memory_trig_0407.result b/mysql-test/suite/funcs_1/r/memory_trig_0407.result index bf9d20da2f13b..c9a15b46aba07 100644 --- a/mysql-test/suite/funcs_1/r/memory_trig_0407.result +++ b/mysql-test/suite/funcs_1/r/memory_trig_0407.result @@ -138,7 +138,7 @@ create table t1_433a (f1a char (5)) engine = ; CREATE TRIGGER trg3 BEFORE INSERT on t1_433 for each row set new.f1 = 'Trigger 3.5.4.3'; Drop trigger t1.433.trg3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.433.trg3' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.trg3' at line 1 Drop trigger db_drop3.t1.433.trg3; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.433.trg3' at line 1 Drop trigger mysql.trg3; diff --git a/mysql-test/suite/funcs_1/r/myisam_trig_0407.result b/mysql-test/suite/funcs_1/r/myisam_trig_0407.result index bf9d20da2f13b..c9a15b46aba07 100644 --- a/mysql-test/suite/funcs_1/r/myisam_trig_0407.result +++ b/mysql-test/suite/funcs_1/r/myisam_trig_0407.result @@ -138,7 +138,7 @@ create table t1_433a (f1a char (5)) engine = ; CREATE TRIGGER trg3 BEFORE INSERT on t1_433 for each row set new.f1 = 'Trigger 3.5.4.3'; Drop trigger t1.433.trg3; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.433.trg3' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.trg3' at line 1 Drop trigger db_drop3.t1.433.trg3; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.433.trg3' at line 1 Drop trigger mysql.trg3; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 8a5b1a14bcca7..bb0d5630a4c4c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2853,7 +2853,7 @@ int Lex_input_stream::scan_ident_middle(THD *thd, Lex_ident_cli_st *str, yylineno++; } } - if (start == get_ptr() && c == '.' && ident_map[(uchar) yyPeek()] && !my_isdigit(cs, yyPeek())) + if (start == get_ptr() && c == '.' && ident_map[(uchar) yyPeek()]) next_state= MY_LEX_IDENT_SEP; else { // '(' must follow directly if function @@ -12511,4 +12511,4 @@ bool SELECT_LEX_UNIT::is_derived_eliminated() const if (!derived->table) return true; return derived->table->map & outer_select()->join->eliminated_tables; -} \ No newline at end of file +} From 29c00416c603f3bb7456ea049511ceed90395757 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 May 2026 19:24:22 +0200 Subject: [PATCH 21/29] MDEV-39654 schema-qualified unquoted table name starting with digit fails to parse add tests --- mysql-test/main/parser.result | 11 ++++++++++- mysql-test/main/parser.test | 14 +++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/parser.result b/mysql-test/main/parser.result index b52af23eb4921..d0f5d756e9a9d 100644 --- a/mysql-test/main/parser.result +++ b/mysql-test/main/parser.result @@ -2266,6 +2266,15 @@ LEAVE sysdate; END WHILE ; END; $$ -# # End of 10.6 tests # +# MDEV-39654 schema-qualified unquoted table name starting with digit fails to parse +# +create table 1a (1b int); +create table `select` (1c int); +select 1b from test.1a; +1b +select select.1c from test.select; +1c +drop table 1a, `select`; +# End of 10.11 tests diff --git a/mysql-test/main/parser.test b/mysql-test/main/parser.test index 5ddbaf29314fd..138234a4d25c7 100644 --- a/mysql-test/main/parser.test +++ b/mysql-test/main/parser.test @@ -2064,6 +2064,18 @@ DELIMITER ;$$ --disable_prepare_warnings ---echo # --echo # End of 10.6 tests + --echo # +--echo # MDEV-39654 schema-qualified unquoted table name starting with digit fails to parse +--echo # + +create table 1a (1b int); +create table `select` (1c int); + +select 1b from test.1a; +select select.1c from test.select; + +drop table 1a, `select`; + +--echo # End of 10.11 tests From ed8404a73f93e79aff7227bb4560a44cbfdb5d1c Mon Sep 17 00:00:00 2001 From: Hemant Dangi Date: Fri, 22 May 2026 20:18:25 +0530 Subject: [PATCH 22/29] MDEV-39721: wsrep_notify.cc: reject shell-unsafe characters in joiner-supplied member fields Issue: wsrep_notify_status() interpolated members[i].name() (the peer's wsrep_node_name) and members[i].incoming() verbatim into a command string that is then executed via 'sh -c' by wsp::process. A peer joining the cluster with shell metacharacters in its wsrep_node_name or wsrep_node_incoming_address caused arbitrary commands to run on every cluster member that had wsrep_notify_cmd configured. MDEV-39413 introduced safe() for the same threat class in the SST scripts but did not cover the C++ wsrep_notify path. Solution: Validate each substituted field against a narrow whitelist before interpolating. Node name allows alnum and -_. ; node address additionally allows :[]/ for host:port and [ipv6] forms. On bad input the notification is skipped with an error log instead of forwarding the unsafe value to sh -c. --- .../galera_wsrep_notify_cmd_injection.result | 10 +++++ .../t/galera_wsrep_notify_cmd_injection.cnf | 10 +++++ .../t/galera_wsrep_notify_cmd_injection.test | 30 ++++++++++++++ sql/wsrep_notify.cc | 41 ++++++++++++++++++- 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/galera/r/galera_wsrep_notify_cmd_injection.result create mode 100644 mysql-test/suite/galera/t/galera_wsrep_notify_cmd_injection.cnf create mode 100644 mysql-test/suite/galera/t/galera_wsrep_notify_cmd_injection.test diff --git a/mysql-test/suite/galera/r/galera_wsrep_notify_cmd_injection.result b/mysql-test/suite/galera/r/galera_wsrep_notify_cmd_injection.result new file mode 100644 index 0000000000000..3757e4f3dc291 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_wsrep_notify_cmd_injection.result @@ -0,0 +1,10 @@ +connection node_2; +connection node_1; +SELECT 1; +1 +1 +connection node_1; +call mtr.add_suppression('Process completed with error'); +call mtr.add_suppression('Notification command failed'); +call mtr.add_suppression('Unsafe characters in cluster member'); +FOUND 3 /Unsafe characters in cluster member/ in mysqld.1.err diff --git a/mysql-test/suite/galera/t/galera_wsrep_notify_cmd_injection.cnf b/mysql-test/suite/galera/t/galera_wsrep_notify_cmd_injection.cnf new file mode 100644 index 0000000000000..9c55be86036ec --- /dev/null +++ b/mysql-test/suite/galera/t/galera_wsrep_notify_cmd_injection.cnf @@ -0,0 +1,10 @@ +!include ../galera_2nodes.cnf + +[mysqld.1] +# Victim: /bin/true exits 0 ignoring argv, so injection happens in sh -c parsing. +wsrep_notify_cmd=/bin/true + +[mysqld.2] +# Attacker: shell metacharacters in wsrep_node_name; trailing '#' comments +# out whatever the server appends after the name. +wsrep_node_name='n;touch PWN;#' diff --git a/mysql-test/suite/galera/t/galera_wsrep_notify_cmd_injection.test b/mysql-test/suite/galera/t/galera_wsrep_notify_cmd_injection.test new file mode 100644 index 0000000000000..474179267c834 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_wsrep_notify_cmd_injection.test @@ -0,0 +1,30 @@ +# +# Joiner-supplied wsrep_node_name must not inject shell commands into +# the donor's wsrep_notify_cmd. Fails if "Notification command failed" +# co-occurs with ";touch" in node_1's error log. +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SELECT 1; + +--connection node_1 +call mtr.add_suppression('Process completed with error'); +call mtr.add_suppression('Notification command failed'); +call mtr.add_suppression('Unsafe characters in cluster member'); +--let $datadir=`select @@datadir` + +--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'WSREP_LOCAL_STATE_COMMENT' +--source include/wait_condition.inc + +--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc + +--sleep 2 + +--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err +--let SEARCH_PATTERN = Unsafe characters in cluster member +--source include/search_pattern_in_file.inc + +--list_files $datadir PWN diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc index bd2919a223e16..bb583755a4d2e 100644 --- a/sql/wsrep_notify.cc +++ b/sql/wsrep_notify.cc @@ -14,10 +14,38 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "mariadb.h" +#include #include #include "wsrep_priv.h" #include "wsrep_utils.h" +/* Allow only alnum and -_. */ +static bool is_valid_node_name(const char* s) +{ + if (!s) return true; + for (; *s; ++s) + { + unsigned char c= (unsigned char) *s; + if (!isalnum(c) && c != '-' && c != '_' && c != '.') + return false; + } + return true; +} + +/* Allow alnum and -_.:[]/ (host:port and [ipv6] forms). */ +static bool is_valid_node_addr(const char* s) +{ + if (!s) return true; + for (; *s; ++s) + { + unsigned char c= (unsigned char) *s; + if (!isalnum(c) && c != '-' && c != '_' && c != '.' && + c != ':' && c != '[' && c != ']' && c != '/') + return false; + } + return true; +} + void wsrep_notify_status(enum wsrep::server_state::state status, const wsrep::view* view) { @@ -67,13 +95,22 @@ void wsrep_notify_status(enum wsrep::server_state::state status, for (unsigned int i= 0; i < members.size(); i++) { + const char* name= members[i].name().c_str(); + const char* incoming= members[i].incoming().c_str(); + if (!is_valid_node_name(name) || !is_valid_node_addr(incoming)) + { + WSREP_ERROR("Unsafe characters in cluster member %u " + "wsrep_node_name or wsrep_node_incoming_address, " + "aborting notification.", i); + my_free(cmd_ptr); + return; + } std::ostringstream id; id << members[i].id(); cmd_off += snprintf(cmd_ptr + cmd_off, cmd_len - cmd_off, "%c%s/%s/%s", i > 0 ? ',' : ' ', id.str().c_str(), - members[i].name().c_str(), - members[i].incoming().c_str()); + name, incoming); } } } From b2050fdb4a8776422baf01a41bf86845994edb97 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 23 May 2026 12:31:36 +0200 Subject: [PATCH 23/29] strengthen safe() in wsrep_sst_common, just in case --- scripts/wsrep_sst_common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 0e05f8d621e1a..3009889cdefbd 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -31,7 +31,7 @@ fi safe() { - if [[ "${!1}" = *[\ \'\`]* ]]; then + if [[ "${!1}" = *[\ \'\`\$]* ]]; then wsrep_log_error "Invalid value for $1: ${!1}" exit 21 fi From fafcaa81f9839684b8f98e0824568634b2960420 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 18 May 2026 12:24:17 -0400 Subject: [PATCH 24/29] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index fa6843f2474d8..9289180a2f935 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=11 -MYSQL_VERSION_PATCH=17 +MYSQL_VERSION_PATCH=18 SERVER_MATURITY=stable From b6921bbfb07d37ead22a0697499fe1c753896ef6 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Fri, 29 May 2026 11:55:48 -0600 Subject: [PATCH 25/29] Test for MDEV-39788 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MDEV-39788 found that the recent refactor on the `main` (now 12.3) branch forgot that the line count includes the line count line itself. This test checks future changes in any supported version that they don’t make this mistake again. --- .../main/rpl_info_file_line_count.result | 12 +++ mysql-test/main/rpl_info_file_line_count.test | 75 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 mysql-test/main/rpl_info_file_line_count.result create mode 100644 mysql-test/main/rpl_info_file_line_count.test diff --git a/mysql-test/main/rpl_info_file_line_count.result b/mysql-test/main/rpl_info_file_line_count.result new file mode 100644 index 0000000000000..ebe9052cb50c4 --- /dev/null +++ b/mysql-test/main/rpl_info_file_line_count.result @@ -0,0 +1,12 @@ +CHANGE MASTER TO master_host='127.0.0.1'; +5 +./mysqld-relay-bin.000001 +4 + +0 +0 +# restart: --skip-slave-start +Master_SSL_Key = '' +Using_Gtid = 'Current_Pos' +SQL_Delay = '0' +CHANGE MASTER TO master_use_gtid=slave_pos; diff --git a/mysql-test/main/rpl_info_file_line_count.test b/mysql-test/main/rpl_info_file_line_count.test new file mode 100644 index 0000000000000..bb77b8ab508d8 --- /dev/null +++ b/mysql-test/main/rpl_info_file_line_count.test @@ -0,0 +1,75 @@ +# Line count / upgrading test for `@@master_info_file` & `@@relay_log_info_file` +# +# This regression test reminds that the line count includes the line count line. +# +# Reference: +# MDEV-39788 CHANGE MASTER savefiles read and write one line to many + +--source include/have_binlog_format_mixed.inc # format-agnostic +CHANGE MASTER TO master_host='127.0.0.1'; # have_info_files + +--let $MYSQLD_DATADIR= `SELECT @@datadir` + + +# `using_gtid` is the key-value section, not the 33rd option. +--remove_file $MYSQLD_DATADIR/master.info +--write_file $MYSQLD_DATADIR/master.info +33 + +4 +127.0.0.1 +root + +3306 +60 +1 + + + + + +1 +60.000 + + + +101010 + + + + + + + + + + + + + +using_gtid=1 +EOF + +# This file does not have the 6th option +# (neither does the current `@@relay_log_info_file`). +--cat_file $MYSQLD_DATADIR/relay-log.info +--remove_file $MYSQLD_DATADIR/relay-log.info +--write_file $MYSQLD_DATADIR/relay-log.info +6 +./mysqld-relay-bin.000001 +4 + +0 +0 +EOF + + +--let $restart_parameters= --skip-slave-start +--source include/restart_mysqld.inc + +--let $status_items= Master_SSL_Key, Using_Gtid, SQL_Delay +--source include/show_slave_status.inc + + +# Reset +CHANGE MASTER TO master_use_gtid=slave_pos; From cef52e2269473606440f605d03cb3793e43ae415 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Fri, 29 May 2026 12:57:49 -0600 Subject: [PATCH 26/29] fixup use RESET SLAVE ALL in case other tests restart the server without specifying `--skip-slave-start` (why not default in MTR I do not know) --- mysql-test/main/rpl_info_file_line_count.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/rpl_info_file_line_count.test b/mysql-test/main/rpl_info_file_line_count.test index bb77b8ab508d8..caea07e2a5d7e 100644 --- a/mysql-test/main/rpl_info_file_line_count.test +++ b/mysql-test/main/rpl_info_file_line_count.test @@ -33,7 +33,7 @@ root -101010 +100000 @@ -72,4 +72,4 @@ EOF # Reset -CHANGE MASTER TO master_use_gtid=slave_pos; +RESET SLAVE ALL; From 78ac3f84e04310aaef4b54dd5ad24994f408600d Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Fri, 29 May 2026 16:07:08 -0600 Subject: [PATCH 27/29] =?UTF-8?q?ye=20smol=20problem=20with=20test-result?= =?UTF-8?q?=20pairs=20is=20that=20it=E2=80=99s=20easy=20to=20forget=20to?= =?UTF-8?q?=20update=20the=20result?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql-test/main/rpl_info_file_line_count.result | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/rpl_info_file_line_count.result b/mysql-test/main/rpl_info_file_line_count.result index ebe9052cb50c4..af9a1ee8989c8 100644 --- a/mysql-test/main/rpl_info_file_line_count.result +++ b/mysql-test/main/rpl_info_file_line_count.result @@ -9,4 +9,6 @@ CHANGE MASTER TO master_host='127.0.0.1'; Master_SSL_Key = '' Using_Gtid = 'Current_Pos' SQL_Delay = '0' -CHANGE MASTER TO master_use_gtid=slave_pos; +RESET SLAVE ALL; +Warnings: +Note 4190 RESET SLAVE is implicitly changing the value of 'Using_Gtid' from 'Current_Pos' to 'Slave_Pos' From df587c18a2a9cef6048048f24fc6c2b28a60a370 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Fri, 29 May 2026 16:15:46 -0600 Subject: [PATCH 28/29] whoops. (RIP our CI today) --- mysql-test/main/rpl_info_file_line_count.result | 6 ------ mysql-test/main/rpl_info_file_line_count.test | 1 - 2 files changed, 7 deletions(-) diff --git a/mysql-test/main/rpl_info_file_line_count.result b/mysql-test/main/rpl_info_file_line_count.result index af9a1ee8989c8..0a747059c5558 100644 --- a/mysql-test/main/rpl_info_file_line_count.result +++ b/mysql-test/main/rpl_info_file_line_count.result @@ -1,10 +1,4 @@ CHANGE MASTER TO master_host='127.0.0.1'; -5 -./mysqld-relay-bin.000001 -4 - -0 -0 # restart: --skip-slave-start Master_SSL_Key = '' Using_Gtid = 'Current_Pos' diff --git a/mysql-test/main/rpl_info_file_line_count.test b/mysql-test/main/rpl_info_file_line_count.test index caea07e2a5d7e..568618e61442f 100644 --- a/mysql-test/main/rpl_info_file_line_count.test +++ b/mysql-test/main/rpl_info_file_line_count.test @@ -52,7 +52,6 @@ EOF # This file does not have the 6th option # (neither does the current `@@relay_log_info_file`). ---cat_file $MYSQLD_DATADIR/relay-log.info --remove_file $MYSQLD_DATADIR/relay-log.info --write_file $MYSQLD_DATADIR/relay-log.info 6 From 0d654f6bbf9643158792c4f2b69fbbf7af8c9ddb Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Fri, 29 May 2026 17:46:02 -0600 Subject: [PATCH 29/29] =?UTF-8?q?didn=E2=80=99t=20notice=20that=20null=20l?= =?UTF-8?q?ists=20were=20allowed=20in=20pre-12.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql-test/main/rpl_info_file_line_count.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/main/rpl_info_file_line_count.test b/mysql-test/main/rpl_info_file_line_count.test index 568618e61442f..aa338f6c37463 100644 --- a/mysql-test/main/rpl_info_file_line_count.test +++ b/mysql-test/main/rpl_info_file_line_count.test @@ -31,7 +31,7 @@ root 1 60.000 - +0 100000