summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-03-29 12:59:18 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2022-03-29 12:59:18 +0300
commitd62b0368ca53cc10b45b703bbeefcf0b674bd39d (patch)
treee65926bf20605d24a87619553374a74e7ef1c2c8
parent9d6d1221230e2acf9fac2ab6fe685c0a2a7845aa (diff)
parent088b37b5eaa8c3198c7f8ea0358d15135833f6bb (diff)
downloadmariadb-git-d62b0368ca53cc10b45b703bbeefcf0b674bd39d.tar.gz
Merge 10.4 into 10.5
-rw-r--r--CREDITS2
-rw-r--r--client/mysqlbinlog.cc1
-rw-r--r--client/mysqltest.cc455
-rw-r--r--cmake/submodules.cmake35
-rw-r--r--include/my_atomic.h18
-rw-r--r--mysql-test/main/contributors.result2
-rw-r--r--mysql-test/main/ctype_utf32.result25
-rw-r--r--mysql-test/main/ctype_utf32.test19
-rw-r--r--mysql-test/main/multi_update_innodb.result15
-rw-r--r--mysql-test/main/multi_update_innodb.test19
-rw-r--r--mysql-test/main/opt_tvc.result27
-rw-r--r--mysql-test/main/opt_tvc.test26
-rw-r--r--mysql-test/main/processlist.result20
-rw-r--r--mysql-test/main/processlist.test35
-rw-r--r--mysql-test/main/sp-cursor.result63
-rw-r--r--mysql-test/main/sp-cursor.test56
-rw-r--r--mysql-test/main/view.result28
-rw-r--r--mysql-test/main/view.test26
-rw-r--r--mysql-test/suite/binlog/r/binlog_autocommit_off_no_hang.result6
-rw-r--r--mysql-test/suite/binlog/r/binlog_mysqlbinlog_raw_flush.result7
-rw-r--r--mysql-test/suite/binlog/t/binlog_autocommit_off_no_hang-master.opt1
-rw-r--r--mysql-test/suite/binlog/t/binlog_autocommit_off_no_hang.test45
-rw-r--r--mysql-test/suite/binlog/t/binlog_mysqlbinlog_raw_flush.test45
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-package.result308
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-package.test327
-rw-r--r--mysql-test/suite/galera/disabled.def1
-rw-r--r--mysql-test/suite/galera/include/kill_galera.inc2
-rw-r--r--mysql-test/suite/galera/r/MDEV-24143.result23
-rw-r--r--mysql-test/suite/galera/r/MDEV-27713.result46
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_ps_bind.result37
-rw-r--r--mysql-test/suite/galera/r/galera_ist_restart_joiner.result1
-rw-r--r--mysql-test/suite/galera/t/MDEV-24143.test20
-rw-r--r--mysql-test/suite/galera/t/MDEV-27713.test67
-rw-r--r--mysql-test/suite/galera/t/MW-328C.test1
-rw-r--r--mysql-test/suite/galera/t/MW-44.test6
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_ps_bind.cnf7
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_ps_bind.test58
-rw-r--r--mysql-test/suite/galera/t/galera_ist_restart_joiner.test14
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_garbd_backup.result41
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_garbd_backup.cnf13
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_garbd_backup.test134
-rw-r--r--mysql-test/suite/galera_sr/disabled.def1
-rw-r--r--mysql-test/suite/galera_sr/r/MDEV-27553.result25
-rw-r--r--mysql-test/suite/galera_sr/t/MDEV-27553.test65
-rw-r--r--mysql-test/suite/rpl/r/mdev_24667.result30
-rw-r--r--mysql-test/suite/rpl/t/mdev_24667.cnf8
-rw-r--r--mysql-test/suite/rpl/t/mdev_24667.test56
-rw-r--r--mysys/my_rename.c9
-rw-r--r--plugin/server_audit/server_audit.c6
-rw-r--r--scripts/CMakeLists.txt1
-rw-r--r--scripts/mysql_install_db.sh2
-rw-r--r--scripts/mysql_system_tables_fix.sql9
-rw-r--r--scripts/wsrep_sst_backup.sh112
-rw-r--r--sql/contributors.h2
-rw-r--r--sql/handler.h4
-rw-r--r--sql/item.cc20
-rw-r--r--sql/item_cmpfunc.cc7
-rw-r--r--sql/item_cmpfunc.h2
-rw-r--r--sql/log.cc4
-rw-r--r--sql/rpl_rli.cc2
-rw-r--r--sql/semisync_master.cc1
-rw-r--r--sql/sp_head.cc1
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h26
-rw-r--r--sql/sql_lex.cc89
-rw-r--r--sql/sql_lex.h11
-rw-r--r--sql/sql_parse.cc22
-rw-r--r--sql/sql_prepare.cc12
-rw-r--r--sql/sql_show.cc12
-rw-r--r--sql/sql_table.cc49
-rw-r--r--sql/sql_tvc.cc31
-rw-r--r--sql/sql_update.cc5
-rw-r--r--sql/sql_view.cc3
-rw-r--r--sql/sql_yacc.yy50
-rw-r--r--sql/table.cc22
-rw-r--r--sql/unireg.cc11
-rw-r--r--sql/wsrep_client_service.cc1
-rw-r--r--sql/wsrep_high_priority_service.cc1
-rw-r--r--sql/wsrep_mysqld.cc87
-rw-r--r--sql/wsrep_mysqld.h1
-rw-r--r--sql/wsrep_sst.cc81
-rw-r--r--storage/innobase/buf/buf0buf.cc97
-rw-r--r--storage/innobase/fil/fil0fil.cc5
-rw-r--r--storage/innobase/fts/fts0fts.cc4
-rw-r--r--storage/perfschema/unittest/stub_pfs_global.h14
-rw-r--r--strings/decimal.c32
86 files changed, 2870 insertions, 246 deletions
diff --git a/CREDITS b/CREDITS
index f5e87e18752..35092602ccf 100644
--- a/CREDITS
+++ b/CREDITS
@@ -4,9 +4,11 @@ organization registered in the USA.
The current main sponsors of the MariaDB Foundation are:
Alibaba Cloud https://www.alibabacloud.com/ (2017)
+Intel https://www.intel.com (2022)
MariaDB Corporation https://www.mariadb.com (2013)
Microsoft https://microsoft.com/ (2017)
ServiceNow https://servicenow.com (2019)
+SIT https://sit.org (2022)
Tencent Cloud https://cloud.tencent.com (2017)
Development Bank of Singapore https://dbs.com (2016)
IBM https://www.ibm.com (2017)
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index b262cd9d7c9..2be52840e91 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -2518,6 +2518,7 @@ static Exit_status handle_event_raw_mode(PRINT_EVENT_INFO *print_event_info,
error("Could not write into log file '%s'", out_file_name);
DBUG_RETURN(ERROR_STOP);
}
+ fflush(result_file);
DBUG_RETURN(OK_CONTINUE);
}
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index d76f3b06efc..e855e1af807 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2021, MariaDB
+ Copyright (c) 2009, 2022, 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
@@ -320,6 +320,7 @@ struct st_connection
char *name;
size_t name_len;
MYSQL_STMT* stmt;
+ MYSQL_BIND *ps_params;
/* Set after send to disallow other queries before reap */
my_bool pending;
@@ -394,6 +395,10 @@ enum enum_commands {
Q_ENABLE_PREPARE_WARNINGS, Q_DISABLE_PREPARE_WARNINGS,
Q_RESET_CONNECTION,
Q_OPTIMIZER_TRACE,
+ Q_PS_PREPARE,
+ Q_PS_BIND,
+ Q_PS_EXECUTE,
+ Q_PS_CLOSE,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
Q_COMMENT_WITH_COMMAND,
@@ -507,6 +512,10 @@ const char *command_names[]=
"disable_prepare_warnings",
"reset_connection",
"optimizer_trace",
+ "PS_prepare",
+ "PS_bind",
+ "PS_execute",
+ "PS_close",
0
};
@@ -7900,6 +7909,15 @@ static void handle_no_active_connection(struct st_command *command,
var_set_errno(2006);
}
+/* handler functions to execute prepared statement calls in client C API */
+void run_prepare_stmt(struct st_connection *cn, struct st_command *command, const char *query,
+ size_t query_len, DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings);
+void run_bind_stmt(struct st_connection *cn, struct st_command *command, const char *query,
+ size_t query_len, DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings);
+void run_execute_stmt(struct st_connection *cn, struct st_command *command, const char *query,
+ size_t query_len, DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings);
+void run_close_stmt(struct st_connection *cn, struct st_command *command, const char *query,
+ size_t query_len, DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings);
/*
Run query using MySQL C API
@@ -7931,6 +7949,32 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
DBUG_VOID_RETURN;
}
+ /* handle prepared statement commands */
+ switch (command->type) {
+ case Q_PS_PREPARE:
+ run_prepare_stmt(cn, command, query, query_len, ds, ds_warnings);
+ flags &= ~QUERY_SEND_FLAG;
+ goto end;
+ break;
+ case Q_PS_BIND:
+ run_bind_stmt(cn, command, query, query_len, ds, ds_warnings);
+ flags &= ~QUERY_SEND_FLAG;
+ goto end;
+ break;
+ case Q_PS_EXECUTE:
+ run_execute_stmt(cn, command, query, query_len, ds, ds_warnings);
+ flags &= ~QUERY_SEND_FLAG;
+ goto end;
+ break;
+ case Q_PS_CLOSE:
+ run_close_stmt(cn, command, query, query_len, ds, ds_warnings);
+ flags &= ~QUERY_SEND_FLAG;
+ goto end;
+ break;
+ default: /* not a prepared statement command */
+ break;
+ }
+
if (flags & QUERY_SEND_FLAG)
{
/*
@@ -8486,6 +8530,411 @@ end:
DBUG_VOID_RETURN;
}
+/*
+ prepare query using prepared statement C API
+
+ SYNPOSIS
+ run_prepare_stmt
+ mysql - mysql handle
+ command - current command pointer
+ query - query string to execute
+ query_len - length query string to execute
+ ds - output buffer where to store result form query
+
+ RETURN VALUE
+ error - function will not return
+*/
+
+void run_prepare_stmt(struct st_connection *cn, struct st_command *command, const char *query, size_t query_len, DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings)
+{
+
+ MYSQL *mysql= cn->mysql;
+ MYSQL_STMT *stmt;
+ DYNAMIC_STRING ds_prepare_warnings;
+ DBUG_ENTER("run_prepare_stmt");
+ DBUG_PRINT("query", ("'%-.60s'", query));
+
+ /*
+ Init a new stmt if it's not already one created for this connection
+ */
+ if(!(stmt= cn->stmt))
+ {
+ if (!(stmt= mysql_stmt_init(mysql)))
+ die("unable to init stmt structure");
+ cn->stmt= stmt;
+ }
+
+ /* Init dynamic strings for warnings */
+ if (!disable_warnings)
+ {
+ init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256);
+ }
+
+ /*
+ Prepare the query
+ */
+ char* PS_query= command->first_argument;
+ size_t PS_query_len= command->end - command->first_argument;
+ if (do_stmt_prepare(cn, PS_query, PS_query_len))
+ {
+ handle_error(command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ goto end;
+ }
+
+ /*
+ Get the warnings from mysql_stmt_prepare and keep them in a
+ separate string
+ */
+ if (!disable_warnings)
+ append_warnings(&ds_prepare_warnings, mysql);
+ end:
+ DBUG_VOID_RETURN;
+}
+
+/*
+ bind parameters for a prepared statement C API
+
+ SYNPOSIS
+ run_bind_stmt
+ mysql - mysql handle
+ command - current command pointer
+ query - query string to execute
+ query_len - length query string to execute
+ ds - output buffer where to store result form query
+
+ RETURN VALUE
+ error - function will not return
+*/
+
+void run_bind_stmt(struct st_connection *cn, struct st_command *command,
+ const char *query, size_t query_len, DYNAMIC_STRING *ds,
+ DYNAMIC_STRING *ds_warnings
+ )
+{
+ MYSQL_STMT *stmt= cn->stmt;
+ DBUG_ENTER("run_bind_stmt");
+ DBUG_PRINT("query", ("'%-.60s'", query));
+ MYSQL_BIND *ps_params= cn->ps_params;
+ if (ps_params)
+ {
+ for (size_t i=0; i<stmt->param_count; i++)
+ {
+ my_free(ps_params[i].buffer);
+ ps_params[i].buffer= NULL;
+ }
+ my_free(ps_params);
+ ps_params= NULL;
+ }
+
+ /* Init PS-parameters. */
+ cn->ps_params= ps_params = (MYSQL_BIND*)my_malloc(PSI_NOT_INSTRUMENTED,
+ sizeof(MYSQL_BIND) *
+ stmt->param_count,
+ MYF(MY_WME));
+ bzero((char *) ps_params, sizeof(MYSQL_BIND) * stmt->param_count);
+
+ int i=0;
+ char *c;
+ long *l;
+ double *d;
+
+ char *p= strtok((char*)command->first_argument, " ");
+ while (p != nullptr)
+ {
+ (void)strtol(p, &c, 10);
+ if (!*c)
+ {
+ ps_params[i].buffer_type= MYSQL_TYPE_LONG;
+ l= (long*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(long), MYF(MY_WME));
+ *l= strtol(p, &c, 10);
+ ps_params[i].buffer= (void*)l;
+ ps_params[i].buffer_length= 8;
+ }
+ else
+ {
+ (void)strtod(p, &c);
+ if (!*c)
+ {
+ ps_params[i].buffer_type= MYSQL_TYPE_DECIMAL;
+ d= (double*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(double),
+ MYF(MY_WME));
+ *d= strtod(p, &c);
+ ps_params[i].buffer= (void*)d;
+ ps_params[i].buffer_length= 8;
+ }
+ else
+ {
+ ps_params[i].buffer_type= MYSQL_TYPE_STRING;
+ ps_params[i].buffer= strdup(p);
+ ps_params[i].buffer_length= (unsigned long)strlen(p);
+ }
+ }
+
+ p= strtok(nullptr, " ");
+ i++;
+ }
+
+ int rc= mysql_stmt_bind_param(stmt, ps_params);
+ if (rc)
+ {
+ die("mysql_stmt_bind_param() failed': %d %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ execute query using prepared statement C API
+
+ SYNPOSIS
+ run_axecute_stmt
+ mysql - mysql handle
+ command - current command pointer
+ query - query string to execute
+ query_len - length query string to execute
+ ds - output buffer where to store result form query
+
+ RETURN VALUE
+ error - function will not return
+*/
+
+void run_execute_stmt(struct st_connection *cn, struct st_command *command,
+ const char *query, size_t query_len, DYNAMIC_STRING *ds,
+ DYNAMIC_STRING *ds_warnings
+ )
+{
+ MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */
+ MYSQL *mysql= cn->mysql;
+ MYSQL_STMT *stmt= cn->stmt;
+ DYNAMIC_STRING ds_execute_warnings;
+ DBUG_ENTER("run_execute_stmt");
+ DBUG_PRINT("query", ("'%-.60s'", query));
+
+ /* Init dynamic strings for warnings */
+ if (!disable_warnings)
+ {
+ init_dynamic_string(&ds_execute_warnings, NULL, 0, 256);
+ }
+
+#if MYSQL_VERSION_ID >= 50000
+ if (cursor_protocol_enabled)
+ {
+ /*
+ Use cursor when retrieving result
+ */
+ ulong type= CURSOR_TYPE_READ_ONLY;
+ if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type))
+ die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+ }
+#endif
+
+ /*
+ Execute the query
+ */
+ if (do_stmt_execute(cn))
+ {
+ handle_error(command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ goto end;
+ }
+
+ /*
+ When running in cursor_protocol get the warnings from execute here
+ and keep them in a separate string for later.
+ */
+ if (cursor_protocol_enabled && !disable_warnings)
+ append_warnings(&ds_execute_warnings, mysql);
+
+ /*
+ We instruct that we want to update the "max_length" field in
+ mysql_stmt_store_result(), this is our only way to know how much
+ buffer to allocate for result data
+ */
+ {
+ my_bool one= 1;
+ if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one))
+ die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+ }
+
+ /*
+ If we got here the statement succeeded and was expected to do so,
+ get data. Note that this can still give errors found during execution!
+ Store the result of the query if if will return any fields
+ */
+ if (mysql_stmt_field_count(stmt) && mysql_stmt_store_result(stmt))
+ {
+ handle_error(command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ goto end;
+ }
+
+ /* If we got here the statement was both executed and read successfully */
+ handle_no_error(command);
+ if (!disable_result_log)
+ {
+ /*
+ Not all statements creates a result set. If there is one we can
+ now create another normal result set that contains the meta
+ data. This set can be handled almost like any other non prepared
+ statement result set.
+ */
+ if ((res= mysql_stmt_result_metadata(stmt)) != NULL)
+ {
+ /* Take the column count from meta info */
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
+ uint num_fields= mysql_num_fields(res);
+
+ if (display_metadata)
+ append_metadata(ds, fields, num_fields);
+
+ if (!display_result_vertically)
+ append_table_headings(ds, fields, num_fields);
+
+ append_stmt_result(ds, stmt, fields, num_fields);
+
+ mysql_free_result(res); /* Free normal result set with meta data */
+
+ /*
+ Normally, if there is a result set, we do not show warnings from the
+ prepare phase. This is because some warnings are generated both during
+ prepare and execute; this would generate different warning output
+ between normal and ps-protocol test runs.
+
+ The --enable_prepare_warnings command can be used to change this so
+ that warnings from both the prepare and execute phase are shown.
+ */
+ }
+ else
+ {
+ /*
+ This is a query without resultset
+ */
+ }
+
+ /*
+ Fetch info before fetching warnings, since it will be reset
+ otherwise.
+ */
+ if (!disable_info)
+ append_info(ds, mysql_stmt_affected_rows(stmt), mysql_info(mysql));
+
+ if (display_session_track_info)
+ append_session_track_info(ds, mysql);
+
+
+ if (!disable_warnings)
+ {
+ /* Get the warnings from execute */
+
+ /* Append warnings to ds - if there are any */
+ if (append_warnings(&ds_execute_warnings, mysql) ||
+ ds_execute_warnings.length ||
+ ds_warnings->length)
+ {
+ dynstr_append_mem(ds, "Warnings:\n", 10);
+ if (ds_warnings->length)
+ dynstr_append_mem(ds, ds_warnings->str,
+ ds_warnings->length);
+ if (ds_execute_warnings.length)
+ dynstr_append_mem(ds, ds_execute_warnings.str,
+ ds_execute_warnings.length);
+ }
+ }
+ }
+
+end:
+ if (!disable_warnings)
+ {
+ dynstr_free(&ds_execute_warnings);
+ }
+
+ /*
+ We save the return code (mysql_stmt_errno(stmt)) from the last call sent
+ to the server into the mysqltest builtin variable $mysql_errno. This
+ variable then can be used from the test case itself.
+ */
+
+ var_set_errno(mysql_stmt_errno(stmt));
+
+ revert_properties();
+
+ /* Close the statement if reconnect, need new prepare */
+ {
+#ifndef EMBEDDED_LIBRARY
+ my_bool reconnect;
+ mysql_get_option(mysql, MYSQL_OPT_RECONNECT, &reconnect);
+ if (reconnect)
+#else
+ if (mysql->reconnect)
+#endif
+ {
+ if (cn->ps_params)
+ {
+ for (size_t i=0; i<stmt->param_count; i++)
+ {
+ my_free(cn->ps_params[i].buffer);
+ cn->ps_params[i].buffer= NULL;
+ }
+ my_free(cn->ps_params);
+ }
+ mysql_stmt_close(stmt);
+ cn->stmt= NULL;
+ cn->ps_params= NULL;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ close a prepared statement C API
+
+ SYNPOSIS
+ run_close_stmt
+ mysql - mysql handle
+ command - current command pointer
+ query - query string to execute
+ query_len - length query string to execute
+ ds - output buffer where to store result form query
+
+ RETURN VALUE
+ error - function will not return
+*/
+
+void run_close_stmt(struct st_connection *cn, struct st_command *command,
+ const char *query, size_t query_len, DYNAMIC_STRING *ds,
+ DYNAMIC_STRING *ds_warnings
+ )
+{
+ MYSQL_STMT *stmt= cn->stmt;
+ DBUG_ENTER("run_close_stmt");
+ DBUG_PRINT("query", ("'%-.60s'", query));
+
+ if (cn->ps_params)
+ {
+
+ for (size_t i=0; i<stmt->param_count; i++)
+ {
+ my_free(cn->ps_params[i].buffer);
+ cn->ps_params[i].buffer= NULL;
+ }
+ my_free(cn->ps_params);
+ }
+
+ /* Close the statement */
+ if (stmt)
+ {
+ mysql_stmt_close(stmt);
+ cn->stmt= NULL;
+ }
+ cn->ps_params= NULL;
+
+ DBUG_VOID_RETURN;
+}
+
/*
@@ -9526,6 +9975,10 @@ int main(int argc, char **argv)
/* fall through */
case Q_QUERY:
case Q_REAP:
+ case Q_PS_PREPARE:
+ case Q_PS_BIND:
+ case Q_PS_EXECUTE:
+ case Q_PS_CLOSE:
{
my_bool old_display_result_vertically= display_result_vertically;
/* Default is full query, both reap and send */
diff --git a/cmake/submodules.cmake b/cmake/submodules.cmake
index 91f9f9e487a..34dcfbea77a 100644
--- a/cmake/submodules.cmake
+++ b/cmake/submodules.cmake
@@ -17,20 +17,29 @@ IF(GIT_EXECUTABLE AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
${GIT_EXECUTABLE} config cmake.update-submodules yes")
ELSEIF(git_config_get_result EQUAL 128)
SET(update_result 0)
- ELSEIF (cmake_update_submodules MATCHES force)
- MESSAGE(STATUS "Updating submodules (forced)")
- EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init --force --recursive --depth=1
- WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
- RESULT_VARIABLE update_result)
- ELSEIF (cmake_update_submodules MATCHES yes)
- EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init --recursive --depth=1
- WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
- RESULT_VARIABLE update_result)
ELSE()
- MESSAGE(STATUS "Updating submodules")
- EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init --recursive --depth=1
- WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
- RESULT_VARIABLE update_result)
+ SET(UPDATE_SUBMODULES_COMMAND
+ "${GIT_EXECUTABLE}" submodule update --init --recursive)
+ # Old Git may not work with "--depth 1".
+ # See also: https://github.com/git/git/commit/fb43e31f2b43076e7a30c9cd00d0241cb8cf97eb
+ IF(NOT GIT_VERSION_STRING VERSION_LESS "2.8.0")
+ SET(UPDATE_SUBMODULES_COMMAND ${UPDATE_SUBMODULES_COMMAND} --depth 1)
+ ENDIF()
+ IF(cmake_update_submodules MATCHES force)
+ MESSAGE(STATUS "Updating submodules (forced)")
+ EXECUTE_PROCESS(COMMAND ${UPDATE_SUBMODULES_COMMAND} --force
+ WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+ RESULT_VARIABLE update_result)
+ ELSEIF(cmake_update_submodules MATCHES yes)
+ EXECUTE_PROCESS(COMMAND ${UPDATE_SUBMODULES_COMMAND}
+ WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+ RESULT_VARIABLE update_result)
+ ELSE()
+ MESSAGE(STATUS "Updating submodules")
+ EXECUTE_PROCESS(COMMAND ${UPDATE_SUBMODULES_COMMAND}
+ WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+ RESULT_VARIABLE update_result)
+ ENDIF()
ENDIF()
ENDIF()
diff --git a/include/my_atomic.h b/include/my_atomic.h
index 81da9e35cf9..270134a6caf 100644
--- a/include/my_atomic.h
+++ b/include/my_atomic.h
@@ -2,7 +2,7 @@
#define MY_ATOMIC_INCLUDED
/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- Copyright (c) 2018, 2020, MariaDB
+ Copyright (c) 2018, 2022, 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
@@ -115,22 +115,6 @@
#include "atomic/gcc_builtins.h"
#endif
-#if SIZEOF_LONG == 4
-#define my_atomic_addlong(A,B) my_atomic_add32((int32*) (A), (B))
-#define my_atomic_loadlong(A) my_atomic_load32((int32*) (A))
-#define my_atomic_loadlong_explicit(A,O) my_atomic_load32_explicit((int32*) (A), (O))
-#define my_atomic_storelong(A,B) my_atomic_store32((int32*) (A), (B))
-#define my_atomic_faslong(A,B) my_atomic_fas32((int32*) (A), (B))
-#define my_atomic_caslong(A,B,C) my_atomic_cas32((int32*) (A), (int32*) (B), (C))
-#else
-#define my_atomic_addlong(A,B) my_atomic_add64((int64*) (A), (B))
-#define my_atomic_loadlong(A) my_atomic_load64((int64*) (A))
-#define my_atomic_loadlong_explicit(A,O) my_atomic_load64_explicit((int64*) (A), (O))
-#define my_atomic_storelong(A,B) my_atomic_store64((int64*) (A), (B))
-#define my_atomic_faslong(A,B) my_atomic_fas64((int64*) (A), (B))
-#define my_atomic_caslong(A,B,C) my_atomic_cas64((int64*) (A), (int64*) (B), (C))
-#endif
-
#ifndef MY_MEMORY_ORDER_SEQ_CST
#define MY_MEMORY_ORDER_RELAXED
#define MY_MEMORY_ORDER_CONSUME
diff --git a/mysql-test/main/contributors.result b/mysql-test/main/contributors.result
index 0c7ca03a2c5..8d72373696c 100644
--- a/mysql-test/main/contributors.result
+++ b/mysql-test/main/contributors.result
@@ -5,6 +5,8 @@ Tencent Cloud https://cloud.tencent.com Platinum Sponsor of the MariaDB Foundati
Microsoft https://microsoft.com/ Platinum Sponsor of the MariaDB Foundation
MariaDB Corporation https://mariadb.com Founding member, Platinum Sponsor of the MariaDB Foundation
ServiceNow https://servicenow.com Platinum Sponsor of the MariaDB Foundation
+Intel https://www.intel.com Platinum Sponsor of the MariaDB Foundation
+SIT https://sit.org Platinum Sponsor of the MariaDB Foundation
Visma https://visma.com Gold Sponsor of the MariaDB Foundation
DBS https://dbs.com Gold Sponsor of the MariaDB Foundation
IBM https://www.ibm.com Gold Sponsor of the MariaDB Foundation
diff --git a/mysql-test/main/ctype_utf32.result b/mysql-test/main/ctype_utf32.result
index cf9db875290..069e4174c9d 100644
--- a/mysql-test/main/ctype_utf32.result
+++ b/mysql-test/main/ctype_utf32.result
@@ -2913,5 +2913,30 @@ t1 CREATE TABLE `t1` (
DROP TABLE t1;
SET NAMES utf8;
#
+# MDEV-28078 Garbage on multiple equal ENUMs with tricky character sets
+#
+CREATE TABLE t1 (
+c1 ENUM ('a','b') CHARACTER SET utf32 DEFAULT 'a',
+c2 ENUM ('a','b') CHARACTER SET utf32 DEFAULT 'a'
+);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` enum('a','b') CHARACTER SET utf32 DEFAULT 'a',
+ `c2` enum('a','b') CHARACTER SET utf32 DEFAULT 'a'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 ENUM ('00000061','00000062') DEFAULT '00000061' COLLATE latin1_bin,
+c2 ENUM ('a','b') DEFAULT 'a' COLLATE utf32_general_ci
+);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` enum('00000061','00000062') CHARACTER SET latin1 COLLATE latin1_bin DEFAULT '00000061',
+ `c2` enum('a','b') CHARACTER SET utf32 DEFAULT 'a'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+#
# End of 10.2 tests
#
diff --git a/mysql-test/main/ctype_utf32.test b/mysql-test/main/ctype_utf32.test
index 6944fdb30be..0e50405f871 100644
--- a/mysql-test/main/ctype_utf32.test
+++ b/mysql-test/main/ctype_utf32.test
@@ -1068,5 +1068,24 @@ SET NAMES utf8;
--echo #
+--echo # MDEV-28078 Garbage on multiple equal ENUMs with tricky character sets
+--echo #
+
+CREATE TABLE t1 (
+ c1 ENUM ('a','b') CHARACTER SET utf32 DEFAULT 'a',
+ c2 ENUM ('a','b') CHARACTER SET utf32 DEFAULT 'a'
+);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c1 ENUM ('00000061','00000062') DEFAULT '00000061' COLLATE latin1_bin,
+ c2 ENUM ('a','b') DEFAULT 'a' COLLATE utf32_general_ci
+);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+
+--echo #
--echo # End of 10.2 tests
--echo #
diff --git a/mysql-test/main/multi_update_innodb.result b/mysql-test/main/multi_update_innodb.result
index 2ec7eb3065e..52bbece4fa0 100644
--- a/mysql-test/main/multi_update_innodb.result
+++ b/mysql-test/main/multi_update_innodb.result
@@ -207,4 +207,19 @@ ERROR 23000: Duplicate entry '0000-00-00 00:00:00' for key 'f2k'
DROP VIEW v1;
DROP TABLE t3,t4;
SET @@sql_mode=@save_sql_mode;
+#
# End of 10.2 tests
+#
+#
+# MDEV-28095 crash in multi-update and implicit grouping
+#
+CREATE TABLE t1 (a int) engine=innodb;
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 (b int);
+INSERT INTO t2 VALUES (1),(2);
+UPDATE t1 NATURAL JOIN t2 SET a = 1 ORDER BY AVG (a) ;
+ERROR HY000: Invalid use of group function
+DROP TABLE t1, t2;
+#
+# End of 10.3 tests
+#
diff --git a/mysql-test/main/multi_update_innodb.test b/mysql-test/main/multi_update_innodb.test
index 04736482011..02f6a7a3316 100644
--- a/mysql-test/main/multi_update_innodb.test
+++ b/mysql-test/main/multi_update_innodb.test
@@ -243,4 +243,23 @@ DROP VIEW v1;
DROP TABLE t3,t4;
SET @@sql_mode=@save_sql_mode;
+--echo #
--echo # End of 10.2 tests
+--echo #
+
+--echo #
+--echo # MDEV-28095 crash in multi-update and implicit grouping
+--echo #
+CREATE TABLE t1 (a int) engine=innodb;
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 (b int);
+INSERT INTO t2 VALUES (1),(2);
+--error ER_INVALID_GROUP_FUNC_USE
+UPDATE t1 NATURAL JOIN t2 SET a = 1 ORDER BY AVG (a) ;
+DROP TABLE t1, t2;
+
+
+--echo #
+--echo # End of 10.3 tests
+--echo #
+
diff --git a/mysql-test/main/opt_tvc.result b/mysql-test/main/opt_tvc.result
index 9752aa71bfb..9b6d97492cd 100644
--- a/mysql-test/main/opt_tvc.result
+++ b/mysql-test/main/opt_tvc.result
@@ -732,3 +732,30 @@ a b
4 4
drop table t1;
SET @@in_predicate_conversion_threshold= default;
+#
+# MDEV-27937: Prepared statement with ? in the list if IN predicate
+#
+set in_predicate_conversion_threshold=2;
+create table t1 (id int, a int, b int);
+insert into t1 values (1,3,30), (2,7,70), (3,1,10);
+prepare stmt from "
+select * from t1 where a in (7, ?, 5, 1);
+";
+execute stmt using 3;
+id a b
+1 3 30
+2 7 70
+3 1 10
+deallocate prepare stmt;
+prepare stmt from "
+select * from t1 where (a,b) in ((7,70), (3,?), (5,50), (1,10));
+";
+execute stmt using 30;
+id a b
+1 3 30
+2 7 70
+3 1 10
+deallocate prepare stmt;
+drop table t1;
+set in_predicate_conversion_threshold=default;
+# End of 10.3 tests
diff --git a/mysql-test/main/opt_tvc.test b/mysql-test/main/opt_tvc.test
index e4e8c6d7919..f8469f22aa1 100644
--- a/mysql-test/main/opt_tvc.test
+++ b/mysql-test/main/opt_tvc.test
@@ -428,3 +428,29 @@ eval $query;
drop table t1;
SET @@in_predicate_conversion_threshold= default;
+--echo #
+--echo # MDEV-27937: Prepared statement with ? in the list if IN predicate
+--echo #
+
+set in_predicate_conversion_threshold=2;
+
+create table t1 (id int, a int, b int);
+insert into t1 values (1,3,30), (2,7,70), (3,1,10);
+
+prepare stmt from "
+select * from t1 where a in (7, ?, 5, 1);
+";
+execute stmt using 3;
+deallocate prepare stmt;
+
+prepare stmt from "
+select * from t1 where (a,b) in ((7,70), (3,?), (5,50), (1,10));
+";
+execute stmt using 30;
+deallocate prepare stmt;
+
+drop table t1;
+
+set in_predicate_conversion_threshold=default;
+
+--echo # End of 10.3 tests
diff --git a/mysql-test/main/processlist.result b/mysql-test/main/processlist.result
index 2d3228a6d91..d99160f5c74 100644
--- a/mysql-test/main/processlist.result
+++ b/mysql-test/main/processlist.result
@@ -40,3 +40,23 @@ utf8mb4_string xxx😎yyy
#
# End of 10.1 tests
#
+#
+# Start of 10.3 tests
+#
+#
+# MDEV-28131 Unexpected warning while selecting from information_schema.processlist
+#
+connect conn1, localhost, root,,;
+connection conn1;
+SELECT SLEEP(1000);
+connection default;
+SELECT progress FROM information_schema.processlist WHERE info='SELECT SLEEP(1000)';
+progress
+0.000
+connection conn1;
+Got one of the listed errors
+connection default;
+disconnect conn1;
+#
+# End of 10.3 tests
+#
diff --git a/mysql-test/main/processlist.test b/mysql-test/main/processlist.test
index 8e98701459a..f419f57ea2f 100644
--- a/mysql-test/main/processlist.test
+++ b/mysql-test/main/processlist.test
@@ -70,3 +70,38 @@ SELECT INFO, INFO_BINARY, 'xxx😎yyy' AS utf8mb4_string FROM INFORMATION_SCHEMA
--echo #
--echo # End of 10.1 tests
--echo #
+
+--echo #
+--echo # Start of 10.3 tests
+--echo #
+
+--echo #
+--echo # MDEV-28131 Unexpected warning while selecting from information_schema.processlist
+--echo #
+
+connect (conn1, localhost, root,,);
+connection conn1;
+let $ID= `select connection_id()`;
+send SELECT SLEEP(1000);
+connection default;
+let $wait_timeout= 10;
+let $wait_condition=select count(*)=1 from information_schema.processlist
+where state='User sleep' and info='SELECT SLEEP(1000)';
+--source include/wait_condition.inc
+SELECT progress FROM information_schema.processlist WHERE info='SELECT SLEEP(1000)';
+disable_query_log;
+eval kill $ID;
+enable_query_log;
+let $wait_timeout= 10;
+let $wait_condition=select count(*)=0 from information_schema.processlist
+where state='User sleep' and info='SELECT SLEEP(1000)';
+--source include/wait_condition.inc
+connection conn1;
+--error 2013,ER_CONNECTION_KILLED
+reap;
+connection default;
+disconnect conn1;
+
+--echo #
+--echo # End of 10.3 tests
+--echo #
diff --git a/mysql-test/main/sp-cursor.result b/mysql-test/main/sp-cursor.result
index 2656ef8821d..b1c2b335ea4 100644
--- a/mysql-test/main/sp-cursor.result
+++ b/mysql-test/main/sp-cursor.result
@@ -737,3 +737,66 @@ rec.en1
c
DROP PROCEDURE p1;
DROP TABLE t1;
+#
+# MDEV-26009: Server crash when calling twice procedure using FOR-loop
+#
+CREATE TABLE t1 ( id int, name varchar(24));
+INSERT INTO t1 values (1, 'x'), (2, 'y'), (3, 'z');
+create function get_name(_id int) returns varchar(24)
+return (select name from t1 where id = _id);
+select get_name(id) from t1;
+get_name(id)
+x
+y
+z
+create procedure test_proc()
+begin
+declare _cur cursor for select get_name(id) from t1;
+for row in _cur do select 1; end for;
+end;
+^^
+call test_proc();
+1
+1
+1
+1
+1
+1
+call test_proc();
+1
+1
+1
+1
+1
+1
+drop procedure test_proc;
+drop function get_name;
+drop table t1;
+CREATE TABLE t1 (id int, name varchar(24));
+INSERT INTO t1 (id, name) VALUES (1, 'x'),(2, 'y'),(3, 'z');
+create function get_name(_id int) returns varchar(24)
+return (select name from t1 where id = _id);
+create view v1 as select get_name(id) from t1;
+create procedure test_proc()
+begin
+declare _cur cursor for select 1 from v1;
+for row in _cur do select 1; end for;
+end$$
+call test_proc();
+1
+1
+1
+1
+1
+1
+call test_proc();
+1
+1
+1
+1
+1
+1
+drop procedure test_proc;
+drop view v1;
+drop function get_name;
+drop table t1;
diff --git a/mysql-test/main/sp-cursor.test b/mysql-test/main/sp-cursor.test
index 97483ef9caf..9794815c784 100644
--- a/mysql-test/main/sp-cursor.test
+++ b/mysql-test/main/sp-cursor.test
@@ -744,3 +744,59 @@ DELIMITER ;$$
CALL p1();
DROP PROCEDURE p1;
DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-26009: Server crash when calling twice procedure using FOR-loop
+--echo #
+
+
+CREATE TABLE t1 ( id int, name varchar(24));
+INSERT INTO t1 values (1, 'x'), (2, 'y'), (3, 'z');
+
+create function get_name(_id int) returns varchar(24)
+ return (select name from t1 where id = _id);
+
+select get_name(id) from t1;
+
+delimiter ^^;
+
+create procedure test_proc()
+begin
+ declare _cur cursor for select get_name(id) from t1;
+ for row in _cur do select 1; end for;
+end;
+^^
+delimiter ;^^
+
+call test_proc();
+call test_proc();
+
+drop procedure test_proc;
+drop function get_name;
+drop table t1;
+
+
+CREATE TABLE t1 (id int, name varchar(24));
+INSERT INTO t1 (id, name) VALUES (1, 'x'),(2, 'y'),(3, 'z');
+
+create function get_name(_id int) returns varchar(24)
+ return (select name from t1 where id = _id);
+
+create view v1 as select get_name(id) from t1;
+
+delimiter $$;
+create procedure test_proc()
+begin
+ declare _cur cursor for select 1 from v1;
+ for row in _cur do select 1; end for;
+end$$
+delimiter ;$$
+
+call test_proc();
+call test_proc();
+
+drop procedure test_proc;
+drop view v1;
+drop function get_name;
+drop table t1;
diff --git a/mysql-test/main/view.result b/mysql-test/main/view.result
index 3ff25dfc127..fe6b5cfbea7 100644
--- a/mysql-test/main/view.result
+++ b/mysql-test/main/view.result
@@ -6846,6 +6846,34 @@ id bar
Drop View v1;
Drop table t1;
#
+# MDEV-24281: Execution of PREPARE from CREATE VIEW statement
+#
+create table t1 (s1 int);
+insert into t1 values (3), (7), (1);
+prepare stmt from "
+create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
+";
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 's1' AS `My_exp_1_s1`,`t1`.`s1` AS `s1`,1 AS `My_exp_s1` from `t1` latin1 latin1_swedish_ci
+select * from v1;
+My_exp_1_s1 s1 My_exp_s1
+s1 3 1
+s1 7 1
+s1 1 1
+drop view v1;
+prepare stmt from "
+create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
+";
+execute stmt;
+execute stmt;
+ERROR 42S01: Table 'v1' already exists
+deallocate prepare stmt;
+drop view v1;
+drop table t1;
+#
# End of 10.3 tests
#
#
diff --git a/mysql-test/main/view.test b/mysql-test/main/view.test
index 3184d3a3fdc..c4de2e6eb03 100644
--- a/mysql-test/main/view.test
+++ b/mysql-test/main/view.test
@@ -6566,6 +6566,32 @@ Drop View v1;
Drop table t1;
--echo #
+--echo # MDEV-24281: Execution of PREPARE from CREATE VIEW statement
+--echo #
+
+create table t1 (s1 int);
+insert into t1 values (3), (7), (1);
+
+prepare stmt from "
+create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
+";
+execute stmt;
+deallocate prepare stmt;
+show create view v1;
+select * from v1;
+drop view v1;
+
+prepare stmt from "
+create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
+";
+execute stmt;
+--error ER_TABLE_EXISTS_ERROR
+execute stmt;
+deallocate prepare stmt;
+drop view v1;
+drop table t1;
+
+--echo #
--echo # End of 10.3 tests
--echo #
diff --git a/mysql-test/suite/binlog/r/binlog_autocommit_off_no_hang.result b/mysql-test/suite/binlog/r/binlog_autocommit_off_no_hang.result
new file mode 100644
index 00000000000..71eecd881ca
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_autocommit_off_no_hang.result
@@ -0,0 +1,6 @@
+ALTER TABLE mysql.gtid_slave_pos ENGINE=innodb;
+# Restart the server so mysqld reads the gtid_slave_pos using innodb
+# Set gtid_slave_pos should not hang
+SET GLOBAL gtid_slave_pos=@@gtid_binlog_pos;
+COMMIT;
+RESET MASTER;
diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_raw_flush.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_raw_flush.result
new file mode 100644
index 00000000000..9148f0e8c2b
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_raw_flush.result
@@ -0,0 +1,7 @@
+CREATE TABLE t1 (a int);
+FLUSH LOGS;
+INSERT INTO t1 VALUES (1);
+# timeout TIMEOUT MYSQL_BINLOG --raw --read-from-remote-server --user=root --host=127.0.0.1 --port=MASTER_MYPORT --stop-never --result-file=MYSQLTEST_VARDIR/tmp/ master-bin.000001
+# MYSQL_BINLOG MYSQLTEST_VARDIR/tmp/master-bin.000002 > MYSQLTEST_VARDIR/tmp/local-bin.000002.out
+FOUND 1 /GTID 0-1-2/ in local-bin.000002.out
+DROP TABLE t1;
diff --git a/mysql-test/suite/binlog/t/binlog_autocommit_off_no_hang-master.opt b/mysql-test/suite/binlog/t/binlog_autocommit_off_no_hang-master.opt
new file mode 100644
index 00000000000..e0fa81e6eeb
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_autocommit_off_no_hang-master.opt
@@ -0,0 +1 @@
+--autocommit=0
diff --git a/mysql-test/suite/binlog/t/binlog_autocommit_off_no_hang.test b/mysql-test/suite/binlog/t/binlog_autocommit_off_no_hang.test
new file mode 100644
index 00000000000..8f1dbb2a2dd
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_autocommit_off_no_hang.test
@@ -0,0 +1,45 @@
+#
+# Purpose:
+# When the mysql.gtid_slave_pos table uses the InnoDB engine, and mysqld
+# starts, it reads the table and begins a transaction. After mysqld reads the
+# value, it should end the transaction and release all associated locks.
+# The bug reported in DBAAS-7828 shows that when autocommit is off, the locks
+# are not released, resulting in indefinite hangs on future attempts to change
+# gtid_slave_pos. This test ensures its fix such that the locks are properly
+# released.
+#
+# References:
+# DBAAS-7828: Primary/replica: configuration change of "autocommit=0" can
+# not be applied
+#
+
+--source include/have_innodb.inc
+--source include/have_log_bin.inc
+
+# Reading gtid_slave_pos table is format independent so just use one for
+# reduced test time
+--source include/have_binlog_format_row.inc
+
+--let old_slave_pos_engine= query_get_value(SHOW TABLE STATUS FROM mysql LIKE 'gtid_slave_pos', Engine, 1)
+
+# Use a transactional engine
+ALTER TABLE mysql.gtid_slave_pos ENGINE=innodb;
+
+--echo # Restart the server so mysqld reads the gtid_slave_pos using innodb
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--shutdown_server
+--source include/wait_until_disconnected.inc
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--echo # Set gtid_slave_pos should not hang
+SET GLOBAL gtid_slave_pos=@@gtid_binlog_pos;
+COMMIT;
+
+# Revert table type
+--disable_query_log
+--eval ALTER TABLE mysql.gtid_slave_pos ENGINE=$old_slave_pos_engine
+--enable_query_log
+
+RESET MASTER;
diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_raw_flush.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_raw_flush.test
new file mode 100644
index 00000000000..f95fc0137a2
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_raw_flush.test
@@ -0,0 +1,45 @@
+#
+# Purpose:
+# When using mariadb-binlog with options for --raw and --stop-never, events
+# from the master's currently active log file should be written to their
+# respective log file specified by --result-file, and shown on-disk. This test
+# ensures that the log files on disk, created by mariadb-binlog, have the most
+# up-to-date events from the master.
+#
+# Methodology:
+# On the master, rotate to a newly active binlog file and write an event to
+# it. Read the master's binlog using mariadb-binlog with --raw and --stop-never
+# and write the data to an intermediary binlog file (a timeout is used on this
+# command to ensure it exits). Read the local intermediary binlog file to ensure
+# that the master's most recent event exists in the local file.
+#
+# References:
+# MDEV-14608: mysqlbinlog lastest backupfile size is 0
+#
+
+--source include/linux.inc
+--source include/have_log_bin.inc
+
+# Create newly active log
+CREATE TABLE t1 (a int);
+FLUSH LOGS;
+INSERT INTO t1 VALUES (1);
+
+# Read binlog data from master to intermediary result file
+--let TIMEOUT=1
+--echo # timeout TIMEOUT MYSQL_BINLOG --raw --read-from-remote-server --user=root --host=127.0.0.1 --port=MASTER_MYPORT --stop-never --result-file=MYSQLTEST_VARDIR/tmp/ master-bin.000001
+--error 124 # Error 124 means timeout was reached
+--exec timeout $TIMEOUT $MYSQL_BINLOG --raw --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT --stop-never --result-file=$MYSQLTEST_VARDIR/tmp/ master-bin.000001
+
+# Ensure the binlog output has the most recent events from the master
+--echo # MYSQL_BINLOG MYSQLTEST_VARDIR/tmp/master-bin.000002 > MYSQLTEST_VARDIR/tmp/local-bin.000002.out
+--exec $MYSQL_BINLOG $MYSQLTEST_VARDIR/tmp/master-bin.000002 > $MYSQLTEST_VARDIR/tmp/local-bin.000002.out
+--let SEARCH_PATTERN= GTID 0-1-2
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/local-bin.000002.out
+--source include/search_pattern_in_file.inc
+
+# Cleanup
+DROP TABLE t1;
+--remove_file $MYSQLTEST_VARDIR/tmp/master-bin.000001
+--remove_file $MYSQLTEST_VARDIR/tmp/master-bin.000002
+--remove_file $MYSQLTEST_VARDIR/tmp/local-bin.000002.out
diff --git a/mysql-test/suite/compat/oracle/r/sp-package.result b/mysql-test/suite/compat/oracle/r/sp-package.result
index 42159ccad54..6fbe568f719 100644
--- a/mysql-test/suite/compat/oracle/r/sp-package.result
+++ b/mysql-test/suite/compat/oracle/r/sp-package.result
@@ -2962,3 +2962,311 @@ END $$
CALL xyz.xyz123(17,18,@R);
DROP PACKAGE xyz;
DROP TABLE t1;
+#
+# MDEV-28166 sql_mode=ORACLE: fully qualified package function calls do not work: db.pkg.func()
+#
+SELECT `db `.pkg.func();
+ERROR 42000: Incorrect database name 'db '
+SELECT db.`pkg `.func();
+ERROR 42000: Incorrect routine name 'pkg '
+SELECT db.pkg.`func `();
+ERROR 42000: Incorrect routine name 'func '
+CREATE DATABASE db1;
+USE db1;
+CREATE PACKAGE pkg1 AS
+FUNCTION f1 RETURN TEXT;
+FUNCTION f2_db1_pkg1_f1 RETURN TEXT;
+FUNCTION f2_pkg1_f1 RETURN TEXT;
+FUNCTION f2_f1 RETURN TEXT;
+END;
+$$
+CREATE PACKAGE BODY pkg1
+AS
+FUNCTION f1 RETURN TEXT IS
+BEGIN
+RETURN 'This is db1.pkg1.f1';
+END;
+FUNCTION f2_db1_pkg1_f1 RETURN TEXT IS
+BEGIN
+RETURN db1.pkg1.f1();
+END;
+FUNCTION f2_pkg1_f1 RETURN TEXT IS
+BEGIN
+RETURN pkg1.f1();
+END;
+FUNCTION f2_f1 RETURN TEXT IS
+BEGIN
+RETURN f1();
+END;
+END;
+$$
+USE db1;
+SELECT pkg1.f2_db1_pkg1_f1();
+pkg1.f2_db1_pkg1_f1()
+This is db1.pkg1.f1
+SELECT pkg1.f2_pkg1_f1();
+pkg1.f2_pkg1_f1()
+This is db1.pkg1.f1
+SELECT pkg1.f2_f1();
+pkg1.f2_f1()
+This is db1.pkg1.f1
+SELECT db1.pkg1.f2_db1_pkg1_f1();
+db1.pkg1.f2_db1_pkg1_f1()
+This is db1.pkg1.f1
+SELECT db1.pkg1.f2_pkg1_f1();
+db1.pkg1.f2_pkg1_f1()
+This is db1.pkg1.f1
+SELECT db1.pkg1.f2_f1();
+db1.pkg1.f2_f1()
+This is db1.pkg1.f1
+USE test;
+SELECT db1.pkg1.f2_db1_pkg1_f1();
+db1.pkg1.f2_db1_pkg1_f1()
+This is db1.pkg1.f1
+SELECT db1.pkg1.f2_pkg1_f1();
+db1.pkg1.f2_pkg1_f1()
+This is db1.pkg1.f1
+SELECT db1.pkg1.f2_f1();
+db1.pkg1.f2_f1()
+This is db1.pkg1.f1
+DROP DATABASE db1;
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+CREATE PACKAGE db1.pkg1 AS
+FUNCTION f1 RETURN TEXT;
+END;
+$$
+CREATE PACKAGE BODY db1.pkg1 AS
+FUNCTION f1 RETURN TEXT AS
+BEGIN
+RETURN 'This is db1.pkg1.f1';
+END;
+END;
+$$
+CREATE PACKAGE db2.pkg1 AS
+FUNCTION f1 RETURN TEXT;
+FUNCTION var1 RETURN TEXT;
+FUNCTION var2 RETURN TEXT;
+END;
+$$
+CREATE PACKAGE BODY db2.pkg1 AS
+m_var1 TEXT;
+m_var2 TEXT;
+FUNCTION f1 RETURN TEXT AS
+BEGIN
+RETURN 'This is db2.pkg1.f1';
+END;
+FUNCTION var1 RETURN TEXT AS
+BEGIN
+RETURN m_var1;
+END;
+FUNCTION var2 RETURN TEXT AS
+BEGIN
+RETURN m_var2;
+END;
+BEGIN
+m_var1:= db1.pkg1.f1();
+m_var2:= db2.pkg1.f1();
+END;
+$$
+SELECT db2.pkg1.var1(), db2.pkg1.var2();
+db2.pkg1.var1() db2.pkg1.var2()
+This is db1.pkg1.f1 This is db2.pkg1.f1
+DROP DATABASE db1;
+DROP DATABASE db2;
+CREATE PACKAGE pkg1 AS
+FUNCTION f1(a TEXT) RETURN TEXT;
+END;
+$$
+CREATE PACKAGE BODY pkg1 AS
+FUNCTION f1(a TEXT) RETURN TEXT AS
+BEGIN
+RETURN a;
+END;
+END;
+$$
+SELECT test.pkg1.f1('xxx');
+test.pkg1.f1('xxx')
+xxx
+SELECT test.pkg1.f1('xxx' AS 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 'AS a)' at line 1
+DROP PACKAGE pkg1;
+#
+# MDEV-19328 sql_mode=ORACLE: Package function in VIEW
+#
+SET sql_mode=ORACLE;
+CREATE PACKAGE test1 AS
+FUNCTION f_test RETURN number;
+END test1;
+$$
+CREATE PACKAGE BODY test1
+AS
+FUNCTION f_test RETURN NUMBER IS
+BEGIN
+RETURN 1;
+END;
+END test1;
+$$
+SET sql_mode=ORACLE;
+CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test1.f_test();
+SELECT * FROM v_test;
+c1
+1
+SHOW CREATE VIEW v_test;
+View v_test
+Create View CREATE VIEW "v_test" AS select 1 AS "c1" from DUAL where 1 = "test"."test1"."f_test"()
+character_set_client latin1
+collation_connection latin1_swedish_ci
+SET sql_mode=DEFAULT;
+SELECT * FROM v_test;
+c1
+1
+SHOW CREATE VIEW v_test;
+View v_test
+Create View CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_test` AS select 1 AS `c1` from DUAL where 1 = `test`.`test1`.`f_test`()
+character_set_client latin1
+collation_connection latin1_swedish_ci
+DROP VIEW v_test;
+SET sql_mode=DEFAULT;
+CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test1.f_test();
+ERROR 42000: FUNCTION test1.f_test does not exist
+SET sql_mode=ORACLE;
+CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test.test1.f_test();
+SELECT * FROM v_test;
+c1
+1
+SHOW CREATE VIEW v_test;
+View v_test
+Create View CREATE VIEW "v_test" AS select 1 AS "c1" from DUAL where 1 = "test"."test1"."f_test"()
+character_set_client latin1
+collation_connection latin1_swedish_ci
+SET sql_mode=DEFAULT;
+SELECT * FROM v_test;
+c1
+1
+SHOW CREATE VIEW v_test;
+View v_test
+Create View CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_test` AS select 1 AS `c1` from DUAL where 1 = `test`.`test1`.`f_test`()
+character_set_client latin1
+collation_connection latin1_swedish_ci
+DROP VIEW v_test;
+SET sql_mode=DEFAULT;
+CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test.test1.f_test();
+SELECT * FROM v_test;
+c1
+1
+SHOW CREATE VIEW v_test;
+View v_test
+Create View CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_test` AS select 1 AS `c1` from DUAL where 1 = `test`.`test1`.`f_test`()
+character_set_client latin1
+collation_connection latin1_swedish_ci
+SET sql_mode=ORACLE;
+SELECT * FROM v_test;
+c1
+1
+SHOW CREATE VIEW v_test;
+View v_test
+Create View CREATE VIEW "v_test" AS select 1 AS "c1" from DUAL where 1 = "test"."test1"."f_test"()
+character_set_client latin1
+collation_connection latin1_swedish_ci
+DROP VIEW v_test;
+SET sql_mode=ORACLE;
+DROP PACKAGE test1;
+#
+# MDEV-19804 sql_mode=ORACLE: call procedure in packages
+#
+CALL `db1 `.pkg.p;
+ERROR 42000: Incorrect database name 'db1 '
+CALL db1.`pkg `.p;
+ERROR 42000: Incorrect routine name 'pkg '
+CALL db1.pkg.`p `;
+ERROR 42000: Incorrect routine name 'p '
+SET sql_mode=ORACLE;
+CREATE PACKAGE pkg1 as
+PROCEDURE p1();
+END;
+$$
+CREATE PACKAGE BODY pkg1 as
+PROCEDURE p1() as
+BEGIN
+SELECT 'test-function' AS c1;
+END;
+END;
+$$
+CALL pkg1.p1;
+c1
+test-function
+CALL test.pkg1.p1;
+c1
+test-function
+SET sql_mode=DEFAULT;
+CALL test.pkg1.p1;
+c1
+test-function
+SET sql_mode=ORACLE;
+BEGIN
+CALL pkg1.p1;
+CALL test.pkg1.p1;
+END
+$$
+c1
+test-function
+c1
+test-function
+BEGIN
+pkg1.p1;
+test.pkg1.p1;
+END
+$$
+c1
+test-function
+c1
+test-function
+DROP PACKAGE pkg1;
+CREATE DATABASE db1;
+CREATE PACKAGE db1.pkg1 AS
+PROCEDURE p1(a OUT TEXT);
+END;
+$$
+CREATE PACKAGE BODY db1.pkg1 AS
+PROCEDURE p1(a OUT TEXT) AS
+BEGIN
+a:= 'This is db1.pkg1.p1';
+END;
+END;
+$$
+CREATE DATABASE db2;
+CREATE PACKAGE db2.pkg1 AS
+FUNCTION var1 RETURN TEXT;
+PROCEDURE p1(a OUT TEXT);
+PROCEDURE p2_db1_pkg1_p1;
+END;
+$$
+CREATE PACKAGE BODY db2.pkg1 AS
+m_var1 TEXT;
+FUNCTION var1 RETURN TEXT AS
+BEGIN
+RETURN m_var1;
+END;
+PROCEDURE p1(a OUT TEXT) AS
+BEGIN
+a:= 'This is db2.pkg1.p1';
+END;
+PROCEDURE p2_db1_pkg1_p1 AS
+a TEXT;
+BEGIN
+db1.pkg1.p1(a);
+SELECT a;
+END;
+BEGIN
+db1.pkg1.p1(m_var1);
+END;
+$$
+SELECT db2.pkg1.var1();
+db2.pkg1.var1()
+This is db1.pkg1.p1
+CALL db2.pkg1.p2_db1_pkg1_p1;
+a
+This is db1.pkg1.p1
+DROP DATABASE db1;
+DROP DATABASE db2;
diff --git a/mysql-test/suite/compat/oracle/t/sp-package.test b/mysql-test/suite/compat/oracle/t/sp-package.test
index 96420c18820..401a46ad206 100644
--- a/mysql-test/suite/compat/oracle/t/sp-package.test
+++ b/mysql-test/suite/compat/oracle/t/sp-package.test
@@ -2689,3 +2689,330 @@ DELIMITER ;$$
CALL xyz.xyz123(17,18,@R);
DROP PACKAGE xyz;
DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-28166 sql_mode=ORACLE: fully qualified package function calls do not work: db.pkg.func()
+--echo #
+
+--error ER_WRONG_DB_NAME
+SELECT `db `.pkg.func();
+--error ER_SP_WRONG_NAME
+SELECT db.`pkg `.func();
+--error ER_SP_WRONG_NAME
+SELECT db.pkg.`func `();
+
+
+CREATE DATABASE db1;
+USE db1;
+
+DELIMITER $$;
+CREATE PACKAGE pkg1 AS
+ FUNCTION f1 RETURN TEXT;
+ FUNCTION f2_db1_pkg1_f1 RETURN TEXT;
+ FUNCTION f2_pkg1_f1 RETURN TEXT;
+ FUNCTION f2_f1 RETURN TEXT;
+END;
+$$
+CREATE PACKAGE BODY pkg1
+AS
+ FUNCTION f1 RETURN TEXT IS
+ BEGIN
+ RETURN 'This is db1.pkg1.f1';
+ END;
+ FUNCTION f2_db1_pkg1_f1 RETURN TEXT IS
+ BEGIN
+ RETURN db1.pkg1.f1();
+ END;
+ FUNCTION f2_pkg1_f1 RETURN TEXT IS
+ BEGIN
+ RETURN pkg1.f1();
+ END;
+ FUNCTION f2_f1 RETURN TEXT IS
+ BEGIN
+ RETURN f1();
+ END;
+END;
+$$
+DELIMITER ;$$
+
+USE db1;
+SELECT pkg1.f2_db1_pkg1_f1();
+SELECT pkg1.f2_pkg1_f1();
+SELECT pkg1.f2_f1();
+
+SELECT db1.pkg1.f2_db1_pkg1_f1();
+SELECT db1.pkg1.f2_pkg1_f1();
+SELECT db1.pkg1.f2_f1();
+
+USE test;
+SELECT db1.pkg1.f2_db1_pkg1_f1();
+SELECT db1.pkg1.f2_pkg1_f1();
+SELECT db1.pkg1.f2_f1();
+
+DROP DATABASE db1;
+
+
+#
+# Testing db.pkg.func() in the package initialization section
+#
+
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+
+DELIMITER $$;
+CREATE PACKAGE db1.pkg1 AS
+ FUNCTION f1 RETURN TEXT;
+END;
+$$
+CREATE PACKAGE BODY db1.pkg1 AS
+ FUNCTION f1 RETURN TEXT AS
+ BEGIN
+ RETURN 'This is db1.pkg1.f1';
+ END;
+END;
+$$
+DELIMITER ;$$
+
+
+DELIMITER $$;
+CREATE PACKAGE db2.pkg1 AS
+ FUNCTION f1 RETURN TEXT;
+ FUNCTION var1 RETURN TEXT;
+ FUNCTION var2 RETURN TEXT;
+END;
+$$
+CREATE PACKAGE BODY db2.pkg1 AS
+ m_var1 TEXT;
+ m_var2 TEXT;
+ FUNCTION f1 RETURN TEXT AS
+ BEGIN
+ RETURN 'This is db2.pkg1.f1';
+ END;
+ FUNCTION var1 RETURN TEXT AS
+ BEGIN
+ RETURN m_var1;
+ END;
+ FUNCTION var2 RETURN TEXT AS
+ BEGIN
+ RETURN m_var2;
+ END;
+BEGIN
+ m_var1:= db1.pkg1.f1();
+ m_var2:= db2.pkg1.f1();
+END;
+$$
+DELIMITER ;$$
+
+SELECT db2.pkg1.var1(), db2.pkg1.var2();
+
+DROP DATABASE db1;
+DROP DATABASE db2;
+
+#
+# Make sure fully qualified package function call does not support AS syntax:
+# SELECT db.pkg.func(10 AS a);
+#
+
+DELIMITER $$;
+CREATE PACKAGE pkg1 AS
+ FUNCTION f1(a TEXT) RETURN TEXT;
+END;
+$$
+CREATE PACKAGE BODY pkg1 AS
+ FUNCTION f1(a TEXT) RETURN TEXT AS
+ BEGIN
+ RETURN a;
+ END;
+END;
+$$
+DELIMITER ;$$
+SELECT test.pkg1.f1('xxx');
+--error ER_PARSE_ERROR
+SELECT test.pkg1.f1('xxx' AS a);
+DROP PACKAGE pkg1;
+
+
+--echo #
+--echo # MDEV-19328 sql_mode=ORACLE: Package function in VIEW
+--echo #
+
+SET sql_mode=ORACLE;
+DELIMITER $$;
+CREATE PACKAGE test1 AS
+ FUNCTION f_test RETURN number;
+END test1;
+$$
+CREATE PACKAGE BODY test1
+AS
+ FUNCTION f_test RETURN NUMBER IS
+ BEGIN
+ RETURN 1;
+ END;
+END test1;
+$$
+DELIMITER ;$$
+
+
+SET sql_mode=ORACLE;
+CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test1.f_test();
+SELECT * FROM v_test;
+--vertical_results
+SHOW CREATE VIEW v_test;
+--horizontal_results
+SET sql_mode=DEFAULT;
+SELECT * FROM v_test;
+--vertical_results
+SHOW CREATE VIEW v_test;
+--horizontal_results
+DROP VIEW v_test;
+
+
+SET sql_mode=DEFAULT;
+--error ER_SP_DOES_NOT_EXIST
+CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test1.f_test();
+
+
+SET sql_mode=ORACLE;
+CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test.test1.f_test();
+SELECT * FROM v_test;
+--vertical_results
+SHOW CREATE VIEW v_test;
+--horizontal_results
+SET sql_mode=DEFAULT;
+SELECT * FROM v_test;
+--vertical_results
+SHOW CREATE VIEW v_test;
+--horizontal_results
+DROP VIEW v_test;
+
+
+SET sql_mode=DEFAULT;
+CREATE VIEW v_test AS SELECT 1 AS c1 FROM DUAL WHERE 1=test.test1.f_test();
+SELECT * FROM v_test;
+--vertical_results
+SHOW CREATE VIEW v_test;
+--horizontal_results
+SET sql_mode=ORACLE;
+SELECT * FROM v_test;
+--vertical_results
+SHOW CREATE VIEW v_test;
+--horizontal_results
+DROP VIEW v_test;
+
+SET sql_mode=ORACLE;
+DROP PACKAGE test1;
+
+
+--echo #
+--echo # MDEV-19804 sql_mode=ORACLE: call procedure in packages
+--echo #
+
+--error ER_WRONG_DB_NAME
+CALL `db1 `.pkg.p;
+--error ER_SP_WRONG_NAME
+CALL db1.`pkg `.p;
+--error ER_SP_WRONG_NAME
+CALL db1.pkg.`p `;
+
+
+SET sql_mode=ORACLE;
+DELIMITER $$;
+CREATE PACKAGE pkg1 as
+ PROCEDURE p1();
+END;
+$$
+CREATE PACKAGE BODY pkg1 as
+ PROCEDURE p1() as
+ BEGIN
+ SELECT 'test-function' AS c1;
+ END;
+END;
+$$
+DELIMITER ;$$
+
+CALL pkg1.p1;
+CALL test.pkg1.p1;
+
+# In sql_mode=DEFAULT we support fully qualified package function names
+# (this is needed for VIEWs). Let's make sure we also support fully
+# qualified package procedure names, for symmetry
+
+SET sql_mode=DEFAULT;
+CALL test.pkg1.p1;
+SET sql_mode=ORACLE;
+
+DELIMITER $$;
+BEGIN
+ CALL pkg1.p1;
+ CALL test.pkg1.p1;
+END
+$$
+DELIMITER ;$$
+
+DELIMITER $$;
+BEGIN
+ pkg1.p1;
+ test.pkg1.p1;
+END
+$$
+DELIMITER ;$$
+
+DROP PACKAGE pkg1;
+
+
+#
+# Testing packages in different databases calling each other
+# in routines and in the initialization section.
+#
+
+CREATE DATABASE db1;
+DELIMITER $$;
+CREATE PACKAGE db1.pkg1 AS
+ PROCEDURE p1(a OUT TEXT);
+END;
+$$
+CREATE PACKAGE BODY db1.pkg1 AS
+ PROCEDURE p1(a OUT TEXT) AS
+ BEGIN
+ a:= 'This is db1.pkg1.p1';
+ END;
+END;
+$$
+DELIMITER ;$$
+
+CREATE DATABASE db2;
+DELIMITER $$;
+CREATE PACKAGE db2.pkg1 AS
+ FUNCTION var1 RETURN TEXT;
+ PROCEDURE p1(a OUT TEXT);
+ PROCEDURE p2_db1_pkg1_p1;
+END;
+$$
+CREATE PACKAGE BODY db2.pkg1 AS
+ m_var1 TEXT;
+ FUNCTION var1 RETURN TEXT AS
+ BEGIN
+ RETURN m_var1;
+ END;
+ PROCEDURE p1(a OUT TEXT) AS
+ BEGIN
+ a:= 'This is db2.pkg1.p1';
+ END;
+ PROCEDURE p2_db1_pkg1_p1 AS
+ a TEXT;
+ BEGIN
+ db1.pkg1.p1(a);
+ SELECT a;
+ END;
+BEGIN
+ db1.pkg1.p1(m_var1);
+END;
+$$
+DELIMITER ;$$
+
+SELECT db2.pkg1.var1();
+CALL db2.pkg1.p2_db1_pkg1_p1;
+
+DROP DATABASE db1;
+DROP DATABASE db2;
diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def
index 2300b5a8c16..2993df7678c 100644
--- a/mysql-test/suite/galera/disabled.def
+++ b/mysql-test/suite/galera/disabled.def
@@ -38,3 +38,4 @@ partition : MDEV-19958 Galera test failure on galera.partition
query_cache: MDEV-15805 Test failure on galera.query_cache
versioning_trx_id: MDEV-18590: galera.versioning_trx_id: Test failure: mysqltest: Result content mismatch
galera_bf_abort_at_after_statement : Unstable
+galera_bf_abort_ps_bind : MDEV-28193 Galera test failure on galera_bf_abort_ps_bind
diff --git a/mysql-test/suite/galera/include/kill_galera.inc b/mysql-test/suite/galera/include/kill_galera.inc
index 98ebf4ff35d..56118df84f9 100644
--- a/mysql-test/suite/galera/include/kill_galera.inc
+++ b/mysql-test/suite/galera/include/kill_galera.inc
@@ -2,7 +2,7 @@
if (!$kill_signal)
{
---let $kill_signal = 9
+--let $kill_signal = KILL
}
# Write file to make mysql-test-run.pl expect the crash, but don't start it
diff --git a/mysql-test/suite/galera/r/MDEV-24143.result b/mysql-test/suite/galera/r/MDEV-24143.result
new file mode 100644
index 00000000000..860d8a35834
--- /dev/null
+++ b/mysql-test/suite/galera/r/MDEV-24143.result
@@ -0,0 +1,23 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (c1 BIGINT NOT NULL PRIMARY KEY, c2 BINARY (10), c3 DATETIME);
+SELECT get_lock ('test2', 0);
+get_lock ('test2', 0)
+1
+DROP TABLE t1;
+CREATE TABLE t1 (c1 SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY);
+INSERT INTO t1 VALUES (1);
+SET SESSION wsrep_trx_fragment_size=10;
+SET SESSION autocommit=0;
+SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC;
+c1
+INSERT INTO t1 VALUES (4),(3),(1),(2);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE;
+ERROR 42S01: Table 't1' already exists
+ALTER TABLE t1 DROP COLUMN c2;
+ERROR 42000: Can't DROP COLUMN `c2`; check that it exists
+SELECT get_lock ('test', 1.5);
+get_lock ('test', 1.5)
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MDEV-27713.result b/mysql-test/suite/galera/r/MDEV-27713.result
new file mode 100644
index 00000000000..14575cb484d
--- /dev/null
+++ b/mysql-test/suite/galera/r/MDEV-27713.result
@@ -0,0 +1,46 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (
+f1 INT,
+f2 VARCHAR(255) PRIMARY KEY
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES(1, 'abc');
+connection node_1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (2,'def');
+connection node_2;
+SET GLOBAL event_scheduler=ON;
+CREATE PROCEDURE update_table()
+BEGIN
+SET AUTOCOMMIT=OFF;
+DO GET_LOCK('local_lock', 0);
+SET DEBUG_SYNC = 'innodb_row_update_for_mysql_begin SIGNAL blocked WAIT_FOR continue';
+UPDATE t1 SET f2 = 'jkl' WHERE f1 != 2;
+DO RELEASE_LOCK('local_lock');
+END|
+CREATE DEFINER=current_user
+EVENT event
+ON SCHEDULE AT CURRENT_TIMESTAMP
+ON COMPLETION PRESERVE
+ENABLE
+DO CALL update_table();
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+SET DEBUG_SYNC = 'now WAIT_FOR blocked';
+connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb";
+connection node_1;
+COMMIT;
+connection node_2b;
+SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+connection node_2a;
+SET DEBUG_SYNC = 'now SIGNAL continue';
+connection node_2;
+SET GLOBAL event_scheduler=default;
+DROP PROCEDURE update_table;
+DROP EVENT event;
+SET DEBUG_SYNC='reset';
+SET GLOBAL debug_dbug = DEFAULT;
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_ps_bind.result b/mysql-test/suite/galera/r/galera_bf_abort_ps_bind.result
new file mode 100644
index 00000000000..adc7da58eae
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_bf_abort_ps_bind.result
@@ -0,0 +1,37 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t (i int primary key auto_increment, j varchar(20) character set utf8);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+connection node_1;
+insert into t values (1, 'first');
+PS_prepare INSERT INTO t(j) VALUES (?);;
+PS_bind node1;
+PS_execute;
+PS_execute;
+select * from t;
+i j
+1 first
+3 node1
+5 node1
+PS_close;
+PS_prepare INSERT INTO t(j) VALUES (?);;
+PS_bind node1;
+begin;
+update t set j='node1' where i=1;
+connection node_2;
+update t set j='node2' where i=1;
+connection node_1a;
+connection node_1;
+PS_execute;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+PS_execute;
+commit;
+select * from t;
+i j
+1 node2
+3 node1
+5 node1
+7 node1
+drop table t;
diff --git a/mysql-test/suite/galera/r/galera_ist_restart_joiner.result b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
index 7cb6d90840e..2f78c475762 100644
--- a/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
+++ b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
@@ -18,6 +18,7 @@ SET SESSION wsrep_on=ON;
connection node_1;
UPDATE t1 SET f2 = 'd' WHERE f1 > 3;
connection node_2;
+Killing server ...
connection node_1;
UPDATE t1 SET f2 = 'e' WHERE f1 > 4;
connection node_2;
diff --git a/mysql-test/suite/galera/t/MDEV-24143.test b/mysql-test/suite/galera/t/MDEV-24143.test
new file mode 100644
index 00000000000..e58f147cb7c
--- /dev/null
+++ b/mysql-test/suite/galera/t/MDEV-24143.test
@@ -0,0 +1,20 @@
+--source include/galera_cluster.inc
+--source include/have_sequence.inc
+
+CREATE TABLE t1 (c1 BIGINT NOT NULL PRIMARY KEY, c2 BINARY (10), c3 DATETIME);
+SELECT get_lock ('test2', 0);
+DROP TABLE t1;
+CREATE TABLE t1 (c1 SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY);
+INSERT INTO t1 VALUES (1);
+SET SESSION wsrep_trx_fragment_size=10;
+SET SESSION autocommit=0;
+SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC;
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (4),(3),(1),(2);
+--error ER_TABLE_EXISTS_ERROR
+CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE;
+--error ER_CANT_DROP_FIELD_OR_KEY
+ALTER TABLE t1 DROP COLUMN c2;
+SELECT get_lock ('test', 1.5);
+DROP TABLE t1;
+
diff --git a/mysql-test/suite/galera/t/MDEV-27713.test b/mysql-test/suite/galera/t/MDEV-27713.test
new file mode 100644
index 00000000000..4bfcd7e3d50
--- /dev/null
+++ b/mysql-test/suite/galera/t/MDEV-27713.test
@@ -0,0 +1,67 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/big_test.inc
+
+CREATE TABLE t1 (
+ f1 INT,
+ f2 VARCHAR(255) PRIMARY KEY
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+INSERT INTO t1 VALUES(1, 'abc');
+
+--connection node_1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (2,'def');
+
+--connection node_2
+
+SET GLOBAL event_scheduler=ON;
+
+DELIMITER |;
+CREATE PROCEDURE update_table()
+BEGIN
+ SET AUTOCOMMIT=OFF;
+ DO GET_LOCK('local_lock', 0);
+ SET DEBUG_SYNC = 'innodb_row_update_for_mysql_begin SIGNAL blocked WAIT_FOR continue';
+ UPDATE t1 SET f2 = 'jkl' WHERE f1 != 2;
+ DO RELEASE_LOCK('local_lock');
+END|
+DELIMITER ;|
+
+CREATE DEFINER=current_user
+ EVENT event
+ ON SCHEDULE AT CURRENT_TIMESTAMP
+ ON COMPLETION PRESERVE
+ ENABLE
+ DO CALL update_table();
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+SET DEBUG_SYNC = 'now WAIT_FOR blocked';
+
+# Applier control thread
+--connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2
+SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb";
+
+--connection node_1
+COMMIT;
+
+# Applier control thread
+--connection node_2b
+SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+
+--connection node_2a
+SET DEBUG_SYNC = 'now SIGNAL continue';
+
+--connection node_2
+SET GLOBAL event_scheduler=default;
+DROP PROCEDURE update_table;
+DROP EVENT event;
+SET DEBUG_SYNC='reset';
+SET GLOBAL debug_dbug = DEFAULT;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-328C.test b/mysql-test/suite/galera/t/MW-328C.test
index 7241dfbdbca..c3370a3decd 100644
--- a/mysql-test/suite/galera/t/MW-328C.test
+++ b/mysql-test/suite/galera/t/MW-328C.test
@@ -7,6 +7,7 @@
# masks all deadlock errors
#
+--source include/no_protocol.inc
--source include/galera_cluster.inc
--source suite/galera/t/MW-328-header.inc
diff --git a/mysql-test/suite/galera/t/MW-44.test b/mysql-test/suite/galera/t/MW-44.test
index a2acfc57f6c..7b479d45844 100644
--- a/mysql-test/suite/galera/t/MW-44.test
+++ b/mysql-test/suite/galera/t/MW-44.test
@@ -19,7 +19,11 @@ SET SESSION wsrep_osu_method=RSU;
ALTER TABLE t1 ADD COLUMN f2 INTEGER;
SET SESSION wsrep_osu_method=TOI;
---let $wait_condition = SELECT COUNT(*) = 2 FROM mysql.general_log WHERE argument LIKE "CREATE%" OR argument LIKE "ALTER%"
+--let $wait_condition = SELECT COUNT(*) = 1 FROM mysql.general_log WHERE argument LIKE "CREATE%" AND command_type != 'Prepare'
+--let $wait_condition_on_error_output = SELECT * FROM mysql.general_log
+--source include/wait_condition_with_debug.inc
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM mysql.general_log WHERE argument LIKE "ALTER%" AND command_type != 'Prepare'
--let $wait_condition_on_error_output = SELECT * FROM mysql.general_log
--source include/wait_condition_with_debug.inc
diff --git a/mysql-test/suite/galera/t/galera_bf_abort_ps_bind.cnf b/mysql-test/suite/galera/t/galera_bf_abort_ps_bind.cnf
new file mode 100644
index 00000000000..62cf1854032
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_abort_ps_bind.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep-debug=1
+
+[mysqld.2]
+wsrep-debug=1
diff --git a/mysql-test/suite/galera/t/galera_bf_abort_ps_bind.test b/mysql-test/suite/galera/t/galera_bf_abort_ps_bind.test
new file mode 100644
index 00000000000..a840f612a82
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_abort_ps_bind.test
@@ -0,0 +1,58 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t (i int primary key auto_increment, j varchar(20) character set utf8);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_1
+insert into t values (1, 'first');
+
+# prepare a statement for inserting rows into table t
+--PS_prepare INSERT INTO t(j) VALUES (?);
+
+# bind parameter, to insert with column j having value 'node1'
+--PS_bind node1
+
+# insert two rows with the PS
+# this is for showing that two execute commands can follow a bind command
+--PS_execute
+--PS_execute
+select * from t;
+
+# close the prepared statement, and prepare a new PS,
+# this happens to be same as the first PS
+# also bind parameter for the PS
+--PS_close
+--PS_prepare INSERT INTO t(j) VALUES (?);
+--PS_bind node1
+
+# start a transaction and make one update
+# leaving the transaction open
+begin;
+update t set j='node1' where i=1;
+
+# replicate a transaction from node2, which BF aborts the open
+# transaction in node1
+--connection node_2
+update t set j='node2' where i=1;
+
+# wait until the BF has completed, and update from node_2 has committed
+--connection node_1a
+--let $wait_condition = SELECT COUNT(*) = 1 FROM t WHERE j='node2'
+--source include/wait_condition.inc
+
+# continue the open transaction, trying to insert third row, deadlock is now observed
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--PS_execute
+
+# try to insert one more row
+--PS_execute
+commit;
+
+select * from t;
+
+drop table t;
diff --git a/mysql-test/suite/galera/t/galera_ist_restart_joiner.test b/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
index f56d0e657bd..c535ac455b9 100644
--- a/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
+++ b/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
@@ -61,19 +61,7 @@ UPDATE t1 SET f2 = 'd' WHERE f1 > 3;
# Kill node #2 while IST is in progress
--connection node_2
-
-# Kill the connected server
---disable_reconnect
-
---perl
- my $pid_filename = $ENV{'KILL_NODE_PIDFILE'};
- my $mysqld_pid = `cat $pid_filename`;
- chomp($mysqld_pid);
- system("kill -9 $mysqld_pid");
- exit(0);
-EOF
-
---source include/wait_until_disconnected.inc
+--source include/kill_galera.inc
--connection node_1
--source include/wait_until_connected_again.inc
diff --git a/mysql-test/suite/galera_3nodes/r/galera_garbd_backup.result b/mysql-test/suite/galera_3nodes/r/galera_garbd_backup.result
new file mode 100644
index 00000000000..f176ef1dd7f
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_garbd_backup.result
@@ -0,0 +1,41 @@
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_1;
+SET GLOBAL innodb_max_dirty_pages_pct=99;
+SET GLOBAL innodb_max_dirty_pages_pct_lwm=99;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER, f2 varchar(1024)) Engine=InnoDB;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+INSERT INTO t1 (f2) SELECT REPEAT('x', 1024) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+connection node_2;
+Killing node #3 to free ports for garbd ...
+connection node_3;
+connection node_1;
+SET GLOBAL debug_dbug = "+d,sync.wsrep_donor_state";
+Starting garbd ...
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_donor_state_reached";
+SET GLOBAL innodb_max_dirty_pages_pct_lwm=0;
+SET GLOBAL innodb_max_dirty_pages_pct=0;
+SET SESSION debug_sync = "now SIGNAL signal.wsrep_donor_state";
+SET GLOBAL debug_dbug = "";
+SET debug_sync='RESET';
+connection node_2;
+Killing garbd ...
+connection node_1;
+connection node_2;
+DROP TABLE t1;
+DROP TABLE ten;
+Restarting node #3 to satisfy MTR's end-of-test checks
+connection node_3;
+connection node_1;
+SET GLOBAL innodb_max_dirty_pages_pct = 75.000000;
+SET GLOBAL innodb_max_dirty_pages_pct_lwm = 0.000000;
+connection node_1;
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+connection node_2;
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+connection node_3;
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
diff --git a/mysql-test/suite/galera_3nodes/t/galera_garbd_backup.cnf b/mysql-test/suite/galera_3nodes/t/galera_garbd_backup.cnf
new file mode 100644
index 00000000000..8b7cb948a87
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_garbd_backup.cnf
@@ -0,0 +1,13 @@
+!include ../galera_3nodes.cnf
+
+[mysqld]
+wsrep_sst_method=rsync
+
+[mysqld.1]
+wsrep_node_name=node1
+
+[mysqld.2]
+wsrep_node_name=node2
+
+[mysqld.3]
+wsrep_node_name=node3
diff --git a/mysql-test/suite/galera_3nodes/t/galera_garbd_backup.test b/mysql-test/suite/galera_3nodes/t/galera_garbd_backup.test
new file mode 100644
index 00000000000..302bf430dde
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_garbd_backup.test
@@ -0,0 +1,134 @@
+#
+# A very basic test for the galera arbitrator. We shut down node #3 and use its port allocation to start garbd.
+# As MTR does not allow multiple servers to be down at the same time, we are limited as to what we can test.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_garbd.inc
+--source include/big_test.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+
+--connection node_1
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+
+--let $galera_connection_name = node_3
+--let $galera_server_number = 3
+--source include/galera_connect.inc
+--source suite/galera/include/galera_base_port.inc
+--let $NODE_GALERAPORT_3 = $_NODE_GALERAPORT
+
+--source ../galera/include/auto_increment_offset_save.inc
+
+# Save galera ports
+--connection node_1
+--source suite/galera/include/galera_base_port.inc
+--let $NODE_GALERAPORT_1 = $_NODE_GALERAPORT
+--let $datadir= `SELECT @@datadir`
+
+--let $innodb_max_dirty_pages_pct = `SELECT @@innodb_max_dirty_pages_pct`
+--let $innodb_max_dirty_pages_pct_lwm = `SELECT @@innodb_max_dirty_pages_pct_lwm`
+
+SET GLOBAL innodb_max_dirty_pages_pct=99;
+SET GLOBAL innodb_max_dirty_pages_pct_lwm=99;
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER, f2 varchar(1024)) Engine=InnoDB;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+INSERT INTO t1 (f2) SELECT REPEAT('x', 1024) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_2
+--source suite/galera/include/galera_base_port.inc
+--let $NODE_GALERAPORT_2 = $_NODE_GALERAPORT
+
+--echo Killing node #3 to free ports for garbd ...
+--connection node_3
+--source include/shutdown_mysqld.inc
+
+--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
+
+# stop SST donor thread when node is in donor state
+SET GLOBAL debug_dbug = "+d,sync.wsrep_donor_state";
+
+--echo Starting garbd ...
+--exec $MTR_GARBD_EXE --address "gcomm://127.0.0.1:$NODE_GALERAPORT_1" --group my_wsrep_cluster --donor node1 --sst backup --options 'base_port=$NODE_GALERAPORT_3' > $MYSQL_TMP_DIR/garbd.log 2>&1 &
+
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_donor_state_reached";
+
+#
+# get hash of data directory contents before BP dirty page flushing
+#
+--exec find $datadir -type f ! -name tables_flushed ! -name backup_sst_complete -exec md5sum {} \; | md5sum >$MYSQLTEST_VARDIR/tmp/innodb_before
+
+# this should force buffer pool flushing, if not already done by donor state change transfer
+SET GLOBAL innodb_max_dirty_pages_pct_lwm=0;
+SET GLOBAL innodb_max_dirty_pages_pct=0;
+
+--disable_query_log
+--disable_result_log
+select f1 from t1;
+select * from ten;
+--enable_result_log
+--enable_query_log
+
+#
+#
+# record the hash of data directory contents after BP dirty page flushing
+#
+--exec find $datadir -type f ! -name tables_flushed ! -name backup_sst_complete -exec md5sum {} \; | md5sum >$MYSQLTEST_VARDIR/tmp/innodb_after
+
+# there should be no disk writes
+--diff_files $MYSQLTEST_VARDIR/tmp/innodb_before $MYSQLTEST_VARDIR/tmp/innodb_after
+
+SET SESSION debug_sync = "now SIGNAL signal.wsrep_donor_state";
+SET GLOBAL debug_dbug = "";
+SET debug_sync='RESET';
+
+--connection node_2
+
+#
+# garbd will die automatically, because of the backup SST script
+# but just to be sure, sending explicit kill here, as well
+#
+--echo Killing garbd ...
+# FreeBSD's /bin/pkill only supports short versions of the options:
+# -o Select only the oldest (least recently started)
+# -f Match against full argument lists
+--error 0,1
+--exec pkill -o -f garbd.*$NODE_GALERAPORT_3
+
+--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
+
+--connection node_2
+
+DROP TABLE t1;
+DROP TABLE ten;
+
+--echo Restarting node #3 to satisfy MTR's end-of-test checks
+--connection node_3
+let $restart_noprint=2;
+--source include/start_mysqld.inc
+
+--connection node_1
+--eval SET GLOBAL innodb_max_dirty_pages_pct = $innodb_max_dirty_pages_pct
+--eval SET GLOBAL innodb_max_dirty_pages_pct_lwm = $innodb_max_dirty_pages_pct_lwm
+
+--source ../galera/include/auto_increment_offset_restore.inc
+
+--connection node_1
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+
+--connection node_2
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+
+--connection node_3
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
diff --git a/mysql-test/suite/galera_sr/disabled.def b/mysql-test/suite/galera_sr/disabled.def
index 9f6ae2a51ef..e45118f6f0a 100644
--- a/mysql-test/suite/galera_sr/disabled.def
+++ b/mysql-test/suite/galera_sr/disabled.def
@@ -14,4 +14,5 @@ GCF-1018B : MDEV-18534 wsrep::transaction::adopt(): Assertion `transaction.is_st
GCF-1060 : MDEV-20848 galera_sr.GCF_1060
GCF-585 : MDEV-24698 galera_sr.GCF-585 MTR failed with SIGABRT: no such a transition REPLICATING -> APPLYING
galera-features#56 : MDEV-24896
+GCF-1060 : MDEV-26528 wrong usage of mutex LOCK_thd_kill and LOCK_thd_kill
galera_sr_shutdown_master : MDEV-23612: galera_sr.galera_sr_shutdown_master MTR failed: WSREP_SST: [ERROR] Possible timeout in receving first data from donor in gtid stage
diff --git a/mysql-test/suite/galera_sr/r/MDEV-27553.result b/mysql-test/suite/galera_sr/r/MDEV-27553.result
index f6f81bd13f1..5a6a5bd4956 100644
--- a/mysql-test/suite/galera_sr/r/MDEV-27553.result
+++ b/mysql-test/suite/galera_sr/r/MDEV-27553.result
@@ -1,23 +1,36 @@
connection node_2;
connection node_1;
-CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
connection node_1;
+connection node_2;
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+connection node_2;
SET SESSION wsrep_trx_fragment_size=1;
START TRANSACTION;
INSERT INTO t1 VALUES (1);
+SELECT COUNT(*) `Expect 1` FROM mysql.wsrep_streaming_log;
+Expect 1
+1
SET @@global.debug_dbug="+d,ha_index_init_fail";
ROLLBACK;
-connection node_2;
+connection node_1;
+SET SESSION wsrep_sync_wait = 0;
SELECT COUNT(*) `Expect 0` FROM mysql.wsrep_streaming_log;
Expect 0
0
-connection node_1;
+connection node_2;
SET @@global.debug_dbug="";
+SET SESSION wsrep_sync_wait = 0;
SELECT COUNT(*) `Expect 1` FROM mysql.wsrep_streaming_log;
Expect 1
1
-SET SESSION wsrep_on=OFF;
-DELETE FROM mysql.wsrep_streaming_log;
-SET SESSION wsrep_on=ON;
+connection node_2;
+SET GLOBAL wsrep_on=OFF;
+# restart
+SELECT COUNT(*) `Expect 0` FROM mysql.wsrep_streaming_log;
+Expect 0
+0
DROP TABLE t1;
CALL mtr.add_suppression("WSREP: Failed to init table for index scan");
+CALL mtr.add_suppression("WSREP: Failed to apply write set");
+CALL mtr.add_suppression("Failed to report last committed");
diff --git a/mysql-test/suite/galera_sr/t/MDEV-27553.test b/mysql-test/suite/galera_sr/t/MDEV-27553.test
index d17af175512..5c557db9201 100644
--- a/mysql-test/suite/galera_sr/t/MDEV-27553.test
+++ b/mysql-test/suite/galera_sr/t/MDEV-27553.test
@@ -5,29 +5,76 @@
--source include/galera_cluster.inc
--source include/have_debug.inc
+--let $node_1=node_1
+--let $node_2=node_2
+--source suite/galera/include/auto_increment_offset_save.inc
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
---connection node_1
---let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
+--connection node_2
SET SESSION wsrep_trx_fragment_size=1;
START TRANSACTION;
INSERT INTO t1 VALUES (1);
-# This will result in failure to remove fragments
-# from streaming log, in the following ROLLBACK.
+SELECT COUNT(*) `Expect 1` FROM mysql.wsrep_streaming_log;
+
+#
+# Issue ROLLBACK and make sure it fails to clean up
+# the streaming log. Failure to remove fragments
+# results in apply failure of the rollback fragment.
+# The node should disconnect from the cluster.
+#
SET @@global.debug_dbug="+d,ha_index_init_fail";
ROLLBACK;
---connection node_2
+
+#
+# Expect the cluster to shrink
+#
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+#
+# ROLLBACK should clean up the streaming log just fine in node 1
+#
SELECT COUNT(*) `Expect 0` FROM mysql.wsrep_streaming_log;
---connection node_1
+#
+# Expect the failure on ROLLBACK to leave a entry in streaming log
+#
+--connection node_2
SET @@global.debug_dbug="";
+SET SESSION wsrep_sync_wait = 0;
+# Expect node to be disconnected
+--let wait_condition = SELECT VARIABLE_VALUE = 'Disconnected' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
SELECT COUNT(*) `Expect 1` FROM mysql.wsrep_streaming_log;
-SET SESSION wsrep_on=OFF;
-DELETE FROM mysql.wsrep_streaming_log;
-SET SESSION wsrep_on=ON;
+
+#
+# Restart node 2, so that it joins the cluster back
+#
+--connection node_2
+SET GLOBAL wsrep_on=OFF;
+--source include/restart_mysqld.inc
+
+#
+# After restart, the streaming log is empty in node 2
+#
+SELECT COUNT(*) `Expect 0` FROM mysql.wsrep_streaming_log;
+
+#
+# Cleanup
+#
DROP TABLE t1;
CALL mtr.add_suppression("WSREP: Failed to init table for index scan");
+CALL mtr.add_suppression("WSREP: Failed to apply write set");
+CALL mtr.add_suppression("Failed to report last committed");
+
+--source suite/galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/rpl/r/mdev_24667.result b/mysql-test/suite/rpl/r/mdev_24667.result
new file mode 100644
index 00000000000..7c7342d63d6
--- /dev/null
+++ b/mysql-test/suite/rpl/r/mdev_24667.result
@@ -0,0 +1,30 @@
+include/rpl_init.inc [topology=1->2->3]
+call mtr.add_suppression('Unsafe statement written to the binary log using ');
+connection server_1;
+set binlog_format=statement;
+#first bug
+create table t1 (a int);
+create temporary table tmp like t1;
+load data local infile 'MYSQLTEST_VARDIR/load_data' INTO TABLE tmp;
+insert into t1 select * from tmp;
+#second bug
+create table t2 (a int);
+create temporary table tmp2 like t2;
+insert into tmp2 values(10);
+update tmp2 set a = 20 limit 1;
+Warnings:
+Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted
+insert into t2 select * from tmp2;
+connection server_2;
+connection server_3;
+#t1 should have 2 rows
+select count(*) = 2 from t1;
+count(*) = 2
+1
+#t2 should have 1 rows with a = 20
+select * from t2;
+a
+20
+connection server_1;
+drop table t1, t2, tmp, tmp2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/mdev_24667.cnf b/mysql-test/suite/rpl/t/mdev_24667.cnf
new file mode 100644
index 00000000000..58b605ad928
--- /dev/null
+++ b/mysql-test/suite/rpl/t/mdev_24667.cnf
@@ -0,0 +1,8 @@
+!include ../my.cnf
+
+[mysqld.3]
+log-slave-updates
+
+[ENV]
+SERVER_MYPORT_3= @mysqld.3.port
+SERVER_MYSOCK_3= @mysqld.3.socket
diff --git a/mysql-test/suite/rpl/t/mdev_24667.test b/mysql-test/suite/rpl/t/mdev_24667.test
new file mode 100644
index 00000000000..d8490b335db
--- /dev/null
+++ b/mysql-test/suite/rpl/t/mdev_24667.test
@@ -0,0 +1,56 @@
+#
+# MDEV-24667 LOAD DATA INFILE/inserted rows not written to binlog
+#
+# In this test we will have a replication configuration like 1->2->3
+# 1 will have statement format
+# 2 and 3 will have mixed format
+# We will make some updates on temporary table which are unsafe , So 2 must
+# Log these queries in row format, Since it is on tmp table , It wont be logged
+# So the next query which copies the data from tmp table to normal must be logged
+# into the row format. Instead of checking for the binlog We will compare the
+# results on the 3, If no binlog is lost(ie it is logged into row format), There
+# should not be any data loss.
+--let $rpl_topology=1->2->3
+--source include/rpl_init.inc
+--source include/have_binlog_format_mixed.inc
+call mtr.add_suppression('Unsafe statement written to the binary log using ');
+--connection server_1
+
+set binlog_format=statement;
+--echo #first bug
+create table t1 (a int);
+create temporary table tmp like t1;
+--write_file $MYSQLTEST_VARDIR/load_data
+1
+2
+EOF
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval load data local infile '$MYSQLTEST_VARDIR/load_data' INTO TABLE tmp;
+insert into t1 select * from tmp;
+
+--echo #second bug
+create table t2 (a int);
+#insert into t2 values(10);
+create temporary table tmp2 like t2;
+insert into tmp2 values(10);
+update tmp2 set a = 20 limit 1;
+insert into t2 select * from tmp2;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+--save_master_pos
+
+--connection server_3
+--sync_with_master
+--echo #t1 should have 2 rows
+select count(*) = 2 from t1;
+--echo #t2 should have 1 rows with a = 20
+select * from t2;
+
+
+# cleanup
+--connection server_1
+drop table t1, t2, tmp, tmp2;
+--remove_file $MYSQLTEST_VARDIR/load_data
+--source include/rpl_end.inc
diff --git a/mysys/my_rename.c b/mysys/my_rename.c
index 7b31e83be20..389994b9a09 100644
--- a/mysys/my_rename.c
+++ b/mysys/my_rename.c
@@ -46,12 +46,15 @@ static BOOL win_rename_with_retries(const char *from, const char *to)
for (int retry= RENAME_MAX_RETRIES; retry--;)
{
- DWORD ret = MoveFileEx(from, to,
+ BOOL ret= MoveFileEx(from, to,
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
- DBUG_ASSERT(fp == NULL || (ret == FALSE && GetLastError() == ERROR_SHARING_VIOLATION));
+ if (ret)
+ return ret;
- if (!ret && (GetLastError() == ERROR_SHARING_VIOLATION))
+ DWORD last_error= GetLastError();
+ if (last_error == ERROR_SHARING_VIOLATION ||
+ last_error == ERROR_ACCESS_DENIED)
{
#ifndef DBUG_OFF
/*
diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c
index 671f07993f4..4a54e0e8f4b 100644
--- a/plugin/server_audit/server_audit.c
+++ b/plugin/server_audit/server_audit.c
@@ -2352,6 +2352,9 @@ int get_db_mysql57(MYSQL_THD thd, char **name, size_t *len)
#ifdef __x86_64__
db_off= 608;
db_len_off= 616;
+#elif __aarch64__
+ db_off= 632;
+ db_len_off= 640;
#else
db_off= 0;
db_len_off= 0;
@@ -2362,6 +2365,9 @@ int get_db_mysql57(MYSQL_THD thd, char **name, size_t *len)
#ifdef __x86_64__
db_off= 536;
db_len_off= 544;
+#elif __aarch64__
+ db_off= 552;
+ db_len_off= 560;
#else
db_off= 0;
db_len_off= 0;
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index cca3d6a2051..34bd059e3c3 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -287,6 +287,7 @@ ELSE()
wsrep_sst_mysqldump
wsrep_sst_rsync
wsrep_sst_mariabackup
+ wsrep_sst_backup
)
# The following script is sourced from other SST scripts, so it should
# not be made executable.
diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh
index 74cc1efc845..b392b9c83ea 100644
--- a/scripts/mysql_install_db.sh
+++ b/scripts/mysql_install_db.sh
@@ -541,7 +541,7 @@ mysqld_install_cmd_line()
{
"$mysqld_bootstrap" $defaults $defaults_group_suffix "$mysqld_opt" --bootstrap $silent_startup\
"--basedir=$basedir" "--datadir=$ldata" --log-warnings=0 --enforce-storage-engine="" \
- "--plugin-dir=${plugindir}" --loose-disable-plugin-file-key-management \
+ "--plugin-dir=${plugindir}" \
$args --max_allowed_packet=8M \
--net_buffer_length=16K
}
diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql
index 613b8ab42d2..3b42c567fd6 100644
--- a/scripts/mysql_system_tables_fix.sql
+++ b/scripts/mysql_system_tables_fix.sql
@@ -1,5 +1,5 @@
-- Copyright (C) 2003, 2013 Oracle and/or its affiliates.
--- Copyright (C) 2010, 2018 MariaDB Corporation
+-- Copyright (C) 2010, 2022, MariaDB Corporation
--
-- 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
@@ -744,6 +744,13 @@ ALTER TABLE help_topic MODIFY url TEXT NOT NULL;
# MDEV-7383 - varbinary on mix/max of column_stats
alter table column_stats modify min_value varbinary(255) DEFAULT NULL, modify max_value varbinary(255) DEFAULT NULL;
+# MDEV-21873: 10.2 to 10.3 upgrade doesn't remove semi-sync reference from
+# mysql.plugin table.
+# As per suggested fix, check INFORMATION_SCHEMA.PLUGINS
+# and if semisync plugins aren't there, delete them from mysql.plugin.
+DELETE FROM mysql.plugin WHERE name="rpl_semi_sync_master" AND NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME="rpl_semi_sync_master");
+DELETE FROM mysql.plugin WHERE name="rpl_semi_sync_slave" AND NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME="rpl_semi_sync_slave");
+
--
-- Ensure that all tables are of type Aria and transactional
--
diff --git a/scripts/wsrep_sst_backup.sh b/scripts/wsrep_sst_backup.sh
new file mode 100644
index 00000000000..55e11ddffc0
--- /dev/null
+++ b/scripts/wsrep_sst_backup.sh
@@ -0,0 +1,112 @@
+#!/usr/bin/env bash
+
+set -ue
+
+# Copyright (C) 2017-2021 MariaDB
+# Copyright (C) 2010-2014 Codership Oy
+#
+# 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
+# MA 02110-1335 USA.
+
+# This is a reference script for rsync-based state snapshot transfer
+
+RSYNC_REAL_PID=0 # rsync process id
+STUNNEL_REAL_PID=0 # stunnel process id
+
+OS="$(uname)"
+[ "$OS" = 'Darwin' ] && export -n LD_LIBRARY_PATH
+
+# Setting the path for lsof on CentOS
+export PATH="/usr/sbin:/sbin:$PATH"
+
+. $(dirname "$0")/wsrep_sst_common
+
+MAGIC_FILE="$WSREP_SST_OPT_DATA/backup_sst_complete"
+rm -rf "$MAGIC_FILE"
+
+WSREP_LOG_DIR=${WSREP_LOG_DIR:-""}
+# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf
+if [ -z "$WSREP_LOG_DIR" ]; then
+ WSREP_LOG_DIR=$(parse_cnf mysqld innodb-log-group-home-dir '')
+fi
+
+if [ -n "$WSREP_LOG_DIR" ]; then
+ # handle both relative and absolute paths
+ WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P)
+else
+ # default to datadir
+ WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P)
+fi
+
+if [ "$WSREP_SST_OPT_ROLE" = 'donor' ]
+then
+
+ [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE"
+
+ RC=0
+
+ if [ $WSREP_SST_OPT_BYPASS -eq 0 ]; then
+
+ FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed"
+ ERROR="$WSREP_SST_OPT_DATA/sst_error"
+
+ [ -f "$FLUSHED" ] && rm -f "$FLUSHED"
+ [ -f "$ERROR" ] && rm -f "$ERROR"
+
+ echo "flush tables"
+
+ # Wait for :
+ # (a) Tables to be flushed, AND
+ # (b) Cluster state ID & wsrep_gtid_domain_id to be written to the file, OR
+ # (c) ERROR file, in case flush tables operation failed.
+
+ while [ ! -r "$FLUSHED" ] && \
+ ! grep -q -F ':' '--' "$FLUSHED" >/dev/null 2>&1
+ do
+ # Check whether ERROR file exists.
+ if [ -f "$ERROR" ]; then
+ # Flush tables operation failed.
+ rm -f "$ERROR"
+ exit 255
+ fi
+ sleep 0.2
+ done
+
+ STATE=$(cat "$FLUSHED")
+ rm -f "$FLUSHED"
+
+
+ else # BYPASS
+
+ wsrep_log_info "Bypassing state dump."
+ fi
+
+ echo 'continue' # now server can resume updating data
+
+ echo "$STATE" > "$MAGIC_FILE"
+
+ echo "done $STATE"
+
+elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]
+then
+ wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'"
+ exit 22 # EINVAL
+
+
+else
+ wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'"
+ exit 22 # EINVAL
+fi
+
+exit 0
diff --git a/sql/contributors.h b/sql/contributors.h
index e16448ee985..bc8ba4eabbb 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -42,6 +42,8 @@ struct show_table_contributors_st show_table_contributors[]= {
{"Microsoft", "https://microsoft.com/", "Platinum Sponsor of the MariaDB Foundation"},
{"MariaDB Corporation", "https://mariadb.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
{"ServiceNow", "https://servicenow.com", "Platinum Sponsor of the MariaDB Foundation"},
+ {"Intel", "https://www.intel.com", "Platinum Sponsor of the MariaDB Foundation"},
+ {"SIT", "https://sit.org", "Platinum Sponsor of the MariaDB Foundation"},
{"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"},
{"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
{"IBM", "https://www.ibm.com", "Gold Sponsor of the MariaDB Foundation"},
diff --git a/sql/handler.h b/sql/handler.h
index ff67235cd70..9eec3f13c73 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -2,7 +2,7 @@
#define HANDLER_INCLUDED
/*
Copyright (c) 2000, 2019, Oracle and/or its affiliates.
- Copyright (c) 2009, 2021, MariaDB
+ Copyright (c) 2009, 2022, MariaDB
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -5161,7 +5161,7 @@ static inline const char *ha_resolve_storage_engine_name(const handlerton *db_ty
static inline bool ha_check_storage_engine_flag(const handlerton *db_type, uint32 flag)
{
- return db_type == NULL ? FALSE : MY_TEST(db_type->flags & flag);
+ return db_type && (db_type->flags & flag);
}
static inline bool ha_storage_engine_is_enabled(const handlerton *db_type)
diff --git a/sql/item.cc b/sql/item.cc
index 5271adb7d50..e941fae9d4c 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2730,9 +2730,11 @@ Item_sp::func_name(THD *thd) const
/* Calculate length to avoid reallocation of string for sure */
size_t len= (((m_name->m_explicit_name ? m_name->m_db.length : 0) +
m_name->m_name.length)*2 + //characters*quoting
- 2 + // ` and `
+ 2 + // quotes for the function name
+ 2 + // quotes for the package name
(m_name->m_explicit_name ?
3 : 0) + // '`', '`' and '.' for the db
+ 1 + // '.' between package and function
1 + // end of string
ALIGN_SIZE(1)); // to avoid String reallocation
String qname((char *)alloc_root(thd->mem_root, len), len,
@@ -2744,7 +2746,21 @@ Item_sp::func_name(THD *thd) const
append_identifier(thd, &qname, &m_name->m_db);
qname.append('.');
}
- append_identifier(thd, &qname, &m_name->m_name);
+ if (m_sp && m_sp->m_handler == &sp_handler_package_function)
+ {
+ /*
+ In case of a package function split `pkg.func` and print
+ quoted `pkg` and `func` separately, so the entire result looks like:
+ `db`.`pkg`.`func`
+ */
+ Database_qualified_name tmp= Database_qualified_name::split(m_name->m_name);
+ DBUG_ASSERT(tmp.m_db.length);
+ append_identifier(thd, &qname, &tmp.m_db);
+ qname.append('.');
+ append_identifier(thd, &qname, &tmp.m_name);
+ }
+ else
+ append_identifier(thd, &qname, &m_name->m_name);
return qname.c_ptr_safe();
}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index ddabdaaff53..ae798913163 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4719,10 +4719,11 @@ void Item_func_in::mark_as_condition_AND_part(TABLE_LIST *embedding)
Query_arena *arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
- if (to_be_transformed_into_in_subq(thd))
+ if (!transform_into_subq_checked)
{
- transform_into_subq= true;
- thd->lex->current_select->in_funcs.push_back(this, thd->mem_root);
+ if ((transform_into_subq= to_be_transformed_into_in_subq(thd)))
+ thd->lex->current_select->in_funcs.push_back(this, thd->mem_root);
+ transform_into_subq_checked= true;
}
if (arena)
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index aa7269ab95a..4eb9416af17 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -2365,6 +2365,7 @@ protected:
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value);
bool transform_into_subq;
+ bool transform_into_subq_checked;
public:
/// An array of values, created when the bisection lookup method is used
in_vector *array;
@@ -2387,6 +2388,7 @@ public:
Item_func_opt_neg(thd, list),
Predicant_to_list_comparator(thd, arg_count - 1),
transform_into_subq(false),
+ transform_into_subq_checked(false),
array(0), have_null(0),
arg_types_compatible(FALSE), emb_on_expr_nest(0)
{ }
diff --git a/sql/log.cc b/sql/log.cc
index d0dcb5d3725..a8a50fe7b79 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates.
- Copyright (c) 2009, 2021, MariaDB Corporation.
+ Copyright (c) 2009, 2022, MariaDB Corporation.
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
@@ -5838,6 +5838,8 @@ THD::binlog_start_trans_and_stmt()
}
Gtid_log_event gtid_event(this, seqno, domain_id, true,
LOG_EVENT_SUPPRESS_USE_F, true, 0);
+ // Replicated events in writeset doesn't have checksum
+ gtid_event.checksum_alg= BINLOG_CHECKSUM_ALG_OFF;
gtid_event.server_id= server_id;
writer.write(&gtid_event);
wsrep_write_cache_buf(&tmp_io_cache, &buf, &len);
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 9a40114ad36..35d84792fcb 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1671,7 +1671,7 @@ end:
{
table->file->ha_index_or_rnd_end();
ha_commit_trans(thd, FALSE);
- ha_commit_trans(thd, TRUE);
+ trans_commit(thd);
}
if (table_opened)
{
diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc
index 2480eebf8d7..cfe29824328 100644
--- a/sql/semisync_master.cc
+++ b/sql/semisync_master.cc
@@ -1229,6 +1229,7 @@ int Repl_semi_sync_master::flush_net(THD *thd,
net_clear(net, 0);
net->pkt_nr++;
+ net->compress_pkt_nr++;
result = 0;
rpl_semi_sync_master_net_wait_num++;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 11571ed706c..2ba2e70ccce 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -3547,6 +3547,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
lex_query_tables_own_last= m_lex->query_tables_own_last;
prelocking_tables= *lex_query_tables_own_last;
*lex_query_tables_own_last= NULL;
+ m_lex->query_tables_last= m_lex->query_tables_own_last;
m_lex->mark_as_requiring_prelocking(NULL);
}
thd->rollback_item_tree_changes();
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 00b53c86688..c53fa5bf1ff 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -703,6 +703,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
wsrep_has_ignored_error(false),
wsrep_ignore_table(false),
wsrep_aborter(0),
+ wsrep_delayed_BF_abort(false),
/* wsrep-lib */
m_wsrep_next_trx_id(WSREP_UNDEFINED_TRX_ID),
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 65b039d89fb..6b8a0403d9d 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4354,13 +4354,13 @@ public:
*/
DBUG_PRINT("debug",
("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s",
- YESNO(has_thd_temporary_tables()), YESNO(in_sub_stmt),
+ YESNO(has_temporary_tables()), YESNO(in_sub_stmt),
show_system_thread(system_thread)));
if (in_sub_stmt == 0)
{
if (wsrep_binlog_format() == BINLOG_FORMAT_ROW)
set_current_stmt_binlog_format_row();
- else if (!has_thd_temporary_tables())
+ else if (!has_temporary_tables())
set_current_stmt_binlog_format_stmt();
}
DBUG_VOID_RETURN;
@@ -5062,6 +5062,10 @@ public:
/* thread who has started kill for this THD protected by LOCK_thd_data*/
my_thread_id wsrep_aborter;
+ /* true if BF abort is observed in do_command() right after reading
+ client's packet, and if the client has sent PS execute command. */
+ bool wsrep_delayed_BF_abort;
+
/*
Transaction id:
* m_wsrep_next_trx_id is assigned on the first query after
@@ -5093,7 +5097,10 @@ public:
{
return m_wsrep_next_trx_id;
}
-
+ /*
+ If node is async slave and have parallel execution, wait for prior commits.
+ */
+ bool wsrep_parallel_slave_wait_for_prior_commit();
private:
wsrep_trx_id_t m_wsrep_next_trx_id; /* cast from query_id_t */
/* wsrep-lib */
@@ -7271,6 +7278,19 @@ public:
}
void copy(MEM_ROOT *mem_root, const LEX_CSTRING &db,
const LEX_CSTRING &name);
+
+ static Database_qualified_name split(const LEX_CSTRING &txt)
+ {
+ DBUG_ASSERT(txt.str[txt.length] == '\0'); // Expect 0-terminated input
+ const char *dot= strchr(txt.str, '.');
+ if (!dot)
+ return Database_qualified_name(NULL, 0, txt.str, txt.length);
+ size_t dblen= dot - txt.str;
+ Lex_cstring db(txt.str, dblen);
+ Lex_cstring name(txt.str + dblen + 1, txt.length - dblen - 1);
+ return Database_qualified_name(db, name);
+ }
+
// Export db and name as a qualified name string: 'db.name'
size_t make_qname(char *dst, size_t dstlen) const
{
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b64d94aac57..c2f2dc05da6 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2019, Oracle and/or its affiliates.
- Copyright (c) 2009, 2021, MariaDB Corporation.
+ Copyright (c) 2009, 2022, MariaDB Corporation.
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
@@ -9164,6 +9164,43 @@ bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
}
+bool LEX::call_statement_start(THD *thd,
+ const Lex_ident_sys_st *db,
+ const Lex_ident_sys_st *pkg,
+ const Lex_ident_sys_st *proc)
+{
+ Database_qualified_name q_db_pkg(db, pkg);
+ Database_qualified_name q_pkg_proc(pkg, proc);
+ sp_name *spname;
+
+ sql_command= SQLCOM_CALL;
+
+ if (check_db_name(reinterpret_cast<LEX_STRING*>
+ (const_cast<LEX_CSTRING*>
+ (static_cast<const LEX_CSTRING*>(db)))))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
+ return NULL;
+ }
+ if (check_routine_name(pkg) ||
+ check_routine_name(proc))
+ return NULL;
+
+ // Concat `pkg` and `name` to `pkg.name`
+ LEX_CSTRING pkg_dot_proc;
+ if (q_pkg_proc.make_qname(thd->mem_root, &pkg_dot_proc) ||
+ check_ident_length(&pkg_dot_proc) ||
+ !(spname= new (thd->mem_root) sp_name(db, &pkg_dot_proc, true)))
+ return NULL;
+
+ sp_handler_package_function.add_used_routine(thd->lex, thd, spname);
+ sp_handler_package_body.add_used_routine(thd->lex, thd, &q_db_pkg);
+
+ return !(m_sql_cmd= new (thd->mem_root) Sql_cmd_call(spname,
+ &sp_handler_package_procedure));
+}
+
+
sp_package *LEX::get_sp_package() const
{
return sphead ? sphead->get_package() : NULL;
@@ -9418,6 +9455,56 @@ Item *LEX::make_item_func_call_generic(THD *thd, Lex_ident_cli_st *cdb,
}
+/*
+ Create a 3-step qualified function call.
+ Currently it's possible for package routines only, e.g.:
+ SELECT db.pkg.func();
+*/
+Item *LEX::make_item_func_call_generic(THD *thd,
+ Lex_ident_cli_st *cdb,
+ Lex_ident_cli_st *cpkg,
+ Lex_ident_cli_st *cfunc,
+ List<Item> *args)
+{
+ static Lex_cstring dot(".", 1);
+ Lex_ident_sys db(thd, cdb), pkg(thd, cpkg), func(thd, cfunc);
+ Database_qualified_name q_db_pkg(db, pkg);
+ Database_qualified_name q_pkg_func(pkg, func);
+ sp_name *qname;
+
+ if (db.is_null() || pkg.is_null() || func.is_null())
+ return NULL; // EOM
+
+ if (check_db_name((LEX_STRING*) static_cast<LEX_CSTRING*>(&db)))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
+ return NULL;
+ }
+ if (check_routine_name(&pkg) ||
+ check_routine_name(&func))
+ return NULL;
+
+ // Concat `pkg` and `name` to `pkg.name`
+ LEX_CSTRING pkg_dot_func;
+ if (q_pkg_func.make_qname(thd->mem_root, &pkg_dot_func) ||
+ check_ident_length(&pkg_dot_func) ||
+ !(qname= new (thd->mem_root) sp_name(&db, &pkg_dot_func, true)))
+ return NULL;
+
+ sp_handler_package_function.add_used_routine(thd->lex, thd, qname);
+ sp_handler_package_body.add_used_routine(thd->lex, thd, &q_db_pkg);
+
+ thd->lex->safe_to_cache_query= 0;
+
+ if (args && args->elements > 0)
+ return new (thd->mem_root) Item_func_sp(thd, thd->lex->current_context(),
+ qname, &sp_handler_package_function,
+ *args);
+ return new (thd->mem_root) Item_func_sp(thd, thd->lex->current_context(),
+ qname, &sp_handler_package_function);
+}
+
+
Item *LEX::make_item_func_call_native_or_parse_error(THD *thd,
Lex_ident_cli_st &name,
List<Item> *args)
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 3ef94c5bddb..afc93e5a646 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2019, Oracle and/or its affiliates.
- Copyright (c) 2010, 2021, MariaDB Corporation
+ Copyright (c) 2010, 2022, MariaDB Corporation.
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
@@ -3850,6 +3850,10 @@ public:
bool call_statement_start(THD *thd, const Lex_ident_sys_st *name);
bool call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
const Lex_ident_sys_st *name2);
+ bool call_statement_start(THD *thd,
+ const Lex_ident_sys_st *db,
+ const Lex_ident_sys_st *pkg,
+ const Lex_ident_sys_st *proc);
sp_variable *find_variable(const LEX_CSTRING *name,
sp_pcontext **ctx,
const Sp_rcontext_handler **rh) const;
@@ -4093,6 +4097,11 @@ public:
Item *make_item_func_substr(THD *thd, Item *a, Item *b);
Item *make_item_func_call_generic(THD *thd, Lex_ident_cli_st *db,
Lex_ident_cli_st *name, List<Item> *args);
+ Item *make_item_func_call_generic(THD *thd,
+ Lex_ident_cli_st *db,
+ Lex_ident_cli_st *pkg,
+ Lex_ident_cli_st *name,
+ List<Item> *args);
Item *make_item_func_call_native_or_parse_error(THD *thd,
Lex_ident_cli_st &name,
List<Item> *args);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ac8a4b5b142..55968fe7ddc 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1163,8 +1163,7 @@ static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables)
static bool wsrep_command_no_result(char command)
{
- return (command == COM_STMT_PREPARE ||
- command == COM_STMT_FETCH ||
+ return (command == COM_STMT_FETCH ||
command == COM_STMT_SEND_LONG_DATA ||
command == COM_STMT_CLOSE);
}
@@ -1310,7 +1309,13 @@ bool do_command(THD *thd)
DBUG_ASSERT(!thd->mdl_context.has_locks());
DBUG_ASSERT(!thd->get_stmt_da()->is_set());
/* We let COM_QUIT and COM_STMT_CLOSE to execute even if wsrep aborted. */
- if (command != COM_STMT_CLOSE &&
+ if (command == COM_STMT_EXECUTE)
+ {
+ WSREP_DEBUG("PS BF aborted at do_command");
+ thd->wsrep_delayed_BF_abort= true;
+ }
+ if (command != COM_STMT_CLOSE &&
+ command != COM_STMT_EXECUTE &&
command != COM_QUIT)
{
my_error(ER_LOCK_DEADLOCK, MYF(0));
@@ -1383,6 +1388,17 @@ out:
if (unlikely(wsrep_service_started))
wsrep_after_command_after_result(thd);
}
+
+ if (thd->wsrep_delayed_BF_abort)
+ {
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ WSREP_DEBUG("Deadlock error for PS query: %s", thd->query());
+ thd->reset_killed();
+ thd->mysys_var->abort = 0;
+ thd->wsrep_retry_counter = 0;
+
+ thd->wsrep_delayed_BF_abort= false;
+ }
#endif /* WITH_WSREP */
DBUG_RETURN(return_value);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index a88ee423203..b5472d2b5c1 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2342,6 +2342,10 @@ static bool check_prepared_statement(Prepared_statement *stmt)
goto error;
}
+#ifdef WITH_WSREP
+ if (wsrep_sync_wait(thd, sql_command))
+ goto error;
+#endif
switch (sql_command) {
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
@@ -4487,7 +4491,13 @@ Prepared_statement::execute_loop(String *expanded_query,
if (set_parameters(expanded_query, packet, packet_end))
return TRUE;
-
+#ifdef WITH_WSREP
+ if (thd->wsrep_delayed_BF_abort)
+ {
+ WSREP_DEBUG("delayed BF abort, quitting execute_loop, stmt: %d", id);
+ return TRUE;
+ }
+#endif /* WITH_WSREP */
reexecute:
// Make sure that reprepare() did not create any new Items.
DBUG_ASSERT(thd->free_list == NULL);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index ff6ec637025..5bf54fb1791 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2021, MariaDB
+ Copyright (c) 2009, 2022, 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
@@ -3296,6 +3296,16 @@ static my_bool processlist_callback(THD *tmp, processlist_callback_arg *arg)
arg->table->field[11]->store((double) tmp->progress.counter /
(double) max_counter*100.0);
}
+ else
+ {
+ /*
+ This is a DECIMAL column without DEFAULT.
+ restore_record() fills its Field::ptr to zero bytes,
+ according to pack_length(). But an array of zero bytes
+ is not a valid decimal. Set it explicitly to 0.
+ */
+ arg->table->field[11]->store((longlong) 0, true);
+ }
mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 13203ee28ad..16fb9870e07 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -9957,7 +9957,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
{
bool engine_changed, error;
bool no_ha_table= true; /* We have not created table in storage engine yet */
- TABLE *table, *new_table;
+ TABLE *table, *new_table= nullptr;
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool partition_changed= false;
bool fast_alter_partition= false;
@@ -9980,7 +9980,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
bool varchar= create_info->varchar, table_creation_was_logged= 0;
bool binlog_as_create_select= 0, log_if_exists= 0;
uint tables_opened;
- handlerton *new_db_type, *old_db_type;
+ handlerton *new_db_type= create_info->db_type, *old_db_type;
ha_rows copied=0, deleted=0;
LEX_CUSTRING frm= {0,0};
char index_file[FN_REFLEN], data_file[FN_REFLEN];
@@ -10311,22 +10311,24 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT;
}
+ old_db_type= table->s->db_type();
+ new_db_type= create_info->db_type;
+
DBUG_PRINT("info", ("old type: %s new type: %s",
- ha_resolve_storage_engine_name(table->s->db_type()),
- ha_resolve_storage_engine_name(create_info->db_type)));
- if (ha_check_storage_engine_flag(table->s->db_type(), HTON_ALTER_NOT_SUPPORTED))
+ ha_resolve_storage_engine_name(old_db_type),
+ ha_resolve_storage_engine_name(new_db_type)));
+ if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED))
{
DBUG_PRINT("info", ("doesn't support alter"));
- my_error(ER_ILLEGAL_HA, MYF(0), hton_name(table->s->db_type())->str,
+ my_error(ER_ILLEGAL_HA, MYF(0), hton_name(old_db_type)->str,
alter_ctx.db.str, alter_ctx.table_name.str);
DBUG_RETURN(true);
}
- if (ha_check_storage_engine_flag(create_info->db_type,
- HTON_ALTER_NOT_SUPPORTED))
+ if (ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
{
DBUG_PRINT("info", ("doesn't support alter"));
- my_error(ER_ILLEGAL_HA, MYF(0), hton_name(create_info->db_type)->str,
+ my_error(ER_ILLEGAL_HA, MYF(0), hton_name(new_db_type)->str,
alter_ctx.new_db.str, alter_ctx.new_name.str);
DBUG_RETURN(true);
}
@@ -10477,6 +10479,17 @@ do_continue:;
DBUG_RETURN(true);
}
}
+ /*
+ If the old table had partitions and we are doing ALTER TABLE ...
+ engine= <new_engine>, the new table must preserve the original
+ partitioning. This means that the new engine is still the
+ partitioning engine, not the engine specified in the parser.
+ This is discovered in prep_alter_part_table, which in such case
+ updates create_info->db_type.
+ It's therefore important that the assignment below is done
+ after prep_alter_part_table.
+ */
+ new_db_type= create_info->db_type;
#endif
if (mysql_prepare_alter_table(thd, table, create_info, alter_info,
@@ -10557,7 +10570,7 @@ do_continue:;
Alter_info::ALTER_TABLE_ALGORITHM_INPLACE)
|| is_inplace_alter_impossible(table, create_info, alter_info)
|| IF_PARTITIONING((partition_changed &&
- !(table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)), 0))
+ !(old_db_type->partition_flags() & HA_USE_AUTO_PARTITION)), 0))
{
if (alter_info->algorithm(thd) ==
Alter_info::ALTER_TABLE_ALGORITHM_INPLACE)
@@ -10575,25 +10588,11 @@ do_continue:;
request table rebuild. Set ALTER_RECREATE flag to force table
rebuild.
*/
- if (create_info->db_type == table->s->db_type() &&
+ if (new_db_type == old_db_type &&
create_info->used_fields & HA_CREATE_USED_ENGINE)
alter_info->flags|= ALTER_RECREATE;
/*
- If the old table had partitions and we are doing ALTER TABLE ...
- engine= <new_engine>, the new table must preserve the original
- partitioning. This means that the new engine is still the
- partitioning engine, not the engine specified in the parser.
- This is discovered in prep_alter_part_table, which in such case
- updates create_info->db_type.
- It's therefore important that the assignment below is done
- after prep_alter_part_table.
- */
- new_db_type= create_info->db_type;
- old_db_type= table->s->db_type();
- new_table= NULL;
-
- /*
Handling of symlinked tables:
If no rename:
Create new data file and index file on the same disk as the
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 9b9b07d55cd..a29f6303607 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, 2020, MariaDB
+/* Copyright (c) 2017, 2022, 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
@@ -931,13 +931,11 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
{
if (!transform_into_subq)
return this;
-
+
Json_writer_object trace_wrapper(thd);
Json_writer_object trace_conv(thd, "in_to_subquery_conversion");
trace_conv.add("item", this);
- transform_into_subq= false;
-
List<List_item> values;
LEX *lex= thd->lex;
@@ -1111,15 +1109,38 @@ uint32 Item_func_in::max_length_of_left_expr()
bool Item_func_in::to_be_transformed_into_in_subq(THD *thd)
{
+ bool is_row_list= args[1]->type() == Item::ROW_ITEM;
uint values_count= arg_count-1;
- if (args[1]->type() == Item::ROW_ITEM)
+ if (is_row_list)
values_count*= ((Item_row *)(args[1]))->cols();
if (thd->variables.in_subquery_conversion_threshold == 0 ||
thd->variables.in_subquery_conversion_threshold > values_count)
return false;
+ if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE))
+ return true;
+
+ /* Occurence of '?' in IN list is checked only for PREPARE <stmt> commands */
+ for (uint i=1; i < arg_count; i++)
+ {
+ if (!is_row_list)
+ {
+ if (args[i]->type() == Item::PARAM_ITEM)
+ return false;
+ }
+ else
+ {
+ Item_row *row_list= (Item_row *)(args[i]);
+ for (uint j=0; j < row_list->cols(); j++)
+ {
+ if (row_list->element_index(j)->type() == Item::PARAM_ITEM)
+ return false;
+ }
+ }
+ }
+
return true;
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index e30da347f8b..a1d4ae4a12f 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -2289,6 +2289,11 @@ multi_update::initialize_tables(JOIN *join)
if (unlikely((thd->variables.option_bits & OPTION_SAFE_UPDATES) &&
error_if_full_join(join)))
DBUG_RETURN(1);
+ if (join->implicit_grouping)
+ {
+ my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
+ DBUG_RETURN(1);
+ }
main_table=join->join_tab->table;
table_to_update= 0;
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 8571d893a8e..1578915aa3d 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -96,7 +96,8 @@ static void make_unique_view_field_name(THD *thd, Item *target,
itc.rewind();
}
- target->orig_name= target->name.str;
+ if (!target->orig_name)
+ target->orig_name= target->name.str;
target->set_name(thd, buff, name_len, system_charset_info);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a5493f94ef6..f775e1aaf5a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2021, MariaDB
+ Copyright (c) 2010, 2022, 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
@@ -2940,9 +2940,29 @@ sp_suid:
;
call:
- CALL_SYM sp_name
+ CALL_SYM ident
{
- if (unlikely(Lex->call_statement_start(thd, $2)))
+ if (unlikely(Lex->call_statement_start(thd, &$2)))
+ MYSQL_YYABORT;
+ }
+ opt_sp_cparam_list
+ {
+ if (Lex->check_cte_dependencies_and_resolve_references())
+ MYSQL_YYABORT;
+ }
+ | CALL_SYM ident '.' ident
+ {
+ if (unlikely(Lex->call_statement_start(thd, &$2, &$4)))
+ MYSQL_YYABORT;
+ }
+ opt_sp_cparam_list
+ {
+ if (Lex->check_cte_dependencies_and_resolve_references())
+ MYSQL_YYABORT;
+ }
+ | CALL_SYM ident '.' ident '.' ident
+ {
+ if (unlikely(Lex->call_statement_start(thd, &$2, &$4, &$6)))
MYSQL_YYABORT;
}
opt_sp_cparam_list
@@ -10699,6 +10719,11 @@ function_call_generic:
if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, $5))))
MYSQL_YYABORT;
}
+ | ident_cli '.' ident_cli '.' ident_cli '(' opt_expr_list ')'
+ {
+ if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, &$5, $7))))
+ MYSQL_YYABORT;
+ }
;
fulltext_options:
@@ -18241,6 +18266,10 @@ sp_statement:
MYSQL_YYABORT;
}
opt_sp_cparam_list
+ {
+ if (Lex->check_cte_dependencies_and_resolve_references())
+ MYSQL_YYABORT;
+ }
| ident_cli_directly_assignable '.' ident
{
Lex_ident_sys tmp(thd, &$1);
@@ -18249,6 +18278,21 @@ sp_statement:
MYSQL_YYABORT;
}
opt_sp_cparam_list
+ {
+ if (Lex->check_cte_dependencies_and_resolve_references())
+ MYSQL_YYABORT;
+ }
+ | ident_cli_directly_assignable '.' ident '.' ident
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->call_statement_start(thd, &tmp, &$3, &$5)))
+ MYSQL_YYABORT;
+ }
+ opt_sp_cparam_list
+ {
+ if (Lex->check_cte_dependencies_and_resolve_references())
+ MYSQL_YYABORT;
+ }
;
sp_if_then_statements:
diff --git a/sql/table.cc b/sql/table.cc
index 561b7fb9ff4..a9e75b066f5 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2008, 2021, MariaDB
+ Copyright (c) 2008, 2022, 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
@@ -1741,6 +1741,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
Field_data_type_info_array field_data_type_info_array;
MEM_ROOT *old_root= thd->mem_root;
Virtual_column_info **table_check_constraints;
+ bool *interval_unescaped= NULL;
extra2_fields extra2;
DBUG_ENTER("TABLE_SHARE::init_from_binary_frm_image");
@@ -2181,6 +2182,13 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
goto err;
+ if (interval_count)
+ {
+ if (!(interval_unescaped= (bool*) my_alloca(interval_count * sizeof(bool))))
+ goto err;
+ bzero(interval_unescaped, interval_count * sizeof(bool));
+ }
+
field_ptr= share->field;
table_check_constraints= share->check_constraints;
read_length=(uint) (share->fields * field_pack_length +
@@ -2532,11 +2540,17 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (share->mysql_version < 100200)
attr.pack_flag&= ~FIELDFLAG_LONG_DECIMAL;
- if (interval_nr && attr.charset->mbminlen > 1)
+ if (interval_nr && attr.charset->mbminlen > 1 &&
+ !interval_unescaped[interval_nr - 1])
{
- /* Unescape UCS2 intervals from HEX notation */
+ /*
+ Unescape UCS2/UTF16/UTF32 intervals from HEX notation.
+ Note, ENUM/SET columns with equal value list share a single
+ copy of TYPELIB. Unescape every TYPELIB only once.
+ */
TYPELIB *interval= share->intervals + interval_nr - 1;
unhex_type2(interval);
+ interval_unescaped[interval_nr - 1]= true;
}
#ifndef TO_BE_DELETED_ON_PRODUCTION
@@ -3256,6 +3270,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->error= OPEN_FRM_OK;
thd->status_var.opened_shares++;
thd->mem_root= old_root;
+ my_afree(interval_unescaped);
DBUG_RETURN(0);
err:
@@ -3283,6 +3298,7 @@ err:
open_table_error(share, OPEN_FRM_CORRUPTED, share->open_errno);
thd->mem_root= old_root;
+ my_afree(interval_unescaped);
DBUG_RETURN(HA_ERR_NOT_A_TABLE);
}
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 51c4eeb4a4c..904fda10599 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -953,7 +953,16 @@ static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
while ((field=it++) != last_field)
{
- if (field->interval_id && field->interval->count == interval->count)
+ /*
+ ENUM/SET columns with equal value lists share a single
+ copy of the underlying TYPELIB.
+ Fields with different mbminlen can't reuse TYPELIBs, because:
+ - mbminlen==1 are written to FRM as is
+ - mbminlen>1 are written to FRM in hex-encoded format
+ */
+ if (field->interval_id &&
+ field->interval->count == interval->count &&
+ field->charset->mbminlen == last_field->charset->mbminlen)
{
const char **a,**b;
for (a=field->interval->type_names, b=interval->type_names ;
diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc
index dc4b1d22818..b7107178717 100644
--- a/sql/wsrep_client_service.cc
+++ b/sql/wsrep_client_service.cc
@@ -342,6 +342,7 @@ int Wsrep_client_service::bf_rollback()
m_thd->global_read_lock.unlock_global_read_lock(m_thd);
}
m_thd->release_transactional_locks();
+ mysql_ull_cleanup(m_thd);
m_thd->mdl_context.release_explicit_locks();
DBUG_RETURN(ret);
diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc
index 1f6537a1351..db6ba43edec 100644
--- a/sql/wsrep_high_priority_service.cc
+++ b/sql/wsrep_high_priority_service.cc
@@ -380,6 +380,7 @@ int Wsrep_high_priority_service::rollback(const wsrep::ws_handle& ws_handle,
}
int ret= (trans_rollback_stmt(m_thd) || trans_rollback(m_thd));
m_thd->release_transactional_locks();
+ mysql_ull_cleanup(m_thd);
m_thd->mdl_context.release_explicit_locks();
free_root(m_thd->mem_root, MYF(MY_KEEP_PREALLOC));
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 7b546f7cab2..4c74d22c325 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -1276,6 +1276,73 @@ wsrep_sync_wait_upto (THD* thd,
return ret;
}
+bool wsrep_is_show_query(enum enum_sql_command command)
+{
+ DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
+ return (sql_command_flags[command] & CF_STATUS_COMMAND) != 0;
+}
+
+static bool wsrep_is_diagnostic_query(enum enum_sql_command command)
+{
+ assert(command >= 0 && command <= SQLCOM_END);
+ return (sql_command_flags[command] & CF_DIAGNOSTIC_STMT) != 0;
+}
+
+static enum enum_wsrep_sync_wait
+wsrep_sync_wait_mask_for_command(enum enum_sql_command command)
+{
+ switch (command)
+ {
+ case SQLCOM_SELECT:
+ case SQLCOM_CHECKSUM:
+ return WSREP_SYNC_WAIT_BEFORE_READ;
+ case SQLCOM_DELETE:
+ case SQLCOM_DELETE_MULTI:
+ case SQLCOM_UPDATE:
+ case SQLCOM_UPDATE_MULTI:
+ return WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE;
+ case SQLCOM_REPLACE:
+ case SQLCOM_INSERT:
+ case SQLCOM_REPLACE_SELECT:
+ case SQLCOM_INSERT_SELECT:
+ return WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE;
+ default:
+ if (wsrep_is_diagnostic_query(command))
+ {
+ return WSREP_SYNC_WAIT_NONE;
+ }
+ if (wsrep_is_show_query(command))
+ {
+ switch (command)
+ {
+ case SQLCOM_SHOW_PROFILE:
+ case SQLCOM_SHOW_PROFILES:
+ case SQLCOM_SHOW_SLAVE_HOSTS:
+ case SQLCOM_SHOW_RELAYLOG_EVENTS:
+ case SQLCOM_SHOW_SLAVE_STAT:
+ case SQLCOM_SHOW_BINLOG_STAT:
+ case SQLCOM_SHOW_ENGINE_STATUS:
+ case SQLCOM_SHOW_ENGINE_MUTEX:
+ case SQLCOM_SHOW_ENGINE_LOGS:
+ case SQLCOM_SHOW_PROCESSLIST:
+ case SQLCOM_SHOW_PRIVILEGES:
+ return WSREP_SYNC_WAIT_NONE;
+ default:
+ return WSREP_SYNC_WAIT_BEFORE_SHOW;
+ }
+ }
+ }
+ return WSREP_SYNC_WAIT_NONE;
+}
+
+bool wsrep_sync_wait(THD* thd, enum enum_sql_command command)
+{
+ bool res = false;
+ if (WSREP_CLIENT(thd) && thd->variables.wsrep_sync_wait)
+ res = wsrep_sync_wait(thd, wsrep_sync_wait_mask_for_command(command));
+ return res;
+}
+
void wsrep_keys_free(wsrep_key_arr_t* key_arr)
{
for (size_t i= 0; i < key_arr->keys_len; ++i)
@@ -2421,6 +2488,12 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
if (!wsrep_thd_is_local(thd))
return 0;
+ if (thd->wsrep_parallel_slave_wait_for_prior_commit())
+ {
+ WSREP_WARN("TOI: wait_for_prior_commit() returned error.");
+ return -1;
+ }
+
int ret= 0;
mysql_mutex_lock(&thd->LOCK_thd_data);
@@ -2949,11 +3022,6 @@ extern bool wsrep_thd_ignore_table(THD *thd)
return thd->wsrep_ignore_table;
}
-bool wsrep_is_show_query(enum enum_sql_command command)
-{
- DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
- return (sql_command_flags[command] & CF_STATUS_COMMAND) != 0;
-}
bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
TABLE_LIST* src_table,
HA_CREATE_INFO *create_info)
@@ -3224,6 +3292,15 @@ enum wsrep::streaming_context::fragment_unit wsrep_fragment_unit(ulong unit)
}
}
+bool THD::wsrep_parallel_slave_wait_for_prior_commit()
+{
+ if (rgi_slave && rgi_slave->is_parallel_exec && wait_for_prior_commit())
+ {
+ return 1;
+ }
+ return 0;
+}
+
/***** callbacks for wsrep service ************/
my_bool get_wsrep_recovery()
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index 79ec6463ce3..c1f6c9fda7d 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -212,6 +212,7 @@ extern bool wsrep_start_replication(const char *wsrep_cluster_address);
extern void wsrep_shutdown_replication();
extern bool wsrep_must_sync_wait (THD* thd, uint mask= WSREP_SYNC_WAIT_BEFORE_READ);
extern bool wsrep_sync_wait (THD* thd, uint mask= WSREP_SYNC_WAIT_BEFORE_READ);
+extern bool wsrep_sync_wait (THD* thd, enum enum_sql_command command);
extern enum wsrep::provider::status
wsrep_sync_wait_upto (THD* thd, wsrep_gtid_t* upto, int timeout);
extern int wsrep_check_opts();
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 2d6d8bc4165..e08ece56877 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -1,4 +1,4 @@
-/* Copyright 2008-2020 Codership Oy <http://www.codership.com>
+/* Copyright 2008-2022 Codership Oy <http://www.codership.com>
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
@@ -33,6 +33,7 @@
#include <cstdio>
#include <cstdlib>
+#include "debug_sync.h"
#include <my_service_manager.h>
@@ -1508,6 +1509,33 @@ static int run_sql_command(THD *thd, const char *query)
return 0;
}
+static void sst_disallow_writes (THD* thd, bool yes)
+{
+ char query_str[64]= { 0, };
+ ssize_t const query_max= sizeof(query_str) - 1;
+ CHARSET_INFO *current_charset;
+
+ current_charset= thd->variables.character_set_client;
+
+ if (!is_supported_parser_charset(current_charset))
+ {
+ /* Do not use non-supported parser character sets */
+ WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname);
+ thd->variables.character_set_client= &my_charset_latin1;
+ WSREP_WARN("For SST temporally setting character set to : %s",
+ my_charset_latin1.csname);
+ }
+
+ snprintf (query_str, query_max, "SET GLOBAL innodb_disallow_writes=%d",
+ yes ? 1 : 0);
+
+ if (run_sql_command(thd, query_str))
+ {
+ WSREP_ERROR("Failed to disallow InnoDB writes");
+ }
+ thd->variables.character_set_client= current_charset;
+}
+
static int sst_flush_tables(THD* thd)
{
@@ -1569,6 +1597,11 @@ static int sst_flush_tables(THD* thd)
else
{
WSREP_INFO("Tables flushed.");
+
+ /* disable further disk IO */
+ sst_disallow_writes(thd, true);
+ WSREP_INFO("Disabled further disk IO.");
+
/*
Tables have been flushed. Create a file with cluster state ID and
wsrep_gtid_domain_id.
@@ -1578,6 +1611,9 @@ static int sst_flush_tables(THD* thd)
(long long)wsrep_locked_seqno, wsrep_gtid_server.domain_id);
err= sst_create_file(flush_success, content);
+ if (err)
+ WSREP_INFO("Creating file for flush_success failed %d",err);
+
const char base_name[]= "tables_flushed";
ssize_t const full_len= strlen(mysql_real_data_home) + strlen(base_name)+2;
char *real_name= (char*) malloc(full_len);
@@ -1617,34 +1653,6 @@ static int sst_flush_tables(THD* thd)
return err;
}
-
-static void sst_disallow_writes (THD* thd, bool yes)
-{
- char query_str[64]= { 0, };
- ssize_t const query_max= sizeof(query_str) - 1;
- CHARSET_INFO *current_charset;
-
- current_charset= thd->variables.character_set_client;
-
- if (!is_supported_parser_charset(current_charset))
- {
- /* Do not use non-supported parser character sets */
- WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname);
- thd->variables.character_set_client= &my_charset_latin1;
- WSREP_WARN("For SST temporally setting character set to : %s",
- my_charset_latin1.csname);
- }
-
- snprintf (query_str, query_max, "SET GLOBAL innodb_disallow_writes=%d",
- yes ? 1 : 0);
-
- if (run_sql_command(thd, query_str))
- {
- WSREP_ERROR("Failed to disallow InnoDB writes");
- }
- thd->variables.character_set_client= current_charset;
-}
-
static void* sst_donor_thread (void* a)
{
sst_thread_arg* arg= (sst_thread_arg*)a;
@@ -1692,8 +1700,7 @@ wait_signal:
err= sst_flush_tables (thd.ptr);
if (!err)
{
- sst_disallow_writes (thd.ptr, true);
- /*
+ /*
Lets also keep statements that modify binary logs (like RESET LOGS,
RESET MASTER) from proceeding until the files have been transferred
to the joiner node.
@@ -1704,6 +1711,18 @@ wait_signal:
}
locked= true;
+
+ WSREP_INFO("Donor state reached");
+
+ DBUG_EXECUTE_IF("sync.wsrep_donor_state",
+ {
+ const char act[]=
+ "now "
+ "SIGNAL sync.wsrep_donor_state_reached "
+ "WAIT_FOR signal.wsrep_donor_state";
+ assert(!debug_sync_set_action(thd.ptr,
+ STRING_WITH_LEN(act)));
+ };);
goto wait_signal;
}
}
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index f55f663a11d..8330ba36520 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -768,9 +768,6 @@ buf_page_is_corrupted(
size_t checksum_field1 = 0;
size_t checksum_field2 = 0;
- uint32_t crc32 = 0;
- bool crc32_inited = false;
- bool crc32_chksum = false;
const ulint zip_size = fil_space_t::zip_size(fsp_flags);
const uint16_t page_type = fil_page_get_type(read_buf);
@@ -869,9 +866,14 @@ buf_page_is_corrupted(
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
return !buf_page_is_checksum_valid_none(
read_buf, checksum_field1, checksum_field2);
+ case SRV_CHECKSUM_ALGORITHM_NONE:
+ /* should have returned false earlier */
+ break;
case SRV_CHECKSUM_ALGORITHM_FULL_CRC32:
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_INNODB:
+ const uint32_t crc32 = buf_calc_page_crc32(read_buf);
+
if (buf_page_is_checksum_valid_none(read_buf,
checksum_field1, checksum_field2)) {
#ifdef UNIV_INNOCHECKSUM
@@ -887,16 +889,13 @@ buf_page_is_corrupted(
" crc32 = " UINT32PF "; recorded = " ULINTPF ";\n",
cur_page_num,
buf_calc_page_new_checksum(read_buf),
- buf_calc_page_crc32(read_buf),
+ crc32,
checksum_field1);
}
#endif /* UNIV_INNOCHECKSUM */
return false;
}
- crc32_chksum = curr_algo == SRV_CHECKSUM_ALGORITHM_CRC32
- || curr_algo == SRV_CHECKSUM_ALGORITHM_FULL_CRC32;
-
/* Very old versions of InnoDB only stored 8 byte lsn to the
start and the end of the page. */
@@ -907,82 +906,34 @@ buf_page_is_corrupted(
!= mach_read_from_4(read_buf + FIL_PAGE_LSN)
&& checksum_field2 != BUF_NO_CHECKSUM_MAGIC) {
- if (crc32_chksum) {
- crc32 = buf_calc_page_crc32(read_buf);
- crc32_inited = true;
-
- DBUG_EXECUTE_IF(
- "page_intermittent_checksum_mismatch", {
- static int page_counter;
- if (page_counter++ == 2) {
- crc32++;
- }
- });
-
- if (checksum_field2 != crc32
- && checksum_field2
- != buf_calc_page_old_checksum(read_buf)) {
- return true;
- }
- } else {
- ut_ad(curr_algo
- == SRV_CHECKSUM_ALGORITHM_INNODB);
-
- if (checksum_field2
- != buf_calc_page_old_checksum(read_buf)) {
- crc32 = buf_calc_page_crc32(read_buf);
- crc32_inited = true;
-
- if (checksum_field2 != crc32) {
- return true;
- }
- }
+ DBUG_EXECUTE_IF(
+ "page_intermittent_checksum_mismatch", {
+ static int page_counter;
+ if (page_counter++ == 2) return true;
+ });
+
+ if ((checksum_field1 != crc32
+ || checksum_field2 != crc32)
+ && checksum_field2
+ != buf_calc_page_old_checksum(read_buf)) {
+ return true;
}
}
- if (checksum_field1 == 0
- || checksum_field1 == BUF_NO_CHECKSUM_MAGIC) {
- } else if (crc32_chksum) {
-
- if (!crc32_inited) {
- crc32 = buf_calc_page_crc32(read_buf);
- crc32_inited = true;
- }
-
- if (checksum_field1 != crc32
+ switch (checksum_field1) {
+ case 0:
+ case BUF_NO_CHECKSUM_MAGIC:
+ break;
+ default:
+ if ((checksum_field1 != crc32
+ || checksum_field2 != crc32)
&& checksum_field1
!= buf_calc_page_new_checksum(read_buf)) {
return true;
}
- } else {
- ut_ad(curr_algo == SRV_CHECKSUM_ALGORITHM_INNODB);
-
- if (checksum_field1
- != buf_calc_page_new_checksum(read_buf)) {
-
- if (!crc32_inited) {
- crc32 = buf_calc_page_crc32(read_buf);
- crc32_inited = true;
- }
-
- if (checksum_field1 != crc32) {
- return true;
- }
- }
- }
-
- if (crc32_inited
- && ((checksum_field1 == crc32
- && checksum_field2 != crc32)
- || (checksum_field1 != crc32
- && checksum_field2 == crc32))) {
- return true;
}
break;
- case SRV_CHECKSUM_ALGORITHM_NONE:
- /* should have returned false earlier */
- break;
}
return false;
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 64b4d6e7ea3..c19487df63d 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -1967,10 +1967,11 @@ fil_make_filepath(
if (path != NULL) {
memcpy(full_name, path, path_len);
len = path_len;
- full_name[len] = '\0';
- os_normalize_path(full_name);
}
+ full_name[len] = '\0';
+ os_normalize_path(full_name);
+
if (trim_name) {
/* Find the offset of the last DIR separator and set it to
null in order to strip off the old basename from this path. */
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 1f719e1962c..d17392eba8f 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -2260,9 +2260,7 @@ fts_trx_table_create(
fts_trx_table_t* ftt;
ftt = static_cast<fts_trx_table_t*>(
- mem_heap_alloc(fts_trx->heap, sizeof(*ftt)));
-
- memset(ftt, 0x0, sizeof(*ftt));
+ mem_heap_zalloc(fts_trx->heap, sizeof *ftt));
ftt->table = table;
ftt->fts_trx = fts_trx;
diff --git a/storage/perfschema/unittest/stub_pfs_global.h b/storage/perfschema/unittest/stub_pfs_global.h
index 4371523b014..6d10e29161d 100644
--- a/storage/perfschema/unittest/stub_pfs_global.h
+++ b/storage/perfschema/unittest/stub_pfs_global.h
@@ -1,4 +1,5 @@
/* Copyright (c) 2008, 2021, Oracle and/or its affiliates.
+ Copyright (c) 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
@@ -24,6 +25,9 @@
#include <my_sys.h>
#include <pfs_global.h>
#include <string.h>
+#ifdef HAVE_MEMALIGN
+# include <malloc.h>
+#endif
bool pfs_initialized= false;
size_t pfs_allocated_memory_size= 0;
@@ -45,7 +49,17 @@ void *pfs_malloc(PFS_builtin_memory_class *klass, size_t size, myf)
if (--stub_alloc_fails_after_count <= 0)
return NULL;
+#ifndef PFS_ALIGNEMENT
void *ptr= malloc(size);
+#elif defined HAVE_MEMALIGN
+ void *ptr= memalign(PFS_ALIGNEMENT, size);
+#elif defined HAVE_ALIGNED_MALLOC
+ void *ptr= _aligned_malloc(size, PFS_ALIGNEMENT);
+#else
+ void *ptr;
+ if (posix_memalign(&ptr, PFS_ALIGNEMENT, size))
+ ptr= NULL;
+#endif
if (ptr != NULL)
memset(ptr, 0, size);
return ptr;
diff --git a/strings/decimal.c b/strings/decimal.c
index 1f9a28c1ad5..acb613f1b74 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -1128,13 +1128,21 @@ int decimal2ulonglong(const decimal_t *from, ulonglong *to)
for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1)
{
- ulonglong y=x;
- x=x*DIG_BASE + *buf++;
- if (unlikely(y > ((ulonglong) ULONGLONG_MAX/DIG_BASE) || x < y))
+ /*
+ Check that the decimal is bigger than any possible integer.
+ Do it before we do the x*=DIB_BASE to avoid integer
+ overflow.
+ */
+ if (unlikely (
+ x >= ULONGLONG_MAX/DIG_BASE &&
+ (x > ULONGLONG_MAX/DIG_BASE ||
+ *buf > (dec1) (ULONGLONG_MAX%DIG_BASE))))
{
*to=ULONGLONG_MAX;
return E_DEC_OVERFLOW;
}
+
+ x=x*DIG_BASE + *buf++;
}
*to=x;
for (frac=from->frac; unlikely(frac > 0); frac-=DIG_PER_DEC1)
@@ -1151,23 +1159,29 @@ int decimal2longlong(const decimal_t *from, longlong *to)
for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1)
{
- longlong y=x;
/*
+ Check that the decimal is less than any possible integer.
+ Do it before we do the x*=DIB_BASE to avoid integer
+ overflow.
Attention: trick!
we're calculating -|from| instead of |from| here
because |LONGLONG_MIN| > LONGLONG_MAX
- so we can convert -9223372036854775808 correctly
+ so we can convert -9223372036854775808 correctly.
*/
- x=x*DIG_BASE - *buf++;
- if (unlikely(y < (LONGLONG_MIN/DIG_BASE) || x > y))
+ if (unlikely (
+ x <= LONGLONG_MIN/DIG_BASE &&
+ (x < LONGLONG_MIN/DIG_BASE ||
+ *buf > (dec1) (-(LONGLONG_MIN%DIG_BASE)))))
{
/*
- the decimal is bigger than any possible integer
- return border integer depending on the sign
+ the decimal is bigger than any possible integer
+ return border integer depending on the sign
*/
*to= from->sign ? LONGLONG_MIN : LONGLONG_MAX;
return E_DEC_OVERFLOW;
}
+
+ x=x*DIG_BASE - *buf++;
}
/* boundary case: 9223372036854775808 */
if (unlikely(from->sign==0 && x == LONGLONG_MIN))