You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2019/01/24 12:29:24 UTC
[ignite] branch master updated: IGNITE-10874: JDBC Thin Driver:
fixed underscore handling in metadata. This closes #5899.
This is an automated email from the ASF dual-hosted git repository.
vozerov 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 4d7a076 IGNITE-10874: JDBC Thin Driver: fixed underscore handling in metadata. This closes #5899.
new 6a61ec9 Merge remote-tracking branch 'origin/master'
4d7a076 is described below
commit 4d7a0760278083236b31b732d5f054f2a8fcc88d
Author: Pavel Kuznetsov <pa...@gmail.com>
AuthorDate: Thu Jan 24 15:28:57 2019 +0300
IGNITE-10874: JDBC Thin Driver: fixed underscore handling in metadata. This closes #5899.
---
.../ignite/jdbc/JdbcThinMetadataSqlMatchTest.java | 150 +++++++++++++++++++++
.../jdbc/suite/IgniteJdbcDriverTestSuite.java | 2 +
.../thin/JdbcThinMetadataPrimaryKeysSelfTest.java | 2 +-
.../internal/processors/odbc/SqlListenerUtils.java | 18 +++
.../processors/odbc/jdbc/JdbcRequestHandler.java | 16 ++-
.../internal/processors/odbc/odbc/OdbcUtils.java | 11 +-
6 files changed, 186 insertions(+), 13 deletions(-)
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcThinMetadataSqlMatchTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcThinMetadataSqlMatchTest.java
new file mode 100644
index 0000000..d3d207a
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcThinMetadataSqlMatchTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.jdbc;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+
+/**
+ * Verify we are able to escape "_" character in the metadata request.
+ */
+@RunWith(JUnit4.class)
+public class JdbcThinMetadataSqlMatchTest extends GridCommonAbstractTest {
+ /** Connection. */
+ private Connection conn;
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ IgniteEx ign = startGrid(0);
+
+ conn = GridTestUtils.connect(ign, null);
+ }
+
+ /**
+ * Execute ddl query via jdbc driver.
+ */
+ protected void executeDDl(String sql) throws SQLException {
+ try (PreparedStatement upd = conn.prepareStatement(sql)) {
+ upd.executeUpdate();
+ }
+ }
+
+ /**
+ * Get tables by name pattern using jdbc metadata request.
+ *
+ * @param tabNamePtrn Table name pattern.
+ */
+ protected List<String> getTableNames(String tabNamePtrn) throws SQLException {
+ ArrayList<String> names = new ArrayList<>();
+
+ try (ResultSet tabsRs =
+ conn.getMetaData().getTables(null, null, tabNamePtrn, new String[] {"TABLE"})) {
+ while (tabsRs.next())
+ names.add(tabsRs.getString("TABLE_NAME"));
+ }
+
+ // Actually metadata should be sorted by TABLE_NAME but it's broken.
+ Collections.sort(names);
+
+ return names;
+ }
+
+ /** Create tables. */
+ @Before
+ public void createTables() throws Exception {
+ executeDDl("CREATE TABLE MY_FAV_TABLE (id INT PRIMARY KEY, val VARCHAR)");
+ executeDDl("CREATE TABLE MY0FAV0TABLE (id INT PRIMARY KEY, val VARCHAR)");
+ executeDDl("CREATE TABLE OTHER_TABLE (id INT PRIMARY KEY, val VARCHAR)");
+ }
+
+ /** Drop tables. */
+ @After
+ public void dropTables() throws Exception {
+ // two tables that both matched by "TABLE MY_FAV_TABLE" sql pattern:
+ executeDDl("DROP TABLE MY_FAV_TABLE");
+ executeDDl("DROP TABLE MY0FAV0TABLE");
+
+ // and another one that doesn't:
+ executeDDl("DROP TABLE OTHER_TABLE");
+ }
+
+ /**
+ * Test for escaping the "_" character in the table metadata request
+ */
+ @Test
+ public void testTablesMatch() throws SQLException {
+ assertEqualsCollections(asList("MY0FAV0TABLE", "MY_FAV_TABLE"), getTableNames("MY_FAV_TABLE"));
+ assertEqualsCollections(singletonList("MY_FAV_TABLE"), getTableNames("MY\\_FAV\\_TABLE"));
+
+ assertEqualsCollections(Collections.emptyList(), getTableNames("\\%"));
+ assertEqualsCollections(asList("MY0FAV0TABLE", "MY_FAV_TABLE", "OTHER_TABLE"), getTableNames("%"));
+
+ assertEqualsCollections(Collections.emptyList(), getTableNames(""));
+ assertEqualsCollections(asList("MY0FAV0TABLE", "MY_FAV_TABLE", "OTHER_TABLE"), getTableNames(null));
+ }
+
+ /**
+ * Assert that collections contains the same elements regardless their order. Each element from the second
+ * collection should be met in the first one exact the same times. This method is required in this test because
+ *
+ * @param exp Expected.
+ * @param actual Actual.
+ */
+ private void assertEqNoOrder(Collection<String> exp, Collection<String> actual) {
+ ArrayList<String> expSorted = new ArrayList<>(exp);
+ ArrayList<String> actSorted = new ArrayList<>(exp);
+
+ Collections.sort(expSorted);
+ Collections.sort(actSorted);
+
+ assertEqualsCollections(expSorted, actSorted);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTestsStopped() throws Exception {
+ try {
+ conn.close();
+
+ conn = null;
+
+ stopAllGrids();
+ }
+ finally {
+ super.afterTestsStopped();
+ }
+ }
+}
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
index 6f8da20..d78e7b5 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
@@ -33,6 +33,7 @@ import org.apache.ignite.jdbc.JdbcPojoQuerySelfTest;
import org.apache.ignite.jdbc.JdbcPreparedStatementSelfTest;
import org.apache.ignite.jdbc.JdbcResultSetSelfTest;
import org.apache.ignite.jdbc.JdbcStatementSelfTest;
+import org.apache.ignite.jdbc.JdbcThinMetadataSqlMatchTest;
import org.apache.ignite.jdbc.thin.JdbcThinAuthenticateConnectionSelfTest;
import org.apache.ignite.jdbc.thin.JdbcThinAutoCloseServerCursorTest;
import org.apache.ignite.jdbc.thin.JdbcThinBatchSelfTest;
@@ -165,6 +166,7 @@ import org.junit.runners.Suite;
JdbcThinEmptyCacheSelfTest.class,
JdbcThinMetadataSelfTest.class,
JdbcThinMetadataPrimaryKeysSelfTest.class,
+ JdbcThinMetadataSqlMatchTest.class,
JdbcThinErrorsSelfTest.class,
JdbcThinStatementCancelSelfTest.class,
JdbcThinStatementTimeoutSelfTest.class,
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataPrimaryKeysSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataPrimaryKeysSelfTest.java
index a4ef311..ee2f234 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataPrimaryKeysSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataPrimaryKeysSelfTest.java
@@ -139,7 +139,7 @@ public class JdbcThinMetadataPrimaryKeysSelfTest extends GridCommonAbstractTest
try (Connection conn = DriverManager.getConnection(URL)) {
DatabaseMetaData md = conn.getMetaData();
- ResultSet rs = md.getPrimaryKeys(conn.getCatalog(), "", tabName);
+ ResultSet rs = md.getPrimaryKeys(conn.getCatalog(), null, tabName);
List<String> colNames = new ArrayList<>();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerUtils.java
index 306e1be..0c3b2c3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerUtils.java
@@ -26,6 +26,7 @@ import org.apache.ignite.internal.binary.BinaryReaderExImpl;
import org.apache.ignite.internal.binary.BinaryUtils;
import org.apache.ignite.internal.binary.BinaryWriterExImpl;
import org.apache.ignite.internal.binary.GridBinaryMarshaller;
+import org.apache.ignite.internal.util.typedef.F;
import org.jetbrains.annotations.Nullable;
/**
@@ -252,4 +253,21 @@ public abstract class SqlListenerUtils {
|| cls == Timestamp[].class
|| cls == java.util.Date[].class || cls == java.sql.Date[].class;
}
+
+ /**
+ * Converts sql pattern wildcards into java regex wildcards.
+ * Translates "_" to "." and "%" to ".*" if those are not escaped with "\" ("\_" or "\%").
+ */
+ public static String translateSqlWildcardsToRegex(String sqlPtrn) {
+ if (F.isEmpty(sqlPtrn))
+ return sqlPtrn;
+
+ String toRegex = ' ' + sqlPtrn;
+
+ toRegex = toRegex.replaceAll("([^\\\\])%", "$1.*");
+ toRegex = toRegex.replaceAll("([^\\\\])_", "$1.");
+ toRegex = toRegex.replaceAll("\\\\(.)", "$1");
+
+ return toRegex.substring(1);
+ }
}
\ No newline at end of file
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 b48c827..7f19491 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
@@ -54,6 +54,7 @@ import org.apache.ignite.internal.processors.odbc.ClientListenerRequest;
import org.apache.ignite.internal.processors.odbc.ClientListenerRequestHandler;
import org.apache.ignite.internal.processors.odbc.ClientListenerResponse;
import org.apache.ignite.internal.processors.odbc.ClientListenerResponseSender;
+import org.apache.ignite.internal.processors.odbc.SqlListenerUtils;
import org.apache.ignite.internal.processors.odbc.odbc.OdbcQueryGetColumnsMetaRequest;
import org.apache.ignite.internal.processors.query.GridQueryCancel;
import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
@@ -1220,12 +1221,19 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
* Checks whether string matches SQL pattern.
*
* @param str String.
- * @param ptrn Pattern.
+ * @param sqlPtrn Pattern.
* @return Whether string matches pattern.
*/
- private static boolean matches(String str, String ptrn) {
- return str != null && (F.isEmpty(ptrn) ||
- str.matches(ptrn.replace("%", ".*").replace("_", ".")));
+ private static boolean matches(String str, String sqlPtrn) {
+ if (str == null)
+ return false;
+
+ if (sqlPtrn == null)
+ return true;
+
+ String regex = SqlListenerUtils.translateSqlWildcardsToRegex(sqlPtrn);
+
+ return str.matches(regex);
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcUtils.java
index d294ac2..c55ff1d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcUtils.java
@@ -24,6 +24,7 @@ import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
import org.apache.ignite.internal.processors.odbc.SqlListenerDataTypes;
+import org.apache.ignite.internal.processors.odbc.SqlListenerUtils;
import org.apache.ignite.internal.processors.query.IgniteSQLException;
import org.apache.ignite.internal.util.typedef.F;
@@ -67,15 +68,9 @@ public class OdbcUtils {
if (F.isEmpty(ptrn))
return ptrn;
- String ptrn0 = ' ' + removeQuotationMarksIfNeeded(ptrn.toUpperCase());
+ String ptrn0 = removeQuotationMarksIfNeeded(ptrn.toUpperCase());
- ptrn0 = ptrn0.replaceAll("([^\\\\])%", "$1.*");
-
- ptrn0 = ptrn0.replaceAll("([^\\\\])_", "$1.");
-
- ptrn0 = ptrn0.replaceAll("\\\\(.)", "$1");
-
- return ptrn0.substring(1);
+ return SqlListenerUtils.translateSqlWildcardsToRegex(ptrn0);
}
/**