IGNITE-6529 JDBC: support column metadata 'nullable' property. This closes #2793.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/c116bfc6 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/c116bfc6 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/c116bfc6 Branch: refs/heads/ignite-3478 Commit: c116bfc68a05376285946b8eae10ed6e51f848e0 Parents: e98e392 Author: tledkov-gridgain <[email protected]> Authored: Thu Oct 5 11:55:26 2017 +0300 Committer: devozerov <[email protected]> Committed: Thu Oct 5 11:55:26 2017 +0300 ---------------------------------------------------------------------- .../internal/jdbc2/JdbcMetadataSelfTest.java | 28 ++-- .../jdbc/thin/JdbcThinMetadataSelfTest.java | 33 ++-- .../jdbc/thin/JdbcThinDatabaseMetadata.java | 3 +- .../internal/jdbc/thin/JdbcThinTcpIo.java | 4 +- .../internal/jdbc2/JdbcDatabaseMetadata.java | 70 +++++++-- .../cache/query/GridCacheQueryManager.java | 87 ++++++++++- .../query/GridCacheQuerySqlMetadataJobV2.java | 154 +++++++++++++++++++ .../query/GridCacheQuerySqlMetadataV2.java | 101 ++++++++++++ .../cache/query/GridCacheSqlMetadata.java | 8 + .../processors/odbc/jdbc/JdbcColumnMeta.java | 10 ++ .../processors/odbc/jdbc/JdbcColumnMetaV2.java | 74 +++++++++ .../odbc/jdbc/JdbcConnectionContext.java | 4 +- .../odbc/jdbc/JdbcMetaColumnsResult.java | 28 +++- .../odbc/jdbc/JdbcMetaColumnsResultV2.java | 50 ++++++ .../odbc/jdbc/JdbcRequestHandler.java | 32 +++- .../processors/odbc/jdbc/JdbcResult.java | 8 + 16 files changed, 642 insertions(+), 52 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java ---------------------------------------------------------------------- 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 6020a3a..bdc6644 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 @@ -42,7 +42,7 @@ import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.ConnectorConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteVersionUtils; -import org.apache.ignite.internal.binary.BinaryMarshaller; +import org.apache.ignite.internal.processors.query.QueryEntityEx; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; @@ -78,11 +78,16 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest { cfg.setCacheConfiguration( cacheConfiguration("pers").setQueryEntities(Arrays.asList( - new QueryEntity(AffinityKey.class, Person.class) - .setIndexes(Arrays.asList( - new QueryIndex("orgId"), - new QueryIndex().setFields(persFields)))) - ), + new QueryEntityEx( + new QueryEntity(AffinityKey.class.getName(), Person.class.getName()) + .addQueryField("name", String.class.getName(), null) + .addQueryField("age", Integer.class.getName(), null) + .addQueryField("orgId", Integer.class.getName(), null) + .setIndexes(Arrays.asList( + new QueryIndex("orgId"), + new QueryIndex().setFields(persFields)))) + .setNotNullFields(new HashSet<>(Arrays.asList("age", "name"))) + )), cacheConfiguration("org").setQueryEntities(Arrays.asList( new QueryEntity(AffinityKey.class, Organization.class)))); @@ -208,7 +213,6 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest { * @throws Exception If failed. */ public void testGetColumns() throws Exception { - final boolean primitivesInformationIsLostAfterStore = ignite(0).configuration().getMarshaller() instanceof BinaryMarshaller; try (Connection conn = DriverManager.getConnection(BASE_URL)) { DatabaseMetaData meta = conn.getMetaData(); @@ -232,11 +236,15 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest { if ("NAME".equals(name)) { assertEquals(VARCHAR, rs.getInt("DATA_TYPE")); assertEquals("VARCHAR", rs.getString("TYPE_NAME")); - assertEquals(1, rs.getInt("NULLABLE")); - } else if ("AGE".equals(name) || "ORGID".equals(name)) { + assertEquals(0, rs.getInt("NULLABLE")); + } else if ("AGE".equals(name)) { + assertEquals(INTEGER, rs.getInt("DATA_TYPE")); + assertEquals("INTEGER", rs.getString("TYPE_NAME")); + assertEquals(0, rs.getInt("NULLABLE")); + } else if ("ORGID".equals(name)) { assertEquals(INTEGER, rs.getInt("DATA_TYPE")); assertEquals("INTEGER", rs.getString("TYPE_NAME")); - assertEquals(primitivesInformationIsLostAfterStore ? 1 : 0, rs.getInt("NULLABLE")); + assertEquals(1, rs.getInt("NULLABLE")); } cnt++; http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java ---------------------------------------------------------------------- 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 01b2e8a..abbe4e1 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 @@ -41,7 +41,7 @@ import org.apache.ignite.cache.affinity.AffinityKey; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteVersionUtils; -import org.apache.ignite.internal.binary.BinaryMarshaller; +import org.apache.ignite.internal.processors.query.QueryEntityEx; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; @@ -118,13 +118,15 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { persFields.put("age", false); IgniteCache<AffinityKey, Person> personCache = jcache(grid(0), cacheConfiguration( - new QueryEntity(AffinityKey.class.getName(), Person.class.getName()) - .addQueryField("name", String.class.getName(), null) - .addQueryField("age", Integer.class.getName(), null) - .addQueryField("orgId", Integer.class.getName(), null) - .setIndexes(Arrays.asList( - new QueryIndex("orgId"), - new QueryIndex().setFields(persFields))) + new QueryEntityEx( + new QueryEntity(AffinityKey.class.getName(), Person.class.getName()) + .addQueryField("name", String.class.getName(), null) + .addQueryField("age", Integer.class.getName(), null) + .addQueryField("orgId", Integer.class.getName(), null) + .setIndexes(Arrays.asList( + new QueryIndex("orgId"), + new QueryIndex().setFields(persFields)))) + .setNotNullFields(new HashSet<>(Arrays.asList("age", "name"))) ), "pers"); assert personCache != null; @@ -251,9 +253,6 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { * @throws Exception If failed. */ public void testGetColumns() throws Exception { - final boolean primitivesInformationIsLostAfterStore = ignite(0).configuration().getMarshaller() - instanceof BinaryMarshaller; - try (Connection conn = DriverManager.getConnection(URL)) { conn.setSchema("pers"); @@ -279,18 +278,22 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { if ("NAME".equals(name)) { assert rs.getInt("DATA_TYPE") == VARCHAR; assert "VARCHAR".equals(rs.getString("TYPE_NAME")); + assert rs.getInt("NULLABLE") == 0; + } else if ("ORGID".equals(name)) { + assert rs.getInt("DATA_TYPE") == INTEGER; + assert "INTEGER".equals(rs.getString("TYPE_NAME")); assert rs.getInt("NULLABLE") == 1; - } else if ("AGE".equals(name) || "ORGID".equals(name)) { + } else if ("AGE".equals(name)) { assert rs.getInt("DATA_TYPE") == INTEGER; assert "INTEGER".equals(rs.getString("TYPE_NAME")); - assertEquals(primitivesInformationIsLostAfterStore ? 1 : 0, rs.getInt("NULLABLE")); + assert rs.getInt("NULLABLE") == 0; } - if ("_KEY".equals(name)) { + else if ("_KEY".equals(name)) { assert rs.getInt("DATA_TYPE") == OTHER; assert "OTHER".equals(rs.getString("TYPE_NAME")); assert rs.getInt("NULLABLE") == 0; } - if ("_VAL".equals(name)) { + else if ("_VAL".equals(name)) { assert rs.getInt("DATA_TYPE") == OTHER; assert "OTHER".equals(rs.getString("TYPE_NAME")); assert rs.getInt("NULLABLE") == 0; http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java ---------------------------------------------------------------------- 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 2ce7983..8b26900 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,7 +29,6 @@ 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; @@ -845,7 +844,7 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData { row.add((Integer)null); row.add((Integer)null); row.add(10); - row.add(JdbcUtils.nullable(colMeta.columnName(), colMeta.dataTypeClass()) ? 1 : 0 ); + row.add(colMeta.isNullable() ? 1 : 0); row.add((String)null); row.add((String)null); row.add(Integer.MAX_VALUE); http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java ---------------------------------------------------------------------- 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 7ac9c2c..688f908 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 @@ -50,10 +50,10 @@ public class JdbcThinTcpIo { private static final ClientListenerProtocolVersion VER_2_1_0 = ClientListenerProtocolVersion.create(2, 1, 0); /** Version 2.3.1. */ - private static final ClientListenerProtocolVersion VER_2_3_1 = ClientListenerProtocolVersion.create(2, 3, 1); + private static final ClientListenerProtocolVersion VER_2_3_0 = ClientListenerProtocolVersion.create(2, 3, 0); /** Current version. */ - private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_3_1; + private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_3_0; /** Initial output stream capacity for handshake. */ private static final int HANDSHAKE_MSG_SIZE = 13; http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java ---------------------------------------------------------------------- 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 4c21cbd..03fde79 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,6 +26,7 @@ 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; @@ -59,7 +60,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { private final JdbcConnection conn; /** Metadata. */ - private Map<String, Map<String, Map<String, String>>> meta; + private Map<String, Map<String, Map<String, ColumnInfo>>> meta; /** Index info. */ private Collection<List<Object>> indexes; @@ -714,7 +715,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { List<List<?>> rows = new LinkedList<>(); if (validCatalogPattern(catalog) && (tblTypes == null || Arrays.asList(tblTypes).contains("TABLE"))) { - for (Map.Entry<String, Map<String, Map<String, String>>> schema : meta.entrySet()) { + 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)) @@ -796,14 +797,14 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { int cnt = 0; if (validCatalogPattern(catalog)) { - for (Map.Entry<String, Map<String, Map<String, String>>> schema : meta.entrySet()) { + for (Map.Entry<String, Map<String, Map<String, ColumnInfo>>> schema : meta.entrySet()) { if (matches(schema.getKey(), schemaPtrn)) { - for (Map.Entry<String, Map<String, String>> tbl : schema.getValue().entrySet()) { + for (Map.Entry<String, Map<String, ColumnInfo>> tbl : schema.getValue().entrySet()) { if (matches(tbl.getKey(), tblNamePtrn)) { - for (Map.Entry<String, String> col : tbl.getValue().entrySet()) { + for (Map.Entry<String, ColumnInfo> col : tbl.getValue().entrySet()) { rows.add(columnRow(schema.getKey(), tbl.getKey(), col.getKey(), - JdbcUtils.type(col.getValue()), JdbcUtils.typeName(col.getValue()), - JdbcUtils.nullable(col.getKey(), col.getValue()), ++cnt)); + JdbcUtils.type(col.getValue().typeName()), JdbcUtils.typeName(col.getValue().typeName()), + !col.getValue().isNotNull(), ++cnt)); } } } @@ -925,9 +926,9 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { List<List<?>> rows = new LinkedList<>(); if (validCatalogPattern(catalog)) { - for (Map.Entry<String, Map<String, Map<String, String>>> schema : meta.entrySet()) { + for (Map.Entry<String, Map<String, Map<String, ColumnInfo>>> schema : meta.entrySet()) { if (matches(schema.getKey(), schemaPtrn)) { - for (Map.Entry<String, Map<String, String>> tbl : schema.getValue().entrySet()) { + for (Map.Entry<String, Map<String, ColumnInfo>> tbl : schema.getValue().entrySet()) { if (matches(tbl.getKey(), tblNamePtrn)) rows.add(Arrays.<Object>asList(null, schema.getKey(), tbl.getKey(), "_KEY", 1, "_KEY")); } @@ -1361,10 +1362,21 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { Collection<String> types = m.types(); - Map<String, Map<String, String>> typesMap = U.newHashMap(types.size()); + Map<String, Map<String, ColumnInfo>> typesMap = U.newHashMap(types.size()); for (String type : types) { - typesMap.put(type.toUpperCase(), m.fields(type)); + 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; @@ -1435,7 +1447,41 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { @Override public Collection<GridCacheSqlMetadata> call() throws Exception { IgniteCache cache = ignite.cache(cacheName); - return ((IgniteCacheProxy)cache).context().queries().sqlMetadata(); + return ((IgniteCacheProxy)cache).context().queries().sqlMetadataV2(); + } + } + + /** + * Column info. + */ + private static class ColumnInfo { + /** Class name. */ + private final String typeName; + + /** Not null flag. */ + private final boolean notNull; + + /** + * @param typeName Type name. + * @param notNull Not null flag. + */ + private ColumnInfo(String typeName, boolean notNull) { + this.typeName = typeName; + this.notNull = notNull; + } + + /** + * @return Type name. + */ + public String typeName() { + return typeName; + } + + /** + * @return Not null flag. + */ + public boolean isNotNull() { + return notNull; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java index f873461..64e74fb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java @@ -113,6 +113,7 @@ import org.apache.ignite.lang.IgniteBiPredicate; import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteCallable; import org.apache.ignite.lang.IgniteClosure; +import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.lang.IgniteReducer; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.resources.IgniteInstanceResource; @@ -145,6 +146,9 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte /** Maximum number of query detail metrics to evict at once. */ private static final int QRY_DETAIL_METRICS_EVICTION_LIMIT = 10_000; + /** Support 'not null' field constraint since v 2.3.0. */ + private static final IgniteProductVersion NOT_NULLS_SUPPORT_VER = IgniteProductVersion.fromString("2.3.0"); + /** Comparator for priority queue with query detail metrics with priority to new metrics. */ private static final Comparator<GridCacheQueryDetailMetricsAdapter> QRY_DETAIL_METRICS_PRIORITY_NEW_CMP = new Comparator<GridCacheQueryDetailMetricsAdapter>() { @@ -1908,6 +1912,79 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte } /** + * Gets SQL metadata with not nulls fields. + * + * @return SQL metadata. + * @throws IgniteCheckedException In case of error. + */ + public Collection<GridCacheSqlMetadata> sqlMetadataV2() throws IgniteCheckedException { + if (!enterBusy()) + throw new IllegalStateException("Failed to get metadata (grid is stopping)."); + + try { + Callable<Collection<CacheSqlMetadata>> job = new GridCacheQuerySqlMetadataJobV2(); + + // Remote nodes that have current cache. + Collection<ClusterNode> nodes = CU.affinityNodes(cctx, AffinityTopologyVersion.NONE); + + Collection<Collection<CacheSqlMetadata>> res = new ArrayList<>(nodes.size() + 1); + + IgniteInternalFuture<Collection<Collection<CacheSqlMetadata>>> rmtFut = null; + + // Get metadata from remote nodes. + if (!nodes.isEmpty()) { + boolean allNodesNew = true; + + for (ClusterNode n : nodes) { + if (n.version().compareTo(NOT_NULLS_SUPPORT_VER) < 0) + allNodesNew = false; + } + + if (!allNodesNew) + return sqlMetadata(); + + rmtFut = cctx.closures().callAsyncNoFailover(BROADCAST, Collections.singleton(job), nodes, true, 0); + } + + // Get local metadata. + IgniteInternalFuture<Collection<CacheSqlMetadata>> locFut = cctx.closures().callLocalSafe(job, true); + + if (rmtFut != null) + res.addAll(rmtFut.get()); + + res.add(locFut.get()); + + Map<String, Collection<CacheSqlMetadata>> map = new HashMap<>(); + + for (Collection<CacheSqlMetadata> col : res) { + for (CacheSqlMetadata meta : col) { + String name = meta.cacheName(); + + Collection<CacheSqlMetadata> cacheMetas = map.get(name); + + if (cacheMetas == null) + map.put(name, cacheMetas = new LinkedList<>()); + + cacheMetas.add(meta); + } + } + + Collection<GridCacheSqlMetadata> col = new ArrayList<>(map.size()); + + // Metadata for current cache must be first in list. + col.add(new GridCacheQuerySqlMetadataV2(map.remove(cacheName))); + + for (Collection<CacheSqlMetadata> metas : map.values()) + col.add(new GridCacheQuerySqlMetadataV2(metas)); + + return col; + } + finally { + leaveBusy(); + } + } + + /** * @param <K> Key type. * @param <V> Value type. * @param includeBackups Include backups. @@ -2079,7 +2156,7 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte /** * Cache metadata. */ - private static class CacheSqlMetadata implements GridCacheSqlMetadata { + public static class CacheSqlMetadata implements GridCacheSqlMetadata { /** */ private static final long serialVersionUID = 0L; @@ -2183,6 +2260,11 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte } /** {@inheritDoc} */ + @Override public Collection<String> notNullFields(String type) { + return null; + } + + /** {@inheritDoc} */ @Override public Map<String, String> keyClasses() { return keyClasses; } @@ -2236,7 +2318,7 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte /** * Cache metadata index. */ - private static class CacheSqlIndexMetadata implements GridCacheSqlIndexMetadata { + public static class CacheSqlIndexMetadata implements GridCacheSqlIndexMetadata { /** */ private static final long serialVersionUID = 0L; @@ -2371,6 +2453,7 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte /** * @return Metadata. + * @throws IgniteCheckedException On error. */ public List<GridQueryFieldMetadata> metaData() throws IgniteCheckedException { get(); // Ensure that result is ready. http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQuerySqlMetadataJobV2.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQuerySqlMetadataJobV2.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQuerySqlMetadataJobV2.java new file mode 100644 index 0000000..9907d1a --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQuerySqlMetadataJobV2.java @@ -0,0 +1,154 @@ +/* + * 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.cache.query; + +import org.apache.ignite.Ignite; +import org.apache.ignite.cache.QueryIndexType; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteKernal; +import org.apache.ignite.internal.processors.cache.IgniteInternalCache; +import org.apache.ignite.internal.processors.datastructures.DataStructuresProcessor; +import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor; +import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; +import org.apache.ignite.internal.processors.task.GridInternal; +import org.apache.ignite.internal.util.typedef.C1; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.P1; +import org.apache.ignite.internal.util.typedef.internal.CU; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteCallable; +import org.apache.ignite.resources.IgniteInstanceResource; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +/** + * Metadata job. + */ +@GridInternal +class GridCacheQuerySqlMetadataJobV2 implements IgniteCallable<Collection<GridCacheQueryManager.CacheSqlMetadata>> { + /** */ + private static final long serialVersionUID = 0L; + + /** Number of fields to report when no fields defined. Includes _key and _val columns. */ + private static final int NO_FIELDS_COLUMNS_COUNT = 2; + + /** Grid */ + @IgniteInstanceResource + private Ignite ignite; + + /** {@inheritDoc} */ + @Override public Collection<GridCacheQueryManager.CacheSqlMetadata> call() { + final GridKernalContext ctx = ((IgniteKernal)ignite).context(); + + Collection<String> cacheNames = F.viewReadOnly(ctx.cache().caches(), + new C1<IgniteInternalCache<?, ?>, String>() { + @Override public String apply(IgniteInternalCache<?, ?> c) { + return c.name(); + } + }, + new P1<IgniteInternalCache<?, ?>>() { + @Override public boolean apply(IgniteInternalCache<?, ?> c) { + return !CU.isSystemCache(c.name()) && !DataStructuresProcessor.isDataStructureCache(c.name()); + } + } + ); + + return F.transform(cacheNames, new C1<String, GridCacheQueryManager.CacheSqlMetadata>() { + @Override public GridCacheQueryManager.CacheSqlMetadata apply(String cacheName) { + Collection<GridQueryTypeDescriptor> types = ctx.query().types(cacheName); + + Collection<String> names = U.newHashSet(types.size()); + Map<String, String> keyClasses = U.newHashMap(types.size()); + Map<String, String> valClasses = U.newHashMap(types.size()); + Map<String, Map<String, String>> fields = U.newHashMap(types.size()); + Map<String, Collection<GridCacheSqlIndexMetadata>> indexes = U.newHashMap(types.size()); + Map<String, Set<String>> notNullFields = U.newHashMap(types.size()); + + for (GridQueryTypeDescriptor type : types) { + // Filter internal types (e.g., data structures). + if (type.name().startsWith("GridCache")) + continue; + + names.add(type.name()); + + keyClasses.put(type.name(), type.keyClass().getName()); + valClasses.put(type.name(), type.valueClass().getName()); + + int size = type.fields().isEmpty() ? NO_FIELDS_COLUMNS_COUNT : type.fields().size(); + + Map<String, String> fieldsMap = U.newLinkedHashMap(size); + HashSet<String> notNullFieldsSet = U.newHashSet(1); + + // _KEY and _VAL are not included in GridIndexingTypeDescriptor.valueFields + if (type.fields().isEmpty()) { + fieldsMap.put("_KEY", type.keyClass().getName()); + fieldsMap.put("_VAL", type.valueClass().getName()); + } + + for (Map.Entry<String, Class<?>> e : type.fields().entrySet()) { + String fieldName = e.getKey(); + + fieldsMap.put(fieldName.toUpperCase(), e.getValue().getName()); + + if (type.property(fieldName).notNull()) + notNullFieldsSet.add(fieldName.toUpperCase()); + } + + fields.put(type.name(), fieldsMap); + notNullFields.put(type.name(), notNullFieldsSet); + + Map<String, GridQueryIndexDescriptor> idxs = type.indexes(); + + Collection<GridCacheSqlIndexMetadata> indexesCol = new ArrayList<>(idxs.size()); + + for (Map.Entry<String, GridQueryIndexDescriptor> e : idxs.entrySet()) { + GridQueryIndexDescriptor desc = e.getValue(); + + // Add only SQL indexes. + if (desc.type() == QueryIndexType.SORTED) { + Collection<String> idxFields = new LinkedList<>(); + Collection<String> descendings = new LinkedList<>(); + + for (String idxField : e.getValue().fields()) { + String idxFieldUpper = idxField.toUpperCase(); + + idxFields.add(idxFieldUpper); + + if (desc.descending(idxField)) + descendings.add(idxFieldUpper); + } + + indexesCol.add(new GridCacheQueryManager.CacheSqlIndexMetadata(e.getKey().toUpperCase(), + idxFields, descendings, false)); + } + } + + indexes.put(type.name(), indexesCol); + } + + return new GridCacheQuerySqlMetadataV2(cacheName, names, keyClasses, valClasses, fields, indexes, + notNullFields); + } + }); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQuerySqlMetadataV2.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQuerySqlMetadataV2.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQuerySqlMetadataV2.java new file mode 100644 index 0000000..66821c9 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQuerySqlMetadataV2.java @@ -0,0 +1,101 @@ +/* + * 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.cache.query; + +import org.apache.ignite.internal.util.typedef.internal.U; +import org.jetbrains.annotations.Nullable; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Cache metadata with not null field. + */ +public class GridCacheQuerySqlMetadataV2 extends GridCacheQueryManager.CacheSqlMetadata { + /** */ + private static final long serialVersionUID = 0L; + + /** Not null fields. */ + private Map<String, Set<String>> notNullFields; + + /** + * Required by {@link Externalizable}. + */ + public GridCacheQuerySqlMetadataV2() { + // No-op. + } + + /** + * @param cacheName Cache name. + * @param types Types. + * @param keyClasses Key classes map. + * @param valClasses Value classes map. + * @param fields Fields maps. + * @param indexes Indexes. + * @param notNullFields Not null fields. + */ + GridCacheQuerySqlMetadataV2(@Nullable String cacheName, Collection<String> types, Map<String, String> keyClasses, + Map<String, String> valClasses, Map<String, Map<String, String>> fields, + Map<String, Collection<GridCacheSqlIndexMetadata>> indexes, Map<String, Set<String>> notNullFields) { + super(cacheName, types, keyClasses, valClasses, fields, indexes); + + this.notNullFields = notNullFields; + } + + /** + * @param metas Meta data instances from different nodes. + */ + GridCacheQuerySqlMetadataV2(Iterable<GridCacheQueryManager.CacheSqlMetadata> metas) { + super(metas); + + notNullFields = new HashMap<>(); + + for (GridCacheQueryManager.CacheSqlMetadata meta : metas) { + if (meta instanceof GridCacheQuerySqlMetadataV2) { + GridCacheQuerySqlMetadataV2 metaV2 = (GridCacheQuerySqlMetadataV2)meta; + + notNullFields.putAll(metaV2.notNullFields); + } + } + } + + /** {@inheritDoc} */ + @Override public Collection<String> notNullFields(String type) { + return notNullFields.get(type); + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + super.writeExternal(out); + + U.writeMap(out, notNullFields); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + super.readExternal(in); + + notNullFields = U.readHashMap(in); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java index 724962e..ddc2860 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlMetadata.java @@ -78,6 +78,14 @@ public interface GridCacheSqlMetadata extends Externalizable { @Nullable public Map<String, String> fields(String type); /** + * Gets not null fields. + * + * @param type Type name. + * @return Not null fields collection map or {@code null} if type name is unknown. + */ + Collection<String> notNullFields(String type); + + /** * @return Key classes. */ public Map<String, String> keyClasses(); http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMeta.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMeta.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMeta.java index 9f145e0..d927c26 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMeta.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMeta.java @@ -20,6 +20,7 @@ package org.apache.ignite.internal.processors.odbc.jdbc; import org.apache.ignite.internal.binary.BinaryReaderExImpl; import org.apache.ignite.internal.binary.BinaryWriterExImpl; import org.apache.ignite.internal.jdbc.thin.JdbcThinUtils; +import org.apache.ignite.internal.jdbc2.JdbcUtils; import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; @@ -126,6 +127,15 @@ public class JdbcColumnMeta implements JdbcRawBinarylizable { return dataTypeClass; } + /** + * Return 'nullable' flag in compatibility mode (according with column name and column type). + * + * @return {@code true} in case the column allows null values. Otherwise returns {@code false} + */ + public boolean isNullable() { + return JdbcUtils.nullable(colName, dataTypeClass); + } + /** {@inheritDoc} */ @Override public void writeBinary(BinaryWriterExImpl writer) { writer.writeString(schemaName); http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV2.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV2.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV2.java new file mode 100644 index 0000000..a2b4acf --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV2.java @@ -0,0 +1,74 @@ +/* + * 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 org.apache.ignite.internal.binary.BinaryReaderExImpl; +import org.apache.ignite.internal.binary.BinaryWriterExImpl; +import org.apache.ignite.internal.util.typedef.internal.S; + +/** + * JDBC column metadata. + */ +public class JdbcColumnMetaV2 extends JdbcColumnMeta{ + /** Allow nulls . */ + private boolean nullable; + + /** + * Default constructor is used for serialization. + */ + JdbcColumnMetaV2() { + // No-op. + } + + /** + * @param schemaName Schema. + * @param tblName Table. + * @param colName Column. + * @param cls Type. + * @param nullable Allow nulls. + */ + public JdbcColumnMetaV2(String schemaName, String tblName, String colName, Class<?> cls, boolean nullable) { + super(schemaName, tblName, colName, cls); + + this.nullable = nullable; + } + + /** {@inheritDoc} */ + @Override public boolean isNullable() { + return nullable; + } + + /** {@inheritDoc} */ + @Override public void writeBinary(BinaryWriterExImpl writer) { + super.writeBinary(writer); + + writer.writeBoolean(nullable); + } + + /** {@inheritDoc} */ + @Override public void readBinary(BinaryReaderExImpl reader) { + super.readBinary(reader); + + nullable = reader.readBoolean(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcColumnMetaV2.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java ---------------------------------------------------------------------- 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 38d1972..a6a7aa5 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 @@ -38,10 +38,10 @@ public class JdbcConnectionContext implements ClientListenerConnectionContext { private static final ClientListenerProtocolVersion VER_2_1_5 = ClientListenerProtocolVersion.create(2, 1, 5); /** Version 2.3.1: added "multiple statements query" feature. */ - public static final ClientListenerProtocolVersion VER_2_3_1 = ClientListenerProtocolVersion.create(2, 3, 1); + public static final ClientListenerProtocolVersion VER_2_3_0 = ClientListenerProtocolVersion.create(2, 3, 0); /** Current version. */ - private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_3_1; + private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_3_0; /** Supported versions. */ private static final Set<ClientListenerProtocolVersion> SUPPORTED_VERS = new HashSet<>(); http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResult.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResult.java index da270de..9931ce0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResult.java @@ -51,6 +51,25 @@ public class JdbcMetaColumnsResult extends JdbcResult { } /** + * Used by children classes. + * @param type Type ID. + */ + protected JdbcMetaColumnsResult(byte type) { + super(type); + } + + /** + * Used by children classes. + * @param type Type ID. + * @param meta Columns metadata. + */ + protected JdbcMetaColumnsResult(byte type, Collection<JdbcColumnMeta> meta) { + super(type); + + this.meta = new ArrayList<>(meta); + } + + /** * @return Columns metadata. */ public List<JdbcColumnMeta> meta() { @@ -83,7 +102,7 @@ public class JdbcMetaColumnsResult extends JdbcResult { meta = new ArrayList<>(size); for (int i = 0; i < size; ++i) { - JdbcColumnMeta m = new JdbcColumnMeta(); + JdbcColumnMeta m = createMetaColumn(); m.readBinary(reader); @@ -92,6 +111,13 @@ public class JdbcMetaColumnsResult extends JdbcResult { } } + /** + * @return Empty columns metadata to deserialization. + */ + protected JdbcColumnMeta createMetaColumn() { + return new JdbcColumnMeta(); + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(JdbcMetaColumnsResult.class, this); http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV2.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV2.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV2.java new file mode 100644 index 0000000..2673a13 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV2.java @@ -0,0 +1,50 @@ +/* + * 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.util.Collection; +import org.apache.ignite.internal.util.typedef.internal.S; + +/** + * JDBC columns metadata result. + */ +public class JdbcMetaColumnsResultV2 extends JdbcMetaColumnsResult { + /** + * Default constructor is used for deserialization. + */ + JdbcMetaColumnsResultV2() { + super(META_COLUMNS_V2); + } + + /** + * @param meta Columns metadata. + */ + JdbcMetaColumnsResultV2(Collection<JdbcColumnMeta> meta) { + super(META_COLUMNS_V2, meta); + } + + /** {@inheritDoc} */ + @Override protected JdbcColumnMeta createMetaColumn() { + return new JdbcColumnMetaV2(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcMetaColumnsResultV2.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java ---------------------------------------------------------------------- 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 202f813..166402f 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 @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -43,6 +44,7 @@ import org.apache.ignite.internal.processors.odbc.ClientListenerRequestHandler; import org.apache.ignite.internal.processors.odbc.ClientListenerResponse; import org.apache.ignite.internal.processors.odbc.odbc.OdbcQueryGetColumnsMetaRequest; 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.QueryUtils; @@ -51,6 +53,7 @@ import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; +import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext.VER_2_3_0; import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.BATCH_EXEC; import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.META_COLUMNS; import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.META_INDEXES; @@ -291,7 +294,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { qry.setSchema(schemaName); List<FieldsQueryCursor<List<?>>> results = ctx.query().querySqlFieldsNoCache(qry, true, - protocolVer.compareTo(JdbcConnectionContext.VER_2_3_1) < 0); + protocolVer.compareTo(VER_2_3_0) < 0); if (results.size() == 1) { FieldsQueryCursor<List<?>> qryCur = results.get(0); @@ -559,9 +562,10 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { * @param req Get columns metadata request. * @return Response. */ + @SuppressWarnings("unchecked") private JdbcResponse getColumnsMeta(JdbcMetaColumnsRequest req) { try { - Collection<JdbcColumnMeta> meta = new HashSet<>(); + Collection<JdbcColumnMeta> meta = new LinkedHashSet<>(); for (String cacheName : ctx.cache().publicCacheNames()) { for (GridQueryTypeDescriptor table : ctx.query().types(cacheName)) { @@ -572,11 +576,22 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { continue; for (Map.Entry<String, Class<?>> field : table.fields().entrySet()) { - if (!matches(field.getKey(), req.columnName())) + String colName = field.getKey(); + + if (!matches(colName, req.columnName())) continue; - JdbcColumnMeta columnMeta = new JdbcColumnMeta(table.schemaName(), table.tableName(), - field.getKey(), field.getValue()); + JdbcColumnMeta columnMeta; + + 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); @@ -584,7 +599,12 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { } } - JdbcMetaColumnsResult res = new JdbcMetaColumnsResult(meta); + JdbcMetaColumnsResult res; + + if (protocolVer.compareTo(VER_2_3_0) >= 0) + res = new JdbcMetaColumnsResultV2(meta); + else + res = new JdbcMetaColumnsResult(meta); return new JdbcResponse(res); } http://git-wip-us.apache.org/repos/asf/ignite/blob/c116bfc6/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java index c6c7438..6d460e6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java @@ -59,6 +59,9 @@ public class JdbcResult implements JdbcRawBinarylizable { /** Multiple statements query results. */ static final byte QRY_EXEC_MULT = 13; + /** Columns metadata result V2. */ + static final byte META_COLUMNS_V2 = 14; + /** Success status. */ private byte type; @@ -147,6 +150,11 @@ public class JdbcResult implements JdbcRawBinarylizable { break; + case META_COLUMNS_V2: + res = new JdbcMetaColumnsResultV2(); + + break; + default: throw new IgniteException("Unknown SQL listener request ID: [request ID=" + resId + ']'); }
