1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-08 14:02:17 +03:00

MDEV-17832 Protocol: extensions for Pluggable types and JSON, GEOMETRY

This commit is contained in:
Alexander Barkov
2020-03-10 17:02:59 +04:00
parent d4f75481f6
commit 6632cb69d7
7 changed files with 190 additions and 17 deletions

View File

@@ -113,3 +113,9 @@ struct st_mariadb_extension {
(a)->options.extension->key : 0 (a)->options.extension->key : 0
#endif #endif
typedef struct st_mariadb_field_extension
{
MARIADB_CONST_STRING metadata[MARIADB_FIELD_ATTR_LAST+1]; /* 10.5 */
} MA_FIELD_EXTENSION;

View File

@@ -24,8 +24,27 @@
void free_rows(MYSQL_DATA *cur); void free_rows(MYSQL_DATA *cur);
int ma_multi_command(MYSQL *mysql, enum enum_multi_status status); int ma_multi_command(MYSQL *mysql, enum enum_multi_status status);
MYSQL_FIELD * unpack_fields(MYSQL_DATA *data, MYSQL_FIELD * unpack_fields(const MYSQL *mysql, MYSQL_DATA *data,
MA_MEM_ROOT *alloc,uint fields, MA_MEM_ROOT *alloc,uint fields,
my_bool default_value); my_bool default_value);
static inline my_bool ma_has_extended_type_info(const MYSQL *mysql)
{
return ((mysql->extension->mariadb_server_capabilities << 32) &
MARIADB_CLIENT_EXTENDED_METADATA) != 0;
}
static inline uint ma_extended_type_info_rows(const MYSQL *mysql)
{
return ma_has_extended_type_info(mysql) ? 1 : 0;
}
static inline uint ma_result_set_rows(const MYSQL *mysql)
{
return ma_has_extended_type_info(mysql) ? 9 : 8;
}
MA_FIELD_EXTENSION *ma_field_extension_deep_dup(MA_MEM_ROOT *memroot,
const MA_FIELD_EXTENSION *from);
#endif #endif

View File

@@ -170,13 +170,16 @@ enum enum_server_command
#define MARIADB_CLIENT_PROGRESS (1ULL << 32) #define MARIADB_CLIENT_PROGRESS (1ULL << 32)
#define MARIADB_CLIENT_COM_MULTI (1ULL << 33) #define MARIADB_CLIENT_COM_MULTI (1ULL << 33)
#define MARIADB_CLIENT_STMT_BULK_OPERATIONS (1ULL << 34) #define MARIADB_CLIENT_STMT_BULK_OPERATIONS (1ULL << 34)
/* support of extended data type/format information, since 10.5.0 */
#define MARIADB_CLIENT_EXTENDED_METADATA (1ULL << 35)
#define IS_MARIADB_EXTENDED_SERVER(mysql)\ #define IS_MARIADB_EXTENDED_SERVER(mysql)\
!(mysql->server_capabilities & CLIENT_MYSQL) !(mysql->server_capabilities & CLIENT_MYSQL)
#define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\ #define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\
MARIADB_CLIENT_COM_MULTI |\ MARIADB_CLIENT_COM_MULTI |\
MARIADB_CLIENT_STMT_BULK_OPERATIONS) MARIADB_CLIENT_STMT_BULK_OPERATIONS|\
MARIADB_CLIENT_EXTENDED_METADATA)
#define CLIENT_SUPPORTED_FLAGS (CLIENT_MYSQL |\ #define CLIENT_SUPPORTED_FLAGS (CLIENT_MYSQL |\
CLIENT_FOUND_ROWS |\ CLIENT_FOUND_ROWS |\

View File

