You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2017/01/19 10:35:13 UTC

[1/8] ignite git commit: IGNITE-4514: Hadoop: fixed intermittent intermittent failure in HadoopCommandLineTest.testHiveCommandLine. This closes #1397.

Repository: ignite
Updated Branches:
  refs/heads/ignite-2.0 f1365421c -> e08b6ff48


IGNITE-4514: Hadoop: fixed intermittent intermittent failure in HadoopCommandLineTest.testHiveCommandLine. This closes #1397.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d6d42c2a
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d6d42c2a
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d6d42c2a

Branch: refs/heads/ignite-2.0
Commit: d6d42c2a17b7cf53a71d59931b2cf838bd8116c9
Parents: 82dd912
Author: Ivan Veselovskiy <iv...@gridgain.com>
Authored: Mon Jan 16 16:46:20 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Mon Jan 16 16:46:20 2017 +0300

----------------------------------------------------------------------
 .../processors/hadoop/impl/v2/HadoopV2TaskContext.java        | 7 -------
 1 file changed, 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/d6d42c2a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java
----------------------------------------------------------------------
diff --git a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java
index d328550..5229590 100644
--- a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java
+++ b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java
@@ -42,7 +42,6 @@ import org.apache.hadoop.util.ReflectionUtils;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.hadoop.io.PartiallyRawComparator;
 import org.apache.ignite.hadoop.io.TextPartiallyRawComparator;
-import org.apache.ignite.internal.processors.hadoop.HadoopClassLoader;
 import org.apache.ignite.internal.processors.hadoop.HadoopCommonUtils;
 import org.apache.ignite.internal.processors.hadoop.HadoopExternalSplit;
 import org.apache.ignite.internal.processors.hadoop.HadoopInputSplit;
@@ -508,12 +507,6 @@ public class HadoopV2TaskContext extends HadoopTaskContext {
         FileSystem fs;
 
         try {
-            // This assertion uses .startsWith() instead of .equals() because task class loaders may
-            // be reused between tasks of the same job.
-            assert ((HadoopClassLoader)getClass().getClassLoader()).name()
-                .startsWith(HadoopClassLoader.nameForTask(taskInfo(), true));
-
-            // We also cache Fs there, all them will be cleared explicitly upon the Job end.
             fs = fileSystemForMrUserWithCaching(jobDir.toUri(), jobConf(), fsMap);
         }
         catch (IOException e) {


[8/8] ignite git commit: Merge branch 'master' into ignite-2.0

Posted by pt...@apache.org.
Merge branch 'master' into ignite-2.0


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/e08b6ff4
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/e08b6ff4
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/e08b6ff4

Branch: refs/heads/ignite-2.0
Commit: e08b6ff48916edfab2dbd5d62092be5a1f819a2f
Parents: f136542 664dc88
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Thu Jan 19 13:34:59 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Thu Jan 19 13:34:59 2017 +0300

----------------------------------------------------------------------
 .../tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java |  37 ++-
 .../TcpDiscoveryS3IpFinderAbstractSelfTest.java |  84 ++++++
 ...3IpFinderAwsCredentialsProviderSelfTest.java |  46 +++
 ...scoveryS3IpFinderAwsCredentialsSelfTest.java |  45 +++
 .../s3/TcpDiscoveryS3IpFinderSelfTest.java      |  79 -----
 .../ignite/testsuites/IgniteS3TestSuite.java    |  26 +-
 .../cache/query/GridCacheQueryAdapter.java      |   8 +
 .../internal/processors/odbc/IgniteTypes.java   |  69 +++++
 .../internal/processors/odbc/OdbcTypes.java     | 131 ++++++++
 .../internal/processors/odbc/OdbcUtils.java     |  85 ++++++
 .../processors/odbc/escape/OdbcEscapeUtils.java |  52 +++-
 .../utils/PlatformConfigurationUtils.java       | 128 +++++++-
 .../IgniteCacheQueryCacheDestroySelfTest.java   | 142 +++++++++
 .../odbc/OdbcEscapeSequenceSelfTest.java        | 131 ++++++++
 .../hadoop/impl/v2/HadoopV2TaskContext.java     |   7 -
 .../IgniteCacheQuerySelfTestSuite.java          |   2 +
 .../cpp/binary/src/impl/binary/binary_utils.cpp |   6 +-
 .../cpp/common/include/ignite/common/utils.h    |   8 +
 .../cpp/common/os/linux/src/common/utils.cpp    |  22 +-
 .../cpp/common/os/win/src/common/utils.cpp      |  14 +-
 modules/platforms/cpp/odbc-test/Makefile.am     |   1 +
 .../odbc-test/include/sql_test_suite_fixture.h  |  13 +
 .../cpp/odbc-test/project/vs/odbc-test.vcxproj  |   1 +
 .../project/vs/odbc-test.vcxproj.filters        |   3 +
 .../cpp/odbc-test/src/api_robustness_test.cpp   |   2 +-
 .../src/sql_aggregate_functions_test.cpp        |   4 +-
 .../src/sql_esc_convert_function_test.cpp       | 160 ++++++++++
 .../odbc-test/src/sql_test_suite_fixture.cpp    |  52 +++-
 .../cpp/odbc-test/src/sql_types_test.cpp        | 131 +++++++-
 .../odbc/src/app/application_data_buffer.cpp    |  58 +++-
 .../platforms/cpp/odbc/src/app/parameter.cpp    |   4 +-
 .../cpp/odbc/src/config/connection_info.cpp     | 260 ++++++++++++++--
 .../Apache.Ignite.Core.Tests.csproj             |   3 +
 .../Binary/BinaryBuilderSelfTest.cs             | 159 ++++++----
 .../BinaryBuilderSelfTestArrayIdentity.cs       |  34 +++
 .../Binary/BinaryEqualityComparerTest.cs        | 279 +++++++++++++++++
 .../Binary/IO/BinaryStreamsTest.cs              |  19 ++
 .../Cache/CacheConfigurationTest.cs             |   5 +-
 .../Cache/Query/CacheDmlQueriesTest.cs          | 296 +++++++++++++++++++
 .../IgniteConfigurationSerializerTest.cs        |  46 ++-
 .../IgniteConfigurationTest.cs                  |  28 ++
 .../Apache.Ignite.Core.csproj                   |   5 +
 .../Binary/BinaryArrayEqualityComparer.cs       | 149 ++++++++++
 .../Binary/BinaryConfiguration.cs               |  24 ++
 .../Binary/BinaryTypeConfiguration.cs           |  14 +
 .../Cache/Configuration/QueryEntity.cs          |  33 ++-
 .../Cache/Configuration/QueryField.cs           |   6 +
 .../Apache.Ignite.Core/IgniteConfiguration.cs   |  85 ++++--
 .../IgniteConfigurationSection.xsd              |  19 ++
 .../Apache.Ignite.Core/Impl/Binary/Binary.cs    |  28 +-
 .../Binary/BinaryEqualityComparerSerializer.cs  |  99 +++++++
 .../Impl/Binary/BinaryFieldEqualityComparer.cs  | 138 +++++++++
 .../Impl/Binary/BinaryFullTypeDescriptor.cs     |  21 +-
 .../Impl/Binary/BinaryObject.cs                 |  31 +-
 .../Impl/Binary/BinaryObjectBuilder.cs          |  62 +++-
 .../Impl/Binary/BinaryObjectHeader.cs           |  21 +-
 .../Impl/Binary/BinaryObjectSchemaHolder.cs     |  22 ++
 .../Binary/BinarySurrogateTypeDescriptor.cs     |   6 +
 .../Impl/Binary/BinarySystemHandlers.cs         |   6 +-
 .../Impl/Binary/BinaryWriter.cs                 |  11 +-
 .../Impl/Binary/DateTimeHolder.cs               |  35 ++-
 .../Impl/Binary/IBinaryEqualityComparer.cs      |  53 ++++
 .../Impl/Binary/IBinaryTypeDescriptor.cs        |   5 +
 .../Impl/Binary/Io/BinaryHeapStream.cs          |   9 +
 .../Impl/Binary/Io/BinaryStreamBase.cs          |  13 +
 .../Impl/Binary/Io/IBinaryStream.cs             |  11 +-
 .../Impl/Binary/Io/IBinaryStreamProcessor.cs    |  36 +++
 .../Impl/Binary/Marshaller.cs                   |  22 +-
 .../Impl/Binary/SerializableObjectHolder.cs     |  16 +
 .../Common/IgniteConfigurationXmlSerializer.cs  |   5 +-
 .../Impl/Memory/PlatformMemoryStream.cs         |  16 +
 71 files changed, 3390 insertions(+), 291 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/e08b6ff4/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java
----------------------------------------------------------------------
diff --cc modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java
index 8b8a728,5229590..c698ee3
--- a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java
+++ b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/impl/v2/HadoopV2TaskContext.java
@@@ -42,11 -42,10 +42,10 @@@ import org.apache.hadoop.util.Reflectio
  import org.apache.ignite.IgniteCheckedException;
  import org.apache.ignite.hadoop.io.PartiallyRawComparator;
  import org.apache.ignite.hadoop.io.TextPartiallyRawComparator;
- import org.apache.ignite.internal.processors.hadoop.HadoopClassLoader;
  import org.apache.ignite.internal.processors.hadoop.HadoopCommonUtils;
  import org.apache.ignite.internal.processors.hadoop.HadoopExternalSplit;
 -import org.apache.ignite.internal.processors.hadoop.HadoopInputSplit;
 -import org.apache.ignite.internal.processors.hadoop.HadoopJob;
 +import org.apache.ignite.hadoop.HadoopInputSplit;
 +import org.apache.ignite.internal.processors.hadoop.HadoopJobEx;
  import org.apache.ignite.internal.processors.hadoop.HadoopJobId;
  import org.apache.ignite.internal.processors.hadoop.HadoopJobProperty;
  import org.apache.ignite.internal.processors.hadoop.HadoopPartitioner;


[7/8] ignite git commit: IGNITE-3837: ODBC: Support for CONVERT function escape sequence

Posted by pt...@apache.org.
IGNITE-3837: ODBC: Support for CONVERT function escape sequence

This closes #1422


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/664dc88e
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/664dc88e
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/664dc88e

Branch: refs/heads/ignite-2.0
Commit: 664dc88e94a8ac0506c2762b7e964f51c72d7459
Parents: 80bcf27
Author: Sergey Kalashnikov <sk...@gridgain.com>
Authored: Thu Jan 19 13:03:10 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Thu Jan 19 13:03:10 2017 +0300

----------------------------------------------------------------------
 .../internal/processors/odbc/IgniteTypes.java   |  69 +++++
 .../internal/processors/odbc/OdbcTypes.java     | 131 ++++++++++
 .../internal/processors/odbc/OdbcUtils.java     |  85 ++++++
 .../processors/odbc/escape/OdbcEscapeUtils.java |  52 +++-
 .../odbc/OdbcEscapeSequenceSelfTest.java        | 131 ++++++++++
 .../cpp/binary/src/impl/binary/binary_utils.cpp |   6 +-
 .../cpp/common/include/ignite/common/utils.h    |   8 +
 .../cpp/common/os/linux/src/common/utils.cpp    |  22 +-
 .../cpp/common/os/win/src/common/utils.cpp      |  14 +-
 modules/platforms/cpp/odbc-test/Makefile.am     |   1 +
 .../odbc-test/include/sql_test_suite_fixture.h  |  13 +
 .../cpp/odbc-test/project/vs/odbc-test.vcxproj  |   1 +
 .../project/vs/odbc-test.vcxproj.filters        |   3 +
 .../cpp/odbc-test/src/api_robustness_test.cpp   |   2 +-
 .../src/sql_aggregate_functions_test.cpp        |   4 +-
 .../src/sql_esc_convert_function_test.cpp       | 160 ++++++++++++
 .../odbc-test/src/sql_test_suite_fixture.cpp    |  52 +++-
 .../cpp/odbc-test/src/sql_types_test.cpp        | 131 +++++++++-
 .../odbc/src/app/application_data_buffer.cpp    |  58 ++++-
 .../platforms/cpp/odbc/src/app/parameter.cpp    |   4 +-
 .../cpp/odbc/src/config/connection_info.cpp     | 260 +++++++++++++++++--
 21 files changed, 1168 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/IgniteTypes.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/IgniteTypes.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/IgniteTypes.java
new file mode 100644
index 0000000..1eea4e2
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/IgniteTypes.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+/**
+ * Data type names usable in SQL queries
+ * after escape sequence transformation
+ */
+public class IgniteTypes {
+    /** Type name for 64-bit integer */
+    static final String BIGINT = "BIGINT";
+
+    /** Type name for byte array */
+    static final String BINARY = "BINARY";
+
+    /** Type name for boolean flag */
+    static final String BIT = "BIT";
+
+    /** Type name for unicode string */
+    static final String CHAR = "CHAR";
+
+    /** Type name for decimal number */
+    static final String DECIMAL = "DECIMAL";
+
+    /** Type name for unicode string */
+    static final String VARCHAR = "VARCHAR";
+
+    /** Type name for floating point number */
+    static final String DOUBLE = "DOUBLE";
+
+    /** Type name for single precision floating point number */
+    static final String REAL = "REAL";
+
+    /** Type name for universally unique identifier */
+    static final String UUID = "UUID";
+
+    /** Type name for 16-bit integer */
+    static final String SMALLINT = "SMALLINT";
+
+    /** Type name for 32-bit integer */
+    static final String INTEGER = "INTEGER";
+
+    /** Type name for 8-bit integer */
+    static final String TINYINT = "TINYINT";
+
+    /** Type name for date */
+    static final String DATE = "DATE";
+
+    /** Type name for time */
+    static final String TIME = "TIME";
+
+    /** Type name for timestamp */
+    static final String TIMESTAMP = "TIMESTAMP";
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcTypes.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcTypes.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcTypes.java
new file mode 100644
index 0000000..70ac92b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcTypes.java
@@ -0,0 +1,131 @@
+/*
+ * 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;
+
+/**
+ * Data type names that can occur within ODBC escape sequence
+ */
+public class OdbcTypes {
+    /** Type name for BIGINT */
+    static final String SQL_BIGINT = "SQL_BIGINT";
+
+    /** Type name for BINARY */
+    static final String SQL_BINARY = "SQL_BINARY";
+
+    /** Type name for LONGVARBINARY */
+    static final String SQL_LONGVARBINARY = "SQL_LONGVARBINARY";
+
+    /** Type name for VARBINARY */
+    static final String SQL_VARBINARY = "SQL_VARBINARY";
+
+    /** Type name for BIT */
+    static final String SQL_BIT = "SQL_BIT";
+
+    /** Type name for CHAR */
+    static final String SQL_CHAR = "SQL_CHAR";
+
+    /** Type name for DECIMAL */
+    static final String SQL_DECIMAL = "SQL_DECIMAL";
+
+    /** Type name for NUMERIC */
+    static final String SQL_NUMERIC = "SQL_NUMERIC";
+
+    /** Type name for LONGVARCHAR */
+    static final String SQL_LONGVARCHAR = "SQL_LONGVARCHAR";
+
+    /** Type name for VARCHAR */
+    static final String SQL_VARCHAR = "SQL_VARCHAR";
+
+    /** Type name for WCHAR */
+    static final String SQL_WCHAR = "SQL_WCHAR";
+
+    /** Type name for WLONGVARCHAR */
+    static final String SQL_WLONGVARCHAR = "SQL_WLONGVARCHAR";
+
+    /** Type name for WVARCHAR */
+    static final String SQL_WVARCHAR = "SQL_WVARCHAR";
+
+    /** Type name for DOUBLE */
+    static final String SQL_DOUBLE = "SQL_DOUBLE";
+
+    /** Type name for FLOAT */
+    static final String SQL_FLOAT = "SQL_FLOAT";
+
+    /** Type name for REAL */
+    static final String SQL_REAL = "SQL_REAL";
+
+    /** Type name for GUID */
+    static final String SQL_GUID = "SQL_GUID";
+
+    /** Type name for SMALLINT */
+    static final String SQL_SMALLINT = "SQL_SMALLINT";
+
+    /** Type name for INTEGER */
+    static final String SQL_INTEGER = "SQL_INTEGER";
+
+    /** Type name for DATE */
+    static final String SQL_DATE = "SQL_DATE";
+
+    /** Type name for TIME */
+    static final String SQL_TIME = "SQL_TIME";
+
+    /** Type name for TIMESTAMP */
+    static final String SQL_TIMESTAMP = "SQL_TIMESTAMP";
+
+    /** Type name for TINYINT */
+    static final String SQL_TINYINT = "SQL_TINYINT";
+
+    /** Type name for INTERVAL_SECOND */
+    static final String SQL_INTERVAL_SECOND = "SQL_INTERVAL_SECOND";
+
+    /** Type name for INTERVAL_MINUTE */
+    static final String SQL_INTERVAL_MINUTE = "SQL_INTERVAL_MINUTE";
+
+    /** Type name for INTERVAL_HOUR */
+    static final String SQL_INTERVAL_HOUR = "SQL_INTERVAL_HOUR";
+
+    /** Type name for INTERVAL_DAY */
+    static final String SQL_INTERVAL_DAY = "SQL_INTERVAL_DAY";
+
+    /** Type name for INTERVAL_MONTH */
+    static final String SQL_INTERVAL_MONTH = "SQL_INTERVAL_MONTH";
+
+    /** Type name for INTERVAL_YEAR */
+    static final String SQL_INTERVAL_YEAR = "SQL_INTERVAL_YEAR";
+
+    /** Type name for INTERVAL_YEAR_TO_MONTH */
+    static final String SQL_INTERVAL_YEAR_TO_MONTH = "SQL_INTERVAL_YEAR_TO_MONTH";
+
+    /** Type name for INTERVAL_HOUR_TO_MINUTE */
+    static final String SQL_INTERVAL_HOUR_TO_MINUTE = "SQL_INTERVAL_HOUR_TO_MINUTE";
+
+    /** Type name for INTERVAL_HOUR_TO_SECOND */
+    static final String SQL_INTERVAL_HOUR_TO_SECOND = "SQL_INTERVAL_HOUR_TO_SECOND";
+
+    /** Type name for INTERVAL_MINUTE_TO_SECOND */
+    static final String SQL_INTERVAL_MINUTE_TO_SECOND = "SQL_INTERVAL_MINUTE_TO_SECOND";
+
+    /** Type name for INTERVAL_DAY_TO_HOUR */
+    static final String SQL_INTERVAL_DAY_TO_HOUR = "SQL_INTERVAL_DAY_TO_HOUR";
+
+    /** Type name for INTERVAL_DAY_TO_MINUTE */
+    static final String SQL_INTERVAL_DAY_TO_MINUTE = "SQL_INTERVAL_DAY_TO_MINUTE";
+
+    /** Type name for INTERVAL_DAY_TO_SECOND */
+    static final String SQL_INTERVAL_DAY_TO_SECOND  = "SQL_INTERVAL_DAY_TO_SECOND";
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java
index 3903562..d851d13 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java
@@ -17,6 +17,8 @@
 
 package org.apache.ignite.internal.processors.odbc;
 
+import org.apache.ignite.IgniteException;
+
 /**
  * Various ODBC utility methods.
  */
@@ -53,4 +55,87 @@ public class OdbcUtils {
     private OdbcUtils() {
         // No-op.
     }
+
+    /**
+     * Lookup Ignite data type corresponding to specific ODBC data type
+     *
+     * @param odbcDataType ODBC data type identifier
+     * @return Ignite data type name
+     */
+    public static String getIgniteTypeFromOdbcType(String odbcDataType) {
+        assert odbcDataType != null;
+        switch (odbcDataType.toUpperCase()) {
+            case OdbcTypes.SQL_BIGINT:
+                return IgniteTypes.BIGINT;
+
+            case OdbcTypes.SQL_BINARY:
+            case OdbcTypes.SQL_LONGVARBINARY:
+            case OdbcTypes.SQL_VARBINARY:
+                return IgniteTypes.BINARY;
+
+            case OdbcTypes.SQL_BIT:
+                return IgniteTypes.BIT;
+
+            case OdbcTypes.SQL_CHAR:
+                return IgniteTypes.CHAR;
+
+            case OdbcTypes.SQL_DECIMAL:
+            case OdbcTypes.SQL_NUMERIC:
+                return IgniteTypes.DECIMAL;
+
+            case OdbcTypes.SQL_LONGVARCHAR:
+            case OdbcTypes.SQL_VARCHAR:
+            case OdbcTypes.SQL_WCHAR:
+            case OdbcTypes.SQL_WLONGVARCHAR:
+            case OdbcTypes.SQL_WVARCHAR:
+                return IgniteTypes.VARCHAR;
+
+            case OdbcTypes.SQL_DOUBLE:
+            case OdbcTypes.SQL_FLOAT:
+                return IgniteTypes.DOUBLE;
+
+            case OdbcTypes.SQL_REAL:
+                return IgniteTypes.REAL;
+
+            case OdbcTypes.SQL_GUID:
+                return IgniteTypes.UUID;
+
+            case OdbcTypes.SQL_SMALLINT:
+                return IgniteTypes.SMALLINT;
+
+            case OdbcTypes.SQL_INTEGER:
+                return IgniteTypes.INTEGER;
+
+            case OdbcTypes.SQL_DATE:
+                return IgniteTypes.DATE;
+
+            case OdbcTypes.SQL_TIME:
+                return IgniteTypes.TIME;
+
+            case OdbcTypes.SQL_TIMESTAMP:
+                return IgniteTypes.TIMESTAMP;
+
+            case OdbcTypes.SQL_TINYINT:
+                return IgniteTypes.TINYINT;
+
+            //No support for interval types
+            case OdbcTypes.SQL_INTERVAL_SECOND:
+            case OdbcTypes.SQL_INTERVAL_MINUTE:
+            case OdbcTypes.SQL_INTERVAL_HOUR:
+            case OdbcTypes.SQL_INTERVAL_DAY:
+            case OdbcTypes.SQL_INTERVAL_MONTH:
+            case OdbcTypes.SQL_INTERVAL_YEAR:
+            case OdbcTypes.SQL_INTERVAL_YEAR_TO_MONTH:
+            case OdbcTypes.SQL_INTERVAL_HOUR_TO_MINUTE:
+            case OdbcTypes.SQL_INTERVAL_HOUR_TO_SECOND:
+            case OdbcTypes.SQL_INTERVAL_MINUTE_TO_SECOND:
+            case OdbcTypes.SQL_INTERVAL_DAY_TO_HOUR:
+            case OdbcTypes.SQL_INTERVAL_DAY_TO_MINUTE:
+            case OdbcTypes.SQL_INTERVAL_DAY_TO_SECOND:
+                throw new IgniteException("Unsupported ODBC data type '" + odbcDataType + "'");
+
+            default:
+                throw new IgniteException("Invalid ODBC data type '" + odbcDataType + "'");
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java
index bbf19c7..01f32d1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java
@@ -18,8 +18,9 @@
 package org.apache.ignite.internal.processors.odbc.escape;
 
 import org.apache.ignite.IgniteException;
-
+import org.apache.ignite.internal.processors.odbc.OdbcUtils;
 import java.util.LinkedList;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
@@ -40,6 +41,11 @@ public class OdbcEscapeUtils {
     private static final Pattern GUID_PATTERN =
         Pattern.compile("^'\\p{XDigit}{8}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{12}'$");
 
+    /** CONVERT function data type parameter pattern: last parameter, after comma */
+    private static final Pattern CONVERT_TYPE_PATTERN =
+        Pattern.compile(",\\s*(SQL_[\\w_]+)\\s*(?:\\(\\s*\\d+\\s*(?:,\\s*\\d+\\s*)?\\))?\\s*\\)\\s*$",
+                        Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+
     /**
      * Parse escape sequence.
      *
@@ -248,7 +254,7 @@ public class OdbcEscapeUtils {
 
         switch (token.type()) {
             case SCALAR_FUNCTION:
-                return parseExpression(text, startPos0, len0);
+                return parseScalarFunctionExpression(text, startPos0, len0);
 
             case GUID: {
                 String res = parseExpression(text, startPos0, len0, token.type(), GUID_PATTERN);
@@ -326,6 +332,48 @@ public class OdbcEscapeUtils {
     }
 
     /**
+     * Parse scalar function expression.
+     *
+     * @param text Text.
+     * @param startPos Start position.
+     * @param len Length.
+     * @return Parsed expression.
+     */
+    private static String parseScalarFunctionExpression(String text, int startPos, int len) {
+        int pos = startPos;
+        int endPos = startPos + len;
+        final String errPrefix = "Malformed scalar function escape sequence.";
+
+        while ((++pos < endPos) && Character.isWhitespace(text.charAt(pos)));
+        if (pos == endPos)
+            throw new IgniteException(errPrefix + " Expected function name.");
+
+        int funcNamePos = pos;
+        while ((++pos < endPos) && Character.isAlphabetic(text.charAt(pos)));
+        if (pos == endPos)
+            throw new IgniteException(errPrefix + " Expected function parameter list: " +
+                                      substring(text, startPos, len));
+
+        String funcName = text.substring(funcNamePos, pos);
+
+        switch (funcName.toUpperCase()) {
+            case "CONVERT": {
+                Matcher matcher = CONVERT_TYPE_PATTERN.matcher(text.substring(startPos, endPos));
+
+                if (!matcher.find())
+                    throw new IgniteException(errPrefix + " Invalid arguments :" +
+                                              substring(text, startPos, len));
+
+                return (text.substring(startPos, startPos + matcher.start(1)) +
+                        OdbcUtils.getIgniteTypeFromOdbcType(matcher.group(1)) +
+                        text.substring(startPos + matcher.end(1), startPos + len)).trim();
+            }
+            default:
+                return substring(text, startPos, len).trim();
+        }
+    }
+
+    /**
      * Append nested results.
      *
      * @param text Original text.

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java
index 5303c6e..ecb6c2d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java
@@ -74,6 +74,137 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest {
     }
 
     /**
+     * Test escape sequence for explicit data type conversion
+     */
+    public void testConvertFunction() throws Exception {
+        check(
+         "CONVERT ( CURDATE(), CHAR )",
+         "{ fn CONVERT ( { fn CURDATE() }, SQL_CHAR ) }"
+        );
+
+        check(
+         "conVerT ( some_expression('one', 'two') , DECIMAL ( 5 , 2 ) )",
+         "{ fn conVerT ( some_expression('one', 'two') , SQL_DECIMAL ( 5 , 2 ) ) }"
+        );
+
+        check(
+         "convert(field,CHAR)",
+         "{fn convert(field,sql_char)}"
+        );
+
+        check(
+         "convert(field,BIGINT)",
+         "{fn convert(field,sql_bigint)}"
+        );
+
+        check(
+         "convert(field,BINARY)",
+         "{fn convert(field,sql_binary)}" // also sql_varbinary,sql_longvarbinary
+        );
+
+        check(
+         "convert(field,BIT)",
+         "{fn convert(field,sql_bit)}"
+        );
+
+        check(
+         "convert(field,CHAR(100))",
+         "{fn convert(field,sql_char(100))}"
+        );
+
+        check(
+         "convert(field,DECIMAL(5,2))",
+         "{fn convert(field,sql_decimal(5,2))}" // also sql_numeric
+        );
+
+        check(
+         "convert(field,VARCHAR(100))",
+         "{fn convert(field,sql_varchar(100))}" // also sql_longvarchar,sql_wchar,sql_wlongvarchar,sql_wvarchar
+        );
+
+        check(
+         "convert(field,DOUBLE)",
+         "{fn convert(field,sql_double)}" // also sql_float
+        );
+
+        check(
+         "convert(field,REAL)",
+         "{fn convert(field,sql_real)}"
+        );
+
+        check(
+         "convert(field,UUID)",
+         "{fn convert(field,sql_guid)}"
+        );
+
+        check(
+         "convert(field,SMALLINT)",
+         "{fn convert(field,sql_smallint)}"
+        );
+
+        check(
+         "convert(field,INTEGER)",
+         "{fn convert(field,sql_integer)}"
+        );
+
+        check(
+         "convert(field,DATE)",
+         "{fn convert(field,sql_date)}"
+        );
+
+        check(
+         "convert(field,TIME)",
+         "{fn convert(field,sql_time)}"
+        );
+
+        check(
+         "convert(field,TIMESTAMP)",
+         "{fn convert(field,sql_timestamp)}"
+        );
+
+        check(
+         "convert(field,TINYINT)",
+         "{fn convert(field,sql_tinyint)}"
+        );
+
+        //invalid odbc type
+        checkFail("{fn convert(field,char)}");
+
+        //no support for interval types
+        checkFail("{fn convert(field,sql_interval_second)}");
+        checkFail("{fn convert(field,sql_interval_minute)}");
+        checkFail("{fn convert(field,sql_interval_hour)}");
+        checkFail("{fn convert(field,sql_interval_day)}");
+        checkFail("{fn convert(field,sql_interval_month)}");
+        checkFail("{fn convert(field,sql_interval_year)}");
+        checkFail("{fn convert(field,sql_interval_year_to_month)}");
+        checkFail("{fn convert(field,sql_interval_hour_to_minute)}");
+        checkFail("{fn convert(field,sql_interval_hour_to_second)}");
+        checkFail("{fn convert(field,sql_interval_minute_to_second)}");
+        checkFail("{fn convert(field,sql_interval_day_to_hour)}");
+        checkFail("{fn convert(field,sql_interval_day_to_minute)}");
+        checkFail("{fn convert(field,sql_interval_day_to_second)}");
+
+        //failure: expected function name
+        checkFail("{fn    }");
+
+        //failure: expected function parameter list
+        checkFail("{fn convert}");
+
+        //failure: expected data type parameter for convert function
+        checkFail("{fn convert ( justoneparam ) }");
+
+        //failure: empty precision/scale
+        checkFail("{fn convert ( justoneparam, sql_decimal( ) }");
+
+        //failure: empty precision/scale
+        checkFail("{fn convert ( justoneparam, sql_decimal(not_a_number) }");
+
+        //failure: missing scale after comma
+        checkFail("{fn convert ( justoneparam, sql_decimal(10,) }");
+    }
+
+    /**
      * Test simple nested escape sequences. Depth = 2.
      */
     public void testNestedFunction() throws Exception {

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/binary/src/impl/binary/binary_utils.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/binary/src/impl/binary/binary_utils.cpp b/modules/platforms/cpp/binary/src/impl/binary/binary_utils.cpp
index 1a1946c..22738ef 100644
--- a/modules/platforms/cpp/binary/src/impl/binary/binary_utils.cpp
+++ b/modules/platforms/cpp/binary/src/impl/binary/binary_utils.cpp
@@ -220,13 +220,13 @@ namespace ignite
                 int64_t milliseconds = stream->ReadInt64();
                 int32_t nanoseconds = stream->ReadInt32();
 
-                return Timestamp(milliseconds / 1000, nanoseconds);
+                return Timestamp(milliseconds / 1000, (milliseconds % 1000) * 1000000 + nanoseconds);
             }
 
             void BinaryUtils::WriteTimestamp(interop::InteropOutputStream* stream, const Timestamp val)
             {
-                stream->WriteInt64(val.GetSeconds() * 1000);
-                stream->WriteInt32(val.GetSecondFraction());
+                stream->WriteInt64(val.GetSeconds() * 1000 + val.GetSecondFraction() / 1000000);
+                stream->WriteInt32(val.GetSecondFraction() % 1000000);
             }
 
             void BinaryUtils::WriteString(interop::InteropOutputStream* stream, const char* val, const int32_t len)

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/common/include/ignite/common/utils.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/common/include/ignite/common/utils.h b/modules/platforms/cpp/common/include/ignite/common/utils.h
index f4d2a9f..6ac3c17 100644
--- a/modules/platforms/cpp/common/include/ignite/common/utils.h
+++ b/modules/platforms/cpp/common/include/ignite/common/utils.h
@@ -204,6 +204,14 @@ namespace ignite
 
             return i == end;
         }
+
+        /**
+        * Converts 32-bit integer to big endian format
+        *
+        * @param value Input value
+        * @return Resulting value
+        */
+        IGNITE_IMPORT_EXPORT uint32_t ToBigEndian(uint32_t value);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/common/os/linux/src/common/utils.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/common/os/linux/src/common/utils.cpp b/modules/platforms/cpp/common/os/linux/src/common/utils.cpp
index e37a91c..0fa9231 100644
--- a/modules/platforms/cpp/common/os/linux/src/common/utils.cpp
+++ b/modules/platforms/cpp/common/os/linux/src/common/utils.cpp
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- 
+
 #include <time.h>
 
 #include <sys/stat.h>
@@ -109,17 +109,17 @@ namespace ignite
         std::string GetEnv(const std::string& name, bool& found)
         {
             char* val = std::getenv(name.c_str());
-            
+
             if (val)
             {
                 found = true;
-                
+
                 return std::string(val);
             }
             else
             {
                 found = false;
-                
+
                 return std::string();
             }
         }
@@ -127,10 +127,22 @@ namespace ignite
         bool FileExists(const std::string& path)
         {
             struct stat s;
-            
+
             int res = stat(path.c_str(), &s);
 
             return res != -1;
         }
+
+        uint32_t ToBigEndian(uint32_t value)
+        {
+            // The answer is 42
+            static const int num = 42;
+            static const bool isLittleEndian = (*reinterpret_cast<const char*>(&num) == num);
+
+            if (isLittleEndian)
+                return ((value & 0xFF) << 24) | (((value >> 8) & 0xFF) << 16) | (((value >> 16) & 0xFF) << 8) | ((value >> 24) & 0xFF);
+
+            return value;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/common/os/win/src/common/utils.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/common/os/win/src/common/utils.cpp b/modules/platforms/cpp/common/os/win/src/common/utils.cpp
index 77c90b8..c6afce2 100644
--- a/modules/platforms/cpp/common/os/win/src/common/utils.cpp
+++ b/modules/platforms/cpp/common/os/win/src/common/utils.cpp
@@ -115,7 +115,7 @@ namespace ignite
 
                 return std::string(res0);
             }
-            else 
+            else
             {
                 found = false;
 
@@ -138,5 +138,17 @@ namespace ignite
                 return true;
             }
         }
+
+        uint32_t ToBigEndian(uint32_t value)
+        {
+            // The answer is 42
+            static const int num = 42;
+            static const bool isLittleEndian = (*reinterpret_cast<const char*>(&num) == num);
+
+            if (isLittleEndian)
+                return ((value & 0xFF) << 24) | (((value >> 8) & 0xFF) << 16) | (((value >> 16) & 0xFF) << 8) | ((value >> 24) & 0xFF);
+
+            return value;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/Makefile.am
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/Makefile.am b/modules/platforms/cpp/odbc-test/Makefile.am
index c2f3fa2..56ae56a 100644
--- a/modules/platforms/cpp/odbc-test/Makefile.am
+++ b/modules/platforms/cpp/odbc-test/Makefile.am
@@ -69,6 +69,7 @@ ignite_odbc_tests_SOURCES = \
     src/sql_numeric_functions_test.cpp \
     src/sql_aggregate_functions_test.cpp \
     src/sql_system_functions_test.cpp \
+    src/sql_esc_convert_function_test.cpp \
     src/sql_operators_test.cpp \
     src/sql_value_expressions_test.cpp \
     src/sql_types_test.cpp \

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/include/sql_test_suite_fixture.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/include/sql_test_suite_fixture.h b/modules/platforms/cpp/odbc-test/include/sql_test_suite_fixture.h
index 55353e5..0fa6ec9 100644
--- a/modules/platforms/cpp/odbc-test/include/sql_test_suite_fixture.h
+++ b/modules/platforms/cpp/odbc-test/include/sql_test_suite_fixture.h
@@ -35,6 +35,7 @@
 
 #include "ignite/ignite.h"
 #include "ignite/ignition.h"
+#include "ignite/common/decimal.h"
 
 #include "test_type.h"
 
@@ -195,6 +196,18 @@ namespace ignite
 
     template<>
     void SqlTestSuiteFixture::CheckSingleResult<std::vector<int8_t> >(const char* request, const std::vector<int8_t>& expected);
+
+    template<>
+    void SqlTestSuiteFixture::CheckSingleResult<ignite::common::Decimal>(const char* request, const ignite::common::Decimal& expected);
+
+    template<>
+    void SqlTestSuiteFixture::CheckSingleResult<Date>(const char* request, const Date& expected);
+
+    template<>
+    void SqlTestSuiteFixture::CheckSingleResult<SQL_TIME_STRUCT>(const char* request, const SQL_TIME_STRUCT& expected);
+
+    template<>
+    void SqlTestSuiteFixture::CheckSingleResult<Timestamp>(const char* request, const Timestamp& expected);
 }
 
 #endif //_IGNITE_ODBC_TEST_SQL_TEST_SUIT_FIXTURE

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
index 6f85896..8740d5a 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
@@ -178,6 +178,7 @@
     <ClCompile Include="..\..\src\sql_operators_test.cpp" />
     <ClCompile Include="..\..\src\sql_string_functions_test.cpp" />
     <ClCompile Include="..\..\src\sql_system_functions_test.cpp" />
+    <ClCompile Include="..\..\src\sql_esc_convert_function_test.cpp" />
     <ClCompile Include="..\..\src\sql_types_test.cpp" />
     <ClCompile Include="..\..\src\sql_value_expressions_test.cpp" />
     <ClCompile Include="..\..\src\teamcity\teamcity_boost.cpp" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
index bedceaa..a53cc47 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
@@ -94,6 +94,9 @@
     <ClCompile Include="..\..\src\sql_system_functions_test.cpp">
       <Filter>Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\sql_esc_convert_function_test.cpp">
+      <Filter>Code</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\sql_operators_test.cpp">
       <Filter>Code</Filter>
     </ClCompile>

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
index 0b6df93..5247129 100644
--- a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp
@@ -354,7 +354,7 @@ BOOST_AUTO_TEST_CASE(TestSQLConnect)
     // Everyting is ok.
     SQLRETURN ret = SQLGetInfo(dbc, SQL_DRIVER_NAME, buffer, ODBC_BUFFER_SIZE, &resLen);
 
-    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
 
     // Resulting length is null.
     SQLGetInfo(dbc, SQL_DRIVER_NAME, buffer, ODBC_BUFFER_SIZE, 0);

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/src/sql_aggregate_functions_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/sql_aggregate_functions_test.cpp b/modules/platforms/cpp/odbc-test/src/sql_aggregate_functions_test.cpp
index 3fa4d97..de1f5f8 100644
--- a/modules/platforms/cpp/odbc-test/src/sql_aggregate_functions_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/sql_aggregate_functions_test.cpp
@@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(TestAggregateFunctionAvgFloat)
     {
         testCache.Put(i, in[i]);
 
-        avg += in[i].i32Field;
+        avg += in[i].floatField;
     }
 
     avg /= in.size();
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(TestAggregateFunctionAvgFloatDistinct)
     {
         testCache.Put(i, in[i]);
 
-        avg += in[i].i32Field;
+        avg += in[i].floatField;
     }
 
     avg /= in.size();

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/src/sql_esc_convert_function_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/sql_esc_convert_function_test.cpp b/modules/platforms/cpp/odbc-test/src/sql_esc_convert_function_test.cpp
new file mode 100644
index 0000000..d9a14a9
--- /dev/null
+++ b/modules/platforms/cpp/odbc-test/src/sql_esc_convert_function_test.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+#ifndef _MSC_VER
+#   define BOOST_TEST_DYN_LINK
+#endif
+
+#include <boost/test/unit_test.hpp>
+#include "ignite/common/decimal.h"
+#include "ignite/common/utils.h"
+#include "sql_test_suite_fixture.h"
+#include "test_utils.h"
+
+using namespace ignite;
+using namespace ignite::common;
+using namespace boost::unit_test;
+
+BOOST_FIXTURE_TEST_SUITE(SqlEscConvertFunctionTestSuite, ignite::SqlTestSuiteFixture)
+
+int CheckConnectionInfo(HDBC dbc, int infoType)
+{
+    SQLUINTEGER mask = 0;
+    SQLRETURN ret = SQLGetInfo(dbc, infoType, &mask, sizeof(mask), 0);
+    ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_DBC, dbc);
+    return mask;
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionGetInfo)
+{
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_FUNCTIONS) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_BIGINT) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_BINARY) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_BIT) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_CHAR) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_DATE) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_DECIMAL) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_DOUBLE) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_FLOAT) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_INTEGER) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_LONGVARCHAR) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_NUMERIC) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_REAL) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_SMALLINT) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_TIME) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_TIMESTAMP) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_TINYINT) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_VARBINARY) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_VARCHAR) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_LONGVARBINARY) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_WCHAR) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_WLONGVARCHAR) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_WVARCHAR) != 0);
+    BOOST_REQUIRE(CheckConnectionInfo(dbc, SQL_CONVERT_GUID) != 0);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionInt64)
+{
+    CheckSingleResult<int64_t>("SELECT {fn CONVERT(72623859790382856, SQL_BIGINT)}", 72623859790382856);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionInt32)
+{
+    CheckSingleResult<int32_t>("SELECT {fn CONVERT(1234567890, SQL_INTEGER)}", 1234567890);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionInt16)
+{
+    CheckSingleResult<int16_t>("SELECT {fn CONVERT(12345, SQL_SMALLINT)}", 12345);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionInt8)
+{
+    CheckSingleResult<int8_t>("SELECT {fn CONVERT(123, SQL_TINYINT)}", 123);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionByteArray)
+{
+    int32_t value = ToBigEndian(123456);
+
+    std::vector<int8_t> val;
+    val.assign((const int8_t*)&value, (const int8_t*)&value+sizeof(value));
+
+    CheckSingleResult<std::vector<int8_t> >("SELECT {fn CONVERT(123456, SQL_BINARY(4))}", val);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionBool)
+{
+    CheckSingleResult<bool>("SELECT {fn CONVERT(1, SQL_BIT)}", true);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionString)
+{
+    CheckSingleResult<std::string>("SELECT {fn CONVERT(123, SQL_VARCHAR(10))}", "123");
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionDecimal)
+{
+    CheckSingleResult<Decimal>("SELECT {fn CONVERT(-1.25, SQL_DECIMAL(5,2))}", Decimal("-1.25"));
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionDouble)
+{
+    CheckSingleResult<double>("SELECT CAST(-1.25 AS DOUBLE)", -1.25);
+    CheckSingleResult<double>("SELECT CONVERT(-1.25, DOUBLE)", -1.25);
+    CheckSingleResult<double>("SELECT {fn CONVERT(-1.25, SQL_DOUBLE)}", -1.25);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionFloat)
+{
+    CheckSingleResult<float>("SELECT CAST(-1.25 AS REAL)", -1.25);
+    CheckSingleResult<float>("SELECT CONVERT(-1.25, REAL)", -1.25);
+    CheckSingleResult<float>("SELECT CAST(-1.25 AS FLOAT4)", -1.25);
+    CheckSingleResult<float>("SELECT CONVERT(-1.25, FLOAT4)", -1.25);
+    CheckSingleResult<float>("SELECT {fn CONVERT(-1.25, SQL_REAL)}", -1.25);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionGuid)
+{
+    //no support for binding as GUID because we report v3.0 to DM, thus fallback to string binding for now
+    CheckSingleResult<std::string>("SELECT {fn CONVERT({guid '04cc382a-0b82-f520-08d0-07a0620c0004'}, SQL_GUID)}", "04cc382a-0b82-f520-08d0-07a0620c0004");
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionDate)
+{
+    using ignite::impl::binary::BinaryUtils;
+    Date date = BinaryUtils::MakeDateGmt(1983, 3, 14);
+    CheckSingleResult<Date>("SELECT {fn CONVERT('1983-03-14', SQL_DATE)}", date);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionTime)
+{
+    SQL_TIME_STRUCT exp;
+    exp.hour = 13;
+    exp.minute = 20;
+    exp.second = 15;
+    CheckSingleResult<SQL_TIME_STRUCT>("SELECT {fn CONVERT('13:20:15', SQL_TIME)}", exp);
+}
+
+BOOST_AUTO_TEST_CASE(TestEscConvertFunctionTimestamp)
+{
+    using ignite::impl::binary::BinaryUtils;
+    Timestamp ts = BinaryUtils::MakeTimestampGmt(1983, 3, 14, 13, 20, 15, 999999999);
+    CheckSingleResult<Timestamp>("SELECT {fn CONVERT('1983-03-14 13:20:15.999999999', SQL_TIMESTAMP)}", ts);
+}
+
+BOOST_AUTO_TEST_SUITE_END()

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp b/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp
index b118ff8..1ecd26a 100644
--- a/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp
+++ b/modules/platforms/cpp/odbc-test/src/sql_test_suite_fixture.cpp
@@ -177,7 +177,7 @@ namespace ignite
     template<>
     void SqlTestSuiteFixture::CheckSingleResult<float>(const char* request, const float& expected)
     {
-        SQLFLOAT res = 0;
+        SQLREAL res = 0;
 
         CheckSingleResult0(request, SQL_C_FLOAT, &res, 0, 0);
 
@@ -257,7 +257,7 @@ namespace ignite
     template<>
     void SqlTestSuiteFixture::CheckSingleResult<float>(const char* request)
     {
-        SQLFLOAT res = 0;
+        SQLREAL res = 0;
 
         CheckSingleResult0(request, SQL_C_FLOAT, &res, 0, 0);
     }
@@ -302,4 +302,52 @@ namespace ignite
             BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), actual.begin(), actual.end());
         }
     }
