Commit e7608a78 authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-8931: (server part of) session state tracking

initial commit to test
parent 468a6ad7
...@@ -87,6 +87,15 @@ enum enum_mysql_set_option ...@@ -87,6 +87,15 @@ enum enum_mysql_set_option
MYSQL_OPTION_MULTI_STATEMENTS_ON, MYSQL_OPTION_MULTI_STATEMENTS_ON,
MYSQL_OPTION_MULTI_STATEMENTS_OFF MYSQL_OPTION_MULTI_STATEMENTS_OFF
}; };
enum enum_session_state_type
{
SESSION_TRACK_SYSTEM_VARIABLES,
SESSION_TRACK_SCHEMA,
SESSION_TRACK_STATE_CHANGE,
SESSION_TRACK_GTIDS,
SESSION_TRACK_TRANSACTION_CHARACTERISTICS,
SESSION_TRACK_TRANSACTION_STATE
};
my_bool my_net_init(NET *net, Vio* vio, void *thd, unsigned int my_flags); my_bool my_net_init(NET *net, Vio* vio, void *thd, unsigned int my_flags);
void my_net_local_init(NET *net); void my_net_local_init(NET *net);
void net_end(NET *net); void net_end(NET *net);
......
...@@ -72,6 +72,14 @@ ...@@ -72,6 +72,14 @@
#define INDEX_COMMENT_MAXLEN 1024 #define INDEX_COMMENT_MAXLEN 1024
#define TABLE_PARTITION_COMMENT_MAXLEN 1024 #define TABLE_PARTITION_COMMENT_MAXLEN 1024
/*
Maximum length of protocol packet.
OK packet length limit also restricted to this value as any length greater
than this value will have first byte of OK packet to be 254 thus does not
provide a means to identify if this is OK or EOF packet.
*/
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
/* /*
USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain
username and hostname parts of the user identifier with trailing zero in username and hostname parts of the user identifier with trailing zero in
...@@ -221,6 +229,14 @@ enum enum_server_command ...@@ -221,6 +229,14 @@ enum enum_server_command
/* Don't close the connection for a connection with expired password. */ /* Don't close the connection for a connection with expired password. */
#define CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS (1UL << 22) #define CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS (1UL << 22)
/**
Capable of handling server state change information. Its a hint to the
server to include the state change information in Ok packet.
*/
#define CLIENT_SESSION_TRACK (1UL << 23)
/* Client no longer needs EOF packet */
#define CLIENT_DEPRECATE_EOF (1UL << 24)
#define CLIENT_PROGRESS_OBSOLETE (1UL << 29) #define CLIENT_PROGRESS_OBSOLETE (1UL << 29)
#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) #define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
/* /*
...@@ -272,10 +288,12 @@ enum enum_server_command ...@@ -272,10 +288,12 @@ enum enum_server_command
CLIENT_MULTI_RESULTS | \ CLIENT_MULTI_RESULTS | \
CLIENT_PS_MULTI_RESULTS | \ CLIENT_PS_MULTI_RESULTS | \
CLIENT_SSL_VERIFY_SERVER_CERT | \ CLIENT_SSL_VERIFY_SERVER_CERT | \
CLIENT_REMEMBER_OPTIONS | \ CLIENT_REMEMBER_OPTIONS | \
MARIADB_CLIENT_PROGRESS | \ MARIADB_CLIENT_PROGRESS | \
CLIENT_PLUGIN_AUTH | \ CLIENT_PLUGIN_AUTH | \
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \ CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
CLIENT_SESSION_TRACK |\
CLIENT_DEPRECATE_EOF |\
CLIENT_CONNECT_ATTRS |\ CLIENT_CONNECT_ATTRS |\
MARIADB_CLIENT_COM_MULTI) MARIADB_CLIENT_COM_MULTI)
...@@ -340,6 +358,11 @@ enum enum_server_command ...@@ -340,6 +358,11 @@ enum enum_server_command
*/ */
#define SERVER_STATUS_IN_TRANS_READONLY 8192 #define SERVER_STATUS_IN_TRANS_READONLY 8192
/**
This status flag, when on, implies that one of the state information has
changed on the server because of the execution of the last statement.
*/
#define SERVER_SESSION_STATE_CHANGED (1UL << 14)
/** /**
Server status flags that must be cleared when starting Server status flags that must be cleared when starting
...@@ -356,7 +379,8 @@ enum enum_server_command ...@@ -356,7 +379,8 @@ enum enum_server_command
SERVER_QUERY_WAS_SLOW |\ SERVER_QUERY_WAS_SLOW |\
SERVER_STATUS_DB_DROPPED |\ SERVER_STATUS_DB_DROPPED |\
SERVER_STATUS_CURSOR_EXISTS|\ SERVER_STATUS_CURSOR_EXISTS|\
SERVER_STATUS_LAST_ROW_SENT) SERVER_STATUS_LAST_ROW_SENT|\
SERVER_SESSION_STATE_CHANGED)
#define MYSQL_ERRMSG_SIZE 512 #define MYSQL_ERRMSG_SIZE 512
#define NET_READ_TIMEOUT 30 /* Timeout on read */ #define NET_READ_TIMEOUT 30 /* Timeout on read */
...@@ -523,6 +547,30 @@ enum enum_mysql_set_option ...@@ -523,6 +547,30 @@ enum enum_mysql_set_option
MYSQL_OPTION_MULTI_STATEMENTS_OFF MYSQL_OPTION_MULTI_STATEMENTS_OFF
}; };
/*
Type of state change information that the server can include in the Ok
packet.
Note : 1) session_state_type shouldn't go past 255 (i.e. 1-byte boundary).
2) Modify the definition of SESSION_TRACK_END when a new member is
added.
*/
enum enum_session_state_type
{
SESSION_TRACK_SYSTEM_VARIABLES, /* Session system variables */
SESSION_TRACK_SCHEMA, /* Current schema */
SESSION_TRACK_STATE_CHANGE, /* track session state changes */
SESSION_TRACK_GTIDS,
SESSION_TRACK_TRANSACTION_CHARACTERISTICS, /* Transaction chistics */
SESSION_TRACK_TRANSACTION_STATE /* Transaction state */
};
#define SESSION_TRACK_BEGIN SESSION_TRACK_SYSTEM_VARIABLES
#define SESSION_TRACK_END SESSION_TRACK_TRANSACTION_STATE
#define IS_SESSION_STATE_TYPE(T) \
(((int)(T) >= SESSION_TRACK_BEGIN) && ((T) <= SESSION_TRACK_END))
#define net_new_transaction(net) ((net)->pkt_nr=0) #define net_new_transaction(net) ((net)->pkt_nr=0)
#ifdef __cplusplus #ifdef __cplusplus
...@@ -641,6 +689,7 @@ my_ulonglong net_field_length_ll(uchar **packet); ...@@ -641,6 +689,7 @@ my_ulonglong net_field_length_ll(uchar **packet);
my_ulonglong safe_net_field_length_ll(uchar **packet, size_t packet_len); my_ulonglong safe_net_field_length_ll(uchar **packet, size_t packet_len);
uchar *net_store_length(uchar *pkg, ulonglong length); uchar *net_store_length(uchar *pkg, ulonglong length);
uchar *safe_net_store_length(uchar *pkg, size_t pkg_len, ulonglong length); uchar *safe_net_store_length(uchar *pkg, size_t pkg_len, ulonglong length);
unsigned int net_length_size(ulonglong num);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -112,6 +112,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ...@@ -112,6 +112,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/item_windowfunc.cc ../sql/sql_window.cc ../sql/item_windowfunc.cc ../sql/sql_window.cc
../sql/sql_cte.cc ../sql/sql_cte.cc
../sql/temporary_tables.cc ../sql/temporary_tables.cc
../sql/session_tracker.cc
${GEN_SOURCES} ${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE} ${MYSYS_LIBWRAP_SOURCE}
) )
......
...@@ -1172,7 +1172,8 @@ bool ...@@ -1172,7 +1172,8 @@ bool
net_send_ok(THD *thd, net_send_ok(THD *thd,
uint server_status, uint statement_warn_count, uint server_status, uint statement_warn_count,
ulonglong affected_rows, ulonglong id, const char *message, ulonglong affected_rows, ulonglong id, const char *message,
bool unused __attribute__((unused))) bool unused1 __attribute__((unused)),
bool unused2 __attribute__((unused)))
{ {
DBUG_ENTER("emb_net_send_ok"); DBUG_ENTER("emb_net_send_ok");
MYSQL_DATA *data; MYSQL_DATA *data;
......
...@@ -903,6 +903,11 @@ The following options may be given as the first argument: ...@@ -903,6 +903,11 @@ The following options may be given as the first argument:
files within specified directory files within specified directory
--server-id=# Uniquely identifies the server instance in the community --server-id=# Uniquely identifies the server instance in the community
of replication partners of replication partners
--session-track-schema
Track changes to the 'default schema'.
(Defaults to on; use --skip-session-track-schema to disable.)
--session-track-state-change
Track changes to the 'session state'.
--show-slave-auth-info --show-slave-auth-info
Show user and password in SHOW SLAVE HOSTS on this Show user and password in SHOW SLAVE HOSTS on this
master. master.
...@@ -1385,6 +1390,8 @@ safe-user-create FALSE ...@@ -1385,6 +1390,8 @@ safe-user-create FALSE
secure-auth TRUE secure-auth TRUE
secure-file-priv (No default value) secure-file-priv (No default value)
server-id 1 server-id 1
session-track-schema TRUE
session-track-state-change FALSE
show-slave-auth-info FALSE show-slave-auth-info FALSE
silent-startup FALSE silent-startup FALSE
skip-grant-tables TRUE skip-grant-tables TRUE
......
...@@ -3327,6 +3327,34 @@ NUMERIC_BLOCK_SIZE 1 ...@@ -3327,6 +3327,34 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL ENUM_VALUE_LIST NULL
READ_ONLY NO READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME SESSION_TRACK_SCHEMA
SESSION_VALUE ON
GLOBAL_VALUE ON
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE ON
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Track changes to the 'default schema'.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME SESSION_TRACK_STATE_CHANGE
SESSION_VALUE OFF
GLOBAL_VALUE OFF
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE OFF
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Track changes to the 'session state'.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME SKIP_EXTERNAL_LOCKING VARIABLE_NAME SKIP_EXTERNAL_LOCKING
SESSION_VALUE NULL SESSION_VALUE NULL
GLOBAL_VALUE ON GLOBAL_VALUE ON
......
...@@ -3789,6 +3789,34 @@ NUMERIC_BLOCK_SIZE 1 ...@@ -3789,6 +3789,34 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL ENUM_VALUE_LIST NULL
READ_ONLY NO READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME SESSION_TRACK_SCHEMA
SESSION_VALUE ON
GLOBAL_VALUE ON
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE ON
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Track changes to the 'default schema'.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME SESSION_TRACK_STATE_CHANGE
SESSION_VALUE OFF
GLOBAL_VALUE OFF
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE OFF
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BOOLEAN
VARIABLE_COMMENT Track changes to the 'session state'.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME SKIP_EXTERNAL_LOCKING VARIABLE_NAME SKIP_EXTERNAL_LOCKING
SESSION_VALUE NULL SESSION_VALUE NULL
GLOBAL_VALUE ON GLOBAL_VALUE ON
......
...@@ -186,3 +186,25 @@ uchar *safe_net_store_length(uchar *packet, size_t packet_len, ulonglong length) ...@@ -186,3 +186,25 @@ uchar *safe_net_store_length(uchar *packet, size_t packet_len, ulonglong length)
return packet+8; return packet+8;
} }
/**
The length of space required to store the resulting length-encoded integer
for the given number. This function can be used at places where one needs to
dynamically allocate the buffer for a given number to be stored as length-
encoded integer.
@param num [IN] the input number
@return length of buffer needed to store this number [1, 3, 4, 9].
*/
uint net_length_size(ulonglong num)
{
if (num < (ulonglong) 251LL)
return 1;
if (num < (ulonglong) 65536LL)
return 3;
if (num < (ulonglong) 16777216LL)
return 4;
return 9;
}
...@@ -95,7 +95,9 @@ SET (SQL_SOURCE ...@@ -95,7 +95,9 @@ SET (SQL_SOURCE
../sql-common/client_plugin.c ../sql-common/client_plugin.c
opt_range.cc opt_range.h opt_sum.cc opt_range.cc opt_range.h opt_sum.cc
../sql-common/pack.c parse_file.cc password.c procedure.cc ../sql-common/pack.c parse_file.cc password.c procedure.cc
protocol.cc records.cc repl_failsafe.cc rpl_filter.cc set_var.cc protocol.cc records.cc repl_failsafe.cc rpl_filter.cc
session_tracker.cc
set_var.cc
slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc
sp_rcontext.cc spatial.cc sql_acl.cc sql_analyse.cc sql_base.cc sp_rcontext.cc spatial.cc sql_acl.cc sql_analyse.cc sql_base.cc
sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h
......
...@@ -117,7 +117,6 @@ extern my_bool thd_net_is_killed(); ...@@ -117,7 +117,6 @@ extern my_bool thd_net_is_killed();
#endif #endif
#define TEST_BLOCKING 8 #define TEST_BLOCKING 8
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
static my_bool net_write_buff(NET *, const uchar *, ulong); static my_bool net_write_buff(NET *, const uchar *, ulong);
......
...@@ -35,7 +35,8 @@ static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; ...@@ -35,7 +35,8 @@ static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
/* Declared non-static only because of the embedded library. */ /* Declared non-static only because of the embedded library. */
bool net_send_error_packet(THD *, uint, const char *, const char *); bool net_send_error_packet(THD *, uint, const char *, const char *);
/* Declared non-static only because of the embedded library. */ /* Declared non-static only because of the embedded library. */
bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *, bool); bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *,
bool, bool);
/* Declared non-static only because of the embedded library. */ /* Declared non-static only because of the embedded library. */
bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count); bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count);
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
...@@ -197,7 +198,8 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err, ...@@ -197,7 +198,8 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err,
@param affected_rows Number of rows changed by statement @param affected_rows Number of rows changed by statement
@param id Auto_increment id for first row (if used) @param id Auto_increment id for first row (if used)
@param message Message to send to the client (Used by mysql_status) @param message Message to send to the client (Used by mysql_status)
@param is_eof this called inted of old EOF packet
@return @return
@retval FALSE The message was successfully sent @retval FALSE The message was successfully sent
@retval TRUE An error occurred and the messages wasn't sent properly @retval TRUE An error occurred and the messages wasn't sent properly
...@@ -209,10 +211,18 @@ bool ...@@ -209,10 +211,18 @@ bool
net_send_ok(THD *thd, net_send_ok(THD *thd,
uint server_status, uint statement_warn_count, uint server_status, uint statement_warn_count,
ulonglong affected_rows, ulonglong id, const char *message, ulonglong affected_rows, ulonglong id, const char *message,
bool is_eof,
bool skip_flush) bool skip_flush)
{ {
NET *net= &thd->net; NET *net= &thd->net;
uchar buff[MYSQL_ERRMSG_SIZE+10],*pos; StringBuffer<MYSQL_ERRMSG_SIZE + 10> store;
/*
To be used to manage the data storage in case session state change
information is present.
*/
bool state_changed= false;
bool error= FALSE; bool error= FALSE;
DBUG_ENTER("net_send_ok"); DBUG_ENTER("net_send_ok");
...@@ -222,38 +232,82 @@ net_send_ok(THD *thd, ...@@ -222,38 +232,82 @@ net_send_ok(THD *thd,
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
buff[0]=0; // No fields /*
pos=net_store_length(buff+1,affected_rows); OK send instead of EOF still require 0xFE header, but OK packet content.
pos=net_store_length(pos, id); */
if (is_eof)
{
DBUG_ASSERT(thd->client_capabilities & CLIENT_DEPRECATE_EOF);
store.q_append((char)254);
}
else
store.q_append('\0');
/* affected rows */
store.q_net_store_length(affected_rows);
/* last insert id */
store.q_net_store_length(id);
if (thd->client_capabilities & CLIENT_PROTOCOL_41) if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{ {
DBUG_PRINT("info", DBUG_PRINT("info",
("affected_rows: %lu id: %lu status: %u warning_count: %u", ("affected_rows: %lu id: %lu status: %u warning_count: %u",
(ulong) affected_rows, (ulong) affected_rows,
(ulong) id, (ulong) id,
(uint) (server_status & 0xffff), (uint) (server_status & 0xffff),
(uint) statement_warn_count)); (uint) statement_warn_count));
int2store(pos, server_status); store.q_append2b(server_status);
pos+=2;
/* We can only return up to 65535 warnings in two bytes */ /* We can only return up to 65535 warnings in two bytes */
uint tmp= MY_MIN(statement_warn_count, 65535); uint tmp= MY_MIN(statement_warn_count, 65535);
int2store(pos, tmp); store.q_append2b(tmp);
pos+= 2;
} }
else if (net->return_status) // For 4.0 protocol else if (net->return_status) // For 4.0 protocol
{ {
int2store(pos, server_status); store.q_append2b(server_status);
pos+=2;
} }
thd->get_stmt_da()->set_overwrite_status(true); thd->get_stmt_da()->set_overwrite_status(true);
if (message && message[0]) if ((thd->client_capabilities & CLIENT_SESSION_TRACK))
pos= net_store_data(pos, (uchar*) message, strlen(message)); {
error= my_net_write(net, buff, (size_t) (pos-buff)); if (server_status & SERVER_SESSION_STATE_CHANGED)
if (!error && !skip_flush) state_changed= true;
/* the info field */
if (state_changed || (message && message[0]))
{
DBUG_ASSERT(strlen(message) <= MYSQL_ERRMSG_SIZE);
store.q_net_store_data((uchar*) message, message ? strlen(message) : 0);
}
/* session state change information */
if (unlikely(state_changed))
{
store.set_charset(thd->variables.collation_database);
thd->session_tracker.store(thd, &store);
}
}
else if (message && message[0])
{
/* the info field, if there is a message to store */
DBUG_ASSERT(strlen(message) <= MYSQL_ERRMSG_SIZE);
store.q_net_store_data((uchar*) message, strlen(message));
}
if (store.length() > MAX_PACKET_LENGTH)
{
net->error= 1;
net->last_errno= ER_NET_OK_PACKET_TOO_LARGE;
my_error(ER_NET_OK_PACKET_TOO_LARGE, MYF(0));
DBUG_PRINT("info", ("OK packet too large"));
DBUG_RETURN(1);
}
error= my_net_write(net, (const unsigned char*)store.ptr(), store.length());
if (!error && (!skip_flush || is_eof))
error= net_flush(net); error= net_flush(net);
thd->server_status&= ~SERVER_SESSION_STATE_CHANGED;
thd->get_stmt_da()->set_overwrite_status(false); thd->get_stmt_da()->set_overwrite_status(false);
DBUG_PRINT("info", ("OK sent, so no more error sending allowed")); DBUG_PRINT("info", ("OK sent, so no more error sending allowed"));
...@@ -261,6 +315,7 @@ net_send_ok(THD *thd, ...@@ -261,6 +315,7 @@ net_send_ok(THD *thd,
DBUG_RETURN(error); DBUG_RETURN(error);
} }
static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */
/** /**
...@@ -292,6 +347,22 @@ net_send_eof(THD *thd, uint server_status, uint statement_warn_count) ...@@ -292,6 +347,22 @@ net_send_eof(THD *thd, uint server_status, uint statement_warn_count)
NET *net= &thd->net; NET *net= &thd->net;
bool error= FALSE; bool error= FALSE;
DBUG_ENTER("net_send_eof"); DBUG_ENTER("net_send_eof");
/*
Check if client understand new format packets (OK instead of EOF)
Normally end of statement reply is signaled by OK packet, but in case
of binlog dump request an EOF packet is sent instead. Also, old clients
expect EOF packet instead of OK
*/
if ((thd->client_capabilities & CLIENT_DEPRECATE_EOF) &&
(thd->get_command() != COM_BINLOG_DUMP ))
{
error= net_send_ok(thd, server_status, statement_warn_count, 0, 0, NULL,
true, false);
DBUG_RETURN(error);
}
/* Set to TRUE if no active vio, to work well in case of --init-file */ /* Set to TRUE if no active vio, to work well in case of --init-file */
if (net->vio != 0) if (net->vio != 0)
{ {
...@@ -546,9 +617,9 @@ bool Protocol::send_ok(uint server_status, uint statement_warn_count, ...@@ -546,9 +617,9 @@ bool Protocol::send_ok(uint server_status, uint statement_warn_count,
const char *message, bool skip_flush) const char *message, bool skip_flush)
{ {
DBUG_ENTER("Protocol::send_ok"); DBUG_ENTER("Protocol::send_ok");
const bool retval= const bool retval=
net_send_ok(thd, server_status, statement_warn_count, net_send_ok(thd, server_status, statement_warn_count,
affected_rows, last_insert_id, message, skip_flush); affected_rows, last_insert_id, message, false, skip_flush);
DBUG_RETURN(retval); DBUG_RETURN(retval);
} }
...@@ -562,7 +633,7 @@ bool Protocol::send_ok(uint server_status, uint statement_warn_count, ...@@ -562,7 +633,7 @@ bool Protocol::send_ok(uint server_status, uint statement_warn_count,
bool Protocol::send_eof(uint server_status, uint statement_warn_count) bool Protocol::send_eof(uint server_status, uint statement_warn_count)
{ {
DBUG_ENTER("Protocol::send_eof"); DBUG_ENTER("Protocol::send_eof");
const bool retval= net_send_eof(thd, server_status, statement_warn_count); bool retval= net_send_eof(thd, server_status, statement_warn_count);
DBUG_RETURN(retval); DBUG_RETURN(retval);
} }
...@@ -862,14 +933,19 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags) ...@@ -862,14 +933,19 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags)
if (flags & SEND_EOF) if (flags & SEND_EOF)
{ {
/*
Mark the end of meta-data result set, and store thd->server_status, /* if it is new client do not send EOF packet */
to show that there is no cursor. if (!(thd->client_capabilities & CLIENT_DEPRECATE_EOF))
Send no warning information, as it will be sent at statement end. {
*/ /*
if (write_eof_packet(thd, &thd->net, thd->server_status, Mark the end of meta-data result set, and store thd->server_status,
thd->get_stmt_da()->current_statement_warn_count())) to show that there is no cursor.
DBUG_RETURN(1); Send no warning information, as it will be sent at statement end.
*/
if (write_eof_packet(thd, &thd->net, thd->server_status,
thd->get_stmt_da()->current_statement_warn_count()))
DBUG_RETURN(1);
}
} }
DBUG_RETURN(prepare_for_send(list->elements)); DBUG_RETURN(prepare_for_send(list->elements));
...@@ -1505,6 +1581,7 @@ bool Protocol_binary::store_time(MYSQL_TIME *tm, int decimals) ...@@ -1505,6 +1581,7 @@ bool Protocol_binary::store_time(MYSQL_TIME *tm, int decimals)
bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params) bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params)
{ {
bool ret;
if (!(thd->client_capabilities & CLIENT_PS_MULTI_RESULTS)) if (!(thd->client_capabilities & CLIENT_PS_MULTI_RESULTS))
{ {
/* The client does not support OUT-parameters. */ /* The client does not support OUT-parameters. */
...@@ -1558,8 +1635,7 @@ bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params) ...@@ -1558,8 +1635,7 @@ bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params)
/* Restore THD::server_status. */ /* Restore THD::server_status. */
thd->server_status&= ~SERVER_PS_OUT_PARAMS; thd->server_status&= ~SERVER_PS_OUT_PARAMS;
/* Send EOF-packet. */ ret= net_send_eof(thd, thd->server_status, 0);
net_send_eof(thd, thd->server_status, 0);
/* /*
Reset SERVER_MORE_RESULTS_EXISTS bit, because this is the last packet Reset SERVER_MORE_RESULTS_EXISTS bit, because this is the last packet
...@@ -1567,5 +1643,5 @@ bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params) ...@@ -1567,5 +1643,5 @@ bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params)
*/ */
thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
return FALSE; return ret ? FALSE : TRUE;
} }
/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2016, MariaDB
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-1301 USA */
#include "session_tracker.h"
#include "hash.h"
#include "table.h"
#include "rpl_gtid.h"
#include "sql_class.h"
#include "sql_show.h"
#include "sql_plugin.h"
class Not_implemented_tracker : public State_tracker
{
public:
bool enable(THD *thd)
{ return false; }
bool check(THD *, set_var *)
{ return false; }
bool update(THD *)
{ return false; }
bool store(THD *, String *)
{ return false; }
void mark_as_changed(THD *, LEX_CSTRING *tracked_item_name)
{}
};
/**
Current_schema_tracker,
This is a tracker class that enables & manages the tracking of current
schema for a particular connection.
*/
class Current_schema_tracker : public State_tracker
{
private:
bool schema_track_inited;
void reset();
public:
Current_schema_tracker()
{
schema_track_inited= false;
}
bool enable(THD *thd)
{ return update(thd); }
bool check(THD *thd, set_var *var)
{ return false; }
bool update(THD *thd);
bool store(THD *thd, String *buf);
void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name);
};
/*
Session_state_change_tracker
This is a boolean tracker class that will monitor any change that contributes
to a session state change.
Attributes that contribute to session state change include:
- Successful change to System variables
- User defined variables assignments
- temporary tables created, altered or deleted
- prepared statements added or removed
- change in current database
- change of current role
*/
class Session_state_change_tracker : public State_tracker
{
private:
void reset();
public:
Session_state_change_tracker();
bool enable(THD *thd)
{ return update(thd); };
bool check(THD *thd, set_var *var)
{ return false; }
bool update(THD *thd);
bool store(THD *thd, String *buf);
void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name);
bool is_state_changed(THD*);
void ensure_enabled(THD *thd)
{}
};
/* To be used in expanding the buffer. */
static const unsigned int EXTRA_ALLOC= 1024;
///////////////////////////////////////////////////////////////////////////////
/**
Enable/disable the tracker based on @@session_track_schema's value.
@param thd [IN] The thd handle.
@return
false (always)
*/
bool Current_schema_tracker::update(THD *thd)
{
m_enabled= thd->variables.session_track_schema;
return false;
}
/**
Store the schema name as length-encoded string in the specified buffer.
@param thd [IN] The thd handle.
@paran buf [INOUT] Buffer to store the information to.
@reval false Success
@retval true Error
*/
bool Current_schema_tracker::store(THD *thd, String *buf)
{
ulonglong db_length, length;
/*
Protocol made (by unknown reasons) redundant:
It saves length of database name and name of database name +
length of saved length of database length.
*/
length= db_length= thd->db_length;
length += net_length_size(length);
compile_time_assert(SESSION_TRACK_SCHEMA < 251);
compile_time_assert(NAME_LEN < 251);
DBUG_ASSERT(net_length_size(length) < 251);
if (buf->prep_alloc(1 + 1 + length, EXTRA_ALLOC))
return true;
/* Session state type (SESSION_TRACK_SCHEMA) */
buf->q_net_store_length((ulonglong)SESSION_TRACK_SCHEMA);
/* Length of the overall entity. */
buf->q_net_store_length(length);
/* Length and current schema name */
buf->q_net_store_data((const uchar *)thd->db, thd->db_length);
reset();
return false;
}
/**
Mark the tracker as changed.
*/
void Current_schema_tracker::mark_as_changed(THD *thd, LEX_CSTRING *)
{
m_changed= true;
thd->lex->safe_to_cache_query= 0;
thd->server_status|= SERVER_SESSION_STATE_CHANGED;
}
/**
Reset the m_changed flag for next statement.
@return void
*/
void Current_schema_tracker::reset()
{
m_changed= false;
}
///////////////////////////////////////////////////////////////////////////////
Session_state_change_tracker::Session_state_change_tracker()
{
m_changed= false;
}
/**
@Enable/disable the tracker based on @@session_track_state_change value.
@param thd [IN] The thd handle.
@return false (always)
**/
bool Session_state_change_tracker::update(THD *thd)
{
m_enabled= thd->variables.session_track_state_change;
return false;
}
/**
Store the '1' in the specified buffer when state is changed.
@param thd [IN] The thd handle.
@paran buf [INOUT] Buffer to store the information to.
@reval false Success
@retval true Error
**/
bool Session_state_change_tracker::store(THD *thd, String *buf)
{
if (buf->prep_alloc(1 + 1 + 1, EXTRA_ALLOC))
return true;
compile_time_assert(SESSION_TRACK_STATE_CHANGE < 251);
/* Session state type (SESSION_TRACK_STATE_CHANGE) */
buf->q_net_store_length((ulonglong)SESSION_TRACK_STATE_CHANGE);
/* Length of the overall entity (1 byte) */
buf->q_append('\1');
DBUG_ASSERT(is_state_changed(thd));
buf->q_append('1');
reset();
return false;
}
/**
Mark the tracker as changed and associated session
attributes accordingly.
*/
void Session_state_change_tracker::mark_as_changed(THD *thd, LEX_CSTRING *)
{
m_changed= true;
thd->lex->safe_to_cache_query= 0;
thd->server_status|= SERVER_SESSION_STATE_CHANGED;
}
/**
Reset the m_changed flag for next statement.
*/
void Session_state_change_tracker::reset()
{
m_changed= false;
}
/**
Find if there is a session state change.
*/
bool Session_state_change_tracker::is_state_changed(THD *)
{
return m_changed;
}
///////////////////////////////////////////////////////////////////////////////
/**
@brief Initialize session tracker objects.
*/
Session_tracker::Session_tracker()
{
m_trackers[SESSION_SYSVARS_TRACKER]=
new (std::nothrow) Not_implemented_tracker;
m_trackers[CURRENT_SCHEMA_TRACKER]=
new (std::nothrow) Current_schema_tracker;
m_trackers[SESSION_STATE_CHANGE_TRACKER]=
new (std::nothrow) Session_state_change_tracker;
m_trackers[SESSION_GTIDS_TRACKER]=
new (std::nothrow) Not_implemented_tracker;
m_trackers[TRANSACTION_INFO_TRACKER]=
new (std::nothrow) Not_implemented_tracker;
}
/**
@brief Enables the tracker objects.
@param thd [IN] The thread handle.
@return void
*/
void Session_tracker::enable(THD *thd)
{
for (int i= 0; i <= SESSION_TRACKER_END; i ++)
m_trackers[i]->enable(thd);
}
/**
@brief Store all change information in the specified buffer.
@param thd [IN] The thd handle.
@param buf [OUT] Reference to the string buffer to which the state
change data needs to be written.
*/
void Session_tracker::store(THD *thd, String *buf)
{
/* Temporary buffer to store all the changes. */
size_t start;
/*
Probably most track result will fit in 251 byte so lets made it at
least efficient. We allocate 1 byte for length and then will move
string if there is more.
*/
buf->append('\0');
start= buf->length();
/* Get total length. */
for (int i= 0; i <= SESSION_TRACKER_END; i ++)
{
if (m_trackers[i]->is_changed() &&
m_trackers[i]->store(thd, buf))
{
buf->length(start); // it is safer to have 0-length block in case of error
return;
}
}
size_t length= buf->length() - start;
uchar *data= (uchar *)(buf->ptr() + start);
uint size;
if ((size= net_length_size(length)) != 1)
{
if (buf->prep_alloc(size - 1, EXTRA_ALLOC))
{
buf->length(start); // it is safer to have 0-length block in case of error
return;
}
memmove(data + (size - 1), data, length);
}
net_store_length(data - 1, length);
}
#ifndef SESSION_TRACKER_INCLUDED
#define SESSION_TRACKER_INCLUDED
/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2016, MariaDB
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-1301 USA */
#include "m_string.h"
#include "thr_lock.h"
/* forward declarations */
class THD;
class set_var;
class String;
enum enum_session_tracker
{
SESSION_SYSVARS_TRACKER, /* Session system variables */
CURRENT_SCHEMA_TRACKER, /* Current schema */
SESSION_STATE_CHANGE_TRACKER,
SESSION_GTIDS_TRACKER, /* Tracks GTIDs */
TRANSACTION_INFO_TRACKER /* Transaction state */
};
#define SESSION_TRACKER_END TRANSACTION_INFO_TRACKER
/**
State_tracker
An abstract class that defines the interface for any of the server's
'session state change tracker'. A tracker, however, is a sub- class of
this class which takes care of tracking the change in value of a part-
icular session state type and thus defines various methods listed in this
interface. The change information is later serialized and transmitted to
the client through protocol's OK packet.
Tracker system variables :-
A tracker is normally mapped to a system variable. So in order to enable,
disable or modify the sub-entities of a tracker, the user needs to modify
the respective system variable either through SET command or via command
line option. As required in system variable handling, this interface also
includes two functions to help in the verification of the supplied value
(ON_CHECK) and the updation (ON_UPDATE) of the tracker system variable,
namely - check() and update().
*/
class State_tracker
{
protected:
/**
Is tracking enabled for a particular session state type ?
@note: It is cache to avoid virtual functions and checking thd
when we want mark tracker as changed.
*/
bool m_enabled;
/** Has the session state type changed ? */
bool m_changed;
public:
/** Constructor */
State_tracker() : m_enabled(false), m_changed(false)
{}
/** Destructor */
virtual ~State_tracker()
{}
/** Getters */
bool is_enabled() const
{ return m_enabled; }
bool is_changed() const
{ return m_changed; }
/** Called in the constructor of THD*/
virtual bool enable(THD *thd)= 0;
/** To be invoked when the tracker's system variable is checked (ON_CHECK). */
virtual bool check(THD *thd, set_var *var)= 0;
/** To be invoked when the tracker's system variable is updated (ON_UPDATE).*/
virtual bool update(THD *thd)= 0;
/** Store changed data into the given buffer. */
virtual bool store(THD *thd, String *buf)= 0;
/** Mark the entity as changed. */
virtual void mark_as_changed(THD *thd, LEX_CSTRING *name)= 0;
};
/**
Session_tracker
This class holds an object each for all tracker classes and provides
methods necessary for systematic detection and generation of session
state change information.
*/
class Session_tracker
{
private:
State_tracker *m_trackers[SESSION_TRACKER_END + 1];
/* The following two functions are private to disable copying. */
Session_tracker(Session_tracker const &other)
{
DBUG_ASSERT(FALSE);
}
Session_tracker& operator= (Session_tracker const &rhs)
{
DBUG_ASSERT(FALSE);
return *this;
}
public:
Session_tracker();
~Session_tracker()
{
for (int i= 0; i <= SESSION_TRACKER_END; i ++)
delete m_trackers[i];
}
void enable(THD *thd);
/** Returns the pointer to the tracker object for the specified tracker. */
inline State_tracker *get_tracker(enum_session_tracker tracker) const
{
return m_trackers[tracker];
}
inline void mark_as_changed(THD *thd, enum enum_session_tracker tracker,
LEX_CSTRING *data)
{
if (m_trackers[tracker]->is_enabled())
m_trackers[tracker]->mark_as_changed(thd, data);
}
void store(THD *thd, String *main_buf);
};
#endif /* SESSION_TRACKER_INCLUDED */
...@@ -204,8 +204,28 @@ bool sys_var::update(THD *thd, set_var *var) ...@@ -204,8 +204,28 @@ bool sys_var::update(THD *thd, set_var *var)
(on_update && on_update(this, thd, OPT_GLOBAL)); (on_update && on_update(this, thd, OPT_GLOBAL));
} }
else else
return session_update(thd, var) || {
bool ret= session_update(thd, var) ||
(on_update && on_update(this, thd, OPT_SESSION)); (on_update && on_update(this, thd, OPT_SESSION));
/*
Make sure we don't session-track variables that are not actually
part of the session. tx_isolation and and tx_read_only for example
exist as GLOBAL, SESSION, and one-shot ("for next transaction only").
*/
if ((var->type == OPT_SESSION) && (!ret))
{
/*
Here MySQL sends variable name to avoid reporting change of
the tracker itself, but we decided that it is not needed
*/
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
NULL);
}
return ret;
}
} }
uchar *sys_var::session_value_ptr(THD *thd, const LEX_STRING *base) uchar *sys_var::session_value_ptr(THD *thd, const LEX_STRING *base)
...@@ -867,6 +887,8 @@ int set_var_user::update(THD *thd) ...@@ -867,6 +887,8 @@ int set_var_user::update(THD *thd)
MYF(0)); MYF(0));
return -1; return -1;
} }
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
return 0; return 0;
} }
...@@ -914,7 +936,11 @@ int set_var_role::check(THD *thd) ...@@ -914,7 +936,11 @@ int set_var_role::check(THD *thd)
int set_var_role::update(THD *thd) int set_var_role::update(THD *thd)
{ {
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
return acl_setrole(thd, role.str, access); int res= acl_setrole(thd, role.str, access);
if (!res)
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
NULL);
return res;
#else #else
return 0; return 0;
#endif #endif
...@@ -968,6 +994,8 @@ int set_var_collation_client::update(THD *thd) ...@@ -968,6 +994,8 @@ int set_var_collation_client::update(THD *thd)
{ {
thd->update_charset(character_set_client, collation_connection, thd->update_charset(character_set_client, collation_connection,
character_set_results); character_set_results);
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
thd->protocol_text.init(thd); thd->protocol_text.init(thd);
thd->protocol_binary.init(thd); thd->protocol_binary.init(thd);
return 0; return 0;
......
...@@ -385,7 +385,7 @@ extern SHOW_COMP_OPTION have_openssl; ...@@ -385,7 +385,7 @@ extern SHOW_COMP_OPTION have_openssl;
SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type); SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond); int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond);
sys_var *find_sys_var(THD *thd, const char *str, uint length=0); sys_var *find_sys_var(THD *thd, const char *str, size_t length=0);
int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free); int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free);
#define SYSVAR_AUTOSIZE(VAR,VAL) \ #define SYSVAR_AUTOSIZE(VAR,VAL) \
......
...@@ -7139,7 +7139,6 @@ ER_KILL_QUERY_DENIED_ERROR ...@@ -7139,7 +7139,6 @@ ER_KILL_QUERY_DENIED_ERROR
ER_NO_EIS_FOR_FIELD ER_NO_EIS_FOR_FIELD
eng "Engine-independent statistics are not collected for column '%s'" eng "Engine-independent statistics are not collected for column '%s'"
ukr "Незалежна від типу таблиці статистика не збирається для стовбця '%s'" ukr "Незалежна від типу таблиці статистика не збирається для стовбця '%s'"
# #
# Internal errors, not used # Internal errors, not used
# #
...@@ -7151,6 +7150,10 @@ skip-to-error-number 3000 ...@@ -7151,6 +7150,10 @@ skip-to-error-number 3000
ER_MYSQL_57_TEST ER_MYSQL_57_TEST
eng "5.7 test" eng "5.7 test"
ER_NET_OK_PACKET_TOO_LARGE 08S01
eng "OK packet too large"
ukr "Пакет OK надто великий"
# MariaDB extra error numbers starts from 4000 # MariaDB extra error numbers starts from 4000
skip-to-error-number 4000 skip-to-error-number 4000
......
...@@ -2977,6 +2977,16 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, ...@@ -2977,6 +2977,16 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
reinit_stmt_before_use(thd, m_lex); reinit_stmt_before_use(thd, m_lex);
#ifndef EMBEDDED_LIBRARY
/*
if there was instruction which changed tracking state before, result
can go with this command OK packet, so better do not cache the result.
*/
if ((thd->client_capabilities & CLIENT_SESSION_TRACK) &&
(thd->server_status & SERVER_SESSION_STATE_CHANGED))
thd->lex->safe_to_cache_query= 0;
#endif
if (open_tables) if (open_tables)
res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables); res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
......
...@@ -1465,6 +1465,9 @@ void THD::init(void) ...@@ -1465,6 +1465,9 @@ void THD::init(void)
/* Initialize the Debug Sync Facility. See debug_sync.cc. */ /* Initialize the Debug Sync Facility. See debug_sync.cc. */
debug_sync_init_thread(this); debug_sync_init_thread(this);
#endif /* defined(ENABLED_DEBUG_SYNC) */ #endif /* defined(ENABLED_DEBUG_SYNC) */
session_tracker.enable(this);
apc_target.init(&LOCK_thd_data); apc_target.init(&LOCK_thd_data);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <mysql/psi/mysql_idle.h> #include <mysql/psi/mysql_idle.h>
#include <mysql/psi/mysql_table.h> #include <mysql/psi/mysql_table.h>
#include <mysql_com_server.h> #include <mysql_com_server.h>
#include "session_tracker.h"
extern "C" extern "C"
void set_thd_stage_info(void *thd, void set_thd_stage_info(void *thd,
...@@ -688,6 +689,8 @@ typedef struct system_variables ...@@ -688,6 +689,8 @@ typedef struct system_variables
my_bool pseudo_slave_mode; my_bool pseudo_slave_mode;
my_bool session_track_schema;
my_bool session_track_state_change;
} SV; } SV;
/** /**
...@@ -4054,6 +4057,7 @@ class THD :public Statement, ...@@ -4054,6 +4057,7 @@ class THD :public Statement,
LEX_STRING invoker_host; LEX_STRING invoker_host;
public: public:
Session_tracker session_tracker;
/* /*
Flag, mutex and condition for a thread to wait for a signal from another Flag, mutex and condition for a thread to wait for a signal from another
thread. thread.
......
...@@ -1035,7 +1035,10 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent) ...@@ -1035,7 +1035,10 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
it to 0. it to 0.
*/ */
if (thd->db && cmp_db_names(thd->db, db) && !error) if (thd->db && cmp_db_names(thd->db, db) && !error)
{
mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
thd->session_tracker.mark_as_changed(thd, CURRENT_SCHEMA_TRACKER, NULL);
}
my_dirend(dirp); my_dirend(dirp);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -1459,7 +1462,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) ...@@ -1459,7 +1462,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
DBUG_RETURN(FALSE); goto done;
} }
else else
{ {
...@@ -1476,8 +1479,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) ...@@ -1476,8 +1479,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL, mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL,
system_charset_info); system_charset_info);
goto done;
DBUG_RETURN(FALSE);
} }
/* /*
...@@ -1564,8 +1566,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) ...@@ -1564,8 +1566,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
/* The operation succeed. */ /* The operation succeed. */
goto done;
DBUG_RETURN(FALSE);
} }
else else
{ {
...@@ -1589,6 +1590,9 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) ...@@ -1589,6 +1590,9 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
mysql_change_db_impl(thd, &new_db_file_name, db_access, db_default_cl); mysql_change_db_impl(thd, &new_db_file_name, db_access, db_default_cl);
done:
thd->session_tracker.mark_as_changed(thd, CURRENT_SCHEMA_TRACKER, NULL);
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
......
...@@ -3852,6 +3852,12 @@ mysql_execute_command(THD *thd) ...@@ -3852,6 +3852,12 @@ mysql_execute_command(THD *thd)
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.tmp_table()) if (create_info.tmp_table())
thd->variables.option_bits|= OPTION_KEEP_LOG; thd->variables.option_bits|= OPTION_KEEP_LOG;
/* in case of create temp tables if @@session_track_state_change is
ON then send session state notification in OK packet */
if(create_info.options & HA_LEX_CREATE_TMP_TABLE)
thd->session_tracker.mark_as_changed(thd,
SESSION_STATE_CHANGE_TRACKER,
NULL);
my_ok(thd); my_ok(thd);
} }
} }
...@@ -4608,6 +4614,14 @@ mysql_execute_command(THD *thd) ...@@ -4608,6 +4614,14 @@ mysql_execute_command(THD *thd)
/* DDL and binlog write order are protected by metadata locks. */ /* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table()); res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table());
/* when dropping temporary tables if @@session_track_state_change is ON then
send the boolean tracker in the OK packet */
if(!res && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
NULL);
}
break; break;
} }
case SQLCOM_SHOW_PROCESSLIST: case SQLCOM_SHOW_PROCESSLIST:
......
...@@ -2781,7 +2781,7 @@ static void update_func_double(THD *thd, struct st_mysql_sys_var *var, ...@@ -2781,7 +2781,7 @@ static void update_func_double(THD *thd, struct st_mysql_sys_var *var,
****************************************************************************/ ****************************************************************************/
sys_var *find_sys_var(THD *thd, const char *str, uint length) sys_var *find_sys_var(THD *thd, const char *str, size_t length)
{ {
sys_var *var; sys_var *var;
sys_var_pluginvar *pi= NULL; sys_var_pluginvar *pi= NULL;
......
...@@ -120,6 +120,8 @@ struct st_plugin_int ...@@ -120,6 +120,8 @@ struct st_plugin_int
}; };
extern mysql_mutex_t LOCK_plugin;
/* /*
See intern_plugin_lock() for the explanation for the See intern_plugin_lock() for the explanation for the
conditionally defined plugin_ref type conditionally defined plugin_ref type
......
...@@ -2758,7 +2758,11 @@ void mysql_sql_stmt_prepare(THD *thd) ...@@ -2758,7 +2758,11 @@ void mysql_sql_stmt_prepare(THD *thd)
thd->stmt_map.erase(stmt); thd->stmt_map.erase(stmt);
} }
else else
{
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
NULL);
my_ok(thd, 0L, 0L, "Statement prepared"); my_ok(thd, 0L, 0L, "Statement prepared");
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -3208,6 +3212,8 @@ void mysql_sql_stmt_close(THD *thd) ...@@ -3208,6 +3212,8 @@ void mysql_sql_stmt_close(THD *thd)
else else
{ {
stmt->deallocate(); stmt->deallocate();
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
NULL);
my_ok(thd); my_ok(thd);
} }
} }
......
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. /* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2016, MariaDB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -1157,3 +1158,16 @@ uint convert_to_printable(char *to, size_t to_len, ...@@ -1157,3 +1158,16 @@ uint convert_to_printable(char *to, size_t to_len,
*t= '\0'; *t= '\0';
return t - to; return t - to;
} }
void String::q_net_store_length(ulonglong length)
{
char *pos= (char *) net_store_length((uchar *)(Ptr + str_length), length);
str_length= pos - Ptr;
}
void String::q_net_store_data(const uchar *from, size_t length)
{
q_net_store_length(length);
bool res= append((const char *)from, length);
DBUG_ASSERT(!res);
}
...@@ -495,6 +495,11 @@ class String ...@@ -495,6 +495,11 @@ class String
{ {
Ptr[str_length++] = c; Ptr[str_length++] = c;
} }
void q_append2b(const uint32 n)
{
int2store(Ptr + str_length, n);
str_length += 2;
}
void q_append(const uint32 n) void q_append(const uint32 n)
{ {
int4store(Ptr + str_length, n); int4store(Ptr + str_length, n);
...@@ -559,6 +564,17 @@ class String ...@@ -559,6 +564,17 @@ class String
return Ptr+ old_length; /* Area to use */ return Ptr+ old_length; /* Area to use */
} }
inline bool prep_alloc(uint32 arg_length, uint32 step_alloc)
{
uint32 new_length= arg_length + str_length;
if (new_length > Alloced_length)
{
if (realloc(new_length + step_alloc))
return true;
}
return false;
}
inline bool append(const char *s, uint32 arg_length, uint32 step_alloc) inline bool append(const char *s, uint32 arg_length, uint32 step_alloc)
{ {
uint32 new_length= arg_length + str_length; uint32 new_length= arg_length + str_length;
...@@ -623,6 +639,8 @@ class String ...@@ -623,6 +639,8 @@ class String
{ {
return !sortcmp(this, other, cs); return !sortcmp(this, other, cs);
} }
void q_net_store_length(ulonglong length);
void q_net_store_data(const uchar *from, size_t length);
}; };
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "transaction.h" #include "transaction.h"
#include "sql_audit.h" #include "sql_audit.h"
#ifdef __WIN__ #ifdef __WIN__
#include <io.h> #include <io.h>
#endif #endif
...@@ -9228,6 +9229,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -9228,6 +9229,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{ {
goto err_new_table_cleanup; goto err_new_table_cleanup;
} }
/* in case of alter temp table send the tracker in OK packet */
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
NULL);
} }
......
...@@ -5374,3 +5374,36 @@ static Sys_var_ulong Sys_log_tc_size( ...@@ -5374,3 +5374,36 @@ static Sys_var_ulong Sys_log_tc_size(
DEFAULT(my_getpagesize() * 6), DEFAULT(my_getpagesize() * 6),
BLOCK_SIZE(my_getpagesize())); BLOCK_SIZE(my_getpagesize()));
#endif #endif
static bool update_session_track_schema(sys_var *self, THD *thd,
enum_var_type type)
{
DBUG_ENTER("update_session_track_schema");
DBUG_RETURN(thd->session_tracker.get_tracker(CURRENT_SCHEMA_TRACKER)->update(thd));
}
static Sys_var_mybool Sys_session_track_schema(
"session_track_schema",
"Track changes to the 'default schema'.",
SESSION_VAR(session_track_schema),
CMD_LINE(OPT_ARG), DEFAULT(TRUE),
NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(0),
ON_UPDATE(update_session_track_schema));
static bool update_session_track_state_change(sys_var *self, THD *thd,
enum_var_type type)
{
DBUG_ENTER("update_session_track_state_change");
DBUG_RETURN(thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->update(thd));
}
static Sys_var_mybool Sys_session_track_state_change(
"session_track_state_change",
"Track changes to the 'session state'.",
SESSION_VAR(session_track_state_change),
CMD_LINE(OPT_ARG), DEFAULT(FALSE),
NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(0),
ON_UPDATE(update_session_track_state_change));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment