IGNITE-5623: SQL: default column values support for CREATE TABLE. This closes #3256.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/78e79e01 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/78e79e01 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/78e79e01 Branch: refs/heads/ignite-zk Commit: 78e79e011f1bb017653e628587faf606cfd37510 Parents: 2f2fa8b Author: tledkov-gridgain <tled...@gridgain.com> Authored: Fri Jan 5 12:08:54 2018 +0300 Committer: devozerov <voze...@gridgain.com> Committed: Fri Jan 5 12:08:54 2018 +0300 ---------------------------------------------------------------------- .../jdbc/thin/JdbcThinMetadataSelfTest.java | 27 ++- .../org/apache/ignite/cache/QueryEntity.java | 37 ++- .../ignite/internal/binary/BinaryFieldImpl.java | 5 + .../jdbc/thin/JdbcThinDatabaseMetadata.java | 2 +- .../internal/jdbc/thin/JdbcThinTcpIo.java | 9 +- .../processors/odbc/jdbc/JdbcColumnMeta.java | 7 + .../processors/odbc/jdbc/JdbcColumnMetaV3.java | 83 +++++++ .../odbc/jdbc/JdbcConnectionContext.java | 6 +- .../odbc/jdbc/JdbcMetaColumnsResultV3.java | 50 ++++ .../odbc/jdbc/JdbcRequestHandler.java | 13 +- .../processors/odbc/jdbc/JdbcResult.java | 8 + .../utils/PlatformConfigurationUtils.java | 10 + .../processors/query/GridQueryProcessor.java | 2 +- .../processors/query/GridQueryProperty.java | 7 + .../query/GridQueryTypeDescriptor.java | 13 +- .../internal/processors/query/QueryField.java | 21 ++ .../query/QueryTypeDescriptorImpl.java | 23 ++ .../internal/processors/query/QueryUtils.java | 17 +- .../query/property/QueryBinaryProperty.java | 13 +- .../query/property/QueryClassProperty.java | 5 + .../query/h2/ddl/DdlStatementsProcessor.java | 13 +- .../processors/query/h2/dml/UpdatePlan.java | 3 + .../processors/query/h2/sql/GridSqlColumn.java | 10 + .../query/h2/sql/GridSqlQueryParser.java | 34 ++- .../query/IgniteSqlDefaultValueTest.java | 234 +++++++++++++++++++ .../h2/GridIndexingSpiAbstractSelfTest.java | 10 + .../query/h2/sql/GridQueryParsingTest.java | 20 +- .../IgniteCacheQuerySelfTestSuite.java | 3 + .../QueryEntityConfigurationParityTest.cs | 3 +- .../Cache/CacheConfigurationTest.cs | 5 +- .../Cache/Query/CacheDmlQueriesTest.cs | 42 +++- .../Config/full-config.xml | 4 +- .../IgniteConfigurationSerializerTest.cs | 4 +- .../Cache/Configuration/QueryEntity.cs | 3 +- .../Cache/Configuration/QueryField.cs | 7 + .../Configuration/QuerySqlFieldAttribute.cs | 5 + .../IgniteConfigurationSection.xsd | 7 + 37 files changed, 721 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 2fd40d1..16b0ad5 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 @@ -138,7 +138,8 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { try (Connection conn = DriverManager.getConnection(URL)) { Statement stmt = conn.createStatement(); - stmt.execute("CREATE TABLE TEST (ID INT, NAME VARCHAR(50), VAL VARCHAR(50), PRIMARY KEY (ID, NAME))"); + stmt.execute("CREATE TABLE TEST (ID INT, NAME VARCHAR(50) default 'default name', " + + "age int default 21, VAL VARCHAR(50), PRIMARY KEY (ID, NAME))"); 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)"); @@ -371,23 +372,25 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest { ResultSet rs = meta.getColumns(null, null, null, null); Set<String> expectedCols = new HashSet<>(Arrays.asList( - "org.ORGANIZATION.ID", - "org.ORGANIZATION.NAME", - "pers.PERSON.ORGID", - "pers.PERSON.AGE", - "pers.PERSON.NAME", - "PUBLIC.TEST.ID", - "PUBLIC.TEST.NAME", - "PUBLIC.TEST.VAL", - "PUBLIC.Quoted.Id", - "PUBLIC.Quoted.Name")); + "org.ORGANIZATION.ID.null", + "org.ORGANIZATION.NAME.null", + "pers.PERSON.ORGID.null", + "pers.PERSON.AGE.null", + "pers.PERSON.NAME.null", + "PUBLIC.TEST.ID.null", + "PUBLIC.TEST.NAME.'default name'", + "PUBLIC.TEST.VAL.null", + "PUBLIC.TEST.AGE.21", + "PUBLIC.Quoted.Id.null", + "PUBLIC.Quoted.Name.null")); Set<String> actualCols = new HashSet<>(expectedCols.size()); while(rs.next()) { actualCols.add(rs.getString("TABLE_SCHEM") + '.' + rs.getString("TABLE_NAME") + "." - + rs.getString("COLUMN_NAME")); + + rs.getString("COLUMN_NAME") + "." + + rs.getString("COLUMN_DEF")); } assert expectedCols.equals(actualCols) : "expectedCols=" + expectedCols + http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 2002b4f..0065bae 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 @@ -86,6 +86,9 @@ public class QueryEntity implements Serializable { /** Fields that must have non-null value. NB: DO NOT remove underscore to avoid clashes with QueryEntityEx. */ private Set<String> _notNullFields; + /** Fields default values. */ + private Map<String, Object> defaultFieldValues = new HashMap<>(); + /** * Creates an empty query entity. */ @@ -114,6 +117,9 @@ public class QueryEntity implements Serializable { tableName = other.tableName; _notNullFields = other._notNullFields != null ? new HashSet<>(other._notNullFields) : null; + + defaultFieldValues = other.defaultFieldValues != null ? new HashMap<>(other.defaultFieldValues) + : new HashMap<String, Object>(); } /** @@ -355,9 +361,12 @@ public class QueryEntity implements Serializable { * Sets table name for this query entity. * * @param tableName table name + * @return {@code this} for chaining. */ - public void setTableName(String tableName) { + public QueryEntity setTableName(String tableName) { this.tableName = tableName; + + return this; } /** @@ -382,6 +391,27 @@ public class QueryEntity implements Serializable { } /** + * Gets fields default values. + * + * @return Field's name to default value map. + */ + public Map<String, Object> getDefaultFieldValues() { + return defaultFieldValues; + } + + /** + * Sets fields default values. + * + * @param defaultFieldValues Field's name to default value map. + * @return {@code this} for chaining. + */ + public QueryEntity setDefaultFieldValues(Map<String, Object> defaultFieldValues) { + this.defaultFieldValues = defaultFieldValues; + + return this; + } + + /** * Utility method for building query entities programmatically. * * @param fullName Full name of the field. @@ -639,13 +669,14 @@ public class QueryEntity implements Serializable { F.eq(aliases, entity.aliases) && F.eqNotOrdered(idxs, entity.idxs) && F.eq(tableName, entity.tableName) && - F.eq(_notNullFields, entity._notNullFields); + F.eq(_notNullFields, entity._notNullFields) && + F.eq(defaultFieldValues, entity.defaultFieldValues); } /** {@inheritDoc} */ @Override public int hashCode() { return Objects.hash(keyType, valType, keyFieldName, valueFieldName, fields, keyFields, aliases, idxs, - tableName, _notNullFields); + tableName, _notNullFields, defaultFieldValues); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java index 59bd03d..883576c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java @@ -56,6 +56,8 @@ public class BinaryFieldImpl implements BinaryFieldEx { /** * Constructor. * + * @param ctx Binary context. + * @param typeId Type ID. * @param schemas Schemas. * @param fieldName Field name. * @param fieldId Field ID. @@ -278,6 +280,9 @@ public class BinaryFieldImpl implements BinaryFieldEx { int schemaId = obj.schemaId(); + if (schemaId == 0) + return BinarySchema.ORDER_NOT_FOUND; + BinarySchema schema = schemas.schema(schemaId); if (schema == null) { http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 cfc3b68..dd8b733 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 @@ -852,7 +852,7 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData { row.add(10); // 10. NUM_PREC_RADIX row.add(colMeta.isNullable() ? columnNullable : columnNoNulls); // 11. NULLABLE row.add((String)null); // 12. REMARKS - row.add((String)null); // 13. COLUMN_DEF + row.add(colMeta.defaultValue()); // 13. COLUMN_DEF row.add(colMeta.dataType()); // 14. SQL_DATA_TYPE row.add((Integer)null); // 15. SQL_DATETIME_SUB row.add(Integer.MAX_VALUE); // 16. CHAR_OCTET_LENGTH http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 4d23934..fec218e 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 @@ -74,8 +74,11 @@ public class JdbcThinTcpIo { /** Version 2.3.1. */ private static final ClientListenerProtocolVersion VER_2_3_0 = ClientListenerProtocolVersion.create(2, 3, 0); + /** Version 2.4.0. */ + private static final ClientListenerProtocolVersion VER_2_4_0 = ClientListenerProtocolVersion.create(2, 4, 0); + /** Current version. */ - private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_3_0; + private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_4_0; /** Initial output stream capacity for handshake. */ private static final int HANDSHAKE_MSG_SIZE = 13; @@ -212,8 +215,8 @@ public class JdbcThinTcpIo { ClientListenerProtocolVersion srvProtocolVer = ClientListenerProtocolVersion.create(maj, min, maintenance); - if (VER_2_1_5.equals(srvProtocolVer)) - handshake(VER_2_1_5); + if (VER_2_3_0.equals(srvProtocolVer) || VER_2_1_5.equals(srvProtocolVer)) + handshake(srvProtocolVer); else if (VER_2_1_0.equals(srvProtocolVer)) handshake_2_1_0(); else { http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 d927c26..c0ac322 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 @@ -128,6 +128,13 @@ public class JdbcColumnMeta implements JdbcRawBinarylizable { } /** + * @return Column's default value. + */ + public String defaultValue() { + return null; + } + + /** * 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/78e79e01/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV3.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV3.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV3.java new file mode 100644 index 0000000..9911be0 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcColumnMetaV3.java @@ -0,0 +1,83 @@ +/* + * 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 V3. + */ +public class JdbcColumnMetaV3 extends JdbcColumnMetaV2 { + /** Default value. */ + private String dfltValue; + + /** + * Default constructor is used for serialization. + */ + JdbcColumnMetaV3() { + // No-op. + } + + /** + * @param schemaName Schema. + * @param tblName Table. + * @param colName Column. + * @param cls Type. + * @param nullable Allow nulls. + * @param dfltVal Default value. + */ + public JdbcColumnMetaV3(String schemaName, String tblName, String colName, Class<?> cls, boolean nullable, + Object dfltVal) { + super(schemaName, tblName, colName, cls, nullable); + + if (dfltVal == null) + dfltValue = null; + else { + if (dfltVal instanceof String) + dfltValue = "'" + String.valueOf(dfltVal) + "'"; + else + dfltValue = String.valueOf(dfltVal); + } + } + + /** {@inheritDoc} */ + @Override public String defaultValue() { + return dfltValue; + } + + /** {@inheritDoc} */ + @Override public void writeBinary(BinaryWriterExImpl writer) { + super.writeBinary(writer); + + writer.writeString(dfltValue); + } + + /** {@inheritDoc} */ + @Override public void readBinary(BinaryReaderExImpl reader) { + super.readBinary(reader); + + dfltValue = reader.readString(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcColumnMetaV3.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 7b40466..5841a4d 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 @@ -40,8 +40,11 @@ public class JdbcConnectionContext implements ClientListenerConnectionContext { /** Version 2.3.1: added "multiple statements query" feature. */ public static final ClientListenerProtocolVersion VER_2_3_0 = ClientListenerProtocolVersion.create(2, 3, 0); + /** Version 2.4.0: adds default values for columns feature. */ + public static final ClientListenerProtocolVersion VER_2_4_0 = ClientListenerProtocolVersion.create(2, 4, 0); + /** Current version. */ - private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_3_0; + private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_4_0; /** Supported versions. */ private static final Set<ClientListenerProtocolVersion> SUPPORTED_VERS = new HashSet<>(); @@ -63,6 +66,7 @@ public class JdbcConnectionContext implements ClientListenerConnectionContext { static { SUPPORTED_VERS.add(CURRENT_VER); + SUPPORTED_VERS.add(VER_2_3_0); SUPPORTED_VERS.add(VER_2_1_5); SUPPORTED_VERS.add(VER_2_1_0); } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV3.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV3.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV3.java new file mode 100644 index 0000000..0cee9b7 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcMetaColumnsResultV3.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 JdbcMetaColumnsResultV3 extends JdbcMetaColumnsResult { + /** + * Default constructor is used for deserialization. + */ + JdbcMetaColumnsResultV3() { + super(META_COLUMNS_V3); + } + + /** + * @param meta Columns metadata. + */ + JdbcMetaColumnsResultV3(Collection<JdbcColumnMeta> meta) { + super(META_COLUMNS_V3, meta); + } + + /** {@inheritDoc} */ + @Override protected JdbcColumnMeta createMetaColumn() { + return new JdbcColumnMetaV3(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcMetaColumnsResultV3.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 e3b6f5b..458c99c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -54,6 +54,7 @@ import org.apache.ignite.internal.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.JdbcConnectionContext.VER_2_4_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; @@ -592,7 +593,13 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { JdbcColumnMeta columnMeta; - if (protocolVer.compareTo(VER_2_3_0) >= 0) { + if (protocolVer.compareTo(VER_2_4_0) >= 0) { + GridQueryProperty prop = table.property(colName); + + columnMeta = new JdbcColumnMetaV3(table.schemaName(), table.tableName(), + field.getKey(), field.getValue(), !prop.notNull(), prop.defaultValue()); + } + else if (protocolVer.compareTo(VER_2_3_0) >= 0) { GridQueryProperty prop = table.property(colName); columnMeta = new JdbcColumnMetaV2(table.schemaName(), table.tableName(), @@ -610,7 +617,9 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { JdbcMetaColumnsResult res; - if (protocolVer.compareTo(VER_2_3_0) >= 0) + 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); else res = new JdbcMetaColumnsResult(meta); http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 6d460e6..623a339 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 @@ -62,6 +62,9 @@ public class JdbcResult implements JdbcRawBinarylizable { /** Columns metadata result V2. */ static final byte META_COLUMNS_V2 = 14; + /** Columns metadata result V3. */ + static final byte META_COLUMNS_V3 = 15; + /** Success status. */ private byte type; @@ -155,6 +158,11 @@ public class JdbcResult implements JdbcRawBinarylizable { break; + case META_COLUMNS_V3: + res = new JdbcMetaColumnsResultV3(); + + break; + default: throw new IgniteException("Unknown SQL listener request ID: [request ID=" + resId + ']'); } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 b048f48..c4c354e 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 @@ -489,6 +489,7 @@ public class PlatformConfigurationUtils { int cnt = in.readInt(); Set<String> keyFields = new HashSet<>(cnt); Set<String> notNullFields = new HashSet<>(cnt); + Map<String, Object> defVals = new HashMap<>(cnt); if (cnt > 0) { LinkedHashMap<String, String> fields = new LinkedHashMap<>(cnt); @@ -504,6 +505,10 @@ public class PlatformConfigurationUtils { if (in.readBoolean()) notNullFields.add(fieldName); + + Object defVal = in.readObject(); + if (defVal != null) + defVals.put(fieldName, defVal); } res.setFields(fields); @@ -513,6 +518,9 @@ public class PlatformConfigurationUtils { if (!notNullFields.isEmpty()) res.setNotNullFields(notNullFields); + + if (!defVals.isEmpty()) + res.setDefaultFieldValues(defVals); } // Aliases @@ -996,6 +1004,7 @@ public class PlatformConfigurationUtils { if (fields != null) { Set<String> keyFields = qryEntity.getKeyFields(); Set<String> notNullFields = qryEntity.getNotNullFields(); + Map<String, Object> defVals = qryEntity.getDefaultFieldValues(); writer.writeInt(fields.size()); @@ -1004,6 +1013,7 @@ public class PlatformConfigurationUtils { writer.writeString(field.getValue()); 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); } } else http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 dbe2e9b..ab84a1a 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 @@ -2423,7 +2423,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())); + false, null, !col.isNullable(), null)); } catch (ClassNotFoundException e) { throw new SchemaOperationException("Class not found for new property: " + col.typeName()); http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 c8ae212..b258b7c 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 @@ -70,4 +70,11 @@ public interface GridQueryProperty { * @return {@code true} if property does not allow {@code null} value. */ public boolean notNull(); + + /** + * Gets the default value for this property. + * + * @return {@code null} if a default value is not set for the property. + */ + public Object defaultValue(); } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java index dcf850c..8a23e50 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java @@ -19,6 +19,8 @@ package org.apache.ignite.internal.processors.query; import java.util.Map; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.util.lang.GridMapEntry; import org.jetbrains.annotations.Nullable; /** @@ -177,4 +179,13 @@ public interface GridQueryTypeDescriptor { * @throws IgniteCheckedException, If failure happens. */ public void validateKeyAndValue(Object key, Object val) throws IgniteCheckedException; -} \ No newline at end of file + + /** + * Sets defaults value for given key and value. + * + * @param key Key. + * @param val Value. + * @throws IgniteCheckedException If failed. + */ + public void setDefaults(Object key, Object val) throws IgniteCheckedException; +} http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 8c7d367..1a75ef1 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 @@ -37,15 +37,29 @@ public class QueryField implements Serializable { /** Nullable flag. */ private final boolean nullable; + /** Default value. */ + private final Object dfltValue; + /** * @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); + } + + /** + * @param name Field name. + * @param typeName Class name for this field's values. + * @param nullable Nullable flag. + * @param dfltValue Default value. + */ + public QueryField(String name, String typeName, boolean nullable, Object dfltValue) { this.name = name; this.typeName = typeName; this.nullable = nullable; + this.dfltValue = dfltValue; } /** @@ -69,6 +83,13 @@ public class QueryField implements Serializable { return nullable; } + /** + * @return Default value. + */ + public Object defaultValue() { + return dfltValue; + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(QueryField.class, this); http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java index de58a4d..a7710f9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java @@ -107,6 +107,9 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor { /** */ private List<GridQueryProperty> validateProps; + /** */ + private List<GridQueryProperty> propsWithDefaultValue; + /** * Constructor. * @@ -380,6 +383,13 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor { validateProps.add(prop); } + if (prop.defaultValue() != null) { + if (propsWithDefaultValue == null) + propsWithDefaultValue = new ArrayList<>(); + + propsWithDefaultValue.add(prop); + } + fields.put(name, prop.type()); } @@ -537,4 +547,17 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor { throw new IgniteSQLException("Null value is not allowed for column '" + prop.name() + "'", errCode); } } + + /** {@inheritDoc} */ + @SuppressWarnings("ForLoopReplaceableByForEach") + @Override public void setDefaults(Object key, Object val) throws IgniteCheckedException { + if (F.isEmpty(propsWithDefaultValue)) + return; + + for (int i = 0; i < propsWithDefaultValue.size(); ++i) { + GridQueryProperty prop = propsWithDefaultValue.get(i); + + prop.setValue(key, val, prop.defaultValue()); + } + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 91509f4..3397492 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 @@ -241,6 +241,7 @@ public class QueryUtils { normalEntity.setKeyFieldName(entity.getKeyFieldName()); normalEntity.setValueFieldName(entity.getValueFieldName()); normalEntity.setNotNullFields(entity.getNotNullFields()); + normalEntity.setDefaultFieldValues(entity.getDefaultFieldValues()); // Normalize table name. String normalTblName = entity.getTableName(); @@ -515,6 +516,7 @@ public class QueryUtils { throws IgniteCheckedException { Set<String> keyFields = qryEntity.getKeyFields(); Set<String> notNulls = qryEntity.getNotNullFields(); + Map<String, Object> dlftVals = qryEntity.getDefaultFieldValues(); // 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 @@ -543,9 +545,11 @@ public class QueryUtils { boolean notNull = notNulls != null && notNulls.contains(entry.getKey()); + Object dfltVal = dlftVals != null ? dlftVals.get(entry.getKey()) : null; + QueryBinaryProperty prop = buildBinaryProperty(ctx, entry.getKey(), U.classForName(entry.getValue(), Object.class, true), - d.aliases(), isKeyField, notNull); + d.aliases(), isKeyField, notNull, dfltVal); d.addProperty(prop, false); } @@ -688,10 +692,12 @@ public class QueryUtils { * @param isKeyField Key ownership flag, as defined in {@link QueryEntity#keyFields}: {@code true} if field belongs * to key, {@code false} if it belongs to value, {@code null} if QueryEntity#keyFields is null. * @param notNull {@code true} if {@code null} value is not allowed. + * @param dlftVal Default value. * @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) throws IgniteCheckedException { + Map<String, String> aliases, @Nullable Boolean isKeyField, boolean notNull, Object dlftVal) throws IgniteCheckedException { String[] path = pathStr.split("\\."); QueryBinaryProperty res = null; @@ -707,7 +713,7 @@ 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); + res = new QueryBinaryProperty(ctx, prop, res, resType, isKeyField, alias, notNull, dlftVal); } return res; @@ -1365,5 +1371,10 @@ public class QueryUtils { @Override public boolean notNull() { return true; } + + /** {@inheritDoc} */ + @Override public Object defaultValue() { + return null; + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 18508a8..f440d12 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 @@ -68,6 +68,9 @@ public class QueryBinaryProperty implements GridQueryProperty { /** */ private final boolean notNull; + /** */ + private final Object defaultValue; + /** * Constructor. * @@ -78,9 +81,10 @@ public class QueryBinaryProperty implements GridQueryProperty { * @param key {@code true} if key property, {@code false} otherwise, {@code null} if unknown. * @param alias Field alias. * @param notNull {@code true} if null value is not allowed. + * @param defaultValue Default value. */ public QueryBinaryProperty(GridKernalContext ctx, String propName, QueryBinaryProperty parent, - Class<?> type, @Nullable Boolean key, String alias, boolean notNull) { + Class<?> type, @Nullable Boolean key, String alias, boolean notNull, Object defaultValue) { this.ctx = ctx; log = ctx.log(QueryBinaryProperty.class); @@ -93,6 +97,8 @@ public class QueryBinaryProperty implements GridQueryProperty { if (key != null) this.isKeyProp = key ? 1 : -1; + + this.defaultValue = defaultValue; } /** {@inheritDoc} */ @@ -275,4 +281,9 @@ public class QueryBinaryProperty implements GridQueryProperty { @Override public boolean notNull() { return notNull; } + + /** {@inheritDoc} */ + @Override public Object defaultValue() { + return defaultValue; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 076a769..575fe17 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 @@ -141,4 +141,9 @@ public class QueryClassProperty implements GridQueryProperty { @Override public boolean notNull() { return notNull; } + + /** {@inheritDoc} */ + @Override public Object defaultValue() { + return null; + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 b198922..01629ce 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 @@ -19,6 +19,7 @@ package org.apache.ignite.internal.processors.query.h2.ddl; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -347,7 +348,7 @@ public class DdlStatementsProcessor { QueryField field = new QueryField(col.columnName(), DataType.getTypeClassName(col.column().getType()), - col.column().isNullable()); + col.column().isNullable(), col.defaultValue()); cols.add(field); @@ -504,6 +505,8 @@ public class DdlStatementsProcessor { Set<String> notNullFields = null; + HashMap<String, Object> dfltValues = new HashMap<>(); + for (Map.Entry<String, GridSqlColumn> e : createTbl.columns().entrySet()) { GridSqlColumn gridCol = e.getValue(); @@ -517,8 +520,16 @@ public class DdlStatementsProcessor { notNullFields.add(e.getKey()); } + + Object dfltVal = gridCol.defaultValue(); + + if (dfltVal != null) + dfltValues.put(e.getKey(), dfltVal); } + if (!F.isEmpty(dfltValues)) + res.setDefaultFieldValues(dfltValues); + String valTypeName = QueryUtils.createTableValueTypeName(createTbl.schemaName(), createTbl.tableName()); String keyTypeName = QueryUtils.createTableKeyTypeName(valTypeName); http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java index 6a45c3c..5625e37 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/dml/UpdatePlan.java @@ -237,6 +237,8 @@ public final class UpdatePlan { newColVals.put(colName, DmlUtils.convert(row.get(i), rowDesc, expCls, colTypes[i])); } + desc.setDefaults(key, val); + // We update columns in the order specified by the table for a reason - table's // column order preserves their precedence for correct update of nested properties. Column[] cols = tbl.getColumns(); @@ -274,6 +276,7 @@ public final class UpdatePlan { * * @param row Row to process. * @throws IgniteCheckedException if failed. + * @return Tuple contains: [key, old value, new value] */ public T3<Object, Object, Object> processRowForUpdate(List<?> row) throws IgniteCheckedException { GridH2RowDescriptor rowDesc = tbl.rowDescriptor(); http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 ef460e3..bc14ae2 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 @@ -20,6 +20,7 @@ package org.apache.ignite.internal.processors.query.h2.sql; import java.util.Collections; import org.apache.ignite.internal.util.typedef.F; import org.h2.command.Parser; +import org.h2.expression.Expression; import org.h2.table.Column; /** @@ -119,6 +120,15 @@ public class GridSqlColumn extends GridSqlElement { } /** + * @return Default value. + */ + public Object defaultValue() { + Expression dfltExpr = col.getDefaultExpression(); + + return dfltExpr != null ? col.convert(dfltExpr.getValue(null)).getObject() : null; + } + + /** * @return H2 Column. */ public Column column() { http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java index 388231f..61d7510 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java @@ -95,6 +95,7 @@ import org.h2.table.Table; import org.h2.table.TableBase; import org.h2.table.TableFilter; import org.h2.table.TableView; +import org.h2.value.DataType; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperationType.AND; @@ -1199,9 +1200,23 @@ public class GridSqlQueryParser { throw new IgniteSQLException("Computed columns are not supported [colName=" + col.getName() + ']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); - if (col.getDefaultExpression() != null) - throw new IgniteSQLException("DEFAULT expressions are not supported [colName=" + col.getName() + ']', - IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + if (col.getDefaultExpression() != null) { + if (!col.getDefaultExpression().isConstant()) { + throw new IgniteSQLException("Non-constant DEFAULT expressions are not supported [colName=" + col.getName() + ']', + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + } + + DataType colType = DataType.getDataType(col.getType()); + DataType dfltType = DataType.getDataType(col.getDefaultExpression().getType()); + + if ((DataType.isStringType(colType.type) && !DataType.isStringType(dfltType.type)) + || (DataType.supportsAdd(colType.type) && !DataType.supportsAdd(dfltType.type))) { + throw new IgniteSQLException("Invalid default value for column. [colName=" + col.getName() + + ", colType=" + colType.name + + ", dfltValueType=" + dfltType.name + ']', + IgniteQueryErrorCode.UNEXPECTED_ELEMENT_TYPE); + } + } if (col.getSequence() != null) throw new IgniteSQLException("SEQUENCE columns are not supported [colName=" + col.getName() + ']', @@ -1225,13 +1240,15 @@ public class GridSqlQueryParser { /** * Parse {@code ALTER TABLE ... ADD COLUMN} statement. * @param addCol H2 statement. + * @return Grid SQL statement. + * * @see <a href="http://www.h2database.com/html/grammar.html#alter_table_add"></a> */ private GridSqlStatement parseAddColumn(AlterTableAlterColumn addCol) { assert addCol.getType() == CommandInterface.ALTER_TABLE_ADD_COLUMN; if (ALTER_COLUMN_BEFORE_COL.get(addCol) != null || ALTER_COLUMN_AFTER_COL.get(addCol) != null) - throw new IgniteSQLException("ALTER TABLE ADD COLUMN BEFORE/AFTER is not supported", + throw new IgniteSQLException("ALTER TABLE ADD COLUMN BEFORE/AFTER is not supported" , IgniteQueryErrorCode.UNSUPPORTED_OPERATION); GridSqlAlterTableAddColumn res = new GridSqlAlterTableAddColumn(); @@ -1240,8 +1257,15 @@ public class GridSqlQueryParser { GridSqlColumn[] gridNewCols = new GridSqlColumn[h2NewCols.size()]; - for (int i = 0; i < h2NewCols.size(); i++) + for (int i = 0; i < h2NewCols.size(); i++) { + Column col = h2NewCols.get(i); + + if (col.getDefaultExpression() != null) + throw new IgniteSQLException("ALTER TABLE ADD COLUMN with DEFAULT value is not supported " + + "[col=" + col.getName() + ']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + gridNewCols[i] = parseColumn(h2NewCols.get(i)); + } res.columns(gridNewCols); http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlDefaultValueTest.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlDefaultValueTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlDefaultValueTest.java new file mode 100644 index 0000000..6747e28 --- /dev/null +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlDefaultValueTest.java @@ -0,0 +1,234 @@ +/* + * 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.query; + +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Callable; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +/** */ +@SuppressWarnings("ThrowableNotThrown") +public class IgniteSqlDefaultValueTest extends GridCommonAbstractTest { + /** IP finder. */ + private static final TcpDiscoveryVmIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); + + /** Name of client node. */ + private static final String NODE_CLIENT = "client"; + + /** Number of server nodes. */ + private static final int NODE_COUNT = 2; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { + IgniteConfiguration c = super.getConfiguration(gridName); + + TcpDiscoverySpi disco = new TcpDiscoverySpi(); + + disco.setIpFinder(IP_FINDER); + disco.setForceServerMode(true); + + c.setDiscoverySpi(disco); + + if (gridName.equals(NODE_CLIENT)) + c.setClientMode(true); + + return c; + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + startGrids(NODE_COUNT); + + startGrid(NODE_CLIENT); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + stopAllGrids(); + + super.afterTestsStopped(); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + Collection<String> tblNames = new ArrayList<>(); + + for (String cacheName : grid(0).context().cache().publicCacheNames()) { + for (GridQueryTypeDescriptor table : grid(0).context().query().types(cacheName)) + tblNames.add(table.tableName()); + } + + for (String tbl : tblNames) + sql("DROP TABLE " + tbl); + + super.afterTest(); + } + + /** + */ + public void testDefaultValueColumn() { + sql("CREATE TABLE TEST (id int, val0 varchar DEFAULT 'default-val', primary key (id))"); + sql("INSERT INTO TEST (id) VALUES (?)", 1); + sql("INSERT INTO TEST (id, val0) VALUES (?, ?)", 2, null); + sql("INSERT INTO TEST (id, val0) VALUES (?, ?)", 3, "test-val"); + + List<List<Object>> exp = Arrays.asList( + Arrays.<Object>asList(1, "default-val"), + Arrays.<Object>asList(2, null), + Arrays.<Object>asList(3, "test-val") + ); + + List<List<?>> res = sql("select id, val0 from TEST"); + + checkResults(exp, res); + } + + /** + */ + public void testDefaultValueColumnAfterUpdate() { + sql("CREATE TABLE TEST (id int, val0 varchar DEFAULT 'default-val', val1 varchar, primary key (id))"); + sql("INSERT INTO TEST (id, val1) VALUES (?, ?)", 1, "val-10"); + sql("INSERT INTO TEST (id, val1) VALUES (?, ?)", 2, "val-20"); + sql("INSERT INTO TEST (id, val1) VALUES (?, ?)", 3, "val-30"); + + List<List<Object>> exp = Arrays.asList( + Arrays.<Object>asList(1, "default-val", "val-10"), + Arrays.<Object>asList(2, "default-val", "val-20"), + Arrays.<Object>asList(3, "default-val", "val-30") + ); + + List<List<?>> res = sql("select id, val0, val1 from TEST"); + + checkResults(exp, res); + + sql("UPDATE TEST SET val1=? where id=?", "val-21", 2); + + List<List<Object>> expAfterUpdate = Arrays.asList( + Arrays.<Object>asList(1, "default-val", "val-10"), + Arrays.<Object>asList(2, "default-val", "val-21"), + Arrays.<Object>asList(3, "default-val", "val-30") + ); + + List<List<?>> resAfterUpdate = sql("select id, val0, val1 from TEST"); + + checkResults(expAfterUpdate, resAfterUpdate); + } + + /** + */ + public void testEmptyValueNullDefaults() { + sql("CREATE TABLE TEST (id int, val0 varchar, primary key (id))"); + sql("INSERT INTO TEST (id) VALUES (?)", 1); + sql("INSERT INTO TEST (id, val0) VALUES (?, ?)", 2, "test-val"); + + List<List<Object>> expected = Arrays.asList( + Arrays.<Object>asList(1, null), + Arrays.<Object>asList(2, "test-val") + ); + + List<List<?>> res = sql("select id, val0 from TEST"); + + checkResults(expected, res); + } + + /** + */ + public void testAddColumnWithDefaults() { + sql("CREATE TABLE TEST (id int, val0 varchar, primary key (id))"); + + GridTestUtils.assertThrows(log, new Callable<Object>() { + @Override public Object call() { + sql("ALTER TABLE TEST ADD COLUMN val1 varchar DEFAULT 'default-val'"); + + return null; + } + }, IgniteSQLException.class, "ALTER TABLE ADD COLUMN with DEFAULT value is not supported"); + } + + /** + */ + public void testDefaultTypes() { + assertEquals("Check tinyint", (byte)28, getDefaultObject("TINYINT", "28")); + assertEquals("Check smallint", (short)28, getDefaultObject("SMALLINT", "28")); + assertEquals("Check int", 28, getDefaultObject("INT", "28")); + assertEquals("Check double", 28.25, getDefaultObject("DOUBLE", "28.25")); + assertEquals("Check float", 28.25, getDefaultObject("FLOAT", "28.25")); + assertEquals("Check decimal", BigDecimal.valueOf(28.25), getDefaultObject("DECIMAL", "28.25")); + assertEquals("Check varchar", "test value", getDefaultObject("VARCHAR", "'test value'")); + assertEquals("Check time", Time.valueOf("14:01:01"), getDefaultObject("TIME", "'14:01:01'")); + assertEquals("Check date", Date.valueOf("2017-12-29"), getDefaultObject("DATE", "'2017-12-29'")); + assertEquals("Check timestamp", Timestamp.valueOf("2017-12-29 14:01:01"), + getDefaultObject("TIMESTAMP", "'2017-12-29 14:01:01'")); + } + + /** + * @param sqlType SQL type. + * @param dfltVal Value string representation. + * @return Object is returned by SELECT query. + */ + private Object getDefaultObject(String sqlType, String dfltVal) { + sql(String.format("CREATE TABLE TEST (id int, val %s default %s, primary key (id))", + sqlType, dfltVal)); + + sql("INSERT INTO TEST (id) VALUES (1)"); + + List<List<?>> res = sql("SELECT val FROM TEST WHERE id=1"); + + sql("DROP TABLE TEST"); + + return res.get(0).get(0); + } + + /** + * @param exp Expected results. + * @param actual Actual results. + */ + @SuppressWarnings("SuspiciousMethodCalls") + private void checkResults(Collection<List<Object>> exp, Collection<List<?>> actual) { + assertEquals(exp.size(), actual.size()); + + for (List<?> row : actual) { + if (!exp.contains(row)) + fail("Unexpected results: [row=" + row + ']'); + } + } + + /** + * @param sql SQL query + * @param args Query parameters. + * @return Results set. + */ + private List<List<?>> sql(String sql, Object ... args) { + return grid(NODE_CLIENT).context().query().querySqlFieldsNoCache( + new SqlFieldsQuery(sql).setArgs(args), false).getAll(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 62860c0..1da695b 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 @@ -560,6 +560,11 @@ public abstract class GridIndexingSpiAbstractSelfTest extends GridCommonAbstract @Override public boolean notNull() { return false; } + + /** */ + @Override public Object defaultValue() { + return null; + } }; } @@ -654,6 +659,11 @@ public abstract class GridIndexingSpiAbstractSelfTest extends GridCommonAbstract @Override public void validateKeyAndValue(Object key, Object value) throws IgniteCheckedException { // No-op. } + + /** {@inheritDoc} */ + @Override public void setDefaults(Object key, Object val) throws IgniteCheckedException { + // No-op. + } } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java index dc72c31..6efb99f 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java @@ -634,14 +634,28 @@ public class GridQueryParsingTest extends GridCommonAbstractTest { assertParseThrows("create table Person (id int as age * 2 primary key, age int) WITH \"template=cache\"", IgniteSQLException.class, "Computed columns are not supported [colName=ID]"); - assertParseThrows("create table Person (id int primary key, age int default 5) WITH \"template=cache\"", - IgniteSQLException.class, "DEFAULT expressions are not supported [colName=AGE]"); - assertParseThrows("create table Int (_key int primary key, _val int) WITH \"template=cache\"", IgniteSQLException.class, "Direct specification of _KEY and _VAL columns is forbidden"); } /** */ + public void testParseCreateTableWithDefaults() { + assertParseThrows("create table Person (id int primary key, age int, " + + "ts TIMESTAMP default CURRENT_TIMESTAMP()) WITH \"template=cache\"", + IgniteSQLException.class, "Non-constant DEFAULT expressions are not supported [colName=TS]"); + + assertParseThrows("create table Person (id int primary key, age int default 'test') " + + "WITH \"template=cache\"", + IgniteSQLException.class, "Invalid default value for column. " + + "[colName=AGE, colType=INTEGER, dfltValueType=VARCHAR]"); + + assertParseThrows("create table Person (id int primary key, name varchar default 1) " + + "WITH \"template=cache\"", + IgniteSQLException.class, "Invalid default value for column. " + + "[colName=NAME, colType=VARCHAR, dfltValueType=INTEGER]"); + } + + /** */ public void testParseAlterTableAddColumn() throws Exception { assertAlterTableAddColumnEquals(buildAlterTableAddColumn("SCH2", "Person", false, false, c("COMPANY", Value.STRING)), "ALTER TABLE SCH2.Person ADD company varchar"); http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 55d0b5c..564019a 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 @@ -134,6 +134,7 @@ import org.apache.ignite.internal.processors.cache.query.IgniteCacheQueryCacheDe import org.apache.ignite.internal.processors.cache.query.IndexingSpiQuerySelfTest; import org.apache.ignite.internal.processors.cache.query.IndexingSpiQueryTxSelfTest; import org.apache.ignite.internal.processors.client.ClientConnectorConfigurationValidationSelfTest; +import org.apache.ignite.internal.processors.query.IgniteSqlDefaultValueTest; import org.apache.ignite.internal.processors.query.IgniteSqlDistributedJoinSelfTest; import org.apache.ignite.internal.processors.query.IgniteSqlSkipReducerOnUpdateDmlFlagSelfTest; import org.apache.ignite.internal.processors.query.IgniteSqlParameterizedQueryTest; @@ -376,6 +377,8 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite { suite.addTestSuite(IgniteCheckClusterStateBeforeExecuteQueryTest.class); suite.addTestSuite(OptimizedMarshallerIndexNameTest.class); + suite.addTestSuite(IgniteSqlDefaultValueTest.class); + return suite; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 e186612..98ab084 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/QueryEntityConfigurationParityTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/QueryEntityConfigurationParityTest.cs @@ -31,7 +31,8 @@ namespace Apache.Ignite.Core.Tests.ApiParity "findKeyType", "findValueType", "KeyFields", - "NotNullFields" + "NotNullFields", + "FieldsDefaultValues" }; /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 536cb18..fbd8775 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs @@ -550,6 +550,7 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(x.FieldTypeName, y.FieldTypeName); Assert.AreEqual(x.IsKeyField, y.IsKeyField); Assert.AreEqual(x.NotNull, y.NotNull); + Assert.AreEqual(x.DefaultValue, y.DefaultValue); } /// <summary> @@ -625,7 +626,7 @@ namespace Apache.Ignite.Core.Tests.Cache Fields = new[] { new QueryField("length", typeof(int)), - new QueryField("name", typeof(string)) {IsKeyField = true}, + new QueryField("name", typeof(string)) {IsKeyField = true, DefaultValue = "defName"}, new QueryField("location", typeof(string)) {NotNull = true}, }, Aliases = new [] {new QueryAlias("length", "len") }, @@ -734,7 +735,7 @@ namespace Apache.Ignite.Core.Tests.Cache TableName = "MyTable", Fields = new[] { - new QueryField("length", typeof(int)), + new QueryField("length", typeof(int)) {DefaultValue = -1}, new QueryField("name", typeof(string)), new QueryField("location", typeof(string)) {IsKeyField = true} }, http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs index f289e56..7ee6695 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs @@ -387,6 +387,46 @@ namespace Apache.Ignite.Core.Tests.Cache.Query } /// <summary> + /// Tests the QueryField.DefaultValue functionality. + /// </summary> + [Test] + public void TestDefaultValue() + { + // Attribute-based config. + var cfg = new CacheConfiguration("def_value_attr", new QueryEntity(typeof(int), typeof(Foo))); + Assert.AreEqual(-1, cfg.QueryEntities.Single().Fields.Single(x => x.Name == "Id").DefaultValue); + + var cache = Ignition.GetIgnite().CreateCache<int, Foo>(cfg); + Assert.AreEqual(-1, + cache.GetConfiguration().QueryEntities.Single().Fields.Single(x => x.Name == "Id").DefaultValue); + + cache.Query(new SqlFieldsQuery("insert into foo(_key, id, name) values (?, ?, ?)", 1, 2, "John")).GetAll(); + cache.Query(new SqlFieldsQuery("insert into foo(_key, name) values (?, ?)", 3, "Mary")).GetAll(); + + Assert.AreEqual(2, cache[1].Id); + Assert.AreEqual(-1, cache[3].Id); + + // QueryEntity-based config. + cfg = new CacheConfiguration("def_value_binary", new QueryEntity + { + KeyType = typeof(int), + ValueTypeName = "DefValTest", + Fields = new[] + { + new QueryField("Name", typeof(string)) {DefaultValue = "foo"} + } + }); + + var cache2 = Ignition.GetIgnite().CreateCache<int, int>(cfg).WithKeepBinary<int, IBinaryObject>(); + + cache2.Query(new SqlFieldsQuery("insert into DefValTest(_key, name) values (?, ?)", 1, "John")).GetAll(); + cache2.Query(new SqlFieldsQuery("insert into DefValTest(_key) values (?)", 2)).GetAll(); + + Assert.AreEqual("John", cache2[1].GetField<string>("Name")); + Assert.AreEqual("foo", cache2[2].GetField<string>("Name")); + } + + /// <summary> /// Key. /// </summary> private struct Key @@ -423,7 +463,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query /// </summary> private class Foo { - [QuerySqlField] public int Id { get; set; } + [QuerySqlField(DefaultValue = -1)] public int Id { get; set; } [QuerySqlField(NotNull = true)] public string Name { get; set; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml index aff48f5..29aa704 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml @@ -57,7 +57,9 @@ <queryEntities> <queryEntity keyType='System.Int32' valueType='System.String' tableName='myTable'> <fields> - <queryField name='length' fieldType='System.Int32' isKeyField='true' notNull='true' /> + <queryField name='length' fieldType='System.Int32' isKeyField='true' notNull='true'> + <defaultValue type="System.Double">3.456</defaultValue> + </queryField> </fields> <aliases> <queryAlias fullName='somefield.field' alias='shortField' /> http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs index 5512975..1260aa5 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs @@ -132,6 +132,7 @@ namespace Apache.Ignite.Core.Tests Assert.AreEqual(typeof(int), queryEntity.Fields.Single().FieldType); Assert.IsTrue(queryEntity.Fields.Single().IsKeyField); Assert.IsTrue(queryEntity.Fields.Single().NotNull); + Assert.AreEqual(3.456d, (double)queryEntity.Fields.Single().DefaultValue); Assert.AreEqual("somefield.field", queryEntity.Aliases.Single().FullName); Assert.AreEqual("shortField", queryEntity.Aliases.Single().Alias); @@ -677,7 +678,8 @@ namespace Apache.Ignite.Core.Tests new QueryField("field", typeof(int)) { IsKeyField = true, - NotNull = true + NotNull = true, + DefaultValue = "foo" } }, Indexes = new[] http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 4db15eb..a1fb4e0 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs @@ -457,7 +457,8 @@ namespace Apache.Ignite.Core.Cache.Configuration fields.Add(new QueryField(columnName, memberInfo.Value) { IsKeyField = isKey, - NotNull = attr.NotNull + NotNull = attr.NotNull, + DefaultValue = attr.DefaultValue }); ScanAttributes(memberInfo.Value, fields, indexes, columnName, visitedTypes, isKey); http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 b8142fd..38aeed3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs @@ -84,6 +84,7 @@ namespace Apache.Ignite.Core.Cache.Configuration FieldTypeName = reader.ReadString(); IsKeyField = reader.ReadBoolean(); NotNull = reader.ReadBoolean(); + DefaultValue = reader.ReadObject<object>(); } /// <summary> @@ -97,6 +98,7 @@ namespace Apache.Ignite.Core.Cache.Configuration writer.WriteString(FieldTypeName); writer.WriteBoolean(IsKeyField); writer.WriteBoolean(NotNull); + writer.WriteObject(DefaultValue); } /// <summary> @@ -147,6 +149,11 @@ namespace Apache.Ignite.Core.Cache.Configuration public bool NotNull { get; set; } /// <summary> + /// Gets or sets the default value for the field. + /// </summary> + public object DefaultValue { get; set; } + + /// <summary> /// Validates this instance and outputs information to the log, if necessary. /// </summary> internal void Validate(ILogger log, string logInfo) http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 d15cc1a..96912dd 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QuerySqlFieldAttribute.cs @@ -76,5 +76,10 @@ namespace Apache.Ignite.Core.Cache.Configuration /// Gets or sets a value indicating whether null values are allowed for this field. /// </summary> public bool NotNull { get; set; } + + /// <summary> + /// Gets or sets the default value for the field (has effect when inserting with DML). + /// </summary> + public object DefaultValue { get; set; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/78e79e01/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 190b3ad..84afdc4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd @@ -308,6 +308,13 @@ <xs:sequence> <xs:element name="queryField" maxOccurs="unbounded"> <xs:complexType> + <xs:all> + <xs:element name="defaultValue" minOccurs="0"> + <xs:annotation> + <xs:documentation>Default field value.</xs:documentation> + </xs:annotation> + </xs:element> + </xs:all> <xs:attribute name="name" type="xs:string" use="required"> <xs:annotation> <xs:documentation>Cache name.</xs:documentation>