+
+    template<>
+    void SqlTestSuiteFixture::CheckSingleResult<ignite::common::Decimal>(const char* request, const ignite::common::Decimal& expected)
+    {
+        SQLCHAR res[ODBC_BUFFER_SIZE] = { 0 };
+        SQLLEN resLen = 0;
+
+        CheckSingleResult0(request, SQL_C_CHAR, res, ODBC_BUFFER_SIZE, &resLen);
+        ignite::common::Decimal actual(std::string(res, res + resLen));
+    }
+
+    template<>
+    void SqlTestSuiteFixture::CheckSingleResult<Date>(const char* request, const Date& expected)
+    {
+        SQL_DATE_STRUCT res;
+
+        CheckSingleResult0(request, SQL_C_DATE, &res, 0, 0);
+
+        using ignite::impl::binary::BinaryUtils;
+        Date actual = BinaryUtils::MakeDateGmt(res.year, res.month, res.day);
+        BOOST_REQUIRE_EQUAL(actual.GetSeconds(), expected.GetSeconds());
+    }
+
+    template<>
+    void SqlTestSuiteFixture::CheckSingleResult<SQL_TIME_STRUCT>(const char* request, const SQL_TIME_STRUCT& expected)
+    {
+        SQL_TIME_STRUCT res;
+
+        CheckSingleResult0(request, SQL_C_TIME, &res, 0, 0);
+
+        BOOST_REQUIRE_EQUAL(res.hour, expected.hour);
+        BOOST_REQUIRE_EQUAL(res.minute, expected.minute);
+        BOOST_REQUIRE_EQUAL(res.second, expected.second);
+    }
+
+    template<>
+    void SqlTestSuiteFixture::CheckSingleResult<Timestamp>(const char* request, const Timestamp& expected)
+    {
+        SQL_TIMESTAMP_STRUCT res;
+
+        CheckSingleResult0(request, SQL_C_TIMESTAMP, &res, 0, 0);
+
+        using ignite::impl::binary::BinaryUtils;
+        Timestamp actual = BinaryUtils::MakeTimestampGmt(res.year, res.month, res.day, res.hour, res.minute, res.second, res.fraction);
+
+        BOOST_REQUIRE_EQUAL(actual.GetSeconds(), expected.GetSeconds());
+        BOOST_REQUIRE_EQUAL(actual.GetSecondFraction(), expected.GetSecondFraction());
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc-test/src/sql_types_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/sql_types_test.cpp b/modules/platforms/cpp/odbc-test/src/sql_types_test.cpp
index 33797b0..bba806c 100644
--- a/modules/platforms/cpp/odbc-test/src/sql_types_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/sql_types_test.cpp
@@ -76,14 +76,14 @@ BOOST_AUTO_TEST_CASE(TestByteArraySelect)
 BOOST_AUTO_TEST_CASE(TestByteArrayParam)
 {
     SQLRETURN ret;
-    
+
     TestType in;
     in.i8Field = 101;
 
     const int8_t data[] = { 'A','B','C','D','E','F','G','H','I','J' };
     in.i8ArrayField.assign(data, data + sizeof(data) / sizeof(data[0]));
 
-    testCache.Put(1, in);   
+    testCache.Put(1, in);
 
     SQLLEN colLen = 0;
     SQLCHAR colData = 0;
@@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(TestByteArrayParamInsert)
 
     if (!SQL_SUCCEEDED(ret))
         BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
-    
+
     SQLLEN paramLen = paramData.size();
 
     ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, paramData.size(), 0, &paramData[0], paramData.size(), &paramLen);
@@ -188,4 +188,129 @@ BOOST_AUTO_TEST_CASE(TestByteParamInsert)
     BOOST_REQUIRE_EQUAL(out.i8Field, data);
 }
 
+BOOST_AUTO_TEST_CASE(TestTimestampSelect)
+{
+    TestType in1;
+    in1.i32Field = 1;
+    in1.timestampField = impl::binary::BinaryUtils::MakeTimestampGmt(2017, 1, 13, 19, 54, 01, 987654321);
+
+    testCache.Put(1, in1);
+
+    CheckSingleResult<int32_t>(
+        "SELECT i32Field FROM TestType WHERE timestampField = '2017-01-13 19:54:01.987654321'", in1.i32Field);
+
+    CheckSingleResult<Timestamp>(
+        "SELECT timestampField FROM TestType WHERE i32Field = 1", in1.timestampField);
+}
+
+BOOST_AUTO_TEST_CASE(TestTimestampInsert)
+{
+    SQLRETURN ret;
+
+    SQLCHAR request[] = "INSERT INTO TestType(_key, timestampField) VALUES(?, ?)";
+
+    ret = SQLPrepare(stmt, request, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    int64_t key = 1;
+    ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    SQL_TIMESTAMP_STRUCT data;
+    data.year = 2017;
+    data.month = 1;
+    data.day = 13;
+    data.hour = 19;
+    data.minute = 54;
+    data.second = 1;
+    data.fraction = 987654321;
+
+    using ignite::impl::binary::BinaryUtils;
+    Timestamp expected = BinaryUtils::MakeTimestampGmt(data.year, data.month, data.day, data.hour,
+        data.minute, data.second, data.fraction);
+
+    SQLLEN lenInd = sizeof(data);
+    ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP, sizeof(data), 0, &data, sizeof(data), &lenInd);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    ret = SQLExecute(stmt);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    TestType out = testCache.Get(key);
+
+    BOOST_REQUIRE_EQUAL(out.timestampField.GetSeconds(), expected.GetSeconds());
+    BOOST_REQUIRE_EQUAL(out.timestampField.GetSecondFraction(), expected.GetSecondFraction());
+}
+
+BOOST_AUTO_TEST_CASE(TestTimeSelect)
+{
+    SQL_TIME_STRUCT ts;
+    ts.hour = 19;
+    ts.minute = 54;
+    ts.second = 1;
+
+    TestType in1;
+    in1.i32Field = 1;
+    in1.timestampField = impl::binary::BinaryUtils::MakeTimestampGmt(2017, 1, 13, ts.hour, ts.minute, ts.second);
+
+    testCache.Put(1, in1);
+
+    CheckSingleResult<SQL_TIME_STRUCT>(
+        "SELECT CAST(timestampField AS TIME) FROM TestType WHERE i32Field = 1", ts);
+
+    CheckSingleResult<int32_t>(
+        "SELECT i32Field FROM TestType WHERE CAST(timestampField AS TIME) = '19:54:01'", in1.i32Field);
+}
+
+BOOST_AUTO_TEST_CASE(TestTimeInsertToTimestamp)
+{
+    SQLRETURN ret;
+
+    SQLCHAR request[] = "INSERT INTO TestType(_key, timestampField) VALUES(?, ?)";
+
+    ret = SQLPrepare(stmt, request, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    int64_t key = 1;
+    ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_BIGINT, 0, 0, &key, 0, 0);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    SQL_TIME_STRUCT data = { 0 };
+    data.hour = 19;
+    data.minute = 54;
+    data.second = 1;
+
+    using ignite::impl::binary::BinaryUtils;
+    Timestamp expected = BinaryUtils::MakeTimestampGmt(1970, 1, 1, data.hour,
+        data.minute, data.second, 0);
+
+    SQLLEN lenInd = sizeof(data);
+    ret = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_TIME, SQL_TIMESTAMP, sizeof(data), 0, &data, sizeof(data), &lenInd);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    ret = SQLExecute(stmt);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    TestType out = testCache.Get(key);
+
+    BOOST_REQUIRE_EQUAL(out.timestampField.GetSeconds(), expected.GetSeconds());
+    BOOST_REQUIRE_EQUAL(out.timestampField.GetSecondFraction(), expected.GetSecondFraction());
+}
+
 BOOST_AUTO_TEST_SUITE_END()

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp b/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp
index 71c5f39..85979c8 100644
--- a/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp
+++ b/modules/platforms/cpp/odbc/src/app/application_data_buffer.cpp
@@ -45,7 +45,7 @@ namespace ignite
                 // No-op.
             }
 
