summaryrefslogtreecommitdiff
path: root/sql/field.h
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2019-02-21 21:44:44 +0400
committerAlexander Barkov <bar@mariadb.com>2019-02-25 12:29:42 +0400
commitb25ad1bc47d2db600ab241d889f9f8f9e775b99d (patch)
tree52de378bed623d6f90cffb3d5d011ba6ee2c3668 /sql/field.h
parent1ab2e7573a378144fc120e97e8218081d17cfa89 (diff)
downloadmariadb-git-b25ad1bc47d2db600ab241d889f9f8f9e775b99d.tar.gz
MDEV-18408 Assertion `0' failed in Item::val_native_result / Timestamp_or_zero_datetime_native_null::Timestamp_or_zero_datetime_native_null upon mysqld_list_fields after crash recovery
The problem happened because Item_ident_for_show did not implement val_native(). Solution: - Removing class Item_ident_for_show - Implementing a new method Protocol::send_list_fields() instead, which accepts a List<Field> instead of List<Item> as input. Now no any Item creation is done during mysqld_list_fields(). Adding helper methods, to reuse the code easier: - Moved a part of Protocol::send_result_set_metadata(), responsible for sending an individual field metadata, into a new method Protocol_text::store_field_metadata(). Reusing it in both send_list_fields() and send_result_set_metadata(). - Adding Protocol_text::store_field_metadata() - Adding Protocol_text::store_field_metadata_for_list_fields() Note, this patch also automatically fixed another bug: MDEV-18685 mysql_list_fields() returns DEFAULT 0 instead of DEFAULT NULL for view columns The reason for this bug was that Item_ident_for_show::val_xxx() and get_date() did not check field->is_null() before calling field->val_xxx()/get_date(). Now the default value is correctly sent by Protocol_text::store(Field*).
Diffstat (limited to 'sql/field.h')
-rw-r--r--sql/field.h77
1 files changed, 77 insertions, 0 deletions
diff --git a/sql/field.h b/sql/field.h
index 97926a356d1..aad96adcd40 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -4958,6 +4958,83 @@ class Send_field :public Sql_alloc {
uint flags, decimals;
enum_field_types type;
Send_field() {}
+ Send_field(Field *field)
+ {
+ field->make_send_field(this);
+ DBUG_ASSERT(table_name != 0);
+ normalize();
+ }
+
+ Send_field(Field *field,
+ const char *db_name_arg,
+ const char *table_name_arg)
+ :db_name(db_name_arg),
+ table_name(table_name_arg),
+ org_table_name(table_name_arg),
+ col_name(field->field_name),
+ org_col_name(field->field_name),
+ length(field->field_length),
+ flags(field->table->maybe_null ?
+ (field->flags & ~NOT_NULL_FLAG) : field->flags),
+ decimals(field->decimals()),
+ type(field->type())
+ {
+ normalize();
+ }
+
+ // This should move to Type_handler eventually
+ static enum_field_types protocol_type_code(enum_field_types type)
+ {
+ /* Keep things compatible for old clients */
+ if (type == MYSQL_TYPE_VARCHAR)
+ return MYSQL_TYPE_VAR_STRING;
+ return type;
+ }
+ void normalize()
+ {
+ /* limit number of decimals for float and double */
+ if (type == MYSQL_TYPE_FLOAT || type == MYSQL_TYPE_DOUBLE)
+ set_if_smaller(decimals, FLOATING_POINT_DECIMALS);
+ /* Keep things compatible for old clients */
+ type= protocol_type_code(type);
+ }
+
+ // This should move to Type_handler eventually
+ uint32 max_char_length(CHARSET_INFO *cs) const
+ {
+ return type >= MYSQL_TYPE_TINY_BLOB && type <= MYSQL_TYPE_BLOB ?
+ length / cs->mbminlen :
+ length / cs->mbmaxlen;
+ }
+ uint32 max_octet_length(CHARSET_INFO *from, CHARSET_INFO *to) const
+ {
+ /*
+ For TEXT/BLOB columns, field_length describes the maximum data
+ length in bytes. There is no limit to the number of characters
+ that a TEXT column can store, as long as the data fits into
+ the designated space.
+ For the rest of textual columns, field_length is evaluated as
+ char_count * mbmaxlen, where character count is taken from the
+ definition of the column. In other words, the maximum number
+ of characters here is limited by the column definition.
+
+ When one has a LONG TEXT column with a single-byte
+ character set, and the connection character set is multi-byte, the
+ client may get fields longer than UINT_MAX32, due to
+ <character set column> -> <character set connection> conversion.
+ In that case column max length would not fit into the 4 bytes
+ reserved for it in the protocol. So we cut it here to UINT_MAX32.
+ */
+ return char_to_byte_length_safe(max_char_length(from), to->mbmaxlen);
+ }
+
+ // This should move to Type_handler eventually
+ bool is_sane() const
+ {
+ return (decimals <= FLOATING_POINT_DECIMALS ||
+ (type != MYSQL_TYPE_FLOAT && type != MYSQL_TYPE_DOUBLE)) &&
+ type != MYSQL_TYPE_VARCHAR;
+ }
};