This is an automated email from the ASF dual-hosted git repository. amashenkov 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 4b3d155 IGNITE-13075 NPE on request JDBC metadata. (#7851) 4b3d155 is described below commit 4b3d155f4f38f5cf0d520752a440cc43ebfe42cd Author: korlov42 <kor...@gridgain.com> AuthorDate: Fri May 29 16:25:33 2020 +0300 IGNITE-13075 NPE on request JDBC metadata. (#7851) --- .../ignite/jdbc/thin/JdbcThinMetadataSelfTest.java | 105 +++++++++++++++++++++ .../internal/processors/query/QueryUtils.java | 26 ++--- .../apache/ignite/internal/util/lang/GridFunc.java | 14 +++ 3 files changed, 126 insertions(+), 19 deletions(-) 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 e8aeb58..a2c1eff 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 @@ -62,7 +62,10 @@ import static java.sql.Types.VARCHAR; import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; import static org.apache.ignite.internal.processors.query.QueryUtils.DFLT_SCHEMA; +import static org.apache.ignite.internal.processors.query.QueryUtils.KEY_FIELD_NAME; import static org.apache.ignite.internal.processors.query.QueryUtils.SCHEMA_SYS; +import static org.apache.ignite.internal.processors.query.QueryUtils.VAL_FIELD_NAME; +import static org.apache.ignite.internal.util.lang.GridFunc.asMap; /** * Metadata tests. @@ -204,6 +207,84 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { } /** + * Ensure metadata returned for cache without explicit query entities: <ul> + * <li>create a cache with indexed types and without explicit query entities</li> + * <li>request metadata for columns from the cache</li> + * <li>verify returned result</li> + * </ul> + * + * @throws SQLException + */ + @Test + public void testMetadataPresentedForAutogeneratedColumns() throws SQLException { + final String cacheName = "testCache"; + + IgniteCache<?, ?> cache = grid(0).createCache( + new CacheConfiguration<>(cacheName).setIndexedTypes(Integer.class, String.class) + ); + + try (Connection conn = DriverManager.getConnection(URL)) { + DatabaseMetaData meta = conn.getMetaData(); + + ResultSet rs = meta.getColumns(null, cacheName, null, null); + + assertTrue(rs.next()); + assertEquals(cacheName, rs.getString(MetadataColumn.TABLE_SCHEMA.columnName())); + assertEquals(KEY_FIELD_NAME, rs.getString(MetadataColumn.COLUMN_NAME.columnName())); + + assertTrue(rs.next()); + assertEquals(cacheName, rs.getString(MetadataColumn.TABLE_SCHEMA.columnName())); + assertEquals(VAL_FIELD_NAME, rs.getString(MetadataColumn.COLUMN_NAME.columnName())); + + assertFalse(rs.next()); + } + finally { + cache.destroy(); + } + } + + /** + * Ensure metadata returned for cache with explicit query entities has no duplicate columns: <ul> + * <li>create a cache with indexed types and explicit query entity</li> + * <li>request metadata for columns from the cache</li> + * <li>verify returned result</li> + * </ul> + * + * @throws SQLException + */ + @Test + public void testMetadataNotDublicatedIfFieldsSetExplicitly() throws SQLException { + final String cacheName = "testCache"; + + IgniteCache<?, ?> cache = grid(0).createCache( + new CacheConfiguration<>(cacheName) + .setQueryEntities(Collections.singleton( + new QueryEntity() + .setKeyType(Integer.class.getName()) + .setKeyFieldName("my_key") + .setValueType(String.class.getName()) + .setFields(new LinkedHashMap<>(asMap("my_key", Integer.class.getName()))) + )) + .setIndexedTypes(Integer.class, String.class) + ); + + try (Connection conn = DriverManager.getConnection(URL)) { + DatabaseMetaData meta = conn.getMetaData(); + + ResultSet rs = meta.getColumns(null, cacheName, null, null); + + assertTrue(rs.next()); + assertEquals(cacheName, rs.getString(MetadataColumn.TABLE_SCHEMA.columnName())); + assertEquals("MY_KEY", rs.getString(MetadataColumn.COLUMN_NAME.columnName())); + + assertFalse(rs.next()); + } + finally { + cache.destroy(); + } + } + + /** * @throws Exception If failed. */ @Test @@ -1341,4 +1422,28 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { this.name = name; } } + + /** */ + private enum MetadataColumn { + /** */ + TABLE_SCHEMA("TABLE_SCHEM"), + + /** */ + COLUMN_NAME("COLUMN_NAME"); + + /** Column name. */ + private final String colName; + + /** + * @param colName Column name. + */ + MetadataColumn(String colName) { + this.colName = colName; + } + + /** */ + public String columnName() { + return colName; + } + } } 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 8487d78..5edb492 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 @@ -625,25 +625,13 @@ public class QueryUtils { } // Sql-typed key/value doesn't have field property, but they may have precision and scale constraints. - String keyFieldName = qryEntity.getKeyFieldName(); + // Also if fields are not set then _KEY and _VAL will be created as visible, + // so we have to add binary properties for them + if ((qryEntity.getKeyFieldName() == null && F.mapContainsKey(precision, KEY_FIELD_NAME)) || F.isEmpty(fields)) + addKeyValueProperty(ctx, qryEntity, d, KEY_FIELD_NAME, true); - if (keyFieldName == null) - keyFieldName = KEY_FIELD_NAME; - - if (!F.isEmpty(precision) && precision.containsKey(keyFieldName) && - !fields.containsKey(keyFieldName)) { - addKeyValueValidationProperty(ctx, qryEntity, d, keyFieldName, true); - } - - String valFieldName = qryEntity.getValueFieldName(); - - if (valFieldName == null) - valFieldName = VAL_FIELD_NAME; - - if (!F.isEmpty(precision) && precision.containsKey(valFieldName) && - !fields.containsKey(valFieldName)) { - addKeyValueValidationProperty(ctx, qryEntity, d, valFieldName, false); - } + if ((qryEntity.getValueFieldName() == null && F.mapContainsKey(precision, VAL_FIELD_NAME)) || F.isEmpty(fields)) + addKeyValueProperty(ctx, qryEntity, d, VAL_FIELD_NAME, false); processIndexes(qryEntity, d); } @@ -657,7 +645,7 @@ public class QueryUtils { * @param name Field name. * @throws IgniteCheckedException */ - private static void addKeyValueValidationProperty(GridKernalContext ctx, QueryEntity qryEntity, QueryTypeDescriptorImpl d, + private static void addKeyValueProperty(GridKernalContext ctx, QueryEntity qryEntity, QueryTypeDescriptorImpl d, String name, boolean isKey) throws IgniteCheckedException { Map<String, Object> dfltVals = qryEntity.getDefaultFieldValues(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java b/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java index e8d156c..cb53ac4 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/lang/GridFunc.java @@ -2799,6 +2799,20 @@ public class GridFunc { } /** + * Checks if key is contained in the map passed in. If the map + * is {@code null}, then {@code false} is returned. + * + * @param m Map to check. + * @param k Key to check for containment. + * @param <T> Key type. + * @return {@code true} if map is not {@code null} and contains given + * key, {@code false} otherwise. + */ + public static <T> boolean mapContainsKey(@Nullable final Map<T, ?> m, final T k) { + return m != null && m.containsKey(k); + } + + /** * Check's that {@code val} contains ignore case in collection {@code col}. * * @param col Collection of values.