Merge branch '2.2' into develop

This commit is contained in:
Esa Korhonen 2018-09-11 12:57:19 +03:00
commit fd176c4122
18 changed files with 255 additions and 108 deletions

View File

@ -16,7 +16,7 @@ endif()
# Set default values for cache entries and set the MaxScale version
include(cmake/defaults.cmake)
include(VERSION22.cmake)
include(VERSION.cmake)
include(ExternalProject)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")

View File

@ -31,7 +31,9 @@ monitor_interval=2500
### `backend_connect_timeout`
This parameter controls the timeout for connecting to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 3 seconds.
This parameter controls the timeout for connecting to a monitored server. It is
in seconds and the minimum value is 1 second. The default value for this
parameter is 3 seconds.
```
backend_connect_timeout=6
@ -39,7 +41,9 @@ backend_connect_timeout=6
### `backend_write_timeout`
This parameter controls the timeout for writing to a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 2 seconds.
This parameter controls the timeout for writing to a monitored server. It is in
seconds and the minimum value is 1 second. The default value for this parameter
is 3 seconds.
```
backend_write_timeout=4
@ -47,7 +51,9 @@ backend_write_timeout=4
### `backend_read_timeout`
This parameter controls the timeout for reading from a monitored server. It is in seconds and the minimum value is 1 second. The default value for this parameter is 1 seconds.
This parameter controls the timeout for reading from a monitored server. It is
in seconds and the minimum value is 1 second. The default value for this
parameter is 3 seconds.
```
backend_read_timeout=2

View File

@ -2,22 +2,19 @@
Release 2.2.14 is a GA release.
This document describes the changes in release 2.2.14, when compared to
release 2.2.13.
This document describes the changes in release 2.2.14, when compared to the
previous release in the same series.
For any problems you encounter, please consider submitting a bug
report on [our Jira](https://jira.mariadb.org/projects/MXS).
## New Features
### Avrorouter Table Filtering
The tables that the avrorouter processes can now be filtered with two new
parameters: [`match`](../Routers/Avrorouter.md#match) and
[`exclude`](../Routers/Avrorouter.md#exclude).
* [MXS-2039](https://jira.mariadb.org/browse/MXS-2039) Filter tables in avrorouter
## Bug fixes
* [MXS-2037](https://jira.mariadb.org/browse/MXS-2037) % wildcards not working with source in Named Server Filter
* [MXS-2034](https://jira.mariadb.org/browse/MXS-2034) query_retry_timeout was not set
* [MXS-2027](https://jira.mariadb.org/browse/MXS-2027) LOAD DATA LOCAL INFILE is not ignored by protocol modules
* [MXS-2024](https://jira.mariadb.org/browse/MXS-2024) Crash in reauthenticate_client

View File

@ -0,0 +1,42 @@
#!/bin/bash
major=`cmake -P ../../VERSION.cmake -L|grep 'MAXSCALE_VERSION_MAJOR'|sed 's/.*=//'`
minor=`cmake -P ../../VERSION.cmake -L|grep 'MAXSCALE_VERSION_MINOR'|sed 's/.*=//'`
patch=`cmake -P ../../VERSION.cmake -L|grep 'MAXSCALE_VERSION_PATCH'|sed 's/.*=//'`
maturity=`cmake -P ../../VERSION.cmake -L|grep 'MAXSCALE_MATURITY'|sed 's/.*=//'`
VERSION=${major}.${minor}.${patch}
cat <<EOF > MaxScale-$VERSION-Release-Notes.md
# MariaDB MaxScale ${VERSION} Release Notes
Release ${VERSION} is a ${maturity} release.
This document describes the changes in release ${VERSION}, when compared to the
previous release in the same series.
For any problems you encounter, please consider submitting a bug
report on [our Jira](https://jira.mariadb.org/projects/MXS).
`../list_fixed.sh ${VERSION}`
## Known Issues and Limitations
There are some limitations and known issues within this version of MaxScale.
For more information, please refer to the [Limitations](../About/Limitations.md) document.
## Packaging
RPM and Debian packages are provided for supported the Linux distributions.
Packages can be downloaded [here](https://mariadb.com/downloads/mariadb-tx/maxscale).
## Source Code
The source code of MaxScale is tagged at GitHub with a tag, which is identical
with the version of MaxScale. For instance, the tag of version X.Y.Z of MaxScale
is \`maxscale-X.Y.Z\`. Further, the default branch is always the latest GA version
of MaxScale.
The source code is available [here](https://github.com/mariadb-corporation/MaxScale).
EOF

View File

@ -11,4 +11,4 @@ fi
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
version=$1
curl -s "https://jira.mariadb.org/sr/jira.issueviews:searchrequest-csv-current-fields/temp/SearchRequest.csv?jqlQuery=project+%3D+MXS+AND+issuetype+%3D+Bug+AND+status+%3D+Closed+AND+fixVersion+%3D+$version" | $DIR/process.pl
curl -s "https://jira.mariadb.org/sr/jira.issueviews:searchrequest-csv-all-fields/temp/SearchRequest.csv?jqlQuery=project+%3D+MXS+AND+status+%3D+Closed+AND+fixVersion+%3D+$version" | $DIR/process.py

View File

@ -1,14 +0,0 @@
#!/bin/bash
if [ $# -ne 1 ]
then
echo "USAGE: $0 VERSION"
exit 1
fi
# Script location
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
version=$1
curl -s "https://jira.mariadb.org/sr/jira.issueviews:searchrequest-csv-current-fields/temp/SearchRequest.csv?jqlQuery=project+%3D+MXS+AND+issuetype+%21%3D+Bug+AND+status+%3D+Closed+AND+fixVersion+%3D+$version" | $DIR/process.pl

View File

@ -1,22 +0,0 @@
#!/usr/bin/env perl
# Discard the CSV headers
<>;
while (<>)
{
# Replace commas that are inside double quotes
while (s/("[^"]*),([^"]*")/$1$2/g)
{
;
}
# Replace the double quotes themselves
s/"//g;
# Split the line and grab the issue number and description
my @parts = split(/,/);
my $issue = @parts[1];
my $desc = @parts[0];
print "* [$issue](https://jira.mariadb.org/browse/$issue) $desc\n";
}

30
Documentation/process.py Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
import sys
import csv
bugs = []
new_features = []
for row in csv.DictReader(sys.stdin):
if row['Issue Type'] == 'Bug':
bugs.append(row)
elif row['Issue Type'] == 'New Feature':
new_features.append(row)
if len(new_features) > 0:
print("## New Features")
print()
for f in new_features:
print("* [" + f['Issue key'] + "](https://jira.mariadb.org/browse/" + f['Issue key'] + ") " + f['Summary'])
print()
print("## Bug fixes")
print()
for b in bugs:
print("* [" + b['Issue key'] + "](https://jira.mariadb.org/browse/" + b['Issue key'] + ") " + b['Summary'])
print()

1
VERSION.cmake Normal file
View File

@ -0,0 +1 @@
include(${CMAKE_SOURCE_DIR}/VERSION22.cmake)

View File

@ -10,5 +10,7 @@ set(MAXSCALE_VERSION_PATCH "3" CACHE STRING "Patch version")
# This should only be incremented if a package is rebuilt
set(MAXSCALE_BUILD_NUMBER 1 CACHE STRING "Release number")
set(MAXSCALE_MATURITY "GA" CACHE STRING "Release maturity")
set(MAXSCALE_VERSION_NUMERIC "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}")
set(MAXSCALE_VERSION "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}")

View File

@ -10,5 +10,7 @@ set(MAXSCALE_VERSION_PATCH "18" CACHE STRING "Patch version")
# This should only be incremented if a package is rebuilt
set(MAXSCALE_BUILD_NUMBER 1 CACHE STRING "Release number")
set(MAXSCALE_MATURITY "GA" CACHE STRING "Release maturity")
set(MAXSCALE_VERSION_NUMERIC "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}")
set(MAXSCALE_VERSION "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}")

View File

@ -10,5 +10,7 @@ set(MAXSCALE_VERSION_PATCH "14" CACHE STRING "Patch version")
# This should only be incremented if a package is rebuilt
set(MAXSCALE_BUILD_NUMBER 1 CACHE STRING "Release number")
set(MAXSCALE_MATURITY "GA" CACHE STRING "Release maturity")
set(MAXSCALE_VERSION_NUMERIC "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}")
set(MAXSCALE_VERSION "${MAXSCALE_VERSION_MAJOR}.${MAXSCALE_VERSION_MINOR}.${MAXSCALE_VERSION_PATCH}")

View File

@ -1,2 +1,2 @@
include(../VERSION22.cmake)
include(../VERSION.cmake)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/lib/version.js.in ${CMAKE_CURRENT_BINARY_DIR}/lib/version.js @ONLY)

View File

@ -491,6 +491,10 @@ add_test_executable(mxs827_write_timeout.cpp mxs827_write_timeout mxs827_write_t
# https://jira.mariadb.org/browse/MXS-872
add_test_executable(mxs872_roles.cpp mxs872_roles replication LABELS REPL_BACKEND)
# MXS-1947: Composite roles are not supported
# https://jira.mariadb.org/browse/MXS-1947
add_test_executable(mxs1947_composite_roles.cpp mxs1947_composite_roles replication LABELS REPL_BACKEND)
# Block and unblock first and second slaves and check that they are recovered
add_test_executable(mxs874_slave_recovery.cpp mxs874_slave_recovery mxs874 LABELS readwritesplit REPL_BACKEND)

View File

@ -0,0 +1,55 @@
/**
* MXS-1947: Composite roles are not supported
*
* https://jira.mariadb.org/browse/MXS-1947
*/
#include "testconnections.h"
int main(int argc, char** argv)
{
TestConnections test(argc, argv);
test.repl->connect();
auto prepare =
{
"DROP USER test@'%'",
"CREATE USER test@'%' IDENTIFIED BY 'test';",
"CREATE ROLE a;",
"CREATE ROLE b;",
"CREATE DATABASE db;",
"GRANT ALL ON db.* TO a;",
"GRANT a TO b;",
"GRANT b TO test@'%';",
"SET DEFAULT ROLE b FOR test@'%';"
};
for (auto a : prepare)
{
execute_query_silent(test.repl->nodes[0], a);
}
// Wait for the users to replicate
test.repl->sync_slaves();
test.tprintf("Connect with a user that has a composite role as the default role");
MYSQL* conn = open_conn_db(test.maxscales->rwsplit_port[0], test.maxscales->IP[0], "db", "test", "test");
test.assert(mysql_errno(conn) == 0, "Connection failed: %s", mysql_error(conn));
mysql_close(conn);
auto cleanup =
{
"DROP DATABASE IF EXISTS db;",
"DROP ROLE IF EXISTS a;",
"DROP ROLE IF EXISTS b;",
"DROP USER 'test'@'%';"
};
for (auto a : cleanup)
{
execute_query_silent(test.repl->nodes[0], a);
}
return test.global_result;
}

View File

@ -23,9 +23,9 @@ MXS_BEGIN_DECLS
#define MON_ARG_MAX 8192
#define DEFAULT_CONNECT_TIMEOUT 3
#define DEFAULT_READ_TIMEOUT 1
#define DEFAULT_WRITE_TIMEOUT 2
#define DEFAULT_CONNECT_TIMEOUT 3
#define DEFAULT_READ_TIMEOUT 3
#define DEFAULT_WRITE_TIMEOUT 3
#define DEFAULT_CONNECTION_ATTEMPTS 1
#define DEFAULT_MONITOR_INTERVAL 2000 // in milliseconds

View File

@ -43,8 +43,8 @@
/** MySQL 5.7 password column name */
#define MYSQL57_PASSWORD "authentication_string"
#define NEW_LOAD_DBUSERS_QUERY \
"SELECT u.user, u.host, d.db, u.select_priv, u.%s \
// Query used with 10.0 or older
#define NEW_LOAD_DBUSERS_QUERY "SELECT u.user, u.host, d.db, u.select_priv, u.%s \
FROM mysql.user AS u LEFT JOIN mysql.db AS d \
ON (u.user = d.user AND u.host = d.host) WHERE u.plugin IN ('', 'mysql_native_password') %s \
UNION \
@ -52,56 +52,93 @@
FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t \
ON (u.user = t.user AND u.host = t.host) WHERE u.plugin IN ('', 'mysql_native_password') %s"
// Query used with MariaDB 10.1 and newer, supports roles
const char* mariadb_users_query
= // First, select all users
"SELECT t.user, t.host, t.db, t.select_priv, t.password FROM "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS t "
// Discard any users that are roles
"WHERE t.is_role <> 'Y' %s "
"UNION "
// Then select all users again
"SELECT r.user, r.host, u.db, u.select_priv, t.password FROM "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS t "
// Join it to the roles_mapping table to only have users with roles
"JOIN mysql.roles_mapping AS r "
"ON (r.user = t.user AND r.host = t.host) "
// Then join it into itself to get the privileges of the role with the name of the user
"JOIN "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS u "
"ON (u.user = r.role AND u.is_role = 'Y') "
// We only care about users that have a default role assigned
"WHERE t.default_role = u.user %s;";
// Used with 10.2 or newer, supports composite roles
const char* mariadb_102_users_query =
// `t` is users that are not roles
"WITH RECURSIVE t AS ( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role, u.default_role"
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host)"
"), users AS ("
// Select the root row, the actual user
" SELECT t.user, t.host, t.db, t.select_priv, t.password, t.default_role AS role FROM t"
" WHERE t.is_role <> 'Y'"
" UNION"
// Recursively select all roles for the users
" SELECT u.user, u.host, t.db, t.select_priv, u.password, r.role FROM t"
" JOIN users AS u"
" ON (t.user = u.role)"
" LEFT JOIN mysql.roles_mapping AS r"
" ON (t.user = r.user)"
")"
"SELECT DISTINCT t.user, t.host, t.db, t.select_priv, t.password FROM users AS t %s";
static int get_users(SERV_LISTENER* listener, bool skip_local);
static MYSQL* gw_mysql_init(void);
static int gw_mysql_set_timeouts(MYSQL* handle);
static char* mysql_format_user_entry(void* data);
static bool get_hostname(DCB* dcb, char* client_hostname, size_t size);
// Query used with MariaDB 10.1, supports basic roles
const char* mariadb_users_query =
// First, select all users
"SELECT t.user, t.host, t.db, t.select_priv, t.password FROM "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS t "
// Discard any users that are roles
"WHERE t.is_role <> 'Y' %s "
"UNION "
// Then select all users again
"SELECT r.user, r.host, u.db, u.select_priv, t.password FROM "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.default_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS t "
// Join it to the roles_mapping table to only have users with roles
"JOIN mysql.roles_mapping AS r "
"ON (r.user = t.user AND r.host = t.host) "
// Then join it into itself to get the privileges of the role with the name of the user
"JOIN "
"( "
" SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.db AS d "
" ON (u.user = d.user AND u.host = d.host) "
" UNION "
" SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role "
" FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t "
" ON (u.user = t.user AND u.host = t.host) "
") AS u "
"ON (u.user = r.role AND u.is_role = 'Y') "
// We only care about users that have a default role assigned
"WHERE t.default_role = u.user %s;";
static int get_users(SERV_LISTENER *listener, bool skip_local);
static MYSQL *gw_mysql_init(void);
static int gw_mysql_set_timeouts(MYSQL* handle);
static char *mysql_format_user_entry(void *data);
static bool get_hostname(DCB *dcb, char *client_hostname, size_t size);
static char* get_mariadb_102_users_query(bool include_root)
{
const char *root = include_root ? "" : " WHERE t.user <> 'root'";
size_t n_bytes = snprintf(NULL, 0, mariadb_102_users_query, root);
char *rval = static_cast<char*>(MXS_MALLOC(n_bytes + 1));
MXS_ABORT_IF_NULL(rval);
snprintf(rval, n_bytes + 1, mariadb_102_users_query, root);
return rval;
}
static char* get_mariadb_users_query(bool include_root)
{
@ -115,11 +152,13 @@ static char* get_mariadb_users_query(bool include_root)
return rval;
}
static char* get_users_query(const char* server_version, bool include_root, bool is_mariadb)
static char* get_users_query(const char *server_version, int version, bool include_root, bool is_mariadb)
{
if (is_mariadb) // 10.1.1 or newer, supports default roles
{
return get_mariadb_users_query(include_root);
return version >= 100202 ?
get_mariadb_102_users_query(include_root) :
get_mariadb_users_query(include_root);
}
// Either an older MariaDB version or a MySQL variant, use the legacy query
@ -896,7 +935,8 @@ int get_users_from_server(MYSQL* con, SERVER_REF* server_ref, SERVICE* service,
mxs_mysql_set_server_version(con, server_ref->server);
}
char* query = get_users_query(server_ref->server->version_string,
char *query = get_users_query(server_ref->server->version_string,
server_ref->server->version,
service->enable_root,
roles_are_available(con, service, server_ref->server));
@ -906,7 +946,8 @@ int get_users_from_server(MYSQL* con, SERVER_REF* server_ref, SERVICE* service,
if (query)
{
if (mxs_mysql_query(con, query) == 0)
if (mxs_mysql_query(con, "USE mysql") == 0 && // Set default database in case we use CTEs
mxs_mysql_query(con, query) == 0)
{
MYSQL_RES* result = mysql_store_result(con);

View File

@ -866,7 +866,8 @@ static int gw_read_and_write(DCB* dcb)
if (mxs_mysql_is_result_set(read_buffer))
{
bool more = false;
if (modutil_count_signal_packets(read_buffer, 0, &more, NULL) != 2)
int eof_cnt = modutil_count_signal_packets(read_buffer, 0, &more, NULL);
if (more || eof_cnt % 2 != 0)
{
dcb_readq_prepend(dcb, read_buffer);
return 0;