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

status and session_tracik callback function:

This feature allows client applications to register a callback function,
which is called as soon as the server status changes or session_track
information was sent by the server.

Registration is handled via mysql_optionsv() API function:

mysql_optionsv(mysql, MARIADB_OPT_STATUS_CALLBACK, function, data)

The callback function must be defined as follws:

void status_callback(void *data, enum enum_mariadb_status_info type, ..)

  Parameters:
    - data  Pointer passed with registration of callback function
            (usually a connection handle)
    - type  Information type  STATUS_TYPE or SESSION_TRACK_TYPE

  Variadic Parameters:

  if (type == STATUS_TYPE):
    - server status (unsigned int)

  if (type == SESSION_TRACK_TYPE)
    - enum enum_session_state_type track_type - session track type

    if (track_type == SESSION_TRACK_SYSTEM_VARIABLES)
      - MARIADB_CONST_STRING *key
      - MARIADB_CONST_STRING *value

    else
      - MARIADB_CONST_STRING *value

An example can be found in connection.c (test_status_callback)
This commit is contained in:
Georg Richter
2022-08-02 10:10:50 +02:00
parent 8eff2a866e
commit a8832afa2a
5 changed files with 236 additions and 34 deletions

View File

@@ -1419,6 +1419,10 @@ mysql_real_connect(MYSQL *mysql, const char *host, const char *user,
if (!mysql->methods)
mysql->methods= &MARIADB_DEFAULT_METHODS;
/* set default */
if (!mysql->options.extension || !mysql->options.extension->status_callback)
mysql_optionsv(mysql, MARIADB_OPT_STATUS_CALLBACK, NULL, NULL);
/* if host contains a semicolon, we need to parse connection string */
if (host && strchr(host, ';'))
{
@@ -2430,19 +2434,97 @@ mysql_query(MYSQL *mysql, const char *query)
finish processing it.
*/
int STDCALL
mysql_send_query(MYSQL* mysql, const char* query, unsigned long length)
{
return ma_simple_command(mysql, COM_QUERY, query, length, 1,0);
}
void ma_save_session_track_info(void *ptr, enum enum_mariadb_status_info type, ...)
{
MYSQL *mysql= (MYSQL *)ptr;
enum enum_session_state_type track_type;
va_list ap;
DBUG_ASSERT(mysql != NULL);
/* We only handle SESSION_TRACK_TYPE here */
if (type != SESSION_TRACK_TYPE)
return;
va_start(ap, type);
track_type= va_arg(ap, enum enum_session_state_type);
switch (track_type) {
case SESSION_TRACK_SCHEMA:
case SESSION_TRACK_STATE_CHANGE:
case SESSION_TRACK_TRANSACTION_CHARACTERISTICS:
case SESSION_TRACK_TRANSACTION_STATE:
case SESSION_TRACK_GTIDS:
case SESSION_TRACK_SYSTEM_VARIABLES:
{
LIST *session_item;
MYSQL_LEX_STRING *str;
char *tmp;
MARIADB_CONST_STRING *data1= va_arg(ap, MARIADB_CONST_STRING *);
if (!(session_item= ma_multi_malloc(0,
&session_item, sizeof(LIST),
&str, sizeof(MYSQL_LEX_STRING),
&tmp, data1->length,
NULL)))
goto mem_error;
str->str= tmp;
memcpy(str->str, data1->str, data1->length);
str->length= data1->length;
session_item->data= str;
mysql->extension->session_state[track_type].list= list_add(mysql->extension->session_state[track_type].list,
session_item);
if (track_type == SESSION_TRACK_SYSTEM_VARIABLES)
{
MARIADB_CONST_STRING *data2= va_arg(ap, MARIADB_CONST_STRING *);
if (!(session_item= ma_multi_malloc(0,
&session_item, sizeof(LIST),
&str, sizeof(MYSQL_LEX_STRING),
&tmp, data2->length,
NULL)))
goto mem_error;
str->str= tmp;
memcpy(str->str, data2->str, data2->length);
str->length= data2->length;
session_item->data= str;
mysql->extension->session_state[track_type].list= list_add(mysql->extension->session_state[track_type].list,
session_item);
}
}
break;
}
return;
mem_error:
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return;
}
int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
{
uchar *end= mysql->net.read_pos+length;
size_t item_len;
unsigned int last_server_status= mysql->server_status;
mysql->affected_rows= net_field_length_ll(&pos);
mysql->insert_id= net_field_length_ll(&pos);
mysql->server_status=uint2korr(pos);
/* callback */
if (mysql->options.extension->status_callback &&
mysql->server_status != last_server_status)
mysql->options.extension->status_callback(mysql->options.extension->status_data,
STATUS_TYPE, mysql->server_status);
pos+=2;
mysql->warning_count=uint2korr(pos);
pos+=2;
@@ -2466,8 +2548,6 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
int i;
if (pos < end)
{
LIST *session_item;
MYSQL_LEX_STRING *str= NULL;
enum enum_session_state_type si_type;
uchar *old_pos= pos;
@@ -2483,7 +2563,7 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
while (pos < end)
{
size_t plen;
char *data;
MYSQL_LEX_STRING data1, data2;
si_type= (enum enum_session_state_type)net_field_length(&pos);
switch(si_type) {
@@ -2505,55 +2585,52 @@ int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
plen= net_field_length(&pos);
if (pos + plen > end)
goto corrupted;
if (!(session_item= ma_multi_malloc(0,
&session_item, sizeof(LIST),
&str, sizeof(MYSQL_LEX_STRING),
&data, plen,
NULL)))
goto oom;
str->length= plen;
str->str= data;
memcpy(str->str, (char *)pos, plen);
pos+= plen;
session_item->data= str;
mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item);
data1.str= (char *)pos;
data1.length= plen;
if (si_type != SESSION_TRACK_SYSTEM_VARIABLES)
{
mysql->options.extension->status_callback(mysql->options.extension->status_data,
SESSION_TRACK_TYPE, si_type,
&data1);
if (mysql->net.last_errno)
goto oom;
}
pos+= plen;
/* in case schema has changed, we have to update mysql->db */
if (si_type == SESSION_TRACK_SCHEMA)
{
free(mysql->db);
mysql->db= malloc(plen + 1);
memcpy(mysql->db, str->str, plen);
mysql->db[plen]= 0;
memcpy(mysql->db, data1.str, data1.length);
mysql->db[data1.length]= 0;
}
else if (si_type == SESSION_TRACK_SYSTEM_VARIABLES)
{
my_bool set_charset= 0;
/* make sure that we update charset in case it has changed */
if (!strncmp(str->str, "character_set_client", str->length))
if (!strncmp(data1.str, "character_set_client", plen))
set_charset= 1;
plen= net_field_length(&pos);
if (pos + plen > end)
goto corrupted;
if (!(session_item= ma_multi_malloc(0,
&session_item, sizeof(LIST),
&str, sizeof(MYSQL_LEX_STRING),
&data, plen,
NULL)))
goto oom;
str->length= plen;
str->str= data;
memcpy(str->str, (char *)pos, plen);
data2.str= (char *)pos;
data2.length= plen;
mysql->options.extension->status_callback(mysql->options.extension->status_data,
SESSION_TRACK_TYPE, si_type,
&data1, &data2);
if (mysql->net.last_errno)
goto oom;
pos+= plen;
session_item->data= str;
mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item);
if (set_charset && str->length < CHARSET_NAME_LEN &&
strncmp(mysql->charset->csname, str->str, str->length) != 0)
if (set_charset && plen < CHARSET_NAME_LEN &&
strncmp(mysql->charset->csname, data2.str, data2.length) != 0)
{
char cs_name[CHARSET_NAME_LEN];
const MARIADB_CHARSET_INFO *cs_info;
memcpy(cs_name, str->str, str->length);
cs_name[str->length]= 0;
memcpy(cs_name, data2.str, data2.length);
cs_name[plen]= 0;
if ((cs_info = mysql_find_charset_name(cs_name)))
mysql->charset= cs_info;
}
@@ -3663,6 +3740,19 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
OPT_SET_EXTENDED_VALUE(&mysql->options, rpl_port, (ushort)arg2);
}
break;
case MARIADB_OPT_STATUS_CALLBACK:
{
void *arg2= va_arg(ap, void *);
if (arg1)
{
OPT_SET_EXTENDED_VALUE(&mysql->options, status_callback, arg1);
OPT_SET_EXTENDED_VALUE(&mysql->options, status_data, arg2);
} else {
OPT_SET_EXTENDED_VALUE(&mysql->options, status_callback, ma_save_session_track_info);
OPT_SET_EXTENDED_VALUE(&mysql->options, status_data, mysql);
}
}
break;
default:
va_end(ap);
SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);