-            ApplicationDataBuffer::ApplicationDataBuffer(type_traits::IgniteSqlType type, 
+            ApplicationDataBuffer::ApplicationDataBuffer(type_traits::IgniteSqlType type,
                 void* buffer, SqlLen buflen, SqlLen* reslen, int** offset) :
                 type(type),
                 buffer(buffer),
@@ -736,6 +736,20 @@ namespace ignite
                         break;
                     }
 
+                    case IGNITE_ODBC_C_TYPE_TTIME:
+                    {
+                        SQL_TIME_STRUCT* buffer = reinterpret_cast<SQL_TIME_STRUCT*>(dataPtr);
+
+                        buffer->hour = tmTime.tm_hour;
+                        buffer->minute = tmTime.tm_min;
+                        buffer->second = tmTime.tm_sec;
+
+                        if (resLenPtr)
+                            *resLenPtr = static_cast<SqlLen>(sizeof(SQL_TIME_STRUCT));
+
+                        break;
+                    }
+
                     case IGNITE_ODBC_C_TYPE_TTIMESTAMP:
                     {
                         SQL_TIMESTAMP_STRUCT* buffer = reinterpret_cast<SQL_TIMESTAMP_STRUCT*>(dataPtr);
@@ -856,6 +870,20 @@ namespace ignite
                         break;
                     }
 
+                    case IGNITE_ODBC_C_TYPE_TTIME:
+                    {
+                        SQL_TIME_STRUCT* buffer = reinterpret_cast<SQL_TIME_STRUCT*>(dataPtr);
+
+                        buffer->hour = tmTime.tm_hour;
+                        buffer->minute = tmTime.tm_min;
+                        buffer->second = tmTime.tm_sec;
+
+                        if (resLenPtr)
+                            *resLenPtr = static_cast<SqlLen>(sizeof(SQL_TIME_STRUCT));
+
+                        break;
+                    }
+
                     case IGNITE_ODBC_C_TYPE_TTIMESTAMP:
                     {
                         SQL_TIMESTAMP_STRUCT* buffer = reinterpret_cast<SQL_TIMESTAMP_STRUCT*>(dataPtr);
@@ -1080,7 +1108,7 @@ namespace ignite
                 return ApplyOffset(reslen);
             }
 
-            void* ApplicationDataBuffer::GetData() 
+            void* ApplicationDataBuffer::GetData()
             {
                 return ApplyOffset(buffer);
             }
@@ -1228,6 +1256,19 @@ namespace ignite
                         break;
                     }
 
+                    case IGNITE_ODBC_C_TYPE_TTIME:
+                    {
+                        const SQL_TIME_STRUCT* buffer = reinterpret_cast<const SQL_TIME_STRUCT*>(GetData());
+
+                        tmTime.tm_year = 70;
+                        tmTime.tm_mday = 1;
+                        tmTime.tm_hour = buffer->hour;
+                        tmTime.tm_min = buffer->minute;
+                        tmTime.tm_sec = buffer->second;
+
+                        break;
+                    }
+
                     case IGNITE_ODBC_C_TYPE_TTIMESTAMP:
                     {
                         const SQL_TIMESTAMP_STRUCT* buffer = reinterpret_cast<const SQL_TIMESTAMP_STRUCT*>(GetData());
@@ -1289,6 +1330,19 @@ namespace ignite
                         break;
                     }
 
+                    case IGNITE_ODBC_C_TYPE_TTIME:
+                    {
+                        const SQL_TIME_STRUCT* buffer = reinterpret_cast<const SQL_TIME_STRUCT*>(GetData());
+
+                        tmTime.tm_year = 70;
+                        tmTime.tm_mday = 1;
+                        tmTime.tm_hour = buffer->hour;
+                        tmTime.tm_min = buffer->minute;
+                        tmTime.tm_sec = buffer->second;
+
+                        break;
+                    }
+
                     case IGNITE_ODBC_C_TYPE_TTIMESTAMP:
                     {
                         const SQL_TIMESTAMP_STRUCT* buffer = reinterpret_cast<const SQL_TIMESTAMP_STRUCT*>(GetData());

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc/src/app/parameter.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/app/parameter.cpp b/modules/platforms/cpp/odbc/src/app/parameter.cpp
index 937ef58..ded2e4b 100644
--- a/modules/platforms/cpp/odbc/src/app/parameter.cpp
+++ b/modules/platforms/cpp/odbc/src/app/parameter.cpp
@@ -40,7 +40,7 @@ namespace ignite
                 // No-op.
             }
 
-            Parameter::Parameter(const ApplicationDataBuffer& buffer, int16_t sqlType, 
+            Parameter::Parameter(const ApplicationDataBuffer& buffer, int16_t sqlType,
                 size_t columnSize, int16_t decDigits) :
                 buffer(buffer),
                 sqlType(sqlType),
@@ -150,12 +150,14 @@ namespace ignite
                         break;
                     }
 
+                    case SQL_TYPE_DATE:
                     case SQL_DATE:
                     {
                         writer.WriteDate(buf.GetDate());
                         break;
                     }
 
