From c2857b976a560c17305d4bd54531ca5959a2398c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Wed, 29 Mar 2017 07:22:26 +0300 Subject: [PATCH] Add collectable resultset buffer type The new type allows routers to send queries and get complete result sets as a response. This allows the routers to easily send commands that create result sets and which are parsed by the router. Currently only the schemarouter benefits from this new capability as it generates the database mappings by parsing the output of a SHOW DATABASES query. --- include/maxscale/buffer.h | 4 ++- include/maxscale/protocol/mysql.h | 3 ++- .../MySQL/MySQLBackend/mysql_backend.c | 25 +++++++++++++++---- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/include/maxscale/buffer.h b/include/maxscale/buffer.h index 375d85b88..139d6e2a8 100644 --- a/include/maxscale/buffer.h +++ b/include/maxscale/buffer.h @@ -56,7 +56,8 @@ typedef enum GWBUF_TYPE_RESPONSE_END = 0x02, GWBUF_TYPE_SESCMD = 0x04, GWBUF_TYPE_HTTP = 0x08, - GWBUF_TYPE_IGNORABLE = 0x10 + GWBUF_TYPE_IGNORABLE = 0x10, + GWBUF_TYPE_COLLECT_RESULT = 0x20 } gwbuf_type_t; #define GWBUF_IS_TYPE_UNDEFINED(b) (b->gwbuf_type == 0) @@ -64,6 +65,7 @@ typedef enum #define GWBUF_IS_TYPE_RESPONSE_END(b) (b->gwbuf_type & GWBUF_TYPE_RESPONSE_END) #define GWBUF_IS_TYPE_SESCMD(b) (b->gwbuf_type & GWBUF_TYPE_SESCMD) #define GWBUF_IS_IGNORABLE(b) (b->gwbuf_type & GWBUF_TYPE_IGNORABLE) +#define GWBUF_SHOULD_COLLECT_RESULT(b) (b->gwbuf_type & GWBUF_TYPE_COLLECT_RESULT) /** * A structure to encapsulate the data in a form that the data itself can be diff --git a/include/maxscale/protocol/mysql.h b/include/maxscale/protocol/mysql.h index 5f3daca08..7221fc6ac 100644 --- a/include/maxscale/protocol/mysql.h +++ b/include/maxscale/protocol/mysql.h @@ -305,8 +305,9 @@ typedef struct uint32_t extra_capabilities; /*< MariaDB 10.2 capabilities */ unsigned long tid; /*< MySQL Thread ID, in handshake */ unsigned int charset; /*< MySQL character set at connect time */ - int ignore_replies; /*< How many replies should be discarded */ + int ignore_replies; /*< How many replies should be discarded */ GWBUF* stored_query; /*< Temporarily stored queries */ + bool collect_result; /*< Collect the next result set as one buffer */ #if defined(SS_DEBUG) skygw_chk_t protocol_chk_tail; #endif diff --git a/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c b/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c index 0ccf20748..5f78e7fc6 100644 --- a/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c +++ b/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c @@ -618,6 +618,12 @@ static inline bool expecting_resultset(MySQLProtocol *proto) proto->current_command == MYSQL_COM_STMT_FETCH; } +static inline bool collecting_resultset(MySQLProtocol *proto, uint64_t capabilities) +{ + return rcap_type_required(capabilities, RCAP_TYPE_RESULTSET_OUTPUT) || + proto->collect_result; +} + /** * @brief With authentication completed, read new data and write to backend * @@ -673,7 +679,10 @@ gw_read_and_write(DCB *dcb) read_buffer = tmp; - if (rcap_type_required(capabilities, RCAP_TYPE_CONTIGUOUS_OUTPUT)) + MySQLProtocol *proto = (MySQLProtocol*)dcb->protocol; + + if (rcap_type_required(capabilities, RCAP_TYPE_CONTIGUOUS_OUTPUT) || + proto->collect_result) { if ((tmp = gwbuf_make_contiguous(read_buffer))) { @@ -687,10 +696,9 @@ gw_read_and_write(DCB *dcb) return 0; } - MySQLProtocol *proto = (MySQLProtocol*)dcb->protocol; - - if (rcap_type_required(capabilities, RCAP_TYPE_RESULTSET_OUTPUT) && - expecting_resultset(proto) && mxs_mysql_is_result_set(read_buffer)) + if (collecting_resultset(proto, capabilities) && + expecting_resultset(proto) && + mxs_mysql_is_result_set(read_buffer)) { int more = 0; if (modutil_count_signal_packets(read_buffer, 0, 0, &more) != 2) @@ -698,6 +706,9 @@ gw_read_and_write(DCB *dcb) dcb->dcb_readqueue = read_buffer; return 0; } + + // Collected the complete result + proto->collect_result = false; } } } @@ -968,6 +979,10 @@ static int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue) /** Record the command to backend's protocol */ protocol_add_srv_command(backend_protocol, cmd); } + else if (GWBUF_SHOULD_COLLECT_RESULT(queue)) + { + backend_protocol->collect_result = true; + } if (cmd == MYSQL_COM_QUIT && dcb->server->persistpoolmax) {