MXS-1149: maxrows should return empty resultset instead of OK
maxrows returns empty resultset instead of OK. The response with coulmndefs is sent then an EOF without flags is added. Limitations: in case of MULTI_RESULT sets only the first one coulmndefs is sent with EOF
This commit is contained in:
@ -147,6 +147,7 @@ typedef struct maxrows_response_state
|
|||||||
size_t n_fields; /**< How many fields we have received, <= n_totalfields. */
|
size_t n_fields; /**< How many fields we have received, <= n_totalfields. */
|
||||||
size_t n_rows; /**< How many rows we have received. */
|
size_t n_rows; /**< How many rows we have received. */
|
||||||
size_t offset; /**< Where we are in the response buffer. */
|
size_t offset; /**< Where we are in the response buffer. */
|
||||||
|
size_t rows_offset; /**< Offset to first row in result set */
|
||||||
} MAXROWS_RESPONSE_STATE;
|
} MAXROWS_RESPONSE_STATE;
|
||||||
|
|
||||||
static void maxrows_response_state_reset(MAXROWS_RESPONSE_STATE *state);
|
static void maxrows_response_state_reset(MAXROWS_RESPONSE_STATE *state);
|
||||||
@ -175,6 +176,7 @@ static bool process_params(char **options, MXS_CONFIG_PARAMETER *params, MAXROWS
|
|||||||
|
|
||||||
static int send_upstream(MAXROWS_SESSION_DATA *csdata);
|
static int send_upstream(MAXROWS_SESSION_DATA *csdata);
|
||||||
static int send_ok_upstream(MAXROWS_SESSION_DATA *csdata);
|
static int send_ok_upstream(MAXROWS_SESSION_DATA *csdata);
|
||||||
|
static int send_eof_upstream(MAXROWS_SESSION_DATA *csdata, size_t offset);
|
||||||
|
|
||||||
/* API BEGIN */
|
/* API BEGIN */
|
||||||
|
|
||||||
@ -438,6 +440,7 @@ static void maxrows_response_state_reset(MAXROWS_RESPONSE_STATE *state)
|
|||||||
state->n_fields = 0;
|
state->n_fields = 0;
|
||||||
state->n_rows = 0;
|
state->n_rows = 0;
|
||||||
state->offset = 0;
|
state->offset = 0;
|
||||||
|
state->rows_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -511,6 +514,15 @@ static int handle_expecting_fields(MAXROWS_SESSION_DATA *csdata)
|
|||||||
{
|
{
|
||||||
case 0xfe: // EOF, the one after the fields.
|
case 0xfe: // EOF, the one after the fields.
|
||||||
csdata->res.offset += packetlen;
|
csdata->res.offset += packetlen;
|
||||||
|
|
||||||
|
/* Now set the offset to the first resultset
|
||||||
|
* this could be used for empty response handler
|
||||||
|
*/
|
||||||
|
if (!csdata->res.rows_offset)
|
||||||
|
{
|
||||||
|
csdata->res.rows_offset = csdata->res.offset;
|
||||||
|
}
|
||||||
|
|
||||||
csdata->state = MAXROWS_EXPECTING_ROWS;
|
csdata->state = MAXROWS_EXPECTING_ROWS;
|
||||||
rv = handle_rows(csdata);
|
rv = handle_rows(csdata);
|
||||||
break;
|
break;
|
||||||
@ -599,7 +611,7 @@ static int handle_expecting_response(MAXROWS_SESSION_DATA *csdata)
|
|||||||
|
|
||||||
if (csdata->discard_resultset)
|
if (csdata->discard_resultset)
|
||||||
{
|
{
|
||||||
rv = send_ok_upstream(csdata);
|
rv = send_eof_upstream(csdata, csdata->res.rows_offset);
|
||||||
csdata->state = MAXROWS_EXPECTING_NOTHING;
|
csdata->state = MAXROWS_EXPECTING_NOTHING;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -746,7 +758,7 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata)
|
|||||||
// Send data in buffer or empty resultset
|
// Send data in buffer or empty resultset
|
||||||
if (csdata->discard_resultset)
|
if (csdata->discard_resultset)
|
||||||
{
|
{
|
||||||
rv = send_ok_upstream(csdata);
|
rv = send_eof_upstream(csdata, csdata->res.rows_offset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -779,7 +791,7 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata)
|
|||||||
if (packetlen < MYSQL_EOF_PACKET_LEN)
|
if (packetlen < MYSQL_EOF_PACKET_LEN)
|
||||||
{
|
{
|
||||||
MXS_ERROR("EOF packet has size of %lu instead of %d", packetlen, MYSQL_EOF_PACKET_LEN);
|
MXS_ERROR("EOF packet has size of %lu instead of %d", packetlen, MYSQL_EOF_PACKET_LEN);
|
||||||
rv = send_ok_upstream(csdata);
|
rv = send_eof_upstream(csdata, csdata->res.rows_offset);
|
||||||
csdata->state = MAXROWS_EXPECTING_NOTHING;
|
csdata->state = MAXROWS_EXPECTING_NOTHING;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -800,7 +812,7 @@ static int handle_rows(MAXROWS_SESSION_DATA *csdata)
|
|||||||
// Discard data or send data
|
// Discard data or send data
|
||||||
if (csdata->discard_resultset)
|
if (csdata->discard_resultset)
|
||||||
{
|
{
|
||||||
rv = send_ok_upstream(csdata);
|
rv = send_eof_upstream(csdata, csdata->res.rows_offset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -907,7 +919,20 @@ static int send_ok_upstream(MAXROWS_SESSION_DATA *csdata)
|
|||||||
{
|
{
|
||||||
/* Note: sequence id is always 01 (4th byte) */
|
/* Note: sequence id is always 01 (4th byte) */
|
||||||
uint8_t ok[MYSQL_OK_PACKET_MIN_LEN] = {07, 00, 00, 01, 00, 00, 00, 02, 00, 00, 00};
|
uint8_t ok[MYSQL_OK_PACKET_MIN_LEN] = {07, 00, 00, 01, 00, 00, 00, 02, 00, 00, 00};
|
||||||
|
|
||||||
|
ss_dassert(csdata->res.data != NULL);
|
||||||
|
|
||||||
GWBUF *packet = gwbuf_alloc(MYSQL_OK_PACKET_MIN_LEN);
|
GWBUF *packet = gwbuf_alloc(MYSQL_OK_PACKET_MIN_LEN);
|
||||||
|
if(!packet)
|
||||||
|
{
|
||||||
|
/* Abort clienrt connection */
|
||||||
|
poll_fake_hangup_event(csdata->session->client_dcb);
|
||||||
|
gwbuf_free(csdata->res.data);
|
||||||
|
csdata->res.data = NULL;
|
||||||
|
gwbuf_free(packet);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *ptr = GWBUF_DATA(packet);
|
uint8_t *ptr = GWBUF_DATA(packet);
|
||||||
memcpy(ptr, &ok, MYSQL_OK_PACKET_MIN_LEN);
|
memcpy(ptr, &ok, MYSQL_OK_PACKET_MIN_LEN);
|
||||||
|
|
||||||
@ -919,3 +944,68 @@ static int send_ok_upstream(MAXROWS_SESSION_DATA *csdata)
|
|||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send upstream the Respnse Buffer up to columns def in response
|
||||||
|
* including its EOF of the first result set
|
||||||
|
* An EOF packet for empty result set with no MULTI flags is added
|
||||||
|
* at the end.
|
||||||
|
*
|
||||||
|
* @param csdata Session data
|
||||||
|
* @param offset The offset to server reply pointing to
|
||||||
|
* next byte after EOF or column definitions of first result set
|
||||||
|
*
|
||||||
|
* @return Whatever the upstream returns.
|
||||||
|
*/
|
||||||
|
static int send_eof_upstream(MAXROWS_SESSION_DATA *csdata, size_t offset)
|
||||||
|
{
|
||||||
|
int rv = -1;
|
||||||
|
/* Sequence byte is #3 */
|
||||||
|
uint8_t eof[MYSQL_EOF_PACKET_LEN] = {05, 00, 00, 01, 0xfe, 00, 00, 02, 00};
|
||||||
|
GWBUF *new_pkt = NULL;
|
||||||
|
|
||||||
|
ss_dassert(csdata->res.data != NULL);
|
||||||
|
|
||||||
|
/* Data to send + added EOF */
|
||||||
|
uint8_t *new_result = MXS_MALLOC(offset + MYSQL_EOF_PACKET_LEN);
|
||||||
|
|
||||||
|
if (new_result)
|
||||||
|
{
|
||||||
|
/* Get contiguous data from beginning to specified offset */
|
||||||
|
gwbuf_copy_data(csdata->res.data, 0, offset, new_result);
|
||||||
|
|
||||||
|
/* Increment sequence number for the EOF being added for empty resultset:
|
||||||
|
* last one if found in EOF terminating column def
|
||||||
|
*/
|
||||||
|
eof[3] = new_result[offset - (MYSQL_EOF_PACKET_LEN - 3)] + 1;
|
||||||
|
|
||||||
|
/* Copy EOF data */
|
||||||
|
memcpy(new_result + offset, &eof, MYSQL_EOF_PACKET_LEN);
|
||||||
|
|
||||||
|
/* Create new packet */
|
||||||
|
new_pkt = gwbuf_alloc_and_load(offset + MYSQL_EOF_PACKET_LEN, new_result);
|
||||||
|
|
||||||
|
/* Free intermediate data */
|
||||||
|
MXS_FREE(new_result);
|
||||||
|
|
||||||
|
if (new_pkt)
|
||||||
|
{
|
||||||
|
/* new_pkt will be freed by write routine */
|
||||||
|
rv = csdata->up.clientReply(csdata->up.instance, csdata->up.session, new_pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Abort client connection */
|
||||||
|
if (!(new_result && new_pkt))
|
||||||
|
{
|
||||||
|
/* Abort client connection */
|
||||||
|
poll_fake_hangup_event(csdata->session->client_dcb);
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free full input buffer */
|
||||||
|
gwbuf_free(csdata->res.data);
|
||||||
|
csdata->res.data = NULL;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user