mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
MDEV-8931: (server part of) session state tracking
initial commit to test
This commit is contained in:
parent
468a6ad722
commit
e7608a78ef
28 changed files with 928 additions and 46 deletions
|
@ -87,6 +87,15 @@ enum enum_mysql_set_option
|
|||
MYSQL_OPTION_MULTI_STATEMENTS_ON,
|
||||
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);
|
||||
void my_net_local_init(NET *net);
|
||||
void net_end(NET *net);
|
||||
|
|
|
@ -72,6 +72,14 @@
|
|||
#define INDEX_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
|
||||
username and hostname parts of the user identifier with trailing zero in
|
||||
|
@ -221,6 +229,14 @@ enum enum_server_command
|
|||
/* Don't close the connection for a connection with expired password. */
|
||||
#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_SSL_VERIFY_SERVER_CERT (1UL << 30)
|
||||
/*
|
||||
|
@ -272,10 +288,12 @@ enum enum_server_command
|
|||
CLIENT_MULTI_RESULTS | \
|
||||
CLIENT_PS_MULTI_RESULTS | \
|
||||
CLIENT_SSL_VERIFY_SERVER_CERT | \
|
||||
CLIENT_REMEMBER_OPTIONS | \
|
||||
CLIENT_REMEMBER_OPTIONS | \
|
||||
MARIADB_CLIENT_PROGRESS | \
|
||||
CLIENT_PLUGIN_AUTH | \
|
||||
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \
|
||||
CLIENT_SESSION_TRACK |\
|
||||
CLIENT_DEPRECATE_EOF |\
|
||||
CLIENT_CONNECT_ATTRS |\
|
||||
MARIADB_CLIENT_COM_MULTI)
|
||||
|
||||
|
@ -340,6 +358,11 @@ enum enum_server_command
|
|||
*/
|
||||
#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
|
||||
|
@ -356,7 +379,8 @@ enum enum_server_command
|
|||
SERVER_QUERY_WAS_SLOW |\
|
||||
SERVER_STATUS_DB_DROPPED |\
|
||||
SERVER_STATUS_CURSOR_EXISTS|\
|
||||
SERVER_STATUS_LAST_ROW_SENT)
|
||||
SERVER_STATUS_LAST_ROW_SENT|\
|
||||
SERVER_SESSION_STATE_CHANGED)
|
||||
|
||||
#define MYSQL_ERRMSG_SIZE 512
|
||||
#define NET_READ_TIMEOUT 30 /* Timeout on read */
|
||||
|
@ -523,6 +547,30 @@ enum enum_mysql_set_option
|
|||
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)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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);
|
||||
uchar *net_store_length(uchar *pkg, ulonglong length);
|
||||
uchar *safe_net_store_length(uchar *pkg, size_t pkg_len, ulonglong length);
|
||||
unsigned int net_length_size(ulonglong num);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -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/sql_cte.cc
|
||||
../sql/temporary_tables.cc
|
||||
../sql/session_tracker.cc
|
||||
${GEN_SOURCES}
|
||||
${MYSYS_LIBWRAP_SOURCE}
|
||||
)
|
||||
|
|
|
@ -1172,7 +1172,8 @@ bool
|
|||
net_send_ok(THD *thd,
|
||||
uint server_status, uint statement_warn_count,
|
||||
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");
|
||||
MYSQL_DATA *data;
|
||||
|
|
|
@ -903,6 +903,11 @@ The following options may be given as the first argument:
|
|||
files within specified directory
|
||||
--server-id=# Uniquely identifies the server instance in the community
|
||||
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 user and password in SHOW SLAVE HOSTS on this
|
||||
master.
|
||||
|
@ -1385,6 +1390,8 @@ safe-user-create FALSE
|
|||
secure-auth TRUE
|
||||
secure-file-priv (No default value)
|
||||
server-id 1
|
||||
session-track-schema TRUE
|
||||
session-track-state-change FALSE
|
||||
show-slave-auth-info FALSE
|
||||
silent-startup FALSE
|
||||
skip-grant-tables TRUE
|
||||
|
|
|
@ -3327,6 +3327,34 @@ NUMERIC_BLOCK_SIZE 1
|
|||
ENUM_VALUE_LIST NULL
|
||||
READ_ONLY NO
|
||||
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
|
||||
SESSION_VALUE NULL
|
||||
GLOBAL_VALUE ON
|
||||
|
|
|
@ -3789,6 +3789,34 @@ NUMERIC_BLOCK_SIZE 1
|
|||
ENUM_VALUE_LIST NULL
|
||||
READ_ONLY NO
|
||||
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
|
||||
SESSION_VALUE NULL
|
||||
GLOBAL_VALUE ON
|
||||
|
|
|
@ -186,3 +186,25 @@ uchar *safe_net_store_length(uchar *packet, size_t packet_len, ulonglong length)
|
|||
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
|
|||
../sql-common/client_plugin.c
|
||||
opt_range.cc opt_range.h opt_sum.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
|
||||
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
|
||||
|
|
|
@ -117,7 +117,6 @@ extern my_bool thd_net_is_killed();
|
|||
#endif
|
||||
|
||||
#define TEST_BLOCKING 8
|
||||
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
|
||||
|
||||
static my_bool net_write_buff(NET *, const uchar *, ulong);
|
||||
|
||||
|
|
138
sql/protocol.cc
138
sql/protocol.cc
|
@ -35,7 +35,8 @@ static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
|
|||
/* Declared non-static only because of the embedded library. */
|
||||
bool net_send_error_packet(THD *, uint, const char *, const char *);
|
||||
/* 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. */
|
||||
bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
@ -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 id Auto_increment id for first row (if used)
|
||||
@param message Message to send to the client (Used by mysql_status)
|
||||
|
||||
@param is_eof this called inted of old EOF packet
|
||||
|
||||
@return
|
||||
@retval FALSE The message was successfully sent
|
||||
@retval TRUE An error occurred and the messages wasn't sent properly
|
||||
|
@ -209,10 +211,18 @@ bool
|
|||
net_send_ok(THD *thd,
|
||||
uint server_status, uint statement_warn_count,
|
||||
ulonglong affected_rows, ulonglong id, const char *message,
|
||||
bool is_eof,
|
||||
bool skip_flush)
|
||||
{
|
||||
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;
|
||||
DBUG_ENTER("net_send_ok");
|
||||
|
||||
|
@ -222,38 +232,82 @@ net_send_ok(THD *thd,
|
|||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
buff[0]=0; // No fields
|
||||
pos=net_store_length(buff+1,affected_rows);
|
||||
pos=net_store_length(pos, id);
|
||||
/*
|
||||
OK send instead of EOF still require 0xFE header, but OK packet content.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
DBUG_PRINT("info",
|
||||
("affected_rows: %lu id: %lu status: %u warning_count: %u",
|
||||
(ulong) affected_rows,
|
||||
(ulong) affected_rows,
|
||||
(ulong) id,
|
||||
(uint) (server_status & 0xffff),
|
||||
(uint) statement_warn_count));
|
||||
int2store(pos, server_status);
|
||||
pos+=2;
|
||||
store.q_append2b(server_status);
|
||||
|
||||
/* We can only return up to 65535 warnings in two bytes */
|
||||
uint tmp= MY_MIN(statement_warn_count, 65535);
|
||||
int2store(pos, tmp);
|
||||
pos+= 2;
|
||||
store.q_append2b(tmp);
|
||||
}
|
||||
else if (net->return_status) // For 4.0 protocol
|
||||
{
|
||||
int2store(pos, server_status);
|
||||
pos+=2;
|
||||
store.q_append2b(server_status);
|
||||
}
|
||||
thd->get_stmt_da()->set_overwrite_status(true);
|
||||
|
||||
if (message && message[0])
|
||||
pos= net_store_data(pos, (uchar*) message, strlen(message));
|
||||
error= my_net_write(net, buff, (size_t) (pos-buff));
|
||||
if (!error && !skip_flush)
|
||||
if ((thd->client_capabilities & CLIENT_SESSION_TRACK))
|
||||
{
|
||||
if (server_status & SERVER_SESSION_STATE_CHANGED)
|
||||
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);
|
||||
|
||||
thd->server_status&= ~SERVER_SESSION_STATE_CHANGED;
|
||||
|
||||
thd->get_stmt_da()->set_overwrite_status(false);
|
||||
DBUG_PRINT("info", ("OK sent, so no more error sending allowed"));
|
||||
|
@ -261,6 +315,7 @@ net_send_ok(THD *thd,
|
|||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
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)
|
|||
NET *net= &thd->net;
|
||||
bool error= FALSE;
|
||||
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 */
|
||||
if (net->vio != 0)
|
||||
{
|
||||
|
@ -546,9 +617,9 @@ bool Protocol::send_ok(uint server_status, uint statement_warn_count,
|
|||
const char *message, bool skip_flush)
|
||||
{
|
||||
DBUG_ENTER("Protocol::send_ok");
|
||||
const bool retval=
|
||||
const bool retval=
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -862,14 +933,19 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags)
|
|||
|
||||
if (flags & SEND_EOF)
|
||||
{
|
||||
/*
|
||||
Mark the end of meta-data result set, and store thd->server_status,
|
||||
to show that there is no cursor.
|
||||
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);
|
||||
|
||||
/* if it is new client do not send EOF packet */
|
||||
if (!(thd->client_capabilities & CLIENT_DEPRECATE_EOF))
|
||||
{
|
||||
/*
|
||||
Mark the end of meta-data result set, and store thd->server_status,
|
||||
to show that there is no cursor.
|
||||
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));
|
||||
|
||||
|
@ -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 ret;
|
||||
if (!(thd->client_capabilities & CLIENT_PS_MULTI_RESULTS))
|
||||
{
|
||||
/* The client does not support OUT-parameters. */
|
||||
|
@ -1558,8 +1635,7 @@ bool Protocol_binary::send_out_parameters(List<Item_param> *sp_params)
|
|||
/* Restore THD::server_status. */
|
||||
thd->server_status&= ~SERVER_PS_OUT_PARAMS;
|
||||
|
||||
/* Send EOF-packet. */
|
||||
net_send_eof(thd, thd->server_status, 0);
|
||||
ret= net_send_eof(thd, thd->server_status, 0);
|
||||
|
||||
/*
|
||||
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)
|
|||
*/
|
||||
thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
|
||||
|
||||
return FALSE;
|
||||
return ret ? FALSE : TRUE;
|
||||
}
|
||||
|
|
358
sql/session_tracker.cc
Normal file
358
sql/session_tracker.cc
Normal file
|
@ -0,0 +1,358 @@
|
|||
/* 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);
|
||||
}
|
159
sql/session_tracker.h
Normal file
159
sql/session_tracker.h
Normal file
|
@ -0,0 +1,159 @@
|
|||
#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)
|
|||
(on_update && on_update(this, thd, OPT_GLOBAL));
|
||||
}
|
||||
else
|
||||
return session_update(thd, var) ||
|
||||
{
|
||||
bool ret= session_update(thd, var) ||
|
||||
(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)
|
||||
|
@ -867,6 +887,8 @@ int set_var_user::update(THD *thd)
|
|||
MYF(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -914,7 +936,11 @@ int set_var_role::check(THD *thd)
|
|||
int set_var_role::update(THD *thd)
|
||||
{
|
||||
#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
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -968,6 +994,8 @@ int set_var_collation_client::update(THD *thd)
|
|||
{
|
||||
thd->update_charset(character_set_client, collation_connection,
|
||||
character_set_results);
|
||||
|
||||
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
|
||||
thd->protocol_text.init(thd);
|
||||
thd->protocol_binary.init(thd);
|
||||
return 0;
|
||||
|
|
|
@ -385,7 +385,7 @@ extern SHOW_COMP_OPTION have_openssl;
|
|||
SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
|
||||
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);
|
||||
|
||||
#define SYSVAR_AUTOSIZE(VAR,VAL) \
|
||||
|
|
|
@ -7139,7 +7139,6 @@ ER_KILL_QUERY_DENIED_ERROR
|
|||
ER_NO_EIS_FOR_FIELD
|
||||
eng "Engine-independent statistics are not collected for column '%s'"
|
||||
ukr "Незалежна від типу таблиці статистика не збирається для стовбця '%s'"
|
||||
|
||||
#
|
||||
# Internal errors, not used
|
||||
#
|
||||
|
@ -7151,6 +7150,10 @@ skip-to-error-number 3000
|
|||
ER_MYSQL_57_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
|
||||
skip-to-error-number 4000
|
||||
|
||||
|
|
|
@ -2977,6 +2977,16 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
|
|||
|
||||
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)
|
||||
res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
|
||||
|
||||
|
|
|
@ -1465,6 +1465,9 @@ void THD::init(void)
|
|||
/* Initialize the Debug Sync Facility. See debug_sync.cc. */
|
||||
debug_sync_init_thread(this);
|
||||
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
||||
|
||||
session_tracker.enable(this);
|
||||
|
||||
apc_target.init(&LOCK_thd_data);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <mysql/psi/mysql_idle.h>
|
||||
#include <mysql/psi/mysql_table.h>
|
||||
#include <mysql_com_server.h>
|
||||
#include "session_tracker.h"
|
||||
|
||||
extern "C"
|
||||
void set_thd_stage_info(void *thd,
|
||||
|
@ -688,6 +689,8 @@ typedef struct system_variables
|
|||
|
||||
my_bool pseudo_slave_mode;
|
||||
|
||||
my_bool session_track_schema;
|
||||
my_bool session_track_state_change;
|
||||
} SV;
|
||||
|
||||
/**
|
||||
|
@ -4054,6 +4057,7 @@ private:
|
|||
LEX_STRING invoker_host;
|
||||
|
||||
public:
|
||||
Session_tracker session_tracker;
|
||||
/*
|
||||
Flag, mutex and condition for a thread to wait for a signal from another
|
||||
thread.
|
||||
|
|
|
@ -1035,7 +1035,10 @@ exit:
|
|||
it to 0.
|
||||
*/
|
||||
if (thd->db && cmp_db_names(thd->db, db) && !error)
|
||||
{
|
||||
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);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -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,
|
||||
system_charset_info);
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
/* The operation succeed. */
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -3852,6 +3852,12 @@ mysql_execute_command(THD *thd)
|
|||
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
|
||||
if (create_info.tmp_table())
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -4608,6 +4614,14 @@ end_with_restore_list:
|
|||
|
||||
/* DDL and binlog write order are protected by metadata locks. */
|
||||
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;
|
||||
}
|
||||
case SQLCOM_SHOW_PROCESSLIST:
|
||||
|
|
|
@ -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_pluginvar *pi= NULL;
|
||||
|
|
|
@ -120,6 +120,8 @@ struct st_plugin_int
|
|||
};
|
||||
|
||||
|
||||
extern mysql_mutex_t LOCK_plugin;
|
||||
|
||||
/*
|
||||
See intern_plugin_lock() for the explanation for the
|
||||
conditionally defined plugin_ref type
|
||||
|
|
|
@ -2758,7 +2758,11 @@ void mysql_sql_stmt_prepare(THD *thd)
|
|||
thd->stmt_map.erase(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
|
||||
NULL);
|
||||
my_ok(thd, 0L, 0L, "Statement prepared");
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -3208,6 +3212,8 @@ void mysql_sql_stmt_close(THD *thd)
|
|||
else
|
||||
{
|
||||
stmt->deallocate();
|
||||
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER,
|
||||
NULL);
|
||||
my_ok(thd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* 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
|
||||
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,
|
|||
*t= '\0';
|
||||
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 @@ public:
|
|||
{
|
||||
Ptr[str_length++] = c;
|
||||
}
|
||||
void q_append2b(const uint32 n)
|
||||
{
|
||||
int2store(Ptr + str_length, n);
|
||||
str_length += 2;
|
||||
}
|
||||
void q_append(const uint32 n)
|
||||
{
|
||||
int4store(Ptr + str_length, n);
|
||||
|
@ -559,6 +564,17 @@ public:
|
|||
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)
|
||||
{
|
||||
uint32 new_length= arg_length + str_length;
|
||||
|
@ -623,6 +639,8 @@ public:
|
|||
{
|
||||
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 @@
|
|||
#include "transaction.h"
|
||||
#include "sql_audit.h"
|
||||
|
||||
|
||||
#ifdef __WIN__
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
@ -9228,6 +9229,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||
{
|
||||
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(
|
|||
DEFAULT(my_getpagesize() * 6),
|
||||
BLOCK_SIZE(my_getpagesize()));
|
||||
#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));
|
||||
|
|
Loading…
Add table
Reference in a new issue