/** * @file bug694.cpp - regression test for bug694 ("RWSplit: SELECT @a:=@a+1 as a, test.b FROM test breaks * client session") * * - set use_sql_variables_in=all in MaxScale.cnf * - connect to readwritesplit router and execute: * @verbatim * CREATE TABLE test (b integer); * SELECT @a:=@a+1 as a, test.b FROM test; * USE test * @endverbatim * - check if MaxScale alive */ /* * * Description Vilho Raatikka 2015-01-14 08:09:45 UTC * Reproduce: * - set use_sql_variables_in=all in MaxScale.cnf * - connect to readwritesplit router and execute: * CREATE TABLE test (b integer); * SELECT @a:=@a+1 as a, test.b FROM test; * USE test * * You'll get: * ERROR 2006 (HY000): MySQL server has gone away * * It is a known limitation that SELÈCTs with SQL variable modifications are not supported. The issue is that * they aren't detected and as a consequence hte client session is disconnected. * * It is possible to detect this kind of query in query classifier, but set_query_type loses part of the * information. If both SELECT and SQL variable update are detected they can be stored in query type and * rwsplit could, for example, prevent from executing the query, execute it in master only (and log), force * all SQL variable modifications from that point to master (and log), etc. * Comment 1 Vilho Raatikka 2015-01-15 13:19:18 UTC * query_classifier.cc: set_query_type lost previous query type if the new was more restrictive. Problem was * that if query is both READ and SESSION_WRITE and configuration parameter use_sql_variables_in=all was set, * routing target became ambiguous. Replaced call to set_query_type with simply adding new type to type (=bit * field) and checking unsupported combinations in readwritesplit.c:get_route_target. If such a case is met, a * detailed error is written to error log in readwritesplit.c. mysql_client.c sees the error code and sends an * error to client. Then mysql_client.c calls router's handleError which ensures that there are enough backend * servers so that the session can continue. */ #include #include "testconnections.h" #include "mariadb_func.h" int main(int argc, char* argv[]) { TestConnections* Test = new TestConnections(argc, argv); Test->set_timeout(120); Test->maxscales->connect_maxscale(0); Test->try_query(Test->maxscales->conn_rwsplit[0], "USE test"); Test->try_query(Test->maxscales->conn_rwsplit[0], "DROP TABLE IF EXISTS test"); Test->try_query(Test->maxscales->conn_rwsplit[0], "CREATE TABLE test (b integer)"); const int iter = Test->smoke ? 10 : 100; Test->tprintf("Creating and inserting %d rows into a table\n", iter); for (int i = 0; i < iter; i++) { Test->set_timeout(30); execute_query(Test->maxscales->conn_rwsplit[0], "insert into test value(2);"); Test->stop_timeout(); } Test->set_timeout(200); Test->tprintf("Trying SELECT @a:=@a+1 as a, test.b FROM test\n"); if (execute_query(Test->maxscales->conn_rwsplit[0], "SELECT @a:=@a+1 as a, test.b FROM test;") == 0) { Test->add_result(1, "Query succeded, but expected to fail.\n"); } Test->tprintf("Trying USE test\n"); Test->try_query(Test->maxscales->conn_rwsplit[0], "USE test"); Test->try_query(Test->maxscales->conn_rwsplit[0], "DROP TABLE IF EXISTS test"); Test->tprintf("Checking if MaxScale alive\n"); Test->maxscales->close_maxscale_connections(0); Test->tprintf("Checking logs\n"); Test->check_log_err(0, (char*) "The query can't be routed to all backend servers because it includes SELECT and SQL variable modifications which is not supported", true); Test->check_log_err(0, (char*) "SELECT with session data modification is not supported if configuration parameter use_sql_variables_in=all", true); Test->check_maxscale_alive(0); int rval = Test->global_result; delete Test; return rval; }