summaryrefslogtreecommitdiff
path: root/sql-common
diff options
context:
space:
mode:
authorKonstantin Osipov <kostja@sun.com>2009-10-22 00:02:06 +0400
committerKonstantin Osipov <kostja@sun.com>2009-10-22 00:02:06 +0400
commitd4632dff5aea3eacfe3c6a126c6b8ca9c839b5ec (patch)
tree5a3482665c78a3698f529755e2407524f79327d9 /sql-common
parent2b91a639cc767928ca063a466b4058e22f8fb7ff (diff)
downloadmariadb-git-d4632dff5aea3eacfe3c6a126c6b8ca9c839b5ec.tar.gz
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29, 2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and some other minor revisions. This patch implements: WL#4264 "Backup: Stabilize Service Interface" -- all the server prerequisites except si_objects.{h,cc} themselves (they can be just copied over, when needed). WL#4435: Support OUT-parameters in prepared statements. (and all issues in the initial patches for these two tasks, that were discovered in pushbuild and during testing). Bug#39519: mysql_stmt_close() should flush all data associated with the statement. After execution of a prepared statement, send OUT parameters of the invoked stored procedure, if any, to the client. When using the binary protocol, send the parameters in an additional result set over the wire. When using the text protocol, assign out parameters to the user variables from the CALL(@var1, @var2, ...) specification. The following refactoring has been made: - Protocol::send_fields() was renamed to Protocol::send_result_set_metadata(); - A new Protocol::send_result_set_row() was introduced to incapsulate common functionality for sending row data. - Signature of Protocol::prepare_for_send() was changed: this operation does not need a list of items, the number of items is fully sufficient. The following backward incompatible changes have been made: - CLIENT_MULTI_RESULTS is now enabled by default in the client; - CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
Diffstat (limited to 'sql-common')
-rw-r--r--sql-common/client.c137
1 files changed, 121 insertions, 16 deletions
diff --git a/sql-common/client.c b/sql-common/client.c
index 8ebd38178fa..fbc85ee2161 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -710,10 +710,14 @@ err:
}
#endif
-/*****************************************************************************
+/**
Read a packet from server. Give error message if socket was down
or packet is an error message
-*****************************************************************************/
+
+ @retval packet_error An error occurred during reading.
+ Error message is set.
+ @retval
+*/
ulong
cli_safe_read(MYSQL *mysql)
@@ -879,31 +883,132 @@ void free_old_query(MYSQL *mysql)
DBUG_VOID_RETURN;
}
+
+/**
+ Finish reading of a partial result set from the server.
+ Get the EOF packet, and update mysql->status
+ and mysql->warning_count.
+
+ @return TRUE if a communication or protocol error, an error
+ is set in this case, FALSE otherwise.
+*/
+
+my_bool flush_one_result(MYSQL *mysql)
+{
+ ulong packet_length;
+
+ DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY);
+
+ do
+ {
+ packet_length= cli_safe_read(mysql);
+ /*
+ There is an error reading from the connection,
+ or (sic!) there were no error and no
+ data in the stream, i.e. no more data from the server.
+ Since we know our position in the stream (somewhere in
+ the middle of a result set), this latter case is an error too
+ -- each result set must end with a EOF packet.
+ cli_safe_read() has set an error for us, just return.
+ */
+ if (packet_length == packet_error)
+ return TRUE;
+ }
+ while (packet_length > 8 || mysql->net.read_pos[0] != 254);
+
+ /* Analyze EOF packet of the result set. */
+
+ if (protocol_41(mysql))
+ {
+ char *pos= (char*) mysql->net.read_pos + 1;
+ mysql->warning_count=uint2korr(pos);
+ pos+=2;
+ mysql->server_status=uint2korr(pos);
+ pos+=2;
+ }
+ return FALSE;
+}
+
+
+/**
+ Read a packet from network. If it's an OK packet, flush it.
+
+ @return TRUE if error, FALSE otherwise. In case of
+ success, is_ok_packet is set to TRUE or FALSE,
+ based on what we got from network.
+*/
+
+my_bool opt_flush_ok_packet(MYSQL *mysql, my_bool *is_ok_packet)
+{
+ ulong packet_length= cli_safe_read(mysql);
+
+ if (packet_length == packet_error)
+ return TRUE;
+
+ /* cli_safe_read always reads a non-empty packet. */
+ DBUG_ASSERT(packet_length);
+
+ *is_ok_packet= mysql->net.read_pos[0] == 0;
+ if (*is_ok_packet)
+ {
+ uchar *pos= mysql->net.read_pos + 1;
+
+ net_field_length_ll(&pos); /* affected rows */
+ net_field_length_ll(&pos); /* insert id */
+
+ mysql->server_status=uint2korr(pos);
+ pos+=2;
+
+ if (protocol_41(mysql))
+ {
+ mysql->warning_count=uint2korr(pos);
+ pos+=2;
+ }
+ }
+ return FALSE;
+}
+
+
/*
Flush result set sent from server
*/
-static void cli_flush_use_result(MYSQL *mysql)
+static void cli_flush_use_result(MYSQL *mysql, my_bool flush_all_results)
{
/* Clear the current execution status */
DBUG_ENTER("cli_flush_use_result");
DBUG_PRINT("warning",("Not all packets read, clearing them"));
- for (;;)
+
+ if (flush_one_result(mysql))
+ DBUG_VOID_RETURN; /* An error occurred */
+
+ if (! flush_all_results)
+ DBUG_VOID_RETURN;
+
+ while (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
{
- ulong pkt_len;
- if ((pkt_len=cli_safe_read(mysql)) == packet_error)
- break;
- if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
+ my_bool is_ok_packet;
+ if (opt_flush_ok_packet(mysql, &is_ok_packet))
+ DBUG_VOID_RETURN; /* An error occurred. */
+ if (is_ok_packet)
{
- if (protocol_41(mysql))
- {
- char *pos= (char*) mysql->net.read_pos + 1;
- mysql->warning_count=uint2korr(pos); pos+=2;
- mysql->server_status=uint2korr(pos); pos+=2;
- }
- break; /* End of data */
+ /*
+ Indeed what we got from network was an OK packet, and we
+ know that OK is the last one in a multi-result-set, so
+ just return.
+ */
+ DBUG_VOID_RETURN;
}
+ /*
+ It's a result set, not an OK packet. A result set contains
+ of two result set subsequences: field metadata, terminated
+ with EOF packet, and result set data, again terminated with
+ EOF packet. Read and flush them.
+ */
+ if (flush_one_result(mysql) || flush_one_result(mysql))
+ DBUG_VOID_RETURN; /* An error occurred. */
}
+
DBUG_VOID_RETURN;
}
@@ -1009,7 +1114,7 @@ mysql_free_result(MYSQL_RES *result)
mysql->unbuffered_fetch_owner= 0;
if (mysql->status == MYSQL_STATUS_USE_RESULT)
{
- (*mysql->methods->flush_use_result)(mysql);
+ (*mysql->methods->flush_use_result)(mysql, FALSE);
mysql->status=MYSQL_STATUS_READY;
if (mysql->unbuffered_fetch_owner)
*mysql->unbuffered_fetch_owner= TRUE;