IGNITE-7691: Provide info about DECIMAL column precision and scale. - Fixes #3691.
Signed-off-by: Nikolay Izhikov <nizhi...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/6df5f99b Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/6df5f99b Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/6df5f99b Branch: refs/heads/ignite-7708 Commit: 6df5f99bec46d9b0eabd2e623f0d26b32d031e4c Parents: 08a700d Author: Nikolay Izhikov <nizhi...@apache.org> Authored: Fri Apr 13 11:53:50 2018 +0300 Committer: Nikolay Izhikov <nizhi...@apache.org> Committed: Fri Apr 13 11:53:50 2018 +0300 ---------------------------------------------------------------------- .../jdbc/thin/JdbcThinMetadataSelfTest.java | 22 +- .../org/apache/ignite/cache/QueryEntity.java | 41 ++- .../cache/query/annotations/QuerySqlField.java | 16 +- .../internal/client/thin/ClientUtils.java | 38 ++- .../jdbc/thin/JdbcThinDatabaseMetadata.java | 6 +- .../cache/query/QueryEntityTypeDescriptor.java | 21 ++ .../processors/odbc/jdbc/JdbcColumnMeta.java | 14 + .../processors/odbc/jdbc/JdbcColumnMetaV4.java | 90 +++++++ .../odbc/jdbc/JdbcConnectionContext.java | 4 +- .../odbc/jdbc/JdbcMetaColumnsResultV4.java | 50 ++++ .../odbc/jdbc/JdbcRequestHandler.java | 14 +- .../processors/odbc/jdbc/JdbcResult.java | 8 + .../utils/PlatformConfigurationUtils.java | 20 ++ .../processors/query/GridQueryProcessor.java | 2 +- .../processors/query/GridQueryProperty.java | 14 + .../internal/processors/query/QueryField.java | 26 +- .../internal/processors/query/QueryUtils.java | 28 +- .../query/property/QueryBinaryProperty.java | 23 +- .../query/property/QueryClassProperty.java | 10 + .../query/h2/ddl/DdlStatementsProcessor.java | 13 +- .../processors/query/h2/sql/GridSqlColumn.java | 17 +- .../cache/index/IgniteDecimalSelfTest.java | 265 +++++++++++++++++++ .../h2/GridIndexingSpiAbstractSelfTest.java | 12 +- .../IgniteCacheQuerySelfTestSuite.java | 2 + .../QueryEntityConfigurationParityTest.cs | 5 +- .../Cache/CacheConfigurationTest.cs | 2 + .../Cache/Configuration/QueryEntity.cs | 4 +- .../Cache/Configuration/QueryField.cs | 16 +- .../Configuration/QuerySqlFieldAttribute.cs | 10 + .../IgniteConfigurationSection.xsd | 10 + 30 files changed, 773 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/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 4a34be6..cc6790a 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 @@ -18,6 +18,7 @@ package org.apache.ignite.jdbc.thin; import java.io.Serializable; +import java.math.BigDecimal; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; @@ -143,6 +144,7 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { stmt.execute("CREATE TABLE \"Quoted\" (\"Id\" INT primary key, \"Name\" VARCHAR(50)) WITH WRAP_KEY"); stmt.execute("CREATE INDEX \"MyTestIndex quoted\" on \"Quoted\" (\"Id\" DESC)"); stmt.execute("CREATE INDEX IDX ON TEST (ID ASC)"); + stmt.execute("CREATE TABLE TEST_DECIMAL_COLUMN (ID INT primary key, DEC_COL DECIMAL(8, 3))"); } } @@ -244,7 +246,8 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { "org.ORGANIZATION", "pers.PERSON", "PUBLIC.TEST", - "PUBLIC.Quoted")); + "PUBLIC.Quoted", + "PUBLIC.TEST_DECIMAL_COLUMN")); Set<String> actualTbls = new HashSet<>(expectedTbls.size()); @@ -390,15 +393,25 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { "PUBLIC.TEST.VAL.null", "PUBLIC.TEST.AGE.21", "PUBLIC.Quoted.Id.null", - "PUBLIC.Quoted.Name.null")); + "PUBLIC.Quoted.Name.null", + "PUBLIC.TEST_DECIMAL_COLUMN.ID.null", + "PUBLIC.TEST_DECIMAL_COLUMN.DEC_COL.null.8.3" + )); Set<String> actualCols = new HashSet<>(expectedCols.size()); while(rs.next()) { + int precision = rs.getInt("COLUMN_SIZE"); + + int scale = rs.getInt("DECIMAL_DIGITS"); + actualCols.add(rs.getString("TABLE_SCHEM") + '.' + rs.getString("TABLE_NAME") + "." + rs.getString("COLUMN_NAME") + "." - + rs.getString("COLUMN_DEF")); + + rs.getString("COLUMN_DEF") + + (precision == 0 ? "" : ("." + precision)) + + (scale == 0 ? "" : ("." + scale)) + ); } assert expectedCols.equals(actualCols) : "expectedCols=" + expectedCols + @@ -532,7 +545,8 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { "pers.PERSON.PK_pers_PERSON._KEY", "PUBLIC.TEST.PK_PUBLIC_TEST.ID", "PUBLIC.TEST.PK_PUBLIC_TEST.NAME", - "PUBLIC.Quoted.PK_PUBLIC_Quoted.Id")); + "PUBLIC.Quoted.PK_PUBLIC_Quoted.Id", + "PUBLIC.TEST_DECIMAL_COLUMN.ID._KEY")); Set<String> actualPks = new HashSet<>(expectedPks.size()); http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java index 0065bae..aff3461 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java @@ -19,6 +19,7 @@ package org.apache.ignite.cache; import java.io.Serializable; import java.lang.reflect.Field; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -42,8 +43,11 @@ import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteBiTuple; import org.jetbrains.annotations.Nullable; +import static java.util.Collections.unmodifiableMap; + /** * Query entity is a description of {@link org.apache.ignite.IgniteCache cache} entry (composed of key and value) * in a way of how it must be indexed and can be queried. @@ -89,6 +93,9 @@ public class QueryEntity implements Serializable { /** Fields default values. */ private Map<String, Object> defaultFieldValues = new HashMap<>(); + /** Decimal fields information. */ + private Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = new HashMap<>(); + /** * Creates an empty query entity. */ @@ -120,6 +127,8 @@ public class QueryEntity implements Serializable { defaultFieldValues = other.defaultFieldValues != null ? new HashMap<>(other.defaultFieldValues) : new HashMap<String, Object>(); + + decimalInfo = other.decimalInfo != null ? new HashMap<>(other.decimalInfo) : new HashMap<>(); } /** @@ -391,6 +400,27 @@ public class QueryEntity implements Serializable { } /** + * Gets set of field name to precision and scale. + * + * @return Set of names of fields that must have non-null values. + */ + public Map<String, IgniteBiTuple<Integer, Integer>> getDecimalInfo() { + return unmodifiableMap(decimalInfo); + } + + /** + * Sets decimal fields info. + * + * @param decimalInfo Set of name to precision and scale for decimal fields. + * @return {@code this} for chaining. + */ + public QueryEntity setDecimalInfo(Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo) { + this.decimalInfo = decimalInfo; + + return this; + } + + /** * Gets fields default values. * * @return Field's name to default value map. @@ -504,6 +534,9 @@ public class QueryEntity implements Serializable { if (!F.isEmpty(desc.notNullFields())) entity.setNotNullFields(desc.notNullFields()); + if (!F.isEmpty(desc.decimalInfo())) + entity.setDecimalInfo(desc.decimalInfo()); + return entity; } @@ -629,6 +662,9 @@ public class QueryEntity implements Serializable { if (sqlAnn.notNull()) desc.addNotNullField(prop.fullName()); + if (BigDecimal.class == fldCls && sqlAnn.precision() != -1 && sqlAnn.scale() != -1) + desc.addDecimalInfo(prop.fullName(), F.t(sqlAnn.precision(), sqlAnn.scale())); + if ((!F.isEmpty(sqlAnn.groups()) || !F.isEmpty(sqlAnn.orderedGroups())) && sqlAnn.inlineSize() != QueryIndex.DFLT_INLINE_SIZE) { throw new CacheException("Inline size cannot be set on a field with group index [" + @@ -670,13 +706,14 @@ public class QueryEntity implements Serializable { F.eqNotOrdered(idxs, entity.idxs) && F.eq(tableName, entity.tableName) && F.eq(_notNullFields, entity._notNullFields) && - F.eq(defaultFieldValues, entity.defaultFieldValues); + F.eq(defaultFieldValues, entity.defaultFieldValues) && + F.eq(decimalInfo, entity.decimalInfo); } /** {@inheritDoc} */ @Override public int hashCode() { return Objects.hash(keyType, valType, keyFieldName, valueFieldName, fields, keyFields, aliases, idxs, - tableName, _notNullFields, defaultFieldValues); + tableName, _notNullFields, defaultFieldValues, decimalInfo); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java b/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java index 0343474..35b7575 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java @@ -64,6 +64,20 @@ public @interface QuerySqlField { boolean notNull() default false; /** + * Specifies precision for a decimal field. + * + * @return precision for a decimal field. + */ + int precision() default -1; + + /** + * Specifies scale for a decimal field. + * + * @return scale for a decimal field. + */ + int scale() default -1; + + /** * Array of index groups this field belongs to. Groups are used for compound indexes, * whenever index should be created on more than one field. All fields within the same * group will belong to the same index. @@ -155,4 +169,4 @@ public @interface QuerySqlField { */ boolean descending() default false; } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientUtils.java index e21cc4e..a50d78e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/thin/ClientUtils.java @@ -55,6 +55,7 @@ import org.apache.ignite.internal.binary.BinarySchema; import org.apache.ignite.internal.binary.BinaryWriterExImpl; import org.apache.ignite.internal.binary.streams.BinaryInputStream; import org.apache.ignite.internal.binary.streams.BinaryOutputStream; +import org.apache.ignite.lang.IgniteBiTuple; /** * Shared serialization/deserialization utils. @@ -309,6 +310,8 @@ final class ClientUtils { w.writeBoolean(qf.isKey()); w.writeBoolean(qf.isNotNull()); w.writeObject(qf.getDefaultValue()); + w.writeInt(qf.getPrecision()); + w.writeInt(qf.getScale()); } ); ClientUtils.collection( @@ -392,7 +395,9 @@ final class ClientUtils { reader.readString(), reader.readBoolean(), reader.readBoolean(), - reader.readObject() + reader.readObject(), + reader.readInt(), + reader.readInt() ) ); @@ -494,6 +499,12 @@ final class ClientUtils { /** Default value. */ private final Object dfltVal; + /** Precision. */ + private final int precision; + + /** Scale. */ + private final int scale; + /** Serialization constructor. */ QueryField(QueryEntity e, Map.Entry<String, String> nameAndTypeName) { name = nameAndTypeName.getKey(); @@ -502,19 +513,28 @@ final class ClientUtils { Set<String> keys = e.getKeyFields(); Set<String> notNulls = e.getNotNullFields(); Map<String, Object> dflts = e.getDefaultFieldValues(); + Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = e.getDecimalInfo(); isKey = keys != null && keys.contains(name); isNotNull = notNulls != null && notNulls.contains(name); dfltVal = dflts == null ? null : dflts.get(name); + + IgniteBiTuple<Integer, Integer> precisionAndScale = decimalInfo == null ? null : decimalInfo.get(name); + + precision = precisionAndScale == null? -1 : precisionAndScale.get1(); + scale = precisionAndScale == null? -1 : precisionAndScale.get2(); } /** Deserialization constructor. */ - public QueryField(String name, String typeName, boolean isKey, boolean isNotNull, Object dfltVal) { + public QueryField(String name, String typeName, boolean isKey, boolean isNotNull, Object dfltVal, + int precision, int scale) { this.name = name; this.typeName = typeName; this.isKey = isKey; this.isNotNull = isNotNull; this.dfltVal = dfltVal; + this.precision = precision; + this.scale = scale; } /** @@ -551,6 +571,20 @@ final class ClientUtils { Object getDefaultValue() { return dfltVal; } + + /** + * @return Precision. + */ + public int getPrecision() { + return precision; + } + + /** + * @return Scale. + */ + public int getScale() { + return scale; + } } /** Thin client protocol cache configuration item codes. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/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 dd8b733..7adc301 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 @@ -846,9 +846,9 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData { row.add(colMeta.columnName()); // 4. COLUMN_NAME row.add(colMeta.dataType()); // 5. DATA_TYPE row.add(colMeta.dataTypeName()); // 6. TYPE_NAME - row.add((Integer)null); // 7. COLUMN_SIZE + row.add(colMeta.precision() == -1 ? null : colMeta.precision()); // 7. COLUMN_SIZE row.add((Integer)null); // 8. BUFFER_LENGTH - row.add((Integer)null); // 9. DECIMAL_DIGITS + 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 @@ -1542,4 +1542,4 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData { @Override public boolean generatedKeyAlwaysReturned() throws SQLException { return false; } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java index fd0ef2b..9f8abc1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java @@ -30,6 +30,7 @@ import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.lang.IgniteBiTuple; /** * Descriptor of type. @@ -54,6 +55,9 @@ public class QueryEntityTypeDescriptor { /** */ private Set<String> notNullFields = new HashSet<>(); + /** Decimal fields information. */ + private Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = new HashMap<>(); + /** */ private QueryEntityIndexDescriptor fullTextIdx; @@ -187,6 +191,16 @@ public class QueryEntityTypeDescriptor { } /** + * Adds decimal info. + * + * @param field Field. + * @param info Decimal column info. + */ + public void addDecimalInfo(String field, IgniteBiTuple<Integer, Integer> info) { + decimalInfo.put(field, info); + } + + /** * @return notNull fields. */ public Set<String> notNullFields() { @@ -194,6 +208,13 @@ public class QueryEntityTypeDescriptor { } /** + * @return Decimal info for fields. + */ + public Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo() { + return decimalInfo; + } + + /** * @return Class properties. */ public Map<String, QueryEntityClassProperty> properties() { http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/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 c0ac322..5b6304d 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 @@ -135,6 +135,20 @@ public class JdbcColumnMeta implements JdbcRawBinarylizable { } /** + * @return Column's precision. + */ + public int precision() { + return -1; + } + + /** + * @return Column's scale. + */ + public int scale() { + return -1; + } + + /** * 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} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV4.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV4.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV4.java new file mode 100644 index 0000000..ec76983 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV4.java @@ -0,0 +1,90 @@ +/* + * 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 V4. + */ +public class JdbcColumnMetaV4 extends JdbcColumnMetaV3 { + /** Decimal field precision. */ + private int precision; + + /** Decimal field scale. */ + private int scale; + + /** + * Default constructor is used for serialization. + */ + JdbcColumnMetaV4() { + // No-op. + } + + /** + * @param schemaName Schema. + * @param tblName Table. + * @param colName Column. + * @param cls Type. + * @param nullable Allow nulls. + * @param dfltVal Default value. + * @param precision Decimal column precision. + * @param scale Decimal column scale. + */ + public JdbcColumnMetaV4(String schemaName, String tblName, String colName, Class<?> cls, boolean nullable, + Object dfltVal, int precision, int scale) { + super(schemaName, tblName, colName, cls, nullable, dfltVal); + + this.precision = precision; + + this.scale = scale; + } + + /** {@inheritDoc} */ + @Override public int precision() { + return precision; + } + + /** {@inheritDoc} */ + @Override public int scale() { + return scale; + } + + /** {@inheritDoc} */ + @Override public void writeBinary(BinaryWriterExImpl writer) { + super.writeBinary(writer); + + writer.writeInt(precision); + writer.writeInt(scale); + } + + /** {@inheritDoc} */ + @Override public void readBinary(BinaryReaderExImpl reader) { + super.readBinary(reader); + + precision = reader.readInt(); + scale = reader.readInt(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcColumnMetaV4.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/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 2fe3b9c..ed37e0b 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 @@ -47,8 +47,8 @@ public class JdbcConnectionContext implements ClientListenerConnectionContext { /** Version 2.4.0: adds default values for columns feature. */ static final ClientListenerProtocolVersion VER_2_4_0 = ClientListenerProtocolVersion.create(2, 4, 0); - /** Version 2.5.0. */ - private static final ClientListenerProtocolVersion VER_2_5_0 = ClientListenerProtocolVersion.create(2, 5, 0); + /** Version 2.5.0: adds precision and scale for columns feature. */ + static final ClientListenerProtocolVersion VER_2_5_0 = ClientListenerProtocolVersion.create(2, 5, 0); /** Current version. */ private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_5_0; http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV4.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV4.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV4.java new file mode 100644 index 0000000..9c8e2b7 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV4.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 JdbcMetaColumnsResultV4 extends JdbcMetaColumnsResult { + /** + * Default constructor is used for deserialization. + */ + JdbcMetaColumnsResultV4() { + super(META_COLUMNS_V4); + } + + /** + * @param meta Columns metadata. + */ + JdbcMetaColumnsResultV4(Collection<JdbcColumnMeta> meta) { + super(META_COLUMNS_V4, meta); + } + + /** {@inheritDoc} */ + @Override protected JdbcColumnMeta createMetaColumn() { + return new JdbcColumnMetaV4(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcMetaColumnsResultV4.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/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 cf0e98b..b9c9cdd 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 @@ -67,6 +67,7 @@ import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcBulkLoadBatchR import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcBulkLoadBatchRequest.CMD_FINISHED_ERROR; 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_5_0; import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.BATCH_EXEC; import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.BULK_LOAD_BATCH; import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.META_COLUMNS; @@ -744,7 +745,14 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { JdbcColumnMeta columnMeta; - if (protocolVer.compareTo(VER_2_4_0) >= 0) { + if (protocolVer.compareTo(VER_2_5_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(), @@ -768,7 +776,9 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { JdbcMetaColumnsResult res; - if (protocolVer.compareTo(VER_2_4_0) >= 0) + if (protocolVer.compareTo(VER_2_5_0) >= 0) + res = new JdbcMetaColumnsResultV4(meta); + else if (protocolVer.compareTo(VER_2_4_0) >= 0) res = new JdbcMetaColumnsResultV3(meta); else if (protocolVer.compareTo(VER_2_3_0) >= 0) res = new JdbcMetaColumnsResultV2(meta); http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/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 43631e9..4fea207 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 @@ -68,6 +68,9 @@ public class JdbcResult implements JdbcRawBinarylizable { /** A request to send file from client to server. */ static final byte BULK_LOAD_ACK = 16; + /** Columns metadata result V4. */ + static final byte META_COLUMNS_V4 = 17; + /** Success status. */ private byte type; @@ -171,6 +174,11 @@ public class JdbcResult implements JdbcRawBinarylizable { break; + case META_COLUMNS_V4: + res = new JdbcMetaColumnsResultV4(); + + break; + default: throw new IgniteException("Unknown SQL listener request ID: [request ID=" + resId + ']'); } http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java index 8ebf09e..fa8e509 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java @@ -76,6 +76,8 @@ import org.apache.ignite.internal.processors.platform.cache.affinity.PlatformAff import org.apache.ignite.internal.processors.platform.cache.expiry.PlatformExpiryPolicyFactory; import org.apache.ignite.internal.processors.platform.events.PlatformLocalEventListener; import org.apache.ignite.internal.processors.platform.plugin.cache.PlatformCachePluginConfiguration; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.platform.dotnet.PlatformDotNetAffinityFunction; import org.apache.ignite.platform.dotnet.PlatformDotNetBinaryConfiguration; @@ -492,6 +494,7 @@ public class PlatformConfigurationUtils { Set<String> keyFields = new HashSet<>(cnt); Set<String> notNullFields = new HashSet<>(cnt); Map<String, Object> defVals = new HashMap<>(cnt); + Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = new HashMap<>(cnt); if (cnt > 0) { LinkedHashMap<String, String> fields = new LinkedHashMap<>(cnt); @@ -511,6 +514,13 @@ public class PlatformConfigurationUtils { Object defVal = in.readObject(); if (defVal != null) defVals.put(fieldName, defVal); + + int precision = in.readInt(); + + int scale = in.readInt(); + + if (precision != -1 || scale != -1) + decimalInfo.put(fieldName, F.t(precision, scale)); } res.setFields(fields); @@ -523,6 +533,9 @@ public class PlatformConfigurationUtils { if (!defVals.isEmpty()) res.setDefaultFieldValues(defVals); + + if (!decimalInfo.isEmpty()) + res.setDecimalInfo(decimalInfo); } // Aliases @@ -1012,6 +1025,7 @@ public class PlatformConfigurationUtils { Set<String> keyFields = qryEntity.getKeyFields(); Set<String> notNullFields = qryEntity.getNotNullFields(); Map<String, Object> defVals = qryEntity.getDefaultFieldValues(); + Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = qryEntity.getDecimalInfo(); writer.writeInt(fields.size()); @@ -1021,6 +1035,12 @@ public class PlatformConfigurationUtils { writer.writeBoolean(keyFields != null && keyFields.contains(field.getKey())); writer.writeBoolean(notNullFields != null && notNullFields.contains(field.getKey())); writer.writeObject(defVals != null ? defVals.get(field.getKey()) : null); + + IgniteBiTuple<Integer, Integer> precisionAndScale = + decimalInfo == null ? null : decimalInfo.get(field.getKey()); + + writer.writeInt(precisionAndScale == null ? -1 : precisionAndScale.get1()); + writer.writeInt(precisionAndScale == null ? -1 : precisionAndScale.get2()); } } else http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index 03e5254..a74548a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -2400,7 +2400,7 @@ public class GridQueryProcessor extends GridProcessorAdapter { for (QueryField col : cols) { try { props.add(new QueryBinaryProperty(ctx, col.name(), null, Class.forName(col.typeName()), - false, null, !col.isNullable(), null)); + false, null, !col.isNullable(), null, -1, -1)); } catch (ClassNotFoundException e) { throw new SchemaOperationException("Class not found for new property: " + col.typeName()); http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProperty.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProperty.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProperty.java index b258b7c..448c844 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProperty.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProperty.java @@ -77,4 +77,18 @@ public interface GridQueryProperty { * @return {@code null} if a default value is not set for the property. */ public Object defaultValue(); + + /** + * Gets precision for this property. + * + * @return Precision for a decimal property or -1. + */ + public int precision(); + + /** + * Gets scale for this property. + * + * @return Scale for a decimal property or -1. + */ + public int scale(); } http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java index 1a75ef1..882d816 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java @@ -40,13 +40,19 @@ public class QueryField implements Serializable { /** Default value. */ private final Object dfltValue; + /** Precision. */ + private final int precision; + + /** Scale. */ + private final int scale; + /** * @param name Field name. * @param typeName Class name for this field's values. * @param nullable Nullable flag. */ public QueryField(String name, String typeName, boolean nullable) { - this(name, typeName, nullable, null); + this(name, typeName, nullable, null, -1, -1); } /** @@ -55,11 +61,13 @@ public class QueryField implements Serializable { * @param nullable Nullable flag. * @param dfltValue Default value. */ - public QueryField(String name, String typeName, boolean nullable, Object dfltValue) { + public QueryField(String name, String typeName, boolean nullable, Object dfltValue, int precision, int scale) { this.name = name; this.typeName = typeName; this.nullable = nullable; this.dfltValue = dfltValue; + this.precision = precision; + this.scale = scale; } /** @@ -90,6 +98,20 @@ public class QueryField implements Serializable { return dfltValue; } + /** + * @return Precision. + */ + public int precision() { + return precision; + } + + /** + * @return Scale. + */ + public int scale() { + return scale; + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(QueryField.class, this); http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java ---------------------------------------------------------------------- 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 2ee37a1..12eacef 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 @@ -61,6 +61,7 @@ import org.apache.ignite.internal.util.Jsr310Java8DateTimeApiUtils; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteBiTuple; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -264,6 +265,7 @@ public class QueryUtils { normalEntity.setValueFieldName(entity.getValueFieldName()); normalEntity.setNotNullFields(entity.getNotNullFields()); normalEntity.setDefaultFieldValues(entity.getDefaultFieldValues()); + normalEntity.setDecimalInfo(entity.getDecimalInfo()); // Normalize table name. String normalTblName = entity.getTableName(); @@ -541,6 +543,7 @@ public class QueryUtils { Set<String> keyFields = qryEntity.getKeyFields(); Set<String> notNulls = qryEntity.getNotNullFields(); Map<String, Object> dlftVals = qryEntity.getDefaultFieldValues(); + Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = qryEntity.getDecimalInfo(); // We have to distinguish between empty and null keyFields when the key is not of SQL type - // when a key is not of SQL type, absence of a field in nonnull keyFields tell us that this field @@ -571,9 +574,14 @@ public class QueryUtils { Object dfltVal = dlftVals != null ? dlftVals.get(entry.getKey()) : null; + IgniteBiTuple<Integer, Integer> precisionAndScale = + decimalInfo != null ? decimalInfo.get(entry.getKey()) : null; + QueryBinaryProperty prop = buildBinaryProperty(ctx, entry.getKey(), U.classForName(entry.getValue(), Object.class, true), - d.aliases(), isKeyField, notNull, dfltVal); + d.aliases(), isKeyField, notNull, dfltVal, + precisionAndScale != null ? precisionAndScale.get1() : -1, + precisionAndScale != null ? precisionAndScale.get2() : -1); d.addProperty(prop, false); } @@ -717,11 +725,14 @@ public class QueryUtils { * to key, {@code false} if it belongs to value, {@code null} if QueryEntity#keyFields is null. * @param notNull {@code true} if {@code null} value is not allowed. * @param dlftVal Default value. + * @param precision Precision. + * @param scale Scale. * @return Binary property. * @throws IgniteCheckedException On error. */ public static QueryBinaryProperty buildBinaryProperty(GridKernalContext ctx, String pathStr, Class<?> resType, - Map<String, String> aliases, @Nullable Boolean isKeyField, boolean notNull, Object dlftVal) throws IgniteCheckedException { + Map<String, String> aliases, @Nullable Boolean isKeyField, boolean notNull, Object dlftVal, + int precision, int scale) throws IgniteCheckedException { String[] path = pathStr.split("\\."); QueryBinaryProperty res = null; @@ -737,7 +748,8 @@ public class QueryUtils { String alias = aliases.get(fullName.toString()); // The key flag that we've found out is valid for the whole path. - res = new QueryBinaryProperty(ctx, prop, res, resType, isKeyField, alias, notNull, dlftVal); + res = new QueryBinaryProperty(ctx, prop, res, resType, isKeyField, alias, notNull, dlftVal, + precision, scale); } return res; @@ -1400,5 +1412,15 @@ public class QueryUtils { @Override public Object defaultValue() { return null; } + + /** {@inheritDoc} */ + @Override public int precision() { + return -1; + } + + /** {@inheritDoc} */ + @Override public int scale() { + return -1; + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryBinaryProperty.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryBinaryProperty.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryBinaryProperty.java index f440d12..7a47c2f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryBinaryProperty.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryBinaryProperty.java @@ -71,6 +71,12 @@ public class QueryBinaryProperty implements GridQueryProperty { /** */ private final Object defaultValue; + /** */ + private final int precision; + + /** */ + private final int scale; + /** * Constructor. * @@ -82,9 +88,12 @@ public class QueryBinaryProperty implements GridQueryProperty { * @param alias Field alias. * @param notNull {@code true} if null value is not allowed. * @param defaultValue Default value. + * @param precision Precision. + * @param scale Scale. */ public QueryBinaryProperty(GridKernalContext ctx, String propName, QueryBinaryProperty parent, - Class<?> type, @Nullable Boolean key, String alias, boolean notNull, Object defaultValue) { + Class<?> type, @Nullable Boolean key, String alias, boolean notNull, Object defaultValue, + int precision, int scale) { this.ctx = ctx; log = ctx.log(QueryBinaryProperty.class); @@ -99,6 +108,8 @@ public class QueryBinaryProperty implements GridQueryProperty { this.isKeyProp = key ? 1 : -1; this.defaultValue = defaultValue; + this.precision = precision; + this.scale = scale; } /** {@inheritDoc} */ @@ -286,4 +297,14 @@ public class QueryBinaryProperty implements GridQueryProperty { @Override public Object defaultValue() { return defaultValue; } + + /** {@inheritDoc} */ + @Override public int precision() { + return precision; + } + + /** {@inheritDoc} */ + @Override public int scale() { + return scale; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryClassProperty.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryClassProperty.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryClassProperty.java index 575fe17..487ee5b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryClassProperty.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/property/QueryClassProperty.java @@ -146,4 +146,14 @@ public class QueryClassProperty implements GridQueryProperty { @Override public Object defaultValue() { return null; } + + /** {@inheritDoc} */ + @Override public int precision() { + return -1; + } + + /** {@inheritDoc} */ + @Override public int scale() { + return -1; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index bc5c1e0..f907138 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -71,6 +71,7 @@ import org.apache.ignite.internal.sql.command.SqlIndexColumn; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.plugin.security.SecurityPermission; import org.h2.command.Prepared; import org.h2.command.ddl.AlterTableAlterColumn; @@ -80,6 +81,7 @@ import org.h2.command.ddl.DropIndex; import org.h2.command.ddl.DropTable; import org.h2.table.Column; import org.h2.value.DataType; +import org.h2.value.Value; import static org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.UPDATE_RESULT_META; import static org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser.PARAM_WRAP_VALUE; @@ -420,7 +422,8 @@ public class DdlStatementsProcessor { QueryField field = new QueryField(col.columnName(), DataType.getTypeClassName(col.column().getType()), - col.column().isNullable(), col.defaultValue()); + col.column().isNullable(), col.defaultValue(), + col.precision(), col.scale()); cols.add(field); @@ -595,6 +598,8 @@ public class DdlStatementsProcessor { HashMap<String, Object> dfltValues = new HashMap<>(); + Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = new HashMap<>(); + for (Map.Entry<String, GridSqlColumn> e : createTbl.columns().entrySet()) { GridSqlColumn gridCol = e.getValue(); @@ -613,11 +618,17 @@ public class DdlStatementsProcessor { if (dfltVal != null) dfltValues.put(e.getKey(), dfltVal); + + if (col.getType() == Value.DECIMAL) + decimalInfo.put(e.getKey(), F.t((int)col.getPrecision(), col.getScale())); } if (!F.isEmpty(dfltValues)) res.setDefaultFieldValues(dfltValues); + if (!F.isEmpty(decimalInfo)) + res.setDecimalInfo(decimalInfo); + String valTypeName = QueryUtils.createTableValueTypeName(createTbl.schemaName(), createTbl.tableName()); String keyTypeName = QueryUtils.createTableKeyTypeName(valTypeName); http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlColumn.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlColumn.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlColumn.java index bc14ae2..0efbd4c 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlColumn.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlColumn.java @@ -22,6 +22,7 @@ import org.apache.ignite.internal.util.typedef.F; import org.h2.command.Parser; import org.h2.expression.Expression; import org.h2.table.Column; +import org.h2.value.Value; /** * Column. @@ -129,9 +130,23 @@ public class GridSqlColumn extends GridSqlElement { } /** + * @return Precision. + */ + public int precision() { + return (int) col.getPrecision(); + } + + /** + * @return Scale. + */ + public int scale() { + return col.getScale(); + } + + /** * @return H2 Column. */ public Column column() { return col; } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java new file mode 100644 index 0000000..9e65276 --- /dev/null +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java @@ -0,0 +1,265 @@ +/* + * 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.index; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.cache.QueryEntity; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.cache.query.annotations.QuerySqlField; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.lang.IgniteBiTuple; +import org.jetbrains.annotations.NotNull; + +import static java.math.RoundingMode.HALF_UP; +import static java.util.Arrays.asList; + +/** + * Test to check decimal columns. + */ +public class IgniteDecimalSelfTest extends AbstractSchemaSelfTest { + /** */ + private static final int PRECISION = 9; + + /** */ + private static final int SCALE = 8; + + /** */ + private static final String DEC_TAB_NAME = "DECIMAL_TABLE"; + + /** */ + private static final String VALUE = "VALUE"; + + /** */ + private static final String SALARY_TAB_NAME = "SALARY"; + + /** */ + private static final MathContext MATH_CTX = new MathContext(PRECISION); + + /** */ + private static final BigDecimal VAL_1 = new BigDecimal("123456789", MATH_CTX).setScale(SCALE, HALF_UP); + + /** */ + private static final BigDecimal VAL_2 = new BigDecimal("12345678.12345678", MATH_CTX).setScale(SCALE, HALF_UP); + + /** */ + private static final BigDecimal VAL_3 = new BigDecimal(".123456789", MATH_CTX).setScale(SCALE, HALF_UP); + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + IgniteEx grid = startGrid(0); + + execute(grid, "CREATE TABLE " + DEC_TAB_NAME + + "(id LONG PRIMARY KEY, " + VALUE + " DECIMAL(" + PRECISION + ", " + SCALE + "))"); + + String insertQry = "INSERT INTO " + DEC_TAB_NAME + " VALUES (?, ?)"; + + execute(grid, insertQry, 1, VAL_1); + execute(grid, insertQry, 2, VAL_2); + execute(grid, insertQry, 3, VAL_3); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + CacheConfiguration<Integer, Salary> ccfg = cacheCfg(SALARY_TAB_NAME, "salary_cache"); + + cfg.setCacheConfiguration(ccfg); + + return cfg; + } + + /** */ + @NotNull private CacheConfiguration<Integer, Salary> cacheCfg(String tabName, String cacheName) { + CacheConfiguration<Integer, Salary> ccfg = new CacheConfiguration<>(cacheName); + + QueryEntity queryEntity = new QueryEntity(Integer.class.getName(), Salary.class.getName()); + + queryEntity.setTableName(tabName); + + queryEntity.addQueryField("id", Integer.class.getName(), null); + queryEntity.addQueryField("amount", BigDecimal.class.getName(), null); + + Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = new HashMap<>(); + + decimalInfo.put("amount", F.t(PRECISION, SCALE)); + + queryEntity.setDecimalInfo(decimalInfo); + + ccfg.setQueryEntities(Collections.singletonList(queryEntity)); + + return ccfg; + } + + /** + * @throws Exception If failed. + */ + public void testConfiguredFromDdl() throws Exception { + checkDecimalInfo(DEC_TAB_NAME, VALUE, PRECISION, SCALE); + } + + /** + * @throws Exception If failed. + */ + public void testConfiguredFromQueryEntity() throws Exception { + checkDecimalInfo(SALARY_TAB_NAME, "amount", PRECISION, SCALE); + } + + /** + * @throws Exception If failed. + */ + public void testConfiguredFromQueryEntityInDynamicallyCreatedCache() throws Exception { + IgniteEx grid = grid(0); + + String tabName = SALARY_TAB_NAME + "2"; + + CacheConfiguration<Integer, Salary> ccfg = cacheCfg(tabName, "SalaryCache-2"); + + IgniteCache<Integer, Salary> cache = grid.createCache(ccfg); + + checkDecimalInfo(tabName, "amount", PRECISION, SCALE); + } + + /** + * @throws Exception If failed. + */ + public void testConfiguredFromAnnotations() throws Exception { + IgniteEx grid = grid(0); + + CacheConfiguration<Integer, Salary> ccfg = new CacheConfiguration<>("SalaryCache-3"); + + ccfg.setIndexedTypes(Integer.class, SalaryWithAnnotations.class); + + grid.createCache(ccfg); + + checkDecimalInfo(SalaryWithAnnotations.class.getSimpleName().toUpperCase(), "amount", PRECISION, SCALE); + } + + /** */ + public void testSelectDecimal() throws Exception { + IgniteEx grid = grid(0); + + List rows = execute(grid, "SELECT id, value FROM " + DEC_TAB_NAME + " order by id"); + + assertEquals(rows.size(), 3); + + assertEquals(asList(1L, VAL_1), rows.get(0)); + assertEquals(asList(2L, VAL_2), rows.get(1)); + assertEquals(asList(3L, VAL_3), rows.get(2)); + } + + /** */ + private void checkDecimalInfo(String tabName, String colName, Integer precision, Integer scale) { + QueryEntity queryEntity = findTableInfo(tabName); + + assertNotNull(queryEntity); + + Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = queryEntity.getDecimalInfo(); + + assertNotNull(decimalInfo); + + IgniteBiTuple<Integer, Integer> columnInfo = decimalInfo.get(colName); + + assertNotNull(columnInfo); + + assertEquals(columnInfo.get1(), precision); + assertEquals(columnInfo.get2(), scale); + } + + /** + * @param tabName Table name. + * @return QueryEntity of table. + */ + private QueryEntity findTableInfo(String tabName) { + IgniteEx ignite = grid(0); + + Collection<String> cacheNames = ignite.cacheNames(); + + for (String cacheName : cacheNames) { + CacheConfiguration ccfg = ignite.cache(cacheName).getConfiguration(CacheConfiguration.class); + + Collection<QueryEntity> entities = ccfg.getQueryEntities(); + + for (QueryEntity entity : entities) + if (entity.getTableName().equalsIgnoreCase(tabName)) + return entity; + } + + return null; + } + + /** + * Execute DDL statement on given node. + * + * @param node Node. + * @param sql Statement. + */ + private List<List<?>> execute(Ignite node, String sql, Object... args) { + SqlFieldsQuery qry = new SqlFieldsQuery(sql) + .setArgs(args) + .setSchema("PUBLIC"); + + return queryProcessor(node).querySqlFields(qry, true).getAll(); + } + + /** */ + private static class Salary { + /** */ + private BigDecimal amount; + + /** */ + public BigDecimal getAmount() { + return amount; + } + + /** */ + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + } + + /** */ + private static class SalaryWithAnnotations { + /** */ + @QuerySqlField(index = true, precision = PRECISION, scale = SCALE) + private BigDecimal amount; + + /** */ + public BigDecimal getAmount() { + return amount; + } + + /** */ + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java index 1da695b..235b28b 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java @@ -565,6 +565,16 @@ public abstract class GridIndexingSpiAbstractSelfTest extends GridCommonAbstract @Override public Object defaultValue() { return null; } + + /** */ + @Override public int precision() { + return -1; + } + + /** */ + @Override public int scale() { + return -1; + } }; } @@ -783,4 +793,4 @@ public abstract class GridIndexingSpiAbstractSelfTest extends GridCommonAbstract return false; } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java index e10fff1..619e7cf 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java @@ -108,6 +108,7 @@ import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerCoord import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerNodeFIlterBasicSelfTest; import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerNodeFilterCoordinatorBasicSelfTest; import org.apache.ignite.internal.processors.cache.index.H2ConnectionLeaksSelfTest; +import org.apache.ignite.internal.processors.cache.index.IgniteDecimalSelfTest; import org.apache.ignite.internal.processors.cache.index.H2DynamicColumnsClientBasicSelfTest; import org.apache.ignite.internal.processors.cache.index.H2DynamicColumnsServerBasicSelfTest; import org.apache.ignite.internal.processors.cache.index.H2DynamicColumnsServerCoordinatorBasicSelfTest; @@ -397,6 +398,7 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite { suite.addTestSuite(OptimizedMarshallerIndexNameTest.class); suite.addTestSuite(IgniteSqlDefaultValueTest.class); + suite.addTestSuite(IgniteDecimalSelfTest.class); // H2 Rows on-heap cache suite.addTestSuite(H2RowCacheSelfTest.class); http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/QueryEntityConfigurationParityTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/QueryEntityConfigurationParityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/QueryEntityConfigurationParityTest.cs index a9830d8..ba10cda 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/QueryEntityConfigurationParityTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/QueryEntityConfigurationParityTest.cs @@ -32,7 +32,8 @@ namespace Apache.Ignite.Core.Tests.ApiParity "findValueType", "KeyFields", "NotNullFields", - "DefaultFieldValues" + "DefaultFieldValues", + "DecimalInfo" }; /// <summary> @@ -47,4 +48,4 @@ namespace Apache.Ignite.Core.Tests.ApiParity UnneededProperties); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs index 6834d5d..9d59a50 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs @@ -551,6 +551,8 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(x.IsKeyField, y.IsKeyField); Assert.AreEqual(x.NotNull, y.NotNull); Assert.AreEqual(x.DefaultValue, y.DefaultValue); + Assert.AreEqual(x.Precision, y.Precision); + Assert.AreEqual(x.Scale, y.Scale); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs index 8855535..32173ba 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs @@ -458,7 +458,9 @@ namespace Apache.Ignite.Core.Cache.Configuration { IsKeyField = isKey, NotNull = attr.NotNull, - DefaultValue = attr.DefaultValue + DefaultValue = attr.DefaultValue, + Precision = attr.Precision, + Scale = attr.Scale }); ScanAttributes(memberInfo.Value, fields, indexes, columnName, visitedTypes, isKey); http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs index a96f1bf..869ce7d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs @@ -85,6 +85,8 @@ namespace Apache.Ignite.Core.Cache.Configuration IsKeyField = reader.ReadBoolean(); NotNull = reader.ReadBoolean(); DefaultValue = reader.ReadObject<object>(); + Precision = reader.ReadInt(); + Scale = reader.ReadInt(); } /// <summary> @@ -99,6 +101,8 @@ namespace Apache.Ignite.Core.Cache.Configuration writer.WriteBoolean(IsKeyField); writer.WriteBoolean(NotNull); writer.WriteObject(DefaultValue); + writer.WriteInt(Precision); + writer.WriteInt(Scale); } /// <summary> @@ -154,6 +158,16 @@ namespace Apache.Ignite.Core.Cache.Configuration public object DefaultValue { get; set; } /// <summary> + /// Gets or sets the precision for the field. + /// </summary> + public int Precision { get; set; } + + /// <summary> + /// Gets or sets the scale for the field. + /// </summary> + public int Scale { get; set; } + + /// <summary> /// Validates this instance and outputs information to the log, if necessary. /// </summary> internal void Validate(ILogger log, string logInfo) @@ -179,4 +193,4 @@ namespace Apache.Ignite.Core.Cache.Configuration } } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs index dd131f9..bfd3575 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs @@ -81,5 +81,15 @@ namespace Apache.Ignite.Core.Cache.Configuration /// Gets or sets the default value for the field (has effect when inserting with DML). /// </summary> public object DefaultValue { get; set; } + + /// <summary> + /// Gets or sets the precision for the field. + /// </summary> + public int Precision { get; set; } + + /// <summary> + /// Gets or sets the scale for the field. + /// </summary> + public int Scale { get; set; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/6df5f99b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd index a97136f..8707272 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd @@ -340,6 +340,16 @@ <xs:documentation>Indicates whether null value is allowed for the field.</xs:documentation> </xs:annotation> </xs:attribute> + <xs:attribute name="precision" type="xs:int"> + <xs:annotation> + <xs:documentation>Precision of field</xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute name="scale" type="xs:int"> + <xs:annotation> + <xs:documentation>Scale of field</xs:documentation> + </xs:annotation> + </xs:attribute> </xs:complexType> </xs:element> </xs:sequence>