+                    case SQL_TYPE_TIMESTAMP:
                     case SQL_TIMESTAMP:
                     {
                         writer.WriteTimestamp(buf.GetTimestamp());

http://git-wip-us.apache.org/repos/asf/ignite/blob/664dc88e/modules/platforms/cpp/odbc/src/config/connection_info.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/config/connection_info.cpp b/modules/platforms/cpp/odbc/src/config/connection_info.cpp
index ed76aab..a34d434 100644
--- a/modules/platforms/cpp/odbc/src/config/connection_info.cpp
+++ b/modules/platforms/cpp/odbc/src/config/connection_info.cpp
@@ -29,11 +29,11 @@
 
 #ifndef SQL_ASYNC_NOTIFICATION_NOT_CAPABLE
 #define SQL_ASYNC_NOTIFICATION_NOT_CAPABLE      0x00000000L
-#endif 
+#endif
 
 #ifndef SQL_ASYNC_NOTIFICATION_CAPABLE
 #define SQL_ASYNC_NOTIFICATION_CAPABLE          0x00000001L
-#endif 
+#endif
 
 namespace ignite
 {
@@ -93,7 +93,32 @@ namespace ignite
                     DBG_STR_CASE(SQL_SQL92_VALUE_EXPRESSIONS);
                     DBG_STR_CASE(SQL_STATIC_CURSOR_ATTRIBUTES1);
                     DBG_STR_CASE(SQL_STATIC_CURSOR_ATTRIBUTES2);
-                default: 
+                    DBG_STR_CASE(SQL_CONVERT_BIGINT);
+                    DBG_STR_CASE(SQL_CONVERT_BINARY);
+                    DBG_STR_CASE(SQL_CONVERT_BIT);
+                    DBG_STR_CASE(SQL_CONVERT_CHAR);
+                    DBG_STR_CASE(SQL_CONVERT_DATE);
+                    DBG_STR_CASE(SQL_CONVERT_DECIMAL);
+                    DBG_STR_CASE(SQL_CONVERT_DOUBLE);
+                    DBG_STR_CASE(SQL_CONVERT_FLOAT);
+                    DBG_STR_CASE(SQL_CONVERT_INTEGER);
+                    DBG_STR_CASE(SQL_CONVERT_LONGVARCHAR);
+                    DBG_STR_CASE(SQL_CONVERT_NUMERIC);
+                    DBG_STR_CASE(SQL_CONVERT_REAL);
+                    DBG_STR_CASE(SQL_CONVERT_SMALLINT);
+                    DBG_STR_CASE(SQL_CONVERT_TIME);
+                    DBG_STR_CASE(SQL_CONVERT_TIMESTAMP);
+                    DBG_STR_CASE(SQL_CONVERT_TINYINT);
+                    DBG_STR_CASE(SQL_CONVERT_VARBINARY);
+                    DBG_STR_CASE(SQL_CONVERT_VARCHAR);
+                    DBG_STR_CASE(SQL_CONVERT_LONGVARBINARY);
+                    DBG_STR_CASE(SQL_CONVERT_WCHAR);
+                    DBG_STR_CASE(SQL_CONVERT_INTERVAL_DAY_TIME);
+                    DBG_STR_CASE(SQL_CONVERT_INTERVAL_YEAR_MONTH);
+                    DBG_STR_CASE(SQL_CONVERT_WLONGVARCHAR);
+                    DBG_STR_CASE(SQL_CONVERT_WVARCHAR);
+                    DBG_STR_CASE(SQL_CONVERT_GUID);
+                default:
                     break;
                 }
                 return "<< UNKNOWN TYPE >>";
@@ -114,7 +139,7 @@ namespace ignite
                 strParams[SQL_DBMS_VER]        = "03.00";
 
 #ifdef SQL_DRIVER_VER
-                // Driver version. At a minimum, the version is of the form 
+                // Driver version. At a minimum, the version is of the form
                 // ##.##.####, where the first two digits are the major version,
                 // the next two digits are the minor version, and the last four
                 // digits are the release version.
@@ -122,7 +147,7 @@ namespace ignite
 #endif // SQL_DRIVER_VER
 
 #ifdef SQL_COLUMN_ALIAS
-                // A character string: "Y" if the data source supports column 
+                // A character string: "Y" if the data source supports column
                 // aliases; otherwise, "N".
                 strParams[SQL_COLUMN_ALIAS] = "Y";
 #endif // SQL_COLUMN_ALIAS
@@ -165,7 +190,7 @@ namespace ignite
 #endif // SQL_TABLE_TERM
 
 #ifdef SQL_SCHEMA_TERM
-                // A character string with the data source vendor's name for 
+                // A character string with the data source vendor's name for
                 // a schema; for example, "owner", "Authorization ID", or "Schema".
                 strParams[SQL_SCHEMA_TERM] = "schema";
 #endif // SQL_SCHEMA_TERM
@@ -191,9 +216,9 @@ namespace ignite
 
 #ifdef SQL_ASYNC_NOTIFICATION
                 // Indicates if the driver supports asynchronous notification.
-                // SQL_ASYNC_NOTIFICATION_CAPABLE  = Asynchronous execution 
+                // SQL_ASYNC_NOTIFICATION_CAPABLE  = Asynchronous execution
                 // notification is supported by the driver.
-                // SQL_ASYNC_NOTIFICATION_NOT_CAPABLE Asynchronous execution 
+                // SQL_ASYNC_NOTIFICATION_NOT_CAPABLE Asynchronous execution
                 // notification is not supported by the driver.
                 intParams[SQL_ASYNC_NOTIFICATION] = SQL_ASYNC_NOTIFICATION_NOT_CAPABLE;
 #endif // SQL_ASYNC_NOTIFICATION
@@ -204,7 +229,7 @@ namespace ignite
 #endif // SQL_GETDATA_EXTENSIONS
 
 #ifdef SQL_ODBC_INTERFACE_CONFORMANCE
-                // Indicates the level of the ODBC 3.x interface that the driver 
+                // Indicates the level of the ODBC 3.x interface that the driver
                 // complies with.
                 intParams[SQL_ODBC_INTERFACE_CONFORMANCE] = SQL_OIC_CORE;
 #endif // SQL_ODBC_INTERFACE_CONFORMANCE
@@ -226,7 +251,7 @@ namespace ignite
 #endif // SQL_SCHEMA_USAGE
 
 #ifdef SQL_MAX_IDENTIFIER_LEN
-                // Indicates the maximum size in characters that the data source 
+                // Indicates the maximum size in characters that the data source
                 // supports for user-defined names.
                 intParams[SQL_MAX_IDENTIFIER_LEN] = 128;
 #endif // SQL_MAX_IDENTIFIER_LEN
@@ -240,7 +265,7 @@ namespace ignite
 #ifdef SQL_NUMERIC_FUNCTIONS
                 // Bitmask enumerating the scalar numeric functions supported by
                 // the driver and associated data source.
-                intParams[SQL_NUMERIC_FUNCTIONS] = SQL_FN_NUM_ABS | SQL_FN_NUM_ACOS | SQL_FN_NUM_ASIN | 
+                intParams[SQL_NUMERIC_FUNCTIONS] = SQL_FN_NUM_ABS | SQL_FN_NUM_ACOS | SQL_FN_NUM_ASIN |
                     SQL_FN_NUM_ATAN | SQL_FN_NUM_ATAN2 | SQL_FN_NUM_CEILING | SQL_FN_NUM_COS | SQL_FN_NUM_COT |
                     SQL_FN_NUM_EXP | SQL_FN_NUM_FLOOR | SQL_FN_NUM_LOG | SQL_FN_NUM_MOD | SQL_FN_NUM_SIGN |
                     SQL_FN_NUM_SIN | SQL_FN_NUM_SQRT | SQL_FN_NUM_TAN | SQL_FN_NUM_PI | SQL_FN_NUM_RAND |
@@ -270,7 +295,7 @@ namespace ignite
 #endif // SQL_TIMEDATE_FUNCTIONS
 
 #ifdef SQL_TIMEDATE_ADD_INTERVALS
-                // Bitmask enumerating timestamp intervals supported by the driver 
+                // Bitmask enumerating timestamp intervals supported by the driver
                 // and associated data source for the TIMESTAMPADD scalar function.
                 intParams[SQL_TIMEDATE_ADD_INTERVALS] = 0;
 #endif // SQL_TIMEDATE_ADD_INTERVALS
@@ -296,11 +321,11 @@ namespace ignite
 #ifdef SQL_CONVERT_FUNCTIONS
                 // Bitmask enumerating the scalar conversion functions supported
                 // by the driver and associated data source.
-                intParams[SQL_CONVERT_FUNCTIONS] = 0;
+                intParams[SQL_CONVERT_FUNCTIONS] = SQL_FN_CVT_CONVERT | SQL_FN_CVT_CAST;
 #endif // SQL_CONVERT_FUNCTIONS
 
 #ifdef SQL_OJ_CAPABILITIES
-                // Bitmask enumerating the types of outer joins supported by the 
+                // Bitmask enumerating the types of outer joins supported by the
                 // driver and data source.
                 intParams[SQL_OJ_CAPABILITIES] = SQL_OJ_LEFT | SQL_OJ_NOT_ORDERED | SQL_OJ_ALL_COMPARISON_OPS;
 #endif // SQL_OJ_CAPABILITIES
@@ -330,7 +355,7 @@ namespace ignite
 #ifdef SQL_SQL92_VALUE_EXPRESSIONS
                 // Bitmask enumerating the value expressions supported,
                 // as defined in SQL-92.
-                intParams[SQL_SQL92_VALUE_EXPRESSIONS] = SQL_SVE_CASE | 
+                intParams[SQL_SQL92_VALUE_EXPRESSIONS] = SQL_SVE_CASE |
                     SQL_SVE_CAST | SQL_SVE_COALESCE | SQL_SVE_NULLIF;
 #endif // SQL_SQL92_VALUE_EXPRESSIONS
 
@@ -366,6 +391,207 @@ namespace ignite
                 intParams[SQL_STATIC_CURSOR_ATTRIBUTES2] = 0;
 #endif //SQL_STATIC_CURSOR_ATTRIBUTES2
 
+#ifdef SQL_CONVERT_BIGINT
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type BIGINT
+                intParams[SQL_CONVERT_BIGINT] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_WCHAR |
+                    SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR | SQL_CVT_NUMERIC | SQL_CVT_BIT |
+                    SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER | SQL_CVT_BIGINT |
+                    SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_BIGINT
+
+#ifdef SQL_CONVERT_BINARY
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type BINARY
+                intParams[SQL_CONVERT_BINARY] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL |
+                    SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL |
+                    SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY |
+                    SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_BINARY
+
+#ifdef SQL_CONVERT_BIT
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type BIT
+                intParams[SQL_CONVERT_BIT] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR | SQL_CVT_NUMERIC |
+                    SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER | SQL_CVT_BIGINT;
+#endif //SQL_CONVERT_BIT
+
+#ifdef SQL_CONVERT_CHAR
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type CHAR
+                intParams[SQL_CONVERT_CHAR] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER |
+                    SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_CHAR
+
+#ifdef SQL_CONVERT_VARCHAR
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type VARCHAR
+                intParams[SQL_CONVERT_VARCHAR] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER |
+                    SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_VARCHAR
+
+#ifdef SQL_CONVERT_LONGVARCHAR
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type LONGVARCHAR
+                intParams[SQL_CONVERT_LONGVARCHAR] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER |
+                    SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_LONGVARCHAR
+
+#ifdef SQL_CONVERT_WCHAR
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type WCHAR
+                intParams[SQL_CONVERT_WCHAR] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER |
+                    SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_WCHAR
+
+#ifdef SQL_CONVERT_WVARCHAR
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type WVARCHAR
+                intParams[SQL_CONVERT_WVARCHAR] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER |
+                    SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_WVARCHAR
+
+#ifdef SQL_CONVERT_WLONGVARCHAR
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type WLONGVARCHAR
+                intParams[SQL_CONVERT_WLONGVARCHAR] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER |
+                    SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_WLONGVARCHAR
+
+#ifdef SQL_CONVERT_DATE
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type DATE
+                intParams[SQL_CONVERT_DATE] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY |
+                    SQL_CVT_DATE | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_DATE
+
+#ifdef SQL_CONVERT_DECIMAL
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type DECIMAL
+                intParams[SQL_CONVERT_DECIMAL] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER | SQL_CVT_BIGINT |
+                    SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_DECIMAL
+
+#ifdef SQL_CONVERT_DOUBLE
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type DOUBLE
+                intParams[SQL_CONVERT_DOUBLE] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER |
+                    SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_DOUBLE
+
+#ifdef SQL_CONVERT_FLOAT
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type FLOAT
+                intParams[SQL_CONVERT_FLOAT] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT | SQL_CVT_INTEGER |
+                    SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_FLOAT
+
+#ifdef SQL_CONVERT_REAL
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type REAL
+                intParams[SQL_CONVERT_REAL] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT |
+                    SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE |
+                    SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_REAL
+
+#ifdef SQL_CONVERT_INTEGER
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type INTEGER
+                intParams[SQL_CONVERT_INTEGER] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT |
+                    SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY |
+                    SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_INTEGER
+
+#ifdef SQL_CONVERT_NUMERIC
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type NUMERIC
+                intParams[SQL_CONVERT_NUMERIC] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT |
+                    SQL_CVT_SMALLINT | SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL |
+                    SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_NUMERIC
+
+#ifdef SQL_CONVERT_SMALLINT
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type SMALLINT
+                intParams[SQL_CONVERT_SMALLINT] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT |
+                    SQL_CVT_SMALLINT | SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL |
+                    SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_BINARY | SQL_CVT_VARBINARY |
+                    SQL_CVT_LONGVARBINARY | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_SMALLINT
+
+#ifdef SQL_CONVERT_TINYINT
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type TINYINT
+                intParams[SQL_CONVERT_TINYINT] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT |
+                    SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE |
+                    SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_TINYINT
+
+#ifdef SQL_CONVERT_TIME
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type TIME
+                intParams[SQL_CONVERT_TIME] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY |
+                    SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_TIME
+
+#ifdef SQL_CONVERT_TIMESTAMP
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type TIMESTAMP
+                intParams[SQL_CONVERT_TIMESTAMP] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_BINARY |
+                    SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP;
+#endif //SQL_CONVERT_TIMESTAMP
+
+#ifdef SQL_CONVERT_VARBINARY
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type VARBINARY
+                intParams[SQL_CONVERT_VARBINARY] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT |
+                    SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE |
+                    SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_DATE |
+                    SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_VARBINARY
+
+#ifdef SQL_CONVERT_LONGVARBINARY
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type LONGVARBINARY
+                intParams[SQL_CONVERT_LONGVARBINARY] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_SMALLINT |
+                    SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE |
+                    SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_DATE |
+                    SQL_CVT_TIME | SQL_CVT_TIMESTAMP | SQL_CVT_GUID;
+#endif //SQL_CONVERT_LONGVARBINARY
+
+#ifdef SQL_CONVERT_GUID
+                // Bitmask indicates the conversions supported by the CONVERT scalar function for target type GUID
+                intParams[SQL_CONVERT_GUID] = SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR |
+                    SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR | SQL_CVT_WVARCHAR |
+                    SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_GUID;
+#endif //SQL_CONVERT_GUID
+
                 //======================= Short Params ========================
 #ifdef SQL_MAX_CONCURRENT_ACTIVITIES
                 // The maximum number of active statements that the driver can
@@ -409,10 +635,10 @@ namespace ignite
 
                 StringInfoMap::const_iterator itStr = strParams.find(type);
 
-                if (itStr != strParams.end()) 
+                if (itStr != strParams.end())
                 {
                     unsigned short strlen = static_cast<short>(
-                        utility::CopyStringToBuffer(itStr->second, 
+                        utility::CopyStringToBuffer(itStr->second,
                             reinterpret_cast<char*>(buf), buflen));
 
                     if (reslen)


[5/8] ignite git commit: IGNITE-4487 Fixed NPE on query execution during concurrent cache destroy. This closes #1388

Posted by pt...@apache.org.
IGNITE-4487 Fixed NPE on query execution during concurrent cache destroy. This closes #1388


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/177d7f49
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/177d7f49
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/177d7f49

Branch: refs/heads/ignite-2.0
Commit: 177d7f49934e24e85472a8e44a641c4b57a25914
Parents: 7b711a3
Author: Alexander Menshikov <sh...@gmail.com>
Authored: Wed Jan 18 18:33:45 2017 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Wed Jan 18 18:33:45 2017 +0300

----------------------------------------------------------------------
 .../cache/query/GridCacheQueryAdapter.java      |   8 ++
 .../IgniteCacheQueryCacheDestroySelfTest.java   | 142 +++++++++++++++++++
 .../IgniteCacheQuerySelfTestSuite.java          |   2 +
 3 files changed, 152 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/177d7f49/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryAdapter.java
index 1fe263d..3ecacf8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryAdapter.java
@@ -34,6 +34,7 @@ import org.apache.ignite.cache.query.Query;
 import org.apache.ignite.cache.query.QueryMetrics;
 import org.apache.ignite.cluster.ClusterGroup;
 import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.cluster.ClusterTopologyException;
 import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterGroupEmptyCheckedException;
@@ -666,6 +667,13 @@ public class GridCacheQueryAdapter<T> implements CacheQuery<T> {
 
             nodes = fallbacks(cctx.discovery().topologyVersionEx());
 
+            if (F.isEmpty(nodes))
+                throw new ClusterTopologyException("Failed to execute the query " +
+                    "(all affinity nodes left the grid) [cache=" + cctx.name() +
+                    ", qry=" + qry +
+                    ", startTopVer=" + cctx.versions().last().topologyVersion() +
+                    ", curTopVer=" + qryMgr.queryTopologyVersion().topologyVersion() + ']');
+
             init();
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/177d7f49/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/IgniteCacheQueryCacheDestroySelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/IgniteCacheQueryCacheDestroySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/IgniteCacheQueryCacheDestroySelfTest.java
new file mode 100644
index 0000000..dc104ff
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/IgniteCacheQueryCacheDestroySelfTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.query;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.cache.Cache;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMemoryMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.CacheRebalanceMode;
+import org.apache.ignite.cache.CacheWriteSynchronizationMode;
+import org.apache.ignite.cache.query.QueryCursor;
+import org.apache.ignite.cache.query.ScanQuery;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * The test for the destruction of the cache during the execution of the query
+ */
+public class IgniteCacheQueryCacheDestroySelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final String CACHE_NAME = "cache";
+
+    /** */
+    public static final int GRID_CNT = 3;
+
+    /**
+     * The main test code.
+     */
+    public void testQueue() throws Throwable {
+        startGridsMultiThreaded(GRID_CNT);
+
+        Ignite ig = ignite(0);
+
+        ig.getOrCreateCache(cacheConfiguration());
+
+        final AtomicBoolean stop = new AtomicBoolean();
+        final AtomicReference<Exception> npe = new AtomicReference<>();
+
+        IgniteInternalFuture<Long> fut = GridTestUtils.runMultiThreadedAsync(new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                try {
+                    while (!stop.get())
+                        runQuery();
+                }
+                catch (Exception e) {
+                    NullPointerException npe0 = X.cause(e, NullPointerException.class);
+
+                    if (npe0 != null)
+                        npe.compareAndSet(null, npe0);
+                    else
+                        info("Expected exception: " + e);
+                }
+
+                return null;
+            }
+        }, 6, "query-runner");
+
+        U.sleep(500);
+
+        ig.destroyCache(CACHE_NAME);
+
+        stop.set(true);
+
+        fut.get();
+
+        assertNull(npe.get());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    private void runQuery() throws Exception {
+        ScanQuery<String, String> scanQuery = new ScanQuery<String, String>()
+            .setLocal(true)
+            .setFilter(new IgniteBiPredicate<String, String>() {
+                @Override public boolean apply(String key, String p) {
+                    return key != null && key.isEmpty();
+                }
+            });
+
+        Ignite ignite = ignite(ThreadLocalRandom.current().nextInt(GRID_CNT));
+
+        IgniteCache<String, String> example = ignite.cache(CACHE_NAME);
+
+        for (int partition : ignite.affinity(CACHE_NAME).primaryPartitions(ignite.cluster().localNode())) {
+            scanQuery.setPartition(partition);
+
+            try (QueryCursor cursor = example.query(scanQuery)) {
+                for (Object p : cursor) {
+                    String value = (String) ((Cache.Entry)p).getValue();
+
+                    assertNotNull(value);
+                }
+            }
+        }
+    }
+
+    /**
+     * @return Cache configuration for this test.
+     */
+    private CacheConfiguration cacheConfiguration() {
+        CacheConfiguration cfg = new CacheConfiguration(CACHE_NAME);
+
+        cfg.setAtomicityMode(CacheAtomicityMode.ATOMIC)
+            .setCacheMode(CacheMode.PARTITIONED)
+            .setMemoryMode(CacheMemoryMode.OFFHEAP_TIERED)
+            .setRebalanceMode(CacheRebalanceMode.SYNC)
+            .setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC)
+            .setRebalanceThrottle(100)
+            .setRebalanceBatchSize(2 * 1024 * 1024)
+            .setBackups(1)
+            .setEagerTtl(false);
+
+        return cfg;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/177d7f49/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 1e98eb5..b5e4078 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
@@ -92,6 +92,7 @@ import org.apache.ignite.internal.processors.cache.local.IgniteCacheLocalQueryCa
 import org.apache.ignite.internal.processors.cache.local.IgniteCacheLocalQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.query.GridCacheQueryTransformerSelfTest;
 import org.apache.ignite.internal.processors.cache.query.GridCacheSwapScanQuerySelfTest;
+import org.apache.ignite.internal.processors.cache.query.IgniteCacheQueryCacheDestroySelfTest;
 import org.apache.ignite.internal.processors.cache.query.IndexingSpiQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.query.IndexingSpiQueryTxSelfTest;
 import org.apache.ignite.internal.processors.query.IgniteSqlSchemaIndexingTest;
@@ -238,6 +239,7 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite {
         suite.addTestSuite(CacheQueryNewClientSelfTest.class);
         suite.addTestSuite(CacheOffheapBatchIndexingSingleTypeTest.class);
         suite.addTestSuite(CacheSqlQueryValueCopySelfTest.class);
+        suite.addTestSuite(IgniteCacheQueryCacheDestroySelfTest.class);
 
         return suite;
     }


[2/8] ignite git commit: IGNITE-4045 .NET: Support DML API

Posted by pt...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
index 08789b6..ce9fcf6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
@@ -157,8 +157,6 @@
         {
             IgniteArgumentCheck.NotNull(configuration, "configuration");
 
-            CopyLocalProperties(configuration);
-
             using (var stream = IgniteManager.Memory.Allocate().GetStream())
             {
                 var marsh = new Marshaller(configuration.BinaryConfiguration);
@@ -171,6 +169,8 @@
 
                 ReadCore(marsh.StartUnmarshal(stream));
             }
+
+            CopyLocalProperties(configuration);
         }
 
         /// <summary>
@@ -255,12 +255,37 @@
                 writer.WriteBoolean(false);
 
             // Binary config
-            var isCompactFooterSet = BinaryConfiguration != null && BinaryConfiguration.CompactFooterInternal != null;
+            if (BinaryConfiguration != null)
+            {
+                writer.WriteBoolean(true);
 
-            writer.WriteBoolean(isCompactFooterSet);
+                if (BinaryConfiguration.CompactFooterInternal != null)
+                {
+                    writer.WriteBoolean(true);
+                    writer.WriteBoolean(BinaryConfiguration.CompactFooter);
+                }
+                else
+                {
+                    writer.WriteBoolean(false);
+                }
+
+                // Send only descriptors with non-null EqualityComparer to preserve old behavior where
+                // remote nodes can have no BinaryConfiguration.
+                var types = writer.Marshaller.GetUserTypeDescriptors().Where(x => x.EqualityComparer != null).ToList();
+
+                writer.WriteInt(types.Count);
 
-            if (isCompactFooterSet)
-                writer.WriteBoolean(BinaryConfiguration.CompactFooter);
+                foreach (var type in types)
+                {
+                    writer.WriteString(BinaryUtils.SimpleTypeName(type.TypeName));
+                    writer.WriteBoolean(type.IsEnum);
+                    BinaryEqualityComparerSerializer.Write(writer, type.EqualityComparer);
+                }
+            }
+            else
+            {
+                writer.WriteBoolean(false);
+            }
 
             // User attributes
             var attrs = UserAttributes;
@@ -361,7 +386,28 @@
             if (r.ReadBoolean())
             {
                 BinaryConfiguration = BinaryConfiguration ?? new BinaryConfiguration();
-                BinaryConfiguration.CompactFooter = r.ReadBoolean();
+
+                if (r.ReadBoolean())
+                    BinaryConfiguration.CompactFooter = r.ReadBoolean();
+
+                var typeCount = r.ReadInt();
+
+                if (typeCount > 0)
+                {
+                    var types = new List<BinaryTypeConfiguration>(typeCount);
+
+                    for (var i = 0; i < typeCount; i++)
+                    {
+                        types.Add(new BinaryTypeConfiguration
+                        {
+                            TypeName = r.ReadString(),
+                            IsEnum = r.ReadBoolean(),
+                            EqualityComparer = BinaryEqualityComparerSerializer.Read(r)
+                        });
+                    }
+
+                    BinaryConfiguration.TypeConfigurations = types;
+                }
             }
 
             // User attributes
@@ -402,17 +448,15 @@
         /// <param name="binaryReader">The binary reader.</param>
         private void Read(BinaryReader binaryReader)
         {
-            var r = binaryReader;
-
-            CopyLocalProperties(r.Marshaller.Ignite.Configuration);
+            ReadCore(binaryReader);
 
-            ReadCore(r);
+            CopyLocalProperties(binaryReader.Marshaller.Ignite.Configuration);
 
             // Misc
-            IgniteHome = r.ReadString();
+            IgniteHome = binaryReader.ReadString();
 
-            JvmInitialMemoryMb = (int) (r.ReadLong()/1024/2014);
-            JvmMaxMemoryMb = (int) (r.ReadLong()/1024/2014);
+            JvmInitialMemoryMb = (int) (binaryReader.ReadLong()/1024/2014);
+            JvmMaxMemoryMb = (int) (binaryReader.ReadLong()/1024/2014);
 
             // Local data (not from reader)
             JvmDllPath = Process.GetCurrentProcess().Modules.OfType<ProcessModule>()
@@ -426,9 +470,16 @@
         private void CopyLocalProperties(IgniteConfiguration cfg)
         {
             GridName = cfg.GridName;
-            BinaryConfiguration = cfg.BinaryConfiguration == null
-                ? null
-                : new BinaryConfiguration(cfg.BinaryConfiguration);
+
+            if (BinaryConfiguration != null && cfg.BinaryConfiguration != null)
+            {
+                BinaryConfiguration.MergeTypes(cfg.BinaryConfiguration);
+            }
+            else if (cfg.BinaryConfiguration != null)
+            {
+                BinaryConfiguration = new BinaryConfiguration(cfg.BinaryConfiguration);
+            }
+            
             JvmClasspath = cfg.JvmClasspath;
             JvmOptions = cfg.JvmOptions;
             Assemblies = cfg.Assemblies;

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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 b35527d..d54a200 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
@@ -152,6 +152,20 @@
                                                             </xs:attribute>
                                                         </xs:complexType>
                                                     </xs:element>
+                                                    <xs:element name="equalityComparer" minOccurs="0">
+                                                        <xs:annotation>
+                                                            <xs:documentation>
+                                                                Equality comparer to compute hash codes and compare objects in IBinaryObject form.
+                                                            </xs:documentation>
+                                                        </xs:annotation>
+                                                        <xs:complexType>
+                                                            <xs:attribute name="type" type="xs:string" use="required">
+                                                                <xs:annotation>
+                                                                    <xs:documentation>Assembly-qualified type name.</xs:documentation>
+                                                                </xs:annotation>
+                                                            </xs:attribute>
+                                                        </xs:complexType>
+                                                    </xs:element>
                                                 </xs:all>
                                                 <xs:attribute name="typeName" type="xs:string">
                                                     <xs:annotation>
@@ -297,6 +311,11 @@
                                                                                             <xs:documentation>Java field type name.</xs:documentation>
                                                                                         </xs:annotation>
                                                                                     </xs:attribute>
+                                                                                    <xs:attribute name="isKeyField" type="xs:boolean">
+                                                                                        <xs:annotation>
+                                                                                            <xs:documentation>Indicates whether this field belongs to the cache key.</xs:documentation>
+                                                                                        </xs:annotation>
+                                                                                    </xs:attribute>
                                                                                 </xs:complexType>
                                                                             </xs:element>
                                                                         </xs:sequence>

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs
index 3d55acd..fa7cf6c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs
@@ -81,7 +81,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 throw new IgniteException("Type is not binary (add it to BinaryConfiguration): " + 
                     type.FullName);
 
-            return Builder0(null, BinaryFromDescriptor(desc), desc);
+            return Builder0(null, null, desc);
         }
 
         /** <inheritDoc /> */
@@ -91,7 +91,7 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             IBinaryTypeDescriptor desc = _marsh.GetDescriptor(typeName);
             
-            return Builder0(null, BinaryFromDescriptor(desc), desc);
+            return Builder0(null, null, desc);
         }
 
         /** <inheritDoc /> */
@@ -182,30 +182,6 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
-        /// Create empty binary object from descriptor.
-        /// </summary>
-        /// <param name="desc">Descriptor.</param>
-        /// <returns>Empty binary object.</returns>
-        private BinaryObject BinaryFromDescriptor(IBinaryTypeDescriptor desc)
-        {
-            const int len = BinaryObjectHeader.Size;
-
-            var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None;
-
-            if (_marsh.CompactFooter && desc.UserType)
-                flags |= BinaryObjectHeader.Flag.CompactFooter;
-
-            var hdr = new BinaryObjectHeader(desc.TypeId, 0, len, 0, len, flags);
-
-            using (var stream = new BinaryHeapStream(len))
-            {
-                BinaryObjectHeader.Write(hdr, stream, 0);
-
-                return new BinaryObject(_marsh, stream.InternalArray, 0, hdr);
-            }
-        }
-
-        /// <summary>
         /// Internal builder creation routine.
         /// </summary>
         /// <param name="parent">Parent builder.</param>

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs
new file mode 100644
index 0000000..aa4795e
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs
@@ -0,0 +1,99 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// Reads and writes <see cref="IBinaryEqualityComparer"/>.
+    /// </summary>
+    internal static class BinaryEqualityComparerSerializer
+    {
+        /// <summary>
+        /// SwapSpace type.
+        /// </summary>
+        private enum Type : byte
+        {
+            None = 0,
+            Array = 1,
+            Field = 2
+        }
+
+        /// <summary>
+        /// Writes an instance.
+        /// </summary>
+        public static void Write(IBinaryRawWriter writer, IBinaryEqualityComparer comparer)
+        {
+            if (comparer == null)
+            {
+                writer.WriteByte((byte) Type.None);
+                return;
+            }
+
+            var arrCmp = comparer as BinaryArrayEqualityComparer;
+
+            if (arrCmp != null)
+            {
+                writer.WriteByte((byte) Type.Array);
+                return;
+            }
+
+            var fieldCmp = (BinaryFieldEqualityComparer) comparer;
+
+            writer.WriteByte((byte) Type.Field);
+
+            fieldCmp.Validate();
+
+            writer.WriteInt(fieldCmp.FieldNames.Count);
+
+            foreach (var field in fieldCmp.FieldNames)
+                writer.WriteString(field);
+        }
+
+        /// <summary>
+        /// Reads an instance.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        /// <returns></returns>
+        public static IEqualityComparer<IBinaryObject> Read(IBinaryRawReader reader)
+        {
+            var type = (Type) reader.ReadByte();
+
+            switch (type)
+            {
+                case Type.None:
+                    return null;
+
+                case Type.Array:
+                    return new BinaryArrayEqualityComparer();
+
+                case Type.Field:
+                    return new BinaryFieldEqualityComparer
+                    {
+                        FieldNames = Enumerable.Range(0, reader.ReadInt()).Select(x => reader.ReadString()).ToArray()
+                    };
+
+                default:
+                    throw new ArgumentOutOfRangeException();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFieldEqualityComparer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFieldEqualityComparer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFieldEqualityComparer.cs
new file mode 100644
index 0000000..433657a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFieldEqualityComparer.cs
@@ -0,0 +1,138 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.IO;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+    using Apache.Ignite.Core.Impl.Common;
+
+    /// <summary>
+    /// Uses a set of binary object fields to calculate hash code and check equality.
+    /// Not implemented for now, will be done as part of IGNITE-4397.
+    /// </summary>
+    internal class BinaryFieldEqualityComparer : IEqualityComparer<IBinaryObject>, IBinaryEqualityComparer
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BinaryFieldEqualityComparer"/> class.
+        /// </summary>
+        public BinaryFieldEqualityComparer()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BinaryFieldEqualityComparer"/> class.
+        /// </summary>
+        /// <param name="fieldNames">The field names for comparison.</param>
+        public BinaryFieldEqualityComparer(params string[] fieldNames)
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(fieldNames, "fieldNames");
+
+            FieldNames = fieldNames;
+        }
+
+        /// <summary>
+        /// Gets or sets the field names to be used for equality comparison.
+        /// </summary>
+        public ICollection<string> FieldNames { get; set; }
+
+        /// <summary>
+        /// Determines whether the specified objects are equal.
+        /// </summary>
+        /// <param name="x">The first object to compare.</param>
+        /// <param name="y">The second object to compare.</param>
+        /// <returns>
+        /// true if the specified objects are equal; otherwise, false.
+        /// </returns>
+        public bool Equals(IBinaryObject x, IBinaryObject y)
+        {
+            throw new NotSupportedException(GetType() + "is not intended for direct usage.");
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <param name="obj">The object.</param>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public int GetHashCode(IBinaryObject obj)
+        {
+            throw new NotSupportedException(GetType() + "is not intended for direct usage.");
+        }
+
+        /** <inheritdoc /> */
+        int IBinaryEqualityComparer.GetHashCode(IBinaryStream stream, int startPos, int length,
+            BinaryObjectSchemaHolder schema, int schemaId, Marshaller marshaller, IBinaryTypeDescriptor desc)
+        {
+            Debug.Assert(stream != null);
+            Debug.Assert(startPos >= 0);
+            Debug.Assert(length >= 0);
+            Debug.Assert(schema != null);
+            Debug.Assert(marshaller != null);
+            Debug.Assert(desc != null);
+
+            Validate();
+
+            stream.Flush();
+
+            // Preserve stream position.
+            var pos = stream.Position;
+
+            var reader = marshaller.StartUnmarshal(stream, BinaryMode.ForceBinary);
+            var fields = schema.GetFullSchema(schemaId);
+
+            int hash = 0;
+
+            foreach (var fieldName in FieldNames)
+            {
+                int fieldId = BinaryUtils.FieldId(desc.TypeId, fieldName, desc.NameMapper, desc.IdMapper);
+                int fieldHash = 0;  // Null (missing) field hash code is 0.
+                int fieldPos;
+
+                if (fields.TryGetValue(fieldId, out fieldPos))
+                {
+                    stream.Seek(startPos + fieldPos - BinaryObjectHeader.Size, SeekOrigin.Begin);
+                    var fieldVal = reader.Deserialize<object>();
+                    fieldHash = fieldVal != null ? fieldVal.GetHashCode() : 0;
+                }
+
+                hash = 31 * hash + fieldHash;
+            }
+
+            // Restore stream position.
+            stream.Seek(pos, SeekOrigin.Begin);
+
+            return hash;
+        }
+
+        /// <summary>
+        /// Validates this instance.
+        /// </summary>
+        public void Validate()
+        {
+            if (FieldNames == null || FieldNames.Count == 0)
+                throw new IgniteException("BinaryFieldEqualityComparer.FieldNames can not be null or empty.");
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
index 6dc5d4d..d88e7a9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
@@ -20,6 +20,7 @@ namespace Apache.Ignite.Core.Impl.Binary
     using System;
     using System.Collections.Generic;
     using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Impl.Binary.Structure;
 
     /// <summary>
@@ -66,6 +67,9 @@ namespace Apache.Ignite.Core.Impl.Binary
         /** Enum flag. */
         private readonly bool _isEnum;
 
+        /** Comparer. */
+        private readonly IBinaryEqualityComparer _equalityComparer;
+
         /// <summary>
         /// Constructor.
         /// </summary>
@@ -79,6 +83,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param>
         /// <param name="affKeyFieldName">Affinity field key name.</param>
         /// <param name="isEnum">Enum flag.</param>
+        /// <param name="comparer">Equality comparer.</param>
         public BinaryFullTypeDescriptor(
             Type type, 
             int typeId, 
@@ -89,7 +94,8 @@ namespace Apache.Ignite.Core.Impl.Binary
             IBinarySerializerInternal serializer, 
             bool keepDeserialized, 
             string affKeyFieldName,
-            bool isEnum)
+            bool isEnum, 
+            IEqualityComparer<IBinaryObject> comparer)
         {
             _type = type;
             _typeId = typeId;
@@ -101,6 +107,13 @@ namespace Apache.Ignite.Core.Impl.Binary
             _keepDeserialized = keepDeserialized;
             _affKeyFieldName = affKeyFieldName;
             _isEnum = isEnum;
+
+            _equalityComparer = comparer as IBinaryEqualityComparer;
+
+            if (comparer != null && _equalityComparer == null)
+                throw new IgniteException(string.Format("Unsupported IEqualityComparer<IBinaryObject> " +
+                                                        "implementation: {0}. Only predefined implementations " +
+                                                        "are supported.", comparer.GetType()));
         }
 
         /// <summary>
@@ -181,6 +194,12 @@ namespace Apache.Ignite.Core.Impl.Binary
             get { return _isEnum; }
         }
 
+        /** <inheritdoc/> */
+        public IBinaryEqualityComparer EqualityComparer
+        {
+            get { return _equalityComparer; }
+        }
+
         /** <inheritDoc /> */
         public BinaryStructure WriterTypeStructure
         {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
index 39a2f8b..0a14bd2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
@@ -195,6 +195,14 @@ namespace Apache.Ignite.Core.Impl.Binary
             get { return _offset; }
         }
 
+        /// <summary>
+        /// Gets the header.
+        /// </summary>
+        public BinaryObjectHeader Header
+        {
+            get { return _header; }
+        }
+
         public bool TryGetFieldPosition(string fieldName, out int pos)
         {
             var desc = _marsh.GetDescriptor(true, _header.TypeId);
@@ -244,6 +252,14 @@ namespace Apache.Ignite.Core.Impl.Binary
                 if (_data == that._data && _offset == that._offset)
                     return true;
 
+                if (TypeId != that.TypeId)
+                    return false;
+
+                var desc = _marsh.GetDescriptor(true, TypeId);
+
+                if (desc != null && desc.EqualityComparer != null)
+                    return desc.EqualityComparer.Equals(this, that);
+
                 // 1. Check headers
                 if (_header == that._header)
                 {
@@ -266,8 +282,21 @@ namespace Apache.Ignite.Core.Impl.Binary
                         object fieldVal = GetField<object>(field.Value, null);
                         object thatFieldVal = that.GetField<object>(that._fields[field.Key], null);
 
-                        if (!Equals(fieldVal, thatFieldVal))
+                        var arr = fieldVal as Array;
+                        var thatArr = thatFieldVal as Array;
+
+                        if (arr != null && thatArr != null && arr.Length == thatArr.Length)
+                        {
+                            for (var i = 0; i < arr.Length; i++)
+                            {
+                                if (!Equals(arr.GetValue(i), thatArr.GetValue(i)))
+                                    return false;
+                            }
+                        }
+                        else if (!Equals(fieldVal, thatFieldVal))
+                        {
                             return false;
+                        }
                     }
 
                     // 4. Check if objects have the same raw data.

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
index 1626a2d..db18638 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
@@ -55,7 +55,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         private IDictionary<int, BinaryBuilderField> _cache;
 
         /** Hash code. */
-        private int _hashCode;
+        private int? _hashCode;
         
         /** Current context. */
         private Context _ctx;
@@ -87,15 +87,21 @@ namespace Apache.Ignite.Core.Impl.Binary
             BinaryObject obj, IBinaryTypeDescriptor desc)
         {
             Debug.Assert(binary != null);
-            Debug.Assert(obj != null);
             Debug.Assert(desc != null);
 
             _binary = binary;
             _parent = parent ?? this;
-            _obj = obj;
             _desc = desc;
 
-            _hashCode = obj.GetHashCode();
+            if (obj != null)
+            {
+                _obj = obj;
+                _hashCode = obj.GetHashCode();
+            }
+            else
+            {
+                _obj = BinaryFromDescriptor(desc);
+            }
         }
 
         /** <inheritDoc /> */
@@ -508,7 +514,7 @@ namespace Apache.Ignite.Core.Impl.Binary
             BinaryHeapStream inStream,
             BinaryHeapStream outStream,
             IBinaryTypeDescriptor desc,
-            int hashCode, 
+            int? hashCode, 
             IDictionary<string, BinaryBuilderField> vals)
         {
             // Set correct builder to writer frame.
@@ -578,7 +584,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="vals">Values to be replaced.</param>
         /// <returns>Mutated object.</returns>
         private void Mutate0(Context ctx, BinaryHeapStream inStream, IBinaryStream outStream,
-            bool changeHash, int hash, IDictionary<int, BinaryBuilderField> vals)
+            bool changeHash, int? hash, IDictionary<int, BinaryBuilderField> vals)
         {
             int inStartPos = inStream.Position;
             int outStartPos = outStream.Position;
@@ -730,7 +736,25 @@ namespace Apache.Ignite.Core.Impl.Binary
 
                             var outLen = outStream.Position - outStartPos;
 
-                            var outHash = changeHash ? hash : inHeader.HashCode;
+                            var outHash = inHeader.HashCode;
+
+                            if (changeHash)
+                            {
+                                if (hash != null)
+                                {
+                                    outHash = hash.Value;
+                                }
+                                else
+                                {
+                                    // Get from identity resolver.
+                                    outHash = _desc.EqualityComparer != null
+                                        ? _desc.EqualityComparer.GetHashCode(outStream,
+                                            outStartPos + BinaryObjectHeader.Size,
+                                            schemaPos - outStartPos - BinaryObjectHeader.Size,
+                                            outSchema, outSchemaId, _binary.Marshaller, _desc)
+                                        : 0;
+                                }
+                            }
 
                             var outHeader = new BinaryObjectHeader(inHeader.TypeId, outHash, outLen, 
                                 outSchemaId, outSchemaOff, flags);
@@ -1027,6 +1051,30 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
+        /// Create empty binary object from descriptor.
+        /// </summary>
+        /// <param name="desc">Descriptor.</param>
+        /// <returns>Empty binary object.</returns>
+        private BinaryObject BinaryFromDescriptor(IBinaryTypeDescriptor desc)
+        {
+            const int len = BinaryObjectHeader.Size;
+
+            var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None;
+
+            if (_binary.Marshaller.CompactFooter && desc.UserType)
+                flags |= BinaryObjectHeader.Flag.CompactFooter;
+
+            var hdr = new BinaryObjectHeader(desc.TypeId, 0, len, 0, len, flags);
+
+            using (var stream = new BinaryHeapStream(len))
+            {
+                BinaryObjectHeader.Write(hdr, stream, 0);
+
+                return new BinaryObject(_binary.Marshaller, stream.InternalArray, 0, hdr);
+            }
+        }
+
+        /// <summary>
         /// Mutation context.
         /// </summary>
         private class Context

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs
index 0e5ad2a..636b177 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectHeader.cs
@@ -211,21 +211,40 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// Gets the raw offset of this object in specified stream.
         /// </summary>
         /// <param name="stream">The stream.</param>
-        /// <param name="position">The position.</param>
+        /// <param name="position">The binary object position in the stream.</param>
         /// <returns>Raw offset.</returns>
         public int GetRawOffset(IBinaryStream stream, int position)
         {
             Debug.Assert(stream != null);
 
+            // Either schema or raw is not present - offset is in the header.
             if (!HasRaw || !HasSchema)
                 return SchemaOffset;
 
+            // Both schema and raw data are present: raw offset is in the last 4 bytes.
             stream.Seek(position + Length - 4, SeekOrigin.Begin);
 
             return stream.ReadInt();
         }
 
         /// <summary>
+        /// Gets the footer offset where raw and non-raw data ends.
+        /// </summary>
+        /// <value>Footer offset.</value>
+        public int FooterStartOffset
+        {
+            get
+            {
+                // No schema: all we have is data. There is no offset in last 4 bytes.
+                if (!HasSchema)
+                    return Length;
+
+                // There is schema. Regardless of raw data presence, footer starts with schema.
+                return SchemaOffset;
+            }
+        }
+
+        /// <summary>
         /// Writes specified header to a stream.
         /// </summary>
         /// <param name="header">The header.</param>

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs
index c95746a..8ad78a4 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectSchemaHolder.cs
@@ -18,6 +18,7 @@
 namespace Apache.Ignite.Core.Impl.Binary
 {
     using System;
+    using System.Collections.Generic;
     using System.Threading;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Common;
@@ -119,5 +120,26 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             return result;
         }
+
+        /// <summary>
+        /// Gets the schema.
+        /// </summary>
+        /// <param name="schemaOffset">The schema offset.</param>
+        /// <returns>Current schema as a dictionary.</returns>
+        public Dictionary<int, int> GetFullSchema(int schemaOffset)
+        {
+            var size = _idx - schemaOffset;
+
+            var result = new Dictionary<int, int>(size);
+
+            for (int i = schemaOffset; i < _idx; i++)
+            {
+                var fld = _fields[i];
+
+                result[fld.Id] = fld.Offset;
+            }
+
+            return result;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
index b572e7c..adba577 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
@@ -130,6 +130,12 @@ namespace Apache.Ignite.Core.Impl.Binary
             get { return false; }
         }
 
+        /** <inheritdoc/> */
+        public IBinaryEqualityComparer EqualityComparer
+        {
+            get { return null; }
+        }
+
         /** <inheritDoc /> */
         public BinaryStructure WriterTypeStructure
         {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
index ccb2d1b..bdd7137 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
@@ -614,7 +614,9 @@ namespace Apache.Ignite.Core.Impl.Binary
          */
         private static object ReadEnumArray(BinaryReader ctx, Type type)
         {
-            return BinaryUtils.ReadTypedArray(ctx, true, type.GetElementType());
+            var elemType = type.GetElementType() ?? typeof(object);
+
+            return BinaryUtils.ReadTypedArray(ctx, true, elemType);
         }
 
         /**
@@ -622,7 +624,7 @@ namespace Apache.Ignite.Core.Impl.Binary
          */
         private static object ReadArray(BinaryReader ctx, Type type)
         {
-            var elemType = type.IsArray ? type.GetElementType() : typeof(object);
+            var elemType = type.GetElementType() ?? typeof(object);
 
             return BinaryUtils.ReadTypedArray(ctx, true, elemType);
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
index 77a22dd..47b0663 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
@@ -1195,9 +1195,10 @@ namespace Apache.Ignite.Core.Impl.Binary
                 {
                     // Write object fields.
                     desc.Serializer.WriteBinary(obj, this);
+                    var dataEnd = _stream.Position;
 
                     // Write schema
-                    var schemaOffset = _stream.Position - pos;
+                    var schemaOffset = dataEnd - pos;
 
                     int schemaId;
                     
@@ -1230,8 +1231,12 @@ namespace Apache.Ignite.Core.Impl.Binary
 
                     var len = _stream.Position - pos;
 
-                    var header = new BinaryObjectHeader(desc.TypeId, obj.GetHashCode(), len,
-                        schemaId, schemaOffset, flags);
+                    var hashCode = desc.EqualityComparer != null
+                        ? desc.EqualityComparer.GetHashCode(Stream, pos + BinaryObjectHeader.Size,
+                            dataEnd - pos - BinaryObjectHeader.Size, _schema, schemaIdx, _marsh, desc)
+                        : obj.GetHashCode();
+
+                    var header = new BinaryObjectHeader(desc.TypeId, hashCode, len, schemaId, schemaOffset, flags);
 
                     BinaryObjectHeader.Write(header, _stream, pos);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
index b80348e..6adb847 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
@@ -24,7 +24,7 @@ namespace Apache.Ignite.Core.Impl.Binary
     /// <summary>
     /// Wraps DateTime item in a binarizable.
     /// </summary>
-    internal class DateTimeHolder : IBinaryWriteAware
+    internal struct DateTimeHolder : IBinaryWriteAware
     {
         /** */
         private readonly DateTime _item;
@@ -64,5 +64,18 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             writer.GetRawWriter().WriteLong(_item.ToBinary());
         }
+
+        /** <inheritDoc /> */
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            return obj is DateTimeHolder && _item.Equals(((DateTimeHolder) obj)._item);
+        }
+
+        /** <inheritDoc /> */
+        public override int GetHashCode()
+        {
+            return _item.GetHashCode();
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryEqualityComparer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryEqualityComparer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryEqualityComparer.cs
new file mode 100644
index 0000000..9628688
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryEqualityComparer.cs
@@ -0,0 +1,53 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+
+    /// <summary>
+    /// Internal comparer interface for <see cref="BinaryTypeConfiguration.EqualityComparer"/> implementations,
+    /// provides more efficient API.
+    /// </summary>
+    internal interface IBinaryEqualityComparer
+    {
+        /// <summary>
+        /// Returns a hash code for the binary object in specified stream at specified position.
+        /// </summary>
+        /// <param name="stream">Stream.</param>
+        /// <param name="startPos">Data start position (right after the header).</param>
+        /// <param name="length">Data length (without header and schema).</param>
+        /// <param name="schema">Schema holder.</param>
+        /// <param name="schemaId">Schema identifier.</param>
+        /// <param name="marshaller">Marshaller.</param>
+        /// <param name="desc">Type descriptor.</param>
+        /// <returns>
+        /// A hash code for the object in the stream.
+        /// </returns>
+        int GetHashCode(IBinaryStream stream, int startPos, int length, BinaryObjectSchemaHolder schema, int schemaId,
+            Marshaller marshaller, IBinaryTypeDescriptor desc);
+
+        /// <summary>
+        /// Returns a value indicating that two binary object are equal.
+        /// </summary>
+        /// <param name="x">First object.</param>
+        /// <param name="y">Second object.</param>
+        /// <returns>True when objects are equal; otherwise false.</returns>
+        bool Equals(IBinaryObject x, IBinaryObject y);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
index e25d720..6c7e360 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
@@ -78,6 +78,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         bool IsEnum { get; }
 
         /// <summary>
+        /// Gets the equality comparer.
+        /// </summary>
+        IBinaryEqualityComparer EqualityComparer { get; }
+
+        /// <summary>
         /// Write type structure.
         /// </summary>
         BinaryStructure WriterTypeStructure { get; }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs
index 2ce2138..ad35ff9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryHeapStream.cs
@@ -420,6 +420,15 @@ namespace Apache.Ignite.Core.Impl.Binary.IO
         }
 
         /** <inheritdoc /> */
+        public override T Apply<TArg, T>(IBinaryStreamProcessor<TArg, T> proc, TArg arg)
+        {
+            fixed (byte* data0 = _data)
+            {
+                return proc.Invoke(data0, arg);
+            }
+        }
+
+        /** <inheritdoc /> */
         protected override void Dispose(bool disposing)
         {
             // No-op.

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs
index 184209f..0b855f8 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/BinaryStreamBase.cs
@@ -1119,6 +1119,19 @@ namespace Apache.Ignite.Core.Impl.Binary.IO
             return Pos;
         }
 
+        /// <summary>
+        /// Returns a hash code for the specified byte range.
+        /// </summary>
+        public abstract T Apply<TArg, T>(IBinaryStreamProcessor<TArg, T> proc, TArg arg);
+
+        /// <summary>
+        /// Flushes the data to underlying storage.
+        /// </summary>
+        public void Flush()
+        {
+            // No-op.
+        }
+
         /** <inheritdoc /> */
         public void Dispose()
         {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs
index cd509c6..3a46515 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs
@@ -318,5 +318,30 @@ namespace Apache.Ignite.Core.Impl.Binary.IO
         /// <param name="origin">Seek origin.</param>
         /// <returns>Position.</returns>
         int Seek(int offset, SeekOrigin origin);
+
+        /// <summary>
+        /// Applies specified processor to the raw stream data.
+        /// </summary>
+        T Apply<TArg, T>(IBinaryStreamProcessor<TArg, T> proc, TArg arg);
+
+        /// <summary>
+        /// Flushes the data to underlying storage.
+        /// </summary>
+        void Flush();
+    }
+
+    /// <summary>
+    /// Binary stream processor.
+    /// </summary>
+    [CLSCompliant(false)]
+    public unsafe interface IBinaryStreamProcessor<in TArg, out T>
+    {
+        /// <summary>
+        /// Invokes the processor.
+        /// </summary>
+        /// <param name="data">Data.</param>
+        /// <param name="arg">Argument.</param>
+        /// <returns>Result.</returns>
+        T Invoke(byte* data, TArg arg);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
index 475762a..6dee998 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
@@ -408,7 +408,7 @@ namespace Apache.Ignite.Core.Impl.Binary
             if (meta != BinaryType.Empty)
             {
                 desc = new BinaryFullTypeDescriptor(null, meta.TypeId, meta.TypeName, true, null, null, null, false, 
-                    meta.AffinityKeyFieldName, meta.IsEnum);
+                    meta.AffinityKeyFieldName, meta.IsEnum, null);
 
                 _idToDesc.GetOrAdd(typeKey, _ => desc);
 
@@ -419,6 +419,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
+        /// Gets the user type descriptors.
+        /// </summary>
+        public ICollection<IBinaryTypeDescriptor> GetUserTypeDescriptors()
+        {
+            return _typeNameToDesc.Values;
+        }
+
+        /// <summary>
         /// Add user type.
         /// </summary>
         /// <param name="cfg">Configuration.</param>
@@ -453,7 +461,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 var serializer = GetSerializer(cfg, typeCfg, type, typeId, nameMapper, idMapper);
 
                 AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer,
-                    affKeyFld, type.IsEnum);
+                    affKeyFld, type.IsEnum, typeCfg.EqualityComparer);
             }
             else
             {
@@ -463,7 +471,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper);
 
                 AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null,
-                    typeCfg.AffinityKeyFieldName, typeCfg.IsEnum);
+                    typeCfg.AffinityKeyFieldName, typeCfg.IsEnum, typeCfg.EqualityComparer);
             }
         }
 
@@ -521,9 +529,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="serializer">Serializer.</param>
         /// <param name="affKeyFieldName">Affinity key field name.</param>
         /// <param name="isEnum">Enum flag.</param>
+        /// <param name="comparer">Comparer.</param>
         private void AddType(Type type, int typeId, string typeName, bool userType, 
             bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper,
-            IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum)
+            IBinarySerializerInternal serializer, string affKeyFieldName, bool isEnum, 
+            IEqualityComparer<IBinaryObject> comparer)
         {
             long typeKey = BinaryUtils.TypeKey(userType, typeId);
 
@@ -545,7 +555,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 throw new BinaryObjectException("Conflicting type name: " + typeName);
 
             var descriptor = new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, 
-                serializer, keepDeserialized, affKeyFieldName, isEnum);
+                serializer, keepDeserialized, affKeyFieldName, isEnum, comparer);
 
             if (type != null)
                 _typeToDesc[type] = descriptor;
