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>

Reply via email to