@@ -61,6 +61,14 @@ typedef int my_socket;
#include "ma_list.h" #include "ma_list.h"
#include "mariadb_ctype.h" #include "mariadb_ctype.h"
typedef struct st_ma_const_string
{
const char *str;
size_t length;
} MARIADB_CONST_STRING;
#ifndef ST_MA_USED_MEM_DEFINED #ifndef ST_MA_USED_MEM_DEFINED
#define ST_MA_USED_MEM_DEFINED #define ST_MA_USED_MEM_DEFINED
typedef struct st_ma_used_mem { /* struct for once_alloc */ typedef struct st_ma_used_mem { /* struct for once_alloc */
@@ -383,6 +391,20 @@ typedef struct
void *extension; void *extension;
} MYSQL_PARAMETERS; } MYSQL_PARAMETERS;
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
int STDCALL mariadb_field_attr(MARIADB_CONST_STRING *attr,
const MYSQL_FIELD *field,
enum mariadb_field_attr_t type);
#ifndef _mysql_time_h_ #ifndef _mysql_time_h_
enum enum_mysql_timestamp_type enum enum_mysql_timestamp_type
{ {

View File

@@ -29,7 +29,9 @@ SET(MARIADB_LIB_SYMBOLS
mariadb_rpl_fetch mariadb_rpl_fetch
mariadb_rpl_optionsv mariadb_rpl_optionsv
mariadb_rpl_get_optionsv mariadb_rpl_get_optionsv
mariadb_free_rpl_event) mariadb_free_rpl_event
mariadb_field_attr
)
IF(WITH_SSL) IF(WITH_SSL)
SET(MARIADB_LIB_SYMBOLS ${MARIADB_LIB_SYMBOLS} mariadb_deinitialize_ssl) SET(MARIADB_LIB_SYMBOLS ${MARIADB_LIB_SYMBOLS} mariadb_deinitialize_ssl)
ENDIF() ENDIF()

View File

@@ -752,6 +752,79 @@ my_bool _mariadb_set_conf_option(MYSQL *mysql, const char *config_option, const
return 1; return 1;
} }
static MARIADB_CONST_STRING null_const_string= {0,0};
/***************************************************************************
** Allocate a string copy on memroot
***************************************************************************/
static MARIADB_CONST_STRING ma_const_string_copy_root(MA_MEM_ROOT *memroot,
const char *str,
size_t length)
{
MARIADB_CONST_STRING res;
if (!str || !(res.str= ma_memdup_root(memroot, str, length)))
return null_const_string;
res.length= length;
return res;
}
/***************************************************************************
** Allocate and initialize MA_FIELD_EXTENSION
***************************************************************************/
MA_FIELD_EXTENSION *new_ma_field_extension(MA_MEM_ROOT *memroot)
{
MA_FIELD_EXTENSION *ext= ma_alloc_root(memroot, sizeof(MA_FIELD_EXTENSION));
if (ext)
memset((void *) ext, 0, sizeof(*ext));
return ext;
}
/***************************************************************************
** Populate field extension from a type info packet
***************************************************************************/
static void ma_field_extension_init_type_info(MA_MEM_ROOT *memroot,
MA_FIELD_EXTENSION *ext,
const char *ptr, size_t length)
{
const char *end= ptr + length;
for ( ; ptr < end; )
{
uint itype= (uchar) *ptr++;
uint len= (uchar) *ptr++;
if (ptr + len > end || len > 127)
break; /*Badly encoded data*/
if (itype <= 127 && itype <= MARIADB_FIELD_ATTR_LAST)
ext->metadata[itype]= ma_const_string_copy_root(memroot, ptr, len);
ptr+= len;
}
}
/***************************************************************************
** Allocate a field extension deep copy
***************************************************************************/
MA_FIELD_EXTENSION *ma_field_extension_deep_dup(MA_MEM_ROOT *memroot,
const MA_FIELD_EXTENSION *from)
{
MA_FIELD_EXTENSION *ext= new_ma_field_extension(memroot);
uint i;
if (!ext)
return NULL;
for (i= 0; i < MARIADB_FIELD_ATTR_LAST; i++)
{
if (from->metadata[i].str)
ext->metadata[i]= ma_const_string_copy_root(memroot,
from->metadata[i].str,
from->metadata[i].length);
}
return ext;
}
/*************************************************************************** /***************************************************************************
** Change field rows to field structs ** Change field rows to field structs
***************************************************************************/ ***************************************************************************/
@@ -772,7 +845,8 @@ static size_t rset_field_offsets[]= {
}; };
MYSQL_FIELD * MYSQL_FIELD *
unpack_fields(MYSQL_DATA *data,MA_MEM_ROOT *alloc,uint fields, unpack_fields(const MYSQL *mysql,
MYSQL_DATA *data, MA_MEM_ROOT *alloc, uint fields,
my_bool default_value) my_bool default_value)
{ {
MYSQL_ROWS *row; MYSQL_ROWS *row;
@@ -805,7 +879,20 @@ unpack_fields(MYSQL_DATA *data,MA_MEM_ROOT *alloc,uint fields,
} }
} }
p= (char *)row->data[6]; field->extension= NULL;
if (ma_has_extended_type_info(mysql))
{
if (row->data[i+1] - row->data[i] > 1)
{
size_t len= row->data[i+1] - row->data[i] - 1;
MA_FIELD_EXTENSION *ext= new_ma_field_extension(alloc);
if ((field->extension= ext))
ma_field_extension_init_type_info(alloc, ext, row->data[i], len);
}
i++;
}
p= (char *)row->data[i];
/* filler */ /* filler */
field->charsetnr= uint2korr(p); field->charsetnr= uint2korr(p);
p+= 2; p+= 2;
@@ -824,10 +911,11 @@ unpack_fields(MYSQL_DATA *data,MA_MEM_ROOT *alloc,uint fields,
if (INTERNAL_NUM_FIELD(field)) if (INTERNAL_NUM_FIELD(field))
field->flags|= NUM_FLAG; field->flags|= NUM_FLAG;
i++;
/* This is used by deprecated function mysql_list_fields only, /* This is used by deprecated function mysql_list_fields only,
however the reported length is not correct, so we always zero it */ however the reported length is not correct, so we always zero it */
if (default_value && row->data[7]) if (default_value && row->data[i])
field->def=ma_strdup_root(alloc,(char*) row->data[7]); field->def=ma_strdup_root(alloc,(char*) row->data[i]);
else else
field->def=0; field->def=0;
field->def_length= 0; field->def_length= 0;
@@ -2213,9 +2301,10 @@ get_info:
mysql->server_status|= SERVER_STATUS_IN_TRANS; mysql->server_status|= SERVER_STATUS_IN_TRANS;
mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */ mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8))) if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,
ma_result_set_rows(mysql))))
return(-1); return(-1);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, if (!(mysql->fields=unpack_fields(mysql, fields, &mysql->field_alloc,
(uint) field_count, 1))) (uint) field_count, 1)))
return(-1); return(-1);
mysql->status=MYSQL_STATUS_GET_RESULT; mysql->status=MYSQL_STATUS_GET_RESULT;
@@ -2365,6 +2454,26 @@ mysql_fetch_field(MYSQL_RES *result)
return &result->fields[result->current_field++]; return &result->fields[result->current_field++];
} }
/**************************************************************************
** Return mysql field metadata
**************************************************************************/
int STDCALL
mariadb_field_attr(MARIADB_CONST_STRING *attr,
const MYSQL_FIELD *field,
enum mariadb_field_attr_t type)
{
MA_FIELD_EXTENSION *ext= (MA_FIELD_EXTENSION*) field->extension;
if (!ext || type > MARIADB_FIELD_ATTR_LAST)
{
*attr= null_const_string;
return 1;
}
*attr= ext->metadata[type];
return 0;
}
/************************************************************************** /**************************************************************************
** Return next row of the query results ** Return next row of the query results
**************************************************************************/ **************************************************************************/
@@ -2544,7 +2653,8 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
length= snprintf(buff, 128, "%s%c%s", table, '\0', wild ? wild : ""); length= snprintf(buff, 128, "%s%c%s", table, '\0', wild ? wild : "");
if (ma_simple_command(mysql, COM_FIELD_LIST,buff,length,1,0) || if (ma_simple_command(mysql, COM_FIELD_LIST,buff,length,1,0) ||
!(query = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8))) !(query = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,
ma_result_set_rows(mysql))))
return(NULL); return(NULL);
free_old_query(mysql); free_old_query(mysql);
@@ -2557,7 +2667,7 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
mysql->fields=0; mysql->fields=0;
result->eof=1; result->eof=1;
result->field_count = (uint) query->rows; result->field_count = (uint) query->rows;
result->fields= unpack_fields(query,&result->field_alloc, result->fields= unpack_fields(mysql, query, &result->field_alloc,
result->field_count, 1); result->field_count, 1);
if (result->fields) if (result->fields)
return(result); return(result);
@@ -2589,7 +2699,7 @@ mysql_list_processes(MYSQL *mysql)
field_count=(uint) net_field_length(&pos); field_count=(uint) net_field_length(&pos);
if (!(fields = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,7))) if (!(fields = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,7)))
return(NULL); return(NULL);
if (!(mysql->fields=unpack_fields(fields, &mysql->field_alloc, if (!(mysql->fields= unpack_fields(mysql, fields, &mysql->field_alloc,
field_count, 0))) field_count, 0)))
return(NULL); return(NULL);
mysql->status=MYSQL_STATUS_GET_RESULT; mysql->status=MYSQL_STATUS_GET_RESULT;

