diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index 125e265c1e7..d43b1c79f1f 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -207,7 +207,7 @@ static char TMPDIR[FN_REFLEN];
static char global_subst_from[200];
static char global_subst_to[200];
static char *global_subst= NULL;
-static char *read_command_buf= NULL;
+static char *read_command_buf= NULL, *read_command_buf_end;
static MEM_ROOT require_file_root;
static const my_bool my_true= 1;
static const my_bool my_false= 0;
@@ -3866,9 +3866,24 @@ end:
#endif
if (error)
{
- uint status= WEXITSTATUS(error);
+ uint status;
int i;
+#ifdef _WIN32
+ status= WEXITSTATUS(error);
+#else
+ /* WEXITSTATUS() is only valid for a normal exit; a process killed by an
+ uncaught signal must be translated using the shell's 128+signal
+ convention, or the real error is silently lost as status 0. */
+ if (WIFEXITED(error))
+ status= WEXITSTATUS(error);
+ else if (WIFSIGNALED(error))
+ status= 128 + WTERMSIG(error);
+ else
+ status= error;
+
+#endif
+
if (command->abort_on_error)
{
report_or_die("exec of '%s' failed, error: %d, status: %d, errno: %d\n"
@@ -5602,7 +5617,7 @@ static void primary(Expression_value *result, const char **s)
enum func_type func_type= get_expr_function_type(start,
end - start);
if (func_type == FUNC_UNKNOWN)
- die("Syntax error: Unknown function");
+ die("Syntax error: Unknown function '%.*s'", (int) (end - start), start);
*s= end + 1; // skip '('
handle_expr_function_call(func_type, result, s);
@@ -6049,47 +6064,48 @@ static void expr(Expression_value *result, const char **s)
static struct {
const char *name;
+ size_t length;
enum func_type type;
} function_table[]= {
// Numeric functions
- {"abs", FUNC_ABS},
- {"bin", FUNC_BIN},
- {"conv", FUNC_CONV},
- {"hex", FUNC_HEX},
- {"oct", FUNC_OCT},
+ {STRING_WITH_LEN("abs"), FUNC_ABS},
+ {STRING_WITH_LEN("bin"), FUNC_BIN},
+ {STRING_WITH_LEN("conv"), FUNC_CONV},
+ {STRING_WITH_LEN("hex"), FUNC_HEX},
+ {STRING_WITH_LEN("oct"), FUNC_OCT},
// String functions
- {"concat", FUNC_CONCAT},
- {"concat_ws", FUNC_CONCAT_WS},
- {"greatest", FUNC_GREATEST},
- {"insert", FUNC_INSERT},
- {"instr", FUNC_INSTR},
- {"lcase", FUNC_LOWER},
- {"least", FUNC_LEAST},
- {"length", FUNC_LENGTH},
- {"locate", FUNC_LOCATE},
- {"lower", FUNC_LOWER},
- {"lpad", FUNC_LPAD},
- {"ltrim", FUNC_LTRIM},
- {"repeat", FUNC_REPEAT},
- {"replace", FUNC_REPLACE},
- {"reverse", FUNC_REVERSE},
- {"rpad", FUNC_RPAD},
- {"rtrim", FUNC_RTRIM},
- {"substr", FUNC_SUBSTR},
- {"substring", FUNC_SUBSTR},
- {"substring_index", FUNC_SUBSTR_IDX},
- {"trim", FUNC_TRIM},
- {"ucase", FUNC_UPPER},
- {"upper", FUNC_UPPER},
+ {STRING_WITH_LEN("concat"), FUNC_CONCAT},
+ {STRING_WITH_LEN("concat_ws"), FUNC_CONCAT_WS},
+ {STRING_WITH_LEN("greatest"), FUNC_GREATEST},
+ {STRING_WITH_LEN("insert"), FUNC_INSERT},
+ {STRING_WITH_LEN("instr"), FUNC_INSTR},
+ {STRING_WITH_LEN("lcase"), FUNC_LOWER},
+ {STRING_WITH_LEN("least"), FUNC_LEAST},
+ {STRING_WITH_LEN("length"), FUNC_LENGTH},
+ {STRING_WITH_LEN("locate"), FUNC_LOCATE},
+ {STRING_WITH_LEN("lower"), FUNC_LOWER},
+ {STRING_WITH_LEN("lpad"), FUNC_LPAD},
+ {STRING_WITH_LEN("ltrim"), FUNC_LTRIM},
+ {STRING_WITH_LEN("repeat"), FUNC_REPEAT},
+ {STRING_WITH_LEN("replace"), FUNC_REPLACE},
+ {STRING_WITH_LEN("reverse"), FUNC_REVERSE},
+ {STRING_WITH_LEN("rpad"), FUNC_RPAD},
+ {STRING_WITH_LEN("rtrim"), FUNC_RTRIM},
+ {STRING_WITH_LEN("substr"), FUNC_SUBSTR},
+ {STRING_WITH_LEN("substring"), FUNC_SUBSTR},
+ {STRING_WITH_LEN("substring_index"), FUNC_SUBSTR_IDX},
+ {STRING_WITH_LEN("trim"), FUNC_TRIM},
+ {STRING_WITH_LEN("ucase"), FUNC_UPPER},
+ {STRING_WITH_LEN("upper"), FUNC_UPPER},
// Regexp functions
- {"regexp_instr", FUNC_REGEXP_INSTR},
- {"regexp_replace", FUNC_REGEXP_REPLACE},
- {"regexp_substr", FUNC_REGEXP_SUBSTR},
+ {STRING_WITH_LEN("regexp_instr"), FUNC_REGEXP_INSTR},
+ {STRING_WITH_LEN("regexp_replace"), FUNC_REGEXP_REPLACE},
+ {STRING_WITH_LEN("regexp_substr"), FUNC_REGEXP_SUBSTR},
// Null functions
- {"coalesce", FUNC_COALESCE},
- {"ifnull", FUNC_IFNULL},
- {"nullif", FUNC_NULLIF},
- {NULL, FUNC_UNKNOWN}
+ {STRING_WITH_LEN("coalesce"), FUNC_COALESCE},
+ {STRING_WITH_LEN("ifnull"), FUNC_IFNULL},
+ {STRING_WITH_LEN("nullif"), FUNC_NULLIF},
+ {NULL, 0, FUNC_UNKNOWN}
};
@@ -6329,9 +6345,9 @@ void func_oct(Expression_value args[], int count, Expression_value *result)
@param[out] result Expression_value to store result
@details
- Converts a number to hexadecimal representation.
HEX(N) returns a string representation of the hexadecimal value of N.
This is equivalent to CONV(N, 10, 16).
+ HEX(str) returns a hexadecimal representation of the bytes of str.
@note Dies if argument count != 1
*/
@@ -6341,7 +6357,15 @@ void func_hex(Expression_value args[], int count, Expression_value *result)
if (count != 1)
die("hex() expects 1 argument, got %d", count);
- convert_base_helper(args[0].to_string(), 10, 16, result);
+ if (args[0].is_numeric)
+ convert_base_helper(args[0].to_string(), 10, 16, result);
+ else
+ {
+ My_string str= args[0].to_string();
+ My_string hex_str;
+ hex_str.set_hex(str.ptr(), str.length());
+ result->set_string(hex_str.ptr(), hex_str.length());
+ }
}
@@ -7605,7 +7629,8 @@ enum func_type get_expr_function_type(const char *name, size_t len)
{
for (int i= 0; function_table[i].name; ++i)
{
- if (!strncasecmp(function_table[i].name, name, len))
+ if (function_table[i].length == len &&
+ !strncasecmp(function_table[i].name, name, len))
return function_table[i].type;
}
return FUNC_UNKNOWN;
@@ -9687,7 +9712,7 @@ int read_line()
*p= 0;
DBUG_PRINT("exit", ("Found delimiter '%s' at line %d",
delimiter, cur_file->lineno));
- DBUG_RETURN(0);
+ goto ret;
}
else if ((c == '{' &&
(!my_strnncoll_simple(charset_info, (const uchar*) "while", 5,
@@ -9700,7 +9725,7 @@ int read_line()
*p= 0;
DBUG_PRINT("exit", ("Found '{' indicating start of block at line %d",
cur_file->lineno));
- DBUG_RETURN(0);
+ goto ret;
}
else if (c == '\'' || c == '"' || c == '`')
{
@@ -9734,7 +9759,7 @@ int read_line()
*p= 0;
DBUG_PRINT("exit", ("Found newline in comment at line: %d",
cur_file->lineno));
- DBUG_RETURN(0);
+ goto ret;
}
break;
@@ -9754,7 +9779,7 @@ int read_line()
DBUG_PRINT("info", ("Found two new lines in a row"));
*p++= c;
*p= 0;
- DBUG_RETURN(0);
+ goto ret;
}
/* Query hasn't started yet */
@@ -9771,7 +9796,7 @@ int read_line()
*p= 0;
DBUG_PRINT("exit", ("Found delimiter '%s' at line: %d",
delimiter, cur_file->lineno));
- DBUG_RETURN(0);
+ goto ret;
}
else if (c == '}')
{
@@ -9780,7 +9805,7 @@ int read_line()
*p= 0;
DBUG_PRINT("exit", ("Found '}' in beginning of a line at line: %d",
cur_file->lineno));
- DBUG_RETURN(0);
+ goto ret;
}
else if (c == '\'' || c == '"' || c == '`')
{
@@ -9839,6 +9864,8 @@ int read_line()
}
}
}
+ret:
+ read_command_buf_end= p;
DBUG_RETURN(0);
}
@@ -9854,14 +9881,13 @@ int read_line()
*/
-void convert_to_format_v1(char* query)
+void convert_to_format_v1(char* query, char **end)
{
int last_c_was_quote= 0;
char *p= query, *to= query;
- char *end= strend(query);
char last_c;
- while (p <= end)
+ while (p <= *end)
{
if (*p == '\n' && !last_c_was_quote)
{
@@ -9892,6 +9918,7 @@ void convert_to_format_v1(char* query)
last_c_was_quote= 0;
}
}
+ *end= to;
}
@@ -10008,9 +10035,9 @@ int read_command(struct st_command** command_ptr)
}
if (opt_result_format_version == 1)
- convert_to_format_v1(read_command_buf);
+ convert_to_format_v1(read_command_buf, &read_command_buf_end);
- char *p= read_command_buf;
+ char *p= read_command_buf, *end= read_command_buf_end;
DBUG_PRINT("info", ("query: '%s'", read_command_buf));
if (*p == '#')
{
@@ -10027,29 +10054,32 @@ int read_command(struct st_command** command_ptr)
}
/* Skip leading spaces */
- while (*p && my_isspace(charset_info, *p))
+ while (p < end && my_isspace(charset_info, *p))
p++;
- if (!(command->query_buf= command->query= my_strdup(PSI_NOT_INSTRUMENTED, p, MYF(MY_WME))))
+ if (!(command->query_buf= command->query=
+ (char*)my_memdup(PSI_NOT_INSTRUMENTED, p, end - p, MYF(MY_WME))))
die("Out of memory");
+ command->query_len= (int)(end - p - 1);
+ command->end= command->query + command->query_len;
+ p= command->query;
+ end= command->end;
/*
Calculate first word length(the command), terminated
- by 'space' , '(' or 'delimiter' */
- p= command->query;
- while (*p && !my_isspace(charset_info, *p) && *p != '(' && !is_delimiter(p))
+ by 'space' , '(' or 'delimiter'
+ */
+ while (p < end && !my_isspace(charset_info, *p) && *p != '(' && !is_delimiter(p))
p++;
command->first_word_len= (uint) (p - command->query);
DBUG_PRINT("info", ("first_word: %.*s",
command->first_word_len, command->query));
/* Skip spaces between command and first argument */
- while (*p && my_isspace(charset_info, *p))
+ while (p < end && my_isspace(charset_info, *p))
p++;
command->first_argument= p;
- command->end= strend(command->query);
- command->query_len= (int)(command->end - command->query);
parser.read_lines++;
DBUG_RETURN(0);
}
@@ -12351,7 +12381,7 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
else
{
query = command->query;
- query_len = strlen(query);
+ query_len = command->query_len;
}
/*
@@ -12741,6 +12771,7 @@ void get_command_type(struct st_command* command)
if (type == Q_QUERY)
{
/* Skip the "query" part */
+ command->query_len-= (int)(command->first_argument - command->query);
command->query= command->first_argument;
}
}
@@ -13312,7 +13343,8 @@ int main(int argc, char **argv)
if (command->query == command->query_buf)
{
/* Skip the first part of command, i.e query_xxx */
- command->query= command->first_argument;
+ command->query_len-= (int)(command->first_argument - command->query);
+ command->query= command->first_argument;
command->first_word_len= 0;
}
/* fall through */
@@ -13374,7 +13406,10 @@ int main(int argc, char **argv)
/* Remove "send" if this is first iteration */
if (command->query == command->query_buf)
+ {
+ command->query_len-= (int)(command->first_argument - command->query);
command->query= command->first_argument;
+ }
/*
run_query() can execute a query partially, depending on the flags.
diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake
index 706a8156095..82d437fc1b8 100644
--- a/cmake/cpack_rpm.cmake
+++ b/cmake/cpack_rpm.cmake
@@ -248,7 +248,7 @@ IF(WITH_WSREP)
SETA(CPACK_RPM_server_PACKAGE_REQUIRES
"galera-4" "rsync" "grep" "gawk" "iproute"
"coreutils" "findutils" "tar")
- SETA(CPACK_RPM_server_PACKAGE_RECOMMENDS "lsof" "socat" "pv")
+ SETA(CPACK_RPM_server_PACKAGE_RECOMMENDS "lsof" "socat" "pv" "stunnel")
SETA(CPACK_RPM_test_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES}" "socat")
ENDIF()
diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake
index 9410bc7a48a..1ebf5013730 100644
--- a/cmake/install_layout.cmake
+++ b/cmake/install_layout.cmake
@@ -64,6 +64,9 @@
#
# - INSTALL_UNIX_ADDRDIR (path to mysql.sock)
#
+# - INSTALL_RUNDIR (runtime state files that mariadbd must not write,
+# e.g. what systemd reads as EnvironmentFile)
+#
IF(NOT INSTALL_LAYOUT)
IF(DEB)
@@ -163,7 +166,7 @@ SET(INSTALL_UNIX_ADDRDIR_RPM "${INSTALL_MYSQLDATADIR_RPM}/mysql.sock"
SET(INSTALL_SYSTEMD_UNITDIR_RPM "/usr/lib/systemd/system")
SET(INSTALL_SYSTEMD_SYSUSERSDIR_RPM "/usr/lib/sysusers.d")
SET(INSTALL_SYSTEMD_TMPFILESDIR_RPM "/usr/lib/tmpfiles.d")
-SET(INSTALL_RUNDATADIR_RPM "/run/mariadb")
+SET(INSTALL_RUNDIR_RPM "/run")
SET(INSTALL_PAMDIR_RPM "/${INSTALL_LIBDIR_RPM}/security")
SET(INSTALL_PAMDATADIR_RPM "/etc/security")
@@ -194,8 +197,8 @@ SET(INSTALL_SUPPORTFILESDIR_DEB "share/mysql")
#
SET(INSTALL_MYSQLDATADIR_DEB "/var/lib/mysql")
-SET(INSTALL_RUNDATADIR_DEB "/run/mysqld")
-SET(INSTALL_UNIX_ADDRDIR_DEB "${INSTALL_RUNDATADIR_DEB}/mysqld.sock")
+SET(INSTALL_RUNDIR_DEB "/run")
+SET(INSTALL_UNIX_ADDRDIR_DEB "${INSTALL_RUNDIR_DEB}/mysqld/mysqld.sock")
SET(INSTALL_SYSTEMD_UNITDIR_DEB "/lib/systemd/system")
SET(INSTALL_SYSTEMD_SYSUSERSDIR_DEB "/usr/lib/sysusers.d")
SET(INSTALL_SYSTEMD_TMPFILESDIR_DEB "/usr/lib/tmpfiles.d")
@@ -259,7 +262,10 @@ IF(NOT MYSQL_UNIX_ADDR)
SET(MYSQL_UNIX_ADDR ${INSTALL_UNIX_ADDRDIR})
ENDIF()
-IF(NOT INSTALL_RUNDATADIR)
+IF(NOT INSTALL_RUNDIR)
+ # No /run in a tarball installation - fall back to the socket directory.
+ # Note that mariadbd can write there, so the isolation that /run gives to
+ # packages (see EnvironmentFile= in mariadb.service) is not achieved.
get_filename_component(MYSQL_UNIX_DIR ${MYSQL_UNIX_ADDR} DIRECTORY)
- SET(INSTALL_RUNDATADIR "${MYSQL_UNIX_DIR}" CACHE FILEPATH "Rundata installation directory" ${FORCE})
+ SET(INSTALL_RUNDIR "${MYSQL_UNIX_DIR}" CACHE FILEPATH "Runtime state directory" ${FORCE})
ENDIF()
diff --git a/debian/control b/debian/control
index 5810bb1e4c0..e9788e5ceb6 100644
--- a/debian/control
+++ b/debian/control
@@ -676,7 +676,8 @@ Architecture: any
Suggests: mariadb-test,
netcat-openbsd
Recommends: libhtml-template-perl,
- pv
+ pv,
+ stunnel
Pre-Depends: adduser (>= 3.40),
debconf,
mariadb-common (>= ${source:Version})
diff --git a/libmariadb b/libmariadb
index 93bb9266666..35c41cddb3c 160000
--- a/libmariadb
+++ b/libmariadb
@@ -1 +1 @@
-Subproject commit 93bb9266666a0a838187679ad2cc14af169895da
+Subproject commit 35c41cddb3c16e9d80dee55158a59118a8fd831d
diff --git a/mysql-test/main/alter_table_combinations.result b/mysql-test/main/alter_table_combinations.result
index cbf98f620ef..7eeb97d659d 100644
--- a/mysql-test/main/alter_table_combinations.result
+++ b/mysql-test/main/alter_table_combinations.result
@@ -321,4 +321,13 @@ drop table t1;
#
# End of 10.5 tests
#
+#
+# MDEV-31808 Server crash upon altering table with NEXTVAL for default under exclusive lock
+#
+CREATE SEQUENCE s ENGINE=Aria;
+CREATE TABLE t (a INT DEFAULT(NEXTVAL(s)), b INT);
+ALTER TABLE t FORCE, ALGORITHM=COPY, LOCK=EXCLUSIVE;
+DROP TABLE t;
+DROP SEQUENCE s;
+# End of 10.6 tests
set @@default_storage_engine= @save_default_engine;
diff --git a/mysql-test/main/alter_table_combinations.test b/mysql-test/main/alter_table_combinations.test
index 7c8d7f42096..b208f0e4416 100644
--- a/mysql-test/main/alter_table_combinations.test
+++ b/mysql-test/main/alter_table_combinations.test
@@ -260,4 +260,18 @@ drop table t1;
--echo # End of 10.5 tests
--echo #
+--echo #
+--echo # MDEV-31808 Server crash upon altering table with NEXTVAL for default under exclusive lock
+--echo #
+
+CREATE SEQUENCE s ENGINE=Aria;
+CREATE TABLE t (a INT DEFAULT(NEXTVAL(s)), b INT);
+ALTER TABLE t FORCE, ALGORITHM=COPY, LOCK=EXCLUSIVE;
+
+# Cleanup
+DROP TABLE t;
+DROP SEQUENCE s;
+
+--echo # End of 10.6 tests
+
set @@default_storage_engine= @save_default_engine;
diff --git a/mysql-test/main/gis-json.result b/mysql-test/main/gis-json.result
index 49ec7739458..912fb405327 100644
--- a/mysql-test/main/gis-json.result
+++ b/mysql-test/main/gis-json.result
@@ -110,6 +110,8 @@ Warning 4076 Incorrect GeoJSON format - empty 'coordinates' array.
SELECT ST_GEOMFROMGEOJSON("{ \"type\": \"Feature\", \"geometry\": [10, 20] }") as exp;
exp
NULL
+Warnings:
+Warning 4048 Incorrect GeoJSON format specified for st_geomfromgeojson function.
SELECT ST_ASTEXT (ST_GEOMFROMGEOJSON ('{ "type": "GEOMETRYCOLLECTION", "coordinates": [102.0, 0.0]}')) as exp;
exp
NULL
@@ -135,7 +137,126 @@ repeat(']}', 2000)
exp
NULL
Warnings:
-Warning 4040 Limit of 32 on JSON nested structures depth is reached in argument 1 to function 'st_geomfromgeojson' at position 473
+Warning 4040 Limit of 32 on JSON nested structures depth is reached in argument 1 to function 'st_geomfromgeojson' at position 688
+# Boundary condition: foreign-member nesting at depth 32
+SET @geom := '{"type":"Point","coordinates":[1,2]}';
+SET @doc := CONCAT(
+REPEAT('{"x":', 29),
+@geom,
+REPEAT('}', 29)
+);
+SELECT ST_ASTEXT( ST_GeomFromGeoJSON(@doc) ) AS expr;
+expr
+NULL
+Warnings:
+Warning 4048 Incorrect GeoJSON format specified for st_geomfromgeojson function.
+# Foreign-member nesting exceeds depth 32
+SET @geom := '{"type":"Point","coordinates":[1,2]}';
+SET @doc := CONCAT(
+REPEAT('{"x":', 30),
+@geom,
+REPEAT('}', 30)
+);
+SELECT ST_GeomFromGeoJSON(@doc) AS expr;
+expr
+NULL
+Warnings:
+Warning 4040 Limit of 32 on JSON nested structures depth is reached in argument 1 to function 'st_geomfromgeojson' at position 181
+# Deep foreign member attached to otherwise valid GeoJSON
+SET @foreign := CONCAT(
+REPEAT('{"x":', 28),
+'{"leaf":1}',
+REPEAT('}', 28)
+);
+SET @doc := CONCAT(
+'{"type":"Point","coordinates":[10,20],"foreign":',
+@foreign,
+'}'
+);
+SELECT ST_ASTEXT(ST_GeomFromGeoJSON(@doc)) AS expr;
+expr
+POINT(10 20)
+# Foreign member exceeds depth limit
+SET @foreign := CONCAT(
+REPEAT('{"x":', 29),
+'{"leaf":1}',
+REPEAT('}', 29)
+);
+SET @doc := CONCAT(
+'{"type":"Point","coordinates":[10,20],"foreign":',
+@foreign,
+'}'
+);
+SELECT ST_ASTEXT(ST_GeomFromGeoJSON(@doc)) AS expr;
+expr
+POINT(10 20)
+# GeometryCollection containing 33 valid GeoJSON Point objects
+SET @point := '{"type":"Point","coordinates":[1,2]}';
+SET @geoms := CONCAT(
+@point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+@point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+@point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+@point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+@point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+@point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+@point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+@point, ',', @point, ',', @point
+);
+SET @doc := CONCAT(
+'{"type":"GeometryCollection","geometries":[',
+@geoms,
+']}'
+);
+SELECT ST_AsText(ST_GeomFromGeoJSON(@doc)) AS expr;
+expr
+GEOMETRYCOLLECTION(POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2),POINT(1 2))
+#
+# MDEV-39981: ST_GEOMFROMGEOJSON returns wrong result with reversed key order
+#
+# GeometryCollection: type before geometries (baseline)
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"type":"GeometryCollection","geometries":[]}')) as expr;
+expr
+GEOMETRYCOLLECTION EMPTY
+# GeometryCollection: geometries before type (empty)
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[],"type":"GeometryCollection"}')) as expr;
+expr
+GEOMETRYCOLLECTION EMPTY
+# GeometryCollection: geometries before type (non-empty)
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[{"type":"Point","coordinates":[0,1]}],"type":"GeometryCollection"}')) as expr;
+expr
+GEOMETRYCOLLECTION(POINT(0 1))
+# GeometryCollection: multiple geometries before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[{"type":"Point","coordinates":[1,2]},{"type":"Point","coordinates":[3,4]}],"type":"GeometryCollection"}')) as expr;
+expr
+GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))
+# Point: coordinates before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"coordinates":[0,1],"type":"Point"}')) as expr;
+expr
+POINT(0 1)
+# LineString: coordinates before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"coordinates":[[0,0],[1,1],[2,2]],"type":"LineString"}')) as expr;
+expr
+LINESTRING(0 0,1 1,2 2)
+# Polygon: coordinates before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"coordinates":[[[0,0],[1,0],[1,1],[0,1],[0,0]]],"type":"Polygon"}')) as expr;
+expr
+POLYGON((0 0,1 0,1 1,0 1,0 0))
+# FeatureCollection: features before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"features":[{"geometry":{"type":"Point","coordinates":[5,6]},"type":"Feature","properties":{}}],"type":"FeatureCollection"}')) as expr;
+expr
+GEOMETRYCOLLECTION(POINT(5 6))
+# Feature: geometry before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometry":{"coordinates":[7,8],"type":"Point"},"type":"Feature","properties":{}}')) as expr;
+expr
+POINT(7 8)
+# Unknown keys interspersed (should be ignored)
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"foo":"bar","geometries":[],"type":"GeometryCollection","extra":123}')) as expr;
+expr
+GEOMETRYCOLLECTION EMPTY
+# Deeply nested geometries before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[{"geometries":[{"type":"Point","coordinates":[9,10]}],"type":"GeometryCollection"}],"type":"GeometryCollection"}')) as expr;
+expr
+GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(9 10)))
# End of 10.6 tests
#
# MDEV-34079: ST_AsGeoJSON returns incorrect value for empty geometry
diff --git a/mysql-test/main/gis-json.test b/mysql-test/main/gis-json.test
index ca402d1c2ef..dbbf7b7f667 100644
--- a/mysql-test/main/gis-json.test
+++ b/mysql-test/main/gis-json.test
@@ -70,6 +70,120 @@ SELECT ST_GeomFromGeoJSON(
repeat(']}', 2000)
)) as exp;
+--echo # Boundary condition: foreign-member nesting at depth 32
+SET @geom := '{"type":"Point","coordinates":[1,2]}';
+
+SET @doc := CONCAT(
+ REPEAT('{"x":', 29),
+ @geom,
+ REPEAT('}', 29)
+);
+
+SELECT ST_ASTEXT( ST_GeomFromGeoJSON(@doc) ) AS expr;
+
+
+--echo # Foreign-member nesting exceeds depth 32
+SET @geom := '{"type":"Point","coordinates":[1,2]}';
+
+SET @doc := CONCAT(
+ REPEAT('{"x":', 30),
+ @geom,
+ REPEAT('}', 30)
+);
+
+SELECT ST_GeomFromGeoJSON(@doc) AS expr;
+
+
+--echo # Deep foreign member attached to otherwise valid GeoJSON
+SET @foreign := CONCAT(
+ REPEAT('{"x":', 28),
+ '{"leaf":1}',
+ REPEAT('}', 28)
+);
+
+SET @doc := CONCAT(
+ '{"type":"Point","coordinates":[10,20],"foreign":',
+ @foreign,
+ '}'
+);
+
+SELECT ST_ASTEXT(ST_GeomFromGeoJSON(@doc)) AS expr;
+
+
+--echo # Foreign member exceeds depth limit
+SET @foreign := CONCAT(
+ REPEAT('{"x":', 29),
+ '{"leaf":1}',
+ REPEAT('}', 29)
+);
+
+SET @doc := CONCAT(
+ '{"type":"Point","coordinates":[10,20],"foreign":',
+ @foreign,
+ '}'
+);
+
+SELECT ST_ASTEXT(ST_GeomFromGeoJSON(@doc)) AS expr;
+
+--echo # GeometryCollection containing 33 valid GeoJSON Point objects
+SET @point := '{"type":"Point","coordinates":[1,2]}';
+
+SET @geoms := CONCAT(
+ @point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+ @point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+ @point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+ @point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+ @point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+ @point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+ @point, ',', @point, ',', @point, ',', @point, ',', @point, ',',
+ @point, ',', @point, ',', @point
+);
+
+SET @doc := CONCAT(
+ '{"type":"GeometryCollection","geometries":[',
+ @geoms,
+ ']}'
+);
+
+SELECT ST_AsText(ST_GeomFromGeoJSON(@doc)) AS expr;
+
+--echo #
+--echo # MDEV-39981: ST_GEOMFROMGEOJSON returns wrong result with reversed key order
+--echo #
+
+--echo # GeometryCollection: type before geometries (baseline)
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"type":"GeometryCollection","geometries":[]}')) as expr;
+
+--echo # GeometryCollection: geometries before type (empty)
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[],"type":"GeometryCollection"}')) as expr;
+
+--echo # GeometryCollection: geometries before type (non-empty)
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[{"type":"Point","coordinates":[0,1]}],"type":"GeometryCollection"}')) as expr;
+
+--echo # GeometryCollection: multiple geometries before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[{"type":"Point","coordinates":[1,2]},{"type":"Point","coordinates":[3,4]}],"type":"GeometryCollection"}')) as expr;
+
+--echo # Point: coordinates before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"coordinates":[0,1],"type":"Point"}')) as expr;
+
+--echo # LineString: coordinates before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"coordinates":[[0,0],[1,1],[2,2]],"type":"LineString"}')) as expr;
+
+--echo # Polygon: coordinates before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"coordinates":[[[0,0],[1,0],[1,1],[0,1],[0,0]]],"type":"Polygon"}')) as expr;
+
+--echo # FeatureCollection: features before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"features":[{"geometry":{"type":"Point","coordinates":[5,6]},"type":"Feature","properties":{}}],"type":"FeatureCollection"}')) as expr;
+
+--echo # Feature: geometry before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometry":{"coordinates":[7,8],"type":"Point"},"type":"Feature","properties":{}}')) as expr;
+
+--echo # Unknown keys interspersed (should be ignored)
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"foo":"bar","geometries":[],"type":"GeometryCollection","extra":123}')) as expr;
+
+--echo # Deeply nested geometries before type
+SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[{"geometries":[{"type":"Point","coordinates":[9,10]}],"type":"GeometryCollection"}],"type":"GeometryCollection"}')) as expr;
+
--echo # End of 10.6 tests
--echo #
diff --git a/mysql-test/main/grant5.result b/mysql-test/main/grant5.result
index d67e3443fe3..941afe73a73 100644
--- a/mysql-test/main/grant5.result
+++ b/mysql-test/main/grant5.result
@@ -494,6 +494,34 @@ CREATE USER for u2@localhost
CREATE USER `u2`@`localhost` IDENTIFIED BY PASSWORD '*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD'
drop user u1@localhost;
drop user u2@localhost;
+#
+# MDEV-40541 role vs user@localhost acl_cache key confusion
+#
+create database db;
+create table db.t1(a varchar(40));
+insert into db.t1 values ('role-cache-collision-row');
+create role r1;
+create user r1@localhost identified by 'r1pass';
+create user u1@'127.0.0.1' identified by 'u1pass';
+grant select on db.* to r1@localhost;
+grant r1 to u1@'127.0.0.1';
+connect r1,localhost,r1,r1pass;
+select a as precache from db.t1;
+precache
+role-cache-collision-row
+connect u1,127.0.0.1,u1,u1pass;
+set role r1;
+show grants;
+Grants for u1@127.0.0.1
+GRANT `r1` TO `u1`@`127.0.0.1`
+GRANT USAGE ON *.* TO `u1`@`127.0.0.1` IDENTIFIED BY PASSWORD '*4C5C0A2C80D7567C7CFBDFC09409901AADC4B390'
+GRANT USAGE ON *.* TO `r1`
+select a from db.t1;
+ERROR 42000: SELECT command denied to user 'u1'@'localhost' for table `db`.`t1`
+connection default;
+drop database db;
+drop role r1;
+drop user r1@localhost, u1@'127.0.0.1';
# End of 10.6 tests
#
# MDEV-37256: The permission check of LOAD INDEX INTO CACHE and CACHE INDEX is broken
diff --git a/mysql-test/main/grant5.test b/mysql-test/main/grant5.test
index 249bb5790d0..62f538145e0 100644
--- a/mysql-test/main/grant5.test
+++ b/mysql-test/main/grant5.test
@@ -455,6 +455,35 @@ show create user u2@localhost;
drop user u1@localhost;
drop user u2@localhost;
+--echo #
+--echo # MDEV-40541 role vs user@localhost acl_cache key confusion
+--echo #
+create database db;
+create table db.t1(a varchar(40));
+insert into db.t1 values ('role-cache-collision-row');
+
+create role r1;
+create user r1@localhost identified by 'r1pass';
+create user u1@'127.0.0.1' identified by 'u1pass';
+
+grant select on db.* to r1@localhost;
+grant r1 to u1@'127.0.0.1';
+#flush privileges;
+
+connect r1,localhost,r1,r1pass;
+select a as precache from db.t1;
+
+connect u1,127.0.0.1,u1,u1pass;
+set role r1;
+show grants;
+--error ER_TABLEACCESS_DENIED_ERROR
+select a from db.t1;
+
+connection default;
+drop database db;
+drop role r1;
+drop user r1@localhost, u1@'127.0.0.1';
+
--echo # End of 10.6 tests
--echo #
diff --git a/mysql-test/main/intersect_all.result b/mysql-test/main/intersect_all.result
index 966053c7c98..28268655074 100644
--- a/mysql-test/main/intersect_all.result
+++ b/mysql-test/main/intersect_all.result
@@ -1356,3 +1356,69 @@ a b
1 2
drop tables t1, t2, t3;
set sql_mode= default;
+#
+# MDEV-38722 server crash hp_rec_key_cmp
+#
+# original reproducer (used to crash), returns a single row
+SELECT 1 INTERSECT SELECT 1 UNION ALL SELECT 1 EXCEPT ALL SELECT 1;
+1
+1
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (1),(1),(2),(3);
+CREATE TABLE t2 (i INT);
+INSERT INTO t2 VALUES (1),(2),(2);
+CREATE TABLE t3 (i INT);
+INSERT INTO t3 VALUES (1),(3);
+SELECT i FROM t1 INTERSECT SELECT i FROM t3
+UNION ALL SELECT i FROM t2 EXCEPT ALL SELECT i FROM t3 ORDER BY i;
+i
+1
+2
+2
+(((SELECT i FROM t1) INTERSECT (SELECT i FROM t3)) UNION ALL (SELECT i FROM t2))
+EXCEPT ALL (SELECT i FROM t3) ORDER BY i;
+i
+1
+2
+2
+# trailing UNION ALL after the EXCEPT ALL
+SELECT i FROM t1 INTERSECT SELECT i FROM t2 UNION ALL SELECT i FROM t2
+EXCEPT ALL SELECT i FROM t3 UNION ALL SELECT i FROM t1 ORDER BY i;
+i
+1
+1
+1
+2
+2
+2
+2
+3
+((((SELECT i FROM t1) INTERSECT (SELECT i FROM t2)) UNION ALL (SELECT i FROM t2))
+EXCEPT ALL (SELECT i FROM t3)) UNION ALL (SELECT i FROM t1) ORDER BY i;
+i
+1
+1
+1
+2
+2
+2
+2
+3
+# a leading INTERSECT ALL keeps the operation extended while the last
+# INTERSECT DISTINCT node is the index-release point
+SELECT i FROM t1 INTERSECT ALL SELECT i FROM t2 INTERSECT SELECT i FROM t3
+UNION ALL SELECT i FROM t2 ORDER BY i;
+i
+1
+1
+2
+2
+(((SELECT i FROM t1) INTERSECT ALL (SELECT i FROM t2)) INTERSECT (SELECT i FROM t3))
+UNION ALL (SELECT i FROM t2) ORDER BY i;
+i
+1
+1
+2
+2
+DROP TABLE t1,t2,t3;
+# End of 10.6 tests
diff --git a/mysql-test/main/intersect_all.test b/mysql-test/main/intersect_all.test
index c3dc4e123f0..75d08182f80 100644
--- a/mysql-test/main/intersect_all.test
+++ b/mysql-test/main/intersect_all.test
@@ -497,3 +497,34 @@ select * from t1 except all select * from t2 intersect all select * from t1 unio
select * from t1 except all select * from t2 intersect all select * from t1 union all select * from t2 order by a desc limit 3;
drop tables t1, t2, t3;
set sql_mode= default;
+
+--echo #
+--echo # MDEV-38722 server crash hp_rec_key_cmp
+--echo #
+--echo # original reproducer (used to crash), returns a single row
+SELECT 1 INTERSECT SELECT 1 UNION ALL SELECT 1 EXCEPT ALL SELECT 1;
+
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (1),(1),(2),(3);
+CREATE TABLE t2 (i INT);
+INSERT INTO t2 VALUES (1),(2),(2);
+CREATE TABLE t3 (i INT);
+INSERT INTO t3 VALUES (1),(3);
+SELECT i FROM t1 INTERSECT SELECT i FROM t3
+ UNION ALL SELECT i FROM t2 EXCEPT ALL SELECT i FROM t3 ORDER BY i;
+(((SELECT i FROM t1) INTERSECT (SELECT i FROM t3)) UNION ALL (SELECT i FROM t2))
+ EXCEPT ALL (SELECT i FROM t3) ORDER BY i;
+--echo # trailing UNION ALL after the EXCEPT ALL
+SELECT i FROM t1 INTERSECT SELECT i FROM t2 UNION ALL SELECT i FROM t2
+ EXCEPT ALL SELECT i FROM t3 UNION ALL SELECT i FROM t1 ORDER BY i;
+((((SELECT i FROM t1) INTERSECT (SELECT i FROM t2)) UNION ALL (SELECT i FROM t2))
+ EXCEPT ALL (SELECT i FROM t3)) UNION ALL (SELECT i FROM t1) ORDER BY i;
+--echo # a leading INTERSECT ALL keeps the operation extended while the last
+--echo # INTERSECT DISTINCT node is the index-release point
+SELECT i FROM t1 INTERSECT ALL SELECT i FROM t2 INTERSECT SELECT i FROM t3
+ UNION ALL SELECT i FROM t2 ORDER BY i;
+(((SELECT i FROM t1) INTERSECT ALL (SELECT i FROM t2)) INTERSECT (SELECT i FROM t3))
+ UNION ALL (SELECT i FROM t2) ORDER BY i;
+DROP TABLE t1,t2,t3;
+
+--echo # End of 10.6 tests
diff --git a/mysql-test/main/lotofstack.result b/mysql-test/main/lotofstack.result
index 6f776eb6733..eb51ccd8e04 100644
--- a/mysql-test/main/lotofstack.result
+++ b/mysql-test/main/lotofstack.result
@@ -103,4 +103,16 @@ drop table t3|
# MDEV-40409 ST_GeomFromText stack overrun on deeply nested GeometryCollection
#
SELECT ST_GeomFromText(CONCAT(REPEAT('GEOMETRYCOLLECTION(',5000),'POINT(1 1)',REPEAT(')',5000)));
+#
+# MDEV-40540 ST_GeomFromWKB stack overrun on deeply nested GeometryCollection
+#
+set @a=concat(0x0107000000, repeat(0x010000000107000000, 120000), 0x00000000);
+SELECT ST_GeomFromWKB(@a);
+#
+# MDEV-39750 ExtractValue does not control recursion depth.
+#
+SELECT ExtractValue('', REPEAT('(', 100000));
+ERROR HY000: Thread stack overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed. Consider increasing the thread_stack system variable.
+SELECT ExtractValue('', REPEAT('/n', 100000));
+ERROR HY000: Thread stack overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed. Consider increasing the thread_stack system variable.
# End of 10.6 tests
diff --git a/mysql-test/main/lotofstack.test b/mysql-test/main/lotofstack.test
index 20d9789b99c..b8ce7f566c4 100644
--- a/mysql-test/main/lotofstack.test
+++ b/mysql-test/main/lotofstack.test
@@ -147,4 +147,24 @@ delimiter ;|
SELECT ST_GeomFromText(CONCAT(REPEAT('GEOMETRYCOLLECTION(',5000),'POINT(1 1)',REPEAT(')',5000)));
--enable_result_log
+--echo #
+--echo # MDEV-40540 ST_GeomFromWKB stack overrun on deeply nested GeometryCollection
+--echo #
+set @a=concat(0x0107000000, repeat(0x010000000107000000, 120000), 0x00000000);
+--disable_result_log
+--error ER_STACK_OVERRUN_NEED_MORE
+SELECT ST_GeomFromWKB(@a);
+--enable_result_log
+
+--echo #
+--echo # MDEV-39750 ExtractValue does not control recursion depth.
+--echo #
+--replace_regex /overrun: [0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed/
+--error ER_STACK_OVERRUN_NEED_MORE
+SELECT ExtractValue('', REPEAT('(', 100000));
+
+--replace_regex /overrun: [0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed/
+--error ER_STACK_OVERRUN_NEED_MORE
+SELECT ExtractValue('', REPEAT('/n', 100000));
+
--echo # End of 10.6 tests
diff --git a/mysql-test/main/mdev-37000.result b/mysql-test/main/mdev-37000.result
new file mode 100644
index 00000000000..73e6812382a
--- /dev/null
+++ b/mysql-test/main/mdev-37000.result
@@ -0,0 +1,8 @@
+#
+# MDEV-37000 Deleting a row from Aria table results to 'Index is corrupt'
+#
+CREATE OR REPLACE TABLE t (a INT, b CHAR(8) NOT NULL, KEY(b)) ENGINE=Aria DEFAULT CHARSET=utf8;
+INSERT INTO t VALUES (1,'20070101'), (2,'20070101');
+DELETE FROM t LIMIT 2;
+DROP TABLE t;
+# End of 10.6 tests
diff --git a/mysql-test/main/mdev-37000.test b/mysql-test/main/mdev-37000.test
new file mode 100644
index 00000000000..631be073f8c
--- /dev/null
+++ b/mysql-test/main/mdev-37000.test
@@ -0,0 +1,9 @@
+--echo #
+--echo # MDEV-37000 Deleting a row from Aria table results to 'Index is corrupt'
+--echo #
+CREATE OR REPLACE TABLE t (a INT, b CHAR(8) NOT NULL, KEY(b)) ENGINE=Aria DEFAULT CHARSET=utf8;
+INSERT INTO t VALUES (1,'20070101'), (2,'20070101');
+DELETE FROM t LIMIT 2;
+DROP TABLE t;
+
+--echo # End of 10.6 tests
diff --git a/mysql-test/main/mysql_json_table_recreate.result b/mysql-test/main/mysql_json_table_recreate.result
index c8c53c9036a..25a72885317 100644
--- a/mysql-test/main/mysql_json_table_recreate.result
+++ b/mysql-test/main/mysql_json_table_recreate.result
@@ -245,6 +245,14 @@ DECLARE a mysql_json;
END;
$$
ERROR HY000: 'MYSQL_JSON' is not allowed in this context
-#
# End of 10.5 tests
#
+# MDEV-40678 mysql_json plugin OOB reads
+#
+alter table t1 force;
+ERROR HY000: Error parsing MySQL JSON format, please dump this table from MySQL and then restore it to be able to use it in MariaDB.
+flush tables;
+alter table t1 force;
+ERROR HY000: Error parsing MySQL JSON format, please dump this table from MySQL and then restore it to be able to use it in MariaDB.
+drop table t1;
+# End of 10.6 tests
diff --git a/mysql-test/main/mysql_json_table_recreate.test b/mysql-test/main/mysql_json_table_recreate.test
index 94477d4f328..26cc7a6cc6b 100644
--- a/mysql-test/main/mysql_json_table_recreate.test
+++ b/mysql-test/main/mysql_json_table_recreate.test
@@ -17,7 +17,7 @@ call mtr.add_suppression("Table rebuild required");
call mtr.add_suppression("is marked as crashed");
call mtr.add_suppression("Checking");
-let $MYSQLD_DATADIR= `select @@datadir`;
+let MYSQLD_DATADIR= `select @@datadir`;
SET NAMES utf8;
@@ -161,6 +161,40 @@ END;
$$
DELIMITER ;$$
---echo #
--echo # End of 10.5 tests
+
--echo #
+--echo # MDEV-40678 mysql_json plugin OOB reads
+--echo #
+
+--copy_file std_data/mysql_json/mysql_json_test.frm $MYSQLD_DATADIR/test/t1.frm
+--copy_file std_data/mysql_json/mysql_json_test.MYI $MYSQLD_DATADIR/test/t1.MYI
+--copy_file std_data/mysql_json/mysql_json_test.MYD $MYSQLD_DATADIR/test/t1.MYD
+
+perl;
+ my $f="$ENV{MYSQLD_DATADIR}/test/t1.MYD";
+ open F, '+<', $f or die "open($f): $!";
+ sysseek F, 0x3c5, 0 or die "sysseek: $!";
+ syswrite F, '(' or die "syswrite: $!";
+EOF
+
+--error ER_UNKNOWN_ERROR
+alter table t1 force;
+flush tables;
+
+--remove_file $MYSQLD_DATADIR/test/t1.MYD
+--copy_file std_data/mysql_json/mysql_json_test.MYD $MYSQLD_DATADIR/test/t1.MYD
+
+perl;
+ my $f="$ENV{MYSQLD_DATADIR}/test/t1.MYD";
+ open F, '+<', $f or die "open($f): $!";
+ sysseek F, 0x3bc, 0 or die "sysseek: $!";
+ syswrite F, '(' or die "syswrite: $!";
+EOF
+
+--error ER_UNKNOWN_ERROR
+alter table t1 force;
+
+drop table t1;
+
+--echo # End of 10.6 tests
diff --git a/mysql-test/main/mysqld--help,win.rdiff b/mysql-test/main/mysqld--help,win.rdiff
index 6016db9eac9..67f2651bdc8 100644
--- a/mysql-test/main/mysqld--help,win.rdiff
+++ b/mysql-test/main/mysqld--help,win.rdiff
@@ -16,7 +16,17 @@
--net-buffer-length=#
Buffer length for TCP/IP and socket communication
--net-read-timeout=#
-@@ -1374,6 +1376,10 @@
+@@ -1216,8 +1218,7 @@
+ (Defaults to on; use --skip-secure-auth to disable.)
+ --secure-file-priv=name
+ Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to
+- files within specified directory. Empty value means no
+- limits except /proc
++ files within specified directory.
+ --secure-timestamp=name
+ Restricts direct setting of a session timestamp. Possible
+ levels are: YES - timestamp cannot deviate from the
+@@ -1375,6 +1376,10 @@
Alias for log_slow_query_file. Log slow queries to given
log file. Defaults logging to 'hostname'-slow.log. Must
be enabled to activate other slow log options
@@ -27,7 +37,7 @@
--socket=name Socket file to use for connection
--sort-buffer-size=#
Each thread that needs to do a sort allocates a buffer of
-@@ -1394,6 +1400,7 @@
+@@ -1395,6 +1400,7 @@
aborted. Prevents the common mistake of accidentally
deleting or updating every row in a table.
--stack-trace Print a symbolic stack trace on failure
@@ -35,7 +45,7 @@
--standard-compliant-cte
Allow only CTEs compliant to SQL standard
(Defaults to on; use --skip-standard-compliant-cte to disable.)
-@@ -1472,6 +1479,12 @@
+@@ -1473,6 +1479,12 @@
--thread-pool-max-threads=#
Maximum allowed number of worker threads in the thread
pool
@@ -48,7 +58,7 @@
--thread-pool-oversubscribe=#
How many additional active worker threads in a group are
allowed.
-@@ -1510,8 +1523,8 @@
+@@ -1511,8 +1523,8 @@
automatically convert it to an on-disk MyISAM or Aria
table.
-t, --tmpdir=name Path for temporary files. Several paths may be specified,
@@ -59,7 +69,7 @@
--transaction-alloc-block-size=#
Allocation block size for transactions to be stored in
binary log
-@@ -1731,6 +1744,7 @@
+@@ -1732,6 +1744,7 @@
myisam-stats-method NULLS_UNEQUAL
myisam-use-mmap FALSE
mysql56-temporal-format TRUE
@@ -67,7 +77,7 @@
net-buffer-length 16384
net-read-timeout 30
net-retry-count 10
-@@ -1891,6 +1905,7 @@
+@@ -1892,6 +1905,7 @@
slave-type-conversions
slow-launch-time 2
slow-query-log FALSE
@@ -75,7 +85,7 @@
sort-buffer-size 2097152
sql-mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
sql-safe-updates FALSE
-@@ -1917,6 +1932,8 @@
+@@ -1918,6 +1932,8 @@
thread-pool-exact-stats FALSE
thread-pool-idle-timeout 60
thread-pool-max-threads 65536
diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result
index 1e80bede89b..883c3eecadf 100644
--- a/mysql-test/main/mysqld--help.result
+++ b/mysql-test/main/mysqld--help.result
@@ -1216,7 +1216,8 @@ The following specify which files/extra groups are read (specified before remain
(Defaults to on; use --skip-secure-auth to disable.)
--secure-file-priv=name
Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to
- files within specified directory
+ files within specified directory. Empty value means no
+ limits except /proc
--secure-timestamp=name
Restricts direct setting of a session timestamp. Possible
levels are: YES - timestamp cannot deviate from the
diff --git a/mysql-test/main/mysqltest.result b/mysql-test/main/mysqltest.result
index af12773b193..747d6f2e706 100644
--- a/mysql-test/main/mysqltest.result
+++ b/mysql-test/main/mysqltest.result
@@ -1023,6 +1023,12 @@ the false block has written nothing
mysqltest: At line 1: End of file encountered before 'eval' delimiter was found
# Only 'eval' is allowed as the third argument
mysqltest: At line 1: Invalid argument 'junk' to 'write_file', only 'eval' is allowed
+#
+# \0 in a query
+#
+select hex("1 2");
+hex("1\x002")
+310032
# End of 10.6 tests
#
# MDEV-29344: engines/iuds.insert_time cannot run with PS protocol (syntax error)
diff --git a/mysql-test/main/mysqltest.test b/mysql-test/main/mysqltest.test
index f4061c09045..8932b061c57 100644
--- a/mysql-test/main/mysqltest.test
+++ b/mysql-test/main/mysqltest.test
@@ -3054,6 +3054,11 @@ EOF
--error 1
--exec echo "--write_file $file EOF junk" | $MYSQL_TEST 2>&1
+--echo #
+--echo # \0 in a query
+--echo #
+select hex("1 2");
+
--echo # End of 10.6 tests
--echo #
@@ -3077,12 +3082,11 @@ SELECT 1 /* doesn't throw error */;
--rmdir $srcdir
+--echo # End of 10.11 tests
+
# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc
--disable_query_log
--eval SET GLOBAL max_connections = $saved_max_connections
--enable_query_log
-
---echo # End of 10.11 tests
-
diff --git a/mysql-test/main/mysqltest_expression_evaluation.result b/mysql-test/main/mysqltest_expression_evaluation.result
index d9fa0ccb3b8..b74fc767d47 100644
--- a/mysql-test/main/mysqltest_expression_evaluation.result
+++ b/mysql-test/main/mysqltest_expression_evaluation.result
@@ -505,4 +505,11 @@ mysqltest: At line 1: Evaluation error: Modulo by zero
# Test case: Overflow
mysqltest: At line 1: Range error: 18446744073709551616 value out of range for Integer type
mysqltest: At line 1: Range error: 18446744073709551616 value out of range for Integer type
+#
+# MDEV-37865: IF() function is returning incorrect error
+#
+# Test case: unknown function name that is a prefix of a known one
+mysqltest: At line 1: Syntax error: Unknown function 'if'
+mysqltest: At line 1: Syntax error: Unknown function 'l'
# Expression evaluation tests completed successfully
+# End of 10.6 tests
diff --git a/mysql-test/main/mysqltest_expression_evaluation.test b/mysql-test/main/mysqltest_expression_evaluation.test
index 7a108f2fe17..b76648284fc 100644
--- a/mysql-test/main/mysqltest_expression_evaluation.test
+++ b/mysql-test/main/mysqltest_expression_evaluation.test
@@ -894,4 +894,17 @@ let $large_xor = $(0x7FFFFFFFFFFFFFFF ^ 0x7FFFFFFFFFFFFFFE);
--error 1
--exec echo "let \$a = \$(-18446744073709551616);" | $MYSQL_TEST 2>&1
+--echo #
+--echo # MDEV-37865: IF() function is returning incorrect error
+--echo #
+
+--echo # Test case: unknown function name that is a prefix of a known one
+--error 1
+--exec echo "let \$a = \$(if(null, 'fallback', 'actual'));" | $MYSQL_TEST 2>&1
+
+--error 1
+--exec echo "let \$a = \$(l('AB'));" | $MYSQL_TEST 2>&1
+
--echo # Expression evaluation tests completed successfully
+
+--echo # End of 10.6 tests
diff --git a/mysql-test/main/mysqltest_string_functions.result b/mysql-test/main/mysqltest_string_functions.result
index eb3d56e6554..2f4eb0c94b0 100644
--- a/mysql-test/main/mysqltest_string_functions.result
+++ b/mysql-test/main/mysqltest_string_functions.result
@@ -1116,4 +1116,11 @@ insert(upper('hello world'), 7, 5, lower('MARIADB')) -> HELLO mariadb
concat_ws(' ', upper('hello'), lower('WORLD')) -> HELLO world
ifnull(nullif('same', 'same'), 'default') -> default
coalesce(nullif('test', 'test'), 'backup') -> backup
+#
+# MDEV-37859: Mysqltest hex() not working for string values
+#
+hex("abc") -> 616263
+hex("255") -> 323535
+hex('') ->
# Expression evaluation string functions tests completed successfully
+# End of 10.6 tests
diff --git a/mysql-test/main/mysqltest_string_functions.test b/mysql-test/main/mysqltest_string_functions.test
index 10e0d546e15..4ccdfec59c0 100644
--- a/mysql-test/main/mysqltest_string_functions.test
+++ b/mysql-test/main/mysqltest_string_functions.test
@@ -2128,4 +2128,19 @@ let $result5 = $(ifnull(nullif('same', 'same'), 'default'));
let $result6 = $(coalesce(nullif('test', 'test'), 'backup'));
--echo coalesce(nullif('test', 'test'), 'backup') -> $result6
+--echo #
+--echo # MDEV-37859: Mysqltest hex() not working for string values
+--echo #
+
+let $hex_str1 = $(hex("abc"));
+--echo hex("abc") -> $hex_str1
+
+let $hex_str2 = $(hex("255"));
+--echo hex("255") -> $hex_str2
+
+let $hex_str3 = $(hex(''));
+--echo hex('') -> $hex_str3
+
--echo # Expression evaluation string functions tests completed successfully
+
+--echo # End of 10.6 tests
diff --git a/mysql-test/main/rli_run_lock.result b/mysql-test/main/rli_run_lock.result
new file mode 100644
index 00000000000..e2776a356d0
--- /dev/null
+++ b/mysql-test/main/rli_run_lock.result
@@ -0,0 +1,18 @@
+CHANGE MASTER TO master_host='127.0.0.1', master_user='root';
+START SLAVE SQL_THREAD;
+include/wait_for_slave_sql_to_start.inc
+SET @@SESSION.debug_sync=
+'hold_sss_with_run_lock SIGNAL sss_got_run_lock WAIT_FOR sss_continue';
+SHOW SLAVE STATUS;
+connect stopper, 127.0.0.1, root, , , $SERVER_MYPORT_1;
+SET @@SESSION.debug_sync= 'now WAIT_FOR sss_got_run_lock';
+STOP SLAVE SQL_THREAD;
+connect continuer, 127.0.0.1, root, , , $SERVER_MYPORT_1;
+SET @@SESSION.debug_sync= 'now SIGNAL sss_continue';
+connection stopper;
+disconnect continuer;
+connection default;
+disconnect stopper;
+SET @@SESSION.debug_sync= RESET;
+include/wait_for_slave_sql_to_stop.inc
+RESET SLAVE ALL;
diff --git a/mysql-test/main/rli_run_lock.test b/mysql-test/main/rli_run_lock.test
new file mode 100644
index 00000000000..ca8eaf4d929
--- /dev/null
+++ b/mysql-test/main/rli_run_lock.test
@@ -0,0 +1,43 @@
+# MDEV-40298
+# Use-After-Free when SQL Thread stops in the middle of SHOW SLAVE STATUS
+#
+# Test that the correct synchronization is performed
+
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_mixed.inc # No actual replication required
+CHANGE MASTER TO master_host='127.0.0.1', master_user='root'; # basic setup
+
+START SLAVE SQL_THREAD;
+--source include/wait_for_slave_sql_to_start.inc
+
+
+SET @@SESSION.debug_sync=
+ 'hold_sss_with_run_lock SIGNAL sss_got_run_lock WAIT_FOR sss_continue';
+--send SHOW SLAVE STATUS
+
+--connect (stopper, 127.0.0.1, root, , , $SERVER_MYPORT_1)
+ SET @@SESSION.debug_sync= 'now WAIT_FOR sss_got_run_lock';
+ --send STOP SLAVE SQL_THREAD
+ # Wait a bit for the thread to "shut down"
+ # (It should not shut down, but block waiting for the ongoing SSS;
+ # the tested bug instead pulled this carpet under the SSS's feet.)
+ --sleep 1
+
+ --connect (continuer, 127.0.0.1, root, , , $SERVER_MYPORT_1)
+ SET @@SESSION.debug_sync= 'now SIGNAL sss_continue';
+ --connection stopper
+ --disconnect continuer
+
+ --reap
+--connection default
+--disconnect stopper
+
+
+--disable_result_log
+ --reap
+--enable_result_log
+
+# Clean-up
+SET @@SESSION.debug_sync= RESET;
+--source include/wait_for_slave_sql_to_stop.inc
+RESET SLAVE ALL;
diff --git a/mysql-test/main/xml.result b/mysql-test/main/xml.result
index 1cf232e5475..e699a8fb108 100644
--- a/mysql-test/main/xml.result
+++ b/mysql-test/main/xml.result
@@ -1414,11 +1414,4 @@ ExtractValue(@xml, '/employee/dt3')
NULL
Warnings:
Warning 1525 Incorrect XML value: 'parse error at line 10 pos 27: unexpected END-OF-INPUT'
-#
-# MDEV-39750 ExtractValue does not control recursion depth.
-#
-SELECT ExtractValue('', REPEAT('(', 100000));
-ERROR HY000: Thread stack overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed. Consider increasing the thread_stack system variable.
-SELECT ExtractValue('', REPEAT('/n', 100000));
-ERROR HY000: Thread stack overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed. Consider increasing the thread_stack system variable.
# End of 10.6 tests
diff --git a/mysql-test/main/xml.test b/mysql-test/main/xml.test
index f849e81d974..bc1e36a0eb8 100644
--- a/mysql-test/main/xml.test
+++ b/mysql-test/main/xml.test
@@ -899,17 +899,5 @@ set @xml= '
SELECT ExtractValue(@xml, '/employee/dt3');
---echo #
---echo # MDEV-39750 ExtractValue does not control recursion depth.
---echo #
-
---replace_regex /overrun: [0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed/
---error ER_STACK_OVERRUN_NEED_MORE
-SELECT ExtractValue('', REPEAT('(', 100000));
-
---replace_regex /overrun: [0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed/
---error ER_STACK_OVERRUN_NEED_MORE
-SELECT ExtractValue('', REPEAT('/n', 100000));
-
--echo # End of 10.6 tests
diff --git a/mysql-test/suite/archive/repair_text.result b/mysql-test/suite/archive/repair_text.result
new file mode 100644
index 00000000000..67926d923cf
--- /dev/null
+++ b/mysql-test/suite/archive/repair_text.result
@@ -0,0 +1,12 @@
+CREATE TABLE t1(
+t TEXT NULL DEFAULT NULL
+) COLLATE='utf8_general_ci' ENGINE=archive;
+INSERT INTO t1(t) VALUES ('Testtext');
+REPAIR TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+SELECT t = 'Testtext' as Expect_1 from t1;
+Expect_1
+1
+DROP TABLE t1;
+# End of 10.6 tests
diff --git a/mysql-test/suite/archive/repair_text.test b/mysql-test/suite/archive/repair_text.test
new file mode 100644
index 00000000000..842b1edb201
--- /dev/null
+++ b/mysql-test/suite/archive/repair_text.test
@@ -0,0 +1,10 @@
+--source include/have_archive.inc
+CREATE TABLE t1(
+ t TEXT NULL DEFAULT NULL
+) COLLATE='utf8_general_ci' ENGINE=archive;
+INSERT INTO t1(t) VALUES ('Testtext');
+REPAIR TABLE t1;
+SELECT t = 'Testtext' as Expect_1 from t1;
+DROP TABLE t1;
+
+--echo # End of 10.6 tests
diff --git a/mysql-test/suite/compat/oracle/r/sp-package-security.result b/mysql-test/suite/compat/oracle/r/sp-package-security.result
index c08b78cb8cf..c11589a0ea4 100644
--- a/mysql-test/suite/compat/oracle/r/sp-package-security.result
+++ b/mysql-test/suite/compat/oracle/r/sp-package-security.result
@@ -320,3 +320,26 @@ SESSION_USER() CURRENT_USER() msg
root@localhost root@localhost p1.p1
DROP PACKAGE p1;
DROP USER xxx@localhost;
+#
+# MDEV-40722 DROP PACKAGE leaves PACKAGE BODY grant in mysql.procs_priv
+#
+CREATE PACKAGE pkg1 AS
+FUNCTION f RETURN VARCHAR2(64);
+END
+$$
+CREATE PACKAGE BODY pkg1 AS
+FUNCTION f RETURN VARCHAR2(64) AS
+BEGIN RETURN 'f';
+END;
+END$$
+CREATE USER reader@localhost;
+GRANT EXECUTE ON PACKAGE test.pkg1 TO reader@localhost;
+GRANT EXECUTE ON PACKAGE BODY test.pkg1 TO reader@localhost;
+SELECT host,db,user,routine_name,routine_type,proc_priv FROM mysql.procs_priv ORDER BY routine_type;
+host db user routine_name routine_type proc_priv
+localhost test reader pkg1 PACKAGE Execute
+localhost test reader pkg1 PACKAGE BODY Execute
+DROP PACKAGE pkg1;
+SELECT host,db,user,routine_name,routine_type,proc_priv FROM mysql.procs_priv ORDER BY routine_type;
+host db user routine_name routine_type proc_priv
+DROP USER reader@localhost;
diff --git a/mysql-test/suite/compat/oracle/t/sp-package-security.test b/mysql-test/suite/compat/oracle/t/sp-package-security.test
index 583f70afe14..20a4fddb5b4 100644
--- a/mysql-test/suite/compat/oracle/t/sp-package-security.test
+++ b/mysql-test/suite/compat/oracle/t/sp-package-security.test
@@ -330,3 +330,28 @@ DELIMITER ;$$
CALL p1.p1;
DROP PACKAGE p1;
DROP USER xxx@localhost;
+
+
+--echo #
+--echo # MDEV-40722 DROP PACKAGE leaves PACKAGE BODY grant in mysql.procs_priv
+--echo #
+
+DELIMITER $$;
+CREATE PACKAGE pkg1 AS
+ FUNCTION f RETURN VARCHAR2(64);
+END
+$$
+CREATE PACKAGE BODY pkg1 AS
+ FUNCTION f RETURN VARCHAR2(64) AS
+ BEGIN RETURN 'f';
+ END;
+END$$
+DELIMITER ;$$
+
+CREATE USER reader@localhost;
+GRANT EXECUTE ON PACKAGE test.pkg1 TO reader@localhost;
+GRANT EXECUTE ON PACKAGE BODY test.pkg1 TO reader@localhost;
+SELECT host,db,user,routine_name,routine_type,proc_priv FROM mysql.procs_priv ORDER BY routine_type;
+DROP PACKAGE pkg1;
+SELECT host,db,user,routine_name,routine_type,proc_priv FROM mysql.procs_priv ORDER BY routine_type;
+DROP USER reader@localhost;
diff --git a/mysql-test/suite/csv/delete.result b/mysql-test/suite/csv/delete.result
new file mode 100644
index 00000000000..73dc585fc26
--- /dev/null
+++ b/mysql-test/suite/csv/delete.result
@@ -0,0 +1,11 @@
+#
+# MDEV-40636 CSV crashes on DELETE
+#
+create table t1 (id int not null, pad char(10) not null) engine=csv;
+insert t1 select seq,'AAAAAAAAAA' from seq_1_to_2048;
+delete from t1 where id % 2 = 0;
+select count(*), sum(id) from t1;
+count(*) sum(id)
+1024 1048576
+drop table t1;
+# End of 10.6 tests
diff --git a/mysql-test/suite/csv/delete.test b/mysql-test/suite/csv/delete.test
new file mode 100644
index 00000000000..2b4b1eea6c9
--- /dev/null
+++ b/mysql-test/suite/csv/delete.test
@@ -0,0 +1,13 @@
+--source include/have_csv.inc
+--source include/have_sequence.inc
+
+--echo #
+--echo # MDEV-40636 CSV crashes on DELETE
+--echo #
+create table t1 (id int not null, pad char(10) not null) engine=csv;
+insert t1 select seq,'AAAAAAAAAA' from seq_1_to_2048;
+delete from t1 where id % 2 = 0;
+select count(*), sum(id) from t1;
+drop table t1;
+
+--echo # End of 10.6 tests
diff --git a/mysql-test/suite/encryption/r/filekeys_encfile_badfile.result b/mysql-test/suite/encryption/r/filekeys_encfile_badfile.result
index 7e244c2c381..5dcf1857c44 100644
--- a/mysql-test/suite/encryption/r/filekeys_encfile_badfile.result
+++ b/mysql-test/suite/encryption/r/filekeys_encfile_badfile.result
@@ -1,9 +1,46 @@
-call mtr.add_suppression("File 'bad' not found");
+call mtr.add_suppression("File 'bad.key' not found");
call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
-FOUND 1 /File 'bad' not found/ in mysqld.1.err
+FOUND 1 /File 'bad.key' not found/ in mysqld.1.err
create table t1(c1 bigint not null, b char(200)) engine=innodb encrypted=yes encryption_key_id=1;
ERROR HY000: Can't create table `test`.`t1` (errno: 140 "Wrong create options")
select plugin_status from information_schema.plugins
where plugin_name = 'file_key_management';
plugin_status
+install soname 'file_key_management';
+ERROR HY000: Cannot decrypt MTR_SUITE_DIR/t/filekeys-data.enc. Wrong key?
+call mtr.add_suppression("Cannot decrypt .*filekeys-data.enc. Wrong key");
+call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
+call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
+FOUND 1 /Cannot decrypt .*filekeys-data.enc. Wrong key/ in mysqld.1.err
+create table t1(c1 bigint not null, b char(200)) engine=innodb encrypted=yes encryption_key_id=1;
+ERROR HY000: Can't create table `test`.`t1` (errno: 140 "Wrong create options")
+select plugin_status from information_schema.plugins
+where plugin_name = 'file_key_management';
+plugin_status
+install soname 'file_key_management';
+ERROR HY000: Cannot read bad.key, the filekey is too long, max secret size is 256B
+call mtr.add_suppression("the filekey is too long");
+call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
+call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
+FOUND 1 /the filekey is too long/ in mysqld.1.err
+create table t1(c1 bigint not null, b char(200)) engine=innodb encrypted=yes encryption_key_id=1;
+ERROR HY000: Can't create table `test`.`t1` (errno: 140 "Wrong create options")
+select plugin_status from information_schema.plugins
+where plugin_name = 'file_key_management';
+plugin_status
+#
+# MDEV-40658 file_key_management crash on empty FILE: file
+#
+install soname 'file_key_management';
+ERROR HY000: Cannot decrypt MTR_SUITE_DIR/t/filekeys-data.enc. Wrong key?
+call mtr.add_suppression("Cannot decrypt .*filekeys-data.enc. Wrong key");
+call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
+call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
+FOUND 1 /Cannot decrypt .*filekeys-data.enc. Wrong key/ in mysqld.1.err
+create table t1(c1 bigint not null, b char(200)) engine=innodb encrypted=yes encryption_key_id=1;
+ERROR HY000: Can't create table `test`.`t1` (errno: 140 "Wrong create options")
+select plugin_status from information_schema.plugins
+where plugin_name = 'file_key_management';
+plugin_status
+# End of 10.6 tests
diff --git a/mysql-test/suite/encryption/r/filekeys_secret_too_long.result b/mysql-test/suite/encryption/r/filekeys_secret_too_long.result
deleted file mode 100644
index bd11e8d925e..00000000000
--- a/mysql-test/suite/encryption/r/filekeys_secret_too_long.result
+++ /dev/null
@@ -1,10 +0,0 @@
-call mtr.add_suppression("the filekey is too long");
-call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
-call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
-FOUND 1 /the filekey is too long/ in mysqld.1.err
-create table t1(c1 bigint not null, b char(200)) engine=innodb encrypted=yes encryption_key_id=1;
-ERROR HY000: Can't create table `test`.`t1` (errno: 140 "Wrong create options")
-select plugin_status from information_schema.plugins
-where plugin_name = 'file_key_management';
-plugin_status
-# Test checks if opening an too large secret does not crash the server.
diff --git a/mysql-test/suite/encryption/t/filekeys-data-too-long.key b/mysql-test/suite/encryption/t/filekeys-data-too-long.key
deleted file mode 100644
index ba1624fb324..00000000000
--- a/mysql-test/suite/encryption/t/filekeys-data-too-long.key
+++ /dev/null
@@ -1,4 +0,0 @@
-secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret
-secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret
-secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret
-
diff --git a/mysql-test/suite/encryption/t/filekeys_encfile_badfile.opt b/mysql-test/suite/encryption/t/filekeys_encfile_badfile.opt
index 374a41395b8..713ce507eac 100644
--- a/mysql-test/suite/encryption/t/filekeys_encfile_badfile.opt
+++ b/mysql-test/suite/encryption/t/filekeys_encfile_badfile.opt
@@ -1,2 +1,2 @@
---loose-file-key-management-filekey=FILE:bad
+--loose-file-key-management-filekey=FILE:bad.key
--loose-file-key-management-filename=$MTR_SUITE_DIR/t/filekeys-data.enc
diff --git a/mysql-test/suite/encryption/t/filekeys_encfile_badfile.test b/mysql-test/suite/encryption/t/filekeys_encfile_badfile.test
index e0b07ac62b1..6af2e1c2f01 100644
--- a/mysql-test/suite/encryption/t/filekeys_encfile_badfile.test
+++ b/mysql-test/suite/encryption/t/filekeys_encfile_badfile.test
@@ -1,2 +1,51 @@
-let SEARCH_PATTERN=File 'bad' not found;
-source filekeys_badtest.inc;
+#
+# first test: no file
+#
+--let SEARCH_PATTERN=File 'bad.key' not found
+--source filekeys_badtest.inc
+
+#
+# second test: wrong key
+#
+--let $datadir=`select @@datadir`
+--write_file $datadir/bad.key
+wrong key
+EOF
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--error 2
+install soname 'file_key_management';
+--let SEARCH_PATTERN=Cannot decrypt .*filekeys-data.enc. Wrong key
+--source filekeys_badtest.inc
+--remove_file $datadir/bad.key
+
+#
+# third test: too long key
+#
+--let $datadir=`select @@datadir`
+--write_file $datadir/bad.key
+secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret
+secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret
+secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret
+EOF
+--error 2
+install soname 'file_key_management';
+--let SEARCH_PATTERN=the filekey is too long
+--source filekeys_badtest.inc
+--remove_file $datadir/bad.key
+
+--echo #
+--echo # MDEV-40658 file_key_management crash on empty FILE: file
+--echo #
+--let $datadir=`select @@datadir`
+--write_file $datadir/bad.key
+
+
+EOF
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--error 2
+install soname 'file_key_management';
+--let SEARCH_PATTERN=Cannot decrypt .*filekeys-data.enc. Wrong key
+--source filekeys_badtest.inc
+--remove_file $datadir/bad.key
+
+--echo # End of 10.6 tests
diff --git a/mysql-test/suite/encryption/t/filekeys_secret_too_long.opt b/mysql-test/suite/encryption/t/filekeys_secret_too_long.opt
deleted file mode 100644
index c3f95019f2a..00000000000
--- a/mysql-test/suite/encryption/t/filekeys_secret_too_long.opt
+++ /dev/null
@@ -1,3 +0,0 @@
---loose-file-key-management-filekey=FILE:$MTR_SUITE_DIR/t/filekeys-data-too-long.key
---loose-file-key-management-filename=$MTR_SUITE_DIR/t/filekeys-data.enc
-
diff --git a/mysql-test/suite/encryption/t/filekeys_secret_too_long.test b/mysql-test/suite/encryption/t/filekeys_secret_too_long.test
deleted file mode 100644
index 0032e94de37..00000000000
--- a/mysql-test/suite/encryption/t/filekeys_secret_too_long.test
+++ /dev/null
@@ -1,4 +0,0 @@
-let SEARCH_PATTERN=the filekey is too long;
-source filekeys_badtest.inc;
-
---echo # Test checks if opening an too large secret does not crash the server.
diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/galera/galera_2nodes.cnf
index f0996fa3a97..391cdbf6019 100644
--- a/mysql-test/suite/galera/galera_2nodes.cnf
+++ b/mysql-test/suite/galera/galera_2nodes.cnf
@@ -34,6 +34,8 @@ wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
[ENV]
diff --git a/mysql-test/suite/galera/galera_2nodes_as_master.cnf b/mysql-test/suite/galera/galera_2nodes_as_master.cnf
index 43bd091c8ee..64f10b086e1 100644
--- a/mysql-test/suite/galera/galera_2nodes_as_master.cnf
+++ b/mysql-test/suite/galera/galera_2nodes_as_master.cnf
@@ -48,6 +48,8 @@ wsrep-on=OFF
server-id=3
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
[ENV]
diff --git a/mysql-test/suite/galera/galera_2nodes_as_replica_2primary.cnf b/mysql-test/suite/galera/galera_2nodes_as_replica_2primary.cnf
index 570eeda0bc6..32f02ad0876 100644
--- a/mysql-test/suite/galera/galera_2nodes_as_replica_2primary.cnf
+++ b/mysql-test/suite/galera/galera_2nodes_as_replica_2primary.cnf
@@ -54,6 +54,8 @@ gtid_domain_id=4
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
[ENV]
diff --git a/mysql-test/suite/galera/galera_2nodes_as_slave.cnf b/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
index c00e6c6a937..75c247d05b3 100644
--- a/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
+++ b/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
@@ -47,6 +47,8 @@ wsrep-on=OFF
server-id=3
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
[ENV]
diff --git a/mysql-test/suite/galera/galera_2x2nodes.cnf b/mysql-test/suite/galera/galera_2x2nodes.cnf
index a35baed0c32..68d81983528 100644
--- a/mysql-test/suite/galera/galera_2x2nodes.cnf
+++ b/mysql-test/suite/galera/galera_2x2nodes.cnf
@@ -61,6 +61,8 @@ wsrep_node_incoming_address=127.0.0.1:@mysqld.4.port
wsrep_sst_receive_address='127.0.0.1:@mysqld.4.#sst_port'
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
[ENV]
diff --git a/mysql-test/suite/galera/galera_3nodes_as_slave.cnf b/mysql-test/suite/galera/galera_3nodes_as_slave.cnf
index 6231da6c246..b1091cfd645 100644
--- a/mysql-test/suite/galera/galera_3nodes_as_slave.cnf
+++ b/mysql-test/suite/galera/galera_3nodes_as_slave.cnf
@@ -60,6 +60,8 @@ wsrep-on=OFF
server-id=4
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
[ENV]
diff --git a/mysql-test/suite/galera/galera_4nodes.cnf b/mysql-test/suite/galera/galera_4nodes.cnf
index 3006882eda3..c54ff58e5e2 100644
--- a/mysql-test/suite/galera/galera_4nodes.cnf
+++ b/mysql-test/suite/galera/galera_4nodes.cnf
@@ -61,6 +61,8 @@ wsrep_sst_receive_address='127.0.0.1:@mysqld.4.#sst_port'
auto-increment-offset=4
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
[ENV]
diff --git a/mysql-test/suite/galera/include/have_pkill.inc b/mysql-test/suite/galera/include/have_pkill.inc
new file mode 100644
index 00000000000..0dd693f2c63
--- /dev/null
+++ b/mysql-test/suite/galera/include/have_pkill.inc
@@ -0,0 +1,4 @@
+#
+# suite.pm will make sure that all tests including this file
+# will be skipped as needed
+#
diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup_missing_ssl.result b/mysql-test/suite/galera/r/galera_sst_mariabackup_missing_ssl.result
new file mode 100644
index 00000000000..0424988061e
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_mariabackup_missing_ssl.result
@@ -0,0 +1,27 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_1;
+call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
+call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
+connection node_2;
+# Force a fresh SST on node_2
+# Start node_2 with SSL cert/key simulated as missing
+# node_2 failed to start, as expected
+# Joiner refused the SST instead of running unencrypted
+FOUND 1 /ssl-mode is set to .REQUIRED., but no usable SSL/ in mysqld.2.err
+# Restart node_2 normally so it rejoins
+connection node_2;
+call mtr.add_suppression("WSREP_SST:");
+call mtr.add_suppression("WSREP: Process completed with error:");
+call mtr.add_suppression("WSREP: Failed to read .ready .");
+call mtr.add_suppression("WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.");
+call mtr.add_suppression("WSREP: Failed to read state from: .*");
+call mtr.add_suppression("WSREP: Failed to prepare for .*");
+call mtr.add_suppression("WSREP: SST failed:.*");
+call mtr.add_suppression("WSREP: SST request callback failed. This is unrecoverable, restart required.");
+call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
+call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
+call mtr.add_suppression("WSREP: Requesting state transfer failed:.*");
+connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_sst_rsync_missing_stunnel.result b/mysql-test/suite/galera/r/galera_sst_rsync_missing_stunnel.result
new file mode 100644
index 00000000000..771d6e0fd75
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_rsync_missing_stunnel.result
@@ -0,0 +1,27 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_1;
+call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
+call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
+connection node_2;
+# Force a fresh SST on node_2
+# Start node_2 with stunnel simulated as missing
+# node_2 failed to start, as expected
+# Joiner refused the SST instead of running unencrypted
+FOUND 1 /ssl-mode is set to .REQUIRED., but the .stunnel. binary was not found/ in mysqld.2.err
+# Restart node_2 normally so it rejoins
+connection node_2;
+call mtr.add_suppression("WSREP_SST:");
+call mtr.add_suppression("WSREP: Process completed with error:");
+call mtr.add_suppression("WSREP: Failed to read .ready .");
+call mtr.add_suppression("WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.");
+call mtr.add_suppression("WSREP: Failed to read state from: .*");
+call mtr.add_suppression("WSREP: Failed to prepare for .*");
+call mtr.add_suppression("WSREP: SST failed:.*");
+call mtr.add_suppression("WSREP: SST request callback failed. This is unrecoverable, restart required.");
+call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
+call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
+call mtr.add_suppression("WSREP: Requesting state transfer failed:.*");
+connection node_1;
diff --git a/mysql-test/suite/galera/suite.pm b/mysql-test/suite/galera/suite.pm
index 612a8bfa595..b4fd4c62f06 100644
--- a/mysql-test/suite/galera/suite.pm
+++ b/mysql-test/suite/galera/suite.pm
@@ -80,6 +80,10 @@ sub skip_combinations {
unless which("lsof") || which("sockstat") || which("ss");
$skip{'include/have_stunnel.inc'} = "Need 'stunnel' utility"
unless which("stunnel");
+ # 'mariabackup' combination doesn't need stunnel: only 'rsync' SST goes
+ # through it.
+ $skip{'t/galera_sst_cn_injection.combinations'} = [ 'rsync' ]
+ unless which("stunnel");
$skip{'include/have_qpress.inc'} = "Need 'qpress' utility"
unless which("qpress");
$skip{'../encryption/include/have_file_key_management_plugin.combinations'} = [ 'ctr' ]
@@ -93,6 +97,9 @@ sub skip_combinations {
$skip{'t/galera_sst_cn_injection.test'} = 'does not work with OpenSSL <= 1.1.1'
unless $openssl_ver ge "3.0.0";
+ $skip{'include/have_pkill.inc'} = "Need 'pkill' utility"
+ unless which("pkill");
+
%skip;
}
diff --git a/mysql-test/suite/galera/t/galera_ist_rsync_verify_ca.test b/mysql-test/suite/galera/t/galera_ist_rsync_verify_ca.test
index d9f7bb152fc..fb16ba7f8d3 100644
--- a/mysql-test/suite/galera/t/galera_ist_rsync_verify_ca.test
+++ b/mysql-test/suite/galera/t/galera_ist_rsync_verify_ca.test
@@ -1,6 +1,7 @@
--source include/big_test.inc
--source include/galera_cluster.inc
--source include/have_innodb.inc
+--source include/have_stunnel.inc
--let $node_1=node_1
--let $node_2=node_2
diff --git a/mysql-test/suite/galera/t/galera_sst_cn_injection.test b/mysql-test/suite/galera/t/galera_sst_cn_injection.test
index 9b8058267e8..b970950a0a5 100644
--- a/mysql-test/suite/galera/t/galera_sst_cn_injection.test
+++ b/mysql-test/suite/galera/t/galera_sst_cn_injection.test
@@ -10,6 +10,7 @@
--source include/have_mariabackup.inc
--source include/have_ssl_communication.inc
--source include/have_openssl.inc
+--source include/have_pkill.inc
# This test asserts that the initial cluster-bootstrap SST was SSL-encrypted by
# grepping the donor's error log. That is a one-time event, so the cluster must
# be freshly bootstrapped on every run (e.g. with --repeat) for node_2 to SST
@@ -56,7 +57,8 @@ call mtr.add_suppression("WSREP: Illegal character in variable:");
--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
+# pkill below might return 0 = success or 1 in error when it does not find socat
+# anymore
--error 0,1,15
--exec pkill -f 'socat.*[s]erver-new-cert'
--exec echo ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert.pem >> $MYSQLTEST_VARDIR/my.cnf
diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_missing_ssl.cnf b/mysql-test/suite/galera/t/galera_sst_mariabackup_missing_ssl.cnf
new file mode 100644
index 00000000000..5c9ea2149a3
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_missing_ssl.cnf
@@ -0,0 +1,11 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=mariabackup
+wsrep_sst_auth="root:"
+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=REQUIRED
diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_missing_ssl.test b/mysql-test/suite/galera/t/galera_sst_mariabackup_missing_ssl.test
new file mode 100644
index 00000000000..a636634cd50
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_missing_ssl.test
@@ -0,0 +1,69 @@
+# MDEV-28233: with ssl-mode requiring encryption but no usable cert/key,
+# wsrep_sst_mariabackup used to fall back to an unencrypted transfer
+# WITHOUT any error or warning. Before the fix the joiner only logged the
+# informational line:
+# WSREP_SST: [INFO] SSL configuration: ... MODE='REQUIRED' ... encrypt='0'
+# and then opened a cleartext socket.
+#
+# Steps:
+# 1. Form a 2-node cluster with ssl-mode=REQUIRED and SSL cert/key.
+# 2. Shut node_2 down and force a fresh SST.
+# 3. Restart node_2 with cert/key simulated as missing
+# (MTR_SST_SIMULATE_NO_SSL_CERT=1).
+# 4. Check the joiner refuses the SST and logs the error.
+# 5. Restart node_2 normally so it rejoins.
+#
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_mariabackup.inc
+
+# Save auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+--connection node_1
+# Donor-side noise when the joiner aborts the SST.
+call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
+call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+
+--echo # Force a fresh SST on node_2
+--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+
+--echo # Start node_2 with SSL cert/key simulated as missing
+# Abort exit code varies by platform.
+--error 1,134
+--exec MTR_SST_SIMULATE_NO_SSL_CERT=1 $MYSQLD_LAST_CMD
+--echo # node_2 failed to start, as expected
+
+--echo # Joiner refused the SST instead of running unencrypted
+--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.2.err
+--let SEARCH_PATTERN = ssl-mode is set to .REQUIRED., but no usable SSL
+--source include/search_pattern_in_file.inc
+
+--echo # Restart node_2 normally so it rejoins
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--connection node_2
+# Joiner-side noise from the failed SST attempt.
+call mtr.add_suppression("WSREP_SST:");
+call mtr.add_suppression("WSREP: Process completed with error:");
+call mtr.add_suppression("WSREP: Failed to read .ready .");
+call mtr.add_suppression("WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.");
+call mtr.add_suppression("WSREP: Failed to read state from: .*");
+call mtr.add_suppression("WSREP: Failed to prepare for .*");
+call mtr.add_suppression("WSREP: SST failed:.*");
+call mtr.add_suppression("WSREP: SST request callback failed. This is unrecoverable, restart required.");
+call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
+call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
+call mtr.add_suppression("WSREP: Requesting state transfer failed:.*");
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--source include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera/t/galera_sst_rsync_missing_stunnel.cnf b/mysql-test/suite/galera/t/galera_sst_rsync_missing_stunnel.cnf
new file mode 100644
index 00000000000..39fbab6cb5c
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_rsync_missing_stunnel.cnf
@@ -0,0 +1,10 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=rsync
+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=REQUIRED
diff --git a/mysql-test/suite/galera/t/galera_sst_rsync_missing_stunnel.test b/mysql-test/suite/galera/t/galera_sst_rsync_missing_stunnel.test
new file mode 100644
index 00000000000..1310c27c6db
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_rsync_missing_stunnel.test
@@ -0,0 +1,66 @@
+# MDEV-28233: the rsync SST script must NOT silently fall back to an
+# unencrypted transfer when encryption is requested (ssl-mode is set to a
+# value other than DISABLED) but the stunnel binary is not installed.
+#
+# Steps:
+# 1. Form a 2-node cluster with ssl-mode=REQUIRED (stunnel present).
+# 2. Shut node_2 down and force a fresh SST.
+# 3. Restart node_2 with stunnel hidden (MTR_SST_SIMULATE_NO_STUNNEL=1).
+# 4. Check the joiner refuses the SST and logs the error.
+# 5. Restart node_2 normally so it rejoins.
+#
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+# Needed for the initial SST; only simulated as missing below.
+--source include/have_stunnel.inc
+
+# Save auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+--connection node_1
+# Donor-side noise when the joiner aborts the SST.
+call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
+call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+
+--echo # Force a fresh SST on node_2
+--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+
+--echo # Start node_2 with stunnel simulated as missing
+# Abort exit code
+--error 1,134
+--exec MTR_SST_SIMULATE_NO_STUNNEL=1 $MYSQLD_LAST_CMD
+--echo # node_2 failed to start, as expected
+
+--echo # Joiner refused the SST instead of running unencrypted
+--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.2.err
+--let SEARCH_PATTERN = ssl-mode is set to .REQUIRED., but the .stunnel. binary was not found
+--source include/search_pattern_in_file.inc
+
+--echo # Restart node_2 normally so it rejoins
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--connection node_2
+# Joiner-side noise from the failed SST attempt.
+call mtr.add_suppression("WSREP_SST:");
+call mtr.add_suppression("WSREP: Process completed with error:");
+call mtr.add_suppression("WSREP: Failed to read .ready .");
+call mtr.add_suppression("WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.");
+call mtr.add_suppression("WSREP: Failed to read state from: .*");
+call mtr.add_suppression("WSREP: Failed to prepare for .*");
+call mtr.add_suppression("WSREP: SST failed:.*");
+call mtr.add_suppression("WSREP: SST request callback failed. This is unrecoverable, restart required.");
+call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
+call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
+call mtr.add_suppression("WSREP: Requesting state transfer failed:.*");
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--source include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf b/mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf
index 5cd16f029e0..b385d5c160f 100644
--- a/mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf
+++ b/mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf
@@ -85,6 +85,8 @@ wsrep_node_incoming_address=127.0.0.1:@mysqld.6.port
wsrep_sst_receive_address='127.0.0.1:@mysqld.6.#sst_port'
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
[ENV]
diff --git a/mysql-test/suite/galera_3nodes/galera_3nodes.cnf b/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
index b0229971c57..35d51c98a0f 100644
--- a/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
+++ b/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
@@ -50,6 +50,8 @@ wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
wsrep_node_name=node3
[sst]
+# SSL mode is disabled for SST unless tests specifically enable it.
+ssl-mode=DISABLED
sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log
transferfmt=@ENV.MTR_GALERA_TFMT
diff --git a/mysql-test/suite/plugins/r/qc_info.result b/mysql-test/suite/plugins/r/qc_info.result
index afab7671b5c..5ad4e13f1e1 100644
Binary files a/mysql-test/suite/plugins/r/qc_info.result and b/mysql-test/suite/plugins/r/qc_info.result differ
diff --git a/mysql-test/suite/plugins/t/qc_info.test b/mysql-test/suite/plugins/t/qc_info.test
index 5345bac12ff..0bccd7f6672 100644
Binary files a/mysql-test/suite/plugins/t/qc_info.test and b/mysql-test/suite/plugins/t/qc_info.test differ
diff --git a/mysql-test/suite/rpl/r/rpl_corrupted_decimal_precision.result b/mysql-test/suite/rpl/r/rpl_corrupted_decimal_precision.result
index 9070bef9dc0..b56808e1128 100644
--- a/mysql-test/suite/rpl/r/rpl_corrupted_decimal_precision.result
+++ b/mysql-test/suite/rpl/r/rpl_corrupted_decimal_precision.result
@@ -27,7 +27,7 @@ master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; insert into t1 values (0.5)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
-master-bin.000001 # User var # #
+master-bin.000001 # User var # # NULL
master-bin.000001 # Query # # use `test`; insert into t1 values (@a)
master-bin.000001 # Query # # COMMIT
set @@session.debug_dbug= "";
diff --git a/mysql-test/suite/sys_vars/r/secure_file_priv,win.rdiff b/mysql-test/suite/sys_vars/r/secure_file_priv,win.rdiff
new file mode 100644
index 00000000000..44674696c9c
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/secure_file_priv,win.rdiff
@@ -0,0 +1,10 @@
+--- secure_file_priv.result
++++ secure_file_priv.reject
+@@ -30,6 +30,6 @@
+ #
+ CREATE TABLE t1 (c1 VARCHAR(50));
+ LOAD DATA INFILE '/proc/cpuinfo' INTO TABLE t1;
+-ERROR HY000: The MariaDB server is running with the --secure-file-priv option so it cannot execute this statement
++ERROR HY000: File 'C:\proc\cpuinfo' not found (Errcode: 2 "No such file or directory")
+ DROP TABLE t1;
+ # End of 10.6 tests
diff --git a/mysql-test/suite/sys_vars/r/secure_file_priv.result b/mysql-test/suite/sys_vars/r/secure_file_priv.result
index 74f816df59d..06968a185e7 100644
--- a/mysql-test/suite/sys_vars/r/secure_file_priv.result
+++ b/mysql-test/suite/sys_vars/r/secure_file_priv.result
@@ -6,14 +6,17 @@ INSERT INTO t1 VALUES ("one"),("two"),("three"),("four"),("five");
SHOW VARIABLES LIKE 'secure_file_priv';
Variable_name Value
secure_file_priv
-Warnings:
-Warning 1287 '