@@ -571,7 +581,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 typeId = BinaryUtils.TypeId(type.Name, null, null);
 
             AddType(type, typeId, BinaryUtils.GetTypeName(type), false, false, null, null, serializer, affKeyFldName,
-                false);
+                false, null);
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs
index 99c8f49..26b1d5f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableObjectHolder.cs
@@ -76,5 +76,21 @@ namespace Apache.Ignite.Core.Impl.Binary
                 _item = new BinaryFormatter().Deserialize(streamAdapter, null);
             }
         }
+
+        /** <inheritdoc /> */
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != GetType()) return false;
+
+            return Equals(_item, ((SerializableObjectHolder) obj)._item);
+        }
+
+        /** <inheritdoc /> */
+        public override int GetHashCode()
+        {
+            return _item != null ? _item.GetHashCode() : 0;
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
index e1df50b..bb9cbfc 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Common/IgniteConfigurationXmlSerializer.cs
@@ -142,7 +142,7 @@ namespace Apache.Ignite.Core.Impl.Common
         /// </summary>
         private static void WriteComplexProperty(object obj, XmlWriter writer, Type valueType)
         {
-            var props = GetNonDefaultProperties(obj).ToList();
+            var props = GetNonDefaultProperties(obj).OrderBy(x => x.Name).ToList();
 
             // Specify type for interfaces and abstract classes
             if (valueType.IsAbstract)
@@ -353,7 +353,8 @@ namespace Apache.Ignite.Core.Impl.Common
         /// </summary>
         private static List<Type> GetConcreteDerivedTypes(Type type)
         {
-            return type.Assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && type.IsAssignableFrom(t)).ToList();
+            return typeof(IIgnite).Assembly.GetTypes()
+                .Where(t => t.IsClass && !t.IsAbstract && type.IsAssignableFrom(t)).ToList();
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs
index c758d28..3719846 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs
@@ -732,6 +732,22 @@ namespace Apache.Ignite.Core.Impl.Memory
         }
 
         /// <summary>
+        /// Returns a hash code for the specified byte range.
+        /// </summary>
+        public T Apply<TArg, T>(IBinaryStreamProcessor<TArg, T> proc, TArg arg)
+        {
+            return proc.Invoke(_data, arg);
+        }
+
+        /// <summary>
+        /// Flushes the data to underlying storage.
+        /// </summary>
+        public void Flush()
+        {
+            SynchronizeOutput();
+        }
+
+        /// <summary>
         /// Ensure capacity for write and shift position.
         /// </summary>
         /// <param name="cnt">Bytes count.</param>


[3/8] ignite git commit: IGNITE-4045 .NET: Support DML API

Posted by pt...@apache.org.
IGNITE-4045 .NET: Support DML API

This closes #1309


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/b7908d7a
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/b7908d7a
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/b7908d7a

Branch: refs/heads/ignite-2.0
Commit: b7908d7a65f07615f2ff183e107c5002658bd511
Parents: d6d42c2
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Mon Jan 16 17:48:08 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Mon Jan 16 17:48:08 2017 +0300

----------------------------------------------------------------------
 .../utils/PlatformConfigurationUtils.java       | 128 +++++++-
 .../Apache.Ignite.Core.Tests.csproj             |   3 +
 .../Binary/BinaryBuilderSelfTest.cs             | 159 ++++++----
 .../BinaryBuilderSelfTestArrayIdentity.cs       |  34 +++
 .../Binary/BinaryEqualityComparerTest.cs        | 279 +++++++++++++++++
 .../Binary/IO/BinaryStreamsTest.cs              |  19 ++
 .../Cache/CacheConfigurationTest.cs             |   5 +-
 .../Cache/Query/CacheDmlQueriesTest.cs          | 296 +++++++++++++++++++
 .../IgniteConfigurationSerializerTest.cs        |  46 ++-
 .../IgniteConfigurationTest.cs                  |  28 ++
 .../Apache.Ignite.Core.csproj                   |   4 +
 .../Binary/BinaryArrayEqualityComparer.cs       | 149 ++++++++++
 .../Binary/BinaryConfiguration.cs               |  24 ++
 .../Binary/BinaryTypeConfiguration.cs           |  14 +
 .../Cache/Configuration/QueryEntity.cs          |  33 ++-
 .../Cache/Configuration/QueryField.cs           |   6 +
 .../Apache.Ignite.Core/IgniteConfiguration.cs   |  85 ++++--
 .../IgniteConfigurationSection.xsd              |  19 ++
 .../Apache.Ignite.Core/Impl/Binary/Binary.cs    |  28 +-
 .../Binary/BinaryEqualityComparerSerializer.cs  |  99 +++++++
 .../Impl/Binary/BinaryFieldEqualityComparer.cs  | 138 +++++++++
 .../Impl/Binary/BinaryFullTypeDescriptor.cs     |  21 +-
 .../Impl/Binary/BinaryObject.cs                 |  31 +-
 .../Impl/Binary/BinaryObjectBuilder.cs          |  62 +++-
 .../Impl/Binary/BinaryObjectHeader.cs           |  21 +-
 .../Impl/Binary/BinaryObjectSchemaHolder.cs     |  22 ++
 .../Binary/BinarySurrogateTypeDescriptor.cs     |   6 +
 .../Impl/Binary/BinarySystemHandlers.cs         |   6 +-
 .../Impl/Binary/BinaryWriter.cs                 |  11 +-
 .../Impl/Binary/DateTimeHolder.cs               |  15 +-
 .../Impl/Binary/IBinaryEqualityComparer.cs      |  53 ++++
 .../Impl/Binary/IBinaryTypeDescriptor.cs        |   5 +
 .../Impl/Binary/Io/BinaryHeapStream.cs          |   9 +
 .../Impl/Binary/Io/BinaryStreamBase.cs          |  13 +
 .../Impl/Binary/Io/IBinaryStream.cs             |  25 ++
 .../Impl/Binary/Marshaller.cs                   |  22 +-
 .../Impl/Binary/SerializableObjectHolder.cs     |  16 +
 .../Common/IgniteConfigurationXmlSerializer.cs  |   5 +-
 .../Impl/Memory/PlatformMemoryStream.cs         |  16 +
 39 files changed, 1803 insertions(+), 152 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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 f845675..c0fde97 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
@@ -17,8 +17,12 @@
 
 package org.apache.ignite.internal.processors.platform.utils;
 
+import org.apache.ignite.binary.BinaryArrayIdentityResolver;
+import org.apache.ignite.binary.BinaryFieldIdentityResolver;
+import org.apache.ignite.binary.BinaryIdentityResolver;
 import org.apache.ignite.binary.BinaryRawReader;
 import org.apache.ignite.binary.BinaryRawWriter;
+import org.apache.ignite.binary.BinaryTypeConfiguration;
 import org.apache.ignite.cache.CacheAtomicWriteOrderMode;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMemoryMode;
@@ -68,6 +72,8 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
 
 /**
  * Configuration utils.
@@ -428,14 +434,25 @@ public class PlatformConfigurationUtils {
 
         // Fields
         int cnt = in.readInt();
+        Set<String> keyFields = new HashSet<>(cnt);
 
         if (cnt > 0) {
             LinkedHashMap<String, String> fields = new LinkedHashMap<>(cnt);
 
-            for (int i = 0; i < cnt; i++)
-                fields.put(in.readString(), in.readString());
+            for (int i = 0; i < cnt; i++) {
+                String fieldName = in.readString();
+                String fieldType = in.readString();
+
+                fields.put(fieldName, fieldType);
+
+                if (in.readBoolean())
+                    keyFields.add(fieldName);
+            }
 
             res.setFields(fields);
+
+            if (!keyFields.isEmpty())
+                res.setKeyFields(keyFields);
         }
 
         // Aliases
@@ -539,11 +556,29 @@ public class PlatformConfigurationUtils {
             cfg.setCommunicationSpi(comm);
         }
 
-        if (in.readBoolean()) {
+        if (in.readBoolean()) {  // binary config is present
             if (cfg.getBinaryConfiguration() == null)
                 cfg.setBinaryConfiguration(new BinaryConfiguration());
 
-            cfg.getBinaryConfiguration().setCompactFooter(in.readBoolean());
+            if (in.readBoolean())  // compact footer is set
+                cfg.getBinaryConfiguration().setCompactFooter(in.readBoolean());
+
+            int typeCnt = in.readInt();
+
+            if (typeCnt > 0) {
+                Collection<BinaryTypeConfiguration> types = new ArrayList<>(typeCnt);
+
+                for (int i = 0; i < typeCnt; i++) {
+                    BinaryTypeConfiguration type = new BinaryTypeConfiguration(in.readString());
+
+                    type.setEnum(in.readBoolean());
+                    type.setIdentityResolver(readBinaryIdentityResolver(in));
+
+                    types.add(type);
+                }
+
+                cfg.getBinaryConfiguration().setTypeConfigurations(types);
+            }
         }
 
         int attrCnt = in.readInt();
@@ -812,11 +847,14 @@ public class PlatformConfigurationUtils {
         LinkedHashMap<String, String> fields = queryEntity.getFields();
 
         if (fields != null) {
+            Set<String> keyFields = queryEntity.getKeyFields();
+
             writer.writeInt(fields.size());
 
             for (Map.Entry<String, String> field : fields.entrySet()) {
                 writer.writeString(field.getKey());
                 writer.writeString(field.getValue());
+                writer.writeBoolean(keyFields != null && keyFields.contains(field.getKey()));
             }
         }
         else
@@ -941,11 +979,29 @@ public class PlatformConfigurationUtils {
             w.writeBoolean(false);
 
         BinaryConfiguration bc = cfg.getBinaryConfiguration();
-        w.writeBoolean(bc != null);
 
-        if (bc != null)
+        if (bc != null) {
+            w.writeBoolean(true);  // binary config exists
+            w.writeBoolean(true);  // compact footer is set
             w.writeBoolean(bc.isCompactFooter());
 
+            Collection<BinaryTypeConfiguration> types = bc.getTypeConfigurations();
+
+            if (types != null) {
+                w.writeInt(types.size());
+
+                for (BinaryTypeConfiguration type : types) {
+                    w.writeString(type.getTypeName());
+                    w.writeBoolean(type.isEnum());
+                    writeBinaryIdentityResolver(w, type.getIdentityResolver());
+                }
+            }
+            else
+                w.writeInt(0);
+        }
+        else
+            w.writeBoolean(false);
+
         Map<String, ?> attrs = cfg.getUserAttributes();
 
         if (attrs != null) {
@@ -1117,6 +1173,66 @@ public class PlatformConfigurationUtils {
     }
 
     /**
+     * Reads resolver
+     *
+     * @param r Reader.
+     * @return Resolver.
+     */
+    private static BinaryIdentityResolver readBinaryIdentityResolver(BinaryRawReader r) {
+        int type = r.readByte();
+
+        switch (type) {
+            case 0:
+                return null;
+
+            case 1:
+                return new BinaryArrayIdentityResolver();
+
+            case 2:
+                int cnt = r.readInt();
+
+                String[] fields = new String[cnt];
+
+                for (int i = 0; i < cnt; i++)
+                    fields[i] = r.readString();
+
+                return new BinaryFieldIdentityResolver().setFieldNames(fields);
+
+            default:
+                assert false;
+                return null;
+        }
+    }
+
+    /**
+     * Writes the resolver.
+     *
+     * @param w Writer.
+     * @param resolver Resolver.
+     */
+    private static void writeBinaryIdentityResolver(BinaryRawWriter w, BinaryIdentityResolver resolver) {
+        if (resolver instanceof BinaryArrayIdentityResolver)
+            w.writeByte((byte)1);
+        else if (resolver instanceof BinaryFieldIdentityResolver) {
+            w.writeByte((byte)2);
+
+            String[] fields = ((BinaryFieldIdentityResolver)resolver).getFieldNames();
+
+            if (fields != null) {
+                w.writeInt(fields.length);
+
+                for (String field : fields)
+                    w.writeString(field);
+            }
+            else
+                w.writeInt(0);
+        }
+        else {
+            w.writeByte((byte)0);
+        }
+    }
+
+    /**
      * Private constructor.
      */
     private PlatformConfigurationUtils() {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
index 78a08d2..e09c682 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
@@ -67,6 +67,8 @@
     <Reference Include="System.Xml.Linq" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Binary\BinaryBuilderSelfTestArrayIdentity.cs" />
+    <Compile Include="Binary\BinaryEqualityComparerTest.cs" />
     <Compile Include="Binary\BinaryReaderWriterTest.cs" />
     <Compile Include="Binary\IO\BinaryStreamsTest.cs" />
     <Compile Include="Binary\JavaTypeMappingTest.cs" />
@@ -76,6 +78,7 @@
     <Compile Include="Cache\CacheMetricsTest.cs" />
     <Compile Include="Cache\CacheResultTest.cs" />
     <Compile Include="Cache\CacheSwapSpaceTest.cs" />
+    <Compile Include="Cache\Query\CacheDmlQueriesTest.cs" />
     <Compile Include="Cache\CacheAbstractTransactionalTest.cs" />
     <Compile Include="Cache\Store\CacheStoreAdapterTest.cs" />
     <Compile Include="Collections\MultiValueDictionaryTest.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
index c280255..d6551b5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
@@ -58,33 +58,57 @@ namespace Apache.Ignite.Core.Tests.Binary
                 {
                     TypeConfigurations = new List<BinaryTypeConfiguration>
                     {
-                        new BinaryTypeConfiguration(typeof (Empty)),
-                        new BinaryTypeConfiguration(typeof (Primitives)),
-                        new BinaryTypeConfiguration(typeof (PrimitiveArrays)),
-                        new BinaryTypeConfiguration(typeof (StringDateGuidEnum)),
-                        new BinaryTypeConfiguration(typeof (WithRaw)),
-                        new BinaryTypeConfiguration(typeof (MetaOverwrite)),
-                        new BinaryTypeConfiguration(typeof (NestedOuter)),
-                        new BinaryTypeConfiguration(typeof (NestedInner)),
-                        new BinaryTypeConfiguration(typeof (MigrationOuter)),
-                        new BinaryTypeConfiguration(typeof (MigrationInner)),
-                        new BinaryTypeConfiguration(typeof (InversionOuter)),
-                        new BinaryTypeConfiguration(typeof (InversionInner)),
-                        new BinaryTypeConfiguration(typeof (CompositeOuter)),
-                        new BinaryTypeConfiguration(typeof (CompositeInner)),
-                        new BinaryTypeConfiguration(typeof (CompositeArray)),
-                        new BinaryTypeConfiguration(typeof (CompositeContainer)),
-                        new BinaryTypeConfiguration(typeof (ToBinary)),
-                        new BinaryTypeConfiguration(typeof (Remove)),
-                        new BinaryTypeConfiguration(typeof (RemoveInner)),
-                        new BinaryTypeConfiguration(typeof (BuilderInBuilderOuter)),
-                        new BinaryTypeConfiguration(typeof (BuilderInBuilderInner)),
-                        new BinaryTypeConfiguration(typeof (BuilderCollection)),
-                        new BinaryTypeConfiguration(typeof (BuilderCollectionItem)),
-                        new BinaryTypeConfiguration(typeof (DecimalHolder)),
-                        new BinaryTypeConfiguration(TypeEmpty),
-                        new BinaryTypeConfiguration(typeof(TestEnumRegistered)),
+                        new BinaryTypeConfiguration(typeof(Empty)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(Primitives)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(PrimitiveArrays)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(StringDateGuidEnum))
+                        {
+                            EqualityComparer = GetIdentityResolver()
+                        },
+                        new BinaryTypeConfiguration(typeof(WithRaw)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(MetaOverwrite)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(NestedOuter)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(NestedInner)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(MigrationOuter)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(MigrationInner)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(InversionOuter)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(InversionInner)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(CompositeOuter)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(CompositeInner)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(CompositeArray)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(CompositeContainer))
+                        {
+                            EqualityComparer = GetIdentityResolver()
+                        },
+                        new BinaryTypeConfiguration(typeof(ToBinary)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(Remove)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(RemoveInner)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(BuilderInBuilderOuter))
+                        {
+                            EqualityComparer = GetIdentityResolver()
+                        },
+                        new BinaryTypeConfiguration(typeof(BuilderInBuilderInner))
+                        {
+                            EqualityComparer = GetIdentityResolver()
+                        },
+                        new BinaryTypeConfiguration(typeof(BuilderCollection))
+                        {
+                            EqualityComparer = GetIdentityResolver()
+                        },
+                        new BinaryTypeConfiguration(typeof(BuilderCollectionItem))
+                        {
+                            EqualityComparer = GetIdentityResolver()
+                        },
+                        new BinaryTypeConfiguration(typeof(DecimalHolder)) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(TypeEmpty) {EqualityComparer = GetIdentityResolver()},
+                        new BinaryTypeConfiguration(typeof(TestEnumRegistered))
+                        {
+                            EqualityComparer = GetIdentityResolver()
+                        },
                         new BinaryTypeConfiguration(typeof(NameMapperTestType))
+                        {
+                            EqualityComparer = GetIdentityResolver()
+                        }
                     },
                     DefaultIdMapper = new IdMapper(),
                     DefaultNameMapper = new NameMapper(),
@@ -106,6 +130,14 @@ namespace Apache.Ignite.Core.Tests.Binary
         }
 
         /// <summary>
+        /// Gets the identity resolver.
+        /// </summary>
+        protected virtual IEqualityComparer<IBinaryObject> GetIdentityResolver()
+        {
+            return null;
+        }
+
+        /// <summary>
         /// Tear down routine.
         /// </summary>
         [TestFixtureTearDown]
@@ -535,7 +567,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             IBinaryObject binObj = _grid.GetBinary().GetBuilder(typeof(Empty)).Build();
 
             Assert.IsNotNull(binObj);
-            Assert.AreEqual(0, binObj.GetHashCode());
+            Assert.AreEqual(GetIdentityResolver() == null ? 0 : 1, binObj.GetHashCode());
 
             IBinaryType meta = binObj.GetBinaryType();
 
@@ -557,7 +589,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             IBinaryObject binObj = _grid.GetBinary().GetBuilder(TypeEmpty).Build();
 
             Assert.IsNotNull(binObj);
-            Assert.AreEqual(0, binObj.GetHashCode());
+            Assert.AreEqual(GetIdentityResolver() == null ? 0 : 1, binObj.GetHashCode());
 
             IBinaryType meta = binObj.GetBinaryType();
 
@@ -602,7 +634,9 @@ namespace Apache.Ignite.Core.Tests.Binary
             var obj2 = bin.GetBuilder("myType").SetStringField("str", "foo").SetIntField("int", 1).Build();
 
             Assert.AreEqual(obj1, obj2);
-            Assert.AreEqual(obj1.GetHashCode(), obj2.GetHashCode());
+
+            Assert.AreEqual(0, obj1.GetHashCode());
+            Assert.AreEqual(0, obj2.GetHashCode());
 
             Assert.IsTrue(Regex.IsMatch(obj1.ToString(), @"myType \[idHash=[0-9]+, str=foo, int=1\]"));
         }
@@ -630,7 +664,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             CheckPrimitiveFields1(binObj);
 
             // Specific setter methods.
-            binObj = _grid.GetBinary().GetBuilder(typeof(Primitives))
+            var binObj2 = _grid.GetBinary().GetBuilder(typeof(Primitives))
                 .SetByteField("fByte", 1)
                 .SetBooleanField("fBool", true)
                 .SetShortField("fShort", 2)
@@ -643,7 +677,11 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetHashCode(100)
                 .Build();
 
-            CheckPrimitiveFields1(binObj);
+            CheckPrimitiveFields1(binObj2);
+
+            // Check equality.
+            Assert.AreEqual(binObj, binObj2);
+            Assert.AreEqual(binObj.GetHashCode(), binObj2.GetHashCode());
 
             // Overwrite with generic methods.
             binObj = binObj.ToBuilder()
@@ -656,13 +694,12 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetField<float>("fFloat", 11)
                 .SetField<double>("fDouble", 12)
                 .SetField("fDecimal", 13.13m)
-                .SetHashCode(200)
                 .Build();
 
             CheckPrimitiveFields2(binObj);
 
             // Overwrite with specific methods.
-            binObj = binObj.ToBuilder()
+            binObj2 = binObj.ToBuilder()
                 .SetByteField("fByte", 7)
                 .SetBooleanField("fBool", false)
                 .SetShortField("fShort", 8)
@@ -672,10 +709,13 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetFloatField("fFloat", 11)
                 .SetDoubleField("fDouble", 12)
                 .SetDecimalField("fDecimal", 13.13m)
-                .SetHashCode(200)
                 .Build();
 
             CheckPrimitiveFields2(binObj);
+
+            // Check equality.
+            Assert.AreEqual(binObj, binObj2);
+            Assert.AreEqual(binObj.GetHashCode(), binObj2.GetHashCode());
         }
 
         /// <summary>
