Skip to content

Commit

Permalink
Fix for Bug#102404 (32435618), CONTRIBUTION: ADD TRACK SESSION STATE
Browse files Browse the repository at this point in the history
CHANGE.
  • Loading branch information
soklakov committed May 13, 2021
1 parent 60c0119 commit 1177f29
Show file tree
Hide file tree
Showing 16 changed files with 561 additions and 9 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

Version 8.0.26

- Fix for Bug#102404 (32435618), CONTRIBUTION: ADD TRACK SESSION STATE CHANGE.
Thanks to William Lee for his contribution.

- Fix for Bug#95280 (29757140), DATABASEMETADATA.GETIMPORTEDKEYS RETURNS DOUBLE THE ROWS.
Thanks to Miron Balcerzak for his contribution.

Expand Down
5 changes: 4 additions & 1 deletion src/main/core-api/java/com/mysql/cj/MysqlConnection.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
Expand Down Expand Up @@ -33,6 +33,7 @@

import com.mysql.cj.conf.PropertySet;
import com.mysql.cj.exceptions.ExceptionInterceptor;
import com.mysql.cj.protocol.ServerSessionStateController;

public interface MysqlConnection {

Expand Down Expand Up @@ -76,4 +77,6 @@ public interface MysqlConnection {
* exception caused the connection clean up
*/
void cleanup(Throwable whyCleanedUp);

ServerSessionStateController getServerSessionStateController();
}
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ public enum DatabaseTerm {
new StringPropertyDefinition(PropertyKey.sessionVariables, DEFAULT_VALUE_NULL_STRING, RUNTIME_MODIFIABLE,
Messages.getString("ConnectionProperties.sessionVariables"), "3.1.8", CATEGORY_SESSION, Integer.MAX_VALUE),

new BooleanPropertyDefinition(PropertyKey.trackSessionState, DEFAULT_VALUE_FALSE, RUNTIME_MODIFIABLE,
Messages.getString("ConnectionProperties.trackSessionState"), "8.0.26", CATEGORY_SESSION, Integer.MIN_VALUE),

//
// CATEGORY_NETWORK
//
Expand Down
1 change: 1 addition & 0 deletions src/main/core-api/java/com/mysql/cj/conf/PropertyKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ public enum PropertyKey {
serverConfigCacheFactory("serverConfigCacheFactory", true), //
serverRSAPublicKeyFile("serverRSAPublicKeyFile", true), //
sessionVariables("sessionVariables", true), //
trackSessionState("trackSessionState", true), //
slowQueryThresholdMillis("slowQueryThresholdMillis", true), //
slowQueryThresholdNanos("slowQueryThresholdNanos", true), //
socketFactory("socketFactory", true), //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import java.util.TimeZone;

import com.mysql.cj.ServerVersion;
import com.mysql.cj.exceptions.CJOperationNotSupportedException;
import com.mysql.cj.exceptions.ExceptionFactory;

/**
* Keeps the effective states of server/session variables,
Expand Down Expand Up @@ -248,4 +250,9 @@ public interface ServerSession {
* @return The default JVM time zone
*/
TimeZone getDefaultTimeZone();

default ServerSessionStateController getServerSessionStateController() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
* Free Software Foundation.
*
* This program is also distributed with certain software (including but not
* limited to OpenSSL) that is licensed under separate terms, as designated in a
* particular file or component or in included license documentation. The
* authors of MySQL hereby grant you an additional permission to link the
* program and your derivative works with the separately licensed software that
* they have included with MySQL.
*
* Without limiting anything contained in the foregoing, this file, which is
* part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
* version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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, version 2.0,
* 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
*/

package com.mysql.cj.protocol;

import java.util.ArrayList;
import java.util.List;

import com.mysql.cj.exceptions.CJOperationNotSupportedException;
import com.mysql.cj.exceptions.ExceptionFactory;

public interface ServerSessionStateController {

public static int SESSION_TRACK_SYSTEM_VARIABLES = 0x00;
public static int SESSION_TRACK_SCHEMA = 0x01;
public static int SESSION_TRACK_STATE_CHANGE = 0x02;
public static int SESSION_TRACK_GTIDS = 0x03;
public static int SESSION_TRACK_TRANSACTION_CHARACTERISTICS = 0x04;
public static int SESSION_TRACK_TRANSACTION_STATE = 0x05;

/**
* Set the object containing server session changes collected from the latest query execution. Used internally.
*
* @param changes
* {@link ServerSessionStateChanges} object.
*
*/
default void setSessionStateChanges(ServerSessionStateChanges changes) {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}

/**
* Get the object containing server session changes collected from the latest query execution.
* <p>
* Please note that the driver could issue some queries internally. With that there is no guarantee that all session changes are reflected in the
* {@link ServerSessionStateChanges} object after the recent user's query. If this is an issue, a {@link SessionStateChangesListener} can be added via
* {@link #addSessionStateChangesListener(SessionStateChangesListener)} to catch all session changes.
* </p>
*
* @return {@link ServerSessionStateChanges} object.
*/
default ServerSessionStateChanges getSessionStateChanges() {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}

@FunctionalInterface
public static interface SessionStateChangesListener {
void handleSessionStateChanges(ServerSessionStateChanges changes);
}

/**
* Add the {@link SessionStateChangesListener} that will process {@link ServerSessionStateChanges} on it's arrival.
*
* @param l
* {@link SessionStateChangesListener} object.
*/
default void addSessionStateChangesListener(SessionStateChangesListener l) {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}

/**
* Remove {@link SessionStateChangesListener}.
*
* @param l
* {@link SessionStateChangesListener} object.
*/
default void removeSessionStateChangesListener(SessionStateChangesListener l) {
throw ExceptionFactory.createException(CJOperationNotSupportedException.class, "Not supported");
}

/**
* The object containing server session changes collected from the latest query execution.
* <p>
* Driver is getting these changes when connection property trackSessionState=true and server supports session tracking.
* </p>
*
*/
public static interface ServerSessionStateChanges {
List<SessionStateChange> getSessionStateChangesList();
}

/**
* A single server session change record.
* <p>
* The server messages about session changes are parsed according to their known types:
* <ul>
* <li>{@link #SESSION_TRACK_SYSTEM_VARIABLES} - two values, the system variable name and it's new value;</li>
* <li>{@link #SESSION_TRACK_SCHEMA} - single value, the new schema name;</li>
* <li>{@link #SESSION_TRACK_STATE_CHANGE} - single value, "1" or "0";</li>
* <li>{@link #SESSION_TRACK_GTIDS} - single value, list of GTIDs as reported by server;</li>
* <li>{@link #SESSION_TRACK_TRANSACTION_CHARACTERISTICS} - single value, transaction characteristics statement;</li>
* <li>{@link #SESSION_TRACK_TRANSACTION_STATE} - single value, transaction state record.</li>
* </ul>
* For the unknown change type the raw payload is written into the single value.
* </p>
* <p>
* See more details in the <a href="https://dev.mysql.com/doc/refman/8.0/en/session-state-tracking.html">server documentation</a>.
* </p>
*/
public static class SessionStateChange {
private int type;
private List<String> values = new ArrayList<>();

public SessionStateChange(int type) {
this.type = type;
}

public int getType() {
return this.type;
}

public List<String> getValues() {
return this.values;
}

public SessionStateChange addValue(String value) {
this.values.add(value);
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,10 @@ public void connect(ServerSession sessState, String user, String pass, String db
: (capabilityFlags & NativeServerSession.CLIENT_CONNECT_ATTRS))
| (this.propertySet.<SslMode>getEnumProperty(PropertyKey.sslMode).getValue() != SslMode.DISABLED
? (capabilityFlags & NativeServerSession.CLIENT_SSL)
: 0)
| (this.propertySet.getBooleanProperty(PropertyKey.trackSessionState).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_SESSION_TRACK)
: 0);

// TODO MYSQLCONNJ-437
// clientParam |= (capabilityFlags & NativeServerSession.CLIENT_SESSION_TRACK);

sessState.setClientParam(clientParam);

/* First, negotiate SSL connection */
Expand Down Expand Up @@ -467,6 +466,7 @@ private void proceedHandshakeWithPluggableAuthentication(ServerSession serverSes
// read OK packet
OkPacket ok = OkPacket.parse(last_received, null);
serverSession.setStatusFlags(ok.getStatusFlags(), true);
serverSession.getServerSessionStateController().setSessionStateChanges(ok.getSessionStateChanges());

// if OK packet then finish handshake
plugin.destroy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,7 @@ public final <T> T readServerStatusForResultSets(NativePacketPayload rowPacket,
result = (T) ok;

this.serverSession.setStatusFlags(ok.getStatusFlags(), saveOldStatus);
this.serverSession.getServerSessionStateController().setSessionStateChanges(ok.getSessionStateChanges());
checkTransactionState();

this.warningCount = ok.getWarningCount();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.mysql.cj.exceptions.WrongArgumentException;
import com.mysql.cj.protocol.ServerCapabilities;
import com.mysql.cj.protocol.ServerSession;
import com.mysql.cj.protocol.ServerSessionStateController;
import com.mysql.cj.util.StringUtils;
import com.mysql.cj.util.TimeUtil;

Expand Down Expand Up @@ -86,6 +87,7 @@ public class NativeServerSession implements ServerSession {
private int statusFlags = 0;
private int serverDefaultCollationIndex;
private long clientParam = 0;
private NativeServerSessionStateController serverSessionStateController;

/** The map of server variables that we retrieve at connection init. */
private Map<String, String> serverVariables = new HashMap<>();
Expand Down Expand Up @@ -125,6 +127,7 @@ public class NativeServerSession implements ServerSession {
public NativeServerSession(PropertySet propertySet) {
this.propertySet = propertySet;
this.cacheDefaultTimeZone = this.propertySet.getBooleanProperty(PropertyKey.cacheDefaultTimeZone);
this.serverSessionStateController = new NativeServerSessionStateController();

// preconfigure some server variables which are consulted before their initialization from server
this.serverVariables.put("character_set_server", "utf8");
Expand Down Expand Up @@ -570,4 +573,10 @@ public TimeZone getDefaultTimeZone() {
}
return TimeZone.getDefault();
}

@Override
public ServerSessionStateController getServerSessionStateController() {
return this.serverSessionStateController;
}

}
Loading

0 comments on commit 1177f29

Please sign in to comment.