View File

@@ -1581,7 +1581,8 @@ my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt)
{ {
MYSQL_DATA *result; MYSQL_DATA *result;
if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7))) if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0,
7 + ma_extended_type_info_rows(stmt->mysql))))
return(1); return(1);
free_rows(result); free_rows(result);
@@ -1593,9 +1594,10 @@ my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt)
MYSQL_DATA *result; MYSQL_DATA *result;
MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root; MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0, 7))) if (!(result= stmt->mysql->methods->db_read_rows(stmt->mysql, (MYSQL_FIELD *)0,
7 + ma_extended_type_info_rows(stmt->mysql))))
return(1); return(1);
if (!(stmt->fields= unpack_fields(result,fields_ma_alloc_root, if (!(stmt->fields= unpack_fields(stmt->mysql, result, fields_ma_alloc_root,
stmt->field_count, 0))) stmt->field_count, 0)))
return(1); return(1);
return(0); return(0);
@@ -1836,6 +1838,11 @@ static int madb_alloc_stmt_fields(MYSQL_STMT *stmt)
stmt->fields[i].decimals= stmt->mysql->fields[i].decimals; stmt->fields[i].decimals= stmt->mysql->fields[i].decimals;
stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr; stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr;
stmt->fields[i].max_length= stmt->mysql->fields[i].max_length; stmt->fields[i].max_length= stmt->mysql->fields[i].max_length;
stmt->fields[i].extension=
stmt->mysql->fields[i].extension ?
ma_field_extension_deep_dup(fields_ma_alloc_root,
stmt->mysql->fields[i].extension) :
NULL;
} }
if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND)))) if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
{ {
@@ -1912,7 +1919,6 @@ int stmt_read_execute_response(MYSQL_STMT *stmt)
/* since all pointers will be incorrect if another statement will /* since all pointers will be incorrect if another statement will
be executed, so we need to allocate memory and copy the be executed, so we need to allocate memory and copy the
information */ information */
stmt->fields[i].extension= 0; /* not in use yet */
if (mysql->fields[i].db) if (mysql->fields[i].db)
stmt->fields[i].db= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].db); stmt->fields[i].db= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].db);
if (mysql->fields[i].table) if (mysql->fields[i].table)
@@ -1927,6 +1933,11 @@ int stmt_read_execute_response(MYSQL_STMT *stmt)
stmt->fields[i].catalog= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].catalog); stmt->fields[i].catalog= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].catalog);
if (mysql->fields[i].def) if (mysql->fields[i].def)
stmt->fields[i].def= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].def); stmt->fields[i].def= ma_strdup_root(fields_ma_alloc_root, mysql->fields[i].def);
stmt->fields[i].extension=
mysql->fields[i].extension ?
ma_field_extension_deep_dup(fields_ma_alloc_root,
mysql->fields[i].extension) :
NULL;
} }
} }