@@ -729,8 +769,6 @@ namespace Apache.Ignite.Core.Tests.Binary
         /// </summary>
         private static void CheckPrimitiveFields2(IBinaryObject binObj)
         {
-            Assert.AreEqual(200, binObj.GetHashCode());
-
             Assert.AreEqual(7, binObj.GetField<byte>("fByte"));
             Assert.AreEqual(false, binObj.GetField<bool>("fBool"));
             Assert.AreEqual(8, binObj.GetField<short>("fShort"));
@@ -777,7 +815,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             CheckPrimitiveArrayFields1(binObj);
 
             // Specific setters.
-            binObj = _grid.GetBinary().GetBuilder(typeof(PrimitiveArrays))
+            var binObj2 = _grid.GetBinary().GetBuilder(typeof(PrimitiveArrays))
                 .SetByteArrayField("fByte", new byte[] {1})
                 .SetBooleanArrayField("fBool", new[] {true})
                 .SetShortArrayField("fShort", new short[] {2})
@@ -789,7 +827,13 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetDecimalArrayField("fDecimal", new decimal?[] {7.7m})
                 .SetHashCode(100)
                 .Build();
-            
+
+            CheckPrimitiveArrayFields1(binObj2);
+
+            // Check equality.
+            Assert.AreEqual(binObj, binObj2);
+            Assert.AreEqual(binObj.GetHashCode(), binObj2.GetHashCode());
+
             // Overwrite with generic setter.
             binObj = _grid.GetBinary().GetBuilder(binObj)
                 .SetField("fByte", new byte[] { 7 })
@@ -801,13 +845,12 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetField("fFloat", new float[] { 11 })
                 .SetField("fDouble", new double[] { 12 })
                 .SetField("fDecimal", new decimal?[] { 13.13m })
-                .SetHashCode(200)
                 .Build();
 
             CheckPrimitiveArrayFields2(binObj);
 
             // Overwrite with specific setters.
-            binObj = _grid.GetBinary().GetBuilder(binObj)
+            binObj2 = _grid.GetBinary().GetBuilder(binObj)
                 .SetByteArrayField("fByte", new byte[] { 7 })
                 .SetBooleanArrayField("fBool", new[] { false })
                 .SetShortArrayField("fShort", new short[] { 8 })
@@ -817,10 +860,13 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetFloatArrayField("fFloat", new float[] { 11 })
                 .SetDoubleArrayField("fDouble", new double[] { 12 })
                 .SetDecimalArrayField("fDecimal", new decimal?[] { 13.13m })
-                .SetHashCode(200)
                 .Build();
 
             CheckPrimitiveArrayFields2(binObj);
+            
+            // Check equality.
+            Assert.AreEqual(binObj, binObj2);
+            Assert.AreEqual(binObj.GetHashCode(), binObj2.GetHashCode());
         }
 
         /// <summary>
@@ -874,8 +920,6 @@ namespace Apache.Ignite.Core.Tests.Binary
         /// </summary>
         private static void CheckPrimitiveArrayFields2(IBinaryObject binObj)
         {
-            Assert.AreEqual(200, binObj.GetHashCode());
-
             Assert.AreEqual(new byte[] { 7 }, binObj.GetField<byte[]>("fByte"));
             Assert.AreEqual(new[] { false }, binObj.GetField<bool[]>("fBool"));
             Assert.AreEqual(new short[] { 8 }, binObj.GetField<short[]>("fShort"));
@@ -910,7 +954,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             Guid? nGuid = Guid.NewGuid();
 
             // Generic setters.
-            IBinaryObject binObj = _grid.GetBinary().GetBuilder(typeof(StringDateGuidEnum))
+            var binObj = _grid.GetBinary().GetBuilder(typeof(StringDateGuidEnum))
                 .SetField("fStr", "str")
                 .SetField("fNDate", nDate)
                 .SetTimestampField("fNTimestamp", nDate)
@@ -927,7 +971,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             CheckStringDateGuidEnum1(binObj, nDate, nGuid);
 
             // Specific setters.
-            binObj = _grid.GetBinary().GetBuilder(typeof(StringDateGuidEnum))
+            var binObj2 = _grid.GetBinary().GetBuilder(typeof(StringDateGuidEnum))
                 .SetStringField("fStr", "str")
                 .SetField("fNDate", nDate)
                 .SetTimestampField("fNTimestamp", nDate)
@@ -941,7 +985,11 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetHashCode(100)
                 .Build();
 
-            CheckStringDateGuidEnum1(binObj, nDate, nGuid);
+            CheckStringDateGuidEnum1(binObj2, nDate, nGuid);
+
+            // Check equality.
+            Assert.AreEqual(binObj, binObj2);
+            Assert.AreEqual(binObj.GetHashCode(), binObj2.GetHashCode());
 
             // Overwrite.
             nDate = DateTime.Now.ToUniversalTime();
@@ -958,13 +1006,12 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetTimestampArrayField("fTimestampArr", new[] { nDate })
                 .SetField("fGuidArr", new[] { nGuid })
                 .SetField("fEnumArr", new[] { TestEnum.Two })
-                .SetHashCode(200)
                 .Build();
 
             CheckStringDateGuidEnum2(binObj, nDate, nGuid);
 
             // Overwrite with specific setters
-            binObj = _grid.GetBinary().GetBuilder(typeof(StringDateGuidEnum))
+            binObj2 = _grid.GetBinary().GetBuilder(typeof(StringDateGuidEnum))
                 .SetStringField("fStr", "str2")
                 .SetField("fNDate", nDate)
                 .SetTimestampField("fNTimestamp", nDate)
@@ -975,10 +1022,13 @@ namespace Apache.Ignite.Core.Tests.Binary
                 .SetTimestampArrayField("fTimestampArr", new[] { nDate })
                 .SetGuidArrayField("fGuidArr", new[] { nGuid })
                 .SetEnumArrayField("fEnumArr", new[] { TestEnum.Two })
-                .SetHashCode(200)
                 .Build();
 
-            CheckStringDateGuidEnum2(binObj, nDate, nGuid);
+            CheckStringDateGuidEnum2(binObj2, nDate, nGuid);
+
+            // Check equality.
+            Assert.AreEqual(binObj, binObj2);
+            Assert.AreEqual(binObj.GetHashCode(), binObj2.GetHashCode());
         }
 
         /// <summary>
@@ -1074,8 +1124,6 @@ namespace Apache.Ignite.Core.Tests.Binary
         /// </summary>
         private static void CheckStringDateGuidEnum2(IBinaryObject binObj, DateTime? nDate, Guid? nGuid)
         {
-            Assert.AreEqual(200, binObj.GetHashCode());
-
             Assert.AreEqual("str2", binObj.GetField<string>("fStr"));
             Assert.AreEqual(nDate, binObj.GetField<DateTime?>("fNDate"));
             Assert.AreEqual(nDate, binObj.GetField<DateTime?>("fNTimestamp"));
@@ -1432,7 +1480,8 @@ namespace Apache.Ignite.Core.Tests.Binary
 
             IBinaryObjectBuilder builder = _grid.GetBinary().GetBuilder(typeof(MigrationOuter));
 
-            builder.SetHashCode(outer.GetHashCode());
+            if (GetIdentityResolver() == null)
+                builder.SetHashCode(outer.GetHashCode());
 
             builder.SetField<object>("inner1", inner);
             builder.SetField<object>("inner2", inner);
@@ -1642,6 +1691,7 @@ namespace Apache.Ignite.Core.Tests.Binary
             }
 
             Assert.AreEqual(binEnums[0], binEnums[1]);
+            Assert.AreEqual(binEnums[0].GetHashCode(), binEnums[1].GetHashCode());
         }
 
         /// <summary>
