/** * MXS-2521: COM_STMT_EXECUTE maybe return empty result * https://jira.mariadb.org/browse/MXS-2521 */ #include "testconnections.h" void do_test(TestConnections& test, MYSQL* conn) { auto stmt = mysql_stmt_init(conn); std::string sql = "select a, @@server_id from double_execute where a = ?"; test.expect(mysql_stmt_prepare(stmt, sql.c_str(), sql.length()) == 0, "Prepare should work: %s", mysql_error(conn)); int data_out = 123; MYSQL_BIND bind_out; char null_out = 0; bind_out.buffer_type = MYSQL_TYPE_LONG; bind_out.buffer = &data_out; bind_out.buffer_length = sizeof(data_out); bind_out.is_null = &null_out; test.expect(mysql_stmt_bind_param(stmt, &bind_out) == 0, "Bind: %s", mysql_stmt_error(stmt)); // The first execute is done on the master test.try_query(conn, "BEGIN"); test.expect(mysql_stmt_execute(stmt) == 0, "First execute should work: %s", mysql_stmt_error(stmt)); int data_in[2] = {}; MYSQL_BIND bind_in[2] = {}; char null_in[2] = {}; for (int i = 0; i < 2; i++) { bind_in[i].buffer_type = MYSQL_TYPE_LONG; bind_in[i].buffer = &data_in[i]; bind_in[i].buffer_length = sizeof(data_in[i]); bind_in[i].is_null = &null_in[i]; } mysql_stmt_bind_result(stmt, bind_in); mysql_stmt_store_result(stmt); test.expect(mysql_stmt_fetch(stmt) == 0, "First fetch of first execute should work"); test.expect(data_in[0] == 123, "Query should return one row with value 123: `%d`", data_in[0]); test.expect(mysql_stmt_fetch(stmt) != 0, "Second fetch of first execute should NOT work"); int first_server = data_in[1]; test.try_query(conn, "COMMIT"); // The second execute goes to a slave, no new parameters are sent in it memset(data_in, 0, sizeof(data_in)); test.expect(mysql_stmt_execute(stmt) == 0, "Second execute should work: %s", mysql_stmt_error(stmt)); mysql_stmt_bind_result(stmt, bind_in); mysql_stmt_store_result(stmt); test.expect(mysql_stmt_fetch(stmt) == 0, "First fetch of second execute should work"); test.expect(data_in[0] == 123, "Query should return one row with value 123: `%d`", data_in[0]); test.expect(data_in[1] == first_server, "The query should be routed to the server with server_id %d, not %d", first_server, data_in[1]); test.expect(mysql_stmt_fetch(stmt) != 0, "Second fetch of second execute should NOT work"); mysql_stmt_close(stmt); } int main(int argc, char** argv) { TestConnections test(argc, argv); test.repl->connect(); test.maxscales->connect(); // Prepare a table test.try_query(test.repl->nodes[0], "DROP TABLE IF EXISTS double_execute;"); test.try_query(test.repl->nodes[0], "CREATE TABLE double_execute(a int);"); test.try_query(test.repl->nodes[0], "INSERT INTO double_execute VALUES (123), (456)"); test.repl->sync_slaves(); test.tprintf("Running test with a direct connection"); do_test(test, test.repl->nodes[0]); test.tprintf("Running test through readwritesplit"); do_test(test, test.maxscales->conn_rwsplit[0]); test.try_query(test.repl->nodes[0], "DROP TABLE IF EXISTS double_execute;"); return test.global_result; }