summaryrefslogtreecommitdiff
path: root/sql/protocol.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/protocol.cc')
-rw-r--r--sql/protocol.cc99
1 files changed, 84 insertions, 15 deletions
diff --git a/sql/protocol.cc b/sql/protocol.cc
index a74f6084df4..c0e30f8d7ee 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1,4 +1,5 @@
-/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -59,6 +60,65 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
}
+/*
+ net_store_data() - extended version with character set conversion.
+
+ It is optimized for short strings whose length after
+ conversion is garanteed to be less than 251, which accupies
+ exactly one byte to store length. It allows not to use
+ the "convert" member as a temporary buffer, conversion
+ is done directly to the "packet" member.
+ The limit 251 is good enough to optimize send_fields()
+ because column, table, database names fit into this limit.
+*/
+
+#ifndef EMBEDDED_LIBRARY
+bool Protocol::net_store_data(const uchar *from, size_t length,
+ CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
+{
+ uint dummy_errors;
+ /* Calculate maxumum possible result length */
+ size_t conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen;
+ ulong packet_length, new_length;
+ char *length_pos, *to;
+
+ if (conv_length > 250)
+ {
+ /*
+ For strings with conv_length greater than 250 bytes
+ we don't know how many bytes we will need to store length: one or two,
+ because we don't know result length until conversion is done.
+ For example, when converting from utf8 (mbmaxlen=3) to latin1,
+ conv_length=300 means that the result length can vary between 100 to 300.
+ length=100 needs one byte, length=300 needs to bytes.
+
+ Thus conversion directly to "packet" is not worthy.
+ Let's use "convert" as a temporary buffer.
+ */
+ return (convert->copy((const char*) from, length, from_cs, to_cs,
+ &dummy_errors) ||
+ net_store_data((const uchar*) convert->ptr(), convert->length()));
+ }
+
+ packet_length= packet->length();
+ new_length= packet_length + conv_length + 1;
+
+ if (new_length > packet->alloced_length() && packet->realloc(new_length))
+ return 1;
+
+ length_pos= (char*) packet->ptr() + packet_length;
+ to= length_pos + 1;
+
+ to+= copy_and_convert(to, conv_length, to_cs,
+ (const char*) from, length, from_cs, &dummy_errors);
+
+ net_store_length((uchar*) length_pos, to - length_pos - 1);
+ packet->length((uint) (to - packet->ptr()));
+ return 0;
+}
+#endif
+
+
/**
Send a error string to client.
@@ -145,7 +205,7 @@ net_send_ok(THD *thd,
NET *net= &thd->net;
uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
bool error= FALSE;
- DBUG_ENTER("my_ok");
+ DBUG_ENTER("net_send_ok");
if (! net->vio) // hack for re-parsing queries
{
@@ -431,6 +491,7 @@ static uchar *net_store_length_fast(uchar *packet, uint length)
void net_end_statement(THD *thd)
{
+ DBUG_ENTER("net_end_statement");
DBUG_ASSERT(! thd->main_da.is_sent);
/* Can not be true, but do not take chances in production. */
@@ -470,6 +531,7 @@ void net_end_statement(THD *thd)
}
if (!error)
thd->main_da.is_sent= TRUE;
+ DBUG_VOID_RETURN;
}
@@ -528,7 +590,8 @@ void Protocol::init(THD *thd_arg)
void Protocol::end_partial_result_set(THD *thd_arg)
{
- net_send_eof(thd_arg, thd_arg->server_status, 0 /* no warnings, we're inside SP */);
+ net_send_eof(thd_arg, thd_arg->server_status,
+ 0 /* no warnings, we're inside SP */);
}
@@ -830,10 +893,10 @@ bool Protocol::store_string_aux(const char *from, size_t length,
fromcs != &my_charset_bin &&
tocs != &my_charset_bin)
{
- uint dummy_errors;
- return (convert->copy(from, length, fromcs, tocs, &dummy_errors) ||
- net_store_data((uchar*) convert->ptr(), convert->length()));
+ /* Store with conversion */
+ return net_store_data((uchar*) from, length, fromcs, tocs);
}
+ /* Store without conversion */
return net_store_data((uchar*) from, length);
}
@@ -1013,12 +1076,16 @@ bool Protocol_text::store(MYSQL_TIME *tm)
#endif
char buff[40];
uint length;
- length= sprintf(buff, "%04d-%02d-%02d %02d:%02d:%02d",
- (int) tm->year, (int) tm->month,
- (int) tm->day, (int) tm->hour,
- (int) tm->minute, (int) tm->second);
+ length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d",
+ (int) tm->year,
+ (int) tm->month,
+ (int) tm->day,
+ (int) tm->hour,
+ (int) tm->minute,
+ (int) tm->second));
if (tm->second_part)
- length+= sprintf(buff+length, ".%06d", (int) tm->second_part);
+ length+= my_sprintf(buff+length,(buff+length, ".%06d",
+ (int)tm->second_part));
return net_store_data((uchar*) buff, length);
}
@@ -1052,11 +1119,13 @@ bool Protocol_text::store_time(MYSQL_TIME *tm)
char buff[40];
uint length;
uint day= (tm->year || tm->month) ? 0 : tm->day;
- length= sprintf(buff, "%s%02ld:%02d:%02d", tm->neg ? "-" : "",
- (long) day*24L+(long) tm->hour, (int) tm->minute,
- (int) tm->second);
+ length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d",
+ tm->neg ? "-" : "",
+ (long) day*24L+(long) tm->hour,
+ (int) tm->minute,
+ (int) tm->second));
if (tm->second_part)
- length+= sprintf(buff+length, ".%06d", (int) tm->second_part);
+ length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part));
return net_store_data((uchar*) buff, length);
}