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

MDEV-19237 - do not resend prepared statement metadata unnecessarily

fix warnings
This commit is contained in:
Vladislav Vaintroub
2020-09-22 18:10:40 +02:00
parent 779925868d
commit ed4d747510
5 changed files with 174 additions and 52 deletions

View File

@@ -39,6 +39,13 @@ static inline uint ma_extended_type_info_rows(const MYSQL *mysql)
return ma_has_extended_type_info(mysql) ? 1 : 0;
}
static inline my_bool ma_supports_cache_metadata(const MYSQL *mysql)
{
return (mysql->extension->mariadb_server_capabilities &
(MARIADB_CLIENT_CACHE_METADATA >> 32)) != 0 ;
}
static inline uint ma_result_set_rows(const MYSQL *mysql)
{
return ma_has_extended_type_info(mysql) ? 9 : 8;
@@ -47,4 +54,7 @@ static inline uint ma_result_set_rows(const MYSQL *mysql)
MA_FIELD_EXTENSION *ma_field_extension_deep_dup(MA_MEM_ROOT *memroot,
const MA_FIELD_EXTENSION *from);
MYSQL_FIELD *ma_duplicate_resultset_metadata(MYSQL_FIELD *fields, size_t count,
MA_MEM_ROOT *memroot);
#endif

View File

@@ -172,13 +172,16 @@ enum enum_server_command
#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)
/* Do not resend metadata for prepared statements, since 10.6*/
#define MARIADB_CLIENT_CACHE_METADATA (1ULL << 36)
#define IS_MARIADB_EXTENDED_SERVER(mysql)\
(!(mysql->server_capabilities & CLIENT_MYSQL))
#define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\
MARIADB_CLIENT_STMT_BULK_OPERATIONS|\
MARIADB_CLIENT_EXTENDED_METADATA)
MARIADB_CLIENT_EXTENDED_METADATA|\
MARIADB_CLIENT_CACHE_METADATA)
#define CLIENT_SUPPORTED_FLAGS (CLIENT_MYSQL |\
CLIENT_FOUND_ROWS |\

View File

