maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #09474
Re: 4c51152: MDEV-8931: (server part of) session state tracking
Hi, Sanja!
Summary:
Lots of comments below, many changes needed.
When you copy a big feature from MySQL next time - please, take a
more critical look at what you're merging.
On Mar 28, OleksandrByelkin wrote:
> revision-id: 4c51152d9f43e271e17a2bc266f5887ce092c00f (mariadb-10.1.8-187-g4c51152)
> parent(s): 69b5c4a4220c8fa98bbca8b3f935b2a3735e19ac
> committer: Oleksandr Byelkin
> timestamp: 2016-03-28 19:19:54 +0200
> message:
>
> MDEV-8931: (server part of) session state tracking
>
> diff --git a/include/mysql_com.h b/include/mysql_com.h
> index c13999a..c6608b7 100644
> --- a/include/mysql_com.h
> +++ b/include/mysql_com.h
> @@ -520,6 +544,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 */
support comes in the next patch, I know
> + SESSION_TRACK_SCHEMA, /* Current schema */
suported, I presume
> + SESSION_TRACK_STATE_CHANGE, /* track session state changes */
suported, I presume
> + SESSION_TRACK_GTIDS,
not suported, I presume
> + SESSION_TRACK_TRANSACTION_CHARACTERISTICS, /* Transaction chistics */
> + SESSION_TRACK_TRANSACTION_STATE /* Transaction state */
to be imlemented later, I suppose
> +};
> +
> +#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
> diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result
> index a35693e..f69b615 100644
> --- a/mysql-test/r/mysqld--help.result
> +++ b/mysql-test/r/mysqld--help.result
> @@ -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.
> diff --git a/mysql-test/suite/sys_vars/r/session_track_schema_basic.result b/mysql-test/suite/sys_vars/r/session_track_schema_basic.result
> new file mode 100644
> index 0000000..be4b892
> --- /dev/null
> +++ b/mysql-test/suite/sys_vars/r/session_track_schema_basic.result
> @@ -0,0 +1,116 @@
we don't need these "basic" sysvar tests anymore. The test
that checks for them is disabled. sysvar_* tests are now used to
show basic sysvar characteristics
> +#
> +# Variable name : session_track_schema
> +# Scope : Global & Session
> +#
> +# Global - default
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +1
> +# Session - default
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +1
> +
> +# via INFORMATION_SCHEMA.GLOBAL_VARIABLES
> +SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'track_current%';
> +VARIABLE_NAME VARIABLE_VALUE
> +# via INFORMATION_SCHEMA.SESSION_VARIABLES
> +SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'track_current%';
> +VARIABLE_NAME VARIABLE_VALUE
> +SET @global_saved_tmp = @@global.session_track_schema;
> +
> +# Altering global variable's value
> +SET @@global.session_track_schema = 0;
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +0
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +1
> +SET @@global.session_track_schema = TrUe;
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +1
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +1
> +SET @@global.session_track_schema = FaLsE;
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +0
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +1
> +
> +# Altering session variable's value
> +SET @@session.session_track_schema = 0;
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +0
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +0
> +
> +# Variables' values in a new session.
> +# Global - expect 0
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +0
> +
> +# Session - expect 0
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +0
> +
> +# Switching to the default connection.
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +0
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +0
> +
> +# Test if DEFAULT is working as expected.
> +SET @@global.session_track_schema = DEFAULT;
> +SET @@session.session_track_schema = DEFAULT;
> +
> +# Global - expect 1
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +1
> +# Session - expect 1
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +1
> +
> +# Variables' values in a new session (con2).
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +1
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +1
> +
> +# Altering session should not affect global.
> +SET @@session.session_track_schema = FALSE;
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +1
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +0
> +
> +# Variables' values in a new session (con3).
> +# Altering global should not affect session.
> +SET @@global.session_track_schema = OFF;
> +SELECT @@global.session_track_schema;
> +@@global.session_track_schema
> +0
> +SELECT @@session.session_track_schema;
> +@@session.session_track_schema
> +1
> +
> +# Switching to the default connection.
> +# Restoring the original values.
> +SET @@global.session_track_schema = @global_saved_tmp;
> +# End of tests.
> diff --git a/mysql-test/suite/sys_vars/t/session_track_schema_basic.test b/mysql-test/suite/sys_vars/t/session_track_schema_basic.test
> new file mode 100644
> index 0000000..220ae35
> --- /dev/null
> +++ b/mysql-test/suite/sys_vars/t/session_track_schema_basic.test
> @@ -0,0 +1,105 @@
another meaningless basic test
> +--source include/not_embedded.inc
> +
> +--echo #
> +--echo # Variable name : session_track_schema
> +--echo # Scope : Global & Session
> +--echo #
> +
> +--echo # Global - default
> +SELECT @@global.session_track_schema;
> +--echo # Session - default
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # via INFORMATION_SCHEMA.GLOBAL_VARIABLES
> +--disable_warnings
> +SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'track_current%';
> +--enable_warnings
> +
> +--echo # via INFORMATION_SCHEMA.SESSION_VARIABLES
> +--disable_warnings
> +SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'track_current%';
> +--enable_warnings
> +
> +# Save the global value to be used to restore the original value.
> +SET @global_saved_tmp = @@global.session_track_schema;
> +--echo
> +
> +--echo # Altering global variable's value
> +SET @@global.session_track_schema = 0;
> +SELECT @@global.session_track_schema;
> +SELECT @@session.session_track_schema;
> +
> +SET @@global.session_track_schema = TrUe;
> +SELECT @@global.session_track_schema;
> +SELECT @@session.session_track_schema;
> +
> +SET @@global.session_track_schema = FaLsE;
> +SELECT @@global.session_track_schema;
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # Altering session variable's value
> +SET @@session.session_track_schema = 0;
> +SELECT @@global.session_track_schema;
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # Variables' values in a new session.
> +connect (con1,"127.0.0.1",root,,test,$MASTER_MYPORT,);
> +
> +--echo # Global - expect 0
> +SELECT @@global.session_track_schema;
> +--echo
> +--echo # Session - expect 0
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # Switching to the default connection.
> +connection default;
> +
> +SELECT @@global.session_track_schema;
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # Test if DEFAULT is working as expected.
> +SET @@global.session_track_schema = DEFAULT;
> +SET @@session.session_track_schema = DEFAULT;
> +--echo
> +
> +--echo # Global - expect 1
> +SELECT @@global.session_track_schema;
> +--echo # Session - expect 1
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # Variables' values in a new session (con2).
> +connect (con2,"127.0.0.1",root,,test,$MASTER_MYPORT,);
> +
> +SELECT @@global.session_track_schema;
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # Altering session should not affect global.
> +SET @@session.session_track_schema = FALSE;
> +SELECT @@global.session_track_schema;
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # Variables' values in a new session (con3).
> +connect (con3,"127.0.0.1",root,,test,$MASTER_MYPORT,);
> +
> +--echo # Altering global should not affect session.
> +SET @@global.session_track_schema = OFF;
> +SELECT @@global.session_track_schema;
> +SELECT @@session.session_track_schema;
> +--echo
> +
> +--echo # Switching to the default connection.
> +connection default;
> +
> +--echo # Restoring the original values.
> +SET @@global.session_track_schema = @global_saved_tmp;
> +
> +--echo # End of tests.
> +
> diff --git a/sql/protocol.cc b/sql/protocol.cc
> index 9e52870..c1e66d7 100644
> --- a/sql/protocol.cc
> +++ b/sql/protocol.cc
> @@ -197,6 +197,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 eof_indentifier when true [FE] will be set in OK header
> + else [00] will be used
eh, I understand that's what MySQL has, and we want to be
protocol-compatible, but can you put a meaningful comment here, please?
Not like
i++; // increment i by 1
and a better name for the parameter would be nice too.
>
> @return
> @retval FALSE The message was successfully sent
> @@ -221,9 +233,32 @@ 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);
> + start= buff;
> +
> + /*
> + Use 0xFE packet header if eof_identifier is true
> + unless we are talking to old client
> + */
fix this comment, please
> + if (eof_identifier &&
> + (thd->client_capabilities & CLIENT_DEPRECATE_EOF))
> + buff[0]= 254;
> + else
> + buff[0]= 0;
I don't understand this, because the comment doesn't explain anything
> +
> + /* affected rows */
> + pos= net_store_length(buff + 1, affected_rows);
> +
> + /* last insert id */
> + pos= net_store_length(pos, id);
> +
> + if ((thd->client_capabilities & CLIENT_SESSION_TRACK) &&
> + thd->session_tracker.enabled_any() &&
> + thd->session_tracker.changed_any())
> + {
> + server_status |= SERVER_SESSION_STATE_CHANGED;
> + state_changed= true;
I'd rather have trackers to set server_status when they're changed,
instead of iterating the list of trackers here twice for every statement
just because we apparently have free CPU cycles to burn
> + }
> +
> if (thd->client_capabilities & CLIENT_PROTOCOL_41)
> {
> DBUG_PRINT("info",
> @@ -247,9 +282,45 @@ net_send_ok(THD *thd,
> }
> thd->get_stmt_da()->set_overwrite_status(true);
>
> + if ((thd->client_capabilities & CLIENT_SESSION_TRACK))
> + {
> + /* the info field */
> + if (state_changed || (message && message[0]))
> + pos= net_store_data(pos, (uchar*) message, message ? strlen(message) : 0);
> + /* session state change information */
> + if (unlikely(state_changed))
> + {
> + store.set_charset(thd->variables.collation_database);
> +
> + /*
> + First append the fields collected so far. In case of malloc, memory
> + for message is also allocated here.
> + */
> + store.append((const char *)start, (pos - start), MYSQL_ERRMSG_SIZE);
no, don't use "buf or store, depending on whether session tracking is used"
that's ridiculous (and an extra memcpy)
always use store, remove buf. declare store as
StringBuffer<MYSQL_ERRMSG_SIZE+10> store(thd->variables.collation_database);
> +
> + /* .. and then the state change information. */
> + thd->session_tracker.store(thd, store);
> +
> + start= (uchar *) store.ptr();
> + pos= start+store.length();
> + }
> + }
> - if (message && message[0])
> + else if (message && message[0])
> + {
> + /* the info field, if there is a message to store */
> pos= net_store_data(pos, (uchar*) message, strlen(message));
> - error= my_net_write(net, buff, (size_t) (pos-buff));
> + }
> +
> + /* OK packet length will be restricted to 16777215 bytes */
> + if (((size_t) (pos - start)) > MAX_PACKET_LENGTH)
> + {
> + net->error= 1;
I'm surprised, this doesn't have a comment "setting net->error to 1"
would be quite in style with what I've seen so far :)
> + 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, start, (size_t) (pos - start));
> if (!error)
> error= net_flush(net);
>
> @@ -559,7 +630,20 @@ 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;
> + /*
> + 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
> + */
> +#ifndef EMBEDDED_LIBRARY
> + if ((thd->client_capabilities & CLIENT_DEPRECATE_EOF) &&
> + (thd->get_command() != COM_BINLOG_DUMP ))
> + retval= net_send_ok(thd, server_status, statement_warn_count, 0, 0, NULL,
> + true);
> + else
> +#endif
> + retval= net_send_eof(thd, server_status, statement_warn_count);
better keep the old code here, just net_send_eof().
and in net_send_eof() you do, like
if (thd->client_capabilities & CLIENT_DEPRECATE_EOF)
return net_send_ok(..., 0, 0, NULL, true);
> DBUG_RETURN(retval);
> }
>
> @@ -1551,8 +1641,14 @@ 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);
> + if (thd->client_capabilities & CLIENT_DEPRECATE_EOF)
> + ret= net_send_ok(thd,
> + (thd->server_status | SERVER_PS_OUT_PARAMS |
> + SERVER_MORE_RESULTS_EXISTS),
> + 0, 0, 0, NULL, true);
> + else
> + /* In case of old clients send EOF packet. */
> + ret= net_send_eof(thd, thd->server_status, 0);
>
> /*
> Reset SERVER_MORE_RESULTS_EXISTS bit, because this is the last packet
note that unlike 5.7 you we have this "Reset SERVER_MORE_RESULTS_EXISTS"
*after* net_send_eof() (bugfix for MDEV-4604)
1. you don't need "| SERVER_MORE_RESULTS_EXISTS" for net_send_ok()
2. you might try to use only net_send_eof() here too (with both flags set)
> diff --git a/sql/session_tracker.h b/sql/session_tracker.h
> new file mode 100644
> index 0000000..7477f96
> --- /dev/null
> +++ b/sql/session_tracker.h
> @@ -0,0 +1,255 @@
> +#ifndef SESSION_TRACKER_INCLUDED
> +#define SESSION_TRACKER_INCLUDED
> +
> +/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
> +
> + 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 */
why not to use the same enum from mysql_com.h ?
> +};
> +
> +#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().
this is illogical. check() and update() do not belong in the base State_tracker
> +*/
> +
> +class State_tracker
> +{
> +protected:
> + /** Is tracking enabled for a particular session state type ? */
> + 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. */
> + /** Copy constructor */
> + Session_tracker(Session_tracker const &other)
> + {
> + DBUG_ASSERT(FALSE);
> + }
> +
> + /** Copy assignment operator */
> + Session_tracker& operator= (Session_tracker const &rhs)
> + {
> + DBUG_ASSERT(FALSE);
> + return *this;
> + }
> +
> +public:
judging by other comments in this file (above and below), I'm surprised
this keyword does not have a comment, like /* declare the rest of the
object public. that makes the methods below accessible from the
other code, not only from this object itself */
Serisouly, why do these comments explain basic C++ features?
or repeat whatever the function is obviously doing (like, get_tracker() or
enabled_any())
And non-trivial functions are not commented, for example server_boot_verify()
> +
> + /** Constructor */
> + Session_tracker()
> + {}
> +
> + /** Destructor */
> + ~Session_tracker()
> + {
> + }
> + /**
> + Initialize Session_tracker objects and enable them based on the
> + tracker_xxx variables' value that the session inherit from global
> + variables at the time of session initialization (see plugin_thdvar_init).
> + */
> + void init(const CHARSET_INFO *char_set);
> + void enable(THD *thd);
> + bool server_boot_verify(const CHARSET_INFO *char_set, LEX_STRING var_list);
> +
> + /** Returns the pointer to the tracker object for the specified tracker. */
> + State_tracker *get_tracker(enum_session_tracker tracker) const;
> +
> + /** Checks if m_enabled flag is set for any of the tracker objects. */
> + bool enabled_any();
> +
> + /** Checks if m_changed flag is set for any of the tracker objects. */
> + bool changed_any();
> +
> + /**
> + Stores the session state change information of all changes session state
> + type entities into the specified buffer.
> + */
> + void store(THD *thd, String &main_buf);
> + void deinit()
> + {
> + for (int i= 0; i <= SESSION_TRACKER_END; i ++)
> + delete m_trackers[i];
> + }
> +};
> +
> +/*
> + 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
> +*/
> +
> +class Session_state_change_tracker : public State_tracker
Why is this one in the header, not in session_tracker.cc?
> +{
> +private:
> +
> + void reset();
> +
> +public:
> + Session_state_change_tracker();
> + bool enable(THD *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)
> + {}
> +};
> +
> +
> +/**
> + Transaction_state_tracker
> + ----------------------
> + This is a tracker class that enables & manages the tracking of
> + current transaction info for a particular connection.
> +*/
> +
> +/**
> + Transaction state (no transaction, transaction active, work attached, etc.)
> +*/
> +enum enum_tx_state {
> + TX_EMPTY = 0, ///< "none of the below"
> + TX_EXPLICIT = 1, ///< an explicit transaction is active
> + TX_IMPLICIT = 2, ///< an implicit transaction is active
> + TX_READ_TRX = 4, ///< transactional reads were done
> + TX_READ_UNSAFE = 8, ///< non-transaction reads were done
> + TX_WRITE_TRX = 16, ///< transactional writes were done
> + TX_WRITE_UNSAFE = 32, ///< non-transactional writes were done
> + TX_STMT_UNSAFE = 64, ///< "unsafe" (non-deterministic like UUID()) stmts
> + TX_RESULT_SET = 128, ///< result-set was sent
> + TX_WITH_SNAPSHOT= 256, ///< WITH CONSISTENT SNAPSHOT was used
> + TX_LOCKED_TABLES= 512 ///< LOCK TABLES is active
> +};
> +
> +/**
> + Transaction access mode
> +*/
> +enum enum_tx_read_flags {
> + TX_READ_INHERIT = 0, ///< not explicitly set, inherit session.tx_read_only
> + TX_READ_ONLY = 1, ///< START TRANSACTION READ ONLY, or tx_read_only=1
> + TX_READ_WRITE = 2, ///< START TRANSACTION READ WRITE, or tx_read_only=0
> +};
> +
> +/**
> + Transaction isolation level
> +*/
> +enum enum_tx_isol_level {
> + TX_ISOL_INHERIT = 0, ///< not explicitly set, inherit session.tx_isolation
> + TX_ISOL_UNCOMMITTED = 1,
> + TX_ISOL_COMMITTED = 2,
> + TX_ISOL_REPEATABLE = 3,
> + TX_ISOL_SERIALIZABLE= 4
> +};
> +
> +/**
> + Transaction tracking level
> +*/
> +enum enum_session_track_transaction_info {
> + TX_TRACK_NONE = 0, ///< do not send tracker items on transaction info
> + TX_TRACK_STATE = 1, ///< track transaction status
> + TX_TRACK_CHISTICS = 2 ///< track status and characteristics
> +};
Better remove all declarations related to transaction tracking and add
them later in a separate patch (with the complete transaction tracking
feature).
> +
> +#endif /* SESSION_TRACKER_INCLUDED */
> diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc
> new file mode 100644
> index 0000000..6abff2a
> --- /dev/null
> +++ b/sql/session_tracker.cc
> @@ -0,0 +1,454 @@
> +/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
and "Copyright(c) 2016, MariaDB" because it's not 1:1 copy
> +
> + 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"
> +//#include "xa.h"
this is for SESSION_TRACK_TRANSACTION_STATE too I suppose
> +
> +static void store_lenenc_string(String &to, const char *from,
> + size_t length);
> +
> +class Dummy_tracker : public State_tracker
> +{
> +bool enable(THD *thd __attribute__((unused)))
why __attribute__((unused)) if it is used?
and why is it used, if the tracker is dummy?
btw, seeing how this Dummy_tracker is used, I'd rather
rename it to Not_implemented_tracker
> + { return update(thd); }
> + bool check(THD *thd __attribute__((unused)),
> + set_var *var __attribute__((unused)))
> + { return false; }
it's C++, you don't need __attribute__((unused)), write
bool check(THD *, set_var *) { return false; }
> + bool update(THD *thd __attribute__((unused)))
> + { return false; }
> + bool store(THD *thd __attribute__((unused)),
> + String &buf __attribute__((unused)))
> +
> + { return false; }
> + void mark_as_changed(THD *thd __attribute__((unused)),
> + LEX_CSTRING *tracked_item_name __attribute__((unused)))
> + {}
> +
> +};
> +
> +
> +/**
> + 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:
> +
> + /** Constructor */
> + 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);
> +};
> +
> +/* To be used in expanding the buffer. */
> +static const unsigned int EXTRA_ALLOC= 1024;
> +
> +///////////////////////////////////////////////////////////////////////////////
> +
> +/**
> + @brief 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)? true: false;
> + return false;
> +}
> +
> +
> +/**
> + @brief Store the schema name as length-encoded string in the specified
> + buffer. Once the data is stored, we reset the flags related to
> + state-change (see reset()).
> +
> +
> + @param thd [IN] The thd handle.
> + @paran buf [INOUT] Buffer to store the information to.
> +
> + @return
> + false Success
> + true Error
> +*/
> +
> +bool Current_schema_tracker::store(THD *thd, String &buf)
> +{
> + ulonglong db_length, length;
> +
> + length= db_length= thd->db_length;
> + length += net_length_size(length);
> +
> + uchar *to= (uchar *) buf.prep_append(net_length_size(length) + 1,
> + EXTRA_ALLOC);
> +
> + /* Session state type (SESSION_TRACK_SCHEMA) */
> + to= net_store_length(to, (ulonglong)SESSION_TRACK_SCHEMA);
> +
> + /* Length of the overall entity. */
> + to= net_store_length(to, length);
> +
> + /* Length of the changed current schema name. */
> + net_store_length(to, db_length);
> +
> + /* Current schema name (length-encoded string). */
> + store_lenenc_string(buf, thd->db, thd->db_length);
> +
> + reset();
> +
> + return false;
> +}
> +
> +
> +/**
> + @brief Mark the tracker as changed.
> +
> + @param name [IN] Always null.
> +
> + @return void
> +*/
> +
> +void Current_schema_tracker::mark_as_changed(THD *thd,
> + LEX_CSTRING *tracked_item_name
> + __attribute__((unused)))
you don't need __attribute__((unused)) here, it's C++
besides, as I've just found, we compile with -Wno-unused-parameter
(this was merged from MySQL, perhaps we should remove that flag)
> +{
> + m_changed= true;
> + thd->lex->safe_to_cache_query= 0;
> +}
> +
> +
> +/**
> + @brief Reset the m_changed flag for next statement.
> +
> + @return void
> +*/
> +
> +void Current_schema_tracker::reset()
> +{
> + m_changed= false;
> +}
> +
> +
> +///////////////////////////////////////////////////////////////////////////////
> +
> +/** Constructor */
> +Session_state_change_tracker::Session_state_change_tracker()
> +{
> + m_changed= false;
> +}
> +
> +/**
> + @brief Initiate the value of m_enabled based on
> + @@session_track_state_change value.
> +
> + @param thd [IN] The thd handle.
> + @return false (always)
> +
> +**/
> +
> +bool Session_state_change_tracker::enable(THD *thd)
> +{
> + m_enabled= (thd->variables.session_track_state_change)? true: false;
> + return 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)
> +{
> + return enable(thd);
> +}
you're kidding, right?
For Dummy_tracker and Current_schema_tracker enable() calls upate(),
for Session_state_change_tracker update() calls enable().
and no matter what method calls what, it's always
one_method(THD *thd) { return other_method(thd); }
other_method(THD *thd) {
m_enabled= (thd->variables.session_track_XXX)? true: false;
}
why two methods enable/update and not one?
why "? true : false", and not m_enabled=thd->variables.session_track_XXX
(hint: m_enabled is bool, ?true:false is the same as cast to bool anyway)
and why to copy the value in the first place??? Just use the value
from thd->variables.session_track_XXX
> +
> +/**
> + @brief Store the 1byte boolean flag in the specified buffer. Once the
> + data is stored, we reset the flags related to state-change. If
> + 1byte flag valie is 1 then there is a session state change else
> + there is no state change information.
> +
> + @param thd [IN] The thd handle.
> + @paran buf [INOUT] Buffer to store the information to.
> +
> + @return
> + false Success
> + true Error
> +**/
> +
> +bool Session_state_change_tracker::store(THD *thd, String &buf)
> +{
> + /* since its a boolean tracker length is always 1 */
> + const ulonglong length= 1;
> +
> + uchar *to= (uchar *) buf.prep_append(3,EXTRA_ALLOC);
> +
> + /* format of the payload is as follows:
> + [ tracker type] [length] [1 byte flag] */
Noooo! Do not copy the payload format logic to every tracker.
Keep it in one place (preferrably, in the protocol)
> + /* Session state type (SESSION_TRACK_STATE_CHANGE) */
> + to= net_store_length(to, (ulonglong)SESSION_TRACK_STATE_CHANGE);
> +
> + /* Length of the overall entity it is always 1 byte */
> + to= net_store_length(to, length);
> +
> + /* boolean tracker will go here */
> + *to= (is_state_changed(thd) ? '1' : '0');
> +
> + reset();
> +
> + return false;
> +}
> +
> +/**
> + @brief Mark the tracker as changed and associated session
> + attributes accordingly.
> +
> + @param name [IN] Always null.
> + @return void
> +*/
> +
> +void Session_state_change_tracker::mark_as_changed(THD *thd,
> + LEX_CSTRING *tracked_item_name)
> +{
> + /* do not send the boolean flag for the tracker itself
> + in the OK packet */
> + if(tracked_item_name &&
> + (strncmp(tracked_item_name->str, "session_track_state_change", 26) == 0))
> + m_changed= false;
Grrr.
1. Why not?
2. what if it is SET @foobar=5, @@session_track_state_change=ON;
> + else
> + {
> + m_changed= true;
> + thd->lex->safe_to_cache_query= 0;
why?
> + }
> +}
> +
> +/**
> + @brief Reset the m_changed flag for next statement.
> +
> + @return void
> +*/
> +
> +void Session_state_change_tracker::reset()
> +{
> + m_changed= false;
> +}
> +
> +/**
> + @brief find if there is a session state change
> +
> + @return
> + true - if there is a session state change
> + false - if there is no session state change
> +**/
> +
> +bool Session_state_change_tracker::is_state_changed(THD* thd)
> +{
> + return m_changed;
> +}
> +
> +///////////////////////////////////////////////////////////////////////////////
> +
> +/**
> + @brief Initialize session tracker objects.
> +
> + @param char_set [IN] The character set info.
> +
> + @return void
> +*/
> +
> +void Session_tracker::init(const CHARSET_INFO *char_set)
> +{
> + m_trackers[SESSION_SYSVARS_TRACKER]=
> + new (std::nothrow) Dummy_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) Dummy_tracker;
> + m_trackers[TRANSACTION_INFO_TRACKER]=
> + new (std::nothrow) Dummy_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 Method called during the server startup to verify the contents
> + of @@session_track_system_variables.
I see. Please remove it from this patch.
It should've been added in the next (sysvar) patch, but
as it's a wrong approach in general, I hope we'll do it correctly.
> +
> + @param char_set The character set info.
> + @param var_list Value of @@session_track_system_variables.
> +
> + @return false Success
> + true failure
> +*/
> +bool Session_tracker::server_boot_verify(const CHARSET_INFO *char_set,
> + LEX_STRING var_list)
> +{
> + return false;
> +}
> +
> +
> +
> +/**
> + @brief Returns the pointer to the tracker object for the specified tracker.
> +
> + @param tracker [IN] Tracker type.
> +
> + @return Pointer to the tracker object.
> +*/
> +
> +State_tracker *
> +Session_tracker::get_tracker(enum_session_tracker tracker) const
> +{
> + return m_trackers[tracker];
> +}
make that inline in session_tracker.h
> +
> +
> +/**
> + @brief Checks if m_enabled flag is set for any of the tracker objects.
> +
> + @return
> + true - At least one of the trackers is enabled.
> + false - None of the trackers is enabled.
> +
> +*/
> +
> +bool Session_tracker::enabled_any()
> +{
> + for (int i= 0; i <= SESSION_TRACKER_END; i ++)
> + {
> + if (m_trackers[i]->is_enabled())
> + return true;
> + }
> + return false;
> +}
remove enabled_any() and changed_any(). See my comments where these
methods are used.
> +
> +/**
> + @brief Checks if m_changed flag is set for any of the tracker objects.
> +
> + @return
> + true At least one of the entities being tracker has
> + changed.
> + false None of the entities being tracked has changed.
> +*/
> +
> +bool Session_tracker::changed_any()
> +{
> + for (int i= 0; i <= SESSION_TRACKER_END; i ++)
> + {
> + if (m_trackers[i]->is_changed())
> + return true;
> + }
> + return false;
> +}
> +
> +
> +/**
> + @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.
> +
> + @return void
> +*/
> +
> +void Session_tracker::store(THD *thd, String &buf)
> +{
> + /* Temporary buffer to store all the changes. */
> + String temp;
> + size_t length;
> +
> + /* Get total length. */
> + for (int i= 0; i <= SESSION_TRACKER_END; i ++)
> + {
> + if (m_trackers[i]->is_changed())
> + m_trackers[i]->store(thd, temp);
> + }
> +
> + length= temp.length();
> + /* Store length first.. */
> + char *to= buf.prep_append(net_length_size(length), EXTRA_ALLOC);
> + net_store_length((uchar *) to, length);
> +
> + /* .. and then the actual info. */
> + buf.append(temp);
Nice. Copy all data into a temporary malloced buffer,
them memcopy it again into the malloced real buffer.
At least use StringBuffer here. it would be good to avoid memcpy too,
but I only see two possible approaches, both not perfect:
1. assume it's, say, less than 251 byte in the most common case.
put the data directly into buf, starting from buf.ptr() + 1.
when done, put the length into the reserved byte. If the length
is more than 251 - memmove everything to free more bytes.
2. iterate all session trackers twice. first - to get the length,
second - to put the actual data
ah, yes, and don't use references (String &buf) use pointers (String *buf)
> +}
> +
> +
> +/**
> + @brief Stores the given string in length-encoded format into the specified
> + buffer.
> +
> + @param to [IN] Buffer to store the given string in.
> + @param from [IN] The give string to be stored.
> + @param length [IN] Length of the above string.
> +
> + @return void.
> +*/
> +
> +static
> +void store_lenenc_string(String &to, const char *from, size_t length)
why not make it a method of String ?
Like, append_lenenc() ?
> +{
> + char *ptr;
> + ptr= to.prep_append(net_length_size(length), EXTRA_ALLOC);
> + net_store_length((uchar *) ptr, length);
> + to.append(from, length);
> +}
> +
> diff --git a/sql/set_var.cc b/sql/set_var.cc
> index b5430c5..a55fc54 100644
> --- a/sql/set_var.cc
> +++ b/sql/set_var.cc
> @@ -199,8 +199,24 @@ 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)
> + {
> + if ((!ret) &&
> + thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->is_enabled())
> + thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->mark_as_changed(thd, &var->var->name);
don't check for is_enabled here. Alternatives:
1. just do mark_as_changed unconditionally. this works if mark_as_changed
is cheap and has no side-effects. neither is true now, but I don't
understand why.
2. create a wrapper method, like
Session_tracker::mark_as_changed(tracker)
at least you won't need to copy this long line in every place where
a state changes.
doing 1 is preferrable, but I don't know if it's easily possible (because
I don't understand why it's done that way now)
> + }
> +
> + return ret;
> + }
> }
>
> uchar *sys_var::session_value_ptr(THD *thd, const LEX_STRING *base)
> @@ -965,6 +983,8 @@ int set_var_collation_client::update(THD *thd)
> thd->variables.character_set_results= character_set_results;
> thd->variables.collation_connection= collation_connection;
> thd->update_charset();
> + if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->is_enabled())
> + thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->mark_as_changed(thd, NULL);
> thd->protocol_text.init(thd);
> thd->protocol_binary.init(thd);
> return 0;
what about set_var_password::update and set_var_role::update ?
Wouldn't it be better to mark_as_changed in sql_set_variables instead of
doing that in individual sys_var descendands?
> diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
> index 0d168e9..933f060 100644
> --- a/sql/share/errmsg-utf8.txt
> +++ b/sql/share/errmsg-utf8.txt
> @@ -7154,3 +7154,8 @@ ER_WRONG_ORDER_IN_WITH_CLAUSE
> eng "The definition of the table '%s' refers to the table '%s' defined later in a non-recursive WITH clause"
> ER_RECURSIVE_QUERY_IN_WITH_CLAUSE
> eng "Recursive queries in WITH clause are not supported yet"
> +ER_DUP_LIST_ENTRY
> + eng "Duplicate entry '%-.192s'."
really, a bug?
remove this. having the same value twice is not a bug:
MariaDB (test)> set sql_mode='ansi,ansi';
Query OK, 0 rows affected (0.00 sec)
Let's be consistent
> +ER_NET_OK_PACKET_TOO_LARGE 08S01
> + eng "OK packet too large"
> + ukr "Пакет OK надто великий"
> diff --git a/sql/sp_head.cc b/sql/sp_head.cc
> index d58b51a..6205dd6 100644
> --- a/sql/sp_head.cc
> +++ b/sql/sp_head.cc
> @@ -2975,6 +2975,13 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
>
> reinit_stmt_before_use(thd, m_lex);
>
> +#ifndef EMBEDDED_LIBRARY
why?
> + if ((thd->client_capabilities & CLIENT_SESSION_TRACK) &&
> + thd->session_tracker.enabled_any() &&
> + thd->session_tracker.changed_any())
> + thd->lex->safe_to_cache_query= 0;
why?
> +#endif
> +
> if (open_tables)
> res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
>
> diff --git a/sql/sql_class.cc b/sql/sql_class.cc
> index e3b7056..bf70594 100644
> --- a/sql/sql_class.cc
> +++ b/sql/sql_class.cc
> @@ -1461,6 +1461,11 @@ void THD::init(void)
> /* Initialize the Debug Sync Facility. See debug_sync.cc. */
> debug_sync_init_thread(this);
> #endif /* defined(ENABLED_DEBUG_SYNC) */
> +
> + /* Initialize session_tracker and create all tracker objects */
> + session_tracker.init(this->charset());
> + session_tracker.enable(this);
1. you don't need charset here, it's unused
2. thus you don't need to invoke init() explicitly at all,
do it from the Session_tracker constructor. In fact, move init
functionality into the constructor.
> +
> apc_target.init(&LOCK_thd_data);
> DBUG_VOID_RETURN;
> }
> @@ -1620,6 +1625,12 @@ void THD::cleanup(void)
> /* All metadata locks must have been released by now. */
> DBUG_ASSERT(!mdl_context.has_locks());
>
> + /*
> + Destroy trackers only after finishing manipulations with transaction
> + state to avoid issues with Transaction_state_tracker.
> + */
> + session_tracker.deinit();
may be you can do that from the destructor too
> +
> apc_target.destroy();
> cleanup_done=1;
> DBUG_VOID_RETURN;
> diff --git a/sql/sql_class.h b/sql/sql_class.h
> index be652e6..063198e 100644
> --- a/sql/sql_class.h
> +++ b/sql/sql_class.h
> @@ -681,6 +682,11 @@ typedef struct system_variables
>
> my_bool pseudo_slave_mode;
>
> + char *track_sysvars_ptr;
no track_sysvars_ptr in this patch please
> + my_bool session_track_schema;
> + my_bool session_track_state_change;
> + ulong session_track_transaction_info;
and no session_track_transaction_info either
> +
> } SV;
>
> /**
> diff --git a/sql/sql_db.cc b/sql/sql_db.cc
> index 2ba67cb..53719e5 100644
> --- a/sql/sql_db.cc
> +++ b/sql/sql_db.cc
> @@ -1034,7 +1034,18 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
> it to 0.
> */
> 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);\
eh? trailing backslash?
> + /*
> + Check if current database tracker is enabled. If so, set the 'changed' flag.
> + */
> + if (thd->session_tracker.get_tracker(CURRENT_SCHEMA_TRACKER)->is_enabled())
> + {
> + LEX_CSTRING dummy= { C_STRING_WITH_LEN("") };
> + dummy.length= dummy.length*1;
WAT???
> + thd->session_tracker.get_tracker(CURRENT_SCHEMA_TRACKER)->mark_as_changed(thd, &dummy);
alternatively, make mark_as_changed to take const char* and size_t,
then you won't need to create LEX_CSTRING
alternatively, create LEX_CSTRING dummy statically and use it always
alternatively, use empty_lex_string
btw, what's the point of using an *empty string* as an argument?
other trackers accept NULL. why empty string is better?
and anyway, why to construct and pass down an argument that
is ignored anyway???
> + }
> + }
> my_dirend(dirp);
> DBUG_RETURN(error);
> }
> @@ -1588,6 +1597,18 @@ 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:
> + /*
> + Check if current database tracker is enabled. If so, set the 'changed' flag.
> + */
> + if (thd->session_tracker.get_tracker(CURRENT_SCHEMA_TRACKER)->is_enabled())
> + {
> + LEX_CSTRING dummy= { C_STRING_WITH_LEN("") };
> + dummy.length= dummy.length*1;
> + thd->session_tracker.get_tracker(CURRENT_SCHEMA_TRACKER)->mark_as_changed(thd, &dummy);
same
> + }
> + if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->is_enabled())
> + thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->mark_as_changed(thd, NULL);
> DBUG_RETURN(FALSE);
> }
>
> diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
> index dbe1967..244ff5b 100644
> --- a/sql/sql_plugin.cc
> +++ b/sql/sql_plugin.cc
> @@ -322,6 +322,8 @@ static void unlock_variables(THD *thd, struct system_variables *vars);
> static void cleanup_variables(struct system_variables *vars);
> static void plugin_vars_free_values(sys_var *vars);
> static void restore_ptr_backup(uint n, st_ptr_backup *backup);
> +#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B)
> +#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B)
remove that
> static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin);
> static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
> static void reap_plugins(void);
> @@ -2776,22 +2778,23 @@ static void update_func_double(THD *thd, struct st_mysql_sys_var *var,
> System Variables support
> ****************************************************************************/
>
> -
> -sys_var *find_sys_var(THD *thd, const char *str, uint length)
> +sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length,
> + bool throw_error, bool locked)
revert all sql_plugin.cc and sql_plugin.h changes.
if you need them for sysvars - do them in the second patch
> {
> sys_var *var;
> sys_var_pluginvar *pi= NULL;
> plugin_ref plugin;
> - DBUG_ENTER("find_sys_var");
> + DBUG_ENTER("find_sys_var_ex");
>
> - mysql_mutex_lock(&LOCK_plugin);
> + if (!locked)
> + mysql_mutex_lock(&LOCK_plugin);
> mysql_rwlock_rdlock(&LOCK_system_variables_hash);
> if ((var= intern_find_sys_var(str, length)) &&
> (pi= var->cast_pluginvar()))
> {
> mysql_rwlock_unlock(&LOCK_system_variables_hash);
> LEX *lex= thd ? thd->lex : 0;
> - if (!(plugin= intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
> + if (!(plugin= my_intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
> var= NULL; /* failed to lock it, it must be uninstalling */
> else
> if (!(plugin_state(plugin) & PLUGIN_IS_READY))
> diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
> index 8e5ab71..03f3a93 100644
> --- a/sql/sql_prepare.cc
> +++ b/sql/sql_prepare.cc
> @@ -2755,7 +2755,13 @@ void mysql_sql_stmt_prepare(THD *thd)
> thd->stmt_map.erase(stmt);
> }
> else
> + {
> + /* send the boolean tracker in the OK packet when
rewrite the comment into something that makes sense, please
> + @@session_track_state_change is set to ON */
> + if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->is_enabled())
> + thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->mark_as_changed(thd, NULL);
> my_ok(thd, 0L, 0L, "Statement prepared");
> + }
>
> DBUG_VOID_RETURN;
> }
Regards,
Sergei
Chief Architect MariaDB
and security@xxxxxxxxxxx
Follow ups