Merge 10.4 into 10.5

This commit is contained in:
Marko Mäkelä 2022-03-29 12:59:18 +03:00
commit d62b0368ca
86 changed files with 2875 additions and 251 deletions

View file

@ -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)

View file

@ -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);
}

View file

@ -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 */

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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
#

View file

@ -1067,6 +1067,25 @@ DROP TABLE t1;
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 #

View file

@ -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
#

View file

@ -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 #

View file

@ -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

View file

@ -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

View file

@ -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
#

View file

@ -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 #

View file

@ -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;

View file

@ -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;

View file

@ -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
#
#

View file

@ -6565,6 +6565,32 @@ SELECT v.id, v.foo AS bar FROM v1 v
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 #

View file

@ -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;

View file

@ -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;

View file

@ -0,0 +1 @@
--autocommit=0

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld.1]
wsrep-debug=1
[mysqld.2]
wsrep-debug=1

View file

@ -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;

View file

@ -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

View file

@ -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\)");

View file

@ -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

View file

@ -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\)");

View file

@ -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

View file

@ -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);
SET @@global.debug_dbug="+d,ha_index_init_fail";
ROLLBACK;
connection node_2;
SELECT COUNT(*) `Expect 0` FROM mysql.wsrep_streaming_log;
Expect 0
0
connection node_1;
SET @@global.debug_dbug="";
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;
SET @@global.debug_dbug="+d,ha_index_init_fail";
ROLLBACK;
connection node_1;
SET SESSION wsrep_sync_wait = 0;
SELECT COUNT(*) `Expect 0` FROM mysql.wsrep_streaming_log;
Expect 0
0
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
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");

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
/*

View file

@ -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;

View file

@ -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.

View file

@ -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
}

View file

@ -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
--

112
scripts/wsrep_sst_backup.sh Normal file
View file

@ -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

View file

@ -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"},

View file

@ -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)

View file

@ -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();
}

View file

@ -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)

View file

@ -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)
{ }

View file

@ -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);

View file

@ -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)
{

View file

@ -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++;

View file

@ -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();

View file

@ -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),

View file

@ -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
{

View file

@ -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)

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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,24 +10588,10 @@ 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:

View file

@ -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;
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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:

View file

@ -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);
}

View file

@ -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 ;

View file

@ -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);

View file

@ -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));

View file

@ -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()

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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,81 +906,33 @@ 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) return 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;
}
}
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;
}

View file

@ -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. */

View file

@ -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;

View file

@ -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;

View file

@ -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))