@@ -1659,6 +1709,9 @@ namespace Apache.Ignite.Core.Tests.Binary
         [Test]
         public void TestRemoteBinaryMode()
         {
+            if (GetIdentityResolver() != null)
+                return;  // When identity resolver is set, it is required to have the same config on all nodes.
+
             var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
             {
                 GridName = "grid2",

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestArrayIdentity.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestArrayIdentity.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestArrayIdentity.cs
new file mode 100644
index 0000000..b5e767c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTestArrayIdentity.cs
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Binary
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// Tests with array equality comparer (identity resolver).
+    /// </summary>
+    public class BinaryBuilderSelfTestArrayIdentity : BinaryBuilderSelfTest
+    {
+        /** <inheritdoc /> */
+        protected override IEqualityComparer<IBinaryObject> GetIdentityResolver()
+        {
+            return new BinaryArrayEqualityComparer();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryEqualityComparerTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryEqualityComparerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryEqualityComparerTest.cs
new file mode 100644
index 0000000..f0550a8
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryEqualityComparerTest.cs
@@ -0,0 +1,279 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Tests.Binary
+{
+    using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Equality comparers test.
+    /// </summary>
+    public class BinaryEqualityComparerTest
+    {
+        /// <summary>
+        /// Tests common public methods logic.
+        /// </summary>
+        [Test]
+        [SuppressMessage("ReSharper", "ReturnValueOfPureMethodIsNotUsed")]
+        public void TestPublicMethods()
+        {
+            var cmps = new IEqualityComparer<IBinaryObject>[]
+            {
+                new BinaryArrayEqualityComparer()
+                //new BinaryFieldEqualityComparer()
+            };
+
+            var obj = GetBinaryObject(1, "x", 0);
+
+            foreach (var cmp in cmps)
+            {
+                Assert.IsTrue(cmp.Equals(null, null));
+                Assert.IsTrue(cmp.Equals(obj, obj));
+
+                Assert.IsFalse(cmp.Equals(obj, null));
+                Assert.IsFalse(cmp.Equals(null, obj));
+
+                Assert.AreEqual(0, cmp.GetHashCode(null));
+                Assert.AreNotEqual(0, cmp.GetHashCode(obj));
+            }
+        }
+
+        /// <summary>
+        /// Tests the custom comparer.
+        /// </summary>
+        [Test]
+        public void TestCustomComparer()
+        {
+            var ex = Assert.Throws<IgniteException>(() => Ignition.Start(
+                new IgniteConfiguration(TestUtils.GetTestConfiguration())
+                {
+                    BinaryConfiguration = new BinaryConfiguration
+                    {
+                        TypeConfigurations = new[]
+                        {
+                            new BinaryTypeConfiguration(typeof(Foo))
+                            {
+                                EqualityComparer = new MyComparer()
+                            }
+                        }
+                    }
+                }));
+
+            Assert.AreEqual("Unsupported IEqualityComparer<IBinaryObject> implementation: " +
+                            "Apache.Ignite.Core.Tests.Binary.BinaryEqualityComparerTest+MyComparer. " +
+                            "Only predefined implementations are supported.", ex.Message);
+        }
+
+        /// <summary>
+        /// Tests the array comparer.
+        /// </summary>
+        [Test]
+        public void TestArrayComparer()
+        {
+            var cmp = (IBinaryEqualityComparer) new BinaryArrayEqualityComparer();
+
+            var ms = new BinaryHeapStream(10);
+
+            Assert.AreEqual(1, cmp.GetHashCode(ms, 0, 0, null, 0, null, null));
+
+            ms.WriteByte(1);
+            Assert.AreEqual(31 + 1, cmp.GetHashCode(ms, 0, 1, null, 0, null, null));
+
+            ms.WriteByte(3);
+            Assert.AreEqual((31 + 1) * 31 + 3, cmp.GetHashCode(ms, 0, 2, null, 0, null, null));
+        }
+
+        /// <summary>
+        /// Tests public methods of array comparer.
+        /// </summary>
+        [Test]
+        public void TestArrayComparerPublic()
+        {
+            var cmp = new BinaryArrayEqualityComparer();
+
+            var obj1 = GetBinaryObject(1, "foo", 11);
+            var obj2 = GetBinaryObject(1, "bar", 11);
+            var obj3 = GetBinaryObject(2, "foo", 11);
+            var obj4 = GetBinaryObject(2, "bar", 11);
+            var obj5 = GetBinaryObject(1, "foo", 11);
+            var obj6 = GetBinaryObject(1, "foo", 12);
+
+            // Equals.
+            Assert.IsTrue(cmp.Equals(obj1, obj1));
+            Assert.IsTrue(cmp.Equals(obj1, obj5));
+            Assert.IsFalse(cmp.Equals(obj1, obj2));
+            Assert.IsFalse(cmp.Equals(obj1, obj3));
+            Assert.IsFalse(cmp.Equals(obj1, obj4));
+            Assert.IsFalse(cmp.Equals(obj1, obj6));
+
+            Assert.IsTrue(cmp.Equals(obj2, obj2));
+            Assert.IsFalse(cmp.Equals(obj2, obj5));
+            Assert.IsFalse(cmp.Equals(obj2, obj3));
+            Assert.IsFalse(cmp.Equals(obj2, obj4));
+            Assert.IsFalse(cmp.Equals(obj2, obj6));
+
+            Assert.IsTrue(cmp.Equals(obj3, obj3));
+            Assert.IsFalse(cmp.Equals(obj3, obj5));
+            Assert.IsFalse(cmp.Equals(obj3, obj4));
+            Assert.IsFalse(cmp.Equals(obj3, obj6));
+
+            Assert.IsTrue(cmp.Equals(obj4, obj4));
+            Assert.IsFalse(cmp.Equals(obj4, obj5));
+            Assert.IsFalse(cmp.Equals(obj4, obj6));
+
+            Assert.IsTrue(cmp.Equals(obj5, obj5));
+            Assert.IsFalse(cmp.Equals(obj5, obj6));
+
+            // BinaryObject.GetHashCode.
+            Assert.AreEqual(1934949494, obj1.GetHashCode());
+            Assert.AreEqual(-2013102781, obj2.GetHashCode());
+            Assert.AreEqual(1424415317, obj3.GetHashCode());
+            Assert.AreEqual(1771330338, obj4.GetHashCode());
+            Assert.AreEqual(obj1.GetHashCode(), obj5.GetHashCode());
+            Assert.AreEqual(1934979285, cmp.GetHashCode(obj6));
+
+            // Comparer.GetHashCode.
+            Assert.AreEqual(2001751043, cmp.GetHashCode(GetBinaryObject(0, null, 0)));
+            Assert.AreEqual(194296580, cmp.GetHashCode(GetBinaryObject(1, null, 0)));
+            Assert.AreEqual(1934949494, cmp.GetHashCode(obj1));
+            Assert.AreEqual(-2013102781, cmp.GetHashCode(obj2));
+            Assert.AreEqual(1424415317, cmp.GetHashCode(obj3));
+            Assert.AreEqual(1771330338, cmp.GetHashCode(obj4));
+            Assert.AreEqual(cmp.GetHashCode(obj1), cmp.GetHashCode(obj5));
+            Assert.AreEqual(1934979285, cmp.GetHashCode(obj6));
+
+            // GetHashCode consistency.
+            foreach (var obj in new[] {obj1, obj2, obj3, obj4, obj5, obj6})
+                Assert.AreEqual(obj.GetHashCode(), cmp.GetHashCode(obj));
+        }
+
+        /// <summary>
+        /// Tests the field comparer.
+        /// </summary>
+        [Test]
+        public void TestFieldComparer()
+        {
+            var marsh = new Marshaller(new BinaryConfiguration
+            {
+                TypeConfigurations = new[]
+                {
+                    new BinaryTypeConfiguration(typeof(Foo))
+                    {
+                        EqualityComparer = new BinaryFieldEqualityComparer("Name", "Id")
+                    }
+                }
+            });
+
+            var val = new Foo {Id = 58, Name = "John"};
+            var binObj = marsh.Unmarshal<IBinaryObject>(marsh.Marshal(val), BinaryMode.ForceBinary);
+            var expHash = val.Name.GetHashCode() * 31 + val.Id.GetHashCode();
+            Assert.AreEqual(expHash, binObj.GetHashCode());
+
+            val = new Foo {Id = 95};
+            binObj = marsh.Unmarshal<IBinaryObject>(marsh.Marshal(val), BinaryMode.ForceBinary);
+            expHash = val.Id.GetHashCode();
+            Assert.AreEqual(expHash, binObj.GetHashCode());
+        }
+
+        /// <summary>
+        /// Tests the field comparer validation.
+        /// </summary>
+        [Test]
+        public void TestFieldComparerValidation()
+        {
+            var ex = Assert.Throws<IgniteException>(() => Ignition.Start(
+                new IgniteConfiguration(TestUtils.GetTestConfiguration())
+                {
+                    BinaryConfiguration = new BinaryConfiguration
+                    {
+                        TypeConfigurations = new[]
+                        {
+                            new BinaryTypeConfiguration(typeof(Foo))
+                            {
+                                EqualityComparer = new BinaryFieldEqualityComparer()
+                            }
+                        }
+                    }
+                }));
+
+            Assert.AreEqual("BinaryFieldEqualityComparer.FieldNames can not be null or empty.", ex.Message);
+        }
+
+        /// <summary>
+        /// Gets the binary object.
+        /// </summary>
+        private static IBinaryObject GetBinaryObject(int id, string name, int raw)
+        {
+            var marsh = new Marshaller(new BinaryConfiguration
+            {
+                TypeConfigurations = new[]
+                {
+                    new BinaryTypeConfiguration(typeof(Foo))
+                    {
+                        EqualityComparer = new BinaryArrayEqualityComparer()
+                    }
+                }
+            });
+
+            var bytes = marsh.Marshal(new Foo {Id = id, Name = name, Raw = raw});
+
+            return marsh.Unmarshal<IBinaryObject>(bytes, BinaryMode.ForceBinary);
+        }
+
+        private class Foo : IBinarizable
+        {
+            public int Id { get; set; }
+            public string Name { get; set; }
+            public int Raw { get; set; }
+
+            public void WriteBinary(IBinaryWriter writer)
+            {
+                writer.WriteInt("id", Id);
+                writer.WriteString("name", Name);
+
+                writer.GetRawWriter().WriteInt(Raw);
+            }
+
+            public void ReadBinary(IBinaryReader reader)
+            {
+                Id = reader.ReadInt("id");
+                Name = reader.ReadString("name");
+
+                Raw = reader.GetRawReader().ReadInt();
+            }
+        }
+
+        private class MyComparer : IEqualityComparer<IBinaryObject>
+        {
+            public bool Equals(IBinaryObject x, IBinaryObject y)
+            {
+                return true;
+            }
+
+            public int GetHashCode(IBinaryObject obj)
+            {
+                return 0;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/IO/BinaryStreamsTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/IO/BinaryStreamsTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/IO/BinaryStreamsTest.cs
index ad5358d..1ebe906 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/IO/BinaryStreamsTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/IO/BinaryStreamsTest.cs
@@ -94,6 +94,12 @@ namespace Apache.Ignite.Core.Tests.Binary.IO
 
             stream.Write(bytes, 2);
             Assert.AreEqual(2, stream.Position);
+
+            var proc = new SumStreamProcessor();
+            Assert.AreEqual(0, stream.Apply(proc, 0));
+            Assert.AreEqual(1, stream.Apply(proc, 1));
+            Assert.AreEqual(3, stream.Apply(proc, 2));
+
             flush();
 
             seek();
@@ -147,5 +153,18 @@ namespace Apache.Ignite.Core.Tests.Binary.IO
             check(() => stream.WriteShort(4), () => stream.ReadShort(), (short)4);
             check(() => stream.WriteShortArray(new short[] {4}), () => stream.ReadShortArray(1), new short[] {4});
         }
+
+        private class SumStreamProcessor : IBinaryStreamProcessor<int, int>
+        {
+            public unsafe int Invoke(byte* data, int arg)
+            {
+                int res = 0;
+
+                for (var i = 0; i < arg; i++)
+                    res += *(data + i);
+
+                return res;
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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 9d55160..fb8725c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs
@@ -447,6 +447,7 @@ namespace Apache.Ignite.Core.Tests.Cache
 
             Assert.AreEqual(x.Name, y.Name);
             Assert.AreEqual(x.FieldTypeName, y.FieldTypeName);
+            Assert.AreEqual(x.IsKeyField, y.IsKeyField);
         }
 
         /// <summary>
@@ -528,7 +529,7 @@ namespace Apache.Ignite.Core.Tests.Cache
                         Fields = new[]
                         {
                             new QueryField("length", typeof(int)), 
-                            new QueryField("name", typeof(string)), 
+                            new QueryField("name", typeof(string)) {IsKeyField = true}, 
                             new QueryField("location", typeof(string)),
                         },
                         Aliases = new [] {new QueryAlias("length", "len") },
@@ -624,7 +625,7 @@ namespace Apache.Ignite.Core.Tests.Cache
                         {
                             new QueryField("length", typeof(int)), 
                             new QueryField("name", typeof(string)), 
-                            new QueryField("location", typeof(string)),
+                            new QueryField("location", typeof(string)) {IsKeyField = true}
                         },
                         Aliases = new [] {new QueryAlias("length", "len") },
                         Indexes = new[]

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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
new file mode 100644
index 0000000..c460252
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheDmlQueriesTest.cs
@@ -0,0 +1,296 @@
+\ufeff/*
+ * 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.
+ */
+
+// ReSharper disable UnusedAutoPropertyAccessor.Local
+namespace Apache.Ignite.Core.Tests.Cache.Query
+{
+    using System.Linq;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Cache.Query;
+    using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Impl.Binary;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests Data Manipulation Language queries.
+    /// </summary>
+    public class CacheDmlQueriesTest
+    {
+        /// <summary>
+        /// Sets up test fixture.
+        /// </summary>
+        [TestFixtureSetUp]
+        public void FixtureSetUp()
+        {
+            var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                BinaryConfiguration = new BinaryConfiguration(typeof(Foo))
+                {
+                    TypeConfigurations =
+                    {
+                        new BinaryTypeConfiguration(typeof(Key))
+                        {
+                            EqualityComparer = new BinaryArrayEqualityComparer()
+                        },
+                        new BinaryTypeConfiguration(typeof(Key2))
+                        {
+                            EqualityComparer = new BinaryFieldEqualityComparer("Hi", "Lo")
+                        }
+                    }
+                }
+            };
+
+            Ignition.Start(cfg);
+        }
+
+        /// <summary>
+        /// Tears down test fixture.
+        /// </summary>
+        [TestFixtureTearDown]
+        public void FixtureTearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
+        /// <summary>
+        /// Tests primitive key.
+        /// </summary>
+        [Test]
+        public void TestPrimitiveKey()
+        {
+            var cfg = new CacheConfiguration("primitive_key", new QueryEntity(typeof(int), typeof(Foo)));
+            var cache = Ignition.GetIgnite().CreateCache<int, Foo>(cfg);
+
+            // Test insert.
+            var res = cache.QueryFields(new SqlFieldsQuery("insert into foo(_key, id, name) " +
+                                                           "values (?, ?, ?), (?, ?, ?)",
+                1, 2, "John", 3, 4, "Mary")).GetAll();
+
+            Assert.AreEqual(1, res.Count);
+            Assert.AreEqual(1, res[0].Count);
+            Assert.AreEqual(2, res[0][0]);  // 2 affected rows
+
+            var foos = cache.OrderBy(x => x.Key).ToArray();
+
+            Assert.AreEqual(2, foos.Length);
+
+            Assert.AreEqual(1, foos[0].Key);
+            Assert.AreEqual(2, foos[0].Value.Id);
+            Assert.AreEqual("John", foos[0].Value.Name);
+
+            Assert.AreEqual(3, foos[1].Key);
+            Assert.AreEqual(4, foos[1].Value.Id);
+            Assert.AreEqual("Mary", foos[1].Value.Name);
+
+            // Test key existence.
+            Assert.IsTrue(cache.ContainsKey(1));
+            Assert.IsTrue(cache.ContainsKey(3));
+        }
+
+        /// <summary>
+        /// Tests composite key (which requires QueryField.IsKeyField).
+        /// </summary>
+        [Test]
+        public void TestCompositeKeyArrayEquality()
+        {
+            var cfg = new CacheConfiguration("composite_key_arr", new QueryEntity(typeof(Key), typeof(Foo)));
+            var cache = Ignition.GetIgnite().CreateCache<Key, Foo>(cfg);
+
+            // Test insert.
+            var res = cache.QueryFields(new SqlFieldsQuery("insert into foo(hi, lo, id, name) " +
+                                               "values (1, 2, 3, 'John'), (4, 5, 6, 'Mary')")).GetAll();
+
+            Assert.AreEqual(1, res.Count);
+            Assert.AreEqual(1, res[0].Count);
+            Assert.AreEqual(2, res[0][0]);  // 2 affected rows
+
+            var foos = cache.OrderBy(x => x.Key.Lo).ToArray();
+
+            Assert.AreEqual(2, foos.Length);
+
+            Assert.AreEqual(1, foos[0].Key.Hi);
+            Assert.AreEqual(2, foos[0].Key.Lo);
+            Assert.AreEqual(3, foos[0].Value.Id);
+            Assert.AreEqual("John", foos[0].Value.Name);
+
+            Assert.AreEqual(4, foos[1].Key.Hi);
+            Assert.AreEqual(5, foos[1].Key.Lo);
+            Assert.AreEqual(6, foos[1].Value.Id);
+            Assert.AreEqual("Mary", foos[1].Value.Name);
+
+            // Existence tests check that hash codes are consistent.
+            var binary = cache.Ignite.GetBinary();
+            var binCache = cache.WithKeepBinary<IBinaryObject, IBinaryObject>();
+
+            Assert.IsTrue(cache.ContainsKey(new Key(2, 1)));
+            Assert.IsTrue(cache.ContainsKey(foos[0].Key));
+            Assert.IsTrue(binCache.ContainsKey(
+                binary.GetBuilder(typeof(Key)).SetField("hi", 1).SetField("lo", 2).Build()));
+
+            Assert.IsTrue(cache.ContainsKey(new Key(5, 4)));
+            Assert.IsTrue(cache.ContainsKey(foos[1].Key));
+            Assert.IsTrue(binCache.ContainsKey(
+                binary.GetBuilder(typeof(Key)).SetField("hi", 4).SetField("lo", 5).Build()));
+        }
+
+        /// <summary>
+        /// Tests composite key (which requires QueryField.IsKeyField).
+        /// </summary>
+        [Test]
+        public void TestCompositeKeyFieldEquality()
+        {
+            var cfg = new CacheConfiguration("composite_key_fld", new QueryEntity(typeof(Key2), typeof(Foo)));
+            var cache = Ignition.GetIgnite().CreateCache<Key2, Foo>(cfg);
+
+            // Test insert.
+            var res = cache.QueryFields(new SqlFieldsQuery("insert into foo(hi, lo, str, id, name) " +
+                                               "values (1, 2, 'Foo', 3, 'John'), (4, 5, 'Bar', 6, 'Mary')")).GetAll();
+
+            Assert.AreEqual(1, res.Count);
+            Assert.AreEqual(1, res[0].Count);
+            Assert.AreEqual(2, res[0][0]);  // 2 affected rows
+
+            var foos = cache.OrderBy(x => x.Key.Lo).ToArray();
+
+            Assert.AreEqual(2, foos.Length);
+
+            Assert.AreEqual(1, foos[0].Key.Hi);
+            Assert.AreEqual(2, foos[0].Key.Lo);
+            Assert.AreEqual("Foo", foos[0].Key.Str);
+            Assert.AreEqual(3, foos[0].Value.Id);
+            Assert.AreEqual("John", foos[0].Value.Name);
+
+            Assert.AreEqual(4, foos[1].Key.Hi);
+            Assert.AreEqual(5, foos[1].Key.Lo);
+            Assert.AreEqual("Bar", foos[1].Key.Str);
+            Assert.AreEqual(6, foos[1].Value.Id);
+            Assert.AreEqual("Mary", foos[1].Value.Name);
+
+            // Existence tests check that hash codes are consistent.
+            Assert.IsTrue(cache.ContainsKey(new Key2(2, 1, "Foo")));
+            Assert.IsTrue(cache.ContainsKey(foos[0].Key));
+
+            Assert.IsTrue(cache.ContainsKey(new Key2(5, 4, "Bar")));
+            Assert.IsTrue(cache.ContainsKey(foos[1].Key));
+        }
+
+        /// <summary>
+        /// Tests the composite key without IsKeyField configuration.
+        /// </summary>
+        [Test]
+        public void TestInvalidCompositeKey()
+        {
+            var cfg = new CacheConfiguration("invalid_composite_key", new QueryEntity
+            {
+                KeyTypeName = "Key",
+                ValueTypeName = "Foo",
+                Fields = new[]
+                {
+                    new QueryField("Lo", typeof(int)),
+                    new QueryField("Hi", typeof(int)),
+                    new QueryField("Id", typeof(int)),
+                    new QueryField("Name", typeof(string))
+                }
+            });
+
+            var cache = Ignition.GetIgnite().CreateCache<Key, Foo>(cfg);
+
+            var ex = Assert.Throws<IgniteException>(
+                () => cache.QueryFields(new SqlFieldsQuery("insert into foo(lo, hi, id, name) " +
+                                                           "values (1, 2, 3, 'John'), (4, 5, 6, 'Mary')")));
+
+            Assert.AreEqual("Ownership flag not set for binary property. Have you set 'keyFields' " +
+                            "property of QueryEntity in programmatic or XML configuration?", ex.Message);
+        }
+
+        /// <summary>
+        /// Tests DML with pure binary cache mode, without classes.
+        /// </summary>
+        [Test]
+        public void TestBinaryMode()
+        {
+            var cfg = new CacheConfiguration("binary_only", new QueryEntity
+            {
+                KeyTypeName = "CarKey",
+                ValueTypeName = "Car",
+                Fields = new[]
+                {
+                    new QueryField("VIN", typeof(string)) {IsKeyField = true},
+                    new QueryField("Id", typeof(int)) {IsKeyField = true},
+                    new QueryField("Make", typeof(string)),
+                    new QueryField("Year", typeof(int))
+                }
+            });
+
+            var cache = Ignition.GetIgnite().CreateCache<object, object>(cfg)
+                .WithKeepBinary<IBinaryObject, IBinaryObject>();
+
+            var res = cache.QueryFields(new SqlFieldsQuery("insert into car(VIN, Id, Make, Year) " +
+                                                           "values ('DLRDMC', 88, 'DeLorean', 1982)")).GetAll();
+
+            Assert.AreEqual(1, res.Count);
+            Assert.AreEqual(1, res[0].Count);
+            Assert.AreEqual(1, res[0][0]);
+
+            var car = cache.Single();
+            Assert.AreEqual("CarKey", car.Key.GetBinaryType().TypeName);
+            Assert.AreEqual("Car", car.Value.GetBinaryType().TypeName);
+        }
+
+        /// <summary>
+        /// Key.
+        /// </summary>
+        private struct Key
+        {
+            public Key(int lo, int hi) : this()
+            {
+                Lo = lo;
+                Hi = hi;
+            }
+
+            [QuerySqlField] public int Lo { get; private set; }
+            [QuerySqlField] public int Hi { get; private set; }
+        }
+
+        /// <summary>
+        /// Key.
+        /// </summary>
+        private struct Key2
+        {
+            public Key2(int lo, int hi, string str) : this()
+            {
+                Lo = lo;
+                Hi = hi;
+                Str = str;
+            }
+
+            [QuerySqlField] public int Lo { get; private set; }
+            [QuerySqlField] public int Hi { get; private set; }
+            [QuerySqlField] public string Str { get; private set; }
+        }
+
+        /// <summary>
+        /// Value.
+        /// </summary>
+        private class Foo
+        {
+            [QuerySqlField] public int Id { get; set; }
+            [QuerySqlField] public string Name { get; set; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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 55b8dcf..26e04a9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs
@@ -45,6 +45,7 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Discovery.Tcp;
     using Apache.Ignite.Core.Discovery.Tcp.Multicast;
     using Apache.Ignite.Core.Events;
+    using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.Lifecycle;
     using Apache.Ignite.Core.Log;
@@ -72,6 +73,14 @@ namespace Apache.Ignite.Core.Tests
                                 <types>
                                     <string>Apache.Ignite.Core.Tests.IgniteConfigurationSerializerTest+FooClass, Apache.Ignite.Core.Tests</string>
                                 </types>
+                                <typeConfigurations>
+                                    <binaryTypeConfiguration affinityKeyFieldName='affKeyFieldName' isEnum='true' keepDeserialized='True' typeName='typeName'>
+                                        <equalityComparer type='BinaryArrayEqualityComparer' />
+                                        <idMapper type='Apache.Ignite.Core.Tests.Binary.IdMapper, Apache.Ignite.Core.Tests' />
+                                        <nameMapper type='Apache.Ignite.Core.Tests.IgniteConfigurationSerializerTest+NameMapper, Apache.Ignite.Core.Tests' />
+                                        <serializer type='Apache.Ignite.Core.Tests.IgniteConfigurationSerializerTest+TestSerializer, Apache.Ignite.Core.Tests' />
+                                    </binaryTypeConfiguration>
+                                </typeConfigurations>
                             </binaryConfiguration>
                             <discoverySpi type='TcpDiscoverySpi' joinTimeout='0:1:0' localAddress='192.168.1.1' localPort='6655'>
                                 <ipFinder type='TcpDiscoveryMulticastIpFinder' addressRequestAttempts='7' />
@@ -86,7 +95,7 @@ namespace Apache.Ignite.Core.Tests
                                     <queryEntities>    
                                         <queryEntity keyType='System.Int32' valueType='System.String'>    
                                             <fields>
-                                                <queryField name='length' fieldType='System.Int32' />
+                                                <queryField name='length' fieldType='System.Int32' isKeyField='true' />
                                             </fields>
                                             <aliases>
                                                 <queryAlias fullName='somefield.field' alias='shortField' />
@@ -159,6 +168,7 @@ namespace Apache.Ignite.Core.Tests
             Assert.AreEqual(typeof(string), queryEntity.ValueType);
             Assert.AreEqual("length", queryEntity.Fields.Single().Name);
             Assert.AreEqual(typeof(int), queryEntity.Fields.Single().FieldType);
+            Assert.IsTrue(queryEntity.Fields.Single().IsKeyField);
             Assert.AreEqual("somefield.field", queryEntity.Aliases.Single().FullName);
             Assert.AreEqual("shortField", queryEntity.Aliases.Single().Alias);
             Assert.AreEqual(QueryIndexType.Geospatial, queryEntity.Indexes.Single().IndexType);
@@ -214,6 +224,16 @@ namespace Apache.Ignite.Core.Tests
             Assert.AreEqual(25, swap.MaximumWriteQueueSize);
             Assert.AreEqual(36, swap.ReadStripesNumber);
             Assert.AreEqual(47, swap.WriteBufferSize);
+
+            var binType = cfg.BinaryConfiguration.TypeConfigurations.Single();
+            Assert.AreEqual("typeName", binType.TypeName);
+            Assert.AreEqual("affKeyFieldName", binType.AffinityKeyFieldName);
+            Assert.IsTrue(binType.IsEnum);
+            Assert.AreEqual(true, binType.KeepDeserialized);
+            Assert.IsInstanceOf<BinaryArrayEqualityComparer>(binType.EqualityComparer);
+            Assert.IsInstanceOf<IdMapper>(binType.IdMapper);
+            Assert.IsInstanceOf<NameMapper>(binType.NameMapper);
+            Assert.IsInstanceOf<TestSerializer>(binType.Serializer);
         }
 
         /// <summary>
@@ -334,12 +354,12 @@ namespace Apache.Ignite.Core.Tests
             };
 
             Assert.AreEqual(FixLineEndings(@"<?xml version=""1.0"" encoding=""utf-16""?>
-<igniteConfiguration gridName=""myGrid"" clientMode=""true"" xmlns=""http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection"">
+<igniteConfiguration clientMode=""true"" gridName=""myGrid"" xmlns=""http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection"">
   <cacheConfiguration>
-    <cacheConfiguration name=""myCache"" cacheMode=""Replicated"">
+    <cacheConfiguration cacheMode=""Replicated"" name=""myCache"">
       <queryEntities>
-        <queryEntity valueTypeName=""java.lang.Integer"" valueType=""System.Int32"" />
-        <queryEntity keyTypeName=""java.lang.Integer"" keyType=""System.Int32"" valueTypeName=""java.lang.String"" valueType=""System.String"" />
+        <queryEntity valueType=""System.Int32"" valueTypeName=""java.lang.Integer"" />
+        <queryEntity keyType=""System.Int32"" keyTypeName=""java.lang.Integer"" valueType=""System.String"" valueTypeName=""java.lang.String"" />
       </queryEntities>
     </cacheConfiguration>
   </cacheConfiguration>
@@ -364,12 +384,12 @@ namespace Apache.Ignite.Core.Tests
             }
 
             Assert.AreEqual(FixLineEndings(@"<?xml version=""1.0"" encoding=""utf-16""?>
-<igCfg gridName=""myGrid"" clientMode=""true"" xmlns=""http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection"">
+<igCfg clientMode=""true"" gridName=""myGrid"" xmlns=""http://ignite.apache.org/schema/dotnet/IgniteConfigurationSection"">
  <cacheConfiguration>
-  <cacheConfiguration name=""myCache"" cacheMode=""Replicated"">
+  <cacheConfiguration cacheMode=""Replicated"" name=""myCache"">
    <queryEntities>
-    <queryEntity valueTypeName=""java.lang.Integer"" valueType=""System.Int32"" />
-    <queryEntity keyTypeName=""java.lang.Integer"" keyType=""System.Int32"" valueTypeName=""java.lang.String"" valueType=""System.String"" />
+    <queryEntity valueType=""System.Int32"" valueTypeName=""java.lang.Integer"" />
+    <queryEntity keyType=""System.Int32"" keyTypeName=""java.lang.Integer"" valueType=""System.String"" valueTypeName=""java.lang.String"" />
    </queryEntities>
   </cacheConfiguration>
  </cacheConfiguration>
@@ -547,7 +567,8 @@ namespace Apache.Ignite.Core.Tests
                             TypeName = "typeName",
                             IdMapper = new IdMapper(),
                             NameMapper = new NameMapper(),
-                            Serializer = new TestSerializer()
+                            Serializer = new TestSerializer(),
+                            EqualityComparer = new BinaryArrayEqualityComparer()
                         },
                         new BinaryTypeConfiguration
                         {
@@ -555,7 +576,8 @@ namespace Apache.Ignite.Core.Tests
                             KeepDeserialized = false,
                             AffinityKeyFieldName = "affKeyFieldName",
                             TypeName = "typeName2",
-                            Serializer = new BinaryReflectiveSerializer()
+                            Serializer = new BinaryReflectiveSerializer(),
+                            EqualityComparer = new BinaryFieldEqualityComparer()
                         }
                     },
                     Types = new[] {typeof (string).FullName},
@@ -595,7 +617,7 @@ namespace Apache.Ignite.Core.Tests
                             {
                                 Fields = new[]
                                 {
-                                    new QueryField("field", typeof (int))
+                                    new QueryField("field", typeof (int)) { IsKeyField = true }
                                 },
                                 Indexes = new[]
                                 {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
index 2e39b9b..86ece98 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
@@ -34,6 +34,7 @@ namespace Apache.Ignite.Core.Tests
     using Apache.Ignite.Core.Discovery.Tcp.Static;
     using Apache.Ignite.Core.Events;
     using Apache.Ignite.Core.Impl;
+    using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.SwapSpace.File;
     using Apache.Ignite.Core.Transactions;
     using NUnit.Framework;
@@ -181,6 +182,18 @@ namespace Apache.Ignite.Core.Tests
                 Assert.AreEqual(swap.MaximumWriteQueueSize, resSwap.MaximumWriteQueueSize);
                 Assert.AreEqual(swap.ReadStripesNumber, resSwap.ReadStripesNumber);
                 Assert.AreEqual(swap.WriteBufferSize, resSwap.WriteBufferSize);
+
+                var binCfg = cfg.BinaryConfiguration;
+                Assert.IsFalse(binCfg.CompactFooter);
+
+                var typ = binCfg.TypeConfigurations.Single();
+                Assert.AreEqual("myType", typ.TypeName);
+                Assert.IsTrue(typ.IsEnum);
+                Assert.AreEqual("affKey", typ.AffinityKeyFieldName);
+                Assert.AreEqual(false, typ.KeepDeserialized);
+
+                CollectionAssert.AreEqual(new[] {"fld1", "fld2"}, 
+                    ((BinaryFieldEqualityComparer)typ.EqualityComparer).FieldNames);
             }
         }
 
@@ -513,6 +526,21 @@ namespace Apache.Ignite.Core.Tests
                     WriteBufferSize = 9,
                     BaseDirectory = Path.GetTempPath(),
                     MaximumSparsity = 11.22f
+                },
+                BinaryConfiguration = new BinaryConfiguration
+                {
+                    CompactFooter = false,
+                    TypeConfigurations = new[]
+                    {
+                        new BinaryTypeConfiguration
+                        {
+                            TypeName = "myType",
+                            IsEnum = true,
+                            AffinityKeyFieldName = "affKey",
+                            KeepDeserialized = false,
+                            EqualityComparer = new BinaryFieldEqualityComparer("fld1", "fld2")
+                        }
+                    }
                 }
             };
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index a80dfc0..42ccdd4 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -90,6 +90,8 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Binary\BinaryArrayEqualityComparer.cs" />
+    <Compile Include="Impl\Binary\BinaryFieldEqualityComparer.cs" />
     <Compile Include="Binary\BinaryReflectiveSerializer.cs" />
     <Compile Include="Common\JavaException.cs" />
     <Compile Include="DataStructures\Configuration\Package-Info.cs" />
@@ -97,8 +99,10 @@
     <Compile Include="Discovery\Tcp\Multicast\Package-Info.cs" />
     <Compile Include="Discovery\Tcp\Package-Info.cs" />
     <Compile Include="Discovery\Tcp\Static\Package-Info.cs" />
+    <Compile Include="Impl\Binary\BinaryEqualityComparerSerializer.cs" />
     <Compile Include="Impl\Binary\BinaryProcessor.cs" />
     <Compile Include="Impl\Binary\BinaryReflectiveSerializerInternal.cs" />
+    <Compile Include="Impl\Binary\IBinaryEqualityComparer.cs" />
     <Compile Include="Impl\Binary\IBinarySerializerInternal.cs" />
     <Compile Include="Binary\Package-Info.cs" />
     <Compile Include="Cache\Affinity\AffinityKey.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs
new file mode 100644
index 0000000..09f7f0f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs
@@ -0,0 +1,149 @@
+\ufeff/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Binary
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+
+    /// <summary>
+    /// Compares binary object equality using underlying byte array.
+    /// </summary>
+    public class BinaryArrayEqualityComparer : IEqualityComparer<IBinaryObject>, IBinaryEqualityComparer,
+        IBinaryStreamProcessor<KeyValuePair<int,int>, int>
+    {
+        /// <summary>
+        /// Determines whether the specified objects are equal.
+        /// </summary>
+        /// <param name="x">The first object to compare.</param>
+        /// <param name="y">The second object to compare.</param>
+        /// <returns>
+        /// true if the specified objects are equal; otherwise, false.
+        /// </returns>
+        public bool Equals(IBinaryObject x, IBinaryObject y)
+        {
+            if (x == null)
+                return y == null;
+
+            if (y == null)
+                return false;
+
+            if (ReferenceEquals(x, y))
+                return true;
+
+            var binx = GetBinaryObject(x);
+            var biny = GetBinaryObject(y);
+
+            var lenx = GetDataLength(binx);
+            var leny = GetDataLength(biny);
+
+            if (lenx != leny)
+                return false;
+
+            var startx = GetDataStart(binx);
+            var starty = GetDataStart(biny);
+
+            var arrx = binx.Data;
+            var arry = biny.Data;
+
+            for (var i = 0; i < lenx; i++)
+            {
+                if (arrx[i + startx] != arry[i + starty])
+                    return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Returns a hash code for this instance.
+        /// </summary>
+        /// <param name="obj">The object.</param>
+        /// <returns>
+        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
+        /// </returns>
+        public int GetHashCode(IBinaryObject obj)
+        {
+            if (obj == null)
+                return 0;
+
+            var binObj = GetBinaryObject(obj);
+
+            var arg = new KeyValuePair<int, int>(GetDataStart(binObj), GetDataLength(binObj));
+
+            return new BinaryHeapStream(binObj.Data).Apply(this, arg);
+        }
+
+        /** <inheritdoc /> */
+        int IBinaryEqualityComparer.GetHashCode(IBinaryStream stream, int startPos, int length, 
+            BinaryObjectSchemaHolder schema, int schemaId, Marshaller marshaller, IBinaryTypeDescriptor desc)
+        {
+            Debug.Assert(stream != null);
+            Debug.Assert(startPos >= 0);
+            Debug.Assert(length >= 0);
+
+            var arg = new KeyValuePair<int, int>(startPos, length);
+
+            return stream.Apply(this, arg);
+        }
+
+        /** <inheritdoc /> */
+        unsafe int IBinaryStreamProcessor<KeyValuePair<int, int>, int>.Invoke(byte* data, KeyValuePair<int, int> arg)
+        {
+            var hash = 1;
+            var ptr = data + arg.Key;
+
+            for (var i = 0; i < arg.Value; i++)
+                hash = 31 * hash + *(ptr + i);
+
+            return hash;
+        }
+
+        /// <summary>
+        /// Casts to <see cref="BinaryObject"/> or throws an error.
+        /// </summary>
+        private static BinaryObject GetBinaryObject(IBinaryObject obj)
+        {
+            var binObj = obj as BinaryObject;
+
+            if (binObj != null)
+                return binObj;
+
+            throw new NotSupportedException(string.Format("{0} of type {1} is not supported.",
+                typeof(IBinaryObject), obj.GetType()));
+        }
+
+        /// <summary>
+        /// Gets the non-raw data length.
+        /// </summary>
+        private static int GetDataLength(BinaryObject binObj)
+        {
+            return binObj.Header.FooterStartOffset - BinaryObjectHeader.Size;
+        }
+
+        /// <summary>
+        /// Gets the data starting position.
+        /// </summary>
+        private static int GetDataStart(BinaryObject binObj)
+        {
+            return binObj.Offset + BinaryObjectHeader.Size;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs
index 51df907..c738f28 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs
@@ -141,5 +141,29 @@ namespace Apache.Ignite.Core.Binary
         {
             get { return _compactFooter; }
         }
+
+        /// <summary>
+        /// Merges other config into this.
+        /// </summary>
+        internal void MergeTypes(BinaryConfiguration localConfig)
+        {
+            if (TypeConfigurations == null)
+            {
+                TypeConfigurations = localConfig.TypeConfigurations;
+            }
+            else if (localConfig.TypeConfigurations != null)
+            {
+                // Both configs are present.
+                // Local configuration is more complete and takes preference when it exists for a given type.
+                var localTypeNames = new HashSet<string>(localConfig.TypeConfigurations.Select(x => x.TypeName), 
+                    StringComparer.OrdinalIgnoreCase);
+
+                var configs = new List<BinaryTypeConfiguration>(localConfig.TypeConfigurations);
+
+                configs.AddRange(TypeConfigurations.Where(x=>!localTypeNames.Contains(x.TypeName)));
+
+                TypeConfigurations = configs;
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs
index c36b9fd..722197c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs
@@ -18,6 +18,7 @@
 namespace Apache.Ignite.Core.Binary
 {
     using System;
+    using System.Collections.Generic;
     using Apache.Ignite.Core.Impl.Common;
 
     /// <summary>
@@ -69,6 +70,7 @@ namespace Apache.Ignite.Core.Binary
             TypeName = cfg.TypeName;
             KeepDeserialized = cfg.KeepDeserialized;
             IsEnum = cfg.IsEnum;
+            EqualityComparer = cfg.EqualityComparer;
         }
 
         /// <summary>
@@ -113,6 +115,18 @@ namespace Apache.Ignite.Core.Binary
         public bool IsEnum { get; set; }
 
         /// <summary>
+        /// Gets or sets the equality comparer to compute hash codes and compare objects
+        /// in <see cref="IBinaryObject"/> form.
+        /// This comparer is important only for types that are used as cache keys.
+        /// <para />
+        /// Null means legacy behavior: hash code is computed by calling <see cref="object.GetHashCode"/>, equality is
+        /// computed by comparing bytes in serialized (binary) form.
+        /// <para />
+        /// Only predefined implementations are supported: <see cref="BinaryArrayEqualityComparer"/>.
+        /// </summary>
+        public IEqualityComparer<IBinaryObject> EqualityComparer { get; set; }
+
+        /// <summary>
         /// Returns a string that represents the current object.
         /// </summary>
         /// <returns>

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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 adfe9e1..ff9af37 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
@@ -178,8 +178,11 @@ namespace Apache.Ignite.Core.Cache.Configuration
             ValueTypeName = reader.ReadString();
 
             var count = reader.ReadInt();
-            Fields = count == 0 ? null : Enumerable.Range(0, count).Select(x =>
-                    new QueryField(reader.ReadString(), reader.ReadString())).ToList();
+            Fields = count == 0
+                ? null
+                : Enumerable.Range(0, count).Select(x =>
+                    new QueryField(reader.ReadString(), reader.ReadString()) {IsKeyField = reader.ReadBoolean()})
+                    .ToList();
 
             count = reader.ReadInt();
             Aliases = count == 0 ? null : Enumerable.Range(0, count)
@@ -205,6 +208,7 @@ namespace Apache.Ignite.Core.Cache.Configuration
                 {
                     writer.WriteString(field.Name);
                     writer.WriteString(field.FieldTypeName);
+                    writer.WriteBoolean(field.IsKeyField);
                 }
             }
             else
@@ -264,16 +268,19 @@ namespace Apache.Ignite.Core.Cache.Configuration
         /// <summary>
         /// Rescans the attributes in <see cref="KeyType"/> and <see cref="ValueType"/>.
         /// </summary>
-        private void RescanAttributes(params Type[] types)
+        private void RescanAttributes(Type keyType, Type valType)
         {
-            if (types.Length == 0 || types.All(t => t == null))
+            if (keyType == null && valType == null)
                 return;
 
             var fields = new List<QueryField>();
             var indexes = new List<QueryIndexEx>();
 
-            foreach (var type in types.Where(t => t != null))
-                ScanAttributes(type, fields, indexes, null, new HashSet<Type>());
+            if (keyType != null)
+                ScanAttributes(keyType, fields, indexes, null, new HashSet<Type>(), true);
+
+            if (valType != null)
+                ScanAttributes(valType, fields, indexes, null, new HashSet<Type>(), false);
 
             if (fields.Any())
                 Fields = fields;
@@ -308,15 +315,17 @@ namespace Apache.Ignite.Core.Cache.Configuration
         }
 
         /// <summary>
-        /// Scans specified type for occurences of <see cref="QuerySqlFieldAttribute"/>.
+        /// Scans specified type for occurences of <see cref="QuerySqlFieldAttribute" />.
         /// </summary>
         /// <param name="type">The type.</param>
         /// <param name="fields">The fields.</param>
         /// <param name="indexes">The indexes.</param>
         /// <param name="parentPropName">Name of the parent property.</param>
         /// <param name="visitedTypes">The visited types.</param>
+        /// <param name="isKey">Whether this is a key type.</param>
+        /// <exception cref="System.InvalidOperationException">Recursive Query Field definition detected:  + type</exception>
         private static void ScanAttributes(Type type, List<QueryField> fields, List<QueryIndexEx> indexes, 
-            string parentPropName, ISet<Type> visitedTypes)
+            string parentPropName, ISet<Type> visitedTypes, bool isKey)
         {
             Debug.Assert(type != null);
             Debug.Assert(fields != null);
@@ -344,9 +353,9 @@ namespace Apache.Ignite.Core.Cache.Configuration
                     if (parentPropName != null)
                         columnName = parentPropName + "." + columnName;
 
-                    fields.Add(new QueryField(columnName, memberInfo.Value));
+                    fields.Add(new QueryField(columnName, memberInfo.Value) {IsKeyField = isKey});
 
-                    ScanAttributes(memberInfo.Value, fields, indexes, columnName, visitedTypes);
+                    ScanAttributes(memberInfo.Value, fields, indexes, columnName, visitedTypes, isKey);
                 }
 
                 foreach (var attr in customAttributes.OfType<QueryTextFieldAttribute>())
@@ -359,9 +368,9 @@ namespace Apache.Ignite.Core.Cache.Configuration
                     if (parentPropName != null)
                         columnName = parentPropName + "." + columnName;
 
-                    fields.Add(new QueryField(columnName, memberInfo.Value));
+                    fields.Add(new QueryField(columnName, memberInfo.Value) {IsKeyField = isKey});
 
-                    ScanAttributes(memberInfo.Value, fields, indexes, columnName, visitedTypes);
+                    ScanAttributes(memberInfo.Value, fields, indexes, columnName, visitedTypes, isKey);
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/b7908d7a/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 12028e2..c33aa57 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryField.cs
@@ -109,6 +109,12 @@ namespace Apache.Ignite.Core.Cache.Configuration
         }
 
         /// <summary>
+        /// Gets or sets a value indicating whether this field belongs to the cache key.
+        /// Proper value here is required for SQL DML queries which create/modify cache keys.
+        /// </summary>
+        public bool IsKeyField { get; set; }
+
+        /// <summary>
         /// Validates this instance and outputs information to the log, if necessary.
         /// </summary>
         internal void Validate(ILogger log, string logInfo)


[6/8] ignite git commit: IGNITE-4530: Add support to provide AWSCredentialsProvider to TcpDiscoveryS3IpFinder in addition to just AWSCredentials Reviewed and merged by Denis Magda (dmagda@apache.org)

Posted by pt...@apache.org.
IGNITE-4530: Add support to provide AWSCredentialsProvider to TcpDiscoveryS3IpFinder in addition to just AWSCredentials
Reviewed and merged by Denis Magda (dmagda@apache.org)


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/80bcf273
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/80bcf273
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/80bcf273

Branch: refs/heads/ignite-2.0
Commit: 80bcf2739c3f84769805005d7c0acb5769606e7d
Parents: 177d7f4
Author: Aliaksandr Kazlou <al...@gmail.com>
Authored: Wed Jan 18 11:39:36 2017 -0800
Committer: Denis Magda <dm...@gridgain.com>
Committed: Wed Jan 18 11:39:36 2017 -0800

----------------------------------------------------------------------
 .../tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java | 37 ++++++++-
 .../TcpDiscoveryS3IpFinderAbstractSelfTest.java | 84 ++++++++++++++++++++
 ...3IpFinderAwsCredentialsProviderSelfTest.java | 46 +++++++++++
 ...scoveryS3IpFinderAwsCredentialsSelfTest.java | 45 +++++++++++
 .../s3/TcpDiscoveryS3IpFinderSelfTest.java      | 79 ------------------
 .../ignite/testsuites/IgniteS3TestSuite.java    | 26 +++---
 6 files changed, 225 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/80bcf273/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
----------------------------------------------------------------------
diff --git a/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java b/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
index 86e4eb2..53d6532 100644
--- a/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
+++ b/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
@@ -20,6 +20,7 @@ package org.apache.ignite.spi.discovery.tcp.ipfinder.s3;
 import com.amazonaws.AmazonClientException;
 import com.amazonaws.ClientConfiguration;
 import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.AWSCredentialsProvider;
 import com.amazonaws.services.s3.AmazonS3;
 import com.amazonaws.services.s3.AmazonS3Client;
 import com.amazonaws.services.s3.model.ObjectListing;
@@ -51,7 +52,8 @@ import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinderAdapter;
  * <h1 class="header">Configuration</h1>
  * <h2 class="header">Mandatory</h2>
  * <ul>
- *      <li>AWS credentials (see {@link #setAwsCredentials(AWSCredentials)})</li>
+ *      <li>AWS credentials (see {@link #setAwsCredentials(AWSCredentials)} and
+ *      {@link #setAwsCredentials(AWSCredentialsProvider)})</li>
  *      <li>Bucket name (see {@link #setBucketName(String)})</li>
  * </ul>
  * <h2 class="header">Optional</h2>
@@ -111,6 +113,10 @@ public class TcpDiscoveryS3IpFinder extends TcpDiscoveryIpFinderAdapter {
     @GridToStringExclude
     private AWSCredentials cred;
 
+    /** AWS Credentials. */
+    @GridToStringExclude
+    private AWSCredentialsProvider credProvider;
+
     /**
      * Constructor.
      */
@@ -236,7 +242,7 @@ public class TcpDiscoveryS3IpFinder extends TcpDiscoveryIpFinderAdapter {
     private void initClient() throws IgniteSpiException {
         if (initGuard.compareAndSet(false, true))
             try {
-                if (cred == null)
+                if (cred == null && credProvider == null)
                     throw new IgniteSpiException("AWS credentials are not set.");
 
                 if (cfg == null)
@@ -245,7 +251,7 @@ public class TcpDiscoveryS3IpFinder extends TcpDiscoveryIpFinderAdapter {
                 if (F.isEmpty(bucketName))
                     throw new IgniteSpiException("Bucket name is null or empty (provide bucket name and restart).");
 
-                s3 = cfg != null ? new AmazonS3Client(cred, cfg) : new AmazonS3Client(cred);
+                s3 = createAmazonS3Client();
 
                 if (!s3.doesBucketExist(bucketName)) {
                     try {
@@ -288,6 +294,17 @@ public class TcpDiscoveryS3IpFinder extends TcpDiscoveryIpFinderAdapter {
     }
 
     /**
+     * Instantiates {@code AmazonS3Client} instance.
+     *
+     * @return Client instance to use to connect to AWS.
+     */
+    private AmazonS3Client createAmazonS3Client() {
+        return cfg != null
+            ? (cred != null ? new AmazonS3Client(cred, cfg) : new AmazonS3Client(credProvider, cfg))
+            : (cred != null ? new AmazonS3Client(cred) : new AmazonS3Client(credProvider));
+    }
+
+    /**
      * Sets bucket name for IP finder.
      *
      * @param bucketName Bucket name.
@@ -310,7 +327,7 @@ public class TcpDiscoveryS3IpFinder extends TcpDiscoveryIpFinderAdapter {
     }
 
     /**
-     * Sets AWS credentials.
+     * Sets AWS credentials. Either use {@link #setAwsCredentials(AWSCredentialsProvider)} or this one.
      * <p>
      * For details refer to Amazon S3 API reference.
      *
@@ -321,6 +338,18 @@ public class TcpDiscoveryS3IpFinder extends TcpDiscoveryIpFinderAdapter {
         this.cred = cred;
     }
 
+    /**
+     * Sets AWS credentials provider. Either use {@link #setAwsCredentials(AWSCredentials)} or this one.
+     * <p>
+     * For details refer to Amazon S3 API reference.
+     *
+     * @param credProvider AWS credentials provider.
+     */
+    @IgniteSpiConfiguration(optional = false)
+    public void setAwsCredentials(AWSCredentialsProvider credProvider) {
+        this.credProvider = credProvider;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(TcpDiscoveryS3IpFinder.class, this, "super", super.toString());

http://git-wip-us.apache.org/repos/asf/ignite/blob/80bcf273/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java
new file mode 100644
index 0000000..d17416f
--- /dev/null
+++ b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.spi.discovery.tcp.ipfinder.s3;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Collection;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinderAbstractSelfTest;
+import org.apache.ignite.testsuites.IgniteIgnore;
+import org.apache.ignite.testsuites.IgniteS3TestSuite;
+
+/**
+ * Abstract TcpDiscoveryS3IpFinder to test with different ways of setting AWS credentials.
+ */
+abstract class TcpDiscoveryS3IpFinderAbstractSelfTest
+    extends TcpDiscoveryIpFinderAbstractSelfTest<TcpDiscoveryS3IpFinder> {
+    /**
+     * Constructor.
+     *
+     * @throws Exception If any error occurs.
+     */
+    protected TcpDiscoveryS3IpFinderAbstractSelfTest() throws Exception {
+    }
+
+    /** {@inheritDoc} */
+    @Override protected TcpDiscoveryS3IpFinder ipFinder() throws Exception {
+        TcpDiscoveryS3IpFinder finder = new TcpDiscoveryS3IpFinder();
+
+        injectLogger(finder);
+
+        assert finder.isShared() : "Ip finder should be shared by default.";
+
+        setAwsCredentials(finder);
+
+        // Bucket name should be unique for the host to parallel test run on one bucket.
+        String bucketName = IgniteS3TestSuite.getBucketName(
+            "ip-finder-unit-test-bucket-" + InetAddress.getLocalHost().getAddress()[3]);
+        finder.setBucketName(bucketName);
+
+        for (int i = 0; i < 5; i++) {
+            Collection<InetSocketAddress> addrs = finder.getRegisteredAddresses();
+
+            if (!addrs.isEmpty())
+                finder.unregisterAddresses(addrs);
+            else
+                return finder;
+
+            U.sleep(1000);
+        }
+
+        if (!finder.getRegisteredAddresses().isEmpty())
+            throw new Exception("Failed to initialize IP finder.");
+
+        return finder;
+    }
+
+    /** {@inheritDoc} */
+    @IgniteIgnore("https://issues.apache.org/jira/browse/IGNITE-2420")
+    @Override public void testIpFinder() throws Exception {
+        super.testIpFinder();
+    }
+
+    /**
+     * Set AWS credentials into the provided {@code finder}.
+     * @param finder finder credentials to set into
+     */
+    protected abstract void setAwsCredentials(TcpDiscoveryS3IpFinder finder);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/80bcf273/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest.java b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest.java
new file mode 100644
index 0000000..6952b54
--- /dev/null
+++ b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.spi.discovery.tcp.ipfinder.s3;
+
+import com.amazonaws.auth.AWSStaticCredentialsProvider;
+import com.amazonaws.auth.BasicAWSCredentials;
+import org.apache.ignite.testsuites.IgniteS3TestSuite;
+
+/**
+ * TcpDiscoveryS3IpFinder test using AWS credentials provider.
+ */
+public class TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest extends TcpDiscoveryS3IpFinderAbstractSelfTest {
+    /**
+     * Constructor.
+     *
+     * @throws Exception If any error occurs.
+     */
+    public TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest() throws Exception {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void setAwsCredentials(TcpDiscoveryS3IpFinder finder) {
+        finder.setAwsCredentials(new AWSStaticCredentialsProvider(
+            new BasicAWSCredentials(IgniteS3TestSuite.getAccessKey(), IgniteS3TestSuite.getSecretKey())));
+    }
+
+    @Override public void testIpFinder() throws Exception {
+        super.testIpFinder();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/80bcf273/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAwsCredentialsSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAwsCredentialsSelfTest.java b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAwsCredentialsSelfTest.java
new file mode 100644
index 0000000..7447378
--- /dev/null
+++ b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAwsCredentialsSelfTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.spi.discovery.tcp.ipfinder.s3;
+
+import com.amazonaws.auth.BasicAWSCredentials;
+import org.apache.ignite.testsuites.IgniteS3TestSuite;
+
+/**
+ * TcpDiscoveryS3IpFinder test using AWS credentials.
+ */
+public class TcpDiscoveryS3IpFinderAwsCredentialsSelfTest extends TcpDiscoveryS3IpFinderAbstractSelfTest {
+    /**
+     * Constructor.
+     *
+     * @throws Exception If any error occurs.
+     */
+    public TcpDiscoveryS3IpFinderAwsCredentialsSelfTest() throws Exception {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void setAwsCredentials(TcpDiscoveryS3IpFinder finder) {
+        finder.setAwsCredentials(new BasicAWSCredentials(IgniteS3TestSuite.getAccessKey(),
+            IgniteS3TestSuite.getSecretKey()));
+    }
+
+    @Override public void testIpFinder() throws Exception {
+        super.testIpFinder();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/80bcf273/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderSelfTest.java b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderSelfTest.java
deleted file mode 100644
index a1ebc8f..0000000
--- a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderSelfTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.spi.discovery.tcp.ipfinder.s3;
-
-import com.amazonaws.auth.BasicAWSCredentials;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.Collection;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinderAbstractSelfTest;
-import org.apache.ignite.testsuites.IgniteIgnore;
-import org.apache.ignite.testsuites.IgniteS3TestSuite;
-
-/**
- * TcpDiscoveryS3IpFinder test.
- */
-public class TcpDiscoveryS3IpFinderSelfTest
-    extends TcpDiscoveryIpFinderAbstractSelfTest<TcpDiscoveryS3IpFinder> {
-    /**
-     * Constructor.
-     *
-     * @throws Exception If any error occurs.
-     */
-    public TcpDiscoveryS3IpFinderSelfTest() throws Exception {
-        // No-op.
-    }
-
-    /** {@inheritDoc} */
-    @Override protected TcpDiscoveryS3IpFinder ipFinder() throws Exception {
-        TcpDiscoveryS3IpFinder finder = new TcpDiscoveryS3IpFinder();
-
-        injectLogger(finder);
-
-        assert finder.isShared() : "Ip finder should be shared by default.";
-
-        finder.setAwsCredentials(new BasicAWSCredentials(IgniteS3TestSuite.getAccessKey(),
-            IgniteS3TestSuite.getSecretKey()));
-
-        // Bucket name should be unique for the host to parallel test run on one bucket.
-        finder.setBucketName("ip-finder-unit-test-bucket-" + InetAddress.getLocalHost().getAddress()[3]);
-
-        for (int i = 0; i < 5; i++) {
-            Collection<InetSocketAddress> addrs = finder.getRegisteredAddresses();
-
-            if (!addrs.isEmpty())
-                finder.unregisterAddresses(addrs);
-            else
-                return finder;
-
-            U.sleep(1000);
-        }
-
-        if (!finder.getRegisteredAddresses().isEmpty())
-            throw new Exception("Failed to initialize IP finder.");
-
-        return finder;
-    }
-
-    /** {@inheritDoc} */
-    @IgniteIgnore("https://issues.apache.org/jira/browse/IGNITE-2420")
-    @Override public void testIpFinder() throws Exception {
-        super.testIpFinder();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/80bcf273/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java
----------------------------------------------------------------------
diff --git a/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java b/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java
index 86322e6..a703c66 100644
--- a/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java
+++ b/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java
@@ -23,7 +23,8 @@ import org.apache.ignite.spi.checkpoint.s3.S3CheckpointSpiConfigSelfTest;
 import org.apache.ignite.spi.checkpoint.s3.S3CheckpointSpiSelfTest;
 import org.apache.ignite.spi.checkpoint.s3.S3CheckpointSpiStartStopSelfTest;
 import org.apache.ignite.spi.checkpoint.s3.S3SessionCheckpointSelfTest;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinderSelfTest;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinderAwsCredentialsSelfTest;
 import org.apache.ignite.testframework.IgniteTestSuite;
 
 /**
@@ -45,7 +46,8 @@ public class IgniteS3TestSuite extends TestSuite {
         suite.addTestSuite(S3SessionCheckpointSelfTest.class);
 
         // S3 IP finder.
-        suite.addTestSuite(TcpDiscoveryS3IpFinderSelfTest.class);
+        suite.addTestSuite(TcpDiscoveryS3IpFinderAwsCredentialsSelfTest.class);
+        suite.addTestSuite(TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest.class);
 
         return suite;
     }
@@ -54,20 +56,26 @@ public class IgniteS3TestSuite extends TestSuite {
      * @return Access key.
      */
     public static String getAccessKey() {
-        String key = System.getenv("test.amazon.access.key");
-
-        assert key != null : "Environment variable 'test.amazon.access.key' is not set";
-
-        return key;
+        return getRequiredEnvVar("test.amazon.access.key");
     }
 
     /**
      * @return Access key.
      */
     public static String getSecretKey() {
-        String key = System.getenv("test.amazon.secret.key");
+        return getRequiredEnvVar("test.amazon.secret.key");
+    }
+
+    public static String getBucketName(final String defaultBucketName) {
+        String value = System.getenv("test.s3.bucket.name");
+
+        return value == null ? defaultBucketName : value;
+    }
+
+    private static String getRequiredEnvVar(String name) {
+        String key = System.getenv(name);
 
-        assert key != null : "Environment variable 'test.amazon.secret.key' is not set";
+        assert key != null : String.format("Environment variable '%s' is not set", name);
 
         return key;
     }


[4/8] ignite git commit: IGNITE-4045 .NET: Support DML API - fix code analysis warnings

Posted by pt...@apache.org.
IGNITE-4045 .NET: Support DML API - fix code analysis warnings


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/7b711a32
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/7b711a32
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/7b711a32

Branch: refs/heads/ignite-2.0
Commit: 7b711a3248b0dafdcea195766b50be4d44656f7f
Parents: b7908d7
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Mon Jan 16 19:50:35 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Mon Jan 16 19:50:35 2017 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.csproj                   |  1 +
 .../Binary/BinaryArrayEqualityComparer.cs       |  2 +-
 .../Binary/BinaryEqualityComparerSerializer.cs  |  2 +-
 .../Impl/Binary/DateTimeHolder.cs               | 22 +++++++++++-
 .../Impl/Binary/Io/IBinaryStream.cs             | 16 ---------
 .../Impl/Binary/Io/IBinaryStreamProcessor.cs    | 36 ++++++++++++++++++++
 6 files changed, 60 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/7b711a32/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index 42ccdd4..d58c872 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -185,6 +185,7 @@
     <Compile Include="Common\IgniteGuid.cs" />
     <Compile Include="Common\Package-Info.cs" />
     <Compile Include="Impl\Binary\DateTimeSerializer.cs" />
+    <Compile Include="Impl\Binary\IO\IBinaryStreamProcessor.cs" />
     <Compile Include="Impl\Binary\SerializableSerializer.cs" />
     <Compile Include="Impl\Binary\BinaryWriterExtensions.cs" />
     <Compile Include="Impl\Cache\Affinity\AffinityFunctionBase.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/7b711a32/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs
index 09f7f0f..4e29a91 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryArrayEqualityComparer.cs
@@ -26,7 +26,7 @@ namespace Apache.Ignite.Core.Binary
     /// <summary>
     /// Compares binary object equality using underlying byte array.
     /// </summary>
-    public class BinaryArrayEqualityComparer : IEqualityComparer<IBinaryObject>, IBinaryEqualityComparer,
+    public sealed class BinaryArrayEqualityComparer : IEqualityComparer<IBinaryObject>, IBinaryEqualityComparer,
         IBinaryStreamProcessor<KeyValuePair<int,int>, int>
     {
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/7b711a32/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs
index aa4795e..bb26076 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEqualityComparerSerializer.cs
@@ -92,7 +92,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                     };
 
                 default:
-                    throw new ArgumentOutOfRangeException();
+                    throw new ArgumentOutOfRangeException("reader", type, "Invalid EqualityComparer type code");
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7b711a32/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
index 6adb847..21c56a9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/DateTimeHolder.cs
@@ -69,7 +69,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         public override bool Equals(object obj)
         {
             if (ReferenceEquals(null, obj)) return false;
-            return obj is DateTimeHolder && _item.Equals(((DateTimeHolder) obj)._item);
+            return obj is DateTimeHolder && Equals((DateTimeHolder) obj);
         }
 
         /** <inheritDoc /> */
@@ -77,5 +77,25 @@ namespace Apache.Ignite.Core.Impl.Binary
         {
             return _item.GetHashCode();
         }
+
+        /** <inheritDoc /> */
+        public static bool operator ==(DateTimeHolder left, DateTimeHolder right)
+        {
+            return left.Equals(right);
+        }
+
+        /** <inheritDoc /> */
+        public static bool operator !=(DateTimeHolder left, DateTimeHolder right)
+        {
+            return !left.Equals(right);
+        }
+
+        /// <summary>
+        /// Checks equality.
+        /// </summary>
+        private bool Equals(DateTimeHolder other)
+        {
+            return _item.Equals(other._item);
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7b711a32/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs
index 3a46515..80c1a74 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStream.cs
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-
 namespace Apache.Ignite.Core.Impl.Binary.IO
 {
     using System;
@@ -329,19 +328,4 @@ namespace Apache.Ignite.Core.Impl.Binary.IO
         /// </summary>
         void Flush();
     }
-
-    /// <summary>
-    /// Binary stream processor.
-    /// </summary>
-    [CLSCompliant(false)]
-    public unsafe interface IBinaryStreamProcessor<in TArg, out T>
-    {
-        /// <summary>
-        /// Invokes the processor.
-        /// </summary>
-        /// <param name="data">Data.</param>
-        /// <param name="arg">Argument.</param>
-        /// <returns>Result.</returns>
-        T Invoke(byte* data, TArg arg);
-    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7b711a32/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStreamProcessor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStreamProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStreamProcessor.cs
new file mode 100644
index 0000000..3b8bd8b
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Io/IBinaryStreamProcessor.cs
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary.IO
+{
+    using System;
+
+    /// <summary>
+    /// Binary stream processor.
+    /// </summary>
+    [CLSCompliant(false)]
+    public unsafe interface IBinaryStreamProcessor<in TArg, out T>
+    {
+        /// <summary>
+        /// Invokes the processor.
+        /// </summary>
+        /// <param name="data">Data.</param>
+        /// <param name="arg">Argument.</param>
+        /// <returns>Result.</returns>
+        T Invoke(byte* data, TArg arg);
+    }
+}
\ No newline at end of file