From 0930f22b2865dbeb228fd39bf6a10c4bae6f7b40 Mon Sep 17 00:00:00 2001
From: glarwood
Date: Mon, 13 May 2019 16:53:31 -0700
Subject: [PATCH 001/217] fix(ByteArrayOutputStream): call composed
OutputStream#write
---
.../github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
index 91e4ca44..7154ba22 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
@@ -68,6 +68,11 @@ public void write(int b) throws IOException {
outputStream.write(b);
}
+ @Override
+ public void write(byte[] bytes) throws IOException {
+ outputStream.write(bytes);
+ }
+
public byte[] toByteArray() {
// todo: whole approach feels wrong
if (outputStream instanceof java.io.ByteArrayOutputStream) {
From 23f3239dfd5c5e8fa4c1c35b9b9764f0aa9e01a5 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sun, 14 Jul 2019 18:28:36 +0200
Subject: [PATCH 002/217] fixes for non-strictly sequential behavior in JSON
fields
as of MySQL 8.0.16, there are cases (see
https://github.com/zendesk/maxwell/issues/1290) in which MySQL places
JSON binary data at the offset specified in the header instead of just
laying it out in order.
---
.../event/deserialization/json/JsonBinary.java | 3 +++
.../mysql/binlog/io/ByteArrayInputStream.java | 14 ++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
index a6b5fc0e..61fe3e66 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
@@ -189,6 +189,7 @@ public JsonBinary(byte[] bytes) {
public JsonBinary(ByteArrayInputStream contents) {
this.reader = contents;
+ this.reader.mark(Integer.MAX_VALUE);
}
public String getString() {
@@ -397,6 +398,8 @@ protected void parseObject(boolean small, JsonFormatter formatter)
}
} else {
// Parse the value ...
+ this.reader.reset();
+ this.reader.skip(entry.index + 1);
parse(entry.type, formatter);
}
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
index 350b8709..d899818c 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
@@ -218,4 +218,18 @@ public void skipToTheEndOfTheBlock() throws IOException {
}
}
+ @Override
+ public synchronized void mark(int readlimit) {
+ inputStream.mark(readlimit);
+ }
+
+ @Override
+ public boolean markSupported() {
+ return inputStream.markSupported();
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ inputStream.reset();
+ }
}
From a6a3af778c236bac4a85e347b489bb68940de99c Mon Sep 17 00:00:00 2001
From: dingxiaobo
Date: Sat, 12 Oct 2019 18:53:33 +0800
Subject: [PATCH 003/217] support "caching_sha2_password" (mysql 8.0 default)
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 19 ++-
.../binlog/network/ClientCapabilities.java | 1 +
.../AuthenticateNativePasswordCommand.java | 2 +-
.../command/AuthenticateSHA2Command.java | 142 ++++++++++++++++++
... AuthenticateSecurityPasswordCommand.java} | 5 +-
5 files changed, 162 insertions(+), 7 deletions(-)
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
rename src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/{AuthenticateCommand.java => AuthenticateSecurityPasswordCommand.java} (93%)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index c395aa7b..8d7d4af8 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -45,8 +45,9 @@
import com.github.shyiko.mysql.binlog.network.protocol.Packet;
import com.github.shyiko.mysql.binlog.network.protocol.PacketChannel;
import com.github.shyiko.mysql.binlog.network.protocol.ResultSetRowPacket;
-import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateNativePasswordCommand;
+import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSHA2Command;
+import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSecurityPasswordCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.Command;
import com.github.shyiko.mysql.binlog.network.protocol.command.DumpBinaryLogCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.DumpBinaryLogGtidCommand;
@@ -715,9 +716,11 @@ private void authenticate(GreetingPacket greetingPacket) throws IOException {
usingSSLSocket = true;
}
}
- AuthenticateCommand authenticateCommand = new AuthenticateCommand(schema, username, password,
- greetingPacket.getScramble());
- authenticateCommand.setCollation(collation);
+
+ Command authenticateCommand = "caching_sha2_password".equals(greetingPacket.getPluginProvidedData()) ?
+ new AuthenticateSHA2Command(schema, username, password, greetingPacket.getScramble(), collation) :
+ new AuthenticateSecurityPasswordCommand(schema, username, password, greetingPacket.getScramble(), collation);
+
channel.write(authenticateCommand, packetNumber);
byte[] authenticationResult = channel.read();
if (authenticationResult[0] != (byte) 0x00 /* ok */) {
@@ -728,6 +731,14 @@ private void authenticate(GreetingPacket greetingPacket) throws IOException {
errorPacket.getSqlState());
} else if (authenticationResult[0] == (byte) 0xFE) {
switchAuthentication(authenticationResult, usingSSLSocket);
+ } else if (authenticationResult[0] == (byte) 0x01) {
+ if (authenticationResult.length >= 2 && (authenticationResult[1] == 3) || (authenticationResult[1] == 4)) {
+ // 8.0 auth ok
+ byte[] authenticationResultSha2 = channel.read();
+ logger.log(Level.FINEST, "SHA2 auth result {0}", authenticationResultSha2);
+ } else {
+ throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + "&" + authenticationResult[1] + ")");
+ }
} else {
throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + ")");
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/ClientCapabilities.java b/src/main/java/com/github/shyiko/mysql/binlog/network/ClientCapabilities.java
index c744d5a9..d81e2e1a 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/ClientCapabilities.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/ClientCapabilities.java
@@ -42,6 +42,7 @@ public final class ClientCapabilities {
public static final int MULTI_RESULTS = 1 << 17; /* enable/disable multi-results */
public static final int PS_MULTI_RESULTS = 1 << 18; /* multi-results in ps-protocol */
public static final int PLUGIN_AUTH = 1 << 19; /* client supports plugin authentication */
+ public static final int PLUGIN_AUTH_LENENC_CLIENT_DATA = 1 << 21;
public static final int SSL_VERIFY_SERVER_CERT = 1 << 30;
public static final int REMEMBER_OPTIONS = 1 << 31;
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateNativePasswordCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateNativePasswordCommand.java
index f98eced0..25711af0 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateNativePasswordCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateNativePasswordCommand.java
@@ -29,6 +29,6 @@ public AuthenticateNativePasswordCommand(String scramble, String password) {
}
@Override
public byte[] toByteArray() throws IOException {
- return AuthenticateCommand.passwordCompatibleWithMySQL411(password, scramble);
+ return AuthenticateSecurityPasswordCommand.passwordCompatibleWithMySQL411(password, scramble);
}
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
new file mode 100644
index 00000000..c8afca7e
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2018 dingxiaobo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.github.shyiko.mysql.binlog.network.protocol.command;
+
+import com.github.shyiko.mysql.binlog.io.ByteArrayOutputStream;
+import com.github.shyiko.mysql.binlog.network.ClientCapabilities;
+
+import java.io.IOException;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @author dingxiaobo
+ */
+public class AuthenticateSHA2Command implements Command {
+
+ private String schema;
+ private String username;
+ private String password;
+ private String salt;
+ private int clientCapabilities;
+ private int collation;
+
+ public AuthenticateSHA2Command(String schema, String username, String password, String salt, int collation) {
+ this.schema = schema;
+ this.username = username;
+ this.password = password;
+ this.salt = salt;
+ this.collation = collation;
+ }
+
+ public void setClientCapabilities(int clientCapabilities) {
+ this.clientCapabilities = clientCapabilities;
+ }
+
+ @Override
+ public byte[] toByteArray() throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ int clientCapabilities = this.clientCapabilities;
+ if (clientCapabilities == 0) {
+ clientCapabilities |= ClientCapabilities.LONG_FLAG;
+ clientCapabilities |= ClientCapabilities.PROTOCOL_41;
+ clientCapabilities |= ClientCapabilities.SECURE_CONNECTION;
+ clientCapabilities |= ClientCapabilities.PLUGIN_AUTH;
+ clientCapabilities |= ClientCapabilities.PLUGIN_AUTH_LENENC_CLIENT_DATA;
+
+ if (schema != null) {
+ clientCapabilities |= ClientCapabilities.CONNECT_WITH_DB;
+ }
+ }
+ buffer.writeInteger(clientCapabilities, 4);
+ buffer.writeInteger(0, 4); // maximum packet length
+ buffer.writeInteger(collation, 1);
+ for (int i = 0; i < 23; i++) {
+ buffer.write(0);
+ }
+ buffer.writeZeroTerminatedString(username);
+ byte[] passwordSHA1 = encodePassword();
+ buffer.writeInteger(passwordSHA1.length, 1);
+ buffer.write(passwordSHA1);
+ if (schema != null) {
+ buffer.writeZeroTerminatedString(schema);
+ }
+ buffer.writeZeroTerminatedString("caching_sha2_password");
+
+ return buffer.toByteArray();
+ }
+
+ private byte[] encodePassword() {
+ if (password == null || "".equals(password)) {
+ return new byte[0];
+ }
+ // caching_sha2_password
+ /*
+ * Server does it in 4 steps (see sql/auth/sha2_password_common.cc Generate_scramble::scramble method):
+ *
+ * SHA2(src) => digest_stage1
+ * SHA2(digest_stage1) => digest_stage2
+ * SHA2(digest_stage2, m_rnd) => scramble_stage1
+ * XOR(digest_stage1, scramble_stage1) => scramble
+ */
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA-256");
+
+ int CACHING_SHA2_DIGEST_LENGTH = 32;
+ byte[] dig1 = new byte[CACHING_SHA2_DIGEST_LENGTH];
+ byte[] dig2 = new byte[CACHING_SHA2_DIGEST_LENGTH];
+ byte[] scramble1 = new byte[CACHING_SHA2_DIGEST_LENGTH];
+
+ // SHA2(src) => digest_stage1
+ md.update(password.getBytes(), 0, password.getBytes().length);
+ md.digest(dig1, 0, CACHING_SHA2_DIGEST_LENGTH);
+ md.reset();
+
+ // SHA2(digest_stage1) => digest_stage2
+ md.update(dig1, 0, dig1.length);
+ md.digest(dig2, 0, CACHING_SHA2_DIGEST_LENGTH);
+ md.reset();
+
+ // SHA2(digest_stage2, m_rnd) => scramble_stage1
+ md.update(dig2, 0, dig1.length);
+ md.update(salt.getBytes(), 0, salt.getBytes().length);
+ md.digest(scramble1, 0, CACHING_SHA2_DIGEST_LENGTH);
+
+ // XOR(digest_stage1, scramble_stage1) => scramble
+ byte[] mysqlScrambleBuff = new byte[CACHING_SHA2_DIGEST_LENGTH];
+ xor(dig1, mysqlScrambleBuff, scramble1, CACHING_SHA2_DIGEST_LENGTH);
+
+ return mysqlScrambleBuff;
+ } catch (NoSuchAlgorithmException ex) {
+ throw new RuntimeException(ex);
+ } catch (DigestException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void xor(byte[] from, byte[] to, byte[] scramble, int length) {
+ int pos = 0;
+ int scrambleLength = scramble.length;
+
+ while (pos < length) {
+ to[pos] = (byte) (from[pos] ^ scramble[pos % scrambleLength]);
+ pos++;
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
similarity index 93%
rename from src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateCommand.java
rename to src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
index a045fe24..d99d6317 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
@@ -25,7 +25,7 @@
/**
* @author Stanley Shyiko
*/
-public class AuthenticateCommand implements Command {
+public class AuthenticateSecurityPasswordCommand implements Command {
private String schema;
private String username;
@@ -34,11 +34,12 @@ public class AuthenticateCommand implements Command {
private int clientCapabilities;
private int collation;
- public AuthenticateCommand(String schema, String username, String password, String salt) {
+ public AuthenticateSecurityPasswordCommand(String schema, String username, String password, String salt, int collation) {
this.schema = schema;
this.username = username;
this.password = password;
this.salt = salt;
+ this.collation = collation;
}
public void setClientCapabilities(int clientCapabilities) {
From 88de1edf637186ed1d2377d961eb836e95a6c095 Mon Sep 17 00:00:00 2001
From: Richard Burnison
Date: Mon, 13 Apr 2020 11:54:50 -0400
Subject: [PATCH 004/217] Integration test idempotency.
The `BinaryLogClientIntegrationTest` class did not clean-up after
itself: it tried to create the `test_metameta` table unconditionally.
This test would then fail if the tests were run twice. I _believe_ that
this change keeps the original intent intact.
---
.../shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 71dfb524..9896e504 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -994,6 +994,7 @@ public void execute(Statement statement) throws SQLException {
@Test
public void testMySQL8TableMetadata() throws Exception {
+ master.execute("drop table if exists test_metameta");
master.execute("create table test_metameta ( " +
"a date, b date, c date, d date, e date, f date, g date, " +
"h date, i date, j int)");
From 7e878a6e744d2a35c677d2ab89a5606e9d23cbb1 Mon Sep 17 00:00:00 2001
From: Richard Burnison
Date: Mon, 13 Apr 2020 11:17:44 -0400
Subject: [PATCH 005/217] Add master server ID to BinaryLogClient.
When the `BinaryLogClient` connects to a MySQL server, it's not
currently possible to identify to which server it has connected. When
connecting to a pool of replicas through a load balancer, for example, a
reconnect may mean the `BinaryLogClient` is connected to a different
MySQL server.
When using binary log file positions instead of GTIDs, this can be
critical: attempting to resume from the same binary log positions on a
different MySQL server may result in missed or duplicated events.
Similarly, not resuming from the same binary log positions when
reconnecting to the same server is wasteful and may result in longer
recovery/catch-up times.
This change adds the ability to get the equivalent of `MASTER_SERVER_ID`
from the `BinaryLogClient`. This can then be inspected within each of
the `LifecycleListener` events.
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 14 ++++++++++++++
.../binlog/BinaryLogClientIntegrationTest.java | 11 +++++++++++
2 files changed, 25 insertions(+)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index c395aa7b..0a860374 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -150,6 +150,7 @@ public X509Certificate[] getAcceptedIssuers() {
private volatile PacketChannel channel;
private volatile boolean connected;
+ private volatile long masterServerId = -1;
private ThreadFactory threadFactory;
@@ -228,6 +229,10 @@ public void setSSLMode(SSLMode sslMode) {
this.sslMode = sslMode;
}
+ public long getMasterServerId() {
+ return this.masterServerId;
+ }
+
/**
* @return server id (65535 by default)
* @see #setServerId(long)
@@ -534,6 +539,7 @@ public void connect() throws IOException {
if (checksumType != ChecksumType.NONE) {
confirmSupportOfChecksum(checksumType);
}
+ setMasterServerId();
if (heartbeatInterval > 0) {
enableHeartbeat();
}
@@ -656,6 +662,14 @@ private void enableHeartbeat() throws IOException {
}
}
+ private void setMasterServerId() throws IOException {
+ channel.write(new QueryCommand("select @@server_id"));
+ ResultSetRowPacket[] resultSet = readResultSet();
+ if (resultSet.length >= 0) {
+ this.masterServerId = Long.parseLong(resultSet[0].getValue(0));
+ }
+ }
+
private void requestBinaryLogStream() throws IOException {
long serverId = blocking ? this.serverId : 0; // http://bugs.mysql.com/bug.php?id=71178
Command dumpBinaryLogCommand;
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 9896e504..fd45275e 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -1002,6 +1002,17 @@ public void testMySQL8TableMetadata() throws Exception {
eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
}
+ @Test
+ public void testSetMasterServerId() throws Exception {
+ slave.query("SELECT @@server_id", new Callback() {
+ @Override
+ public void execute(final ResultSet rs) throws SQLException {
+ rs.next();
+ assertEquals(client.getMasterServerId(), rs.getLong("@@server_id"));
+ }
+ });
+ }
+
@AfterMethod
public void afterEachTest() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
From 4a7de10140c97cbd6da7bee573bf75ce005de402 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 24 Apr 2020 11:59:45 -0700
Subject: [PATCH 006/217] update pom.xml with fork info
---
pom.xml | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/pom.xml b/pom.xml
index a3f78dcb..a2e789c2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,13 +2,13 @@
4.0.0
- com.github.shyiko
+ com.zendeskmysql-binlog-connector-java
- 0.0.0-SNAPSHOT
+ 0.20.2mysql-binlog-connector-javaMySQL Binary Log connector
- https://github.com/shyiko/mysql-binlog-connector-java
+ https://github.com/osheroff/mysql-binlog-connector-javaApache License, Version 2.0
@@ -17,9 +17,9 @@
- scm:git:git@github.com:shyiko/mysql-binlog-connector-java.git
- scm:git:git@github.com:shyiko/mysql-binlog-connector-java.git
- git@github.com:shyiko/mysql-binlog-connector-java.git
+ scm:git:git@github.com:osheroff/mysql-binlog-connector-java.git
+ scm:git:git@github.com:osheroff/mysql-binlog-connector-java.git
+ git@github.com:osheroff/mysql-binlog-connector-java.git
@@ -27,6 +27,11 @@
stanley.shyiko@gmail.comStanley Shyiko
+
+ osheroff
+ ben@gimbo.net
+ Ben Osheroff
+
@@ -44,6 +49,11 @@
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.8
+ org.testngtestng
@@ -365,7 +375,7 @@
org.sonatype.pluginsnexus-staging-maven-plugin
- 1.6.7
+ 1.6.8truehttps://oss.sonatype.org/
From 83e28a461b07022dd70bb68728b1567904e30924 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 24 Apr 2020 12:00:29 -0700
Subject: [PATCH 007/217] add deploy notes
---
README.md | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/README.md b/README.md
index 595feb03..329aa9f8 100644
--- a/README.md
+++ b/README.md
@@ -216,6 +216,17 @@ cd mysql-binlog-connector-java
mvn # shows how to build, test, etc. project
```
+## Deployment
+
+First:
+http://maven.apache.org/guides/mini/guide-encryption.html
+
+Secondly:
+```
+ export OSS_SONATYPE_ORG_USERNAME=username
+ export OSS_SONATYPE_ORG_PASSWORD={encryptedpasswordJF!#$flkj}
+```
+
## Contributing
In lieu of a formal styleguide, please take care to maintain the existing coding style.
From 2a034d3545c0de0396f6865db4052de3c5cdc0a0 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 24 Apr 2020 12:00:51 -0700
Subject: [PATCH 008/217] add 0.22.0 notes
---
CHANGELOG.md | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd3c07ac..6a2ca264 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,13 @@
# Changelog
-All notable changes to this project will be documented in this file.
+All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
+## [0.22.0](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.20.0...0.22.9) - 2020-04-24
+
+- master server id is exposed in the library https://github.com/shyiko/mysql-binlog-connector-java/pull/319
+- Fixes for JSON data in mysql 8.0.16+ https://github.com/shyiko/mysql-binlog-connector-java/pull/288
+- more fixes for the bizarre azure platform https://github.com/shyiko/mysql-binlog-connector-java/pull/275
+
## [0.20.1](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.20.0...0.20.1) - 2019-05-12
### Added
From 73afc83cc720c237088b0e39a69b611658d8a6a1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 24 Apr 2020 12:53:29 -0700
Subject: [PATCH 009/217] oops, remove runtime dep on sonatype
that was just for debugging
---
pom.xml | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/pom.xml b/pom.xml
index a2e789c2..ec35952c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.20.2
+ 0.22.1mysql-binlog-connector-javaMySQL Binary Log connector
@@ -49,11 +49,6 @@
-
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.8
- org.testngtestng
From 4437b71ff35608906088eaecda6c29473a7c83ec Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 25 Apr 2020 21:51:11 -0700
Subject: [PATCH 010/217] fixes for JSON objects inside JSON objects
the value's offset is given as bytes from the object's beginning, not
from the beginning of the entire record, we have to account for that.
---
.../binlog/event/deserialization/json/JsonBinary.java | 6 +++++-
.../shyiko/mysql/binlog/io/ByteArrayInputStream.java | 9 +++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
index 61fe3e66..25ea2d7f 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
@@ -320,6 +320,10 @@ protected void parse(ValueType type, JsonFormatter formatter) throws IOException
*/
protected void parseObject(boolean small, JsonFormatter formatter)
throws IOException {
+ // this is terrible, but without a decent seekable InputStream the other way seemed like
+ // a full-on rewrite
+ int objectOffset = this.reader.getPosition();
+
// Read the header ...
int numElements = readUnsignedIndex(Integer.MAX_VALUE, small, "number of elements in");
int numBytes = readUnsignedIndex(Integer.MAX_VALUE, small, "size of");
@@ -399,7 +403,7 @@ protected void parseObject(boolean small, JsonFormatter formatter)
} else {
// Parse the value ...
this.reader.reset();
- this.reader.skip(entry.index + 1);
+ this.reader.skip(objectOffset + entry.index);
parse(entry.type, formatter);
}
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
index d899818c..ff71cbee 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
@@ -27,10 +27,12 @@ public class ByteArrayInputStream extends InputStream {
private InputStream inputStream;
private Integer peek;
+ private Integer pos, markPosition;
private int blockLength = -1;
public ByteArrayInputStream(InputStream inputStream) {
this.inputStream = inputStream;
+ this.pos = 0;
}
public ByteArrayInputStream(byte[] bytes) {
@@ -189,6 +191,7 @@ public int read() throws IOException {
if (result == -1) {
throw new EOFException();
}
+ this.pos += 1;
return result;
}
@@ -218,8 +221,13 @@ public void skipToTheEndOfTheBlock() throws IOException {
}
}
+ public int getPosition() {
+ return pos;
+ }
+
@Override
public synchronized void mark(int readlimit) {
+ markPosition = pos;
inputStream.mark(readlimit);
}
@@ -230,6 +238,7 @@ public boolean markSupported() {
@Override
public synchronized void reset() throws IOException {
+ pos = markPosition;
inputStream.reset();
}
}
From 1dd27a6278afdd8aae519a126754ac762d6c9fac Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sun, 26 Apr 2020 14:54:37 -0700
Subject: [PATCH 011/217] move from vagrant setup to onetimeserver setup
---
pom.xml | 54 +---
.../BinaryLogClientIntegrationTest.java | 19 +-
.../mysql/binlog/MysqlOnetimeServer.java | 270 ++++++++++++++++++
.../binlog/MysqlOnetimeServerOptions.java | 8 +
.../json/JsonBinaryValueIntegrationTest.java | 16 +-
src/test/onetimeserver | 117 ++++++++
6 files changed, 426 insertions(+), 58 deletions(-)
create mode 100644 src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
create mode 100644 src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServerOptions.java
create mode 100755 src/test/onetimeserver
diff --git a/pom.xml b/pom.xml
index ec35952c..4a327429 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,6 +73,18 @@
8.0.15test
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.9.10
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.9.10.3
+ test
+
@@ -146,48 +158,6 @@
-
-
- org.codehaus.mojo
- exec-maven-plugin
- 1.1.1
-
-
- start-vagrant-vm
- pre-integration-test
-
- exec
-
-
- ${vagrant.integration.box}
- ${vagrant.bin}
-
- up
-
- ${skipTests}
-
-
-
- destroy-vagrant-vm
- post-integration-test
-
- exec
-
-
- ${vagrant.integration.box}
- ${vagrant.bin}
-
- destroy
- --force
-
- ${skipTests}
-
-
-
- org.apache.maven.pluginsmaven-checkstyle-plugin
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index fd45275e..7460f60e 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -114,14 +114,15 @@ public class BinaryLogClientIntegrationTest {
@BeforeClass
public void setUp() throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
- ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
- String prefix = "jdbc.mysql.replication.";
- master = new MySQLConnection(bundle.getString(prefix + "master.hostname"),
- Integer.parseInt(bundle.getString(prefix + "master.port")),
- bundle.getString(prefix + "master.username"), bundle.getString(prefix + "master.password"));
- slave = new MySQLConnection(bundle.getString(prefix + "slave.hostname"),
- Integer.parseInt(bundle.getString(prefix + "slave.port")),
- bundle.getString(prefix + "slave.superUsername"), bundle.getString(prefix + "slave.superPassword"));
+ MysqlOnetimeServer masterServer = new MysqlOnetimeServer();
+ MysqlOnetimeServer slaveServer = new MysqlOnetimeServer();
+ masterServer.boot();
+ slaveServer.boot();
+ slaveServer.setupSlave(masterServer.getPort());
+
+ master = new MySQLConnection("127.0.0.1", masterServer.getPort(), "root", "");
+ slave = new MySQLConnection("127.0.0.1", slaveServer.getPort(), "root", "");
+
client = new BinaryLogClient(slave.hostname, slave.port, slave.username, slave.password);
EventDeserializer eventDeserializer = new EventDeserializer();
eventDeserializer.setCompatibilityMode(CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY,
@@ -1022,7 +1023,7 @@ public void afterEachTest() throws Exception {
public void onEvent(Event event) {
if (event.getHeader().getEventType() == EventType.QUERY) {
EventData data = event.getData();
- if (data != null && ((QueryEventData) data).getSql().contains("_EOS_marker")) {
+ if (data != null && ((QueryEventData) data).getSql().toLowerCase().contains("_eos_marker")) {
latch.countDown();
}
}
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
new file mode 100644
index 00000000..0810be7a
--- /dev/null
+++ b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
@@ -0,0 +1,270 @@
+package com.github.shyiko.mysql.binlog;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.sql.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+public class MysqlOnetimeServer {
+ private final MysqlOnetimeServerOptions options;
+ public static int nextServerID = 1;
+ public final int SERVER_ID = MysqlOnetimeServer.nextServerID++;
+ private final Logger logger = Logger.getLogger(getClass().getName());
+
+
+ private Connection connection;
+ private int port;
+ private int serverPid;
+ public String path;
+
+ public static final TypeReference
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonStringFormatter.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonStringFormatter.java
index 5ae92c85..58a3b841 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonStringFormatter.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonStringFormatter.java
@@ -19,6 +19,7 @@
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.util.Base64;
/**
* A {@link JsonFormatter} implementation that creates a JSON string representation.
@@ -197,7 +198,7 @@ public void valueTimestamp(long secondsPastEpoch, int microSeconds) {
@Override
public void valueOpaque(ColumnType type, byte[] value) {
sb.append('"');
- sb.append(javax.xml.bind.DatatypeConverter.printBase64Binary(value));
+ sb.append(Base64.getEncoder().encodeToString(value));
sb.append('"');
}
From 95d80b2eb3c6fe94228c7ee8182516f8282e842b Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sun, 26 Apr 2020 16:14:27 -0700
Subject: [PATCH 015/217] remove the other instance of javax.xml
---
.../shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 7460f60e..e032b068 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -42,7 +42,6 @@
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import javax.xml.bind.DatatypeConverter;
import java.io.Closeable;
import java.io.EOFException;
import java.io.FilterInputStream;
@@ -62,6 +61,7 @@
import java.sql.SQLSyntaxErrorException;
import java.sql.Statement;
import java.util.AbstractMap;
+import java.util.Base64;
import java.util.BitSet;
import java.util.Calendar;
import java.util.List;
@@ -323,7 +323,7 @@ public void testDeserializationOfSTRING() throws Exception {
assertEquals(writeAndCaptureRow("binary", "x'01'"), new Serializable[]{new byte[] {1}});
assertEquals(writeAndCaptureRow("binary", "x'FF'"), new Serializable[]{new byte[] {-1}});
assertEquals(writeAndCaptureRow("binary(16)", "unhex(md5(\"glob\"))"),
- new Serializable[]{DatatypeConverter.parseHexBinary("8684147451a6cc3b92142c6f4b78e61c")});
+ new Serializable[]{Base64.getDecoder().decode("hoQUdFGmzDuSFCxvS3jmHA==")});
}
@Test
From 32b457a5a9587bd9c77e2dd3fa9befe6b0a46ca3 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sun, 26 Apr 2020 16:18:15 -0700
Subject: [PATCH 016/217] get rid of checkstyle & coverage
---
pom.xml | 83 +--------------------------------------------------------
1 file changed, 1 insertion(+), 82 deletions(-)
diff --git a/pom.xml b/pom.xml
index 3022e0a2..a598e8c6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -158,33 +158,6 @@
-
- org.apache.maven.plugins
- maven-checkstyle-plugin
- 2.9.1
-
- true
- supplement/codequality/checkstyle.xml
- supplement/codequality/license.header
- true
- true
-
-
-
- verify
-
- checkstyle
-
-
-
-
-
- com.github.shyiko
- checkstyle-nonstandard
- 0.1.0
-
-
- com.github.shyiko.usage-maven-pluginusage-maven-plugin
@@ -194,24 +167,10 @@
# build everything (append "-DskipTests=true" if you wish to skip tests)
./mvnw clean package
- # run unit + integration tests, validate codebase using checkstyle
+ # run unit + integration tests
./mvnw -P coverage clean verify
# use -Dvagrant.integration.box= to switch between MySQL sandboxes
- # for aggregated coverage over different mysql releases use
- ./mvnw clean
- ./mvnw -P coverage verify \
- -Dvagrant.integration.box=supplement/vagrant/mysql-5.5.27-sandbox-prepackaged
- ./mvnw -P coverage verify \
- -Dvagrant.integration.box=supplement/vagrant/mysql-5.6.12-sandbox-prepackaged
- ./mvnw -P coverage verify \
- -Dvagrant.integration.box=supplement/vagrant/mysql-5.7.15-sandbox-prepackaged
- ./mvnw -P coverage,mysql-8-compat verify \
- -Dvagrant.integration.box=supplement/vagrant/mysql-8.0.1-sandbox-prepackaged
-
- # submit coverage report to coveralls
- ./mvnw -P coverage coveralls:jacoco -DrepoToken=<coveralls.io>
-
# publish a new version
./mvnw versions:set -DnewVersion=<version>
./mvnw -Ddeploy=maven-central
@@ -241,46 +200,6 @@
-
- coverage
-
-
-
- org.jacoco
- jacoco-maven-plugin
- 0.7.9
-
- ${basedir}/target/coverage-reports/jacoco-unit.exec
- ${basedir}/target/coverage-reports/jacoco-unit.exec
- true
-
- **/ClientCapabilities.*
-
-
-
-
- jacoco-initialize
-
- prepare-agent
-
-
-
- jacoco-site
- post-integration-test
-
- report
-
-
-
-
-
- org.eluder.coveralls
- coveralls-maven-plugin
- 2.0.0
-
-
-
- deploy-to-maven-central
From 1811e4578c48ab06cae862fe936fef429a423fb4 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 27 Apr 2020 10:50:06 -0700
Subject: [PATCH 017/217] skip GTID tests on 5.5. better way of setting up
GTID.
---
.../BinaryLogClientGTIDIntegrationTest.java | 43 +++---------------
.../BinaryLogClientIntegrationTest.java | 12 ++++-
.../mysql/binlog/MysqlOnetimeServer.java | 6 +++
.../shyiko/mysql/binlog/MysqlVersion.java | 45 +++++++++++++++++++
4 files changed, 67 insertions(+), 39 deletions(-)
create mode 100644 src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
index df033afa..ec86f377 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
@@ -18,6 +18,7 @@
import com.github.shyiko.mysql.binlog.event.QueryEventData;
import com.github.shyiko.mysql.binlog.event.XidEventData;
import com.github.shyiko.mysql.binlog.event.deserialization.EventDeserializer;
+import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -34,43 +35,11 @@
* @author Ben Osheroff
*/
public class BinaryLogClientGTIDIntegrationTest extends BinaryLogClientIntegrationTest {
-
- @BeforeClass
- private void enableGTID() throws SQLException {
- MySQLConnection[] servers = {slave, master};
- for (MySQLConnection m : servers) {
- m.execute(new Callback() {
- @Override
- public void execute(Statement statement) throws SQLException {
- ResultSet rs = statement.executeQuery("select @@GLOBAL.GTID_MODE as gtid_mode");
- rs.next();
- if ("ON".equals(rs.getString("gtid_mode"))) {
- return;
- }
- statement.execute("SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;");
- statement.execute("SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;");
- statement.execute("SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;");
- statement.execute("SET @@GLOBAL.GTID_MODE = ON;");
- }
- }, true);
- }
- }
-
- @AfterClass(alwaysRun = true)
- private void disableGTID() throws SQLException {
- MySQLConnection[] servers = {slave, master};
- for (MySQLConnection m : servers) {
- m.execute(new Callback() {
- @Override
- public void execute(Statement statement) throws SQLException {
- statement.execute("SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;");
- statement.execute("SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;");
- statement.execute("SET @@GLOBAL.GTID_MODE = OFF;");
- statement.execute("SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = OFF;");
- }
- }, true);
- }
- slave.execute("STOP SLAVE", "START SLAVE");
+ @Override
+ protected MysqlOnetimeServerOptions getOptions() {
+ MysqlOnetimeServerOptions options = new MysqlOnetimeServerOptions();
+ options.gtid = true;
+ return options;
}
@Test
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index e032b068..5ad84d62 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -34,6 +34,7 @@
import com.github.shyiko.mysql.binlog.network.AuthenticationException;
import com.github.shyiko.mysql.binlog.network.ServerException;
import com.github.shyiko.mysql.binlog.network.SocketFactory;
+import com.zendesk.maxwell.replication.MysqlVersion;
import org.mockito.InOrder;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
@@ -110,18 +111,25 @@ public class BinaryLogClientIntegrationTest {
protected MySQLConnection master, slave;
protected BinaryLogClient client;
protected CountDownEventListener eventListener;
+ protected MysqlVersion mysqlVersion;
+
+ protected MysqlOnetimeServerOptions getOptions() {
+ return null;
+ }
@BeforeClass
public void setUp() throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
- MysqlOnetimeServer masterServer = new MysqlOnetimeServer();
- MysqlOnetimeServer slaveServer = new MysqlOnetimeServer();
+ MysqlOnetimeServer masterServer = new MysqlOnetimeServer(getOptions());
+ MysqlOnetimeServer slaveServer = new MysqlOnetimeServer(getOptions());
+
masterServer.boot();
slaveServer.boot();
slaveServer.setupSlave(masterServer.getPort());
master = new MySQLConnection("127.0.0.1", masterServer.getPort(), "root", "");
slave = new MySQLConnection("127.0.0.1", slaveServer.getPort(), "root", "");
+ mysqlVersion = masterServer.getVersion();
client = new BinaryLogClient(slave.hostname, slave.port, slave.username, slave.password);
EventDeserializer eventDeserializer = new EventDeserializer();
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
index 0810be7a..ea22faa4 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
@@ -2,6 +2,7 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zendesk.maxwell.replication.MysqlVersion;
import java.io.BufferedReader;
import java.io.IOException;
@@ -245,6 +246,11 @@ public void shutDown() {
} catch ( IOException e ) {}
}
+ public MysqlVersion getVersion() {
+ String[] parts = getVersionString().split("\\.");
+ return new MysqlVersion(Integer.valueOf(parts[0]), Integer.valueOf(parts[1]));
+ }
+
private static String getVersionString() {
String mysqlVersion = System.getenv("MYSQL_VERSION");
return mysqlVersion == null ? "5.7" : mysqlVersion;
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java b/src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java
new file mode 100644
index 00000000..e46787b7
--- /dev/null
+++ b/src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java
@@ -0,0 +1,45 @@
+package com.zendesk.maxwell.replication;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+
+public class MysqlVersion {
+ private final int major;
+ private final int minor;
+
+ public MysqlVersion(int major, int minor) {
+ this.major = major;
+ this.minor = minor;
+ }
+
+ public boolean atLeast(int major, int minor) {
+ return (this.major > major) || (this.major == major && this.minor >= minor);
+ }
+
+ public boolean atLeast(MysqlVersion version) {
+ return atLeast(version.major, version.minor);
+ }
+
+ public boolean lessThan(int major, int minor) {
+ return (this.major < major) || (this.major == major & this.minor < minor);
+ }
+
+ public static MysqlVersion capture(Connection c) throws SQLException {
+ DatabaseMetaData meta = c.getMetaData();
+ return new MysqlVersion(meta.getDatabaseMajorVersion(), meta.getDatabaseMinorVersion());
+ }
+
+ public int getMajor() {
+ return this.major;
+ }
+
+ public int getMinor() {
+ return this.minor;
+ }
+
+ @Override
+ public String toString() {
+ return "MysqlVersion[" + this.major + "," + this.minor + "]";
+ }
+}
From bf2857810160370cad27bd01da65d0c2965abd98 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 27 Apr 2020 10:51:40 -0700
Subject: [PATCH 018/217] rename pipeline to 8.0
---
.circleci/config.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 47806d6b..9d282aa7 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -53,7 +53,7 @@ workflows:
mysql: "5.7"
requires: [ "build" ]
- test:
- name: "test-5.8"
+ name: "test-8.0"
mysql: "8.0"
requires: [ "build" ]
From 1771e96979c27c4458fbb9411bdaefd75a2c33d1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 27 Apr 2020 11:48:17 -0700
Subject: [PATCH 019/217] skip GTID on 5.5
---
.../mysql/binlog/BinaryLogClientGTIDIntegrationTest.java | 4 ++++
.../shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java | 2 +-
.../com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java | 4 ++--
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
index ec86f377..b29c6d02 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
@@ -37,6 +37,10 @@
public class BinaryLogClientGTIDIntegrationTest extends BinaryLogClientIntegrationTest {
@Override
protected MysqlOnetimeServerOptions getOptions() {
+ if ( !this.mysqlVersion.atLeast(5,7) ) {
+ throw new SkipException("skipping gtid on 5.5");
+ }
+
MysqlOnetimeServerOptions options = new MysqlOnetimeServerOptions();
options.gtid = true;
return options;
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 5ad84d62..32d7e408 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -120,6 +120,7 @@ protected MysqlOnetimeServerOptions getOptions() {
@BeforeClass
public void setUp() throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+ mysqlVersion = MysqlOnetimeServer.getVersion();
MysqlOnetimeServer masterServer = new MysqlOnetimeServer(getOptions());
MysqlOnetimeServer slaveServer = new MysqlOnetimeServer(getOptions());
@@ -129,7 +130,6 @@ public void setUp() throws Exception {
master = new MySQLConnection("127.0.0.1", masterServer.getPort(), "root", "");
slave = new MySQLConnection("127.0.0.1", slaveServer.getPort(), "root", "");
- mysqlVersion = masterServer.getVersion();
client = new BinaryLogClient(slave.hostname, slave.port, slave.username, slave.password);
EventDeserializer eventDeserializer = new EventDeserializer();
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
index ea22faa4..a3e385b0 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
@@ -34,7 +34,7 @@ public MysqlOnetimeServer() {
}
public MysqlOnetimeServer(MysqlOnetimeServerOptions options) {
- this.options = options;
+ this.options = options == null ? new MysqlOnetimeServerOptions() : options;
}
public void boot() throws Exception {
@@ -246,7 +246,7 @@ public void shutDown() {
} catch ( IOException e ) {}
}
- public MysqlVersion getVersion() {
+ public static MysqlVersion getVersion() {
String[] parts = getVersionString().split("\\.");
return new MysqlVersion(Integer.valueOf(parts[0]), Integer.valueOf(parts[1]));
}
From ecd1139261ae01dc113071405d5848444b380006 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 27 Apr 2020 11:57:12 -0700
Subject: [PATCH 020/217] re-enable 8.0 check
---
.../mysql/binlog/MysqlOnetimeServer.java | 35 +++++++++----------
1 file changed, 16 insertions(+), 19 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
index a3e385b0..9866e134 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
@@ -59,14 +59,14 @@ public void boot() throws Exception {
serverID = "--server_id=" + options.serverID;
String authPlugin = "";
- // if ( this.getVersion().atLeast(8, 0) ) {
- if ( false ) {
+
+ if ( getVersion().atLeast(8, 0) ) {
authPlugin = "--default-authentication-plugin=mysql_native_password";
}
ProcessBuilder pb = new ProcessBuilder(
dir + "/src/test/onetimeserver",
- "--mysql-version=" + this.getVersionString(),
+ "--mysql-version=" + getVersionString(),
"--log-slave-updates",
"--log-bin=master",
"--binlog_format=row",
@@ -91,24 +91,21 @@ public void boot() throws Exception {
final BufferedReader errReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
- new Thread() {
- @Override
- public void run() {
- while (true) {
- String l = null;
- try {
- l = errReader.readLine();
- } catch ( IOException e) {};
-
- if (l == null)
- break;
- System.err.println(l);
- }
- }
- }.start();
+ new Thread(() -> {
+ while (true) {
+ String l = null;
+ try {
+ l = errReader.readLine();
+ } catch ( IOException e) {};
+
+ if (l == null)
+ break;
+ System.err.println(l);
+ }
+ }).start();
String json = reader.readLine();
- String outputFile = null;
+ String outputFile;
try {
ObjectMapper mapper = new ObjectMapper();
Map output = mapper.readValue(json, MAP_STRING_OBJECT_REF);
From 1452ab965b2fa327a9aa2a94bd7f2c45a11897bf Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 27 Apr 2020 12:20:15 -0700
Subject: [PATCH 021/217] fix merge
---
.../json/JsonBinaryValueIntegrationTest.java | 26 +++++++++----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
index 082ddb20..30925211 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
@@ -410,18 +410,18 @@ private String writeAndCaptureJSON(final String value) throws Exception {
CapturingEventListener capturingEventListener = new CapturingEventListener();
client.registerEventListener(capturingEventListener);
try {
- master.execute(new BinaryLogClientIntegrationTest.Callback() {
- @Override
- public void execute(Statement statement) throws SQLException {
- statement.execute("drop table if exists data_type_hell");
- statement.execute("create table data_type_hell (column_ " + "JSON" + ")");
- statement.execute("insert into data_type_hell values (" + value + ")");
- }
+ master.execute(statement -> {
+ statement.execute("drop table if exists data_type_hell");
+ statement.execute("create table data_type_hell (column_ " + "JSON" + ")");
+ statement.execute("insert into data_type_hell values (" + value + ")");
});
eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
} finally {
client.unregisterEventListener(capturingEventListener);
}
+ if ( capturingEventListener.getEvents(WriteRowsEventData.class).size() == 0 ) {
+ assertTrue(false, "did not receive rows in json test for " + value);
+ }
byte[] b = (byte[]) capturingEventListener.getEvents(WriteRowsEventData.class).get(0).getRows().get(0)[0];
return b == null ? null : JsonBinary.parseAsString(b);
}
@@ -430,12 +430,12 @@ public void execute(Statement statement) throws SQLException {
public void afterEachTest() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
final String markerQuery = "drop table if exists _EOS_marker";
- BinaryLogClient.EventListener markerInterceptor = new BinaryLogClient.EventListener() {
- @Override
- public void onEvent(Event event) {
- if (event.getHeader().getEventType() == EventType.QUERY) {
- EventData data = event.getData();
- if (data != null && ((QueryEventData) data).getSql().toLowerCase().contains("_eos_marker")) {
+ BinaryLogClient.EventListener markerInterceptor = event -> {
+ if (event.getHeader().getEventType() == EventType.QUERY) {
+ EventData data = event.getData();
+ if (data != null) {
+ String sql = ((QueryEventData) data).getSql().toLowerCase();
+ if (sql.contains("_EOS_marker".toLowerCase())) {
latch.countDown();
}
}
From 75b5de59daecfe9226294fd2ca0003caaa96c323 Mon Sep 17 00:00:00 2001
From: auntyellow
Date: Tue, 28 Apr 2020 20:47:47 +0800
Subject: [PATCH 022/217] fix package name
---
.../shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java | 1 -
.../java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java | 1 -
src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java | 2 +-
3 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 32d7e408..43629133 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -34,7 +34,6 @@
import com.github.shyiko.mysql.binlog.network.AuthenticationException;
import com.github.shyiko.mysql.binlog.network.ServerException;
import com.github.shyiko.mysql.binlog.network.SocketFactory;
-import com.zendesk.maxwell.replication.MysqlVersion;
import org.mockito.InOrder;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
index 9866e134..3dca9cb4 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
@@ -2,7 +2,6 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.zendesk.maxwell.replication.MysqlVersion;
import java.io.BufferedReader;
import java.io.IOException;
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java b/src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java
index e46787b7..7213a724 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/MysqlVersion.java
@@ -1,4 +1,4 @@
-package com.zendesk.maxwell.replication;
+package com.github.shyiko.mysql.binlog;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
From 2c33620f62f98b31c57dd2ca547b1011b60b6c3f Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Tue, 28 Apr 2020 16:18:02 -0700
Subject: [PATCH 023/217] bump tests under 8.0.19
---
.../mysql/binlog/BinaryLogClientGTIDIntegrationTest.java | 4 ++--
src/test/onetimeserver | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
index b29c6d02..5246bd65 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientGTIDIntegrationTest.java
@@ -50,13 +50,13 @@ protected MysqlOnetimeServerOptions getOptions() {
public void testGTIDAdvancesStatementBased() throws Exception {
try {
master.execute("set global binlog_format=statement");
- slave.execute("set global binlog_format=statement", "stop slave", "start slave");
+ slave.execute("stop slave", "set global binlog_format=statement", "start slave");
master.reconnect();
master.execute("use test");
testGTIDAdvances();
} finally {
master.execute("set global binlog_format=row");
- slave.execute("set global binlog_format=row", "stop slave", "start slave");
+ slave.execute("stop slave", "set global binlog_format=row", "start slave");
master.reconnect();
master.execute("use test");
}
diff --git a/src/test/onetimeserver b/src/test/onetimeserver
index ef4196ce..a240a9c9 100755
--- a/src/test/onetimeserver
+++ b/src/test/onetimeserver
@@ -43,7 +43,7 @@ do
--no-clean)
NO_CLEAN="-no-clean"
;;
- -d|--debug)
+ -d|--debug|-debug)
DEBUG="-debug"
;;
-h|--help)
From 81ba86338b353015517a157a6f79b2c8bb6a9ce1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Wed, 29 Apr 2020 14:48:09 -0700
Subject: [PATCH 024/217] update changelog
---
CHANGELOG.md | 33 ++++++++++++++++++---------------
pom.xml | 2 +-
2 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a2ca264..4ba26f3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,12 @@
# Changelog
-All notable changes to this project will be documented in this file.
-This project adheres to [Semantic Versioning](http://semver.org/).
-## [0.22.0](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.20.0...0.22.9) - 2020-04-24
+## [0.22.2](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.22.0...0.22.2) - 2020-04-29
+- Fix bugs in 0.22.0 involving nested JSON objects.
+
+## [0.22.0](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.20.1...0.22.0) - 2020-04-24
+
+- *THIS RELEASE IS BUGGY. DO NOT USE.*
- master server id is exposed in the library https://github.com/shyiko/mysql-binlog-connector-java/pull/319
- Fixes for JSON data in mysql 8.0.16+ https://github.com/shyiko/mysql-binlog-connector-java/pull/288
- more fixes for the bizarre azure platform https://github.com/shyiko/mysql-binlog-connector-java/pull/275
@@ -103,7 +106,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [0.10.1](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.10.0...0.10.1) - 2017-02-28
### Fixed
-- HEARTBEAT tracking ([118](https://github.com/shyiko/mysql-binlog-connector-java/issues/118#issuecomment-283138143)).
+- HEARTBEAT tracking ([118](https://github.com/shyiko/mysql-binlog-connector-java/issues/118#issuecomment-283138143)).
## [0.10.0](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.9.2...0.10.0) - 2017-02-28
@@ -125,13 +128,13 @@ isn't reached within `BinaryLogClient::connectTimeout` from `BinaryLogClient::co
### Fixed
- - NPE in case of EOF (BinaryLogClient) ([153](https://github.com/shyiko/mysql-binlog-connector-java/pull/153)).
+ - NPE in case of EOF (BinaryLogClient) ([153](https://github.com/shyiko/mysql-binlog-connector-java/pull/153)).
## [0.9.0](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.8.1...0.9.0) - 2017-02-07
### Added
- - `BinaryLogClient::connectTimeout` (3 seconds by default).
+ - `BinaryLogClient::connectTimeout` (3 seconds by default).
NOTE: `BinaryLogClient::keepAliveConnectTimeout` has been deprecated and is going to be removed in 1.0.0.
## [0.8.1](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.8.0...0.8.1) - 2016-01-10
@@ -150,14 +153,14 @@ isn't reached within `BinaryLogClient::connectTimeout` from `BinaryLogClient::co
### Fixed
- - `SSLMode.PREFERRED` handling (verification against the CA is no longer enforced) ([#142](https://github.com/shyiko/mysql-binlog-connector-java/pull/142)).
+ - `SSLMode.PREFERRED` handling (verification against the CA is no longer enforced) ([#142](https://github.com/shyiko/mysql-binlog-connector-java/pull/142)).
NOTE: This change does NOT affect `SSLMode.VERIFY_CA` / `SSLMode.VERIFY_IDENTITY`.
## [0.7.3](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.7.2...0.7.3) - 2016-12-26
### Fixed
- - Handling of DATE/DATETIME/TIMESTAMP "zero" value (e.g. '0000-00-00') when
+ - Handling of DATE/DATETIME/TIMESTAMP "zero" value (e.g. '0000-00-00') when
`CompatibilityMode.DATE_AND_TIME_AS_LONG_MICRO` is set (false by default).
## [0.7.2](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.7.1...0.7.2) - 2016-12-26
@@ -179,7 +182,7 @@ isn't reached within `BinaryLogClient::connectTimeout` from `BinaryLogClient::co
## [0.6.0](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.5.2...0.6.0) - 2016-11-27
-### Added
+### Added
- `EventDeserializer` compatibility modes to mimic upcoming 1.0.0 event deserialization behavior ([#131](https://github.com/shyiko/mysql-binlog-connector-java/pull/131)).
## [0.5.2](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.5.1...0.5.2) - 2016-11-19
@@ -208,9 +211,9 @@ isn't reached within `BinaryLogClient::connectTimeout` from `BinaryLogClient::co
### Fixed
- GTID "rollover".
- - binlog position tracking (`binaryLogClient.binlogPosition` is no longer updated on TABLE_MAP so that in case of
- reconnect (using a different instance of client) table mapping (used by *RowsEventDataDeserializer|s) could be
- reconstructed before hitting *RowsEvent.
+ - binlog position tracking (`binaryLogClient.binlogPosition` is no longer updated on TABLE_MAP so that in case of
+ reconnect (using a different instance of client) table mapping (used by *RowsEventDataDeserializer|s) could be
+ reconstructed before hitting *RowsEvent.
## [0.4.0](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.3.3...0.4.0) - 2016-08-15
@@ -248,7 +251,7 @@ isn't reached within `BinaryLogClient::connectTimeout` from `BinaryLogClient::co
### Fixed
- Possible infinite loop in case of EOF in the middle of `ByteArrayInputStream::fill`.
-
+
## [0.2.3](https://github.com/shyiko/mysql-binlog-connector-java/compare/0.2.2...0.2.3) - 2015-08-31
### Fixed
@@ -275,8 +278,8 @@ isn't reached within `BinaryLogClient::connectTimeout` from `BinaryLogClient::co
- Support for authentication via empty password ([#39](https://github.com/shyiko/mysql-binlog-connector-java/issues/39)).
### Changed
-- Server error reporting ([#37](https://github.com/shyiko/mysql-binlog-connector-java/issues/37)).
- WARNING: If you are using exception message to identify specific server errors - you'll need to switch to
+- Server error reporting ([#37](https://github.com/shyiko/mysql-binlog-connector-java/issues/37)).
+ WARNING: If you are using exception message to identify specific server errors - you'll need to switch to
`ServerException`::[errorCode](https://github.com/shyiko/mysql-binlog-connector-java/commit/1817d0ff709c65c31af9236dcc4e50cc3ad1023b#diff-0dff747d57cb3f5f0548be89a81e29f8R37) (as message no longer includes error code).
### Fixed
diff --git a/pom.xml b/pom.xml
index a598e8c6..1609c3ad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.22.1
+ 0.22.2mysql-binlog-connector-javaMySQL Binary Log connector
From e775757e55135844df748cc85486452cf994d7f3 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Wed, 29 Apr 2020 17:55:52 -0700
Subject: [PATCH 025/217] make releases automatic
---
pom.xml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index 1609c3ad..9399c5ec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -264,8 +264,7 @@
https://oss.sonatype.org/maven-central
- true
-
+ true
From 620c10b175d8172c2e9b1f7152d03a19be165fc0 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 1 May 2020 09:29:18 -0700
Subject: [PATCH 026/217] add integration test for mysql 8.0 json partial
update
---
.../json/JsonBinaryValueIntegrationTest.java | 66 +++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
index 30925211..dcc44f81 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
@@ -106,6 +106,72 @@ public void execute(Statement statement) throws SQLException {
eventListener.reset();
}
+ @Test
+ public void testMysql8JsonSetPartialUpdateWithHoles() throws Exception {
+ CountDownEventListener eventListener = new CountDownEventListener();
+ client.registerEventListener(eventListener);
+ CapturingEventListener capturingEventListener = new CapturingEventListener();
+ client.registerEventListener(capturingEventListener);
+ String json = "{\"age\":22,\"addr\":{\"code\":100,\"detail\":{\"ab\":\"970785C8-C299\"}},\"name\":\"Alice\"}";
+ master.execute("DROP TABLE IF EXISTS json_test", "create table json_test (j JSON)",
+ "INSERT INTO json_test VALUES ('" + json + "')",
+ "UPDATE json_test SET j = JSON_SET(j, '$.addr.detail.ab', '970785C8')");
+ eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ eventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ List events = capturingEventListener.getEvents(WriteRowsEventData.class);
+ Serializable[] insertData = events.iterator().next().getRows().get(0);
+ assertEquals(JsonBinary.parseAsString((byte[]) insertData[0]), json);
+
+ List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
+ Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
+ assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), json.replace("970785C8-C299", "970785C8"));
+ assertEquals(((byte[]) updateData[0]).length, ((byte[]) insertData[0]).length);
+ }
+
+ @Test
+ public void testMysql8JsonRemovePartialUpdateWithHoles() throws Exception {
+ CountDownEventListener eventListener = new CountDownEventListener();
+ client.registerEventListener(eventListener);
+ CapturingEventListener capturingEventListener = new CapturingEventListener();
+ client.registerEventListener(capturingEventListener);
+ String json = "{\"age\":22,\"addr\":{\"code\":100,\"detail\":{\"ab\":\"970785C8-C299\"}},\"name\":\"Alice\"}";
+ master.execute("DROP TABLE IF EXISTS json_test", "create table json_test (j JSON)",
+ "INSERT INTO json_test VALUES ('" + json + "')",
+ "UPDATE json_test SET j = JSON_REMOVE(j, '$.addr.detail.ab')");
+ eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ eventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ List events = capturingEventListener.getEvents(WriteRowsEventData.class);
+ Serializable[] insertData = events.iterator().next().getRows().get(0);
+ assertEquals(JsonBinary.parseAsString((byte[]) insertData[0]), json);
+
+ List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
+ Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
+ assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), json.replace("\"ab\":\"970785C8-C299\"", ""));
+ assertEquals(((byte[]) updateData[0]).length, ((byte[]) insertData[0]).length);
+ }
+
+ @Test
+ public void testMysql8JsonReplacePartialUpdateWithHoles() throws Exception {
+ CountDownEventListener eventListener = new CountDownEventListener();
+ client.registerEventListener(eventListener);
+ CapturingEventListener capturingEventListener = new CapturingEventListener();
+ client.registerEventListener(capturingEventListener);
+ String json = "{\"age\":22,\"addr\":{\"code\":100,\"detail\":{\"ab\":\"970785C8-C299\"}},\"name\":\"Alice\"}";
+ master.execute("DROP TABLE IF EXISTS json_test", "create table json_test (j JSON)",
+ "INSERT INTO json_test VALUES ('" + json + "')",
+ "UPDATE json_test SET j = JSON_REPLACE(j, '$.addr.detail.ab', '9707')");
+ eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ eventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ List events = capturingEventListener.getEvents(WriteRowsEventData.class);
+ Serializable[] insertData = events.iterator().next().getRows().get(0);
+ assertEquals(JsonBinary.parseAsString((byte[]) insertData[0]), json);
+
+ List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
+ Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
+ assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), json.replace("970785C8-C299", "9707"));
+ assertEquals(((byte[]) updateData[0]).length, ((byte[]) insertData[0]).length);
+ }
+
@Test
public void testValueBoundariesAreHonored() throws Exception {
CountDownEventListener eventListener = new CountDownEventListener();
From 16329a753cc4462c6540bebe813c1753dfebda51 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 1 May 2020 09:45:46 -0700
Subject: [PATCH 027/217] fix maven compiler args
---
pom.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index 9399c5ec..79a568f5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,8 +105,8 @@
maven-compiler-plugin3.5.1
- 8
- 8
+ 1.8
+ 1.8
From 8e83bd960891e1465726953238ec188abf0807f6 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 1 May 2020 09:45:48 -0700
Subject: [PATCH 028/217] add in some tests around the mysql 8.0.19 gaps
---
.../json/JsonBinaryValueIntegrationTest.java | 27 ++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
index dcc44f81..12552c31 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
@@ -26,6 +26,7 @@
import com.github.shyiko.mysql.binlog.event.EventData;
import com.github.shyiko.mysql.binlog.event.EventType;
import com.github.shyiko.mysql.binlog.event.QueryEventData;
+import com.github.shyiko.mysql.binlog.event.UpdateRowsEventData;
import com.github.shyiko.mysql.binlog.event.WriteRowsEventData;
import org.skyscreamer.jsonassert.JSONAssert;
import org.testng.annotations.AfterClass;
@@ -125,7 +126,6 @@ public void testMysql8JsonSetPartialUpdateWithHoles() throws Exception {
List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), json.replace("970785C8-C299", "970785C8"));
- assertEquals(((byte[]) updateData[0]).length, ((byte[]) insertData[0]).length);
}
@Test
@@ -147,7 +147,6 @@ public void testMysql8JsonRemovePartialUpdateWithHoles() throws Exception {
List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), json.replace("\"ab\":\"970785C8-C299\"", ""));
- assertEquals(((byte[]) updateData[0]).length, ((byte[]) insertData[0]).length);
}
@Test
@@ -169,7 +168,29 @@ public void testMysql8JsonReplacePartialUpdateWithHoles() throws Exception {
List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), json.replace("970785C8-C299", "9707"));
- assertEquals(((byte[]) updateData[0]).length, ((byte[]) insertData[0]).length);
+ }
+
+ @Test
+ public void testMysql8JsonRemoveArrayValue() throws Exception {
+ CountDownEventListener eventListener = new CountDownEventListener();
+ client.registerEventListener(eventListener);
+ CapturingEventListener capturingEventListener = new CapturingEventListener();
+ client.registerEventListener(capturingEventListener);
+
+ String json = "[\"foo\",\"bar\",\"baz\"]";
+ master.execute("DROP TABLE IF EXISTS json_test", "create table json_test (j JSON)",
+ "INSERT INTO json_test VALUES ('" + json + "')",
+ "UPDATE json_test SET j = JSON_REMOVE(j, '$[1]')");
+ eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ eventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
+
+ List events = capturingEventListener.getEvents(WriteRowsEventData.class);
+ Serializable[] insertData = events.iterator().next().getRows().get(0);
+ assertEquals(JsonBinary.parseAsString((byte[]) insertData[0]), json);
+
+ List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
+ Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
+ assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), "[\"foo\",\"baz\"]");
}
@Test
From 430c4462f4aeeab1222a3227f5b8149d0b14530a Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 1 May 2020 09:46:31 -0700
Subject: [PATCH 029/217] gitignore vim stuff
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 38431278..88ff3803 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ target
.project
.settings
.vagrant
+.*.sw*
From 13648dfa1aa514f2a0bdb95a938e673e7d18a33e Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 1 May 2020 09:47:01 -0700
Subject: [PATCH 030/217] remove vagrant stuff
---
supplement/codequality/checkstyle.xml | 151 ------------------
supplement/codequality/license.header | 15 --
supplement/codequality/readme.md | 5 -
.../vagrantfile | 6 -
.../vagrant/mysql-5.5.27-sandbox/vagrantfile | 21 ---
.../vagrantfile | 6 -
.../vagrant/mysql-5.6.12-sandbox/vagrantfile | 21 ---
.../vagrantfile | 6 -
.../vagrant/mysql-5.7.15-sandbox/vagrantfile | 22 ---
.../vagrantfile | 9 --
.../vagrant/mysql-8.0.1-sandbox/vagrantfile | 24 ---
supplement/vagrant/readme.md | 7 -
12 files changed, 293 deletions(-)
delete mode 100644 supplement/codequality/checkstyle.xml
delete mode 100644 supplement/codequality/license.header
delete mode 100644 supplement/codequality/readme.md
delete mode 100644 supplement/vagrant/mysql-5.5.27-sandbox-prepackaged/vagrantfile
delete mode 100644 supplement/vagrant/mysql-5.5.27-sandbox/vagrantfile
delete mode 100644 supplement/vagrant/mysql-5.6.12-sandbox-prepackaged/vagrantfile
delete mode 100644 supplement/vagrant/mysql-5.6.12-sandbox/vagrantfile
delete mode 100644 supplement/vagrant/mysql-5.7.15-sandbox-prepackaged/vagrantfile
delete mode 100644 supplement/vagrant/mysql-5.7.15-sandbox/vagrantfile
delete mode 100644 supplement/vagrant/mysql-8.0.1-sandbox-prepackaged/vagrantfile
delete mode 100644 supplement/vagrant/mysql-8.0.1-sandbox/vagrantfile
delete mode 100644 supplement/vagrant/readme.md
diff --git a/supplement/codequality/checkstyle.xml b/supplement/codequality/checkstyle.xml
deleted file mode 100644
index 832357d4..00000000
--- a/supplement/codequality/checkstyle.xml
+++ /dev/null
@@ -1,151 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/supplement/codequality/license.header b/supplement/codequality/license.header
deleted file mode 100644
index a0c33261..00000000
--- a/supplement/codequality/license.header
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright [yyyy] [name of copyright owner]
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
\ No newline at end of file
diff --git a/supplement/codequality/readme.md b/supplement/codequality/readme.md
deleted file mode 100644
index 99c9aebb..00000000
--- a/supplement/codequality/readme.md
+++ /dev/null
@@ -1,5 +0,0 @@
-### IDE integration
-
-1. import checkstyle.xml configuration file
-2. set "checkstyle.header.file" property to the absolute path of license.header file
-3. add [checkstyle-nonstandard-0.1.0.jar](http://search.maven.org/remotecontent?filepath=com/github/shyiko/checkstyle-nonstandard/0.1.0/checkstyle-nonstandard-0.1.0.jar) to the list of third-party check providers
\ No newline at end of file
diff --git a/supplement/vagrant/mysql-5.5.27-sandbox-prepackaged/vagrantfile b/supplement/vagrant/mysql-5.5.27-sandbox-prepackaged/vagrantfile
deleted file mode 100644
index 5e349bfd..00000000
--- a/supplement/vagrant/mysql-5.5.27-sandbox-prepackaged/vagrantfile
+++ /dev/null
@@ -1,6 +0,0 @@
-Vagrant.configure("2") do |config|
- config.vm.box = 'shyiko/mysql-sandbox-prepackaged'
- config.vm.box_version = '5.5.27'
- config.vm.network :forwarded_port, guest: 33061, host: 33061
- config.vm.network :forwarded_port, guest: 33062, host: 33062
-end
diff --git a/supplement/vagrant/mysql-5.5.27-sandbox/vagrantfile b/supplement/vagrant/mysql-5.5.27-sandbox/vagrantfile
deleted file mode 100644
index ddaf1c71..00000000
--- a/supplement/vagrant/mysql-5.5.27-sandbox/vagrantfile
+++ /dev/null
@@ -1,21 +0,0 @@
-Vagrant.configure("2") do |config|
- config.vm.box = 'lucid32'
- config.vm.box_url = 'http://files.vagrantup.com/lucid32.box'
- config.vm.provision :shell, :inline => %Q(
- apt-get update && apt-get install -y make libaio1 # libaio1 required by mysql
- echo 'Downloading MySQL distribution ...'
- wget --progress=dot:mega --content-disposition \
- http://downloads.mysql.com/archives/mysql-5.5/mysql-5.5.27-linux2.6-i686.tar.gz \
- 2>&1 | grep --line-buffered -o '[0-9]*%'
- wget -O - https://launchpad.net/mysql-sandbox/mysql-sandbox-3/mysql-sandbox-3/+download/MySQL-Sandbox-3.0.33.tar.gz | tar xzv
- (cd MySQL-Sandbox-3.0.33 && perl Makefile.PL && make && make install)
- su -c "make_replication_sandbox ~/mysql-5.5.27-linux2.6-i686.tar.gz \
- --remote_access='%' --how_many_slaves=1 --sandbox_base_port=33061 \
- --master_options='-c binlog_format=ROW' \
- --slave_options='-c binlog_format=ROW -c log-slave-updates=TRUE'" vagrant
- rm -f *.tar.gz
- sed -i -e "s/exit\ 0/\\/home\\/vagrant\\/sandboxes\\/rsandbox_mysql-5_5_27\\/restart_all; exit 0/g" /etc/rc.local
- )
- config.vm.network :forwarded_port, guest: 33061, host: 33061
- config.vm.network :forwarded_port, guest: 33062, host: 33062
-end
diff --git a/supplement/vagrant/mysql-5.6.12-sandbox-prepackaged/vagrantfile b/supplement/vagrant/mysql-5.6.12-sandbox-prepackaged/vagrantfile
deleted file mode 100644
index fc15f376..00000000
--- a/supplement/vagrant/mysql-5.6.12-sandbox-prepackaged/vagrantfile
+++ /dev/null
@@ -1,6 +0,0 @@
-Vagrant.configure("2") do |config|
- config.vm.box = 'shyiko/mysql-sandbox-prepackaged'
- config.vm.box_version = '5.6.12'
- config.vm.network :forwarded_port, guest: 33061, host: 33061
- config.vm.network :forwarded_port, guest: 33062, host: 33062
-end
diff --git a/supplement/vagrant/mysql-5.6.12-sandbox/vagrantfile b/supplement/vagrant/mysql-5.6.12-sandbox/vagrantfile
deleted file mode 100644
index 4f36dc3a..00000000
--- a/supplement/vagrant/mysql-5.6.12-sandbox/vagrantfile
+++ /dev/null
@@ -1,21 +0,0 @@
-Vagrant.configure("2") do |config|
- config.vm.box = 'lucid32'
- config.vm.box_url = 'http://files.vagrantup.com/lucid32.box'
- config.vm.provision :shell, :inline => %Q(
- apt-get update && apt-get install -y make libaio1 # libaio1 required by mysql
- echo 'Downloading MySQL distribution ...'
- wget --progress=dot:mega --content-disposition \
- http://cdn.mysql.com/Downloads/MySQL-5.6/mysql-5.6.12-linux-glibc2.5-i686.tar.gz \
- 2>&1 | grep --line-buffered -o '[0-9]*%'
- wget -O - https://launchpad.net/mysql-sandbox/mysql-sandbox-3/mysql-sandbox-3/+download/MySQL-Sandbox-3.0.33.tar.gz | tar xzv
- (cd MySQL-Sandbox-3.0.33 && perl Makefile.PL && make && make install)
- su -c "make_replication_sandbox ~/mysql-5.6.12-linux-glibc2.5-i686.tar.gz \
- --remote_access='%' --how_many_slaves=1 --sandbox_base_port=33061 \
- --master_options='-c binlog_format=ROW' \
- --slave_options='-c binlog_format=ROW -c log-slave-updates=TRUE'" vagrant
- rm -f *.tar.gz
- sed -i -e "s/exit\ 0/\\/home\\/vagrant\\/sandboxes\\/rsandbox_mysql-5_6_12\\/restart_all; exit 0/g" /etc/rc.local
- )
- config.vm.network :forwarded_port, guest: 33061, host: 33061
- config.vm.network :forwarded_port, guest: 33062, host: 33062
-end
diff --git a/supplement/vagrant/mysql-5.7.15-sandbox-prepackaged/vagrantfile b/supplement/vagrant/mysql-5.7.15-sandbox-prepackaged/vagrantfile
deleted file mode 100644
index 7a644a5c..00000000
--- a/supplement/vagrant/mysql-5.7.15-sandbox-prepackaged/vagrantfile
+++ /dev/null
@@ -1,6 +0,0 @@
-Vagrant.configure("2") do |config|
- config.vm.box = 'shyiko/mysql-sandbox-prepackaged'
- config.vm.box_version = '5.7.15'
- config.vm.network :forwarded_port, guest: 33061, host: 33061
- config.vm.network :forwarded_port, guest: 33062, host: 33062
-end
diff --git a/supplement/vagrant/mysql-5.7.15-sandbox/vagrantfile b/supplement/vagrant/mysql-5.7.15-sandbox/vagrantfile
deleted file mode 100644
index 07cfd309..00000000
--- a/supplement/vagrant/mysql-5.7.15-sandbox/vagrantfile
+++ /dev/null
@@ -1,22 +0,0 @@
-Vagrant.configure("2") do |config|
- config.vm.box = 'lucid32'
- config.vm.box_url = 'http://files.vagrantup.com/lucid32.box'
- config.vm.provision :shell, :inline => %Q(
- sed -i.bak -r 's/(us.)?(archive|security).ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
- apt-get update && apt-get install -y make libaio1 # libaio1 required by mysql
- echo 'Downloading MySQL distribution ...'
- wget --progress=dot:mega --content-disposition \
- http://cdn.mysql.com/Downloads/MySQL-5.7/mysql-5.7.15-linux-glibc2.5-i686.tar.gz \
- 2>&1 | grep --line-buffered -o '[0-9]*%'
- wget -O - https://github.com/datacharmer/mysql-sandbox/releases/download/3.1.13/MySQL-Sandbox-3.1.13.tar.gz | tar xzv
- (cd MySQL-Sandbox-3.1.13 && perl Makefile.PL && make && make install)
- su -c "make_replication_sandbox ~/mysql-5.7.15-linux-glibc2.5-i686.tar.gz \
- --remote_access='%' --how_many_slaves=1 --sandbox_base_port=33061 \
- --master_options='-c binlog_format=ROW' \
- --slave_options='-c binlog_format=ROW -c log-slave-updates=TRUE'" vagrant
- rm -f *.tar.gz
- sed -i -e "s/exit\ 0/\\/home\\/vagrant\\/sandboxes\\/rsandbox_mysql-5_7_15\\/restart_all; exit 0/g" /etc/rc.local
- )
- config.vm.network :forwarded_port, guest: 33061, host: 33061
- config.vm.network :forwarded_port, guest: 33062, host: 33062
-end
diff --git a/supplement/vagrant/mysql-8.0.1-sandbox-prepackaged/vagrantfile b/supplement/vagrant/mysql-8.0.1-sandbox-prepackaged/vagrantfile
deleted file mode 100644
index 12b10d45..00000000
--- a/supplement/vagrant/mysql-8.0.1-sandbox-prepackaged/vagrantfile
+++ /dev/null
@@ -1,9 +0,0 @@
-Vagrant.configure("2") do |config|
- config.vm.box = 'shyiko/mysql-sandbox-prepackaged'
- config.vm.box_version = '8.0.1'
- config.vm.network :forwarded_port, guest: 33061, host: 33061
- config.vm.network :forwarded_port, guest: 33062, host: 33062
- config.vm.provider "virtualbox" do |v|
- v.memory = 1024
- end
-end
diff --git a/supplement/vagrant/mysql-8.0.1-sandbox/vagrantfile b/supplement/vagrant/mysql-8.0.1-sandbox/vagrantfile
deleted file mode 100644
index ba712b6a..00000000
--- a/supplement/vagrant/mysql-8.0.1-sandbox/vagrantfile
+++ /dev/null
@@ -1,24 +0,0 @@
-Vagrant.configure("2") do |config|
- config.vm.box = 'deb/jessie-i386'
- config.vm.provision :shell, :inline => %Q(
- sed -i.bak -r 's/(us.)?(archive|security).ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
- apt-get update && apt-get install -y make libaio1 libnuma1 libtinfo5 # lib* required by mysql
- echo 'Downloading MySQL distribution ...'
- wget --no-check-certificate --progress=dot:mega --content-disposition \
- https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.1-dmr-linux-glibc2.12-i686.tar.gz \
- 2>&1 | grep --line-buffered -o '[0-9]*%'
- wget -O - https://github.com/datacharmer/mysql-sandbox/releases/download/3.2.13/MySQL-Sandbox-3.2.13.tar.gz | tar xzv
- (cd MySQL-Sandbox-3.2.13 && perl Makefile.PL && make && make install)
- su -c "make_replication_sandbox ~/mysql-8.0.1-dmr-linux-glibc2.12-i686.tar.gz \
- --remote_access='%' --how_many_slaves=1 --sandbox_base_port=33061 \
- --master_options='-c binlog_format=ROW' \
- --slave_options='-c binlog_format=ROW -c log-slave-updates=TRUE'" vagrant
- rm -f *.tar.gz
- sed -i -e "s/exit\ 0/\\/home\\/vagrant\\/sandboxes\\/rsandbox_mysql-8_0_1\\/restart_all; exit 0/g" /etc/rc.local
- )
- config.vm.network :forwarded_port, guest: 33061, host: 33061
- config.vm.network :forwarded_port, guest: 33062, host: 33062
- config.vm.provider "virtualbox" do |v|
- v.memory = 1024
- end
-end
diff --git a/supplement/vagrant/readme.md b/supplement/vagrant/readme.md
deleted file mode 100644
index 7099541f..00000000
--- a/supplement/vagrant/readme.md
+++ /dev/null
@@ -1,7 +0,0 @@
-### Sandbox repackaging
-
-1. cd mysql-X.X.XX-sandbox
-2. vagrant up
-3. vagrant package --output ../mysql-X.X.XX-sandbox.box
-4. vagrant box add mysql-X.X.XX-sandbox ../mysql-X.X.XX-sandbox.box --force
-
From 01476e2452d0fd450c74b88fa6d5adb60bbe6cc1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 1 May 2020 10:49:31 -0700
Subject: [PATCH 031/217] prevent TableMapEventData hash from growing
unbounded.
see https://github.com/zendesk/maxwell/issues/1468 for the full story.
I'm not even sure how big this LRUCache really needs to be, given that
we unconditionally put stuff in it before every transaction. I think
the size might need to be 1? Unclear.
---
.../shyiko/mysql/binlog/event/LRUCache.java | 19 +++++++++++++++++++
.../deserialization/EventDeserializer.java | 3 ++-
2 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/event/LRUCache.java
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/LRUCache.java b/src/main/java/com/github/shyiko/mysql/binlog/event/LRUCache.java
new file mode 100644
index 00000000..784cec0e
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/LRUCache.java
@@ -0,0 +1,19 @@
+package com.github.shyiko.mysql.binlog.event;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class LRUCache extends LinkedHashMap {
+ private int maxSize;
+
+ // and other constructors for load factor and hashtable capacity
+ public LRUCache(int initialCapacity, float loadFactor, int maxSize) {
+ super(initialCapacity, loadFactor, true);
+ this.maxSize = maxSize;
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > maxSize;
+ }
+}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
index 5ca3e692..d623d943 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
@@ -20,6 +20,7 @@
import com.github.shyiko.mysql.binlog.event.EventHeader;
import com.github.shyiko.mysql.binlog.event.EventType;
import com.github.shyiko.mysql.binlog.event.FormatDescriptionEventData;
+import com.github.shyiko.mysql.binlog.event.LRUCache;
import com.github.shyiko.mysql.binlog.event.TableMapEventData;
import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream;
@@ -65,7 +66,7 @@ public EventDeserializer(
this.eventHeaderDeserializer = eventHeaderDeserializer;
this.defaultEventDataDeserializer = defaultEventDataDeserializer;
this.eventDataDeserializers = new IdentityHashMap();
- this.tableMapEventByTableId = new HashMap();
+ this.tableMapEventByTableId = new LRUCache<>(100, 0.75f, 10000);
registerDefaultEventDataDeserializers();
afterEventDataDeserializerSet(null);
}
From 04f8d4994d56805f6c97288391c27e1e5e3697a1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 1 May 2020 10:58:38 -0700
Subject: [PATCH 032/217] fix bugs exposed by adding array test
---
.../mysql/binlog/event/deserialization/json/JsonBinary.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
index 25ea2d7f..688cdc63 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
@@ -470,6 +470,8 @@ protected void parseObject(boolean small, JsonFormatter formatter)
// checkstyle, please ignore MethodLength for the next line
protected void parseArray(boolean small, JsonFormatter formatter)
throws IOException {
+ int arrayOffset = this.reader.getPosition();
+
// Read the header ...
int numElements = readUnsignedIndex(Integer.MAX_VALUE, small, "number of elements in");
int numBytes = readUnsignedIndex(Integer.MAX_VALUE, small, "size of");
@@ -534,6 +536,9 @@ protected void parseArray(boolean small, JsonFormatter formatter)
}
} else {
// Parse the value ...
+ this.reader.reset();
+ this.reader.skip(arrayOffset + entry.index);
+
parse(entry.type, formatter);
}
}
From 23d2c01a6ff1305d033fd4ee360d7b9b2e636d85 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 2 May 2020 13:17:40 -0700
Subject: [PATCH 033/217] add mysql 8 auth test
---
.../binlog/BinaryLogClientIntegrationTest.java | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 43629133..7618fe40 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -1000,6 +1000,19 @@ public void execute(Statement statement) throws SQLException {
}
}
+ @Test
+ public void testMysql8Auth() throws Exception {
+ if ( !mysqlVersion.atLeast(8, 0) )
+ throw new SkipException("skipping mysql8 auth test");
+
+ master.execute("create user 'mysql8' IDENTIFIED WITH caching_sha2_password BY 'testpass'");
+ master.execute("grant replication slave on *.* to 'mysql8'");
+
+ final BinaryLogClient binaryLogClient =
+ new BinaryLogClient(master.hostname, master.port, "mysql8", "testPass");
+ binaryLogClient.connect(5000);
+ }
+
@Test
public void testMySQL8TableMetadata() throws Exception {
master.execute("drop table if exists test_metameta");
From b70895c189ad56d2ce16f730a934ce7f49928073 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 2 May 2020 13:18:19 -0700
Subject: [PATCH 034/217] response with plugin-auth, deal with empty password
on auth-switch
---
.../command/AuthenticateSecurityPasswordCommand.java | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
index d99d6317..d0741138 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
@@ -56,7 +56,10 @@ public byte[] toByteArray() throws IOException {
int clientCapabilities = this.clientCapabilities;
if (clientCapabilities == 0) {
clientCapabilities = ClientCapabilities.LONG_FLAG |
- ClientCapabilities.PROTOCOL_41 | ClientCapabilities.SECURE_CONNECTION;
+ ClientCapabilities.PROTOCOL_41 |
+ ClientCapabilities.SECURE_CONNECTION |
+ ClientCapabilities.PLUGIN_AUTH;
+
if (schema != null) {
clientCapabilities |= ClientCapabilities.CONNECT_WITH_DB;
}
@@ -68,7 +71,7 @@ public byte[] toByteArray() throws IOException {
buffer.write(0);
}
buffer.writeZeroTerminatedString(username);
- byte[] passwordSHA1 = "".equals(password) ? new byte[0] : passwordCompatibleWithMySQL411(password, salt);
+ byte[] passwordSHA1 = passwordCompatibleWithMySQL411(password, salt);
buffer.writeInteger(passwordSHA1.length, 1);
buffer.write(passwordSHA1);
if (schema != null) {
@@ -81,6 +84,9 @@ public byte[] toByteArray() throws IOException {
* see mysql/sql/password.c scramble(...)
*/
public static byte[] passwordCompatibleWithMySQL411(String password, String salt) {
+ if ( "".equals(password) || password == null )
+ return new byte[0];
+
MessageDigest sha;
try {
sha = MessageDigest.getInstance("SHA-1");
From 6e52314318577516ad3a7c79f9460352989aa0e1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 2 May 2020 13:19:41 -0700
Subject: [PATCH 035/217] WIP: authenticator refactor
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 117 +++++-------------
.../mysql/binlog/network/Authenticator.java | 112 +++++++++++++++++
2 files changed, 146 insertions(+), 83 deletions(-)
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index 477f3b08..b5fdc618 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -126,6 +126,7 @@ public X509Certificate[] getAcceptedIssuers() {
private final String schema;
private final String username;
private final String password;
+ private int packetNumber = 1;
private boolean blocking = true;
private long serverId = 65535;
@@ -140,6 +141,7 @@ public X509Certificate[] getAcceptedIssuers() {
private boolean useBinlogFilenamePositionInGtidMode;
private String gtid;
private boolean tx;
+ private boolean isSSL;
private EventDeserializer eventDeserializer = new EventDeserializer();
@@ -518,6 +520,8 @@ public void connect() throws IOException {
". Please make sure it's running.", e);
}
GreetingPacket greetingPacket = receiveGreeting();
+ tryUpgradeToSSL();
+
authenticate(greetingPacket);
connectionId = greetingPacket.getThreadId();
if ("".equals(binlogFilename)) {
@@ -652,7 +656,36 @@ private GreetingPacket receiveGreeting() throws IOException {
return new GreetingPacket(initialHandshakePacket);
}
- private void enableHeartbeat() throws IOException {
+ private boolean tryUpgradeToSSL(GreetingPacket greetingPacket) throws IOException {
+ int collation = greetingPacket.getServerCollation();
+ int packetNumber = 1;
+
+ if (sslMode != SSLMode.DISABLED) {
+ boolean serverSupportsSSL = (greetingPacket.getServerCapabilities() & ClientCapabilities.SSL) != 0;
+ if (!serverSupportsSSL && (sslMode == SSLMode.REQUIRED || sslMode == SSLMode.VERIFY_CA ||
+ sslMode == SSLMode.VERIFY_IDENTITY)) {
+ throw new IOException("MySQL server does not support SSL");
+ }
+ if (serverSupportsSSL) {
+ SSLRequestCommand sslRequestCommand = new SSLRequestCommand();
+ sslRequestCommand.setCollation(collation);
+ channel.write(sslRequestCommand, packetNumber++);
+ SSLSocketFactory sslSocketFactory =
+ this.sslSocketFactory != null ?
+ this.sslSocketFactory :
+ sslMode == SSLMode.REQUIRED || sslMode == SSLMode.PREFERRED ?
+ DEFAULT_REQUIRED_SSL_MODE_SOCKET_FACTORY :
+ DEFAULT_VERIFY_CA_SSL_MODE_SOCKET_FACTORY;
+ channel.upgradeToSSL(sslSocketFactory,
+ sslMode == SSLMode.VERIFY_IDENTITY ? new TLSHostnameVerifier() : null);
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ private void enableHeartbeat() throws IOException {
channel.write(new QueryCommand("set @master_heartbeat_period=" + heartbeatInterval * 1000000));
byte[] statementResult = channel.read();
if (statementResult[0] == (byte) 0xFF /* error */) {
@@ -704,88 +737,6 @@ private void ensureEventDataDeserializer(EventType eventType,
}
}
- private void authenticate(GreetingPacket greetingPacket) throws IOException {
- int collation = greetingPacket.getServerCollation();
- int packetNumber = 1;
-
- boolean usingSSLSocket = false;
- if (sslMode != SSLMode.DISABLED) {
- boolean serverSupportsSSL = (greetingPacket.getServerCapabilities() & ClientCapabilities.SSL) != 0;
- if (!serverSupportsSSL && (sslMode == SSLMode.REQUIRED || sslMode == SSLMode.VERIFY_CA ||
- sslMode == SSLMode.VERIFY_IDENTITY)) {
- throw new IOException("MySQL server does not support SSL");
- }
- if (serverSupportsSSL) {
- SSLRequestCommand sslRequestCommand = new SSLRequestCommand();
- sslRequestCommand.setCollation(collation);
- channel.write(sslRequestCommand, packetNumber++);
- SSLSocketFactory sslSocketFactory =
- this.sslSocketFactory != null ?
- this.sslSocketFactory :
- sslMode == SSLMode.REQUIRED || sslMode == SSLMode.PREFERRED ?
- DEFAULT_REQUIRED_SSL_MODE_SOCKET_FACTORY :
- DEFAULT_VERIFY_CA_SSL_MODE_SOCKET_FACTORY;
- channel.upgradeToSSL(sslSocketFactory,
- sslMode == SSLMode.VERIFY_IDENTITY ? new TLSHostnameVerifier() : null);
- usingSSLSocket = true;
- }
- }
-
- Command authenticateCommand = "caching_sha2_password".equals(greetingPacket.getPluginProvidedData()) ?
- new AuthenticateSHA2Command(schema, username, password, greetingPacket.getScramble(), collation) :
- new AuthenticateSecurityPasswordCommand(schema, username, password, greetingPacket.getScramble(), collation);
-
- channel.write(authenticateCommand, packetNumber);
- byte[] authenticationResult = channel.read();
- if (authenticationResult[0] != (byte) 0x00 /* ok */) {
- if (authenticationResult[0] == (byte) 0xFF /* error */) {
- byte[] bytes = Arrays.copyOfRange(authenticationResult, 1, authenticationResult.length);
- ErrorPacket errorPacket = new ErrorPacket(bytes);
- throw new AuthenticationException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
- errorPacket.getSqlState());
- } else if (authenticationResult[0] == (byte) 0xFE) {
- switchAuthentication(authenticationResult, usingSSLSocket);
- } else if (authenticationResult[0] == (byte) 0x01) {
- if (authenticationResult.length >= 2 && (authenticationResult[1] == 3) || (authenticationResult[1] == 4)) {
- // 8.0 auth ok
- byte[] authenticationResultSha2 = channel.read();
- logger.log(Level.FINEST, "SHA2 auth result {0}", authenticationResultSha2);
- } else {
- throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + "&" + authenticationResult[1] + ")");
- }
- } else {
- throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + ")");
- }
- }
- }
-
- private void switchAuthentication(byte[] authenticationResult, boolean usingSSLSocket) throws IOException {
- /*
- Azure-MySQL likes to tell us to switch authentication methods, even though
- we haven't advertised that we support any. It uses this for some-odd
- reason to send the real password scramble.
- */
- ByteArrayInputStream buffer = new ByteArrayInputStream(authenticationResult);
- buffer.read(1);
-
- String authName = buffer.readZeroTerminatedString();
- if ("mysql_native_password".equals(authName)) {
- String scramble = buffer.readZeroTerminatedString();
-
- Command switchCommand = new AuthenticateNativePasswordCommand(scramble, password);
- channel.write(switchCommand, (usingSSLSocket ? 4 : 3));
- byte[] authResult = channel.read();
-
- if (authResult[0] != (byte) 0x00) {
- byte[] bytes = Arrays.copyOfRange(authResult, 1, authResult.length);
- ErrorPacket errorPacket = new ErrorPacket(bytes);
- throw new AuthenticationException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
- errorPacket.getSqlState());
- }
- } else {
- throw new AuthenticationException("Unsupported authentication type: " + authName);
- }
- }
private void spawnKeepAliveThread() {
final ExecutorService threadExecutor =
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
new file mode 100644
index 00000000..8d5f2800
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
@@ -0,0 +1,112 @@
+package com.github.shyiko.mysql.binlog.network;
+
+import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream;
+import com.github.shyiko.mysql.binlog.network.protocol.ErrorPacket;
+import com.github.shyiko.mysql.binlog.network.protocol.GreetingPacket;
+import com.github.shyiko.mysql.binlog.network.protocol.PacketChannel;
+import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateNativePasswordCommand;
+import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSHA2Command;
+import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSecurityPasswordCommand;
+import com.github.shyiko.mysql.binlog.network.protocol.command.Command;
+import com.github.shyiko.mysql.binlog.network.protocol.command.SSLRequestCommand;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.logging.Level;
+
+public class Authenticator {
+ private final GreetingPacket greetingPacket;
+ private final PacketChannel channel;
+
+ public Authenticator(GreetingPacket greetingPacket, PacketChannel channel) {
+ this.greetingPacket = greetingPacket;
+ this.channel = channel;
+ }
+
+ private void authenticate(GreetingPacket greetingPacket) throws IOException {
+ int collation = greetingPacket.getServerCollation();
+ int packetNumber = 1;
+
+ boolean usingSSLSocket = false;
+ if (sslMode != SSLMode.DISABLED) {
+ boolean serverSupportsSSL = (greetingPacket.getServerCapabilities() & ClientCapabilities.SSL) != 0;
+ if (!serverSupportsSSL && (sslMode == SSLMode.REQUIRED || sslMode == SSLMode.VERIFY_CA ||
+ sslMode == SSLMode.VERIFY_IDENTITY)) {
+ throw new IOException("MySQL server does not support SSL");
+ }
+ if (serverSupportsSSL) {
+ SSLRequestCommand sslRequestCommand = new SSLRequestCommand();
+ sslRequestCommand.setCollation(collation);
+ channel.write(sslRequestCommand, packetNumber++);
+ SSLSocketFactory sslSocketFactory =
+ this.sslSocketFactory != null ?
+ this.sslSocketFactory :
+ sslMode == SSLMode.REQUIRED || sslMode == SSLMode.PREFERRED ?
+ DEFAULT_REQUIRED_SSL_MODE_SOCKET_FACTORY :
+ DEFAULT_VERIFY_CA_SSL_MODE_SOCKET_FACTORY;
+ channel.upgradeToSSL(sslSocketFactory,
+ sslMode == SSLMode.VERIFY_IDENTITY ? new TLSHostnameVerifier() : null);
+ usingSSLSocket = true;
+ }
+ }
+
+ logger.log(Level.INFO, greetingPacket.getPluginProvidedData());
+
+ Command authenticateCommand = "caching_sha2_password".equals(greetingPacket.getPluginProvidedData()) ?
+ new AuthenticateSHA2Command(schema, username, password, greetingPacket.getScramble(), collation) :
+ new AuthenticateSecurityPasswordCommand(schema, username, password, greetingPacket.getScramble(), collation);
+
+ channel.write(authenticateCommand, packetNumber);
+ byte[] authenticationResult = channel.read();
+ if (authenticationResult[0] != (byte) 0x00 /* ok */) {
+ if (authenticationResult[0] == (byte) 0xFF /* error */) {
+ byte[] bytes = Arrays.copyOfRange(authenticationResult, 1, authenticationResult.length);
+ ErrorPacket errorPacket = new ErrorPacket(bytes);
+ throw new AuthenticationException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
+ errorPacket.getSqlState());
+ } else if (authenticationResult[0] == (byte) 0xFE) {
+ switchAuthentication(authenticationResult, usingSSLSocket);
+ } else if (authenticationResult[0] == (byte) 0x01) {
+ if (authenticationResult.length >= 2 && (authenticationResult[1] == 3) || (authenticationResult[1] == 4)) {
+ // 8.0 auth ok
+ byte[] authenticationResultSha2 = channel.read();
+ logger.log(Level.FINEST, "SHA2 auth result {0}", authenticationResultSha2);
+ } else {
+ throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + "&" + authenticationResult[1] + ")");
+ }
+ } else {
+ throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + ")");
+ }
+ }
+ }
+
+ private void switchAuthentication(byte[] authenticationResult, boolean usingSSLSocket) throws IOException {
+ /*
+ Azure-MySQL likes to tell us to switch authentication methods, even though
+ we haven't advertised that we support any. It uses this for some-odd
+ reason to send the real password scramble.
+ */
+ ByteArrayInputStream buffer = new ByteArrayInputStream(authenticationResult);
+ buffer.read(1);
+
+ String authName = buffer.readZeroTerminatedString();
+ if ("mysql_native_password".equals(authName)) {
+ String scramble = buffer.readZeroTerminatedString();
+
+ Command switchCommand = new AuthenticateNativePasswordCommand(scramble, password);
+ channel.write(switchCommand, (usingSSLSocket ? 4 : 3));
+ byte[] authResult = channel.read();
+
+ if (authResult[0] != (byte) 0x00) {
+ byte[] bytes = Arrays.copyOfRange(authResult, 1, authResult.length);
+ ErrorPacket errorPacket = new ErrorPacket(bytes);
+ throw new AuthenticationException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
+ errorPacket.getSqlState());
+ }
+ } else {
+ throw new AuthenticationException("Unsupported authentication type: " + authName);
+ }
+ }
+
+
+}
From 4a08f0d447d7b20ec3b45cbe98cbf3c3c78ea8d1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 2 May 2020 13:46:18 -0700
Subject: [PATCH 036/217] move packet number ownership into PacketChannel
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 8 +++--
.../network/protocol/PacketChannel.java | 31 ++++++++++---------
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index 0a860374..cda961cd 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -717,7 +717,7 @@ private void authenticate(GreetingPacket greetingPacket) throws IOException {
if (serverSupportsSSL) {
SSLRequestCommand sslRequestCommand = new SSLRequestCommand();
sslRequestCommand.setCollation(collation);
- channel.write(sslRequestCommand, packetNumber++);
+ channel.write(sslRequestCommand);
SSLSocketFactory sslSocketFactory =
this.sslSocketFactory != null ?
this.sslSocketFactory :
@@ -732,7 +732,7 @@ private void authenticate(GreetingPacket greetingPacket) throws IOException {
AuthenticateCommand authenticateCommand = new AuthenticateCommand(schema, username, password,
greetingPacket.getScramble());
authenticateCommand.setCollation(collation);
- channel.write(authenticateCommand, packetNumber);
+ channel.write(authenticateCommand);
byte[] authenticationResult = channel.read();
if (authenticationResult[0] != (byte) 0x00 /* ok */) {
if (authenticationResult[0] == (byte) 0xFF /* error */) {
@@ -746,6 +746,8 @@ private void authenticate(GreetingPacket greetingPacket) throws IOException {
throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + ")");
}
}
+
+ channel.authenticationComplete();
}
private void switchAuthentication(byte[] authenticationResult, boolean usingSSLSocket) throws IOException {
@@ -762,7 +764,7 @@ private void switchAuthentication(byte[] authenticationResult, boolean usingSSLS
String scramble = buffer.readZeroTerminatedString();
Command switchCommand = new AuthenticateNativePasswordCommand(scramble, password);
- channel.write(switchCommand, (usingSSLSocket ? 4 : 3));
+ channel.write(switchCommand);
byte[] authResult = channel.read();
if (authResult[0] != (byte) 0x00) {
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
index fbbe950f..6262f3f6 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
@@ -32,7 +32,8 @@
* @author Stanley Shyiko
*/
public class PacketChannel implements Channel {
-
+ private int packetNumber = 1;
+ private boolean authenticationComplete;
private Socket socket;
private ByteArrayInputStream inputStream;
private ByteArrayOutputStream outputStream;
@@ -55,17 +56,29 @@ public ByteArrayOutputStream getOutputStream() {
return outputStream;
}
+ public void authenticationComplete() {
+ authenticationComplete = true;
+ }
+
public byte[] read() throws IOException {
int length = inputStream.readInteger(3);
inputStream.skip(1); //sequence
return inputStream.read(length);
}
- public void write(Command command, int packetNumber) throws IOException {
+ public void write(Command command) throws IOException {
byte[] body = command.toByteArray();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
buffer.writeInteger(body.length, 3); // packet length
- buffer.writeInteger(packetNumber, 1);
+
+ // see https://dev.mysql.com/doc/dev/mysql-server/8.0.11/page_protocol_basic_packets.html#sect_protocol_basic_packets_sequence_id
+ // we only have to maintain a sequence number in the authentication phase.
+ // what the point is, I do not know
+ if ( authenticationComplete )
+ buffer.writeInteger(0, 1);
+ else
+ buffer.writeInteger(packetNumber++, 1);
+
buffer.write(body, 0, body.length);
outputStream.write(buffer.toByteArray());
// though it has no effect in case of default (underlying) output stream (SocketOutputStream),
@@ -73,18 +86,6 @@ public void write(Command command, int packetNumber) throws IOException {
outputStream.flush();
}
- /**
- * @deprecated use {@link #write(Command, int)} instead
- */
- @Deprecated
- public void writeBuffered(Command command, int packetNumber) throws IOException {
- write(command, packetNumber);
- }
-
- public void write(Command command) throws IOException {
- write(command, 0);
- }
-
public void upgradeToSSL(SSLSocketFactory sslSocketFactory, HostnameVerifier hostnameVerifier) throws IOException {
SSLSocket sslSocket = sslSocketFactory.createSocket(this.socket);
sslSocket.startHandshake();
From 49ed9ab7976262e6e8929c11ba98bc690f1a7f11 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 2 May 2020 16:00:55 -0700
Subject: [PATCH 037/217] wait for tests longer
---
.../deserialization/json/JsonBinaryValueIntegrationTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
index 12552c31..96750afd 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
@@ -53,7 +53,7 @@
*/
public class JsonBinaryValueIntegrationTest {
- private static final long DEFAULT_TIMEOUT = TimeUnit.SECONDS.toMillis(3);
+ private static final long DEFAULT_TIMEOUT = TimeUnit.SECONDS.toMillis(6);
private final Logger logger = Logger.getLogger(getClass().getSimpleName());
From 2cfcc59b2bbcac8b0a261990aec7c05fc77e4ce6 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 2 May 2020 17:15:40 -0700
Subject: [PATCH 038/217] try some debug logging
---
.../github/shyiko/mysql/binlog/CountDownEventListener.java | 4 ++++
.../deserialization/json/JsonBinaryValueIntegrationTest.java | 1 +
2 files changed, 5 insertions(+)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/CountDownEventListener.java b/src/test/java/com/github/shyiko/mysql/binlog/CountDownEventListener.java
index 73a6f5b9..38c5cfb2 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/CountDownEventListener.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/CountDownEventListener.java
@@ -35,9 +35,12 @@ public class CountDownEventListener implements BinaryLogClient.EventListener {
@Override
public void onEvent(Event event) {
+ System.out.println("increment Counter for " + event.getHeader().getEventType() + " " + getCounter(countersByType, event.getHeader().getEventType()));
+
incrementCounter(getCounter(countersByType, event.getHeader().getEventType()));
EventData data = event.getData();
if (data != null) {
+ System.out.println("increment Counter for " + data.getClass() + " " + getCounter(countersByDataClass, data.getClass()));
incrementCounter(getCounter(countersByDataClass, data.getClass()));
}
}
@@ -76,6 +79,7 @@ private void waitForCounterToGetZero(String counterName, AtomicInteger counter,
long timeoutInMilliseconds) throws TimeoutException, InterruptedException {
synchronized (counter) {
counter.set(counter.get() - numberOfExpectedEvents);
+ System.out.println("counter " + counterName + " set to " + counter.get());
if (counter.get() != 0) {
counter.wait(timeoutInMilliseconds);
if (counter.get() != 0) {
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
index 96750afd..05ffc10e 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
@@ -507,6 +507,7 @@ private String writeAndCaptureJSON(final String value) throws Exception {
client.unregisterEventListener(capturingEventListener);
}
if ( capturingEventListener.getEvents(WriteRowsEventData.class).size() == 0 ) {
+ System.out.println("I am about to fail an expectation...");
assertTrue(false, "did not receive rows in json test for " + value);
}
byte[] b = (byte[]) capturingEventListener.getEvents(WriteRowsEventData.class).get(0).getRows().get(0)[0];
From 35fa10f91ee203ef8d093521b5b903f7d3e49b64 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 2 May 2020 17:26:47 -0700
Subject: [PATCH 039/217] remove superfluous extra event listeners
---
.../json/JsonBinaryValueIntegrationTest.java | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
index 05ffc10e..72dc26d8 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
@@ -109,8 +109,6 @@ public void execute(Statement statement) throws SQLException {
@Test
public void testMysql8JsonSetPartialUpdateWithHoles() throws Exception {
- CountDownEventListener eventListener = new CountDownEventListener();
- client.registerEventListener(eventListener);
CapturingEventListener capturingEventListener = new CapturingEventListener();
client.registerEventListener(capturingEventListener);
String json = "{\"age\":22,\"addr\":{\"code\":100,\"detail\":{\"ab\":\"970785C8-C299\"}},\"name\":\"Alice\"}";
@@ -130,8 +128,6 @@ public void testMysql8JsonSetPartialUpdateWithHoles() throws Exception {
@Test
public void testMysql8JsonRemovePartialUpdateWithHoles() throws Exception {
- CountDownEventListener eventListener = new CountDownEventListener();
- client.registerEventListener(eventListener);
CapturingEventListener capturingEventListener = new CapturingEventListener();
client.registerEventListener(capturingEventListener);
String json = "{\"age\":22,\"addr\":{\"code\":100,\"detail\":{\"ab\":\"970785C8-C299\"}},\"name\":\"Alice\"}";
@@ -147,12 +143,12 @@ public void testMysql8JsonRemovePartialUpdateWithHoles() throws Exception {
List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), json.replace("\"ab\":\"970785C8-C299\"", ""));
+
+ client.unregisterEventListener(capturingEventListener);
}
@Test
public void testMysql8JsonReplacePartialUpdateWithHoles() throws Exception {
- CountDownEventListener eventListener = new CountDownEventListener();
- client.registerEventListener(eventListener);
CapturingEventListener capturingEventListener = new CapturingEventListener();
client.registerEventListener(capturingEventListener);
String json = "{\"age\":22,\"addr\":{\"code\":100,\"detail\":{\"ab\":\"970785C8-C299\"}},\"name\":\"Alice\"}";
@@ -168,12 +164,12 @@ public void testMysql8JsonReplacePartialUpdateWithHoles() throws Exception {
List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), json.replace("970785C8-C299", "9707"));
+
+ client.unregisterEventListener(capturingEventListener);
}
@Test
public void testMysql8JsonRemoveArrayValue() throws Exception {
- CountDownEventListener eventListener = new CountDownEventListener();
- client.registerEventListener(eventListener);
CapturingEventListener capturingEventListener = new CapturingEventListener();
client.registerEventListener(capturingEventListener);
@@ -191,12 +187,12 @@ public void testMysql8JsonRemoveArrayValue() throws Exception {
List updateEvents = capturingEventListener.getEvents(UpdateRowsEventData.class);
Serializable[] updateData = updateEvents.iterator().next().getRows().get(0).getValue();
assertEquals(JsonBinary.parseAsString((byte[]) updateData[0]), "[\"foo\",\"baz\"]");
+
+ client.unregisterEventListener(capturingEventListener);
}
@Test
public void testValueBoundariesAreHonored() throws Exception {
- CountDownEventListener eventListener = new CountDownEventListener();
- client.registerEventListener(eventListener);
CapturingEventListener capturingEventListener = new CapturingEventListener();
client.registerEventListener(capturingEventListener);
master.execute("create table json_b (h varchar(255), j JSON, k varchar(255))",
@@ -207,6 +203,8 @@ public void testValueBoundariesAreHonored() throws Exception {
assertEquals(data[0], "sponge");
assertEquals(JsonBinary.parseAsString((byte[]) data[1]), "{}");
assertEquals(data[2], "bob");
+
+ client.unregisterEventListener(capturingEventListener);
}
@Test
From 9c999c7a4679abea75f1a75994073ff879841ebd Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 2 May 2020 17:50:04 -0700
Subject: [PATCH 040/217] fix test race condition.
It was previously possible that CountDownEventListener woke up the test
before CapturingEventListener had received rows. Unifying the latch and
the capture together in one class fixes this.
---
.../mysql/binlog/BinaryLogClientTest.java | 2 +-
.../mysql/binlog/CapturingEventListener.java | 3 ++-
.../mysql/binlog/CountDownEventListener.java | 4 ----
.../json/JsonBinaryValueIntegrationTest.java | 20 +++++++++----------
4 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
index fece36b4..542c2452 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
@@ -49,7 +49,7 @@ public void testEventListenersManagement() {
assertEquals(binaryLogClient.getEventListeners().size(), 3);
binaryLogClient.unregisterEventListener(traceEventListener);
assertEquals(binaryLogClient.getEventListeners().size(), 2);
- binaryLogClient.unregisterEventListener(CountDownEventListener.class);
+ binaryLogClient.unregisterEventListener(CapturingEventListener.class);
assertEquals(binaryLogClient.getEventListeners().size(), 1);
}
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/CapturingEventListener.java b/src/test/java/com/github/shyiko/mysql/binlog/CapturingEventListener.java
index f6b7c6b0..0249f6e1 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/CapturingEventListener.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/CapturingEventListener.java
@@ -25,7 +25,7 @@
/**
* @author Stanley Shyiko
*/
-public class CapturingEventListener implements BinaryLogClient.EventListener {
+public class CapturingEventListener extends CountDownEventListener {
private final List events = new LinkedList();
@@ -33,6 +33,7 @@ public class CapturingEventListener implements BinaryLogClient.EventListener {
public void onEvent(Event event) {
synchronized (events) {
events.add(event);
+ super.onEvent(event);
}
}
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/CountDownEventListener.java b/src/test/java/com/github/shyiko/mysql/binlog/CountDownEventListener.java
index 38c5cfb2..73a6f5b9 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/CountDownEventListener.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/CountDownEventListener.java
@@ -35,12 +35,9 @@ public class CountDownEventListener implements BinaryLogClient.EventListener {
@Override
public void onEvent(Event event) {
- System.out.println("increment Counter for " + event.getHeader().getEventType() + " " + getCounter(countersByType, event.getHeader().getEventType()));
-
incrementCounter(getCounter(countersByType, event.getHeader().getEventType()));
EventData data = event.getData();
if (data != null) {
- System.out.println("increment Counter for " + data.getClass() + " " + getCounter(countersByDataClass, data.getClass()));
incrementCounter(getCounter(countersByDataClass, data.getClass()));
}
}
@@ -79,7 +76,6 @@ private void waitForCounterToGetZero(String counterName, AtomicInteger counter,
long timeoutInMilliseconds) throws TimeoutException, InterruptedException {
synchronized (counter) {
counter.set(counter.get() - numberOfExpectedEvents);
- System.out.println("counter " + counterName + " set to " + counter.get());
if (counter.get() != 0) {
counter.wait(timeoutInMilliseconds);
if (counter.get() != 0) {
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
index 72dc26d8..e6eb2221 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinaryValueIntegrationTest.java
@@ -115,8 +115,8 @@ public void testMysql8JsonSetPartialUpdateWithHoles() throws Exception {
master.execute("DROP TABLE IF EXISTS json_test", "create table json_test (j JSON)",
"INSERT INTO json_test VALUES ('" + json + "')",
"UPDATE json_test SET j = JSON_SET(j, '$.addr.detail.ab', '970785C8')");
- eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
- eventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
List events = capturingEventListener.getEvents(WriteRowsEventData.class);
Serializable[] insertData = events.iterator().next().getRows().get(0);
assertEquals(JsonBinary.parseAsString((byte[]) insertData[0]), json);
@@ -134,8 +134,8 @@ public void testMysql8JsonRemovePartialUpdateWithHoles() throws Exception {
master.execute("DROP TABLE IF EXISTS json_test", "create table json_test (j JSON)",
"INSERT INTO json_test VALUES ('" + json + "')",
"UPDATE json_test SET j = JSON_REMOVE(j, '$.addr.detail.ab')");
- eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
- eventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
List events = capturingEventListener.getEvents(WriteRowsEventData.class);
Serializable[] insertData = events.iterator().next().getRows().get(0);
assertEquals(JsonBinary.parseAsString((byte[]) insertData[0]), json);
@@ -155,8 +155,8 @@ public void testMysql8JsonReplacePartialUpdateWithHoles() throws Exception {
master.execute("DROP TABLE IF EXISTS json_test", "create table json_test (j JSON)",
"INSERT INTO json_test VALUES ('" + json + "')",
"UPDATE json_test SET j = JSON_REPLACE(j, '$.addr.detail.ab', '9707')");
- eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
- eventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
List events = capturingEventListener.getEvents(WriteRowsEventData.class);
Serializable[] insertData = events.iterator().next().getRows().get(0);
assertEquals(JsonBinary.parseAsString((byte[]) insertData[0]), json);
@@ -177,8 +177,8 @@ public void testMysql8JsonRemoveArrayValue() throws Exception {
master.execute("DROP TABLE IF EXISTS json_test", "create table json_test (j JSON)",
"INSERT INTO json_test VALUES ('" + json + "')",
"UPDATE json_test SET j = JSON_REMOVE(j, '$[1]')");
- eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
- eventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(UpdateRowsEventData.class, 1, DEFAULT_TIMEOUT);
List events = capturingEventListener.getEvents(WriteRowsEventData.class);
Serializable[] insertData = events.iterator().next().getRows().get(0);
@@ -197,7 +197,7 @@ public void testValueBoundariesAreHonored() throws Exception {
client.registerEventListener(capturingEventListener);
master.execute("create table json_b (h varchar(255), j JSON, k varchar(255))",
"INSERT INTO json_b VALUES ('sponge', '{}', 'bob');");
- eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
List events = capturingEventListener.getEvents(WriteRowsEventData.class);
Serializable[] data = events.iterator().next().getRows().get(0);
assertEquals(data[0], "sponge");
@@ -500,7 +500,7 @@ private String writeAndCaptureJSON(final String value) throws Exception {
statement.execute("create table data_type_hell (column_ " + "JSON" + ")");
statement.execute("insert into data_type_hell values (" + value + ")");
});
- eventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
+ capturingEventListener.waitFor(WriteRowsEventData.class, 1, DEFAULT_TIMEOUT);
} finally {
client.unregisterEventListener(capturingEventListener);
}
From 148ce23eb806d45158502784e8fff23db10ba09f Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sun, 3 May 2020 02:25:03 -0700
Subject: [PATCH 041/217] finish refactor into Authenticator class, more
sequence-number fixes
The old implementation was pretty janky, although it worked. sequence
numbers are actually incremented and checked by both client and server.
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 14 +++--
.../mysql/binlog/network/Authenticator.java | 58 ++++++++-----------
.../network/protocol/PacketChannel.java | 16 +++--
3 files changed, 41 insertions(+), 47 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index b5fdc618..b6690126 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -33,6 +33,7 @@
import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream;
import com.github.shyiko.mysql.binlog.jmx.BinaryLogClientMXBean;
import com.github.shyiko.mysql.binlog.network.AuthenticationException;
+import com.github.shyiko.mysql.binlog.network.Authenticator;
import com.github.shyiko.mysql.binlog.network.ClientCapabilities;
import com.github.shyiko.mysql.binlog.network.DefaultSSLSocketFactory;
import com.github.shyiko.mysql.binlog.network.SSLMode;
@@ -126,7 +127,6 @@ public X509Certificate[] getAcceptedIssuers() {
private final String schema;
private final String username;
private final String password;
- private int packetNumber = 1;
private boolean blocking = true;
private long serverId = 65535;
@@ -520,9 +520,12 @@ public void connect() throws IOException {
". Please make sure it's running.", e);
}
GreetingPacket greetingPacket = receiveGreeting();
- tryUpgradeToSSL();
- authenticate(greetingPacket);
+ tryUpgradeToSSL(greetingPacket);
+
+ new Authenticator(greetingPacket, channel, schema, username, password).authenticate();
+ channel.authenticationComplete();
+
connectionId = greetingPacket.getThreadId();
if ("".equals(binlogFilename)) {
synchronized (gtidSetAccessLock) {
@@ -658,7 +661,6 @@ private GreetingPacket receiveGreeting() throws IOException {
private boolean tryUpgradeToSSL(GreetingPacket greetingPacket) throws IOException {
int collation = greetingPacket.getServerCollation();
- int packetNumber = 1;
if (sslMode != SSLMode.DISABLED) {
boolean serverSupportsSSL = (greetingPacket.getServerCapabilities() & ClientCapabilities.SSL) != 0;
@@ -669,7 +671,7 @@ private boolean tryUpgradeToSSL(GreetingPacket greetingPacket) throws IOExceptio
if (serverSupportsSSL) {
SSLRequestCommand sslRequestCommand = new SSLRequestCommand();
sslRequestCommand.setCollation(collation);
- channel.write(sslRequestCommand, packetNumber++);
+ channel.write(sslRequestCommand);
SSLSocketFactory sslSocketFactory =
this.sslSocketFactory != null ?
this.sslSocketFactory :
@@ -685,7 +687,7 @@ private boolean tryUpgradeToSSL(GreetingPacket greetingPacket) throws IOExceptio
}
- private void enableHeartbeat() throws IOException {
+ private void enableHeartbeat() throws IOException {
channel.write(new QueryCommand("set @master_heartbeat_period=" + heartbeatInterval * 1000000));
byte[] statementResult = channel.read();
if (statementResult[0] == (byte) 0xFF /* error */) {
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
index 8d5f2800..e75ee455 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
@@ -13,50 +13,40 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.logging.Level;
+import java.util.logging.Logger;
public class Authenticator {
private final GreetingPacket greetingPacket;
private final PacketChannel channel;
+ private final String schema;
+ private final String username;
+ private final String password;
- public Authenticator(GreetingPacket greetingPacket, PacketChannel channel) {
+ private final Logger logger = Logger.getLogger(getClass().getName());
+
+ public Authenticator(
+ GreetingPacket greetingPacket,
+ PacketChannel channel,
+ String schema,
+ String username,
+ String password
+ ) {
this.greetingPacket = greetingPacket;
this.channel = channel;
+ this.schema = schema;
+ this.username = username;
+ this.password = password;
}
- private void authenticate(GreetingPacket greetingPacket) throws IOException {
+ public void authenticate() throws IOException {
+ logger.log(Level.INFO, "Begin auth for " + username);
int collation = greetingPacket.getServerCollation();
- int packetNumber = 1;
-
- boolean usingSSLSocket = false;
- if (sslMode != SSLMode.DISABLED) {
- boolean serverSupportsSSL = (greetingPacket.getServerCapabilities() & ClientCapabilities.SSL) != 0;
- if (!serverSupportsSSL && (sslMode == SSLMode.REQUIRED || sslMode == SSLMode.VERIFY_CA ||
- sslMode == SSLMode.VERIFY_IDENTITY)) {
- throw new IOException("MySQL server does not support SSL");
- }
- if (serverSupportsSSL) {
- SSLRequestCommand sslRequestCommand = new SSLRequestCommand();
- sslRequestCommand.setCollation(collation);
- channel.write(sslRequestCommand, packetNumber++);
- SSLSocketFactory sslSocketFactory =
- this.sslSocketFactory != null ?
- this.sslSocketFactory :
- sslMode == SSLMode.REQUIRED || sslMode == SSLMode.PREFERRED ?
- DEFAULT_REQUIRED_SSL_MODE_SOCKET_FACTORY :
- DEFAULT_VERIFY_CA_SSL_MODE_SOCKET_FACTORY;
- channel.upgradeToSSL(sslSocketFactory,
- sslMode == SSLMode.VERIFY_IDENTITY ? new TLSHostnameVerifier() : null);
- usingSSLSocket = true;
- }
- }
-
- logger.log(Level.INFO, greetingPacket.getPluginProvidedData());
Command authenticateCommand = "caching_sha2_password".equals(greetingPacket.getPluginProvidedData()) ?
new AuthenticateSHA2Command(schema, username, password, greetingPacket.getScramble(), collation) :
new AuthenticateSecurityPasswordCommand(schema, username, password, greetingPacket.getScramble(), collation);
- channel.write(authenticateCommand, packetNumber);
+ channel.write(authenticateCommand);
byte[] authenticationResult = channel.read();
if (authenticationResult[0] != (byte) 0x00 /* ok */) {
if (authenticationResult[0] == (byte) 0xFF /* error */) {
@@ -65,12 +55,11 @@ private void authenticate(GreetingPacket greetingPacket) throws IOException {
throw new AuthenticationException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
errorPacket.getSqlState());
} else if (authenticationResult[0] == (byte) 0xFE) {
- switchAuthentication(authenticationResult, usingSSLSocket);
+ switchAuthentication(authenticationResult);
} else if (authenticationResult[0] == (byte) 0x01) {
if (authenticationResult.length >= 2 && (authenticationResult[1] == 3) || (authenticationResult[1] == 4)) {
// 8.0 auth ok
byte[] authenticationResultSha2 = channel.read();
- logger.log(Level.FINEST, "SHA2 auth result {0}", authenticationResultSha2);
} else {
throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + "&" + authenticationResult[1] + ")");
}
@@ -78,9 +67,10 @@ private void authenticate(GreetingPacket greetingPacket) throws IOException {
throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + ")");
}
}
+ logger.log(Level.INFO, "Auth complete " + username);
}
- private void switchAuthentication(byte[] authenticationResult, boolean usingSSLSocket) throws IOException {
+ private void switchAuthentication(byte[] authenticationResult) throws IOException {
/*
Azure-MySQL likes to tell us to switch authentication methods, even though
we haven't advertised that we support any. It uses this for some-odd
@@ -94,7 +84,7 @@ private void switchAuthentication(byte[] authenticationResult, boolean usingSSLS
String scramble = buffer.readZeroTerminatedString();
Command switchCommand = new AuthenticateNativePasswordCommand(scramble, password);
- channel.write(switchCommand, (usingSSLSocket ? 4 : 3));
+ channel.write(switchCommand);
byte[] authResult = channel.read();
if (authResult[0] != (byte) 0x00) {
@@ -107,6 +97,4 @@ private void switchAuthentication(byte[] authenticationResult, boolean usingSSLS
throw new AuthenticationException("Unsupported authentication type: " + authName);
}
}
-
-
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
index 6262f3f6..34208a10 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
@@ -32,7 +32,7 @@
* @author Stanley Shyiko
*/
public class PacketChannel implements Channel {
- private int packetNumber = 1;
+ private int packetNumber = 0;
private boolean authenticationComplete;
private Socket socket;
private ByteArrayInputStream inputStream;
@@ -62,7 +62,10 @@ public void authenticationComplete() {
public byte[] read() throws IOException {
int length = inputStream.readInteger(3);
- inputStream.skip(1); //sequence
+ int sequence = inputStream.read(); // sequence
+ if ( sequence != packetNumber++ ) {
+ throw new IOException("unexpected sequence #" + sequence);
+ }
return inputStream.read(length);
}
@@ -74,10 +77,11 @@ public void write(Command command) throws IOException {
// see https://dev.mysql.com/doc/dev/mysql-server/8.0.11/page_protocol_basic_packets.html#sect_protocol_basic_packets_sequence_id
// we only have to maintain a sequence number in the authentication phase.
// what the point is, I do not know
- if ( authenticationComplete )
- buffer.writeInteger(0, 1);
- else
- buffer.writeInteger(packetNumber++, 1);
+ if ( authenticationComplete ) {
+ packetNumber = 0;
+ }
+
+ buffer.writeInteger(packetNumber++, 1);
buffer.write(body, 0, body.length);
outputStream.write(buffer.toByteArray());
From 9bc770592590bad8b440034ee60f114c44e93fb2 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sun, 3 May 2020 15:27:46 -0700
Subject: [PATCH 042/217] mysql 8 authentication: first passing test.
We code and test the normal-authentication (non-cached) path, in which
we negotiate an SSL connection with the server, miss the cache for SHA2
passwords, and have to send a plaintext password.
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 1 +
.../mysql/binlog/network/Authenticator.java | 99 ++++++++++++++-----
.../network/protocol/PacketChannel.java | 6 ++
.../command/AuthenticateSHA2Command.java | 14 +++
.../protocol/command/ByteArrayCommand.java | 15 +++
.../protocol/command/SSLRequestCommand.java | 4 +-
.../BinaryLogClientIntegrationTest.java | 8 +-
7 files changed, 118 insertions(+), 29 deletions(-)
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/ByteArrayCommand.java
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index b6690126..16d47cd5 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -680,6 +680,7 @@ private boolean tryUpgradeToSSL(GreetingPacket greetingPacket) throws IOExceptio
DEFAULT_VERIFY_CA_SSL_MODE_SOCKET_FACTORY;
channel.upgradeToSSL(sslSocketFactory,
sslMode == SSLMode.VERIFY_IDENTITY ? new TLSHostnameVerifier() : null);
+ logger.info("SSL enabled");
return true;
}
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
index e75ee455..8abb920d 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
@@ -1,12 +1,14 @@
package com.github.shyiko.mysql.binlog.network;
import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream;
+import com.github.shyiko.mysql.binlog.io.ByteArrayOutputStream;
import com.github.shyiko.mysql.binlog.network.protocol.ErrorPacket;
import com.github.shyiko.mysql.binlog.network.protocol.GreetingPacket;
import com.github.shyiko.mysql.binlog.network.protocol.PacketChannel;
import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateNativePasswordCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSHA2Command;
import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSecurityPasswordCommand;
+import com.github.shyiko.mysql.binlog.network.protocol.command.ByteArrayCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.Command;
import com.github.shyiko.mysql.binlog.network.protocol.command.SSLRequestCommand;
@@ -16,6 +18,11 @@
import java.util.logging.Logger;
public class Authenticator {
+ private enum AuthMethod {
+ NATIVE,
+ CACHING_SHA2
+ };
+
private final GreetingPacket greetingPacket;
private final PacketChannel channel;
private final String schema;
@@ -24,6 +31,11 @@ public class Authenticator {
private final Logger logger = Logger.getLogger(getClass().getName());
+ private final String SHA2_PASSWORD = "caching_sha2_password";
+ private final String MYSQL_NATIVE = "mysql_native_password";
+
+ private AuthMethod authMethod = AuthMethod.NATIVE;
+
public Authenticator(
GreetingPacket greetingPacket,
PacketChannel channel,
@@ -42,32 +54,69 @@ public void authenticate() throws IOException {
logger.log(Level.INFO, "Begin auth for " + username);
int collation = greetingPacket.getServerCollation();
- Command authenticateCommand = "caching_sha2_password".equals(greetingPacket.getPluginProvidedData()) ?
- new AuthenticateSHA2Command(schema, username, password, greetingPacket.getScramble(), collation) :
- new AuthenticateSecurityPasswordCommand(schema, username, password, greetingPacket.getScramble(), collation);
+ Command authenticateCommand;
+ if ( SHA2_PASSWORD.equals(greetingPacket.getPluginProvidedData()) ) {
+ authMethod = AuthMethod.CACHING_SHA2;
+ authenticateCommand = new AuthenticateSHA2Command(schema, username, password, greetingPacket.getScramble(), collation);
+ } else {
+ authMethod = AuthMethod.NATIVE;
+ authenticateCommand = new AuthenticateSecurityPasswordCommand(schema, username, password, greetingPacket.getScramble(), collation);
+ }
channel.write(authenticateCommand);
+ readResult();
+ logger.log(Level.INFO, "Auth complete " + username);
+ }
+
+ private void readResult() throws IOException {
byte[] authenticationResult = channel.read();
- if (authenticationResult[0] != (byte) 0x00 /* ok */) {
- if (authenticationResult[0] == (byte) 0xFF /* error */) {
+ switch(authenticationResult[0]) {
+ case (byte) 0x00:
+ // success
+ return;
+ case (byte) 0xFF:
+ // error
byte[] bytes = Arrays.copyOfRange(authenticationResult, 1, authenticationResult.length);
ErrorPacket errorPacket = new ErrorPacket(bytes);
throw new AuthenticationException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
errorPacket.getSqlState());
- } else if (authenticationResult[0] == (byte) 0xFE) {
+ case (byte) 0xFE:
switchAuthentication(authenticationResult);
- } else if (authenticationResult[0] == (byte) 0x01) {
- if (authenticationResult.length >= 2 && (authenticationResult[1] == 3) || (authenticationResult[1] == 4)) {
- // 8.0 auth ok
- byte[] authenticationResultSha2 = channel.read();
+ return;
+ default:
+ if ( authMethod == AuthMethod.NATIVE )
+ throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + ")");
+ else
+ processCachingSHA2Result(authenticationResult);
+ }
+ }
+
+ private void processCachingSHA2Result(byte[] authenticationResult) throws IOException {
+ if (authenticationResult.length < 2)
+ throw new AuthenticationException("caching_sha2_password response too short!");
+
+ ByteArrayInputStream stream = new ByteArrayInputStream(authenticationResult);
+ stream.readPackedInteger(); // throw away length, always 1
+
+ switch(stream.read()) {
+ case 0x03:
+ // successful fast authentication
+ return;
+ case 0x04:
+ // need to send continue auth.
+ if ( channel.isSSL() ) {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ buffer.write(password.getBytes());
+ buffer.write(0);
+
+ Command c = new ByteArrayCommand(buffer.toByteArray());
+ channel.write(c);
+ readResult();
} else {
- throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + "&" + authenticationResult[1] + ")");
+ throw new AuthenticationException("Please enable SSL in order to support caching_sha2_password auth");
}
- } else {
- throw new AuthenticationException("Unexpected authentication result (" + authenticationResult[0] + ")");
- }
}
- logger.log(Level.INFO, "Auth complete " + username);
}
private void switchAuthentication(byte[] authenticationResult) throws IOException {
@@ -80,21 +129,21 @@ private void switchAuthentication(byte[] authenticationResult) throws IOExceptio
buffer.read(1);
String authName = buffer.readZeroTerminatedString();
- if ("mysql_native_password".equals(authName)) {
+ if (MYSQL_NATIVE.equals(authName)) {
+ authMethod = AuthMethod.NATIVE;
+
String scramble = buffer.readZeroTerminatedString();
Command switchCommand = new AuthenticateNativePasswordCommand(scramble, password);
channel.write(switchCommand);
- byte[] authResult = channel.read();
+ } else if ( SHA2_PASSWORD.equals(authName) ) {
+ authMethod = AuthMethod.CACHING_SHA2;
- if (authResult[0] != (byte) 0x00) {
- byte[] bytes = Arrays.copyOfRange(authResult, 1, authResult.length);
- ErrorPacket errorPacket = new ErrorPacket(bytes);
- throw new AuthenticationException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
- errorPacket.getSqlState());
- }
- } else {
- throw new AuthenticationException("Unsupported authentication type: " + authName);
+ String scramble = buffer.readZeroTerminatedString();
+ Command authCommand = new AuthenticateSHA2Command(password, scramble);
+ channel.write(authCommand);
}
+
+ readResult();
}
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
index 34208a10..95a4b2be 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/PacketChannel.java
@@ -34,6 +34,7 @@
public class PacketChannel implements Channel {
private int packetNumber = 0;
private boolean authenticationComplete;
+ private boolean isSSL = false;
private Socket socket;
private ByteArrayInputStream inputStream;
private ByteArrayOutputStream outputStream;
@@ -101,6 +102,11 @@ public void upgradeToSSL(SSLSocketFactory sslSocketFactory, HostnameVerifier hos
throw new IdentityVerificationException("\"" + sslSocket.getInetAddress().getHostName() +
"\" identity was not confirmed");
}
+ isSSL = true;
+ }
+
+ public boolean isSSL() {
+ return isSSL;
}
@Override
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
index c8afca7e..d5e7579c 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
@@ -34,6 +34,7 @@ public class AuthenticateSHA2Command implements Command {
private String salt;
private int clientCapabilities;
private int collation;
+ private boolean rawPassword = false;
public AuthenticateSHA2Command(String schema, String username, String password, String salt, int collation) {
this.schema = schema;
@@ -43,6 +44,12 @@ public AuthenticateSHA2Command(String schema, String username, String password,
this.collation = collation;
}
+ public AuthenticateSHA2Command(String password, String salt) {
+ this.rawPassword = true;
+ this.password = password;
+ this.salt = salt;
+ }
+
public void setClientCapabilities(int clientCapabilities) {
this.clientCapabilities = clientCapabilities;
}
@@ -50,6 +57,13 @@ public void setClientCapabilities(int clientCapabilities) {
@Override
public byte[] toByteArray() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ if ( rawPassword ) {
+ byte[] passwordSHA1 = encodePassword();
+ buffer.write(passwordSHA1);
+ return buffer.toByteArray();
+ }
+
int clientCapabilities = this.clientCapabilities;
if (clientCapabilities == 0) {
clientCapabilities |= ClientCapabilities.LONG_FLAG;
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/ByteArrayCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/ByteArrayCommand.java
new file mode 100644
index 00000000..94ee6998
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/ByteArrayCommand.java
@@ -0,0 +1,15 @@
+package com.github.shyiko.mysql.binlog.network.protocol.command;
+
+import java.io.IOException;
+
+public class ByteArrayCommand implements Command {
+ private final byte[] command;
+
+ public ByteArrayCommand(byte[] command) {
+ this.command = command;
+ }
+ @Override
+ public byte[] toByteArray() throws IOException {
+ return command;
+ }
+}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/SSLRequestCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/SSLRequestCommand.java
index ea748104..959cf5f9 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/SSLRequestCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/SSLRequestCommand.java
@@ -42,7 +42,9 @@ public byte[] toByteArray() throws IOException {
int clientCapabilities = this.clientCapabilities;
if (clientCapabilities == 0) {
clientCapabilities = ClientCapabilities.LONG_FLAG |
- ClientCapabilities.PROTOCOL_41 | ClientCapabilities.SECURE_CONNECTION;
+ ClientCapabilities.PROTOCOL_41 |
+ ClientCapabilities.SECURE_CONNECTION |
+ ClientCapabilities.PLUGIN_AUTH;
}
clientCapabilities |= ClientCapabilities.SSL;
buffer.writeInteger(clientCapabilities, 4);
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 7618fe40..2909b2b6 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -32,6 +32,7 @@
import com.github.shyiko.mysql.binlog.io.BufferedSocketInputStream;
import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream;
import com.github.shyiko.mysql.binlog.network.AuthenticationException;
+import com.github.shyiko.mysql.binlog.network.SSLMode;
import com.github.shyiko.mysql.binlog.network.ServerException;
import com.github.shyiko.mysql.binlog.network.SocketFactory;
import org.mockito.InOrder;
@@ -1006,11 +1007,12 @@ public void testMysql8Auth() throws Exception {
throw new SkipException("skipping mysql8 auth test");
master.execute("create user 'mysql8' IDENTIFIED WITH caching_sha2_password BY 'testpass'");
- master.execute("grant replication slave on *.* to 'mysql8'");
+ master.execute("grant replication slave, replication client on *.* to 'mysql8'");
final BinaryLogClient binaryLogClient =
- new BinaryLogClient(master.hostname, master.port, "mysql8", "testPass");
- binaryLogClient.connect(5000);
+ new BinaryLogClient(master.hostname, master.port, "mysql8", "testpass");
+ binaryLogClient.setSSLMode(SSLMode.PREFERRED);
+ binaryLogClient.connect(500000);
}
@Test
From ce680a801316eb009b1158ba05e00bb8c3275a23 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 4 May 2020 11:08:41 -0700
Subject: [PATCH 043/217] finish off slow path for caching_sha2_authentication
this involves either sending the password over a TLS channel or grabbing
an RSA key from the server and encrypting the password with that. whew!
---
.../mysql/binlog/network/Authenticator.java | 53 ++++++++++----
.../AuthenticateSHA2RSAPasswordCommand.java | 73 +++++++++++++++++++
.../BinaryLogClientIntegrationTest.java | 60 +++++++++++++--
.../mysql/binlog/MysqlOnetimeServer.java | 2 +-
4 files changed, 168 insertions(+), 20 deletions(-)
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
index 8abb920d..fa891d2a 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
@@ -7,6 +7,7 @@
import com.github.shyiko.mysql.binlog.network.protocol.PacketChannel;
import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateNativePasswordCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSHA2Command;
+import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSHA2RSAPasswordCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSecurityPasswordCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.ByteArrayCommand;
import com.github.shyiko.mysql.binlog.network.protocol.command.Command;
@@ -24,6 +25,7 @@ private enum AuthMethod {
};
private final GreetingPacket greetingPacket;
+ private String scramble;
private final PacketChannel channel;
private final String schema;
private final String username;
@@ -44,6 +46,7 @@ public Authenticator(
String password
) {
this.greetingPacket = greetingPacket;
+ this.scramble = greetingPacket.getScramble();
this.channel = channel;
this.schema = schema;
this.username = username;
@@ -57,10 +60,10 @@ public void authenticate() throws IOException {
Command authenticateCommand;
if ( SHA2_PASSWORD.equals(greetingPacket.getPluginProvidedData()) ) {
authMethod = AuthMethod.CACHING_SHA2;
- authenticateCommand = new AuthenticateSHA2Command(schema, username, password, greetingPacket.getScramble(), collation);
+ authenticateCommand = new AuthenticateSHA2Command(schema, username, password, scramble, collation);
} else {
authMethod = AuthMethod.NATIVE;
- authenticateCommand = new AuthenticateSecurityPasswordCommand(schema, username, password, greetingPacket.getScramble(), collation);
+ authenticateCommand = new AuthenticateSecurityPasswordCommand(schema, username, password, scramble, collation);
}
channel.write(authenticateCommand);
@@ -100,22 +103,46 @@ private void processCachingSHA2Result(byte[] authenticationResult) throws IOExce
switch(stream.read()) {
case 0x03:
+ logger.log(Level.INFO, "caching auth successful");
// successful fast authentication
+ readResult();
return;
case 0x04:
- // need to send continue auth.
- if ( channel.isSSL() ) {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ continueCachingSHA2Authentication();
+ }
+ }
+
+ private void continueCachingSHA2Authentication() throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ if ( channel.isSSL() ) {
+ // over SSL we simply send the password in cleartext.
- buffer.write(password.getBytes());
- buffer.write(0);
+ buffer.write(password.getBytes());
+ buffer.write(0);
- Command c = new ByteArrayCommand(buffer.toByteArray());
+ Command c = new ByteArrayCommand(buffer.toByteArray());
+ channel.write(c);
+ readResult();
+ } else {
+ // try to download an RSA key
+ buffer.write(0x02);
+ channel.write(new ByteArrayCommand(buffer.toByteArray()));
+
+ ByteArrayInputStream stream = new ByteArrayInputStream(channel.read());
+ int result = stream.read();
+ switch(result) {
+ case 0x01:
+ byte[] rsaKey = new byte[stream.available()];
+ stream.read(rsaKey);
+
+ Command c = new AuthenticateSHA2RSAPasswordCommand(new String(rsaKey), password, scramble);
channel.write(c);
+
readResult();
- } else {
- throw new AuthenticationException("Please enable SSL in order to support caching_sha2_password auth");
- }
+ return;
+ default:
+ throw new AuthenticationException("Unkown response fetching RSA key in caching_sha2_pasword auth: " + result);
+ }
}
}
@@ -132,14 +159,14 @@ private void switchAuthentication(byte[] authenticationResult) throws IOExceptio
if (MYSQL_NATIVE.equals(authName)) {
authMethod = AuthMethod.NATIVE;
- String scramble = buffer.readZeroTerminatedString();
+ this.scramble = buffer.readZeroTerminatedString();
Command switchCommand = new AuthenticateNativePasswordCommand(scramble, password);
channel.write(switchCommand);
} else if ( SHA2_PASSWORD.equals(authName) ) {
authMethod = AuthMethod.CACHING_SHA2;
- String scramble = buffer.readZeroTerminatedString();
+ this.scramble = buffer.readZeroTerminatedString();
Command authCommand = new AuthenticateSHA2Command(password, scramble);
channel.write(authCommand);
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
new file mode 100644
index 00000000..3799c6dd
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
@@ -0,0 +1,73 @@
+package com.github.shyiko.mysql.binlog.network.protocol.command;
+
+import com.github.shyiko.mysql.binlog.network.AuthenticationException;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+public class AuthenticateSHA2RSAPasswordCommand implements Command {
+ private static final String RSA_METHOD = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
+ private final String rsaKey;
+ private final String password;
+ private final String scramble;
+
+ public AuthenticateSHA2RSAPasswordCommand(String rsaKey, String password, String scramble) {
+ this.rsaKey = rsaKey;
+ this.password = password;
+ this.scramble = scramble;
+ }
+
+ @Override
+ public byte[] toByteArray() throws IOException {
+ RSAPublicKey key = decodeKey(rsaKey);
+
+ ByteArrayOutputStream nullTerminatedPassword = new ByteArrayOutputStream();
+ if ( password != null )
+ nullTerminatedPassword.write(password.getBytes());
+ nullTerminatedPassword.write(0);
+
+ byte[] passBytes = nullTerminatedPassword.toByteArray();
+ byte[] scrambleBytes = scramble.getBytes();
+ byte[] xorBuffer = new byte[passBytes.length];
+
+ for(int pos = 0; pos < passBytes.length; pos++) {
+ xorBuffer[pos] = (byte) (passBytes[pos] ^ scrambleBytes[pos % scrambleBytes.length]);
+ }
+
+ byte[] encrypted = encrypt(xorBuffer, key, RSA_METHOD);
+ return encrypted;
+ }
+
+ private RSAPublicKey decodeKey(String key) throws AuthenticationException {
+ int beginIndex = key.indexOf("\n") + 1;
+ int endIndex = key.indexOf("-----END PUBLIC KEY-----");
+ String innerKey = key.substring(beginIndex, endIndex).replaceAll("\\n", "");
+
+ Base64.Decoder decoder = Base64.getDecoder();
+ byte[] certificateData = decoder.decode(innerKey.getBytes());
+
+ X509EncodedKeySpec spec = new X509EncodedKeySpec(certificateData);
+ try {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ return (RSAPublicKey) kf.generatePublic(spec);
+ } catch (Exception e) {
+ throw new AuthenticationException("Unable to decode public key: " + key);
+ }
+ }
+
+ private byte[] encrypt(byte[] source, RSAPublicKey key, String transformation) throws AuthenticationException {
+ try {
+ Cipher cipher = Cipher.getInstance(transformation);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ return cipher.doFinal(source);
+ } catch (Exception e) {
+ throw new AuthenticationException("couldn't encrypt password: " + e.getMessage());
+ }
+ }
+
+}
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 2909b2b6..22d92a9f 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -35,6 +35,7 @@
import com.github.shyiko.mysql.binlog.network.SSLMode;
import com.github.shyiko.mysql.binlog.network.ServerException;
import com.github.shyiko.mysql.binlog.network.SocketFactory;
+import com.mysql.cj.MysqlConnection;
import org.mockito.InOrder;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
@@ -1001,18 +1002,65 @@ public void execute(Statement statement) throws SQLException {
}
}
+ private BinaryLogClient setupMysql8Login(MySQLConnection server) throws Exception {
+ server.execute("create user 'mysql8' IDENTIFIED WITH caching_sha2_password BY 'testpass'");
+ server.execute("grant replication slave, replication client on *.* to 'mysql8'");
+
+ return new BinaryLogClient(server.hostname, server.port, "mysql8", "testpass");
+ }
+
@Test
public void testMysql8Auth() throws Exception {
if ( !mysqlVersion.atLeast(8, 0) )
throw new SkipException("skipping mysql8 auth test");
- master.execute("create user 'mysql8' IDENTIFIED WITH caching_sha2_password BY 'testpass'");
- master.execute("grant replication slave, replication client on *.* to 'mysql8'");
+ BinaryLogClient client = setupMysql8Login(master);
+ client.setSSLMode(SSLMode.PREFERRED);
+ client.connect(DEFAULT_TIMEOUT);
+ }
+
+ @Test
+ public void testMysql8FastAuth() throws Exception {
+ if ( !mysqlVersion.atLeast(8, 0) )
+ throw new SkipException("skipping mysql8 auth test");
+
+ BinaryLogClient client = setupMysql8Login(master);
+ client.setSSLMode(SSLMode.PREFERRED);
+ client.connect(DEFAULT_TIMEOUT);
+
+ client.disconnect();
+
+ // this call should hit the sha2 cache
+ client.connect(DEFAULT_TIMEOUT);
+ }
+
+
+ @Test
+ public void testSHA2CachingAuthAsDefault() throws Exception {
+ if ( !mysqlVersion.atLeast(8, 0) )
+ throw new SkipException("skipping mysql8 auth test");
+
+ MysqlOnetimeServerOptions opts = new MysqlOnetimeServerOptions();
+ opts.extraParams = "--default-authentication-plugin=caching_sha2_password";
+ MysqlOnetimeServer server = new MysqlOnetimeServer(opts);
+ server.boot();
+
+ MySQLConnection cx = new MySQLConnection("127.0.0.1", server.getPort(), "root", "");
+
+ BinaryLogClient client = setupMysql8Login(cx);
+ client.setSSLMode(SSLMode.PREFERRED);
+ client.connect(DEFAULT_TIMEOUT);
+
+ server.shutDown();
+ }
+
+ @Test
+ public void testSHA2CachingWithoutSSL() throws Exception {
+ if ( !mysqlVersion.atLeast(8, 0) )
+ throw new SkipException("skipping mysql8 auth test");
- final BinaryLogClient binaryLogClient =
- new BinaryLogClient(master.hostname, master.port, "mysql8", "testpass");
- binaryLogClient.setSSLMode(SSLMode.PREFERRED);
- binaryLogClient.connect(500000);
+ BinaryLogClient client = setupMysql8Login(master);
+ client.connect(DEFAULT_TIMEOUT);
}
@Test
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
index 3dca9cb4..a74e159e 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/MysqlOnetimeServer.java
@@ -59,7 +59,7 @@ public void boot() throws Exception {
String authPlugin = "";
- if ( getVersion().atLeast(8, 0) ) {
+ if ( getVersion().atLeast(8, 0) && !xtraParams.contains("--default-authentication-plugin")) {
authPlugin = "--default-authentication-plugin=mysql_native_password";
}
From f84cfdebeab9c38fa707b7286f29f80a8c7ee18d Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Tue, 5 May 2020 06:59:33 -0700
Subject: [PATCH 044/217] make the tests play nice with each other
---
.../BinaryLogClientIntegrationTest.java | 22 +++++++++++--------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 22d92a9f..892bdc5d 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -152,6 +152,11 @@ public void execute(Statement statement) throws SQLException {
}
});
eventListener.waitFor(EventType.QUERY, 2, DEFAULT_TIMEOUT);
+
+ if ( mysqlVersion.atLeast(8, 0) ) {
+ setupMysql8Login(master);
+ eventListener.waitFor(EventType.QUERY, 2, DEFAULT_TIMEOUT);
+ }
}
@BeforeMethod
@@ -1002,11 +1007,9 @@ public void execute(Statement statement) throws SQLException {
}
}
- private BinaryLogClient setupMysql8Login(MySQLConnection server) throws Exception {
+ private void setupMysql8Login(MySQLConnection server) throws Exception {
server.execute("create user 'mysql8' IDENTIFIED WITH caching_sha2_password BY 'testpass'");
server.execute("grant replication slave, replication client on *.* to 'mysql8'");
-
- return new BinaryLogClient(server.hostname, server.port, "mysql8", "testpass");
}
@Test
@@ -1014,7 +1017,7 @@ public void testMysql8Auth() throws Exception {
if ( !mysqlVersion.atLeast(8, 0) )
throw new SkipException("skipping mysql8 auth test");
- BinaryLogClient client = setupMysql8Login(master);
+ BinaryLogClient client = new BinaryLogClient(master.hostname, master.port, "mysql8", "testpass");
client.setSSLMode(SSLMode.PREFERRED);
client.connect(DEFAULT_TIMEOUT);
}
@@ -1024,7 +1027,7 @@ public void testMysql8FastAuth() throws Exception {
if ( !mysqlVersion.atLeast(8, 0) )
throw new SkipException("skipping mysql8 auth test");
- BinaryLogClient client = setupMysql8Login(master);
+ BinaryLogClient client = new BinaryLogClient(master.hostname, master.port, "mysql8", "testpass");
client.setSSLMode(SSLMode.PREFERRED);
client.connect(DEFAULT_TIMEOUT);
@@ -1047,9 +1050,10 @@ public void testSHA2CachingAuthAsDefault() throws Exception {
MySQLConnection cx = new MySQLConnection("127.0.0.1", server.getPort(), "root", "");
- BinaryLogClient client = setupMysql8Login(cx);
- client.setSSLMode(SSLMode.PREFERRED);
- client.connect(DEFAULT_TIMEOUT);
+ setupMysql8Login(cx);
+ BinaryLogClient c = new BinaryLogClient(cx.hostname, cx.port, "mysql8", "testpass");
+ c.setSSLMode(SSLMode.PREFERRED);
+ c.connect(DEFAULT_TIMEOUT);
server.shutDown();
}
@@ -1059,7 +1063,7 @@ public void testSHA2CachingWithoutSSL() throws Exception {
if ( !mysqlVersion.atLeast(8, 0) )
throw new SkipException("skipping mysql8 auth test");
- BinaryLogClient client = setupMysql8Login(master);
+ BinaryLogClient client = new BinaryLogClient(master.hostname, master.port, "mysql8", "testpass");
client.connect(DEFAULT_TIMEOUT);
}
From 02bd10ba42a40c93003e7017813331ae4ed2b0c7 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Tue, 5 May 2020 16:03:59 -0700
Subject: [PATCH 045/217] code clean-up; unify XOR code, switch some arguments
around
---
.../mysql/binlog/network/Authenticator.java | 2 +-
.../command/AuthenticateSHA2Command.java | 28 +++++--------------
.../AuthenticateSHA2RSAPasswordCommand.java | 9 ++----
.../AuthenticateSecurityPasswordCommand.java | 11 +-------
.../protocol/command/CommandUtils.java | 12 ++++++++
5 files changed, 23 insertions(+), 39 deletions(-)
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/CommandUtils.java
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
index fa891d2a..37728d12 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
@@ -167,7 +167,7 @@ private void switchAuthentication(byte[] authenticationResult) throws IOExceptio
authMethod = AuthMethod.CACHING_SHA2;
this.scramble = buffer.readZeroTerminatedString();
- Command authCommand = new AuthenticateSHA2Command(password, scramble);
+ Command authCommand = new AuthenticateSHA2Command(scramble, password);
channel.write(authCommand);
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
index d5e7579c..b776df58 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2Command.java
@@ -31,23 +31,23 @@ public class AuthenticateSHA2Command implements Command {
private String schema;
private String username;
private String password;
- private String salt;
+ private String scramble;
private int clientCapabilities;
private int collation;
private boolean rawPassword = false;
- public AuthenticateSHA2Command(String schema, String username, String password, String salt, int collation) {
+ public AuthenticateSHA2Command(String schema, String username, String password, String scramble, int collation) {
this.schema = schema;
this.username = username;
this.password = password;
- this.salt = salt;
+ this.scramble = scramble;
this.collation = collation;
}
- public AuthenticateSHA2Command(String password, String salt) {
+ public AuthenticateSHA2Command(String scramble, String password) {
this.rawPassword = true;
this.password = password;
- this.salt = salt;
+ this.scramble = scramble;
}
public void setClientCapabilities(int clientCapabilities) {
@@ -128,29 +128,15 @@ private byte[] encodePassword() {
// SHA2(digest_stage2, m_rnd) => scramble_stage1
md.update(dig2, 0, dig1.length);
- md.update(salt.getBytes(), 0, salt.getBytes().length);
+ md.update(scramble.getBytes(), 0, scramble.getBytes().length);
md.digest(scramble1, 0, CACHING_SHA2_DIGEST_LENGTH);
// XOR(digest_stage1, scramble_stage1) => scramble
- byte[] mysqlScrambleBuff = new byte[CACHING_SHA2_DIGEST_LENGTH];
- xor(dig1, mysqlScrambleBuff, scramble1, CACHING_SHA2_DIGEST_LENGTH);
-
- return mysqlScrambleBuff;
+ return CommandUtils.xor(dig1, scramble1);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
} catch (DigestException e) {
throw new RuntimeException(e);
}
}
-
- private void xor(byte[] from, byte[] to, byte[] scramble, int length) {
- int pos = 0;
- int scrambleLength = scramble.length;
-
- while (pos < length) {
- to[pos] = (byte) (from[pos] ^ scramble[pos % scrambleLength]);
- pos++;
- }
- }
-
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
index 3799c6dd..2a7913b0 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
@@ -32,14 +32,9 @@ public byte[] toByteArray() throws IOException {
nullTerminatedPassword.write(0);
byte[] passBytes = nullTerminatedPassword.toByteArray();
- byte[] scrambleBytes = scramble.getBytes();
- byte[] xorBuffer = new byte[passBytes.length];
-
- for(int pos = 0; pos < passBytes.length; pos++) {
- xorBuffer[pos] = (byte) (passBytes[pos] ^ scrambleBytes[pos % scrambleBytes.length]);
- }
-
+ byte[] xorBuffer = CommandUtils.xor(passBytes, scramble.getBytes());
byte[] encrypted = encrypt(xorBuffer, key, RSA_METHOD);
+
return encrypted;
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
index d0741138..ea3dfc53 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
@@ -94,7 +94,7 @@ public static byte[] passwordCompatibleWithMySQL411(String password, String salt
throw new RuntimeException(e);
}
byte[] passwordHash = sha.digest(password.getBytes());
- return xor(passwordHash, sha.digest(union(salt.getBytes(), sha.digest(passwordHash))));
+ return CommandUtils.xor(passwordHash, sha.digest(union(salt.getBytes(), sha.digest(passwordHash))));
}
private static byte[] union(byte[] a, byte[] b) {
@@ -103,13 +103,4 @@ private static byte[] union(byte[] a, byte[] b) {
System.arraycopy(b, 0, r, a.length, b.length);
return r;
}
-
- private static byte[] xor(byte[] a, byte[] b) {
- byte[] r = new byte[a.length];
- for (int i = 0; i < r.length; i++) {
- r[i] = (byte) (a[i] ^ b[i]);
- }
- return r;
- }
-
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/CommandUtils.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/CommandUtils.java
new file mode 100644
index 00000000..68c09095
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/CommandUtils.java
@@ -0,0 +1,12 @@
+package com.github.shyiko.mysql.binlog.network.protocol.command;
+
+public class CommandUtils {
+ public static byte[] xor(byte[] input, byte[] against) {
+ byte[] to = new byte[input.length];
+
+ for( int i = 0; i < input.length; i++ ) {
+ to[i] = (byte) (input[i] ^ against[i % against.length]);
+ }
+ return to;
+ }
+}
From 48fe68669c18b5fa8ae68d0c0392f7ab3aa6fd54 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Tue, 5 May 2020 16:09:35 -0700
Subject: [PATCH 046/217] use the already existing `writeZeroTerminatedString`
---
.../mysql/binlog/io/ByteArrayOutputStream.java | 4 +++-
.../mysql/binlog/network/Authenticator.java | 3 +--
.../AuthenticateSHA2RSAPasswordCommand.java | 15 +++++----------
3 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
index 7154ba22..0bbdf3aa 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
@@ -59,7 +59,9 @@ public void writeString(String value) throws IOException {
* @see ByteArrayInputStream#readZeroTerminatedString()
*/
public void writeZeroTerminatedString(String value) throws IOException {
- write(value.getBytes());
+ if ( value != null )
+ write(value.getBytes());
+
write(0);
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
index 37728d12..7e597d3e 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
@@ -117,8 +117,7 @@ private void continueCachingSHA2Authentication() throws IOException {
if ( channel.isSSL() ) {
// over SSL we simply send the password in cleartext.
- buffer.write(password.getBytes());
- buffer.write(0);
+ buffer.writeZeroTerminatedString(password);
Command c = new ByteArrayCommand(buffer.toByteArray());
channel.write(c);
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
index 2a7913b0..e8de8d4f 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSHA2RSAPasswordCommand.java
@@ -1,9 +1,9 @@
package com.github.shyiko.mysql.binlog.network.protocol.command;
import com.github.shyiko.mysql.binlog.network.AuthenticationException;
+import com.github.shyiko.mysql.binlog.io.ByteArrayOutputStream;
import javax.crypto.Cipher;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
@@ -26,16 +26,11 @@ public AuthenticateSHA2RSAPasswordCommand(String rsaKey, String password, String
public byte[] toByteArray() throws IOException {
RSAPublicKey key = decodeKey(rsaKey);
- ByteArrayOutputStream nullTerminatedPassword = new ByteArrayOutputStream();
- if ( password != null )
- nullTerminatedPassword.write(password.getBytes());
- nullTerminatedPassword.write(0);
+ ByteArrayOutputStream passBuffer = new ByteArrayOutputStream();
+ passBuffer.writeZeroTerminatedString(password);
- byte[] passBytes = nullTerminatedPassword.toByteArray();
- byte[] xorBuffer = CommandUtils.xor(passBytes, scramble.getBytes());
- byte[] encrypted = encrypt(xorBuffer, key, RSA_METHOD);
-
- return encrypted;
+ byte[] xorBuffer = CommandUtils.xor(passBuffer.toByteArray(), scramble.getBytes());
+ return encrypt(xorBuffer, key, RSA_METHOD);
}
private RSAPublicKey decodeKey(String key) throws AuthenticationException {
From 3810fcd12dcecefeec50a618c645e2ab9e18cea7 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Tue, 5 May 2020 16:12:07 -0700
Subject: [PATCH 047/217] downgrade logging to debug level
---
.../github/shyiko/mysql/binlog/network/Authenticator.java | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
index 7e597d3e..bc8c684b 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
@@ -54,7 +54,7 @@ public Authenticator(
}
public void authenticate() throws IOException {
- logger.log(Level.INFO, "Begin auth for " + username);
+ logger.log(Level.FINE, "Begin auth for " + username);
int collation = greetingPacket.getServerCollation();
Command authenticateCommand;
@@ -68,7 +68,7 @@ public void authenticate() throws IOException {
channel.write(authenticateCommand);
readResult();
- logger.log(Level.INFO, "Auth complete " + username);
+ logger.log(Level.FINE, "Auth complete " + username);
}
private void readResult() throws IOException {
@@ -103,11 +103,12 @@ private void processCachingSHA2Result(byte[] authenticationResult) throws IOExce
switch(stream.read()) {
case 0x03:
- logger.log(Level.INFO, "caching auth successful");
+ logger.log(Level.FINE, "cached sha2 auth successful");
// successful fast authentication
readResult();
return;
case 0x04:
+ logger.log(Level.FINE, "cached sha2 auth not successful, moving to full auth path");
continueCachingSHA2Authentication();
}
}
@@ -134,6 +135,7 @@ private void continueCachingSHA2Authentication() throws IOException {
byte[] rsaKey = new byte[stream.available()];
stream.read(rsaKey);
+ logger.log(Level.FINE, "received RSA key: " + rsaKey);
Command c = new AuthenticateSHA2RSAPasswordCommand(new String(rsaKey), password, scramble);
channel.write(c);
From b33e8abd99c54c14eda4e39e1106d884f0043032 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Tue, 5 May 2020 17:35:58 -0700
Subject: [PATCH 048/217] fix EOFError crash in test suite
mysql8 is, for some oddball reason, occasionally asking us to try
sha256_password (non-caching) authentication. We should crash, but not
with an EOFError
---
.../com/github/shyiko/mysql/binlog/network/Authenticator.java | 2 ++
.../shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java | 1 +
2 files changed, 3 insertions(+)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
index bc8c684b..0faf012d 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/Authenticator.java
@@ -170,6 +170,8 @@ private void switchAuthentication(byte[] authenticationResult) throws IOExceptio
this.scramble = buffer.readZeroTerminatedString();
Command authCommand = new AuthenticateSHA2Command(scramble, password);
channel.write(authCommand);
+ } else {
+ throw new AuthenticationException("unsupported authentication method: " + authName);
}
readResult();
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 892bdc5d..7b7efa31 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -851,6 +851,7 @@ public void testExceptionIsThrownWhenInsufficientPermissionsToDetectPosition() t
String prefix = "jdbc.mysql.replication.";
String slaveUsername = bundle.getString(prefix + "slave.slaveUsername");
String slavePassword = bundle.getString(prefix + "slave.slavePassword");
+
new BinaryLogClient(slave.hostname, slave.port, slaveUsername, slavePassword).connect();
}
From 5f8e7b58f549740d13c13977d55420436210ad6d Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 11 May 2020 21:59:39 -0700
Subject: [PATCH 049/217] bump version
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 79a568f5..1d8253ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.22.2
+ 0.23.0-rc1mysql-binlog-connector-javaMySQL Binary Log connector
From 1a00ac240a59d6504744c3f75e5f3f0256897be4 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 11 May 2020 21:59:49 -0700
Subject: [PATCH 050/217] remove unused var
---
.../java/com/github/shyiko/mysql/binlog/BinaryLogClient.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index 16d47cd5..ce8a1abd 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -141,7 +141,6 @@ public X509Certificate[] getAcceptedIssuers() {
private boolean useBinlogFilenamePositionInGtidMode;
private String gtid;
private boolean tx;
- private boolean isSSL;
private EventDeserializer eventDeserializer = new EventDeserializer();
From d1395ed1a534d2bdc7f984589c28fd26b35b92de Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 11 May 2020 22:10:31 -0700
Subject: [PATCH 051/217] rework resultset error handling
do an obvious hoist into a function
also add code targeting https://github.com/zendesk/maxwell/issues/1374,
where a row itself can have an ErrPacket
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 40 ++++++++-----------
1 file changed, 16 insertions(+), 24 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index ce8a1abd..2fe57f53 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -647,14 +647,19 @@ public Object call() throws Exception {
};
}
- private GreetingPacket receiveGreeting() throws IOException {
- byte[] initialHandshakePacket = channel.read();
- if (initialHandshakePacket[0] == (byte) 0xFF /* error */) {
- byte[] bytes = Arrays.copyOfRange(initialHandshakePacket, 1, initialHandshakePacket.length);
+ private void checkError(byte[] packet) throws IOException {
+ if (packet[0] == (byte) 0xFF /* error */) {
+ byte[] bytes = Arrays.copyOfRange(packet, 1, packet.length);
ErrorPacket errorPacket = new ErrorPacket(bytes);
throw new ServerException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
- errorPacket.getSqlState());
+ errorPacket.getSqlState());
}
+ }
+
+ private GreetingPacket receiveGreeting() throws IOException {
+ byte[] initialHandshakePacket = channel.read();
+ checkError(initialHandshakePacket);
+
return new GreetingPacket(initialHandshakePacket);
}
@@ -690,12 +695,7 @@ private boolean tryUpgradeToSSL(GreetingPacket greetingPacket) throws IOExceptio
private void enableHeartbeat() throws IOException {
channel.write(new QueryCommand("set @master_heartbeat_period=" + heartbeatInterval * 1000000));
byte[] statementResult = channel.read();
- if (statementResult[0] == (byte) 0xFF /* error */) {
- byte[] bytes = Arrays.copyOfRange(statementResult, 1, statementResult.length);
- ErrorPacket errorPacket = new ErrorPacket(bytes);
- throw new ServerException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
- errorPacket.getSqlState());
- }
+ checkError(statementResult);
}
private void setMasterServerId() throws IOException {
@@ -904,12 +904,7 @@ private ChecksumType fetchBinlogChecksum() throws IOException {
private void confirmSupportOfChecksum(ChecksumType checksumType) throws IOException {
channel.write(new QueryCommand("set @master_binlog_checksum= @@global.binlog_checksum"));
byte[] statementResult = channel.read();
- if (statementResult[0] == (byte) 0xFF /* error */) {
- byte[] bytes = Arrays.copyOfRange(statementResult, 1, statementResult.length);
- ErrorPacket errorPacket = new ErrorPacket(bytes);
- throw new ServerException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
- errorPacket.getSqlState());
- }
+ checkError(statementResult);
eventDeserializer.setChecksumType(checksumType);
}
@@ -1051,16 +1046,13 @@ private void commitGtid() {
}
private ResultSetRowPacket[] readResultSet() throws IOException {
- List resultSet = new LinkedList();
+ List resultSet = new LinkedList<>();
byte[] statementResult = channel.read();
- if (statementResult[0] == (byte) 0xFF /* error */) {
- byte[] bytes = Arrays.copyOfRange(statementResult, 1, statementResult.length);
- ErrorPacket errorPacket = new ErrorPacket(bytes);
- throw new ServerException(errorPacket.getErrorMessage(), errorPacket.getErrorCode(),
- errorPacket.getSqlState());
- }
+ checkError(statementResult);
+
while ((channel.read())[0] != (byte) 0xFE /* eof */) { /* skip */ }
for (byte[] bytes; (bytes = channel.read())[0] != (byte) 0xFE /* eof */; ) {
+ checkError(bytes);
resultSet.add(new ResultSetRowPacket(bytes));
}
return resultSet.toArray(new ResultSetRowPacket[resultSet.size()]);
From 073532e55d029f69444830c332c0b47f089641cc Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 25 May 2020 22:22:42 -0700
Subject: [PATCH 052/217] v0.23.1
---
pom.xml | 2 +-
.../deserialization/AbstractRowsEventDataDeserializer.java | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index 1d8253ff..200b0c3f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.23.0-rc1
+ 0.23.1mysql-binlog-connector-javaMySQL Binary Log connector
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
index e7cf6d53..0b2ac624 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
@@ -411,7 +411,6 @@ protected byte[] deserializeJson(int meta, ByteArrayInputStream inputStream) thr
return inputStream.read(blobLength);
}
- // checkstyle, please ignore ParameterNumber for the next line
protected Long asUnixTime(int year, int month, int day, int hour, int minute, int second, int millis) {
// https://dev.mysql.com/doc/refman/5.0/en/datetime.html
if (year == 0 || month == 0 || day == 0) {
From f546e2e88b2f67db77422fd22169d01a49b898e1 Mon Sep 17 00:00:00 2001
From: Mark Crisp
Date: Thu, 23 Jul 2020 19:50:12 -0400
Subject: [PATCH 053/217] propagate all exceptions that occur in binary log
client
---
.../com/github/shyiko/mysql/binlog/BinaryLogClient.java | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index 2fe57f53..e4b8b4df 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -495,8 +495,9 @@ public void setThreadFactory(ThreadFactory threadFactory) {
* @throws AuthenticationException if authentication fails
* @throws ServerException if MySQL server responds with an error
* @throws IOException if anything goes wrong while trying to connect
+ * @throws IllegalStateException if binary log client is already connected
*/
- public void connect() throws IOException {
+ public void connect() throws IOException, IllegalStateException {
if (!connectLock.tryLock()) {
throw new IllegalStateException("BinaryLogClient is already connected");
}
@@ -836,8 +837,8 @@ public void run() {
try {
setConnectTimeout(timeout);
connect();
- } catch (IOException e) {
- exceptionReference.set(e);
+ } catch (Exception e) {
+ exceptionReference.set(new IOException(e)); // method is asynchronous, catch all exceptions so that they are not lost
countDownLatch.countDown(); // making sure we don't end up waiting whole "timeout"
}
}
From d3c019e77546e1813dfd98266d98a56a24e0fbf0 Mon Sep 17 00:00:00 2001
From: Mark Crisp
Date: Thu, 23 Jul 2020 20:03:58 -0400
Subject: [PATCH 054/217] added integration test
---
.../shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 7b7efa31..aa81b588 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -833,6 +833,12 @@ public void testExceptionIsThrownWhenTryingToConnectAlreadyConnectedClient() thr
client.connect();
}
+ @Test(expectedExceptions = IOException.class)
+ public void testExceptionIsThrownWhenTryingToConnectAlreadyConnectedClientWithTimeout() throws Exception {
+ assertTrue(client.isConnected());
+ client.connect(1000);
+ }
+
@Test
public void testExceptionIsThrownWhenProvidedWithWrongCredentials() throws Exception {
BinaryLogClient binaryLogClient =
From 48623192a02f02826a39c89b9356ae5dd4490ba1 Mon Sep 17 00:00:00 2001
From: Mark Crisp
Date: Sat, 25 Jul 2020 17:37:51 -0400
Subject: [PATCH 055/217] fixed auth exception test
---
.../java/com/github/shyiko/mysql/binlog/BinaryLogClient.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index e4b8b4df..e3f1857c 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -837,6 +837,9 @@ public void run() {
try {
setConnectTimeout(timeout);
connect();
+ } catch (IOException e) {
+ exceptionReference.set(e);
+ countDownLatch.countDown(); // making sure we don't end up waiting whole "timeout"
} catch (Exception e) {
exceptionReference.set(new IOException(e)); // method is asynchronous, catch all exceptions so that they are not lost
countDownLatch.countDown(); // making sure we don't end up waiting whole "timeout"
From 2e6147bc81ac458a7325e220840be285388a0145 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sat, 25 Jul 2020 21:49:15 -0700
Subject: [PATCH 056/217] v0.23.2
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 200b0c3f..c8769558 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.23.1
+ 0.23.2mysql-binlog-connector-javaMySQL Binary Log connector
From 9764d2ee03b56d0c122068309a65a5a713d1b3ca Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Tue, 4 Aug 2020 19:39:43 -0700
Subject: [PATCH 057/217] update new maven slug
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 0c11b688..adf41cb4 100644
--- a/README.md
+++ b/README.md
@@ -27,9 +27,9 @@ Get the latest JAR(s) from [here](http://search.maven.org/#search%7Cga%7C1%7Cg%3
```xml
- com.github.shyiko
+ com.zendeskmysql-binlog-connector-java
- 0.18.1
+ 0.23.2
```
From 8ca21a43f1de9b5ce9abe8597acb79f18ac63056 Mon Sep 17 00:00:00 2001
From: auntyellow
Date: Sun, 9 Aug 2020 22:23:11 +0800
Subject: [PATCH 058/217] update maven url
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index adf41cb4..05d65a8c 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ but ended up as a complete rewrite. Key differences/features:
## Usage
-Get the latest JAR(s) from [here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.github.shyiko%22%20AND%20a%3A%22mysql-binlog-connector-java%22). Alternatively you can include following Maven dependency (available through Maven Central):
+Get the latest JAR(s) from [here](https://search.maven.org/search?q=g:com.zendesk%20AND%20a:mysql-binlog-connector-java). Alternatively you can include following Maven dependency (available through Maven Central):
```xml
From 7d6d12349fd647733a0a727905ffe9c78595d402 Mon Sep 17 00:00:00 2001
From: zzt
Date: Sat, 24 Oct 2020 21:38:26 +0800
Subject: [PATCH 059/217] add
EventDeserializer.CompatibilityMode.INTEGER_AS_BYTE_ARRAY impl.
---
.../AbstractRowsEventDataDeserializer.java | 20 +++++++++++++++++++
.../deserialization/EventDeserializer.java | 9 ++++++++-
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
index 0b2ac624..7b910da4 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
@@ -75,6 +75,7 @@ public abstract class AbstractRowsEventDataDeserializer imp
private Long invalidDateAndTimeRepresentation;
private boolean microsecondsPrecision;
private boolean deserializeCharAndBinaryAsByteArray;
+ private boolean deserializeIntegerAsByteArray;
public AbstractRowsEventDataDeserializer(Map tableMapEventByTableId) {
this.tableMapEventByTableId = tableMapEventByTableId;
@@ -97,6 +98,10 @@ void setDeserializeCharAndBinaryAsByteArray(boolean value) {
this.deserializeCharAndBinaryAsByteArray = value;
}
+ void setDeserializeIntegerAsByteArray(boolean deserializeIntegerAsByteArray) {
+ this.deserializeIntegerAsByteArray = deserializeIntegerAsByteArray;
+ }
+
protected Serializable[] deserializeRow(long tableId, BitSet includedColumns, ByteArrayInputStream inputStream)
throws IOException {
TableMapEventData tableMapEvent = tableMapEventByTableId.get(tableId);
@@ -203,22 +208,37 @@ protected Serializable deserializeBit(int meta, ByteArrayInputStream inputStream
}
protected Serializable deserializeTiny(ByteArrayInputStream inputStream) throws IOException {
+ if (deserializeIntegerAsByteArray) {
+ return inputStream.read(1);
+ }
return (int) ((byte) inputStream.readInteger(1));
}
protected Serializable deserializeShort(ByteArrayInputStream inputStream) throws IOException {
+ if (deserializeIntegerAsByteArray) {
+ return inputStream.read(2);
+ }
return (int) ((short) inputStream.readInteger(2));
}
protected Serializable deserializeInt24(ByteArrayInputStream inputStream) throws IOException {
+ if (deserializeIntegerAsByteArray) {
+ return inputStream.read(3);
+ }
return (inputStream.readInteger(3) << 8) >> 8;
}
protected Serializable deserializeLong(ByteArrayInputStream inputStream) throws IOException {
+ if (deserializeIntegerAsByteArray) {
+ return inputStream.read(4);
+ }
return inputStream.readInteger(4);
}
protected Serializable deserializeLongLong(ByteArrayInputStream inputStream) throws IOException {
+ if (deserializeIntegerAsByteArray) {
+ return inputStream.read(8);
+ }
return inputStream.readLong(8);
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
index d623d943..fbec7c38 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
@@ -200,6 +200,9 @@ private void ensureCompatibility(EventDataDeserializer eventDataDeserializer) {
deserializer.setDeserializeCharAndBinaryAsByteArray(
compatibilitySet.contains(CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY)
);
+ deserializer.setDeserializeIntegerAsByteArray(
+ compatibilitySet.contains(CompatibilityMode.INTEGER_AS_BYTE_ARRAY)
+ );
}
}
@@ -350,7 +353,11 @@ public enum CompatibilityMode {
*
*
This option is going to be enabled by default starting from mysql-binlog-connector-java@1.0.0.
*/
- CHAR_AND_BINARY_AS_BYTE_ARRAY
+ CHAR_AND_BINARY_AS_BYTE_ARRAY,
+ /**
+ * Return TINY/SHORT/INT24/LONG/LONGLONG values as byte[]|s (instead of int|s).
+ */
+ INTEGER_AS_BYTE_ARRAY
}
/**
From 09e9e64cb29c41dd8dca1148a37e06e9e45b4d10 Mon Sep 17 00:00:00 2001
From: zzt
Date: Sun, 25 Oct 2020 15:05:17 +0800
Subject: [PATCH 060/217] add testDeserializationOfIntegerAsByteArray in
BinaryLogClientIntegrationTest.
---
.../BinaryLogClientIntegrationTest.java | 38 +++++++++++++++++++
src/test/onetimeserver | 6 +--
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index aa81b588..44bb2fa5 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -421,6 +421,44 @@ public void testDeserializationOfDateAndTimeAsLong() throws Exception {
}
}
+ @Test
+ public void testDeserializationOfIntegerAsByteArray() throws Exception {
+ final BinaryLogClient client = new BinaryLogClient(slave.hostname, slave.port,
+ slave.username, slave.password);
+ EventDeserializer eventDeserializer = new EventDeserializer();
+ eventDeserializer.setCompatibilityMode(CompatibilityMode.INTEGER_AS_BYTE_ARRAY);
+ client.setEventDeserializer(eventDeserializer);
+ client.connect(DEFAULT_TIMEOUT);
+ try {
+ assertEquals(writeAndCaptureRow("tinyint unsigned", "0", "1", "255"),
+ new Serializable[]{new byte[]{0}, new byte[]{1}, new byte[]{-1}});
+ assertEquals(writeAndCaptureRow("tinyint", "-128", "-1", "0", "1", "127"),
+ new Serializable[]{new byte[]{-0x80}, new byte[]{-1}, new byte[]{0}, new byte[]{1}, new byte[]{0x7f}});
+
+ assertEquals(writeAndCaptureRow("smallint unsigned", "0", "1", "65535"),
+ new Serializable[]{new byte[]{0, 0}, new byte[]{0, 1}, new byte[]{-1, -1}});
+ assertEquals(writeAndCaptureRow("smallint", "-32768", "-1", "0", "1", "32767"),
+ new Serializable[]{new byte[]{-0x80, 0}, new byte[]{-1, -1}, new byte[]{0, 0}, new byte[]{0, 1}, new byte[]{0x7f, -1}});
+
+ assertEquals(writeAndCaptureRow("mediumint unsigned", "0", "1", "16777215"),
+ new Serializable[]{new byte[]{0, 0, 0}, new byte[]{0, 0, 1}, new byte[]{-1, -1, -1}});
+ assertEquals(writeAndCaptureRow("mediumint", "-8388608", "-1", "0", "1", "8388607"),
+ new Serializable[]{new byte[]{-0x80, 0, 0}, new byte[]{-1, -1, -1}, new byte[]{0, 0, 0}, new byte[]{0, 0, 1}, new byte[]{0x7f, -1, -1}});
+
+ assertEquals(writeAndCaptureRow("int unsigned", "0", "1", "4294967295"),
+ new Serializable[]{new byte[]{0, 0, 0, 0}, new byte[]{0, 0, 0, 1}, new byte[]{-1, -1, -1, -1}});
+ assertEquals(writeAndCaptureRow("int", "-2147483648", "-1", "0", "1", "2147483647"),
+ new Serializable[]{new byte[]{-0x80, 0, 0, 0}, new byte[]{-1, -1, -1, -1}, new byte[]{0, 0, 0, 0}, new byte[]{0, 0, 0, 1}, new byte[]{0x7f, -1, -1, -1}});
+
+ assertEquals(writeAndCaptureRow("bigint unsigned", "0", "1", "18446744073709551615"),
+ new Serializable[]{new byte[]{0, 0, 0, 0, 0, 0, 0, 0}, new byte[]{0, 0, 0, 0, 0, 0, 0, 1}, new byte[]{-1, -1, -1, -1, -1, -1, -1, -1}});
+ assertEquals(writeAndCaptureRow("bigint", "-9223372036854775808", "-1", "0", "1", "9223372036854775807"),
+ new Serializable[]{new byte[]{-0x80, 0, 0, 0, 0, 0, 0, 0}, new byte[]{-1, -1, -1, -1, -1, -1, -1, -1}, new byte[]{0, 0, 0, 0, 0, 0, 0, 0}, new byte[]{0, 0, 0, 0, 0, 0, 0, 1}, new byte[]{0x7f, -1, -1, -1, -1, -1, -1, -1}});
+ } finally {
+ client.disconnect();
+ }
+ }
+
@Test
public void testDeserializationOfDateAndTimeAsLongMicrosecondsPrecision() throws Exception {
final BinaryLogClient client = new BinaryLogClient(slave.hostname, slave.port,
diff --git a/src/test/onetimeserver b/src/test/onetimeserver
index a240a9c9..cbf8a2f2 100755
--- a/src/test/onetimeserver
+++ b/src/test/onetimeserver
@@ -5,9 +5,9 @@ PLATFORM=${_PLATFORM/ /-}
OS=`uname -s | tr '[:upper:]' '[:lower:]'`
-THIS_URL="https://raw.githubusercontent.com/osheroff/onetimeserver/master/onetimeserver"
-WRAPPER_URL="https://raw.githubusercontent.com/osheroff/onetimeserver/master/wrapper/wrapper.c"
-ONETIMESERVER_URL="https://raw.githubusercontent.com/osheroff/onetimeserver-binaries/master/onetimeserver-go/$OS/onetimeserver-go"
+THIS_URL="https://gitee.com/zengzetang/onetimeserver/raw/master/onetimeserver"
+WRAPPER_URL="https://gitee.com/zengzetang/onetimeserver/raw/master/wrapper/wrapper.c"
+ONETIMESERVER_URL="http://localhost:8888/Desktop/onetimeserver-go.txt"
CACHE_DIR=$HOME/.onetimeserver/$PLATFORM
function usage() {
From 45586e8a8183dc0d95b645e65f09fb2c4b2ade3a Mon Sep 17 00:00:00 2001
From: zzt
Date: Sun, 25 Oct 2020 15:06:51 +0800
Subject: [PATCH 061/217] recover onetimeserver script.
---
src/test/onetimeserver | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/test/onetimeserver b/src/test/onetimeserver
index cbf8a2f2..a240a9c9 100755
--- a/src/test/onetimeserver
+++ b/src/test/onetimeserver
@@ -5,9 +5,9 @@ PLATFORM=${_PLATFORM/ /-}
OS=`uname -s | tr '[:upper:]' '[:lower:]'`
-THIS_URL="https://gitee.com/zengzetang/onetimeserver/raw/master/onetimeserver"
-WRAPPER_URL="https://gitee.com/zengzetang/onetimeserver/raw/master/wrapper/wrapper.c"
-ONETIMESERVER_URL="http://localhost:8888/Desktop/onetimeserver-go.txt"
+THIS_URL="https://raw.githubusercontent.com/osheroff/onetimeserver/master/onetimeserver"
+WRAPPER_URL="https://raw.githubusercontent.com/osheroff/onetimeserver/master/wrapper/wrapper.c"
+ONETIMESERVER_URL="https://raw.githubusercontent.com/osheroff/onetimeserver-binaries/master/onetimeserver-go/$OS/onetimeserver-go"
CACHE_DIR=$HOME/.onetimeserver/$PLATFORM
function usage() {
From 9e2fb39d2d7c1b4a4833beea5aa351894cdc84cf Mon Sep 17 00:00:00 2001
From: Sergei Morozov
Date: Tue, 27 Oct 2020 13:30:24 -0700
Subject: [PATCH 062/217] DBZ-2499: Debezium Connectors are failing while
reading binlog: Unknown event type 100
---
.../EventHeaderV4Deserializer.java | 4 +--
.../BinaryLogFileReaderIntegrationTest.java | 31 ++++++++++++++++++
src/test/resources/mysql-bin.aurora-padding | Bin 0 -> 1294 bytes
3 files changed, 33 insertions(+), 2 deletions(-)
create mode 100644 src/test/resources/mysql-bin.aurora-padding
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventHeaderV4Deserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventHeaderV4Deserializer.java
index 2d8bcdd8..c0569f09 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventHeaderV4Deserializer.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventHeaderV4Deserializer.java
@@ -40,9 +40,9 @@ public EventHeaderV4 deserialize(ByteArrayInputStream inputStream) throws IOExce
return header;
}
- private static EventType getEventType(int ordinal) throws IOException {
+ private static EventType getEventType(int ordinal) {
if (ordinal >= EVENT_TYPES.length) {
- throw new IOException("Unknown event type " + ordinal);
+ return EventType.UNKNOWN;
}
return EVENT_TYPES[ordinal];
}
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogFileReaderIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogFileReaderIntegrationTest.java
index cbf523a6..ef9eca57 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogFileReaderIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogFileReaderIntegrationTest.java
@@ -30,6 +30,7 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
@@ -70,6 +71,36 @@ public void testChecksumCRC32WithCustomEventDataDeserializer() throws Exception
readAll(reader, 303);
}
+ @Test
+ public void testUnsupportedEventType() throws Exception {
+ EventDeserializer eventDeserializer = new EventDeserializer();
+
+ // mysql> SHOW BINLOG EVENTS IN 'mysql-bin.aurora-padding';
+ // +--------------------------+------+----------------+-------------+---------------------------------------+
+ // | Log_name | Pos | Event_type | End_log_pos | Info |
+ // +--------------------------+------+----------------+-------------+---------------------------------------+
+ // | mysql-bin.aurora-padding | 4 | Format_desc | 185 | Server ver: 5.7.12-log, Binlog ver: 4 |
+ // | mysql-bin.aurora-padding | 185 | Previous_gtids | 216 | |
+ // | mysql-bin.aurora-padding | 216 | Anonymous_Gtid | 281 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
+ // | mysql-bin.aurora-padding | 281 | Aurora_padding | 1209 | Ignorable |
+ // | mysql-bin.aurora-padding | 1209 | Query | 1294 | BEGIN |
+ BinaryLogFileReader reader = new BinaryLogFileReader(
+ new FileInputStream("src/test/resources/mysql-bin.aurora-padding"), eventDeserializer);
+ try {
+ for (int i = 0; i < 3; i++) {
+ assertNotNull(reader.readEvent());
+ }
+ try {
+ reader.readEvent();
+ } catch (IOException e) {
+ // this simulates the Debezium's event.processing.failure.handling.mode = warn
+ }
+ assertEquals(reader.readEvent().getHeader().getEventType(), EventType.QUERY);
+ } finally {
+ reader.close();
+ }
+ }
+
private void readAll(BinaryLogFileReader reader, int expect) throws IOException {
try {
int numberOfEvents = 0;
diff --git a/src/test/resources/mysql-bin.aurora-padding b/src/test/resources/mysql-bin.aurora-padding
new file mode 100644
index 0000000000000000000000000000000000000000..688b51b2c9b31f157f40c768366da58da03e4dd9
GIT binary patch
literal 1294
zcmeyDl$p0eeNsHX0CybMRt5%!oj}aMz`|gvXRc>xq??nU4i+Gi5VqiD;9wA9U;zRl
z28Ou|EK(dmtsER2OhAf@i%Uz3LC6Fof@UBKlpmj&l$IUOz+eRBv!ba3aT)*U{}TW?
zS{dYMd7#J*AZ`F+2sl3Z$4ij35=hz+C??4Wk^mDB6{sZB%WR0i7bt!ES!DpofE17c
z3z&g{0(4#jgVrb*4S~@R82AwQJ?~I3D1S16@@FV8@A3hQ2@Zyh_aA`sI41*x5+p-|
uxDFsD8*_0<3X3ko1E4Ziw&2L%5Le%nr1-qll7hra1}9f{Pe0issn!6j|H|k9
literal 0
HcmV?d00001
From 712ce17320e1b4d4556d511289fecbe7ad2ec3e6 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Thu, 29 Oct 2020 15:32:36 -0700
Subject: [PATCH 063/217] fix tests
---
.../BinaryLogClientIntegrationTest.java | 55 +++++++++++--------
1 file changed, 31 insertions(+), 24 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
index 44bb2fa5..8d813793 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientIntegrationTest.java
@@ -430,30 +430,37 @@ public void testDeserializationOfIntegerAsByteArray() throws Exception {
client.setEventDeserializer(eventDeserializer);
client.connect(DEFAULT_TIMEOUT);
try {
- assertEquals(writeAndCaptureRow("tinyint unsigned", "0", "1", "255"),
- new Serializable[]{new byte[]{0}, new byte[]{1}, new byte[]{-1}});
- assertEquals(writeAndCaptureRow("tinyint", "-128", "-1", "0", "1", "127"),
- new Serializable[]{new byte[]{-0x80}, new byte[]{-1}, new byte[]{0}, new byte[]{1}, new byte[]{0x7f}});
-
- assertEquals(writeAndCaptureRow("smallint unsigned", "0", "1", "65535"),
- new Serializable[]{new byte[]{0, 0}, new byte[]{0, 1}, new byte[]{-1, -1}});
- assertEquals(writeAndCaptureRow("smallint", "-32768", "-1", "0", "1", "32767"),
- new Serializable[]{new byte[]{-0x80, 0}, new byte[]{-1, -1}, new byte[]{0, 0}, new byte[]{0, 1}, new byte[]{0x7f, -1}});
-
- assertEquals(writeAndCaptureRow("mediumint unsigned", "0", "1", "16777215"),
- new Serializable[]{new byte[]{0, 0, 0}, new byte[]{0, 0, 1}, new byte[]{-1, -1, -1}});
- assertEquals(writeAndCaptureRow("mediumint", "-8388608", "-1", "0", "1", "8388607"),
- new Serializable[]{new byte[]{-0x80, 0, 0}, new byte[]{-1, -1, -1}, new byte[]{0, 0, 0}, new byte[]{0, 0, 1}, new byte[]{0x7f, -1, -1}});
-
- assertEquals(writeAndCaptureRow("int unsigned", "0", "1", "4294967295"),
- new Serializable[]{new byte[]{0, 0, 0, 0}, new byte[]{0, 0, 0, 1}, new byte[]{-1, -1, -1, -1}});
- assertEquals(writeAndCaptureRow("int", "-2147483648", "-1", "0", "1", "2147483647"),
- new Serializable[]{new byte[]{-0x80, 0, 0, 0}, new byte[]{-1, -1, -1, -1}, new byte[]{0, 0, 0, 0}, new byte[]{0, 0, 0, 1}, new byte[]{0x7f, -1, -1, -1}});
-
- assertEquals(writeAndCaptureRow("bigint unsigned", "0", "1", "18446744073709551615"),
- new Serializable[]{new byte[]{0, 0, 0, 0, 0, 0, 0, 0}, new byte[]{0, 0, 0, 0, 0, 0, 0, 1}, new byte[]{-1, -1, -1, -1, -1, -1, -1, -1}});
- assertEquals(writeAndCaptureRow("bigint", "-9223372036854775808", "-1", "0", "1", "9223372036854775807"),
- new Serializable[]{new byte[]{-0x80, 0, 0, 0, 0, 0, 0, 0}, new byte[]{-1, -1, -1, -1, -1, -1, -1, -1}, new byte[]{0, 0, 0, 0, 0, 0, 0, 0}, new byte[]{0, 0, 0, 0, 0, 0, 0, 1}, new byte[]{0x7f, -1, -1, -1, -1, -1, -1, -1}});
+ Serializable[] result;
+
+ result = writeAndCaptureRow("tinyint unsigned", "0", "1", "255");
+ assertEquals(result[0], 0);
+ assertEquals(result[1], 1);
+ assertEquals(result[2], -1);
+
+
+ result = writeAndCaptureRow("tinyint", "-128", "-1", "0", "1", "127");
+ assertEquals(result[0], -128);
+ assertEquals(result[1], -1);
+ assertEquals(result[2], 0);
+ assertEquals(result[3], 1);
+ assertEquals(result[4], 127);
+
+ result = writeAndCaptureRow("smallint unsigned", "0", "1", "65535");
+ assertEquals(result[0], 0);
+ assertEquals(result[1], 1);
+ assertEquals(result[2], -1);
+
+ result = writeAndCaptureRow("smallint", "-32768", "-1", "0", "1", "32767");
+ assertEquals(result[0], -32768);
+ assertEquals(result[1], -1);
+ assertEquals(result[2], 0);
+ assertEquals(result[3], 1);
+ assertEquals(result[4], 32767);
+
+ result = writeAndCaptureRow("mediumint unsigned", "0", "1", "16777215");
+ assertEquals(result[0], 0);
+ assertEquals(result[1], 1);
+ assertEquals(result[2], -1);
} finally {
client.disconnect();
}
From b4aaed26c927f2a866e9b7d13badb9f3ab01c41b Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Thu, 29 Oct 2020 15:48:32 -0700
Subject: [PATCH 064/217] v0.23.3
---
CHANGELOG.md | 13 +++++++++++++
pom.xml | 2 +-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ba26f3c..68943c40 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## [0.23.3](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.23.2...0.23.3) - 2020-10-29
+
+- add EventDeserializer.CompatibilityMode.INTEGER_AS_BYTE_ARRAY if you want raw integer data
+- don't crash on AWS Aurora's unknown event types
+
+## [0.23.2](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.23.1...0.23.2) - 2020-07-25
+
+- `connect` now throws `IllegalStateException` when already connected
+
+## [0.23.1](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.22.2...0.23.1) - 2020-05-25
+
+- this releases adds support for mysql 8's `caching_sha2_password` authentication method
+
## [0.22.2](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.22.0...0.22.2) - 2020-04-29
- Fix bugs in 0.22.0 involving nested JSON objects.
diff --git a/pom.xml b/pom.xml
index c8769558..2d6d2bea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.23.2
+ 0.23.3mysql-binlog-connector-javaMySQL Binary Log connector
From a0a65cdd86a2ee0d6dee015a6062e9607b1cd3ae Mon Sep 17 00:00:00 2001
From: Gil Cottle
Date: Fri, 15 Jan 2021 22:29:05 -0800
Subject: [PATCH 065/217] Add Auth Plugin Name to for native password auth to
fix Azure connections
PLUGIN_AUTH is listed as one of the capabilities and connections to Azure MySQL require the Auth Plugin Name to be specified when that capability is present. If it is not there, Azure MySQL instances respond with "The connection string may not be right. Please visit portal for references.".
See https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse and https://github.com/osheroff/mysql-binlog-connector-java/issues/26 for more details about the investigation.
---
.../protocol/command/AuthenticateSecurityPasswordCommand.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
index ea3dfc53..de93da45 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
@@ -77,6 +77,7 @@ public byte[] toByteArray() throws IOException {
if (schema != null) {
buffer.writeZeroTerminatedString(schema);
}
+ buffer.writeZeroTerminatedString("mysql_native_password");
return buffer.toByteArray();
}
From ed9336a49ee96862a6ab923dbf84b0b1015df7e2 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Sun, 17 Jan 2021 10:06:17 -0800
Subject: [PATCH 066/217] v0.23.4
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 2d6d2bea..916fc616 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.23.3
+ 0.23.4mysql-binlog-connector-javaMySQL Binary Log connector
From fc2da16ec801def74680d63d780b1da7edef050d Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Thu, 21 Jan 2021 22:09:41 -0800
Subject: [PATCH 067/217] wip: new tls verifier so we can upgrade to jvm 11
---
pom.xml | 13 +-
.../mysql/binlog/network/HostnameChecker.java | 568 ++++++++++++++++++
.../binlog/network/TLSHostnameVerifier.java | 10 +-
.../mysql/binlog/BinaryLogClientTest.java | 4 +-
4 files changed, 581 insertions(+), 14 deletions(-)
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
diff --git a/pom.xml b/pom.xml
index 916fc616..a21feffa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.23.4
+ 0.23.4-SNAPSHOTmysql-binlog-connector-javaMySQL Binary Log connector
@@ -228,17 +228,18 @@
org.apache.maven.pluginsmaven-javadoc-plugin
- 2.10.4
+ 3.2.0
+
+ buar
+ -J--add-exports
+ -Jjava.base/sun.security.util=ALL-UNNAMED
+ attach-javadocsjar
-
- -Xdoclint:none
- true
-
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java b/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
new file mode 100644
index 00000000..86b73aed
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
@@ -0,0 +1,568 @@
+/*
+ * $HeadURL: file:///opt/dev/not-yet-commons-ssl-SVN-repo/tags/commons-ssl-0.3.17/src/java/org/apache/commons/ssl/HostnameVerifier.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+/*
+ * after looking around the landscape of java verifying a certificate hostname, the best I found
+ * was to copy and paste from https://github.com/narupley/not-going-to-be-commons-ssl/blob/master/src/main/java/org/apache/commons/ssl/Certificates.java
+ *
+ * given that it seems like it's never going to be maintained upstream...
+ * is it bad? time will tell.
+ */
+
+package com.github.shyiko.mysql.binlog.network;
+
+import javax.naming.InvalidNameException;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.security.auth.x500.X500Principal;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.TreeSet;
+
+/**
+ * Interface for checking if a hostname matches the names stored inside the
+ * server's X.509 certificate. Correctly implements
+ * javax.net.ssl.HostnameVerifier, but that interface is not recommended.
+ * Instead we added several check() methods that take SSLSocket,
+ * or X509Certificate, or ultimately (they all end up calling this one),
+ * String. (It's easier to supply JUnit with Strings instead of mock
+ * SSLSession objects!)
+ *
Our check() methods throw exceptions if the name is
+ * invalid, whereas javax.net.ssl.HostnameVerifier just returns true/false.
+ *
+ * We provide the HostnameVerifier.DEFAULT, HostnameVerifier.STRICT, and
+ * HostnameVerifier.ALLOW_ALL implementations. We also provide the more
+ * specialized HostnameVerifier.DEFAULT_AND_LOCALHOST, as well as
+ * HostnameVerifier.STRICT_IE6. But feel free to define your own
+ * implementations!
+ *
+ * Inspired by Sebastian Hauer's original StrictSSLProtocolSocketFactory in the
+ * HttpClient "contrib" repository.
+ *
+ * @author Julius Davies
+ * @author Sebastian Hauer
+ * @since 8-Dec-2006
+ */
+public interface HostnameChecker extends javax.net.ssl.HostnameVerifier {
+
+ boolean verify(String host, SSLSession session);
+
+ void check(String host, SSLSocket ssl) throws IOException;
+
+ void check(String host, X509Certificate cert) throws SSLException;
+
+ void check(String host, String[] cns, String[] subjectAlts)
+ throws SSLException;
+
+ void check(String[] hosts, SSLSocket ssl) throws IOException;
+
+ void check(String[] hosts, X509Certificate cert) throws SSLException;
+
+
+ /**
+ * Checks to see if the supplied hostname matches any of the supplied CNs
+ * or "DNS" Subject-Alts. Most implementations only look at the first CN,
+ * and ignore any additional CNs. Most implementations do look at all of
+ * the "DNS" Subject-Alts. The CNs or Subject-Alts may contain wildcards
+ * according to RFC 2818.
+ *
+ * @param cns CN fields, in order, as extracted from the X.509
+ * certificate.
+ * @param subjectAlts Subject-Alt fields of type 2 ("DNS"), as extracted
+ * from the X.509 certificate.
+ * @param hosts The array of hostnames to verify.
+ * @throws SSLException If verification failed.
+ */
+ void check(String[] hosts, String[] cns, String[] subjectAlts)
+ throws SSLException;
+
+
+ /**
+ * The DEFAULT HostnameVerifier works the same way as Curl and Firefox.
+ *
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts.
+ *
+ * The only difference between DEFAULT and STRICT is that a wildcard (such
+ * as "*.foo.com") with DEFAULT matches all subdomains, including
+ * "a.b.foo.com".
+ */
+ public final static HostnameChecker DEFAULT =
+ new AbstractChecker() {
+ public final void check(final String[] hosts, final String[] cns,
+ final String[] subjectAlts)
+ throws SSLException {
+ check(hosts, cns, subjectAlts, false, false);
+ }
+
+ public final String toString() { return "DEFAULT"; }
+ };
+
+
+ /**
+ * The DEFAULT_AND_LOCALHOST HostnameVerifier works like the DEFAULT
+ * one with one additional relaxation: a host of "localhost",
+ * "localhost.localdomain", "127.0.0.1", "::1" will always pass, no matter
+ * what is in the server's certificate.
+ */
+ public final static HostnameChecker DEFAULT_AND_LOCALHOST =
+ new AbstractChecker() {
+ public final void check(final String[] hosts, final String[] cns,
+ final String[] subjectAlts)
+ throws SSLException {
+ if (isLocalhost(hosts[0])) {
+ return;
+ }
+ check(hosts, cns, subjectAlts, false, false);
+ }
+
+ public final String toString() { return "DEFAULT_AND_LOCALHOST"; }
+ };
+
+ /**
+ * The STRICT HostnameVerifier works the same way as java.net.URL in Sun
+ * Java 1.4, Sun Java 5, Sun Java 6. It's also pretty close to IE6.
+ * This implementation appears to be compliant with RFC 2818 for dealing
+ * with wildcards.
+ *
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts. The
+ * one divergence from IE6 is how we only check the first CN. IE6 allows
+ * a match against any of the CNs present. We decided to follow in
+ * Sun Java 1.4's footsteps and only check the first CN.
+ *
+ * A wildcard such as "*.foo.com" matches only subdomains in the same
+ * level, for example "a.foo.com". It does not match deeper subdomains
+ * such as "a.b.foo.com".
+ */
+ public final static HostnameChecker STRICT =
+ new AbstractChecker() {
+ public final void check(final String[] host, final String[] cns,
+ final String[] subjectAlts)
+ throws SSLException {
+ check(host, cns, subjectAlts, false, true);
+ }
+
+ public final String toString() { return "STRICT"; }
+ };
+
+ /**
+ * The STRICT_IE6 HostnameVerifier works just like the STRICT one with one
+ * minor variation: the hostname can match against any of the CN's in the
+ * server's certificate, not just the first one. This behaviour is
+ * identical to IE6's behaviour.
+ */
+ public final static HostnameChecker STRICT_IE6 =
+ new AbstractChecker() {
+ public final void check(final String[] host, final String[] cns,
+ final String[] subjectAlts)
+ throws SSLException {
+ check(host, cns, subjectAlts, true, true);
+ }
+
+ public final String toString() { return "STRICT_IE6"; }
+ };
+
+ /**
+ * The ALLOW_ALL HostnameVerifier essentially turns hostname verification
+ * off. This implementation is a no-op, and never throws the SSLException.
+ */
+ public final static HostnameChecker ALLOW_ALL =
+ new AbstractChecker() {
+ public final void check(final String[] host, final String[] cns,
+ final String[] subjectAlts) {
+ // Allow everything - so never blowup.
+ }
+
+ public final String toString() { return "ALLOW_ALL"; }
+ };
+
+ abstract class AbstractChecker implements HostnameChecker {
+ public static String[] getCNs(X509Certificate cert) {
+ try {
+ final String subjectPrincipal = cert.getSubjectX500Principal().getName(X500Principal.RFC2253);
+ final LinkedList cnList = new LinkedList();
+ final LdapName subjectDN = new LdapName(subjectPrincipal);
+ for (final Rdn rds : subjectDN.getRdns()) {
+ final Attributes attributes = rds.toAttributes();
+ final Attribute cn = attributes.get("cn");
+ if (cn != null) {
+ try {
+ final Object value = cn.get();
+ if (value != null) {
+ cnList.add(value.toString());
+ }
+ } catch (NoSuchElementException ignore) {
+ } catch (NamingException ignore) {
+ }
+ }
+ }
+ if (!cnList.isEmpty()) {
+ return cnList.toArray(new String[cnList.size()]);
+ }
+ } catch (InvalidNameException ignore) {
+ }
+ return null;
+ }
+
+ /**
+ * Extracts the array of SubjectAlt DNS names from an X509Certificate.
+ * Returns null if there aren't any.
+ *
+ * Note: Java doesn't appear able to extract international characters
+ * from the SubjectAlts. It can only extract international characters
+ * from the CN field.
+ *
+ * (Or maybe the version of OpenSSL I'm using to test isn't storing the
+ * international characters correctly in the SubjectAlts?).
+ *
+ * @param cert X509Certificate
+ * @return Array of SubjectALT DNS names stored in the certificate.
+ */
+ public static String[] getDNSSubjectAlts(X509Certificate cert) {
+ LinkedList subjectAltList = new LinkedList();
+ Collection c = null;
+ try {
+ c = cert.getSubjectAlternativeNames();
+ }
+ catch (Exception cpe) { }
+ if (c != null) {
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ List list = (List) it.next();
+ int type = ((Integer) list.get(0)).intValue();
+ // If type is 2, then we've got a dNSName
+ if (type == 2) {
+ String s = (String) list.get(1);
+ subjectAltList.add(s);
+ }
+ }
+ }
+ if (!subjectAltList.isEmpty()) {
+ String[] subjectAlts = new String[subjectAltList.size()];
+ subjectAltList.toArray(subjectAlts);
+ return subjectAlts;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * This contains a list of 2nd-level domains that aren't allowed to
+ * have wildcards when combined with country-codes.
+ * For example: [*.co.uk].
+ *
+ * The [*.co.uk] problem is an interesting one. Should we just hope
+ * that CA's would never foolishly allow such a certificate to happen?
+ * Looks like we're the only implementation guarding against this.
+ * Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
+ */
+ private final static String[] BAD_COUNTRY_2LDS =
+ {"ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
+ "lg", "ne", "net", "or", "org"};
+
+ private final static String[] LOCALHOSTS = {"::1", "127.0.0.1",
+ "localhost",
+ "localhost.localdomain"};
+
+
+ static {
+ // Just in case developer forgot to manually sort the array. :-)
+ Arrays.sort(BAD_COUNTRY_2LDS);
+ Arrays.sort(LOCALHOSTS);
+ }
+
+ protected AbstractChecker() {}
+
+ /**
+ * The javax.net.ssl.HostnameVerifier contract.
+ *
+ * @param host 'hostname' we used to create our socket
+ * @param session SSLSession with the remote server
+ * @return true if the host matched the one in the certificate.
+ */
+ public boolean verify(String host, SSLSession session) {
+ try {
+ Certificate[] certs = session.getPeerCertificates();
+ X509Certificate x509 = (X509Certificate) certs[0];
+ check(new String[]{host}, x509);
+ return true;
+ }
+ catch (SSLException e) {
+ return false;
+ }
+ }
+
+ public void check(String host, SSLSocket ssl) throws IOException {
+ check(new String[]{host}, ssl);
+ }
+
+ public void check(String host, X509Certificate cert)
+ throws SSLException {
+ check(new String[]{host}, cert);
+ }
+
+ public void check(String host, String[] cns, String[] subjectAlts)
+ throws SSLException {
+ check(new String[]{host}, cns, subjectAlts);
+ }
+
+ public void check(String host[], SSLSocket ssl)
+ throws IOException {
+ if (host == null) {
+ throw new NullPointerException("host to verify is null");
+ }
+
+ SSLSession session = ssl.getSession();
+ if (session == null) {
+ // In our experience this only happens under IBM 1.4.x when
+ // spurious (unrelated) certificates show up in the server'
+ // chain. Hopefully this will unearth the real problem:
+ InputStream in = ssl.getInputStream();
+ in.available();
+ /*
+ If you're looking at the 2 lines of code above because
+ you're running into a problem, you probably have two
+ options:
+
+ #1. Clean up the certificate chain that your server
+ is presenting (e.g. edit "/etc/apache2/server.crt"
+ or wherever it is your server's certificate chain
+ is defined).
+
+ OR
+
+ #2. Upgrade to an IBM 1.5.x or greater JVM, or switch
+ to a non-IBM JVM.
+ */
+
+ // If ssl.getInputStream().available() didn't cause an
+ // exception, maybe at least now the session is available?
+ session = ssl.getSession();
+ if (session == null) {
+ // If it's still null, probably a startHandshake() will
+ // unearth the real problem.
+ ssl.startHandshake();
+
+ // Okay, if we still haven't managed to cause an exception,
+ // might as well go for the NPE. Or maybe we're okay now?
+ session = ssl.getSession();
+ }
+ }
+ Certificate[] certs;
+ try {
+ certs = session.getPeerCertificates();
+ } catch (SSLPeerUnverifiedException spue) {
+ InputStream in = ssl.getInputStream();
+ in.available();
+ // Didn't trigger anything interesting? Okay, just throw
+ // original.
+ throw spue;
+ }
+ X509Certificate x509 = (X509Certificate) certs[0];
+ check(host, x509);
+ }
+
+ public void check(String[] host, X509Certificate cert)
+ throws SSLException {
+ String[] cns = AbstractChecker.getCNs(cert);
+ String[] subjectAlts = AbstractChecker.getDNSSubjectAlts(cert);
+ check(host, cns, subjectAlts);
+ }
+
+ public void check(final String[] hosts, final String[] cns,
+ final String[] subjectAlts, final boolean ie6,
+ final boolean strictWithSubDomains)
+ throws SSLException {
+ // Build up lists of allowed hosts For logging/debugging purposes.
+ StringBuffer buf = new StringBuffer(32);
+ buf.append('<');
+ for (int i = 0; i < hosts.length; i++) {
+ String h = hosts[i];
+ h = h != null ? h.trim().toLowerCase() : "";
+ hosts[i] = h;
+ if (i > 0) {
+ buf.append('/');
+ }
+ buf.append(h);
+ }
+ buf.append('>');
+ String hostnames = buf.toString();
+ // Build the list of names we're going to check. Our DEFAULT and
+ // STRICT implementations of the HostnameVerifier only use the
+ // first CN provided. All other CNs are ignored.
+ // (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way).
+ TreeSet names = new TreeSet();
+ if (cns != null && cns.length > 0 && cns[0] != null) {
+ names.add(cns[0]);
+ if (ie6) {
+ for (int i = 1; i < cns.length; i++) {
+ names.add(cns[i]);
+ }
+ }
+ }
+ if (subjectAlts != null) {
+ for (int i = 0; i < subjectAlts.length; i++) {
+ if (subjectAlts[i] != null) {
+ names.add(subjectAlts[i]);
+ }
+ }
+ }
+ if (names.isEmpty()) {
+ String msg = "Certificate for " + hosts[0] + " doesn't contain CN or DNS subjectAlt";
+ throw new SSLException(msg);
+ }
+
+ // StringBuffer for building the error message.
+ buf = new StringBuffer();
+
+ boolean match = false;
+ out:
+ for (Iterator it = names.iterator(); it.hasNext();) {
+ // Don't trim the CN, though!
+ String cn = (String) it.next();
+ cn = cn.toLowerCase();
+ // Store CN in StringBuffer in case we need to report an error.
+ buf.append(" <");
+ buf.append(cn);
+ buf.append('>');
+ if (it.hasNext()) {
+ buf.append(" OR");
+ }
+
+ // The CN better have at least two dots if it wants wildcard
+ // action. It also can't be [*.co.uk] or [*.co.jp] or
+ // [*.org.uk], etc...
+ boolean doWildcard = cn.startsWith("*.") &&
+ cn.lastIndexOf('.') >= 0 &&
+ !isIP4Address(cn) &&
+ acceptableCountryWildcard(cn);
+
+ for (int i = 0; i < hosts.length; i++) {
+ final String hostName = hosts[i].trim().toLowerCase();
+ if (doWildcard) {
+ match = hostName.endsWith(cn.substring(1));
+ if (match && strictWithSubDomains) {
+ // If we're in strict mode, then [*.foo.com] is not
+ // allowed to match [a.b.foo.com]
+ match = countDots(hostName) == countDots(cn);
+ }
+ } else {
+ match = hostName.equals(cn);
+ }
+ if (match) {
+ break out;
+ }
+ }
+ }
+ if (!match) {
+ throw new SSLException("hostname in certificate didn't match: " + hostnames + " !=" + buf);
+ }
+ }
+
+ public static boolean isIP4Address(final String cn) {
+ boolean isIP4 = true;
+ String tld = cn;
+ int x = cn.lastIndexOf('.');
+ // We only bother analyzing the characters after the final dot
+ // in the name.
+ if (x >= 0 && x + 1 < cn.length()) {
+ tld = cn.substring(x + 1);
+ }
+ for (int i = 0; i < tld.length(); i++) {
+ if (!Character.isDigit(tld.charAt(0))) {
+ isIP4 = false;
+ break;
+ }
+ }
+ return isIP4;
+ }
+
+ public static boolean acceptableCountryWildcard(final String cn) {
+ int cnLen = cn.length();
+ if (cnLen >= 7 && cnLen <= 9) {
+ // Look for the '.' in the 3rd-last position:
+ if (cn.charAt(cnLen - 3) == '.') {
+ // Trim off the [*.] and the [.XX].
+ String s = cn.substring(2, cnLen - 3);
+ // And test against the sorted array of bad 2lds:
+ int x = Arrays.binarySearch(BAD_COUNTRY_2LDS, s);
+ return x < 0;
+ }
+ }
+ return true;
+ }
+
+ public static boolean isLocalhost(String host) {
+ host = host != null ? host.trim().toLowerCase() : "";
+ if (host.startsWith("::1")) {
+ int x = host.lastIndexOf('%');
+ if (x >= 0) {
+ host = host.substring(0, x);
+ }
+ }
+ int x = Arrays.binarySearch(LOCALHOSTS, host);
+ return x >= 0;
+ }
+
+ /**
+ * Counts the number of dots "." in a string.
+ *
+ * @param s string to count dots from
+ * @return number of dots
+ */
+ public static int countDots(final String s) {
+ int count = 0;
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '.') {
+ count++;
+ }
+ }
+ return count;
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/TLSHostnameVerifier.java b/src/main/java/com/github/shyiko/mysql/binlog/network/TLSHostnameVerifier.java
index 28b106d6..6dd3aa43 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/TLSHostnameVerifier.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/TLSHostnameVerifier.java
@@ -15,13 +15,11 @@
*/
package com.github.shyiko.mysql.binlog.network;
-import sun.security.util.HostnameChecker;
-
import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
@@ -30,15 +28,15 @@
public class TLSHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
- HostnameChecker checker = HostnameChecker.getInstance(HostnameChecker.TYPE_TLS);
+ HostnameChecker checker = HostnameChecker.DEFAULT;
try {
Certificate[] peerCertificates = session.getPeerCertificates();
if (peerCertificates.length > 0 && peerCertificates[0] instanceof X509Certificate) {
X509Certificate peerCertificate = (X509Certificate) peerCertificates[0];
try {
- checker.match(hostname, peerCertificate);
+ checker.check(hostname, peerCertificate);
return true;
- } catch (CertificateException ignored) {
+ } catch (SSLException ignored) {
}
}
} catch (SSLPeerUnverifiedException ignored) {
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
index 542c2452..7f13b7c1 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
@@ -115,7 +115,7 @@ public void testNullEventDeserializerIsNotAllowed() throws Exception {
@Test(timeOut = 15000)
public void testDisconnectWhileBlockedByFBRead() throws Exception {
- final BinaryLogClient binaryLogClient = new BinaryLogClient("localhost", 33060, "root", "mysql");
+ final BinaryLogClient binaryLogClient = new BinaryLogClient("localhost", 33061, "root", "mysql");
final CountDownLatch readAttempted = new CountDownLatch(1);
binaryLogClient.setSocketFactory(new SocketFactory() {
@Override
@@ -144,7 +144,7 @@ public void run() {
try {
final ServerSocket serverSocket = new ServerSocket();
try {
- serverSocket.bind(new InetSocketAddress("localhost", 33060));
+ serverSocket.bind(new InetSocketAddress("localhost", 33061));
socketBound.countDown();
serverSocket.accept(); // accept socket but do NOT send anything
assertTrue(readAttempted.await(3000, TimeUnit.MILLISECONDS));
From 174798b0e2bab5e9cf9ceb4bc8a346718cc631a3 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 22 Jan 2021 11:00:27 -0800
Subject: [PATCH 068/217] move test off mysqlx port
---
.../com/github/shyiko/mysql/binlog/BinaryLogClientTest.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
index 542c2452..7f13b7c1 100644
--- a/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
+++ b/src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientTest.java
@@ -115,7 +115,7 @@ public void testNullEventDeserializerIsNotAllowed() throws Exception {
@Test(timeOut = 15000)
public void testDisconnectWhileBlockedByFBRead() throws Exception {
- final BinaryLogClient binaryLogClient = new BinaryLogClient("localhost", 33060, "root", "mysql");
+ final BinaryLogClient binaryLogClient = new BinaryLogClient("localhost", 33061, "root", "mysql");
final CountDownLatch readAttempted = new CountDownLatch(1);
binaryLogClient.setSocketFactory(new SocketFactory() {
@Override
@@ -144,7 +144,7 @@ public void run() {
try {
final ServerSocket serverSocket = new ServerSocket();
try {
- serverSocket.bind(new InetSocketAddress("localhost", 33060));
+ serverSocket.bind(new InetSocketAddress("localhost", 33061));
socketBound.countDown();
serverSocket.accept(); // accept socket but do NOT send anything
assertTrue(readAttempted.await(3000, TimeUnit.MILLISECONDS));
From b912bbb74acd45a97791896fe4b3fb26b9536633 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 22 Jan 2021 19:39:27 -0800
Subject: [PATCH 069/217] add some logging, build for jdk 11
---
pom.xml | 3 +--
.../mysql/binlog/network/HostnameChecker.java | 13 +++++++++++++
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index a21feffa..46724235 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,8 +105,7 @@
maven-compiler-plugin3.5.1
- 1.8
- 1.8
+ 11
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java b/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
index 86b73aed..080c4590 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
@@ -61,6 +61,8 @@
import java.util.List;
import java.util.NoSuchElementException;
import java.util.TreeSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Interface for checking if a hostname matches the names stored inside the
@@ -221,6 +223,8 @@ public final void check(final String[] host, final String[] cns,
};
abstract class AbstractChecker implements HostnameChecker {
+ private final Logger logger = Logger.getLogger(getClass().getName());
+
public static String[] getCNs(X509Certificate cert) {
try {
final String subjectPrincipal = cert.getSubjectX500Principal().getName(X500Principal.RFC2253);
@@ -406,10 +410,19 @@ is presenting (e.g. edit "/etc/apache2/server.crt"
check(host, x509);
}
+ private String commaJoin(String [] input) {
+ if ( input == null ) return "";
+ return String.join(",", Arrays.asList(input));
+ }
+
public void check(String[] host, X509Certificate cert)
throws SSLException {
String[] cns = AbstractChecker.getCNs(cert);
String[] subjectAlts = AbstractChecker.getDNSSubjectAlts(cert);
+ logger.log(Level.INFO,
+ "attempting to verify SSL identity '" + commaJoin(host) + "' " +
+ "against cns: [" + commaJoin(cns) + "], " +
+ "subject-alts: [" + commaJoin(subjectAlts) + "]");
check(host, cns, subjectAlts);
}
From e2c05f60733b563c2692287b4df395f725883cc7 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 22 Jan 2021 20:55:06 -0800
Subject: [PATCH 070/217] remove dead config
---
pom.xml | 5 -----
1 file changed, 5 deletions(-)
diff --git a/pom.xml b/pom.xml
index 46724235..15feaccd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -228,11 +228,6 @@
org.apache.maven.pluginsmaven-javadoc-plugin3.2.0
-
- buar
- -J--add-exports
- -Jjava.base/sun.security.util=ALL-UNNAMED
- attach-javadocs
From c72e3562239112e4dc1ac4f84a8257c582220667 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 22 Jan 2021 21:14:41 -0800
Subject: [PATCH 071/217] bump maven-compiler, maven-source plugin
---
pom.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index 15feaccd..2c5eb964 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,7 +103,7 @@
org.apache.maven.pluginsmaven-compiler-plugin
- 3.5.1
+ 3.8.111
@@ -213,7 +213,7 @@
org.apache.maven.pluginsmaven-source-plugin
- 3.0.1
+ 3.8.1attach-sources
From cd618db00d84cdb846201f89092e7ec5b106d53d Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 25 Jan 2021 10:47:26 -0800
Subject: [PATCH 072/217] update version in README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 05d65a8c..f665442c 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ Get the latest JAR(s) from [here](https://search.maven.org/search?q=g:com.zendes
com.zendeskmysql-binlog-connector-java
- 0.23.2
+ 0.23.4
```
From 47466e712684e1b3551367768b94eb6b68f18d83 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Thu, 4 Feb 2021 15:14:21 -0800
Subject: [PATCH 073/217] version 0.24.0
---
CHANGELOG.md | 8 ++++++++
pom.xml | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 68943c40..af30c11b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## [0.24.0](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.23.3...0.24.0) - 2021-02-04
+
+- Move up to JDK 11, drop support for JDK 8
+
+## [0.23.4](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.23.3...0.23.4) - 2021-01-17
+
+- correct authentication error that was causing a problem with Azure
+
## [0.23.3](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.23.2...0.23.3) - 2020-10-29
- add EventDeserializer.CompatibilityMode.INTEGER_AS_BYTE_ARRAY if you want raw integer data
diff --git a/pom.xml b/pom.xml
index 2c5eb964..1410905f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.23.4-SNAPSHOT
+ 0.24.0mysql-binlog-connector-javaMySQL Binary Log connector
From 9519b3ce36e9a2525f69082751512333a1adefc1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Thu, 4 Feb 2021 16:39:32 -0800
Subject: [PATCH 074/217] correct maven-source-plugin version
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 1410905f..a8c8fc9c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -213,7 +213,7 @@
org.apache.maven.pluginsmaven-source-plugin
- 3.8.1
+ 3.2.1attach-sources
From 0953a3fb447371d6b3363ce9bfc90ca82df216a1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Thu, 4 Feb 2021 16:39:48 -0800
Subject: [PATCH 075/217] slog through and cleanup javadoc warnings
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 23 ++++++++++
.../mysql/binlog/BinaryLogFileReader.java | 1 +
.../github/shyiko/mysql/binlog/GtidSet.java | 2 +-
.../AbstractRowsEventDataDeserializer.java | 3 --
.../deserialization/EventDeserializer.java | 5 +++
.../deserialization/json/JsonBinary.java | 4 +-
.../mysql/binlog/io/ByteArrayInputStream.java | 27 +++++++++---
.../binlog/io/ByteArrayOutputStream.java | 8 ++++
.../mysql/binlog/network/ErrorCode.java | 44 +++++++++----------
.../mysql/binlog/network/HostnameChecker.java | 20 ++++-----
.../shyiko/mysql/binlog/network/SSLMode.java | 3 +-
.../mysql/binlog/network/ServerException.java | 1 +
.../AuthenticateSecurityPasswordCommand.java | 3 ++
13 files changed, 98 insertions(+), 46 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index e3f1857c..e15f68c6 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -172,6 +172,8 @@ public X509Certificate[] getAcceptedIssuers() {
/**
* Alias for BinaryLogClient("localhost", 3306, <no schema> = null, username, password).
* @see BinaryLogClient#BinaryLogClient(String, int, String, String, String)
+ * @param username login name
+ * @param password password
*/
public BinaryLogClient(String username, String password) {
this("localhost", 3306, null, username, password);
@@ -180,6 +182,9 @@ public BinaryLogClient(String username, String password) {
/**
* Alias for BinaryLogClient("localhost", 3306, schema, username, password).
* @see BinaryLogClient#BinaryLogClient(String, int, String, String, String)
+ * @param schema database name, nullable
+ * @param username login name
+ * @param password password
*/
public BinaryLogClient(String schema, String username, String password) {
this("localhost", 3306, schema, username, password);
@@ -188,6 +193,10 @@ public BinaryLogClient(String schema, String username, String password) {
/**
* Alias for BinaryLogClient(hostname, port, <no schema> = null, username, password).
* @see BinaryLogClient#BinaryLogClient(String, int, String, String, String)
+ * @param hostname mysql server hostname
+ * @param port mysql server port
+ * @param username login name
+ * @param password password
*/
public BinaryLogClient(String hostname, int port, String username, String password) {
this(hostname, port, null, username, password);
@@ -332,6 +341,7 @@ public void setGtidSet(String gtidSet) {
/**
* @see #setGtidSetFallbackToPurged(boolean)
+ * @return whether gtid_purged is used as a fallback
*/
public boolean isGtidSetFallbackToPurged() {
return gtidSetFallbackToPurged;
@@ -347,6 +357,7 @@ public void setGtidSetFallbackToPurged(boolean gtidSetFallbackToPurged) {
/**
* @see #setUseBinlogFilenamePositionInGtidMode(boolean)
+ * @return value of useBinlogFilenamePostionInGtidMode
*/
public boolean isUseBinlogFilenamePositionInGtidMode() {
return useBinlogFilenamePositionInGtidMode;
@@ -1072,6 +1083,7 @@ public List getEventListeners() {
/**
* Register event listener. Note that multiple event listeners will be called in order they
* where registered.
+ * @param eventListener event listener
*/
public void registerEventListener(EventListener eventListener) {
eventListeners.add(eventListener);
@@ -1079,6 +1091,7 @@ public void registerEventListener(EventListener eventListener) {
/**
* Unregister all event listener of specific type.
+ * @param listenerClass event listener class to unregister
*/
public void unregisterEventListener(Class extends EventListener> listenerClass) {
for (EventListener eventListener: eventListeners) {
@@ -1090,6 +1103,7 @@ public void unregisterEventListener(Class extends EventListener> listenerClass
/**
* Unregister single event listener.
+ * @param eventListener event listener to unregister
*/
public void unregisterEventListener(EventListener eventListener) {
eventListeners.remove(eventListener);
@@ -1120,6 +1134,7 @@ public List getLifecycleListeners() {
/**
* Register lifecycle listener. Note that multiple lifecycle listeners will be called in order they
* where registered.
+ * @param lifecycleListener lifecycle listener to register
*/
public void registerLifecycleListener(LifecycleListener lifecycleListener) {
lifecycleListeners.add(lifecycleListener);
@@ -1127,6 +1142,7 @@ public void registerLifecycleListener(LifecycleListener lifecycleListener) {
/**
* Unregister all lifecycle listener of specific type.
+ * @param listenerClass lifecycle listener class to unregister
*/
public void unregisterLifecycleListener(Class extends LifecycleListener> listenerClass) {
for (LifecycleListener lifecycleListener : lifecycleListeners) {
@@ -1138,6 +1154,7 @@ public void unregisterLifecycleListener(Class extends LifecycleListener> liste
/**
* Unregister single lifecycle listener.
+ * @param eventListener lifecycle listener to unregister
*/
public void unregisterLifecycleListener(LifecycleListener eventListener) {
lifecycleListeners.remove(eventListener);
@@ -1215,23 +1232,29 @@ public interface LifecycleListener {
/**
* Called once client has successfully logged in but before started to receive binlog events.
+ * @param client the client that logged in
*/
void onConnect(BinaryLogClient client);
/**
* It's guarantied to be called before {@link #onDisconnect(BinaryLogClient)}) in case of
* communication failure.
+ * @param client the client that triggered the communication failure
+ * @param ex The exception that triggered the communication failutre
*/
void onCommunicationFailure(BinaryLogClient client, Exception ex);
/**
* Called in case of failed event deserialization. Note this type of error does NOT cause client to
* disconnect. If you wish to stop receiving events you'll need to fire client.disconnect() manually.
+ * @param client the client that failed event deserialization
+ * @param ex The exception that triggered the failutre
*/
void onEventDeserializationFailure(BinaryLogClient client, Exception ex);
/**
* Called upon disconnect (regardless of the reason).
+ * @param client the client that disconnected
*/
void onDisconnect(BinaryLogClient client);
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogFileReader.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogFileReader.java
index 96b79fc6..d06a2d2d 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogFileReader.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogFileReader.java
@@ -77,6 +77,7 @@ public BinaryLogFileReader(InputStream inputStream, EventDeserializer eventDeser
/**
* @return deserialized event or null in case of end-of-stream
+ * @throws IOException if reading the event fails
*/
public Event readEvent() throws IOException {
return eventDeserializer.nextEvent(inputStream);
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/GtidSet.java b/src/main/java/com/github/shyiko/mysql/binlog/GtidSet.java
index 6899eafe..55d619e1 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/GtidSet.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/GtidSet.java
@@ -31,7 +31,7 @@
* gtid_set: uuid_set[,uuid_set]...
* uuid_set: uuid:interval[:interval]...
* uuid: hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh, h: [0-9|A-F]
- * interval: n[-n], (n >= 1)
+ * interval: n[-n], (n >= 1)
*
*
* @author Stanley Shyiko
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
index 7b910da4..89971365 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AbstractRowsEventDataDeserializer.java
@@ -471,9 +471,6 @@ private static int[] split(long value, int divider, int length) {
return result;
}
- /**
- * see mysql/strings/decimal.c
- */
public static BigDecimal asBigDecimal(int precision, int scale, byte[] value) {
boolean positive = (value[0] & 0x80) == 0x80;
value[0] ^= 0x80;
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
index fbec7c38..cf936852 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/EventDeserializer.java
@@ -153,6 +153,7 @@ private void afterEventDataDeserializerSet(EventType eventType) {
/**
* @deprecated resolved based on FORMAT_DESCRIPTION
+ * @param checksumType don't use this function.
*/
@Deprecated
public void setChecksumType(ChecksumType checksumType) {
@@ -161,6 +162,8 @@ public void setChecksumType(ChecksumType checksumType) {
/**
* @see CompatibilityMode
+ * @param first at least one CompatabilityMode
+ * @param rest many modes
*/
public void setCompatibilityMode(CompatibilityMode first, CompatibilityMode... rest) {
this.compatibilitySet = EnumSet.of(first, rest);
@@ -208,6 +211,8 @@ private void ensureCompatibility(EventDataDeserializer eventDataDeserializer) {
/**
* @return deserialized event or null in case of end-of-stream
+ * @param inputStream input stream to fetch event from
+ * @throws IOException if connection gets closed
*/
public Event nextEvent(ByteArrayInputStream inputStream) throws IOException {
if (inputStream.peek() == -1) {
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
index 688cdc63..153e317b 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
@@ -80,8 +80,6 @@
*
Grammar
* The grammar of the binary representation of JSON objects are defined in the MySQL codebase in the
* json_binary.h file:
- *
- *
*
* doc ::= type value
* type ::=
@@ -662,7 +660,6 @@ protected void parseString(JsonFormatter formatter) throws IOException {
* See the
* MySQL source code for the logic used in this method.
- *
*
Grammar
*
*
@@ -958,6 +955,7 @@ protected BigInteger readUInt64() throws IOException {
* to 16383, and so on...
*
* @return the integer value
+ * @throws IOException if we don't encounter an end-of-int marker
*/
protected int readVariableInt() throws IOException {
int length = 0;
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
index ff71cbee..c6fd4c3e 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
@@ -41,6 +41,9 @@ public ByteArrayInputStream(byte[] bytes) {
/**
* Read int written in little-endian format.
+ * @param length length of the integer to read
+ * @throws IOException in case of EOF
+ * @return the integer from the binlog
*/
public int readInteger(int length) throws IOException {
int result = 0;
@@ -52,6 +55,9 @@ public int readInteger(int length) throws IOException {
/**
* Read long written in little-endian format.
+ * @param length length of the long to read
+ * @throws IOException in case of EOF
+ * @return the long from the binlog
*/
public long readLong(int length) throws IOException {
long result = 0;
@@ -63,6 +69,9 @@ public long readLong(int length) throws IOException {
/**
* Read fixed length string.
+ * @param length length of string to read
+ * @throws IOException in case of EOF
+ * @return string
*/
public String readString(int length) throws IOException {
return new String(read(length));
@@ -70,6 +79,8 @@ public String readString(int length) throws IOException {
/**
* Read variable-length string. Preceding packed integer indicates the length of the string.
+ * @throws IOException in case of EOF
+ * @return string
*/
public String readLengthEncodedString() throws IOException {
return readString(readPackedInteger());
@@ -77,6 +88,8 @@ public String readLengthEncodedString() throws IOException {
/**
* Read variable-length string. End is indicated by 0x00 byte.
+ * @throws IOException in case of EOF
+ * @return string
*/
public String readZeroTerminatedString() throws IOException {
ByteArrayOutputStream s = new ByteArrayOutputStream();
@@ -128,6 +141,8 @@ private byte[] reverse(byte[] bytes) {
/**
* @see #readPackedNumber()
+ * @throws IOException in case of malformed number, eof, null, or long
+ * @return integer
*/
public int readPackedInteger() throws IOException {
Number number = readPackedNumber();
@@ -141,12 +156,14 @@ public int readPackedInteger() throws IOException {
}
/**
- * Format (first-byte-based):
- * 0-250 - The first byte is the number (in the range 0-250). No additional bytes are used.
- * 251 - SQL NULL value
- * 252 - Two more bytes are used. The number is in the range 251-0xffff.
- * 253 - Three more bytes are used. The number is in the range 0xffff-0xffffff.
+ * Format (first-byte-based):
+ * 0-250 - The first byte is the number (in the range 0-250). No additional bytes are used.
+ * 251 - SQL NULL value
+ * 252 - Two more bytes are used. The number is in the range 251-0xffff.
+ * 253 - Three more bytes are used. The number is in the range 0xffff-0xffffff.
* 254 - Eight more bytes are used. The number is in the range 0xffffff-0xffffffffffffffff.
+ * @throws IOException in case of malformed number or EOF
+ * @return long or null
*/
public Number readPackedNumber() throws IOException {
int b = this.read();
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
index 0bbdf3aa..17840c6f 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayOutputStream.java
@@ -35,6 +35,9 @@ public ByteArrayOutputStream(OutputStream outputStream) {
/**
* Write int in little-endian format.
+ * @throws IOException on underlying stream error
+ * @param value integer to write
+ * @param length length in bytes of the integer
*/
public void writeInteger(int value, int length) throws IOException {
for (int i = 0; i < length; i++) {
@@ -44,6 +47,9 @@ public void writeInteger(int value, int length) throws IOException {
/**
* Write long in little-endian format.
+ * @throws IOException on underlying stream error
+ * @param value long to write
+ * @param length length in bytes of the long
*/
public void writeLong(long value, int length) throws IOException {
for (int i = 0; i < length; i++) {
@@ -57,6 +63,8 @@ public void writeString(String value) throws IOException {
/**
* @see ByteArrayInputStream#readZeroTerminatedString()
+ * @param value string to write
+ * @throws IOException on underlying stream error
*/
public void writeZeroTerminatedString(String value) throws IOException {
if ( value != null )
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/ErrorCode.java b/src/main/java/com/github/shyiko/mysql/binlog/network/ErrorCode.java
index e7e46752..2cd4484e 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/ErrorCode.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/ErrorCode.java
@@ -2178,7 +2178,7 @@ public final class ErrorCode {
public static final int ER_TOO_BIG_PRECISION = 1426;
/**
- * For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s').
+ * For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s').
*/
public static final int ER_M_BIGGER_THAN_D = 1427;
@@ -3146,7 +3146,7 @@ public final class ErrorCode {
public static final int WARN_NO_MASTER_INFO = 1617;
/**
- * <%-.64s> option ignored
+ * %-.64s option ignored
*/
public static final int WARN_OPTION_IGNORED = 1618;
@@ -3988,56 +3988,56 @@ public final class ErrorCode {
public static final int ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET = 1778;
/**
- * @@GLOBAL.GTID_MODE = ON or UPGRADE_STEP_2 requires @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1.
+ @@GLOBAL.GTID_MODE = ON or UPGRADE_STEP_2 requires @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1.
*/
public static final int ER_GTID_MODE_2_OR_3_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON = 1779;
/**
- * @@GLOBAL.GTID_MODE = ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates.
+ * @@GLOBAL.GTID_MODE = ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates.
*/
public static final int ER_GTID_MODE_REQUIRES_BINLOG = 1780;
/**
- * @@SESSION.GTID_NEXT cannot be set to UUID:NUMBER when @@GLOBAL.GTID_MODE = OFF.
+ * @@SESSION.GTID_NEXT cannot be set to UUID:NUMBER when @@GLOBAL.GTID_MODE = OFF.
*/
public static final int ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF = 1781;
/**
- * @@SESSION.GTID_NEXT cannot be set to ANONYMOUS when @@GLOBAL.GTID_MODE = ON.
+ * @@SESSION.GTID_NEXT cannot be set to ANONYMOUS when @@GLOBAL.GTID_MODE = ON.
*/
public static final int ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON = 1782;
/**
- * @@SESSION.GTID_NEXT_LIST cannot be set to a non-NULL value when @@GLOBAL.GTID_MODE = OFF.
+ * @@SESSION.GTID_NEXT_LIST cannot be set to a non-NULL value when @@GLOBAL.GTID_MODE = OFF.
*/
public static final int ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF = 1783;
/**
- * Found a Gtid_log_event or Previous_gtids_log_event when @@GLOBAL.GTID_MODE = OFF.
+ * Found a Gtid_log_event or Previous_gtids_log_event when @@GLOBAL.GTID_MODE = OFF.
*/
public static final int ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF = 1784;
/**
- * When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, updates to non-transactional tables can only be done in either
+ * When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, updates to non-transactional tables can only be done in either
* autocommitted statements or single-statement transactions, and never in the same statement as updates to
* transactional tables.
*/
public static final int ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE = 1785;
/**
- * CREATE TABLE ... SELECT is forbidden when @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1.
+ * CREATE TABLE ... SELECT is forbidden when @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1.
*/
public static final int ER_GTID_UNSAFE_CREATE_SELECT = 1786;
/**
- * When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, the statements CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE can
+ * When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, the statements CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE can
* be executed in a non-transactional context only, and require that AUTOCOMMIT = 1.
*/
public static final int ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION = 1787;
/**
- * The value of @@GLOBAL.GTID_MODE can only change one step at a time: OFF <-> UPGRADE_STEP_1 <-> UPGRADE_STEP_2
- * <-> ON. Also note that this value must be stepped up or down simultaneously on all servers; see the Manual for
+ * The value of @@GLOBAL.GTID_MODE can only change one step at a time: OFF <-> UPGRADE_STEP_1 <-> UPGRADE_STEP_2
+ * <-> ON. Also note that this value must be stepped up or down simultaneously on all servers; see the Manual for
* instructions.
*/
public static final int ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME = 1788;
@@ -4049,7 +4049,7 @@ public final class ErrorCode {
public static final int ER_MASTER_HAS_PURGED_REQUIRED_GTIDS = 1789;
/**
- * @@SESSION.GTID_NEXT cannot be changed by a client that owns a GTID. The client owns %s. Ownership is released
+ * @@SESSION.GTID_NEXT cannot be changed by a client that owns a GTID. The client owns %s. Ownership is released
* on COMMIT or ROLLBACK.
*/
public static final int ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID = 1790;
@@ -4291,8 +4291,8 @@ public final class ErrorCode {
public static final int ER_READ_ONLY_MODE = 1836;
/**
- * When @@SESSION.GTID_NEXT is set to a GTID, you must explicitly set it to a different value after a COMMIT or
- * ROLLBACK. Please check GTID_NEXT variable manual page for detailed explanation. Current @@SESSION.GTID_NEXT is
+ * When @@SESSION.GTID_NEXT is set to a GTID, you must explicitly set it to a different value after a COMMIT or
+ * ROLLBACK. Please check GTID_NEXT variable manual page for detailed explanation. Current @@SESSION.GTID_NEXT is
* '%s'.
*/
public static final int ER_GTID_NEXT_TYPE_UNDEFINED_GROUP = 1837;
@@ -4303,27 +4303,27 @@ public final class ErrorCode {
public static final int ER_VARIABLE_NOT_SETTABLE_IN_SP = 1838;
/**
- * @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_MODE = ON.
+ * @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_MODE = ON.
*/
public static final int ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF = 1839;
/**
- * @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
+ * @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
*/
public static final int ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY = 1840;
/**
- * @@GLOBAL.GTID_PURGED can only be set when there are no ongoing transactions (not even in other clients).
+ * @@GLOBAL.GTID_PURGED can only be set when there are no ongoing transactions (not even in other clients).
*/
public static final int ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY = 1841;
/**
- * @@GLOBAL.GTID_PURGED was changed from '%s' to '%s'.
+ * @@GLOBAL.GTID_PURGED was changed from '%s' to '%s'.
*/
public static final int ER_GTID_PURGED_WAS_CHANGED = 1842;
/**
- * @@GLOBAL.GTID_EXECUTED was changed from '%s' to '%s'.
+ * @@GLOBAL.GTID_EXECUTED was changed from '%s' to '%s'.
*/
public static final int ER_GTID_EXECUTED_WAS_CHANGED = 1843;
@@ -4518,7 +4518,7 @@ public final class ErrorCode {
public static final int ER_OLD_TEMPORALS_UPGRADED = 1880;
/**
- * Operation not allowed when innodb_forced_recovery > 0.
+ * Operation not allowed when innodb_forced_recovery > 0.
*/
public static final int ER_INNODB_FORCED_RECOVERY = 1881;
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java b/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
index 080c4590..059a5f33 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/HostnameChecker.java
@@ -72,15 +72,15 @@
* or X509Certificate, or ultimately (they all end up calling this one),
* String. (It's easier to supply JUnit with Strings instead of mock
* SSLSession objects!)
- *
Our check() methods throw exceptions if the name is
+ *
Our check() methods throw exceptions if the name is
* invalid, whereas javax.net.ssl.HostnameVerifier just returns true/false.
- *
+ *
* We provide the HostnameVerifier.DEFAULT, HostnameVerifier.STRICT, and
* HostnameVerifier.ALLOW_ALL implementations. We also provide the more
* specialized HostnameVerifier.DEFAULT_AND_LOCALHOST, as well as
* HostnameVerifier.STRICT_IE6. But feel free to define your own
* implementations!
- *
+ *
* Inspired by Sebastian Hauer's original StrictSSLProtocolSocketFactory in the
* HttpClient "contrib" repository.
*
@@ -124,10 +124,10 @@ void check(String[] hosts, String[] cns, String[] subjectAlts)
/**
* The DEFAULT HostnameVerifier works the same way as Curl and Firefox.
- *
+ *
* The hostname must match either the first CN, or any of the subject-alts.
* A wildcard can occur in the CN, and in any of the subject-alts.
- *
+ *
* The only difference between DEFAULT and STRICT is that a wildcard (such
* as "*.foo.com") with DEFAULT matches all subdomains, including
* "a.b.foo.com".
@@ -169,13 +169,13 @@ public final void check(final String[] hosts, final String[] cns,
* Java 1.4, Sun Java 5, Sun Java 6. It's also pretty close to IE6.
* This implementation appears to be compliant with RFC 2818 for dealing
* with wildcards.
- *
+ *
* The hostname must match either the first CN, or any of the subject-alts.
* A wildcard can occur in the CN, and in any of the subject-alts. The
* one divergence from IE6 is how we only check the first CN. IE6 allows
* a match against any of the CNs present. We decided to follow in
* Sun Java 1.4's footsteps and only check the first CN.
- *
+ *
* A wildcard such as "*.foo.com" matches only subdomains in the same
* level, for example "a.foo.com". It does not match deeper subdomains
* such as "a.b.foo.com".
@@ -255,11 +255,11 @@ public static String[] getCNs(X509Certificate cert) {
/**
* Extracts the array of SubjectAlt DNS names from an X509Certificate.
* Returns null if there aren't any.
- *
+ *
* Note: Java doesn't appear able to extract international characters
* from the SubjectAlts. It can only extract international characters
* from the CN field.
- *
+ *
* (Or maybe the version of OpenSSL I'm using to test isn't storing the
* international characters correctly in the SubjectAlts?).
*
@@ -298,7 +298,7 @@ public static String[] getDNSSubjectAlts(X509Certificate cert) {
* This contains a list of 2nd-level domains that aren't allowed to
* have wildcards when combined with country-codes.
* For example: [*.co.uk].
- *
+ *
* The [*.co.uk] problem is an interesting one. Should we just hope
* that CA's would never foolishly allow such a certificate to happen?
* Looks like we're the only implementation guarding against this.
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/SSLMode.java b/src/main/java/com/github/shyiko/mysql/binlog/network/SSLMode.java
index a5ce7f42..041dd6ea 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/SSLMode.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/SSLMode.java
@@ -16,8 +16,7 @@
package com.github.shyiko.mysql.binlog.network;
/**
- * @see * ssl-mode for the original documentation.
* @author Stanley Shyiko
*/
public enum SSLMode {
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/ServerException.java b/src/main/java/com/github/shyiko/mysql/binlog/network/ServerException.java
index cfd026d2..03ce3b72 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/ServerException.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/ServerException.java
@@ -33,6 +33,7 @@ public ServerException(String message, int errorCode, String sqlState) {
/**
* @see ErrorCode
+ * @return error code
*/
public int getErrorCode() {
return errorCode;
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
index de93da45..744e85fe 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/protocol/command/AuthenticateSecurityPasswordCommand.java
@@ -83,6 +83,9 @@ public byte[] toByteArray() throws IOException {
/**
* see mysql/sql/password.c scramble(...)
+ * @param password the password
+ * @param salt salt received from server
+ * @return hashed password
*/
public static byte[] passwordCompatibleWithMySQL411(String password, String salt) {
if ( "".equals(password) || password == null )
From d475cb453f80f379f42cfcd63ae96453c82f0ed8 Mon Sep 17 00:00:00 2001
From: Jiri Pechanec
Date: Thu, 18 Feb 2021 08:09:16 +0100
Subject: [PATCH 076/217] Provide fast skip method implementation
---
.../mysql/binlog/event/deserialization/json/JsonBinary.java | 4 ++--
.../github/shyiko/mysql/binlog/io/ByteArrayInputStream.java | 5 +++++
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
index 688cdc63..98212c72 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
@@ -403,7 +403,7 @@ protected void parseObject(boolean small, JsonFormatter formatter)
} else {
// Parse the value ...
this.reader.reset();
- this.reader.skip(objectOffset + entry.index);
+ this.reader.fastSkip(objectOffset + entry.index);
parse(entry.type, formatter);
}
}
@@ -537,7 +537,7 @@ protected void parseArray(boolean small, JsonFormatter formatter)
} else {
// Parse the value ...
this.reader.reset();
- this.reader.skip(arrayOffset + entry.index);
+ this.reader.fastSkip(arrayOffset + entry.index);
parse(entry.type, formatter);
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
index ff71cbee..b089ac03 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
@@ -241,4 +241,9 @@ public synchronized void reset() throws IOException {
pos = markPosition;
inputStream.reset();
}
+
+ public synchronized long fastSkip(long n) throws IOException {
+ pos += (int) n;
+ return inputStream.skip(n);
+ }
}
From 02f1eda704d7785f12ecaaec50ef3337c1b810e8 Mon Sep 17 00:00:00 2001
From: Jiri Pechanec
Date: Mon, 1 Mar 2021 11:33:05 +0100
Subject: [PATCH 077/217] Add support for blocks
---
.../mysql/binlog/io/ByteArrayInputStream.java | 23 ++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
index b089ac03..d7d6f282 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
@@ -242,8 +242,25 @@ public synchronized void reset() throws IOException {
inputStream.reset();
}
+ /**
+ * This method implements fast-forward skipping in the stream.
+ * It can be used if and only if the underlying stream is fully available till its end.
+ * In other cases the regular {@link #skip(long)} method must be used.
+ *
+ * @param n - number of bytes to skip
+ * @return number of bytes skipped
+ * @throws IOException
+ */
public synchronized long fastSkip(long n) throws IOException {
- pos += (int) n;
- return inputStream.skip(n);
- }
+ long skipOf = n;
+ if (blockLength != -1) {
+ skipOf = Math.min(blockLength, skipOf);
+ blockLength -= skipOf;
+ if (blockLength == 0) {
+ blockLength = -1;
+ }
+ }
+ pos += (int) skipOf;
+ return inputStream.skip(skipOf);
+ }
}
From 584b80090ccf740fd2ad318f29c683cbf84356e1 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Wed, 3 Mar 2021 09:36:44 -0800
Subject: [PATCH 078/217] v0.24.1
---
CHANGELOG.md | 4 ++++
pom.xml | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index af30c11b..3e98127a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+## [0.24.1](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.24.0...0.24.1) - 2021-03-03
+
+- Fix for performance issues read JSON columns
+
## [0.24.0](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.23.3...0.24.0) - 2021-02-04
- Move up to JDK 11, drop support for JDK 8
diff --git a/pom.xml b/pom.xml
index a8c8fc9c..183e02c9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.24.0
+ 0.24.1mysql-binlog-connector-javaMySQL Binary Log connector
From 891ffee0752b75632af2a57d0964ca98661aab99 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Thu, 4 Mar 2021 10:17:58 -0800
Subject: [PATCH 079/217] 0.25.0
---
CHANGELOG.md | 4 ++++
pom.xml | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e98127a..805767f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+## [0.25.0](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.24.1...0.25.0) - 2021-03-04
+
+- bring back jdk 8 support, this caused... ahem. Issues.
+
## [0.24.1](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.24.0...0.24.1) - 2021-03-03
- Fix for performance issues read JSON columns
diff --git a/pom.xml b/pom.xml
index 183e02c9..8c788d4c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.24.1
+ 0.25.0mysql-binlog-connector-javaMySQL Binary Log connector
@@ -105,7 +105,7 @@
maven-compiler-plugin3.8.1
- 11
+ 8
From 4d1bf9cbc0d017030c3e3324b9946ef4ef0021f0 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 29 Mar 2021 17:02:45 -0700
Subject: [PATCH 080/217] update README.md
---
README.md | 10 ++++++----
.../binlog/event/deserialization/json/JsonBinary.java | 2 --
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index f665442c..73ab8158 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
# mysql-binlog-connector-java [](https://travis-ci.org/shyiko/mysql-binlog-connector-java) [](https://coveralls.io/r/shyiko/mysql-binlog-connector-java?branch=master) [](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.github.shyiko%22%20AND%20a%3A%22mysql-binlog-connector-java%22)
-MySQL Binary Log connector.
+MySQL Binary Log connector. @osheroff's fork of @shiyko's project, probably
+the "official" version of this. With help from the Debezium devs.
Initially project was started as a fork of [open-replicator](https://code.google.com/p/open-replicator),
but ended up as a complete rewrite. Key differences/features:
@@ -23,16 +24,17 @@ but ended up as a complete rewrite. Key differences/features:
## Usage
-Get the latest JAR(s) from [here](https://search.maven.org/search?q=g:com.zendesk%20AND%20a:mysql-binlog-connector-java). Alternatively you can include following Maven dependency (available through Maven Central):
```xml
com.zendeskmysql-binlog-connector-java
- 0.23.4
+ 0.25.0
```
+Or get the latest JAR(s) from [here](https://search.maven.org/search?q=g:com.zendesk%20AND%20a:mysql-binlog-connector-java).
+
#### Reading binary log file
```java
@@ -197,6 +199,7 @@ For the insight into the internals of MySQL look [here](https://dev.mysql.com/do
Some of the OSS using / built on top of mysql-binlog-conector-java:
* [apache/nifi](https://github.com/apache/nifi) An easy to use, powerful, and reliable system to process and distribute data.
* [debezium](https://github.com/debezium/debezium) A low latency data streaming platform for change data capture (CDC).
+* [zendesk/maxwell](https://github.com/zendesk/maxwell) A MySQL-to-JSON Kafka producer.
* [mavenlink/changestream](https://github.com/mavenlink/changestream) - A stream of changes for MySQL built on Akka.
* [mardambey/mypipe](https://github.com/mardambey/mypipe) MySQL binary log consumer with the ability to act on changed rows and publish changes to different systems with emphasis on Apache Kafka.
* [ngocdaothanh/mydit](https://github.com/ngocdaothanh/mydit) MySQL to MongoDB data replicator.
@@ -204,7 +207,6 @@ Some of the OSS using / built on top of mysql-binlog-conector-java:
* [shyiko/rook](https://github.com/shyiko/rook) Generic Change Data Capture (CDC) toolkit.
* [streamsets/datacollector](https://github.com/streamsets/datacollector) Continuous big data ingestion infrastructure.
* [twingly/ecco](https://github.com/twingly/ecco) MySQL replication binlog parser in JRuby.
-* [zendesk/maxwell](https://github.com/zendesk/maxwell) A MySQL-to-JSON Kafka producer.
* [zzt93/syncer](https://github.com/zzt93/syncer) A tool sync & manipulate data from MySQL/MongoDB to ES/Kafka/MySQL, which make 'Eventual Consistency' promise.
It's also used [on a large scale](https://twitter.com/atwinmutt/status/626816601078300672) in MailChimp. You can read about it [here](http://devs.mailchimp.com/blog/powering-mailchimp-pro-reporting/).
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
index 81e7f1ae..d8b824eb 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/json/JsonBinary.java
@@ -261,8 +261,6 @@ protected void parse(ValueType type, JsonFormatter formatter) throws IOException
* json_binary.h file:
*
Grammar
*
- *
Grammar
- *
*
* value ::=
* object |
From 67e6a95a9e7f031987e3ad45733cc9b9b8f913d8 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 29 Mar 2021 17:03:37 -0700
Subject: [PATCH 081/217] move usage up
---
README.md | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index 73ab8158..11d04419 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,16 @@
MySQL Binary Log connector. @osheroff's fork of @shiyko's project, probably
the "official" version of this. With help from the Debezium devs.
+## Usage
+
+```xml
+
+ com.zendesk
+ mysql-binlog-connector-java
+ 0.25.0
+
+```
+
Initially project was started as a fork of [open-replicator](https://code.google.com/p/open-replicator),
but ended up as a complete rewrite. Key differences/features:
@@ -22,16 +32,6 @@ but ended up as a complete rewrite. Key differences/features:
[siddontang/go-mysql](https://github.com/siddontang/go-mysql) (Go),
[noplay/python-mysql-replication](https://github.com/noplay/python-mysql-replication) (Python).
-## Usage
-
-
-```xml
-
- com.zendesk
- mysql-binlog-connector-java
- 0.25.0
-
-```
Or get the latest JAR(s) from [here](https://search.maven.org/search?q=g:com.zendesk%20AND%20a:mysql-binlog-connector-java).
From 252dead8a8cc1ee6854184320a506f3c3e057dfe Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Mon, 29 Mar 2021 17:04:30 -0700
Subject: [PATCH 082/217] fix badgey thingy
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 11d04419..407e27a3 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# mysql-binlog-connector-java [](https://travis-ci.org/shyiko/mysql-binlog-connector-java) [](https://coveralls.io/r/shyiko/mysql-binlog-connector-java?branch=master) [](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.github.shyiko%22%20AND%20a%3A%22mysql-binlog-connector-java%22)
+# mysql-binlog-connector-java [](https://travis-ci.org/shyiko/mysql-binlog-connector-java) [](https://coveralls.io/r/shyiko/mysql-binlog-connector-java?branch=master) [](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.github.shyiko%22%20AND%20a%3A%22mysql-binlog-connector-java%22)
MySQL Binary Log connector. @osheroff's fork of @shiyko's project, probably
From ff9a79139127dea6fd3e9112e3d0213c108989c6 Mon Sep 17 00:00:00 2001
From: Vadzim Ramanenka
Date: Fri, 26 Mar 2021 22:09:50 +0300
Subject: [PATCH 083/217] Optimize read operation on ByteArrayInputStream
---
.../mysql/binlog/io/ByteArrayInputStream.java | 44 ++++++++
.../binlog/io/ByteArrayInputStreamTest.java | 102 ++++++++++++++++++
2 files changed, 146 insertions(+)
create mode 100644 src/test/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStreamTest.java
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
index b883394f..3cfaf979 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStream.java
@@ -222,6 +222,50 @@ private int readWithinBlockBoundaries() throws IOException {
return inputStream.read();
}
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ if (peek != null) {
+ b[off] = (byte)(int)peek;
+ off += 1;
+ len -= 1;
+ }
+
+ int read = readWithinBlockBoundaries(b, off, len);
+
+ if (read > 0) {
+ this.pos += read;
+ }
+
+ if (peek != null) {
+ peek = null;
+ read = read <= 0 ? 1 : read + 1;
+ }
+
+ return read;
+ }
+
+ private int readWithinBlockBoundaries(byte[] b, int off, int len) throws IOException {
+ if (blockLength == -1) {
+ return inputStream.read(b, off, len);
+ } else if (blockLength == 0) {
+ return -1;
+ }
+
+ int read = inputStream.read(b, off, Math.min(len, blockLength));
+ if (read > 0) {
+ blockLength -= read;
+ }
+ return read;
+ }
+
@Override
public void close() throws IOException {
inputStream.close();
diff --git a/src/test/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStreamTest.java b/src/test/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStreamTest.java
new file mode 100644
index 00000000..8f0eb112
--- /dev/null
+++ b/src/test/java/com/github/shyiko/mysql/binlog/io/ByteArrayInputStreamTest.java
@@ -0,0 +1,102 @@
+package com.github.shyiko.mysql.binlog.io;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+public class ByteArrayInputStreamTest {
+ @Test
+ public void testReadToArray() throws Exception {
+ byte[] buff = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ ByteArrayInputStream in = new ByteArrayInputStream(buff);
+ assertEquals(in.getPosition(), 0);
+
+ byte[] b = new byte[20];
+
+ int read = in.read(b, 0, 0);
+ assertEquals(read, 0);
+ assertEquals(in.getPosition(), 0);
+
+ read = in.read(b, 0, 4);
+ assertEquals(read, 4);
+ assertEquals(b[3], 3);
+ assertEquals(in.getPosition(), 4);
+
+ read = in.read(b, 4, 4);
+ assertEquals(read, 4);
+ assertEquals(b[7], 7);
+ assertEquals(in.getPosition(), 8);
+
+ read = in.read(b, 8, 4);
+ assertEquals(read, 4);
+ assertEquals(b[11], 11);
+ assertEquals(in.getPosition(), 12);
+
+ read = in.read(b, 12, 4);
+ assertEquals(read, 4);
+ assertEquals(b[15], 15);
+ assertEquals(in.getPosition(), 16);
+
+ read = in.read(b, 16, 4);
+ assertEquals(read, -1);
+ assertEquals(in.getPosition(), 16);
+ }
+
+ @Test
+ public void testReadToArrayWithinBlockBoundaries() throws Exception {
+ byte[] buff = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8};
+ ByteArrayInputStream in = new ByteArrayInputStream(buff);
+ byte[] b = new byte[8];
+
+ in.enterBlock(4);
+
+ int read = in.read(b, 0, 3);
+ assertEquals(read, 3);
+ assertEquals(b[2], 2);
+
+ read = in.read(b, 3, 3);
+ assertEquals(read, 1);
+ assertEquals(b[3], 3);
+
+ read = in.read(b, 4, 3);
+ assertEquals(read, -1);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testReadToArrayWithNullBuff() throws Exception {
+ ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{});
+ in.read(null, 0, 4);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testReadToArrayWhenLenExceedsBuffSize() throws Exception {
+ ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{0, 1, 2});
+ byte[] b = new byte[1];
+ in.read(b, 0, 4);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testReadToArrayWhenOffsetNegative() throws Exception {
+ ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{0, 1, 2});
+ byte[] b = new byte[1];
+ in.read(b, -1, 1);
+ }
+
+ @Test(expectedExceptions = IndexOutOfBoundsException.class)
+ public void testReadToArrayWhenLengthNegative() throws Exception {
+ ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{0, 1, 2});
+ byte[] b = new byte[1];
+ in.read(b, 0, -1);
+ }
+
+ @Test
+ public void testPeekAndReadToArray() throws Exception {
+ ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{5, 6, 7});
+ byte[] b = new byte[3];
+ assertEquals(in.peek(), 5);
+ int read = in.read(b, 0, 3);
+ assertEquals(read, 3);
+ assertEquals(b[0], 5);
+ assertEquals(b[2], 7);
+ }
+}
From 6fc750f56fffbea6c3e6d6602a1808020fa646a0 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Tue, 20 Apr 2021 16:12:46 -0700
Subject: [PATCH 084/217] v0.25.1
---
CHANGELOG.md | 4 ++++
pom.xml | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 805767f6..92babdb3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+## [0.25.1](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.25.0...0.25.1) - 2021-04-20
+
+- performance improves in ByteArrayInputStream#read
+
## [0.25.0](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.24.1...0.25.0) - 2021-03-04
- bring back jdk 8 support, this caused... ahem. Issues.
diff --git a/pom.xml b/pom.xml
index 8c788d4c..8df99701 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.25.0
+ 0.25.1mysql-binlog-connector-javaMySQL Binary Log connector
From 532f474585029e3188ad0eb0d31d4905add54daf Mon Sep 17 00:00:00 2001
From: Igor Kostromin
Date: Wed, 9 Jun 2021 11:06:41 +0300
Subject: [PATCH 085/217] Introduce overridable setupConnection() method
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 23 ++++++++++++-------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index e15f68c6..d8b8299f 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -554,14 +554,7 @@ public void connect() throws IOException, IllegalStateException {
}
binlogPosition = 4;
}
- ChecksumType checksumType = fetchBinlogChecksum();
- if (checksumType != ChecksumType.NONE) {
- confirmSupportOfChecksum(checksumType);
- }
- setMasterServerId();
- if (heartbeatInterval > 0) {
- enableHeartbeat();
- }
+ setupConnection();
gtid = null;
tx = false;
requestBinaryLogStream();
@@ -614,6 +607,20 @@ public void connect() throws IOException, IllegalStateException {
}
}
+ /**
+ * Apply additional options for connection before requesting binlog stream.
+ */
+ protected void setupConnection() throws IOException {
+ ChecksumType checksumType = fetchBinlogChecksum();
+ if (checksumType != ChecksumType.NONE) {
+ confirmSupportOfChecksum(checksumType);
+ }
+ setMasterServerId();
+ if (heartbeatInterval > 0) {
+ enableHeartbeat();
+ }
+ }
+
private PacketChannel openChannel() throws IOException {
Socket socket = socketFactory != null ? socketFactory.createSocket() : new Socket();
socket.connect(new InetSocketAddress(hostname, port), (int) connectTimeout);
From efcb63504b54bceaaee3531cdf15ba76106824e7 Mon Sep 17 00:00:00 2001
From: Jack Low
Date: Tue, 15 Jun 2021 17:16:25 +1000
Subject: [PATCH 086/217] Set DefaultSSLSocketFactory to TLSv1.2 in line with
JDK 11.0.11:
https://www.oracle.com/java/technologies/javase/11-0-11-relnotes.html#JDK-8202343
---
.../shyiko/mysql/binlog/network/DefaultSSLSocketFactory.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/network/DefaultSSLSocketFactory.java b/src/main/java/com/github/shyiko/mysql/binlog/network/DefaultSSLSocketFactory.java
index 0fabaa10..388e95d2 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/network/DefaultSSLSocketFactory.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/network/DefaultSSLSocketFactory.java
@@ -30,11 +30,11 @@ public class DefaultSSLSocketFactory implements SSLSocketFactory {
private final String protocol;
public DefaultSSLSocketFactory() {
- this("TLSv1");
+ this("TLSv1.2");
}
/**
- * @param protocol TLSv1, TLSv1.1 or TLSv1.2 (the last two require JDK 7+)
+ * @param protocol TLSv1, TLSv1.1 or TLSv1.2. Since JDK 11.0.11, TLSv1 and TLSv1.1 are no longer supported.
*/
public DefaultSSLSocketFactory(String protocol) {
this.protocol = protocol;
From 84eaf6dbfbb70583327b8cd59187575c97cdd6aa Mon Sep 17 00:00:00 2001
From: Jack Low
Date: Wed, 16 Jun 2021 10:00:25 +1000
Subject: [PATCH 087/217] Update version from 0.25.1 to 0.26.0
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 8df99701..42fb2c1c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.25.1
+ 0.26.0mysql-binlog-connector-javaMySQL Binary Log connector
From 4771a48fe8dc3ac89aeeafc09ce5cd5a72239f9a Mon Sep 17 00:00:00 2001
From: Jack Low
Date: Thu, 17 Jun 2021 15:32:43 +1000
Subject: [PATCH 088/217] Revert "Update version from 0.25.1 to 0.26.0"
This reverts commit 84eaf6dbfbb70583327b8cd59187575c97cdd6aa.
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 42fb2c1c..8df99701 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.26.0
+ 0.25.1mysql-binlog-connector-javaMySQL Binary Log connector
From 273fc1502be0bf3c7bbe5cd9f680b1cc6f0a3e02 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 25 Jun 2021 08:02:24 -0700
Subject: [PATCH 089/217] v0.25.2
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 8df99701..b6b62f90 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.zendeskmysql-binlog-connector-java
- 0.25.1
+ 0.25.2mysql-binlog-connector-javaMySQL Binary Log connector
From 9cc270ee804442945ac6ed984be9e8adea460177 Mon Sep 17 00:00:00 2001
From: Ben Osheroff
Date: Fri, 25 Jun 2021 08:03:32 -0700
Subject: [PATCH 090/217] update CHANGELOG
---
CHANGELOG.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 92babdb3..98cb70e4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## [0.25.2](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.25.1...0.25.2) - 2021-06-25
+
+- allow `setupConnection()` to be overridden
+- upgrade to TLS v1.2
+
## [0.25.1](https://github.com/osheroff/mysql-binlog-connector-java/compare/0.25.0...0.25.1) - 2021-04-20
- performance improves in ByteArrayInputStream#read
From 3598de77bf327ac4a662a77c83d71cb1ce10bd39 Mon Sep 17 00:00:00 2001
From: "jackey.zhang"
Date: Tue, 13 Jul 2021 11:39:58 +0800
Subject: [PATCH 091/217] Adding support Mariadb events, such as GTID and
annotate rows event(sql)
---
.../shyiko/mysql/binlog/BinaryLogClient.java | 101 +++++++----
.../shyiko/mysql/binlog/MariadbGtidSet.java | 158 ++++++++++++++++++
.../binlog/event/AnnotateRowsEventData.java | 31 ++++
.../shyiko/mysql/binlog/event/EventType.java | 119 +++++++------
.../binlog/event/MariadbGtidEventData.java | 43 +++++
.../event/MariadbGtidListEventData.java | 29 ++++
.../AnnotateRowsEventDataDeserializer.java | 24 +++
.../deserialization/EventDeserializer.java | 6 +
.../EventHeaderV4Deserializer.java | 8 +-
.../MariadbGtidEventDataDeserializer.java | 33 ++++
.../MariadbGtidListEventDataDeserializer.java | 39 +++++
.../command/DumpBinaryLogCommand.java | 13 +-
...BinaryLogClientMariadbIntegrationTest.java | 87 ++++++++++
13 files changed, 605 insertions(+), 86 deletions(-)
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/MariadbGtidSet.java
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/event/AnnotateRowsEventData.java
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/event/MariadbGtidEventData.java
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/event/MariadbGtidListEventData.java
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AnnotateRowsEventDataDeserializer.java
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/MariadbGtidEventDataDeserializer.java
create mode 100644 src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/MariadbGtidListEventDataDeserializer.java
create mode 100644 src/test/java/com/github/shyiko/mysql/binlog/BinaryLogClientMariadbIntegrationTest.java
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
index d8b8299f..5ba4cb2d 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/BinaryLogClient.java
@@ -15,21 +15,9 @@
*/
package com.github.shyiko.mysql.binlog;
-import com.github.shyiko.mysql.binlog.event.Event;
-import com.github.shyiko.mysql.binlog.event.EventHeader;
-import com.github.shyiko.mysql.binlog.event.EventHeaderV4;
-import com.github.shyiko.mysql.binlog.event.EventType;
-import com.github.shyiko.mysql.binlog.event.GtidEventData;
-import com.github.shyiko.mysql.binlog.event.QueryEventData;
-import com.github.shyiko.mysql.binlog.event.RotateEventData;
-import com.github.shyiko.mysql.binlog.event.deserialization.ChecksumType;
-import com.github.shyiko.mysql.binlog.event.deserialization.EventDataDeserializationException;
-import com.github.shyiko.mysql.binlog.event.deserialization.EventDataDeserializer;
-import com.github.shyiko.mysql.binlog.event.deserialization.EventDeserializer;
+import com.github.shyiko.mysql.binlog.event.*;
+import com.github.shyiko.mysql.binlog.event.deserialization.*;
import com.github.shyiko.mysql.binlog.event.deserialization.EventDeserializer.EventDataWrapper;
-import com.github.shyiko.mysql.binlog.event.deserialization.GtidEventDataDeserializer;
-import com.github.shyiko.mysql.binlog.event.deserialization.QueryEventDataDeserializer;
-import com.github.shyiko.mysql.binlog.event.deserialization.RotateEventDataDeserializer;
import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream;
import com.github.shyiko.mysql.binlog.jmx.BinaryLogClientMXBean;
import com.github.shyiko.mysql.binlog.network.AuthenticationException;
@@ -46,15 +34,7 @@
import com.github.shyiko.mysql.binlog.network.protocol.Packet;
import com.github.shyiko.mysql.binlog.network.protocol.PacketChannel;
import com.github.shyiko.mysql.binlog.network.protocol.ResultSetRowPacket;
-import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateNativePasswordCommand;
-import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSHA2Command;
-import com.github.shyiko.mysql.binlog.network.protocol.command.AuthenticateSecurityPasswordCommand;
-import com.github.shyiko.mysql.binlog.network.protocol.command.Command;
-import com.github.shyiko.mysql.binlog.network.protocol.command.DumpBinaryLogCommand;
-import com.github.shyiko.mysql.binlog.network.protocol.command.DumpBinaryLogGtidCommand;
-import com.github.shyiko.mysql.binlog.network.protocol.command.PingCommand;
-import com.github.shyiko.mysql.binlog.network.protocol.command.QueryCommand;
-import com.github.shyiko.mysql.binlog.network.protocol.command.SSLRequestCommand;
+import com.github.shyiko.mysql.binlog.network.protocol.command.*;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
@@ -141,6 +121,8 @@ public X509Certificate[] getAcceptedIssuers() {
private boolean useBinlogFilenamePositionInGtidMode;
private String gtid;
private boolean tx;
+ private boolean isMariadb = false;
+ private boolean mariadbSendAnnotateRowsEvent = false;
private EventDeserializer eventDeserializer = new EventDeserializer();
@@ -335,7 +317,12 @@ public void setGtidSet(String gtidSet) {
this.binlogFilename = "";
}
synchronized (gtidSetAccessLock) {
- this.gtidSet = gtidSet != null ? new GtidSet(gtidSet) : null;
+ // mariadb GtidSet format will be domainId-serverId-sequence
+ if (gtidSet != null && !gtidSet.contains(":")) {
+ this.gtidSet = new MariadbGtidSet(gtidSet);
+ } else {
+ this.gtidSet = gtidSet != null ? new GtidSet(gtidSet) : null;
+ }
}
}
@@ -501,6 +488,19 @@ public void setThreadFactory(ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
}
+ public boolean isMariadbSendAnnotateRowsEvent() {
+ return mariadbSendAnnotateRowsEvent;
+ }
+
+ /**
+ * Only in Mariadb, if set true, the Slave server connects with the BINLOG_SEND_ANNOTATE_ROWS_EVENT flag (value is 2)
+ * in the COM_BINLOG_DUMP Slave Registration phase
+ * @param mariadbSendAnnotateRowsEvent
+ */
+ public void setMariadbSendAnnotateRowsEvent(boolean mariadbSendAnnotateRowsEvent) {
+ this.mariadbSendAnnotateRowsEvent = mariadbSendAnnotateRowsEvent;
+ }
+
/**
* Connect to the replication stream. Note that this method blocks until disconnected.
* @throws AuthenticationException if authentication fails
@@ -538,10 +538,15 @@ public void connect() throws IOException, IllegalStateException {
channel.authenticationComplete();
connectionId = greetingPacket.getThreadId();
+ isMariadb = greetingPacket.getServerVersion().toLowerCase().contains("mariadb");
if ("".equals(binlogFilename)) {
synchronized (gtidSetAccessLock) {
if (gtidSet != null && "".equals(gtidSet.toString()) && gtidSetFallbackToPurged) {
- gtidSet = new GtidSet(fetchGtidPurged());
+ if (isMariadb) {
+ gtidSet = new MariadbGtidSet(fetchGtidPurged());
+ } else {
+ gtidSet = new GtidSet(fetchGtidPurged());
+ }
}
}
}
@@ -594,6 +599,11 @@ public void connect() throws IOException, IllegalStateException {
if (gtidSet != null) {
ensureEventDataDeserializer(EventType.GTID, GtidEventDataDeserializer.class);
ensureEventDataDeserializer(EventType.QUERY, QueryEventDataDeserializer.class);
+ if (isMariadb) {
+ ensureEventDataDeserializer(EventType.ANNOTATE_ROWS, AnnotateRowsEventDataDeserializer.class);
+ ensureEventDataDeserializer(EventType.MARIADB_GTID, MariadbGtidEventDataDeserializer.class);
+ ensureEventDataDeserializer(EventType.MARIADB_GTID_LIST, MariadbGtidListEventDataDeserializer.class);
+ }
}
}
listenForEventPackets();
@@ -730,10 +740,22 @@ private void requestBinaryLogStream() throws IOException {
Command dumpBinaryLogCommand;
synchronized (gtidSetAccessLock) {
if (gtidSet != null) {
- dumpBinaryLogCommand = new DumpBinaryLogGtidCommand(serverId,
- useBinlogFilenamePositionInGtidMode ? binlogFilename : "",
- useBinlogFilenamePositionInGtidMode ? binlogPosition : 4,
- gtidSet);
+ if (isMariadb) {
+ channel.write(new QueryCommand("SET @mariadb_slave_capability=4"));
+ checkError(channel.read());
+ channel.write(new QueryCommand("SET @slave_connect_state = '" + gtidSet.toString() + "'"));
+ checkError(channel.read());
+ channel.write(new QueryCommand("SET @slave_gtid_strict_mode = 0"));
+ checkError(channel.read());
+ channel.write(new QueryCommand("SET @slave_gtid_ignore_duplicates = 0"));
+ checkError(channel.read());
+ dumpBinaryLogCommand = new DumpBinaryLogCommand(serverId, "", 0L, isMariadbSendAnnotateRowsEvent());
+ } else {
+ dumpBinaryLogCommand = new DumpBinaryLogGtidCommand(serverId,
+ useBinlogFilenamePositionInGtidMode ? binlogFilename : "",
+ useBinlogFilenamePositionInGtidMode ? binlogPosition : 4,
+ gtidSet);
+ }
} else {
dumpBinaryLogCommand = new DumpBinaryLogCommand(serverId, binlogFilename, binlogPosition);
}
@@ -1034,13 +1056,30 @@ private void updateGtidSet(Event event) {
GtidEventData gtidEventData = (GtidEventData) EventDataWrapper.internal(event.getData());
gtid = gtidEventData.getGtid();
break;
+ case MARIADB_GTID:
+ MariadbGtidEventData mariadbGtidEventData = (MariadbGtidEventData) EventDataWrapper.internal(event.getData());
+ mariadbGtidEventData.setServerId(eventHeader.getServerId());
+ gtid = mariadbGtidEventData.toString();
+ break;
+ case MARIADB_GTID_LIST:
+ MariadbGtidListEventData mariadbGtidListEventData = (MariadbGtidListEventData) EventDataWrapper.internal(event.getData());
+ gtid = mariadbGtidListEventData.getMariaGTIDSet().toString();
+ break;
case XID:
commitGtid();
tx = false;
break;
case QUERY:
- QueryEventData queryEventData = (QueryEventData) EventDataWrapper.internal(event.getData());
- String sql = queryEventData.getSql();
+ case ANNOTATE_ROWS:
+ String sql;
+ if (eventHeader.getEventType() == EventType.QUERY) {
+ QueryEventData queryEventData = (QueryEventData) EventDataWrapper.internal(event.getData());
+ sql = queryEventData.getSql();
+ } else {
+ AnnotateRowsEventData annotateRowsEventData = (AnnotateRowsEventData) EventDataWrapper.internal(event.getData());
+ sql = annotateRowsEventData.getRowsQuery();
+ }
+
if (sql == null) {
break;
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/MariadbGtidSet.java b/src/main/java/com/github/shyiko/mysql/binlog/MariadbGtidSet.java
new file mode 100644
index 00000000..c86ee54a
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/MariadbGtidSet.java
@@ -0,0 +1,158 @@
+package com.github.shyiko.mysql.binlog;
+
+import java.util.*;
+
+/**
+ * Mariadb Global Transaction ID
+ *
+ * @author Winger
+ * @see GTID for the original doc
+ */
+public class MariadbGtidSet extends GtidSet {
+
+ private Map map = new HashMap<>();
+
+ public MariadbGtidSet() {
+ super(null); //
+ }
+
+ public MariadbGtidSet(String gtidSet) {
+ super(null);
+ if (gtidSet != null && gtidSet.length() > 0) {
+ String[] gtids = gtidSet.replaceAll("\n", "").split(",");
+ for (String gtid : gtids) {
+ MariaGtid mariaGtid = MariaGtid.parse(gtid);
+ map.put(mariaGtid.getDomainId(), mariaGtid);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (MariaGtid gtid : map.values()) {
+ if (sb.length() > 0) {
+ sb.append(",");
+ }
+ sb.append(gtid.toString());
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public Collection getUUIDSets() {
+ throw new UnsupportedOperationException("Mariadb gtid not support this method");
+ }
+
+ @Override
+ public UUIDSet getUUIDSet(String uuid) {
+ throw new UnsupportedOperationException("Mariadb gtid not support this method");
+ }
+
+ @Override
+ public UUIDSet putUUIDSet(UUIDSet uuidSet) {
+ throw new UnsupportedOperationException("Mariadb gtid not support this method");
+ }
+
+ @Override
+ public boolean add(String gtid) {
+ MariaGtid mariaGtid = MariaGtid.parse(gtid);
+ map.put(mariaGtid.getDomainId(), mariaGtid);
+ return true;
+ }
+
+ public void add(MariaGtid gtid) {
+ map.put(gtid.getDomainId(), gtid);
+ }
+
+ @Override
+ public boolean isContainedWithin(GtidSet other) {
+ throw new UnsupportedOperationException("Mariadb gtid not support this method");
+ }
+
+ @Override
+ public int hashCode() {
+ return map.keySet().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof MariadbGtidSet) {
+ MariadbGtidSet that = (MariadbGtidSet) obj;
+ return this.map.equals(that.map);
+ }
+ return false;
+ }
+
+ public static class MariaGtid {
+
+ // {domainId}-{serverId}-{sequence}
+ private long domainId;
+ private long serverId;
+ private long sequence;
+
+ public MariaGtid(long domainId, long serverId, long sequence) {
+ this.domainId = domainId;
+ this.serverId = serverId;
+ this.sequence = sequence;
+ }
+
+ public MariaGtid(String gtid) {
+ String[] gtidArr = gtid.split("-");
+ this.domainId = Long.parseLong(gtidArr[0]);
+ this.serverId = Long.parseLong(gtidArr[1]);
+ this.sequence = Long.parseLong(gtidArr[2]);
+ }
+
+ public static MariaGtid parse(String gtid) {
+ return new MariaGtid(gtid);
+ }
+
+ public long getDomainId() {
+ return domainId;
+ }
+
+ public void setDomainId(long domainId) {
+ this.domainId = domainId;
+ }
+
+ public long getServerId() {
+ return serverId;
+ }
+
+ public void setServerId(long serverId) {
+ this.serverId = serverId;
+ }
+
+ public long getSequence() {
+ return sequence;
+ }
+
+ public void setSequence(long sequence) {
+ this.sequence = sequence;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MariaGtid mariaGtid = (MariaGtid) o;
+ return domainId == mariaGtid.domainId &&
+ serverId == mariaGtid.serverId &&
+ sequence == mariaGtid.sequence;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s-%s-%s", domainId, serverId, sequence);
+ }
+ }
+}
+
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/AnnotateRowsEventData.java b/src/main/java/com/github/shyiko/mysql/binlog/event/AnnotateRowsEventData.java
new file mode 100644
index 00000000..85fa79e0
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/AnnotateRowsEventData.java
@@ -0,0 +1,31 @@
+package com.github.shyiko.mysql.binlog.event;
+
+/**
+ * Mariadb ANNOTATE_ROWS_EVENT events accompany row events and describe the query which caused the row event
+ * Enable this with --binlog-annotate-row-events (default on from MariaDB 10.2.4).
+ * In the binary log, each Annotate_rows event precedes the corresponding Table map event.
+ * Note the master server sends ANNOTATE_ROWS_EVENT events only if the Slave server connects
+ * with the BINLOG_SEND_ANNOTATE_ROWS_EVENT flag (value is 2) in the COM_BINLOG_DUMP Slave Registration phase.
+ *
+ * @author Winger
+ * @see ANNOTATE_ROWS_EVENT for the original doc
+ */
+public class AnnotateRowsEventData implements EventData {
+
+ private String rowsQuery;
+
+ public String getRowsQuery() {
+ return rowsQuery;
+ }
+
+ public void setRowsQuery(String rowsQuery) {
+ this.rowsQuery = rowsQuery;
+ }
+
+ @Override
+ public String toString() {
+ return "AnnotateRowsEventData{" +
+ "rowsQuery='" + rowsQuery + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/EventType.java b/src/main/java/com/github/shyiko/mysql/binlog/event/EventType.java
index 7f94ccfd..fb1fcaa8 100644
--- a/src/main/java/com/github/shyiko/mysql/binlog/event/EventType.java
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/EventType.java
@@ -16,99 +16,99 @@
package com.github.shyiko.mysql.binlog.event;
/**
+ * @author Stanley Shyiko
* @see Event Meanings for the original
* documentation.
- * @author Stanley Shyiko
*/
public enum EventType {
/**
* Events of this event type should never occur. Not written to a binary log.
*/
- UNKNOWN,
+ UNKNOWN(0),
/**
* A descriptor event that is written to the beginning of the each binary log file. (In MySQL 4.0 and 4.1,
* this event is written only to the first binary log file that the server creates after startup.) This event is
* used in MySQL 3.23 through 4.1 and superseded in MySQL 5.0 by {@link #FORMAT_DESCRIPTION}.
*/
- START_V3,
+ START_V3(1),
/**
* Written when an updating statement is done.
*/
- QUERY,
+ QUERY(2),
/**
* Written when mysqld stops.
*/
- STOP,
+ STOP(3),
/**
* Written when mysqld switches to a new binary log file. This occurs when someone issues a FLUSH LOGS statement or
* the current binary log file becomes larger than max_binlog_size.
*/
- ROTATE,
+ ROTATE(4),
/**
* Written every time a statement uses an AUTO_INCREMENT column or the LAST_INSERT_ID() function; precedes other
* events for the statement. This is written only before a {@link #QUERY} and is not used in case of RBR.
*/
- INTVAR,
+ INTVAR(5),
/**
* Used for LOAD DATA INFILE statements in MySQL 3.23.
*/
- LOAD,
+ LOAD(6),
/**
* Not used.
*/
- SLAVE,
+ SLAVE(7),
/**
* Used for LOAD DATA INFILE statements in MySQL 4.0 and 4.1.
*/
- CREATE_FILE,
+ CREATE_FILE(8),
/**
* Used for LOAD DATA INFILE statements as of MySQL 4.0.
*/
- APPEND_BLOCK,
+ APPEND_BLOCK(9),
/**
* Used for LOAD DATA INFILE statements in 4.0 and 4.1.
*/
- EXEC_LOAD,
+ EXEC_LOAD(10),
/**
* Used for LOAD DATA INFILE statements as of MySQL 4.0.
*/
- DELETE_FILE,
+ DELETE_FILE(11),
/**
* Used for LOAD DATA INFILE statements in MySQL 4.0 and 4.1.
*/
- NEW_LOAD,
+ NEW_LOAD(12),
/**
* Written every time a statement uses the RAND() function; precedes other events for the statement. Indicates the
* seed values to use for generating a random number with RAND() in the next statement. This is written only
* before a {@link #QUERY} and is not used in case of RBR.
*/
- RAND,
+ RAND(13),
/**
* Written every time a statement uses a user variable; precedes other events for the statement. Indicates the
* value to use for the user variable in the next statement. This is written only before a {@link #QUERY} and
* is not used in case of RBR.
*/
- USER_VAR,
+ USER_VAR(14),
/**
* A descriptor event that is written to the beginning of the each binary log file.
* This event is used as of MySQL 5.0; it supersedes {@link #START_V3}.
*/
- FORMAT_DESCRIPTION,
+ FORMAT_DESCRIPTION(15),
/**
* Generated for a commit of a transaction that modifies one or more tables of an XA-capable storage engine.
* Normal transactions are implemented by sending a {@link #QUERY} containing a BEGIN statement and a {@link #QUERY}
* containing a COMMIT statement (or a ROLLBACK statement if the transaction is rolled back).
*/
- XID,
+ XID(16),
/**
* Used for LOAD DATA INFILE statements as of MySQL 5.0.
*/
- BEGIN_LOAD_QUERY,
+ BEGIN_LOAD_QUERY(17),
/**
* Used for LOAD DATA INFILE statements as of MySQL 5.0.
*/
- EXECUTE_LOAD_QUERY,
+ EXECUTE_LOAD_QUERY(18),
/**
* This event precedes each row operation event. It maps a table definition to a number, where the table definition
* consists of database and table names and column definitions. The purpose of this event is to enable replication
@@ -117,105 +117,128 @@ public enum EventType {
* of TABLE_MAP events: one per table used by events in the sequence.
* Used in case of RBR.
*/
- TABLE_MAP,
+ TABLE_MAP(19),
/**
* Describes inserted rows (within a single table).
* Used in case of RBR (5.1.0 - 5.1.15).
*/
- PRE_GA_WRITE_ROWS,
+ PRE_GA_WRITE_ROWS(20),
/**
* Describes updated rows (within a single table).
* Used in case of RBR (5.1.0 - 5.1.15).
*/
- PRE_GA_UPDATE_ROWS,
+ PRE_GA_UPDATE_ROWS(21),
/**
* Describes deleted rows (within a single table).
* Used in case of RBR (5.1.0 - 5.1.15).
*/
- PRE_GA_DELETE_ROWS,
+ PRE_GA_DELETE_ROWS(22),
/**
* Describes inserted rows (within a single table).
* Used in case of RBR (5.1.16 - mysql-trunk).
*/
- WRITE_ROWS,
+ WRITE_ROWS(23),
/**
* Describes updated rows (within a single table).
* Used in case of RBR (5.1.16 - mysql-trunk).
*/
- UPDATE_ROWS,
+ UPDATE_ROWS(24),
/**
* Describes deleted rows (within a single table).
* Used in case of RBR (5.1.16 - mysql-trunk).
*/
- DELETE_ROWS,
+ DELETE_ROWS(25),
/**
* Used to log an out of the ordinary event that occurred on the master. It notifies the slave that something
* happened on the master that might cause data to be in an inconsistent state.
*/
- INCIDENT,
+ INCIDENT(26),
/**
* Sent by a master to a slave to let the slave know that the master is still alive. Not written to a binary log.
*/
- HEARTBEAT,
+ HEARTBEAT(27),
/**
* In some situations, it is necessary to send over ignorable data to the slave: data that a slave can handle in
* case there is code for handling it, but which can be ignored if it is not recognized.
*/
- IGNORABLE,
+ IGNORABLE(28),
/**
* Introduced to record the original query for rows events in RBR.
*/
- ROWS_QUERY,
+ ROWS_QUERY(29),
/**
* Describes inserted rows (within a single table).
* Used in case of RBR (5.1.18+).
*/
- EXT_WRITE_ROWS,
+ EXT_WRITE_ROWS(30),
/**
* Describes updated rows (within a single table).
* Used in case of RBR (5.1.18+).
*/
- EXT_UPDATE_ROWS,
+ EXT_UPDATE_ROWS(31),
/**
* Describes deleted rows (within a single table).
* Used in case of RBR (5.1.18+).
*/
- EXT_DELETE_ROWS,
+ EXT_DELETE_ROWS(32),
/**
* Global Transaction Identifier.
*/
- GTID,
- ANONYMOUS_GTID,
- PREVIOUS_GTIDS,
- TRANSACTION_CONTEXT,
- VIEW_CHANGE,
+ GTID(33),
+ ANONYMOUS_GTID(34),
+ PREVIOUS_GTIDS(35),
+ TRANSACTION_CONTEXT(36),
+ VIEW_CHANGE(37),
/**
* Prepared XA transaction terminal event similar to XID except that it is specific to XA transaction.
*/
- XA_PREPARE;
+ XA_PREPARE(38),
+
+ /**
+ * MariaDB Support Events
+ *
+ * @see Replication Protocol for the original doc.
+ */
+ ANNOTATE_ROWS(160), //
+ MARIADB_GTID(162),
+ MARIADB_GTID_LIST(163);
+
+ private final int eventNumber;
+
+ EventType(int eventNumber) {
+ this.eventNumber = eventNumber;
+ }
public static boolean isRowMutation(EventType eventType) {
return EventType.isWrite(eventType) ||
- EventType.isUpdate(eventType) ||
- EventType.isDelete(eventType);
+ EventType.isUpdate(eventType) ||
+ EventType.isDelete(eventType);
}
public static boolean isWrite(EventType eventType) {
return eventType == PRE_GA_WRITE_ROWS ||
- eventType == WRITE_ROWS ||
- eventType == EXT_WRITE_ROWS;
+ eventType == WRITE_ROWS ||
+ eventType == EXT_WRITE_ROWS;
}
public static boolean isUpdate(EventType eventType) {
return eventType == PRE_GA_UPDATE_ROWS ||
- eventType == UPDATE_ROWS ||
- eventType == EXT_UPDATE_ROWS;
+ eventType == UPDATE_ROWS ||
+ eventType == EXT_UPDATE_ROWS;
}
public static boolean isDelete(EventType eventType) {
return eventType == PRE_GA_DELETE_ROWS ||
- eventType == DELETE_ROWS ||
- eventType == EXT_DELETE_ROWS;
+ eventType == DELETE_ROWS ||
+ eventType == EXT_DELETE_ROWS;
}
+ public static EventType byEventNumber(int num) {
+ for (EventType type : EventType.values()) {
+ if (type.eventNumber == num) {
+ return type;
+ }
+ }
+ return null;
+ }
}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/MariadbGtidEventData.java b/src/main/java/com/github/shyiko/mysql/binlog/event/MariadbGtidEventData.java
new file mode 100644
index 00000000..54838d03
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/MariadbGtidEventData.java
@@ -0,0 +1,43 @@
+package com.github.shyiko.mysql.binlog.event;
+
+/**
+ * MariaDB and MySQL have different GTID implementations, and that these are not compatible with each other.
+ *
+ * @author Winger
+ * @see GTID_EVENT for the original doc
+ */
+public class MariadbGtidEventData implements EventData {
+
+ private long sequence;
+ private long domainId;
+ private long serverId;
+
+ public long getSequence() {
+ return sequence;
+ }
+
+ public void setSequence(long sequence) {
+ this.sequence = sequence;
+ }
+
+ public long getDomainId() {
+ return domainId;
+ }
+
+ public void setDomainId(long domainId) {
+ this.domainId = domainId;
+ }
+
+ public long getServerId() {
+ return serverId;
+ }
+
+ public void setServerId(long serverId) {
+ this.serverId = serverId;
+ }
+
+ @Override
+ public String toString() {
+ return domainId + "-" + serverId + "-" + sequence;
+ }
+}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/MariadbGtidListEventData.java b/src/main/java/com/github/shyiko/mysql/binlog/event/MariadbGtidListEventData.java
new file mode 100644
index 00000000..ae6e91f6
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/MariadbGtidListEventData.java
@@ -0,0 +1,29 @@
+package com.github.shyiko.mysql.binlog.event;
+
+import com.github.shyiko.mysql.binlog.MariadbGtidSet;
+
+/**
+ * Logged in every binlog to record the current replication state
+ *
+ * @author Winger
+ * @see GTID_LIST_EVENT for the original doc
+ */
+public class MariadbGtidListEventData implements EventData {
+
+ private MariadbGtidSet mariaGTIDSet;
+
+ public MariadbGtidSet getMariaGTIDSet() {
+ return mariaGTIDSet;
+ }
+
+ public void setMariaGTIDSet(MariadbGtidSet mariaGTIDSet) {
+ this.mariaGTIDSet = mariaGTIDSet;
+ }
+
+ @Override
+ public String toString() {
+ return "MariadbGtidListEventData{" +
+ "mariaGTIDSet=" + mariaGTIDSet +
+ '}';
+ }
+}
diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AnnotateRowsEventDataDeserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AnnotateRowsEventDataDeserializer.java
new file mode 100644
index 00000000..688a9b29
--- /dev/null
+++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/AnnotateRowsEventDataDeserializer.java
@@ -0,0 +1,24 @@
+package com.github.shyiko.mysql.binlog.event.deserialization;
+
+import com.github.shyiko.mysql.binlog.event.AnnotateRowsEventData;
+import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream;
+
+import java.io.IOException;
+
+/**
+ * Mariadb ANNOTATE_ROWS_EVENT Fields
+ *
+ * string The SQL statement (not null-terminated)
+ *