@@ -2300,12 +2300,84 @@ corrupted:
return -1;
}
static int ma_deep_copy_field(const MYSQL_FIELD *src, MYSQL_FIELD *dst,
MA_MEM_ROOT *r)
{
#define MA_STRDUP(f) \
do \
{ \
if (src->f) \
{ \
if ((dst->f= ma_strdup_root(r, src->f)) == NULL) \
return -1; \
} \
else \
{ \
dst->f= NULL; \
} \
} \
while (0)
MA_STRDUP(catalog);
MA_STRDUP(db);
MA_STRDUP(def);
MA_STRDUP(name);
MA_STRDUP(org_name);
MA_STRDUP(org_table);
MA_STRDUP(table);
#undef MA_STRDUP
dst->catalog_length= src->catalog_length;
dst->charsetnr= src->charsetnr;
dst->db_length= src->db_length;
dst->decimals= src->decimals;
dst->def_length= src->def_length;
dst->extension=
src->extension
? ma_field_extension_deep_dup(r,
src->extension)
: NULL;
dst->flags= src->flags;
dst->length= src->length;
dst->max_length = src->max_length;
dst->name_length= src->name_length;
dst->org_name_length= src->org_name_length;
dst->org_table_length= src->org_table_length;
dst->table_length= src->table_length;
dst->type= src->type;
return 0;
}
MYSQL_FIELD *ma_duplicate_resultset_metadata(MYSQL_FIELD *fields, size_t count,
MA_MEM_ROOT *memroot)
{
size_t i;
MYSQL_FIELD *result=
(MYSQL_FIELD *) ma_alloc_root(memroot, sizeof(MYSQL_FIELD) * count);
if (!result)
return NULL;
for (i= 0; i < count; i++)
{
if (ma_deep_copy_field(&fields[i], &result[i], memroot))
return NULL;
}
return result;
}
int mthd_my_read_query_result(MYSQL *mysql)
{
uchar *pos;
ulong field_count;
MYSQL_DATA *fields;
ulong length;
const uchar *end;
uchar has_metadata;
my_bool can_local_infile= (mysql->options.extension) && (mysql->extension->auto_local_infile != WAIT_FOR_QUERY);
if (mysql->options.extension && mysql->extension->auto_local_infile == ACCEPT_FILE_REQUEST)
@@ -2318,6 +2390,7 @@ int mthd_my_read_query_result(MYSQL *mysql)
free_old_query(mysql); /* Free old result */
get_info:
pos=(uchar*) mysql->net.read_pos;
end= pos + length;
if ((field_count= net_field_length(&pos)) == 0)
return ma_read_ok_packet(mysql, pos, length);
if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
@@ -2328,16 +2401,45 @@ get_info:
return(-1);
goto get_info; /* Get info packet */
}
has_metadata= 1;
if (ma_supports_cache_metadata(mysql))
{
assert(mysql->fields == NULL);
if (pos < end)
{
has_metadata= *pos;
pos++;
}
}
if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS;
mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,
if (has_metadata)
{
if (!(fields= mysql->methods->db_read_rows(mysql, (MYSQL_FIELD *) 0,
ma_result_set_rows(mysql))))
return(-1);
if (!(mysql->fields=unpack_fields(mysql, fields, &mysql->field_alloc,
return (-1);
if (!(mysql->fields= unpack_fields(mysql, fields, &mysql->field_alloc,
(uint) field_count, 1)))
return(-1);
return (-1);
}
else
{
/* Read EOF, to get the status and warning count. */
if ((length= ma_net_safe_read(mysql)) == packet_error)
{
return -1;
}
pos= (uchar *) mysql->net.read_pos;
if (length != 5 || pos[0] != 0xfe)
{
return -1;
}
mysql->warning_count= uint2korr(pos + 1);
mysql->server_status= uint2korr(pos + 3);
}
mysql->status=MYSQL_STATUS_GET_RESULT;
mysql->field_count=field_count;
return(0);

View File

@@ -56,6 +56,7 @@
#include <mysql/client_plugin.h>
#include <ma_common.h>
#include "ma_priv.h"
#include <assert.h>
#define UPDATE_STMT_ERROR(stmt)\
@@ -1648,7 +1649,8 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned lon
stmt->param_count= 0;
stmt->field_count= 0;
stmt->params= 0;
stmt->fields= NULL;
stmt->params= NULL;
int4store(stmt_id, stmt->stmt_id);
if (mysql->methods->db_command(mysql, COM_STMT_CLOSE, stmt_id,
@@ -1803,55 +1805,32 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
static int madb_alloc_stmt_fields(MYSQL_STMT *stmt)
{
uint i;
MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
MYSQL *mysql= stmt->mysql;
if (!mysql->field_count)
return 0;
if (stmt->mysql->field_count)
stmt->field_count= mysql->field_count;
if (mysql->fields)
{
/* Column info was sent by server */
ma_free_root(fields_ma_alloc_root, MYF(0));
if (!(stmt->fields= (MYSQL_FIELD *)ma_alloc_root(fields_ma_alloc_root,
sizeof(MYSQL_FIELD) * stmt->mysql->field_count)))
if (!(stmt->fields= ma_duplicate_resultset_metadata(
mysql->fields, mysql->field_count,
fields_ma_alloc_root)))
{
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return(1);
}
stmt->field_count= stmt->mysql->field_count;
for (i=0; i < stmt->field_count; i++)
{
if (stmt->mysql->fields[i].db)
stmt->fields[i].db= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].db);
if (stmt->mysql->fields[i].table)
stmt->fields[i].table= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].table);
if (stmt->mysql->fields[i].org_table)
stmt->fields[i].org_table= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].org_table);
if (stmt->mysql->fields[i].name)
stmt->fields[i].name= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].name);
if (stmt->mysql->fields[i].org_name)
stmt->fields[i].org_name= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].org_name);
if (stmt->mysql->fields[i].catalog)
stmt->fields[i].catalog= ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].catalog);
stmt->fields[i].def= stmt->mysql->fields[i].def ? ma_strdup_root(fields_ma_alloc_root, stmt->mysql->fields[i].def) : NULL;
stmt->fields[i].type= stmt->mysql->fields[i].type;
stmt->fields[i].length= stmt->mysql->fields[i].length;
stmt->fields[i].flags= stmt->mysql->fields[i].flags;
stmt->fields[i].decimals= stmt->mysql->fields[i].decimals;
stmt->fields[i].charsetnr= stmt->mysql->fields[i].charsetnr;
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))))
{
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return(1);
return (1);
}
}
memset(stmt->bind, 0, stmt->field_count * sizeof(MYSQL_BIND));
stmt->bind_result_done= 0;
}
return(0);
}
@@ -1863,11 +1842,36 @@ int stmt_read_execute_response(MYSQL_STMT *stmt)
if (!mysql)
return(1);
ret= test((mysql->methods->db_read_stmt_result &&
mysql->methods->db_read_stmt_result(mysql)));
/* if a reconnect occurred, our connection handle is invalid */
if (!stmt->mysql)
return(1);
return (1);
ret= test((mysql->methods->db_read_stmt_result &&
mysql->methods->db_read_stmt_result(mysql)));
if (!ret && mysql->field_count && !mysql->fields)
{
/*
Column info was not sent by server, copy
from stmt->fields
*/
assert(stmt->fields);
/*
Too bad, C/C resets stmt->field_count to 0
before reading SP output variables result sets.
*/
if(!stmt->field_count)
stmt->field_count = mysql->field_count;
else
assert(mysql->field_count == stmt->field_count);
mysql->fields= ma_duplicate_resultset_metadata(
stmt->fields, stmt->field_count, &mysql->field_alloc);
if (!mysql->fields)
{
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return (1);
}
}
/* update affected rows, also if an error occurred */
stmt->upsert_status.affected_rows= stmt->mysql->affected_rows;

View File

@@ -267,7 +267,10 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
memset(buff + 9, 0, 32-9);
if (!(mysql->server_capabilities & CLIENT_MYSQL))
{
mysql->extension->mariadb_client_flag = MARIADB_CLIENT_SUPPORTED_FLAGS >> 32;
uint server_extended_cap= mysql->extension->mariadb_server_capabilities;
uint client_extended_cap= (uint)(MARIADB_CLIENT_SUPPORTED_FLAGS >> 32);
mysql->extension->mariadb_client_flag=
server_extended_cap & client_extended_cap;
int4store(buff + 28, mysql->extension->mariadb_client_flag);
}
end= buff+32;