diff options
Diffstat (limited to 'sql/protocol.cc')
-rw-r--r-- | sql/protocol.cc | 243 |
1 files changed, 151 insertions, 92 deletions
diff --git a/sql/protocol.cc b/sql/protocol.cc index eb7f19d2bd0..eb50b02cf3c 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -32,17 +32,16 @@ #include <stdarg.h> static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; -/* Declared non-static only because of the embedded library. */ -bool net_send_error_packet(THD *, uint, const char *, const char *); -/* Declared non-static only because of the embedded library. */ -bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *, - bool, bool); -/* Declared non-static only because of the embedded library. */ -bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count); #ifndef EMBEDDED_LIBRARY static bool write_eof_packet(THD *, NET *, uint, uint); #endif +CHARSET_INFO *Protocol::character_set_results() const +{ + return thd->variables.character_set_results; +} + + #ifndef EMBEDDED_LIBRARY bool Protocol::net_store_data(const uchar *from, size_t length) #else @@ -147,11 +146,11 @@ bool Protocol_binary::net_store_data_cs(const uchar *from, size_t length, @retval TRUE An error occurred and the message wasn't sent properly */ -bool net_send_error(THD *thd, uint sql_errno, const char *err, - const char* sqlstate) +bool Protocol::net_send_error(THD *thd, uint sql_errno, const char *err, + const char* sqlstate) { bool error; - DBUG_ENTER("net_send_error"); + DBUG_ENTER("Protocol::net_send_error"); DBUG_ASSERT(!thd->spcont); DBUG_ASSERT(sql_errno); @@ -209,11 +208,11 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err, #ifndef EMBEDDED_LIBRARY bool -net_send_ok(THD *thd, - uint server_status, uint statement_warn_count, - ulonglong affected_rows, ulonglong id, const char *message, - bool is_eof, - bool skip_flush) +Protocol::net_send_ok(THD *thd, + uint server_status, uint statement_warn_count, + ulonglong affected_rows, ulonglong id, + const char *message, bool is_eof, + bool skip_flush) { NET *net= &thd->net; StringBuffer<MYSQL_ERRMSG_SIZE + 10> store; @@ -221,7 +220,7 @@ net_send_ok(THD *thd, bool state_changed= false; bool error= FALSE; - DBUG_ENTER("net_send_ok"); + DBUG_ENTER("Protocol::net_send_ok"); if (! net->vio) // hack for re-parsing queries { @@ -324,11 +323,11 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ */ bool -net_send_eof(THD *thd, uint server_status, uint statement_warn_count) +Protocol::net_send_eof(THD *thd, uint server_status, uint statement_warn_count) { NET *net= &thd->net; bool error= FALSE; - DBUG_ENTER("net_send_eof"); + DBUG_ENTER("Protocol::net_send_eof"); /* Check if client understand new format packets (OK instead of EOF) @@ -415,8 +414,8 @@ static bool write_eof_packet(THD *thd, NET *net, @retval TRUE An error occurred and the messages wasn't sent properly */ -bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, - const char* sqlstate) +bool Protocol::net_send_error_packet(THD *thd, uint sql_errno, const char *err, + const char* sqlstate) { NET *net= &thd->net; @@ -429,7 +428,7 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, char buff[2+1+SQLSTATE_LENGTH+MYSQL_ERRMSG_SIZE], *pos; my_bool ret; uint8 save_compress; - DBUG_ENTER("send_error_packet"); + DBUG_ENTER("Protocol::send_error_packet"); if (net->vio == 0) { @@ -599,6 +598,7 @@ void Protocol::end_statement() thd->get_stmt_da()->get_sqlstate()); break; case Diagnostics_area::DA_EOF: + case Diagnostics_area::DA_EOF_BULK: error= send_eof(thd->server_status, thd->get_stmt_da()->statement_warn_count()); break; @@ -770,6 +770,7 @@ void Protocol::init(THD *thd_arg) convert= &thd->convert_buffer; #ifndef DBUG_OFF field_handlers= 0; + field_pos= 0; #endif } @@ -801,6 +802,41 @@ bool Protocol::flush() #ifndef EMBEDDED_LIBRARY + +class Send_field_packed_extended_metadata: public Binary_string +{ +public: + bool append_chunk(mariadb_field_attr_t type, const LEX_CSTRING &value) + { + /* + If we eventually support many metadata chunk types and long metadata + values, we'll need to encode type and length using net_store_length() + and do corresponding changes to the unpacking code in libmariadb. + For now let's just assert that type and length fit into one byte. + */ + DBUG_ASSERT(net_length_size(type) == 1); + DBUG_ASSERT(net_length_size(value.length) == 1); + size_t nbytes= 1/*type*/ + 1/*length*/ + value.length; + if (reserve(nbytes)) + return true; + qs_append((char) (uchar) type); + qs_append((char) (uchar) value.length); + qs_append(&value); + return false; + } + bool pack(const Send_field_extended_metadata &src) + { + for (uint i= 0 ; i <= MARIADB_FIELD_ATTR_LAST; i++) + { + const LEX_CSTRING attr= src.attr(i); + if (attr.str && append_chunk((mariadb_field_attr_t) i, attr)) + return true; + } + return false; + } +}; + + bool Protocol_text::store_field_metadata(const THD * thd, const Send_field &field, CHARSET_INFO *charset_for_protocol, @@ -808,18 +844,31 @@ bool Protocol_text::store_field_metadata(const THD * thd, { CHARSET_INFO *thd_charset= thd->variables.character_set_results; char *pos; - CHARSET_INFO *cs= system_charset_info; DBUG_ASSERT(field.is_sane()); if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (store(STRING_WITH_LEN("def"), cs, thd_charset) || - store_str(field.db_name, cs, thd_charset) || - store_str(field.table_name, cs, thd_charset) || - store_str(field.org_table_name, cs, thd_charset) || - store_str(field.col_name, cs, thd_charset) || - store_str(field.org_col_name, cs, thd_charset) || - packet->realloc(packet->length() + 12)) + const LEX_CSTRING def= {STRING_WITH_LEN("def")}; + if (store_ident(def) || + store_ident(field.db_name) || + store_ident(field.table_name) || + store_ident(field.org_table_name) || + store_ident(field.col_name) || + store_ident(field.org_col_name)) + return true; + if (thd->client_capabilities & MARIADB_CLIENT_EXTENDED_METADATA) + { + Send_field_packed_extended_metadata metadata; + metadata.pack(field); + + /* + Don't apply character set conversion: + extended metadata is a binary encoded data. + */ + if (store_binary_string(metadata.ptr(), metadata.length())) + return true; + } + if (packet->realloc(packet->length() + 12)) return true; /* Store fixed length fields */ pos= (char*) packet->end(); @@ -849,8 +898,8 @@ bool Protocol_text::store_field_metadata(const THD * thd, } else { - if (store_str(field.table_name, cs, thd_charset) || - store_str(field.col_name, cs, thd_charset) || + if (store_ident(field.table_name) || + store_ident(field.col_name) || packet->realloc(packet->length() + 10)) return true; pos= (char*) packet->end(); @@ -910,7 +959,7 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags) for (uint pos= 0; (item=it++); pos++) { prot.prepare_for_resend(); - if (prot.store_field_metadata(thd, item, pos)) + if (prot.store_item_metadata(thd, item, pos)) goto err; if (prot.write()) DBUG_RETURN(1); @@ -990,7 +1039,7 @@ bool Protocol::write() #endif /* EMBEDDED_LIBRARY */ -bool Protocol_text::store_field_metadata(THD *thd, Item *item, uint pos) +bool Protocol_text::store_item_metadata(THD *thd, Item *item, uint pos) { Send_field field(thd, item); return store_field_metadata(thd, field, item->charset_for_protocol(), pos); @@ -1003,7 +1052,7 @@ bool Protocol_text::store_field_metadata_for_list_fields(const THD *thd, uint pos) { Send_field field= tl->view ? - Send_field(fld, tl->view_db.str, tl->view_name.str) : + Send_field(fld, tl->view_db, tl->view_name) : Send_field(fld); return store_field_metadata(thd, field, fld->charset_for_protocol(), pos); } @@ -1133,9 +1182,7 @@ bool Protocol::store_string_aux(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { /* 'tocs' is set 0 when client issues SET character_set_results=NULL */ - if (tocs && !my_charset_same(fromcs, tocs) && - fromcs != &my_charset_bin && - tocs != &my_charset_bin) + if (needs_conversion(fromcs, tocs)) { /* Store with conversion */ return net_store_data_cs((uchar*) from, length, fromcs, tocs); @@ -1145,10 +1192,35 @@ bool Protocol::store_string_aux(const char *from, size_t length, } -bool Protocol_text::store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs) +bool Protocol_text::store_numeric_string_aux(const char *from, size_t length) +{ + CHARSET_INFO *tocs= thd->variables.character_set_results; + // 'tocs' is NULL when the client issues SET character_set_results=NULL + if (tocs && (tocs->state & MY_CS_NONASCII)) // Conversion needed + return net_store_data_cs((uchar*) from, length, &my_charset_latin1, tocs); + return net_store_data((uchar*) from, length); // No conversion +} + + +bool Protocol::store_warning(const char *from, size_t length) +{ + BinaryStringBuffer<MYSQL_ERRMSG_SIZE> tmp; + CHARSET_INFO *cs= thd->variables.character_set_results; + if (!cs || cs == &my_charset_bin) + cs= system_charset_info; + if (tmp.copy_printable_hhhh(cs, system_charset_info, from, length)) + return net_store_data((const uchar*)"", 0); + return net_store_data((const uchar *) tmp.ptr(), tmp.length()); +} + + +bool Protocol_text::store_str(const char *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { #ifndef DBUG_OFF + DBUG_PRINT("info", ("Protocol_text::store field %u : %.*b", field_pos, + (int) length, (length == 0 ? "" : from))); + DBUG_ASSERT(field_handlers == 0 || field_pos < field_count); DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_STRING)); field_pos++; #endif @@ -1156,18 +1228,19 @@ bool Protocol_text::store(const char *from, size_t length, } -bool Protocol_text::store(const char *from, size_t length, - CHARSET_INFO *fromcs) +bool Protocol_text::store_numeric_zerofill_str(const char *from, + size_t length, + protocol_send_type_t send_type) { - 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, (int) length, (length == 0 ? "" : from))); + DBUG_PRINT("info", + ("Protocol_text::store_numeric_zerofill_str field %u : %.*b", + field_pos, (int) length, (length == 0 ? "" : from))); DBUG_ASSERT(field_handlers == 0 || field_pos < field_count); - DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_STRING)); + DBUG_ASSERT(valid_handler(field_pos, send_type)); field_pos++; #endif - return store_string_aux(from, length, fromcs, tocs); + return store_numeric_string_aux(from, length); } @@ -1178,8 +1251,8 @@ bool Protocol_text::store_tiny(longlong from) field_pos++; #endif char buff[22]; - return net_store_data((uchar*) buff, - (size_t) (int10_to_str((int) from, buff, -10) - buff)); + size_t length= (size_t) (int10_to_str((int) from, buff, -10) - buff); + return store_numeric_string_aux(buff, length); } @@ -1190,9 +1263,8 @@ bool Protocol_text::store_short(longlong from) field_pos++; #endif char buff[22]; - return net_store_data((uchar*) buff, - (size_t) (int10_to_str((int) from, buff, -10) - - buff)); + size_t length= (size_t) (int10_to_str((int) from, buff, -10) - buff); + return store_numeric_string_aux(buff, length); } @@ -1203,9 +1275,9 @@ bool Protocol_text::store_long(longlong from) field_pos++; #endif char buff[22]; - return net_store_data((uchar*) buff, - (size_t) (int10_to_str((long int)from, buff, - (from <0)?-10:10)-buff)); + size_t length= (size_t) (int10_to_str((long int)from, buff, + (from < 0) ? - 10 : 10) - buff); + return store_numeric_string_aux(buff, length); } @@ -1216,10 +1288,10 @@ bool Protocol_text::store_longlong(longlong from, bool unsigned_flag) field_pos++; #endif char buff[22]; - return net_store_data((uchar*) buff, - (size_t) (longlong10_to_str(from,buff, - unsigned_flag ? 10 : -10)- - buff)); + size_t length= (size_t) (longlong10_to_str(from, buff, + unsigned_flag ? 10 : -10) - + buff); + return store_numeric_string_aux(buff, length); } @@ -1231,29 +1303,29 @@ bool Protocol_text::store_decimal(const my_decimal *d) #endif StringBuffer<DECIMAL_MAX_STR_LENGTH> str; (void) d->to_string(&str); - return net_store_data((uchar*) str.ptr(), str.length()); + return store_numeric_string_aux(str.ptr(), str.length()); } -bool Protocol_text::store(float from, uint32 decimals, String *buffer) +bool Protocol_text::store_float(float from, uint32 decimals) { #ifndef DBUG_OFF DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_FLOAT)); field_pos++; #endif - Float(from).to_string(buffer, decimals); - return net_store_data((uchar*) buffer->ptr(), buffer->length()); + Float(from).to_string(&buffer, decimals); + return store_numeric_string_aux(buffer.ptr(), buffer.length()); } -bool Protocol_text::store(double from, uint32 decimals, String *buffer) +bool Protocol_text::store_double(double from, uint32 decimals) { #ifndef DBUG_OFF DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_DOUBLE)); field_pos++; #endif - buffer->set_real(from, decimals, thd->charset()); - return net_store_data((uchar*) buffer->ptr(), buffer->length()); + buffer.set_real(from, decimals, thd->charset()); + return store_numeric_string_aux(buffer.ptr(), buffer.length()); } @@ -1261,12 +1333,6 @@ bool Protocol_text::store(Field *field) { if (field->is_null()) return store_null(); -#ifndef DBUG_OFF - field_pos++; -#endif - char buff[MAX_FIELD_WIDTH]; - String str(buff,sizeof(buff), &my_charset_bin); - CHARSET_INFO *tocs= this->thd->variables.character_set_results; #ifdef DBUG_ASSERT_EXISTS TABLE *table= field->table; MY_BITMAP *old_map= 0; @@ -1274,13 +1340,14 @@ bool Protocol_text::store(Field *field) old_map= dbug_tmp_use_all_columns(table, &table->read_set); #endif - field->val_str(&str); + bool rc= field->send(this); + #ifdef DBUG_ASSERT_EXISTS if (old_map) dbug_tmp_restore_column_map(&table->read_set, old_map); #endif - return store_string_aux(str.ptr(), str.length(), str.charset(), tocs); + return rc; } @@ -1292,7 +1359,7 @@ bool Protocol_text::store(MYSQL_TIME *tm, int decimals) #endif char buff[MAX_DATE_STRING_REP_LENGTH]; uint length= my_datetime_to_str(tm, buff, decimals); - return net_store_data((uchar*) buff, length); + return store_numeric_string_aux(buff, length); } @@ -1304,7 +1371,7 @@ bool Protocol_text::store_date(MYSQL_TIME *tm) #endif char buff[MAX_DATE_STRING_REP_LENGTH]; size_t length= my_date_to_str(tm, buff); - return net_store_data((uchar*) buff, length); + return store_numeric_string_aux(buff, length); } @@ -1316,7 +1383,7 @@ bool Protocol_text::store_time(MYSQL_TIME *tm, int decimals) #endif char buff[MAX_DATE_STRING_REP_LENGTH]; uint length= my_time_to_str(tm, buff, decimals); - return net_store_data((uchar*) buff, length); + return store_numeric_string_aux(buff, length); } /** @@ -1398,16 +1465,8 @@ void Protocol_binary::prepare_for_resend() } -bool Protocol_binary::store(const char *from, size_t length, - CHARSET_INFO *fromcs) -{ - CHARSET_INFO *tocs= thd->variables.character_set_results; - field_pos++; - return store_string_aux(from, length, fromcs, tocs); -} - -bool Protocol_binary::store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs) +bool Protocol_binary::store_str(const char *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { field_pos++; return store_string_aux(from, length, fromcs, tocs); @@ -1469,14 +1528,14 @@ bool Protocol_binary::store_decimal(const my_decimal *d) { #ifndef DBUG_OFF DBUG_ASSERT(0); // This method is not used yet - field_pos++; #endif StringBuffer<DECIMAL_MAX_STR_LENGTH> str; (void) d->to_string(&str); - return store(str.ptr(), str.length(), str.charset()); + return store_str(str.ptr(), str.length(), str.charset(), + thd->variables.character_set_results); } -bool Protocol_binary::store(float from, uint32 decimals, String *buffer) +bool Protocol_binary::store_float(float from, uint32 decimals) { field_pos++; char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC); @@ -1487,7 +1546,7 @@ bool Protocol_binary::store(float from, uint32 decimals, String *buffer) } -bool Protocol_binary::store(double from, uint32 decimals, String *buffer) +bool Protocol_binary::store_double(double from, uint32 decimals) { field_pos++; char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC); @@ -1501,12 +1560,12 @@ bool Protocol_binary::store(double from, uint32 decimals, String *buffer) bool Protocol_binary::store(Field *field) { /* - We should not increment field_pos here as send_binary() will call another + We should not increment field_pos here as send() will call another protocol function to do this for us */ if (field->is_null()) return store_null(); - return field->send_binary(this); + return field->send(this); } |