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/02/01 13:29:44 UTC
[ignite] branch master updated: IGNITE-9989: JDBC: Fixed metadata
pattern handling for JDBCv2 driver. Moved metadata management code common
to v2 and thin drivers to a single place. This closes #5716.
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 bf49d56 IGNITE-9989: JDBC: Fixed metadata pattern handling for JDBCv2 driver. Moved metadata management code common to v2 and thin drivers to a single place. This closes #5716.
bf49d56 is described below
commit bf49d56cc0635a5962523415c6a9d97a31c4e62c
Author: Pavel Kuznetsov <pa...@gmail.com>
AuthorDate: Fri Feb 1 16:29:20 2019 +0300
IGNITE-9989: JDBC: Fixed metadata pattern handling for JDBCv2 driver. Moved metadata management code common to v2 and thin drivers to a single place. This closes #5716.
---
.../internal/jdbc2/JdbcMetadataSelfTest.java | 88 +++++--
.../ignite/jdbc/thin/JdbcThinMetadataSelfTest.java | 26 +-
.../jdbc/thin/JdbcThinDatabaseMetadata.java | 123 +--------
.../ignite/internal/jdbc2/JdbcConnection.java | 4 +-
.../internal/jdbc2/JdbcDatabaseMetadata.java | 289 ++++++---------------
.../apache/ignite/internal/jdbc2/JdbcUtils.java | 125 ++++++++-
.../processors/odbc/jdbc/JdbcMetadataInfo.java | 269 +++++++++++++++++++
.../processors/odbc/jdbc/JdbcRequestHandler.java | 172 ++----------
.../internal/processors/query/QueryUtils.java | 26 +-
.../processors/query/h2/dml/UpdatePlanBuilder.java | 3 +
.../Cache/Query/CacheDmlQueriesTest.cs | 2 +-
11 files changed, 604 insertions(+), 523 deletions(-)
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
index f845b9e..ad21e6a 100755
--- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
@@ -21,6 +21,7 @@ import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
+import java.sql.Date;
import java.sql.DriverManager;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
@@ -29,7 +30,6 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
-import java.sql.Date;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -51,10 +51,10 @@ import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
+import static java.sql.Types.DATE;
+import static java.sql.Types.DECIMAL;
import static java.sql.Types.INTEGER;
import static java.sql.Types.VARCHAR;
-import static java.sql.Types.DECIMAL;
-import static java.sql.Types.DATE;
import static org.apache.ignite.IgniteJdbcDriver.CFG_URL_PREFIX;
import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -129,6 +129,21 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
personCache.put(new AffinityKey<>("p1", "o1"), new Person("John White", 25, 1));
personCache.put(new AffinityKey<>("p2", "o1"), new Person("Joe Black", 35, 1));
personCache.put(new AffinityKey<>("p3", "o2"), new Person("Mike Green", 40, 2));
+
+ jcache(grid(0),
+ defaultCacheConfiguration().setIndexedTypes(Integer.class, Department.class),
+ "dep");
+
+ try (Connection conn = DriverManager.getConnection(BASE_URL)) {
+ Statement stmt = conn.createStatement();
+
+ stmt.execute("CREATE TABLE PUBLIC.TEST (ID INT, NAME VARCHAR(50) default 'default name', " +
+ "age int default 21, VAL VARCHAR(50), PRIMARY KEY (ID, NAME))");
+ stmt.execute("CREATE TABLE PUBLIC.\"Quoted\" (\"Id\" INT primary key, \"Name\" VARCHAR(50)) WITH WRAP_KEY");
+ stmt.execute("CREATE INDEX \"MyTestIndex quoted\" on PUBLIC.\"Quoted\" (\"Id\" DESC)");
+ stmt.execute("CREATE INDEX IDX ON PUBLIC.TEST (ID ASC)");
+ stmt.execute("CREATE TABLE PUBLIC.TEST_DECIMAL_COLUMN (ID INT primary key, DEC_COL DECIMAL(8, 3))");
+ }
}
/**
@@ -213,28 +228,28 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
assertNotNull(rs);
assertTrue(rs.next());
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
- assertEquals(JdbcDatabaseMetadata.CATALOG_NAME, rs.getString("TABLE_CAT"));
+ assertEquals(JdbcUtils.CATALOG_NAME, rs.getString("TABLE_CAT"));
assertEquals("PERSON", rs.getString("TABLE_NAME"));
rs = meta.getTables(null, "org", "%", new String[]{"TABLE"});
assertNotNull(rs);
assertTrue(rs.next());
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
- assertEquals(JdbcDatabaseMetadata.CATALOG_NAME, rs.getString("TABLE_CAT"));
+ assertEquals(JdbcUtils.CATALOG_NAME, rs.getString("TABLE_CAT"));
assertEquals("ORGANIZATION", rs.getString("TABLE_NAME"));
rs = meta.getTables(null, "pers", "%", null);
assertNotNull(rs);
assertTrue(rs.next());
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
- assertEquals(JdbcDatabaseMetadata.CATALOG_NAME, rs.getString("TABLE_CAT"));
+ assertEquals(JdbcUtils.CATALOG_NAME, rs.getString("TABLE_CAT"));
assertEquals("PERSON", rs.getString("TABLE_NAME"));
rs = meta.getTables(null, "org", "%", null);
assertNotNull(rs);
assertTrue(rs.next());
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
- assertEquals(JdbcDatabaseMetadata.CATALOG_NAME, rs.getString("TABLE_CAT"));
+ assertEquals(JdbcUtils.CATALOG_NAME, rs.getString("TABLE_CAT"));
assertEquals("ORGANIZATION", rs.getString("TABLE_NAME"));
rs = meta.getTables(null, "PUBLIC", "", new String[]{"WRONG"});
@@ -447,18 +462,30 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
*/
@Test
public void testPrimaryKeyMetadata() throws Exception {
- try (Connection conn = DriverManager.getConnection(BASE_URL);
- ResultSet rs = conn.getMetaData().getPrimaryKeys(null, "pers", "PERSON")) {
-
- int cnt = 0;
-
- while (rs.next()) {
- assertEquals("_KEY", rs.getString("COLUMN_NAME"));
-
- cnt++;
+ try (Connection conn = DriverManager.getConnection(BASE_URL)) {
+ ResultSet rs = conn.getMetaData().getPrimaryKeys(null, null, null);
+
+ // TABLE_SCHEM.TABLE_NAME.PK_NAME.COLUMN_NAME
+ Set<String> expectedPks = new HashSet<>(Arrays.asList(
+ "org.ORGANIZATION.PK_org_ORGANIZATION._KEY",
+ "pers.PERSON.PK_pers_PERSON._KEY",
+ "dep.DEPARTMENT.PK_dep_DEPARTMENT._KEY",
+ "PUBLIC.TEST.PK_PUBLIC_TEST.ID",
+ "PUBLIC.TEST.PK_PUBLIC_TEST.NAME",
+ "PUBLIC.Quoted.PK_PUBLIC_Quoted.Id",
+ "PUBLIC.TEST_DECIMAL_COLUMN.ID.ID",
+ "metaTest.METATEST.PK_metaTest_METATEST._KEY"));
+
+ Set<String> actualPks = new HashSet<>(expectedPks.size());
+
+ while(rs.next()) {
+ actualPks.add(rs.getString("TABLE_SCHEM") +
+ '.' + rs.getString("TABLE_NAME") +
+ '.' + rs.getString("PK_NAME") +
+ '.' + rs.getString("COLUMN_NAME"));
}
- assertEquals(1, cnt);
+ assertEquals("Metadata contains unexpected primary keys info.", expectedPks, actualPks);
}
}
@@ -495,7 +522,7 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
try (Connection conn = DriverManager.getConnection(BASE_URL)) {
ResultSet rs = conn.getMetaData().getSchemas();
- Set<String> expectedSchemas = new HashSet<>(Arrays.asList("pers", "org", "metaTest"));
+ Set<String> expectedSchemas = new HashSet<>(Arrays.asList("pers", "org", "metaTest", "dep", "PUBLIC"));
Set<String> schemas = new HashSet<>();
@@ -503,7 +530,7 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
schemas.add(rs.getString(1));
assertEquals("There is only one possible catalog.",
- JdbcDatabaseMetadata.CATALOG_NAME, rs.getString(2));
+ JdbcUtils.CATALOG_NAME, rs.getString(2));
}
assertEquals(expectedSchemas, schemas);
@@ -609,4 +636,27 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
this.decimal = decimal;
}
}
+
+ /**
+ * Department.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ private static class Department implements Serializable {
+ /** ID. */
+ @QuerySqlField
+ private final int id;
+
+ /** Name. */
+ @QuerySqlField(precision = 43)
+ private final String name;
+
+ /**
+ * @param id ID.
+ * @param name Name.
+ */
+ private Department(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
}
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
index edbe6a5..13ae776 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
@@ -44,16 +44,16 @@ import org.apache.ignite.cache.affinity.AffinityKey;
import org.apache.ignite.cache.query.annotations.QuerySqlField;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.internal.IgniteVersionUtils;
-import org.apache.ignite.internal.jdbc.thin.JdbcThinDatabaseMetadata;
+import org.apache.ignite.internal.jdbc2.JdbcUtils;
import org.apache.ignite.internal.processors.query.QueryEntityEx;
import org.apache.ignite.internal.util.typedef.F;
import org.junit.Test;
-import static java.sql.Types.INTEGER;
-import static java.sql.Types.VARCHAR;
-import static java.sql.Types.DECIMAL;
import static java.sql.Types.DATE;
+import static java.sql.Types.DECIMAL;
+import static java.sql.Types.INTEGER;
import static java.sql.Types.OTHER;
+import static java.sql.Types.VARCHAR;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
@@ -128,8 +128,9 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
personCache.put(new AffinityKey<>("p2", "o1"), new Person("Joe Black", 35, 1));
personCache.put(new AffinityKey<>("p3", "o2"), new Person("Mike Green", 40, 2));
- IgniteCache<Integer, Department> departmentCache = jcache(grid(0),
- defaultCacheConfiguration().setIndexedTypes(Integer.class, Department.class), "dep");
+ jcache(grid(0),
+ defaultCacheConfiguration().setIndexedTypes(Integer.class, Department.class),
+ "dep");
try (Connection conn = DriverManager.getConnection(URL)) {
Statement stmt = conn.createStatement();
@@ -229,7 +230,7 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
assertNotNull(rs);
assertTrue(rs.next());
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
- assertEquals(JdbcThinDatabaseMetadata.CATALOG_NAME, rs.getString("TABLE_CAT"));
+ assertEquals(JdbcUtils.CATALOG_NAME, rs.getString("TABLE_CAT"));
assertEquals("PERSON", rs.getString("TABLE_NAME"));
assertFalse(rs.next());
@@ -238,7 +239,7 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
assertNotNull(rs);
assertTrue(rs.next());
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
- assertEquals(JdbcThinDatabaseMetadata.CATALOG_NAME, rs.getString("TABLE_CAT"));
+ assertEquals(JdbcUtils.CATALOG_NAME, rs.getString("TABLE_CAT"));
assertEquals("ORGANIZATION", rs.getString("TABLE_NAME"));
assertFalse(rs.next());
@@ -247,7 +248,7 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
assertNotNull(rs);
assertTrue(rs.next());
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
- assertEquals(JdbcThinDatabaseMetadata.CATALOG_NAME, rs.getString("TABLE_CAT"));
+ assertEquals(JdbcUtils.CATALOG_NAME, rs.getString("TABLE_CAT"));
assertEquals("PERSON", rs.getString("TABLE_NAME"));
assertFalse(rs.next());
@@ -256,7 +257,7 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
assertNotNull(rs);
assertTrue(rs.next());
assertEquals("TABLE", rs.getString("TABLE_TYPE"));
- assertEquals(JdbcThinDatabaseMetadata.CATALOG_NAME, rs.getString("TABLE_CAT"));
+ assertEquals(JdbcUtils.CATALOG_NAME, rs.getString("TABLE_CAT"));
assertEquals("ORGANIZATION", rs.getString("TABLE_NAME"));
assertFalse(rs.next());
@@ -611,8 +612,7 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
'.' + rs.getString("COLUMN_NAME"));
}
- assert expectedPks.equals(actualPks) : "expectedPks=" + expectedPks +
- ", actualPks" + actualPks;
+ assertEquals("Metadata contains unexpected primary keys info.", expectedPks, actualPks);
}
}
@@ -657,7 +657,7 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
schemas.add(rs.getString(1));
assertEquals("There is only one possible catalog.",
- JdbcThinDatabaseMetadata.CATALOG_NAME, rs.getString(2));
+ JdbcUtils.CATALOG_NAME, rs.getString(2));
}
assert expectedSchemas.equals(schemas) : "Unexpected schemas: " + schemas +
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java
index d1a5f6d..0de592e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java
@@ -29,6 +29,7 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.apache.ignite.internal.IgniteVersionUtils;
+import org.apache.ignite.internal.jdbc2.JdbcUtils;
import org.apache.ignite.internal.processors.odbc.jdbc.JdbcColumnMeta;
import org.apache.ignite.internal.processors.odbc.jdbc.JdbcIndexMeta;
import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaColumnsRequest;
@@ -50,15 +51,17 @@ import static java.sql.ResultSet.CONCUR_READ_ONLY;
import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
import static java.sql.ResultSet.TYPE_FORWARD_ONLY;
import static java.sql.RowIdLifetime.ROWID_UNSUPPORTED;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.CATALOG_NAME;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.columnRow;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.indexRows;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.primaryKeyRows;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.tableRow;
/**
* JDBC database metadata implementation.
*/
@SuppressWarnings("RedundantCast")
public class JdbcThinDatabaseMetadata implements DatabaseMetaData {
- /** The only possible name for catalog. */
- public static final String CATALOG_NAME = "IGNITE";
-
/** Driver name. */
public static final String DRIVER_NAME = "Apache Ignite Thin JDBC Driver";
@@ -752,27 +755,6 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData {
return new JdbcThinResultSet(rows, meta);
}
- /**
- * @param tblMeta Table metadata.
- * @return Table metadata row.
- */
- private List<Object> tableRow(JdbcTableMeta tblMeta) {
- List<Object> row = new ArrayList<>(10);
-
- row.add(CATALOG_NAME);
- row.add(tblMeta.schemaName());
- row.add(tblMeta.tableName());
- row.add("TABLE");
- row.add(null);
- row.add(null);
- row.add(null);
- row.add(null);
- row.add(null);
- row.add(null);
-
- return row;
- }
-
/** {@inheritDoc} */
@Override public ResultSet getSchemas() throws SQLException {
return getSchemas(null, "%");
@@ -837,42 +819,6 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData {
return new JdbcThinResultSet(rows, meta);
}
- /**
- * @param colMeta Column metadata.
- * @param pos Ordinal position.
- * @return Column metadata row.
- */
- private List<Object> columnRow(JdbcColumnMeta colMeta, int pos) {
- List<Object> row = new ArrayList<>(24);
-
- row.add(CATALOG_NAME); // 1. TABLE_CAT
- row.add(colMeta.schemaName()); // 2. TABLE_SCHEM
- row.add(colMeta.tableName()); // 3. TABLE_NAME
- row.add(colMeta.columnName()); // 4. COLUMN_NAME
- row.add(colMeta.dataType()); // 5. DATA_TYPE
- row.add(colMeta.dataTypeName()); // 6. TYPE_NAME
- row.add(colMeta.precision() == -1 ? null : colMeta.precision()); // 7. COLUMN_SIZE
- row.add((Integer)null); // 8. BUFFER_LENGTH
- row.add(colMeta.scale() == -1 ? null : colMeta.scale()); // 9. DECIMAL_DIGITS
- row.add(10); // 10. NUM_PREC_RADIX
- row.add(colMeta.isNullable() ? columnNullable : columnNoNulls); // 11. NULLABLE
- row.add((String)null); // 12. REMARKS
- row.add(colMeta.defaultValue()); // 13. COLUMN_DEF
- row.add(colMeta.dataType()); // 14. SQL_DATA_TYPE
- row.add((Integer)null); // 15. SQL_DATETIME_SUB
- row.add(Integer.MAX_VALUE); // 16. CHAR_OCTET_LENGTH
- row.add(pos); // 17. ORDINAL_POSITION
- row.add(colMeta.isNullable() ? "YES" : "NO"); // 18. IS_NULLABLE
- row.add((String)null); // 19. SCOPE_CATALOG
- row.add((String)null); // 20. SCOPE_SCHEMA
- row.add((String)null); // 21. SCOPE_TABLE
- row.add((Short)null); // 22. SOURCE_DATA_TYPE
- row.add("NO"); // 23. IS_AUTOINCREMENT
- row.add("NO"); // 23. IS_GENERATEDCOLUMN
-
- return row;
- }
-
/** {@inheritDoc} */
@Override public ResultSet getColumnPrivileges(String catalog, String schema, String tbl,
String colNamePtrn) throws SQLException {
@@ -956,29 +902,6 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData {
return new JdbcThinResultSet(rows, meta);
}
- /**
- * @param pkMeta Primary key metadata.
- * @return Result set rows for primary key.
- */
- private List<List<Object>> primaryKeyRows(JdbcPrimaryKeyMeta pkMeta) {
- List<List<Object>> rows = new ArrayList<>(pkMeta.fields().size());
-
- for (int i = 0; i < pkMeta.fields().size(); ++i) {
- List<Object> row = new ArrayList<>(6);
-
- row.add(CATALOG_NAME); // table catalog
- row.add(pkMeta.schemaName());
- row.add(pkMeta.tableName());
- row.add(pkMeta.fields().get(i));
- row.add((Integer)i + 1); // sequence number
- row.add(pkMeta.name());
-
- rows.add(row);
- }
-
- return rows;
- }
-
/** {@inheritDoc} */
@Override public ResultSet getImportedKeys(String catalog, String schema, String tbl) throws SQLException {
return new JdbcThinResultSet(Collections.<List<Object>>emptyList(), Arrays.asList(
@@ -1183,36 +1106,6 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData {
return new JdbcThinResultSet(rows, meta);
}
- /**
- * @param idxMeta Index metadata.
- * @return List of result rows correspond to index.
- */
- private List<List<Object>> indexRows(JdbcIndexMeta idxMeta) {
- List<List<Object>> rows = new ArrayList<>(idxMeta.fields().size());
-
- for (int i = 0; i < idxMeta.fields().size(); ++i) {
- List<Object> row = new ArrayList<>(13);
-
- row.add(CATALOG_NAME); // table catalog
- row.add(idxMeta.schemaName());
- row.add(idxMeta.tableName());
- row.add(true); // non unique
- row.add(null); // index qualifier (index catalog)
- row.add(idxMeta.indexName());
- row.add((short)tableIndexOther); // type
- row.add((Integer)i); // field ordinal position in index
- row.add(idxMeta.fields().get(i));
- row.add(idxMeta.fieldsAsc().get(i) ? "A" : "D");
- row.add((Integer)0); // cardinality
- row.add((Integer)0); // pages
- row.add((String)null); // filer condition
-
- rows.add(row);
- }
-
- return rows;
- }
-
/** {@inheritDoc} */
@Override public boolean supportsResultSetType(int type) throws SQLException {
return type == TYPE_FORWARD_ONLY;
@@ -1534,10 +1427,10 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData {
}
/**
- * Checks if specified catalog matches the only possible catalog value. See {@link #CATALOG_NAME}.
+ * Checks if specified catalog matches the only possible catalog value. See {@link JdbcUtils#CATALOG_NAME}.
*
* @param catalog Catalog name or {@code null}.
- * @return {@code true} If catalog equal ignoring case to {@link #CATALOG_NAME} or null (which means any catalog).
+ * @return {@code true} If catalog equal ignoring case to {@link JdbcUtils#CATALOG_NAME} or null (which means any catalog).
* Otherwise returns {@code false}.
*/
private static boolean isValidCatalog(String catalog) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java
index 896deb7..0409c94 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java
@@ -83,13 +83,13 @@ import static org.apache.ignite.IgniteJdbcDriver.PROP_LAZY;
import static org.apache.ignite.IgniteJdbcDriver.PROP_LOCAL;
import static org.apache.ignite.IgniteJdbcDriver.PROP_MULTIPLE_STMTS;
import static org.apache.ignite.IgniteJdbcDriver.PROP_NODE_ID;
+import static org.apache.ignite.IgniteJdbcDriver.PROP_SKIP_REDUCER_ON_UPDATE;
import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING;
import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING_ALLOW_OVERWRITE;
import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING_FLUSH_FREQ;
import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING_PER_NODE_BUF_SIZE;
import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING_PER_NODE_PAR_OPS;
import static org.apache.ignite.IgniteJdbcDriver.PROP_TX_ALLOWED;
-import static org.apache.ignite.IgniteJdbcDriver.PROP_SKIP_REDUCER_ON_UPDATE;
import static org.apache.ignite.internal.jdbc2.JdbcUtils.convertToSqlException;
import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.createJdbcSqlException;
@@ -901,7 +901,7 @@ public class JdbcConnection implements Connection {
*
* @throws SQLException If connection is closed.
*/
- private void ensureNotClosed() throws SQLException {
+ void ensureNotClosed() throws SQLException {
if (closed)
throw new SQLException("Connection is closed.", SqlStateCode.CONNECTION_CLOSED);
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java
index 663c988..cc58780 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java
@@ -26,20 +26,19 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
-import java.util.UUID;
+import java.util.Set;
+import java.util.SortedSet;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.internal.IgniteVersionUtils;
import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
-import org.apache.ignite.internal.processors.cache.query.GridCacheSqlIndexMetadata;
import org.apache.ignite.internal.processors.cache.query.GridCacheSqlMetadata;
-import org.apache.ignite.internal.processors.odbc.SqlStateCode;
-import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcColumnMeta;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcIndexMeta;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetadataInfo;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcPrimaryKeyMeta;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcTableMeta;
import org.apache.ignite.lang.IgniteCallable;
import org.apache.ignite.resources.IgniteInstanceResource;
@@ -47,32 +46,31 @@ import static java.sql.Connection.TRANSACTION_NONE;
import static java.sql.ResultSet.CONCUR_READ_ONLY;
import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
import static java.sql.RowIdLifetime.ROWID_UNSUPPORTED;
-import static org.apache.ignite.internal.jdbc2.JdbcUtils.convertToSqlException;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.CATALOG_NAME;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.columnRow;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.indexRows;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.primaryKeyRows;
+import static org.apache.ignite.internal.jdbc2.JdbcUtils.tableRow;
/**
* JDBC database metadata implementation.
*/
public class JdbcDatabaseMetadata implements DatabaseMetaData {
- /** The only possible name for catalog. */
- public static final String CATALOG_NAME = "IGNITE";
-
/** Driver name. */
public static final String DRIVER_NAME = "Apache Ignite JDBC Driver";
/** Connection. */
private final JdbcConnection conn;
- /** Metadata. */
- private Map<String, Map<String, Map<String, ColumnInfo>>> meta;
-
- /** Index info. */
- private Collection<List<Object>> indexes;
+ private final JdbcMetadataInfo meta;
/**
* @param conn Connection.
*/
JdbcDatabaseMetadata(JdbcConnection conn) {
this.conn = conn;
+
+ meta = new JdbcMetadataInfo(conn.ignite().context());
}
/** {@inheritDoc} */
@@ -713,19 +711,19 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
/** {@inheritDoc} */
@Override public ResultSet getTables(String catalog, String schemaPtrn, String tblNamePtrn,
String[] tblTypes) throws SQLException {
- updateMetaData();
-
- List<List<?>> rows = new LinkedList<>();
-
- if (isValidCatalog(catalog) && (tblTypes == null || Arrays.asList(tblTypes).contains("TABLE"))) {
- for (Map.Entry<String, Map<String, Map<String, ColumnInfo>>> schema : meta.entrySet()) {
- if (matches(schema.getKey(), schemaPtrn)) {
- for (String tbl : schema.getValue().keySet()) {
- if (matches(tbl, tblNamePtrn))
- rows.add(tableRow(schema.getKey(), tbl));
- }
- }
- }
+ conn.ensureNotClosed();
+
+ List<List<?>> rows = Collections.emptyList();
+
+ boolean areTypesValid = tblTypes == null || Arrays.asList(tblTypes).contains("TABLE");
+
+ if (isValidCatalog(catalog) && areTypesValid) {
+ List<JdbcTableMeta> tabMetas = meta.getTablesMeta(schemaPtrn, tblNamePtrn);
+
+ rows = new ArrayList<>(tabMetas.size());
+
+ for (JdbcTableMeta m : tabMetas)
+ rows.add(tableRow(m));
}
return new JdbcResultSet(true, null,
@@ -740,28 +738,6 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
);
}
- /**
- * @param schema Schema name.
- * @param tbl Table name.
- * @return Table metadata row.
- */
- private List<Object> tableRow(String schema, String tbl) {
- List<Object> row = new ArrayList<>(10);
-
- row.add(CATALOG_NAME);
- row.add(schema);
- row.add(tbl.toUpperCase());
- row.add("TABLE");
- row.add(null);
- row.add(null);
- row.add(null);
- row.add(null);
- row.add(null);
- row.add(null);
-
- return row;
- }
-
/** {@inheritDoc} */
@Override public ResultSet getSchemas() throws SQLException {
return getSchemas(null, "%");
@@ -793,26 +769,21 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
/** {@inheritDoc} */
@Override public ResultSet getColumns(String catalog, String schemaPtrn, String tblNamePtrn,
String colNamePtrn) throws SQLException {
- updateMetaData();
+ conn.ensureNotClosed();
- List<List<?>> rows = new LinkedList<>();
+ List<List<?>> rows = Collections.emptyList();
+ // FIXME: IGNITE-10745
int cnt = 0;
if (isValidCatalog(catalog)) {
- for (Map.Entry<String, Map<String, Map<String, ColumnInfo>>> schema : meta.entrySet()) {
- if (matches(schema.getKey(), schemaPtrn)) {
- for (Map.Entry<String, Map<String, ColumnInfo>> tbl : schema.getValue().entrySet()) {
- if (matches(tbl.getKey(), tblNamePtrn)) {
- for (Map.Entry<String, ColumnInfo> col : tbl.getValue().entrySet()) {
- rows.add(columnRow(schema.getKey(), tbl.getKey(), col.getKey(),
- JdbcUtils.type(col.getValue().typeName()), JdbcUtils.typeName(col.getValue().typeName()),
- !col.getValue().isNotNull(), ++cnt));
- }
- }
- }
- }
- }
+ Collection<JdbcColumnMeta> colMetas =
+ meta.getColumnsMeta(null /* latest */, schemaPtrn, tblNamePtrn, colNamePtrn);
+
+ rows = new ArrayList<>(colMetas.size());
+
+ for (JdbcColumnMeta col : colMetas)
+ rows.add(columnRow(col, ++cnt));
}
return new JdbcResultSet(true, null,
@@ -872,48 +843,6 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
);
}
- /**
- * @param schema Schema name.
- * @param tbl Table name.
- * @param col Column name.
- * @param type Type.
- * @param typeName Type name.
- * @param nullable Nullable flag.
- * @param pos Ordinal position.
- * @return Column metadata row.
- */
- private List<Object> columnRow(String schema, String tbl, String col, int type, String typeName,
- boolean nullable, int pos) {
- List<Object> row = new ArrayList<>(24);
-
- row.add(CATALOG_NAME); // 1. TABLE_CAT
- row.add(schema); // 2. TABLE_SCHEM
- row.add(tbl); // 3. TABLE_NAME
- row.add(col); // 4. COLUMN_NAME
- row.add(type); // 5. DATA_TYPE
- row.add(typeName); // 6. TYPE_NAME
- row.add(null); // 7. COLUMN_SIZE
- row.add(null); // 8. BUFFER_LENGTH
- row.add(null); // 9. DECIMAL_DIGITS
- row.add(10); // 10. NUM_PREC_RADIX
- row.add(nullable ? columnNullable : columnNoNulls); // 11. NULLABLE
- row.add(null); // 12. REMARKS
- row.add(null); // 13. COLUMN_DEF
- row.add(type); // 14. SQL_DATA_TYPE
- row.add(null); // 15. SQL_DATETIME_SUB
- row.add(Integer.MAX_VALUE); // 16. CHAR_OCTET_LENGTH
- row.add(pos); // 17. ORDINAL_POSITION
- row.add(nullable ? "YES" : "NO"); // 18. IS_NULLABLE
- row.add(null); // 19. SCOPE_CATALOG
- row.add(null); // 20. SCOPE_SCHEMA
- row.add(null); // 21. SCOPE_TABLE
- row.add(null); // 22. SOURCE_DATA_TYPE
- row.add("NO"); // 23. IS_AUTOINCREMENT
- row.add("NO"); // 24. IS_GENERATEDCOLUMN
-
- return row;
- }
-
/** {@inheritDoc} */
@Override public ResultSet getColumnPrivileges(String catalog, String schema, String tbl,
String colNamePtrn) throws SQLException {
@@ -968,20 +897,21 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
/** {@inheritDoc} */
@Override public ResultSet getPrimaryKeys(String catalog, String schemaPtrn, String tblNamePtrn)
throws SQLException {
- updateMetaData();
+ conn.ensureNotClosed();
- List<List<?>> rows = new LinkedList<>();
+ List<List<?>> rows;
if (isValidCatalog(catalog)) {
- for (Map.Entry<String, Map<String, Map<String, ColumnInfo>>> schema : meta.entrySet()) {
- if (matches(schema.getKey(), schemaPtrn)) {
- for (Map.Entry<String, Map<String, ColumnInfo>> tbl : schema.getValue().entrySet()) {
- if (matches(tbl.getKey(), tblNamePtrn))
- rows.add(Arrays.<Object>asList(CATALOG_NAME, schema.getKey(), tbl.getKey(), "_KEY", 1, "_KEY"));
- }
- }
- }
+ Collection<JdbcPrimaryKeyMeta> tabsKeyInfo = meta.getPrimaryKeys(schemaPtrn, tblNamePtrn);
+
+ rows = new ArrayList<>();
+
+ for (JdbcPrimaryKeyMeta keyInfo : tabsKeyInfo)
+ rows.addAll(primaryKeyRows(keyInfo));
+
}
+ else
+ rows = Collections.emptyList();
return new JdbcResultSet(true, null,
conn.createStatement0(),
@@ -1045,35 +975,18 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
/** {@inheritDoc} */
@Override public ResultSet getIndexInfo(String catalog, String schema, String tbl, boolean unique,
boolean approximate) throws SQLException {
- updateMetaData();
+ conn.ensureNotClosed();
- List<List<?>> rows = new ArrayList<>(indexes.size());
+ List<List<?>> rows = Collections.emptyList();
if (isValidCatalog(catalog)) {
- for (List<Object> idx : indexes) {
- String idxSchema = (String)idx.get(0);
- String idxTbl = (String)idx.get(1);
-
- if ((schema == null || schema.equals(idxSchema)) && (tbl == null || tbl.equals(idxTbl))) {
- List<Object> row = new ArrayList<>(13);
-
- row.add(CATALOG_NAME);
- row.add(idxSchema);
- row.add(idxTbl);
- row.add(idx.get(2));
- row.add(null);
- row.add(idx.get(3));
- row.add((int)tableIndexOther);
- row.add(idx.get(4));
- row.add(idx.get(5));
- row.add((Boolean)idx.get(6) ? "D" : "A");
- row.add(0);
- row.add(0);
- row.add(null);
-
- rows.add(row);
- }
- }
+ // Currently we are treating schema and tbl as sql patterns.
+ SortedSet<JdbcIndexMeta> idxMetas = meta.getIndexesMeta(schema, tbl);
+
+ rows = new ArrayList<>(idxMetas.size());
+
+ for (JdbcIndexMeta idxMeta : idxMetas)
+ rows.addAll(indexRows(idxMeta));
}
return new JdbcResultSet(true, null,
@@ -1269,12 +1182,16 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
/** {@inheritDoc} */
@Override public ResultSet getSchemas(String catalog, String schemaPtrn) throws SQLException {
- updateMetaData();
+ conn.ensureNotClosed();
- List<List<?>> rows = new ArrayList<>(meta.size());
+ List<List<?>> rows = Collections.emptyList();
if (isValidCatalog(catalog)) {
- for (String schema : meta.keySet()) {
+ Set<String> schemas = meta.getSchemasMeta(schemaPtrn);
+
+ rows = new ArrayList<>(schemas.size());
+
+ for (String schema : schemas) {
if (matches(schema, schemaPtrn))
rows.add(Arrays.<Object>asList(schema, CATALOG_NAME));
}
@@ -1376,72 +1293,6 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
}
/**
- * Updates meta data.
- *
- * @throws SQLException In case of error.
- */
- private void updateMetaData() throws SQLException {
- if (conn.isClosed())
- throw new SQLException("Connection is closed.", SqlStateCode.CONNECTION_CLOSED);
-
- try {
- Ignite ignite = conn.ignite();
-
- UUID nodeId = conn.nodeId();
-
- Collection<GridCacheSqlMetadata> metas;
-
- UpdateMetadataTask task = new UpdateMetadataTask(conn.cacheName(), nodeId == null ? ignite : null);
-
- metas = nodeId == null ? task.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(task);
-
- meta = U.newHashMap(metas.size());
-
- indexes = new ArrayList<>();
-
- for (GridCacheSqlMetadata m : metas) {
- String name = m.cacheName();
-
- if (name == null)
- name = "PUBLIC";
-
- Collection<String> types = m.types();
-
- Map<String, Map<String, ColumnInfo>> typesMap = U.newHashMap(types.size());
-
- for (String type : types) {
- Collection<String> notNullFields = m.notNullFields(type);
-
- Map<String, ColumnInfo> fields = new LinkedHashMap<>();
-
- for (Map.Entry<String, String> fld : m.fields(type).entrySet()) {
- ColumnInfo colInfo = new ColumnInfo(fld.getValue(),
- notNullFields == null ? false : notNullFields.contains(fld.getKey()));
-
- fields.put(fld.getKey(), colInfo);
- }
-
- typesMap.put(type.toUpperCase(), fields);
-
- for (GridCacheSqlIndexMetadata idx : m.indexes(type)) {
- int cnt = 0;
-
- for (String field : idx.fields()) {
- indexes.add(F.<Object>asList(name, type.toUpperCase(), !idx.unique(),
- idx.name(), ++cnt, field, idx.descending(field)));
- }
- }
- }
-
- meta.put(name, typesMap);
- }
- }
- catch (Exception e) {
- throw convertToSqlException(e, "Failed to get meta data from Ignite.");
- }
- }
-
- /**
* Checks whether string matches SQL pattern.
*
* @param str String.
@@ -1454,10 +1305,10 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
}
/**
- * Checks if specified catalog matches the only possible catalog value. See {@link #CATALOG_NAME}.
+ * Checks if specified catalog matches the only possible catalog value. See {@link JdbcUtils#CATALOG_NAME}.
*
* @param catalog Catalog name or {@code null}.
- * @return {@code true} If catalog equal ignoring case to {@link #CATALOG_NAME} or null (which means any catalog).
+ * @return {@code true} If catalog equal ignoring case to {@link JdbcUtils#CATALOG_NAME} or null (which means any catalog).
* Otherwise returns {@code false}.
*/
private static boolean isValidCatalog(String catalog) {
@@ -1465,7 +1316,9 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
}
/**
+ * This class is held only for compatibility purposes and shouldn't be used;
*
+ * @deprecated Use {@link JdbcMetadataInfo} instead.
*/
private static class UpdateMetadataTask implements IgniteCallable<Collection<GridCacheSqlMetadata>> {
/** Serial version uid. */
@@ -1497,7 +1350,11 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData {
}
/**
+ * This class is held only for compatibility purposes and shouldn't be used;
+ *
* Column info.
+ *
+ * @deprecated Use {@link JdbcMetadataInfo} instead.
*/
private static class ColumnInfo {
/** Class name. */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java
index 80881d7..6f7d3a4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java
@@ -23,16 +23,25 @@ import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
+import java.util.ArrayList;
import java.util.Date;
-
+import java.util.List;
import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcColumnMeta;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcIndexMeta;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcPrimaryKeyMeta;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcTableMeta;
import org.apache.ignite.internal.processors.query.IgniteSQLException;
import org.apache.ignite.internal.processors.query.QueryUtils;
+import static java.sql.DatabaseMetaData.columnNullable;
+import static java.sql.DatabaseMetaData.tableIndexOther;
+import static java.sql.ResultSetMetaData.columnNoNulls;
import static java.sql.Types.BIGINT;
import static java.sql.Types.BINARY;
import static java.sql.Types.BOOLEAN;
import static java.sql.Types.DATE;
+import static java.sql.Types.DECIMAL;
import static java.sql.Types.DOUBLE;
import static java.sql.Types.FLOAT;
import static java.sql.Types.INTEGER;
@@ -42,11 +51,13 @@ import static java.sql.Types.TIME;
import static java.sql.Types.TIMESTAMP;
import static java.sql.Types.TINYINT;
import static java.sql.Types.VARCHAR;
-import static java.sql.Types.DECIMAL;
/**
* Utility methods for JDBC driver.
*/
public class JdbcUtils {
+ /** The only possible name for catalog. */
+ public static final String CATALOG_NAME = "IGNITE";
+
/**
* Converts Java class name to type from {@link Types}.
*
@@ -188,4 +199,114 @@ public class JdbcUtils {
return new SQLException(msgForUnknown, sqlStateForUnknown, e);
}
+
+ /**
+ * @param colMeta Column metadata.
+ * @param pos Ordinal position.
+ * @return Column metadata row.
+ */
+ public static List<Object> columnRow(JdbcColumnMeta colMeta, int pos) {
+ List<Object> row = new ArrayList<>(24);
+
+ row.add(CATALOG_NAME); // 1. TABLE_CAT
+ row.add(colMeta.schemaName()); // 2. TABLE_SCHEM
+ row.add(colMeta.tableName()); // 3. TABLE_NAME
+ row.add(colMeta.columnName()); // 4. COLUMN_NAME
+ row.add(colMeta.dataType()); // 5. DATA_TYPE
+ row.add(colMeta.dataTypeName()); // 6. TYPE_NAME
+ row.add(colMeta.precision() == -1 ? null : colMeta.precision()); // 7. COLUMN_SIZE
+ row.add((Integer)null); // 8. BUFFER_LENGTH
+ row.add(colMeta.scale() == -1 ? null : colMeta.scale()); // 9. DECIMAL_DIGITS
+ row.add(10); // 10. NUM_PREC_RADIX
+ row.add(colMeta.isNullable() ? columnNullable : columnNoNulls); // 11. NULLABLE
+ row.add((String)null); // 12. REMARKS
+ row.add(colMeta.defaultValue()); // 13. COLUMN_DEF
+ row.add(colMeta.dataType()); // 14. SQL_DATA_TYPE
+ row.add((Integer)null); // 15. SQL_DATETIME_SUB
+ row.add(Integer.MAX_VALUE); // 16. CHAR_OCTET_LENGTH
+ row.add(pos); // 17. ORDINAL_POSITION
+ row.add(colMeta.isNullable() ? "YES" : "NO"); // 18. IS_NULLABLE
+ row.add((String)null); // 19. SCOPE_CATALOG
+ row.add((String)null); // 20. SCOPE_SCHEMA
+ row.add((String)null); // 21. SCOPE_TABLE
+ row.add((Short)null); // 22. SOURCE_DATA_TYPE
+ row.add("NO"); // 23. IS_AUTOINCREMENT
+ row.add("NO"); // 23. IS_GENERATEDCOLUMN
+
+ return row;
+ }
+
+ /**
+ * @param idxMeta Index metadata.
+ * @return List of result rows correspond to index.
+ */
+ public static List<List<Object>> indexRows(JdbcIndexMeta idxMeta) {
+ List<List<Object>> rows = new ArrayList<>(idxMeta.fields().size());
+
+ for (int i = 0; i < idxMeta.fields().size(); ++i) {
+ List<Object> row = new ArrayList<>(13);
+
+ row.add(CATALOG_NAME); // TABLE_CAT
+ row.add(idxMeta.schemaName()); // TABLE_SCHEM
+ row.add(idxMeta.tableName()); // TABLE_NAME
+ row.add(true); // NON_UNIQUE
+ row.add(null); // INDEX_QUALIFIER (index catalog)
+ row.add(idxMeta.indexName()); // INDEX_NAME
+ row.add(tableIndexOther); // TYPE
+ row.add(i + 1); // ORDINAL_POSITION
+ row.add(idxMeta.fields().get(i)); // COLUMN_NAME
+ row.add(idxMeta.fieldsAsc().get(i) ? "A" : "D"); // ASC_OR_DESC
+ row.add((Integer)0); // CARDINALITY
+ row.add((Integer)0); // PAGES
+ row.add((String)null); // FILTER_CONDITION
+
+ rows.add(row);
+ }
+
+ return rows;
+ }
+
+ /**
+ * @param pkMeta Primary key metadata.
+ * @return Result set rows for primary key.
+ */
+ public static List<List<Object>> primaryKeyRows(JdbcPrimaryKeyMeta pkMeta) {
+ List<List<Object>> rows = new ArrayList<>(pkMeta.fields().size());
+
+ for (int i = 0; i < pkMeta.fields().size(); ++i) {
+ List<Object> row = new ArrayList<>(6);
+
+ row.add(CATALOG_NAME); // table catalog
+ row.add(pkMeta.schemaName());
+ row.add(pkMeta.tableName());
+ row.add(pkMeta.fields().get(i));
+ row.add(i + 1); // sequence number
+ row.add(pkMeta.name());
+
+ rows.add(row);
+ }
+
+ return rows;
+ }
+
+ /**
+ * @param tblMeta Table metadata.
+ * @return Table metadata row.
+ */
+ public static List<Object> tableRow(JdbcTableMeta tblMeta) {
+ List<Object> row = new ArrayList<>(10);
+
+ row.add(CATALOG_NAME);
+ row.add(tblMeta.schemaName());
+ row.add(tblMeta.tableName());
+ row.add("TABLE");
+ row.add(null);
+ row.add(null);
+ row.add(null);
+ row.add(null);
+ row.add(null);
+ row.add(null);
+
+ return row;
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetadataInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetadataInfo.java
new file mode 100644
index 0000000..77d61f7
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetadataInfo.java
@@ -0,0 +1,269 @@
+/*
+ * 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.internal.processors.odbc.jdbc;
+
+import java.sql.DatabaseMetaData;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.odbc.ClientListenerProtocolVersion;
+import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
+import org.apache.ignite.internal.processors.query.GridQueryProperty;
+import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
+import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext.VER_2_3_0;
+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.query.QueryUtils.matches;
+
+/**
+ * Facade over {@link GridKernalContext} to get information about database entities in terms of JDBC.
+ */
+public class JdbcMetadataInfo {
+ /** Root context. Used to get all the database metadata. */
+ private final GridKernalContext ctx;
+
+ /** The only one possible value of table type. */
+ public static final String TABLE_TYPE = "TABLE";
+
+ /**
+ * Initializes info.
+ *
+ * @param ctx GridKernalContext
+ */
+ public JdbcMetadataInfo(GridKernalContext ctx) {
+ this.ctx = ctx;
+ }
+
+ /**
+ * See {@link DatabaseMetaData#getPrimaryKeys(String, String, String)} for details.
+ *
+ * Ignite has only one possible CATALOG_NAME, it is handled on the client (driver) side.
+ *
+ * @return Collection of primary keys information for tables that matches specified schema and table name patterns.
+ */
+ public Collection<JdbcPrimaryKeyMeta> getPrimaryKeys(String schemaNamePtrn, String tableNamePtrn) {
+ Collection<JdbcPrimaryKeyMeta> meta = new HashSet<>();
+
+ for (String cacheName : ctx.cache().publicCacheNames()) {
+ for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
+ if (!matches(table.schemaName(), schemaNamePtrn))
+ continue;
+
+ if (!matches(table.tableName(), tableNamePtrn))
+ continue;
+
+ List<String> fields = new ArrayList<>();
+
+ for (String field : table.fields().keySet()) {
+ if (table.property(field).key())
+ fields.add(field);
+ }
+
+ final String keyName = table.keyFieldName() == null ?
+ "PK_" + table.schemaName() + "_" + table.tableName() :
+ table.keyFieldName();
+
+ if (fields.isEmpty()) {
+ String keyColName =
+ table.keyFieldName() == null ? QueryUtils.KEY_FIELD_NAME : table.keyFieldName();
+
+ meta.add(new JdbcPrimaryKeyMeta(table.schemaName(), table.tableName(), keyName,
+ Collections.singletonList(keyColName)));
+ }
+ else
+ meta.add(new JdbcPrimaryKeyMeta(table.schemaName(), table.tableName(), keyName, fields));
+ }
+ }
+
+ return meta;
+ }
+
+ /**
+ * See {@link DatabaseMetaData#getTables(String, String, String, String[])} for details.
+ *
+ * Ignite has only one possible value for CATALOG_NAME and has only one table type so these parameters are handled
+ * on the client (driver) side.
+ *
+ * Result is ordered by (schema name, table name).
+ *
+ * @param schemaPtrn sql pattern for schema name.
+ * @param tabPtrn sql pattern for table name.
+ * @return List of metadatas of tables that matches .
+ */
+ public List<JdbcTableMeta> getTablesMeta(String schemaPtrn, String tabPtrn) {
+ Comparator<JdbcTableMeta> bySchemaThenTabname = new Comparator<JdbcTableMeta>() {
+ @Override public int compare(JdbcTableMeta o1, JdbcTableMeta o2) {
+ int schemCmp = o1.schemaName().compareTo(o2.schemaName());
+
+ if (schemCmp != 0)
+ return schemCmp;
+
+ return o1.tableName().compareTo(o2.tableName());
+ }
+ };
+
+ TreeSet<JdbcTableMeta> tabMetas = new TreeSet<>(bySchemaThenTabname);
+
+ for (String cacheName : ctx.cache().publicCacheNames()) {
+ for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
+ if (!matches(table.schemaName(), schemaPtrn))
+ continue;
+
+ if (!matches(table.tableName(), tabPtrn))
+ continue;
+
+ JdbcTableMeta tableMeta = new JdbcTableMeta(table.schemaName(), table.tableName(), TABLE_TYPE);
+
+ tabMetas.add(tableMeta);
+ }
+ }
+
+ return new ArrayList<>(tabMetas);
+ }
+
+ /**
+ * See {@link DatabaseMetaData#getColumns(String, String, String, String)} for details.
+ *
+ * Ignite has only one possible CATALOG_NAME, it is handled on the client (driver) side.
+ *
+ * @param protocolVer for what version of protocol to generate metadata. Early versions of protocol don't support
+ * some features like default values or precision/scale. If {@code null}, current version will be used.
+ * @return List of metadatas about columns that match specified schema/tablename/columnname criterias.
+ */
+ public Collection<JdbcColumnMeta> getColumnsMeta(@Nullable ClientListenerProtocolVersion protocolVer,
+ String schemaNamePtrn, String tableNamePtrn, String columnNamePtrn) {
+
+ boolean useNewest = protocolVer == null;
+
+ Collection<JdbcColumnMeta> metas = new LinkedHashSet<>();
+
+ for (String cacheName : ctx.cache().publicCacheNames()) {
+ for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
+ if (!matches(table.schemaName(), schemaNamePtrn))
+ continue;
+
+ if (!matches(table.tableName(), tableNamePtrn))
+ continue;
+
+ for (Map.Entry<String, Class<?>> field : table.fields().entrySet()) {
+ String colName = field.getKey();
+
+ Class<?> fieldCls = field.getValue();
+
+ if (!matches(colName, columnNamePtrn))
+ continue;
+
+ JdbcColumnMeta columnMeta;
+
+ if (useNewest || protocolVer.compareTo(VER_2_7_0) >= 0) {
+ GridQueryProperty prop = table.property(colName);
+
+ columnMeta = new JdbcColumnMetaV4(table.schemaName(), table.tableName(),
+ colName, fieldCls, !prop.notNull(), prop.defaultValue(),
+ prop.precision(), prop.scale());
+ }
+ else if (protocolVer.compareTo(VER_2_4_0) >= 0) {
+ GridQueryProperty prop = table.property(colName);
+
+ columnMeta = new JdbcColumnMetaV3(table.schemaName(), table.tableName(),
+ colName, fieldCls, !prop.notNull(), prop.defaultValue());
+ }
+ else if (protocolVer.compareTo(VER_2_3_0) >= 0) {
+ GridQueryProperty prop = table.property(colName);
+
+ columnMeta = new JdbcColumnMetaV2(table.schemaName(), table.tableName(),
+ colName, fieldCls, !prop.notNull());
+ }
+ else
+ columnMeta = new JdbcColumnMeta(table.schemaName(), table.tableName(),
+ colName, fieldCls);
+
+ if (!metas.contains(columnMeta))
+ metas.add(columnMeta);
+ }
+ }
+ }
+
+ return metas;
+ }
+
+ /**
+ * See {@link DatabaseMetaData#getSchemas(String, String)} for details.
+ *
+ * Ignite has only one possible CATALOG_NAME, it is handled on the client (driver) side.
+ *
+ * @param schemaNamePtrn sql pattern for schema name filter.
+ * @return schema names that matches provided pattern.
+ */
+ public SortedSet<String> getSchemasMeta(String schemaNamePtrn) {
+ SortedSet<String> schemas = new TreeSet<>(); // to have values sorted.
+
+ for (String cacheName : ctx.cache().publicCacheNames()) {
+ for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
+ if (matches(table.schemaName(), schemaNamePtrn))
+ schemas.add(table.schemaName());
+ }
+ }
+
+ return schemas;
+ }
+
+ /**
+ * See {@link DatabaseMetaData#getIndexInfo(String, String, String, boolean, boolean)} for details.
+ *
+ * Ignite has only one possible CATALOG_NAME, it is handled on the client (driver) side. Parameters {@code unique}
+ * {@code approximate} are ignored.
+ *
+ * @return Sorted by index name collection of index info, filtered according to specified criterias.
+ */
+ public SortedSet<JdbcIndexMeta> getIndexesMeta(String schemaNamePtrn, String tableNamePtrn) {
+ final Comparator<JdbcIndexMeta> byIndexName = new Comparator<JdbcIndexMeta>() {
+ @Override public int compare(JdbcIndexMeta o1, JdbcIndexMeta o2) {
+ return o1.indexName().compareTo(o2.indexName());
+ }
+ };
+
+ TreeSet<JdbcIndexMeta> meta = new TreeSet<>(byIndexName);
+
+ for (String cacheName : ctx.cache().publicCacheNames()) {
+ for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
+ if (!matches(table.schemaName(), schemaNamePtrn))
+ continue;
+
+ if (!matches(table.tableName(), tableNamePtrn))
+ continue;
+
+ for (GridQueryIndexDescriptor idxDesc : table.indexes().values())
+ meta.add(new JdbcIndexMeta(table.schemaName(), table.tableName(), idxDesc));
+ }
+ }
+
+ return meta;
+ }
+}
\ 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 7f19491..da83515 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
@@ -22,15 +22,12 @@ import java.sql.ParameterMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
-import java.util.Set;
+import java.util.SortedSet;
import java.util.concurrent.ConcurrentHashMap;
import javax.cache.configuration.Factory;
import org.apache.ignite.IgniteCheckedException;
@@ -54,12 +51,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;
-import org.apache.ignite.internal.processors.query.GridQueryProperty;
-import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
import org.apache.ignite.internal.processors.query.IgniteSQLException;
import org.apache.ignite.internal.processors.query.NestedTxMode;
import org.apache.ignite.internal.processors.query.QueryUtils;
@@ -148,6 +140,9 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
/** Authentication context */
private AuthorizationContext actx;
+ /** Facade that hides transformations internal cache api entities -> jdbc metadata. */
+ private final JdbcMetadataInfo meta;
+
/** Register that keeps non-cancelled requests. */
private Map<Long, JdbcQueryDescriptor> reqRegister = new HashMap<>();
@@ -175,6 +170,8 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
this.ctx = ctx;
this.sender = sender;
+ this.meta = new JdbcMetadataInfo(ctx);
+
Factory<GridWorker> orderedFactory = new Factory<GridWorker>() {
@Override public GridWorker create() {
return new OrderedBatchWorker();
@@ -983,24 +980,9 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
*/
private JdbcResponse getTablesMeta(JdbcMetaTablesRequest req) {
try {
- List<JdbcTableMeta> meta = new ArrayList<>();
-
- for (String cacheName : ctx.cache().publicCacheNames()) {
- for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
- if (!matches(table.schemaName(), req.schemaName()))
- continue;
-
- if (!matches(table.tableName(), req.tableName()))
- continue;
-
- JdbcTableMeta tableMeta = new JdbcTableMeta(table.schemaName(), table.tableName(), "TABLE");
-
- if (!meta.contains(tableMeta))
- meta.add(tableMeta);
- }
- }
+ List<JdbcTableMeta> tabMetas = meta.getTablesMeta(req.schemaName(), req.tableName());
- JdbcMetaTablesResult res = new JdbcMetaTablesResult(meta);
+ JdbcMetaTablesResult res = new JdbcMetaTablesResult(tabMetas);
return new JdbcResponse(res);
}
@@ -1012,70 +994,24 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
}
/**
- * {@link OdbcQueryGetColumnsMetaRequest} command handler.
- *
* @param req Get columns metadata request.
* @return Response.
*/
private JdbcResponse getColumnsMeta(JdbcMetaColumnsRequest req) {
try {
- Collection<JdbcColumnMeta> meta = new LinkedHashSet<>();
-
- for (String cacheName : ctx.cache().publicCacheNames()) {
- for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
- if (!matches(table.schemaName(), req.schemaName()))
- continue;
-
- if (!matches(table.tableName(), req.tableName()))
- continue;
-
- for (Map.Entry<String, Class<?>> field : table.fields().entrySet()) {
- String colName = field.getKey();
-
- if (!matches(colName, req.columnName()))
- continue;
-
- JdbcColumnMeta columnMeta;
-
- if (protocolVer.compareTo(VER_2_7_0) >= 0) {
- GridQueryProperty prop = table.property(colName);
-
- columnMeta = new JdbcColumnMetaV4(table.schemaName(), table.tableName(),
- field.getKey(), field.getValue(), !prop.notNull(), prop.defaultValue(),
- prop.precision(), prop.scale());
- }
- else if (protocolVer.compareTo(VER_2_4_0) >= 0) {
- GridQueryProperty prop = table.property(colName);
-
- columnMeta = new JdbcColumnMetaV3(table.schemaName(), table.tableName(),
- field.getKey(), field.getValue(), !prop.notNull(), prop.defaultValue());
- }
- else if (protocolVer.compareTo(VER_2_3_0) >= 0) {
- GridQueryProperty prop = table.property(colName);
-
- columnMeta = new JdbcColumnMetaV2(table.schemaName(), table.tableName(),
- field.getKey(), field.getValue(), !prop.notNull());
- }
- else
- columnMeta = new JdbcColumnMeta(table.schemaName(), table.tableName(),
- field.getKey(), field.getValue());
-
- if (!meta.contains(columnMeta))
- meta.add(columnMeta);
- }
- }
- }
+ Collection<JdbcColumnMeta> colsMeta =
+ meta.getColumnsMeta(protocolVer, req.schemaName(), req.tableName(), req.columnName());
JdbcMetaColumnsResult res;
if (protocolVer.compareTo(VER_2_7_0) >= 0)
- res = new JdbcMetaColumnsResultV4(meta);
+ res = new JdbcMetaColumnsResultV4(colsMeta);
else if (protocolVer.compareTo(VER_2_4_0) >= 0)
- res = new JdbcMetaColumnsResultV3(meta);
+ res = new JdbcMetaColumnsResultV3(colsMeta);
else if (protocolVer.compareTo(VER_2_3_0) >= 0)
- res = new JdbcMetaColumnsResultV2(meta);
+ res = new JdbcMetaColumnsResultV2(colsMeta);
else
- res = new JdbcMetaColumnsResult(meta);
+ res = new JdbcMetaColumnsResult(colsMeta);
return new JdbcResponse(res);
}
@@ -1092,22 +1028,9 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
*/
private ClientListenerResponse getIndexesMeta(JdbcMetaIndexesRequest req) {
try {
- Collection<JdbcIndexMeta> meta = new HashSet<>();
-
- for (String cacheName : ctx.cache().publicCacheNames()) {
- for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
- if (!matches(table.schemaName(), req.schemaName()))
- continue;
+ Collection<JdbcIndexMeta> idxInfos = meta.getIndexesMeta(req.schemaName(), req.tableName());
- if (!matches(table.tableName(), req.tableName()))
- continue;
-
- for (GridQueryIndexDescriptor idxDesc : table.indexes().values())
- meta.add(new JdbcIndexMeta(table.schemaName(), table.tableName(), idxDesc));
- }
- }
-
- return new JdbcResponse(new JdbcMetaIndexesResult(meta));
+ return new JdbcResponse(new JdbcMetaIndexesResult(idxInfos));
}
catch (Exception e) {
U.error(log, "Failed to get parameters metadata [reqId=" + req.requestId() + ", req=" + req + ']', e);
@@ -1149,40 +1072,9 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
*/
private ClientListenerResponse getPrimaryKeys(JdbcMetaPrimaryKeysRequest req) {
try {
- Collection<JdbcPrimaryKeyMeta> meta = new HashSet<>();
-
- for (String cacheName : ctx.cache().publicCacheNames()) {
- for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
- if (!matches(table.schemaName(), req.schemaName()))
- continue;
-
- if (!matches(table.tableName(), req.tableName()))
- continue;
-
- List<String> fields = new ArrayList<>();
-
- for (String field : table.fields().keySet()) {
- if (table.property(field).key())
- fields.add(field);
- }
-
- final String keyName = table.keyFieldName() == null ?
- "PK_" + table.schemaName() + "_" + table.tableName() :
- table.keyFieldName();
-
- if (fields.isEmpty()) {
- String keyColName =
- table.keyFieldName() == null ? QueryUtils.KEY_FIELD_NAME : table.keyFieldName();
-
- meta.add(new JdbcPrimaryKeyMeta(table.schemaName(), table.tableName(), keyName,
- Collections.singletonList(keyColName)));
- }
- else
- meta.add(new JdbcPrimaryKeyMeta(table.schemaName(), table.tableName(), keyName, fields));
- }
- }
+ Collection<JdbcPrimaryKeyMeta> pkMeta = meta.getPrimaryKeys(req.schemaName(), req.tableName());
- return new JdbcResponse(new JdbcMetaPrimaryKeysResult(meta));
+ return new JdbcResponse(new JdbcMetaPrimaryKeysResult(pkMeta));
}
catch (Exception e) {
U.error(log, "Failed to get parameters metadata [reqId=" + req.requestId() + ", req=" + req + ']', e);
@@ -1199,14 +1091,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
try {
String schemaPtrn = req.schemaName();
- Set<String> schemas = new HashSet<>();
-
- for (String cacheName : ctx.cache().publicCacheNames()) {
- for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) {
- if (matches(table.schemaName(), schemaPtrn))
- schemas.add(table.schemaName());
- }
- }
+ SortedSet<String> schemas = meta.getSchemasMeta(schemaPtrn);
return new JdbcResponse(new JdbcMetaSchemasResult(schemas));
}
@@ -1218,25 +1103,6 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
}
/**
- * Checks whether string matches SQL pattern.
- *
- * @param str String.
- * @param sqlPtrn Pattern.
- * @return Whether string matches pattern.
- */
- 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);
- }
-
- /**
* Create {@link JdbcResponse} bearing appropriate Ignite specific result code if possible
* from given {@link Exception}.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
index 322bd8d..2942713 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
@@ -54,6 +54,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
import org.apache.ignite.internal.processors.cache.GridCacheDefaultAffinityKeyMapper;
import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.odbc.SqlListenerUtils;
import org.apache.ignite.internal.processors.query.property.QueryBinaryProperty;
import org.apache.ignite.internal.processors.query.property.QueryClassProperty;
import org.apache.ignite.internal.processors.query.property.QueryFieldAccessor;
@@ -177,6 +178,7 @@ public class QueryUtils {
return indexName(tableName(entity), idx);
}
+
/**
* Get index name.
*
@@ -614,6 +616,7 @@ public class QueryUtils {
d.addProperty(prop, false);
}
+ // Sql-typed key/value doesn't have field property, but they may have precision and scale constraints.
String keyFieldName = qryEntity.getKeyFieldName();
if (keyFieldName == null)
@@ -803,8 +806,8 @@ public class QueryUtils {
* nested fields.
* @param resType Result type.
* @param aliases Aliases.
- * @param isKeyField Key ownership flag, as defined in {@link QueryEntity#keyFields}: {@code true} if field belongs
- * to key, {@code false} if it belongs to value, {@code null} if QueryEntity#keyFields is null.
+ * @param isKeyField Key ownership flag, {@code true} if this property is a field of the key object. Note that key
+ * not a field of itself.
* @param notNull {@code true} if {@code null} value is not allowed.
* @param dlftVal Default value.
* @param precision Precision.
@@ -1469,6 +1472,25 @@ public class QueryUtils {
}
/**
+ * Checks whether string matches SQL pattern.
+ *
+ * @param str String.
+ * @param sqlPtrn Pattern.
+ * @return Whether string matches pattern.
+ */
+ public 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);
+ }
+
+ /**
* Private constructor.
*/
private QueryUtils() {
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
index 027ac7e..068e3b7 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlanBuilder.java
@@ -294,13 +294,16 @@ public final class UpdatePlanBuilder {
colTypes[i] = col.resultType().type();
int colId = col.column().getColumnId();
+
if (desc.isKeyColumn(colId)) {
keyColIdx = i;
+
continue;
}
if (desc.isValueColumn(colId)) {
valColIdx = i;
+
continue;
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs
index ae57880..716fdc2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs
@@ -284,7 +284,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
Fields = new[]
{
/// Next two fieleds belong to the <see cref="Key"/> object, so should have been marked with <see cref="QueryField.IsKeyField"/>
- // But if we forgot to do this - all fields are treated as value fields. Key fields have default values and second insert fails.
+ // But if we forgot to do this - all fields are treated as value fields. Key fields have default values and second insert fails.
new QueryField("Lo", typeof(int)),
new QueryField("Hi", typeof(int)),