You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by al...@apache.org on 2020/09/11 10:17:12 UTC
[ignite] branch master updated: IGNITE-13414 JDBC Thin:
Compatibility fix for 2.8-2.9 versions - Fixes #8227.
This is an automated email from the ASF dual-hosted git repository.
alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 23cecab IGNITE-13414 JDBC Thin: Compatibility fix for 2.8-2.9 versions - Fixes #8227.
23cecab is described below
commit 23cecab5a8846939dbf12ddc62c763c0b1ffa320
Author: Aleksey Plekhanov <pl...@gmail.com>
AuthorDate: Fri Sep 11 13:15:21 2020 +0300
IGNITE-13414 JDBC Thin: Compatibility fix for 2.8-2.9 versions - Fixes #8227.
Signed-off-by: Aleksey Plekhanov <pl...@gmail.com>
---
.../jdbc/JdbcThinCompatibilityTest.java | 197 +++++++++++++++++++++
.../ignite/compatibility/jdbc/package-info.java | 22 +++
.../junits/IgniteCompatibilityAbstractTest.java | 87 ++++-----
.../IgniteCompatibilityBasicTestSuite.java | 4 +-
.../ignite/internal/jdbc/thin/JdbcThinTcpIo.java | 21 ++-
.../odbc/jdbc/JdbcConnectionContext.java | 12 +-
.../processors/odbc/jdbc/JdbcRequestHandler.java | 4 +-
7 files changed, 289 insertions(+), 58 deletions(-)
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/jdbc/JdbcThinCompatibilityTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/jdbc/JdbcThinCompatibilityTest.java
new file mode 100644
index 0000000..50254e6
--- /dev/null
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/jdbc/JdbcThinCompatibilityTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.compatibility.jdbc;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collection;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.compatibility.testframework.junits.Dependency;
+import org.apache.ignite.compatibility.testframework.junits.IgniteCompatibilityAbstractTest;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteVersionUtils;
+import org.apache.ignite.internal.util.GridJavaProcess;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.multijvm.IgniteProcessProxy;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * Tests that current client version can connect to the server with specified version and
+ * specified client version can connect to the current server version.
+ */
+@RunWith(Parameterized.class)
+public class JdbcThinCompatibilityTest extends IgniteCompatibilityAbstractTest {
+ /** Table name. */
+ private static final String TABLE_NAME = "test_table";
+
+ /** URL. */
+ private static final String URL = "jdbc:ignite:thin://127.0.0.1";
+
+ /** Rows count. */
+ private static final int ROWS_CNT = 10;
+
+ /** Parameters. */
+ @Parameterized.Parameters(name = "Version {0}")
+ public static Iterable<String[]> versions() {
+ return Arrays.asList(
+ new String[] {"2.7.0"},
+ new String[] {"2.7.5"},
+ new String[] {"2.7.6"},
+ new String[] {"2.8.0"},
+ new String[] {"2.8.1"}
+ );
+ }
+
+ /** Old Ignite version. */
+ @Parameterized.Parameter
+ public String ver;
+
+ /** {@inheritDoc} */
+ @Override protected @NotNull Collection<Dependency> getDependencies(String igniteVer) {
+ Collection<Dependency> dependencies = super.getDependencies(igniteVer);
+
+ dependencies.add(new Dependency("indexing", "ignite-indexing", false));
+
+ return dependencies;
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testOldClientToCurrentServer() throws Exception {
+ try (Ignite ignite = startGrid(0)) {
+ initTable(ignite);
+
+ GridJavaProcess proc = GridJavaProcess.exec(
+ JdbcThinQueryRunner.class.getName(),
+ null,
+ log,
+ log::info,
+ null,
+ null,
+ getProcessProxyJvmArgs(ver),
+ null
+ );
+
+ try {
+ GridTestUtils.waitForCondition(() -> !proc.getProcess().isAlive(), 5_000L);
+
+ assertEquals(0, proc.getProcess().exitValue());
+ }
+ finally {
+ if (proc.getProcess().isAlive())
+ proc.kill();
+ }
+ }
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testCurrentClientToOldServer() throws Exception {
+ IgniteProcessProxy proxy = null;
+
+ try {
+ Ignite ignite = startGrid(1, ver,
+ cfg -> cfg
+ .setLocalHost("127.0.0.1")
+ .setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(new TcpDiscoveryVmIpFinder(true))),
+ JdbcThinCompatibilityTest::initTable);
+
+ proxy = IgniteProcessProxy.ignite(ignite.name());
+
+ testJdbcQuery();
+ }
+ finally {
+ stopAllGrids();
+
+ if (proxy != null) {
+ Process proc = proxy.getProcess().getProcess();
+
+ // We should wait until process exits, or it can affect next tests.
+ GridTestUtils.waitForCondition(() -> !proc.isAlive(), 5_000L);
+ }
+ }
+ }
+
+ /** Execute sql. */
+ private static void executeSql(IgniteEx igniteEx, String sql) {
+ igniteEx.context().query().querySqlFields(new SqlFieldsQuery(sql), false).getAll();
+ }
+
+ /** */
+ private static void initTable(Ignite ignite) {
+ IgniteEx igniteEx = (IgniteEx)ignite;
+
+ executeSql(igniteEx, "CREATE TABLE " + TABLE_NAME + " (id int primary key, name varchar)");
+
+ for (int i = 0; i < ROWS_CNT; i++)
+ executeSql(igniteEx, "INSERT INTO " + TABLE_NAME + " (id, name) VALUES(" + i + ", 'name" + i + "')");
+ }
+
+ /** */
+ private static void testJdbcQuery() throws Exception {
+ try (Connection conn = DriverManager.getConnection(URL); Statement stmt = conn.createStatement()) {
+ ResultSet rs = stmt.executeQuery("SELECT id, name FROM " + TABLE_NAME + " ORDER BY id");
+
+ assertNotNull(rs);
+
+ int cnt = 0;
+
+ while (rs.next()) {
+ int id = rs.getInt("id");
+ String name = rs.getString("name");
+
+ assertEquals(cnt, id);
+ assertEquals("name" + cnt, name);
+
+ cnt++;
+ }
+
+ assertEquals(ROWS_CNT, cnt);
+ }
+ }
+
+ /**
+ * Runner class to test query from remote JVM process with old Ignite version as dependencies in class path.
+ */
+ public static class JdbcThinQueryRunner {
+ /** */
+ public static void main(String[] args) throws Exception {
+ X.println(GridJavaProcess.PID_MSG_PREFIX + U.jvmPid());
+ X.println("Start JDBC connection with Ignite version: " + IgniteVersionUtils.VER);
+
+ testJdbcQuery();
+
+ X.println("Success");
+ }
+ }
+}
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/jdbc/package-info.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/jdbc/package-info.java
new file mode 100644
index 0000000..50d961b
--- /dev/null
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/jdbc/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Contains compatibility tests related to JDBC.
+ */
+
+package org.apache.ignite.compatibility.jdbc;
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
index 2b5fd3c..e3f693a 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
@@ -159,46 +159,7 @@ public abstract class IgniteCompatibilityAbstractTest extends GridCommonAbstract
}
@Override protected Collection<String> filteredJvmArgs() throws Exception {
- Collection<String> filteredJvmArgs = new ArrayList<>();
-
- filteredJvmArgs.add("-ea");
-
- for (String arg : U.jvmArgs()) {
- if (arg.startsWith("-Xmx") || arg.startsWith("-Xms"))
- filteredJvmArgs.add(arg);
- }
-
- final Collection<Dependency> dependencies = getDependencies(ver);
-
- Set<String> excluded = getExcluded(ver, dependencies);
-
- StringBuilder pathBuilder = new StringBuilder();
-
- for (URL url : CompatibilityTestsUtils.classLoaderUrls(CLASS_LOADER)) {
- String path = url.getPath();
-
- if (excluded.stream().noneMatch(path::contains))
- pathBuilder.append(path).append(File.pathSeparator);
- }
-
- for (Dependency dependency : dependencies) {
- final String artifactVer = Optional.ofNullable(dependency.version()).orElse(ver);
-
- String pathToArtifact = MavenUtils.getPathToIgniteArtifact(dependency.groupId(),
- dependency.artifactId(), artifactVer, dependency.classifier());
-
- pathBuilder.append(pathToArtifact).append(File.pathSeparator);
- }
-
- filteredJvmArgs.add("-cp");
- filteredJvmArgs.add(pathBuilder.toString());
-
- final Collection<String> jvmParms = getJvmParams();
-
- if (jvmParms != null)
- filteredJvmArgs.addAll(jvmParms);
-
- return filteredJvmArgs;
+ return getProcessProxyJvmArgs(ver);
}
};
@@ -227,6 +188,52 @@ public abstract class IgniteCompatibilityAbstractTest extends GridCommonAbstract
}
/**
+ * Creates list of JVM arguments to be used to start new Ignite process in separate JVM.
+ */
+ protected Collection<String> getProcessProxyJvmArgs(String ver) throws Exception {
+ Collection<String> filteredJvmArgs = new ArrayList<>();
+
+ filteredJvmArgs.add("-ea");
+
+ for (String arg : U.jvmArgs()) {
+ if (arg.startsWith("-Xmx") || arg.startsWith("-Xms"))
+ filteredJvmArgs.add(arg);
+ }
+
+ final Collection<Dependency> dependencies = getDependencies(ver);
+
+ Set<String> excluded = getExcluded(ver, dependencies);
+
+ StringBuilder pathBuilder = new StringBuilder();
+
+ for (URL url : CompatibilityTestsUtils.classLoaderUrls(CLASS_LOADER)) {
+ String path = url.getPath();
+
+ if (excluded.stream().noneMatch(path::contains))
+ pathBuilder.append(path).append(File.pathSeparator);
+ }
+
+ for (Dependency dependency : dependencies) {
+ final String artifactVer = Optional.ofNullable(dependency.version()).orElse(ver);
+
+ String pathToArtifact = MavenUtils.getPathToIgniteArtifact(dependency.groupId(),
+ dependency.artifactId(), artifactVer, dependency.classifier());
+
+ pathBuilder.append(pathToArtifact).append(File.pathSeparator);
+ }
+
+ filteredJvmArgs.add("-cp");
+ filteredJvmArgs.add(pathBuilder.toString());
+
+ final Collection<String> jvmParms = getJvmParams();
+
+ if (jvmParms != null)
+ filteredJvmArgs.addAll(jvmParms);
+
+ return filteredJvmArgs;
+ }
+
+ /**
* Total amount of milliseconds.
*
* @return timeout in ms.
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java
index 27fdb1a..4da7401a 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testsuites/IgniteCompatibilityBasicTestSuite.java
@@ -18,6 +18,7 @@
package org.apache.ignite.compatibility.testsuites;
import org.apache.ignite.compatibility.cache.LocalCacheTest;
+import org.apache.ignite.compatibility.jdbc.JdbcThinCompatibilityTest;
import org.apache.ignite.compatibility.persistence.FoldersReuseCompatibilityTest;
import org.apache.ignite.compatibility.persistence.MetaStorageCompatibilityTest;
import org.apache.ignite.compatibility.persistence.MigratingToWalV2SerializerWithCompactionTest;
@@ -36,7 +37,8 @@ import org.junit.runners.Suite;
MigratingToWalV2SerializerWithCompactionTest.class,
MetaStorageCompatibilityTest.class,
LocalCacheTest.class,
- MoveBinaryMetadataCompatibility.class
+ MoveBinaryMetadataCompatibility.class,
+ JdbcThinCompatibilityTest.class
})
public class IgniteCompatibilityBasicTestSuite {
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
index 9129666..b8c5cd4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
@@ -94,11 +94,11 @@ public class JdbcThinTcpIo {
/** Version 2.8.0. */
private static final ClientListenerProtocolVersion VER_2_8_0 = ClientListenerProtocolVersion.create(2, 8, 0);
- /** Version 2.8.1. Adds features flags support. */
- private static final ClientListenerProtocolVersion VER_2_8_1 = ClientListenerProtocolVersion.create(2, 8, 1);
+ /** Version 2.9.0. Adds user attributes support. Adds features flags support. */
+ private static final ClientListenerProtocolVersion VER_2_9_0 = ClientListenerProtocolVersion.create(2, 9, 0);
/** Current version. */
- private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_8_1;
+ private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_9_0;
/** Initial output stream capacity for handshake. */
private static final int HANDSHAKE_MSG_SIZE = 13;
@@ -285,7 +285,9 @@ public class JdbcThinTcpIo {
writer.writeByte(nullableBooleanToByte(connProps.isDataPageScanEnabled()));
JdbcUtils.writeNullableInteger(writer, connProps.getUpdateBatchSize());
+ }
+ if (ver.compareTo(VER_2_9_0) >= 0) {
String userAttrs = connProps.getUserAttributesFactory();
if (F.isEmpty(userAttrs))
@@ -304,10 +306,9 @@ public class JdbcThinTcpIo {
SqlStateCode.CLIENT_CONNECTION_FAILED, e);
}
}
- }
- if (ver.compareTo(VER_2_8_1) >= 0)
writer.writeByteArray(ThinProtocolFeature.featuresAsBytes(enabledFeatures()));
+ }
if (!F.isEmpty(connProps.getUsername())) {
assert ver.compareTo(VER_2_5_0) >= 0 : "Authentication is supported since 2.5";
@@ -341,7 +342,7 @@ public class JdbcThinTcpIo {
handshakeRes.igniteVersion(new IgniteProductVersion(maj, min, maintenance, stage, ts, hash));
- if (ver.compareTo(VER_2_8_1) >= 0) {
+ if (ver.compareTo(VER_2_9_0) >= 0) {
byte[] srvFeatures = reader.readByteArray();
EnumSet<JdbcThinFeature> features = JdbcThinFeature.enumSet(srvFeatures);
@@ -373,7 +374,8 @@ public class JdbcThinTcpIo {
+ ", url=" + connProps.getUrl() + " address=" + sockAddr + ']', SqlStateCode.CONNECTION_REJECTED);
}
- if (VER_2_7_0.equals(srvProtoVer0)
+ if (VER_2_8_0.equals(srvProtoVer0)
+ || VER_2_7_0.equals(srvProtoVer0)
|| VER_2_5_0.equals(srvProtoVer0)
|| VER_2_4_0.equals(srvProtoVer0)
|| VER_2_3_0.equals(srvProtoVer0)
@@ -736,8 +738,9 @@ public class JdbcThinTcpIo {
}
/**
- * Set of features enabled on clien side. To get features
- * supported by both sides use {@link #protoCtx}.
+ * Set of features enabled on client side. To get features supported by both sides use {@link #protoCtx}.
+ * Since {@link #protoCtx} only available after handshake, any handshake protocol change should not use features,
+ * but increment protocol version.
*/
private EnumSet<JdbcThinFeature> enabledFeatures() {
EnumSet<JdbcThinFeature> features = JdbcThinFeature.allFeaturesAsEnumSet();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java
index 2359e98..0d9ea39 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java
@@ -65,11 +65,11 @@ public class JdbcConnectionContext extends ClientListenerAbstractConnectionConte
/** Version 2.8.0: adds query id in order to implement cancel feature, partition awareness support: IEP-23.*/
static final ClientListenerProtocolVersion VER_2_8_0 = ClientListenerProtocolVersion.create(2, 8, 0);
- /** Version 2.8.1: adds features flags support.*/
- static final ClientListenerProtocolVersion VER_2_8_1 = ClientListenerProtocolVersion.create(2, 8, 1);
+ /** Version 2.9.0: adds user attributes, adds features flags support. */
+ static final ClientListenerProtocolVersion VER_2_9_0 = ClientListenerProtocolVersion.create(2, 9, 0);
/** Current version. */
- public static final ClientListenerProtocolVersion CURRENT_VER = VER_2_8_1;
+ public static final ClientListenerProtocolVersion CURRENT_VER = VER_2_9_0;
/** Supported versions. */
private static final Set<ClientListenerProtocolVersion> SUPPORTED_VERS = new HashSet<>();
@@ -97,7 +97,7 @@ public class JdbcConnectionContext extends ClientListenerAbstractConnectionConte
static {
SUPPORTED_VERS.add(CURRENT_VER);
- SUPPORTED_VERS.add(VER_2_8_1);
+ SUPPORTED_VERS.add(VER_2_9_0);
SUPPORTED_VERS.add(VER_2_8_0);
SUPPORTED_VERS.add(VER_2_7_0);
SUPPORTED_VERS.add(VER_2_5_0);
@@ -179,11 +179,11 @@ public class JdbcConnectionContext extends ClientListenerAbstractConnectionConte
dataPageScanEnabled = nullableBooleanFromByte(reader.readByte());
updateBatchSize = JdbcUtils.readNullableInteger(reader);
+ }
+ if (ver.compareTo(VER_2_9_0) >= 0) {
userAttrs = reader.readMap();
- }
- if (ver.compareTo(VER_2_8_1) >= 0) {
byte[] cliFeatures = reader.readByteArray();
features = JdbcThinFeature.enumSet(cliFeatures);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
index c64e776..ecf6fbf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
@@ -91,7 +91,7 @@ import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionCont
import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext.VER_2_4_0;
import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext.VER_2_7_0;
import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext.VER_2_8_0;
-import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext.VER_2_8_1;
+import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext.VER_2_9_0;
import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.BATCH_EXEC;
import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.BATCH_EXEC_ORDERED;
import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.BINARY_TYPE_GET;
@@ -534,7 +534,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
writer.writeUuid(connCtx.kernalContext().localNodeId());
// Write all features supported by the node.
- if (protocolVer.compareTo(VER_2_8_1) >= 0)
+ if (protocolVer.compareTo(VER_2_9_0) >= 0)
writer.writeByteArray(ThinProtocolFeature.featuresAsBytes(connCtx.protocolContext().features()));
}