diff options
Diffstat (limited to 'sql/protocol.cc')
-rw-r--r-- | sql/protocol.cc | 101 |
1 files changed, 74 insertions, 27 deletions
diff --git a/sql/protocol.cc b/sql/protocol.cc index 9242b348f0b..a0e14423b73 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. 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 @@ -58,6 +58,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. @@ -144,7 +203,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 { @@ -282,24 +341,6 @@ static bool write_eof_packet(THD *thd, NET *net, } /** - Please client to send scrambled_password in old format. - - @param thd thread handle - - @retval - 0 ok - @retval - !0 error -*/ - -bool send_old_password_request(THD *thd) -{ - NET *net= &thd->net; - return my_net_write(net, eof_buff, 1) || net_flush(net); -} - - -/** @param thd Thread handler @param sql_errno The error code to send @param err A pointer to the error message @@ -430,6 +471,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. */ @@ -469,6 +511,7 @@ void net_end_statement(THD *thd) } if (!error) thd->main_da.is_sent= TRUE; + DBUG_VOID_RETURN; } @@ -527,7 +570,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 */); } @@ -573,7 +617,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) Protocol_text prot(thd); String *local_packet= prot.storage_packet(); CHARSET_INFO *thd_charset= thd->variables.character_set_results; - DBUG_ENTER("send_fields"); + DBUG_ENTER("Protocol::send_fields"); if (flags & SEND_NUM_ROWS) { // Packet with number of elements @@ -588,6 +632,9 @@ bool Protocol::send_fields(List<Item> *list, uint flags) uint count= 0; #endif + /* We have to reallocate it here as a stored procedure may have reset it */ + (void) local_packet->alloc(thd->variables.net_buffer_length); + while ((item=it++)) { char *pos; @@ -827,10 +874,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); } @@ -856,8 +903,8 @@ bool Protocol_text::store(const char *from, size_t length, { CHARSET_INFO *tocs= this->thd->variables.character_set_results; #ifndef DBUG_OFF - DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %s", field_pos, - field_count, (length == 0? "" : from))); + DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %.*s", field_pos, + field_count, (int) length, (length == 0? "" : from))); DBUG_ASSERT(field_pos < field_count); DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || |