From 232f807ef32d0648784ab1449dc1cab65e5bbaa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Tue, 17 Apr 2018 11:19:37 +0300 Subject: [PATCH] MXS-1808: Only store SQL statements for retrying Only commands that can contain an SQL statements should be stored for retrying (COM_QUERY and COM_EXECUTE). Other commands are either session commands or do not work with query retrying. --- maxscale-system-test/CMakeLists.txt | 4 + maxscale-system-test/mxs1808_long_data.cpp | 86 +++++++++++++++++++ .../readwritesplit/rwsplit_route_stmt.cc | 8 +- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 maxscale-system-test/mxs1808_long_data.cpp diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 77ab4cc62..23b6708fb 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -648,6 +648,10 @@ add_test_executable(mxs1786_statistics.cpp mxs1786_statistics replication LABELS # https://jira.mariadb.org/browse/MXS-1787 add_test_executable(mxs1787_call_ps.cpp mxs1787_call_ps replication LABELS readwritesplit REPL_BACKEND) +# MXS-1808: Crash with mysql_stmt_send_long_data +# https://jira.mariadb.org/browse/MXS-1808 +add_test_executable(mxs1808_long_data.cpp mxs1808_long_data replication LABELS readwritesplit REPL_BACKEND) + # 'namedserverfilter' test add_test_executable(namedserverfilter.cpp namedserverfilter namedserverfilter LABELS namedserverfilter LIGHT REPL_BACKEND) diff --git a/maxscale-system-test/mxs1808_long_data.cpp b/maxscale-system-test/mxs1808_long_data.cpp new file mode 100644 index 000000000..c0617f6ab --- /dev/null +++ b/maxscale-system-test/mxs1808_long_data.cpp @@ -0,0 +1,86 @@ +#include "testconnections.h" +#include + +using namespace std; + +void print_stmt_error(MYSQL_STMT *stmt, const char* msg) +{ + cout << "Error: " << msg << ": " << mysql_stmt_error(stmt) << endl; +} + +static int test_long_data(MYSQL *conn, int sqlsize) +{ + int data1size = sqlsize / 2; + + char * data1 = (char*) malloc(data1size); + memset(data1, 97, data1size); + char * data3 = (char*) malloc(sqlsize); + memset(data3, 99, sqlsize); + + MYSQL_STMT *stmt; + stmt = mysql_stmt_init(conn); + int rc, int_data; + MYSQL_RES *result; + MYSQL_BIND my_bind[1]; + + rc = mysql_autocommit(conn, 1); + + if (NULL == stmt) + { + fprintf(stderr, "%s", mysql_error(conn)); + return 0; + } + if (mysql_stmt_prepare(stmt, "select ?", strlen("select ?")) != 0) + { + print_stmt_error(stmt, "stmt prepare fail"); + return 0; + } + + memset((char*) my_bind, 0, sizeof(my_bind)); + + my_bind[0].buffer = (void *)&int_data; + my_bind[0].buffer_type = MYSQL_TYPE_STRING; + + if (mysql_stmt_bind_param(stmt, my_bind) != 0) + { + print_stmt_error(stmt, "bind param error"); + return 0; + } + + /* supply data in pieces */ + if (mysql_stmt_send_long_data(stmt, 0, data1, data1size) != 0) + { + print_stmt_error(stmt, "send long data1 failed"); + return 0; + } + if (mysql_stmt_send_long_data(stmt, 0, data3, sqlsize) != 0) + { + print_stmt_error(stmt, "send long data3 failed"); + return 0; + } + + /* execute */ + if (mysql_stmt_execute(stmt) != 0) + { + print_stmt_error(stmt, "execute prepare stmt failed"); + return 0; + } + /* get the result */ + result = mysql_store_result(conn); + mysql_free_result(result); + mysql_stmt_close(stmt); + free(data1); + free(data3); + return 1; +} + +int main(int argc, char** argv) +{ + TestConnections test(argc, argv); + + test.maxscales->connect(); + test.assert(test_long_data(test.maxscales->conn_rwsplit[0], 123456), "Test should work"); + test.maxscales->disconnect(); + + return test.global_result; +} diff --git a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc index cca0e5663..f9d943fbc 100644 --- a/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc +++ b/server/modules/routing/readwritesplit/rwsplit_route_stmt.cc @@ -242,7 +242,13 @@ bool route_single_stmt(RWSplit *inst, RWSplitSession *rses, GWBUF *querybuf, con if ((target = handle_slave_is_target(inst, rses, command, stmt_id))) { succp = true; - store_stmt = rses->rses_config.retry_failed_reads; + + if (rses->rses_config.retry_failed_reads && + (command == MXS_COM_QUERY || command == MXS_COM_STMT_EXECUTE)) + { + // Only commands that can contain an SQL statement should be stored + store_stmt = true; + } } } else if (TARGET_IS_MASTER(route_target))