diff options
35 files changed, 894 insertions, 9 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index dfa805fc7e8..0f63f58e5da 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -44,7 +44,9 @@ IF(UNIX) SET_TARGET_PROPERTIES(mysql PROPERTIES ENABLE_EXPORTS TRUE) ENDIF(UNIX) -MYSQL_ADD_EXECUTABLE(mysqltest mysqltest.cc COMPONENT Test) +MYSQL_ADD_EXECUTABLE(mysqltest mysqltest.cc + ${CMAKE_SOURCE_DIR}/sql/sql_string.cc + COMPONENT Test) SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS ${PCRE2_DEBIAN_HACK}") TARGET_LINK_LIBRARIES(mysqltest ${CLIENT_LIB} pcre2-posix pcre2-8) SET_TARGET_PROPERTIES(mysqltest PROPERTIES ENABLE_EXPORTS TRUE) diff --git a/client/client_metadata.h b/client/client_metadata.h new file mode 100644 index 00000000000..49921f01885 --- /dev/null +++ b/client/client_metadata.h @@ -0,0 +1,57 @@ +#ifndef SQL_CLIENT_METADATA_INCLUDED +#define SQL_CLIENT_METADATA_INCLUDED +/* + Copyright (c) 2020, MariaDB Corporation. + + 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include "sql_string.h" + + +/* + Print MYSQL_FIELD metadata in human readable format +*/ +class Client_field_metadata +{ + const MYSQL_FIELD *m_field; +public: + Client_field_metadata(MYSQL_FIELD *field) + :m_field(field) + { } + void print_attr(Binary_string *to, + const LEX_CSTRING &name, + mariadb_field_attr_t attr, + uint orig_to_length) const + { + MARIADB_CONST_STRING tmp; + if (!mariadb_field_attr(&tmp, m_field, attr) && tmp.length) + { + if (to->length() != orig_to_length) + to->append(" ", 1); + to->append(name); + to->append(tmp.str, tmp.length); + } + } + void print_data_type_related_attributes(Binary_string *to) const + { + static const LEX_CSTRING type= {C_STRING_WITH_LEN("type=")}; + static const LEX_CSTRING format= {C_STRING_WITH_LEN("format=")}; + uint to_length_orig= to->length(); + print_attr(to, type, MARIADB_FIELD_ATTR_DATA_TYPE_NAME, to_length_orig); + print_attr(to, format, MARIADB_FIELD_ATTR_FORMAT_NAME, to_length_orig); + } +}; + + +#endif // SQL_CLIENT_METADATA_INCLUDED diff --git a/client/mysql.cc b/client/mysql.cc index 2c7f0a500b9..c30139cd96b 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -58,6 +58,7 @@ static char *server_version= NULL; #define MAX_SERVER_ARGS 64 #include "sql_string.h" +#include "client_metadata.h" extern "C" { #if defined(HAVE_CURSES_H) && defined(HAVE_TERM_H) @@ -3513,12 +3514,15 @@ print_field_types(MYSQL_RES *result) while ((field = mysql_fetch_field(result))) { + Client_field_metadata metadata(field); + BinaryStringBuffer<128> data_type_metadata_str; + metadata.print_data_type_related_attributes(&data_type_metadata_str); tee_fprintf(PAGER, "Field %3u: `%s`\n" "Catalog: `%s`\n" "Database: `%s`\n" "Table: `%s`\n" "Org_table: `%s`\n" - "Type: %s\n" + "Type: %s%s%.*s%s\n" "Collation: %s (%u)\n" "Length: %lu\n" "Max_length: %lu\n" @@ -3527,6 +3531,9 @@ print_field_types(MYSQL_RES *result) ++i, field->name, field->catalog, field->db, field->table, field->org_table, fieldtype2str(field->type), + data_type_metadata_str.length() ? " (" : "", + data_type_metadata_str.length(), data_type_metadata_str.ptr(), + data_type_metadata_str.length() ? ")" : "", get_charset_name(field->charsetnr), field->charsetnr, field->length, field->max_length, field->decimals, fieldflags2str(field->flags)); diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 148a492a648..910db0f714e 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -40,6 +40,7 @@ #include <mysqld_error.h> #include <sql_common.h> #include <m_ctype.h> +#include "client_metadata.h" #include <my_dir.h> #include <hash.h> #include <stdarg.h> @@ -7709,6 +7710,17 @@ void append_metadata(DYNAMIC_STRING *ds, dynstr_append_mem(ds, field->name, field->name_length); dynstr_append_mem(ds, "\t", 1); replace_dynstr_append_uint(ds, field->type); + + Client_field_metadata metadata(field); + BinaryStringBuffer<128> data_type_metadata_str; + metadata.print_data_type_related_attributes(&data_type_metadata_str); + if (data_type_metadata_str.length()) + { + dynstr_append_mem(ds, " (", 2); + dynstr_append_mem(ds, data_type_metadata_str.ptr(), + data_type_metadata_str.length()); + dynstr_append_mem(ds, ")", 1); + } dynstr_append_mem(ds, "\t", 1); replace_dynstr_append_uint(ds, field->length); dynstr_append_mem(ds, "\t", 1); diff --git a/include/mysql.h b/include/mysql.h index ec49ca0482a..6ff4c6d3fad 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -97,6 +97,9 @@ extern char *mysql_unix_port; #define IS_LONGDATA(t) ((t) >= MYSQL_TYPE_TINY_BLOB && (t) <= MYSQL_TYPE_STRING) +typedef struct st_mysql_const_lex_string MARIADB_CONST_STRING; + + typedef struct st_mysql_field { char *name; /* Name of column */ char *org_name; /* Original column name, if an alias */ @@ -411,6 +414,14 @@ MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res); MYSQL_ROW_OFFSET STDCALL mysql_row_tell(MYSQL_RES *res); MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res); + + + +int STDCALL mariadb_field_attr(MARIADB_CONST_STRING *attr, + const MYSQL_FIELD *field, + enum mariadb_field_attr_t type); + + unsigned int STDCALL mysql_field_count(MYSQL *mysql); my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql); my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql); diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 4fcfab4aea4..705bf7e712c 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -28,6 +28,11 @@ enum enum_indicator_type STMT_INDICATOR_DEFAULT, STMT_INDICATOR_IGNORE }; +enum mariadb_field_attr_t +{ + MARIADB_FIELD_ATTR_DATA_TYPE_NAME= 0, + MARIADB_FIELD_ATTR_FORMAT_NAME= 1 +}; struct st_vio; typedef struct st_vio Vio; typedef struct st_net { @@ -207,6 +212,7 @@ extern int list_walk(LIST *,list_walk_action action,unsigned char * argument); extern unsigned int mariadb_deinitialize_ssl; extern unsigned int mysql_port; extern char *mysql_unix_port; +typedef struct st_mysql_const_lex_string MARIADB_CONST_STRING; typedef struct st_mysql_field { char *name; char *org_name; @@ -436,6 +442,9 @@ MYSQL_FIELD * mysql_fetch_field_direct(MYSQL_RES *res, MYSQL_FIELD * mysql_fetch_fields(MYSQL_RES *res); MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *res); MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *res); +int mariadb_field_attr(MARIADB_CONST_STRING *attr, + const MYSQL_FIELD *field, + enum mariadb_field_attr_t type); unsigned int mysql_field_count(MYSQL *mysql); my_ulonglong mysql_affected_rows(MYSQL *mysql); my_ulonglong mysql_insert_id(MYSQL *mysql); diff --git a/include/mysql_com.h b/include/mysql_com.h index cc89f014f8e..2bfacdeec20 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -298,6 +298,8 @@ enum enum_indicator_type #define MARIADB_CLIENT_COM_MULTI (1ULL << 33) /* support of array binding */ #define MARIADB_CLIENT_STMT_BULK_OPERATIONS (1ULL << 34) +/* support of extended metadata (e.g. type/format information) */ +#define MARIADB_CLIENT_EXTENDED_METADATA (1ULL << 35) #ifdef HAVE_COMPRESS #define CAN_CLIENT_COMPRESS CLIENT_COMPRESS @@ -339,6 +341,7 @@ enum enum_indicator_type CLIENT_CONNECT_ATTRS |\ MARIADB_CLIENT_COM_MULTI |\ MARIADB_CLIENT_STMT_BULK_OPERATIONS |\ + MARIADB_CLIENT_EXTENDED_METADATA|\ CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS) /* @@ -350,6 +353,15 @@ enum enum_indicator_type & ~CLIENT_COMPRESS) \ & ~CLIENT_SSL_VERIFY_SERVER_CERT) +enum mariadb_field_attr_t +{ + MARIADB_FIELD_ATTR_DATA_TYPE_NAME= 0, + MARIADB_FIELD_ATTR_FORMAT_NAME= 1 +}; + +#define MARIADB_FIELD_ATTR_LAST MARIADB_FIELD_ATTR_FORMAT_NAME + + /** Is raised when a multi-statement transaction has been started, either explicitly, by means diff --git a/libmariadb b/libmariadb -Subproject 8e9c3116105d9a998a60991b7f4ba910d454d4b +Subproject b7047003c5b460f16b901359c68cbe670e52cf0 diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index f9eba7d7713..ae54fb4ef5f 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -424,9 +424,15 @@ mysql_net_field_length mysql_options4 ) + +SET(CLIENT_API_FUNCTIONS_10_5 +mariadb_field_attr +) + SET(CLIENT_API_FUNCTIONS ${CLIENT_API_FUNCTIONS_5_1} ${CLIENT_API_FUNCTIONS_5_5} + ${CLIENT_API_FUNCTIONS_10_5} ) diff --git a/libmysqld/emb_qcache.cc b/libmysqld/emb_qcache.cc index 603542e820e..fb623f91458 100644 --- a/libmysqld/emb_qcache.cc +++ b/libmysqld/emb_qcache.cc @@ -445,6 +445,7 @@ int emb_load_querycache_result(THD *thd, Querycache_stream *src) !(field->catalog= src->load_str(f_alloc, &field->catalog_length)) || src->load_safe_str(f_alloc, &field->def, &field->def_length)) goto err; + field->extension= NULL; } data->rows= rows; diff --git a/libmysqld/embedded_priv.h b/libmysqld/embedded_priv.h index 77955ea499e..af80f5bc6a9 100644 --- a/libmysqld/embedded_priv.h +++ b/libmysqld/embedded_priv.h @@ -38,4 +38,11 @@ typedef struct embedded_query_result char sqlstate[SQLSTATE_LENGTH+1]; } EQR; + +typedef struct st_mariadb_field_extension +{ + MARIADB_CONST_STRING metadata[MARIADB_FIELD_ATTR_LAST+1]; /* 10.5 */ +} MARIADB_FIELD_EXTENSION; + + C_MODE_END diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 8b25515405c..c6a7486e399 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -1032,6 +1032,39 @@ void Protocol_text::remove_last_row() } + +static MARIADB_CONST_STRING ma_const_string_copy_root(MEM_ROOT *memroot, + const char *str, + size_t length) +{ + MARIADB_CONST_STRING res; + if (!str || !(res.str= strmake_root(memroot, str, length))) + return null_clex_str; + res.length= length; + return res; +} + + +class Client_field_extension: public Sql_alloc, + public MARIADB_FIELD_EXTENSION +{ +public: + Client_field_extension() + { + memset(this, 0, sizeof(*this)); + } + void copy_extended_metadata(MEM_ROOT *memroot, + const Send_field_extended_metadata &src) + { + for (uint i= 0; i <= MARIADB_FIELD_ATTR_LAST; i++) + { + LEX_CSTRING attr= src.attr(i); + metadata[i]= ma_const_string_copy_root(memroot, attr.str, attr.length); + } + } +}; + + bool Protocol_text::store_field_metadata(const THD * thd, const Send_field &server_field, CHARSET_INFO *charset_for_protocol, @@ -1080,6 +1113,17 @@ bool Protocol_text::store_field_metadata(const THD * thd, client_field->catalog= dup_str_aux(field_alloc, "def", 3, cs, thd_cs); client_field->catalog_length= 3; + if (server_field.has_extended_metadata()) + { + Client_field_extension *ext= new (field_alloc) Client_field_extension(); + if ((client_field->extension= static_cast<MARIADB_FIELD_EXTENSION*>(ext))) + ext->copy_extended_metadata(field_alloc, server_field); + } + else + { + client_field->extension= NULL; + } + if (IS_NUM(client_field->type)) client_field->flags|= NUM_FLAG; diff --git a/libmysqld/libmysql.c b/libmysqld/libmysql.c index 2be94882303..8ede487e413 100644 --- a/libmysqld/libmysql.c +++ b/libmysqld/libmysql.c @@ -64,6 +64,7 @@ #include <sql_common.h> #include "client_settings.h" +#include "embedded_priv.h" #undef net_buffer_length #undef max_allowed_packet @@ -733,6 +734,26 @@ mysql_fetch_field(MYSQL_RES *result) /************************************************************************** +** Return mysql field metadata +**************************************************************************/ +int STDCALL +mariadb_field_attr(MARIADB_CONST_STRING *attr, + const MYSQL_FIELD *field, + enum mariadb_field_attr_t type) +{ + MARIADB_FIELD_EXTENSION *ext= (MARIADB_FIELD_EXTENSION*) field->extension; + if (!ext || type > MARIADB_FIELD_ATTR_LAST) + { + static MARIADB_CONST_STRING null_str= {0,0}; + *attr= null_str; + return 1; + } + *attr= ext->metadata[type]; + return 0; +} + + +/************************************************************************** Move to a specific row and column **************************************************************************/ diff --git a/mysql-test/main/gis.result b/mysql-test/main/gis.result index 936924ffe87..fa7ded103b2 100644 --- a/mysql-test/main/gis.result +++ b/mysql-test/main/gis.result @@ -5095,5 +5095,211 @@ ERROR HY000: Operator does not exists: 'CAST(expr AS multilinestring)' SELECT CONVERT(1, MULTIPOLYGON); ERROR HY000: Operator does not exists: 'CAST(expr AS multipolygon)' # +# MDEV-17832 Protocol: extensions for Pluggable types and JSON, GEOMETRY +# +SET NAMES utf8; +CREATE TABLE t1 ( +p POINT, +ls LINESTRING, +pl POLYGON, +mp MULTIPOINT, +mls MULTILINESTRING, +mpl MULTIPOLYGON, +gc GEOMETRYCOLLECTION, +g GEOMETRY +) CHARACTER SET utf8; +SELECT * FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 p p 255 (type=point) 4294967295 0 Y 144 0 63 +def test t1 t1 ls ls 255 (type=linestring) 4294967295 0 Y 144 0 63 +def test t1 t1 pl pl 255 (type=polygon) 4294967295 0 Y 144 0 63 +def test t1 t1 mp mp 255 (type=multipoint) 4294967295 0 Y 144 0 63 +def test t1 t1 mls mls 255 (type=multilinestring) 4294967295 0 Y 144 0 63 +def test t1 t1 mpl mpl 255 (type=multipolygon) 4294967295 0 Y 144 0 63 +def test t1 t1 gc gc 255 (type=geometrycollection) 4294967295 0 Y 144 0 63 +def test t1 t1 g g 255 4294967295 0 Y 144 0 63 +p ls pl mp mls mpl gc g +SELECT +COALESCE(p) AS p, +COALESCE(ls) AS ls, +COALESCE(pl) AS pl, +COALESCE(mp) AS mp, +COALESCE(mls) AS mls, +COALESCE(mpl) AS mpl, +COALESCE(gc) AS gc, +COALESCE(g) AS g +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def p 255 (type=point) 4294967295 0 Y 128 0 63 +def ls 255 (type=linestring) 4294967295 0 Y 128 0 63 +def pl 255 (type=polygon) 4294967295 0 Y 128 0 63 +def mp 255 (type=multipoint) 4294967295 0 Y 128 0 63 +def mls 255 (type=multilinestring) 4294967295 0 Y 128 0 63 +def mpl 255 (type=multipolygon) 4294967295 0 Y 128 0 63 +def gc 255 (type=geometrycollection) 4294967295 0 Y 128 0 63 +def g 255 4294967295 0 Y 128 0 63 +p ls pl mp mls mpl gc g +SELECT +COALESCE(p,p), +COALESCE(p,ls), +COALESCE(p,pl), +COALESCE(p,mp), +COALESCE(p,mls), +COALESCE(p,mpl), +COALESCE(p,g), +COALESCE(p,gc) +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(p,p) 255 (type=point) 4294967295 0 Y 128 0 63 +def COALESCE(p,ls) 255 4294967295 0 Y 128 0 63 +def COALESCE(p,pl) 255 4294967295 0 Y 128 0 63 +def COALESCE(p,mp) 255 4294967295 0 Y 128 0 63 +def COALESCE(p,mls) 255 4294967295 0 Y 128 0 63 +def COALESCE(p,mpl) 255 4294967295 0 Y 128 0 63 +def COALESCE(p,g) 255 4294967295 0 Y 128 0 63 +def COALESCE(p,gc) 255 4294967295 0 Y 128 0 63 +COALESCE(p,p) COALESCE(p,ls) COALESCE(p,pl) COALESCE(p,mp) COALESCE(p,mls) COALESCE(p,mpl) COALESCE(p,g) COALESCE(p,gc) +SELECT +COALESCE(ls,p), +COALESCE(ls,ls), +COALESCE(ls,pl), +COALESCE(ls,mp), +COALESCE(ls,mls), +COALESCE(ls,mpl), +COALESCE(ls,g), +COALESCE(ls,gc) +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(ls,p) 255 4294967295 0 Y 128 0 63 +def COALESCE(ls,ls) 255 (type=linestring) 4294967295 0 Y 128 0 63 +def COALESCE(ls,pl) 255 4294967295 0 Y 128 0 63 +def COALESCE(ls,mp) 255 4294967295 0 Y 128 0 63 +def COALESCE(ls,mls) 255 4294967295 0 Y 128 0 63 +def COALESCE(ls,mpl) 255 4294967295 0 Y 128 0 63 +def COALESCE(ls,g) 255 4294967295 0 Y 128 0 63 +def COALESCE(ls,gc) 255 4294967295 0 Y 128 0 63 +COALESCE(ls,p) COALESCE(ls,ls) COALESCE(ls,pl) COALESCE(ls,mp) COALESCE(ls,mls) COALESCE(ls,mpl) COALESCE(ls,g) COALESCE(ls,gc) +SELECT +COALESCE(pl,p), +COALESCE(pl,ls), +COALESCE(pl,pl), +COALESCE(pl,mp), +COALESCE(pl,mls), +COALESCE(pl,mpl), +COALESCE(pl,g), +COALESCE(pl,gc) +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(pl,p) 255 4294967295 0 Y 128 0 63 +def COALESCE(pl,ls) 255 4294967295 0 Y 128 0 63 +def COALESCE(pl,pl) 255 (type=polygon) 4294967295 0 Y 128 0 63 +def COALESCE(pl,mp) 255 4294967295 0 Y 128 0 63 +def COALESCE(pl,mls) 255 4294967295 0 Y 128 0 63 +def COALESCE(pl,mpl) 255 4294967295 0 Y 128 0 63 +def COALESCE(pl,g) 255 4294967295 0 Y 128 0 63 +def COALESCE(pl,gc) 255 4294967295 0 Y 128 0 63 +COALESCE(pl,p) COALESCE(pl,ls) COALESCE(pl,pl) COALESCE(pl,mp) COALESCE(pl,mls) COALESCE(pl,mpl) COALESCE(pl,g) COALESCE(pl,gc) +SELECT +COALESCE(mp,p), +COALESCE(mp,ls), +COALESCE(mp,pl), +COALESCE(mp,mp), +COALESCE(mp,mls), +COALESCE(mp,mpl), +COALESCE(mp,g), +COALESCE(mp,gc) +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(mp,p) 255 4294967295 0 Y 128 0 63 +def COALESCE(mp,ls) 255 4294967295 0 Y 128 0 63 +def COALESCE(mp,pl) 255 4294967295 0 Y 128 0 63 +def COALESCE(mp,mp) 255 (type=multipoint) 4294967295 0 Y 128 0 63 +def COALESCE(mp,mls) 255 4294967295 0 Y 128 0 63 +def COALESCE(mp,mpl) 255 4294967295 0 Y 128 0 63 +def COALESCE(mp,g) 255 4294967295 0 Y 128 0 63 +def COALESCE(mp,gc) 255 4294967295 0 Y 128 0 63 +COALESCE(mp,p) COALESCE(mp,ls) COALESCE(mp,pl) COALESCE(mp,mp) COALESCE(mp,mls) COALESCE(mp,mpl) COALESCE(mp,g) COALESCE(mp,gc) +SELECT +COALESCE(mls,p), +COALESCE(mls,ls), +COALESCE(mls,pl), +COALESCE(mls,mp), +COALESCE(mls,mls), +COALESCE(mls,mpl), +COALESCE(mls,g), +COALESCE(mls,gc) +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(mls,p) 255 4294967295 0 Y 128 0 63 +def COALESCE(mls,ls) 255 4294967295 0 Y 128 0 63 +def COALESCE(mls,pl) 255 4294967295 0 Y 128 0 63 +def COALESCE(mls,mp) 255 4294967295 0 Y 128 0 63 +def COALESCE(mls,mls) 255 (type=multilinestring) 4294967295 0 Y 128 0 63 +def COALESCE(mls,mpl) 255 4294967295 0 Y 128 0 63 +def COALESCE(mls,g) 255 4294967295 0 Y 128 0 63 +def COALESCE(mls,gc) 255 4294967295 0 Y 128 0 63 +COALESCE(mls,p) COALESCE(mls,ls) COALESCE(mls,pl) COALESCE(mls,mp) COALESCE(mls,mls) COALESCE(mls,mpl) COALESCE(mls,g) COALESCE(mls,gc) +SELECT +COALESCE(mpl,p), +COALESCE(mpl,ls), +COALESCE(mpl,pl), +COALESCE(mpl,mp), +COALESCE(mpl,mls), +COALESCE(mpl,mpl), +COALESCE(mpl,g), +COALESCE(mpl,gc) +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(mpl,p) 255 4294967295 0 Y 128 0 63 +def COALESCE(mpl,ls) 255 4294967295 0 Y 128 0 63 +def COALESCE(mpl,pl) 255 4294967295 0 Y 128 0 63 +def COALESCE(mpl,mp) 255 4294967295 0 Y 128 0 63 +def COALESCE(mpl,mls) 255 4294967295 0 Y 128 0 63 +def COALESCE(mpl,mpl) 255 (type=multipolygon) 4294967295 0 Y 128 0 63 +def COALESCE(mpl,g) 255 4294967295 0 Y 128 0 63 +def COALESCE(mpl,gc) 255 4294967295 0 Y 128 0 63 +COALESCE(mpl,p) COALESCE(mpl,ls) COALESCE(mpl,pl) COALESCE(mpl,mp) COALESCE(mpl,mls) COALESCE(mpl,mpl) COALESCE(mpl,g) COALESCE(mpl,gc) +SELECT +COALESCE(g,p), +COALESCE(g,ls), +COALESCE(g,pl), +COALESCE(g,mp), +COALESCE(g,mls), +COALESCE(g,mpl), +COALESCE(g,g), +COALESCE(g,gc) +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(g,p) 255 4294967295 0 Y 128 0 63 +def COALESCE(g,ls) 255 4294967295 0 Y 128 0 63 +def COALESCE(g,pl) 255 4294967295 0 Y 128 0 63 +def COALESCE(g,mp) 255 4294967295 0 Y 128 0 63 +def COALESCE(g,mls) 255 4294967295 0 Y 128 0 63 +def COALESCE(g,mpl) 255 4294967295 0 Y 128 0 63 +def COALESCE(g,g) 255 4294967295 0 Y 128 0 63 +def COALESCE(g,gc) 255 4294967295 0 Y 128 0 63 +COALESCE(g,p) COALESCE(g,ls) COALESCE(g,pl) COALESCE(g,mp) COALESCE(g,mls) COALESCE(g,mpl) COALESCE(g,g) COALESCE(g,gc) +SELECT +COALESCE(gc,p), +COALESCE(gc,ls), +COALESCE(gc,pl), +COALESCE(gc,mp), +COALESCE(gc,mls), +COALESCE(gc,mpl), +COALESCE(gc,g), +COALESCE(gc,gc) +FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def COALESCE(gc,p) 255 4294967295 0 Y 128 0 63 +def COALESCE(gc,ls) 255 4294967295 0 Y 128 0 63 +def COALESCE(gc,pl) 255 4294967295 0 Y 128 0 63 +def COALESCE(gc,mp) 255 4294967295 0 Y 128 0 63 +def COALESCE(gc,mls) 255 4294967295 0 Y 128 0 63 +def COALESCE(gc,mpl) 255 4294967295 0 Y 128 0 63 +def COALESCE(gc,g) 255 4294967295 0 Y 128 0 63 +def COALESCE(gc,gc) 255 (type=geometrycollection) 4294967295 0 Y 128 0 63 +COALESCE(gc,p) COALESCE(gc,ls) COALESCE(gc,pl) COALESCE(gc,mp) COALESCE(gc,mls) COALESCE(gc,mpl) COALESCE(gc,g) COALESCE(gc,gc) +DROP TABLE t1; +# # End of 10.5 tests # diff --git a/mysql-test/main/gis.test b/mysql-test/main/gis.test index 48f2803b27d..3249b2579d3 100644 --- a/mysql-test/main/gis.test +++ b/mysql-test/main/gis.test @@ -3181,5 +3181,126 @@ SELECT CONVERT(1, MULTIPOLYGON); --echo # +--echo # MDEV-17832 Protocol: extensions for Pluggable types and JSON, GEOMETRY +--echo # + +SET NAMES utf8; +CREATE TABLE t1 ( + p POINT, + ls LINESTRING, + pl POLYGON, + mp MULTIPOINT, + mls MULTILINESTRING, + mpl MULTIPOLYGON, + gc GEOMETRYCOLLECTION, + g GEOMETRY +) CHARACTER SET utf8; + +--enable_metadata +SELECT * FROM t1; + +SELECT + COALESCE(p) AS p, + COALESCE(ls) AS ls, + COALESCE(pl) AS pl, + COALESCE(mp) AS mp, + COALESCE(mls) AS mls, + COALESCE(mpl) AS mpl, + COALESCE(gc) AS gc, + COALESCE(g) AS g +FROM t1; + +SELECT + COALESCE(p,p), + COALESCE(p,ls), + COALESCE(p,pl), + COALESCE(p,mp), + COALESCE(p,mls), + COALESCE(p,mpl), + COALESCE(p,g), + COALESCE(p,gc) +FROM t1; + +SELECT + COALESCE(ls,p), + COALESCE(ls,ls), + COALESCE(ls,pl), + COALESCE(ls,mp), + COALESCE(ls,mls), + COALESCE(ls,mpl), + COALESCE(ls,g), + COALESCE(ls,gc) +FROM t1; + +SELECT + COALESCE(pl,p), + COALESCE(pl,ls), + COALESCE(pl,pl), + COALESCE(pl,mp), + COALESCE(pl,mls), + COALESCE(pl,mpl), + COALESCE(pl,g), + COALESCE(pl,gc) +FROM t1; + +SELECT + COALESCE(mp,p), + COALESCE(mp,ls), + COALESCE(mp,pl), + COALESCE(mp,mp), + COALESCE(mp,mls), + COALESCE(mp,mpl), + COALESCE(mp,g), + COALESCE(mp,gc) +FROM t1; + +SELECT + COALESCE(mls,p), + COALESCE(mls,ls), + COALESCE(mls,pl), + COALESCE(mls,mp), + COALESCE(mls,mls), + COALESCE(mls,mpl), + COALESCE(mls,g), + COALESCE(mls,gc) +FROM t1; + +SELECT + COALESCE(mpl,p), + COALESCE(mpl,ls), + COALESCE(mpl,pl), + COALESCE(mpl,mp), + COALESCE(mpl,mls), + COALESCE(mpl,mpl), + COALESCE(mpl,g), + COALESCE(mpl,gc) +FROM t1; + +SELECT + COALESCE(g,p), + COALESCE(g,ls), + COALESCE(g,pl), + COALESCE(g,mp), + COALESCE(g,mls), + COALESCE(g,mpl), + COALESCE(g,g), + COALESCE(g,gc) +FROM t1; + +SELECT + COALESCE(gc,p), + COALESCE(gc,ls), + COALESCE(gc,pl), + COALESCE(gc,mp), + COALESCE(gc,mls), + COALESCE(gc,mpl), + COALESCE(gc,g), + COALESCE(gc,gc) +FROM t1; + +--disable_metadata +DROP TABLE t1; + +--echo # --echo # End of 10.5 tests --echo # diff --git a/mysql-test/main/mysql-metadata.result b/mysql-test/main/mysql-metadata.result new file mode 100644 index 00000000000..ce6c77ed7fa --- /dev/null +++ b/mysql-test/main/mysql-metadata.result @@ -0,0 +1,87 @@ +# +# MDEV-17832 Protocol: extensions for Pluggable types and JSON, GEOMETRY +# +SET NAMES utf8; +CREATE TABLE t1 ( +js0 JSON, +js1 TEXT CHECK (JSON_VALID(js1)), +js2 TEXT CHECK (LENGTH(js2) > 0 AND JSON_VALID(js2)), +js3 TEXT CHECK (LENGTH(js2) > 0 OR JSON_VALID(js2)) +) CHARACTER SET utf8; +-------------- +SELECT * FROM t1 +-------------- + +Field 1: `js0` +Catalog: `def` +Database: `test` +Table: `t1` +Org_table: `t1` +Type: BLOB (format=json) +Collation: latin1_swedish_ci (8) +Length: 4294967295 +Max_length: 0 +Decimals: 0 +Flags: BLOB BINARY + +Field 2: `js1` +Catalog: `def` +Database: `test` +Table: `t1` +Org_table: `t1` +Type: BLOB (format=json) +Collation: latin1_swedish_ci (8) +Length: 65535 +Max_length: 0 +Decimals: 0 +Flags: BLOB + +Field 3: `js2` +Catalog: `def` +Database: `test` +Table: `t1` +Org_table: `t1` +Type: BLOB (format=json) +Collation: latin1_swedish_ci (8) +Length: 65535 +Max_length: 0 +Decimals: 0 +Flags: BLOB + +Field 4: `js3` +Catalog: `def` +Database: `test` +Table: `t1` +Org_table: `t1` +Type: BLOB +Collation: latin1_swedish_ci (8) +Length: 65535 +Max_length: 0 +Decimals: 0 +Flags: BLOB + + +0 rows in set (TIME) + +Bye +-------------- +SELECT JSON_COMPACT(js0) FROM t1 +-------------- + +Field 1: `JSON_COMPACT(js0)` +Catalog: `def` +Database: `` +Table: `` +Org_table: `` +Type: LONG_BLOB (format=json) +Collation: binary (63) +Length: 4294967295 +Max_length: 0 +Decimals: 0 +Flags: BINARY + + +0 rows in set (TIME) + +Bye +DROP TABLE t1; diff --git a/mysql-test/main/mysql-metadata.test b/mysql-test/main/mysql-metadata.test new file mode 100644 index 00000000000..bab44496f78 --- /dev/null +++ b/mysql-test/main/mysql-metadata.test @@ -0,0 +1,22 @@ +-- source include/have_working_dns.inc +-- source include/not_embedded.inc + +--echo # +--echo # MDEV-17832 Protocol: extensions for Pluggable types and JSON, GEOMETRY +--echo # + +SET NAMES utf8; +CREATE TABLE t1 ( + js0 JSON, + js1 TEXT CHECK (JSON_VALID(js1)), + js2 TEXT CHECK (LENGTH(js2) > 0 AND JSON_VALID(js2)), + js3 TEXT CHECK (LENGTH(js2) > 0 OR JSON_VALID(js2)) +) CHARACTER SET utf8; + +--replace_regex /0 rows in set [(].*[)]/0 rows in set (TIME)/ +--exec $MYSQL -vvv --column-type-info --database=test -e "SELECT * FROM t1;" + +--replace_regex /0 rows in set [(].*[)]/0 rows in set (TIME)/ +--exec $MYSQL -vvv --column-type-info --database=test -e "SELECT JSON_COMPACT(js0) FROM t1;" + +DROP TABLE t1; diff --git a/mysql-test/main/type_json.result b/mysql-test/main/type_json.result index 96e96cca404..2c4f7b7d42b 100644 --- a/mysql-test/main/type_json.result +++ b/mysql-test/main/type_json.result @@ -98,3 +98,33 @@ select cast('{a:1}' as text); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'text)' at line 1 select cast('{a:1}' as json); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'json)' at line 1 +# +# Start of 10.5 tests +# +# +# MDEV-17832 Protocol: extensions for Pluggable types and JSON, GEOMETRY +# +SET NAMES utf8; +CREATE TABLE t1 ( +js0 JSON, +js1 TEXT CHECK (JSON_VALID(js1)), +js2 TEXT CHECK (LENGTH(js2) > 0 AND JSON_VALID(js2)), +js3 TEXT CHECK (LENGTH(js2) > 0 OR JSON_VALID(js2)) +) CHARACTER SET utf8; +SELECT * FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 js0 js0 252 (format=json) 4294967295 0 Y 144 0 33 +def test t1 t1 js1 js1 252 (format=json) 196605 0 Y 16 0 33 +def test t1 t1 js2 js2 252 (format=json) 196605 0 Y 16 0 33 +def test t1 t1 js3 js3 252 196605 0 Y 16 0 33 +js0 js1 js2 js3 +SELECT js0, JSON_COMPACT(js0), JSON_COMPACT('{}') FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 js0 js0 252 (format=json) 4294967295 0 Y 144 0 33 +def JSON_COMPACT(js0) 251 (format=json) 4294967295 0 Y 128 0 63 +def JSON_COMPACT('{}') 253 (format=json) 6 0 Y 128 0 63 +js0 JSON_COMPACT(js0) JSON_COMPACT('{}') +DROP TABLE t1; +# +# End of 10.5 tests +# diff --git a/mysql-test/main/type_json.test b/mysql-test/main/type_json.test index bd13dc1fcf4..7ab0af20e03 100644 --- a/mysql-test/main/type_json.test +++ b/mysql-test/main/type_json.test @@ -64,3 +64,30 @@ drop table t1; select cast('{a:1}' as text); --error ER_PARSE_ERROR select cast('{a:1}' as json); + +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-17832 Protocol: extensions for Pluggable types and JSON, GEOMETRY +--echo # + +SET NAMES utf8; +CREATE TABLE t1 ( + js0 JSON, + js1 TEXT CHECK (JSON_VALID(js1)), + js2 TEXT CHECK (LENGTH(js2) > 0 AND JSON_VALID(js2)), + js3 TEXT CHECK (LENGTH(js2) > 0 OR JSON_VALID(js2)) +) CHARACTER SET utf8; +--disable_ps_protocol +--enable_metadata +SELECT * FROM t1; +SELECT js0, JSON_COMPACT(js0), JSON_COMPACT('{}') FROM t1; +--disable_metadata +--enable_ps_protocol +DROP TABLE t1; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.result b/plugin/type_inet/mysql-test/type_inet/type_inet6.result index 3dbbbccb100..15c8dbf8ca9 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.result @@ -40,12 +40,12 @@ CREATE TABLE t1 (a INET6); INSERT INTO t1 VALUES ('::1'); SELECT * FROM t1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t1 t1 a a 254 39 3 Y 160 0 8 +def test t1 t1 a a 254 (type=inet6) 39 3 Y 160 0 8 a ::1 SELECT CAST('::' AS INET6) AS a; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def a 254 39 2 N 33 0 8 +def a 254 (type=inet6) 39 2 N 33 0 8 a :: DROP TABLE t1; diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.result index 468e9fea41e..868b9902f5c 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.result @@ -4,12 +4,36 @@ Catalog: `def` Database: `test` Table: `t1` Org_table: `t1` -Type: STRING +Type: STRING (type=inet6) Collation: latin1_swedish_ci (8) Length: 39 Max_length: 0 Decimals: 0 Flags: UNSIGNED BINARY +Field 2: `b` +Catalog: `def` +Database: `` +Table: `` +Org_table: `` +Type: STRING (type=inet6) +Collation: latin1_swedish_ci (8) +Length: 39 +Max_length: 0 +Decimals: 0 +Flags: NOT_NULL UNSIGNED + +Field 3: `c` +Catalog: `def` +Database: `` +Table: `` +Org_table: `` +Type: STRING (type=inet6) +Collation: latin1_swedish_ci (8) +Length: 39 +Max_length: 0 +Decimals: 0 +Flags: UNSIGNED + DROP TABLE t1; diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.test index 5e6ac6f3804..dfb300816d9 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.test +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.test @@ -2,5 +2,5 @@ -- source include/not_embedded.inc CREATE TABLE t1 (a INET6); ---exec $MYSQL -t test --column-type-info -e "SELECT * FROM t1" 2>&1 +--exec $MYSQL -t test --column-type-info -e "SELECT a, CAST('::' AS INET6) AS b, COALESCE(a) AS c FROM t1" 2>&1 DROP TABLE t1; diff --git a/plugin/type_inet/sql_type_inet.cc b/plugin/type_inet/sql_type_inet.cc index e9c1c27269b..29234aa4a56 100644 --- a/plugin/type_inet/sql_type_inet.cc +++ b/plugin/type_inet/sql_type_inet.cc @@ -705,6 +705,12 @@ public: str.set_ascii(name.ptr(), name.length()); } + void make_send_field(Send_field *to) override + { + Field::make_send_field(to); + to->set_data_type_name(type_handler_inet6.name().lex_cstring()); + } + bool validate_value_in_record(THD *thd, const uchar *record) const override { return false; diff --git a/plugin/type_inet/sql_type_inet.h b/plugin/type_inet/sql_type_inet.h index a13931a83a0..c8118a111e4 100644 --- a/plugin/type_inet/sql_type_inet.h +++ b/plugin/type_inet/sql_type_inet.h @@ -328,6 +328,11 @@ public: { return PROTOCOL_SEND_STRING; } + bool Item_append_extended_type_info(Send_field_extended_metadata *to, + const Item *item) const override + { + return to->set_data_type_name(name().lex_cstring()); + } enum_field_types field_type() const override { diff --git a/sql/field.cc b/sql/field.cc index c9b29af1155..5a2dbdfa15c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7070,6 +7070,27 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end, } +/* + This is JSON specific. + We should eventually add Field_json_varchar and Field_json_blob + and move make_send_field() to the new classes. +*/ +void Field_longstr::make_send_field(Send_field *field) +{ + Field_str::make_send_field(field); + if (check_constraint) + { + /* + Append the format that is implicitly implied by the CHECK CONSTRAINT. + For example: + CREATE TABLE t1 (js longtext DEFAULT NULL CHECK (json_valid(a))); + SELECT j FROM t1; + will add "format=json" to the extended type info metadata for t1.js. + */ + check_constraint->expr->set_format_by_check_constraint(field); + } +} + /* Copy a string and fill with space */ int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs) diff --git a/sql/field.h b/sql/field.h index 71e9b3a2128..310c5ca33ae 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2142,6 +2142,7 @@ public: const Conv_param ¶m) const; int store_decimal(const my_decimal *d); uint32 max_data_length() const; + void make_send_field(Send_field *) override; bool is_varchar_and_in_write_set() const { @@ -5511,7 +5512,8 @@ public: */ class Send_field :public Sql_alloc, - public Type_handler_hybrid_field_type + public Type_handler_hybrid_field_type, + public Send_field_extended_metadata { public: LEX_CSTRING db_name; diff --git a/sql/item.cc b/sql/item.cc index 49005030930..c7454b789fb 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6197,6 +6197,9 @@ void Item::init_make_send_field(Send_field *tmp_field, tmp_field->decimals=decimals; if (unsigned_flag) tmp_field->flags |= UNSIGNED_FLAG; + static_cast<Send_field_extended_metadata>(*tmp_field)= + Send_field_extended_metadata(); + h->Item_append_extended_type_info(tmp_field, this); } void Item::make_send_field(THD *thd, Send_field *tmp_field) diff --git a/sql/item.h b/sql/item.h index c51ea35b254..5eab1d049f0 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1823,6 +1823,15 @@ public: virtual bool need_parentheses_in_default() { return false; } virtual void save_in_result_field(bool no_conversions) {} /* + Data type format implied by the CHECK CONSTRAINT, + to be sent to the client in the result set metadata. + */ + virtual bool set_format_by_check_constraint(Send_field_extended_metadata *) + const + { + return false; + } + /* set value of aggregate function in case of no rows for grouping were found */ virtual void no_rows_in_result() {} diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6df2b5dbd3a..7fe16848082 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -6481,6 +6481,21 @@ Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */ } +bool +Item_cond_and::set_format_by_check_constraint( + Send_field_extended_metadata *to) const +{ + List_iterator_fast<Item> li(const_cast<List<Item>&>(list)); + Item *item; + while ((item= li++)) + { + if (item->set_format_by_check_constraint(to)) + return true; + } + return false; +} + + Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */ /* NOT a AND NOT b AND ... */ { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 9b20fa50214..8d5cfb359ec 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -3349,6 +3349,7 @@ public: COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref); + bool set_format_by_check_constraint(Send_field_extended_metadata *to) const; void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables); SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr); diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index e61d0875056..44f9e8146c2 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -84,6 +84,11 @@ public: maybe_null= 1; return FALSE; } + bool set_format_by_check_constraint(Send_field_extended_metadata *to) const + { + static const Lex_cstring fmt(STRING_WITH_LEN("json")); + return to->set_format_name(fmt); + } Item *get_copy(THD *thd) { return get_item_copy<Item_func_json_valid>(thd, this); } }; @@ -118,6 +123,12 @@ public: Item_json_func(THD *thd, List<Item> &list) :Item_str_func(thd, list) { } bool is_json_type() { return true; } + void make_send_field(THD *thd, Send_field *tmp_field) + { + Item_str_func::make_send_field(thd, tmp_field); + static const Lex_cstring fmt(STRING_WITH_LEN("json")); + tmp_field->set_format_name(fmt); + } }; diff --git a/sql/protocol.cc b/sql/protocol.cc index 30e4cc6c214..21efac46c52 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -799,6 +799,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, @@ -816,8 +851,20 @@ bool Protocol_text::store_field_metadata(const THD * thd, 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)) + store_str(field.org_col_name, cs, thd_charset)) + 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_str(metadata.lex_cstring(), cs, &my_charset_bin)) + return true; + } + if (packet->realloc(packet->length() + 12)) return true; /* Store fixed length fields */ pos= (char*) packet->end(); diff --git a/sql/sql_type.h b/sql/sql_type.h index ee56e7146da..588984f08bc 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -23,6 +23,7 @@ #include "mysqld.h" +#include "lex_string.h" #include "sql_array.h" #include "sql_const.h" #include "sql_time.h" @@ -138,6 +139,41 @@ enum column_definition_type_t }; +class Send_field_extended_metadata +{ + LEX_CSTRING m_attr[MARIADB_FIELD_ATTR_LAST+1]; +public: + Send_field_extended_metadata() + { + bzero(this, sizeof(*this)); + } + bool set_data_type_name(const LEX_CSTRING &str) + { + m_attr[MARIADB_FIELD_ATTR_DATA_TYPE_NAME]= str; + return false; + } + bool set_format_name(const LEX_CSTRING &str) + { + m_attr[MARIADB_FIELD_ATTR_FORMAT_NAME]= str; + return false; + } + bool has_extended_metadata() const + { + for (uint i= 0; i <= MARIADB_FIELD_ATTR_LAST; i++) + { + if (m_attr[i].str) + return true; + } + return false; + } + const LEX_CSTRING &attr(uint i) const + { + DBUG_ASSERT(i <= MARIADB_FIELD_ATTR_LAST); + return m_attr[i]; + } +}; + + class Data_type_statistics { public: @@ -3435,6 +3471,11 @@ public: return field_type(); } virtual protocol_send_type_t protocol_send_type() const= 0; + virtual bool Item_append_extended_type_info(Send_field_extended_metadata *to, + const Item *item) const + { + return false; + } virtual Item_result result_type() const= 0; virtual Item_result cmp_type() const= 0; virtual enum_dynamic_column_type diff --git a/sql/sql_type_geom.cc b/sql/sql_type_geom.cc index 3ca0eaabc3f..0dcde0009b0 100644 --- a/sql/sql_type_geom.cc +++ b/sql/sql_type_geom.cc @@ -34,6 +34,14 @@ Named_type_handler<Type_handler_geometrycollection> type_handler_geometrycollect Type_collection_geometry type_collection_geometry; + +LEX_CSTRING Type_handler_geometry::extended_metadata_data_type_name() const +{ + return geometry_type() == GEOM_GEOMETRY ? null_clex_str : + name().lex_cstring(); +} + + const Type_handler_geometry * Type_handler_geometry::type_handler_geom_by_type(uint type) { diff --git a/sql/sql_type_geom.h b/sql/sql_type_geom.h index a2baa5ae299..b1aa8063902 100644 --- a/sql/sql_type_geom.h +++ b/sql/sql_type_geom.h @@ -39,9 +39,16 @@ public: Item * const *args, uint start, uint end); static const Type_handler_geometry *type_handler_geom_by_type(uint type); + LEX_CSTRING extended_metadata_data_type_name() const; public: virtual ~Type_handler_geometry() {} enum_field_types field_type() const override { return MYSQL_TYPE_GEOMETRY; } + bool Item_append_extended_type_info(Send_field_extended_metadata *to, + const Item *item) const override + { + LEX_CSTRING tmp= extended_metadata_data_type_name(); + return tmp.length ? to->set_data_type_name(tmp) : false; + } bool is_param_long_data_type() const override { return true; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; @@ -361,6 +368,9 @@ public: void make_send_field(Send_field *to) override { Field_longstr::make_send_field(to); + LEX_CSTRING tmp= m_type_handler->extended_metadata_data_type_name(); + if (tmp.length) + to->set_data_type_name(tmp); } bool can_optimize_range(const Item_bool_func *cond, const Item *item, |